Keep the master refresh separate from the V3-to-V4 lossless-conversion and
checkpoint JSON fixes so the release baseline and each feature change remain
independently reviewable. This checkpoint extends the already-published
4435f6f519 merge before the #4583 child is rebased.
Integrate exactly master 5ec3ffe337062ab5bb4955933008afe8d0a0b915. Its #4156
changes add watched file/document refresh, filesystem watch readiness,
directory expansion restoration, and chat bottom-follow fixes. They update
shared filesystem and Client consumers without changing Session format or
snapshot generation.
The merge has no conflicts. Its 114-file scope and line counts match upstream;
code and prose additions/removals are unchanged. Only the two translation
pairing records incorporate the release branch's retained V4 documentation.
Validation: 762 owner tests passed (1 platform skip), 11 focused Web tests
passed, full build passed, and all 41 doc-sync checks passed. Runtime closure
and Client package checks passed; fs-local publint completed with the existing
source-wildcard export warning.
Represent tool results as tool-role messages and migrate released wrappers
without losing outer own JSON fields, call identity, error state, or writer
field order. Refuse nested or wrapper-only information that has no lossless
current representation before successor publication.
Validate current event relationships directly instead of projecting V4 data
back into V3. Keep lifecycle, PTC, title/command, compaction, system-field and
retired-syntax checks on catalog restoration and ordinary JSONL opens. The
Worker JSON equality helper must inspect own keys so it cannot admit PTC
arguments that Node rejects.
Keep the source role change, required native admission and consumer fixture
updates in one complete review layer. Explain shared-type changes in the
persistence record and the native reader rationale in its existing note.
Use checked branded fixture identities and discriminant narrowing instead
of unknown double casts; fixture values and assertions remain intact.
This recomposes the original tool-role work by _Kerman with the independently
validated migration and admission repairs by Tianyi Cui. Frozen generations
and snapshot input version selection are retained.
Co-authored-by: Tianyi Cui <[email protected]>
Master's `deprecate-synchronous-session-event-reads` marks `Session.eventAt`
deprecated and rejects new production calls. `liveEvents` predates that decision
and still needs the ordered log to reconstruct the preset a session runs under,
so carry the repository's standard line-scoped waiver for deferred migration.
Address the Code Entropy follow-up on d9c4f53758: the runner entry still
expanded its process-substitution object with a `readStdin` hook used only by
tests. Move that seam to `src/runner-internals.ts`, mirroring
`src/startup-internals.ts`, so neither entry grows package API for tests.
Address the Code Entropy finding on f67d722243: the `./startup` entry exported
`internals` only so tests could substitute process facts, which added avoidable
package API. Move the seam to `src/startup-internals.ts`, which no package
export names, and have the provider and its tests import it from there.
Address the ds-review-bot suggestions on 4099b84ee8:
- The post-resume comment scopes the write lease to other processes, so it no
longer contradicts the post-idle re-check that defends against a same-process
overlay writer.
- The Agent Note attributes `pnpm-lock.yaml` to the new
`@deepseek-ai/dsh-session-query` workspace link instead of the shared chunk,
which `scripts/check-workspace-constraints.ts` and the manifest publish.
- The package summary keeps "leaves nothing running behind", so it does not
imply the runner leaves no persisted Session behind.
Address the ds-review-bot findings on 8724223621:
- The JSON error override throws commander's control-flow error instead of
delegating to `program.error`, whose own printer wrote an unprefixed
`error: …` line to stderr and broke the documented `--json` contract.
- Cover the post-idle adoptability re-check with a focused case: an overlay that
appends a preset while the runner awaits idle is still rejected, and the stale
"live Session" comment now names that residual writer.
- Scope the Agent Note change sentence to the product change so it no longer
claims the whole patch is confined to one package.
Address the ds-review-bot findings on 472554a29e:
- resolveAgent refuses an Agent already live under the requested id: its owner
may still drive it, and `whenIdle` is not a single-message signal, so the
one-shot runner cannot own an exclusive run interval over it. The adoptability
rules still run first so the refusal stays specific.
- Refresh the README intro, identity section, and limitations, and the Agent
Note live-identity rule and change scope, for adopt-only.
- Clarify the loader-smoke `cwd` JSDoc (the prefix/parent inputs are ignored)
and pin the resumed wake's final text in the two-wake e2e.
Address the ds-review-bot findings on 9aea4b0804:
- Drop the stale "freshly created" wording from the resolveAgent `@returns`
and rewrite its leading comment for the two remaining identity paths.
- Rewrite the README run-flow paragraph (EN and ZH), the intro sentence, and
the cordis.patch.yml header comment for adopt-only.
- Add a real-composition two-wake e2e: capture the generated id from the first
`--json` wake, resume it by `--session-id`, and assert one persisted log holds
both tasks. `runLoaderSmoke` gains an optional caller-owned `cwd` so both
wakes share one world; the harness leaves that directory in place.
`--session-id` now adopts only: an id with no stored Session fails before the
task runs instead of creating an empty history the caller believes it is
resuming. A first round omits the flag, and the runtime reports the minted
`session-<uuid>` identity in the opening `session` event, so a supervisor
persists it and names it on every later wake.
Updates the help text, the README pair, the Agent Note pair, the generated
config catalog, the unit suite, and the product-profile e2e.
Address the ds-review-bot v12 critical on PR #3849: `addUsage` published the
sum of the attempts that reported usage while silently dropping the ones that
did not, so `step_end.usage` looked exact but under-counted billed tokens.
Track completeness per step and omit usage entirely when any attempt in the
step reports no sample, matching `deriveTurnTokenUsage`'s fail-closed rule.
Address the ds-review-bot v11 review on PR #3849:
- Accumulate every attempt's usage into `step_end.usage`, including a retried
attempt whose only sample sits in its discarded `assistant/attempt` stream.
- Re-check the adopted Session after the idle wait, so a preset selected in
that window is still rejected.
- Reject a whitespace-only `sessionId` supplied through a Cordis overlay, which
bypasses the CLI trim check.
- Narrow the documented error contract: a profile whose own plugins fail to
load exits before the runner mounts and keeps only stderr diagnostics.
Address the ds-review-bot v10 review on PR #3849: `boundJsonLine` bounded the
serialized JSON but not the newline the writer appends, so an event that
serialized to exactly 32 KiB produced a 32 KiB + 1 byte record. Reserve the
terminator byte inside the cap, document the cap as newline-inclusive, and
assert the written record length in the boundary tests.
Address the ds-review-bot v9 review on PR #3849:
- Require `sessionQuery` before the live fast path too: a later process has no
live Agent and must find the id through the query service, so a live identity
no longer bypasses the check.
- Soften the live `stat` comment to what it proves: a stored record rules out an
in-memory registration, while write-handle ownership is not queryable.
- Complete the `parseArguments` JSDoc and fix the broken English sentence in
README.md and the Agent Note.
Address the ds-review-bot v6 review on PR #3849:
- A persisted `agent-preset/selected` record whose `data.agentPreset` is not a
non-empty string used to read as "no preset", letting the run continue under
this bundle's composition. It now fails closed.
- A live identity now has to be known to `sessionPersistence` (`stat`), since
an Agent registered only in memory has no write handle and would flush
nothing.
- Tool arguments that JSON cannot round-trip (an overflowing number such as
`1e400`) keep their raw text instead of the `null` JSON.stringify reports.
Address the ds-review-bot v6 review on PR #3849: the guard sat before the
create branch only, so adopting an already-live identity could still run a
session whose history dies at exit. Move it to the top of resolveAgent, where
it covers both the live and the create path, and add a rejection test for the
live path alongside the existing create-path one.
Address the ds-review-bot v6 review on PR #3849:
- Require the composed sessionPersistence service before creating an exact
--session-id identity, so a profile that keeps sessionQuery but drops
persistence exits 1 instead of printing an id whose history dies at exit.
- Stop exporting the now-internal boundJsonEvent and describe it in the
present tense; its test now exercises boundJsonLine.
- Say "64 levels or deeper" in the README and Agent Note, matching the
depth budget (an input keeps 63 nested containers, the 64th is cut).
Tests: 77 headless unit tests with per-file 100% coverage on src, 14 profile
e2e tests, constraints/typecheck/lint/doc/pairing gates.
Address the ds-review-bot v6 review on PR #3849:
- Cut a projected payload nested deeper than 64 levels instead of recursing
until the stack overflows; the isolated session listener would otherwise
drop the `tool_call` silently.
- Write both `error` events (startup usage errors and runner failures) through
`boundJsonLine`, so the documented 32 KiB line cap covers JSON-escaping
expansion as well as the 8 KiB message cap.
Tests: 76 headless unit tests with per-file 100% coverage on src, 14 profile
e2e tests, constraints/typecheck/lint/doc/pairing gates.
Address the ds-review-bot v5/v6 review on PR #3849:
- Register the shared `lib/json-stream-*.js` chunk in `packageFileExtras` and
order `files` as the workspace-constraints gate requires, so
`pnpm run constraints` passes.
- Re-validate the preset on the Session `agents.resume` actually attached,
closing the TOCTOU window between `observeSession` and the write lease.
- Bound one serialized event line at 32 KiB: an over-long event keeps its
scalar fields, drops structured ones, and at the extreme reduces to `type`.
- Normalize an empty tool-argument string to `{}`, matching the executor.
- Scan only real `--json` flags (stop at `--`, skip a `--session-id` value)
before installing the JSON error override.
Tests: 74 headless unit tests with per-file 100% coverage on src, 14 profile
e2e tests, constraints/typecheck/lint/doc/pairing gates, tarball import smoke.
Address the ds-review-bot v6 review on PR #3849:
- Publish the `lib/json-stream-*.js` chunk that both entry points import.
Without it the installed tarball failed to load with ERR_MODULE_NOT_FOUND,
because `files` listed only `lib/index.js` and `lib/startup.js`.
- Resolve a Session's preset from its log (`agent-preset/selected`) instead of
only the immutable creation header, so a Session that switched preset while
blank is rejected too. Both the persisted and the live path scan the events.
- Write the `--json` error event for Commander grammar rejections (an unknown
option, a missing option value) as well as the action's own usage errors, and
drop Commander's `error: ` prefix from the event message so one event type
carries one message shape.
- Reject a whitespace-only positional instead of falling back to stdin, so an
accidental blank argument cannot consume a pipe.
- Document the stdin task as verbatim and the widened usage-error contract.
Tests: 68 headless unit tests with per-file 100% coverage on src, 14 profile
e2e tests, plus a packed-tarball import smoke check.
- Reject adopting a Session recorded under an agent preset, and one that
recorded no cwd; align the subagent/forked diagnostic wording.
- Write the bounded JSON `error` event for a --json usage error before exit,
since the runner never mounts to write it.
- Keep the caller's exact --session-id instead of the trimmed value.
- Bound object keys and copy a literal `__proto__` key as data rather than
through the inherited setter.
- Reject a lone `-` mixed with other task words.
- Document the in-turn failure contract and step-commit text/thinking timing.