@ljwei-stak/dsh-model-router 0.16.0 → 0.16.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.
@@ -1591,18 +1591,27 @@ function applyQualityBiases(routes, biases) {
1591
1591
  var finite2 = (value) => typeof value === "number" && Number.isFinite(value);
1592
1592
  var clean3 = (value) => typeof value === "string" ? value.trim() : "";
1593
1593
  var routeKey3 = (provider, model) => `${provider}\0${model}`;
1594
+ var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1594
1595
  function applyFeedbackProfile(routes, profile) {
1595
- if (!Array.isArray(routes) || profile?.enabled !== true || !profile.adjustments || typeof profile.adjustments !== "object" || Array.isArray(profile.adjustments)) return routes;
1596
+ if (!Array.isArray(routes) || !record(profile) || typeof profile.enabled !== "boolean") return routes;
1596
1597
  return routes.map((route) => {
1597
- if (!route || typeof route !== "object") return route;
1598
+ if (!record(route)) return route;
1599
+ let base = route;
1600
+ if (Object.hasOwn(route, "preferenceAdjustments") || Object.hasOwn(route, "preferenceAdjustmentMeta")) {
1601
+ base = { ...route };
1602
+ delete base.preferenceAdjustments;
1603
+ delete base.preferenceAdjustmentMeta;
1604
+ }
1605
+ if (profile.enabled !== true || !record(profile.adjustments)) return base;
1598
1606
  const key = routeKey3(clean3(route.provider), clean3(route.model));
1599
- if (!Object.hasOwn(profile.adjustments, key)) return route;
1607
+ if (!Object.hasOwn(profile.adjustments, key)) return base;
1600
1608
  const value = profile.adjustments[key];
1601
- if (!value || typeof value !== "object" || Array.isArray(value)) return route;
1602
- const adjustments = Object.fromEntries(Object.entries(value).filter(([, bias]) => finite2(bias) && Math.abs(bias) <= 0.1));
1603
- if (!Object.keys(adjustments).length) return route;
1609
+ if (!record(value)) return base;
1610
+ const limit = finite2(profile.maxAdjustment) && profile.maxAdjustment >= 0 && profile.maxAdjustment <= 0.1 ? profile.maxAdjustment : 0.1;
1611
+ const adjustments = Object.fromEntries(Object.entries(value).filter(([, bias]) => finite2(bias) && Math.abs(bias) <= limit));
1612
+ if (!Object.keys(adjustments).length) return base;
1604
1613
  return {
1605
- ...route,
1614
+ ...base,
1606
1615
  preferenceAdjustments: adjustments,
1607
1616
  preferenceAdjustmentMeta: {
1608
1617
  policyVersion: profile.policyVersion,
@@ -1613,7 +1622,11 @@ function applyFeedbackProfile(routes, profile) {
1613
1622
  updatedAt: profile.updatedAt,
1614
1623
  halfLifeDays: profile.halfLifeDays,
1615
1624
  maxAdjustment: profile.maxAdjustment,
1616
- window: profile.window
1625
+ window: profile.window,
1626
+ cellStats: Object.hasOwn(profile.cellStats ?? {}, key) ? profile.cellStats[key] : {},
1627
+ evaluatedAt: profile.evaluatedAt,
1628
+ decayRefreshMs: profile.decayRefreshMs,
1629
+ revisionSemantics: profile.revisionSemantics
1617
1630
  }
1618
1631
  };
1619
1632
  });
@@ -1863,33 +1876,73 @@ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
1863
1876
  } }, "\u5220\u9664\u6B64\u6A21\u578B\u914D\u7F6E")), notice && /* @__PURE__ */ import_react.default.createElement("p", { className: notice.tone === "error" ? "mr-error" : "mr-profile-success", role: notice.tone === "error" ? "alert" : "status" }, notice.text), /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-caption" }, "\u8D28\u91CF\u8BC4\u5206\u548C\u4EF7\u683C\u90FD\u662F\u7528\u6237\u63D0\u4F9B\u7684\u4F30\u503C\u3002\u672A\u586B\u5199\u5355\u4EF7\u65F6\u663E\u793A\u201C\u4EF7\u683C\u5F85\u914D\u7F6E\u201D\uFF1B\u9884\u7B97\u53EA\u5F71\u54CD\u672C\u5730\u89C4\u5212\uFF0C\u4E0D\u9650\u5236\u5B9E\u9645\u8D26\u5355\u3002CLI \u6A21\u578B\u540D\u987B\u4E0E\u5382\u5546\u5DE5\u5177\u6838\u5BF9\u3002\u6267\u884C\u65B9\u5F0F\u51B3\u5B9A\u8BE5\u6A21\u578B\u6536\u5230\u4EFB\u52A1\u65F6\u8D70\u5B98\u65B9\u65E0\u754C\u9762\u5DE5\u5177\u8FD8\u662F\u6A21\u578B\u76EE\u5F55 API\uFF1B\u5B98\u65B9\u5DE5\u5177\u5931\u8D25\u65F6\u4ECD\u4F1A\u56DE\u9000 API\u3002\u8BA1\u8D39\u65B9\u5F0F\u9ED8\u8BA4\u8BA2\u9605\u4F18\u5148\uFF1A\u5148\u7528 CLI \u8D26\u53F7\u767B\u5F55\u6216\u7F16\u7A0B\u5957\u9910 Key \u8DEF\u7EBF\uFF0C\u8BA2\u9605\u989D\u5EA6\u7528\u5C3D\u6216\u9650\u6D41\u65F6\u540C\u4E00\u6B65\u9AA4\u81EA\u52A8\u6539\u7528 API Key\uFF0C\u5E76\u8BB0\u5165\u8FD0\u884C\u5386\u53F2\u3002"))));
1864
1877
  }
1865
1878
 
