@cannbot-plugin/cannbot-harness 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  插件详情页提供 **检查更新** 按钮。发现新版后,点击 **更新到版本号**,通过 DSH 官方接口安装,保留当前的长包名或短包名入口。检查本身不会自动安装。
4
4
 
5
- 若当前 DSH 的官方接口要求先卸载,则显示 **下载新版安装包**:先下载文件,再在插件页卸载旧版并添加该文件。首次获得更新按钮需升级到 0.2.2;不修改 DSH 核心。
5
+ 从 **0.2.4** 起支持一键升级:点击“更新到版本号”后由 Host 后台完成。优先调用 DSH 官方更新接口;旧版 DSH 使用官方安装、卸载接口串联事务,保留启用状态及配置,安装失败时尝试恢复原版本。任务不随插件自身卸载或浏览器关闭而取消。首次使用这项能力需安装 0.2.4;不修改 DSH 核心。一键升级依赖 DSH 官方插件管理与认证 Fetch 路由接口,更早版本仍可使用工作流功能。
6
6
 
7
7
  CANNBot Harness 是安装在原版 DeepSeek Harness(DSH)中的独立插件。
8
8
  Windows 桌面端和 Linux Web 端使用同一个 `.tgz` 安装包。
@@ -29,13 +29,13 @@ Windows 桌面端和 Linux Web 端使用同一个 `.tgz` 安装包。
29
29
  Windows 桌面端先正常退出 DSH,再用 DSH 自带的 CLI 安装:
30
30
 
31
31
  ```powershell
32
- dsh plugin --profile desktop add @cannbot-plugin/cannbot-harness@0.2.2
32
+ dsh plugin --profile desktop add @cannbot-plugin/cannbot-harness@0.2.4
33
33
  ```
34
34
 
35
35
  Linux 使用运行 DSH 的同一用户安装,随后启动对应配置:
36
36
 
37
37
  ```bash
38
- dsh plugin --profile web add @cannbot-plugin/cannbot-harness@0.2.2
38
+ dsh plugin --profile web add @cannbot-plugin/cannbot-harness@0.2.4
39
39
  dsh web --no-open
40
40
  ```
41
41
 
@@ -49,12 +49,12 @@ dsh plugin --profile <你的配置名> remove @cannbot/dsh-harness
49
49
 
50
50
  ### Windows 桌面端
51
51
 
52
- 在原版 DSH 的 **插件 → 添加插件** 中安装本地文件 `cannbot-plugin-cannbot-harness-0.2.2.tgz`。
52
+ 在原版 DSH 的 **插件 → 添加插件** 中安装本地文件 `cannbot-plugin-cannbot-harness-0.2.4.tgz`。
53
53
  安装后启用 **CANNBot Harness**。如果当前 DSH 提示需要重启,正常退出并重新打开 DSH。
54
54
  也可先完全退出 DSH,再用 DSH 自带的 CLI:
55
55
 
56
56
  ```powershell
57
- dsh plugin --profile desktop add "C:\Downloads\cannbot-plugin-cannbot-harness-0.2.2.tgz"
57
+ dsh plugin --profile desktop add "C:\Downloads\cannbot-plugin-cannbot-harness-0.2.4.tgz"
58
58
  ```
59
59
 
60
60
  ### Linux 浏览器端
@@ -62,7 +62,7 @@ dsh plugin --profile desktop add "C:\Downloads\cannbot-plugin-cannbot-harness-0.
62
62
  先安装原版 DSH,再将安装包放到服务器上,以运行 DSH 的同一用户执行:
63
63
 
64
64
  ```bash
65
- dsh plugin --profile web add /path/to/cannbot-plugin-cannbot-harness-0.2.2.tgz
65
+ dsh plugin --profile web add /path/to/cannbot-plugin-cannbot-harness-0.2.4.tgz
66
66
  dsh web --no-open
67
67
  ```
68
68
 
