@max-null/dsh-node-appearance 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,10 +8,11 @@ This plugin belongs to the **`@max-null/*` family** — a set of plugins that to
8
8
 
9
9
  ## 功能
10
10
 
11
- - **节点着色**:工具调用、联网搜索、智能体调用、代码 / 指令执行、文件操作、任务 / 目标、指令节点(`/command`)、思考行(Think)——每种类别一个可配置颜色,左侧 3px 色条 + 淡色底,深 / 浅主题均可读。
11
+ - **节点着色**:工具调用、联网搜索、智能体调用、代码 / 指令执行、文件操作、交付文件、任务 / 目标、指令节点(`/command`)、思考行(Think)——每种类别一个可配置颜色,左侧 3px 色条 + 淡色底,深 / 浅主题均可读。
12
12
  - **工具级颜色覆盖**:任意工具名(如 `web_search`、`subagent`、`run_code`)可单独指定颜色,优先级高于类别色。
13
13
  - **提问卡片**:`ask_user_question` 的卡片改为展示**当时给出的全部选项**,被选中的选项用 `ask` 类别色(默认蓝)反显并打勾。官方转录卡只保留已选答案,提问一旦结算就再也看不到其他选项 —— 本插件把选项读回来。
14
14
  - **目标条详情**:官方目标条下方接一条**与它拼成同一张卡**的详情行(借待办卡片的折叠形态),把官方条上被 ellipsis 截断的目标展开成可读详情:完整目标、阶段、阻塞原因、自主轮次、目标标识。只读投影,不碰官方的编辑/暂停/清除,那四个按钮仍是官方在跑。
15
+ - **交付文件行**:`present` 的行改为折叠态只报「首个文件名 + 数量」,展开后逐文件成行(扩展名徽标 + 文件名 + 所在目录),并在结果文本上方标注行数。官方折叠行把全部文件名逗号拼成一行(`fileNames()` 的 `.join(', ')`),多文件时读不完,也看不出这一轮交付了几个。配色单列 `deliver` 类别(默认青蓝 `#06b6d4`)——本轮生成文件的那些行与交付行常常同屏出现,与 `file`(`read`/`write`)共用绿色会分不清谁是谁。
15
16
  - **思考过程显示开关**:关闭后 Think 思考行前端隐藏(`display: none`),配置项与配色在同一张设置卡片里。
16
17
  - **即时生效**:设置改动立即重绘会话,并持久化到 DSH 用户设置文档(`$DSH_HOME/settings.yaml`)。
17
18
 
@@ -19,12 +20,20 @@ This plugin belongs to the **`@max-null/*` family** — a set of plugins that to
19
20
 
20
21
  | 会话节点着色 | 设置卡片 |
21
22
  |---|---|
22
- | ![会话节点着色](docs/shots/会话面板截图.png) | ![设置卡片](docs/shots/设置页截图.png) |
23
+ | ![会话节点着色](docs/shots/会话面板截图.png) | ![设置卡片](docs/shots/设置卡片.png) |
23
24
 
24
25
  | 提问卡片 | 目标条(折叠 / 展开) |
25
26
  |---|---|
26
27
  | ![提问卡片](docs/shots/提问卡片截图.png) | ![目标条折叠](docs/shots/目标详情-折叠.png) ![目标条展开](docs/shots/目标详情-展开.png) |
27
28
 
29
+ | 交付文件行(折叠) |
30
+ |---|
31
+ | ![交付行折叠](docs/shots/交付行-折叠.png) |
32
+
33
+ | 交付文件行(展开 · 青=交付、绿=写入) |
34
+ |---|
35
+ | ![交付行展开](docs/shots/交付行-展开.png) |
36
+
28
37
  ## 安装
29
38
 
30
39
  ```sh
@@ -54,6 +63,7 @@ node-appearance:
54
63
  agent: '#a855f7' # 智能体调用
55
64
  execute: '#f59e0b' # 代码 / 指令执行
56
65
  file: '#22c55e' # 文件操作
66
+ deliver: '#06b6d4' # 交付文件(present 行)
57
67
  task: '#ec4899' # 任务 / 目标
58
68
  ask: '#65a30d' # 提问卡片
59
69
  command: '#f97316' # 指令节点
@@ -71,6 +81,7 @@ node-appearance:
71
81
  - Browser half 绑定 `ctx.settingsScope`,把快照交给纯函数 `buildCss()` 生成 CSS,注入一个 `<style data-plugin-css="node-appearance/rules">` 标签;快照变化即重绘。
72
82
  - 着色目标全部使用 DSH 会话 DOM 的稳定 data 属性(`data-chat-flow-kind` / `data-tool` / `data-variant`),不依赖任何 CSS Modules 哈希类名。
73
83
  - 提问卡片是**接管**而非样式覆盖:`tool.call.toolview` 是 keyed slot,同一 key 只有最低 priority 的注册会渲染(DSH 的 slot 契约原话是 "a key the shipped composition already covers is replaced, not shared"),插件以 `priority: -1` 注册自己的 `ask_user_question` 视图,从调用参数里读回官方丢弃的 `options`。行外壳(24px 折叠行、running 扫光、Inspect 胶囊)与官方 `ToolRow` 逐项对齐,组件复用共享的 `ui-primitives`,locale 文案复用官方 `conversation` 字典。
84
+ - 交付文件行同样是**接管**:官方 ui-deliverables 在 `tool.call.toolview` 的 `present` key 上有一条 priority 0 的注册,插件以同样的 `priority: -1` 遮蔽它。字段取用面照官方 `PresentRow`(结算前读 `block.argsRaw`、结算后读 `block.call.argsRaw`,半截 JSON 原样显示参数文本而不是当成零个文件),行外壳与提问卡同一套基线,locale 文案复用官方 `deliverables` 字典(`row.title` / `row.ok` / `row.inspect` …)。派生逻辑在纯函数 `deliverable-model.ts` 里,组件只做 JSX。
74
85
  - 目标详情折叠条是**并列追加**而非接管:`conversation.input.dock` 是 list 槽(官方占 `todo` order 0 / `goal` order 10 / `queue` order 20),插件以 `order: 11` 紧随官方目标条追加自己的条目,只读 `useProjection('goal')`。官方的 edit/pause/resume/clear 是 ui-goal 的注册者私有注入面(四个 Remote 动词 + 一个带竞态防护的 activation 订阅源),接管它们等于在本插件里再养一套会写会话数据的 RPC 客户端。
75
86
 
76
87
  ## 已知限制
@@ -78,6 +89,8 @@ node-appearance:
78
89
  - v0.1 不做运行态动画与节点折叠。
79
90
  - 提问卡是接管式实现:组件来自共享 `ui-primitives`、业务字段只读调用与结果的 JSON,但官方 `ask_user_question` 的行外壳若变更,插件需同步。
80
91
  - 提问卡高度随内容自适应、不做卡片内滚动;选项极多时由整条会话流承担滚动。
92
+ - 交付行同为接管式实现:官方 `present` 的字段取用面若变更,插件需同步。
93
+ - 交付行的折叠摘要(「… 等 N 个文件」)与展开区的「输出 N 行」是插件自有文案:官方 `deliverables` 字典没有对应 key,与目标详情条直写中文同一取径。
81
94
  - 命令节点只有类别色(`command`),暂无命令名级配色。
82
95
  - `toolColors` 按工具名精确匹配;DSH 工具名变更时旧条目静默失效(可在设置面板删除)。
83
96
 
@@ -86,7 +99,7 @@ node-appearance:
86
99
  ```sh
87
100
  npm install
88
101
  npm run typecheck # tsc
89
- npm test # vitest(CSS 规则生成 + Config schema + 提问卡派生)
102
+ npm test # vitest(CSS 规则生成 + Config schema + 提问卡派生 + 交付行派生)
90
103
  npm run build # tsc 类型 + tsdown(lib/index.js + lib/client.js)
