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 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 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.
Apply the rename pass to READMEs and docs the master sweep rewrote, fix
PTC mode anchors and the renamed-note links in the spill READMEs, and
regenerate the doc graphs.
The base-mounted projection cache's write-behind forces session-log flushes
at cache-chosen times, splitting packed chunk rows and changing the durable
JSONL batching the keyless headless and sdk replay fixtures pin. Neither
profile exposes a session-listing surface — the one-shot runner and the SDK
protocol — so both bundles disable the base row, restoring the pre-base
behavior the fixtures were recorded against (the same pattern acp-app uses).
Move the shared module-reload policy into dsh-base by inserting its HMR row disabled, then remove the redundant disabled overrides from Web, headless, SDK, and ACP. No shipped profile enables server module reload; live profile patch watching continues through the launcher-owned config-only fallback, and browser client HMR remains a separate mechanism.
A later profile layer can opt into source-module reload explicitly with disabled: false while retaining the base root configuration. Composition tests cover every shipped mode and the explicit enable path, and the bundle references plus launcher Agent Notes document the resulting ownership and safety rationale.
The web runtime creates its dev-mode client-hmr row in the root tree
after Loader settlement with plain loader.create, deleting the vendored
Entry.enableRuntime state machine and dsh-cmdline's enableRow export.
Include declares the existing EntryGroup.key tree-carrier marker instead
of the EntryConfigResolver protocol (its own path stays literal; nothing
used a dynamic path). The launcher recognizes no app row: SIGTERM exits
0 on every surface, every boot watches its user patch layers, and the
headless runner exits through ctx.appExit, deleting ctx.headlessIo. Also
restores the vendor README rescope entry to the position the
rescope-vendor exact-edit anchor requires, fixing the master hygiene
regression.
dsh-web-app owns --host/--port/--dev/--workspace-root/--trusted-host and
its --help in a web-startup row; the rows it configures wait for the
webStartup service, and the client-plugin HMR receiver now ships disabled
so --dev is a row toggle rather than a runtime insert (the Loader cannot
resolve a row inserted from inside a mounting plugin).
dsh-headless owns the task positional and rejects a missing task as its own
usage error. Its runner ships disabled, not merely waiting: the schema
requires the task, and a row's config is validated when its fiber is
created, before the startup row can supply one. A composition has exactly
one command-line owner, so the patch disables the web startup row and this
one provides webStartup too, leaving the web rows on their composed
one-shot values.
The keyless web scaffold provides the same three values with no arguments,
which is what an embedding host with no command line does.
Profile bundles are npm packages declaring dsh.patch in their manifest:
dsh-base carries the former base.cordis.yml rows as one insert over the empty
profile root; dsh-web-app carries the web overlay plus a runtime glue plugin
owning what used to be launcher code (frontend dist resolution via
frontend-static, the web-surface prompt section, bash runtime variables, the
readiness-gated URL line); dsh-headless carries the one-shot runner driving a
task turn through the in-process API carrier under the launcher-provided
ctx.headlessIo seam.