@lemoncat7/dsh-partner 2.7.1 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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.2**,适配并验证 **DSH 0.1.7-rc.2**。插件为正式版,宿主仍为 RC;不支持直接用于旧宿主。Node.js **^22.19.0 或 >=24.0.0**。旧版源码保留于 `pre-dsh-0.1.7-rc.2`;详见 [2.7.2 发布说明](docs/releases/2.7.2.md)。
4
4
 
5
5
  面向 DeepSeek Harness 的长期 AI 伙伴与多渠道插件。
6
6
 
@@ -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,尚未安全消费的续接记录会继续保留。
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"}`