@lemoncat7/dsh-partner 2.7.1 → 2.7.3

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
@@ -1,6 +1,6 @@
1
1
  # DSH Partner
2
2
 
3
- > 当前正式版 **2.7.1**,适配并验证 **DSH 0.1.7-rc.2**。插件为正式版,宿主仍为 RC;不支持直接用于旧宿主。Node.js **^22.19.0 或 >=24.0.0**。旧版源码保留于 `pre-dsh-0.1.7-rc.2`;详见 [2.7.1 发布说明](docs/releases/2.7.1.md)。
3
+ > 当前版本 **2.7.3**,已验证宿主 **DSH 0.2.0-rc.2**(宿主仍为 RC)。Node.js **^22.19.0 或 >=24.0.0**。详见 [兼容说明](docs/dsh-020-compatibility.md) 和 [发布说明](docs/releases/2.7.3.md)。
4
4
 
5
5
  面向 DeepSeek Harness 的长期 AI 伙伴与多渠道插件。
6
6
 
@@ -0,0 +1,11 @@
1
+ # DSH 0.2.0-rc.2 兼容说明
2
+
3
+ 本次发布版本:2.7.3,适配 DSH 0.2.0-rc.2。此前 2.7.2 安装包不因此获得新宿主兼容声明。
4
+
5
+ - 已验证宿主:DSH 0.2.0-rc.2;Node.js ^22.19.0 或 >=24.0.0。
6
+ - 宿主版本依赖已更新;知识库和主题补充了可供安装器识别的 DSH peerDependencies,不再仅依赖 README 描述。
7
+ - 七个插件合计 1,213 项测试通过,1 项原有跳过;隔离宿主验证召回、回写、伙伴次轮权限、配置保存及重启持久化,浏览器错误为 0。
8
+ - 工作区已检查桌面、390px 手机和 1024px 平板宽度;Desktop Origin 检查不等同于完整 Windows/macOS 客户端端到端测试。
9
+ - 未触发真实渠道消息、付费模型生成或远程 SSH 操作;不保证所有外部服务兼容。
10
+ - 新兼容构建面向 DSH 0.2.0,不应直接覆盖旧宿主安装。升级时保留旧宿主镜像、配置和数据卷,回退须使用配套备份。
11
+ - 不修改 DSH 核心源码;原有功能和数据保留。
@@ -0,0 +1,12 @@
1
+ # 2.7.2 · 任务清理与功能页响应优化
2
+
3
+ 正式补丁版本,适配并验证 **DSH 0.1.7-rc.2**。Node.js **^22.19.0 或 >=24.0.0**。
4
+
5
+ - 看板受阻任务继续采用安全恢复语义:暂时性执行故障进入自动重试;需要重新规划的任务不会原样循环执行,解决权限、工具或分工问题后可由负责人恢复。
6
+ - 已完成或取消的一次性续接不再占用计划列表。独立任务在最终回复可靠送达后删除持久记录;看板任务在恢复执行消费完结果后删除,避免丢失通知或误判任务中断。
7
+ - 伙伴能力页不再预取三份资源目录;Skill 市场的本地安装列表、远程市场和网络设置独立加载,远程来源缓慢或失败不再阻塞本地内容。
8
+ - 设置页“升级迁移”区域压缩段落、详情和路径卡片留白,保留 44px 操作区域与完整说明文字。
9
+
10
+ Node 24 完成 622 项全量测试;其中 619 项在高并发全量运行中直接通过,3 项既有等待时序用例在资源竞争下超时,隔离重跑均通过。新增的一次性清理、续接可靠投递、请求解耦和紧凑布局测试全部通过。
11
+
12
+ 本版本不改变存储 schema。升级前仍建议备份插件数据目录;可回退到 2.7.1,尚未安全消费的续接记录会继续保留。
@@ -0,0 +1,6 @@
1
+ # 2.7.3 · DSH 0.2.0-rc.2 兼容发布
2
+
3
+ - 更新宿主依赖与兼容声明,配套 DSH **0.2.0-rc.2**;需要 Node.js **^22.19.0 或 >=24.0.0**。
4
+ - 保留现有功能;未修改 DSH 核心源码。
5
+ - 已完成七插件回归及隔离宿主验证,正式环境工作区、设置接口验收通过。范围与限制见 [兼容说明](../dsh-020-compatibility.md)。
6
+ - 宿主仍处于 RC。旧宿主请保留 **2.7.2** 和配套数据备份,升级前备份配置与数据。
package/lib/client.js CHANGED
@@ -1803,8 +1803,12 @@ body[data-ds-dark-theme] .dsh-partner-workspace {
1803
1803
  .dsh-partner-general-settings { padding: 16px clamp(20px, 4vw, 46px); color: var(--partner-text); }
1804
1804
  .dsh-partner-general-settings h2 { font-size: 18px; }
1805
1805
  .dsh-partner-general-settings p { color: var(--partner-text-secondary); line-height: 1.7; overflow-wrap: anywhere; }
1806
- .dsh-partner-migration-paths { display: grid; gap: 12px; margin-top: 12px; min-width: 0; }
1807
- .dsh-partner-migration-paths > div { display: grid; gap: 5px; padding: 12px; border: 1px solid var(--partner-border); border-radius: 10px; min-width: 0; }
1806
+ .dsh-partner-feature-block.is-storage-migration { gap: 10px; padding: 16px 18px; }
1807
+ .dsh-partner-feature-block.is-storage-migration > :is(p, details) { margin-block: 0; }
1808
+ .dsh-partner-feature-block.is-storage-migration p { margin-block: 0; line-height: 1.55; }
1809
+ .dsh-partner-feature-block.is-storage-migration details > p { margin-top: 6px; }
1810
+ .dsh-partner-migration-paths { display: grid; gap: 8px; margin-top: 6px; min-width: 0; }
1811
+ .dsh-partner-migration-paths > div { display: grid; gap: 3px; padding: 10px; border: 1px solid var(--partner-border); border-radius: 10px; min-width: 0; }
1808
1812
  .dsh-partner-migration-paths code { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 12px; }
1809
1813
  .dsh-partner-general-settings :is(summary,button) { min-height: 44px; }
1810
1814
  .dsh-partner-general-settings [role="alert"] { color: var(--partner-danger); overflow-wrap: anywhere; }
@@ -13461,8 +13465,12 @@ function SkillsPanel() {
13461
13465
  const [query, setQuery] = (0, import_react30.useState)("");
13462
13466
  const [activeSource, setActiveSource] = (0, import_react30.useState)("market-clawhub");
13463
13467
  const [busy, setBusy] = (0, import_react30.useState)();
13464
- const [loading, setLoading] = (0, import_react30.useState)(true);
13465
- const [error, setError] = (0, import_react30.useState)();
13468
+ const [catalogLoading, setCatalogLoading] = (0, import_react30.useState)(true);
13469
+ const [marketLoading, setMarketLoading] = (0, import_react30.useState)(true);
13470
+ const [networkLoading, setNetworkLoading] = (0, import_react30.useState)(true);
13471
+ const [catalogError, setCatalogError] = (0, import_react30.useState)();
13472
+ const [marketError, setMarketError] = (0, import_react30.useState)();
13473
+ const [networkError, setNetworkError] = (0, import_react30.useState)();
13466
13474
  const [actionError, setActionError] = (0, import_react30.useState)();
13467
13475
  const [addingSource, setAddingSource] = (0, import_react30.useState)(false);
13468
13476
  const [creatingSkill, setCreatingSkill] = (0, import_react30.useState)(false);
@@ -13470,26 +13478,46 @@ function SkillsPanel() {
13470
13478
  const [editingNetwork, setEditingNetwork] = (0, import_react30.useState)(false);
13471
13479
  const [showAllInstalled, setShowAllInstalled] = (0, import_react30.useState)(false);
13472
13480
  const [network, setNetwork] = (0, import_react30.useState)({});
13473
- const load2 = (0, import_react30.useCallback)(async (refresh = false) => {
13481
+ const loadCatalog = (0, import_react30.useCallback)(async () => {
13482
+ setCatalogLoading(true);
13474
13483
  try {
13475
- const [nextCatalog, nextMarket, nextNetwork] = await Promise.all([
13476
- api("/skills"),
13477
- api(`/skills/market${refresh ? "?refresh=1" : ""}`),
13478
- api("/skill-markets/network")
13479
- ]);
13480
- setCatalog(nextCatalog);
13481
- setMarket(nextMarket);
13482
- setNetwork(nextNetwork);
13483
- setError(void 0);
13484
+ setCatalog(await api("/skills"));
13485
+ setCatalogError(void 0);
13484
13486
  } catch (reason) {
13485
- setError(errorMessage(reason));
13487
+ setCatalogError(errorMessage(reason));
13486
13488
  } finally {
13487
- setLoading(false);
13489
+ setCatalogLoading(false);
13488
13490
  }
13489
13491
  }, []);
13492
+ const loadMarket = (0, import_react30.useCallback)(async (refresh = false) => {
13493
+ setMarketLoading(true);
13494
+ try {
13495
+ setMarket(await api(`/skills/market${refresh ? "?refresh=1" : ""}`));
13496
+ setMarketError(void 0);
13497
+ } catch (reason) {
13498
+ setMarketError(errorMessage(reason));
13499
+ } finally {
13500
+ setMarketLoading(false);
13501
+ }
13502
+ }, []);
13503
+ const loadNetwork = (0, import_react30.useCallback)(async () => {
13504
+ setNetworkLoading(true);
13505
+ try {
13506
+ setNetwork(await api("/skill-markets/network"));
13507
+ setNetworkError(void 0);
13508
+ } catch (reason) {
13509
+ setNetworkError(errorMessage(reason));
13510
+ } finally {
13511
+ setNetworkLoading(false);
13512
+ }
13513
+ }, []);
13514
+ const load2 = (0, import_react30.useCallback)(async (refresh = false) => {
13515
+ await Promise.all([loadCatalog(), loadMarket(refresh), loadNetwork()]);
13516
+ }, [loadCatalog, loadMarket, loadNetwork]);
13490
13517
  (0, import_react30.useEffect)(() => {
13491
13518
  void load2();
13492
13519
  }, [load2]);
13520
+ const loading = catalogLoading || marketLoading || networkLoading;
13493
13521
  const installed = new Map(catalog.installed.map((item) => [item.id, item]));
13494
13522
  const visibleInstalled = showAllInstalled ? catalog.installed : catalog.installed.slice(0, 4);
13495
13523
  const visible = (0, import_react30.useMemo)(() => {
@@ -13506,7 +13534,7 @@ function SkillsPanel() {
13506
13534
  setActionError(void 0);
13507
13535
  try {
13508
13536
  await api("/skills/market/install", { method: "POST", body: JSON.stringify({ sourceId: entry.sourceId, entryId: entry.id }) });
13509
- await load2();
13537
+ await loadCatalog();
13510
13538
  } catch (reason) {
13511
13539
  setActionError({ kind: "install", id: entry.id, message: errorMessage(reason) });
13512
13540
  } finally {
@@ -13518,7 +13546,7 @@ function SkillsPanel() {
13518
13546
  setActionError(void 0);
13519
13547
  try {
13520
13548
  await api(`/skills/${encodeURIComponent(id)}`, { method: "DELETE" });
13521
- await load2();
13549
+ await loadCatalog();
13522
13550
  } catch (reason) {
13523
13551
  setActionError({ kind: "uninstall", id, message: errorMessage(reason) });
13524
13552
  } finally {
@@ -13532,12 +13560,23 @@ function SkillsPanel() {
13532
13560
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_dsh_client_ui_primitives11.IconRefreshOutlineRegular, { size: 15 }),
13533
13561
  loading ? "\u540C\u6B65\u4E2D\u2026" : "\u5237\u65B0\u5E02\u573A"
13534
13562
  ] }) }),
13535
- error && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(WorkspaceNotice, { children: error }),
13536
- importingSkill && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SkillImportDialog, { close: () => setImportingSkill(false), changed: load2 }),
13537
- creatingSkill && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(WorkspaceDialog, { title: "\u65B0\u5EFA Skill", detail: "\u521B\u5EFA\u4E00\u4E2A\u53EF\u590D\u7528\u7684\u5DE5\u4F5C\u6D41\u7A0B\uFF0C\u5E76\u660E\u786E\u6267\u884C\u4E0A\u4E0B\u6587\u3001\u5DE5\u5177\u8FB9\u754C\u548C\u9A8C\u6536\u6307\u4EE4\u3002", close: () => setCreatingSkill(false), width: "wide", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NewSkillForm, { existingIds: catalog.installed.map((skill) => skill.id), close: () => setCreatingSkill(false), changed: load2 }) }),
13563
+ catalogError && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(WorkspaceNotice, { children: [
13564
+ "\u5DF2\u5B89\u88C5 Skill \u8BFB\u53D6\u5931\u8D25\uFF1A",
13565
+ catalogError
13566
+ ] }),
13567
+ marketError && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(WorkspaceNotice, { children: [
13568
+ "\u5E02\u573A\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF1A",
13569
+ marketError
13570
+ ] }),
13571
+ networkError && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(WorkspaceNotice, { children: [
13572
+ "\u5E02\u573A\u7F51\u7EDC\u8BBE\u7F6E\u8BFB\u53D6\u5931\u8D25\uFF1A",
13573
+ networkError
13574
+ ] }),
13575
+ importingSkill && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SkillImportDialog, { close: () => setImportingSkill(false), changed: loadCatalog }),
13576
+ creatingSkill && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(WorkspaceDialog, { title: "\u65B0\u5EFA Skill", detail: "\u521B\u5EFA\u4E00\u4E2A\u53EF\u590D\u7528\u7684\u5DE5\u4F5C\u6D41\u7A0B\uFF0C\u5E76\u660E\u786E\u6267\u884C\u4E0A\u4E0B\u6587\u3001\u5DE5\u5177\u8FB9\u754C\u548C\u9A8C\u6536\u6307\u4EE4\u3002", close: () => setCreatingSkill(false), width: "wide", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NewSkillForm, { existingIds: catalog.installed.map((skill) => skill.id), close: () => setCreatingSkill(false), changed: loadCatalog }) }),
13538
13577
  editingNetwork && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(WorkspaceDialog, { title: "\u5E02\u573A\u7F51\u7EDC\u8BBE\u7F6E", detail: "\u914D\u7F6E Skill \u7D22\u5F15\u548C\u5B89\u88C5\u5305\u4E0B\u8F7D\u5171\u7528\u7684 HTTP \u4EE3\u7406\uFF0C\u5E76\u5728\u4FDD\u5B58\u524D\u6D4B\u8BD5\u8FDE\u901A\u6027\u3002", close: () => setEditingNetwork(false), children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(NetworkSettingsForm, { value: network, close: () => setEditingNetwork(false), changed: async (next) => {
13539
13578
  setNetwork(next);
13540
- await load2(true);
13579
+ await loadMarket(true);
13541
13580
  } }) }),
13542
13581
  addingSource && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(WorkspaceDialog, { title: "\u6DFB\u52A0\u5E02\u573A\u6765\u6E90", detail: "\u63A5\u5165\u56E2\u961F\u6216\u4E2A\u4EBA\u7EF4\u62A4\u7684 Skill \u7D22\u5F15\u3002\u81EA\u5B9A\u4E49\u6765\u6E90\u9ED8\u8BA4\u6309\u4E0D\u53EF\u4FE1\u6765\u6E90\u9694\u79BB\u6267\u884C\u3002", close: () => setAddingSource(false), children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(MarketSourceForm, { close: () => setAddingSource(false), changed: () => load2(true) }) }),
13543
13582
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(WorkspaceBlock, { title: "\u5DF2\u5B89\u88C5", detail: `${catalog.installed.length} \u4E2A\u53EF\u4F9B\u4F19\u4F34\u4F7F\u7528`, actions: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
@@ -13546,7 +13585,7 @@ function SkillsPanel() {
13546
13585
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_dsh_client_ui_primitives11.IconPlusOutlineRegular, { size: 14 }),
13547
13586
  "\u65B0\u5EFA Skill"
13548
13587
  ] })
13549
- ] }), children: loading ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CollectionSkeleton, { rows: 2 }) : catalog.installed.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CollectionEmpty, { title: "\u8FD8\u6CA1\u6709\u5B89\u88C5 Skill", detail: "\u53EF\u4EE5\u521B\u5EFA\u81EA\u5DF1\u7684 Skill\uFF0C\u6216\u4ECE\u4E0B\u65B9\u5E02\u573A\u9009\u62E9\u3002", action: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("button", { type: "button", onClick: () => setCreatingSkill(true), children: [
13588
+ ] }), children: catalogLoading ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CollectionSkeleton, { rows: 2 }) : catalog.installed.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CollectionEmpty, { title: "\u8FD8\u6CA1\u6709\u5B89\u88C5 Skill", detail: "\u53EF\u4EE5\u521B\u5EFA\u81EA\u5DF1\u7684 Skill\uFF0C\u6216\u4ECE\u4E0B\u65B9\u5E02\u573A\u9009\u62E9\u3002", action: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("button", { type: "button", onClick: () => setCreatingSkill(true), children: [
13550
13589
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_dsh_client_ui_primitives11.IconPlusOutlineRegular, { size: 14 }),
13551
13590
  "\u65B0\u5EFA\u7B2C\u4E00\u4E2A Skill"
13552
13591
  ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
@@ -13584,14 +13623,14 @@ function SkillsPanel() {
13584
13623
  ] })
13585
13624
  ] }), children: [
13586
13625
  /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "dsh-partner-market-toolbar", children: [
13587
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SkillSearch, { value: query, change: setQuery, count: visible.length, label: "\u641C\u7D22 Skill \u5E02\u573A", placeholder: "\u641C\u7D22\u540D\u79F0\u3001\u8BF4\u660E\u6216\u6807\u7B7E", loading }),
13626
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(SkillSearch, { value: query, change: setQuery, count: visible.length, label: "\u641C\u7D22 Skill \u5E02\u573A", placeholder: "\u641C\u7D22\u540D\u79F0\u3001\u8BF4\u660E\u6216\u6807\u7B7E", loading: marketLoading }),
13588
13627
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("nav", { className: "dsh-partner-market-sources", "aria-label": "Skill \u5E02\u573A\u6765\u6E90", children: sources.map((source) => /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("button", { type: "button", className: activeSource === source.id ? "is-active" : "", "aria-pressed": activeSource === source.id, onClick: () => setActiveSource(source.id), children: [
13589
13628
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { children: source.name }),
13590
13629
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("small", { children: sourceCounts.get(source.id) ?? 0 })
13591
13630
  ] }, source.id)) })
