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 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 — mounts the Host plugin. The settings below are
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
- "name": "dsh-device-fleet",
3
- "version": "0.1.0-dev.1",
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": "\u003e=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 \u0026\u0026 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
- }
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
+ }
@@ -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 { Schema } from '@deepseek-ai/schemastery'
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
- const logger = ctx.logger ?? console
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 = ctx.sessionController ?? ctx.get?.('sessionController')
144
- const fs = ctx.fs ?? ctx.get?.('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 = ctx.get?.('deepseekAccount')
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 = ctx.get?.('systemPrompt') ?? ctx.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
- ctx.logger?.info?.(`[device-fleet] v${pluginVersion} device ${state.identity.deviceId} (${config.deviceName})`)
283
+ logger.info?.(`[device-fleet] v${pluginVersion} device ${state.identity.deviceId} (${config.deviceName})`)
275
284
  void ready
276
285
  }