Sfoglia il codice sorgente

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.
imccyu 2 mesi fa
parent
commit
f5506cf35f
34 ha cambiato i file con 86 aggiunte e 86 eliminazioni
  1. 2 2
      .agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.i18n.yaml
  2. 2 2
      .agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md
  3. 2 2
      .agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md
  4. 3 3
      docs/capability-seams.md
  5. 21 21
      docs/config-catalog.md
  6. 1 1
      docs/cordis-catalog/events.md
  7. 1 1
      docs/event-producer-consumer.md
  8. 6 6
      docs/module-graph.md
  9. 4 4
      missions/tasks/20260724-storage-workspace/dev-plan.md
  10. 1 1
      packages/storage/storage-domain/README.md
  11. 1 1
      packages/storage/storage-domain/package.json
  12. 1 1
      packages/storage/storage-domain/src/domain.ts
  13. 1 1
      packages/storage/storage-domain/src/error.ts
  14. 1 1
      packages/storage/storage-domain/src/events.ts
  15. 2 2
      packages/storage/storage-domain/src/index.ts
  16. 4 4
      packages/storage/storage-domain/src/invariant.ts
  17. 1 1
      packages/storage/storage-domain/src/spec.ts
  18. 0 0
      packages/storage/storage-domain/tests/domain.spec.ts
  19. 0 0
      packages/storage/storage-domain/tests/helpers/memory-backend.ts
  20. 2 2
      packages/storage/storage-domain/tests/invariant.spec.ts
  21. 0 0
      packages/storage/storage-domain/tsconfig.json
  22. 1 1
      packages/storage/storage/README.md
  23. 2 2
      packages/workspace/workspace/package.json
  24. 1 1
      packages/workspace/workspace/src/entity.ts
  25. 1 1
      packages/workspace/workspace/src/index.ts
  26. 1 1
      packages/workspace/workspace/src/invariant.ts
  27. 1 1
      packages/workspace/workspace/src/spec.ts
  28. 1 1
      packages/workspace/workspace/tests/invariant.spec.ts
  29. 3 3
      packages/workspace/workspace/tests/workspace.spec.ts
  30. 1 1
      packages/workspace/workspace/tsconfig.json
  31. 13 13
      pnpm-lock.yaml
  32. 3 3
      scripts/gen-cordis-catalog.ts
  33. 1 1
      scripts/gen-doc-graphs.ts
  34. 1 1
      tsconfig.host.json

+ 2 - 2
.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write
-2026-07-24-domain-kv-storage-and-workspace.md: f6b74b656270f4791fd9369438235c7fc1b1edb8
-2026-07-24-domain-kv-storage-and-workspace.zh.md: f6649fc0c387d9c1240d45efda4b4a0ab9372486
+2026-07-24-domain-kv-storage-and-workspace.md: cd666a47a3cba4dea8846cd0f1373224e6fc456f
+2026-07-24-domain-kv-storage-and-workspace.zh.md: 81adf1eb6bc32aa3ca8b9ef4c352fb94f95ace91

+ 2 - 2
.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md

@@ -22,7 +22,7 @@ Create the `packages/storage/` group — the `ctx.storage` hub (backend registry
 | `@deepseek-ai/dsh-storage` | `packages/storage/storage/` | `ctx.storage` (the hub) | ✓ |
 | `@deepseek-ai/dsh-storage-json` | `packages/storage/storage-json/` | registers backend `json` | ✓ |
 | `@deepseek-ai/dsh-storage-sqlite` | `packages/storage/storage-sqlite/` | registers backend `sqlite` | ✓ |
-| `@deepseek-ai/dsh-domain` | `packages/storage/domain/` | mounts `ctx.storage.domain` | ✓ |
+| `@deepseek-ai/dsh-storage-domain` | `packages/storage/storage-domain/` | mounts `ctx.storage.domain` | ✓ |
 | `@deepseek-ai/dsh-workspace` | `packages/workspace/workspace/` | `ctx.workspace` | ✓ |
 | `SessionPersistence.delete` extension + cascade orchestration | `packages/session-persistence/*` | new method on the existing seam | ✗ future work (session side untouched this phase) |
 | `workspace.*` / `session.delete` RPC, GUI wiring, boot assembly | — | — | ✗ next phase |
@@ -157,7 +157,7 @@ Rules:
 - **Records are plain data**: immutable, directly JSON-serializable POJOs; values returned by `get`/`entries` must not be mutated in place (TypeScript readonly projection, no runtime freezing). Behavior-carrying domain objects belong to consumer packages.
 - **Serialized writes**: one promise chain per domain; `put`/`delete`/`update`/`global.set` all queue on it; `update`'s fn runs on the chain, so concurrency cannot interleave. No active-record (pulling out a mutable object that auto-persists — uncontrollable persist timing, in conflict with the whole-unit atomic-rewrite model).
 - **Version fails loud**: a stored version differing from the spec throws outright; no migration, no rebuild (the data is not regenerable; pre-release rejects old formats).
-- **Change events**: after each write's durability resolves, emit `domain/changed` (`@mode emit`), one per record, no old value (matching the repository's "new snapshot + operation discriminant" convention, template `goal/changed`); the payload `DomainChanged` is a put/deleted discriminated union — domain + table + key (both `''` for global changes) + operation, with the put branch carrying the new snapshot value and the deleted branch carrying none (`packages/storage/domain/src/events.ts`). This is next phase's RPC push-frame event source. The error vocabulary is `DomainError`, codes: `already-open` / `facet-unsupported` / `invalid-record` (with `{ table, key }`) / `missing-key` / `closed`.
+- **Change events**: after each write's durability resolves, emit `domain/changed` (`@mode emit`), one per record, no old value (matching the repository's "new snapshot + operation discriminant" convention, template `goal/changed`); the payload `DomainChanged` is a put/deleted discriminated union — domain + table + key (both `''` for global changes) + operation, with the put branch carrying the new snapshot value and the deleted branch carrying none (`packages/storage/storage-domain/src/events.ts`). This is next phase's RPC push-frame event source. The error vocabulary is `DomainError`, codes: `already-open` / `facet-unsupported` / `invalid-record` (with `{ table, key }`) / `missing-key` / `closed`.
 
 ### Future work: session-side deletion (design settled, not implemented this phase)
 

