@ljwei-stak/model-router-galgame 0.11.1 → 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.
Files changed (49) hide show
  1. package/.dsh-plugin/client.js +3092 -4
  2. package/.dsh-plugin/index.mjs +1132 -48
  3. package/.dsh-plugin/official-tools-remote-service.mjs +33 -81
  4. package/.dsh-plugin/shared/harness-plan.mjs +65 -20
  5. package/.dsh-plugin/shared/model-profiles.mjs +43 -2
  6. package/.dsh-plugin/shared/official-team-runtime.mjs +70 -8
  7. package/.dsh-plugin/shared/official-tool-executor.mjs +28 -7
  8. package/.dsh-plugin/shared/official-tool-registry.mjs +16 -1
  9. package/.dsh-plugin/shared/official-tools-remote.mjs +79 -42
  10. package/.dsh-plugin/shared/official-tools-runtime.mjs +8 -6
  11. package/.dsh-plugin/shared/router-state.mjs +207 -0
  12. package/.dsh-plugin/shared/router.mjs +74 -7
  13. package/.dsh-plugin/shared/routing-presets.mjs +49 -0
  14. package/.dsh-plugin/shared/run-ledger.mjs +348 -0
  15. package/.dsh-plugin/shared/security-boundaries.mjs +54 -0
  16. package/.dsh-plugin/shared/subscription-billing.mjs +340 -0
  17. package/.dsh-plugin/shared/task-executors.mjs +1154 -0
  18. package/.dsh-plugin/shared/tool-health.mjs +311 -0
  19. package/.dsh-plugin/shared/vendor-mimo-grok-adapter.mjs +10 -0
  20. package/.dsh-plugin/shared/zcode-bundle.mjs +15 -0
  21. package/CHANGELOG.md +32 -0
  22. package/INSTALLATION_GUIDE.zh.md +84 -69
  23. package/MIGRATION.md +36 -16
  24. package/README.i18n.yaml +3 -6
  25. package/README.md +209 -119
  26. package/README.zh.md +219 -100
  27. package/docs/assets/router-only-0.12.0.png +0 -0
  28. package/package.json +14 -24
  29. package/.dsh-plugin/shared/gal-spring-act1.mjs +0 -164
  30. package/.dsh-plugin/shared/gal-spring-act2.mjs +0 -482
  31. package/.dsh-plugin/shared/gal-spring-act3.mjs +0 -124
  32. package/.dsh-plugin/shared/gal-spring-sides.mjs +0 -392
  33. package/.dsh-plugin/shared/gal-story-echo.mjs +0 -415
  34. package/.dsh-plugin/shared/gal-story-echocity.mjs +0 -1283
  35. package/.dsh-plugin/shared/gal-story-spring.mjs +0 -333
  36. package/aipicture/story-backgrounds/README.md +0 -16
  37. package/aipicture/story-backgrounds/model-city-title.webp +0 -0
  38. package/docs/ECHO_CITY_STORY.zh.md +0 -117
  39. package/docs/GAL_ART_PROMPTS.zh.md +0 -53
  40. package/docs/GAL_ART_SOURCES.zh.md +0 -84
  41. package/docs/GAL_SETTINGS.zh.md +0 -211
  42. package/docs/assets/gal-claude-0.10.1-preview.png +0 -0
  43. package/docs/assets/gal-fullbody-0.11.0-preview.jpg +0 -0
  44. package/docs/assets/gal-official-fullbody-0.11.0.jpg +0 -0
  45. package/docs/assets/gal-official-rc2-0.11.0.jpg +0 -0
  46. package/docs/assets/gal-portrait-sources.json +0 -355
  47. package/docs/assets/gal-settings-0.11.0-preview.jpg +0 -0
  48. package/docs/assets/gal-spring-0.10.1-preview.png +0 -0
  49. package/docs/assets/gal-title-0.11.0-preview.jpg +0 -0
