Commit Graph
32 Commits
Author SHA1 Message Date
Tianyi Cui d167af3fb7 Merge branch 'master' into worktree-tasks-service-seam 2026-07-26 22:57:38 +08:00
Tianyi Cui eb2760eeef Merge remote-tracking branch 'origin/master' into web-e2e-interactions 2026-07-26 21:19:26 +08:00
Tianyi Cui f8342b0a8e test(web): cover the settings surface and workspace management
Two new keyless scenarios for the functionality master gained since this
lane's base (#644 websettings, #643 workspace browser rework), both zero
model calls:

- settings-chrome: the modal shell (sidebar-foot trigger aria states,
  role=dialog, aria-current section switch to the deliberately empty
  Models, Escape + close-button paths, dialog aria golden); the Appearance
  row as the REAL theme gesture — retiring lifecycle-chrome's
  TODO(web-theme-gesture): clicking 深色 runs aria-pressed -> persisted
  dsh.theme -> body[data-ds-dark-theme] -> alias-token flip, survives
  reload, and 'system' follows the emulated OS scheme both ways; the
  Language row switches the settings-scoped copy to English (dsh.locale
  persisted, survives reload) and restores zh. Intentional reloads tear
  the SSE stream, so the spec drains exactly its own reconnect warnings —
  the tripwire still fails on unexpected connection loss.
- workspace-management: create-by-name twice through the region-header
  dialog (host-durable via ctx.workspace.list()); rename end to end —
  hover-revealed row menu (the button is display:none until the row
  hovers), duplicate-name pre-check (inline role=alert + disabled primary
  before any wire call), then workspace.rename through the real RPC,
  row update, host durability, reload survival; the flat 'In one list'
  view (section label flips, group headers drop, dsh.workspace.view
  persists across reload, grouped restored); the session hover card
  (dwell to open, closes on pointer leave). The one session row reuses
  seeded-history's committed seed — no new recording. Deliberately not
  driven: the inert menu rows and drag reorder (deferred in the note
  with re-entry triggers).

Agent Note gains scenarios 8-9 and the drag-reorder deferred item in both
languages; llm-replay README's zh side catches up with the { patches }
paragraph; pairings re-recorded.
2026-07-26 20:38:36 +08:00
Tianyi Cui cbb5fc7a51 test(web): lifecycle & chrome scenarios — workspace flow, reload recovery, dark mode
One tiny recorded text turn drives three whole-page concerns:

- workspace flow over the real wire: the empty-state hero's first send
  materializes a real Workspace + Session (the jsdom workspace-flow suite
  pins this state machine over the fixture client; this scenario pins it
  through HTTP RPC + SSE + the gateway). Durable proof: the session
  header's cwd is the create-by-name target <workspaceRoot>/workspace.
  Adds the hero waiting-state aria golden.
- reload recovery: collapse the sidebar (persisted dsh.layout.panels),
  page.reload, and the surface comes back whole from persistence alone —
  layout collapsed, selection restored (dsh.sessions.current), the
  recorded turn re-rendered from session.history with zero model calls
  (the drained replay cursor makes any stray request fail loud at close).
- dark mode: no product control flips the theme yet, so the scenario
  drives the ThemeService's entire DOM contract — body[data-ds-dark-theme]
  — and pins the shipped cascade: the alias token flips, a painted surface
  repaints, and removing the attribute restores the light sample exactly.
  TODO(web-theme-gesture) upgrades to a real settings control; no theme
  golden per the lane's scope ruling (aria is color-blind).

Agent Note scenario list extended in both languages; pairing re-recorded.
2026-07-26 06:08:08 +08:00
Tianyi Cui 4964e9c729 test(web): navigation & panes scenarios over one rich seeded session
One two-turn seed (turn 1: bash + two parallel reads in a single assistant
message; turn 2: a markdown-heavy reply) rendered cold through the
seeded-history pattern — zero model calls — serving four surfaces:

- sidebar search: client-side title filter; asserted only after the durable
  title lands with the attach baseline (a cold SessionSummary carries no
  title — search matches the displayTitle the user sees). Negative query
  empties the tree, positive narrows to the match + its force-expanded
  group, clear restores.
- Trajectory tab: turn sections, the step group's tool mix ('bash read×2'),
  and a view-area aria golden.
- Waterfall tab: span stats header + one lane per span. The P-I fold counts
  a turn-0 prologue span (only assistant/steering nodes carry a turn
  number) — pinned as-is; real spans are P-III per the view's ledger.