1866
- // .dsh-plugin/client/tool-install-state.mjs
1867
- function stableVersionOrder(left, right) {
1868
- const parse = (value) => /^([0-9]+)\.([0-9]+)\.([0-9]+)$/.exec(String(value ?? ""));
1869
- const current = parse(left);
1870
- const target = parse(right);
1871
- if (!current || !target) return null;
1872
- for (let index = 1; index <= 3; index += 1) {
1873
- const delta = Number(current[index]) - Number(target[index]);
1874
- if (delta) return Math.sign(delta);
1879
+ // .dsh-plugin/shared/version-order.mjs
1880
+ var VERSION = /^(\d{1,6})\.(\d{1,6})\.(\d{1,6})(?:-[0-9A-Za-z.-]{1,64})?$/;
1881
+ function compareReleaseVersions(left, right) {
1882
+ const parse = (value) => {
1883
+ const match = VERSION.exec(String(value ?? ""));
1884
+ return match ? { parts: match.slice(1, 4).map(Number), pre: String(value).includes("-") } : null;
1885
+ };
1886
+ const a = parse(left);
1887
+ const b2 = parse(right);
1888
+ if (!a || !b2) return null;
1889
+ for (let index = 0; index < 3; index += 1) {
1890
+ if (a.parts[index] !== b2.parts[index]) return a.parts[index] > b2.parts[index] ? 1 : -1;
1875
1891
  }
1892
+ if (a.pre !== b2.pre) return a.pre ? -1 : 1;
1876
1893
  return 0;
1877
1894
  }
1895
+
1896
+ // .dsh-plugin/client/tool-install-state.mjs
1878
1897
  function toolInstallAction({ tool, probe, readiness, job, probeStatus, latestVersion = null }) {
1879
1898
  const running = job?.status === "running";
1880
1899
  const installed = probe?.installed === true;
1881
- const order = installed && latestVersion ? stableVersionOrder(probe.version, latestVersion) : null;
1900
+ const order = installed && latestVersion ? compareReleaseVersions(probe.version, latestVersion) : null;
1882
1901
  const ready = readiness?.ready === true;
1883
1902
  const desktop = tool.manager === "signed-windows-installer";
1884
1903
  const noRunner = desktop || tool.headlessAdapter === true;
1885
1904
  const repair = installed && !noRunner && readiness?.ready === false;
1886
1905
  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";
1887
1906
  const current = order === 0 && (ready || noRunner);
1907
+ const interactive = probeStatus === "ready" || probeStatus === "refreshing";
1888
1908
  return {
1889
1909
  label,
1890
- disabled: probeStatus !== "ready" || running || installed && (order === 1 || current)
1910
+ disabled: !interactive || running || installed && (order === 1 || current)
1891
1911
  };
1892
1912
  }
1913
+ function installClickRefusal({ tool, submitting = false, running = false } = {}) {
1914
+ if (!tool) return "\u672A\u77E5\u5B98\u65B9\u5DE5\u5177\uFF0C\u65E0\u6CD5\u5F00\u59CB\u5B89\u88C5\u3002";
1915
+ if (tool.unsupported) return String(tool.unsupportedReason ?? "").trim() || "\u6B64\u5DE5\u5177\u6682\u4E0D\u652F\u6301\u4E00\u952E\u5B89\u88C5\u3002";
1916
+ if (submitting || running) return "\u8BE5\u5DE5\u5177\u6B63\u5728\u5B89\u88C5\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u3002";
1917
+ return "";
1918
+ }
1919
+ function payloadError(payload, fallback) {
1920
+ if (!payload || typeof payload !== "object") return fallback;
1921
+ if (typeof payload.error === "string" && payload.error.trim()) return payload.error.trim();
1922
+ const message = payload.error?.message;
1923
+ if (typeof message === "string" && message.trim()) return message.trim();
1924
+ return fallback;
1925
+ }
1926
+ function acceptedInstallJob(response) {
1927
+ const fallback = "\u5B89\u88C5\u4EFB\u52A1\u672A\u88AB\u63A5\u53D7\u3002";
1928
+ if (!response || typeof response !== "object") return { job: null, error: fallback };
1929
+ let payload = response;
1930
+ if (payload.ok === false) return { job: null, error: payloadError(payload, fallback) };
1931
+ if (payload.ok === true && payload.value && typeof payload.value === "object") {
1932
+ payload = payload.value;
1933
+ if (payload.ok === false) return { job: null, error: payloadError(payload, fallback) };
1934
+ if (payload.ok === true && payload.value && typeof payload.value === "object") payload = payload.value;
1935
+ }
1936
+ if (payload.accepted === true && payload.job && typeof payload.job === "object") return { job: payload.job, error: "" };
1937
+ return { job: null, error: payloadError(payload, fallback) };
1938
+ }
1939
+ function shouldApplyInstallStatus(localJob, remoteJob) {
1940
+ if (!remoteJob || typeof remoteJob !== "object") return false;
1941
+ const localStarted = typeof localJob?.startedAt === "string" ? localJob.startedAt : "";
1942
+ const remoteStarted = typeof remoteJob.startedAt === "string" ? remoteJob.startedAt : "";
1943
+ if (!localStarted || !remoteStarted) return true;
1944
+ return remoteStarted >= localStarted;
1945
+ }
1893
1946
 
1894
1947
  // .dsh-plugin/client/router-insights.jsx
1895
1948
  var import_react2 = __toESM(require("react"), 1);
@@ -2176,8 +2229,10 @@ function feedbackRatingArguments(run, item, direction) {
2176
2229
  var nonnegative2 = (value) => Number.isFinite(value) && value >= 0 ? value : 0;
2177
2230
  function learningView(learning, settings = {}) {
2178
2231
  return {
2179
- available: Boolean(learning && typeof learning === "object"),
2180
- enabled: typeof learning?.enabled === "boolean" ? learning.enabled : adaptiveSettingValue(settings, "feedbackLearningEnabled") !== false,
2232
+ available: Boolean(learning && typeof learning === "object" && !Array.isArray(learning)),
2233
+ // Current settings govern the next plan; a failed refresh must not make an
2234
+ // older profile claim that a newly disabled policy is still enabled.
2235
+ enabled: adaptiveSettingValue(settings, "feedbackLearningEnabled") !== false,
2181
2236
  feedbackCount: nonnegative2(learning?.feedbackCount),
2182
2237
  ignoredCount: nonnegative2(learning?.ignoredCount),
2183
2238
  effectiveWeight: nonnegative2(learning?.effectiveWeight),
@@ -2185,18 +2240,71 @@ function learningView(learning, settings = {}) {
2185
2240
  resetAt: nonnegative2(adaptiveSettingValue(settings, "feedbackResetAt"))
2186
2241
  };
2187
2242
  }
2243
+ function learningEvidenceRows(learning, limit = 12) {
2244
+ const cells = learning?.cellStats;
2245
+ if (!cells || typeof cells !== "object" || Array.isArray(cells)) return { rows: [], total: 0 };
2246
+ const rows = [];
2247
+ for (const [key, domains] of Object.entries(cells)) {
2248
+ const identity = key.split("\0");
2249
+ if (identity.length !== 2 || identity.some((part) => !part.trim()) || !domains || typeof domains !== "object" || Array.isArray(domains)) continue;
2250
+ for (const [domain, cell] of Object.entries(domains)) {
2251
+ if (!domain.trim() || !cell || typeof cell !== "object" || Array.isArray(cell) || !Number.isFinite(cell.adjustment) || Math.abs(cell.adjustment) > 0.1 || ["feedbackCount", "positiveCount", "negativeCount", "effectiveWeight", "effectiveSampleSize"].some((name) => !Number.isFinite(cell[name]) || cell[name] < 0) || !Number.isFinite(cell.shrinkage) || cell.shrinkage < 0 || cell.shrinkage > 1) continue;
2252
+ rows.push({
2253
+ id: JSON.stringify([key, domain]),
2254
+ route: identity.map((part) => part.slice(0, 100)).join("/"),
2255
+ domain: domain.slice(0, 80),
2256
+ feedbackCount: nonnegative2(cell.feedbackCount),
2257
+ positiveCount: nonnegative2(cell.positiveCount),
2258
+ negativeCount: nonnegative2(cell.negativeCount),
2259
+ effectiveWeight: nonnegative2(cell.effectiveWeight),
2260
+ effectiveSampleSize: nonnegative2(cell.effectiveSampleSize),
2261
+ shrinkage: Number.isFinite(cell.shrinkage) && cell.shrinkage >= 0 && cell.shrinkage <= 1 ? cell.shrinkage : 0,
2262
+ adjustment: cell.adjustment
2263
+ });
2264
+ }
2265
+ }
2266
+ rows.sort((left, right) => left.route === right.route ? left.domain.localeCompare(right.domain) : left.route.localeCompare(right.route));
2267
+ const count = Number.isInteger(limit) && limit > 0 ? Math.min(limit, 50) : 12;
2268
+ return { rows: rows.slice(0, count), total: rows.length };
2269
+ }
2270
+ var EXCLUSION_LABELS = Object.freeze({
2271
+ "unrated": "\u5C1A\u672A\u8BC4\u4EF7\uFF08\u4E0D\u662F\u4E0D\u6EE1\u610F\uFF09",
2272
+ "not-successful": "\u6CA1\u6709\u6210\u529F\u6267\u884C\u7ED3\u679C",
2273
+ "cli-model-unverified": "CLI \u5B9E\u9645\u6A21\u578B\u672A\u6838\u9A8C",
2274
+ "before-reset": "\u7ED3\u679C\u65E9\u4E8E\u5B66\u4E60\u8D77\u70B9",
2275
+ "superseded": "\u5DF2\u88AB\u540C\u4E00\u7ED3\u679C\u7684\u65B0\u8BB0\u5F55\u66FF\u4EE3",
2276
+ "missing-identity": "\u7F3A\u5C11\u8FD0\u884C\u6216\u6B65\u9AA4\u6807\u8BC6",
2277
+ "invalid-route": "\u8DEF\u7EBF\u6807\u8BC6\u65E0\u6548",
2278
+ "invalid-time": "\u7ED3\u679C\u6216\u8BC4\u4EF7\u65F6\u95F4\u65E0\u6548",
2279
+ "future-time": "\u65F6\u95F4\u665A\u4E8E\u5F53\u524D\u65F6\u523B"
2280
+ });
2281
+ function learningExclusionRows(learning) {
2282
+ return Object.entries(EXCLUSION_LABELS).flatMap(([reason, label]) => {
2283
+ const count = nonnegative2(learning?.exclusionReasons?.[reason]);
2284
+ return count > 0 ? [{ reason, label, count }] : [];
2285
+ });
2286
+ }
2188
2287
  var STATUS_LABEL = Object.freeze({ disabled: "\u672A\u542F\u7528", missing: "\u5C1A\u65E0\u5FEB\u7167", fresh: "\u5FEB\u7167\u6709\u6548", stale: "\u5FEB\u7167\u8FC7\u671F", error: "\u66F4\u65B0\u5931\u8D25" });
2189
- function dynamicSourceView(source) {
2190
- const status = Object.hasOwn(STATUS_LABEL, source?.status ?? "") ? source.status : "missing";
2288
+ var PUBLIC_ERROR_CODES = /* @__PURE__ */ new Set(["refresh-failed", "snapshot-rollback-rejected", "storage-failed", "refresh-interrupted"]);
2289
+ var positiveTime = (value) => Number.isFinite(value) && value > 0 ? value : null;
2290
+ function dynamicSourceView(source, enabled = true) {
2291
+ const status = enabled === false ? "disabled" : Object.hasOwn(STATUS_LABEL, source?.status ?? "") ? source.status : "missing";
2191
2292
  let publicSource = "";
2192
- if (typeof source?.source === "string") publicSource = publicEndpointDraft("pricingSnapshotEndpoint", source.source);
2293
+ if (enabled !== false && typeof source?.source === "string") publicSource = publicEndpointDraft("pricingSnapshotEndpoint", source.source);
2193
2294
  return {
2194
2295
  status,
2195
2296
  label: STATUS_LABEL[status],
2196
2297
  source: publicSource,
2197
- version: typeof source?.version === "string" ? source.version.slice(0, 160) : null,
2198
- verifiedAt: Number.isFinite(source?.verifiedAt) && source.verifiedAt > 0 ? source.verifiedAt : null,
2199
- count: nonnegative2(source?.modelCount ?? source?.rowCount)
2298
+ version: enabled !== false && typeof source?.version === "string" ? source.version.slice(0, 160) : null,
2299
+ verifiedAt: enabled !== false && Number.isFinite(source?.verifiedAt) && source.verifiedAt > 0 ? source.verifiedAt : null,
2300
+ count: enabled === false ? 0 : nonnegative2(source?.modelCount ?? source?.rowCount),
2301
+ refreshing: enabled !== false && source?.refreshing === true,
2302
+ pending: enabled !== false && source?.pending === true,
2303
+ lastAttemptAt: enabled === false ? null : positiveTime(source?.lastAttemptAt),
2304
+ lastSuccessAt: enabled === false ? null : positiveTime(source?.lastSuccessAt),
2305
+ errorCode: enabled !== false && PUBLIC_ERROR_CODES.has(source?.error) ? source.error : "",
2306
+ endpoint: enabled === false ? "" : publicEndpointDraft("pricingSnapshotEndpoint", source?.configuredEndpoint ?? source?.endpoint ?? ""),
2307
+ lastGoodEndpoint: enabled === false ? "" : publicEndpointDraft("pricingSnapshotEndpoint", source?.lastGoodEndpoint ?? "")
2200
2308
  };
2201
2309
  }
2202
2310
 
@@ -2234,21 +2342,36 @@ function Meter({ label, meter }) {
2234
2342
  function useSettingsWriter(settingsScope) {
2235
2343
  const [snapshot, setSnapshot] = import_react2.default.useState(() => settingsScope.getSnapshot());
2236
2344
  const [notice, setNotice] = import_react2.default.useState("");
2345
+ const [busy, setBusy] = import_react2.default.useState(false);
2346
+ const pending = import_react2.default.useRef(false);
2347
+ const mounted = import_react2.default.useRef(true);
2348
+ import_react2.default.useEffect(() => {
2349
+ mounted.current = true;
2350
+ return () => {
2351
+ mounted.current = false;
2352
+ };
2353
+ }, []);
2237
2354
  import_react2.default.useEffect(() => settingsScope.subscribe(() => setSnapshot(settingsScope.getSnapshot())), [settingsScope]);
2238
- const writable = snapshot.status === "ready" && snapshot.writable === true;
2355
+ const writable = snapshot.status === "ready" && snapshot.writable === true && !busy;
2239
2356
  const write = async (key, value) => {
2240
- if (!writable) return false;
2357
+ const current = settingsScope.getSnapshot();
2358
+ if (pending.current || current.status !== "ready" || current.writable !== true) return false;
2359
+ pending.current = true;
2360
+ setBusy(true);
2241
2361
  setNotice("");
2242
2362
  try {
2243
- const accepted = await settingsScope.mutate([{ op: "set", path: [key], value }], snapshot.revision);
2244
- if (!accepted) setNotice("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u53EF\u80FD\u5DF2\u5728\u5176\u4ED6\u9875\u9762\u4FEE\u6539\uFF0C\u8BF7\u91CD\u8BD5\u3002");
2363
+ const accepted = await settingsScope.mutate([{ op: "set", path: [key], value }], current.revision);
2364
+ if (!accepted && mounted.current) setNotice("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u53EF\u80FD\u5DF2\u5728\u5176\u4ED6\u9875\u9762\u4FEE\u6539\uFF0C\u8BF7\u91CD\u8BD5\u3002");
2245
2365
  return accepted;
2246
2366
  } catch (error) {
2247
- setNotice(text(error?.message) || "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
2367
+ if (mounted.current) setNotice(text(error?.message) || "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
2248
2368
  return false;
2369
+ } finally {
2370
+ pending.current = false;
2371
+ if (mounted.current) setBusy(false);
2249
2372
  }
2250
2373
  };
2251
- return { value: snapshot.value ?? {}, writable, write, notice };
2374
+ return { value: snapshot.value ?? {}, writable, busy, write, notice };
2252
2375
  }
2253
2376
  var ADAPTIVE_FIELD_LABEL = {
2254
2377
  feedbackHalfLifeDays: "\u53CD\u9988\u534A\u8870\u671F\uFF08\u5929\uFF09",
@@ -2260,12 +2383,18 @@ function AdaptiveNumberControl({ field: field2, value, writable, onSave }) {
2260
2383
  const [draft, setDraft] = import_react2.default.useState("");
2261
2384
  const [notice, setNotice] = import_react2.default.useState("");
2262
2385
  const save = async () => {
2386
+ let next;
2263
2387
  try {
2264
- const next = parseAdaptiveNumber(field2.key, draft);
2265
- setNotice("");
2266
- if (await onSave(field2.key, next)) setDraft("");
2388
+ next = parseAdaptiveNumber(field2.key, draft);
2267
2389
  } catch {
2268
2390
  setNotice(`\u8BF7\u8F93\u5165 ${field2.min} \u5230 ${field2.max} \u7684\u6570\u5B57\u3002`);
2391
+ return;
2392
+ }
2393
+ setNotice("");
2394
+ try {
2395
+ if (await onSave(field2.key, next)) setDraft((current) => current === draft ? "" : current);
2396
+ } catch {
2397
+ setNotice("\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
2269
2398
  }
2270
2399
  };
2271
2400
  return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-control-label", htmlFor: `mr-${field2.key}` }, ADAPTIVE_FIELD_LABEL[field2.key]), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement(
@@ -2291,12 +2420,18 @@ function PublicEndpointControl({ name, label, value, writable, onSave }) {
2291
2420
  const [notice, setNotice] = import_react2.default.useState("");
2292
2421
  const current = publicEndpointDraft(name, value);
2293
2422
  const save = async () => {
2423
+ let next;
2294
2424
  try {
2295
- const next = parsePublicEndpoint(name, draft ?? current);
2296
- setNotice("");
2297
- if (await onSave(name, next)) setDraft(null);
2425
+ next = parsePublicEndpoint(name, draft ?? current);
2298
2426
  } catch {
2299
2427
  setNotice("\u8BF7\u8F93\u5165\u4E0D\u542B\u8BA4\u8BC1\u3001\u67E5\u8BE2\u53C2\u6570\u6216\u7247\u6BB5\u7684\u516C\u5F00 HTTPS \u5730\u5740\uFF1B\u4EF7\u683C\u5FEB\u7167\u53EF\u7559\u7A7A\u3002");
2428
+ return;
2429
+ }
2430
+ setNotice("");
2431
+ try {
2432
+ if (await onSave(name, next)) setDraft((currentDraft) => currentDraft === draft ? null : currentDraft);
2433
+ } catch {
2434
+ setNotice("\u5730\u5740\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002");
2300
2435
  }
2301
2436
  };
2302
2437
  return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-control-label", htmlFor: `mr-${name}` }, label), /* @__PURE__ */ import_react2.default.createElement(
@@ -2315,25 +2450,42 @@ function PublicEndpointControl({ name, label, value, writable, onSave }) {
2315
2450
  void save();
2316
2451
  } }, "\u4FDD\u5B58\u5730\u5740"), notice && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-error", role: "alert" }, notice));
2317
2452
  }
2318
- function PublicSourceStatus({ label, source }) {
2319
- const view = dynamicSourceView(source);
2320
- return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, label, "\uFF1A", view.label), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, view.version ? `\u7248\u672C ${view.version} \xB7 ` : "", view.count, " \u6761\u8BB0\u5F55", view.verifiedAt ? ` \xB7 \u6700\u8FD1\u6821\u9A8C ${new Date(view.verifiedAt).toLocaleString()}` : ""), view.source && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u516C\u5F00\u6765\u6E90\uFF1A", view.source), view.status === "error" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u66F4\u65B0\u5931\u8D25\uFF1B\u662F\u5426\u53EF\u7528\u7531 Host \u6821\u9A8C\uFF0C\u4E0D\u5C06\u7F3A\u5931\u6570\u636E\u5F53\u4F5C\u96F6\u6210\u672C\u6216\u6EE1\u5206\u3002"));
2453
+ function PublicSourceStatus({ label, source, enabled }) {
2454
+ const view = dynamicSourceView(source, enabled);
2455
+ return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, label, "\uFF1A", view.label), view.status !== "disabled" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, view.version ? `\u7248\u672C ${view.version} \xB7 ` : "", view.count, " \u6761\u8BB0\u5F55", view.verifiedAt ? ` \xB7 \u6700\u8FD1\u6821\u9A8C ${new Date(view.verifiedAt).toLocaleString()}` : ""), view.source && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u516C\u5F00\u6765\u6E90\uFF1A", view.source), (view.refreshing || view.pending) && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption", role: "status" }, "\u516C\u5F00\u6E90\u6B63\u5728\u5237\u65B0\uFF1B\u4E0A\u9762\u7684\u7248\u672C\u4ECD\u662F\u6700\u8FD1\u4E00\u6B21\u5DF2\u4FDD\u5B58\u5FEB\u7167\uFF0C\u4E0D\u662F\u672C\u6B21\u8BF7\u6C42\u5DF2\u6210\u529F\u3002"), view.lastAttemptAt && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u6700\u8FD1\u5C1D\u8BD5 ", new Date(view.lastAttemptAt).toLocaleString(), view.lastSuccessAt ? ` \xB7 \u6700\u8FD1\u6210\u529F ${new Date(view.lastSuccessAt).toLocaleString()}` : ""), view.status === "error" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u66F4\u65B0\u5931\u8D25\uFF1B\u662F\u5426\u53EF\u7528\u7531 Host \u6821\u9A8C\uFF0C\u4E0D\u5C06\u7F3A\u5931\u6570\u636E\u5F53\u4F5C\u96F6\u6210\u672C\u6216\u6EE1\u5206\u3002"), view.status === "stale" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u4E0A\u6B21\u6709\u6548\u5FEB\u7167\u5DF2\u8FC7\u671F\u6216\u672C\u6B21\u66F4\u65B0\u5931\u8D25\uFF1BHost \u53EF\u80FD\u6CBF\u7528\u65E7\u6570\u636E\uFF0C\u4E0D\u80FD\u5F53\u4F5C\u6700\u65B0\u4EF7\u683C\u6216\u80FD\u529B\u3002"), view.errorCode === "storage-failed" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u672C\u6B21\u72B6\u6001\u4FDD\u5B58\u5931\u8D25\uFF1B\u53EA\u80FD\u4F7F\u7528\u6B64\u524D\u5DF2\u4FDD\u5B58\u7684\u5F53\u524D\u6E90\u5FEB\u7167\uFF0C\u8BF7\u91CD\u8BD5\u5237\u65B0\u3002"), view.errorCode === "refresh-interrupted" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u4E0A\u6B21\u516C\u5F00\u6570\u636E\u5237\u65B0\u4E2D\u65AD\uFF1B\u8BF7\u5237\u65B0\u6458\u8981\u67E5\u770B Host \u7684\u540E\u7EED\u91CD\u8BD5\u72B6\u6001\u3002"), view.lastGoodEndpoint && view.endpoint && view.lastGoodEndpoint !== view.endpoint && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u6B64\u524D\u6765\u6E90\u7684\u6709\u6548\u5FEB\u7167\u4ECD\u4FDD\u7559\u5728\u672C\u5730\uFF0C\u4F46\u4E0D\u5E94\u7528\u5230\u5F53\u524D\u516C\u5F00\u6E90\u3002"), view.status === "disabled" && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u5F53\u524D\u8BBE\u7F6E\u4E0D\u4F7F\u7528\u6B64\u516C\u5F00\u6E90\uFF1B\u4FDD\u7559\u7684\u5386\u53F2\u5FEB\u7167\u4E0D\u4EE3\u8868\u6B63\u5728\u4F7F\u7528\u3002"));
2456
+ }
2457
+ function LearningEvidence({ learning }) {
2458
+ const evidence = learningEvidenceRows(learning);
2459
+ const exclusions = learningExclusionRows(learning);
2460
+ return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, evidence.total > 0 && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u5206\u6A21\u578B / \u4EFB\u52A1\u7C7B\u578B\u7684\u5DF2\u89C2\u5BDF\u53CD\u9988\uFF08", evidence.total, " \u7EC4\uFF09"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u53EA\u63CF\u8FF0\u5DF2\u9009\u62E9\u5E76\u83B7\u5F97\u8BC4\u4EF7\u7684\u7ED3\u679C\uFF0C\u4E0D\u4EE3\u8868\u6240\u6709\u6A21\u578B\u7684\u771F\u5B9E\u8D28\u91CF\u6216\u6536\u76CA\uFF1B\u6709\u6548\u6837\u672C\u91CF\u53CD\u6620\u6743\u91CD\u96C6\u4E2D\u7A0B\u5EA6\uFF0C\u4E0D\u662F\u8D28\u91CF\u7F6E\u4FE1\u5EA6\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-table-wrap" }, /* @__PURE__ */ import_react2.default.createElement("table", { className: "mr-table" }, /* @__PURE__ */ import_react2.default.createElement("thead", null, /* @__PURE__ */ import_react2.default.createElement("tr", null, /* @__PURE__ */ import_react2.default.createElement("th", null, "\u8DEF\u7EBF / \u4EFB\u52A1\u7C7B\u578B"), /* @__PURE__ */ import_react2.default.createElement("th", null, "\u6709\u7528 / \u4E0D\u597D"), /* @__PURE__ */ import_react2.default.createElement("th", null, "\u504F\u597D\u6548\u7528\u8C03\u6574"))), /* @__PURE__ */ import_react2.default.createElement("tbody", null, evidence.rows.map((row) => /* @__PURE__ */ import_react2.default.createElement("tr", { key: row.id }, /* @__PURE__ */ import_react2.default.createElement("td", null, row.route, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-caption" }, row.domain)), /* @__PURE__ */ import_react2.default.createElement("td", null, row.positiveCount, " / ", row.negativeCount, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-caption" }, "\u5DF2\u89C2\u5BDF ", row.feedbackCount, " \xB7 \u6709\u6548\u6743\u91CD ", row.effectiveWeight.toFixed(2), " \xB7 \u6709\u6548\u6837\u672C\u91CF ", row.effectiveSampleSize.toFixed(2))), /* @__PURE__ */ import_react2.default.createElement("td", null, row.adjustment > 0 ? "+" : "", row.adjustment.toFixed(4), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-caption" }, "\u6536\u7F29\u7CFB\u6570 ", row.shrinkage.toFixed(2)))))))), evidence.total > evidence.rows.length && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u4EC5\u5C55\u793A\u524D ", evidence.rows.length, " \u7EC4\uFF1B\u4E0D\u662F\u6240\u6709\u6A21\u578B\u7684\u8986\u76D6\u7387\u3002")), exclusions.length > 0 && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u672A\u53C2\u4E0E\u5B66\u4E60\u7684\u539F\u56E0"), /* @__PURE__ */ import_react2.default.createElement("ul", { className: "mr-checklist" }, exclusions.map((row) => /* @__PURE__ */ import_react2.default.createElement("li", { key: row.reason }, row.label, "\uFF1A", row.count)))));
2321
2461
  }
