@ljwei-stak/dsh-model-router 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dsh-plugin/client.js +331 -85
- package/.dsh-plugin/index.mjs +1 -1
- package/.dsh-plugin/official-tools-remote-service.mjs +46 -10
- package/.dsh-plugin/shared/official-tool-executor.mjs +135 -47
- package/.dsh-plugin/shared/official-tool-registry.mjs +145 -12
- package/.dsh-plugin/shared/official-tools-runtime.mjs +426 -118
- package/.dsh-plugin/shared/tool-install-preferences.mjs +82 -26
- package/.dsh-plugin/shared/vendor-mimo-grok-adapter.mjs +41 -16
- package/CHANGELOG.md +22 -1
- package/README.md +19 -10
- package/README.zh.md +19 -10
- package/{INSTALLATION_GUIDE.zh.md → docs/INSTALLATION_GUIDE.zh.md} +16 -16
- package/docs/WORKBENCH_USER_GUIDE.zh.md +27 -5
- package/{MIGRATION.md → docs/archive/MIGRATION.md} +1 -1
- package/docs/archive/README.md +21 -0
- package/package.json +4 -4
package/.dsh-plugin/client.js
CHANGED
|
@@ -47,7 +47,7 @@ var import_react6 = __toESM(require("react"), 1);
|
|
|
47
47
|
|
|
48
48
|
// .dsh-plugin/shared/official-tool-registry.mjs
|
|
49
49
|
var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
50
|
-
function packageManagerMethod(id2, label, manager, spec, { registryFlag = "--registry=" } = {}) {
|
|
50
|
+
function packageManagerMethod(id2, label, manager, spec, { registryFlag = "--registry=", command = "install", extraArgs = [] } = {}) {
|
|
51
51
|
return Object.freeze({
|
|
52
52
|
id: id2,
|
|
53
53
|
label,
|
|
@@ -55,14 +55,31 @@ function packageManagerMethod(id2, label, manager, spec, { registryFlag = "--reg
|
|
|
55
55
|
manager,
|
|
56
56
|
spec,
|
|
57
57
|
registryFlag,
|
|
58
|
-
installArgs: Object.freeze([
|
|
58
|
+
installArgs: Object.freeze([command, "-g", spec, ...extraArgs]),
|
|
59
59
|
uninstallArgs: Object.freeze(["uninstall", "-g", spec.replace(/@latest$/, "")]),
|
|
60
|
-
/**
|
|
60
|
+
/** The resolver binds npm prefix or pnpm global-dir/global-bin-dir. */
|
|
61
61
|
supportsInstallDir: true,
|
|
62
62
|
supportsRegistry: true
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
|
-
function scriptMethod(id2, label, {
|
|
65
|
+
function scriptMethod(id2, label, {
|
|
66
|
+
shell,
|
|
67
|
+
scriptUrl,
|
|
68
|
+
verify,
|
|
69
|
+
installArg = [],
|
|
70
|
+
env = [],
|
|
71
|
+
platforms,
|
|
72
|
+
supportsInstallDir = false,
|
|
73
|
+
installDirEnv = "",
|
|
74
|
+
installDirSuffix = "",
|
|
75
|
+
defaultScriptInstallDir,
|
|
76
|
+
defaultScriptInstallDirEnv,
|
|
77
|
+
scriptBinaryNames,
|
|
78
|
+
registryEnv,
|
|
79
|
+
installDirSubdir,
|
|
80
|
+
uninstallUnsupportedReason,
|
|
81
|
+
scriptFallbackUrls
|
|
82
|
+
}) {
|
|
66
83
|
return Object.freeze({
|
|
67
84
|
id: id2,
|
|
68
85
|
label,
|
|
@@ -77,7 +94,16 @@ function scriptMethod(id2, label, { shell, scriptUrl, verify, installArg = [], e
|
|
|
77
94
|
platforms: Object.freeze(platforms),
|
|
78
95
|
/** Whether the vendor script honours a caller-chosen directory at all. */
|
|
79
96
|
supportsInstallDir,
|
|
80
|
-
|
|
97
|
+
installDirEnv,
|
|
98
|
+
installDirSuffix,
|
|
99
|
+
...installDirSubdir ? { installDirSubdir } : {},
|
|
100
|
+
...uninstallUnsupportedReason ? { uninstallUnsupportedReason } : {},
|
|
101
|
+
...defaultScriptInstallDir ? { defaultScriptInstallDir } : {},
|
|
102
|
+
...defaultScriptInstallDirEnv ? { defaultScriptInstallDirEnv } : {},
|
|
103
|
+
...scriptBinaryNames ? { scriptBinaryNames: Object.freeze(scriptBinaryNames) } : {},
|
|
104
|
+
...scriptFallbackUrls ? { scriptFallbackUrls: Object.freeze(scriptFallbackUrls) } : {},
|
|
105
|
+
...registryEnv ? { registryEnv } : {},
|
|
106
|
+
supportsRegistry: Boolean(registryEnv)
|
|
81
107
|
});
|
|
82
108
|
}
|
|
83
109
|
var OFFICIAL_TOOLS = Object.freeze([
|
|
@@ -93,9 +119,33 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
93
119
|
probeExecutables: ["kimi"],
|
|
94
120
|
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",
|
|
95
121
|
providerHints: ["moonshot", "kimi"],
|
|
122
|
+
scriptBinaryNames: Object.freeze(["kimi", "kimi.exe"]),
|
|
123
|
+
defaultScriptInstallDir: ".kimi-code/bin",
|
|
96
124
|
installMethods: Object.freeze([
|
|
97
125
|
packageManagerMethod("npm", "npm", "npm", "@moonshot-ai/kimi-code@latest"),
|
|
98
|
-
packageManagerMethod("pnpm", "pnpm", "pnpm", "@moonshot-ai/kimi-code@latest")
|
|
126
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@moonshot-ai/kimi-code@latest"),
|
|
127
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
128
|
+
shell: "bash",
|
|
129
|
+
scriptUrl: "https://code.kimi.com/kimi-code/install.sh",
|
|
130
|
+
platforms: ["linux", "darwin"],
|
|
131
|
+
supportsInstallDir: true,
|
|
132
|
+
installDirEnv: "KIMI_INSTALL_DIR",
|
|
133
|
+
installDirSuffix: "bin",
|
|
134
|
+
env: ["KIMI_INSTALL_DIR"],
|
|
135
|
+
scriptBinaryNames: ["kimi"],
|
|
136
|
+
verify: Object.freeze({ mustInclude: ["kimi-code", "code.kimi.com/kimi-code"] })
|
|
137
|
+
}),
|
|
138
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
139
|
+
shell: "powershell",
|
|
140
|
+
scriptUrl: "https://code.kimi.com/kimi-code/install.ps1",
|
|
141
|
+
platforms: ["win32"],
|
|
142
|
+
supportsInstallDir: true,
|
|
143
|
+
installDirEnv: "KIMI_INSTALL_DIR",
|
|
144
|
+
installDirSuffix: "bin",
|
|
145
|
+
env: ["KIMI_INSTALL_DIR"],
|
|
146
|
+
scriptBinaryNames: ["kimi.exe"],
|
|
147
|
+
verify: Object.freeze({ mustInclude: ["kimi-code", "code.kimi.com/kimi-code"] })
|
|
148
|
+
})
|
|
99
149
|
])
|
|
100
150
|
}),
|
|
101
151
|
Object.freeze({
|
|
@@ -109,9 +159,31 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
109
159
|
uninstallArgs: ["uninstall", "-g", "@anthropic-ai/claude-code"],
|
|
110
160
|
probeExecutables: ["claude"],
|
|
111
161
|
providerHints: ["anthropic", "claude"],
|
|
162
|
+
scriptBinaryNames: Object.freeze(["claude", "claude.exe"]),
|
|
163
|
+
defaultScriptInstallDir: ".local/bin",
|
|
112
164
|
installMethods: Object.freeze([
|
|
113
165
|
packageManagerMethod("npm", "npm", "npm", "@anthropic-ai/claude-code@latest"),
|
|
114
|
-
packageManagerMethod("pnpm", "pnpm", "pnpm", "@anthropic-ai/claude-code@latest"
|
|
166
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@anthropic-ai/claude-code@latest", {
|
|
167
|
+
command: "add",
|
|
168
|
+
extraArgs: ["--ignore-scripts=false", "--allow-build=@anthropic-ai/claude-code"]
|
|
169
|
+
}),
|
|
170
|
+
// The native installer has no directory argument. npm/pnpm support a prefix.
|
|
171
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
172
|
+
shell: "bash",
|
|
173
|
+
scriptUrl: "https://claude.ai/install.sh",
|
|
174
|
+
scriptFallbackUrls: ["https://downloads.claude.ai/claude-code-releases/bootstrap.sh"],
|
|
175
|
+
platforms: ["linux", "darwin"],
|
|
176
|
+
scriptBinaryNames: ["claude"],
|
|
177
|
+
verify: Object.freeze({ mustInclude: ["downloads.claude.ai/claude-code-releases", "manifest.json"] })
|
|
178
|
+
}),
|
|
179
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
180
|
+
shell: "powershell",
|
|
181
|
+
scriptUrl: "https://claude.ai/install.ps1",
|
|
182
|
+
scriptFallbackUrls: ["https://downloads.claude.ai/claude-code-releases/bootstrap.ps1"],
|
|
183
|
+
platforms: ["win32"],
|
|
184
|
+
scriptBinaryNames: ["claude.exe"],
|
|
185
|
+
verify: Object.freeze({ mustInclude: ["downloads.claude.ai/claude-code-releases", "manifest.json"] })
|
|
186
|
+
})
|
|
115
187
|
])
|
|
116
188
|
}),
|
|
117
189
|
Object.freeze({
|
|
@@ -126,9 +198,36 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
126
198
|
probeExecutables: ["codex"],
|
|
127
199
|
probeNote: "Codex \u7248\u672C\u6A2A\u5E45\u7531\u9002\u914D\u5C42\u5BBD\u5339\u914D\uFF1B\u5B89\u88C5\u65F6\u53D6 npm \u6700\u65B0\u7248\u3002",
|
|
128
200
|
providerHints: ["openai", "gpt", "codex"],
|
|
201
|
+
scriptBinaryNames: Object.freeze(["codex", "codex.exe"]),
|
|
202
|
+
defaultScriptInstallDir: ".local/bin",
|
|
129
203
|
installMethods: Object.freeze([
|
|
130
204
|
packageManagerMethod("npm", "npm", "npm", "@openai/codex@latest"),
|
|
131
|
-
packageManagerMethod("pnpm", "pnpm", "pnpm", "@openai/codex@latest")
|
|
205
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@openai/codex@latest"),
|
|
206
|
+
scriptMethod("script-sh", "curl | sh", {
|
|
207
|
+
shell: "sh",
|
|
208
|
+
scriptUrl: "https://chatgpt.com/codex/install.sh",
|
|
209
|
+
platforms: ["linux", "darwin"],
|
|
210
|
+
supportsInstallDir: true,
|
|
211
|
+
installDirEnv: "CODEX_INSTALL_DIR",
|
|
212
|
+
env: ["CODEX_INSTALL_DIR"],
|
|
213
|
+
scriptBinaryNames: ["codex"],
|
|
214
|
+
verify: Object.freeze({ mustInclude: ["releases.openai.com/codex", "CODEX_INSTALL_DIR"] })
|
|
215
|
+
}),
|
|
216
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
217
|
+
shell: "powershell",
|
|
218
|
+
scriptUrl: "https://chatgpt.com/codex/install.ps1",
|
|
219
|
+
platforms: ["win32"],
|
|
220
|
+
supportsInstallDir: true,
|
|
221
|
+
installDirEnv: "CODEX_INSTALL_DIR",
|
|
222
|
+
env: ["CODEX_INSTALL_DIR"],
|
|
223
|
+
defaultScriptInstallDirEnv: "LOCALAPPDATA",
|
|
224
|
+
defaultScriptInstallDir: "Programs/OpenAI/Codex/bin",
|
|
225
|
+
installDirSubdir: "codex/bin",
|
|
226
|
+
uninstallUnsupportedReason: "Codex \u5B98\u65B9 Windows \u811A\u672C\u4F7F\u7528\u76EE\u5F55\u8054\u63A5\u548C\u7248\u672C\u5316\u8D44\u6E90\uFF1B\u8BF7\u6309\u5B98\u65B9\u5378\u8F7D\u8BF4\u660E\u79FB\u9664\uFF0C\u63D2\u4EF6\u4E0D\u4F1A\u5220\u9664\u8054\u63A5\u76EE\u6807\u3002",
|
|
227
|
+
// The Windows bin directory is a junction to the versioned payload.
|
|
228
|
+
scriptBinaryNames: ["codex.exe"],
|
|
229
|
+
verify: Object.freeze({ mustInclude: ["releases.openai.com/codex", "CODEX_INSTALL_DIR"] })
|
|
230
|
+
})
|
|
132
231
|
])
|
|
133
232
|
}),
|
|
134
233
|
Object.freeze({
|
|
@@ -142,9 +241,40 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
142
241
|
uninstallArgs: ["uninstall", "-g", "@minimax-ai/code"],
|
|
143
242
|
probeExecutables: ["mcode"],
|
|
144
243
|
providerHints: ["minimax"],
|
|
244
|
+
defaultMethodsByPlatform: Object.freeze({ win32: "script-powershell" }),
|
|
245
|
+
scriptBinaryNames: Object.freeze(["mcode", "mcode-tools"]),
|
|
246
|
+
defaultScriptInstallDir: ".minimax-code/bin",
|
|
145
247
|
installMethods: Object.freeze([
|
|
146
|
-
packageManagerMethod("npm", "npm", "npm", "@minimax-ai/code@latest"
|
|
147
|
-
|
|
248
|
+
packageManagerMethod("npm", "npm", "npm", "@minimax-ai/code@latest", {
|
|
249
|
+
extraArgs: ["--ignore-scripts=false", "--include=optional", "--allow-scripts=@minimax-ai/code,better-sqlite3"]
|
|
250
|
+
}),
|
|
251
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@minimax-ai/code@latest", {
|
|
252
|
+
command: "add",
|
|
253
|
+
extraArgs: ["--ignore-scripts=false", "--allow-build=@minimax-ai/code", "--allow-build=better-sqlite3"]
|
|
254
|
+
}),
|
|
255
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
256
|
+
shell: "bash",
|
|
257
|
+
scriptUrl: "https://filecdn.minimax.chat/public/install.sh",
|
|
258
|
+
platforms: ["linux", "darwin"],
|
|
259
|
+
supportsInstallDir: true,
|
|
260
|
+
installDirEnv: "MCODE_INSTALL_DIR",
|
|
261
|
+
installDirSuffix: "bin",
|
|
262
|
+
registryEnv: "MCODE_NPM_REGISTRY",
|
|
263
|
+
env: ["MCODE_INSTALL_DIR", "MCODE_NPM_REGISTRY"],
|
|
264
|
+
verify: Object.freeze({ mustInclude: ["MiniMax Code CLI", "@minimax-ai/code"] })
|
|
265
|
+
}),
|
|
266
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
267
|
+
shell: "powershell",
|
|
268
|
+
scriptUrl: "https://filecdn.minimax.chat/public/install.ps1",
|
|
269
|
+
platforms: ["win32"],
|
|
270
|
+
supportsInstallDir: true,
|
|
271
|
+
installDirEnv: "MCODE_INSTALL_DIR",
|
|
272
|
+
registryEnv: "MCODE_NPM_REGISTRY",
|
|
273
|
+
env: ["MCODE_INSTALL_DIR", "MCODE_NPM_REGISTRY"],
|
|
274
|
+
defaultScriptInstallDir: ".minimax-code",
|
|
275
|
+
scriptBinaryNames: ["mcode.cmd", "mcode.ps1", "mcode-tools.cmd", "mcode-tools.ps1"],
|
|
276
|
+
verify: Object.freeze({ mustInclude: ["MiniMax Code CLI", "@minimax-ai/code"] })
|
|
277
|
+
})
|
|
148
278
|
])
|
|
149
279
|
}),
|
|
150
280
|
Object.freeze({
|
|
@@ -158,9 +288,28 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
158
288
|
uninstallArgs: ["uninstall", "-g", "@mimo-ai/cli"],
|
|
159
289
|
probeExecutables: ["mimo"],
|
|
160
290
|
providerHints: ["mimo", "xiaomi"],
|
|
291
|
+
scriptBinaryNames: Object.freeze(["mimo", "mimo.exe"]),
|
|
292
|
+
defaultScriptInstallDir: ".mimocode/bin",
|
|
161
293
|
installMethods: Object.freeze([
|
|
162
294
|
packageManagerMethod("npm", "npm", "npm", "@mimo-ai/cli@latest"),
|
|
163
|
-
packageManagerMethod("pnpm", "pnpm", "pnpm", "@mimo-ai/cli@latest")
|
|
295
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@mimo-ai/cli@latest"),
|
|
296
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
297
|
+
shell: "bash",
|
|
298
|
+
scriptUrl: "https://mimo.xiaomi.com/install",
|
|
299
|
+
platforms: ["linux", "darwin"],
|
|
300
|
+
scriptBinaryNames: ["mimo"],
|
|
301
|
+
verify: Object.freeze({ mustInclude: ["mimo.xiaomi.com", ".mimocode"] })
|
|
302
|
+
}),
|
|
303
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
304
|
+
shell: "powershell",
|
|
305
|
+
scriptUrl: "https://mimo.xiaomi.com/install.ps1",
|
|
306
|
+
platforms: ["win32"],
|
|
307
|
+
supportsInstallDir: true,
|
|
308
|
+
installDirEnv: "MIMOCODE_INSTALL_DIR",
|
|
309
|
+
env: ["MIMOCODE_INSTALL_DIR"],
|
|
310
|
+
scriptBinaryNames: ["mimo.exe"],
|
|
311
|
+
verify: Object.freeze({ mustInclude: ["mimo.xiaomi.com", ".mimocode"] })
|
|
312
|
+
})
|
|
164
313
|
])
|
|
165
314
|
}),
|
|
166
315
|
Object.freeze({
|
|
@@ -174,9 +323,32 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
174
323
|
uninstallArgs: ["uninstall", "-g", "@xai-official/grok"],
|
|
175
324
|
probeExecutables: ["grok"],
|
|
176
325
|
providerHints: ["xai", "grok"],
|
|
326
|
+
scriptBinaryNames: Object.freeze(["grok", "agent", "grok.exe", "agent.exe", "grove.exe", "grove-fsmonitor.exe", "grove-credential.exe"]),
|
|
327
|
+
defaultScriptInstallDir: ".grok/bin",
|
|
328
|
+
pathProfileMarkers: Object.freeze(["# >>> grok installer >>>", "# <<< grok installer <<<"]),
|
|
177
329
|
installMethods: Object.freeze([
|
|
178
330
|
packageManagerMethod("npm", "npm", "npm", "@xai-official/grok@latest"),
|
|
179
|
-
packageManagerMethod("pnpm", "pnpm", "pnpm", "@xai-official/grok@latest")
|
|
331
|
+
packageManagerMethod("pnpm", "pnpm", "pnpm", "@xai-official/grok@latest"),
|
|
332
|
+
scriptMethod("script-bash", "curl | bash", {
|
|
333
|
+
shell: "bash",
|
|
334
|
+
scriptUrl: "https://x.ai/cli/install.sh",
|
|
335
|
+
platforms: ["linux", "darwin"],
|
|
336
|
+
supportsInstallDir: true,
|
|
337
|
+
installDirEnv: "GROK_BIN_DIR",
|
|
338
|
+
env: ["GROK_BIN_DIR"],
|
|
339
|
+
scriptBinaryNames: ["grok", "agent"],
|
|
340
|
+
verify: Object.freeze({ mustInclude: ["Grok CLI installer", "x.ai/cli"] })
|
|
341
|
+
}),
|
|
342
|
+
scriptMethod("script-powershell", "irm | iex", {
|
|
343
|
+
shell: "powershell",
|
|
344
|
+
scriptUrl: "https://x.ai/cli/install.ps1",
|
|
345
|
+
platforms: ["win32"],
|
|
346
|
+
supportsInstallDir: true,
|
|
347
|
+
installDirEnv: "GROK_BIN_DIR",
|
|
348
|
+
env: ["GROK_BIN_DIR"],
|
|
349
|
+
scriptBinaryNames: ["grok.exe", "agent.exe", "grove.exe", "grove-fsmonitor.exe", "grove-credential.exe"],
|
|
350
|
+
verify: Object.freeze({ mustInclude: ["Grok CLI installer", "x.ai/cli"] })
|
|
351
|
+
})
|
|
180
352
|
])
|
|
181
353
|
}),
|
|
182
354
|
Object.freeze({
|
|
@@ -306,7 +478,8 @@ function installMethodsFor(tool) {
|
|
|
306
478
|
function installMethodFor(tool, methodId) {
|
|
307
479
|
const wanted = String(methodId ?? "").trim();
|
|
308
480
|
if (!wanted) return null;
|
|
309
|
-
|
|
481
|
+
const canonical = tool?.id === "codex" && wanted === "script-bash" ? "script-sh" : wanted;
|
|
482
|
+
return installMethodsFor(tool).find((method) => method.id === canonical) ?? null;
|
|
310
483
|
}
|
|
311
484
|
function defaultInstallMethod(tool) {
|
|
312
485
|
return installMethodsFor(tool)[0] ?? null;
|
|
@@ -320,8 +493,8 @@ function installCommandLineFor(tool, method) {
|
|
|
320
493
|
if (!tool || tool.unsupported) return null;
|
|
321
494
|
if (!method) return null;
|
|
322
495
|
if (method.kind === "script") {
|
|
323
|
-
const piped = method.shell === "powershell" ? `irm ${method.scriptUrl} | iex` : `curl -fsSL ${method.scriptUrl} |
|
|
324
|
-
return
|
|
496
|
+
const piped = method.shell === "powershell" ? `irm ${method.scriptUrl} | iex` : `curl -fsSL ${method.scriptUrl} | ${method.shell}`;
|
|
497
|
+
return piped;
|
|
325
498
|
}
|
|
326
499
|
return `${method.manager} ${method.installArgs.join(" ")}`;
|
|
327
500
|
}
|
|
@@ -651,9 +824,9 @@ function keepKnownToolIds(raw, known, subject) {
|
|
|
651
824
|
}
|
|
652
825
|
return raw;
|
|
653
826
|
}
|
|
654
|
-
function parseInstallPreferences(config = {}, { tools = [] } = {}) {
|
|
827
|
+
function parseInstallPreferences(config = {}, { tools = [], home = "", env = {} } = {}) {
|
|
655
828
|
const known = new Set(tools.map((tool) => tool.id));
|
|
656
|
-
const installDir = expandInstallDir(valueOf(config, "toolInstallDir", ""));
|
|
829
|
+
const installDir = expandInstallDir(valueOf(config, "toolInstallDir", ""), { home, env });
|
|
657
830
|
const registry = normalizeSourceUrl(valueOf(config, "toolNpmRegistry", DEFAULT_NPM_REGISTRY), "npm \u6E90") || DEFAULT_NPM_REGISTRY;
|
|
658
831
|
const methodRaw = keepKnownToolIds(
|
|
659
832
|
parseJsonObject(valueOf(config, "toolInstallMethodsJson", "{}"), "\u5B89\u88C5\u65B9\u5F0F\u8986\u76D6"),
|
|
@@ -670,9 +843,11 @@ function parseInstallPreferences(config = {}, { tools = [] } = {}) {
|
|
|
670
843
|
for (const [id2, methodId] of Object.entries(methodRaw)) methods[id2] = methodId.trim();
|
|
671
844
|
for (const [id2, url] of Object.entries(scriptRaw)) scriptUrls[id2] = normalizeSourceUrl(url, `${id2} \u5B89\u88C5\u811A\u672C\u6E90`);
|
|
672
845
|
for (const [id2, methodId] of Object.entries(methods)) {
|
|
673
|
-
|
|
846
|
+
const selected = installMethodFor({ id: id2, installMethods: tools.find((tool) => tool.id === id2)?.installMethods }, methodId);
|
|
847
|
+
if (!selected) {
|
|
674
848
|
throw new Error(`${id2} \u4E0D\u652F\u6301\u5B89\u88C5\u65B9\u5F0F ${methodId}\u3002`);
|
|
675
849
|
}
|
|
850
|
+
methods[id2] = selected.id;
|
|
676
851
|
}
|
|
677
852
|
return {
|
|
678
853
|
installDir,
|
|
@@ -2167,6 +2342,23 @@ function compareReleaseVersions(left, right) {
|
|
|
2167
2342
|
}
|
|
2168
2343
|
|
|
2169
2344
|
// .dsh-plugin/client/tool-install-state.mjs
|
|
2345
|
+
var INSTALL_DEFAULTS = Object.freeze({
|
|
2346
|
+
toolInstallDir: "",
|
|
2347
|
+
toolNpmRegistry: DEFAULT_NPM_REGISTRY,
|
|
2348
|
+
toolScriptUrlsJson: "{}",
|
|
2349
|
+
toolAllowScriptInstall: true
|
|
2350
|
+
});
|
|
2351
|
+
function validateToolInstallSetting(key, value) {
|
|
2352
|
+
try {
|
|
2353
|
+
parseInstallPreferences({ [key]: value }, { tools: OFFICIAL_TOOLS });
|
|
2354
|
+
return "";
|
|
2355
|
+
} catch (error) {
|
|
2356
|
+
return error?.message || "\u5B89\u88C5\u8BBE\u7F6E\u65E0\u6548\u3002";
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
function retainToolInstallDrafts(drafts, values = {}) {
|
|
2360
|
+
return Object.fromEntries(Object.entries(drafts).filter(([key, value]) => value !== (values[key] ?? INSTALL_DEFAULTS[key])));
|
|
2361
|
+
}
|
|
2170
2362
|
function toolInstallAction({ tool, probe, readiness, job, probeStatus, latestVersion = null }) {
|
|
2171
2363
|
const running = job?.status === "running";
|
|
2172
2364
|
const installed = probe?.installed === true;
|
|
@@ -2201,7 +2393,7 @@ function toolMaintenanceActions({ tool, probe, job, probeStatus, summary }) {
|
|
|
2201
2393
|
}
|
|
2202
2394
|
};
|
|
2203
2395
|
}
|
|
2204
|
-
function installClickRefusal({ tool, submitting = false, running = false, operation = "install" } = {}) {
|
|
2396
|
+
function installClickRefusal({ tool, submitting = false, running = false, operation = "install", pendingSettings = false, installError = "" } = {}) {
|
|
2205
2397
|
if (!tool) return "\u672A\u77E5\u5B98\u65B9\u5DE5\u5177\uFF0C\u65E0\u6CD5\u5F00\u59CB\u5B89\u88C5\u3002";
|
|
2206
2398
|
if (tool.unsupported) return String(tool.unsupportedReason ?? "").trim() || "\u6B64\u5DE5\u5177\u6682\u4E0D\u652F\u6301\u4E00\u952E\u5B89\u88C5\u3002";
|
|
2207
2399
|
if (tool.manager === "signed-windows-installer" && operation !== "install") {
|
|
@@ -2210,6 +2402,8 @@ function installClickRefusal({ tool, submitting = false, running = false, operat
|
|
|
2210
2402
|
if (submitting || running) {
|
|
2211
2403
|
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";
|
|
2212
2404
|
}
|
|
2405
|
+
if (pendingSettings) return "\u8BF7\u5148\u4FDD\u5B58\u6216\u653E\u5F03\u5B89\u88C5\u8BBE\u7F6E\u66F4\u6539\uFF0C\u5E76\u7B49\u5F85\u5B89\u88C5\u547D\u4EE4\u5237\u65B0\u3002";
|
|
2406
|
+
if (installError) return installError;
|
|
2213
2407
|
return "";
|
|
2214
2408
|
}
|
|
2215
2409
|
function payloadError(payload, fallback) {
|
|
@@ -12451,7 +12645,7 @@ var xterm_default = `/**
|
|
|
12451
12645
|
`;
|
|
12452
12646
|
|
|
12453
12647
|
// .dsh-plugin/client/host-version.mjs
|
|
12454
|
-
var ROUTER_CLIENT_VERSION = true ? "0.
|
|
12648
|
+
var ROUTER_CLIENT_VERSION = true ? "0.18.0" : "";
|
|
12455
12649
|
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";
|
|
12456
12650
|
function isMissingRemoteMethod(message) {
|
|
12457
12651
|
const value = String(message ?? "");
|
|
@@ -13043,14 +13237,15 @@ var router_main_default = `.mr-workspace {
|
|
|
13043
13237
|
.mr-tool-dot.running { background: #e9a640; }
|
|
13044
13238
|
.mr-tool-command { display: block; margin-top: 6px; padding: 4px 8px; font-size: 12px; background: var(--dsw-alias-markdown-code-block); border-radius: 6px; overflow-wrap: anywhere; }
|
|
13045
13239
|
.mr-tool-button { flex-shrink: 0; }
|
|
13046
|
-
.mr-tool-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
|
|
13240
|
+
.mr-tool-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; flex: 0 1 420px; }
|
|
13047
13241
|
.mr-tool-detail { margin: 7px 0 0; }
|
|
13048
13242
|
.mr-tool-error { margin: 8px 0 0; padding: 9px 11px; }
|
|
13049
13243
|
.mr-tool-log { margin-top: 7px; color: var(--mr-muted); font-size: 11px; }
|
|
13050
13244
|
.mr-tool-log summary { cursor: pointer; }
|
|
13051
13245
|
.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; }
|
|
13052
|
-
.mr-tool-methods { display: flex; align-items: center; gap: 6px;
|
|
13053
|
-
.mr-tool-methods label { display: flex; align-items: center; gap: 6px; color: var(--mr-muted); font-size: 11px; }
|
|
13246
|
+
.mr-tool-methods { display: flex; align-items: center; gap: 6px; width: 100%; }
|
|
13247
|
+
.mr-tool-methods label { display: flex; align-items: center; justify-content: flex-end; gap: 6px; width: 100%; color: var(--mr-muted); font-size: 11px; }
|
|
13248
|
+
.mr-tool-methods .mr-mini-select { min-width: 0; max-width: calc(100% - 54px); }
|
|
13054
13249
|
.mr-install-settings { margin-bottom: 14px; padding: 13px 14px; border: 1px solid var(--mr-line); border-radius: 11px; background: var(--mr-card); }
|
|
13055
13250
|
.mr-install-settings-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
|
|
13056
13251
|
.mr-install-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
|
|
@@ -13059,6 +13254,7 @@ var router_main_default = `.mr-workspace {
|
|
|
13059
13254
|
.mr-install-field small { font-size: 11px; line-height: 1.6; }
|
|
13060
13255
|
.mr-install-error { color: #d95360; }
|
|
13061
13256
|
.mr-install-toggle-row { display: flex; align-items: center; gap: 7px; }
|
|
13257
|
+
.mr-install-save-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
|
|
13062
13258
|
.mr-channel-line { display: flex; align-items: center; gap: 8px; margin: 8px 0; flex-wrap: wrap; }
|
|
13063
13259
|
.mr-pill-channel-ok { border-color: var(--dsw-alias-success, #2f9e63); color: var(--dsw-alias-success, #2f9e63); }
|
|
13064
13260
|
.mr-pill-warn { border-color: var(--dsw-alias-warning, #c27c0e); color: var(--dsw-alias-warning, #c27c0e); }
|
|
@@ -13071,7 +13267,7 @@ var router_main_default = `.mr-workspace {
|
|
|
13071
13267
|
.mr-profile-advanced summary { cursor: pointer; }
|
|
13072
13268
|
.mr-profile-success { padding: 10px 12px; border-radius: 10px; background: #e5f5eb; color: #175f3a; font-size: 12px; }
|
|
13073
13269
|
@media (prefers-color-scheme: dark) { .mr-profile-success { background: #193b2b; color: #b4f1cc; } }
|
|
13074
|
-
@media (max-width: 560px) { .mr-tool { align-items: stretch; flex-direction: column; gap: 10px; } .mr-tool-button { align-self: flex-start; } }
|
|
13270
|
+
@media (max-width: 560px) { .mr-tool { align-items: stretch; flex-direction: column; gap: 10px; } .mr-tool-actions { flex-basis: auto; justify-content: flex-start; } .mr-tool-methods label { justify-content: flex-start; } .mr-tool-button { align-self: flex-start; } }
|
|
13075
13271
|
|
|
13076
13272
|
/* \u5F00\u7BB1\u4F53\u68C0\u3001\u6210\u672C\u63A7\u5236\u3001\u6267\u884C\u8BB0\u5F55\u3001\u5B89\u5168\u8FB9\u754C */
|
|
13077
13273
|
.mr-onboarding, .mr-cost { margin-bottom: 18px; }
|
|
@@ -13285,41 +13481,24 @@ var INSTALL_SETTING_FIELDS = [
|
|
|
13285
13481
|
label: "\u7EDF\u4E00\u5B89\u88C5\u76EE\u5F55",
|
|
13286
13482
|
fallback: "",
|
|
13287
13483
|
placeholder: "\u7559\u7A7A = \u5404\u5382\u5546\u9ED8\u8BA4\u76EE\u5F55",
|
|
13288
|
-
hint: "
|
|
13289
|
-
validate: () => null
|
|
13484
|
+
hint: "\u586B\u5199\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 D:/AI/tools\u3002\u5404\u65B9\u5F0F\u7684\u5B9E\u9645\u76EE\u5F55\u4F1A\u663E\u793A\u5728\u5DE5\u5177\u547D\u4EE4\u65C1\uFF1B\u4E0D\u652F\u6301\u7EDF\u4E00\u76EE\u5F55\u7684\u65B9\u5F0F\u4F1A\u8BF4\u660E\u539F\u56E0\u3002"
|
|
13290
13485
|
},
|
|
13291
13486
|
{
|
|
13292
13487
|
key: "toolNpmRegistry",
|
|
13293
13488
|
label: "npm \u6E90\u5730\u5740",
|
|
13294
13489
|
fallback: "https://registry.npmjs.org/",
|
|
13295
13490
|
placeholder: "https://registry.npmjs.org/",
|
|
13296
|
-
hint: "\u5FC5\u987B\u4EE5 https:// \u5F00\u5934\u3002\
|
|
13297
|
-
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/"
|
|
13491
|
+
hint: "\u5FC5\u987B\u4EE5 https:// \u5F00\u5934\u3002\u6240\u6709 npm / pnpm \u65B9\u5F0F\u5171\u7528\u6B64\u4E0B\u8F7D\u6E90\uFF0C\u4F8B\u5982 https://registry.npmmirror.com/\u3002"
|
|
13298
13492
|
},
|
|
13299
13493
|
{
|
|
13300
13494
|
key: "toolScriptUrlsJson",
|
|
13301
13495
|
label: "\u5B89\u88C5\u811A\u672C\u6E90\u8986\u76D6\uFF08JSON\uFF0C\u53EF\u9009\uFF09",
|
|
13302
13496
|
fallback: "{}",
|
|
13303
13497
|
placeholder: '{ "stepcode": "https://mirror/stepcode/install.ps1" }',
|
|
13304
|
-
hint: "\u6309\u5DE5\u5177 ID \u6307\u5B9A\
|
|
13305
|
-
validate: (raw) => {
|
|
13306
|
-
if (!raw.trim()) return null;
|
|
13307
|
-
let parsed;
|
|
13308
|
-
try {
|
|
13309
|
-
parsed = JSON.parse(raw);
|
|
13310
|
-
} catch {
|
|
13311
|
-
return "JSON \u683C\u5F0F\u65E0\u6548\u3002";
|
|
13312
|
-
}
|
|
13313
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return "\u9700\u8981 JSON \u5BF9\u8C61\u3002";
|
|
13314
|
-
for (const [id2, url] of Object.entries(parsed)) {
|
|
13315
|
-
if (!OFFICIAL_TOOLS.some((tool) => tool.id === id2)) return `${id2} \u4E0D\u662F\u5B98\u65B9\u5DE5\u5177 ID\u3002`;
|
|
13316
|
-
if (typeof url !== "string" || !/^https:\/\/\S+$/i.test(url.trim())) return `${id2} \u7684\u5730\u5740\u5FC5\u987B\u662F https \u94FE\u63A5\u3002`;
|
|
13317
|
-
}
|
|
13318
|
-
return null;
|
|
13319
|
-
}
|
|
13498
|
+
hint: "\u6309\u5DE5\u5177 ID \u6307\u5B9A https \u955C\u50CF\u5730\u5740\u3002\u811A\u672C\u4E0B\u8F7D\u540E\u4ECD\u4F1A\u6838\u5BF9\u5382\u5546\u6807\u8BB0\uFF0C\u518D\u6267\u884C\u672C\u5730\u526F\u672C\u3002"
|
|
13320
13499
|
}
|
|
13321
13500
|
];
|
|
13322
|
-
function InstallSettings({ settingsScope, install }) {
|
|
13501
|
+
function InstallSettings({ settingsScope, install, onPendingChange }) {
|
|
13323
13502
|
const [snapshot, setSnapshot] = import_react5.default.useState(() => settingsScope?.getSnapshot?.() ?? { value: {}, writable: false });
|
|
13324
13503
|
const [drafts, setDrafts] = import_react5.default.useState({});
|
|
13325
13504
|
const [saving, setSaving] = import_react5.default.useState(false);
|
|
@@ -13327,36 +13506,48 @@ function InstallSettings({ settingsScope, install }) {
|
|
|
13327
13506
|
import_react5.default.useEffect(() => {
|
|
13328
13507
|
if (typeof settingsScope?.subscribe !== "function") return void 0;
|
|
13329
13508
|
const unsubscribe = settingsScope.subscribe(() => {
|
|
13330
|
-
|
|
13331
|
-
|
|
13509
|
+
const next = settingsScope.getSnapshot();
|
|
13510
|
+
setSnapshot(next);
|
|
13511
|
+
setDrafts((previous) => retainToolInstallDrafts(previous, next.value));
|
|
13332
13512
|
});
|
|
13333
13513
|
setSnapshot(settingsScope.getSnapshot());
|
|
13334
13514
|
return unsubscribe;
|
|
13335
13515
|
}, [settingsScope]);
|
|
13516
|
+
const dirty = Object.keys(drafts).length > 0;
|
|
13517
|
+
import_react5.default.useEffect(() => {
|
|
13518
|
+
onPendingChange?.(saving || dirty);
|
|
13519
|
+
}, [saving, dirty, onPendingChange]);
|
|
13336
13520
|
if (!settingsScope) return null;
|
|
13337
13521
|
const writable = snapshot.writable === true && !saving;
|
|
13338
13522
|
const shown = (field2) => drafts[field2.key] ?? String(snapshot.value?.[field2.key] ?? field2.fallback);
|
|
13339
|
-
const errors = Object.fromEntries(INSTALL_SETTING_FIELDS.map((field2) => [field2.key, field2.
|
|
13340
|
-
const
|
|
13523
|
+
const errors = Object.fromEntries(INSTALL_SETTING_FIELDS.map((field2) => [field2.key, validateToolInstallSetting(field2.key, shown(field2))]));
|
|
13524
|
+
const invalid = Object.values(errors).some(Boolean);
|
|
13525
|
+
const edit = (key, value) => {
|
|
13526
|
+
const next = retainToolInstallDrafts({ ...drafts, [key]: value }, snapshot.value);
|
|
13527
|
+
onPendingChange?.(saving || Object.keys(next).length > 0);
|
|
13528
|
+
setNotice("");
|
|
13529
|
+
setDrafts(next);
|
|
13530
|
+
};
|
|
13531
|
+
const apply2 = async () => {
|
|
13532
|
+
if (!writable || !dirty || invalid) return;
|
|
13341
13533
|
setSaving(true);
|
|
13534
|
+
onPendingChange?.(true);
|
|
13342
13535
|
setNotice("");
|
|
13343
13536
|
try {
|
|
13537
|
+
const entries = Object.entries(drafts).map(([key, value]) => ({ op: "set", path: [key], value }));
|
|
13344
13538
|
const accepted = await settingsScope.mutate(entries, snapshot.revision);
|
|
13345
13539
|
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");
|
|
13346
|
-
|
|
13540
|
+
const next = settingsScope.getSnapshot();
|
|
13541
|
+
setSnapshot(next);
|
|
13542
|
+
setDrafts((previous) => retainToolInstallDrafts(previous, next.value));
|
|
13543
|
+
setNotice("\u5B89\u88C5\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002");
|
|
13347
13544
|
} catch (error) {
|
|
13348
13545
|
setNotice(text5(error?.message) || "\u5B89\u88C5\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
|
|
13349
13546
|
} finally {
|
|
13350
13547
|
setSaving(false);
|
|
13351
13548
|
}
|
|
13352
13549
|
};
|
|
13353
|
-
|
|
13354
|
-
const saved = String(snapshot.value?.[field2.key] ?? field2.fallback);
|
|
13355
|
-
const raw = shown(field2);
|
|
13356
|
-
if (raw === saved || errors[field2.key]) return;
|
|
13357
|
-
return apply2([{ op: "set", path: [field2.key], value: raw }], `\u5DF2\u4FDD\u5B58${field2.label}\uFF0C\u4E0B\u4E00\u6B21\u5B89\u88C5\u8D77\u751F\u6548\u3002`);
|
|
13358
|
-
};
|
|
13359
|
-
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(
|
|
13550
|
+
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" }, "\u4FDD\u5B58\u540E\u7528\u4E8E\u540E\u7EED\u5B89\u88C5\u4E0E\u66F4\u65B0\u3002\u6BCF\u4E2A\u5DE5\u5177\u4E0B\u65B9\u663E\u793A\u5B9E\u9645\u65B9\u5F0F\u548C\u76EE\u5F55\uFF0C\u63D2\u4EF6\u8BBE\u7F6E\u9875\u91CC\u4E5F\u80FD\u4FEE\u6539\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(
|
|
13360
13551
|
"input",
|
|
13361
13552
|
{
|
|
13362
13553
|
className: "mr-input",
|
|
@@ -13364,37 +13555,47 @@ function InstallSettings({ settingsScope, install }) {
|
|
|
13364
13555
|
placeholder: field2.placeholder,
|
|
13365
13556
|
disabled: !writable,
|
|
13366
13557
|
"aria-invalid": Boolean(errors[field2.key]),
|
|
13367
|
-
onChange: (event) =>
|
|
13368
|
-
onBlur: () => {
|
|
13369
|
-
void commit(field2);
|
|
13370
|
-
}
|
|
13558
|
+
onChange: (event) => edit(field2.key, event.target.value)
|
|
13371
13559
|
}
|
|
13372
13560
|
), 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(
|
|
13373
13561
|
"input",
|
|
13374
13562
|
{
|
|
13375
13563
|
type: "checkbox",
|
|
13376
|
-
checked: snapshot.value?.toolAllowScriptInstall !== false,
|
|
13564
|
+
checked: (drafts.toolAllowScriptInstall ?? snapshot.value?.toolAllowScriptInstall) !== false,
|
|
13377
13565
|
disabled: !writable,
|
|
13378
13566
|
onChange: (event) => {
|
|
13379
|
-
|
|
13380
|
-
void apply2(
|
|
13381
|
-
[{ op: "set", path: ["toolAllowScriptInstall"], value: allowed }],
|
|
13382
|
-
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"
|
|
13383
|
-
);
|
|
13567
|
+
edit("toolAllowScriptInstall", event.target.checked);
|
|
13384
13568
|
}
|
|
13385
13569
|
}
|
|
13386
|
-
), /* @__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("
|
|
13570
|
+
), /* @__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("div", { className: "mr-install-save-row" }, /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: !writable || !dirty || invalid, onClick: () => {
|
|
13571
|
+
void apply2();
|
|
13572
|
+
} }, saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u5B89\u88C5\u8BBE\u7F6E"), dirty && /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: saving, onClick: () => {
|
|
13573
|
+
setDrafts({});
|
|
13574
|
+
setNotice("");
|
|
13575
|
+
onPendingChange?.(false);
|
|
13576
|
+
} }, "\u653E\u5F03\u66F4\u6539"), dirty && /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-caption" }, invalid ? "\u8BF7\u4FEE\u6B63\u8F93\u5165\u540E\u4FDD\u5B58\u3002" : "\u66F4\u6539\u5C1A\u672A\u4FDD\u5B58\uFF0C\u5B89\u88C5\u4E0E\u66F4\u65B0\u6682\u4E0D\u53EF\u7528\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}` : ""));
|
|
13387
13577
|
}
|
|
13388
13578
|
function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes, health, onRefreshHealth, settingsScope }) {
|
|
13389
13579
|
const healthById = Object.fromEntries((health?.tools ?? []).map((item) => [item.id, item]));
|
|
13390
13580
|
const [probeState, setProbeState] = import_react5.default.useState({ status: "loading", probes: [], capabilities: [], readiness: [], install: null, error: "" });
|
|
13391
13581
|
const [jobs, setJobs] = import_react5.default.useState({});
|
|
13392
13582
|
const [rowErrors, setRowErrors] = import_react5.default.useState({});
|
|
13583
|
+
const [settingsPending, setSettingsPending] = import_react5.default.useState(false);
|
|
13584
|
+
const [methodSaving, setMethodSaving] = import_react5.default.useState(null);
|
|
13585
|
+
const [previewPending, setPreviewPending] = import_react5.default.useState(false);
|
|
13586
|
+
const [settingsWritable, setSettingsWritable] = import_react5.default.useState(() => settingsScope?.getSnapshot?.()?.writable === true);
|
|
13587
|
+
const settingsPendingRef = import_react5.default.useRef(false);
|
|
13588
|
+
const methodSavingRef = import_react5.default.useRef(null);
|
|
13589
|
+
const previewPendingRef = import_react5.default.useRef(false);
|
|
13393
13590
|
const mounted = import_react5.default.useRef(false);
|
|
13394
13591
|
const request = import_react5.default.useRef(0);
|
|
13395
13592
|
const submitting = import_react5.default.useRef(/* @__PURE__ */ new Set());
|
|
13396
13593
|
const polling = import_react5.default.useRef(/* @__PURE__ */ new Set());
|
|
13397
13594
|
const jobsRef = import_react5.default.useRef({});
|
|
13595
|
+
const handleSettingsPending = import_react5.default.useCallback((value) => {
|
|
13596
|
+
settingsPendingRef.current = value;
|
|
13597
|
+
setSettingsPending(value);
|
|
13598
|
+
}, []);
|
|
13398
13599
|
const rememberJobs = (updater) => {
|
|
13399
13600
|
setJobs((previous) => {
|
|
13400
13601
|
const next = typeof updater === "function" ? updater(previous) : updater;
|
|
@@ -13419,6 +13620,8 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13419
13620
|
const capabilities = Array.isArray(response.value?.executionCapabilities) ? response.value.executionCapabilities : [];
|
|
13420
13621
|
const readiness = Array.isArray(response.value?.executionReadiness) ? response.value.executionReadiness : [];
|
|
13421
13622
|
setProbeState({ status: "ready", probes, capabilities, readiness, install: response.value?.install ?? null, error: "" });
|
|
13623
|
+
previewPendingRef.current = false;
|
|
13624
|
+
setPreviewPending(false);
|
|
13422
13625
|
onProbes({ probes, capabilities, readiness, hostVersion: typeof response.value?.hostVersion === "string" ? response.value.hostVersion : null });
|
|
13423
13626
|
} catch (error) {
|
|
13424
13627
|
if (!mounted.current || current !== request.current) return;
|
|
@@ -13463,6 +13666,29 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13463
13666
|
request.current += 1;
|
|
13464
13667
|
};
|
|
13465
13668
|
}, []);
|
|
13669
|
+
const refreshRef = import_react5.default.useRef(refresh);
|
|
13670
|
+
refreshRef.current = refresh;
|
|
13671
|
+
import_react5.default.useEffect(() => {
|
|
13672
|
+
if (typeof settingsScope?.subscribe !== "function") return void 0;
|
|
13673
|
+
const signature2 = (snapshot) => JSON.stringify([
|
|
13674
|
+
snapshot?.value?.toolInstallDir,
|
|
13675
|
+
snapshot?.value?.toolNpmRegistry,
|
|
13676
|
+
snapshot?.value?.toolInstallMethodsJson,
|
|
13677
|
+
snapshot?.value?.toolScriptUrlsJson,
|
|
13678
|
+
snapshot?.value?.toolAllowScriptInstall
|
|
13679
|
+
]);
|
|
13680
|
+
let previous = signature2(settingsScope.getSnapshot());
|
|
13681
|
+
return settingsScope.subscribe(() => {
|
|
13682
|
+
const snapshot = settingsScope.getSnapshot();
|
|
13683
|
+
setSettingsWritable(snapshot.writable === true);
|
|
13684
|
+
const next = signature2(snapshot);
|
|
13685
|
+
if (next === previous) return;
|
|
13686
|
+
previous = next;
|
|
13687
|
+
previewPendingRef.current = true;
|
|
13688
|
+
setPreviewPending(true);
|
|
13689
|
+
void refreshRef.current();
|
|
13690
|
+
});
|
|
13691
|
+
}, [settingsScope]);
|
|
13466
13692
|
import_react5.default.useEffect(() => {
|
|
13467
13693
|
const active = Object.values(jobs).filter((job) => job?.status === "running").map((job) => job.tool);
|
|
13468
13694
|
if (active.length === 0 || typeof officialToolInstallStatus !== "function") return void 0;
|
|
@@ -13503,18 +13729,24 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13503
13729
|
}, [jobs, officialToolInstallStatus]);
|
|
13504
13730
|
const run = async (id2, operation) => {
|
|
13505
13731
|
const tool = OFFICIAL_TOOLS.find((item) => item.id === id2);
|
|
13732
|
+
const summary = (probeState.install?.tools ?? []).find((item) => item.id === id2);
|
|
13506
13733
|
const bridge = { install: installOfficialTool, repair: repairOfficialTool, uninstall: uninstallOfficialTool }[operation];
|
|
13507
13734
|
const refusal = installClickRefusal({
|
|
13508
13735
|
tool,
|
|
13509
13736
|
submitting: submitting.current.has(id2),
|
|
13510
13737
|
running: jobsRef.current[id2]?.status === "running",
|
|
13511
|
-
operation
|
|
13738
|
+
operation,
|
|
13739
|
+
pendingSettings: settingsPendingRef.current || Boolean(methodSavingRef.current) || previewPendingRef.current,
|
|
13740
|
+
installError: operation === "uninstall" ? summary?.uninstallError ?? (summary?.uninstallCommand ? "" : summary?.error ?? "") : summary?.installError ?? summary?.error ?? ""
|
|
13512
13741
|
});
|
|
13513
13742
|
if (refusal) {
|
|
13514
13743
|
setRowErrors((previous) => ({ ...previous, [id2]: refusal }));
|
|
13515
13744
|
return;
|
|
13516
13745
|
}
|
|
13517
|
-
if (typeof bridge !== "function")
|
|
13746
|
+
if (typeof bridge !== "function") {
|
|
13747
|
+
setRowErrors((previous) => ({ ...previous, [id2]: "\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002" }));
|
|
13748
|
+
return;
|
|
13749
|
+
}
|
|
13518
13750
|
submitting.current.add(id2);
|
|
13519
13751
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13520
13752
|
setRowErrors((previous) => ({ ...previous, [id2]: "" }));
|
|
@@ -13551,7 +13783,10 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13551
13783
|
const uninstall = (id2) => run(id2, "uninstall");
|
|
13552
13784
|
const setInstallMethod = async (toolId, methodId) => {
|
|
13553
13785
|
const snapshot = settingsScope?.getSnapshot?.();
|
|
13554
|
-
if (!snapshot) return;
|
|
13786
|
+
if (!snapshot?.writable || methodSavingRef.current || settingsPendingRef.current) return;
|
|
13787
|
+
methodSavingRef.current = toolId;
|
|
13788
|
+
setMethodSaving(toolId);
|
|
13789
|
+
setRowErrors((previous) => ({ ...previous, [toolId]: "" }));
|
|
13555
13790
|
let map = {};
|
|
13556
13791
|
try {
|
|
13557
13792
|
map = JSON.parse(String(snapshot.value?.toolInstallMethodsJson ?? "{}")) || {};
|
|
@@ -13564,9 +13799,14 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13564
13799
|
try {
|
|
13565
13800
|
const accepted = await settingsScope.mutate([{ op: "set", path: ["toolInstallMethodsJson"], value: JSON.stringify(map) }], snapshot.revision);
|
|
13566
13801
|
if (!accepted) throw new Error("\u5B89\u88C5\u65B9\u5F0F\u672A\u88AB\u4FDD\u5B58\uFF0C\u53EF\u80FD\u88AB\u5176\u4ED6\u9875\u9762\u4FEE\u6539\u3002");
|
|
13567
|
-
|
|
13802
|
+
previewPendingRef.current = true;
|
|
13803
|
+
setPreviewPending(true);
|
|
13804
|
+
await refresh();
|
|
13568
13805
|
} catch (error) {
|
|
13569
13806
|
if (mounted.current) setRowErrors((previous) => ({ ...previous, [toolId]: text5(error?.message) || "\u5B89\u88C5\u65B9\u5F0F\u4FDD\u5B58\u5931\u8D25\u3002" }));
|
|
13807
|
+
} finally {
|
|
13808
|
+
methodSavingRef.current = null;
|
|
13809
|
+
if (mounted.current) setMethodSaving(null);
|
|
13570
13810
|
}
|
|
13571
13811
|
};
|
|
13572
13812
|
const cancel = async (id2) => {
|
|
@@ -13588,10 +13828,12 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13588
13828
|
const installById = Object.fromEntries((probeState.install?.tools ?? []).map((item) => [item.id, item]));
|
|
13589
13829
|
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: () => {
|
|
13590
13830
|
void refresh();
|
|
13591
|
-
} }, "\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) => {
|
|
13831
|
+
} }, "\u91CD\u65B0\u4F53\u68C0")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-card-body" }, /* @__PURE__ */ import_react5.default.createElement(InstallSettings, { settingsScope, install: probeState.install, onPendingChange: handleSettingsPending }), previewPending && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", role: "status" }, "\u5B89\u88C5\u8BBE\u7F6E\u5DF2\u53D8\u66F4\uFF0C\u6B63\u5728\u5237\u65B0\u5B9E\u9645\u5B89\u88C5\u547D\u4EE4\uFF1B\u5237\u65B0\u5B8C\u6210\u540E\u53EF\u7EE7\u7EED\u5B89\u88C5\u4E0E\u66F4\u65B0\u3002"), 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) => {
|
|
13592
13832
|
const summary = installById[tool.id];
|
|
13593
|
-
const command = summary
|
|
13833
|
+
const command = summary ? summary.command : installCommandLine(tool);
|
|
13834
|
+
const updateCommand = summary?.updateCommand ?? command;
|
|
13594
13835
|
const methods = summary?.methods ?? installMethodsFor(tool).map((method) => ({ id: method.id, label: method.label }));
|
|
13836
|
+
const settingsBusy = settingsPending || Boolean(methodSaving) || previewPending;
|
|
13595
13837
|
const probe = byId[tool.id];
|
|
13596
13838
|
const capability = capabilitiesById[tool.id];
|
|
13597
13839
|
const readiness = readinessById[tool.id];
|
|
@@ -13603,32 +13845,36 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13603
13845
|
probe,
|
|
13604
13846
|
job,
|
|
13605
13847
|
probeStatus: probeState.status,
|
|
13606
|
-
summary: {
|
|
13848
|
+
summary: {
|
|
13849
|
+
installable: !(summary?.installError ?? summary?.error),
|
|
13850
|
+
removable: !(summary?.uninstallError ?? (summary?.uninstallCommand ? "" : summary?.error))
|
|
13851
|
+
}
|
|
13607
13852
|
});
|
|
13608
13853
|
const verified = job?.status === "succeeded" && (job.operation === "uninstall" ? job.postInstallProbe?.installed === false : job.postInstallProbe?.installed === true);
|
|
13609
13854
|
const operation = job?.operation === "uninstall" ? "\u5378\u8F7D" : job?.operation === "repair" ? "\u4FEE\u590D" : "\u5B89\u88C5";
|
|
13610
13855
|
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);
|
|
13611
|
-
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(
|
|
13856
|
+
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(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, "\u5B89\u88C5\u65B9\u5F0F\uFF1A", methods.find((method) => method.id === summary?.methodId)?.label ?? tool.manager, " \xB7 \u5B9E\u9645\u5B89\u88C5\u76EE\u5F55\uFF1A", summary?.installDir || "\u5404\u5382\u5546\u9ED8\u8BA4\u76EE\u5F55"), /* @__PURE__ */ import_react5.default.createElement("code", { className: "mr-tool-command", "aria-label": `${tool.label} \u5B89\u88C5\u547D\u4EE4` }, command), updateCommand !== command && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, "\u66F4\u65B0\u6CBF\u7528\u539F\u5B89\u88C5\u4F4D\u7F6E\uFF1A", summary?.updateInstallDir || "\u5404\u5382\u5546\u9ED8\u8BA4\u76EE\u5F55"), /* @__PURE__ */ import_react5.default.createElement("code", { className: "mr-tool-command", "aria-label": `${tool.label} \u66F4\u65B0\u547D\u4EE4` }, updateCommand))) : /* @__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 || methods.length > 0) && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-actions" }, methods.length > 0 && /* @__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(
|
|
13612
13857
|
"select",
|
|
13613
13858
|
{
|
|
13614
13859
|
className: "mr-mini-select",
|
|
13615
|
-
value: summary?.savedMethodId ??
|
|
13616
|
-
disabled: running ||
|
|
13860
|
+
value: summary?.savedMethodId ?? "",
|
|
13861
|
+
disabled: running || settingsBusy || !settingsWritable,
|
|
13617
13862
|
onChange: (event) => {
|
|
13618
13863
|
void setInstallMethod(tool.id, event.target.value);
|
|
13619
13864
|
}
|
|
13620
13865
|
},
|
|
13866
|
+
/* @__PURE__ */ import_react5.default.createElement("option", { value: "" }, "\u81EA\u52A8\u9009\u62E9"),
|
|
13621
13867
|
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` : ""))
|
|
13622
|
-
))), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-tool-button", type: "button", disabled: action.disabled, onClick: () => {
|
|
13868
|
+
))), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-tool-button", type: "button", disabled: action.disabled || settingsBusy || !command || Boolean(summary?.error), title: summary?.error || (settingsBusy ? "\u8BF7\u5148\u4FDD\u5B58\u6216\u653E\u5F03\u5B89\u88C5\u8BBE\u7F6E\u66F4\u6539\uFF0C\u5E76\u7B49\u5F85\u547D\u4EE4\u5237\u65B0\u3002" : void 0), onClick: () => {
|
|
13623
13869
|
void install(tool.id);
|
|
13624
|
-
} }, 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: () => {
|
|
13870
|
+
} }, methodSaving === tool.id ? "\u4FDD\u5B58\u65B9\u5F0F\u4E2D\u2026" : action.label), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary mr-tool-button", type: "button", disabled: maintenance.repair.disabled || settingsBusy, title: maintenance.repair.title, onClick: () => {
|
|
13625
13871
|
void repair(tool.id);
|
|
13626
|
-
} }, 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: () => {
|
|
13872
|
+
} }, maintenance.repair.label), /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary mr-tool-button", type: "button", disabled: maintenance.uninstall.disabled || settingsBusy, title: maintenance.uninstall.title, onClick: () => {
|
|
13627
13873
|
void uninstall(tool.id);
|
|
13628
13874
|
} }, 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: () => {
|
|
13629
13875
|
void cancel(tool.id);
|
|
13630
13876
|
} }, job.cancelRequested ? "\u6B63\u5728\u53D6\u6D88\u2026" : `\u53D6\u6D88${operation}`)));
|
|
13631
|
-
})), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { marginTop: 12 } }, "\u5B89\u88C5\
|
|
13877
|
+
})), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { marginTop: 12 } }, "\u5B89\u88C5\u76EE\u5F55\u4E0E\u4E0B\u8F7D\u6E90\u4F7F\u7528\u5DF2\u4FDD\u5B58\u8BBE\u7F6E\uFF0C\u547D\u4EE4\u4E0A\u65B9\u663E\u793A\u5B9E\u9645\u6267\u884C\u65B9\u5F0F\u3002\u53EF\u70B9\u201C\u53D6\u6D88\u201D\u7EC8\u6B62\u4E0B\u8F7D\u4EFB\u52A1\uFF0C\u968F\u540E\u91CD\u65B0\u68C0\u6D4B\u7248\u672C\u3002\u5378\u8F7D\u4FDD\u7559\u914D\u7F6E\u3001\u767B\u5F55\u4FE1\u606F\u548C\u5386\u53F2\u8BB0\u5F55\uFF1B\u811A\u672C\u65B9\u5F0F\u53EA\u79FB\u9664\u767B\u8BB0\u7684\u547D\u4EE4\u5165\u53E3\uFF0C\u53EF\u80FD\u4FDD\u7559\u5382\u5546\u7248\u672C\u76EE\u5F55\u3002\u4E0D\u652F\u6301\u5B89\u5168\u5378\u8F7D\u7684\u65B9\u5F0F\u4F1A\u8BF4\u660E\u539F\u56E0\u3002ZCode \u9700\u5728\u5B98\u65B9\u5B89\u88C5\u7A97\u53E3\u5B8C\u6210\u5B89\u88C5\u3002\u4F1A\u8BDD\u4E0E Agent \u4E5F\u53EF\u4F7F\u7528 ", /* @__PURE__ */ import_react5.default.createElement("code", null, "/tools"), "\u3001", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_tool_install"), "\u3001", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_tool_repair"), " \u548C ", /* @__PURE__ */ import_react5.default.createElement("code", null, "model_router_tool_uninstall"), "\u3002")));
|
|
13632
13878
|
}
|
|
13633
13879
|
var HEADLESS_TOOLS = /* @__PURE__ */ new Set(["claude-code", "codex", "gemini"]);
|
|
13634
13880
|
var WORKSPACE_VIEWS = [
|
|
@@ -14490,12 +14736,12 @@ function RouterSettingsCard(props) {
|
|
|
14490
14736
|
), 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, `{
|
|
14491
14737
|
"kimi-code": { "quota": ["\u989D\u5EA6\u5DF2\u7528\u5B8C"], "rateLimit": ["\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41"] },
|
|
14492
14738
|
"my-glm-plan": { "quota": ["Usage limit reached for", "1308"] }
|
|
14493
|
-
}`)), /* @__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 }, "\
|
|
14739
|
+
}`)), /* @__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 }, "\u7528\u4E8E\u5B98\u65B9\u5DE5\u5177\u7684\u5B89\u88C5\u4E0E\u66F4\u65B0\u3002\u5DE5\u4F5C\u53F0\u7684\u201C\u5B98\u65B9\u5DE5\u5177\u201D\u9875\u4E5F\u80FD\u4FDD\u5B58\u540C\u6837\u7684\u5B57\u6BB5\uFF0C\u5E76\u4F1A\u663E\u793A\u6BCF\u4E2A\u5DE5\u5177\u7684\u5B9E\u9645\u5B89\u88C5\u65B9\u5F0F\u3001\u76EE\u5F55\u4E0E\u6267\u884C\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(
|
|
14494
14740
|
import_dsh_client_ui_primitives.SettingsValueField,
|
|
14495
14741
|
{
|
|
14496
14742
|
id: "model-router-tool-install-dir",
|
|
14497
14743
|
label: "\u7EDF\u4E00\u5B89\u88C5\u76EE\u5F55",
|
|
14498
|
-
hint: "\u7559\u7A7A\
|
|
14744
|
+
hint: "\u586B\u5199\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u7559\u7A7A\u4F7F\u7528\u5382\u5546\u9ED8\u8BA4\u4F4D\u7F6E\u3002npm / pnpm \u4F7F\u7528\u8BE5\u76EE\u5F55\u5B89\u88C5\uFF1B\u5382\u5546\u811A\u672C\u4E0D\u652F\u6301\u81EA\u5B9A\u4E49\u76EE\u5F55\u65F6\uFF0C\u5B98\u65B9\u5DE5\u5177\u9875\u4F1A\u663E\u793A\u5B9E\u9645\u76EE\u5F55\u4E0E\u539F\u56E0\u3002\u66F4\u65B0\u4F7F\u7528\u540C\u4E00\u5B89\u88C5\u65B9\u5F0F\u3001\u76EE\u5F55\u4E0E\u4E0B\u8F7D\u6E90\u3002",
|
|
14499
14745
|
disabled,
|
|
14500
14746
|
...state.toolInstallDir,
|
|
14501
14747
|
overriddenLabel: FIELD_COPY.overridden,
|
|
@@ -14531,7 +14777,7 @@ function RouterSettingsCard(props) {
|
|
|
14531
14777
|
{
|
|
14532
14778
|
id: "model-router-tool-install-methods",
|
|
14533
14779
|
label: "\u9ED8\u8BA4\u5B89\u88C5\u65B9\u5F0F\uFF08JSON\uFF0C\u53EF\u9009\uFF09",
|
|
14534
|
-
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\
|
|
14780
|
+
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\u81EA\u52A8\u9009\u62E9\u9002\u5408\u672C\u673A\u7684\u65B9\u5F0F\u3002\u53EF\u9009\u503C\u4EE5\u5DE5\u5177\u4E0B\u62C9\u6846\u4E3A\u51C6\uFF1Anpm\u3001pnpm\u3001script-bash\uFF08curl | bash\uFF09\u3001script-sh\uFF08curl | sh\uFF09\u3001script-powershell\uFF08irm | iex\uFF09\u3002",
|
|
14535
14781
|
disabled,
|
|
14536
14782
|
...state.toolInstallMethodsJson,
|
|
14537
14783
|
overriddenLabel: FIELD_COPY.overridden,
|