dsh-expert-group 0.1.2 → 0.1.4

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
@@ -8,41 +8,6 @@
8
8
  把「按角色区分模型与思考深度」的专家子代理能力引入 DSH,并在 Web 界面的“dsh-expert-group”设置页维护全局模型、思考深度与通知偏好。
9
9
  同时把 oh-my-opencode-slim 的主代理 orchestrator 设计移植过来:根会话负责拆解、委派、整合和验证,专家子代理保持叶子 worker 约束。
10
10
 
11
- 本包**不修改** `@deepseek-ai/dsh` 的任何核心源码,也不修改 shipped agent preset。能力全部通过
12
- 现有 Host 服务与客户端 Slot 注册;**最低宿主契约**是下面这些声明在 `inject` 里的服务:
13
- `tools`、`subagents`、`systemPrompt`、`llm`、`agents`、`settings`、`webServer`。
14
-
15
- 其中 **goals 是可选只读投影源**:插件通过 `ctx.get("goals")` 读取,不把它声明为 `inject` 依赖,
16
- 且**只用于侧边栏的目标阶段展示**。插件不调用 `goals.pause` / `goals.resume`,等待语义完全由
17
- 「保持 root 当前 turn 打开」实现(见下)。宿主缺少该服务时,插件主体、专家派发与其他工具仍正常
18
- 加载,只是目标阶段投影为空。
19
-
20
- 等待判定需要一条**能证明**「该 root 没有 running 后代」的 root-scoped 查询,分两档:
21
- - **权威**:`subagents.listDescendants(rootSessionId)`——递归后代枚举,每行带
22
- `activity: "running" | "inactive"`;整条 listing reject、出现不可读分支
23
- (`kind: "diagnostic"`)或结构非法都按 unknown 处理。**只有**它「干净且完整」地回答
24
- 才能证明静止,这也是等待唯一的释放依据;
25
- - **降级**:公开 `workspace/session-activity` waterfall。它是**非专属**扩展点,
26
- **只能报告 activity,不能证明 quiet**,两个原因都必须处理:
27
- - 宿主 subagent provider 在空闲时是原样透传最内层返回值,因此「没有 provider」与
28
- 「provider 报告空」在返回值上同形;插件用模块唯一的 sentinel 兜底,sentinel 命中一律
29
- unknown;
30
- - 即使拿到的是**非 sentinel 的新数组**,也无法识别贡献者:任意第三方 listener 都能返回
31
- 一个全新的空数组(既不 spread 最内层值,也不检查 subagent 血缘),它与「provider
32
- 明确报告没有 running 后代」同形但**不可信**。因此**任何空数组**(含 fresh `[]`)
33
- 都不是静止证明。
34
- 该档唯一可用的明确结论是**正向**的「确有 `kind: "subagent"` 的 running 后代」,
35
- 它只用于继续等待。
36
-
37
- 两档都不可用时能力矩阵标记 `required: false`、`status: "unavailable"` 和
38
- `degradation: "root-turn-wait-descendant-query-unavailable"`;只有 waterfall 时标记
39
- `status: "degraded"` 和 `root-turn-wait-descendant-listing-unavailable`。任何 unknown
40
- 一律 fail-closed(继续等待,绝不把「查不到」当成「没有人跑」)。
41
-
42
- 图片规范化额外使用可选公开 `ctx.attachments` 服务,冷会话精确读取使用可选 `ctx.sessionQuery`;
43
- 两者缺失时只禁用受影响能力(`image-normalization-disabled` / `cold-session-read-disabled`),
44
- 文本专家能力仍可加载。
45
-
46
11
  ## 能力
47
12
 
48
13
  - 5 个专家子代理工具(默认启用):
@@ -59,92 +24,33 @@
59
24
  - **无内置默认模型**:新安装后所有角色均为空,需在“dsh-expert-group”设置页从 DSH
