@max-null/dsh-node-appearance 0.3.6 → 0.4.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 +12 -1
- package/docs/shots//344/274/232/350/257/235/351/235/242/346/235/277/346/210/252/345/233/276.png +0 -0
- package/docs/shots//346/217/220/351/227/256/345/215/241/347/211/207/346/210/252/345/233/276.png +0 -0
- package/docs/shots//347/233/256/346/240/207/350/257/246/346/203/205-/345/261/225/345/274/200.png +0 -0
- package/docs/shots//347/233/256/346/240/207/350/257/246/346/203/205-/346/212/230/345/217/240.png +0 -0
- package/docs/shots//350/256/276/347/275/256/351/241/265/346/210/252/345/233/276.png +0 -0
- package/lib/client.js +526 -26
- package/lib/client.js.map +1 -1
- package/lib/index.js +2 -0
- package/lib/types/client/ask-card.d.ts +19 -0
- package/lib/types/client/ask-card.d.ts.map +1 -0
- package/lib/types/client/ask-model.d.ts +92 -0
- package/lib/types/client/ask-model.d.ts.map +1 -0
- package/lib/types/client/goal-detail.d.ts +32 -0
- package/lib/types/client/goal-detail.d.ts.map +1 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/palette.d.ts +1 -1
- package/lib/types/client/palette.d.ts.map +1 -1
- package/lib/types/client/settings-card.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@ This plugin belongs to the **`@max-null/*` family** — a set of plugins that to
|
|
|
10
10
|
|
|
11
11
|
- **节点着色**:工具调用、联网搜索、智能体调用、代码 / 指令执行、文件操作、任务 / 目标、指令节点(`/command`)、思考行(Think)——每种类别一个可配置颜色,左侧 3px 色条 + 淡色底,深 / 浅主题均可读。
|
|
12
12
|
- **工具级颜色覆盖**:任意工具名(如 `web_search`、`subagent`、`run_code`)可单独指定颜色,优先级高于类别色。
|
|
13
|
+
- **提问卡片**:`ask_user_question` 的卡片改为展示**当时给出的全部选项**,被选中的选项用 `ask` 类别色(默认蓝)反显并打勾。官方转录卡只保留已选答案,提问一旦结算就再也看不到其他选项 —— 本插件把选项读回来。
|
|
14
|
+
- **目标条详情**:官方目标条下方接一条**与它拼成同一张卡**的详情行(借待办卡片的折叠形态),把官方条上被 ellipsis 截断的目标展开成可读详情:完整目标、阶段、阻塞原因、自主轮次、目标标识。只读投影,不碰官方的编辑/暂停/清除,那四个按钮仍是官方在跑。
|
|
13
15
|
- **思考过程显示开关**:关闭后 Think 思考行前端隐藏(`display: none`),配置项与配色在同一张设置卡片里。
|
|
14
16
|
- **即时生效**:设置改动立即重绘会话,并持久化到 DSH 用户设置文档(`$DSH_HOME/settings.yaml`)。
|
|
15
17
|
|
|
@@ -19,6 +21,10 @@ This plugin belongs to the **`@max-null/*` family** — a set of plugins that to
|
|
|
19
21
|
|---|---|
|
|
20
22
|
|  |  |
|
|
21
23
|
|
|
24
|
+
| 提问卡片 | 目标条(折叠 / 展开) |
|
|
25
|
+
|---|---|
|
|
26
|
+
|  |   |
|
|
27
|
+
|
|
22
28
|
## 安装
|
|
23
29
|
|
|
24
30
|
```sh
|
|
@@ -49,6 +55,7 @@ node-appearance:
|
|
|
49
55
|
execute: '#f59e0b' # 代码 / 指令执行
|
|
50
56
|
file: '#22c55e' # 文件操作
|
|
51
57
|
task: '#ec4899' # 任务 / 目标
|
|
58
|
+
ask: '#65a30d' # 提问卡片
|
|
52
59
|
command: '#f97316' # 指令节点
|
|
53
60
|
thinking: '#c4b5fd' # 思考过程
|
|
54
61
|
context: '#8a9bb5' # 上下文注入
|
|
@@ -63,10 +70,14 @@ node-appearance:
|
|
|
63
70
|
- Host half 通过 `installSettingsSection` 注册 `node-appearance` settings namespace,插件配置作为 base 层。
|
|
64
71
|
- Browser half 绑定 `ctx.settingsScope`,把快照交给纯函数 `buildCss()` 生成 CSS,注入一个 `<style data-plugin-css="node-appearance/rules">` 标签;快照变化即重绘。
|
|
65
72
|
- 着色目标全部使用 DSH 会话 DOM 的稳定 data 属性(`data-chat-flow-kind` / `data-tool` / `data-variant`),不依赖任何 CSS Modules 哈希类名。
|
|
73
|
+
- 提问卡片是**接管**而非样式覆盖:`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` 字典。
|
|
74
|
+
- 目标详情折叠条是**并列追加**而非接管:`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 客户端。
|
|
66
75
|
|
|
67
76
|
## 已知限制
|
|
68
77
|
|
|
69
78
|
- v0.1 不做运行态动画与节点折叠。
|
|
79
|
+
- 提问卡是接管式实现:组件来自共享 `ui-primitives`、业务字段只读调用与结果的 JSON,但官方 `ask_user_question` 的行外壳若变更,插件需同步。
|
|
80
|
+
- 提问卡高度随内容自适应、不做卡片内滚动;选项极多时由整条会话流承担滚动。
|
|
70
81
|
- 命令节点只有类别色(`command`),暂无命令名级配色。
|
|
71
82
|
- `toolColors` 按工具名精确匹配;DSH 工具名变更时旧条目静默失效(可在设置面板删除)。
|
|
72
83
|
|
|
@@ -75,7 +86,7 @@ node-appearance:
|
|
|
75
86
|
```sh
|
|
76
87
|
npm install
|
|
77
88
|
npm run typecheck # tsc
|
|
78
|
-
npm test # vitest(CSS 规则生成 + Config schema
|
|
89
|
+
npm test # vitest(CSS 规则生成 + Config schema + 提问卡派生)
|
|
79
90
|
npm run build # tsc 类型 + tsdown(lib/index.js + lib/client.js)
|
|
80
91
|
```
|
|
81
92
|
|
package/docs/shots//344/274/232/350/257/235/351/235/242/346/235/277/346/210/252/345/233/276.png
ADDED
|
Binary file
|
package/docs/shots//346/217/220/351/227/256/345/215/241/347/211/207/346/210/252/345/233/276.png
ADDED
|
Binary file
|
package/docs/shots//347/233/256/346/240/207/350/257/246/346/203/205-/345/261/225/345/274/200.png
ADDED
|
Binary file
|
package/docs/shots//347/233/256/346/240/207/350/257/246/346/203/205-/346/212/230/345/217/240.png
ADDED
|
Binary file
|
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -26,6 +26,7 @@ window.__ModuleLoader__.load({
|
|
|
26
26
|
execute: "#f59e0b",
|
|
27
27
|
file: "#22c55e",
|
|
28
28
|
task: "#ec4899",
|
|
29
|
+
ask: "#65a30d",
|
|
29
30
|
command: "#f97316",
|
|
30
31
|
thinking: "#c4b5fd",
|
|
31
32
|
context: "#8a9bb5",
|
|
@@ -78,6 +79,7 @@ window.__ModuleLoader__.load({
|
|
|
78
79
|
"schedule_list",
|
|
79
80
|
"exit_plan_mode"
|
|
80
81
|
],
|
|
82
|
+
ask: ["ask_user_question"],
|
|
81
83
|
other: []
|
|
82
84
|
};
|
|
83
85
|
/** Selector matching every tool row inside a tool-call node. */
|
|
@@ -192,45 +194,45 @@ window.__ModuleLoader__.load({
|
|
|
192
194
|
}
|
|
193
195
|
//#endregion
|
|
194
196
|
//#region \0dsh-css:H:\MaxNull\WorkStation\max-null-plugins\dsh-node-appearance\src\client\card.module.css.mjs
|
|
195
|
-
const css = ".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}";
|
|
196
|
-
const tagId = "@max-null/dsh-node-appearance/card.module.css";
|
|
197
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
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) {
|
|
198
200
|
const tag = document.createElement("style");
|
|
199
201
|
tag.dataset.plugin = "@max-null/dsh-node-appearance";
|
|
200
|
-
tag.dataset.pluginCss = tagId;
|
|
201
|
-
tag.textContent = css;
|
|
202
|
+
tag.dataset.pluginCss = tagId$2;
|
|
203
|
+
tag.textContent = css$2;
|
|
202
204
|
document.head.appendChild(tag);
|
|
203
205
|
}
|
|
204
206
|
var card_module_css_default = {
|
|
205
|
-
"
|
|
207
|
+
"resetConfirm": "CDqThG_resetConfirm",
|
|
208
|
+
"body": "CDqThG_body",
|
|
209
|
+
"statusLine": "CDqThG_statusLine",
|
|
206
210
|
"header": "CDqThG_header",
|
|
207
|
-
"
|
|
208
|
-
"
|
|
209
|
-
"chevron": "CDqThG_chevron",
|
|
211
|
+
"cardOpen": "CDqThG_cardOpen",
|
|
212
|
+
"switch": "CDqThG_switch",
|
|
210
213
|
"rowHint": "CDqThG_rowHint",
|
|
211
|
-
"
|
|
212
|
-
"addButton": "CDqThG_addButton",
|
|
213
|
-
"sectionTitle": "CDqThG_sectionTitle",
|
|
214
|
+
"toolInput": "CDqThG_toolInput",
|
|
214
215
|
"headText": "CDqThG_headText",
|
|
216
|
+
"addButton": "CDqThG_addButton",
|
|
217
|
+
"disabled": "CDqThG_disabled",
|
|
218
|
+
"chevronOpen": "CDqThG_chevronOpen",
|
|
219
|
+
"row": "CDqThG_row",
|
|
220
|
+
"knob": "CDqThG_knob",
|
|
221
|
+
"chevron": "CDqThG_chevron",
|
|
215
222
|
"colorInput": "CDqThG_colorInput",
|
|
216
|
-
"
|
|
217
|
-
"
|
|
218
|
-
"resetConfirm": "CDqThG_resetConfirm",
|
|
219
|
-
"on": "CDqThG_on",
|
|
223
|
+
"name": "CDqThG_name",
|
|
224
|
+
"sectionTitle": "CDqThG_sectionTitle",
|
|
220
225
|
"description": "CDqThG_description",
|
|
221
|
-
"row": "CDqThG_row",
|
|
222
226
|
"addRow": "CDqThG_addRow",
|
|
227
|
+
"removeButton": "CDqThG_removeButton",
|
|
228
|
+
"card": "CDqThG_card",
|
|
223
229
|
"footer": "CDqThG_footer",
|
|
224
|
-
"
|
|
225
|
-
"
|
|
226
|
-
"
|
|
230
|
+
"on": "CDqThG_on",
|
|
231
|
+
"readOnly": "CDqThG_readOnly",
|
|
232
|
+
"reset": "CDqThG_reset",
|
|
227
233
|
"rowLabel": "CDqThG_rowLabel",
|
|
228
|
-
"
|
|
229
|
-
"
|
|
230
|
-
"toolName": "CDqThG_toolName",
|
|
231
|
-
"cardOpen": "CDqThG_cardOpen",
|
|
232
|
-
"card": "CDqThG_card",
|
|
233
|
-
"colorValue": "CDqThG_colorValue"
|
|
234
|
+
"colorValue": "CDqThG_colorValue",
|
|
235
|
+
"toolName": "CDqThG_toolName"
|
|
234
236
|
};
|
|
235
237
|
//#endregion
|
|
236
238
|
//#region src/client/settings-card.tsx
|
|
@@ -254,6 +256,7 @@ window.__ModuleLoader__.load({
|
|
|
254
256
|
execute: "代码 / 指令执行",
|
|
255
257
|
file: "文件操作",
|
|
256
258
|
task: "任务 / 目标",
|
|
259
|
+
ask: "提问卡片",
|
|
257
260
|
command: "指令节点",
|
|
258
261
|
thinking: "思考过程",
|
|
259
262
|
context: "上下文注入",
|
|
@@ -480,6 +483,492 @@ window.__ModuleLoader__.load({
|
|
|
480
483
|
});
|
|
481
484
|
}
|
|
482
485
|
//#endregion
|
|
486
|
+
//#region src/client/ask-model.ts
|
|
487
|
+
function isRecord(value) {
|
|
488
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
489
|
+
}
|
|
490
|
+
/** 读一个字符串字段,非字符串一律当空串。 */
|
|
491
|
+
function text(value) {
|
|
492
|
+
return typeof value === "string" ? value : "";
|
|
493
|
+
}
|
|
494
|
+
function parseJson(source) {
|
|
495
|
+
try {
|
|
496
|
+
return JSON.parse(source);
|
|
497
|
+
} catch {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
/** 从结果内容块拼出展示文本(文本块原样、其余块转 JSON)。 */
|
|
502
|
+
function resultTextOf(block) {
|
|
503
|
+
const content = block.content;
|
|
504
|
+
if (!Array.isArray(content) || content.length === 0) return null;
|
|
505
|
+
const parts = [];
|
|
506
|
+
for (const part of content) if (isRecord(part) && part.type === "text" && typeof part.text === "string") parts.push(part.text);
|
|
507
|
+
else parts.push(JSON.stringify(part, null, 2));
|
|
508
|
+
return parts.length === 0 ? null : parts.join("\n");
|
|
509
|
+
}
|
|
510
|
+
function readOptions(value) {
|
|
511
|
+
if (!Array.isArray(value)) return [];
|
|
512
|
+
const options = [];
|
|
513
|
+
for (const item of value) {
|
|
514
|
+
if (typeof item === "string") {
|
|
515
|
+
if (item !== "") options.push({
|
|
516
|
+
label: item,
|
|
517
|
+
description: ""
|
|
518
|
+
});
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
if (!isRecord(item)) continue;
|
|
522
|
+
const label = text(item.label);
|
|
523
|
+
if (label === "") continue;
|
|
524
|
+
options.push({
|
|
525
|
+
label,
|
|
526
|
+
description: text(item.description)
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
return options;
|
|
530
|
+
}
|
|
531
|
+
/** 读调用参数里的问题列表;拿不到合法问题时返回 null(由调用方兜底)。 */
|
|
532
|
+
function readQuestions(argsRaw) {
|
|
533
|
+
const parsed = parseJson(argsRaw);
|
|
534
|
+
if (!isRecord(parsed) || !Array.isArray(parsed.questions)) return null;
|
|
535
|
+
const questions = [];
|
|
536
|
+
for (const item of parsed.questions) {
|
|
537
|
+
if (!isRecord(item)) continue;
|
|
538
|
+
const question = text(item.question);
|
|
539
|
+
if (question === "") continue;
|
|
540
|
+
questions.push({
|
|
541
|
+
id: text(item.id),
|
|
542
|
+
question,
|
|
543
|
+
header: text(item.header),
|
|
544
|
+
detail: text(item.detail),
|
|
545
|
+
multiSelect: item.multiSelect === true,
|
|
546
|
+
options: readOptions(item.options)
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
return questions.length === 0 ? null : questions;
|
|
550
|
+
}
|
|
551
|
+
function readAnswers(resultText) {
|
|
552
|
+
if (resultText === null) return null;
|
|
553
|
+
const parsed = parseJson(resultText);
|
|
554
|
+
if (!isRecord(parsed) || !Array.isArray(parsed.answers)) return null;
|
|
555
|
+
const answers = [];
|
|
556
|
+
for (const item of parsed.answers) {
|
|
557
|
+
if (!isRecord(item)) continue;
|
|
558
|
+
const selected = Array.isArray(item.selected) ? item.selected.filter((v) => typeof v === "string") : [];
|
|
559
|
+
answers.push({
|
|
560
|
+
id: text(item.id),
|
|
561
|
+
selected,
|
|
562
|
+
custom: text(item.custom)
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
return answers;
|
|
566
|
+
}
|
|
567
|
+
/** 调用参数:运行中取 block 自身,结算后取结算节点的调用头。 */
|
|
568
|
+
function argsRawOf(block) {
|
|
569
|
+
return "kind" in block ? block.call?.argsRaw ?? "" : block.argsRaw ?? "";
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* 从一次提问调用的冻结切片派生卡片模型。
|
|
573
|
+
* @param block - 运行中的调用或已结算的结果节点。
|
|
574
|
+
* @returns 卡片模型;参数或结果畸形时 `questions` 为空并带兜底文本。
|
|
575
|
+
*/
|
|
576
|
+
function askCardModel(block) {
|
|
577
|
+
const settled = "kind" in block;
|
|
578
|
+
const code = settled ? block.error?.code : void 0;
|
|
579
|
+
const state = !settled ? "running" : code === "ASK_ABORTED" || code === "interrupted" ? "stopped" : code === "ASK_CANCELLED" ? "ok" : block.isError === true ? "error" : "ok";
|
|
580
|
+
const argsRaw = argsRawOf(block);
|
|
581
|
+
const resultText = settled ? resultTextOf(block) : null;
|
|
582
|
+
let verdict;
|
|
583
|
+
let phase;
|
|
584
|
+
if (code === "ASK_CANCELLED") {
|
|
585
|
+
verdict = "cancelled";
|
|
586
|
+
phase = "unanswered";
|
|
587
|
+
} else if (code === "ASK_ABORTED") {
|
|
588
|
+
verdict = "aborted";
|
|
589
|
+
phase = "unanswered";
|
|
590
|
+
} else if (!settled) phase = "pending";
|
|
591
|
+
else phase = resultText === null ? "unanswered" : "answered";
|
|
592
|
+
const raw = readQuestions(argsRaw);
|
|
593
|
+
if (raw === null) return {
|
|
594
|
+
state,
|
|
595
|
+
phase,
|
|
596
|
+
verdict,
|
|
597
|
+
questions: [],
|
|
598
|
+
answeredCount: 0,
|
|
599
|
+
fallbackText: resultText ?? (argsRaw === "" ? null : argsRaw)
|
|
600
|
+
};
|
|
601
|
+
const byId = /* @__PURE__ */ new Map();
|
|
602
|
+
for (const answer of readAnswers(resultText) ?? []) if (!byId.has(answer.id)) byId.set(answer.id, answer);
|
|
603
|
+
const questions = raw.map((question) => {
|
|
604
|
+
const answer = byId.get(question.id);
|
|
605
|
+
return {
|
|
606
|
+
...question,
|
|
607
|
+
selected: answer?.selected ?? [],
|
|
608
|
+
custom: answer?.custom ?? ""
|
|
609
|
+
};
|
|
610
|
+
});
|
|
611
|
+
const answeredCount = questions.filter((question) => question.selected.length > 0 || question.custom !== "").length;
|
|
612
|
+
return {
|
|
613
|
+
state,
|
|
614
|
+
phase,
|
|
615
|
+
verdict,
|
|
616
|
+
questions,
|
|
617
|
+
answeredCount,
|
|
618
|
+
fallbackText: resultText
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
/** 折叠行右侧的进度计数(文案由组件用 locale 组装)。 */
|
|
622
|
+
function askProgress(model) {
|
|
623
|
+
return {
|
|
624
|
+
answered: model.answeredCount,
|
|
625
|
+
total: model.questions.length
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
//#endregion
|
|
629
|
+
//#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 tag = document.createElement("style");
|
|
634
|
+
tag.dataset.plugin = "@max-null/dsh-node-appearance";
|
|
635
|
+
tag.dataset.pluginCss = tagId$1;
|
|
636
|
+
tag.textContent = css$1;
|
|
637
|
+
document.head.appendChild(tag);
|
|
638
|
+
}
|
|
639
|
+
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
|
+
"ask-row-sweep": "ylzLDa_ask-row-sweep",
|
|
652
|
+
"root": "ylzLDa_root",
|
|
653
|
+
"label": "ylzLDa_label",
|
|
654
|
+
"bodyWrap": "ylzLDa_bodyWrap",
|
|
655
|
+
"row": "ylzLDa_row",
|
|
656
|
+
"verdict": "ylzLDa_verdict",
|
|
657
|
+
"desc": "ylzLDa_desc",
|
|
658
|
+
"card": "ylzLDa_card",
|
|
659
|
+
"options": "ylzLDa_options",
|
|
660
|
+
"option": "ylzLDa_option",
|
|
661
|
+
"header": "ylzLDa_header",
|
|
662
|
+
"item": "ylzLDa_item",
|
|
663
|
+
"question": "ylzLDa_question",
|
|
664
|
+
"marker": "ylzLDa_marker",
|
|
665
|
+
"fallback": "ylzLDa_fallback"
|
|
666
|
+
};
|
|
667
|
+
//#endregion
|
|
668
|
+
//#region src/client/ask-card.tsx
|
|
669
|
+
/**
|
|
670
|
+
* 提问卡:接管 `ask_user_question` 的工具行。
|
|
671
|
+
*
|
|
672
|
+
* 官方转录卡只列**已选答案**,结算后就再也看不到当时还有哪些选项。本卡片
|
|
673
|
+
* 用调用参数里的 `options` 把每个选项都渲染成一块,被选中的那块用插件色板
|
|
674
|
+
* 里 ask 类别的强调色(默认蓝)反显并打勾。
|
|
675
|
+
*
|
|
676
|
+
* 接管是 DSH 支持的机制(keyed slot 用不同 priority 遮蔽既有占用者,
|
|
677
|
+
* 见 ui-slots 的 `register()`),代价是本文件要自己承担官方 ToolRow 的
|
|
678
|
+
* 折叠行外观 —— 因此行外壳逐项对齐 ToolRow.module.css 的既有视觉
|
|
679
|
+
* (24px 行高、2px 分隔点、13px 次级摘要、running 扫光、hover 才现的
|
|
680
|
+
* Inspect 胶囊),组件则全部来自共享的 ui-primitives。
|
|
681
|
+
*/
|
|
682
|
+
/** 折叠行右侧的摘要:等待 / 已取消 / 已中断 / 未回答 / N-M 已回答。 */
|
|
683
|
+
function summaryText(model, t) {
|
|
684
|
+
if (model.phase === "pending") return t("ask.waiting");
|
|
685
|
+
if (model.phase === "unanswered") {
|
|
686
|
+
if (model.verdict === "cancelled") return t("ask.cancelled");
|
|
687
|
+
if (model.verdict === "aborted") return t("ask.interrupted");
|
|
688
|
+
return t("ask.skipped");
|
|
689
|
+
}
|
|
690
|
+
const { answered, total } = askProgress(model);
|
|
691
|
+
return t("ask.answered", {
|
|
692
|
+
answered,
|
|
693
|
+
total
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
/** 一行「未选/已选」选项块。 */
|
|
697
|
+
function OptionRow({ label, description, chosen }) {
|
|
698
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
699
|
+
className: ask_card_module_css_default.option,
|
|
700
|
+
"data-chosen": chosen ? "" : void 0,
|
|
701
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
702
|
+
className: ask_card_module_css_default.marker,
|
|
703
|
+
"aria-hidden": "true",
|
|
704
|
+
children: chosen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline14, {})
|
|
705
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
706
|
+
className: ask_card_module_css_default.optionText,
|
|
707
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
708
|
+
className: ask_card_module_css_default.label,
|
|
709
|
+
children: label
|
|
710
|
+
}), description !== void 0 && description !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
711
|
+
className: ask_card_module_css_default.desc,
|
|
712
|
+
children: description
|
|
713
|
+
})]
|
|
714
|
+
})]
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
/** 展开后的卡片体:逐问题列出全部选项并标出选中项。 */
|
|
718
|
+
function QuestionList({ model, t }) {
|
|
719
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
720
|
+
className: ask_card_module_css_default.card,
|
|
721
|
+
children: [model.verdict !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
722
|
+
className: ask_card_module_css_default.verdict,
|
|
723
|
+
children: model.verdict === "cancelled" ? t("ask.cancelledDetail") : t("ask.interruptedDetail")
|
|
724
|
+
}), model.questions.map((question, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
725
|
+
className: ask_card_module_css_default.item,
|
|
726
|
+
children: [
|
|
727
|
+
question.header !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
728
|
+
className: ask_card_module_css_default.header,
|
|
729
|
+
children: question.header
|
|
730
|
+
}),
|
|
731
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
732
|
+
className: ask_card_module_css_default.question,
|
|
733
|
+
children: question.question
|
|
734
|
+
}),
|
|
735
|
+
question.detail !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
736
|
+
className: ask_card_module_css_default.detail,
|
|
737
|
+
children: question.detail
|
|
738
|
+
}),
|
|
739
|
+
question.options.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
740
|
+
className: ask_card_module_css_default.options,
|
|
741
|
+
children: [question.options.map((option, optionIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OptionRow, {
|
|
742
|
+
label: option.label,
|
|
743
|
+
description: option.description,
|
|
744
|
+
chosen: question.selected.includes(option.label)
|
|
745
|
+
}, `${String(optionIndex)}-${option.label}`)), question.custom !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OptionRow, {
|
|
746
|
+
label: question.custom,
|
|
747
|
+
chosen: true
|
|
748
|
+
})]
|
|
749
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
750
|
+
className: ask_card_module_css_default.answers,
|
|
751
|
+
children: [
|
|
752
|
+
question.selected.map((answer, answerIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
753
|
+
className: ask_card_module_css_default.answerLine,
|
|
754
|
+
children: answer
|
|
755
|
+
}, `${String(answerIndex)}-${answer}`)),
|
|
756
|
+
question.custom !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
757
|
+
className: ask_card_module_css_default.answerLine,
|
|
758
|
+
children: question.custom
|
|
759
|
+
}),
|
|
760
|
+
question.selected.length === 0 && question.custom === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
761
|
+
className: ask_card_module_css_default.answersEmpty,
|
|
762
|
+
children: t("ask.skipped")
|
|
763
|
+
})
|
|
764
|
+
]
|
|
765
|
+
})
|
|
766
|
+
]
|
|
767
|
+
}, question.id !== "" ? question.id : `q${String(index)}`))]
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* 渲染一次提问的完整记录。
|
|
772
|
+
* @param props - locale 翻译函数、冻结的调用切片与可选的轨迹入口。
|
|
773
|
+
* @returns 折叠行 + 展开后的选项卡片。
|
|
774
|
+
*/
|
|
775
|
+
function AskQuestionRow({ t, block, inspect }) {
|
|
776
|
+
const model = (0, react.useMemo)(() => askCardModel(block), [block]);
|
|
777
|
+
const [expanded, setExpanded] = (0, react.useState)(false);
|
|
778
|
+
const hasBody = model.questions.length > 0 || model.fallbackText !== null;
|
|
779
|
+
const open = expanded && hasBody;
|
|
780
|
+
const leading = model.state === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "error" }) : model.state === "stopped" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, { state: "warning" }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQuestionOutline14, {});
|
|
781
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
782
|
+
className: ask_card_module_css_default.root,
|
|
783
|
+
"data-variant": "others",
|
|
784
|
+
"data-tool": "ask_user_question",
|
|
785
|
+
"data-state": model.state,
|
|
786
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
|
|
787
|
+
rowClassName: ask_card_module_css_default.row,
|
|
788
|
+
leadingClassName: ask_card_module_css_default.leading,
|
|
789
|
+
titleClassName: ask_card_module_css_default.title,
|
|
790
|
+
chevronClassName: ask_card_module_css_default.chevron,
|
|
791
|
+
icon: leading,
|
|
792
|
+
title: t("ask.rowTitle"),
|
|
793
|
+
open,
|
|
794
|
+
expandable: hasBody,
|
|
795
|
+
expandOnRowClick: true,
|
|
796
|
+
keepContentWhenOpen: true,
|
|
797
|
+
onToggle: () => {
|
|
798
|
+
setExpanded((value) => !value);
|
|
799
|
+
},
|
|
800
|
+
collapsedContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
801
|
+
className: ask_card_module_css_default.sep,
|
|
802
|
+
"aria-hidden": true
|
|
803
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
804
|
+
className: ask_card_module_css_default.summary,
|
|
805
|
+
children: summaryText(model, t)
|
|
806
|
+
})] }),
|
|
807
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
808
|
+
className: ask_card_module_css_default.bodyWrap,
|
|
809
|
+
children: [model.questions.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuestionList, {
|
|
810
|
+
model,
|
|
811
|
+
t
|
|
812
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
813
|
+
className: ask_card_module_css_default.fallback,
|
|
814
|
+
children: model.fallbackText
|
|
815
|
+
}), inspect !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
816
|
+
type: "button",
|
|
817
|
+
className: ask_card_module_css_default.inspectButton,
|
|
818
|
+
onClick: inspect,
|
|
819
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconInspectOutline12, {}), t("row.inspect")]
|
|
820
|
+
})]
|
|
821
|
+
})
|
|
822
|
+
})
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
//#endregion
|
|
826
|
+
//#region \0dsh-css:H:\MaxNull\WorkStation\max-null-plugins\dsh-node-appearance\src\client\goal-detail.module.css.mjs
|
|
827
|
+
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
|
+
const tagId = "@max-null/dsh-node-appearance/goal-detail.module.css";
|
|
829
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
830
|
+
const tag = document.createElement("style");
|
|
831
|
+
tag.dataset.plugin = "@max-null/dsh-node-appearance";
|
|
832
|
+
tag.dataset.pluginCss = tagId;
|
|
833
|
+
tag.textContent = css;
|
|
834
|
+
document.head.appendChild(tag);
|
|
835
|
+
}
|
|
836
|
+
var goal_detail_module_css_default = {
|
|
837
|
+
"header": "WyWU3a_header",
|
|
838
|
+
"summary": "WyWU3a_summary",
|
|
839
|
+
"row": "WyWU3a_row",
|
|
840
|
+
"lead": "WyWU3a_lead",
|
|
841
|
+
"value": "WyWU3a_value",
|
|
842
|
+
"chevron": "WyWU3a_chevron",
|
|
843
|
+
"key": "WyWU3a_key",
|
|
844
|
+
"detail": "WyWU3a_detail",
|
|
845
|
+
"code": "WyWU3a_code",
|
|
846
|
+
"root": "WyWU3a_root",
|
|
847
|
+
"body": "WyWU3a_body",
|
|
848
|
+
"title": "WyWU3a_title"
|
|
849
|
+
};
|
|
850
|
+
//#endregion
|
|
851
|
+
//#region src/client/goal-detail.tsx
|
|
852
|
+
/**
|
|
853
|
+
* 目标详情折叠条:接在官方 GoalBar 下面(`conversation.input.dock` 里
|
|
854
|
+
* `order: 11`,官方那条是 10),把官方条上被 ellipsis 截断的目标展开成可读
|
|
855
|
+
* 详情。
|
|
856
|
+
*
|
|
857
|
+
* 卡片形态照同槽的待办面板(ui-conversation 的 TodoPanel):同一套 dock 宽度
|
|
858
|
+
* 公式、同一张 `--dsw-specific-tip` 卡片、同一个「标题 + 右侧摘要 + chevron」
|
|
859
|
+
* 折叠头,默认收起。折叠头只放官方条**没有**的元信息(版本号、自主轮次),
|
|
860
|
+
* 目标原文放在展开区 —— 这样两块不会互相重复。
|
|
861
|
+
*
|
|
862
|
+
* 为什么是「另加一条」而不是接管官方条:`conversation.input.dock` 是 list
|
|
863
|
+
* 槽,不同 id 各自成格并列渲染;而官方 ui-goal 的注入面(edit/pause/resume/
|
|
864
|
+
* clear 四个 Remote 动词 + 一个带竞态防护的 activation 订阅源)是**注册者
|
|
865
|
+
* 私有**的,接管就得整套复刻 —— 那会把这个「只读地多看一行」的需求变成
|
|
866
|
+
* 插件里多一处会写会话数据的 RPC 客户端。这里只读 `useProjection('goal')`。
|
|
867
|
+
*/
|
|
868
|
+
/** 阶段文案:与官方 goal 字典同义,按本插件既有做法直写中文。 */
|
|
869
|
+
const PHASE_LABEL = {
|
|
870
|
+
active: "进行中",
|
|
871
|
+
paused: "已暂停",
|
|
872
|
+
blocked: "已阻塞",
|
|
873
|
+
complete: "已完成"
|
|
874
|
+
};
|
|
875
|
+
/** 折叠头右侧摘要:只放官方条没有的元信息。 */
|
|
876
|
+
function summaryLabel(goal) {
|
|
877
|
+
const parts = [`rev ${String(goal.revision)}`];
|
|
878
|
+
if (goal.roundsStarted !== void 0) parts.push(goal.maxGoalRounds === void 0 ? `${String(goal.roundsStarted)} 轮` : `${String(goal.roundsStarted)} / ${String(goal.maxGoalRounds)} 轮`);
|
|
879
|
+
return parts.join(" · ");
|
|
880
|
+
}
|
|
881
|
+
/** 展开区里的一组「键 / 值」。 */
|
|
882
|
+
function Row({ label, children }) {
|
|
883
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
884
|
+
className: goal_detail_module_css_default.row,
|
|
885
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
886
|
+
className: goal_detail_module_css_default.key,
|
|
887
|
+
children: label
|
|
888
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
889
|
+
className: goal_detail_module_css_default.value,
|
|
890
|
+
children
|
|
891
|
+
})]
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
/**
|
|
895
|
+
* 渲染目标详情折叠条。
|
|
896
|
+
* @param props - 框架标准投影席位。
|
|
897
|
+
* @returns 折叠条;加载中、无目标、或目标已完成时不渲染(与官方条一致)。
|
|
898
|
+
*/
|
|
899
|
+
function GoalDetail({ useProjection }) {
|
|
900
|
+
const projection = useProjection("goal");
|
|
901
|
+
const [collapsed, setCollapsed] = (0, react.useState)(true);
|
|
902
|
+
const goalId = projection?.goal.id;
|
|
903
|
+
(0, react.useEffect)(() => {
|
|
904
|
+
setCollapsed(true);
|
|
905
|
+
}, [goalId]);
|
|
906
|
+
const goal = projection?.goal;
|
|
907
|
+
if (goal === void 0 || goal === null || goal.phase === "complete") return null;
|
|
908
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
909
|
+
className: goal_detail_module_css_default.root,
|
|
910
|
+
"data-goal-detail": true,
|
|
911
|
+
"aria-label": "目标详情",
|
|
912
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
913
|
+
className: goal_detail_module_css_default.body,
|
|
914
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
915
|
+
type: "button",
|
|
916
|
+
className: goal_detail_module_css_default.header,
|
|
917
|
+
"aria-expanded": !collapsed,
|
|
918
|
+
onClick: () => {
|
|
919
|
+
setCollapsed((value) => !value);
|
|
920
|
+
},
|
|
921
|
+
children: [
|
|
922
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
923
|
+
className: goal_detail_module_css_default.lead,
|
|
924
|
+
"aria-hidden": true,
|
|
925
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGoalOutline16, { size: 14 })
|
|
926
|
+
}),
|
|
927
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
928
|
+
className: goal_detail_module_css_default.title,
|
|
929
|
+
children: "目标详情"
|
|
930
|
+
}),
|
|
931
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
932
|
+
className: goal_detail_module_css_default.summary,
|
|
933
|
+
children: summaryLabel(goal)
|
|
934
|
+
}),
|
|
935
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
936
|
+
className: goal_detail_module_css_default.chevron,
|
|
937
|
+
"aria-hidden": true,
|
|
938
|
+
children: collapsed ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})
|
|
939
|
+
})
|
|
940
|
+
]
|
|
941
|
+
}), !collapsed && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
|
|
942
|
+
className: goal_detail_module_css_default.detail,
|
|
943
|
+
children: [
|
|
944
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
945
|
+
label: "目标",
|
|
946
|
+
children: goal.objective
|
|
947
|
+
}),
|
|
948
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
949
|
+
label: "阶段",
|
|
950
|
+
children: PHASE_LABEL[goal.phase]
|
|
951
|
+
}),
|
|
952
|
+
goal.blockedReason !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Row, {
|
|
953
|
+
label: "阻塞",
|
|
954
|
+
children: [goal.blockedReason.message, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
955
|
+
className: goal_detail_module_css_default.code,
|
|
956
|
+
children: goal.blockedReason.code
|
|
957
|
+
})]
|
|
958
|
+
}),
|
|
959
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Row, {
|
|
960
|
+
label: "标识",
|
|
961
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
962
|
+
className: goal_detail_module_css_default.code,
|
|
963
|
+
children: goal.id
|
|
964
|
+
})
|
|
965
|
+
})
|
|
966
|
+
]
|
|
967
|
+
})]
|
|
968
|
+
})
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
//#endregion
|
|
483
972
|
//#region src/client/index.ts
|
|
484
973
|
const inject = [
|
|
485
974
|
"slots",
|
|
@@ -543,6 +1032,17 @@ window.__ModuleLoader__.load({
|
|
|
543
1032
|
key: NODE_APPEARANCE_NS,
|
|
544
1033
|
inject: () => face
|
|
545
1034
|
}, NodeAppearanceRow));
|
|
1035
|
+
ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
1036
|
+
name: "tool.call.toolview",
|
|
1037
|
+
key: "ask_user_question",
|
|
1038
|
+
priority: -1,
|
|
1039
|
+
locale: "conversation"
|
|
1040
|
+
}, AskQuestionRow));
|
|
1041
|
+
ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
|
|
1042
|
+
name: "conversation.input.dock",
|
|
1043
|
+
id: "max-null/goal-detail",
|
|
1044
|
+
order: 11
|
|
1045
|
+
}, GoalDetail));
|
|
546
1046
|
}
|
|
547
1047
|
//#endregion
|
|
548
1048
|
exports.apply = apply;
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useState","css","IconChevronDownOutline14"],"sources":["../src/client/palette.ts","../src/client/settings-card.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' | '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 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 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 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 * 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'\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"],"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","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":";;;;;;;;;;;;;;;;;;EASA,MAAa,qBAAqB;;EAGlC,MAAa,eAAe,GAAG,mBAAmB;;EAoBlD,MAAa,iBAAuC;GAClD,QAAQ;GACR,OAAO;GACP,SAAS;GACT,MAAM;GACN,MAAM;GACN,KAAK;GACL,SAAS;GACT,UAAU;GACV,SAAS;GACT,UAAU;GACV,OAAO;EACT;;EAGA,MAAa,kBAAqH;GAChI,QAAQ,CAAC,cAAc,WAAW;GAClC,OAAO;IAAC;IAAY;IAAgB;IAAiB;IAAgB;IAAmB;IAAe;IAAU;GAAU;GAC3H,SAAS;IAAC;IAAQ;IAAQ;IAAY;IAAiB;IAAkB;IAAiB;IAAiB;IAAiB;IAAmB;GAAoB;GACnK,MAAM;IAAC;IAAQ;IAAS;IAAQ;IAAc;IAAQ;GAAM;GAC5D,MAAM;IAAC;IAAc;IAAe;IAAY;IAAe;IAAY;IAAY;IAAc;IAAmB;IAAmB;IAAiB;GAAgB;GAC5K,KAAK,CAAC,mBAAmB;GACzB,OAAO,CAAC;EACV;;EAGA,MAAM,WAAW;;EAEjB,MAAM,gBAAgB;;EAEtB,MAAM,cAAc;;EAEpB,MAAM,YAAY;;EAElB,MAAM,cAAc;;EAEpB,MAAM,kBAAkB;;;;;;;;;;;EAYxB,MAAM,gBAAgB;GACpB;GAAe;GAAa;GAAW;GAAa;EACtD,CAAC,CAAC,KAAK,KAAK;;;;;;;EAQZ,SAAgB,WAAW,OAAwB;GACjD,MAAM,UAAU,MAAM,KAAK;GAC3B,IAAI,YAAY,IAAI,OAAO;GAC3B,IAAI,oBAAoB,KAAK,OAAO,GAAG,OAAO;GAC9C,OAAO,oEAAoE,KAAK,OAAO;EACzF;;EAGA,SAAgB,cAAc,UAAwD;GACpF,MAAM,SAA+B,EAAE,GAAG,eAAe;GACzD,MAAM,aAAa,SAAS;GAC5B,IAAI,eAAe,KAAA,KAAa,OAAO,eAAe,YAAY,eAAe,MAC/E,KAAK,MAAM,OAAO,OAAO,KAAK,cAAc,GAAqB;IAC/D,MAAM,QAAQ,WAAW;IACzB,IAAI,OAAO,UAAU,YAAY,WAAW,KAAK,GAAG,OAAO,OAAO;GACpE;GAEF,OAAO;EACT;;EAGA,SAAS,iBAAiB,OAAuB;GAC/C,OAAO,MAAM,QAAQ,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAK;EACzD;;;;;;EAOA,MAAM,gBAAgB;;;;;;EAOtB,SAAgB,SAAS,UAAsD;GAC7E,MAAM,SAAS,cAAc,YAAY,CAAC,CAAC;GAC3C,MAAM,gBAAgB,UAAU;GAChC,MAAM,QAAkB,CAAC;GAMzB,MAAM,KAAK,GAAG,SAAS,sBAAsB,OAAO,MAAM,IAAI;GAG9D,KAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,eAAe,GAAG;IAC/D,MAAM,MAAM;IACZ,KAAK,MAAM,QAAQ,OAAO;KACxB,MAAM,WAAW,gBAAgB;KACjC,MAAM,QAAQ,OAAO,aAAa,YAAY,WAAW,QAAQ,IAC7D,WACA,OAAO;KACX,MAAM,KAAK,iDAAiD,iBAAiB,IAAI,EAAE,wBAAwB,MAAM,IAAI;IACvH;GACF;GAGA,MAAM,KAAK,GAAG,YAAY,sBAAsB,OAAO,QAAQ,IAAI;GACnE,MAAM,KAAK,GAAG,UAAU,sBAAsB,OAAO,SAAS,IAAI;GAClE,MAAM,KAAK,GAAG,YAAY,sBAAsB,OAAO,QAAQ,IAAI;GACnE,MAAM,KAAK,GAAG,gBAAgB,sBAAsB,OAAO,KAAK,IAAI;GAKpE,MAAM,KAAK,GAAG,cAAc;;;;EAI5B;GAYA,MAAM,KAAK;;EAEX;GACA,MAAM,KAAK;;;;;;;;;sBASS,OAAO,SAAS;uBACf,cAAc;eACtB,cAAc;EAC3B;GAKA,IAAI,UAAU,iBAAiB,OAAO;IACpC,MAAM,KAAK,GAAG,UAAU,+BAA+B;IAMvD,MAAM,KACJ,yCAAyC,UAAU,gBACnD,8CAA8C,UAAU,2CAC1D;GACF;GAEA,OAAO,MAAM,KAAK,IAAI;EACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC/JA,MAAM,kBAAgD;GACpD,QAAQ;GACR,OAAO;GACP,SAAS;GACT,MAAM;GACN,MAAM;GACN,KAAK;GACL,SAAS;GACT,UAAU;GACV,SAAS;GACT,UAAU;GACV,OAAO;EACT;;EAGA,MAAM,mBAAmB,OAAO,OAAO,eAAe,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG;;EAGvE,MAAM,OAAO;GACX,OAAO;GACP,aAAa;GACb,OAAO;GACP,cAAc;GACd,WAAW;GACX,UAAU;GACV,SAAS;GACT,cAAc;GACd,kBAAkB;GAClB,YAAY;GACZ,SAAS;GACT,YAAY;EACd;;EAGA,MAAM,mBAA2C;GAC/C,cAAc;GACd,QAAQ;GACR,YAAY,CAAC;EACf;;;;;;EAOA,SAAgB,kBAAkB,EAAE,mBAAmB,OAAO,iBAAiB,kBAAkB,cAAc,mBAA2C;GACxJ,MAAM,CAAC,MAAM,YAAA,GAAWA,MAAAA,SAAAA,CAAS,KAAK;GACtC,MAAM,CAAC,cAAc,oBAAA,GAAmBA,MAAAA,SAAAA,CAAS,KAAK;GACtD,MAAM,CAAC,WAAW,iBAAA,GAAgBA,MAAAA,SAAAA,CAAS,KAAK;GAChD,MAAM,CAAC,UAAU,gBAAA,GAAeA,MAAAA,SAAAA,CAAS,EAAE;GAC3C,MAAM,CAAC,WAAW,sBAAA,GAAqBA,MAAAA,SAAAA,CAAS,SAAS;GACzD,MAAM,WAAW,mBAAkB,aAAY,QAAQ;GACvD,MAAM,SAAS,SAAS,SAAS,CAAC;GAClC,MAAM,SAAS,cAAc,MAAM;GACnC,MAAM,aAAa,OAAO,cAAc,CAAC;GACzC,MAAM,eAAe,OAAO,gBAAgB;GAC5C,MAAM,WAAW,SAAS,aAAa;GACvC,MAAM,cAAc,SAAS,WAAW;GAExC,MAAM,eAAe,YAA2B;IAC9C,IAAI,WAAW;IACf,aAAa,IAAI;IACjB,IAAI;KACF,MAAM,MAAM,gBAAgB;KAC5B,gBAAgB,KAAK;IACvB,QAAQ,CAER,UAAU;KACR,aAAa,KAAK;IACpB;GACF;GAEA,MAAM,oBAA0B;IAC9B,IAAI,cACF,aAAkB;SAElB,gBAAgB,IAAI;GAExB;GAEA,MAAM,WAAW,UAA2B;IAC1C,MAAM,eAAe;IACrB,MAAM,OAAO,SAAS,KAAK;IAC3B,IAAI,SAAS,MAAM,CAAC,WAAW,SAAS,GAAG;IAC3C,aAAa,MAAM,SAAS;IAC5B,YAAY,EAAE;GAChB;GAEA,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;IAAI,WAAWC,wBAAI,QAAQ,OAAO,MAAMA,wBAAI,WAAW;IAAvD,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;KACE,MAAK;KACL,WAAWA,wBAAI;KACf,iBAAe;KACf,cAAY,GAAG,OAAO,OAAO,KAAK,GAAG,KAAK;KAC1C,eAAe;MAAE,QAAQ,CAAC,IAAI;KAAE;KALlC,UAAA,CAOE,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;MAAM,WAAWA,wBAAI;MAArB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,wBAAI;OAAO,UAAA,KAAK;MAAY,CAAA,GAC7C,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;OAAM,WAAWA,wBAAI;OAAc,UAAA,KAAK;MAAkB,CAAA,CACtD;KACN,CAAA,GAAA,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,0BAAD,EAA0B,WAAWD,wBAAI,WAAW,OAAO,MAAMA,wBAAI,cAAc,IAAM,CAAA,CACnF;IACP,CAAA,GAAA,QACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,wBAAI;KAApB,UAAA;MACG,eAAe,CAAC,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,wBAAI;OAAa,UAAA,KAAK;MAAW,CAAA;MAC3E,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;OAAG,WAAWA,wBAAI;OAAU,MAAK;OAAU,UAAA,KAAK;MAAY,CAAA;MACzE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAW,WAAWA,wBAAI,WAAW;OAA1C,UAAA;QACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,wBAAI;SAApB,UAAA;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WAAO,WAAWA,wBAAI;WAAU,SAAQ;WAAiC,UAAA,KAAK;UAAoB,CAAA;UAClG,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,wBAAI;WAAU,UAAA,KAAK;UAAuB,CAAA;UAC3D,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WACE,IAAG;WACH,WAAWA,wBAAI,UAAU,eAAe,MAAMA,wBAAI,KAAK;WACvD,MAAK;WACL,gBAAc;WACd,eAAe;YAAE,gBAAgB,CAAC,YAAY;WAAE;WAEhD,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAM,WAAWA,wBAAI,KAAO,CAAA;UACtB,CAAA;SACL;;QACH,OAAO,KAAK,eAAe,CAAC,CAAoB,KAAI,aACpD,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,wBAAI;SAApB,UAAA;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WAAO,WAAWA,wBAAI;WAAU,SAAS,yBAAyB;WAAa,UAAA,gBAAgB;UAAiB,CAAA;UAChH,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WACE,IAAI,yBAAyB;WAC7B,WAAWA,wBAAI;WACf,MAAK;WACL,OAAO,OAAO;WACd,WAAW,UAAyC;YAAE,iBAAiB,UAAU,MAAM,OAAO,KAAK;WAAE;UACtG,CAAA;UACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,wBAAI;WAAa,UAAA,OAAO;UAAgB,CAAA;SACtD;QAVyB,GAAA,QAUzB,CACN;QACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;SAAK,WAAWA,wBAAI;SAAe,UAAA,KAAK;QAAgB,CAAA;QACvD,OAAO,QAAQ,UAAU,CAAC,CAAC,KAAK,CAAC,MAAM,WACtC,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;SAAK,WAAWA,wBAAI;SAApB,UAAA;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;WAAM,WAAWA,wBAAI;WAAU,OAAO;WAAO,UAAA;UAAW,CAAA;UACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WACE,WAAWA,wBAAI;WACf,MAAK;WACL,OAAO,WAAW,KAAK,IAAI,QAAQ,eAAe;WAClD,WAAW,UAAyC;YAAE,aAAa,MAAM,MAAM,OAAO,KAAK;WAAE;UAC9F,CAAA;UACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAAQ,MAAK;WAAS,WAAWA,wBAAI;WAAc,eAAe;YAAE,gBAAgB,IAAI;WAAE;WAAI,UAAA,KAAK;UAAmB,CAAA;SACnH;QATyB,GAAA,IASzB,CACN;QACD,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;SAAM,WAAWA,wBAAI;SAAQ,UAAU;SAAvC,UAAA;UACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WACE,WAAWA,wBAAI;WACf,MAAK;WACL,aAAa,SAAS;WACtB,OAAO;WACP,WAAW,UAAyC;YAAE,YAAY,MAAM,OAAO,KAAK;WAAE;UACvF,CAAA;UACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;WAAO,WAAWA,wBAAI;WAAY,MAAK;WAAQ,OAAO;WAAW,WAAW,UAAyC;YAAE,kBAAkB,MAAM,OAAO,KAAK;WAAE;UAAI,CAAA;UACjK,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;WAAQ,MAAK;WAAS,WAAWA,wBAAI;WAAW,UAAU,SAAS,KAAK,MAAM;WAAK,UAAA,KAAK;UAAgB,CAAA;SACpG;;OACH;;MACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,wBAAI;OAClB,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;QACE,MAAK;QACL,WAAWA,wBAAI,SAAS,eAAe,MAAMA,wBAAI,eAAe;QAChE,UAAU;QACV,SAAS;QACT,UAAA,YAAY,KAAK,YAAY,eAAe,KAAK,eAAe,KAAK;OAAc,CAAA;MAClF,CAAA;KACF;IAEL,CAAA,CAAA;;EAER;;;EC5IA,SAAS,SAAS,OAAkD;GAClE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;EAC5E;;EAGA,SAAS,KAAK,OAAwB;GACpC,OAAO,OAAO,UAAU,WAAW,QAAQ;EAC7C;EAEA,SAAS,UAAU,QAAyB;GAC1C,IAAI;IACF,OAAO,KAAK,MAAM,MAAM;GAC1B,QAAQ;IAEN;GACF;EACF;;EAGA,SAAgB,aAAa,OAAoC;GAC/D,MAAM,UAAU,MAAM;GACtB,IAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,GAAG,OAAO;GAC5D,MAAM,QAAkB,CAAC;GACzB,KAAK,MAAM,QAAQ,SACjB,IAAI,SAAS,IAAI,KAAK,KAAK,SAAS,UAAU,OAAO,KAAK,SAAS,UAAU,MAAM,KAAK,KAAK,IAAI;QAC5F,MAAM,KAAK,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;GAE/C,OAAO,MAAM,WAAW,IAAI,OAAO,MAAM,KAAK,IAAI;EACpD;EAYA,SAAS,YAAY,OAA6B;GAChD,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC;GACnC,MAAM,UAAuB,CAAC;GAC9B,KAAK,MAAM,QAAQ,OAAO;IACxB,IAAI,OAAO,SAAS,UAAU;KAE5B,IAAI,SAAS,IAAI,QAAQ,KAAK;MAAE,OAAO;MAAM,aAAa;KAAG,CAAC;KAC9D;IACF;IACA,IAAI,CAAC,SAAS,IAAI,GAAG;IACrB,MAAM,QAAQ,KAAK,KAAK,KAAK;IAC7B,IAAI,UAAU,IAAI;IAClB,QAAQ,KAAK;KAAE;KAAO,aAAa,KAAK,KAAK,WAAW;IAAE,CAAC;GAC7D;GACA,OAAO;EACT;;EAGA,SAAS,cAAc,SAAuC;GAC5D,MAAM,SAAS,UAAU,OAAO;GAChC,IAAI,CAAC,SAAS,MAAM,KAAK,CAAC,MAAM,QAAQ,OAAO,SAAS,GAAG,OAAO;GAClE,MAAM,YAA2B,CAAC;GAClC,KAAK,MAAM,QAAQ,OAAO,WAAW;IACnC,IAAI,CAAC,SAAS,IAAI,GAAG;IACrB,MAAM,WAAW,KAAK,KAAK,QAAQ;IACnC,IAAI,aAAa,IAAI;IACrB,UAAU,KAAK;KACb,IAAI,KAAK,KAAK,EAAE;KAChB;KACA,QAAQ,KAAK,KAAK,MAAM;KACxB,QAAQ,KAAK,KAAK,MAAM;KACxB,aAAa,KAAK,gBAAgB;KAClC,SAAS,YAAY,KAAK,OAAO;IACnC,CAAC;GACH;GACA,OAAO,UAAU,WAAW,IAAI,OAAO;EACzC;EASA,SAAS,YAAY,YAA+C;GAClE,IAAI,eAAe,MAAM,OAAO;GAChC,MAAM,SAAS,UAAU,UAAU;GACnC,IAAI,CAAC,SAAS,MAAM,KAAK,CAAC,MAAM,QAAQ,OAAO,OAAO,GAAG,OAAO;GAChE,MAAM,UAAuB,CAAC;GAC9B,KAAK,MAAM,QAAQ,OAAO,SAAS;IACjC,IAAI,CAAC,SAAS,IAAI,GAAG;IACrB,MAAM,WAAW,MAAM,QAAQ,KAAK,QAAQ,IACxC,KAAK,SAAS,QAAQ,MAAmB,OAAO,MAAM,QAAQ,IAC9D,CAAC;IACL,QAAQ,KAAK;KAAE,IAAI,KAAK,KAAK,EAAE;KAAG;KAAU,QAAQ,KAAK,KAAK,MAAM;IAAE,CAAC;GACzE;GACA,OAAO;EACT;;EAGA,SAAS,UAAU,OAA6B;GAC9C,OAAO,UAAU,QAAQ,MAAM,MAAM,WAAW,KAAK,MAAM,WAAW;EACxE;;;;;;EAOA,SAAgB,aAAa,OAAmC;GAC9D,MAAM,UAAU,UAAU;GAC1B,MAAM,OAAO,UAAU,MAAM,OAAO,OAAO,KAAA;GAK3C,MAAM,QAAqB,CAAC,UAAU,YAClC,SAAS,iBAAiB,SAAS,gBAAgB,YACjD,SAAS,kBAAkB,OACzB,MAAM,YAAY,OAAO,UAAU;GAC3C,MAAM,UAAU,UAAU,KAAK;GAC/B,MAAM,aAAa,UAAU,aAAa,KAAK,IAAI;GAInD,IAAI;GACJ,IAAI;GACJ,IAAI,SAAS,iBAAiB;IAC5B,UAAU;IACV,QAAQ;GACV,OAAO,IAAI,SAAS,eAAe;IACjC,UAAU;IACV,QAAQ;GACV,OAAO,IAAI,CAAC,SACV,QAAQ;QAER,QAAQ,eAAe,OAAO,eAAe;GAG/C,MAAM,MAAM,cAAc,OAAO;GACjC,IAAI,QAAQ,MACV,OAAO;IACL;IAAO;IAAO;IAAS,WAAW,CAAC;IAAG,eAAe;IACrD,cAAc,eAAe,YAAY,KAAK,OAAO;GACvD;GAKF,MAAM,uBAAO,IAAI,IAAuB;GACxC,KAAK,MAAM,UAAU,YAAY,UAAU,KAAK,CAAC,GAC/C,IAAI,CAAC,KAAK,IAAI,OAAO,EAAE,GAAG,KAAK,IAAI,OAAO,IAAI,MAAM;GAEtD,MAAM,YAA2B,IAAI,KAAI,aAAY;IACnD,MAAM,SAAS,KAAK,IAAI,SAAS,EAAE;IACnC,OAAO;KACL,GAAG;KACH,UAAU,QAAQ,YAAY,CAAC;KAC/B,QAAQ,QAAQ,UAAU;IAC5B;GACF,CAAC;GACD,MAAM,gBAAgB,UACnB,QAAO,aAAY,SAAS,SAAS,SAAS,KAAK,SAAS,WAAW,EAAE,CAAC,CAC1E;GACH,OAAO;IAAE;IAAO;IAAO;IAAS;IAAW;IAAe,cAAc;GAAW;EACrF;;EAGA,SAAgB,YAAY,OAA0D;GACpF,OAAO;IAAE,UAAU,MAAM;IAAe,OAAO,MAAM,UAAU;GAAO;EACxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC1NA,SAAS,YAAY,OAAqB,GAAyB;GACjE,IAAI,MAAM,UAAU,WAAW,OAAO,EAAE,aAAa;GACrD,IAAI,MAAM,UAAU,cAAc;IAChC,IAAI,MAAM,YAAY,aAAa,OAAO,EAAE,eAAe;IAC3D,IAAI,MAAM,YAAY,WAAW,OAAO,EAAE,iBAAiB;IAC3D,OAAO,EAAE,aAAa;GACxB;GACA,MAAM,EAAE,UAAU,UAAU,YAAY,KAAK;GAC7C,OAAO,EAAE,gBAAgB;IAAE;IAAU;GAAM,CAAC;EAC9C;;EAGA,SAAS,UAAU,EAAE,OAAO,aAAa,UAItC;GACD,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWE,4BAAI;IAAQ,eAAa,SAAS,KAAK,KAAA;IAAvD,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;KAAM,WAAWA,4BAAI;KAAQ,eAAY;KACtC,UAAA,UAAU,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,oBAAD,CAAqB,CAAA;IAC5B,CAAA,GACN,iBAAA,GAAA,kBAAA,KAAA,CAAC,QAAD;KAAM,WAAWD,4BAAI;KAArB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,4BAAI;MAAQ,UAAA;KAAY,CAAA,GACxC,gBAAgB,KAAA,KAAa,gBAAgB,MAC5C,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,4BAAI;MAAO,UAAA;KAAkB,CAAA,CAE5C;IACH,CAAA,CAAA;;EAET;;EAGA,SAAS,aAAa,EAAE,OAAO,KAA+C;GAC5E,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWA,4BAAI;IAApB,UAAA,CACG,MAAM,YAAY,KAAA,KACjB,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;KAAG,WAAWA,4BAAI;KACf,UAAA,MAAM,YAAY,cAAc,EAAE,qBAAqB,IAAI,EAAE,uBAAuB;IACpF,CAAA,GAEJ,MAAM,UAAU,KAAK,UAAU,UAC9B,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,4BAAI;KAApB,UAAA;MACG,SAAS,WAAW,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAAS,UAAA,SAAS;MAAY,CAAA;MAC7E,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAAW,UAAA,SAAS;MAAc,CAAA;MACrD,SAAS,WAAW,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAAS,UAAA,SAAS;MAAY,CAAA;MAC5E,SAAS,QAAQ,SAAS,IAEvB,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAApB,UAAA,CACG,SAAS,QAAQ,KAAK,QAAQ,gBAC7B,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;QAEE,OAAO,OAAO;QACd,aAAa,OAAO;QACpB,QAAQ,SAAS,SAAS,SAAS,OAAO,KAAK;OAChD,GAJM,GAAG,OAAO,WAAW,EAAE,GAAG,OAAO,OAIvC,CACF,GAEA,SAAS,WAAW,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;QAAW,OAAO,SAAS;QAAQ,QAAA;OAAQ,CAAA,CACnE;MAGL,CAAA,IAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAApB,UAAA;QACG,SAAS,SAAS,KAAK,QAAQ,gBAC9B,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,4BAAI;SAAsD,UAAA;QAAa,GAAlD,GAAG,OAAO,WAAW,EAAE,GAAG,QAAwB,CACzF;QACA,SAAS,WAAW,MAAM,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,4BAAI;SAAa,UAAA,SAAS;QAAa,CAAA;QAClF,SAAS,SAAS,WAAW,KAAK,SAAS,WAAW,MACrD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,4BAAI;SAAe,UAAA,EAAE,aAAa;QAAQ,CAAA;OAE1D;;KAEN;IA9B0B,GAAA,SAAS,OAAO,KAAK,SAAS,KAAK,IAAI,OAAO,KAAK,GA8B7E,CACN,CACE;;EAET;;;;;;EAOA,SAAgB,eAAe,EAAE,GAAG,OAAO,WAAyB;GAClE,MAAM,SAAA,GAAQE,MAAAA,QAAAA,OAAc,aAAa,KAAK,GAAG,CAAC,KAAK,CAAC;GACxD,MAAM,CAAC,UAAU,gBAAA,GAAeC,MAAAA,SAAAA,CAAS,KAAK;GAC9C,MAAM,UAAU,MAAM,UAAU,SAAS,KAAK,MAAM,iBAAiB;GACrE,MAAM,OAAO,YAAY;GACzB,MAAM,UAAU,MAAM,UAAU,UAC5B,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,UAAD,EAAU,OAAM,QAAS,CAAA,IACzB,MAAM,UAAU,YACd,iBAAA,GAAA,kBAAA,IAAA,CAACA,sCAAAA,UAAD,EAAU,OAAM,UAAW,CAAA,IAC3B,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,uBAAD,CAAwB,CAAA;GAC9B,OAGE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAWL,4BAAI;IAAM,gBAAa;IAAS,aAAU;IAAoB,cAAY,MAAM;IAC9F,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACM,sCAAAA,eAAD;KACE,cAAcN,4BAAI;KAClB,kBAAkBA,4BAAI;KACtB,gBAAgBA,4BAAI;KACpB,kBAAkBA,4BAAI;KACtB,MAAM;KACN,OAAO,EAAE,cAAc;KACjB;KACN,YAAY;KACZ,kBAAA;KACA,qBAAA;KACA,gBAAgB;MAAE,aAAY,UAAS,CAAC,KAAK;KAAE;KAC/C,kBACE,iBAAA,GAAA,kBAAA,KAAA,CAAA,kBAAA,UAAA,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,4BAAI;MAAK,eAAA;KAAa,CAAA,GACvC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAWA,4BAAI;MAAU,UAAA,YAAY,OAAO,CAAC;KAAQ,CAAA,CAC3D,EAAA,CAAA;KAGJ,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAWA,4BAAI;MAApB,UAAA,CACG,MAAM,UAAU,SAAS,IACtB,iBAAA,GAAA,kBAAA,IAAA,CAAC,cAAD;OAAqB;OAAU;MAAI,CAAA,IAEnC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;OAAK,WAAWA,4BAAI;OAAW,UAAA,MAAM;MAAkB,CAAA,GAC1D,YAAY,KAAA,KACX,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;OAAQ,MAAK;OAAS,WAAWA,4BAAI;OAAe,SAAS;OAA7D,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACO,sCAAAA,sBAAD,CAAuB,CAAA,GACtB,EAAE,aAAa,CACV;MAEP,CAAA,CAAA;;IACQ,CAAA;GACZ,CAAA;EAET;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECpHA,MAAM,cAAyD;GAC7D,QAAQ;GACR,QAAQ;GACR,SAAS;GACT,UAAU;EACZ;;EAGA,SAAS,aAAa,MAAgC;GACpD,MAAM,QAAQ,CAAC,OAAO,OAAO,KAAK,QAAQ,GAAG;GAC7C,IAAI,KAAK,kBAAkB,KAAA,GACzB,MAAM,KAAK,KAAK,kBAAkB,KAAA,IAC9B,GAAG,OAAO,KAAK,aAAa,EAAE,MAC9B,GAAG,OAAO,KAAK,aAAa,EAAE,KAAK,OAAO,KAAK,aAAa,EAAE,GAAG;GAEvE,OAAO,MAAM,KAAK,KAAe;EACnC;;EAGA,SAAS,IAAI,EAAE,OAAO,YAAoD;GACxE,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAWC,+BAAI;IAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;KAAI,WAAWA,+BAAI;KAAM,UAAA;IAAU,CAAA,GACnC,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;KAAI,WAAWA,+BAAI;KAAQ;IAAa,CAAA,CACrC;;EAET;;;;;;EAOA,SAAgB,WAAW,EAAE,iBAAkC;GAC7D,MAAM,aAAa,cAAc,MAAM;GACvC,MAAM,CAAC,WAAW,iBAAA,GAAgBC,MAAAA,SAAAA,CAAS,IAAI;GAC/C,MAAM,SAAS,YAAY,KAAK;GAGhC,CAAA,GAAA,MAAA,UAAA,OAAgB;IAAE,aAAa,IAAI;GAAE,GAAG,CAAC,MAAM,CAAC;GAEhD,MAAM,OAAO,YAAY;GACzB,IAAI,SAAS,KAAA,KAAa,SAAS,QAAQ,KAAK,UAAU,YAAY,OAAO;GAE7E,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;IAAS,WAAWD,+BAAI;IAAM,oBAAA;IAAiB,cAAW;IACxD,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAWA,+BAAI;KAApB,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,MAAK;MACL,WAAWA,+BAAI;MACf,iBAAe,CAAC;MAChB,eAAe;OAAE,cAAa,UAAS,CAAC,KAAK;MAAE;MAJjD,UAAA;OAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,+BAAI;QAAM,eAAA;QAAY,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAACE,sCAAAA,mBAAD,EAAmB,MAAM,GAAK,CAAA;OAAO,CAAA;OAC5E,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWF,+BAAI;QAAO,UAAA;OAAU,CAAA;OACtC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,+BAAI;QAAU,UAAA,aAAa,IAAI;OAAQ,CAAA;OACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;QAAM,WAAWA,+BAAI;QAAS,eAAA;QAC3B,UAAA,YAAY,iBAAA,GAAA,kBAAA,IAAA,CAACG,sCAAAA,wBAAD,CAAyB,CAAA,IAAI,iBAAA,GAAA,kBAAA,IAAA,CAACC,sCAAAA,0BAAD,CAA2B,CAAA;OACjE,CAAA;MACA;KACP,CAAA,GAAA,CAAC,aACA,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;MAAI,WAAWJ,+BAAI;MAAnB,UAAA;OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAK,OAAM;QAAM,UAAA,KAAK;OAAe,CAAA;OACrC,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAK,OAAM;QAAM,UAAA,YAAY,KAAK;OAAY,CAAA;OAC7C,KAAK,kBAAkB,KAAA,KACtB,iBAAA,GAAA,kBAAA,KAAA,CAAC,KAAD;QAAK,OAAM;QAAX,UAAA,CACG,KAAK,cAAc,SACpB,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,+BAAI;SAAO,UAAA,KAAK,cAAc;QAAW,CAAA,CACvD;;OAEP,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;QAAK,OAAM;QACT,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;SAAM,WAAWA,+BAAI;SAAO,UAAA,KAAK;QAAS,CAAA;OACvC,CAAA;MACH;KAEH,CAAA,CAAA;;GACE,CAAA;EAEb;;;EC1GA,MAAa,SAAS;GAAC;GAAS;GAAc;GAAU;EAAe;;EAGvE,SAAS,MAAM,OAAoD;GACjE,IAAI,MAAM,SAAS,cAAgC,0BAA0B,aAAa,GAAG;GAC7F,IAAI,QAAQ,MAAM;IAChB,MAAM,SAAS,cAAc,OAAO;IACpC,IAAI,QAAQ,SAAS;IACrB,IAAI,QAAQ,YAAY;IACxB,SAAS,KAAK,YAAY,GAAG;GAC/B;GACA,IAAI,cAAc,SAAS,MAAM,YAAY,CAAC,CAAC,KAAK;EACtD;;;;;EAMA,SAAgB,MAAM,KAA0B;GAG9C,MAAM,QAAQ,IAAI,cAAc,KAA6B,EAAE,WAAW,mBAAmB,CAAC;GAE9F,MAAM,KAAK;GACX,IAAI,aACI,MAAM,gBAAgB;IAAE,MAAM,KAAK;GAAE,CAAC,GAC5C,iDACF;GAEA,MAAM,OAA8B;IAClC,OAAO,EAAE,gBAAgB,MAAM;IAG/B,OAAO,OAAO,UAAU;KACtB,MAAM,MAAM,IAAI,gBAAgB,MAAM,gBAAgB,IAAI;KAC1D,MAAM,MAAM,IAAI,UAAU,MAAM,UAAU,CAAC,CAAC;KAC5C,MAAM,MAAM,IAAI,cAAc,MAAM,cAAc,CAAC,CAAC;IACtD;IACA,kBAAkB,SAAS;KAAE,MAAW,IAAI,gBAAgB,IAAI;IAAE;IAClE,mBAAmB,UAAU,UAAU;KACrC,MAAM,QAAQ,MAAM,YAAY,CAAC,CAAC;KAClC,MAAW,IAAI,UAAU;MAAE,GAAG,OAAO;OAAS,WAAW;KAAM,CAAC;IAClE;IACA,eAAe,MAAM,UAAU;KAC7B,MAAM,QAAQ,MAAM,YAAY,CAAC,CAAC;KAClC,MAAW,IAAI,cAAc;MAAE,GAAG,OAAO;OAAa,OAAO;KAAM,CAAC;IACtE;IACA,kBAAkB,SAAS;KAEzB,MAAM,aAAa,EAAE,GADP,MAAM,YAAY,CAAC,CAAC,OACH,WAAW;KAC1C,OAAO,WAAW;KAClB,MAAW,IAAI,cAAc,UAAU;IACzC;GACF;GAKA,IAAI,MAAM,OAAO,8BAA8B,IAAI,MAAM,SAAS;IAChE,MAAM;IACN,KAAK;IACL,cAAc;GAGhB,GAAY,iBAAiB,CAAC;GAa9B,IAAI,MAAM,OAAO,4BAAqC,IAAI,MAAM,SAAS;IACvE,MAAM;IACN,KAAK;IACL,UAAU;IAGV,QAAQ;GACV,GAAY,cAAuB,CAAC;GASpC,IAAI,MAAM,OAAO,iCAA0C,IAAI,MAAM,SAAS;IAC5E,MAAM;IACN,IAAI;IACJ,OAAO;GACT,GAAY,UAAmB,CAAC;EAClC"}
|
package/lib/index.js
CHANGED
|
@@ -12,6 +12,7 @@ const DEFAULT_COLORS = {
|
|
|
12
12
|
execute: "#f59e0b",
|
|
13
13
|
file: "#22c55e",
|
|
14
14
|
task: "#ec4899",
|
|
15
|
+
ask: "#65a30d",
|
|
15
16
|
command: "#f97316",
|
|
16
17
|
thinking: "#c4b5fd",
|
|
17
18
|
context: "#8a9bb5",
|
|
@@ -26,6 +27,7 @@ const Config = z.object({
|
|
|
26
27
|
execute: z.string().default(DEFAULT_COLORS.execute),
|
|
27
28
|
file: z.string().default(DEFAULT_COLORS.file),
|
|
28
29
|
task: z.string().default(DEFAULT_COLORS.task),
|
|
30
|
+
ask: z.string().default(DEFAULT_COLORS.ask),
|
|
29
31
|
command: z.string().default(DEFAULT_COLORS.command),
|
|
30
32
|
thinking: z.string().default(DEFAULT_COLORS.thinking),
|
|
31
33
|
context: z.string().default(DEFAULT_COLORS.context),
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type AskToolBlock } from './ask-model.ts';
|
|
2
|
+
/** 注入的 locale 翻译函数(注册时声明 `conversation` 命名空间)。 */
|
|
3
|
+
export interface AskTranslate {
|
|
4
|
+
(key: string, params?: Record<string, string | number>): string;
|
|
5
|
+
}
|
|
6
|
+
/** 卡片从 slot owner 收到的字段;其余 owner props 与本行无关。 */
|
|
7
|
+
export interface AskCardProps {
|
|
8
|
+
t: AskTranslate;
|
|
9
|
+
block: AskToolBlock;
|
|
10
|
+
/** 跳到轨迹视图查看原始调用;缺省时不渲染该入口。 */
|
|
11
|
+
inspect?: (() => void) | undefined;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 渲染一次提问的完整记录。
|
|
15
|
+
* @param props - locale 翻译函数、冻结的调用切片与可选的轨迹入口。
|
|
16
|
+
* @returns 折叠行 + 展开后的选项卡片。
|
|
17
|
+
*/
|
|
18
|
+
export declare function AskQuestionRow({ t, block, inspect }: AskCardProps): import("react").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=ask-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask-card.d.ts","sourceRoot":"","sources":["../../../src/client/ask-card.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAgD,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAGhG,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,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,YAAY;IAC3B,CAAC,EAAE,YAAY,CAAA;IACf,KAAK,EAAE,YAAY,CAAA;IACnB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;CACnC;AAiFD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,YAAY,+BAgDjE"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 提问卡数据派生:把一次 `ask_user_question` 调用还原成「问题 + 全部选项 +
|
|
3
|
+
* 实际选中项」。
|
|
4
|
+
*
|
|
5
|
+
* 为什么要自己解析:DSH 官方的转录卡只保留**已选答案**
|
|
6
|
+
* (`ui-tool/src/client/tool/toolviews/ask-question-row.tsx` 的
|
|
7
|
+
* `questionEntries()` 只取 `id`/`question`,把 `options` 丢掉了),所以提问
|
|
8
|
+
* 结算后「当时还有哪些选项」在客户端管线上就没了。选项列表只存在于调用的
|
|
9
|
+
* 参数 JSON 里 —— 这也是本插件接管 `ask_user_question` toolview 的唯一原因。
|
|
10
|
+
*
|
|
11
|
+
* 本模块是纯函数:不碰 locale、不碰 DOM,解析失败一律降级而不是抛错
|
|
12
|
+
* (接管后卡片由我们渲染,渲染不出来就等于用户什么都看不到)。
|
|
13
|
+
*/
|
|
14
|
+
/** 模型给出的一个可选项。 */
|
|
15
|
+
export interface AskOption {
|
|
16
|
+
/** 选项文本;同时是被 `selected` 回传的那个值。 */
|
|
17
|
+
label: string;
|
|
18
|
+
/** 选项下方的补充说明,模型没给时为空。 */
|
|
19
|
+
description: string;
|
|
20
|
+
}
|
|
21
|
+
/** 一个问题:全部选项 + 实际回答。 */
|
|
22
|
+
export interface AskQuestion {
|
|
23
|
+
id: string;
|
|
24
|
+
question: string;
|
|
25
|
+
/** 可选的短标题(模型提供时显示在问题上方)。 */
|
|
26
|
+
header: string;
|
|
27
|
+
/** 可选的补充说明。 */
|
|
28
|
+
detail: string;
|
|
29
|
+
/** 模型是否允许多选。 */
|
|
30
|
+
multiSelect: boolean;
|
|
31
|
+
/** 模型当时给出的全部选项;调用没带选项时为空数组。 */
|
|
32
|
+
options: AskOption[];
|
|
33
|
+
/** 被选中的选项文本,按回答记录的顺序。 */
|
|
34
|
+
selected: string[];
|
|
35
|
+
/** 直接输入的文本答案(没选选项或额外补充时)。 */
|
|
36
|
+
custom: string;
|
|
37
|
+
}
|
|
38
|
+
/** 行的运行状态,与通用工具行保持同一套词汇。 */
|
|
39
|
+
export type AskRowState = 'running' | 'ok' | 'error' | 'stopped';
|
|
40
|
+
/** 问题集的结算程度。 */
|
|
41
|
+
export type AskPhase = 'pending' | 'answered' | 'unanswered';
|
|
42
|
+
/** 卡片渲染所需的全部派生结果。 */
|
|
43
|
+
export interface AskCardModel {
|
|
44
|
+
state: AskRowState;
|
|
45
|
+
phase: AskPhase;
|
|
46
|
+
/** 被取消或被中断时记录判定来源;正常结算为 undefined。 */
|
|
47
|
+
verdict: 'cancelled' | 'aborted' | undefined;
|
|
48
|
+
questions: AskQuestion[];
|
|
49
|
+
/** 至少选了选项或填了自定义答案的问题数(折叠行的 N/M 用)。 */
|
|
50
|
+
answeredCount: number;
|
|
51
|
+
/**
|
|
52
|
+
* 参数 JSON 解析不出来时用于兜底展示的结果文本;运行中或结果无文本时为
|
|
53
|
+
* null。没有它,一次畸形调用会让接管后的行变成空白。
|
|
54
|
+
*/
|
|
55
|
+
fallbackText: string | null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* `ask_user_question` 的 block 里本卡读到的字段子集。
|
|
59
|
+
* 结构照 DSH 的 `ToolCallBlock`(运行中=调用自身,结算后=带 `kind` 的结果
|
|
60
|
+
* 节点)声明为鸭子类型:跨插件只允许 type-only 引用,这里连类型引用都不需要。
|
|
61
|
+
*/
|
|
62
|
+
export interface AskToolBlock {
|
|
63
|
+
/** 运行中的调用没有这个字段;结算后为 `'tool-result'`。 */
|
|
64
|
+
kind?: string | undefined;
|
|
65
|
+
callId?: string | undefined;
|
|
66
|
+
/** 运行中形态:调用自身携带参数。 */
|
|
67
|
+
argsRaw?: string | undefined;
|
|
68
|
+
/** 结算形态:调用头(子调用被剥掉时为 null)。 */
|
|
69
|
+
call?: {
|
|
70
|
+
argsRaw?: string | undefined;
|
|
71
|
+
} | null | undefined;
|
|
72
|
+
/** 结算形态:结果内容块。 */
|
|
73
|
+
content?: readonly unknown[] | undefined;
|
|
74
|
+
error?: {
|
|
75
|
+
code?: string | undefined;
|
|
76
|
+
} | undefined;
|
|
77
|
+
isError?: boolean | undefined;
|
|
78
|
+
}
|
|
79
|
+
/** 从结果内容块拼出展示文本(文本块原样、其余块转 JSON)。 */
|
|
80
|
+
export declare function resultTextOf(block: AskToolBlock): string | null;
|
|
81
|
+
/**
|
|
82
|
+
* 从一次提问调用的冻结切片派生卡片模型。
|
|
83
|
+
* @param block - 运行中的调用或已结算的结果节点。
|
|
84
|
+
* @returns 卡片模型;参数或结果畸形时 `questions` 为空并带兜底文本。
|
|
85
|
+
*/
|
|
86
|
+
export declare function askCardModel(block: AskToolBlock): AskCardModel;
|
|
87
|
+
/** 折叠行右侧的进度计数(文案由组件用 locale 组装)。 */
|
|
88
|
+
export declare function askProgress(model: AskCardModel): {
|
|
89
|
+
answered: number;
|
|
90
|
+
total: number;
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=ask-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask-model.d.ts","sourceRoot":"","sources":["../../../src/client/ask-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,kBAAkB;AAClB,MAAM,WAAW,SAAS;IACxB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,yBAAyB;IACzB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,wBAAwB;AACxB,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,eAAe;IACf,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB;IAChB,WAAW,EAAE,OAAO,CAAA;IACpB,+BAA+B;IAC/B,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB,yBAAyB;IACzB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAA;CACf;AAED,4BAA4B;AAC5B,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,SAAS,CAAA;AAEhE,gBAAgB;AAChB,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,CAAA;AAE5D,qBAAqB;AACrB,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,WAAW,CAAA;IAClB,KAAK,EAAE,QAAQ,CAAA;IACf,sCAAsC;IACtC,OAAO,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,CAAA;IAC5C,SAAS,EAAE,WAAW,EAAE,CAAA;IACxB,sCAAsC;IACtC,aAAa,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5B,+BAA+B;IAC/B,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAA;IAC1D,kBAAkB;IAClB,OAAO,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,CAAA;IACxC,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAA;IACjD,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC9B;AAoBD,qCAAqC;AACrC,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAS/D;AA6ED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,CAwD9D;AAED,oCAAoC;AACpC,wBAAgB,WAAW,CAAC,KAAK,EAAE,YAAY,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAEpF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** 投影里本卡渲染的字段(照 DSH 的 `GoalSnapshot` 声明为鸭子类型)。 */
|
|
2
|
+
export interface GoalSnapshotLike {
|
|
3
|
+
id: string;
|
|
4
|
+
revision: number;
|
|
5
|
+
objective: string;
|
|
6
|
+
phase: 'active' | 'paused' | 'blocked' | 'complete';
|
|
7
|
+
/** 自主轮次上限;未设置时为 undefined。 */
|
|
8
|
+
maxGoalRounds?: number | undefined;
|
|
9
|
+
/** 已开始的自主轮次;旧快照可能没有该字段。 */
|
|
10
|
+
roundsStarted?: number | undefined;
|
|
11
|
+
/** 仅 blocked 阶段存在。 */
|
|
12
|
+
blockedReason?: {
|
|
13
|
+
code: string;
|
|
14
|
+
message: string;
|
|
15
|
+
} | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** `useProjection('goal')` 的返回形状。 */
|
|
18
|
+
export interface GoalProjectionLike {
|
|
19
|
+
goal: GoalSnapshotLike;
|
|
20
|
+
}
|
|
21
|
+
/** 本卡从 slot 标准 props 取用的部分(其余 owner props 与本卡无关)。 */
|
|
22
|
+
export interface GoalDetailProps {
|
|
23
|
+
/** 框架标准投影席位:按 key 读当前会话的投影。 */
|
|
24
|
+
useProjection: (key: string) => GoalProjectionLike | null | undefined;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 渲染目标详情折叠条。
|
|
28
|
+
* @param props - 框架标准投影席位。
|
|
29
|
+
* @returns 折叠条;加载中、无目标、或目标已完成时不渲染(与官方条一致)。
|
|
30
|
+
*/
|
|
31
|
+
export declare function GoalDetail({ useProjection }: GoalDetailProps): import("react").JSX.Element | null;
|
|
32
|
+
//# sourceMappingURL=goal-detail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-detail.d.ts","sourceRoot":"","sources":["../../../src/client/goal-detail.tsx"],"names":[],"mappings":"AAuBA,kDAAkD;AAClD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAA;IACnD,8BAA8B;IAC9B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,2BAA2B;IAC3B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,sBAAsB;IACtB,aAAa,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;CAC9D;AAED,qCAAqC;AACrC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,gBAAgB,CAAA;CACvB;AAED,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAA;CACtE;AA+BD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EAAE,aAAa,EAAE,EAAE,eAAe,sCA6C5D"}
|
|
@@ -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;
|
|
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"}
|
|
@@ -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' | 'command' | 'thinking' | 'context' | 'steering' | 'other';
|
|
13
|
+
export type NodeCategory = 'search' | 'agent' | 'execute' | 'file' | '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,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,CAAA;
|
|
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 +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;
|
|
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"}
|
package/lib/types/index.d.ts
CHANGED
package/lib/types/index.d.ts.map
CHANGED
|
@@ -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,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,
|
|
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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@max-null/dsh-node-appearance",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "会话节点外观插件:节点/工具分类着色(可配置)、提问卡展示全部选项并高亮选中、目标详情折叠条、思考过程显示开关(DeepSeek Harness Web GUI)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -24,8 +24,7 @@
|
|
|
24
24
|
"files": [
|
|
25
25
|
"lib",
|
|
26
26
|
"cordis.patch.yml",
|
|
27
|
-
"README.md"
|
|
28
|
-
],
|
|
27
|
+
"README.md", "docs/shots"],
|
|
29
28
|
"dsh": {
|
|
30
29
|
"bundle": {
|
|
31
30
|
"patch": "./cordis.patch.yml"
|