@ljwei-stak/model-router-galgame 0.12.0 → 0.13.0

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.
@@ -43,7 +43,7 @@ __export(official_harness_exports, {
43
43
  inject: () => inject
44
44
  });
45
45
  module.exports = __toCommonJS(official_harness_exports);
46
- var import_react3 = __toESM(require("react"), 1);
46
+ var import_react5 = __toESM(require("react"), 1);
47
47
 
48
48
  // .dsh-plugin/shared/official-tool-registry.mjs
49
49
  var OFFICIAL_TOOLS = Object.freeze([
@@ -121,6 +121,21 @@ var OFFICIAL_TOOLS = Object.freeze([
121
121
  probeExecutables: ["grok"],
122
122
  providerHints: ["xai", "grok"]
123
123
  }),
124
+ Object.freeze({
125
+ id: "gemini",
126
+ label: "Gemini CLI",
127
+ vendor: "Google",
128
+ purpose: "Google \u5B98\u65B9 Gemini CLI\uFF0C\u65E0\u754C\u9762\u6A21\u5F0F\u4F7F\u7528 gemini -p\u3002",
129
+ package: "@google/gemini-cli",
130
+ version: "0.62.0",
131
+ manager: "npm",
132
+ installArgs: ["install", "-g", "@google/gemini-cli@0.62.0", "--registry=https://registry.npmjs.org/"],
133
+ probeExecutables: ["gemini"],
134
+ providerHints: ["gemini", "google"],
135
+ // Headless runs go through the task adapter. The signed sandbox runner does
136
+ // not launch this CLI; a missing or failed process falls back to the API.
137
+ headlessAdapter: true
138
+ }),
124
139
  Object.freeze({
125
140
  id: "zcode",
126
141
  label: "ZCode",
@@ -131,7 +146,7 @@ var OFFICIAL_TOOLS = Object.freeze([
131
146
  installArgs: [],
132
147
  probeExecutables: [],
133
148
  probeNote: "\u68C0\u6D4B\u7ECF\u8FC7\u6709\u6548\u7B7E\u540D\u7684 ZCode.exe \u548C\u540C\u76EE\u5F55 GLM \u8D44\u6E90\uFF1B\u684C\u9762\u5B89\u88C5\u5668\u9700\u4EBA\u5DE5\u9009\u62E9\u5B89\u88C5\u4F4D\u7F6E\u3002",
134
- providerHints: ["zai", "z.ai", "zcode", "glm", "zhipu"]
149
+ providerHints: ["zai", "z.ai", "zcode", "glm", "zhipu", "bigmodel"]
135
150
  })
136
151
  ]);
137
152
  var TOOL_BY_ID = new Map(OFFICIAL_TOOLS.map((tool) => [tool.id, tool]));
@@ -156,6 +171,8 @@ function installCommandLine(tool) {
156
171
  var MAX_TEXT = 32e3;
157
172
  var MAX_PROFILES = 200;
158
173
  var id = (value) => typeof value === "string" ? value.trim() : "";
174
+ var BILLING_VALUES = /* @__PURE__ */ new Set(["subscription-first", "api-only", "subscription-only"]);
175
+ var SUBSCRIPTION_VALUES = /* @__PURE__ */ new Set(["plan-key", "cli-login", "none"]);
159
176
  function nonnegative(value, label) {
160
177
  if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1e6) {
161
178
  throw new Error(`${label} \u5FC5\u987B\u662F 0 \u5230 1000000 \u4E4B\u95F4\u7684\u6709\u9650\u6570\u5B57`);
@@ -165,7 +182,7 @@ function nonnegative(value, label) {
165
182
  function normalizeProfile(entry, index) {
166
183
  const label = `\u7B2C ${index + 1} \u4E2A\u6A21\u578B`;
167
184
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) throw new Error(`${label} \u5FC5\u987B\u662F\u5BF9\u8C61`);
168
- const allowed = /* @__PURE__ */ new Set(["provider", "model", "quality", "pricing", "specialties", "cliModel"]);
185
+ const allowed = /* @__PURE__ */ new Set(["provider", "model", "quality", "pricing", "specialties", "cliModel", "execution", "billing", "subscription", "apiRoute"]);
169
186
  const unknown = Object.keys(entry).find((key) => !allowed.has(key));
170
187
  if (unknown) throw new Error(`${label} \u542B\u4E0D\u652F\u6301\u7684\u5B57\u6BB5 ${unknown}\uFF1B\u4E0D\u8981\u5728\u8FD9\u91CC\u586B\u5199\u5BC6\u94A5\u6216\u547D\u4EE4`);
171
188
  const provider = id(entry.provider);
@@ -206,9 +223,40 @@ function normalizeProfile(entry, index) {
206
223
  if (toolForProvider(provider)?.id === "zcode") throw new Error(`${label} \u5BF9\u5E94\u7684 ZCode CLI \u6682\u4E0D\u652F\u6301\u9010\u6B21\u5207\u6362\u6A21\u578B`);
207
224
  profile.cliModel = cliModel;
208
225
  }
209
- if (Object.keys(profile).length === 2) throw new Error(`${label} \u81F3\u5C11\u63D0\u4F9B quality\u3001pricing\u3001specialties \u6216 cliModel \u4E4B\u4E00`);
226
+ if (entry.execution !== void 0) {
227
+ if (entry.execution !== "auto" && entry.execution !== "official" && entry.execution !== "api") {
228
+ throw new Error(`${label} \u7684 execution \u53EA\u80FD\u662F auto\u3001official \u6216 api`);
229
+ }
230
+ if (entry.execution !== "auto") profile.execution = entry.execution;
231
+ }
232
+ if (entry.billing !== void 0) {
233
+ if (!BILLING_VALUES.has(entry.billing)) throw new Error(`${label} \u7684 billing \u53EA\u80FD\u662F subscription-first\u3001api-only \u6216 subscription-only`);
234
+ profile.billing = entry.billing;
235
+ }
236
+ if (entry.subscription !== void 0) {
237
+ if (!SUBSCRIPTION_VALUES.has(entry.subscription)) throw new Error(`${label} \u7684 subscription \u53EA\u80FD\u662F plan-key\u3001cli-login \u6216 none`);
238
+ profile.subscription = entry.subscription;
239
+ }
240
+ if (entry.apiRoute !== void 0) {
241
+ const target = entry.apiRoute;
242
+ if (!target || typeof target !== "object" || Array.isArray(target) || Object.keys(target).some((key) => key !== "provider" && key !== "model")) {
243
+ throw new Error(`${label} \u7684 apiRoute \u5FC5\u987B\u662F { provider, model }`);
244
+ }
245
+ const apiProvider = id(target.provider);
246
+ const apiModel = id(target.model);
247
+ if (!apiProvider || !apiModel || apiProvider.length > 160 || apiModel.length > 240) throw new Error(`${label} \u7684 apiRoute \u9700\u8981\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u51C6\u786E provider \u548C model`);
248
+ if (profile.subscription !== "plan-key") throw new Error(`${label} \u53EA\u6709 subscription \u4E3A plan-key \u65F6\u624D\u80FD\u8BBE\u7F6E apiRoute`);
249
+ if (apiProvider === provider && apiModel === model) throw new Error(`${label} \u7684 apiRoute \u4E0D\u80FD\u6307\u5411\u81EA\u5DF1`);
250
+ profile.apiRoute = { provider: apiProvider, model: apiModel };
251
+ }
252
+ if (Object.keys(profile).length === 2) throw new Error(`${label} \u81F3\u5C11\u63D0\u4F9B quality\u3001pricing\u3001specialties\u3001cliModel\u3001execution\u3001billing \u6216 subscription \u4E4B\u4E00`);
210
253
  return profile;
211
254
  }
255
+ function normalizeExecutionPreference(value) {
256
+ if (value === void 0 || value === null || value === "" || value === "auto") return "auto";
257
+ if (value === "official" || value === "api") return value;
258
+ throw new TypeError("execution must be auto, official, or api");
259
+ }
212
260
  function parseModelProfilesJson(value) {
213
261
  const source = value == null || value === "" ? "[]" : value;
214
262
  if (typeof source !== "string" || source.length > MAX_TEXT) throw new Error("\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u914D\u7F6E\u8D85\u8FC7 32000 \u5B57\u7B26\u4E0A\u9650");
@@ -241,13 +289,176 @@ function applyModelProfiles(routes, profiles) {
241
289
  ...profile.quality === void 0 ? {} : { quality: profile.quality, qualitySource: "user" },
242
290
  ...profile.pricing === void 0 ? {} : { pricing: { ...profile.pricing }, pricingSource: "user" },
243
291
  ...profile.specialties === void 0 ? {} : { specialties: [...profile.specialties] },
244
- ...profile.cliModel === void 0 ? {} : { cliModel: profile.cliModel }
292
+ ...profile.cliModel === void 0 ? {} : { cliModel: profile.cliModel },
293
+ ...profile.execution === void 0 ? {} : { execution: profile.execution },
294
+ ...profile.billing === void 0 ? {} : { billing: profile.billing },
295
+ ...profile.subscription === void 0 ? {} : { subscription: profile.subscription },
296
+ ...profile.apiRoute === void 0 ? {} : { apiRoute: { ...profile.apiRoute } }
245
297
  };
246
298
  });
247
299
  }
248
300
 
301
+ // .dsh-plugin/shared/subscription-billing.mjs
302
+ var BILLING_MODES = Object.freeze(["subscription-first", "api-only", "subscription-only"]);
303
+ var DEFAULT_BILLING_MODE = "subscription-first";
304
+ var MAX_COOLDOWN_MS = 31 * 24 * 60 * 6e4;
305
+ var BILLING_MODE_LABEL = Object.freeze({
306
+ "subscription-first": "\u8BA2\u9605\u4F18\u5148",
307
+ "api-only": "\u53EA\u7528 API Key",
308
+ "subscription-only": "\u53EA\u7528\u8BA2\u9605"
309
+ });
310
+ var VENDOR_QUOTA_PATTERNS = Object.freeze({
311
+ "claude-code": Object.freeze([
312
+ { kind: "quota", source: "code.claude.com/docs/en/errors", re: /you['’]?ve hit your [a-z0-9 -]{0,24}limit/i },
313
+ { kind: "quota", source: "\u65E7\u7248 CLI \u6587\u672C\uFF08\u672A\u6838\u9A8C\uFF09", re: /claude ai usage limit reached|usage limit reached\|\d{10}/i },
314
+ { kind: "rate-limit", source: "code.claude.com/docs/en/errors", re: /server is temporarily limiting requests|request rejected \(429\)/i }
315
+ ]),
316
+ codex: Object.freeze([
317
+ { kind: "quota", source: "Codex usage_limit_reached\uFF08\u793E\u533A\u8BB0\u5F55\u7684 API \u8FD4\u56DE\uFF09", re: /usage_limit_reached|you['’]?ve hit your usage limit|usage limit has been reached/i },
318
+ { kind: "rate-limit", source: "OpenAI 429\uFF08\u901A\u7528\uFF09", re: /rate_limit_exceeded|rate limit reached for/i }
319
+ ]),
320
+ gemini: Object.freeze([
321
+ { kind: "quota", source: "Google API RESOURCE_EXHAUSTED", re: /RESOURCE_EXHAUSTED|quota exceeded|exhausted your (?:daily )?quota|usage limit reached for all/i }
322
+ ]),
323
+ "kimi-code": Object.freeze([
324
+ { kind: "quota", source: "kimi.com/code/docs \u9519\u8BEF\u53C2\u8003", re: /you['’]?ve reached your (?:5-hour|weekly \(7-day\)|monthly) usage limit/i },
325
+ { kind: "rate-limit", source: "kimi.com/code/docs \u9519\u8BEF\u53C2\u8003", re: /you['’]?ve reached your concurrent request limit|we['’]?re receiving too many requests|engine is currently overloaded/i }
326
+ ]),
327
+ "minimax-code": Object.freeze([
328
+ { kind: "quota", source: "platform.minimax.io \u9519\u8BEF\u7801 2056", re: /(?:\bcode\b["'\s:=]*|\[)2056\b|usage limit exceeded|token plan usage limit reached/i },
329
+ { kind: "rate-limit", source: "platform.minimax.io \u9519\u8BEF\u7801 2045", re: /(?:\bcode\b["'\s:=]*|\[)2045\b|rate growth limit/i }
330
+ ]),
331
+ zcode: Object.freeze([
332
+ { kind: "quota", source: "docs.z.ai / docs.bigmodel.cn \u9519\u8BEF\u7801 1308\u20131321", re: /(?:\bcode\b["'\s:=]*|\[)13(?:08|09|10|1[6-9]|2[01])\b|usage limit reached for|weekly\/monthly limit exhausted|已达到.{0,20}使用上限|套餐已到期|每周\/每月使用上限/i },
333
+ { kind: "rate-limit", source: "docs.z.ai \u9519\u8BEF\u7801 1302/1305", re: /(?:\bcode\b["'\s:=]*|\[)130[25]\b|rate limit reached for requests|速率限制|访问量过大/i }
334
+ ]),
335
+ "*": Object.freeze([
336
+ { kind: "rate-limit", source: "HTTP 429\uFF08\u901A\u7528\uFF09", re: /\b429\b|too many requests|rate[_ ]limit/i }
337
+ ])
338
+ });
339
+ var clean = (value) => typeof value === "string" ? value.trim() : "";
340
+ function parseQuotaPatterns(value) {
341
+ const patterns = {};
342
+ const errors = [];
343
+ if (value === void 0 || value === null || clean(value) === "") return { patterns, errors };
344
+ let input;
345
+ try {
346
+ input = JSON.parse(value);
347
+ } catch {
348
+ return { patterns, errors: ["quotaPatternsJson \u4E0D\u662F\u6709\u6548\u7684 JSON"] };
349
+ }
350
+ if (!input || typeof input !== "object" || Array.isArray(input)) return { patterns, errors: ["quotaPatternsJson \u5FC5\u987B\u662F\u5BF9\u8C61"] };
351
+ for (const [key, entry] of Object.entries(input).slice(0, 40)) {
352
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
353
+ errors.push(`${key}: \u5FC5\u987B\u662F\u5BF9\u8C61`);
354
+ continue;
355
+ }
356
+ const list = [];
357
+ for (const [field2, kind] of [["quota", "quota"], ["rateLimit", "rate-limit"]]) {
358
+ const values = entry[field2];
359
+ if (values === void 0) continue;
360
+ if (!Array.isArray(values)) {
361
+ errors.push(`${key}.${field2}: \u5FC5\u987B\u662F\u6570\u7EC4`);
362
+ continue;
363
+ }
364
+ for (const source of values.slice(0, 20)) {
365
+ if (typeof source !== "string" || !source || source.length > 200) {
366
+ errors.push(`${key}.${field2}: \u6BCF\u9879\u5FC5\u987B\u662F 1\u2013200 \u5B57\u7B26\u7684\u6B63\u5219`);
367
+ continue;
368
+ }
369
+ try {
370
+ list.push({ kind, source: "\u7528\u6237\u914D\u7F6E", re: new RegExp(source, "i") });
371
+ } catch {
372
+ errors.push(`${key}.${field2}: \u65E0\u6548\u6B63\u5219 ${source.slice(0, 40)}`);
373
+ }
374
+ }
375
+ }
376
+ if (list.length) patterns[key] = list;
377
+ }
378
+ return { patterns, errors };
379
+ }
380
+ var SUBSCRIPTION_STATE_LABEL = Object.freeze({
381
+ "logged-in": "\u5DF2\u767B\u5F55\u8BA2\u9605\u8D26\u53F7",
382
+ "plan-key": "\u7F16\u7A0B\u5957\u9910 Key \u8DEF\u7EBF",
383
+ "api-key-only": "\u4EC5 API Key \u767B\u5F55",
384
+ "logged-out": "\u672A\u767B\u5F55",
385
+ exhausted: "\u989D\u5EA6\u5DF2\u7528\u5C3D",
386
+ unknown: "\u767B\u5F55\u72B6\u6001\u672A\u77E5",
387
+ none: "\u65E0\u8BA2\u9605"
388
+ });
389
+
390
+ // .dsh-plugin/shared/security-boundaries.mjs
391
+ var READ_ONLY_SCOPE = Object.freeze({
392
+ "claude-code": "\u5F53\u524D\u4F1A\u8BDD\u5DE5\u4F5C\u533A\uFF08\u4EC5 Read/Glob/Grep \u5DE5\u5177\uFF0CdontAsk \u6A21\u5F0F\u62D2\u7EDD\u672A\u6388\u6743\u7684\u5DE5\u4F5C\u533A\u5916\u8BFB\u53D6\uFF09",
393
+ codex: "\u5F53\u524D\u7528\u6237\u53EF\u8BFB\u7684\u5168\u90E8\u6587\u4EF6\uFF08Codex read-only \u6C99\u7BB1\u53EA\u7981\u6B62\u5199\u5165\u548C\u8054\u7F51\u547D\u4EE4\uFF09",
394
+ gemini: "\u5F53\u524D\u4F1A\u8BDD\u5DE5\u4F5C\u533A\uFF08Gemini CLI \u9ED8\u8BA4\u5DE5\u4F5C\u533A\u9650\u5236\uFF09"
395
+ });
396
+ function toolBoundary(toolId, { sandboxed = false, platform = "unknown" } = {}) {
397
+ const directOnly = toolId === "gemini";
398
+ const harnessSandbox = sandboxed && !directOnly;
399
+ return {
400
+ toolId,
401
+ readOnly: {
402
+ readable: READ_ONLY_SCOPE[toolId] ?? "\u5F53\u524D\u4F1A\u8BDD\u5DE5\u4F5C\u533A",
403
+ writable: "\u65E0\uFF08\u53EA\u8BFB\u8FD0\u884C\uFF0C\u4E0D\u5E94\u7528\u4EFB\u4F55\u6539\u52A8\uFF09",
404
+ sandbox: harnessSandbox ? platform === "win32" ? "Harness \u8FDB\u7A0B\u6C99\u7BB1\uFF08Windows ACL \u540E\u7AEF\u4E3A\u90E8\u5206\u5F3A\u5236\uFF09" : "Harness \u8FDB\u7A0B\u6C99\u7BB1" : "\u65E0 Harness \u6C99\u7BB1\uFF1A\u76F4\u63A5\u542F\u52A8 CLI\uFF0C\u53EA\u8BFB\u4EC5\u7531 CLI \u81EA\u8EAB\u53C2\u6570\u4FDD\u8BC1",
405
+ direct: !harnessSandbox
406
+ },
407
+ write: toolId === "gemini" ? null : {
408
+ readable: "\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\uFF08\u5F53\u524D\u4ED3\u5E93\u7684\u5E72\u51C0\u526F\u672C\uFF09",
409
+ writable: "\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\uFF1BCLI \u6210\u529F\u4E14\u539F\u5DE5\u4F5C\u533A\u672A\u53D8\u52A8\u65F6\uFF0C\u624D\u628A\u6E90\u4EE3\u7801\u8865\u4E01\u5E94\u7528\u56DE\u5F53\u524D\u5DE5\u4F5C\u533A",
410
+ sandbox: "Harness \u8FDB\u7A0B\u6C99\u7BB1\uFF0C\u7F3A\u5C11\u6C99\u7BB1\u65F6\u62D2\u7EDD\u542F\u52A8",
411
+ requiresApproval: true
412
+ }
413
+ };
414
+ }
415
+
249
416
  // .dsh-plugin/client/router-main.jsx
250
- var import_react2 = __toESM(require("react"), 1);
417
+ var import_react4 = __toESM(require("react"), 1);
418
+
419
+ // .dsh-plugin/shared/routing-presets.mjs
420
+ var DEFAULT_ROUTING_PRESET = "balanced";
421
+ var ROUTING_PRESETS = Object.freeze({
422
+ economy: Object.freeze({
423
+ id: "economy",
424
+ label: "\u7701\u94B1\u4F18\u5148",
425
+ description: "\u66F4\u770B\u91CD\u5355\u4EF7\uFF0C\u5141\u8BB8\u8D28\u91CF\u7565\u4F4E\u7684\u6A21\u578B\u627F\u62C5\u7B80\u5355\u548C\u4E2D\u7B49\u4EFB\u52A1\u3002",
426
+ floorDelta: -0.04,
427
+ tilt: Object.freeze({ quality: 0.75, cost: 1.6, latency: 1.1 })
428
+ }),
429
+ balanced: Object.freeze({
430
+ id: "balanced",
431
+ label: "\u5747\u8861",
432
+ description: "\u9ED8\u8BA4\uFF1A\u6309\u4EFB\u52A1\u96BE\u5EA6\u5E73\u8861\u8D28\u91CF\u3001\u6210\u672C\u548C\u901F\u5EA6\u3002",
433
+ floorDelta: 0,
434
+ tilt: Object.freeze({})
435
+ }),
436
+ quality: Object.freeze({
437
+ id: "quality",
438
+ label: "\u6548\u679C\u4F18\u5148",
439
+ description: "\u66F4\u770B\u91CD\u8D28\u91CF\uFF0C\u63D0\u9AD8\u66FF\u4EE3\u6A21\u578B\u5FC5\u987B\u8FBE\u5230\u7684\u8D28\u91CF\u95E8\u69DB\u3002",
440
+ floorDelta: 0.04,
441
+ tilt: Object.freeze({ quality: 1.35, cost: 0.5, specialty: 1.2, reasoning: 1.2 })
442
+ })
443
+ });
444
+ function normalizeRoutingPreset(value) {
445
+ return Object.hasOwn(ROUTING_PRESETS, value) ? value : DEFAULT_ROUTING_PRESET;
446
+ }
447
+ function routingPreset(value) {
448
+ return ROUTING_PRESETS[normalizeRoutingPreset(value)];
449
+ }
450
+ function presetWeights(weights, preset) {
451
+ const { tilt } = routingPreset(preset);
452
+ if (!weights || Object.keys(tilt).length === 0) return weights;
453
+ const total = Object.values(weights).reduce((sum, value) => sum + value, 0);
454
+ const tilted = Object.fromEntries(Object.entries(weights).map(([key, value]) => [key, value * (tilt[key] ?? 1)]));
455
+ const tiltedTotal = Object.values(tilted).reduce((sum, value) => sum + value, 0);
456
+ return Object.freeze(Object.fromEntries(Object.entries(tilted).map(([key, value]) => [key, value * total / tiltedTotal])));
457
+ }
458
+ function presetFloor(floor, preset) {
459
+ const value = Number(floor) + routingPreset(preset).floorDelta;
460
+ return Math.max(0.5, Math.min(0.97, value));
461
+ }
251
462
 
252
463
  // .dsh-plugin/shared/livebench.mjs
253
464
  var TASK_ALIASES = Object.freeze({
@@ -334,8 +545,8 @@ var OPENCODE_CATALOG_PROVIDERS = Object.freeze([
334
545
  "opencode-zen",
335
546
  "opencode-go-zen"
336
547
  ]);
337
- function classifyTask(text2) {
338
- const value = String(text2 ?? "");
548
+ function classifyTask(text4) {
549
+ const value = String(text4 ?? "");
339
550
  if (value.length < 80 && /翻译|解释|translate|explain/i.test(value)) return "general";
340
551
  return detectTaskTypes(value)[0] ?? "general";
341
552
  }
@@ -355,8 +566,8 @@ var TASK_TYPE_LABELS = Object.freeze({
355
566
  summarization: "\u6458\u8981\u4E0E\u6574\u7406",
356
567
  writing: "\u5199\u4F5C\u4E0E\u8868\u8FBE"
357
568
  });
358
- function detectTaskTypes(text2) {
359
- const value = String(text2 ?? "");
569
+ function detectTaskTypes(text4) {
570
+ const value = String(text4 ?? "");
360
571
  const ranked = TASK_TYPE_RULES.map(([type, pattern]) => ({
361
572
  type,
362
573
  signals: value.match(new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`))?.length ?? 0
@@ -364,8 +575,8 @@ function detectTaskTypes(text2) {
364
575
  ranked.sort((left, right) => right.signals - left.signals || left.type.localeCompare(right.type));
365
576
  return ranked.map((item) => item.type);
366
577
  }
367
- function assessComplexity(text2) {
368
- const value = String(text2 ?? "");
578
+ function assessComplexity(text4) {
579
+ const value = String(text4 ?? "");
369
580
  const lengthScore = clamp(value.length / 2200);
370
581
  const requirementScore = clamp((value.match(/(?:^|\n)\s*(?:[-*]|\d+[.)]|[一二三四五六七八九十]+[、.])/g) ?? []).length / 8);
371
582
  const codeScore = /(代码|工程|架构|接口|实现|部署|测试|code|api|debug)/i.test(value) ? 0.22 : 0;
@@ -387,7 +598,8 @@ function specialtyMatch(model, taskType, liveScores = {}) {
387
598
  return 0.38;
388
599
  }
389
600
  function qualityForTask(row, taskType) {
390
- return asScore(row?.liveScores?.[taskType]) ?? asScore(row?.liveOverall) ?? row?.metadata?.quality ?? row?.quality ?? 0;
601
+ const base = asScore(row?.liveScores?.[taskType]) ?? asScore(row?.liveOverall) ?? row?.metadata?.quality ?? row?.quality ?? 0;
602
+ return row?.qualityBias ? clamp(base + row.qualityBias) : base;
391
603
  }
392
604
  function specialtyForTask(row, taskType) {
393
605
  return specialtyMatch(row.metadata, taskType, row.liveScores);
@@ -454,10 +666,10 @@ function costScore(pricing, maxCost, cacheReadRatio = 0, cacheWriteRatio = 0) {
454
666
  if (maxCost <= 0) return mean === 0 ? 1 : 0;
455
667
  return clamp(1 - mean / maxCost);
456
668
  }
457
- function estimateCost(model, text2, outputTokens = 900, pricingOverrides = {}, cacheReadRatio = 0, cacheWriteRatio = 0) {
669
+ function estimateCost(model, text4, outputTokens = 900, pricingOverrides = {}, cacheReadRatio = 0, cacheWriteRatio = 0) {
458
670
  const pricing = pricingFor(model, pricingOverrides);
459
671
  if (pricing === null) return null;
460
- const inputTokens = Math.max(80, Math.ceil(String(text2 ?? "").length / 3.7));
672
+ const inputTokens = Math.max(80, Math.ceil(String(text4 ?? "").length / 3.7));
461
673
  const ratios = normalizedCacheRatios(cacheReadRatio, cacheWriteRatio);
462
674
  const cacheReadTokens = Math.min(inputTokens, Math.max(0, Math.round(inputTokens * ratios.read)));
463
675
  const cacheWriteTokens = Math.min(inputTokens - cacheReadTokens, Math.max(0, Math.round(inputTokens * ratios.write)));
@@ -469,8 +681,8 @@ function modelMetadata(name) {
469
681
  if (!key) return null;
470
682
  return MODEL_CATALOG.find((model) => model.aliases.some((alias) => key === normalize(alias))) ?? null;
471
683
  }
472
- function taskTokenBudget(text2, task, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
473
- const inputTokens = Math.max(80, Math.ceil(String(text2 ?? "").length / 3.7));
684
+ function taskTokenBudget(text4, task, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
685
+ const inputTokens = Math.max(80, Math.ceil(String(text4 ?? "").length / 3.7));
474
686
  const multipliers = {
475
687
  analysis: { input: 0.9, output: 0.55 },
476
688
  execution: { input: 1.2, output: (task.difficulty ?? complexity) === "complex" ? 1.45 : 1 },
@@ -534,10 +746,10 @@ function looksLikeRequirement(value) {
534
746
  const item = requirementText(value);
535
747
  return item.length >= 3 && !/[::]$/u.test(item) && !/(?:以下|下列|如下)(?:的)?(?:任务|需求|工作|事项|要求)/u.test(item) && REQUIREMENT_ACTION.test(item.slice(0, 32));
536
748
  }
537
- function explicitRequirements(text2) {
749
+ function explicitRequirements(text4) {
538
750
  const visibleLines = [];
539
751
  let fence = null;
540
- for (const line of String(text2 ?? "").split(/\r?\n/u)) {
752
+ for (const line of String(text4 ?? "").split(/\r?\n/u)) {
541
753
  const marker2 = /^\s*(`{3,}|~{3,})/u.exec(line);
542
754
  if (fence) {
543
755
  if (marker2 && marker2[1][0] === fence.char && marker2[1].length >= fence.length && !line.slice(marker2[0].length).trim()) fence = null;
@@ -569,16 +781,57 @@ function explicitRequirements(text2) {
569
781
  }
570
782
  return [];
571
783
  }
572
- function taskPackages(taskType, text2, band) {
784
+ var CN_DIGITS = Object.freeze({ \u4E00: 1, \u4E8C: 2, \u4E24: 2, \u4E09: 3, \u56DB: 4, \u4E94: 5, \u516D: 6, \u4E03: 7, \u516B: 8, \u4E5D: 9, \u5341: 10 });
785
+ var stepNumber = (token) => {
786
+ const value = String(token ?? "").trim();
787
+ if (/^\d{1,2}$/u.test(value)) return Number(value);
788
+ if (/^十[一二三四五六七八九]?$/u.test(value)) return 10 + (CN_DIGITS[value[1]] ?? 0);
789
+ if (/^[一二两三四五六七八九]十?$/u.test(value)) return CN_DIGITS[value[0]] * (value.length === 2 ? 10 : 1);
790
+ return null;
791
+ };
792
+ var STEP_TOKEN = "(?:\\d{1,2}|[\u4E00\u4E8C\u4E24\u4E09\u56DB\u4E94\u516D\u4E03\u516B\u4E5D\u5341]{1,2})";
793
+ var STEP_LIST = `${STEP_TOKEN}(?:\\s*(?:[\u3001,\uFF0C/]|\u548C|\u4E0E|\u53CA|\u4EE5\u53CA|and|&|-|~|\u5230|\u81F3)\\s*(?:\u7B2C\\s*)?${STEP_TOKEN})*`;
794
+ var STEP_REFERENCE_PATTERNS = Object.freeze([
795
+ // 依赖第 1 步 / 基于第 2、3 步 / 根据步骤 1 / 在第 2 步完成后 / 第 1 步之后
796
+ new RegExp(`(?:\u4F9D\u8D56|\u4F9D\u9760|\u53D6\u51B3\u4E8E|\u57FA\u4E8E|\u6839\u636E|\u627F\u63A5|\u4F7F\u7528|\u5229\u7528|\u9700\u8981|\u7B49\u5F85|\u5F85)(?:\u4E8E)?\\s*(?:\u7B2C\\s*(${STEP_LIST})\\s*(?:\u6B65|\u9879|\u4E2A?\u6B65\u9AA4|\u6761)|\u6B65\u9AA4\\s*(${STEP_LIST}))`, "giu"),
797
+ new RegExp(`(?:\u5728|\u7B49)?\\s*\u7B2C\\s*(${STEP_LIST})\\s*(?:\u6B65|\u9879|\u4E2A?\u6B65\u9AA4|\u6761)(?:\u5B8C\u6210|\u7ED3\u675F|\u505A\u5B8C)?(?:\u4E4B\u540E|\u4EE5\u540E|\u540E)`, "giu"),
798
+ new RegExp(`\u6B65\u9AA4\\s*(${STEP_LIST})\\s*(?:\u5B8C\u6210|\u7ED3\u675F)?(?:\u4E4B\u540E|\u4EE5\u540E|\u540E)`, "giu"),
799
+ // depends on step 1 / after steps 1 and 2 / based on step #2 / requires step 3
800
+ new RegExp(`(?:depends?\\s+on|depending\\s+on|after|based\\s+on|builds?\\s+on|requires?|using(?:\\s+the\\s+output\\s+of)?)\\s+(?:the\\s+(?:result|output)s?\\s+of\\s+)?(?:steps?|items?|#)\\s*#?(${STEP_LIST})`, "giu")
801
+ ]);
802
+ function explicitStepReferences(objective) {
803
+ const found = /* @__PURE__ */ new Set();
804
+ const value = String(objective ?? "");
805
+ for (const pattern of STEP_REFERENCE_PATTERNS) {
806
+ pattern.lastIndex = 0;
807
+ for (const match of value.matchAll(pattern)) {
808
+ const list = match.slice(1).find(Boolean) ?? "";
809
+ const parts = list.split(/\s*(?:[、,,/]|和|与|及|以及|and|&)\s*/iu);
810
+ for (const part of parts) {
811
+ const range = /^(.+?)\s*(?:-|~|到|至)\s*(?:第\s*)?(.+)$/u.exec(part);
812
+ if (range) {
813
+ const from = stepNumber(range[1]);
814
+ const to = stepNumber(range[2]);
815
+ if (from && to && to >= from && to - from < 20) for (let step2 = from; step2 <= to; step2 += 1) found.add(step2);
816
+ continue;
817
+ }
818
+ const step = stepNumber(part.replace(/^第\s*/u, ""));
819
+ if (step) found.add(step);
820
+ }
821
+ }
822
+ }
823
+ return [...found].sort((a, b) => a - b);
824
+ }
825
+ function taskPackages(taskType, text4, band) {
573
826
  if (band !== "complex") {
574
827
  const task = { id: "execution", name: "\u76F4\u63A5\u56DE\u7B54\u4E0E\u5FC5\u8981\u6821\u9A8C", type: taskType, purpose: "execution", difficulty: band, criticality: 0.65, dependsOn: [], preferredReasoningEffort: band === "simple" ? "low" : "medium" };
575
828
  return [{ ...task, qualityFloor: taskQualityFloor(band, task) }];
576
829
  }
577
- const value = String(text2 ?? "");
830
+ const value = String(text4 ?? "");
578
831
  const packages = [
579
832
  { id: "analysis", name: "\u95EE\u9898\u5EFA\u6A21\u4E0E\u7EA6\u675F\u63D0\u53D6", type: "reasoning", purpose: "analysis", difficulty: "balanced", criticality: 0.8, dependsOn: [], preferredReasoningEffort: "medium" }
580
833
  ];
581
- const requirements = explicitRequirements(text2);
834
+ const requirements = explicitRequirements(text4);
582
835
  if (requirements.length >= 2) {
583
836
  const groups = requirements.length > MAX_EXPLICIT_EXECUTION_PACKAGES ? [
584
837
  ...requirements.slice(0, MAX_EXPLICIT_EXECUTION_PACKAGES - 1).map((item) => [item]),
@@ -589,7 +842,9 @@ function taskPackages(taskType, text2, band) {
589
842
  const type = detectTaskTypes(objective)[0] ?? "general";
590
843
  const difficulty = group.length > 1 ? "complex" : requirementDifficulty(objective, type);
591
844
  const previous = packages.at(-1);
592
- const sequential = /^(?:最后|然后|接着|随后|再|基于|根据|测试|验证|部署|发布)|(?:完成|结束|实现)后/u.test(objective);
845
+ const groupOf = (step) => requirements.length > MAX_EXPLICIT_EXECUTION_PACKAGES && step >= MAX_EXPLICIT_EXECUTION_PACKAGES ? MAX_EXPLICIT_EXECUTION_PACKAGES - 1 : step - 1;
846
+ const explicit = [...new Set(group.flatMap((item) => explicitStepReferences(item)).map(groupOf))].filter((target) => target >= 0 && target < index).map((target) => `execution-${target + 1}`);
847
+ const sequential = explicit.length === 0 && /^(?:最后|然后|接着|随后|再|基于|根据|测试|验证|部署|发布)|(?:完成|结束|实现)后/u.test(objective);
593
848
  packages.push({
594
849
  id: `execution-${index + 1}`,
595
850
  name: group.length === 1 ? `\u9700\u6C42 ${index + 1}\uFF1A${group[0].slice(0, 28)}` : `\u9700\u6C42 ${index + 1}\uFF1A\u5176\u4F59 ${group.length} \u9879`,
@@ -598,12 +853,12 @@ function taskPackages(taskType, text2, band) {
598
853
  purpose: "execution",
599
854
  difficulty,
600
855
  criticality: difficulty === "simple" ? 0.55 : difficulty === "balanced" ? 0.72 : 0.86,
601
- dependsOn: sequential && previous?.purpose === "execution" ? ["analysis", previous.id] : ["analysis"],
856
+ dependsOn: explicit.length ? ["analysis", ...explicit] : sequential && previous?.purpose === "execution" ? ["analysis", previous.id] : ["analysis"],
602
857
  preferredReasoningEffort: difficulty === "simple" ? "low" : difficulty === "balanced" ? "medium" : "high"
603
858
  });
604
859
  });
605
860
  } else {
606
- const domains = [...new Set([...detectTaskTypes(text2), taskType].filter((type) => type !== "general"))];
861
+ const domains = [...new Set([...detectTaskTypes(text4), taskType].filter((type) => type !== "general"))];
607
862
  for (const type of domains.length > 0 ? domains : [taskType]) {
608
863
  const objective = value.split(/[,,。;;]|最后|然后|接着|并且/u).map((item) => item.trim()).filter((item) => detectTaskTypes(item).includes(type)).join("\uFF1B") || value;
609
864
  const difficulty = requirementDifficulty(objective, type);
@@ -648,6 +903,7 @@ var SYNTHESIS_WEIGHTS = Object.freeze({ quality: 0.58, cost: 0.08, latency: 0.04
648
903
  var ROUTING_BEAM_WIDTH = 256;
649
904
  var ROUTING_CANDIDATE_LIMIT = 12;
650
905
  function weightsForTask(weights, task) {
906
+ if (task.weights) return task.weights;
651
907
  return task.purpose === "synthesis" ? SYNTHESIS_WEIGHTS : OBJECTIVE_WEIGHTS[task.difficulty] ?? weights;
652
908
  }
653
909
  function compareText(left, right) {
@@ -714,19 +970,19 @@ function candidateUtility(row, task, weights, maxCost, usedRoutes, cacheReadRati
714
970
  const score = weights.quality * quality + weights.cost * cost + weights.latency * (1 - clamp(row.latency * reasoning.multiplier.latency)) + weights.specialty * specialtyForTask(row, task.type) + (weights.reasoning ?? 0) * reasoning.reasoningFit - weights.risk * row.risk - duplicatePenalty - qualityGap * (task.criticality ?? 0.75) + synthesisPreference;
715
971
  return { score, floor, qualityGap, ...reasoning };
716
972
  }
717
- function taskCost(row, task, text2, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
973
+ function taskCost(row, task, text4, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
718
974
  if (row?.pricing === null) return 0;
719
975
  const decision = row === null ? null : reasoningDecision(row, task);
720
- const tokens = taskTokenBudget(text2, { ...task, reasoningEffort: decision?.reasoningEffort }, complexity, cacheReadRatio, cacheWriteRatio);
976
+ const tokens = taskTokenBudget(text4, { ...task, reasoningEffort: decision?.reasoningEffort }, complexity, cacheReadRatio, cacheWriteRatio);
721
977
  return row === null ? 0 : ((tokens.inputTokens - tokens.cacheReadTokens - tokens.cacheWriteTokens) * row.pricing.input + tokens.cacheReadTokens * row.pricing.cacheRead + tokens.cacheWriteTokens * row.pricing.cacheWrite + tokens.outputTokens * row.pricing.output) / 1e6;
722
978
  }
723
- function dominates(left, right, task, text2, complexity, cacheReadRatio, cacheWriteRatio) {
979
+ function dominates(left, right, task, text4, complexity, cacheReadRatio, cacheWriteRatio) {
724
980
  if (left.pricing === null || right.pricing === null) return false;
725
981
  const leftReasoning = reasoningDecision(left, task);
726
982
  const rightReasoning = reasoningDecision(right, task);
727
983
  const leftValues = {
728
984
  quality: qualityForTask(left, task.type),
729
- cost: taskCost(left, task, text2, complexity, cacheReadRatio, cacheWriteRatio),
985
+ cost: taskCost(left, task, text4, complexity, cacheReadRatio, cacheWriteRatio),
730
986
  latency: clamp(left.latency * leftReasoning.multiplier.latency),
731
987
  specialty: specialtyForTask(left, task.type),
732
988
  reasoning: leftReasoning.reasoningFit,
@@ -734,7 +990,7 @@ function dominates(left, right, task, text2, complexity, cacheReadRatio, cacheWr
734
990
  };
735
991
  const rightValues = {
736
992
  quality: qualityForTask(right, task.type),
737
- cost: taskCost(right, task, text2, complexity, cacheReadRatio, cacheWriteRatio),
993
+ cost: taskCost(right, task, text4, complexity, cacheReadRatio, cacheWriteRatio),
738
994
  latency: clamp(right.latency * rightReasoning.multiplier.latency),
739
995
  specialty: specialtyForTask(right, task.type),
740
996
  reasoning: rightReasoning.reasoningFit,
@@ -744,7 +1000,7 @@ function dominates(left, right, task, text2, complexity, cacheReadRatio, cacheWr
744
1000
  const strictlyBetter = leftValues.quality > rightValues.quality || leftValues.cost < rightValues.cost || leftValues.latency < rightValues.latency || leftValues.specialty > rightValues.specialty || leftValues.reasoning > rightValues.reasoning || leftValues.risk < rightValues.risk;
745
1001
  return noWorse && strictlyBetter;
746
1002
  }
747
- function candidatePool(rows, task, weights, maxCost, text2, complexity, cacheReadRatio, cacheWriteRatio) {
1003
+ function candidatePool(rows, task, weights, maxCost, text4, complexity, cacheReadRatio, cacheWriteRatio) {
748
1004
  const eligibleRows = task.type === "vision" ? rows.filter((row) => row.inputModalities.length === 0 || row.inputModalities.includes("image")) : rows;
749
1005
  const floor = Number(task.qualityFloor ?? 0);
750
1006
  const feasible = eligibleRows.filter((row) => qualityForTask(row, task.type) >= floor);
@@ -753,9 +1009,9 @@ function candidatePool(rows, task, weights, maxCost, text2, complexity, cacheRea
753
1009
  const scored = source.map((row) => ({
754
1010
  row,
755
1011
  decision: candidateUtility(row, task, taskWeights, maxCost, /* @__PURE__ */ new Set(), cacheReadRatio, cacheWriteRatio),
756
- cost: taskCost(row, task, text2, complexity, cacheReadRatio, cacheWriteRatio)
1012
+ cost: taskCost(row, task, text4, complexity, cacheReadRatio, cacheWriteRatio)
757
1013
  }));
758
- const frontier = scored.filter((item) => !source.some((other) => other !== item.row && dominates(other, item.row, task, text2, complexity, cacheReadRatio, cacheWriteRatio)));
1014
+ const frontier = scored.filter((item) => !source.some((other) => other !== item.row && dominates(other, item.row, task, text4, complexity, cacheReadRatio, cacheWriteRatio)));
759
1015
  const essential = [
760
1016
  scored.slice().sort((left, right) => left.cost - right.cost || compareRowsStable(left.row, right.row))[0],
761
1017
  scored.slice().sort((left, right) => right.decision.score - left.decision.score || compareRowsStable(left.row, right.row))[0],
@@ -777,8 +1033,8 @@ function compareUtilityStates(left, right) {
777
1033
  function compareCostStates(left, right) {
778
1034
  return left.relaxedCount - right.relaxedCount || left.qualityShortfall - right.qualityShortfall || left.cost - right.cost || right.score - left.score || left.switches - right.switches || compareText(stateSignature(left), stateSignature(right));
779
1035
  }
780
- function solveAssignments({ rows, tasks, weights, maxCost, text: text2, complexity, budget, cacheReadRatio, cacheWriteRatio, minimizeCost = false }) {
781
- const pools = tasks.map((task) => candidatePool(rows, task, weights, maxCost, text2, complexity, cacheReadRatio, cacheWriteRatio));
1036
+ function solveAssignments({ rows, tasks, weights, maxCost, text: text4, complexity, budget, cacheReadRatio, cacheWriteRatio, minimizeCost = false }) {
1037
+ const pools = tasks.map((task) => candidatePool(rows, task, weights, maxCost, text4, complexity, cacheReadRatio, cacheWriteRatio));
782
1038
  if (pools.some((pool) => pool.options.length === 0)) return null;
783
1039
  const suffixMinimum = Array(tasks.length + 1).fill(0);
784
1040
  for (let index = tasks.length - 1; index >= 0; index -= 1) {
@@ -833,15 +1089,16 @@ function solveAssignments({ rows, tasks, weights, maxCost, text: text2, complexi
833
1089
  minimumFeasibleCost: suffixMinimum[0]
834
1090
  };
835
1091
  }
836
- function buildPlan({ text: text2 = "", available = [], mode = "collective", pricing = {}, liveBench = null, liveBenchError = "", budgetUsd = 0, cacheReadRatio = 0, cacheWriteRatio = 0 } = {}) {
837
- const firstLine = String(text2 ?? "").split(/\r?\n/u)[0].trim();
1092
+ function buildPlan({ text: text4 = "", available = [], mode = "collective", pricing = {}, liveBench = null, liveBenchError = "", budgetUsd = 0, cacheReadRatio = 0, cacheWriteRatio = 0, preset = DEFAULT_ROUTING_PRESET } = {}) {
1093
+ const presetId = normalizeRoutingPreset(preset);
1094
+ const firstLine = String(text4 ?? "").split(/\r?\n/u)[0].trim();
838
1095
  const transformOnly = /^(?:请|帮我)?(?:总结|概括|翻译|摘要|解释)(?:以下|下列|下面|这份|这些)/u.test(firstLine) && !/(?:执行|完成|实施|分配)/u.test(firstLine);
839
- const assessed = assessComplexity(transformOnly ? firstLine : text2);
840
- const requirements = explicitRequirements(text2);
1096
+ const assessed = assessComplexity(transformOnly ? firstLine : text4);
1097
+ const requirements = explicitRequirements(text4);
841
1098
  const compound = shouldSplitRequirements(requirements);
842
1099
  const complexity = compound && assessed.band !== "complex" ? { value: Math.max(0.66, assessed.value), band: "complex" } : assessed;
843
- const taskType = classifyTask(transformOnly ? firstLine : text2);
844
- const weights = OBJECTIVE_WEIGHTS[complexity.band];
1100
+ const taskType = classifyTask(transformOnly ? firstLine : text4);
1101
+ const weights = presetWeights(OBJECTIVE_WEIGHTS[complexity.band], presetId);
845
1102
  const discovered = Array.isArray(available) ? available.map((entry) => {
846
1103
  const rawEfforts = Array.isArray(entry.reasoningEfforts) ? entry.reasoningEfforts : [];
847
1104
  const reasoningEfforts = rawEfforts.map((effort) => String(effort?.id ?? effort ?? "")).filter(Boolean);
@@ -852,6 +1109,7 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
852
1109
  defaultReasoningEffort: entry.defaultReasoningEffort === void 0 ? void 0 : String(entry.defaultReasoningEffort),
853
1110
  reasoningKnown: entry.reasoningKnown === true || entry.reasoningKnown === void 0 && Array.isArray(entry.reasoningEfforts),
854
1111
  quality: asScore(entry.quality),
1112
+ qualityBias: Number.isFinite(entry.qualityBias) ? clamp(entry.qualityBias, -0.05, 0.05) : 0,
855
1113
  qualitySource: entry.qualitySource === "user" ? "user" : "route",
856
1114
  latency: asScore(entry.latency),
857
1115
  risk: asScore(entry.risk),
@@ -876,7 +1134,7 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
876
1134
  const live = liveBenchRow(liveBench, route.model);
877
1135
  const liveScores = live?.scores ?? {};
878
1136
  const liveOverall = asScore(live?.overall);
879
- const quality = asScore(liveScores?.[taskType]) ?? liveOverall ?? asScore(metadata.quality) ?? 0;
1137
+ const quality = clamp((asScore(liveScores?.[taskType]) ?? liveOverall ?? asScore(metadata.quality) ?? 0) + route.qualityBias);
880
1138
  const qualitySource = liveOverall !== void 0 || asScore(liveScores?.[taskType]) !== void 0 ? "livebench" : route.quality !== void 0 ? route.qualitySource : catalog ? "catalog-heuristic" : "unknown";
881
1139
  const userPrice = normalizedPrices[normalize(`${route.provider}/${route.model}`)] ?? normalizedPrices[normalize(route.model)];
882
1140
  const pricingRow = userPrice ?? route.pricing ?? null;
@@ -887,6 +1145,7 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
887
1145
  model: route.model,
888
1146
  metadata,
889
1147
  quality,
1148
+ qualityBias: route.qualityBias,
890
1149
  qualitySource,
891
1150
  pricingSource,
892
1151
  liveScores,
@@ -906,14 +1165,18 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
906
1165
  costOut: pricingRow.output,
907
1166
  cacheRead: pricingRow.cacheRead,
908
1167
  cacheWrite: pricingRow.cacheWrite
909
- }, text2, 900, {}, cacheReadRatio, cacheWriteRatio)
1168
+ }, text4, 900, {}, cacheReadRatio, cacheWriteRatio)
910
1169
  });
911
1170
  }
912
1171
  const maxCost = Math.max(1, ...rows.filter((row) => row.pricing !== null).map((row) => {
913
1172
  const effective = effectivePricing(row.pricing, cacheReadRatio, cacheWriteRatio);
914
1173
  return effective.input + effective.output;
915
1174
  }));
916
- const taskNodes = taskPackages(taskType, text2, complexity.band);
1175
+ const taskNodes = taskPackages(taskType, text4, complexity.band).map((task) => presetId === DEFAULT_ROUTING_PRESET ? task : {
1176
+ ...task,
1177
+ qualityFloor: presetFloor(task.qualityFloor, presetId),
1178
+ weights: presetWeights(weightsForTask(weights, task), presetId)
1179
+ });
917
1180
  const unassignableTasks = taskNodes.filter((task) => task.type === "vision" && !rows.some((row) => row.inputModalities.length === 0 || row.inputModalities.includes("image"))).map((task) => task.id);
918
1181
  const budget = Number(budgetUsd);
919
1182
  const utilityPlan = solveAssignments({
@@ -921,7 +1184,7 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
921
1184
  tasks: taskNodes,
922
1185
  weights,
923
1186
  maxCost,
924
- text: text2,
1187
+ text: text4,
925
1188
  complexity: complexity.band,
926
1189
  budget: Number.POSITIVE_INFINITY,
927
1190
  cacheReadRatio,
@@ -932,7 +1195,7 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
932
1195
  tasks: taskNodes,
933
1196
  weights,
934
1197
  maxCost,
935
- text: text2,
1198
+ text: text4,
936
1199
  complexity: complexity.band,
937
1200
  budget,
938
1201
  cacheReadRatio,
@@ -943,7 +1206,7 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
943
1206
  tasks: taskNodes,
944
1207
  weights,
945
1208
  maxCost,
946
- text: text2,
1209
+ text: text4,
947
1210
  complexity: complexity.band,
948
1211
  budget: Number.POSITIVE_INFINITY,
949
1212
  cacheReadRatio,
@@ -981,8 +1244,8 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
981
1244
  dependsOn: [...task.dependsOn ?? []]
982
1245
  }));
983
1246
  const costBreakdown = assignments.map(({ task, row, decision, estimatedCost, handoffPenalty }, index) => {
984
- const tokens = taskTokenBudget(text2, { ...task, reasoningEffort: decision?.reasoningEffort }, complexity.band, cacheReadRatio, cacheWriteRatio);
985
- const taskEstimate = estimatedCost ?? taskCost(row, task, text2, complexity.band, cacheReadRatio, cacheWriteRatio);
1247
+ const tokens = taskTokenBudget(text4, { ...task, reasoningEffort: decision?.reasoningEffort }, complexity.band, cacheReadRatio, cacheWriteRatio);
1248
+ const taskEstimate = estimatedCost ?? taskCost(row, task, text4, complexity.band, cacheReadRatio, cacheWriteRatio);
986
1249
  return {
987
1250
  stage: index + 1,
988
1251
  purpose: task.purpose,
@@ -1010,7 +1273,7 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
1010
1273
  const strongest = rows.reduce((best, row) => qualityForTask(row, task.type) > (best === null ? -1 : qualityForTask(best, task.type)) ? row : best, null);
1011
1274
  return { task, strongest };
1012
1275
  });
1013
- const baselineCost = baselineRows.every((item) => item.strongest?.pricing !== null && item.strongest !== null) ? baselineRows.reduce((sum, { task, strongest }) => sum + taskCost(strongest, task, text2, complexity.band, cacheReadRatio, cacheWriteRatio), 0) : null;
1276
+ const baselineCost = baselineRows.every((item) => item.strongest?.pricing !== null && item.strongest !== null) ? baselineRows.reduce((sum, { task, strongest }) => sum + taskCost(strongest, task, text4, complexity.band, cacheReadRatio, cacheWriteRatio), 0) : null;
1014
1277
  const qualityEvidenceComplete = assignments.length > 0 && assignments.every(({ row }) => ["livebench", "route", "user"].includes(row?.qualitySource)) && baselineRows.every(({ strongest }) => ["livebench", "route", "user"].includes(strongest?.qualitySource));
1015
1278
  const budgetExceeded = Number(budgetUsd) > 0 && totalEstimate !== null ? totalEstimate > Number(budgetUsd) : null;
1016
1279
  const savings = baselineCost === null || totalEstimate === null || !qualityEvidenceComplete ? null : baselineCost <= 0 ? 0 : clamp((baselineCost - totalEstimate) / baselineCost);
@@ -1019,6 +1282,7 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
1019
1282
  const reason = selected === null ? unassignableTasks.length > 0 ? `\u56FE\u50CF\u5DE5\u4F5C\u5305 ${unassignableTasks.join("\u3001")} \u6CA1\u6709\u53EF\u7528\u7684\u56FE\u50CF\u6A21\u578B\uFF0C\u65E0\u6CD5\u5F62\u6210\u5B8C\u6574\u5206\u914D\u8BA1\u5212\u3002` : "\u5C1A\u672A\u53D1\u73B0\u53EF\u7528\u6A21\u578B\uFF0C\u4FDD\u7559 Harness \u539F\u59CB\u6A21\u578B\u9009\u62E9\u3002" : `${complexity.band === "simple" ? "\u4F4E\u590D\u6742\u5EA6\u4F18\u5148\u6210\u672C\u3001\u54CD\u5E94\u901F\u5EA6\u4E0E\u8F83\u4F4E\u63A8\u7406\u5F00\u9500" : complexity.band === "balanced" ? "\u5728\u8D28\u91CF\u3001\u6210\u672C\u3001\u63A8\u7406\u7B49\u7EA7\u3001\u5EF6\u8FDF\u4E0E\u98CE\u9669\u4E4B\u95F4\u5E73\u8861" : "\u9AD8\u590D\u6742\u5EA6\u6267\u884C\u5305\u542B\u63A8\u7406\u7B49\u7EA7\u7684\u4F9D\u8D56\u611F\u77E5\u5168\u5C40\u7EA6\u675F\u5206\u914D"}\uFF1B\u4EFB\u52A1\u7C7B\u578B\u4E3A ${taskType}\uFF0C\u5DF2\u5BF9 ${String(subtasks.length)} \u4E2A\u5DE5\u4F5C\u5305\u8FDB\u884C Pareto \u526A\u679D\u548C\u6709\u754C\u7EC4\u5408\u641C\u7D22\u3002`;
1020
1283
  return {
1021
1284
  mode,
1285
+ preset: presetId,
1022
1286
  complexity: { value: Number(complexity.value.toFixed(3)), band: complexity.band },
1023
1287
  compound,
1024
1288
  unassignableTasks,
@@ -1060,16 +1324,47 @@ function buildPlan({ text: text2 = "", available = [], mode = "collective", pric
1060
1324
  }
1061
1325
 
1062
1326
  // .dsh-plugin/shared/harness-plan.mjs
1063
- var clean = (value) => typeof value === "string" ? value.trim() : "";
1064
- function channelForProvider(provider, installedToolIds = [], runnableToolIds = []) {
1327
+ var clean2 = (value) => typeof value === "string" ? value.trim() : "";
1328
+ var HEADLESS_TOOL_IDS = /* @__PURE__ */ new Set(["claude-code", "codex", "gemini"]);
1329
+ function channelForProvider(provider, installedToolIds = [], runnableToolIds = [], route = null, loggedOutToolIds = []) {
1330
+ const preference = normalizeExecutionPreference(route?.execution);
1065
1331
  const tool = toolForProvider(provider);
1332
+ if (preference === "api") {
1333
+ return {
1334
+ kind: "harness-llm",
1335
+ preference,
1336
+ ...tool ? { tool: tool.id, label: tool.label } : {},
1337
+ detail: "\u8BE5\u6A21\u578B\u914D\u7F6E\u4E3A\u53EA\u4F7F\u7528\u6A21\u578B\u76EE\u5F55 API\u3002"
1338
+ };
1339
+ }
1066
1340
  if (!tool || tool.unsupported) {
1067
- return { kind: "harness-llm", detail: "\u901A\u8FC7\u5B98\u65B9\u6A21\u578B\u76EE\u5F55 API \u8C03\u7528\u3002" };
1341
+ return { kind: "harness-llm", preference, detail: "\u901A\u8FC7\u5B98\u65B9\u6A21\u578B\u76EE\u5F55 API \u8C03\u7528\u3002" };
1068
1342
  }
1069
1343
  const installed = Array.isArray(installedToolIds) && installedToolIds.includes(tool.id);
1344
+ if (installed && Array.isArray(loggedOutToolIds) && loggedOutToolIds.includes(tool.id)) {
1345
+ return {
1346
+ kind: "harness-llm",
1347
+ preference,
1348
+ tool: tool.id,
1349
+ label: tool.label,
1350
+ loginRequired: true,
1351
+ detail: `${tool.label} \u5DF2\u5B89\u88C5\u4F46\u672A\u767B\u5F55\uFF08\u5F00\u7BB1\u4F53\u68C0\u7ED3\u679C\uFF09\uFF1B\u5B9E\u9645\u8C03\u7528\u76F4\u63A5\u4F7F\u7528\u6A21\u578B\u76EE\u5F55 API\uFF0C\u4E0D\u7B49\u5F85 CLI \u5931\u8D25\u3002`
1352
+ };
1353
+ }
1070
1354
  const runnable = installed && Array.isArray(runnableToolIds) && runnableToolIds.includes(tool.id);
1071
- return runnable ? { kind: "official-cli", tool: tool.id, label: tool.label, 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" : `${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` } : {
1355
+ const headless = installed && HEADLESS_TOOL_IDS.has(tool.id);
1356
+ if (runnable || headless) {
1357
+ return {
1358
+ kind: "official-cli",
1359
+ preference,
1360
+ tool: tool.id,
1361
+ 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`
1363
+ };
1364
+ }
1365
+ return {
1072
1366
  kind: "harness-llm",
1367
+ preference,
1073
1368
  tool: tool.id,
1074
1369
  label: tool.label,
1075
1370
  detail: installed ? `${tool.label} \u5DF2\u5B89\u88C5\uFF0C\u4F46\u5F53\u524D\u5E73\u53F0\u7F3A\u5C11\u7ECF\u6838\u9A8C\u7684\u6258\u7BA1\u6267\u884C\u9002\u914D\u5668\uFF1B\u5B9E\u9645\u8C03\u7528\u4F7F\u7528\u5B98\u65B9\u6A21\u578B\u76EE\u5F55 API\u3002` : `${tool.label} \u672A\u5B89\u88C5\uFF1B\u5B9E\u9645\u8C03\u7528\u4F7F\u7528\u5B98\u65B9\u6A21\u578B\u76EE\u5F55 API\u3002\u53EF\u5728\u5DE5\u4F5C\u53F0\u4E00\u952E\u5B89\u88C5\uFF0C\u6216\u8FD0\u884C /tools install ${tool.id}\u3002`
@@ -1080,6 +1375,8 @@ function annotate(channel) {
1080
1375
  executionChannel: channel.kind,
1081
1376
  ...channel.tool ? { channelTool: channel.tool } : {},
1082
1377
  ...channel.label ? { channelLabel: channel.label } : {},
1378
+ ...channel.preference ? { executionPreference: channel.preference } : {},
1379
+ ...channel.loginRequired ? { loginRequired: true } : {},
1083
1380
  channelDetail: channel.detail
1084
1381
  };
1085
1382
  }
@@ -1091,33 +1388,54 @@ function createPlanFromRoutes(task, availableRoutes, {
1091
1388
  pricing = {},
1092
1389
  liveBench = null,
1093
1390
  cacheReadRatio = 0,
1094
- cacheWriteRatio = 0
1391
+ cacheWriteRatio = 0,
1392
+ directProvider = "",
1393
+ directModel = "",
1394
+ preset = "balanced",
1395
+ loggedOutToolIds = []
1095
1396
  } = {}) {
1096
- const taskText = clean(task);
1397
+ const taskText = clean2(task);
1097
1398
  if (!taskText) throw new Error("task must contain text");
1399
+ const requestedDirect = mode === "direct" || clean2(directProvider) !== "" || clean2(directModel) !== "";
1098
1400
  const selectedMode = mode === "team" ? "team" : "single";
1099
- const routes = Array.isArray(availableRoutes) ? availableRoutes : [];
1401
+ let routes = Array.isArray(availableRoutes) ? availableRoutes : [];
1402
+ let directRoute = null;
1403
+ if (requestedDirect) {
1404
+ const provider = clean2(directProvider);
1405
+ const model = clean2(directModel);
1406
+ if (!provider || !model) throw new Error("\u6307\u5B9A\u5355\u4E00\u6A21\u578B\u9700\u8981\u540C\u65F6\u63D0\u4F9B provider \u548C model");
1407
+ const match = routes.filter((route) => route.provider === provider && route.model === model);
1408
+ if (match.length !== 1) throw new Error(`\u6307\u5B9A\u6A21\u578B ${provider}/${model} \u4E0D\u5728\u5F53\u524D\u6A21\u578B\u76EE\u5F55\u4E2D`);
1409
+ routes = match;
1410
+ directRoute = { provider, model };
1411
+ }
1100
1412
  const installedIds = Array.isArray(installedToolIds) ? installedToolIds.filter(Boolean) : [];
1101
1413
  const channelCache = /* @__PURE__ */ new Map();
1102
- const channelOf = (provider) => {
1103
- const key = String(provider ?? "");
1104
- if (!channelCache.has(key)) channelCache.set(key, channelForProvider(key, installedIds, runnableToolIds));
1414
+ const channelOf = (provider, model) => {
1415
+ const route = routes.find((item) => item.provider === provider && item.model === model);
1416
+ const key = `${String(provider ?? "")}\0${String(model ?? "")}\0${route?.execution ?? ""}`;
1417
+ if (!channelCache.has(key)) channelCache.set(key, channelForProvider(provider, installedIds, runnableToolIds, route, loggedOutToolIds));
1105
1418
  return channelCache.get(key);
1106
1419
  };
1107
1420
  const needsImage = detectTaskTypes(taskText).includes("vision");
1108
1421
  const plan = buildPlan({
1109
1422
  text: taskText,
1110
1423
  available: routes,
1111
- mode: selectedMode,
1424
+ mode: directRoute ? "single" : selectedMode,
1112
1425
  budgetUsd: Math.max(0, Number.isFinite(budgetUsd) ? budgetUsd : 0),
1113
1426
  pricing,
1114
1427
  liveBench,
1115
1428
  cacheReadRatio,
1116
- cacheWriteRatio
1429
+ cacheWriteRatio,
1430
+ preset
1117
1431
  });
1118
- const selectedChannel = plan.selected ? channelOf(plan.selected.provider) : null;
1432
+ const selectedChannel = plan.selected ? channelOf(plan.selected.provider, plan.selected.model) : null;
1119
1433
  return {
1120
1434
  ...plan,
1435
+ mode: directRoute ? "direct" : plan.mode,
1436
+ routingBypassed: directRoute !== null,
1437
+ directRoute,
1438
+ ...directRoute ? { reason: `\u5DF2\u6307\u5B9A ${directRoute.provider}/${directRoute.model}\uFF0C\u4E0D\u4E0E\u5176\u4ED6\u5DF2\u914D\u7F6E\u6A21\u578B\u6BD4\u8F83\u3002\u590D\u6742\u5EA6\u4ECD\u6309\u4EFB\u52A1\u6587\u672C\u4F30\u8BA1\u3002` } : {},
1121
1439
  contractVersion: 2,
1122
1440
  availableRoutes: routes,
1123
1441
  ...selectedChannel ? annotate(selectedChannel) : {},
@@ -1144,39 +1462,69 @@ function createPlanFromRoutes(task, availableRoutes, {
1144
1462
  recommendedModel: item.recommended,
1145
1463
  estimatedCost: plan.costBreakdown[index]?.estimatedCost ?? null,
1146
1464
  ...item.recommendedReasoningEffort ? { recommendedReasoningEffort: item.recommendedReasoningEffort } : {},
1147
- ...annotate(channelOf(item.recommendedProvider)),
1465
+ ...annotate(channelOf(item.recommendedProvider, item.recommended)),
1148
1466
  verificationChecklist: item.purpose === "synthesis" ? ["\u6838\u5BF9\u5404\u5DE5\u4F5C\u5305\u4EA4\u4ED8\u7269\u4E0E\u4F9D\u8D56", "\u8BB0\u5F55\u51B2\u7A81\u3001\u672A\u89E3\u51B3\u4E8B\u9879\u548C\u6700\u7EC8\u9A8C\u6536\u7ED3\u679C"] : item.type === "code" ? ["\u8BF4\u660E\u6539\u52A8\u6587\u4EF6\u4E0E\u63A5\u53E3", "\u8FD0\u884C\u4E0E\u6539\u52A8\u76F8\u5173\u7684\u9A8C\u8BC1\u5E76\u8BB0\u5F55\u7ED3\u679C", "\u5217\u51FA\u5C1A\u672A\u5B8C\u6210\u7684\u8FB9\u754C\u60C5\u51B5"] : item.type === "research" ? ["\u5217\u51FA\u6765\u6E90\u3001\u65E5\u671F\u548C\u53EF\u6838\u5BF9\u7684\u7ED3\u8BBA", "\u6807\u51FA\u63A8\u65AD\u4E0E\u4E0D\u786E\u5B9A\u4E8B\u9879"] : ["\u5217\u51FA\u4EA4\u4ED8\u5185\u5BB9\u548C\u9A8C\u6536\u4F9D\u636E", "\u6807\u51FA\u672A\u5B8C\u6210\u4E8B\u9879"]
1149
1467
  }))
1150
1468
  }
1151
1469
  };
1152
1470
  }
1153
1471
 
1472
+ // .dsh-plugin/shared/run-ledger.mjs
1473
+ var finite = (value) => typeof value === "number" && Number.isFinite(value);
1474
+ var routeKey2 = (provider, model) => `${String(provider ?? "")}\0${String(model ?? "")}`;
1475
+ function formatUsd(value) {
1476
+ return typeof value === "number" && Number.isFinite(value) ? `$${value.toFixed(4)}` : "\u2014";
1477
+ }
1478
+ function budgetCheck({ estimateUsd = null, spent = { today: 0, month: 0 }, dailyLimitUsd = 0, monthlyLimitUsd = 0 } = {}) {
1479
+ const limits = [];
1480
+ if (finite(dailyLimitUsd) && dailyLimitUsd > 0) limits.push({ period: "daily", label: "\u4ECA\u65E5", limit: dailyLimitUsd, spent: spent.today ?? 0 });
1481
+ if (finite(monthlyLimitUsd) && monthlyLimitUsd > 0) limits.push({ period: "monthly", label: "\u672C\u6708", limit: monthlyLimitUsd, spent: spent.month ?? 0 });
1482
+ const estimateKnown = finite(estimateUsd);
1483
+ const remaining = limits.length ? Math.max(0, Math.min(...limits.map((item) => item.limit - item.spent))) : null;
1484
+ const exceeded = limits.find((item) => item.spent >= item.limit || estimateKnown && item.spent + estimateUsd > item.limit) ?? null;
1485
+ return {
1486
+ limited: limits.length > 0,
1487
+ estimateKnown,
1488
+ estimateUsd: estimateKnown ? estimateUsd : null,
1489
+ remainingUsd: remaining,
1490
+ exceeded: exceeded ? exceeded.period : null,
1491
+ message: exceeded ? `${exceeded.label}\u9884\u7B97 ${formatUsd(exceeded.limit)}\uFF0C\u5DF2\u7528 ${formatUsd(exceeded.spent)}${estimateKnown ? `\uFF0C\u672C\u6B21\u9884\u4F30 ${formatUsd(estimateUsd)}` : ""}\uFF0C\u5C06\u8D85\u51FA\u4E0A\u9650\u3002` : limits.length && !estimateKnown ? "\u90E8\u5206\u8DEF\u7EBF\u7F3A\u5C11\u5355\u4EF7\uFF0C\u65E0\u6CD5\u9884\u4F30\u672C\u6B21\u8D39\u7528\uFF1B\u4EC5\u5728\u5DF2\u7528\u91D1\u989D\u8FBE\u5230\u4E0A\u9650\u65F6\u963B\u6B62\u3002" : ""
1492
+ };
1493
+ }
1494
+ function applyQualityBiases(routes, biases) {
1495
+ if (!biases || typeof biases !== "object") return routes;
1496
+ return (Array.isArray(routes) ? routes : []).map((route) => {
1497
+ const bias = biases[routeKey2(route.provider, route.model)];
1498
+ return finite(bias) && bias !== 0 ? { ...route, qualityBias: bias } : route;
1499
+ });
1500
+ }
1501
+
1154
1502
  // .dsh-plugin/client/catalog.mjs
1155
- var clean2 = (value) => typeof value === "string" ? value.trim() : "";
1503
+ var clean3 = (value) => typeof value === "string" ? value.trim() : "";
1156
1504
  function routesFromModelCatalog(catalog) {
1157
1505
  const groups = Array.isArray(catalog?.groups) ? catalog.groups : [];
1158
1506
  const routable = new Set(Array.isArray(catalog?.routableProviders) ? catalog.routableProviders : []);
1159
1507
  const routes = [];
1160
1508
  const seen = /* @__PURE__ */ new Set();
1161
1509
  for (const group of groups) {
1162
- const provider = clean2(group?.id);
1510
+ const provider = clean3(group?.id);
1163
1511
  if (!provider || !routable.has(provider)) continue;
1164
1512
  for (const entry of Array.isArray(group.models) ? group.models : []) {
1165
- const model = clean2(entry?.id);
1513
+ const model = clean3(entry?.id);
1166
1514
  if (!model) continue;
1167
1515
  const key = `${provider}\0${model}`;
1168
1516
  if (seen.has(key)) continue;
1169
1517
  seen.add(key);
1170
1518
  const reasoning = entry?.reasoning;
1171
- const efforts = Array.isArray(reasoning?.efforts) ? [...new Set(reasoning.efforts.map((item) => clean2(item?.id ?? item)).filter(Boolean))] : [];
1519
+ const efforts = Array.isArray(reasoning?.efforts) ? [...new Set(reasoning.efforts.map((item) => clean3(item?.id ?? item)).filter(Boolean))] : [];
1172
1520
  routes.push({
1173
1521
  provider,
1174
- providerName: clean2(group.name) || provider,
1522
+ providerName: clean3(group.name) || provider,
1175
1523
  model,
1176
- name: clean2(entry.name) || model,
1524
+ name: clean3(entry.name) || model,
1177
1525
  reasoningKnown: reasoning !== void 0 && reasoning !== null,
1178
1526
  reasoningEfforts: efforts,
1179
- ...clean2(reasoning?.defaultEffort) ? { defaultReasoningEffort: clean2(reasoning.defaultEffort) } : {},
1527
+ ...clean3(reasoning?.defaultEffort) ? { defaultReasoningEffort: clean3(reasoning.defaultEffort) } : {},
1180
1528
  // modelCatalog deliberately omits modalities; unknown means the Host
1181
1529
  // must still validate image capability before a real request.
1182
1530
  inputModalities: []
@@ -1187,10 +1535,10 @@ function routesFromModelCatalog(catalog) {
1187
1535
  return routes;
1188
1536
  }
1189
1537
  function createWorkspacePlan(task, catalog, options = {}) {
1190
- const routes = applyModelProfiles(
1538
+ const routes = applyQualityBiases(applyModelProfiles(
1191
1539
  routesFromModelCatalog(catalog),
1192
1540
  parseModelProfilesJson(options.modelProfilesJson ?? "[]")
1193
- );
1541
+ ), options.qualityBiases ?? null);
1194
1542
  return createPlanFromRoutes(task, routes, options);
1195
1543
  }
1196
1544
 
@@ -1216,7 +1564,11 @@ function profileDraft(profile) {
1216
1564
  cacheRead: profile?.pricing?.cacheRead === void 0 ? "" : String(profile.pricing.cacheRead),
1217
1565
  cacheWrite: profile?.pricing?.cacheWrite === void 0 ? "" : String(profile.pricing.cacheWrite),
1218
1566
  specialties: Array.isArray(profile?.specialties) ? profile.specialties.join(", ") : "",
1219
- cliModel: profile?.cliModel ?? ""
1567
+ cliModel: profile?.cliModel ?? "",
1568
+ execution: profile?.execution === "official" || profile?.execution === "api" ? profile.execution : "auto",
1569
+ billing: BILLING_MODES.includes(profile?.billing) ? profile.billing : DEFAULT_BILLING_MODE,
1570
+ subscription: ["plan-key", "cli-login", "none"].includes(profile?.subscription) ? profile.subscription : "auto",
1571
+ apiRoute: profile?.apiRoute ? profileRouteKey(profile.apiRoute) : ""
1220
1572
  };
1221
1573
  }
1222
1574
  function profileFromDraft(route, draft) {
@@ -1250,6 +1602,23 @@ function profileFromDraft(route, draft) {
1250
1602
  if (!/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,119}$/.test(cliModel)) throw new Error("CLI \u6A21\u578B\u540D\u9700\u7531\u5B57\u6BCD\u6570\u5B57\u5F00\u5934\uFF0C\u4E14\u53EA\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u70B9\u3001\u4E0B\u5212\u7EBF\u3001\u5192\u53F7\u3001\u659C\u6760\u6216\u8FDE\u5B57\u7B26\u3002");
1251
1603
  profile.cliModel = cliModel;
1252
1604
  }
1605
+ const execution = field(draft?.execution) || "auto";
1606
+ if (!["auto", "official", "api"].includes(execution)) throw new Error("\u6267\u884C\u65B9\u5F0F\u53EA\u80FD\u662F\u81EA\u52A8\u3001\u5B98\u65B9\u5DE5\u5177\u6216\u6A21\u578B\u76EE\u5F55 API\u3002");
1607
+ if (execution !== "auto") profile.execution = execution;
1608
+ const billing = field(draft?.billing) || DEFAULT_BILLING_MODE;
1609
+ if (!BILLING_MODES.includes(billing)) throw new Error("\u8BA1\u8D39\u65B9\u5F0F\u53EA\u80FD\u662F\u8BA2\u9605\u4F18\u5148\u3001\u53EA\u7528 API Key \u6216\u53EA\u7528\u8BA2\u9605\u3002");
1610
+ if (billing !== DEFAULT_BILLING_MODE) profile.billing = billing;
1611
+ const subscription = field(draft?.subscription) || "auto";
1612
+ if (!["auto", "plan-key", "cli-login", "none"].includes(subscription)) throw new Error("\u8BA2\u9605\u6765\u6E90\u53EA\u80FD\u662F\u81EA\u52A8\u3001\u7F16\u7A0B\u5957\u9910 Key\u3001CLI \u8D26\u53F7\u767B\u5F55\u6216\u65E0\u8BA2\u9605\u3002");
1613
+ if (subscription !== "auto") profile.subscription = subscription;
1614
+ const apiKey = String(draft?.apiRoute ?? "");
1615
+ if (apiKey) {
1616
+ if (subscription !== "plan-key") throw new Error("\u53EA\u6709\u201C\u7F16\u7A0B\u5957\u9910 Key\u201D\u8DEF\u7EBF\u9700\u8981\u9009\u62E9\u56DE\u9000\u7684 API \u8DEF\u7EBF\u3002");
1617
+ const [apiProvider, apiModel] = apiKey.split("\0");
1618
+ if (!field(apiProvider) || !field(apiModel)) throw new Error("\u56DE\u9000 API \u8DEF\u7EBF\u65E0\u6548\uFF0C\u8BF7\u91CD\u65B0\u9009\u62E9\u3002");
1619
+ if (field(apiProvider) === provider && field(apiModel) === model) throw new Error("\u56DE\u9000 API \u8DEF\u7EBF\u4E0D\u80FD\u662F\u5957\u9910\u8DEF\u7EBF\u672C\u8EAB\u3002");
1620
+ profile.apiRoute = { provider: field(apiProvider), model: field(apiModel) };
1621
+ }
1253
1622
  return profile;
1254
1623
  }
1255
1624
  function updateProfileJson(rawJson, route, draft) {
@@ -1276,7 +1645,7 @@ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
1276
1645
  const [notice, setNotice] = import_react.default.useState(null);
1277
1646
  import_react.default.useEffect(() => settingsScope.subscribe(() => setSnapshot(settingsScope.getSnapshot())), [settingsScope]);
1278
1647
  const route = routes.find((item) => profileRouteKey(item) === selected) ?? routes[0];
1279
- const routeKey2 = route ? profileRouteKey(route) : "";
1648
+ const routeKey3 = route ? profileRouteKey(route) : "";
1280
1649
  const rawJson = snapshot.value?.modelProfilesJson ?? "[]";
1281
1650
  let profiles = [];
1282
1651
  let loadError = "";
@@ -1285,16 +1654,16 @@ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
1285
1654
  } catch (error) {
1286
1655
  loadError = messageOf(error);
1287
1656
  }
1288
- const saved = profiles.find((item) => profileRouteKey(item) === routeKey2);
1289
- const pending = drafts[routeKey2];
1657
+ const saved = profiles.find((item) => profileRouteKey(item) === routeKey3);
1658
+ const pending = drafts[routeKey3];
1290
1659
  const draft = pending?.fields ?? profileDraft(saved);
1291
1660
  const writable = snapshot.status === "ready" && snapshot.writable === true && !saving && !loadError;
1292
1661
  const unmatched = profiles.filter((item) => !routes.some((route2) => profileRouteKey(route2) === profileRouteKey(item))).length;
1293
1662
  const edit = (name, value) => {
1294
1663
  if (!route || !writable) return;
1295
1664
  setDrafts((previous) => {
1296
- const previousEntry = previous[routeKey2] ?? { fields: profileDraft(saved), baseRevision: snapshot.revision };
1297
- return { ...previous, [routeKey2]: { ...previousEntry, fields: { ...previousEntry.fields, [name]: value } } };
1665
+ const previousEntry = previous[routeKey3] ?? { fields: profileDraft(saved), baseRevision: snapshot.revision };
1666
+ return { ...previous, [routeKey3]: { ...previousEntry, fields: { ...previousEntry.fields, [name]: value } } };
1298
1667
  });
1299
1668
  setNotice(null);
1300
1669
  };
@@ -1319,7 +1688,7 @@ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
1319
1688
  if (!accepted) throw new Error("\u8BBE\u7F6E\u672A\u88AB\u4FDD\u5B58\uFF0C\u53EF\u80FD\u88AB\u5176\u4ED6\u9875\u9762\u4FEE\u6539\u3002\u8F93\u5165\u5DF2\u4FDD\u7559\uFF0C\u8BF7\u91CD\u65B0\u52A0\u8F7D\u540E\u6838\u5BF9\u3002");
1320
1689
  setDrafts((previous) => {
1321
1690
  const next = { ...previous };
1322
- delete next[routeKey2];
1691
+ delete next[routeKey3];
1323
1692
  return next;
1324
1693
  });
1325
1694
  setNotice({ tone: "success", text: remove ? "\u5DF2\u5220\u9664\u8BE5\u6A21\u578B\u7684\u81EA\u62A5\u914D\u7F6E\u3002" : "\u8BE5\u6A21\u578B\u914D\u7F6E\u5DF2\u4FDD\u5B58\uFF1B\u91CD\u65B0\u751F\u6210\u5EFA\u8BAE\u5373\u53EF\u4F7F\u7528\u3002" });
@@ -1333,19 +1702,19 @@ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
1333
1702
  const reload = () => {
1334
1703
  setDrafts((previous) => {
1335
1704
  const next = { ...previous };
1336
- delete next[routeKey2];
1705
+ delete next[routeKey3];
1337
1706
  return next;
1338
1707
  });
1339
1708
  setNotice(null);
1340
1709
  };
1341
- return /* @__PURE__ */ import_react.default.createElement("section", { className: "mr-card mr-profile-card", "aria-label": "\u9010\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u914D\u7F6E" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("h2", { className: "mr-card-title" }, "\u9010\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B"), /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-card-copy" }, "\u9009\u62E9\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u51C6\u786E\u8DEF\u7EBF\uFF0C\u586B\u5199\u4F60\u638C\u63E1\u7684\u8D28\u91CF\u8BC4\u5206\u4E0E\u5355\u4EF7\u3002\u914D\u7F6E\u7531\u4F60\u63D0\u4F9B\uFF0C\u63D2\u4EF6\u4E0D\u4F1A\u8BFB\u53D6\u8D26\u53F7\u5BC6\u94A5\u3002"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-card-body" }, loadError && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-error", role: "alert" }, "\u5DF2\u6709\u914D\u7F6E\u65E0\u6CD5\u89E3\u6790\uFF1A", loadError, "\u3002\u8BF7\u5148\u5728\u63D2\u4EF6\u8BBE\u7F6E\u9875\u4FEE\u6B63 JSON\u3002"), snapshot.status !== "ready" && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-caption" }, "\u8BBE\u7F6E\u72B6\u6001\uFF1A", snapshot.status === "loading" ? "\u6B63\u5728\u52A0\u8F7D" : "\u5F53\u524D\u4E0D\u53EF\u7528"), snapshot.status === "ready" && !snapshot.writable && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-error", role: "status" }, "\u5F53\u524D\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\uFF0C\u8BF7\u5728\u53EF\u5199\u7684\u672C\u673A\u73AF\u5883\u914D\u7F6E\u3002"), routes.length === 0 ? /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-empty" }, "\u8BF7\u5148\u5728 DeepSeek Harness \u7684\u201C\u6A21\u578B\u201D\u9875\u6DFB\u52A0\u6A21\u578B\uFF0C\u518D\u8FD4\u56DE\u8FD9\u91CC\u586B\u5199\u4EF7\u683C\u4E0E\u80FD\u529B\u3002") : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-label", htmlFor: "mr-profile-route" }, "\u6A21\u578B\u8DEF\u7EBF"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", id: "mr-profile-route", value: routeKey2, onChange: (event) => {
1710
+ return /* @__PURE__ */ import_react.default.createElement("section", { className: "mr-card mr-profile-card", "aria-label": "\u9010\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u914D\u7F6E" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("h2", { className: "mr-card-title" }, "\u9010\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B"), /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-card-copy" }, "\u9009\u62E9\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u51C6\u786E\u8DEF\u7EBF\uFF0C\u586B\u5199\u4F60\u638C\u63E1\u7684\u8D28\u91CF\u8BC4\u5206\u4E0E\u5355\u4EF7\u3002\u914D\u7F6E\u7531\u4F60\u63D0\u4F9B\uFF0C\u63D2\u4EF6\u4E0D\u4F1A\u8BFB\u53D6\u8D26\u53F7\u5BC6\u94A5\u3002"))), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-card-body" }, loadError && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-error", role: "alert" }, "\u5DF2\u6709\u914D\u7F6E\u65E0\u6CD5\u89E3\u6790\uFF1A", loadError, "\u3002\u8BF7\u5148\u5728\u63D2\u4EF6\u8BBE\u7F6E\u9875\u4FEE\u6B63 JSON\u3002"), snapshot.status !== "ready" && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-caption" }, "\u8BBE\u7F6E\u72B6\u6001\uFF1A", snapshot.status === "loading" ? "\u6B63\u5728\u52A0\u8F7D" : "\u5F53\u524D\u4E0D\u53EF\u7528"), snapshot.status === "ready" && !snapshot.writable && /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-error", role: "status" }, "\u5F53\u524D\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\uFF0C\u8BF7\u5728\u53EF\u5199\u7684\u672C\u673A\u73AF\u5883\u914D\u7F6E\u3002"), routes.length === 0 ? /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-empty" }, "\u8BF7\u5148\u5728 DeepSeek Harness \u7684\u201C\u6A21\u578B\u201D\u9875\u6DFB\u52A0\u6A21\u578B\uFF0C\u518D\u8FD4\u56DE\u8FD9\u91CC\u586B\u5199\u4EF7\u683C\u4E0E\u80FD\u529B\u3002") : /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-label", htmlFor: "mr-profile-route" }, "\u6A21\u578B\u8DEF\u7EBF"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", id: "mr-profile-route", value: routeKey3, onChange: (event) => {
1342
1711
  setSelected(event.target.value);
1343
1712
  setNotice(null);
1344
- } }, routes.map((item) => /* @__PURE__ */ import_react.default.createElement("option", { key: profileRouteKey(item), value: profileRouteKey(item) }, item.provider, "/", item.model))), /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-caption mr-profile-state" }, saved ? `\u5DF2\u914D\u7F6E${saved.pricing ? "\u5355\u4EF7" : "\u80FD\u529B\uFF0C\u4EF7\u683C\u672A\u77E5"}` : "\u672A\u914D\u7F6E\uFF0C\u4EF7\u683C\u4E0E\u8D28\u91CF\u6765\u6E90\u672A\u77E5", pending ? " \xB7 \u5F53\u524D\u6709\u672A\u4FDD\u5B58\u8F93\u5165" : "", unmatched > 0 ? ` \xB7 \u53E6\u6709 ${unmatched} \u6761\u914D\u7F6E\u4E0D\u5728\u5F53\u524D\u6A21\u578B\u76EE\u5F55\u4E2D\uFF0C\u4FDD\u5B58\u65F6\u4F1A\u4FDD\u7559` : ""), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-profile-grid" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8D28\u91CF\u8BC4\u5206\uFF080\u2013100\uFF0C\u81EA\u62A5\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", max: "100", step: "any", value: draft.quality, disabled: !writable, onChange: (event) => edit("quality", event.target.value), placeholder: "\u4F8B\u5982 85\uFF1B\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8F93\u5165\u5355\u4EF7\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.input, disabled: !writable, onChange: (event) => edit("input", event.target.value), placeholder: "\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8F93\u51FA\u5355\u4EF7\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.output, disabled: !writable, onChange: (event) => edit("output", event.target.value), placeholder: "\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u64C5\u957F\u65B9\u5411\uFF08\u82F1\u6587\u6807\u7B7E\uFF0C\u9017\u53F7\u5206\u9694\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "text", value: draft.specialties, disabled: !writable, onChange: (event) => edit("specialties", event.target.value), placeholder: PROFILE_SPECIALTY_HINT })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u5B98\u65B9 CLI \u6A21\u578B\u540D\uFF08\u53EF\u9009\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "text", value: draft.cliModel, disabled: !writable, onChange: (event) => edit("cliModel", event.target.value), placeholder: "\u4EC5\u5728\u5382\u5546 CLI \u652F\u6301\u8BE5\u51C6\u786E\u540D\u79F0\u65F6\u586B\u5199" }))), /* @__PURE__ */ import_react.default.createElement("details", { className: "mr-profile-advanced" }, /* @__PURE__ */ import_react.default.createElement("summary", null, "\u7F13\u5B58\u5355\u4EF7\uFF08\u53EF\u9009\uFF09"), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-profile-grid" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u7F13\u5B58\u8BFB\u53D6\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.cacheRead, disabled: !writable, onChange: (event) => edit("cacheRead", event.target.value), placeholder: "\u7559\u7A7A\u6309\u666E\u901A\u8F93\u5165\u4EF7\u683C\u4F30\u7B97" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u7F13\u5B58\u5199\u5165\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.cacheWrite, disabled: !writable, onChange: (event) => edit("cacheWrite", event.target.value), placeholder: "\u7559\u7A7A\u6309\u666E\u901A\u8F93\u5165\u4EF7\u683C\u4F30\u7B97" })))), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react.default.createElement("button", { className: "mr-button", type: "button", disabled: !writable || !pending, onClick: () => {
1713
+ } }, routes.map((item) => /* @__PURE__ */ import_react.default.createElement("option", { key: profileRouteKey(item), value: profileRouteKey(item) }, item.provider, "/", item.model))), /* @__PURE__ */ import_react.default.createElement("p", { className: "mr-caption mr-profile-state" }, saved ? `\u5DF2\u914D\u7F6E${saved.pricing ? "\u5355\u4EF7" : "\u80FD\u529B\uFF0C\u4EF7\u683C\u672A\u77E5"}` : "\u672A\u914D\u7F6E\uFF0C\u4EF7\u683C\u4E0E\u8D28\u91CF\u6765\u6E90\u672A\u77E5", pending ? " \xB7 \u5F53\u524D\u6709\u672A\u4FDD\u5B58\u8F93\u5165" : "", unmatched > 0 ? ` \xB7 \u53E6\u6709 ${unmatched} \u6761\u914D\u7F6E\u4E0D\u5728\u5F53\u524D\u6A21\u578B\u76EE\u5F55\u4E2D\uFF0C\u4FDD\u5B58\u65F6\u4F1A\u4FDD\u7559` : ""), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-profile-grid" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8D28\u91CF\u8BC4\u5206\uFF080\u2013100\uFF0C\u81EA\u62A5\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", max: "100", step: "any", value: draft.quality, disabled: !writable, onChange: (event) => edit("quality", event.target.value), placeholder: "\u4F8B\u5982 85\uFF1B\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8F93\u5165\u5355\u4EF7\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.input, disabled: !writable, onChange: (event) => edit("input", event.target.value), placeholder: "\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8F93\u51FA\u5355\u4EF7\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.output, disabled: !writable, onChange: (event) => edit("output", event.target.value), placeholder: "\u7559\u7A7A\u8868\u793A\u672A\u77E5" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u64C5\u957F\u65B9\u5411\uFF08\u82F1\u6587\u6807\u7B7E\uFF0C\u9017\u53F7\u5206\u9694\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "text", value: draft.specialties, disabled: !writable, onChange: (event) => edit("specialties", event.target.value), placeholder: PROFILE_SPECIALTY_HINT })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u5B98\u65B9 CLI \u6A21\u578B\u540D\uFF08\u53EF\u9009\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "text", value: draft.cliModel, disabled: !writable, onChange: (event) => edit("cliModel", event.target.value), placeholder: "\u4EC5\u5728\u5382\u5546 CLI \u652F\u6301\u8BE5\u51C6\u786E\u540D\u79F0\u65F6\u586B\u5199" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u6267\u884C\u65B9\u5F0F"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.execution || "auto", disabled: !writable, onChange: (event) => edit("execution", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "auto" }, "\u81EA\u52A8\uFF1A\u5DF2\u5B89\u88C5\u5219\u7528\u5B98\u65B9\u5DE5\u5177\uFF0C\u5931\u8D25\u56DE\u9000 API"), /* @__PURE__ */ import_react.default.createElement("option", { value: "official" }, "\u5B98\u65B9\u5DE5\u5177\uFF1A\u5931\u8D25\u6216\u672A\u5B89\u88C5\u65F6\u56DE\u9000 API"), /* @__PURE__ */ import_react.default.createElement("option", { value: "api" }, "\u4EC5\u6A21\u578B\u76EE\u5F55 API"))), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8BA1\u8D39\u65B9\u5F0F"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.billing, disabled: !writable, onChange: (event) => edit("billing", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "subscription-first" }, "\u8BA2\u9605\u4F18\u5148\uFF1A\u989D\u5EA6\u7528\u5C3D\u6216\u9650\u6D41\u65F6\u5207\u6362 API Key"), /* @__PURE__ */ import_react.default.createElement("option", { value: "api-only" }, "\u53EA\u7528 API Key"), /* @__PURE__ */ import_react.default.createElement("option", { value: "subscription-only" }, "\u53EA\u7528\u8BA2\u9605\uFF1A\u989D\u5EA6\u7528\u5C3D\u65F6\u4E0D\u5207\u6362"))), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u8BA2\u9605\u6765\u6E90"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.subscription, disabled: !writable, onChange: (event) => edit("subscription", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "auto" }, "\u81EA\u52A8\uFF1A\u6709\u5B98\u65B9 CLI \u65F6\u7528 CLI \u8D26\u53F7\u767B\u5F55"), /* @__PURE__ */ import_react.default.createElement("option", { value: "plan-key" }, "\u7F16\u7A0B\u5957\u9910 Key\uFF1A\u8BE5\u8DEF\u7EBF\u672C\u8EAB\u662F\u5957\u9910\u7AEF\u70B9"), /* @__PURE__ */ import_react.default.createElement("option", { value: "cli-login" }, "\u5B98\u65B9 CLI \u8D26\u53F7\u767B\u5F55"), /* @__PURE__ */ import_react.default.createElement("option", { value: "none" }, "\u65E0\u8BA2\u9605\uFF1A\u59CB\u7EC8\u6309 API \u8BA1\u8D39"))), draft.subscription === "plan-key" && /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u989D\u5EA6\u7528\u5C3D\u65F6\u56DE\u9000\u7684 API \u8DEF\u7EBF"), /* @__PURE__ */ import_react.default.createElement("select", { className: "mr-input", value: draft.apiRoute, disabled: !writable, onChange: (event) => edit("apiRoute", event.target.value) }, /* @__PURE__ */ import_react.default.createElement("option", { value: "" }, "\u4E0D\u56DE\u9000\uFF08\u672A\u914D\u7F6E API \u8DEF\u7EBF\uFF09"), routes.filter((item) => profileRouteKey(item) !== routeKey3).map((item) => /* @__PURE__ */ import_react.default.createElement("option", { key: profileRouteKey(item), value: profileRouteKey(item) }, item.provider, "/", item.model))))), /* @__PURE__ */ import_react.default.createElement("details", { className: "mr-profile-advanced" }, /* @__PURE__ */ import_react.default.createElement("summary", null, "\u7F13\u5B58\u5355\u4EF7\uFF08\u53EF\u9009\uFF09"), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-profile-grid" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u7F13\u5B58\u8BFB\u53D6\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.cacheRead, disabled: !writable, onChange: (event) => edit("cacheRead", event.target.value), placeholder: "\u7559\u7A7A\u6309\u666E\u901A\u8F93\u5165\u4EF7\u683C\u4F30\u7B97" })), /* @__PURE__ */ import_react.default.createElement("label", { className: "mr-profile-field" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u7F13\u5B58\u5199\u5165\uFF08USD / \u767E\u4E07 token\uFF09"), /* @__PURE__ */ import_react.default.createElement("input", { className: "mr-input", type: "number", min: "0", step: "any", value: draft.cacheWrite, disabled: !writable, onChange: (event) => edit("cacheWrite", event.target.value), placeholder: "\u7559\u7A7A\u6309\u666E\u901A\u8F93\u5165\u4EF7\u683C\u4F30\u7B97" })))), /* @__PURE__ */ import_react.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react.default.createElement("button", { className: "mr-button", type: "button", disabled: !writable || !pending, onClick: () => {
1345
1714
  void write(false);
1346
1715
  } }, saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u6B64\u6A21\u578B"), /* @__PURE__ */ import_react.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !pending || saving, onClick: reload }, "\u91CD\u65B0\u52A0\u8F7D\u6B64\u8DEF\u7EBF"), saved && /* @__PURE__ */ import_react.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !writable, onClick: () => {
1347
1716
  void write(true);
1348
- } }, "\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"))));
1717
+ } }, "\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"))));
1349
1718
  }
1350
1719
 
1351
1720
  // .dsh-plugin/client/tool-install-state.mjs
@@ -1366,40 +1735,470 @@ function toolInstallAction({ tool, probe, readiness, job, probeStatus }) {
1366
1735
  const currentAndReady = versionOrder === 0 && readiness?.ready === true;
1367
1736
  const repairable = versionOrder === 0 && readiness?.ready === false;
1368
1737
  const newerOrUncertain = probe?.installed && (versionOrder === null || versionOrder > 0);
1369
- 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" : "\u4E0B\u8F7D\u5B89\u88C5";
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";
1370
1739
  return {
1371
1740
  label,
1372
1741
  disabled: probeStatus !== "ready" || running || currentAndReady || newerOrUncertain
1373
1742
  };
1374
1743
  }
1375
1744
 
1745
+ // .dsh-plugin/client/router-insights.jsx
1746
+ var import_react2 = __toESM(require("react"), 1);
1747
+
1748
+ // .dsh-plugin/client/insights-state.mjs
1749
+ var PACKAGE_STATUS = Object.freeze({
1750
+ pending: Object.freeze({ label: "\u5F85\u6267\u884C", tone: "pending" }),
1751
+ succeeded: Object.freeze({ label: "\u5B98\u65B9 CLI \u5B8C\u6210", tone: "ok" }),
1752
+ fallback: Object.freeze({ label: "\u5DF2\u56DE\u9000 API \u5B8C\u6210", tone: "warn" }),
1753
+ failed: Object.freeze({ label: "\u5931\u8D25", tone: "error" }),
1754
+ blocked: Object.freeze({ label: "\u4F9D\u8D56\u672A\u5B8C\u6210", tone: "blocked" }),
1755
+ cancelled: Object.freeze({ label: "\u5DF2\u53D6\u6D88", tone: "blocked" }),
1756
+ paused: Object.freeze({ label: "\u7B49\u5F85\u786E\u8BA4", tone: "warn" }),
1757
+ waiting: Object.freeze({ label: "\u7B49\u5F85\u4E0A\u6E38\u786E\u8BA4", tone: "blocked" })
1758
+ });
1759
+ function packageStatus(item) {
1760
+ if (item?.status === "succeeded" && item.channel === "harness-llm") return { label: "API \u5B8C\u6210", tone: "ok" };
1761
+ return PACKAGE_STATUS[item?.status] ?? PACKAGE_STATUS.pending;
1762
+ }
1763
+ function dagLayers(packages) {
1764
+ const list = Array.isArray(packages) ? packages : [];
1765
+ const byId = new Map(list.map((item) => [item.id, item]));
1766
+ const depth = /* @__PURE__ */ new Map();
1767
+ const visit = (id2, trail = /* @__PURE__ */ new Set()) => {
1768
+ if (depth.has(id2)) return depth.get(id2);
1769
+ if (trail.has(id2) || !byId.has(id2)) return -1;
1770
+ trail.add(id2);
1771
+ const deps = (byId.get(id2).dependsOn ?? []).map((dep) => visit(dep, trail));
1772
+ const value = deps.length ? Math.max(...deps) + 1 : 0;
1773
+ depth.set(id2, Math.max(0, value));
1774
+ return depth.get(id2);
1775
+ };
1776
+ list.forEach((item) => visit(item.id));
1777
+ const layers = [];
1778
+ for (const item of list) {
1779
+ const level = depth.get(item.id) ?? 0;
1780
+ (layers[level] ?? (layers[level] = [])).push(item);
1781
+ }
1782
+ return layers.filter(Boolean);
1783
+ }
1784
+ 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" });
1786
+ function healthSummary(tools) {
1787
+ const list = Array.isArray(tools) ? tools : [];
1788
+ const installed = list.filter((item) => item.installed);
1789
+ return {
1790
+ total: list.length,
1791
+ installed: installed.length,
1792
+ ready: installed.filter((item) => item.login?.state === "logged-in").length,
1793
+ loggedOut: installed.filter((item) => item.login?.state === "logged-out").length,
1794
+ unknown: installed.filter((item) => item.login?.state === "unknown").length,
1795
+ older: installed.filter((item) => item.versionStatus === "older").length
1796
+ };
1797
+ }
1798
+ var money = formatUsd;
1799
+ function budgetMeter(spent, limit) {
1800
+ if (!(limit > 0)) return { limited: false, share: 0, text: `${money(spent)}\uFF08\u672A\u8BBE\u4E0A\u9650\uFF09` };
1801
+ const share = Math.min(1, Math.max(0, spent / limit));
1802
+ return { limited: true, share, over: spent >= limit, text: `${money(spent)} / ${money(limit)}` };
1803
+ }
1804
+ function planBudget(ledger, estimateUsd) {
1805
+ if (!ledger?.budget) return null;
1806
+ return budgetCheck({
1807
+ estimateUsd,
1808
+ spent: ledger.spent ?? { today: 0, month: 0 },
1809
+ dailyLimitUsd: ledger.budget.dailyLimitUsd,
1810
+ monthlyLimitUsd: ledger.budget.monthlyLimitUsd
1811
+ });
1812
+ }
1813
+ function unwrapRemote(response, fallback) {
1814
+ if (!response?.ok) throw new Error(String(response?.error?.message ?? "") || fallback);
1815
+ const inner = response.value;
1816
+ if (inner && typeof inner === "object" && "ok" in inner && !inner.ok) {
1817
+ const error = inner.error;
1818
+ throw new Error(String((error && typeof error === "object" ? error.message : error) ?? "") || fallback);
1819
+ }
1820
+ return inner && typeof inner === "object" && "ok" in inner ? inner.value : inner;
1821
+ }
1822
+ var RUN_KIND_LABEL = Object.freeze({ assign: "\u8DEF\u7531\u6267\u884C", team: "\u56E2\u961F\u6267\u884C", tool: "\u5355\u5DE5\u5177\u8C03\u7528" });
1823
+ var RUN_STATUS_LABEL = Object.freeze({
1824
+ completed: "\u5B8C\u6210",
1825
+ partial: "\u90E8\u5206\u5B8C\u6210",
1826
+ failed: "\u5931\u8D25",
1827
+ "cli-completed": "\u5B8C\u6210",
1828
+ incomplete: "\u672A\u5B8C\u6210",
1829
+ paused: "\u7B49\u5F85\u786E\u8BA4",
1830
+ "integration-pending": "\u5F85\u6574\u5408",
1831
+ blocked: "\u88AB\u963B\u6B62",
1832
+ cancelled: "\u5DF2\u53D6\u6D88",
1833
+ pending: "\u5F85\u6267\u884C"
1834
+ });
1835
+ function packageCost(item) {
1836
+ if (item?.billing === "subscription") {
1837
+ return {
1838
+ budget: "\u4E0D\u8BA1\u5165\u9884\u7B97",
1839
+ reference: item.referenceCostUsd !== null && item.referenceCostUsd !== void 0 ? `\u8BA2\u9605\u53C2\u8003\u8D39\u7528 ${money(item.referenceCostUsd)}\uFF08\u6309 API \u4EF7\u6298\u7B97\uFF09` : "\u8BA2\u9605\u767B\u5F55\uFF0C\u672A\u56DE\u62A5\u53EF\u6298\u7B97\u7684\u7528\u91CF"
1840
+ };
1841
+ }
1842
+ if (item?.costUsd !== null && item?.costUsd !== void 0) {
1843
+ return { budget: `${money(item.costUsd)}${item.costSource === "cli-reported" ? "\uFF08CLI \u81EA\u62A5\uFF09" : ""}`, reference: null };
1844
+ }
1845
+ return { budget: item?.ran ? "\u8D39\u7528\u672A\u77E5" : "\u2014", reference: null };
1846
+ }
1847
+ function runTotals(run) {
1848
+ const items = [...run?.packages ?? [], ...run?.reviews ?? []];
1849
+ let budgetUsd = 0;
1850
+ let referenceUsd = 0;
1851
+ let subscription = false;
1852
+ for (const item of items) {
1853
+ if (item.billing === "subscription") {
1854
+ subscription = true;
1855
+ if (typeof item.referenceCostUsd === "number") referenceUsd += item.referenceCostUsd;
1856
+ } else if (typeof item.costUsd === "number") budgetUsd += item.costUsd;
1857
+ }
1858
+ return { budgetUsd, referenceUsd, subscription };
1859
+ }
1860
+ function rerunSupport(run) {
1861
+ if (run?.kind === "tool") {
1862
+ const editable = run.executionMode === "workspace-write";
1863
+ return {
1864
+ supported: true,
1865
+ writes: editable,
1866
+ reassign: false,
1867
+ reason: "",
1868
+ confirm: editable ? "\u91CD\u8DD1\u4F1A\u5728\u65B0\u7684\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\u4E2D\u518D\u6B21\u6267\u884C\u8FD9\u6B21\u53EF\u7F16\u8F91\u8C03\u7528\uFF0C\u6210\u529F\u540E\u628A\u6539\u52A8\u6574\u5408\u56DE\u5DE5\u4F5C\u533A\uFF08\u5DE5\u4F5C\u533A\u987B\u4E3A\u5E72\u51C0\u7684 Git \u4ED3\u5E93\uFF09\u3002" : ""
1869
+ };
1870
+ }
1871
+ if (run?.kind === "team" && run.executionMode === "workspace-write") {
1872
+ if (!["incomplete", "cancelled"].includes(run.status)) {
1873
+ return { supported: false, writes: true, reassign: false, reason: run.status === "integration-pending" ? "\u6539\u52A8\u5C1A\u5F85\u4EBA\u5DE5\u6574\u5408\uFF08\u72EC\u7ACB\u5DE5\u4F5C\u533A\u5DF2\u4FDD\u7559\uFF09\uFF0C\u4E0D\u80FD\u5355\u6B65\u91CD\u8DD1\uFF1B\u8BF7\u5148\u6838\u5BF9\u5E76\u6574\u5408\uFF0C\u518D\u5728\u4F1A\u8BDD\u4E2D\u91CD\u65B0\u6267\u884C\u56E2\u961F\u4EFB\u52A1\u3002" : "\u6539\u52A8\u5DF2\u6574\u5408\u5230\u5DE5\u4F5C\u533A\uFF0C\u5355\u6B65\u91CD\u8DD1\u4F1A\u91CD\u590D\u5957\u7528\u6539\u52A8\uFF1B\u5982\u9700\u91CD\u505A\u8BF7\u5728\u4F1A\u8BDD\u4E2D\u91CD\u65B0\u8C03\u7528 model_router_team_execute\u3002" };
1874
+ }
1875
+ if (!run.isolatedWorkspace || !run.baseCommit) {
1876
+ return { supported: false, writes: true, reassign: false, reason: "\u65E7\u7248\u672C\u8BB0\u5F55\u7F3A\u5C11\u72EC\u7ACB\u5DE5\u4F5C\u533A\u6216 Git \u57FA\u7EBF\uFF0C\u65E0\u6CD5\u5B89\u5168\u7EED\u8DD1\uFF1B\u8BF7\u5728\u4F1A\u8BDD\u4E2D\u91CD\u65B0\u8C03\u7528 model_router_team_execute\u3002" };
1877
+ }
1878
+ return {
1879
+ supported: true,
1880
+ writes: true,
1881
+ reassign: true,
1882
+ reason: "",
1883
+ confirm: "\u7EED\u8DD1\u4F1A\u5728\u65B0\u7684\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\u4E2D\u5148\u5957\u7528\u4E4B\u524D\u7684\u6539\u52A8\uFF0C\u518D\u91CD\u8DD1\u8BE5\u6B65\u9AA4\u53CA\u5176\u4E0B\u6E38\uFF1B\u6210\u529F\u540E\u628A\u5408\u5E76\u8865\u4E01\u6574\u5408\u56DE\u5DE5\u4F5C\u533A\uFF08\u5DE5\u4F5C\u533A\u987B\u5E72\u51C0\u4E14\u4ECD\u5728\u539F\u57FA\u7EBF\u63D0\u4EA4\uFF09\u3002"
1884
+ };
1885
+ }
1886
+ return { supported: true, writes: false, reassign: true, reason: "", confirm: "" };
1887
+ }
1888
+ var pad2 = (value) => String(value).padStart(2, "0");
1889
+ function formatResetTime(at) {
1890
+ if (!Number.isFinite(at)) return "";
1891
+ const date = new Date(at);
1892
+ return `${date.getMonth() + 1}-${date.getDate()} ${pad2(date.getHours())}:${pad2(date.getMinutes())}`;
1893
+ }
1894
+ var BILLING_CHANNEL_LABEL = Object.freeze({ subscription: "\u8BA2\u9605", api: "API Key" });
1895
+ function billingRows(billing) {
1896
+ return (billing?.providers ?? []).map((row) => {
1897
+ const sub = row.subscription ?? {};
1898
+ const subscription = sub.kind === "plan-key" ? `\u7F16\u7A0B\u5957\u9910 Key${sub.planRoute ? `\uFF08${sub.planRoute.provider}/${sub.planRoute.model}\uFF09` : ""}` : sub.kind === "cli-login" ? `\u5B98\u65B9 CLI \u8D26\u53F7\u767B\u5F55 \xB7 ${sub.toolId}` : "\u65E0\u8BA2\u9605";
1899
+ const state = sub.state === "exhausted" ? `${sub.exhaustedKind === "rate-limit" ? "\u9650\u6D41\u4E2D" : "\u989D\u5EA6\u5DF2\u7528\u5C3D"}\uFF0C\u9884\u8BA1 ${formatResetTime(sub.exhaustedUntil)} \u6062\u590D${sub.resetReported ? "" : "\uFF08\u5382\u5546\u672A\u7ED9\u51FA\u65F6\u95F4\uFF0C\u6309\u51B7\u5374\u65F6\u95F4\u4F30\u7B97\uFF09"}` : sub.stateLabel ?? "\u2014";
1900
+ const api = row.mode === "subscription-only" ? "\u4E0D\u56DE\u9000\uFF08\u53EA\u7528\u8BA2\u9605\uFF09" : row.api?.available ? `\u53EF\u7528${row.api.route ? `\uFF1A${row.api.route.provider}/${row.api.route.model}` : ""}${row.api.cliKeyEnv ? " \xB7 CLI \u73AF\u5883\u53D8\u91CF\u4E5F\u6709 Key" : ""}` : "\u672A\u914D\u7F6E\u56DE\u9000\u7684 API \u8DEF\u7EBF";
1901
+ return {
1902
+ key: `${row.provider}\0${sub.key ?? "none"}\0${row.mode}`,
1903
+ provider: row.provider,
1904
+ models: (row.models ?? []).join("\u3001"),
1905
+ mode: row.modeLabel ?? row.mode,
1906
+ subscription,
1907
+ state,
1908
+ exhausted: sub.state === "exhausted",
1909
+ api,
1910
+ apiAvailable: row.api?.available === true
1911
+ };
1912
+ });
1913
+ }
1914
+ function billingSwitchText(item) {
1915
+ const note = item?.billingSwitch;
1916
+ if (!note?.reason) return null;
1917
+ return note.reason;
1918
+ }
1919
+ function launchRequest({ task, mode, directRoute, budgetUsd, preset, workspace } = {}) {
1920
+ const budget = Number(budgetUsd);
1921
+ return {
1922
+ task: typeof task === "string" ? task : "",
1923
+ ...mode === "direct" && directRoute ? { provider: directRoute.provider, model: directRoute.model } : { planMode: mode === "team" ? "team" : "single", preset },
1924
+ ...Number.isFinite(budget) && budget >= 0 ? { budgetUsd: budget } : {},
1925
+ ...typeof workspace === "string" && workspace.trim() ? { workspace: workspace.trim() } : {}
1926
+ };
1927
+ }
1928
+ function rerunConfirmations({ run, item, override = null, choice = null, ledger = null, health = null, toolFor = () => null, headlessIds = /* @__PURE__ */ new Set() } = {}) {
1929
+ const reasons = [];
1930
+ const support = rerunSupport(run);
1931
+ if (support.writes) reasons.push({ code: "workspace-write", text: support.confirm });
1932
+ if (choice === "api") reasons.push({ code: "subscription-api", text: "\u6539\u7528 API Key \u91CD\u8BD5\uFF1A\u4F1A\u6309 API \u8BA1\u8D39\u5E76\u8BA1\u5165\u9884\u7B97\u3002" });
1933
+ const tool = toolFor(override?.provider ?? item?.provider);
1934
+ const entry = (health?.tools ?? []).find((candidate) => candidate.id === tool?.id);
1935
+ if (choice !== "api" && choice !== "cancel" && run?.kind !== "team" && run?.kind !== "tool" && ledger?.settings?.confirmUnsandboxedCli !== false && tool && headlessIds.has(tool.id) && entry?.installed && entry.login?.state !== "logged-out") {
1936
+ reasons.push({ code: "unsandboxed", text: `\u4F1A\u76F4\u63A5\u542F\u52A8 ${tool.label} \u7684\u65E0\u754C\u9762 CLI\uFF0C\u4E0D\u7ECF\u8FC7 Harness \u8FDB\u7A0B\u6C99\u7BB1\uFF0C\u53EA\u8BFB\u4EC5\u7531 CLI \u53C2\u6570\u4FDD\u8BC1\u3002` });
1937
+ }
1938
+ const estimate = override ? null : item?.estimatedCost;
1939
+ const check = ledger?.budget ? budgetCheck({
1940
+ estimateUsd: typeof estimate === "number" ? estimate : null,
1941
+ spent: ledger.spent ?? {},
1942
+ dailyLimitUsd: ledger.budget.dailyLimitUsd,
1943
+ monthlyLimitUsd: ledger.budget.monthlyLimitUsd
1944
+ }) : null;
1945
+ if (check?.exceeded) reasons.push({ code: "over-budget", text: `\u8D85\u51FA\u9884\u7B97\uFF1A${check.message}` });
1946
+ return reasons;
1947
+ }
1948
+
1949
+ // .dsh-plugin/client/router-insights.jsx
1950
+ var text = (value) => typeof value === "string" ? value.trim() : "";
1951
+ var BAND = { simple: "\u7B80\u5355", balanced: "\u4E2D\u7B49", complex: "\u56F0\u96BE" };
1952
+ var SUBSCRIPTION_FAILURE_OPTIONS = [["ask", "\u6682\u505C\u5E76\u8BE2\u95EE"], ["api", "\u81EA\u52A8\u6539\u7528 API"], ["fail", "\u76F4\u63A5\u5931\u8D25"]];
1953
+ var SUBSCRIPTION_CHOICE_BUTTONS = [["api", "\u6539\u7528 API \u91CD\u8BD5", false], ["subscription", "\u91CD\u8BD5\u8BA2\u9605", true], ["cancel", "\u53D6\u6D88", true]];
1954
+ function OnboardingBanner({ health, onDone, onRefresh, refreshing, error }) {
1955
+ 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
+ }
1959
+ function ToolLoginLine({ entry }) {
1960
+ const [open, setOpen] = import_react2.default.useState(false);
1961
+ const [copied, setCopied] = import_react2.default.useState(false);
1962
+ if (!entry?.installed) return null;
1963
+ const state = entry.login?.state ?? "unknown";
1964
+ const copy = async () => {
1965
+ try {
1966
+ await navigator.clipboard.writeText(entry.login.command);
1967
+ setCopied(true);
1968
+ } catch {
1969
+ setCopied(false);
1970
+ }
1971
+ };
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: () => {
1973
+ void copy();
1974
+ } }, 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
+ }
1976
+ function Meter({ label, meter }) {
1977
+ return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-meter" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-meter-top" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, label), /* @__PURE__ */ import_react2.default.createElement("span", { className: meter.over ? "mr-meter-over" : "" }, meter.text)), meter.limited && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-meter-track", role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(meter.share * 100) }, /* @__PURE__ */ import_react2.default.createElement("div", { className: `mr-meter-fill ${meter.over ? "over" : meter.share > 0.8 ? "near" : ""}`, style: { width: `${Math.round(meter.share * 100)}%` } })));
1978
+ }
1979
+ function useSettingsWriter(settingsScope) {
1980
+ const [snapshot, setSnapshot] = import_react2.default.useState(() => settingsScope.getSnapshot());
1981
+ const [notice, setNotice] = import_react2.default.useState("");
1982
+ import_react2.default.useEffect(() => settingsScope.subscribe(() => setSnapshot(settingsScope.getSnapshot())), [settingsScope]);
1983
+ const writable = snapshot.status === "ready" && snapshot.writable === true;
1984
+ const write = async (key, value) => {
1985
+ if (!writable) return false;
1986
+ setNotice("");
1987
+ try {
1988
+ const accepted = await settingsScope.mutate([{ op: "set", path: [key], value }], snapshot.revision);
1989
+ if (!accepted) setNotice("\u8BBE\u7F6E\u672A\u4FDD\u5B58\uFF0C\u53EF\u80FD\u5DF2\u5728\u5176\u4ED6\u9875\u9762\u4FEE\u6539\uFF0C\u8BF7\u91CD\u8BD5\u3002");
1990
+ return accepted;
1991
+ } catch (error) {
1992
+ setNotice(text(error?.message) || "\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
1993
+ return false;
1994
+ }
1995
+ };
1996
+ return { value: snapshot.value ?? {}, writable, write, notice };
1997
+ }
1998
+ function CostControlCard({ ledger, settingsScope, onChanged, error }) {
1999
+ const settings = useSettingsWriter(settingsScope);
2000
+ const [dailyDraft, setDailyDraft] = import_react2.default.useState("");
2001
+ const [monthlyDraft, setMonthlyDraft] = import_react2.default.useState("");
2002
+ const value = settings.value;
2003
+ const preset = value.routingPreset ?? "balanced";
2004
+ const daily = Number(value.dailyBudgetUsd ?? 0);
2005
+ const monthly = Number(value.monthlyBudgetUsd ?? 0);
2006
+ const spent = ledger?.spent ?? { today: 0, month: 0, unknownToday: 0, unknownMonth: 0 };
2007
+ const set = async (key, next) => {
2008
+ if (await settings.write(key, next)) onChanged?.();
2009
+ };
2010
+ const saveLimit = async (key, draft, reset) => {
2011
+ const parsed = Number(draft);
2012
+ if (draft === "" || !Number.isFinite(parsed) || parsed < 0) return;
2013
+ if (await settings.write(key, parsed)) {
2014
+ reset("");
2015
+ onChanged?.();
2016
+ }
2017
+ };
2018
+ return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-cost", "aria-label": "\u6210\u672C\u63A7\u5236" }, /* @__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" }, "\u6210\u672C\u63A7\u5236\u4E0E\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u9884\u7B97\u53EA\u8BA1\u7B97\u8D70 API Key \u6216\u6A21\u578B\u76EE\u5F55 API \u7684\u82B1\u8D39\uFF08CLI \u81EA\u62A5\u91D1\u989D\u6216 token \u7528\u91CF \xD7 \u4F60\u914D\u7F6E\u7684\u5355\u4EF7\uFF09\u3002\u5B98\u65B9 CLI \u7528\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\u3001\u672A\u6CE8\u5165 API Key \u65F6\uFF0C\u53EA\u663E\u793A\u6309 API \u4EF7\u6298\u7B97\u7684\u201C\u8BA2\u9605\u53C2\u8003\u8D39\u7528\u201D\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\u3002\u7F3A\u5C11\u5355\u4EF7\u7684\u8C03\u7528\u8BA1\u4E3A\u201C\u8D39\u7528\u672A\u77E5\u201D\u3002\u8FD9\u662F\u672C\u673A\u4F30\u7B97\uFF0C\u4E0D\u662F\u5382\u5546\u8D26\u5355\u3002"))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, error), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-meters" }, /* @__PURE__ */ import_react2.default.createElement(Meter, { label: "\u4ECA\u65E5\u5DF2\u7528\uFF08\u8BA1\u5165\u9884\u7B97\uFF09", meter: budgetMeter(spent.today, daily) }), /* @__PURE__ */ import_react2.default.createElement(Meter, { label: "\u672C\u6708\u5DF2\u7528\uFF08\u8BA1\u5165\u9884\u7B97\uFF09", meter: budgetMeter(spent.month, monthly) })), (spent.subscriptionRunsMonth ?? 0) > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8BA2\u9605\u53C2\u8003\u8D39\u7528\uFF08\u6309 API \u4EF7\u6298\u7B97\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\uFF09\uFF1A\u4ECA\u65E5 ", money(spent.subscriptionToday ?? 0), " \xB7 \u672C\u6708 ", money(spent.subscriptionMonth ?? 0), "\uFF0C\u672C\u6708\u5171 ", spent.subscriptionRunsMonth, " \u6B21\u8BA2\u9605\u767B\u5F55\u8C03\u7528\u3002"), (spent.unknownToday > 0 || spent.unknownMonth > 0) && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u672C\u6708\u6709 ", spent.unknownMonth, " \u6B21\u8C03\u7528\u7F3A\u5C11\u5355\u4EF7\u6216\u7528\u91CF\uFF0C\u672A\u8BA1\u5165\u91D1\u989D\u3002\u8BF7\u5728\u201C\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u201D\u4E2D\u8865\u9F50\u5355\u4EF7\u3002"), ledger?.budget?.exceeded && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, ledger.budget.message, " ", ledger.budget.action === "pause" ? "\u65B0\u7684\u6267\u884C\u4F1A\u5148\u6682\u505C\u5E76\u8BF7\u6C42\u786E\u8BA4\u3002" : "\u65B0\u7684\u6267\u884C\u4F1A\u5C1D\u8BD5\u81EA\u52A8\u964D\u7EA7\u4E3A\u201C\u7701\u94B1\u4F18\u5148\u201D\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, "\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u8DEF\u7531\u65B9\u6848" }, Object.values(ROUTING_PRESETS).map((item) => /* @__PURE__ */ import_react2.default.createElement("button", { key: item.id, type: "button", title: item.description, "aria-pressed": preset === item.id, disabled: !settings.writable, onClick: () => {
2019
+ void set("routingPreset", item.id);
2020
+ } }, item.label))), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, ROUTING_PRESETS[preset]?.description)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-daily-budget" }, "\u6BCF\u65E5\u4E0A\u9650\uFF08USD\uFF0C0 \u4E3A\u4E0D\u9650\uFF09"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement("input", { className: "mr-input mr-budget", id: "mr-daily-budget", type: "number", min: "0", step: "0.5", placeholder: String(daily), value: dailyDraft, onChange: (event) => setDailyDraft(event.target.value) }), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !settings.writable || dailyDraft === "", onClick: () => {
2021
+ void saveLimit("dailyBudgetUsd", dailyDraft, setDailyDraft);
2022
+ } }, "\u4FDD\u5B58"))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-monthly-budget" }, "\u6BCF\u6708\u4E0A\u9650\uFF08USD\uFF0C0 \u4E3A\u4E0D\u9650\uFF09"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-inline" }, /* @__PURE__ */ import_react2.default.createElement("input", { className: "mr-input mr-budget", id: "mr-monthly-budget", type: "number", min: "0", step: "1", placeholder: String(monthly), value: monthlyDraft, onChange: (event) => setMonthlyDraft(event.target.value) }), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !settings.writable || monthlyDraft === "", onClick: () => {
2023
+ void saveLimit("monthlyBudgetUsd", monthlyDraft, setMonthlyDraft);
2024
+ } }, "\u4FDD\u5B58"))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, "\u8D85\u51FA\u9884\u7B97\u65F6"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u8D85\u51FA\u9884\u7B97\u65F6" }, /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", "aria-pressed": (value.overBudgetAction ?? "downgrade") === "downgrade", disabled: !settings.writable, onClick: () => {
2025
+ void set("overBudgetAction", "downgrade");
2026
+ } }, "\u81EA\u52A8\u964D\u7EA7"), /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", "aria-pressed": value.overBudgetAction === "pause", disabled: !settings.writable, onClick: () => {
2027
+ void set("overBudgetAction", "pause");
2028
+ } }, "\u6682\u505C\u5E76\u8BE2\u95EE"))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, "\u8BA2\u9605\u8C03\u7528\u5931\u8D25\uFF08\u975E\u989D\u5EA6\u7528\u5C3D\uFF09\u65F6"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u8BA2\u9605\u8C03\u7528\u5931\u8D25\u65F6" }, SUBSCRIPTION_FAILURE_OPTIONS.map(([id2, label]) => /* @__PURE__ */ import_react2.default.createElement("button", { key: id2, type: "button", "aria-pressed": (value.onSubscriptionFailure ?? "ask") === id2, disabled: !settings.writable, onClick: () => {
2029
+ void set("onSubscriptionFailure", id2);
2030
+ } }, label))), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u8D85\u65F6\u3001\u5D29\u6E83\u3001\u89E3\u6790\u5931\u8D25\u3001\u975E\u96F6\u9000\u51FA\u3001\u767B\u5F55\u9519\u8BEF\u7B49\u3002\u989D\u5EA6\u7528\u5C3D\u6216\u9650\u6D41\u4ECD\u4F1A\u81EA\u52A8\u5207\u6362 API Key\u3002"))), /* @__PURE__ */ import_react2.default.createElement("h3", { className: "mr-section-title" }, "\u8D28\u91CF\u56DE\u8DEF"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, "\u5F3A\u6A21\u578B\u62BD\u67E5"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u5F3A\u6A21\u578B\u62BD\u67E5" }, [["off", "\u5173\u95ED"], ["sample", "\u6309\u6BD4\u4F8B\u62BD\u67E5"], ["always", "\u6BCF\u6B21\u5BA1\u9605"]].map(([id2, label]) => /* @__PURE__ */ import_react2.default.createElement("button", { key: id2, type: "button", "aria-pressed": (value.reviewMode ?? "off") === id2, disabled: !settings.writable, onClick: () => {
2031
+ void set("reviewMode", id2);
2032
+ } }, label))), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u62BD\u67E5\u7531\u76EE\u5F55\u4E2D\u8D28\u91CF\u6700\u9AD8\u7684\u5DF2\u914D\u7F6E\u6A21\u578B\u5B8C\u6210\uFF0C\u53EA\u5BA1\u9605\u66F4\u4FBF\u5B9C\u6A21\u578B\u7684\u7ED3\u679C\uFF1B\u5BA1\u9605\u672C\u8EAB\u4E5F\u4F1A\u8BA1\u8D39\u3002\u62BD\u67E5\u6BD4\u4F8B ", Math.round(Number(value.reviewSampleRate ?? 0.2) * 100), "%\uFF08\u53EF\u5728\u63D2\u4EF6\u8BBE\u7F6E\u4E2D\u8C03\u6574\uFF09\u3002")), /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-check" }, /* @__PURE__ */ import_react2.default.createElement("input", { type: "checkbox", checked: value.allowManualReassign !== false, disabled: !settings.writable, onChange: (event) => {
2033
+ void set("allowManualReassign", event.target.checked);
2034
+ } }), "\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) => {
2035
+ void set("confirmUnsandboxedCli", event.target.checked);
2036
+ } }), "\u76F4\u63A5\u542F\u52A8\u65E0\u6C99\u7BB1 CLI \u524D\u5148\u786E\u8BA4")), settings.notice && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, settings.notice)));
2037
+ }
2038
+ function DagView({ packages, renderNode, label = "\u5B50\u4EFB\u52A1\u4F9D\u8D56\u56FE" }) {
2039
+ const layers = dagLayers(packages);
2040
+ if (layers.length === 0) return null;
2041
+ const names = new Map((packages ?? []).map((item) => [item.id, item.name]));
2042
+ return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-dag", role: "list", "aria-label": label }, layers.map((layer, index) => /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-dag-column", key: index }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-dag-step" }, "\u7B2C ", index + 1, " \u6B65"), layer.map((item) => {
2043
+ const status = packageStatus(item);
2044
+ return /* @__PURE__ */ import_react2.default.createElement("article", { className: `mr-dag-node ${status.tone}`, role: "listitem", key: item.id }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-dag-node-top" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-package-name" }, item.name), /* @__PURE__ */ import_react2.default.createElement("span", { className: `mr-pill mr-status-${status.tone}` }, status.label)), (item.dependsOn ?? []).length > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u4F9D\u8D56\uFF1A", item.dependsOn.map((id2) => names.get(id2) ?? id2).join("\u3001")), renderNode?.(item));
2045
+ }))));
2046
+ }
2047
+ function ChannelText({ item }) {
2048
+ if (!item.channel) return /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-pill" }, "\u5F85\u6267\u884C");
2049
+ 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");
2050
+ }
2051
+ function RunNode({ run, item, routes, allowReassign, busy, onRate, onRerun }) {
2052
+ if (item.status === "paused") return /* @__PURE__ */ import_react2.default.createElement(PausedNode, { run, item, busy, onRerun });
2053
+ const [target, setTarget] = import_react2.default.useState("");
2054
+ const cost = packageCost(item);
2055
+ const rerun = rerunSupport(run);
2056
+ const canRerun = rerun.supported && !item.ok && !busy;
2057
+ const others = routes.filter((route) => `${route.provider}/${route.model}` !== `${item.provider}/${item.model}`);
2058
+ 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(run.id, item.id, item.rating === 1 ? "clear" : "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(run.id, item.id, item.rating === -1 ? "clear" : "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: () => {
2059
+ const [provider, model] = target.split("\0");
2060
+ onRerun(run.id, item.id, { provider, model });
2061
+ } }, "\u6539\u6D3E\u5E76\u91CD\u8DD1"))));
2062
+ }
2063
+ function PausedNode({ run, item, busy, onRerun }) {
2064
+ const pause = item.pause ?? {};
2065
+ 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), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-pill mr-pill-warn" }, "\u7B49\u5F85\u786E\u8BA4"), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, "\u8BA2\u9605\u8C03\u7528\u5931\u8D25\uFF0C\u672A\u81EA\u52A8\u6539\u7528 API Key")), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-warn-text" }, pause.reason ?? item.error), pause.detail && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy mr-fallback-error" }, "\u771F\u5B9E\u9519\u8BEF\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, pause.detail)), pause.loginRequired && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u770B\u8D77\u6765\u662F\u767B\u5F55\u95EE\u9898\uFF1A\u8BF7\u5148\u5728\u7EC8\u7AEF\u91CD\u65B0\u767B\u5F55\u8BE5 CLI\uFF0C\u518D\u70B9\u201C\u91CD\u8BD5\u8BA2\u9605\u201D\u3002"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-node-actions" }, SUBSCRIPTION_CHOICE_BUTTONS.map(([choice, label, secondary]) => /* @__PURE__ */ import_react2.default.createElement(
2066
+ "button",
2067
+ {
2068
+ key: choice,
2069
+ className: `mr-button mr-mini${secondary ? " mr-button-secondary" : ""}`,
2070
+ type: "button",
2071
+ disabled: busy,
2072
+ onClick: () => onRerun(run.id, item.id, null, choice)
2073
+ },
2074
+ label
2075
+ ))));
2076
+ }
2077
+ function RunHistoryCard({ ledger, routes, onRefresh, onRate, onRerun, busy, error }) {
2078
+ const runs = ledger?.runs ?? [];
2079
+ const [openId, setOpenId] = import_react2.default.useState(null);
2080
+ const current = runs.find((run) => run.id === openId) ?? runs[0];
2081
+ return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u6267\u884C\u8BB0\u5F55" }, /* @__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" }, "\u6267\u884C\u8BB0\u5F55\u4E0E\u5B50\u4EFB\u52A1"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u6765\u81EA\u4F1A\u8BDD\u4E2D\u7684 model_router_execute\u3001model_router_team_execute \u548C model_router_tool_run\u3002\u6BCF\u4E2A\u5DE5\u4F5C\u5305\u663E\u793A\u5206\u914D\u7684\u6A21\u578B\u3001\u539F\u56E0\u3001\u6E20\u9053\u3001\u8D39\u7528\uFF1B\u56DE\u9000\u65F6\u663E\u793A CLI \u539F\u59CB\u9519\u8BEF\u3002\u5931\u8D25\u7684\u6B65\u9AA4\u53EF\u5355\u72EC\u91CD\u8DD1\uFF0C\u4E0D\u4F1A\u91CD\u505A\u5DF2\u5B8C\u6210\u7684\u6B65\u9AA4\uFF1B\u53EF\u7F16\u8F91\u56E2\u961F\u8FD0\u884C\u4F1A\u5728\u65B0\u7684\u72EC\u7ACB\u5DE5\u4F5C\u533A\u5148\u5957\u7528\u4E4B\u524D\u7684\u6539\u52A8\u518D\u7EED\u8DD1\uFF0C\u5931\u8D25\u7684\u5355\u6B21\u8C03\u7528\u4F1A\u4F5C\u4E3A\u65B0\u8FD0\u884C\u91CD\u65B0\u6267\u884C\uFF0C\u4E8C\u8005\u90FD\u9700\u5148\u786E\u8BA4\u3002")), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: busy, onClick: onRefresh }, "\u5237\u65B0")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, error), !ledger && !error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u8BFB\u53D6\u6267\u884C\u8BB0\u5F55\u2026"), ledger && runs.length === 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty" }, "\u8FD8\u6CA1\u6709\u6267\u884C\u8BB0\u5F55\u3002\u53EF\u5728\u4E0A\u65B9\u201C\u5728\u5DE5\u4F5C\u53F0\u6267\u884C\u201D\u4E2D\u9884\u89C8\u5E76\u6267\u884C\uFF0C\u6216\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u8C03\u7528 model_router_execute\u3001model_router_team_execute\u3001model_router_tool_run\uFF0C\u8FD9\u91CC\u4F1A\u663E\u793A\u51B3\u7B56\u548C\u7ED3\u679C\u3002"), runs.length > 0 && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-label", htmlFor: "mr-run-select" }, "\u9009\u62E9\u8BB0\u5F55"), /* @__PURE__ */ import_react2.default.createElement("select", { className: "mr-input", id: "mr-run-select", value: current?.id ?? "", onChange: (event) => setOpenId(event.target.value) }, runs.map((run) => /* @__PURE__ */ import_react2.default.createElement("option", { key: run.id, value: run.id }, new Date(run.createdAt).toLocaleString(), " \xB7 ", RUN_KIND_LABEL[run.kind ?? "assign"] ?? run.kind, " \xB7 ", RUN_STATUS_LABEL[run.status] ?? run.status, " \xB7 ", run.task.slice(0, 40)))), current && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-run" }, /* @__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" }, "\u65B9\u6848"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[current.preset]?.label ?? current.preset, current.budget?.downgraded ? "\uFF08\u8D85\u9884\u7B97\u81EA\u52A8\u964D\u7EA7\uFF09" : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u96BE\u5EA6"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, BAND[current.decision?.complexity?.band] ?? "\u2014", current.decision?.complexity?.value !== null && current.decision?.complexity?.value !== void 0 ? ` \xB7 ${current.decision.complexity.value}` : "")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u9884\u4F30 / \u5B9E\u9645\uFF08\u8BA1\u5165\u9884\u7B97\uFF09"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, money(current.decision?.estimatedCost), " / ", money(runTotals(current).budgetUsd))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u7C7B\u578B"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, RUN_KIND_LABEL[current.kind ?? "assign"] ?? current.kind, current.kind === "team" || current.kind === "tool" ? ` \xB7 ${current.executionMode === "workspace-write" ? "\u53EF\u7F16\u8F91" : "\u53EA\u8BFB"}` : ""))), runTotals(current).subscription && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8BA2\u9605\u53C2\u8003\u8D39\u7528\uFF08\u6309 API \u4EF7\u6298\u7B97\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\uFF09\uFF1A", money(runTotals(current).referenceUsd)), current.isolatedWorkspace && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u72EC\u7ACB\u5DE5\u4F5C\u533A\uFF1A", /* @__PURE__ */ import_react2.default.createElement("code", null, current.isolatedWorkspace)), current.rerunOf && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u91CD\u65B0\u6267\u884C\u81EA\u8FD0\u884C ", current.rerunOf.slice(0, 8), "\u3002"), current.decision?.reason && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u8DEF\u7531\u539F\u56E0\uFF1A", current.decision.reason), /* @__PURE__ */ import_react2.default.createElement(DagView, { packages: current.packages, renderNode: (item) => /* @__PURE__ */ import_react2.default.createElement(RunNode, { run: current, item, routes, allowReassign: ledger?.settings?.allowManualReassign !== false, busy, onRate, onRerun }) })))));
2082
+ }
2083
+ function BillingCard({ billing, error, onRefresh, refreshing }) {
2084
+ const rows = billingRows(billing);
2085
+ return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u8BA2\u9605\u4E0E API Key" }, /* @__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" }, "\u8BA2\u9605\u4E0E API Key"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u9ED8\u8BA4\u8BA2\u9605\u4F18\u5148\uFF1A\u6709\u8BA2\u9605\uFF08\u5B98\u65B9 CLI \u8D26\u53F7\u767B\u5F55\u6216\u7F16\u7A0B\u5957\u9910 Key \u8DEF\u7EBF\uFF09\u5C31\u5148\u7528\u8BA2\u9605\uFF1B\u8BA2\u9605\u989D\u5EA6\u7528\u5C3D\u6216\u9650\u6D41\u65F6\uFF0C\u540C\u4E00\u6B65\u9AA4\u81EA\u52A8\u6539\u7528 API Key\uFF0C\u5E76\u5728\u6267\u884C\u8BB0\u5F55\u4E2D\u5199\u660E\u539F\u56E0\u3002\u8BA2\u9605\u8FD0\u884C\u53EA\u663E\u793A\u53C2\u8003\u8D39\u7528\uFF0C\u4E0D\u8BA1\u5165\u9884\u7B97\u3002")), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: refreshing, onClick: onRefresh }, "\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), billing?.quotaPatternErrors?.length > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, "\u989D\u5EA6\u8BC6\u522B\u89C4\u5219\u6709\u8BEF\uFF0C\u5DF2\u5FFD\u7565\uFF1A", billing.quotaPatternErrors.join("\uFF1B")), rows.length === 0 && !error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty", role: billing ? void 0 : "status" }, billing ? "\u6A21\u578B\u76EE\u5F55\u4E2D\u6CA1\u6709\u8DEF\u7EBF\uFF1B\u8BF7\u5148\u5728\u5B98\u65B9\u201C\u6A21\u578B\u201D\u9875\u6DFB\u52A0\u6A21\u578B\uFF0C\u518D\u70B9\u201C\u5237\u65B0\u201D\u3002" : "\u6B63\u5728\u8BFB\u53D6\u8BA1\u8D39\u72B6\u6001\u2026"), rows.length > 0 && /* @__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, "\u4F9B\u5E94\u5546"), /* @__PURE__ */ import_react2.default.createElement("th", null, "\u8BA1\u8D39\u65B9\u5F0F"), /* @__PURE__ */ import_react2.default.createElement("th", null, "\u8BA2\u9605"), /* @__PURE__ */ import_react2.default.createElement("th", null, "\u8BA2\u9605\u72B6\u6001 / \u6062\u590D\u65F6\u95F4"), /* @__PURE__ */ import_react2.default.createElement("th", null, "API Key \u56DE\u9000"))), /* @__PURE__ */ import_react2.default.createElement("tbody", null, rows.map((row) => /* @__PURE__ */ import_react2.default.createElement("tr", { key: row.key }, /* @__PURE__ */ import_react2.default.createElement("td", null, /* @__PURE__ */ import_react2.default.createElement("strong", null, row.provider), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-caption" }, row.models)), /* @__PURE__ */ import_react2.default.createElement("td", null, row.mode), /* @__PURE__ */ import_react2.default.createElement("td", null, row.subscription), /* @__PURE__ */ import_react2.default.createElement("td", { className: row.exhausted ? "mr-warn-text" : "" }, row.state), /* @__PURE__ */ import_react2.default.createElement("td", { className: row.apiAvailable ? "" : "mr-warn-text" }, row.api)))))), billing && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, "\u5382\u5546\u6CA1\u6709\u7ED9\u51FA\u6062\u590D\u65F6\u95F4\u65F6\uFF0C\u6309\u8BBE\u7F6E\u4E2D\u7684\u51B7\u5374\u65F6\u95F4\uFF08", billing.cooldownMinutes ?? 60, " \u5206\u949F\uFF09\u6682\u505C\u4F7F\u7528\u8BE5\u8BA2\u9605\u3002\u56E2\u961F\u6267\u884C\u548C\u5355\u5DE5\u5177\u8C03\u7528\u53EA\u80FD\u901A\u8FC7\u5B98\u65B9 CLI \u4FEE\u6539\u6587\u4EF6\uFF0C\u989D\u5EA6\u7528\u5C3D\u65F6\u4F1A\u8BB0\u5F55\u5E76\u63D0\u793A\uFF0C\u4F46\u4E0D\u4F1A\u81EA\u52A8\u6539\u7528 API Key\u3002")));
2086
+ }
2087
+ function SecurityCard({ data, error, onRefresh }) {
2088
+ const rows = data?.boundaries ?? [];
2089
+ return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u5B89\u5168\u8FB9\u754C" }, /* @__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" }, "\u5B89\u5168\u8FB9\u754C"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u6BCF\u6761\u5DF2\u914D\u7F6E\u8DEF\u7EBF\u53EF\u8BFB\u3001\u53EF\u5199\u7684\u8303\u56F4\u548C\u662F\u5426\u7ECF\u8FC7 Harness \u8FDB\u7A0B\u6C99\u7BB1\u3002\u53EF\u7F16\u8F91\u8FD0\u884C\u603B\u662F\u9700\u8981\u4F60\u5728\u5B98\u65B9\u5BA1\u6279\u4E2D\u786E\u8BA4\uFF1B\u76F4\u63A5\u542F\u52A8\u65E0\u6C99\u7BB1 CLI \u524D\u9ED8\u8BA4\u4E5F\u4F1A\u8BE2\u95EE\u3002")), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: onRefresh }, "\u5237\u65B0")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, error), data && !data.sandboxAvailable && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error" }, "\u5F53\u524D Host \u6CA1\u6709\u63D0\u4F9B Harness \u8FDB\u7A0B\u6C99\u7BB1\uFF1A\u53EF\u7F16\u8F91\u8FD0\u884C\u4F1A\u88AB\u62D2\u7EDD\uFF0C\u53EA\u8BFB\u7684\u65E0\u754C\u9762 CLI \u5C06\u76F4\u63A5\u542F\u52A8\u3002"), rows.length === 0 && !error && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty", role: data ? void 0 : "status" }, data ? "\u6A21\u578B\u76EE\u5F55\u4E2D\u6CA1\u6709\u8DEF\u7EBF\uFF1B\u8BF7\u5148\u5728\u5B98\u65B9\u201C\u6A21\u578B\u201D\u9875\u6DFB\u52A0\u6A21\u578B\uFF0C\u518D\u70B9\u201C\u5237\u65B0\u201D\u3002" : "\u6B63\u5728\u8BFB\u53D6\u5B89\u5168\u8FB9\u754C\u2026"), rows.length > 0 && /* @__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"), /* @__PURE__ */ import_react2.default.createElement("th", null, "\u53EA\u8BFB\u8FD0\u884C\u53EF\u8BFB"), /* @__PURE__ */ import_react2.default.createElement("th", null, "\u53EA\u8BFB\u8FD0\u884C\u6C99\u7BB1"), /* @__PURE__ */ import_react2.default.createElement("th", null, "\u53EF\u7F16\u8F91\u8FD0\u884C"))), /* @__PURE__ */ import_react2.default.createElement("tbody", null, rows.map((row) => /* @__PURE__ */ import_react2.default.createElement("tr", { key: `${row.provider}/${row.model}` }, /* @__PURE__ */ import_react2.default.createElement("td", null, /* @__PURE__ */ import_react2.default.createElement("strong", null, row.provider, "/", row.model), row.toolLabel ? /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-caption" }, row.toolLabel) : /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-caption" }, "\u4EC5 API")), /* @__PURE__ */ import_react2.default.createElement("td", null, row.readOnly.readable), /* @__PURE__ */ import_react2.default.createElement("td", { className: row.readOnly.direct ? "mr-warn-text" : "" }, row.readOnly.sandbox), /* @__PURE__ */ import_react2.default.createElement("td", null, row.write ? `${row.write.writable}\uFF1B\u9700\u5BA1\u6279` : "\u4E0D\u652F\u6301"))))))));
2090
+ }
2091
+
2092
+ // .dsh-plugin/client/run-launcher.jsx
2093
+ var import_react3 = __toESM(require("react"), 1);
2094
+ var text2 = (value) => typeof value === "string" ? value.trim() : "";
2095
+ var STATUS_TEXT = Object.freeze({
2096
+ succeeded: "\u6267\u884C\u5B8C\u6210",
2097
+ completed: "\u6267\u884C\u5B8C\u6210",
2098
+ partial: "\u90E8\u5206\u6B65\u9AA4\u5931\u8D25",
2099
+ failed: "\u6267\u884C\u5931\u8D25",
2100
+ cancelled: "\u5DF2\u53D6\u6D88",
2101
+ "paused-budget": "\u5DF2\u56E0\u9884\u7B97\u6682\u505C\uFF0C\u672A\u542F\u52A8\u6A21\u578B",
2102
+ "paused-subscription-failure": "\u6709\u6B65\u9AA4\u56E0\u8BA2\u9605\u8C03\u7528\u5931\u8D25\u800C\u6682\u505C\uFF0C\u8BF7\u5728\u4E0B\u65B9\u6267\u884C\u8BB0\u5F55\u4E2D\u9009\u62E9\u5982\u4F55\u7EE7\u7EED"
2103
+ });
2104
+ function RunLauncher({ task, mode, directRoute, budgetUsd, defaultPreset, ledger, previewRun, startRun, onStarted, disabledReason }) {
2105
+ const [preset, setPreset] = import_react3.default.useState(defaultPreset || "balanced");
2106
+ const lastWorkspace = [...ledger?.runs ?? []].map((run) => run.workspace).find(Boolean) ?? "";
2107
+ const [workspace, setWorkspace] = import_react3.default.useState("");
2108
+ const [phase, setPhase] = import_react3.default.useState({ kind: "idle" });
2109
+ const mounted = import_react3.default.useRef(true);
2110
+ const confirmRef = import_react3.default.useRef(null);
2111
+ import_react3.default.useEffect(() => () => {
2112
+ mounted.current = false;
2113
+ }, []);
2114
+ import_react3.default.useEffect(() => {
2115
+ setPreset(defaultPreset || "balanced");
2116
+ }, [defaultPreset]);
2117
+ import_react3.default.useEffect(() => {
2118
+ setPhase((previous) => previous.kind === "preview" || previous.kind === "error" ? { kind: "idle" } : previous);
2119
+ }, [task, mode, directRoute?.provider, directRoute?.model, budgetUsd, preset, workspace]);
2120
+ import_react3.default.useEffect(() => {
2121
+ if (phase.kind === "preview") confirmRef.current?.focus();
2122
+ }, [phase.kind]);
2123
+ const request = () => launchRequest({ task, mode, directRoute, budgetUsd, preset, workspace: text2(workspace) || lastWorkspace });
2124
+ const unavailable = typeof previewRun !== "function" || typeof startRun !== "function";
2125
+ const blocked = disabledReason || (unavailable ? "\u5DE5\u4F5C\u53F0\u6267\u884C\u670D\u52A1\u5C1A\u672A\u52A0\u8F7D\uFF0C\u8BF7\u66F4\u65B0\u63D2\u4EF6\u540E\u91CD\u8BD5\u3002" : !text2(task) ? "\u5148\u5728\u4E0A\u65B9\u201C\u4EFB\u52A1\u89C4\u5212\u201D\u4E2D\u63CF\u8FF0\u4EFB\u52A1\u3002" : "");
2126
+ const busy = phase.kind === "previewing" || phase.kind === "running";
2127
+ const preview = async () => {
2128
+ setPhase({ kind: "previewing" });
2129
+ try {
2130
+ const value = unwrapRemote(await previewRun(request()), "\u6267\u884C\u9884\u89C8\u5931\u8D25\u3002");
2131
+ if (mounted.current) setPhase({ kind: "preview", value });
2132
+ } catch (error) {
2133
+ if (mounted.current) setPhase({ kind: "error", message: text2(error?.message) || "\u6267\u884C\u9884\u89C8\u5931\u8D25\u3002" });
2134
+ }
2135
+ };
2136
+ const confirm = async () => {
2137
+ const shown = phase.value;
2138
+ setPhase({ kind: "running", value: shown });
2139
+ try {
2140
+ const value = unwrapRemote(await startRun({ ...request(), confirmedReasons: shown.reasons.map((item) => item.code) }), "\u6267\u884C\u5931\u8D25\u3002");
2141
+ if (!mounted.current) return;
2142
+ if (value.status === "needs-confirmation") {
2143
+ setPhase({ kind: "preview", value, changed: true });
2144
+ return;
2145
+ }
2146
+ setPhase({ kind: "done", value });
2147
+ onStarted?.(value.runId);
2148
+ } catch (error) {
2149
+ if (mounted.current) setPhase({ kind: "error", message: text2(error?.message) || "\u6267\u884C\u5931\u8D25\u3002" });
2150
+ }
2151
+ };
2152
+ return /* @__PURE__ */ import_react3.default.createElement("section", { className: "mr-card", "aria-label": "\u5728\u5DE5\u4F5C\u53F0\u6267\u884C" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react3.default.createElement("div", null, /* @__PURE__ */ import_react3.default.createElement("h2", { className: "mr-card-title" }, "\u5728\u5DE5\u4F5C\u53F0\u6267\u884C"), /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-card-copy" }, "\u4F7F\u7528\u4E0A\u65B9\u7684\u4EFB\u52A1\u63CF\u8FF0\u4E0E\u89C4\u5212\u6A21\u5F0F\uFF0C\u5148\u9884\u89C8\u6267\u884C\u8BA1\u5212\u4E0E\u9884\u4F30\u8D39\u7528\uFF0C\u786E\u8BA4\u540E\u624D\u4F1A\u8C03\u7528\u6A21\u578B\u3002\u6267\u884C\u4E3A\u53EA\u8BFB\uFF1A\u5B98\u65B9 CLI \u4EE5\u65E0\u754C\u9762\u53EA\u8BFB\u65B9\u5F0F\u8FD0\u884C\uFF0C\u4E0D\u4FEE\u6539\u6587\u4EF6\uFF1B\u53EF\u7F16\u8F91\u4EFB\u52A1\u8BF7\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u4F7F\u7528 model_router_tool_run \u6216 model_router_team_execute\u3002"))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-control-label", id: "mr-launch-preset" }, "\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-segment", role: "group", "aria-labelledby": "mr-launch-preset" }, Object.values(ROUTING_PRESETS).map((item) => /* @__PURE__ */ import_react3.default.createElement("button", { key: item.id, type: "button", title: item.description, "aria-pressed": preset === item.id, disabled: busy || mode === "direct", onClick: () => setPreset(item.id) }, item.label)))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-control-group mr-launch-workspace" }, /* @__PURE__ */ import_react3.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-launch-workspace" }, "\u5DE5\u4F5C\u533A\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09"), /* @__PURE__ */ import_react3.default.createElement("input", { className: "mr-input", id: "mr-launch-workspace", value: workspace, disabled: busy, placeholder: lastWorkspace ? `\u7559\u7A7A\u6CBF\u7528\u4E0A\u6B21\u8FD0\u884C\uFF1A${lastWorkspace}` : "\u4F8B\u5982 D:\\projects\\demo \u6216 /home/me/demo", onChange: (event) => setWorkspace(event.target.value) }))), /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, mode === "direct" ? `\u6307\u5B9A\u6A21\u578B\uFF1A${directRoute ? `${directRoute.provider}/${directRoute.model}` : "\u672A\u9009\u62E9"}\uFF08\u8DF3\u8FC7\u8DEF\u7531\uFF0C\u65B9\u6848\u4E0D\u751F\u6548\uFF09` : mode === "team" ? "\u56E2\u961F\u5206\u5DE5\uFF1A\u6309\u65B9\u6848\u62C6\u5206\u5DE5\u4F5C\u5305\uFF0C\u9010\u4E2A\u5206\u914D\u6A21\u578B\u3002" : "\u5355\u4EFB\u52A1\uFF1A\u6309\u65B9\u6848\u9009\u62E9\u4E00\u6761\u8DEF\u7EBF\u3002"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react3.default.createElement("button", { className: "mr-button", type: "button", disabled: Boolean(blocked) || busy, onClick: () => {
2153
+ void preview();
2154
+ } }, phase.kind === "previewing" ? "\u6B63\u5728\u751F\u6210\u9884\u89C8\u2026" : "\u9884\u89C8\u6267\u884C\u8BA1\u5212"), blocked && /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-caption" }, blocked)), phase.kind === "previewing" && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u6309\u5F53\u524D\u6A21\u578B\u76EE\u5F55\u3001\u767B\u5F55\u72B6\u6001\u548C\u9884\u7B97\u751F\u6210\u6267\u884C\u8BA1\u5212\u2026"), phase.kind === "error" && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-error", role: "alert" }, phase.message), (phase.kind === "preview" || phase.kind === "running") && /* @__PURE__ */ import_react3.default.createElement(
2155
+ LaunchPreview,
2156
+ {
2157
+ value: phase.value,
2158
+ changed: phase.changed,
2159
+ running: phase.kind === "running",
2160
+ confirmRef,
2161
+ onConfirm: () => {
2162
+ void confirm();
2163
+ },
2164
+ onCancel: () => setPhase({ kind: "idle" })
2165
+ }
2166
+ ), phase.kind === "done" && /* @__PURE__ */ import_react3.default.createElement("div", { className: phase.value.status === "failed" || phase.value.status?.startsWith("paused") ? "mr-error" : "mr-empty", role: "status" }, STATUS_TEXT[phase.value.status] ?? `\u72B6\u6001\uFF1A${phase.value.status}`, phase.value.runId ? `\uFF1B\u7ED3\u679C\u5DF2\u8BB0\u5F55\uFF08\u8FD0\u884C ${phase.value.runId.slice(0, 8)}\uFF09\uFF0C\u89C1\u4E0B\u65B9\u201C\u6267\u884C\u8BB0\u5F55\u4E0E\u5B50\u4EFB\u52A1\u201D\u3002` : "\u3002", phase.value.budget?.message ? ` ${phase.value.budget.exceeded && phase.value.status !== "paused-budget" ? "\u5DF2\u6309\u4F60\u7684\u786E\u8BA4\u8D85\u9884\u7B97\u6267\u884C\uFF1A" : ""}${phase.value.budget.message}` : "")));
2167
+ }
2168
+ function LaunchPreview({ value, changed, running, confirmRef, onConfirm, onCancel }) {
2169
+ const packages = value.decision?.packages ?? [];
2170
+ const reasons = value.reasons ?? [];
2171
+ return /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-launch-preview", role: "region", "aria-label": "\u6267\u884C\u9884\u89C8" }, changed && /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-error", role: "alert" }, "\u786E\u8BA4\u671F\u95F4\u60C5\u51B5\u6709\u53D8\u5316\uFF08\u4F8B\u5982\u9884\u7B97\u6216\u767B\u5F55\u72B6\u6001\uFF09\uFF0C\u8BF7\u91CD\u65B0\u6838\u5BF9\u4E0B\u9762\u7684\u786E\u8BA4\u9879\u3002"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, "\u8DEF\u7EBF"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value" }, value.selected ? `${value.selected.provider}/${value.selected.model}` : "\u6682\u65E0\u8DEF\u7EBF", value.routingBypassed ? "\uFF08\u6307\u5B9A\u6A21\u578B\uFF09" : "")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, "\u9884\u4F30\u8D39\u7528"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value" }, value.estimatedCost === null || value.estimatedCost === void 0 ? "\u4EF7\u683C\u5F85\u914D\u7F6E" : money(value.estimatedCost))), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, "\u65B9\u6848"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[value.decision?.preset]?.label ?? "\u2014", value.budget?.downgraded ? "\uFF08\u8D85\u9884\u7B97\u81EA\u52A8\u964D\u7EA7\uFF09" : "")), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-label" }, "\u5DE5\u4F5C\u533A"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-metric-value mr-break" }, /* @__PURE__ */ import_react3.default.createElement("code", null, value.workspace)))), value.budget?.message && /* @__PURE__ */ import_react3.default.createElement("p", { className: value.budget.exceeded ? "mr-error" : "mr-caption" }, "\u9884\u7B97\u68C0\u67E5\uFF1A", value.budget.message), packages.length > 0 && /* @__PURE__ */ import_react3.default.createElement("ol", { className: "mr-launch-packages" }, packages.map((item) => /* @__PURE__ */ import_react3.default.createElement("li", { key: item.id }, /* @__PURE__ */ import_react3.default.createElement("strong", null, item.name), " \u2192 ", item.route, " ", /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-caption" }, "\uFF08\u9884\u4F30 ", money(item.estimatedCost), item.channel === "official-cli" ? " \xB7 \u5B98\u65B9 CLI" : item.channel ? " \xB7 \u6A21\u578B\u76EE\u5F55 API" : "", "\uFF09")))), reasons.length > 0 ? /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-confirm-box" }, /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-section-title" }, "\u6267\u884C\u524D\u9700\u8981\u786E\u8BA4\u4EE5\u4E0B ", reasons.length, " \u9879\uFF1A"), /* @__PURE__ */ import_react3.default.createElement("ol", null, reasons.map((item) => /* @__PURE__ */ import_react3.default.createElement("li", { key: item.code }, item.zh)))) : /* @__PURE__ */ import_react3.default.createElement("p", { className: "mr-caption" }, "\u65E0\u9700\u989D\u5916\u786E\u8BA4\uFF1A\u672A\u8D85\u9884\u7B97\uFF0C\u4E5F\u4E0D\u4F1A\u4E0D\u7ECF\u6C99\u7BB1\u542F\u52A8 CLI\u3002"), /* @__PURE__ */ import_react3.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react3.default.createElement("button", { ref: confirmRef, className: "mr-button", type: "button", disabled: running, onClick: onConfirm }, running ? "\u6B63\u5728\u6267\u884C\u2026" : reasons.length ? "\u5168\u90E8\u786E\u8BA4\u5E76\u6267\u884C" : "\u786E\u8BA4\u6267\u884C"), /* @__PURE__ */ import_react3.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: running, onClick: onCancel }, "\u53D6\u6D88"), running && /* @__PURE__ */ import_react3.default.createElement("span", { className: "mr-caption", role: "status", "aria-live": "polite" }, "\u6A21\u578B\u8C03\u7528\u53EF\u80FD\u9700\u8981\u51E0\u5206\u949F\uFF0C\u8BF7\u52FF\u5173\u95ED\u5DE5\u4F5C\u53F0\u3002")));
2172
+ }
2173
+
1376
2174
  // .dsh-plugin/client/router-main.css
1377
- var router_main_default = ".mr-workspace {\r\n --mr-card: rgba(255, 255, 255, .94);\r\n --mr-ink: #182232;\r\n --mr-muted: #526174;\r\n --mr-line: rgba(38, 55, 75, .13);\r\n --mr-accent: #315cc8;\r\n --mr-soft: #edf3ff;\r\n box-sizing: border-box;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 0;\r\n overflow-y: auto;\r\n background: rgba(246, 249, 253, .9);\r\n backdrop-filter: blur(18px);\r\n color: var(--mr-ink);\r\n font-family: inherit;\r\n}\r\n.mr-workspace *, .mr-workspace *::before, .mr-workspace *::after { box-sizing: border-box; }\r\n.mr-shell { width: min(1160px, 100%); margin: 0 auto; padding: 36px 32px 64px; }\r\n.mr-header { display: flex; flex-wrap: wrap; gap: 20px; align-items: end; justify-content: space-between; margin-bottom: 24px; }\r\n.mr-eyebrow { margin: 0 0 8px; color: var(--mr-accent); font-size: 11px; font-weight: 750; letter-spacing: .14em; text-transform: uppercase; }\r\n.mr-title { margin: 0; font-size: clamp(25px, 3vw, 34px); letter-spacing: -.035em; line-height: 1.16; }\r\n.mr-subtitle { margin: 10px 0 0; color: var(--mr-muted); font-size: 14px; line-height: 1.65; }\r\n.mr-status { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; border: 1px solid var(--mr-line); border-radius: 999px; background: var(--mr-card); color: var(--mr-muted); font-size: 12px; white-space: nowrap; }\r\n.mr-status-dot { width: 7px; height: 7px; border-radius: 50%; background: #2cba83; }\r\n.mr-status-dot.loading { background: #e9a640; }\r\n.mr-status-dot.error { background: #d95360; }\r\n.mr-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(280px, .85fr); gap: 18px; align-items: start; }\r\n.mr-card { min-width: 0; border: 1px solid var(--mr-line); border-radius: 18px; background: var(--mr-card); box-shadow: 0 12px 42px rgba(25, 45, 76, .08); }\r\n.mr-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 20px 22px 0; }\r\n.mr-card-title { margin: 0; font-size: 16px; font-weight: 700; }\r\n.mr-card-copy { margin: 5px 0 0; color: var(--mr-muted); font-size: 12px; line-height: 1.55; }\r\n.mr-card-body { padding: 18px 22px 22px; }\r\n.mr-label { display: block; margin: 0 0 8px; font-size: 12px; font-weight: 700; }\r\n.mr-textarea, .mr-input { width: 100%; border: 1px solid var(--mr-line); border-radius: 11px; background: #fff; color: var(--mr-ink); font: inherit; outline: none; }\r\n.mr-textarea { min-height: 154px; padding: 13px 14px; resize: vertical; line-height: 1.6; font-size: 14px; }\r\n.mr-input { min-height: 38px; padding: 8px 11px; font-size: 13px; }\r\n.mr-textarea:focus, .mr-input:focus { border-color: var(--mr-accent); box-shadow: 0 0 0 3px rgba(49, 92, 200, .13); }\r\n.mr-controls { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 14px; margin-top: 17px; }\r\n.mr-control-group { display: flex; flex-direction: column; gap: 7px; }\r\n.mr-control-label { color: var(--mr-muted); font-size: 11px; font-weight: 650; }\r\n.mr-segment { display: inline-flex; padding: 3px; border-radius: 10px; background: #edf1f7; }\r\n.mr-segment button { border: 0; border-radius: 8px; padding: 8px 12px; background: transparent; color: var(--mr-muted); font: inherit; font-size: 12px; cursor: pointer; }\r\n.mr-segment button[aria-pressed='true'] { background: #fff; color: var(--mr-ink); box-shadow: 0 2px 8px rgba(20, 35, 56, .1); font-weight: 700; }\r\n.mr-budget { width: 140px; }\r\n.mr-actions { display: flex; flex-wrap: wrap; gap: 9px; align-items: center; margin-top: 18px; }\r\n.mr-button { border: 1px solid transparent; border-radius: 10px; min-height: 38px; padding: 8px 14px; background: var(--mr-accent); color: #fff; font: inherit; font-size: 13px; font-weight: 700; cursor: pointer; }\r\n.mr-button:hover:not(:disabled) { filter: brightness(.94); }\r\n.mr-button:disabled { cursor: not-allowed; opacity: .5; }\r\n.mr-button-secondary { border-color: var(--mr-line); background: #fff; color: var(--mr-ink); }\r\n.mr-caption { color: var(--mr-muted); font-size: 11px; line-height: 1.5; }\r\n.mr-search { margin-top: 14px; }\r\n.mr-list { display: grid; gap: 8px; margin-top: 13px; max-height: 395px; overflow-y: auto; }\r\n.mr-route { display: flex; justify-content: space-between; gap: 10px; padding: 10px 11px; border: 1px solid var(--mr-line); border-radius: 10px; background: #f9fbfe; }\r\n.mr-route-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 700; }\r\n.mr-route-provider { margin-top: 2px; color: var(--mr-muted); font-size: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\r\n.mr-pill { align-self: start; flex: none; padding: 3px 7px; border-radius: 7px; background: var(--mr-soft); color: var(--mr-accent); font-size: 10px; font-weight: 700; }\r\n.mr-empty, .mr-error { padding: 14px; border-radius: 10px; background: #f4f6fa; color: var(--mr-muted); font-size: 12px; line-height: 1.6; }\r\n.mr-error { background: #fff0f1; color: #a52d3c; }\r\n.mr-results { margin-top: 18px; }\r\n.mr-result-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 16px; }\r\n.mr-metric { padding: 13px; border-radius: 12px; background: #f5f8fd; }\r\n.mr-metric-label { color: var(--mr-muted); font-size: 10px; }\r\n.mr-metric-value { margin-top: 5px; font-size: 15px; font-weight: 750; word-break: break-word; }\r\n.mr-section-title { margin: 20px 0 10px; font-size: 13px; font-weight: 750; }\r\n.mr-package { padding: 13px 14px; border: 1px solid var(--mr-line); border-radius: 11px; background: #fafcff; }\r\n.mr-package + .mr-package { margin-top: 8px; }\r\n.mr-package-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px; align-items: center; }\r\n.mr-package-name { font-size: 12px; font-weight: 750; }\r\n.mr-package-route { color: var(--mr-accent); font-size: 11px; font-weight: 700; }\r\n.mr-package-copy { margin: 7px 0 0; color: var(--mr-muted); font-size: 11px; line-height: 1.6; }\r\n.mr-notice { margin-top: 18px; padding: 14px 16px; border: 1px solid rgba(49, 92, 200, .16); border-radius: 12px; background: #eff4ff; color: #354d7a; font-size: 11px; line-height: 1.65; }\r\n.mr-notice code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 11px; }\r\n@media (max-width: 850px) { .mr-grid { grid-template-columns: 1fr; } .mr-shell { padding: 24px 18px 48px; } }\r\n@media (prefers-color-scheme: dark) {\r\n .mr-workspace { --mr-card: rgba(30, 38, 51, .94); --mr-ink: #ecf2ff; --mr-muted: #aebbd0; --mr-line: rgba(210, 224, 245, .15); --mr-accent: #91adff; --mr-soft: rgba(97, 132, 222, .18); background: rgba(18, 23, 32, .91); }\r\n .mr-textarea, .mr-input, .mr-segment button[aria-pressed='true'], .mr-button-secondary { background: #273245; color: var(--mr-ink); }\r\n .mr-segment, .mr-empty, .mr-metric { background: #222d3e; }\r\n .mr-route, .mr-package { background: #222d3e; }\r\n .mr-notice { background: #243454; color: #c9d6fa; }\r\n .mr-error { background: #4a2730; color: #ffd4da; }\r\n}\r\n\r\n/* \u5B98\u65B9\u5DE5\u5177\u5361\u7247 */\r\n.mr-tools { display: grid; gap: 9px; }\r\n.mr-tool { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px; border: 1px solid var(--mr-line); border-radius: 11px; background: var(--mr-card); }\r\n.mr-tool-info { min-width: 0; flex: 1; }\r\n.mr-tool-status { display: flex; align-items: center; gap: 6px; margin-top: 7px; color: var(--mr-muted); font-size: 11px; }\r\n.mr-tool-dot { width: 7px; height: 7px; flex: none; border-radius: 50%; background: #8d9aaa; }\r\n.mr-tool-dot.installed { background: #2cba83; }\r\n.mr-tool-dot.running { background: #e9a640; }\r\n.mr-tool-command { display: block; margin-top: 6px; padding: 4px 8px; font-size: 12px; background: var(--dsw-alias-markdown-code-block); border-radius: 6px; overflow-wrap: anywhere; }\r\n.mr-tool-button { flex-shrink: 0; }\r\n.mr-tool-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }\r\n.mr-tool-detail { margin: 7px 0 0; }\r\n.mr-tool-error { margin: 8px 0 0; padding: 9px 11px; }\r\n.mr-tool-log { margin-top: 7px; color: var(--mr-muted); font-size: 11px; }\r\n.mr-tool-log summary { cursor: pointer; }\r\n.mr-tool-log pre { max-height: 140px; overflow: auto; padding: 8px; border-radius: 7px; background: var(--dsw-alias-markdown-code-block); font-size: 10px; white-space: pre-wrap; overflow-wrap: anywhere; }\r\n.mr-channel-line { display: flex; align-items: center; gap: 8px; margin: 8px 0; flex-wrap: wrap; }\r\n.mr-pill-channel-ok { border-color: var(--dsw-alias-success, #2f9e63); color: var(--dsw-alias-success, #2f9e63); }\n.mr-profile-card { margin-top: 18px; }\n.mr-profile-state { display: block; margin: 8px 0 0; }\n.mr-profile-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; margin-top: 15px; }\n.mr-profile-field { display: grid; align-content: start; gap: 6px; color: var(--mr-muted); font-size: 11px; font-weight: 650; }\n.mr-profile-field .mr-input { color: var(--mr-ink); }\n.mr-profile-advanced { margin-top: 14px; color: var(--mr-muted); font-size: 11px; }\n.mr-profile-advanced summary { cursor: pointer; }\n.mr-profile-success { padding: 10px 12px; border-radius: 10px; background: #e5f5eb; color: #175f3a; font-size: 12px; }\n@media (prefers-color-scheme: dark) { .mr-profile-success { background: #193b2b; color: #b4f1cc; } }\n@media (max-width: 560px) { .mr-tool { align-items: stretch; flex-direction: column; gap: 10px; } .mr-tool-button { align-self: flex-start; } }\n";
2175
+ var router_main_default = ".mr-workspace {\n --mr-card: rgba(255, 255, 255, .94);\n --mr-ink: #182232;\n --mr-muted: #526174;\n --mr-line: rgba(38, 55, 75, .13);\n --mr-accent: #315cc8;\n --mr-soft: #edf3ff;\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n min-height: 0;\n overflow-y: auto;\n background: rgba(246, 249, 253, .9);\n backdrop-filter: blur(18px);\n color: var(--mr-ink);\n font-family: inherit;\n}\n.mr-workspace *, .mr-workspace *::before, .mr-workspace *::after { box-sizing: border-box; }\n.mr-shell { width: min(1160px, 100%); margin: 0 auto; padding: 36px 32px 64px; }\n.mr-header { display: flex; flex-wrap: wrap; gap: 20px; align-items: end; justify-content: space-between; margin-bottom: 24px; }\n.mr-eyebrow { margin: 0 0 8px; color: var(--mr-accent); font-size: 11px; font-weight: 750; letter-spacing: .14em; text-transform: uppercase; }\n.mr-title { margin: 0; font-size: clamp(25px, 3vw, 34px); letter-spacing: -.035em; line-height: 1.16; }\n.mr-subtitle { margin: 10px 0 0; color: var(--mr-muted); font-size: 14px; line-height: 1.65; }\n.mr-status { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; border: 1px solid var(--mr-line); border-radius: 999px; background: var(--mr-card); color: var(--mr-muted); font-size: 12px; white-space: nowrap; }\n.mr-status-dot { width: 7px; height: 7px; border-radius: 50%; background: #2cba83; }\n.mr-status-dot.loading { background: #e9a640; }\n.mr-status-dot.error { background: #d95360; }\n.mr-grid { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(280px, .85fr); gap: 18px; align-items: start; }\n.mr-card { min-width: 0; border: 1px solid var(--mr-line); border-radius: 18px; background: var(--mr-card); box-shadow: 0 12px 42px rgba(25, 45, 76, .08); }\n.mr-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 20px 22px 0; }\n.mr-card-title { margin: 0; font-size: 16px; font-weight: 700; }\n.mr-card-copy { margin: 5px 0 0; color: var(--mr-muted); font-size: 12px; line-height: 1.55; }\n.mr-card-body { padding: 18px 22px 22px; }\n.mr-label { display: block; margin: 0 0 8px; font-size: 12px; font-weight: 700; }\n.mr-textarea, .mr-input { width: 100%; border: 1px solid var(--mr-line); border-radius: 11px; background: #fff; color: var(--mr-ink); font: inherit; outline: none; }\n.mr-textarea { min-height: 154px; padding: 13px 14px; resize: vertical; line-height: 1.6; font-size: 14px; }\n.mr-input { min-height: 38px; padding: 8px 11px; font-size: 13px; }\n.mr-textarea:focus, .mr-input:focus { border-color: var(--mr-accent); box-shadow: 0 0 0 3px rgba(49, 92, 200, .13); }\n.mr-controls { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 14px; margin-top: 17px; }\n.mr-control-group { display: flex; flex-direction: column; gap: 7px; }\n.mr-control-label { color: var(--mr-muted); font-size: 11px; font-weight: 650; }\n.mr-segment { display: inline-flex; padding: 3px; border-radius: 10px; background: #edf1f7; }\n.mr-segment button { border: 0; border-radius: 8px; padding: 8px 12px; background: transparent; color: var(--mr-muted); font: inherit; font-size: 12px; cursor: pointer; }\n.mr-segment button[aria-pressed='true'] { background: #fff; color: var(--mr-ink); box-shadow: 0 2px 8px rgba(20, 35, 56, .1); font-weight: 700; }\n.mr-budget { width: 140px; }\n.mr-direct { min-width: min(100%, 280px); }\n.mr-actions { display: flex; flex-wrap: wrap; gap: 9px; align-items: center; margin-top: 18px; }\n.mr-button { border: 1px solid transparent; border-radius: 10px; min-height: 38px; padding: 8px 14px; background: var(--mr-accent); color: #fff; font: inherit; font-size: 13px; font-weight: 700; cursor: pointer; }\n.mr-button:hover:not(:disabled) { filter: brightness(.94); }\n.mr-button:disabled { cursor: not-allowed; opacity: .5; }\n.mr-button-secondary { border-color: var(--mr-line); background: #fff; color: var(--mr-ink); }\n.mr-caption { color: var(--mr-muted); font-size: 11px; line-height: 1.5; }\n.mr-search { margin-top: 14px; }\n.mr-list { display: grid; gap: 8px; margin-top: 13px; max-height: 395px; overflow-y: auto; }\n.mr-route { display: flex; justify-content: space-between; gap: 10px; padding: 10px 11px; border: 1px solid var(--mr-line); border-radius: 10px; background: #f9fbfe; }\n.mr-route-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 700; }\n.mr-route-provider { margin-top: 2px; color: var(--mr-muted); font-size: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.mr-pill { align-self: start; flex: none; padding: 3px 7px; border-radius: 7px; background: var(--mr-soft); color: var(--mr-accent); font-size: 10px; font-weight: 700; }\n.mr-empty, .mr-error { padding: 14px; border-radius: 10px; background: #f4f6fa; color: var(--mr-muted); font-size: 12px; line-height: 1.6; }\n.mr-error { background: #fff0f1; color: #a52d3c; }\n.mr-results { margin-top: 18px; }\n.mr-result-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin-bottom: 16px; }\n.mr-metric { padding: 13px; border-radius: 12px; background: #f5f8fd; }\n.mr-metric-label { color: var(--mr-muted); font-size: 10px; }\n.mr-metric-value { margin-top: 5px; font-size: 15px; font-weight: 750; word-break: break-word; }\n.mr-section-title { margin: 20px 0 10px; font-size: 13px; font-weight: 750; }\n.mr-package { padding: 13px 14px; border: 1px solid var(--mr-line); border-radius: 11px; background: #fafcff; }\n.mr-package + .mr-package { margin-top: 8px; }\n.mr-package-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px; align-items: center; }\n.mr-package-name { font-size: 12px; font-weight: 750; }\n.mr-package-route { color: var(--mr-accent); font-size: 11px; font-weight: 700; }\n.mr-package-copy { margin: 7px 0 0; color: var(--mr-muted); font-size: 11px; line-height: 1.6; }\n.mr-notice { margin-top: 18px; padding: 14px 16px; border: 1px solid rgba(49, 92, 200, .16); border-radius: 12px; background: #eff4ff; color: #354d7a; font-size: 11px; line-height: 1.65; }\n.mr-notice code { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 11px; }\n@media (max-width: 850px) { .mr-grid { grid-template-columns: 1fr; } .mr-shell { padding: 24px 18px 48px; } }\n@media (prefers-color-scheme: dark) {\n .mr-workspace { --mr-card: rgba(30, 38, 51, .94); --mr-ink: #ecf2ff; --mr-muted: #aebbd0; --mr-line: rgba(210, 224, 245, .15); --mr-accent: #91adff; --mr-soft: rgba(97, 132, 222, .18); background: rgba(18, 23, 32, .91); }\n .mr-textarea, .mr-input, .mr-segment button[aria-pressed='true'], .mr-button-secondary { background: #273245; color: var(--mr-ink); }\n .mr-segment, .mr-empty, .mr-metric { background: #222d3e; }\n .mr-route, .mr-package { background: #222d3e; }\n .mr-notice { background: #243454; color: #c9d6fa; }\n .mr-error { background: #4a2730; color: #ffd4da; }\n}\n\n/* \u5B98\u65B9\u5DE5\u5177\u5361\u7247 */\n.mr-tools { display: grid; gap: 9px; }\n.mr-tool { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px; border: 1px solid var(--mr-line); border-radius: 11px; background: var(--mr-card); }\n.mr-tool-info { min-width: 0; flex: 1; }\n.mr-tool-status { display: flex; align-items: center; gap: 6px; margin-top: 7px; color: var(--mr-muted); font-size: 11px; }\n.mr-tool-dot { width: 7px; height: 7px; flex: none; border-radius: 50%; background: #8d9aaa; }\n.mr-tool-dot.installed { background: #2cba83; }\n.mr-tool-dot.running { background: #e9a640; }\n.mr-tool-command { display: block; margin-top: 6px; padding: 4px 8px; font-size: 12px; background: var(--dsw-alias-markdown-code-block); border-radius: 6px; overflow-wrap: anywhere; }\n.mr-tool-button { flex-shrink: 0; }\n.mr-tool-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }\n.mr-tool-detail { margin: 7px 0 0; }\n.mr-tool-error { margin: 8px 0 0; padding: 9px 11px; }\n.mr-tool-log { margin-top: 7px; color: var(--mr-muted); font-size: 11px; }\n.mr-tool-log summary { cursor: pointer; }\n.mr-tool-log pre { max-height: 140px; overflow: auto; padding: 8px; border-radius: 7px; background: var(--dsw-alias-markdown-code-block); font-size: 10px; white-space: pre-wrap; overflow-wrap: anywhere; }\n.mr-channel-line { display: flex; align-items: center; gap: 8px; margin: 8px 0; flex-wrap: wrap; }\n.mr-pill-channel-ok { border-color: var(--dsw-alias-success, #2f9e63); color: var(--dsw-alias-success, #2f9e63); }\n.mr-pill-warn { border-color: var(--dsw-alias-warning, #c27c0e); color: var(--dsw-alias-warning, #c27c0e); }\n.mr-profile-card { margin-top: 18px; }\n.mr-profile-state { display: block; margin: 8px 0 0; }\n.mr-profile-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; margin-top: 15px; }\n.mr-profile-field { display: grid; align-content: start; gap: 6px; color: var(--mr-muted); font-size: 11px; font-weight: 650; }\n.mr-profile-field .mr-input { color: var(--mr-ink); }\n.mr-profile-advanced { margin-top: 14px; color: var(--mr-muted); font-size: 11px; }\n.mr-profile-advanced summary { cursor: pointer; }\n.mr-profile-success { padding: 10px 12px; border-radius: 10px; background: #e5f5eb; color: #175f3a; font-size: 12px; }\n@media (prefers-color-scheme: dark) { .mr-profile-success { background: #193b2b; color: #b4f1cc; } }\n@media (max-width: 560px) { .mr-tool { align-items: stretch; flex-direction: column; gap: 10px; } .mr-tool-button { align-self: flex-start; } }\n\n/* \u5F00\u7BB1\u4F53\u68C0\u3001\u6210\u672C\u63A7\u5236\u3001\u6267\u884C\u8BB0\u5F55\u3001\u5B89\u5168\u8FB9\u754C */\n.mr-onboarding, .mr-cost { margin-bottom: 18px; }\n.mr-onboarding { border-color: rgba(49, 92, 200, .35); }\n.mr-checklist { margin: 4px 0 0; padding-left: 18px; color: var(--mr-ink); font-size: 12px; line-height: 1.8; }\n.mr-login { margin-top: 4px; }\n.mr-login-button { margin-top: 8px; min-height: 30px; padding: 4px 10px; font-size: 12px; }\n.mr-login-guide { margin-top: 8px; padding: 10px 12px; border: 1px dashed var(--mr-line); border-radius: 10px; }\n.mr-login-command { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }\n.mr-login-command .mr-tool-command { margin: 0; }\n.mr-tool-dot.missing-strong { background: #d95360; }\n.mr-meters { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; }\n.mr-meter { padding: 12px 13px; border-radius: 12px; background: #f5f8fd; }\n.mr-meter-top { display: flex; justify-content: space-between; gap: 8px; font-size: 15px; font-weight: 750; }\n.mr-meter-over { color: #a52d3c; }\n.mr-meter-track { height: 7px; margin-top: 9px; border-radius: 999px; background: rgba(38, 55, 75, .1); overflow: hidden; }\n.mr-meter-fill { height: 100%; border-radius: inherit; background: #2cba83; }\n.mr-meter-fill.near { background: #e9a640; }\n.mr-meter-fill.over { background: #d95360; }\n.mr-inline { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.mr-check { display: inline-flex; align-items: center; gap: 7px; color: var(--mr-ink); font-size: 12px; }\n.mr-dag { display: flex; gap: 12px; margin: 12px 0; overflow-x: auto; padding-bottom: 6px; }\n.mr-dag-column { display: grid; align-content: start; gap: 8px; min-width: 240px; flex: 1 0 240px; }\n.mr-dag-step { color: var(--mr-muted); font-size: 10px; font-weight: 750; letter-spacing: .08em; }\n.mr-dag-node { padding: 11px 12px; border: 1px solid var(--mr-line); border-left-width: 4px; border-radius: 11px; background: #fafcff; }\n.mr-dag-node.ok { border-left-color: #2cba83; }\n.mr-dag-node.warn { border-left-color: #e9a640; }\n.mr-dag-node.error { border-left-color: #d95360; }\n.mr-dag-node.blocked { border-left-color: #8d9aaa; }\n.mr-dag-node.pending { border-left-color: var(--mr-accent); }\n.mr-dag-node-top { display: flex; justify-content: space-between; gap: 8px; align-items: center; }\n.mr-status-error { background: #fff0f1; color: #a52d3c; }\n.mr-status-warn { background: #fff6e6; color: #8a5a08; }\n.mr-status-ok { background: #e5f5eb; color: #175f3a; }\n.mr-fallback-error code { font-size: 10px; overflow-wrap: anywhere; }\n.mr-node-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }\n.mr-mini { min-height: 28px; padding: 3px 9px; font-size: 11px; }\n.mr-mini-select { min-height: 28px; width: auto; max-width: 180px; padding: 3px 7px; font-size: 11px; }\n.mr-run { margin-top: 14px; }\n.mr-table-wrap { overflow-x: auto; }\n.mr-table { width: 100%; border-collapse: collapse; font-size: 11px; line-height: 1.55; }\n.mr-table th, .mr-table td { padding: 8px 9px; border-bottom: 1px solid var(--mr-line); text-align: left; vertical-align: top; }\n.mr-table th { color: var(--mr-muted); font-weight: 700; }\n.mr-warn-text { color: #8a5a08; }\n@media (prefers-color-scheme: dark) {\n .mr-meter, .mr-dag-node { background: #222d3e; }\n .mr-status-error { background: #4a2730; color: #ffd4da; }\n .mr-status-warn { background: #4a3a1c; color: #ffe2a8; }\n .mr-status-ok { background: #193b2b; color: #b4f1cc; }\n .mr-warn-text { color: #ffd38a; }\n}\n/* Keyboard focus: every interactive control shows a visible ring. */\n.mr-workspace button:focus-visible, .mr-workspace select:focus-visible, .mr-workspace input:focus-visible, .mr-workspace textarea:focus-visible, .mr-workspace summary:focus-visible, .mr-workspace a:focus-visible { outline: 2px solid var(--mr-accent); outline-offset: 2px; }\n.mr-segment button:disabled { cursor: not-allowed; opacity: .55; }\n.mr-launch-workspace { flex: 1 1 320px; min-width: min(100%, 260px); }\n.mr-launch-preview { margin-top: 16px; padding: 14px; border: 1px solid var(--mr-line); border-radius: 12px; background: #f9fbfe; }\n.mr-launch-packages { margin: 12px 0 0; padding-left: 20px; font-size: 12px; line-height: 1.7; }\n.mr-confirm-box { margin-top: 12px; padding: 10px 14px; border: 1px solid rgba(217, 140, 30, .35); border-radius: 10px; background: #fff8ec; color: #6d4a12; font-size: 12px; line-height: 1.6; }\n.mr-confirm-box .mr-section-title { margin: 0 0 6px; }\n.mr-confirm-box ol { margin: 0; padding-left: 20px; }\n.mr-break { overflow-wrap: anywhere; }\n@media (prefers-color-scheme: dark) {\n .mr-launch-preview { background: rgba(255, 255, 255, .04); }\n .mr-confirm-box { background: rgba(217, 140, 30, .12); color: #f2d39b; }\n}\n";
1378
2176
 
1379
2177
  // .dsh-plugin/client/router-main.jsx
1380
- var money = (value) => value === null || value === void 0 ? "\u4EF7\u683C\u5F85\u914D\u7F6E" : `$${Number(value).toFixed(4)}`;
1381
- var text = (value) => typeof value === "string" ? value.trim() : "";
2178
+ var money2 = (value) => value === null || value === void 0 ? "\u4EF7\u683C\u5F85\u914D\u7F6E" : `$${Number(value).toFixed(4)}`;
2179
+ var text3 = (value) => typeof value === "string" ? value.trim() : "";
1382
2180
  function RouterPanelIcon({ size = 20, active = false }) {
1383
- return /* @__PURE__ */ import_react2.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true" }, /* @__PURE__ */ import_react2.default.createElement("path", { d: "M7 6.5h7M7 17.5h7M15 6.5v11", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }), /* @__PURE__ */ import_react2.default.createElement("circle", { cx: "5", cy: "6.5", r: "2", fill: active ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.6" }), /* @__PURE__ */ import_react2.default.createElement("circle", { cx: "5", cy: "17.5", r: "2", fill: active ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.6" }), /* @__PURE__ */ import_react2.default.createElement("circle", { cx: "17", cy: "12", r: "3", fill: active ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.7" }));
2181
+ return /* @__PURE__ */ import_react4.default.createElement("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true" }, /* @__PURE__ */ import_react4.default.createElement("path", { d: "M7 6.5h7M7 17.5h7M15 6.5v11", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round" }), /* @__PURE__ */ import_react4.default.createElement("circle", { cx: "5", cy: "6.5", r: "2", fill: active ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.6" }), /* @__PURE__ */ import_react4.default.createElement("circle", { cx: "5", cy: "17.5", r: "2", fill: active ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.6" }), /* @__PURE__ */ import_react4.default.createElement("circle", { cx: "17", cy: "12", r: "3", fill: active ? "currentColor" : "none", stroke: "currentColor", strokeWidth: "1.7" }));
1384
2182
  }
1385
2183
  function RouteList({ routes, query }) {
1386
2184
  const filtered = routes.filter((route) => {
1387
2185
  const haystack = `${route.providerName} ${route.provider} ${route.name} ${route.model}`.toLowerCase();
1388
2186
  return haystack.includes(query.toLowerCase());
1389
2187
  });
1390
- if (filtered.length === 0) return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-empty" }, routes.length === 0 ? "\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u5C1A\u65E0\u53EF\u89C4\u5212\u7684\u8DEF\u7EBF\u3002\u8BF7\u5148\u5728\u201C\u6A21\u578B\u201D\u9875\u5B8C\u6210\u914D\u7F6E\u3002" : "\u6CA1\u6709\u5339\u914D\u7684\u6A21\u578B\u3002");
1391
- return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-list", role: "list", "aria-label": "\u5B98\u65B9\u5DF2\u767B\u8BB0\u6A21\u578B\u8DEF\u7EBF" }, filtered.map((route) => /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-route", role: "listitem", key: `${route.provider}/${route.model}` }, /* @__PURE__ */ import_react2.default.createElement("div", { style: { minWidth: 0 } }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-route-name", title: route.name }, route.name), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-route-provider", title: `${route.provider}/${route.model}` }, route.provider, "/", route.model)), route.reasoningKnown && /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-pill" }, "\u63A8\u7406\u7B49\u7EA7"))));
2188
+ if (filtered.length === 0) return /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-empty" }, routes.length === 0 ? "\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u5C1A\u65E0\u53EF\u89C4\u5212\u7684\u8DEF\u7EBF\u3002\u8BF7\u5148\u5728\u201C\u6A21\u578B\u201D\u9875\u5B8C\u6210\u914D\u7F6E\u3002" : "\u6CA1\u6709\u5339\u914D\u7684\u6A21\u578B\u3002");
2189
+ return /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-list", role: "list", "aria-label": "\u5B98\u65B9\u5DF2\u767B\u8BB0\u6A21\u578B\u8DEF\u7EBF" }, filtered.map((route) => /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-route", role: "listitem", key: `${route.provider}/${route.model}` }, /* @__PURE__ */ import_react4.default.createElement("div", { style: { minWidth: 0 } }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-route-name", title: route.name }, route.name), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-route-provider", title: `${route.provider}/${route.model}` }, route.provider, "/", route.model)), route.reasoningKnown && /* @__PURE__ */ import_react4.default.createElement("span", { className: "mr-pill" }, "\u63A8\u7406\u7B49\u7EA7"))));
1392
2190
  }
1393
2191
  function ChannelBadge({ item }) {
1394
2192
  if (!item?.executionChannel) return null;
1395
2193
  const official = item.executionChannel === "official-cli";
1396
- return /* @__PURE__ */ import_react2.default.createElement("span", { className: official ? "mr-pill mr-pill-channel-ok" : "mr-pill", title: item.channelDetail ?? "" }, official ? `\u5B98\u65B9 CLI \xB7 ${item.channelLabel ?? item.channelTool}` : "\u6A21\u578B\u76EE\u5F55 API");
2194
+ return /* @__PURE__ */ import_react4.default.createElement("span", { className: official ? "mr-pill mr-pill-channel-ok" : "mr-pill", title: item.channelDetail ?? "" }, official ? `\u5B98\u65B9 CLI \xB7 ${item.channelLabel ?? item.channelTool}` : "\u6A21\u578B\u76EE\u5F55 API");
1397
2195
  }
1398
- function PlanResults({ plan }) {
2196
+ function PlanResults({ plan, ledger }) {
1399
2197
  const selected = plan.selected;
1400
- return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u8DEF\u7531\u5EFA\u8BAE" }, /* @__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" }, "\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react2.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_react2.default.createElement("div", { className: "mr-card-body" }, /* @__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" }, "\u63A8\u8350\u8DEF\u7EBF"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, selected ? `${selected.provider}/${selected.model}` : "\u6682\u65E0\u8DEF\u7EBF")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u4EFB\u52A1\u590D\u6742\u5EA6"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, { simple: "\u7B80\u5355", balanced: "\u4E2D\u7B49", complex: "\u590D\u6742" }[plan.complexity.band] || plan.complexity.band)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-label" }, "\u4F30\u7B97\u603B\u6210\u672C"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-metric-value" }, money(plan.estimatedCost)))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, "\u6267\u884C\u6E20\u9053"), /* @__PURE__ */ import_react2.default.createElement(ChannelBadge, { item: plan })), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, plan.reason), plan.optimization.budgetExceeded && /* @__PURE__ */ import_react2.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_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("h3", { className: "mr-section-title" }, "\u56E2\u961F\u5DE5\u4F5C\u5305"), /* @__PURE__ */ import_react2.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 === 0 ? /* @__PURE__ */ import_react2.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_react2.default.createElement("article", { className: "mr-package", key: item.id }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-package-top" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-package-name" }, index + 1, ". ", item.name), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-package-route" }, item.recommendedProvider, "/", item.recommendedModel)), item.objective && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u5177\u4F53\u76EE\u6807\uFF1A", item.objective), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, item.purpose, item.dependsOn.length > 0 ? ` \xB7 \u4F9D\u8D56\uFF1A${item.dependsOn.join("\u3001")}` : ""), /* @__PURE__ */ import_react2.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", money(item.estimatedCost)), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-package-copy" }, "\u9A8C\u6536\uFF1A", item.verificationChecklist.join("\uFF1B")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react2.default.createElement(ChannelBadge, { item }))))), plan.mode === "team" && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, plan.team.handoff), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-notice" }, plan.pricingNotice, " ", plan.qualityNotice, " ", plan.availabilityNotice, " ", plan.modalityNotice || "")));
2198
+ const budget = planBudget(ledger, plan.estimatedCost);
2199
+ return /* @__PURE__ */ import_react4.default.createElement("section", { className: "mr-card mr-results", "aria-label": "\u8DEF\u7531\u5EFA\u8BAE" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react4.default.createElement("div", null, /* @__PURE__ */ import_react4.default.createElement("h2", { className: "mr-card-title" }, "\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react4.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_react4.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-result-grid" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-metric-label" }, "\u63A8\u8350\u8DEF\u7EBF"), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-metric-value" }, selected ? `${selected.provider}/${selected.model}` : "\u6682\u65E0\u8DEF\u7EBF")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-metric-label" }, "\u4EFB\u52A1\u590D\u6742\u5EA6 \xB7 \u96BE\u5EA6\u5206"), /* @__PURE__ */ import_react4.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_react4.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-metric-label" }, "\u4F30\u7B97\u603B\u6210\u672C"), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-metric-value" }, money2(plan.estimatedCost))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-metric" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-metric-label" }, "\u8DEF\u7531\u65B9\u6848"), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-metric-value" }, ROUTING_PRESETS[plan.preset]?.label ?? "\u5747\u8861"))), budget?.exceeded && /* @__PURE__ */ import_react4.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_react4.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_react4.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_react4.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "mr-control-label" }, "\u6267\u884C\u6E20\u9053"), /* @__PURE__ */ import_react4.default.createElement(ChannelBadge, { item: plan })), /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption" }, plan.reason), plan.optimization.budgetExceeded && /* @__PURE__ */ import_react4.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_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("h3", { className: "mr-section-title" }, "\u56E2\u961F\u5DE5\u4F5C\u5305"), /* @__PURE__ */ import_react4.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_react4.default.createElement(DagView, { packages: plan.team.workPackages, label: "\u5DE5\u4F5C\u5305\u4F9D\u8D56\u56FE", renderNode: (item) => /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-package-route" }, item.recommendedProvider, "/", item.recommendedModel) }), plan.team.workPackages.length === 0 ? /* @__PURE__ */ import_react4.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_react4.default.createElement("article", { className: "mr-package", key: item.id }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-package-top" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-package-name" }, index + 1, ". ", item.name), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-package-route" }, item.recommendedProvider, "/", item.recommendedModel)), item.objective && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-package-copy" }, "\u5177\u4F53\u76EE\u6807\uFF1A", item.objective), /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-package-copy" }, item.purpose, item.dependsOn.length > 0 ? ` \xB7 \u4F9D\u8D56\uFF1A${item.dependsOn.join("\u3001")}` : ""), /* @__PURE__ */ import_react4.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_react4.default.createElement("p", { className: "mr-package-copy" }, "\u9A8C\u6536\uFF1A", item.verificationChecklist.join("\uFF1B")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-channel-line" }, /* @__PURE__ */ import_react4.default.createElement(ChannelBadge, { item }), item.loginRequired && /* @__PURE__ */ import_react4.default.createElement("span", { className: "mr-pill" }, "CLI \u672A\u767B\u5F55")), item.channelDetail && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-package-copy" }, "\u6E20\u9053\u8BF4\u660E\uFF1A", item.channelDetail)))), plan.routingBypassed && /* @__PURE__ */ import_react4.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_react4.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_react4.default.createElement("p", { className: "mr-caption" }, plan.team.handoff), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-notice" }, plan.pricingNotice, " ", plan.qualityNotice, " ", plan.availabilityNotice, " ", plan.modalityNotice || "")));
1401
2200
  }
1402
- var remoteError = (response, fallback) => text(response?.error?.message) || text(response?.value?.error) || fallback;
2201
+ var remoteError = (response, fallback) => text3(response?.error?.message) || text3(response?.value?.error) || fallback;
1403
2202
  function probeLabel(probe) {
1404
2203
  if (!probe) return "\u5C1A\u672A\u68C0\u6D4B";
1405
2204
  if (probe.installed) return `\u5DF2\u5B89\u88C5${probe.version ? ` \xB7 ${probe.version}` : ""}`;
@@ -1408,15 +2207,17 @@ function probeLabel(probe) {
1408
2207
  if (probe.status === "probe-failed") return "\u68C0\u6D4B\u5931\u8D25";
1409
2208
  return probe.detail || "\u672A\u5B89\u88C5";
1410
2209
  }
1411
- function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes }) {
1412
- const [probeState, setProbeState] = import_react2.default.useState({ status: "loading", probes: [], capabilities: [], readiness: [], error: "" });
1413
- const [jobs, setJobs] = import_react2.default.useState({});
1414
- const [rowErrors, setRowErrors] = import_react2.default.useState({});
1415
- const mounted = import_react2.default.useRef(false);
1416
- const request = import_react2.default.useRef(0);
1417
- const submitting = import_react2.default.useRef(/* @__PURE__ */ new Set());
1418
- const polling = import_react2.default.useRef(/* @__PURE__ */ new Set());
2210
+ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes, health, onRefreshHealth }) {
2211
+ const healthById = Object.fromEntries((health?.tools ?? []).map((item) => [item.id, item]));
2212
+ const [probeState, setProbeState] = import_react4.default.useState({ status: "loading", probes: [], capabilities: [], readiness: [], error: "" });
2213
+ const [jobs, setJobs] = import_react4.default.useState({});
2214
+ const [rowErrors, setRowErrors] = import_react4.default.useState({});
2215
+ const mounted = import_react4.default.useRef(false);
2216
+ const request = import_react4.default.useRef(0);
2217
+ const submitting = import_react4.default.useRef(/* @__PURE__ */ new Set());
2218
+ const polling = import_react4.default.useRef(/* @__PURE__ */ new Set());
1419
2219
  const refresh = async () => {
2220
+ onRefreshHealth?.();
1420
2221
  const current = ++request.current;
1421
2222
  setProbeState((previous) => ({ ...previous, status: "loading", error: "" }));
1422
2223
  try {
@@ -1431,11 +2232,11 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
1431
2232
  onProbes({ probes, capabilities, readiness });
1432
2233
  } catch (error) {
1433
2234
  if (!mounted.current || current !== request.current) return;
1434
- setProbeState({ status: "error", probes: [], capabilities: [], readiness: [], error: text(error?.message) || "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002" });
2235
+ setProbeState({ status: "error", probes: [], capabilities: [], readiness: [], error: text3(error?.message) || "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002" });
1435
2236
  onProbes({ probes: [], capabilities: [], readiness: [] });
1436
2237
  }
1437
2238
  };
1438
- import_react2.default.useEffect(() => {
2239
+ import_react4.default.useEffect(() => {
1439
2240
  mounted.current = true;
1440
2241
  void refresh();
1441
2242
  if (typeof officialToolInstallStatus === "function") {
@@ -1455,7 +2256,7 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
1455
2256
  request.current += 1;
1456
2257
  };
1457
2258
  }, []);
1458
- import_react2.default.useEffect(() => {
2259
+ import_react4.default.useEffect(() => {
1459
2260
  const active = Object.values(jobs).filter((job) => job?.status === "running").map((job) => job.tool);
1460
2261
  if (active.length === 0 || typeof officialToolInstallStatus !== "function") return void 0;
1461
2262
  let listening = true;
@@ -1472,7 +2273,7 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
1472
2273
  setRowErrors((previous) => ({ ...previous, [id2]: "" }));
1473
2274
  if (job.status !== "running") void refresh();
1474
2275
  } catch (error) {
1475
- if (listening && mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: text(error?.message) || "\u5B89\u88C5\u72B6\u6001\u8BFB\u53D6\u5931\u8D25\uFF0C\u5C06\u7EE7\u7EED\u91CD\u8BD5\u3002" }));
2276
+ if (listening && mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: text3(error?.message) || "\u5B89\u88C5\u72B6\u6001\u8BFB\u53D6\u5931\u8D25\uFF0C\u5C06\u7EE7\u7EED\u91CD\u8BD5\u3002" }));
1476
2277
  } finally {
1477
2278
  polling.current.delete(id2);
1478
2279
  }
@@ -1499,8 +2300,8 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
1499
2300
  setJobs((previous) => ({ ...previous, [id2]: response.value.job }));
1500
2301
  } catch (error) {
1501
2302
  if (mounted.current) {
1502
- setJobs((previous) => ({ ...previous, [id2]: { tool: id2, status: "failed", error: text(error?.message) || "\u5B89\u88C5\u542F\u52A8\u5931\u8D25\u3002" } }));
1503
- setRowErrors((previous) => ({ ...previous, [id2]: text(error?.message) || "\u5B89\u88C5\u542F\u52A8\u5931\u8D25\u3002" }));
2303
+ setJobs((previous) => ({ ...previous, [id2]: { tool: id2, status: "failed", error: text3(error?.message) || "\u5B89\u88C5\u542F\u52A8\u5931\u8D25\u3002" } }));
2304
+ setRowErrors((previous) => ({ ...previous, [id2]: text3(error?.message) || "\u5B89\u88C5\u542F\u52A8\u5931\u8D25\u3002" }));
1504
2305
  }
1505
2306
  } finally {
1506
2307
  submitting.current.delete(id2);
@@ -1516,15 +2317,15 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
1516
2317
  setJobs((previous) => ({ ...previous, [id2]: response.value.job }));
1517
2318
  if (response.value.job.status !== "running") void refresh();
1518
2319
  } catch (error) {
1519
- if (mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: text(error?.message) || "\u65E0\u6CD5\u53D6\u6D88\u5B89\u88C5\u3002" }));
2320
+ if (mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: text3(error?.message) || "\u65E0\u6CD5\u53D6\u6D88\u5B89\u88C5\u3002" }));
1520
2321
  }
1521
2322
  };
1522
2323
  const byId = Object.fromEntries(probeState.probes.map((probe) => [probe.id, probe]));
1523
2324
  const capabilitiesById = Object.fromEntries(probeState.capabilities.map((item) => [item.id, item]));
1524
2325
  const readinessById = Object.fromEntries(probeState.readiness.map((item) => [item.id, item]));
1525
- return /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card", "aria-label": "\u5B98\u65B9\u5DE5\u5177" }, /* @__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" }, "\u5B98\u65B9\u5DE5\u5177"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\uFF0C\u5E76\u4ECE\u56FA\u5B9A\u6CE8\u518C\u8868\u4E00\u952E\u4E0B\u8F7D\u5B89\u88C5\u3002ZCode \u4F1A\u6253\u5F00\u5B98\u65B9\u5B89\u88C5\u7A97\u53E3\u4F9B\u4F60\u9009\u62E9\u76EE\u5F55\uFF1B\u5B8C\u6210\u540E\u91CD\u65B0\u68C0\u6D4B\u7248\u672C\u3002")), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: probeState.status === "loading", onClick: () => {
2326
+ return /* @__PURE__ */ import_react4.default.createElement("section", { className: "mr-card", "aria-label": "\u5B98\u65B9\u5DE5\u5177" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react4.default.createElement("div", null, /* @__PURE__ */ import_react4.default.createElement("h2", { className: "mr-card-title" }, "\u5B98\u65B9\u5DE5\u5177 \xB7 \u4F53\u68C0"), /* @__PURE__ */ import_react4.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_react4.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: probeState.status === "loading", onClick: () => {
1526
2327
  void refresh();
1527
- } }, "\u91CD\u65B0\u68C0\u6D4B")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, probeState.status === "loading" && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u2026"), probeState.status === "error" && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, probeState.error), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-tools", role: "list", "aria-label": "\u5B98\u65B9\u5DE5\u5177\u6CE8\u518C\u8868" }, OFFICIAL_TOOLS.map((tool) => {
2328
+ } }, "\u91CD\u65B0\u4F53\u68C0")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-card-body" }, probeState.status === "loading" && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u2026"), probeState.status === "error" && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-error", role: "alert" }, probeState.error), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-tools", role: "list", "aria-label": "\u5B98\u65B9\u5DE5\u5177\u6CE8\u518C\u8868" }, OFFICIAL_TOOLS.map((tool) => {
1528
2329
  const command = installCommandLine(tool);
1529
2330
  const probe = byId[tool.id];
1530
2331
  const capability = capabilitiesById[tool.id];
@@ -1534,27 +2335,126 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
1534
2335
  const action = toolInstallAction({ tool, probe, readiness, job, probeStatus: probeState.status });
1535
2336
  const verified = job?.status === "succeeded" && job.postInstallProbe?.installed === true;
1536
2337
  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);
1537
- return /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-tool", role: "listitem", key: tool.id }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-tool-info" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-route-name", title: tool.purpose }, tool.label), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-route-provider" }, tool.vendor, " \xB7 ", tool.id), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-tool-status", role: "status" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: `mr-tool-dot ${running ? "running" : probe?.installed ? "installed" : "missing"}` }), status, tool.version ? ` \xB7 \u76EE\u6807 ${tool.version}` : ""), probe?.installed && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption mr-tool-detail" }, 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_react2.default.createElement("code", { className: "mr-tool-command" }, command) : /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", style: { margin: "6px 0 0" } }, tool.unsupportedReason), probe?.detail && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption mr-tool-detail" }, probe.detail), (rowErrors[tool.id] || job?.error) && /* @__PURE__ */ import_react2.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_react2.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react2.default.createElement("summary", null, "\u5B89\u88C5\u65E5\u5FD7"), /* @__PURE__ */ import_react2.default.createElement("pre", null, job.outputTail.slice(-6).join("\n")))), command && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-tool-actions" }, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-tool-button", type: "button", disabled: action.disabled, onClick: () => {
2338
+ return /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-tool", role: "listitem", key: tool.id }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-tool-info" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-route-name", title: tool.purpose }, tool.label), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-route-provider" }, tool.vendor, " \xB7 ", tool.id), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-tool-status", role: "status" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: `mr-tool-dot ${running ? "running" : probe?.installed ? "installed" : "missing"}` }), status, tool.version ? ` \xB7 \u76EE\u6807 ${tool.version}` : ""), /* @__PURE__ */ import_react4.default.createElement(ToolLoginLine, { entry: healthById[tool.id] }), probe?.installed && /* @__PURE__ */ import_react4.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_react4.default.createElement("code", { className: "mr-tool-command" }, command) : /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption", style: { margin: "6px 0 0" } }, tool.unsupportedReason), probe?.detail && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption mr-tool-detail" }, probe.detail), (rowErrors[tool.id] || job?.error) && /* @__PURE__ */ import_react4.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_react4.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react4.default.createElement("summary", null, "\u5B89\u88C5\u65E5\u5FD7"), /* @__PURE__ */ import_react4.default.createElement("pre", null, job.outputTail.slice(-6).join("\n")))), command && /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-tool-actions" }, /* @__PURE__ */ import_react4.default.createElement("button", { className: "mr-button mr-tool-button", type: "button", disabled: action.disabled, onClick: () => {
1538
2339
  void install(tool.id);
1539
- } }, action.label), running && /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary mr-tool-button", type: "button", disabled: job.cancelRequested, onClick: () => {
2340
+ } }, action.label), running && /* @__PURE__ */ import_react4.default.createElement("button", { className: "mr-button mr-button-secondary mr-tool-button", type: "button", disabled: job.cancelRequested, onClick: () => {
1540
2341
  void cancel(tool.id);
1541
2342
  } }, job.cancelRequested ? "\u6B63\u5728\u53D6\u6D88\u2026" : "\u53D6\u6D88\u5B89\u88C5")));
1542
- })), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", style: { marginTop: 12 } }, "\u5B89\u88C5\u7531 Host \u6309\u6CE8\u518C\u8868\u56FA\u5B9A\u6765\u6E90\u6267\u884C\uFF0C\u4E0D\u63A5\u53D7\u81EA\u5B9A\u4E49\u5305\u540D\uFF1B\u53EF\u70B9\u201C\u53D6\u6D88\u5B89\u88C5\u201D\u7EC8\u6B62\u4E0B\u8F7D\u4EFB\u52A1\uFF0C\u968F\u540E\u91CD\u65B0\u68C0\u6D4B\u5B9E\u9645\u7248\u672C\u3002ZCode \u5B89\u88C5\u5668\u542F\u52A8\u540E\u4ECD\u9700\u5728\u539F\u5382\u7A97\u53E3\u9009\u62E9\u76EE\u5F55\u5E76\u5B8C\u6210\u5B89\u88C5\u3002Agent \u4E5F\u53EF\u8C03\u7528 ", /* @__PURE__ */ import_react2.default.createElement("code", null, "model_router_tool_install"), "\uFF0C\u6216\u5728\u4F1A\u8BDD\u4F7F\u7528 ", /* @__PURE__ */ import_react2.default.createElement("code", null, "/tools"), "\u3002")));
1543
- }
1544
- function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, installOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus }) {
1545
- const [catalogState, setCatalogState] = import_react2.default.useState({ status: "loading", catalog: null, error: "" });
1546
- const [task, setTask] = import_react2.default.useState("");
1547
- const [mode, setMode] = import_react2.default.useState("single");
1548
- const [budget, setBudget] = import_react2.default.useState(() => String(settingsScope.getSnapshot().value?.budgetUsd ?? 0));
1549
- const [query, setQuery] = import_react2.default.useState("");
1550
- const [plan, setPlan] = import_react2.default.useState(null);
1551
- const [planError, setPlanError] = import_react2.default.useState("");
1552
- const [toolProbes, setToolProbes] = import_react2.default.useState(null);
1553
- const budgetEdited = import_react2.default.useRef(false);
1554
- const budgetValue = import_react2.default.useRef(budget);
1555
- const mounted = import_react2.default.useRef(false);
1556
- const catalogRequest = import_react2.default.useRef(0);
1557
- import_react2.default.useEffect(() => {
2343
+ })), /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption", style: { marginTop: 12 } }, "\u5B89\u88C5\u7531 Host \u6309\u6CE8\u518C\u8868\u56FA\u5B9A\u6765\u6E90\u6267\u884C\uFF0C\u4E0D\u63A5\u53D7\u81EA\u5B9A\u4E49\u5305\u540D\uFF1B\u53EF\u70B9\u201C\u53D6\u6D88\u5B89\u88C5\u201D\u7EC8\u6B62\u4E0B\u8F7D\u4EFB\u52A1\uFF0C\u968F\u540E\u91CD\u65B0\u68C0\u6D4B\u5B9E\u9645\u7248\u672C\u3002ZCode \u5B89\u88C5\u5668\u542F\u52A8\u540E\u4ECD\u9700\u5728\u539F\u5382\u7A97\u53E3\u9009\u62E9\u76EE\u5F55\u5E76\u5B8C\u6210\u5B89\u88C5\u3002Agent \u4E5F\u53EF\u8C03\u7528 ", /* @__PURE__ */ import_react4.default.createElement("code", null, "model_router_tool_install"), "\uFF0C\u6216\u5728\u4F1A\u8BDD\u4F7F\u7528 ", /* @__PURE__ */ import_react4.default.createElement("code", null, "/tools"), "\u3002")));
2344
+ }
2345
+ var HEADLESS_TOOLS = /* @__PURE__ */ new Set(["claude-code", "codex", "gemini"]);
2346
+ function useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries }) {
2347
+ const [health, setHealth] = import_react4.default.useState({ report: null, error: "", refreshing: false });
2348
+ const [ledger, setLedger] = import_react4.default.useState({ value: null, error: "" });
2349
+ const [boundaries, setBoundaries] = import_react4.default.useState({ value: null, error: "" });
2350
+ const [busy, setBusy] = import_react4.default.useState(false);
2351
+ const mounted = import_react4.default.useRef(true);
2352
+ import_react4.default.useEffect(() => () => {
2353
+ mounted.current = false;
2354
+ }, []);
2355
+ const call = async (operation, fallback) => {
2356
+ 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");
2357
+ return unwrapRemote(await operation(), fallback);
2358
+ };
2359
+ const refreshHealth = async (fresh) => {
2360
+ setHealth((previous) => ({ ...previous, refreshing: true, error: "" }));
2361
+ try {
2362
+ const report = await call(() => toolHealth(fresh === true), "\u4F53\u68C0\u5931\u8D25\u3002");
2363
+ if (mounted.current) setHealth({ report, error: "", refreshing: false });
2364
+ } catch (error) {
2365
+ if (mounted.current) setHealth((previous) => ({ ...previous, refreshing: false, error: text3(error?.message) || "\u4F53\u68C0\u5931\u8D25\u3002" }));
2366
+ }
2367
+ };
2368
+ const refreshLedger = async () => {
2369
+ try {
2370
+ const value = await call(loadLedger, "\u6267\u884C\u8BB0\u5F55\u8BFB\u53D6\u5931\u8D25\u3002");
2371
+ if (mounted.current) setLedger({ value, error: "" });
2372
+ } catch (error) {
2373
+ if (mounted.current) setLedger((previous) => ({ ...previous, error: text3(error?.message) || "\u6267\u884C\u8BB0\u5F55\u8BFB\u53D6\u5931\u8D25\u3002" }));
2374
+ }
2375
+ };
2376
+ const refreshBoundaries = async () => {
2377
+ try {
2378
+ const value = await call(loadBoundaries, "\u5B89\u5168\u8FB9\u754C\u8BFB\u53D6\u5931\u8D25\u3002");
2379
+ if (mounted.current) setBoundaries({ value, error: "" });
2380
+ } catch (error) {
2381
+ if (mounted.current) setBoundaries({ value: null, error: text3(error?.message) || "\u5B89\u5168\u8FB9\u754C\u8BFB\u53D6\u5931\u8D25\u3002" });
2382
+ }
2383
+ };
2384
+ const finishOnboarding = async () => {
2385
+ try {
2386
+ const onboarding = await call(completeOnboarding, "\u65E0\u6CD5\u4FDD\u5B58\u4F53\u68C0\u72B6\u6001\u3002");
2387
+ if (mounted.current) setHealth((previous) => ({ ...previous, report: { ...previous.report, onboarding } }));
2388
+ } catch (error) {
2389
+ if (mounted.current) setHealth((previous) => ({ ...previous, error: text3(error?.message) || "\u65E0\u6CD5\u4FDD\u5B58\u4F53\u68C0\u72B6\u6001\u3002" }));
2390
+ }
2391
+ };
2392
+ const rate = async (runId, packageId, rating) => {
2393
+ setBusy(true);
2394
+ try {
2395
+ await call(() => rateResult({ runId, packageId, rating }), "\u8BC4\u4EF7\u4FDD\u5B58\u5931\u8D25\u3002");
2396
+ await refreshLedger();
2397
+ } catch (error) {
2398
+ if (mounted.current) setLedger((previous) => ({ ...previous, error: text3(error?.message) || "\u8BC4\u4EF7\u4FDD\u5B58\u5931\u8D25\u3002" }));
2399
+ } finally {
2400
+ if (mounted.current) setBusy(false);
2401
+ }
2402
+ };
2403
+ const rerun = async (runId, packageId, override, choice = null) => {
2404
+ const run = ledger.value?.runs?.find((item2) => item2.id === runId);
2405
+ const item = run?.packages?.find((entry) => entry.id === packageId);
2406
+ const reasons = rerunConfirmations({ run, item, override, choice, ledger: ledger.value, health: health.report, toolFor: toolForProvider, headlessIds: HEADLESS_TOOLS });
2407
+ if (reasons.length && !window.confirm(reasons.length === 1 ? `${reasons[0].text}
2408
+ \u7EE7\u7EED\u5417\uFF1F` : `\u91CD\u8DD1\u524D\u9700\u8981\u786E\u8BA4\u4EE5\u4E0B ${reasons.length} \u9879\uFF1A
2409
+ ${reasons.map((entry, index) => `${index + 1}. ${entry.text}`).join("\n")}
2410
+ \u5168\u90E8\u786E\u8BA4\u5E76\u7EE7\u7EED\u5417\uFF1F`)) return;
2411
+ const codes = new Set(reasons.map((entry) => entry.code));
2412
+ setBusy(true);
2413
+ try {
2414
+ const request = {
2415
+ runId,
2416
+ packageId,
2417
+ ...override ? { provider: override.provider, model: override.model } : {},
2418
+ ...choice ? { subscriptionChoice: choice } : {},
2419
+ ...codes.has("over-budget") ? { confirmOverBudget: true } : {},
2420
+ ...codes.has("workspace-write") ? { confirmWrite: true } : {}
2421
+ };
2422
+ let result = await call(() => rerunStep(request), "\u91CD\u8DD1\u5931\u8D25\u3002");
2423
+ if (result?.paused && result.budget?.exceeded && !request.confirmOverBudget) {
2424
+ if (!window.confirm(`${result.budget?.message ?? "\u672C\u6B21\u91CD\u8DD1\u4F1A\u8D85\u51FA\u9884\u7B97\u3002"}
2425
+ \u4ECD\u8981\u7EE7\u7EED\u5417\uFF1F`)) return;
2426
+ result = await call(() => rerunStep({ ...request, confirmOverBudget: true }), "\u91CD\u8DD1\u5931\u8D25\u3002");
2427
+ }
2428
+ await refreshLedger();
2429
+ } catch (error) {
2430
+ if (mounted.current) setLedger((previous) => ({ ...previous, error: `${text3(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` }));
2431
+ } finally {
2432
+ if (mounted.current) setBusy(false);
2433
+ }
2434
+ };
2435
+ import_react4.default.useEffect(() => {
2436
+ void refreshHealth(false);
2437
+ void refreshLedger();
2438
+ void refreshBoundaries();
2439
+ }, []);
2440
+ return { health, ledger, boundaries, busy, refreshHealth, refreshLedger, refreshBoundaries, finishOnboarding, rate, rerun };
2441
+ }
2442
+ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, installOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries, previewRun, startRun }) {
2443
+ const workbench = useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries });
2444
+ const [catalogState, setCatalogState] = import_react4.default.useState({ status: "loading", catalog: null, error: "" });
2445
+ const [task, setTask] = import_react4.default.useState("");
2446
+ const [mode, setMode] = import_react4.default.useState("single");
2447
+ const [directKey, setDirectKey] = import_react4.default.useState("");
2448
+ const [budget, setBudget] = import_react4.default.useState(() => String(settingsScope.getSnapshot().value?.budgetUsd ?? 0));
2449
+ const [query, setQuery] = import_react4.default.useState("");
2450
+ const [plan, setPlan] = import_react4.default.useState(null);
2451
+ const [planError, setPlanError] = import_react4.default.useState("");
2452
+ const [toolProbes, setToolProbes] = import_react4.default.useState(null);
2453
+ const budgetEdited = import_react4.default.useRef(false);
2454
+ const budgetValue = import_react4.default.useRef(budget);
2455
+ const mounted = import_react4.default.useRef(false);
2456
+ const catalogRequest = import_react4.default.useRef(0);
2457
+ import_react4.default.useEffect(() => {
1558
2458
  const syncBudget = () => {
1559
2459
  if (budgetEdited.current) return;
1560
2460
  const next = String(settingsScope.getSnapshot().value?.budgetUsd ?? 0);
@@ -1568,15 +2468,15 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
1568
2468
  syncBudget();
1569
2469
  return settingsScope.subscribe(syncBudget);
1570
2470
  }, [settingsScope]);
1571
- import_react2.default.useEffect(() => {
2471
+ import_react4.default.useEffect(() => {
1572
2472
  mounted.current = true;
1573
2473
  const request = ++catalogRequest.current;
1574
2474
  Promise.resolve().then(loadCatalog).then((response) => {
1575
2475
  if (!mounted.current || request !== catalogRequest.current) return;
1576
2476
  if (response?.ok) setCatalogState({ status: "ready", catalog: response.value, error: "" });
1577
- else setCatalogState({ status: "error", catalog: null, error: text(response?.error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
2477
+ else setCatalogState({ status: "error", catalog: null, error: text3(response?.error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
1578
2478
  }).catch((error) => {
1579
- if (mounted.current && request === catalogRequest.current) setCatalogState({ status: "error", catalog: null, error: text(error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
2479
+ if (mounted.current && request === catalogRequest.current) setCatalogState({ status: "error", catalog: null, error: text3(error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
1580
2480
  });
1581
2481
  return () => {
1582
2482
  mounted.current = false;
@@ -1593,16 +2493,16 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
1593
2493
  const response = await loadCatalog();
1594
2494
  if (!mounted.current || request !== catalogRequest.current) return;
1595
2495
  if (response?.ok) setCatalogState({ status: "ready", catalog: response.value, error: "" });
1596
- else setCatalogState({ status: "error", catalog: null, error: text(response?.error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
2496
+ else setCatalogState({ status: "error", catalog: null, error: text3(response?.error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
1597
2497
  } catch (error) {
1598
- if (mounted.current && request === catalogRequest.current) setCatalogState({ status: "error", catalog: null, error: text(error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
2498
+ if (mounted.current && request === catalogRequest.current) setCatalogState({ status: "error", catalog: null, error: text3(error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
1599
2499
  }
1600
2500
  };
1601
2501
  const invalidatePlan = () => {
1602
2502
  setPlan(null);
1603
2503
  setPlanError("");
1604
2504
  };
1605
- const handleToolProbes = import_react2.default.useCallback((snapshot) => {
2505
+ const handleToolProbes = import_react4.default.useCallback((snapshot) => {
1606
2506
  setToolProbes(snapshot);
1607
2507
  setPlan(null);
1608
2508
  setPlanError("");
@@ -1610,37 +2510,131 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
1610
2510
  const generate = () => {
1611
2511
  setPlanError("");
1612
2512
  try {
1613
- if (!text(task)) throw new Error("\u8BF7\u5148\u63CF\u8FF0\u4EFB\u52A1\u3002");
2513
+ if (!text3(task)) throw new Error("\u8BF7\u5148\u63CF\u8FF0\u4EFB\u52A1\u3002");
1614
2514
  if (routes.length === 0) throw new Error("\u8BF7\u5148\u5728\u5B98\u65B9\u201C\u6A21\u578B\u201D\u9875\u914D\u7F6E\u81F3\u5C11\u4E00\u6761\u6A21\u578B\u8DEF\u7EBF\u3002");
1615
2515
  const parsedBudget = Number(budget);
1616
2516
  if (!Number.isFinite(parsedBudget) || parsedBudget < 0) throw new Error("\u9884\u7B97\u5FC5\u987B\u662F\u4E0D\u5C0F\u4E8E 0 \u7684\u6570\u5B57\u3002");
2517
+ const direct = mode === "direct" ? routes.find((route) => `${route.provider}/${route.model}` === directKey) ?? routes[0] : null;
2518
+ if (mode === "direct" && !direct) throw new Error("\u8BF7\u9009\u62E9\u8981\u76F4\u63A5\u4F7F\u7528\u7684\u6A21\u578B\u3002");
1617
2519
  setPlan(createWorkspacePlan(task, catalogState.catalog, {
1618
2520
  mode,
2521
+ ...direct ? { directProvider: direct.provider, directModel: direct.model } : {},
1619
2522
  budgetUsd: parsedBudget,
1620
2523
  modelProfilesJson: settingsScope.getSnapshot().value?.modelProfilesJson ?? "[]",
1621
2524
  installedToolIds: (toolProbes?.probes ?? []).filter((probe) => probe.installed).map((probe) => probe.id),
1622
- runnableToolIds: (toolProbes?.readiness ?? []).filter((item) => item.ready).map((item) => item.id)
2525
+ runnableToolIds: (toolProbes?.readiness ?? []).filter((item) => item.ready).map((item) => item.id),
2526
+ preset: settingsScope.getSnapshot().value?.routingPreset ?? "balanced",
2527
+ qualityBiases: workbench.ledger.value?.biases ?? null,
2528
+ loggedOutToolIds: (workbench.health.report?.tools ?? []).filter((item) => item.installed && item.login?.state === "logged-out").map((item) => item.id)
1623
2529
  }));
1624
2530
  } catch (error) {
1625
2531
  setPlan(null);
1626
- setPlanError(text(error?.message) || "\u65E0\u6CD5\u751F\u6210\u8DEF\u7531\u5EFA\u8BAE\u3002");
2532
+ setPlanError(text3(error?.message) || "\u65E0\u6CD5\u751F\u6210\u8DEF\u7531\u5EFA\u8BAE\u3002");
1627
2533
  }
1628
2534
  };
1629
- return /* @__PURE__ */ import_react2.default.createElement("main", { className: "mr-workspace" }, /* @__PURE__ */ import_react2.default.createElement("style", null, router_main_default), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-shell" }, /* @__PURE__ */ import_react2.default.createElement("header", { className: "mr-header" }, /* @__PURE__ */ import_react2.default.createElement("div", null, /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-eyebrow" }, "Model Router \xB7 DeepSeek Harness"), /* @__PURE__ */ import_react2.default.createElement("h1", { className: "mr-title" }, "\u6A21\u578B\u8DEF\u7531\u5DE5\u4F5C\u53F0"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-subtitle" }, "\u67E5\u770B\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\uFF0C\u4E3A\u4EFB\u52A1\u751F\u6210\u8DEF\u7EBF\u5EFA\u8BAE\u4E0E\u56E2\u961F\u5DE5\u4F5C\u5305\u3002\u4E3B\u4F1A\u8BDD\u6A21\u578B\u4ECD\u7531\u5B98\u65B9\u9009\u62E9\u5668\u7BA1\u7406\u3002")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-status" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: `mr-status-dot ${catalogState.status === "loading" ? "loading" : catalogState.status === "error" ? "error" : ""}` }), catalogState.status === "ready" ? `${providerCount} \u4E2A\u4F9B\u5E94\u5546 \xB7 ${routes.length} \u6761\u8DEF\u7EBF` : catalogState.status === "loading" ? "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u76EE\u5F55" : "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-grid" }, /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card", "aria-label": "\u4EFB\u52A1\u89C4\u5212" }, /* @__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" }, "\u4EFB\u52A1\u89C4\u5212"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u89C4\u5212\u5728\u672C\u673A\u5B8C\u6210\uFF0C\u4E0D\u4F1A\u542F\u52A8\u6A21\u578B\u6216\u56E2\u961F\u4EFB\u52A1\u3002"))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-label", htmlFor: "mr-task" }, "\u4EFB\u52A1\u63CF\u8FF0"), /* @__PURE__ */ import_react2.default.createElement("textarea", { className: "mr-textarea", id: "mr-task", value: task, onChange: (event) => {
2535
+ return /* @__PURE__ */ import_react4.default.createElement("main", { className: "mr-workspace" }, /* @__PURE__ */ import_react4.default.createElement("style", null, router_main_default), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-shell" }, /* @__PURE__ */ import_react4.default.createElement("header", { className: "mr-header" }, /* @__PURE__ */ import_react4.default.createElement("div", null, /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-eyebrow" }, "Model Router \xB7 DeepSeek Harness"), /* @__PURE__ */ import_react4.default.createElement("h1", { className: "mr-title" }, "\u6A21\u578B\u8DEF\u7531\u5DE5\u4F5C\u53F0"), /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-subtitle" }, "\u67E5\u770B\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\uFF0C\u4E3A\u4EFB\u52A1\u751F\u6210\u8DEF\u7EBF\u5EFA\u8BAE\u4E0E\u56E2\u961F\u5DE5\u4F5C\u5305\u3002\u4E3B\u4F1A\u8BDD\u6A21\u578B\u4ECD\u7531\u5B98\u65B9\u9009\u62E9\u5668\u7BA1\u7406\u3002")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-status" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: `mr-status-dot ${catalogState.status === "loading" ? "loading" : catalogState.status === "error" ? "error" : ""}` }), catalogState.status === "ready" ? `${providerCount} \u4E2A\u4F9B\u5E94\u5546 \xB7 ${routes.length} \u6761\u8DEF\u7EBF` : catalogState.status === "loading" ? "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u76EE\u5F55" : "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25")), (workbench.health.report?.notices ?? []).map((notice) => /* @__PURE__ */ import_react4.default.createElement("div", { key: `${notice.kind}-${notice.at}`, className: "mr-error", role: "alert" }, notice.message)), workbench.health.report && !workbench.health.report.onboarding?.completedAt && /* @__PURE__ */ import_react4.default.createElement(
2536
+ OnboardingBanner,
2537
+ {
2538
+ health: workbench.health.report,
2539
+ error: workbench.health.error,
2540
+ refreshing: workbench.health.refreshing,
2541
+ onRefresh: () => {
2542
+ void workbench.refreshHealth(true);
2543
+ },
2544
+ onDone: () => {
2545
+ void workbench.finishOnboarding();
2546
+ }
2547
+ }
2548
+ ), /* @__PURE__ */ import_react4.default.createElement(
2549
+ CostControlCard,
2550
+ {
2551
+ ledger: workbench.ledger.value,
2552
+ error: workbench.ledger.error && !workbench.ledger.value ? workbench.ledger.error : "",
2553
+ settingsScope,
2554
+ onChanged: () => {
2555
+ invalidatePlan();
2556
+ void workbench.refreshLedger();
2557
+ }
2558
+ }
2559
+ ), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-grid" }, /* @__PURE__ */ import_react4.default.createElement("section", { className: "mr-card", "aria-label": "\u4EFB\u52A1\u89C4\u5212" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react4.default.createElement("div", null, /* @__PURE__ */ import_react4.default.createElement("h2", { className: "mr-card-title" }, "\u4EFB\u52A1\u89C4\u5212"), /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-card-copy" }, "\u201C\u751F\u6210\u8DEF\u7531\u5EFA\u8BAE\u201D\u5728\u672C\u673A\u5B8C\u6210\uFF0C\u4E0D\u4F1A\u542F\u52A8\u6A21\u578B\uFF1B\u8981\u5B9E\u9645\u6267\u884C\uFF0C\u8BF7\u5728\u4E0B\u65B9\u201C\u5728\u5DE5\u4F5C\u53F0\u6267\u884C\u201D\u4E2D\u9884\u89C8\u5E76\u786E\u8BA4\u3002"))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react4.default.createElement("label", { className: "mr-label", htmlFor: "mr-task" }, "\u4EFB\u52A1\u63CF\u8FF0"), /* @__PURE__ */ import_react4.default.createElement("textarea", { className: "mr-textarea", id: "mr-task", value: task, onChange: (event) => {
1630
2560
  setTask(event.target.value);
1631
2561
  invalidatePlan();
1632
- }, placeholder: "\u4F8B\u5982\uFF1A\u5206\u6790\u9879\u76EE\u67B6\u6784\uFF0C\u5206\u5DE5\u4FEE\u590D\u5173\u952E\u95EE\u9898\uFF0C\u5E76\u7ED9\u51FA\u9A8C\u6536\u6E05\u5355" }), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-control-label" }, "\u89C4\u5212\u6A21\u5F0F"), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u89C4\u5212\u6A21\u5F0F" }, /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", "aria-pressed": mode === "single", onClick: () => {
2562
+ }, placeholder: "\u4F8B\u5982\uFF1A\u5206\u6790\u9879\u76EE\u67B6\u6784\uFF0C\u5206\u5DE5\u4FEE\u590D\u5173\u952E\u95EE\u9898\uFF0C\u5E76\u7ED9\u51FA\u9A8C\u6536\u6E05\u5355" }), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "mr-control-label" }, "\u89C4\u5212\u6A21\u5F0F"), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-segment", role: "group", "aria-label": "\u89C4\u5212\u6A21\u5F0F" }, /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", "aria-pressed": mode === "single", onClick: () => {
1633
2563
  setMode("single");
1634
2564
  invalidatePlan();
1635
- } }, "\u5355\u4EFB\u52A1"), /* @__PURE__ */ import_react2.default.createElement("button", { type: "button", "aria-pressed": mode === "team", onClick: () => {
2565
+ } }, "\u5355\u4EFB\u52A1"), /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", "aria-pressed": mode === "team", onClick: () => {
1636
2566
  setMode("team");
1637
2567
  invalidatePlan();
1638
- } }, "\u56E2\u961F\u5206\u5DE5"))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-control-group mr-budget" }, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-budget" }, "\u672C\u6B21\u4F30\u7B97\u9884\u7B97\uFF08USD\uFF09"), /* @__PURE__ */ import_react2.default.createElement("input", { className: "mr-input", id: "mr-budget", type: "number", min: "0", step: "0.01", value: budget, onChange: (event) => {
2568
+ } }, "\u56E2\u961F\u5206\u5DE5"), /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", "aria-pressed": mode === "direct", onClick: () => {
2569
+ setMode("direct");
2570
+ invalidatePlan();
2571
+ } }, "\u6307\u5B9A\u6A21\u578B"))), mode === "direct" && /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-control-group mr-direct" }, /* @__PURE__ */ import_react4.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-direct-model" }, "\u76F4\u63A5\u4F7F\u7528"), /* @__PURE__ */ import_react4.default.createElement("select", { className: "mr-input", id: "mr-direct-model", value: directKey || (routes[0] ? `${routes[0].provider}/${routes[0].model}` : ""), onChange: (event) => {
2572
+ setDirectKey(event.target.value);
2573
+ invalidatePlan();
2574
+ } }, routes.map((route) => /* @__PURE__ */ import_react4.default.createElement("option", { key: `${route.provider}/${route.model}`, value: `${route.provider}/${route.model}` }, route.provider, "/", route.model)))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-control-group mr-budget" }, /* @__PURE__ */ import_react4.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-budget" }, "\u672C\u6B21\u4F30\u7B97\u9884\u7B97\uFF08USD\uFF09"), /* @__PURE__ */ import_react4.default.createElement("input", { className: "mr-input", id: "mr-budget", type: "number", min: "0", step: "0.01", value: budget, onChange: (event) => {
1639
2575
  budgetEdited.current = true;
1640
2576
  budgetValue.current = event.target.value;
1641
2577
  setBudget(event.target.value);
1642
2578
  invalidatePlan();
1643
- } }))), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button", type: "button", disabled: catalogState.status !== "ready" || routes.length === 0 || toolProbes === null, onClick: generate }, "\u751F\u6210\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react2.default.createElement("span", { className: "mr-caption" }, toolProbes === null ? "\u6B63\u5728\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u2026" : "0 \u8868\u793A\u4E0D\u9650\u5236\u672C\u6B21\u5EFA\u8BAE\uFF1B\u4E0D\u4F1A\u8BBE\u7F6E\u771F\u5B9E\u652F\u51FA\u4E0A\u9650\u3002")), planError && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-error", role: "alert" }, planError))), /* @__PURE__ */ import_react2.default.createElement("section", { className: "mr-card", "aria-label": "\u6A21\u578B\u76EE\u5F55" }, /* @__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" }, "\u6A21\u578B\u76EE\u5F55"), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-card-copy" }, "\u53EA\u663E\u793A\u5B98\u65B9\u5DF2\u767B\u8BB0\u7684 provider/model\uFF0C\u4E0D\u8BFB\u53D6 API Key\u3002")), /* @__PURE__ */ import_react2.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: refresh }, "\u5237\u65B0")), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-card-body" }, catalogState.status === "error" && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-error", role: "alert" }, catalogState.error), catalogState.status === "loading" && /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-empty" }, "\u6B63\u5728\u52A0\u8F7D\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u2026"), catalogState.status === "ready" && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement("label", { className: "mr-label", htmlFor: "mr-model-search" }, "\u641C\u7D22\u8DEF\u7EBF"), /* @__PURE__ */ import_react2.default.createElement("input", { className: "mr-input mr-search", id: "mr-model-search", value: query, onChange: (event) => setQuery(event.target.value), placeholder: "\u6A21\u578B\u6216\u4F9B\u5E94\u5546" }), /* @__PURE__ */ import_react2.default.createElement(RouteList, { routes, query }), catalogState.catalog?.failures?.length > 0 && /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption" }, catalogState.catalog.failures.length, " \u4E2A\u4F9B\u5E94\u5546\u7684\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u5728\u5B98\u65B9\u6A21\u578B\u9875\u68C0\u67E5\u914D\u7F6E\u3002")), /* @__PURE__ */ import_react2.default.createElement("p", { className: "mr-caption", style: { marginTop: 13 } }, "\u76EE\u5F55\u767B\u8BB0\u4E0D\u4EE3\u8868\u51ED\u636E\u6216\u7F51\u7EDC\u5F53\u524D\u53EF\u7528\uFF1B\u56FE\u50CF\u80FD\u529B\u9700\u8981\u5728\u5B9E\u9645\u4F7F\u7528\u524D\u6838\u5BF9\u3002")))), /* @__PURE__ */ import_react2.default.createElement(ModelProfileEditor, { routes, settingsScope, onSaved: invalidatePlan }), plan && /* @__PURE__ */ import_react2.default.createElement(PlanResults, { plan }), /* @__PURE__ */ import_react2.default.createElement(OfficialToolsCard, { listOfficialTools, installOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes: handleToolProbes }), /* @__PURE__ */ import_react2.default.createElement("div", { className: "mr-notice" }, "\u5B9E\u9645\u8C03\u7528\u8BF7\u5728\u5B98\u65B9\u4F1A\u8BDD\u4E2D\u4F7F\u7528 ", /* @__PURE__ */ import_react2.default.createElement("code", null, "model_router_consult"), "\u3001", /* @__PURE__ */ import_react2.default.createElement("code", null, "model_router_tool_run"), " \u6216 ", /* @__PURE__ */ import_react2.default.createElement("code", null, "model_router_team_execute"), "\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")));
2579
+ } }))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react4.default.createElement("button", { className: "mr-button", type: "button", disabled: catalogState.status !== "ready" || routes.length === 0 || toolProbes === null, onClick: generate }, "\u751F\u6210\u8DEF\u7531\u5EFA\u8BAE"), /* @__PURE__ */ import_react4.default.createElement("span", { className: "mr-caption" }, toolProbes === null ? "\u6B63\u5728\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u2026" : "0 \u8868\u793A\u4E0D\u9650\u5236\u672C\u6B21\u5EFA\u8BAE\uFF1B\u4E0D\u4F1A\u8BBE\u7F6E\u771F\u5B9E\u652F\u51FA\u4E0A\u9650\u3002")), planError && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-error", role: "alert" }, planError))), /* @__PURE__ */ import_react4.default.createElement("section", { className: "mr-card", "aria-label": "\u6A21\u578B\u76EE\u5F55" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react4.default.createElement("div", null, /* @__PURE__ */ import_react4.default.createElement("h2", { className: "mr-card-title" }, "\u6A21\u578B\u76EE\u5F55"), /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-card-copy" }, "\u53EA\u663E\u793A\u5B98\u65B9\u5DF2\u767B\u8BB0\u7684 provider/model\uFF0C\u4E0D\u8BFB\u53D6 API Key\u3002")), /* @__PURE__ */ import_react4.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: refresh }, "\u5237\u65B0")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-card-body" }, catalogState.status === "error" && /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-error", role: "alert" }, catalogState.error), catalogState.status === "loading" && /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-empty" }, "\u6B63\u5728\u52A0\u8F7D\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u2026"), catalogState.status === "ready" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("label", { className: "mr-label", htmlFor: "mr-model-search" }, "\u641C\u7D22\u8DEF\u7EBF"), /* @__PURE__ */ import_react4.default.createElement("input", { className: "mr-input mr-search", id: "mr-model-search", value: query, onChange: (event) => setQuery(event.target.value), placeholder: "\u6A21\u578B\u6216\u4F9B\u5E94\u5546" }), /* @__PURE__ */ import_react4.default.createElement(RouteList, { routes, query }), catalogState.catalog?.failures?.length > 0 && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption" }, catalogState.catalog.failures.length, " \u4E2A\u4F9B\u5E94\u5546\u7684\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u5728\u5B98\u65B9\u6A21\u578B\u9875\u68C0\u67E5\u914D\u7F6E\u3002")), /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption", style: { marginTop: 13 } }, "\u76EE\u5F55\u767B\u8BB0\u4E0D\u4EE3\u8868\u51ED\u636E\u6216\u7F51\u7EDC\u5F53\u524D\u53EF\u7528\uFF1B\u56FE\u50CF\u80FD\u529B\u9700\u8981\u5728\u5B9E\u9645\u4F7F\u7528\u524D\u6838\u5BF9\u3002")))), /* @__PURE__ */ import_react4.default.createElement(ModelProfileEditor, { routes, settingsScope, onSaved: invalidatePlan }), plan && /* @__PURE__ */ import_react4.default.createElement(PlanResults, { plan, ledger: workbench.ledger.value }), /* @__PURE__ */ import_react4.default.createElement(
2580
+ RunLauncher,
2581
+ {
2582
+ task,
2583
+ mode,
2584
+ budgetUsd: budget,
2585
+ ledger: workbench.ledger.value,
2586
+ previewRun,
2587
+ startRun,
2588
+ directRoute: mode === "direct" ? routes.find((route) => `${route.provider}/${route.model}` === directKey) ?? routes[0] ?? null : null,
2589
+ defaultPreset: settingsScope.getSnapshot().value?.routingPreset ?? "balanced",
2590
+ disabledReason: catalogState.status === "loading" ? "\u6B63\u5728\u8BFB\u53D6\u6A21\u578B\u76EE\u5F55\u2026" : catalogState.status === "error" ? "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25\uFF0C\u8BF7\u5728\u201C\u6A21\u578B\u76EE\u5F55\u201D\u5361\u7247\u70B9\u201C\u5237\u65B0\u201D\u3002" : routes.length === 0 ? "\u8BF7\u5148\u5728\u5B98\u65B9\u201C\u6A21\u578B\u201D\u9875\u914D\u7F6E\u81F3\u5C11\u4E00\u6761\u6A21\u578B\u8DEF\u7EBF\u3002" : "",
2591
+ onStarted: () => {
2592
+ void workbench.refreshLedger();
2593
+ }
2594
+ }
2595
+ ), /* @__PURE__ */ import_react4.default.createElement(
2596
+ RunHistoryCard,
2597
+ {
2598
+ ledger: workbench.ledger.value,
2599
+ routes,
2600
+ busy: workbench.busy,
2601
+ error: workbench.ledger.error,
2602
+ onRefresh: () => {
2603
+ void workbench.refreshLedger();
2604
+ },
2605
+ onRate: (runId, packageId, rating) => {
2606
+ void workbench.rate(runId, packageId, rating);
2607
+ },
2608
+ onRerun: (runId, packageId, override, choice) => {
2609
+ void workbench.rerun(runId, packageId, override, choice);
2610
+ }
2611
+ }
2612
+ ), /* @__PURE__ */ import_react4.default.createElement(
2613
+ OfficialToolsCard,
2614
+ {
2615
+ listOfficialTools,
2616
+ installOfficialTool,
2617
+ cancelOfficialToolInstall,
2618
+ officialToolInstallStatus,
2619
+ onProbes: handleToolProbes,
2620
+ health: workbench.health.report,
2621
+ onRefreshHealth: () => {
2622
+ void workbench.refreshHealth(true);
2623
+ }
2624
+ }
2625
+ ), /* @__PURE__ */ import_react4.default.createElement(
2626
+ BillingCard,
2627
+ {
2628
+ billing: workbench.health.report?.billing ?? null,
2629
+ error: workbench.health.report ? "" : workbench.health.error,
2630
+ refreshing: workbench.health.refreshing,
2631
+ onRefresh: () => {
2632
+ void workbench.refreshHealth(true);
2633
+ }
2634
+ }
2635
+ ), /* @__PURE__ */ import_react4.default.createElement(SecurityCard, { data: workbench.boundaries.value, error: workbench.boundaries.error, onRefresh: () => {
2636
+ void workbench.refreshBoundaries();
2637
+ } }), /* @__PURE__ */ import_react4.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_react4.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_react4.default.createElement("code", null, "model_router_consult"), "\u3001", /* @__PURE__ */ import_react4.default.createElement("code", null, "model_router_tool_run"), " \u6216 ", /* @__PURE__ */ import_react4.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")));
1644
2638
  }
1645
2639
 
1646
2640
  // .dsh-plugin/shared/official-tools-remote.mjs
@@ -1680,6 +2674,69 @@ var statusResultCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#OfficialTo
1680
2674
  }
1681
2675
  return result;
1682
2676
  });
2677
+ var anyObjectCodec = (name) => strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#${name}`, (value) => plainObject(value, name));
2678
+ var freshCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#HealthFresh`, (value) => {
2679
+ if (typeof value !== "boolean") throw new TypeError("fresh must be a boolean");
2680
+ return value;
2681
+ });
2682
+ var idText = (value, subject) => {
2683
+ if (typeof value !== "string" || !/^[A-Za-z0-9._:-]{1,80}$/.test(value)) throw new TypeError(`${subject} must be a short id`);
2684
+ return value;
2685
+ };
2686
+ var optionalRouteText = (value, subject) => {
2687
+ if (value === void 0 || value === null || value === "") return void 0;
2688
+ if (typeof value !== "string" || value.length > 240 || value.includes("\0")) throw new TypeError(`${subject} is invalid`);
2689
+ return value;
2690
+ };
2691
+ var rateRequestCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#RateRequest`, (value) => {
2692
+ const request = plainObject(value, "rate request");
2693
+ if (!["up", "down", "clear"].includes(request.rating)) throw new TypeError("rating must be up, down or clear");
2694
+ return { runId: idText(request.runId, "runId"), packageId: idText(request.packageId, "packageId"), rating: request.rating };
2695
+ });
2696
+ var rerunRequestCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#RerunRequest`, (value) => {
2697
+ const request = plainObject(value, "rerun request");
2698
+ const provider = optionalRouteText(request.provider, "provider");
2699
+ const model = optionalRouteText(request.model, "model");
2700
+ if (Boolean(provider) !== Boolean(model)) throw new TypeError("provider and model must be supplied together");
2701
+ return {
2702
+ runId: idText(request.runId, "runId"),
2703
+ packageId: idText(request.packageId, "packageId"),
2704
+ ...provider ? { provider, model } : {},
2705
+ confirmOverBudget: request.confirmOverBudget === true,
2706
+ confirmWrite: request.confirmWrite === true,
2707
+ ...["api", "subscription", "cancel"].includes(request.subscriptionChoice) ? { subscriptionChoice: request.subscriptionChoice } : {}
2708
+ };
2709
+ });
2710
+ var RUN_CONFIRMATION_CODES = Object.freeze(["workspace-write", "rerun-write", "subscription-api", "over-budget", "unsandboxed"]);
2711
+ var MAX_RUN_TASK_CHARS = 2e5;
2712
+ function parseRunRequest(value) {
2713
+ const request = plainObject(value, "run request");
2714
+ if (typeof request.task !== "string" || !request.task.trim() || request.task.length > MAX_RUN_TASK_CHARS) {
2715
+ throw new TypeError("task must be a non-empty string");
2716
+ }
2717
+ const provider = optionalRouteText(request.provider, "provider");
2718
+ const model = optionalRouteText(request.model, "model");
2719
+ if (Boolean(provider) !== Boolean(model)) throw new TypeError("provider and model must be supplied together");
2720
+ const workspace = request.workspace === void 0 || request.workspace === null || request.workspace === "" ? void 0 : request.workspace;
2721
+ if (workspace !== void 0 && (typeof workspace !== "string" || workspace.length > 4096 || workspace.includes("\0"))) throw new TypeError("workspace is invalid");
2722
+ if (request.budgetUsd !== void 0 && (typeof request.budgetUsd !== "number" || !Number.isFinite(request.budgetUsd) || request.budgetUsd < 0)) {
2723
+ throw new TypeError("budgetUsd must be a non-negative number");
2724
+ }
2725
+ const confirmed = Array.isArray(request.confirmedReasons) ? request.confirmedReasons : [];
2726
+ if (confirmed.length > RUN_CONFIRMATION_CODES.length || confirmed.some((code) => !RUN_CONFIRMATION_CODES.includes(code))) {
2727
+ throw new TypeError("confirmedReasons contains an unknown reason");
2728
+ }
2729
+ return {
2730
+ task: request.task,
2731
+ ...provider ? { provider, model } : {},
2732
+ ...["single", "team"].includes(request.planMode) ? { planMode: request.planMode } : {},
2733
+ ...["economy", "balanced", "quality"].includes(request.preset) ? { preset: request.preset } : {},
2734
+ ...request.budgetUsd !== void 0 ? { budgetUsd: request.budgetUsd } : {},
2735
+ ...workspace ? { workspace } : {},
2736
+ confirmedReasons: [...new Set(confirmed)]
2737
+ };
2738
+ }
2739
+ var runRequestCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#RunRequest`, parseRunRequest);
1683
2740
  function descriptor(method, parameters, result) {
1684
2741
  return Object.freeze({
1685
2742
  id: `${OFFICIAL_TOOLS_REMOTE_PACKAGE}#${OFFICIAL_TOOLS_REMOTE_NAMESPACE}/${method}`,
@@ -1697,11 +2754,22 @@ var toolIdParameter = Object.freeze({
1697
2754
  source: "json",
1698
2755
  codec: toolIdCodec
1699
2756
  });
2757
+ var jsonParameter = (name, codec) => Object.freeze({ name, wire: name, source: "json", codec });
1700
2758
  var OFFICIAL_TOOLS_REMOTE_DESCRIPTORS = Object.freeze([
1701
2759
  descriptor("list", [], listResultCodec),
1702
2760
  descriptor("installTool", [toolIdParameter], installResultCodec),
1703
2761
  descriptor("cancel", [toolIdParameter], installResultCodec),
1704
- descriptor("status", [toolIdParameter], statusResultCodec)
2762
+ descriptor("status", [toolIdParameter], statusResultCodec),
2763
+ // Workbench: onboarding health check, run ledger, ratings, step retry, security boundaries.
2764
+ descriptor("health", [jsonParameter("fresh", freshCodec)], anyObjectCodec("HealthReport")),
2765
+ descriptor("completeOnboarding", [], anyObjectCodec("OnboardingState")),
2766
+ descriptor("ledger", [], anyObjectCodec("RunLedger")),
2767
+ descriptor("rateResult", [jsonParameter("request", rateRequestCodec)], anyObjectCodec("RateResult")),
2768
+ descriptor("rerunStep", [jsonParameter("request", rerunRequestCodec)], anyObjectCodec("RerunResult")),
2769
+ descriptor("boundaries", [], anyObjectCodec("SecurityBoundaries")),
2770
+ // Workbench "start a run": plan preview with cost estimate and confirmation reasons, then execute.
2771
+ descriptor("previewRun", [jsonParameter("request", runRequestCodec)], anyObjectCodec("RunPreview")),
2772
+ descriptor("startRun", [jsonParameter("request", runRequestCodec)], anyObjectCodec("RunStarted"))
1705
2773
  ]);
1706
2774
  var OFFICIAL_TOOLS_CLIENT_REMOTE = Object.freeze({
1707
2775
  package: OFFICIAL_TOOLS_REMOTE_PACKAGE,
@@ -1745,8 +2813,8 @@ function boundedNumberField(field2, { minimum = 0, maximum = Number.MAX_SAFE_INT
1745
2813
  const numeric = (0, import_dsh_client_ui_primitives.settingsNumberField)(field2);
1746
2814
  return {
1747
2815
  ...numeric,
1748
- parse: (text2) => {
1749
- const write = numeric.parse(text2);
2816
+ parse: (text4) => {
2817
+ const write = numeric.parse(text4);
1750
2818
  if (write?.kind !== "set") return write;
1751
2819
  const value = write.value;
1752
2820
  if (typeof value !== "number" || value < minimum || value > maximum) return void 0;
@@ -1759,13 +2827,29 @@ function modelProfilesField() {
1759
2827
  const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("modelProfilesJson");
1760
2828
  return {
1761
2829
  ...field2,
1762
- parse: (text2) => {
2830
+ parse: (text4) => {
2831
+ try {
2832
+ parseModelProfilesJson(text4);
2833
+ return field2.parse(text4);
2834
+ } catch {
2835
+ return void 0;
2836
+ }
2837
+ }
2838
+ };
2839
+ }
2840
+ function quotaPatternsField() {
2841
+ const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("quotaPatternsJson");
2842
+ return {
2843
+ ...field2,
2844
+ parse: (text4) => {
2845
+ const raw = String(text4 ?? "").trim() || "{}";
1763
2846
  try {
1764
- parseModelProfilesJson(text2);
1765
- return field2.parse(text2);
2847
+ const value = JSON.parse(raw);
2848
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1766
2849
  } catch {
1767
2850
  return void 0;
1768
2851
  }
2852
+ return parseQuotaPatterns(raw).errors.length ? void 0 : field2.parse(text4);
1769
2853
  }
1770
2854
  };
1771
2855
  }
@@ -1774,13 +2858,23 @@ var RouterSettingsCardController = class {
1774
2858
  this.form = new import_dsh_client_ui_primitives.SettingsFormModel(scope, [
1775
2859
  boundedNumberField("budgetUsd", { minimum: 0 }),
1776
2860
  boundedNumberField("maxConsultOutputChars", { minimum: 500, maximum: 5e4, integer: true }),
1777
- modelProfilesField()
2861
+ boundedNumberField("dailyBudgetUsd", { minimum: 0, maximum: 1e6 }),
2862
+ boundedNumberField("monthlyBudgetUsd", { minimum: 0, maximum: 1e6 }),
2863
+ boundedNumberField("reviewSampleRate", { minimum: 0, maximum: 1 }),
2864
+ boundedNumberField("subscriptionCooldownMinutes", { minimum: 1, maximum: 10080, integer: true }),
2865
+ modelProfilesField(),
2866
+ quotaPatternsField()
1778
2867
  ]);
1779
2868
  this.store = this.form.bind(() => ({
1780
2869
  ...this.form.shell(),
1781
2870
  budgetUsd: this.form.field("budgetUsd"),
1782
2871
  maxConsultOutputChars: this.form.field("maxConsultOutputChars"),
1783
- modelProfilesJson: this.form.field("modelProfilesJson")
2872
+ dailyBudgetUsd: this.form.field("dailyBudgetUsd"),
2873
+ monthlyBudgetUsd: this.form.field("monthlyBudgetUsd"),
2874
+ reviewSampleRate: this.form.field("reviewSampleRate"),
2875
+ subscriptionCooldownMinutes: this.form.field("subscriptionCooldownMinutes"),
2876
+ modelProfilesJson: this.form.field("modelProfilesJson"),
2877
+ quotaPatternsJson: this.form.field("quotaPatternsJson")
1784
2878
  }));
1785
2879
  }
1786
2880
  /** Supply the snapshot hook and staged form actions to the Plugins slot. */
@@ -1798,7 +2892,7 @@ function RouterSettingsCard(props) {
1798
2892
  return "\u4E3A\u5B98\u65B9\u5DF2\u914D\u7F6E\u7684\u6A21\u578B\u751F\u6210\u8DEF\u7531\u8BA1\u5212\uFF0C\u5E76\u63D0\u4F9B\u8DE8\u6A21\u578B\u54A8\u8BE2\u5DE5\u5177\u3002";
1799
2893
  }
1800
2894
  const disabled = !state.writable || state.saving;
1801
- return /* @__PURE__ */ import_react3.default.createElement(import_dsh_client_ui_primitives.SettingsForm, { labels: FORM_LABELS, state, onSave: props.save, onDiscard: props.discard }, /* @__PURE__ */ import_react3.default.createElement(
2895
+ return /* @__PURE__ */ import_react5.default.createElement(import_dsh_client_ui_primitives.SettingsForm, { labels: FORM_LABELS, state, onSave: props.save, onDiscard: props.discard }, /* @__PURE__ */ import_react5.default.createElement(
1802
2896
  import_dsh_client_ui_primitives.SettingsValueField,
1803
2897
  {
1804
2898
  id: "model-router-budget-usd",
@@ -1813,14 +2907,14 @@ function RouterSettingsCard(props) {
1813
2907
  overriddenLabel: FIELD_COPY.overridden,
1814
2908
  resetLabel: FIELD_COPY.reset,
1815
2909
  invalidLabel: FIELD_COPY.invalidNumber,
1816
- onEdit: (text2) => {
1817
- props.edit("budgetUsd", text2);
2910
+ onEdit: (text4) => {
2911
+ props.edit("budgetUsd", text4);
1818
2912
  },
1819
2913
  onReset: () => {
1820
2914
  props.resetField("budgetUsd");
1821
2915
  }
1822
2916
  }
1823
- ), /* @__PURE__ */ import_react3.default.createElement(
2917
+ ), /* @__PURE__ */ import_react5.default.createElement(
1824
2918
  import_dsh_client_ui_primitives.SettingsValueField,
1825
2919
  {
1826
2920
  id: "model-router-consult-output",
@@ -1832,14 +2926,41 @@ function RouterSettingsCard(props) {
1832
2926
  overriddenLabel: FIELD_COPY.overridden,
1833
2927
  resetLabel: FIELD_COPY.reset,
1834
2928
  invalidLabel: FIELD_COPY.invalidNumber,
1835
- onEdit: (text2) => {
1836
- props.edit("maxConsultOutputChars", text2);
2929
+ onEdit: (text4) => {
2930
+ props.edit("maxConsultOutputChars", text4);
1837
2931
  },
1838
2932
  onReset: () => {
1839
2933
  props.resetField("maxConsultOutputChars");
1840
2934
  }
1841
2935
  }
1842
- ), /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.profileEditor }, /* @__PURE__ */ import_react3.default.createElement("label", { htmlFor: "model-router-profiles-json", style: styles.profileLabel }, "\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u914D\u7F6E\uFF08JSON\uFF09"), /* @__PURE__ */ import_react3.default.createElement("p", { style: styles.noticeText }, "\u6309\u201C\u6A21\u578B\u76EE\u5F55\u201D\u4E2D\u7684\u51C6\u786E provider/model \u586B\u5199\u3002quality \u4E3A\u81EA\u5B9A\u7684 0\u2013100 \u5206\uFF1Binput/output \u662F\u7F8E\u5143\u6BCF\u767E\u4E07 token\u3002\u7F3A\u5C11\u4EF7\u683C\u65F6\u53EA\u7ED9\u8DEF\u7EBF\u5EFA\u8BAE\uFF0C\u4E0D\u663E\u793A\u865A\u6784\u8D39\u7528\u3002"), /* @__PURE__ */ import_react3.default.createElement(
2936
+ ), [
2937
+ ["dailyBudgetUsd", "model-router-daily-budget", "\u6BCF\u65E5\u6267\u884C\u9884\u7B97\uFF08USD\uFF09", "0 \u8868\u793A\u4E0D\u9650\u3002\u6309\u672C\u673A\u6267\u884C\u8BB0\u5F55\u7684\u5B9E\u9645\u8D39\u7528\u7D2F\u8BA1\uFF0C\u8D85\u51FA\u540E\u6309\u5DE5\u4F5C\u53F0\u8BBE\u7F6E\u81EA\u52A8\u964D\u7EA7\u6216\u6682\u505C\u8BE2\u95EE\u3002"],
2938
+ ["monthlyBudgetUsd", "model-router-monthly-budget", "\u6BCF\u6708\u6267\u884C\u9884\u7B97\uFF08USD\uFF09", "0 \u8868\u793A\u4E0D\u9650\u3002\u6309\u672C\u5730\u65F6\u533A\u7684\u81EA\u7136\u6708\u7D2F\u8BA1\u3002"],
2939
+ ["reviewSampleRate", "model-router-review-rate", "\u5F3A\u6A21\u578B\u62BD\u68C0\u6BD4\u4F8B\uFF080\u20131\uFF09", "\u8D28\u91CF\u56DE\u8DEF\u8BBE\u4E3A\u201C\u62BD\u68C0\u201D\u65F6\uFF0C\u6309\u6B64\u6BD4\u4F8B\u8BA9\u66F4\u5F3A\u7684\u6A21\u578B\u590D\u6838\u4FBF\u5B9C\u6A21\u578B\u7684\u7ED3\u679C\u3002"],
2940
+ ["subscriptionCooldownMinutes", "model-router-subscription-cooldown", "\u8BA2\u9605\u989D\u5EA6\u51B7\u5374\u65F6\u95F4\uFF08\u5206\u949F\uFF09", "\u8BA2\u9605\u989D\u5EA6\u7528\u5C3D\u6216\u9650\u6D41\u3001\u4F46\u5382\u5546\u6CA1\u6709\u7ED9\u51FA\u6062\u590D\u65F6\u95F4\u65F6\uFF0C\u6682\u505C\u4F7F\u7528\u8BE5\u8BA2\u9605\u7684\u65F6\u957F\uFF1B\u671F\u95F4\u540C\u4E00\u8DEF\u7EBF\u76F4\u63A5\u4F7F\u7528 API Key\u3002"]
2941
+ ].map(([key, id2, label, hint]) => /* @__PURE__ */ import_react5.default.createElement(
2942
+ import_dsh_client_ui_primitives.SettingsValueField,
2943
+ {
2944
+ key,
2945
+ id: id2,
2946
+ label,
2947
+ hint,
2948
+ disabled,
2949
+ ...state[key],
2950
+ overriddenLabel: FIELD_COPY.overridden,
2951
+ resetLabel: FIELD_COPY.reset,
2952
+ invalidLabel: FIELD_COPY.invalidNumber,
2953
+ onEdit: (text4) => {
2954
+ props.edit(key, text4);
2955
+ },
2956
+ onReset: () => {
2957
+ props.resetField(key);
2958
+ }
2959
+ }
2960
+ )), /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.profileEditor }, /* @__PURE__ */ import_react5.default.createElement("span", { style: styles.profileLabel }, "\u5B98\u65B9 CLI \u8BFB\u5199\u8FB9\u754C"), /* @__PURE__ */ import_react5.default.createElement("p", { style: styles.noticeText }, "\u53EA\u8BFB\u6267\u884C\u4E0D\u5199\u4EFB\u4F55\u6587\u4EF6\uFF1B\u4FEE\u6539\u6587\u4EF6\u7684\u6267\u884C\u5728\u72EC\u7ACB Git \u5DE5\u4F5C\u6811\u4E2D\u8FDB\u884C\uFF0C\u9700\u8981\u4F60\u786E\u8BA4\u540E\u624D\u4F1A\u628A\u8865\u4E01\u5E94\u7528\u56DE\u5F53\u524D\u5DE5\u4F5C\u533A\u3002\u5DE5\u4F5C\u53F0\u201C\u5B89\u5168\u8FB9\u754C\u201D\u5361\u7247\u6309\u5DF2\u914D\u7F6E\u6A21\u578B\u9010\u6761\u5217\u51FA\u3002"), /* @__PURE__ */ import_react5.default.createElement("table", { style: styles.boundaryTable }, /* @__PURE__ */ import_react5.default.createElement("thead", null, /* @__PURE__ */ import_react5.default.createElement("tr", null, /* @__PURE__ */ import_react5.default.createElement("th", { style: styles.boundaryCell }, "\u5DE5\u5177"), /* @__PURE__ */ import_react5.default.createElement("th", { style: styles.boundaryCell }, "\u53EA\u8BFB\u6267\u884C\u53EF\u8BFB"), /* @__PURE__ */ import_react5.default.createElement("th", { style: styles.boundaryCell }, "\u4FEE\u6539\u6267\u884C\u53EF\u5199"))), /* @__PURE__ */ import_react5.default.createElement("tbody", null, [["claude-code", "Claude Code"], ["codex", "Codex"], ["gemini", "Gemini CLI"]].map(([toolId, label]) => {
2961
+ const boundary = toolBoundary(toolId);
2962
+ return /* @__PURE__ */ import_react5.default.createElement("tr", { key: toolId }, /* @__PURE__ */ import_react5.default.createElement("td", { style: styles.boundaryCell }, label), /* @__PURE__ */ import_react5.default.createElement("td", { style: styles.boundaryCell }, boundary.readOnly.readable), /* @__PURE__ */ import_react5.default.createElement("td", { style: styles.boundaryCell }, boundary.write?.writable ?? "\u4E0D\u652F\u6301\u4FEE\u6539\u6267\u884C"));
2963
+ })))), /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.profileEditor }, /* @__PURE__ */ import_react5.default.createElement("label", { htmlFor: "model-router-profiles-json", style: styles.profileLabel }, "\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u914D\u7F6E\uFF08JSON\uFF09"), /* @__PURE__ */ import_react5.default.createElement("p", { style: styles.noticeText }, "\u6309\u201C\u6A21\u578B\u76EE\u5F55\u201D\u4E2D\u7684\u51C6\u786E provider/model \u586B\u5199\u3002quality \u4E3A\u81EA\u5B9A\u7684 0\u2013100 \u5206\uFF1Binput/output \u662F\u7F8E\u5143\u6BCF\u767E\u4E07 token\u3002\u7F3A\u5C11\u4EF7\u683C\u65F6\u53EA\u7ED9\u8DEF\u7EBF\u5EFA\u8BAE\uFF0C\u4E0D\u663E\u793A\u865A\u6784\u8D39\u7528\u3002"), /* @__PURE__ */ import_react5.default.createElement(
1843
2964
  "textarea",
1844
2965
  {
1845
2966
  id: "model-router-profiles-json",
@@ -1850,20 +2971,38 @@ function RouterSettingsCard(props) {
1850
2971
  spellCheck: false,
1851
2972
  style: styles.profileTextarea
1852
2973
  }
1853
- ), state.modelProfilesJson.invalid && /* @__PURE__ */ import_react3.default.createElement("p", { style: styles.profileError, role: "alert" }, "JSON \u683C\u5F0F\u6216\u67D0\u9879\u914D\u7F6E\u65E0\u6548\u3002\u6BCF\u9879\u9700\u63D0\u4F9B\u51C6\u786E\u7684 provider/model\uFF0C\u5355\u4EF7\u4E3A\u975E\u8D1F USD \u6570\u5B57\uFF0C\u8D28\u91CF\u4E3A 0\u2013100\u3002"), /* @__PURE__ */ import_react3.default.createElement("details", { style: styles.profileExample }, /* @__PURE__ */ import_react3.default.createElement("summary", null, "\u67E5\u770B\u914D\u7F6E\u683C\u5F0F"), /* @__PURE__ */ import_react3.default.createElement("pre", null, `[
2974
+ ), state.modelProfilesJson.invalid && /* @__PURE__ */ import_react5.default.createElement("p", { style: styles.profileError, role: "alert" }, "JSON \u683C\u5F0F\u6216\u67D0\u9879\u914D\u7F6E\u65E0\u6548\u3002\u6BCF\u9879\u9700\u63D0\u4F9B\u51C6\u786E\u7684 provider/model\uFF0C\u5355\u4EF7\u4E3A\u975E\u8D1F USD \u6570\u5B57\uFF0C\u8D28\u91CF\u4E3A 0\u2013100\u3002"), /* @__PURE__ */ import_react5.default.createElement("details", { style: styles.profileExample }, /* @__PURE__ */ import_react5.default.createElement("summary", null, "\u67E5\u770B\u914D\u7F6E\u683C\u5F0F"), /* @__PURE__ */ import_react5.default.createElement("pre", null, `[
1854
2975
  {
1855
2976
  "provider": "\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u4F9B\u5E94\u5546 ID",
1856
2977
  "model": "\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u6A21\u578B ID",
1857
2978
  "quality": 80,
1858
2979
  "pricing": { "input": 0.2, "output": 0.8 },
1859
2980
  "specialties": ["code"],
1860
- "cliModel": "\u5382\u5546 CLI \u4F7F\u7528\u7684\u6A21\u578B\u540D\uFF08\u53EF\u9009\uFF09"
2981
+ "cliModel": "\u5382\u5546 CLI \u4F7F\u7528\u7684\u6A21\u578B\u540D\uFF08\u53EF\u9009\uFF09",
2982
+ "execution": "auto",
2983
+ "billing": "subscription-first",
2984
+ "subscription": "plan-key",
2985
+ "apiRoute": { "provider": "\u6309\u91CF\u4ED8\u8D39\u4F9B\u5E94\u5546 ID", "model": "\u6A21\u578B ID" }
1861
2986
  }
1862
- ]`)), /* @__PURE__ */ import_react3.default.createElement("button", { type: "button", disabled, onClick: () => props.resetField("modelProfilesJson") }, "\u6062\u590D\u9ED8\u8BA4\u914D\u7F6E")), /* @__PURE__ */ import_react3.default.createElement("aside", { style: styles.notice, "aria-label": "\u6A21\u578B\u8DEF\u7531\u4F7F\u7528\u8BF4\u660E" }, /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.titleLine }, /* @__PURE__ */ import_react3.default.createElement(import_dsh_client_ui_primitives.Tag, { tone: "info" }, "\u5B98\u65B9\u6A21\u578B\u914D\u7F6E")), /* @__PURE__ */ import_react3.default.createElement("p", { style: styles.noticeText }, "\u8BF7\u5728 DeepSeek Harness \u7684\u201C\u6A21\u578B\u201D\u9875\u9762\u914D\u7F6E DeepSeek\u3001OpenAI \u517C\u5BB9\u6216 Anthropic \u517C\u5BB9\u670D\u52A1\u3002\u6B64\u63D2\u4EF6\u8BFB\u53D6\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\uFF0C\u4E0D\u4FDD\u5B58 API Key\uFF1B\u76EE\u5F55\u4E2D\u7684\u8DEF\u7EBF\u4ECD\u9700\u901A\u8FC7\u5B9E\u9645\u8C03\u7528\u9A8C\u8BC1\u8D26\u53F7\u548C\u7F51\u7EDC\u53EF\u7528\u6027\u3002"), /* @__PURE__ */ import_react3.default.createElement("p", { style: styles.noticeText }, "\u4F7F\u7528 ", /* @__PURE__ */ import_react3.default.createElement("code", null, "model_router_plan"), " \u83B7\u53D6\u53EF\u5BA1\u9605\u7684\u8DEF\u7531\u5EFA\u8BAE\uFF0C\u4F7F\u7528 ", /* @__PURE__ */ import_react3.default.createElement("code", null, "model_router_consult"), " \u54A8\u8BE2\u4E00\u4E2A\u5DF2\u914D\u7F6E\u6A21\u578B\u3002\u5EFA\u8BAE\u4E0D\u4F1A\u6539\u5199\u4E3B\u4F1A\u8BDD\u6A21\u578B\uFF1B\u591A\u4EBA\u5206\u5DE5\u7531\u5B98\u65B9 Agent Teams \u5DE5\u5177\u6267\u884C\u3002")));
2987
+ ]`), /* @__PURE__ */ import_react5.default.createElement("p", { style: styles.noticeText }, "execution \u53EF\u7701\u7565\u3002auto \u6216 official \u8868\u793A\u4F18\u5148\u5B98\u65B9\u65E0\u754C\u9762\u5DE5\u5177\uFF0C\u5931\u8D25\u540E\u56DE\u9000 API\uFF1Bapi \u8868\u793A\u59CB\u7EC8\u8D70\u6A21\u578B\u76EE\u5F55\u3002billing \u9ED8\u8BA4 subscription-first\uFF08\u8BA2\u9605\u4F18\u5148\uFF0C\u989D\u5EA6\u7528\u5C3D\u6216\u9650\u6D41\u65F6\u5207\u6362 API Key\uFF09\uFF0C\u4E5F\u53EF\u8BBE\u4E3A api-only \u6216 subscription-only\u3002subscription \u4E3A plan-key \u8868\u793A\u8BE5\u8DEF\u7EBF\u672C\u8EAB\u662F\u7F16\u7A0B\u5957\u9910\u7AEF\u70B9\uFF08\u5982 GLM Coding Plan\u3001Kimi Code\u3001MiniMax Token Plan\uFF09\uFF0CapiRoute \u6307\u5B9A\u989D\u5EA6\u7528\u5C3D\u65F6\u56DE\u9000\u7684\u6309\u91CF\u4ED8\u8D39\u8DEF\u7EBF\u3002")), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", disabled, onClick: () => props.resetField("modelProfilesJson") }, "\u6062\u590D\u9ED8\u8BA4\u914D\u7F6E")), /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.profileEditor }, /* @__PURE__ */ import_react5.default.createElement("label", { htmlFor: "model-router-quota-patterns", style: styles.profileLabel }, "\u8BA2\u9605\u989D\u5EA6\u8BC6\u522B\u89C4\u5219\uFF08JSON\uFF0C\u53EF\u9009\uFF09"), /* @__PURE__ */ import_react5.default.createElement("p", { style: styles.noticeText }, "\u5185\u7F6E\u89C4\u5219\u5DF2\u8986\u76D6 Claude\u3001Codex\u3001Gemini\u3001Kimi\u3001MiniMax\u3001GLM \u7684\u6587\u6863\u5316\u62A5\u9519\u3002\u5382\u5546\u6539\u4E86\u62A5\u9519\u6587\u6848\u65F6\uFF0C\u53EF\u6309\u5DE5\u5177 ID\u3001\u4F9B\u5E94\u5546 ID \u6216 * \u8FFD\u52A0\u6B63\u5219\uFF1Aquota \u8868\u793A\u989D\u5EA6\u7528\u5C3D\uFF0CrateLimit \u8868\u793A\u9650\u6D41\u3002"), /* @__PURE__ */ import_react5.default.createElement(
2988
+ "textarea",
2989
+ {
2990
+ id: "model-router-quota-patterns",
2991
+ value: state.quotaPatternsJson.text,
2992
+ disabled,
2993
+ "aria-invalid": state.quotaPatternsJson.invalid,
2994
+ onChange: (event) => props.edit("quotaPatternsJson", event.target.value),
2995
+ spellCheck: false,
2996
+ style: styles.profileTextarea
2997
+ }
2998
+ ), state.quotaPatternsJson.invalid && /* @__PURE__ */ import_react5.default.createElement("p", { style: styles.profileError, role: "alert" }, "\u9700\u8981 JSON \u5BF9\u8C61\uFF0C\u4E14\u6BCF\u6761\u89C4\u5219\u90FD\u662F\u6709\u6548\u7684\u6B63\u5219\u8868\u8FBE\u5F0F\u3002"), /* @__PURE__ */ import_react5.default.createElement("details", { style: styles.profileExample }, /* @__PURE__ */ import_react5.default.createElement("summary", null, "\u67E5\u770B\u89C4\u5219\u683C\u5F0F"), /* @__PURE__ */ import_react5.default.createElement("pre", null, `{
2999
+ "kimi-code": { "quota": ["\u989D\u5EA6\u5DF2\u7528\u5B8C"], "rateLimit": ["\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41"] },
3000
+ "my-glm-plan": { "quota": ["Usage limit reached for", "1308"] }
3001
+ }`)), /* @__PURE__ */ import_react5.default.createElement("button", { type: "button", disabled, onClick: () => props.resetField("quotaPatternsJson") }, "\u6062\u590D\u9ED8\u8BA4\u89C4\u5219")), /* @__PURE__ */ import_react5.default.createElement("aside", { style: styles.notice, "aria-label": "\u6A21\u578B\u8DEF\u7531\u4F7F\u7528\u8BF4\u660E" }, /* @__PURE__ */ import_react5.default.createElement("div", { style: styles.titleLine }, /* @__PURE__ */ import_react5.default.createElement(import_dsh_client_ui_primitives.Tag, { tone: "info" }, "\u5B98\u65B9\u6A21\u578B\u914D\u7F6E")), /* @__PURE__ */ import_react5.default.createElement("p", { style: styles.noticeText }, "\u8BF7\u5728 DeepSeek Harness \u7684\u201C\u6A21\u578B\u201D\u9875\u9762\u914D\u7F6E DeepSeek\u3001OpenAI \u517C\u5BB9\u6216 Anthropic \u517C\u5BB9\u670D\u52A1\u3002\u6B64\u63D2\u4EF6\u8BFB\u53D6\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\uFF0C\u4E0D\u4FDD\u5B58 API Key\uFF1B\u76EE\u5F55\u4E2D\u7684\u8DEF\u7EBF\u4ECD\u9700\u901A\u8FC7\u5B9E\u9645\u8C03\u7528\u9A8C\u8BC1\u8D26\u53F7\u548C\u7F51\u7EDC\u53EF\u7528\u6027\u3002"), /* @__PURE__ */ import_react5.default.createElement("p", { style: styles.noticeText }, "\u4F7F\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_plan"), " \u83B7\u53D6\u53EF\u5BA1\u9605\u7684\u8DEF\u7531\u5EFA\u8BAE\uFF0C\u4F7F\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_consult"), " \u54A8\u8BE2\u4E00\u4E2A\u5DF2\u914D\u7F6E\u6A21\u578B\u3002\u5EFA\u8BAE\u4E0D\u4F1A\u6539\u5199\u4E3B\u4F1A\u8BDD\u6A21\u578B\uFF1B\u591A\u4EBA\u5206\u5DE5\u7531\u5B98\u65B9 Agent Teams \u5DE5\u5177\u6267\u884C\u3002")));
1863
3002
  }
1864
3003
  function OpenRouterWorkspace({ subject, openPanel }) {
1865
3004
  if (subject?.kind !== "bundle" || subject.pkg?.name !== ROUTER_PACKAGE) return null;
1866
- return /* @__PURE__ */ import_react3.default.createElement(import_dsh_client_ui_primitives.Button, { variant: "outline", size: "sm", type: "button", onClick: openPanel }, "\u6253\u5F00\u5DE5\u4F5C\u53F0");
3005
+ return /* @__PURE__ */ import_react5.default.createElement(import_dsh_client_ui_primitives.Button, { variant: "outline", size: "sm", type: "button", onClick: openPanel }, "\u6253\u5F00\u5DE5\u4F5C\u53F0");
1867
3006
  }
1868
3007
  function registerUi(ctx) {
1869
3008
  const officialToolsRemote = ctx.remote[OFFICIAL_TOOLS_REMOTE_NAMESPACE];
@@ -1886,7 +3025,15 @@ function registerUi(ctx) {
1886
3025
  listOfficialTools: () => officialToolsRemote.list(),
1887
3026
  installOfficialTool: (toolId) => officialToolsRemote.installTool(toolId),
1888
3027
  cancelOfficialToolInstall: (toolId) => officialToolsRemote.cancel(toolId),
1889
- officialToolInstallStatus: (toolId) => officialToolsRemote.status(toolId)
3028
+ officialToolInstallStatus: (toolId) => officialToolsRemote.status(toolId),
3029
+ toolHealth: (fresh) => officialToolsRemote.health(fresh),
3030
+ completeOnboarding: () => officialToolsRemote.completeOnboarding(),
3031
+ loadLedger: () => officialToolsRemote.ledger(),
3032
+ rateResult: (request) => officialToolsRemote.rateResult(request),
3033
+ rerunStep: (request) => officialToolsRemote.rerunStep(request),
3034
+ loadBoundaries: () => officialToolsRemote.boundaries(),
3035
+ previewRun: (request) => officialToolsRemote.previewRun(request),
3036
+ startRun: (request) => officialToolsRemote.startRun(request)
1890
3037
  })
1891
3038
  }, RouterMainPage))), "model-router-galgame: main workspace");
1892
3039
  ctx.effect(() => ctx.configForms.whileServed([ROUTER_NAMESPACE], () => ctx.slots.inject("sidebar.panellist", () => ctx.slots.register({
@@ -1926,6 +3073,8 @@ var styles = Object.freeze({
1926
3073
  borderRadius: "8px",
1927
3074
  background: "var(--dsw-alias-markdown-code-block)"
1928
3075
  },
3076
+ boundaryTable: { width: "100%", borderCollapse: "collapse", fontSize: 12, lineHeight: 1.5 },
3077
+ boundaryCell: { padding: "6px 8px", borderBottom: "1px solid rgba(127, 127, 127, .25)", textAlign: "left", verticalAlign: "top" },
1929
3078
  noticeText: {
1930
3079
  margin: "7px 0 0",
1931
3080
  color: "var(--dsw-alias-label-secondary)",