Commit Graph
399 Commits
Author SHA1 Message Date
Dudu-0223 1409e2ed15 fix: address codex review round 1
Translate a mid-read AbortError from readFile into the seam's structured
FsError('FS_ABORTED') in readWholeText and readForEdit (the streaming/write
paths already did), and make the socket-type probe test reject on a listen
error instead of hanging where unix-domain sockets are unavailable.
2026-06-26 17:45:54 +08:00
Dudu-0223 ef37ce3b9d refactor(fs): split filesystem seam into provider ctx.fs + policy ctx.fileContext
Implements the split-the-filesystem-seam RFC. ctx.fs shrinks to a text-storage
provider seam (resolve/stat/readText/streamText/writeText/editText with branded
FsTargetKey/FsVersion and an explicit FsWriteExpectation); the new
dsh-file-context package owns the model-facing policy (read windowing,
observed-state, write/edit freshness) as the concrete ctx.fileContext service.

Authorization is now freshness-based rather than full/partial view: a windowed
read records the file version and authorizes a later edit when the file is
unchanged, removing the dead-end where reading lines 100-150 of a large file
could not edit line 120. editText stays a provider primitive so version guard +
literal match + atomic rewrite remain one critical section, and the stale check
runs before matching so a stale edit reports FS_STALE_VERSION. tool-fs injects
fileContext, never reaching around to ctx.fs (the no-bypass contract).
2026-06-26 17:23:18 +08:00
Dudu-0223 c7a197fb5f fix(fs-local): reject unsafe text observations 2026-06-22 18:51:30 +08:00
Dudu-0223 ac28e1a1d3 docs: add filesystem data structures catalog 2026-06-22 14:53:36 +08:00
Dudu-0223 5e01564afb Add filesystem capability seam and tools 2026-06-22 10:48:41 +08:00
Tianyi Cui 6b4dc48fbd Merge pull request #89 from deepseek-ai/worktree-lessons-learned
docs(agents): stacked-PR orchestration + sharper real-entry-path lessons
2026-06-21 20:38:31 +08:00
Tianyi Cui a20e3b70b9 Merge remote-tracking branch 'origin/master' into worktree-lessons-learned 2026-06-21 20:37:26 +08:00
Tianyi Cui 5d3e7dd590 Merge pull request #88 from deepseek-ai/worktree-simplify-extract-examples
refactor(examples): extract the app spine into dsh-agent-core + app packages
2026-06-21 20:37:01 +08:00
Tianyi Cui 0b75598c91 Merge remote-tracking branch 'origin/master' into worktree-simplify-extract-examples 2026-06-21 20:36:05 +08:00
Tianyi Cui 7373941493 Merge pull request #87 from deepseek-ai/worktree-simplify-snapshot-goldens
test(snapshot): use session.jsonl as the only session-log artifact
2026-06-21 20:35:41 +08:00
Tianyi Cui c85713d11e Merge remote-tracking branch 'origin/master' into worktree-simplify-snapshot-goldens 2026-06-21 20:34:55 +08:00
Tianyi Cui e770e22486 Merge pull request #86 from deepseek-ai/worktree-simplify-trace-events
simplify(session): fold trace-only usage/error events into load-bearing events
2026-06-21 20:34:41 +08:00
Tianyi Cui 5d7af3be82 Merge remote-tracking branch 'origin/master' into worktree-simplify-trace-events 2026-06-21 20:33:53 +08:00
Tianyi Cui 9f13dd02f6 Merge pull request #85 from deepseek-ai/worktree-simplify-agent-stop
simplify(agent): drop unused public Agent.abort(), keep whenIdle()
2026-06-21 20:33:27 +08:00
Tianyi Cui 4ead67c06d Merge remote-tracking branch 'origin/master' into worktree-simplify-agent-stop 2026-06-21 20:32:21 +08:00
Tianyi Cui 8f50008d8b Merge pull request #84 from deepseek-ai/worktree-simplify-branded-ids
feat(types): brand the bash ids and stop brand erosion
2026-06-21 20:32:05 +08:00
Tianyi Cui 74344a8bd4 Merge remote-tracking branch 'origin/master' into worktree-simplify-branded-ids 2026-06-21 20:30:41 +08:00
Tianyi Cui 2d4c367e51 Merge pull request #83 from deepseek-ai/worktree-simplify-prune-seam
simplify(seams): prune dead methods from the persistence seam
2026-06-21 20:30:14 +08:00
Tianyi Cui fa5cf0afd7 Merge remote-tracking branch 'origin/master' into worktree-simplify-prune-seam 2026-06-21 20:27:19 +08:00
Tianyi Cui 89d9a6679b Merge pull request #82 from deepseek-ai/worktree-simplify-llm-surface
simplify(llm): drop unconsumed adapter-change event and assembled call surfaces
2026-06-21 20:27:04 +08:00
Tianyi Cui df4f8a4dea Merge remote-tracking branch 'origin/worktree-simplify-extract-examples' into worktree-lessons-learned 2026-06-21 20:22:47 +08:00
Tianyi Cui 6cb8f35adb Merge remote-tracking branch 'origin/worktree-simplify-snapshot-goldens' into worktree-simplify-extract-examples
# Conflicts:
#	AGENTS.md
2026-06-21 20:21:37 +08:00
Tianyi Cui 56a2351e08 Merge remote-tracking branch 'origin/worktree-simplify-trace-events' into worktree-simplify-snapshot-goldens 2026-06-21 20:19:16 +08:00
Tianyi Cui fd76791c6b Merge remote-tracking branch 'origin/worktree-simplify-agent-stop' into worktree-simplify-trace-events 2026-06-21 20:18:15 +08:00
Tianyi Cui a6a5892e8a Merge remote-tracking branch 'origin/worktree-simplify-branded-ids' into worktree-simplify-agent-stop
# Conflicts:
#	docs/rfc/README.md
2026-06-21 20:17:29 +08:00
Tianyi Cui 4661905714 Merge remote-tracking branch 'origin/worktree-simplify-prune-seam' into worktree-simplify-branded-ids
# Conflicts:
#	docs/rfc/implemented/simplification/2026-06-20-prune-dead-seam-methods.md
2026-06-21 20:15:21 +08:00
Tianyi Cui 5c0597e9de Merge branch 'worktree-simplify-extract-examples' into worktree-lessons-learned 2026-06-21 19:48:37 +08:00
Tianyi Cui 4d7726ecd3 fix review findings: don't treat disabled entries as load failures; scope the verify-package-paths lib skip to a real package root
assertEntriesLoaded() flagged ANY fiber-less entry as a failed import, but a
`disabled: true` entry settles without a fiber by design (Entry.refresh() skips
init() when disabled) — a valid "plugin off" config, not a broken import. Both
app bins now filter `fiber === undefined && !entry.disabled`. The stdio built-bin
smoke gains a disabled-(unresolvable)-entry config that must still boot.