- details column: the bash toolview row routes click to openDetails;
  open/closed is asserted on the frame's data-details-collapsed attribute
  because close collapses the grid column to width 0 without unmounting
  the subtree (hidden, not absent, is the contract).

Agent Note scenario list extended in both languages; pairing re-recorded.
2026-07-26 05:15:47 +08:00
Tianyi Cui 698b391bd6 refactor(tasks): split the task registry into seam and local implementation
The tasks/ family now matches the capability-seam shape: @deepseek-ai/dsh-tasks
keeps the abstract TaskService (ctx.tasks contract, vocabulary types, snapshot
invariant companion) and the new @deepseek-ai/dsh-tasks-local carries the
process-local registry (LocalTaskService: in-memory store, settlement,
owner-cleanup effects, teardown, TASK_WAIT_TIMEOUT). Compositions and test
harnesses now load dsh-tasks-local; producers, TaskKindMap merges, and
dsh-tool-tasks keep importing the seam only.

Producer misconfiguration diagnostics name dsh-tasks-local because loading the
implementation is the fix. The registry behavior suite moves to tasks-local;
the seam keeps a stub-subclass registration test and the probe-based invariant
suite.
2026-07-26 05:13:39 +08:00
Tianyi Cui 07770f90f9 Merge remote-tracking branch 'origin/master' into web-e2e-interactions
# Conflicts:
#	.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.i18n.yaml
#	.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.md
#	.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.zh.md
#	apps/web/tests/scaffold.ts
2026-07-26 04:10:37 +08:00
Tianyi Cui 13f7c62318 feat(web): render Code Mode sub-calls as native rows nested under the run_code row
The client indexes tool/code-dispatch events into
ConversationSnapshot.codeDispatches (parent callId -> ToolResultNode-shaped
sub-calls; live mux and history replay build the identical index). ChatView
renders each run_code parent as the new code variant (description summary,
program as the expanded monospace body) with its sub-dispatches as
always-visible indented rows — every sub-row dispatches through the SAME
keyed conversation.chat.toolview hole with the same GenericToolCard
fallback, so custom registrations (bash sample) take over sub-rows exactly
as top-level rows. The details panel resolves sub-callIds to full logged
args and complete output through the native path.

Evidence: fixture turn 64 + built-bundle jsdom snapshot, real-machinery
jsdom suites (nesting, error state, details, running parent, reference
stability), and a recorded code-mode browser e2e round (keyless replay +
aria golden). Scaffold gains a toolsMode patch knob.
2026-07-26 04:02:38 +08:00
Tianyi Cui 04b7f517ae test(web): live-turn interaction scenarios — cancel, error, retry, question composer, steering
Five browser e2e scenarios over the existing keyless lane, one recorded
base fixture per spec family:

- live-interactions: one tool-free recorded turn + per-run override
  sidecars authored in the spec (content single-sourced from the fixture
  via deriveReplayScript, minted into a spec-owned temp dir). Cancel uses
  a hang patch with a readyFile marker — the marker proves the stream is
  parked mid-turn before the Stop click, so mid-stream cancellation is
  deterministic by construction (turn/end 'aborted', composer re-enabled).
  AUTH pins the non-retryable path: turn/end 'error', zero llm/retry
  events, composer recovers; FIXME(web-error-surface) marks the found
  product gap (no error copy renders — the client consumes no agent/error
  frames and a pre-chunk failure freezes no partial). SERVER retry appends
  the fixture's own success after an injected throw and proves llm-retry
  end-to-end in the browser via the durable llm/retry record.
- question-composer: the shipped ask_user_question takeover blocks the
  turn mid-step on the real userInteraction seam; the test answers through
  the composer (the one sanctioned model-content-reactive drive step: the
  turn cannot complete without it) and the tool result carries the answer.
  Adds the composer waiting-state aria golden.
- steering: steers mid-turn while the composer blocks the step (the
  deterministic mid-turn window). The steer rides the real wire
  (session.prompt mode:'steer' POSTed from the page; the locked composer
  has no steering gesture yet — TODO(web-steer-composer)); downstream is
  all product: gateway -> Agent.steer -> step-boundary drain -> durable
  steering/message -> SSE -> badged interjection bubble. Record mode
  rejects a fixture whose live reply ignored the steer.

