master introduced AttachmentStore.saveImages as the batch admission
(count/aggregate-byte/media-type limits, validate-all-before-save,
ordered commit). admitEncodedImages narrows to the shared wire entry:
canonical-base64 enforcement plus delegation to saveImages, keeping one
home for batch policy while both wire endpoints (prompt RPC and the
command executor) still call one function. Test doubles gain saveImages;
batch-limit error texts follow saveImages' wording.
- Honor a cancellation that lands during image admission before the
handler runs, settling command/done with the abort reason (executor
re-check after admitEncodedImages; the committed objects stay
unreferenced, deferred-GC territory, now recorded in the Agent Note).
- Never let a pending draft-image serialization reach claim.submit after
the attempt died (dispose/session teardown race).
- Refuse image removal while a command submit is in flight so the rail
cannot diverge from the serialized snapshot mid-transaction.
- Declare dsh-llm as a runtime peer dependency of command-goal.
- Mirror the host executor's ordering and the producer grammar
rejections in the fixture command plane: image checks run after
command resolution (unknown names stay lifecycle-free), bare /goal and
/plan//plan off with images answer the producers' error texts.
- Explain the deliberate serialize/release asymmetry in the hub's
commandImages plumbing.
A claimed slash command consumed only the text half of the composer
submission: /goal with reference images executed, cleared the draft, and
silently stranded the images in the rail. Model-visible attachment intent
had no route through the command plane.
The submission envelope is now modeled end to end. CommandDefinition
input.images declares acceptance; the declaration rides the descriptor to
every client, onto the minted CommandClaim, and into the input machine's
claim snapshot. commands.execute carries the submission's base64 images
and enforces the declaration in the executor: non-declaring commands, a
missing attachment store, and exceeded batch limits settle as logged
error results before the handler runs. Admission reuses the attachment
package's new admitEncodedImages, extracted from api-proxy's prompt path
so both wire endpoints share one limits/validation/commit sequence.
Producers own model visibility: /goal submits one user followup (image
blocks + a fixed reference line) after a successful create/edit so goal
rounds read the images from session history; /plan folds them into its
steered message. Grammar misfits (/goal pause, bare /plan, /plan off)
return direct errors and the composer keeps the images.
On the client, enter adjudication carries a SubmitEnvelope and every
command route that cannot consume images throws a localized refusal that
renders as one composer notice with draft and images retained; the
claimed pre-gate applies the same copy. An accepting claim serializes the
draft images, forwards them to commands.execute, and clears plus releases
them only on a success outcome.
The assembled web test roster gains the ui-input-trigger and ui-commands
plugins, mirroring the shipped composition, so slash submissions exercise
the command plane; a new keyless snapshot pins the refusal banner and the
accepting /goal flow over the built client graph.
The provisional locale fell back to zh, so a browser asking for neither
zh nor en (fr, de) opened the product in Chinese. Resolve to en instead,
and use en as the dictionary fallback: the shipped zh/en dictionaries
declare identical key sets, so one constant serves both roles.
Add scripts/locale-dictionary-parity.spec.ts to gate that symmetry, and
set the asserted locale explicitly in specs that had relied on the old
zh fallback through a dead usePinnedBrowserLanguages call (those files
declare no jsdom environment, so browser detection never ran there).
- wire the directory pick's continue flag through InsertTextRequest to the
input shell, which re-tracks at the caret so descent reopens completion
(the flag was produced and forwarded but never consumed)
- guard the image-only send against a second Enter during the Host round-trip
- keep text appended after the sent snapshot when a submit settles ok; only
interleaved edits clear with the committed content
- drop the dead restoreImages left from the sink rewrite
- read recall labels through a shared defensive sessionRecallLabels helper
instead of unchecked casts over durable log data, and take the reference
summary separator from the locale dictionary
- align the composer specs merged from master with the transactional submit
contract (sinks resolve SubmitOutcome, settlement is awaited, call
assertions carry the AbortSignal), and restore master's forms where the
divergence served nothing (queue-mode sink case, single-line filter
expectation, component-identity slot lookup)
Replace the legacy reference.* API Proxy domain with @Remote methods on the
owning services, following the typert gateway design master adopted on
2026-08-02 (message-feedback and plugin-inventory precedents):
- FileReferenceService and SessionReferenceResolver extend TypertRemoteService;
fileReferences/list and sessionReferenceResolver/candidates are unary Remote
methods cancelled through the reserved trailing signal, and the candidates
face attaches each candidate's canonical mention under the configured limit
- move the wire types to type-only ./types subpaths (FileReferenceCandidate,
SessionReferenceMentionCandidate) and export ./typert plus ./remote artifacts
- mount both contributions in the api-remotes client assembly; ui-reference
consumes ctx.remote instead of connection.api.references and registers zh/en
locale dictionaries for its sections and labels
- delete the reference.* routes, schemas, map rows, client stubs, and fixtures;
the connection fixture serves the Remote endpoints instead
- release deliverPrompt admission listeners when the agent is disposed with the
prepared prompt still pending, and cover the reference-* RpcError codes in
the schema spec
- add the missing tsconfig paths for the /grammar and /types subpaths (clean-
tree vitest could not resolve @deepseek-ai/dsh-file-reference/grammar)
- regenerate the cordis catalog, capability seams, and event matrix; update the
owning bilingual READMEs, Agent Notes, and the reference-composer golden
packages/AGENTS.md:18 requires a package-specific "No runtime invariant:"
reason on an empty installer. This one described a process-boundary
implementation and real-subprocess integration tests that the package does
not carry — it ships the wire-protocol codec and its Python mirror, covered
by protocol.spec.ts and protocol-mirror.e2e.ts.
The barrel's module comment described where a later implementation would sit
relative to this seam, which docs/AGENTS.md:38 keeps out of durable prose.
State what the module exports instead.
docs/AGENTS.md:38 keeps PRs, commits, and stack positions out of durable
prose. Both README sides described where this layer sits in a PR stack and
what a later PR would add, which goes stale the moment the backend lands.
Describe what the package owns instead: the wire protocol, with an exported
surface that carries no subprocess execution path.
Re-record README.i18n.yaml.
master added verify-dsh-package-licenses while this branch was open: every
repository-owned DSH package must declare "license": "MIT". This package
carried BSD-3-Clause from its creation, so the gate failed and took the
required "node 24 / static" lane down with it.
Resolutions:
- docs/module-graph.md, docs/config-catalog.md: generated files. Regenerated
with gen-module-graph and gen-config-catalog on the merged tree, then carried
the new package's entries into the Chinese sides and re-recorded both
pairings. Each side now differs from master by exactly the
code-runtime-python rows.
- scripts/verify-package-readme-model-experience.ts, tsconfig.host.json: master
renamed packages/bash -> packages/shell, packages/pty -> packages/terminal,
code-runtime-worker -> code-runtime-worker-thread and agent-tool-mode ->
agent-tool-presentation. Kept master's names and re-added this branch's
code-runtime-python entry.
Adapted the package to conventions master introduced while the branch was open:
version 0.1.0-rc.6 with publishConfig.access "public" (the release-member rule
check-workspace-constraints now enforces), the invariants project reference
moved to packages/runtime-diagnostics/invariants, and the README companion link
retargeted to code-runtime-worker-thread.
The Python lane never compared what the minimal composition shows the
model: the mock model only asserted system-role messages, and the
advanced snapshot tokenizes the assembled system prompt and tool
schemas.
The sdk-minimal scenario now records model-visible.json — every model
request's advertised tool schemas verbatim and its message list, with
system and user text kept and assistant/tool payloads reduced to call
identity so the expected output replays on macOS and Linux. It excludes
the dynamic runtime-context snapshot, which the same composition emits
on macOS and not on Linux (#2488).
AGENTS.md and the testing policy name both SDKs as independent
projections of the agent loop, session lifecycle, and SessionEventMap.