The verify-package-paths lib-skip was unconditional and ran before the
moved-package check, so a stale group-less `packages/acp-agent/lib/bin.js` (the
exact drift this gate catches) was silently ignored just for containing `lib`.
Scope the skip: only exempt `lib` when it is the segment after an EXISTING
`packages/<group>/<pkg>` root, so a real-but-unbuilt `lib/bin.js` is still exempt
while a stale package path flags.
2026-06-21 19:47:22 +08:00
Tianyi Cui 64976df216 Merge branch 'worktree-simplify-extract-examples' into worktree-lessons-learned 2026-06-21 18:38:56 +08:00
Tianyi Cui 9f5e2b352c Merge branch 'worktree-simplify-snapshot-goldens' into worktree-simplify-extract-examples 2026-06-21 18:38:50 +08:00
Tianyi Cui ebe8c8e21f Merge branch 'worktree-simplify-trace-events' into worktree-simplify-snapshot-goldens 2026-06-21 18:38:40 +08:00
Tianyi Cui f09a88ecee Merge branch 'worktree-simplify-agent-stop' into worktree-simplify-trace-events 2026-06-21 18:38:29 +08:00
Tianyi Cui 2903f96548 fix review findings: RFC says session.jsonl is required for every snapshot scenario
The required-fixture-guard description still said session.jsonl was needed only
for model scenarios, but the harness passes <dir>/session.jsonl to llm-replay
unconditionally, so loadReplayScript() fails for a no-model scenario without it.
The code already requires it for all scenarios; align the RFC prose.
2026-06-21 18:36:13 +08:00
Tianyi Cui d0e1b02a7f fix review findings: correct whenIdle live-consumer claim in the stop-surface RFC
The retained-whenIdle paragraph claimed "live consumers (the ACP bridge's settle
points)", but `packages/ui/acp/src` has no whenIdle() call — the bridge owns its
agents and tears them down via AgentHandle.dispose(). whenIdle()'s live consumers
are ACP and agent TESTS awaiting settlement through the public seam. State that.
2026-06-21 18:36:04 +08:00
Tianyi Cui b7d018580e fix review findings: skip lib/ build-output refs in verify-package-paths; resolve acp built-bin npm deps from the declaring package
verify-package-paths flagged the new built-bin smokes' `lib/bin.js` citations
as stale-source drift, failing CI: doc-sync runs BEFORE build, so the build
output is absent at lint time. The gate targets moved SOURCE paths, so skip any
reference whose target goes through a `lib/` segment — mirroring how the file
scan already excludes `lib/`.

