@ljwei-stak/dsh-model-router 0.14.0-beta.2 → 0.14.0-beta.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.
@@ -53,9 +53,8 @@ var OFFICIAL_TOOLS = Object.freeze([
53
53
  vendor: "Moonshot AI",
54
54
  purpose: "Kimi \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B kimi \u547D\u4EE4\u4E0E ACP \u4F1A\u8BDD\u3002",
55
55
  package: "@moonshot-ai/kimi-code",
56
- version: "2.1.1",
57
56
  manager: "npm",
58
- installArgs: ["install", "-g", "@moonshot-ai/kimi-code@2.1.1", "--registry=https://registry.npmjs.org/"],
57
+ installArgs: ["install", "-g", "@moonshot-ai/kimi-code@latest", "--registry=https://registry.npmjs.org/"],
59
58
  probeExecutables: ["kimi"],
60
59
  probeNote: "kimi \u4E0E\u65E7 Python \u7248 kimi-cli \u540C\u540D\uFF1B\u8BF7\u6838\u5BF9\u53EF\u6267\u884C\u6587\u4EF6\u6765\u6E90\u548C\u7248\u672C\u3002",
61
60
  providerHints: ["moonshot", "kimi"]
@@ -66,9 +65,8 @@ var OFFICIAL_TOOLS = Object.freeze([
66
65
  vendor: "Anthropic",
67
66
  purpose: "Anthropic \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B claude \u547D\u4EE4\u3002",
68
67
  package: "@anthropic-ai/claude-code",
69
- version: "2.1.283",
70
68
  manager: "npm",
71
- installArgs: ["install", "-g", "@anthropic-ai/claude-code@2.1.283", "--registry=https://registry.npmjs.org/"],
69
+ installArgs: ["install", "-g", "@anthropic-ai/claude-code@latest", "--registry=https://registry.npmjs.org/"],
72
70
  probeExecutables: ["claude"],
73
71
  providerHints: ["anthropic", "claude"]
74
72
  }),
@@ -78,11 +76,10 @@ var OFFICIAL_TOOLS = Object.freeze([
78
76
  vendor: "OpenAI",
79
77
  purpose: "OpenAI \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B codex \u547D\u4EE4\u3002",
80
78
  package: "@openai/codex",
81
- version: "0.157.1",
82
- installArgs: ["install", "-g", "@openai/codex@0.157.1", "--registry=https://registry.npmjs.org/"],
79
+ installArgs: ["install", "-g", "@openai/codex@latest", "--registry=https://registry.npmjs.org/"],
83
80
  manager: "npm",
84
81
  probeExecutables: ["codex"],
85
- probeNote: "Codex \u7248\u672C\u6A2A\u5E45\u7531\u9002\u914D\u5C42\u5BBD\u5339\u914D\uFF1B\u5B89\u88C5\u65F6\u56FA\u5B9A\u7248\u672C\u3002",
82
+ probeNote: "Codex \u7248\u672C\u6A2A\u5E45\u7531\u9002\u914D\u5C42\u5BBD\u5339\u914D\uFF1B\u5B89\u88C5\u65F6\u53D6 npm \u6700\u65B0\u7248\u3002",
86
83
  providerHints: ["openai", "gpt", "codex"]
87
84
  }),
88
85
  Object.freeze({
@@ -91,9 +88,8 @@ var OFFICIAL_TOOLS = Object.freeze([
91
88
  vendor: "MiniMax",
92
89
  purpose: "MiniMax \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B mcode \u547D\u4EE4\u3002",
93
90
  package: "@minimax-ai/code",
94
- version: "0.5.5",
95
91
  manager: "npm",
96
- installArgs: ["install", "-g", "@minimax-ai/code@0.5.5", "--registry=https://registry.npmjs.org/", "--ignore-scripts=false", "--include=optional", "--allow-scripts=@minimax-ai/code,better-sqlite3"],
92
+ installArgs: ["install", "-g", "@minimax-ai/code@latest", "--registry=https://registry.npmjs.org/", "--ignore-scripts=false", "--include=optional", "--allow-scripts=@minimax-ai/code,better-sqlite3"],
97
93
  probeExecutables: ["mcode"],
98
94
  providerHints: ["minimax"]
99
95
  }),
@@ -103,9 +99,8 @@ var OFFICIAL_TOOLS = Object.freeze([
103
99
  vendor: "XiaoMi",
104
100
  purpose: "\u5C0F\u7C73 MiMo \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B mimo \u547D\u4EE4\u3002",
105
101
  package: "@mimo-ai/cli",
106
- version: "0.1.15",
107
102
  manager: "npm",
108
- installArgs: ["install", "-g", "@mimo-ai/cli@0.1.15", "--registry=https://registry.npmjs.org/"],
103
+ installArgs: ["install", "-g", "@mimo-ai/cli@latest", "--registry=https://registry.npmjs.org/"],
109
104
  probeExecutables: ["mimo"],
110
105
  providerHints: ["mimo", "xiaomi"]
111
106
  }),
@@ -115,9 +110,8 @@ var OFFICIAL_TOOLS = Object.freeze([
115
110
  vendor: "xAI",
116
111
  purpose: "xAI \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B grok \u547D\u4EE4\u4E0E ACP \u4F1A\u8BDD\u3002",
117
112
  package: "@xai-official/grok",
118
- version: "1.0.41",
119
113
  manager: "npm",
120
- installArgs: ["install", "-g", "@xai-official/grok@1.0.41", "--registry=https://registry.npmjs.org/"],
114
+ installArgs: ["install", "-g", "@xai-official/grok@latest", "--registry=https://registry.npmjs.org/"],
121
115
  probeExecutables: ["grok"],
122
116
  providerHints: ["xai", "grok"]
123
117
  }),
@@ -127,9 +121,8 @@ var OFFICIAL_TOOLS = Object.freeze([
127
121
  vendor: "Google",
128
122
  purpose: "Google \u5B98\u65B9 Gemini CLI\uFF0C\u65E0\u754C\u9762\u6A21\u5F0F\u4F7F\u7528 gemini -p\u3002",
129
123
  package: "@google/gemini-cli",
130
- version: "0.62.0",
131
124
  manager: "npm",
132
- installArgs: ["install", "-g", "@google/gemini-cli@0.62.0", "--registry=https://registry.npmjs.org/"],
125
+ installArgs: ["install", "-g", "@google/gemini-cli@latest", "--registry=https://registry.npmjs.org/"],
133
126
  probeExecutables: ["gemini"],
134
127
  providerHints: ["gemini", "google"],
135
128
  // Headless runs go through the task adapter. The signed sandbox runner does
@@ -141,7 +134,6 @@ var OFFICIAL_TOOLS = Object.freeze([
141
134
  label: "ZCode",
142
135
  vendor: "Z.ai",
143
136
  purpose: "\u667A\u8C31\u5B98\u65B9 ZCode \u684C\u9762\u7248\uFF0C\u5185\u542B GLM \u7F16\u7A0B\u4EE3\u7406\u3002Windows \u5B89\u88C5\u5668\u53EF\u9009\u62E9 D \u76D8\u76EE\u5F55\u3002",
144
- version: "3.14.3",
145
137
  manager: "signed-windows-installer",
146
138
  installArgs: [],
147
139
  probeExecutables: [],
@@ -1359,7 +1351,7 @@ function channelForProvider(provider, installedToolIds = [], runnableToolIds = [
1359
1351
  preference,
1360
1352
  tool: tool.id,
1361
1353
  label: tool.label,
1362
- detail: tool.id === "zcode" ? "ZCode \u5DF2\u5B89\u88C5\uFF0C\u63D2\u4EF6\u53EF\u8C03\u7528\u5176\u5B98\u65B9\u7F16\u7A0B\u4EE3\u7406\uFF1B3.14.3 \u7684 CLI \u4F7F\u7528\u81EA\u8EAB\u914D\u7F6E\u7684\u9ED8\u8BA4\u6A21\u578B\uFF0C\u4E0D\u80FD\u4FDD\u8BC1\u4E0E Harness \u5EFA\u8BAE\u6A21\u578B\u4E00\u81F4\u3002" : headless && !runnable ? `${tool.label} \u5DF2\u5B89\u88C5\u3002\u5206\u914D\u5230\u8BE5\u6A21\u578B\u7684\u4EFB\u52A1\u4F1A\u5148\u8D70\u5B98\u65B9\u65E0\u754C\u9762\u547D\u4EE4\uFF1B\u547D\u4EE4\u7F3A\u5931\u6216\u5931\u8D25\u65F6\u56DE\u9000\u6A21\u578B\u76EE\u5F55 API\u3002` : `${tool.label} \u5DF2\u5B89\u88C5\uFF0C\u63D2\u4EF6\u53EF\u6258\u7BA1\u8C03\u7528\u5176\u5B98\u65B9 CLI\uFF1BHarness \u6A21\u578B\u76EE\u5F55\u4E0E\u5382\u5546 CLI \u540D\u79F0\u53EF\u80FD\u4E0D\u540C\uFF0C\u56E2\u961F\u65E0\u6CD5\u786E\u8BA4\u6620\u5C04\u65F6\u4F7F\u7528 CLI \u9ED8\u8BA4\u6A21\u578B\uFF0C\u5B9E\u9645\u6A21\u578B\u4ECD\u987B\u6838\u5BF9\u8FD0\u884C\u8BB0\u5F55\u3002`
1354
+ detail: tool.id === "zcode" ? "ZCode \u5DF2\u5B89\u88C5\uFF0C\u63D2\u4EF6\u53EF\u8C03\u7528\u5176\u5B98\u65B9\u7F16\u7A0B\u4EE3\u7406\uFF1B\u5176 CLI \u4F7F\u7528\u81EA\u8EAB\u914D\u7F6E\u7684\u9ED8\u8BA4\u6A21\u578B\uFF0C\u4E0D\u80FD\u4FDD\u8BC1\u4E0E Harness \u5EFA\u8BAE\u6A21\u578B\u4E00\u81F4\u3002" : headless && !runnable ? `${tool.label} \u5DF2\u5B89\u88C5\u3002\u5206\u914D\u5230\u8BE5\u6A21\u578B\u7684\u4EFB\u52A1\u4F1A\u5148\u8D70\u5B98\u65B9\u65E0\u754C\u9762\u547D\u4EE4\uFF1B\u547D\u4EE4\u7F3A\u5931\u6216\u5931\u8D25\u65F6\u56DE\u9000\u6A21\u578B\u76EE\u5F55 API\u3002` : `${tool.label} \u5DF2\u5B89\u88C5\uFF0C\u63D2\u4EF6\u53EF\u6258\u7BA1\u8C03\u7528\u5176\u5B98\u65B9 CLI\uFF1BHarness \u6A21\u578B\u76EE\u5F55\u4E0E\u5382\u5546 CLI \u540D\u79F0\u53EF\u80FD\u4E0D\u540C\uFF0C\u56E2\u961F\u65E0\u6CD5\u786E\u8BA4\u6620\u5C04\u65F6\u4F7F\u7528 CLI \u9ED8\u8BA4\u6A21\u578B\uFF0C\u5B9E\u9645\u6A21\u578B\u4ECD\u987B\u6838\u5BF9\u8FD0\u884C\u8BB0\u5F55\u3002`
1363
1355
  };
1364
1356
  }
1365
1357
  return {
@@ -1729,16 +1721,19 @@ function stableVersionOrder(left, right) {
1729
1721
  }
1730
1722
  return 0;
1731
1723
  }
1732
- function toolInstallAction({ tool, probe, readiness, job, probeStatus }) {
1724
+ function toolInstallAction({ tool, probe, readiness, job, probeStatus, latestVersion = null }) {
1733
1725
  const running = job?.status === "running";
1734
- const versionOrder = probe?.installed ? stableVersionOrder(probe.version, tool.version) : null;
1735
- const currentAndReady = versionOrder === 0 && readiness?.ready === true;
1736
- const repairable = versionOrder === 0 && readiness?.ready === false;
1737
- const newerOrUncertain = probe?.installed && (versionOrder === null || versionOrder > 0);
1738
- const label = running ? "\u5B89\u88C5\u4E2D\u2026" : currentAndReady ? "\u5DF2\u662F\u76EE\u6807\u7248\u672C" : repairable ? "\u4FEE\u590D\u5B98\u65B9\u6267\u884C\u5165\u53E3" : newerOrUncertain ? "\u8BF7\u4EBA\u5DE5\u6838\u5BF9\u7248\u672C" : probe?.installed ? "\u66F4\u65B0\u5230\u76EE\u6807\u7248\u672C" : job?.status === "failed" ? "\u91CD\u8BD5\u5B89\u88C5" : tool.manager === "signed-windows-installer" ? "\u4E0B\u8F7D\u5B89\u88C5\u5668" : "\u4E00\u952E\u5B89\u88C5";
1726
+ const installed = probe?.installed === true;
1727
+ const order = installed && latestVersion ? stableVersionOrder(probe.version, latestVersion) : null;
1728
+ const ready = readiness?.ready === true;
1729
+ const desktop = tool.manager === "signed-windows-installer";
1730
+ const noRunner = desktop || tool.headlessAdapter === true;
1731
+ const repair = installed && !noRunner && readiness?.ready === false;
1732
+ const label = running ? "\u5B89\u88C5\u4E2D\u2026" : !installed ? job?.status === "failed" ? "\u91CD\u8BD5\u5B89\u88C5" : desktop ? "\u4E0B\u8F7D\u6700\u65B0\u5B89\u88C5\u5668" : "\u4E00\u952E\u5B89\u88C5\u6700\u65B0\u7248" : order === -1 ? `\u66F4\u65B0\u5230\u6700\u65B0\u7248 ${latestVersion}` : order === 1 ? "\u5DF2\u9AD8\u4E8E\u6700\u65B0\u6B63\u5F0F\u7248" : repair ? "\u4FEE\u590D\u5B98\u65B9\u6267\u884C\u5165\u53E3" : order === 0 ? "\u5DF2\u662F\u6700\u65B0\u7248\u672C" : "\u5B89\u88C5\u6700\u65B0\u7248";
1733
+ const current = order === 0 && (ready || noRunner);
1739
1734
  return {
1740
1735
  label,
1741
- disabled: probeStatus !== "ready" || running || currentAndReady || newerOrUncertain
1736
+ disabled: probeStatus !== "ready" || running || installed && (order === 1 || current)
1742
1737
  };
1743
1738
  }
1744
1739
 
@@ -1782,7 +1777,14 @@ function dagLayers(packages) {
1782
1777
  return layers.filter(Boolean);
1783
1778
  }
1784
1779
  var LOGIN_LABEL = Object.freeze({ "logged-in": "\u5DF2\u767B\u5F55", "logged-out": "\u672A\u767B\u5F55", unknown: "\u767B\u5F55\u72B6\u6001\u672A\u77E5" });
1785
- var VERSION_LABEL = Object.freeze({ ok: "\u7248\u672C\u7B26\u5408", older: "\u7248\u672C\u4F4E\u4E8E\u76EE\u6807", unknown: "\u7248\u672C\u672A\u77E5" });
1780
+ var VERSION_LABEL = Object.freeze({ latest: "\u5DF2\u662F\u6700\u65B0\u7248", "update-available": "\u6709\u65B0\u7248\u672C", unknown: "\u6700\u65B0\u7248\u672C\u672A\u77E5" });
1781
+ var UNTESTED_VERSION_NOTE = "\u63D2\u4EF6\u4E0D\u518D\u56FA\u5B9A\u5B98\u65B9\u5DE5\u5177\u7248\u672C\uFF0C\u5B89\u88C5\u548C\u66F4\u65B0\u90FD\u53D6\u5404\u5382\u5546\u7684\u6700\u65B0\u7248\uFF1B\u65B0\u7248\u672C\u672A\u7ECF\u63D2\u4EF6\u6D4B\u8BD5\uFF0C\u8F93\u51FA\u683C\u5F0F\u53D8\u5316\u65F6\u63D2\u4EF6\u4F1A\u5C3D\u91CF\u517C\u5BB9\uFF0C\u9047\u5230\u95EE\u9898\u8BF7\u53CD\u9988\u3002";
1782
+ function versionLine(entry) {
1783
+ if (!entry?.installed) return "";
1784
+ const installed = entry.version ? `\u5DF2\u5B89\u88C5 ${entry.version}` : "\u5DF2\u5B89\u88C5\uFF08\u7248\u672C\u672A\u77E5\uFF09";
1785
+ if (!entry.latestVersion) return `${installed} \xB7 ${VERSION_LABEL.unknown}`;
1786
+ return entry.versionStatus === "update-available" ? `${installed} \xB7 \u6700\u65B0 ${entry.latestVersion}\uFF08\u6709\u65B0\u7248\u672C\uFF0C\u53EF\u5728\u4E0B\u65B9\u66F4\u65B0\uFF09` : `${installed} \xB7 ${VERSION_LABEL.latest}`;
1787
+ }
1786
1788
  function healthSummary(tools) {
1787
1789
  const list = Array.isArray(tools) ? tools : [];
1788
1790
  const installed = list.filter((item) => item.installed);
@@ -1792,7 +1794,7 @@ function healthSummary(tools) {
1792
1794
  ready: installed.filter((item) => item.login?.state === "logged-in").length,
1793
1795
  loggedOut: installed.filter((item) => item.login?.state === "logged-out").length,
1794
1796
  unknown: installed.filter((item) => item.login?.state === "unknown").length,
1795
- older: installed.filter((item) => item.versionStatus === "older").length
1797
+ updates: installed.filter((item) => item.versionStatus === "update-available").length
1796
1798
  };
1797
1799
  }
1798
1800
  var money = formatUsd;
@@ -1953,8 +1955,9 @@ var SUBSCRIPTION_FAILURE_OPTIONS = [["ask", "\u6682\u505C\u5E76\u8BE2\u95EE"], [
1953
1955
  var SUBSCRIPTION_CHOICE_BUTTONS = [["api", "\u6539\u7528 API \u91CD\u8BD5", false], ["subscription", "\u91CD\u8BD5\u8BA2\u9605", true], ["cancel", "\u53D6\u6D88", true]];
1954
1956
  function OnboardingBanner({ health, onDone, onRefresh, refreshing, error }) {
1955
1957
  const summary = healthSummary(health?.tools);
1956
- const problems = (health?.tools ?? []).filter((item) => item.installed && (item.login?.state === "logged-out" || item.versionStatus === "older"));
1957
- return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-onboarding", "aria-label": "\u5F00\u7BB1\u4F53\u68C0" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react2.default.createElement("div", null, /* @__PURE__ */ import_react2.default.createElement("h2", { className: "mr-card-title" }, "\u5F00\u7BB1\u4F53\u68C0"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u9996\u6B21\u6253\u5F00\u65F6\u68C0\u6D4B\u6BCF\u4E2A\u5B98\u65B9\u5DE5\u5177\u662F\u5426\u5DF2\u5B89\u88C5\u3001\u7248\u672C\u662F\u5426\u7B26\u5408\u3001\u662F\u5426\u5DF2\u767B\u5F55\u3002\u672A\u767B\u5F55\u7684\u5DE5\u5177\u4F1A\u88AB\u8DEF\u7531\u76F4\u63A5\u8DF3\u8FC7\uFF0C\u6539\u8D70\u6A21\u578B\u76EE\u5F55 API\uFF0C\u4E0D\u5FC5\u7B49\u5F85 CLI \u5931\u8D25\u3002")), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: refreshing, onClick: onRefresh }, refreshing ? "\u68C0\u6D4B\u4E2D\u2026" : "\u91CD\u65B0\u4F53\u68C0")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, error), !health && !error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u4F53\u68C0\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u2026"), health && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u5DF2\u5B89\u88C5"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, summary.installed, " / ", summary.total)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u5DF2\u767B\u5F55\u53EF\u7528"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, summary.ready)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u672A\u767B\u5F55"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, summary.loggedOut)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u767B\u5F55\u72B6\u6001\u672A\u77E5"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, summary.unknown))), problems.length > 0 ? /* @__PURE__ */ import_react2.default.createElement("ul", { className: "mr-checklist" }, problems.map((item) => /* @__PURE__ */ import_react2.default.createElement("li", { key: item.id }, /* @__PURE__ */ import_react2.default.createElement("strong", null, item.label), "\uFF1A", item.login?.state === "logged-out" ? `\u672A\u767B\u5F55\uFF0C\u53EF\u5728\u4E0B\u65B9\u70B9\u201C\u53BB\u767B\u5F55\u201D\u67E5\u770B\u767B\u5F55\u65B9\u6CD5\uFF08${item.login.command ?? "\u89C1\u8BF4\u660E"}\uFF09\u3002` : "", item.versionStatus === "older" ? `\u5F53\u524D ${item.version}\uFF0C\u4F4E\u4E8E\u76EE\u6807 ${item.pinnedVersion}\uFF0C\u53EF\u5728\u4E0B\u65B9\u66F4\u65B0\u3002` : ""))) : /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u5DF2\u5B89\u88C5\u7684\u5DE5\u5177\u6CA1\u6709\u53D1\u73B0\u672A\u767B\u5F55\u6216\u7248\u672C\u8FC7\u65E7\u7684\u95EE\u9898\u3002\u672A\u5B89\u88C5\u7684\u5DE5\u5177\u53EF\u5728\u4E0B\u65B9\u4E00\u952E\u5B89\u88C5\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button", type: "button", onClick: onDone }, "\u5B8C\u6210\u4F53\u68C0"), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u4E4B\u540E\u53EF\u968F\u65F6\u5728\u201C\u5B98\u65B9\u5DE5\u5177\u201D\u5361\u7247\u4E2D\u91CD\u65B0\u4F53\u68C0\u3002")))));
1958
+ const problems = (health?.tools ?? []).filter((item) => item.installed && item.login?.state === "logged-out");
1959
+ const updates = (health?.tools ?? []).filter((item) => item.installed && item.versionStatus === "update-available");
1960
+ return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-onboarding", "aria-label": "\u5F00\u7BB1\u4F53\u68C0" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react2.default.createElement("div", null, /* @__PURE__ */ import_react2.default.createElement("h2", { className: "mr-card-title" }, "\u5F00\u7BB1\u4F53\u68C0"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u9996\u6B21\u6253\u5F00\u65F6\u68C0\u6D4B\u6BCF\u4E2A\u5B98\u65B9\u5DE5\u5177\u662F\u5426\u5DF2\u5B89\u88C5\u3001\u5F53\u524D\u7248\u672C\uFF08\u4EE5\u53CA\u80FD\u67E5\u5230\u65F6\u7684\u6700\u65B0\u7248\u672C\uFF09\u3001\u662F\u5426\u5DF2\u767B\u5F55\u3002\u672A\u767B\u5F55\u7684\u5DE5\u5177\u4F1A\u88AB\u8DEF\u7531\u76F4\u63A5\u8DF3\u8FC7\uFF0C\u6539\u8D70\u6A21\u578B\u76EE\u5F55 API\uFF0C\u4E0D\u5FC5\u7B49\u5F85 CLI \u5931\u8D25\u3002")), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: refreshing, onClick: onRefresh }, refreshing ? "\u68C0\u6D4B\u4E2D\u2026" : "\u91CD\u65B0\u4F53\u68C0")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, error), !health && !error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u4F53\u68C0\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u2026"), health && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u5DF2\u5B89\u88C5"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, summary.installed, " / ", summary.total)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u5DF2\u767B\u5F55\u53EF\u7528"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, summary.ready)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u672A\u767B\u5F55"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, summary.loggedOut)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u767B\u5F55\u72B6\u6001\u672A\u77E5"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, summary.unknown))), problems.length > 0 ? /* @__PURE__ */ import_react2.default.createElement("ul", { className: "mr-checklist" }, problems.map((item) => /* @__PURE__ */ import_react2.default.createElement("li", { key: item.id }, /* @__PURE__ */ import_react2.default.createElement("strong", null, item.label), "\uFF1A\u672A\u767B\u5F55\uFF0C\u53EF\u5728\u4E0B\u65B9\u70B9\u201C\u53BB\u767B\u5F55\u201D\u67E5\u770B\u767B\u5F55\u65B9\u6CD5\uFF08", item.login.command ?? "\u89C1\u8BF4\u660E", "\uFF09\u3002"))) : /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u5DF2\u5B89\u88C5\u7684\u5DE5\u5177\u6CA1\u6709\u53D1\u73B0\u672A\u767B\u5F55\u7684\u95EE\u9898\u3002\u672A\u5B89\u88C5\u7684\u5DE5\u5177\u53EF\u5728\u4E0B\u65B9\u4E00\u952E\u5B89\u88C5\u3002"), updates.length > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u6709\u65B0\u7248\u672C\uFF1A", updates.map((item) => `${item.label} ${item.version ?? "?"} \u2192 ${item.latestVersion}`).join("\uFF1B"), "\u3002\u53EF\u5728\u4E0B\u65B9\u201C\u5B98\u65B9\u5DE5\u5177\u201D\u4E2D\u66F4\u65B0\uFF08\u53EF\u9009\uFF09\u3002"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, UNTESTED_VERSION_NOTE), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button", type: "button", onClick: onDone }, "\u5B8C\u6210\u4F53\u68C0"), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u4E4B\u540E\u53EF\u968F\u65F6\u5728\u201C\u5B98\u65B9\u5DE5\u5177\u201D\u5361\u7247\u4E2D\u91CD\u65B0\u4F53\u68C0\u3002")))));
1958
1961
  }
