dsh-device-fleet 0.1.0-dev.1 → 0.1.0-dev.2
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.md +38 -0
- package/cordis.patch.yml +3 -1
- package/docs/notes/dev-release.md +28 -0
- package/package.json +45 -45
- package/src/plugin/index.js +16 -7
package/README.md
CHANGED
|
@@ -9,6 +9,44 @@ DeepSeek Harness 的设备联邦插件:把登录同一账号、且都安装本
|
|
|
9
9
|
- ✅ **Host 插件 + 直调 MVP(代码完成、单测通过,待真实 DSH 安装联调)**:`fleet_list` / `fleet_tools` / `fleet_call` + `fleet_read` / `fleet_fetch` / `fleet_run`、Tool Policy、Execution Slot、审批 fail-closed
|
|
10
10
|
- ⏳ Room / Room Board、委派、审批收件箱 UI、设备页/配对/房间 UI(下一步)
|
|
11
11
|
|
|
12
|
+
## 安装(开发版)
|
|
13
|
+
|
|
14
|
+
已发布到 npm:**`dsh-device-fleet@0.1.0-dev.1`**(dist-tag `dev`)。
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
# CLI / web profile
|
|
18
|
+
dsh plugin --profile web add dsh-device-fleet@dev
|
|
19
|
+
|
|
20
|
+
# 桌面 app:先完全退出 app,再安装,然后重新打开
|
|
21
|
+
dsh plugin --profile desktop add dsh-device-fleet@dev
|
|
22
|
+
|
|
23
|
+
# 离线安装包(拷到另一台设备)
|
|
24
|
+
dsh plugin --profile desktop add C:/path/to/dsh-device-fleet-0.1.0-dev.1.tgz
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
两台设备的 **DSH 版本与插件版本必须一致**(ADR-0024);不一致会在握手时直接拒绝。
|
|
28
|
+
|
|
29
|
+
### 配对(Fleet 入网)
|
|
30
|
+
|
|
31
|
+
1. 设备 A:对 agent 说“生成 Fleet 邀请码” → 模型调用 `fleet_invite`,拿到一次性邀请码(含 fleetKey,注意保密)。
|
|
32
|
+
2. 设备 B:安装并重启后,对 agent 说“加入 Fleet:`<code>`” → `fleet_join` 把邀请排队;**重启 DSH** 后生效。
|
|
33
|
+
3. 两台设备各自在 profile patch 里配置 `policy.allowedRoots` 与 `execution.cwd`(不配时直调读取一律被拒)。
|
|
34
|
+
4. 设备 B:`fleet_list` 看到设备 A → `fleet_read(device=A, path="A 允许根内的文件")` 验证。
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
# 两个 profile 的 cordis.patch.yml 里给 device-fleet 行追加 config:
|
|
38
|
+
- id: device-fleet
|
|
39
|
+
config:
|
|
40
|
+
deviceName: desktop
|
|
41
|
+
execution:
|
|
42
|
+
cwd: D:/work
|
|
43
|
+
agentPreset: standard
|
|
44
|
+
policy:
|
|
45
|
+
allowedRoots: [D:/work]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`fleet_run` 默认需要目标设备本机审批;审批收件箱 UI 尚未实现(当前 fail-closed)。第一阶段建议先用 `fleet_read` / `fleet_fetch` 验证链路。
|
|
49
|
+
|
|
12
50
|
## 设计文档
|
|
13
51
|
|
|
14
52
|
- 术语表:[CONTEXT.md](./CONTEXT.md)
|
package/cordis.patch.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# dsh-device-fleet bundle patch
|
|
1
|
+
# dsh-device-fleet bundle patch 鈥?mounts the Host plugin. The settings below are
|
|
2
2
|
# safe defaults; real values (relay address, allowed roots, execution cwd) are
|
|
3
3
|
# meant to be edited in the profile or through the plugin settings page.
|
|
4
4
|
- insert:
|
|
@@ -22,3 +22,5 @@
|
|
|
22
22
|
allowedTools: []
|
|
23
23
|
promptSection: true
|
|
24
24
|
autoApproveAsk: false
|
|
25
|
+
|
|
26
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# 开发版发布记录
|
|
2
|
+
|
|
3
|
+
- 包名:`dsh-device-fleet`
|
|
4
|
+
- 版本:`0.1.0-dev.1`
|
|
5
|
+
- dist-tag:`dev`(同时也可用精确版本安装)
|
|
6
|
+
- registry:<https://registry.npmjs.org/dsh-device-fleet>
|
|
7
|
+
- tarball:<https://registry.npmjs.org/dsh-device-fleet/-/dsh-device-fleet-0.1.0-dev.1.tgz>
|
|
8
|
+
- 本地离线包:`dsh-device-fleet-0.1.0-dev.1.tgz`(仓库根目录,可拷贝安装)
|
|
9
|
+
- 发布时间:2026-11-09(Asia/Shanghai)
|
|
10
|
+
- 内容:网络层 v1/v2 + Host 插件 + 直调 MVP(`fleet_invite/join/list/tools/call/read/fetch/run`);Room/Board/委派/审批 UI 未包含。
|
|
11
|
+
|
|
12
|
+
## 安装
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
dsh plugin --profile web add dsh-device-fleet@dev
|
|
16
|
+
# 桌面 app:完全退出后
|
|
17
|
+
dsh plugin --profile desktop add dsh-device-fleet@dev
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
发布时 npm 对新包做了短暂的处理/占位(`0.0.0-stage`),约几分钟后真实版本生效;后续版本号递增、tag 复用 `dev`。
|
|
21
|
+
|
|
22
|
+
## 已知限制
|
|
23
|
+
|
|
24
|
+
- 严格同版本:两台设备必须安装同一 `0.1.0-dev.1`,DSH 版本也要同一发布线;
|
|
25
|
+
- `fleet_run` 的 `ask` 审批目前 fail-closed(审批收件箱未实现);
|
|
26
|
+
- `fleet_fetch` 仅返回文本;
|
|
27
|
+
- 首次加载会在 `$DSH_HOME/device-fleet/` 自动创建身份与独立 Fleet;加入已有 Fleet 需要先 `fleet_join` 再重启;
|
|
28
|
+
- 默认 `direct.host=0.0.0.0` + UDP 组播发现;Windows 防火墙可能弹窗,需允许。
|
package/package.json
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-device-fleet",
|
|
3
|
+
"version": "0.1.0-dev.2",
|
|
4
|
+
"description": "DeepSeek Harness device fleet: enroll devices, direct-call remote tools, shared Rooms with lazy-woken agents, and delegated subagents across devices.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/plugin/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/plugin/index.js",
|
|
9
|
+
"./net": "./src/net/index.js",
|
|
10
|
+
"./host": "./src/host/index.js",
|
|
11
|
+
"./package.json": "./package.json"
|
|
12
|
+
},
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=22"
|
|
15
|
+
},
|
|
16
|
+
"dsh": {
|
|
17
|
+
"bundle": {
|
|
18
|
+
"patch": "./cordis.patch.yml"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@deepseek-ai/cordis": "~4.1.0",
|
|
23
|
+
"@deepseek-ai/dsh-tools": "^0.2.2-rc.1",
|
|
24
|
+
"@deepseek-ai/dsh-llm": "^0.2.2-rc.1",
|
|
25
|
+
"@deepseek-ai/schemastery": "~3.19.0"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"test": "node test/net.test.mjs && node test/host.test.mjs",
|
|
29
|
+
"test:net": "node test/net.test.mjs",
|
|
30
|
+
"test:host": "node test/host.test.mjs"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"src",
|
|
34
|
+
"cordis.patch.yml",
|
|
35
|
+
"README.md",
|
|
36
|
+
"CONTEXT.md",
|
|
37
|
+
"docs",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public",
|
|
42
|
+
"tag": "dev"
|
|
43
|
+
},
|
|
44
|
+
"license": "MIT"
|
|
45
|
+
}
|
package/src/plugin/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { readFileSync } from 'node:fs'
|
|
|
8
8
|
import { fileURLToPath } from 'node:url'
|
|
9
9
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
10
10
|
import { createUserMessage } from '@deepseek-ai/dsh-llm'
|
|
11
|
-
import
|
|
11
|
+
import Schema from '@deepseek-ai/schemastery'
|
|
12
12
|
import { FleetNode } from '../net/fleet-node.js'
|
|
13
13
|
import { accountFingerprint } from '../net/identity.js'
|
|
14
14
|
import { DirectCallClient, DirectCallHost } from '../host/direct-call.js'
|
|
@@ -115,7 +115,16 @@ function withManual(definitions) {
|
|
|
115
115
|
export function apply(ctx, config) {
|
|
116
116
|
const pluginVersion = packageVersion()
|
|
117
117
|
const dshVersion = process.env.DSH_CLIENT_VERSION ?? 'unknown'
|
|
118
|
-
|
|
118
|
+
// Optional services: Cordis throws on direct property access for services the
|
|
119
|
+
// plugin did not inject, so every optional service goes through get().
|
|
120
|
+
const service = (name) => {
|
|
121
|
+
try {
|
|
122
|
+
return ctx.get?.(name)
|
|
123
|
+
} catch {
|
|
124
|
+
return undefined
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const logger = service('logger') ?? console
|
|
119
128
|
|
|
120
129
|
let state
|
|
121
130
|
try {
|
|
@@ -140,8 +149,8 @@ export function apply(ctx, config) {
|
|
|
140
149
|
})
|
|
141
150
|
|
|
142
151
|
const policy = new ToolPolicy(config.policy)
|
|
143
|
-
const sessionController =
|
|
144
|
-
const fs =
|
|
152
|
+
const sessionController = service('sessionController')
|
|
153
|
+
const fs = service('fs')
|
|
145
154
|
if (!sessionController) logger.warn?.('[device-fleet] sessionController unavailable: direct calls to stateful tools will fail')
|
|
146
155
|
const slot = sessionController
|
|
147
156
|
? new ExecutionSlot({ sessionController, tools: ctx.tools, config: config.execution })
|
|
@@ -186,7 +195,7 @@ export function apply(ctx, config) {
|
|
|
186
195
|
})
|
|
187
196
|
|
|
188
197
|
// Bind the local account fingerprint when the account service is composed.
|
|
189
|
-
const account =
|
|
198
|
+
const account = service('deepseekAccount')
|
|
190
199
|
if (account && typeof account.getDeviceIdentity === 'function') {
|
|
191
200
|
void account
|
|
192
201
|
.getDeviceIdentity()
|
|
@@ -225,7 +234,7 @@ export function apply(ctx, config) {
|
|
|
225
234
|
for (const definition of wrapped) ctx.tools.register(definition)
|
|
226
235
|
|
|
227
236
|
// Adoption layer 2: one sentence, only when the Fleet has members.
|
|
228
|
-
const systemPrompt =
|
|
237
|
+
const systemPrompt = service('systemPrompt')
|
|
229
238
|
if (systemPrompt && config.promptSection !== false) {
|
|
230
239
|
const order = systemPrompt.getSectionOrder?.('TOOL_SUBAGENT') ?? PROMPT_SECTION_ORDER
|
|
231
240
|
ctx.effect(() =>
|
|
@@ -271,6 +280,6 @@ export function apply(ctx, config) {
|
|
|
271
280
|
void node.close()
|
|
272
281
|
})
|
|
273
282
|
|
|
274
|
-
|
|
283
|
+
logger.info?.(`[device-fleet] v${pluginVersion} device ${state.identity.deviceId} (${config.deviceName})`)
|
|
275
284
|
void ready
|
|
276
285
|
}
|