The acp built-bin smoke resolved `zod`/`@agentclientprotocol/sdk` via
`import.meta.resolve` from the test file's own context, but `acp-agent` does not
declare them — `dsh-acp` does. Under pnpm's strict layout they are not exposed
where the test resolves, so the new CI built-bin step failed with
"Cannot find package 'zod'". Resolve each from the `ui/acp` package URL (the one
that declares it) instead.
2026-06-21 18:35:46 +08:00
Tianyi Cui a96b1e3ae7 docs(agents): capture stacked-PR orchestration + sharper real-entry-path lessons
Three hard-won lessons from running a 7-PR simplification stack through two
waves of review feedback:

- New "## Orchestrating review feedback across a stacked PR chain" section: one
  worktree per branch; a fix belongs on the PR that introduced the issue then
  flows DOWN; review-fixes are separate commits never amends; delegated work is
  trust-but-verify (prove a regression guard FAILS on unfixed code); reply
  in-thread on the merits.
- "## Conventions" gains a "Never rewrite a pushed branch" rule next to the
  merge-commit rule: update a child by merging the parent down, never
  rebase/amend/force-push a pushed branch; a fix lands on its originating PR.
- Extended the "Line coverage is not behavior coverage" defensive-patterns
  bullet with two corollaries this stack re-taught: (1) a real-load-path test
  only GUARDS the export shape if a broken shape actually FAILS it — an
  inject-less composition plugin boots fine on a stray `export default`, so it
  needs an explicit no-default + unwrapExports assertion; (2) "real entry path"
  means the PUBLISHED artifact (built lib/bin.js under plain node), not the dev
  runtime (tsx), which masks boot settle-races, module-resolution differences,
  and a load failure that loader.await()'s Promise.allSettled swallows.
2026-06-21 17:17:00 +08:00
Tianyi Cui e63641bcfd Merge branch 'worktree-simplify-snapshot-goldens' into worktree-simplify-extract-examples 2026-06-21 15:48:33 +08:00
Tianyi Cui e04ca55374 fix review findings: require session.jsonl for every snapshot scenario
The per-kind fixture guard claimed no-model scenarios need no session.jsonl, but
the replay path requires one for ALL scenarios: runScenario() passes
`fixtureFile: <dir>/session.jsonl` unconditionally and llm-replay's
loadReplayScript() throws "fixture not found" when it is absent and no override
replaces it. A no-model scenario ships a header-only session.jsonl that derives
to an empty script. The guard + its comment now match that reality, so a future
no-model scenario following them won't fail at subprocess startup.
2026-06-21 15:46:38 +08:00
Tianyi Cui 3567808171 fix review findings: harden the app bins + built-bin smokes, arch-exception doc, snapshot fixture-guard
BLOCKER — the published lib/bin.js (stdio + acp) was exercised only via tsx
(demo:* / the src/bin.ts smokes); the built artifact under plain `node` was
unguarded. Root-cause on the BUILT bin:
  1. Settle race: boot() returned once loader.create() registered the include
     ENTRY, but the include loads its child plugins asynchronously — so boot()
     (and main()) resolved while the app plugins (stdin reader, agent loop, ACP
     bridge) were still mounting. A CLI with no attached handles yet exits 0
     silently, and a load error surfaces as an unhandled rejection AFTER boot.
     Fix: `await ctx.loader.await()` after create() — settle the whole tree.
  2. Config-path robustness: hand the include the config's ABSOLUTE file:// URL
     so resolution never depends on ctx.baseUrl / can never fall back to cwd.
Both bins fixed identically. NOTE: the cordis Loader resolves a config's bare
plugin specifiers via its internal module loader, active only under
`node --expose-internals`; the bin cannot add a node flag itself, so this is
documented in the bin JSDoc + both package READMEs (the demos already comply).
The repo `examples/*/cordis.yml` are tsx-only artifacts (workspace plugins
resolve through the tsconfig paths map, not node_modules), so they are not a
valid plain-node bin target — the smokes use a real-install-shaped temp dir.