@@ -1,4 +1,3092 @@
1
- [diffend] Oversized file quarantined before diffing.
2
- name: package/.dsh-plugin/client.js
3
- size: 57234430 bytes
4
- sha256: 3408d5989501efa0d7c28c0845c8a3f2b553014fcd4a5e76d9fb0df9016d7924
1
+ window.__ModuleLoader__.load({
2
+ id: "@ljwei-stak/model-router-galgame",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
+
34
+ // .dsh-plugin/client/official-harness.jsx
35
+ var official_harness_exports = {};
36
+ __export(official_harness_exports, {
37
+ ROUTER_NAMESPACE: () => ROUTER_NAMESPACE,
38
+ ROUTER_PACKAGE: () => ROUTER_PACKAGE,
39
+ ROUTER_PANEL: () => ROUTER_PANEL,
40
+ RouterSettingsCard: () => RouterSettingsCard,
41
+ RouterSettingsCardController: () => RouterSettingsCardController,
42
+ apply: () => apply,
43
+ inject: () => inject
44
+ });
45
+ module.exports = __toCommonJS(official_harness_exports);
46
+ var import_react5 = __toESM(require("react"), 1);
47
+
48
+ // .dsh-plugin/shared/official-tool-registry.mjs
49
+ var OFFICIAL_TOOLS = Object.freeze([
50
+ Object.freeze({
51
+ id: "kimi-code",
52
+ label: "Kimi Code \xB7 Node",
53
+ vendor: "Moonshot AI",
54
+ purpose: "Kimi \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B kimi \u547D\u4EE4\u4E0E ACP \u4F1A\u8BDD\u3002",
55
+ package: "@moonshot-ai/kimi-code",
56
+ version: "2.1.1",
57
+ manager: "npm",
58
+ installArgs: ["install", "-g", "@moonshot-ai/kimi-code@2.1.1", "--registry=https://registry.npmjs.org/"],
59
+ probeExecutables: ["kimi"],
60
+ probeNote: "kimi \u4E0E\u65E7 Python \u7248 kimi-cli \u540C\u540D\uFF1B\u8BF7\u6838\u5BF9\u53EF\u6267\u884C\u6587\u4EF6\u6765\u6E90\u548C\u7248\u672C\u3002",
61
+ providerHints: ["moonshot", "kimi"]
62
+ }),
63
+ Object.freeze({
64
+ id: "claude-code",
65
+ label: "Claude Code",
66
+ vendor: "Anthropic",
67
+ purpose: "Anthropic \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B claude \u547D\u4EE4\u3002",
68
+ package: "@anthropic-ai/claude-code",
69
+ version: "2.1.283",
70
+ manager: "npm",
71
+ installArgs: ["install", "-g", "@anthropic-ai/claude-code@2.1.283", "--registry=https://registry.npmjs.org/"],
72
+ probeExecutables: ["claude"],
73
+ providerHints: ["anthropic", "claude"]
74
+ }),
75
+ Object.freeze({
76
+ id: "codex",
77
+ label: "Codex CLI",
78
+ vendor: "OpenAI",
79
+ purpose: "OpenAI \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B codex \u547D\u4EE4\u3002",
80
+ package: "@openai/codex",
81
+ version: "0.157.1",
82
+ installArgs: ["install", "-g", "@openai/codex@0.157.1", "--registry=https://registry.npmjs.org/"],
83
+ manager: "npm",
84
+ probeExecutables: ["codex"],
85
+ probeNote: "Codex \u7248\u672C\u6A2A\u5E45\u7531\u9002\u914D\u5C42\u5BBD\u5339\u914D\uFF1B\u5B89\u88C5\u65F6\u56FA\u5B9A\u7248\u672C\u3002",
86
+ providerHints: ["openai", "gpt", "codex"]
87
+ }),
88
+ Object.freeze({
89
+ id: "minimax-code",
90
+ label: "MiniMax Code",
91
+ vendor: "MiniMax",
92
+ purpose: "MiniMax \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B mcode \u547D\u4EE4\u3002",
93
+ package: "@minimax-ai/code",
94
+ version: "0.5.5",
95
+ manager: "npm",
96
+ installArgs: ["install", "-g", "@minimax-ai/code@0.5.5", "--registry=https://registry.npmjs.org/", "--ignore-scripts=false", "--include=optional", "--allow-scripts=@minimax-ai/code,better-sqlite3"],
97
+ probeExecutables: ["mcode"],
98
+ providerHints: ["minimax"]
99
+ }),
100
+ Object.freeze({
101
+ id: "mimo-code",
102
+ label: "MiMo Code",
103
+ vendor: "XiaoMi",
104
+ purpose: "\u5C0F\u7C73 MiMo \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B mimo \u547D\u4EE4\u3002",
105
+ package: "@mimo-ai/cli",
106
+ version: "0.1.15",
107
+ manager: "npm",
108
+ installArgs: ["install", "-g", "@mimo-ai/cli@0.1.15", "--registry=https://registry.npmjs.org/"],
109
+ probeExecutables: ["mimo"],
110
+ providerHints: ["mimo", "xiaomi"]
111
+ }),
112
+ Object.freeze({
113
+ id: "grok-build",
114
+ label: "Grok Build",
115
+ vendor: "xAI",
116
+ purpose: "xAI \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B grok \u547D\u4EE4\u4E0E ACP \u4F1A\u8BDD\u3002",
117
+ package: "@xai-official/grok",
118
+ version: "1.0.41",
119
+ manager: "npm",
120
+ installArgs: ["install", "-g", "@xai-official/grok@1.0.41", "--registry=https://registry.npmjs.org/"],
121
+ probeExecutables: ["grok"],
122
+ providerHints: ["xai", "grok"]
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
+ }),
139
+ Object.freeze({
140
+ id: "zcode",
141
+ label: "ZCode",
142
+ vendor: "Z.ai",
143
+ purpose: "\u667A\u8C31\u5B98\u65B9 ZCode \u684C\u9762\u7248\uFF0C\u5185\u542B GLM \u7F16\u7A0B\u4EE3\u7406\u3002Windows \u5B89\u88C5\u5668\u53EF\u9009\u62E9 D \u76D8\u76EE\u5F55\u3002",
144
+ version: "3.14.3",
145
+ manager: "signed-windows-installer",
146
+ installArgs: [],
147
+ probeExecutables: [],
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",
149
+ providerHints: ["zai", "z.ai", "zcode", "glm", "zhipu", "bigmodel"]
150
+ })
151
+ ]);
152
+ var TOOL_BY_ID = new Map(OFFICIAL_TOOLS.map((tool) => [tool.id, tool]));
153
+ function getOfficialTool(id2) {
154
+ return TOOL_BY_ID.get(String(id2 ?? "").trim()) ?? null;
155
+ }
156
+ function toolForProvider(provider) {
157
+ const value = String(provider ?? "").trim().toLowerCase();
158
+ if (!value) return null;
159
+ for (const tool of OFFICIAL_TOOLS) {
160
+ if (tool.providerHints.some((hint) => value.includes(hint))) return tool;
161
+ }
162
+ return null;
163
+ }
164
+ function installCommandLine(tool) {
165
+ if (!tool || tool.unsupported) return null;
166
+ if (tool.manager === "signed-windows-installer") return "\u6253\u5F00\u5B98\u65B9\u7B7E\u540D\u5B89\u88C5\u5668\uFF08\u9009\u62E9\u5B89\u88C5\u76EE\u5F55\uFF09";
167
+ return tool.manager === "npm" ? `npm ${tool.installArgs.join(" ")}` : `${tool.manager} ${tool.installArgs.join(" ")}`;
168
+ }
169
+
170
+ // .dsh-plugin/shared/model-profiles.mjs
171
+ var MAX_TEXT = 32e3;
172
+ var MAX_PROFILES = 200;
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"]);
176
+ function nonnegative(value, label) {
177
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1e6) {
178
+ throw new Error(`${label} \u5FC5\u987B\u662F 0 \u5230 1000000 \u4E4B\u95F4\u7684\u6709\u9650\u6570\u5B57`);
179
+ }
180
+ return value;
181
+ }
182
+ function normalizeProfile(entry, index) {
183
+ const label = `\u7B2C ${index + 1} \u4E2A\u6A21\u578B`;
184
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) throw new Error(`${label} \u5FC5\u987B\u662F\u5BF9\u8C61`);
185
+ const allowed = /* @__PURE__ */ new Set(["provider", "model", "quality", "pricing", "specialties", "cliModel", "execution", "billing", "subscription", "apiRoute"]);
186
+ const unknown = Object.keys(entry).find((key) => !allowed.has(key));
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`);
188
+ const provider = id(entry.provider);
189
+ const model = id(entry.model);
190
+ if (!provider || !model || provider.length > 160 || model.length > 240) {
191
+ throw new Error(`${label} \u9700\u8981\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u51C6\u786E provider \u548C model`);
192
+ }
193
+ const profile = { provider, model };
194
+ if (entry.quality !== void 0) {
195
+ const value = nonnegative(entry.quality, `${label} \u7684 quality`);
196
+ if (value > 100) throw new Error(`${label} \u7684 quality \u5E94\u5728 0 \u5230 100 \u4E4B\u95F4`);
197
+ profile.quality = value / 100;
198
+ }
199
+ if (entry.pricing !== void 0) {
200
+ const prices = entry.pricing;
201
+ if (!prices || typeof prices !== "object" || Array.isArray(prices)) throw new Error(`${label} \u7684 pricing \u5FC5\u987B\u662F\u5BF9\u8C61`);
202
+ const priceFields = /* @__PURE__ */ new Set(["input", "output", "cacheRead", "cacheWrite", "currency"]);
203
+ const unknownPrice = Object.keys(prices).find((key) => !priceFields.has(key));
204
+ if (unknownPrice) throw new Error(`${label} \u7684 pricing \u542B\u4E0D\u652F\u6301\u7684\u5B57\u6BB5 ${unknownPrice}`);
205
+ if (prices.currency !== void 0 && prices.currency !== "USD") throw new Error(`${label} \u7684\u4EF7\u683C\u5E01\u79CD\u76EE\u524D\u4EC5\u652F\u6301 USD`);
206
+ profile.pricing = {
207
+ input: nonnegative(prices.input, `${label} \u7684\u8F93\u5165\u5355\u4EF7`),
208
+ output: nonnegative(prices.output, `${label} \u7684\u8F93\u51FA\u5355\u4EF7`),
209
+ currency: "USD"
210
+ };
211
+ if (prices.cacheRead !== void 0) profile.pricing.cacheRead = nonnegative(prices.cacheRead, `${label} \u7684\u7F13\u5B58\u8BFB\u53D6\u5355\u4EF7`);
212
+ if (prices.cacheWrite !== void 0) profile.pricing.cacheWrite = nonnegative(prices.cacheWrite, `${label} \u7684\u7F13\u5B58\u5199\u5165\u5355\u4EF7`);
213
+ }
214
+ if (entry.specialties !== void 0) {
215
+ if (!Array.isArray(entry.specialties) || entry.specialties.length > 16 || entry.specialties.some((value) => !/^[a-z][a-z0-9-]{0,39}$/.test(value))) {
216
+ throw new Error(`${label} \u7684 specialties \u5FC5\u987B\u662F\u81F3\u591A 16 \u4E2A\u82F1\u6587\u4EFB\u52A1\u6807\u7B7E`);
217
+ }
218
+ profile.specialties = [...new Set(entry.specialties)];
219
+ }
220
+ if (entry.cliModel !== void 0) {
221
+ const cliModel = id(entry.cliModel);
222
+ if (!/^[A-Za-z0-9][A-Za-z0-9._:/-]{0,119}$/.test(cliModel)) throw new Error(`${label} \u7684 cliModel \u65E0\u6548`);
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`);
224
+ profile.cliModel = cliModel;
225
+ }
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`);
253
+ return profile;
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
+ }
260
+ function parseModelProfilesJson(value) {
261
+ const source = value == null || value === "" ? "[]" : value;
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");
263
+ let input;
264
+ try {
265
+ input = JSON.parse(source);
266
+ } catch {
267
+ throw new Error("\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u914D\u7F6E\u4E0D\u662F\u6709\u6548\u7684 JSON");
268
+ }
269
+ if (!Array.isArray(input) || input.length > MAX_PROFILES) throw new Error("\u6A21\u578B\u4EF7\u683C\u4E0E\u80FD\u529B\u914D\u7F6E\u5FC5\u987B\u662F\u6700\u591A 200 \u9879\u7684 JSON \u6570\u7EC4");
270
+ const profiles = input.map(normalizeProfile);
271
+ const seen = /* @__PURE__ */ new Set();
272
+ for (const profile of profiles) {
273
+ const key = `${profile.provider}\0${profile.model}`;
274
+ if (seen.has(key)) throw new Error(`\u6A21\u578B ${profile.provider}/${profile.model} \u91CD\u590D\u914D\u7F6E`);
275
+ seen.add(key);
276
+ }
277
+ return profiles;
278
+ }
279
+ function applyModelProfiles(routes, profiles) {
280
+ const input = Array.isArray(routes) ? routes : [];
281
+ const values = typeof profiles === "string" ? parseModelProfilesJson(profiles) : profiles;
282
+ if (!Array.isArray(values)) throw new Error("\u6A21\u578B\u914D\u7F6E\u5FC5\u987B\u662F\u6570\u7EC4");
283
+ const byKey = new Map(values.map((profile) => [`${profile.provider}\0${profile.model}`, profile]));
284
+ return input.map((route) => {
285
+ const profile = byKey.get(`${route.provider}\0${route.model}`);
286
+ if (!profile) return route;
287
+ return {
288
+ ...route,
289
+ ...profile.quality === void 0 ? {} : { quality: profile.quality, qualitySource: "user" },
290
+ ...profile.pricing === void 0 ? {} : { pricing: { ...profile.pricing }, pricingSource: "user" },
291
+ ...profile.specialties === void 0 ? {} : { specialties: [...profile.specialties] },
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 } }
297
+ };
298
+ });
299
+ }
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
+
416
+ // .dsh-plugin/client/router-main.jsx
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
+ }
462
+
463
+ // .dsh-plugin/shared/livebench.mjs
464
+ var TASK_ALIASES = Object.freeze({
465
+ reasoning: ["reasoning", "reasoning_score", "hard_reasoning"],
466
+ code: ["code", "coding", "coding_score"],
467
+ math: ["math", "mathematics", "math_score"],
468
+ research: ["research", "retrieval", "knowledge", "data_analysis"],
469
+ writing: ["writing", "creative_writing", "language"],
470
+ vision: ["vision", "multimodal", "visual"],
471
+ summarization: ["summarization", "summary", "if"],
472
+ classification: ["classification", "instruction_following"]
473
+ });
474
+ var CATEGORY_TO_TASK = Object.freeze({
475
+ reasoning: "reasoning",
476
+ coding: "code",
477
+ "agentic coding": "code",
478
+ mathematics: "math",
479
+ "data analysis": "research",
480
+ language: "writing",
481
+ if: "summarization",
482
+ vision: "vision",
483
+ multimodal: "vision"
484
+ });
485
+ function normalized(value) {
486
+ return String(value ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "");
487
+ }
488
+ function liveBenchRow(snapshot, model) {
489
+ return snapshot?.models?.[normalized(model)] ?? null;
490
+ }
491
+
492
+ // .dsh-plugin/shared/router.mjs
493
+ var OBJECTIVE_WEIGHTS = Object.freeze({
494
+ simple: Object.freeze({ quality: 0.28, cost: 0.45, latency: 0.14, specialty: 0.04, reasoning: 0.07, risk: 0.02 }),
495
+ balanced: Object.freeze({ quality: 0.4, cost: 0.26, latency: 0.1, specialty: 0.09, reasoning: 0.1, risk: 0.05 }),
496
+ complex: Object.freeze({ quality: 0.48, cost: 0.14, latency: 0.06, specialty: 0.14, reasoning: 0.11, risk: 0.07 })
497
+ });
498
+ var REASONING_EFFORT_ORDER = Object.freeze(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
499
+ var REASONING_EFFORT_MULTIPLIERS = Object.freeze({
500
+ off: Object.freeze({ output: 0.78, latency: 0.75 }),
501
+ minimal: Object.freeze({ output: 0.86, latency: 0.82 }),
502
+ low: Object.freeze({ output: 0.93, latency: 0.9 }),
503
+ medium: Object.freeze({ output: 1, latency: 1 }),
504
+ high: Object.freeze({ output: 1.16, latency: 1.15 }),
505
+ xhigh: Object.freeze({ output: 1.34, latency: 1.3 }),
506
+ max: Object.freeze({ output: 1.58, latency: 1.5 })
507
+ });
508
+ var QUALITY_FLOORS = Object.freeze({ simple: 0.75, balanced: 0.78, complex: 0.82 });
509
+ var DEFAULT_ROUTER_SETTINGS = Object.freeze({
510
+ pricing: Object.freeze({}),
511
+ // The official site publishes versioned table/categories assets and the
512
+ // adapter discovers the newest release from this root URL.
513
+ liveBenchEndpoint: "https://livebench.ai",
514
+ liveBenchTtlMs: 9e5,
515
+ budgetUsd: 0,
516
+ cacheReadRatio: 0,
517
+ cacheWriteRatio: 0
518
+ });
519
+ var MODEL_CATALOG = Object.freeze([
520
+ { id: "claude-fable-5", aliases: ["claude-fable-5", "claude fable 5"], quality: 0.99, latency: 0.34, costIn: 10, costOut: 50, specialties: ["reasoning", "writing", "research"], risk: 0.06 },
521
+ { id: "claude-opus-4-8", aliases: ["claude-opus-4-8", "claude opus 4.8"], quality: 0.97, latency: 0.39, costIn: 5, costOut: 25, specialties: ["reasoning", "writing", "code"], risk: 0.07 },
522
+ { id: "gpt-5.6-sol", aliases: ["gpt-5.6-sol", "gpt 5.6 sol"], quality: 0.98, latency: 0.4, costIn: 5, costOut: 30, specialties: ["reasoning", "code", "math", "vision"], risk: 0.06 },
523
+ { id: "gpt-5.5", aliases: ["gpt-5.5", "gpt 5.5"], quality: 0.95, latency: 0.44, costIn: 5, costOut: 30, specialties: ["reasoning", "code", "math"], risk: 0.08 },
524
+ { id: "deepseek-v4-pro", aliases: ["deepseek-v4-pro", "deepseek v4 pro"], quality: 0.93, latency: 0.52, costIn: 1.74, costOut: 3.48, specialties: ["code", "math", "reasoning"], risk: 0.1 },
525
+ { id: "deepseek-v4-flash", aliases: ["deepseek-v4-flash", "deepseek v4 flash"], quality: 0.82, latency: 0.82, costIn: 0.14, costOut: 0.28, specialties: ["code", "summarization", "classification"], risk: 0.14 },
526
+ { id: "kimi-k3", aliases: ["kimi-k3", "kimi k3"], quality: 0.91, latency: 0.56, costIn: 3, costOut: 15, specialties: ["reasoning", "long-context", "code"], risk: 0.1 },
527
+ { id: "qwen3.7-max", aliases: ["qwen3.7-max", "qwen 3.7 max"], quality: 0.94, latency: 0.5, costIn: 2.5, costOut: 7.5, specialties: ["reasoning", "math", "code"], risk: 0.08 },
528
+ { id: "qwen3.7-plus", aliases: ["qwen3.7-plus", "qwen 3.7 plus"], quality: 0.87, latency: 0.72, costIn: 0.4, costOut: 1.6, specialties: ["code", "math", "writing"], risk: 0.12 },
529
+ { id: "glm-5.2", aliases: ["glm-5.2", "glm 5.2"], quality: 0.89, latency: 0.64, costIn: 1.4, costOut: 4.4, specialties: ["reasoning", "writing", "math"], risk: 0.11 },
530
+ { id: "gpt-5.6-luna", aliases: ["gpt-5.6-luna", "gpt 5.6 luna"], quality: 0.84, latency: 0.86, costIn: 0.2, costOut: 1.2, specialties: ["classification", "summarization", "code"], risk: 0.14 },
531
+ { id: "gpt-5.6-terra", aliases: ["gpt-5.6-terra", "gpt 5.6 terra"], quality: 0.91, latency: 0.66, costIn: 2, costOut: 12, specialties: ["code", "writing", "reasoning"], risk: 0.1 },
532
+ { id: "minimax-m3", aliases: ["minimax-m3", "minimax m3"], quality: 0.86, latency: 0.69, costIn: 0.3, costOut: 1.2, specialties: ["writing", "code", "summarization"], risk: 0.13 },
533
+ { id: "gemini-3-flash", aliases: ["gemini 3 flash", "gemini-3-flash"], quality: 0.88, latency: 0.73, costIn: 0.5, costOut: 3, specialties: ["vision", "research", "summarization"], risk: 0.12 },
534
+ { id: "big-pickle", aliases: ["big pickle"], quality: 0.7, latency: 0.88, costIn: 0, costOut: 0, specialties: ["classification", "summarization"], risk: 0.24 }
535
+ ]);
536
+ var clamp = (value, min = 0, max = 1) => Math.max(min, Math.min(max, value));
537
+ var normalize = (value) => String(value ?? "").toLowerCase().replace(/[^a-z0-9]+/g, "");
538
+ var routeKey = (provider, model) => `${String(provider ?? "")}/${String(model ?? "")}`;
539
+ var OPENCODE_CATALOG_PROVIDERS = Object.freeze([
540
+ "opencode",
541
+ "opencode-go",
542
+ // Some OpenCode-compatible configuration examples use the product name as
543
+ // the route id. Treat those aliases as catalog routes too; the pi-ai catalog
544
+ // still owns the actual model endpoints.
545
+ "opencode-zen",
546
+ "opencode-go-zen"
547
+ ]);
548
+ function classifyTask(text4) {
549
+ const value = String(text4 ?? "");
550
+ if (value.length < 80 && /翻译|解释|translate|explain/i.test(value)) return "general";
551
+ return detectTaskTypes(value)[0] ?? "general";
552
+ }
553
+ var TASK_TYPE_RULES = Object.freeze([
554
+ ["vision", /图片|图像|照片|视觉|image|vision|截图|识图/i],
555
+ ["math", /数学|证明|定理|公式|方程|math|proof|theorem/i],
556
+ ["code", /代码|编程|工程|项目|架构|接口|api|debug|实现|部署|测试|code/i],
557
+ ["research", /研究|论文|文献|联网|检索|research|source|引用/i],
558
+ ["summarization", /总结|摘要|提炼|提取|关键词|分类|翻译|summar|classif|extract/i],
559
+ ["writing", /写作|润色|小说|文案|报告|writing|draft/i]
560
+ ]);
561
+ var TASK_TYPE_LABELS = Object.freeze({
562
+ vision: "\u89C6\u89C9\u5904\u7406",
563
+ math: "\u6570\u5B66\u63A8\u5BFC",
564
+ code: "\u5DE5\u7A0B\u4E0E\u4EE3\u7801",
565
+ research: "\u7814\u7A76\u4E0E\u68C0\u7D22",
566
+ summarization: "\u6458\u8981\u4E0E\u6574\u7406",
567
+ writing: "\u5199\u4F5C\u4E0E\u8868\u8FBE"
568
+ });
569
+ function detectTaskTypes(text4) {
570
+ const value = String(text4 ?? "");
571
+ const ranked = TASK_TYPE_RULES.map(([type, pattern]) => ({
572
+ type,
573
+ signals: value.match(new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`))?.length ?? 0
574
+ })).filter((item) => item.signals > 0);
575
+ ranked.sort((left, right) => right.signals - left.signals || left.type.localeCompare(right.type));
576
+ return ranked.map((item) => item.type);
577
+ }
578
+ function assessComplexity(text4) {
579
+ const value = String(text4 ?? "");
580
+ const lengthScore = clamp(value.length / 2200);
581
+ const requirementScore = clamp((value.match(/(?:^|\n)\s*(?:[-*]|\d+[.)]|[一二三四五六七八九十]+[、.])/g) ?? []).length / 8);
582
+ const codeScore = /(代码|工程|架构|接口|实现|部署|测试|code|api|debug)/i.test(value) ? 0.22 : 0;
583
+ const highReasoningScore = /(数学|证明|定理|研究|论文|复杂|多步骤|约束|比较|评估|架构|模块|部署|math|proof|research)/i.test(value) ? 0.2 : 0;
584
+ const visionScore = /(图片|图像|照片|截图|视觉|image|vision)/i.test(value) ? 0.12 : 0;
585
+ const domainMarkers = (value.match(/代码|工程|架构|接口|实现|部署|测试|模块|拆分|约束|评估|证明|定理|研究|论文|图片|图像|照片|视觉|code|api|debug|proof|research|vision/gi) ?? []).length;
586
+ const domainComplexity = clamp(domainMarkers / 5) * 0.28;
587
+ const raw = clamp(0.1 + lengthScore * 0.3 + requirementScore * 0.18 + domainComplexity + codeScore + highReasoningScore + visionScore);
588
+ const band = isHardRequirement(value) ? "complex" : isSimpleRequirement(value) && value.length <= 180 ? "simple" : raw < 0.34 ? "simple" : raw < 0.66 ? "balanced" : "complex";
589
+ return { value: raw, band };
590
+ }
591
+ function specialtyMatch(model, taskType, liveScores = {}) {
592
+ const benchmark = asScore(liveScores?.[taskType]);
593
+ if (benchmark !== void 0) return benchmark;
594
+ if (model.specialties.includes(taskType)) return 1;
595
+ if (taskType === "general") return 0.58;
596
+ if (taskType === "research" && model.specialties.includes("writing")) return 0.68;
597
+ if (taskType === "writing" && model.specialties.includes("reasoning")) return 0.62;
598
+ return 0.38;
599
+ }
600
+ function qualityForTask(row, taskType) {
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;
603
+ }
604
+ function specialtyForTask(row, taskType) {
605
+ return specialtyMatch(row.metadata, taskType, row.liveScores);
606
+ }
607
+ function asScore(value) {
608
+ if (value === null || value === void 0 || value === "") return void 0;
609
+ const number = Number(value);
610
+ if (!Number.isFinite(number)) return void 0;
611
+ return clamp(number > 1 ? number / 100 : number);
612
+ }
613
+ function normalizePricing(pricing) {
614
+ if (pricing === null || typeof pricing !== "object" || Array.isArray(pricing)) return {};
615
+ const normalized2 = {};
616
+ for (const [id2, raw] of Object.entries(pricing)) {
617
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) continue;
618
+ if ((raw.input ?? raw.costIn) === null || (raw.input ?? raw.costIn) === void 0) continue;
619
+ if ((raw.output ?? raw.costOut) === null || (raw.output ?? raw.costOut) === void 0) continue;
620
+ const input = Number(raw.input ?? raw.costIn);
621
+ const output = Number(raw.output ?? raw.costOut);
622
+ const cacheRead = Number(raw.cacheRead ?? input);
623
+ const cacheWrite = Number(raw.cacheWrite ?? input);
624
+ if (![input, output, cacheRead, cacheWrite].every((value) => Number.isFinite(value) && value >= 0)) continue;
625
+ if (String(raw.currency ?? "USD").toUpperCase() !== "USD") continue;
626
+ normalized2[normalize(id2)] = {
627
+ input,
628
+ output,
629
+ cacheRead,
630
+ cacheWrite,
631
+ currency: String(raw.currency ?? "USD").toUpperCase()
632
+ };
633
+ }
634
+ return normalized2;
635
+ }
636
+ function pricingFor(model, pricing, provider = "") {
637
+ const normalizedPricing = normalizePricing(pricing);
638
+ const providerOverride = provider === "" ? void 0 : normalizedPricing[normalize(`${provider}/${model.id}`)];
639
+ const override = providerOverride ?? normalizedPricing[normalize(model.id)];
640
+ if (override) return override;
641
+ if (!Number.isFinite(Number(model.costIn)) || !Number.isFinite(Number(model.costOut)) || model.costIn === null || model.costIn === void 0 || model.costOut === null || model.costOut === void 0) return null;
642
+ return {
643
+ input: Number(model.costIn),
644
+ output: Number(model.costOut),
645
+ cacheRead: Number(model.cacheRead ?? model.costIn),
646
+ cacheWrite: Number(model.cacheWrite ?? model.costIn),
647
+ currency: "USD"
648
+ };
649
+ }
650
+ function normalizedCacheRatios(cacheReadRatio = 0, cacheWriteRatio = 0) {
651
+ const read = Number.isFinite(Number(cacheReadRatio)) ? clamp(Number(cacheReadRatio)) : 0;
652
+ const write = Number.isFinite(Number(cacheWriteRatio)) ? Math.min(clamp(Number(cacheWriteRatio)), 1 - read) : 0;
653
+ return { read, write };
654
+ }
655
+ function effectivePricing(pricing, cacheReadRatio = 0, cacheWriteRatio = 0) {
656
+ const { read, write } = normalizedCacheRatios(cacheReadRatio, cacheWriteRatio);
657
+ return {
658
+ input: (1 - read - write) * Number(pricing.input) + read * Number(pricing.cacheRead) + write * Number(pricing.cacheWrite),
659
+ output: Number(pricing.output)
660
+ };
661
+ }
662
+ function costScore(pricing, maxCost, cacheReadRatio = 0, cacheWriteRatio = 0) {
663
+ if (pricing === null) return 0;
664
+ const effective = effectivePricing(pricing, cacheReadRatio, cacheWriteRatio);
665
+ const mean = (effective.input + effective.output) / 2;
666
+ if (maxCost <= 0) return mean === 0 ? 1 : 0;
667
+ return clamp(1 - mean / maxCost);
668
+ }
669
+ function estimateCost(model, text4, outputTokens = 900, pricingOverrides = {}, cacheReadRatio = 0, cacheWriteRatio = 0) {
670
+ const pricing = pricingFor(model, pricingOverrides);
671
+ if (pricing === null) return null;
672
+ const inputTokens = Math.max(80, Math.ceil(String(text4 ?? "").length / 3.7));
673
+ const ratios = normalizedCacheRatios(cacheReadRatio, cacheWriteRatio);
674
+ const cacheReadTokens = Math.min(inputTokens, Math.max(0, Math.round(inputTokens * ratios.read)));
675
+ const cacheWriteTokens = Math.min(inputTokens - cacheReadTokens, Math.max(0, Math.round(inputTokens * ratios.write)));
676
+ const billableInputTokens = inputTokens - cacheReadTokens - cacheWriteTokens;
677
+ return (billableInputTokens * pricing.input + cacheReadTokens * pricing.cacheRead + cacheWriteTokens * pricing.cacheWrite + outputTokens * pricing.output) / 1e6;
678
+ }
679
+ function modelMetadata(name) {
680
+ const key = normalize(name);
681
+ if (!key) return null;
682
+ return MODEL_CATALOG.find((model) => model.aliases.some((alias) => key === normalize(alias))) ?? null;
683
+ }
684
+ function taskTokenBudget(text4, task, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
685
+ const inputTokens = Math.max(80, Math.ceil(String(text4 ?? "").length / 3.7));
686
+ const multipliers = {
687
+ analysis: { input: 0.9, output: 0.55 },
688
+ execution: { input: 1.2, output: (task.difficulty ?? complexity) === "complex" ? 1.45 : 1 },
689
+ verification: { input: 1.15, output: 0.7 },
690
+ synthesis: { input: 1.65, output: 1.3 }
691
+ };
692
+ const multiplier = multipliers[task.purpose] ?? { input: 1, output: 1 };
693
+ const effortMultiplier = reasoningEffortMultiplier(task.reasoningEffort);
694
+ const totalInputTokens = Math.max(80, Math.round(inputTokens * multiplier.input));
695
+ const ratios = normalizedCacheRatios(cacheReadRatio, cacheWriteRatio);
696
+ const cacheReadTokens = Math.min(totalInputTokens, Math.max(0, Math.round(totalInputTokens * ratios.read)));
697
+ const cacheWriteTokens = Math.min(totalInputTokens - cacheReadTokens, Math.max(0, Math.round(totalInputTokens * ratios.write)));
698
+ return {
699
+ inputTokens: totalInputTokens,
700
+ cacheReadTokens,
701
+ cacheWriteTokens,
702
+ outputTokens: Math.max(220, Math.round(900 * multiplier.output * effortMultiplier.output))
703
+ };
704
+ }
705
+ function taskQualityFloor(band, task) {
706
+ const difficulty = task.difficulty ?? band;
707
+ const base = QUALITY_FLOORS[difficulty] ?? QUALITY_FLOORS.balanced;
708
+ if (task.purpose === "synthesis") return Math.max(base, band === "complex" ? 0.84 : base);
709
+ if (difficulty !== "complex") return base;
710
+ return clamp(base + Math.max(0, Number(task.criticality ?? 0.75) - 0.65) * 0.12);
711
+ }
712
+ var MAX_EXPLICIT_EXECUTION_PACKAGES = 6;
713
+ var REQUIREMENT_ACTION = /(?:实现|新增|添加|修复|更新|构建|设计|完成|编写|优化|接入|支持|配置|部署|测试|验证|检查|整理|创建|移除|替换|迁移|适配|开发|调研|安装|下载|上传|发布|生成|集成|改造|封装|显示|提供|允许|确保|处理|解决|分析|探测|检测|选择|分配|拆分|对接|加入|保留|记录|输出|审查|核对|对比|提取|摘要|总结|分类|翻译|格式化|润色|可以|能够|需要|进行|implement|add|fix|update|build|design|write|improve|support|configure|deploy|test|verify|check|create|remove|replace|migrate|install|publish|generate|integrate|review|extract|summarize|classify|translate|format|should|must|need)/i;
714
+ var HIGH_STAKES_WORK = /架构|安全|隐私|权限|并发|事务|迁移|生产|部署|发布|证明|定理|科研|论文|复杂|多步骤|跨系统|系统设计|architecture|security|migration|production|proof|theorem|research/i;
715
+ var SIMPLE_WORK = /翻译|摘要|总结|提取|分类|格式化|列出|改写|润色|拼写|校对|translate|summarize|extract|classify|format|proofread/i;
716
+ var HIGH_STAKES_ACTION = /设计|实现|修复|审计|测试|验证|证明|推导|部署|迁移|规划|研究|解决|推理|design|implement|fix|audit|verify|prove|derive|deploy|migrate|research|solve/i;
717
+ var SIMPLE_REQUEST_START = /^(?:请|帮我)?(?:翻译|摘要|总结|提取|分类|格式化|列出|改写|润色|拼写|校对|translate|summarize|extract|classify|format|proofread)/i;
718
+ function isSimpleRequirement(value) {
719
+ const item = String(value ?? "").trim();
720
+ return SIMPLE_REQUEST_START.test(item) && !/(?:并|然后|最后|同时|以及|and then).{0,20}(?:设计|实现|验证|部署|证明|审计|测试|design|implement|verify|deploy|prove|audit|test)/i.test(item);
721
+ }
722
+ function isHardRequirement(value) {
723
+ const item = String(value ?? "").trim();
724
+ if (isSimpleRequirement(item)) return false;
725
+ return HIGH_STAKES_WORK.test(item) && HIGH_STAKES_ACTION.test(item);
726
+ }
727
+ function requirementDifficulty(objective, type, fallback = "balanced") {
728
+ const value = String(objective ?? "").trim();
729
+ if (isHardRequirement(value)) return "complex";
730
+ if (value.length <= 180 && SIMPLE_WORK.test(value)) return "simple";
731
+ const assessed = assessComplexity(value);
732
+ if (type === "math" && /证明|推导|proof|derive/i.test(value)) return "complex";
733
+ if (assessed.band === "simple" && (type === "code" || type === "research")) return "balanced";
734
+ return assessed.band === "simple" ? "simple" : assessed.band === "complex" ? "complex" : fallback;
735
+ }
736
+ function shouldSplitRequirements(requirements) {
737
+ if (requirements.length >= 3) return true;
738
+ if (requirements.length !== 2) return false;
739
+ const types = requirements.map((item) => detectTaskTypes(item)[0] ?? "general");
740
+ return types[0] !== types[1] || /^(?:最后|然后|接着|随后|再|基于|根据|测试|验证|部署|发布)|(?:完成|结束|实现)后/u.test(requirements[1]);
741
+ }
742
+ function requirementText(value) {
743
+ return String(value ?? "").trim().replace(/[。;;\s]+$/u, "").trim();
744
+ }
745
+ function looksLikeRequirement(value) {
746
+ const item = requirementText(value);
747
+ return item.length >= 3 && !/[::]$/u.test(item) && !/(?:以下|下列|如下)(?:的)?(?:任务|需求|工作|事项|要求)/u.test(item) && REQUIREMENT_ACTION.test(item.slice(0, 32));
748
+ }
749
+ function explicitRequirements(text4) {
750
+ const visibleLines = [];
751
+ let fence = null;
752
+ for (const line of String(text4 ?? "").split(/\r?\n/u)) {
753
+ const marker2 = /^\s*(`{3,}|~{3,})/u.exec(line);
754
+ if (fence) {
755
+ if (marker2 && marker2[1][0] === fence.char && marker2[1].length >= fence.length && !line.slice(marker2[0].length).trim()) fence = null;
756
+ continue;
757
+ }
758
+ if (marker2) {
759
+ fence = { char: marker2[1][0], length: marker2[1].length };
760
+ continue;
761
+ }
762
+ visibleLines.push(line);
763
+ }
764
+ const value = visibleLines.join("\n");
765
+ const lines = visibleLines.map((line) => line.trim()).filter(Boolean);
766
+ if (/^(?:请|帮我)?(?:总结|概括|翻译|摘要|解释)(?:以下|下列|下面|这份|这些)/u.test(lines[0] ?? "") && !/(?:执行|完成|实施|分配)/u.test(lines[0])) return [];
767
+ const marker = /^(?:[-*•]\s+|\d{1,2}[.)、](?!\d)\s*|[一二三四五六七八九十]{1,3}[、.)]\s*)(.+)$/u;
768
+ const marked = lines.map((line) => marker.exec(line)?.[1]).filter(Boolean).map(requirementText).filter(looksLikeRequirement);
769
+ if (marked.length >= 2) return marked;
770
+ const plain = lines.filter((line) => !/^#{1,6}\s|^```|[::]$/u.test(line));
771
+ if (plain.length >= 2 && plain.every(looksLikeRequirement)) {
772
+ return plain.map(requirementText).filter((item) => item.length >= 3);
773
+ }
774
+ const clauses = value.split(/[;;,,]/u).map(requirementText).filter(Boolean);
775
+ if (clauses.length >= 2 && clauses.every(looksLikeRequirement)) {
776
+ return clauses;
777
+ }
778
+ const sentences = value.split(/[。!?]/u).map(requirementText).filter(Boolean);
779
+ if (sentences.length >= 2 && sentences.every(looksLikeRequirement)) {
780
+ return sentences;
781
+ }
782
+ return [];
783
+ }
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) {
826
+ if (band !== "complex") {
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" };
828
+ return [{ ...task, qualityFloor: taskQualityFloor(band, task) }];
829
+ }
830
+ const value = String(text4 ?? "");
831
+ const packages = [
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" }
833
+ ];
834
+ const requirements = explicitRequirements(text4);
835
+ if (requirements.length >= 2) {
836
+ const groups = requirements.length > MAX_EXPLICIT_EXECUTION_PACKAGES ? [
837
+ ...requirements.slice(0, MAX_EXPLICIT_EXECUTION_PACKAGES - 1).map((item) => [item]),
838
+ requirements.slice(MAX_EXPLICIT_EXECUTION_PACKAGES - 1)
839
+ ] : requirements.map((item) => [item]);
840
+ groups.forEach((group, index) => {
841
+ const objective = group.length === 1 ? group[0] : group.map((item, offset) => `${MAX_EXPLICIT_EXECUTION_PACKAGES + offset}. ${item}`).join("\n");
842
+ const type = detectTaskTypes(objective)[0] ?? "general";
843
+ const difficulty = group.length > 1 ? "complex" : requirementDifficulty(objective, type);
844
+ const previous = packages.at(-1);
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);
848
+ packages.push({
849
+ id: `execution-${index + 1}`,
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`,
851
+ objective,
852
+ type,
853
+ purpose: "execution",
854
+ difficulty,
855
+ criticality: difficulty === "simple" ? 0.55 : difficulty === "balanced" ? 0.72 : 0.86,
856
+ dependsOn: explicit.length ? ["analysis", ...explicit] : sequential && previous?.purpose === "execution" ? ["analysis", previous.id] : ["analysis"],
857
+ preferredReasoningEffort: difficulty === "simple" ? "low" : difficulty === "balanced" ? "medium" : "high"
858
+ });
859
+ });
860
+ } else {
861
+ const domains = [...new Set([...detectTaskTypes(text4), taskType].filter((type) => type !== "general"))];
862
+ for (const type of domains.length > 0 ? domains : [taskType]) {
863
+ const objective = value.split(/[,,。;;]|最后|然后|接着|并且/u).map((item) => item.trim()).filter((item) => detectTaskTypes(item).includes(type)).join("\uFF1B") || value;
864
+ const difficulty = requirementDifficulty(objective, type);
865
+ packages.push({
866
+ id: `execution-${type}`,
867
+ name: `${TASK_TYPE_LABELS[type] ?? type}\u65B9\u5411\u5904\u7406`,
868
+ objective,
869
+ type,
870
+ purpose: "execution",
871
+ difficulty,
872
+ criticality: difficulty === "simple" ? 0.55 : difficulty === "balanced" ? 0.72 : 0.86,
873
+ dependsOn: ["analysis"],
874
+ preferredReasoningEffort: difficulty === "simple" ? "low" : difficulty === "balanced" ? "medium" : "high"
875
+ });
876
+ }
877
+ }
878
+ if (/(测试|验证|评估|对比|benchmark|test|verify|audit)/i.test(value)) {
879
+ packages.push({
880
+ id: "verification",
881
+ name: "\u9A8C\u8BC1\u3001\u53CD\u4F8B\u4E0E\u98CE\u9669\u5BA1\u67E5",
882
+ type: "reasoning",
883
+ purpose: "verification",
884
+ difficulty: "complex",
885
+ criticality: 0.88,
886
+ dependsOn: packages.filter((task) => task.purpose === "execution").map((task) => task.id),
887
+ preferredReasoningEffort: "high"
888
+ });
889
+ }
890
+ packages.push({
891
+ id: "synthesis",
892
+ name: "\u7ED3\u679C\u6821\u9A8C\u4E0E\u6574\u5408",
893
+ type: "reasoning",
894
+ purpose: "synthesis",
895
+ difficulty: "complex",
896
+ criticality: 1,
897
+ dependsOn: packages.filter((task) => task.purpose !== "analysis").map((task) => task.id),
898
+ preferredReasoningEffort: "xhigh"
899
+ });
900
+ return packages.map((task) => ({ ...task, qualityFloor: taskQualityFloor(band, task) }));
901
+ }
902
+ var SYNTHESIS_WEIGHTS = Object.freeze({ quality: 0.58, cost: 0.08, latency: 0.04, specialty: 0.08, reasoning: 0.16, risk: 0.06 });
903
+ var ROUTING_BEAM_WIDTH = 256;
904
+ var ROUTING_CANDIDATE_LIMIT = 12;
905
+ function weightsForTask(weights, task) {
906
+ if (task.weights) return task.weights;
907
+ return task.purpose === "synthesis" ? SYNTHESIS_WEIGHTS : OBJECTIVE_WEIGHTS[task.difficulty] ?? weights;
908
+ }
909
+ function compareText(left, right) {
910
+ const a = String(left);
911
+ const b = String(right);
912
+ return a < b ? -1 : a > b ? 1 : 0;
913
+ }
914
+ function compareRowsStable(left, right) {
915
+ return compareText(routeKey(left.provider, left.model), routeKey(right.provider, right.model));
916
+ }
917
+ function reasoningEffortRank(effort) {
918
+ const normalized2 = String(effort ?? "").trim().toLowerCase().replace(/[\s_-]+/g, "");
919
+ const aliases = { none: "off", disabled: "off", extra: "xhigh", extrahigh: "xhigh", maximum: "max" };
920
+ const canonical = aliases[normalized2] ?? normalized2;
921
+ const index = REASONING_EFFORT_ORDER.indexOf(canonical);
922
+ return index < 0 ? REASONING_EFFORT_ORDER.indexOf("medium") : index;
923
+ }
924
+ function reasoningEffortMultiplier(effort) {
925
+ const normalized2 = String(effort ?? "").trim().toLowerCase().replace(/[\s_-]+/g, "");
926
+ const aliases = { none: "off", disabled: "off", extra: "xhigh", extrahigh: "xhigh", maximum: "max" };
927
+ return REASONING_EFFORT_MULTIPLIERS[aliases[normalized2] ?? normalized2] ?? REASONING_EFFORT_MULTIPLIERS.medium;
928
+ }
929
+ function selectReasoningEffort(efforts, preferred = "medium") {
930
+ const exact = Array.isArray(efforts) ? [...new Set(efforts.map((effort) => String(effort?.id ?? effort ?? "")).filter(Boolean))] : [];
931
+ if (exact.length === 0) return void 0;
932
+ const preferredRank = reasoningEffortRank(preferred);
933
+ return exact.slice().sort((left, right) => {
934
+ const distance = Math.abs(reasoningEffortRank(left) - preferredRank) - Math.abs(reasoningEffortRank(right) - preferredRank);
935
+ if (distance !== 0) return distance;
936
+ return reasoningEffortRank(left) - reasoningEffortRank(right) || compareText(left, right);
937
+ })[0];
938
+ }
939
+ function reasoningDecision(row, task) {
940
+ const preferred = String(task.preferredReasoningEffort ?? "medium");
941
+ const efforts = Array.isArray(row.reasoningEfforts) ? row.reasoningEfforts : [];
942
+ if (efforts.length === 0) {
943
+ const knownUnsupported = row.reasoningKnown === true;
944
+ const preferredRank2 = reasoningEffortRank(preferred);
945
+ return {
946
+ reasoningEffort: void 0,
947
+ reasoningFit: knownUnsupported ? clamp(0.78 - preferredRank2 * 0.08) : 0.55,
948
+ preferredReasoningEffort: preferred,
949
+ multiplier: REASONING_EFFORT_MULTIPLIERS.medium
950
+ };
951
+ }
952
+ const preferredRank = reasoningEffortRank(preferred);
953
+ const chosen = selectReasoningEffort(efforts, preferred);
954
+ const distance = Math.abs(reasoningEffortRank(chosen) - preferredRank);
955
+ return {
956
+ reasoningEffort: chosen,
957
+ reasoningFit: clamp(1 - distance / (REASONING_EFFORT_ORDER.length - 1)),
958
+ preferredReasoningEffort: preferred,
959
+ multiplier: reasoningEffortMultiplier(chosen)
960
+ };
961
+ }
962
+ function candidateUtility(row, task, weights, maxCost, usedRoutes, cacheReadRatio = 0, cacheWriteRatio = 0) {
963
+ const quality = qualityForTask(row, task.type);
964
+ const floor = Number(task.qualityFloor ?? taskQualityFloor("complex", task));
965
+ const qualityGap = Math.max(0, floor - quality);
966
+ const duplicatePenalty = 0;
967
+ const synthesisPreference = task.purpose === "synthesis" && /deepseek[- ]?v4[- ]?pro/i.test(row.model) ? 0.025 : 0;
968
+ const reasoning = reasoningDecision(row, task);
969
+ const cost = clamp(costScore(row.pricing, maxCost, cacheReadRatio, cacheWriteRatio) / Math.sqrt(reasoning.multiplier.output));
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;
971
+ return { score, floor, qualityGap, ...reasoning };
972
+ }
973
+ function taskCost(row, task, text4, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
974
+ if (row?.pricing === null) return 0;
975
+ const decision = row === null ? null : reasoningDecision(row, task);
976
+ const tokens = taskTokenBudget(text4, { ...task, reasoningEffort: decision?.reasoningEffort }, complexity, cacheReadRatio, cacheWriteRatio);
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;
978
+ }
979
+ function dominates(left, right, task, text4, complexity, cacheReadRatio, cacheWriteRatio) {
980
+ if (left.pricing === null || right.pricing === null) return false;
981
+ const leftReasoning = reasoningDecision(left, task);
982
+ const rightReasoning = reasoningDecision(right, task);
983
+ const leftValues = {
984
+ quality: qualityForTask(left, task.type),
985
+ cost: taskCost(left, task, text4, complexity, cacheReadRatio, cacheWriteRatio),
986
+ latency: clamp(left.latency * leftReasoning.multiplier.latency),
987
+ specialty: specialtyForTask(left, task.type),
988
+ reasoning: leftReasoning.reasoningFit,
989
+ risk: clamp(left.risk)
990
+ };
991
+ const rightValues = {
992
+ quality: qualityForTask(right, task.type),
993
+ cost: taskCost(right, task, text4, complexity, cacheReadRatio, cacheWriteRatio),
994
+ latency: clamp(right.latency * rightReasoning.multiplier.latency),
995
+ specialty: specialtyForTask(right, task.type),
996
+ reasoning: rightReasoning.reasoningFit,
997
+ risk: clamp(right.risk)
998
+ };
999
+ const noWorse = leftValues.quality >= rightValues.quality && leftValues.cost <= rightValues.cost && leftValues.latency <= rightValues.latency && leftValues.specialty >= rightValues.specialty && leftValues.reasoning >= rightValues.reasoning && leftValues.risk <= rightValues.risk;
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;
1001
+ return noWorse && strictlyBetter;
1002
+ }
1003
+ function candidatePool(rows, task, weights, maxCost, text4, complexity, cacheReadRatio, cacheWriteRatio) {
1004
+ const eligibleRows = task.type === "vision" ? rows.filter((row) => row.inputModalities.length === 0 || row.inputModalities.includes("image")) : rows;
1005
+ const floor = Number(task.qualityFloor ?? 0);
1006
+ const feasible = eligibleRows.filter((row) => qualityForTask(row, task.type) >= floor);
1007
+ const source = feasible.length > 0 ? feasible : eligibleRows.slice().sort((left, right) => qualityForTask(right, task.type) - qualityForTask(left, task.type) || compareRowsStable(left, right)).slice(0, 3);
1008
+ const taskWeights = weightsForTask(weights, task);
1009
+ const scored = source.map((row) => ({
1010
+ row,
1011
+ decision: candidateUtility(row, task, taskWeights, maxCost, /* @__PURE__ */ new Set(), cacheReadRatio, cacheWriteRatio),
1012
+ cost: taskCost(row, task, text4, complexity, cacheReadRatio, cacheWriteRatio)
1013
+ }));
1014
+ const frontier = scored.filter((item) => !source.some((other) => other !== item.row && dominates(other, item.row, task, text4, complexity, cacheReadRatio, cacheWriteRatio)));
1015
+ const essential = [
1016
+ scored.slice().sort((left, right) => left.cost - right.cost || compareRowsStable(left.row, right.row))[0],
1017
+ scored.slice().sort((left, right) => right.decision.score - left.decision.score || compareRowsStable(left.row, right.row))[0],
1018
+ scored.slice().sort((left, right) => qualityForTask(right.row, task.type) - qualityForTask(left.row, task.type) || compareRowsStable(left.row, right.row))[0]
1019
+ ].filter(Boolean);
1020
+ const ordered = [...frontier, ...essential].filter((item, index, all) => all.findIndex((candidate) => candidate.row === item.row) === index).sort((left, right) => right.decision.score - left.decision.score || left.cost - right.cost || compareRowsStable(left.row, right.row)).slice(0, ROUTING_CANDIDATE_LIMIT);
1021
+ return {
1022
+ options: ordered,
1023
+ relaxed: feasible.length === 0,
1024
+ pruned: Math.max(0, eligibleRows.length - ordered.length)
1025
+ };
1026
+ }
1027
+ function stateSignature(state) {
1028
+ return state.assignments.map((assignment) => `${routeKey(assignment.row?.provider, assignment.row?.model)}@${assignment.decision?.reasoningEffort ?? "provider-default"}`).join("|");
1029
+ }
1030
+ function compareUtilityStates(left, right) {
1031
+ return left.relaxedCount - right.relaxedCount || left.qualityShortfall - right.qualityShortfall || right.score - left.score || left.cost - right.cost || left.switches - right.switches || compareText(stateSignature(left), stateSignature(right));
1032
+ }
1033
+ function compareCostStates(left, right) {
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));
1035
+ }
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));
1038
+ if (pools.some((pool) => pool.options.length === 0)) return null;
1039
+ const suffixMinimum = Array(tasks.length + 1).fill(0);
1040
+ for (let index = tasks.length - 1; index >= 0; index -= 1) {
1041
+ const costOptions = Number.isFinite(budget) ? pools[index].options.filter((option) => option.row.pricing !== null) : pools[index].options;
1042
+ if (costOptions.length === 0) return null;
1043
+ suffixMinimum[index] = suffixMinimum[index + 1] + Math.min(...costOptions.map((option) => option.cost));
1044
+ }
1045
+ if (Number.isFinite(budget) && suffixMinimum[0] > budget + 1e-12) return null;
1046
+ let states = [{ assignments: [], routesByTask: /* @__PURE__ */ new Map(), usedRoutes: /* @__PURE__ */ new Set(), score: 0, cost: 0, switches: 0, relaxedCount: 0, qualityShortfall: 0 }];
1047
+ for (let index = 0; index < tasks.length; index += 1) {
1048
+ const task = tasks[index];
1049
+ const pool = pools[index];
1050
+ const expanded = [];
1051
+ for (const state of states) {
1052
+ for (const option of pool.options) {
1053
+ if (Number.isFinite(budget) && option.row.pricing === null) continue;
1054
+ const nextCost = state.cost + option.cost;
1055
+ if (Number.isFinite(budget) && nextCost + suffixMinimum[index + 1] > budget + 1e-12) continue;
1056
+ const taskWeights = weightsForTask(weights, task);
1057
+ const decision = candidateUtility(option.row, task, taskWeights, maxCost, state.usedRoutes, cacheReadRatio, cacheWriteRatio);
1058
+ const route = routeKey(option.row.provider, option.row.model);
1059
+ const dependencySwitches = (task.dependsOn ?? []).reduce((count, dependency) => {
1060
+ const dependencyRoute = state.routesByTask.get(dependency);
1061
+ return count + (dependencyRoute !== void 0 && dependencyRoute !== route ? 1 : 0);
1062
+ }, 0);
1063
+ const handoffPenalty = dependencySwitches * 0.015;
1064
+ const qualityShortfall = Math.max(0, decision.floor - qualityForTask(option.row, task.type));
1065
+ const usedRoutes = new Set(state.usedRoutes);
1066
+ usedRoutes.add(route);
1067
+ const routesByTask = new Map(state.routesByTask);
1068
+ routesByTask.set(task.id, route);
1069
+ expanded.push({
1070
+ assignments: [...state.assignments, { task, row: option.row, decision: { ...decision, relaxed: qualityShortfall > 0 }, estimatedCost: option.cost, handoffPenalty }],
1071
+ routesByTask,
1072
+ usedRoutes,
1073
+ score: state.score + decision.score - handoffPenalty,
1074
+ cost: nextCost,
1075
+ switches: state.switches + dependencySwitches,
1076
+ relaxedCount: state.relaxedCount + (qualityShortfall > 0 ? 1 : 0),
1077
+ qualityShortfall: state.qualityShortfall + qualityShortfall
1078
+ });
1079
+ }
1080
+ }
1081
+ if (expanded.length === 0) return null;
1082
+ expanded.sort(minimizeCost ? compareCostStates : compareUtilityStates);
1083
+ states = expanded.slice(0, ROUTING_BEAM_WIDTH);
1084
+ }
1085
+ states.sort(minimizeCost ? compareCostStates : compareUtilityStates);
1086
+ return {
1087
+ ...states[0],
1088
+ candidatePools: pools,
1089
+ minimumFeasibleCost: suffixMinimum[0]
1090
+ };
1091
+ }
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();
1095
+ const transformOnly = /^(?:请|帮我)?(?:总结|概括|翻译|摘要|解释)(?:以下|下列|下面|这份|这些)/u.test(firstLine) && !/(?:执行|完成|实施|分配)/u.test(firstLine);
1096
+ const assessed = assessComplexity(transformOnly ? firstLine : text4);
1097
+ const requirements = explicitRequirements(text4);
1098
+ const compound = shouldSplitRequirements(requirements);
1099
+ const complexity = compound && assessed.band !== "complex" ? { value: Math.max(0.66, assessed.value), band: "complex" } : assessed;
1100
+ const taskType = classifyTask(transformOnly ? firstLine : text4);
1101
+ const weights = presetWeights(OBJECTIVE_WEIGHTS[complexity.band], presetId);
1102
+ const discovered = Array.isArray(available) ? available.map((entry) => {
1103
+ const rawEfforts = Array.isArray(entry.reasoningEfforts) ? entry.reasoningEfforts : [];
1104
+ const reasoningEfforts = rawEfforts.map((effort) => String(effort?.id ?? effort ?? "")).filter(Boolean);
1105
+ return {
1106
+ provider: String(entry.provider ?? ""),
1107
+ model: String(entry.model ?? ""),
1108
+ reasoningEfforts: [...new Set(reasoningEfforts)],
1109
+ defaultReasoningEffort: entry.defaultReasoningEffort === void 0 ? void 0 : String(entry.defaultReasoningEffort),
1110
+ reasoningKnown: entry.reasoningKnown === true || entry.reasoningKnown === void 0 && Array.isArray(entry.reasoningEfforts),
1111
+ quality: asScore(entry.quality),
1112
+ qualityBias: Number.isFinite(entry.qualityBias) ? clamp(entry.qualityBias, -0.05, 0.05) : 0,
1113
+ qualitySource: entry.qualitySource === "user" ? "user" : "route",
1114
+ latency: asScore(entry.latency),
1115
+ risk: asScore(entry.risk),
1116
+ specialties: Array.isArray(entry.specialties) ? entry.specialties.filter((item) => typeof item === "string") : null,
1117
+ pricing: normalizePricing({ route: entry.pricing ?? entry.price }).route ?? null,
1118
+ pricingSource: entry.pricingSource === "user" ? "user" : "route",
1119
+ inputModalities: Array.isArray(entry.inputModalities) ? entry.inputModalities.map((item) => String(item).toLowerCase()) : []
1120
+ };
1121
+ }) : [];
1122
+ const rows = [];
1123
+ const normalizedPrices = normalizePricing(pricing);
1124
+ for (const route of discovered) {
1125
+ if (!route.provider || !route.model) continue;
1126
+ const catalog = modelMetadata(route.model);
1127
+ const metadata = {
1128
+ ...catalog ?? { id: route.model, aliases: [route.model], specialties: [] },
1129
+ ...route.quality === void 0 ? {} : { quality: route.quality },
1130
+ ...route.latency === void 0 ? {} : { latency: route.latency },
1131
+ ...route.risk === void 0 ? {} : { risk: route.risk },
1132
+ ...route.specialties === null ? {} : { specialties: route.specialties }
1133
+ };
1134
+ const live = liveBenchRow(liveBench, route.model);
1135
+ const liveScores = live?.scores ?? {};
1136
+ const liveOverall = asScore(live?.overall);
1137
+ const quality = clamp((asScore(liveScores?.[taskType]) ?? liveOverall ?? asScore(metadata.quality) ?? 0) + route.qualityBias);
1138
+ const qualitySource = liveOverall !== void 0 || asScore(liveScores?.[taskType]) !== void 0 ? "livebench" : route.quality !== void 0 ? route.qualitySource : catalog ? "catalog-heuristic" : "unknown";
1139
+ const userPrice = normalizedPrices[normalize(`${route.provider}/${route.model}`)] ?? normalizedPrices[normalize(route.model)];
1140
+ const pricingRow = userPrice ?? route.pricing ?? null;
1141
+ const pricingSource = userPrice ? "user" : route.pricing ? route.pricingSource : "unknown";
1142
+ const specialty = specialtyMatch(metadata, taskType, liveScores);
1143
+ rows.push({
1144
+ provider: route.provider,
1145
+ model: route.model,
1146
+ metadata,
1147
+ quality,
1148
+ qualityBias: route.qualityBias,
1149
+ qualitySource,
1150
+ pricingSource,
1151
+ liveScores,
1152
+ liveOverall,
1153
+ latency: metadata.latency ?? 0.5,
1154
+ risk: metadata.risk ?? 0.2,
1155
+ specialty,
1156
+ reasoningEfforts: route.reasoningEfforts,
1157
+ defaultReasoningEffort: route.defaultReasoningEffort,
1158
+ reasoningKnown: route.reasoningKnown,
1159
+ inputModalities: route.inputModalities,
1160
+ pricing: pricingRow,
1161
+ score: 0,
1162
+ estimatedCost: pricingRow === null ? null : estimateCost({
1163
+ id: route.model,
1164
+ costIn: pricingRow.input,
1165
+ costOut: pricingRow.output,
1166
+ cacheRead: pricingRow.cacheRead,
1167
+ cacheWrite: pricingRow.cacheWrite
1168
+ }, text4, 900, {}, cacheReadRatio, cacheWriteRatio)
1169
+ });
1170
+ }
1171
+ const maxCost = Math.max(1, ...rows.filter((row) => row.pricing !== null).map((row) => {
1172
+ const effective = effectivePricing(row.pricing, cacheReadRatio, cacheWriteRatio);
1173
+ return effective.input + effective.output;
1174
+ }));
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
+ });
1180
+ const unassignableTasks = taskNodes.filter((task) => task.type === "vision" && !rows.some((row) => row.inputModalities.length === 0 || row.inputModalities.includes("image"))).map((task) => task.id);
1181
+ const budget = Number(budgetUsd);
1182
+ const utilityPlan = solveAssignments({
1183
+ rows,
1184
+ tasks: taskNodes,
1185
+ weights,
1186
+ maxCost,
1187
+ text: text4,
1188
+ complexity: complexity.band,
1189
+ budget: Number.POSITIVE_INFINITY,
1190
+ cacheReadRatio,
1191
+ cacheWriteRatio
1192
+ });
1193
+ const budgetPlan = budget > 0 ? solveAssignments({
1194
+ rows,
1195
+ tasks: taskNodes,
1196
+ weights,
1197
+ maxCost,
1198
+ text: text4,
1199
+ complexity: complexity.band,
1200
+ budget,
1201
+ cacheReadRatio,
1202
+ cacheWriteRatio
1203
+ }) : null;
1204
+ const minimumCostPlan = budget > 0 && budgetPlan === null ? solveAssignments({
1205
+ rows,
1206
+ tasks: taskNodes,
1207
+ weights,
1208
+ maxCost,
1209
+ text: text4,
1210
+ complexity: complexity.band,
1211
+ budget: Number.POSITIVE_INFINITY,
1212
+ cacheReadRatio,
1213
+ cacheWriteRatio,
1214
+ minimizeCost: true
1215
+ }) : null;
1216
+ const optimized = budget > 0 ? budgetPlan ?? minimumCostPlan ?? utilityPlan : utilityPlan;
1217
+ const assignments = optimized?.assignments ?? [];
1218
+ const usedRoutes = optimized?.usedRoutes ?? /* @__PURE__ */ new Set();
1219
+ const constraintRelaxed = (optimized?.relaxedCount ?? 0) > 0;
1220
+ for (const row of rows) {
1221
+ row.score = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band] }, weights, maxCost, /* @__PURE__ */ new Set(), cacheReadRatio, cacheWriteRatio).score;
1222
+ }
1223
+ rows.sort((left, right) => right.score - left.score || compareRowsStable(left, right));
1224
+ const selectedAssignment = assignments[0];
1225
+ const selected = selectedAssignment?.row ?? (unassignableTasks.length > 0 ? null : rows[0] ?? null);
1226
+ const synthesizerAssignment = assignments.at(-1);
1227
+ const synthesizer = synthesizerAssignment?.row ?? (unassignableTasks.length > 0 ? null : rows.find((row) => /deepseek/i.test(row.model)) ?? rows[0]);
1228
+ const subtasks = assignments.map(({ task, row, decision }) => ({
1229
+ id: task.id,
1230
+ name: task.name,
1231
+ ...task.objective ? { objective: task.objective } : {},
1232
+ type: task.type,
1233
+ difficulty: task.difficulty,
1234
+ recommended: row?.model ?? "\u5F85\u53D1\u73B0\u6A21\u578B",
1235
+ recommendedProvider: row?.provider ?? "",
1236
+ qualitySource: row?.qualitySource ?? "unknown",
1237
+ pricingSource: row?.pricingSource ?? "unknown",
1238
+ recommendedReasoningEffort: decision?.reasoningEffort,
1239
+ preferredReasoningEffort: decision?.preferredReasoningEffort ?? task.preferredReasoningEffort,
1240
+ reasoningFit: Number(Number(decision?.reasoningFit ?? 0).toFixed(3)),
1241
+ purpose: task.purpose,
1242
+ criticality: task.criticality,
1243
+ qualityFloor: Number(task.qualityFloor.toFixed(3)),
1244
+ dependsOn: [...task.dependsOn ?? []]
1245
+ }));
1246
+ const costBreakdown = assignments.map(({ task, row, decision, estimatedCost, handoffPenalty }, index) => {
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);
1249
+ return {
1250
+ stage: index + 1,
1251
+ purpose: task.purpose,
1252
+ difficulty: task.difficulty,
1253
+ model: row?.model ?? "\u5F85\u53D1\u73B0\u6A21\u578B",
1254
+ provider: row?.provider ?? "",
1255
+ reasoningEffort: decision?.reasoningEffort,
1256
+ preferredReasoningEffort: decision?.preferredReasoningEffort,
1257
+ reasoningFit: Number(Number(decision?.reasoningFit ?? 0).toFixed(3)),
1258
+ reasoningOutputMultiplier: Number(Number(decision?.multiplier?.output ?? 1).toFixed(2)),
1259
+ inputTokens: tokens.inputTokens,
1260
+ cacheReadTokens: tokens.cacheReadTokens,
1261
+ cacheWriteTokens: tokens.cacheWriteTokens,
1262
+ outputTokens: tokens.outputTokens,
1263
+ estimatedCost: row?.pricing === null || row === null ? null : Number(taskEstimate.toFixed(6)),
1264
+ quality: row?.qualitySource === "unknown" || row === null ? null : Number(qualityForTask(row, task.type).toFixed(3)),
1265
+ qualitySource: row?.qualitySource ?? "unknown",
1266
+ pricingSource: row?.pricingSource ?? "unknown",
1267
+ handoffPenalty: Number(Number(handoffPenalty ?? 0).toFixed(3))
1268
+ };
1269
+ });
1270
+ const pricingComplete = assignments.length > 0 && assignments.every(({ row }) => row?.pricing !== null);
1271
+ const totalEstimate = pricingComplete ? costBreakdown.reduce((sum, row) => sum + row.estimatedCost, 0) : null;
1272
+ const baselineRows = assignments.map(({ task }) => {
1273
+ const strongest = rows.reduce((best, row) => qualityForTask(row, task.type) > (best === null ? -1 : qualityForTask(best, task.type)) ? row : best, null);
1274
+ return { task, strongest };
1275
+ });
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;
1277
+ const qualityEvidenceComplete = assignments.length > 0 && assignments.every(({ row }) => ["livebench", "route", "user"].includes(row?.qualitySource)) && baselineRows.every(({ strongest }) => ["livebench", "route", "user"].includes(strongest?.qualitySource));
1278
+ const budgetExceeded = Number(budgetUsd) > 0 && totalEstimate !== null ? totalEstimate > Number(budgetUsd) : null;
1279
+ const savings = baselineCost === null || totalEstimate === null || !qualityEvidenceComplete ? null : baselineCost <= 0 ? 0 : clamp((baselineCost - totalEstimate) / baselineCost);
1280
+ const paretoPruned = (optimized?.candidatePools ?? []).reduce((sum, pool) => sum + pool.pruned, 0);
1281
+ const minimumFeasibleCost = rows.every((row) => row.pricing !== null) ? optimized?.minimumFeasibleCost ?? minimumCostPlan?.cost ?? 0 : null;
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`;
1283
+ return {
1284
+ mode,
1285
+ preset: presetId,
1286
+ complexity: { value: Number(complexity.value.toFixed(3)), band: complexity.band },
1287
+ compound,
1288
+ unassignableTasks,
1289
+ taskType,
1290
+ taskTypes: [...new Set(taskNodes.map((task) => task.type).filter((type) => type !== "reasoning"))],
1291
+ objectiveWeights: weights,
1292
+ candidates: rows.slice(0, 8).map((row) => {
1293
+ const decision = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band], preferredReasoningEffort: complexity.band === "simple" ? "low" : "medium" }, weights, maxCost, /* @__PURE__ */ new Set(), cacheReadRatio, cacheWriteRatio);
1294
+ return { provider: row.provider, model: row.model, score: Number(row.score.toFixed(3)), quality: row.qualitySource === "unknown" ? null : Number(row.quality.toFixed(3)), qualitySource: row.qualitySource, specialty: Number(row.specialty.toFixed(3)), reasoningEffort: decision.reasoningEffort, preferredReasoningEffort: decision.preferredReasoningEffort, reasoningFit: Number(decision.reasoningFit.toFixed(3)), reasoningKnown: row.reasoningKnown, reasoningEfforts: row.reasoningEfforts, estimatedCost: row.estimatedCost === null ? null : Number(row.estimatedCost.toFixed(6)), inputPrice: row.pricing?.input ?? null, outputPrice: row.pricing?.output ?? null, pricingSource: row.pricingSource };
1295
+ }),
1296
+ selected: selected === null ? null : { provider: selected.provider, model: selected.model, reasoningEffort: selectedAssignment?.decision?.reasoningEffort, estimatedCost: selected.estimatedCost === null ? null : Number(selected.estimatedCost.toFixed(6)), qualitySource: selected.qualitySource, pricingSource: selected.pricingSource },
1297
+ subtasks,
1298
+ synthesizer: synthesizer == null ? null : { provider: synthesizer.provider, model: synthesizer.model, reasoningEffort: synthesizerAssignment?.decision?.reasoningEffort },
1299
+ estimatedCost: totalEstimate === null ? null : Number(totalEstimate.toFixed(6)),
1300
+ costBreakdown,
1301
+ optimization: {
1302
+ solver: "pareto-pruned quality-constrained beam assignment",
1303
+ qualityFloor: QUALITY_FLOORS[complexity.band],
1304
+ budgetUsd: Number(Number(budgetUsd) > 0 ? Number(budgetUsd) : 0),
1305
+ cacheReadRatio: normalizedCacheRatios(cacheReadRatio, cacheWriteRatio).read,
1306
+ cacheWriteRatio: normalizedCacheRatios(cacheReadRatio, cacheWriteRatio).write,
1307
+ budgetExceeded,
1308
+ constraintRelaxed,
1309
+ pricingComplete,
1310
+ qualityEvidenceComplete,
1311
+ baselineAllStrongCost: baselineCost === null ? null : Number(baselineCost.toFixed(6)),
1312
+ estimatedSavings: savings === null ? null : Number(savings.toFixed(4)),
1313
+ distinctRoutes: usedRoutes.size,
1314
+ handoffCount: optimized?.switches ?? 0,
1315
+ paretoPruned,
1316
+ beamWidth: ROUTING_BEAM_WIDTH,
1317
+ budgetFeasible: budget <= 0 ? pricingComplete ? true : null : budgetPlan !== null,
1318
+ minimumFeasibleCost: minimumFeasibleCost === null ? null : Number(Number(minimumFeasibleCost).toFixed(6)),
1319
+ liveBench: liveBench?.fetchedAt ? { source: liveBench.source ?? "livebench", fetchedAt: liveBench.fetchedAt, models: Object.keys(liveBench.models ?? {}).length, stale: String(liveBenchError).length > 0, error: String(liveBenchError || "") } : { source: "experimental-baseline", fetchedAt: null, models: 0, stale: false, error: String(liveBenchError || "") }
1320
+ },
1321
+ reason,
1322
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
1323
+ };
1324
+ }
1325
+
1326
+ // .dsh-plugin/shared/harness-plan.mjs
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);
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
+ }
1340
+ if (!tool || tool.unsupported) {
1341
+ return { kind: "harness-llm", preference, detail: "\u901A\u8FC7\u5B98\u65B9\u6A21\u578B\u76EE\u5F55 API \u8C03\u7528\u3002" };
1342
+ }
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
+ }
1354
+ const runnable = installed && Array.isArray(runnableToolIds) && runnableToolIds.includes(tool.id);
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 {
1366
+ kind: "harness-llm",
1367
+ preference,
1368
+ tool: tool.id,
1369
+ label: tool.label,
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`
1371
+ };
1372
+ }
1373
+ function annotate(channel) {
1374
+ return {
1375
+ executionChannel: channel.kind,
1376
+ ...channel.tool ? { channelTool: channel.tool } : {},
1377
+ ...channel.label ? { channelLabel: channel.label } : {},
1378
+ ...channel.preference ? { executionPreference: channel.preference } : {},
1379
+ ...channel.loginRequired ? { loginRequired: true } : {},
1380
+ channelDetail: channel.detail
1381
+ };
1382
+ }
1383
+ function createPlanFromRoutes(task, availableRoutes, {
1384
+ mode = "single",
1385
+ budgetUsd = 0,
1386
+ installedToolIds = [],
1387
+ runnableToolIds = [],
1388
+ pricing = {},
1389
+ liveBench = null,
1390
+ cacheReadRatio = 0,
1391
+ cacheWriteRatio = 0,
1392
+ directProvider = "",
1393
+ directModel = "",
1394
+ preset = "balanced",
1395
+ loggedOutToolIds = []
1396
+ } = {}) {
1397
+ const taskText = clean2(task);
1398
+ if (!taskText) throw new Error("task must contain text");
1399
+ const requestedDirect = mode === "direct" || clean2(directProvider) !== "" || clean2(directModel) !== "";
1400
+ const selectedMode = mode === "team" ? "team" : "single";
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
+ }
1412
+ const installedIds = Array.isArray(installedToolIds) ? installedToolIds.filter(Boolean) : [];
1413
+ const channelCache = /* @__PURE__ */ new Map();
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));
1418
+ return channelCache.get(key);
1419
+ };
1420
+ const needsImage = detectTaskTypes(taskText).includes("vision");
1421
+ const plan = buildPlan({
1422
+ text: taskText,
1423
+ available: routes,
1424
+ mode: directRoute ? "single" : selectedMode,
1425
+ budgetUsd: Math.max(0, Number.isFinite(budgetUsd) ? budgetUsd : 0),
1426
+ pricing,
1427
+ liveBench,
1428
+ cacheReadRatio,
1429
+ cacheWriteRatio,
1430
+ preset
1431
+ });
1432
+ const selectedChannel = plan.selected ? channelOf(plan.selected.provider, plan.selected.model) : null;
1433
+ return {
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` } : {},
1439
+ contractVersion: 2,
1440
+ availableRoutes: routes,
1441
+ ...selectedChannel ? annotate(selectedChannel) : {},
1442
+ availabilityNotice: "\u6A21\u578B\u76EE\u5F55\u5217\u51FA\u7684\u8DEF\u7EBF\u5C1A\u672A\u9A8C\u8BC1\u5F53\u524D\u51ED\u636E\u548C\u7F51\u7EDC\uFF1B\u5B9E\u9645\u53EF\u7528\u6027\u4EE5\u5B98\u65B9\u9002\u914D\u5668\u8C03\u7528\u7ED3\u679C\u4E3A\u51C6\u3002",
1443
+ pricingNotice: plan.estimatedCost === null ? "\u90E8\u5206\u8DEF\u7EBF\u5C1A\u672A\u914D\u7F6E\u8BE5\u4F9B\u5E94\u5546\u7684\u7F8E\u5143\u8F93\u5165/\u8F93\u51FA\u5355\u4EF7\uFF0C\u65E0\u6CD5\u8BA1\u7B97\u53EF\u9760\u7684\u603B\u8D39\u7528\u4E0E\u8282\u7701\u6BD4\u4F8B\uFF1B\u8BF7\u5728\u6A21\u578B\u4EF7\u683C\u8BBE\u7F6E\u4E2D\u8865\u9F50\u3002" : "\u8D39\u7528\u6309\u5DF2\u63D0\u4F9B\u7684\u7F8E\u5143\u5355\u4EF7\u548C\u4F30\u8BA1 token \u6570\u8BA1\u7B97\uFF0C\u4E0D\u662F\u4F9B\u5E94\u5546\u8D26\u5355\uFF0C\u4E5F\u4E0D\u662F\u786C\u6027\u652F\u51FA\u4E0A\u9650\u3002",
1444
+ qualityNotice: plan.optimization.qualityEvidenceComplete ? "\u6A21\u578B\u8D28\u91CF\u4F7F\u7528\u5DF2\u63D0\u4F9B\u8BC4\u5206\u6216\u57FA\u51C6\u6570\u636E\u4F30\u8BA1\uFF0C\u4ECD\u9700\u5B9E\u9645\u4EFB\u52A1\u9A8C\u8BC1\u3002" : "\u90E8\u5206\u6A21\u578B\u8D28\u91CF\u7F3A\u5C11\u53EF\u6838\u9A8C\u8BC4\u5206\uFF1B\u76EE\u5F55\u542F\u53D1\u5F0F\u53EA\u4F9B\u9009\u62E9\u53C2\u8003\uFF0C\u8D28\u91CF\u95E8\u69DB\u548C\u8282\u7701\u6BD4\u4F8B\u65E0\u6CD5\u4FDD\u8BC1\u3002",
1445
+ modalityNotice: needsImage ? plan.unassignableTasks.length > 0 ? "\u56FE\u50CF\u5DE5\u4F5C\u5305\u6CA1\u6709\u53EF\u786E\u8BA4\u652F\u6301\u56FE\u50CF\u8F93\u5165\u7684\u8DEF\u7EBF\uFF0C\u5F53\u524D\u8BA1\u5212\u65E0\u6CD5\u5B8C\u6574\u5206\u914D\uFF1B\u8BF7\u5728\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u914D\u7F6E\u652F\u6301\u56FE\u50CF\u7684\u6A21\u578B\u3002" : routes.some((route) => !Array.isArray(route.inputModalities) || route.inputModalities.length === 0) ? "\u56FE\u50CF\u5DE5\u4F5C\u5305\u53EA\u5206\u7ED9\u5DF2\u58F0\u660E\u56FE\u50CF\u80FD\u529B\u6216\u672A\u58F0\u660E\u8F93\u5165\u80FD\u529B\u7684\u6A21\u578B\uFF1B\u672A\u58F0\u660E\u80FD\u529B\u7684\u6A21\u578B\u4ECD\u9700\u5B9E\u9645\u9A8C\u8BC1\u3002\u5176\u4ED6\u6587\u672C\u5DE5\u4F5C\u5305\u53EF\u7EE7\u7EED\u4F7F\u7528\u7ECF\u6D4E\u578B\u6587\u672C\u6A21\u578B\u3002" : "\u56FE\u50CF\u5DE5\u4F5C\u5305\u53EA\u5206\u7ED9\u660E\u786E\u652F\u6301\u56FE\u50CF\u8F93\u5165\u7684\u6A21\u578B\uFF1B\u5176\u4ED6\u6587\u672C\u5DE5\u4F5C\u5305\u53EF\u7EE7\u7EED\u4F7F\u7528\u7ECF\u6D4E\u578B\u6587\u672C\u6A21\u578B\u3002" : null,
1446
+ toolNotice: "\u6267\u884C\u6E20\u9053\u6309\u5B98\u65B9\u5DE5\u5177\u6CE8\u518C\u8868\u548C\u5DF2\u6838\u9A8C\u9002\u914D\u5668\u6807\u6CE8\uFF1Aofficial-cli \u8868\u793A\u8BE5\u5382\u5546\u5B98\u65B9 CLI \u5DF2\u5B89\u88C5\u4E14\u53EF\u6258\u7BA1\u6267\u884C\uFF1Bharness-llm \u8868\u793A\u901A\u8FC7\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u8C03\u7528\u3002\u53EF\u5728\u5DE5\u4F5C\u53F0\u67E5\u770B\u5B89\u88C5\u4E0E\u6267\u884C\u652F\u6301\u72B6\u6001\u3002",
1447
+ team: {
1448
+ requested: selectedMode === "team",
1449
+ recommended: selectedMode === "team" && plan.complexity.band === "complex" && plan.subtasks.length > 1,
1450
+ handoff: "\u53EF\u5728\u5B98\u65B9\u4F1A\u8BDD\u8C03\u7528 model_router_team_execute \u6258\u7BA1\u6267\u884C\u5F53\u524D\u5E73\u53F0\u652F\u6301\u7684\u5B98\u65B9 CLI \u5DE5\u4F5C\u5305\uFF1B\u5B98\u65B9 Agent Teams \u53EF\u534F\u4F5C\u7BA1\u7406\u4EFB\u52A1\uFF0C\u4F46\u6210\u5458\u6A21\u578B\u7531\u5BBF\u4E3B\u914D\u7F6E\uFF0C\u4E0D\u80FD\u76F4\u63A5\u6309\u672C\u8BA1\u5212\u9010\u4E2A\u5207\u6362\u3002",
1451
+ workPackages: plan.subtasks.map((item, index) => ({
1452
+ id: item.id,
1453
+ name: item.name,
1454
+ ...item.objective ? { objective: item.objective } : {},
1455
+ type: item.type,
1456
+ purpose: item.purpose,
1457
+ difficulty: item.difficulty,
1458
+ qualitySource: item.qualitySource,
1459
+ pricingSource: item.pricingSource,
1460
+ dependsOn: item.dependsOn,
1461
+ recommendedProvider: item.recommendedProvider,
1462
+ recommendedModel: item.recommended,
1463
+ estimatedCost: plan.costBreakdown[index]?.estimatedCost ?? null,
1464
+ ...item.recommendedReasoningEffort ? { recommendedReasoningEffort: item.recommendedReasoningEffort } : {},
1465
+ ...annotate(channelOf(item.recommendedProvider, item.recommended)),
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"]
1467
+ }))
1468
+ }
1469
+ };
1470
+ }
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
+
1502
+ // .dsh-plugin/client/catalog.mjs
1503
+ var clean3 = (value) => typeof value === "string" ? value.trim() : "";
1504
+ function routesFromModelCatalog(catalog) {
1505
+ const groups = Array.isArray(catalog?.groups) ? catalog.groups : [];
1506
+ const routable = new Set(Array.isArray(catalog?.routableProviders) ? catalog.routableProviders : []);
1507
+ const routes = [];
1508
+ const seen = /* @__PURE__ */ new Set();
1509
+ for (const group of groups) {
1510
+ const provider = clean3(group?.id);
1511
+ if (!provider || !routable.has(provider)) continue;
1512
+ for (const entry of Array.isArray(group.models) ? group.models : []) {
1513
+ const model = clean3(entry?.id);
1514
+ if (!model) continue;
1515
+ const key = `${provider}\0${model}`;
1516
+ if (seen.has(key)) continue;
1517
+ seen.add(key);
1518
+ const reasoning = entry?.reasoning;
1519
+ const efforts = Array.isArray(reasoning?.efforts) ? [...new Set(reasoning.efforts.map((item) => clean3(item?.id ?? item)).filter(Boolean))] : [];
1520
+ routes.push({
1521
+ provider,
1522
+ providerName: clean3(group.name) || provider,
1523
+ model,
1524
+ name: clean3(entry.name) || model,
1525
+ reasoningKnown: reasoning !== void 0 && reasoning !== null,
1526
+ reasoningEfforts: efforts,
1527
+ ...clean3(reasoning?.defaultEffort) ? { defaultReasoningEffort: clean3(reasoning.defaultEffort) } : {},
1528
+ // modelCatalog deliberately omits modalities; unknown means the Host
1529
+ // must still validate image capability before a real request.
1530
+ inputModalities: []
1531
+ });
1532
+ }
1533
+ }
1534
+ routes.sort((left, right) => `${left.provider}/${left.model}`.localeCompare(`${right.provider}/${right.model}`));
1535
+ return routes;
1536
+ }
1537
+ function createWorkspacePlan(task, catalog, options = {}) {
1538
+ const routes = applyQualityBiases(applyModelProfiles(
1539
+ routesFromModelCatalog(catalog),
1540
+ parseModelProfilesJson(options.modelProfilesJson ?? "[]")
1541
+ ), options.qualityBiases ?? null);
1542
+ return createPlanFromRoutes(task, routes, options);
1543
+ }
1544
+
1545
+ // .dsh-plugin/client/model-profile-editor.jsx
1546
+ var import_react = __toESM(require("react"), 1);
1547
+
1548
+ // .dsh-plugin/client/model-profile-editor-state.mjs
1549
+ var PROFILE_SPECIALTY_HINT = "code, math, research, summarization, writing, vision, reasoning";
1550
+ var profileRouteKey = (route) => `${String(route?.provider ?? "")}\0${String(route?.model ?? "")}`;
1551
+ var field = (value) => String(value ?? "").trim();
1552
+ function nonnegativeField(value, label, max = 1e6) {
1553
+ const raw = field(value);
1554
+ if (!raw) return null;
1555
+ const parsed = Number(raw);
1556
+ if (!Number.isFinite(parsed) || parsed < 0 || parsed > max) throw new Error(`${label} \u5FC5\u987B\u662F 0 \u5230 ${max} \u7684\u6570\u5B57\u3002`);
1557
+ return parsed;
1558
+ }
1559
+ function profileDraft(profile) {
1560
+ return {
1561
+ quality: profile?.quality === void 0 ? "" : String(Number((profile.quality * 100).toFixed(4))),
1562
+ input: profile?.pricing?.input === void 0 ? "" : String(profile.pricing.input),
1563
+ output: profile?.pricing?.output === void 0 ? "" : String(profile.pricing.output),
1564
+ cacheRead: profile?.pricing?.cacheRead === void 0 ? "" : String(profile.pricing.cacheRead),
1565
+ cacheWrite: profile?.pricing?.cacheWrite === void 0 ? "" : String(profile.pricing.cacheWrite),
1566
+ specialties: Array.isArray(profile?.specialties) ? profile.specialties.join(", ") : "",
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) : ""
1572
+ };
1573
+ }
1574
+ function profileFromDraft(route, draft) {
1575
+ const provider = field(route?.provider);
1576
+ const model = field(route?.model);
1577
+ if (!provider || !model) throw new Error("\u8BF7\u5148\u4ECE\u5B98\u65B9\u6A21\u578B\u76EE\u5F55\u9009\u62E9\u4E00\u6761\u51C6\u786E\u7684\u6A21\u578B\u8DEF\u7EBF\u3002");
1578
+ const profile = { provider, model };
1579
+ const quality = nonnegativeField(draft?.quality, "\u8D28\u91CF\u8BC4\u5206", 100);
1580
+ if (quality !== null) profile.quality = quality;
1581
+ const input = nonnegativeField(draft?.input, "\u8F93\u5165\u5355\u4EF7");
1582
+ const output = nonnegativeField(draft?.output, "\u8F93\u51FA\u5355\u4EF7");
1583
+ const cacheRead = nonnegativeField(draft?.cacheRead, "\u7F13\u5B58\u8BFB\u53D6\u5355\u4EF7");
1584
+ const cacheWrite = nonnegativeField(draft?.cacheWrite, "\u7F13\u5B58\u5199\u5165\u5355\u4EF7");
1585
+ if (input === null !== (output === null)) throw new Error("\u8F93\u5165\u548C\u8F93\u51FA\u5355\u4EF7\u9700\u8981\u540C\u65F6\u586B\u5199\uFF1B\u7559\u7A7A\u8868\u793A\u4EF7\u683C\u672A\u77E5\u3002");
1586
+ if (input === null && (cacheRead !== null || cacheWrite !== null)) throw new Error("\u586B\u5199\u7F13\u5B58\u5355\u4EF7\u524D\uFF0C\u8BF7\u5148\u586B\u5199\u8F93\u5165\u548C\u8F93\u51FA\u5355\u4EF7\u3002");
1587
+ if (input !== null) {
1588
+ profile.pricing = { input, output, currency: "USD" };
1589
+ if (cacheRead !== null) profile.pricing.cacheRead = cacheRead;
1590
+ if (cacheWrite !== null) profile.pricing.cacheWrite = cacheWrite;
1591
+ }
1592
+ const rawSpecialties = field(draft?.specialties);
1593
+ if (rawSpecialties) {
1594
+ const specialties = [...new Set(rawSpecialties.split(/[,,\s]+/u).filter(Boolean))];
1595
+ if (specialties.length > 16 || specialties.some((item) => !/^[a-z][a-z0-9-]{0,39}$/.test(item))) {
1596
+ throw new Error("\u64C5\u957F\u65B9\u5411\u6700\u591A 16 \u9879\uFF0C\u7528\u82F1\u6587\u5C0F\u5199\u6807\u7B7E\u5E76\u4EE5\u9017\u53F7\u5206\u9694\uFF0C\u4F8B\u5982 code, research\u3002");
1597
+ }
1598
+ profile.specialties = specialties;
1599
+ }
1600
+ const cliModel = field(draft?.cliModel);
1601
+ if (cliModel) {
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");
1603
+ profile.cliModel = cliModel;
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
+ }
1622
+ return profile;
1623
+ }
1624
+ function updateProfileJson(rawJson, route, draft) {
1625
+ const profiles = parseModelProfilesJson(rawJson ?? "[]");
1626
+ const candidate = draft === null ? null : profileFromDraft(route, draft);
1627
+ const selected = profileRouteKey(route);
1628
+ const others = profiles.filter((profile) => profileRouteKey(profile) !== selected).map((profile) => ({
1629
+ ...profile,
1630
+ ...profile.quality === void 0 ? {} : { quality: Number((profile.quality * 100).toFixed(6)) }
1631
+ }));
1632
+ const next = candidate && Object.keys(candidate).length > 2 ? [...others, candidate] : others;
1633
+ const json = JSON.stringify(next, null, 2);
1634
+ parseModelProfilesJson(json);
1635
+ return json;
1636
+ }
1637
+
1638
+ // .dsh-plugin/client/model-profile-editor.jsx
1639
+ var messageOf = (error) => typeof error?.message === "string" ? error.message : "\u6A21\u578B\u914D\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002";
1640
+ function ModelProfileEditor({ routes, settingsScope, onSaved }) {
1641
+ const [snapshot, setSnapshot] = import_react.default.useState(() => settingsScope.getSnapshot());
1642
+ const [selected, setSelected] = import_react.default.useState("");
1643
+ const [drafts, setDrafts] = import_react.default.useState({});
1644
+ const [saving, setSaving] = import_react.default.useState(false);
1645
+ const [notice, setNotice] = import_react.default.useState(null);
1646
+ import_react.default.useEffect(() => settingsScope.subscribe(() => setSnapshot(settingsScope.getSnapshot())), [settingsScope]);
1647
+ const route = routes.find((item) => profileRouteKey(item) === selected) ?? routes[0];
1648
+ const routeKey3 = route ? profileRouteKey(route) : "";
1649
+ const rawJson = snapshot.value?.modelProfilesJson ?? "[]";
1650
+ let profiles = [];
1651
+ let loadError = "";
1652
+ try {
1653
+ profiles = parseModelProfilesJson(rawJson);
1654
+ } catch (error) {
1655
+ loadError = messageOf(error);
1656
+ }
1657
+ const saved = profiles.find((item) => profileRouteKey(item) === routeKey3);
1658
+ const pending = drafts[routeKey3];
1659
+ const draft = pending?.fields ?? profileDraft(saved);
1660
+ const writable = snapshot.status === "ready" && snapshot.writable === true && !saving && !loadError;
1661
+ const unmatched = profiles.filter((item) => !routes.some((route2) => profileRouteKey(route2) === profileRouteKey(item))).length;
1662
+ const edit = (name, value) => {
1663
+ if (!route || !writable) return;
1664
+ setDrafts((previous) => {
1665
+ const previousEntry = previous[routeKey3] ?? { fields: profileDraft(saved), baseRevision: snapshot.revision };
1666
+ return { ...previous, [routeKey3]: { ...previousEntry, fields: { ...previousEntry.fields, [name]: value } } };
1667
+ });
1668
+ setNotice(null);
1669
+ };
1670
+ const write = async (remove) => {
1671
+ if (!route || !writable) return;
1672
+ const revision = pending?.baseRevision ?? snapshot.revision;
1673
+ if (revision !== snapshot.revision) {
1674
+ setNotice({ tone: "error", text: "\u8BBE\u7F6E\u5DF2\u5728\u5176\u4ED6\u9875\u9762\u66F4\u65B0\u3002\u5F53\u524D\u8F93\u5165\u4ECD\u5728\uFF1B\u8BF7\u6838\u5BF9\u6700\u65B0\u5185\u5BB9\uFF0C\u518D\u9009\u62E9\u201C\u91CD\u65B0\u52A0\u8F7D\u6B64\u8DEF\u7EBF\u201D\u540E\u7F16\u8F91\u3002" });
1675
+ return;
1676
+ }
1677
+ let nextJson;
1678
+ try {
1679
+ nextJson = updateProfileJson(rawJson, route, remove ? null : draft);
1680
+ } catch (error) {
1681
+ setNotice({ tone: "error", text: messageOf(error) });
1682
+ return;
1683
+ }
1684
+ setSaving(true);
1685
+ setNotice(null);
1686
+ try {
1687
+ const accepted = await settingsScope.mutate([{ op: "set", path: ["modelProfilesJson"], value: nextJson }], revision);
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");
1689
+ setDrafts((previous) => {
1690
+ const next = { ...previous };
1691
+ delete next[routeKey3];
1692
+ return next;
1693
+ });
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" });
1695
+ onSaved?.();
1696
+ } catch (error) {
1697
+ setNotice({ tone: "error", text: messageOf(error) });
1698
+ } finally {
1699
+ setSaving(false);
1700
+ }
1701
+ };
1702
+ const reload = () => {
1703
+ setDrafts((previous) => {
1704
+ const next = { ...previous };
1705
+ delete next[routeKey3];
1706
+ return next;
1707
+ });
1708
+ setNotice(null);
1709
+ };
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) => {
1711
+ setSelected(event.target.value);
1712
+ setNotice(null);
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: () => {
1714
+ void write(false);
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: () => {
1716
+ void write(true);
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"))));
1718
+ }
1719
+
1720
+ // .dsh-plugin/client/tool-install-state.mjs
1721
+ function stableVersionOrder(left, right) {
1722
+ const parse = (value) => /^([0-9]+)\.([0-9]+)\.([0-9]+)$/.exec(String(value ?? ""));
1723
+ const current = parse(left);
1724
+ const target = parse(right);
1725
+ if (!current || !target) return null;
1726
+ for (let index = 1; index <= 3; index += 1) {
1727
+ const delta = Number(current[index]) - Number(target[index]);
1728
+ if (delta) return Math.sign(delta);
1729
+ }
1730
+ return 0;
1731
+ }
1732
+ function toolInstallAction({ tool, probe, readiness, job, probeStatus }) {
1733
+ const running = job?.status === "running";
1734
+ const versionOrder = probe?.installed ? stableVersionOrder(probe.version, tool.version) : null;
1735
+ const currentAndReady = versionOrder === 0 && readiness?.ready === true;
1736
+ const repairable = versionOrder === 0 && readiness?.ready === false;
1737
+ const newerOrUncertain = probe?.installed && (versionOrder === null || versionOrder > 0);
1738
+ const label = running ? "\u5B89\u88C5\u4E2D\u2026" : currentAndReady ? "\u5DF2\u662F\u76EE\u6807\u7248\u672C" : repairable ? "\u4FEE\u590D\u5B98\u65B9\u6267\u884C\u5165\u53E3" : newerOrUncertain ? "\u8BF7\u4EBA\u5DE5\u6838\u5BF9\u7248\u672C" : probe?.installed ? "\u66F4\u65B0\u5230\u76EE\u6807\u7248\u672C" : job?.status === "failed" ? "\u91CD\u8BD5\u5B89\u88C5" : tool.manager === "signed-windows-installer" ? "\u4E0B\u8F7D\u5B89\u88C5\u5668" : "\u4E00\u952E\u5B89\u88C5";
1739
+ return {
1740
+ label,
1741
+ disabled: probeStatus !== "ready" || running || currentAndReady || newerOrUncertain
1742
+ };
1743
+ }
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
+
2174
+ // .dsh-plugin/client/router-main.css
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";
2176
+
2177
+ // .dsh-plugin/client/router-main.jsx
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() : "";
2180
+ function RouterPanelIcon({ size = 20, active = false }) {
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" }));
2182
+ }
2183
+ function RouteList({ routes, query }) {
2184
+ const filtered = routes.filter((route) => {
2185
+ const haystack = `${route.providerName} ${route.provider} ${route.name} ${route.model}`.toLowerCase();
2186
+ return haystack.includes(query.toLowerCase());
2187
+ });
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"))));
2190
+ }
2191
+ function ChannelBadge({ item }) {
2192
+ if (!item?.executionChannel) return null;
2193
+ const official = item.executionChannel === "official-cli";
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");
2195
+ }
2196
+ function PlanResults({ plan, ledger }) {
2197
+ const selected = plan.selected;
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 || "")));
2200
+ }
2201
+ var remoteError = (response, fallback) => text3(response?.error?.message) || text3(response?.value?.error) || fallback;
2202
+ function probeLabel(probe) {
2203
+ if (!probe) return "\u5C1A\u672A\u68C0\u6D4B";
2204
+ if (probe.installed) return `\u5DF2\u5B89\u88C5${probe.version ? ` \xB7 ${probe.version}` : ""}`;
2205
+ if (probe.status === "not-installed") return "\u672A\u5B89\u88C5";
2206
+ if (probe.status === "probe-timeout") return "\u68C0\u6D4B\u8D85\u65F6";
2207
+ if (probe.status === "probe-failed") return "\u68C0\u6D4B\u5931\u8D25";
2208
+ return probe.detail || "\u672A\u5B89\u88C5";
2209
+ }
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());
2219
+ const refresh = async () => {
2220
+ onRefreshHealth?.();
2221
+ const current = ++request.current;
2222
+ setProbeState((previous) => ({ ...previous, status: "loading", error: "" }));
2223
+ try {
2224
+ if (typeof listOfficialTools !== "function") throw new Error("\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002");
2225
+ const response = await listOfficialTools();
2226
+ if (!mounted.current || current !== request.current) return;
2227
+ if (!response?.ok) throw new Error(remoteError(response, "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002"));
2228
+ const probes = Array.isArray(response.value?.tools) ? response.value.tools : [];
2229
+ const capabilities = Array.isArray(response.value?.executionCapabilities) ? response.value.executionCapabilities : [];
2230
+ const readiness = Array.isArray(response.value?.executionReadiness) ? response.value.executionReadiness : [];
2231
+ setProbeState({ status: "ready", probes, capabilities, readiness, error: "" });
2232
+ onProbes({ probes, capabilities, readiness });
2233
+ } catch (error) {
2234
+ if (!mounted.current || current !== request.current) return;
2235
+ setProbeState({ status: "error", probes: [], capabilities: [], readiness: [], error: text3(error?.message) || "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002" });
2236
+ onProbes({ probes: [], capabilities: [], readiness: [] });
2237
+ }
2238
+ };
2239
+ import_react4.default.useEffect(() => {
2240
+ mounted.current = true;
2241
+ void refresh();
2242
+ if (typeof officialToolInstallStatus === "function") {
2243
+ void Promise.all(OFFICIAL_TOOLS.map(async (tool) => {
2244
+ try {
2245
+ const response = await officialToolInstallStatus(tool.id);
2246
+ return response?.ok && response.value?.job ? [tool.id, response.value.job] : null;
2247
+ } catch {
2248
+ return null;
2249
+ }
2250
+ })).then((entries) => {
2251
+ if (mounted.current) setJobs((previous) => ({ ...Object.fromEntries(entries.filter(Boolean)), ...previous }));
2252
+ });
2253
+ }
2254
+ return () => {
2255
+ mounted.current = false;
2256
+ request.current += 1;
2257
+ };
2258
+ }, []);
2259
+ import_react4.default.useEffect(() => {
2260
+ const active = Object.values(jobs).filter((job) => job?.status === "running").map((job) => job.tool);
2261
+ if (active.length === 0 || typeof officialToolInstallStatus !== "function") return void 0;
2262
+ let listening = true;
2263
+ const poll = async (id2) => {
2264
+ if (polling.current.has(id2)) return;
2265
+ polling.current.add(id2);
2266
+ try {
2267
+ const response = await officialToolInstallStatus(id2);
2268
+ if (!listening || !mounted.current) return;
2269
+ if (!response?.ok) throw new Error(remoteError(response, "\u65E0\u6CD5\u83B7\u53D6\u5B89\u88C5\u8FDB\u5EA6\u3002"));
2270
+ const job = response.value?.job;
2271
+ if (!job) throw new Error("\u5B89\u88C5\u4EFB\u52A1\u72B6\u6001\u6682\u4E0D\u53EF\u7528\u3002");
2272
+ setJobs((previous) => ({ ...previous, [id2]: job }));
2273
+ setRowErrors((previous) => ({ ...previous, [id2]: "" }));
2274
+ if (job.status !== "running") void refresh();
2275
+ } catch (error) {
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" }));
2277
+ } finally {
2278
+ polling.current.delete(id2);
2279
+ }
2280
+ };
2281
+ const timer = setInterval(() => active.forEach((id2) => {
2282
+ void poll(id2);
2283
+ }), 1500);
2284
+ return () => {
2285
+ listening = false;
2286
+ clearInterval(timer);
2287
+ };
2288
+ }, [jobs, officialToolInstallStatus]);
2289
+ const install = async (id2) => {
2290
+ const tool = OFFICIAL_TOOLS.find((item) => item.id === id2);
2291
+ if (!tool || tool.unsupported || submitting.current.has(id2) || jobs[id2]?.status === "running") return;
2292
+ submitting.current.add(id2);
2293
+ setRowErrors((previous) => ({ ...previous, [id2]: "" }));
2294
+ setJobs((previous) => ({ ...previous, [id2]: { tool: id2, status: "running", outputTail: [] } }));
2295
+ try {
2296
+ if (typeof installOfficialTool !== "function") throw new Error("\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002");
2297
+ const response = await installOfficialTool(id2);
2298
+ if (!mounted.current) return;
2299
+ if (!response?.ok || !response.value?.accepted || !response.value?.job) throw new Error(remoteError(response, "\u5B89\u88C5\u4EFB\u52A1\u672A\u88AB\u63A5\u53D7\u3002"));
2300
+ setJobs((previous) => ({ ...previous, [id2]: response.value.job }));
2301
+ } catch (error) {
2302
+ if (mounted.current) {
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" }));
2305
+ }
2306
+ } finally {
2307
+ submitting.current.delete(id2);
2308
+ }
2309
+ };
2310
+ const cancel = async (id2) => {
2311
+ if (typeof cancelOfficialToolInstall !== "function" || jobs[id2]?.status !== "running" || jobs[id2]?.cancelRequested) return;
2312
+ setRowErrors((previous) => ({ ...previous, [id2]: "" }));
2313
+ try {
2314
+ const response = await cancelOfficialToolInstall(id2);
2315
+ if (!mounted.current) return;
2316
+ if (!response?.ok || !response.value?.accepted || !response.value?.job) throw new Error(remoteError(response, "\u53D6\u6D88\u8BF7\u6C42\u672A\u88AB\u63A5\u53D7\u3002"));
2317
+ setJobs((previous) => ({ ...previous, [id2]: response.value.job }));
2318
+ if (response.value.job.status !== "running") void refresh();
2319
+ } catch (error) {
2320
+ if (mounted.current) setRowErrors((previous) => ({ ...previous, [id2]: text3(error?.message) || "\u65E0\u6CD5\u53D6\u6D88\u5B89\u88C5\u3002" }));
2321
+ }
2322
+ };
2323
+ const byId = Object.fromEntries(probeState.probes.map((probe) => [probe.id, probe]));
2324
+ const capabilitiesById = Object.fromEntries(probeState.capabilities.map((item) => [item.id, item]));
2325
+ const readinessById = Object.fromEntries(probeState.readiness.map((item) => [item.id, item]));
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: () => {
2327
+ void refresh();
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) => {
2329
+ const command = installCommandLine(tool);
2330
+ const probe = byId[tool.id];
2331
+ const capability = capabilitiesById[tool.id];
2332
+ const readiness = readinessById[tool.id];
2333
+ const job = jobs[tool.id];
2334
+ const running = job?.status === "running";
2335
+ const action = toolInstallAction({ tool, probe, readiness, job, probeStatus: probeState.status });
2336
+ const verified = job?.status === "succeeded" && job.postInstallProbe?.installed === true;
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);
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: () => {
2339
+ void install(tool.id);
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: () => {
2341
+ void cancel(tool.id);
2342
+ } }, job.cancelRequested ? "\u6B63\u5728\u53D6\u6D88\u2026" : "\u53D6\u6D88\u5B89\u88C5")));
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(() => {
2458
+ const syncBudget = () => {
2459
+ if (budgetEdited.current) return;
2460
+ const next = String(settingsScope.getSnapshot().value?.budgetUsd ?? 0);
2461
+ if (next !== budgetValue.current) {
2462
+ budgetValue.current = next;
2463
+ setBudget(next);
2464
+ setPlan(null);
2465
+ setPlanError("");
2466
+ }
2467
+ };
2468
+ syncBudget();
2469
+ return settingsScope.subscribe(syncBudget);
2470
+ }, [settingsScope]);
2471
+ import_react4.default.useEffect(() => {
2472
+ mounted.current = true;
2473
+ const request = ++catalogRequest.current;
2474
+ Promise.resolve().then(loadCatalog).then((response) => {
2475
+ if (!mounted.current || request !== catalogRequest.current) return;
2476
+ if (response?.ok) setCatalogState({ status: "ready", catalog: response.value, error: "" });
2477
+ else setCatalogState({ status: "error", catalog: null, error: text3(response?.error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
2478
+ }).catch((error) => {
2479
+ if (mounted.current && request === catalogRequest.current) setCatalogState({ status: "error", catalog: null, error: text3(error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
2480
+ });
2481
+ return () => {
2482
+ mounted.current = false;
2483
+ catalogRequest.current += 1;
2484
+ };
2485
+ }, []);
2486
+ const routes = routesFromModelCatalog(catalogState.catalog);
2487
+ const providerCount = new Set(routes.map((route) => route.provider)).size;
2488
+ const refresh = async () => {
2489
+ const request = ++catalogRequest.current;
2490
+ setCatalogState({ status: "loading", catalog: null, error: "" });
2491
+ setPlan(null);
2492
+ try {
2493
+ const response = await loadCatalog();
2494
+ if (!mounted.current || request !== catalogRequest.current) return;
2495
+ if (response?.ok) setCatalogState({ status: "ready", catalog: response.value, error: "" });
2496
+ else setCatalogState({ status: "error", catalog: null, error: text3(response?.error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
2497
+ } catch (error) {
2498
+ if (mounted.current && request === catalogRequest.current) setCatalogState({ status: "error", catalog: null, error: text3(error?.message) || "\u6A21\u578B\u76EE\u5F55\u8BFB\u53D6\u5931\u8D25" });
2499
+ }
2500
+ };
2501
+ const invalidatePlan = () => {
2502
+ setPlan(null);
2503
+ setPlanError("");
2504
+ };
2505
+ const handleToolProbes = import_react4.default.useCallback((snapshot) => {
2506
+ setToolProbes(snapshot);
2507
+ setPlan(null);
2508
+ setPlanError("");
2509
+ }, []);
2510
+ const generate = () => {
2511
+ setPlanError("");
2512
+ try {
2513
+ if (!text3(task)) throw new Error("\u8BF7\u5148\u63CF\u8FF0\u4EFB\u52A1\u3002");
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");
2515
+ const parsedBudget = Number(budget);
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");
2519
+ setPlan(createWorkspacePlan(task, catalogState.catalog, {
2520
+ mode,
2521
+ ...direct ? { directProvider: direct.provider, directModel: direct.model } : {},
2522
+ budgetUsd: parsedBudget,
2523
+ modelProfilesJson: settingsScope.getSnapshot().value?.modelProfilesJson ?? "[]",
2524
+ installedToolIds: (toolProbes?.probes ?? []).filter((probe) => probe.installed).map((probe) => probe.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)
2529
+ }));
2530
+ } catch (error) {
2531
+ setPlan(null);
2532
+ setPlanError(text3(error?.message) || "\u65E0\u6CD5\u751F\u6210\u8DEF\u7531\u5EFA\u8BAE\u3002");
2533
+ }
2534
+ };
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) => {
2560
+ setTask(event.target.value);
2561
+ invalidatePlan();
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: () => {
2563
+ setMode("single");
2564
+ invalidatePlan();
2565
+ } }, "\u5355\u4EFB\u52A1"), /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", "aria-pressed": mode === "team", onClick: () => {
2566
+ setMode("team");
2567
+ invalidatePlan();
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) => {
2575
+ budgetEdited.current = true;
2576
+ budgetValue.current = event.target.value;
2577
+ setBudget(event.target.value);
2578
+ invalidatePlan();
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")));
2638
+ }
2639
+
2640
+ // .dsh-plugin/shared/official-tools-remote.mjs
2641
+ var OFFICIAL_TOOLS_REMOTE_PACKAGE = "@ljwei-stak/model-router-galgame";
2642
+ var OFFICIAL_TOOLS_REMOTE_NAMESPACE = "modelRouterOfficialTools";
2643
+ function strictCodec(typeSymbol, parse) {
2644
+ return Object.freeze({ mode: "strict", typeSymbol, create: () => ({ parse }) });
2645
+ }
2646
+ function plainObject(value, subject) {
2647
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
2648
+ throw new TypeError(`${subject} must be an object`);
2649
+ }
2650
+ return value;
2651
+ }
2652
+ var toolIdCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#OfficialToolId`, (value) => {
2653
+ if (typeof value !== "string" || !getOfficialTool(value)) {
2654
+ throw new TypeError("toolId must name a fixed official tool");
2655
+ }
2656
+ return value;
2657
+ });
2658
+ var listResultCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#OfficialToolList`, (value) => {
2659
+ const result = plainObject(value, "tool list result");
2660
+ if (!Array.isArray(result.tools)) throw new TypeError("tool list result needs a tools array");
2661
+ return result;
2662
+ });
2663
+ var installResultCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#OfficialToolInstall`, (value) => {
2664
+ const result = plainObject(value, "install result");
2665
+ if (typeof result.accepted !== "boolean") throw new TypeError("install result needs accepted");
2666
+ if (result.accepted && !result.job) throw new TypeError("accepted install needs a job");
2667
+ if (!result.accepted && typeof result.error !== "string") throw new TypeError("refused install needs an error");
2668
+ return result;
2669
+ });
2670
+ var statusResultCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#OfficialToolStatus`, (value) => {
2671
+ const result = plainObject(value, "install status result");
2672
+ if (result.job !== null && (typeof result.job !== "object" || Array.isArray(result.job))) {
2673
+ throw new TypeError("install status result needs a job or null");
2674
+ }
2675
+ return result;
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);
2740
+ function descriptor(method, parameters, result) {
2741
+ return Object.freeze({
2742
+ id: `${OFFICIAL_TOOLS_REMOTE_PACKAGE}#${OFFICIAL_TOOLS_REMOTE_NAMESPACE}/${method}`,
2743
+ service: OFFICIAL_TOOLS_REMOTE_NAMESPACE,
2744
+ namespace: OFFICIAL_TOOLS_REMOTE_NAMESPACE,
2745
+ method,
2746
+ invocation: { kind: "direct" },
2747
+ parameters,
2748
+ result
2749
+ });
2750
+ }
2751
+ var toolIdParameter = Object.freeze({
2752
+ name: "toolId",
2753
+ wire: "toolId",
2754
+ source: "json",
2755
+ codec: toolIdCodec
2756
+ });
2757
+ var jsonParameter = (name, codec) => Object.freeze({ name, wire: name, source: "json", codec });
2758
+ var OFFICIAL_TOOLS_REMOTE_DESCRIPTORS = Object.freeze([
2759
+ descriptor("list", [], listResultCodec),
2760
+ descriptor("installTool", [toolIdParameter], installResultCodec),
2761
+ descriptor("cancel", [toolIdParameter], installResultCodec),
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"))
2773
+ ]);
2774
+ var OFFICIAL_TOOLS_CLIENT_REMOTE = Object.freeze({
2775
+ package: OFFICIAL_TOOLS_REMOTE_PACKAGE,
2776
+ descriptors: OFFICIAL_TOOLS_REMOTE_DESCRIPTORS
2777
+ });
2778
+ var OFFICIAL_TOOLS_HOST_TYPERT = Object.freeze({
2779
+ package: OFFICIAL_TOOLS_REMOTE_PACKAGE,
2780
+ face: "host",
2781
+ schemas: [],
2782
+ invocations: OFFICIAL_TOOLS_REMOTE_DESCRIPTORS,
2783
+ model: { services: [], events: [], objects: [] }
2784
+ });
2785
+
2786
+ // .dsh-plugin/client/official-harness.jsx
2787
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
2788
+ var ROUTER_NAMESPACE = "model-router-galgame";
2789
+ var ROUTER_PACKAGE = "@ljwei-stak/model-router-galgame";
2790
+ var ROUTER_PANEL = "model-router-galgame";
2791
+ var inject = ["remote"];
2792
+ var UI_INJECT = [
2793
+ "slots",
2794
+ "configForms",
2795
+ "remote",
2796
+ "remote.session",
2797
+ `remote.${OFFICIAL_TOOLS_REMOTE_NAMESPACE}`,
2798
+ "layout"
2799
+ ];
2800
+ var FORM_LABELS = Object.freeze({
2801
+ unavailable: "\u8BE5\u63D2\u4EF6\u5F53\u524D\u672A\u52A0\u8F7D\uFF0C\u6682\u65F6\u65E0\u6CD5\u914D\u7F6E\u3002",
2802
+ readOnly: "\u5F53\u524D\u914D\u7F6E\u4E3A\u53EA\u8BFB\u3002",
2803
+ saveFailed: "\u8BBE\u7F6E\u6CA1\u6709\u88AB\u4FDD\u5B58\uFF0C\u8BF7\u68C0\u67E5\u8F93\u5165\u540E\u91CD\u8BD5\u3002",
2804
+ save: "\u4FDD\u5B58\u8BBE\u7F6E",
2805
+ saving: "\u4FDD\u5B58\u4E2D\u2026"
2806
+ });
2807
+ var FIELD_COPY = Object.freeze({
2808
+ overridden: "\u5DF2\u8986\u76D6",
2809
+ reset: "\u6062\u590D\u9ED8\u8BA4",
2810
+ invalidNumber: "\u8BF7\u8F93\u5165\u5141\u8BB8\u8303\u56F4\u5185\u7684\u6570\u5B57\uFF0C\u6216\u7559\u7A7A\u6062\u590D\u9ED8\u8BA4\u3002"
2811
+ });
2812
+ function boundedNumberField(field2, { minimum = 0, maximum = Number.MAX_SAFE_INTEGER, integer = false } = {}) {
2813
+ const numeric = (0, import_dsh_client_ui_primitives.settingsNumberField)(field2);
2814
+ return {
2815
+ ...numeric,
2816
+ parse: (text4) => {
2817
+ const write = numeric.parse(text4);
2818
+ if (write?.kind !== "set") return write;
2819
+ const value = write.value;
2820
+ if (typeof value !== "number" || value < minimum || value > maximum) return void 0;
2821
+ if (integer && (!Number.isSafeInteger(value) || Object.is(value, -0))) return void 0;
2822
+ return write;
2823
+ }
2824
+ };
2825
+ }
2826
+ function modelProfilesField() {
2827
+ const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("modelProfilesJson");
2828
+ return {
2829
+ ...field2,
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() || "{}";
2846
+ try {
2847
+ const value = JSON.parse(raw);
2848
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
2849
+ } catch {
2850
+ return void 0;
2851
+ }
2852
+ return parseQuotaPatterns(raw).errors.length ? void 0 : field2.parse(text4);
2853
+ }
2854
+ };
2855
+ }
2856
+ var RouterSettingsCardController = class {
2857
+ constructor(scope) {
2858
+ this.form = new import_dsh_client_ui_primitives.SettingsFormModel(scope, [
2859
+ boundedNumberField("budgetUsd", { minimum: 0 }),
2860
+ boundedNumberField("maxConsultOutputChars", { minimum: 500, maximum: 5e4, integer: true }),
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()
2867
+ ]);
2868
+ this.store = this.form.bind(() => ({
2869
+ ...this.form.shell(),
2870
+ budgetUsd: this.form.field("budgetUsd"),
2871
+ maxConsultOutputChars: this.form.field("maxConsultOutputChars"),
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")
2878
+ }));
2879
+ }
2880
+ /** Supply the snapshot hook and staged form actions to the Plugins slot. */
2881
+ inject() {
2882
+ return { hooks: { modelRouterSettings: this.store }, ...this.form.actions() };
2883
+ }
2884
+ /** Release the live Host-form subscription when the client plugin unloads. */
2885
+ dispose() {
2886
+ this.form.dispose();
2887
+ }
2888
+ };
2889
+ function RouterSettingsCard(props) {
2890
+ const state = props.useModelRouterSettings((snapshot) => snapshot);
2891
+ if (props.view === "summary") {
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";
2893
+ }
2894
+ const disabled = !state.writable || state.saving;
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(
2896
+ import_dsh_client_ui_primitives.SettingsValueField,
2897
+ {
2898
+ id: "model-router-budget-usd",
2899
+ label: "\u5355\u6B21\u8BA1\u5212\u9884\u7B97\u4E0A\u9650\uFF08USD\uFF09",
2900
+ hint: "0 \u8868\u793A\u4E0D\u8BBE\u9884\u7B97\u4E0A\u9650\u3002\u53EA\u6709\u586B\u5199\u4E0B\u65B9\u5B9E\u9645\u4F7F\u7528\u7684\u5355\u4EF7\u540E\uFF0C\u624D\u80FD\u4F30\u7B97\u8D39\u7528\uFF1B\u9884\u7B97\u53EA\u5F71\u54CD\u8DEF\u7531\u5EFA\u8BAE\u3002",
2901
+ help: {
2902
+ label: "\u9884\u7B97\u8BF4\u660E",
2903
+ content: "\u9884\u7B97\u53EA\u5F71\u54CD\u8DEF\u7531\u5EFA\u8BAE\uFF0C\u4E0D\u4F1A\u9650\u5236\u670D\u52A1\u5546\u6263\u8D39\uFF0C\u4E5F\u4E0D\u4F1A\u8BFB\u53D6\u6216\u4FDD\u5B58 API Key\u3002"
2904
+ },
2905
+ disabled,
2906
+ ...state.budgetUsd,
2907
+ overriddenLabel: FIELD_COPY.overridden,
2908
+ resetLabel: FIELD_COPY.reset,
2909
+ invalidLabel: FIELD_COPY.invalidNumber,
2910
+ onEdit: (text4) => {
2911
+ props.edit("budgetUsd", text4);
2912
+ },
2913
+ onReset: () => {
2914
+ props.resetField("budgetUsd");
2915
+ }
2916
+ }
2917
+ ), /* @__PURE__ */ import_react5.default.createElement(
2918
+ import_dsh_client_ui_primitives.SettingsValueField,
2919
+ {
2920
+ id: "model-router-consult-output",
2921
+ label: "\u8DE8\u6A21\u578B\u54A8\u8BE2\u6700\u5927\u8F93\u51FA\u5B57\u7B26\u6570",
2922
+ hint: "\u9650\u5236 model_router_consult \u8FD4\u56DE\u7684\u5B57\u7B26\u6570\uFF0C\u9632\u6B62\u5355\u6B21\u54A8\u8BE2\u5360\u7528\u8FC7\u591A\u4E0A\u4E0B\u6587\u3002",
2923
+ numeric: true,
2924
+ disabled,
2925
+ ...state.maxConsultOutputChars,
2926
+ overriddenLabel: FIELD_COPY.overridden,
2927
+ resetLabel: FIELD_COPY.reset,
2928
+ invalidLabel: FIELD_COPY.invalidNumber,
2929
+ onEdit: (text4) => {
2930
+ props.edit("maxConsultOutputChars", text4);
2931
+ },
2932
+ onReset: () => {
2933
+ props.resetField("maxConsultOutputChars");
2934
+ }
2935
+ }
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(
2964
+ "textarea",
2965
+ {
2966
+ id: "model-router-profiles-json",
2967
+ value: state.modelProfilesJson.text,
2968
+ disabled,
2969
+ "aria-invalid": state.modelProfilesJson.invalid,
2970
+ onChange: (event) => props.edit("modelProfilesJson", event.target.value),
2971
+ spellCheck: false,
2972
+ style: styles.profileTextarea
2973
+ }
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, `[
2975
+ {
2976
+ "provider": "\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u4F9B\u5E94\u5546 ID",
2977
+ "model": "\u6A21\u578B\u76EE\u5F55\u4E2D\u7684\u6A21\u578B ID",
2978
+ "quality": 80,
2979
+ "pricing": { "input": 0.2, "output": 0.8 },
2980
+ "specialties": ["code"],
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" }
2986
+ }
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")));
3002
+ }
3003
+ function OpenRouterWorkspace({ subject, openPanel }) {
3004
+ if (subject?.kind !== "bundle" || subject.pkg?.name !== ROUTER_PACKAGE) return null;
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");
3006
+ }
3007
+ function registerUi(ctx) {
3008
+ const officialToolsRemote = ctx.remote[OFFICIAL_TOOLS_REMOTE_NAMESPACE];
3009
+ const settingsScope = ctx.configForms.get(ROUTER_NAMESPACE);
3010
+ const card = new RouterSettingsCardController(settingsScope);
3011
+ ctx.effect(() => () => {
3012
+ card.dispose();
3013
+ }, "model-router-galgame: settings form subscription");
3014
+ ctx.effect(() => ctx.configForms.whileServed([ROUTER_NAMESPACE], () => ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({
3015
+ name: "plugins.bundle.config",
3016
+ key: ROUTER_PACKAGE,
3017
+ inject: () => card.inject()
3018
+ }, RouterSettingsCard))), "model-router-galgame: installed bundle settings");
3019
+ ctx.effect(() => ctx.configForms.whileServed([ROUTER_NAMESPACE], () => ctx.slots.inject("main", () => ctx.slots.register({
3020
+ name: "main",
3021
+ key: ROUTER_PANEL,
3022
+ inject: () => ({
3023
+ loadCatalog: () => ctx.remote.session.modelCatalog(),
3024
+ settingsScope,
3025
+ listOfficialTools: () => officialToolsRemote.list(),
3026
+ installOfficialTool: (toolId) => officialToolsRemote.installTool(toolId),
3027
+ cancelOfficialToolInstall: (toolId) => officialToolsRemote.cancel(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)
3037
+ })
3038
+ }, RouterMainPage))), "model-router-galgame: main workspace");
3039
+ ctx.effect(() => ctx.configForms.whileServed([ROUTER_NAMESPACE], () => ctx.slots.inject("sidebar.panellist", () => ctx.slots.register({
3040
+ name: "sidebar.panellist",
3041
+ id: ROUTER_PANEL,
3042
+ order: 30,
3043
+ label: "\u6A21\u578B\u8DEF\u7531"
3044
+ }, RouterPanelIcon))), "model-router-galgame: sidebar entry");
3045
+ ctx.effect(() => ctx.configForms.whileServed([ROUTER_NAMESPACE], () => ctx.slots.inject("plugins.detail.actions", () => ctx.slots.register({
3046
+ name: "plugins.detail.actions",
3047
+ id: "model-router-open-workspace",
3048
+ order: 30,
3049
+ inject: () => ({ openPanel: () => ctx.layout.selectPanel(ROUTER_PANEL) })
3050
+ }, OpenRouterWorkspace))), "model-router-galgame: bundle open action");
3051
+ }
3052
+ async function apply(ctx) {
3053
+ const disposeRemote = await ctx.remote.$mount(OFFICIAL_TOOLS_CLIENT_REMOTE);
3054
+ const ui = ctx.inject(UI_INJECT, registerUi);
3055
+ try {
3056
+ await ui;
3057
+ } catch (error) {
3058
+ await ui.dispose();
3059
+ await disposeRemote();
3060
+ throw error;
3061
+ }
3062
+ return async () => {
3063
+ await ui.dispose();
3064
+ await disposeRemote();
3065
+ };
3066
+ }
3067
+ var styles = Object.freeze({
3068
+ titleLine: { display: "flex", alignItems: "center", flexWrap: "wrap", gap: "8px" },
3069
+ notice: {
3070
+ marginTop: "4px",
3071
+ padding: "12px",
3072
+ border: "1px solid var(--dsw-alias-border-l1)",
3073
+ borderRadius: "8px",
3074
+ background: "var(--dsw-alias-markdown-code-block)"
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" },
3078
+ noticeText: {
3079
+ margin: "7px 0 0",
3080
+ color: "var(--dsw-alias-label-secondary)",
3081
+ fontSize: "13px",
3082
+ lineHeight: "20px"
3083
+ },
3084
+ profileEditor: { display: "grid", gap: "8px", marginTop: "14px" },
3085
+ profileLabel: { fontSize: "13px", fontWeight: 600 },
3086
+ profileTextarea: { width: "100%", minHeight: "150px", padding: "10px", fontFamily: "monospace", fontSize: "12px", borderRadius: "7px", border: "1px solid var(--dsw-alias-border-l1)", boxSizing: "border-box" },
3087
+ profileError: { color: "var(--dsw-alias-label-danger)", fontSize: "12px", margin: 0 },
3088
+ profileExample: { fontSize: "12px", whiteSpace: "pre-wrap" }
3089
+ });
3090
+ return module.exports;
3091
+ },
3092
+ });