60
25
  已配置的模型中自行选择并保存;未配置模型的角色在调用时会给出明确提示。
61
26
  - 模型与思考深度通过 `llm.listProviders/listModels` + `resolveCallConfig` 校验,只接受设置中已添加的模型。
62
- - **动态 settings 保存能力**:插件不在模块加载期 import `@deepseek-ai/dsh-settings`,package 也不声明该 peer,因此默认安装不会额外下载 settings 包。目标运行时为 `0.2.0-rc.1`;插件通过宿主 settings 服务的 describe/update/mutate 面读写 profile 条目,并由 DEG 自有的 settings-commit 端点完成语义校验与 revision 冲突检测(宿主不再提供 owner validate 钩子)。
27
+ - **动态 settings 保存能力**:插件不在模块加载期 import `@deepseek-ai/dsh-settings`,package 也不声明该 peer,因此默认安装不会额外下载 settings 包。目标运行时为 `0.2.0-rc.2`;插件通过宿主 settings 服务的 describe/update/mutate 面读写 profile 条目,并由 DEG 自有的 settings-commit 端点完成语义校验与 revision 冲突检测(宿主不再提供 owner validate 钩子)。
63
28
  - 子代理的 `reasoningEffort` 通过子代理 `agent/request` waterfall 注入,绕开 `dsh-tool-subagent`
64
29
  `AgentOptions` 尚未公开该字段的限制。
65
30
 
66
- ## 安装与平台分工
67
-
68
- 本插件发布到 npm 公共源,按包名安装。**CLI/web 与桌面版是两套管理面,命令不通用**:
69
- CLI/web 的完整流程见 [安装说明.txt](安装说明.txt) 与 [web-install.ps1](web-install.ps1) / [web-uninstall.ps1](web-uninstall.ps1)(这两个脚本只处理 web profile);
70
- 桌面版见 [desktop-install.ps1](desktop-install.ps1)(构建 → 测试 → 打包 → 备份 → 安装 → 校验的快速部署流程,脚本头部注释即流程说明)。
71
-
72
- | 目标 | 安装入口 | 卸载入口 | 生效方式 |
73
- | --- | --- | --- | --- |
74
- | **CLI / `dsh web`** | `dsh plugin --profile web add dsh-expert-group` | `web-uninstall.ps1`(等价于 `dsh plugin --profile web remove dsh-expert-group`) | 重启 DSH Web |
75
- | **桌面版(Electron 客户端)** | 桌面版**应用自带**的 `dsh.cmd`(`plugin --profile desktop`,见下),或 GUI「插件 → 添加插件」 | `desktop-uninstall.ps1`(内部调用应用自带 CLI,见下) | 重启桌面版 |
76
-
77
- 两个卸载脚本各自只处理自己的 profile,**不可混用**:`web-uninstall.ps1` 操作 `profiles\web`,`desktop-uninstall.ps1` 操作 `profiles\desktop`。
31
+ ## 安装
78
32
 
79
- ### CLI / `dsh web`
33
+ 本插件发布到 npm 公共源,用 DSH 官方 `dsh plugin` CLI 按包名安装(`--profile` 为必填参数,一般填 `web`):
80
34
 
81
35
  ```powershell
82
36
  dsh plugin --profile web add dsh-expert-group
83
37
  ```
84
38
 
85
- 安装会把本包写入 `$DSH_HOME\profiles\web` 的依赖并加入 profile 的 bundle 层;**重启 DSH Web** 后生效(已运行的进程不会热加载新的 Host 行)。
86
-
87
- 要求:DSH Web 可运行(`dsh web`)、Node.js ≥ 22、PATH 上有 `pnpm`。**本插件不内置任何角色默认模型**——安装后需先在「设置 → dsh-expert-group」为各角色选择模型并保存。
88
-
89
- ### 桌面版(Electron 客户端)
90
-
91
- 桌面版的 profile 是 `desktop`,由 Electron 应用管理;**不要用 PATH 上的 npm 全局 `dsh` 去操作它**:
92
- 启动器里的开关 `manageDesktopProfile` **只作用于 `plugin` 子命令**,
93
- boot / `--dump-config` 路径是无条件拒绝的——**应用自带 CLI(rc.2)同样拒**:
94
-
95
- ```text
96
- error: profile "desktop" is managed exclusively by the Electron application
97
- ```
98
-
99
- 三条可用入口:
100
-
101
- | 入口 | 适用场景 | 说明 |
102
- | --- | --- | --- |
103
- | **应用自带 CLI** | 安装 / 升级 / 卸载的默认路径 | `0.2.0-rc.2` 起发行包带 `resources\runtime\cli\bin\dsh.cmd`(`0.2.0-rc.1` 上不存在);只有它放行 `plugin --profile desktop` |
104
- | **GUI「插件 → 添加插件」** | 图形化安装 | 与版本无关;**按 spec 检查同名**——包名 / 本地目录形式的 spec 命中已安装依赖时提示「该插件已安装。如需升级,请卸载后重新安装」,**tgz spec 的实际行为本轮未验证**;也不提供版本豁免入口 |
105
- | **手工维护 profile 文件** | 无 CLI、无 GUI 的兜底 | 手工建 junction / 复制副本**不是默认升级方式**,会绕过 pnpm 的锁与 integrity 校验 |
106
-
107
- ```powershell
108
- $cli = Join-Path '<DSH 安装目录>' 'resources\runtime\cli\bin\dsh.cmd' # 应用自带 CLI
109
- $tgz = '<候选包 tgz 的绝对路径>' # 也接受包名 / 本地目录绝对路径
110
-
111
- & $cli plugin --profile desktop add $tgz
112
- if ($LASTEXITCODE -ne 0) { throw "add 失败(exit=$LASTEXITCODE),先查落盘状态再决定回滚" }
113
-
114
- & $cli plugin --profile desktop list
115
- if ($LASTEXITCODE -ne 0) { throw "list 失败(exit=$LASTEXITCODE)" }
39
+ 也可以直接用 npm 安装:
116
40
 
117
- # 卸载:可直接运行仓库根的 .\desktop-uninstall.ps1(内部就是下面的 remove);
118
- # 手工执行等价于把 add 换成 remove;版本豁免:version-exemptions / allow-version / revoke-version
41
+ ```bash
42
+ npm i dsh-expert-group
119
43
  ```
120
44
 
121
- **生效与验收:命令执行者是主代理,最后一步重启由用户完成。** 构建 → 测试 → 打包 → 备份 → 安装
122
- → 校验的完整流程(含判据与回滚)见 **[desktop-install.ps1](desktop-install.ps1)**(流程与判据在脚本头部注释与各阶段日志中)。
123
-
124
- > 在线(桌面版运行中)安装属于受控测试:CLI 只检查 profile 是否初始化(提示 `... then fully quit it before
125
- > running dsh plugin --profile desktop.`),**没有进程硬拦截**,因此可能出现内存里旧模块 + 磁盘上新模块混用。
126
- > **磁盘安装成功 ≠ 内存生效、更 ≠ 功能验收**——真正验收要等用户重启后读证据(卸载入口见 [desktop-uninstall.ps1](desktop-uninstall.ps1))。
45
+ 前置条件:DSH Web 可正常运行(`dsh web`)、Node.js ≥ 22,且 PATH 上有 `pnpm`。安装后重启 `dsh web` 使插件生效。
127
46
 
128
- **验证安装登记与目标文件**(直接检查目标 profile,真实目录、Junction 和 pnpm 链接均适用):
47
+ 桌面版(Electron 客户端)的 `desktop` profile 由客户端独占管理,PATH 上的 `dsh` CLI 改不动它:先打开 Desktop 完成初始化再完全退出,用安装目录自带的 CLI 执行同一命令。
129
48
 
130
49
  ```powershell
131
- $ErrorActionPreference = 'Stop'
132
- $home_dsh = if ($env:DSH_HOME) { $env:DSH_HOME } else { Join-Path $env:USERPROFILE '.dsh' }
133
- $d = Join-Path $home_dsh 'profiles\desktop'
134
- $pkg = Get-Content -LiteralPath (Join-Path $d 'package.json') -Raw -Encoding UTF8 | ConvertFrom-Json
135
- if (-not $pkg.dependencies.'dsh-expert-group' -or 'dsh-expert-group' -notin @($pkg.dsh.profile.bundles)) {
136
- throw '目标 profile 未完整登记 DEG 依赖与 bundle'
137
- }
138
- $installedManifest = Join-Path $d 'node_modules\dsh-expert-group\package.json'
139
- if (-not (Test-Path -LiteralPath $installedManifest -PathType Leaf)) { throw '目标 profile 中没有 DEG 包清单' }
140
- $installed = Get-Content -LiteralPath $installedManifest -Raw -Encoding UTF8 | ConvertFrom-Json
141
- if ($installed.name -ne 'dsh-expert-group') { throw '目标包名不符' }
142
- [pscustomobject]@{ Path = $installedManifest; Name = $installed.name; Version = $installed.version }
50
+ & '<DSH 安装目录>\resources\runtime\cli\bin\dsh.cmd' plugin --profile desktop add dsh-expert-group
143
51
  ```
144
52
 
145
- 这只是快速检查;同版本替换还须按详细指南比对实际文件与候选 tgz 的哈希,不能只看版本号。
146
-
147
- **可选图像增强**:`sharp` 是 `optionalDependencies`(约 30 MB 原生二进制),用于把 JPEG / WebP / GIF 转码为 PNG;拉取失败或未安装都不影响插件加载,仅会拒绝非 PNG 图片的转码,其余功能全部正常。
53
+ 安装后重新打开 Desktop 使插件生效。本插件不内置角色默认模型:先在 DSH「设置 → 模型」配置模型,再到「设置 → dsh-expert-group」为各角色选择模型并保存。
148
54
 
149
55
  ## 界面总览
150
56
 
@@ -366,7 +272,7 @@ Expert Group 是 DEG 注册在右侧栏的任务视图:它把**当前会话所
366
272
  | 主代理(根节点) | 固定中文 `主代理` | 恒有;不显示 root 的 taskName / session id |
367
273
  | 普通专家 | 最新一次派发的短描述 | 每次专家委派生成一个节点 |
368
274
  | fan-out 聚合分支 | `<角色> · <N> shards · running|ready` | 一次 fan-out 提交生成一个父节点,分片是它的子节点 |
369
- | 空闲子代理分组 | `空闲子代理(N)` | 存在空闲(ready)的普通专家时出现,可折叠 |
275
+ | 空闲子代理分组 | `空闲子代理(N)` | 存在 ready 普通专家或已结算 fan-out 父任务时出现,可折叠 |
370
276
 
371
277
  ### 任务行的三行结构
372
278
 
@@ -411,7 +317,7 @@ Expert Group 是 DEG 注册在右侧栏的任务视图:它把**当前会话所
411
317
 
412
318
  ![空闲子代理分组](docs/assets/sidebar/05-idle-group.png)
413
319
 
414
- 运行中的专家留在主列表,空闲(ready)的普通专家会被收进可折叠分组 `空闲子代理(N)`,避免长任务树被历史节点淹没。分组头是容器而不是代理,它的圆点恒为 ready;组内成员各自按自己的实际状态取色。
320
+ 运行中的专家和未结算的 fan-out 留在主列表;空闲(ready)的普通专家及全部分片已结算的 fan-out 父任务会被收进可折叠分组 `空闲子代理(N)`,避免长任务树被历史节点淹没。已结算 fan-out 进入分组后仍保留分片树与任务操作。分组头是容器而不是代理,它的圆点恒为 ready;组内成员各自按自己的实际状态取色。
415
321
 
416
322
  ### `>>` 与 `<<`:在右栏打开 / 关闭子代理会话
417
323
 
@@ -441,36 +347,3 @@ Expert Group 是 DEG 注册在右侧栏的任务视图:它把**当前会话所
441
347
  - 首次从「只有 Expert Group」的单 pane 分栏时,打开事务会先临时把右栏写到约 50%,目标 tab 确认落到返回的 pane 后保留 50% 的可调模式;分栏失败则恢复原来的 20% 锁定宽度。
442
348
  - 日常在已有子代理 pane 里打开 / 关闭 tab 不改宽度。
443
349
  - 首次形成两个 pane 后:Expert Group 占右栏 40%(视口约 20%),子代理 pane 占右栏 60%(视口约 30%);最后一个被跟踪的 pane 关闭后恢复约 20% 的默认宽度。
444
-
445
- **能力缺失时的降级**:宿主没有 `sidebarRight.openResource` 时箭头不渲染、其余行内容完整;缺少关闭确认能力时保留静态 `>>`;整条侧栏接缝不可用时 DEG 只注册页面,不猜测打开状态。
446
-
447
- ## 只读能力矩阵与运行时诊断
448
-
449
- Host RPC 的 `meta` 动作返回两份**只读投影**(设置页诊断块与客户端归一化都消费它们):
450
-
451
- - `capabilities`:宿主服务可达性与固定降级标记,带 schema 版本 `version`。
452
- 每个能力条目只允许固定字段(`required` / `status` / `degradation` / `methods` / `probe` /
453
- `transport` / `failure` / `binding`),不含任何自由文本。
454
- - 硬依赖(`tools` / `subagents` / `agents` / `settings` / `webServer` / `systemPrompt` / `llm`)
455
- 在 `inject` 中声明,缺失时插件不加载;
456
- - `rootTurnWait` 是可选宿主 seam:权威档是 `subagents.listDescendants`(**唯一**能证明
457
- 「该 root 没有 running 后代」的 seam,且必须干净且完整),降级档是公开的
458
- `workspace/session-activity` waterfall(只能报告 activity,不能证明 quiet)。
459
- 只有 waterfall 时为 `degraded` + `root-turn-wait-descendant-listing-unavailable`;
460
- 两档都没有时为 `unavailable` + `root-turn-wait-descendant-query-unavailable`,
461
- 此时等待一律 fail-closed(继续等待);
462
- - `connectionRpc` / `storageDomain` / `attachments` / `sessionQuery` 各自报告
463
- `available` / `degraded` / `absent` / `unknown`,缺失时只禁用对应能力。
464
- - `diagnostics`:children / fanout / recovery / settings / storage / handoff / notifications /
465
- rpc 的**计数与固定 token**,同样带 `version`。
466
-
467
- 敏感性边界:两份投影不含 prompt、原始请求体、token、Cookie、authorization、文件路径、
468
- 会话/child 标识或错误消息正文;能力状态与降级说明都从固定枚举取值,任何超出字符面的输入
469
- 在归一化时被丢弃。客户端遇到未知 `version` 时整体忽略该块,绝不猜测字段含义。
470
-
471
- 系统通知(Windows Toast)的诊断字段与固定 token 同样在这一份 `diagnostics` 里:
472
- `notifications.systemToast` 报告 `status` / `version` / `platform` / `aumidResolved` /
473
- `aumidReason` / `inflight` / `queued` / `sent` / `failed` / `dropped` / `lastReason`;
474
- 解释器不可用时 `status` 为 `absent` 且固定 `reason` 为 `powershell-unavailable`,
475
- AUMID 解析失败的固定 token 为 `shortcut-read-failed`。这些字段只报状态与计数,不含命令行、
476
- 路径或通知正文。