1959
1962
  function ToolLoginLine({ entry }) {
1960
1963
  const [open, setOpen] = import_react2.default.useState(false);
@@ -1969,7 +1972,7 @@ function ToolLoginLine({ entry }) {
1969
1972
  setCopied(false);
1970
1973
  }
1971
1974
  };
1972
- return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-login" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-tool-status" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: `mr-tool-dot ${state === "logged-in" ? "installed" : state === "logged-out" ? "missing-strong" : ""}` }), LOGIN_LABEL[state], " \xB7 ", VERSION_LABEL[entry.versionStatus] ?? "\u7248\u672C\u672A\u77E5", entry.pinnedVersion ? `\uFF08\u76EE\u6807 ${entry.pinnedVersion}\uFF09` : ""), entry.login?.detail && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption mr-tool-detail" }, entry.login.detail), state === "logged-in" && entry.login?.billing === "subscription" && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption mr-tool-detail" }, "\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\uFF1A\u8D39\u7528\u53EA\u4F5C\u53C2\u8003\u663E\u793A\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\u3002"), state === "logged-in" && entry.login?.billing === "api-key" && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption mr-tool-detail" }, "API Key \u8BA1\u8D39\uFF1A\u8D39\u7528\u8BA1\u5165\u6BCF\u65E5/\u6BCF\u6708\u9884\u7B97\u3002"), state !== "logged-in" && /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-tool-button mr-login-button", type: "button", "aria-expanded": open, onClick: () => setOpen((value) => !value) }, "\u53BB\u767B\u5F55"), open && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-login-guide" }, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, entry.login.steps), entry.login.command && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-login-command" }, /* @__PURE__ */ import_react2.default.createElement("code", { className: "mr-tool-command" }, entry.login.command), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => {
1975
+ return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-login" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-tool-status" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: `mr-tool-dot ${state === "logged-in" ? "installed" : state === "logged-out" ? "missing-strong" : ""}` }), LOGIN_LABEL[state], " \xB7 ", versionLine(entry)), entry.login?.detail && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption mr-tool-detail" }, entry.login.detail), state === "logged-in" && entry.login?.billing === "subscription" && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption mr-tool-detail" }, "\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\uFF1A\u8D39\u7528\u53EA\u4F5C\u53C2\u8003\u663E\u793A\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\u3002"), state === "logged-in" && entry.login?.billing === "api-key" && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption mr-tool-detail" }, "API Key \u8BA1\u8D39\uFF1A\u8D39\u7528\u8BA1\u5165\u6BCF\u65E5/\u6BCF\u6708\u9884\u7B97\u3002"), state !== "logged-in" && /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-tool-button mr-login-button", type: "button", "aria-expanded": open, onClick: () => setOpen((value) => !value) }, "\u53BB\u767B\u5F55"), open && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-login-guide" }, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, entry.login.steps), entry.login.command && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-login-command" }, /* @__PURE__ */ import_react2.default.createElement("code", { className: "mr-tool-command" }, entry.login.command), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => {
1973
1976
  void copy();
1974
1977
  } }, copied ? "\u5DF2\u590D\u5236" : "\u590D\u5236\u547D\u4EE4")), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u63D2\u4EF6\u4E0D\u4F1A\u66FF\u4F60\u542F\u52A8\u4EA4\u4E92\u5F0F\u767B\u5F55\u3002\u767B\u5F55\u5B8C\u6210\u540E\u70B9\u201C\u91CD\u65B0\u4F53\u68C0\u201D\u3002")));