2322
- function AdaptiveControls({ ledger, settings, onChanged }) {
2462
+ function AdaptiveControls({ ledger, settings, onChanged, refreshing }) {
2323
2463
  const value = settings.value;
2324
2464
  const learning = learningView(ledger?.learning, value);
2325
2465
  const [resetBusy, setResetBusy] = import_react2.default.useState(false);
2466
+ const [refreshNotice, setRefreshNotice] = import_react2.default.useState("");
2467
+ const resetPending = import_react2.default.useRef(false);
2326
2468
  const save = async (key, next) => {
2327
2469
  const accepted = await settings.write(key, next);
2328
- if (accepted) onChanged?.();
2470
+ if (accepted) {
2471
+ setRefreshNotice("");
2472
+ try {
2473
+ await onChanged?.();
2474
+ } catch {
2475
+ setRefreshNotice("\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\uFF0C\u4F46\u6458\u8981\u5237\u65B0\u5931\u8D25\uFF1B\u8BF7\u5237\u65B0\u6267\u884C\u8BB0\u5F55\u540E\u91CD\u65B0\u89C4\u5212\u3002");
2476
+ }
2477
+ }
2329
2478
  return accepted;
2330
2479
  };
2331
2480
  const reset = async () => {
2332
- if (!window.confirm("\u4ECE\u73B0\u5728\u91CD\u65B0\u5B66\u4E60\u4F60\u7684\u504F\u597D\uFF1F\u6B64\u524D\u53CD\u9988\u5C06\u4E0D\u518D\u53C2\u4E0E\u8C03\u6574\uFF0C\u4F46\u6267\u884C\u8BB0\u5F55\u3001\u8D39\u7528\u5386\u53F2\u548C\u539F\u8BC4\u4EF7\u4E0D\u4F1A\u5220\u9664\u3002")) return;
2333
- setResetBusy(true);
2481
+ if (resetPending.current || !settings.writable) return;
2482
+ resetPending.current = true;
2334
2483
  try {
2484
+ if (!window.confirm("\u4ECE\u73B0\u5728\u91CD\u65B0\u5B66\u4E60\u4F60\u7684\u504F\u597D\uFF1F\u6B64\u524D\u53CD\u9988\u5C06\u4E0D\u518D\u53C2\u4E0E\u8C03\u6574\uFF0C\u4F46\u6267\u884C\u8BB0\u5F55\u3001\u8D39\u7528\u5386\u53F2\u548C\u539F\u8BC4\u4EF7\u4E0D\u4F1A\u5220\u9664\u3002")) return;
2485
+ setResetBusy(true);
2335
2486
  await save("feedbackResetAt", Date.now());
2336
2487
  } finally {
2488
+ resetPending.current = false;
2337
2489
  setResetBusy(false);
2338
2490
  }
2339
2491
  };
@@ -2356,7 +2508,7 @@ function AdaptiveControls({ ledger, settings, onChanged }) {
2356
2508
  writable: settings.writable,
2357
2509
  onSave: save
2358
2510
  }
2359
- ))), learning.available ? /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, learning.enabled ? "\u5B66\u4E60\u5DF2\u542F\u7528" : "\u5B66\u4E60\u5DF2\u505C\u7528", " \xB7 \u6709\u6548\u53CD\u9988 ", learning.feedbackCount, " \xB7 \u6709\u6548\u6743\u91CD ", learning.effectiveWeight.toFixed(2), " \xB7 \u5FFD\u7565 ", learning.ignoredCount, learning.policyVersion ? ` \xB7 \u7B56\u7565 ${learning.policyVersion}` : "") : /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, "\u5B66\u4E60\u6458\u8981\u5C1A\u672A\u8BFB\u53D6\uFF1B\u4FDD\u5B58\u540E\u5237\u65B0\u6267\u884C\u8BB0\u5F55\u67E5\u770B\u3002"), learning.resetAt > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u5B66\u4E60\u8D77\u70B9\uFF1A", new Date(learning.resetAt).toLocaleString(), "\uFF0C\u6B64\u524D\u53CD\u9988\u4E0D\u518D\u53C2\u4E0E\u8C03\u6574\u3002"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !settings.writable || resetBusy, onClick: () => {
2511
+ ))), settings.busy && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, "\u6B63\u5728\u4FDD\u5B58\u8BBE\u7F6E\uFF0C\u8BF7\u7A0D\u5019\u2026"), refreshing && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u53CD\u9988\u4E0E\u516C\u5F00\u6570\u636E\u6458\u8981\u2026"), refreshNotice && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, refreshNotice), learning.available ? /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, learning.enabled ? "\u5B66\u4E60\u5DF2\u542F\u7528" : "\u5B66\u4E60\u5DF2\u505C\u7528", " \xB7 \u6700\u8FD1\u4E00\u6B21\u8D26\u672C\u6458\u8981\uFF1A\u6709\u6548\u53CD\u9988 ", learning.feedbackCount, " \xB7 \u6709\u6548\u6743\u91CD ", learning.effectiveWeight.toFixed(2), " \xB7 \u5FFD\u7565 ", learning.ignoredCount, learning.policyVersion ? ` \xB7 \u7B56\u7565 ${learning.policyVersion}` : "") : /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", role: "status" }, "\u5B66\u4E60\u6458\u8981\u5C1A\u672A\u8BFB\u53D6\uFF1B\u4FDD\u5B58\u540E\u5237\u65B0\u6267\u884C\u8BB0\u5F55\u67E5\u770B\u3002"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u6458\u8981\u662F\u6700\u8FD1\u4E00\u6B21\u8BFB\u53D6\u7684\u5DF2\u89C2\u5BDF\u8BC1\u636E\u3002\u4FEE\u6539\u8BC4\u4EF7 / \u5B66\u4E60\u8BBE\u7F6E\u540E\u9700\u5237\u65B0\u6458\u8981\u5E76\u91CD\u65B0\u751F\u6210\u5EFA\u8BAE\uFF1B\u5237\u65B0\u6309\u68C0\u67E5\u95F4\u9694\u590D\u7528\u516C\u5F00\u5FEB\u7167\uFF0C\u4E0D\u4FDD\u8BC1\u6BCF\u6B21\u4E0B\u8F7D\u65B0\u6570\u636E\u3002"), /* @__PURE__ */ import_react2.default.createElement(LearningEvidence, { learning: ledger?.learning }), learning.resetAt > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u5B66\u4E60\u8D77\u70B9\uFF1A", new Date(learning.resetAt).toLocaleString(), "\uFF0C\u6B64\u524D\u53CD\u9988\u4E0D\u518D\u53C2\u4E0E\u8C03\u6574\u3002"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !settings.writable || resetBusy, onClick: () => {
2360
2512
  void reset();
2361
2513
  } }, resetBusy ? "\u6B63\u5728\u8BBE\u7F6E\u2026" : "\u4ECE\u73B0\u5728\u91CD\u65B0\u5B66\u4E60"), /* @__PURE__ */ import_react2.default.createElement("h3", { className: "mr-section-title" }, "\u52A8\u6001\u516C\u5171\u6570\u636E"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u9ED8\u8BA4\u5173\u95ED\u3002\u660E\u786E\u542F\u7528\u540E\uFF0C\u5728\u6253\u5F00 / \u5237\u65B0\u8D26\u672C\u53CA\u6267\u884C\u524D\u6309\u68C0\u67E5\u95F4\u9694\u8BFB\u53D6\u516C\u5F00 LiveBench \u548C\u53EF\u9009\u4EF7\u683C\u5FEB\u7167\uFF1B\u4EF7\u683C\u4E0E\u80FD\u529B\u5148\u9A8C\u4FDD\u7559\u7248\u672C\uFF0C\u4E0D\u4EE3\u8868\u771F\u5B9E\u4EFB\u52A1\u6536\u76CA\u3002\u53EA\u6709\u6253\u5F00\u516C\u5171\u6E90\u5F00\u5173\u624D\u4F1A\u8BFB\u53D6\u8FDC\u7A0B\u6570\u636E\uFF0C\u4E0D\u53D1\u9001\u4EFB\u52A1\u6216\u53CD\u9988\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-check" }, /* @__PURE__ */ import_react2.default.createElement(
2362
2514
  "input",
@@ -2376,9 +2528,9 @@ function AdaptiveControls({ ledger, settings, onChanged }) {
2376
2528
  writable: settings.writable,
2377
2529
  onSave: save
2378
2530
  }
2379
- ), /* @__PURE__ */ import_react2.default.createElement(PublicEndpointControl, { name: "liveBenchEndpoint", label: "LiveBench \u516C\u5F00\u6E90", value: adaptiveSettingValue(value, "liveBenchEndpoint"), writable: settings.writable, onSave: save }), /* @__PURE__ */ import_react2.default.createElement(PublicEndpointControl, { name: "pricingSnapshotEndpoint", label: "\u4EF7\u683C\u5FEB\u7167\u516C\u5F00\u6E90\uFF08\u53EF\u9009\uFF09", value: adaptiveSettingValue(value, "pricingSnapshotEndpoint"), writable: settings.writable, onSave: save }), /* @__PURE__ */ import_react2.default.createElement(PublicSourceStatus, { label: "LiveBench", source: ledger?.dynamicData?.liveBench }), /* @__PURE__ */ import_react2.default.createElement(PublicSourceStatus, { label: "\u4EF7\u683C", source: ledger?.dynamicData?.pricing })));
2531
+ ), /* @__PURE__ */ import_react2.default.createElement(PublicEndpointControl, { name: "liveBenchEndpoint", label: "LiveBench \u516C\u5F00\u6E90", value: adaptiveSettingValue(value, "liveBenchEndpoint"), writable: settings.writable, onSave: save }), /* @__PURE__ */ import_react2.default.createElement(PublicEndpointControl, { name: "pricingSnapshotEndpoint", label: "\u4EF7\u683C\u5FEB\u7167\u516C\u5F00\u6E90\uFF08\u53EF\u9009\uFF09", value: adaptiveSettingValue(value, "pricingSnapshotEndpoint"), writable: settings.writable, onSave: save }), /* @__PURE__ */ import_react2.default.createElement(PublicSourceStatus, { label: "LiveBench", source: ledger?.dynamicData?.liveBench, enabled: adaptiveSettingValue(value, "dynamicDataEnabled") === true }), /* @__PURE__ */ import_react2.default.createElement(PublicSourceStatus, { label: "\u4EF7\u683C", source: ledger?.dynamicData?.pricing, enabled: adaptiveSettingValue(value, "dynamicDataEnabled") === true && Boolean(adaptiveSettingValue(value, "pricingSnapshotEndpoint")) })));
2380
2532
  }
