@ljwei-stak/dsh-model-router 0.18.0 → 0.18.2
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 +201 -35
- package/.dsh-plugin/index.mjs +29 -7
- package/.dsh-plugin/official-tools-remote-service.mjs +15 -1
- package/.dsh-plugin/shared/official-tool-executor.mjs +6 -6
- package/.dsh-plugin/shared/official-tool-registry.mjs +18 -1
- package/.dsh-plugin/shared/official-tools-remote.mjs +1 -0
- package/.dsh-plugin/shared/official-tools-runtime.mjs +137 -12
- package/.dsh-plugin/shared/task-executors.mjs +52 -3
- package/.dsh-plugin/shared/tool-install-preferences.mjs +20 -1
- package/CHANGELOG.md +19 -0
- package/README.md +9 -5
- package/README.zh.md +9 -5
- package/docs/INSTALLATION_GUIDE.zh.md +12 -12
- package/docs/WORKBENCH_USER_GUIDE.zh.md +10 -8
- package/package.json +2 -2
package/.dsh-plugin/client.js
CHANGED
|
@@ -77,6 +77,8 @@ function scriptMethod(id2, label, {
|
|
|
77
77
|
scriptBinaryNames,
|
|
78
78
|
registryEnv,
|
|
79
79
|
installDirSubdir,
|
|
80
|
+
legacySharedInstallDir = false,
|
|
81
|
+
sharedDefaultBin = false,
|
|
80
82
|
uninstallUnsupportedReason,
|
|
81
83
|
scriptFallbackUrls
|
|
82
84
|
}) {
|
|
@@ -97,6 +99,8 @@ function scriptMethod(id2, label, {
|
|
|
97
99
|
installDirEnv,
|
|
98
100
|
installDirSuffix,
|
|
99
101
|
...installDirSubdir ? { installDirSubdir } : {},
|
|
102
|
+
...legacySharedInstallDir ? { legacySharedInstallDir: true } : {},
|
|
103
|
+
...sharedDefaultBin ? { sharedDefaultBin: true } : {},
|
|
100
104
|
...uninstallUnsupportedReason ? { uninstallUnsupportedReason } : {},
|
|
101
105
|
...defaultScriptInstallDir ? { defaultScriptInstallDir } : {},
|
|
102
106
|
...defaultScriptInstallDirEnv ? { defaultScriptInstallDirEnv } : {},
|
|
@@ -131,6 +135,8 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
131
135
|
supportsInstallDir: true,
|
|
132
136
|
installDirEnv: "KIMI_INSTALL_DIR",
|
|
133
137
|
installDirSuffix: "bin",
|
|
138
|
+
installDirSubdir: "kimi-code",
|
|
139
|
+
legacySharedInstallDir: true,
|
|
134
140
|
env: ["KIMI_INSTALL_DIR"],
|
|
135
141
|
scriptBinaryNames: ["kimi"],
|
|
136
142
|
verify: Object.freeze({ mustInclude: ["kimi-code", "code.kimi.com/kimi-code"] })
|
|
@@ -142,6 +148,8 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
142
148
|
supportsInstallDir: true,
|
|
143
149
|
installDirEnv: "KIMI_INSTALL_DIR",
|
|
144
150
|
installDirSuffix: "bin",
|
|
151
|
+
installDirSubdir: "kimi-code",
|
|
152
|
+
legacySharedInstallDir: true,
|
|
145
153
|
env: ["KIMI_INSTALL_DIR"],
|
|
146
154
|
scriptBinaryNames: ["kimi.exe"],
|
|
147
155
|
verify: Object.freeze({ mustInclude: ["kimi-code", "code.kimi.com/kimi-code"] })
|
|
@@ -174,6 +182,7 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
174
182
|
scriptFallbackUrls: ["https://downloads.claude.ai/claude-code-releases/bootstrap.sh"],
|
|
175
183
|
platforms: ["linux", "darwin"],
|
|
176
184
|
scriptBinaryNames: ["claude"],
|
|
185
|
+
sharedDefaultBin: true,
|
|
177
186
|
verify: Object.freeze({ mustInclude: ["downloads.claude.ai/claude-code-releases", "manifest.json"] })
|
|
178
187
|
}),
|
|
179
188
|
scriptMethod("script-powershell", "irm | iex", {
|
|
@@ -182,6 +191,7 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
182
191
|
scriptFallbackUrls: ["https://downloads.claude.ai/claude-code-releases/bootstrap.ps1"],
|
|
183
192
|
platforms: ["win32"],
|
|
184
193
|
scriptBinaryNames: ["claude.exe"],
|
|
194
|
+
sharedDefaultBin: true,
|
|
185
195
|
verify: Object.freeze({ mustInclude: ["downloads.claude.ai/claude-code-releases", "manifest.json"] })
|
|
186
196
|
})
|
|
187
197
|
])
|
|
@@ -210,6 +220,9 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
210
220
|
supportsInstallDir: true,
|
|
211
221
|
installDirEnv: "CODEX_INSTALL_DIR",
|
|
212
222
|
env: ["CODEX_INSTALL_DIR"],
|
|
223
|
+
installDirSubdir: "codex/bin",
|
|
224
|
+
legacySharedInstallDir: true,
|
|
225
|
+
sharedDefaultBin: true,
|
|
213
226
|
scriptBinaryNames: ["codex"],
|
|
214
227
|
verify: Object.freeze({ mustInclude: ["releases.openai.com/codex", "CODEX_INSTALL_DIR"] })
|
|
215
228
|
}),
|
|
@@ -259,6 +272,8 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
259
272
|
supportsInstallDir: true,
|
|
260
273
|
installDirEnv: "MCODE_INSTALL_DIR",
|
|
261
274
|
installDirSuffix: "bin",
|
|
275
|
+
installDirSubdir: "minimax-code",
|
|
276
|
+
legacySharedInstallDir: true,
|
|
262
277
|
registryEnv: "MCODE_NPM_REGISTRY",
|
|
263
278
|
env: ["MCODE_INSTALL_DIR", "MCODE_NPM_REGISTRY"],
|
|
264
279
|
verify: Object.freeze({ mustInclude: ["MiniMax Code CLI", "@minimax-ai/code"] })
|
|
@@ -269,6 +284,8 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
269
284
|
platforms: ["win32"],
|
|
270
285
|
supportsInstallDir: true,
|
|
271
286
|
installDirEnv: "MCODE_INSTALL_DIR",
|
|
287
|
+
installDirSubdir: "minimax-code",
|
|
288
|
+
legacySharedInstallDir: true,
|
|
272
289
|
registryEnv: "MCODE_NPM_REGISTRY",
|
|
273
290
|
env: ["MCODE_INSTALL_DIR", "MCODE_NPM_REGISTRY"],
|
|
274
291
|
defaultScriptInstallDir: ".minimax-code",
|
|
@@ -307,6 +324,8 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
307
324
|
supportsInstallDir: true,
|
|
308
325
|
installDirEnv: "MIMOCODE_INSTALL_DIR",
|
|
309
326
|
env: ["MIMOCODE_INSTALL_DIR"],
|
|
327
|
+
installDirSubdir: "mimo-code",
|
|
328
|
+
legacySharedInstallDir: true,
|
|
310
329
|
scriptBinaryNames: ["mimo.exe"],
|
|
311
330
|
verify: Object.freeze({ mustInclude: ["mimo.xiaomi.com", ".mimocode"] })
|
|
312
331
|
})
|
|
@@ -336,6 +355,8 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
336
355
|
supportsInstallDir: true,
|
|
337
356
|
installDirEnv: "GROK_BIN_DIR",
|
|
338
357
|
env: ["GROK_BIN_DIR"],
|
|
358
|
+
installDirSubdir: "grok-build",
|
|
359
|
+
legacySharedInstallDir: true,
|
|
339
360
|
scriptBinaryNames: ["grok", "agent"],
|
|
340
361
|
verify: Object.freeze({ mustInclude: ["Grok CLI installer", "x.ai/cli"] })
|
|
341
362
|
}),
|
|
@@ -346,6 +367,8 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
346
367
|
supportsInstallDir: true,
|
|
347
368
|
installDirEnv: "GROK_BIN_DIR",
|
|
348
369
|
env: ["GROK_BIN_DIR"],
|
|
370
|
+
installDirSubdir: "grok-build",
|
|
371
|
+
legacySharedInstallDir: true,
|
|
349
372
|
scriptBinaryNames: ["grok.exe", "agent.exe", "grove.exe", "grove-fsmonitor.exe", "grove-credential.exe"],
|
|
350
373
|
verify: Object.freeze({ mustInclude: ["Grok CLI installer", "x.ai/cli"] })
|
|
351
374
|
})
|
|
@@ -428,6 +451,10 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
428
451
|
installArg: ["--install-dir"],
|
|
429
452
|
env: ["STEP_INSTALL_DIR", "STEP_RELEASE_BASE_URL"],
|
|
430
453
|
supportsInstallDir: true,
|
|
454
|
+
// The installer replaces its runtime directories, including the entire
|
|
455
|
+
// node_modules tree on Windows. It must own a dedicated directory.
|
|
456
|
+
installDirSubdir: "stepcode",
|
|
457
|
+
legacySharedInstallDir: true,
|
|
431
458
|
verify: Object.freeze({
|
|
432
459
|
mustInclude: ["static-openapi.stepfun.com", "stepcode installer"],
|
|
433
460
|
mustNotInclude: ["anomalyco/opencode"]
|
|
@@ -440,6 +467,8 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
440
467
|
installArg: ["-InstallDir"],
|
|
441
468
|
env: ["STEP_INSTALL_DIR", "STEP_RELEASE_BASE_URL"],
|
|
442
469
|
supportsInstallDir: true,
|
|
470
|
+
installDirSubdir: "stepcode",
|
|
471
|
+
legacySharedInstallDir: true,
|
|
443
472
|
verify: Object.freeze({
|
|
444
473
|
mustInclude: ["static-openapi.stepfun.com", "stepcode"],
|
|
445
474
|
mustNotInclude: ["anomalyco/opencode"]
|
|
@@ -2348,6 +2377,65 @@ var INSTALL_DEFAULTS = Object.freeze({
|
|
|
2348
2377
|
toolScriptUrlsJson: "{}",
|
|
2349
2378
|
toolAllowScriptInstall: true
|
|
2350
2379
|
});
|
|
2380
|
+
function toolInstallSettingsSignature(value = {}) {
|
|
2381
|
+
try {
|
|
2382
|
+
const preferences = parseInstallPreferences({ ...value, toolInstallDir: "" }, { tools: OFFICIAL_TOOLS });
|
|
2383
|
+
const sorted = (map) => Object.entries(map).sort(([left], [right]) => left.localeCompare(right));
|
|
2384
|
+
return JSON.stringify([
|
|
2385
|
+
String(value.toolInstallDir ?? "").trim(),
|
|
2386
|
+
preferences.registry,
|
|
2387
|
+
sorted(preferences.methods),
|
|
2388
|
+
sorted(preferences.scriptUrls),
|
|
2389
|
+
preferences.allowScriptInstall
|
|
2390
|
+
]);
|
|
2391
|
+
} catch {
|
|
2392
|
+
return JSON.stringify([
|
|
2393
|
+
"invalid",
|
|
2394
|
+
value.toolInstallDir,
|
|
2395
|
+
value.toolNpmRegistry,
|
|
2396
|
+
value.toolInstallMethodsJson,
|
|
2397
|
+
value.toolScriptUrlsJson,
|
|
2398
|
+
value.toolAllowScriptInstall
|
|
2399
|
+
]);
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
function installSummaryMatchesSettings(summary, value) {
|
|
2403
|
+
if (!summary) return false;
|
|
2404
|
+
return toolInstallSettingsSignature(value) === toolInstallSettingsSignature({
|
|
2405
|
+
toolInstallDir: summary.requestedInstallDir ?? summary.installDir ?? "",
|
|
2406
|
+
toolNpmRegistry: summary.registry || DEFAULT_NPM_REGISTRY,
|
|
2407
|
+
toolInstallMethodsJson: JSON.stringify(summary.methods ?? {}),
|
|
2408
|
+
toolScriptUrlsJson: JSON.stringify(summary.scriptUrls ?? {}),
|
|
2409
|
+
toolAllowScriptInstall: summary.allowScriptInstall !== false
|
|
2410
|
+
});
|
|
2411
|
+
}
|
|
2412
|
+
function savedToolInstallMethods(value = {}) {
|
|
2413
|
+
try {
|
|
2414
|
+
return parseInstallPreferences({ toolInstallMethodsJson: value.toolInstallMethodsJson }, { tools: OFFICIAL_TOOLS }).methods;
|
|
2415
|
+
} catch {
|
|
2416
|
+
return {};
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
async function mutateToolInstallSettings(scope, operations, revision, { timeoutMs = 15e3, onSettled } = {}) {
|
|
2420
|
+
let timer;
|
|
2421
|
+
try {
|
|
2422
|
+
const writing = Promise.resolve().then(() => scope.mutate(operations, revision)).then((accepted) => {
|
|
2423
|
+
onSettled?.({ accepted });
|
|
2424
|
+
return accepted;
|
|
2425
|
+
}, (error) => {
|
|
2426
|
+
onSettled?.({ accepted: false, error });
|
|
2427
|
+
throw error;
|
|
2428
|
+
});
|
|
2429
|
+
return await Promise.race([
|
|
2430
|
+
writing,
|
|
2431
|
+
new Promise((_2, reject) => {
|
|
2432
|
+
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);
|
|
2433
|
+
})
|
|
2434
|
+
]);
|
|
2435
|
+
} finally {
|
|
2436
|
+
clearTimeout(timer);
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2351
2439
|
function validateToolInstallSetting(key, value) {
|
|
2352
2440
|
try {
|
|
2353
2441
|
parseInstallPreferences({ [key]: value }, { tools: OFFICIAL_TOOLS });
|
|
@@ -12645,7 +12733,7 @@ var xterm_default = `/**
|
|
|
12645
12733
|
`;
|
|
12646
12734
|
|
|
12647
12735
|
// .dsh-plugin/client/host-version.mjs
|
|
12648
|
-
var ROUTER_CLIENT_VERSION = true ? "0.18.
|
|
12736
|
+
var ROUTER_CLIENT_VERSION = true ? "0.18.2" : "";
|
|
12649
12737
|
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";
|
|
12650
12738
|
function isMissingRemoteMethod(message) {
|
|
12651
12739
|
const value = String(message ?? "");
|
|
@@ -13478,10 +13566,10 @@ function probeLabel(probe) {
|
|
|
13478
13566
|
var INSTALL_SETTING_FIELDS = [
|
|
13479
13567
|
{
|
|
13480
13568
|
key: "toolInstallDir",
|
|
13481
|
-
label: "\u7EDF\u4E00\u5B89\u88C5\u76EE\u5F55",
|
|
13569
|
+
label: "\u7EDF\u4E00\u5B89\u88C5\u6839\u76EE\u5F55",
|
|
13482
13570
|
fallback: "",
|
|
13483
13571
|
placeholder: "\u7559\u7A7A = \u5404\u5382\u5546\u9ED8\u8BA4\u76EE\u5F55",
|
|
13484
|
-
hint: "\
|
|
13572
|
+
hint: "\u4F8B\u5982 D:/AI/tools\u3002npm / pnpm \u4F7F\u7528\u8BE5\u6839\uFF1B\u5382\u5546\u811A\u672C\u4F7F\u7528\u5DE5\u5177\u4E13\u5C5E\u5B50\u76EE\u5F55\uFF0C\u5B9E\u9645\u5730\u5740\u89C1\u5DE5\u5177\u884C\u3002\u56FA\u5B9A\u5382\u5546\u5730\u5740\u7684\u65B9\u5F0F\u4F1A\u8BF4\u660E\u539F\u56E0\u3002"
|
|
13485
13573
|
},
|
|
13486
13574
|
{
|
|
13487
13575
|
key: "toolNpmRegistry",
|
|
@@ -13498,7 +13586,7 @@ var INSTALL_SETTING_FIELDS = [
|
|
|
13498
13586
|
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"
|
|
13499
13587
|
}
|
|
13500
13588
|
];
|
|
13501
|
-
function InstallSettings({ settingsScope, install, onPendingChange }) {
|
|
13589
|
+
function InstallSettings({ settingsScope, install, onPendingChange, onMutationStart }) {
|
|
13502
13590
|
const [snapshot, setSnapshot] = import_react5.default.useState(() => settingsScope?.getSnapshot?.() ?? { value: {}, writable: false });
|
|
13503
13591
|
const [drafts, setDrafts] = import_react5.default.useState({});
|
|
13504
13592
|
const [saving, setSaving] = import_react5.default.useState(false);
|
|
@@ -13535,7 +13623,12 @@ function InstallSettings({ settingsScope, install, onPendingChange }) {
|
|
|
13535
13623
|
setNotice("");
|
|
13536
13624
|
try {
|
|
13537
13625
|
const entries = Object.entries(drafts).map(([key, value]) => ({ op: "set", path: [key], value }));
|
|
13538
|
-
const
|
|
13626
|
+
const finishMutation = onMutationStart?.(entries);
|
|
13627
|
+
const onSettled = (outcome) => {
|
|
13628
|
+
const current = finishMutation?.(outcome);
|
|
13629
|
+
if (current && outcome.accepted) setNotice("\u5B89\u88C5\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002");
|
|
13630
|
+
};
|
|
13631
|
+
const accepted = await mutateToolInstallSettings(settingsScope, entries, snapshot.revision, { onSettled });
|
|
13539
13632
|
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");
|
|
13540
13633
|
const next = settingsScope.getSnapshot();
|
|
13541
13634
|
setSnapshot(next);
|
|
@@ -13575,7 +13668,7 @@ function InstallSettings({ settingsScope, install, onPendingChange }) {
|
|
|
13575
13668
|
onPendingChange?.(false);
|
|
13576
13669
|
} }, "\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}` : ""));
|
|
13577
13670
|
}
|
|
13578
|
-
function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes, health, onRefreshHealth, settingsScope }) {
|
|
13671
|
+
function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes, health, onRefreshHealth, settingsScope }) {
|
|
13579
13672
|
const healthById = Object.fromEntries((health?.tools ?? []).map((item) => [item.id, item]));
|
|
13580
13673
|
const [probeState, setProbeState] = import_react5.default.useState({ status: "loading", probes: [], capabilities: [], readiness: [], install: null, error: "" });
|
|
13581
13674
|
const [jobs, setJobs] = import_react5.default.useState({});
|
|
@@ -13583,12 +13676,17 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13583
13676
|
const [settingsPending, setSettingsPending] = import_react5.default.useState(false);
|
|
13584
13677
|
const [methodSaving, setMethodSaving] = import_react5.default.useState(null);
|
|
13585
13678
|
const [previewPending, setPreviewPending] = import_react5.default.useState(false);
|
|
13586
|
-
const [
|
|
13679
|
+
const [settingsSnapshot, setSettingsSnapshot] = import_react5.default.useState(() => settingsScope?.getSnapshot?.() ?? { value: {}, writable: false });
|
|
13680
|
+
const [previewError, setPreviewError] = import_react5.default.useState("");
|
|
13681
|
+
const [probeSettingsStale, setProbeSettingsStale] = import_react5.default.useState(false);
|
|
13587
13682
|
const settingsPendingRef = import_react5.default.useRef(false);
|
|
13588
13683
|
const methodSavingRef = import_react5.default.useRef(null);
|
|
13589
13684
|
const previewPendingRef = import_react5.default.useRef(false);
|
|
13590
13685
|
const mounted = import_react5.default.useRef(false);
|
|
13591
13686
|
const request = import_react5.default.useRef(0);
|
|
13687
|
+
const previewRequest = import_react5.default.useRef(0);
|
|
13688
|
+
const mutationGeneration = import_react5.default.useRef(0);
|
|
13689
|
+
const mutationPendingRef = import_react5.default.useRef(null);
|
|
13592
13690
|
const submitting = import_react5.default.useRef(/* @__PURE__ */ new Set());
|
|
13593
13691
|
const polling = import_react5.default.useRef(/* @__PURE__ */ new Set());
|
|
13594
13692
|
const jobsRef = import_react5.default.useRef({});
|
|
@@ -13606,29 +13704,46 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13606
13704
|
const refresh = async () => {
|
|
13607
13705
|
onRefreshHealth?.();
|
|
13608
13706
|
const current = ++request.current;
|
|
13707
|
+
const settingsSignature = toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value);
|
|
13609
13708
|
setProbeState((previous) => ({
|
|
13610
13709
|
...previous,
|
|
13611
|
-
status: previous.probes.length > 0 ? "refreshing" : "loading",
|
|
13710
|
+
status: previous.probes.length > 0 || previous.install ? "refreshing" : "loading",
|
|
13612
13711
|
error: ""
|
|
13613
13712
|
}));
|
|
13614
13713
|
try {
|
|
13615
13714
|
if (typeof listOfficialTools !== "function") throw new Error("\u5B98\u65B9\u5DE5\u5177\u5B89\u88C5\u6865\u5C1A\u672A\u52A0\u8F7D\u3002");
|
|
13616
13715
|
const response = await listOfficialTools();
|
|
13617
13716
|
if (!mounted.current || current !== request.current) return;
|
|
13717
|
+
if (settingsSignature !== toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value)) return;
|
|
13618
13718
|
if (!response?.ok) throw new Error(remoteError(response, "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002"));
|
|
13619
13719
|
const probes = Array.isArray(response.value?.tools) ? response.value.tools : [];
|
|
13620
13720
|
const capabilities = Array.isArray(response.value?.executionCapabilities) ? response.value.executionCapabilities : [];
|
|
13621
13721
|
const readiness = Array.isArray(response.value?.executionReadiness) ? response.value.executionReadiness : [];
|
|
13622
|
-
|
|
13623
|
-
|
|
13624
|
-
|
|
13722
|
+
const install2 = response.value?.install;
|
|
13723
|
+
const matches = settingsSignature === toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value) && installSummaryMatchesSettings(install2, settingsScope?.getSnapshot?.()?.value);
|
|
13724
|
+
if (!matches) return;
|
|
13725
|
+
setProbeState((previous) => ({
|
|
13726
|
+
status: "ready",
|
|
13727
|
+
probes,
|
|
13728
|
+
capabilities,
|
|
13729
|
+
readiness,
|
|
13730
|
+
install: matches ? install2 : previous.install,
|
|
13731
|
+
error: ""
|
|
13732
|
+
}));
|
|
13733
|
+
setProbeSettingsStale(false);
|
|
13734
|
+
if (matches && !mutationPendingRef.current) {
|
|
13735
|
+
previewPendingRef.current = false;
|
|
13736
|
+
setPreviewPending(false);
|
|
13737
|
+
setPreviewError("");
|
|
13738
|
+
}
|
|
13625
13739
|
onProbes({ probes, capabilities, readiness, hostVersion: typeof response.value?.hostVersion === "string" ? response.value.hostVersion : null });
|
|
13626
13740
|
} catch (error) {
|
|
13627
13741
|
if (!mounted.current || current !== request.current) return;
|
|
13742
|
+
if (settingsSignature !== toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value)) return;
|
|
13628
13743
|
const message = remoteErrorText(text5(error?.message), "\u65E0\u6CD5\u68C0\u6D4B\u5B98\u65B9\u5DE5\u5177\u3002");
|
|
13629
13744
|
let kept = false;
|
|
13630
13745
|
setProbeState((previous) => {
|
|
13631
|
-
if (previous.probes.length > 0) {
|
|
13746
|
+
if (previous.probes.length > 0 || previous.install) {
|
|
13632
13747
|
kept = true;
|
|
13633
13748
|
return { ...previous, status: "ready", error: message };
|
|
13634
13749
|
}
|
|
@@ -13637,9 +13752,38 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13637
13752
|
if (!kept) onProbes({ probes: [], capabilities: [], readiness: [] });
|
|
13638
13753
|
}
|
|
13639
13754
|
};
|
|
13755
|
+
const refreshInstallSettings = async () => {
|
|
13756
|
+
const current = ++previewRequest.current;
|
|
13757
|
+
const snapshot = settingsScope?.getSnapshot?.();
|
|
13758
|
+
const signature2 = toolInstallSettingsSignature(snapshot?.value);
|
|
13759
|
+
previewPendingRef.current = true;
|
|
13760
|
+
setPreviewPending(true);
|
|
13761
|
+
setPreviewError("");
|
|
13762
|
+
try {
|
|
13763
|
+
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");
|
|
13764
|
+
const response = await loadOfficialInstallSettings();
|
|
13765
|
+
if (!mounted.current || current !== previewRequest.current || signature2 !== toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value)) return;
|
|
13766
|
+
if (!response?.ok) throw new Error(remoteError(response, "\u65E0\u6CD5\u8BFB\u53D6\u5B89\u88C5\u8BBE\u7F6E\u3002"));
|
|
13767
|
+
if (!installSummaryMatchesSettings(response.value?.install, settingsScope?.getSnapshot?.()?.value)) {
|
|
13768
|
+
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");
|
|
13769
|
+
}
|
|
13770
|
+
setProbeState((previous) => ({
|
|
13771
|
+
...previous,
|
|
13772
|
+
status: previous.status === "loading" || previous.status === "error" ? "ready" : previous.status,
|
|
13773
|
+
install: response.value.install
|
|
13774
|
+
}));
|
|
13775
|
+
if (!mutationPendingRef.current) {
|
|
13776
|
+
previewPendingRef.current = false;
|
|
13777
|
+
setPreviewPending(false);
|
|
13778
|
+
}
|
|
13779
|
+
} catch (error) {
|
|
13780
|
+
if (mounted.current && current === previewRequest.current) setPreviewError(text5(error?.message) || "\u5B89\u88C5\u547D\u4EE4\u5237\u65B0\u5931\u8D25\u3002");
|
|
13781
|
+
}
|
|
13782
|
+
};
|
|
13640
13783
|
import_react5.default.useEffect(() => {
|
|
13641
13784
|
mounted.current = true;
|
|
13642
13785
|
void refresh();
|
|
13786
|
+
void refreshInstallSettings();
|
|
13643
13787
|
if (typeof officialToolInstallStatus === "function") {
|
|
13644
13788
|
void Promise.all(OFFICIAL_TOOLS.map(async (tool) => {
|
|
13645
13789
|
try {
|
|
@@ -13664,29 +13808,40 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13664
13808
|
return () => {
|
|
13665
13809
|
mounted.current = false;
|
|
13666
13810
|
request.current += 1;
|
|
13811
|
+
previewRequest.current += 1;
|
|
13812
|
+
};
|
|
13813
|
+
}, []);
|
|
13814
|
+
const refreshInstallSettingsRef = import_react5.default.useRef(refreshInstallSettings);
|
|
13815
|
+
refreshInstallSettingsRef.current = refreshInstallSettings;
|
|
13816
|
+
const beginSettingsMutation = import_react5.default.useCallback((operations) => {
|
|
13817
|
+
const generation = ++mutationGeneration.current;
|
|
13818
|
+
mutationPendingRef.current = { generation, operations };
|
|
13819
|
+
previewPendingRef.current = true;
|
|
13820
|
+
setPreviewPending(true);
|
|
13821
|
+
return () => {
|
|
13822
|
+
if (!mounted.current || mutationPendingRef.current?.generation !== generation) return false;
|
|
13823
|
+
mutationPendingRef.current = null;
|
|
13824
|
+
void refreshInstallSettingsRef.current();
|
|
13825
|
+
return true;
|
|
13667
13826
|
};
|
|
13668
13827
|
}, []);
|
|
13669
|
-
const refreshRef = import_react5.default.useRef(refresh);
|
|
13670
|
-
refreshRef.current = refresh;
|
|
13671
13828
|
import_react5.default.useEffect(() => {
|
|
13672
13829
|
if (typeof settingsScope?.subscribe !== "function") return void 0;
|
|
13673
|
-
const signature2 = (snapshot) =>
|
|
13674
|
-
snapshot?.value?.toolInstallDir,
|
|
13675
|
-
snapshot?.value?.toolNpmRegistry,
|
|
13676
|
-
snapshot?.value?.toolInstallMethodsJson,
|
|
13677
|
-
snapshot?.value?.toolScriptUrlsJson,
|
|
13678
|
-
snapshot?.value?.toolAllowScriptInstall
|
|
13679
|
-
]);
|
|
13830
|
+
const signature2 = (snapshot) => toolInstallSettingsSignature(snapshot?.value);
|
|
13680
13831
|
let previous = signature2(settingsScope.getSnapshot());
|
|
13681
13832
|
return settingsScope.subscribe(() => {
|
|
13682
13833
|
const snapshot = settingsScope.getSnapshot();
|
|
13683
|
-
|
|
13834
|
+
setSettingsSnapshot(snapshot);
|
|
13684
13835
|
const next = signature2(snapshot);
|
|
13685
13836
|
if (next === previous) return;
|
|
13686
13837
|
previous = next;
|
|
13838
|
+
request.current += 1;
|
|
13839
|
+
setProbeSettingsStale(true);
|
|
13840
|
+
setProbeState((previous2) => ({ ...previous2, status: "ready", probes: [], readiness: [], error: "" }));
|
|
13841
|
+
onProbes({ probes: [], capabilities: [], readiness: [] });
|
|
13687
13842
|
previewPendingRef.current = true;
|
|
13688
13843
|
setPreviewPending(true);
|
|
13689
|
-
void
|
|
13844
|
+
void refreshInstallSettingsRef.current();
|
|
13690
13845
|
});
|
|
13691
13846
|
}, [settingsScope]);
|
|
13692
13847
|
import_react5.default.useEffect(() => {
|
|
@@ -13797,11 +13952,14 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13797
13952
|
if (methodId) map[toolId] = methodId;
|
|
13798
13953
|
else delete map[toolId];
|
|
13799
13954
|
try {
|
|
13800
|
-
const
|
|
13955
|
+
const operations = [{ op: "set", path: ["toolInstallMethodsJson"], value: JSON.stringify(map) }];
|
|
13956
|
+
const finishMutation = beginSettingsMutation(operations);
|
|
13957
|
+
const onSettled = (outcome) => {
|
|
13958
|
+
if (finishMutation(outcome) && outcome.accepted) setRowErrors((previous) => ({ ...previous, [toolId]: "" }));
|
|
13959
|
+
};
|
|
13960
|
+
const accepted = await mutateToolInstallSettings(settingsScope, operations, snapshot.revision, { onSettled });
|
|
13801
13961
|
if (!accepted) throw new Error("\u5B89\u88C5\u65B9\u5F0F\u672A\u88AB\u4FDD\u5B58\uFF0C\u53EF\u80FD\u88AB\u5176\u4ED6\u9875\u9762\u4FEE\u6539\u3002");
|
|
13802
|
-
|
|
13803
|
-
setPreviewPending(true);
|
|
13804
|
-
await refresh();
|
|
13962
|
+
setSettingsSnapshot(settingsScope.getSnapshot());
|
|
13805
13963
|
} catch (error) {
|
|
13806
13964
|
if (mounted.current) setRowErrors((previous) => ({ ...previous, [toolId]: text5(error?.message) || "\u5B89\u88C5\u65B9\u5F0F\u4FDD\u5B58\u5931\u8D25\u3002" }));
|
|
13807
13965
|
} finally {
|
|
@@ -13826,9 +13984,14 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13826
13984
|
const capabilitiesById = Object.fromEntries(probeState.capabilities.map((item) => [item.id, item]));
|
|
13827
13985
|
const readinessById = Object.fromEntries(probeState.readiness.map((item) => [item.id, item]));
|
|
13828
13986
|
const installById = Object.fromEntries((probeState.install?.tools ?? []).map((item) => [item.id, item]));
|
|
13987
|
+
const savedMethods = savedToolInstallMethods(settingsSnapshot.value);
|
|
13829
13988
|
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: () => {
|
|
13830
13989
|
void refresh();
|
|
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\
|
|
13990
|
+
} }, "\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: () => {
|
|
13991
|
+
void refreshInstallSettings();
|
|
13992
|
+
} }, "\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: () => {
|
|
13993
|
+
void refreshInstallSettings();
|
|
13994
|
+
} }, "\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) => {
|
|
13832
13995
|
const summary = installById[tool.id];
|
|
13833
13996
|
const command = summary ? summary.command : installCommandLine(tool);
|
|
13834
13997
|
const updateCommand = summary?.updateCommand ?? command;
|
|
@@ -13850,15 +14013,15 @@ function OfficialToolsCard({ listOfficialTools, installOfficialTool, uninstallOf
|
|
|
13850
14013
|
removable: !(summary?.uninstallError ?? (summary?.uninstallCommand ? "" : summary?.error))
|
|
13851
14014
|
}
|
|
13852
14015
|
});
|
|
13853
|
-
const verified = job?.status === "succeeded" && (job.operation === "uninstall" ? job.postInstallProbe?.installed === false : job.postInstallProbe?.installed === true);
|
|
14016
|
+
const verified = Boolean(probe) && job?.status === "succeeded" && (job.operation === "uninstall" ? job.postInstallProbe?.installed === false : job.postInstallProbe?.installed === true);
|
|
13854
14017
|
const operation = job?.operation === "uninstall" ? "\u5378\u8F7D" : job?.operation === "repair" ? "\u4FEE\u590D" : "\u5B89\u88C5";
|
|
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);
|
|
14018
|
+
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";
|
|
13856
14019
|
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(
|
|
13857
14020
|
"select",
|
|
13858
14021
|
{
|
|
13859
14022
|
className: "mr-mini-select",
|
|
13860
|
-
value:
|
|
13861
|
-
disabled: running ||
|
|
14023
|
+
value: savedMethods[tool.id] ?? "",
|
|
14024
|
+
disabled: running || settingsPending || Boolean(methodSaving) || settingsSnapshot.writable !== true,
|
|
13862
14025
|
onChange: (event) => {
|
|
13863
14026
|
void setInstallMethod(tool.id, event.target.value);
|
|
13864
14027
|
}
|
|
@@ -14001,7 +14164,7 @@ ${reasons.map((entry, index) => `${index + 1}. ${entry.text}`).join("\n")}
|
|
|
14001
14164
|
}, []);
|
|
14002
14165
|
return { health, ledger, boundaries, busy, refreshHealth, refreshLedger, refreshBoundaries, finishOnboarding, rate, rerun };
|
|
14003
14166
|
}
|
|
14004
|
-
function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries, previewRun, startRun, terminalApi }) {
|
|
14167
|
+
function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOfficialInstallSettings, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries, previewRun, startRun, terminalApi }) {
|
|
14005
14168
|
const workbench = useWorkbenchData({ toolHealth, completeOnboarding, loadLedger, rateResult, rerunStep, loadBoundaries });
|
|
14006
14169
|
const [catalogState, setCatalogState] = import_react5.default.useState({ status: "loading", catalog: null, error: "" });
|
|
14007
14170
|
const [task, setTask] = import_react5.default.useState("");
|
|
@@ -14223,6 +14386,7 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, install
|
|
|
14223
14386
|
OfficialToolsCard,
|
|
14224
14387
|
{
|
|
14225
14388
|
listOfficialTools,
|
|
14389
|
+
loadOfficialInstallSettings,
|
|
14226
14390
|
installOfficialTool,
|
|
14227
14391
|
uninstallOfficialTool,
|
|
14228
14392
|
repairOfficialTool,
|
|
@@ -14413,6 +14577,7 @@ var toolIdParameter = Object.freeze({
|
|
|
14413
14577
|
var jsonParameter = (name, codec) => Object.freeze({ name, wire: name, source: "json", codec });
|
|
14414
14578
|
var OFFICIAL_TOOLS_REMOTE_DESCRIPTORS = Object.freeze([
|
|
14415
14579
|
descriptor("list", [], listResultCodec),
|
|
14580
|
+
descriptor("installSettings", [], anyObjectCodec("OfficialInstallSettings")),
|
|
14416
14581
|
descriptor("installTool", [jsonParameter("request", toolActionCodec)], installResultCodec),
|
|
14417
14582
|
descriptor("uninstallTool", [jsonParameter("request", toolActionCodec)], installResultCodec),
|
|
14418
14583
|
descriptor("repairTool", [jsonParameter("request", toolActionCodec)], installResultCodec),
|
|
@@ -14740,8 +14905,8 @@ function RouterSettingsCard(props) {
|
|
|
14740
14905
|
import_dsh_client_ui_primitives.SettingsValueField,
|
|
14741
14906
|
{
|
|
14742
14907
|
id: "model-router-tool-install-dir",
|
|
14743
|
-
label: "\u7EDF\u4E00\u5B89\u88C5\u76EE\u5F55",
|
|
14744
|
-
hint: "\u586B\u5199\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u7559\u7A7A\u4F7F\u7528\u5382\u5546\u9ED8\u8BA4\u4F4D\u7F6E\u3002npm / pnpm \
|
|
14908
|
+
label: "\u7EDF\u4E00\u5B89\u88C5\u6839\u76EE\u5F55",
|
|
14909
|
+
hint: "\u586B\u5199\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u7559\u7A7A\u4F7F\u7528\u5382\u5546\u9ED8\u8BA4\u4F4D\u7F6E\u3002npm / pnpm \u5171\u7528\u8BE5\u6839\uFF1B\u53EF\u914D\u7F6E\u5382\u5546\u811A\u672C\u4F7F\u7528\u5DE5\u5177\u4E13\u5C5E\u5B50\u76EE\u5F55\uFF0C\u5B9E\u9645\u4F4D\u7F6E\u89C1\u5B98\u65B9\u5DE5\u5177\u9875\u3002\u66F4\u65B0\u590D\u7528\u6240\u9009\u65B9\u5F0F\u3001\u76EE\u5F55\u4E0E\u4E0B\u8F7D\u6E90\u3002",
|
|
14745
14910
|
disabled,
|
|
14746
14911
|
...state.toolInstallDir,
|
|
14747
14912
|
overriddenLabel: FIELD_COPY.overridden,
|
|
@@ -14836,6 +15001,7 @@ function registerUi(ctx) {
|
|
|
14836
15001
|
loadCatalog: () => ctx.remote.session.modelCatalog(),
|
|
14837
15002
|
settingsScope,
|
|
14838
15003
|
listOfficialTools: () => officialToolsRemote.list(),
|
|
15004
|
+
loadOfficialInstallSettings: () => officialToolsRemote.installSettings(),
|
|
14839
15005
|
installOfficialTool: (request) => officialToolsRemote.installTool(request),
|
|
14840
15006
|
uninstallOfficialTool: (request) => officialToolsRemote.uninstallTool(request),
|
|
14841
15007
|
repairOfficialTool: (request) => officialToolsRemote.repairTool(request),
|
package/.dsh-plugin/index.mjs
CHANGED
|
@@ -1434,11 +1434,25 @@ export function routerRemoteServices(ctx, config, { terminals = null } = {}) {
|
|
|
1434
1434
|
/** Register model-facing tools and the human /router command. */
|
|
1435
1435
|
export function apply(ctx, config = {}) {
|
|
1436
1436
|
// Install addresses (directory, npm source, per-tool method and script source)
|
|
1437
|
-
//
|
|
1438
|
-
//
|
|
1437
|
+
// are volatile refs: Loader changes them without re-applying the plugin.
|
|
1438
|
+
// Read them after the owning fiber's live update, before a saved view is sent.
|
|
1439
1439
|
let installPreferenceError = null
|
|
1440
|
-
|
|
1441
|
-
|
|
1440
|
+
const syncInstallPreferences = () => {
|
|
1441
|
+
try {
|
|
1442
|
+
const next = parseInstallPreferences(config, { tools: OFFICIAL_TOOLS, ...currentInstallOptions() })
|
|
1443
|
+
setInstallPreferences(next)
|
|
1444
|
+
installPreferenceError = null
|
|
1445
|
+
} catch (error) { installPreferenceError = errorText(error) }
|
|
1446
|
+
}
|
|
1447
|
+
const installFields = new Set(['toolInstallDir', 'toolNpmRegistry', 'toolInstallMethodsJson', 'toolScriptUrlsJson', 'toolAllowScriptInstall'])
|
|
1448
|
+
syncInstallPreferences()
|
|
1449
|
+
// Loader scopes this event to the fiber whose refs were committed.
|
|
1450
|
+
ctx.on('loader/volatile-update', paths => {
|
|
1451
|
+
if (Array.isArray(paths) && paths.some(path => installFields.has(path?.[0]))) syncInstallPreferences()
|
|
1452
|
+
})
|
|
1453
|
+
const assertInstallPreferences = () => {
|
|
1454
|
+
if (installPreferenceError) throw new Error(`官方工具安装设置无效:${installPreferenceError}`)
|
|
1455
|
+
}
|
|
1442
1456
|
// The official Host injects typert; direct lightweight uses of apply may
|
|
1443
1457
|
// supply only the model/command services and do not expose the Desktop RPC.
|
|
1444
1458
|
if (ctx.typert) {
|
|
@@ -1449,7 +1463,11 @@ export function apply(ctx, config = {}) {
|
|
|
1449
1463
|
process.once('exit', onExit)
|
|
1450
1464
|
return () => { process.off('exit', onExit); terminals.disposeAll('dispose') }
|
|
1451
1465
|
}, 'model-router-galgame: interactive terminals')
|
|
1452
|
-
registerOfficialToolsRemote(ctx,
|
|
1466
|
+
registerOfficialToolsRemote(ctx, {
|
|
1467
|
+
...routerRemoteServices(ctx, config, { terminals }),
|
|
1468
|
+
installSettingsError: () => installPreferenceError,
|
|
1469
|
+
installRequestedDirectory: () => valueOf(config, 'toolInstallDir', ''),
|
|
1470
|
+
})
|
|
1453
1471
|
}
|
|
1454
1472
|
ctx.on('tools/pre-execute', async (exec, next) => {
|
|
1455
1473
|
const decision = await next()
|
|
@@ -1498,7 +1516,7 @@ export function apply(ctx, config = {}) {
|
|
|
1498
1516
|
if (reasons.length) return combinedAsk(reasons)
|
|
1499
1517
|
return decision
|
|
1500
1518
|
})
|
|
1501
|
-
registerOfficialToolModels(ctx, config)
|
|
1519
|
+
registerOfficialToolModels(ctx, config, assertInstallPreferences)
|
|
1502
1520
|
ctx.tools.register(defineTool({
|
|
1503
1521
|
name: 'model_router_routes',
|
|
1504
1522
|
description: 'List provider/model routes registered in the official DeepSeek Harness model directory. Credential and network availability are not verified. No API keys or endpoints are returned.',
|
|
@@ -1611,6 +1629,7 @@ export function apply(ctx, config = {}) {
|
|
|
1611
1629
|
const toolId = matched[2]
|
|
1612
1630
|
const method = matched[3]
|
|
1613
1631
|
try {
|
|
1632
|
+
assertInstallPreferences()
|
|
1614
1633
|
const job = action === 'uninstall' ? startUninstall(toolId, { method })
|
|
1615
1634
|
: action === 'repair' ? startRepair(toolId, { method })
|
|
1616
1635
|
: startInstall(toolId, { method })
|
|
@@ -1649,7 +1668,7 @@ async function waitForInstall(toolId, signal) {
|
|
|
1649
1668
|
}
|
|
1650
1669
|
|
|
1651
1670
|
/** Register the model-facing official-tool probes and installer. */
|
|
1652
|
-
function registerOfficialToolModels(ctx, config) {
|
|
1671
|
+
function registerOfficialToolModels(ctx, config, assertInstallPreferences) {
|
|
1653
1672
|
ctx.tools.register(defineTool({
|
|
1654
1673
|
name: 'model_router_tools',
|
|
1655
1674
|
description: 'Probe the fixed registry of official model tools (Kimi Code, Claude Code, Codex, MiniMax Code, MiMo Code, Grok Build, Gemini CLI, OpenCode, Step Code, ZCode) and report which are installed with their versions, plus each tool\'s available install methods and the effective install directory and npm source. Never reads credentials.',
|
|
@@ -1680,6 +1699,7 @@ function registerOfficialToolModels(ctx, config) {
|
|
|
1680
1699
|
},
|
|
1681
1700
|
output: JSON_OUTPUT,
|
|
1682
1701
|
async execute(args, exec) {
|
|
1702
|
+
assertInstallPreferences()
|
|
1683
1703
|
const job = startInstall(args.tool, { method: text(args.method) || undefined })
|
|
1684
1704
|
const settled = await waitForInstall(job.tool, exec.signal)
|
|
1685
1705
|
const tool = getOfficialTool(args.tool)
|
|
@@ -1704,6 +1724,7 @@ function registerOfficialToolModels(ctx, config) {
|
|
|
1704
1724
|
},
|
|
1705
1725
|
output: JSON_OUTPUT,
|
|
1706
1726
|
async execute(args, exec) {
|
|
1727
|
+
assertInstallPreferences()
|
|
1707
1728
|
const job = startRepair(args.tool, { method: text(args.method) || undefined })
|
|
1708
1729
|
const settled = await waitForInstall(job.tool, exec.signal)
|
|
1709
1730
|
const tool = getOfficialTool(args.tool)
|
|
@@ -1726,6 +1747,7 @@ function registerOfficialToolModels(ctx, config) {
|
|
|
1726
1747
|
},
|
|
1727
1748
|
output: JSON_OUTPUT,
|
|
1728
1749
|
async execute(args, exec) {
|
|
1750
|
+
assertInstallPreferences()
|
|
1729
1751
|
const job = startUninstall(args.tool, { method: text(args.method) || undefined })
|
|
1730
1752
|
const settled = await waitForInstall(job.tool, exec.signal)
|
|
1731
1753
|
const tool = getOfficialTool(args.tool)
|