+ 2 - 2
.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md

@@ -22,7 +22,7 @@ host 侧唯一的持久化面是 session 事件日志(`packages/session-persis
 | `@deepseek-ai/dsh-storage` | `packages/storage/storage/` | `ctx.storage`(枢纽) | ✓ |
 | `@deepseek-ai/dsh-storage-json` | `packages/storage/storage-json/` | 注册 backend `json` | ✓ |
 | `@deepseek-ai/dsh-storage-sqlite` | `packages/storage/storage-sqlite/` | 注册 backend `sqlite` | ✓ |
-| `@deepseek-ai/dsh-domain` | `packages/storage/domain/` | 挂载 `ctx.storage.domain` | ✓ |
+| `@deepseek-ai/dsh-storage-domain` | `packages/storage/storage-domain/` | 挂载 `ctx.storage.domain` | ✓ |
 | `@deepseek-ai/dsh-workspace` | `packages/workspace/workspace/` | `ctx.workspace` | ✓ |
 | `SessionPersistence.delete` 扩面 + 级联删编排 | `packages/session-persistence/*` | 既有 seam 新方法 | ✗ future work(本期不动 session 侧) |
 | `workspace.*` / `session.delete` RPC、GUI 接线、boot 组装 | — | — | ✗ 下期 |
@@ -157,7 +157,7 @@ export interface KvTable<K extends string, V> {
 - **记录是纯数据**:可直接 JSON 序列化的不可变 POJO;`get`/`entries` 返回值不得原地改(TypeScript readonly 投影,不做运行时冻结)。带行为的领域对象属于消费者包。
 - **写串行**:域内一条 promise 链,`put`/`delete`/`update`/`global.set` 全排队;`update` 的 fn 在链上执行,并发不交错。不做 active-record(取出可变对象自动落盘——落盘时机不可控,与整域原子覆写冲突)。
 - **版本 fail loud**:盘上版本与 spec 不符直接报错,不迁移不重建(数据不可再生,pre-release 拒绝旧格式)。
-- **变更事件**:每次写落盘 resolve 后 emit `domain/changed`(`@mode emit`),逐条发、不带旧值(对齐仓库"新快照 + 操作判别"惯例,范本 `goal/changed`);payload `DomainChanged` 是 put/deleted 判别联合——域名 + 表名 + key(global 变更两者为 `''`)+ operation,put 支带新快照 value、deleted 支无 value(`packages/storage/domain/src/events.ts`)。此为下期 RPC 推帧的事件源。错误词汇 `DomainError`,码表:`already-open` / `facet-unsupported` / `invalid-record`(带 `{ table, key }`)/ `missing-key` / `closed`。
+- **变更事件**:每次写落盘 resolve 后 emit `domain/changed`(`@mode emit`),逐条发、不带旧值(对齐仓库"新快照 + 操作判别"惯例,范本 `goal/changed`);payload `DomainChanged` 是 put/deleted 判别联合——域名 + 表名 + key(global 变更两者为 `''`)+ operation,put 支带新快照 value、deleted 支无 value(`packages/storage/storage-domain/src/events.ts`)。此为下期 RPC 推帧的事件源。错误词汇 `DomainError`,码表:`already-open` / `facet-unsupported` / `invalid-record`(带 `{ table, key }`)/ `missing-key` / `closed`。
 
 ### Future work:session 侧删除(设计定案,本期不实施)
 

+ 3 - 3
docs/capability-seams.md

@@ -40,7 +40,7 @@ flowchart LR
   svc_storage["ctx.storage<br/>Non-session storage hub"]
   pkg_storage_json["storage-json"]
   pkg_storage_sqlite["storage-sqlite"]
-  pkg_domain["domain"]
+  pkg_storage_domain["storage-domain"]
   pkg_workspace["workspace"]
   svc_workspace["ctx.workspace<br/>Workspace entity registry"]
   svc_sessionQuery["ctx.sessionQuery<br/>Session reads, traces, filters, and search"]
@@ -246,7 +246,7 @@ flowchart LR
   svc_sessions --> pkg_subagent_inprocess
   svc_skills --> pkg_tool_skill
   svc_spillStore --> pkg_spill_policy
-  svc_storage --> pkg_domain
+  svc_storage --> pkg_storage_domain
   svc_storage --> pkg_workspace
   svc_subagents --> pkg_tool_ralph
   svc_subagents --> pkg_tool_subagent
@@ -289,7 +289,7 @@ flowchart LR
 | `ctx.sessions` | `core` | [`session`](../packages/core/session) | - | [`agent-loop`](../packages/core/agent-loop), [`agent`](../packages/core/agent), [`cli-demo`](../packages/examples/cli-demo), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite), [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`invariants`](../packages/support/invariants) | - | Owns append-only Session instances and emits the durable session event feed. |
 | `ctx.invariants` | `core` | [`invariants`](../packages/support/invariants) | - | [`session`](../packages/core/session), [`agent`](../packages/core/agent), [`scope`](../packages/core/scope), [`agent-loop`](../packages/core/agent-loop) | - | Companion subpaths register owner-local checks; the service owns selection, uniqueness, child fibers, and package-attributed failures. |
 | `ctx.sessionPersistence` | `seam` | [`session-persistence`](../packages/session-persistence/session-persistence) | [`session-persistence-jsonl`](../packages/session-persistence/session-persistence-jsonl), [`session-persistence-sqlite`](../packages/session-persistence/session-persistence-sqlite) | [`agent-loop`](../packages/core/agent-loop), [`tool-bash`](../packages/bash/tool-bash), [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`acp`](../packages/ui/acp), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | - | Backends persist the same SessionEvent vocabulary; apps choose a backend at composition time. |
-| `ctx.storage` | `seam` | [`storage`](../packages/storage/storage) | [`storage-json`](../packages/storage/storage-json), [`storage-sqlite`](../packages/storage/storage-sqlite) | [`domain`](../packages/storage/domain), [`workspace`](../packages/workspace/workspace) | - | Backends register side by side under names; data forms (domain first) mount on the hub and translate typed operations into opaque KV-unit primitives. |
+| `ctx.storage` | `seam` | [`storage`](../packages/storage/storage) | [`storage-json`](../packages/storage/storage-json), [`storage-sqlite`](../packages/storage/storage-sqlite) | [`storage-domain`](../packages/storage/storage-domain), [`workspace`](../packages/workspace/workspace) | - | Backends register side by side under names; data forms (domain first) mount on the hub and translate typed operations into opaque KV-unit primitives. |
 | `ctx.workspace` | `core` | [`workspace`](../packages/workspace/workspace) | - | - | - | Owns WorkspaceId-branded records over the domain form; sessionIds is the single source of ownership truth. RPC and GUI consumers arrive next phase. |
 | `ctx.sessionQuery` | `seam` | [`session-query`](../packages/session-query/session-query) | [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | [`session-reference`](../packages/context/session-reference) | - | The interface supplies exact reads, filters, and traces; its concrete backend adds full-text reconciliation, ranking, snippets, and cursor generations on the same service. |
 | `ctx.sessionReferences` | `core` | [`session-reference`](../packages/context/session-reference) | - | [`tui`](../packages/ui/tui), [`acp`](../packages/ui/acp) | - | Projects bounded current-surface conversation snapshots into durable untrusted message context; host adapters own mention syntax. |

+ 21 - 21
docs/config-catalog.md

@@ -369,27 +369,6 @@ export interface ToolResultPruneConfig {
 
 Source: [`packages/compact/compact-tool-result-prune/src/types.ts:4`](../packages/compact/compact-tool-result-prune/src/types.ts)
 
-## `@deepseek-ai/dsh-domain`
-
-Requires: `storage`
-
-```ts config-catalog
-/**
- * Plugin config. Which backend serves which domain is decided here, not
- * globally on the hub: `backend` is the default route and `routes` overrides
- * it per domain name. A route naming an unregistered backend fails loud at
- * `open` with `backend-not-found`.
- */
-export interface Config {
-  /** Default backend name for every domain without an explicit route. Required: there is no universally correct medium. */
-  backend: string
-  /** Per-domain overrides: domain name → backend name. */
-  routes?: Record<string, string>
-}
-```
-
-Source: [`packages/storage/domain/src/index.ts:45`](../packages/storage/domain/src/index.ts)
-
 ## `@deepseek-ai/dsh-fs-local`
 
 ```ts config-catalog
@@ -1176,6 +1155,27 @@ export interface Config {
 
 Source: [`packages/spill/spill-policy/src/index.ts:51`](../packages/spill/spill-policy/src/index.ts)
 
+## `@deepseek-ai/dsh-storage-domain`
+
+Requires: `storage`
+
+```ts config-catalog
+/**
+ * Plugin config. Which backend serves which domain is decided here, not
+ * globally on the hub: `backend` is the default route and `routes` overrides
+ * it per domain name. A route naming an unregistered backend fails loud at
+ * `open` with `backend-not-found`.
+ */
+export interface Config {
+  /** Default backend name for every domain without an explicit route. Required: there is no universally correct medium. */
+  backend: string
+  /** Per-domain overrides: domain name → backend name. */
+  routes?: Record<string, string>
+}
+```
+
+Source: [`packages/storage/storage-domain/src/index.ts:45`](../packages/storage/storage-domain/src/index.ts)
+
 ## `@deepseek-ai/dsh-storage-json`
 
 Requires: `storage`

+ 1 - 1
docs/cordis-catalog/events.md

@@ -507,7 +507,7 @@ A domain record or the global singleton changed, emitted once per write strictly
 'domain/changed'(change: DomainChanged): void
 ```
 
-Source: [`packages/storage/domain/src/events.ts:46`](../../packages/storage/domain/src/events.ts)
+Source: [`packages/storage/storage-domain/src/events.ts:46`](../../packages/storage/storage-domain/src/events.ts)
 
 ## `fs/*`
 

+ 1 - 1
docs/event-producer-consumer.md

@@ -28,7 +28,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac
 | `agent/turn-stop` | `serial` | [`packages/core/agent/src/types.ts:485`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`tool-goal`](../packages/goal/tool-goal) |
 | `approval/request` | `waterfall` | [`packages/ui/user-approval/src/index.ts:30`](../packages/ui/user-approval/src/index.ts) | [`user-approval`](../packages/ui/user-approval) (`waterfall`) | [`acp`](../packages/ui/acp) |
 | `commands/change` | `emit` | [`packages/ui/commands/src/index.ts:103`](../packages/ui/commands/src/index.ts) | [`commands`](../packages/ui/commands) (`events.dispatch`) | [`acp`](../packages/ui/acp), [`tui`](../packages/ui/tui) |
-| `domain/changed` | `emit` | [`packages/storage/domain/src/events.ts:46`](../packages/storage/domain/src/events.ts) | [`domain`](../packages/storage/domain) (`emit`) | [`domain`](../packages/storage/domain), [`workspace`](../packages/workspace/workspace) |
+| `domain/changed` | `emit` | [`packages/storage/storage-domain/src/events.ts:46`](../packages/storage/storage-domain/src/events.ts) | [`storage-domain`](../packages/storage/storage-domain) (`emit`) | [`storage-domain`](../packages/storage/storage-domain), [`workspace`](../packages/workspace/workspace) |
 | `fs/edit-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:62`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`) | [`fs-policy`](../packages/fs/fs-policy) |
 | `fs/observed` | `emit` | [`packages/fs/fs/src/index.ts:71`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`emit`) | [`fs-policy`](../packages/fs/fs-policy) |
 | `fs/write-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:54`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`) | [`fs-policy`](../packages/fs/fs-policy) |

+ 6 - 6
docs/module-graph.md

@@ -196,8 +196,8 @@ flowchart TD
     pkg_telemetry["telemetry"]
   end
   subgraph group_storage["packages/storage"]
-    pkg_domain["domain"]
     pkg_storage["storage"]
+    pkg_storage_domain["storage-domain"]
     pkg_storage_json["storage-json"]
     pkg_storage_sqlite["storage-sqlite"]
   end
@@ -260,8 +260,8 @@ flowchart TD
   pkg_telemetry --> pkg_brand
   pkg_telemetry --> pkg_invariants
   pkg_telemetry --> pkg_paths
-  pkg_domain --> pkg_invariants
-  pkg_domain --> pkg_storage
+  pkg_storage_domain --> pkg_invariants
+  pkg_storage_domain --> pkg_storage
   pkg_storage_json --> pkg_invariants
   pkg_storage_json --> pkg_storage
   pkg_storage_sqlite --> pkg_invariants
@@ -430,11 +430,11 @@ flowchart TD
   pkg_workflow --> pkg_llm
   pkg_workflow --> pkg_session
   pkg_workspace --> pkg_brand
-  pkg_workspace --> pkg_domain
   pkg_workspace --> pkg_invariants
   pkg_workspace --> pkg_session
   pkg_workspace --> pkg_session_persistence
   pkg_workspace --> pkg_storage
+  pkg_workspace --> pkg_storage_domain
   pkg_tools --> pkg_agent
   pkg_tools --> pkg_code_runtime
   pkg_tools --> pkg_invariants
@@ -835,7 +835,7 @@ flowchart TD
 | [`client-ui-sidebar`](../packages/client/ui-sidebar) | `client` | [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/support/invariants) |
 | [`helper`](../packages/sdk/helper) | `sdk` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants) |
 | [`telemetry`](../packages/sdk/telemetry) | `sdk` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`paths`](../packages/util/paths) |
-| [`domain`](../packages/storage/domain) | `storage` | [`invariants`](../packages/support/invariants), [`storage`](../packages/storage/storage) |
+| [`storage-domain`](../packages/storage/storage-domain) | `storage` | [`invariants`](../packages/support/invariants), [`storage`](../packages/storage/storage) |
 | [`storage-json`](../packages/storage/storage-json) | `storage` | [`invariants`](../packages/support/invariants), [`storage`](../packages/storage/storage) |
 | [`storage-sqlite`](../packages/storage/storage-sqlite) | `storage` | [`invariants`](../packages/support/invariants), [`storage`](../packages/storage/storage) |
 | [`llm-deepseek`](../packages/llm/llm-deepseek) | `llm` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`timeout`](../packages/util/timeout) |
@@ -885,7 +885,7 @@ flowchart TD
 | [`scripts`](../packages/sdk/scripts) | `sdk` | [`app-boot`](../packages/ui/app-boot), [`invariants`](../packages/support/invariants) |
 | [`tasks`](../packages/tasks/tasks) | `tasks` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session), [`timeout`](../packages/util/timeout) |
 | [`workflow`](../packages/workflow/workflow) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
-| [`workspace`](../packages/workspace/workspace) | `workspace` | [`brand`](../packages/util/brand), [`domain`](../packages/storage/domain), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`storage`](../packages/storage/storage) |
+| [`workspace`](../packages/workspace/workspace) | `workspace` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`storage`](../packages/storage/storage), [`storage-domain`](../packages/storage/storage-domain) |
 | [`tools`](../packages/core/tools) | `core` | [`agent`](../packages/core/agent), [`code-runtime`](../packages/code-runtime/code-runtime), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`user-approval`](../packages/ui/user-approval) |
 | [`command-goal`](../packages/goal/command-goal) | `goal` | [`commands`](../packages/ui/commands), [`goal`](../packages/goal/goal), [`invariants`](../packages/support/invariants) |
 | [`goal-session`](../packages/goal/goal-session) | `goal` | [`agent`](../packages/core/agent), [`goal`](../packages/goal/goal), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |

+ 4 - 4
missions/tasks/20260724-storage-workspace/dev-plan.md

@@ -10,7 +10,7 @@ packages/storage/
   storage/         dsh-storage         枢纽:Storage service + BackendRegistry + StorageForms
   storage-json/    dsh-storage-json    JsonStorageBackend(kv facet)
   storage-sqlite/  dsh-storage-sqlite  SqliteStorageBackend(kv facet)
-  domain/          dsh-domain          DomainFacility + Domain + KvTable + domain/changed
+  storage-domain/  dsh-storage-domain          DomainFacility + Domain + KvTable + domain/changed
 packages/workspace/
   workspace/       dsh-workspace       WorkspaceRegistry + WorkspaceEntity + workspaceDomainSpec
 ```
@@ -56,7 +56,7 @@ class/接口逐条(签名以 Note 为准,此处列实现要点):
 | `const UNIT_NAME_RE = /^[a-z][a-z0-9_]*$/` | 导出;descriptor 校验用(backend open 时验,fail loud) |
 | invariant | 枢纽自身无运行时不变量(纯注册表,无事件流/可变盘面),写"explained empty"(措辞照抄 sqlite 后端 invariant.ts 的 "No runtime invariant:" 模板) |
 
-事件面:本包**无**事件(`domain/changed` 归 dsh-domain)。
+事件面:本包**无**事件(`domain/changed` 归 dsh-storage-domain)。
 
 ## 2. W2a:`dsh-storage-json` —— teammate **json-backend**
 
@@ -99,10 +99,10 @@ packages/storage/storage-sqlite/
 | `class SqliteKvUnit` | 预编译语句(每表 upsert/delete/select-all + global upsert);`loadAll` 全表 SELECT 组装;`putRecord` = `INSERT … ON CONFLICT(key) DO UPDATE`;单语句原子,无显式事务;value `JSON.stringify`/parse |
 | invariant | 断言候选:STRICT 表 + user_version 与常量一致(open 后检);或 explained empty |
 
-## 4. W3:`dsh-domain` —— teammate **domain-layer**
+## 4. W3:`dsh-storage-domain` —— teammate **domain-layer**
 
 ```
-packages/storage/domain/
+packages/storage/storage-domain/
   src/index.ts                # Config + apply + DomainFacility
   src/spec.ts                 # DomainSpec/defineDomain/domainTable + descriptorOf
   src/domain.ts               # DomainImpl + KvTableImpl + 写链

+ 1 - 1
packages/storage/domain/README.md → packages/storage/storage-domain/README.md

@@ -1,4 +1,4 @@
-# @deepseek-ai/dsh-domain
+# @deepseek-ai/dsh-storage-domain
 
 Domain data form for the DeepSeek Harness storage hub: mounts `ctx.storage.domain`, opening schema-validated KV domains over configured storage backends. A domain is declared once with `defineDomain` (zod record schemas, `z.infer`-derived types), opened through `DomainFacility.open`, and served from authoritative in-memory state — reads are synchronous, writes serialize on one per-domain chain, reach durability on the routed backend first, then update memory and emit `domain/changed`. The opening consumer owns the handle's lifecycle and releases it with `Domain.close()` (idempotent; typically its own `ctx.effect` disposer); domains still open when the plugin unmounts are closed by the facility.
 

+ 1 - 1
packages/storage/domain/package.json → packages/storage/storage-domain/package.json

@@ -1,5 +1,5 @@
 {
-  "name": "@deepseek-ai/dsh-domain",
+  "name": "@deepseek-ai/dsh-storage-domain",
   "description": "Domain data form (ctx.storage.domain): schema-validated, event-emitting KV domains over storage backends for the DeepSeek Harness",
   "version": "0.0.1",
   "private": true,

+ 1 - 1
packages/storage/domain/src/domain.ts → packages/storage/storage-domain/src/domain.ts

@@ -6,7 +6,7 @@
  * backend write leaves memory untouched (no divergence between reads and the
  * medium), and events carry values that equal the in-memory state at
  * emission, in write order.
- * @module @deepseek-ai/dsh-domain/src/domain
+ * @module @deepseek-ai/dsh-storage-domain/src/domain
  */
 
 import type { Context } from 'cordis'

+ 1 - 1
packages/storage/domain/src/error.ts → packages/storage/storage-domain/src/error.ts

@@ -1,6 +1,6 @@
 /**
  * Error vocabulary of the domain data form.
- * @module @deepseek-ai/dsh-domain/src/error
+ * @module @deepseek-ai/dsh-storage-domain/src/error
  */
 
 /** Discriminant codes carried by every {@link DomainError}. */

+ 1 - 1
packages/storage/domain/src/events.ts → packages/storage/storage-domain/src/events.ts

@@ -4,7 +4,7 @@
  * and an operation discriminant — never the old value (a diffing consumer
  * keeps its own previous snapshot). This is the event source for cross-process
  * change push (RPC frames) in a later phase.
- * @module @deepseek-ai/dsh-domain/src/events
+ * @module @deepseek-ai/dsh-storage-domain/src/events
  */
 
 /** Shared location fields of one durable domain change. */

+ 2 - 2
packages/storage/domain/src/index.ts → packages/storage/storage-domain/src/index.ts

@@ -4,7 +4,7 @@
  * layer — consumers depend on this package and never touch backends directly.
  * Plugin `Config` is schemastery; record schemas inside domain specs are zod
  * (see `src/spec.ts` for the split rationale).
- * @module @deepseek-ai/dsh-domain
+ * @module @deepseek-ai/dsh-storage-domain
  */
 
 import type { Context } from 'cordis'
@@ -32,7 +32,7 @@ declare module '@deepseek-ai/dsh-storage' {
 }
 
 /** Cordis plugin name. */
-export const name = 'domain'
+export const name = 'storage-domain'
 /** The storage hub must be present before the form can mount. */
 export const inject = ['storage']
 

+ 4 - 4
packages/storage/domain/src/invariant.ts → packages/storage/storage-domain/src/invariant.ts

@@ -1,22 +1,22 @@
 /**
- * Package-owned invariant companion for `@deepseek-ai/dsh-domain`: every
+ * Package-owned invariant companion for `@deepseek-ai/dsh-storage-domain`: every
  * `domain/changed` event must agree with the emitting domain's authoritative
  * in-memory state (the owned event-stream ↔ mutable-data relationship of this
  * package). Writes emit strictly after mutating memory and the write chain
  * serializes them, so at emission time the event's snapshot equals the
  * current read — any divergence means a write path skipped the chain or
  * emitted a stale value.
- * @module @deepseek-ai/dsh-domain/invariant
+ * @module @deepseek-ai/dsh-storage-domain/invariant
  */
 
 import type { Context } from 'cordis'
 import type { InvariantFailure, InvariantInstaller } from '@deepseek-ai/dsh-invariants'
 import type { DomainChanged } from './events.ts'
 
-const PACKAGE_NAME = '@deepseek-ai/dsh-domain'
+const PACKAGE_NAME = '@deepseek-ai/dsh-storage-domain'
 
 /** Cordis companion plugin name. */
-export const name = 'domain-invariant'
+export const name = 'storage-domain-invariant'
 /** Service required before the companion can reserve package ownership. */
 export const inject = ['invariants']
 

+ 1 - 1
packages/storage/domain/src/spec.ts → packages/storage/storage-domain/src/spec.ts

@@ -5,7 +5,7 @@
  * (validation, descriptor projection) derive from it. Record schemas are zod
  * (`z.infer` keeps types un-duplicated and the same schemas later project to
  * RPC wire schemas); plugin `Config` stays schemastery.
- * @module @deepseek-ai/dsh-domain/src/spec
+ * @module @deepseek-ai/dsh-storage-domain/src/spec
  */
 
 import type { ZodType } from 'zod'

+ 0 - 0
packages/storage/domain/tests/domain.spec.ts → packages/storage/storage-domain/tests/domain.spec.ts


+ 0 - 0
packages/storage/domain/tests/helpers/memory-backend.ts → packages/storage/storage-domain/tests/helpers/memory-backend.ts


+ 2 - 2
packages/storage/domain/tests/invariant.spec.ts → packages/storage/storage-domain/tests/invariant.spec.ts

@@ -3,7 +3,7 @@ import { Context } from 'cordis'
 import { z } from 'zod'
 import Storage from '@deepseek-ai/dsh-storage'
 import InvariantService, { InvariantError } from '@deepseek-ai/dsh-invariants'
-import * as DomainInvariantCompanion from '@deepseek-ai/dsh-domain/invariant'
+import * as DomainInvariantCompanion from '@deepseek-ai/dsh-storage-domain/invariant'
 import { DomainFacility, defineDomain, domainTable } from '../src/index.ts'
 import type { DomainChanged } from '../src/events.ts'
 import { MemoryStorageBackend } from './helpers/memory-backend.ts'
@@ -31,7 +31,7 @@ async function setup() {
 
 const invariantViolation: unknown = expect.objectContaining<Partial<InvariantError>>({
   code: 'INVARIANT',
-  packageName: '@deepseek-ai/dsh-domain',
+  packageName: '@deepseek-ai/dsh-storage-domain',
 })
 
 describe('domain change-event invariants', () => {

+ 0 - 0
packages/storage/domain/tsconfig.json → packages/storage/storage-domain/tsconfig.json


+ 1 - 1
packages/storage/storage/README.md

@@ -15,7 +15,7 @@ Storage hub (`ctx.storage`) for non-session data: a named backend registry plus
 | `dsh-storage` | The hub service + backend vocabulary + shared conformance suite |
 | `dsh-storage-json` | JSON backend: one unit per human-readable file, atomic whole-file rewrite |
 | `dsh-storage-sqlite` | SQLite backend: one database hosting all routed units, document-per-row |
-| `dsh-domain` | Domain data form (`ctx.storage.domain`): typed schemas, write chain, change events |
+| `dsh-storage-domain` | Domain data form (`ctx.storage.domain`): typed schemas, write chain, change events |
 
 ## Model Experience
 

+ 2 - 2
packages/workspace/workspace/package.json

@@ -28,7 +28,7 @@
   "license": "BSD-3-Clause",
   "peerDependencies": {
     "@deepseek-ai/dsh-brand": "^0.0.1",
-    "@deepseek-ai/dsh-domain": "^0.0.1",
+    "@deepseek-ai/dsh-storage-domain": "^0.0.1",
     "@deepseek-ai/dsh-invariants": "^0.0.1",
     "@deepseek-ai/dsh-session": "^0.0.1",
     "@deepseek-ai/dsh-session-persistence": "^0.0.1",
@@ -40,7 +40,7 @@
   },
   "devDependencies": {
     "@deepseek-ai/dsh-brand": "workspace:^",
-    "@deepseek-ai/dsh-domain": "workspace:^",
+    "@deepseek-ai/dsh-storage-domain": "workspace:^",
     "@deepseek-ai/dsh-invariants": "workspace:^",
     "@deepseek-ai/dsh-session": "workspace:^",
     "@deepseek-ai/dsh-session-persistence": "workspace:^",

+ 1 - 1
packages/workspace/workspace/src/entity.ts

@@ -10,7 +10,7 @@
 
 import { stat } from 'node:fs/promises'
 import type { SessionHeader, SessionId } from '@deepseek-ai/dsh-session'
-import type { KvTable } from '@deepseek-ai/dsh-domain'
+import type { KvTable } from '@deepseek-ai/dsh-storage-domain'
 import type { WorkspaceRecord } from './spec.ts'
 import type { Workspace, WorkspaceId } from './types.ts'
 import { realpathNormalize } from './paths.ts'

+ 1 - 1
packages/workspace/workspace/src/index.ts

@@ -14,7 +14,7 @@ import type { SessionHeader, SessionId } from '@deepseek-ai/dsh-session'
 // Type-only: merges `sessionPersistence` into the Context service map for the
 // optional `ctx.get` lookups below.
 import type {} from '@deepseek-ai/dsh-session-persistence'
-import type { KvTable } from '@deepseek-ai/dsh-domain'
+import type { KvTable } from '@deepseek-ai/dsh-storage-domain'
 import { workspaceDomainSpec } from './spec.ts'
 import type { WorkspaceRecord } from './spec.ts'
 import { WorkspaceEntity } from './entity.ts'

+ 1 - 1
packages/workspace/workspace/src/invariant.ts

@@ -5,7 +5,7 @@
 
 import type { Context } from 'cordis'
 import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
-import type { DomainChanged } from '@deepseek-ai/dsh-domain'
+import type { DomainChanged } from '@deepseek-ai/dsh-storage-domain'
 import { WorkspaceId } from '@deepseek-ai/dsh-workspace'
 
 const PACKAGE_NAME = '@deepseek-ai/dsh-workspace'

+ 1 - 1
packages/workspace/workspace/src/spec.ts

@@ -7,7 +7,7 @@
 
 import { z } from 'zod'
 import { SessionId } from '@deepseek-ai/dsh-session'
-import { defineDomain, domainTable } from '@deepseek-ai/dsh-domain'
+import { defineDomain, domainTable } from '@deepseek-ai/dsh-storage-domain'
 import type { WorkspaceId } from './types.ts'
 
 /**

+ 1 - 1
packages/workspace/workspace/tests/invariant.spec.ts

@@ -1,7 +1,7 @@
 import { describe, expect, it } from 'vitest'
 import { Context } from 'cordis'
 import InvariantService from '@deepseek-ai/dsh-invariants'
-import type { DomainChanged } from '@deepseek-ai/dsh-domain'
+import type { DomainChanged } from '@deepseek-ai/dsh-storage-domain'
 import * as WorkspaceInvariant from '../src/invariant.ts'
 import { WorkspaceId } from '../src/index.ts'
 

+ 3 - 3
packages/workspace/workspace/tests/workspace.spec.ts

@@ -5,11 +5,11 @@ import { basename, join } from 'node:path'
 import { Context } from 'cordis'
 import Storage from '@deepseek-ai/dsh-storage'
 import type { StorageBackend } from '@deepseek-ai/dsh-storage'
-import { DomainFacility } from '@deepseek-ai/dsh-domain'
-import type { DomainChanged } from '@deepseek-ai/dsh-domain'
+import { DomainFacility } from '@deepseek-ai/dsh-storage-domain'
+import type { DomainChanged } from '@deepseek-ai/dsh-storage-domain'
 import { SessionId } from '@deepseek-ai/dsh-session'
 import type { SessionHeader } from '@deepseek-ai/dsh-session'
-import { MemoryMediaPool, MemoryStorageBackend } from '../../../storage/domain/tests/helpers/memory-backend.ts'
+import { MemoryMediaPool, MemoryStorageBackend } from '../../../storage/storage-domain/tests/helpers/memory-backend.ts'
 import WorkspaceRegistry, { WorkspaceId } from '../src/index.ts'
 import type { WorkspaceRecord } from '../src/index.ts'
 

+ 1 - 1
packages/workspace/workspace/tsconfig.json

@@ -21,7 +21,7 @@
       "path": "../../storage/storage"
     },
     {
-      "path": "../../storage/domain"
+      "path": "../../storage/storage-domain"
     },
     {
       "path": "../../core/session"

+ 13 - 13
pnpm-lock.yaml

@@ -3167,7 +3167,16 @@ importers:
         specifier: ^4.0.0-rc.6
         version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
 
-  packages/storage/domain:
+  packages/storage/storage:
+    devDependencies:
+      '@deepseek-ai/dsh-invariants':
+        specifier: workspace:^
+        version: link:../../support/invariants
+      cordis:
+        specifier: ^4.0.0-rc.7
+        version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
+
+  packages/storage/storage-domain:
     dependencies:
       schemastery:
         specifier: ^3.18.0
@@ -3186,15 +3195,6 @@ importers:
         specifier: ^4.0.0-rc.7
         version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
 
-  packages/storage/storage:
-    devDependencies:
-      '@deepseek-ai/dsh-invariants':
-        specifier: workspace:^
-        version: link:../../support/invariants
-      cordis:
-        specifier: ^4.0.0-rc.7
-        version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)
-
   packages/storage/storage-json:
     dependencies:
       schemastery:
@@ -4342,9 +4342,6 @@ importers:
       '@deepseek-ai/dsh-brand':
         specifier: workspace:^
         version: link:../../util/brand
-      '@deepseek-ai/dsh-domain':
-        specifier: workspace:^
-        version: link:../../storage/domain
       '@deepseek-ai/dsh-invariants':
         specifier: workspace:^
         version: link:../../support/invariants
@@ -4357,6 +4354,9 @@ importers:
       '@deepseek-ai/dsh-storage':
         specifier: workspace:^
         version: link:../../storage/storage
+      '@deepseek-ai/dsh-storage-domain':
+        specifier: workspace:^
+        version: link:../../storage/storage-domain
       cordis:
         specifier: ^4.0.0-rc.7
         version: 4.0.0-rc.7(@cordisjs/plugin-include@1.0.4)(@cordisjs/plugin-loader@1.0.0-rc.5)

+ 3 - 3
scripts/gen-cordis-catalog.ts

@@ -207,9 +207,9 @@ const TYPE_LINK_EXEMPTIONS: Readonly<Record<string, string>> = {
   BashEnvVariableInfo: 'service-local metadata type is owned by packages/bash/tool-bash/src/index.ts',
   CompactAgentContext: 'compaction service input is owned by packages/compact/compact/src/index.ts',
   CreateAgentOptions: 'agent creation contract is owned by packages/core/agent/README.md',
-  DomainChanged: 'event-local snapshot is owned by packages/storage/domain/src/events.ts',
-  DomainFacility: 'domain form facility is owned by packages/storage/domain/README.md',
-  DomainSpec: 'domain declaration contract is owned by packages/storage/domain/README.md',
+  DomainChanged: 'event-local snapshot is owned by packages/storage/storage-domain/src/events.ts',
+  DomainFacility: 'domain form facility is owned by packages/storage/storage-domain/README.md',
+  DomainSpec: 'domain declaration contract is owned by packages/storage/storage-domain/README.md',
   StorageBackend: 'backend contract is owned by packages/storage/storage/src/backend.ts',
   StorageForms: 'merge-extensible form map is owned by packages/storage/storage/src/index.ts',
   InvariantInstaller: 'service-local contribution contract is owned by packages/support/invariants/README.md',

+ 1 - 1
scripts/gen-doc-graphs.ts

@@ -140,7 +140,7 @@ const SERVICE_ROLES: ServiceRole[] = [
     title: 'Non-session storage hub',
     mode: 'seam',
     implementations: ['storage-json', 'storage-sqlite'],
-    consumers: ['domain', 'workspace'],
+    consumers: ['storage-domain', 'workspace'],
     note: 'Backends register side by side under names; data forms (domain first) mount on the hub and translate typed operations into opaque KV-unit primitives.',
   },
   {

+ 1 - 1
tsconfig.host.json

@@ -47,7 +47,7 @@
     { "path": "./packages/storage/storage" },
     { "path": "./packages/storage/storage-json" },
     { "path": "./packages/storage/storage-sqlite" },
-    { "path": "./packages/storage/domain" },
+    { "path": "./packages/storage/storage-domain" },
     { "path": "./packages/workspace/workspace" },
     { "path": "./packages/session-title/session-title" },
     { "path": "./packages/session-title/session-title-llm" },