2381
- function CostControlCard({ ledger, settingsScope, onChanged, error }) {
2533
+ function CostControlCard({ ledger, settingsScope, onChanged, error, refreshing = false }) {
2382
2534
  const settings = useSettingsWriter(settingsScope);
2383
2535
  const [dailyDraft, setDailyDraft] = import_react2.default.useState("");
2384
2536
  const [monthlyDraft, setMonthlyDraft] = import_react2.default.useState("");
@@ -2416,7 +2568,7 @@ function CostControlCard({ ledger, settingsScope, onChanged, error }) {
2416
2568
  void set("allowManualReassign", event.target.checked);
2417
2569
  } }), "\u5141\u8BB8\u624B\u52A8\u6539\u6D3E\u5DE5\u4F5C\u5305"), /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-check" }, /* @__PURE__ */ import_react2.default.createElement("input", { type: "checkbox", checked: value.confirmUnsandboxedCli !== false, disabled: !settings.writable, onChange: (event) => {
2418
2570
  void set("confirmUnsandboxedCli", event.target.checked);
2419
- } }), "\u76F4\u63A5\u542F\u52A8\u65E0\u6C99\u7BB1 CLI \u524D\u5148\u786E\u8BA4")), /* @__PURE__ */ import_react2.default.createElement(AdaptiveControls, { ledger, settings, onChanged }), settings.notice && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, settings.notice)));
2571
+ } }), "\u76F4\u63A5\u542F\u52A8\u65E0\u6C99\u7BB1 CLI \u524D\u5148\u786E\u8BA4")), /* @__PURE__ */ import_react2.default.createElement(AdaptiveControls, { ledger, settings, onChanged, refreshing }), settings.notice && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, settings.notice)));
2420
2572
  }
