Skip to content

build: bump the dev-dependencies group across 1 directory with 7 updates - #23

Closed
dependabot[bot] wants to merge 253 commits into
mainfrom
dependabot/npm_and_yarn/dev-dependencies-73dc522bc4
Closed

dependabot[bot] wants to merge 253 commits into
mainfrom
dependabot/npm_and_yarn/dev-dependencies-73dc522bc4

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Oct 8, 2026 •

Copy link
Copy Markdown

Bumps the dev-dependencies group with 7 updates in the / directory:

Package From To
@types/node 26.6.3 26.6.4
@vitest/coverage-v8 5.0.1 5.0.3
react 18.3.1 19.3.0
@types/react 18.3.31 19.3.0
react-dom 18.3.1 19.3.0
ultracite 7.12.2 7.12.4
vitest 5.0.2 5.0.3

Updates @types/node from 26.6.3 to 26.6.4

Commits

Updates @vitest/coverage-v8 from 5.0.1 to 5.0.3

Release notes

Sourced from @​vitest/coverage-v8's releases.

v5.0.3

   🐞 Bug Fixes

    View changes on GitHub

v5.0.2

   🐞 Bug Fixes

... (truncated)

Commits

Updates react from 18.3.1 to 19.3.0

Release notes

Sourced from react's releases.

19.3.0 (September 9, 2026)

Below is a list of all new features, APIs, and bug fixes.

Read the React 19.3 release post for more information.

New React Features

