@cannbot-plugin/cannbot-harness 0.2.0 → 0.2.2
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 +13 -9
- package/lib/client.js +434 -47
- package/lib/client.js.map +1 -1
- package/lib/index.js +107 -2
- package/package.json +14 -2
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# CANNBot Harness
|
|
2
2
|
|
|
3
|
+
插件详情页提供 **检查更新** 按钮。发现新版后,点击 **更新到版本号**,通过 DSH 官方接口安装,保留当前的长包名或短包名入口。检查本身不会自动安装。
|
|
4
|
+
|
|
5
|
+
若当前 DSH 的官方接口要求先卸载,则显示 **下载新版安装包**:先下载文件,再在插件页卸载旧版并添加该文件。首次获得更新按钮需升级到 0.2.2;不修改 DSH 核心。
|
|
6
|
+
|
|
3
7
|
CANNBot Harness 是安装在原版 DeepSeek Harness(DSH)中的独立插件。
|
|
4
8
|
Windows 桌面端和 Linux Web 端使用同一个 `.tgz` 安装包。
|
|
5
9
|
|
|
@@ -7,9 +11,9 @@ Windows 桌面端和 Linux Web 端使用同一个 `.tgz` 安装包。
|
|
|
7
11
|
|
|
8
12
|
- 在 DSH 的插件页面启用 **CANNBot Harness**:立即显示品牌、红白主题和全部 9 个官方工作流,同时挂载 129 个 Skills。
|
|
9
13
|
- 左下角提供 **CANNBot Harness** 开关,启用插件时默认开启。关闭开关仅恢复原版界面,工作流 Skills 继续可用。
|
|
10
|
-
- 选择工作目录,在 **选择工作流**
|
|
11
|
-
|
|
12
|
-
-
|
|
14
|
+
- 选择工作目录,在 **选择工作流** 中选择任一官方工作流。输入框仅填写自己的需求,不会添加 `/工作流名称`。
|
|
15
|
+
手动发送后,插件在 DSH 官方 `agent/pre-step` 扩展点加载对应 Skill,作为后台模型上下文;用户消息正文、引用和附件保持原样。
|
|
16
|
+
- 工作流按会话保存,切换不会修改输入;选择 **普通对话** 可清除本会话的后台工作流。设置保存失败时保留上次成功的选择并提示重试。
|
|
13
17
|
- 在 DSH 的插件页面停用 **CANNBot Harness**:恢复原版界面和模式选择,同时卸载 Skills;重新启用后界面与 Skills 一起恢复。
|
|
14
18
|
- 本插件不提供 SSH 或远程连接控件。Linux 用户通过 DSH 自身的 Web 界面访问服务。
|
|
15
19
|
|
|
@@ -25,13 +29,13 @@ Windows 桌面端和 Linux Web 端使用同一个 `.tgz` 安装包。
|
|
|
25
29
|
Windows 桌面端先正常退出 DSH,再用 DSH 自带的 CLI 安装:
|
|
26
30
|
|
|
27
31
|
```powershell
|
|
28
|
-
dsh plugin --profile desktop add @cannbot-plugin/cannbot-harness@0.2.
|
|
32
|
+
dsh plugin --profile desktop add @cannbot-plugin/cannbot-harness@0.2.2
|
|
29
33
|
```
|
|
30
34
|
|
|
31
35
|
Linux 使用运行 DSH 的同一用户安装,随后启动对应配置:
|
|
32
36
|
|
|
33
37
|
```bash
|
|
34
|
-
dsh plugin --profile web add @cannbot-plugin/cannbot-harness@0.2.
|
|
38
|
+
dsh plugin --profile web add @cannbot-plugin/cannbot-harness@0.2.2
|
|
35
39
|
dsh web --no-open
|
|
36
40
|
```
|
|
37
41
|
|
|
@@ -45,12 +49,12 @@ dsh plugin --profile <你的配置名> remove @cannbot/dsh-harness
|
|
|
45
49
|
|
|
46
50
|
### Windows 桌面端
|
|
47
51
|
|
|
48
|
-
在原版 DSH 的 **插件 → 添加插件** 中安装本地文件 `cannbot-plugin-cannbot-harness-0.2.
|
|
52
|
+
在原版 DSH 的 **插件 → 添加插件** 中安装本地文件 `cannbot-plugin-cannbot-harness-0.2.2.tgz`。
|
|
49
53
|
安装后启用 **CANNBot Harness**。如果当前 DSH 提示需要重启,正常退出并重新打开 DSH。
|
|
50
54
|
也可先完全退出 DSH,再用 DSH 自带的 CLI:
|
|
51
55
|
|
|
52
56
|
```powershell
|
|
53
|
-
dsh plugin --profile desktop add "C:\Downloads\cannbot-plugin-cannbot-harness-0.2.
|
|
57
|
+
dsh plugin --profile desktop add "C:\Downloads\cannbot-plugin-cannbot-harness-0.2.2.tgz"
|
|
54
58
|
```
|
|
55
59
|
|
|
56
60
|
### Linux 浏览器端
|
|
@@ -58,7 +62,7 @@ dsh plugin --profile desktop add "C:\Downloads\cannbot-plugin-cannbot-harness-0.
|
|
|
58
62
|
先安装原版 DSH,再将安装包放到服务器上,以运行 DSH 的同一用户执行:
|
|
59
63
|
|
|
60
64
|
```bash
|
|
61
|
-
dsh plugin --profile web add /path/to/cannbot-plugin-cannbot-harness-0.2.
|
|
65
|
+
dsh plugin --profile web add /path/to/cannbot-plugin-cannbot-harness-0.2.2.tgz
|
|
62
66
|
dsh web --no-open
|
|
63
67
|
```
|
|
64
68
|
|
|
@@ -73,7 +77,7 @@ Node 半区通过官方 `FileSystemSkillProvider` 挂载随包 Skills。
|
|
|
73
77
|
Browser 半区使用原有品牌插槽、`conversation.hero.agentPreset` 和主题覆盖 API。
|
|
74
78
|
插件启用时直接挂载界面;停用时撤销插槽和主题覆盖,原版控件一直保留在下层,不改写 DSH 核心文件。
|
|
75
79
|
工作流图标直接复用 DSH 标准模式使用的 `IconAgentPresetOutlineRegular`。
|
|
76
|
-
|
|
80
|
+
工作流选择通过 DSH 官方设置接口按会话保存。发送时在 `agent/pre-step` 扩展点加载对应 Skill 作为后台上下文,不修改草稿、引用或附件,也不自动提交。
|
|
77
81
|
|
|
78
82
|
首页标题的样式规则仅以本插件的品牌插槽标记为锚点,隐藏旁边的原版标语;不依赖 DSH 私有 CSS 类名。
|
|
79
83
|
该规则与插件的界面生命周期一起撤销。DSH 的插件 API 仍在预览阶段,升级 DSH 后需要重新验证。
|
package/lib/client.js
CHANGED
|
@@ -35,9 +35,25 @@ window.__ModuleLoader__.load({
|
|
|
35
35
|
const NAMESPACE = "cannbotHarness";
|
|
36
36
|
const PACKAGE = "@cannbot-plugin/cannbot-harness";
|
|
37
37
|
const zh = {
|
|
38
|
+
updateTitle: "版本更新",
|
|
39
|
+
updateCurrent: "当前版本",
|
|
40
|
+
updateCheck: "检查更新",
|
|
41
|
+
updateChecking: "正在检查…",
|
|
42
|
+
updateTo: "更新到",
|
|
43
|
+
updateRunning: "正在更新…",
|
|
44
|
+
updateAvailable: "发现新版本,点击上方按钮更新。",
|
|
45
|
+
updateLatest: "当前已是最新版本。",
|
|
46
|
+
updateDone: "更新已完成。",
|
|
47
|
+
updateRestart: "新版已安装,重启 DSH 后生效。",
|
|
48
|
+
updateManual: "当前 DSH 要求先卸载旧版。请先下载新版包,再在插件页卸载旧版并添加下载的安装包。",
|
|
49
|
+
updateIncompatible: "当前 DSH 不支持此版本,请先升级 DSH。",
|
|
50
|
+
updateFailed: "暂时无法完成,请稍后重试。",
|
|
51
|
+
updateDownload: "下载新版安装包",
|
|
38
52
|
workflow: "选择工作流",
|
|
53
|
+
ordinary: "普通对话",
|
|
54
|
+
saving: "正在应用工作流…",
|
|
39
55
|
operator: "算子开发工作流",
|
|
40
|
-
commandHint: "
|
|
56
|
+
commandHint: "发送时自动应用所选工作流,只需填写需求。",
|
|
41
57
|
flash: "Ascend C Flash 核函数开发",
|
|
42
58
|
registry: "ACLNN / GEIR 注册算子开发",
|
|
43
59
|
model: "NPU 模型推理优化",
|
|
@@ -47,12 +63,28 @@ window.__ModuleLoader__.load({
|
|
|
47
63
|
performance: "Ascend C 性能调优",
|
|
48
64
|
pypto: "PyPTO 算子开发",
|
|
49
65
|
chooseWorkspace: "请先选择工作目录。",
|
|
50
|
-
insertFailed: "
|
|
66
|
+
insertFailed: "工作流设置未保存,请稍后重试。"
|
|
51
67
|
};
|
|
52
68
|
const en = {
|
|
69
|
+
updateTitle: "Updates",
|
|
70
|
+
updateCurrent: "Installed version",
|
|
71
|
+
updateCheck: "Check for updates",
|
|
72
|
+
updateChecking: "Checking…",
|
|
73
|
+
updateTo: "Update to",
|
|
74
|
+
updateRunning: "Updating…",
|
|
75
|
+
updateAvailable: "A new version is available. Use the button above to update.",
|
|
76
|
+
updateLatest: "You are up to date.",
|
|
77
|
+
updateDone: "Update completed.",
|
|
78
|
+
updateRestart: "The update is installed. Restart DSH to apply it.",
|
|
79
|
+
updateManual: "This DSH version requires removing the old plugin first. Download the update, then uninstall the old plugin and add the downloaded package.",
|
|
80
|
+
updateIncompatible: "This release requires updating DSH first.",
|
|
81
|
+
updateFailed: "Unable to complete this operation. Please retry.",
|
|
82
|
+
updateDownload: "Download update",
|
|
53
83
|
workflow: "Choose workflow",
|
|
84
|
+
ordinary: "Ordinary conversation",
|
|
85
|
+
saving: "Applying workflow…",
|
|
54
86
|
operator: "Operator development workflow",
|
|
55
|
-
commandHint: "
|
|
87
|
+
commandHint: "The selected workflow is applied in the background when you send.",
|
|
56
88
|
flash: "Ascend C Flash kernel development",
|
|
57
89
|
registry: "ACLNN / GEIR operator development",
|
|
58
90
|
model: "NPU model inference optimization",
|
|
@@ -62,7 +94,7 @@ window.__ModuleLoader__.load({
|
|
|
62
94
|
performance: "Ascend C performance tuning",
|
|
63
95
|
pypto: "PyPTO operator development",
|
|
64
96
|
chooseWorkspace: "Choose a working directory first.",
|
|
65
|
-
insertFailed: "The
|
|
97
|
+
insertFailed: "The workflow preference was not saved. Please retry."
|
|
66
98
|
};
|
|
67
99
|
//#endregion
|
|
68
100
|
//#region src/client/Brand.tsx
|
|
@@ -171,26 +203,15 @@ window.__ModuleLoader__.load({
|
|
|
171
203
|
//#endregion
|
|
172
204
|
//#region src/client/WorkflowSelector.tsx
|
|
173
205
|
/** Select a workflow without submitting, replacing text, or discarding reference chips. */
|
|
174
|
-
function WorkflowSelector({ inputActions, useInput, t }) {
|
|
206
|
+
function WorkflowSelector({ sessionId, inputActions, useInput, t, selection }) {
|
|
175
207
|
const input = useInput((state) => state);
|
|
208
|
+
const saved = (0, react.useSyncExternalStore)(selection.subscribe, selection.getSnapshot);
|
|
176
209
|
const [open, setOpen] = (0, react.useState)(false);
|
|
177
|
-
const
|
|
178
|
-
const
|
|
179
|
-
const
|
|
180
|
-
const pick = (workflow) => {
|
|
210
|
+
const selected = WORKFLOWS.find((workflow) => sessionId && saved.values[sessionId] === workflow.id);
|
|
211
|
+
const available = !!sessionId && saved.ready && !saved.pending && inputActions !== void 0 && input !== void 0 && input.phase === "plain";
|
|
212
|
+
const pick = (id) => {
|
|
181
213
|
setOpen(false);
|
|
182
|
-
if (
|
|
183
|
-
if (selected?.id === workflow.id) {
|
|
184
|
-
setFailed(false);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
const oldCommand = selected ? `/${selected.id}` : "";
|
|
188
|
-
const end = oldCommand.length + (oldCommand && input.draft[oldCommand.length] === " " ? 1 : 0);
|
|
189
|
-
setFailed(!inputActions.insertText(`/${workflow.id} `, {
|
|
190
|
-
start: 0,
|
|
191
|
-
end,
|
|
192
|
-
draftRev: input.draftRev
|
|
193
|
-
}));
|
|
214
|
+
if (sessionId && available) selection.choose(sessionId, id, t("saving"));
|
|
194
215
|
};
|
|
195
216
|
const anchor = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
196
217
|
type: "button",
|
|
@@ -210,24 +231,28 @@ window.__ModuleLoader__.load({
|
|
|
210
231
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronIcon, { size: 12 })
|
|
211
232
|
]
|
|
212
233
|
});
|
|
213
|
-
const label = (workflow) => /* @__PURE__ */ (0, react_jsx_runtime.
|
|
234
|
+
const label = (workflow) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
214
235
|
className: "cannbot-harness-workflow-option",
|
|
215
|
-
children:
|
|
236
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(workflow.label) })
|
|
216
237
|
});
|
|
217
238
|
const { Menu, MenuItemButton } = _deepseek_ai_dsh_client_ui_primitives;
|
|
218
239
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
219
240
|
className: "cannbot-harness-workflow",
|
|
220
|
-
children: [typeof MenuItemButton === "function" ? /* @__PURE__ */ (0, react_jsx_runtime.
|
|
241
|
+
children: [typeof MenuItemButton === "function" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Menu, {
|
|
221
242
|
open,
|
|
222
243
|
onClose: () => setOpen(false),
|
|
223
244
|
portal: true,
|
|
224
245
|
className: "cannbot-harness-workflow-anchor",
|
|
225
246
|
anchor,
|
|
226
|
-
children:
|
|
247
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuItemButton, {
|
|
248
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkflowIcon, {}),
|
|
249
|
+
onSelect: () => pick(""),
|
|
250
|
+
children: t("ordinary")
|
|
251
|
+
}), WORKFLOWS.map((workflow) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MenuItemButton, {
|
|
227
252
|
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkflowIcon, {}),
|
|
228
|
-
onSelect: () => pick(workflow),
|
|
253
|
+
onSelect: () => pick(workflow.id),
|
|
229
254
|
children: label(workflow)
|
|
230
|
-
}, workflow.id))
|
|
255
|
+
}, workflow.id))]
|
|
231
256
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Menu, {
|
|
232
257
|
open,
|
|
233
258
|
onClose: () => setOpen(false),
|
|
@@ -235,16 +260,17 @@ window.__ModuleLoader__.load({
|
|
|
235
260
|
className: "cannbot-harness-workflow-anchor",
|
|
236
261
|
anchor,
|
|
237
262
|
selectedId: selected?.id,
|
|
238
|
-
items:
|
|
263
|
+
items: [{
|
|
264
|
+
id: "",
|
|
265
|
+
label: t("ordinary"),
|
|
266
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkflowIcon, {})
|
|
267
|
+
}, ...WORKFLOWS.map((workflow) => ({
|
|
239
268
|
id: workflow.id,
|
|
240
269
|
label: label(workflow),
|
|
241
270
|
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkflowIcon, {})
|
|
242
|
-
})),
|
|
243
|
-
onSelect:
|
|
244
|
-
|
|
245
|
-
if (workflow) pick(workflow);
|
|
246
|
-
}
|
|
247
|
-
}), failed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
271
|
+
}))],
|
|
272
|
+
onSelect: pick
|
|
273
|
+
}), saved.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
248
274
|
role: "alert",
|
|
249
275
|
className: "cannbot-harness-error",
|
|
250
276
|
children: t("insertFailed")
|
|
@@ -262,22 +288,18 @@ window.__ModuleLoader__.load({
|
|
|
262
288
|
});
|
|
263
289
|
}
|
|
264
290
|
function LegacyWorkflow({ ctx, ...props }) {
|
|
265
|
-
const
|
|
291
|
+
const legacy = ctx;
|
|
292
|
+
const sessions = (0, react.useSyncExternalStore)(legacy.sessions.list.subscribe, legacy.sessions.list.getSnapshot);
|
|
266
293
|
const input = (0, react.useMemo)(() => {
|
|
267
|
-
const scope = sessions.current &&
|
|
294
|
+
const scope = sessions.current && legacy.sessions.scope(sessions.current);
|
|
268
295
|
return scope ? ctx.conversation.input.for(scope) : void 0;
|
|
269
296
|
}, [ctx, sessions.current]);
|
|
270
297
|
const state = (0, react.useSyncExternalStore)(input?.state.subscribe ?? noSubscribe, input?.state.getSnapshot ?? noSnapshot);
|
|
271
|
-
const inputActions = input ? { insertText(text, span) {
|
|
272
|
-
const current = input.state.getSnapshot();
|
|
273
|
-
if (current.phase !== "plain" || current.draftRev !== span.draftRev) return false;
|
|
274
|
-
input.setDraft(current.draft.slice(0, span.start) + text + current.draft.slice(span.end));
|
|
275
|
-
return true;
|
|
276
|
-
} } : void 0;
|
|
277
298
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkflowSelector, {
|
|
278
299
|
...props,
|
|
300
|
+
sessionId: sessions.current,
|
|
279
301
|
useInput: (select) => state ? select(state) : void 0,
|
|
280
|
-
inputActions
|
|
302
|
+
inputActions: input ? {} : void 0
|
|
281
303
|
});
|
|
282
304
|
}
|
|
283
305
|
const noSubscribe = () => () => {};
|
|
@@ -334,7 +356,7 @@ window.__ModuleLoader__.load({
|
|
|
334
356
|
var interface_css_default = "span:has(>[data-slot=\"conversation.hero.brand.mark\"]>[data-cannbot-harness-hero]){width:auto;min-width:0;height:auto}span:has(>[data-slot=\"conversation.hero.brand.mark\"]>[data-cannbot-harness-hero])+span{display:none}[data-cannbot-harness-hero]{letter-spacing:-.6px;color:var(--dsw-alias-label-primary);justify-content:center;align-items:center;gap:12px;font-size:26px;font-weight:650;line-height:1.3;display:inline-flex}[data-cannbot-harness-hero] svg{flex-shrink:0}.cannbot-harness-name{letter-spacing:-.3px;font-weight:650}";
|
|
335
357
|
//#endregion
|
|
336
358
|
//#region \0dsh-global-css:D:\code\cannbot-harness-plugin\src\client\controls.css.mjs
|
|
337
|
-
const css = ".cannbot-harness-workflow{align-items:center;min-width:0;max-width:240px;display:inline-flex;position:relative}.cannbot-harness-workflow-anchor{min-width:54px;max-width:100%}.cannbot-harness-workflow-trigger{border-radius:var(--dsw-radius-sm);min-width:0;max-width:100%;min-height:28px;color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border:0;align-items:center;gap:4px;padding:0 8px;font-family:inherit;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.cannbot-harness-workflow-trigger svg{flex:none}.cannbot-harness-workflow-trigger svg:last-child{color:var(--dsw-alias-label-caption)}.cannbot-harness-workflow-trigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}.cannbot-harness-workflow-trigger:disabled{cursor:default;color:var(--dsw-alias-label-quaternary)}.cannbot-harness-workflow-trigger:focus-visible{outline:2px solid var(--dsw-focus-ring-color);outline-offset:2px}.cannbot-harness-workflow-label{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}@media (hover:hover){.cannbot-harness-workflow-trigger:not(:disabled):hover{background:var(--dsw-alias-interactive-bg-hover)}}.cannbot-harness-workflow-option{white-space:normal;flex-direction:column;gap:4px;max-width:320px;padding:5px 0;display:flex}.cannbot-harness-workflow-option small{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}.cannbot-harness-error{color:var(--dsw-alias-label-secondary);margin:4px 0;font-size:12px}.cannbot-harness-toggle{box-sizing:border-box;justify-content:space-between;align-items:center;gap:8px;width:100%;padding:8px;display:flex}.cannbot-harness-toggle-name{min-width:0;color:var(--dsw-alias-label-primary);align-items:center;gap:8px;font-size:12px;line-height:20px;display:inline-flex}.cannbot-harness-toggle-name svg{flex-shrink:0}.cannbot-harness-toggle-compact{flex-direction:column;gap:6px}.cannbot-harness-switch{background:var(--dsw-alias-interactive-bg-hover,#d7dadd);cursor:pointer;border:0;border-radius:99px;flex-shrink:0;width:36px;height:20px;padding:2px}.cannbot-harness-switch[aria-checked=true]{background:#cf1740}.cannbot-harness-switch>span{background:#fff;border-radius:50%;width:16px;height:16px;display:block;transform:translate(0)}.cannbot-harness-switch[aria-checked=true]>span{transform:translate(16px)}.cannbot-harness-switch:focus-visible{outline:2px solid var(--dsw-focus-ring-color,#cf1740);outline-offset:2px}";
|
|
359
|
+
const css = ".cannbot-harness-workflow{align-items:center;min-width:0;max-width:240px;display:inline-flex;position:relative}.cannbot-harness-workflow-anchor{min-width:54px;max-width:100%}.cannbot-harness-workflow-trigger{border-radius:var(--dsw-radius-sm);min-width:0;max-width:100%;min-height:28px;color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border:0;align-items:center;gap:4px;padding:0 8px;font-family:inherit;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.cannbot-harness-workflow-trigger svg{flex:none}.cannbot-harness-workflow-trigger svg:last-child{color:var(--dsw-alias-label-caption)}.cannbot-harness-workflow-trigger[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}.cannbot-harness-workflow-trigger:disabled{cursor:default;color:var(--dsw-alias-label-quaternary)}.cannbot-harness-workflow-trigger:focus-visible{outline:2px solid var(--dsw-focus-ring-color);outline-offset:2px}.cannbot-harness-workflow-label{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}@media (hover:hover){.cannbot-harness-workflow-trigger:not(:disabled):hover{background:var(--dsw-alias-interactive-bg-hover)}}.cannbot-harness-workflow-option{white-space:normal;flex-direction:column;gap:4px;max-width:320px;padding:5px 0;display:flex}.cannbot-harness-workflow-option small{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}.cannbot-harness-error{color:var(--dsw-alias-label-secondary);margin:4px 0;font-size:12px}.cannbot-harness-toggle{box-sizing:border-box;justify-content:space-between;align-items:center;gap:8px;width:100%;padding:8px;display:flex}.cannbot-harness-toggle-name{min-width:0;color:var(--dsw-alias-label-primary);align-items:center;gap:8px;font-size:12px;line-height:20px;display:inline-flex}.cannbot-harness-toggle-name svg{flex-shrink:0}.cannbot-harness-toggle-compact{flex-direction:column;gap:6px}.cannbot-harness-switch{background:var(--dsw-alias-interactive-bg-hover,#d7dadd);cursor:pointer;border:0;border-radius:99px;flex-shrink:0;width:36px;height:20px;padding:2px}.cannbot-harness-switch[aria-checked=true]{background:#cf1740}.cannbot-harness-switch>span{background:#fff;border-radius:50%;width:16px;height:16px;display:block;transform:translate(0)}.cannbot-harness-switch[aria-checked=true]>span{transform:translate(16px)}.cannbot-harness-switch:focus-visible{outline:2px solid var(--dsw-focus-ring-color,#cf1740);outline-offset:2px}.cannbot-harness-update{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:var(--dsw-radius-md,12px);color:var(--dsw-alias-label-primary);padding:16px}.cannbot-harness-update-heading{flex-wrap:wrap;align-items:baseline;gap:12px;margin-bottom:14px;display:flex}.cannbot-harness-update h4{margin:0;font-size:14px;font-weight:600}.cannbot-harness-update-heading>span,.cannbot-harness-update p{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.6}.cannbot-harness-update-actions{flex-wrap:wrap;align-items:center;gap:12px;display:flex}.cannbot-harness-update-button{box-sizing:border-box;background:var(--dsw-alias-brand-primary,#cf1740);color:#fff;min-height:32px;font:inherit;cursor:pointer;border:0;border-radius:8px;align-items:center;padding:5px 14px;font-size:13px;text-decoration:none;display:inline-flex}.cannbot-harness-update-button:disabled{opacity:.6;cursor:default}.cannbot-harness-update-button:focus-visible,.cannbot-harness-update-recheck:focus-visible{outline:2px solid var(--dsw-focus-ring-color,#cf1740);outline-offset:3px}.cannbot-harness-update-recheck{font:inherit;color:var(--dsw-alias-brand-primary,#cf1740);cursor:pointer;background:0 0;border:0;padding:4px;font-size:12px}.cannbot-harness-update p{margin:10px 0 0}";
|
|
338
360
|
const tagId = "@cannbot-plugin/cannbot-harness/controls.css";
|
|
339
361
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
340
362
|
const tag = document.createElement("style");
|
|
@@ -406,6 +428,356 @@ window.__ModuleLoader__.load({
|
|
|
406
428
|
return typeof ctx.slots.inject === "function" ? ctx.slots.inject(name, register) : register();
|
|
407
429
|
}
|
|
408
430
|
//#endregion
|
|
431
|
+
//#region src/client/workflow-selection.ts
|
|
432
|
+
const NS = "cannbot-harness";
|
|
433
|
+
const valuesOf = (view) => Object.fromEntries((view?.value.selections ?? []).map((item) => [item.sessionId, item.workflow]));
|
|
434
|
+
function createWorkflowSelection(blockSubmission = () => () => {}) {
|
|
435
|
+
let snapshot = {
|
|
436
|
+
ready: false,
|
|
437
|
+
pending: false,
|
|
438
|
+
error: false,
|
|
439
|
+
values: {}
|
|
440
|
+
};
|
|
441
|
+
let transport;
|
|
442
|
+
let generation = 0;
|
|
443
|
+
let pendingRelease;
|
|
444
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
445
|
+
const publish = (next) => {
|
|
446
|
+
snapshot = next;
|
|
447
|
+
for (const listener of listeners) listener();
|
|
448
|
+
};
|
|
449
|
+
return {
|
|
450
|
+
subscribe(listener) {
|
|
451
|
+
listeners.add(listener);
|
|
452
|
+
return () => {
|
|
453
|
+
listeners.delete(listener);
|
|
454
|
+
};
|
|
455
|
+
},
|
|
456
|
+
getSnapshot: () => snapshot,
|
|
457
|
+
attach(next) {
|
|
458
|
+
transport = next;
|
|
459
|
+
const own = ++generation;
|
|
460
|
+
next.describe().then((view) => {
|
|
461
|
+
if (own !== generation) return;
|
|
462
|
+
const section = view.namespaces.find((item) => item.ns === NS);
|
|
463
|
+
publish({
|
|
464
|
+
ready: !!section,
|
|
465
|
+
pending: false,
|
|
466
|
+
error: !section,
|
|
467
|
+
values: valuesOf(section)
|
|
468
|
+
});
|
|
469
|
+
}).catch(() => {
|
|
470
|
+
if (own === generation) publish({
|
|
471
|
+
...snapshot,
|
|
472
|
+
ready: false,
|
|
473
|
+
error: true
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
return () => {
|
|
477
|
+
if (own === generation) {
|
|
478
|
+
generation++;
|
|
479
|
+
transport = void 0;
|
|
480
|
+
publish({
|
|
481
|
+
...snapshot,
|
|
482
|
+
ready: false
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
},
|
|
487
|
+
async choose(sessionId, workflow, reason = "CANNBot Harness…") {
|
|
488
|
+
if (!transport || !snapshot.ready || snapshot.pending) return;
|
|
489
|
+
if (workflow !== "" && !WORKFLOWS.some((item) => item.id === workflow)) throw new Error("Unknown workflow");
|
|
490
|
+
const current = transport, own = generation;
|
|
491
|
+
const unblock = blockSubmission(sessionId, reason);
|
|
492
|
+
let released = false;
|
|
493
|
+
const release = () => {
|
|
494
|
+
if (!released) {
|
|
495
|
+
released = true;
|
|
496
|
+
unblock();
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
pendingRelease = release;
|
|
500
|
+
publish({
|
|
501
|
+
...snapshot,
|
|
502
|
+
pending: true,
|
|
503
|
+
error: false
|
|
504
|
+
});
|
|
505
|
+
try {
|
|
506
|
+
const view = (await current.describe()).namespaces.find((item) => item.ns === NS);
|
|
507
|
+
if (!view) throw new Error("Workflow settings unavailable");
|
|
508
|
+
const values = {
|
|
509
|
+
...valuesOf(view),
|
|
510
|
+
[sessionId]: workflow
|
|
511
|
+
};
|
|
512
|
+
const selections = Object.entries(values).filter(([, id]) => id !== "").map(([sessionId, workflow]) => ({
|
|
513
|
+
sessionId,
|
|
514
|
+
workflow
|
|
515
|
+
}));
|
|
516
|
+
const result = await current.update(NS, { selections }, view.revision);
|
|
517
|
+
if (own === generation) publish({
|
|
518
|
+
ready: true,
|
|
519
|
+
pending: false,
|
|
520
|
+
error: false,
|
|
521
|
+
values: valuesOf(result)
|
|
522
|
+
});
|
|
523
|
+
} catch {
|
|
524
|
+
if (own === generation) publish({
|
|
525
|
+
...snapshot,
|
|
526
|
+
pending: false,
|
|
527
|
+
error: true
|
|
528
|
+
});
|
|
529
|
+
} finally {
|
|
530
|
+
release();
|
|
531
|
+
if (pendingRelease === release) pendingRelease = void 0;
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
dispose() {
|
|
535
|
+
generation++;
|
|
536
|
+
transport = void 0;
|
|
537
|
+
pendingRelease?.();
|
|
538
|
+
pendingRelease = void 0;
|
|
539
|
+
listeners.clear();
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
/** Both transports are official DSH settings APIs; no private editor access. */
|
|
544
|
+
function connectWorkflowSelection(ctx, selection) {
|
|
545
|
+
ctx.inject(["remote", "remote.settings"], (scoped) => {
|
|
546
|
+
const settings = scoped.remote.settings;
|
|
547
|
+
scoped.effect(() => selection.attach({
|
|
548
|
+
describe: async () => unwrap$1(await settings.describe()),
|
|
549
|
+
update: async (ns, patch, revision) => unwrap$1(await settings.update(ns, patch, revision))
|
|
550
|
+
}));
|
|
551
|
+
});
|
|
552
|
+
ctx.inject(["connection"], (scoped) => {
|
|
553
|
+
const api = scoped.connection.api;
|
|
554
|
+
if (!api?.settings) return;
|
|
555
|
+
scoped.effect(() => selection.attach({
|
|
556
|
+
describe: async () => unwrap$1(await api.settings.describe({})),
|
|
557
|
+
update: async (ns, patch, expectedRevision) => unwrap$1(await api.settings.update({
|
|
558
|
+
ns,
|
|
559
|
+
patch,
|
|
560
|
+
expectedRevision
|
|
561
|
+
}))
|
|
562
|
+
}));
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
function unwrap$1(response) {
|
|
566
|
+
const result = response.result ?? response;
|
|
567
|
+
if (!result.ok) throw new Error(result.error?.message ?? "Workflow settings failed");
|
|
568
|
+
return result.value;
|
|
569
|
+
}
|
|
570
|
+
//#endregion
|
|
571
|
+
//#region src/client/plugin-update.ts
|
|
572
|
+
const UPDATE_PACKAGES = ["cannbot-harness", "@cannbot-plugin/cannbot-harness"];
|
|
573
|
+
/** Only stable npm releases of our two installation entries may be selected. */
|
|
574
|
+
function newerVersion(candidate, current) {
|
|
575
|
+
const next = /^(\d+)\.(\d+)\.(\d+)$/.exec(candidate);
|
|
576
|
+
const old = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(current);
|
|
577
|
+
if (!next || !old) return false;
|
|
578
|
+
for (let index = 1; index < 4; index++) {
|
|
579
|
+
const difference = Number(next[index]) - Number(old[index]);
|
|
580
|
+
if (difference) return difference > 0;
|
|
581
|
+
}
|
|
582
|
+
return current.includes("-");
|
|
583
|
+
}
|
|
584
|
+
async function latestRelease(name, signal) {
|
|
585
|
+
if (!UPDATE_PACKAGES.includes(name)) throw new Error("Unsupported update target");
|
|
586
|
+
const answers = await Promise.allSettled(["https://registry.npmjs.org/", "https://registry.npmmirror.com/"].map(async (registry) => {
|
|
587
|
+
const response = await fetch(`${registry}${encodeURIComponent(name)}/latest`, {
|
|
588
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(15e3)]),
|
|
589
|
+
cache: "no-store"
|
|
590
|
+
});
|
|
591
|
+
if (!response.ok) throw new Error("Registry unavailable");
|
|
592
|
+
const manifest = await response.json();
|
|
593
|
+
if (manifest.name !== name || !manifest.version || !/^\d+\.\d+\.\d+$/.test(manifest.version) || !manifest.dsh?.bundle || !manifest.dist?.tarball) throw new Error("Invalid release");
|
|
594
|
+
const url = new URL(manifest.dist.tarball);
|
|
595
|
+
if (url.protocol !== "https:" || !["registry.npmjs.org", "registry.npmmirror.com"].includes(url.hostname)) throw new Error("Invalid download origin");
|
|
596
|
+
return {
|
|
597
|
+
name,
|
|
598
|
+
version: manifest.version,
|
|
599
|
+
tarball: url.href
|
|
600
|
+
};
|
|
601
|
+
}));
|
|
602
|
+
signal.throwIfAborted();
|
|
603
|
+
const latest = answers.flatMap((answer) => answer.status === "fulfilled" ? [answer.value] : []).reduce((best, release) => !best || newerVersion(release.version, best.version) ? release : best, void 0);
|
|
604
|
+
if (!latest) throw new Error("No release available");
|
|
605
|
+
return latest;
|
|
606
|
+
}
|
|
607
|
+
function createPluginUpdater(bridge, requestedName, lookup = latestRelease) {
|
|
608
|
+
let state = { phase: "idle" };
|
|
609
|
+
let disposed = false;
|
|
610
|
+
let checking;
|
|
611
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
612
|
+
const publish = (next) => {
|
|
613
|
+
if (disposed) return;
|
|
614
|
+
state = next;
|
|
615
|
+
for (const listener of listeners) listener();
|
|
616
|
+
};
|
|
617
|
+
const failed = (result) => !["applied", "restart-required"].includes(result.application) || !!result.error;
|
|
618
|
+
return {
|
|
619
|
+
getSnapshot: () => state,
|
|
620
|
+
subscribe(listener) {
|
|
621
|
+
listeners.add(listener);
|
|
622
|
+
return () => {
|
|
623
|
+
listeners.delete(listener);
|
|
624
|
+
};
|
|
625
|
+
},
|
|
626
|
+
async check() {
|
|
627
|
+
if (disposed || state.phase === "checking" || state.phase === "updating") return;
|
|
628
|
+
checking?.abort();
|
|
629
|
+
const abort = new AbortController();
|
|
630
|
+
checking = abort;
|
|
631
|
+
publish({
|
|
632
|
+
...state,
|
|
633
|
+
phase: "checking"
|
|
634
|
+
});
|
|
635
|
+
try {
|
|
636
|
+
const bundles = (await bridge.list()).filter((bundle) => bundle.installed && UPDATE_PACKAGES.includes(bundle.name));
|
|
637
|
+
const bundle = bundles.find((bundle) => bundle.name === requestedName) ?? bundles[0];
|
|
638
|
+
if (!bundle?.version) throw new Error("Installed entry unavailable");
|
|
639
|
+
publish({
|
|
640
|
+
...state,
|
|
641
|
+
current: bundle.version,
|
|
642
|
+
packageName: bundle.name
|
|
643
|
+
});
|
|
644
|
+
const release = await lookup(bundle.name, abort.signal);
|
|
645
|
+
if (checking !== abort || disposed) return;
|
|
646
|
+
publish({
|
|
647
|
+
phase: newerVersion(release.version, bundle.version) ? "available" : "latest",
|
|
648
|
+
current: bundle.version,
|
|
649
|
+
release,
|
|
650
|
+
packageName: bundle.name
|
|
651
|
+
});
|
|
652
|
+
} catch {
|
|
653
|
+
if (!abort.signal.aborted) publish({
|
|
654
|
+
...state,
|
|
655
|
+
phase: "error"
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
},
|
|
659
|
+
async update() {
|
|
660
|
+
if (disposed || state.phase !== "available" || !state.release || !state.packageName) return;
|
|
661
|
+
const target = state.release, name = state.packageName;
|
|
662
|
+
publish({
|
|
663
|
+
...state,
|
|
664
|
+
phase: "updating"
|
|
665
|
+
});
|
|
666
|
+
try {
|
|
667
|
+
const result = (bridge.update ? await bridge.update(name, target.version) : { result: await bridge.install(`${name}@${target.version}`) }).result;
|
|
668
|
+
if (failed(result)) {
|
|
669
|
+
const code = result.error?.code;
|
|
670
|
+
publish({
|
|
671
|
+
...state,
|
|
672
|
+
phase: code === "already-installed" || code === "stop-profile" ? "manual" : code === "incompatible-version" ? "incompatible" : "error"
|
|
673
|
+
});
|
|
674
|
+
} else publish({
|
|
675
|
+
...state,
|
|
676
|
+
phase: result.application === "restart-required" ? "restart" : "done",
|
|
677
|
+
current: target.version
|
|
678
|
+
});
|
|
679
|
+
} catch {
|
|
680
|
+
publish({
|
|
681
|
+
...state,
|
|
682
|
+
phase: "error"
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
},
|
|
686
|
+
dispose() {
|
|
687
|
+
disposed = true;
|
|
688
|
+
checking?.abort();
|
|
689
|
+
listeners.clear();
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
//#endregion
|
|
694
|
+
//#region src/client/PluginUpdateCard.tsx
|
|
695
|
+
function PluginUpdateCard({ updater, t }) {
|
|
696
|
+
const state = (0, react.useSyncExternalStore)(updater.subscribe, updater.getSnapshot);
|
|
697
|
+
(0, react.useEffect)(() => {
|
|
698
|
+
updater.check();
|
|
699
|
+
}, [updater]);
|
|
700
|
+
const busy = state.phase === "checking" || state.phase === "updating";
|
|
701
|
+
const canUpdate = state.phase === "available";
|
|
702
|
+
const message = state.phase === "latest" ? t("updateLatest") : state.phase === "available" ? t("updateAvailable") : state.phase === "updating" ? t("updateRunning") : state.phase === "done" ? t("updateDone") : state.phase === "restart" ? t("updateRestart") : state.phase === "manual" ? t("updateManual") : state.phase === "incompatible" ? t("updateIncompatible") : state.phase === "error" ? t("updateFailed") : "";
|
|
703
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
704
|
+
className: "cannbot-harness-update",
|
|
705
|
+
"aria-label": t("updateTitle"),
|
|
706
|
+
children: [
|
|
707
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
708
|
+
className: "cannbot-harness-update-heading",
|
|
709
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", { children: t("updateTitle") }), state.current && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
710
|
+
t("updateCurrent"),
|
|
711
|
+
" ",
|
|
712
|
+
state.current
|
|
713
|
+
] })]
|
|
714
|
+
}),
|
|
715
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
716
|
+
className: "cannbot-harness-update-actions",
|
|
717
|
+
children: state.phase === "manual" && state.release ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
718
|
+
className: "cannbot-harness-update-button",
|
|
719
|
+
href: state.release.tarball,
|
|
720
|
+
download: true,
|
|
721
|
+
rel: "noreferrer",
|
|
722
|
+
children: [
|
|
723
|
+
t("updateDownload"),
|
|
724
|
+
" ",
|
|
725
|
+
state.release.version
|
|
726
|
+
]
|
|
727
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
728
|
+
type: "button",
|
|
729
|
+
className: "cannbot-harness-update-recheck",
|
|
730
|
+
onClick: () => {
|
|
731
|
+
updater.check();
|
|
732
|
+
},
|
|
733
|
+
children: t("updateCheck")
|
|
734
|
+
})] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
735
|
+
type: "button",
|
|
736
|
+
className: "cannbot-harness-update-button",
|
|
737
|
+
disabled: busy,
|
|
738
|
+
onClick: () => {
|
|
739
|
+
canUpdate ? updater.update() : updater.check();
|
|
740
|
+
},
|
|
741
|
+
children: state.phase === "checking" ? t("updateChecking") : state.phase === "updating" ? t("updateRunning") : canUpdate ? `${t("updateTo")} ${state.release?.version}` : t("updateCheck")
|
|
742
|
+
})
|
|
743
|
+
}),
|
|
744
|
+
message && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
745
|
+
role: state.phase === "error" ? "alert" : "status",
|
|
746
|
+
"aria-live": "polite",
|
|
747
|
+
children: message
|
|
748
|
+
})
|
|
749
|
+
]
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
//#endregion
|
|
753
|
+
//#region src/client/register-updates.ts
|
|
754
|
+
/** Optional integration: old DSH versions without a Plugins page keep loading. */
|
|
755
|
+
function registerPluginUpdates(ctx) {
|
|
756
|
+
ctx.inject(["remote", "remote.pluginManager"], (scoped) => {
|
|
757
|
+
const manager = scoped.remote.pluginManager;
|
|
758
|
+
for (const name of UPDATE_PACKAGES) {
|
|
759
|
+
const updater = createPluginUpdater({
|
|
760
|
+
list: async () => unwrap(await manager.listBundles()),
|
|
761
|
+
install: async (spec) => unwrap(await manager.installBundle(spec, { saveExact: true })),
|
|
762
|
+
...typeof manager.updateBundle === "function" ? { update: async (name, version) => unwrap(await manager.updateBundle(name, version, {})) } : {}
|
|
763
|
+
}, name);
|
|
764
|
+
scoped.effect(() => () => updater.dispose());
|
|
765
|
+
scoped.effect(() => injectSlot(scoped, "plugins.bundle.config", () => scoped.slots.register({
|
|
766
|
+
name: "plugins.bundle.config",
|
|
767
|
+
key: name,
|
|
768
|
+
locale: NAMESPACE
|
|
769
|
+
}, (props) => (0, react.createElement)(PluginUpdateCard, {
|
|
770
|
+
...props,
|
|
771
|
+
updater
|
|
772
|
+
}))));
|
|
773
|
+
}
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
function unwrap(result) {
|
|
777
|
+
if (!result.ok) throw result.error;
|
|
778
|
+
return result.value;
|
|
779
|
+
}
|
|
780
|
+
//#endregion
|
|
409
781
|
//#region src/client/index.ts
|
|
410
782
|
const inject = [
|
|
411
783
|
"slots",
|
|
@@ -415,7 +787,7 @@ window.__ModuleLoader__.load({
|
|
|
415
787
|
"conversation"
|
|
416
788
|
];
|
|
417
789
|
/** Register presentation with an explicit disposer so the original entries remain live underneath. */
|
|
418
|
-
function mountInterface(ctx) {
|
|
790
|
+
function mountInterface(ctx, selection) {
|
|
419
791
|
const style = document.createElement("style");
|
|
420
792
|
style.dataset.cannbotHarness = "interface";
|
|
421
793
|
style.textContent = interface_css_default;
|
|
@@ -440,7 +812,8 @@ window.__ModuleLoader__.load({
|
|
|
440
812
|
locale: NAMESPACE
|
|
441
813
|
}, (props) => (0, react.createElement)(WorkflowCompat, {
|
|
442
814
|
...props,
|
|
443
|
-
ctx
|
|
815
|
+
ctx,
|
|
816
|
+
selection
|
|
444
817
|
})))
|
|
445
818
|
];
|
|
446
819
|
return () => {
|
|
@@ -449,6 +822,20 @@ window.__ModuleLoader__.load({
|
|
|
449
822
|
};
|
|
450
823
|
}
|
|
451
824
|
function apply(ctx) {
|
|
825
|
+
registerPluginUpdates(ctx);
|
|
826
|
+
const selection = createWorkflowSelection((sessionId, reason) => {
|
|
827
|
+
const blocks = ctx.conversation.blocks;
|
|
828
|
+
const id = sessionId;
|
|
829
|
+
const store = blocks.storeFor(id);
|
|
830
|
+
if (store.getSnapshot() !== void 0) return () => {};
|
|
831
|
+
const block = { reason };
|
|
832
|
+
blocks.set(id, block);
|
|
833
|
+
return () => {
|
|
834
|
+
if (store.getSnapshot() === block) blocks.set(id, void 0);
|
|
835
|
+
};
|
|
836
|
+
});
|
|
837
|
+
connectWorkflowSelection(ctx, selection);
|
|
838
|
+
ctx.effect(() => () => selection.dispose());
|
|
452
839
|
ctx.effect(() => ctx.locale.register(NAMESPACE, {
|
|
453
840
|
zh,
|
|
454
841
|
en,
|
|
@@ -460,7 +847,7 @@ window.__ModuleLoader__.load({
|
|
|
460
847
|
pt: en
|
|
461
848
|
}));
|
|
462
849
|
ctx.effect(() => {
|
|
463
|
-
const controller = createPresentationController(() => mountInterface(ctx));
|
|
850
|
+
const controller = createPresentationController(() => mountInterface(ctx, selection));
|
|
464
851
|
const releaseToggle = injectSlot(ctx, "sidebar.footer.action", () => ctx.slots.register({
|
|
465
852
|
name: "sidebar.footer.action",
|
|
466
853
|
id: "cannbot-harness-interface",
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["primitives","primitives","LegacyMenu","interfaceCss"],"sources":["../src/client/locales.ts","../src/client/Brand.tsx","../src/workflows.ts","../src/client/WorkflowIcon.tsx","../src/client/WorkflowSelector.tsx","../src/client/WorkflowCompat.tsx","../src/client/theme.ts","../src/client/InterfaceToggle.tsx","../src/client/presentation.ts","../src/client/slot-compat.ts","../src/client/index.ts"],"sourcesContent":["export const PRODUCT = 'CANNBot Harness'\nexport const NAMESPACE = 'cannbotHarness'\nexport const PACKAGE = '@cannbot-plugin/cannbot-harness'\nexport const COMMAND = '/ops-direct-invoke'\n\nexport const zh = {\n workflow: '选择工作流', operator: '算子开发工作流', commandHint: '填入所选工作流指令,由你补充需求后发送。',\n flash: 'Ascend C Flash 核函数开发', registry: 'ACLNN / GEIR 注册算子开发', model: 'NPU 模型推理优化',\n hccl: 'HCCL 通信算子开发', triton: 'Triton 算子开发', catlass: 'CATLASS 算子开发', performance: 'Ascend C 性能调优', pypto: 'PyPTO 算子开发',\n chooseWorkspace: '请先选择工作目录。', insertFailed: '输入框正在处理其他操作,请稍后重试。',\n}\nexport const en: typeof zh = {\n workflow: 'Choose workflow', operator: 'Operator development workflow', commandHint: 'Insert the selected workflow command, add your requirements, then send.',\n flash: 'Ascend C Flash kernel development', registry: 'ACLNN / GEIR operator development', model: 'NPU model inference optimization',\n hccl: 'HCCL communication operators', triton: 'Triton operator development', catlass: 'CATLASS operator development', performance: 'Ascend C performance tuning', pypto: 'PyPTO operator development',\n chooseWorkspace: 'Choose a working directory first.', insertFailed: 'The composer is busy. Please retry.',\n}\nexport type LocaleKey = keyof typeof zh\n","import type { HeroBrandMarkOwnerProps } from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type { SidebarBrandMarkOwnerProps } from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport { PRODUCT } from './locales.ts'\n\nexport function Mark({ size }: { size: number }) {\n return <svg width={size} height={size} viewBox=\"0 0 40 40\" aria-hidden=\"true\">\n <rect x=\"1\" y=\"1\" width=\"38\" height=\"38\" rx=\"12\" fill=\"var(--dsw-alias-brand-primary)\" />\n <path d=\"M27 12a11 11 0 1 0 0 16\" fill=\"none\" stroke=\"var(--dsw-alias-label-primary-foreground)\" strokeWidth=\"4\" strokeLinecap=\"round\" />\n </svg>\n}\nexport function SidebarMark({ size }: SidebarBrandMarkOwnerProps) { return <Mark size={size} /> }\nexport function SidebarName() { return <span className=\"cannbot-harness-name\">{PRODUCT}</span> }\nexport function Hero({ size }: HeroBrandMarkOwnerProps) {\n return <span data-cannbot-harness-hero=\"\"><Mark size={size} /><span>{PRODUCT}</span></span>\n}\n","export const WORKFLOWS = [\n { id: 'ops-direct-invoke', label: 'operator' },\n { id: 'ops-direct-invoke-flash', label: 'flash' },\n { id: 'ops-registry-invoke', label: 'registry' },\n { id: 'model-infer-optimize', label: 'model' },\n { id: 'hccl-op-generator', label: 'hccl' },\n { id: 'triton-op-generator', label: 'triton' },\n { id: 'catlass-op-generator', label: 'catlass' },\n { id: 'ops-perf-optimize', label: 'performance' },\n { id: 'pypto-op-orchestrator', label: 'pypto' },\n] as const\n","import * as primitives from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ComponentType } from 'react'\n\n/** The exact icon component used by DSH's original Standard mode selector. */\nexport function WorkflowIcon({ size = 16 }: { size?: number }) {\n const icons = primitives as unknown as Record<string, ComponentType<{ size?: number }>>\n const Icon = icons.IconAgentPresetOutlineRegular ?? icons.IconAgentPresetOutline16 ?? icons.IconRefreshOutline16\n return Icon ? <Icon size={size} /> : null\n}\n\nexport function ChevronIcon({ size = 12 }: { size?: number }) {\n const icons = primitives as unknown as Record<string, ComponentType<{ size?: number }>>\n const Icon = icons.IconChevronDownOutlineRegular ?? icons.IconChevronDownOutline14\n return Icon ? <Icon size={size} /> : <svg width={size} height={size} viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\"><path d=\"m3 4.5 3 3 3-3\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" /></svg>\n}\n","import { useState, type ComponentType, type ReactNode } from 'react'\nimport * as primitives from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { WORKFLOWS } from '../workflows.ts'\nimport { WorkflowIcon, ChevronIcon } from './WorkflowIcon.tsx'\n\nexport type WorkflowProps = PropsRuntime<'conversation.hero.agentPreset'> & PropsLocale<'cannbotHarness'>\n\n/** Select a workflow without submitting, replacing text, or discarding reference chips. */\nexport function WorkflowSelector({ inputActions, useInput, t }: WorkflowProps) {\n const input = useInput(state => state)\n const [open, setOpen] = useState(false)\n const [failed, setFailed] = useState(false)\n const selected = WORKFLOWS.find(workflow => input?.draft === `/${workflow.id}` || input?.draft.startsWith(`/${workflow.id} `) || input?.draft.startsWith(`/${workflow.id}\\n`))\n const available = inputActions !== undefined && input !== undefined && input.phase === 'plain'\n const pick = (workflow: typeof WORKFLOWS[number]) => {\n setOpen(false)\n if (!inputActions || !input) return\n if (selected?.id === workflow.id) { setFailed(false); return }\n const oldCommand = selected ? `/${selected.id}` : ''\n const end = oldCommand.length + (oldCommand && input.draft[oldCommand.length] === ' ' ? 1 : 0)\n const accepted = inputActions.insertText(`/${workflow.id} `, { start: 0, end, draftRev: input.draftRev })\n setFailed(!accepted)\n }\n const anchor = (\n <button type=\"button\" className=\"cannbot-harness-workflow-trigger\" aria-label={t('workflow')} aria-haspopup=\"menu\" aria-expanded={open}\n disabled={!available} title={inputActions === undefined ? t('chooseWorkspace') : t('commandHint')}\n onClick={() => setOpen(value => !value)}>\n <WorkflowIcon />\n <span className=\"cannbot-harness-workflow-label\">{selected ? t(selected.label) : t('workflow')}</span><ChevronIcon size={12} />\n </button>\n )\n const label = (workflow: typeof WORKFLOWS[number]) => <span className=\"cannbot-harness-workflow-option\">\n <span>{t(workflow.label)}</span><small>/{workflow.id}</small>\n </span>\n const { Menu, MenuItemButton } = primitives\n const LegacyMenu = Menu as unknown as ComponentType<{ open: boolean; anchor: ReactNode; portal: boolean; className: string; onClose(): void; selectedId?: string; onSelect(id: string): void; items: { id: string; label: ReactNode; icon: ReactNode }[] }>\n return <span className=\"cannbot-harness-workflow\">\n {typeof MenuItemButton === 'function' ? <Menu open={open} onClose={() => setOpen(false)} portal className=\"cannbot-harness-workflow-anchor\" anchor={anchor}>\n {WORKFLOWS.map(workflow => <MenuItemButton key={workflow.id} icon={<WorkflowIcon />} onSelect={() => pick(workflow)}>{label(workflow)}</MenuItemButton>)}\n </Menu> : <LegacyMenu open={open} onClose={() => setOpen(false)} portal className=\"cannbot-harness-workflow-anchor\" anchor={anchor}\n selectedId={selected?.id} items={WORKFLOWS.map(workflow => ({ id: workflow.id, label: label(workflow), icon: <WorkflowIcon /> }))}\n onSelect={id => { const workflow = WORKFLOWS.find(item => item.id === id); if (workflow) pick(workflow) }} />}\n {failed && <span role=\"alert\" className=\"cannbot-harness-error\">{t('insertFailed')}</span>}\n </span>\n}\n","import { useMemo, useSyncExternalStore } from 'react'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { WorkflowSelector, type WorkflowProps } from './WorkflowSelector.tsx'\n\n/** Older DSH declares the hero seat at root scope. Resolve its current session\n * through the public services rather than reaching into the editor or DOM. */\nexport function WorkflowCompat({ ctx, ...props }: WorkflowProps & { ctx: Context }) {\n return typeof props.useInput === 'function'\n ? <WorkflowSelector {...props} />\n : <LegacyWorkflow ctx={ctx} {...props} />\n}\n\nfunction LegacyWorkflow({ ctx, ...props }: WorkflowProps & { ctx: Context }) {\n const sessions = useSyncExternalStore(ctx.sessions.list.subscribe, ctx.sessions.list.getSnapshot) as unknown as { current?: Parameters<Context['sessions']['scope']>[0] }\n const input = useMemo(() => {\n const scope = sessions.current && ctx.sessions.scope(sessions.current)\n return scope ? ctx.conversation.input.for(scope) : undefined\n }, [ctx, sessions.current])\n const state = useSyncExternalStore(input?.state.subscribe ?? noSubscribe, input?.state.getSnapshot ?? noSnapshot)\n const inputActions = input ? {\n insertText(text: string, span: { start: number; end: number; draftRev: number }) {\n const current = input.state.getSnapshot()\n if (current.phase !== 'plain' || current.draftRev !== span.draftRev) return false\n // Public legacy setDraft performs the occurrence diff; images live in a\n // separate store and are never rewritten by this operation.\n input.setDraft(current.draft.slice(0, span.start) + text + current.draft.slice(span.end))\n return true\n },\n } : undefined\n return <WorkflowSelector {...props} useInput={select => state ? select(state) : undefined as never} inputActions={inputActions as WorkflowProps['inputActions']} />\n}\nconst noSubscribe = () => () => {}\nconst noSnapshot = () => undefined\n","import type { ThemeTokenOverrides } from '@deepseek-ai/dsh-client-ui-theme/client'\n\n/** Portal design-v2 palette, applied through the documented theme override layer. */\nexport const cannTheme: ThemeTokenOverrides = Object.fromEntries(Object.entries({\n '--dsw-alias-bg-base': ['#ffffff', '#101114'],\n '--dsw-alias-bg-layer-1': ['#ffffff', '#17191e'],\n '--dsw-alias-bg-layer-2': ['#ffffff', '#1d2026'],\n '--dsw-alias-bg-layer-3': ['#f6f8fa', '#252830'],\n '--dsw-specific-sidebar-fill': ['#f6f8fa', '#14161b'],\n '--dsw-specific-input-major': ['#ffffff', '#1d2026'],\n '--dsw-specific-sidebar-nav-item-active': ['#fdeef0', '#392029'],\n '--dsw-specific-sidebar-nav-item-active-accent': ['#fdeef0', '#392029'],\n '--dsw-alias-label-primary': ['#17181d', '#f3f4f6'],\n '--dsw-alias-label-primary-foreground': ['#ffffff', '#ffffff'],\n '--dsw-alias-label-primary-inverted': ['#ffffff', '#ffffff'],\n '--dsw-alias-label-primary-dimmed': ['#30343e', '#dde1e8'],\n '--dsw-alias-label-primary-bluish': ['#7f0f26', '#ff9aab'],\n '--dsw-alias-label-secondary': ['#59637a', '#b0b8c7'],\n '--dsw-alias-label-tertiary': ['#727d91', '#929db0'],\n '--dsw-alias-brand-primary': ['#da203e', '#ef4560'],\n '--dsw-alias-brand-text': ['#17181d', '#f3f4f6'],\n '--dsw-alias-button-primary-hover': ['#b11430', '#ff647d'],\n '--dsw-alias-button-info-fill': ['#da203e', '#da203e'],\n '--dsw-alias-button-info-hover': ['#b11430', '#b11430'],\n '--dsw-alias-state-business-primary': ['#da203e', '#ff8297'],\n '--dsw-alias-state-business-tertiary': ['#fdeef0', '#392029'],\n '--dsw-alias-link': ['#b11430', '#ff9aab'],\n '--dsw-focus-ring-color': ['#da203e', '#ff8297'],\n '--dsw-alias-border-l1': ['#f0f1f5', '#252830'],\n '--dsw-alias-border-l2': ['#e6e9ef', '#323641'],\n '--dsw-alias-border-l3': ['#dce0e8', '#414754'],\n '--dsw-alias-border-l4': ['#ced4df', '#505867'],\n '--dsw-alias-interactive-bg-hover': ['#eef0f4', '#252830'],\n '--dsw-alias-interactive-bg-active': ['#fdeef0', '#392029'],\n '--dsw-specific-bubble': ['#fff3f5', '#302027'],\n '--dsw-specific-bubble-highlight': ['#fbd6dd', '#59303d'],\n '--dsw-radius-panel': ['18px', '18px'],\n '--dsw-radius-xl': ['14px', '14px'],\n '--dsw-radius-lg': ['12px', '12px'],\n '--dsw-radius-md': ['10px', '10px'],\n '--cann-grid': ['#e6e9ef', '#323641'],\n '--cann-night': ['#0e0f12', '#0e0f12'],\n '--cann-night-label': ['#dde1e8', '#dde1e8'],\n}).map(([name, values]) => [name, { light: values[0]!, dark: values[1]! }]))\n","import { useSyncExternalStore } from 'react'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { PresentationController } from './presentation.ts'\nimport { Mark } from './Brand.tsx'\nimport { PRODUCT } from './locales.ts'\n\nexport function InterfaceToggle({ wide, controller }: PropsRuntime<'sidebar.footer.action'> & { controller: PresentationController }) {\n const enabled = useSyncExternalStore(controller.subscribe, controller.getSnapshot, controller.getSnapshot)\n return <div className={`cannbot-harness-toggle${wide ? '' : ' cannbot-harness-toggle-compact'}`}>\n <span className=\"cannbot-harness-toggle-name\" title={PRODUCT}><Mark size={20} />{wide && <span>{PRODUCT}</span>}</span>\n <button type=\"button\" role=\"switch\" aria-label={PRODUCT} aria-checked={enabled} title={PRODUCT}\n className=\"cannbot-harness-switch\" onClick={() => controller.setEnabled(!enabled)}><span /></button>\n </div>\n}\n","/** Per-activation UI preference: enabling the plugin always starts with its interface on. */\nexport interface PresentationController {\n getSnapshot(): boolean\n subscribe(listener: () => void): () => void\n setEnabled(enabled: boolean): void\n dispose(): void\n}\nexport function createPresentationController(mount: () => () => void): PresentationController {\n let enabled = true\n let stopped = false\n let unmount: (() => void) | undefined = mount()\n const listeners = new Set<() => void>()\n return {\n getSnapshot: () => enabled,\n subscribe(listener) { listeners.add(listener); return () => { listeners.delete(listener) } },\n setEnabled(next) {\n if (stopped || next === enabled) return\n if (next) unmount = mount()\n else { unmount?.(); unmount = undefined }\n enabled = next\n for (const listener of listeners) listener()\n },\n dispose() { if (stopped) return; stopped = true; unmount?.(); unmount = undefined; listeners.clear() },\n }\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { SlotMap } from '@deepseek-ai/dsh-client-ui-slots'\n\n/** Older DSH declares the injected parent modules before this plugin and uses direct register(). */\nexport function injectSlot(ctx: Context, name: keyof SlotMap & string, register: () => () => void): () => void {\n return typeof ctx.slots.inject === 'function' ? ctx.slots.inject(name, register) : register()\n}\n","/** Browser companion using the existing DSH theme, settings and UI slots. */\nimport type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-theme/client'\nimport { en, zh, NAMESPACE, PACKAGE, type LocaleKey } from './locales.ts'\nimport { SidebarMark, SidebarName, Hero } from './Brand.tsx'\nimport { WorkflowCompat } from './WorkflowCompat.tsx'\nimport { cannTheme } from './theme.ts'\nimport interfaceCss from './interface.css?inline'\nimport './controls.css'\nimport { createElement } from 'react'\nimport { InterfaceToggle } from './InterfaceToggle.tsx'\nimport { createPresentationController } from './presentation.ts'\nimport { injectSlot } from './slot-compat.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap { cannbotHarness: LocaleKey }\n}\nexport const inject = ['slots', 'theme', 'locale', 'sessions', 'conversation']\n\n/** Register presentation with an explicit disposer so the original entries remain live underneath. */\nfunction mountInterface(ctx: Context): () => void {\n const style = document.createElement('style')\n style.dataset.cannbotHarness = 'interface'\n style.textContent = interfaceCss\n document.head.append(style)\n const releases = [\n ctx.theme.overrideTokens(PACKAGE, cannTheme),\n injectSlot(ctx, 'sidebar.brand.mark', () => ctx.slots.register({ name: 'sidebar.brand.mark', priority: -100 }, SidebarMark)),\n injectSlot(ctx, 'sidebar.brand.name', () => ctx.slots.register({ name: 'sidebar.brand.name', priority: -100 }, SidebarName)),\n injectSlot(ctx, 'conversation.hero.brand.mark', () => ctx.slots.register({ name: 'conversation.hero.brand.mark', priority: -100 }, Hero)),\n injectSlot(ctx, 'conversation.hero.agentPreset', () => ctx.slots.register({ name: 'conversation.hero.agentPreset', priority: -100, locale: NAMESPACE }, props => createElement(WorkflowCompat, { ...props, ctx }))),\n ]\n return () => { for (const release of releases.reverse()) release(); style.remove() }\n}\n\nexport function apply(ctx: Context): void {\n ctx.effect(() => ctx.locale.register(NAMESPACE, { zh, en, ja: en, es: en, fr: en, de: en, ru: en, pt: en }))\n ctx.effect(() => {\n const controller = createPresentationController(() => mountInterface(ctx))\n const releaseToggle = injectSlot(ctx, 'sidebar.footer.action', () => ctx.slots.register({\n name: 'sidebar.footer.action', id: 'cannbot-harness-interface', order: -100,\n }, props => createElement(InterfaceToggle, { ...props, controller })))\n return () => { releaseToggle(); controller.dispose() }\n })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["primitives","primitives","LegacyMenu","unwrap","raw","interfaceCss"],"sources":["../src/client/locales.ts","../src/client/Brand.tsx","../src/workflows.ts","../src/client/WorkflowIcon.tsx","../src/client/WorkflowSelector.tsx","../src/client/WorkflowCompat.tsx","../src/client/theme.ts","../src/client/InterfaceToggle.tsx","../src/client/presentation.ts","../src/client/slot-compat.ts","../src/client/workflow-selection.ts","../src/client/plugin-update.ts","../src/client/PluginUpdateCard.tsx","../src/client/register-updates.ts","../src/client/index.ts"],"sourcesContent":["export const PRODUCT = 'CANNBot Harness'\nexport const NAMESPACE = 'cannbotHarness'\nexport const PACKAGE = '@cannbot-plugin/cannbot-harness'\nexport const COMMAND = '/ops-direct-invoke'\n\nexport const zh = {\n updateTitle: '版本更新', updateCurrent: '当前版本', updateCheck: '检查更新', updateChecking: '正在检查…',\n updateTo: '更新到', updateRunning: '正在更新…', updateAvailable: '发现新版本,点击上方按钮更新。',\n updateLatest: '当前已是最新版本。', updateDone: '更新已完成。', updateRestart: '新版已安装,重启 DSH 后生效。',\n updateManual: '当前 DSH 要求先卸载旧版。请先下载新版包,再在插件页卸载旧版并添加下载的安装包。',\n updateIncompatible: '当前 DSH 不支持此版本,请先升级 DSH。', updateFailed: '暂时无法完成,请稍后重试。', updateDownload: '下载新版安装包',\n workflow: '选择工作流', ordinary: '普通对话', saving: '正在应用工作流…', operator: '算子开发工作流', commandHint: '发送时自动应用所选工作流,只需填写需求。',\n flash: 'Ascend C Flash 核函数开发', registry: 'ACLNN / GEIR 注册算子开发', model: 'NPU 模型推理优化',\n hccl: 'HCCL 通信算子开发', triton: 'Triton 算子开发', catlass: 'CATLASS 算子开发', performance: 'Ascend C 性能调优', pypto: 'PyPTO 算子开发',\n chooseWorkspace: '请先选择工作目录。', insertFailed: '工作流设置未保存,请稍后重试。',\n}\nexport const en: typeof zh = {\n updateTitle: 'Updates', updateCurrent: 'Installed version', updateCheck: 'Check for updates', updateChecking: 'Checking…',\n updateTo: 'Update to', updateRunning: 'Updating…', updateAvailable: 'A new version is available. Use the button above to update.',\n updateLatest: 'You are up to date.', updateDone: 'Update completed.', updateRestart: 'The update is installed. Restart DSH to apply it.',\n updateManual: 'This DSH version requires removing the old plugin first. Download the update, then uninstall the old plugin and add the downloaded package.',\n updateIncompatible: 'This release requires updating DSH first.', updateFailed: 'Unable to complete this operation. Please retry.', updateDownload: 'Download update',\n workflow: 'Choose workflow', ordinary: 'Ordinary conversation', saving: 'Applying workflow…', operator: 'Operator development workflow', commandHint: 'The selected workflow is applied in the background when you send.',\n flash: 'Ascend C Flash kernel development', registry: 'ACLNN / GEIR operator development', model: 'NPU model inference optimization',\n hccl: 'HCCL communication operators', triton: 'Triton operator development', catlass: 'CATLASS operator development', performance: 'Ascend C performance tuning', pypto: 'PyPTO operator development',\n chooseWorkspace: 'Choose a working directory first.', insertFailed: 'The workflow preference was not saved. Please retry.',\n}\nexport type LocaleKey = keyof typeof zh\n","import type { HeroBrandMarkOwnerProps } from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type { SidebarBrandMarkOwnerProps } from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport { PRODUCT } from './locales.ts'\n\nexport function Mark({ size }: { size: number }) {\n return <svg width={size} height={size} viewBox=\"0 0 40 40\" aria-hidden=\"true\">\n <rect x=\"1\" y=\"1\" width=\"38\" height=\"38\" rx=\"12\" fill=\"var(--dsw-alias-brand-primary)\" />\n <path d=\"M27 12a11 11 0 1 0 0 16\" fill=\"none\" stroke=\"var(--dsw-alias-label-primary-foreground)\" strokeWidth=\"4\" strokeLinecap=\"round\" />\n </svg>\n}\nexport function SidebarMark({ size }: SidebarBrandMarkOwnerProps) { return <Mark size={size} /> }\nexport function SidebarName() { return <span className=\"cannbot-harness-name\">{PRODUCT}</span> }\nexport function Hero({ size }: HeroBrandMarkOwnerProps) {\n return <span data-cannbot-harness-hero=\"\"><Mark size={size} /><span>{PRODUCT}</span></span>\n}\n","export const WORKFLOWS = [\n { id: 'ops-direct-invoke', label: 'operator' },\n { id: 'ops-direct-invoke-flash', label: 'flash' },\n { id: 'ops-registry-invoke', label: 'registry' },\n { id: 'model-infer-optimize', label: 'model' },\n { id: 'hccl-op-generator', label: 'hccl' },\n { id: 'triton-op-generator', label: 'triton' },\n { id: 'catlass-op-generator', label: 'catlass' },\n { id: 'ops-perf-optimize', label: 'performance' },\n { id: 'pypto-op-orchestrator', label: 'pypto' },\n] as const\n","import * as primitives from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { ComponentType } from 'react'\n\n/** The exact icon component used by DSH's original Standard mode selector. */\nexport function WorkflowIcon({ size = 16 }: { size?: number }) {\n const icons = primitives as unknown as Record<string, ComponentType<{ size?: number }>>\n const Icon = icons.IconAgentPresetOutlineRegular ?? icons.IconAgentPresetOutline16 ?? icons.IconRefreshOutline16\n return Icon ? <Icon size={size} /> : null\n}\n\nexport function ChevronIcon({ size = 12 }: { size?: number }) {\n const icons = primitives as unknown as Record<string, ComponentType<{ size?: number }>>\n const Icon = icons.IconChevronDownOutlineRegular ?? icons.IconChevronDownOutline14\n return Icon ? <Icon size={size} /> : <svg width={size} height={size} viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\"><path d=\"m3 4.5 3 3 3-3\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" /></svg>\n}\n","import { useState, useSyncExternalStore, type ComponentType, type ReactNode } from 'react'\nimport * as primitives from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { WORKFLOWS } from '../workflows.ts'\nimport { WorkflowIcon, ChevronIcon } from './WorkflowIcon.tsx'\nimport type { WorkflowSelection } from './workflow-selection.ts'\n\nexport type WorkflowProps = PropsRuntime<'conversation.hero.agentPreset'> & PropsLocale<'cannbotHarness'> & { selection: WorkflowSelection }\n\n/** Select a workflow without submitting, replacing text, or discarding reference chips. */\nexport function WorkflowSelector({ sessionId, inputActions, useInput, t, selection }: WorkflowProps) {\n const input = useInput(state => state)\n const saved = useSyncExternalStore(selection.subscribe, selection.getSnapshot)\n const [open, setOpen] = useState(false)\n const selected = WORKFLOWS.find(workflow => sessionId && saved.values[sessionId] === workflow.id)\n const available = !!sessionId && saved.ready && !saved.pending && inputActions !== undefined && input !== undefined && input.phase === 'plain'\n const pick = (id: string) => {\n setOpen(false)\n if (sessionId && available) void selection.choose(sessionId, id, t('saving'))\n }\n const anchor = (\n <button type=\"button\" className=\"cannbot-harness-workflow-trigger\" aria-label={t('workflow')} aria-haspopup=\"menu\" aria-expanded={open}\n disabled={!available} title={inputActions === undefined ? t('chooseWorkspace') : t('commandHint')}\n onClick={() => setOpen(value => !value)}>\n <WorkflowIcon />\n <span className=\"cannbot-harness-workflow-label\">{selected ? t(selected.label) : t('workflow')}</span><ChevronIcon size={12} />\n </button>\n )\n const label = (workflow: typeof WORKFLOWS[number]) => <span className=\"cannbot-harness-workflow-option\">\n <span>{t(workflow.label)}</span>\n </span>\n const { Menu, MenuItemButton } = primitives\n const LegacyMenu = Menu as unknown as ComponentType<{ open: boolean; anchor: ReactNode; portal: boolean; className: string; onClose(): void; selectedId?: string; onSelect(id: string): void; items: { id: string; label: ReactNode; icon: ReactNode }[] }>\n return <span className=\"cannbot-harness-workflow\">\n {typeof MenuItemButton === 'function' ? <Menu open={open} onClose={() => setOpen(false)} portal className=\"cannbot-harness-workflow-anchor\" anchor={anchor}>\n <MenuItemButton icon={<WorkflowIcon />} onSelect={() => pick('')}>{t('ordinary')}</MenuItemButton>\n {WORKFLOWS.map(workflow => <MenuItemButton key={workflow.id} icon={<WorkflowIcon />} onSelect={() => pick(workflow.id)}>{label(workflow)}</MenuItemButton>)}\n </Menu> : <LegacyMenu open={open} onClose={() => setOpen(false)} portal className=\"cannbot-harness-workflow-anchor\" anchor={anchor}\n selectedId={selected?.id} items={[{ id: '', label: t('ordinary'), icon: <WorkflowIcon /> }, ...WORKFLOWS.map(workflow => ({ id: workflow.id, label: label(workflow), icon: <WorkflowIcon /> }))]}\n onSelect={pick} />}\n {saved.error && <span role=\"alert\" className=\"cannbot-harness-error\">{t('insertFailed')}</span>}\n </span>\n}\n","import { useMemo, useSyncExternalStore } from 'react'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { WorkflowSelector, type WorkflowProps } from './WorkflowSelector.tsx'\n\n/** Older DSH declares the hero seat at root scope. Resolve its current session\n * through the public services rather than reaching into the editor or DOM. */\nexport function WorkflowCompat({ ctx, ...props }: WorkflowProps & { ctx: Context }) {\n return typeof props.useInput === 'function'\n ? <WorkflowSelector {...props} />\n : <LegacyWorkflow ctx={ctx} {...props} />\n}\n\nfunction LegacyWorkflow({ ctx, ...props }: WorkflowProps & { ctx: Context }) {\n type Input = ReturnType<Context['conversation']['input']['for']>\n const legacy = ctx as unknown as { sessions: { list: { subscribe(listener: () => void): () => void; getSnapshot(): { current?: string } }; scope(id: string): Context | undefined } }\n const sessions = useSyncExternalStore(legacy.sessions.list.subscribe, legacy.sessions.list.getSnapshot)\n const input = useMemo(() => {\n const scope = sessions.current && legacy.sessions.scope(sessions.current)\n return scope ? ctx.conversation.input.for(scope) as Input : undefined\n }, [ctx, sessions.current])\n const state = useSyncExternalStore(input?.state.subscribe ?? noSubscribe, input?.state.getSnapshot ?? noSnapshot)\n return <WorkflowSelector {...props} sessionId={sessions.current as WorkflowProps['sessionId']} useInput={select => state ? select(state) : undefined as never} inputActions={input ? {} as WorkflowProps['inputActions'] : undefined} />\n}\nconst noSubscribe = () => () => {}\nconst noSnapshot = () => undefined\n","import type { ThemeTokenOverrides } from '@deepseek-ai/dsh-client-ui-theme/client'\n\n/** Portal design-v2 palette, applied through the documented theme override layer. */\nexport const cannTheme: ThemeTokenOverrides = Object.fromEntries(Object.entries({\n '--dsw-alias-bg-base': ['#ffffff', '#101114'],\n '--dsw-alias-bg-layer-1': ['#ffffff', '#17191e'],\n '--dsw-alias-bg-layer-2': ['#ffffff', '#1d2026'],\n '--dsw-alias-bg-layer-3': ['#f6f8fa', '#252830'],\n '--dsw-specific-sidebar-fill': ['#f6f8fa', '#14161b'],\n '--dsw-specific-input-major': ['#ffffff', '#1d2026'],\n '--dsw-specific-sidebar-nav-item-active': ['#fdeef0', '#392029'],\n '--dsw-specific-sidebar-nav-item-active-accent': ['#fdeef0', '#392029'],\n '--dsw-alias-label-primary': ['#17181d', '#f3f4f6'],\n '--dsw-alias-label-primary-foreground': ['#ffffff', '#ffffff'],\n '--dsw-alias-label-primary-inverted': ['#ffffff', '#ffffff'],\n '--dsw-alias-label-primary-dimmed': ['#30343e', '#dde1e8'],\n '--dsw-alias-label-primary-bluish': ['#7f0f26', '#ff9aab'],\n '--dsw-alias-label-secondary': ['#59637a', '#b0b8c7'],\n '--dsw-alias-label-tertiary': ['#727d91', '#929db0'],\n '--dsw-alias-brand-primary': ['#da203e', '#ef4560'],\n '--dsw-alias-brand-text': ['#17181d', '#f3f4f6'],\n '--dsw-alias-button-primary-hover': ['#b11430', '#ff647d'],\n '--dsw-alias-button-info-fill': ['#da203e', '#da203e'],\n '--dsw-alias-button-info-hover': ['#b11430', '#b11430'],\n '--dsw-alias-state-business-primary': ['#da203e', '#ff8297'],\n '--dsw-alias-state-business-tertiary': ['#fdeef0', '#392029'],\n '--dsw-alias-link': ['#b11430', '#ff9aab'],\n '--dsw-focus-ring-color': ['#da203e', '#ff8297'],\n '--dsw-alias-border-l1': ['#f0f1f5', '#252830'],\n '--dsw-alias-border-l2': ['#e6e9ef', '#323641'],\n '--dsw-alias-border-l3': ['#dce0e8', '#414754'],\n '--dsw-alias-border-l4': ['#ced4df', '#505867'],\n '--dsw-alias-interactive-bg-hover': ['#eef0f4', '#252830'],\n '--dsw-alias-interactive-bg-active': ['#fdeef0', '#392029'],\n '--dsw-specific-bubble': ['#fff3f5', '#302027'],\n '--dsw-specific-bubble-highlight': ['#fbd6dd', '#59303d'],\n '--dsw-radius-panel': ['18px', '18px'],\n '--dsw-radius-xl': ['14px', '14px'],\n '--dsw-radius-lg': ['12px', '12px'],\n '--dsw-radius-md': ['10px', '10px'],\n '--cann-grid': ['#e6e9ef', '#323641'],\n '--cann-night': ['#0e0f12', '#0e0f12'],\n '--cann-night-label': ['#dde1e8', '#dde1e8'],\n}).map(([name, values]) => [name, { light: values[0]!, dark: values[1]! }]))\n","import { useSyncExternalStore } from 'react'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { PresentationController } from './presentation.ts'\nimport { Mark } from './Brand.tsx'\nimport { PRODUCT } from './locales.ts'\n\nexport function InterfaceToggle({ wide, controller }: PropsRuntime<'sidebar.footer.action'> & { controller: PresentationController }) {\n const enabled = useSyncExternalStore(controller.subscribe, controller.getSnapshot, controller.getSnapshot)\n return <div className={`cannbot-harness-toggle${wide ? '' : ' cannbot-harness-toggle-compact'}`}>\n <span className=\"cannbot-harness-toggle-name\" title={PRODUCT}><Mark size={20} />{wide && <span>{PRODUCT}</span>}</span>\n <button type=\"button\" role=\"switch\" aria-label={PRODUCT} aria-checked={enabled} title={PRODUCT}\n className=\"cannbot-harness-switch\" onClick={() => controller.setEnabled(!enabled)}><span /></button>\n </div>\n}\n","/** Per-activation UI preference: enabling the plugin always starts with its interface on. */\nexport interface PresentationController {\n getSnapshot(): boolean\n subscribe(listener: () => void): () => void\n setEnabled(enabled: boolean): void\n dispose(): void\n}\nexport function createPresentationController(mount: () => () => void): PresentationController {\n let enabled = true\n let stopped = false\n let unmount: (() => void) | undefined = mount()\n const listeners = new Set<() => void>()\n return {\n getSnapshot: () => enabled,\n subscribe(listener) { listeners.add(listener); return () => { listeners.delete(listener) } },\n setEnabled(next) {\n if (stopped || next === enabled) return\n if (next) unmount = mount()\n else { unmount?.(); unmount = undefined }\n enabled = next\n for (const listener of listeners) listener()\n },\n dispose() { if (stopped) return; stopped = true; unmount?.(); unmount = undefined; listeners.clear() },\n }\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { SlotMap } from '@deepseek-ai/dsh-client-ui-slots'\n\n/** Older DSH declares the injected parent modules before this plugin and uses direct register(). */\nexport function injectSlot(ctx: Context, name: keyof SlotMap & string, register: () => () => void): () => void {\n return typeof ctx.slots.inject === 'function' ? ctx.slots.inject(name, register) : register()\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-api-remotes/client'\nimport { WORKFLOWS } from '../workflows.ts'\n\nconst NS = 'cannbot-harness'\ntype Values = Record<string, string>\ninterface Choice { sessionId: string; workflow: string }\ninterface View { ns: string; value: { selections?: Choice[] }; revision?: number }\nconst valuesOf = (view?: View): Values => Object.fromEntries((view?.value.selections ?? []).map(item => [item.sessionId, item.workflow]))\nexport interface WorkflowTransport {\n describe(): Promise<{ namespaces: View[] }>\n update(ns: string, patch: { selections: Choice[] }, revision?: number): Promise<View>\n}\nexport interface SelectionSnapshot { ready: boolean; pending: boolean; error: boolean; values: Values }\nexport interface WorkflowSelection {\n subscribe(listener: () => void): () => void\n getSnapshot(): SelectionSnapshot\n attach(transport: WorkflowTransport): () => void\n choose(sessionId: string, workflow: string, reason?: string): Promise<void>\n dispose(): void\n}\nexport function createWorkflowSelection(blockSubmission: (sessionId: string, reason: string) => () => void = () => () => {}): WorkflowSelection {\n let snapshot: SelectionSnapshot = { ready: false, pending: false, error: false, values: {} }\n let transport: WorkflowTransport | undefined\n let generation = 0\n let pendingRelease: (() => void) | undefined\n const listeners = new Set<() => void>()\n const publish = (next: SelectionSnapshot) => { snapshot = next; for (const listener of listeners) listener() }\n return {\n subscribe(listener) { listeners.add(listener); return () => { listeners.delete(listener) } },\n getSnapshot: () => snapshot,\n attach(next) {\n transport = next\n const own = ++generation\n void next.describe().then(view => {\n if (own !== generation) return\n const section = view.namespaces.find(item => item.ns === NS)\n publish({ ready: !!section, pending: false, error: !section, values: valuesOf(section) })\n }).catch(() => { if (own === generation) publish({ ...snapshot, ready: false, error: true }) })\n return () => { if (own === generation) { generation++; transport = undefined; publish({ ...snapshot, ready: false }) } }\n },\n async choose(sessionId, workflow, reason = 'CANNBot Harness…') {\n if (!transport || !snapshot.ready || snapshot.pending) return\n if (workflow !== '' && !WORKFLOWS.some(item => item.id === workflow)) throw new Error('Unknown workflow')\n const current = transport, own = generation\n const unblock = blockSubmission(sessionId, reason)\n let released = false\n const release = () => { if (!released) { released = true; unblock() } }\n pendingRelease = release\n publish({ ...snapshot, pending: true, error: false })\n try {\n // Fresh revision prevents simultaneous windows from overwriting selections.\n const view = (await current.describe()).namespaces.find(item => item.ns === NS)\n if (!view) throw new Error('Workflow settings unavailable')\n const values = { ...valuesOf(view), [sessionId]: workflow }\n const selections = Object.entries(values).filter(([, id]) => id !== '').map(([sessionId, workflow]) => ({ sessionId, workflow }))\n const result = await current.update(NS, { selections }, view.revision)\n if (own === generation) publish({ ready: true, pending: false, error: false, values: valuesOf(result) })\n } catch {\n if (own === generation) publish({ ...snapshot, pending: false, error: true })\n } finally {\n release()\n if (pendingRelease === release) pendingRelease = undefined\n }\n },\n dispose() { generation++; transport = undefined; pendingRelease?.(); pendingRelease = undefined; listeners.clear() },\n }\n}\n\n/** Both transports are official DSH settings APIs; no private editor access. */\nexport function connectWorkflowSelection(ctx: Context, selection: WorkflowSelection) {\n ctx.inject(['remote', 'remote.settings'], scoped => {\n const settings = scoped.remote.settings\n scoped.effect(() => selection.attach({\n describe: async () => unwrap(await settings.describe()),\n update: async (ns, patch, revision) => unwrap(await settings.update(ns, patch, revision)),\n }))\n })\n ctx.inject(['connection'], scoped => {\n const api = (scoped as unknown as { connection: { api?: { settings: { describe(payload: object): Promise<unknown>; update(payload: object): Promise<unknown> } } } }).connection.api\n if (!api?.settings) return\n scoped.effect(() => selection.attach({\n describe: async () => unwrap(await api.settings.describe({})),\n update: async (ns, patch, expectedRevision) => unwrap(await api.settings.update({ ns, patch, expectedRevision })),\n }))\n })\n}\nfunction unwrap<T>(response: unknown): T {\n const raw = response as { result?: unknown }\n const result = (raw.result ?? response) as { ok: boolean; value: T; error?: { message: string } }\n if (!result.ok) throw new Error(result.error?.message ?? 'Workflow settings failed')\n return result.value\n}\n","export const UPDATE_PACKAGES = ['cannbot-harness', '@cannbot-plugin/cannbot-harness'] as const\nexport interface InstalledBundle { name: string; version?: string; installed: boolean }\nexport interface Change { application: string; error?: { code: string }; version?: string }\nexport interface UpdateBridge {\n list(): Promise<InstalledBundle[]>\n install(spec: string): Promise<Change>\n update?(name: string, version: string): Promise<{ result: Change; restore?: Change }>\n}\nexport interface Release { name: string; version: string; tarball: string }\nexport type UpdatePhase = 'idle' | 'checking' | 'latest' | 'available' | 'updating' | 'done' | 'restart' | 'manual' | 'incompatible' | 'error'\nexport interface UpdateSnapshot { phase: UpdatePhase; current?: string; release?: Release; packageName?: string }\n\n/** Only stable npm releases of our two installation entries may be selected. */\nexport function newerVersion(candidate: string, current: string): boolean {\n const next = /^(\\d+)\\.(\\d+)\\.(\\d+)$/.exec(candidate)\n const old = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:[-+].*)?$/.exec(current)\n if (!next || !old) return false\n for (let index = 1; index < 4; index++) {\n const difference = Number(next[index]) - Number(old[index])\n if (difference) return difference > 0\n }\n return current.includes('-')\n}\n\nexport async function latestRelease(name: string, signal: AbortSignal): Promise<Release> {\n if (!UPDATE_PACKAGES.includes(name as typeof UPDATE_PACKAGES[number])) throw new Error('Unsupported update target')\n const answers = await Promise.allSettled(['https://registry.npmjs.org/', 'https://registry.npmmirror.com/'].map(async registry => {\n const response = await fetch(`${registry}${encodeURIComponent(name)}/latest`, {\n signal: AbortSignal.any([signal, AbortSignal.timeout(15000)]), cache: 'no-store',\n })\n if (!response.ok) throw new Error('Registry unavailable')\n const manifest = await response.json() as { name?: string; version?: string; dist?: { tarball?: string }; dsh?: { bundle?: unknown } }\n if (manifest.name !== name || !manifest.version || !/^\\d+\\.\\d+\\.\\d+$/.test(manifest.version) || !manifest.dsh?.bundle || !manifest.dist?.tarball) throw new Error('Invalid release')\n const url = new URL(manifest.dist.tarball)\n if (url.protocol !== 'https:' || !['registry.npmjs.org', 'registry.npmmirror.com'].includes(url.hostname)) throw new Error('Invalid download origin')\n return { name, version: manifest.version, tarball: url.href }\n }))\n signal.throwIfAborted()\n const releases = answers.flatMap(answer => answer.status === 'fulfilled' ? [answer.value] : [])\n const latest = releases.reduce<Release | undefined>((best, release) => !best || newerVersion(release.version, best.version) ? release : best, undefined)\n if (!latest) throw new Error('No release available')\n return latest\n}\n\nexport function createPluginUpdater(bridge: UpdateBridge, requestedName: string, lookup = latestRelease) {\n let state: UpdateSnapshot = { phase: 'idle' }\n let disposed = false\n let checking: AbortController | undefined\n const listeners = new Set<() => void>()\n const publish = (next: UpdateSnapshot) => { if (disposed) return; state = next; for (const listener of listeners) listener() }\n const failed = (result: Change) => !['applied', 'restart-required'].includes(result.application) || !!result.error\n return {\n getSnapshot: () => state,\n subscribe(listener: () => void) { listeners.add(listener); return () => { listeners.delete(listener) } },\n async check() {\n if (disposed || state.phase === 'checking' || state.phase === 'updating') return\n checking?.abort()\n const abort = new AbortController()\n checking = abort\n publish({ ...state, phase: 'checking' })\n try {\n const bundles = (await bridge.list()).filter(bundle => bundle.installed && UPDATE_PACKAGES.includes(bundle.name as typeof UPDATE_PACKAGES[number]))\n // Update the actual direct dependency, preserving short/long installation form.\n const bundle = bundles.find(bundle => bundle.name === requestedName) ?? bundles[0]\n if (!bundle?.version) throw new Error('Installed entry unavailable')\n publish({ ...state, current: bundle.version, packageName: bundle.name })\n const release = await lookup(bundle.name, abort.signal)\n if (checking !== abort || disposed) return\n publish({ phase: newerVersion(release.version, bundle.version) ? 'available' : 'latest', current: bundle.version, release, packageName: bundle.name })\n } catch {\n if (!abort.signal.aborted) publish({ ...state, phase: 'error' })\n }\n },\n async update() {\n if (disposed || state.phase !== 'available' || !state.release || !state.packageName) return\n const target = state.release, name = state.packageName\n publish({ ...state, phase: 'updating' })\n try {\n // Each path is a single official Host operation with its own rollback.\n // The plugin never removes itself to try to bypass DSH's HMR guard.\n const answer = bridge.update\n ? await bridge.update(name, target.version)\n : { result: await bridge.install(`${name}@${target.version}`) }\n const result = answer.result\n if (failed(result)) {\n const code = result.error?.code\n publish({ ...state, phase: code === 'already-installed' || code === 'stop-profile' ? 'manual' : code === 'incompatible-version' ? 'incompatible' : 'error' })\n } else {\n publish({ ...state, phase: result.application === 'restart-required' ? 'restart' : 'done', current: target.version })\n }\n } catch { publish({ ...state, phase: 'error' }) }\n },\n dispose() { disposed = true; checking?.abort(); listeners.clear() },\n }\n}\nexport type PluginUpdater = ReturnType<typeof createPluginUpdater>\n","import { useEffect, useSyncExternalStore } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { PluginUpdater } from './plugin-update.ts'\n\nexport function PluginUpdateCard({ updater, t }: { updater: PluginUpdater } & PropsLocale<'cannbotHarness'>) {\n const state = useSyncExternalStore(updater.subscribe, updater.getSnapshot)\n useEffect(() => { void updater.check() }, [updater])\n const busy = state.phase === 'checking' || state.phase === 'updating'\n const canUpdate = state.phase === 'available'\n const message = state.phase === 'latest' ? t('updateLatest')\n : state.phase === 'available' ? t('updateAvailable')\n : state.phase === 'updating' ? t('updateRunning')\n : state.phase === 'done' ? t('updateDone')\n : state.phase === 'restart' ? t('updateRestart')\n : state.phase === 'manual' ? t('updateManual')\n : state.phase === 'incompatible' ? t('updateIncompatible')\n : state.phase === 'error' ? t('updateFailed') : ''\n return <section className=\"cannbot-harness-update\" aria-label={t('updateTitle')}>\n <div className=\"cannbot-harness-update-heading\"><h4>{t('updateTitle')}</h4>\n {state.current && <span>{t('updateCurrent')} {state.current}</span>}</div>\n <div className=\"cannbot-harness-update-actions\">\n {state.phase === 'manual' && state.release ? <>\n <a className=\"cannbot-harness-update-button\" href={state.release.tarball} download rel=\"noreferrer\">{t('updateDownload')} {state.release.version}</a>\n <button type=\"button\" className=\"cannbot-harness-update-recheck\" onClick={() => { void updater.check() }}>{t('updateCheck')}</button>\n </> :\n <button type=\"button\" className=\"cannbot-harness-update-button\" disabled={busy}\n onClick={() => { void (canUpdate ? updater.update() : updater.check()) }}>\n {state.phase === 'checking' ? t('updateChecking') : state.phase === 'updating' ? t('updateRunning')\n : canUpdate ? `${t('updateTo')} ${state.release?.version}` : t('updateCheck')}\n </button>\n }\n </div>\n {message && <p role={state.phase === 'error' ? 'alert' : 'status'} aria-live=\"polite\">{message}</p>}\n </section>\n}\n","import { createElement } from 'react'\nimport type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-ui-plugin-manager/client'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport { createPluginUpdater, UPDATE_PACKAGES } from './plugin-update.ts'\nimport { PluginUpdateCard } from './PluginUpdateCard.tsx'\nimport { NAMESPACE } from './locales.ts'\nimport { injectSlot } from './slot-compat.ts'\n\n/** Optional integration: old DSH versions without a Plugins page keep loading. */\nexport function registerPluginUpdates(ctx: Context) {\n ctx.inject(['remote', 'remote.pluginManager'], scoped => {\n const manager = scoped.remote.pluginManager\n for (const name of UPDATE_PACKAGES) {\n const updater = createPluginUpdater({\n list: async () => unwrap(await manager.listBundles()),\n install: async spec => unwrap(await manager.installBundle(spec, { saveExact: true })),\n ...typeof manager.updateBundle === 'function' ? { update: async (name: string, version: string) => unwrap(await manager.updateBundle(name, version, {})) } : {},\n }, name)\n scoped.effect(() => () => updater.dispose())\n scoped.effect(() => injectSlot(scoped, 'plugins.bundle.config', () => scoped.slots.register({\n name: 'plugins.bundle.config', key: name, locale: NAMESPACE,\n }, props => createElement(PluginUpdateCard, { ...(props as PropsLocale<'cannbotHarness'>), updater }))))\n }\n })\n}\nfunction unwrap<T>(result: { ok: true; value: T } | { ok: false; error: unknown }): T {\n if (!result.ok) throw result.error\n return result.value\n}\n","/** Browser companion using the existing DSH theme, settings and UI slots. */\nimport type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-theme/client'\nimport { en, zh, NAMESPACE, PACKAGE, type LocaleKey } from './locales.ts'\nimport { SidebarMark, SidebarName, Hero } from './Brand.tsx'\nimport { WorkflowCompat } from './WorkflowCompat.tsx'\nimport { cannTheme } from './theme.ts'\nimport interfaceCss from './interface.css?inline'\nimport './controls.css'\nimport { createElement } from 'react'\nimport { InterfaceToggle } from './InterfaceToggle.tsx'\nimport { createPresentationController } from './presentation.ts'\nimport { injectSlot } from './slot-compat.ts'\nimport { createWorkflowSelection, connectWorkflowSelection, type WorkflowSelection } from './workflow-selection.ts'\nimport { registerPluginUpdates } from './register-updates.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap { cannbotHarness: LocaleKey }\n}\nexport const inject = ['slots', 'theme', 'locale', 'sessions', 'conversation']\n\n/** Register presentation with an explicit disposer so the original entries remain live underneath. */\nfunction mountInterface(ctx: Context, selection: WorkflowSelection): () => void {\n const style = document.createElement('style')\n style.dataset.cannbotHarness = 'interface'\n style.textContent = interfaceCss\n document.head.append(style)\n const releases = [\n ctx.theme.overrideTokens(PACKAGE, cannTheme),\n injectSlot(ctx, 'sidebar.brand.mark', () => ctx.slots.register({ name: 'sidebar.brand.mark', priority: -100 }, SidebarMark)),\n injectSlot(ctx, 'sidebar.brand.name', () => ctx.slots.register({ name: 'sidebar.brand.name', priority: -100 }, SidebarName)),\n injectSlot(ctx, 'conversation.hero.brand.mark', () => ctx.slots.register({ name: 'conversation.hero.brand.mark', priority: -100 }, Hero)),\n injectSlot(ctx, 'conversation.hero.agentPreset', () => ctx.slots.register({ name: 'conversation.hero.agentPreset', priority: -100, locale: NAMESPACE }, props => createElement(WorkflowCompat, { ...props, ctx, selection }))),\n ]\n return () => { for (const release of releases.reverse()) release(); style.remove() }\n}\n\nexport function apply(ctx: Context): void {\n registerPluginUpdates(ctx)\n const selection = createWorkflowSelection((sessionId, reason) => {\n const blocks = ctx.conversation.blocks\n const id = sessionId as Parameters<typeof blocks.set>[0]\n const store = blocks.storeFor(id)\n // Do not replace a block owned by another DSH plugin.\n if (store.getSnapshot() !== undefined) return () => {}\n const block = { reason }\n blocks.set(id, block)\n return () => { if (store.getSnapshot() === block) blocks.set(id, undefined) }\n })\n connectWorkflowSelection(ctx, selection)\n ctx.effect(() => () => selection.dispose())\n ctx.effect(() => ctx.locale.register(NAMESPACE, { zh, en, ja: en, es: en, fr: en, de: en, ru: en, pt: en }))\n ctx.effect(() => {\n const controller = createPresentationController(() => mountInterface(ctx, selection))\n const releaseToggle = injectSlot(ctx, 'sidebar.footer.action', () => ctx.slots.register({\n name: 'sidebar.footer.action', id: 'cannbot-harness-interface', order: -100,\n }, props => createElement(InterfaceToggle, { ...props, controller })))\n return () => { releaseToggle(); controller.dispose() }\n })\n}\n"],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -2,9 +2,114 @@ import { FileSystemSkillProvider } from "@deepseek-ai/dsh-skill-filesystem";
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
|
+
import { createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
6
|
+
import { isUserInvocable, renderSkillContent } from "@deepseek-ai/dsh-skill";
|
|
7
|
+
import z from "@deepseek-ai/schemastery";
|
|
8
|
+
//#region src/workflows.ts
|
|
9
|
+
const WORKFLOWS = [
|
|
10
|
+
{
|
|
11
|
+
id: "ops-direct-invoke",
|
|
12
|
+
label: "operator"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "ops-direct-invoke-flash",
|
|
16
|
+
label: "flash"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "ops-registry-invoke",
|
|
20
|
+
label: "registry"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "model-infer-optimize",
|
|
24
|
+
label: "model"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "hccl-op-generator",
|
|
28
|
+
label: "hccl"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "triton-op-generator",
|
|
32
|
+
label: "triton"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "catlass-op-generator",
|
|
36
|
+
label: "catlass"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: "ops-perf-optimize",
|
|
40
|
+
label: "performance"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "pypto-op-orchestrator",
|
|
44
|
+
label: "pypto"
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/workflow-context.ts
|
|
49
|
+
const WORKFLOW_SETTINGS = "cannbot-harness";
|
|
50
|
+
const choiceSchema = () => z.array(z.object({
|
|
51
|
+
sessionId: z.string(),
|
|
52
|
+
workflow: z.union(["", ...WORKFLOWS.map((item) => item.id)])
|
|
53
|
+
})).default([]);
|
|
54
|
+
const selections = choiceSchema();
|
|
55
|
+
const Config = z.object({ selections: typeof selections.volatile === "function" ? selections.volatile() : selections });
|
|
56
|
+
const LegacyConfig = z.object({ selections: choiceSchema() });
|
|
57
|
+
function selectedWorkflows(config) {
|
|
58
|
+
const value = config.selections;
|
|
59
|
+
return Array.isArray(value) ? value : value?.get() ?? [];
|
|
60
|
+
}
|
|
61
|
+
function installWorkflowContext(ctx, config) {
|
|
62
|
+
let read = () => config;
|
|
63
|
+
ctx.inject(["settings"], (scoped) => {
|
|
64
|
+
const settings = scoped.settings;
|
|
65
|
+
if (typeof settings.register === "function") {
|
|
66
|
+
const base = { selections: selectedWorkflows(config).map(({ sessionId, workflow }) => ({
|
|
67
|
+
sessionId,
|
|
68
|
+
workflow
|
|
69
|
+
})) };
|
|
70
|
+
const handle = settings.register(WORKFLOW_SETTINGS, LegacyConfig, { base });
|
|
71
|
+
read = () => handle.get();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
ctx.inject(["agents", "workingDirectory"], (scoped) => {
|
|
75
|
+
scoped.on("agent/pre-step", async ({ agent, signal }, next) => {
|
|
76
|
+
const decision = await next();
|
|
77
|
+
if (decision.kind === "reject") return decision;
|
|
78
|
+
const messages = decision.messages.filter((message) => message.source?.kind !== "cannbot-harness-workflow");
|
|
79
|
+
const id = selectedWorkflows(read()).find((item) => item.sessionId === agent.id)?.workflow;
|
|
80
|
+
if (!id || !WORKFLOWS.some((item) => item.id === id)) return {
|
|
81
|
+
...decision,
|
|
82
|
+
messages
|
|
83
|
+
};
|
|
84
|
+
const skill = await scoped.skills.get(id, {
|
|
85
|
+
cwd: await scoped.workingDirectory.ensure(agent, signal),
|
|
86
|
+
scope: agent,
|
|
87
|
+
signal
|
|
88
|
+
});
|
|
89
|
+
if (!skill || !isUserInvocable(skill)) throw new Error(`CANNBot Harness workflow is unavailable: ${id}`);
|
|
90
|
+
const source = {
|
|
91
|
+
kind: "cannbot-harness-workflow",
|
|
92
|
+
name: id,
|
|
93
|
+
form: "instructions"
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
...decision,
|
|
97
|
+
messages: [...messages, createUserMessage({
|
|
98
|
+
source,
|
|
99
|
+
content: [{
|
|
100
|
+
type: "text",
|
|
101
|
+
text: renderSkillContent(skill)
|
|
102
|
+
}]
|
|
103
|
+
})]
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
5
109
|
//#region src/index.ts
|
|
6
110
|
const inject = ["skills"];
|
|
7
|
-
function apply(ctx) {
|
|
111
|
+
function apply(ctx, config = {}) {
|
|
112
|
+
installWorkflowContext(ctx, config);
|
|
8
113
|
const base = new URL("../assets/official/", import.meta.url);
|
|
9
114
|
const catalog = JSON.parse(readFileSync(new URL("catalog.json", base), "utf8"));
|
|
10
115
|
const byPath = new Map(catalog.exposedSkills.map((skill) => [resolve(fileURLToPath(new URL(skill.path, base))), skill]));
|
|
@@ -70,4 +175,4 @@ function apply(ctx) {
|
|
|
70
175
|
});
|
|
71
176
|
}
|
|
72
177
|
//#endregion
|
|
73
|
-
export { apply, inject };
|
|
178
|
+
export { Config, apply, inject };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cannbot-plugin/cannbot-harness",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "CANNBot Harness: all nine official CANNBot plugins and workflows for DSH",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN THIRD_PARTY_NOTICES.md",
|
|
@@ -54,11 +54,23 @@
|
|
|
54
54
|
],
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
57
|
-
"@deepseek-ai/dsh-skill-filesystem": ">=0.1.1-0 <0.3.0"
|
|
57
|
+
"@deepseek-ai/dsh-skill-filesystem": ">=0.1.1-0 <0.3.0",
|
|
58
|
+
"@deepseek-ai/schemastery": ">=3.18.0 <4",
|
|
59
|
+
"@deepseek-ai/dsh-llm": ">=0.1.1-0 <0.3.0",
|
|
60
|
+
"@deepseek-ai/dsh-skill": ">=0.1.1-0 <0.3.0"
|
|
58
61
|
},
|
|
59
62
|
"peerDependenciesMeta": {
|
|
60
63
|
"@deepseek-ai/dsh-skill-filesystem": {
|
|
61
64
|
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"@deepseek-ai/schemastery": {
|
|
67
|
+
"optional": true
|
|
68
|
+
},
|
|
69
|
+
"@deepseek-ai/dsh-llm": {
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
72
|
+
"@deepseek-ai/dsh-skill": {
|
|
73
|
+
"optional": true
|
|
62
74
|
}
|
|
63
75
|
},
|
|
64
76
|
"scripts": {
|