@ljwei-stak/dsh-model-router 0.16.4 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dsh-plugin/client.js +920 -102
- package/.dsh-plugin/index.mjs +133 -27
- package/.dsh-plugin/official-tools-remote-service.mjs +82 -10
- package/.dsh-plugin/shared/latest-versions.mjs +19 -0
- package/.dsh-plugin/shared/official-tool-executor.mjs +8 -0
- package/.dsh-plugin/shared/official-tool-registry.mjs +393 -12
- package/.dsh-plugin/shared/official-tools-remote.mjs +38 -2
- package/.dsh-plugin/shared/official-tools-runtime.mjs +599 -68
- package/.dsh-plugin/shared/tool-health.mjs +7 -0
- package/.dsh-plugin/shared/tool-install-preferences.mjs +346 -0
- package/CHANGELOG.md +26 -1
- package/README.md +13 -3
- package/README.zh.md +13 -3
- package/{INSTALLATION_GUIDE.zh.md → docs/INSTALLATION_GUIDE.zh.md} +7 -7
- package/docs/WORKBENCH_USER_GUIDE.zh.md +36 -5
- package/{MIGRATION.md → docs/archive/MIGRATION.md} +1 -1
- package/docs/archive/README.md +21 -0
- package/package.json +5 -4
package/.dsh-plugin/client.js
CHANGED
|
@@ -46,6 +46,53 @@ module.exports = __toCommonJS(official_harness_exports);
|
|
|
46
46
|
var import_react6 = __toESM(require("react"), 1);
|
|
47
47
|
|
|
48
48
|
// .dsh-plugin/shared/official-tool-registry.mjs
|
|
49
|
+
var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
50
|
+
function packageManagerMethod(id2, label, manager, spec, { registryFlag = "--registry=" } = {}) {
|
|
51
|
+
return Object.freeze({
|
|
52
|
+
id: id2,
|
|
53
|
+
label,
|
|
54
|
+
kind: "package-manager",
|
|
55
|
+
manager,
|
|
56
|
+
spec,
|
|
57
|
+
registryFlag,
|
|
58
|
+
installArgs: Object.freeze(["install", "-g", spec]),
|
|
59
|
+
uninstallArgs: Object.freeze(["uninstall", "-g", spec.replace(/@latest$/, "")]),
|
|
60
|
+
/** npm/pnpm both accept --prefix to place a global install off the default. */
|
|
61
|
+
supportsInstallDir: true,
|
|
62
|
+
supportsRegistry: true
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function scriptMethod(id2, label, {
|
|
66
|
+
shell,
|
|
67
|
+
scriptUrl,
|
|
68
|
+
verify,
|
|
69
|
+
installArg = [],
|
|
70
|
+
env = [],
|
|
71
|
+
platforms,
|
|
72
|
+
installDirEnv = "",
|
|
73
|
+
defaultInstallDir = ""
|
|
74
|
+
}) {
|
|
75
|
+
return Object.freeze({
|
|
76
|
+
id: id2,
|
|
77
|
+
label,
|
|
78
|
+
kind: "script",
|
|
79
|
+
shell,
|
|
80
|
+
scriptUrl,
|
|
81
|
+
verify,
|
|
82
|
+
/** Passed after the staged script path; empty means the script takes no argument. */
|
|
83
|
+
installArgs: Object.freeze(installArg),
|
|
84
|
+
/** Environment the vendor script itself documents for this install. */
|
|
85
|
+
env: Object.freeze(env),
|
|
86
|
+
/** When set, the configured directory is this environment variable, not an argv flag. */
|
|
87
|
+
installDirEnv,
|
|
88
|
+
/** Home-relative directory the vendor uses when the user sets none. Slashes only. */
|
|
89
|
+
defaultInstallDir,
|
|
90
|
+
platforms: Object.freeze(platforms),
|
|
91
|
+
/** Whether the vendor script honours a caller-chosen directory at all. */
|
|
92
|
+
supportsInstallDir: Boolean(installDirEnv) || installArg.length > 0,
|
|
93
|
+
supportsRegistry: false
|
|
94
|
+
});
|
|
95
|
+
}
|
|
49
96
|
var OFFICIAL_TOOLS = Object.freeze([
|
|
50
97
|
Object.freeze({
|
|
51
98
|
id: "kimi-code",
|
|
@@ -55,9 +102,41 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
55
102
|
package: "@moonshot-ai/kimi-code",
|
|
56
103
|
manager: "npm",
|
|
57
104
|
installArgs: ["install", "-g", "@moonshot-ai/kimi-code@latest", "--registry=https://registry.npmjs.org/"],
|
|
105
|
+
uninstallArgs: ["uninstall", "-g", "@moonshot-ai/kimi-code"],
|
|
58
106
|
probeExecutables: ["kimi"],
|
|
59
107
|
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",
|
|
60
|
-
providerHints: ["moonshot", "kimi"]
|
|
108
|
+
providerHints: ["moonshot", "kimi"],
|
|
109
|
+
scriptBinaryNames: Object.freeze(["kimi", "kimi.exe"]),
|
|
110
|
+
scriptBinaryRelatives: Object.freeze(["bin/kimi", "bin/kimi.exe"]),
|
|
111
|
+
defaultScriptInstallDir: ".kimi-code",
|
|
112
|
+
installMethods: Object.freeze([
|
|
113
|
+
packageManagerMethod("npm", "npm", "npm", "@moonshot-ai/kimi-code@latest"),
|
|
114
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@moonshot-ai/kimi-code@latest"),
|
|
115
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
116
|
+
shell: "bash",
|
|
117
|
+
scriptUrl: "https://code.kimi.com/kimi-code/install.sh",
|
|
118
|
+
platforms: ["linux", "darwin"],
|
|
119
|
+
installDirEnv: "KIMI_INSTALL_DIR",
|
|
120
|
+
defaultInstallDir: ".kimi-code",
|
|
121
|
+
env: ["KIMI_INSTALL_DIR"],
|
|
122
|
+
verify: Object.freeze({
|
|
123
|
+
mustInclude: ["code.kimi.com/kimi-code", "KIMI_INSTALL_DIR"],
|
|
124
|
+
mustNotInclude: ["downloads.claude.ai/claude-code-releases", "@minimax-ai/code"]
|
|
125
|
+
})
|
|
126
|
+
}),
|
|
127
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
128
|
+
shell: "powershell",
|
|
129
|
+
scriptUrl: "https://code.kimi.com/kimi-code/install.ps1",
|
|
130
|
+
platforms: ["win32"],
|
|
131
|
+
installDirEnv: "KIMI_INSTALL_DIR",
|
|
132
|
+
defaultInstallDir: ".kimi-code",
|
|
133
|
+
env: ["KIMI_INSTALL_DIR"],
|
|
134
|
+
verify: Object.freeze({
|
|
135
|
+
mustInclude: ["code.kimi.com/kimi-code", "KIMI_INSTALL_DIR"],
|
|
136
|
+
mustNotInclude: ["downloads.claude.ai/claude-code-releases", "@minimax-ai/code"]
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
])
|
|
61
140
|
}),
|
|
62
141
|
Object.freeze({
|
|
63
142
|
id: "claude-code",
|
|
@@ -67,8 +146,36 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
67
146
|
package: "@anthropic-ai/claude-code",
|
|
68
147
|
manager: "npm",
|
|
69
148
|
installArgs: ["install", "-g", "@anthropic-ai/claude-code@latest", "--registry=https://registry.npmjs.org/"],
|
|
149
|
+
uninstallArgs: ["uninstall", "-g", "@anthropic-ai/claude-code"],
|
|
70
150
|
probeExecutables: ["claude"],
|
|
71
|
-
providerHints: ["anthropic", "claude"]
|
|
151
|
+
providerHints: ["anthropic", "claude"],
|
|
152
|
+
// The native installer always lands in ~/.local/bin; it has no directory flag.
|
|
153
|
+
scriptBinaryNames: Object.freeze(["claude", "claude.exe"]),
|
|
154
|
+
defaultScriptInstallDir: ".local/bin",
|
|
155
|
+
installMethods: Object.freeze([
|
|
156
|
+
packageManagerMethod("npm", "npm", "npm", "@anthropic-ai/claude-code@latest"),
|
|
157
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@anthropic-ai/claude-code@latest"),
|
|
158
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
159
|
+
shell: "bash",
|
|
160
|
+
scriptUrl: "https://claude.ai/install.sh",
|
|
161
|
+
platforms: ["linux", "darwin"],
|
|
162
|
+
defaultInstallDir: ".local/bin",
|
|
163
|
+
verify: Object.freeze({
|
|
164
|
+
mustInclude: ["downloads.claude.ai/claude-code-releases", "claude.ai/install.sh"],
|
|
165
|
+
mustNotInclude: ["@minimax-ai/code", "releases.openai.com/codex"]
|
|
166
|
+
})
|
|
167
|
+
}),
|
|
168
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
169
|
+
shell: "powershell",
|
|
170
|
+
scriptUrl: "https://claude.ai/install.ps1",
|
|
171
|
+
platforms: ["win32"],
|
|
172
|
+
defaultInstallDir: ".local/bin",
|
|
173
|
+
verify: Object.freeze({
|
|
174
|
+
mustInclude: ["downloads.claude.ai/claude-code-releases"],
|
|
175
|
+
mustNotInclude: ["@minimax-ai/code", "releases.openai.com/codex"]
|
|
176
|
+
})
|
|
177
|
+
})
|
|
178
|
+
])
|
|
72
179
|
}),
|
|
73
180
|
Object.freeze({
|
|
74
181
|
id: "codex",
|
|
@@ -76,11 +183,42 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
76
183
|
vendor: "OpenAI",
|
|
77
184
|
purpose: "OpenAI \u5B98\u65B9\u7F16\u7A0B CLI\uFF0C\u63D0\u4F9B codex \u547D\u4EE4\u3002",
|
|
78
185
|
package: "@openai/codex",
|
|
79
|
-
installArgs: ["install", "-g", "@openai/codex@latest", "--registry=https://registry.npmjs.org/"],
|
|
80
186
|
manager: "npm",
|
|
187
|
+
installArgs: ["install", "-g", "@openai/codex@latest", "--registry=https://registry.npmjs.org/"],
|
|
188
|
+
uninstallArgs: ["uninstall", "-g", "@openai/codex"],
|
|
81
189
|
probeExecutables: ["codex"],
|
|
82
190
|
probeNote: "Codex \u7248\u672C\u6A2A\u5E45\u7531\u9002\u914D\u5C42\u5BBD\u5339\u914D\uFF1B\u5B89\u88C5\u65F6\u53D6 npm \u6700\u65B0\u7248\u3002",
|
|
83
|
-
providerHints: ["openai", "gpt", "codex"]
|
|
191
|
+
providerHints: ["openai", "gpt", "codex"],
|
|
192
|
+
scriptBinaryNames: Object.freeze(["codex", "codex.exe"]),
|
|
193
|
+
installMethods: Object.freeze([
|
|
194
|
+
packageManagerMethod("npm", "npm", "npm", "@openai/codex@latest"),
|
|
195
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@openai/codex@latest"),
|
|
196
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
197
|
+
shell: "bash",
|
|
198
|
+
scriptUrl: "https://chatgpt.com/codex/install.sh",
|
|
199
|
+
platforms: ["linux", "darwin"],
|
|
200
|
+
installDirEnv: "CODEX_INSTALL_DIR",
|
|
201
|
+
defaultInstallDir: ".local/bin",
|
|
202
|
+
env: ["CODEX_INSTALL_DIR"],
|
|
203
|
+
verify: Object.freeze({
|
|
204
|
+
mustInclude: ["releases.openai.com/codex", "CODEX_INSTALL_DIR"],
|
|
205
|
+
mustNotInclude: ["downloads.claude.ai/claude-code-releases", "@minimax-ai/code"]
|
|
206
|
+
})
|
|
207
|
+
}),
|
|
208
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
209
|
+
shell: "powershell",
|
|
210
|
+
scriptUrl: "https://chatgpt.com/codex/install.ps1",
|
|
211
|
+
platforms: ["win32"],
|
|
212
|
+
installDirEnv: "CODEX_INSTALL_DIR",
|
|
213
|
+
// %LOCALAPPDATA%\Programs\OpenAI\Codex\bin under a normal user profile.
|
|
214
|
+
defaultInstallDir: "AppData/Local/Programs/OpenAI/Codex/bin",
|
|
215
|
+
env: ["CODEX_INSTALL_DIR"],
|
|
216
|
+
verify: Object.freeze({
|
|
217
|
+
mustInclude: ["releases.openai.com/codex", "CODEX_INSTALL_DIR"],
|
|
218
|
+
mustNotInclude: ["downloads.claude.ai/claude-code-releases", "@minimax-ai/code"]
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
])
|
|
84
222
|
}),
|
|
85
223
|
Object.freeze({
|
|
86
224
|
id: "minimax-code",
|
|
@@ -90,8 +228,55 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
90
228
|
package: "@minimax-ai/code",
|
|
91
229
|
manager: "npm",
|
|
92
230
|
installArgs: ["install", "-g", "@minimax-ai/code@latest", "--registry=https://registry.npmjs.org/", "--ignore-scripts=false", "--include=optional", "--allow-scripts=@minimax-ai/code,better-sqlite3"],
|
|
231
|
+
uninstallArgs: ["uninstall", "-g", "@minimax-ai/code"],
|
|
93
232
|
probeExecutables: ["mcode"],
|
|
94
|
-
providerHints: ["minimax"]
|
|
233
|
+
providerHints: ["minimax"],
|
|
234
|
+
scriptBinaryNames: Object.freeze([
|
|
235
|
+
"mcode",
|
|
236
|
+
"mcode.exe",
|
|
237
|
+
"mcode.cmd",
|
|
238
|
+
"mcode.ps1",
|
|
239
|
+
"mcode-tools",
|
|
240
|
+
"mcode-tools.cmd",
|
|
241
|
+
"mcode-tools.ps1"
|
|
242
|
+
]),
|
|
243
|
+
scriptBinaryRelatives: Object.freeze([
|
|
244
|
+
"mcode.cmd",
|
|
245
|
+
"mcode.ps1",
|
|
246
|
+
"mcode-tools.cmd",
|
|
247
|
+
"mcode-tools.ps1",
|
|
248
|
+
"bin/mcode",
|
|
249
|
+
"bin/mcode-tools"
|
|
250
|
+
]),
|
|
251
|
+
defaultScriptInstallDir: ".minimax-code",
|
|
252
|
+
installMethods: Object.freeze([
|
|
253
|
+
packageManagerMethod("npm", "npm", "npm", "@minimax-ai/code@latest"),
|
|
254
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@minimax-ai/code@latest"),
|
|
255
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
256
|
+
shell: "bash",
|
|
257
|
+
scriptUrl: "https://filecdn.minimax.chat/public/install.sh",
|
|
258
|
+
platforms: ["linux", "darwin"],
|
|
259
|
+
installDirEnv: "MCODE_INSTALL_DIR",
|
|
260
|
+
defaultInstallDir: ".minimax-code",
|
|
261
|
+
env: ["MCODE_INSTALL_DIR", "MCODE_NPM_REGISTRY"],
|
|
262
|
+
verify: Object.freeze({
|
|
263
|
+
mustInclude: ["@minimax-ai/code", "MCODE_INSTALL_DIR", "MiniMax Code"],
|
|
264
|
+
mustNotInclude: ["downloads.claude.ai/claude-code-releases", "releases.openai.com/codex"]
|
|
265
|
+
})
|
|
266
|
+
}),
|
|
267
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
268
|
+
shell: "powershell",
|
|
269
|
+
scriptUrl: "https://filecdn.minimax.chat/public/install.ps1",
|
|
270
|
+
platforms: ["win32"],
|
|
271
|
+
installDirEnv: "MCODE_INSTALL_DIR",
|
|
272
|
+
defaultInstallDir: ".minimax-code",
|
|
273
|
+
env: ["MCODE_INSTALL_DIR", "MCODE_NPM_REGISTRY"],
|
|
274
|
+
verify: Object.freeze({
|
|
275
|
+
mustInclude: ["@minimax-ai/code", "MCODE_INSTALL_DIR", "MiniMax Code"],
|
|
276
|
+
mustNotInclude: ["downloads.claude.ai/claude-code-releases", "releases.openai.com/codex"]
|
|
277
|
+
})
|
|
278
|
+
})
|
|
279
|
+
])
|
|
95
280
|
}),
|
|
96
281
|
Object.freeze({
|
|
97
282
|
id: "mimo-code",
|
|
@@ -101,8 +286,38 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
101
286
|
package: "@mimo-ai/cli",
|
|
102
287
|
manager: "npm",
|
|
103
288
|
installArgs: ["install", "-g", "@mimo-ai/cli@latest", "--registry=https://registry.npmjs.org/"],
|
|
289
|
+
uninstallArgs: ["uninstall", "-g", "@mimo-ai/cli"],
|
|
104
290
|
probeExecutables: ["mimo"],
|
|
105
|
-
providerHints: ["mimo", "xiaomi"]
|
|
291
|
+
providerHints: ["mimo", "xiaomi"],
|
|
292
|
+
scriptBinaryNames: Object.freeze(["mimo", "mimo.exe"]),
|
|
293
|
+
defaultScriptInstallDir: ".mimocode/bin",
|
|
294
|
+
installMethods: Object.freeze([
|
|
295
|
+
packageManagerMethod("npm", "npm", "npm", "@mimo-ai/cli@latest"),
|
|
296
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@mimo-ai/cli@latest"),
|
|
297
|
+
// The Unix script hardcodes ~/.mimocode/bin and ignores MIMOCODE_INSTALL_DIR.
|
|
298
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
299
|
+
shell: "bash",
|
|
300
|
+
scriptUrl: "https://mimo.xiaomi.com/install",
|
|
301
|
+
platforms: ["linux", "darwin"],
|
|
302
|
+
defaultInstallDir: ".mimocode/bin",
|
|
303
|
+
verify: Object.freeze({
|
|
304
|
+
mustInclude: ["MiMoCode", "mimo.xiaomi.com"],
|
|
305
|
+
mustNotInclude: ["@minimax-ai/code", "downloads.claude.ai/claude-code-releases"]
|
|
306
|
+
})
|
|
307
|
+
}),
|
|
308
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
309
|
+
shell: "powershell",
|
|
310
|
+
scriptUrl: "https://mimo.xiaomi.com/install.ps1",
|
|
311
|
+
platforms: ["win32"],
|
|
312
|
+
installDirEnv: "MIMOCODE_INSTALL_DIR",
|
|
313
|
+
defaultInstallDir: ".mimocode/bin",
|
|
314
|
+
env: ["MIMOCODE_INSTALL_DIR"],
|
|
315
|
+
verify: Object.freeze({
|
|
316
|
+
mustInclude: ["MiMoCode", "mimo.xiaomi.com", "MIMOCODE_INSTALL_DIR"],
|
|
317
|
+
mustNotInclude: ["@minimax-ai/code", "downloads.claude.ai/claude-code-releases"]
|
|
318
|
+
})
|
|
319
|
+
})
|
|
320
|
+
])
|
|
106
321
|
}),
|
|
107
322
|
Object.freeze({
|
|
108
323
|
id: "grok-build",
|
|
@@ -112,8 +327,39 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
112
327
|
package: "@xai-official/grok",
|
|
113
328
|
manager: "npm",
|
|
114
329
|
installArgs: ["install", "-g", "@xai-official/grok@latest", "--registry=https://registry.npmjs.org/"],
|
|
330
|
+
uninstallArgs: ["uninstall", "-g", "@xai-official/grok"],
|
|
115
331
|
probeExecutables: ["grok"],
|
|
116
|
-
providerHints: ["xai", "grok"]
|
|
332
|
+
providerHints: ["xai", "grok"],
|
|
333
|
+
scriptBinaryNames: Object.freeze(["grok", "grok.exe", "agent", "agent.exe"]),
|
|
334
|
+
defaultScriptInstallDir: ".grok/bin",
|
|
335
|
+
installMethods: Object.freeze([
|
|
336
|
+
packageManagerMethod("npm", "npm", "npm", "@xai-official/grok@latest"),
|
|
337
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@xai-official/grok@latest"),
|
|
338
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
339
|
+
shell: "bash",
|
|
340
|
+
scriptUrl: "https://x.ai/cli/install.sh",
|
|
341
|
+
platforms: ["linux", "darwin"],
|
|
342
|
+
installDirEnv: "GROK_BIN_DIR",
|
|
343
|
+
defaultInstallDir: ".grok/bin",
|
|
344
|
+
env: ["GROK_BIN_DIR"],
|
|
345
|
+
verify: Object.freeze({
|
|
346
|
+
mustInclude: ["x.ai/cli", "GROK_BIN_DIR"],
|
|
347
|
+
mustNotInclude: ["@minimax-ai/code", "downloads.claude.ai/claude-code-releases"]
|
|
348
|
+
})
|
|
349
|
+
}),
|
|
350
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
351
|
+
shell: "powershell",
|
|
352
|
+
scriptUrl: "https://x.ai/cli/install.ps1",
|
|
353
|
+
platforms: ["win32"],
|
|
354
|
+
installDirEnv: "GROK_BIN_DIR",
|
|
355
|
+
defaultInstallDir: ".grok/bin",
|
|
356
|
+
env: ["GROK_BIN_DIR"],
|
|
357
|
+
verify: Object.freeze({
|
|
358
|
+
mustInclude: ["x.ai/cli", "GROK_BIN_DIR"],
|
|
359
|
+
mustNotInclude: ["@minimax-ai/code", "downloads.claude.ai/claude-code-releases"]
|
|
360
|
+
})
|
|
361
|
+
})
|
|
362
|
+
])
|
|
117
363
|
}),
|
|
118
364
|
Object.freeze({
|
|
119
365
|
id: "gemini",
|
|
@@ -123,11 +369,91 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
123
369
|
package: "@google/gemini-cli",
|
|
124
370
|
manager: "npm",
|
|
125
371
|
installArgs: ["install", "-g", "@google/gemini-cli@latest", "--registry=https://registry.npmjs.org/"],
|
|
372
|
+
uninstallArgs: ["uninstall", "-g", "@google/gemini-cli"],
|
|
126
373
|
probeExecutables: ["gemini"],
|
|
127
374
|
providerHints: ["gemini", "google"],
|
|
128
375
|
// Headless runs go through the task adapter. The signed sandbox runner does
|
|
129
376
|
// not launch this CLI; a missing or failed process falls back to the API.
|
|
130
|
-
headlessAdapter: true
|
|
377
|
+
headlessAdapter: true,
|
|
378
|
+
installMethods: Object.freeze([
|
|
379
|
+
packageManagerMethod("npm", "npm", "npm", "@google/gemini-cli@latest"),
|
|
380
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@google/gemini-cli@latest")
|
|
381
|
+
])
|
|
382
|
+
}),
|
|
383
|
+
Object.freeze({
|
|
384
|
+
id: "opencode",
|
|
385
|
+
label: "OpenCode",
|
|
386
|
+
vendor: "anomalyco / SST",
|
|
387
|
+
purpose: "\u5F00\u6E90\u7EC8\u7AEF\u7F16\u7A0B\u4EE3\u7406\uFF0C\u63D0\u4F9B opencode \u547D\u4EE4\uFF1B\u53EF\u7528 npm/pnpm \u6216\u5B98\u65B9\u5B89\u88C5\u811A\u672C\u83B7\u53D6\u3002",
|
|
388
|
+
package: "opencode-ai",
|
|
389
|
+
manager: "npm",
|
|
390
|
+
installArgs: ["install", "-g", "opencode-ai@latest", "--registry=https://registry.npmjs.org/"],
|
|
391
|
+
uninstallArgs: ["uninstall", "-g", "opencode-ai"],
|
|
392
|
+
probeExecutables: ["opencode"],
|
|
393
|
+
probeNote: "opencode \u547D\u4EE4\u7531 npm \u5168\u5C40\u5305\u6216\u5B98\u65B9\u811A\u672C\u5B89\u88C5\u7684\u4E8C\u8FDB\u5236\u63D0\u4F9B\uFF1B\u811A\u672C\u5B89\u88C5\u56FA\u5B9A\u843D\u5728 ~/.opencode/bin\u3002",
|
|
394
|
+
providerHints: ["opencode", "anomalyco"],
|
|
395
|
+
/** File an uninstall may delete, when the copy came from a script install. */
|
|
396
|
+
scriptBinaryNames: Object.freeze(["opencode", "opencode.exe"]),
|
|
397
|
+
/** Where the vendor script puts the binary when the user sets no directory. */
|
|
398
|
+
defaultScriptInstallDir: ".opencode/bin",
|
|
399
|
+
installMethods: Object.freeze([
|
|
400
|
+
packageManagerMethod("npm", "npm", "npm", "opencode-ai@latest"),
|
|
401
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "opencode-ai@latest"),
|
|
402
|
+
// The published script hardcodes $HOME/.opencode/bin, so it cannot honour
|
|
403
|
+
// a custom install directory; the npm/pnpm methods above can.
|
|
404
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
405
|
+
shell: "bash",
|
|
406
|
+
scriptUrl: "https://opencode.ai/install",
|
|
407
|
+
platforms: ["linux", "darwin"],
|
|
408
|
+
defaultInstallDir: ".opencode/bin",
|
|
409
|
+
verify: Object.freeze({
|
|
410
|
+
mustInclude: ["anomalyco/opencode", "opencode.ai"],
|
|
411
|
+
mustNotInclude: ["static-openapi.stepfun.com"]
|
|
412
|
+
})
|
|
413
|
+
})
|
|
414
|
+
])
|
|
415
|
+
}),
|
|
416
|
+
Object.freeze({
|
|
417
|
+
id: "stepcode",
|
|
418
|
+
label: "Step Code",
|
|
419
|
+
vendor: "StepFun \u9636\u8DC3\u661F\u8FB0",
|
|
420
|
+
purpose: "\u9636\u8DC3\u661F\u8FB0\u5F00\u6E90\u7EC8\u7AEF\u7F16\u7A0B\u4EE3\u7406\uFF0C\u63D0\u4F9B step \u547D\u4EE4\uFF1B\u5B98\u65B9\u53EA\u53D1\u5E03\u5B89\u88C5\u811A\u672C\uFF0C\u6CA1\u6709 npm \u5305\u3002",
|
|
421
|
+
manager: "script-installer",
|
|
422
|
+
installArgs: [],
|
|
423
|
+
uninstallArgs: [],
|
|
424
|
+
probeExecutables: ["step"],
|
|
425
|
+
probeNote: "step \u547D\u4EE4\u6765\u81EA\u9636\u8DC3\u5B98\u65B9\u5B89\u88C5\u811A\u672C\uFF0C\u6821\u9A8C\u548C\u5199\u5165 ~/.stepcode\uFF1B\u914D\u7F6E\u4E0E\u51ED\u636E\u540C\u5728\u8BE5\u76EE\u5F55\uFF0C\u5378\u8F7D\u53EA\u5220\u9664\u53EF\u6267\u884C\u6587\u4EF6\u3002",
|
|
426
|
+
providerHints: ["stepfun", "stepcode"],
|
|
427
|
+
scriptBinaryNames: Object.freeze(["step", "step.exe"]),
|
|
428
|
+
defaultScriptInstallDir: ".stepcode/bin",
|
|
429
|
+
/** The vendor installer writes this marked block into the shell profile. */
|
|
430
|
+
pathProfileMarkers: Object.freeze(["# stepcode"]),
|
|
431
|
+
installMethods: Object.freeze([
|
|
432
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
433
|
+
shell: "bash",
|
|
434
|
+
scriptUrl: "https://static-openapi.stepfun.com/stepcode/install.sh",
|
|
435
|
+
platforms: ["linux", "darwin"],
|
|
436
|
+
installArg: ["--install-dir"],
|
|
437
|
+
env: ["STEP_INSTALL_DIR", "STEP_RELEASE_BASE_URL"],
|
|
438
|
+
defaultInstallDir: ".stepcode/bin",
|
|
439
|
+
verify: Object.freeze({
|
|
440
|
+
mustInclude: ["static-openapi.stepfun.com", "stepcode installer"],
|
|
441
|
+
mustNotInclude: ["anomalyco/opencode"]
|
|
442
|
+
})
|
|
443
|
+
}),
|
|
444
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
445
|
+
shell: "powershell",
|
|
446
|
+
scriptUrl: "https://static-openapi.stepfun.com/stepcode/install.ps1",
|
|
447
|
+
platforms: ["win32"],
|
|
448
|
+
installArg: ["-InstallDir"],
|
|
449
|
+
env: ["STEP_INSTALL_DIR", "STEP_RELEASE_BASE_URL"],
|
|
450
|
+
defaultInstallDir: ".stepcode/bin",
|
|
451
|
+
verify: Object.freeze({
|
|
452
|
+
mustInclude: ["static-openapi.stepfun.com", "stepcode"],
|
|
453
|
+
mustNotInclude: ["anomalyco/opencode"]
|
|
454
|
+
})
|
|
455
|
+
})
|
|
456
|
+
])
|
|
131
457
|
}),
|
|
132
458
|
Object.freeze({
|
|
133
459
|
id: "zcode",
|
|
@@ -136,6 +462,7 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
136
462
|
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",
|
|
137
463
|
manager: "signed-windows-installer",
|
|
138
464
|
installArgs: [],
|
|
465
|
+
uninstallArgs: [],
|
|
139
466
|
probeExecutables: [],
|
|
140
467
|
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",
|
|
141
468
|
providerHints: ["zai", "z.ai", "zcode", "glm", "zhipu", "bigmodel"]
|
|
@@ -153,10 +480,30 @@ function toolForProvider(provider) {
|
|
|
153
480
|
}
|
|
154
481
|
return null;
|
|
155
482
|
}
|
|
483
|
+
function installMethodsFor(tool) {
|
|
484
|
+
return Array.isArray(tool?.installMethods) ? tool.installMethods : [];
|
|
485
|
+
}
|
|
486
|
+
function installMethodFor(tool, methodId) {
|
|
487
|
+
const wanted = String(methodId ?? "").trim();
|
|
488
|
+
if (!wanted) return null;
|
|
489
|
+
return installMethodsFor(tool).find((method) => method.id === wanted) ?? null;
|
|
490
|
+
}
|
|
491
|
+
function defaultInstallMethod(tool) {
|
|
492
|
+
return installMethodsFor(tool)[0] ?? null;
|
|
493
|
+
}
|
|
156
494
|
function installCommandLine(tool) {
|
|
157
495
|
if (!tool || tool.unsupported) return null;
|
|
158
496
|
if (tool.manager === "signed-windows-installer") return "\u6253\u5F00\u5B98\u65B9\u7B7E\u540D\u5B89\u88C5\u5668\uFF08\u9009\u62E9\u5B89\u88C5\u76EE\u5F55\uFF09";
|
|
159
|
-
return tool
|
|
497
|
+
return installCommandLineFor(tool, defaultInstallMethod(tool));
|
|
498
|
+
}
|
|
499
|
+
function installCommandLineFor(tool, method) {
|
|
500
|
+
if (!tool || tool.unsupported) return null;
|
|
501
|
+
if (!method) return null;
|
|
502
|
+
if (method.kind === "script") {
|
|
503
|
+
const piped = method.shell === "powershell" ? `irm ${method.scriptUrl} | iex` : `curl -fsSL ${method.scriptUrl} | bash`;
|
|
504
|
+
return method.installArgs.length ? `${piped} ${method.installArgs[0]} <\u5B89\u88C5\u76EE\u5F55>` : piped;
|
|
505
|
+
}
|
|
506
|
+
return `${method.manager} ${method.installArgs.join(" ")}`;
|
|
160
507
|
}
|
|
161
508
|
|
|
162
509
|
// .dsh-plugin/shared/model-profiles.mjs
|
|
@@ -411,6 +758,112 @@ function toolBoundary(toolId, { sandboxed = false, platform = "unknown" } = {})
|
|
|
411
758
|
};
|
|
412
759
|
}
|
|
413
760
|
|
|
761
|
+
// .dsh-plugin/shared/tool-install-preferences.mjs
|
|
762
|
+
var MAX_INSTALL_DIR_CHARS = 4096;
|
|
763
|
+
var MAX_SOURCE_URL_CHARS = 2048;
|
|
764
|
+
var MAX_OVERRIDES = 64;
|
|
765
|
+
function isAbsolutePath(value) {
|
|
766
|
+
const raw = String(value ?? "");
|
|
767
|
+
if (!raw) return false;
|
|
768
|
+
if (raw.startsWith("/")) return true;
|
|
769
|
+
if (/^[A-Za-z]:[\\/]/.test(raw)) return true;
|
|
770
|
+
return /^\\\\[^\\]+\\[^\\]+/.test(raw);
|
|
771
|
+
}
|
|
772
|
+
function joinPath(base, ...segments) {
|
|
773
|
+
const separator = String(base ?? "").includes("\\") && !String(base ?? "").includes("/") ? "\\" : "/";
|
|
774
|
+
const parts = [String(base ?? "").replace(/[\\/]+$/, ""), ...segments.map((item) => String(item ?? "").replace(/^[\\/]+|[\\/]+$/g, ""))];
|
|
775
|
+
return parts.filter(Boolean).join(separator) || separator;
|
|
776
|
+
}
|
|
777
|
+
function expandInstallDir(value, { home = "", env = {} } = {}) {
|
|
778
|
+
const raw = String(value ?? "").trim();
|
|
779
|
+
if (!raw) return "";
|
|
780
|
+
if (raw.includes("\0")) throw new Error("\u5B89\u88C5\u76EE\u5F55\u5305\u542B\u65E0\u6548\u5B57\u7B26\u3002");
|
|
781
|
+
let expanded = raw;
|
|
782
|
+
const userHome = String(home ?? "");
|
|
783
|
+
if (expanded === "~") expanded = userHome;
|
|
784
|
+
else if (expanded.startsWith("~/") || expanded.startsWith("~\\")) expanded = joinPath(userHome, expanded.slice(2));
|
|
785
|
+
expanded = expanded.replace(/%([A-Za-z_][A-Za-z0-9_]*)%/g, (match, name) => env[name] ?? match).replace(/\$([A-Za-z_][A-Za-z0-9_]*)/g, (match, name) => env[name] ?? match);
|
|
786
|
+
if (expanded.length > MAX_INSTALL_DIR_CHARS) throw new Error("\u5B89\u88C5\u76EE\u5F55\u8FC7\u957F\u3002");
|
|
787
|
+
if (!isAbsolutePath(expanded)) throw new Error("\u5B89\u88C5\u76EE\u5F55\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002");
|
|
788
|
+
const withoutTrailing = expanded.replace(/[\\/]+$/, "");
|
|
789
|
+
if (!withoutTrailing) throw new Error("\u5B89\u88C5\u76EE\u5F55\u4E0D\u80FD\u662F\u6587\u4EF6\u7CFB\u7EDF\u6839\u76EE\u5F55\u3002");
|
|
790
|
+
if (/^[A-Za-z]:$/.test(withoutTrailing)) throw new Error("\u5B89\u88C5\u76EE\u5F55\u4E0D\u80FD\u662F\u6587\u4EF6\u7CFB\u7EDF\u6839\u76EE\u5F55\u3002");
|
|
791
|
+
if (/^\\\\[^\\]+\\[^\\]+$/.test(withoutTrailing)) throw new Error("\u5B89\u88C5\u76EE\u5F55\u4E0D\u80FD\u662F\u7F51\u7EDC\u5171\u4EAB\u6839\u76EE\u5F55\u3002");
|
|
792
|
+
return expanded;
|
|
793
|
+
}
|
|
794
|
+
function normalizeSourceUrl(value, subject) {
|
|
795
|
+
const raw = String(value ?? "").trim();
|
|
796
|
+
if (!raw) return "";
|
|
797
|
+
if (raw.length > MAX_SOURCE_URL_CHARS) throw new Error(`${subject}\u5730\u5740\u8FC7\u957F\u3002`);
|
|
798
|
+
let url;
|
|
799
|
+
try {
|
|
800
|
+
url = new URL(raw);
|
|
801
|
+
} catch {
|
|
802
|
+
throw new Error(`${subject}\u4E0D\u662F\u6709\u6548\u7F51\u5740\u3002`);
|
|
803
|
+
}
|
|
804
|
+
if (url.protocol !== "https:") throw new Error(`${subject}\u5FC5\u987B\u4F7F\u7528 https\u3002`);
|
|
805
|
+
if (url.username || url.password) throw new Error(`${subject}\u4E0D\u80FD\u5305\u542B\u8D26\u53F7\u5BC6\u7801\u3002`);
|
|
806
|
+
return url.toString();
|
|
807
|
+
}
|
|
808
|
+
function parseJsonObject(value, subject) {
|
|
809
|
+
const raw = String(value ?? "").trim();
|
|
810
|
+
if (!raw) return {};
|
|
811
|
+
let parsed;
|
|
812
|
+
try {
|
|
813
|
+
parsed = JSON.parse(raw);
|
|
814
|
+
} catch {
|
|
815
|
+
throw new Error(`${subject}\u4E0D\u662F\u6709\u6548 JSON\u3002`);
|
|
816
|
+
}
|
|
817
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
818
|
+
throw new Error(`${subject}\u5FC5\u987B\u662F JSON \u5BF9\u8C61\u3002`);
|
|
819
|
+
}
|
|
820
|
+
const entries = Object.entries(parsed);
|
|
821
|
+
if (entries.length > MAX_OVERRIDES) throw new Error(`${subject}\u6761\u76EE\u8FC7\u591A\u3002`);
|
|
822
|
+
return Object.fromEntries(entries.filter(([, item]) => typeof item === "string" && item.trim()));
|
|
823
|
+
}
|
|
824
|
+
function valueOf(config, key, fallback) {
|
|
825
|
+
const value = config?.[key];
|
|
826
|
+
return value !== void 0 && typeof value?.get === "function" ? value.get() : value ?? fallback;
|
|
827
|
+
}
|
|
828
|
+
function keepKnownToolIds(raw, known, subject) {
|
|
829
|
+
for (const key of Object.keys(raw)) {
|
|
830
|
+
if (!known.has(key)) throw new Error(`${subject}\u4E2D\u7684 ${key} \u4E0D\u662F\u5B98\u65B9\u5DE5\u5177 ID\u3002`);
|
|
831
|
+
}
|
|
832
|
+
return raw;
|
|
833
|
+
}
|
|
834
|
+
function parseInstallPreferences(config = {}, { tools = [] } = {}) {
|
|
835
|
+
const known = new Set(tools.map((tool) => tool.id));
|
|
836
|
+
const installDir = expandInstallDir(valueOf(config, "toolInstallDir", ""));
|
|
837
|
+
const registry = normalizeSourceUrl(valueOf(config, "toolNpmRegistry", DEFAULT_NPM_REGISTRY), "npm \u6E90") || DEFAULT_NPM_REGISTRY;
|
|
838
|
+
const methodRaw = keepKnownToolIds(
|
|
839
|
+
parseJsonObject(valueOf(config, "toolInstallMethodsJson", "{}"), "\u5B89\u88C5\u65B9\u5F0F\u8986\u76D6"),
|
|
840
|
+
known,
|
|
841
|
+
"\u5B89\u88C5\u65B9\u5F0F\u8986\u76D6"
|
|
842
|
+
);
|
|
843
|
+
const scriptRaw = keepKnownToolIds(
|
|
844
|
+
parseJsonObject(valueOf(config, "toolScriptUrlsJson", "{}"), "\u5B89\u88C5\u811A\u672C\u6E90\u8986\u76D6"),
|
|
845
|
+
known,
|
|
846
|
+
"\u5B89\u88C5\u811A\u672C\u6E90\u8986\u76D6"
|
|
847
|
+
);
|
|
848
|
+
const methods = {};
|
|
849
|
+
const scriptUrls = {};
|
|
850
|
+
for (const [id2, methodId] of Object.entries(methodRaw)) methods[id2] = methodId.trim();
|
|
851
|
+
for (const [id2, url] of Object.entries(scriptRaw)) scriptUrls[id2] = normalizeSourceUrl(url, `${id2} \u5B89\u88C5\u811A\u672C\u6E90`);
|
|
852
|
+
for (const [id2, methodId] of Object.entries(methods)) {
|
|
853
|
+
if (!installMethodFor({ id: id2, installMethods: tools.find((tool) => tool.id === id2)?.installMethods }, methodId)) {
|
|
854
|
+
throw new Error(`${id2} \u4E0D\u652F\u6301\u5B89\u88C5\u65B9\u5F0F ${methodId}\u3002`);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
return {
|
|
858
|
+
installDir,
|
|
859
|
+
registry,
|
|
860
|
+
methods,
|
|
861
|
+
scriptUrls,
|
|
862
|
+
/** Script execution stays a deliberate act; a config file alone must not run one. */
|
|
863
|
+
allowScriptInstall: valueOf(config, "toolAllowScriptInstall", true) !== false
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
|
|
414
867
|
// .dsh-plugin/client/router-main.jsx
|
|
415
868
|
var import_react5 = __toESM(require("react"), 1);
|
|
416
869
|
|
|
@@ -621,8 +1074,8 @@ var OPENCODE_CATALOG_PROVIDERS = Object.freeze([
|
|
|
621
1074
|
"opencode-zen",
|
|
622
1075
|
"opencode-go-zen"
|
|
623
1076
|
]);
|
|
624
|
-
function classifyTask(
|
|
625
|
-
const value = String(
|
|
1077
|
+
function classifyTask(text7) {
|
|
1078
|
+
const value = String(text7 ?? "");
|
|
626
1079
|
if (value.length < 80 && /翻译|解释|translate|explain/i.test(value)) return "general";
|
|
627
1080
|
return detectTaskTypes(value)[0] ?? "general";
|
|
628
1081
|
}
|
|
@@ -642,8 +1095,8 @@ var TASK_TYPE_LABELS = Object.freeze({
|
|
|
642
1095
|
summarization: "\u6458\u8981\u4E0E\u6574\u7406",
|
|
643
1096
|
writing: "\u5199\u4F5C\u4E0E\u8868\u8FBE"
|
|
644
1097
|
});
|
|
645
|
-
function detectTaskTypes(
|
|
646
|
-
const value = String(
|
|
1098
|
+
function detectTaskTypes(text7) {
|
|
1099
|
+
const value = String(text7 ?? "");
|
|
647
1100
|
const ranked = TASK_TYPE_RULES.map(([type, pattern]) => ({
|
|
648
1101
|
type,
|
|
649
1102
|
signals: value.match(new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`))?.length ?? 0
|
|
@@ -651,8 +1104,8 @@ function detectTaskTypes(text6) {
|
|
|
651
1104
|
ranked.sort((left, right) => right.signals - left.signals || left.type.localeCompare(right.type));
|
|
652
1105
|
return ranked.map((item) => item.type);
|
|
653
1106
|
}
|
|
654
|
-
function assessComplexity(
|
|
655
|
-
const value = String(
|
|
1107
|
+
function assessComplexity(text7) {
|
|
1108
|
+
const value = String(text7 ?? "");
|
|
656
1109
|
const lengthScore = clamp(value.length / 2200);
|
|
657
1110
|
const requirementScore = clamp((value.match(/(?:^|\n)\s*(?:[-*]|\d+[.)]|[一二三四五六七八九十]+[、.])/g) ?? []).length / 8);
|
|
658
1111
|
const codeScore = /(代码|工程|架构|接口|实现|部署|测试|code|api|debug)/i.test(value) ? 0.22 : 0;
|
|
@@ -732,10 +1185,10 @@ function normalizedCacheRatios(cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
|
732
1185
|
return { read, write };
|
|
733
1186
|
}
|
|
734
1187
|
var COST_REFERENCE_PRICING = Object.freeze({ input: 1, output: 5, cacheRead: 1, cacheWrite: 1, currency: "USD" });
|
|
735
|
-
function estimateCost(model,
|
|
1188
|
+
function estimateCost(model, text7, outputTokens = 900, pricingOverrides = {}, cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
736
1189
|
const pricing = pricingFor(model, pricingOverrides);
|
|
737
1190
|
if (pricing === null) return null;
|
|
738
|
-
const inputTokens = Math.max(80, Math.ceil(String(
|
|
1191
|
+
const inputTokens = Math.max(80, Math.ceil(String(text7 ?? "").length / 3.7));
|
|
739
1192
|
const ratios = normalizedCacheRatios(cacheReadRatio, cacheWriteRatio);
|
|
740
1193
|
const cacheReadTokens = Math.min(inputTokens, Math.max(0, Math.round(inputTokens * ratios.read)));
|
|
741
1194
|
const cacheWriteTokens = Math.min(inputTokens - cacheReadTokens, Math.max(0, Math.round(inputTokens * ratios.write)));
|
|
@@ -747,8 +1200,8 @@ function modelMetadata(name) {
|
|
|
747
1200
|
if (!key) return null;
|
|
748
1201
|
return MODEL_CATALOG.find((model) => model.aliases.some((alias) => key === normalize(alias))) ?? null;
|
|
749
1202
|
}
|
|
750
|
-
function taskTokenBudget(
|
|
751
|
-
const inputTokens = Math.max(80, Math.ceil(String(
|
|
1203
|
+
function taskTokenBudget(text7, task, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
1204
|
+
const inputTokens = Math.max(80, Math.ceil(String(text7 ?? "").length / 3.7));
|
|
752
1205
|
const multipliers = {
|
|
753
1206
|
analysis: { input: 0.9, output: 0.55 },
|
|
754
1207
|
execution: { input: 1.2, output: (task.difficulty ?? complexity) === "complex" ? 1.45 : 1 },
|
|
@@ -812,10 +1265,10 @@ function looksLikeRequirement(value) {
|
|
|
812
1265
|
const item = requirementText(value);
|
|
813
1266
|
return item.length >= 3 && !/[::]$/u.test(item) && !/(?:以下|下列|如下)(?:的)?(?:任务|需求|工作|事项|要求)/u.test(item) && REQUIREMENT_ACTION.test(item.slice(0, 32));
|
|
814
1267
|
}
|
|
815
|
-
function explicitRequirements(
|
|
1268
|
+
function explicitRequirements(text7) {
|
|
816
1269
|
const visibleLines = [];
|
|
817
1270
|
let fence = null;
|
|
818
|
-
for (const line of String(
|
|
1271
|
+
for (const line of String(text7 ?? "").split(/\r?\n/u)) {
|
|
819
1272
|
const marker2 = /^\s*(`{3,}|~{3,})/u.exec(line);
|
|
820
1273
|
if (fence) {
|
|
821
1274
|
if (marker2 && marker2[1][0] === fence.char && marker2[1].length >= fence.length && !line.slice(marker2[0].length).trim()) fence = null;
|
|
@@ -888,16 +1341,16 @@ function explicitStepReferences(objective) {
|
|
|
888
1341
|
}
|
|
889
1342
|
return [...found].sort((a, b2) => a - b2);
|
|
890
1343
|
}
|
|
891
|
-
function taskPackages(taskType,
|
|
1344
|
+
function taskPackages(taskType, text7, band) {
|
|
892
1345
|
if (band !== "complex") {
|
|
893
1346
|
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" };
|
|
894
1347
|
return [{ ...task, qualityFloor: taskQualityFloor(band, task) }];
|
|
895
1348
|
}
|
|
896
|
-
const value = String(
|
|
1349
|
+
const value = String(text7 ?? "");
|
|
897
1350
|
const packages = [
|
|
898
1351
|
{ id: "analysis", name: "\u95EE\u9898\u5EFA\u6A21\u4E0E\u7EA6\u675F\u63D0\u53D6", type: "reasoning", purpose: "analysis", difficulty: "balanced", criticality: 0.8, dependsOn: [], preferredReasoningEffort: "medium" }
|
|
899
1352
|
];
|
|
900
|
-
const requirements = explicitRequirements(
|
|
1353
|
+
const requirements = explicitRequirements(text7);
|
|
901
1354
|
if (requirements.length >= 2) {
|
|
902
1355
|
const groups = requirements.length > MAX_EXPLICIT_EXECUTION_PACKAGES ? [
|
|
903
1356
|
...requirements.slice(0, MAX_EXPLICIT_EXECUTION_PACKAGES - 1).map((item) => [item]),
|
|
@@ -924,7 +1377,7 @@ function taskPackages(taskType, text6, band) {
|
|
|
924
1377
|
});
|
|
925
1378
|
});
|
|
926
1379
|
} else {
|
|
927
|
-
const domains = [...new Set([...detectTaskTypes(
|
|
1380
|
+
const domains = [...new Set([...detectTaskTypes(text7), taskType].filter((type) => type !== "general"))];
|
|
928
1381
|
for (const type of domains.length > 0 ? domains : [taskType]) {
|
|
929
1382
|
const objective = value.split(/[,,。;;]|最后|然后|接着|并且/u).map((item) => item.trim()).filter((item) => detectTaskTypes(item).includes(type)).join("\uFF1B") || value;
|
|
930
1383
|
const difficulty = requirementDifficulty(objective, type);
|
|
@@ -1025,31 +1478,31 @@ function reasoningDecision(row, task) {
|
|
|
1025
1478
|
multiplier: reasoningEffortMultiplier(chosen)
|
|
1026
1479
|
};
|
|
1027
1480
|
}
|
|
1028
|
-
function candidateUtility(row, task, weights, cacheReadRatio = 0, cacheWriteRatio = 0,
|
|
1481
|
+
function candidateUtility(row, task, weights, cacheReadRatio = 0, cacheWriteRatio = 0, text7 = "", complexity = "balanced") {
|
|
1029
1482
|
const quality = qualityForTask(row, task.type);
|
|
1030
1483
|
const rawPreference = row.preferenceAdjustments?.[task.type];
|
|
1031
1484
|
const preferenceAdjustment = Number.isFinite(rawPreference) ? clamp(rawPreference, -0.1, 0.1) : 0;
|
|
1032
1485
|
const floor = Number(task.qualityFloor ?? taskQualityFloor("complex", task));
|
|
1033
1486
|
const qualityGap = Math.max(0, floor - quality);
|
|
1034
1487
|
const reasoning = reasoningDecision(row, task);
|
|
1035
|
-
const reference = taskCost({ pricing: COST_REFERENCE_PRICING, reasoningKnown: true, reasoningEfforts: [] }, task,
|
|
1036
|
-
const cost = row.pricing === null ? 0 : 1 / (1 + taskCost(row, task,
|
|
1488
|
+
const reference = taskCost({ pricing: COST_REFERENCE_PRICING, reasoningKnown: true, reasoningEfforts: [] }, task, text7, complexity, cacheReadRatio, cacheWriteRatio);
|
|
1489
|
+
const cost = row.pricing === null ? 0 : 1 / (1 + taskCost(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio) / Math.max(reference, 1e-12));
|
|
1037
1490
|
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 - qualityGap * (task.criticality ?? 0.75) + preferenceAdjustment;
|
|
1038
1491
|
return { score, floor, qualityGap, preferenceAdjustment, ...reasoning };
|
|
1039
1492
|
}
|
|
1040
|
-
function taskCost(row, task,
|
|
1493
|
+
function taskCost(row, task, text7, complexity, cacheReadRatio = 0, cacheWriteRatio = 0) {
|
|
1041
1494
|
if (row?.pricing === null) return 0;
|
|
1042
1495
|
const decision = row === null ? null : reasoningDecision(row, task);
|
|
1043
|
-
const tokens = taskTokenBudget(
|
|
1496
|
+
const tokens = taskTokenBudget(text7, { ...task, reasoningEffort: decision?.reasoningEffort }, complexity, cacheReadRatio, cacheWriteRatio);
|
|
1044
1497
|
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;
|
|
1045
1498
|
}
|
|
1046
|
-
function dominates(left, right, task,
|
|
1499
|
+
function dominates(left, right, task, text7, complexity, cacheReadRatio, cacheWriteRatio) {
|
|
1047
1500
|
if (left.pricing === null || right.pricing === null) return false;
|
|
1048
1501
|
const leftReasoning = reasoningDecision(left, task);
|
|
1049
1502
|
const rightReasoning = reasoningDecision(right, task);
|
|
1050
1503
|
const leftValues = {
|
|
1051
1504
|
quality: qualityForTask(left, task.type),
|
|
1052
|
-
cost: taskCost(left, task,
|
|
1505
|
+
cost: taskCost(left, task, text7, complexity, cacheReadRatio, cacheWriteRatio),
|
|
1053
1506
|
latency: clamp(left.latency * leftReasoning.multiplier.latency),
|
|
1054
1507
|
specialty: specialtyForTask(left, task.type),
|
|
1055
1508
|
reasoning: leftReasoning.reasoningFit,
|
|
@@ -1057,7 +1510,7 @@ function dominates(left, right, task, text6, complexity, cacheReadRatio, cacheWr
|
|
|
1057
1510
|
};
|
|
1058
1511
|
const rightValues = {
|
|
1059
1512
|
quality: qualityForTask(right, task.type),
|
|
1060
|
-
cost: taskCost(right, task,
|
|
1513
|
+
cost: taskCost(right, task, text7, complexity, cacheReadRatio, cacheWriteRatio),
|
|
1061
1514
|
latency: clamp(right.latency * rightReasoning.multiplier.latency),
|
|
1062
1515
|
specialty: specialtyForTask(right, task.type),
|
|
1063
1516
|
reasoning: rightReasoning.reasoningFit,
|
|
@@ -1070,7 +1523,7 @@ function dominates(left, right, task, text6, complexity, cacheReadRatio, cacheWr
|
|
|
1070
1523
|
function eligibleRowsForTask(rows, task) {
|
|
1071
1524
|
return task.type === "vision" ? rows.filter((row) => row.inputModalities.length === 0 || row.inputModalities.includes("image")) : rows;
|
|
1072
1525
|
}
|
|
1073
|
-
function candidatePool(rows, task, weights,
|
|
1526
|
+
function candidatePool(rows, task, weights, text7, complexity, cacheReadRatio, cacheWriteRatio, dependencySensitive = false) {
|
|
1074
1527
|
const eligibleRows = eligibleRowsForTask(rows, task);
|
|
1075
1528
|
const floor = Number(task.qualityFloor ?? 0);
|
|
1076
1529
|
const feasible = eligibleRows.filter((row) => qualityForTask(row, task.type) >= floor);
|
|
@@ -1078,10 +1531,10 @@ function candidatePool(rows, task, weights, text6, complexity, cacheReadRatio, c
|
|
|
1078
1531
|
const taskWeights = weightsForTask(weights, task);
|
|
1079
1532
|
const scored = source.map((row) => ({
|
|
1080
1533
|
row,
|
|
1081
|
-
decision: candidateUtility(row, task, taskWeights, cacheReadRatio, cacheWriteRatio,
|
|
1082
|
-
cost: taskCost(row, task,
|
|
1534
|
+
decision: candidateUtility(row, task, taskWeights, cacheReadRatio, cacheWriteRatio, text7, complexity),
|
|
1535
|
+
cost: taskCost(row, task, text7, complexity, cacheReadRatio, cacheWriteRatio)
|
|
1083
1536
|
}));
|
|
1084
|
-
const frontier = dependencySensitive ? scored : scored.filter((item) => !scored.some((other) => other !== item && other.decision.score >= item.decision.score && dominates(other.row, item.row, task,
|
|
1537
|
+
const frontier = dependencySensitive ? scored : scored.filter((item) => !scored.some((other) => other !== item && other.decision.score >= item.decision.score && dominates(other.row, item.row, task, text7, complexity, cacheReadRatio, cacheWriteRatio)));
|
|
1085
1538
|
const essential = [
|
|
1086
1539
|
scored.filter((item) => item.row.pricing !== null).sort((left, right) => left.cost - right.cost || compareRowsStable(left.row, right.row))[0],
|
|
1087
1540
|
scored.slice().sort((left, right) => right.decision.score - left.decision.score || compareRowsStable(left.row, right.row))[0],
|
|
@@ -1099,9 +1552,9 @@ function candidatePool(rows, task, weights, text6, complexity, cacheReadRatio, c
|
|
|
1099
1552
|
dependencySensitive
|
|
1100
1553
|
};
|
|
1101
1554
|
}
|
|
1102
|
-
function solveAssignments({ rows, tasks, weights, text:
|
|
1555
|
+
function solveAssignments({ rows, tasks, weights, text: text7, complexity, budget, cacheReadRatio, cacheWriteRatio, minimizeCost = false }) {
|
|
1103
1556
|
const dependencySensitive = tasks.some((task) => (task.dependsOn ?? []).length > 0);
|
|
1104
|
-
const pools = tasks.map((task) => candidatePool(rows, task, weights,
|
|
1557
|
+
const pools = tasks.map((task) => candidatePool(rows, task, weights, text7, complexity, cacheReadRatio, cacheWriteRatio, dependencySensitive));
|
|
1105
1558
|
const result = solveCandidateAssignments({ tasks, pools: pools.map((pool, index) => pool.options.map((option) => ({
|
|
1106
1559
|
route: routeKey(option.row.provider, option.row.model),
|
|
1107
1560
|
score: option.decision.score,
|
|
@@ -1125,15 +1578,15 @@ function solveAssignments({ rows, tasks, weights, text: text6, complexity, budge
|
|
|
1125
1578
|
minimumFeasibleCost: result.minimumCostLowerBound
|
|
1126
1579
|
};
|
|
1127
1580
|
}
|
|
1128
|
-
function buildPlan({ text:
|
|
1581
|
+
function buildPlan({ text: text7 = "", available = [], mode = "collective", pricing = {}, liveBench = null, liveBenchError = "", dataVersions = null, learning = null, budgetUsd = 0, cacheReadRatio = 0, cacheWriteRatio = 0, preset = DEFAULT_ROUTING_PRESET } = {}) {
|
|
1129
1582
|
const presetId = normalizeRoutingPreset(preset);
|
|
1130
|
-
const firstLine = String(
|
|
1583
|
+
const firstLine = String(text7 ?? "").split(/\r?\n/u)[0].trim();
|
|
1131
1584
|
const transformOnly = /^(?:请|帮我)?(?:总结|概括|翻译|摘要|解释)(?:以下|下列|下面|这份|这些)/u.test(firstLine) && !/(?:执行|完成|实施|分配)/u.test(firstLine);
|
|
1132
|
-
const assessed = assessComplexity(transformOnly ? firstLine :
|
|
1133
|
-
const requirements = explicitRequirements(
|
|
1585
|
+
const assessed = assessComplexity(transformOnly ? firstLine : text7);
|
|
1586
|
+
const requirements = explicitRequirements(text7);
|
|
1134
1587
|
const compound = shouldSplitRequirements(requirements);
|
|
1135
1588
|
const complexity = compound && assessed.band !== "complex" ? { value: Math.max(0.66, assessed.value), band: "complex" } : assessed;
|
|
1136
|
-
const taskType = classifyTask(transformOnly ? firstLine :
|
|
1589
|
+
const taskType = classifyTask(transformOnly ? firstLine : text7);
|
|
1137
1590
|
const weights = presetWeights(OBJECTIVE_WEIGHTS[complexity.band], presetId);
|
|
1138
1591
|
const discovered = Array.isArray(available) ? available.map((entry) => {
|
|
1139
1592
|
const rawEfforts = Array.isArray(entry.reasoningEfforts) ? entry.reasoningEfforts : [];
|
|
@@ -1212,10 +1665,10 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1212
1665
|
costOut: pricingRow.output,
|
|
1213
1666
|
cacheRead: pricingRow.cacheRead,
|
|
1214
1667
|
cacheWrite: pricingRow.cacheWrite
|
|
1215
|
-
},
|
|
1668
|
+
}, text7, 900, {}, cacheReadRatio, cacheWriteRatio)
|
|
1216
1669
|
});
|
|
1217
1670
|
}
|
|
1218
|
-
const taskNodes = taskPackages(taskType,
|
|
1671
|
+
const taskNodes = taskPackages(taskType, text7, complexity.band).map((task) => presetId === DEFAULT_ROUTING_PRESET ? task : {
|
|
1219
1672
|
...task,
|
|
1220
1673
|
qualityFloor: presetFloor(task.qualityFloor, presetId),
|
|
1221
1674
|
weights: presetWeights(weightsForTask(weights, task), presetId)
|
|
@@ -1226,7 +1679,7 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1226
1679
|
rows,
|
|
1227
1680
|
tasks: taskNodes,
|
|
1228
1681
|
weights,
|
|
1229
|
-
text:
|
|
1682
|
+
text: text7,
|
|
1230
1683
|
complexity: complexity.band,
|
|
1231
1684
|
budget: Number.POSITIVE_INFINITY,
|
|
1232
1685
|
cacheReadRatio,
|
|
@@ -1236,7 +1689,7 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1236
1689
|
rows,
|
|
1237
1690
|
tasks: taskNodes,
|
|
1238
1691
|
weights,
|
|
1239
|
-
text:
|
|
1692
|
+
text: text7,
|
|
1240
1693
|
complexity: complexity.band,
|
|
1241
1694
|
budget,
|
|
1242
1695
|
cacheReadRatio,
|
|
@@ -1246,7 +1699,7 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1246
1699
|
rows,
|
|
1247
1700
|
tasks: taskNodes,
|
|
1248
1701
|
weights,
|
|
1249
|
-
text:
|
|
1702
|
+
text: text7,
|
|
1250
1703
|
complexity: complexity.band,
|
|
1251
1704
|
budget: Number.POSITIVE_INFINITY,
|
|
1252
1705
|
cacheReadRatio,
|
|
@@ -1258,8 +1711,8 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1258
1711
|
const usedRoutes = optimized?.usedRoutes ?? /* @__PURE__ */ new Set();
|
|
1259
1712
|
const constraintRelaxed = (optimized?.relaxedCount ?? 0) > 0;
|
|
1260
1713
|
for (const row of rows) {
|
|
1261
|
-
row.score = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band] }, weights, cacheReadRatio, cacheWriteRatio,
|
|
1262
|
-
if (row.pricing !== null && taskNodes[0]) row.estimatedCost = taskCost(row, taskNodes[0],
|
|
1714
|
+
row.score = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band] }, weights, cacheReadRatio, cacheWriteRatio, text7, complexity.band).score;
|
|
1715
|
+
if (row.pricing !== null && taskNodes[0]) row.estimatedCost = taskCost(row, taskNodes[0], text7, complexity.band, cacheReadRatio, cacheWriteRatio);
|
|
1263
1716
|
}
|
|
1264
1717
|
rows.sort((left, right) => right.score - left.score || compareRowsStable(left, right));
|
|
1265
1718
|
const selectedAssignment = assignments[0];
|
|
@@ -1285,8 +1738,8 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1285
1738
|
dependsOn: [...task.dependsOn ?? []]
|
|
1286
1739
|
}));
|
|
1287
1740
|
const costBreakdown = assignments.map(({ task, row, decision, estimatedCost, handoffPenalty }, index) => {
|
|
1288
|
-
const tokens = taskTokenBudget(
|
|
1289
|
-
const taskEstimate = estimatedCost ?? taskCost(row, task,
|
|
1741
|
+
const tokens = taskTokenBudget(text7, { ...task, reasoningEffort: decision?.reasoningEffort }, complexity.band, cacheReadRatio, cacheWriteRatio);
|
|
1742
|
+
const taskEstimate = estimatedCost ?? taskCost(row, task, text7, complexity.band, cacheReadRatio, cacheWriteRatio);
|
|
1290
1743
|
return {
|
|
1291
1744
|
stage: index + 1,
|
|
1292
1745
|
purpose: task.purpose,
|
|
@@ -1309,12 +1762,12 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1309
1762
|
};
|
|
1310
1763
|
});
|
|
1311
1764
|
const pricingComplete = assignments.length > 0 && assignments.every(({ row }) => row?.pricing !== null);
|
|
1312
|
-
const totalEstimate = pricingComplete ? assignments.reduce((sum, { task, row, estimatedCost }) => sum + (estimatedCost ?? taskCost(row, task,
|
|
1765
|
+
const totalEstimate = pricingComplete ? assignments.reduce((sum, { task, row, estimatedCost }) => sum + (estimatedCost ?? taskCost(row, task, text7, complexity.band, cacheReadRatio, cacheWriteRatio)), 0) : null;
|
|
1313
1766
|
const baselineRows = assignments.map(({ task }) => {
|
|
1314
1767
|
const strongest = eligibleRowsForTask(rows, task).reduce((best, row) => qualityForTask(row, task.type) > (best === null ? -1 : qualityForTask(best, task.type)) ? row : best, null);
|
|
1315
1768
|
return { task, strongest };
|
|
1316
1769
|
});
|
|
1317
|
-
const baselineCost = baselineRows.every((item) => item.strongest?.pricing !== null && item.strongest !== null) ? baselineRows.reduce((sum, { task, strongest }) => sum + taskCost(strongest, task,
|
|
1770
|
+
const baselineCost = baselineRows.every((item) => item.strongest?.pricing !== null && item.strongest !== null) ? baselineRows.reduce((sum, { task, strongest }) => sum + taskCost(strongest, task, text7, complexity.band, cacheReadRatio, cacheWriteRatio), 0) : null;
|
|
1318
1771
|
const qualityEvidenceComplete = assignments.length > 0 && assignments.every(({ row, task }) => ["livebench", "route", "user"].includes(qualitySourceForTask(row, task.type))) && baselineRows.every(({ strongest, task }) => ["livebench", "route", "user"].includes(qualitySourceForTask(strongest, task.type)));
|
|
1319
1772
|
const budgetExceeded = Number(budgetUsd) > 0 && totalEstimate !== null ? totalEstimate > Number(budgetUsd) : null;
|
|
1320
1773
|
const savings = baselineCost === null || totalEstimate === null || !qualityEvidenceComplete ? null : baselineCost <= 0 ? 0 : clamp((baselineCost - totalEstimate) / baselineCost);
|
|
@@ -1331,7 +1784,7 @@ function buildPlan({ text: text6 = "", available = [], mode = "collective", pric
|
|
|
1331
1784
|
taskTypes: [...new Set(taskNodes.map((task) => task.type).filter((type) => type !== "reasoning"))],
|
|
1332
1785
|
objectiveWeights: weights,
|
|
1333
1786
|
candidates: rows.slice(0, 8).map((row) => {
|
|
1334
|
-
const decision = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band], preferredReasoningEffort: complexity.band === "simple" ? "low" : "medium" }, weights, cacheReadRatio, cacheWriteRatio,
|
|
1787
|
+
const decision = candidateUtility(row, taskNodes[0] ?? { type: taskType, qualityFloor: QUALITY_FLOORS[complexity.band], preferredReasoningEffort: complexity.band === "simple" ? "low" : "medium" }, weights, cacheReadRatio, cacheWriteRatio, text7, complexity.band);
|
|
1335
1788
|
return { provider: row.provider, model: row.model, score: Number(row.score.toFixed(3)), preferenceAdjustment: decision.preferenceAdjustment, 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, pricingVersion: row.pricingVersion, pricingAsOf: row.snapshotAsOf };
|
|
1336
1789
|
}),
|
|
1337
1790
|
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: qualitySourceForTask(selected, selectedAssignment?.task.type ?? taskType), pricingSource: selected.pricingSource },
|
|
@@ -1909,10 +2362,34 @@ function toolInstallAction({ tool, probe, readiness, job, probeStatus, latestVer
|
|
|
1909
2362
|
disabled: !interactive || running || installed && (order === 1 || current)
|
|
1910
2363
|
};
|
|
1911
2364
|
}
|
|
1912
|
-
function
|
|
2365
|
+
function toolMaintenanceActions({ tool, probe, job, probeStatus, summary }) {
|
|
2366
|
+
const running = job?.status === "running";
|
|
2367
|
+
const installed = probe?.installed === true;
|
|
2368
|
+
const interactive = probeStatus === "ready" || probeStatus === "refreshing";
|
|
2369
|
+
const desktop = tool.manager === "signed-windows-installer";
|
|
2370
|
+
const busy = running || !interactive;
|
|
2371
|
+
return {
|
|
2372
|
+
repair: {
|
|
2373
|
+
label: "\u4E00\u952E\u4FEE\u590D",
|
|
2374
|
+
title: "\u7528\u540C\u4E00\u6761\u56FA\u5B9A\u5B98\u65B9\u5B89\u88C5\u547D\u4EE4\u91CD\u65B0\u5B89\u88C5\u4E00\u904D\uFF0C\u4FEE\u590D\u635F\u574F\u6216\u4E0D\u5B8C\u6574\u7684\u5B89\u88C5",
|
|
2375
|
+
disabled: busy || desktop || summary?.installable === false
|
|
2376
|
+
},
|
|
2377
|
+
uninstall: {
|
|
2378
|
+
label: "\u4E00\u952E\u5378\u8F7D",
|
|
2379
|
+
title: "\u53EA\u5220\u9664\u7A0B\u5E8F\u672C\u8EAB\uFF1B\u914D\u7F6E\u3001\u767B\u5F55\u4FE1\u606F\u548C\u5386\u53F2\u8BB0\u5F55\u4FDD\u7559",
|
|
2380
|
+
disabled: busy || desktop || !installed || summary?.removable === false
|
|
2381
|
+
}
|
|
2382
|
+
};
|
|
2383
|
+
}
|
|
2384
|
+
function installClickRefusal({ tool, submitting = false, running = false, operation = "install" } = {}) {
|
|
1913
2385
|
if (!tool) return "\u672A\u77E5\u5B98\u65B9\u5DE5\u5177\uFF0C\u65E0\u6CD5\u5F00\u59CB\u5B89\u88C5\u3002";
|
|
1914
2386
|
if (tool.unsupported) return String(tool.unsupportedReason ?? "").trim() || "\u6B64\u5DE5\u5177\u6682\u4E0D\u652F\u6301\u4E00\u952E\u5B89\u88C5\u3002";
|
|
1915
|
-
if (
|
|
2387
|
+
if (tool.manager === "signed-windows-installer" && operation !== "install") {
|
|
2388
|
+
return `${tool.label} \u7531\u5B98\u65B9\u7B7E\u540D\u684C\u9762\u5B89\u88C5\u5668\u5B89\u88C5\uFF0C\u8BF7\u5728\u7CFB\u7EDF\u201C\u5E94\u7528\u201D\u4E2D\u5378\u8F7D\u5B83\u3002`;
|
|
2389
|
+
}
|
|
2390
|
+
if (submitting || running) {
|
|
2391
|
+
return operation === "uninstall" ? "\u8BE5\u5DE5\u5177\u6B63\u5728\u5378\u8F7D\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u3002" : operation === "repair" ? "\u8BE5\u5DE5\u5177\u6B63\u5728\u4FEE\u590D\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u3002" : "\u8BE5\u5DE5\u5177\u6B63\u5728\u5B89\u88C5\uFF0C\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u3002";
|
|
2392
|
+
}
|
|
1916
2393
|
return "";
|
|
1917
2394
|
}
|
|
1918
2395
|
function payloadError(payload, fallback) {
|
|
@@ -2727,7 +3204,7 @@ function LaunchPreview({ value, changed, running, confirmRef, onConfirm, onCance
|
|
|
2727
3204
|
// .dsh-plugin/client/cli-terminal.jsx
|
|
2728
3205
|
var import_react4 = __toESM(require("react"), 1);
|
|
2729
3206
|
|
|
2730
|
-
// node_modules
|
|
3207
|
+
// node_modules/@xterm/xterm/lib/xterm.mjs
|
|
2731
3208
|
var zs = Object.defineProperty;
|
|
2732
3209
|
var Rl = Object.getOwnPropertyDescriptor;
|
|
2733
3210
|
var Ll = (s15, t) => {
|
|
@@ -11841,7 +12318,7 @@ var Dl = class extends D {
|
|
|
11841
12318
|
}
|
|
11842
12319
|
};
|
|
11843
12320
|
|
|
11844
|
-
// node_modules
|
|
12321
|
+
// node_modules/@xterm/addon-fit/lib/addon-fit.mjs
|
|
11845
12322
|
var h = 2;
|
|
11846
12323
|
var _ = 1;
|
|
11847
12324
|
var o = class {
|
|
@@ -11865,7 +12342,7 @@ var o = class {
|
|
|
11865
12342
|
}
|
|
11866
12343
|
};
|
|
11867
12344
|
|
|
11868
|
-
// node_modules
|
|
12345
|
+
// node_modules/@xterm/xterm/css/xterm.css
|
|
11869
12346
|
var xterm_default = `/**
|
|
11870
12347
|
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
11871
12348
|
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
@@ -12154,7 +12631,7 @@ var xterm_default = `/**
|
|
|
12154
12631
|
`;
|
|
12155
12632
|
|
|
12156
12633
|
// .dsh-plugin/client/host-version.mjs
|
|
12157
|
-
var ROUTER_CLIENT_VERSION = true ? "0.
|
|
12634
|
+
var ROUTER_CLIENT_VERSION = true ? "0.17.1" : "";
|
|
12158
12635
|
var STALE_HOST_MESSAGE = "\u63D2\u4EF6\u540E\u53F0\u7248\u672C\u8F83\u65E7\uFF0C\u8BF7\u5B8C\u5168\u9000\u51FA\u5E76\u91CD\u542F Harness\uFF08\u5305\u62EC\u6258\u76D8\u56FE\u6807\uFF09\u540E\u518D\u4F7F\u7528\u3002";
|
|
12159
12636
|
function isMissingRemoteMethod(message) {
|
|
12160
12637
|
const value = String(message ?? "");
|
|
@@ -12752,6 +13229,16 @@ var router_main_default = `.mr-workspace {
|
|
|
12752
13229
|
.mr-tool-log { margin-top: 7px; color: var(--mr-muted); font-size: 11px; }
|
|
12753
13230
|
.mr-tool-log summary { cursor: pointer; }
|
|
12754
13231
|
.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; }
|
|
13232
|
+
.mr-tool-methods { display: flex; align-items: center; gap: 6px; margin-right: 2px; }
|
|
13233
|
+
.mr-tool-methods label { display: flex; align-items: center; gap: 6px; color: var(--mr-muted); font-size: 11px; }
|
|
13234
|
+
.mr-install-settings { margin-bottom: 14px; padding: 13px 14px; border: 1px solid var(--mr-line); border-radius: 11px; background: var(--mr-card); }
|
|
13235
|
+
.mr-install-settings-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
|
|
13236
|
+
.mr-install-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
|
|
13237
|
+
.mr-install-field { display: flex; flex-direction: column; gap: 5px; font-size: 12px; color: var(--mr-muted); }
|
|
13238
|
+
.mr-install-field > span { font-weight: 600; color: var(--mr-ink); }
|
|
13239
|
+
.mr-install-field small { font-size: 11px; line-height: 1.6; }
|
|
13240
|
+
.mr-install-error { color: #d95360; }
|
|
13241
|
+
.mr-install-toggle-row { display: flex; align-items: center; gap: 7px; }
|
|
12755
13242
|
.mr-channel-line { display: flex; align-items: center; gap: 8px; margin: 8px 0; flex-wrap: wrap; }
|
|
12756
13243
|
.mr-pill-channel-ok { border-color: var(--dsw-alias-success, #2f9e63); color: var(--dsw-alias-success, #2f9e63); }
|
|
12757
13244
|
.mr-pill-warn { border-color: var(--dsw-alias-warning, #c27c0e); color: var(--dsw-alias-warning, #c27c0e); }
|
|
@@ -12972,9 +13459,115 @@ function probeLabel(probe) {
|
|
|
12972
13459
|
if (probe.status === "probe-failed") return "\u68C0\u6D4B\u5931\u8D25";
|
|
12973
13460
|
return probe.detail || "\u672A\u5B89\u88C5";
|
|
12974
13461
|
}
|
|
12975
|
-
|
|
13462
|
+
var INSTALL_SETTING_FIELDS = [
|
|
13463
|
+
{
|
|
13464
|
+
key: "toolInstallDir",
|
|
13465
|
+
label: "\u7EDF\u4E00\u5B89\u88C5\u76EE\u5F55",
|
|
13466
|
+
fallback: "",
|
|
13467
|
+
placeholder: "\u7559\u7A7A = \u5404\u5382\u5546\u9ED8\u8BA4\u76EE\u5F55",
|
|
13468
|
+
hint: "npm / pnpm \u4F1A\u52A0 --prefix\u3002\u652F\u6301\u76EE\u5F55\u7684\u5B98\u65B9\u811A\u672C\u628A\u8FD9\u4E2A\u8DEF\u5F84\u4F20\u7ED9\u5382\u5546\u81EA\u5DF1\u7684\u5B89\u88C5\u76EE\u5F55\u53D8\u91CF\uFF1B\u5199\u6B7B\u8DEF\u5F84\u7684\u811A\u672C\u4F1A\u6807\u660E\u5B9E\u9645\u843D\u70B9\u3002\u66F4\u65B0\u4E5F\u4F7F\u7528\u8FD9\u91CC\uFF0C\u4E0D\u4F1A\u6539\u53BB\u522B\u7684\u9ED8\u8BA4\u4F4D\u7F6E\u3002",
|
|
13469
|
+
validate: () => null
|
|
13470
|
+
},
|
|
13471
|
+
{
|
|
13472
|
+
key: "toolNpmRegistry",
|
|
13473
|
+
label: "npm \u6E90\u5730\u5740",
|
|
13474
|
+
fallback: "https://registry.npmjs.org/",
|
|
13475
|
+
placeholder: "https://registry.npmjs.org/",
|
|
13476
|
+
hint: "\u5FC5\u987B\u4EE5 https:// \u5F00\u5934\u3002\u6362\u6210\u56FD\u5185\u955C\u50CF\u540E\uFF0C\u6240\u6709\u5305\u7BA1\u7406\u5668\u65B9\u5F0F\u90FD\u4ECE\u8FD9\u91CC\u4E0B\u8F7D\u3002",
|
|
13477
|
+
validate: (raw) => /^https:\/\/\S+$/i.test(raw.trim()) ? null : "\u9700\u8981 https \u5F00\u5934\u7684\u5B8C\u6574\u5730\u5740\uFF0C\u4F8B\u5982 https://registry.npmmirror.com/"
|
|
13478
|
+
},
|
|
13479
|
+
{
|
|
13480
|
+
key: "toolScriptUrlsJson",
|
|
13481
|
+
label: "\u5B89\u88C5\u811A\u672C\u6E90\u8986\u76D6\uFF08JSON\uFF0C\u53EF\u9009\uFF09",
|
|
13482
|
+
fallback: "{}",
|
|
13483
|
+
placeholder: '{ "stepcode": "https://mirror/stepcode/install.ps1" }',
|
|
13484
|
+
hint: "\u6309\u5DE5\u5177 ID \u6307\u5B9A\u5382\u5546\u5B89\u88C5\u811A\u672C\u7684\u955C\u50CF\u5730\u5740\u3002\u811A\u672C\u4ECD\u4F1A\u4E0B\u8F7D\u540E\u6821\u9A8C\u5382\u5546\u6807\u8BB0\u518D\u6267\u884C\uFF0C\u955C\u50CF\u4E0D\u80FD\u6362\u6210\u522B\u7684\u7A0B\u5E8F\u3002",
|
|
13485
|
+
validate: (raw) => {
|
|
13486
|
+
if (!raw.trim()) return null;
|
|
13487
|
+
let parsed;
|
|
13488
|
+
try {
|
|
13489
|
+
parsed = JSON.parse(raw);
|
|
13490
|
+
} catch {
|
|
13491
|
+
return "JSON \u683C\u5F0F\u65E0\u6548\u3002";
|
|
13492
|
+
}
|
|
13493
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return "\u9700\u8981 JSON \u5BF9\u8C61\u3002";
|
|
13494
|
+
for (const [id2, url] of Object.entries(parsed)) {
|
|
13495
|
+
if (!OFFICIAL_TOOLS.some((tool) => tool.id === id2)) return `${id2} \u4E0D\u662F\u5B98\u65B9\u5DE5\u5177 ID\u3002`;
|
|
13496
|
+
if (typeof url !== "string" || !/^https:\/\/\S+$/i.test(url.trim())) return `${id2} \u7684\u5730\u5740\u5FC5\u987B\u662F https \u94FE\u63A5\u3002`;
|
|
13497
|
+
}
|
|
13498
|
+
return null;
|
|
13499
|
+
}
|
|
13500
|
+
}
|
|
13501
|
+
];
|
|
13502
|
+
function InstallSettings({ settingsScope, install }) {
|
|
13503
|
+
const [snapshot, setSnapshot] = import_react5.default.useState(() => settingsScope?.getSnapshot?.() ?? { value: {}, writable: false });
|
|
13504
|
+
const [drafts, setDrafts] = import_react5.default.useState({});
|
|
13505
|
+
const [saving, setSaving] = import_react5.default.useState(false);
|
|
13506
|
+
const [notice, setNotice] = import_react5.default.useState("");
|
|
13507
|
+
import_react5.default.useEffect(() => {
|
|
13508
|
+
if (typeof settingsScope?.subscribe !== "function") return void 0;
|
|
13509
|
+
const unsubscribe = settingsScope.subscribe(() => {
|
|
13510
|
+
setSnapshot(settingsScope.getSnapshot());
|
|
13511
|
+
setDrafts({});
|
|
13512
|
+
});
|
|
13513
|
+
setSnapshot(settingsScope.getSnapshot());
|
|
13514
|
+
return unsubscribe;
|
|
13515
|
+
}, [settingsScope]);
|
|
13516
|
+
if (!settingsScope) return null;
|
|
13517
|
+
const writable = snapshot.writable === true && !saving;
|
|
13518
|
+
const shown = (field2) => drafts[field2.key] ?? String(snapshot.value?.[field2.key] ?? field2.fallback);
|
|
13519
|
+
const errors = Object.fromEntries(INSTALL_SETTING_FIELDS.map((field2) => [field2.key, field2.validate(shown(field2))]));
|
|
13520
|
+
const apply2 = async (entries, successText) => {
|
|
13521
|
+
setSaving(true);
|
|
13522
|
+
setNotice("");
|
|
13523
|
+
try {
|
|
13524
|
+
const accepted = await settingsScope.mutate(entries, snapshot.revision);
|
|
13525
|
+
if (!accepted) throw new Error("\u8BBE\u7F6E\u672A\u88AB\u4FDD\u5B58\uFF0C\u53EF\u80FD\u88AB\u5176\u4ED6\u9875\u9762\u4FEE\u6539\uFF1B\u8F93\u5165\u5DF2\u4FDD\u7559\uFF0C\u8BF7\u91CD\u65B0\u6838\u5BF9\u3002");
|
|
13526
|
+
setNotice(successText);
|
|
13527
|
+
} catch (error) {
|
|
13528
|
+
setNotice(text5(error?.message) || "\u5B89\u88C5\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
|
|
13529
|
+
} finally {
|
|
13530
|
+
setSaving(false);
|
|
13531
|
+
}
|
|
13532
|
+
};
|
|
13533
|
+
const commit = (field2) => {
|
|
13534
|
+
const saved = String(snapshot.value?.[field2.key] ?? field2.fallback);
|
|
13535
|
+
const raw = shown(field2);
|
|
13536
|
+
if (raw === saved || errors[field2.key]) return;
|
|
13537
|
+
return apply2([{ op: "set", path: [field2.key], value: raw }], `\u5DF2\u4FDD\u5B58${field2.label}\uFF0C\u4E0B\u4E00\u6B21\u5B89\u88C5\u8D77\u751F\u6548\u3002`);
|
|
13538
|
+
};
|
|
13539
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-install-settings", "aria-label": "\u7EDF\u4E00\u5B89\u88C5\u8BBE\u7F6E" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-install-settings-head" }, /* @__PURE__ */ import_react5.default.createElement("strong", null, "\u7EDF\u4E00\u5B89\u88C5\u8BBE\u7F6E"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-caption" }, "\u5BF9\u6240\u6709\u5B98\u65B9\u5DE5\u5177\u751F\u6548\uFF0C\u6539\u52A8\u540E\u4E0B\u4E00\u6B21\u4E00\u952E\u5B89\u88C5\u3001\u4FEE\u590D\u6216\u5378\u8F7D\u7ACB\u5373\u4F7F\u7528\u3002\u63D2\u4EF6\u8BBE\u7F6E\u9875\u91CC\u6709\u540C\u6837\u7684\u5B57\u6BB5\u3002")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-install-grid" }, INSTALL_SETTING_FIELDS.map((field2) => /* @__PURE__ */ import_react5.default.createElement("label", { className: "mr-install-field", key: field2.key }, /* @__PURE__ */ import_react5.default.createElement("span", null, field2.label), /* @__PURE__ */ import_react5.default.createElement(
|
|
13540
|
+
"input",
|
|
13541
|
+
{
|
|
13542
|
+
className: "mr-input",
|
|
13543
|
+
value: shown(field2),
|
|
13544
|
+
placeholder: field2.placeholder,
|
|
13545
|
+
disabled: !writable,
|
|
13546
|
+
"aria-invalid": Boolean(errors[field2.key]),
|
|
13547
|
+
onChange: (event) => setDrafts((previous) => ({ ...previous, [field2.key]: event.target.value })),
|
|
13548
|
+
onBlur: () => {
|
|
13549
|
+
void commit(field2);
|
|
13550
|
+
}
|
|
13551
|
+
}
|
|
13552
|
+
), errors[field2.key] ? /* @__PURE__ */ import_react5.default.createElement("small", { className: "mr-install-error", role: "alert" }, errors[field2.key]) : /* @__PURE__ */ import_react5.default.createElement("small", null, field2.hint))), /* @__PURE__ */ import_react5.default.createElement("label", { className: "mr-install-field" }, /* @__PURE__ */ import_react5.default.createElement("span", null, "\u5B89\u88C5\u811A\u672C\u65B9\u5F0F"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-install-toggle-row" }, /* @__PURE__ */ import_react5.default.createElement(
|
|
13553
|
+
"input",
|
|
13554
|
+
{
|
|
13555
|
+
type: "checkbox",
|
|
13556
|
+
checked: snapshot.value?.toolAllowScriptInstall !== false,
|
|
13557
|
+
disabled: !writable,
|
|
13558
|
+
onChange: (event) => {
|
|
13559
|
+
const allowed = event.target.checked;
|
|
13560
|
+
void apply2(
|
|
13561
|
+
[{ op: "set", path: ["toolAllowScriptInstall"], value: allowed }],
|
|
13562
|
+
allowed ? "\u5DF2\u5141\u8BB8\u811A\u672C\u5B89\u88C5\u65B9\u5F0F\uFF08curl / irm\uFF09\u3002" : "\u5DF2\u5173\u95ED\u811A\u672C\u5B89\u88C5\u65B9\u5F0F\uFF0C\u53EA\u80FD\u4F7F\u7528 npm / pnpm\u3002"
|
|
13563
|
+
);
|
|
13564
|
+
}
|
|
13565
|
+
}
|
|
13566
|
+
), /* @__PURE__ */ import_react5.default.createElement("span", null, "\u5141\u8BB8 curl / irm \u5B89\u88C5\u811A\u672C")), /* @__PURE__ */ import_react5.default.createElement("small", null, "\u5173\u95ED\u540E\u53EA\u80FD\u4F7F\u7528 npm / pnpm \u65B9\u5F0F\uFF1B\u811A\u672C\u65B9\u5F0F\u9700\u8981\u5148\u4E0B\u8F7D\u5E76\u6821\u9A8C\u5382\u5546\u6807\u8BB0\u518D\u6267\u884C\u3002"))), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { marginTop: 8 }, role: notice ? "status" : void 0 }, "\u5F53\u524D\u751F\u6548\uFF1A\u5B89\u88C5\u76EE\u5F55 ", install?.installDir || "\uFF08\u5404\u5382\u5546\u9ED8\u8BA4\uFF09", " \xB7 npm \u6E90 ", install?.registry || "\uFF08\u9ED8\u8BA4\uFF09", notice ? ` \xB7 ${notice}` : ""));
|
|
13567
|
+
}
|
|
13568
|
+
function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes, health, onRefreshHealth, settingsScope }) {
|
|
12976
13569
|
const healthById = Object.fromEntries((health?.tools ?? []).map((item) => [item.id, item]));
|
|
12977
|
-
const [probeState, setProbeState] = import_react5.default.useState({ status: "loading", probes: [], capabilities: [], readiness: [], error: "" });
|
|
13570
|
+
const [probeState, setProbeState] = import_react5.default.useState({ status: "loading", probes: [], capabilities: [], readiness: [], install: null, error: "" });
|
|
12978
13571
|
const [jobs, setJobs] = import_react5.default.useState({});
|
|
12979
13572
|
const [rowErrors, setRowErrors] = import_react5.default.useState({});
|
|
12980
13573
|
const mounted = import_react5.default.useRef(false);
|
|
@@ -13005,7 +13598,7 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
13005
13598
|
const probes = Array.isArray(response.value?.tools) ? response.value.tools : [];
|
|
13006
13599
|
const capabilities = Array.isArray(response.value?.executionCapabilities) ? response.value.executionCapabilities : [];
|
|
13007
13600
|
const readiness = Array.isArray(response.value?.executionReadiness) ? response.value.executionReadiness : [];
|
|
13008
|
-
setProbeState({ status: "ready", probes, capabilities, readiness, error: "" });
|
|
13601
|
+
setProbeState({ status: "ready", probes, capabilities, readiness, install: response.value?.install ?? null, error: "" });
|
|
13009
13602
|
onProbes({ probes, capabilities, readiness, hostVersion: typeof response.value?.hostVersion === "string" ? response.value.hostVersion : null });
|
|
13010
13603
|
} catch (error) {
|
|
13011
13604
|
if (!mounted.current || current !== request.current) return;
|
|
@@ -13016,7 +13609,7 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
13016
13609
|
kept = true;
|
|
13017
13610
|
return { ...previous, status: "ready", error: message };
|
|
13018
13611
|
}
|
|
13019
|
-
return { status: "error", probes: [], capabilities: [], readiness: [], error: message };
|
|
13612
|
+
return { status: "error", probes: [], capabilities: [], readiness: [], install: null, error: message };
|
|
13020
13613
|
});
|
|
13021
13614
|
if (!kept) onProbes({ probes: [], capabilities: [], readiness: [] });
|
|
13022
13615
|
}
|
|
@@ -13088,34 +13681,36 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
13088
13681
|
clearInterval(timer);
|
|
13089
13682
|
};
|
|
13090
13683
|
}, [jobs, officialToolInstallStatus]);
|
|
13091
|
-
const
|
|
13684
|
+
const run = async (id2, operation) => {
|
|
13092
13685
|
const tool = OFFICIAL_TOOLS.find((item) => item.id === id2);
|
|
13686
|
+
const bridge = { install: installOfficialTool, repair: repairOfficialTool, uninstall: uninstallOfficialTool }[operation];
|
|
13093
13687
|
const refusal = installClickRefusal({
|
|
13094
13688
|
tool,
|
|
13095
13689
|
submitting: submitting.current.has(id2),
|
|
13096
|
-
running: jobsRef.current[id2]?.status === "running"
|
|
13690
|
+
running: jobsRef.current[id2]?.status === "running",
|
|
13691
|
+
operation
|
|
13097
13692
|
});
|
|
13098
13693
|
if (refusal) {
|
|
13099
13694
|
setRowErrors((previous) => ({ ...previous, [id2]: refusal }));
|
|
13100
13695
|
return;
|
|
13101
13696
|
}
|
|
13697
|
+
if (typeof bridge !== "function") throw new Error("\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002");
|
|
13102
13698
|
submitting.current.add(id2);
|
|
13103
13699
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13104
13700
|
setRowErrors((previous) => ({ ...previous, [id2]: "" }));
|
|
13105
13701
|
rememberJobs((previous) => ({
|
|
13106
13702
|
...previous,
|
|
13107
|
-
[id2]: { tool: id2, status: "running", outputTail: [], startedAt, error: null }
|
|
13703
|
+
[id2]: { tool: id2, operation, status: "running", outputTail: [], startedAt, error: null }
|
|
13108
13704
|
}));
|
|
13109
13705
|
try {
|
|
13110
|
-
|
|
13111
|
-
const response = await installOfficialTool(id2);
|
|
13706
|
+
const response = await bridge({ tool: id2 });
|
|
13112
13707
|
if (!mounted.current) return;
|
|
13113
13708
|
const accepted = acceptedInstallJob(response);
|
|
13114
|
-
if (!accepted.job) throw new Error(remoteErrorText(accepted.error, "\
|
|
13709
|
+
if (!accepted.job) throw new Error(remoteErrorText(accepted.error, "\u4EFB\u52A1\u672A\u88AB\u63A5\u53D7\u3002"));
|
|
13115
13710
|
rememberJobs((previous) => shouldApplyInstallStatus(previous[id2], accepted.job) ? { ...previous, [id2]: accepted.job } : previous);
|
|
13116
13711
|
} catch (error) {
|
|
13117
13712
|
if (!mounted.current) return;
|
|
13118
|
-
const message = remoteErrorText(text5(error?.message), "\
|
|
13713
|
+
const message = remoteErrorText(text5(error?.message), "\u542F\u52A8\u5931\u8D25\u3002");
|
|
13119
13714
|
rememberJobs((previous) => ({
|
|
13120
13715
|
...previous,
|
|
13121
13716
|
[id2]: {
|
|
@@ -13131,6 +13726,29 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
13131
13726
|
submitting.current.delete(id2);
|
|
13132
13727
|
}
|
|
13133
13728
|
};
|
|
13729
|
+
const install = (id2) => run(id2, "install");
|
|
13730
|
+
const repair = (id2) => run(id2, "repair");
|
|
13731
|
+
const uninstall = (id2) => run(id2, "uninstall");
|
|
13732
|
+
const setInstallMethod = async (toolId, methodId) => {
|
|
13733
|
+
const snapshot = settingsScope?.getSnapshot?.();
|
|
13734
|
+
if (!snapshot) return;
|
|
13735
|
+
let map = {};
|
|
13736
|
+
try {
|
|
13737
|
+
map = JSON.parse(String(snapshot.value?.toolInstallMethodsJson ?? "{}")) || {};
|
|
13738
|
+
} catch {
|
|
13739
|
+
map = {};
|
|
13740
|
+
}
|
|
13741
|
+
if (typeof map !== "object" || Array.isArray(map)) map = {};
|
|
13742
|
+
if (methodId) map[toolId] = methodId;
|
|
13743
|
+
else delete map[toolId];
|
|
13744
|
+
try {
|
|
13745
|
+
const accepted = await settingsScope.mutate([{ op: "set", path: ["toolInstallMethodsJson"], value: JSON.stringify(map) }], snapshot.revision);
|
|
13746
|
+
if (!accepted) throw new Error("\u5B89\u88C5\u65B9\u5F0F\u672A\u88AB\u4FDD\u5B58\uFF0C\u53EF\u80FD\u88AB\u5176\u4ED6\u9875\u9762\u4FEE\u6539\u3002");
|
|
13747
|
+
void refresh();
|
|
13748
|
+
} catch (error) {
|
|
13749
|
+
if (mounted.current) setRowErrors((previous) => ({ ...previous, [toolId]: text5(error?.message) || "\u5B89\u88C5\u65B9\u5F0F\u4FDD\u5B58\u5931\u8D25\u3002" }));
|
|
13750
|
+
}
|
|
13751
|
+
};
|
|
13134
13752
|
const cancel = async (id2) => {
|
|
13135
13753
|
if (typeof cancelOfficialToolInstall !== "function" || jobs[id2]?.status !== "running" || jobs[id2]?.cancelRequested) return;
|
|
13136
13754
|
setRowErrors((previous) => ({ ...previous, [id2]: "" }));
|
|
@@ -13147,24 +13765,50 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, cancelOffic
|
|
|
13147
13765
|
const byId = Object.fromEntries(probeState.probes.map((probe) => [probe.id, probe]));
|
|
13148
13766
|
const capabilitiesById = Object.fromEntries(probeState.capabilities.map((item) => [item.id, item]));
|
|
13149
13767
|
const readinessById = Object.fromEntries(probeState.readiness.map((item) => [item.id, item]));
|
|
13150
|
-
|
|
13768
|
+
const installById = Object.fromEntries((probeState.install?.tools ?? []).map((item) => [item.id, item]));
|
|
13769
|
+
return /* @__PURE__ */ import_react5.default.createElement("section", { className: "mr-card", "aria-label": "\u5B98\u65B9\u5DE5\u5177" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react5.default.createElement("div", null, /* @__PURE__ */ import_react5.default.createElement("h2", { className: "mr-card-title" }, "\u5B98\u65B9\u5DE5\u5177 \xB7 \u4F53\u68C0"), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-card-copy" }, "\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u7684\u5B89\u88C5\u3001\u7248\u672C\u548C\u767B\u5F55\u72B6\u6001\uFF0C\u5E76\u4ECE\u56FA\u5B9A\u6CE8\u518C\u8868\u4E00\u952E\u5B89\u88C5\u6216\u66F4\u65B0\u5230\u5404\u5382\u5546\u6700\u65B0\u7248\uFF08\u65B0\u7248\u672C\u672A\u7ECF\u63D2\u4EF6\u6D4B\u8BD5\uFF09\u3002\u53EF\u6309\u5DE5\u5177\u9009\u62E9 npm\u3001pnpm \u6216\u5382\u5546\u5B89\u88C5\u811A\u672C\u65B9\u5F0F\uFF0C\u5E76\u7EDF\u4E00\u8BBE\u7F6E\u5B89\u88C5\u76EE\u5F55\u4E0E\u4E0B\u8F7D\u6E90\uFF1B\u5378\u8F7D\u53EA\u5220\u9664\u7A0B\u5E8F\uFF0C\u914D\u7F6E\u4E0E\u767B\u5F55\u4FDD\u7559\u3002\u672A\u767B\u5F55\u7684\u5DE5\u5177\u70B9\u201C\u53BB\u767B\u5F55\u201D\u67E5\u770B\u767B\u5F55\u547D\u4EE4\u3002ZCode \u4F1A\u6253\u5F00\u5B98\u65B9\u5B89\u88C5\u7A97\u53E3\u4F9B\u4F60\u9009\u62E9\u76EE\u5F55\uFF1B\u5B8C\u6210\u540E\u91CD\u65B0\u4F53\u68C0\u3002")), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: probeState.status === "loading", onClick: () => {
|
|
13151
13770
|
void refresh();
|
|
13152
|
-
} }, "\u91CD\u65B0\u4F53\u68C0")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, probeState.status === "loading" && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u2026"), probeState.error && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error", role: "alert" }, probeState.error), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tools", role: "list", "aria-label": "\u5B98\u65B9\u5DE5\u5177\u6CE8\u518C\u8868" }, OFFICIAL_TOOLS.map((tool) => {
|
|
13153
|
-
const
|
|
13771
|
+
} }, "\u91CD\u65B0\u4F53\u68C0")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react5.default.createElement(InstallSettings, { settingsScope, install: probeState.install }), probeState.status === "loading" && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-empty", role: "status" }, "\u6B63\u5728\u68C0\u6D4B\u672C\u673A\u5B98\u65B9\u5DE5\u5177\u2026"), probeState.error && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error", role: "alert" }, probeState.error), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tools", role: "list", "aria-label": "\u5B98\u65B9\u5DE5\u5177\u6CE8\u518C\u8868" }, OFFICIAL_TOOLS.map((tool) => {
|
|
13772
|
+
const summary = installById[tool.id];
|
|
13773
|
+
const command = summary?.command ?? installCommandLine(tool);
|
|
13774
|
+
const methods = summary?.methods ?? installMethodsFor(tool).map((method) => ({ id: method.id, label: method.label }));
|
|
13154
13775
|
const probe = byId[tool.id];
|
|
13155
13776
|
const capability = capabilitiesById[tool.id];
|
|
13156
13777
|
const readiness = readinessById[tool.id];
|
|
13157
13778
|
const job = jobs[tool.id];
|
|
13158
13779
|
const running = job?.status === "running";
|
|
13159
13780
|
const action = toolInstallAction({ tool, probe, readiness, job, probeStatus: probeState.status, latestVersion: healthById[tool.id]?.latestVersion ?? null });
|
|
13160
|
-
const
|
|
13161
|
-
|
|
13162
|
-
|
|
13781
|
+
const maintenance = toolMaintenanceActions({
|
|
13782
|
+
tool,
|
|
13783
|
+
probe,
|
|
13784
|
+
job,
|
|
13785
|
+
probeStatus: probeState.status,
|
|
13786
|
+
summary: { installable: !summary?.error, removable: !summary?.error }
|
|
13787
|
+
});
|
|
13788
|
+
const verified = job?.status === "succeeded" && (job.operation === "uninstall" ? job.postInstallProbe?.installed === false : job.postInstallProbe?.installed === true);
|
|
13789
|
+
const operation = job?.operation === "uninstall" ? "\u5378\u8F7D" : job?.operation === "repair" ? "\u4FEE\u590D" : "\u5B89\u88C5";
|
|
13790
|
+
const status = running ? job.cancelRequested ? `\u6B63\u5728\u53D6\u6D88${operation}\u2026` : `${operation}\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" ? `${operation}\u5DF2\u53D6\u6D88\uFF0C\u8BF7\u91CD\u65B0\u68C0\u6D4B` : verified ? `${operation}\u6210\u529F\u5E76\u9A8C\u8BC1` : probeLabel(probe);
|
|
13791
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool", role: "listitem", key: tool.id }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-info" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-route-name", title: tool.purpose }, tool.label), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-route-provider" }, tool.vendor, " \xB7 ", tool.id), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-status", role: "status" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: `mr-tool-dot ${running ? "running" : probe?.installed ? "installed" : "missing"}` }), status, probe?.installed && probe.version ? ` \xB7 ${probe.version}` : "", healthById[tool.id]?.latestVersion ? ` \xB7 \u6700\u65B0 ${healthById[tool.id].latestVersion}` : ""), /* @__PURE__ */ import_react5.default.createElement(ToolLoginLine, { entry: healthById[tool.id] }), probe?.installed && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, tool.headlessAdapter ? "\u5DF2\u53EF\u7531 model_router_execute \u4EE5\u65E0\u754C\u9762\u65B9\u5F0F\u8C03\u7528\u3002\u547D\u4EE4\u7F3A\u5931\u6216\u5931\u8D25\u65F6\u56DE\u9000\u6A21\u578B\u76EE\u5F55 API\u3002\u7B7E\u540D\u6C99\u7BB1\u5165\u53E3\u4E0D\u542F\u52A8\u6B64 CLI\u3002" : readiness?.ready ? `\u5B98\u65B9\u6267\u884C\u5165\u53E3\u5DF2\u6838\u9A8C\uFF0C\u53EF\u5728\u4F1A\u8BDD\u4E2D\u8C03\u7528 model_router_tool_run\uFF1B${capability?.modes?.includes("read-only") ? "\u652F\u6301\u53EA\u8BFB\u548C\u7ECF\u5BA1\u6279\u7684\u53EF\u7F16\u8F91\u4EFB\u52A1" : "\u4EC5\u652F\u6301\u7ECF\u5BA1\u6279\u7684\u53EF\u7F16\u8F91\u9694\u79BB\u5DE5\u4F5C\u533A\u4EFB\u52A1"}\uFF0C\u8D26\u53F7\u53CA\u6A21\u578B\u4ECD\u9700\u5B9E\u6D4B\u3002` : `\u5DF2\u5B89\u88C5\uFF0C\u4F46\u5F53\u524D\u4E0D\u53EF\u6258\u7BA1\u6267\u884C\uFF1A${readiness?.reason || capability?.reason || "\u6267\u884C\u5165\u53E3\u5C1A\u672A\u6838\u9A8C\u3002"}`), command ? /* @__PURE__ */ import_react5.default.createElement("code", { className: "mr-tool-command" }, command) : /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { margin: "6px 0 0" } }, summary?.error ?? tool.unsupportedReason), (summary?.notices ?? []).map((notice) => /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail", key: notice }, notice)), probe?.detail && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, probe.detail), (rowErrors[tool.id] || job?.error) && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error mr-tool-error", role: "alert" }, rowErrors[tool.id] || job.error), Array.isArray(job?.outputTail) && job.outputTail.length > 0 && /* @__PURE__ */ import_react5.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, "\u5B89\u88C5\u65E5\u5FD7"), /* @__PURE__ */ import_react5.default.createElement("pre", null, job.outputTail.slice(-6).join("\n")))), command && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-actions" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-methods" }, /* @__PURE__ */ import_react5.default.createElement("label", null, /* @__PURE__ */ import_react5.default.createElement("span", null, "\u5B89\u88C5\u65B9\u5F0F"), /* @__PURE__ */ import_react5.default.createElement(
|
|
13792
|
+
"select",
|
|
13793
|
+
{
|
|
13794
|
+
className: "mr-mini-select",
|
|
13795
|
+
value: summary?.savedMethodId ?? summary?.methodId ?? "",
|
|
13796
|
+
disabled: running || methods.length === 0,
|
|
13797
|
+
onChange: (event) => {
|
|
13798
|
+
void setInstallMethod(tool.id, event.target.value);
|
|
13799
|
+
}
|
|
13800
|
+
},
|
|
13801
|
+
methods.map((method) => /* @__PURE__ */ import_react5.default.createElement("option", { key: method.id, value: method.id, disabled: Boolean(method.blocked) }, method.label, method.blocked ? `\uFF08${method.blocked}\uFF09` : ""))
|
|
13802
|
+
))), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-tool-button", type: "button", disabled: action.disabled, onClick: () => {
|
|
13163
13803
|
void install(tool.id);
|
|
13164
|
-
} }, action.label),
|
|
13804
|
+
} }, action.label), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary mr-tool-button", type: "button", disabled: maintenance.repair.disabled, title: maintenance.repair.title, onClick: () => {
|
|
13805
|
+
void repair(tool.id);
|
|
13806
|
+
} }, maintenance.repair.label), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary mr-tool-button", type: "button", disabled: maintenance.uninstall.disabled, title: maintenance.uninstall.title, onClick: () => {
|
|
13807
|
+
void uninstall(tool.id);
|
|
13808
|
+
} }, maintenance.uninstall.label), running && /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary mr-tool-button", type: "button", disabled: job.cancelRequested, onClick: () => {
|
|
13165
13809
|
void cancel(tool.id);
|
|
13166
|
-
} }, job.cancelRequested ? "\u6B63\u5728\u53D6\u6D88\u2026" :
|
|
13167
|
-
})), /* @__PURE__ */ import_react5.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\
|
|
13810
|
+
} }, job.cancelRequested ? "\u6B63\u5728\u53D6\u6D88\u2026" : `\u53D6\u6D88${operation}`)));
|
|
13811
|
+
})), /* @__PURE__ */ import_react5.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\u5B89\u88C5\u76EE\u5F55\u4E0E\u4E0B\u8F7D\u6E90\u6765\u81EA\u4F60\u81EA\u5DF1\u586B\u5199\u7684\u8BBE\u7F6E\uFF0C\u547D\u4EE4\u4E0A\u65B9\u5B9E\u65F6\u663E\u793A\u5C06\u8981\u6267\u884C\u7684\u5185\u5BB9\u3002\u53EF\u70B9\u201C\u53D6\u6D88\u201D\u7EC8\u6B62\u4E0B\u8F7D\u4EFB\u52A1\uFF0C\u968F\u540E\u91CD\u65B0\u68C0\u6D4B\u5B9E\u9645\u7248\u672C\u3002\u4E00\u952E\u5378\u8F7D\u53EA\u5220\u9664\u7A0B\u5E8F\u672C\u8EAB\uFF08\u811A\u672C\u5B89\u88C5\u4F1A\u987A\u5E26\u6E05\u6389\u5B83\u5728 shell \u914D\u7F6E\u91CC\u5199\u7684 PATH \u8BB0\u5F55\uFF09\uFF0C\u914D\u7F6E\u3001\u767B\u5F55\u4FE1\u606F\u548C\u5386\u53F2\u8BB0\u5F55\u4FDD\u7559\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_react5.default.createElement("code", null, "model_router_tool_install"), " / ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_tool_repair"), " / ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_tool_uninstall"), "\uFF0C\u6216\u5728\u4F1A\u8BDD\u4F7F\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "/tools"), "\u3002")));
|
|
13168
13812
|
}
|
|
13169
13813
|
var HEADLESS_TOOLS = /* @__PURE__ */ new Set(["claude-code", "codex", "gemini"]);
|
|
13170
13814
|
var WORKSPACE_VIEWS = [
|
|
@@ -13291,7 +13935,7 @@ ${reasons.map((entry, index) => `${index + 1}. ${entry.text}`).join("\n")}
|
|
|
13291
13935
|
}, []);
|
|
13292
13936
|
return { health, ledger, boundaries, busy, refreshHealth, refreshLedger, refreshBoundaries, finishOnboarding, rate, rerun };
|
|
13293
13937
|
}
|
|
13294
|
-
function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, installOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries, previewRun, startRun, terminalApi }) {
|
|
13938
|
+
function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries, previewRun, startRun, terminalApi }) {
|
|
13295
13939
|
const workbench = useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries });
|
|
13296
13940
|
const [catalogState, setCatalogState] = import_react5.default.useState({ status: "loading", catalog: null, error: "" });
|
|
13297
13941
|
const [task, setTask] = import_react5.default.useState("");
|
|
@@ -13514,9 +14158,12 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
13514
14158
|
{
|
|
13515
14159
|
listOfficialTools,
|
|
13516
14160
|
installOfficialTool,
|
|
14161
|
+
uninstallOfficialTool,
|
|
14162
|
+
repairOfficialTool,
|
|
13517
14163
|
cancelOfficialToolInstall,
|
|
13518
14164
|
officialToolInstallStatus,
|
|
13519
14165
|
onProbes: handleToolProbes,
|
|
14166
|
+
settingsScope,
|
|
13520
14167
|
health: workbench.health.report,
|
|
13521
14168
|
onRefreshHealth: () => {
|
|
13522
14169
|
void workbench.refreshHealth(true);
|
|
@@ -13567,6 +14214,26 @@ var toolIdCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#OfficialToolId`,
|
|
|
13567
14214
|
}
|
|
13568
14215
|
return value;
|
|
13569
14216
|
});
|
|
14217
|
+
var MAX_METHOD_ID_CHARS = 40;
|
|
14218
|
+
var text6 = (value) => typeof value === "string" ? value.trim() : "";
|
|
14219
|
+
var toolActionCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#OfficialToolAction`, (value) => {
|
|
14220
|
+
const request = plainObject2(value, "tool action request");
|
|
14221
|
+
for (const key of Object.keys(request)) {
|
|
14222
|
+
if (key !== "tool" && key !== "method") throw new TypeError(`unknown field ${key} in tool action request`);
|
|
14223
|
+
}
|
|
14224
|
+
const tool = getOfficialTool(text6(request.tool));
|
|
14225
|
+
if (!tool) throw new TypeError("tool must name a fixed official tool");
|
|
14226
|
+
const method = request.method === void 0 || request.method === null || request.method === "" ? null : text6(request.method);
|
|
14227
|
+
if (method !== null) {
|
|
14228
|
+
if (method.length > MAX_METHOD_ID_CHARS || !/^[A-Za-z0-9-]+$/.test(method)) {
|
|
14229
|
+
throw new TypeError("method must be one of the tool's declared install methods");
|
|
14230
|
+
}
|
|
14231
|
+
if (!installMethodsFor(tool).some((item) => item.id === method)) {
|
|
14232
|
+
throw new TypeError(`${tool.label} does not offer the install method ${method}`);
|
|
14233
|
+
}
|
|
14234
|
+
}
|
|
14235
|
+
return method === null ? { tool: tool.id } : { tool: tool.id, method };
|
|
14236
|
+
});
|
|
13570
14237
|
var listResultCodec = strictCodec(`${OFFICIAL_TOOLS_REMOTE_PACKAGE}#OfficialToolList`, (value) => {
|
|
13571
14238
|
const result = plainObject2(value, "tool list result");
|
|
13572
14239
|
if (!Array.isArray(result.tools)) throw new TypeError("tool list result needs a tools array");
|
|
@@ -13680,7 +14347,9 @@ var toolIdParameter = Object.freeze({
|
|
|
13680
14347
|
var jsonParameter = (name, codec) => Object.freeze({ name, wire: name, source: "json", codec });
|
|
13681
14348
|
var OFFICIAL_TOOLS_REMOTE_DESCRIPTORS = Object.freeze([
|
|
13682
14349
|
descriptor("list", [], listResultCodec),
|
|
13683
|
-
descriptor("installTool", [
|
|
14350
|
+
descriptor("installTool", [jsonParameter("request", toolActionCodec)], installResultCodec),
|
|
14351
|
+
descriptor("uninstallTool", [jsonParameter("request", toolActionCodec)], installResultCodec),
|
|
14352
|
+
descriptor("repairTool", [jsonParameter("request", toolActionCodec)], installResultCodec),
|
|
13684
14353
|
descriptor("cancel", [toolIdParameter], installResultCodec),
|
|
13685
14354
|
descriptor("status", [toolIdParameter], statusResultCodec),
|
|
13686
14355
|
// Workbench: onboarding health check, run ledger, ratings, step retry, security boundaries.
|
|
@@ -13744,8 +14413,8 @@ function boundedNumberField(field2, { minimum = 0, maximum = Number.MAX_SAFE_INT
|
|
|
13744
14413
|
const numeric = (0, import_dsh_client_ui_primitives.settingsNumberField)(field2);
|
|
13745
14414
|
return {
|
|
13746
14415
|
...numeric,
|
|
13747
|
-
parse: (
|
|
13748
|
-
const write = numeric.parse(
|
|
14416
|
+
parse: (text7) => {
|
|
14417
|
+
const write = numeric.parse(text7);
|
|
13749
14418
|
if (write?.kind !== "set") return write;
|
|
13750
14419
|
const value = write.value;
|
|
13751
14420
|
if (typeof value !== "number" || value < minimum || value > maximum) return void 0;
|
|
@@ -13758,10 +14427,10 @@ function modelProfilesField() {
|
|
|
13758
14427
|
const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("modelProfilesJson");
|
|
13759
14428
|
return {
|
|
13760
14429
|
...field2,
|
|
13761
|
-
parse: (
|
|
14430
|
+
parse: (text7) => {
|
|
13762
14431
|
try {
|
|
13763
|
-
parseModelProfilesJson(
|
|
13764
|
-
return field2.parse(
|
|
14432
|
+
parseModelProfilesJson(text7);
|
|
14433
|
+
return field2.parse(text7);
|
|
13765
14434
|
} catch {
|
|
13766
14435
|
return void 0;
|
|
13767
14436
|
}
|
|
@@ -13772,15 +14441,79 @@ function quotaPatternsField() {
|
|
|
13772
14441
|
const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("quotaPatternsJson");
|
|
13773
14442
|
return {
|
|
13774
14443
|
...field2,
|
|
13775
|
-
parse: (
|
|
13776
|
-
const raw = String(
|
|
14444
|
+
parse: (text7) => {
|
|
14445
|
+
const raw = String(text7 ?? "").trim() || "{}";
|
|
13777
14446
|
try {
|
|
13778
14447
|
const value = JSON.parse(raw);
|
|
13779
14448
|
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
13780
14449
|
} catch {
|
|
13781
14450
|
return void 0;
|
|
13782
14451
|
}
|
|
13783
|
-
return parseQuotaPatterns(raw).errors.length ? void 0 : field2.parse(
|
|
14452
|
+
return parseQuotaPatterns(raw).errors.length ? void 0 : field2.parse(text7);
|
|
14453
|
+
}
|
|
14454
|
+
};
|
|
14455
|
+
}
|
|
14456
|
+
function installDirField() {
|
|
14457
|
+
const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("toolInstallDir");
|
|
14458
|
+
return {
|
|
14459
|
+
...field2,
|
|
14460
|
+
parse: (text7) => {
|
|
14461
|
+
if (!String(text7 ?? "").trim()) return field2.parse(text7);
|
|
14462
|
+
try {
|
|
14463
|
+
expandInstallDir(text7);
|
|
14464
|
+
} catch {
|
|
14465
|
+
return void 0;
|
|
14466
|
+
}
|
|
14467
|
+
return field2.parse(text7);
|
|
14468
|
+
}
|
|
14469
|
+
};
|
|
14470
|
+
}
|
|
14471
|
+
function npmRegistryField() {
|
|
14472
|
+
const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("toolNpmRegistry");
|
|
14473
|
+
return {
|
|
14474
|
+
...field2,
|
|
14475
|
+
parse: (text7) => {
|
|
14476
|
+
const raw = String(text7 ?? "").trim() || DEFAULT_NPM_REGISTRY;
|
|
14477
|
+
try {
|
|
14478
|
+
normalizeSourceUrl(raw, "npm \u6E90");
|
|
14479
|
+
} catch {
|
|
14480
|
+
return void 0;
|
|
14481
|
+
}
|
|
14482
|
+
return field2.parse(text7);
|
|
14483
|
+
}
|
|
14484
|
+
};
|
|
14485
|
+
}
|
|
14486
|
+
function scriptUrlsField() {
|
|
14487
|
+
const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("toolScriptUrlsJson");
|
|
14488
|
+
return {
|
|
14489
|
+
...field2,
|
|
14490
|
+
parse: (text7) => {
|
|
14491
|
+
const raw = String(text7 ?? "").trim() || "{}";
|
|
14492
|
+
try {
|
|
14493
|
+
const parsed = JSON.parse(raw);
|
|
14494
|
+
parseInstallPreferences({ toolScriptUrlsJson: raw }, { tools: OFFICIAL_TOOLS });
|
|
14495
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
14496
|
+
} catch {
|
|
14497
|
+
return void 0;
|
|
14498
|
+
}
|
|
14499
|
+
return field2.parse(text7);
|
|
14500
|
+
}
|
|
14501
|
+
};
|
|
14502
|
+
}
|
|
14503
|
+
function installMethodsField() {
|
|
14504
|
+
const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("toolInstallMethodsJson");
|
|
14505
|
+
return {
|
|
14506
|
+
...field2,
|
|
14507
|
+
parse: (text7) => {
|
|
14508
|
+
const raw = String(text7 ?? "").trim() || "{}";
|
|
14509
|
+
try {
|
|
14510
|
+
const parsed = JSON.parse(raw);
|
|
14511
|
+
parseInstallPreferences({ toolInstallMethodsJson: raw }, { tools: OFFICIAL_TOOLS });
|
|
14512
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
|
|
14513
|
+
} catch {
|
|
14514
|
+
return void 0;
|
|
14515
|
+
}
|
|
14516
|
+
return field2.parse(text7);
|
|
13784
14517
|
}
|
|
13785
14518
|
};
|
|
13786
14519
|
}
|
|
@@ -13794,7 +14527,11 @@ var RouterSettingsCardController = class {
|
|
|
13794
14527
|
boundedNumberField("reviewSampleRate", { minimum: 0, maximum: 1 }),
|
|
13795
14528
|
boundedNumberField("subscriptionCooldownMinutes", { minimum: 1, maximum: 10080, integer: true }),
|
|
13796
14529
|
modelProfilesField(),
|
|
13797
|
-
quotaPatternsField()
|
|
14530
|
+
quotaPatternsField(),
|
|
14531
|
+
installDirField(),
|
|
14532
|
+
npmRegistryField(),
|
|
14533
|
+
installMethodsField(),
|
|
14534
|
+
scriptUrlsField()
|
|
13798
14535
|
]);
|
|
13799
14536
|
this.store = this.form.bind(() => ({
|
|
13800
14537
|
...this.form.shell(),
|
|
@@ -13805,7 +14542,11 @@ var RouterSettingsCardController = class {
|
|
|
13805
14542
|
reviewSampleRate: this.form.field("reviewSampleRate"),
|
|
13806
14543
|
subscriptionCooldownMinutes: this.form.field("subscriptionCooldownMinutes"),
|
|
13807
14544
|
modelProfilesJson: this.form.field("modelProfilesJson"),
|
|
13808
|
-
quotaPatternsJson: this.form.field("quotaPatternsJson")
|
|
14545
|
+
quotaPatternsJson: this.form.field("quotaPatternsJson"),
|
|
14546
|
+
toolInstallDir: this.form.field("toolInstallDir"),
|
|
14547
|
+
toolNpmRegistry: this.form.field("toolNpmRegistry"),
|
|
14548
|
+
toolInstallMethodsJson: this.form.field("toolInstallMethodsJson"),
|
|
14549
|
+
toolScriptUrlsJson: this.form.field("toolScriptUrlsJson")
|
|
13809
14550
|
}));
|
|
13810
14551
|
}
|
|
13811
14552
|
/** Supply the snapshot hook and staged form actions to the Plugins slot. */
|
|
@@ -13838,8 +14579,8 @@ function RouterSettingsCard(props) {
|
|
|
13838
14579
|
overriddenLabel: FIELD_COPY.overridden,
|
|
13839
14580
|
resetLabel: FIELD_COPY.reset,
|
|
13840
14581
|
invalidLabel: FIELD_COPY.invalidNumber,
|
|
13841
|
-
onEdit: (
|
|
13842
|
-
props.edit("budgetUsd",
|
|
14582
|
+
onEdit: (text7) => {
|
|
14583
|
+
props.edit("budgetUsd", text7);
|
|
13843
14584
|
},
|
|
13844
14585
|
onReset: () => {
|
|
13845
14586
|
props.resetField("budgetUsd");
|
|
@@ -13857,8 +14598,8 @@ function RouterSettingsCard(props) {
|
|
|
13857
14598
|
overriddenLabel: FIELD_COPY.overridden,
|
|
13858
14599
|
resetLabel: FIELD_COPY.reset,
|
|
13859
14600
|
invalidLabel: FIELD_COPY.invalidNumber,
|
|
13860
|
-
onEdit: (
|
|
13861
|
-
props.edit("maxConsultOutputChars",
|
|
14601
|
+
onEdit: (text7) => {
|
|
14602
|
+
props.edit("maxConsultOutputChars", text7);
|
|
13862
14603
|
},
|
|
13863
14604
|
onReset: () => {
|
|
13864
14605
|
props.resetField("maxConsultOutputChars");
|
|
@@ -13881,8 +14622,8 @@ function RouterSettingsCard(props) {
|
|
|
13881
14622
|
overriddenLabel: FIELD_COPY.overridden,
|
|
13882
14623
|
resetLabel: FIELD_COPY.reset,
|
|
13883
14624
|
invalidLabel: FIELD_COPY.invalidNumber,
|
|
13884
|
-
onEdit: (
|
|
13885
|
-
props.edit(key,
|
|
14625
|
+
onEdit: (text7) => {
|
|
14626
|
+
props.edit(key, text7);
|
|
13886
14627
|
},
|
|
13887
14628
|
onReset: () => {
|
|
13888
14629
|
props.resetField(key);
|
|
@@ -13929,7 +14670,82 @@ function RouterSettingsCard(props) {
|
|
|
13929
14670
|
), state.quotaPatternsJson.invalid && /* @__PURE__ */ import_react6.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_react6.default.createElement("details", { style: styles.profileExample }, /* @__PURE__ */ import_react6.default.createElement("summary", null, "\u67E5\u770B\u89C4\u5219\u683C\u5F0F"), /* @__PURE__ */ import_react6.default.createElement("pre", null, `{
|
|
13930
14671
|
"kimi-code": { "quota": ["\u989D\u5EA6\u5DF2\u7528\u5B8C"], "rateLimit": ["\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41"] },
|
|
13931
14672
|
"my-glm-plan": { "quota": ["Usage limit reached for", "1308"] }
|
|
13932
|
-
}`)), /* @__PURE__ */ import_react6.default.createElement("button", { type: "button", disabled, onClick: () => props.resetField("quotaPatternsJson") }, "\u6062\u590D\u9ED8\u8BA4\u89C4\u5219")), /* @__PURE__ */ import_react6.default.createElement("
|
|
14673
|
+
}`)), /* @__PURE__ */ import_react6.default.createElement("button", { type: "button", disabled, onClick: () => props.resetField("quotaPatternsJson") }, "\u6062\u590D\u9ED8\u8BA4\u89C4\u5219")), /* @__PURE__ */ import_react6.default.createElement("div", { style: styles.profileEditor }, /* @__PURE__ */ import_react6.default.createElement("span", { style: styles.profileLabel }, "\u5B98\u65B9\u5DE5\u5177\u7EDF\u4E00\u5B89\u88C5\u8BBE\u7F6E"), /* @__PURE__ */ import_react6.default.createElement("p", { style: styles.noticeText }, "\u5BF9\u6240\u6709\u5B98\u65B9\u5DE5\u5177\u7684\u4E00\u952E\u5B89\u88C5\u3001\u4FEE\u590D\u548C\u5378\u8F7D\u751F\u6548\u3002\u5DE5\u4F5C\u53F0\u7684\u201C\u5B98\u65B9\u5DE5\u5177\u201D\u9875\u4E5F\u80FD\u6539\u540C\u6837\u7684\u5B57\u6BB5\uFF0C\u5E76\u4F1A\u5B9E\u65F6\u663E\u793A\u6BCF\u4E2A\u5DE5\u5177\u5C06\u8981\u6267\u884C\u7684\u547D\u4EE4\u3002 \u5B89\u88C5\u547D\u4EE4\u59CB\u7EC8\u6765\u81EA\u56FA\u5B9A\u6CE8\u518C\u8868\uFF0C\u8FD9\u91CC\u53EA\u51B3\u5B9A\u76EE\u5F55\u4E0E\u4E0B\u8F7D\u6E90\uFF0C\u4E0D\u63A5\u53D7\u81EA\u5B9A\u4E49\u5305\u540D\u6216\u4EFB\u610F\u5730\u5740\u3002"), /* @__PURE__ */ import_react6.default.createElement(
|
|
14674
|
+
import_dsh_client_ui_primitives.SettingsValueField,
|
|
14675
|
+
{
|
|
14676
|
+
id: "model-router-tool-install-dir",
|
|
14677
|
+
label: "\u7EDF\u4E00\u5B89\u88C5\u76EE\u5F55",
|
|
14678
|
+
hint: "\u7559\u7A7A\u8868\u793A\u4F7F\u7528\u5404\u5382\u5546\u9ED8\u8BA4\u4F4D\u7F6E\u3002npm \u4E0E pnpm \u4F1A\u5E26\u4E0A --prefix\uFF1B\u652F\u6301\u76EE\u5F55\u7684\u5B98\u65B9\u811A\u672C\u4F1A\u628A\u8FD9\u4E2A\u8DEF\u5F84\u4F20\u7ED9\u5382\u5546\u81EA\u5DF1\u7684\u5B89\u88C5\u76EE\u5F55\u53D8\u91CF\uFF08\u4F8B\u5982 MCODE_INSTALL_DIR\uFF09\u3002\u5199\u6B7B\u8DEF\u5F84\u7684\u811A\u672C\u4F1A\u5728\u5DE5\u5177\u884C\u6807\u660E\u5B9E\u9645\u843D\u70B9\u3002\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u3002\u66F4\u65B0\u4F7F\u7528\u540C\u4E00\u8DEF\u5F84\u3002",
|
|
14679
|
+
disabled,
|
|
14680
|
+
...state.toolInstallDir,
|
|
14681
|
+
overriddenLabel: FIELD_COPY.overridden,
|
|
14682
|
+
resetLabel: FIELD_COPY.reset,
|
|
14683
|
+
invalidLabel: "\u8BF7\u8F93\u5165\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u6216\u7559\u7A7A\u6062\u590D\u9ED8\u8BA4\u3002",
|
|
14684
|
+
onEdit: (value) => {
|
|
14685
|
+
props.edit("toolInstallDir", value);
|
|
14686
|
+
},
|
|
14687
|
+
onReset: () => {
|
|
14688
|
+
props.resetField("toolInstallDir");
|
|
14689
|
+
}
|
|
14690
|
+
}
|
|
14691
|
+
), /* @__PURE__ */ import_react6.default.createElement(
|
|
14692
|
+
import_dsh_client_ui_primitives.SettingsValueField,
|
|
14693
|
+
{
|
|
14694
|
+
id: "model-router-tool-npm-registry",
|
|
14695
|
+
label: "npm \u6E90\u5730\u5740",
|
|
14696
|
+
hint: "\u6240\u6709\u5305\u7BA1\u7406\u5668\u5B89\u88C5\u65B9\u5F0F\u4ECE\u8BE5\u5730\u5740\u4E0B\u8F7D\uFF0C\u5FC5\u987B\u662F https \u94FE\u63A5\u3002\u56FD\u5185\u7F51\u7EDC\u53EF\u586B\u955C\u50CF\u6E90\uFF0C\u4F8B\u5982 https://registry.npmmirror.com/\u3002",
|
|
14697
|
+
disabled,
|
|
14698
|
+
...state.toolNpmRegistry,
|
|
14699
|
+
overriddenLabel: FIELD_COPY.overridden,
|
|
14700
|
+
resetLabel: FIELD_COPY.reset,
|
|
14701
|
+
invalidLabel: "\u9700\u8981 https \u5F00\u5934\u7684\u5B8C\u6574\u5730\u5740\u3002",
|
|
14702
|
+
onEdit: (value) => {
|
|
14703
|
+
props.edit("toolNpmRegistry", value);
|
|
14704
|
+
},
|
|
14705
|
+
onReset: () => {
|
|
14706
|
+
props.resetField("toolNpmRegistry");
|
|
14707
|
+
}
|
|
14708
|
+
}
|
|
14709
|
+
), /* @__PURE__ */ import_react6.default.createElement(
|
|
14710
|
+
import_dsh_client_ui_primitives.SettingsValueField,
|
|
14711
|
+
{
|
|
14712
|
+
id: "model-router-tool-install-methods",
|
|
14713
|
+
label: "\u9ED8\u8BA4\u5B89\u88C5\u65B9\u5F0F\uFF08JSON\uFF0C\u53EF\u9009\uFF09",
|
|
14714
|
+
hint: "\u6309\u5DE5\u5177 ID \u56FA\u5B9A\u4E00\u79CD\u5B89\u88C5\u65B9\u5F0F\uFF0C\u4F8B\u5982\u56FA\u5B9A Step Code \u5728 Windows \u4E0A\u7528 irm | iex\u3002\u7559\u7A7A\u8868\u793A\u4F7F\u7528\u8BE5\u5DE5\u5177\u7684\u9ED8\u8BA4\u65B9\u5F0F\u3002\u53EF\u9009\u503C\uFF1Anpm\u3001pnpm\u3001script-bash\uFF08curl | bash\uFF09\u3001script-powershell\uFF08irm | iex\uFF09\u3002",
|
|
14715
|
+
disabled,
|
|
14716
|
+
...state.toolInstallMethodsJson,
|
|
14717
|
+
overriddenLabel: FIELD_COPY.overridden,
|
|
14718
|
+
resetLabel: FIELD_COPY.reset,
|
|
14719
|
+
invalidLabel: "\u9700\u8981 JSON \u5BF9\u8C61\uFF0C\u4E14\u6BCF\u4E2A\u952E\u90FD\u662F\u5B98\u65B9\u5DE5\u5177 ID\u3001\u6BCF\u4E2A\u503C\u90FD\u662F\u8BE5\u5DE5\u5177\u652F\u6301\u7684\u5B89\u88C5\u65B9\u5F0F\u3002",
|
|
14720
|
+
onEdit: (value) => {
|
|
14721
|
+
props.edit("toolInstallMethodsJson", value);
|
|
14722
|
+
},
|
|
14723
|
+
onReset: () => {
|
|
14724
|
+
props.resetField("toolInstallMethodsJson");
|
|
14725
|
+
}
|
|
14726
|
+
}
|
|
14727
|
+
), /* @__PURE__ */ import_react6.default.createElement(
|
|
14728
|
+
import_dsh_client_ui_primitives.SettingsValueField,
|
|
14729
|
+
{
|
|
14730
|
+
id: "model-router-tool-script-urls",
|
|
14731
|
+
label: "\u5B89\u88C5\u811A\u672C\u6E90\u8986\u76D6\uFF08JSON\uFF0C\u53EF\u9009\uFF09",
|
|
14732
|
+
hint: "\u6309\u5DE5\u5177 ID \u6307\u5B9A\u5382\u5546\u5B89\u88C5\u811A\u672C\u7684\u955C\u50CF\u5730\u5740\uFF08\u5FC5\u987B\u662F https\uFF09\u3002\u63D2\u4EF6\u4F1A\u5148\u4E0B\u8F7D\u811A\u672C\u3001\u6838\u5BF9\u5B83\u4ECD\u7136\u662F\u8BE5\u5382\u5546\u7684\u5B98\u65B9\u5B89\u88C5\u811A\u672C\uFF0C\u518D\u6267\u884C\u672C\u5730\u526F\u672C\uFF1B\u955C\u50CF\u4E0D\u80FD\u66FF\u6362\u6210\u522B\u7684\u7A0B\u5E8F\u3002",
|
|
14733
|
+
disabled,
|
|
14734
|
+
...state.toolScriptUrlsJson,
|
|
14735
|
+
overriddenLabel: FIELD_COPY.overridden,
|
|
14736
|
+
resetLabel: FIELD_COPY.reset,
|
|
14737
|
+
invalidLabel: "\u9700\u8981 JSON \u5BF9\u8C61\uFF0C\u952E\u662F\u5B98\u65B9\u5DE5\u5177 ID\uFF0C\u503C\u662F https \u94FE\u63A5\u3002",
|
|
14738
|
+
onEdit: (value) => {
|
|
14739
|
+
props.edit("toolScriptUrlsJson", value);
|
|
14740
|
+
},
|
|
14741
|
+
onReset: () => {
|
|
14742
|
+
props.resetField("toolScriptUrlsJson");
|
|
14743
|
+
}
|
|
14744
|
+
}
|
|
14745
|
+
), /* @__PURE__ */ import_react6.default.createElement("details", { style: styles.profileExample }, /* @__PURE__ */ import_react6.default.createElement("summary", null, "\u67E5\u770B\u683C\u5F0F"), /* @__PURE__ */ import_react6.default.createElement("pre", null, `{
|
|
14746
|
+
"stepcode": "https://mirror.example.com/stepcode/install.ps1",
|
|
14747
|
+
"opencode": "https://mirror.example.com/opencode/install"
|
|
14748
|
+
}`), /* @__PURE__ */ import_react6.default.createElement("p", { style: styles.noticeText }, "\u5B89\u88C5\u811A\u672C\u65B9\u5F0F\uFF08curl / irm\uFF09\u53EF\u4EE5\u5728\u5DE5\u4F5C\u53F0\u7684\u201C\u5B98\u65B9\u5DE5\u5177\u201D\u9875\u5173\u95ED\uFF1B\u5173\u95ED\u540E\u6240\u6709\u5DE5\u5177\u53EA\u80FD\u901A\u8FC7 npm \u6216 pnpm \u5B89\u88C5\u3002"))), /* @__PURE__ */ import_react6.default.createElement("aside", { style: styles.notice, "aria-label": "\u6A21\u578B\u8DEF\u7531\u4F7F\u7528\u8BF4\u660E" }, /* @__PURE__ */ import_react6.default.createElement("div", { style: styles.titleLine }, /* @__PURE__ */ import_react6.default.createElement(import_dsh_client_ui_primitives.Tag, { tone: "info" }, "\u5B98\u65B9\u6A21\u578B\u914D\u7F6E")), /* @__PURE__ */ import_react6.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_react6.default.createElement("p", { style: styles.noticeText }, "\u4F7F\u7528 ", /* @__PURE__ */ import_react6.default.createElement("code", null, "model_router_plan"), " \u83B7\u53D6\u53EF\u5BA1\u9605\u7684\u8DEF\u7531\u5EFA\u8BAE\uFF0C\u4F7F\u7528 ", /* @__PURE__ */ import_react6.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")));
|
|
13933
14749
|
}
|
|
13934
14750
|
function OpenRouterWorkspace({ subject, openPanel }) {
|
|
13935
14751
|
if (subject?.kind !== "bundle" || subject.pkg?.name !== ROUTER_PACKAGE) return null;
|
|
@@ -13954,7 +14770,9 @@ function registerUi(ctx) {
|
|
|
13954
14770
|
loadCatalog: () => ctx.remote.session.modelCatalog(),
|
|
13955
14771
|
settingsScope,
|
|
13956
14772
|
listOfficialTools: () => officialToolsRemote.list(),
|
|
13957
|
-
installOfficialTool: (
|
|
14773
|
+
installOfficialTool: (request) => officialToolsRemote.installTool(request),
|
|
14774
|
+
uninstallOfficialTool: (request) => officialToolsRemote.uninstallTool(request),
|
|
14775
|
+
repairOfficialTool: (request) => officialToolsRemote.repairTool(request),
|
|
13958
14776
|
cancelOfficialToolInstall: (toolId) => officialToolsRemote.cancel(toolId),
|
|
13959
14777
|
officialToolInstallStatus: (toolId) => officialToolsRemote.status(toolId),
|
|
13960
14778
|
toolHealth: (fresh) => officialToolsRemote.health(fresh),
|