2421
2573
  function DagView({ packages, renderNode, label = "\u5B50\u4EFB\u52A1\u4F9D\u8D56\u56FE" }) {
2422
2574
  const layers = dagLayers(packages);
@@ -2432,13 +2584,13 @@ function ChannelText({ item }) {
2432
2584
  return /* @__PURE__ */ import_react2.default.createElement("span", { className: item.channel === "official-cli" ? "mr-pill mr-pill-channel-ok" : "mr-pill" }, item.channel === "official-cli" ? `\u5B98\u65B9 CLI \xB7 ${item.toolId ?? ""}` : "\u6A21\u578B\u76EE\u5F55 API");
2433
2585
  }
2434
2586
  function RunNode({ run, item, routes, allowReassign, busy, onRate, onRerun }) {
2435
- if (item.status === "paused") return /* @__PURE__ */ import_react2.default.createElement(PausedNode, { run, item, busy, onRerun });
2436
2587
  const [target, setTarget] = import_react2.default.useState("");
2588
+ if (item.status === "paused") return /* @__PURE__ */ import_react2.default.createElement(PausedNode, { run, item, busy, onRerun });
2437
2589
  const cost = packageCost(item);
2438
2590
  const rerun = rerunSupport(run);
2439
2591
  const canRerun = rerun.supported && !item.ok && !busy;
2440
2592
  const others = routes.filter((route) => `${route.provider}/${route.model}` !== `${item.provider}/${item.model}`);
2441
- return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-route" }, item.provider, "/", item.model, item.reassigned ? "\uFF08\u5DF2\u6539\u6D3E\uFF09" : ""), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement(ChannelText, { item }), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u9884\u4F30 ", money(item.estimatedCost), " \xB7 \u5B9E\u9645 ", cost.budget, item.difficulty ? ` \xB7 \u96BE\u5EA6 ${BAND[item.difficulty] ?? item.difficulty}` : "")), cost.reference && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, cost.reference), item.actualModel && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "CLI \u56DE\u62A5\u6A21\u578B\uFF1A", item.actualModel), (item.billing || item.billingMode) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u8BA1\u8D39\uFF1A", BILLING_CHANNEL_LABEL[item.billing] ?? "\u2014", item.subscriptionRoute ? ` \xB7 \u5957\u9910\u8DEF\u7EBF ${item.subscriptionRoute.provider}/${item.subscriptionRoute.model}` : "", item.billingMode && item.billingMode !== "subscription-first" ? ` \xB7 ${BILLING_MODE_LABEL[item.billingMode] ?? item.billingMode}` : ""), billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-warn-text" }, "\u8BA1\u8D39\u5207\u6362\uFF1A", billingSwitchText(item)), item.fallback?.reason && item.fallback.reason !== billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u56DE\u9000\u539F\u56E0\uFF1A", item.fallback.reason), item.fallback?.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, "CLI \u539F\u59CB\u9519\u8BEF\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, item.fallback.error)), !item.ok && item.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, item.error), item.review && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u5F3A\u6A21\u578B\u62BD\u67E5\uFF08", item.review.provider, "/", item.review.model, "\uFF09\uFF1A", item.review.score ? `${item.review.score}/5` : "\u672A\u8BC4\u5206", " ", item.review.summary), item.answer && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u7ED3\u679C"), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.answer, item.answerTruncated ? "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-node-actions" }, item.ok && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", "aria-pressed": item.rating === 1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "up")) }, "\u{1F44D} \u6709\u7528"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", "aria-pressed": item.rating === -1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "down")) }, "\u{1F44E} \u4E0D\u597D")), canRerun && /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-mini", type: "button", title: rerun.confirm || void 0, onClick: () => onRerun(run.id, item.id, null) }, run.kind === "tool" ? "\u91CD\u65B0\u6267\u884C\u6B64\u8C03\u7528" : rerun.writes ? "\u5728\u65B0\u5DE5\u4F5C\u533A\u7EED\u8DD1" : "\u91CD\u8DD1\u6B64\u6B65"), !rerun.supported && !item.ok && item.ran && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, rerun.reason), rerun.supported && rerun.reassign && !(rerun.writes && item.ok) && allowReassign && others.length > 0 && !busy && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input mr-mini-select", "aria-label": "\u6539\u6D3E\u5230", value: target, onChange: (event) => setTarget(event.target.value) }, /* @__PURE__ */ import_react2.default.createElement("option", { value: "" }, "\u6539\u6D3E\u5230\u2026"), others.map((route) => /* @__PURE__ */ import_react2.default.createElement("option", { key: `${route.provider}/${route.model}`, value: `${route.provider}\0${route.model}` }, route.provider, "/", route.model))), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", disabled: !target, onClick: () => {
2593
+ return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-route" }, item.provider, "/", item.model, item.reassigned ? "\uFF08\u5DF2\u6539\u6D3E\uFF09" : ""), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement(ChannelText, { item }), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u9884\u4F30 ", money(item.estimatedCost), " \xB7 \u5B9E\u9645 ", cost.budget, item.difficulty ? ` \xB7 \u96BE\u5EA6 ${BAND[item.difficulty] ?? item.difficulty}` : "")), cost.reference && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, cost.reference), item.actualModel && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "CLI \u56DE\u62A5\u6A21\u578B\uFF1A", item.actualModel), (item.billing || item.billingMode) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u8BA1\u8D39\uFF1A", BILLING_CHANNEL_LABEL[item.billing] ?? "\u2014", item.subscriptionRoute ? ` \xB7 \u5957\u9910\u8DEF\u7EBF ${item.subscriptionRoute.provider}/${item.subscriptionRoute.model}` : "", item.billingMode && item.billingMode !== "subscription-first" ? ` \xB7 ${BILLING_MODE_LABEL[item.billingMode] ?? item.billingMode}` : ""), billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-warn-text" }, "\u8BA1\u8D39\u5207\u6362\uFF1A", billingSwitchText(item)), item.fallback?.reason && item.fallback.reason !== billingSwitchText(item) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u56DE\u9000\u539F\u56E0\uFF1A", item.fallback.reason), item.fallback?.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, "CLI \u539F\u59CB\u9519\u8BEF\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, item.fallback.error)), !item.ok && item.error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, item.error), item.review && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u5F3A\u6A21\u578B\u62BD\u67E5\uFF08", item.review.provider, "/", item.review.model, "\uFF09\uFF1A", item.review.score ? `${item.review.score}/5` : "\u672A\u8BC4\u5206", " ", item.review.summary), item.answer && /* @__PURE__ */ import_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u67E5\u770B\u7ED3\u679C"), /* @__PURE__ */ import_react2.default.createElement("pre", null, item.answer, item.answerTruncated ? "\n\u2026\uFF08\u5DF2\u622A\u65AD\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-node-actions" }, item.ok && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", title: item.rating === 1 ? "\u518D\u6B21\u70B9\u51FB\u64A4\u56DE\u6709\u7528\u8BC4\u4EF7" : "\u8BC4\u4EF7\u6B64\u7ED3\u679C\u6709\u7528", "aria-pressed": item.rating === 1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "up")) }, "\u{1F44D} \u6709\u7528"), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", title: item.rating === -1 ? "\u518D\u6B21\u70B9\u51FB\u64A4\u56DE\u4E0D\u597D\u8BC4\u4EF7" : "\u8BC4\u4EF7\u6B64\u7ED3\u679C\u4E0D\u597D", "aria-pressed": item.rating === -1, disabled: busy, onClick: () => onRate(...feedbackRatingArguments(run, item, "down")) }, "\u{1F44E} \u4E0D\u597D")), canRerun && /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-mini", type: "button", title: rerun.confirm || void 0, onClick: () => onRerun(run.id, item.id, null) }, run.kind === "tool" ? "\u91CD\u65B0\u6267\u884C\u6B64\u8C03\u7528" : rerun.writes ? "\u5728\u65B0\u5DE5\u4F5C\u533A\u7EED\u8DD1" : "\u91CD\u8DD1\u6B64\u6B65"), !rerun.supported && !item.ok && item.ran && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, rerun.reason), rerun.supported && rerun.reassign && !(rerun.writes && item.ok) && allowReassign && others.length > 0 && !busy && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input mr-mini-select", "aria-label": "\u6539\u6D3E\u5230", value: target, onChange: (event) => setTarget(event.target.value) }, /* @__PURE__ */ import_react2.default.createElement("option", { value: "" }, "\u6539\u6D3E\u5230\u2026"), others.map((route) => /* @__PURE__ */ import_react2.default.createElement("option", { key: `${route.provider}/${route.model}`, value: `${route.provider}\0${route.model}` }, route.provider, "/", route.model))), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-mini", type: "button", disabled: !target, onClick: () => {
2442
2594
  const [provider, model] = target.split("\0");
