@deepseek-ai/dsh-workspace 0.2.0-rc.2 → 0.2.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +12 -15
- package/README.md +5 -8
- package/README.zh.md +5 -8
- package/package.json +14 -21
- package/lib/invariant.js +0 -119
- package/lib/types/invariant.d.ts +0 -16
- package/lib/types/invariant.js +0 -43
package/README.i18n.yaml
CHANGED
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
en: a092fc7b0db9c299
|
|
28
28
|
zh: 6d7ed93e34237773
|
|
29
29
|
/deepseek-ai-dsh-workspace/use-this-package/first-use-workspace:
|
|
30
|
-
en:
|
|
31
|
-
zh:
|
|
30
|
+
en: 217475057b6506ed
|
|
31
|
+
zh: be2312a29499c203
|
|
32
32
|
/deepseek-ai-dsh-workspace/use-this-package/grouping-sessions-under-a-project:
|
|
33
33
|
en: 510be21d012de28c
|
|
34
34
|
zh: fdcb05447d6ba93c
|
|
35
35
|
/deepseek-ai-dsh-workspace/use-this-package/hiding-and-restoring-sessions-and-removing-projects:
|
|
36
|
-
en:
|
|
37
|
-
zh:
|
|
36
|
+
en: 7b298aa5c48501d4
|
|
37
|
+
zh: 8ffeec728c1c13fe
|
|
38
38
|
/deepseek-ai-dsh-workspace/understand-the-implementation:
|
|
39
39
|
en: 447ced401b3b14a8
|
|
40
40
|
zh: 3ce2105605223945
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
en: 69327adb9ea52680
|
|
46
46
|
zh: fa32eea5019c7abb
|
|
47
47
|
/deepseek-ai-dsh-workspace/understand-the-implementation/source-map:
|
|
48
|
-
en:
|
|
49
|
-
zh:
|
|
48
|
+
en: 6899c50041c3d1ef
|
|
49
|
+
zh: ea70fda89cc50465
|
|
50
50
|
/deepseek-ai-dsh-workspace/understand-the-implementation/durable-shape:
|
|
51
51
|
en: 056a266f4a15b29d
|
|
52
52
|
zh: e1589f5750662887
|
|
@@ -54,14 +54,11 @@
|
|
|
54
54
|
en: e41db10d48acbf9a
|
|
55
55
|
zh: 457d329fe37ba33c
|
|
56
56
|
/deepseek-ai-dsh-workspace/understand-the-implementation/failure-and-recovery:
|
|
57
|
-
en:
|
|
58
|
-
zh:
|
|
59
|
-
/deepseek-ai-dsh-workspace/understand-the-implementation/invariant:
|
|
60
|
-
en: d20f2bba9aab0d1d
|
|
61
|
-
zh: 2ff06f27e7a8a867
|
|
57
|
+
en: 8b53b9369bea6f67
|
|
58
|
+
zh: 612fd3439a23e035
|
|
62
59
|
/deepseek-ai-dsh-workspace/further-exploration:
|
|
63
|
-
en:
|
|
64
|
-
zh:
|
|
60
|
+
en: 642397907af144b3
|
|
61
|
+
zh: 2b35c1a6237db0c0
|
|
65
62
|
/deepseek-ai-dsh-workspace/model-experience:
|
|
66
63
|
en: 215e7ba838619b7b
|
|
67
64
|
zh: a311da3843709f90
|
|
@@ -78,8 +75,8 @@
|
|
|
78
75
|
en: 524afbded27fb06b
|
|
79
76
|
zh: 9dcf8539495e9c68
|
|
80
77
|
/deepseek-ai-dsh-workspace/known-limitations-and-deferred-work:
|
|
81
|
-
en:
|
|
82
|
-
zh:
|
|
78
|
+
en: 85694227357bbd7c
|
|
79
|
+
zh: 16ad935226c51022
|
|
83
80
|
/deepseek-ai-dsh-workspace/known-limitations-and-deferred-work/dev-note:
|
|
84
81
|
en: ac1d08360a93382b
|
|
85
82
|
zh: 6c58749bae9a6e65
|
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ ctx.workspaceRegistry.list() // shows the project, newest first
|
|
|
66
66
|
|
|
67
67
|
The directory resolver runs inside the mutation queue only when creation is eligible. It returns an absolute path; the registry creates missing parent directories, canonicalizes the path, rechecks Session history, and commits the Workspace with its initialization marker, titled after the requested directory's final segment rather than the canonical one, so a symlink at that path does not retitle the Workspace after its target. An existing directory is reused; a file conflict or directory failure rejects initialization. The [Host controller](../../api/workspace-controller/README.md#first-use-workspace) supplies the Documents path policy.
|
|
68
68
|
|
|
69
|
-
The first successful registration records its identity durably. Repeated calls return it without resolving a directory again; renaming keeps that identity, and deleting its registration does not permit another automatic creation. Directory or registration failure leaves initialization unset for retry. Directories created before a later failure remain on disk. Once directory resolution succeeds, caller cancellation does not roll back directory creation or registration. The [first-use decision](../../../.agents/notes/
|
|
69
|
+
The first successful registration records its identity durably. Repeated calls return it without resolving a directory again; renaming keeps that identity, and deleting its registration does not permit another automatic creation. Directory or registration failure leaves initialization unset for retry. Directories created before a later failure remain on disk. Once directory resolution succeeds, caller cancellation does not roll back directory creation or registration. The [historical first-use decision](../../../.agents/notes/archived/feature/2026-09-20-default-workspace.md) explains this lifetime.
|
|
70
70
|
|
|
71
71
|
### Grouping sessions under a project
|
|
72
72
|
|
|
@@ -76,6 +76,8 @@ A session joins the project of the directory it runs in: create a session in a p
|
|
|
76
76
|
|
|
77
77
|
Hide a session from the grouping when it should stop appearing there: it disappears from the visible list, while its session, history, and place in the project stay intact. A session with running work — its own turn, a running subagent, a background job, or an active reminder — is not hidden underneath that work: the registry refuses with the list of what runs, and a caller that asks to stop the work first has it stopped the way the user's own stop actions do, then hidden. Restore a hidden session when it should appear again: it returns to its recorded position under its project, or to the ungrouped sessions when it belongs to none, and continues the conversation from a regularly ended log. Remove a project when it is no longer needed: it leaves the list, and its folder, files, and session histories are never touched — those sessions become ungrouped. Adding the same directory again afterwards starts a fresh project without the old sessions.
|
|
78
78
|
|
|
79
|
+
Workspace registration does not establish ownership of its directory. A future destructive filesystem action must be separately named, explicitly confirmed, and enforce ownership and safety checks.
|
|
80
|
+
|
|
79
81
|
-----
|
|
80
82
|
|
|
81
83
|
<a id="understand-the-implementation"></a>
|
|
@@ -109,7 +111,6 @@ Archive admission is a capability seam over two Host events this package declare
|
|
|
109
111
|
| [`src/spec.ts`](src/spec.ts) | Domain declaration: record schema, registry state, `defineDomain` spec |
|
|
110
112
|
| [`src/types.ts`](src/types.ts) | Public `Workspace` interface and `WorkspaceId` brand |
|
|
111
113
|
| [`src/paths.ts`](src/paths.ts) | The `realpath` uniqueness canon |
|
|
112
|
-
| [`src/invariant.ts`](src/invariant.ts) | Invariant companion: the entity cache mirrors the durable table |
|
|
113
114
|
|
|
114
115
|
### Durable shape
|
|
115
116
|
|
|
@@ -123,10 +124,6 @@ On start, the registry opens the domain, completes a marked mutation if one is p
|
|
|
123
124
|
|
|
124
125
|
A create or delete whose second write fails rolls the cache and the prior order back; when both the operation and its rollback fail, the durable marker still names the interrupted operation and the next startup completes or rolls it back. A committed delete whose marker cleanup fails still reports success, and the next startup clears the marker idempotently.
|
|
125
126
|
|
|
126
|
-
### Invariant
|
|
127
|
-
|
|
128
|
-
The `workspace-invariant` companion registers the owned relationship: every durable `domain/changed` for the `workspaces` table must name a record the entity cache already holds — a delete is valid only after the registry removed the entity from its cache, so a bypassing write path fails the invariant.
|
|
129
|
-
|
|
130
127
|
</details>
|
|
131
128
|
|
|
132
129
|
-----
|
|
@@ -140,7 +137,7 @@ Read these pages when this package's view is not enough: the subsystem reference
|
|
|
140
137
|
- [Workspace package map](../README.md) — the group's single package and its repository position.
|
|
141
138
|
- [domain KV storage Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.md) — why project records use the domain data form.
|
|
142
139
|
- [Workspace UI product-flow Agent Note](../../../.agents/notes/archived/feature/2026-07-25-workspace-ui-product-flow.md) — how the first start builds projects from session history and how the GUI orders them.
|
|
143
|
-
- [Workspace registration deletion decision](../../../.agents/notes/
|
|
140
|
+
- [historical Workspace registration deletion decision](../../../.agents/notes/archived/feature/2026-07-27-workspace-registration-deletion.md) — why removing a project never deletes its folder or sessions.
|
|
144
141
|
|
|
145
142
|
-----
|
|
146
143
|
|
|
@@ -168,7 +165,7 @@ Independent of live requests: the package never touches a request prefix, so it
|
|
|
168
165
|
|
|
169
166
|
These limits define when the project list is a poor fit or needs special operational care. They are current package constraints, not a task backlog.
|
|
170
167
|
|
|
171
|
-
- **Removal never deletes data** — removing a project leaves its folder, files, and session histories in place; those sessions become ungrouped, and session deletion or folder removal are separate, absent capabilities
|
|
168
|
+
- **Removal never deletes data** — removing a project leaves its folder, files, and session histories in place; those sessions become ungrouped, and session deletion or folder removal are separate, absent capabilities.
|
|
172
169
|
- **A session joins only with a recorded directory** — a session belongs to a project only when its record carries a directory that resolves to the project's path; sessions without one stay ungrouped, and a session from another directory cannot be moved in.
|
|
173
170
|
- **External changes are seen late** — if another process deletes or damages a directory, the project reflects it only at the next refresh or restart.
|
|
174
171
|
- **Archive and unarchive enforce different session checks** — a restore only drops an id from the archive set, so an entry whose session is gone still unarchives and leaves no unknown referent; a restore of an id that is not archived resolves without writing, while `archiveSession` rejects a session that is neither live nor persisted.
|
package/README.zh.md
CHANGED
|
@@ -66,7 +66,7 @@ ctx.workspaceRegistry.list() // shows the project, newest first
|
|
|
66
66
|
|
|
67
67
|
目录解析器仅在允许创建时于变更队列内运行。它返回绝对路径;注册表创建缺失的父目录、规范化路径、重新检查 Session 历史,再一起提交 Workspace 和初始化标记,标题取所请求目录(而非规范路径)的最后一段,因此该路径上的符号链接不会让工作区改用链接目标的名称。已存在的目录直接复用;文件冲突或目录操作失败时拒绝初始化。[Host 控制器](../../api/workspace-controller/README.zh.md#first-use-workspace)提供 Documents 路径策略。
|
|
68
68
|
|
|
69
|
-
首次成功登记会持久保存工作区身份。重复调用直接返回它,不再解析目录;改名保留该身份,删除登记也不会允许再次自动创建。目录或登记失败时,初始化状态保持未设置,可以重试。后续步骤失败前已创建的目录会保留在磁盘上。目录解析成功后,调用方取消操作不会回滚目录创建或登记。[
|
|
69
|
+
首次成功登记会持久保存工作区身份。重复调用直接返回它,不再解析目录;改名保留该身份,删除登记也不会允许再次自动创建。目录或登记失败时,初始化状态保持未设置,可以重试。后续步骤失败前已创建的目录会保留在磁盘上。目录解析成功后,调用方取消操作不会回滚目录创建或登记。[历史首次使用决策](../../../.agents/notes/archived/feature/2026-09-20-default-workspace.md)说明这一生命周期。
|
|
70
70
|
|
|
71
71
|
### 将会话归入项目
|
|
72
72
|
|
|
@@ -76,6 +76,8 @@ ctx.workspaceRegistry.list() // shows the project, newest first
|
|
|
76
76
|
|
|
77
77
|
当会话不应再出现在分组中时隐藏它:它会从可见列表中消失,但其会话、历史与在项目中的位置都保持不变。仍有工作在跑的会话——它自己的回合、运行中的子代理、后台任务或活跃提醒——不会被藏在这些工作之下:注册表会拒绝并列出还在跑的内容;调用方若要求先停止这些工作,注册表会按用户自己的停止操作同样的方式停掉它们,然后再隐藏。当被隐藏的会话应重新出现时恢复它:它会回到其项目下记录的位置;不属于任何项目时则回到 Ungrouped,并从一份正常收尾的日志继续对话。项目不再需要时移除它:它离开列表,而其文件夹、文件与会话历史绝不受影响——这些会话变成 Ungrouped。之后再次添加同一目录会从空项目开始,不会带回旧会话。
|
|
78
78
|
|
|
79
|
+
Workspace 注册不意味着拥有其目录。未来的破坏性文件系统操作必须单独命名、获得明确确认,并执行所有权与安全检查。
|
|
80
|
+
|
|
79
81
|
-----
|
|
80
82
|
|
|
81
83
|
<a id="understand-the-implementation"></a>
|
|
@@ -110,7 +112,6 @@ ctx.workspaceRegistry.list() // shows the project, newest first
|
|
|
110
112
|
| [`src/spec.ts`](src/spec.ts) | 领域声明:记录 schema、注册表状态、`defineDomain` 规范 |
|
|
111
113
|
| [`src/types.ts`](src/types.ts) | 公开 `Workspace` 接口与 `WorkspaceId` 品牌 |
|
|
112
114
|
| [`src/paths.ts`](src/paths.ts) | `realpath` 唯一性规范 |
|
|
113
|
-
| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件:实体缓存镜像持久表 |
|
|
114
115
|
|
|
115
116
|
### 持久形态
|
|
116
117
|
|
|
@@ -124,10 +125,6 @@ ctx.workspaceRegistry.list() // shows the project, newest first
|
|
|
124
125
|
|
|
125
126
|
创建或删除的第二次写入失败时,缓存与先前顺序会回滚;当操作与回滚都失败时,持久标记仍指明被中断的操作,下一次启动会补全或回滚它。已提交的删除即使标记清理失败仍报告成功,下一次启动会幂等地清除该标记。
|
|
126
127
|
|
|
127
|
-
### 不变式
|
|
128
|
-
|
|
129
|
-
`workspace-invariant` 伴生插件注册归属关系:`workspaces` 表的每个持久 `domain/changed` 都必须指向实体缓存已持有的记录——只有在注册表从缓存移除实体之后删除才有效,因此绕过注册表的写入路径会触发不变式失败。
|
|
130
|
-
|
|
131
128
|
</details>
|
|
132
129
|
|
|
133
130
|
-----
|
|
@@ -141,7 +138,7 @@ ctx.workspaceRegistry.list() // shows the project, newest first
|
|
|
141
138
|
- [Workspace 包映射](../README.zh.md)——本组唯一的包及其仓库位置。
|
|
142
139
|
- [领域 KV 存储 Agent Note](../../../.agents/notes/proposed/architecture/2026-07-24-domain-kv-storage-and-workspace.zh.md)——为什么项目记录使用领域数据形式。
|
|
143
140
|
- [Workspace UI 产品流 Agent Note](../../../.agents/notes/archived/feature/2026-07-25-workspace-ui-product-flow.md)——首次启动如何从会话历史构建项目,以及 GUI 如何排序。
|
|
144
|
-
- [
|
|
141
|
+
- [历史删除 Workspace 注册记录决策](../../../.agents/notes/archived/feature/2026-07-27-workspace-registration-deletion.md)——为什么移除项目绝不会删除其文件夹或会话。
|
|
145
142
|
|
|
146
143
|
-----
|
|
147
144
|
|
|
@@ -169,7 +166,7 @@ ctx.workspaceRegistry.list() // shows the project, newest first
|
|
|
169
166
|
|
|
170
167
|
这些限制说明项目列表何时不合适,或何时需要特别的运维注意。它们是当前包约束,不是任务积压。
|
|
171
168
|
|
|
172
|
-
- **移除绝不删除数据**——移除项目会保留其文件夹、文件与会话历史;这些会话变成 Ungrouped
|
|
169
|
+
- **移除绝不删除数据**——移除项目会保留其文件夹、文件与会话历史;这些会话变成 Ungrouped,而会话删除与文件夹移除是彼此独立且尚未提供的功能。
|
|
173
170
|
- **只有带记录目录的会话才能加入**——只有记录中带有可解析为项目路径的目录的会话才属于项目;没有目录的会话保持 Ungrouped,来自其他目录的会话无法移入。
|
|
174
171
|
- **外部变更延迟可见**——如果另一进程删除或损坏目录,项目只能在下次刷新或重启后反映出来。
|
|
175
172
|
- **归档与取消归档执行不同的会话校验**——恢复只是从归档集合中移除 id,因此会话已不存在的条目仍能取消归档,也不会留下未知引用;对未归档 id 执行恢复不写盘即完成,而 `archiveSession` 会拒绝既非实时也未持久化的会话。
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-workspace",
|
|
3
3
|
"description": "Workspace entity registry (ctx.workspaceRegistry): durable workspace records with validated session attachment over the domain data form for the DeepSeek Harness",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.1-alpha.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -18,10 +18,6 @@
|
|
|
18
18
|
"types": "./lib/types/index.d.ts",
|
|
19
19
|
"default": "./lib/index.js"
|
|
20
20
|
},
|
|
21
|
-
"./invariant": {
|
|
22
|
-
"types": "./lib/types/invariant.d.ts",
|
|
23
|
-
"default": "./lib/invariant.js"
|
|
24
|
-
},
|
|
25
21
|
"./types": {
|
|
26
22
|
"types": "./lib/types/types.d.ts",
|
|
27
23
|
"default": "./lib/types/types.js"
|
|
@@ -31,31 +27,28 @@
|
|
|
31
27
|
},
|
|
32
28
|
"files": [
|
|
33
29
|
"lib/index.js",
|
|
34
|
-
"lib/invariant.js",
|
|
35
30
|
"lib/types/**/*.js",
|
|
36
31
|
"lib/types/**/*.d.ts"
|
|
37
32
|
],
|
|
38
33
|
"license": "MIT",
|
|
39
34
|
"peerDependencies": {
|
|
40
|
-
"@deepseek-ai/dsh-session": "0.2.
|
|
41
|
-
"@deepseek-ai/
|
|
42
|
-
"@deepseek-ai/dsh-session-persistence": "0.2.
|
|
43
|
-
"@deepseek-ai/dsh-storage": "0.2.
|
|
44
|
-
"@deepseek-ai/dsh-storage-domain": "0.2.
|
|
45
|
-
"@deepseek-ai/dsh-typert-protocol": "0.2.
|
|
46
|
-
"@deepseek-ai/cordis": "~4.0.4"
|
|
35
|
+
"@deepseek-ai/dsh-session": "0.2.1-alpha.1",
|
|
36
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.1",
|
|
37
|
+
"@deepseek-ai/dsh-session-persistence": "0.2.1-alpha.1",
|
|
38
|
+
"@deepseek-ai/dsh-storage": "0.2.1-alpha.1",
|
|
39
|
+
"@deepseek-ai/dsh-storage-domain": "0.2.1-alpha.1",
|
|
40
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.1"
|
|
47
41
|
},
|
|
48
42
|
"dependencies": {
|
|
49
43
|
"zod": "^4.4.3",
|
|
50
|
-
"@deepseek-ai/dsh-brand": "0.2.
|
|
44
|
+
"@deepseek-ai/dsh-brand": "0.2.1-alpha.1"
|
|
51
45
|
},
|
|
52
46
|
"devDependencies": {
|
|
53
|
-
"@deepseek-ai/cordis": "~4.0.
|
|
54
|
-
"@deepseek-ai/dsh-
|
|
55
|
-
"@deepseek-ai/dsh-session": "0.2.
|
|
56
|
-
"@deepseek-ai/dsh-
|
|
57
|
-
"@deepseek-ai/dsh-
|
|
58
|
-
"@deepseek-ai/dsh-storage-domain": "0.2.
|
|
59
|
-
"@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2"
|
|
47
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.1",
|
|
48
|
+
"@deepseek-ai/dsh-session": "0.2.1-alpha.1",
|
|
49
|
+
"@deepseek-ai/dsh-session-persistence": "0.2.1-alpha.1",
|
|
50
|
+
"@deepseek-ai/dsh-storage": "0.2.1-alpha.1",
|
|
51
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.1",
|
|
52
|
+
"@deepseek-ai/dsh-storage-domain": "0.2.1-alpha.1"
|
|
60
53
|
}
|
|
61
54
|
}
|
package/lib/invariant.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import "node:crypto";
|
|
2
|
-
import "node:fs/promises";
|
|
3
|
-
import { Service } from "@deepseek-ai/cordis";
|
|
4
|
-
import "node:path";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { brandString } from "@deepseek-ai/dsh-brand";
|
|
7
|
-
import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
|
|
8
|
-
//#endregion
|
|
9
|
-
//#region src/spec.ts
|
|
10
|
-
/**
|
|
11
|
-
* The workspace domain declaration: record schema and the `defineDomain` spec
|
|
12
|
-
* the registry opens. The zod schema validates the shipped format at the
|
|
13
|
-
* durability boundary and is the direct source of a future RPC wire projection.
|
|
14
|
-
* @module @deepseek-ai/dsh-workspace/src/spec
|
|
15
|
-
*/
|
|
16
|
-
/** Workspace id schema at the durable boundary; branding has no runtime representation. */
|
|
17
|
-
const workspaceId = z.string().transform((value) => value);
|
|
18
|
-
const sessionId = z.string().transform((value) => brandString(value));
|
|
19
|
-
/**
|
|
20
|
-
* Durable shape of one workspace record. `path` is the `fs.realpath` canon
|
|
21
|
-
* stamped at create; `sessionIds` is the ordered ownership account (array
|
|
22
|
-
* order is display order); timestamps are ISO-8601 strings.
|
|
23
|
-
*/
|
|
24
|
-
const workspaceRecord = z.object({
|
|
25
|
-
path: z.string(),
|
|
26
|
-
title: z.string(),
|
|
27
|
-
sessionIds: z.array(sessionId),
|
|
28
|
-
createdAt: z.string(),
|
|
29
|
-
updatedAt: z.string()
|
|
30
|
-
});
|
|
31
|
-
/**
|
|
32
|
-
* Recoverable two-write mutation marker. The marker is persisted before the
|
|
33
|
-
* record/order pair can diverge, so startup can distinguish an interrupted
|
|
34
|
-
* registry operation from unexplained medium corruption.
|
|
35
|
-
*/
|
|
36
|
-
const workspacePendingMutation = z.discriminatedUnion("operation", [z.object({
|
|
37
|
-
operation: z.literal("create"),
|
|
38
|
-
workspaceId
|
|
39
|
-
}), z.object({
|
|
40
|
-
operation: z.literal("delete"),
|
|
41
|
-
workspaceId
|
|
42
|
-
})]);
|
|
43
|
-
defineDomain({
|
|
44
|
-
name: "workspace",
|
|
45
|
-
version: 2,
|
|
46
|
-
global: {
|
|
47
|
-
schema: z.object({
|
|
48
|
-
initialized: z.boolean(),
|
|
49
|
-
/** First-use Workspace identity, retained after its registration is deleted. */
|
|
50
|
-
defaultWorkspaceId: workspaceId.optional(),
|
|
51
|
-
workspaceIds: z.array(workspaceId),
|
|
52
|
-
archivedSessionIds: z.array(sessionId).default([]),
|
|
53
|
-
pinnedSessionIds: z.array(sessionId).default([]),
|
|
54
|
-
pendingMutation: workspacePendingMutation.optional()
|
|
55
|
-
}),
|
|
56
|
-
initial: {
|
|
57
|
-
initialized: false,
|
|
58
|
-
workspaceIds: [],
|
|
59
|
-
archivedSessionIds: [],
|
|
60
|
-
pinnedSessionIds: []
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
tables: { workspaces: domainTable(workspaceRecord) }
|
|
64
|
-
});
|
|
65
|
-
//#endregion
|
|
66
|
-
//#region src/index.ts
|
|
67
|
-
/**
|
|
68
|
-
* Workspace entity registry (`ctx.workspaceRegistry`): durable workspace records,
|
|
69
|
-
* stable registry order, and header-validated session membership over the
|
|
70
|
-
* domain data form.
|
|
71
|
-
* @module @deepseek-ai/dsh-workspace
|
|
72
|
-
*/
|
|
73
|
-
/**
|
|
74
|
-
* Brand a string as a {@link WorkspaceId}.
|
|
75
|
-
* @param id - Raw workspace id string.
|
|
76
|
-
* @returns the same string, branded at compile time.
|
|
77
|
-
*/
|
|
78
|
-
function WorkspaceId(id) {
|
|
79
|
-
return id;
|
|
80
|
-
}
|
|
81
|
-
Service.init;
|
|
82
|
-
//#endregion
|
|
83
|
-
//#region lib/types/invariant.js
|
|
84
|
-
/**
|
|
85
|
-
* Package-owned invariant companion for `@deepseek-ai/dsh-workspace`.
|
|
86
|
-
* @module @deepseek-ai/dsh-workspace/invariant
|
|
87
|
-
*/
|
|
88
|
-
const PACKAGE_NAME = "@deepseek-ai/dsh-workspace";
|
|
89
|
-
/** Cordis companion plugin name. */
|
|
90
|
-
const name = "workspace-invariant";
|
|
91
|
-
/** Service required before the companion can reserve package ownership. */
|
|
92
|
-
const inject = ["invariants"];
|
|
93
|
-
/**
|
|
94
|
-
* Owned relationship: the registry's entity cache mirrors the workspace
|
|
95
|
-
* domain's durable table. Every `domain/changed` for the `workspaces` table
|
|
96
|
-
* must name a record the cache already holds an entity for (the registry
|
|
97
|
-
* caches before the durable put and mutates only through cached entities).
|
|
98
|
-
* A delete is valid only after the registry has removed the entity from its
|
|
99
|
-
* cache, whether for create rollback or an explicit registration deletion;
|
|
100
|
-
* deleting while the cache still publishes the entity proves a bypass.
|
|
101
|
-
*/
|
|
102
|
-
const install = Object.assign((ctx, fail) => {
|
|
103
|
-
ctx.on("domain/changed", (change) => {
|
|
104
|
-
if (change.domain !== "workspace" || change.table !== "workspaces") return;
|
|
105
|
-
if (change.operation === "deleted") {
|
|
106
|
-
if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) !== void 0) fail(`workspace record '${change.key}' was deleted while the registry cache still publishes it — some write path bypassed ctx.workspaceRegistry`);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) === void 0) fail(`workspace record '${change.key}' landed durably but the registry cache holds no entity for it — the cache and the domain table have diverged`);
|
|
110
|
-
});
|
|
111
|
-
}, { inject: ["workspaceRegistry"] });
|
|
112
|
-
/**
|
|
113
|
-
* Register this package's invariant companion.
|
|
114
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
115
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
116
|
-
*/
|
|
117
|
-
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
118
|
-
//#endregion
|
|
119
|
-
export { apply, inject, name };
|
package/lib/types/invariant.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Package-owned invariant companion for `@deepseek-ai/dsh-workspace`.
|
|
3
|
-
* @module @deepseek-ai/dsh-workspace/invariant
|
|
4
|
-
*/
|
|
5
|
-
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
-
/** Cordis companion plugin name. */
|
|
7
|
-
export declare const name = "workspace-invariant";
|
|
8
|
-
/** Service required before the companion can reserve package ownership. */
|
|
9
|
-
export declare const inject: string[];
|
|
10
|
-
/**
|
|
11
|
-
* Register this package's invariant companion.
|
|
12
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
-
*/
|
|
15
|
-
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
-
//# sourceMappingURL=invariant.d.ts.map
|
package/lib/types/invariant.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Package-owned invariant companion for `@deepseek-ai/dsh-workspace`.
|
|
3
|
-
* @module @deepseek-ai/dsh-workspace/invariant
|
|
4
|
-
*/
|
|
5
|
-
import { WorkspaceId } from '@deepseek-ai/dsh-workspace';
|
|
6
|
-
const PACKAGE_NAME = '@deepseek-ai/dsh-workspace';
|
|
7
|
-
/** Cordis companion plugin name. */
|
|
8
|
-
export const name = 'workspace-invariant';
|
|
9
|
-
/** Service required before the companion can reserve package ownership. */
|
|
10
|
-
export const inject = ['invariants'];
|
|
11
|
-
/**
|
|
12
|
-
* Owned relationship: the registry's entity cache mirrors the workspace
|
|
13
|
-
* domain's durable table. Every `domain/changed` for the `workspaces` table
|
|
14
|
-
* must name a record the cache already holds an entity for (the registry
|
|
15
|
-
* caches before the durable put and mutates only through cached entities).
|
|
16
|
-
* A delete is valid only after the registry has removed the entity from its
|
|
17
|
-
* cache, whether for create rollback or an explicit registration deletion;
|
|
18
|
-
* deleting while the cache still publishes the entity proves a bypass.
|
|
19
|
-
*/
|
|
20
|
-
const install = Object.assign((ctx, fail) => {
|
|
21
|
-
ctx.on('domain/changed', (change) => {
|
|
22
|
-
if (change.domain !== 'workspace' || change.table !== 'workspaces')
|
|
23
|
-
return;
|
|
24
|
-
if (change.operation === 'deleted') {
|
|
25
|
-
if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) !== undefined) {
|
|
26
|
-
fail(`workspace record '${change.key}' was deleted while the registry cache still `
|
|
27
|
-
+ 'publishes it — some write path bypassed ctx.workspaceRegistry');
|
|
28
|
-
}
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (ctx.workspaceRegistry.get(WorkspaceId(change.key)) === undefined) {
|
|
32
|
-
fail(`workspace record '${change.key}' landed durably but the registry cache holds `
|
|
33
|
-
+ 'no entity for it — the cache and the domain table have diverged');
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
}, { inject: ['workspaceRegistry'] });
|
|
37
|
-
/**
|
|
38
|
-
* Register this package's invariant companion.
|
|
39
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
40
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
41
|
-
*/
|
|
42
|
-
export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
43
|
-
//# sourceMappingURL=invariant.js.map
|