Scaffold gains the replayOverride passthrough; specs register in both
tsconfig planes (client exclude, host include).
2026-07-26 03:36:55 +08:00
Tianyi Cui 674d916ef8 Merge branch 'master' into worktree/llm-mock-fault-server 2026-07-26 00:45:44 +08:00
Tianyi Cui 882bd4a591 Merge origin/master into web-e2e-lane
# Conflicts:
#	tsconfig.host.json
2026-07-26 00:16:12 +08:00
Tianyi Cui 8af3d2461b Merge branch 'master' into worktree/dsh-arg-parser 2026-07-26 00:05:16 +08:00
Yichen Jiang 5446714177 Merge branch 'master' into worktree/llm-mock-fault-server 2026-07-25 22:27:29 +08:00
Hypatia May 729485216d Merge remote-tracking branch 'origin/master' into session-query-tool
# Conflicts:
#	docs/capability-seams.md
#	packages/host/runtime/README.md
#	packages/host/runtime/package.json
#	packages/host/runtime/src/boot.ts
#	packages/host/runtime/tests/host-runtime.spec.ts
#	packages/host/runtime/tsconfig.json
#	pnpm-lock.yaml
2026-07-25 18:27:39 +08:00
Tianyi Cui ee25ccf38b Merge remote-tracking branch 'origin/master' into web-e2e-lane
# Conflicts:
#	vitest.web.config.ts
2026-07-25 18:19:22 +08:00
Turtle 2243023575 Merge branch 'master' into worktree/dsh-arg-parser
Integrate the Commander adapter with master's headless rework (dsh -p now boots
through AppCLIEntry — the same cordis.yml composition as dsh web, web-observable
while it runs — via toFetchHandler(ctx.apiProxy)).

- headless.ts: keep master's AppCLIEntry-based body but take the adapter's
  pre-parsed `task` (drop the re-added parseArgs). Old startHost path and the
  now-deleted packages/host/runtime dependency are gone.
- remove the stale packages/host/runtime dir left on disk by master's deletion
  (mirrors the earlier packages/ui/acp cleanup).
