Commit Graph

78 Commits

Author SHA1 Message Date
imccyu
6f77da4c8c refactor: relocate demo app bundles to packages/examples/*-demo
Move the agent-spine bundle and the stdio/ACP/JSON-RPC app packages out of
core/ and ui/ into a new packages/examples/ group, renamed with a -demo
suffix so the npm name marks them as non-product surface:

  core/agent-core   -> examples/agent-spine-demo  (dsh-agent-spine-demo)
  ui/stdio-agent    -> examples/stdio-demo        (dsh-stdio-demo)
  ui/acp-agent      -> examples/acp-demo          (dsh-acp-demo)
  ui/jsonrpc-agent  -> examples/jsonrpc-demo      (dsh-jsonrpc-demo)

Update every code/config/test reference and reference-only doc mentions, and
regenerate module-graph, config-catalog, and doc-graphs. The jsonrpc bin
(dsh-jsonrpc-agent) and single-file exe (dsh-jsonrpc-agent-pkg) keep their
names; the SDK runtime-startup surface is reconciled separately.
2026-07-15 16:46:05 +08:00
Tianyi Cui
96851da571 Merge remote-tracking branch 'origin/master' into codex/simp-prune-web-seam-fields
# Conflicts:
#	docs/rfc/INDEX.md
2026-07-15 13:28:40 +08:00
imccyu
517964fe84 Merge branch 'master' into refactor/agent-leaf-dependencies 2026-07-15 13:09:33 +08:00
imccyu
80fbeefbd6 refactor(ui): extract stdio plugin package
Move the readline front door from stdio-agent into @deepseek-ai/dsh-stdio, keeping the loader shape and the stdio coverage with the new package.
2026-07-15 10:04:40 +08:00
Tianyi Cui
2df64c22ad Merge remote-tracking branch 'origin/master' into codex/simp-drop-skill-provider-events
# Conflicts:
#	docs/event-producer-consumer.md
2026-07-14 18:00:41 +08:00
Tianyi Cui
92c52eec20 Merge remote-tracking branch 'origin/master' into codex/simp-prune-web-seam-fields
# Conflicts:
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/web.md
#	docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md
#	packages/web/tool-web/tests/integration.spec.ts
#	packages/web/web-fetch-local/README.md
#	packages/web/web-fetch-local/src/provider.ts
#	packages/web/web/src/types.ts
2026-07-14 17:57:50 +08:00
Tianyi Cui
582a8ba288 refactor: drop unconsumed skill provider events 2026-07-14 04:32:40 +08:00
Tianyi Cui
a8d1624695 docs: close web seam simplification RFC 2026-07-14 04:26:35 +08:00
Tianyi Cui
3ab35de64f refactor: prune unused web seam fields 2026-07-14 04:17:38 +08:00
Tianyi Cui
148046b9c8 docs: rebalance prose cleanup and add trimming skill 2026-07-13 23:27:00 +08:00
Tianyi Cui
c45d7927cf docs: tighten prose audit after master retarget 2026-07-13 16:24:32 +08:00
Tianyi Cui
74ada5777c Merge PR #224 updates into prose cleanup 2026-07-12 23:36:49 +08:00
Tianyi Cui
e8fed4fb66 fix(session): contain post-commit observers 2026-07-12 18:57:42 +08:00
Tianyi Cui
75838e10b5 docs: trim generated prose 2026-07-12 03:36:43 +08:00
Tianyi Cui
bffdee88e4 Merge origin/master: adopt the uniform RFC format
This branch's two RFCs (prompt-variables, provider-lifecycle events)
conform to the new contract in the same merge: 'Status: implemented'
dateless header, 'Rejected alternatives' -> 'Alternatives considered',
'What we give up' folded into '## Consequences' (per the uniform-format
RFC's own rejection of a costs-only closer), and the index regenerated
into the new INDEX.md. docs/rfc/README.md resolved to master's rewrite.
2026-07-06 00:13:09 +08:00
Tianyi Cui
3f83a4ee96 review: the persona becomes the system-prompt plugin's deployment config
Review round 2 (tianyicui inline comments):

- dsh-system-prompt itself registers the harness:identity (-100) and
  deployment:persona (0) sections — they must survive a swapped loop
  plugin, so they leave dsh-agent-loop; the persona text is the plugin's
  own validated 'persona' config. The model/cwd variables STAY on the
  loop: runtime facts of the agents it drives.
- AgentOptions.systemPrompt is deleted with all its forwarding plumbing:
  the app configs' systemPrompt keys become 'persona' routed through
  dsh-agent-core (schema = z.intersect of the owners'), the ACP bridge
  and tool-subagent stop carrying persona configuration, and subagent
  children now render the deployment persona like every other agent.
- Example personas drop transport/interface trivia (ACP, CLI) — facts
  irrelevant to the model.
- Root CONTEXT.md removed (not idiomatic); its persona definition was
  wrong under the new ownership anyway.
- Docs, READMEs, the prompt-variables RFC, and generated catalogs
  updated; new loop test pins the assemble-waterfall escape valve
  (an emptied assembly sends NO system field).
2026-07-05 23:23:46 +08:00
Tianyi Cui
e6fad266a6 docs(rfc): define and enforce a uniform RFC format; adopt it across the corpus
Define the in-file RFC contract in docs/rfc/README.md § The file format:
the header block (`# RFC: <title>` plus a dateless Status enum
cross-checked against the lifecycle folder), the per-lifecycle body
skeleton (a Problem opener everywhere; Proposal/Alternatives considered/
Acceptance criteria/Risks in proposed/; present-tense Decision/
Consequences with proposal-era headings banned in implemented/; the
frozen proposal shape in rejected/), and a mandatory Alternatives
considered section with a date-fenced grandfather comment for pre-format
RFCs whose alternatives are not reconstructible from the record.

Enforce it with a new doc-sync gate, scripts/verify-rfc-format.ts, and
normalize all 112 RFCs to it: ~15 Status-line spellings collapse to the
enum, 29 Context openers become Problem, the 39 legacy-format XXX debt
markers are resolved and banned from reappearing, proposal-era sections
in implemented RFCs are rewritten to shipped reality (including the
web/fs/subagent seam RFCs' migration plans and test checklists, closing
the doc-tiers deferred-work item on the web seam), every RFC gains an
Alternatives considered section or the grandfather comment, and the
bilingual pair is re-mirrored and re-recorded.

Move the generated index tables out of README.md into a fully generated
docs/rfc/INDEX.md — gen-rfc-index now writes the whole file, and
verify-rfc-classification checks its freshness and rejects index-shaped
rows in the curated README — which makes room for the format contract to
live in the README front door instead of a separate FORMAT.md.

The decision record, and the first RFC written in the new format, is
docs/rfc/implemented/process/2026-07-05-uniform-rfc-format.md.
2026-07-05 22:58:25 +08:00
Tianyi Cui
021dae58e2 Merge remote-tracking branch 'origin/master' into simpl-e-acp-trim
# Conflicts:
#	docs/rfc/README.md
2026-07-04 23:43:20 +08:00
Tianyi Cui
9857bb0c07 Merge remote-tracking branch 'origin/master' into simpl-g-hook-contract
# Conflicts:
#	docs/rfc/README.md
2026-07-04 23:40:05 +08:00
Tianyi Cui
f90f1c358e Merge remote-tracking branch 'origin/master' into simpl-e-acp-trim
# Conflicts:
#	docs/rfc/README.md
2026-07-04 23:22:16 +08:00
Tianyi Cui
c01d8c0dfc Merge remote-tracking branch 'origin/master' into simpl-g-hook-contract
# Conflicts:
#	docs/rfc/README.md
2026-07-04 23:22:08 +08:00
Tianyi Cui
54fc3d65ab Merge remote-tracking branch 'origin/master' into simpl-d-fs-write-only
# Conflicts:
#	docs/rfc/README.md
2026-07-04 23:21:46 +08:00
Tianyi Cui
c64cfbbe5d Merge remote-tracking branch 'origin/master' into simpl-a3-knobs
# Conflicts:
#	docs/rfc/README.md
2026-07-04 23:17:51 +08:00
Tianyi Cui
9862eae898 Merge remote-tracking branch 'origin/master' into simpl-a2-vocab
# Conflicts:
#	docs/rfc/README.md
2026-07-04 23:11:07 +08:00
Tianyi Cui
8f62086feb Merge remote-tracking branch 'origin/master' into simpl-b2-app-boot
# Conflicts:
#	docs/rfc/README.md
2026-07-04 22:58:26 +08:00
Tianyi Cui
5f295de096 Merge remote-tracking branch 'origin/master' into simpl-f-steering-mirror
# Conflicts:
#	docs/rfc/README.md
2026-07-04 22:50:47 +08:00
Tianyi Cui
1ddd6a9eea Merge remote-tracking branch 'origin/master' into simpl-a1-drop-image
# Conflicts:
#	docs/rfc/README.md
2026-07-04 22:46:55 +08:00
Tianyi Cui
80609cca11 Merge remote-tracking branch 'origin/master' into simpl-c-web-observation
# Conflicts:
#	docs/rfc/README.md
2026-07-04 22:39:41 +08:00
Tianyi Cui
0b97b2f7c1 restore hook/result durationMs — review keeps wall-clock audit timing durable
Reverses item 3 of the tighten-hook-protocol-contract RFC per review:
a persistence log is written for future readers, and hook wall-clock
runtime is audit signal (which hook made a turn slow). runHook keeps
its injected now clock and RunHookResult wrapper, the bridges pass the
measured duration through HookResultRecord, the snapshot normalizer
keeps its replay scrub, and the hook fixtures carry the field again.
The RFC records the reversal; the other three prunes stand.
2026-07-04 22:00:12 +08:00
Tianyi Cui
663e57c6d6 Merge branch 'simpl-a2-vocab' into simpl-a3-knobs
# Conflicts:
#	packages/core/tools/src/index.ts
2026-07-04 21:20:55 +08:00
Tianyi Cui
5441665585 Merge branch 'simpl-b1-fold-ui-stdio' into simpl-b2-app-boot
# Conflicts:
#	AGENTS.md
#	packages/README.md
2026-07-04 21:14:15 +08:00
Tianyi Cui
7ab322909f Merge branch 'simpl-a1-drop-image' into simpl-a2-vocab 2026-07-04 21:14:14 +08:00
Tianyi Cui
456cb3b532 Merge remote-tracking branch 'origin/master' into simpl-a1-drop-image
# Conflicts:
#	docs/architecture.md
#	packages/compact/compact-basic/README.md
2026-07-04 21:12:33 +08:00
Tianyi Cui
e2cd7379ed Merge remote-tracking branch 'origin/master' into simpl-e-acp-trim 2026-07-04 21:11:25 +08:00
Tianyi Cui
19ae955009 Merge remote-tracking branch 'origin/master' into simpl-g-hook-contract
# Conflicts:
#	packages/hooks/hook-protocol/src/events.ts
#	packages/hooks/hook-protocol/tests/events.spec.ts
#	packages/hooks/hooks-claude/README.md
#	packages/hooks/hooks-claude/src/index.ts
#	packages/hooks/hooks-codex/README.md
#	packages/hooks/hooks-codex/src/index.ts
2026-07-04 21:08:50 +08:00
Tianyi Cui
1905c809e3 Merge remote-tracking branch 'origin/master' into simpl-c-web-observation
# Conflicts:
#	docs/architecture.md
#	packages/web/web/src/index.ts
2026-07-04 20:54:42 +08:00
Tianyi Cui
52addacf66 Merge remote-tracking branch 'origin/master' into simpl-d-fs-write-only
# Conflicts:
#	docs/rfc/implemented/simplification/2026-07-04-prune-write-only-fs-surface.md
#	packages/fs/fs-local/src/fsio.ts
2026-07-04 20:50:40 +08:00
Tianyi Cui
582caee90a Merge remote-tracking branch 'origin/master' into simpl-f-steering-mirror
# Conflicts:
#	docs/cordis-catalog/events-and-services.md
#	packages/core/agent/src/types.ts
2026-07-04 20:44:34 +08:00
Tianyi Cui
ef86a36ef6 Merge remote-tracking branch 'origin/master' into simpl-b1-fold-ui-stdio
# Conflicts:
#	AGENTS.md
#	packages/README.md
2026-07-04 20:38:38 +08:00
Tianyi Cui
5a8234643a refactor(llm): drop the inert request knobs — prefill and strict
GenerateOptions.prefill had no production setter and both adapters
rejected it with LlmError('UNSUPPORTED') — its entire observable
behavior was two throws, each pinned by one adapter test. DeepSeek's
chat-prefix completion is a Beta feature on a base URL neither adapter
targets. ToolSchema.strict was threaded through defineTool, the
registry's schemas() allowlist, the deepseek wire mapping, a per-tool
payload-patching pass in the pi-ai adapter, and a tool-catalog render
row, yet no shipped tool set it and the internal endpoint story for
strict mode was never built.

Remove both fields end-to-end: the vocabulary in dsh-llm, the adapter
guards and wire branches, the dsh-tools threading, the tool-catalog
Strict row, the pinning tests, the core.md pastes, the adapter README
rows, and the cookbook line that used prefill as the UNSUPPORTED
example (now stated generically). The pi-ai payload fixup keeps the
half with a job: pi-ai stamps strict:false on every serialized tool,
so the fixup scrubs it unconditionally for wire parity with the
hand-rolled twin (per-tool set/delete machinery gone). temperature/
stop/maxTokens are untouched — honored end-to-end by both adapters.

Each knob returns with its first real producer: prefill with an
adapter that implements chat-prefix completion, strict with a tool
that wants it and a beta-endpoint story.

RFC: docs/rfc/implemented/simplification/2026-07-04-drop-inert-request-knobs.md
(moved from proposed/, amended to shipped reality); the content-block
vocabulary RFC's consequence line now records prefill as producer-gated.
2026-07-04 18:38:39 +08:00
Tianyi Cui
75b97e7463 docs(rfc): state the pruned-vocabulary RFC as current facts, not patch mechanics
The Decision and Risks paragraphs described the change relative to the patch
that landed it (what was updated together, what another change took first).
An implemented RFC reads as standing truth: the pastes match the pruned maps,
the manifest rows remain because the symbols survive, and the image block's
cache field belongs to the drop-image RFC's record.
2026-07-04 18:04:26 +08:00
Tianyi Cui
3567d000c4 refactor(vocab): prune producer-less variants — cache hints, agent source, continuation trigger
The vocabulary maps grow by declaration merging, and the admission policy
stated on TurnEndReasonMap is that a variant lands with its first emitter.
Three declared items had no producer and no consumer:

- CacheHint and the cache?: CacheHint fields on TextBlock/ToolResultBlock:
  nothing constructs a block with cache:, and neither adapter reads .cache —
  DeepSeek prompt caching is automatic (hints map OUT of responses, never IN).
- MessageSourceMap.agent: zero constructors; the subagent backends send the
  parent prompt with no source (logs as user), and the envelope renderer
  interpolates source.kind without routing on it.
- TurnTriggerMap.continuation: the loop structurally cannot emit it —
  continuation is further steps within a turn, never a new turn — and its only
  writer was an llm-replay test fixture that needed any non-message trigger
  (now an injection trigger).

Each variant returns the day it gains a real producer, via the same
merge-extensible maps. Docs updated in the same change: the MessageSourceMap
paste in core.md, the TurnTriggerMap paste in session.md (manifest untouched —
both symbols survive), the content-block vocabulary RFC's cache-hints
consequence line, and the RFC moved to implemented/ and amended to shipped
reality (the image block's own cache field had already left with the
drop-image RFC).
2026-07-04 17:50:50 +08:00
Tianyi Cui
2745879132 refactor(llm): drop the image content block until a path can honor it
ImageBlock had no production producer and every consumer dropped it:
the deepseek serializer skipped it, the pi-ai converter skipped it as
unrepresentable, the ACP bridge neither advertises image prompt
capability nor forwards image blocks, and compact-basic charged a flat
85-token estimate and rendered an [image] placeholder. A block
constructed today would silently vanish from the wire — the vocabulary
advertised a capability no path honors, the silent-data-loss shape the
defensive patterns warn against. The only constructors were tests
pinning the skip/estimate branches.

Remove ImageBlock and its ContentBlockMap entry (its cache?: CacheHint
field leaves with it; CacheHint itself and the other two cache? fields
are out of scope). compact-basic loses its explicit image estimate and
placeholder arms (the merge-extensible default arms absorb the case);
the deepseek serializer, pi-ai converter, and ACP codec already handled
image in their default arms, so only their image-naming comments
change. The codec's inbound rejection of ACP-protocol image prompt
content stays — that guards wire content a client can send regardless
of our vocabulary.

Tests that constructed harness image blocks to pin the removed branches
are dropped (the 85-token estimate pin) or retargeted onto plugin-added
block types / other non-text blocks, which the surviving default arms
own. Docs, the type-equiv pastes, and the content-block vocabulary
RFC's block list and multimodal-home consequence are updated in the
same change; the RFC moves to implemented/ and the index is
regenerated. A real multimodal feature reintroduces image via
declaration merging together with the adapter mapping, ACP
advertisement, and compaction pricing that honor it.
2026-07-04 17:21:13 +08:00
Tianyi Cui
4a0941fb4b feat(ui): share the app bins' boot glue in @deepseek-ai/dsh-app-boot
The four near-twin helpers the two published bins carried — loadEnv,
installFailLoud, assertEntriesLoaded, boot — live once in
packages/ui/app-boot, parameterized by the bin's diagnostic prefix and
injectable at their side-effect seams (warn sink, process slice), so
every branch sits under the per-file 100% coverage gate: the unit suite
drives boot() in-process against the real Loader (relative-specifier
configs) through both the settled-tree path and the fiber-less-entry
rejection, and exercises the ENOENT/unloadable .env split, the
Error/non-Error/stackless fail-loud arms, and the disabled-entry
exclusion. resolveConfigPath (snapshot-aware) becomes the single path
resolver for both bins.

Each bin.ts is now a thin self-executing composition plus its
app-specific lifecycle (acp: replay env-skip + stdin-EOF dispose;
stdio: nothing extra), exports nothing, and stays coverage-excluded;
the built-bin smokes still prove both artifacts under plain node in the
node_modules-shaped temp dir (now symlinking ui/app-boot), including
the missing-config non-zero exit.

Implements docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md
(moved from proposed/ and amended); the extract-example-app-packages
RFC's bin-ownership facts are amended in the same change.
2026-07-04 16:43:06 +08:00
Tianyi Cui
e9589b523f docs: fix review findings — support-group summary row, smoke-prose export-shape claims
The packages/README.md group table still described support/ as holding
the stdio UI; and three prose sites credited the keyless smokes with
guarding the app export shape, which a bundle without inject cannot do
(a stray default boots rather than crashes) — the shape is pinned by
the stdio-agent unit suite's explicit unwrapExports assertion; the
smokes prove the composed tree boots.
2026-07-04 15:59:12 +08:00
Tianyi Cui
4036300353 refactor(acp): trim unreachable bridge surface (branding knobs, kind-sniffing fallback)
Two pieces of dsh-acp surface were unreachable from any shipped config:

- AcpConfig.agentName/agentVersion: the app package hands the bridge only
  { model, systemPrompt }, so no leaf cordis.yml could set them; they were
  settable only by direct-mounting the bridge (a unit test). Hardcode
  agentInfo at the initialize site and delete the fields, their schema
  defaults, the ?? fallbacks, and the TODO(double-default) whose subject
  vanishes. The handshake wire value is unchanged (all snapshot initialize
  lines byte-identical).

- The toolKindFor name heuristic special-cased bash*/read*/write/edit*
  names in the generic-fallback path, violating the bridge's own design
  rule ("the bridge never special-cases tool names"). Every first-party
  tool ships its kind via presentCall; the fallback now renders the
  neutral kind 'other'. The fallback is reachable when a presentCall
  throws OR when model args fail the tool schema (defineTool's presentCall
  wrapper returns undefined on violations) — the latter shows up in one
  committed golden (hook-codex-posttool-block: three bash calls missing
  the required description), whose kind cells flip execute->other. That
  3-line golden refresh is the whole transcript delta.

