@ljwei-stak/dsh-model-router 0.17.1 → 0.18.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 +390 -187
- package/.dsh-plugin/index.mjs +29 -7
- package/.dsh-plugin/official-tools-remote-service.mjs +61 -11
- package/.dsh-plugin/shared/official-tool-executor.mjs +135 -47
- package/.dsh-plugin/shared/official-tool-registry.mjs +113 -150
- package/.dsh-plugin/shared/official-tools-remote.mjs +1 -0
- package/.dsh-plugin/shared/official-tools-runtime.mjs +420 -223
- package/.dsh-plugin/shared/tool-install-preferences.mjs +77 -73
- package/.dsh-plugin/shared/vendor-mimo-grok-adapter.mjs +41 -16
- package/CHANGELOG.md +20 -1
- package/README.md +19 -8
- package/README.zh.md +19 -8
- package/docs/INSTALLATION_GUIDE.zh.md +14 -14
- package/docs/WORKBENCH_USER_GUIDE.zh.md +27 -5
- package/package.json +2 -2
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,9 +55,9 @@ 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
|
});
|
|
@@ -69,8 +69,16 @@ function scriptMethod(id2, label, {
|
|
|
69
69
|
installArg = [],
|
|
70
70
|
env = [],
|
|
71
71
|
platforms,
|
|
72
|
+
supportsInstallDir = false,
|
|
72
73
|
installDirEnv = "",
|
|
73
|
-
|
|
74
|
+
installDirSuffix = "",
|
|
75
|
+
defaultScriptInstallDir,
|
|
76
|
+
defaultScriptInstallDirEnv,
|
|
77
|
+
scriptBinaryNames,
|
|
78
|
+
registryEnv,
|
|
79
|
+
installDirSubdir,
|
|
80
|
+
uninstallUnsupportedReason,
|
|
81
|
+
scriptFallbackUrls
|
|
74
82
|
}) {
|
|
75
83
|
return Object.freeze({
|
|
76
84
|
id: id2,
|
|
@@ -83,14 +91,19 @@ function scriptMethod(id2, label, {
|
|
|
83
91
|
installArgs: Object.freeze(installArg),
|
|
84
92
|
/** Environment the vendor script itself documents for this install. */
|
|
85
93
|
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
94
|
platforms: Object.freeze(platforms),
|
|
91
95
|
/** Whether the vendor script honours a caller-chosen directory at all. */
|
|
92
|
-
supportsInstallDir
|
|
93
|
-
|
|
96
|
+
supportsInstallDir,
|
|
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)
|
|
94
107
|
});
|
|
95
108
|
}
|
|
96
109
|
var OFFICIAL_TOOLS = Object.freeze([
|
|
@@ -107,8 +120,7 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
107
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",
|
|
108
121
|
providerHints: ["moonshot", "kimi"],
|
|
109
122
|
scriptBinaryNames: Object.freeze(["kimi", "kimi.exe"]),
|
|
110
|
-
|
|
111
|
-
defaultScriptInstallDir: ".kimi-code",
|
|
123
|
+
defaultScriptInstallDir: ".kimi-code/bin",
|
|
112
124
|
installMethods: Object.freeze([
|
|
113
125
|
packageManagerMethod("npm", "npm", "npm", "@moonshot-ai/kimi-code@latest"),
|
|
114
126
|
packageManagerMethod("pnpm", "pnpm", "pnpm", "@moonshot-ai/kimi-code@latest"),
|
|
@@ -116,25 +128,23 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
116
128
|
shell: "bash",
|
|
117
129
|
scriptUrl: "https://code.kimi.com/kimi-code/install.sh",
|
|
118
130
|
platforms: ["linux", "darwin"],
|
|
131
|
+
supportsInstallDir: true,
|
|
119
132
|
installDirEnv: "KIMI_INSTALL_DIR",
|
|
120
|
-
|
|
133
|
+
installDirSuffix: "bin",
|
|
121
134
|
env: ["KIMI_INSTALL_DIR"],
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
mustNotInclude: ["downloads.claude.ai/claude-code-releases", "@minimax-ai/code"]
|
|
125
|
-
})
|
|
135
|
+
scriptBinaryNames: ["kimi"],
|
|
136
|
+
verify: Object.freeze({ mustInclude: ["kimi-code", "code.kimi.com/kimi-code"] })
|
|
126
137
|
}),
|
|
127
138
|
scriptMethod("script-powershell", "irm | iex", {
|
|
128
139
|
shell: "powershell",
|
|
129
140
|
scriptUrl: "https://code.kimi.com/kimi-code/install.ps1",
|
|
130
141
|
platforms: ["win32"],
|
|
142
|
+
supportsInstallDir: true,
|
|
131
143
|
installDirEnv: "KIMI_INSTALL_DIR",
|
|
132
|
-
|
|
144
|
+
installDirSuffix: "bin",
|
|
133
145
|
env: ["KIMI_INSTALL_DIR"],
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
mustNotInclude: ["downloads.claude.ai/claude-code-releases", "@minimax-ai/code"]
|
|
137
|
-
})
|
|
146
|
+
scriptBinaryNames: ["kimi.exe"],
|
|
147
|
+
verify: Object.freeze({ mustInclude: ["kimi-code", "code.kimi.com/kimi-code"] })
|
|
138
148
|
})
|
|
139
149
|
])
|
|
140
150
|
}),
|
|
@@ -149,31 +159,30 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
149
159
|
uninstallArgs: ["uninstall", "-g", "@anthropic-ai/claude-code"],
|
|
150
160
|
probeExecutables: ["claude"],
|
|
151
161
|
providerHints: ["anthropic", "claude"],
|
|
152
|
-
// The native installer always lands in ~/.local/bin; it has no directory flag.
|
|
153
162
|
scriptBinaryNames: Object.freeze(["claude", "claude.exe"]),
|
|
154
163
|
defaultScriptInstallDir: ".local/bin",
|
|
155
164
|
installMethods: Object.freeze([
|
|
156
165
|
packageManagerMethod("npm", "npm", "npm", "@anthropic-ai/claude-code@latest"),
|
|
157
|
-
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.
|
|
158
171
|
scriptMethod("script-bash", "curl | bash", {
|
|
159
172
|
shell: "bash",
|
|
160
173
|
scriptUrl: "https://claude.ai/install.sh",
|
|
174
|
+
scriptFallbackUrls: ["https://downloads.claude.ai/claude-code-releases/bootstrap.sh"],
|
|
161
175
|
platforms: ["linux", "darwin"],
|
|
162
|
-
|
|
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
|
-
})
|
|
176
|
+
scriptBinaryNames: ["claude"],
|
|
177
|
+
verify: Object.freeze({ mustInclude: ["downloads.claude.ai/claude-code-releases", "manifest.json"] })
|
|
167
178
|
}),
|
|
168
179
|
scriptMethod("script-powershell", "irm | iex", {
|
|
169
180
|
shell: "powershell",
|
|
170
181
|
scriptUrl: "https://claude.ai/install.ps1",
|
|
182
|
+
scriptFallbackUrls: ["https://downloads.claude.ai/claude-code-releases/bootstrap.ps1"],
|
|
171
183
|
platforms: ["win32"],
|
|
172
|
-
|
|
173
|
-
verify: Object.freeze({
|
|
174
|
-
mustInclude: ["downloads.claude.ai/claude-code-releases"],
|
|
175
|
-
mustNotInclude: ["@minimax-ai/code", "releases.openai.com/codex"]
|
|
176
|
-
})
|
|
184
|
+
scriptBinaryNames: ["claude.exe"],
|
|
185
|
+
verify: Object.freeze({ mustInclude: ["downloads.claude.ai/claude-code-releases", "manifest.json"] })
|
|
177
186
|
})
|
|
178
187
|
])
|
|
179
188
|
}),
|
|
@@ -190,33 +199,34 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
190
199
|
probeNote: "Codex \u7248\u672C\u6A2A\u5E45\u7531\u9002\u914D\u5C42\u5BBD\u5339\u914D\uFF1B\u5B89\u88C5\u65F6\u53D6 npm \u6700\u65B0\u7248\u3002",
|
|
191
200
|
providerHints: ["openai", "gpt", "codex"],
|
|
192
201
|
scriptBinaryNames: Object.freeze(["codex", "codex.exe"]),
|
|
202
|
+
defaultScriptInstallDir: ".local/bin",
|
|
193
203
|
installMethods: Object.freeze([
|
|
194
204
|
packageManagerMethod("npm", "npm", "npm", "@openai/codex@latest"),
|
|
195
205
|
packageManagerMethod("pnpm", "pnpm", "pnpm", "@openai/codex@latest"),
|
|
196
|
-
scriptMethod("script-
|
|
197
|
-
shell: "
|
|
206
|
+
scriptMethod("script-sh", "curl | sh", {
|
|
207
|
+
shell: "sh",
|
|
198
208
|
scriptUrl: "https://chatgpt.com/codex/install.sh",
|
|
199
209
|
platforms: ["linux", "darwin"],
|
|
210
|
+
supportsInstallDir: true,
|
|
200
211
|
installDirEnv: "CODEX_INSTALL_DIR",
|
|
201
|
-
defaultInstallDir: ".local/bin",
|
|
202
212
|
env: ["CODEX_INSTALL_DIR"],
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
mustNotInclude: ["downloads.claude.ai/claude-code-releases", "@minimax-ai/code"]
|
|
206
|
-
})
|
|
213
|
+
scriptBinaryNames: ["codex"],
|
|
214
|
+
verify: Object.freeze({ mustInclude: ["releases.openai.com/codex", "CODEX_INSTALL_DIR"] })
|
|
207
215
|
}),
|
|
208
216
|
scriptMethod("script-powershell", "irm | iex", {
|
|
209
217
|
shell: "powershell",
|
|
210
218
|
scriptUrl: "https://chatgpt.com/codex/install.ps1",
|
|
211
219
|
platforms: ["win32"],
|
|
220
|
+
supportsInstallDir: true,
|
|
212
221
|
installDirEnv: "CODEX_INSTALL_DIR",
|
|
213
|
-
// %LOCALAPPDATA%\Programs\OpenAI\Codex\bin under a normal user profile.
|
|
214
|
-
defaultInstallDir: "AppData/Local/Programs/OpenAI/Codex/bin",
|
|
215
222
|
env: ["CODEX_INSTALL_DIR"],
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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"] })
|
|
220
230
|
})
|
|
221
231
|
])
|
|
222
232
|
}),
|
|
@@ -231,50 +241,39 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
231
241
|
uninstallArgs: ["uninstall", "-g", "@minimax-ai/code"],
|
|
232
242
|
probeExecutables: ["mcode"],
|
|
233
243
|
providerHints: ["minimax"],
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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",
|
|
244
|
+
defaultMethodsByPlatform: Object.freeze({ win32: "script-powershell" }),
|
|
245
|
+
scriptBinaryNames: Object.freeze(["mcode", "mcode-tools"]),
|
|
246
|
+
defaultScriptInstallDir: ".minimax-code/bin",
|
|
252
247
|
installMethods: Object.freeze([
|
|
253
|
-
packageManagerMethod("npm", "npm", "npm", "@minimax-ai/code@latest"
|
|
254
|
-
|
|
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
255
|
scriptMethod("script-bash", "curl | bash", {
|
|
256
256
|
shell: "bash",
|
|
257
257
|
scriptUrl: "https://filecdn.minimax.chat/public/install.sh",
|
|
258
258
|
platforms: ["linux", "darwin"],
|
|
259
|
+
supportsInstallDir: true,
|
|
259
260
|
installDirEnv: "MCODE_INSTALL_DIR",
|
|
260
|
-
|
|
261
|
+
installDirSuffix: "bin",
|
|
262
|
+
registryEnv: "MCODE_NPM_REGISTRY",
|
|
261
263
|
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
|
-
})
|
|
264
|
+
verify: Object.freeze({ mustInclude: ["MiniMax Code CLI", "@minimax-ai/code"] })
|
|
266
265
|
}),
|
|
267
266
|
scriptMethod("script-powershell", "irm | iex", {
|
|
268
267
|
shell: "powershell",
|
|
269
268
|
scriptUrl: "https://filecdn.minimax.chat/public/install.ps1",
|
|
270
269
|
platforms: ["win32"],
|
|
270
|
+
supportsInstallDir: true,
|
|
271
271
|
installDirEnv: "MCODE_INSTALL_DIR",
|
|
272
|
-
|
|
272
|
+
registryEnv: "MCODE_NPM_REGISTRY",
|
|
273
273
|
env: ["MCODE_INSTALL_DIR", "MCODE_NPM_REGISTRY"],
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
})
|
|
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"] })
|
|
278
277
|
})
|
|
279
278
|
])
|
|
280
279
|
}),
|
|
@@ -294,28 +293,22 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
294
293
|
installMethods: Object.freeze([
|
|
295
294
|
packageManagerMethod("npm", "npm", "npm", "@mimo-ai/cli@latest"),
|
|
296
295
|
packageManagerMethod("pnpm", "pnpm", "pnpm", "@mimo-ai/cli@latest"),
|
|
297
|
-
// The Unix script hardcodes ~/.mimocode/bin and ignores MIMOCODE_INSTALL_DIR.
|
|
298
296
|
scriptMethod("script-bash", "curl | bash", {
|
|
299
297
|
shell: "bash",
|
|
300
298
|
scriptUrl: "https://mimo.xiaomi.com/install",
|
|
301
299
|
platforms: ["linux", "darwin"],
|
|
302
|
-
|
|
303
|
-
verify: Object.freeze({
|
|
304
|
-
mustInclude: ["MiMoCode", "mimo.xiaomi.com"],
|
|
305
|
-
mustNotInclude: ["@minimax-ai/code", "downloads.claude.ai/claude-code-releases"]
|
|
306
|
-
})
|
|
300
|
+
scriptBinaryNames: ["mimo"],
|
|
301
|
+
verify: Object.freeze({ mustInclude: ["mimo.xiaomi.com", ".mimocode"] })
|
|
307
302
|
}),
|
|
308
303
|
scriptMethod("script-powershell", "irm | iex", {
|
|
309
304
|
shell: "powershell",
|
|
310
305
|
scriptUrl: "https://mimo.xiaomi.com/install.ps1",
|
|
311
306
|
platforms: ["win32"],
|
|
307
|
+
supportsInstallDir: true,
|
|
312
308
|
installDirEnv: "MIMOCODE_INSTALL_DIR",
|
|
313
|
-
defaultInstallDir: ".mimocode/bin",
|
|
314
309
|
env: ["MIMOCODE_INSTALL_DIR"],
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
mustNotInclude: ["@minimax-ai/code", "downloads.claude.ai/claude-code-releases"]
|
|
318
|
-
})
|
|
310
|
+
scriptBinaryNames: ["mimo.exe"],
|
|
311
|
+
verify: Object.freeze({ mustInclude: ["mimo.xiaomi.com", ".mimocode"] })
|
|
319
312
|
})
|
|
320
313
|
])
|
|
321
314
|
}),
|
|
@@ -330,8 +323,9 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
330
323
|
uninstallArgs: ["uninstall", "-g", "@xai-official/grok"],
|
|
331
324
|
probeExecutables: ["grok"],
|
|
332
325
|
providerHints: ["xai", "grok"],
|
|
333
|
-
scriptBinaryNames: Object.freeze(["grok", "grok.exe", "agent", "
|
|
326
|
+
scriptBinaryNames: Object.freeze(["grok", "agent", "grok.exe", "agent.exe", "grove.exe", "grove-fsmonitor.exe", "grove-credential.exe"]),
|
|
334
327
|
defaultScriptInstallDir: ".grok/bin",
|
|
328
|
+
pathProfileMarkers: Object.freeze(["# >>> grok installer >>>", "# <<< grok installer <<<"]),
|
|
335
329
|
installMethods: Object.freeze([
|
|
336
330
|
packageManagerMethod("npm", "npm", "npm", "@xai-official/grok@latest"),
|
|
337
331
|
packageManagerMethod("pnpm", "pnpm", "pnpm", "@xai-official/grok@latest"),
|
|
@@ -339,25 +333,21 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
339
333
|
shell: "bash",
|
|
340
334
|
scriptUrl: "https://x.ai/cli/install.sh",
|
|
341
335
|
platforms: ["linux", "darwin"],
|
|
336
|
+
supportsInstallDir: true,
|
|
342
337
|
installDirEnv: "GROK_BIN_DIR",
|
|
343
|
-
defaultInstallDir: ".grok/bin",
|
|
344
338
|
env: ["GROK_BIN_DIR"],
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
mustNotInclude: ["@minimax-ai/code", "downloads.claude.ai/claude-code-releases"]
|
|
348
|
-
})
|
|
339
|
+
scriptBinaryNames: ["grok", "agent"],
|
|
340
|
+
verify: Object.freeze({ mustInclude: ["Grok CLI installer", "x.ai/cli"] })
|
|
349
341
|
}),
|
|
350
342
|
scriptMethod("script-powershell", "irm | iex", {
|
|
351
343
|
shell: "powershell",
|
|
352
344
|
scriptUrl: "https://x.ai/cli/install.ps1",
|
|
353
345
|
platforms: ["win32"],
|
|
346
|
+
supportsInstallDir: true,
|
|
354
347
|
installDirEnv: "GROK_BIN_DIR",
|
|
355
|
-
defaultInstallDir: ".grok/bin",
|
|
356
348
|
env: ["GROK_BIN_DIR"],
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
mustNotInclude: ["@minimax-ai/code", "downloads.claude.ai/claude-code-releases"]
|
|
360
|
-
})
|
|
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"] })
|
|
361
351
|
})
|
|
362
352
|
])
|
|
363
353
|
}),
|
|
@@ -405,7 +395,9 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
405
395
|
shell: "bash",
|
|
406
396
|
scriptUrl: "https://opencode.ai/install",
|
|
407
397
|
platforms: ["linux", "darwin"],
|
|
408
|
-
|
|
398
|
+
// The published script hardcodes $HOME/.opencode/bin, so it cannot honour
|
|
399
|
+
// a custom install directory; the npm/pnpm methods above can.
|
|
400
|
+
supportsInstallDir: false,
|
|
409
401
|
verify: Object.freeze({
|
|
410
402
|
mustInclude: ["anomalyco/opencode", "opencode.ai"],
|
|
411
403
|
mustNotInclude: ["static-openapi.stepfun.com"]
|
|
@@ -435,7 +427,7 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
435
427
|
platforms: ["linux", "darwin"],
|
|
436
428
|
installArg: ["--install-dir"],
|
|
437
429
|
env: ["STEP_INSTALL_DIR", "STEP_RELEASE_BASE_URL"],
|
|
438
|
-
|
|
430
|
+
supportsInstallDir: true,
|
|
439
431
|
verify: Object.freeze({
|
|
440
432
|
mustInclude: ["static-openapi.stepfun.com", "stepcode installer"],
|
|
441
433
|
mustNotInclude: ["anomalyco/opencode"]
|
|
@@ -447,7 +439,7 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
447
439
|
platforms: ["win32"],
|
|
448
440
|
installArg: ["-InstallDir"],
|
|
449
441
|
env: ["STEP_INSTALL_DIR", "STEP_RELEASE_BASE_URL"],
|
|
450
|
-
|
|
442
|
+
supportsInstallDir: true,
|
|
451
443
|
verify: Object.freeze({
|
|
452
444
|
mustInclude: ["static-openapi.stepfun.com", "stepcode"],
|
|
453
445
|
mustNotInclude: ["anomalyco/opencode"]
|
|
@@ -486,7 +478,8 @@ function installMethodsFor(tool) {
|
|
|
486
478
|
function installMethodFor(tool, methodId) {
|
|
487
479
|
const wanted = String(methodId ?? "").trim();
|
|
488
480
|
if (!wanted) return null;
|
|
489
|
-
|
|
481
|
+
const canonical = tool?.id === "codex" && wanted === "script-bash" ? "script-sh" : wanted;
|
|
482
|
+
return installMethodsFor(tool).find((method) => method.id === canonical) ?? null;
|
|
490
483
|
}
|
|
491
484
|
function defaultInstallMethod(tool) {
|
|
492
485
|
return installMethodsFor(tool)[0] ?? null;
|
|
@@ -500,8 +493,8 @@ function installCommandLineFor(tool, method) {
|
|
|
500
493
|
if (!tool || tool.unsupported) return null;
|
|
501
494
|
if (!method) return null;
|
|
502
495
|
if (method.kind === "script") {
|
|
503
|
-
const piped = method.shell === "powershell" ? `irm ${method.scriptUrl} | iex` : `curl -fsSL ${method.scriptUrl} |
|
|
504
|
-
return
|
|
496
|
+
const piped = method.shell === "powershell" ? `irm ${method.scriptUrl} | iex` : `curl -fsSL ${method.scriptUrl} | ${method.shell}`;
|
|
497
|
+
return piped;
|
|
505
498
|
}
|
|
506
499
|
return `${method.manager} ${method.installArgs.join(" ")}`;
|
|
507
500
|
}
|
|
@@ -831,9 +824,9 @@ function keepKnownToolIds(raw, known, subject) {
|
|
|
831
824
|
}
|
|
832
825
|
return raw;
|
|
833
826
|
}
|
|
834
|
-
function parseInstallPreferences(config = {}, { tools = [] } = {}) {
|
|
827
|
+
function parseInstallPreferences(config = {}, { tools = [], home = "", env = {} } = {}) {
|
|
835
828
|
const known = new Set(tools.map((tool) => tool.id));
|
|
836
|
-
const installDir = expandInstallDir(valueOf(config, "toolInstallDir", ""));
|
|
829
|
+
const installDir = expandInstallDir(valueOf(config, "toolInstallDir", ""), { home, env });
|
|
837
830
|
const registry = normalizeSourceUrl(valueOf(config, "toolNpmRegistry", DEFAULT_NPM_REGISTRY), "npm \u6E90") || DEFAULT_NPM_REGISTRY;
|
|
838
831
|
const methodRaw = keepKnownToolIds(
|
|
839
832
|
parseJsonObject(valueOf(config, "toolInstallMethodsJson", "{}"), "\u5B89\u88C5\u65B9\u5F0F\u8986\u76D6"),
|
|
@@ -850,9 +843,11 @@ function parseInstallPreferences(config = {}, { tools = [] } = {}) {
|
|
|
850
843
|
for (const [id2, methodId] of Object.entries(methodRaw)) methods[id2] = methodId.trim();
|
|
851
844
|
for (const [id2, url] of Object.entries(scriptRaw)) scriptUrls[id2] = normalizeSourceUrl(url, `${id2} \u5B89\u88C5\u811A\u672C\u6E90`);
|
|
852
845
|
for (const [id2, methodId] of Object.entries(methods)) {
|
|
853
|
-
|
|
846
|
+
const selected = installMethodFor({ id: id2, installMethods: tools.find((tool) => tool.id === id2)?.installMethods }, methodId);
|
|
847
|
+
if (!selected) {
|
|
854
848
|
throw new Error(`${id2} \u4E0D\u652F\u6301\u5B89\u88C5\u65B9\u5F0F ${methodId}\u3002`);
|
|
855
849
|
}
|
|
850
|
+
methods[id2] = selected.id;
|
|
856
851
|
}
|
|
857
852
|
return {
|
|
858
853
|
installDir,
|
|
@@ -2347,6 +2342,82 @@ function compareReleaseVersions(left, right) {
|
|
|
2347
2342
|
}
|
|
2348
2343
|
|
|
2349
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 toolInstallSettingsSignature(value = {}) {
|
|
2352
|
+
try {
|
|
2353
|
+
const preferences = parseInstallPreferences({ ...value, toolInstallDir: "" }, { tools: OFFICIAL_TOOLS });
|
|
2354
|
+
const sorted = (map) => Object.entries(map).sort(([left], [right]) => left.localeCompare(right));
|
|
2355
|
+
return JSON.stringify([
|
|
2356
|
+
String(value.toolInstallDir ?? "").trim(),
|
|
2357
|
+
preferences.registry,
|
|
2358
|
+
sorted(preferences.methods),
|
|
2359
|
+
sorted(preferences.scriptUrls),
|
|
2360
|
+
preferences.allowScriptInstall
|
|
2361
|
+
]);
|
|
2362
|
+
} catch {
|
|
2363
|
+
return JSON.stringify([
|
|
2364
|
+
"invalid",
|
|
2365
|
+
value.toolInstallDir,
|
|
2366
|
+
value.toolNpmRegistry,
|
|
2367
|
+
value.toolInstallMethodsJson,
|
|
2368
|
+
value.toolScriptUrlsJson,
|
|
2369
|
+
value.toolAllowScriptInstall
|
|
2370
|
+
]);
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
function installSummaryMatchesSettings(summary, value) {
|
|
2374
|
+
if (!summary) return false;
|
|
2375
|
+
return toolInstallSettingsSignature(value) === toolInstallSettingsSignature({
|
|
2376
|
+
toolInstallDir: summary.requestedInstallDir ?? summary.installDir ?? "",
|
|
2377
|
+
toolNpmRegistry: summary.registry || DEFAULT_NPM_REGISTRY,
|
|
2378
|
+
toolInstallMethodsJson: JSON.stringify(summary.methods ?? {}),
|
|
2379
|
+
toolScriptUrlsJson: JSON.stringify(summary.scriptUrls ?? {}),
|
|
2380
|
+
toolAllowScriptInstall: summary.allowScriptInstall !== false
|
|
2381
|
+
});
|
|
2382
|
+
}
|
|
2383
|
+
function savedToolInstallMethods(value = {}) {
|
|
2384
|
+
try {
|
|
2385
|
+
return parseInstallPreferences({ toolInstallMethodsJson: value.toolInstallMethodsJson }, { tools: OFFICIAL_TOOLS }).methods;
|
|
2386
|
+
} catch {
|
|
2387
|
+
return {};
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
async function mutateToolInstallSettings(scope, operations, revision, { timeoutMs = 15e3, onSettled } = {}) {
|
|
2391
|
+
let timer;
|
|
2392
|
+
try {
|
|
2393
|
+
const writing = Promise.resolve().then(() => scope.mutate(operations, revision)).then((accepted) => {
|
|
2394
|
+
onSettled?.({ accepted });
|
|
2395
|
+
return accepted;
|
|
2396
|
+
}, (error) => {
|
|
2397
|
+
onSettled?.({ accepted: false, error });
|
|
2398
|
+
throw error;
|
|
2399
|
+
});
|
|
2400
|
+
return await Promise.race([
|
|
2401
|
+
writing,
|
|
2402
|
+
new Promise((_2, reject) => {
|
|
2403
|
+
timer = setTimeout(() => reject(new Error("\u5B89\u88C5\u8BBE\u7F6E\u4FDD\u5B58\u672A\u6536\u5230\u786E\u8BA4\uFF0C\u8BF7\u5728\u8FDE\u63A5\u6062\u590D\u540E\u91CD\u8BD5\uFF1B\u8FDF\u5230\u7ED3\u679C\u4F1A\u6309\u5B9E\u9645\u5DF2\u4FDD\u5B58\u8BBE\u7F6E\u663E\u793A\u3002")), timeoutMs);
|
|
2404
|
+
})
|
|
2405
|
+
]);
|
|
2406
|
+
} finally {
|
|
2407
|
+
clearTimeout(timer);
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
function validateToolInstallSetting(key, value) {
|
|
2411
|
+
try {
|
|
2412
|
+
parseInstallPreferences({ [key]: value }, { tools: OFFICIAL_TOOLS });
|
|
2413
|
+
return "";
|
|
2414
|
+
} catch (error) {
|
|
2415
|
+
return error?.message || "\u5B89\u88C5\u8BBE\u7F6E\u65E0\u6548\u3002";
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
function retainToolInstallDrafts(drafts, values = {}) {
|
|
2419
|
+
return Object.fromEntries(Object.entries(drafts).filter(([key, value]) => value !== (values[key] ?? INSTALL_DEFAULTS[key])));
|
|
2420
|
+
}
|
|
2350
2421
|
function toolInstallAction({ tool, probe, readiness, job, probeStatus, latestVersion = null }) {
|
|
2351
2422
|
const running = job?.status === "running";
|
|
2352
2423
|
const installed = probe?.installed === true;
|
|
@@ -2381,7 +2452,7 @@ function toolMaintenanceActions({ tool, probe, job, probeStatus, summary }) {
|
|
|
2381
2452
|
}
|
|
2382
2453
|
};
|
|
2383
2454
|
}
|
|
2384
|
-
function installClickRefusal({ tool, submitting = false, running = false, operation = "install" } = {}) {
|
|
2455
|
+
function installClickRefusal({ tool, submitting = false, running = false, operation = "install", pendingSettings = false, installError = "" } = {}) {
|
|
2385
2456
|
if (!tool) return "\u672A\u77E5\u5B98\u65B9\u5DE5\u5177\uFF0C\u65E0\u6CD5\u5F00\u59CB\u5B89\u88C5\u3002";
|
|
2386
2457
|
if (tool.unsupported) return String(tool.unsupportedReason ?? "").trim() || "\u6B64\u5DE5\u5177\u6682\u4E0D\u652F\u6301\u4E00\u952E\u5B89\u88C5\u3002";
|
|
2387
2458
|
if (tool.manager === "signed-windows-installer" && operation !== "install") {
|
|
@@ -2390,6 +2461,8 @@ function installClickRefusal({ tool, submitting = false, running = false, operat
|
|
|
2390
2461
|
if (submitting || running) {
|
|
2391
2462
|
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
2463
|
}
|
|
2464
|
+
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";
|
|
2465
|
+
if (installError) return installError;
|
|
2393
2466
|
return "";
|
|
2394
2467
|
}
|
|
2395
2468
|
function payloadError(payload, fallback) {
|
|
@@ -3204,7 +3277,7 @@ function LaunchPreview({ value, changed, running, confirmRef, onConfirm, onCance
|
|
|
3204
3277
|
// .dsh-plugin/client/cli-terminal.jsx
|
|
3205
3278
|
var import_react4 = __toESM(require("react"), 1);
|
|
3206
3279
|
|
|
3207
|
-
// node_modules/@xterm/xterm/lib/xterm.mjs
|
|
3280
|
+
// node_modules/.pnpm/@xterm+xterm@6.0.0/node_modules/@xterm/xterm/lib/xterm.mjs
|
|
3208
3281
|
var zs = Object.defineProperty;
|
|
3209
3282
|
var Rl = Object.getOwnPropertyDescriptor;
|
|
3210
3283
|
var Ll = (s15, t) => {
|
|
@@ -12318,7 +12391,7 @@ var Dl = class extends D {
|
|
|
12318
12391
|
}
|
|
12319
12392
|
};
|
|
12320
12393
|
|
|
12321
|
-
// node_modules/@xterm/addon-fit/lib/addon-fit.mjs
|
|
12394
|
+
// node_modules/.pnpm/@xterm+addon-fit@0.11.0/node_modules/@xterm/addon-fit/lib/addon-fit.mjs
|
|
12322
12395
|
var h = 2;
|
|
12323
12396
|
var _ = 1;
|
|
12324
12397
|
var o = class {
|
|
@@ -12342,7 +12415,7 @@ var o = class {
|
|
|
12342
12415
|
}
|
|
12343
12416
|
};
|
|
12344
12417
|
|
|
12345
|
-
// node_modules/@xterm/xterm/css/xterm.css
|
|
12418
|
+
// node_modules/.pnpm/@xterm+xterm@6.0.0/node_modules/@xterm/xterm/css/xterm.css
|
|
12346
12419
|
var xterm_default = `/**
|
|
12347
12420
|
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
|
12348
12421
|
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
|
@@ -12631,7 +12704,7 @@ var xterm_default = `/**
|
|
|
12631
12704
|
`;
|
|
12632
12705
|
|
|
12633
12706
|
// .dsh-plugin/client/host-version.mjs
|
|
12634
|
-
var ROUTER_CLIENT_VERSION = true ? "0.
|
|
12707
|
+
var ROUTER_CLIENT_VERSION = true ? "0.18.1" : "";
|
|
12635
12708
|
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";
|
|
12636
12709
|
function isMissingRemoteMethod(message) {
|
|
12637
12710
|
const value = String(message ?? "");
|
|
@@ -13223,14 +13296,15 @@ var router_main_default = `.mr-workspace {
|
|
|
13223
13296
|
.mr-tool-dot.running { background: #e9a640; }
|
|
13224
13297
|
.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; }
|
|
13225
13298
|
.mr-tool-button { flex-shrink: 0; }
|
|
13226
|
-
.mr-tool-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
|
|
13299
|
+
.mr-tool-actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; flex: 0 1 420px; }
|
|
13227
13300
|
.mr-tool-detail { margin: 7px 0 0; }
|
|
13228
13301
|
.mr-tool-error { margin: 8px 0 0; padding: 9px 11px; }
|
|
13229
13302
|
.mr-tool-log { margin-top: 7px; color: var(--mr-muted); font-size: 11px; }
|
|
13230
13303
|
.mr-tool-log summary { cursor: pointer; }
|
|
13231
13304
|
.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;
|
|
13233
|
-
.mr-tool-methods label { display: flex; align-items: center; gap: 6px; color: var(--mr-muted); font-size: 11px; }
|
|
13305
|
+
.mr-tool-methods { display: flex; align-items: center; gap: 6px; width: 100%; }
|
|
13306
|
+
.mr-tool-methods label { display: flex; align-items: center; justify-content: flex-end; gap: 6px; width: 100%; color: var(--mr-muted); font-size: 11px; }
|
|
13307
|
+
.mr-tool-methods .mr-mini-select { min-width: 0; max-width: calc(100% - 54px); }
|
|
13234
13308
|
.mr-install-settings { margin-bottom: 14px; padding: 13px 14px; border: 1px solid var(--mr-line); border-radius: 11px; background: var(--mr-card); }
|
|
13235
13309
|
.mr-install-settings-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
|
|
13236
13310
|
.mr-install-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
|
|
@@ -13239,6 +13313,7 @@ var router_main_default = `.mr-workspace {
|
|
|
13239
13313
|
.mr-install-field small { font-size: 11px; line-height: 1.6; }
|
|
13240
13314
|
.mr-install-error { color: #d95360; }
|
|
13241
13315
|
.mr-install-toggle-row { display: flex; align-items: center; gap: 7px; }
|
|
13316
|
+
.mr-install-save-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
|
|
13242
13317
|
.mr-channel-line { display: flex; align-items: center; gap: 8px; margin: 8px 0; flex-wrap: wrap; }
|
|
13243
13318
|
.mr-pill-channel-ok { border-color: var(--dsw-alias-success, #2f9e63); color: var(--dsw-alias-success, #2f9e63); }
|
|
13244
13319
|
.mr-pill-warn { border-color: var(--dsw-alias-warning, #c27c0e); color: var(--dsw-alias-warning, #c27c0e); }
|
|
@@ -13251,7 +13326,7 @@ var router_main_default = `.mr-workspace {
|
|
|
13251
13326
|
.mr-profile-advanced summary { cursor: pointer; }
|
|
13252
13327
|
.mr-profile-success { padding: 10px 12px; border-radius: 10px; background: #e5f5eb; color: #175f3a; font-size: 12px; }
|
|
13253
13328
|
@media (prefers-color-scheme: dark) { .mr-profile-success { background: #193b2b; color: #b4f1cc; } }
|
|
13254
|
-
@media (max-width: 560px) { .mr-tool { align-items: stretch; flex-direction: column; gap: 10px; } .mr-tool-button { align-self: flex-start; } }
|
|
13329
|
+
@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; } }
|
|
13255
13330
|
|
|
13256
13331
|
/* \u5F00\u7BB1\u4F53\u68C0\u3001\u6210\u672C\u63A7\u5236\u3001\u6267\u884C\u8BB0\u5F55\u3001\u5B89\u5168\u8FB9\u754C */
|
|
13257
13332
|
.mr-onboarding, .mr-cost { margin-bottom: 18px; }
|
|
@@ -13465,41 +13540,24 @@ var INSTALL_SETTING_FIELDS = [
|
|
|
13465
13540
|
label: "\u7EDF\u4E00\u5B89\u88C5\u76EE\u5F55",
|
|
13466
13541
|
fallback: "",
|
|
13467
13542
|
placeholder: "\u7559\u7A7A = \u5404\u5382\u5546\u9ED8\u8BA4\u76EE\u5F55",
|
|
13468
|
-
hint: "
|
|
13469
|
-
validate: () => null
|
|
13543
|
+
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"
|
|
13470
13544
|
},
|
|
13471
13545
|
{
|
|
13472
13546
|
key: "toolNpmRegistry",
|
|
13473
13547
|
label: "npm \u6E90\u5730\u5740",
|
|
13474
13548
|
fallback: "https://registry.npmjs.org/",
|
|
13475
13549
|
placeholder: "https://registry.npmjs.org/",
|
|
13476
|
-
hint: "\u5FC5\u987B\u4EE5 https:// \u5F00\u5934\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/"
|
|
13550
|
+
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"
|
|
13478
13551
|
},
|
|
13479
13552
|
{
|
|
13480
13553
|
key: "toolScriptUrlsJson",
|
|
13481
13554
|
label: "\u5B89\u88C5\u811A\u672C\u6E90\u8986\u76D6\uFF08JSON\uFF0C\u53EF\u9009\uFF09",
|
|
13482
13555
|
fallback: "{}",
|
|
13483
13556
|
placeholder: '{ "stepcode": "https://mirror/stepcode/install.ps1" }',
|
|
13484
|
-
hint: "\u6309\u5DE5\u5177 ID \u6307\u5B9A\
|
|
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
|
-
}
|
|
13557
|
+
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"
|
|
13500
13558
|
}
|
|
13501
13559
|
];
|
|
13502
|
-
function InstallSettings({ settingsScope, install }) {
|
|
13560
|
+
function InstallSettings({ settingsScope, install, onPendingChange, onMutationStart }) {
|
|
13503
13561
|
const [snapshot, setSnapshot] = import_react5.default.useState(() => settingsScope?.getSnapshot?.() ?? { value: {}, writable: false });
|
|
13504
13562
|
const [drafts, setDrafts] = import_react5.default.useState({});
|
|
13505
13563
|
const [saving, setSaving] = import_react5.default.useState(false);
|
|
@@ -13507,36 +13565,53 @@ function InstallSettings({ settingsScope, install }) {
|
|
|
13507
13565
|
import_react5.default.useEffect(() => {
|
|
13508
13566
|
if (typeof settingsScope?.subscribe !== "function") return void 0;
|
|
13509
13567
|
const unsubscribe = settingsScope.subscribe(() => {
|
|
13510
|
-
|
|
13511
|
-
|
|
13568
|
+
const next = settingsScope.getSnapshot();
|
|
13569
|
+
setSnapshot(next);
|
|
13570
|
+
setDrafts((previous) => retainToolInstallDrafts(previous, next.value));
|
|
13512
13571
|
});
|
|
13513
13572
|
setSnapshot(settingsScope.getSnapshot());
|
|
13514
13573
|
return unsubscribe;
|
|
13515
13574
|
}, [settingsScope]);
|
|
13575
|
+
const dirty = Object.keys(drafts).length > 0;
|
|
13576
|
+
import_react5.default.useEffect(() => {
|
|
13577
|
+
onPendingChange?.(saving || dirty);
|
|
13578
|
+
}, [saving, dirty, onPendingChange]);
|
|
13516
13579
|
if (!settingsScope) return null;
|
|
13517
13580
|
const writable = snapshot.writable === true && !saving;
|
|
13518
13581
|
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.
|
|
13520
|
-
const
|
|
13582
|
+
const errors = Object.fromEntries(INSTALL_SETTING_FIELDS.map((field2) => [field2.key, validateToolInstallSetting(field2.key, shown(field2))]));
|
|
13583
|
+
const invalid = Object.values(errors).some(Boolean);
|
|
13584
|
+
const edit = (key, value) => {
|
|
13585
|
+
const next = retainToolInstallDrafts({ ...drafts, [key]: value }, snapshot.value);
|
|
13586
|
+
onPendingChange?.(saving || Object.keys(next).length > 0);
|
|
13587
|
+
setNotice("");
|
|
13588
|
+
setDrafts(next);
|
|
13589
|
+
};
|
|
13590
|
+
const apply2 = async () => {
|
|
13591
|
+
if (!writable || !dirty || invalid) return;
|
|
13521
13592
|
setSaving(true);
|
|
13593
|
+
onPendingChange?.(true);
|
|
13522
13594
|
setNotice("");
|
|
13523
13595
|
try {
|
|
13524
|
-
const
|
|
13596
|
+
const entries = Object.entries(drafts).map(([key, value]) => ({ op: "set", path: [key], value }));
|
|
13597
|
+
const finishMutation = onMutationStart?.(entries);
|
|
13598
|
+
const onSettled = (outcome) => {
|
|
13599
|
+
const current = finishMutation?.(outcome);
|
|
13600
|
+
if (current && outcome.accepted) setNotice("\u5B89\u88C5\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002");
|
|
13601
|
+
};
|
|
13602
|
+
const accepted = await mutateToolInstallSettings(settingsScope, entries, snapshot.revision, { onSettled });
|
|
13525
13603
|
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
|
-
|
|
13604
|
+
const next = settingsScope.getSnapshot();
|
|
13605
|
+
setSnapshot(next);
|
|
13606
|
+
setDrafts((previous) => retainToolInstallDrafts(previous, next.value));
|
|
13607
|
+
setNotice("\u5B89\u88C5\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002");
|
|
13527
13608
|
} catch (error) {
|
|
13528
13609
|
setNotice(text5(error?.message) || "\u5B89\u88C5\u8BBE\u7F6E\u4FDD\u5B58\u5931\u8D25\u3002");
|
|
13529
13610
|
} finally {
|
|
13530
13611
|
setSaving(false);
|
|
13531
13612
|
}
|
|
13532
13613
|
};
|
|
13533
|
-
|
|
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(
|
|
13614
|
+
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(
|
|
13540
13615
|
"input",
|
|
13541
13616
|
{
|
|
13542
13617
|
className: "mr-input",
|
|
@@ -13544,37 +13619,52 @@ function InstallSettings({ settingsScope, install }) {
|
|
|
13544
13619
|
placeholder: field2.placeholder,
|
|
13545
13620
|
disabled: !writable,
|
|
13546
13621
|
"aria-invalid": Boolean(errors[field2.key]),
|
|
13547
|
-
onChange: (event) =>
|
|
13548
|
-
onBlur: () => {
|
|
13549
|
-
void commit(field2);
|
|
13550
|
-
}
|
|
13622
|
+
onChange: (event) => edit(field2.key, event.target.value)
|
|
13551
13623
|
}
|
|
13552
13624
|
), 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
13625
|
"input",
|
|
13554
13626
|
{
|
|
13555
13627
|
type: "checkbox",
|
|
13556
|
-
checked: snapshot.value?.toolAllowScriptInstall !== false,
|
|
13628
|
+
checked: (drafts.toolAllowScriptInstall ?? snapshot.value?.toolAllowScriptInstall) !== false,
|
|
13557
13629
|
disabled: !writable,
|
|
13558
13630
|
onChange: (event) => {
|
|
13559
|
-
|
|
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
|
-
);
|
|
13631
|
+
edit("toolAllowScriptInstall", event.target.checked);
|
|
13564
13632
|
}
|
|
13565
13633
|
}
|
|
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("
|
|
13634
|
+
), /* @__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: () => {
|
|
13635
|
+
void apply2();
|
|
13636
|
+
} }, 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: () => {
|
|
13637
|
+
setDrafts({});
|
|
13638
|
+
setNotice("");
|
|
13639
|
+
onPendingChange?.(false);
|
|
13640
|
+
} }, "\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}` : ""));
|
|
13567
13641
|
}
|
|
13568
|
-
function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes, health, onRefreshHealth, settingsScope }) {
|
|
13642
|
+
function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes, health, onRefreshHealth, settingsScope }) {
|
|
13569
13643
|
const healthById = Object.fromEntries((health?.tools ?? []).map((item) => [item.id, item]));
|
|
13570
13644
|
const [probeState, setProbeState] = import_react5.default.useState({ status: "loading", probes: [], capabilities: [], readiness: [], install: null, error: "" });
|
|
13571
13645
|
const [jobs, setJobs] = import_react5.default.useState({});
|
|
13572
13646
|
const [rowErrors, setRowErrors] = import_react5.default.useState({});
|
|
13647
|
+
const [settingsPending, setSettingsPending] = import_react5.default.useState(false);
|
|
13648
|
+
const [methodSaving, setMethodSaving] = import_react5.default.useState(null);
|
|
13649
|
+
const [previewPending, setPreviewPending] = import_react5.default.useState(false);
|
|
13650
|
+
const [settingsSnapshot, setSettingsSnapshot] = import_react5.default.useState(() => settingsScope?.getSnapshot?.() ?? { value: {}, writable: false });
|
|
13651
|
+
const [previewError, setPreviewError] = import_react5.default.useState("");
|
|
13652
|
+
const [probeSettingsStale, setProbeSettingsStale] = import_react5.default.useState(false);
|
|
13653
|
+
const settingsPendingRef = import_react5.default.useRef(false);
|
|
13654
|
+
const methodSavingRef = import_react5.default.useRef(null);
|
|
13655
|
+
const previewPendingRef = import_react5.default.useRef(false);
|
|
13573
13656
|
const mounted = import_react5.default.useRef(false);
|
|
13574
13657
|
const request = import_react5.default.useRef(0);
|
|
13658
|
+
const previewRequest = import_react5.default.useRef(0);
|
|
13659
|
+
const mutationGeneration = import_react5.default.useRef(0);
|
|
13660
|
+
const mutationPendingRef = import_react5.default.useRef(null);
|
|
13575
13661
|
const submitting = import_react5.default.useRef(/* @__PURE__ */ new Set());
|
|
13576
13662
|
const polling = import_react5.default.useRef(/* @__PURE__ */ new Set());
|
|
13577
13663
|
const jobsRef = import_react5.default.useRef({});
|
|
13664
|
+
const handleSettingsPending = import_react5.default.useCallback((value) => {
|
|
13665
|
+
settingsPendingRef.current = value;
|
|
13666
|
+
setSettingsPending(value);
|
|
13667
|
+
}, []);
|
|
13578
13668
|
const rememberJobs = (updater) => {
|
|
13579
13669
|
setJobs((previous) => {
|
|
13580
13670
|
const next = typeof updater === "function" ? updater(previous) : updater;
|
|
@@ -13585,27 +13675,46 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13585
13675
|
const refresh = async () => {
|
|
13586
13676
|
onRefreshHealth?.();
|
|
13587
13677
|
const current = ++request.current;
|
|
13678
|
+
const settingsSignature = toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value);
|
|
13588
13679
|
setProbeState((previous) => ({
|
|
13589
13680
|
...previous,
|
|
13590
|
-
status: previous.probes.length > 0 ? "refreshing" : "loading",
|
|
13681
|
+
status: previous.probes.length > 0 || previous.install ? "refreshing" : "loading",
|
|
13591
13682
|
error: ""
|
|
13592
13683
|
}));
|
|
13593
13684
|
try {
|
|
13594
13685
|
if (typeof listOfficialTools !== "function") throw new Error("\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002");
|
|
13595
13686
|
const response = await listOfficialTools();
|
|
13596
13687
|
if (!mounted.current || current !== request.current) return;
|
|
13688
|
+
if (settingsSignature !== toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value)) return;
|
|
13597
13689
|
if (!response?.ok) throw new Error(remoteError(response, "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002"));
|
|
13598
13690
|
const probes = Array.isArray(response.value?.tools) ? response.value.tools : [];
|
|
13599
13691
|
const capabilities = Array.isArray(response.value?.executionCapabilities) ? response.value.executionCapabilities : [];
|
|
13600
13692
|
const readiness = Array.isArray(response.value?.executionReadiness) ? response.value.executionReadiness : [];
|
|
13601
|
-
|
|
13693
|
+
const install2 = response.value?.install;
|
|
13694
|
+
const matches = settingsSignature === toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value) && installSummaryMatchesSettings(install2, settingsScope?.getSnapshot?.()?.value);
|
|
13695
|
+
if (!matches) return;
|
|
13696
|
+
setProbeState((previous) => ({
|
|
13697
|
+
status: "ready",
|
|
13698
|
+
probes,
|
|
13699
|
+
capabilities,
|
|
13700
|
+
readiness,
|
|
13701
|
+
install: matches ? install2 : previous.install,
|
|
13702
|
+
error: ""
|
|
13703
|
+
}));
|
|
13704
|
+
setProbeSettingsStale(false);
|
|
13705
|
+
if (matches && !mutationPendingRef.current) {
|
|
13706
|
+
previewPendingRef.current = false;
|
|
13707
|
+
setPreviewPending(false);
|
|
13708
|
+
setPreviewError("");
|
|
13709
|
+
}
|
|
13602
13710
|
onProbes({ probes, capabilities, readiness, hostVersion: typeof response.value?.hostVersion === "string" ? response.value.hostVersion : null });
|
|
13603
13711
|
} catch (error) {
|
|
13604
13712
|
if (!mounted.current || current !== request.current) return;
|
|
13713
|
+
if (settingsSignature !== toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value)) return;
|
|
13605
13714
|
const message = remoteErrorText(text5(error?.message), "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002");
|
|
13606
13715
|
let kept = false;
|
|
13607
13716
|
setProbeState((previous) => {
|
|
13608
|
-
if (previous.probes.length > 0) {
|
|
13717
|
+
if (previous.probes.length > 0 || previous.install) {
|
|
13609
13718
|
kept = true;
|
|
13610
13719
|
return { ...previous, status: "ready", error: message };
|
|
13611
13720
|
}
|
|
@@ -13614,9 +13723,38 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13614
13723
|
if (!kept) onProbes({ probes: [], capabilities: [], readiness: [] });
|
|
13615
13724
|
}
|
|
13616
13725
|
};
|
|
13726
|
+
const refreshInstallSettings = async () => {
|
|
13727
|
+
const current = ++previewRequest.current;
|
|
13728
|
+
const snapshot = settingsScope?.getSnapshot?.();
|
|
13729
|
+
const signature2 = toolInstallSettingsSignature(snapshot?.value);
|
|
13730
|
+
previewPendingRef.current = true;
|
|
13731
|
+
setPreviewPending(true);
|
|
13732
|
+
setPreviewError("");
|
|
13733
|
+
try {
|
|
13734
|
+
if (typeof loadOfficialInstallSettings !== "function") throw new Error("\u5B89\u88C5\u8BBE\u7F6E\u6865\u5C1A\u672A\u52A0\u8F7D\uFF0C\u8BF7\u66F4\u65B0 Host \u540E\u91CD\u65B0\u6253\u5F00\u5DE5\u4F5C\u53F0\u3002");
|
|
13735
|
+
const response = await loadOfficialInstallSettings();
|
|
13736
|
+
if (!mounted.current || current !== previewRequest.current || signature2 !== toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value)) return;
|
|
13737
|
+
if (!response?.ok) throw new Error(remoteError(response, "\u65E0\u6CD5\u8BFB\u53D6\u5B89\u88C5\u8BBE\u7F6E\u3002"));
|
|
13738
|
+
if (!installSummaryMatchesSettings(response.value?.install, settingsScope?.getSnapshot?.()?.value)) {
|
|
13739
|
+
throw new Error("\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\uFF0C\u4F46 Host \u5B89\u88C5\u914D\u7F6E\u5C1A\u672A\u540C\u6B65\uFF1B\u8BF7\u5237\u65B0\u5B89\u88C5\u547D\u4EE4\u540E\u518D\u5B89\u88C5\u3002");
|
|
13740
|
+
}
|
|
13741
|
+
setProbeState((previous) => ({
|
|
13742
|
+
...previous,
|
|
13743
|
+
status: previous.status === "loading" || previous.status === "error" ? "ready" : previous.status,
|
|
13744
|
+
install: response.value.install
|
|
13745
|
+
}));
|
|
13746
|
+
if (!mutationPendingRef.current) {
|
|
13747
|
+
previewPendingRef.current = false;
|
|
13748
|
+
setPreviewPending(false);
|
|
13749
|
+
}
|
|
13750
|
+
} catch (error) {
|
|
13751
|
+
if (mounted.current && current === previewRequest.current) setPreviewError(text5(error?.message) || "\u5B89\u88C5\u547D\u4EE4\u5237\u65B0\u5931\u8D25\u3002");
|
|
13752
|
+
}
|
|
13753
|
+
};
|
|
13617
13754
|
import_react5.default.useEffect(() => {
|
|
13618
13755
|
mounted.current = true;
|
|
13619
13756
|
void refresh();
|
|
13757
|
+
void refreshInstallSettings();
|
|
13620
13758
|
if (typeof officialToolInstallStatus === "function") {
|
|
13621
13759
|
void Promise.all(OFFICIAL_TOOLS.map(async (tool) => {
|
|
13622
13760
|
try {
|
|
@@ -13641,8 +13779,42 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13641
13779
|
return () => {
|
|
13642
13780
|
mounted.current = false;
|
|
13643
13781
|
request.current += 1;
|
|
13782
|
+
previewRequest.current += 1;
|
|
13783
|
+
};
|
|
13784
|
+
}, []);
|
|
13785
|
+
const refreshInstallSettingsRef = import_react5.default.useRef(refreshInstallSettings);
|
|
13786
|
+
refreshInstallSettingsRef.current = refreshInstallSettings;
|
|
13787
|
+
const beginSettingsMutation = import_react5.default.useCallback((operations) => {
|
|
13788
|
+
const generation = ++mutationGeneration.current;
|
|
13789
|
+
mutationPendingRef.current = { generation, operations };
|
|
13790
|
+
previewPendingRef.current = true;
|
|
13791
|
+
setPreviewPending(true);
|
|
13792
|
+
return () => {
|
|
13793
|
+
if (!mounted.current || mutationPendingRef.current?.generation !== generation) return false;
|
|
13794
|
+
mutationPendingRef.current = null;
|
|
13795
|
+
void refreshInstallSettingsRef.current();
|
|
13796
|
+
return true;
|
|
13644
13797
|
};
|
|
13645
13798
|
}, []);
|
|
13799
|
+
import_react5.default.useEffect(() => {
|
|
13800
|
+
if (typeof settingsScope?.subscribe !== "function") return void 0;
|
|
13801
|
+
const signature2 = (snapshot) => toolInstallSettingsSignature(snapshot?.value);
|
|
13802
|
+
let previous = signature2(settingsScope.getSnapshot());
|
|
13803
|
+
return settingsScope.subscribe(() => {
|
|
13804
|
+
const snapshot = settingsScope.getSnapshot();
|
|
13805
|
+
setSettingsSnapshot(snapshot);
|
|
13806
|
+
const next = signature2(snapshot);
|
|
13807
|
+
if (next === previous) return;
|
|
13808
|
+
previous = next;
|
|
13809
|
+
request.current += 1;
|
|
13810
|
+
setProbeSettingsStale(true);
|
|
13811
|
+
setProbeState((previous2) => ({ ...previous2, status: "ready", probes: [], readiness: [], error: "" }));
|
|
13812
|
+
onProbes({ probes: [], capabilities: [], readiness: [] });
|
|
13813
|
+
previewPendingRef.current = true;
|
|
13814
|
+
setPreviewPending(true);
|
|
13815
|
+
void refreshInstallSettingsRef.current();
|
|
13816
|
+
});
|
|
13817
|
+
}, [settingsScope]);
|
|
13646
13818
|
import_react5.default.useEffect(() => {
|
|
13647
13819
|
const active = Object.values(jobs).filter((job) => job?.status === "running").map((job) => job.tool);
|
|
13648
13820
|
if (active.length === 0 || typeof officialToolInstallStatus !== "function") return void 0;
|
|
@@ -13683,18 +13855,24 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13683
13855
|
}, [jobs, officialToolInstallStatus]);
|
|
13684
13856
|
const run = async (id2, operation) => {
|
|
13685
13857
|
const tool = OFFICIAL_TOOLS.find((item) => item.id === id2);
|
|
13858
|
+
const summary = (probeState.install?.tools ?? []).find((item) => item.id === id2);
|
|
13686
13859
|
const bridge = { install: installOfficialTool, repair: repairOfficialTool, uninstall: uninstallOfficialTool }[operation];
|
|
13687
13860
|
const refusal = installClickRefusal({
|
|
13688
13861
|
tool,
|
|
13689
13862
|
submitting: submitting.current.has(id2),
|
|
13690
13863
|
running: jobsRef.current[id2]?.status === "running",
|
|
13691
|
-
operation
|
|
13864
|
+
operation,
|
|
13865
|
+
pendingSettings: settingsPendingRef.current || Boolean(methodSavingRef.current) || previewPendingRef.current,
|
|
13866
|
+
installError: operation === "uninstall" ? summary?.uninstallError ?? (summary?.uninstallCommand ? "" : summary?.error ?? "") : summary?.installError ?? summary?.error ?? ""
|
|
13692
13867
|
});
|
|
13693
13868
|
if (refusal) {
|
|
13694
13869
|
setRowErrors((previous) => ({ ...previous, [id2]: refusal }));
|
|
13695
13870
|
return;
|
|
13696
13871
|
}
|
|
13697
|
-
if (typeof bridge !== "function")
|
|
13872
|
+
if (typeof bridge !== "function") {
|
|
13873
|
+
setRowErrors((previous) => ({ ...previous, [id2]: "\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002" }));
|
|
13874
|
+
return;
|
|
13875
|
+
}
|
|
13698
13876
|
submitting.current.add(id2);
|
|
13699
13877
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13700
13878
|
setRowErrors((previous) => ({ ...previous, [id2]: "" }));
|
|
@@ -13731,7 +13909,10 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13731
13909
|
const uninstall = (id2) => run(id2, "uninstall");
|
|
13732
13910
|
const setInstallMethod = async (toolId, methodId) => {
|
|
13733
13911
|
const snapshot = settingsScope?.getSnapshot?.();
|
|
13734
|
-
if (!snapshot) return;
|
|
13912
|
+
if (!snapshot?.writable || methodSavingRef.current || settingsPendingRef.current) return;
|
|
13913
|
+
methodSavingRef.current = toolId;
|
|
13914
|
+
setMethodSaving(toolId);
|
|
13915
|
+
setRowErrors((previous) => ({ ...previous, [toolId]: "" }));
|
|
13735
13916
|
let map = {};
|
|
13736
13917
|
try {
|
|
13737
13918
|
map = JSON.parse(String(snapshot.value?.toolInstallMethodsJson ?? "{}")) || {};
|
|
@@ -13742,11 +13923,19 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13742
13923
|
if (methodId) map[toolId] = methodId;
|
|
13743
13924
|
else delete map[toolId];
|
|
13744
13925
|
try {
|
|
13745
|
-
const
|
|
13926
|
+
const operations = [{ op: "set", path: ["toolInstallMethodsJson"], value: JSON.stringify(map) }];
|
|
13927
|
+
const finishMutation = beginSettingsMutation(operations);
|
|
13928
|
+
const onSettled = (outcome) => {
|
|
13929
|
+
if (finishMutation(outcome) && outcome.accepted) setRowErrors((previous) => ({ ...previous, [toolId]: "" }));
|
|
13930
|
+
};
|
|
13931
|
+
const accepted = await mutateToolInstallSettings(settingsScope, operations, snapshot.revision, { onSettled });
|
|
13746
13932
|
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
|
-
|
|
13933
|
+
setSettingsSnapshot(settingsScope.getSnapshot());
|
|
13748
13934
|
} catch (error) {
|
|
13749
13935
|
if (mounted.current) setRowErrors((previous) => ({ ...previous, [toolId]: text5(error?.message) || "\u5B89\u88C5\u65B9\u5F0F\u4FDD\u5B58\u5931\u8D25\u3002" }));
|
|
13936
|
+
} finally {
|
|
13937
|
+
methodSavingRef.current = null;
|
|
13938
|
+
if (mounted.current) setMethodSaving(null);
|
|
13750
13939
|
}
|
|
13751
13940
|
};
|
|
13752
13941
|
const cancel = async (id2) => {
|
|
@@ -13766,12 +13955,19 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13766
13955
|
const capabilitiesById = Object.fromEntries(probeState.capabilities.map((item) => [item.id, item]));
|
|
13767
13956
|
const readinessById = Object.fromEntries(probeState.readiness.map((item) => [item.id, item]));
|
|
13768
13957
|
const installById = Object.fromEntries((probeState.install?.tools ?? []).map((item) => [item.id, item]));
|
|
13958
|
+
const savedMethods = savedToolInstallMethods(settingsSnapshot.value);
|
|
13769
13959
|
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: () => {
|
|
13770
13960
|
void refresh();
|
|
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 }),
|
|
13961
|
+
} }, "\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, onMutationStart: beginSettingsMutation }), 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\u4ECD\u53EF\u5207\u6362\u65B9\u5F0F\uFF0C\u5237\u65B0\u5B8C\u6210\u540E\u53EF\u5B89\u88C5\u4E0E\u66F4\u65B0\u3002", !previewError && /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => {
|
|
13962
|
+
void refreshInstallSettings();
|
|
13963
|
+
} }, "\u5237\u65B0\u5B89\u88C5\u547D\u4EE4")), previewError && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error", role: "alert" }, previewError, " ", /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => {
|
|
13964
|
+
void refreshInstallSettings();
|
|
13965
|
+
} }, "\u5237\u65B0\u5B89\u88C5\u547D\u4EE4")), probeSettingsStale && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", role: "status" }, "\u5B89\u88C5\u8BBE\u7F6E\u5DF2\u66F4\u6539\uFF0C\u65E7\u76EE\u6807\u7684\u7248\u672C\u4E0E\u5B89\u88C5\u72B6\u6001\u5DF2\u8FC7\u671F\u3002\u53EF\u5B89\u88C5\u6240\u9009\u76EE\u6807\uFF1B\u5378\u8F7D\u524D\u8BF7\u91CD\u65B0\u4F53\u68C0\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) => {
|
|
13772
13966
|
const summary = installById[tool.id];
|
|
13773
|
-
const command = summary
|
|
13967
|
+
const command = summary ? summary.command : installCommandLine(tool);
|
|
13968
|
+
const updateCommand = summary?.updateCommand ?? command;
|
|
13774
13969
|
const methods = summary?.methods ?? installMethodsFor(tool).map((method) => ({ id: method.id, label: method.label }));
|
|
13970
|
+
const settingsBusy = settingsPending || Boolean(methodSaving) || previewPending;
|
|
13775
13971
|
const probe = byId[tool.id];
|
|
13776
13972
|
const capability = capabilitiesById[tool.id];
|
|
13777
13973
|
const readiness = readinessById[tool.id];
|
|
@@ -13783,32 +13979,36 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13783
13979
|
probe,
|
|
13784
13980
|
job,
|
|
13785
13981
|
probeStatus: probeState.status,
|
|
13786
|
-
summary: {
|
|
13982
|
+
summary: {
|
|
13983
|
+
installable: !(summary?.installError ?? summary?.error),
|
|
13984
|
+
removable: !(summary?.uninstallError ?? (summary?.uninstallCommand ? "" : summary?.error))
|
|
13985
|
+
}
|
|
13787
13986
|
});
|
|
13788
|
-
const verified = job?.status === "succeeded" && (job.operation === "uninstall" ? job.postInstallProbe?.installed === false : job.postInstallProbe?.installed === true);
|
|
13987
|
+
const verified = Boolean(probe) && job?.status === "succeeded" && (job.operation === "uninstall" ? job.postInstallProbe?.installed === false : job.postInstallProbe?.installed === true);
|
|
13789
13988
|
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(
|
|
13989
|
+
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` : probe ? probeLabel(probe) : "\u6240\u9009\u5B89\u88C5\u76EE\u6807\u5C1A\u672A\u4F53\u68C0";
|
|
13990
|
+
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(
|
|
13792
13991
|
"select",
|
|
13793
13992
|
{
|
|
13794
13993
|
className: "mr-mini-select",
|
|
13795
|
-
value:
|
|
13796
|
-
disabled: running ||
|
|
13994
|
+
value: savedMethods[tool.id] ?? "",
|
|
13995
|
+
disabled: running || settingsPending || Boolean(methodSaving) || settingsSnapshot.writable !== true,
|
|
13797
13996
|
onChange: (event) => {
|
|
13798
13997
|
void setInstallMethod(tool.id, event.target.value);
|
|
13799
13998
|
}
|
|
13800
13999
|
},
|
|
14000
|
+
/* @__PURE__ */ import_react5.default.createElement("option", { value: "" }, "\u81EA\u52A8\u9009\u62E9"),
|
|
13801
14001
|
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: () => {
|
|
14002
|
+
))), /* @__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: () => {
|
|
13803
14003
|
void install(tool.id);
|
|
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: () => {
|
|
14004
|
+
} }, 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: () => {
|
|
13805
14005
|
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: () => {
|
|
14006
|
+
} }, 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: () => {
|
|
13807
14007
|
void uninstall(tool.id);
|
|
13808
14008
|
} }, 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: () => {
|
|
13809
14009
|
void cancel(tool.id);
|
|
13810
14010
|
} }, 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\
|
|
14011
|
+
})), /* @__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")));
|
|
13812
14012
|
}
|
|
13813
14013
|
var HEADLESS_TOOLS = /* @__PURE__ */ new Set(["claude-code", "codex", "gemini"]);
|
|
13814
14014
|
var WORKSPACE_VIEWS = [
|
|
@@ -13935,7 +14135,7 @@ ${reasons.map((entry, index) => `${index + 1}. ${entry.text}`).join("\n")}
|
|
|
13935
14135
|
}, []);
|
|
13936
14136
|
return { health, ledger, boundaries, busy, refreshHealth, refreshLedger, refreshBoundaries, finishOnboarding, rate, rerun };
|
|
13937
14137
|
}
|
|
13938
|
-
function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries, previewRun, startRun, terminalApi }) {
|
|
14138
|
+
function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOfficialInstallSettings, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries, previewRun, startRun, terminalApi }) {
|
|
13939
14139
|
const workbench = useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries });
|
|
13940
14140
|
const [catalogState, setCatalogState] = import_react5.default.useState({ status: "loading", catalog: null, error: "" });
|
|
13941
14141
|
const [task, setTask] = import_react5.default.useState("");
|
|
@@ -14157,6 +14357,7 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
14157
14357
|
OfficialToolsCard,
|
|
14158
14358
|
{
|
|
14159
14359
|
listOfficialTools,
|
|
14360
|
+
loadOfficialInstallSettings,
|
|
14160
14361
|
installOfficialTool,
|
|
14161
14362
|
uninstallOfficialTool,
|
|
14162
14363
|
repairOfficialTool,
|
|
@@ -14347,6 +14548,7 @@ var toolIdParameter = Object.freeze({
|
|
|
14347
14548
|
var jsonParameter = (name, codec) => Object.freeze({ name, wire: name, source: "json", codec });
|
|
14348
14549
|
var OFFICIAL_TOOLS_REMOTE_DESCRIPTORS = Object.freeze([
|
|
14349
14550
|
descriptor("list", [], listResultCodec),
|
|
14551
|
+
descriptor("installSettings", [], anyObjectCodec("OfficialInstallSettings")),
|
|
14350
14552
|
descriptor("installTool", [jsonParameter("request", toolActionCodec)], installResultCodec),
|
|
14351
14553
|
descriptor("uninstallTool", [jsonParameter("request", toolActionCodec)], installResultCodec),
|
|
14352
14554
|
descriptor("repairTool", [jsonParameter("request", toolActionCodec)], installResultCodec),
|
|
@@ -14670,12 +14872,12 @@ function RouterSettingsCard(props) {
|
|
|
14670
14872
|
), 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, `{
|
|
14671
14873
|
"kimi-code": { "quota": ["\u989D\u5EA6\u5DF2\u7528\u5B8C"], "rateLimit": ["\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41"] },
|
|
14672
14874
|
"my-glm-plan": { "quota": ["Usage limit reached for", "1308"] }
|
|
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 }, "\
|
|
14875
|
+
}`)), /* @__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(
|
|
14674
14876
|
import_dsh_client_ui_primitives.SettingsValueField,
|
|
14675
14877
|
{
|
|
14676
14878
|
id: "model-router-tool-install-dir",
|
|
14677
14879
|
label: "\u7EDF\u4E00\u5B89\u88C5\u76EE\u5F55",
|
|
14678
|
-
hint: "\u7559\u7A7A\
|
|
14880
|
+
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",
|
|
14679
14881
|
disabled,
|
|
14680
14882
|
...state.toolInstallDir,
|
|
14681
14883
|
overriddenLabel: FIELD_COPY.overridden,
|
|
@@ -14711,7 +14913,7 @@ function RouterSettingsCard(props) {
|
|
|
14711
14913
|
{
|
|
14712
14914
|
id: "model-router-tool-install-methods",
|
|
14713
14915
|
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\
|
|
14916
|
+
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",
|
|
14715
14917
|
disabled,
|
|
14716
14918
|
...state.toolInstallMethodsJson,
|
|
14717
14919
|
overriddenLabel: FIELD_COPY.overridden,
|
|
@@ -14770,6 +14972,7 @@ function registerUi(ctx) {
|
|
|
14770
14972
|
loadCatalog: () => ctx.remote.session.modelCatalog(),
|
|
14771
14973
|
settingsScope,
|
|
14772
14974
|
listOfficialTools: () => officialToolsRemote.list(),
|
|
14975
|
+
loadOfficialInstallSettings: () => officialToolsRemote.installSettings(),
|
|
14773
14976
|
installOfficialTool: (request) => officialToolsRemote.installTool(request),
|
|
14774
14977
|
uninstallOfficialTool: (request) => officialToolsRemote.uninstallTool(request),
|
|
14775
14978
|
repairOfficialTool: (request) => officialToolsRemote.repairTool(request),
|