diff --git a/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.i18n.yaml b/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.i18n.yaml index 1ef199c028..5ab7a8229d 100644 --- a/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.i18n.yaml +++ b/.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 diff --git a/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md b/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md index f6b74b6562..cd666a47a3 100644 --- a/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md +++ b/.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) diff --git a/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md b/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md index f6649fc0c3..81adf1eb6b 100644 --- a/.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md +++ b/.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 { - **记录是纯数据**:可直接 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 侧删除(设计定案,本期不实施) diff --git a/docs/capability-seams.md b/docs/capability-seams.md index de2599b579..0f96640e00 100644 --- a/docs/capability-seams.md +++ b/docs/capability-seams.md @@ -40,7 +40,7 @@ flowchart LR svc_storage["ctx.storage
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
Workspace entity registry"] svc_sessionQuery["ctx.sessionQuery
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. | diff --git a/docs/config-catalog.md b/docs/config-catalog.md index 6cce8b61f1..a9609eb1f9 100644 --- a/docs/config-catalog.md +++ b/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 -} -``` - -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 +} +``` + +Source: [`packages/storage/storage-domain/src/index.ts:45`](../packages/storage/storage-domain/src/index.ts) + ## `@deepseek-ai/dsh-storage-json` Requires: `storage` diff --git a/docs/cordis-catalog/events.md b/docs/cordis-catalog/events.md index 3019f059d7..1948c17f97 100644 --- a/docs/cordis-catalog/events.md +++ b/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/*` diff --git a/docs/event-producer-consumer.md b/docs/event-producer-consumer.md index 93fde6582c..d0554a1814 100644 --- a/docs/event-producer-consumer.md +++ b/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) | diff --git a/docs/module-graph.md b/docs/module-graph.md index 5ede1d5d57..ab9a2772b5 100644 --- a/docs/module-graph.md +++ b/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) | diff --git a/missions/tasks/20260724-storage-workspace/dev-plan.md b/missions/tasks/20260724-storage-workspace/dev-plan.md index 40cbb4a136..da621897ba 100644 --- a/missions/tasks/20260724-storage-workspace/dev-plan.md +++ b/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 + 写链 diff --git a/packages/storage/domain/README.md b/packages/storage/storage-domain/README.md similarity index 98% rename from packages/storage/domain/README.md rename to packages/storage/storage-domain/README.md index df1d99644a..e89c2f1d5b 100644 --- a/packages/storage/domain/README.md +++ b/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. diff --git a/packages/storage/domain/package.json b/packages/storage/storage-domain/package.json similarity index 96% rename from packages/storage/domain/package.json rename to packages/storage/storage-domain/package.json index 91ebb26868..1dffd143a9 100644 --- a/packages/storage/domain/package.json +++ b/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, diff --git a/packages/storage/domain/src/domain.ts b/packages/storage/storage-domain/src/domain.ts similarity index 99% rename from packages/storage/domain/src/domain.ts rename to packages/storage/storage-domain/src/domain.ts index 10c71524a9..7327580630 100644 --- a/packages/storage/domain/src/domain.ts +++ b/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' diff --git a/packages/storage/domain/src/error.ts b/packages/storage/storage-domain/src/error.ts similarity index 96% rename from packages/storage/domain/src/error.ts rename to packages/storage/storage-domain/src/error.ts index 15a76cd609..b768c2af35 100644 --- a/packages/storage/domain/src/error.ts +++ b/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}. */ diff --git a/packages/storage/domain/src/events.ts b/packages/storage/storage-domain/src/events.ts similarity index 96% rename from packages/storage/domain/src/events.ts rename to packages/storage/storage-domain/src/events.ts index 42311e865c..f70095e5d5 100644 --- a/packages/storage/domain/src/events.ts +++ b/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. */ diff --git a/packages/storage/domain/src/index.ts b/packages/storage/storage-domain/src/index.ts similarity index 99% rename from packages/storage/domain/src/index.ts rename to packages/storage/storage-domain/src/index.ts index e0dc09214f..974fcadc16 100644 --- a/packages/storage/domain/src/index.ts +++ b/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'] diff --git a/packages/storage/domain/src/invariant.ts b/packages/storage/storage-domain/src/invariant.ts similarity index 91% rename from packages/storage/domain/src/invariant.ts rename to packages/storage/storage-domain/src/invariant.ts index 785d1e4450..b2da8bebe4 100644 --- a/packages/storage/domain/src/invariant.ts +++ b/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'] diff --git a/packages/storage/domain/src/spec.ts b/packages/storage/storage-domain/src/spec.ts similarity index 98% rename from packages/storage/domain/src/spec.ts rename to packages/storage/storage-domain/src/spec.ts index b50af8f25b..9e49ef41e3 100644 --- a/packages/storage/domain/src/spec.ts +++ b/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' diff --git a/packages/storage/domain/tests/domain.spec.ts b/packages/storage/storage-domain/tests/domain.spec.ts similarity index 100% rename from packages/storage/domain/tests/domain.spec.ts rename to packages/storage/storage-domain/tests/domain.spec.ts diff --git a/packages/storage/domain/tests/helpers/memory-backend.ts b/packages/storage/storage-domain/tests/helpers/memory-backend.ts similarity index 100% rename from packages/storage/domain/tests/helpers/memory-backend.ts rename to packages/storage/storage-domain/tests/helpers/memory-backend.ts diff --git a/packages/storage/domain/tests/invariant.spec.ts b/packages/storage/storage-domain/tests/invariant.spec.ts similarity index 96% rename from packages/storage/domain/tests/invariant.spec.ts rename to packages/storage/storage-domain/tests/invariant.spec.ts index c16dbe72c3..80c7264aae 100644 --- a/packages/storage/domain/tests/invariant.spec.ts +++ b/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>({ code: 'INVARIANT', - packageName: '@deepseek-ai/dsh-domain', + packageName: '@deepseek-ai/dsh-storage-domain', }) describe('domain change-event invariants', () => { diff --git a/packages/storage/domain/tsconfig.json b/packages/storage/storage-domain/tsconfig.json similarity index 100% rename from packages/storage/domain/tsconfig.json rename to packages/storage/storage-domain/tsconfig.json diff --git a/packages/storage/storage/README.md b/packages/storage/storage/README.md index 923cc4017a..c2f7da9fd1 100644 --- a/packages/storage/storage/README.md +++ b/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 diff --git a/packages/workspace/workspace/package.json b/packages/workspace/workspace/package.json index 69244e5c3b..6bfab64773 100644 --- a/packages/workspace/workspace/package.json +++ b/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:^", diff --git a/packages/workspace/workspace/src/entity.ts b/packages/workspace/workspace/src/entity.ts index 42f38fe385..6ce2c01a00 100644 --- a/packages/workspace/workspace/src/entity.ts +++ b/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' diff --git a/packages/workspace/workspace/src/index.ts b/packages/workspace/workspace/src/index.ts index 6eded589d7..3754a9917a 100644 --- a/packages/workspace/workspace/src/index.ts +++ b/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' diff --git a/packages/workspace/workspace/src/invariant.ts b/packages/workspace/workspace/src/invariant.ts index f682bdddf6..70c9ea4b48 100644 --- a/packages/workspace/workspace/src/invariant.ts +++ b/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' diff --git a/packages/workspace/workspace/src/spec.ts b/packages/workspace/workspace/src/spec.ts index c249ba02d0..7ef1487bd7 100644 --- a/packages/workspace/workspace/src/spec.ts +++ b/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' /** diff --git a/packages/workspace/workspace/tests/invariant.spec.ts b/packages/workspace/workspace/tests/invariant.spec.ts index 552e8b6562..583c516937 100644 --- a/packages/workspace/workspace/tests/invariant.spec.ts +++ b/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' diff --git a/packages/workspace/workspace/tests/workspace.spec.ts b/packages/workspace/workspace/tests/workspace.spec.ts index fd8610b801..9d2c71c5cc 100644 --- a/packages/workspace/workspace/tests/workspace.spec.ts +++ b/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' diff --git a/packages/workspace/workspace/tsconfig.json b/packages/workspace/workspace/tsconfig.json index b6254015a3..0bddf4672c 100644 --- a/packages/workspace/workspace/tsconfig.json +++ b/packages/workspace/workspace/tsconfig.json @@ -21,7 +21,7 @@ "path": "../../storage/storage" }, { - "path": "../../storage/domain" + "path": "../../storage/storage-domain" }, { "path": "../../core/session" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1890d548a..352afd933a 100644 --- a/pnpm-lock.yaml +++ b/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) diff --git a/scripts/gen-cordis-catalog.ts b/scripts/gen-cordis-catalog.ts index 080a13ef2e..98a356c585 100644 --- a/scripts/gen-cordis-catalog.ts +++ b/scripts/gen-cordis-catalog.ts @@ -207,9 +207,9 @@ const TYPE_LINK_EXEMPTIONS: Readonly> = { 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', diff --git a/scripts/gen-doc-graphs.ts b/scripts/gen-doc-graphs.ts index 2a32429867..96faa3be71 100644 --- a/scripts/gen-doc-graphs.ts +++ b/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.', }, { diff --git a/tsconfig.host.json b/tsconfig.host.json index 8dd8d4b7be..69eaa92093 100644 --- a/tsconfig.host.json +++ b/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" },