13592
13631
  ] }),
13593
13632
  market.errors.some((item) => item.sourceId === activeSource) && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("p", { className: "dsh-partner-inline-warning", children: market.errors.filter((item) => item.sourceId === activeSource).map((item) => item.error).join("\uFF1B") }),
13594
- loading ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CollectionSkeleton, { rows: 4 }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "dsh-partner-market-grid", children: visible.map((entry) => {
13633
+ marketLoading ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CollectionSkeleton, { rows: 4 }) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "dsh-partner-market-grid", children: visible.map((entry) => {
13595
13634
  const current2 = installed.get(entry.id);
13596
13635
  const cardError = actionError?.kind === "install" && actionError.id === entry.id ? actionError.message : void 0;
13597
13636
  const errorId = cardError ? `dsh-partner-skill-error-${entry.id}` : void 0;
@@ -13619,7 +13658,7 @@ function SkillsPanel() {
13619
13658
  ] })
13620
13659
  ] }, `${entry.sourceId}:${entry.id}`);
13621
13660
  }) }),
13622
- !loading && visible.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CollectionEmpty, { title: query ? "\u6CA1\u6709\u5339\u914D\u7684 Skill" : "\u5F53\u524D\u6765\u6E90\u6682\u65F6\u4E0D\u53EF\u7528", detail: query ? "\u6362\u4E00\u4E2A\u5173\u952E\u8BCD\uFF0C\u6216\u5207\u6362\u5E02\u573A\u6765\u6E90\u3002" : "\u5237\u65B0\u5E02\u573A\uFF0C\u6216\u68C0\u67E5\u4EE3\u7406\u4E0E\u6765\u6E90\u914D\u7F6E\u3002" })
13661
+ !marketLoading && visible.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(CollectionEmpty, { title: query ? "\u6CA1\u6709\u5339\u914D\u7684 Skill" : "\u5F53\u524D\u6765\u6E90\u6682\u65F6\u4E0D\u53EF\u7528", detail: query ? "\u6362\u4E00\u4E2A\u5173\u952E\u8BCD\uFF0C\u6216\u5207\u6362\u5E02\u573A\u6765\u6E90\u3002" : "\u5237\u65B0\u5E02\u573A\uFF0C\u6216\u68C0\u67E5\u4EE3\u7406\u4E0E\u6765\u6E90\u914D\u7F6E\u3002" })
13623
13662
  ] })
