@ran-sh/dsh-crew 1.6.2 → 1.7.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-crew",
3
- "version": "1.6.2",
3
+ "version": "1.7.1",
4
4
  "description": "Dispatch subtasks to DeepSeek Harness (DSH) agents as native subagents with live progress",
5
5
  "author": {
6
6
  "name": "ZSeven-W"
package/package.json CHANGED
@@ -1,232 +1,233 @@
1
- {
2
- "name": "@ran-sh/dsh-crew",
3
- "version": "1.6.2",
4
- "type": "module",
5
- "main": "./src/hub/entry.mjs",
6
- "bin": {
7
- "dsh-crew": "bin/dsh-crew.mjs"
8
- },
9
- "description": "DeepSeek Harness plugin: dispatch work to DSH agents from Claude Code / Codex, as native subagents with live progress",
10
- "dshCrew": {
11
- "payloadSchema": 2,
12
- "windowsSupervisorHandoff": 1
13
- },
14
- "dsh": {
15
- "bundle": {
16
- "patch": "./cordis.patch.yml"
17
- },
18
- "client": {
19
- "inject": [
20
- "@deepseek-ai/dsh-client-ui-renderer",
21
- "@deepseek-ai/dsh-client-locale",
22
- "@deepseek-ai/dsh-client-ui-settings"
23
- ],
24
- "platform": "web"
25
- }
26
- },
27
- "scripts": {
28
- "mcp": "node src/server.mjs",
29
- "build:client": "tsdown src/client/entry.tsx --format cjs --platform browser --target es2022 --tsconfig tsconfig.client.json --deps.never-bundle react --deps.never-bundle react/jsx-runtime --deps.never-bundle react-dom --deps.never-bundle react-dom/client --out-dir .client-build --clean --logLevel warn && tsdown src/client/quick-entry.tsx --format cjs --platform browser --target es2022 --tsconfig tsconfig.client.json --deps.never-bundle react --deps.never-bundle react/jsx-runtime --deps.never-bundle react-dom --deps.never-bundle react-dom/client --out-dir .client-build --no-clean --logLevel warn && node scripts/build-client.mjs",
30
- "verify:npm-install": "node scripts/verify-npm-install.mjs",
31
- "verify:npm-install:official": "node scripts/verify-npm-install.mjs --with-official-dsh",
32
- "verify:official-bridge": "node scripts/verify-official-bridge-e2e.mjs --diagnostic-only"
33
- },
34
- "dependencies": {
35
- "@modelcontextprotocol/sdk": "^1.25.4",
36
- "zod": "^3.24.0"
37
- },
38
- "exports": {
39
- ".": "./src/hub/entry.mjs",
40
- "./client": "./lib/client.js",
41
- "./package.json": "./package.json"
42
- },
43
- "peerDependencies": {
44
- "@deepseek-ai/dsh": "0.1.5-rc.2",
45
- "@deepseek-ai/dsh-agent": "0.1.5-rc.2",
46
- "@deepseek-ai/dsh-agent-loop": "0.1.5-rc.2",
47
- "@deepseek-ai/dsh-agent-presets": "0.1.5-rc.2",
48
- "@deepseek-ai/dsh-bash-local": "0.1.5-rc.2",
49
- "@deepseek-ai/dsh-client-locale": "0.1.5-rc.2",
50
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.2",
51
- "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.2",
52
- "@deepseek-ai/dsh-compaction-basic": "0.1.5-rc.2",
53
- "@deepseek-ai/dsh-fs-local": "0.1.5-rc.2",
54
- "@deepseek-ai/dsh-fs-observation-policy": "0.1.5-rc.2",
55
- "@deepseek-ai/dsh-llm": "0.1.5-rc.2",
56
- "@deepseek-ai/dsh-llm-deepseek": "0.1.5-rc.2",
57
- "@deepseek-ai/dsh-sandbox-local": "0.1.5-rc.2",
58
- "@deepseek-ai/dsh-sandbox-policy": "0.1.5-rc.2",
59
- "@deepseek-ai/dsh-sdk-client": "0.1.5-rc.2",
60
- "@deepseek-ai/dsh-sdk-jsonrpc-server": "0.1.5-rc.2",
61
- "@deepseek-ai/dsh-sdk-minimal": "0.1.5-rc.2",
62
- "@deepseek-ai/dsh-session": "0.1.5-rc.2",
63
- "@deepseek-ai/dsh-session-persistence-jsonl": "0.1.5-rc.2",
64
- "@deepseek-ai/dsh-subprocess-local": "0.1.5-rc.2",
65
- "@deepseek-ai/dsh-token-meter": "0.1.5-rc.2",
66
- "@deepseek-ai/dsh-tool-fs": "0.1.5-rc.2",
67
- "@deepseek-ai/dsh-tool-todo": "0.1.5-rc.2",
68
- "react": "^18.0.0",
69
- "react-dom": "^18.0.0"
70
- },
71
- "peerDependenciesMeta": {
72
- "@deepseek-ai/dsh": {
73
- "optional": true
74
- },
75
- "@deepseek-ai/dsh-agent": {
76
- "optional": true
77
- },
78
- "@deepseek-ai/dsh-agent-loop": {
79
- "optional": true
80
- },
81
- "@deepseek-ai/dsh-agent-presets": {
82
- "optional": true
83
- },
84
- "@deepseek-ai/dsh-bash-local": {
85
- "optional": true
86
- },
87
- "@deepseek-ai/dsh-client-locale": {
88
- "optional": true
89
- },
90
- "@deepseek-ai/dsh-client-ui-renderer": {
91
- "optional": true
92
- },
93
- "@deepseek-ai/dsh-client-ui-settings": {
94
- "optional": true
95
- },
96
- "@deepseek-ai/dsh-compaction-basic": {
97
- "optional": true
98
- },
99
- "@deepseek-ai/dsh-fs-local": {
100
- "optional": true
101
- },
102
- "@deepseek-ai/dsh-fs-observation-policy": {
103
- "optional": true
104
- },
105
- "@deepseek-ai/dsh-llm": {
106
- "optional": true
107
- },
108
- "@deepseek-ai/dsh-llm-deepseek": {
109
- "optional": true
110
- },
111
- "@deepseek-ai/dsh-sandbox-local": {
112
- "optional": true
113
- },
114
- "@deepseek-ai/dsh-sandbox-policy": {
115
- "optional": true
116
- },
117
- "@deepseek-ai/dsh-sdk-client": {
118
- "optional": true
119
- },
120
- "@deepseek-ai/dsh-sdk-jsonrpc-server": {
121
- "optional": true
122
- },
123
- "@deepseek-ai/dsh-sdk-minimal": {
124
- "optional": true
125
- },
126
- "@deepseek-ai/dsh-session": {
127
- "optional": true
128
- },
129
- "@deepseek-ai/dsh-session-persistence-jsonl": {
130
- "optional": true
131
- },
132
- "@deepseek-ai/dsh-subprocess-local": {
133
- "optional": true
134
- },
135
- "@deepseek-ai/dsh-token-meter": {
136
- "optional": true
137
- },
138
- "@deepseek-ai/dsh-tool-fs": {
139
- "optional": true
140
- },
141
- "@deepseek-ai/dsh-tool-todo": {
142
- "optional": true
143
- },
144
- "react": {
145
- "optional": true
146
- },
147
- "react-dom": {
148
- "optional": true
149
- }
150
- },
151
- "devDependencies": {
152
- "@deepseek-ai/dsh": "0.1.5-rc.2",
153
- "@deepseek-ai/dsh-agent": "0.1.5-rc.2",
154
- "@deepseek-ai/dsh-agent-loop": "0.1.5-rc.2",
155
- "@deepseek-ai/dsh-agent-presets": "0.1.5-rc.2",
156
- "@deepseek-ai/dsh-bash-local": "0.1.5-rc.2",
157
- "@deepseek-ai/dsh-client-locale": "0.1.5-rc.2",
158
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.2",
159
- "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.2",
160
- "@deepseek-ai/dsh-compaction-basic": "0.1.5-rc.2",
161
- "@deepseek-ai/dsh-fs-local": "0.1.5-rc.2",
162
- "@deepseek-ai/dsh-fs-observation-policy": "0.1.5-rc.2",
163
- "@deepseek-ai/dsh-llm": "0.1.5-rc.2",
164
- "@deepseek-ai/dsh-llm-deepseek": "0.1.5-rc.2",
165
- "@deepseek-ai/dsh-sandbox-local": "0.1.5-rc.2",
166
- "@deepseek-ai/dsh-sandbox-policy": "0.1.5-rc.2",
167
- "@deepseek-ai/dsh-sdk-client": "0.1.5-rc.2",
168
- "@deepseek-ai/dsh-sdk-jsonrpc-server": "0.1.5-rc.2",
169
- "@deepseek-ai/dsh-sdk-minimal": "0.1.5-rc.2",
170
- "@deepseek-ai/dsh-session": "0.1.5-rc.2",
171
- "@deepseek-ai/dsh-session-persistence-jsonl": "0.1.5-rc.2",
172
- "@deepseek-ai/dsh-subprocess-local": "0.1.5-rc.2",
173
- "@deepseek-ai/dsh-token-meter": "0.1.5-rc.2",
174
- "@deepseek-ai/dsh-tool-fs": "0.1.5-rc.2",
175
- "@deepseek-ai/dsh-tool-todo": "0.1.5-rc.2",
176
- "@types/react": "^18.3.0",
177
- "react": "^18.3.1",
178
- "react-dom": "^18.3.1",
179
- "tsdown": "0.22.14",
180
- "typescript": "^5.6.0"
181
- },
182
- "license": "MIT",
183
- "repository": {
184
- "type": "git",
185
- "url": "git+https://github.com/Ran-sh/dsh-crew.git"
186
- },
187
- "homepage": "https://github.com/Ran-sh/dsh-crew",
188
- "bugs": {
189
- "url": "https://github.com/Ran-sh/dsh-crew/issues"
190
- },
191
- "keywords": [
192
- "dsh",
193
- "deepseek",
194
- "claude-code",
195
- "codex",
196
- "zcode",
197
- "windows",
198
- "subagent",
199
- "worker",
200
- "multimodal",
201
- "plugin",
202
- "agent"
203
- ],
204
- "files": [
205
- "bin",
206
- "lib",
207
- "src",
208
- "scripts",
209
- "agents",
210
- "commands",
211
- "codex",
212
- "zcode",
213
- "statusline",
214
- "official-web-bridge",
215
- "windows",
216
- "cordis.patch.yml",
217
- "worker.cordis.yml",
218
- ".claude-plugin",
219
- "README.md",
220
- "README.*.md",
221
- "docs/job-contracts.md",
222
- "docs/readiness-matrix.md",
223
- "docs/gpt-relay-extension.md",
224
- "docs/ui-surfaces.md",
225
- "docs/installation.md",
226
- "docs/images/dsh-crew-logo.png",
227
- "docs/images/dsh-crew-overview.png",
228
- "docs/images/dsh-crew-host.png",
229
- "docs/images/dsh-crew-jobs.png",
230
- "LICENSE"
231
- ]
232
- }
1
+ {
2
+ "name": "@ran-sh/dsh-crew",
3
+ "version": "1.7.1",
4
+ "type": "module",
5
+ "main": "./src/hub/entry.mjs",
6
+ "bin": {
7
+ "dsh-crew": "bin/dsh-crew.mjs"
8
+ },
9
+ "description": "DeepSeek Harness plugin: dispatch work to DSH agents from Claude Code / Codex, as native subagents with live progress",
10
+ "dshCrew": {
11
+ "payloadSchema": 2,
12
+ "windowsSupervisorHandoff": 1
13
+ },
14
+ "dsh": {
15
+ "bundle": {
16
+ "patch": "./cordis.patch.yml"
17
+ },
18
+ "client": {
19
+ "inject": [
20
+ "@deepseek-ai/dsh-client-ui-renderer",
21
+ "@deepseek-ai/dsh-client-locale",
22
+ "@deepseek-ai/dsh-client-ui-settings"
23
+ ],
24
+ "platform": "web"
25
+ }
26
+ },
27
+ "scripts": {
28
+ "mcp": "node src/server.mjs",
29
+ "build:client": "tsdown src/client/entry.tsx --format cjs --platform browser --target es2022 --tsconfig tsconfig.client.json --deps.never-bundle react --deps.never-bundle react/jsx-runtime --deps.never-bundle react-dom --deps.never-bundle react-dom/client --out-dir .client-build --clean --logLevel warn && tsdown src/client/quick-entry.tsx --format cjs --platform browser --target es2022 --tsconfig tsconfig.client.json --deps.never-bundle react --deps.never-bundle react/jsx-runtime --deps.never-bundle react-dom --deps.never-bundle react-dom/client --out-dir .client-build --no-clean --logLevel warn && node scripts/build-client.mjs",
30
+ "verify:npm-install": "node scripts/verify-npm-install.mjs",
31
+ "verify:npm-install:official": "node scripts/verify-npm-install.mjs --with-official-dsh",
32
+ "verify:official-bridge": "node scripts/verify-official-bridge-e2e.mjs --diagnostic-only"
33
+ },
34
+ "dependencies": {
35
+ "@modelcontextprotocol/sdk": "^1.25.4",
36
+ "zod": "^3.24.0"
37
+ },
38
+ "exports": {
39
+ ".": "./src/hub/entry.mjs",
40
+ "./client": "./lib/client.js",
41
+ "./package.json": "./package.json"
42
+ },
43
+ "peerDependencies": {
44
+ "@deepseek-ai/dsh": "0.1.5-rc.2",
45
+ "@deepseek-ai/dsh-agent": "0.1.5-rc.2",
46
+ "@deepseek-ai/dsh-agent-loop": "0.1.5-rc.2",
47
+ "@deepseek-ai/dsh-agent-presets": "0.1.5-rc.2",
48
+ "@deepseek-ai/dsh-bash-local": "0.1.5-rc.2",
49
+ "@deepseek-ai/dsh-client-locale": "0.1.5-rc.2",
50
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.2",
51
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.2",
52
+ "@deepseek-ai/dsh-compaction-basic": "0.1.5-rc.2",
53
+ "@deepseek-ai/dsh-fs-local": "0.1.5-rc.2",
54
+ "@deepseek-ai/dsh-fs-observation-policy": "0.1.5-rc.2",
55
+ "@deepseek-ai/dsh-llm": "0.1.5-rc.2",
56
+ "@deepseek-ai/dsh-llm-deepseek": "0.1.5-rc.2",
57
+ "@deepseek-ai/dsh-sandbox-local": "0.1.5-rc.2",
58
+ "@deepseek-ai/dsh-sandbox-policy": "0.1.5-rc.2",
59
+ "@deepseek-ai/dsh-sdk-client": "0.1.5-rc.2",
60
+ "@deepseek-ai/dsh-sdk-jsonrpc-server": "0.1.5-rc.2",
61
+ "@deepseek-ai/dsh-sdk-minimal": "0.1.5-rc.2",
62
+ "@deepseek-ai/dsh-session": "0.1.5-rc.2",
63
+ "@deepseek-ai/dsh-session-persistence-jsonl": "0.1.5-rc.2",
64
+ "@deepseek-ai/dsh-subprocess-local": "0.1.5-rc.2",
65
+ "@deepseek-ai/dsh-token-meter": "0.1.5-rc.2",
66
+ "@deepseek-ai/dsh-tool-fs": "0.1.5-rc.2",
67
+ "@deepseek-ai/dsh-tool-todo": "0.1.5-rc.2",
68
+ "react": "^18.0.0",
69
+ "react-dom": "^18.0.0"
70
+ },
71
+ "peerDependenciesMeta": {
72
+ "@deepseek-ai/dsh": {
73
+ "optional": true
74
+ },
75
+ "@deepseek-ai/dsh-agent": {
76
+ "optional": true
77
+ },
78
+ "@deepseek-ai/dsh-agent-loop": {
79
+ "optional": true
80
+ },
81
+ "@deepseek-ai/dsh-agent-presets": {
82
+ "optional": true
83
+ },
84
+ "@deepseek-ai/dsh-bash-local": {
85
+ "optional": true
86
+ },
87
+ "@deepseek-ai/dsh-client-locale": {
88
+ "optional": true
89
+ },
90
+ "@deepseek-ai/dsh-client-ui-renderer": {
91
+ "optional": true
92
+ },
93
+ "@deepseek-ai/dsh-client-ui-settings": {
94
+ "optional": true
95
+ },
96
+ "@deepseek-ai/dsh-compaction-basic": {
97
+ "optional": true
98
+ },
99
+ "@deepseek-ai/dsh-fs-local": {
100
+ "optional": true
101
+ },
102
+ "@deepseek-ai/dsh-fs-observation-policy": {
103
+ "optional": true
104
+ },
105
+ "@deepseek-ai/dsh-llm": {
106
+ "optional": true
107
+ },
108
+ "@deepseek-ai/dsh-llm-deepseek": {
109
+ "optional": true
110
+ },
111
+ "@deepseek-ai/dsh-sandbox-local": {
112
+ "optional": true
113
+ },
114
+ "@deepseek-ai/dsh-sandbox-policy": {
115
+ "optional": true
116
+ },
117
+ "@deepseek-ai/dsh-sdk-client": {
118
+ "optional": true
119
+ },
120
+ "@deepseek-ai/dsh-sdk-jsonrpc-server": {
121
+ "optional": true
122
+ },
123
+ "@deepseek-ai/dsh-sdk-minimal": {
124
+ "optional": true
125
+ },
126
+ "@deepseek-ai/dsh-session": {
127
+ "optional": true
128
+ },
129
+ "@deepseek-ai/dsh-session-persistence-jsonl": {
130
+ "optional": true
131
+ },
132
+ "@deepseek-ai/dsh-subprocess-local": {
133
+ "optional": true
134
+ },
135
+ "@deepseek-ai/dsh-token-meter": {
136
+ "optional": true
137
+ },
138
+ "@deepseek-ai/dsh-tool-fs": {
139
+ "optional": true
140
+ },
141
+ "@deepseek-ai/dsh-tool-todo": {
142
+ "optional": true
143
+ },
144
+ "react": {
145
+ "optional": true
146
+ },
147
+ "react-dom": {
148
+ "optional": true
149
+ }
150
+ },
151
+ "devDependencies": {
152
+ "@deepseek-ai/dsh": "0.1.5-rc.2",
153
+ "@deepseek-ai/dsh-agent": "0.1.5-rc.2",
154
+ "@deepseek-ai/dsh-agent-loop": "0.1.5-rc.2",
155
+ "@deepseek-ai/dsh-agent-presets": "0.1.5-rc.2",
156
+ "@deepseek-ai/dsh-bash-local": "0.1.5-rc.2",
157
+ "@deepseek-ai/dsh-client-locale": "0.1.5-rc.2",
158
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.5-rc.2",
159
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.2",
160
+ "@deepseek-ai/dsh-compaction-basic": "0.1.5-rc.2",
161
+ "@deepseek-ai/dsh-fs-local": "0.1.5-rc.2",
162
+ "@deepseek-ai/dsh-fs-observation-policy": "0.1.5-rc.2",
163
+ "@deepseek-ai/dsh-llm": "0.1.5-rc.2",
164
+ "@deepseek-ai/dsh-llm-deepseek": "0.1.5-rc.2",
165
+ "@deepseek-ai/dsh-sandbox-local": "0.1.5-rc.2",
166
+ "@deepseek-ai/dsh-sandbox-policy": "0.1.5-rc.2",
167
+ "@deepseek-ai/dsh-sdk-client": "0.1.5-rc.2",
168
+ "@deepseek-ai/dsh-sdk-jsonrpc-server": "0.1.5-rc.2",
169
+ "@deepseek-ai/dsh-sdk-minimal": "0.1.5-rc.2",
170
+ "@deepseek-ai/dsh-session": "0.1.5-rc.2",
171
+ "@deepseek-ai/dsh-session-persistence-jsonl": "0.1.5-rc.2",
172
+ "@deepseek-ai/dsh-subprocess-local": "0.1.5-rc.2",
173
+ "@deepseek-ai/dsh-token-meter": "0.1.5-rc.2",
174
+ "@deepseek-ai/dsh-tool-fs": "0.1.5-rc.2",
175
+ "@deepseek-ai/dsh-tool-todo": "0.1.5-rc.2",
176
+ "@types/react": "^18.3.0",
177
+ "react": "^18.3.1",
178
+ "react-dom": "^18.3.1",
179
+ "tsdown": "0.22.14",
180
+ "typescript": "^5.6.0"
181
+ },
182
+ "license": "MIT",
183
+ "repository": {
184
+ "type": "git",
185
+ "url": "git+https://github.com/Ran-sh/dsh-crew.git"
186
+ },
187
+ "homepage": "https://github.com/Ran-sh/dsh-crew",
188
+ "bugs": {
189
+ "url": "https://github.com/Ran-sh/dsh-crew/issues"
190
+ },
191
+ "keywords": [
192
+ "dsh",
193
+ "deepseek",
194
+ "claude-code",
195
+ "codex",
196
+ "zcode",
197
+ "windows",
198
+ "subagent",
199
+ "worker",
200
+ "multimodal",
201
+ "plugin",
202
+ "agent"
203
+ ],
204
+ "files": [
205
+ "bin",
206
+ "lib",
207
+ "src",
208
+ "scripts",
209
+ "agents",
210
+ "commands",
211
+ "codex",
212
+ "zcode",
213
+ "skills",
214
+ "statusline",
215
+ "official-web-bridge",
216
+ "windows",
217
+ "cordis.patch.yml",
218
+ "worker.cordis.yml",
219
+ ".claude-plugin",
220
+ "README.md",
221
+ "README.*.md",
222
+ "docs/job-contracts.md",
223
+ "docs/readiness-matrix.md",
224
+ "docs/gpt-relay-extension.md",
225
+ "docs/ui-surfaces.md",
226
+ "docs/installation.md",
227
+ "docs/images/dsh-crew-logo.png",
228
+ "docs/images/dsh-crew-overview.png",
229
+ "docs/images/dsh-crew-host.png",
230
+ "docs/images/dsh-crew-jobs.png",
231
+ "LICENSE"
232
+ ]
233
+ }
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: dsh-crew
3
+ description: "DSH Crew worker/reviewer dispatch (dsh-crew MCP tools): dispatch coding work, configure models and review gates, and maintain session history. Load only when the operator asks to use dsh-crew."
4
+ ---
5
+
6
+ # DSH Crew
7
+
8
+ **On demand only.** Do not dispatch Crew work because it might help — dispatch
9
+ because the operator asked for it in this turn ("use dsh-crew", "call dsh-crew",
10
+ "派给 crew", and the like). Crew is a capability the operator chooses, not a
11
+ standing policy, so nothing here should shape how you work until it is invoked.
12
+ That is the whole point of it living in a skill rather than in a global
13
+ instruction file: the host's own way of working stays untouched.
14
+
15
+ Once invoked, this is the operating guide.
16
+
17
+ ## What it is
18
+
19
+ A plugin on the official DeepSeek Harness. A hub on 3210 dispatches jobs to
20
+ worker/reviewer models, optionally in an isolated git worktree, and returns a
21
+ compact structured result. Codex, ZCode and Claude Code all reach it through the
22
+ same `dsh-crew` MCP server, so the behaviour below is identical from any host.
23
+
24
+ ## Tools
25
+
26
+ | Tool | Use |
27
+ |---|---|
28
+ | `dsh_run_worker` | dispatch one unit and wait for the result |
29
+ | `dsh_spawn_worker` | dispatch and return a workflow id immediately |
30
+ | `dsh_worker_status` | list workflows with phase, role, model, tokens |
31
+ | `dsh_worker_result` | fetch or wait for one workflow (`wait_seconds`) |
32
+ | `dsh_worker_cancel` | cancel a workflow |
33
+ | `dsh_worker_config` | read/update session settings: enable dispatch, tier, effort, timeout, presets, policy |
34
+
35
+ `dsh_worker_config` with no arguments is the cheapest way to answer "what is
36
+ Crew set to right now". Its settings last for the session only; persisted
37
+ changes belong in the 3210 panel.
38
+
39
+ ## Choosing what to dispatch
40
+
41
+ Delegate a bounded, independently verifiable unit when isolation,
42
+ specialization, parallel work or independent review earns its cost. Give each
43
+ unit its objective, owned files, workspace, constraints and acceptance
44
+ evidence. Keep ambiguity, integration, external effects and final communication
45
+ yourself. Trivial work stays local.
46
+
47
+ Continue authorized work after a successful subtask; a returned workflow is a
48
+ checkpoint, not the end of the task. If a worker's result is incomplete or its
49
+ review asks for changes, that is a task result to act on — not approval.
50
+
51
+ ## Configuration
52
+
53
+ Two surfaces, and they are not equivalent:
54
+
55
+ - **3210** — the full control plane: workflow, model priority, routing, provider
56
+ lifecycle, history, and the peak/off-peak schedule.
57
+ - **3080** — the quick surface (sub-agent switch, model priority order). It
58
+ writes through the same config via a restricted key allowlist.
59
+
60
+ Everything lands in `~/.config/dsh-crew/config.json`. Prefer the panel over hand
61
+ editing: the write path validates, and a hand edit can be silently dropped by
62
+ the loader.
63
+
64
+ ## Model routing
65
+
66
+ Worker and reviewer each walk an ordered `{provider, model}` priority list and
67
+ take the first admissible candidate; an empty list falls through to Harness
68
+ Default. Candidates are skipped when the provider is unhealthy, tombstoned, or
69
+ inside a peak window it is blocked for. A `warn` rule keeps the model selectable
70
+ and records the advisory in the selection trace.
71
+
72
+ The **peak/off-peak schedule** (panel → 波峰波谷调度) restricts chosen models by
73
+ local wall clock: `block` skips the model during peak so the next candidate
74
+ serves the job, `warn` uses it and flags the choice, and an unlisted model is
75
+ unrestricted. Defaults mirror DeepSeek's published peak hours.
76
+
77
+ ## Work
78
+
79
+ `isolation: worktree` is the default: a coding worker runs in a per-job git
80
+ worktree and the primary tree is untouched. Non-git workspaces fail with
81
+ `NOT_GIT_REPOSITORY` rather than silently sharing the tree; use `shared`
82
+ explicitly if that is what you want. Concurrent jobs are capped by
83
+ `max_parallel`.
84
+
85
+ The reviewer gate is `required` by default: an unreviewed change fails. Review
86
+ findings and failing tests are results to address, never a reason to bypass the
87
+ gate.
88
+
89
+ ## History
90
+
91
+ Session storage is shared between 3080 and 3210 — clearing one clears both.
92
+ Cleanup is scoped by provenance, and the default scope is **Crew-created only**,
93
+ so the operator's own conversations survive. `all` removes theirs too; use it
94
+ deliberately. Archived batches are restorable from the panel.
95
+
96
+ ## When Crew is unavailable
97
+
98
+ If a capability needed by a work unit you already dispatched becomes unavailable
99
+ or non-callable, **stop and ask**. Do not implement further on that unit, do not
100
+ repair or reconfigure Crew, do not silently fall back to doing it yourself.
101
+ Perform bounded read-only diagnosis, report the evidence and what already
102
+ completed, and wait for the operator to choose: repair Crew and continue through
103
+ it, or leave Crew alone and continue with the host agent.
104
+
105
+ A nonterminal wait is not an outage — keep polling the same workflow rather than
106
+ dispatching a duplicate. This gate applies only once Crew has been selected for
107
+ a work unit; it does not apply when planning chose local work.
108
+
109
+ ## Host boundaries
110
+
111
+ - Never install, update, register, unlink, repair or mutate anything under
112
+ `~/.dsh`. Crew's runtime lives in its own `DSH_HOME`.
113
+ - Runtime upgrades go through the Crew-owned installer (`dsh-crew update`), never
114
+ through direct pnpm/npm/dsh plugin operations.
115
+ - Preparing an upgrade must not restart 3080 or 3210.
116
+ - The legacy 3080 bridge must never be used for 3210 lifecycle or rollback.
117
+ - Delegation grants no new authority: pushing, publishing, messaging, changing
118
+ credentials or deleting data still need their own authorization.
@@ -0,0 +1,91 @@
1
+ // On-demand Crew guidance, installed as a user skill.
2
+ //
3
+ // Crew used to inject a "capability-aware delegation policy" block into the
4
+ // host's global instruction file. That made every host session — Codex, ZCode —
5
+ // carry Crew's delegation rules whether or not the operator wanted Crew that
6
+ // turn, which shapes how the host does its own work.
7
+ //
8
+ // The guidance now lives in a skill instead, loaded only when the operator asks
9
+ // for Crew. Nothing about the host's default behaviour changes; the knowledge is
10
+ // there the moment it is wanted.
11
+ //
12
+ // Each host reads its own skill directory, so the skill is copied to all of them
13
+ // — the same layout the Oracle skill uses, plus the shared `~/.agents/skills`
14
+ // that ZCode reads. Installing a skill replaces writing a policy block, so the
15
+ // host installers also *remove* any block a previous release left behind.
16
+
17
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
18
+ import { homedir } from 'node:os';
19
+ import { dirname, join, resolve } from 'node:path';
20
+
21
+ export const CREW_SKILL_NAME = 'dsh-crew';
22
+
23
+ /**
24
+ * Skill roots, in the order they are installed. `.agents/skills` is the shared
25
+ * directory ZCode reads; the other two are what Codex and Claude Code read. The
26
+ * Codex one is resolved through `CODEX_HOME` because Codex may point elsewhere —
27
+ // writing only to `~/.codex` would put the skill where Codex never looks.
28
+ */
29
+ export function crewSkillRoots({ home = homedir(), env = process.env } = {}) {
30
+ const codexHome = typeof env?.CODEX_HOME === 'string' && env.CODEX_HOME.trim()
31
+ ? resolve(env.CODEX_HOME.trim())
32
+ : join(home, '.codex');
33
+ return [
34
+ join(home, '.agents', 'skills'),
35
+ join(codexHome, 'skills'),
36
+ join(home, '.claude', 'skills'),
37
+ ];
38
+ }
39
+
40
+ export function crewSkillFiles({ home = homedir(), env = process.env } = {}) {
41
+ return crewSkillRoots({ home, env }).map((root) => join(root, CREW_SKILL_NAME, 'SKILL.md'));
42
+ }
43
+
44
+ /** The skill template shipped in the payload. */
45
+ export function crewSkillSource({ root }) {
46
+ return join(root, 'skills', CREW_SKILL_NAME, 'SKILL.md');
47
+ }
48
+
49
+ export function readCrewSkill({ root }) {
50
+ const file = crewSkillSource({ root });
51
+ return existsSync(file) ? readFileSync(file, 'utf8') : null;
52
+ }
53
+
54
+ /**
55
+ * Copy the skill template into every host skill directory. Idempotent: a file
56
+ * that already matches is left alone, so a repeat install stays quiet.
57
+ */
58
+ export function installCrewSkill({ home = homedir(), root, env = process.env } = {}) {
59
+ if (!root) return { ok: false, code: 'CREW_SKILL_SOURCE_REQUIRED' };
60
+ const content = readCrewSkill({ root });
61
+ if (content === null) return { ok: false, code: 'CREW_SKILL_TEMPLATE_MISSING', source: crewSkillSource({ root }) };
62
+ const written = [];
63
+ const files = crewSkillFiles({ home, env });
64
+ for (const file of files) {
65
+ let current = null;
66
+ try { current = readFileSync(file, 'utf8'); } catch { /* absent or unreadable */ }
67
+ if (current === content) continue;
68
+ try {
69
+ mkdirSync(dirname(file), { recursive: true });
70
+ writeFileSync(file, content);
71
+ written.push(file);
72
+ } catch (error) {
73
+ return { ok: false, code: 'CREW_SKILL_WRITE_FAILED', file, error: String(error?.message ?? error) };
74
+ }
75
+ }
76
+ return { ok: true, changed: written.length > 0, written, files, file: files[0] };
77
+ }
78
+
79
+ /**
80
+ * Remove the installed skill from every host directory. Only Crew's own skill
81
+ * folder is touched, so a user's other skills are never affected.
82
+ */
83
+ export function removeCrewSkill({ home = homedir(), env = process.env } = {}) {
84
+ const removed = [];
85
+ for (const dir of crewSkillRoots({ home, env }).map((root) => join(root, CREW_SKILL_NAME))) {
86
+ if (!existsSync(dir)) continue;
87
+ try { rmSync(dir, { recursive: true, force: true }); removed.push(dir); }
88
+ catch { /* best effort: a locked file is not worth failing an uninstall */ }
89
+ }
90
+ return { ok: true, changed: removed.length > 0, removed, file: removed[0] ?? null };
91
+ }
@@ -7,7 +7,8 @@ import { createHash } from 'node:crypto';
7
7
  import { dirname, join, resolve, relative } from 'node:path';
8
8
  import { fileURLToPath } from 'node:url';
9
9
  import { homedir } from 'node:os';
10
- import { normalizeModelPriority } from '../model-routing.mjs';
10
+ import { normalizeModelPriority } from '../model-routing.mjs';
11
+ import { crewSkillFiles, installCrewSkill, readCrewSkill, removeCrewSkill } from './crew-skill.mjs';
11
12
  import { zcodeStatus } from './zcode.mjs';
12
13
 
13
14
  const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
@@ -94,32 +95,13 @@ export function stripKnownLegacyCodexPolicy(text, { knownHashes = CODEX_LEGACY_P
94
95
  return `${keptPrefix}${match[0]}${keptSuffix}`;
95
96
  }
96
97
 
97
- function installGlobalCodexPolicy({ home, root, env = process.env }) {
98
- const file = join(codexHomeDir(home, env), 'AGENTS.md');
99
- const block = managedPolicyBlock(root);
100
- if (!block) return { ok: false, action: 'global policy template missing' };
101
- mkdirSync(dirname(file), { recursive: true });
102
- const current = readText(file) ?? '';
103
- const managed = new RegExp(`${POLICY_START.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?${POLICY_END.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`, 'm');
104
- const template = readText(join(root, 'codex', 'AGENTS.md'))?.trim() ?? '';
105
- let next;
106
- if (managed.test(current)) next = current.replace(managed, block);
107
- else if (current.trim() === template) next = `${block}\n`;
108
- else next = `${current.trimEnd()}${current.trim() ? '\n\n' : ''}${block}\n`;
109
- next = stripKnownLegacyCodexPolicy(next);
110
- if (next !== current) {
111
- backup(file);
112
- writeFileSync(file, next);
113
- }
114
- return { ok: true, action: `global policy: ${file}` };
98
+ /** The installed skill is present and still matches the payload template. */
99
+ function crewSkillInstalled({ home, root, env = process.env }) {
100
+ const expected = readCrewSkill({ root });
101
+ if (expected === null) return false;
102
+ // Every host directory must hold the current template, not just the first.
103
+ return crewSkillFiles({ home, env }).every((file) => readText(file) === expected);
115
104
  }
116
-
117
- function globalCodexPolicyReady({ home, root = ROOT, env = process.env }) {
118
- const block = managedPolicyBlock(root);
119
- const text = readText(join(codexHomeDir(home, env), 'AGENTS.md'));
120
- return !!block && typeof text === 'string' && text.includes(block);
121
- }
122
-
123
105
  function uninstallGlobalCodexPolicy({ home, env = process.env }) {
124
106
  const file = join(codexHomeDir(home, env), 'AGENTS.md');
125
107
  const current = readText(file);
@@ -432,7 +414,7 @@ export function installStatus({ home = homedir(), root = ROOT, env = process.env
432
414
  status_prompt: expectedStatusPrompt !== null && readText(join(codexRoot, 'prompts', 'dsh-status.md')) === expectedStatusPrompt,
433
415
  mcp: !!expectedTarget && mcpTarget === expectedTarget,
434
416
  target_alignment: !!expectedTarget && workerTarget === expectedTarget && reviewerTarget === expectedTarget && mcpTarget === expectedTarget,
435
- global_policy: globalCodexPolicyReady({ home, root, env }),
417
+ skill: crewSkillInstalled({ home, root, env }),
436
418
  };
437
419
  const codexInstalled = Object.values(components).some(Boolean)
438
420
  || existsSync(join(codexRoot, 'agents', 'ds-flash.toml'))
@@ -466,6 +448,8 @@ export function uninstallCodex({ home = homedir(), env = process.env } = {}) {
466
448
  }
467
449
  const policyAction = uninstallGlobalCodexPolicy({ home, env });
468
450
  if (policyAction) actions.push(policyAction);
451
+ const skillAction = removeCrewSkill({ home, env });
452
+ if (skillAction.changed) actions.push(...skillAction.removed.map((dir) => `removed: ${dir}`));
469
453
  // Remove only the dsh-crew entry from [mcp_servers], keeping any other
470
454
  // MCP servers the user configured.
471
455
  const configFile = join(codexHomeDir(home, env), 'config.toml');
@@ -622,9 +606,15 @@ export function installCodex({ home = homedir(), scope, root = ROOT, env = proce
622
606
  if (scope !== 'project') {
623
607
  const act = writeGlobalCodexMcpServer(home, renderedPath, env);
624
608
  actions.push(...act);
625
- const policy = installGlobalCodexPolicy({ home, root, env });
626
- if (!policy.ok) return { ok: false, actions: [...actions, policy.action] };
627
- actions.push(policy.action);
609
+ // Crew guidance is a skill now, loaded only when the operator asks for it.
610
+ // Removing the policy block here cleans up what an earlier release put in
611
+ // the host instruction file; ignoring the result keeps the first install on
612
+ // a machine that never had one quiet.
613
+ const droppedPolicy = uninstallGlobalCodexPolicy({ home, env });
614
+ if (droppedPolicy) actions.push(`removed delegating policy block: ${join(codexHomeDir(home, env), 'AGENTS.md')}`);
615
+ const skill = installCrewSkill({ home, root, env });
616
+ if (!skill.ok) return { ok: false, actions: [...actions, `crew skill: ${skill.code}`] };
617
+ actions.push(...skill.written.map((file) => `skill: ${file}`));
628
618
  }
629
619
  return { ok: true, actions };
630
620
  }
@@ -9,6 +9,8 @@ import { dirname, join, resolve } from 'node:path';
9
9
  import { fileURLToPath } from 'node:url';
10
10
  import { homedir } from 'node:os';
11
11
 
12
+ import { crewSkillFiles, installCrewSkill, readCrewSkill, removeCrewSkill } from './crew-skill.mjs';
13
+
12
14
  const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
13
15
  const HOST = 'zcode';
14
16
  const SERVER = 'dsh-crew';
@@ -103,27 +105,6 @@ function expectedTarget({ root = ROOT } = {}) {
103
105
  return resolve(join(root, 'src', 'server.mjs'));
104
106
  }
105
107
 
106
- function managedPolicyBlock(root) {
107
- const template = readText(join(root, 'zcode', 'AGENTS.md'))?.trim();
108
- return template ? `${POLICY_START}\n${template}\n${POLICY_END}` : null;
109
- }
110
-
111
- function installPolicy({ home, root }) {
112
- const file = join(home, '.zcode', 'AGENTS.md');
113
- const block = managedPolicyBlock(root);
114
- if (!block) return { ok: false, code: 'ZCODE_POLICY_TEMPLATE_MISSING' };
115
- mkdirSync(dirname(file), { recursive: true });
116
- const current = readText(file) ?? '';
117
- const escapedStart = POLICY_START.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
118
- const escapedEnd = POLICY_END.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
119
- const managed = new RegExp(`${escapedStart}[\\s\\S]*?${escapedEnd}`, 'm');
120
- const next = managed.test(current)
121
- ? current.replace(managed, block)
122
- : `${current.trimEnd()}${current.trim() ? '\n\n' : ''}${block}\n`;
123
- if (next !== current) { backup(file); writeFileSync(file, next); }
124
- return { ok: true, file };
125
- }
126
-
127
108
  function removePolicy({ home }) {
128
109
  const file = join(home, '.zcode', 'AGENTS.md');
129
110
  const current = readText(file);
@@ -277,7 +258,8 @@ function updateMcp({ home, root }) {
277
258
  return { ok: true, changed, config_file: source.file, config_kind: source.kind, target };
278
259
  }
279
260
 
280
- export function installZCode({ home = homedir(), root = ROOT } = {}) {
261
+ export function installZCode({ home = homedir(), root = ROOT, env = process.env } = {}) {
262
+ const actions = [];
281
263
  const templates = templateFiles({ home, root });
282
264
  const missing = templates.find(({ source }) => !existsSync(source));
283
265
  if (missing) return { ok: false, code: 'ZCODE_TEMPLATE_MISSING', source: missing.source };
@@ -287,8 +269,14 @@ export function installZCode({ home = homedir(), root = ROOT } = {}) {
287
269
  // failed install is transaction-like and leaves user files untouched.
288
270
  const mcp = updateMcp({ home, root });
289
271
  if (!mcp.ok) return mcp;
290
- const policy = installPolicy({ home, root });
291
- if (!policy.ok) return policy;
272
+ // Crew guidance is a skill now, loaded only when the operator asks for it.
273
+ // The removal cleans up the policy block an earlier release wrote into the
274
+ // host instruction file; ignoring its result keeps a first install quiet.
275
+ const droppedPolicy = removePolicy({ home });
276
+ if (droppedPolicy) actions.push('policy: removed managed ZCode block');
277
+ const skill = installCrewSkill({ home, root, env });
278
+ if (!skill.ok) return { ok: false, code: skill.code, source: skill.source };
279
+ actions.push(...skill.written.map((file) => `skill: ${file}`));
292
280
  const installed = installTemplates({ home, root, priorFiles });
293
281
  if (!installed.ok) return installed;
294
282
  cleanupPriorMcpSources({ owned: previousOwnership, exceptFile: mcp.config_file });
@@ -303,16 +291,20 @@ export function installZCode({ home = homedir(), root = ROOT } = {}) {
303
291
  files: installed.records,
304
292
  configFiles: [currentSourceRecord, ...priorSourceRecords],
305
293
  });
306
- return { ok: true, ...mcp, policy_file: policy.file, files: installed.actions };
294
+ return { ok: true, ...mcp, skill_files: skill.written, files: installed.actions };
307
295
  }
308
296
 
309
- function zcodeComponents({ home = homedir(), root = ROOT } = {}) {
297
+ function zcodeComponents({ home = homedir(), root = ROOT, env = process.env } = {}) {
310
298
  const expected = normalizePath(expectedTarget({ root }));
311
299
  const source = configSource({ home });
312
300
  const configured = serverTarget(source.servers[SERVER]);
313
301
  const owned = ownership({ home });
314
- const expectedPolicy = managedPolicyBlock(root);
315
- const installedPolicy = readText(join(home, '.zcode', 'AGENTS.md'));
302
+ // The guidance is a skill now; a policy block in the host instruction file is
303
+ // no longer written and no longer part of readiness.
304
+ const expectedSkill = readCrewSkill({ root });
305
+ // A block written by an earlier release still counts as an installed
306
+ // footprint, so uninstall knows there is something of ours to clean up.
307
+ const legacyPolicyText = readText(join(home, '.zcode', 'AGENTS.md'));
316
308
  const templates = templateFiles({ home, root });
317
309
  const templateReady = (entry) => {
318
310
  if (!entry) return false;
@@ -335,7 +327,7 @@ function zcodeComponents({ home = homedir(), root = ROOT } = {}) {
335
327
  });
336
328
  const components = {
337
329
  mcp: configured === expected,
338
- policy: !!expectedPolicy && typeof installedPolicy === 'string' && installedPolicy.includes(expectedPolicy),
330
+ skill: expectedSkill !== null && readText(crewSkillFiles({ home, env })[0]) === expectedSkill,
339
331
  worker_agent: templateReady(templateBySuffix(join('agents', 'ds-worker.md'))),
340
332
  reviewer_agent: templateReady(templateBySuffix(join('agents', 'ds-reviewer.md'))),
341
333
  config_prompt: templateReady(templateBySuffix(join('commands', 'dsh-config.md'))),
@@ -345,9 +337,9 @@ function zcodeComponents({ home = homedir(), root = ROOT } = {}) {
345
337
  && normalizePath(owned.target) === expected
346
338
  && ownershipFilesReady,
347
339
  };
348
- const policyFootprint = typeof installedPolicy === 'string'
349
- && installedPolicy.includes(POLICY_START)
350
- && installedPolicy.includes(POLICY_END);
340
+ const policyFootprint = typeof legacyPolicyText === 'string'
341
+ && legacyPolicyText.includes(POLICY_START)
342
+ && legacyPolicyText.includes(POLICY_END);
351
343
  const installed = Object.hasOwn(source.servers, SERVER)
352
344
  || !!owned
353
345
  || policyFootprint
@@ -355,8 +347,8 @@ function zcodeComponents({ home = homedir(), root = ROOT } = {}) {
355
347
  return { components, source, expected, configured, owned, installed };
356
348
  }
357
349
 
358
- export function zcodeStatus({ home = homedir(), root = ROOT } = {}) {
359
- const { components, source, expected, configured, installed } = zcodeComponents({ home, root });
350
+ export function zcodeStatus({ home = homedir(), root = ROOT, env = process.env } = {}) {
351
+ const { components, source, expected, configured, installed } = zcodeComponents({ home, root, env });
360
352
  const missing = Object.entries(components).filter(([, value]) => !value).map(([key]) => key);
361
353
  return {
362
354
  installed,
@@ -369,7 +361,7 @@ export function zcodeStatus({ home = homedir(), root = ROOT } = {}) {
369
361
  };
370
362
  }
371
363
 
372
- export function uninstallZCode({ home = homedir() } = {}) {
364
+ export function uninstallZCode({ home = homedir(), env = process.env } = {}) {
373
365
  const actions = [];
374
366
  const owned = ownership({ home });
375
367
  if (owned) {
@@ -381,6 +373,8 @@ export function uninstallZCode({ home = homedir() } = {}) {
381
373
  rmSync(OWNERSHIP_FILE({ home }), { force: true });
382
374
  }
383
375
  if (removePolicy({ home })) actions.push('policy: removed managed ZCode block');
376
+ const skillAction = removeCrewSkill({ home, env });
377
+ if (skillAction.changed) actions.push(...skillAction.removed.map((dir) => `removed: ${dir}`));
384
378
  const managedFiles = Array.isArray(owned?.files) && owned.files.length
385
379
  ? owned.files
386
380
  : ['agents/ds-worker.md', 'agents/ds-reviewer.md', 'commands/dsh-config.md', 'commands/dsh-status.md']
@@ -36,7 +36,7 @@ export {
36
36
  // included in the identity contract.
37
37
  const RUNTIME_ID = randomUUID();
38
38
 
39
- export const RUNTIME_VERSION = '1.6.2';
39
+ export const RUNTIME_VERSION = '1.7.1';
40
40
  export const HUB_PROTOCOL_VERSION = 1;
41
41
 
42
42
  export const HUB_CAPABILITIES = Object.freeze([