Commit Graph

3080 Commits

Author SHA1 Message Date
Turtle
3feb05fef8 docs(agent-notes): consolidate superseded decisions 2026-07-25 16:43:07 +08:00
Tianyi Cui
9873240390 fix: align empty-response retry with current master 2026-07-25 14:39:57 +08:00
Tianyi Cui
4d9cf310f3 Merge origin/master into feat/llm-empty-response-retry 2026-07-25 14:22:46 +08:00
Tianyi Cui
8c1280fa7d Merge origin/master into fix-webplugins-watch-flake 2026-07-25 13:28:23 +08:00
Tianyi Cui
d67be60933 Merge origin/master into fix-webplugins-watch-flake
# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.md
#	.agents/notes/implemented/architecture/2026-07-23-client-plugin-loading-model.zh.md
#	packages/host/webserver/tests/web-plugins.spec.ts
2026-07-25 13:23:42 +08:00
Tianyi Cui
c429ef0e95 Merge branch 'master' into feat/llm-empty-response-retry 2026-07-25 13:05:55 +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
Tianyi Cui
2cb23a8481 Merge branch 'master' into worktree-wspace-storage 2026-07-25 12:50:36 +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
71923d7213 chore(storage): exempt the copied sqlite open sequence from clone detection
The jscpd gate flags the deliberately mirrored open/stamp sequence
against session-persistence-sqlite and session-query-sqlite. The copy
is the settled this-phase choice — this group is the third user and the
shared medium helper is deferred to the log-facet migration so the
session packages stay untouched (reuse audit in the design note); mark
the span accordingly.
2026-07-25 11:08:04 +08:00
imccyu
507dd25a3a fix(storage,workspace): review-bot findings — emit isolation, domain ownership, null globals
- domain/changed emission is isolated from the write path: an observer
  throwing synchronously can no longer turn a committed (durable +
  in-memory) write into a rejection; the failure is logged and later
  writes proceed.
- Domain lifecycle belongs to the opening consumer: Domain gains an
  idempotent close() (drain, unit close, reservation release), the
  facility stops registering effects on its own context and instead
  closes any still-open domains on unmount; WorkspaceRegistry holds its
  domain through its own effect, so disposing and re-mounting the
  consumer no longer wedges on already-open.
- defineDomain rejects a global schema accepting null at declaration
  time: JSON null is the medium's absence sentinel, so a nullable global
  could never round-trip; failing loud at the spec keeps set(null)
  unrepresentable.

Regression tests cover all three (hostile listener, close/reopen and
consumer re-mount, nullable-global rejection).
2026-07-25 11:08:04 +08:00
imccyu
1bddf5269a fix(storage): keep the json loadAll closed guard a rejection
Dropping async for the lint gate turned the closed-unit guard into a
synchronous throw, breaking the conformance clause that every post-close
operation rejects. Restore async with a justified require-await disable;
the guard's rejection semantics are what the shared suite pins.
2026-07-25 11:08:04 +08:00
imccyu
2e986ee1e3 style(storage,workspace): satisfy the repository lint gate
eslint --fix formatting sweep plus the manual residue: sync method
bodies drop async behind Promise-returning signatures (the sqlite unit
routes primitives through a settle() guard preserving the never-throws-
synchronously contract), catch callbacks type their reason as unknown,
loadAll's global slot is plain unknown (null semantics stay in JSDoc),
a non-null assertion becomes a narrowing, and unsafe any assignments in
tests gain explicit types. One justified eslint-disable for
prefer-promise-reject-errors follows the core/session precedent —
wrapping would discard the original StorageError code.
2026-07-25 11:08:04 +08:00
imccyu
0559e0207e chore(storage,workspace): gates — coverage, catalogs, bilingual note
- Per-file 100% coverage across the five new packages (invariant
  companion suites, failure-injection negatives, lifecycle and
  malformed-medium branches).
- Canonical README Model Experience / Known Limitations sections; new
  storage/ and workspace/ group READMEs; packages/README.md rows (budget
  ceiling raised 760 → 790 for the two new groups).
- Cordis catalog/type-link registrations, service-role classification,
  and regenerated catalogs/graphs for the new services and events.
- Agent Note: English body + i18n pairing record; design-sketch fences
  opted out of doc-typecheck as ignore-check.
- Two exactOptionalPropertyTypes/discriminant fixes in new tests.