2443
2595
  onRerun(run.id, item.id, { provider, model });
2444
2596
  } }, "\u6539\u6D3E\u5E76\u91CD\u8DD1"))));
@@ -12003,7 +12155,7 @@ var xterm_default = `/**
12003
12155
  `;
12004
12156
 
12005
12157
  // .dsh-plugin/client/host-version.mjs
12006
- var ROUTER_CLIENT_VERSION = true ? "0.16.0" : "";
12158
+ var ROUTER_CLIENT_VERSION = true ? "0.16.2" : "";
12007
12159
  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";
12008
12160
  function isMissingRemoteMethod(message) {
12009
12161
  const value = String(message ?? "");
@@ -12809,7 +12961,10 @@ function PlanResults({ plan, ledger, headingRef }) {
12809
12961
  const purposeLabel = { analysis: "\u4EFB\u52A1\u5206\u6790", execution: "\u4EFB\u52A1\u5B9E\u65BD", verification: "\u72EC\u7ACB\u9A8C\u8BC1", synthesis: "\u7ED3\u679C\u6574\u5408" };
12810
12962
  return /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u8DEF\u7531\u5EFA\u8BAE" }, /* @__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", ref: headingRef, tabIndex: -1 }, "\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, "\u672C\u5730\u8BA1\u7B97\u5B8C\u6210\uFF0C\u672A\u5411\u6A21\u578B\u53D1\u9001\u4EFB\u52A1\u5185\u5BB9\u3002"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u63A8\u8350\u8DEF\u7EBF"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, selected ? `${selected.provider}/${selected.model}` : "\u6682\u65E0\u8DEF\u7EBF")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u4EFB\u52A1\u590D\u6742\u5EA6 \xB7 \u5206\u503C\uFF080\u20131\uFF09"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, { simple: "\u7B80\u5355", balanced: "\u4E2D\u7B49", complex: "\u590D\u6742" }[plan.complexity.band] || plan.complexity.band, " \xB7 ", plan.complexity.value)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u4F30\u7B97\u603B\u6210\u672C"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, money2(plan.estimatedCost))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-label" }, "\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[plan.preset]?.label ?? "\u5747\u8861"))), budget?.exceeded && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error", role: "alert" }, "\u6267\u884C\u524D\u9884\u7B97\u68C0\u67E5\uFF1A", budget.message, " \u5B9E\u9645\u6267\u884C\u65F6\u5C06\u6309\u8BBE\u7F6E\u81EA\u52A8\u964D\u7EA7\u6216\u6682\u505C\u8BE2\u95EE\u3002"), budget?.limited && !budget.exceeded && budget.estimateKnown && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u6267\u884C\u524D\u9884\u7B97\u68C0\u67E5\uFF1A\u672C\u6B21\u9884\u4F30 ", money2(plan.estimatedCost), "\uFF0C\u5269\u4F59\u989D\u5EA6 ", money2(budget.remainingUsd), "\u3002"), plan.loginRequired && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u63A8\u8350\u6A21\u578B\u7684\u5B98\u65B9 CLI \u672A\u767B\u5F55\uFF0C\u6267\u884C\u65F6\u76F4\u63A5\u8D70\u6A21\u578B\u76EE\u5F55 API\uFF1B\u53EF\u5728\u201C\u5B98\u65B9\u5DE5\u5177\u201D\u5361\u7247\u70B9\u201C\u53BB\u767B\u5F55\u201D\u3002"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-control-label" }, "\u6267\u884C\u6E20\u9053"), /* @__PURE__ */ import_react5.default.createElement(ChannelBadge, { item: plan })), /* @__PURE__ */ import_react5.default.createElement("details", { className: "mr-plan-explanation" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, "\u67E5\u770B\u89C4\u5212\u4F9D\u636E\u4E0E\u4F30\u7B97\u8BF4\u660E"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, plan.reason), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, plan.pricingNotice, " ", plan.qualityNotice, " ", plan.availabilityNotice, " ", plan.modalityNotice || "")), plan.optimization.budgetExceeded && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error" }, "\u6309\u5DF2\u63D0\u4F9B\u5355\u4EF7\u4F30\u7B97\uFF0C\u4EFB\u52A1\u53EF\u80FD\u8D85\u8FC7\u672C\u6B21\u9884\u7B97\u3002\u9884\u7B97\u53EA\u5F71\u54CD\u5EFA\u8BAE\uFF0C\u4E0D\u4F1A\u963B\u6B62\u5B9E\u9645\u6263\u8D39\u3002"), plan.mode === "team" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("h3", { className: "mr-section-title" }, "\u56E2\u961F\u5DE5\u4F5C\u5305"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u4E0B\u65B9\u6A21\u578B\u662F\u89C4\u5212\u5EFA\u8BAE\uFF1B\u6258\u7BA1\u6267\u884C\u4F1A\u6309\u5382\u5546 CLI \u7684\u6A21\u578B\u540D\u89C4\u5219\u9009\u7528\uFF0C\u672A\u6838\u9A8C\u6620\u5C04\u65F6\u4F7F\u7528\u8BE5 CLI \u7684\u9ED8\u8BA4\u6A21\u578B\u3002"), plan.team.workPackages.length > 1 && /* @__PURE__ */ import_react5.default.createElement(DagView, { packages: plan.team.workPackages, label: "\u5DE5\u4F5C\u5305\u4F9D\u8D56\u56FE", renderNode: (item) => /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-route" }, item.recommendedProvider, "/", item.recommendedModel) }), plan.team.workPackages.length === 0 ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-empty" }, "\u5F53\u524D\u76EE\u5F55\u6CA1\u6709\u53EF\u5206\u914D\u7684\u6A21\u578B\u8DEF\u7EBF\u3002") : plan.team.workPackages.map((item, index) => /* @__PURE__ */ import_react5.default.createElement("details", { className: "mr-package mr-package-details", key: item.id }, /* @__PURE__ */ import_react5.default.createElement("summary", null, /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-package-name" }, index + 1, ". ", item.name), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-package-route" }, item.recommendedProvider, "/", item.recommendedModel)), item.objective && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u5177\u4F53\u76EE\u6807\uFF1A", item.objective), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, purposeLabel[item.purpose] ?? item.purpose, item.dependsOn.length > 0 ? ` \xB7 \u4F9D\u8D56\uFF1A${item.dependsOn.map((id2) => packageNames.get(id2) ?? id2).join("\u3001")}` : ""), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u96BE\u5EA6\uFF1A", { simple: "\u7B80\u5355", balanced: "\u4E2D\u7B49", complex: "\u56F0\u96BE" }[item.difficulty] || item.difficulty || "\u5F85\u8BC4\u4F30", " \xB7 \u8D39\u7528\uFF1A", money2(item.estimatedCost)), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u9A8C\u6536\uFF1A", item.verificationChecklist.join("\uFF1B")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react5.default.createElement(ChannelBadge, { item }), item.loginRequired && /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-pill" }, "CLI \u672A\u767B\u5F55")), item.channelDetail && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-package-copy" }, "\u6E20\u9053\u8BF4\u660E\uFF1A", item.channelDetail)))), plan.routingBypassed && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, "\u5DF2\u6307\u5B9A\u5355\u4E00\u6A21\u578B\uFF0C\u672A\u4E0E\u5176\u4ED6\u8DEF\u7EBF\u6BD4\u8F83\u3002\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u8C03\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_execute"), " \u5E76\u4F20\u5165\u8BE5 provider \u4E0E model \u5373\u53EF\u76F4\u63A5\u6267\u884C\uFF1B\u82E5\u8BE5\u6A21\u578B\u5141\u8BB8\u5B98\u65B9\u5DE5\u5177\uFF0C\u4F1A\u4F18\u5148\u4F7F\u7528\u5BF9\u5E94 CLI\u3002"), plan.mode === "team" && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption" }, plan.team.handoff)));
