Vitest 5 needs Node >=22.12 and Vite >=6.4 — already satisfied (node 24, vite
8.3.1 auto-installed as its peer) — and needs no config or test change here:
`clearMocks` now defaults on, inline projects inherit the root config, and `-t`
joins suites with ">", none of which this repo relies on.
Paired interleaved runs against v4.1.12, on two warm checkouts and alternating
the version per pair to cancel machine drift: `vitest run` 22.40s -> 20.95s and
`vitest run --coverage` 26.09s -> 25.65s (median per-pair delta -5.8%), with the
same 153 files / 2429 tests and the same 131-file coverage scope at 100% per
file.
The hook ran `pnpm test`, the whole coverage suite, and the agent flow in AGENTS.md ran that same suite again before committing: one commit verified identical content twice, about 45s of it.
`pnpm run check` (scripts/check.sh) runs lint, typecheck and coverage concurrently, prints each tool's complete output (also kept in .tmp/check-logs) and fails when any of them does. A green run fingerprints the worktree into .tmp/check.stamp, so the hook skips the suite for content that just passed; any tracked or untracked edit, or a stamp older than an hour (gitignored inputs like lib/ and node_modules can drift unseen), re-runs it, and `--full` always does. The hook gains lint and typecheck at no extra wall time: 3.2s and 1.4s hide inside the 23s test run.
.gitignore now lists the local tool state (.codegraph, .idea, .zcode): it is not a gate input, and its churn would otherwise invalidate every stamp.
Verified: green gate on 146 files / 2305 tests, hook skip in 0.1s, full re-run after any edit, and a stubbed failing tool exits 1 without stamping.
@tailwindcss/node already depends on tailwindcss at the same exact
version (4.3.3), so a top-level entry would only risk a second copy
resolving in the build process. The one-copy pin the native-binding
rule requires is now held solely by @tailwindcss/node's exact
dependency; update the tailwind.css comment to match.
AGENTS.md keeps docs/ to end-user-facing files, and a headless Chromium
generator plus its HTML template are build tooling. They move to
scripts/social-preview/ beside the other maintenance scripts, and the npm
script and its usage comment follow.
@deepseek-ai/dsh-client-store declares both under devDependencies
while its published lib/index.js imports them, so the client lane's
inlined harness bundle needs them hoisted at the root exactly like
`diff` in the previous commit. A clean-room install of the lockfile now
resolves the whole runtime import graph from the checkout alone:
zustand, immer, diff, shiki, katex, anser, clsx, simple-icons and the
micromark/mdast set.
@deepseek-ai/dsh-client-ui-primitives declares `diff` under
devDependencies while its published lib/index.js imports it, so the bare
import only resolves when the consumer's workspace hoists it — exactly
how shiki, katex, anser, clsx and the micromark/mdast set are already
carried here. `diff` was the one name missing, which failed the release
workflow's `pnpm test` with "Failed to resolve import \"diff\"" across 47
client suites while passing on any tree with a hoisted copy above it.
tsc --noEmit supports --incremental in TS >=5.6: it emits a .tsbuildinfo
(ignored via *.tsbuildinfo) and reuses it across runs, halving the
per-check cost (0.74s -> ~0.35s) on every pnpm test since vitest runs the
typecheck first. Still catches injected src errors (verified).
Vitest's experimental.fsModuleCache was measured and rejected: cold runs
pay a ~23MB write with no gain, warm runs sit inside the run-to-run noise
band, and caching transformed modules conflicts with the suite's stated
contract that specs import src/ directly so coverage reflects what ships.
The src-only tsc pass was redundant with the tests pass: tsconfig.tests.json
extends the base config, so its program loads every src file (96/96, both
passes identical) plus the specs, and tsc type-checks the whole program —
injected src errors surface from the tests pass alone. Verified zero src-only
diagnostics on the clean tree. One pass now covers src + tests; drop the
duplicated full-program compile.
The src and tests tsc --noEmit passes are independent (different program
scopes), so they fork instead of running back-to-back: ~0.9s -> ~0.65s.
The vitest body is CPU-bound jsdom startup (workers already saturated:
sequential client is 62s vs 14s in parallel), so no test-file changes are
warranted — the spec sleeps are deliberate (act-attributed state via real
timers, host pacing, real debounce), not redundancy.
The other suspects from the audit (shiki, katex, anser, clsx, the
mdast/micromark set) stay: the published ui-primitives lib is ESM whose
bare imports are undeclared, and vitest resolves that file for real, so
they are load-bearing devDependencies of this workspace.
The supported set is now the two V4-generation lines (0.1.7-rc.2+ and
0.2.0-rc.2+): the manifest's dshReleases, the peer floors (>=0.1.7-rc.2,
cordis ^4.0.4 — both lines vendor 4.0.4), the devDependency pins, the
baseline matrix, the release workflow's tag fetch, and the compatibility
docs.
With every supported line on session format V4, the V3-only paths leave:
the fold reads the tool result's first-class message alone (source.callId
pairing, message.isError — the admission validation refuses any row whose
data.error outlives it); the settings.register host face module is gone
(the Config-form entry schema serves the preferences); the client drops
the settingsScope/settings.plugin.item card seat, the retired sessions.open
jump fallback, the legacy icon spellings, and the settings-dialog leg of
the settings jump; the history page's tool/result mapper reads the V4
message (its V3 wrapper reads were dropping result content on supported
lines); the cache probe rides the 2-arg cachedSnapshot face. The baseline
gate stays: a below-floor harness composes the fallback units and the
upgrade prompt, and an undetectable version still fails open.
Verified: pnpm run lint:fix && pnpm run test && pnpm run build green (1918
tests, 100% per-file coverage); the compat matrix passes against the real
dsh sources at both baseline tags; live on dsh 0.2.0-rc.2 the plugin
composes, the Plugins-page preference card renders and round-trips a
write, the insights warm-up fills the heatmap, and the session jump and
Context tab work end to end.
The v0.62.0 publish wedged in npm's staged pipeline (the registry accepted
it, signed provenance, then never completed processing — publicly invisible,
and a re-publish is refused with E409 'previously staged'). Same content,
new version to route around the stuck stage.
Add dsh-v0.2.0-rc.2 to the supported set alongside the 0.1.5-rc.1 and
0.1.7-rc.2 lines: the manifest's dshReleases, the baseline matrix, the
release workflow's tag fetch, and the compatibility docs.
Every seam the plugin rides is spelled as at 0.1.7-rc.2 - the projection
registry contract, the platform module table, the right Sidebar seats and
guide-entry contract, the session-jump verb pair, the detail channel RPC
faces, the Plugins page card slot over the configForms transport, the
balance settings faces, the step-boundary guard, and the durable event
vocabulary (still the V4 log generation, no v4-to-v5 migration). Cordis
stays 4.0.4 and the dsh peers stay >=0.1.5-rc.1.
Verified on the new tag: all 25 compat-matrix probes pass against the real
harness sources and the vendored cordis, `pnpm run lint:fix && pnpm run
test && pnpm run build` is green (1837 tests, 100% per-file coverage), and
on a disposable DSH_HOME the 0.2.0-rc.2 CLI installs dsh-context@0.60.0
into exactly one composed config row and removes it back to zero.
Also refresh the docs' verification stamp (plugin 0.58.0 -> 0.60.0).
Drop @deepseek-ai/dsh-invariants and @deepseek-ai/dsh-scope (unreferenced
since the two-baseline re-fit) and the duplicate zod entry from
devDependencies; the dependencies entry stays the runtime one. Declare
react-dom as an optional peer - the client bundle requires it and the
host's platform module table provides it, mirroring the react peer.
Refresh dev-only tooling in range: oxlint 1.85.0, oxlint-tsgolint,
simple-icons, @types/node, jsdom, eslint-plugin-sonarjs, playwright-core.
Everything coupled to the dsh baselines stays put on purpose: the
primitives resolution shim at the versions dsh-v0.1.5-rc.1 itself
resolves, dev cordis 4.0.2 against the vendored packages' exact peers,
lightningcss 1.32.0 deduped with @tailwindcss/node, and the zod floor at
^4.4.3 to match the harness's own. Drop the two orphaned
minimumReleaseAgeExclude rows along with the removed packages.
The supported range is now two baselines - dsh-v0.1.5-rc.1 (session
format V3) and dsh-v0.1.7-rc.2 (V4) - enforced by the runtime gate at
BASELINE_DSH_VERSION = 0.1.5-rc.1; below it the fallback units and the
upgrade modal take over (0.1.2/0.1.3 hosts were previously served by the
real folds).
The pre-V3 log shapes are dead code on every supported harness: the
running harness migrates historical logs on every read path (or refuses
the session wholesale), and 0.1.5-rc.1 rejects a request/header carrying
header.system outright. The fold therefore drops the V0/V2-only paths -
the header.system envelope system prompt, assistant/chunk floods,
{start, end} replacement endpoints, tool/code-dispatch - and the state
fields only they wrote (systemsFromHeader, the stepStart decode
accumulators). stateVersion stays 20: no supported log folds
differently, and pre-V3-era cached rows are discarded by the projection
cache's identity gate (and the strict stepStart sub-schema) instead of
served. The headers unit folds metadata-only epochs (envelope
systemTokens write dropped; the v1 cached-row read-compat and its pinned
stateVersion 1 stay); replaceRangeOf speaks startSeq/endSeq only; the
browser's epoch fetch maps request/header to tools and system/message to
the prompt text.
tests/baselines.ts re-fits to the two entries (the right Sidebar seam is
required on both), the compat matrix drives both tags' REAL sources
(canonical logs re-shaped to V3, the hostile probe renumbered past them),
and the version fixtures pin the new floor. Manifest: dshReleases
{0.1.5-rc.1, 0.1.7-rc.2}, dsh peers >=0.1.5-rc.1 (satisfies the 0.1.7
admission check under includePrerelease), devDeps pinned to the
0.1.5-rc.1 surface plus the ui-primitives runtime closure the client
lane inlines (test-only), and the release workflow fetches the two tags.
docs/compatibility.md is rewritten around the two-line matrix; README,
AGENTS.md and the issue template follow.
Also riding this move, from the audit pass: the fold re-proves an inject
source's form before it books the event record (the harness validates
`kind` but not `form` - a hostile one previously failed the strict
wire/state schemas on every delivery, the #44 freeze class), the headers
unit guards a data-less envelope (it has no try/catch of its own), the
schemastery schema annotations drop the explicit z<T> wrappers the 3.18.4
Mode generics reject, and the version-history note records why
stateVersion is deliberately not bumped.
Every runtime seam the plugin rides is source-identical from
0.1.7-alpha.2, so no code changes; the supported V4 baseline moves
from 0.1.7-alpha.2 to 0.1.7-rc.1 (the alphas leave the matrix). rc.1
adds the harness-side plugin peer-compatibility admission gate
(evaluatePluginCompatibility); the plugin's >=0.1.2-rc.1 dsh peers
satisfy it under the gate's includePrerelease check, so the bundle
composes with no exemption. The release workflow fetches the rc.1 tag
for the compat matrix and points the plugin checker at the npm next
dist-tag (0.1.7-rc.1).