preload-panel · diff
git:20260923.cff2db6 to git:20260923.d016376
11 added, 19 removed. Audit A to A.
---
name: preload-panel
description: >
在 DSH 会话中热加载 ascend-sleuth 面板插件:先查 panel_from_file 工具在不在(它按进程
全局注册,通常已在;DSH 重启后第一次才需装 dsh-plugins/loader/panel-from-file.js——
- host-only 免审批的小加载器,两种装法见正文),再用它按路径加载
+ host-only 免审批的小加载器),再用它按路径加载
dsh-plugins/<panel>/ 下的 panel-host.js 与
panel-client.js——**只发两个路径,不转写 ~70KB 源码**,最后 cordis_run 激活,
对话视图出现对应 tab。面板选择:
- ascend-panel →「诊断」「指标」两个 tab(诊断会话/轨迹/证据 + **指标闭环判决**:首屏列要处理的判据、容量逐格、不可解读标记)
- ev-panel →「自演进」tab(演进体检判决 / 触及面 / 执行现场 / EV 卡决策链)
仅 DSH 可用——依赖 DSH 的 cordis_define / cordis_run 工具
与 conversation.view 插槽;其他 agent(Claude Code / Codex / pi)无此机制。
---
# Preload Panel
DSH 会话中加载可视化面板(诊断 / 指标 / 自演进)。每个面板是独立动态插件,各占
conversation.view 一个 tab(list 插槽,按 order 排列,可共存)。
## 触发
用户需要面板但当前会话没有对应 tab 时,用本 skill 加载。
## 面板清单
| 面板 | 目录 | tab id / label | 视图 |
|---|---|---|---|
| 诊断面板 | `dsh-plugins/ascend-panel/` | `ascend-diagnose`(20) / `ascend-metrics`(21) | 会话列表/轨迹/证据 + 指标闭环判决(判据→结论/证据/下一步)/容量逐格/趋势 |
| 自演进看板 | `dsh-plugins/ev-panel/` | `ascend-evolve`(22) | 首屏是**体检判决**(要处理的判据 + 下一步动作)与**触及面**(这批改动落在机器的哪一层);卡收在默认收起的抽屉里作为 diff 日志(决策链全文按需拉取) |
## 依赖预检(激活前跑,避免面板加载后白屏/报错)
面板 host 已做优雅退化(自演进 JSON 不截断、无 traces/ 显示空态、缺 pyyaml 给提示),
但 loader 在激活前跑一次预检,能把"依赖缺失"改成**主动告知**而不是面板里一条报错:
- **通用**:确认会话工作区是 ascend-sleuth 仓库(Host 从 `session.header.cwd` 解析数据目录)。
- **ev-panel(自演进)**:确认 Python 3 + PyYAML 可用——面板 host 会自动探测解释器
(`python3` → `python` → `py -3`,取第一个能打印 Python 3.x 的;Windows 上 `python3` 常不存在),
预检照探测结果来:
```bash
python3 -c "import yaml; print('pyyaml ok')" # 失败 → 试 python / py -3;再失败 → pip install pyyaml
```
若失败,先告知用户"自演进看板需要 PyYAML,请 `pip install pyyaml`",再决定是否仍加载
(host 也会给同样提示,但 loader 提前讲更友好)。
- **ascend-panel(诊断)**:`traces/` 可能不存在(gitignored、按需生成)——host 已把
"目录不存在"当空态处理,无需预建;但如果用户预期有历史诊断却显示为空,提示
"运行 /skill:diagnose 后生成 traces/"。指标 tab 需要 Python 3 + **PyYAML**:
「闭环判决」跑 `scripts/metrics_health.py --json`(判据读 `metrics/gates.yaml`),
「实时计算」跑 `scripts/trace_metrics.py`;缺依赖时面板会显示「体检不可用」并给出
安装/路径提示,**不会**假装闭环正常——所以预检失败仍可加载,只是首屏没有判决条。
## 流程
0. **先查有没有**:跑一次 `cordis_inspect_self`(不带参数)——它一次给出两件事:
本会话已加载的插件清单,以及(对照工具目录)`panel_from_file` 在不在。该工具是
**进程全局**的(一次注册后同一 DSH 进程的所有会话都能直接调),所以"工具不在"只在
DSH 重启后的第一个会话出现;本会话已有面板插件时也可顺手确认 tab id 没撞。
1. **确定要加载的面板**:用户要诊断可视化 → ascend-panel;要自演进状态(EV 卡/
容量/归因)→ ev-panel;两者可同时加载(不同 tab id,互不冲突)。
2. **确保 `panel_from_file` 工具可用**:
- 已有(第 0 步查到 `panel_from_file`)→ 跳到第 3 步。
- - 没有(DSH 刚重启、本进程还没注册过)→ 加载 loader,**按 `cordis_define` 的能力二选一**:
-
- | 你的 `cordis_define` | 怎么发 loader 源码 |
- |---|---|
- | 有 `codeFile` | `codeFile.host: 'dsh-plugins/loader/panel-from-file.js'`(不要再 `read` 一遍) |
- | 只有 `code`(官方发布版) | `read` 该文件全文 → `code.host` 原样粘贴 |
-
- 判法:`cordis_define` 的**参数表**里有没有 `codeFile`;不确定就直接按 `codeFile` 发一次,
- 报"参数不认识 / 缺 code"就换 `read` + `code.host`。**别为此重试第三次**。
+ - 没有(DSH 刚重启、本进程还没注册过)→ 装 loader:
+ 1. `read dsh-plugins/loader/panel-from-file.js`(全文)
+ 2. `cordis_define`:kind: new,idPrefix `ldr`,`code.host` ← 刚读到的全文
+ 3. `cordis_run`(mode: run)——**host-only 包,免审批**
- 两条路都走同一个 loader:`cordis_define`(kind: new,idPrefix `ldr`)→
- `cordis_run`(mode: run)。**host-only 包,免审批**。
- 该 loader 只用 `harness.registerTool` + `ctx.get('dynamicCordisRunner')` 两个
- 公开机制,不依赖任何 DSH 补丁——所以两条路都能装上;差别只是 `read` 那一步的
- 一次重复读入,跑起来完全一样。
+ loader 只用 `harness.registerTool` + `ctx.get('dynamicCordisRunner')` 两个公开机制,
+ 不依赖任何 DSH 补丁,所以在带 Cordis 工具的 DSH 版本上都能装。
+ **若本机 `cordis_define` 的参数表里有 `codeFile`**,可以省掉第 1 步、直接
+ `codeFile.host` 指该文件路径(本机检出有这个参数,官方发布版没有——
+ 所以默认走 `read` + `code.host`,两条路装出来的 loader 完全相同)。
3. **加载面板**:调 `panel_from_file`(不要用 `cordis_define` 转写源码):
```
panel_from_file(
host: dsh-plugins/<面板>/panel-host.js,
client: dsh-plugins/<面板>/panel-client.js,
idPrefix: ascend-panel 用 sleu / ev-panel 用 evbd,
name, purpose)
```
它读盘 → `dynamicCordisRunner.define()` → `run()`,源码**原样进不可变 Package**
(可被 `cordis_inspect_self` 审计),审批流与 `cordis_run` 一致。返回
awaiting-approval 时告知用户在 UI 允许(Client 半需授权);授权后 tab 出现。
面板两个文件合计 ~70KB——**别把全文重新输出一遍**,发路径即可。
**加载期间不要做的事**:`cordis_inspect_query(Tool.listTools)` 与
`Slots.listSubTree` 都不是加载面板的必需品,别顺手自查(前者一次回 53KB 的工具全表,
后者只在核 tab 时看一次)。
4. **验证**:确认插件 running 且无 waitingFor(`cordis_inspect_self`);tab 出现在
对话视图(conversation.view 插槽,按上表 id 核对)。自演进看板首次打开会调
`scripts/ev_board_data.py` 汇总数据——确认数据区渲染(EV 卡/容量有真实数据,
归因/S2 反馈可能显示"数据积累中",如实)。若见"数据加载失败",按顶部
「依赖预检」逐条排查(pyyaml / traces / 工作区)。
## 回退(DSH 版本差异)
- - **`cordis_define` 不带 `codeFile`**(官方发布版都没有它;带它的是本机检出)→ 见第 2 步
- 的两行表:`read` loader 全文 → `code.host` 原样粘贴即可,功能完全相同。
- **先试 `codeFile`,报参数错再退回内联。**
- - **loader 也注册不了工具**(`harness.registerTool` 缺失)→ 内联面板本身:读两个文件
+ - **loader 注册不了工具**(`harness.registerTool` 缺失)→ 内联面板本身:读两个文件
全文 → `code.host` / `code.client` 原样粘贴。文件是函数体形态
(`return { apply(ctx) {...} }`),别改形态——动态插件不经过打包器,
`export default` / `import` 等 ESM 语法无法加载。
- **改完面板代码**:`panel_from_file` 传 `pluginId` + `mode: 'update'` 追加新 Package
再切换(读入的是定义时快照,改文件不会自动生效)。
## 交互原则
**跨 session**:工具 `panel_from_file` 是**进程全局**的——新 session 不必再加载
loader,直接就有它可用;重复加载 loader 会撞名但不报错(工具仍可用),只有要更新 loader
自身代码时才需重启 DSH。面板插件则是 **per-session** 的:新 session 认领不了旧 session
的插件(DSH 的 `define(kind:'existing')` 要求同 session 拥有),所以会新建一个同 tab id 的
插件——新 tab 覆盖旧 tab 的显示,旧插件仍在跑(RPC 还在、仍读它自己 session 的工作目录)。
彻底清理需重启 DSH,或在各 session 内对自己的插件 `cordis_stop`。
**重复加载 = 重载(幂等)**:面板代码改了就再调一次同一条 `panel_from_file`——
同 `idPrefix` 会复用本 session 的已有插件并切到新 Package(返回 `reused: true`),
不会堆出重复 tab;无需手工传 `pluginId`/`mode`。跨 session(DSH 重启)会新建同 tab id
的插件覆盖显示。
面板是**只读可视化 + 指令生成器**——展示状态、生成续接/沉淀指令供用户触发,
面板自身不做决策与写入(唯一例外:诊断面板的沉淀状态标记由用户在面板确认后
更新)。自演进看板纯只读:展示 EV 卡状态与演进信号,产卡/验证走 agent + 攒批。
## 依赖
- DSH 会话(`cordis_define` / `cordis_run` / `cordis_inspect_self` 工具;loader 额外用
`harness.registerTool` + `ctx.get('dynamicCordisRunner')`——DSH 内置机制,无需补丁)
- 工作区为 ascend-sleuth 仓库(Host 从 session.header.cwd 解析数据目录)
- Host 服务:`fs` / `sessions` / `shell`
- **ev-panel(自演进)**:Python 3 + **PyYAML**——两个脚本:`scripts/ev_board_data.py`(卡库/触及面/现场聚合)
与 `scripts/evolution_health.py --json`(体检判决,判据在 `proposals/gates.yaml`)。判决是一次独立调用:
它失败时面板**不渲染结论条**(不拿卡数冒充"没有越界"),其余区块照常。
host 自动探测解释器(`python3` → `python` → `py -3`);缺 pyyaml 时 host 会提示安装;
loader 侧建议激活前预检(见「依赖预检」)。
- **ascend-panel(指标)**:`shell` + Python 3 + PyYAML——
「闭环判决」跑 `scripts/metrics_health.py --json`、「实时计算」跑 `scripts/trace_metrics.py`;
解释器同样自动探测(`python3` → `python` → `py -3`)。缺依赖时判决条退化为
「体检不可用」+ 可执行提示(不是空面板、也不谎报正常)。
- 诊断「打开证据 / 打开报告」按方言阶梯探测:Windows 先试 `Start-Process`,再 `open`、`xdg-open`、
`explorer.exe`,按退出码判定并回报用了哪一路(Windows 走 `ctx.shell` 实际接的是 PowerShell,
不是 bash——bash 链在那边整条命令解析失败,表现为"点了没反应")。四种都不行时界面给原因。
- 「看报告」不需要外部程序:报告正文由 host 只读读入后在面板内渲染(章节跳转 + 复制全文),
「打开文件」才依赖上面的阶梯。
## 说明
- 动态插件定义只存在于当前 DSH 进程,重启后需重新加载(本 skill 即为此设计)。
- 仓库内 `dsh-plugins/<面板>/` 是代码的权威版本(含 README 使用说明);
`dsh-plugins/loader/` 是加载入口的一次性加载器;本 skill 负责串起两者——
改代码走仓库,加载走这里。