2026-07-25 17:48:21 +08:00
imccyu 4a27da44cf test(web): real-composition webserver spec
Boots a test-only cordis.yml through the real Loader and asserts the route
service's behavior surface: exact/longest-prefix matching, tapIndex
transform order and unsubscription, traversal 403, non-GET 405, SPA-200
fallback, malformed-request 400 without process exit, duplicate-pattern
throw, dispose closing held connections with register/disposer symmetry,
and a listen-failure fail-loud case (EADDRINUSE -> FAILED fiber + late
rejection). Replaces the retired factory-era specs.
2026-07-25 14:40:45 +08:00
Turtle 2dfd8635e8 Merge branch 'master' into worktree/dsh-arg-parser
Integrate the Commander argument adapter and dsh-front-door work with master's
config-tree `dsh web` (#601: AppCLIEntry + apps/cli/cordis.yml) and the
packages/ui/acp → packages/acp/acp relocation.

- web.ts: keep master's AppCLIEntry-based boot, but take the adapter's parsed
  (host, port, dev) instead of an internal parseArgs. The adapter's host/port
  defaults (127.0.0.1/3080) match cordis.yml, so always passing them is
  behavior-equivalent to master's "undefined keeps the yml default".
- apps/cli/package.json: master's expanded config-tree dep set + commander.
- retire-readline Agent Note: point the TUI refusal proof at
  apps/cli/tests/built-bin.e2e.ts (both languages), re-record the pair.
- READMEs reconciled (demo-bin removal + master's ACP/channel rewording).
2026-07-25 14:37:57 +08:00
Tianyi Cui fb17d5ec49 Merge remote-tracking branch 'origin/master' into web-e2e-lane
# Conflicts:
#	docs/config-catalog.md
#	docs/testing.i18n.yaml
#	docs/testing.md
#	docs/testing.zh.md
#	packages/host/runtime/src/start.ts
#	packages/support/acp-snapshot/README.md
2026-07-25 14:20:19 +08:00
Hypatia May ddac36e46e Merge remote-tracking branch 'origin/master' into session-query-tool
# Conflicts:
#	docs/architecture.i18n.yaml
#	docs/capability-seams.md
#	examples/acp-agent/composition.md
#	examples/acp-agent/cordis.yml
#	examples/acp-agent/tests/snapshots/model-switching/system-prompt.expected.md
#	examples/acp-agent/tests/snapshots/model-switching/tool-schemas.expected.json
#	examples/acp-agent/tests/snapshots/permission-switching/system-prompt.expected.md
#	examples/acp-agent/tests/snapshots/permission-switching/tool-schemas.expected.json
#	examples/acp-agent/tests/snapshots/plan-mode/system-prompt.expected.md
#	examples/acp-agent/tests/snapshots/plan-mode/tool-schemas.expected.json
#	packages/examples/acp-demo/README.md
#	packages/host/runtime/README.md
#	packages/support/acp-snapshot/src/normalize.ts
#	packages/support/acp-snapshot/tests/normalize.spec.ts
#	packages/ui/acp/tests/harness.ts
#	scripts/type-equiv.manifest.json
#	tsconfig.host.json
2026-07-25 14:17:24 +08:00
Tianyi Cui dc9c3fb1ae Merge remote-tracking branch 'origin/master' into worktree/acp-automation-protocol
# Conflicts:
#	docs/capability-seams.md
#	docs/event-producer-consumer.md
#	tsconfig.base.json
2026-07-25 13:05:30 +08:00
Turtle 6cd139a25b Merge branch 'master' into worktree/dsh-arg-parser
Integrate the Commander argument adapter with master's safe session-resume
feature and dsh web --dev flag.

- args.ts: add --dev to the web parser.
- tui.ts: keep master's process.execve in-place resume handoff, but take the
  adapter's parsed (config, resume); inject the resume id through boot's
  prepare(ctx) hook via ctx.provide(RESUME_SESSION_ID_KEY, id) instead of the
  RESUME_SESSION_ID env var; rebuild the re-exec argv as `dsh --resume <id>`.
- app-boot: drop master's replaceResumeArg (no longer needed) alongside the
  already-removed parseResumeArg; add RESUME_SESSION_ID_KEY.
- the four tui-agent/cordis configs read the ctx-provided resumeSessionId via a
  typeof-guarded !!js expression, so resume needs no env var.
- web.ts: keep master's client roster and --dev watch, take parsed host/port/dev.
2026-07-25 12:04:37 +08:00
imccyu f5506cf35f refactor(storage): rename dsh-domain to dsh-storage-domain
The bare 'domain' name was too generic for a published package. The
directory moves to packages/storage/storage-domain, the package becomes
@deepseek-ai/dsh-storage-domain, and the plugin/invariant names follow;
the ctx surface (ctx.storage.domain), the domain/changed event, and all
runtime behavior are unchanged. References, catalogs, graphs, and the
bilingual design note move together.
2026-07-25 11:08:04 +08:00
imccyu e90b0d51df feat(storage): storage hub with named backend registry and data-form mounts
ctx.storage is a pure registration hub: multiple named backends stay
mounted side by side, data forms (domain first) mount via the
merge-extensible StorageForms map. src/backend.ts is the normative
KV-facet contract; tests/contract.ts is the shared conformance suite
every backend runs. Backends expose data-shape facets (kv now, an
append-log facet reserved for the future session-backend migration).
2026-07-25 11:08:04 +08:00
Yichen Jiang 83cccd7ffc feat(llm): add scriptable mock fault server 2026-07-25 08:20:51 +08:00
Tianyi Cui 6d3c25f494 refactor(web-e2e): rename harness -> scaffold; add interaction coverage
The shared test module was named harness.ts inside a repo whose product
IS a harness — hopelessly ambiguous. Renamed to scaffold.ts with
launchWebScaffold/WebScaffold; tsconfig plane-split entries, the seam
JSDoc/README mentions, and both Agent Note languages updated.

Both scenarios gain a Playwright interaction step over the settled
transcript (after the golden capture, so committed aria surfaces stay
untouched): replay-round-trip clicks the reasoning fold open/closed over
wire-delivered state; seeded-history expands a read tool row rebuilt from
the cold log and asserts the recorded result text appears (read rows are
expand-in-place — rowExpands routes the click to the inline fold, not the
details column). test:web 30 passed | 1 skipped.
2026-07-24 22:18:19 +08:00
Tianyi Cui 46b9a91e55 test(web): keyless browser e2e lane — replayed round trip + seeded cold resume
apps/web/tests/harness.ts boots the real web assembly in-process
(startHost llm:false -> installLlmReplay providers-mode -> mountWebPlugins
-> startWebServer) under DSH_SNAPSHOT replay/record/refresh. Barrier
stack: in-process turn/end -> agent.whenIdle (covers the persistence
flush) -> browser settled-poll. Seeding goes through the real persistence
API (semantic-checkpoint precedent); record harvests fixtures from live
session memory and tokenizes {{sessionId}}/{{cwd}}; refresh is the sole
golden writer. Console tripwires fail scenarios on reconnect/gap-repair
self-healing; harness close asserts full replay-fixture consumption.

Scenarios, each with fixtures recorded against THIS assembly via a live
model run: replay-round-trip (real composer -> real bash echo -> settled
markdown + aria golden + world-state event asserts) and seeded-history
(cold sidebar list -> implicit resume on open -> history tool cards from
the log, zero model calls). apps/web/tests are host-plane programs:
excluded from the client-registered apps/web project, included in
tsconfig.host.json (one program cannot hold both Context merge sides).
2026-07-24 19:49:02 +08:00
Turtle 800bafda3b refactor(cli): parse dsh argv through one Commander adapter
Replace the dsh CLI's three hand-rolled parsing idioms (raw argv[0]/includes
dispatch in bin.ts, per-mode node:util parseArgs in headless.ts/web.ts, and the
bespoke parseResumeArg scanner in dsh-app-boot) with a single Commander adapter
in apps/cli/src/args.ts. parseDshArgs resolves argv into a discriminated
DshInvocation union; bin.ts switches on the mode and dynamic-imports the chosen
module, which now consumes already-parsed values.

- web is a real subcommand; --host uses choices and --port an argParser range
  check, moving validation into the parser.
- --resume rejects empty and repeated forms; --prompt rejects empty; a config
  positional after --prompt and a root flag placed before web fail loud.
- adds --help/--version; removes parseResumeArg from dsh-app-boot.
- new apps/cli/tests/args.spec.ts (apps/*/tests added to vitest include,
  apps/cli/tests to tsconfig.host.json); the tui-agent keyless PTY smoke covers
  bin.ts dispatch end to end unchanged.
2026-07-24 19:43:59 +08:00
Hypatia May a350e95165 feat(session-query): add model-facing tools (round 1) 2026-07-24 15:09:55 +08:00
Tianyi Cui e819a586b0 refactor(acp): reduce bridge to automation protocol 2026-07-24 01:40:25 +08:00
Hypatia May 0a0f19cf57 Merge remote-tracking branch 'origin/master' into session-query-search
# Conflicts:
#	.agents/notes/implemented/feature/2026-07-10-session-query-service.md
#	.agents/notes/implemented/feature/2026-07-10-sqlite-session-query-provider.md
#	.agents/notes/proposed/feature/2026-07-10-sqlite-session-query-provider.md
#	docs/architecture.md
#	docs/capability-seams.md
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.md
#	docs/core-data-structures/persistence.md
#	docs/core-data-structures/session-query.md
#	docs/module-graph.md
#	docs/rfc/INDEX.md
#	packages/README.md
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/hooks/hooks-claude/tests/coverage.spec.ts
#	packages/session-persistence/session-persistence-jsonl/src/index.ts
#	packages/session-persistence/session-persistence-jsonl/tests/jsonl.spec.ts
#	packages/session-persistence/session-persistence-sqlite/README.md
#	packages/session-persistence/session-persistence-sqlite/src/index.ts
#	packages/session-persistence/session-persistence-sqlite/src/schema.ts
#	packages/session-persistence/session-persistence-sqlite/tests/sqlite.spec.ts
#	packages/session-persistence/session-persistence/README.md
#	packages/session-persistence/session-persistence/package.json
#	packages/session-query/README.md
#	packages/session-query/session-query/README.md
#	packages/session-query/session-query/package.json
#	packages/session-query/session-query/src/config.ts
#	packages/session-query/session-query/src/index.ts
#	packages/session-query/session-query/src/types.ts
#	pnpm-lock.yaml
#	scripts/gen-doc-graphs.ts
#	scripts/type-equiv.manifest.json
#	tsconfig.host.json
#	tsconfig.json
2026-07-23 13:56:56 +08:00
imccyu 19e6f7d907 refactor(tsconfig): single root solution graph over host/client aggregates
Root tsconfig.json becomes a pure solution (files:[] + two references);
the former root host aggregate moves verbatim to tsconfig.host.json.
New tsconfig.base.client.json carries the shared client compiler shape
(jsx/DOM lib/types:[]), and tsconfig.client.json plus the 12
packages/client tsconfigs extend it instead of restating the trio.
tsconfig.build.json is deleted: the solution covers the full emit graph,
absorbing the command-goal typecheck/build drift.

Consumers migrate to the single graph: typecheck/build scripts and the
lefthook pre-push hook run bare `tsc -b` (pre-push now covers the client
side); the run-gates build gate needs typecheck so two concurrent tsc -b
runs cannot race the same tsbuildinfo; ts-project.ts and the standalone
doc-typecheck mode seed tsconfig.host.json explicitly (never the root
solution — flattening host+client into one program collides the cordis
Context merges); verify-cordis-config BFS seeds the root solution alone.

Per missions/tsconfig-single-graph-migration.md §2–§3.
2026-07-23 03:59:05 +08:00