package/lib/client.js CHANGED
@@ -35,6 +35,11 @@ window.__ModuleLoader__.load({
35
35
  const NAMESPACE = "cannbotHarness";
36
36
  const PACKAGE = "@cannbot-plugin/cannbot-harness";
37
37
  const zh = {
38
+ updateBackground: "后台正在更新,请勿重复安装。",
39
+ updateRestored: "更新失败,已恢复旧版。",
40
+ updateRepair: "更新和恢复未完成,请在插件页重新安装原版本。",
41
+ updateConnectionLost: "连接中断,后台更新可能仍在进行。请重新打开插件页确认版本,勿重复安装。",
42
+ updateDismiss: "关闭更新提示",
38
43
  updateTitle: "版本更新",
39
44
  updateCurrent: "当前版本",
40
45
  updateCheck: "检查更新",
@@ -66,6 +71,11 @@ window.__ModuleLoader__.load({
66
71
  insertFailed: "工作流设置未保存,请稍后重试。"
67
72
  };
68
73
  const en = {
74
+ updateBackground: "Updating in the background. Do not install again.",
75
+ updateRestored: "Update failed; the previous version was restored.",
76
+ updateRepair: "Update and recovery did not finish. Reinstall the previous version from Plugins.",
77
+ updateConnectionLost: "Connection lost. The Host may still be updating. Reopen Plugins to check the version before retrying.",
78
+ updateDismiss: "Dismiss update notice",
69
79
  updateTitle: "Updates",
70
80
  updateCurrent: "Installed version",
71
81
  updateCheck: "Check for updates",
@@ -231,9 +241,12 @@ window.__ModuleLoader__.load({
231
241
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronIcon, { size: 12 })
232
242
  ]
233
243
  });
234
- const label = (workflow) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
244
+ const label = (workflow) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
235
245
  className: "cannbot-harness-workflow-option",
236
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(workflow.label) })
246
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(workflow.label) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", {
247
+ lang: "en",
248
+ children: workflow.id
249
+ })]
237
250
  });
238
251
  const { Menu, MenuItemButton } = _deepseek_ai_dsh_client_ui_primitives;
239
252
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -750,6 +763,70 @@ window.__ModuleLoader__.load({
750
763
  });
751
764
  }
752
765
  //#endregion
766
+ //#region src/client/host-update.ts
767
+ /** This notice belongs to the in-flight update, so removing the plugin must not remove it. */
768
+ async function updateOnHost(name, version) {
769
+ const words = document.documentElement.lang.startsWith("en") ? en : zh;
770
+ const notice = document.createElement("div");
771
+ notice.setAttribute("role", "status");
772
+ notice.setAttribute("aria-live", "polite");
773
+ notice.dataset.cannbotUpdate = "progress";
774
+ Object.assign(notice.style, {
775
+ position: "fixed",
776
+ bottom: "24px",
777
+ right: "24px",
778
+ zIndex: "2147483647",
779
+ maxWidth: "min(380px, calc(100vw - 48px))",
780
+ padding: "16px",
781
+ borderRadius: "12px",
782
+ background: "var(--dsw-alias-bg-base, white)",
783
+ color: "var(--dsw-alias-label-primary, #222)",
784
+ border: "1px solid var(--dsw-alias-border-l2, #ddd)",
785
+ boxShadow: "0 8px 32px #0002",
786
+ fontSize: "13px",
787
+ lineHeight: "1.6"
788
+ });
789
+ const text = document.createElement("span");
790
+ text.textContent = `${words.updateRunning} ${version} · ${words.updateBackground}`;
791
+ notice.append(text);
792
+ document.body.append(notice);
793
+ try {
794
+ const response = await fetch(new URL("api/cannbot-harness/update", document.baseURI), {
795
+ method: "POST",
796
+ credentials: "same-origin",
797
+ headers: { "content-type": "application/json" },
798
+ body: JSON.stringify({
799
+ name,
800
+ version
801
+ })
802
+ });
803
+ if (!response.ok) throw new Error("Host update unavailable");
804
+ const answer = await response.json();
805
+ if (!answer?.result || typeof answer.result.application !== "string") throw new Error("Invalid update result");
806
+ const succeeded = (result) => !result.error && ["applied", "restart-required"].includes(result.application);
807
+ text.textContent = succeeded(answer.result) ? `${answer.result.application === "restart-required" ? words.updateRestart : words.updateDone} (${version})` : answer.restore ? succeeded(answer.restore) ? words.updateRestored : words.updateRepair : words.updateFailed;
808
+ return answer;
809
+ } catch (error) {
810
+ text.textContent = words.updateConnectionLost;
811
+ throw error;
812
+ } finally {
813
+ const close = document.createElement("button");
814
+ close.type = "button";
815
+ close.textContent = "×";
816
+ close.setAttribute("aria-label", words.updateDismiss);
817
+ Object.assign(close.style, {
818
+ marginLeft: "12px",
819
+ border: "0",
820
+ background: "transparent",
821
+ color: "inherit",
822
+ cursor: "pointer",
823
+ fontSize: "18px"
824
+ });
825
+ close.addEventListener("click", () => notice.remove(), { once: true });
826
+ notice.append(close);
827
+ }
828
+ }
829
+ //#endregion
753
830
  //#region src/client/register-updates.ts
754
831
  /** Optional integration: old DSH versions without a Plugins page keep loading. */
755
832
  function registerPluginUpdates(ctx) {
@@ -759,7 +836,7 @@ window.__ModuleLoader__.load({
759
836
  const updater = createPluginUpdater({
760
837
  list: async () => unwrap(await manager.listBundles()),
761
838
  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, {})) } : {}
839
+ update: updateOnHost
763
840
  }, name);