12811
12963
  }
12812
- var remoteError = (response, fallback) => text5(response?.error?.message) || text5(response?.value?.error) || fallback;
12964
+ var remoteError = (response, fallback) => remoteErrorText(
12965
+ text5(response?.error?.message) || text5(response?.value?.error) || (typeof response?.error === "string" ? response.error : ""),
12966
+ fallback
12967
+ );
12813
12968
  function probeLabel(probe) {
12814
12969
  if (!probe) return "\u5C1A\u672A\u68C0\u6D4B";
12815
12970
  if (probe.installed) return `\u5DF2\u5B89\u88C5${probe.version ? ` \xB7 ${probe.version}` : ""}`;
@@ -12827,10 +12982,22 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
12827
12982
  const request = import_react5.default.useRef(0);
12828
12983
  const submitting = import_react5.default.useRef(/* @__PURE__ */ new Set());
12829
12984
  const polling = import_react5.default.useRef(/* @__PURE__ */ new Set());
12985
+ const jobsRef = import_react5.default.useRef({});
12986
+ const rememberJobs = (updater) => {
12987
+ setJobs((previous) => {
12988
+ const next = typeof updater === "function" ? updater(previous) : updater;
12989
+ jobsRef.current = next;
12990
+ return next;
12991
+ });
12992
+ };
12830
12993
  const refresh = async () => {
12831
12994
  onRefreshHealth?.();
12832
12995
  const current = ++request.current;
12833
- setProbeState((previous) => ({ ...previous, status: "loading", error: "" }));
12996
+ setProbeState((previous) => ({
12997
+ ...previous,
12998
+ status: previous.probes.length > 0 ? "refreshing" : "loading",
12999
+ error: ""
13000
+ }));
12834
13001
  try {
12835
13002
  if (typeof listOfficialTools !== "function") throw new Error("\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002");
12836
13003
  const response = await listOfficialTools();
@@ -12843,8 +13010,16 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
12843
13010
  onProbes({ probes, capabilities, readiness, hostVersion: typeof response.value?.hostVersion === "string" ? response.value.hostVersion : null });
12844
13011
  } catch (error) {
12845
13012
  if (!mounted.current || current !== request.current) return;
12846
- setProbeState({ status: "error", probes: [], capabilities: [], readiness: [], error: text5(error?.message) || "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002" });
12847
- onProbes({ probes: [], capabilities: [], readiness: [] });
13013
+ const message = remoteErrorText(text5(error?.message), "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002");
13014
+ let kept = false;
13015
+ setProbeState((previous) => {
13016
+ if (previous.probes.length > 0) {
13017
+ kept = true;
13018
+ return { ...previous, status: "ready", error: message };
13019
+ }
13020
+ return { status: "error", probes: [], capabilities: [], readiness: [], error: message };
13021
+ });
13022
+ if (!kept) onProbes({ probes: [], capabilities: [], readiness: [] });
12848
13023
  }
12849
13024
  };
12850
13025
  import_react5.default.useEffect(() => {
@@ -12859,7 +13034,16 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
12859
13034
  return null;
12860
13035
  }
12861
13036
  })).then((entries) => {
12862
- if (mounted.current) setJobs((previous) => ({ ...Object.fromEntries(entries.filter(Boolean)), ...previous }));
13037
+ if (!mounted.current) return;
13038
+ rememberJobs((previous) => {
13039
+ const next = { ...previous };
13040
+ for (const entry of entries) {
13041
+ if (!entry) continue;
13042
+ const [id2, job] = entry;
13043
+ if (shouldApplyInstallStatus(previous[id2], job)) next[id2] = job;
13044
+ }
13045
+ return next;
13046
+ });
12863
13047
  });
12864
13048
  }
12865
13049
  return () => {
@@ -12879,12 +13063,20 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
12879
13063
  if (!listening || !mounted.current) return;
12880
13064
  if (!response?.ok) throw new Error(remoteError(response, "\u65E0\u6CD5\u83B7\u53D6\u5B89\u88C5\u8FDB\u5EA6\u3002"));
12881
13065
  const job = response.value?.job;
12882
- if (!job) throw new Error("\u5B89\u88C5\u4EFB\u52A1\u72B6\u6001\u6682\u4E0D\u53EF\u7528\u3002");
12883
- setJobs((previous) => ({ ...previous, [id2]: job }));
12884
- setRowErrors((previous) => ({ ...previous, [id2]: "" }));
13066
+ const local = jobsRef.current[id2];
13067
+ if (!job) {
13068
+ if (local?.status === "running") return;
13069
+ throw new Error("\u5B89\u88C5\u4EFB\u52A1\u72B6\u6001\u6682\u4E0D\u53EF\u7528\u3002");
13070
+ }
13071
+ if (!shouldApplyInstallStatus(local, job)) return;
13072
+ rememberJobs((previous) => shouldApplyInstallStatus(previous[id2], job) ? { ...previous, [id2]: job } : previous);
13073
+ setRowErrors((previous) => ({
13074
+ ...previous,
13075
+ [id2]: job.status === "failed" ? text5(job.error) || "\u5B89\u88C5\u5931\u8D25\u3002" : ""
13076
+ }));
12885
13077
  if (job.status !== "running") void refresh();
12886
13078
  } catch (error) {
12887
- if (listening && mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: text5(error?.message) || "\u5B89\u88C5\u72B6\u6001\u8BFB\u53D6\u5931\u8D25\uFF0C\u5C06\u7EE7\u7EED\u91CD\u8BD5\u3002" }));
13079
+ if (listening && mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: remoteErrorText(text5(error?.message), "\u5B89\u88C5\u72B6\u6001\u8BFB\u53D6\u5931\u8D25\uFF0C\u5C06\u7EE7\u7EED\u91CD\u8BD5\u3002") }));
12888
13080
  } finally {
12889
13081
  polling.current.delete(id2);
12890
13082
  }
@@ -12899,21 +13091,43 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
12899
13091
  }, [jobs, officialToolInstallStatus]);
12900
13092
  const install = async (id2) => {
12901
13093
  const tool = OFFICIAL_TOOLS.find((item) => item.id === id2);
12902
- if (!tool || tool.unsupported || submitting.current.has(id2) || jobs[id2]?.status === "running") return;
13094
+ const refusal = installClickRefusal({
13095
+ tool,
13096
+ submitting: submitting.current.has(id2),
13097
+ running: jobsRef.current[id2]?.status === "running"
13098
+ });
13099
+ if (refusal) {
13100
+ setRowErrors((previous) => ({ ...previous, [id2]: refusal }));
13101
+ return;
13102
+ }
12903
13103
  submitting.current.add(id2);
13104
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
12904
13105
  setRowErrors((previous) => ({ ...previous, [id2]: "" }));
12905
- setJobs((previous) => ({ ...previous, [id2]: { tool: id2, status: "running", outputTail: [] } }));
13106
+ rememberJobs((previous) => ({
13107
+ ...previous,
13108
+ [id2]: { tool: id2, status: "running", outputTail: [], startedAt, error: null }
13109
+ }));
12906
13110
  try {
12907
13111
  if (typeof installOfficialTool !== "function") throw new Error("\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002");
12908
13112
  const response = await installOfficialTool(id2);
12909
13113
  if (!mounted.current) return;
12910
- if (!response?.ok || !response.value?.accepted || !response.value?.job) throw new Error(remoteError(response, "\u5B89\u88C5\u4EFB\u52A1\u672A\u88AB\u63A5\u53D7\u3002"));
12911
- setJobs((previous) => ({ ...previous, [id2]: response.value.job }));
13114
+ const accepted = acceptedInstallJob(response);
13115
+ if (!accepted.job) throw new Error(remoteErrorText(accepted.error, "\u5B89\u88C5\u4EFB\u52A1\u672A\u88AB\u63A5\u53D7\u3002"));
13116
+ rememberJobs((previous) => shouldApplyInstallStatus(previous[id2], accepted.job) ? { ...previous, [id2]: accepted.job } : previous);
12912
13117
  } catch (error) {
12913
- if (mounted.current) {
12914
- setJobs((previous) => ({ ...previous, [id2]: { tool: id2, status: "failed", error: text5(error?.message) || "\u5B89\u88C5\u542F\u52A8\u5931\u8D25\u3002" } }));
12915
- setRowErrors((previous) => ({ ...previous, [id2]: text5(error?.message) || "\u5B89\u88C5\u542F\u52A8\u5931\u8D25\u3002" }));
12916
- }
13118
+ if (!mounted.current) return;
13119
+ const message = remoteErrorText(text5(error?.message), "\u5B89\u88C5\u542F\u52A8\u5931\u8D25\u3002");
13120
+ rememberJobs((previous) => ({
13121
+ ...previous,
13122
+ [id2]: {
13123
+ ...previous[id2] ?? {},
13124
+ tool: id2,
13125
+ status: "failed",
13126
+ error: message,
13127
+ startedAt: previous[id2]?.startedAt || startedAt
13128
+ }
13129
+ }));
13130
+ setRowErrors((previous) => ({ ...previous, [id2]: message }));
12917
13131
  } finally {
12918
13132
  submitting.current.delete(id2);
12919
13133
  }
@@ -12925,7 +13139,7 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
12925
13139
  const response = await cancelOfficialToolInstall(id2);
12926
13140
  if (!mounted.current) return;
12927
13141
  if (!response?.ok || !response.value?.accepted || !response.value?.job) throw new Error(remoteError(response, "\u53D6\u6D88\u8BF7\u6C42\u672A\u88AB\u63A5\u53D7\u3002"));
12928
- setJobs((previous) => ({ ...previous, [id2]: response.value.job }));
13142
+ rememberJobs((previous) => ({ ...previous, [id2]: response.value.job }));
12929
13143
  if (response.value.job.status !== "running") void refresh();
12930
13144
  } catch (error) {
12931
13145
  if (mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: text5(error?.message) || "\u65E0\u6CD5\u53D6\u6D88\u5B89\u88C5\u3002" }));