13624
13663
  ] });
13625
13664
  }
@@ -15241,6 +15280,7 @@ function SchedulePanel({ companions }) {
15241
15280
  const [loading, setLoading] = (0, import_react38.useState)(true);
15242
15281
  const [error, setError] = (0, import_react38.useState)();
15243
15282
  const eligible = companions.filter((c) => c.capabilities.includes("schedules"));
15283
+ const visibleSchedules = schedules.filter((item) => item.schedule.kind !== "once" || !item.continuation || !["completed", "cancelled"].includes(item.continuation.state));
15244
15284
  const load2 = (0, import_react38.useCallback)(async () => {
15245
15285
  try {
15246
15286
  const value = await api("/schedules");
@@ -15316,10 +15356,10 @@ function SchedulePanel({ companions }) {
15316
15356
  eligible.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(WorkspaceNotice, { children: "\u8BF7\u5148\u5728\u4F19\u4F34\u80FD\u529B\u4E2D\u52FE\u9009\u201C\u5B9A\u65F6\u4EFB\u52A1\u201D\u3002\u5173\u95ED\u80FD\u529B\u540E\uFF0C\u5DF2\u6709\u8BA1\u5212\u4E0D\u4F1A\u7EE7\u7EED\u6267\u884C\u3002" }),
15317
15357
  error && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(WorkspaceNotice, { children: error }),
15318
15358
  creating && /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(WorkspaceDialog, { title: "\u65B0\u5EFA\u5B9A\u65F6\u4EFB\u52A1", detail: "\u9009\u62E9\u6267\u884C\u4F19\u4F34\u3001\u8FD0\u884C\u9891\u7387\u548C\u4F1A\u8BDD\u4FDD\u7559\u7B56\u7565\u3002\u957F\u4EFB\u52A1\u7EED\u63A5\u7531\u4F19\u4F34\u901A\u8FC7\u5DE5\u5177\u9884\u7EA6\uFF0C\u65E0\u9700\u5728\u8FD9\u91CC\u624B\u52A8\u521B\u5EFA\u3002", close: () => setCreating(false), width: "wide", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(ScheduleForm, { companions: eligible, close: () => setCreating(false), changed: load2 }) }),
15319
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(WorkspaceBlock, { title: "\u6267\u884C\u8BA1\u5212", detail: `${schedules.filter((item) => item.enabled && eligible.some((c) => c.id === item.companionId)).length} \u4E2A\u542F\u7528`, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(CollectionSkeleton, { rows: 3 }) : schedules.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(CollectionEmpty, { title: "\u8FD8\u6CA1\u6709\u5B9A\u65F6\u4EFB\u52A1", detail: "\u5468\u671F\u8BA1\u5212\u548C\u957F\u4EFB\u52A1\u7EED\u63A5\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002", action: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("button", { type: "button", disabled: eligible.length === 0, onClick: () => setCreating(true), children: [
15359
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(WorkspaceBlock, { title: "\u6267\u884C\u8BA1\u5212", detail: `${visibleSchedules.filter((item) => item.enabled && eligible.some((c) => c.id === item.companionId)).length} \u4E2A\u542F\u7528`, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(CollectionSkeleton, { rows: 3 }) : visibleSchedules.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(CollectionEmpty, { title: "\u8FD8\u6CA1\u6709\u5B9A\u65F6\u4EFB\u52A1", detail: "\u5468\u671F\u8BA1\u5212\u548C\u7B49\u5F85\u5904\u7406\u7684\u957F\u4EFB\u52A1\u7EED\u63A5\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002", action: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("button", { type: "button", disabled: eligible.length === 0, onClick: () => setCreating(true), children: [
15320
15360
  /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_dsh_client_ui_primitives17.IconPlusOutlineRegular, { size: 14 }),
15321
15361
  "\u521B\u5EFA\u7B2C\u4E00\u4E2A\u8BA1\u5212"
15322
- ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "dsh-partner-schedule-list", children: schedules.map((entry) => {
15362
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { className: "dsh-partner-schedule-list", children: visibleSchedules.map((entry) => {
15323
15363
  const wake = entry.continuation, allowed = eligible.some((c) => c.id === entry.companionId);
15324
15364
  const terminal = wake && ["completed", "blocked", "cancelled"].includes(wake.state);
15325
15365
  return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("article", { children: [
@@ -15705,47 +15745,16 @@ var titles = { skills: "Skill", access: "\u53EF\u8BBF\u95EE\u4F19\u4F34", mcp: "
15705
15745
  function CapabilityResources({ companionId, capabilities, disabled, children }) {
15706
15746
  const [opened, setOpened] = (0, import_react41.useState)();
15707
15747
  const [busy, setBusy] = (0, import_react41.useState)(false);
15708
- const [revision, setRevision] = (0, import_react41.useState)(0);
15709
- const [counts, setCounts] = (0, import_react41.useState)({});
15710
- const [failed, setFailed] = (0, import_react41.useState)(false);
15711
- (0, import_react41.useEffect)(() => {
15712
- let live = true;
15713
- setFailed(false);
15714
- const requests = [
15715
- ["access", api(`/companions/${encodeURIComponent(companionId)}/access`).then((v) => v.targetIds.length)]
15716
- ];
15717
- if (capabilities.includes("skills")) requests.push(["skills", api("/skills").then((v) => v.installed.filter((s) => v.bindings.some((b) => b.companionId === companionId && b.skillId === s.id && b.enabled)).length)]);
15718
- if (capabilities.includes("mcp")) requests.push(["mcp", api("/mcp").then((v) => v.servers.filter((s) => v.bindings.some((b) => b.companionId === companionId && b.serverId === s.id)).length)]);
15719
- for (const [key, request] of requests) void request.then((count) => {
15720
- if (live) setCounts((v) => ({ ...v, [key]: count }));
15721
- }).catch(() => {
15722
- if (live) {
15723
- setCounts((v) => ({ ...v, [key]: void 0 }));
15724
- setFailed(true);
15725
- }
15726
- });
15727
- return () => {
15728
- live = false;
15729
- };
15730
- }, [companionId, capabilities, revision]);
15731
15748
  const close = () => {
15732
15749
  if (busy) return;
15733
15750
  setOpened(void 0);
15734
- setRevision((v) => v + 1);
15735
15751
  };
15736
- const manage = (key) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("button", { className: "dsh-partner-capability-manage", type: "button", disabled: disabled || key !== "access" && !capabilities.includes(key), "aria-haspopup": "dialog", "aria-label": `\u7BA1\u7406${titles[key]}`, onClick: () => {
15752
+ const manage = (key) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("button", { className: "dsh-partner-capability-manage", type: "button", disabled: disabled || key !== "access" && !capabilities.includes(key), "aria-haspopup": "dialog", "aria-label": `\u7BA1\u7406${titles[key]}`, onClick: () => {
15737
15753
  setBusy(false);
15738
15754
  setOpened(key);
15739
- }, children: [
15740
- "\u7BA1\u7406",
15741
- counts[key] !== void 0 ? ` \xB7 ${counts[key]}` : ""
15742
- ] });
15755
+ }, children: "\u7BA1\u7406" });
15743
15756
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
15744
15757
  children(manage),
15745
- failed && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("p", { className: "dsh-partner-inline-note", children: [
15746
- "\u90E8\u5206\u6570\u91CF\u8BFB\u53D6\u5931\u8D25\uFF0C\u53EF\u6253\u5F00\u7BA1\u7406\u91CD\u8BD5\u3002",
15747
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("button", { type: "button", onClick: () => setRevision((v) => v + 1), children: "\u5237\u65B0\u6570\u91CF" })
15748
- ] }),
15749
15758
  opened && /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(WorkspaceDialog, { className: "is-capability-resources", eyebrow: "", title: `\u7BA1\u7406${titles[opened]}`, detail: opened === "access" ? "\u9009\u62E9\u6B64\u4F19\u4F34\u53EF\u4EE5\u8BBF\u95EE\u548C\u59D4\u6D3E\u7684\u4F19\u4F34\uFF0C\u5355\u5411\u6388\u6743\u3002" : "\u9009\u62E9\u9700\u8981\u542F\u7528\u7684\u80FD\u529B\uFF0C\u4FEE\u6539\u81EA\u52A8\u4FDD\u5B58\uFF0C\u4E0B\u4E00\u8F6E\u751F\u6548\u3002", close, children: [
15750
15759
  busy && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { role: "status", className: "dsh-partner-inline-note", children: "\u6B63\u5728\u4FDD\u5B58\uFF0C\u8BF7\u7A0D\u5019\u2026" }),
15751
15760
  opened === "skills" && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(CompanionSkillSettings, { companionId, onBusyChange: setBusy }),
@@ -16974,7 +16983,7 @@ function GeneralSettingsPanel() {
16974
16983
  return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("section", { className: "dsh-partner-general-settings", "aria-busy": busy, children: [
16975
16984
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("h2", { children: "\u57FA\u672C\u8BBE\u7F6E" }),
16976
16985
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(AttachmentStoragePanel, {}),
16977
- /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(WorkspaceBlock, { title: "\u5347\u7EA7\u8FC1\u79FB", detail: "\u624B\u52A8\u6574\u7406\u516C\u5171\u6570\u636E\u548C\u6BCF\u4F4D\u4F19\u4F34\u7684\u79C1\u6709\u76EE\u5F55\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u6267\u884C\u3002", actions: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", disabled: busy, onClick: () => void inspect(), children: busy ? "\u5904\u7406\u4E2D\u2026" : "\u68C0\u67E5\u8FC1\u79FB" }), children: [
16986
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(WorkspaceBlock, { className: "is-storage-migration", title: "\u5347\u7EA7\u8FC1\u79FB", detail: "\u624B\u52A8\u6574\u7406\u516C\u5171\u6570\u636E\u548C\u6BCF\u4F4D\u4F19\u4F34\u7684\u79C1\u6709\u76EE\u5F55\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u6267\u884C\u3002", actions: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("button", { type: "button", disabled: busy, onClick: () => void inspect(), children: busy ? "\u5904\u7406\u4E2D\u2026" : "\u68C0\u67E5\u8FC1\u79FB" }), children: [
16978
16987
  /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)("p", { children: [
16979
16988
  "\u6570\u636E\u5B58\u50A8\u7248\u672C\uFF1A",
16980
16989
  version === void 0 ? "\u6B63\u5728\u8BFB\u53D6\u2026" : `v${version}${version === 0 ? " \xB7 \u5F85\u8FC1\u79FB" : " \xB7 \u5DF2\u5347\u7EA7"}`