91
104
  ```
92
105
 
package/lib/client.js CHANGED
@@ -25,6 +25,7 @@ window.__ModuleLoader__.load({
25
25
  agent: "#a855f7",
26
26
  execute: "#f59e0b",
27
27
  file: "#22c55e",
28
+ deliver: "#06b6d4",
28
29
  task: "#ec4899",
29
30
  ask: "#65a30d",
30
31
  command: "#f97316",
@@ -66,6 +67,7 @@ window.__ModuleLoader__.load({
66
67
  "glob",
67
68
  "grep"
68
69
  ],
70
+ deliver: ["present"],
69
71
  task: [
70
72
  "todo_write",
71
73
  "create_goal",
@@ -194,45 +196,45 @@ window.__ModuleLoader__.load({
194
196
  }
195
197
  //#endregion
196
198
  //#region \0dsh-css:H:\MaxNull\WorkStation\max-null-plugins\dsh-node-appearance\src\client\card.module.css.mjs
197
- const css$2 = ".CDqThG_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.CDqThG_card:hover{border-color:var(--dsw-alias-label-dimmed)}.CDqThG_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.CDqThG_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.CDqThG_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.CDqThG_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.CDqThG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.CDqThG_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.CDqThG_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.CDqThG_chevronOpen{transform:rotate(180deg)}.CDqThG_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.CDqThG_readOnly,.CDqThG_statusLine{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.CDqThG_disabled{opacity:.55;pointer-events:none}.CDqThG_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:16px 0 4px;display:flex}.CDqThG_reset{appearance:none;border:1px solid var(--dsw-alias-border-l2);font:inherit;cursor:pointer;color:var(--dsw-alias-label-secondary);background:0 0;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.CDqThG_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.CDqThG_resetConfirm{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.CDqThG_reset:disabled{opacity:.4;cursor:default}.CDqThG_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.CDqThG_row{border-top:1px solid var(--dsw-alias-border-l2);align-items:center;gap:10px;margin-top:10px;padding:10px 0 4px;display:flex;position:relative}.CDqThG_row:first-child{border-top:none;margin-top:4px}.CDqThG_rowLabel{min-width:0;color:var(--dsw-alias-label-primary);flex-direction:column;flex:1;gap:2px;font-size:13px;font-weight:500;line-height:1.5;display:flex}.CDqThG_rowHint{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:1.5}.CDqThG_colorInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);cursor:pointer;border-radius:8px;flex:none;width:34px;height:28px;padding:2px}.CDqThG_colorValue{width:64px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:12px;line-height:1.5}.CDqThG_sectionTitle{color:var(--dsw-alias-label-primary);margin:14px 0 0;font-size:13px;font-weight:600;line-height:1.5}.CDqThG_toolName{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;line-height:1.5;overflow:hidden}.CDqThG_removeButton{appearance:none;border:1px solid var(--dsw-alias-border-l2);font:inherit;cursor:pointer;color:var(--dsw-alias-label-secondary);background:0 0;border-radius:8px;flex:none;padding:3px 10px;font-size:12px;line-height:1.5}.CDqThG_removeButton:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.CDqThG_addRow{align-items:center;gap:8px;margin-top:10px;margin-bottom:12px;display:flex}.CDqThG_toolInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);min-width:0;height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 12px;font-size:13px;line-height:1.5}.CDqThG_toolInput:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.CDqThG_toolInput::placeholder{color:var(--dsw-alias-label-tertiary)}.CDqThG_addButton{appearance:none;font:inherit;cursor:pointer;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3);border:1px solid #0000;border-radius:8px;flex:none;padding:5px 14px;font-size:13px;line-height:1.5}.CDqThG_addButton:disabled{opacity:.4;cursor:default}.CDqThG_switch{cursor:pointer;background:var(--dsw-alias-border-l4,#00000029);border:none;border-radius:11px;flex:none;width:40px;height:22px;padding:0;transition:background .15s}.CDqThG_switch.CDqThG_on{background:var(--dsw-alias-state-business-primary,#4fc3f7)}.CDqThG_knob{pointer-events:none;background:#fff;border-radius:8px;width:16px;height:16px;margin-left:2px;transition:margin-left .15s;display:block}.CDqThG_switch.CDqThG_on .CDqThG_knob{margin-left:22px}";
198
- const tagId$2 = "@max-null/dsh-node-appearance/card.module.css";
199
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
199
+ const css$3 = ".CDqThG_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.CDqThG_card:hover{border-color:var(--dsw-alias-label-dimmed)}.CDqThG_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.CDqThG_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.CDqThG_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.CDqThG_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.CDqThG_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.CDqThG_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.CDqThG_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.CDqThG_chevronOpen{transform:rotate(180deg)}.CDqThG_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.CDqThG_readOnly,.CDqThG_statusLine{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.CDqThG_disabled{opacity:.55;pointer-events:none}.CDqThG_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:16px 0 4px;display:flex}.CDqThG_reset{appearance:none;border:1px solid var(--dsw-alias-border-l2);font:inherit;cursor:pointer;color:var(--dsw-alias-label-secondary);background:0 0;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.CDqThG_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.CDqThG_resetConfirm{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.CDqThG_reset:disabled{opacity:.4;cursor:default}.CDqThG_reset:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.CDqThG_row{border-top:1px solid var(--dsw-alias-border-l2);align-items:center;gap:10px;margin-top:10px;padding:10px 0 4px;display:flex;position:relative}.CDqThG_row:first-child{border-top:none;margin-top:4px}.CDqThG_rowLabel{min-width:0;color:var(--dsw-alias-label-primary);flex-direction:column;flex:1;gap:2px;font-size:13px;font-weight:500;line-height:1.5;display:flex}.CDqThG_rowHint{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:1.5}.CDqThG_colorInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);cursor:pointer;border-radius:8px;flex:none;width:34px;height:28px;padding:2px}.CDqThG_colorValue{width:64px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:12px;line-height:1.5}.CDqThG_sectionTitle{color:var(--dsw-alias-label-primary);margin:14px 0 0;font-size:13px;font-weight:600;line-height:1.5}.CDqThG_toolName{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;line-height:1.5;overflow:hidden}.CDqThG_removeButton{appearance:none;border:1px solid var(--dsw-alias-border-l2);font:inherit;cursor:pointer;color:var(--dsw-alias-label-secondary);background:0 0;border-radius:8px;flex:none;padding:3px 10px;font-size:12px;line-height:1.5}.CDqThG_removeButton:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.CDqThG_addRow{align-items:center;gap:8px;margin-top:10px;margin-bottom:12px;display:flex}.CDqThG_toolInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);min-width:0;height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 12px;font-size:13px;line-height:1.5}.CDqThG_toolInput:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.CDqThG_toolInput::placeholder{color:var(--dsw-alias-label-tertiary)}.CDqThG_addButton{appearance:none;font:inherit;cursor:pointer;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3);border:1px solid #0000;border-radius:8px;flex:none;padding:5px 14px;font-size:13px;line-height:1.5}.CDqThG_addButton:disabled{opacity:.4;cursor:default}.CDqThG_switch{cursor:pointer;background:var(--dsw-alias-border-l4,#00000029);border:none;border-radius:11px;flex:none;width:40px;height:22px;padding:0;transition:background .15s}.CDqThG_switch.CDqThG_on{background:var(--dsw-alias-state-business-primary,#4fc3f7)}.CDqThG_knob{pointer-events:none;background:#fff;border-radius:8px;width:16px;height:16px;margin-left:2px;transition:margin-left .15s;display:block}.CDqThG_switch.CDqThG_on .CDqThG_knob{margin-left:22px}";
200
+ const tagId$3 = "@max-null/dsh-node-appearance/card.module.css";
201
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
200
202
  const tag = document.createElement("style");
201
203
  tag.dataset.plugin = "@max-null/dsh-node-appearance";
202
- tag.dataset.pluginCss = tagId$2;
203
- tag.textContent = css$2;
204
+ tag.dataset.pluginCss = tagId$3;
205
+ tag.textContent = css$3;
204
206
  document.head.appendChild(tag);
205
207
  }
206
208
  var card_module_css_default = {
207
- "resetConfirm": "CDqThG_resetConfirm",
208
- "body": "CDqThG_body",
209
- "statusLine": "CDqThG_statusLine",
210
- "header": "CDqThG_header",
211
- "cardOpen": "CDqThG_cardOpen",
212
- "switch": "CDqThG_switch",
213
- "rowHint": "CDqThG_rowHint",
214
209
  "toolInput": "CDqThG_toolInput",
215
- "headText": "CDqThG_headText",
216
- "addButton": "CDqThG_addButton",
217
- "disabled": "CDqThG_disabled",
218
- "chevronOpen": "CDqThG_chevronOpen",
219
- "row": "CDqThG_row",
220
210
  "knob": "CDqThG_knob",
221
- "chevron": "CDqThG_chevron",
222
- "colorInput": "CDqThG_colorInput",
223
- "name": "CDqThG_name",
211
+ "disabled": "CDqThG_disabled",
212
+ "header": "CDqThG_header",
213
+ "headText": "CDqThG_headText",
214
+ "colorValue": "CDqThG_colorValue",
215
+ "rowHint": "CDqThG_rowHint",
224
216
  "sectionTitle": "CDqThG_sectionTitle",
217
+ "rowLabel": "CDqThG_rowLabel",
218
+ "switch": "CDqThG_switch",
219
+ "chevron": "CDqThG_chevron",
220
+ "readOnly": "CDqThG_readOnly",
225
221
  "description": "CDqThG_description",
226
- "addRow": "CDqThG_addRow",
227
- "removeButton": "CDqThG_removeButton",
228
- "card": "CDqThG_card",
229
- "footer": "CDqThG_footer",
230
222
  "on": "CDqThG_on",
231
- "readOnly": "CDqThG_readOnly",
223
+ "toolName": "CDqThG_toolName",
232
224
  "reset": "CDqThG_reset",
233
- "rowLabel": "CDqThG_rowLabel",
234
- "colorValue": "CDqThG_colorValue",
235
- "toolName": "CDqThG_toolName"
225
+ "resetConfirm": "CDqThG_resetConfirm",
226
+ "body": "CDqThG_body",
227
+ "addRow": "CDqThG_addRow",
228
+ "addButton": "CDqThG_addButton",
229
+ "cardOpen": "CDqThG_cardOpen",
230
+ "statusLine": "CDqThG_statusLine",
231
+ "colorInput": "CDqThG_colorInput",
232
+ "card": "CDqThG_card",
233
+ "removeButton": "CDqThG_removeButton",
234
+ "name": "CDqThG_name",
235
+ "row": "CDqThG_row",
236
+ "chevronOpen": "CDqThG_chevronOpen",
237
+ "footer": "CDqThG_footer"
236
238
  };
237
239
  //#endregion
238
240
  //#region src/client/settings-card.tsx
@@ -255,6 +257,7 @@ window.__ModuleLoader__.load({
255
257
  agent: "智能体调用",
256
258
  execute: "代码 / 指令执行",
257
259
  file: "文件操作",
260
+ deliver: "交付文件",
258
261
  task: "任务 / 目标",
259
262
  ask: "提问卡片",
260
263
  command: "指令节点",
@@ -627,42 +630,42 @@ window.__ModuleLoader__.load({
627
630
  }
628
631
  //#endregion
629
632
  //#region \0dsh-css:H:\MaxNull\WorkStation\max-null-plugins\dsh-node-appearance\src\client\ask-card.module.css.mjs
630
- const css$1 = ".ylzLDa_root{--ask-accent:var(--ncolor-accent,#65a30d);flex-direction:column;display:flex}.ylzLDa_row{position:relative;overflow:hidden}.ylzLDa_root[data-state=running] .ylzLDa_row:after{content:\"\";background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite ylzLDa_ask-row-sweep;position:absolute;top:0;bottom:0;left:0}@keyframes ylzLDa_ask-row-sweep{0%{left:-300px}90%,to{left:100%}}.ylzLDa_leading{flex-shrink:0}.ylzLDa_chevron{color:var(--dsw-alias-label-secondary)}.ylzLDa_title{font-weight:400}.ylzLDa_sep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.ylzLDa_summary{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:auto;overflow:hidden}.ylzLDa_bodyWrap{flex-direction:column;display:flex}.ylzLDa_card{border:1px solid color-mix(in srgb, var(--ask-accent) 34%, transparent);background:color-mix(in srgb, var(--ask-accent) 6%, var(--dsw-alias-bg-base));border-radius:12px;flex-direction:column;gap:14px;margin:4px 0 4px 4px;padding:14px 16px;display:flex}.ylzLDa_item{flex-direction:column;gap:8px;min-width:0;display:flex}.ylzLDa_header{color:var(--ask-accent);font-size:var(--dsh-content-font-size-secondary,13px);font-weight:500;line-height:calc(20px + var(--dsh-content-font-delta,0px))}.ylzLDa_question{color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:pre-wrap;overflow-wrap:anywhere}.ylzLDa_detail{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta,0px));white-space:pre-wrap;overflow-wrap:anywhere}.ylzLDa_verdict{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta,0px));margin:0}.ylzLDa_options{flex-direction:column;gap:6px;display:flex}.ylzLDa_option{border:1px solid var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));border-radius:8px;align-items:flex-start;gap:8px;padding:9px 12px;display:flex}.ylzLDa_option[data-chosen]{border-color:var(--ask-accent);background:color-mix(in srgb, var(--ask-accent) 14%, transparent);color:var(--ask-accent);font-weight:500}.ylzLDa_marker{width:16px;height:calc(22px + var(--dsh-content-font-delta,0px));flex:none;justify-content:center;align-items:center;display:inline-flex}.ylzLDa_optionText{flex-direction:column;gap:2px;min-width:0;display:flex}.ylzLDa_label{overflow-wrap:anywhere}.ylzLDa_desc{color:inherit;opacity:.72;font-size:var(--dsh-content-font-size-secondary,13px);font-weight:400;line-height:calc(20px + var(--dsh-content-font-delta,0px));overflow-wrap:anywhere}.ylzLDa_answers{flex-direction:column;gap:2px;display:flex}.ylzLDa_answerLine{color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:pre-wrap;overflow-wrap:anywhere}.ylzLDa_answersEmpty{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px))}.ylzLDa_fallback{white-space:pre-wrap;overflow-wrap:anywhere;font:var(--dsw-font-xs-13);color:var(--dsw-alias-label-tertiary);margin:4px 0 4px 4px}.ylzLDa_inspectButton{border:.5px solid var(--dsw-alias-border-l3);corner-shape:round;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;border-radius:999px;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;font-size:11px;line-height:16px;transition:opacity .1s;display:inline-flex}.ylzLDa_root:hover .ylzLDa_inspectButton,.ylzLDa_inspectButton:focus-visible{opacity:1}.ylzLDa_inspectButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}";
631
- const tagId$1 = "@max-null/dsh-node-appearance/ask-card.module.css";
632
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
633
+ const css$2 = ".ylzLDa_root{--ask-accent:var(--ncolor-accent,#65a30d);flex-direction:column;display:flex}.ylzLDa_row{position:relative;overflow:hidden}.ylzLDa_root[data-state=running] .ylzLDa_row:after{content:\"\";background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite ylzLDa_ask-row-sweep;position:absolute;top:0;bottom:0;left:0}@keyframes ylzLDa_ask-row-sweep{0%{left:-300px}90%,to{left:100%}}.ylzLDa_leading{flex-shrink:0}.ylzLDa_chevron{color:var(--dsw-alias-label-secondary)}.ylzLDa_title{font-weight:400}.ylzLDa_sep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.ylzLDa_summary{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:auto;overflow:hidden}.ylzLDa_bodyWrap{flex-direction:column;display:flex}.ylzLDa_card{border:1px solid color-mix(in srgb, var(--ask-accent) 34%, transparent);background:color-mix(in srgb, var(--ask-accent) 6%, var(--dsw-alias-bg-base));border-radius:12px;flex-direction:column;gap:14px;margin:4px 0 4px 4px;padding:14px 16px;display:flex}.ylzLDa_item{flex-direction:column;gap:8px;min-width:0;display:flex}.ylzLDa_header{color:var(--ask-accent);font-size:var(--dsh-content-font-size-secondary,13px);font-weight:500;line-height:calc(20px + var(--dsh-content-font-delta,0px))}.ylzLDa_question{color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:pre-wrap;overflow-wrap:anywhere}.ylzLDa_detail{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta,0px));white-space:pre-wrap;overflow-wrap:anywhere}.ylzLDa_verdict{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta,0px));margin:0}.ylzLDa_options{flex-direction:column;gap:6px;display:flex}.ylzLDa_option{border:1px solid var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));border-radius:8px;align-items:flex-start;gap:8px;padding:9px 12px;display:flex}.ylzLDa_option[data-chosen]{border-color:var(--ask-accent);background:color-mix(in srgb, var(--ask-accent) 14%, transparent);color:var(--ask-accent);font-weight:500}.ylzLDa_marker{width:16px;height:calc(22px + var(--dsh-content-font-delta,0px));flex:none;justify-content:center;align-items:center;display:inline-flex}.ylzLDa_optionText{flex-direction:column;gap:2px;min-width:0;display:flex}.ylzLDa_label{overflow-wrap:anywhere}.ylzLDa_desc{color:inherit;opacity:.72;font-size:var(--dsh-content-font-size-secondary,13px);font-weight:400;line-height:calc(20px + var(--dsh-content-font-delta,0px));overflow-wrap:anywhere}.ylzLDa_answers{flex-direction:column;gap:2px;display:flex}.ylzLDa_answerLine{color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px));white-space:pre-wrap;overflow-wrap:anywhere}.ylzLDa_answersEmpty{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size,14px);line-height:calc(22px + var(--dsh-content-font-delta,0px))}.ylzLDa_fallback{white-space:pre-wrap;overflow-wrap:anywhere;font:var(--dsw-font-xs-13);color:var(--dsw-alias-label-tertiary);margin:4px 0 4px 4px}.ylzLDa_inspectButton{border:.5px solid var(--dsw-alias-border-l3);corner-shape:round;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;border-radius:999px;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;font-size:11px;line-height:16px;transition:opacity .1s;display:inline-flex}.ylzLDa_root:hover .ylzLDa_inspectButton,.ylzLDa_inspectButton:focus-visible{opacity:1}.ylzLDa_inspectButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}";
634
+ const tagId$2 = "@max-null/dsh-node-appearance/ask-card.module.css";
635
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
633
636
  const tag = document.createElement("style");
634
637
  tag.dataset.plugin = "@max-null/dsh-node-appearance";
635
- tag.dataset.pluginCss = tagId$1;
636
- tag.textContent = css$1;
638
+ tag.dataset.pluginCss = tagId$2;
639
+ tag.textContent = css$2;
637
640
  document.head.appendChild(tag);
638
641
  }
639
642
  var ask_card_module_css_default = {
640
- "chevron": "ylzLDa_chevron",
641
- "summary": "ylzLDa_summary",
642
- "detail": "ylzLDa_detail",
643
- "optionText": "ylzLDa_optionText",
644
- "answersEmpty": "ylzLDa_answersEmpty",
645
- "sep": "ylzLDa_sep",
646
- "inspectButton": "ylzLDa_inspectButton",
647
- "answers": "ylzLDa_answers",
648
- "answerLine": "ylzLDa_answerLine",
649
- "leading": "ylzLDa_leading",
650
- "title": "ylzLDa_title",
651
643
  "ask-row-sweep": "ylzLDa_ask-row-sweep",
644
+ "answers": "ylzLDa_answers",
645
+ "option": "ylzLDa_option",
652
646
  "root": "ylzLDa_root",
653
- "label": "ylzLDa_label",
654
647
  "bodyWrap": "ylzLDa_bodyWrap",
648
+ "answersEmpty": "ylzLDa_answersEmpty",
649
+ "label": "ylzLDa_label",
650
+ "header": "ylzLDa_header",
651
+ "question": "ylzLDa_question",
655
652
  "row": "ylzLDa_row",
653
+ "detail": "ylzLDa_detail",
656
654
  "verdict": "ylzLDa_verdict",
655
+ "chevron": "ylzLDa_chevron",
656
+ "options": "ylzLDa_options",
657
657
  "desc": "ylzLDa_desc",
658
+ "fallback": "ylzLDa_fallback",
659
+ "inspectButton": "ylzLDa_inspectButton",
658
660
  "card": "ylzLDa_card",
659
- "options": "ylzLDa_options",
660
- "option": "ylzLDa_option",
661
- "header": "ylzLDa_header",
662
- "item": "ylzLDa_item",
663
- "question": "ylzLDa_question",
661
+ "leading": "ylzLDa_leading",
664
662
  "marker": "ylzLDa_marker",
665
- "fallback": "ylzLDa_fallback"
663
+ "summary": "ylzLDa_summary",
664
+ "title": "ylzLDa_title",
665
+ "answerLine": "ylzLDa_answerLine",
666
+ "sep": "ylzLDa_sep",
667
+ "item": "ylzLDa_item",
668
+ "optionText": "ylzLDa_optionText"
666
669
  };
667
670
  //#endregion
668
671
  //#region src/client/ask-card.tsx
@@ -823,6 +826,253 @@ window.__ModuleLoader__.load({
823
826
  });
824
827
  }
825
828
  //#endregion
829
+ //#region src/client/deliverable-model.ts
830
+ /**
831
+ * 从参数 JSON 里取文件路径。
832
+ * 截断的 JSON(调用仍在流式输出)返回 null —— 与官方一致:那时原样显示参数
833
+ * 文本,而不是当成「零个文件」。
834
+ * @param raw - 参数 JSON 原文。
835
+ * @returns 路径数组;JSON 未成形时为 null。
836
+ */
837
+ function parsePaths(raw) {
838
+ let args;
839
+ try {
840
+ args = JSON.parse(raw);
841
+ } catch {
842
+ return null;
843
+ }
844
+ if (typeof args !== "object" || args === null || !("files" in args)) return null;
845
+ const files = args.files;
846
+ if (!Array.isArray(files)) return null;
847
+ return files.flatMap((file) => {
848
+ if (typeof file !== "object" || file === null || !("path" in file)) return [];
849
+ const path = file.path;
850
+ return typeof path === "string" ? [path] : [];
851
+ });
852
+ }
853
+ /** 最后一个路径分隔符的下标;没有分隔符时为 -1。 */
854
+ function separatorAt(path) {
855
+ return Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
856
+ }
857
+ /** 扩展名徽标:最后一个点之后的部分,过长截断;无扩展名返回 null。 */
858
+ function extensionBadge(name) {
859
+ const dot = name.lastIndexOf(".");
860
+ if (dot <= 0 || dot === name.length - 1) return null;
861
+ const ext = name.slice(dot + 1);
862
+ return (ext.length <= 4 ? ext : ext.slice(0, 4)).toUpperCase();
863
+ }
864
+ /** 拆一行:路径 → 文件名 + 所在目录 + 扩展名徽标。 */
865
+ function fileOf(path) {
866
+ const cut = separatorAt(path);
867
+ const name = cut === -1 ? path : path.slice(cut + 1);
868
+ return {
869
+ path,
870
+ name,
871
+ dir: cut === -1 ? "" : path.slice(0, cut),
872
+ badge: extensionBadge(name)
873
+ };
874
+ }
875
+ /**
876
+ * 折叠态摘要。
877
+ * `paths === null` 表示参数 JSON 未成形,此时按官方做法原样显示参数文本;解析
878
+ * 成功但一个路径都没取到时返回空串,不把 `{"files":[]}` 这种原文当摘要抛出去。
879
+ */
880
+ function summaryOf(paths, fallback) {
881
+ if (paths === null) return fallback;
882
+ const first = paths[0];
883
+ if (first === void 0) return "";
884
+ const name = fileOf(first).name;
885
+ return paths.length === 1 ? name : `${name} 等 ${String(paths.length)} 个文件`;
886
+ }
887
+ /** 结果文本:把结果节点拼成一段;未结算时没有结果。 */
888
+ function outputOf(settled, block) {
889
+ if (!settled) return "";
890
+ return (block.content ?? []).map((item) => item.type === "text" ? item.text ?? "" : JSON.stringify(item)).join("\n");
891
+ }
892
+ /** 错误描述:没有结果文本时的兜底,比整行空白有用。 */
893
+ function errorTextOf(error) {
894
+ if (error === void 0) return "";
895
+ const name = error.name ?? "error";
896
+ return error.code === void 0 ? name : `${name}: ${error.code}`;
897
+ }
898
+ /**
899
+ * 派生一次交付的全部渲染数据。
900
+ * @param block - 工具调用/结果块。
901
+ * @returns 状态、折叠摘要、逐文件数据与结果文本。
902
+ */
903
+ function deliverableModel(block) {
904
+ const settled = "kind" in block;
905
+ const state = !settled ? "running" : block.error?.code === "interrupted" ? "stopped" : block.isError === true ? "error" : "ok";
906
+ const args = (settled ? block.call?.argsRaw : block.argsRaw) ?? "";
907
+ const output = outputOf(settled, block);
908
+ const details = output !== "" ? output : settled ? errorTextOf(block.error) : "";
909
+ const paths = parsePaths(args);
910
+ const files = paths?.map(fileOf) ?? [];
911
+ return {
912
+ state,
913
+ summary: summaryOf(paths, args),
914
+ files,
915
+ details,
916
+ lineCount: details === "" ? 0 : details.split("\n").length,
917
+ expandable: files.length > 0 || details !== ""
918
+ };
919
+ }
920
+ //#endregion
921
+ //#region \0dsh-css:H:\MaxNull\WorkStation\max-null-plugins\dsh-node-appearance\src\client\deliverable-row.module.css.mjs
922
+ const css$1 = "._8xFzxq_root{--deliverable-accent:var(--ncolor-accent,#06b6d4);flex-direction:column;display:flex}._8xFzxq_row{position:relative;overflow:hidden}._8xFzxq_root[data-state=running] ._8xFzxq_row:after{content:\"\";background:linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--dsw-alias-bg-base) 60%, transparent) 55%, transparent 100%);pointer-events:none;width:300px;animation:2.6s ease-out infinite _8xFzxq_deliverable-row-sweep;position:absolute;top:0;bottom:0;left:0}@keyframes _8xFzxq_deliverable-row-sweep{0%{left:-300px}90%,to{left:100%}}._8xFzxq_leading{flex-shrink:0}._8xFzxq_chevron{color:var(--dsw-alias-label-secondary)}._8xFzxq_title{font-weight:400}._8xFzxq_sep{background:var(--dsw-alias-label-caption);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}._8xFzxq_summary{min-width:0;font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(24px + var(--dsh-content-font-delta,0px));color:var(--dsw-alias-label-tertiary);flex:auto;align-items:center;gap:8px;display:flex;overflow:hidden}._8xFzxq_state{color:var(--dsw-alias-label-secondary);flex:none}._8xFzxq_paths{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}._8xFzxq_bodyWrap{flex-direction:column;padding:2px 0 2px 4px;display:flex}._8xFzxq_files{flex-direction:column;gap:4px;margin:4px 0 0;padding:0;list-style:none;display:flex}._8xFzxq_file{align-items:center;gap:8px;min-width:0;display:flex}._8xFzxq_ext{box-sizing:border-box;background:color-mix(in srgb, var(--deliverable-accent) 14%, transparent);width:38px;color:var(--deliverable-accent);letter-spacing:.04em;text-align:center;border-radius:4px;flex:none;padding:1px 4px;font-size:10px;font-weight:600;line-height:16px}._8xFzxq_name{color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size,14px);line-height:calc(20px + var(--dsh-content-font-delta,0px));overflow-wrap:anywhere;flex:none}._8xFzxq_path{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta,0px));flex:auto;overflow:hidden}._8xFzxq_meta{color:var(--dsw-alias-label-tertiary);font-size:var(--dsh-content-font-size-secondary,13px);line-height:calc(20px + var(--dsh-content-font-delta,0px));margin-top:10px}._8xFzxq_output{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:8px 0 0;padding:12px;font-size:12px}._8xFzxq_inspectButton{border:.5px solid var(--dsw-alias-border-l3);corner-shape:round;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;border-radius:999px;align-self:flex-start;align-items:center;gap:4px;margin:8px 0 2px;padding:2px 8px;font-size:11px;line-height:16px;transition:opacity .1s;display:inline-flex}._8xFzxq_root:hover ._8xFzxq_inspectButton,._8xFzxq_inspectButton:focus-visible{opacity:1}._8xFzxq_inspectButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}";
923
+ const tagId$1 = "@max-null/dsh-node-appearance/deliverable-row.module.css";
924
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
925
+ const tag = document.createElement("style");
926
+ tag.dataset.plugin = "@max-null/dsh-node-appearance";
927
+ tag.dataset.pluginCss = tagId$1;
928
+ tag.textContent = css$1;
929
+ document.head.appendChild(tag);
930
+ }
931
+ var deliverable_row_module_css_default = {
932
+ "name": "_8xFzxq_name",
933
+ "title": "_8xFzxq_title",
934
+ "state": "_8xFzxq_state",
935
+ "row": "_8xFzxq_row",
936
+ "chevron": "_8xFzxq_chevron",
937
+ "output": "_8xFzxq_output",
938
+ "deliverable-row-sweep": "_8xFzxq_deliverable-row-sweep",
939
+ "leading": "_8xFzxq_leading",
940
+ "path": "_8xFzxq_path",
941
+ "meta": "_8xFzxq_meta",
942
+ "paths": "_8xFzxq_paths",
943
+ "summary": "_8xFzxq_summary",
944
+ "bodyWrap": "_8xFzxq_bodyWrap",
945
+ "root": "_8xFzxq_root",
946
+ "files": "_8xFzxq_files",
947
+ "file": "_8xFzxq_file",
948
+ "ext": "_8xFzxq_ext",
949
+ "sep": "_8xFzxq_sep",
950
+ "inspectButton": "_8xFzxq_inspectButton"
951
+ };
952
+ //#endregion
953
+ //#region src/client/deliverable-row.tsx
954
+ /**
955
+ * 交付行:接管 `present` 的工具行。
956
+ *
957
+ * 官方 PresentRow 是一个 45 行的折叠行:状态点 + 「交付文件」标题 + **逗号拼接
958
+ * 的文件名** + 可展开的结果文本 + inspect 入口。多文件时那串文件名会挤成一行
959
+ * 读不完,也看不出这一轮交付了几个。
960
+ *
961
+ * 本组件保留官方全部信息与交互(四态、状态词、文件名、结果文本、inspect,以及
962
+ * `data-tool="present"` / `data-state` 这两个样式与快照测试的锚点),另加三件:
963
+ * ① 折叠态文件名只报「首个 + 数量」,多文件不再挤成一行;
964
+ * ② 展开态逐文件成行,带扩展名徽标与所在目录;
965
+ * ③ 结果文本标注行数。
966
+ *
967
+ * 全部派生在 deliverable-model.ts 里,本文件只做 JSX。
968
+ *
969
+ * 接管是 DSH 支持的机制(keyed slot 用不同 priority 遮蔽既有占用者,见
970
+ * ui-slots 的 `register()`;官方插件开发 skill:registering an existing key
971
+ * may replace the product's default card)。代价是本文件要自己承担官方行的
972
+ * 折叠外观 —— 因此行外壳逐项对齐 ToolRow.module.css 与同插件的提问卡
973
+ * (24px 行高、2px 分隔点、13px 次级摘要、running 扫光、hover 才现的
974
+ * Inspect 胶囊),组件全部来自共享 ui-primitives。
975
+ *
976
+ * 下载卡片与「打开」菜单不在这里:它们属于 `conversation.chat.turnTail` 槽的
977
+ * Deliverables 网格,与本 toolview 是两个不同的槽,接管互不影响。
978
+ */
979
+ /** 状态点的外观名,四态映射与官方 PresentRow 一致。 */
980
+ const DOT = {
981
+ running: "ongoing",
982
+ ok: "done",
983
+ stopped: "warning",
984
+ error: "error"
985
+ };
986
+ /** 逐文件一行:扩展名徽标 + 文件名 + 所在目录(完整路径挂在 title 上)。 */
987
+ function FileLine({ file }) {
988
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
989
+ className: deliverable_row_module_css_default.file,
990
+ children: [
991
+ file.badge !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
992
+ className: deliverable_row_module_css_default.ext,
993
+ "aria-hidden": true,
994
+ children: file.badge
995
+ }),
996
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
997
+ className: deliverable_row_module_css_default.name,
998
+ children: file.name
999
+ }),
1000
+ file.dir !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1001
+ className: deliverable_row_module_css_default.path,
1002
+ title: file.path,
1003
+ children: file.dir
1004
+ })
1005
+ ]
1006
+ });
1007
+ }
1008
+ /**
1009
+ * 渲染一次交付的完整记录。
1010
+ * @param props - locale 翻译函数、调用/结果切片与可选的轨迹入口。
1011
+ * @returns 折叠行 + 展开后的文件清单与结果文本。
1012
+ */
1013
+ function DeliverableRow({ t, block, inspect }) {
1014
+ const model = deliverableModel(block);
1015
+ const [expanded, setExpanded] = (0, react.useState)(false);
1016
+ const open = expanded && model.expandable;
1017
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1018
+ className: deliverable_row_module_css_default.root,
1019
+ "data-variant": "others",
1020
+ "data-tool": "present",
1021
+ "data-state": model.state,
1022
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
1023
+ rowClassName: deliverable_row_module_css_default.row,
1024
+ leadingClassName: deliverable_row_module_css_default.leading,
1025
+ titleClassName: deliverable_row_module_css_default.title,
1026
+ chevronClassName: deliverable_row_module_css_default.chevron,
1027
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: DOT[model.state] }),
1028
+ title: t("row.title"),
1029
+ open,
1030
+ expandable: model.expandable,
1031
+ expandOnRowClick: true,
1032
+ keepContentWhenOpen: true,
1033
+ onToggle: () => {
1034
+ setExpanded((value) => !value);
1035
+ },
1036
+ collapsedContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1037
+ className: deliverable_row_module_css_default.sep,
1038
+ "aria-hidden": true
1039
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1040
+ className: deliverable_row_module_css_default.summary,
1041
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1042
+ className: deliverable_row_module_css_default.state,
1043
+ children: t(`row.${model.state}`)
1044
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1045
+ className: deliverable_row_module_css_default.paths,
1046
+ children: model.summary
1047
+ })]
1048
+ })] }),
1049
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1050
+ className: deliverable_row_module_css_default.bodyWrap,
1051
+ children: [
1052
+ model.files.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
1053
+ className: deliverable_row_module_css_default.files,
1054
+ "aria-label": t("presented.all", { count: model.files.length }),
1055
+ children: model.files.map((file, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FileLine, { file }, `${String(index)}-${file.path}`))
1056
+ }),
1057
+ model.details !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [model.files.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1058
+ className: deliverable_row_module_css_default.meta,
1059
+ children: `输出 ${String(model.lineCount)} 行`
1060
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
1061
+ className: deliverable_row_module_css_default.output,
1062
+ children: model.details
1063
+ })] }),
1064
+ inspect !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1065
+ type: "button",
1066
+ className: deliverable_row_module_css_default.inspectButton,
1067
+ onClick: inspect,
1068
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconInspectOutline12, {}), t("row.inspect")]
1069
+ })
1070
+ ]
1071
+ })
1072
+ })
1073
+ });
1074
+ }
1075
+ //#endregion
826
1076
  //#region \0dsh-css:H:\MaxNull\WorkStation\max-null-plugins\dsh-node-appearance\src\client\goal-detail.module.css.mjs
827
1077
  const css = ".WyWU3a_root{box-sizing:border-box;width:calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));max-width:calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-tip);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-top-color:#0000;border-radius:0 0 12px 12px;flex:none;margin:-6px auto 0;overflow:hidden}[data-goal-bar]>div:first-child{border-bottom-color:#0000;border-bottom-right-radius:0;border-bottom-left-radius:0}.WyWU3a_body{flex-direction:column;gap:8px;padding:6px 12px;display:flex}.WyWU3a_header{text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:10px;width:100%;padding:0;display:flex}.WyWU3a_lead{color:var(--dsw-alias-label-tertiary);flex:none;place-items:center;display:grid}.WyWU3a_title{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:24px}.WyWU3a_summary{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:auto;font-size:13px;line-height:20px;overflow:hidden}.WyWU3a_chevron{color:var(--dsw-alias-label-tertiary);flex:none;place-items:center;display:grid}.WyWU3a_detail{flex-direction:column;gap:6px;max-height:180px;margin:0;display:flex;overflow-y:auto}.WyWU3a_row{grid-template-columns:max-content 1fr;align-items:baseline;column-gap:10px;margin:0;display:grid}.WyWU3a_key{color:var(--dsw-alias-label-caption);font-size:13px;line-height:20px}.WyWU3a_value{min-width:0;color:var(--dsw-alias-label-secondary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.WyWU3a_code{font-family:var(--ds-font-family-code);color:var(--dsw-alias-label-caption);font-size:11px}.WyWU3a_value>.WyWU3a_code:not(:first-child){margin-left:8px}";
828
1078
  const tagId = "@max-null/dsh-node-appearance/goal-detail.module.css";
@@ -834,18 +1084,18 @@ window.__ModuleLoader__.load({
834
1084
  document.head.appendChild(tag);
835
1085
  }
836
1086
  var goal_detail_module_css_default = {
837
- "header": "WyWU3a_header",
838
- "summary": "WyWU3a_summary",
839
- "row": "WyWU3a_row",
1087
+ "root": "WyWU3a_root",
840
1088
  "lead": "WyWU3a_lead",
841
- "value": "WyWU3a_value",
842
1089
  "chevron": "WyWU3a_chevron",
843
1090
  "key": "WyWU3a_key",
844
- "detail": "WyWU3a_detail",
845
- "code": "WyWU3a_code",
846
- "root": "WyWU3a_root",
847
1091
  "body": "WyWU3a_body",
848
- "title": "WyWU3a_title"
1092
+ "title": "WyWU3a_title",
1093
+ "header": "WyWU3a_header",
1094
+ "summary": "WyWU3a_summary",
1095
+ "value": "WyWU3a_value",
1096
+ "row": "WyWU3a_row",
1097
+ "code": "WyWU3a_code",
1098
+ "detail": "WyWU3a_detail"
849
1099
  };
850
1100
  //#endregion
851
1101
  //#region src/client/goal-detail.tsx
@@ -1038,6 +1288,12 @@ window.__ModuleLoader__.load({
1038
1288
  priority: -1,
1039
1289
  locale: "conversation"
1040
1290
  }, AskQuestionRow));
1291
+ ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
1292
+ name: "tool.call.toolview",
1293
+ key: "present",
1294
+ priority: -1,
1295
+ locale: "deliverables"
1296
+ }, DeliverableRow));
1041
1297
  ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
1042
1298
  name: "conversation.input.dock",
1043
1299
  id: "max-null/goal-detail",
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useState","css","IconChevronDownOutline14","css","IconCheckOutline14","useMemo","useState","StateDot","IconQuestionOutline14","DisclosureRow","IconInspectOutline12","css","useState","IconGoalOutline16","IconChevronUpOutline14","IconChevronDownOutline14"],"sources":["../src/client/palette.ts","../src/client/settings-card.tsx","../src/client/ask-model.ts","../src/client/ask-card.tsx","../src/client/goal-detail.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Node appearance palette: category/tool mapping, default colors, and the pure\n * CSS-rule generator that paints the chat flow. Browser-half owned; the Host\n * half mirrors the same defaults through its schemastery schema (the two\n * cannot share a value import — the browser bundle purity gate forbids\n * cross-package value imports).\n */\n\n/** The settings namespace this plugin owns (spelled identically in both halves). */\nexport const NODE_APPEARANCE_NS = 'node-appearance'\n\n/** The plugin's style tag identity (removed/replaced on every re-paint). */\nexport const STYLE_TAG_ID = `${NODE_APPEARANCE_NS}/rules`\n\n/** One paintable node category. `command`, `thinking`, `context` are non-tool rows. */\nexport type NodeCategory =\n | 'search' | 'agent' | 'execute' | 'file' | 'task' | 'ask' | 'command' | 'thinking' | 'context' | 'steering' | 'other'\n\n/** Accent color per category (CSS colors). */\nexport type NodeAppearanceColors = Record<NodeCategory, string>\n\n/** The settings value this plugin reads from its namespace scope. */\nexport interface NodeAppearanceSettings {\n /** Show assistant reasoning blocks as Think rows; false hides them. */\n showThinking?: boolean | undefined\n /** Per-category accent colors; missing keys fall back to defaults. */\n colors?: Partial<NodeAppearanceColors> | undefined\n /** Per-tool accent overrides keyed by wire tool name. */\n toolColors?: Record<string, string> | undefined\n}\n\n/** Initial palette: mid-luminance hues readable on both light and dark themes. */\nexport const DEFAULT_COLORS: NodeAppearanceColors = {\n search: '#3b82f6', // blue — web_search / web_fetch\n agent: '#a855f7', // purple — subagent / workflow / send_message …\n execute: '#f59e0b', // amber — bash / pwsh / run_code / terminal_*\n file: '#22c55e', // green — read / write / edit / glob / grep\n task: '#ec4899', // pink — todo_write / goal / job_* / schedule_*\n ask: '#65a30d', // lime — ask_user_question 提问卡(取作 --ask-accent;色相落在 execute 琥珀与 file 绿之间的空档,与 search 的蓝区分开)\n command: '#f97316', // orange — /command nodes\n thinking: '#c4b5fd', // light purple — Think rows\n context: '#8a9bb5', // slate blue — injected context rows (informational)\n steering: '#14b8a6', // teal — steering rows (rc.8)\n other: '#64748b', // slate — every unlisted tool\n}\n\n/** Wire tool name → category for the shipped mapping. */\nexport const TOOL_CATEGORIES: Record<Exclude<NodeCategory, 'command' | 'thinking' | 'context' | 'steering'>, readonly string[]> = {\n search: ['web_search', 'web_fetch'],\n agent: ['subagent', 'subagent_acp', 'subagent_fork', 'send_message', 'interrupt_agent', 'list_agents', 'report', 'workflow'],\n execute: ['bash', 'pwsh', 'run_code', 'terminal_open', 'terminal_close', 'terminal_list', 'terminal_read', 'terminal_send', 'terminal_signal', 'str_replace_editor'],\n file: ['read', 'write', 'edit', 'read_image', 'glob', 'grep'],\n task: ['todo_write', 'create_goal', 'get_goal', 'update_goal', 'job_kill', 'job_list', 'job_output', 'schedule_create', 'schedule_delete', 'schedule_list', 'exit_plan_mode'],\n ask: ['ask_user_question'],\n other: [],\n}\n\n/** Selector matching every tool row inside a tool-call node. */\nconst TOOL_ROW = '[data-chat-flow-kind=\"tool-call\"] [data-tool]'\n/** The ToolRow root itself (carries data-variant; the wrapper callRow does not). */\nconst TOOL_ROW_ROOT = '[data-chat-flow-kind=\"tool-call\"] [data-tool][data-variant]'\n/** Selector of the command node wrapper. */\nconst COMMAND_ROW = '[data-chat-flow-kind=\"command\"]'\n/** Selector of the Think reasoning row. */\nconst THINK_ROW = '[data-variant=\"think\"]'\n/** Selector of the injected-context row (the flow-item wrapper). */\nconst CONTEXT_ROW = '[data-chat-flow-kind=\"context\"]'\n/** Selector of a settled tool-result row (rc.8: tool results render as their own row). */\nconst TOOL_RESULT_ROW = '[data-chat-flow-kind=\"tool-result\"]'\n\n/**\n * The rows that carry the accent paint: the ToolRow root (not its wrapper\n * callRow — both carry data-tool, only the inner row carries data-variant),\n * command nodes, Think rows, injected-context rows, and tool-result rows.\n * User input rows are excluded — right-alignment already\n * distinguishes them (2026-08-20 用户反馈);steering rows 也走独立规则\n * (见 buildCss:在 userStack 层做 wash,不涂整行 rail)。\n * The 3px inset rail is compensated\n * with a matching padding-left so the rail never covers the row's leading icon.\n */\nconst ACCENTED_ROWS = [\n TOOL_ROW_ROOT, COMMAND_ROW, THINK_ROW, CONTEXT_ROW, TOOL_RESULT_ROW,\n].join(',\\n')\n\n/**\n * Accept a configured CSS color (hex, color functions) or reject it so an\n * invalid value falls back to the category default instead of poisoning CSS.\n * @param value - configured color string.\n * @returns whether the value is a plausible CSS color literal.\n */\nexport function isCssColor(value: string): boolean {\n const trimmed = value.trim()\n if (trimmed === '') return false\n if (/^#[0-9a-f]{3,8}$/i.test(trimmed)) return true\n return /^(rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color|device-cmyk)\\(/i.test(trimmed)\n}\n\n/** Resolve the effective palette from user settings merged over defaults. */\nexport function resolveColors(settings: NodeAppearanceSettings): NodeAppearanceColors {\n const colors: NodeAppearanceColors = { ...DEFAULT_COLORS }\n const configured = settings.colors\n if (configured !== undefined && typeof configured === 'object' && configured !== null) {\n for (const key of Object.keys(DEFAULT_COLORS) as NodeCategory[]) {\n const value = configured[key]\n if (typeof value === 'string' && isCssColor(value)) colors[key] = value\n }\n }\n return colors\n}\n\n/** Escape a tool name into a CSS attribute selector string literal. */\nfunction attributeLiteral(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n}\n\n/**\n * Steering marker icon: a corner-up-left arrow (mid-turn guidance inserted\n * into the running answer), drawn as a mask so the icon inherits the\n * configured steering color. Encoded data URI, no external asset.\n */\nconst STEERING_ICON = \"data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 14 4 9 9 4'/%3E%3Cpath d='M20 20v-7a4 4 0 0 0-4-4H4'/%3E%3C/svg%3E\"\n\n/**\n * Build the complete stylesheet text for one settings snapshot.\n * @param settings - the namespace scope value (may be partial or undefined).\n * @returns CSS text painting accent rows and (optionally) hiding Think rows.\n */\nexport function buildCss(settings: NodeAppearanceSettings | undefined): string {\n const colors = resolveColors(settings ?? {})\n const toolOverrides = settings?.toolColors\n const lines: string[] = []\n\n // Unlisted tools keep the neutral fallback. Declared BEFORE the per-tool\n // rules: both selectors carry equal specificity (two attribute selectors),\n // so of two conflicting declarations the later one wins — a fallback\n // declared after the category rules would override every category color.\n lines.push(`${TOOL_ROW} { --ncolor-accent: ${colors.other}; }`)\n\n // Per-tool accent assignments (explicit overrides win over category color).\n for (const [category, tools] of Object.entries(TOOL_CATEGORIES)) {\n const key = category as keyof typeof TOOL_CATEGORIES\n for (const tool of tools) {\n const override = toolOverrides?.[tool]\n const color = typeof override === 'string' && isCssColor(override)\n ? override\n : colors[key]\n lines.push(`[data-chat-flow-kind=\"tool-call\"] [data-tool=\"${attributeLiteral(tool)}\"] { --ncolor-accent: ${color}; }`)\n }\n }\n\n // Non-tool accent rows.\n lines.push(`${COMMAND_ROW} { --ncolor-accent: ${colors.command}; }`)\n lines.push(`${THINK_ROW} { --ncolor-accent: ${colors.thinking}; }`)\n lines.push(`${CONTEXT_ROW} { --ncolor-accent: ${colors.context}; }`)\n lines.push(`${TOOL_RESULT_ROW} { --ncolor-accent: ${colors.file}; }`)\n\n // One shared paint rule: 3px inset left rail (layout-free) + 8% wash. The\n // matching padding-left moves the row content off the rail so the leading\n // icon is never covered.\n lines.push(`${ACCENTED_ROWS} {\n box-shadow: inset 3px 0 0 var(--ncolor-accent);\n background-color: color-mix(in srgb, var(--ncolor-accent) 8%, transparent);\n padding-left: 3px;\n}`)\n\n // Steering rows (mid-turn user steering) stay visually distinct from plain\n // user rows with a compass marker beside the right-aligned bubble. The\n // marker is a mask over the user-stack — the container that hugs the bubble\n // — positioned to the left of it, so the tint reads as a glyph next to the\n // message rather than a detached full-width rail (2026-08-21 用户反馈:\n // 整行 rail 突兀,改在 userStack 层做图标区分;slot 方案不可行:\n // conversation.message.images 是 single 槽且已被官方 ui-attachment 占用).\n // alpha.2 锚点迁移(2026-08-31):消息行\"时间悬浮\"标识 data-time-hover-root\n // 已被 TurnTail/MessageItem 的 data-actions-reveal(always|hover)取代;\n // kind 与 首子=userStack 结构不变(ChatNodeSeat L206 / MessageItem L178 验证)。\n lines.push(`[data-chat-flow-kind=\"steering\"] [data-actions-reveal] > :first-child {\n position: relative;\n}`)\n lines.push(`[data-chat-flow-kind=\"steering\"] [data-actions-reveal] > :first-child::before {\n content: '';\n position: absolute;\n right: 100%;\n margin-right: 6px;\n top: 50%;\n width: 14px;\n height: 14px;\n transform: translateY(-50%);\n background-color: ${colors.steering};\n -webkit-mask: url(\"${STEERING_ICON}\") center / contain no-repeat;\n mask: url(\"${STEERING_ICON}\") center / contain no-repeat;\n}`)\n\n // Visibility switch: hide Think rows entirely on the frontend. `!important`\n // outranks the module stylesheet's `.root { display: flex }` (same\n // specificity, but the plugin style tag is injected before the module's).\n if (settings?.showThinking === false) {\n lines.push(`${THINK_ROW} { display: none !important; }`)\n // A think-only node leaves its flowItem seat with zero height: the seat\n // still consumes the column's 16px flex gap on both sides, doubling the\n // spacing between the neighbors. Hide the whole seat when the think row\n // is the only child of its block container — block-internal thinks\n // (text + reasoning in one node) stay gap-neutral after hiding the row.\n lines.push(\n `[data-chat-flow-kind=\"assistant\"]:has(${THINK_ROW}:only-child),`,\n `[data-chat-flow-kind=\"assistant-step\"]:has(${THINK_ROW}:only-child) { display: none !important; }`,\n )\n }\n\n return lines.join('\\n')\n}\n","/**\n * The node-appearance plugin config card. Mirrors the official\n * `settings.plugin.item` card chrome (PluginCard: card shell, name-over-\n * description header, chevron disclosure) with the DSH design tokens —\n * drawn by hand because a feature plugin must not runtime-import another\n * feature plugin's values (bundle purity gate).\n *\n * Writes are immediate: picking a color or flipping the Think switch applies\n * it right away (a palette is a live preview, not a staged form). The footer\n * carries one「恢复初始设置」button that resets the whole namespace to the\n * shipped defaults — two-click confirmation so a miss cannot wipe a custom\n * palette.\n */\n\nimport { useState, type ChangeEvent, type FormEvent } from 'react'\nimport type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store'\nimport type { SettingsScope, SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport {\n DEFAULT_COLORS, isCssColor, resolveColors, TOOL_CATEGORIES,\n type NodeAppearanceSettings, type NodeCategory,\n} from './palette.ts'\nimport css from './card.module.css'\n\n/** The card's inject face: the read-only scope snapshot plus write actions. */\nexport interface NodeAppearanceRowFace {\n hooks: {\n /** The bound settings-scope snapshot, rendered as useNodeAppearance. */\n nodeAppearance: ObservableSnapshot<SettingsScopeSnapshot<NodeAppearanceSettings>>\n }\n /** Persist one full value (reset-to-defaults path; resolves on Host settlement). */\n apply(value: NodeAppearanceSettings): Promise<void>\n /** Write the Think visibility switch. */\n setShowThinking(show: boolean): void\n /** Merge one category color into the palette section. */\n setCategoryColor(category: NodeCategory, color: string): void\n /** Merge one tool override into the toolColors section. */\n setToolColor(tool: string, color: string): void\n /** Remove one tool override. */\n removeToolColor(tool: string): void\n}\n\n/** Props the renderer binds for this plugin config card. */\nexport type NodeAppearanceRowProps =\n PropsRuntime<'settings.plugin.item'>\n & InjectFace<NodeAppearanceRowFace>\n\n/** Chinese labels per category (product copy is Chinese). */\nconst CATEGORY_LABELS: Record<NodeCategory, string> = {\n search: '联网搜索',\n agent: '智能体调用',\n execute: '代码 / 指令执行',\n file: '文件操作',\n task: '任务 / 目标',\n ask: '提问卡片',\n command: '指令节点',\n thinking: '思考过程',\n context: '上下文注入',\n steering: '模型引导',\n other: '其他工具',\n}\n\n/** Tools shown in the add-override autocomplete-free text input placeholder. */\nconst TOOL_SUGGESTIONS = Object.values(TOOL_CATEGORIES).flat().join('、')\n\n/** The card copy (one locale). */\nconst COPY = {\n title: '节点外观',\n description: '消息节点外观与颜色的偏好设置',\n reset: '恢复初始设置',\n resetConfirm: '再次点击确认恢复',\n resetting: '恢复中…',\n readOnly: '配置只读:插件主机侧未挂载或连接非本机。',\n loading: '配置加载中…',\n showThinking: '显示思考过程',\n showThinkingHint: '关闭后会话中的 Think 思考行隐藏',\n toolColors: '工具颜色覆盖(可选)',\n addTool: '添加',\n removeTool: '删除',\n}\n\n/** The shipped defaults, one face call away from any custom palette. */\nconst INITIAL_SETTINGS: NodeAppearanceSettings = {\n showThinking: true,\n colors: DEFAULT_COLORS,\n toolColors: {},\n}\n\n/**\n * Render the node-appearance config card.\n * @param props - the injected scope snapshot hook, its write actions.\n * @returns the card, matching the official plugin-card chrome.\n */\nexport function NodeAppearanceRow({ useNodeAppearance, apply, setShowThinking, setCategoryColor, setToolColor, removeToolColor }: NodeAppearanceRowProps) {\n const [open, setOpen] = useState(false)\n const [confirmReset, setConfirmReset] = useState(false)\n const [resetting, setResetting] = useState(false)\n const [toolName, setToolName] = useState('')\n const [toolColor, setToolColorDraft] = useState('#64748b')\n const snapshot = useNodeAppearance(snapshot => snapshot)\n const served = snapshot.value ?? {}\n const colors = resolveColors(served)\n const toolColors = served.toolColors ?? {}\n const showThinking = served.showThinking ?? true\n const disabled = snapshot.writable === false\n const unavailable = snapshot.status !== 'ready'\n\n const resetInitial = async (): Promise<void> => {\n if (resetting) return\n setResetting(true)\n try {\n await apply(INITIAL_SETTINGS)\n setConfirmReset(false)\n } catch {\n // A refused reset just leaves the current palette in place.\n } finally {\n setResetting(false)\n }\n }\n\n const handleReset = (): void => {\n if (confirmReset) {\n void resetInitial()\n } else {\n setConfirmReset(true)\n }\n }\n\n const addTool = (event: FormEvent): void => {\n event.preventDefault()\n const name = toolName.trim()\n if (name === '' || !isCssColor(toolColor)) return\n setToolColor(name, toolColor)\n setToolName('')\n }\n\n return (\n <li className={css.card + (open ? ' ' + css.cardOpen : '')}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${open ? '收起' : '展开'}:${COPY.title}`}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.headText}>\n <span className={css.name}>{COPY.title}</span>\n <span className={css.description}>{COPY.description}</span>\n </span>\n <IconChevronDownOutline14 className={css.chevron + (open ? ' ' + css.chevronOpen : '')} />\n </button>\n {open && (\n <div className={css.body}>\n {unavailable && !disabled && <p className={css.statusLine}>{COPY.loading}</p>}\n {disabled && <p className={css.readOnly} role=\"status\">{COPY.readOnly}</p>}\n <div className={disabled ? css.disabled : ''}>\n <div className={css.row}>\n <label className={css.rowLabel} htmlFor=\"node-appearance-show-thinking\">{COPY.showThinking}</label>\n <span className={css.rowHint}>{COPY.showThinkingHint}</span>\n <button\n id=\"node-appearance-show-thinking\"\n className={css.switch + (showThinking ? ' ' + css.on : '')}\n type=\"button\"\n aria-pressed={showThinking}\n onClick={() => { setShowThinking(!showThinking) }}\n >\n <span className={css.knob} />\n </button>\n </div>\n {(Object.keys(CATEGORY_LABELS) as NodeCategory[]).map(category => (\n <div className={css.row} key={category}>\n <label className={css.rowLabel} htmlFor={`node-appearance-color-${category}`}>{CATEGORY_LABELS[category]}</label>\n <input\n id={`node-appearance-color-${category}`}\n className={css.colorInput}\n type=\"color\"\n value={colors[category]}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setCategoryColor(category, event.target.value) }}\n />\n <span className={css.colorValue}>{colors[category]}</span>\n </div>\n ))}\n <div className={css.sectionTitle}>{COPY.toolColors}</div>\n {Object.entries(toolColors).map(([tool, color]) => (\n <div className={css.row} key={tool}>\n <span className={css.toolName} title={tool}>{tool}</span>\n <input\n className={css.colorInput}\n type=\"color\"\n value={isCssColor(color) ? color : DEFAULT_COLORS.other}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolColor(tool, event.target.value) }}\n />\n <button type=\"button\" className={css.removeButton} onClick={() => { removeToolColor(tool) }}>{COPY.removeTool}</button>\n </div>\n ))}\n <form className={css.addRow} onSubmit={addTool}>\n <input\n className={css.toolInput}\n type=\"text\"\n placeholder={`工具名,如 ${TOOL_SUGGESTIONS}`}\n value={toolName}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolName(event.target.value) }}\n />\n <input className={css.colorInput} type=\"color\" value={toolColor} onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolColorDraft(event.target.value) }} />\n <button type=\"submit\" className={css.addButton} disabled={toolName.trim() === ''}>{COPY.addTool}</button>\n </form>\n </div>\n <div className={css.footer}>\n <button\n type=\"button\"\n className={css.reset + (confirmReset ? ' ' + css.resetConfirm : '')}\n disabled={resetting}\n onClick={handleReset}\n >{resetting ? COPY.resetting : confirmReset ? COPY.resetConfirm : COPY.reset}</button>\n </div>\n </div>\n )}\n </li>\n )\n}\n","/**\n * 提问卡数据派生:把一次 `ask_user_question` 调用还原成「问题 + 全部选项 +\n * 实际选中项」。\n *\n * 为什么要自己解析:DSH 官方的转录卡只保留**已选答案**\n * (`ui-tool/src/client/tool/toolviews/ask-question-row.tsx` 的\n * `questionEntries()` 只取 `id`/`question`,把 `options` 丢掉了),所以提问\n * 结算后「当时还有哪些选项」在客户端管线上就没了。选项列表只存在于调用的\n * 参数 JSON 里 —— 这也是本插件接管 `ask_user_question` toolview 的唯一原因。\n *\n * 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错\n * (接管后卡片由我们渲染,渲染不出来就等于用户什么都看不到)。\n */\n\n/** 模型给出的一个可选项。 */\nexport interface AskOption {\n /** 选项文本;同时是被 `selected` 回传的那个值。 */\n label: string\n /** 选项下方的补充说明,模型没给时为空。 */\n description: string\n}\n\n/** 一个问题:全部选项 + 实际回答。 */\nexport interface AskQuestion {\n id: string\n question: string\n /** 可选的短标题(模型提供时显示在问题上方)。 */\n header: string\n /** 可选的补充说明。 */\n detail: string\n /** 模型是否允许多选。 */\n multiSelect: boolean\n /** 模型当时给出的全部选项;调用没带选项时为空数组。 */\n options: AskOption[]\n /** 被选中的选项文本,按回答记录的顺序。 */\n selected: string[]\n /** 直接输入的文本答案(没选选项或额外补充时)。 */\n custom: string\n}\n\n/** 行的运行状态,与通用工具行保持同一套词汇。 */\nexport type AskRowState = 'running' | 'ok' | 'error' | 'stopped'\n\n/** 问题集的结算程度。 */\nexport type AskPhase = 'pending' | 'answered' | 'unanswered'\n\n/** 卡片渲染所需的全部派生结果。 */\nexport interface AskCardModel {\n state: AskRowState\n phase: AskPhase\n /** 被取消或被中断时记录判定来源;正常结算为 undefined。 */\n verdict: 'cancelled' | 'aborted' | undefined\n questions: AskQuestion[]\n /** 至少选了选项或填了自定义答案的问题数(折叠行的 N/M 用)。 */\n answeredCount: number\n /**\n * 参数 JSON 解析不出来时用于兜底展示的结果文本;运行中或结果无文本时为\n * null。没有它,一次畸形调用会让接管后的行变成空白。\n */\n fallbackText: string | null\n}\n\n/**\n * `ask_user_question` 的 block 里本卡读到的字段子集。\n * 结构照 DSH 的 `ToolCallBlock`(运行中=调用自身,结算后=带 `kind` 的结果\n * 节点)声明为鸭子类型:跨插件只允许 type-only 引用,这里连类型引用都不需要。\n */\nexport interface AskToolBlock {\n /** 运行中的调用没有这个字段;结算后为 `'tool-result'`。 */\n kind?: string | undefined\n callId?: string | undefined\n /** 运行中形态:调用自身携带参数。 */\n argsRaw?: string | undefined\n /** 结算形态:调用头(子调用被剥掉时为 null)。 */\n call?: { argsRaw?: string | undefined } | null | undefined\n /** 结算形态:结果内容块。 */\n content?: readonly unknown[] | undefined\n error?: { code?: string | undefined } | undefined\n isError?: boolean | undefined\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** 读一个字符串字段,非字符串一律当空串。 */\nfunction text(value: unknown): string {\n return typeof value === 'string' ? value : ''\n}\n\nfunction parseJson(source: string): unknown {\n try {\n return JSON.parse(source)\n } catch {\n // 流式截断的半截 JSON 是正常现象:降级为「无问题」,由调用方兜底展示原文。\n return undefined\n }\n}\n\n/** 从结果内容块拼出展示文本(文本块原样、其余块转 JSON)。 */\nexport function resultTextOf(block: AskToolBlock): string | null {\n const content = block.content\n if (!Array.isArray(content) || content.length === 0) return null\n const parts: string[] = []\n for (const part of content) {\n if (isRecord(part) && part.type === 'text' && typeof part.text === 'string') parts.push(part.text)\n else parts.push(JSON.stringify(part, null, 2))\n }\n return parts.length === 0 ? null : parts.join('\\n')\n}\n\n/** 参数 JSON 里的原始问题(未经回答配对)。 */\ninterface RawQuestion {\n id: string\n question: string\n header: string\n detail: string\n multiSelect: boolean\n options: AskOption[]\n}\n\nfunction readOptions(value: unknown): AskOption[] {\n if (!Array.isArray(value)) return []\n const options: AskOption[] = []\n for (const item of value) {\n if (typeof item === 'string') {\n // 宽容形态:模型偶尔直接给字符串数组而不是 {label} 对象。\n if (item !== '') options.push({ label: item, description: '' })\n continue\n }\n if (!isRecord(item)) continue\n const label = text(item.label)\n if (label === '') continue\n options.push({ label, description: text(item.description) })\n }\n return options\n}\n\n/** 读调用参数里的问题列表;拿不到合法问题时返回 null(由调用方兜底)。 */\nfunction readQuestions(argsRaw: string): RawQuestion[] | null {\n const parsed = parseJson(argsRaw)\n if (!isRecord(parsed) || !Array.isArray(parsed.questions)) return null\n const questions: RawQuestion[] = []\n for (const item of parsed.questions) {\n if (!isRecord(item)) continue\n const question = text(item.question)\n if (question === '') continue\n questions.push({\n id: text(item.id),\n question,\n header: text(item.header),\n detail: text(item.detail),\n multiSelect: item.multiSelect === true,\n options: readOptions(item.options),\n })\n }\n return questions.length === 0 ? null : questions\n}\n\n/** 一条回答记录。 */\ninterface RawAnswer {\n id: string\n selected: string[]\n custom: string\n}\n\nfunction readAnswers(resultText: string | null): RawAnswer[] | null {\n if (resultText === null) return null\n const parsed = parseJson(resultText)\n if (!isRecord(parsed) || !Array.isArray(parsed.answers)) return null\n const answers: RawAnswer[] = []\n for (const item of parsed.answers) {\n if (!isRecord(item)) continue\n const selected = Array.isArray(item.selected)\n ? item.selected.filter((v): v is string => typeof v === 'string')\n : []\n answers.push({ id: text(item.id), selected, custom: text(item.custom) })\n }\n return answers\n}\n\n/** 调用参数:运行中取 block 自身,结算后取结算节点的调用头。 */\nfunction argsRawOf(block: AskToolBlock): string {\n return 'kind' in block ? block.call?.argsRaw ?? '' : block.argsRaw ?? ''\n}\n\n/**\n * 从一次提问调用的冻结切片派生卡片模型。\n * @param block - 运行中的调用或已结算的结果节点。\n * @returns 卡片模型;参数或结果畸形时 `questions` 为空并带兜底文本。\n */\nexport function askCardModel(block: AskToolBlock): AskCardModel {\n const settled = 'kind' in block\n const code = settled ? block.error?.code : undefined\n // Composer 的两种判定自带专用 error code,不能按通用失败处理:用户自己\n // 取消(ASK_CANCELLED)是一次正常结算,中断(ASK_ABORTED)沿用其他被中断\n // 工具调用的 amber「已停止」语义 —— 与官方 ask-question-row 的 state 覆盖\n // 逐条一致。\n const state: AskRowState = !settled ? 'running'\n : code === 'ASK_ABORTED' || code === 'interrupted' ? 'stopped'\n : code === 'ASK_CANCELLED' ? 'ok'\n : block.isError === true ? 'error' : 'ok'\n const argsRaw = argsRawOf(block)\n const resultText = settled ? resultTextOf(block) : null\n\n // 判定来源优先于结算形态:Composer 取消 / 回合中断都会带自己的 error code,\n // 此时结果里没有答案,但仍应列出问题本身(与官方转录卡的语义一致)。\n let verdict: AskCardModel['verdict']\n let phase: AskPhase\n if (code === 'ASK_CANCELLED') {\n verdict = 'cancelled'\n phase = 'unanswered'\n } else if (code === 'ASK_ABORTED') {\n verdict = 'aborted'\n phase = 'unanswered'\n } else if (!settled) {\n phase = 'pending'\n } else {\n phase = resultText === null ? 'unanswered' : 'answered'\n }\n\n const raw = readQuestions(argsRaw)\n if (raw === null) {\n return {\n state, phase, verdict, questions: [], answeredCount: 0,\n fallbackText: resultText ?? (argsRaw === '' ? null : argsRaw),\n }\n }\n\n // 回答按 id 配对;配不上的问题保留全部选项、标记为未选 —— 官方在严格配对\n // 失败时整卡降级,这里宁可少标一个\"已选\"也不丢掉用户想看的选项列表。\n const byId = new Map<string, RawAnswer>()\n for (const answer of readAnswers(resultText) ?? []) {\n if (!byId.has(answer.id)) byId.set(answer.id, answer)\n }\n const questions: AskQuestion[] = raw.map(question => {\n const answer = byId.get(question.id)\n return {\n ...question,\n selected: answer?.selected ?? [],\n custom: answer?.custom ?? '',\n }\n })\n const answeredCount = questions\n .filter(question => question.selected.length > 0 || question.custom !== '')\n .length\n return { state, phase, verdict, questions, answeredCount, fallbackText: resultText }\n}\n\n/** 折叠行右侧的进度计数(文案由组件用 locale 组装)。 */\nexport function askProgress(model: AskCardModel): { answered: number; total: number } {\n return { answered: model.answeredCount, total: model.questions.length }\n}\n","/**\n * 提问卡:接管 `ask_user_question` 的工具行。\n *\n * 官方转录卡只列**已选答案**,结算后就再也看不到当时还有哪些选项。本卡片\n * 用调用参数里的 `options` 把每个选项都渲染成一块,被选中的那块用插件色板\n * 里 ask 类别的强调色(默认蓝)反显并打勾。\n *\n * 接管是 DSH 支持的机制(keyed slot 用不同 priority 遮蔽既有占用者,\n * 见 ui-slots 的 `register()`),代价是本文件要自己承担官方 ToolRow 的\n * 折叠行外观 —— 因此行外壳逐项对齐 ToolRow.module.css 的既有视觉\n * (24px 行高、2px 分隔点、13px 次级摘要、running 扫光、hover 才现的\n * Inspect 胶囊),组件则全部来自共享的 ui-primitives。\n */\nimport { useMemo, useState } from 'react'\nimport {\n DisclosureRow, IconCheckOutline14, IconInspectOutline12, IconQuestionOutline14, StateDot,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport { askCardModel, askProgress, type AskCardModel, type AskToolBlock } from './ask-model.ts'\nimport css from './ask-card.module.css'\n\n/** 注入的 locale 翻译函数(注册时声明 `conversation` 命名空间)。 */\nexport interface AskTranslate {\n (key: string, params?: Record<string, string | number>): string\n}\n\n/** 卡片从 slot owner 收到的字段;其余 owner props 与本行无关。 */\nexport interface AskCardProps {\n t: AskTranslate\n block: AskToolBlock\n /** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */\n inspect?: (() => void) | undefined\n}\n\n/** 折叠行右侧的摘要:等待 / 已取消 / 已中断 / 未回答 / N-M 已回答。 */\nfunction summaryText(model: AskCardModel, t: AskTranslate): string {\n if (model.phase === 'pending') return t('ask.waiting')\n if (model.phase === 'unanswered') {\n if (model.verdict === 'cancelled') return t('ask.cancelled')\n if (model.verdict === 'aborted') return t('ask.interrupted')\n return t('ask.skipped')\n }\n const { answered, total } = askProgress(model)\n return t('ask.answered', { answered, total })\n}\n\n/** 一行「未选/已选」选项块。 */\nfunction OptionRow({ label, description, chosen }: {\n label: string\n description?: string | undefined\n chosen: boolean\n}) {\n return (\n <div className={css.option} data-chosen={chosen ? '' : undefined}>\n <span className={css.marker} aria-hidden=\"true\">\n {chosen && <IconCheckOutline14 />}\n </span>\n <span className={css.optionText}>\n <span className={css.label}>{label}</span>\n {description !== undefined && description !== '' && (\n <span className={css.desc}>{description}</span>\n )}\n </span>\n </div>\n )\n}\n\n/** 展开后的卡片体:逐问题列出全部选项并标出选中项。 */\nfunction QuestionList({ model, t }: { model: AskCardModel; t: AskTranslate }) {\n return (\n <div className={css.card}>\n {model.verdict !== undefined && (\n <p className={css.verdict}>\n {model.verdict === 'cancelled' ? t('ask.cancelledDetail') : t('ask.interruptedDetail')}\n </p>\n )}\n {model.questions.map((question, index) => (\n <div className={css.item} key={question.id !== '' ? question.id : `q${String(index)}`}>\n {question.header !== '' && <div className={css.header}>{question.header}</div>}\n <div className={css.question}>{question.question}</div>\n {question.detail !== '' && <div className={css.detail}>{question.detail}</div>}\n {question.options.length > 0\n ? (\n <div className={css.options}>\n {question.options.map((option, optionIndex) => (\n <OptionRow\n key={`${String(optionIndex)}-${option.label}`}\n label={option.label}\n description={option.description}\n chosen={question.selected.includes(option.label)}\n />\n ))}\n {/* 直接输入的答案不在选项表里,单独补一块,否则这次回答会消失。 */}\n {question.custom !== '' && <OptionRow label={question.custom} chosen />}\n </div>\n )\n : (\n <div className={css.answers}>\n {question.selected.map((answer, answerIndex) => (\n <span className={css.answerLine} key={`${String(answerIndex)}-${answer}`}>{answer}</span>\n ))}\n {question.custom !== '' && <span className={css.answerLine}>{question.custom}</span>}\n {question.selected.length === 0 && question.custom === '' && (\n <span className={css.answersEmpty}>{t('ask.skipped')}</span>\n )}\n </div>\n )}\n </div>\n ))}\n </div>\n )\n}\n\n/**\n * 渲染一次提问的完整记录。\n * @param props - locale 翻译函数、冻结的调用切片与可选的轨迹入口。\n * @returns 折叠行 + 展开后的选项卡片。\n */\nexport function AskQuestionRow({ t, block, inspect }: AskCardProps) {\n const model = useMemo(() => askCardModel(block), [block])\n const [expanded, setExpanded] = useState(false)\n const hasBody = model.questions.length > 0 || model.fallbackText !== null\n const open = expanded && hasBody\n const leading = model.state === 'error'\n ? <StateDot state=\"error\" />\n : model.state === 'stopped'\n ? <StateDot state=\"warning\" />\n : <IconQuestionOutline14 />\n return (\n // data-tool / data-variant / data-state 必须保留:插件既有的强调色规则\n // (palette.ts 的 TOOL_ROW_ROOT)与其他行样式都按这三个属性匹配。\n <div className={css.root} data-variant=\"others\" data-tool=\"ask_user_question\" data-state={model.state}>\n <DisclosureRow\n rowClassName={css.row}\n leadingClassName={css.leading}\n titleClassName={css.title}\n chevronClassName={css.chevron}\n icon={leading}\n title={t('ask.rowTitle')}\n open={open}\n expandable={hasBody}\n expandOnRowClick\n keepContentWhenOpen\n onToggle={() => { setExpanded(value => !value) }}\n collapsedContent={(\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary}>{summaryText(model, t)}</span>\n </>\n )}\n >\n <div className={css.bodyWrap}>\n {model.questions.length > 0\n ? <QuestionList model={model} t={t} />\n // 参数或结果畸形时的兜底:接管后不渲染就等于用户什么都看不到。\n : <pre className={css.fallback}>{model.fallbackText}</pre>}\n {inspect !== undefined && (\n <button type=\"button\" className={css.inspectButton} onClick={inspect}>\n <IconInspectOutline12 />\n {t('row.inspect')}\n </button>\n )}\n </div>\n </DisclosureRow>\n </div>\n )\n}\n","/**\n * 目标详情折叠条:接在官方 GoalBar 下面(`conversation.input.dock` 里\n * `order: 11`,官方那条是 10),把官方条上被 ellipsis 截断的目标展开成可读\n * 详情。\n *\n * 卡片形态照同槽的待办面板(ui-conversation 的 TodoPanel):同一套 dock 宽度\n * 公式、同一张 `--dsw-specific-tip` 卡片、同一个「标题 + 右侧摘要 + chevron」\n * 折叠头,默认收起。折叠头只放官方条**没有**的元信息(版本号、自主轮次),\n * 目标原文放在展开区 —— 这样两块不会互相重复。\n *\n * 为什么是「另加一条」而不是接管官方条:`conversation.input.dock` 是 list\n * 槽,不同 id 各自成格并列渲染;而官方 ui-goal 的注入面(edit/pause/resume/\n * clear 四个 Remote 动词 + 一个带竞态防护的 activation 订阅源)是**注册者\n * 私有**的,接管就得整套复刻 —— 那会把这个「只读地多看一行」的需求变成\n * 插件里多一处会写会话数据的 RPC 客户端。这里只读 `useProjection('goal')`。\n */\nimport { useEffect, useState } from 'react'\nimport {\n IconChevronDownOutline14, IconChevronUpOutline14, IconGoalOutline16,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ReactNode } from 'react'\nimport css from './goal-detail.module.css'\n\n/** 投影里本卡渲染的字段(照 DSH 的 `GoalSnapshot` 声明为鸭子类型)。 */\nexport interface GoalSnapshotLike {\n id: string\n revision: number\n objective: string\n phase: 'active' | 'paused' | 'blocked' | 'complete'\n /** 自主轮次上限;未设置时为 undefined。 */\n maxGoalRounds?: number | undefined\n /** 已开始的自主轮次;旧快照可能没有该字段。 */\n roundsStarted?: number | undefined\n /** 仅 blocked 阶段存在。 */\n blockedReason?: { code: string; message: string } | undefined\n}\n\n/** `useProjection('goal')` 的返回形状。 */\nexport interface GoalProjectionLike {\n goal: GoalSnapshotLike\n}\n\n/** 本卡从 slot 标准 props 取用的部分(其余 owner props 与本卡无关)。 */\nexport interface GoalDetailProps {\n /** 框架标准投影席位:按 key 读当前会话的投影。 */\n useProjection: (key: string) => GoalProjectionLike | null | undefined\n}\n\n/** 阶段文案:与官方 goal 字典同义,按本插件既有做法直写中文。 */\nconst PHASE_LABEL: Record<GoalSnapshotLike['phase'], string> = {\n active: '进行中',\n paused: '已暂停',\n blocked: '已阻塞',\n complete: '已完成',\n}\n\n/** 折叠头右侧摘要:只放官方条没有的元信息。 */\nfunction summaryLabel(goal: GoalSnapshotLike): string {\n const parts = [`rev ${String(goal.revision)}`]\n if (goal.roundsStarted !== undefined) {\n parts.push(goal.maxGoalRounds === undefined\n ? `${String(goal.roundsStarted)} 轮`\n : `${String(goal.roundsStarted)} / ${String(goal.maxGoalRounds)} 轮`)\n }\n return parts.join('\\u2002·\\u2002')\n}\n\n/** 展开区里的一组「键 / 值」。 */\nfunction Row({ label, children }: { label: string; children: ReactNode }) {\n return (\n <div className={css.row}>\n <dt className={css.key}>{label}</dt>\n <dd className={css.value}>{children}</dd>\n </div>\n )\n}\n\n/**\n * 渲染目标详情折叠条。\n * @param props - 框架标准投影席位。\n * @returns 折叠条;加载中、无目标、或目标已完成时不渲染(与官方条一致)。\n */\nexport function GoalDetail({ useProjection }: GoalDetailProps) {\n const projection = useProjection('goal')\n const [collapsed, setCollapsed] = useState(true)\n const goalId = projection?.goal.id\n\n // 目标换了一个(新建 / 清除后重建)就收起:否则展开态会挂在新目标上。\n useEffect(() => { setCollapsed(true) }, [goalId])\n\n const goal = projection?.goal\n if (goal === undefined || goal === null || goal.phase === 'complete') return null\n\n return (\n <section className={css.root} data-goal-detail aria-label=\"目标详情\">\n <div className={css.body}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={!collapsed}\n onClick={() => { setCollapsed(value => !value) }}\n >\n <span className={css.lead} aria-hidden><IconGoalOutline16 size={14} /></span>\n <span className={css.title}>目标详情</span>\n <span className={css.summary}>{summaryLabel(goal)}</span>\n <span className={css.chevron} aria-hidden>\n {collapsed ? <IconChevronUpOutline14 /> : <IconChevronDownOutline14 />}\n </span>\n </button>\n {!collapsed && (\n <dl className={css.detail}>\n <Row label=\"目标\">{goal.objective}</Row>\n <Row label=\"阶段\">{PHASE_LABEL[goal.phase]}</Row>\n {goal.blockedReason !== undefined && (\n <Row label=\"阻塞\">\n {goal.blockedReason.message}\n <span className={css.code}>{goal.blockedReason.code}</span>\n </Row>\n )}\n <Row label=\"标识\">\n <span className={css.code}>{goal.id}</span>\n </Row>\n </dl>\n )}\n </div>\n </section>\n )\n}\n","/**\n * Browser half: binds the `node-appearance` settings scope, paints the chat\n * flow from it (a single <style data-plugin-css> tag rebuilt on every\n * snapshot change), and registers the settings card.\n */\n\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: the ctx.settingsScope Context merge and the slot's declaration.\n// Cross-plugin collaboration goes through cordis services; a value import\n// would fail the client bundle-purity gate.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'\n// Type-only: the ctx.slots Context merge comes from the renderer package\n// (slot registry), not from the removed dsh-client-runtime module.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport { buildCss, NODE_APPEARANCE_NS, STYLE_TAG_ID, type NodeAppearanceSettings } from './palette.ts'\nimport { NodeAppearanceRow, type NodeAppearanceRowFace } from './settings-card.tsx'\nimport { AskQuestionRow } from './ask-card.tsx'\nimport { GoalDetail } from './goal-detail.tsx'\n\nexport const inject = ['slots', 'connection', 'remote', 'settingsScope']\n\n/** Upsert the plugin's paint stylesheet with the current snapshot's CSS. */\nfunction paint(scope: SettingsScope<NodeAppearanceSettings>): void {\n let tag = document.querySelector<HTMLStyleElement>(`style[data-plugin-css=\"${STYLE_TAG_ID}\"]`)\n if (tag === null) {\n tag = document.createElement('style')\n tag.dataset.plugin = NODE_APPEARANCE_NS\n tag.dataset.pluginCss = STYLE_TAG_ID\n document.head.appendChild(tag)\n }\n tag.textContent = buildCss(scope.getSnapshot().value)\n}\n\n/**\n * Mount the node-appearance plugin on the page.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n // settingsScope 由官方 ui-settings 服务提供(DSH 0.1.2-alpha 内核 client\n // 模块表);bind 返回该命名空间的强类型 scope(read/set/unset/subscribe)。\n const scope = ctx.settingsScope.bind<NodeAppearanceSettings>({ namespace: NODE_APPEARANCE_NS })\n // Paint once from the current snapshot (defaults before the first Host read).\n paint(scope)\n ctx.effect(\n () => scope.subscribe(() => { paint(scope) }),\n 'dsh-node-appearance: repaint on settings change',\n )\n\n const face: NodeAppearanceRowFace = {\n hooks: { nodeAppearance: scope },\n // Staged-edit save: write the three keys in one face call (Host settles\n // the whole namespace; per-key resolution keeps observable semantics).\n apply: async (value) => {\n await scope.set('showThinking', value.showThinking ?? true)\n await scope.set('colors', value.colors ?? {})\n await scope.set('toolColors', value.toolColors ?? {})\n },\n setShowThinking: (show) => { void scope.set('showThinking', show) },\n setCategoryColor: (category, color) => {\n const value = scope.getSnapshot().value\n void scope.set('colors', { ...value?.colors, [category]: color })\n },\n setToolColor: (tool, color) => {\n const value = scope.getSnapshot().value\n void scope.set('toolColors', { ...value?.toolColors, [tool]: color })\n },\n removeToolColor: (tool) => {\n const value = scope.getSnapshot().value\n const toolColors = { ...value?.toolColors }\n delete toolColors[tool]\n void scope.set('toolColors', toolColors)\n },\n }\n\n // alpha.2:General 区 slot(settings.general.item)已退役,接入官方\n // 「可配置插件」Tab 的 settings.plugin.item(keyed by namespace)——官方\n // 卡片姿势见 dsh-client-ui-settings-plugins/src/client/index.ts(BashCard 等)。\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n key: NODE_APPEARANCE_NS,\n inject: () => face,\n // npm ui-slots (0.0.1-rc.1) 类型未合并 keyed-slot 选项(官方 monorepo 类型\n // 才有)——运行时与官方源码一致,类型期放宽(官方类型同步后收紧)。\n } as never, NodeAppearanceRow))\n\n // 接管官方提问卡。官方 ui-tool 在 `tool.call.toolview` 的\n // `ask_user_question` key 上有一条 priority 0 的注册,而 keyed cell 只\n // 渲染最低 priority 的条目(ui-slots `register()` 的 shadowing 规则),\n // priority -1 因此遮蔽它——这是 DSH 支持的接管姿势(ui-tool 的 slot 契约\n // 原文:a key the shipped composition already covers is replaced, not shared)。\n //\n // 接管的唯一原因:官方转录卡只保留已选答案,把调用参数里的 `options`\n // 丢掉了,提问一旦结算就再也看不到当时有哪些选项(详见 ask-model.ts)。\n //\n // 类型期放宽同 settings 那条:`tool.call.toolview` 的 SlotMap 声明属于官方\n // @deepseek-ai/dsh-client-ui-tool,本插件不为此引入依赖。\n ctx.slots.inject('tool.call.toolview' as never, () => ctx.slots.register({\n name: 'tool.call.toolview',\n key: 'ask_user_question',\n priority: -1,\n // 复用官方 conversation 字典:卡片文案(提问 / N/M 已回答 / 未回答 /\n // 查看 …)全部取自它,插件不新造 locale 命名空间。\n locale: 'conversation',\n } as never, AskQuestionRow as never))\n\n // 目标详情折叠条:挂进输入框上方的 `conversation.input.dock`(list 槽,\n // 不同 id 各自成格、并列渲染),order 11 紧随官方 ui-goal 的 order 10 ——\n // 官方条只显示一行被 ellipsis 截断的目标,这里补一个可展开的详情。\n //\n // 只读 `useProjection('goal')`,不碰官方条的 edit/pause/resume/clear ——\n // 那四个 Remote 动词与 activation 订阅源都是 ui-goal 的注册者私有注入面,\n // 接管它们等于在本插件里再养一套会写会话数据的 RPC 客户端。\n ctx.slots.inject('conversation.input.dock' as never, () => ctx.slots.register({\n name: 'conversation.input.dock',\n id: 'max-null/goal-detail',\n order: 11,\n } as never, GoalDetail as never))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["useState","css","IconChevronDownOutline14","css","IconCheckOutline14","useMemo","useState","StateDot","IconQuestionOutline14","DisclosureRow","IconInspectOutline12","css","useState","DisclosureRow","StateDot","IconInspectOutline12","css","useState","IconGoalOutline16","IconChevronUpOutline14","IconChevronDownOutline14"],"sources":["../src/client/palette.ts","../src/client/settings-card.tsx","../src/client/ask-model.ts","../src/client/ask-card.tsx","../src/client/deliverable-model.ts","../src/client/deliverable-row.tsx","../src/client/goal-detail.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Node appearance palette: category/tool mapping, default colors, and the pure\n * CSS-rule generator that paints the chat flow. Browser-half owned; the Host\n * half mirrors the same defaults through its schemastery schema (the two\n * cannot share a value import — the browser bundle purity gate forbids\n * cross-package value imports).\n */\n\n/** The settings namespace this plugin owns (spelled identically in both halves). */\nexport const NODE_APPEARANCE_NS = 'node-appearance'\n\n/** The plugin's style tag identity (removed/replaced on every re-paint). */\nexport const STYLE_TAG_ID = `${NODE_APPEARANCE_NS}/rules`\n\n/** One paintable node category. `command`, `thinking`, `context` are non-tool rows. */\nexport type NodeCategory =\n | 'search' | 'agent' | 'execute' | 'file' | 'deliver' | 'task' | 'ask' | 'command' | 'thinking' | 'context' | 'steering' | 'other'\n\n/** Accent color per category (CSS colors). */\nexport type NodeAppearanceColors = Record<NodeCategory, string>\n\n/** The settings value this plugin reads from its namespace scope. */\nexport interface NodeAppearanceSettings {\n /** Show assistant reasoning blocks as Think rows; false hides them. */\n showThinking?: boolean | undefined\n /** Per-category accent colors; missing keys fall back to defaults. */\n colors?: Partial<NodeAppearanceColors> | undefined\n /** Per-tool accent overrides keyed by wire tool name. */\n toolColors?: Record<string, string> | undefined\n}\n\n/** Initial palette: mid-luminance hues readable on both light and dark themes. */\nexport const DEFAULT_COLORS: NodeAppearanceColors = {\n search: '#3b82f6', // blue — web_search / web_fetch\n agent: '#a855f7', // purple — subagent / workflow / send_message …\n execute: '#f59e0b', // amber — bash / pwsh / run_code / terminal_*\n file: '#22c55e', // green — read / write / edit / glob / grep\n deliver: '#06b6d4', // cyan — present 交付文件行。独立于 file:生成文件的那些行与交付行常在同一轮同屏出现,共用绿色分不清谁是谁(用户反馈)\n task: '#ec4899', // pink — todo_write / goal / job_* / schedule_*\n ask: '#65a30d', // lime — ask_user_question 提问卡(取作 --ask-accent;色相落在 execute 琥珀与 file 绿之间的空档,与 search 的蓝区分开)\n command: '#f97316', // orange — /command nodes\n thinking: '#c4b5fd', // light purple — Think rows\n context: '#8a9bb5', // slate blue — injected context rows (informational)\n steering: '#14b8a6', // teal — steering rows (rc.8)\n other: '#64748b', // slate — every unlisted tool\n}\n\n/** Wire tool name → category for the shipped mapping. */\nexport const TOOL_CATEGORIES: Record<Exclude<NodeCategory, 'command' | 'thinking' | 'context' | 'steering'>, readonly string[]> = {\n search: ['web_search', 'web_fetch'],\n agent: ['subagent', 'subagent_acp', 'subagent_fork', 'send_message', 'interrupt_agent', 'list_agents', 'report', 'workflow'],\n execute: ['bash', 'pwsh', 'run_code', 'terminal_open', 'terminal_close', 'terminal_list', 'terminal_read', 'terminal_send', 'terminal_signal', 'str_replace_editor'],\n file: ['read', 'write', 'edit', 'read_image', 'glob', 'grep'],\n deliver: ['present'],\n task: ['todo_write', 'create_goal', 'get_goal', 'update_goal', 'job_kill', 'job_list', 'job_output', 'schedule_create', 'schedule_delete', 'schedule_list', 'exit_plan_mode'],\n ask: ['ask_user_question'],\n other: [],\n}\n\n/** Selector matching every tool row inside a tool-call node. */\nconst TOOL_ROW = '[data-chat-flow-kind=\"tool-call\"] [data-tool]'\n/** The ToolRow root itself (carries data-variant; the wrapper callRow does not). */\nconst TOOL_ROW_ROOT = '[data-chat-flow-kind=\"tool-call\"] [data-tool][data-variant]'\n/** Selector of the command node wrapper. */\nconst COMMAND_ROW = '[data-chat-flow-kind=\"command\"]'\n/** Selector of the Think reasoning row. */\nconst THINK_ROW = '[data-variant=\"think\"]'\n/** Selector of the injected-context row (the flow-item wrapper). */\nconst CONTEXT_ROW = '[data-chat-flow-kind=\"context\"]'\n/** Selector of a settled tool-result row (rc.8: tool results render as their own row). */\nconst TOOL_RESULT_ROW = '[data-chat-flow-kind=\"tool-result\"]'\n\n/**\n * The rows that carry the accent paint: the ToolRow root (not its wrapper\n * callRow — both carry data-tool, only the inner row carries data-variant),\n * command nodes, Think rows, injected-context rows, and tool-result rows.\n * User input rows are excluded — right-alignment already\n * distinguishes them (2026-08-20 用户反馈);steering rows 也走独立规则\n * (见 buildCss:在 userStack 层做 wash,不涂整行 rail)。\n * The 3px inset rail is compensated\n * with a matching padding-left so the rail never covers the row's leading icon.\n */\nconst ACCENTED_ROWS = [\n TOOL_ROW_ROOT, COMMAND_ROW, THINK_ROW, CONTEXT_ROW, TOOL_RESULT_ROW,\n].join(',\\n')\n\n/**\n * Accept a configured CSS color (hex, color functions) or reject it so an\n * invalid value falls back to the category default instead of poisoning CSS.\n * @param value - configured color string.\n * @returns whether the value is a plausible CSS color literal.\n */\nexport function isCssColor(value: string): boolean {\n const trimmed = value.trim()\n if (trimmed === '') return false\n if (/^#[0-9a-f]{3,8}$/i.test(trimmed)) return true\n return /^(rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color|device-cmyk)\\(/i.test(trimmed)\n}\n\n/** Resolve the effective palette from user settings merged over defaults. */\nexport function resolveColors(settings: NodeAppearanceSettings): NodeAppearanceColors {\n const colors: NodeAppearanceColors = { ...DEFAULT_COLORS }\n const configured = settings.colors\n if (configured !== undefined && typeof configured === 'object' && configured !== null) {\n for (const key of Object.keys(DEFAULT_COLORS) as NodeCategory[]) {\n const value = configured[key]\n if (typeof value === 'string' && isCssColor(value)) colors[key] = value\n }\n }\n return colors\n}\n\n/** Escape a tool name into a CSS attribute selector string literal. */\nfunction attributeLiteral(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n}\n\n/**\n * Steering marker icon: a corner-up-left arrow (mid-turn guidance inserted\n * into the running answer), drawn as a mask so the icon inherits the\n * configured steering color. Encoded data URI, no external asset.\n */\nconst STEERING_ICON = \"data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 14 4 9 9 4'/%3E%3Cpath d='M20 20v-7a4 4 0 0 0-4-4H4'/%3E%3C/svg%3E\"\n\n/**\n * Build the complete stylesheet text for one settings snapshot.\n * @param settings - the namespace scope value (may be partial or undefined).\n * @returns CSS text painting accent rows and (optionally) hiding Think rows.\n */\nexport function buildCss(settings: NodeAppearanceSettings | undefined): string {\n const colors = resolveColors(settings ?? {})\n const toolOverrides = settings?.toolColors\n const lines: string[] = []\n\n // Unlisted tools keep the neutral fallback. Declared BEFORE the per-tool\n // rules: both selectors carry equal specificity (two attribute selectors),\n // so of two conflicting declarations the later one wins — a fallback\n // declared after the category rules would override every category color.\n lines.push(`${TOOL_ROW} { --ncolor-accent: ${colors.other}; }`)\n\n // Per-tool accent assignments (explicit overrides win over category color).\n for (const [category, tools] of Object.entries(TOOL_CATEGORIES)) {\n const key = category as keyof typeof TOOL_CATEGORIES\n for (const tool of tools) {\n const override = toolOverrides?.[tool]\n const color = typeof override === 'string' && isCssColor(override)\n ? override\n : colors[key]\n lines.push(`[data-chat-flow-kind=\"tool-call\"] [data-tool=\"${attributeLiteral(tool)}\"] { --ncolor-accent: ${color}; }`)\n }\n }\n\n // Non-tool accent rows.\n lines.push(`${COMMAND_ROW} { --ncolor-accent: ${colors.command}; }`)\n lines.push(`${THINK_ROW} { --ncolor-accent: ${colors.thinking}; }`)\n lines.push(`${CONTEXT_ROW} { --ncolor-accent: ${colors.context}; }`)\n lines.push(`${TOOL_RESULT_ROW} { --ncolor-accent: ${colors.file}; }`)\n\n // One shared paint rule: 3px inset left rail (layout-free) + 8% wash. The\n // matching padding-left moves the row content off the rail so the leading\n // icon is never covered.\n lines.push(`${ACCENTED_ROWS} {\n box-shadow: inset 3px 0 0 var(--ncolor-accent);\n background-color: color-mix(in srgb, var(--ncolor-accent) 8%, transparent);\n padding-left: 3px;\n}`)\n\n // Steering rows (mid-turn user steering) stay visually distinct from plain\n // user rows with a compass marker beside the right-aligned bubble. The\n // marker is a mask over the user-stack — the container that hugs the bubble\n // — positioned to the left of it, so the tint reads as a glyph next to the\n // message rather than a detached full-width rail (2026-08-21 用户反馈:\n // 整行 rail 突兀,改在 userStack 层做图标区分;slot 方案不可行:\n // conversation.message.images 是 single 槽且已被官方 ui-attachment 占用).\n // alpha.2 锚点迁移(2026-08-31):消息行\"时间悬浮\"标识 data-time-hover-root\n // 已被 TurnTail/MessageItem 的 data-actions-reveal(always|hover)取代;\n // kind 与 首子=userStack 结构不变(ChatNodeSeat L206 / MessageItem L178 验证)。\n lines.push(`[data-chat-flow-kind=\"steering\"] [data-actions-reveal] > :first-child {\n position: relative;\n}`)\n lines.push(`[data-chat-flow-kind=\"steering\"] [data-actions-reveal] > :first-child::before {\n content: '';\n position: absolute;\n right: 100%;\n margin-right: 6px;\n top: 50%;\n width: 14px;\n height: 14px;\n transform: translateY(-50%);\n background-color: ${colors.steering};\n -webkit-mask: url(\"${STEERING_ICON}\") center / contain no-repeat;\n mask: url(\"${STEERING_ICON}\") center / contain no-repeat;\n}`)\n\n // Visibility switch: hide Think rows entirely on the frontend. `!important`\n // outranks the module stylesheet's `.root { display: flex }` (same\n // specificity, but the plugin style tag is injected before the module's).\n if (settings?.showThinking === false) {\n lines.push(`${THINK_ROW} { display: none !important; }`)\n // A think-only node leaves its flowItem seat with zero height: the seat\n // still consumes the column's 16px flex gap on both sides, doubling the\n // spacing between the neighbors. Hide the whole seat when the think row\n // is the only child of its block container — block-internal thinks\n // (text + reasoning in one node) stay gap-neutral after hiding the row.\n lines.push(\n `[data-chat-flow-kind=\"assistant\"]:has(${THINK_ROW}:only-child),`,\n `[data-chat-flow-kind=\"assistant-step\"]:has(${THINK_ROW}:only-child) { display: none !important; }`,\n )\n }\n\n return lines.join('\\n')\n}\n","/**\n * The node-appearance plugin config card. Mirrors the official\n * `settings.plugin.item` card chrome (PluginCard: card shell, name-over-\n * description header, chevron disclosure) with the DSH design tokens —\n * drawn by hand because a feature plugin must not runtime-import another\n * feature plugin's values (bundle purity gate).\n *\n * Writes are immediate: picking a color or flipping the Think switch applies\n * it right away (a palette is a live preview, not a staged form). The footer\n * carries one「恢复初始设置」button that resets the whole namespace to the\n * shipped defaults — two-click confirmation so a miss cannot wipe a custom\n * palette.\n */\n\nimport { useState, type ChangeEvent, type FormEvent } from 'react'\nimport type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store'\nimport type { SettingsScope, SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client'\nimport { IconChevronDownOutline14 } from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { InjectFace, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport {\n DEFAULT_COLORS, isCssColor, resolveColors, TOOL_CATEGORIES,\n type NodeAppearanceSettings, type NodeCategory,\n} from './palette.ts'\nimport css from './card.module.css'\n\n/** The card's inject face: the read-only scope snapshot plus write actions. */\nexport interface NodeAppearanceRowFace {\n hooks: {\n /** The bound settings-scope snapshot, rendered as useNodeAppearance. */\n nodeAppearance: ObservableSnapshot<SettingsScopeSnapshot<NodeAppearanceSettings>>\n }\n /** Persist one full value (reset-to-defaults path; resolves on Host settlement). */\n apply(value: NodeAppearanceSettings): Promise<void>\n /** Write the Think visibility switch. */\n setShowThinking(show: boolean): void\n /** Merge one category color into the palette section. */\n setCategoryColor(category: NodeCategory, color: string): void\n /** Merge one tool override into the toolColors section. */\n setToolColor(tool: string, color: string): void\n /** Remove one tool override. */\n removeToolColor(tool: string): void\n}\n\n/** Props the renderer binds for this plugin config card. */\nexport type NodeAppearanceRowProps =\n PropsRuntime<'settings.plugin.item'>\n & InjectFace<NodeAppearanceRowFace>\n\n/** Chinese labels per category (product copy is Chinese). */\nconst CATEGORY_LABELS: Record<NodeCategory, string> = {\n search: '联网搜索',\n agent: '智能体调用',\n execute: '代码 / 指令执行',\n file: '文件操作',\n deliver: '交付文件',\n task: '任务 / 目标',\n ask: '提问卡片',\n command: '指令节点',\n thinking: '思考过程',\n context: '上下文注入',\n steering: '模型引导',\n other: '其他工具',\n}\n\n/** Tools shown in the add-override autocomplete-free text input placeholder. */\nconst TOOL_SUGGESTIONS = Object.values(TOOL_CATEGORIES).flat().join('、')\n\n/** The card copy (one locale). */\nconst COPY = {\n title: '节点外观',\n description: '消息节点外观与颜色的偏好设置',\n reset: '恢复初始设置',\n resetConfirm: '再次点击确认恢复',\n resetting: '恢复中…',\n readOnly: '配置只读:插件主机侧未挂载或连接非本机。',\n loading: '配置加载中…',\n showThinking: '显示思考过程',\n showThinkingHint: '关闭后会话中的 Think 思考行隐藏',\n toolColors: '工具颜色覆盖(可选)',\n addTool: '添加',\n removeTool: '删除',\n}\n\n/** The shipped defaults, one face call away from any custom palette. */\nconst INITIAL_SETTINGS: NodeAppearanceSettings = {\n showThinking: true,\n colors: DEFAULT_COLORS,\n toolColors: {},\n}\n\n/**\n * Render the node-appearance config card.\n * @param props - the injected scope snapshot hook, its write actions.\n * @returns the card, matching the official plugin-card chrome.\n */\nexport function NodeAppearanceRow({ useNodeAppearance, apply, setShowThinking, setCategoryColor, setToolColor, removeToolColor }: NodeAppearanceRowProps) {\n const [open, setOpen] = useState(false)\n const [confirmReset, setConfirmReset] = useState(false)\n const [resetting, setResetting] = useState(false)\n const [toolName, setToolName] = useState('')\n const [toolColor, setToolColorDraft] = useState('#64748b')\n const snapshot = useNodeAppearance(snapshot => snapshot)\n const served = snapshot.value ?? {}\n const colors = resolveColors(served)\n const toolColors = served.toolColors ?? {}\n const showThinking = served.showThinking ?? true\n const disabled = snapshot.writable === false\n const unavailable = snapshot.status !== 'ready'\n\n const resetInitial = async (): Promise<void> => {\n if (resetting) return\n setResetting(true)\n try {\n await apply(INITIAL_SETTINGS)\n setConfirmReset(false)\n } catch {\n // A refused reset just leaves the current palette in place.\n } finally {\n setResetting(false)\n }\n }\n\n const handleReset = (): void => {\n if (confirmReset) {\n void resetInitial()\n } else {\n setConfirmReset(true)\n }\n }\n\n const addTool = (event: FormEvent): void => {\n event.preventDefault()\n const name = toolName.trim()\n if (name === '' || !isCssColor(toolColor)) return\n setToolColor(name, toolColor)\n setToolName('')\n }\n\n return (\n <li className={css.card + (open ? ' ' + css.cardOpen : '')}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={open}\n aria-label={`${open ? '收起' : '展开'}:${COPY.title}`}\n onClick={() => { setOpen(!open) }}\n >\n <span className={css.headText}>\n <span className={css.name}>{COPY.title}</span>\n <span className={css.description}>{COPY.description}</span>\n </span>\n <IconChevronDownOutline14 className={css.chevron + (open ? ' ' + css.chevronOpen : '')} />\n </button>\n {open && (\n <div className={css.body}>\n {unavailable && !disabled && <p className={css.statusLine}>{COPY.loading}</p>}\n {disabled && <p className={css.readOnly} role=\"status\">{COPY.readOnly}</p>}\n <div className={disabled ? css.disabled : ''}>\n <div className={css.row}>\n <label className={css.rowLabel} htmlFor=\"node-appearance-show-thinking\">{COPY.showThinking}</label>\n <span className={css.rowHint}>{COPY.showThinkingHint}</span>\n <button\n id=\"node-appearance-show-thinking\"\n className={css.switch + (showThinking ? ' ' + css.on : '')}\n type=\"button\"\n aria-pressed={showThinking}\n onClick={() => { setShowThinking(!showThinking) }}\n >\n <span className={css.knob} />\n </button>\n </div>\n {(Object.keys(CATEGORY_LABELS) as NodeCategory[]).map(category => (\n <div className={css.row} key={category}>\n <label className={css.rowLabel} htmlFor={`node-appearance-color-${category}`}>{CATEGORY_LABELS[category]}</label>\n <input\n id={`node-appearance-color-${category}`}\n className={css.colorInput}\n type=\"color\"\n value={colors[category]}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setCategoryColor(category, event.target.value) }}\n />\n <span className={css.colorValue}>{colors[category]}</span>\n </div>\n ))}\n <div className={css.sectionTitle}>{COPY.toolColors}</div>\n {Object.entries(toolColors).map(([tool, color]) => (\n <div className={css.row} key={tool}>\n <span className={css.toolName} title={tool}>{tool}</span>\n <input\n className={css.colorInput}\n type=\"color\"\n value={isCssColor(color) ? color : DEFAULT_COLORS.other}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolColor(tool, event.target.value) }}\n />\n <button type=\"button\" className={css.removeButton} onClick={() => { removeToolColor(tool) }}>{COPY.removeTool}</button>\n </div>\n ))}\n <form className={css.addRow} onSubmit={addTool}>\n <input\n className={css.toolInput}\n type=\"text\"\n placeholder={`工具名,如 ${TOOL_SUGGESTIONS}`}\n value={toolName}\n onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolName(event.target.value) }}\n />\n <input className={css.colorInput} type=\"color\" value={toolColor} onChange={(event: ChangeEvent<HTMLInputElement>) => { setToolColorDraft(event.target.value) }} />\n <button type=\"submit\" className={css.addButton} disabled={toolName.trim() === ''}>{COPY.addTool}</button>\n </form>\n </div>\n <div className={css.footer}>\n <button\n type=\"button\"\n className={css.reset + (confirmReset ? ' ' + css.resetConfirm : '')}\n disabled={resetting}\n onClick={handleReset}\n >{resetting ? COPY.resetting : confirmReset ? COPY.resetConfirm : COPY.reset}</button>\n </div>\n </div>\n )}\n </li>\n )\n}\n","/**\n * 提问卡数据派生:把一次 `ask_user_question` 调用还原成「问题 + 全部选项 +\n * 实际选中项」。\n *\n * 为什么要自己解析:DSH 官方的转录卡只保留**已选答案**\n * (`ui-tool/src/client/tool/toolviews/ask-question-row.tsx` 的\n * `questionEntries()` 只取 `id`/`question`,把 `options` 丢掉了),所以提问\n * 结算后「当时还有哪些选项」在客户端管线上就没了。选项列表只存在于调用的\n * 参数 JSON 里 —— 这也是本插件接管 `ask_user_question` toolview 的唯一原因。\n *\n * 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错\n * (接管后卡片由我们渲染,渲染不出来就等于用户什么都看不到)。\n */\n\n/** 模型给出的一个可选项。 */\nexport interface AskOption {\n /** 选项文本;同时是被 `selected` 回传的那个值。 */\n label: string\n /** 选项下方的补充说明,模型没给时为空。 */\n description: string\n}\n\n/** 一个问题:全部选项 + 实际回答。 */\nexport interface AskQuestion {\n id: string\n question: string\n /** 可选的短标题(模型提供时显示在问题上方)。 */\n header: string\n /** 可选的补充说明。 */\n detail: string\n /** 模型是否允许多选。 */\n multiSelect: boolean\n /** 模型当时给出的全部选项;调用没带选项时为空数组。 */\n options: AskOption[]\n /** 被选中的选项文本,按回答记录的顺序。 */\n selected: string[]\n /** 直接输入的文本答案(没选选项或额外补充时)。 */\n custom: string\n}\n\n/** 行的运行状态,与通用工具行保持同一套词汇。 */\nexport type AskRowState = 'running' | 'ok' | 'error' | 'stopped'\n\n/** 问题集的结算程度。 */\nexport type AskPhase = 'pending' | 'answered' | 'unanswered'\n\n/** 卡片渲染所需的全部派生结果。 */\nexport interface AskCardModel {\n state: AskRowState\n phase: AskPhase\n /** 被取消或被中断时记录判定来源;正常结算为 undefined。 */\n verdict: 'cancelled' | 'aborted' | undefined\n questions: AskQuestion[]\n /** 至少选了选项或填了自定义答案的问题数(折叠行的 N/M 用)。 */\n answeredCount: number\n /**\n * 参数 JSON 解析不出来时用于兜底展示的结果文本;运行中或结果无文本时为\n * null。没有它,一次畸形调用会让接管后的行变成空白。\n */\n fallbackText: string | null\n}\n\n/**\n * `ask_user_question` 的 block 里本卡读到的字段子集。\n * 结构照 DSH 的 `ToolCallBlock`(运行中=调用自身,结算后=带 `kind` 的结果\n * 节点)声明为鸭子类型:跨插件只允许 type-only 引用,这里连类型引用都不需要。\n */\nexport interface AskToolBlock {\n /** 运行中的调用没有这个字段;结算后为 `'tool-result'`。 */\n kind?: string | undefined\n callId?: string | undefined\n /** 运行中形态:调用自身携带参数。 */\n argsRaw?: string | undefined\n /** 结算形态:调用头(子调用被剥掉时为 null)。 */\n call?: { argsRaw?: string | undefined } | null | undefined\n /** 结算形态:结果内容块。 */\n content?: readonly unknown[] | undefined\n error?: { code?: string | undefined } | undefined\n isError?: boolean | undefined\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** 读一个字符串字段,非字符串一律当空串。 */\nfunction text(value: unknown): string {\n return typeof value === 'string' ? value : ''\n}\n\nfunction parseJson(source: string): unknown {\n try {\n return JSON.parse(source)\n } catch {\n // 流式截断的半截 JSON 是正常现象:降级为「无问题」,由调用方兜底展示原文。\n return undefined\n }\n}\n\n/** 从结果内容块拼出展示文本(文本块原样、其余块转 JSON)。 */\nexport function resultTextOf(block: AskToolBlock): string | null {\n const content = block.content\n if (!Array.isArray(content) || content.length === 0) return null\n const parts: string[] = []\n for (const part of content) {\n if (isRecord(part) && part.type === 'text' && typeof part.text === 'string') parts.push(part.text)\n else parts.push(JSON.stringify(part, null, 2))\n }\n return parts.length === 0 ? null : parts.join('\\n')\n}\n\n/** 参数 JSON 里的原始问题(未经回答配对)。 */\ninterface RawQuestion {\n id: string\n question: string\n header: string\n detail: string\n multiSelect: boolean\n options: AskOption[]\n}\n\nfunction readOptions(value: unknown): AskOption[] {\n if (!Array.isArray(value)) return []\n const options: AskOption[] = []\n for (const item of value) {\n if (typeof item === 'string') {\n // 宽容形态:模型偶尔直接给字符串数组而不是 {label} 对象。\n if (item !== '') options.push({ label: item, description: '' })\n continue\n }\n if (!isRecord(item)) continue\n const label = text(item.label)\n if (label === '') continue\n options.push({ label, description: text(item.description) })\n }\n return options\n}\n\n/** 读调用参数里的问题列表;拿不到合法问题时返回 null(由调用方兜底)。 */\nfunction readQuestions(argsRaw: string): RawQuestion[] | null {\n const parsed = parseJson(argsRaw)\n if (!isRecord(parsed) || !Array.isArray(parsed.questions)) return null\n const questions: RawQuestion[] = []\n for (const item of parsed.questions) {\n if (!isRecord(item)) continue\n const question = text(item.question)\n if (question === '') continue\n questions.push({\n id: text(item.id),\n question,\n header: text(item.header),\n detail: text(item.detail),\n multiSelect: item.multiSelect === true,\n options: readOptions(item.options),\n })\n }\n return questions.length === 0 ? null : questions\n}\n\n/** 一条回答记录。 */\ninterface RawAnswer {\n id: string\n selected: string[]\n custom: string\n}\n\nfunction readAnswers(resultText: string | null): RawAnswer[] | null {\n if (resultText === null) return null\n const parsed = parseJson(resultText)\n if (!isRecord(parsed) || !Array.isArray(parsed.answers)) return null\n const answers: RawAnswer[] = []\n for (const item of parsed.answers) {\n if (!isRecord(item)) continue\n const selected = Array.isArray(item.selected)\n ? item.selected.filter((v): v is string => typeof v === 'string')\n : []\n answers.push({ id: text(item.id), selected, custom: text(item.custom) })\n }\n return answers\n}\n\n/** 调用参数:运行中取 block 自身,结算后取结算节点的调用头。 */\nfunction argsRawOf(block: AskToolBlock): string {\n return 'kind' in block ? block.call?.argsRaw ?? '' : block.argsRaw ?? ''\n}\n\n/**\n * 从一次提问调用的冻结切片派生卡片模型。\n * @param block - 运行中的调用或已结算的结果节点。\n * @returns 卡片模型;参数或结果畸形时 `questions` 为空并带兜底文本。\n */\nexport function askCardModel(block: AskToolBlock): AskCardModel {\n const settled = 'kind' in block\n const code = settled ? block.error?.code : undefined\n // Composer 的两种判定自带专用 error code,不能按通用失败处理:用户自己\n // 取消(ASK_CANCELLED)是一次正常结算,中断(ASK_ABORTED)沿用其他被中断\n // 工具调用的 amber「已停止」语义 —— 与官方 ask-question-row 的 state 覆盖\n // 逐条一致。\n const state: AskRowState = !settled ? 'running'\n : code === 'ASK_ABORTED' || code === 'interrupted' ? 'stopped'\n : code === 'ASK_CANCELLED' ? 'ok'\n : block.isError === true ? 'error' : 'ok'\n const argsRaw = argsRawOf(block)\n const resultText = settled ? resultTextOf(block) : null\n\n // 判定来源优先于结算形态:Composer 取消 / 回合中断都会带自己的 error code,\n // 此时结果里没有答案,但仍应列出问题本身(与官方转录卡的语义一致)。\n let verdict: AskCardModel['verdict']\n let phase: AskPhase\n if (code === 'ASK_CANCELLED') {\n verdict = 'cancelled'\n phase = 'unanswered'\n } else if (code === 'ASK_ABORTED') {\n verdict = 'aborted'\n phase = 'unanswered'\n } else if (!settled) {\n phase = 'pending'\n } else {\n phase = resultText === null ? 'unanswered' : 'answered'\n }\n\n const raw = readQuestions(argsRaw)\n if (raw === null) {\n return {\n state, phase, verdict, questions: [], answeredCount: 0,\n fallbackText: resultText ?? (argsRaw === '' ? null : argsRaw),\n }\n }\n\n // 回答按 id 配对;配不上的问题保留全部选项、标记为未选 —— 官方在严格配对\n // 失败时整卡降级,这里宁可少标一个\"已选\"也不丢掉用户想看的选项列表。\n const byId = new Map<string, RawAnswer>()\n for (const answer of readAnswers(resultText) ?? []) {\n if (!byId.has(answer.id)) byId.set(answer.id, answer)\n }\n const questions: AskQuestion[] = raw.map(question => {\n const answer = byId.get(question.id)\n return {\n ...question,\n selected: answer?.selected ?? [],\n custom: answer?.custom ?? '',\n }\n })\n const answeredCount = questions\n .filter(question => question.selected.length > 0 || question.custom !== '')\n .length\n return { state, phase, verdict, questions, answeredCount, fallbackText: resultText }\n}\n\n/** 折叠行右侧的进度计数(文案由组件用 locale 组装)。 */\nexport function askProgress(model: AskCardModel): { answered: number; total: number } {\n return { answered: model.answeredCount, total: model.questions.length }\n}\n","/**\n * 提问卡:接管 `ask_user_question` 的工具行。\n *\n * 官方转录卡只列**已选答案**,结算后就再也看不到当时还有哪些选项。本卡片\n * 用调用参数里的 `options` 把每个选项都渲染成一块,被选中的那块用插件色板\n * 里 ask 类别的强调色(默认蓝)反显并打勾。\n *\n * 接管是 DSH 支持的机制(keyed slot 用不同 priority 遮蔽既有占用者,\n * 见 ui-slots 的 `register()`),代价是本文件要自己承担官方 ToolRow 的\n * 折叠行外观 —— 因此行外壳逐项对齐 ToolRow.module.css 的既有视觉\n * (24px 行高、2px 分隔点、13px 次级摘要、running 扫光、hover 才现的\n * Inspect 胶囊),组件则全部来自共享的 ui-primitives。\n */\nimport { useMemo, useState } from 'react'\nimport {\n DisclosureRow, IconCheckOutline14, IconInspectOutline12, IconQuestionOutline14, StateDot,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport { askCardModel, askProgress, type AskCardModel, type AskToolBlock } from './ask-model.ts'\nimport css from './ask-card.module.css'\n\n/** 注入的 locale 翻译函数(注册时声明 `conversation` 命名空间)。 */\nexport interface AskTranslate {\n (key: string, params?: Record<string, string | number>): string\n}\n\n/** 卡片从 slot owner 收到的字段;其余 owner props 与本行无关。 */\nexport interface AskCardProps {\n t: AskTranslate\n block: AskToolBlock\n /** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */\n inspect?: (() => void) | undefined\n}\n\n/** 折叠行右侧的摘要:等待 / 已取消 / 已中断 / 未回答 / N-M 已回答。 */\nfunction summaryText(model: AskCardModel, t: AskTranslate): string {\n if (model.phase === 'pending') return t('ask.waiting')\n if (model.phase === 'unanswered') {\n if (model.verdict === 'cancelled') return t('ask.cancelled')\n if (model.verdict === 'aborted') return t('ask.interrupted')\n return t('ask.skipped')\n }\n const { answered, total } = askProgress(model)\n return t('ask.answered', { answered, total })\n}\n\n/** 一行「未选/已选」选项块。 */\nfunction OptionRow({ label, description, chosen }: {\n label: string\n description?: string | undefined\n chosen: boolean\n}) {\n return (\n <div className={css.option} data-chosen={chosen ? '' : undefined}>\n <span className={css.marker} aria-hidden=\"true\">\n {chosen && <IconCheckOutline14 />}\n </span>\n <span className={css.optionText}>\n <span className={css.label}>{label}</span>\n {description !== undefined && description !== '' && (\n <span className={css.desc}>{description}</span>\n )}\n </span>\n </div>\n )\n}\n\n/** 展开后的卡片体:逐问题列出全部选项并标出选中项。 */\nfunction QuestionList({ model, t }: { model: AskCardModel; t: AskTranslate }) {\n return (\n <div className={css.card}>\n {model.verdict !== undefined && (\n <p className={css.verdict}>\n {model.verdict === 'cancelled' ? t('ask.cancelledDetail') : t('ask.interruptedDetail')}\n </p>\n )}\n {model.questions.map((question, index) => (\n <div className={css.item} key={question.id !== '' ? question.id : `q${String(index)}`}>\n {question.header !== '' && <div className={css.header}>{question.header}</div>}\n <div className={css.question}>{question.question}</div>\n {question.detail !== '' && <div className={css.detail}>{question.detail}</div>}\n {question.options.length > 0\n ? (\n <div className={css.options}>\n {question.options.map((option, optionIndex) => (\n <OptionRow\n key={`${String(optionIndex)}-${option.label}`}\n label={option.label}\n description={option.description}\n chosen={question.selected.includes(option.label)}\n />\n ))}\n {/* 直接输入的答案不在选项表里,单独补一块,否则这次回答会消失。 */}\n {question.custom !== '' && <OptionRow label={question.custom} chosen />}\n </div>\n )\n : (\n <div className={css.answers}>\n {question.selected.map((answer, answerIndex) => (\n <span className={css.answerLine} key={`${String(answerIndex)}-${answer}`}>{answer}</span>\n ))}\n {question.custom !== '' && <span className={css.answerLine}>{question.custom}</span>}\n {question.selected.length === 0 && question.custom === '' && (\n <span className={css.answersEmpty}>{t('ask.skipped')}</span>\n )}\n </div>\n )}\n </div>\n ))}\n </div>\n )\n}\n\n/**\n * 渲染一次提问的完整记录。\n * @param props - locale 翻译函数、冻结的调用切片与可选的轨迹入口。\n * @returns 折叠行 + 展开后的选项卡片。\n */\nexport function AskQuestionRow({ t, block, inspect }: AskCardProps) {\n const model = useMemo(() => askCardModel(block), [block])\n const [expanded, setExpanded] = useState(false)\n const hasBody = model.questions.length > 0 || model.fallbackText !== null\n const open = expanded && hasBody\n const leading = model.state === 'error'\n ? <StateDot state=\"error\" />\n : model.state === 'stopped'\n ? <StateDot state=\"warning\" />\n : <IconQuestionOutline14 />\n return (\n // data-tool / data-variant / data-state 必须保留:插件既有的强调色规则\n // (palette.ts 的 TOOL_ROW_ROOT)与其他行样式都按这三个属性匹配。\n <div className={css.root} data-variant=\"others\" data-tool=\"ask_user_question\" data-state={model.state}>\n <DisclosureRow\n rowClassName={css.row}\n leadingClassName={css.leading}\n titleClassName={css.title}\n chevronClassName={css.chevron}\n icon={leading}\n title={t('ask.rowTitle')}\n open={open}\n expandable={hasBody}\n expandOnRowClick\n keepContentWhenOpen\n onToggle={() => { setExpanded(value => !value) }}\n collapsedContent={(\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary}>{summaryText(model, t)}</span>\n </>\n )}\n >\n <div className={css.bodyWrap}>\n {model.questions.length > 0\n ? <QuestionList model={model} t={t} />\n // 参数或结果畸形时的兜底:接管后不渲染就等于用户什么都看不到。\n : <pre className={css.fallback}>{model.fallbackText}</pre>}\n {inspect !== undefined && (\n <button type=\"button\" className={css.inspectButton} onClick={inspect}>\n <IconInspectOutline12 />\n {t('row.inspect')}\n </button>\n )}\n </div>\n </DisclosureRow>\n </div>\n )\n}\n","/**\n * 交付行数据派生:把一次 `present` 调用还原成「状态 + 文件清单 + 结果文本」。\n *\n * 为什么要自己解析:官方 PresentRow 的折叠态把全部文件名逗号拼成一行\n * (`ui-deliverables/src/client/PresentRow.tsx` 的 `fileNames()`),多文件时读不完,\n * 也看不出这一轮交付了几个。完整清单只存在于调用的参数 JSON 里,所以折叠摘要与\n * 展开态都得自己解一份。\n *\n * 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错(接管后\n * 行由我们渲染,渲染不出来就等于用户什么都看不到)。\n *\n * 「等 N 个文件」这类摘要文案直写中文,与 goal-detail.tsx 同一取径:本插件不新造\n * locale 命名空间,而官方 deliverables 字典没有「共计 N 个」的 key(`presented.more`\n * 是「+ N 个文件」,用于溢出提示)。行内的标题、状态词与 inspect 仍取自官方字典。\n */\n\n/**\n * 工具调用块里本行取用的字段(照官方 PresentRow 的取用面声明为鸭子类型,\n * 不为此引入 @deepseek-ai/dsh-client-ui-tool 依赖)。\n */\nexport interface DeliverableBlock {\n /** 未结算时参数在块本身;结算后搬到 `call` 上。流式中途可能是截断的 JSON。 */\n argsRaw?: string | undefined\n call?: { argsRaw?: string | undefined } | undefined\n content?: ReadonlyArray<{ type: string, text?: string | undefined }> | undefined\n error?: { name?: string | undefined, code?: string | undefined } | undefined\n isError?: boolean | undefined\n}\n\n/** 交付状态:运行中 / 完成 / 中断 / 出错。 */\nexport type DeliverableState = 'running' | 'ok' | 'stopped' | 'error'\n\n/** 展开态里的一行:文件名、所在目录与扩展名徽标已拆好。 */\nexport interface DeliverableFile {\n /** 参数的完整路径,用于悬停提示。 */\n path: string\n /** 文件名部分(正反斜杠都兼容)。 */\n name: string\n /** 所在目录;纯文件名(没有分隔符)时为空串。 */\n dir: string\n /** 扩展名徽标:大写、至多 4 字符;没有扩展名时为 null。 */\n badge: string | null\n}\n\n/** 交付行渲染需要的全部派生结果。 */\nexport interface DeliverableModel {\n state: DeliverableState\n /** 折叠态摘要:单文件报文件名,多文件报「首个 + 数量」;参数未成形时报参数原文。 */\n summary: string\n /** 逐文件数据;参数未成形时为空数组。 */\n files: DeliverableFile[]\n /** 展开后的结果文本(结果无文本时退回错误描述,再没有则为空串)。 */\n details: string\n /** 结果文本的行数;没有文本时为 0。 */\n lineCount: number\n /** 是否有可展开的内容。 */\n expandable: boolean\n}\n\n/**\n * 从参数 JSON 里取文件路径。\n * 截断的 JSON(调用仍在流式输出)返回 null —— 与官方一致:那时原样显示参数\n * 文本,而不是当成「零个文件」。\n * @param raw - 参数 JSON 原文。\n * @returns 路径数组;JSON 未成形时为 null。\n */\nfunction parsePaths(raw: string): string[] | null {\n let args: unknown\n try {\n args = JSON.parse(raw)\n } catch {\n return null\n }\n if (typeof args !== 'object' || args === null || !('files' in args)) return null\n const files = (args as { files?: unknown }).files\n if (!Array.isArray(files)) return null\n return files.flatMap((file: unknown) => {\n if (typeof file !== 'object' || file === null || !('path' in file)) return []\n const path = (file as { path?: unknown }).path\n return typeof path === 'string' ? [path] : []\n })\n}\n\n/** 最后一个路径分隔符的下标;没有分隔符时为 -1。 */\nfunction separatorAt(path: string): number {\n return Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\\\'))\n}\n\n/** 扩展名徽标:最后一个点之后的部分,过长截断;无扩展名返回 null。 */\nfunction extensionBadge(name: string): string | null {\n const dot = name.lastIndexOf('.')\n if (dot <= 0 || dot === name.length - 1) return null\n const ext = name.slice(dot + 1)\n return (ext.length <= 4 ? ext : ext.slice(0, 4)).toUpperCase()\n}\n\n/** 拆一行:路径 → 文件名 + 所在目录 + 扩展名徽标。 */\nfunction fileOf(path: string): DeliverableFile {\n const cut = separatorAt(path)\n const name = cut === -1 ? path : path.slice(cut + 1)\n return { path, name, dir: cut === -1 ? '' : path.slice(0, cut), badge: extensionBadge(name) }\n}\n\n/**\n * 折叠态摘要。\n * `paths === null` 表示参数 JSON 未成形,此时按官方做法原样显示参数文本;解析\n * 成功但一个路径都没取到时返回空串,不把 `{\"files\":[]}` 这种原文当摘要抛出去。\n */\nfunction summaryOf(paths: string[] | null, fallback: string): string {\n if (paths === null) return fallback\n const first = paths[0]\n if (first === undefined) return ''\n const name = fileOf(first).name\n return paths.length === 1 ? name : `${name} 等 ${String(paths.length)} 个文件`\n}\n\n/** 结果文本:把结果节点拼成一段;未结算时没有结果。 */\nfunction outputOf(settled: boolean, block: DeliverableBlock): string {\n if (!settled) return ''\n return (block.content ?? [])\n .map(item => item.type === 'text' ? item.text ?? '' : JSON.stringify(item))\n .join('\\n')\n}\n\n/** 错误描述:没有结果文本时的兜底,比整行空白有用。 */\nfunction errorTextOf(error: DeliverableBlock['error']): string {\n if (error === undefined) return ''\n const name = error.name ?? 'error'\n return error.code === undefined ? name : `${name}: ${error.code}`\n}\n\n/**\n * 派生一次交付的全部渲染数据。\n * @param block - 工具调用/结果块。\n * @returns 状态、折叠摘要、逐文件数据与结果文本。\n */\nexport function deliverableModel(block: DeliverableBlock): DeliverableModel {\n const settled = 'kind' in block\n const state: DeliverableState = !settled\n ? 'running'\n : block.error?.code === 'interrupted'\n ? 'stopped'\n : block.isError === true ? 'error' : 'ok'\n const args = (settled ? block.call?.argsRaw : block.argsRaw) ?? ''\n const output = outputOf(settled, block)\n const details = output !== ''\n ? output\n : settled ? errorTextOf(block.error) : ''\n const paths = parsePaths(args)\n const files = paths?.map(fileOf) ?? []\n return {\n state,\n summary: summaryOf(paths, args),\n files,\n details,\n lineCount: details === '' ? 0 : details.split('\\n').length,\n // 比官方宽:官方只在有结果文本时可展开,这里交付了文件也允许展开看清单。\n expandable: files.length > 0 || details !== '',\n }\n}\n","/**\n * 交付行:接管 `present` 的工具行。\n *\n * 官方 PresentRow 是一个 45 行的折叠行:状态点 + 「交付文件」标题 + **逗号拼接\n * 的文件名** + 可展开的结果文本 + inspect 入口。多文件时那串文件名会挤成一行\n * 读不完,也看不出这一轮交付了几个。\n *\n * 本组件保留官方全部信息与交互(四态、状态词、文件名、结果文本、inspect,以及\n * `data-tool=\"present\"` / `data-state` 这两个样式与快照测试的锚点),另加三件:\n * ① 折叠态文件名只报「首个 + 数量」,多文件不再挤成一行;\n * ② 展开态逐文件成行,带扩展名徽标与所在目录;\n * ③ 结果文本标注行数。\n *\n * 全部派生在 deliverable-model.ts 里,本文件只做 JSX。\n *\n * 接管是 DSH 支持的机制(keyed slot 用不同 priority 遮蔽既有占用者,见\n * ui-slots 的 `register()`;官方插件开发 skill:registering an existing key\n * may replace the product's default card)。代价是本文件要自己承担官方行的\n * 折叠外观 —— 因此行外壳逐项对齐 ToolRow.module.css 与同插件的提问卡\n * (24px 行高、2px 分隔点、13px 次级摘要、running 扫光、hover 才现的\n * Inspect 胶囊),组件全部来自共享 ui-primitives。\n *\n * 下载卡片与「打开」菜单不在这里:它们属于 `conversation.chat.turnTail` 槽的\n * Deliverables 网格,与本 toolview 是两个不同的槽,接管互不影响。\n */\nimport { useState } from 'react'\nimport { DisclosureRow, IconInspectOutline12, StateDot } from '@deepseek-ai/dsh-client-ui-primitives'\nimport {\n deliverableModel, type DeliverableBlock, type DeliverableFile, type DeliverableState,\n} from './deliverable-model.ts'\nimport css from './deliverable-row.module.css'\n\n/** 注入的 locale 翻译函数(注册时声明 `deliverables` 命名空间)。 */\nexport interface DeliverableTranslate {\n (key: string, params?: Record<string, string | number>): string\n}\n\n/** 本行从 slot owner 收到的字段;其余 owner props 与本行无关。 */\nexport interface DeliverableRowProps {\n t: DeliverableTranslate\n block: DeliverableBlock\n /** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */\n inspect?: (() => void) | undefined\n}\n\n/** 状态点的外观名,四态映射与官方 PresentRow 一致。 */\nconst DOT: Record<DeliverableState, 'ongoing' | 'done' | 'warning' | 'error'> = {\n running: 'ongoing',\n ok: 'done',\n stopped: 'warning',\n error: 'error',\n}\n\n/** 逐文件一行:扩展名徽标 + 文件名 + 所在目录(完整路径挂在 title 上)。 */\nfunction FileLine({ file }: { file: DeliverableFile }) {\n return (\n <li className={css.file}>\n {file.badge !== null && <span className={css.ext} aria-hidden>{file.badge}</span>}\n <span className={css.name}>{file.name}</span>\n {file.dir !== '' && <span className={css.path} title={file.path}>{file.dir}</span>}\n </li>\n )\n}\n\n/**\n * 渲染一次交付的完整记录。\n * @param props - locale 翻译函数、调用/结果切片与可选的轨迹入口。\n * @returns 折叠行 + 展开后的文件清单与结果文本。\n */\nexport function DeliverableRow({ t, block, inspect }: DeliverableRowProps) {\n const model = deliverableModel(block)\n const [expanded, setExpanded] = useState(false)\n const open = expanded && model.expandable\n return (\n // data-tool / data-variant / data-state 必须保留:palette.ts 的 TOOL_ROW_ROOT\n // 与其他行样式都按它们匹配(同 ask-card 的约定)。\n <div className={css.root} data-variant=\"others\" data-tool=\"present\" data-state={model.state}>\n <DisclosureRow\n rowClassName={css.row}\n leadingClassName={css.leading}\n titleClassName={css.title}\n chevronClassName={css.chevron}\n icon={<StateDot state={DOT[model.state]} />}\n title={t('row.title')}\n open={open}\n expandable={model.expandable}\n expandOnRowClick\n keepContentWhenOpen\n onToggle={() => { setExpanded(value => !value) }}\n collapsedContent={(\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary}>\n <span className={css.state}>{t(`row.${model.state}`)}</span>\n <span className={css.paths}>{model.summary}</span>\n </span>\n </>\n )}\n >\n <div className={css.bodyWrap}>\n {model.files.length > 0 && (\n <ul className={css.files} aria-label={t('presented.all', { count: model.files.length })}>\n {model.files.map((file, index) => (\n <FileLine key={`${String(index)}-${file.path}`} file={file} />\n ))}\n </ul>\n )}\n {model.details !== '' && (\n <>\n {model.files.length > 0 && <div className={css.meta}>{`输出 ${String(model.lineCount)} 行`}</div>}\n <pre className={css.output}>{model.details}</pre>\n </>\n )}\n {inspect !== undefined && (\n <button type=\"button\" className={css.inspectButton} onClick={inspect}>\n <IconInspectOutline12 />\n {t('row.inspect')}\n </button>\n )}\n </div>\n </DisclosureRow>\n </div>\n )\n}\n","/**\n * 目标详情折叠条:接在官方 GoalBar 下面(`conversation.input.dock` 里\n * `order: 11`,官方那条是 10),把官方条上被 ellipsis 截断的目标展开成可读\n * 详情。\n *\n * 卡片形态照同槽的待办面板(ui-conversation 的 TodoPanel):同一套 dock 宽度\n * 公式、同一张 `--dsw-specific-tip` 卡片、同一个「标题 + 右侧摘要 + chevron」\n * 折叠头,默认收起。折叠头只放官方条**没有**的元信息(版本号、自主轮次),\n * 目标原文放在展开区 —— 这样两块不会互相重复。\n *\n * 为什么是「另加一条」而不是接管官方条:`conversation.input.dock` 是 list\n * 槽,不同 id 各自成格并列渲染;而官方 ui-goal 的注入面(edit/pause/resume/\n * clear 四个 Remote 动词 + 一个带竞态防护的 activation 订阅源)是**注册者\n * 私有**的,接管就得整套复刻 —— 那会把这个「只读地多看一行」的需求变成\n * 插件里多一处会写会话数据的 RPC 客户端。这里只读 `useProjection('goal')`。\n */\nimport { useEffect, useState } from 'react'\nimport {\n IconChevronDownOutline14, IconChevronUpOutline14, IconGoalOutline16,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ReactNode } from 'react'\nimport css from './goal-detail.module.css'\n\n/** 投影里本卡渲染的字段(照 DSH 的 `GoalSnapshot` 声明为鸭子类型)。 */\nexport interface GoalSnapshotLike {\n id: string\n revision: number\n objective: string\n phase: 'active' | 'paused' | 'blocked' | 'complete'\n /** 自主轮次上限;未设置时为 undefined。 */\n maxGoalRounds?: number | undefined\n /** 已开始的自主轮次;旧快照可能没有该字段。 */\n roundsStarted?: number | undefined\n /** 仅 blocked 阶段存在。 */\n blockedReason?: { code: string; message: string } | undefined\n}\n\n/** `useProjection('goal')` 的返回形状。 */\nexport interface GoalProjectionLike {\n goal: GoalSnapshotLike\n}\n\n/** 本卡从 slot 标准 props 取用的部分(其余 owner props 与本卡无关)。 */\nexport interface GoalDetailProps {\n /** 框架标准投影席位:按 key 读当前会话的投影。 */\n useProjection: (key: string) => GoalProjectionLike | null | undefined\n}\n\n/** 阶段文案:与官方 goal 字典同义,按本插件既有做法直写中文。 */\nconst PHASE_LABEL: Record<GoalSnapshotLike['phase'], string> = {\n active: '进行中',\n paused: '已暂停',\n blocked: '已阻塞',\n complete: '已完成',\n}\n\n/** 折叠头右侧摘要:只放官方条没有的元信息。 */\nfunction summaryLabel(goal: GoalSnapshotLike): string {\n const parts = [`rev ${String(goal.revision)}`]\n if (goal.roundsStarted !== undefined) {\n parts.push(goal.maxGoalRounds === undefined\n ? `${String(goal.roundsStarted)} 轮`\n : `${String(goal.roundsStarted)} / ${String(goal.maxGoalRounds)} 轮`)\n }\n return parts.join('\\u2002·\\u2002')\n}\n\n/** 展开区里的一组「键 / 值」。 */\nfunction Row({ label, children }: { label: string; children: ReactNode }) {\n return (\n <div className={css.row}>\n <dt className={css.key}>{label}</dt>\n <dd className={css.value}>{children}</dd>\n </div>\n )\n}\n\n/**\n * 渲染目标详情折叠条。\n * @param props - 框架标准投影席位。\n * @returns 折叠条;加载中、无目标、或目标已完成时不渲染(与官方条一致)。\n */\nexport function GoalDetail({ useProjection }: GoalDetailProps) {\n const projection = useProjection('goal')\n const [collapsed, setCollapsed] = useState(true)\n const goalId = projection?.goal.id\n\n // 目标换了一个(新建 / 清除后重建)就收起:否则展开态会挂在新目标上。\n useEffect(() => { setCollapsed(true) }, [goalId])\n\n const goal = projection?.goal\n if (goal === undefined || goal === null || goal.phase === 'complete') return null\n\n return (\n <section className={css.root} data-goal-detail aria-label=\"目标详情\">\n <div className={css.body}>\n <button\n type=\"button\"\n className={css.header}\n aria-expanded={!collapsed}\n onClick={() => { setCollapsed(value => !value) }}\n >\n <span className={css.lead} aria-hidden><IconGoalOutline16 size={14} /></span>\n <span className={css.title}>目标详情</span>\n <span className={css.summary}>{summaryLabel(goal)}</span>\n <span className={css.chevron} aria-hidden>\n {collapsed ? <IconChevronUpOutline14 /> : <IconChevronDownOutline14 />}\n </span>\n </button>\n {!collapsed && (\n <dl className={css.detail}>\n <Row label=\"目标\">{goal.objective}</Row>\n <Row label=\"阶段\">{PHASE_LABEL[goal.phase]}</Row>\n {goal.blockedReason !== undefined && (\n <Row label=\"阻塞\">\n {goal.blockedReason.message}\n <span className={css.code}>{goal.blockedReason.code}</span>\n </Row>\n )}\n <Row label=\"标识\">\n <span className={css.code}>{goal.id}</span>\n </Row>\n </dl>\n )}\n </div>\n </section>\n )\n}\n","/**\n * Browser half: binds the `node-appearance` settings scope, paints the chat\n * flow from it (a single <style data-plugin-css> tag rebuilt on every\n * snapshot change), and registers the settings card.\n */\n\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: the ctx.settingsScope Context merge and the slot's declaration.\n// Cross-plugin collaboration goes through cordis services; a value import\n// would fail the client bundle-purity gate.\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'\n// Type-only: the ctx.slots Context merge comes from the renderer package\n// (slot registry), not from the removed dsh-client-runtime module.\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport { buildCss, NODE_APPEARANCE_NS, STYLE_TAG_ID, type NodeAppearanceSettings } from './palette.ts'\nimport { NodeAppearanceRow, type NodeAppearanceRowFace } from './settings-card.tsx'\nimport { AskQuestionRow } from './ask-card.tsx'\nimport { DeliverableRow } from './deliverable-row.tsx'\nimport { GoalDetail } from './goal-detail.tsx'\n\nexport const inject = ['slots', 'connection', 'remote', 'settingsScope']\n\n/** Upsert the plugin's paint stylesheet with the current snapshot's CSS. */\nfunction paint(scope: SettingsScope<NodeAppearanceSettings>): void {\n let tag = document.querySelector<HTMLStyleElement>(`style[data-plugin-css=\"${STYLE_TAG_ID}\"]`)\n if (tag === null) {\n tag = document.createElement('style')\n tag.dataset.plugin = NODE_APPEARANCE_NS\n tag.dataset.pluginCss = STYLE_TAG_ID\n document.head.appendChild(tag)\n }\n tag.textContent = buildCss(scope.getSnapshot().value)\n}\n\n/**\n * Mount the node-appearance plugin on the page.\n * @param ctx - client root context.\n */\nexport function apply(ctx: ClientContext): void {\n // settingsScope 由官方 ui-settings 服务提供(DSH 0.1.2-alpha 内核 client\n // 模块表);bind 返回该命名空间的强类型 scope(read/set/unset/subscribe)。\n const scope = ctx.settingsScope.bind<NodeAppearanceSettings>({ namespace: NODE_APPEARANCE_NS })\n // Paint once from the current snapshot (defaults before the first Host read).\n paint(scope)\n ctx.effect(\n () => scope.subscribe(() => { paint(scope) }),\n 'dsh-node-appearance: repaint on settings change',\n )\n\n const face: NodeAppearanceRowFace = {\n hooks: { nodeAppearance: scope },\n // Staged-edit save: write the three keys in one face call (Host settles\n // the whole namespace; per-key resolution keeps observable semantics).\n apply: async (value) => {\n await scope.set('showThinking', value.showThinking ?? true)\n await scope.set('colors', value.colors ?? {})\n await scope.set('toolColors', value.toolColors ?? {})\n },\n setShowThinking: (show) => { void scope.set('showThinking', show) },\n setCategoryColor: (category, color) => {\n const value = scope.getSnapshot().value\n void scope.set('colors', { ...value?.colors, [category]: color })\n },\n setToolColor: (tool, color) => {\n const value = scope.getSnapshot().value\n void scope.set('toolColors', { ...value?.toolColors, [tool]: color })\n },\n removeToolColor: (tool) => {\n const value = scope.getSnapshot().value\n const toolColors = { ...value?.toolColors }\n delete toolColors[tool]\n void scope.set('toolColors', toolColors)\n },\n }\n\n // alpha.2:General 区 slot(settings.general.item)已退役,接入官方\n // 「可配置插件」Tab 的 settings.plugin.item(keyed by namespace)——官方\n // 卡片姿势见 dsh-client-ui-settings-plugins/src/client/index.ts(BashCard 等)。\n ctx.slots.inject('settings.plugin.item', () => ctx.slots.register({\n name: 'settings.plugin.item',\n key: NODE_APPEARANCE_NS,\n inject: () => face,\n // npm ui-slots (0.0.1-rc.1) 类型未合并 keyed-slot 选项(官方 monorepo 类型\n // 才有)——运行时与官方源码一致,类型期放宽(官方类型同步后收紧)。\n } as never, NodeAppearanceRow))\n\n // 接管官方提问卡。官方 ui-tool 在 `tool.call.toolview` 的\n // `ask_user_question` key 上有一条 priority 0 的注册,而 keyed cell 只\n // 渲染最低 priority 的条目(ui-slots `register()` 的 shadowing 规则),\n // priority -1 因此遮蔽它——这是 DSH 支持的接管姿势(ui-tool 的 slot 契约\n // 原文:a key the shipped composition already covers is replaced, not shared)。\n //\n // 接管的唯一原因:官方转录卡只保留已选答案,把调用参数里的 `options`\n // 丢掉了,提问一旦结算就再也看不到当时有哪些选项(详见 ask-model.ts)。\n //\n // 类型期放宽同 settings 那条:`tool.call.toolview` 的 SlotMap 声明属于官方\n // @deepseek-ai/dsh-client-ui-tool,本插件不为此引入依赖。\n ctx.slots.inject('tool.call.toolview' as never, () => ctx.slots.register({\n name: 'tool.call.toolview',\n key: 'ask_user_question',\n priority: -1,\n // 复用官方 conversation 字典:卡片文案(提问 / N/M 已回答 / 未回答 /\n // 查看 …)全部取自它,插件不新造 locale 命名空间。\n locale: 'conversation',\n } as never, AskQuestionRow as never))\n\n // 接管官方交付行。姿势与理由同提问卡:ui-deliverables 在 `tool.call.toolview`\n // 的 `present` key 上有一条 priority 0 的注册,keyed cell 只渲染最低 priority\n // 的条目,priority -1 因此遮蔽它。\n //\n // 接管的唯一原因:官方折叠态把全部文件名逗号拼成一行,多文件时读不完,也看不出\n // 这一轮交付了几个(详见 deliverable-row.tsx)。\n ctx.slots.inject('tool.call.toolview' as never, () => ctx.slots.register({\n name: 'tool.call.toolview',\n key: 'present',\n priority: -1,\n // 复用官方 deliverables 字典:「交付文件 / 正在交付 / 已交付 / 交付失败 /\n // 已中断 / 查看调用」全部取自它,插件不新造 locale 命名空间。\n locale: 'deliverables',\n } as never, DeliverableRow as never))\n\n // 目标详情折叠条:挂进输入框上方的 `conversation.input.dock`(list 槽,\n // 不同 id 各自成格、并列渲染),order 11 紧随官方 ui-goal 的 order 10 ——\n // 官方条只显示一行被 ellipsis 截断的目标,这里补一个可展开的详情。\n //\n // 只读 `useProjection('goal')`,不碰官方条的 edit/pause/resume/clear ——\n // 那四个 Remote 动词与 activation 订阅源都是 ui-goal 的注册者私有注入面,\n // 接管它们等于在本插件里再养一套会写会话数据的 RPC 客户端。\n ctx.slots.inject('conversation.input.dock' as never, () => ctx.slots.register({\n name: 'conversation.input.dock',\n id: 'max-null/goal-detail',\n order: 11,\n } as never, GoalDetail as never))\n}\n"],"mappings":"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"}
package/lib/index.js CHANGED
@@ -11,6 +11,7 @@ const DEFAULT_COLORS = {
11
11
  agent: "#a855f7",
12
12
  execute: "#f59e0b",
13
13
  file: "#22c55e",
14
+ deliver: "#06b6d4",
14
15
  task: "#ec4899",
15
16
  ask: "#65a30d",
16
17
  command: "#f97316",
@@ -26,6 +27,7 @@ const Config = z.object({
26
27
  agent: z.string().default(DEFAULT_COLORS.agent),
27
28
  execute: z.string().default(DEFAULT_COLORS.execute),
28
29
  file: z.string().default(DEFAULT_COLORS.file),
30
+ deliver: z.string().default(DEFAULT_COLORS.deliver),
29
31
  task: z.string().default(DEFAULT_COLORS.task),
30
32
  ask: z.string().default(DEFAULT_COLORS.ask),
31
33
  command: z.string().default(DEFAULT_COLORS.command),
@@ -0,0 +1,69 @@
1
+ /**
2
+ * 交付行数据派生:把一次 `present` 调用还原成「状态 + 文件清单 + 结果文本」。
3
+ *
4
+ * 为什么要自己解析:官方 PresentRow 的折叠态把全部文件名逗号拼成一行
5
+ * (`ui-deliverables/src/client/PresentRow.tsx` 的 `fileNames()`),多文件时读不完,
6
+ * 也看不出这一轮交付了几个。完整清单只存在于调用的参数 JSON 里,所以折叠摘要与
7
+ * 展开态都得自己解一份。
8
+ *
9
+ * 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错(接管后
10
+ * 行由我们渲染,渲染不出来就等于用户什么都看不到)。
11
+ *
12
+ * 「等 N 个文件」这类摘要文案直写中文,与 goal-detail.tsx 同一取径:本插件不新造
13
+ * locale 命名空间,而官方 deliverables 字典没有「共计 N 个」的 key(`presented.more`
14
+ * 是「+ N 个文件」,用于溢出提示)。行内的标题、状态词与 inspect 仍取自官方字典。
15
+ */
16
+ /**
17
+ * 工具调用块里本行取用的字段(照官方 PresentRow 的取用面声明为鸭子类型,
18
+ * 不为此引入 @deepseek-ai/dsh-client-ui-tool 依赖)。
19
+ */
20
+ export interface DeliverableBlock {
21
+ /** 未结算时参数在块本身;结算后搬到 `call` 上。流式中途可能是截断的 JSON。 */
22
+ argsRaw?: string | undefined;
23
+ call?: {
24
+ argsRaw?: string | undefined;
25
+ } | undefined;
26
+ content?: ReadonlyArray<{
27
+ type: string;
28
+ text?: string | undefined;
29
+ }> | undefined;
30
+ error?: {
31
+ name?: string | undefined;
32
+ code?: string | undefined;
33
+ } | undefined;
34
+ isError?: boolean | undefined;
35
+ }
36
+ /** 交付状态:运行中 / 完成 / 中断 / 出错。 */
37
+ export type DeliverableState = 'running' | 'ok' | 'stopped' | 'error';
38
+ /** 展开态里的一行:文件名、所在目录与扩展名徽标已拆好。 */
39
+ export interface DeliverableFile {
40
+ /** 参数的完整路径,用于悬停提示。 */
41
+ path: string;
42
+ /** 文件名部分(正反斜杠都兼容)。 */
43
+ name: string;
44
+ /** 所在目录;纯文件名(没有分隔符)时为空串。 */
45
+ dir: string;
46
+ /** 扩展名徽标:大写、至多 4 字符;没有扩展名时为 null。 */
47
+ badge: string | null;
48
+ }
49
+ /** 交付行渲染需要的全部派生结果。 */
50
+ export interface DeliverableModel {
51
+ state: DeliverableState;
52
+ /** 折叠态摘要:单文件报文件名,多文件报「首个 + 数量」;参数未成形时报参数原文。 */
53
+ summary: string;
54
+ /** 逐文件数据;参数未成形时为空数组。 */
55
+ files: DeliverableFile[];
56
+ /** 展开后的结果文本(结果无文本时退回错误描述,再没有则为空串)。 */
57
+ details: string;
58
+ /** 结果文本的行数;没有文本时为 0。 */
59
+ lineCount: number;
60
+ /** 是否有可展开的内容。 */
61
+ expandable: boolean;
62
+ }
63
+ /**
64
+ * 派生一次交付的全部渲染数据。
65
+ * @param block - 工具调用/结果块。
66
+ * @returns 状态、折叠摘要、逐文件数据与结果文本。
67
+ */
68
+ export declare function deliverableModel(block: DeliverableBlock): DeliverableModel;
69
+ //# sourceMappingURL=deliverable-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliverable-model.d.ts","sourceRoot":"","sources":["../../../src/client/deliverable-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAA;IACnD,OAAO,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,GAAG,SAAS,CAAA;IAChF,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAA;IAC5E,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC9B;AAED,+BAA+B;AAC/B,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAA;AAErE,iCAAiC;AACjC,MAAM,WAAW,eAAe;IAC9B,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,sBAAsB;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,qCAAqC;IACrC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAED,sBAAsB;AACtB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,gBAAgB,CAAA;IACvB,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAA;IACf,wBAAwB;IACxB,KAAK,EAAE,eAAe,EAAE,CAAA;IACxB,sCAAsC;IACtC,OAAO,EAAE,MAAM,CAAA;IACf,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,iBAAiB;IACjB,UAAU,EAAE,OAAO,CAAA;CACpB;AA0ED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,gBAAgB,CAuB1E"}
@@ -0,0 +1,19 @@
1
+ import { type DeliverableBlock } from './deliverable-model.ts';
2
+ /** 注入的 locale 翻译函数(注册时声明 `deliverables` 命名空间)。 */
3
+ export interface DeliverableTranslate {
4
+ (key: string, params?: Record<string, string | number>): string;
5
+ }
6
+ /** 本行从 slot owner 收到的字段;其余 owner props 与本行无关。 */
7
+ export interface DeliverableRowProps {
8
+ t: DeliverableTranslate;
9
+ block: DeliverableBlock;
10
+ /** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */
11
+ inspect?: (() => void) | undefined;
12
+ }
13
+ /**
14
+ * 渲染一次交付的完整记录。
15
+ * @param props - locale 翻译函数、调用/结果切片与可选的轨迹入口。
16
+ * @returns 折叠行 + 展开后的文件清单与结果文本。
17
+ */
18
+ export declare function DeliverableRow({ t, block, inspect }: DeliverableRowProps): import("react").JSX.Element;
19
+ //# sourceMappingURL=deliverable-row.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliverable-row.d.ts","sourceRoot":"","sources":["../../../src/client/deliverable-row.tsx"],"names":[],"mappings":"AA2BA,OAAO,EACa,KAAK,gBAAgB,EACxC,MAAM,wBAAwB,CAAA;AAG/B,kDAAkD;AAClD,MAAM,WAAW,oBAAoB;IACnC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAAA;CAChE;AAED,iDAAiD;AACjD,MAAM,WAAW,mBAAmB;IAClC,CAAC,EAAE,oBAAoB,CAAA;IACvB,KAAK,EAAE,gBAAgB,CAAA;IACvB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;CACnC;AAqBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,mBAAmB,+BAsDxE"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAenE,eAAO,MAAM,MAAM,UAAqD,CAAA;AAcxE;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAgF9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAgBnE,eAAO,MAAM,MAAM,UAAqD,CAAA;AAcxE;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA+F9C"}
@@ -10,7 +10,7 @@ export declare const NODE_APPEARANCE_NS = "node-appearance";
10
10
  /** The plugin's style tag identity (removed/replaced on every re-paint). */
11
11
  export declare const STYLE_TAG_ID = "node-appearance/rules";
12
12
  /** One paintable node category. `command`, `thinking`, `context` are non-tool rows. */
13
- export type NodeCategory = 'search' | 'agent' | 'execute' | 'file' | 'task' | 'ask' | 'command' | 'thinking' | 'context' | 'steering' | 'other';
13
+ export type NodeCategory = 'search' | 'agent' | 'execute' | 'file' | 'deliver' | 'task' | 'ask' | 'command' | 'thinking' | 'context' | 'steering' | 'other';
14
14
  /** Accent color per category (CSS colors). */
15
15
  export type NodeAppearanceColors = Record<NodeCategory, string>;
16
16
  /** The settings value this plugin reads from its namespace scope. */
@@ -1 +1 @@
1
- {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../../src/client/palette.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,oFAAoF;AACpF,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AAEnD,4EAA4E;AAC5E,eAAO,MAAM,YAAY,0BAAgC,CAAA;AAEzD,uFAAuF;AACvF,MAAM,MAAM,YAAY,GACpB,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAA;AAExH,8CAA8C;AAC9C,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;AAE/D,qEAAqE;AACrE,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAClC,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAA;IAClD,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;CAChD;AAED,kFAAkF;AAClF,eAAO,MAAM,cAAc,EAAE,oBAY5B,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAQ7H,CAAA;AA6BD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAKjD;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,sBAAsB,GAAG,oBAAoB,CAUpF;AAcD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,GAAG,SAAS,GAAG,MAAM,CAkF7E"}
1
+ {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../../src/client/palette.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,oFAAoF;AACpF,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AAEnD,4EAA4E;AAC5E,eAAO,MAAM,YAAY,0BAAgC,CAAA;AAEzD,uFAAuF;AACvF,MAAM,MAAM,YAAY,GACpB,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAA;AAEpI,8CAA8C;AAC9C,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;AAE/D,qEAAqE;AACrE,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAClC,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAA;IAClD,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAA;CAChD;AAED,kFAAkF;AAClF,eAAO,MAAM,cAAc,EAAE,oBAa5B,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,OAAO,CAAC,YAAY,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAS7H,CAAA;AA6BD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAKjD;AAED,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,sBAAsB,GAAG,oBAAoB,CAUpF;AAcD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,GAAG,SAAS,GAAG,MAAM,CAkF7E"}
@@ -1 +1 @@
1
- {"version":3,"file":"settings-card.d.ts","sourceRoot":"","sources":["../../../src/client/settings-card.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AACvE,OAAO,KAAK,EAAiB,qBAAqB,EAAE,MAAM,4CAA4C,CAAA;AAEtG,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEhF,OAAO,EAEL,KAAK,sBAAsB,EAAE,KAAK,YAAY,EAC/C,MAAM,cAAc,CAAA;AAGrB,+EAA+E;AAC/E,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE;QACL,wEAAwE;QACxE,cAAc,EAAE,kBAAkB,CAAC,qBAAqB,CAAC,sBAAsB,CAAC,CAAC,CAAA;KAClF,CAAA;IACD,oFAAoF;IACpF,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,yCAAyC;IACzC,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACpC,yDAAyD;IACzD,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7D,2DAA2D;IAC3D,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/C,gCAAgC;IAChC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC;AAED,4DAA4D;AAC5D,MAAM,MAAM,sBAAsB,GAChC,YAAY,CAAC,sBAAsB,CAAC,GAClC,UAAU,CAAC,qBAAqB,CAAC,CAAA;AA2CrC;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,sBAAsB,+BA8HvJ"}
1
+ {"version":3,"file":"settings-card.d.ts","sourceRoot":"","sources":["../../../src/client/settings-card.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAA;AACvE,OAAO,KAAK,EAAiB,qBAAqB,EAAE,MAAM,4CAA4C,CAAA;AAEtG,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAEhF,OAAO,EAEL,KAAK,sBAAsB,EAAE,KAAK,YAAY,EAC/C,MAAM,cAAc,CAAA;AAGrB,+EAA+E;AAC/E,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE;QACL,wEAAwE;QACxE,cAAc,EAAE,kBAAkB,CAAC,qBAAqB,CAAC,sBAAsB,CAAC,CAAC,CAAA;KAClF,CAAA;IACD,oFAAoF;IACpF,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,yCAAyC;IACzC,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACpC,yDAAyD;IACzD,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7D,2DAA2D;IAC3D,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/C,gCAAgC;IAChC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC;AAED,4DAA4D;AAC5D,MAAM,MAAM,sBAAsB,GAChC,YAAY,CAAC,sBAAsB,CAAC,GAClC,UAAU,CAAC,qBAAqB,CAAC,CAAA;AA4CrC;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,eAAe,EAAE,EAAE,sBAAsB,+BA8HvJ"}
@@ -17,6 +17,7 @@ export interface NodeAppearanceColors {
17
17
  agent: string;
18
18
  execute: string;
19
19
  file: string;
20
+ deliver: string;
20
21
  task: string;
21
22
  ask: string;
22
23
  command: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,eAAO,MAAM,IAAI,wBAAwB,CAAA;AAEzC;;sDAEsD;AACtD,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AAEnD,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,0EAA0E;AAC1E,MAAM,WAAW,MAAM;IACrB,uFAAuF;IACvF,YAAY,EAAE,OAAO,CAAA;IACrB,kCAAkC;IAClC,MAAM,EAAE,oBAAoB,CAAA;IAC5B,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAED,kFAAkF;AAClF,eAAO,MAAM,cAAc,EAAE,oBAY5B,CAAA;AAED,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAgB3B,CAAA;AAEF;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAUxD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,eAAO,MAAM,IAAI,wBAAwB,CAAA;AAEzC;;sDAEsD;AACtD,eAAO,MAAM,kBAAkB,oBAAoB,CAAA;AAEnD,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,0EAA0E;AAC1E,MAAM,WAAW,MAAM;IACrB,uFAAuF;IACvF,YAAY,EAAE,OAAO,CAAA;IACrB,kCAAkC;IAClC,MAAM,EAAE,oBAAoB,CAAA;IAC5B,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACnC;AAED,kFAAkF;AAClF,eAAO,MAAM,cAAc,EAAE,oBAa5B,CAAA;AAED,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAiB3B,CAAA;AAEF;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAUxD"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@max-null/dsh-node-appearance",
3
- "version": "0.4.0",
4
- "description": "会话节点外观插件:节点/工具分类着色(可配置)、提问卡展示全部选项并高亮选中、目标详情折叠条、思考过程显示开关(DeepSeek Harness Web GUI)",
3
+ "version": "0.5.0",
4
+ "description": "会话节点外观插件:节点/工具分类着色(可配置)、提问卡展示全部选项并高亮选中、交付文件清单展开、目标详情折叠条、思考过程显示开关(DeepSeek Harness Web GUI)",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
7
7
  "access": "public"