The empty-arguments branch of parseToolArguments lost its only exercise
with the deleted heuristic test; it is live behavior (JSON.parse('')
throws, so the guard is what renders a zero-arg call as rawInput {}), so
it gets a dedicated pin instead of deletion.

RFC moved to docs/rfc/implemented/simplification/ and amended to shipped
reality: fallback reachability includes schema-invalid args, and the
golden churn is exactly the three kind cells (the original zero-churn
claim held only for the branding half).
2026-07-04 15:46:11 +08:00
Tianyi Cui
cd49670f4e refactor(hooks): tighten the hook-protocol contract surface
Implement the tighten-hook-protocol-contract RFC (moved to implemented/):

- HookDialect narrows to 'claude' | 'codex': the 'native' variant had zero
  producers (native plugins on the seams write no hook/* provenance), and the
  dialect is defined as the bridge that ran the hook.
- HookOutput.suppressOutput is gone: the codec parsed it and every path
  discarded it with no warn and no deferral — hook stdout never enters a
  transcript, so there is nothing to suppress.
- hook/result.durationMs is gone: durable timing telemetry with no reader
  that the snapshot normalizer had to scrub as replay noise. With no duration
  to measure, runHook loses its injected now clock and the single-field
  RunHookResult wrapper — it returns the HookOutput directly. The committed
  hook fixtures had the field stripped mechanically (field-only diff); the
  stdout goldens never carried it.
- The bridges' double-defaulted defaultTimeoutMs config knob is replaced by
  one reference-default constant, DEFAULT_HOOK_TIMEOUT_MS, exported from the
  lib's runner and applied inside runHook; per-hook timeoutSec stays the
  override surface.
- The hook/result semantics move into the lib that declares the event:
  HookResultRecord now carries the decoded HookOutput and appendHookResult
  derives the decision string (decision ?? stop-on-continue:false ?? pass)
  and the 500-char stderrSummary truncation; both bridges delete their
  byte-identical private copies. The snapshot suite passes against the
  existing goldens, proving the derived values are unchanged.
- Rider: BLOCKING_EXIT_CODE is codec-internal again (zero importers).

Amend the hook-protocol-lib and hook-snapshot-matrix RFCs to the new facts,
update the lib/bridge READMEs and the session.md event tables, and retarget
the affected unit tests (including new lib-level coverage of the derivation
rules).
2026-07-04 15:44:26 +08:00
Tianyi Cui
de79553d4f refactor(web): drop the unconsumed observation surface
WebService exposed an observation surface nothing in production observes:
the web/providers-change event (declared, emitted on every provider
registration/disposal, rollback-yield ordered before the emit solely so a
throwing change listener unwinds the registration) and the aggregated
searchStatus()/fetchStatus() query with its WebCapabilityStatus union.
dsh-tool-web executes through ctx.web.search()/fetch() and routes on the
structured WebError codes selection throws at execution time; tool
registration follows product enablement, not provider availability. The
only listeners/callers were the web packages' own tests, and the
tool-web README / architecture.md prose claiming the tool 'reads only the
aggregated searchStatus()/fetchStatus()' had drifted from the call sites.

Remove the event declaration, both emits, and the rollback-before-emit
machinery (the plain ctx.effect disposer keeps HMR cleanup, matching
LlmService.registerAdapter). Remove searchStatus()/fetchStatus(),
resolveStatus(), and WebCapabilityStatus; the provider-private status()
stays as the execution-time selection input. Delete the listener-throw
rollback test, and rewrite every event/status assertion across the web
packages' tests onto caller-observable behavior: a successful
search()/fetch() or the structured WEB_PROVIDER_* codes. Regenerate the
cordis catalog; update the web/tool-web READMEs, the architecture.md web
paragraph, core-data-structures/web.md, and the type-equiv manifest; amend
the web capability seam RFC's facts to the shipped surface. This follows
the llm/adapter-change precedent: a boot-time backend-registry signal and
an availability probe distinct from executing both sit on the cut side of
its keep/cut criterion.

RFC: docs/rfc/implemented/simplification/2026-07-04-drop-unconsumed-web-observation-surface.md
2026-07-04 15:42:56 +08:00
Tianyi Cui
205f7cd04d refactor(ui): fold the stdio UI helper into the stdio app
The readline UI lives inside @deepseek-ai/dsh-stdio-agent as the
in-package stdio-chat module; the packages/support/ui-stdio package is
gone. The app's front-door cluster always includes this UI and nothing
else composes it, so the boundary bought manifest/tsconfig/module-graph/
README/publint surface for a helper that is not independently
swappable — and a product app no longer depends on a support package
documented as not-product-surface.

createStdioChat, the StdioRuntime test seam, and both unit suites moved
verbatim (imports rewired to the module path); the named
name/inject/Config/apply export shape stays, being the contract the
app's ctx.plugin mount consumes. Coverage stays per-file 100%; the
built-bin smoke under plain node and both keyless Loader-path smokes
prove the published artifact and the demos end-to-end.

Implements docs/rfc/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md
(moved from proposed/ and amended to the shipped shape).
2026-07-04 15:38:03 +08:00
Tianyi Cui
e64623ebfd refactor(fs): prune write-only fields and the dead routing knob from the seam
The fs seam split left four pieces of pre-split surface populated on
every call and read by nobody:

- STREAM_MIN_SIZE + FsIoInternals.streamMinSize in dsh-fs-local: the
  backend has no read routing (readWholeText/streamWholeText are
  separate primitives the caller picks), and the real 10 MiB routing
  constant lives in dsh-tool-fs's read tool. Delete the dead mirror and
  the knob whose JSDoc claimed an override that did not exist; the
  remaining FsIoInternals knobs stay (the atomic-write tests use them).
- FsTarget.inputPath: a "diagnostics only" field every backend and test
  fake had to fabricate, with zero production readers (policy and error
  messages use targetKey/displayPath). listDir gave children the bare
  entry name, which was nobody's input.
- FsEditOutcome.replacements/.replaceAll: replacements had no reader
  (the single-match policy is enforced by the FS_AMBIGUOUS_EDIT /
  FS_EDIT_NOT_FOUND throws, whose message keeps the internal count);
  replaceAll only echoed the replace_all argument back to
  formatEditOutput, which now takes it from the parsed args. The
  outcome shrinks to { version, before, after }, parallel to
  FsWriteOutcome's backend-discovered fields. Emitted text is unchanged
  for both branches (no snapshot churn).
- FileReadOutcome.limit/.version: formatReadOutput renders
  offset/lines/totalLines/truncatedByBytes only, and the fs/observed
  emit uses info.version directly.

Backends shed four fabrication obligations and gain none. Doc pastes
(core-data-structures/filesystem.md), the dsh-fs README resolve row,
and the test fakes shrink with the types. RFC moved to
implemented/simplification and amended to the shipped shape
(FsEditSpec -> FsEditRequest name fix; manifest rows needed no change).
2026-07-04 15:37:43 +08:00