764
841
  scoped.effect(() => () => updater.dispose());
765
842
  scoped.effect(() => injectSlot(scoped, "plugins.bundle.config", () => scoped.slots.register({
package/lib/client.js.map CHANGED
@@ -1 +1 @@
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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"}
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/host-update.ts","../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 updateBackground: '后台正在更新,请勿重复安装。', updateRestored: '更新失败,已恢复旧版。',\n updateRepair: '更新和恢复未完成,请在插件页重新安装原版本。', updateConnectionLost: '连接中断,后台更新可能仍在进行。请重新打开插件页确认版本,勿重复安装。', updateDismiss: '关闭更新提示',\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 updateBackground: 'Updating in the background. Do not install again.', updateRestored: 'Update failed; the previous version was restored.',\n updateRepair: 'Update and recovery did not finish. Reinstall the previous version from Plugins.', updateConnectionLost: 'Connection lost. The Host may still be updating. Reopen Plugins to check the version before retrying.', updateDismiss: 'Dismiss update notice',\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 <small lang=\"en\">{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 <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 // The Host owns the complete transaction, including self-removal and recovery.\n // Frontend disposal must never cancel an update that already started.\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 type { Change } from './plugin-update.ts'\nimport { en, zh } from './locales.ts'\n\n/** This notice belongs to the in-flight update, so removing the plugin must not remove it. */\nexport async function updateOnHost(name: string, version: string): Promise<{ result: Change; restore?: Change }> {\n const words = document.documentElement.lang.startsWith('en') ? en : zh\n const notice = document.createElement('div')\n notice.setAttribute('role', 'status')\n notice.setAttribute('aria-live', 'polite')\n notice.dataset.cannbotUpdate = 'progress'\n Object.assign(notice.style, { position: 'fixed', bottom: '24px', right: '24px', zIndex: '2147483647',\n maxWidth: 'min(380px, calc(100vw - 48px))', padding: '16px', borderRadius: '12px',\n background: 'var(--dsw-alias-bg-base, white)', color: 'var(--dsw-alias-label-primary, #222)',\n border: '1px solid var(--dsw-alias-border-l2, #ddd)', boxShadow: '0 8px 32px #0002', fontSize: '13px', lineHeight: '1.6' })\n const text = document.createElement('span')\n text.textContent = `${words.updateRunning} ${version} · ${words.updateBackground}`\n notice.append(text)\n document.body.append(notice)\n try {\n const response = await fetch(new URL('api/cannbot-harness/update', document.baseURI), {\n method: 'POST', credentials: 'same-origin', headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ name, version }),\n // No plugin-lifetime abort: its own uninstall is expected during the transaction.\n })\n if (!response.ok) throw new Error('Host update unavailable')\n const answer = await response.json() as { result: Change; restore?: Change }\n if (!answer?.result || typeof answer.result.application !== 'string') throw new Error('Invalid update result')\n const succeeded = (result: Change) => !result.error && ['applied', 'restart-required'].includes(result.application)\n text.textContent = succeeded(answer.result)\n ? `${answer.result.application === 'restart-required' ? words.updateRestart : words.updateDone} (${version})`\n : answer.restore ? succeeded(answer.restore) ? words.updateRestored : words.updateRepair : words.updateFailed\n return answer\n } catch (error) {\n text.textContent = words.updateConnectionLost\n throw error\n } finally {\n const close = document.createElement('button')\n close.type = 'button'; close.textContent = '×'; close.setAttribute('aria-label', words.updateDismiss)\n Object.assign(close.style, { marginLeft: '12px', border: '0', background: 'transparent', color: 'inherit', cursor: 'pointer', fontSize: '18px' })\n close.addEventListener('click', () => notice.remove(), { once: true })\n notice.append(close)\n }\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'\nimport { updateOnHost } from './host-update.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 update: updateOnHost,\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
@@ -106,9 +106,117 @@ function installWorkflowContext(ctx, config) {
106
106
  });
107
107
  }
108
108
  //#endregion
109
+ //#region src/client/plugin-update.ts
110
+ const UPDATE_PACKAGES = ["cannbot-harness", "@cannbot-plugin/cannbot-harness"];
111
+ /** Only stable npm releases of our two installation entries may be selected. */
112
+ function newerVersion(candidate, current) {
113
+ const next = /^(\d+)\.(\d+)\.(\d+)$/.exec(candidate);
114
+ const old = /^(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(current);
115
+ if (!next || !old) return false;
116
+ for (let index = 1; index < 4; index++) {
117
+ const difference = Number(next[index]) - Number(old[index]);
118
+ if (difference) return difference > 0;
119
+ }
120
+ return current.includes("-");
121
+ }
122
+ //#endregion
123
+ //#region src/update-host.ts
124
+ const UPDATE_PATH = "/api/cannbot-harness/update";
125
+ const registry = "https://registry.npmjs.org/";
126
+ const ok = (change) => ["applied", "restart-required"].includes(change.application) && !change.error;
127
+ const failure = (code = "operation-error") => ({
128
+ application: "failed",
129
+ error: { code }
130
+ });
131
+ const settled = async (action) => {
132
+ try {
133
+ return await action();
134
+ } catch {
135
+ return failure();
136
+ }
137
+ };
138
+ async function publishedTarget(name, version) {
139
+ const response = await fetch(`${registry}${encodeURIComponent(name)}/${version}`, {
140
+ signal: AbortSignal.timeout(3e4),
141
+ cache: "no-store"
142
+ });
143
+ if (!response.ok) return false;
144
+ const manifest = await response.json();
145
+ if (manifest.name !== name || manifest.version !== version || !manifest.dsh?.bundle || !manifest.dist?.integrity || !manifest.dist.tarball) return false;
146
+ const tarball = new URL(manifest.dist.tarball);
147
+ return tarball.protocol === "https:" && tarball.hostname === "registry.npmjs.org";
148
+ }
149
+ /** One Host-owned transaction. Unloading this plugin withdraws its route, not this in-flight task. */
150
+ function createHostUpdater(manager, lookup = publishedTarget) {
151
+ let running = false;
152
+ return async (name, version) => {
153
+ if (!UPDATE_PACKAGES.includes(name) || !/^\d+\.\d+\.\d+$/.test(version)) return { result: failure("invalid-spec") };
154
+ if (running) return { result: failure("update-in-progress") };
155
+ running = true;
156
+ try {
157
+ const bundle = (await manager.listBundles()).find((item) => item.name === name && item.installed);
158
+ if (!bundle?.version || !newerVersion(version, bundle.version)) return { result: failure("invalid-spec") };
159
+ if (typeof manager.updateBundle === "function") return await manager.updateBundle(name, version, { registry });
160
+ if (bundle.removable !== true) return { result: failure("not-removable") };
161
+ if (!await lookup(name, version)) return { result: failure("invalid-spec") };
162
+ const install = (value) => settled(() => manager.installBundle(`${name}@${value}`, {
163
+ saveExact: true,
164
+ enabled: bundle.enabled,
165
+ registry
166
+ }));
167
+ const direct = await install(version);
168
+ if (ok(direct) || direct.error?.code !== "already-installed") return { result: direct };
169
+ const removed = await settled(() => manager.removeBundle(name));
170
+ if (!ok(removed)) return { result: removed };
171
+ const result = await install(version);
172
+ if (ok(result)) return { result };
173
+ let installed = true;
174
+ try {
175
+ installed = (await manager.listBundles()).some((item) => item.name === name && item.installed);
176
+ } catch {}
177
+ if (installed) {
178
+ const cleanup = await settled(() => manager.removeBundle(name));
179
+ if (!ok(cleanup) && cleanup.error?.code !== "not-removable") return {
180
+ result,
181
+ restore: cleanup
182
+ };
183
+ }
184
+ return {
185
+ result,
186
+ restore: await install(bundle.version)
187
+ };
188
+ } catch {
189
+ return { result: failure() };
190
+ } finally {
191
+ running = false;
192
+ }
193
+ };
194
+ }
195
+ function registerHostUpdater(ctx) {
196
+ ctx.inject(["connection", "pluginManager"], (scoped) => {
197
+ if (typeof scoped.connection.fetch?.register !== "function") return;
198
+ const update = createHostUpdater(scoped.pluginManager);
199
+ scoped.connection.fetch.register({
200
+ path: UPDATE_PATH,
201
+ methods: ["POST"],
202
+ requestBody: "buffered",
203
+ async fetch(request) {
204
+ try {
205
+ const body = await request.json();
206
+ if (!body || typeof body !== "object" || !("name" in body) || !("version" in body) || typeof body.name !== "string" || typeof body.version !== "string") return Response.json({ error: "invalid-request" }, { status: 400 });
207
+ return Response.json(await update(body.name, body.version), { headers: { "cache-control": "no-store" } });
208
+ } catch {
209
+ return Response.json({ error: "update-failed" }, { status: 500 });
210
+ }
211
+ }
212
+ });
213
+ });
214
+ }
215
+ //#endregion
109
216
  //#region src/index.ts
110
217
  const inject = ["skills"];
111
218
  function apply(ctx, config = {}) {
219
+ registerHostUpdater(ctx);
112
220
  installWorkflowContext(ctx, config);
113
221
  const base = new URL("../assets/official/", import.meta.url);
114
222
  const catalog = JSON.parse(readFileSync(new URL("catalog.json", base), "utf8"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cannbot-plugin/cannbot-harness",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
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",