1975
1978
  }
@@ -11601,7 +11604,7 @@ var xterm_default = `/**
11601
11604
  `;
11602
11605
 
11603
11606
  // .dsh-plugin/client/host-version.mjs
11604
- var ROUTER_CLIENT_VERSION = true ? "0.14.0-beta.2" : "";
11607
+ var ROUTER_CLIENT_VERSION = true ? "0.14.0-beta.4" : "";
11605
11608
  var STALE_HOST_MESSAGE = "\u63D2\u4EF6\u540E\u53F0\u7248\u672C\u8F83\u65E7\uFF0C\u8BF7\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u542F Harness\uFF08\u5305\u62EC\u6258\u76D8\u56FE\u6807\uFF09\u540E\u518D\u4F7F\u7528\u3002";
11606
11609
  function isMissingRemoteMethod(message) {
11607
11610
  const value = String(message ?? "");
@@ -11723,6 +11726,7 @@ function parseTerminalStop(value) {
11723
11726
  const request = plainObject(value, "terminal stop request");
11724
11727
  return { sessionId: sessionIdOf(request.sessionId) };
11725
11728
  }
11729
+ var isTerminalSessionId = (value) => typeof value === "string" && SESSION_ID.test(value);
11726
11730
 
11727
11731
  // .dsh-plugin/client/cli-terminal-state.mjs
11728
11732
  var text3 = (value) => typeof value === "string" ? value.trim() : "";
@@ -11779,10 +11783,26 @@ var formatDuration = (ms2) => {
11779
11783
  const minutes = Math.floor(seconds / 60);
11780
11784
  return minutes < 60 ? `${minutes} \u5206 ${seconds % 60} \u79D2` : `${Math.floor(minutes / 60)} \u5C0F\u65F6 ${minutes % 60} \u5206`;
11781
11785
  };
11782
- var unwrap = (response, fallback) => {
11783
- if (response?.ok) return response.value;
11784
- throw new Error(remoteErrorText(text3(response?.error?.message) || text3(response?.error), fallback));
11785
- };
11786
+ function unwrapTerminal(response, fallback) {
11787
+ if (!response?.ok) throw new Error(remoteErrorText(text3(response?.error?.message) || text3(response?.error), fallback));
11788
+ const inner = response.value;
11789
+ if (inner && typeof inner === "object" && typeof inner.ok === "boolean") {
11790
+ if (!inner.ok) throw new Error(remoteErrorText(text3(inner.error?.message) || text3(inner.error), fallback));
11791
+ return inner.value;
11792
+ }
11793
+ return inner;
11794
+ }
11795
+ var unwrap = unwrapTerminal;
11796
+ async function loadTerminalInfo(api) {
11797
+ const info = unwrap(await api.terminalInfo(), "\u65E0\u6CD5\u8BFB\u53D6\u7EC8\u7AEF\u72B6\u6001\u3002");
11798
+ if (!info || typeof info !== "object" || !["pty", "pipe"].includes(info.backend)) throw new Error("\u7EC8\u7AEF\u72B6\u6001\u683C\u5F0F\u65E0\u6548\u3002");
11799
+ return info;
11800
+ }
11801
+ async function startTerminal(api, request) {
11802
+ const session = unwrap(await api.terminalStart({ ...request, confirmed: true }), "\u7EC8\u7AEF\u542F\u52A8\u5931\u8D25\u3002");
11803
+ if (!isTerminalSessionId(session?.sessionId)) throw new Error("\u7EC8\u7AEF\u542F\u52A8\u7ED3\u679C\u7F3A\u5C11\u6709\u6548\u7684\u4F1A\u8BDD ID\u3002");
11804
+ return session;
11805
+ }
11786
11806
  var TerminalConnection = class {
11787
11807
  constructor({ api, sessionId, onData, onExit, onError, waitMs = 800, retryMs = 1e3, resizeDelayMs = 120, setTimer = setTimeout, clearTimer = clearTimeout }) {
11788
11808
  Object.assign(this, { api, sessionId, onData, onExit, onError, waitMs, retryMs, resizeDelayMs });
@@ -11796,6 +11816,13 @@ var TerminalConnection = class {
11796
11816
  this.failures = 0;
11797
11817
  }
11798
11818
  start() {
11819
+ if (!isTerminalSessionId(this.sessionId)) {
11820
+ this.closed = true;
11821
+ this.onError?.(new Error("\u7EC8\u7AEF\u4F1A\u8BDD ID \u65E0\u6548\uFF0C\u65E0\u6CD5\u8BFB\u53D6\u8F93\u51FA\u3002"));
11822
+ this.onExit?.({ endReason: "lost", exitCode: null });
11823
+ this.loop = Promise.resolve();
11824
+ return this.loop;
11825
+ }
11799
11826
  this.loop = this.readLoop();
11800
11827
  return this.loop;
11801
11828
  }
@@ -11849,7 +11876,9 @@ var TerminalConnection = class {
11849
11876
  }
11850
11877
  }
11851
11878
  resize(cols, rows) {
11852
- if (this.closed) return;
11879
+ if (this.closed || !Number.isFinite(cols) || !Number.isFinite(rows)) return;
11880
+ cols = Math.min(TERMINAL_LIMITS.maxCols, Math.max(TERMINAL_LIMITS.minCols, Math.round(cols)));
11881
+ rows = Math.min(TERMINAL_LIMITS.maxRows, Math.max(TERMINAL_LIMITS.minRows, Math.round(rows)));
11853
11882
  if (this.resizeTimer) this.clearTimer(this.resizeTimer);
11854
11883
  this.resizeTimer = this.setTimer(() => {
11855
11884
  this.resizeTimer = null;
@@ -11975,10 +12004,9 @@ function CliTerminalCard({ api, health }) {
11975
12004
  const mounted = import_react4.default.useRef(true);
11976
12005
  const loadInfo = import_react4.default.useCallback(async () => {
11977
12006
  try {
11978
- const response = await api.terminalInfo();
12007
+ const value = await loadTerminalInfo(api);
11979
12008
  if (!mounted.current) return;
11980
- if (!response?.ok) throw new Error(remoteErrorText(response?.error?.message, "\u65E0\u6CD5\u8BFB\u53D6\u7EC8\u7AEF\u72B6\u6001\u3002"));
11981
- setInfo({ status: "ready", value: response.value, error: "" });
12009
+ setInfo({ status: "ready", value, error: "" });
11982
12010
  } catch (error) {
11983
12011
  if (mounted.current) setInfo({ status: "error", value: null, error: errorText(error, "\u65E0\u6CD5\u8BFB\u53D6\u7EC8\u7AEF\u72B6\u6001\u3002") });
11984
12012
  }
@@ -12007,15 +12035,14 @@ function CliTerminalCard({ api, health }) {
12007
12035
  setStarting(true);
12008
12036
  setStartError("");
12009
12037
  try {
12010
- const response = await api.terminalStart({ target: selected.id, mode, cwd: text4(cwd), cols: 100, rows: 30, confirmed: true });
12011
- if (!response?.ok) throw new Error(remoteErrorText(response?.error?.message, "\u7EC8\u7AEF\u542F\u52A8\u5931\u8D25\u3002"));
12038
+ const session = await startTerminal(api, { target: selected.id, mode, cwd: text4(cwd), cols: 100, rows: 30 });
12012
12039
  storeCwd(text4(cwd));
12013
12040
  if (!mounted.current) {
12014
- void api.terminalStop({ sessionId: response.value.sessionId });
12041
+ void api.terminalStop({ sessionId: session.sessionId });
12015
12042
  return;
12016
12043
  }
12017
- setSessions((previous) => [...previous, { ...response.value, ended: null }]);
12018
- setActiveId(response.value.sessionId);
12044
+ setSessions((previous) => [...previous, { ...session, ended: null }]);
12045
+ setActiveId(session.sessionId);
12019
12046
  setConfirming(false);
12020
12047
  } catch (error) {
12021
12048
  if (mounted.current) setStartError(errorText(error, "\u7EC8\u7AEF\u542F\u52A8\u5931\u8D25\u3002"));
@@ -12419,7 +12446,7 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
12419
12446
  const byId = Object.fromEntries(probeState.probes.map((probe) => [probe.id, probe]));
12420
12447
  const capabilitiesById = Object.fromEntries(probeState.capabilities.map((item) => [item.id, item]));
12421
12448
  const readinessById = Object.fromEntries(probeState.readiness.map((item) => [item.id, item]));
12422
- return /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card", "aria-label": "\u5B98\u65B9\u5DE5\u5177" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", { className: "mr-card-title" }, "\u5B98\u65B9\u5DE5\u5177 \xB7 \u4F53\u68C0"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, "\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u7684\u5B89\u88C5\u3001\u7248\u672C\u548C\u767B\u5F55\u72B6\u6001\uFF0C\u5E76\u4ECE\u56FA\u5B9A\u6CE8\u518C\u8868\u4E00\u952E\u5B89\u88C5\u3002\u672A\u767B\u5F55\u7684\u5DE5\u5177\u70B9\u201C\u53BB\u767B\u5F55\u201D\u67E5\u770B\u767B\u5F55\u547D\u4EE4\u3002ZCode \u4F1A\u6253\u5F00\u5B98\u65B9\u5B89\u88C5\u7A97\u53E3\u4F9B\u4F60\u9009\u62E9\u76EE\u5F55\uFF1B\u5B8C\u6210\u540E\u91CD\u65B0\u4F53\u68C0\u3002")), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: probeState.status === "loading", onClick: () => {
12449
+ return /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card", "aria-label": "\u5B98\u65B9\u5DE5\u5177" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", { className: "mr-card-title" }, "\u5B98\u65B9\u5DE5\u5177 \xB7 \u4F53\u68C0"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, "\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u7684\u5B89\u88C5\u3001\u7248\u672C\u548C\u767B\u5F55\u72B6\u6001\uFF0C\u5E76\u4ECE\u56FA\u5B9A\u6CE8\u518C\u8868\u4E00\u952E\u5B89\u88C5\u6216\u66F4\u65B0\u5230\u5404\u5382\u5546\u6700\u65B0\u7248\uFF08\u65B0\u7248\u672C\u672A\u7ECF\u63D2\u4EF6\u6D4B\u8BD5\uFF09\u3002\u672A\u767B\u5F55\u7684\u5DE5\u5177\u70B9\u201C\u53BB\u767B\u5F55\u201D\u67E5\u770B\u767B\u5F55\u547D\u4EE4\u3002ZCode \u4F1A\u6253\u5F00\u5B98\u65B9\u5B89\u88C5\u7A97\u53E3\u4F9B\u4F60\u9009\u62E9\u76EE\u5F55\uFF1B\u5B8C\u6210\u540E\u91CD\u65B0\u4F53\u68C0\u3002")), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: probeState.status === "loading", onClick: () => {
12423
12450
  void refresh();
12424
12451
  } }, "\u91CD\u65B0\u4F53\u68C0")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, probeState.status === "loading" && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u2026"), probeState.status === "error" && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error", role: "alert" }, probeState.error), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tools", role: "list", "aria-label": "\u5B98\u65B9\u5DE5\u5177\u6CE8\u518C\u8868" }, OFFICIAL_TOOLS.map((tool) => {
12425
12452
  const command = installCommandLine(tool);
@@ -12428,10 +12455,10 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
12428
12455
  const readiness = readinessById[tool.id];
12429
12456
  const job = jobs[tool.id];
12430
12457
  const running = job?.status === "running";
12431
- const action = toolInstallAction({ tool, probe, readiness, job, probeStatus: probeState.status });
12458
+ const action = toolInstallAction({ tool, probe, readiness, job, probeStatus: probeState.status, latestVersion: healthById[tool.id]?.latestVersion ?? null });
12432
12459
  const verified = job?.status === "succeeded" && job.postInstallProbe?.installed === true;
12433
12460
  const status = running ? job.cancelRequested ? "\u6B63\u5728\u53D6\u6D88\u5B89\u88C5\u2026" : "\u5B89\u88C5\u4E2D\u2026" : job?.status === "installer-opened" ? "\u5B98\u65B9\u5B89\u88C5\u5668\u5DF2\u6253\u5F00\uFF0C\u8BF7\u5B8C\u6210\u5B89\u88C5\u540E\u91CD\u65B0\u68C0\u6D4B" : job?.status === "cancelled" ? "\u5B89\u88C5\u5DF2\u53D6\u6D88\uFF0C\u8BF7\u91CD\u65B0\u68C0\u6D4B" : verified ? "\u5B89\u88C5\u6210\u529F\u5E76\u9A8C\u8BC1" : probeLabel(probe);
12434
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool", role: "listitem", key: tool.id }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-info" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-route-name", title: tool.purpose }, tool.label), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-route-provider" }, tool.vendor, " \xB7 ", tool.id), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-status", role: "status" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: `mr-tool-dot ${running ? "running" : probe?.installed ? "installed" : "missing"}` }), status, tool.version ? ` \xB7 \u76EE\u6807 ${tool.version}` : ""), /* @__PURE__ */ import_react5.default.createElement(ToolLoginLine, { entry: healthById[tool.id] }), probe?.installed && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, tool.headlessAdapter ? "\u5DF2\u53EF\u7531 model_router_execute \u4EE5\u65E0\u754C\u9762\u65B9\u5F0F\u8C03\u7528\u3002\u547D\u4EE4\u7F3A\u5931\u6216\u5931\u8D25\u65F6\u56DE\u9000\u6A21\u578B\u76EE\u5F55 API\u3002\u7B7E\u540D\u6C99\u7BB1\u5165\u53E3\u4E0D\u542F\u52A8\u6B64 CLI\u3002" : readiness?.ready ? `\u5B98\u65B9\u6267\u884C\u5165\u53E3\u5DF2\u6838\u9A8C\uFF0C\u53EF\u5728\u4F1A\u8BDD\u4E2D\u8C03\u7528 model_router_tool_run\uFF1B${capability?.modes?.includes("read-only") ? "\u652F\u6301\u53EA\u8BFB\u548C\u7ECF\u5BA1\u6279\u7684\u53EF\u7F16\u8F91\u4EFB\u52A1" : "\u4EC5\u652F\u6301\u7ECF\u5BA1\u6279\u7684\u53EF\u7F16\u8F91\u9694\u79BB\u5DE5\u4F5C\u533A\u4EFB\u52A1"}\uFF0C\u8D26\u53F7\u53CA\u6A21\u578B\u4ECD\u9700\u5B9E\u6D4B\u3002` : `\u5DF2\u5B89\u88C5\uFF0C\u4F46\u5F53\u524D\u4E0D\u53EF\u6258\u7BA1\u6267\u884C\uFF1A${readiness?.reason || capability?.reason || "\u6267\u884C\u5165\u53E3\u5C1A\u672A\u6838\u9A8C\u3002"}`), command ? /* @__PURE__ */ import_react5.default.createElement("code", { className: "mr-tool-command" }, command) : /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { margin: "6px 0 0" } }, tool.unsupportedReason), probe?.detail && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, probe.detail), (rowErrors[tool.id] || job?.error) && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error mr-tool-error", role: "alert" }, rowErrors[tool.id] || job.error), Array.isArray(job?.outputTail) && job.outputTail.length > 0 && /* @__PURE__ */ import_react5.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, "\u5B89\u88C5\u65E5\u5FD7"), /* @__PURE__ */ import_react5.default.createElement("pre", null, job.outputTail.slice(-6).join("\n")))), command && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-actions" }, /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-tool-button", type: "button", disabled: action.disabled, onClick: () => {
12461
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool", role: "listitem", key: tool.id }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-info" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-route-name", title: tool.purpose }, tool.label), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-route-provider" }, tool.vendor, " \xB7 ", tool.id), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-status", role: "status" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: `mr-tool-dot ${running ? "running" : probe?.installed ? "installed" : "missing"}` }), status, probe?.installed && probe.version ? ` \xB7 ${probe.version}` : "", healthById[tool.id]?.latestVersion ? ` \xB7 \u6700\u65B0 ${healthById[tool.id].latestVersion}` : ""), /* @__PURE__ */ import_react5.default.createElement(ToolLoginLine, { entry: healthById[tool.id] }), probe?.installed && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, tool.headlessAdapter ? "\u5DF2\u53EF\u7531 model_router_execute \u4EE5\u65E0\u754C\u9762\u65B9\u5F0F\u8C03\u7528\u3002\u547D\u4EE4\u7F3A\u5931\u6216\u5931\u8D25\u65F6\u56DE\u9000\u6A21\u578B\u76EE\u5F55 API\u3002\u7B7E\u540D\u6C99\u7BB1\u5165\u53E3\u4E0D\u542F\u52A8\u6B64 CLI\u3002" : readiness?.ready ? `\u5B98\u65B9\u6267\u884C\u5165\u53E3\u5DF2\u6838\u9A8C\uFF0C\u53EF\u5728\u4F1A\u8BDD\u4E2D\u8C03\u7528 model_router_tool_run\uFF1B${capability?.modes?.includes("read-only") ? "\u652F\u6301\u53EA\u8BFB\u548C\u7ECF\u5BA1\u6279\u7684\u53EF\u7F16\u8F91\u4EFB\u52A1" : "\u4EC5\u652F\u6301\u7ECF\u5BA1\u6279\u7684\u53EF\u7F16\u8F91\u9694\u79BB\u5DE5\u4F5C\u533A\u4EFB\u52A1"}\uFF0C\u8D26\u53F7\u53CA\u6A21\u578B\u4ECD\u9700\u5B9E\u6D4B\u3002` : `\u5DF2\u5B89\u88C5\uFF0C\u4F46\u5F53\u524D\u4E0D\u53EF\u6258\u7BA1\u6267\u884C\uFF1A${readiness?.reason || capability?.reason || "\u6267\u884C\u5165\u53E3\u5C1A\u672A\u6838\u9A8C\u3002"}`), command ? /* @__PURE__ */ import_react5.default.createElement("code", { className: "mr-tool-command" }, command) : /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { margin: "6px 0 0" } }, tool.unsupportedReason), probe?.detail && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, probe.detail), (rowErrors[tool.id] || job?.error) && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error mr-tool-error", role: "alert" }, rowErrors[tool.id] || job.error), Array.isArray(job?.outputTail) && job.outputTail.length > 0 && /* @__PURE__ */ import_react5.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, "\u5B89\u88C5\u65E5\u5FD7"), /* @__PURE__ */ import_react5.default.createElement("pre", null, job.outputTail.slice(-6).join("\n")))), command && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-actions" }, /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-tool-button", type: "button", disabled: action.disabled, onClick: () => {
12435
12462
  void install(tool.id);
12436
12463
  } }, action.label), running && /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary mr-tool-button", type: "button", disabled: job.cancelRequested, onClick: () => {