@@ -12936,7 +13150,7 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
12936
13150
  const readinessById = Object.fromEntries(probeState.readiness.map((item) => [item.id, item]));
12937
13151
  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: () => {
12938
13152
  void refresh();
12939
- } }, "\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) => {
13153
+ } }, "\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.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) => {
12940
13154
  const command = installCommandLine(tool);
12941
13155
  const probe = byId[tool.id];
12942
13156
  const capability = capabilitiesById[tool.id];
@@ -12962,13 +13176,18 @@ var WORKSPACE_VIEWS = [
12962
13176
  ];
12963
13177
  function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries }) {
12964
13178
  const [health, setHealth] = import_react5.default.useState({ report: null, error: "", refreshing: false });
12965
- const [ledger, setLedger] = import_react5.default.useState({ value: null, error: "" });
13179
+ const [ledger, setLedger] = import_react5.default.useState({ value: null, error: "", refreshing: false });
12966
13180
  const [boundaries, setBoundaries] = import_react5.default.useState({ value: null, error: "" });
12967
13181
  const [busy, setBusy] = import_react5.default.useState(false);
12968
13182
  const mounted = import_react5.default.useRef(true);
12969
13183
  const ledgerRequest = import_react5.default.useRef(0);
12970
- import_react5.default.useEffect(() => () => {
12971
- mounted.current = false;
13184
+ const mutationBusy = import_react5.default.useRef(false);
13185
+ import_react5.default.useEffect(() => {
13186
+ mounted.current = true;
13187
+ return () => {
13188
+ mounted.current = false;
13189
+ ledgerRequest.current += 1;
13190
+ };
12972
13191
  }, []);
12973
13192
  const call = async (operation, fallback) => {
12974
13193
  if (typeof operation !== "function") throw new Error("\u5DE5\u4F5C\u53F0\u670D\u52A1\u5C1A\u672A\u52A0\u8F7D\uFF0C\u8BF7\u66F4\u65B0\u63D2\u4EF6\u540E\u91CD\u8BD5\u3002");
@@ -12985,13 +13204,18 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
12985
13204
  };
12986
13205
  const refreshLedger = async () => {
12987
13206
  const request = ++ledgerRequest.current;
13207
+ if (mounted.current) setLedger((previous) => ({ ...previous, error: "", refreshing: true }));
12988
13208
  try {
12989
13209
  const value = await call(loadLedger, "\u6267\u884C\u8BB0\u5F55\u8BFB\u53D6\u5931\u8D25\u3002");
12990
- if (mounted.current && request === ledgerRequest.current) setLedger({ value, error: "" });
12991
- if (request !== ledgerRequest.current) return null;
13210
+ if (mounted.current && request === ledgerRequest.current) setLedger({ value, error: "", refreshing: false });
13211
+ if (!mounted.current || request !== ledgerRequest.current) return null;
12992
13212
  return value;
12993
13213
  } catch (error) {
12994
- if (mounted.current && request === ledgerRequest.current) setLedger((previous) => ({ ...previous, error: text5(error?.message) || "\u6267\u884C\u8BB0\u5F55\u8BFB\u53D6\u5931\u8D25\u3002" }));
13214
+ if (mounted.current && request === ledgerRequest.current) setLedger((previous) => ({
13215
+ ...previous,
13216
+ refreshing: false,
13217
+ error: `${text5(error?.message) || "\u6267\u884C\u8BB0\u5F55\u8BFB\u53D6\u5931\u8D25\u3002"}${previous.value ? " \u4E0B\u65B9\u4FDD\u7559\u6700\u8FD1\u4E00\u6B21\u6458\u8981\uFF0C\u5C1A\u672A\u91CD\u65B0\u6838\u9A8C\u3002" : ""}`
13218
+ }));
12995
13219
  return null;
12996
13220
  }
12997
13221
  };
@@ -13012,6 +13236,8 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
13012
13236
  }
13013
13237
  };
13014
13238
  const rate = async (runId, packageId, rating, expectedFinishedAt) => {
13239
+ if (mutationBusy.current) return;
13240
+ mutationBusy.current = true;
13015
13241
  setBusy(true);
13016
13242
  try {
13017
13243
  await call(() => rateResult({ runId, packageId, rating, ...expectedFinishedAt === void 0 ? {} : { expectedFinishedAt } }), "\u8BC4\u4EF7\u4FDD\u5B58\u5931\u8D25\u3002");
@@ -13019,10 +13245,12 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
13019
13245
  } catch (error) {
13020
13246
  if (mounted.current) setLedger((previous) => ({ ...previous, error: text5(error?.message) || "\u8BC4\u4EF7\u4FDD\u5B58\u5931\u8D25\u3002" }));
13021
13247
  } finally {
13248
+ mutationBusy.current = false;
13022
13249
  if (mounted.current) setBusy(false);
13023
13250
  }
13024
13251
  };
13025
13252
  const rerun = async (runId, packageId, override, choice = null) => {
13253
+ if (mutationBusy.current) return;
13026
13254
  const run = ledger.value?.runs?.find((item2) => item2.id === runId);
13027
13255
  const item = run?.packages?.find((entry) => entry.id === packageId);
13028
13256
  const reasons = rerunConfirmations({ run, item, override, choice, ledger: ledger.value, health: health.report, toolFor: toolForProvider, headlessIds: HEADLESS_TOOLS });
@@ -13031,6 +13259,8 @@ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResu
13031
13259
  ${reasons.map((entry, index) => `${index + 1}. ${entry.text}`).join("\n")}
13032
13260
  \u5168\u90E8\u786E\u8BA4\u5E76\u7EE7\u7EED\u5417\uFF1F`)) return;
13033
13261
  const codes = new Set(reasons.map((entry) => entry.code));
13262
+ if (mutationBusy.current) return;
13263
+ mutationBusy.current = true;
13034
13264
  setBusy(true);
13035
13265
  try {
13036
13266
  const request = {
@@ -13051,6 +13281,7 @@ ${reasons.map((entry, index) => `${index + 1}. ${entry.text}`).join("\n")}
13051
13281
  } catch (error) {
13052
13282
  if (mounted.current) setLedger((previous) => ({ ...previous, error: `${text5(error?.message) || "\u91CD\u8DD1\u5931\u8D25\u3002"} \u53EF\u4EE5\u4FEE\u6B63\u540E\u518D\u70B9\u201C\u91CD\u8DD1\u6B64\u6B65\u201D\uFF0C\u6216\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u8C03\u7528 model_router_rerun_step\u3002` }));
13053
13283
  } finally {
13284
+ mutationBusy.current = false;
13054
13285
  if (mounted.current) setBusy(false);
13055
13286
  }
13056
13287
  };
@@ -13187,6 +13418,8 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
13187
13418
  const ledger = await workbench.refreshLedger();
13188
13419
  if (request !== generationRequest.current || inputs !== generationInputs.current || !mounted.current) return;
13189
13420
  if (!ledger) throw new Error("\u8BF7\u5148\u6062\u590D\u6267\u884C\u8BB0\u5F55\u8FDE\u63A5\uFF1B\u65E0\u6CD5\u6838\u5BF9\u6700\u65B0\u6570\u636E\u4E0E\u5B66\u4E60\u72B6\u6001\u3002");
13421
+ if (ledger.storageAvailable === false) throw new Error("\u6267\u884C\u8BB0\u5F55\u5B58\u50A8\u6682\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5\u6838\u5BF9\u8D39\u7528\u4E0E\u5B66\u4E60\u72B6\u6001\uFF1B\u8BF7\u6062\u590D\u8FDE\u63A5\u540E\u518D\u89C4\u5212\u3002");
13422
+ if (ledger.budget?.historyVerified === false) throw new Error("\u8D39\u7528\u5386\u53F2\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u4ECE\u5907\u4EFD\u6062\u590D\u5E76\u6838\u9A8C\u540E\u518D\u89C4\u5212\u3002");
13190
13423
  if (signature2 !== routingSettingsSignature(settingsScope.getSnapshot().value ?? {})) throw new Error("\u89C4\u5212\u8BBE\u7F6E\u5DF2\u66F4\u65B0\uFF0C\u8BF7\u91CD\u65B0\u751F\u6210\u5EFA\u8BAE\u3002");
13191
13424
  const next = createWorkspacePlan(task, catalogState.catalog, {
13192
13425
  ...ledger.routingData,
@@ -13294,11 +13527,12 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
13294
13527
  CostControlCard,
13295
13528
  {
13296
13529
  ledger: workbench.ledger.value,
13297
- error: workbench.ledger.error && !workbench.ledger.value ? workbench.ledger.error : "",
13530
+ error: workbench.ledger.error || workbench.ledger.value?.storageNotice || "",
13531
+ refreshing: workbench.ledger.refreshing,
13298
13532
  settingsScope,
13299
13533
  onChanged: () => {
13300
13534
  invalidatePlan();
13301
- void workbench.refreshLedger();
13535
+ return workbench.refreshLedger();
13302
13536
  }
13303
13537
  }
13304
13538
  ), /* @__PURE__ */ import_react5.default.createElement(