doc-sync (24 gates), typecheck, hygiene, and the five-package suite
(92 tests) all pass.
2026-07-25 11:08:04 +08:00
imccyu
80b3b6d917 fix(storage,workspace): post-review hardening
Review findings applied across the group:
- storage hub: stale disposers no longer remove a successor registration;
  the package now default-exports the Storage service class per the
  service-package export shape.
- json backend: failed publishes roll back the authoritative memory state
  (a rejected write can no longer resurface via get() or ride the next
  publish); close() drains in-flight writes and blocks in-flight opens;
  double-open rejects as a plain caller error instead of malformed-medium.
- sqlite backend: loadAll builds records on a null prototype (__proto__
  keys round-trip instead of polluting), user_version is stamped only
  after the schema is fully created, and corrupt record JSON rejects as
  malformed-medium instead of a bare SyntaxError.
- domain form: writes persist before mutating authoritative memory or
  emitting; DomainChanged is a put/deleted discriminated union.
- workspace: attach/detach idempotence decided on the write chain (stale
  snapshots no longer short-circuit), create() requires a directory, and
  startup fails loud on duplicate stored paths.

Eleven regression tests pin the fixed behaviors.
2026-07-25 11:08:04 +08:00
imccyu
013e6f8769 feat(workspace): persistent workspace entity over the domain form
ctx.workspace registry owns WorkspaceId-branded records: realpath-
normalized unique paths (create rejects collisions; resolveByPath shares
the normalization), ordered sessionIds as the single source of ownership
truth, attachSession gated on the session header cwd matching the
workspace path (double-booking structurally impossible), dead session
ids filtered on projection and pruned on the next mutate, status()
reporting missing directories. No delete surface this phase — deletion
ships together with the session-side primitives as future work.
2026-07-25 11:08:04 +08:00
imccyu
7c27107be4 feat(storage): domain data form — typed schemas over opaque KV units
ctx.storage.domain opens declared domains: zod value schemas parsed at
the durable boundary, one write chain per domain (update(fn) is the only
read-modify-write), domain/changed emitted per record after durability
(new snapshot + operation, no old value, per repo event convention).
Domain-to-backend routing is configuration (default backend + per-domain
overrides); unknown names and missing facets fail loud. Ships the
MemoryStorageBackend test helper and a runtime invariant asserting every
change event matches the in-memory state.
2026-07-25 11:08:04 +08:00
imccyu
9dee9e1a71 feat(storage): sqlite backend — one database hosting all routed units
node:sqlite DatabaseSync with the session-persistence-sqlite open
sequence (0o700 dir, exclusive 0o600 create, foreign_keys, configurable
journal mode, user_version stamp-or-reject). STRICT tables throughout:
units/unit_globals meta tables plus one document-per-row table per
declared unit table, keeping per-key durable updates precise.
2026-07-25 11:08:04 +08:00
imccyu
1529be6fd4 feat(storage): json backend — one human-readable file per unit
Atomic whole-file replacement (same-dir temp + fsync + rename + parent
fsync); the in-memory unit state is authoritative and the file is always
the current net state, pretty-printed. Missing files open as empty units
and materialize on first write; foreign or unparsable files reject with
malformed-medium, stored-version drift with version-mismatch.
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
imccyu
2e27b8aeef chore(web): gate repairs for the config-tree boot round
Lint (bridge JSDoc params, service-class export shape, async invariant
listener form), regenerated doc catalogs/graphs with role classifications
for httpServer and clientModuleHost, catalog type-link exemptions for the
route/graph contracts, knip alignment (apps/cli composes via cordis.yml so
its yml-named deps are runtime edges knip cannot see; webserver's deleted
test dir), the zh side of the loading-model note brought along with its
pairing records, and coverage exclusions for the new web-transport halves
under the GUI test-lane TODO (real-composition harnesses land with that
lane).
2026-07-25 10:38:54 +08:00
imccyu
80cd8f54b5 refactor(web): collapse the shell boot into the AppWebEntry class
The four free functions in boot.tsx become one kernel class holding what
must exist before cordis: the parsed BootManifest, the ClientModuleSystem
instance, and the loading-page handles. Context/Loader setup runs in
parallel with the immediately-tier prefetch, but entry creation awaits the
prefetch: materialization is tree.import's synchronous require, so
cross-package require edges (i18n -> runtime/client) need every
immediately-tier factory registered first — unbarriered creation raced
10-25% of boots. The kernel adopts the modules entry (writes the
__DSH_MODULES__ slot pre-cordis, creates the entry first, skips its graph
row), and provide('modules') now lives in the adoption apply. apps/web
drops its host-package edges (composition is apps/cli's job).
2026-07-25 10:23:40 +08:00
imccyu
8d4aa73abe feat(web): grow real node halves in connection and hmr
connection binds the web transport: it injects httpServer + apiProxy and
registers toFetchHandler(ctx.apiProxy) under the /api prefix (the node:http
to fetch bridge moves in from the webserver, keeping the res-close disconnect
detection and drain/close backpressure waits). hmr owns dev reload: a
stat-poll watch per graph row driven by clientModuleHost.onGraphChanged,
rebuilt(id) on content change, and the /plugins/events SSE route (GET/HEAD
guarded); frame types are single-sourced in events.ts shared by both halves.
2026-07-25 10:23:40 +08:00
imccyu
c12277b4bb feat(web): make dsh-client-modules dual-face with an incremental host scan
The node half is ClientModuleHostService (ctx.clientModuleHost): it composes
the __DSH_BOOT__ graph by scanning loader entries for dshClient packages,
serves /plugins/<id>/client.js, taps the index render, and exposes
rebuilt/onRebuilt/onGraphChanged. Scanning is incremental per package — no
full-rescan path exists: internal/plugin marks the fiber's entry name dirty,
a flush reconciles each name against live entries, package metadata
(including negative verdicts) caches forever, and re-hashing is reachable
only through rebuilt(id). The browser half moves wholesale to the standard
./client export (ClientModuleSystem, parseBootManifest with the dual-view
BootManifest, and the adoption plugin face that reads the
window.__DSH_MODULES__ slot and provides ctx.modules).
2026-07-25 10:23:40 +08:00
imccyu
f499872cec refactor(web): rewrite webserver as a plain route-registration plugin
HttpServerService provides ctx.httpServer: register(route) -> disposer
(duplicate patterns throw), tapIndex transforms in registration order, and
the bound port; matching is exact > longest prefix > static dist fallback
(403/405/SPA semantics preserved). The server listens on activation, answers
per-request failures with 400 + a log line instead of exiting the process,
and knows no harness concepts — the boot graph, bundle routes, SSE channel,
and /api prefix all moved to their owning plugins.
2026-07-25 10:23:39 +08:00
imccyu
3cad7f6957 refactor(web): upgrade apiproxy to the api-gateway service plugin
createApiProxy moves from dsh-host-runtime into dsh-host-apiproxy (the
dependency direction already pointed this way); the package now
default-exports ApiProxyService (config {provider, model}, provides
ctx.apiProxy) while staying transport-agnostic — it registers no routes.
Runtime keeps bootHost/startHost for the headless path with its import
re-anchored, and drops the mountWebPlugins roster mounting helper.
2026-07-25 10:22:43 +08:00
Tianyi Cui
2beaa18f42 Merge remote-tracking branch 'origin/master' into worktree/acp-automation-protocol
# Conflicts:
#	packages/support/acp-snapshot/README.md
2026-07-25 02:07:28 +08:00
Tianyi Cui
05ee162723 Merge remote-tracking branch 'origin/master' into fix-webplugins-watch-flake
# Conflicts:
#	packages/host/webserver/src/web-plugins.ts
#	packages/host/webserver/tests/web-plugins.spec.ts
2026-07-25 01:58:59 +08:00
Tianyi Cui
2096050824 fix(webserver): registry-owned stat poll replaces fs.watchFile baseline race
The dev bundle watch missed rebuilds that landed while the registry was
constructing: fs.watchFile captures its comparison baseline with an
ASYNCHRONOUS first stat, so a write racing that window is absorbed into
the baseline and never reported. Standalone repro missed 24/400 same-tick
rewrites; the CI flake in web-plugins.spec.ts ('watch mode: a bundle
content change re-hashes the row...') was exactly this — the spec writes
immediately after createHostWebPluginRegistry returns.

The watch now polls from one registry-owned setInterval against a stat
baseline the scan itself captures synchronously, stat-before-read: a
write landing between stat and read leaves the hash newer than the
baseline (next tick re-hashes to the same rev, no spurious notify); a
write landing after the read leaves the baseline older (next tick
detects and notifies). No blind window. The poll iterates the live
table, so rescans retarget the watch for free and dispose clears one
timer. Stress: real-registry same-tick rewrite 0/600 missed (was 1/300);
spec watch tests 0/50.

New regression test pins the same-tick-as-construction write. Its
rewrite deliberately differs in size from the seed: a same-millisecond
same-size rewrite is invisible to any mtime+size poll (coarse fs
timestamps) — a stat-polling limit, not this regression. Loading-model
Agent Note updated in both languages (pair re-recorded).
2026-07-25 01:22:46 +08:00
Tianyi Cui
1d066e0f74 Fix remaining PTY and bundle watch races
Keep inherited child prompt markers bounded by the normal silence fallback. Stage web-plugin rescans atomically and retain missing watch state until a successful rebuild.
2026-07-25 00:33:33 +08:00
Tianyi Cui
f9a638b8a6 Stabilize master CI across platforms 2026-07-25 00:10:37 +08:00
Tianyi Cui
440384fdb4 Merge remote-tracking branch 'origin/master' into worktree/acp-automation-protocol
# Conflicts:
#	.agents/notes/implemented/architecture/2026-06-14-session-persistence.md
#	.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md
#	.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md
#	.agents/notes/implemented/feature/2026-06-14-acp-agent-client-protocol.md
#	.agents/notes/implemented/feature/2026-06-14-acp-multi-session.md
#	.agents/notes/implemented/feature/2026-06-18-acp-terminal-and-tool-rendering.md
#	.agents/notes/implemented/feature/2026-07-19-model-facing-goal-tools.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-19-model-facing-goal-tools.md
#	.agents/notes/implemented/feature/2026-07-19-model-facing-goal-tools.zh.md
#	.agents/notes/implemented/simplification/2026-07-04-trim-acp-bridge-unreachable-surface.md
#	docs/architecture.i18n.yaml
#	docs/cookbook/extension-cookbook.i18n.yaml
#	docs/cookbook/extension-cookbook.md
#	docs/cookbook/extension-cookbook.zh.md
#	docs/core-data-structures/approval.md
#	docs/core-data-structures/user-interaction.md
#	docs/event-producer-consumer.md
#	docs/persistence-catalog.md
#	docs/testing.md
#	docs/tool-catalog.md
#	examples/acp-agent/tests/fixtures/live-mode-switching-2026-07-07.session.jsonl
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl
#	examples/acp-agent/tests/snapshots/permission-switching/session.jsonl
#	packages/goal/tool-goal/README.md
#	packages/ui/acp/README.md
#	packages/ui/acp/acp-feature-support.md
#	packages/ui/acp/src/index.ts
#	packages/ui/acp/tests/bridge.spec.ts
#	packages/ui/acp/tests/dispose.spec.ts
#	packages/ui/acp/tests/edges.spec.ts
#	packages/ui/acp/tests/turns.spec.ts
2026-07-24 23:43:10 +08:00
Tianyi Cui
90057b25f2 docs(acp): state both arms of the spec's version-negotiation rule 2026-07-24 22:19:10 +08:00
Tianyi Cui
5569f3f8ac docs: repair rewritten rationale and stale claims from the ACP reduction
The automation-only rewrite edited many implemented Agent Notes; several
edits replaced still-live or historical rationale instead of reframing:

- llm-model-catalog: restore the prompt/request consistency section and
  selection-ownership alternatives — installAgentLlmTarget and the TUI
  /model selector still ship that design; only the ACP wire is gone.
- plan-specific-collaboration-state, acp-multi-session, todo-write,
  ask-user-question: link the superseding automation-only note instead
  of silently rewriting the original decision or motivation; drop a
  paragraph duplicating the Web-provider facts stated two paragraphs up.
- sandbox: stop claiming unit coverage for turn-enclosed config writes
  (that mechanism left with the bridge) and retitle the commit-boundary
  paragraph accordingly.
- Fix the missing blank line before '## Consequences' in the
  plugin-command-registration pair, the JSON-RPC/Web render-intent
  consumer misattribution (the second consumer is the host/client
  runtime), stale bash_output/bash_kill names, and 'optional goals' in
  architecture.md.
- examples/acp-agent/README.md: point at the package contract instead
  of restating it; packages/ui/permission and plan-mode READMEs record
  the consumer-less preset service and the exit_plan_mode coverage gap
  under Known Limitations.
- 2026-06-19-acp-snapshot-tests: the new note defers the corpus
  migration rather than committing to it; say so.

Re-record the touched bilingual pairs.
2026-07-24 22:12:23 +08:00
Tianyi Cui
74d14f68bb fix(acp): accept baseline resource links and release a failed prompt slot
ACP v1 requires every agent to accept text AND resource_link prompt
content; the automation rewrite dropped the resource_link half of that
baseline. Restore the old bracketed-reference flattening in the codec,
reject only beyond-baseline blocks, and update the package contract and
Agent Note.

Also release the per-session prompt slot when agent.send() throws
synchronously (an agent disposed outside the bridge would otherwise
wedge the session into permanent 'already in flight' rejections),
drop the tautological version-negotiation branch, prove the scenario
env layer reaches the snapshot subprocess, pin bridge-side fail-closed
permission errors, and correct two overpromising test names.
2026-07-24 22:11:49 +08:00
Tianyi Cui
46dfd503e0 Merge origin/master into codex/sqlite-metadata-contracts 2026-07-24 21:07:23 +08:00
Tianyi Cui
9e691d54c0 fix(goal): normalize strict-schema fillers 2026-07-24 20:45:23 +08:00
Tianyi Cui
145ba169f6 Merge commit 'refs/codex-unblock/20260724/pr591-base-current' into worktree/unblock-pr-591-ci-20260724 2026-07-24 20:32:02 +08:00
Tianyi Cui
51f697db50 test(tui): wait for scoped file completion
The fake terminal retains earlier autocomplete frames, so the directory follow-up assertion could pass before the scoped lookup completed. Wait for the quoted file mention to be applied before submitting.
2026-07-24 19:38:31 +08:00
Turtle
207aab9d8d fix(llm): classify empty model completions as retryable EMPTY_RESPONSE
A well-formed provider stream that ends with finish_reason stop and zero
content blocks previously became a successful empty assistant message: the
turn completed silently, and drivers like goal-session counted the no-op
round. Both adapters now map that degenerate completion to a finish
{kind:'error'} with the new canonical EMPTY_RESPONSE code from dsh-llm, and
dsh-llm-retry adds the code to its default retryable set, so the existing
closed-step recovery path retries it and fails loud once the budget is
exhausted.

Covered by adapter unit tests, an llm-retry default-policy test, and a new
authored keyless ACP snapshot (empty-response-retry) with a deterministic
1 ms zero-jitter retry overlay.
2026-07-24 19:23:12 +08:00
Tianyi Cui
a229b095d6 Merge branch 'master' into fix/goal-completion-strict-fields 2026-07-24 19:19:57 +08:00
Turtle
081bb1a8fd Merge remote-tracking branch 'origin/master' into feat/send-unify
# Conflicts:
#	packages/client/runtime/src/client/sessions/fold-adapter.ts
2026-07-24 17:17:35 +08:00
07akioni
65e6a2adbe Merge branch 'master' into feat/trajectory 2026-07-24 17:06:25 +08:00
Turtle
d2b2539f3e Merge remote-tracking branch 'origin/feat/send-unify' into feat/send-unify
# Conflicts:
#	docs/architecture.i18n.yaml
#	docs/architecture.md
2026-07-24 16:58:32 +08:00
Turtle
4be3301952 fix: migrate merged-in context/message references to user/message
The master merge introduced a tui goal-restore test and the guard parent
README that still used the removed context/message event. Point both at
the coalesced plugin-sourced user/message.
2026-07-24 16:56:36 +08:00
Turtle
80bbe959a7 Merge remote-tracking branch 'origin/master' into feat/send-unify 2026-07-24 16:52:46 +08:00
07akioni
6fc92bbb16 fix: ci 2026-07-24 16:32:35 +08:00
Turtle
bb124c2869 Merge branch 'master' into feat/send-unify 2026-07-24 16:31:00 +08:00
Tianyi Cui
a88364ab66 Merge remote-tracking branch 'origin/master' into worktree/acp-automation-protocol 2026-07-24 16:30:03 +08:00
ZiyaZhang
12dbc00166 fix(tui): harden resume picker input 2026-07-24 01:29:35 -07:00