Fail loud on a load failure: boot() previously exited 0 SILENTLY when a config
path's directory does not exist — the include plugin fails to IMPORT, the cordis
Loader catches+LOGS it and leaves the entry with no fiber (no rejection), and
`loader.await()` does not rethrow (EntryTree.await uses Promise.allSettled). Fix:
boot() now calls assertEntriesLoaded(ctx) after the tree settles and throws on
any entry with no fiber, so a typo'd config dir exits non-zero with a clear
message. main() also installs an unhandledRejection guard (installFailLoud) that
replaces Node's stack dump with a single labelled stderr line for the
companion case (a missing config FILE in a real dir, whose include-init throw
surfaces as a rejection Node already exits non-zero on). Regression tests added
to both built-bin smokes (missing dir + missing file → non-zero exit + stderr);
verified the missing-dir test fails on the pre-fix bin.

Built-bin smokes (the reviewer's ask): packages/ui/{stdio,acp}-agent/tests/
built-bin.e2e.ts run the REAL lib/bin.js under `node` (NOT tsx) in a temp
consumer dir, asserting the stdio echo round-trip / the acp initialize response
+ stdout purity, plus the fail-loud cases above. They build-gate (skip if lib/
absent) and run in a new ci.yml step after the build.

Issue 2 — packages/README.md + docs/architecture.md said "plugins depend on
interfaces, never on the concrete loop", but dsh-agent-core imports the concrete
dsh-agent-loop. Scope the rule to EXTENSION plugins and carve out the sanctioned
COMPOSITION/bundle exception (dsh-agent-core composes the concrete spine); note
it in the implemented RFC too.

Issue 3 — examples/acp-agent/tests/acp.snapshot.ts fixture-guard claimed
no-model scenarios need no session.jsonl, but runScenario() always boots
llm-replay with the session.jsonl path and loadReplayScript() throws when it is
absent. Require session.jsonl for ALL scenarios (no-model ones ship a
header-only fixture) and rewrite the comment to match reality.
2026-06-21 15:39:24 +08:00
Tianyi Cui 9e86fd995c fix(ci): repoint the demo smoke test at the dsh-stdio-agent bin
The CI "Demo smoke test" step booted the deleted examples/echo-agent/start.ts
(removed when the boot glue moved into the dsh-stdio-agent bin), so CI failed on
node 24 + 26 while the local gates and e2e passed. Invoke `pnpm run demo:echo`
instead of hardcoding the boot path — that routes through the canonical demo
script, so the smoke can never drift from it again. The output assertions and
the .sessions/_no-cwd/main-session-*.jsonl artifact check are unchanged
(verified the new bin produces identical output).
2026-06-21 14:23:19 +08:00
Tianyi Cui bfc5a9097d fix review findings: soften the last stdout-purity overclaim in the acp-agent module doc
The acp-agent README/RFC overclaim was already softened; this module doc comment
still said the footgun is "structurally unreachable from the leaf". A leaf
cordis.yml CAN still add a sibling @cordisjs/plugin-logger-console — the app does
not prevent it. Reword to the accurate claim: the app gives the default front
door no logger entry to misconfigure, and the "never add a stdout logger to an
ACP leaf" rule still stands.
2026-06-21 13:08:11 +08:00
Tianyi Cui 66e56bd395 fix review findings: stale coding-agent README, export-shape guards, overclaim wording
Codex review of PR #88 found three issues in the example-app extraction:

A1 — examples/coding-agent/README.md's plugin table still listed the OLD
direct-wired leaf entries (agent-loop, session-persistence, src/stdio-chat.ts —
the whole src/ dir is gone). Rewrite it to the four real leaf entries the
current cordis.yml loads (hmr, llm-deepseek, bash, stdio-agent), noting that
tool-bash/persistence/agent/loop now live inside the agent-core + stdio-agent
bundles.

A2 — the three new app/spine packages (agent-core, stdio-agent, acp-agent)
export NO `inject`, so a stray `export default apply` would let unwrapExports
collapse the module and silently DROP name/Config WITHOUT crashing — the
real-load-path smokes would stay green. agent-core is never Loader-unwrapped at
all. Add an explicit export-shape guard per package: assert no `default` export
and that the real Loader.unwrapExports leaves name/Config/apply intact. Verified
each fails when `export default apply` is added.

B — soften "structurally unreachable / cannot wire a stdout logger" overclaims
in the acp-agent/agent-core READMEs and the implemented RFC: a leaf CAN still add
a sibling logger entry; the accurate claim is the app omits one so the default
leaf has nothing to get wrong. Keep the safety directive (never add a stdout
logger to an ACP leaf).
2026-06-21 12:49:59 +08:00
Tianyi Cui 47afcb297f Merge PR6 (snapshot golden removal + PR5 trace-events) into PR7 2026-06-21 12:10:49 +08:00
Tianyi Cui e2bde2902c refactor(examples): extract the app spine into dsh-agent-core + app packages
Implements docs/rfc/.../2026-06-20-extract-example-app-packages.md. Each
example was thick — a hand-rolled start.ts, an infra preamble, nested
base.yml/base-core.yml/acp-tail.yml includes, and a coupled front-door
cluster enforced only by prose. This moves the composition into packages so
each example is a thin leaf cordis.yml: pick the swappable backends, load one
app package.

New packages:
  - @deepseek-ai/dsh-agent-core (packages/core/agent-core): one bundle plugin
    that loads the providerless/executor-less/UI-less spine (timer + llm +
    sessions + system-prompt + tools + agents + invariants + tool-bash +
    agent-loop) via ctx.plugin(...) inside apply(), and forwards agent-loop's
    `agents` list as its own Config (export const Config = AgentLoop.Config,
    default []).
  - @deepseek-ai/dsh-stdio-agent (packages/ui/stdio-agent): terminal chat APP —
    agent-core + console logger + readline UI + a pre-created `main` agent, with
    a bin. The demo:echo/coding front door.
  - @deepseek-ai/dsh-acp-agent (packages/ui/acp-agent): ACP server APP —
    agent-core + JSONL persistence + the acp bridge, NO stdout logger, with a
    bin. The stdout-purity footgun is structurally unreachable from the leaf.

Amendment to the RFC: hmr stays a LEAF cordis.yml entry, not baked into
dsh-stdio-agent. hmr is a Loader-only dev plugin (throws without
--expose-internals; the in-process test tier can't even import its decorator
form), so a package statically importing it could never carry the per-file
coverage gate. Unlike the console logger, a stray hmr is not a stdout-purity
footgun, so leaving it at the leaf costs no safety. With hmr out, all three new
packages carry in-process unit specs at 100%.

Boot glue (Loader tail, .env load, snapshot-mode selection, stdin-dispose
lifecycle) moves into each app's bin; start.ts and base.yml/base-core.yml/
acp-tail.yml are deleted. Each app package gets a keyless real-load-path test
that boots through its bin + the cordis Loader (guarding the unwrapExports
export-shape bug class, postmortem 0001). ACP snapshot replay stays green
against the existing committed goldens (pure boot restructuring). RFC moved
proposed->implemented with the amendment recorded; package/example/architecture
docs and the module graph updated.
2026-06-21 12:06:38 +08:00
Tianyi Cui ed2e230f20 Merge PR5 doc-sync fixes (b4471e5) into PR6 2026-06-21 11:34:46 +08:00
Tianyi Cui 2eb6ad3260 fix review findings: sync stale v1/removed-event doc references
Codex's re-confirmation pass verified both blocker fixes correct but found
doc/comment drift the fix commit missed:

- session/index.ts + session/README.md: "minimal v1 header" → "minimal header
  (stamped with the current SESSION_FORMAT_VERSION)" — the version is 0, not 1.
- session/index.ts deriveMessages comment listed "usage, and errors" as trace
  data — those standalone events no longer exist; only boundaries + chunks are.
- session-persistence RFC: "no v1 migration" → the pinned-v0 pre-release stance.
- collapse-trace-only RFC format-version note: reframed off the "bump the
  version and reject" wording (which now reads as the OTHER AGENTS.md stance)
  onto the pinned-0 unstable stance the session log actually uses.
- agent-loop/loop.ts finishError JSDoc: "with a logged `error` event" → the
  failure is recorded on turn/end.reason (no standalone error event).
- acp/acp-feature-support.md (two spots): usage is recorded on assistant/message
  now, not as standalone internal usage events.
- Regenerate the cordis catalog (finishError JSDoc line shift).
2026-06-21 11:33:41 +08:00
Tianyi Cui 655206848d Merge PR5 (trace-event collapse + v0 format pin) into PR6
# Conflicts:
#	examples/acp-agent/tests/snapshots/cancel/session.golden.jsonl
#	examples/acp-agent/tests/snapshots/cancel/session.jsonl
#	examples/acp-agent/tests/snapshots/error-finish/session.golden.jsonl
#	examples/acp-agent/tests/snapshots/error-finish/session.jsonl
#	examples/acp-agent/tests/snapshots/multi-turn/session.golden.jsonl
#	examples/acp-agent/tests/snapshots/text-turn/session.golden.jsonl
#	examples/acp-agent/tests/snapshots/tool-call-turn/session.golden.jsonl
#	examples/acp-agent/tests/snapshots/workspace-edit/session.golden.jsonl
2026-06-21 11:12:48 +08:00
Tianyi Cui b0422f2a50 fix review findings: bump session format version + restore late turn-end warn
Codex review of the trace-event fold found two merge-blockers.

Blocker #1 — format version. Folding usage onto assistant/message and removing
the standalone usage/error events changed the persisted SessionEventMap shape,
which per the AGENTS.md "bump the version and reject — don't migrate" policy
requires a backend to reject any non-current log. Centralize the version in an
exported SESSION_FORMAT_VERSION constant (dsh-session), read by both write sites
(Session constructor default, SessionStore.prepare header) and the coordinator's
load-time assertVersion check. The constant is pinned at 0: while unreleased the
on-disk format is unstable/pre-release, so breaking shape churn is absorbed at v0
(no monotonic bump until the first tagged release) and any non-0 log is rejected
on load — no migration. Update every test/fixture/doc that stamps a
currently-written header to the constant, bump the ACP snapshot fixture + golden
headers to v0, and keep the version-rejection test meaningful by switching its
bad value to a clearly non-current 99. AGENTS.md documents both the monotonic
(SQLite SCHEMA_VERSION) and pinned-0 (session log) pre-release stances.

Blocker #2 — restore the late turn-end warn. failTurn now sets the error reason
only while the turn is still open; once turn/end is appended (a throwing
agent/turn-end listener after closeTurn) the reason can no longer reach the
durable log, so the late throw is logged via ctx.logger.warn instead of
vanishing into a futile post-close assignment. A regression test asserts the
warn fires.

Also guard the normal-step assistant/message append with the same
content-or-usage condition as the max-tokens branch (a content-less, usage-less
step records no trace-only row), with a covering test.
2026-06-21 11:08:10 +08:00
Tianyi Cui 00d7646558 fix review findings: make the prune-seam RFC + index match the persistence-only shipped scope
The reviewer caught two pieces of both-seams drift left over after the bash
get()/list() removal was reverted to a persistence-only change.

- docs/rfc/README.md: rename the index row from "persistence and bash seams" to
  "Prune dead methods from the persistence seam" so it matches the RFC title and
  the actually-shipped scope (verify-rfc-classification only checks the path is
  indexed, so this prose slipped the gate).
- The implemented RFC body still read like the original both-seams proposal
  (the "Two capability seams" framing, a `### BashExecutor.get()/.list()` problem
  section, a bash removal bullet in the Proposal, and current-source links that
  imply bash get/list were removed). Rewrite the body into the durable
  decision-record form: Problem/Proposal/criteria/risks now describe only the
  persistence has()/delete() removal that shipped, and the bash reasoning (why
  get()/list() earn their keep — a ~35-line test-harness migration cost makes the
  test consumer a real consumer) is folded into the top decision note as
  "considered and deliberately kept", not as a shipped change. Drop the stale
  bash source-line refs; keep the persistence consumer links pointing at current
  code (agent-loop load, ACP session/list).
2026-06-21 11:05:56 +08:00
Tianyi Cui 83e97ed222 fix review findings: document the util/ group + align branded-ids RFC with dsh-brand
Adding packages/util/brand/ created a new top-level packages/util/ group that
the hierarchy/dependency docs never enumerated. Document it:

- Add packages/util/README.md, the group README (low-level zero-dependency
  utilities shared across groups; lists dsh-brand).
- packages/README.md: add the util/ group to the group table, dsh-brand to the
  package table, and dsh-brand to the dependency graph. Correct the now-false
  "no harness deps" claims — dsh-llm and dsh-bash both depend on dsh-brand
  (verified dsh-bash imports Branded from dsh-brand, not dsh-llm; dsh-session
  and dsh-agent depend on it too).
- Root AGENTS.md Repository Layout: add the util/ group with brand/.

Align the implemented branded-ids RFC with what shipped: Branded lives in
@deepseek-ai/dsh-brand (packages/util/brand/), and dsh-bash depends only on
that utility package instead of dsh-llm. Fix the BashTaskId import source, the
illustrative snippet, and the opening policy reference (now dsh-brand).
2026-06-21 11:04:28 +08:00