12437
12464
  void cancel(tool.id);
@@ -12730,7 +12757,7 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
12730
12757
  }
12731
12758
  ), /* @__PURE__ */ import_react5.default.createElement(SecurityCard, { data: workbench.boundaries.value, error: workbench.boundaries.error, onRefresh: () => {
12732
12759
  void workbench.refreshBoundaries();
12733
- } }), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-notice" }, "\u53EA\u8BFB\u4EFB\u52A1\u53EF\u5728\u4E0A\u65B9\u201C\u5728\u5DE5\u4F5C\u53F0\u6267\u884C\u201D\u4E2D\u76F4\u63A5\u9884\u89C8\u5E76\u6267\u884C\uFF1B\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u53EF\u4F7F\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_execute"), "\uFF08\u6309\u8DEF\u7531\u6216\u6307\u5B9A\u6A21\u578B\u6267\u884C\uFF0C\u5B98\u65B9 CLI \u5931\u8D25\u5219\u56DE\u9000 API\uFF09\u3001", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_consult"), "\u3001", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_tool_run"), " \u6216 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_team_execute"), "\u3002\u6307\u5B9A\u6A21\u578B\u4F1A\u8DF3\u8FC7\u8DEF\u7EBF\u6BD4\u8F83\u3002\u6258\u7BA1\u6267\u884C\u80FD\u529B\u548C\u5C31\u7EEA\u72B6\u6001\u89C1\u4E0A\u65B9\u5404\u5DE5\u5177\u5361\u7247\uFF1B\u5B9E\u9645\u4F7F\u7528\u7684\u6A21\u578B\u4EE5\u5382\u5546\u8BB0\u5F55\u4E3A\u51C6\u3002ZCode 3.14.3 \u4F7F\u7528\u5176\u81EA\u8EAB\u914D\u7F6E\u7684\u9ED8\u8BA4\u6A21\u578B\u3002\u53EF\u7F16\u8F91\u56E2\u961F\u4EFB\u52A1\u8981\u6C42\u5E72\u51C0\u7684 Git \u4ED3\u5E93\uFF0C\u5E76\u7ECF\u5B98\u65B9\u5DE5\u5177\u5BA1\u6279\u3002\u8BBE\u7F6E\u4F4D\u4E8E\u201C\u63D2\u4EF6 \u2192 \u5DF2\u5B89\u88C5 \u2192 @ljwei-stak/model-router-galgame\u201D\u3002")));
12760
+ } }), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-notice" }, "\u53EA\u8BFB\u4EFB\u52A1\u53EF\u5728\u4E0A\u65B9\u201C\u5728\u5DE5\u4F5C\u53F0\u6267\u884C\u201D\u4E2D\u76F4\u63A5\u9884\u89C8\u5E76\u6267\u884C\uFF1B\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u53EF\u4F7F\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_execute"), "\uFF08\u6309\u8DEF\u7531\u6216\u6307\u5B9A\u6A21\u578B\u6267\u884C\uFF0C\u5B98\u65B9 CLI \u5931\u8D25\u5219\u56DE\u9000 API\uFF09\u3001", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_consult"), "\u3001", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_tool_run"), " \u6216 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_team_execute"), "\u3002\u6307\u5B9A\u6A21\u578B\u4F1A\u8DF3\u8FC7\u8DEF\u7EBF\u6BD4\u8F83\u3002\u6258\u7BA1\u6267\u884C\u80FD\u529B\u548C\u5C31\u7EEA\u72B6\u6001\u89C1\u4E0A\u65B9\u5404\u5DE5\u5177\u5361\u7247\uFF1B\u5B9E\u9645\u4F7F\u7528\u7684\u6A21\u578B\u4EE5\u5382\u5546\u8BB0\u5F55\u4E3A\u51C6\u3002ZCode \u4F7F\u7528\u5176\u81EA\u8EAB\u914D\u7F6E\u7684\u9ED8\u8BA4\u6A21\u578B\u3002\u53EF\u7F16\u8F91\u56E2\u961F\u4EFB\u52A1\u8981\u6C42\u5E72\u51C0\u7684 Git \u4ED3\u5E93\uFF0C\u5E76\u7ECF\u5B98\u65B9\u5DE5\u5177\u5BA1\u6279\u3002\u8BBE\u7F6E\u4F4D\u4E8E\u201C\u63D2\u4EF6 \u2192 \u5DF2\u5B89\u88C5 \u2192 @ljwei-stak/model-router-galgame\u201D\u3002")));
12734
12761
  }