New React DOM Features

  • browser(): a new react-dom API that returns a usable which errors during server rendering and resolves in the browser. use(browser()) inside a <Suspense> boundary marks a subtree as browser-only without reporting a recoverable error (@​gnoff: #37143, #37241)
    • Added an onBrowserBailout option to the react-dom/server APIs to observe when a subtree defers to the browser (@​gnoff #37193)

Notable changes

All Changes

React

... (truncated)

Changelog

Sourced from react's changelog.

19.3.0 (September 9, 2026)

New React Features

New React DOM Features

  • browser(): a new react-dom API that returns a usable which errors during server rendering and resolves in the browser. use(browser()) inside a <Suspense> boundary marks a subtree as browser-only without reporting a recoverable error (@​gnoff: #37143, #37241)
    • Added an onBrowserBailout option to the react-dom/server APIs to observe when a subtree defers to the browser (@​gnoff #37193)

Notable changes

All Changes

React

... (truncated)

Commits
Maintainer changes

This version was pushed to npm by GitHub Actions, a new releaser for react since your current version.


Updates @types/react from 18.3.31 to 19.3.0

Commits

Updates react-dom from 18.3.1 to 19.3.0

Release notes

Sourced from react-dom's releases.

19.3.0 (September 9, 2026)

Below is a list of all new features, APIs, and bug fixes.

Read the React 19.3 release post for more information.

New React Features

New React DOM Features

  • browser(): a new react-dom API that returns a usable which errors during server rendering and resolves in the browser. use(browser()) inside a <Suspense> boundary marks a subtree as browser-only without reporting a recoverable error (@​gnoff: #37143, #37241)
    • Added an onBrowserBailout option to the react-dom/server APIs to observe when a subtree defers to the browser (@​gnoff #37193)

Notable changes

All Changes

React

  • Fast Refresh Fixes
    • Fix Fast Refresh to find and remount edits to components wrapped behind lazy() (@​sophiebits #36965)
    • Fix Fast Refresh so edits to a memo() comparison function take effect (@​sophiebits Description has been truncated

github-actions Bot and others added 30 commits September 30, 2026 21:09
…ponents--dsh-opencode

chore(main): release 0.3.0
…lease

release-please appends entries in its own style, which tripped oxfmt and blocked publishing. CHANGELOG.md joins lib/ as fmt-ignored (the .prettierignore convention); lint/types still cover all source. release-please now authenticates with RELEASE_PLEASE_TOKEN so its tags/releases trigger the publish workflow (GITHUB_TOKEN-created refs never fire downstream runs).
…d versions

setup-node only writes auth for registry.npmjs.org, so the mirror step got ENEEDAUTH. Append the registry auth line explicitly. Guard the npmjs step with npm view so re-pushed tags retry cleanly instead of 403.
Boolean toggles read '(default on)' and providers hint names its default, in both en and zh, so users see what's active without opening docs.
…ponents--dsh-opencode

chore(main): release 0.3.1
… name

Third-party bundles render config on plugins.bundle.config, not plugins.item (reserved for official plugins) — the card was registering on a slot the bundle page never reads. Key by npm package name per the slot contract, accept view page, dispose the form model, and prefetch the client bundle with immediately:true.
…ponents--dsh-opencode

chore(main): release 0.3.2
The host resolves row names to node_modules paths, so the unscoped name left over from the rename failed the entry with 'failed to import'. Adds manifest-consistency tests pinning row name to package.json and settings NS to row id.
…ponents--dsh-opencode

chore(main): release 0.3.3
The web loader drops bundles whose __ModuleLoader__.load id differs from the npm package name ('loaded without registering ...'). Same scoped-name lesson as the cordis row: id is now @viztor/dsh-opencode, pinned by a manifest test.
…ponents--dsh-opencode

chore(main): release 0.3.4
Row name must equal the npm package (host path resolution), settings NS must equal the row id (client binding), plugin name export matches the default row id by convention. Documents the triple plus the single-row card assumption in code and AGENTS.md.
Original geometric mark (terminal chevron + session node, no brand appropriation), wired via package.json icon field and published files, pinned by a manifest test (relative path, 256 KiB host limit).
…ponents--dsh-opencode

chore(main): release 0.4.0
Every PluginConfig option is now editable in the card: mode (validated session-id|uuid), debug toggle, and debug file path, all with (default …) labels in en+zh. Session mapping is pure derivation (SHA-256, stable across restarts) so the per-process Map — unbounded growth in a long-lived host for zero benefit — is gone, along with its signature.
…ponents--dsh-opencode

chore(main): release 0.5.0
The session-id|uuid distinction was never necessary: raw DSH UUIDs satisfy no gateway, while derived ses_ values route stably everywhere a UUID would. Deletes the option from config, UI, patch defaults, and docs; derivation is now unconditional.
viztor added 20 commits October 9, 2026 08:33
The owner: 'openai也有好几种' — and the docs said two APIs (Responses and
Messages), which is wrong twice over. OpenCode serves its models on three
shapes, measured 2026-10-05 across the 116 opencode models:

- OpenAI Chat Completions — the DEFAULT, 53 models, which name no SDK at all
- OpenAI Responses — 32 models, naming @ai-sdk/openai
- Anthropic Messages — 23 models, naming @ai-sdk/anthropic

So 'OpenAI' covers two of the three, and they are different wire formats: a
model that needs Responses does not work on the completions endpoint. The
default is not 'OpenAI' either — it is whatever api the route itself was
registered with.

Both dev docs now carry the three-row table with the model counts and the
catalog signal for each, plus the fourth SDK that is deliberately NOT
served: 8 models name @ai-sdk/google, llm-pi-ai implements no such
protocol, and they keep failing on the completions route rather than being
sent somewhere invented.

Both READMEs' 'you keep choosing' bullet named only two shapes; it now
names all three.
Two things made the pill's edge read larger than the thing inside it.

- The root now sets flex: none. A slot wrapper may stretch its child, and a
  stretched box draws the hover tint wider than the label — an edge with
  nothing in it.
- The padding is trimmed from 3px 9px to 2px 7px. That is ~18px tall and
  ~48px wide, still a comfortable target: this thins the edge, it does not
  remove the target. The earlier lesson (the footer's 20px button) was
  about DROPPING padding to fix a gap, which is a different move.

The negative right margin stays: it compensates the dock's own gap, which
is a spacing fact, not a padding one.
The owner: 'the corner radius is too big'.

The token was not the problem — the RATIO was. The host's own controls
(Button, Input, SegmentedControl) all declare --dsw-radius-md, and this
trigger copied them, which is right at THEIR height: 12px on a ~28px
control is 43% of it and reads as a rounded rect. This trigger is ~20px
tall, so the same 12px clamps to 10px — 50% of the box, which IS a
stadium. One rung down the same host ladder (--dsw-radius-sm, 8px)
restores the ratio.

The test is re-pinned to the reasoning rather than to the token, so the
next person reads why the rung differs from the control next to it.

Also fixes a comment I broke while rewriting that rule's explanation: the
replacement body never re-opened its */, so the comment ran on and ate the
declarations after it. CSS in a template literal is not parsed, so nothing
complained — the only symptom was the radius assertion failing. Recorded
in AGENTS.md: a comment's delimiters are part of the edit.
The owner asked the question the code should have asked itself: 'if it is
Zen, should we not show the ring?'

No. A ring is a GAUGE, and Zen has no window to measure. On a Zen route it
was drawn hollow — a gauge with no measurement, which is decoration. The
number beside it (the session spend) is the whole story, and the model
selector next to the trigger is text alone for the same reason.

So the trigger renders the SVG only when !isZen, and the label stays the
spend. isFree loses its  clause: it existed only to hollow a ring
that no longer draws, and a dead condition is how the next reader is
misled.

Tests follow the change rather than the token: the panel case now asserts
NO svg on Zen (it previously asserted one), and the mount case asserts the
ring element is absent instead of reading its dash array.

Docs: the Chinese behaviour doc's trigger table and its 'Zen draws no Go
figure' paragraph, and both READMEs' Zen bullets, which still described
'the same ring'.
…the three shapes

The owner: 'openai有两种'. Both READMEs now open the protocol chapter
with it — Chat Completions and Responses are two different wire formats,
not two names for one thing, and a model that needs Responses answers 500
on the completions endpoint. The old sentence said the patch 'covers all
four families' while the table right below it said Google is 'not offered'
— a contradiction in one screen.

Counts were re-measured from the shipped shim rather than trusted:

| | was | now |
| :-- | --: | --: |
| active opencode models | 80 | 83 |
| names no SDK (Chat Completions) | 26 | 28 |
| @ai-sdk/openai (Responses) | 30 | 30 |
| @ai-sdk/anthropic (Messages) | 17 | 18 |
| @ai-sdk/google (not offered) | 7 | 7 |

The stale '36 of the 116' subtraction is gone: it only ages badly.

Readability: the introduction is now three labelled paragraphs — the
problem, what this does, what you get — instead of one wall that opened
with protocol internals. The install snippet pins ^0.14.0 rather than
^0.12.0.
…reads

Three requests, one pass.

1. 'The README should be a simple explanation.'

   The 184-line Deep Dive chapter moved to docs/deep-dive.md (and its
   Chinese counterpart). README.md is 578 -> 411 lines and the Contents
   list points at the doc. Nothing was deleted: the chapter is byte-for-
   byte where it was, in a file whose job is depth.

2. 'Explain our UI clearly.'

   The Interface chapter now opens with a one-screen map: the three
   surfaces, where each lives, and what each shows — trigger, panel,
   settings card — plus the two rules a reader needs (hovering explains
   the trigger's own number; clicking opens the panel). Both languages.

3. 'The changelog should be written clearly.'

   CHANGELOG.md is release-please's file — hand-editing it is forbidden
   here and would be overwritten. The lever is the generator, so the
   release-please action gains changelog-sections: Features, Fixes,
   Performance and Documentation are shown, in that order; refactors,
   tests, build, CI and chores are hidden — they stay in the commit log,
   where a maintainer looks for them, not in a release note.

   That also means the entries are only ever as clear as the commit
   subjects, which is why the subjects here describe the change and its
   reason rather than naming a file.
The owner: 'session id is changed to adapt to official protocol.'

Our id was ses_<12hex><14base62> — 26 characters after the prefix,
which is exactly a ULID's length, and the vendor's ids ARE ULIDs:
ses_, msg_ and prt_ are prefixed ULIDs written in Crockford base32
(0123456789ABCDEFGHJKMNPQRSTVWXYZ — no I, L, O or U), where
lexicographic order is chronological order. Base62 carries lowercase,
which a ULID never does: the right LENGTH in the wrong ALPHABET, and a
gateway validating the shape would not accept it.

It now emits 26 Crockford characters, still a pure function of the DSH
session id — affinity has to survive a host restart, and a real clock
reading would mint a new id on every boot. 130 bits come from the top of
SHA-256, read out five at a time with arithmetic only: the lint forbids
bitwise operators, and base 256 into base 32 needs only multiply and
divide.

Docs follow: the header matrix in both deep-dive docs, both READMEs and
AGENTS.md said <12hex><14base62>. The format regex lived in one shared
fixture (test/test-helpers.ts), which is why four tests failed from a
change in one module.
It sat between the tagline and the badge row — the middle of the header
block, which is where a reader looks for a title, not for a language
choice. It is now the first line of both READMEs, above the icon.

The flags are gone. A flag is a country, and neither README is written
for one: 简体中文 is a language, and 🇬🇧 claims a dialect the English
here does not have. The active language is bold and unlinked; the other
is a link — the same shape as any other tab pair.
The owner, reading the npm page for @viztor/dsh-opencode: 'update readme
to dsh-opencode-patch everywhere, so the name is consistent.'

The README advertised the scoped aliases in two places — the install
section and the compatibility table — which is what made any of the three
npm pages read as if the package had three names. Both now name one:
the dependency you install, the bundle entry, and the row the host
resolves are all dsh-opencode-patch.

The aliases still exist and still publish the same tree and version; the
maintainer record for them is AGENTS.md and scripts/publish-scoped.ts,
which is where someone changing them looks. Consumer docs should not make
a reader choose between three names for one package.

Left alone on purpose: /tmp/dsh-opencode-debug.jsonl (a path, and it
matches the configured default) and nobu121/dsh-opencode-session (someone
else's repository, credited in Attribution).
The owner: 'Don't say evolved, it's almost a complete re-write, say it's
inspired or based on or stuff like that.'

Both READMEs claimed descent — 'Evolved from' / '演进而来', followed by
'Extended by' / '扩展'. That overstates the relationship: what carries
over is the IDEA (session ID handling for OpenCode on DSH), and the code
around it was written here. Both now say so plainly — 'Inspired by' plus
'This plugin is a separate implementation' / '本插件独立实现:沿用了这个
思路,其余部分都是重写的'.

The credit is unchanged: @nobu121 pioneered the session ID handling, and
the link is still there. What changed is the claim about how much of this
tree came from there.
The owner: 'under @viztor it should also be dsh-opencode-patch, keep the
name consistent.'

Two names were already right: the package is dsh-opencode-patch, and the
scoped alias @viztor/dsh-opencode-patch matches it. The third —
@viztor/dsh-opencode — is already RETIRED on npm: 0.14.0 carries the
deprecation message 'Renamed to @viztor/dsh-opencode-patch'.

What was still inconsistent is that page's README, whose title was
'# @viztor/dsh-opencode (Renamed to dsh-opencode-patch)' — the retired
name presented as the package's identity, and the canonical one as a
parenthetical. It now leads with '# dsh-opencode-patch' and explains the
old name as the reason the reader is on that page, with the migration
installing the canonical name.

Takes effect on the next release: npm serves the README from the
published tarball, so 0.14.0's page is unchanged until a version ships
with this script.
The owner pushed back on my justification for keeping a pure SHA-256 suffix
('affinity has to survive a host restart, and a real clock would mint a new
id on every boot') and was right on two counts, plus one I had missed.

- 'Must survive a restart' overstates it. Affinity requires the SAME id
  across the turns of a live conversation. A restart is a discontinuity,
  and the vendor's cache lives on their side: a new id costs one warm-up,
  not a broken lineage. Cross-restart stability is an optimization.

- 'A real clock mints a new id per boot' conflates the clock with the
  storage. The id changes because it is held in MEMORY. A timestamped id
  can be persisted and be just as stable; a hash-derived one is stable
  because it needs no storage at all. What the design buys is
  STATELESSNESS, not 'the clock'.

- And the thing I skipped: a ULID's first ten characters ARE a millisecond
  timestamp, so a hash-filled suffix claims a random creation instant —
  often far in the future. The vendor mints and stores these ids and
  plausibly reads that field. That does not heal the way a cache miss
  does: it is wrong on every request, forever.

So the ranking inverts. A real timestamp with one warm-up per restart
beats a permanently false timestamp. The design that gets both without
state takes the timestamp from the SESSION (which outlives a restart)
rather than from this process — and that needs a creation time this
module is not given. Recorded as the open question instead of as a
justification; the behaviour is unchanged.
I broke this two commits ago, and the vendor's own generator is what
settles it.

Our id was ses_<12hex><14base62>. I read a third-party analysis claiming
OpenCode ids are prefixed ULIDs in Crockford base32, and changed ours to
match. Their code says otherwise:

  let now = BigInt(currentTimestamp) * BigInt(0x1000) + BigInt(counter)
  return prefix + "_" + timeBytes.toString("hex") + randomBase62(LENGTH - 12)

prefix_ + 12 lowercase hex + 14 base62 — our original shape. Worse, the
twelve hex characters are a timestamp the vendor PARSES BACK:

  export function timestamp(id) {
    const hex = id.slice(prefix.length + 1, prefix.length + 13)
    return Number(BigInt("0x" + hex) / BigInt(0x1000))
  }

BigInt("0x" + "VYCAGN20GK5T") throws, so any consumer calling
timestamp() on our id crashed. Reproduced in one line before reverting.

The timestamp is now REAL rather than hash filler, without a clock and
without state: DSH sessions carry createdAt, so the value is the
session's actual creation time — the same on every turn, in every
process, and after a restart. The 12-bit counter comes from the hash
(arithmetic, because no-bitwise forbids << and |), and the 14 random
characters use the vendor's exact alphabet.

One detail worth keeping: their six-byte buffer truncates now to 48 bits,
so the embedded time wraps every ~795 days — their own filed bug
(opencode#42589). We mirror it exactly. A value that recovers a different
millisecond than we put in is what a REAL id does too, and being
indistinguishable from one is the whole point.

Lesson recorded in AGENTS.md: a blog post about the same project is
evidence about a DIFFERENT snapshot of it. The generator is ten lines and
public — read the party's own code, not a description of it.
The regression I shipped two commits ago had no test that could see it.
The suite asserted a shape regex — which the Crockford alphabet satisfied,
because it was a valid 26-character string. What it never did was the one
thing the vendor does: parse the id back.

These four cases implement their reader verbatim ( from
packages/opencode/src/id/id.ts: slice twelve characters, hex, divide by
0x1000) and run it against values we minted:

- the embedded millisecond is exactly where their reader looks for it,
  modulo the 48-bit truncation their own six-byte buffer imposes;
- the counter lives in the low twelve bits, so conversations created in
  the same millisecond still read back as that millisecond;
- the id is identical for the same session and creation time — affinity
  comes from the session, not from a clock;
- the degraded path (no createdAt) still parses instead of throwing
  inside a consumer.

Verified by hand against the broken value: their reader throws
'Cannot convert VYCAGN20GK5T to a BigInt' on a Crockford id, which is
what the first and fourth cases would have reported.
Two halves of one wire, plus the answer to why direction matters.

WIRING. openCodeSessionIdFor has accepted a creation time since the last
commit, but nobody passed one — the live path still fell back to hash
bits. Now:

- readSessionMetaResolver reads createdAt off the session RECORD (the Host
  validates record.createdAt; the header carries cwd and parentSession),
  and drops anything that is not a non-negative safe integer — a malformed
  value must not become a timestamp.
- stream-hook looks the session up BEFORE deriving, and passes
  sessionMeta.createdAt into headerValueFor. The parent session id gets
  its own lookup, so a subagent's lineage carries the parent's real time.

DIRECTION. ascending vs descending is the bitwise NOT of the timestamp,
so the same instant sorts to opposite ends. It is not cosmetic:

- Their reader is documented 'Does not work with descending IDs', so an id
  minted the wrong way returns garbage from timestamp() — the same class
  of failure as the Crockford alphabet, from a different cause.
- The id IS the sort key, so the direction decides which end of their
  lists a session lands on.
- It is a per-TYPE choice: msg_ and prt_ may be descending while ses_ is
  ascending — which the exported reader implies, since it has to work on
  the ids people read times from. We mint only session ids, so we emit
  ascending, and the parity test pins it: a complemented value cannot be
  recovered by their reader.

Tests: three cases pin the wiring — the record (not the header), the
malformed-value guard, and the value landing where their reader looks.
The owner asked for proof that turning the meter off hides the meter AND
the price. The switch is ONE config knob with two halves in two
processes, and only one half was tested:

- HOST (new test): usageEnabled=false means GoUsageService is never
  mounted, so the remote face the meter reads does not exist. The test
  asserts the component by NAME rather than counting ctx.plugin calls,
  because other installers mount through the same ctx.
- CLIENT (already pinned): the meter injector returns a diagnostic reason
  and no props when remote.opencodeGoUsage.read is missing, so nothing
  mounts — not an empty trigger, and no panel to carry a price row.

Off is therefore absence, not an empty shell. Nothing renders, so the
price cannot either.

Docs: both READMEs now state the three things this plugin is built
around — minimal intrusion (interception only for claimed routes; the
meter one switch from gone), a native DSH plugin (one apply, its own
namespace, ctx.inject, both bundled languages), and OpenCode API
compatibility (the traits the gateways actually check).
The owner, reading the card: 'shouldn't these two be the same? why two
switches?' They were not the same thing — but the second was nested
inside the first, which is worse than redundant.

  usageEnabled   -> does the meter exist at all (the Host does not mount
                    the service, so the client mounts nothing)
  showUsagePrice -> does the meter show MONEY: the Zen trigger's number
                    and the spend row

Off meant: on Go, the ring stays and the money goes; on Zen, the
trigger's ONLY number is the money — so it deleted the meter's content
and kept its frame. That is the empty shell this repo has already paid
for twice.

Three reasons it went, the third deciding it:

1. A switch whose effect only exists inside another switch's surface is a
   state, not a decision. The card shows decisions.
2. Minimal intrusion is measured in switches: the meter is now one switch
   away from being gone.
3. On Zen it produced an empty meter, and the user who wants no money
   display has a coherent answer — turn the meter off. The meter IS the
   quota-and-money surface.

Removing it is safe: unknown keys are tolerated, so a stale
showUsagePrice: false is ignored rather than fatal (verified before
deleting). The one consequence, stated plainly: whoever had set it false
now sees the spend row again.

The card is 7 fields in 3 sections. The counts that moved with it
include a hardcoded boolFields.length — which is exactly what should
break when a field is removed.
The owner: 'there are two endpoints, one is inference, the other is the
old default endpoint for opencode', plus two auth methods on the modern
one. Finding them meant reading the vendor's code, and they were not
where the question pointed.

NOT in provider.ts — 2,094 lines, baseURL 20 times, none of them the
OpenCode endpoint. Line 1812 is the tell:
  options["baseURL"] = model.api.url ?? ...
IN the catalog (models.dev), the same source this plugin already reads:

  provider      provider-level api (the DEFAULT)        models  overrides
  opencode      https://opencode.ai/zen/v1                120        0
  opencode-go   https://opencode.ai/zen/go/v1              36        0

So the two levels are the provider DEFAULT and the per-model INFERENCE
endpoint, and the CLI resolves model.api.url ?? provider default. Every
model inherits the default today — but a model that sets its own URL is
served from it, which is exactly why the plugin matches the
opencode.ai/zen MARKER instead of pinning a base URL.

The two auth methods follow the WIRE SHAPE, not the endpoint: the OpenAI
planes (/chat/completions, /responses) send Authorization: Bearer; the
Anthropic plane (/messages) sends x-api-key. That is why
extractApiKeyFromHeaders reads Authorization first and falls back to
x-api-key / api-key — not defensive coding, but the two SDK families the
three shapes come from.

Recorded simplified in both READMEs (right under the protocol heading)
and in full in both deep-dive docs, with the source-reading note in
AGENTS.md.
The owner: "we don't want path to be exposed... that should be a hardrule
globally."

The leak was one example, in two files, committed and public:

  docs/deep-dive.md:66        /Users/<name>/dev/dsh-opencode -> x-opencode-project
  docs/deep-dive.zh-CN.md:66  same

It is a real filesystem path from a development machine, in a sentence
that only needs to show HOW a folder name becomes a header. Both now use a
neutral placeholder (/home/you/projects/my-app -> my-app).

WHAT IS NOT AFFECTED, verified rather than assumed:

- The three published packages are CLEAN. Grepping the unpacked 0.15.0
  tarballs for the home prefix returns nothing, because package.json's
  files allowlist never included docs/. There is nothing to unpublish, and
  unpublishing is irreversible - so it was not done.
- coverage/ and .workbuddy-ai/ carry absolute paths locally but are both
  in .gitignore and untracked.

WHAT REMAINS: the string is in three commits' diffs in the public history
(2430c03, 9e06a31, baeaa44). Removing it there means rewriting history and
force-pushing over every tag, which invalidates the SHAs the npm
provenance attestations point at. That is the owner's call, not a
side-effect of a docs fix.

HARD RULE added to ~/.dsh/AGENTS.md (global) and this file: an absolute
path from a development machine never leaves the machine - prose,
comments, fixtures, commit messages, artifacts; use a placeholder; grep
the artifact (not just the tree) before publishing; generated outputs
count; and the check belongs before the commit, because afterwards the
price is a history rewrite.
viztor and others added 3 commits October 9, 2026 10:49
The owner, reading the derivation: "why are you using path? Look at the
docs - isn't there a problem?" There was.

path.basename is platform-specific: Node documents `/` and `\` on Windows,
`/` alone on POSIX. So on this host:

  path.basename("C:\Users\<name>\dev\dsh-opencode")
  -> "C:\Users\<name>\dev\dsh-opencode"   (the whole string, username included)

That value is sent as x-opencode-project on every turn, which is the same
class of leak we just removed from the docs: a local path, and a username,
reaching a third party. It only needed a Windows-shaped cwd on a POSIX
host, or the reverse, to trigger - and nothing in the suite could see it,
because the only project assertions fed the value in already-formed.

projectNameFrom now splits on BOTH separators, trims (blanks are absent,
which is the resolver's rule for cwd), and returns nothing for /, ., ..
or an empty name. Five tests pin it, including a property case: whatever
it returns never contains a separator.

The lesson matches the hard rule added one commit earlier - the check
belongs before the value ships, and "the folder name" is only true if the
code that produces it cannot return a path.
The history rewrite removed the local path from every commit, which also
invalidated the SHAs the npm provenance attestations point at. Cutting a
patch release puts the published provenance back on a commit that exists.

Contents: the project-header fix (split both separators) and the docs fix
that removed the path from the example.
Bumps the dev-dependencies group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.6.3` | `26.6.4` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `5.0.1` | `5.0.3` |
| [react](https://github.com/react/react/tree/HEAD/packages/react) | `18.3.1` | `19.3.0` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `18.3.31` | `19.3.0` |
| [react-dom](https://github.com/react/react/tree/HEAD/packages/react-dom) | `18.3.1` | `19.3.0` |
| [ultracite](https://github.com/haydenbleasel/ultracite) | `7.12.2` | `7.12.4` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `5.0.2` | `5.0.3` |



Updates `@types/node` from 26.6.3 to 26.6.4
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@vitest/coverage-v8` from 5.0.1 to 5.0.3
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.3/packages/coverage-v8)

Updates `react` from 18.3.1 to 19.3.0
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.3.0/packages/react)

Updates `@types/react` from 18.3.31 to 19.3.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 18.3.1 to 19.3.0
- [Release notes](https://github.com/react/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/react/react/commits/v19.3.0/packages/react-dom)

Updates `ultracite` from 7.12.2 to 7.12.4
- [Release notes](https://github.com/haydenbleasel/ultracite/releases)
- [Commits](https://github.com/haydenbleasel/ultracite/compare/ultracite@7.12.2...ultracite@7.12.4)

Updates `vitest` from 5.0.2 to 5.0.3
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.3/packages/vitest)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.6.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: "@types/react"
  dependency-version: 19.3.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: dev-dependencies
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 5.0.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: react
  dependency-version: 19.3.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: dev-dependencies
- dependency-name: react-dom
  dependency-version: 19.3.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: dev-dependencies
- dependency-name: ultracite
  dependency-version: 7.12.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
- dependency-name: vitest
  dependency-version: 5.0.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: dev-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot
dependabot Bot force-pushed the dependabot/npm_and_yarn/dev-dependencies-73dc522bc4 branch from 069c7ff to 8bc872f Compare October 9, 2026 03:01
@viztor viztor closed this Oct 9, 2026
@dependabot @github

dependabot Bot commented on behalf of github Oct 9, 2026

Copy link
Copy Markdown
Author

This pull request was built based on a group rule. Closing it will not ignore any of these versions in future pull requests.

To ignore these dependencies, configure ignore rules in dependabot.yml

@dependabot
dependabot Bot deleted the dependabot/npm_and_yarn/dev-dependencies-73dc522bc4 branch October 9, 2026 03:34
@viztor

viztor commented Oct 9, 2026

Copy link
Copy Markdown
Owner

Blocked on two breaking changes, not on the bump itself:

  1. ultracite — vp check cannot start: Failed to parse oxlint configuration file. The lint preset's config format changed, so the whole check job fails before analysis runs.
  2. react / react-dom 18 → 19 (with @types/react 19) — a major migration for the client bundle and its tests, not a routine bump.

The safe part is @vitest/coverage-v8 5.0.1 → 5.0.3. Please split this group so the patch updates can land, or close it and let a React 19 migration be its own change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant