dsh-paoding 0.4.3 → 0.4.5

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
@@ -26,7 +26,7 @@ dsh-paoding(中文品牌「庖丁」,典出《庄子》——庖丁顺纹理
26
26
  - **面板中英双语**:界面文案 zh/en 全覆盖,语言自动识别(显式选择 → 中文信号优先:浏览器语言、宿主页面语言、中文时区),「更多」菜单一键切换并记住。
27
27
  - **版本更新有提醒,面板一键升级**:面板会对比 npm registry(npmmirror 镜像、GitHub release 依次兜底)上的最新版本,发现新版就地提示并附上发布页链接;点「升级」就地换上新版(profile 自动探测:普通 profile 走 `dsh plugin update dsh-paoding`;desktop profile 被 dsh CLI 的 Electron 专属守卫挡住,改在 profile 目录直跑 `pnpm add dsh-paoding@<版本>`,pnpm 找不到时自动回落 `corepack pnpm`),重启 DSH 后生效,编排预设会在重启时按新版自动重生成。开发检出的 link 形态无法就地升级,面板会提示切回 registry 版的办法;检测失败时页头留一行「版本检测失败 · 重试」(完整原因与代理排查提示在悬浮提示里),不弹窗打扰。
28
28
  - **来去自由**:不改 DSH 一行源码;装完新会话即用,卸载即删目录。
29
- - **两代宿主都兼容**:DSH 0.1.5 – 0.2.0-rc.2 全支持(0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2)——两代宿主发现预设的机制不同(目录扫描 vs patch 声明行),安装器自动检测宿主版本选对落点;编排组合里的 workflow worker 行也按宿主版本自动适配(0.1.5 用 workflow-worker-thread,0.1.6+ 换 workflow-ptc——旧包 0.1.6 起已删除,残留行正是 0.2.0 面板上「加载失败」的元凶),宿主升级、降级后的首次保存/自愈自动迁移,全程无感。
29
+ - **两代宿主都兼容**:DSH 0.1.5 – 0.2.1 全支持(0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2 / 0.2.1-rc.2+)——两代宿主发现预设的机制不同(目录扫描 vs patch 声明行),安装器自动检测宿主版本选对落点;编排组合里的 workflow worker 行也按宿主版本自动适配(0.1.5 用 workflow-worker-thread,0.1.6+ 换 workflow-ptc——旧包 0.1.6 起已删除,残留行正是 0.2.0 面板上「加载失败」的元凶);DSH 0.2.1 起角色委派行同步换代(0.2.1 的 dsh-tool-subagent 拒绝内联 persona/toolFilter——人设与工具面改挂各角色的 AgentPreset,spawn 子代理按 agentPreset 选择子预设;0.2.0 及以下保持内联形状),宿主升级、降级后的首次保存/自愈自动迁移(工作区专属预设 orchestrator-<slug> 随同轮自愈一并换代),全程无感;0.2.1 的 prerelease 再细分——tool-subagent 守卫自 0.2.1-rc.2 落地,rc.0/rc.1 仍按内联形状生成。
30
30
 
31
31
  ## 插件截图
32
32
 
@@ -34,7 +34,7 @@ dsh-paoding(中文品牌「庖丁」,典出《庄子》——庖丁顺纹理
34
34
 
35
35
  ## 快速开始
36
36
 
37
- 前置:**Node.js ≥ 18**、**pnpm** 与一台已装好的 DSH host(**@deepseek-ai/dsh 0.1.5 – 0.2.0-rc.2** 全支持,预设落点自动适配两代宿主机制)。
37
+ 前置:**Node.js ≥ 18**、**pnpm** 与一台已装好的 DSH host(**@deepseek-ai/dsh 0.1.5 – 0.2.1** 全支持,预设落点与角色委派行形态自动适配宿主版本)。
38
38
 
39
39
  **官方插件通道(唯一安装入口)**——不用克隆仓库,一条命令,装完重启即用:
40
40
 
@@ -95,7 +95,7 @@ curl http://127.0.0.1:19387/api/paoding/presets
95
95
  | 文档 | 内容 |
96
96
  |---|---|
97
97
  | [架构](docs/architecture.md) | 为什么这样设计——概述、成本账、角色与工具、对应 DSH 原生机制、Token 治理、已知边界。 |
98
- | [安装](docs/installation.md) | 官方插件通道一条命令安装、版本支持与预设落点双轨(DSH 0.1.5 – 0.2.0-rc.2)、首装自动化与版本标记、升级、开发检出自装、host patch 检测机制、庖丁配置面板、卸载、排查。 |
98
+ | [安装](docs/installation.md) | 官方插件通道一条命令安装、版本支持与预设落点双轨(DSH 0.1.5 – 0.2.1)、首装自动化与版本标记、升级、开发检出自装、host patch 检测机制、庖丁配置面板、卸载、排查。 |
99
99
  | [编排](docs/orchestration.md) | 编排总览、失败如何呈现与三层处理、one-shot vs continuable、上下文隔离。 |
100
100
  | [配置](docs/configuration.md) | 配置键全参考、工具条目通配符、内置角色微调、主 agent 工具与技能、自定义角色、按角色分模型、角色会话与启动方式、场景模板、配置导出导入、检查提示、HTTP 接口。 |
101
101
 
package/README_en.md CHANGED
@@ -26,7 +26,7 @@ dsh-paoding (Chinese brand 「庖丁」/ Pao Ding, from the Zhuangzi parable of
26
26
  - **Panel in English and Chinese**: every UI string ships in both languages, auto-detected (explicit choice first, then Chinese signals — browser language, host page language, Chinese time zones — outrank English ones, since the Electron shell pins navigator to en-US regardless of the OS), switchable from the More menu and remembered.
27
27
  - **Notified of new releases, one-click upgrade in the panel**: the panel compares your local version against the latest npm registry publish (npmmirror and GitHub release as successive fallbacks) and points to the release page when a newer one is out. The Upgrade button swaps in the new version in place (profile auto-detected): regular profiles go through `dsh plugin update dsh-paoding`, while the Electron-owned desktop profile — which the dsh CLI guards against — gets a direct `pnpm add dsh-paoding@<version>` run in the profile directory, falling back to `corepack pnpm` when no bare pnpm is on PATH; a DSH restart applies it, and the orchestrator preset regenerates itself against the new version on startup. A dev checkout in link: form cannot be upgraded in place — the panel tells you how to switch back to the registry version. If the check fails (offline, rate-limited), a subdued "version check failed · retry" row stays in the header (full causes and proxy hints in its tooltip) without popping anything up.
28
28
  - **Installs and uninstalls cleanly**: no DSH source changes; active in a new session right after install, gone when you delete one directory.
29
- - **Works on both host generations**: DSH 0.1.5 through 0.2.0-rc.2 are all supported (0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2) — the two generations discover presets differently (directory scan vs patch declaration rows), and the installer picks the right landing automatically; from 0.2.0 the workflow worker row in the orchestration composition also adapts to the host version at generation time (0.1.5 uses workflow-worker-thread, 0.1.6+ swaps to workflow-ptc). Migration happens on the first save/self-heal after a host upgrade or downgrade, all without user action.
29
+ - **Works on both host generations**: DSH 0.1.5 through 0.2.1 are all supported (0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2 / 0.2.1-rc.2+) — the two generations discover presets differently (directory scan vs patch declaration rows), and the installer picks the right landing automatically; from 0.2.0 the workflow worker row in the orchestration composition also adapts to the host version at generation time (0.1.5 uses workflow-worker-thread, 0.1.6+ swaps to workflow-ptc); from DSH 0.2.1 the role delegation rows migrate too (0.2.1's dsh-tool-subagent rejects inline persona/toolFilter — each role gets an AgentPreset holding its persona and a role-restrict tool-surface plugin, selected via agentPreset on the spawn delegation; 0.2.0 and below keep the inline shape). Migration happens on the first save/self-heal after a host upgrade or downgrade (workspace presets, orchestrator-<slug>, are regenerated in the same self-heal pass), all without user action; the 0.2.1 prereleases are subdivided further — the tool-subagent guard landed in 0.2.1-rc.2, so rc.0/rc.1 keep the inline shape.
30
30
 
31
31
  ## Screenshots
32
32
 
@@ -34,7 +34,7 @@ dsh-paoding (Chinese brand 「庖丁」/ Pao Ding, from the Zhuangzi parable of
34
34
 
35
35
  ## Quick Start
36
36
 
37
- Prerequisites: **Node.js ≥ 18**, **pnpm**, and a working DSH host (**@deepseek-ai/dsh 0.1.5 – 0.2.0-rc.2**, all supported — the preset landing adapts to the host generation automatically).
37
+ Prerequisites: **Node.js ≥ 18**, **pnpm**, and a working DSH host (**@deepseek-ai/dsh 0.1.5 – 0.2.1**, all supported — the preset landing and role-row shape adapt to the host version automatically).
38
38
 
39
39
  **The official plugin channel (the only install route)** — no clone needed; one command, then a restart:
40
40
 
@@ -95,7 +95,7 @@ Writes go through the same generation pipeline and write lock as the panel's Sav
95
95
  | Document | Contents |
96
96
  |---|---|
97
97
  | [Architecture](docs/architecture_en.md) | Why it is designed this way — overview, the cost ledger, roles and tools, mapping to DSH's native mechanisms, token governance, known limits. |
98
- | [Installation](docs/installation_en.md) | The single official channel (`dsh plugin add`), version support and the dual preset landing (DSH 0.1.5 – 0.2.0-rc.2), first-install automation and the version marker, upgrading, dev-checkout install, host patch detection, the Paoding Config panel, uninstalling, troubleshooting. |
98
+ | [Installation](docs/installation_en.md) | The single official channel (`dsh plugin add`), version support and the dual preset landing (DSH 0.1.5 – 0.2.1), first-install automation and the version marker, upgrading, dev-checkout install, host patch detection, the Paoding Config panel, uninstalling, troubleshooting. |
99
99
  | [Orchestration](docs/orchestration_en.md) | Orchestration overview, how failures surface and the three recovery layers, one-shot vs continuable, context isolation. |
100
100
  | [Configuration](docs/configuration_en.md) | The full key reference, tool-entry wildcards, tuning built-in roles, main-agent tools and skills, custom roles, per-role models, per-role session and start modes, scenario templates, config export/import, health-check hints, the HTTP API. |
101
101
 
@@ -58,6 +58,7 @@ dsh-paoding(中文品牌「庖丁」,取庖丁解牛之意)是 DSH(DeepS
58
58
  │ │ │ │
59
59
  ▼ ▼ ▼ ▼
60
60
  web_search read/read_image read/read_image glob/grep/read/
61
+ web_fetch
61
62
  mcp__tavily__* glob/grep/bash/ write/edit/ read_image/bash/
62
63
  (5 个) skill/ glob/grep/bash/ ask_user_question/
63
64
  glob/grep/read web_search skill/web_search todo_write/
@@ -78,7 +79,7 @@ dsh-paoding(中文品牌「庖丁」,取庖丁解牛之意)是 DSH(DeepS
78
79
  |---|---|---|---|
79
80
  | 单体(现状,未裁剪) | 60 工具全量 | **~16.2k** | 每请求固定注入 |
80
81
  | 编排主 agent | 21 项白名单(∩ 注册面) | **~5.5k** | ↓66%;内部搜索零委派延迟 |
81
- | search_external 子 agent | 10 项 allow | ~3.0k | 仅实际联网调研时才产生 |
82
+ | search_external 子 agent | 11 项 allow | ~3.0k | 仅实际联网调研时才产生 |
82
83
  | design 子 agent | 12 项 allow | ~3.3k | 仅实际委派设计时才产生 |
83
84
  | implement 子 agent | 17 项 allow | ~3.8k | 仅实际委派实现时才产生 |
84
85
  | search_internal_deep 子 agent | 10 项 allow | 未单独估算 | 仅实际委派全仓深搜时才产生 |
@@ -123,7 +124,7 @@ dsh-paoding(中文品牌「庖丁」,取庖丁解牛之意)是 DSH(DeepS
123
124
  **host 工具不在白名单常量内硬编码**:`mcp__*` 与插件工具(codegraph / memory_search / mnemon_* 等)
124
125
  是"检测期事实"——主 agent 需要时经配置文件 `$DSH_HOME/dsh-paoding.config.yml` 的 `main_agent_extra`
125
126
  勾选,生成层按运行时检测把仍启用的注入 restrict 的 `config.allow`,停用即自动清除(详见
126
- [docs/configuration.md](configuration.md))。因此主 agent 的默认面**不包含** `web_search`、全部
127
+ [docs/configuration.md](configuration.md))。因此主 agent 的默认面**不包含** `web_search` / `web_fetch`、全部
127
128
  `mcp__tavily__*`、`write` / `edit` / `str_replace_editor`、`skill`、`workflow`、`ralph` 及未过滤的
128
129
  `subagent` / `subagent_fork`——这些要么属于角色子 agent,要么成本被刻意清零。
129
130
 
@@ -142,7 +143,7 @@ dsh-paoding(中文品牌「庖丁」,取庖丁解牛之意)是 DSH(DeepS
142
143
 
143
144
  | 委派工具 | 实例 ID | persona 一句话职责 | 加载成本 |
144
145
  |---|---|---|---|
145
- | `search_external` | `delegation-search-external` | 只做联网调研(web_search + tavily),绝不改文件;返回结构化研究摘要(发现、来源、待答问题) | ~3.0k,仅委派时 |
146
+ | `search_external` | `delegation-search-external` | 只做联网调研(web_search + web_fetch + tavily),绝不改文件;返回结构化研究摘要(发现、来源、待答问题) | ~3.0k,仅委派时 |
146
147
  | `design` | `delegation-design` | 产出 UI/UX 设计、线框与前端 spec,可用 skill 工具加载设计技能(frontend-design、html-ppt);先读参考再交付 spec,不写最终代码 | ~3.3k,仅委派时 |
147
148
  | `implement` | `delegation-implement` | 写与改代码:先读上下文 → 精准修改 → 验证(build/test/grep);不改架构 | ~3.8k,仅委派时 |
148
149
  | `search_internal_deep` | `delegation-search-internal-deep` | 只做仓库探索:不改文件、不联网;处理主 agent 上下文装不下的任务(全仓 grep dump、超页大文件通读、跨目录符号/定义追踪),只回浓缩摘要 | 未单独估算,仅委派时 |
@@ -157,12 +158,12 @@ dsh-paoding(中文品牌「庖丁」,取庖丁解牛之意)是 DSH(DeepS
157
158
  **不做**库存对账:手写进去、两头都不占的名字不会被剔除,会静默落盘、运行时以 unknown tools 拒创建
158
159
  (与下方该角色的 codegraph 注同一口径),见 [docs/configuration.md](configuration.md))。
159
160
 
160
- **`search_external`(外部调研,10 项)**
161
+ **`search_external`(外部调研,11 项)**
161
162
 
162
163
  | 字段 | 值 |
163
164
  |---|---|
164
165
  | persona 职责 | 只做联网调研并返回结构化研究摘要(发现、来源、待答问题);绝不修改文件 |
165
- | toolFilter.allow | `web_search`、`mcp__tavily__tavily_search`、`mcp__tavily__tavily_crawl`、`mcp__tavily__tavily_extract`、`mcp__tavily__tavily_map`、`mcp__tavily__tavily_research`、`glob`、`grep`、`read`、`ask_user_question` |
166
+ | toolFilter.allow | `web_search`、`web_fetch`、`mcp__tavily__tavily_search`、`mcp__tavily__tavily_crawl`、`mcp__tavily__tavily_extract`、`mcp__tavily__tavily_map`、`mcp__tavily__tavily_research`、`glob`、`grep`、`read`、`ask_user_question` |
166
167
  | 加载成本 | ~3.0k tokens,仅实际联网调研时发生 |
167
168
 
168
169
  **`design`(设计,12 项)**
@@ -70,6 +70,7 @@ allow lists are in the "Roles & tool surfaces" section below):
70
70
  │ │ │ │
71
71
  ▼ ▼ ▼ ▼
72
72
  web_search read/read_image read/read_image glob/grep/read
73
+ web_fetch
73
74
  mcp__tavily__* glob/grep/bash write/edit read_image/bash
74
75
  (5 tools) skill/web_search glob/grep/bash ask_user_question
75
76
  glob/grep/read ask_user_question skill/web_search todo_write
@@ -90,8 +91,8 @@ In the diagram:
90
91
  ask_user_question / get_goal / create_goal / update_goal / exit_plan_mode / job_output / job_list /
91
92
  job_kill);
92
93
  - Four arrows fan out to the **role sub-agents**, each created on demand (cold path). search_external
93
- carries web_search, the five `mcp__tavily__*` tools, plus glob/grep/read and ask_user_question, with no
94
- write/edit; design carries read/read_image/glob/grep/bash/skill/web_search plus coordination tools;
94
+ carries web_search, web_fetch, the five `mcp__tavily__*` tools, plus glob/grep/read and ask_user_question,
95
+ with no write/edit; design carries read/read_image/glob/grep/bash/skill/web_search plus coordination tools;
95
96
  implement carries read/read_image/write/edit/glob/grep/bash/skill/web_search plus coordination and
96
97
  goal tools;
97
98
  search_internal_deep carries the full read-only internal-search surface (glob/grep/read/read_image/bash
@@ -107,7 +108,7 @@ measured calibration; figures are order-of-magnitude estimates):
107
108
  |---|---|---|---|
108
109
  | Monolithic (status quo, untrimmed) | All 60 tools | **~16.2k** | Paid in full on every request |
109
110
  | Orchestrator main agent | 21-entry whitelist (∩ registry) | **~5.5k** | ↓66%; zero delegation latency for internal search |
110
- | search_external sub-agent | 10 allowed entries | ~3.0k | Paid only when web research actually runs |
111
+ | search_external sub-agent | 11 allowed entries | ~3.0k | Paid only when web research actually runs |
111
112
  | design sub-agent | 12 allowed entries | ~3.3k | Paid only when a design task is delegated |
112
113
  | implement sub-agent | 17 allowed entries | ~3.8k | Paid only when an implementation task is delegated |
113
114
  | search_internal_deep sub-agent | 10 allowed entries | not separately estimated | Paid only when a deep repo search is delegated |
@@ -160,7 +161,7 @@ memory_search / mnemon_* etc.) are "install-time facts" — when the main agent
160
161
  `main_agent_extra` in the configuration file `$DSH_HOME/dsh-paoding.config.yml`, the generator injects the
161
162
  still-enabled ones into the restrict `config.allow` based on runtime detection, and disabled ones are
162
163
  dropped automatically (see [docs/configuration_en.md](configuration_en.md)). The main agent's default surface
163
- therefore excludes `web_search`, every `mcp__tavily__*`, `write` / `edit` / `str_replace_editor`, `skill`,
164
+ therefore excludes `web_search` / `web_fetch`, every `mcp__tavily__*`, `write` / `edit` / `str_replace_editor`, `skill`,
164
165
  `workflow`, `ralph`, and the unfiltered `subagent` / `subagent_fork` — either because they belong to role
165
166
  sub-agents or because their cost is deliberately zeroed out.
166
167
 
@@ -184,7 +185,7 @@ For example, a `ppt` agent carrying the `html-ppt` skill gives slide-making its
184
185
 
185
186
  | Delegation tool | Instance ID | Persona in one sentence | Load cost |
186
187
  |---|---|---|---|
187
- | `search_external` | `delegation-search-external` | Web research only (web_search + tavily), never modifies files; returns a structured research summary (findings, sources, open questions) | ~3.0k, only when delegated |
188
+ | `search_external` | `delegation-search-external` | Web research only (web_search + web_fetch + tavily), never modifies files; returns a structured research summary (findings, sources, open questions) | ~3.0k, only when delegated |
188
189
  | `design` | `delegation-design` | Produces UI/UX designs, wireframes and frontend specs; may load design skills (frontend-design, html-ppt) via the skill tool; reads reference material first, delivers a spec, does not implement final code | ~3.3k, only when delegated |
189
190
  | `implement` | `delegation-implement` | Writes and edits code: read surrounding context → surgical change → verify (build/test/grep); does not redesign architecture | ~3.8k, only when delegated |
190
191
  | `search_internal_deep` | `delegation-search-internal-deep` | Repository exploration only: never modifies files, never uses the network; handles tasks too heavy for the main agent's context (whole-repo grep dumps, full-file reads beyond a page, cross-directory symbol/definition tracking); returns condensed summaries only | not separately estimated, only when delegated |
@@ -213,12 +214,12 @@ on disk silently, and fail at runtime with unknown tools at child creation — s
213
214
  note for that role below; see
214
215
  [docs/configuration_en.md](configuration_en.md)).
215
216
 
216
- **`search_external` (external research, 10 entries)**
217
+ **`search_external` (external research, 11 entries)**
217
218
 
218
219
  | Field | Value |
219
220
  |---|---|
220
221
  | Persona job | Web research only, returning a structured research summary (findings, sources, open questions); never modifies files |
221
- | toolFilter.allow | `web_search`, `mcp__tavily__tavily_search`, `mcp__tavily__tavily_crawl`, `mcp__tavily__tavily_extract`, `mcp__tavily__tavily_map`, `mcp__tavily__tavily_research`, `glob`, `grep`, `read`, `ask_user_question` |
222
+ | toolFilter.allow | `web_search`, `web_fetch`, `mcp__tavily__tavily_search`, `mcp__tavily__tavily_crawl`, `mcp__tavily__tavily_extract`, `mcp__tavily__tavily_map`, `mcp__tavily__tavily_research`, `glob`, `grep`, `read`, `ask_user_question` |
222
223
  | Load cost | ~3.0k tokens, incurred only when web research actually runs |
223
224
 
224
225
  **`design` (design, 12 entries)**
@@ -73,6 +73,7 @@ roles: # toolName -> { persona?, tools[] }
73
73
  You are the external-research agent. Web research only — never modify files.
74
74
  tools:
75
75
  - web_search
76
+ - web_fetch
76
77
  - mcp__tavily__tavily_search
77
78
  - mcp__tavily__tavily_crawl
78
79
  - mcp__tavily__tavily_extract
@@ -138,11 +139,14 @@ skills: # skill -> 分配给的角色(写进角色 persona 的
138
139
  search_external:
139
140
  tools:
140
141
  - web_search
142
+ - web_fetch
141
143
  - mcp__tavily__tavily_* # 生成时展开为 search/crawl/extract/map/research(以实际检测为准)
142
144
  ```
143
145
 
144
146
  `main_agent_extra` 与自定义角色的 `tools` 同样支持。配置文件里模式条目原样存取(配置面板回显不受影响),只有生成的 preset 里落的是展开后的具体名。
145
147
 
148
+ > 宿主 0.2.1-rc.2 起可在 **设置 → 网页搜索** 开启 DeepSeek Search / Fetch API:`web_search` / `web_fetch` 的名字不变,后方 provider 自动切换到官方新后端——无需改动庖丁配置,角色 allow 里的这两个名字照常生效。
149
+
146
150
  示例(替换 `implement` 的 persona 与 tools):下方 tools 与静态默认一致——注意它不含 `str_replace_editor`(原因见 8.2)。显式写出 tools 等于固定意图:将来静态源怎么改都不再影响本角色:
147
151
 
148
152
  ```yaml
@@ -350,7 +354,7 @@ fork 的语义(如实说明):
350
354
  | 内部搜索(热路径) | `glob` `grep` `read` `read_image` `bash` |
351
355
  | 协调 | `todo_write` `ask_user_question` `get_goal` `create_goal` `update_goal` `exit_plan_mode` `job_output` `job_list` `job_kill` |
352
356
 
353
- 对照说明:`web_search`、全部 `mcp__tavily__*`、`write` / `edit` / `str_replace_editor`、`skill`、`workflow`、`ralph`、未过滤的 `subagent` 委派等**刻意不在**主 agent 面上(host 工具如 codegraph / `memory_search` / mnemon 同理不硬编码进源码,需要时用 `main_agent_extra` 勾选,见 3.2)。另外 `restrict.mjs` 在注册层对主 agent deny 了 `skill`(目录注入守卫查的是注册面而非模型可见面),主 agent 的技能目录注入随之归零。
357
+ 对照说明:`web_search` / `web_fetch`、全部 `mcp__tavily__*`、`write` / `edit` / `str_replace_editor`、`skill`、`workflow`、`ralph`、未过滤的 `subagent` 委派等**刻意不在**主 agent 面上(host 工具如 codegraph / `memory_search` / mnemon 同理不硬编码进源码,需要时用 `main_agent_extra` 勾选,见 3.2)。另外 `restrict.mjs` 在注册层对主 agent deny 了 `skill`(目录注入守卫查的是注册面而非模型可见面),主 agent 的技能目录注入随之归零。
354
358
 
355
359
  ### 3.2 追加工具:main_agent_extra
356
360
 
@@ -73,6 +73,7 @@ roles: # toolName -> { persona?, tools[] }
73
73
  You are the external-research agent. Web research only — never modify files.
74
74
  tools:
75
75
  - web_search
76
+ - web_fetch
76
77
  - mcp__tavily__tavily_search
77
78
  - mcp__tavily__tavily_crawl
78
79
  - mcp__tavily__tavily_extract
@@ -138,11 +139,14 @@ Of the four built-in delegation roles, the installer (the `ROLES` constant) mana
138
139
  search_external:
139
140
  tools:
140
141
  - web_search
142
+ - web_fetch
141
143
  - mcp__tavily__tavily_* # expanded at generation to search/crawl/extract/map/research (per actual detection)
142
144
  ```
143
145
 
144
146
  `main_agent_extra` and custom-role `tools` support them too. Pattern entries are stored and read back verbatim in the config file (the config panel renders them fine); only the generated preset contains the expanded concrete names.
145
147
 
148
+ > Host 0.2.1-rc.2 and later can enable the DeepSeek Search / Fetch API under **Settings → Web Search**: `web_search` / `web_fetch` keep their names while the provider behind them switches to the official new backend — no 庖丁 (Paoding) config change needed, and both names in a role's allow list keep working as-is.
149
+
146
150
  Example — replacing `implement`'s persona and tools. The `tools` below match the static default — note that it does **not** contain `str_replace_editor` (why: see 8.2). Writing `tools` out explicitly freezes the intent: later changes to the static source no longer affect this role:
147
151
 
148
152
  ```yaml
@@ -350,7 +354,7 @@ The `MAIN_AGENT_ALLOW` constant in `restrict.mjs` is the **base** (21 names) tha
350
354
  | Internal search (hot path) | `glob` `grep` `read` `read_image` `bash` |
351
355
  | Coordination | `todo_write` `ask_user_question` `get_goal` `create_goal` `update_goal` `exit_plan_mode` `job_output` `job_list` `job_kill` |
352
356
 
353
- For orientation: `web_search`, every `mcp__tavily__*`, `write` / `edit` / `str_replace_editor`, `skill`, `workflow`, `ralph`, and the unfiltered `subagent` delegation are **deliberately absent** from the main-agent surface (host tools such as codegraph / `memory_search` / mnemon are likewise not hard-coded into the source — opt them in via `main_agent_extra`, see 3.2). `restrict.mjs` also denies `skill` at the registry level for the main agent (the catalog-injection guard checks registry visibility, not the model-facing list), which brings the main agent's skill-catalog token tax to zero.
357
+ For orientation: `web_search` / `web_fetch`, every `mcp__tavily__*`, `write` / `edit` / `str_replace_editor`, `skill`, `workflow`, `ralph`, and the unfiltered `subagent` delegation are **deliberately absent** from the main-agent surface (host tools such as codegraph / `memory_search` / mnemon are likewise not hard-coded into the source — opt them in via `main_agent_extra`, see 3.2). `restrict.mjs` also denies `skill` at the registry level for the main agent (the catalog-injection guard checks registry visibility, not the model-facing list), which brings the main agent's skill-catalog token tax to zero.
354
358
 
355
359
  ### 3.2 Appending tools: main_agent_extra
356
360
 
@@ -12,7 +12,7 @@
12
12
 
13
13
  - **Node.js ≥ 18**。DSH host 与插件链路都跑在 Node 上;版本过低时 `dsh` 本身就起不来。可用 `node --version` 自查。
14
14
  - **pnpm 可用**。`dsh plugin` 是 pnpm 的透明转发器:插件包装进 profile 时由 pnpm 完成。缺失时安装命令会报 pnpm 相关错误,装好 pnpm(`npm i -g pnpm` 或 `corepack enable`)后重试。
15
- - **已安装 DSH host**(`dsh` 可用,含其 Web/agent 运行时;**@deepseek-ai/dsh 0.1.5 – 0.2.0-rc.2** 全支持,安装器自动适配两代预设机制,详见第 2 节「版本支持与预设落点双轨」)。本插件不改 DSH 源码,只往 DSH 的 preset roster 写入编排预设、并把「庖丁配置」面板挂进 Web 左侧栏,因此先要有可用的 DSH 家目录。
15
+ - **已安装 DSH host**(`dsh` 可用,含其 Web/agent 运行时;**@deepseek-ai/dsh 0.1.5 – 0.2.1** 全支持,安装器自动适配宿主版本(预设落点与角色委派行形态),详见第 2 节「版本支持与预设落点双轨」)。本插件不改 DSH 源码,只往 DSH 的 preset roster 写入编排预设、并把「庖丁配置」面板挂进 Web 左侧栏,因此先要有可用的 DSH 家目录。
16
16
  - **路径事实**(生成管线内建常量,写死前先了解它们):
17
17
 
18
18
  | 项 | 默认值 | 说明 |
@@ -50,9 +50,9 @@ dsh plugin --profile web add dsh-paoding
50
50
 
51
51
  `--profile web` 决定插件装进哪个 profile:「庖丁配置」面板只在以该 profile 启动的 DSH Web 里出现。`web` 是 `dsh web` 的默认 profile,多数机器无需改动;多 profile 用户对每个需要的 profile 各执行一次 `dsh plugin add`。编排预设本体落在 `$DSH_HOME/.agent-presets/`,全机共享、不随 profile 走——DSH ≥ 0.1.7 的声明行写在 home 层 `$DSH_HOME/cordis.patch.yml`,同样与 profile 无关——在任何 profile 的面板里「保存并应用」,写的都是同一份预设。
52
52
 
53
- ### 版本支持与预设落点双轨(DSH 0.1.5 – 0.2.0-rc.2)
53
+ ### 版本支持与预设落点双轨(DSH 0.1.5 – 0.2.1)
54
54
 
55
- 本插件兼容两代宿主:**DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2 全部支持**,安装与使用流程完全一致。插件 0.3.4 起,package.json 显式声明 `peerDependencies: @deepseek-ai/dsh >= 0.1.5`——0.1.7 起宿主装插件前做兼容性预检,无声明等于默认放行,显式声明后按真实兼容面把关;0.1.5 / 0.1.6 不读这个字段,声明纯属元数据,不影响安装。
55
+ 本插件兼容两代宿主:**DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2 / 0.2.1-rc.2+ 全部支持**,安装与使用流程完全一致。插件 0.3.4 起,package.json 显式声明 `peerDependencies: @deepseek-ai/dsh >= 0.1.5`——0.1.7 起宿主装插件前做兼容性预检,无声明等于默认放行,显式声明后按真实兼容面把关;0.1.5 / 0.1.6 不读这个字段,声明纯属元数据,不影响安装。
56
56
 
57
57
  两代宿主发现「本地 authored preset」的机制不同,安装器据此分双轨落点,宿主检测全自动、用户无感:
58
58
 
@@ -70,6 +70,7 @@ dsh plugin --profile web add dsh-paoding
70
70
 
71
71
  - **降级自愈(0.1.7 → 0.1.6)**:0.1.6 不认识声明行,声明行留在 patch 里会让 profile 启动失败——安装器自动撤下 home patch 里的托管块;目录轨产物本就齐全,预设无缝回到目录扫描。
72
72
  - **升级迁移(0.1.6 → 0.1.7)**:安装器自动补写托管块;`.agent-presets/` 里按旧轨生成的 preset 会话(`agentPreset: orchestrator`)在新轨下按 `config.id` 继续对上,老会话恢复不断档。
73
+ - **角色委派行换代(0.2.0 → 0.2.1)**:0.2.1 起 dsh-tool-subagent 拒绝配置里的内联 persona / toolFilter(出现即抛错,挂编排预设的新建会话直接失败),自愈整盘重生成把人设与工具面迁到各角色的 AgentPreset(`agentPreset: paoding-role-<角色名>`);工作区专属预设(orchestrator-<slug>)随同轮自愈一并换代。0.2.1 的 prerelease 再细分——守卫自 0.2.1-rc.2 落地,rc.0 / rc.1 仍按内联形状生成。
73
74
 
74
75
  另有两处跨版本行为对齐,同样自动完成、无需用户动作:
75
76
 
@@ -12,7 +12,7 @@ Check the following before installing:
12
12
 
13
13
  - **Node.js ≥ 18**. The DSH host and the plugin chain both run on Node; with an older version `dsh` won't start in the first place. Check with `node --version`.
14
14
  - **pnpm available**. `dsh plugin` is a transparent pass-through to pnpm: installing a plugin package into a profile is done by pnpm. If pnpm is missing the install command fails with a pnpm error — install pnpm (`npm i -g pnpm` or `corepack enable`) and retry.
15
- - **A working DSH host** (the `dsh` command, including its Web/agent runtime; **@deepseek-ai/dsh 0.1.5 – 0.2.0-rc.2**, all supported — the installer adapts to the two preset mechanisms automatically; see §2 "Version support and the dual preset landing"). This plugin does not modify DSH source code; it only writes the orchestrator preset into DSH's preset roster and mounts the Paoding Config page into the Web sidebar, so a usable DSH home directory must exist first.
15
+ - **A working DSH host** (the `dsh` command, including its Web/agent runtime; **@deepseek-ai/dsh 0.1.5 – 0.2.1**, all supported — the installer adapts to the host version automatically (preset landing and role-row shape); see §2 "Version support and the dual preset landing"). This plugin does not modify DSH source code; it only writes the orchestrator preset into DSH's preset roster and mounts the Paoding Config page into the Web sidebar, so a usable DSH home directory must exist first.
16
16
  - **Path facts** (constants built into the generation pipeline; know them before customizing):
17
17
 
18
18
  | Item | Default | Description |
@@ -50,9 +50,9 @@ The orchestrator preset needs no separate install — the plugin fills it in aut
50
50
 
51
51
  `--profile web` decides which profile the plugin is installed into: the Paoding Config page appears only in a DSH Web launched with that profile. `web` is the default profile of `dsh web`, so most machines need no change; multi-profile users run `dsh plugin add` once per profile they want it in. The orchestrator preset itself lives under `$DSH_HOME/.agent-presets/` and is shared machine-wide, independent of profiles — under DSH ≥ 0.1.7 the declaration rows go into the home-layer `$DSH_HOME/cordis.patch.yml`, equally profile-independent — Save & Apply from any profile's panel writes the same preset.
52
52
 
53
- ### Version support and the dual preset landing (DSH 0.1.5 – 0.2.0-rc.2)
53
+ ### Version support and the dual preset landing (DSH 0.1.5 – 0.2.1)
54
54
 
55
- The plugin supports two host generations: **DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2 are all supported**, with an identical install and usage flow. As of plugin 0.3.4, package.json declares `peerDependencies: @deepseek-ai/dsh >= 0.1.5` explicitly — from 0.1.7 the host runs a plugin-compatibility precheck before installing: no declaration meant a default pass, an explicit one gets checked against the real compatibility surface; 0.1.5 / 0.1.6 never read the field, where the declaration is pure metadata and changes nothing about the install.
55
+ The plugin supports two host generations: **DSH 0.1.5 / 0.1.6 / 0.1.7-rc.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0-rc.2 / 0.2.1-rc.2+ are all supported**, with an identical install and usage flow. As of plugin 0.3.4, package.json declares `peerDependencies: @deepseek-ai/dsh >= 0.1.5` explicitly — from 0.1.7 the host runs a plugin-compatibility precheck before installing: no declaration meant a default pass, an explicit one gets checked against the real compatibility surface; 0.1.5 / 0.1.6 never read the field, where the declaration is pure metadata and changes nothing about the install.
56
56
 
57
57
  The two generations discover "local authored presets" differently, so the installer maintains a dual landing, detecting the host automatically — nothing for the user to do:
58
58
 
@@ -70,6 +70,7 @@ The first save/self-heal after the host version changes migrates automatically,
70
70
 
71
71
  - **Downgrade self-heal (0.1.7 → 0.1.6)**: 0.1.6 does not understand declaration rows — leaving them in the patch breaks profile startup — so the installer removes the managed block from the home patch automatically; the directory-track artifacts are already complete, and the preset slips back to directory scanning seamlessly.
72
72
  - **Upgrade migration (0.1.6 → 0.1.7)**: the installer writes the managed block automatically; sessions on presets generated under the old track (`.agent-presets/`, `agentPreset: orchestrator`) keep matching under the new track by `config.id`, so old sessions resume without a gap.
73
+ - **Role delegation row migration (0.2.0 → 0.2.1)**: from 0.2.1 dsh-tool-subagent rejects inline persona / toolFilter in the configuration (present means thrown error; new sessions on the orchestrator preset fail outright), and self-heal regenerates the whole preset, moving each role's persona and tool surface into a per-role AgentPreset (`agentPreset: paoding-role-<role>`); workspace presets (orchestrator-<slug>) are regenerated in the same self-heal pass. The 0.2.1 prereleases are subdivided further — the guard landed in 0.2.1-rc.2, so rc.0 / rc.1 keep the inline shape.
73
74
 
74
75
  Two cross-version behavior alignments happen the same automatic way, with no user action:
75
76
 
@@ -10,7 +10,7 @@
10
10
  dsh-paoding 把 DSH 从「单体 agent 全量加载工具」改造成「主 agent 编排 + 角色子 agent 分工」。分工遵循任务纹理:
11
11
 
12
12
  - **热路径——内部文件问题不委派。** 找代码、查引用、读文件这类问题由主 agent 自己用只读工具解决:`glob` / `grep` / `read` / `read_image` / `bash` 全部在主 agent 白名单内,零委派往返延迟。persona 文案里的 `codegraph` 是 host MCP 工具,仅在安装期检测到 codegraph 服务器并经 `main_agent_extra` 注入后才真正可用(详见[配置](configuration.md)与[安装](installation.md))。
13
- - **冷路径——只干自己那活的角色子 agent。** 外部调研委派 `search_external`(只带 `web_search` + tavily 五工具 + 本地只读)、UI/前端设计委派 `design`(读参考 + 设计技能 + 出 spec,不写最终代码)、代码实现委派 `implement`(读上下文 → 精准修改 → 验证)、超大仓库全量探索委派 `search_internal_deep`(第四角色,2026-09 加入,见下节与[架构](architecture.md))。每个子 agent 只在真正被委派的那一次才加载工具面(按需加载)。
13
+ - **冷路径——只干自己那活的角色子 agent。** 外部调研委派 `search_external`(只带 `web_search` / `web_fetch` + tavily 五工具 + 本地只读)、UI/前端设计委派 `design`(读参考 + 设计技能 + 出 spec,不写最终代码)、代码实现委派 `implement`(读上下文 → 精准修改 → 验证)、超大仓库全量探索委派 `search_internal_deep`(第四角色,2026-09 加入,见下节与[架构](architecture.md))。每个子 agent 只在真正被委派的那一次才加载工具面(按需加载)。
14
14
  - **运行中指挥。** 子 agent 运行期间,主 agent 可用 `send_message` 追加指示、`list_agents` 查看状态、`interrupt_agent` 叫停(三者由 `dsh-tool-subagent-control` 注册,属「子 agent 管理」工具面)。
15
15
  - **完成后只集成摘要。** 主 agent 从不把子 agent 的完整上下文倒进自己的上下文——它只收一份摘要(见第 5 节「上下文隔离」)。
16
16
 
@@ -22,7 +22,7 @@ dsh-paoding 把 DSH 从「单体 agent 全量加载工具」改造成「主 agen
22
22
  | 子 agent 管理 | `send_message` / `list_agents` / `interrupt_agent` |
23
23
  | 内部搜索(热路径) | `glob` / `grep` / `read` / `read_image` / `bash` |
24
24
  | 协调 | `todo_write` / `ask_user_question` / `get_goal` / `create_goal` / `update_goal` / `exit_plan_mode` / `job_output` / `job_list` / `job_kill` |
25
- | 主 agent 刻意看不到(节选,全文见 `restrict.mjs` 头注释) | `web_search`、`mcp__tavily__*`、`write` / `edit` / `str_replace_editor`、`skill`、`workflow`、`ralph`、`ssh_*`、`mcp__tablepro__*`、`describe_image`、裸 `subagent` / `subagent_fork` |
25
+ | 主 agent 刻意看不到(节选,全文见 `restrict.mjs` 头注释) | `web_search` / `web_fetch`、`mcp__tavily__*`、`write` / `edit` / `str_replace_editor`、`skill`、`workflow`、`ralph`、`ssh_*`、`mcp__tablepro__*`、`describe_image`、裸 `subagent` / `subagent_fork` |
26
26
 
27
27
  每请求工具开销(估算,随注册面浮动):主 agent 全量 ~16.2k tokens → 白名单后 ~5.5k;`search_external` ~3.0k / `design` ~3.3k / `implement` ~3.8k,仅在真正委派时发生(数值来源:`agent.cordis.yml` 头部注释)。
28
28
 
@@ -10,7 +10,7 @@ Orchestration is the core of dsh-paoding: the main agent (the orchestrator) deco
10
10
  dsh-paoding turns DSH from "a single agent that loads every tool" into "a main agent that orchestrates plus role agents that specialize". The split follows the texture of the task:
11
11
 
12
12
  - **Hot path — internal file questions are never delegated.** Finding code, chasing references, and reading files are solved by the main agent itself with its read-only tools: `glob` / `grep` / `read` / `read_image` / `bash` are all on the main-agent allow list, so there is zero delegation round-trip latency. `codegraph` in the persona copy is a host MCP tool: it is only actually available when the install-time detection finds the codegraph server and it is injected through `main_agent_extra` (see [Configuration](configuration_en.md) and [Installation](installation_en.md)).
13
- - **Cold path — role agents that carry only their own tools.** External research goes to `search_external` (only `web_search` + the five tavily tools + local reads); UI/frontend design goes to `design` (reads references, loads design skills, produces specs, never writes final code); code implementation goes to `implement` (read context → surgical change → verify); whole-repo deep exploration goes to `search_internal_deep` (a fourth role added 2026-09, see next section and [Architecture](architecture_en.md)). Each subagent is paid for only the run in which it is actually used (pay-per-use).
13
+ - **Cold path — role agents that carry only their own tools.** External research goes to `search_external` (only `web_search` / `web_fetch` + the five tavily tools + local reads); UI/frontend design goes to `design` (reads references, loads design skills, produces specs, never writes final code); code implementation goes to `implement` (read context → surgical change → verify); whole-repo deep exploration goes to `search_internal_deep` (a fourth role added 2026-09, see next section and [Architecture](architecture_en.md)). Each subagent is paid for only the run in which it is actually used (pay-per-use).
14
14
  - **Directing a running child.** While a subagent runs, the main agent can append instructions with `send_message`, inspect status with `list_agents`, and stop it with `interrupt_agent` (all three are registered by `dsh-tool-subagent-control` and belong to the "child management" surface).
15
15
  - **Integrate summaries only.** The main agent never dumps a child's full context into its own — it receives one summary (see section 5, Context isolation).
16
16
 
@@ -22,7 +22,7 @@ The main agent's model-facing surface is narrowed by `restrict.mjs` on the `syst
22
22
  | Child management | `send_message` / `list_agents` / `interrupt_agent` |
23
23
  | Internal search (hot path) | `glob` / `grep` / `read` / `read_image` / `bash` |
24
24
  | Coordination | `todo_write` / `ask_user_question` / `get_goal` / `create_goal` / `update_goal` / `exit_plan_mode` / `job_output` / `job_list` / `job_kill` |
25
- | Deliberately hidden from the main agent (excerpt; full list in the `restrict.mjs` header comment) | `web_search`, `mcp__tavily__*`, `write` / `edit` / `str_replace_editor`, `skill`, `workflow`, `ralph`, `ssh_*`, `mcp__tablepro__*`, `describe_image`, bare `subagent` / `subagent_fork` |
25
+ | Deliberately hidden from the main agent (excerpt; full list in the `restrict.mjs` header comment) | `web_search` / `web_fetch`, `mcp__tavily__*`, `write` / `edit` / `str_replace_editor`, `skill`, `workflow`, `ralph`, `ssh_*`, `mcp__tablepro__*`, `describe_image`, bare `subagent` / `subagent_fork` |
26
26
 
27
27
  Per-request tool tax (estimates; they float with the registered surface): full monolithic main agent ~16.2k tokens → ~5.5k after the allow list; `search_external` ~3.0k / `design` ~3.3k / `implement` ~3.8k, incurred only when actually delegated (figures from the header comment of `agent.cordis.yml`).
28
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-paoding",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "庖丁 — DSH (DeepSeek Harness) 编排模式安装器:host 感知的角色工具过滤 + Web 设置页可视化配置器",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,7 +20,8 @@
20
20
  "cordis.patch.yml"
21
21
  ],
22
22
  "engines": {
23
- "node": ">=18"
23
+ "node": ">=18",
24
+ "dsh": ">=0.1.5 <0.3"
24
25
  },
25
26
  "peerDependencies": {
26
27
  "@deepseek-ai/dsh": ">=0.1.5"
@@ -15,17 +15,21 @@ import { autoAssignments, baseAssignments } from '../../tools/lib/alloc.mjs'
15
15
  import { loadConfig, normalizeConfig, normalizeTargetFields, saveConfig, serializeConfig, stripNonTargetKeys } from '../../tools/lib/config.mjs'
16
16
  import { parseYamlSubset, preprocessPatchText } from '../../tools/lib/yaml.mjs'
17
17
  import { captureWarnings, healthCheck } from '../../tools/lib/health.mjs'
18
+ import { warn } from '../../tools/lib/util.mjs'
18
19
  import {
19
20
  backfillHomePatchRows,
20
- detectHostVersionTriple,
21
+ detectAgentRolesFlavor,
22
+ detectHostVersionInfo,
21
23
  detectPresetSystem,
22
24
  formatGeneratorMarker,
23
25
  isPtcWorkerHost,
24
26
  listOrchestratorPresetIds,
25
27
  parseGeneratorMarker,
28
+ presetRolesFlavorOf,
26
29
  presetRowId,
27
30
  readHomePatchRows,
28
31
  stripHomePatchRows,
32
+ ROLES_AGENT_PRESET,
29
33
  WORKER_PTC,
30
34
  WORKER_WORKER_THREAD,
31
35
  } from '../../tools/lib/preset-system.mjs'
@@ -35,6 +39,12 @@ function workerFlavorOf(hostVersionTriple) {
35
39
  return isPtcWorkerHost(hostVersionTriple) ? WORKER_PTC : WORKER_WORKER_THREAD
36
40
  }
37
41
 
42
+ /** 宿主版本信息 → 角色委派行标记行(生成产物行的形态,与 compose 对齐;
43
+ * prerelease 透传——0.2.1 守卫 0.2.1-rc.2 落地,rc.0/rc.1 按内联形态对账)。 */
44
+ function rolesFlavorOf(hostVersionTriple, prerelease) {
45
+ return presetRolesFlavorOf(hostVersionTriple, prerelease)
46
+ }
47
+
38
48
  /**
39
49
  * 标记 worker 行与当前宿主形态是否兼容:只有「产物形态」与「宿主所需形态」在
40
50
  * ptc/worker-thread 上分叉(其中一边是 ptc)才算换代——null(v2/v1 旧标记)与
@@ -46,6 +56,16 @@ function workerFlavorCompatible(markerWorker, currentWorker) {
46
56
  return (markerWorker === WORKER_PTC) === (currentWorker === WORKER_PTC)
47
57
  }
48
58
 
59
+ /**
60
+ * 标记角色行与当前宿主形态是否兼容(workerFlavorCompatible 同款语义):分叉 =
61
+ * 其中一边是 agent-preset;null(v3/v2 旧标记)与 inline 同侧——0.2.1 宿主上
62
+ * 旧插件版本的 inline 产物重生成也产不出新形状,重生成无意义;插件升级后版本
63
+ * 不符走整盘重生成,新形状经那条路径落地。
64
+ */
65
+ function rolesFlavorCompatible(markerRoles, currentRoles) {
66
+ return (markerRoles === ROLES_AGENT_PRESET) === (currentRoles === ROLES_AGENT_PRESET)
67
+ }
68
+
49
69
  export function resolveDshHome() {
50
70
  return process.env.DSH_HOME || path.join(os.homedir(), '.dsh')
51
71
  }
@@ -403,11 +423,12 @@ export function deleteWorkspacePreset(state, workspacePath) {
403
423
  //
404
424
  // 唯一官方安装通道是插件通道(dsh plugin add dsh-paoding),包不再携带 CLI:
405
425
  // preset 的落盘改由插件启动时自愈。对账基准是 preset 目录里的 .generator-version
406
- // 标记文件(v3 起内容 = 生成器版本 + 预设安装轨道 + workflow worker 形态三行):
407
- // 插件包版本变、或宿主轨道翻转 / worker 形态换代(只升 dsh 不动插件——升级最
408
- // 常见路径,旧标记缺行时同样解析为不符)→ 下次启动自动自愈,一举解决「升级后
409
- // preset 还是旧版产物」「升 dsh 后 preset 静默消失」与「升 dsh 后 worker 行
410
- // 失配 never started」三类漂移。
426
+ // 标记文件(v4 起内容 = 生成器版本 + 预设安装轨道 + workflow worker 形态 +
427
+ // 角色委派行形态四行):插件包版本变、或宿主轨道翻转 / worker 形态换代 / 角色
428
+ // 行换代(只升 dsh 不动插件——升级最常见路径,旧标记缺行时同样解析为不符)→
429
+ // 下次启动自动自愈,一举解决「升级后 preset 还是旧版产物」「升 dsh 后 preset
430
+ // 静默消失」「升 dsh 后 worker 行失配 never started」与「升 dsh 0.2.1 后内联
431
+ // persona/toolFilter 被 apply 拒绝、新建会话即抛错」四类漂移。
411
432
 
412
433
  // 生成器版本(标记对账基准):插件包根 package.json 读一次即缓存。读失败兜底
413
434
  // '0.0.0'——最坏后果只是每次启动多重生成一次 preset,不会装坏任何东西。
@@ -423,6 +444,45 @@ export function pluginVersion() {
423
444
  return cachedGeneratorVersion ?? '0.0.0'
424
445
  }
425
446
 
447
+ /**
448
+ * 工作区预设(orchestrator-<slug>)角色行形态迁移:基础 preset 整盘重生成后,
449
+ * 磁盘上各工作区产物的角色行形态若与宿主所需不符(典型:宿主刚升 0.2.1,工作区
450
+ * 产物还是旧内联形状——声明行又在场,挂该预设的新建会话照样被 tool-subagent
451
+ * 守卫拒绝),按该工作区在配置 workspaces 段里最后一次应用的条目就地重生成
452
+ *(顶层配置兜底合入,落盘不回写配置)。产物缺失(从未生成过)与形态判不出的
453
+ *(角色被清空)一律跳过——不自作主张替用户代生成;单个工作区失败只 warn,
454
+ * 绝不拖垮整体自愈。返回完成换代的工作区 presetId 列表。
455
+ */
456
+ function migrateWorkspacePresetRoles({ dshHome, state }) {
457
+ const wanted = presetRolesFlavorOf(state.hostVersionTriple, state.hostPrerelease)
458
+ const wsEntries = state.existing?.workspaces ?? {}
459
+ const wsPaths = Object.keys(wsEntries)
460
+ if (wsPaths.length === 0) return []
461
+ const slugs = assignSlugs(wsPaths)
462
+ const migrated = []
463
+ for (const wsPath of wsPaths) {
464
+ const presetId = presetIdOf(slugs.get(wsPath))
465
+ let flavor = null
466
+ try {
467
+ flavor = detectAgentRolesFlavor(readFileSync(path.join(dshHome, '.agent-presets', presetId, 'agent.cordis.yml'), 'utf8'))
468
+ } catch {
469
+ continue // 目录 / 产物缺失:该工作区从未生成过,保持沉默(生成是显式动作)
470
+ }
471
+ if (flavor === null || flavor === wanted) continue
472
+ try {
473
+ // 该工作区最后一次应用的条目优先,顶层字段兜底(条目缺键时回落全局值);
474
+ // saveConfigOnWrite=false——配置 workspaces 段原样保留,只换代产物。
475
+ const merged = { ...normalizeTargetFields(state.existing), ...normalizeTargetFields(wsEntries[wsPath]) }
476
+ const assignments = autoAssignments({ existing: merged, suggested: state.suggested, staticBase: state.staticBase })
477
+ generateAndInstall(state, assignments, { dryRun: false, saveConfigOnWrite: false, workspacePath: wsPath })
478
+ migrated.push(presetId)
479
+ } catch (err) {
480
+ warn(`工作区预设角色行换代失败(${presetId},可对该工作区重新「保存并应用」修复): ${err?.message ?? err}`)
481
+ }
482
+ }
483
+ return migrated
484
+ }
485
+
426
486
  // dispose 中止时的返回理由(记 reason 而非 error:不算失败,调用方不打日志)。
427
487
  const PRESET_ENSURE_ABORTED = '插件已卸载(dispose),本次 preset 生成中止'
428
488
 
@@ -431,9 +491,10 @@ const PRESET_ENSURE_ABORTED = '插件已卸载(dispose),本次 preset 生
431
491
  *
432
492
  * 判定(满足其一即动盘):
433
493
  * - preset 目录 / 标记缺失,或标记版本与 generatorVersion 不符 → 整盘重生成;
434
- * - 版本一致但标记 worker 形态与当前宿主所需分叉(宿主跨过 0.1.5/0.1.6
435
- * worker 边界;v2/v1 旧标记在真实 ptc 宿主上同样分叉)→ 整盘重生成(该行
436
- * 长在产物正文里,轻量路径覆盖不到);
494
+ * - 版本一致但标记 worker 形态或角色行形态与当前宿主所需分叉(宿主跨过
495
+ * 0.1.5/0.1.6 worker 边界或 0.2.0/0.2.1 角色行边界;旧格式标记在真实
496
+ * ptc/agent-preset 宿主上同样分叉)→ 整盘重生成(这些行长在产物正文里,
497
+ * 轻量路径覆盖不到);
437
498
  * - 版本 worker 都一致但标记轨道与当前宿主轨道不符(只升 dsh 不动插件 /
438
499
  * 旧格式标记)→ 轻量迁移:声明轨上按磁盘产物补写缺失声明行(内容字节
439
500
  * 不动,不重生成),directory 轨上落回整盘重生成(残留声明行会让 0.1.6
@@ -467,12 +528,14 @@ export async function ensurePresetInstalled({ dshHome = resolveDshHome(), genera
467
528
 
468
529
  if (marker !== null && marker.version === generatorVersion) {
469
530
  // 版本一致:内容原则上无需重生成,但宿主可能已随 dsh 升降级翻转轨道或
470
- // 跨过 workflow worker 形态边界(只升 dsh 不动插件是升级常态),声明行也
471
- // 可能被外部动过——这里做轻量对账。worker 形态不符(v2/v1 旧标记没有第
472
- // 三行,一律视为不符)不能走轻量路径:该行长在产物正文里,补行/撤行覆盖
473
- // 不到,必须整盘重生成——落到下方重生成分支。
474
- const currentWorker = workerFlavorOf(detectHostVersionTriple())
475
- if (workerFlavorCompatible(marker.worker, currentWorker)) {
531
+ // 跨过 workflow worker 形态 / 角色委派行形态边界(只升 dsh 不动插件是升级
532
+ // 常态),声明行也可能被外部动过——这里做轻量对账。worker 形态或角色行
533
+ // 形态不符(v3/v2/v1 旧标记缺行,一律视为不符)不能走轻量路径:这些行
534
+ // 长在产物正文里,补行/撤行覆盖不到,必须整盘重生成——落到下方重生成分支。
535
+ const hostInfo = detectHostVersionInfo()
536
+ const currentWorker = workerFlavorOf(hostInfo?.triple ?? null)
537
+ const currentRoles = rolesFlavorOf(hostInfo?.triple ?? null, hostInfo?.prerelease ?? null)
538
+ if (workerFlavorCompatible(marker.worker, currentWorker) && rolesFlavorCompatible(marker.roles, currentRoles)) {
476
539
  const system = await detectPresetSystem({ dshHome })
477
540
  if (shouldAbort?.()) return { installed: false, reason: PRESET_ENSURE_ABORTED }
478
541
  const presetIds = listOrchestratorPresetIds(dshHome)
@@ -481,7 +544,7 @@ export async function ensurePresetInstalled({ dshHome = resolveDshHome(), genera
481
544
  if (marker.track === 'declarative' && backfilled.length === 0) {
482
545
  return { installed: false, reason: 'preset 已由当前版本生成器产出,无需重生成' }
483
546
  }
484
- writeFileSync(markerFile, formatGeneratorMarker(generatorVersion, 'declarative', currentWorker), 'utf8')
547
+ writeFileSync(markerFile, formatGeneratorMarker(generatorVersion, 'declarative', currentWorker, currentRoles), 'utf8')
485
548
  return backfilled.length > 0
486
549
  ? { installed: false, backfilled, reason: `宿主已切换声明行轨,补写 ${backfilled.length} 条预设声明行(preset 内容未重生成)` }
487
550
  : { installed: false, reason: '预设安装轨道标记已更新为声明行轨(内容无需重生成)' }
@@ -492,12 +555,12 @@ export async function ensurePresetInstalled({ dshHome = resolveDshHome(), genera
492
555
  if (marker.track === 'directory') {
493
556
  return { installed: false, reason: 'preset 已由当前版本生成器产出,无需重生成' }
494
557
  }
495
- writeFileSync(markerFile, formatGeneratorMarker(generatorVersion, 'directory', currentWorker), 'utf8')
558
+ writeFileSync(markerFile, formatGeneratorMarker(generatorVersion, 'directory', currentWorker, currentRoles), 'utf8')
496
559
  return { installed: false, reason: '预设安装轨道标记已升级为带轨道格式(内容无需重生成)' }
497
560
  }
498
561
  // 声明行残留 + directory 宿主:落到下方整盘重生成
499
562
  }
500
- // worker 形态不符(含旧格式标记升级到 v3):落到下方整盘重生成
563
+ // worker 形态或角色行形态不符(含旧格式标记升级到 v4):落到下方整盘重生成
501
564
  }
502
565
 
503
566
  if (shouldAbort?.()) return { installed: false, reason: PRESET_ENSURE_ABORTED }
@@ -525,16 +588,20 @@ export async function ensurePresetInstalled({ dshHome = resolveDshHome(), genera
525
588
  if (shouldAbort?.()) return { installed: false, reason: PRESET_ENSURE_ABORTED }
526
589
  mkdirSync(presetDir, { recursive: true })
527
590
  const track = result.presetSystem === 'declarative' ? 'declarative' : 'directory'
528
- writeFileSync(markerFile, formatGeneratorMarker(generatorVersion, track, workerFlavorOf(state.hostVersionTriple)), 'utf8')
591
+ writeFileSync(markerFile, formatGeneratorMarker(generatorVersion, track, workerFlavorOf(state.hostVersionTriple), rolesFlavorOf(state.hostVersionTriple, state.hostPrerelease)), 'utf8')
529
592
  // 声明轨上整盘重生成只重建本 preset 的行:其余工作区 preset 目录若在而
530
593
  // 声明行缺(轨道翻转后首次触发本路径),一并补齐。
531
594
  const backfilled = track === 'declarative' ? backfillHomePatchRows(dshHome, listOrchestratorPresetIds(dshHome)) : []
595
+ // 工作区预设角色行形态换代(宿主跨 0.2.1 边界后的存量 orchestrator-<slug>
596
+ // 产物):基础重生成只换了全局预设,工作区产物不跟手就会继续被守卫拒绝。
597
+ const migratedPresets = migrateWorkspacePresetRoles({ dshHome, state })
532
598
  return {
533
599
  installed: true,
534
600
  ...(backfilled.length > 0 ? { backfilled } : {}),
535
- reason: state.existing
536
- ? 'preset 缺失或由旧版生成器产出,已按现有配置重新生成'
537
- : 'preset 缺失或由旧版生成器产出,已写入基础模板',
601
+ ...(migratedPresets.length > 0 ? { migratedPresets } : {}),
602
+ reason:
603
+ (state.existing ? 'preset 缺失或由旧版生成器产出,已按现有配置重新生成' : 'preset 缺失或由旧版生成器产出,已写入基础模板') +
604
+ (migratedPresets.length > 0 ? `;工作区预设角色行已换代:${migratedPresets.join('、')}` : ''),
538
605
  }
539
606
  } catch (err) {
540
607
  // 绝不抛:首装自愈是锦上添花,失败只带回 error 交调用方记日志,不拖垮插件启动。
@@ -0,0 +1,8 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <rect width="64" height="64" rx="14" fill="#4D6BFE"/>
3
+ <g transform="rotate(-45 32 32)">
4
+ <rect x="14" y="11" width="32" height="22" rx="3" fill="#FFFFFF"/>
5
+ <circle cx="41" cy="16.5" r="2" fill="#4D6BFE"/>
6
+ <rect x="44" y="17" width="13" height="10" rx="4" fill="#FFFFFF" opacity="0.85"/>
7
+ </g>
8
+ </svg>