@cannbot-plugin/cannbot-harness 0.2.8 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -3
- package/lib/client.js +908 -44
- package/lib/client.js.map +1 -1
- package/lib/index.js +18 -9
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -79,16 +79,25 @@ window.__ModuleLoader__.load({
|
|
|
79
79
|
workflow: "选择工作流",
|
|
80
80
|
ordinary: "普通对话",
|
|
81
81
|
saving: "正在应用工作流…",
|
|
82
|
-
operator: "
|
|
82
|
+
operator: "ops-direct-invoke",
|
|
83
83
|
commandHint: "发送时自动应用所选工作流,只需填写需求。",
|
|
84
|
-
flash: "
|
|
85
|
-
registry: "
|
|
86
|
-
model: "
|
|
87
|
-
hccl: "
|
|
88
|
-
triton: "
|
|
89
|
-
catlass: "
|
|
90
|
-
performance: "
|
|
91
|
-
pypto: "
|
|
84
|
+
flash: "ops-direct-invoke-flash",
|
|
85
|
+
registry: "ops-registry-invoke",
|
|
86
|
+
model: "model-infer-optimize",
|
|
87
|
+
hccl: "hccl-op-generator",
|
|
88
|
+
triton: "triton-op-generator",
|
|
89
|
+
catlass: "catlass-op-generator",
|
|
90
|
+
performance: "ops-perf-optimize",
|
|
91
|
+
pypto: "pypto-op-orchestrator",
|
|
92
|
+
operatorDescription: "开发 Ascend C 算子,通过直调方式接入使用。",
|
|
93
|
+
flashDescription: "快速生成并验证 Ascend C 算子。",
|
|
94
|
+
registryDescription: "开发 Ascend C 注册算子,通过 ACLNN / GEIR 接入框架。",
|
|
95
|
+
modelDescription: "将模型迁移到 NPU,完成精度对齐与推理性能优化。",
|
|
96
|
+
hcclDescription: "开发 HCCL AICPU 通信算子,协同完成代码生成与验证。",
|
|
97
|
+
tritonDescription: "生成并优化 Triton-Ascend 算子代码。",
|
|
98
|
+
catlassDescription: "基于 CATLASS 模板开发矩阵计算、注意力等算子,验证精度与性能。",
|
|
99
|
+
performanceDescription: "分析并优化 Ascend C 算子性能,验证精度并检查性能退化。",
|
|
100
|
+
pyptoDescription: "开发并调优 PyPTO 算子,也支持对已有算子单独调优。",
|
|
92
101
|
chooseWorkspace: "请先选择工作目录。",
|
|
93
102
|
insertFailed: "工作流准备或设置未完成,请到插件详情查看准备日志后重试。",
|
|
94
103
|
settingsRetry: "设置连接失败,重试",
|
|
@@ -139,16 +148,25 @@ window.__ModuleLoader__.load({
|
|
|
139
148
|
workflow: "Choose workflow",
|
|
140
149
|
ordinary: "Ordinary conversation",
|
|
141
150
|
saving: "Applying workflow…",
|
|
142
|
-
operator: "
|
|
151
|
+
operator: "ops-direct-invoke",
|
|
143
152
|
commandHint: "The selected workflow is applied in the background when you send.",
|
|
144
|
-
flash: "
|
|
145
|
-
registry: "
|
|
146
|
-
model: "
|
|
147
|
-
hccl: "
|
|
148
|
-
triton: "
|
|
149
|
-
catlass: "
|
|
150
|
-
performance: "
|
|
151
|
-
pypto: "
|
|
153
|
+
flash: "ops-direct-invoke-flash",
|
|
154
|
+
registry: "ops-registry-invoke",
|
|
155
|
+
model: "model-infer-optimize",
|
|
156
|
+
hccl: "hccl-op-generator",
|
|
157
|
+
triton: "triton-op-generator",
|
|
158
|
+
catlass: "catlass-op-generator",
|
|
159
|
+
performance: "ops-perf-optimize",
|
|
160
|
+
pypto: "pypto-op-orchestrator",
|
|
161
|
+
operatorDescription: "Develop Ascend C operators and integrate them through direct invocation.",
|
|
162
|
+
flashDescription: "Quickly generate and validate Ascend C operators.",
|
|
163
|
+
registryDescription: "Develop registered Ascend C operators for framework integration through ACLNN / GEIR.",
|
|
164
|
+
modelDescription: "Migrate models to NPU, align accuracy and optimize inference performance.",
|
|
165
|
+
hcclDescription: "Develop HCCL AICPU communication operators with coordinated code generation and validation.",
|
|
166
|
+
tritonDescription: "Generate and optimize Triton-Ascend operator code.",
|
|
167
|
+
catlassDescription: "Build matrix and attention operators using CATLASS templates; validate accuracy and performance.",
|
|
168
|
+
performanceDescription: "Analyze and optimize Ascend C operator performance, checking accuracy and regressions.",
|
|
169
|
+
pyptoDescription: "Develop and tune PyPTO operators, or tune existing operators independently.",
|
|
152
170
|
chooseWorkspace: "Choose a working directory first.",
|
|
153
171
|
insertFailed: "Workflow preparation or saving failed. Check preparation logs in the plugin details and retry.",
|
|
154
172
|
settingsRetry: "Reconnect settings",
|
|
@@ -198,42 +216,61 @@ window.__ModuleLoader__.load({
|
|
|
198
216
|
const WORKFLOWS = [
|
|
199
217
|
{
|
|
200
218
|
id: "ops-direct-invoke",
|
|
201
|
-
label: "operator"
|
|
219
|
+
label: "operator",
|
|
220
|
+
description: "operatorDescription"
|
|
202
221
|
},
|
|
203
222
|
{
|
|
204
223
|
id: "ops-direct-invoke-flash",
|
|
205
|
-
label: "flash"
|
|
224
|
+
label: "flash",
|
|
225
|
+
description: "flashDescription"
|
|
206
226
|
},
|
|
207
227
|
{
|
|
208
228
|
id: "ops-registry-invoke",
|
|
209
|
-
label: "registry"
|
|
229
|
+
label: "registry",
|
|
230
|
+
description: "registryDescription"
|
|
210
231
|
},
|
|
211
232
|
{
|
|
212
233
|
id: "model-infer-optimize",
|
|
213
|
-
label: "model"
|
|
234
|
+
label: "model",
|
|
235
|
+
description: "modelDescription"
|
|
214
236
|
},
|
|
215
237
|
{
|
|
216
238
|
id: "hccl-op-generator",
|
|
217
|
-
label: "hccl"
|
|
239
|
+
label: "hccl",
|
|
240
|
+
description: "hcclDescription"
|
|
218
241
|
},
|
|
219
242
|
{
|
|
220
243
|
id: "triton-op-generator",
|
|
221
|
-
label: "triton"
|
|
244
|
+
label: "triton",
|
|
245
|
+
description: "tritonDescription"
|
|
222
246
|
},
|
|
223
247
|
{
|
|
224
248
|
id: "catlass-op-generator",
|
|
225
|
-
label: "catlass"
|
|
249
|
+
label: "catlass",
|
|
250
|
+
description: "catlassDescription"
|
|
226
251
|
},
|
|
227
252
|
{
|
|
228
253
|
id: "ops-perf-optimize",
|
|
229
|
-
label: "performance"
|
|
254
|
+
label: "performance",
|
|
255
|
+
description: "performanceDescription"
|
|
230
256
|
},
|
|
231
257
|
{
|
|
232
258
|
id: "pypto-op-orchestrator",
|
|
233
|
-
label: "pypto"
|
|
259
|
+
label: "pypto",
|
|
260
|
+
description: "pyptoDescription"
|
|
234
261
|
}
|
|
235
262
|
];
|
|
236
263
|
//#endregion
|
|
264
|
+
//#region src/client/workflow-copy.ts
|
|
265
|
+
/** Keep presentation consistent even when an older workflow package has a Chinese title. */
|
|
266
|
+
function workflowCopy(workflow, t) {
|
|
267
|
+
const known = WORKFLOWS.find((item) => item.id === workflow.id);
|
|
268
|
+
return {
|
|
269
|
+
name: workflow.id,
|
|
270
|
+
description: known ? t(known.description) : workflow.description ?? (workflow.title === workflow.id ? "" : workflow.title)
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
//#endregion
|
|
237
274
|
//#region src/client/WorkflowIcon.tsx
|
|
238
275
|
/** The exact icon component used by DSH's original Standard mode selector. */
|
|
239
276
|
function WorkflowIcon({ size = 16 }) {
|
|
@@ -357,10 +394,7 @@ window.__ModuleLoader__.load({
|
|
|
357
394
|
/** Select a workflow without submitting, replacing text, or discarding reference chips. */
|
|
358
395
|
function WorkflowSelector({ sessionId, inputActions, useInput, t, selection, content = fallbackContent }) {
|
|
359
396
|
const { workflows } = (0, react.useSyncExternalStore)(content.subscribe, content.getSnapshot);
|
|
360
|
-
const
|
|
361
|
-
const known = WORKFLOWS.find((item) => item.id === workflow.id);
|
|
362
|
-
return known ? t(known.label) : workflow.title;
|
|
363
|
-
};
|
|
397
|
+
const copy = (workflow) => workflowCopy(workflow, t);
|
|
364
398
|
const input = useInput((state) => state);
|
|
365
399
|
const saved = (0, react.useSyncExternalStore)(selection.subscribe, selection.getSnapshot);
|
|
366
400
|
const [open, setOpen] = (0, react.useState)(false);
|
|
@@ -383,17 +417,18 @@ window.__ModuleLoader__.load({
|
|
|
383
417
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkflowIcon, {}),
|
|
384
418
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
385
419
|
className: "cannbot-harness-workflow-label",
|
|
386
|
-
|
|
420
|
+
lang: selected ? "en" : void 0,
|
|
421
|
+
children: selected ? copy(selected).name : t("workflow")
|
|
387
422
|
}),
|
|
388
423
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronIcon, { size: 12 })
|
|
389
424
|
]
|
|
390
425
|
});
|
|
391
426
|
const label = (workflow) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
392
427
|
className: "cannbot-harness-workflow-option",
|
|
393
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
428
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
394
429
|
lang: "en",
|
|
395
|
-
children: workflow.
|
|
396
|
-
})]
|
|
430
|
+
children: copy(workflow).name
|
|
431
|
+
}), copy(workflow).description && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [" ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: copy(workflow).description })] })]
|
|
397
432
|
});
|
|
398
433
|
const { Menu, MenuItemButton } = _deepseek_ai_dsh_client_ui_primitives;
|
|
399
434
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
@@ -521,13 +556,13 @@ window.__ModuleLoader__.load({
|
|
|
521
556
|
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}";
|
|
522
557
|
//#endregion
|
|
523
558
|
//#region \0dsh-global-css:D:\code\cannbot-harness-plugin\src\client\controls.css.mjs
|
|
524
|
-
const css = ".cannbot-harness-workflow{flex-direction:column;align-items:flex-start;gap:4px;min-width:120px;max-width:280px;display:inline-flex;position:relative}.cannbot-harness-workflow-anchor{flex:none;min-width:120px;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);max-width:100%;font-size:12px;line-height:18px}.cannbot-harness-error button{color:inherit;font:inherit;text-align:start;cursor:pointer;text-underline-offset:3px;background:0 0;border:0;padding:0 8px;text-decoration:underline}.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}.cannbot-harness-content{margin-top:16px}.cannbot-harness-content details{margin-top:12px;font-size:12px}.cannbot-harness-content summary{cursor:pointer}.cannbot-harness-content pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:220px;font-size:11px;line-height:1.5;overflow:auto}.cannbot-harness-workflow-package{border-bottom:1px solid var(--dsw-alias-border-l2,#eee);justify-content:space-between;align-items:center;gap:12px;padding:14px 0;display:flex}.cannbot-harness-workflow-package>div:first-child{min-width:0}.cannbot-harness-workflow-package strong{font-size:13px;font-weight:500}.cannbot-harness-workflow-package small{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;font-size:11px;line-height:1.6;display:block}.cannbot-harness-workflow-package-actions{flex-wrap:wrap;flex-shrink:0;justify-content:flex-end;gap:8px;display:flex}@media (width<=480px){.cannbot-harness-workflow-package{flex-direction:column;align-items:flex-start}}";
|
|
525
|
-
const tagId = "@cannbot-plugin/cannbot-harness/controls.css";
|
|
526
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
559
|
+
const css$1 = ".cannbot-harness-workflow{flex-direction:column;align-items:flex-start;gap:4px;min-width:120px;max-width:280px;display:inline-flex;position:relative}.cannbot-harness-workflow-anchor{flex:none;min-width:120px;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);max-width:100%;font-size:12px;line-height:18px}.cannbot-harness-error button{color:inherit;font:inherit;text-align:start;cursor:pointer;text-underline-offset:3px;background:0 0;border:0;padding:0 8px;text-decoration:underline}.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}.cannbot-harness-content{margin-top:16px}.cannbot-harness-content details{margin-top:12px;font-size:12px}.cannbot-harness-content summary{cursor:pointer}.cannbot-harness-content pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:220px;font-size:11px;line-height:1.5;overflow:auto}.cannbot-harness-workflow-package{border-bottom:1px solid var(--dsw-alias-border-l2,#eee);justify-content:space-between;align-items:center;gap:12px;padding:14px 0;display:flex}.cannbot-harness-workflow-package>div:first-child{min-width:0}.cannbot-harness-workflow-package strong{font-size:13px;font-weight:500}.cannbot-harness-workflow-package small{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;font-size:11px;line-height:1.6;display:block}.cannbot-harness-workflow-package-actions{flex-wrap:wrap;flex-shrink:0;justify-content:flex-end;gap:8px;display:flex}@media (width<=480px){.cannbot-harness-workflow-package{flex-direction:column;align-items:flex-start}}";
|
|
560
|
+
const tagId$1 = "@cannbot-plugin/cannbot-harness/controls.css";
|
|
561
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
527
562
|
const tag = document.createElement("style");
|
|
528
563
|
tag.dataset.plugin = "@cannbot-plugin/cannbot-harness";
|
|
529
|
-
tag.dataset.pluginCss = tagId;
|
|
530
|
-
tag.textContent = css;
|
|
564
|
+
tag.dataset.pluginCss = tagId$1;
|
|
565
|
+
tag.textContent = css$1;
|
|
531
566
|
document.head.appendChild(tag);
|
|
532
567
|
}
|
|
533
568
|
//#endregion
|
|
@@ -1077,10 +1112,15 @@ window.__ModuleLoader__.load({
|
|
|
1077
1112
|
className: "cannbot-harness-workflow-packages",
|
|
1078
1113
|
children: status?.workflows?.map((row) => {
|
|
1079
1114
|
const available = row.latest && (!row.version || newerVersion(row.latest, row.version));
|
|
1115
|
+
const copy = workflowCopy(row, t);
|
|
1080
1116
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1081
1117
|
className: "cannbot-harness-workflow-package",
|
|
1082
1118
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
1083
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
1119
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
1120
|
+
lang: "en",
|
|
1121
|
+
children: copy.name
|
|
1122
|
+
}),
|
|
1123
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: copy.description }),
|
|
1084
1124
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
|
|
1085
1125
|
lang: "en",
|
|
1086
1126
|
children: row.package
|
|
@@ -1100,14 +1140,14 @@ window.__ModuleLoader__.load({
|
|
|
1100
1140
|
type: "button",
|
|
1101
1141
|
className: "cannbot-harness-update-recheck",
|
|
1102
1142
|
disabled: busy,
|
|
1103
|
-
"aria-label": `${row.installed ? t("contentUpdate") : t("contentInstall")} ${
|
|
1143
|
+
"aria-label": `${row.installed ? t("contentUpdate") : t("contentInstall")} ${copy.name}`,
|
|
1104
1144
|
onClick: () => act(() => content.update(row.id, row.latest)),
|
|
1105
1145
|
children: row.installed ? t("contentUpdate") : t("contentInstall")
|
|
1106
1146
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: row.installed ? row.latest ? t("contentUpToDate") : t("contentUnchecked") : t("contentUnavailable") }), row.previous && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1107
1147
|
type: "button",
|
|
1108
1148
|
className: "cannbot-harness-update-recheck",
|
|
1109
1149
|
disabled: busy,
|
|
1110
|
-
"aria-label": `${t("contentRollback")} ${
|
|
1150
|
+
"aria-label": `${t("contentRollback")} ${copy.name}`,
|
|
1111
1151
|
onClick: () => act(() => content.rollback(row.id)),
|
|
1112
1152
|
children: [
|
|
1113
1153
|
t("contentRollback"),
|
|
@@ -1159,6 +1199,829 @@ window.__ModuleLoader__.load({
|
|
|
1159
1199
|
return result.value;
|
|
1160
1200
|
}
|
|
1161
1201
|
//#endregion
|
|
1202
|
+
//#region src/client/workbench-state.ts
|
|
1203
|
+
const preparationLabels = {
|
|
1204
|
+
idle: "",
|
|
1205
|
+
workspace: "正在准备工作区…",
|
|
1206
|
+
dependencies: "正在准备工作流依赖…",
|
|
1207
|
+
upload: "正在上传文件…",
|
|
1208
|
+
conversation: "正在进入对话…"
|
|
1209
|
+
};
|
|
1210
|
+
function createWorkbenchState() {
|
|
1211
|
+
let state = {
|
|
1212
|
+
prompt: "",
|
|
1213
|
+
workflow: "",
|
|
1214
|
+
workspaceId: "",
|
|
1215
|
+
files: [],
|
|
1216
|
+
detail: "ops-direct-invoke",
|
|
1217
|
+
busy: false,
|
|
1218
|
+
error: "",
|
|
1219
|
+
stage: "idle"
|
|
1220
|
+
};
|
|
1221
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1222
|
+
const lifetime = new AbortController();
|
|
1223
|
+
return {
|
|
1224
|
+
signal: lifetime.signal,
|
|
1225
|
+
getSnapshot: () => state,
|
|
1226
|
+
subscribe(listener) {
|
|
1227
|
+
listeners.add(listener);
|
|
1228
|
+
return () => {
|
|
1229
|
+
listeners.delete(listener);
|
|
1230
|
+
};
|
|
1231
|
+
},
|
|
1232
|
+
set(patch) {
|
|
1233
|
+
if (lifetime.signal.aborted) return;
|
|
1234
|
+
state = {
|
|
1235
|
+
...state,
|
|
1236
|
+
...patch
|
|
1237
|
+
};
|
|
1238
|
+
for (const listener of listeners) listener();
|
|
1239
|
+
},
|
|
1240
|
+
dispose() {
|
|
1241
|
+
lifetime.abort();
|
|
1242
|
+
listeners.clear();
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
//#endregion
|
|
1247
|
+
//#region src/client/workbench-data.ts
|
|
1248
|
+
/** Presentation copy only. Execution and initialization remain owned by the workflow packages. */
|
|
1249
|
+
const categories = [
|
|
1250
|
+
"全部",
|
|
1251
|
+
"Ascend C",
|
|
1252
|
+
"其他算子",
|
|
1253
|
+
"通信",
|
|
1254
|
+
"性能优化"
|
|
1255
|
+
];
|
|
1256
|
+
const guides = {
|
|
1257
|
+
"ops-direct-invoke": {
|
|
1258
|
+
category: "Ascend C",
|
|
1259
|
+
icon: "code",
|
|
1260
|
+
scenes: ["开发新的 Ascend C 算子", "通过直调方式集成算子"],
|
|
1261
|
+
inputs: ["必需:算子功能、输入输出及数据类型", "可选:参考实现、目标硬件及性能要求"],
|
|
1262
|
+
outputs: ["算子实现与直调示例", "按实际环境生成的验证结果及运行说明"],
|
|
1263
|
+
example: "请开发一个 Ascend C 的 Add 算子,输入为两个 float16 张量,并通过直调方式验证结果。"
|
|
1264
|
+
},
|
|
1265
|
+
"ops-direct-invoke-flash": {
|
|
1266
|
+
category: "Ascend C",
|
|
1267
|
+
icon: "flash",
|
|
1268
|
+
scenes: ["快速实现与验证算子原型", "从明确的功能需求开始开发"],
|
|
1269
|
+
inputs: ["必需:算子功能及输入输出规格", "可选:参考代码、测试数据及目标硬件"],
|
|
1270
|
+
outputs: ["Ascend C 算子代码", "在可用环境中执行的编译与精度验证结果"],
|
|
1271
|
+
example: "帮我快速生成并验证一个 Ascend C 的 MatMul 算子,输入使用 float16,请先确认形状约束。"
|
|
1272
|
+
},
|
|
1273
|
+
"ops-registry-invoke": {
|
|
1274
|
+
category: "Ascend C",
|
|
1275
|
+
icon: "document",
|
|
1276
|
+
scenes: ["开发需要注册到框架的算子", "通过 ACLNN / GEIR 接入算子"],
|
|
1277
|
+
inputs: ["必需:算子定义、输入输出及接入方式", "可选:现有工程、参考实现及目标环境"],
|
|
1278
|
+
outputs: ["注册算子相关代码及接入示例", "按实际环境完成的验证与使用说明"],
|
|
1279
|
+
example: "开发一个 Ascend C 的自定义算子,并通过 ACLNN 接入。请先检查当前工程及输入输出定义。"
|
|
1280
|
+
},
|
|
1281
|
+
"triton-op-generator": {
|
|
1282
|
+
category: "其他算子",
|
|
1283
|
+
icon: "code",
|
|
1284
|
+
scenes: ["使用 Triton-Ascend 开发算子", "优化已有 Triton 算子实现"],
|
|
1285
|
+
inputs: ["必需:功能需求或已有 Triton 代码", "可选:张量规格、目标硬件与性能目标"],
|
|
1286
|
+
outputs: ["Triton-Ascend 算子代码", "实际执行的验证与调优记录"],
|
|
1287
|
+
example: "使用 Triton-Ascend 实现一个逐元素 Add 算子,并为不同输入形状添加验证。"
|
|
1288
|
+
},
|
|
1289
|
+
"catlass-op-generator": {
|
|
1290
|
+
category: "其他算子",
|
|
1291
|
+
icon: "layers",
|
|
1292
|
+
scenes: ["基于 CATLASS 模板开发矩阵计算算子", "开发注意力相关算子并验证精度与性能"],
|
|
1293
|
+
inputs: ["必需:计算需求及张量规格", "可选:CATLASS 工程、参考实现与性能目标"],
|
|
1294
|
+
outputs: ["基于 CATLASS 的实现及调用示例", "可用环境中的精度与性能验证结果"],
|
|
1295
|
+
example: "基于 CATLASS 模板开发一个矩阵乘算子,请先检查工程环境,再验证精度与性能。"
|
|
1296
|
+
},
|
|
1297
|
+
"pypto-op-orchestrator": {
|
|
1298
|
+
category: "其他算子",
|
|
1299
|
+
icon: "nodes",
|
|
1300
|
+
scenes: ["使用 PyPTO 开发并调优算子", "单独调优已有的 PyPTO 算子"],
|
|
1301
|
+
inputs: ["必需:算子需求或已有 PyPTO 代码", "可选:测试用例、目标硬件与性能目标"],
|
|
1302
|
+
outputs: ["PyPTO 算子实现或调优修改", "按实际执行情况整理的验证与优化结果"],
|
|
1303
|
+
example: "请分析当前 PyPTO 算子,保持计算结果一致,尝试优化性能并记录验证结果。"
|
|
1304
|
+
},
|
|
1305
|
+
"hccl-op-generator": {
|
|
1306
|
+
category: "通信",
|
|
1307
|
+
icon: "arrows",
|
|
1308
|
+
scenes: ["开发 HCCL AICPU 通信算子", "生成通信代码并准备验证"],
|
|
1309
|
+
inputs: ["必需:通信操作、参与设备及数据规格", "可选:现有通信工程及运行环境"],
|
|
1310
|
+
outputs: ["通信算子相关代码", "在可用设备环境中的验证结果及运行说明"],
|
|
1311
|
+
example: "帮我开发一个 HCCL AICPU 通信算子,请先确认通信操作、设备数量和测试环境。"
|
|
1312
|
+
},
|
|
1313
|
+
"ops-perf-optimize": {
|
|
1314
|
+
category: "性能优化",
|
|
1315
|
+
icon: "chart",
|
|
1316
|
+
scenes: ["分析已有 Ascend C 算子的性能瓶颈", "在保持精度的前提下迭代调优"],
|
|
1317
|
+
inputs: ["必需:已有算子代码及复现方法", "可选:基准数据、性能分析结果与目标"],
|
|
1318
|
+
outputs: ["性能分析及代码修改", "精度检查、性能对比及退化检查记录"],
|
|
1319
|
+
example: "请分析当前 Ascend C 算子的性能瓶颈,在保持精度的前提下优化,并对比修改前后的表现。"
|
|
1320
|
+
},
|
|
1321
|
+
"model-infer-optimize": {
|
|
1322
|
+
category: "性能优化",
|
|
1323
|
+
icon: "gear",
|
|
1324
|
+
scenes: ["将模型迁移到 NPU", "对齐精度并优化推理性能"],
|
|
1325
|
+
inputs: ["必需:模型代码、依赖及运行方法", "可选:模型权重路径、测试数据和基准结果"],
|
|
1326
|
+
outputs: ["模型迁移或推理优化修改", "实际完成的精度对齐与性能验证记录"],
|
|
1327
|
+
example: "请将当前模型迁移到 NPU,先检查依赖与运行方式,再进行精度对齐和推理性能优化。"
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
const guideFor = (id) => guides[id] ?? {
|
|
1331
|
+
category: "其他算子",
|
|
1332
|
+
icon: "nodes",
|
|
1333
|
+
scenes: ["使用此工作流完成开发需求"],
|
|
1334
|
+
inputs: ["请描述目标,并提供相关工程或代码"],
|
|
1335
|
+
outputs: ["以工作流实际执行结果为准"],
|
|
1336
|
+
example: "请根据当前工程和我的需求开展工作,开始前先检查必要的输入。"
|
|
1337
|
+
};
|
|
1338
|
+
const cardOrder = Object.keys(guides);
|
|
1339
|
+
//#endregion
|
|
1340
|
+
//#region src/client/workbench-workspace.ts
|
|
1341
|
+
/** Read only the public Session catalog and its main-view retention facts. */
|
|
1342
|
+
function inheritedWorkspaceId(workspaces, sessions) {
|
|
1343
|
+
const current = sessions.current ?? Object.entries(sessions.byId ?? {}).find(([, session]) => (session.retainedBy?.mainView ?? 0) > 0)?.[0];
|
|
1344
|
+
return current ? workspaces.find((workspace) => workspace.sessionIds?.includes(current))?.workspaceId : void 0;
|
|
1345
|
+
}
|
|
1346
|
+
//#endregion
|
|
1347
|
+
//#region src/client/WorkbenchIcon.tsx
|
|
1348
|
+
function WorkbenchIcon({ name = "grid", size = 20 }) {
|
|
1349
|
+
const paths = {
|
|
1350
|
+
grid: "M3 3h7v7H3z M14 3h7v7h-7z M3 14h7v7H3z M14 14h7v7h-7z",
|
|
1351
|
+
code: "m8 6-6 6 6 6 M16 6l6 6-6 6 M14 3l-4 18",
|
|
1352
|
+
flash: "m13 2-9 12h7l-1 8 10-13h-7z",
|
|
1353
|
+
document: "M5 3h14v18H5z M8 8h8 M8 12h8 M8 16h5",
|
|
1354
|
+
layers: "m12 2 10 6-10 6L2 8z M2 12l10 6 10-6 M2 16l10 6 10-6",
|
|
1355
|
+
nodes: "M10 2h4v4h-4z M2 18h6v4H2z M16 18h6v4h-6z M12 6v6 M5 18v-6h14v6",
|
|
1356
|
+
arrows: "M3 7h17l-4-4 M20 7l-4 4 M21 17H4l4-4 M4 17l4 4",
|
|
1357
|
+
chart: "M3 13h4v8H3z M10 8h4v13h-4z M17 3h4v18h-4z",
|
|
1358
|
+
gear: "M9 3h6l1 3 3 1 2 5-2 5-3 1-1 3H9l-1-3-3-1-2-5 2-5 3-1z M9 12a3 3 0 1 0 6 0a3 3 0 1 0-6 0",
|
|
1359
|
+
folder: "M2 6h8l2 3h10v12H2z M2 6V3h7l3 3h10v3",
|
|
1360
|
+
search: "M16 16l6 6 M18 10a8 8 0 1 0-16 0a8 8 0 1 0 16 0",
|
|
1361
|
+
clip: "m8 13 7-7a3 3 0 0 1 4 4L9 20a5 5 0 0 1-7-7L13 2 M6 15l9-9"
|
|
1362
|
+
};
|
|
1363
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
1364
|
+
width: size,
|
|
1365
|
+
height: size,
|
|
1366
|
+
viewBox: "0 0 24 24",
|
|
1367
|
+
fill: "none",
|
|
1368
|
+
stroke: "currentColor",
|
|
1369
|
+
strokeWidth: "1.6",
|
|
1370
|
+
strokeLinecap: "round",
|
|
1371
|
+
strokeLinejoin: "round",
|
|
1372
|
+
"aria-hidden": "true",
|
|
1373
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: paths[name] ?? paths.grid })
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
//#endregion
|
|
1377
|
+
//#region src/client/workbench-launch.ts
|
|
1378
|
+
/** Transfer to the resident DSH composer; its own submit policy remains authoritative. */
|
|
1379
|
+
async function launchWorkbench(ctx, selection, request, signal, onStage = () => {}) {
|
|
1380
|
+
if (!selection.getSnapshot().ready || selection.getSnapshot().pending) throw new Error("工作流设置尚未就绪,请稍后重试。");
|
|
1381
|
+
signal.throwIfAborted();
|
|
1382
|
+
const startingPanel = ctx.layout.panelInfo.getSnapshot().activePanelId;
|
|
1383
|
+
const sessions = ctx.sessions;
|
|
1384
|
+
onStage("workspace");
|
|
1385
|
+
const id = await sessions.create({ workspaceId: request.workspaceId });
|
|
1386
|
+
signal.throwIfAborted();
|
|
1387
|
+
const reference = sessions.retain(id, {
|
|
1388
|
+
source: "controllerOperation",
|
|
1389
|
+
signal
|
|
1390
|
+
});
|
|
1391
|
+
const conversation = ctx.conversation;
|
|
1392
|
+
let attachments = [];
|
|
1393
|
+
let transferred = false;
|
|
1394
|
+
try {
|
|
1395
|
+
const binding = await reference.ready;
|
|
1396
|
+
signal.throwIfAborted();
|
|
1397
|
+
if (request.workflow) onStage("dependencies");
|
|
1398
|
+
await selection.choose(id, request.workflow);
|
|
1399
|
+
signal.throwIfAborted();
|
|
1400
|
+
const saved = selection.getSnapshot();
|
|
1401
|
+
if (!saved.ready || saved.pending || saved.error || (saved.values[id] ?? "") !== request.workflow) throw new Error("工作流准备未完成,请在插件设置中查看日志后重试。");
|
|
1402
|
+
if (conversation.blocks.storeFor(id).getSnapshot()) throw new Error("当前对话暂时不能发送,请稍后重试。");
|
|
1403
|
+
const input = conversation.input.for(binding.ctx);
|
|
1404
|
+
if (conversation.input.requestDraftInitialization(binding, {
|
|
1405
|
+
prompt: request.prompt,
|
|
1406
|
+
whenDraftExists: "keep"
|
|
1407
|
+
}) !== "applied") throw new Error("新对话已存在草稿,已保留内容,请重试。");
|
|
1408
|
+
if (request.files.length) {
|
|
1409
|
+
onStage("upload");
|
|
1410
|
+
if (typeof conversation.createDrafts !== "function") throw new Error("此 DSH 版本请进入对话后添加文件。");
|
|
1411
|
+
attachments = conversation.createDrafts(id, request.files, true);
|
|
1412
|
+
await waitForUploads(conversation, attachments.map((item) => item.id), signal);
|
|
1413
|
+
if (!input.addAttachments(attachments.map((item) => item.id))) throw new Error("文件暂时无法加入对话,请重试。");
|
|
1414
|
+
}
|
|
1415
|
+
signal.throwIfAborted();
|
|
1416
|
+
if (ctx.layout.panelInfo.getSnapshot().activePanelId !== startingPanel) throw new Error("你已离开工作台,需求已保留;返回后可重新开始。");
|
|
1417
|
+
onStage("conversation");
|
|
1418
|
+
ctx.uiWorkspace.openSession(id);
|
|
1419
|
+
transferred = true;
|
|
1420
|
+
input.submit("queue", "click");
|
|
1421
|
+
} finally {
|
|
1422
|
+
if (!transferred) for (const attachment of attachments) conversation.releaseDraftAttachment(attachment.id);
|
|
1423
|
+
reference.release();
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
function waitForUploads(conversation, ids, signal) {
|
|
1427
|
+
return new Promise((resolve, reject) => {
|
|
1428
|
+
let unsubscribe = () => {}, timer;
|
|
1429
|
+
const finish = (error) => {
|
|
1430
|
+
unsubscribe();
|
|
1431
|
+
clearTimeout(timer);
|
|
1432
|
+
signal.removeEventListener("abort", abort);
|
|
1433
|
+
error ? reject(error) : resolve();
|
|
1434
|
+
};
|
|
1435
|
+
const abort = () => finish(signal.reason ?? /* @__PURE__ */ new Error("操作已取消。"));
|
|
1436
|
+
const check = () => {
|
|
1437
|
+
const uploads = conversation.fileUploads.getSnapshot();
|
|
1438
|
+
const failed = ids.map((id) => uploads[id]).find((upload) => upload?.status === "error");
|
|
1439
|
+
if (failed?.status === "error") finish(/* @__PURE__ */ new Error(`文件上传失败:${failed.message}`));
|
|
1440
|
+
else if (ids.every((id) => uploads[id]?.status === "ready")) finish();
|
|
1441
|
+
};
|
|
1442
|
+
unsubscribe = conversation.fileUploads.subscribe(check);
|
|
1443
|
+
timer = setTimeout(() => finish(/* @__PURE__ */ new Error("文件上传超时,请检查连接后重试。")), 12e4);
|
|
1444
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
1445
|
+
if (signal.aborted) abort();
|
|
1446
|
+
else check();
|
|
1447
|
+
});
|
|
1448
|
+
}
|
|
1449
|
+
//#endregion
|
|
1450
|
+
//#region src/client/Workbench.tsx
|
|
1451
|
+
const HOME_PANEL = "cannbot-harness-workbench";
|
|
1452
|
+
const LIBRARY_PANEL = "cannbot-harness-workflows";
|
|
1453
|
+
const copy = (workflow) => workflowCopy(workflow, (key) => zh[key]);
|
|
1454
|
+
function Workbench({ ctx, content, selection, store, library = false }) {
|
|
1455
|
+
const state = (0, react.useSyncExternalStore)(store.subscribe, store.getSnapshot);
|
|
1456
|
+
const { workflows, status } = (0, react.useSyncExternalStore)(content.subscribe, content.getSnapshot);
|
|
1457
|
+
const workspaceSource = ctx.workspaces.list;
|
|
1458
|
+
const workspaceBinding = (0, react.useMemo)(() => ({
|
|
1459
|
+
subscribe: (listener) => workspaceSource.subscribe(listener),
|
|
1460
|
+
getSnapshot: () => workspaceSource.getSnapshot()
|
|
1461
|
+
}), [workspaceSource]);
|
|
1462
|
+
const workspaceState = (0, react.useSyncExternalStore)(workspaceBinding.subscribe, workspaceBinding.getSnapshot);
|
|
1463
|
+
const sessionSource = ctx.sessions.list;
|
|
1464
|
+
const sessionBinding = (0, react.useMemo)(() => ({
|
|
1465
|
+
subscribe: (listener) => sessionSource.subscribe(listener),
|
|
1466
|
+
getSnapshot: () => sessionSource.getSnapshot()
|
|
1467
|
+
}), [sessionSource]);
|
|
1468
|
+
const sessionState = (0, react.useSyncExternalStore)(sessionBinding.subscribe, sessionBinding.getSnapshot);
|
|
1469
|
+
const saved = (0, react.useSyncExternalStore)(selection.subscribe, selection.getSnapshot);
|
|
1470
|
+
const [category, setCategory] = (0, react.useState)("全部");
|
|
1471
|
+
const [query, setQuery] = (0, react.useState)("");
|
|
1472
|
+
const input = (0, react.useRef)(null);
|
|
1473
|
+
const files = (0, react.useRef)(null);
|
|
1474
|
+
const visible = [...workflows].sort((a, b) => (cardOrder.indexOf(a.id) < 0 ? 999 : cardOrder.indexOf(a.id)) - (cardOrder.indexOf(b.id) < 0 ? 999 : cardOrder.indexOf(b.id))).filter((workflow) => (category === "全部" || guideFor(workflow.id).category === category) && `${workflow.id} ${copy(workflow).description}`.toLowerCase().includes(query.toLowerCase().trim()));
|
|
1475
|
+
const inheritedId = inheritedWorkspaceId(workspaceState.items, sessionState);
|
|
1476
|
+
const workspace = workspaceState.items.find((item) => item.workspaceId === (state.workspaceId || inheritedId));
|
|
1477
|
+
const inherited = !state.workspaceId && !!workspace && workspace.workspaceId === inheritedId;
|
|
1478
|
+
const selected = workflows.find((item) => item.id === state.workflow);
|
|
1479
|
+
const detail = workflows.find((item) => item.id === state.detail) ?? workflows[0];
|
|
1480
|
+
const navigate = (panel) => ctx.layout.selectPanel(panel);
|
|
1481
|
+
const settings = () => ctx.get("pluginNavigation")?.openBundle(PACKAGE);
|
|
1482
|
+
const fail = (error) => store.set({ error: error instanceof Error ? error.message : "暂时无法完成,请重试。" });
|
|
1483
|
+
const addWorkspace = async () => {
|
|
1484
|
+
if (store.getSnapshot().busy) return;
|
|
1485
|
+
store.set({
|
|
1486
|
+
error: "",
|
|
1487
|
+
busy: true,
|
|
1488
|
+
stage: "workspace"
|
|
1489
|
+
});
|
|
1490
|
+
try {
|
|
1491
|
+
const path = await ctx.uiWorkspace.pickDirectory();
|
|
1492
|
+
if (path && !store.signal.aborted) {
|
|
1493
|
+
const created = await ctx.workspaces.create({ path });
|
|
1494
|
+
store.set({ workspaceId: created.workspaceId });
|
|
1495
|
+
}
|
|
1496
|
+
} catch (error) {
|
|
1497
|
+
fail(error);
|
|
1498
|
+
} finally {
|
|
1499
|
+
store.set({
|
|
1500
|
+
busy: false,
|
|
1501
|
+
stage: "idle"
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
};
|
|
1505
|
+
const start = async (event) => {
|
|
1506
|
+
event?.preventDefault();
|
|
1507
|
+
if (store.getSnapshot().busy) return;
|
|
1508
|
+
if (!workspace) {
|
|
1509
|
+
store.set({ error: "请先选择或添加工作区。" });
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
if (!state.prompt.trim() && state.files.length === 0) {
|
|
1513
|
+
input.current?.focus();
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
store.set({
|
|
1517
|
+
busy: true,
|
|
1518
|
+
error: "",
|
|
1519
|
+
stage: "workspace"
|
|
1520
|
+
});
|
|
1521
|
+
try {
|
|
1522
|
+
await launchWorkbench(ctx, selection, {
|
|
1523
|
+
workspaceId: workspace.workspaceId,
|
|
1524
|
+
workflow: state.workflow,
|
|
1525
|
+
prompt: state.prompt,
|
|
1526
|
+
files: state.files
|
|
1527
|
+
}, store.signal, (stage) => store.set({ stage }));
|
|
1528
|
+
store.set({
|
|
1529
|
+
prompt: "",
|
|
1530
|
+
files: []
|
|
1531
|
+
});
|
|
1532
|
+
} catch (error) {
|
|
1533
|
+
fail(error);
|
|
1534
|
+
} finally {
|
|
1535
|
+
store.set({
|
|
1536
|
+
busy: false,
|
|
1537
|
+
stage: "idle"
|
|
1538
|
+
});
|
|
1539
|
+
}
|
|
1540
|
+
};
|
|
1541
|
+
const useWorkflow = (id, example) => {
|
|
1542
|
+
store.set({
|
|
1543
|
+
workflow: id,
|
|
1544
|
+
...example && !state.prompt.trim() ? { prompt: example } : {},
|
|
1545
|
+
error: ""
|
|
1546
|
+
});
|
|
1547
|
+
navigate(HOME_PANEL);
|
|
1548
|
+
};
|
|
1549
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("main", {
|
|
1550
|
+
className: "cannbot-workbench",
|
|
1551
|
+
"aria-label": library ? "CANNBot 工作流" : "CANNBot工作台",
|
|
1552
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
1553
|
+
className: "cwb-header",
|
|
1554
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1555
|
+
className: "cwb-workspace",
|
|
1556
|
+
children: [
|
|
1557
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchIcon, { name: "folder" }),
|
|
1558
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1559
|
+
className: "cwb-workspace-info",
|
|
1560
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1561
|
+
className: "cwb-workspace-choice",
|
|
1562
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
1563
|
+
"aria-label": "当前工作区",
|
|
1564
|
+
value: workspace?.workspaceId ?? "",
|
|
1565
|
+
disabled: state.busy || workspaceState.phase !== "ready",
|
|
1566
|
+
onChange: (event) => store.set({
|
|
1567
|
+
workspaceId: event.target.value,
|
|
1568
|
+
error: ""
|
|
1569
|
+
}),
|
|
1570
|
+
children: [!workspace && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1571
|
+
value: "",
|
|
1572
|
+
children: "选择工作区"
|
|
1573
|
+
}), workspaceState.items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
1574
|
+
value: item.workspaceId,
|
|
1575
|
+
children: item.title === "default-workspace" ? "默认工作区" : item.title
|
|
1576
|
+
}, item.workspaceId))]
|
|
1577
|
+
}), inherited && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1578
|
+
className: "cwb-inherited",
|
|
1579
|
+
children: "沿用当前对话"
|
|
1580
|
+
})]
|
|
1581
|
+
}), workspace && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1582
|
+
className: "cwb-workspace-path",
|
|
1583
|
+
title: workspace.path,
|
|
1584
|
+
children: workspace.path
|
|
1585
|
+
})]
|
|
1586
|
+
}),
|
|
1587
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1588
|
+
className: "cwb-text-button",
|
|
1589
|
+
disabled: state.busy,
|
|
1590
|
+
onClick: () => void addWorkspace(),
|
|
1591
|
+
children: "+ 添加工作区"
|
|
1592
|
+
})
|
|
1593
|
+
]
|
|
1594
|
+
}), library && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1595
|
+
className: "cwb-text-button",
|
|
1596
|
+
onClick: settings,
|
|
1597
|
+
children: "插件设置"
|
|
1598
|
+
})]
|
|
1599
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1600
|
+
className: "cwb-content",
|
|
1601
|
+
children: [
|
|
1602
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1603
|
+
className: "cwb-heading",
|
|
1604
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", { children: library ? "找到适合你的工作流" : "开始你的 Ascend 开发" }), library && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "了解适用场景,准备好输入,再开始。" })]
|
|
1605
|
+
}),
|
|
1606
|
+
!library && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1607
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
|
|
1608
|
+
className: "cwb-composer",
|
|
1609
|
+
onSubmit: (event) => void start(event),
|
|
1610
|
+
onDragOver: (event) => event.preventDefault(),
|
|
1611
|
+
onDrop: (event) => {
|
|
1612
|
+
event.preventDefault();
|
|
1613
|
+
if (!state.busy) store.set({ files: [...state.files, ...Array.from(event.dataTransfer.files)] });
|
|
1614
|
+
},
|
|
1615
|
+
children: [
|
|
1616
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
1617
|
+
ref: input,
|
|
1618
|
+
"aria-label": "开发需求",
|
|
1619
|
+
placeholder: selected ? `例如:${guideFor(selected.id).example}` : "描述算子需求,或添加需要优化的代码。",
|
|
1620
|
+
value: state.prompt,
|
|
1621
|
+
disabled: state.busy,
|
|
1622
|
+
onChange: (event) => store.set({ prompt: event.target.value })
|
|
1623
|
+
}),
|
|
1624
|
+
state.files.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
1625
|
+
className: "cwb-files",
|
|
1626
|
+
children: state.files.map((file, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
|
|
1627
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchIcon, {
|
|
1628
|
+
name: "document",
|
|
1629
|
+
size: 14
|
|
1630
|
+
}),
|
|
1631
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: file.name }),
|
|
1632
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1633
|
+
type: "button",
|
|
1634
|
+
disabled: state.busy,
|
|
1635
|
+
"aria-label": `移除 ${file.name}`,
|
|
1636
|
+
onClick: () => store.set({ files: state.files.filter((_, i) => i !== index) }),
|
|
1637
|
+
children: "×"
|
|
1638
|
+
})
|
|
1639
|
+
] }, `${file.name}-${index}`))
|
|
1640
|
+
}),
|
|
1641
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1642
|
+
className: "cwb-composer-actions",
|
|
1643
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1644
|
+
className: "cwb-composer-tools",
|
|
1645
|
+
children: [
|
|
1646
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1647
|
+
type: "file",
|
|
1648
|
+
multiple: true,
|
|
1649
|
+
hidden: true,
|
|
1650
|
+
ref: files,
|
|
1651
|
+
onChange: (event) => {
|
|
1652
|
+
store.set({ files: [...state.files, ...Array.from(event.target.files ?? [])] });
|
|
1653
|
+
event.target.value = "";
|
|
1654
|
+
}
|
|
1655
|
+
}),
|
|
1656
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1657
|
+
type: "button",
|
|
1658
|
+
className: "cwb-text-button",
|
|
1659
|
+
disabled: state.busy,
|
|
1660
|
+
onClick: () => files.current?.click(),
|
|
1661
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchIcon, {
|
|
1662
|
+
name: "clip",
|
|
1663
|
+
size: 18
|
|
1664
|
+
}), "添加文件"]
|
|
1665
|
+
}),
|
|
1666
|
+
state.workflow && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1667
|
+
className: "cwb-selection",
|
|
1668
|
+
children: [
|
|
1669
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchIcon, {
|
|
1670
|
+
name: guideFor(state.workflow).icon,
|
|
1671
|
+
size: 16
|
|
1672
|
+
}),
|
|
1673
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: state.workflow }),
|
|
1674
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1675
|
+
type: "button",
|
|
1676
|
+
disabled: state.busy,
|
|
1677
|
+
"aria-label": "取消工作流选择",
|
|
1678
|
+
onClick: () => store.set({ workflow: "" }),
|
|
1679
|
+
children: "×"
|
|
1680
|
+
})
|
|
1681
|
+
]
|
|
1682
|
+
})
|
|
1683
|
+
]
|
|
1684
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1685
|
+
className: "cwb-primary",
|
|
1686
|
+
type: "submit",
|
|
1687
|
+
disabled: state.busy || !saved.ready || saved.pending || !state.prompt.trim() && !state.files.length,
|
|
1688
|
+
children: [state.busy ? "处理中…" : "开始", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1689
|
+
"aria-hidden": "true",
|
|
1690
|
+
children: "→"
|
|
1691
|
+
})]
|
|
1692
|
+
})]
|
|
1693
|
+
})
|
|
1694
|
+
]
|
|
1695
|
+
}),
|
|
1696
|
+
(state.busy || !saved.ready || !workspace) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1697
|
+
className: "cwb-hint",
|
|
1698
|
+
role: "status",
|
|
1699
|
+
"aria-live": "polite",
|
|
1700
|
+
children: state.busy ? preparationLabels[state.stage] : !saved.ready ? "正在连接工作流设置…" : "请先选择或添加工作区。"
|
|
1701
|
+
}),
|
|
1702
|
+
saved.errorKind === "settings" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1703
|
+
className: "cwb-text-button",
|
|
1704
|
+
onClick: () => selection.retry(),
|
|
1705
|
+
children: "重试连接工作流设置"
|
|
1706
|
+
})
|
|
1707
|
+
] }),
|
|
1708
|
+
state.error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1709
|
+
className: "cwb-error",
|
|
1710
|
+
role: "alert",
|
|
1711
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1712
|
+
className: "cwb-error-heading",
|
|
1713
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: "暂时无法开始,需求和文件已保留。" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1714
|
+
type: "button",
|
|
1715
|
+
className: "cwb-text-button",
|
|
1716
|
+
disabled: state.busy || !saved.ready || saved.pending,
|
|
1717
|
+
onClick: () => void start(),
|
|
1718
|
+
children: "重试"
|
|
1719
|
+
})]
|
|
1720
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [
|
|
1721
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", { children: "查看原因" }),
|
|
1722
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: state.error }),
|
|
1723
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1724
|
+
className: "cwb-text-button",
|
|
1725
|
+
onClick: settings,
|
|
1726
|
+
children: "打开插件设置"
|
|
1727
|
+
})
|
|
1728
|
+
] })]
|
|
1729
|
+
}),
|
|
1730
|
+
workspaceState.state === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1731
|
+
role: "alert",
|
|
1732
|
+
className: "cwb-error",
|
|
1733
|
+
children: "工作区加载失败,请检查 DSH 连接。"
|
|
1734
|
+
}),
|
|
1735
|
+
!library && state.workflow && !selected && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1736
|
+
role: "alert",
|
|
1737
|
+
className: "cwb-error",
|
|
1738
|
+
children: "所选工作流已不在当前目录中,请重新选择。"
|
|
1739
|
+
}),
|
|
1740
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1741
|
+
className: "cwb-catalog",
|
|
1742
|
+
"aria-label": "工作流目录",
|
|
1743
|
+
children: [
|
|
1744
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1745
|
+
className: "cwb-catalog-heading",
|
|
1746
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: library ? "全部工作流" : "工作流" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1747
|
+
className: "cwb-search",
|
|
1748
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchIcon, {
|
|
1749
|
+
name: "search",
|
|
1750
|
+
size: 17
|
|
1751
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1752
|
+
"aria-label": "搜索工作流",
|
|
1753
|
+
placeholder: "搜索工作流",
|
|
1754
|
+
value: query,
|
|
1755
|
+
onChange: (event) => setQuery(event.target.value)
|
|
1756
|
+
})]
|
|
1757
|
+
})]
|
|
1758
|
+
}),
|
|
1759
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1760
|
+
className: "cwb-categories",
|
|
1761
|
+
role: "group",
|
|
1762
|
+
"aria-label": "工作流分类",
|
|
1763
|
+
children: categories.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1764
|
+
"aria-pressed": category === item,
|
|
1765
|
+
onClick: () => setCategory(item),
|
|
1766
|
+
children: item
|
|
1767
|
+
}, item))
|
|
1768
|
+
}),
|
|
1769
|
+
library ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1770
|
+
className: "cwb-library",
|
|
1771
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
1772
|
+
"aria-label": "选择工作流详情",
|
|
1773
|
+
className: "cwb-library-list",
|
|
1774
|
+
children: [visible.map((workflow) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1775
|
+
"aria-current": detail?.id === workflow.id ? "true" : void 0,
|
|
1776
|
+
onClick: () => store.set({ detail: workflow.id }),
|
|
1777
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchIcon, { name: guideFor(workflow.id).icon }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: workflow.id }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: copy(workflow).description })] })]
|
|
1778
|
+
}, workflow.id)), !visible.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1779
|
+
className: "cwb-empty",
|
|
1780
|
+
children: "没有匹配的工作流"
|
|
1781
|
+
})]
|
|
1782
|
+
}), detail ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkflowDetail, {
|
|
1783
|
+
workflow: detail,
|
|
1784
|
+
content,
|
|
1785
|
+
onUse: () => useWorkflow(detail.id),
|
|
1786
|
+
onExample: () => useWorkflow(detail.id, guideFor(detail.id).example),
|
|
1787
|
+
onSettings: settings
|
|
1788
|
+
}, detail.id) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1789
|
+
className: "cwb-empty",
|
|
1790
|
+
children: "工作流目录尚未准备完成,请到插件设置查看准备状态。"
|
|
1791
|
+
})]
|
|
1792
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1793
|
+
className: "cwb-grid",
|
|
1794
|
+
children: [visible.map((workflow) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1795
|
+
type: "button",
|
|
1796
|
+
className: "cwb-card",
|
|
1797
|
+
"aria-pressed": state.workflow === workflow.id,
|
|
1798
|
+
disabled: state.busy,
|
|
1799
|
+
onClick: () => {
|
|
1800
|
+
const next = state.workflow === workflow.id ? "" : workflow.id;
|
|
1801
|
+
store.set({
|
|
1802
|
+
workflow: next,
|
|
1803
|
+
error: ""
|
|
1804
|
+
});
|
|
1805
|
+
if (next) input.current?.focus();
|
|
1806
|
+
},
|
|
1807
|
+
children: [
|
|
1808
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1809
|
+
className: "cwb-card-icon",
|
|
1810
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchIcon, {
|
|
1811
|
+
name: guideFor(workflow.id).icon,
|
|
1812
|
+
size: 23
|
|
1813
|
+
})
|
|
1814
|
+
}),
|
|
1815
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1816
|
+
className: "cwb-card-copy",
|
|
1817
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: workflow.id }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: copy(workflow).description })]
|
|
1818
|
+
}),
|
|
1819
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1820
|
+
className: "cwb-card-corner",
|
|
1821
|
+
"aria-hidden": "true",
|
|
1822
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
1823
|
+
width: "18",
|
|
1824
|
+
height: "18",
|
|
1825
|
+
viewBox: "0 0 20 20",
|
|
1826
|
+
fill: "none",
|
|
1827
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
1828
|
+
cx: "10",
|
|
1829
|
+
cy: "10",
|
|
1830
|
+
r: "8",
|
|
1831
|
+
fill: state.workflow === workflow.id ? "#da203e" : "none",
|
|
1832
|
+
stroke: state.workflow === workflow.id ? "#da203e" : "currentColor",
|
|
1833
|
+
strokeWidth: "1.2"
|
|
1834
|
+
}), state.workflow === workflow.id && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
1835
|
+
d: "m6 10 2.6 2.6L14 7.2",
|
|
1836
|
+
stroke: "white",
|
|
1837
|
+
strokeWidth: "1.6",
|
|
1838
|
+
strokeLinecap: "round",
|
|
1839
|
+
strokeLinejoin: "round"
|
|
1840
|
+
})]
|
|
1841
|
+
})
|
|
1842
|
+
})
|
|
1843
|
+
]
|
|
1844
|
+
}, workflow.id)), !visible.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1845
|
+
className: "cwb-empty",
|
|
1846
|
+
children: "没有匹配的工作流,请换一个关键词或分类。"
|
|
1847
|
+
})]
|
|
1848
|
+
})
|
|
1849
|
+
]
|
|
1850
|
+
}),
|
|
1851
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
|
|
1852
|
+
className: "cwb-footer",
|
|
1853
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: status?.phase === "syncing" ? "正在准备工作流包…" : status?.phase === "error" ? "工作流准备异常,请查看插件设置。" : "工作流内容可独立更新" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1854
|
+
className: "cwb-text-button",
|
|
1855
|
+
onClick: settings,
|
|
1856
|
+
children: "查看插件设置 ↗"
|
|
1857
|
+
})]
|
|
1858
|
+
})
|
|
1859
|
+
]
|
|
1860
|
+
})]
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
function WorkflowDetail({ workflow, content, onUse, onExample, onSettings }) {
|
|
1864
|
+
const { status } = (0, react.useSyncExternalStore)(content.subscribe, content.getSnapshot);
|
|
1865
|
+
const [error, setError] = (0, react.useState)(""), [pending, setPending] = (0, react.useState)(false);
|
|
1866
|
+
const guide = guideFor(workflow.id), row = status?.workflows?.find((item) => item.id === workflow.id);
|
|
1867
|
+
const busy = pending || status?.busy || status?.phase === "syncing" || status?.phase === "initializing";
|
|
1868
|
+
const act = async (action) => {
|
|
1869
|
+
setError("");
|
|
1870
|
+
setPending(true);
|
|
1871
|
+
try {
|
|
1872
|
+
await action();
|
|
1873
|
+
} catch {
|
|
1874
|
+
setError("操作未完成,请在插件设置中查看日志后重试。");
|
|
1875
|
+
} finally {
|
|
1876
|
+
setPending(false);
|
|
1877
|
+
}
|
|
1878
|
+
};
|
|
1879
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
1880
|
+
className: "cwb-detail",
|
|
1881
|
+
children: [
|
|
1882
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1883
|
+
className: "cwb-detail-title",
|
|
1884
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1885
|
+
className: "cwb-card-icon",
|
|
1886
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkbenchIcon, {
|
|
1887
|
+
name: guide.icon,
|
|
1888
|
+
size: 25
|
|
1889
|
+
})
|
|
1890
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: guide.category }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: workflow.id })] })]
|
|
1891
|
+
}),
|
|
1892
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1893
|
+
className: "cwb-detail-summary",
|
|
1894
|
+
children: copy(workflow).description
|
|
1895
|
+
}),
|
|
1896
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1897
|
+
className: "cwb-primary",
|
|
1898
|
+
onClick: onUse,
|
|
1899
|
+
children: ["使用此工作流 ", /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1900
|
+
"aria-hidden": "true",
|
|
1901
|
+
children: "→"
|
|
1902
|
+
})]
|
|
1903
|
+
}),
|
|
1904
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1905
|
+
className: "cwb-guide-sections",
|
|
1906
|
+
children: [
|
|
1907
|
+
["适合做什么", guide.scenes],
|
|
1908
|
+
["需要提供什么", guide.inputs],
|
|
1909
|
+
["可以获得什么", guide.outputs]
|
|
1910
|
+
].map(([title, entries]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: title }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", { children: entries.map((line) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: line }, line)) })] }, title))
|
|
1911
|
+
}),
|
|
1912
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1913
|
+
className: "cwb-example",
|
|
1914
|
+
children: [
|
|
1915
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: "试试这样描述需求" }),
|
|
1916
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: guide.example }),
|
|
1917
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1918
|
+
className: "cwb-text-button",
|
|
1919
|
+
onClick: onExample,
|
|
1920
|
+
children: "使用此示例 ↗"
|
|
1921
|
+
}),
|
|
1922
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "已有需求会保留,不会被示例覆盖。" })
|
|
1923
|
+
]
|
|
1924
|
+
}),
|
|
1925
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
1926
|
+
className: "cwb-version",
|
|
1927
|
+
children: [
|
|
1928
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", { children: ["版本与更新 ", row?.version ? ` · ${row.version}` : ""] }),
|
|
1929
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [row?.installed ? `已安装 ${row.version ?? ""}` : "安装状态尚未确认,请检查插件设置。", row?.latest && ` · 最新版本 ${row.latest}`] }),
|
|
1930
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1931
|
+
className: "cwb-version-actions",
|
|
1932
|
+
children: [
|
|
1933
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1934
|
+
className: "cwb-text-button",
|
|
1935
|
+
disabled: busy,
|
|
1936
|
+
onClick: () => void act(content.check),
|
|
1937
|
+
children: "检查更新"
|
|
1938
|
+
}),
|
|
1939
|
+
row?.latest && (!row.version || newerVersion(row.latest, row.version)) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1940
|
+
className: "cwb-text-button",
|
|
1941
|
+
disabled: busy,
|
|
1942
|
+
onClick: () => void act(() => content.update(row.id, row.latest)),
|
|
1943
|
+
children: row.installed ? "更新工作流" : "安装工作流"
|
|
1944
|
+
}),
|
|
1945
|
+
row?.previous && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1946
|
+
className: "cwb-text-button",
|
|
1947
|
+
disabled: busy,
|
|
1948
|
+
onClick: () => void act(() => content.rollback(row.id)),
|
|
1949
|
+
children: ["回退到 ", row.previous]
|
|
1950
|
+
}),
|
|
1951
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1952
|
+
className: "cwb-text-button",
|
|
1953
|
+
onClick: onSettings,
|
|
1954
|
+
children: "准备日志与管理"
|
|
1955
|
+
})
|
|
1956
|
+
]
|
|
1957
|
+
}),
|
|
1958
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: "初始化和验证以当前工作区的实际环境为准。" }),
|
|
1959
|
+
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1960
|
+
role: "alert",
|
|
1961
|
+
children: error
|
|
1962
|
+
})
|
|
1963
|
+
]
|
|
1964
|
+
})
|
|
1965
|
+
]
|
|
1966
|
+
}, workflow.id);
|
|
1967
|
+
}
|
|
1968
|
+
//#endregion
|
|
1969
|
+
//#region \0dsh-global-css:D:\code\cannbot-harness-plugin\src\client\workbench.css.mjs
|
|
1970
|
+
const css = ".cannbot-workbench{--cwb-ink:var(--dsw-alias-label-primary,#17181d);--cwb-muted:var(--dsw-alias-label-secondary,#677185);--cwb-surface:var(--dsw-alias-bg-layer-1,#fff);--cwb-border:var(--dsw-alias-border-l2,#e2e5eb);--cwb-soft:var(--dsw-alias-bg-layer-3,#f6f8fa);--cwb-accent:var(--dsw-alias-state-business-primary,#da203e);--cwb-selected:var(--dsw-alias-state-business-tertiary,#fdeef0);color:var(--cwb-ink);background:var(--cwb-surface);height:100%;font-family:inherit;font-size:14px;overflow:auto}.cannbot-workbench *,.cannbot-workbench :before,.cannbot-workbench :after{box-sizing:border-box}.cannbot-workbench button,.cannbot-workbench input,.cannbot-workbench select,.cannbot-workbench textarea{font:inherit}.cannbot-workbench button{cursor:pointer}.cannbot-workbench button:disabled{opacity:.5;cursor:default}.cannbot-workbench :is(button,input,select,textarea):focus-visible{outline:2px solid var(--cwb-accent);outline-offset:3px}.cwb-header{border-bottom:1px solid var(--cwb-border);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;min-height:62px;padding:12px 30px;display:flex}.cwb-workspace{flex-wrap:wrap;align-items:center;gap:12px;min-width:0;display:flex}.cwb-workspace-info{min-width:0}.cwb-workspace-choice{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.cwb-inherited{color:var(--cwb-muted);background:var(--cwb-soft);border-radius:5px;padding:3px 7px;font-size:11px}.cwb-workspace-path{text-overflow:ellipsis;white-space:nowrap;max-width:min(52vw,560px);color:var(--cwb-muted);padding-left:6px;font-size:12px;line-height:1.5;display:block;overflow:hidden}.cwb-workspace select{background:var(--cwb-surface);max-width:300px;color:var(--cwb-ink);border:0;padding:6px}.cwb-content{max-width:1260px;margin:0 auto;padding:26px 32px 22px}.cwb-heading{margin-bottom:20px}.cwb-heading h1{letter-spacing:-.5px;margin:0 0 8px;font-size:28px;font-weight:650;line-height:1.3}.cwb-heading p{color:var(--cwb-muted);margin:0;font-size:15px;line-height:1.6}.cwb-text-button{color:var(--cwb-muted);text-align:start;background:0 0;border:0;align-items:center;gap:7px;padding:5px 2px;display:inline-flex}.cwb-text-button:hover:not(:disabled){color:var(--cwb-accent)}.cwb-composer{background:var(--cwb-surface);border:1px solid var(--cwb-border);border-radius:14px;padding:18px 20px 14px;box-shadow:0 5px 20px #17213b05}.cwb-composer:focus-within{border-color:var(--cwb-accent)}.cwb-composer textarea{resize:vertical;width:100%;min-height:72px;max-height:340px;color:var(--cwb-ink);background:0 0;border:0;outline:0;padding:0;font-size:15px;line-height:1.65;display:block}.cwb-composer textarea:focus-visible{outline:0}.cwb-composer textarea::placeholder{color:var(--cwb-muted)}.cwb-composer-actions,.cwb-composer-tools{flex-wrap:wrap;align-items:center;gap:16px;min-width:0;display:flex}.cwb-composer-actions{justify-content:space-between;margin-top:12px}.cwb-primary{color:#fff;white-space:nowrap;background:#da203e;border:1px solid #d91d3e;border-radius:9px;justify-content:center;align-items:center;gap:22px;min-height:42px;padding:10px 22px;font-weight:550;display:inline-flex}.cwb-primary:hover:not(:disabled){background:#b11430}.cwb-selection{color:var(--cwb-accent);background:var(--cwb-selected);border-radius:7px;align-items:center;gap:8px;min-width:0;max-width:100%;padding:6px 9px;font-size:12px;display:inline-flex}.cwb-selection>span{overflow-wrap:anywhere}.cwb-selection button,.cwb-files button{color:inherit;background:0 0;border:0;padding:0 4px;font-size:18px}.cwb-files{flex-wrap:wrap;gap:8px;margin:0;padding:10px 0;list-style:none;display:flex}.cwb-files li{border:1px solid var(--cwb-border);border-radius:6px;align-items:center;gap:6px;max-width:250px;padding:3px 6px;display:inline-flex}.cwb-files li span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.cwb-hint{color:var(--cwb-muted);margin:10px 0 0;font-size:12px;line-height:1.6}.cwb-error{border-left:3px solid var(--cwb-accent);background:var(--cwb-selected);color:var(--cwb-ink);padding:12px 14px;line-height:1.6}.cwb-error-heading{justify-content:space-between;align-items:center;gap:12px;display:flex}.cwb-error .cwb-text-button{color:var(--cwb-accent)}.cwb-error summary{cursor:pointer;color:var(--cwb-muted);font-size:12px}.cwb-error details p{white-space:pre-wrap;overflow-wrap:anywhere;margin:8px 0}.cwb-catalog-heading{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:12px;margin:26px 0 6px;display:flex}.cwb-catalog-heading h2{margin:0;font-size:20px;font-weight:600}.cwb-search{border:1px solid var(--cwb-border);color:var(--cwb-muted);border-radius:8px;align-items:center;gap:9px;padding:8px 11px;display:flex}.cwb-search input{width:170px;color:var(--cwb-ink);background:0 0;border:0;outline:0;font-size:13px}.cwb-categories{border-bottom:1px solid var(--cwb-border);gap:22px;margin-bottom:18px;display:flex;overflow-x:auto}.cwb-categories button{color:var(--cwb-muted);white-space:nowrap;background:0 0;border:0;border-bottom:2px solid #0000;padding:12px 3px}.cwb-categories button[aria-pressed=true]{border-bottom-color:var(--cwb-accent);color:var(--cwb-accent);font-weight:550}.cwb-grid{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start;gap:10px;display:grid}.cwb-card{text-align:start;border:1px solid var(--cwb-border);width:100%;min-height:96px;color:var(--cwb-ink);background:var(--cwb-surface);border-radius:9px;grid-template-columns:28px minmax(0,1fr) 18px;align-items:start;gap:10px;padding:14px;transition:border-color .15s,background .15s;display:grid}.cwb-card:hover:not(:disabled){border-color:var(--cwb-accent)}.cwb-card[aria-pressed=true]{border-color:var(--cwb-accent);background:var(--cwb-selected)}.cwb-card-icon{background:var(--cwb-selected);width:40px;height:40px;color:var(--cwb-accent);border-radius:9px;flex:none;justify-content:center;align-items:center;display:inline-flex}.cwb-card .cwb-card-icon{border-radius:6px;width:28px;height:28px}.cwb-card .cwb-card-icon svg{width:19px;height:19px}.cwb-card-copy{flex-direction:column;gap:5px;min-width:0;padding-top:3px;display:flex}.cwb-card-copy strong{overflow-wrap:anywhere;font-size:14px;font-weight:600;line-height:1.4}.cwb-card-copy>span{color:var(--cwb-muted);font-size:12px;line-height:1.55}.cwb-card-corner{width:18px;height:18px;color:var(--cwb-muted);background:0 0;border:0;justify-content:center;align-items:center;margin-top:3px;display:inline-flex}.cwb-card-corner svg{flex:none;display:block}.cwb-footer{color:var(--cwb-muted);flex-wrap:wrap;align-items:center;gap:20px;margin-top:16px;font-size:12px;display:flex}.cwb-footer .cwb-text-button{color:var(--cwb-accent)}.cwb-empty{color:var(--cwb-muted);padding:20px 0;line-height:1.7}.cwb-library{border:1px solid var(--cwb-border);border-radius:12px;grid-template-columns:minmax(220px,.85fr) minmax(0,2fr);display:grid;overflow:hidden}.cwb-library-list{background:var(--cwb-soft);border-right:1px solid var(--cwb-border);padding:10px}.cwb-library-list button{text-align:start;width:100%;color:var(--cwb-ink);background:0 0;border:1px solid #0000;border-radius:8px;gap:12px;padding:14px 12px;display:flex}.cwb-library-list button[aria-current=true]{border-color:var(--cwb-border);background:var(--cwb-surface)}.cwb-library-list button[aria-current=true]>svg{color:var(--cwb-accent)}.cwb-library-list button>svg{flex:none;margin-top:2px}.cwb-library-list button span{min-width:0}.cwb-library-list strong{overflow-wrap:anywhere;font-size:13px;font-weight:550;line-height:1.5;display:block}.cwb-library-list small{color:var(--cwb-muted);margin-top:5px;font-size:12px;line-height:1.6;display:block}.cwb-detail{min-width:0;padding:28px 30px}.cwb-detail-title{align-items:center;gap:14px;display:flex}.cwb-detail-title small{color:var(--cwb-muted);font-size:12px}.cwb-detail-title h2{overflow-wrap:anywhere;margin:5px 0 0;font-size:21px;line-height:1.4}.cwb-detail-summary{color:var(--cwb-muted);margin:17px 0 20px;line-height:1.7}.cwb-guide-sections{grid-template-columns:1fr;gap:18px;margin-top:28px;display:grid}.cwb-detail h3{margin:0 0 9px;font-size:14px;font-weight:600}.cwb-guide-sections ul{color:var(--cwb-muted);margin:0;padding-left:18px;font-size:13px;line-height:1.9}.cwb-example{border:1px solid var(--cwb-border);background:var(--cwb-soft);border-radius:9px;margin-top:24px;padding:18px}.cwb-example p{color:var(--cwb-muted);margin:8px 0;font-size:13px;line-height:1.8}.cwb-example .cwb-text-button{color:var(--cwb-accent)}.cwb-example small{color:var(--cwb-muted);margin-top:6px;font-size:11px;display:block}.cwb-version{border-top:1px solid var(--cwb-border);color:var(--cwb-muted);margin-top:24px;padding-top:18px;font-size:12px;line-height:1.8}.cwb-version summary{cursor:pointer}.cwb-version-actions{flex-wrap:wrap;gap:15px;display:flex}.cannbot-workbench{container:cwb/inline-size}@container cwb (width<=900px){.cwb-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}@container cwb (width<=590px){.cwb-grid{grid-template-columns:1fr}}@media (width<=1120px){.cwb-content{padding:24px}.cwb-library{grid-template-columns:minmax(190px,.9fr) minmax(0,1.6fr)}.cwb-detail{padding:22px}}@media (width<=700px){.cwb-header{padding:12px 16px}.cwb-content{padding:22px 16px}.cwb-heading h1{font-size:25px}.cwb-grid,.cwb-library{grid-template-columns:1fr}.cwb-library-list{border-right:0;border-bottom:1px solid var(--cwb-border);max-height:220px;overflow:auto}.cwb-composer{padding:15px}.cwb-workspace select{max-width:190px}.cwb-composer-tools{gap:8px}.cwb-composer-actions{align-items:end}.cwb-primary{padding:9px 17px}.cwb-search,.cwb-search input{width:100%}}@media (prefers-reduced-motion:reduce){.cwb-card{transition:none}}";
|
|
1971
|
+
const tagId = "@cannbot-plugin/cannbot-harness/workbench.css";
|
|
1972
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
1973
|
+
const tag = document.createElement("style");
|
|
1974
|
+
tag.dataset.plugin = "@cannbot-plugin/cannbot-harness";
|
|
1975
|
+
tag.dataset.pluginCss = tagId;
|
|
1976
|
+
tag.textContent = css;
|
|
1977
|
+
document.head.appendChild(tag);
|
|
1978
|
+
}
|
|
1979
|
+
//#endregion
|
|
1980
|
+
//#region src/client/register-workbench.ts
|
|
1981
|
+
/** Optional public-slot integration: older DSH keeps its existing branded conversation. */
|
|
1982
|
+
function registerWorkbench(ctx, selection, content) {
|
|
1983
|
+
const fiber = ctx.inject([
|
|
1984
|
+
"layout",
|
|
1985
|
+
"uiWorkspace",
|
|
1986
|
+
"workspaces"
|
|
1987
|
+
], (scoped) => {
|
|
1988
|
+
if (typeof scoped.uiWorkspace.openSession !== "function" || typeof scoped.sessions.retain !== "function" || typeof scoped.conversation.input.requestDraftInitialization !== "function") return;
|
|
1989
|
+
scoped.effect(() => {
|
|
1990
|
+
const store = createWorkbenchState();
|
|
1991
|
+
const releases = [];
|
|
1992
|
+
for (const [id, library] of [[HOME_PANEL, false], [LIBRARY_PANEL, true]]) {
|
|
1993
|
+
releases.push(injectSlot(scoped, "main", () => scoped.slots.register({
|
|
1994
|
+
name: "main",
|
|
1995
|
+
key: id
|
|
1996
|
+
}, () => (0, react.createElement)(Workbench, {
|
|
1997
|
+
ctx: scoped,
|
|
1998
|
+
selection,
|
|
1999
|
+
content,
|
|
2000
|
+
store,
|
|
2001
|
+
library
|
|
2002
|
+
}))));
|
|
2003
|
+
if (!library) releases.push(injectSlot(scoped, "sidebar.panellist", () => scoped.slots.register({
|
|
2004
|
+
name: "sidebar.panellist",
|
|
2005
|
+
id,
|
|
2006
|
+
order: -100,
|
|
2007
|
+
label: "CANNBot工作台"
|
|
2008
|
+
}, ({ size }) => (0, react.createElement)(WorkbenchIcon, {
|
|
2009
|
+
name: "grid",
|
|
2010
|
+
size
|
|
2011
|
+
}))));
|
|
2012
|
+
}
|
|
2013
|
+
return () => {
|
|
2014
|
+
store.dispose();
|
|
2015
|
+
if (["cannbot-harness-workbench", "cannbot-harness-workflows"].includes(scoped.layout.panelInfo.getSnapshot().activePanelId)) scoped.layout.selectPanel(null);
|
|
2016
|
+
for (const release of releases.reverse()) release();
|
|
2017
|
+
};
|
|
2018
|
+
});
|
|
2019
|
+
});
|
|
2020
|
+
return () => {
|
|
2021
|
+
if (typeof fiber?.dispose === "function") fiber.dispose();
|
|
2022
|
+
};
|
|
2023
|
+
}
|
|
2024
|
+
//#endregion
|
|
1162
2025
|
//#region src/client/index.ts
|
|
1163
2026
|
const inject = [
|
|
1164
2027
|
"slots",
|
|
@@ -1196,7 +2059,8 @@ window.__ModuleLoader__.load({
|
|
|
1196
2059
|
ctx,
|
|
1197
2060
|
selection,
|
|
1198
2061
|
content
|
|
1199
|
-
})))
|
|
2062
|
+
}))),
|
|
2063
|
+
registerWorkbench(ctx, selection, content)
|
|
1200
2064
|
];
|
|
1201
2065
|
return () => {
|
|
1202
2066
|
for (const release of releases.reverse()) release();
|