dsh-paoding 0.3.0 → 0.3.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.
package/README.md CHANGED
@@ -13,10 +13,10 @@ dsh-paoding(中文品牌「庖丁」,典出《庄子》——庖丁顺纹理
13
13
  - **帮手还能指定专用模型**:写代码的用强档、查资料的用轻快档,各配各的模型;不配就跟随主 agent 当前会话的模型。
14
14
  - **帮手能就地续修**:把某个角色的「会话模式」切成可续(continuable),活干砸了或干得不满意,主 agent 用 `send_message` 在同一个子会话接着修,不用从头重派;默认全员一次性(one-shot)用完即弃,不开启就一切照旧。
15
15
  - **省钱省上下文**:帮手的工具只在被叫到时才加载,用一次付一次;主 agent 每次请求的工具开销约降三分之二,上下文只收摘要,不再被搜索结果和代码改动撑爆。
16
- - **角色随改随用**:删掉用不上的内置角色、给角色改显示名、给主 agent 配显示名,都是配置里一行的事;改完在面板点一次「保存并应用」,即刻生效。
16
+ - **角色随改随用**:删掉用不上的内置角色、给角色改显示名、给主 agent 配显示名,都是配置里一行的事;改完在面板点一次「保存并应用」,预设即时重生成,重启 DSH / 新建会话后生效。
17
17
  - **装了什么都能认出来**:MCP 服务器、本地插件、已装技能,安装与配置时全程检测;默认只装 dsh 基础工具,检测到的 host 工具在「庖丁配置」里按需勾选;停用哪个,重新应用后相关工具自动剔除。
18
18
  - **按工作区各有各的班底**:不同项目可以配不同的主/子 agent——「庖丁配置」里选定工作区单独配置,每个工作区生成自己的预设(`orchestrator-<目录名>`),新建会话时选对应预设即可,全局默认不受影响。
19
- - **图形界面配置**:不习惯改配置文件的话,点开左侧栏「新会话」下方的「庖丁配置」入口,整页点选即可,「保存并应用」与命令行走同一条生成管线。
19
+ - **图形界面配置**:不习惯改配置文件的话,点开左侧栏底部动作条(设置行上方)的「庖丁配置」入口,整页点选即可,「保存并应用」即时重生成预设——与首装自动化同一条生成管线。
20
20
  - **版本更新有提醒,面板一键升级**:面板会对比 npm registry(GitHub release 兜底)上的最新版本,发现新版就地提示并附上发布页链接;点「升级」就地执行 `dsh plugin update dsh-paoding`(profile 自动探测)换上新版,重启 DSH 后生效,编排预设会在重启时按新版自动重生成。开发检出的 link 形态无法就地升级,面板会提示切回 registry 版的办法;检测失败(比如断网)就静默跳过,不影响任何使用。
21
21
  - **来去自由**:不改 DSH 一行源码;装完新会话即用,卸载即删目录。
22
22
 
@@ -24,16 +24,6 @@ dsh-paoding(中文品牌「庖丁」,典出《庄子》——庖丁顺纹理
24
24
 
25
25
  ![截图 1](docs/images/1.png)
26
26
 
27
- ![截图 2](docs/images/2.png)
28
-
29
- ![截图 3](docs/images/3.png)
30
-
31
- ![截图 4](docs/images/4.png)
32
-
33
- ![截图 5](docs/images/5.png)
34
-
35
- ![截图 6](docs/images/6.png)
36
-
37
27
  ## 快速开始
38
28
 
39
29
  前置:**Node.js ≥ 18**、**pnpm** 与一台已装好的 DSH host(**@deepseek-ai/dsh ≥ 0.1.5**,最低支持版本)。
@@ -44,15 +34,16 @@ dsh-paoding(中文品牌「庖丁」,典出《庄子》——庖丁顺纹理
44
34
  dsh plugin --profile web add dsh-paoding
45
35
  ```
46
36
 
47
- 等价捷径:`npx dsh-paoding@latest`(内部转成上面这条命令,默认 profile web,需本机已装 dsh)。
37
+ 等价捷径:`npx dsh-paoding@latest`(内部转成上面这条命令,默认 profile web,需本机已装 dsh)。npx 拉到哪版就装哪版:实际安装的是 `dsh-paoding@<npx 拉取到的版本>`。
48
38
 
49
39
  `dsh plugin` 是 pnpm 的透明转发器:包被 pnpm 装进 profile,包内声明的 bundle patch 把「庖丁配置」面板挂进 DSH Web 左侧栏。**重启 DSH(`dsh web`)**即完成全部安装——插件启动时会自动检测,编排预设缺失或版本不符就自动生成一次(有 `~/.dsh/dsh-paoding.config.yml` 按配置应用,没有则写基础模板),无需再点任何按钮。新会话的预设选择器里选「编排模式 (Orchestrator)」即可;要设为默认,在 Settings → Agent Presets 里选。
50
40
 
51
- 开箱默认只带 DSH 自带的基础工具,检测到的 MCP/host 工具不会自动写入——装完点开左侧栏的**「庖丁配置」**按需勾选工具与角色,「保存并应用」即生效。不想要了,卸载也干净:
41
+ 开箱默认只带 DSH 自带的基础工具,检测到的 MCP/host 工具不会自动写入——装完点开左侧栏的**「庖丁配置」**按需勾选工具与角色,「保存并应用」即生效。不想要了,三条命令卸干净(按工作区配置生成的各工作区预设也一并删除):
52
42
 
53
43
  ```bash
54
44
  dsh plugin --profile web remove dsh-paoding
55
45
  rm -rf "${DSH_HOME:-$HOME/.dsh}/.agent-presets/orchestrator"
46
+ rm -rf "${DSH_HOME:-$HOME/.dsh}/.agent-presets"/orchestrator-*
56
47
  ```
57
48
 
58
49
  **开发检出自装**——想改插件或预设源码时,用 link 形态直连仓库(改动经 HMR/重启生效):
@@ -79,7 +70,7 @@ dsh plugin --profile web add link:"$PWD/dsh-paoding"
79
70
 
80
71
  ## 配置
81
72
 
82
- 所有偏好都写在 `~/.dsh/dsh-paoding.config.yml`:角色增删改、技能分配、专用模型、会话模式(one-shot / continuable)、主 agent 的工具与技能……改完打开 设置 → 庖丁配置,点「保存并应用」即同步生效。预设每次由「静态源 + 配置」重新生成,不攒手工补丁。全部配置键说明见 [配置文档](docs/configuration.md);背后机制与成本账见 [架构文档](docs/architecture.md)。
73
+ 所有偏好都写在 `~/.dsh/dsh-paoding.config.yml`:角色增删改、技能分配、专用模型、会话模式(one-shot / continuable)、主 agent 的工具与技能……改完打开左侧栏底部的「庖丁配置」入口,点「保存并应用」即同步生效。预设每次由「静态源 + 配置」重新生成,不攒手工补丁。全部配置键说明见 [配置文档](docs/configuration.md);背后机制与成本账见 [架构文档](docs/architecture.md)。
83
74
 
84
75
  ## 文档
85
76
 
@@ -92,7 +83,7 @@ dsh plugin --profile web add link:"$PWD/dsh-paoding"
92
83
 
93
84
  ## 贡献
94
85
 
95
- 欢迎 issue 与 PR:使用中发现问题、想要新的角色、或发现文档与实现不一致,都可以提。动手前请先读 [架构](docs/architecture.md) 与 [配置](docs/configuration.md);文档与实现冲突时,以 `presets/orchestrator/` 与 `tools/install.mjs` 源码为准。
86
+ 欢迎 issue 与 PR:使用中发现问题、想要新的角色、或发现文档与实现不一致,都可以提。动手前请先读 [架构](docs/architecture.md) 与 [配置](docs/configuration.md);文档与实现冲突时,以 `presets/orchestrator/` 与 `tools/` 源码为准。
96
87
 
97
88
  ## 许可
98
89
 
package/README_en.md CHANGED
@@ -13,10 +13,10 @@ dsh-paoding (Chinese brand 「庖丁」/ Pao Ding, from the Zhuangzi parable of
13
13
  - **A dedicated model per helper**: pin the coder to a stronger model and the researcher to a lighter, faster one; unset, they follow the main agent's current session model.
14
14
  - **Helpers that finish the job in place**: flip a role's session mode to continuable and, when a run fails or disappoints, the main agent resumes the same child conversation with `send_message` instead of re-delegating from scratch. Every role defaults to one-shot — run and discard — so nothing changes until you flip it.
15
15
  - **Cheaper requests, cleaner context**: a helper's tools load only when it is called — pay per use. The main agent's per-request tool overhead drops by roughly two-thirds, and it keeps only summaries instead of accumulating search dumps and diffs.
16
- - **Roles bend to your setup**: delete built-in roles you don't need, give roles display names, set a display name for the main agent — all one line of config; hit Save & Apply in the panel once and the preset regenerates instantly.
16
+ - **Roles bend to your setup**: delete built-in roles you don't need, give roles display names, set a display name for the main agent — all one line of config; hit Save & Apply in the panel once and the preset regenerates on the spot, taking effect after a DSH restart or a new session.
17
17
  - **Whatever you've installed, it's recognized**: MCP servers, local plugins, installed skills — detected throughout install and configuration; the default install carries only DSH base tools, and detected host tools are opted into per tool in **Paoding Config**; disable one, re-apply, and its tools drop out on their own.
18
18
  - **A different lineup per workspace**: each project can carry its own main/sub-agent setup — pick the workspace in 庖丁配置, configure it separately, and it gets its own preset (`orchestrator-<basename>`); choose that preset when starting a session. The global default stays untouched.
19
- - **A visual configurator**: prefer clicking to editing YAML? the 庖丁配置 (Paoding Config) page in the left sidebar covers everything, sharing the exact same generation pipeline as the CLI.
19
+ - **A visual configurator**: prefer clicking to editing YAML? the 庖丁配置 (Paoding Config) entry in the sidebar bottom action bar (above the Settings row) covers everything; Save & Apply regenerates the preset on the spot — the same generation pipeline as first-install automation.
20
20
  - **Notified of new releases, one-click upgrade in the panel**: the panel compares your local version against the latest npm registry publish (GitHub release as fallback) and points to the release page when a newer one is out. The Upgrade button runs `dsh plugin update dsh-paoding` in place (profile auto-detected) to swap in the new version; 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), it stays silent and nothing is interrupted.
21
21
  - **Installs and uninstalls cleanly**: no DSH source changes; active in a new session right after install, gone when you delete one directory.
22
22
 
@@ -24,16 +24,6 @@ dsh-paoding (Chinese brand 「庖丁」/ Pao Ding, from the Zhuangzi parable of
24
24
 
25
25
  ![Screenshot 1](docs/images/1.png)
26
26
 
27
- ![Screenshot 2](docs/images/2.png)
28
-
29
- ![Screenshot 3](docs/images/3.png)
30
-
31
- ![Screenshot 4](docs/images/4.png)
32
-
33
- ![Screenshot 5](docs/images/5.png)
34
-
35
- ![Screenshot 6](docs/images/6.png)
36
-
37
27
  ## Quick Start
38
28
 
39
29
  Prerequisites: **Node.js ≥ 18**, **pnpm**, and a working DSH host (**@deepseek-ai/dsh >= 0.1.5**, the minimum supported version).
@@ -44,15 +34,16 @@ Prerequisites: **Node.js ≥ 18**, **pnpm**, and a working DSH host (**@deepseek
44
34
  dsh plugin --profile web add dsh-paoding
45
35
  ```
46
36
 
47
- Equivalent shortcut: `npx dsh-paoding@latest` (delegates to the command above; default profile web; requires dsh on PATH).
37
+ Equivalent shortcut: `npx dsh-paoding@latest` (delegates to the command above; default profile web; requires dsh on PATH). Whichever version npx pulls is what gets installed: the actual install is `dsh-paoding@<the version npx resolved>`.
48
38
 
49
39
  `dsh plugin` is a transparent pass-through to pnpm: the package is installed into the profile by pnpm, and the bundle patch declared inside it mounts the 庖丁配置 (Paoding Config) page into the DSH Web left sidebar. **Restart DSH (`dsh web`)** and the install is complete — on startup the plugin checks itself, and if the orchestrator preset is missing or carries an outdated version marker it regenerates it once (applying `~/.dsh/dsh-paoding.config.yml` when present, writing the base template otherwise). Nothing else to click. Pick "编排模式 (Orchestrator)" in the new-session preset selector; to make it the default, choose it in Settings → Agent Presets.
50
40
 
51
- Out of the box only DSH's built-in base tools are enabled — detected MCP/host tools are not written in automatically. Open **庖丁配置 (Paoding Config)** in the sidebar, opt into the tools and roles you need, and hit Save & Apply. When you no longer want it, uninstalling is just as clean:
41
+ Out of the box only DSH's built-in base tools are enabled — detected MCP/host tools are not written in automatically. Open **庖丁配置 (Paoding Config)** in the sidebar, opt into the tools and roles you need, and hit Save & Apply. When you no longer want it, three commands uninstall it for good — the per-workspace presets created by workspace-specific configs are removed too:
52
42
 
53
43
  ```bash
54
44
  dsh plugin --profile web remove dsh-paoding
55
45
  rm -rf "${DSH_HOME:-$HOME/.dsh}/.agent-presets/orchestrator"
46
+ rm -rf "${DSH_HOME:-$HOME/.dsh}/.agent-presets"/orchestrator-*
56
47
  ```
57
48
 
58
49
  **Dev checkout install** — to hack on the plugin or the preset sources, link the repository directly (changes go live via HMR or a restart):
@@ -79,7 +70,7 @@ While a helper runs, the main agent can send follow-ups, check progress, or stop
79
70
 
80
71
  ## Configuration
81
72
 
82
- All preferences live in `~/.dsh/dsh-paoding.config.yml`: role add/remove/tweak, skill assignment, per-role models, per-role session modes (one-shot / continuable), the main agent's tools and skills… Edit it, open Settings → 庖丁配置 (Paoding Config), and hit Save & Apply — the preset syncs. It is regenerated from "static source + config" every time, so no manual patches pile up. The full key reference is in the [configuration guide](docs/configuration_en.md); the rationale and the cost ledger are in the [architecture guide](docs/architecture_en.md).
73
+ All preferences live in `~/.dsh/dsh-paoding.config.yml`: role add/remove/tweak, skill assignment, per-role models, per-role session modes (one-shot / continuable), the main agent's tools and skills… Edit it, open the 庖丁配置 (Paoding Config) entry at the bottom of the sidebar, and hit Save & Apply — the preset syncs. It is regenerated from "static source + config" every time, so no manual patches pile up. The full key reference is in the [configuration guide](docs/configuration_en.md); the rationale and the cost ledger are in the [architecture guide](docs/architecture_en.md).
83
74
 
84
75
  ## Documentation
85
76
 
@@ -92,7 +83,7 @@ All preferences live in `~/.dsh/dsh-paoding.config.yml`: role add/remove/tweak,
92
83
 
93
84
  ## Contributing
94
85
 
95
- Issues and PRs are welcome: report problems, request new roles, or point out where the docs and the implementation disagree. Before contributing, read the [architecture](docs/architecture_en.md) and [configuration](docs/configuration_en.md) guides; when a document and the code conflict, the source of truth is `presets/orchestrator/` and `tools/install.mjs`.
86
+ Issues and PRs are welcome: report problems, request new roles, or point out where the docs and the implementation disagree. Before contributing, read the [architecture](docs/architecture_en.md) and [configuration](docs/configuration_en.md) guides; when a document and the code conflict, the source of truth is `presets/orchestrator/` and `tools/`.
96
87
 
97
88
  ## License
98
89
 
@@ -10,7 +10,7 @@ import os from 'node:os';
10
10
  import { PROFILE_NAME_RE } from '../tools/lib/util.mjs';
11
11
 
12
12
  const REFUSE =
13
- '本入口是 dsh plugin 的快捷方式,完整功能见 dsh plugin --help / 设置 → 庖丁配置';
13
+ '本入口是 dsh plugin 的快捷方式,完整功能见 dsh plugin --help / 侧栏底部「庖丁配置」入口';
14
14
 
15
15
  const usage = `dsh-paoding 安装快捷方式(等价于 dsh plugin --profile <name> add dsh-paoding@<version>)
16
16
 
@@ -68,7 +68,7 @@ child.on('error', (err) => {
68
68
  child.on('close', (code) => {
69
69
  if (code === 0) {
70
70
  console.log(`已通过插件通道安装到 profile ${profile ?? 'web'}。`);
71
- console.log('重启 DSH 后生效——preset 会在启动时自动生成,面板入口在 Web 左侧栏「新会话」下方。');
71
+ console.log('重启 DSH 后生效——preset 会在启动时自动生成,面板入口在左侧栏底部(设置行上方)的「庖丁配置」入口。');
72
72
  }
73
73
  process.exitCode = code ?? 1; // 子进程退出码原样透传,别吞掉 dsh/pnpm 的失败信号
74
74
  });
@@ -34,8 +34,7 @@ dsh-paoding(中文品牌「庖丁」,取庖丁解牛之意)是 DSH(DeepS
34
34
  | 开销 | 每请求固定承载 ~16.2k tokens 工具定义 | 主 agent ~5.5k;角色工具面 ~3.0k–3.8k,仅委派时发生 |
35
35
  | 上下文 | 每次搜索 dump、每轮设计稿、每段 diff 都累积进主上下文 | worker 上下文小而专、用完即弃,主 agent 只收摘要 |
36
36
 
37
- 组合的静态源是 `presets/orchestrator/agent.cordis.yml`(叠加在 DSH builtin `standard` preset 全量组合
38
- 之上,见「原理:对应 DSH 原生机制」一节),运行时由 `restrict.mjs` 裁剪主 agent 工具面。
37
+ 组合的静态源是 `presets/orchestrator/agent.cordis.yml`(原样包含 DSH builtin `standard` preset 的全部组合行——同一组合内复制,而非运行时继承,见「原理:对应 DSH 原生机制」之机制①),运行时由 `restrict.mjs` 裁剪主 agent 工具面。
39
38
  四个角色委派实例的 ID 为 `delegation-search-external` / `delegation-design` /
40
39
  `delegation-implement` / `delegation-search-internal-deep`,均在组合的 delegation 组内;该组还挂有
41
40
  通用委派工具 `subagent` / `subagent_fork` / `workflow` / `ralph`(主 agent 白名单不包含它们,角色委派
@@ -138,7 +137,7 @@ dsh-paoding(中文品牌「庖丁」,取庖丁解牛之意)是 DSH(DeepS
138
137
  内置四角色只是**出厂分工**:任何「工具 + 技能」组合都能以同一机制成为新委派工具——在配置文件 `roles`
139
138
  键写一个 toolName(或在庖丁配置面板新建),生成器生成 `delegation-<toolName>` 块、把 toolName
140
139
  注入主 agent 白名单,并把角色 persona 首行职责句自动追加为主 agent persona 的委派行(tools 为空的
141
- 角色应用时会被拒绝安装),详见 [docs/configuration.md](configuration.md) 第 6 节;自定义角色同样支持 `model` / `provider` 专用模型(与内置角色同一子键、同一生成机制,见 2.5)。例如建一个装配 `html-ppt`
140
+ 角色应用时会被拒绝安装),详见 [docs/configuration.md](configuration.md) 第 6 节;自定义角色同样支持 `model` / `provider` 专用模型与 `background_mode` 会话模式(与内置角色同一子键、同一生成机制——生成器为自定义角色块恒写 `backgroundMode` 行,`continuable` 同样生效,见 2.5 / 2.6)。例如建一个装配 `html-ppt`
142
141
  技能的 `ppt` agent,做 PPT 这类任务就有了专属子 agent。
143
142
 
144
143
  | 委派工具 | 实例 ID | persona 一句话职责 | 加载成本 |
@@ -148,12 +147,15 @@ dsh-paoding(中文品牌「庖丁」,取庖丁解牛之意)是 DSH(DeepS
148
147
  | `implement` | `delegation-implement` | 写与改代码:先读上下文 → 精准修改 → 验证(build/test/grep);不改架构 | ~3.8k,仅委派时 |
149
148
  | `search_internal_deep` | `delegation-search-internal-deep` | 只做仓库探索:不改文件、不联网;处理主 agent 上下文装不下的任务(全仓 grep dump、超页大文件通读、跨目录符号/定义追踪),只回浓缩摘要 | 未单独估算,仅委派时 |
150
149
 
151
- 上表是出厂默认形态,配置层可再裁剪与定制(详见 [docs/configuration.md](configuration.md)):`search_external` / `design` / `implement` 三个可经 `roles_remove` 整条删除(2.3,`search_internal_deep` 删不掉);内置角色可配显示名 `roles.<toolName>.name`,只替换该角色 persona 首行身份句主语(2.4);可配专用模型 `roles.<toolName>.model` / `.provider`,生成器在委派块注入 `agentOptions`,不配则跟随主 agent(2.5);可配会话模式 `roles.<toolName>.background_mode`,配成 `continuable` 时委派块注入 `backgroundMode` 行、子会话跨轮保留(2.6);主 agent 的 persona 身份行不可改名(编排主 agent 的身份不属于可配置项),另有 `main_agent_display_name` 只改 preset 显示名、不动 persona 身份行(见 configuration.md 第 5 节)。
150
+ 上表是出厂默认形态,配置层可再裁剪与定制(详见 [docs/configuration.md](configuration.md)):`search_external` / `design` / `implement` 三个可经 `roles_remove` 整条删除(2.3,`search_internal_deep` 删不掉);内置角色可配显示名 `roles.<toolName>.name`,只替换该角色 persona 首行身份句主语(2.4);可配专用模型 `roles.<toolName>.model` / `.provider`,生成器在委派块注入 `agentOptions`,不配则跟随主 agent(2.5);可配会话模式 `roles.<toolName>.background_mode`,配成 `continuable` 时委派块注入 `backgroundMode` 行、子会话跨轮保留——内置角色与自定义角色同语义,生成器为自定义角色块恒写 `backgroundMode` 行(2.6);主 agent 的 persona 身份行不可改名(编排主 agent 的身份不属于可配置项),另有 `main_agent_display_name` 只改 preset 显示名、不动 persona 身份行(见 configuration.md 第 5 节)。
152
151
 
153
152
  ### 角色 toolFilter.allow 明细
154
153
 
155
154
  以下 allow 列表逐字抄录自 `agent.cordis.yml`(安装期生成器按「preset 自带工具面 ∪ 运行时检测库存」
156
- 白名单对账重写各列表,两头都不占的名字剔除并说明原因,见 [docs/configuration.md](configuration.md))。
155
+ 白名单对账重写的只是 `search_external` / `design` / `implement` 三个可配角色的 allow——两头都不占的
156
+ 名字被剔除并在「预览生成」的 removed 列表给出原因;`search_internal_deep` 为静态委派,其 allow 列表
157
+ **不做**库存对账:手写进去、两头都不占的名字不会被剔除,会静默落盘、运行时以 unknown tools 拒创建
158
+ (与下方该角色的 codegraph 注同一口径),见 [docs/configuration.md](configuration.md))。
157
159
 
158
160
  **`search_external`(外部调研,10 项)**
159
161
 
@@ -39,8 +39,9 @@ The essential differences from monolithic mode:
39
39
  | Cost | ~16.2k tokens tool tax paid on every request | Main agent ~5.5k; role surfaces ~3.0k–3.8k, paid only when delegated |
40
40
  | Context | Every search dump, design draft and diff accumulates in the main context | Worker contexts are small and specialized and discarded after use; the main agent receives only summaries |
41
41
 
42
- The static source of the composition is `presets/orchestrator/agent.cordis.yml`, layered on top of DSH's
43
- builtin `standard` preset in full (see the "Under the hood" section below); at runtime
42
+ The static source of the composition is `presets/orchestrator/agent.cordis.yml`, which includes all of the
43
+ builtin `standard` preset's composition rows verbatim — copied into the same composition, not inherited at
44
+ runtime (see mechanism ① in the "Under the hood" section below); at runtime
44
45
  `restrict.mjs` trims the main agent's tool surface. The four role delegation instances are
45
46
  `delegation-search-external` / `delegation-design` / `delegation-implement` /
46
47
  `delegation-search-internal-deep`, all inside the composition's delegation group. That group also carries the
@@ -176,8 +177,9 @@ it in the 庖丁配置 panel), the generator produces a `delegation-<toolName>`
176
177
  toolName into the main-agent allow list, and appends the role's persona first line (its duty sentence)
177
178
  to the main-agent persona as a delegation row (a role with no tools is rejected at apply time); see
178
179
  section 6 of [docs/configuration_en.md](configuration_en.md).
179
- Custom roles support the same `model` / `provider` dedicated-model sub-keys as the built-in roles (same
180
- sub-keys, same generation mechanism — see 2.5).
180
+ Custom roles support the same `model` / `provider` dedicated-model sub-keys and the same `background_mode`
181
+ session-mode sub-key as the built-in roles (same sub-keys, same generation mechanism — the generator always
182
+ writes a `backgroundMode` row for custom role blocks, and `continuable` takes effect the same way — see 2.5 / 2.6).
181
183
  For example, a `ppt` agent carrying the `html-ppt` skill gives slide-making its own dedicated sub-agent.
182
184
 
183
185
  | Delegation tool | Instance ID | Persona in one sentence | Load cost |
@@ -194,7 +196,8 @@ name `roles.<toolName>.name`, which rewrites only the subject of its persona ide
194
196
  also be pinned to a dedicated model `roles.<toolName>.model` / `.provider`, injected by the generator as
195
197
  `agentOptions` in the delegation block, defaulting to following the main agent (2.5); and it can carry a session
196
198
  mode `roles.<toolName>.background_mode` — configured as `continuable`, the delegation block gets a
197
- `backgroundMode` row and the child conversation is kept across turns (2.6); the main agent's persona
199
+ `backgroundMode` row and the child conversation is kept across turns; built-in and custom roles share the
200
+ semantics, with the generator always writing the `backgroundMode` row for custom role blocks (2.6); the main agent's persona
198
201
  identity line cannot be renamed (the orchestrator's identity is not a configurable item); `main_agent_display_name`
199
202
  (see configuration_en.md section 5) changes only the preset display name and leaves the persona
200
203
  identity line untouched.
@@ -202,8 +205,12 @@ identity line untouched.
202
205
  ### Per-role toolFilter.allow detail
203
206
 
204
207
  The allow lists below are transcribed verbatim from `agent.cordis.yml` (at install time the generator
205
- rewrites each list against the whitelist "preset's own tool face ∪ runtime detection inventory"; names in
206
- neither are dropped with a stated reason, see
208
+ rewrites only the three configurable roles' allow lists — `search_external` / `design` / `implement` —
209
+ against the whitelist "preset's own tool face ∪ runtime detection inventory"; names in neither are dropped
210
+ with a stated reason in the Preview removed list. `search_internal_deep` is a static delegation whose allow
211
+ list is **not** reconciled against the inventory: hand-written names that belong to neither are kept, land
212
+ on disk silently, and fail at runtime with unknown tools at child creation — same caveat as the codegraph
213
+ note for that role below; see
207
214
  [docs/configuration_en.md](configuration_en.md)).
208
215
 
209
216
  **`search_external` (external research, 10 entries)**
@@ -28,7 +28,7 @@ dsh-paoding 把「按角色分工的编排 preset」做成**配置驱动**:你
28
28
 
29
29
  ### 1.2 顶层键
30
30
 
31
- 以下键名与 `tools/install.mjs` 的 `normalizeConfig` 一致(配置文件 schema 的唯一权威来源)。
31
+ 以下键名与 `tools/lib/config.mjs` 的 `normalizeConfig` 一致(配置文件 schema 的唯一权威来源;`tools/install.mjs` 仅转出口)。
32
32
 
33
33
  | 顶层键 | 类型 | 语义 |
34
34
  |---|---|---|
@@ -55,14 +55,14 @@ dsh-paoding 把「按角色分工的编排 preset」做成**配置驱动**:你
55
55
  - `roles` 下键名不在三角色内 = 自定义角色(见第 6 节);请勿把静态角色 `search_internal_deep` 写进 `roles`(见 2.2)。
56
56
  - 内置角色可**整体删除**:`roles_remove` 键只认三角色名,删除效果、与 `roles` 键的一致性及恢复路径见 2.3。
57
57
 
58
- `main_agent_extra` 缺省 / 为空时回落到「按本次检测的智能默认」(检测到的 codegraph、`memory_search` 等归主 agent)——这也是不写任何配置时主 agent 仍能直接调 codegraph 工具的原因。
58
+ `main_agent_extra` **键缺失**(老配置 / 未写过该键)时回落到「按本次检测的智能默认」(检测到的 codegraph、`memory_search` 等归主 agent);**显式 `main_agent_extra: []` 表示明确不要 host 工具,不再回落**——fresh 首装落盘的基础模板即显式 `main_agent_extra: []` 形态,默认不含任何 host 工具(codegraph 等需在配置或面板里显式开启才可用)。
59
59
 
60
60
  ### 1.3 完整最小示例
61
61
 
62
62
  一个覆盖全部常用键的配置文件(键序与面板写出的 `serializeConfig` 一致):
63
63
 
64
64
  ```yaml
65
- # dsh-paoding(庖丁)安装配置 —— 可手编;改后在 设置 → 庖丁配置 应用,或重跑 node tools/install.mjs --auto
65
+ # dsh-paoding(庖丁)安装配置 —— 可手编;改后在侧栏底部「庖丁配置」入口应用,或重跑 node tools/install.mjs --auto
66
66
 
67
67
  profile: web # 检测时扫描 profiles/<profile>/cordis.patch.yml
68
68
 
@@ -84,7 +84,7 @@ roles: # toolName -> { persona?, tools[] }
84
84
  design: # 只改 persona、tools 留空 = 保留静态 allow
85
85
  persona: |-
86
86
  You are the design agent. Produce UI/UX designs and specs; never implement final code.
87
- code-reviewer: # 自定义角色(toolName 匹配 /^[a-z][a-z0-9_]*$/)
87
+ code-reviewer: # 自定义角色(toolName 匹配 /^[a-z][a-z0-9_-]{1,31}$/)
88
88
  persona: |-
89
89
  You are the code-reviewer agent. Review diffs and files for bugs, security
90
90
  issues and style regressions; report a prioritized list with file:line.
@@ -106,7 +106,7 @@ main_agent_remove: # 裁基础工具(实测四项约省 ≈0.8k tokens/
106
106
  - exit_plan_mode
107
107
  main_agent_skills: # 软引导:persona 技能行 + 主 agent 用 read 按需加载
108
108
  - caveman
109
- main_agent_skills_inline: [] # 硬内联(空 = 不用);与 skills 同列时只内联不写软行
109
+ main_agent_skills_inline: [] # 硬内联(空 = 不用);与 `main_agent_skills` 同列时只内联不写软行
110
110
  main_agent_persona_extra: |- # null/缺省 = 默认 codegraph 规则;'' = 不追加;其他 = 覆盖
111
111
  Never call codegraph_* tools without passing projectPath = {{cwd}}.
112
112
 
@@ -191,7 +191,7 @@ roles_remove:
191
191
  - design # 不再生成 delegation-design 块;主 agent persona 里的 design 委派指引一并移除
192
192
  ```
193
193
 
194
- 与 `roles` 键的关系:`roles` 里仍保留**未被删**的内置角色条目(想覆盖其 persona / tools 照旧写)。「删除」的完整状态 = `roles_remove` 含该名 **且** `roles` 无该 key —— UI / CLI 会保证这一致性,手编配置请自行保持一致;两者冲突时,生成以 `roles_remove` 为准。
194
+ 与 `roles` 键的关系:`roles` 里仍保留**未被删**的内置角色条目(想覆盖其 persona / tools 照旧写)。「删除」的完整状态 = `roles_remove` 含该名 **且** `roles` 无该 key —— 面板(与兜底 CLI)会保证这一致性,手编配置请自行保持一致;两者冲突时,生成以 `roles_remove` 为准。
195
195
 
196
196
  恢复:
197
197
 
@@ -309,9 +309,9 @@ main_agent_extra:
309
309
 
310
310
  要点:
311
311
 
312
- - 追加项会进入生成的 `orchestrator-restrict config.allow`。注入同样走白名单对账:名字必须落在 **preset 自带工具面**(`restrict.mjs` 主 agent 白名单 ∪ 源 preset 各角色静态 allow)或**检测库存**里,host 工具(`mcp__*`、`mnemon_*` 等插件工具)以实际检测结果为准——没检测到(MCP/插件未启用、拼写错误)就不注入、不报错,「预览生成」的角色 removed 列表可看原因。
312
+ - 追加项会进入生成的 `orchestrator-restrict config.allow`。注入同样走白名单对账:名字必须落在 **preset 自带工具面**(`restrict.mjs` 主 agent 白名单 ∪ 源 preset 各角色静态 allow)或**检测库存**里,host 工具(`mcp__*`、`mnemon_*` 等插件工具)以实际检测结果为准——没检测到(MCP/插件未启用、拼写错误)就不注入、不报错。注意「预览生成」的 removed 列表只覆盖**角色 allow** 的对账结果;`main_agent_extra` 被丢弃的名字只在兜底 CLI 输出里汇总数量、不列明细,需要明细可直接看预览的主 agent allow 终值。
313
313
  - 面板的「主 agent」卡片里可勾选的具体 MCP / 插件工具,以检测结果(工具池)为准。
314
- - `main_agent_extra` 缺省/为空时,生成器回落到智能默认(检测到的 codegraph、`memory_search` 建议归主 agent)。
314
+ - `main_agent_extra` **键缺失**时,生成器回落到智能默认(检测到的 codegraph、`memory_search` 建议归主 agent);显式 `main_agent_extra: []` = 明确不要 host 工具、不再回落(fresh 首装落盘的基础模板即此形态)。
315
315
 
316
316
  ### 3.3 移除基础工具:main_agent_remove
317
317
 
@@ -391,7 +391,7 @@ main_agent_skills_inline:
391
391
  | 找不到对应 SKILL.md | **警告并跳过**(不中断安装);对两条键各警告一次、去重 |
392
392
  | SKILL.md 存在但正文为空 | 视为找不到,跳过 |
393
393
  | `description` 解析 | 支持单行、引号(单/双)、折叠块(`>`)与字面块(`\|`,含标记独立成行);空白折叠、去外层引号、截断至 200 字符;缺省为空串 |
394
- | SKILL.md 扫描范围 | 全局(CLI 安装 / 面板「全局默认」)只扫用户级两根:`$DSH_HOME/skills`(默认 `~/.dsh/skills`)、`$DSH_AGENTS_HOME/skills`(默认 `~/.agents/skills`);按工作区生成时另加该工作区目录的 `.dsh/skills` 与 `.agents/skills`(见第 9 节)。同根内 `<root>/<name>/SKILL.md` 优先于裸 `<root>/<name>.md` |
394
+ | SKILL.md 扫描范围 | 全局(兜底 CLI 安装 / 面板「全局默认」)只扫用户级两根:`$DSH_HOME/skills`(默认 `~/.dsh/skills`)、`$DSH_AGENTS_HOME/skills`(默认 `~/.agents/skills`);按工作区生成时另加该工作区目录的 `.dsh/skills` 与 `.agents/skills`(见第 9 节)。同根内 `<root>/<name>/SKILL.md` 优先于裸 `<root>/<name>.md` |
395
395
 
396
396
  技能名来自应用时的技能检测(同上四个根);面板只会列出检测到的技能。
397
397
 
@@ -431,11 +431,11 @@ main_agent_display_name: 庖丁 # 仅 preset 显示名换成「庖丁」,per
431
431
  | 显式 `''` | **不追加任何内容**(连默认规则也不加) |
432
432
  | 其它文本 | **覆盖**默认,追加你的文本 |
433
433
 
434
- 写入格式:`''` 会以 `main_agent_persona_extra: ''` 写出(区别于缺省);多行文本以 `|-` 块标量写出。`tools/install.mjs` 的 `normalizeConfig` 只接受 string(非 string / 缺省 → `null`)。
434
+ 写入格式:`''` 会以 `main_agent_persona_extra: ''` 写出(区别于缺省);多行文本以 `|-` 块标量写出。`tools/lib/config.mjs` 的 `normalizeConfig` 只接受 string(非 string / 缺省 → `null`)。
435
435
 
436
436
  ### 5.3 默认常量原文
437
437
 
438
- 单点事实源是 `tools/install.mjs` 里的 `DEFAULT_MAIN_AGENT_PERSONA_EXTRA`(`presets/orchestrator/agent.cordis.yml` **不再内置**该行)。默认值原文(英文):
438
+ 单点事实源是 `tools/lib/util.mjs` 里的 `DEFAULT_MAIN_AGENT_PERSONA_EXTRA`(`tools/install.mjs` 仅 re-export 转出口,不定义;`presets/orchestrator/agent.cordis.yml` **不再内置**该行)。默认值原文(英文):
439
439
 
440
440
  > Codegraph MCP default project may be a DIFFERENT repository than {{cwd}}. Never call codegraph_* tools without passing projectPath = {{cwd}} (the absolute path of your working directory). If {{cwd}} has no .codegraph index, fall back to glob/grep/read directly and do not loop or comment on project mismatches.
441
441
 
@@ -467,7 +467,7 @@ main_agent_display_name: 庖丁 # 仅 preset 显示名换成「庖丁」,per
467
467
 
468
468
  面板流程(左侧栏「庖丁配置」→「Agent 工具分配」→ 底部「新建自定义 agent 角色」):
469
469
 
470
- 1. 新建角色:输入 `toolName`,须匹配 `/^[a-z][a-z0-9_]*$/`;
470
+ 1. 新建角色:输入 `toolName`,须匹配 `/^[a-z][a-z0-9_-]{1,31}$/`(2–32 位:首字符小写字母,其余为小写字母 / 数字 / 下划线 / 连字符;安装器侧另拒保留名、`mcp__` 前缀与 YAML 字面量);
471
471
  2. 从工具池多选工具(工具池 = 三角色静态 allow ∪ 检测到的 MCP / 插件工具);
472
472
  3. 写 persona(可给完整 persona,首行写成一句简短职责);
473
473
  4. 点「保存并应用」——生成器自动把新 `toolName` 注入主 agent 的 `orchestrator-restrict config.allow` —— **`restrict.mjs` 文件本身不用改**;并把分配持久化到配置文件(`roles` 键下多一项)。
@@ -616,7 +616,7 @@ workspaces:
616
616
  ### 9.2 预设命名规则
617
617
 
618
618
  - **slug** 取工作区目录名:小写、非法字符归并为 `-`;归并后为空、或恰好叫 `orchestrator`(与全局预设撞名)时改用 `ws`。
619
- - 多个工作区目录同名时,自动追加路径哈希(sha1 前 6 位)后缀,如同为 `Shop` 的两个项目得到 `orchestrator-shop-acd95b` 与 `orchestrator-shop-34b6aa`——改名或挪动目录后重新应用即可,旧预设目录不会被自动清理,不再需要的可在 DSH 预设页删除。
619
+ - 多个工作区目录同名时,自动追加路径哈希(sha1 前 6 位)后缀,如同为 `Shop` 的两个项目得到 `orchestrator-shop-acd95b` 与 `orchestrator-shop-34b6aa`——改名或挪动目录后重新应用即可。旧路径条目仍留在配置 `workspaces` 段时,旧预设目录暂被保留;条目移除后,下一次任何成功应用会自动回收该孤儿预设(rmSync + 告警可见),无需手动删。
620
620
  - 预设显示名:条目配了 `main_agent_display_name` 就用它;没配则在默认名后缀「·目录名」(如 `编排模式 (Orchestrator)·Shop`),预设列表里一眼可辨。
621
621
 
622
622
  ### 9.3 面板用法
@@ -28,7 +28,7 @@ Fallback-CLI precedence: an explicit `--profile` overrides the `profile` key in
28
28
 
29
29
  ### 1.2 Top-level keys
30
30
 
31
- The key names below match `normalizeConfig` in `tools/install.mjs` — the single authoritative source of the config file schema.
31
+ The key names below match `normalizeConfig` in `tools/lib/config.mjs` — the single authoritative source of the config file schema (`tools/install.mjs` only re-exports it).
32
32
 
33
33
  | Top-level key | Type | Semantics |
34
34
  |---|---|---|
@@ -55,14 +55,14 @@ The key names below match `normalizeConfig` in `tools/install.mjs` — the singl
55
55
  - Keys under `roles` outside the built-in trio are **custom roles** (section 6). Do not put the static role `search_internal_deep` under `roles` (see 2.2).
56
56
  - Built-in roles can be **deleted wholesale**: the `roles_remove` key accepts only the trio's names — deletion effect, consistency with the `roles` key, and the restore paths are in 2.3.
57
57
 
58
- When `main_agent_extra` is absent or empty it falls back to the smart defaults of the current run (detected codegraph / `memory_search` tools land on the main agent) — which is why, with no configuration at all, the main agent can still call the codegraph tools directly.
58
+ When the `main_agent_extra` **key is missing** (older configs / never written) it falls back to the smart defaults of the current run (detected codegraph / `memory_search` tools land on the main agent); an **explicit `main_agent_extra: []` means "no host tools, deliberately" and no longer falls back** — the base template written by a fresh first install is exactly this explicit `main_agent_extra: []` form and carries no host tools at all (codegraph and friends become usable only after being opted in via config or the panel).
59
59
 
60
60
  ### 1.3 Complete minimal example
61
61
 
62
62
  A config file covering all commonly used keys (the key order matches `serializeConfig`, which is what the panel writes):
63
63
 
64
64
  ```yaml
65
- # dsh-paoding installation config — hand-editable; after editing, apply in Settings → 庖丁配置 (Paoding Config), or re-run node tools/install.mjs --auto.
65
+ # dsh-paoding installation config — hand-editable; after editing, apply via the 庖丁配置 (Paoding Config) entry at the sidebar bottom, or re-run node tools/install.mjs --auto.
66
66
 
67
67
  profile: web # scan profiles/<profile>/cordis.patch.yml during detection
68
68
 
@@ -84,7 +84,7 @@ roles: # toolName -> { persona?, tools[] }
84
84
  design: # change the persona only; empty tools = keep the static allow
85
85
  persona: |-
86
86
  You are the design agent. Produce UI/UX designs and specs; never implement final code.
87
- code-reviewer: # custom role (toolName matches /^[a-z][a-z0-9_]*$/)
87
+ code-reviewer: # custom role (toolName matches /^[a-z][a-z0-9_-]{1,31}$/)
88
88
  persona: |-
89
89
  You are the code-reviewer agent. Review diffs and files for bugs, security
90
90
  issues and style regressions; report a prioritized list with file:line.
@@ -191,7 +191,7 @@ roles_remove:
191
191
  - design # the delegation-design block is no longer generated; the design bullet in the main-agent persona goes too
192
192
  ```
193
193
 
194
- Relationship with the `roles` key: `roles` keeps the entries of built-in roles that are **not** deleted (override their persona / tools there as usual). The full "deleted" state is: `roles_remove` contains the name **and** `roles` has no such key — the UI / CLI keeps these consistent; keep them consistent when hand-writing too. On conflict, generation follows `roles_remove`.
194
+ Relationship with the `roles` key: `roles` keeps the entries of built-in roles that are **not** deleted (override their persona / tools there as usual). The full "deleted" state is: `roles_remove` contains the name **and** `roles` has no such key — the panel (and the fallback CLI) keeps these consistent; keep them consistent when hand-writing too. On conflict, generation follows `roles_remove`.
195
195
 
196
196
  Restoring:
197
197
 
@@ -309,9 +309,9 @@ main_agent_extra:
309
309
 
310
310
  Points:
311
311
 
312
- - The entries land in the generated `orchestrator-restrict config.allow`. Injection follows the same whitelist: a name must belong to the **preset's own tool face** (the `restrict.mjs` main-agent allow ∪ the static role allows in the source preset) or to the **detection inventory**, and host tools (`mcp__*`, plugin tools like `mnemon_*`) go by what was actually detected — undetected names (MCP/plugin disabled, typo) are silently not injected, and the removed list in Preview shows the reason.
312
+ - The entries land in the generated `orchestrator-restrict config.allow`. Injection follows the same whitelist: a name must belong to the **preset's own tool face** (the `restrict.mjs` main-agent allow ∪ the static role allows in the source preset) or to the **detection inventory**, and host tools (`mcp__*`, plugin tools like `mnemon_*`) go by what was actually detected — undetected names (MCP/plugin disabled, typo) are silently not injected. Note that the removed list in Preview only covers the **role allow** reconciliation; names dropped from `main_agent_extra` are only counted in the fallback CLI output summary, with no per-name detail (read the final main-agent allow in the preview for details).
313
313
  - The concrete MCP / plugin tools checkable on the panel's "main agent" card are those shown by the detection results (the tool pool).
314
- - When `main_agent_extra` is absent or empty the generator falls back to smart defaults (detected codegraph / `memory_search` tools are suggested for the main agent).
314
+ - When the `main_agent_extra` **key is missing** the generator falls back to smart defaults (detected codegraph / `memory_search` tools are suggested for the main agent); an explicit `main_agent_extra: []` means no host tools, deliberately, with no fallback (the fresh-install base template is exactly this form).
315
315
 
316
316
  ### 3.3 Removing base tools: main_agent_remove
317
317
 
@@ -431,11 +431,11 @@ Where to set it:
431
431
  | Explicit `''` | **Append nothing** (not even the default rule) |
432
432
  | Any other text | **Overrides** the default with your text |
433
433
 
434
- Serialization: `''` is written out explicitly as `main_agent_persona_extra: ''` (distinct from an absent key); multi-line text is written as a `|-` block scalar. `normalizeConfig` in `tools/install.mjs` accepts only strings (a non-string or an absent key normalizes to `null`).
434
+ Serialization: `''` is written out explicitly as `main_agent_persona_extra: ''` (distinct from an absent key); multi-line text is written as a `|-` block scalar. `normalizeConfig` in `tools/lib/config.mjs` accepts only strings (a non-string or an absent key normalizes to `null`).
435
435
 
436
436
  ### 5.3 The default constant, verbatim
437
437
 
438
- The single source of truth is `DEFAULT_MAIN_AGENT_PERSONA_EXTRA` in `tools/install.mjs`; `presets/orchestrator/agent.cordis.yml` no longer embeds the line. The default value, verbatim:
438
+ The single source of truth is `DEFAULT_MAIN_AGENT_PERSONA_EXTRA` in `tools/lib/util.mjs` (`tools/install.mjs` only re-exports it); `presets/orchestrator/agent.cordis.yml` no longer embeds the line. The default value, verbatim:
439
439
 
440
440
  > Codegraph MCP default project may be a DIFFERENT repository than {{cwd}}. Never call codegraph_* tools without passing projectPath = {{cwd}} (the absolute path of your working directory). If {{cwd}} has no .codegraph index, fall back to glob/grep/read directly and do not loop or comment on project mismatches.
441
441
 
@@ -473,7 +473,7 @@ main agent's only routing hint for the role, so make the persona's first line a
473
473
 
474
474
  The panel flow (庖丁配置 in the left sidebar → agent tool assignment → "Create a custom agent role" at the bottom):
475
475
 
476
- 1. Create a role: enter a `toolName` matching `/^[a-z][a-z0-9_]*$/`;
476
+ 1. Create a role: enter a `toolName` matching `/^[a-z][a-z0-9_-]{1,31}$/` (2–32 chars: a lowercase letter first, then lowercase letters / digits / underscores / hyphens; the installer additionally rejects reserved names, the `mcp__` prefix and YAML literals);
477
477
  2. Multi-select tools from the tool pool (the trio's static allows ∪ detected MCP / plugin tools);
478
478
  3. Write a persona (a full persona is accepted; make the first line a short duty sentence);
479
479
  4. Hit Save & Apply — the generator automatically injects the new `toolName` into the main agent's `orchestrator-restrict config.allow` — **`restrict.mjs` itself is never touched** — and persists the assignment to the config file (a new entry under the `roles` key).
@@ -626,7 +626,7 @@ workspaces:
626
626
  ### 9.2 Preset naming
627
627
 
628
628
  - The **slug** comes from the workspace directory's basename: lowercased, invalid characters collapsed to `-`; if that yields an empty string or exactly `orchestrator` (colliding with the global preset), `ws` is used instead.
629
- - When multiple workspaces share a basename, a path-hash suffix (first 6 hex chars of sha1) is appended — two projects both named `Shop` become `orchestrator-shop-acd95b` and `orchestrator-shop-34b6aa`. Rename or move the directory and re-apply; stale preset directories are not cleaned automatically — remove the ones you no longer want on the DSH presets page.
629
+ - When multiple workspaces share a basename, a path-hash suffix (first 6 hex chars of sha1) is appended — two projects both named `Shop` become `orchestrator-shop-acd95b` and `orchestrator-shop-34b6aa`. Rename or move the directory and re-apply. While the old-path entry remains in the config's `workspaces` section, the stale preset directory is kept; once the entry is removed, the next successful apply automatically recycles the orphan preset (rmSync + a visible warning) — no manual deletion needed.
630
630
  - Preset display name: the entry's `main_agent_display_name` if set; otherwise the default name gets the `·<basename>` suffix (e.g. `编排模式 (Orchestrator)·Shop`) so entries are distinguishable at a glance in the roster.
631
631
 
632
632
  ### 9.3 Using the panel
package/docs/images/1.png CHANGED
Binary file