12735
12762
 
12736
12763
  // .dsh-plugin/shared/official-tools-remote.mjs
@@ -7,6 +7,7 @@ import { defineTool } from '@deepseek-ai/dsh-tools'
7
7
  import { DEFAULT_ROUTER_SETTINGS, modelMetadata } from './shared/router.mjs'
8
8
  import { DEFAULT_ROUTING_PRESET, normalizeRoutingPreset, routingPreset } from './shared/routing-presets.mjs'
9
9
  import { HEALTH_CACHE_MS, apiKeyEnvPresent, healthCache, runHealthCheck, subscriptionLoginOf } from './shared/tool-health.mjs'
10
+ import { latestVersions } from './shared/latest-versions.mjs'
10
11
  import {
11
12
  DEFAULT_COOLDOWN_MINUTES, billingOverview, createQuotaTracker, detectQuotaExhaustion, parseQuotaPatterns, vendorKey,
12
13
  } from './shared/subscription-billing.mjs'
@@ -28,6 +29,7 @@ import {
28
29
  parseTerminalWrite,
29
30
  } from './shared/cli-terminal-protocol.mjs'
30
31
  import {
32
+ OFFICIAL_TOOLS,
31
33
  getOfficialTool,
32
34
  installCommandLine,
33
35
  toolForProvider,
@@ -293,9 +295,13 @@ const readAuthState = async path => {
293
295
  }
294
296
 
295
297
  /** 开箱体检: install, version and login state for every registry tool. */
296
- export async function toolHealthReport({ fresh = false, runner = defaultRunner } = {}) {
297
- const probes = await probeAllTools({ fresh })
298
- const report = await runHealthCheck(probes, { runner, home: homedir(), exists: fileExists, readAuthState })
298
+ export async function toolHealthReport({ fresh = false, runner = defaultRunner, latest = latestVersions } = {}) {
299
+ // Latest-version lookups run alongside the probes; failures are non-fatal (offline-safe).
300
+ const [probes, latestById] = await Promise.all([
301
+ probeAllTools({ fresh }),
302
+ latest.lookupAll(OFFICIAL_TOOLS).catch(() => ({})),
303
+ ])
304
+ const report = await runHealthCheck(probes, { runner, home: homedir(), exists: fileExists, readAuthState, latest: latestById })
299
305
  healthCache.remember(report)
300
306
  try { await routerStateStore().saveHealth(report) } catch { /* the cache still serves this process */ }
301
307
  return report
@@ -957,7 +963,7 @@ export async function planToolRun(ctx, config, args = {}, { signal } = {}) {
957
963
  }
958
964
  if (text(args.cliModel)) {
959
965
  if (!route) throw new Error('cliModel 需要同时提供已配置的 provider 和 model 路线')
960
- if (toolId === 'zcode') throw new Error('ZCode 3.14.3 不支持在单次调用中指定 CLI 模型')
966
+ if (toolId === 'zcode') throw new Error('ZCode CLI 不支持在单次调用中指定模型')
961
967
  modelId = text(args.cliModel)
962
968
  }
963
969
  const estimate = route ? createPlanFromRoutes(taskText, routes, { mode: 'direct', directProvider: route.provider, directModel: route.model }).estimatedCost : null
@@ -1503,7 +1509,7 @@ function registerOfficialToolModels(ctx, config) {
1503
1509
  }))
1504
1510
  ctx.tools.register(defineTool({
1505
1511
  name: 'model_router_tool_install',
1506
- description: 'Install one official model tool by registry id using its pinned official source. ZCode opens a verified interactive desktop installer with a directory picker. Only registry ids are accepted; arbitrary packages or executables are refused.',
1512
+ description: 'Install one official model tool by registry id from its fixed official source at the vendor latest release. ZCode opens the latest publisher-signed interactive desktop installer with a directory picker. Only registry ids are accepted; arbitrary packages or executables are refused.',
1507
1513
  parameters: {
1508
1514
  tool: { type: 'string', required: true, description: 'Registry tool id, e.g. kimi-code.' },
1509
1515
  },
@@ -1532,7 +1538,7 @@ function registerOfficialToolModels(ctx, config) {
1532
1538
  task: { type: 'string', required: true, description: 'Concrete task for the official CLI model.' },
1533
1539
  provider: { type: 'string', description: 'Optional configured provider, paired with model.' },
1534
1540
  model: { type: 'string', description: 'Optional model ID from the Harness directory, paired with provider. This ID is advisory for CLIs except Claude/Codex.' },
1535
- cliModel: { type: 'string', description: 'Optional model name already configured in this vendor CLI; requires provider and model. MiniMax/MiMo require provider/model format. ZCode 3.14.3 cannot switch models per call.' },
1541
+ cliModel: { type: 'string', description: 'Optional model name already configured in this vendor CLI; requires provider and model. MiniMax/MiMo require provider/model format. ZCode cannot switch models per call.' },
1536
1542
  mode: { type: 'string', enum: ['read-only', 'workspace-write'], description: 'Default is read-only. Kimi, MiniMax and ZCode require workspace-write. Write mode requires official approval and a clean Git repository.' },
1537
1543
  confirmOverBudget: { type: 'boolean', description: 'Set only after the user agreed to exceed the daily/monthly budget. Triggers an approval prompt.' },
1538
1544
  },
@@ -1597,7 +1603,7 @@ function registerOfficialToolModels(ctx, config) {
1597
1603
  }))
1598
1604
  ctx.tools.register(defineTool({
1599
1605
  name: 'model_router_health',
1600
- description: 'Onboarding health check: for each official CLI in the fixed registry, report installed, version vs pinned version, and login state (cheap status commands only; never starts a login), plus a per-provider billing table: billing mode (subscription-first by default), subscription state (logged in / coding-plan key route / exhausted until a time) and whether an API-key route is available for fallback. Logged-out tools are skipped by routing until re-checked.',
1606
+ description: 'Onboarding health check: for each official CLI in the fixed registry, report installed version, the latest published version when it can be looked up cheaply (update hint only), and login state (cheap status commands only; never starts a login), plus a per-provider billing table: billing mode (subscription-first by default), subscription state (logged in / coding-plan key route / exhausted until a time) and whether an API-key route is available for fallback. Logged-out tools are skipped by routing until re-checked.',
1601
1607
  parameters: {
1602
1608
  fresh: { type: 'boolean', description: 'Re-probe instead of using the 60s probe cache.' },
1603
1609
  },
@@ -1658,7 +1664,7 @@ function registerOfficialToolModels(ctx, config) {
1658
1664
  task: { type: 'string', required: true, description: 'Full task to plan, distribute and execute.' },
1659
1665
  mode: { type: 'string', enum: ['read-only', 'workspace-write'], description: 'Default read-only; workspace-write needs a clean Git repository and approval.' },
1660
1666
  budgetUsd: { type: 'number', description: 'Estimated planning ceiling only, not a vendor billing limit.' },
1661
- cliModelsJson: { type: 'string', description: 'Optional JSON object mapping official tool IDs or work package IDs to exact model names configured in those CLIs. MiniMax/MiMo require provider/model; ZCode 3.14.3 cannot switch per call.' },
1667
+ cliModelsJson: { type: 'string', description: 'Optional JSON object mapping official tool IDs or work package IDs to exact model names configured in those CLIs. MiniMax/MiMo require provider/model; ZCode cannot switch per call.' },
1662
1668
  confirmOverBudget: { type: 'boolean', description: 'Set only after the user agreed to exceed the daily/monthly budget. Triggers an approval prompt.' },
1663
1669
  },
1664
1670
  output: JSON_OUTPUT,
@@ -38,7 +38,7 @@ export function channelForProvider(provider, installedToolIds = [], runnableTool
38
38
  return {
39
39
  kind: 'official-cli', preference, tool: tool.id, label: tool.label,
40
40
  detail: tool.id === 'zcode'
41
- ? 'ZCode 已安装,插件可调用其官方编程代理;3.14.3 的 CLI 使用自身配置的默认模型,不能保证与 Harness 建议模型一致。'
41
+ ? 'ZCode 已安装,插件可调用其官方编程代理;其 CLI 使用自身配置的默认模型,不能保证与 Harness 建议模型一致。'
42
42
  : headless && !runnable
43
43
  ? `${tool.label} 已安装。分配到该模型的任务会先走官方无界面命令;命令缺失或失败时回退模型目录 API。`
44
44
  : `${tool.label} 已安装,插件可托管调用其官方 CLI;Harness 模型目录与厂商 CLI 名称可能不同,团队无法确认映射时使用 CLI 默认模型,实际模型仍须核对运行记录。`,