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.
Two new QuestionComposer cases: the collapse toggle hides the option list
and leaves the header strip, and collapsing between answering preserves
both the picked draft and the current question position through a full
submit; re-expanding does not steal focus back into the textarea. Refresh
the question-composer and steering web e2e goldens for the new header
button.
The ask-user takeover rendered the pending question set as a bottom card
capped at min(60vh, 520px) with no way to reduce it, which buried the
conversation above while the user decided. Add a minimize toggle next to
the dismiss action: collapsed, the card becomes a header strip (title plus
the two icon buttons) and the option body and footer unmount; expanding
restores the full card. Drafts and the current question index live in
QuestionFlow local state, so collapse/expand never loses them. The
free-form textarea autofocuses only on first presentation, so re-expanding
does not steal focus from the toggle.
Agent Note: .agents/notes/implemented/feature/2026-08-11-collapsible-ask-user-question-card.{md,zh.md,i18n.yaml}
A max-tokens response that included a tool call persisted assembler-transformed
content next to replay metadata projected from the untransformed native message,
so the next request died in history reconstruction with INVALID_REPLAY_STATE and
the session stayed permanently stuck.
Write side: the finish chunk's replayState becomes a typed ReplayEnvelope —
opaque response-level metadata plus optional per-block entries aligned with the
emitted block sequence. BlockAssembler computes one keep/drop decision for
blocks and entries together, so stored metadata always describes stored content
and retained blocks keep their signatures. pi-ai splits its state into a
version-2 response half and per-block signature entries.
Read side: durable content is authoritative. toPiAssistant degrades any
unusable state — foreign kind, other versions (including the flat v1 form
already on disk), malformed metadata, or content/block mismatches — to the
existing provider-neutral conversion with an onReplayDegrade diagnostic instead
of failing the request, which un-bricks sessions poisoned before this change.
Covered by assembler and replay unit tests, an agent-loop continuation
regression, keyless real-composition continuation tests (native pruned-envelope
replay and legacy flat-state degrade), and the authored keyless snapshot
scenario max-tokens-continue through the assembled ACP app.
tool-bash-persistent overwrote the backend's PS1, so terminal-bash prompt
readiness never matched and every send degraded to the 3.5s silence tier
(idleSilenceMs + handoffGraceMs) under production defaults.
The controlled PROMPT_COMMAND now re-asserts PS1 before every prompt, so an
in-shell override never survives to the next prompt. The tool initializes
with stty -echo alone and detects the no-end-marker fallback through the
seam's stdin_read wait reason instead of matching its own prompt text.
Tool calls drop from 7180/3560/3566 ms to 355/88/91 ms (spawn+init+echo,
echo, pwd; darwin, production defaults). The loader composition suite now
pins the fast path by pushing idleSilenceMs beyond the send bound, and a
real-PTY case proves PS1 self-healing.
Fixes#2585
The shell's Vite config aliases a few workspace packages to source; every other
workspace name resolved through node_modules to a lib/ entry the real build has
emitted but a clean checkout has not, so the generator only worked on a built
tree — and a static gate has to pass on a clean one. The dry run now supplies
source aliases for the names the shell leaves out.
Aliases rather than the recorder's resolveId hook, because Vite resolves a
stylesheet @import through aliases alone, and the theme package publishes its
stylesheets from lib/styles/. lib/ is compiled from src/, and the recorded set is
identical either way: 24 packages on a built tree and on a clean one.
Moving react, shiki, katex and the markdown pipeline to devDependencies took
them out of the notices runtime tier, which tiers by declaring section — yet
their code is inside lib/client.js and the shell dist. The generator now learns
what the browser artifacts carry from the real build configs: each client bundle
through its own tsdown config, the shell through apps/web's Vite config, with a
recorder that resolves each bare specifier, notes the package behind it, and
stops there. About three seconds, and only packages a resolved file backs, so a
bundler's virtual module is not mistaken for a shipped one.
Net effect on the file: the type-only packages @types/mdast and
micromark-util-types move to the development tier, because neither ships code.
A package a published browser artifact carries is a runtime disclosure whatever
section declares it, and the build answers which ones those are. Record that
clause, the dry run behind it, why a bundler's virtual module is not a shipped
package, why a types-only package is not either, and the generator run cost the
dry run adds.
react, react-dom, shiki, katex, clsx, the micromark and mdast families and nine
more reach only browser artifacts, which resolve nothing on a user's machine.
Moving 79 declarations out of dependencies and non-optional peerDependencies
drops 103 tarballs and 6.05 MB from an install of the published CLI.