@ljwei-stak/dsh-model-router 0.18.2 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dsh-plugin/client.js +177 -39
- package/.dsh-plugin/index.mjs +14 -7
- package/.dsh-plugin/official-tools-remote-service.mjs +7 -3
- package/.dsh-plugin/shared/cli-terminal-protocol.mjs +15 -5
- package/.dsh-plugin/shared/cli-terminal.mjs +126 -18
- package/.dsh-plugin/shared/official-tool-executor.mjs +1 -1
- package/.dsh-plugin/shared/official-tool-registry.mjs +2 -2
- package/.dsh-plugin/shared/official-tools-runtime.mjs +33 -13
- package/.dsh-plugin/shared/tool-install-preferences.mjs +22 -0
- package/.dsh-plugin/shared/zcode-bundle.mjs +29 -8
- package/.dsh-plugin/shared/zcode-installer.mjs +2 -2
- package/CHANGELOG.md +11 -0
- package/README.md +8 -6
- package/README.zh.md +7 -5
- package/docs/INSTALLATION_GUIDE.zh.md +6 -6
- package/docs/WORKBENCH_USER_GUIDE.zh.md +4 -0
- package/package.json +2 -2
package/.dsh-plugin/client.js
CHANGED
|
@@ -480,12 +480,12 @@ var OFFICIAL_TOOLS = Object.freeze([
|
|
|
480
480
|
id: "zcode",
|
|
481
481
|
label: "ZCode",
|
|
482
482
|
vendor: "Z.ai",
|
|
483
|
-
purpose: "\u667A\u8C31\u5B98\u65B9 ZCode \u684C\u9762\u7248\uFF0C\u5185\u542B GLM \
|
|
483
|
+
purpose: "\u667A\u8C31\u5B98\u65B9 ZCode \u684C\u9762\u7248\uFF0C\u5185\u542B\u53EF\u72EC\u7ACB\u8FD0\u884C\u7684 GLM CLI/TUI\u3002\u53EF\u5355\u72EC\u914D\u7F6E\u684C\u9762\u76EE\u5F55\uFF0C\u5185\u7F6E CLI \u968F\u684C\u9762\u7248\u66F4\u65B0\u3002",
|
|
484
484
|
manager: "signed-windows-installer",
|
|
485
485
|
installArgs: [],
|
|
486
486
|
uninstallArgs: [],
|
|
487
487
|
probeExecutables: [],
|
|
488
|
-
probeNote: "\u68C0\u6D4B\u7ECF\u8FC7\u6709\u6548\u7B7E\u540D\u7684 ZCode.exe \u548C\u540C\u76EE\u5F55 GLM \u8D44\u6E90\uFF1B\u684C\u9762\u5B89\u88C5\u5668\u9700\u4EBA\u5DE5\u9009\u62E9\u5B89\u88C5\u4F4D\u7F6E\u3002",
|
|
488
|
+
probeNote: "\u68C0\u6D4B\u7ECF\u8FC7\u6709\u6548\u7B7E\u540D\u7684 ZCode.exe \u548C\u540C\u76EE\u5F55 GLM CLI/TUI \u8D44\u6E90\uFF1B\u684C\u9762\u5B89\u88C5\u5668\u9700\u4EBA\u5DE5\u9009\u62E9\u5B89\u88C5\u4F4D\u7F6E\u3002",
|
|
489
489
|
providerHints: ["zai", "z.ai", "zcode", "glm", "zhipu", "bigmodel"]
|
|
490
490
|
})
|
|
491
491
|
]);
|
|
@@ -813,6 +813,25 @@ function expandInstallDir(value, { home = "", env = {} } = {}) {
|
|
|
813
813
|
if (/^\\\\[^\\]+\\[^\\]+$/.test(withoutTrailing)) throw new Error("\u5B89\u88C5\u76EE\u5F55\u4E0D\u80FD\u662F\u7F51\u7EDC\u5171\u4EAB\u6839\u76EE\u5F55\u3002");
|
|
814
814
|
return expanded;
|
|
815
815
|
}
|
|
816
|
+
function normalizeZCodeInstallDir(value, options = {}) {
|
|
817
|
+
const input = String(value ?? "");
|
|
818
|
+
if (/[\x00-\x1f]/.test(input)) throw new Error("ZCode \u5B89\u88C5\u4F4D\u7F6E\u5305\u542B\u65E0\u6548\u5B57\u7B26\u3002");
|
|
819
|
+
const raw = input.trim().replace(/^"(.*)"$/, "$1");
|
|
820
|
+
if (!raw) return "";
|
|
821
|
+
let path;
|
|
822
|
+
try {
|
|
823
|
+
path = expandInstallDir(raw, options);
|
|
824
|
+
} catch (error) {
|
|
825
|
+
throw new Error(`ZCode \u5B89\u88C5\u4F4D\u7F6E\u65E0\u6548\uFF1A${error.message}`);
|
|
826
|
+
}
|
|
827
|
+
if (!/^[A-Za-z]:[\\/]/.test(path)) {
|
|
828
|
+
throw new Error("ZCode \u5B89\u88C5\u4F4D\u7F6E\u5FC5\u987B\u662F Windows \u672C\u5730\u7EDD\u5BF9\u76EE\u5F55\u6216 ZCode.exe \u8DEF\u5F84\u3002");
|
|
829
|
+
}
|
|
830
|
+
if (/\.exe[\\/]*$/i.test(path) && !/[\\/]ZCode\.exe[\\/]*$/i.test(path)) {
|
|
831
|
+
throw new Error("ZCode \u7A0B\u5E8F\u8DEF\u5F84\u5FC5\u987B\u6307\u5411\u5B98\u65B9 ZCode.exe\u3002");
|
|
832
|
+
}
|
|
833
|
+
return path.replace(/[\\/]+$/, "");
|
|
834
|
+
}
|
|
816
835
|
function normalizeSourceUrl(value, subject) {
|
|
817
836
|
const raw = String(value ?? "").trim();
|
|
818
837
|
if (!raw) return "";
|
|
@@ -856,6 +875,7 @@ function keepKnownToolIds(raw, known, subject) {
|
|
|
856
875
|
function parseInstallPreferences(config = {}, { tools = [], home = "", env = {} } = {}) {
|
|
857
876
|
const known = new Set(tools.map((tool) => tool.id));
|
|
858
877
|
const installDir = expandInstallDir(valueOf(config, "toolInstallDir", ""), { home, env });
|
|
878
|
+
const zcodeInstallDir = normalizeZCodeInstallDir(valueOf(config, "zcodeInstallDir", ""), { home, env });
|
|
859
879
|
const registry = normalizeSourceUrl(valueOf(config, "toolNpmRegistry", DEFAULT_NPM_REGISTRY), "npm \u6E90") || DEFAULT_NPM_REGISTRY;
|
|
860
880
|
const methodRaw = keepKnownToolIds(
|
|
861
881
|
parseJsonObject(valueOf(config, "toolInstallMethodsJson", "{}"), "\u5B89\u88C5\u65B9\u5F0F\u8986\u76D6"),
|
|
@@ -880,6 +900,7 @@ function parseInstallPreferences(config = {}, { tools = [], home = "", env = {}
|
|
|
880
900
|
}
|
|
881
901
|
return {
|
|
882
902
|
installDir,
|
|
903
|
+
zcodeInstallDir,
|
|
883
904
|
registry,
|
|
884
905
|
methods,
|
|
885
906
|
scriptUrls,
|
|
@@ -2375,18 +2396,20 @@ var INSTALL_DEFAULTS = Object.freeze({
|
|
|
2375
2396
|
toolInstallDir: "",
|
|
2376
2397
|
toolNpmRegistry: DEFAULT_NPM_REGISTRY,
|
|
2377
2398
|
toolScriptUrlsJson: "{}",
|
|
2378
|
-
toolAllowScriptInstall: true
|
|
2399
|
+
toolAllowScriptInstall: true,
|
|
2400
|
+
zcodeInstallDir: ""
|
|
2379
2401
|
});
|
|
2380
2402
|
function toolInstallSettingsSignature(value = {}) {
|
|
2381
2403
|
try {
|
|
2382
|
-
const preferences = parseInstallPreferences({ ...value, toolInstallDir: "" }, { tools: OFFICIAL_TOOLS });
|
|
2404
|
+
const preferences = parseInstallPreferences({ ...value, toolInstallDir: "", zcodeInstallDir: "" }, { tools: OFFICIAL_TOOLS });
|
|
2383
2405
|
const sorted = (map) => Object.entries(map).sort(([left], [right]) => left.localeCompare(right));
|
|
2384
2406
|
return JSON.stringify([
|
|
2385
2407
|
String(value.toolInstallDir ?? "").trim(),
|
|
2386
2408
|
preferences.registry,
|
|
2387
2409
|
sorted(preferences.methods),
|
|
2388
2410
|
sorted(preferences.scriptUrls),
|
|
2389
|
-
preferences.allowScriptInstall
|
|
2411
|
+
preferences.allowScriptInstall,
|
|
2412
|
+
String(value.zcodeInstallDir ?? "").trim()
|
|
2390
2413
|
]);
|
|
2391
2414
|
} catch {
|
|
2392
2415
|
return JSON.stringify([
|
|
@@ -2395,7 +2418,8 @@ function toolInstallSettingsSignature(value = {}) {
|
|
|
2395
2418
|
value.toolNpmRegistry,
|
|
2396
2419
|
value.toolInstallMethodsJson,
|
|
2397
2420
|
value.toolScriptUrlsJson,
|
|
2398
|
-
value.toolAllowScriptInstall
|
|
2421
|
+
value.toolAllowScriptInstall,
|
|
2422
|
+
value.zcodeInstallDir
|
|
2399
2423
|
]);
|
|
2400
2424
|
}
|
|
2401
2425
|
}
|
|
@@ -2406,7 +2430,8 @@ function installSummaryMatchesSettings(summary, value) {
|
|
|
2406
2430
|
toolNpmRegistry: summary.registry || DEFAULT_NPM_REGISTRY,
|
|
2407
2431
|
toolInstallMethodsJson: JSON.stringify(summary.methods ?? {}),
|
|
2408
2432
|
toolScriptUrlsJson: JSON.stringify(summary.scriptUrls ?? {}),
|
|
2409
|
-
toolAllowScriptInstall: summary.allowScriptInstall !== false
|
|
2433
|
+
toolAllowScriptInstall: summary.allowScriptInstall !== false,
|
|
2434
|
+
zcodeInstallDir: summary.requestedZCodeInstallDir ?? summary.zcodeInstallDir ?? ""
|
|
2410
2435
|
});
|
|
2411
2436
|
}
|
|
2412
2437
|
function savedToolInstallMethods(value = {}) {
|
|
@@ -2452,6 +2477,10 @@ function toolInstallAction({ tool, probe, readiness, job, probeStatus, latestVer
|
|
|
2452
2477
|
const installed = probe?.installed === true;
|
|
2453
2478
|
const order = installed && latestVersion ? compareReleaseVersions(probe.version, latestVersion) : null;
|
|
2454
2479
|
const desktop = tool.manager === "signed-windows-installer";
|
|
2480
|
+
if (desktop) return {
|
|
2481
|
+
label: running ? "\u684C\u9762\u5B89\u88C5\u5904\u7406\u4E2D\u2026" : installed ? "\u68C0\u67E5\u5E76\u66F4\u65B0\u684C\u9762\u7248" : job?.status === "failed" ? "\u91CD\u8BD5\u684C\u9762\u5B89\u88C5" : "\u5B89\u88C5 ZCode \u684C\u9762\u7248",
|
|
2482
|
+
disabled: !(probeStatus === "ready" || probeStatus === "refreshing") || running
|
|
2483
|
+
};
|
|
2455
2484
|
const noRunner = desktop || tool.headlessAdapter === true;
|
|
2456
2485
|
const repair = installed && !noRunner && readiness?.ready === false && order !== 0;
|
|
2457
2486
|
const label = running ? "\u5B89\u88C5\u4E2D\u2026" : !installed ? job?.status === "failed" ? "\u91CD\u8BD5\u5B89\u88C5" : desktop ? "\u4E0B\u8F7D\u6700\u65B0\u5B89\u88C5\u5668" : "\u4E00\u952E\u5B89\u88C5\u6700\u65B0\u7248" : order === -1 ? `\u66F4\u65B0\u5230\u6700\u65B0\u7248 ${latestVersion}` : order === 1 ? "\u5DF2\u9AD8\u4E8E\u6700\u65B0\u6B63\u5F0F\u7248" : repair ? "\u4FEE\u590D\u5B98\u65B9\u6267\u884C\u5165\u53E3" : order === 0 ? "\u5DF2\u662F\u6700\u65B0\u7248\u672C" : "\u5B89\u88C5\u6700\u65B0\u7248";
|
|
@@ -2470,9 +2499,9 @@ function toolMaintenanceActions({ tool, probe, job, probeStatus, summary }) {
|
|
|
2470
2499
|
const busy = running || !interactive;
|
|
2471
2500
|
return {
|
|
2472
2501
|
repair: {
|
|
2473
|
-
label: "\u4E00\u952E\u4FEE\u590D",
|
|
2474
|
-
title: "\u7528\u540C\u4E00\u6761\u56FA\u5B9A\u5B98\u65B9\u5B89\u88C5\u547D\u4EE4\u91CD\u65B0\u5B89\u88C5\u4E00\u904D\uFF0C\u4FEE\u590D\u635F\u574F\u6216\u4E0D\u5B8C\u6574\u7684\u5B89\u88C5",
|
|
2475
|
-
disabled: busy ||
|
|
2502
|
+
label: desktop ? "\u91CD\u65B0\u5B89\u88C5\u684C\u9762\u7248" : "\u4E00\u952E\u4FEE\u590D",
|
|
2503
|
+
title: desktop ? "\u6253\u5F00\u5DF2\u6838\u9A8C\u7684\u5B98\u65B9\u684C\u9762\u5B89\u88C5\u5668\uFF1B\u5B8C\u6210\u5B89\u88C5\u540E\u91CD\u65B0\u4F53\u68C0\uFF0C\u5237\u65B0\u5185\u7F6E TUI" : "\u7528\u540C\u4E00\u6761\u56FA\u5B9A\u5B98\u65B9\u5B89\u88C5\u547D\u4EE4\u91CD\u65B0\u5B89\u88C5\u4E00\u904D\uFF0C\u4FEE\u590D\u635F\u574F\u6216\u4E0D\u5B8C\u6574\u7684\u5B89\u88C5",
|
|
2504
|
+
disabled: busy || summary?.installable === false
|
|
2476
2505
|
},
|
|
2477
2506
|
uninstall: {
|
|
2478
2507
|
label: "\u4E00\u952E\u5378\u8F7D",
|
|
@@ -2484,7 +2513,7 @@ function toolMaintenanceActions({ tool, probe, job, probeStatus, summary }) {
|
|
|
2484
2513
|
function installClickRefusal({ tool, submitting = false, running = false, operation = "install", pendingSettings = false, installError = "" } = {}) {
|
|
2485
2514
|
if (!tool) return "\u672A\u77E5\u5B98\u65B9\u5DE5\u5177\uFF0C\u65E0\u6CD5\u5F00\u59CB\u5B89\u88C5\u3002";
|
|
2486
2515
|
if (tool.unsupported) return String(tool.unsupportedReason ?? "").trim() || "\u6B64\u5DE5\u5177\u6682\u4E0D\u652F\u6301\u4E00\u952E\u5B89\u88C5\u3002";
|
|
2487
|
-
if (tool.manager === "signed-windows-installer" && operation
|
|
2516
|
+
if (tool.manager === "signed-windows-installer" && operation === "uninstall") {
|
|
2488
2517
|
return `${tool.label} \u7531\u5B98\u65B9\u7B7E\u540D\u684C\u9762\u5B89\u88C5\u5668\u5B89\u88C5\uFF0C\u8BF7\u5728\u7CFB\u7EDF\u201C\u5E94\u7528\u201D\u4E2D\u5378\u8F7D\u5B83\u3002`;
|
|
2489
2518
|
}
|
|
2490
2519
|
if (submitting || running) {
|
|
@@ -12733,7 +12762,7 @@ var xterm_default = `/**
|
|
|
12733
12762
|
`;
|
|
12734
12763
|
|
|
12735
12764
|
// .dsh-plugin/client/host-version.mjs
|
|
12736
|
-
var ROUTER_CLIENT_VERSION = true ? "0.
|
|
12765
|
+
var ROUTER_CLIENT_VERSION = true ? "0.19.0" : "";
|
|
12737
12766
|
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";
|
|
12738
12767
|
function isMissingRemoteMethod(message) {
|
|
12739
12768
|
const value = String(message ?? "");
|
|
@@ -12751,7 +12780,7 @@ function staleHostNotice({ hostVersion, clientVersion = ROUTER_CLIENT_VERSION, l
|
|
|
12751
12780
|
}
|
|
12752
12781
|
|
|
12753
12782
|
// .dsh-plugin/shared/cli-terminal-protocol.mjs
|
|
12754
|
-
var TERMINAL_TOOL_IDS = Object.freeze(
|
|
12783
|
+
var TERMINAL_TOOL_IDS = Object.freeze(OFFICIAL_TOOLS.filter((tool) => !tool.unsupported && (tool.probeExecutables?.length || tool.manager === "signed-windows-installer")).map((tool) => tool.id));
|
|
12755
12784
|
var TERMINAL_SHELL_ID = "shell";
|
|
12756
12785
|
var TERMINAL_TARGETS = Object.freeze([TERMINAL_SHELL_ID, ...TERMINAL_TOOL_IDS]);
|
|
12757
12786
|
var TERMINAL_MODES = Object.freeze(["interactive", "login"]);
|
|
@@ -12781,8 +12810,14 @@ var TERMINAL_LOGIN_ARGS = Object.freeze({
|
|
|
12781
12810
|
"minimax-code": Object.freeze(["login"]),
|
|
12782
12811
|
"mimo-code": Object.freeze(["auth", "login"]),
|
|
12783
12812
|
"grok-build": Object.freeze(["login"]),
|
|
12784
|
-
gemini: Object.freeze([])
|
|
12813
|
+
gemini: Object.freeze([]),
|
|
12814
|
+
opencode: Object.freeze(["auth", "login"]),
|
|
12815
|
+
stepcode: Object.freeze(["login"]),
|
|
12816
|
+
zcode: Object.freeze([])
|
|
12785
12817
|
});
|
|
12818
|
+
function terminalCanLogin(target) {
|
|
12819
|
+
return Boolean(TERMINAL_LOGIN_ARGS[target]?.length);
|
|
12820
|
+
}
|
|
12786
12821
|
var SESSION_ID = /^term-[a-z0-9]{6,40}$/;
|
|
12787
12822
|
function plainObject(value, subject) {
|
|
12788
12823
|
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError(`${subject} must be an object`);
|
|
@@ -12808,7 +12843,7 @@ function terminalTargetLabel(target) {
|
|
|
12808
12843
|
function terminalCommandPreview(target, mode = "interactive", platform = "win32") {
|
|
12809
12844
|
if (target === TERMINAL_SHELL_ID) return platform === "win32" ? "powershell.exe -NoLogo" : "$SHELL -l";
|
|
12810
12845
|
const tool = getOfficialTool(target);
|
|
12811
|
-
const executable = tool?.probeExecutables?.[0] ?? String(target);
|
|
12846
|
+
const executable = target === "zcode" ? "ZCode \u684C\u9762\u7248\u5185\u7F6E TUI" : tool?.probeExecutables?.[0] ?? String(target);
|
|
12812
12847
|
const args = mode === "login" ? TERMINAL_LOGIN_ARGS[target] ?? [] : [];
|
|
12813
12848
|
return [executable, ...args].join(" ");
|
|
12814
12849
|
}
|
|
@@ -12817,7 +12852,7 @@ function parseTerminalStart(value) {
|
|
|
12817
12852
|
if (!TERMINAL_TARGETS.includes(request.target)) throw new TypeError("target must be the shell or a fixed official CLI");
|
|
12818
12853
|
const mode = request.mode === void 0 ? "interactive" : request.mode;
|
|
12819
12854
|
if (!TERMINAL_MODES.includes(mode)) throw new TypeError("mode must be interactive or login");
|
|
12820
|
-
if (mode === "login" && request.target
|
|
12855
|
+
if (mode === "login" && !terminalCanLogin(request.target)) throw new TypeError("this target has no login mode");
|
|
12821
12856
|
if (!isAbsoluteDirectoryText(request.cwd)) throw new TypeError("cwd must be an absolute directory path");
|
|
12822
12857
|
if (request.confirmed !== true) throw new TypeError("starting a terminal requires the user's confirmation");
|
|
12823
12858
|
return {
|
|
@@ -12867,7 +12902,11 @@ function terminalTargets(healthTools = [], platform = "win32") {
|
|
|
12867
12902
|
const installed = new Set((Array.isArray(healthTools) ? healthTools : []).filter((item) => item?.installed).map((item) => item.id));
|
|
12868
12903
|
return [
|
|
12869
12904
|
{ id: TERMINAL_SHELL_ID, label: platform === "win32" ? "PowerShell\uFF08\u7CFB\u7EDF\u7EC8\u7AEF\uFF09" : "Shell\uFF08\u7CFB\u7EDF\u7EC8\u7AEF\uFF09", canLogin: false },
|
|
12870
|
-
...TERMINAL_TOOL_IDS.filter((id2) => installed.has(id2)).map((id2) => ({
|
|
12905
|
+
...TERMINAL_TOOL_IDS.filter((id2) => installed.has(id2)).map((id2) => ({
|
|
12906
|
+
id: id2,
|
|
12907
|
+
label: id2 === "zcode" ? `${terminalTargetLabel(id2)}\uFF08\u684C\u9762\u7248\u5185\u7F6E TUI\uFF09` : terminalTargetLabel(id2),
|
|
12908
|
+
canLogin: terminalCanLogin(id2)
|
|
12909
|
+
}))
|
|
12871
12910
|
];
|
|
12872
12911
|
}
|
|
12873
12912
|
function startProblem({ target, cwd, targets }) {
|
|
@@ -12927,6 +12966,26 @@ async function loadTerminalInfo(api) {
|
|
|
12927
12966
|
if (!info || typeof info !== "object" || !["pty", "pipe"].includes(info.backend)) throw new Error("\u7EC8\u7AEF\u72B6\u6001\u683C\u5F0F\u65E0\u6548\u3002");
|
|
12928
12967
|
return info;
|
|
12929
12968
|
}
|
|
12969
|
+
var TerminalInfoRefresher = class {
|
|
12970
|
+
constructor() {
|
|
12971
|
+
this.generation = 0;
|
|
12972
|
+
}
|
|
12973
|
+
invalidate() {
|
|
12974
|
+
this.generation += 1;
|
|
12975
|
+
}
|
|
12976
|
+
async load(api) {
|
|
12977
|
+
const generation = ++this.generation;
|
|
12978
|
+
try {
|
|
12979
|
+
const value = await loadTerminalInfo(api);
|
|
12980
|
+
return generation === this.generation ? { status: "ready", value, error: "" } : null;
|
|
12981
|
+
} catch (error) {
|
|
12982
|
+
return generation === this.generation ? { status: "error", value: null, error: remoteErrorText(text3(error?.message), "\u65E0\u6CD5\u8BFB\u53D6\u7EC8\u7AEF\u72B6\u6001\u3002") } : null;
|
|
12983
|
+
}
|
|
12984
|
+
}
|
|
12985
|
+
};
|
|
12986
|
+
function terminalInfoTools(info, healthTools = []) {
|
|
12987
|
+
return Array.isArray(info?.tools) ? info.tools : Array.isArray(healthTools) ? healthTools : [];
|
|
12988
|
+
}
|
|
12930
12989
|
async function startTerminal(api, request) {
|
|
12931
12990
|
const session = unwrap(await api.terminalStart({ ...request, confirmed: true }), "\u7EC8\u7AEF\u542F\u52A8\u5931\u8D25\u3002");
|
|
12932
12991
|
if (!isTerminalSessionId(session?.sessionId)) throw new Error("\u7EC8\u7AEF\u542F\u52A8\u7ED3\u679C\u7F3A\u5C11\u6709\u6548\u7684\u4F1A\u8BDD ID\u3002");
|
|
@@ -13120,7 +13179,7 @@ function TerminalPane({ api, session, active, onEnded }) {
|
|
|
13120
13179
|
}, [session.sessionId]);
|
|
13121
13180
|
return /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-term-pane", style: { display: active ? "block" : "none" } }, session.limitation && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption mr-term-warning" }, session.limitation, session.ptyError ? `\uFF08${session.ptyError}\uFF09` : ""), error && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption mr-term-warning", role: "alert" }, error), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-term-screen", ref: host }));
|
|
13122
13181
|
}
|
|
13123
|
-
function CliTerminalCard({ api, health }) {
|
|
13182
|
+
function CliTerminalCard({ api, health, settingsSignature = "" }) {
|
|
13124
13183
|
const [info, setInfo] = import_react4.default.useState({ status: "loading", value: null, error: "" });
|
|
13125
13184
|
const [target, setTarget] = import_react4.default.useState("shell");
|
|
13126
13185
|
const [mode, setMode] = import_react4.default.useState("interactive");
|
|
@@ -13130,29 +13189,38 @@ function CliTerminalCard({ api, health }) {
|
|
|
13130
13189
|
const [startError, setStartError] = import_react4.default.useState("");
|
|
13131
13190
|
const [sessions, setSessions] = import_react4.default.useState([]);
|
|
13132
13191
|
const [activeId, setActiveId] = import_react4.default.useState("");
|
|
13192
|
+
const [tools, setTools] = import_react4.default.useState(health?.tools ?? []);
|
|
13133
13193
|
const mounted = import_react4.default.useRef(true);
|
|
13194
|
+
const refresher = import_react4.default.useRef(null);
|
|
13195
|
+
if (!refresher.current) refresher.current = new TerminalInfoRefresher();
|
|
13196
|
+
const healthTools = import_react4.default.useRef(health?.tools);
|
|
13197
|
+
healthTools.current = health?.tools;
|
|
13198
|
+
const settingsScope = import_react4.default.useRef({ tools: health?.tools, signature: settingsSignature });
|
|
13134
13199
|
const loadInfo = import_react4.default.useCallback(async () => {
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13138
|
-
|
|
13139
|
-
} catch (error) {
|
|
13140
|
-
if (mounted.current) setInfo({ status: "error", value: null, error: errorText(error, "\u65E0\u6CD5\u8BFB\u53D6\u7EC8\u7AEF\u72B6\u6001\u3002") });
|
|
13141
|
-
}
|
|
13200
|
+
const result = await refresher.current.load(api);
|
|
13201
|
+
if (!mounted.current || !result) return;
|
|
13202
|
+
setInfo(result);
|
|
13203
|
+
if (result.status === "ready") setTools(terminalInfoTools(result.value, healthTools.current));
|
|
13142
13204
|
}, [api]);
|
|
13143
13205
|
import_react4.default.useEffect(() => {
|
|
13144
13206
|
mounted.current = true;
|
|
13145
13207
|
void loadInfo();
|
|
13146
13208
|
return () => {
|
|
13147
13209
|
mounted.current = false;
|
|
13210
|
+
refresher.current.invalidate();
|
|
13148
13211
|
};
|
|
13149
13212
|
}, [loadInfo]);
|
|
13213
|
+
import_react4.default.useEffect(() => {
|
|
13214
|
+
if (settingsScope.current.tools === health?.tools && settingsScope.current.signature === settingsSignature) return;
|
|
13215
|
+
settingsScope.current = { tools: health?.tools, signature: settingsSignature };
|
|
13216
|
+
void loadInfo();
|
|
13217
|
+
}, [health?.tools, settingsSignature, loadInfo]);
|
|
13150
13218
|
const platform = info.value?.platform ?? clientPlatform();
|
|
13151
|
-
const targets = terminalTargets(
|
|
13219
|
+
const targets = terminalTargets(tools, platform);
|
|
13152
13220
|
const selected = targets.find((item) => item.id === target) ?? targets[0];
|
|
13153
13221
|
import_react4.default.useEffect(() => {
|
|
13154
13222
|
if (!targets.some((item) => item.id === target)) setTarget("shell");
|
|
13155
|
-
}, [
|
|
13223
|
+
}, [tools, target]);
|
|
13156
13224
|
import_react4.default.useEffect(() => {
|
|
13157
13225
|
if (!selected?.canLogin && mode === "login") setMode("interactive");
|
|
13158
13226
|
}, [selected?.id]);
|
|
@@ -13196,7 +13264,7 @@ function CliTerminalCard({ api, health }) {
|
|
|
13196
13264
|
};
|
|
13197
13265
|
const active = sessions.find((item) => item.sessionId === activeId);
|
|
13198
13266
|
const history = info.value?.history ?? [];
|
|
13199
|
-
return /* @__PURE__ */ import_react4.default.createElement("section", { className: "mr-card", "aria-label": "\u5B98\u65B9\u5DE5\u5177\u7EC8\u7AEF" }, /* @__PURE__ */ import_react4.default.createElement("style", null, xterm_default), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react4.default.createElement("div", null, /* @__PURE__ */ import_react4.default.createElement("h2", { className: "mr-card-title" }, "\u5B98\u65B9\u5DE5\u5177\u7EC8\u7AEF"), /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-card-copy" }, "\u5728\u5DE5\u4F5C\u53F0\u91CC\u4EA4\u4E92\u5F0F\u8FD0\u884C PowerShell
|
|
13267
|
+
return /* @__PURE__ */ import_react4.default.createElement("section", { className: "mr-card", "aria-label": "\u5B98\u65B9\u5DE5\u5177\u7EC8\u7AEF" }, /* @__PURE__ */ import_react4.default.createElement("style", null, xterm_default), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-card-head" }, /* @__PURE__ */ import_react4.default.createElement("div", null, /* @__PURE__ */ import_react4.default.createElement("h2", { className: "mr-card-title" }, "\u5B98\u65B9\u5DE5\u5177\u7EC8\u7AEF"), /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-card-copy" }, "\u5728\u5DE5\u4F5C\u53F0\u91CC\u4EA4\u4E92\u5F0F\u8FD0\u884C PowerShell\u3001\u5DF2\u5B89\u88C5\u7684\u5B98\u65B9 CLI \u6216 ZCode \u684C\u9762\u7248\u5185\u7F6E TUI\uFF08\u591A\u8F6E\u5BF9\u8BDD\u3001\u5B9E\u65F6\u8F93\u51FA\uFF0C\u53EF\u7528\u4E8E ", /* @__PURE__ */ import_react4.default.createElement("code", null, "codex login"), " \u7B49\u767B\u5F55\uFF09\u3002\u542F\u52A8\u5165\u53E3\u4E0E\u5B98\u65B9\u5DE5\u5177\u7684\u5B89\u88C5\u65B9\u5F0F\u548C\u76EE\u5F55\u540C\u6B65\u3002\u7EC8\u7AEF\u4E0D\u7ECF\u8FC7 Harness \u6C99\u7BB1\uFF0C\u4F7F\u7528\u4F60\u81EA\u5DF1\u7684\u767B\u5F55\u548C\u73AF\u5883\u53D8\u91CF\u3002")), /* @__PURE__ */ import_react4.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => {
|
|
13200
13268
|
void loadInfo();
|
|
13201
13269
|
} }, "\u5237\u65B0")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-card-body" }, info.status === "error" && /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-error", role: "alert" }, info.error), info.value && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption" }, info.value.backend === "pty" ? "\u7EC8\u7AEF\u7EC4\u4EF6\uFF1A\u4F2A\u7EC8\u7AEF\uFF08PTY\uFF09\uFF0C\u652F\u6301\u5168\u5C4F\u754C\u9762\u3001\u989C\u8272\u548C\u7A97\u53E3\u5927\u5C0F\u540C\u6B65\u3002" : `\u7EC8\u7AEF\u7EC4\u4EF6\uFF1A\u7BA1\u9053\u6A21\u5F0F\u3002${info.value.limitation ?? ""}${info.value.ptyError ? `\uFF08PTY \u52A0\u8F7D\u5931\u8D25\uFF1A${info.value.ptyError}\uFF09` : ""}`), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-controls" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-control-group" }, /* @__PURE__ */ import_react4.default.createElement("label", { className: "mr-control-label", htmlFor: "mr-term-target" }, "\u542F\u52A8"), /* @__PURE__ */ import_react4.default.createElement("select", { className: "mr-input", id: "mr-term-target", value: selected?.id ?? "shell", onChange: (event) => {
|
|
13202
13270
|
setTarget(event.target.value);
|
|
@@ -13220,7 +13288,7 @@ function CliTerminalCard({ api, health }) {
|
|
|
13220
13288
|
setConfirming(false);
|
|
13221
13289
|
}
|
|
13222
13290
|
}
|
|
13223
|
-
))), targets.length === 1 && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption" }, "\
|
|
13291
|
+
))), targets.length === 1 && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption" }, "\u5C1A\u672A\u53D1\u73B0\u5DF2\u5B89\u88C5\u7684\u5B98\u65B9 CLI\uFF1B\u5B89\u88C5\u6216\u914D\u7F6E\u76EE\u5F55\u540E\u70B9\u672C\u5361\u7247\u201C\u5237\u65B0\u201D\u6216\u201C\u5B98\u65B9\u5DE5\u5177 \xB7 \u4F53\u68C0\u201D\u7684\u201C\u91CD\u65B0\u4F53\u68C0\u201D\uFF0C\u8FD9\u91CC\u4F1A\u51FA\u73B0\u5BF9\u5E94\u9009\u9879\u3002"), !confirming && /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react4.default.createElement("button", { className: "mr-button", type: "button", disabled: Boolean(problem) || live >= maxSessions || info.status !== "ready", onClick: () => {
|
|
13224
13292
|
setStartError("");
|
|
13225
13293
|
setConfirming(true);
|
|
13226
13294
|
} }, "\u5F00\u59CB"), /* @__PURE__ */ import_react4.default.createElement("span", { className: "mr-caption" }, problem || (live >= maxSessions ? `\u6700\u591A\u540C\u65F6\u8FD0\u884C ${maxSessions} \u4E2A\u4F1A\u8BDD\u3002` : `\u5C06\u8FD0\u884C\uFF1A${details.command}`))), confirming && /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-term-confirm", role: "dialog", "aria-label": "\u786E\u8BA4\u542F\u52A8\u7EC8\u7AEF" }, /* @__PURE__ */ import_react4.default.createElement("strong", null, details.title), /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption" }, "\u547D\u4EE4\uFF1A", /* @__PURE__ */ import_react4.default.createElement("code", null, details.command), /* @__PURE__ */ import_react4.default.createElement("br", null), "\u5DE5\u4F5C\u76EE\u5F55\uFF1A", /* @__PURE__ */ import_react4.default.createElement("code", null, details.cwd)), /* @__PURE__ */ import_react4.default.createElement("ul", null, details.points.map((point) => /* @__PURE__ */ import_react4.default.createElement("li", { key: point }, point))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "mr-actions" }, /* @__PURE__ */ import_react4.default.createElement("button", { className: "mr-button", type: "button", disabled: starting, onClick: () => {
|
|
@@ -13586,7 +13654,14 @@ var INSTALL_SETTING_FIELDS = [
|
|
|
13586
13654
|
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"
|
|
13587
13655
|
}
|
|
13588
13656
|
];
|
|
13589
|
-
|
|
13657
|
+
var ZCODE_SETTING_FIELDS = [{
|
|
13658
|
+
key: "zcodeInstallDir",
|
|
13659
|
+
label: "ZCode \u684C\u9762\u5B89\u88C5\u76EE\u5F55",
|
|
13660
|
+
fallback: "",
|
|
13661
|
+
placeholder: "\u4F8B\u5982 D:/Program Files/ZCode\uFF0C\u7559\u7A7A\u81EA\u52A8\u68C0\u6D4B",
|
|
13662
|
+
hint: "\u5DF2\u5B89\u88C5\u684C\u9762\u7248\u5373\u53EF\u4F7F\u7528\u5185\u7F6E TUI\u3002\u4FDD\u5B58\u76EE\u5F55\u540E\u91CD\u65B0\u6838\u9A8C\u684C\u9762\u7A0B\u5E8F\u548C\u5185\u7F6E CLI\uFF1B\u65E0\u9700\u72EC\u7ACB CLI \u5B89\u88C5\u5305\u3002"
|
|
13663
|
+
}];
|
|
13664
|
+
function InstallSettings({ settingsScope, install, onPendingChange, onMutationStart, zcode = false }) {
|
|
13590
13665
|
const [snapshot, setSnapshot] = import_react5.default.useState(() => settingsScope?.getSnapshot?.() ?? { value: {}, writable: false });
|
|
13591
13666
|
const [drafts, setDrafts] = import_react5.default.useState({});
|
|
13592
13667
|
const [saving, setSaving] = import_react5.default.useState(false);
|
|
@@ -13608,7 +13683,8 @@ function InstallSettings({ settingsScope, install, onPendingChange, onMutationSt
|
|
|
13608
13683
|
if (!settingsScope) return null;
|
|
13609
13684
|
const writable = snapshot.writable === true && !saving;
|
|
13610
13685
|
const shown = (field2) => drafts[field2.key] ?? String(snapshot.value?.[field2.key] ?? field2.fallback);
|
|
13611
|
-
const
|
|
13686
|
+
const fields = zcode ? ZCODE_SETTING_FIELDS : INSTALL_SETTING_FIELDS;
|
|
13687
|
+
const errors = Object.fromEntries(fields.map((field2) => [field2.key, validateToolInstallSetting(field2.key, shown(field2))]));
|
|
13612
13688
|
const invalid = Object.values(errors).some(Boolean);
|
|
13613
13689
|
const edit = (key, value) => {
|
|
13614
13690
|
const next = retainToolInstallDrafts({ ...drafts, [key]: value }, snapshot.value);
|
|
@@ -13640,7 +13716,7 @@ function InstallSettings({ settingsScope, install, onPendingChange, onMutationSt
|
|
|
13640
13716
|
setSaving(false);
|
|
13641
13717
|
}
|
|
13642
13718
|
};
|
|
13643
|
-
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" },
|
|
13719
|
+
return /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-install-settings", "aria-label": zcode ? "ZCode TUI \u72EC\u7ACB\u914D\u7F6E" : "\u7EDF\u4E00\u5B89\u88C5\u8BBE\u7F6E" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-install-settings-head" }, /* @__PURE__ */ import_react5.default.createElement("strong", null, zcode ? "ZCode TUI \u72EC\u7ACB\u914D\u7F6E" : "\u7EDF\u4E00\u5B89\u88C5\u8BBE\u7F6E"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-caption" }, zcode ? "\u5185\u7F6E CLI \u968F\u684C\u9762\u7248\u66F4\u65B0\u3002\u4FDD\u5B58\u540E\u5728\u5B98\u65B9\u5DE5\u5177\u7EC8\u7AEF\u9009\u62E9 ZCode TUI\uFF0C\u81EA\u884C\u914D\u7F6E\u767B\u5F55\u3001\u6A21\u578B\u4E0E\u63D2\u4EF6\u3002" : "\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" }, 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(
|
|
13644
13720
|
"input",
|
|
13645
13721
|
{
|
|
13646
13722
|
className: "mr-input",
|
|
@@ -13650,7 +13726,7 @@ function InstallSettings({ settingsScope, install, onPendingChange, onMutationSt
|
|
|
13650
13726
|
"aria-invalid": Boolean(errors[field2.key]),
|
|
13651
13727
|
onChange: (event) => edit(field2.key, event.target.value)
|
|
13652
13728
|
}
|
|
13653
|
-
), 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(
|
|
13729
|
+
), 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))), !zcode && /* @__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(
|
|
13654
13730
|
"input",
|
|
13655
13731
|
{
|
|
13656
13732
|
type: "checkbox",
|
|
@@ -13662,11 +13738,11 @@ function InstallSettings({ settingsScope, install, onPendingChange, onMutationSt
|
|
|
13662
13738
|
}
|
|
13663
13739
|
), /* @__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: () => {
|
|
13664
13740
|
void apply2();
|
|
13665
|
-
} }, 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: () => {
|
|
13741
|
+
} }, saving ? "\u4FDD\u5B58\u4E2D\u2026" : zcode ? "\u4FDD\u5B58\u5E76\u5237\u65B0 TUI \u5165\u53E3" : "\u4FDD\u5B58\u5B89\u88C5\u8BBE\u7F6E"), dirty && /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: saving, onClick: () => {
|
|
13666
13742
|
setDrafts({});
|
|
13667
13743
|
setNotice("");
|
|
13668
13744
|
onPendingChange?.(false);
|
|
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
|
|
13745
|
+
} }, "\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 }, zcode ? `\u5F53\u524D ZCode \u76EE\u5F55\uFF1A${install?.zcodeInstallDir || "\uFF08\u81EA\u52A8\u68C0\u6D4B\uFF09"}` : `\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}` : ""));
|
|
13670
13746
|
}
|
|
13671
13747
|
function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes, health, onRefreshHealth, settingsScope }) {
|
|
13672
13748
|
const healthById = Object.fromEntries((health?.tools ?? []).map((item) => [item.id, item]));
|
|
@@ -13690,9 +13766,18 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
|
|
|
13690
13766
|
const submitting = import_react5.default.useRef(/* @__PURE__ */ new Set());
|
|
13691
13767
|
const polling = import_react5.default.useRef(/* @__PURE__ */ new Set());
|
|
13692
13768
|
const jobsRef = import_react5.default.useRef({});
|
|
13769
|
+
const settingsPendingBySection = import_react5.default.useRef({ shared: false, zcode: false });
|
|
13693
13770
|
const handleSettingsPending = import_react5.default.useCallback((value) => {
|
|
13694
|
-
|
|
13695
|
-
|
|
13771
|
+
settingsPendingBySection.current.shared = value;
|
|
13772
|
+
const pending = Object.values(settingsPendingBySection.current).some(Boolean);
|
|
13773
|
+
settingsPendingRef.current = pending;
|
|
13774
|
+
setSettingsPending(pending);
|
|
13775
|
+
}, []);
|
|
13776
|
+
const handleZCodeSettingsPending = import_react5.default.useCallback((value) => {
|
|
13777
|
+
settingsPendingBySection.current.zcode = value;
|
|
13778
|
+
const pending = Object.values(settingsPendingBySection.current).some(Boolean);
|
|
13779
|
+
settingsPendingRef.current = pending;
|
|
13780
|
+
setSettingsPending(pending);
|
|
13696
13781
|
}, []);
|
|
13697
13782
|
const rememberJobs = (updater) => {
|
|
13698
13783
|
setJobs((previous) => {
|
|
@@ -13813,6 +13898,8 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
|
|
|
13813
13898
|
}, []);
|
|
13814
13899
|
const refreshInstallSettingsRef = import_react5.default.useRef(refreshInstallSettings);
|
|
13815
13900
|
refreshInstallSettingsRef.current = refreshInstallSettings;
|
|
13901
|
+
const refreshProbesRef = import_react5.default.useRef(refresh);
|
|
13902
|
+
refreshProbesRef.current = refresh;
|
|
13816
13903
|
const beginSettingsMutation = import_react5.default.useCallback((operations) => {
|
|
13817
13904
|
const generation = ++mutationGeneration.current;
|
|
13818
13905
|
mutationPendingRef.current = { generation, operations };
|
|
@@ -13829,12 +13916,15 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
|
|
|
13829
13916
|
if (typeof settingsScope?.subscribe !== "function") return void 0;
|
|
13830
13917
|
const signature2 = (snapshot) => toolInstallSettingsSignature(snapshot?.value);
|
|
13831
13918
|
let previous = signature2(settingsScope.getSnapshot());
|
|
13919
|
+
let previousZCode = settingsScope.getSnapshot()?.value?.zcodeInstallDir ?? "";
|
|
13832
13920
|
return settingsScope.subscribe(() => {
|
|
13833
13921
|
const snapshot = settingsScope.getSnapshot();
|
|
13834
13922
|
setSettingsSnapshot(snapshot);
|
|
13835
13923
|
const next = signature2(snapshot);
|
|
13836
13924
|
if (next === previous) return;
|
|
13837
13925
|
previous = next;
|
|
13926
|
+
const zcodeChanged = previousZCode !== (snapshot?.value?.zcodeInstallDir ?? "");
|
|
13927
|
+
previousZCode = snapshot?.value?.zcodeInstallDir ?? "";
|
|
13838
13928
|
request.current += 1;
|
|
13839
13929
|
setProbeSettingsStale(true);
|
|
13840
13930
|
setProbeState((previous2) => ({ ...previous2, status: "ready", probes: [], readiness: [], error: "" }));
|
|
@@ -13842,6 +13932,7 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
|
|
|
13842
13932
|
previewPendingRef.current = true;
|
|
13843
13933
|
setPreviewPending(true);
|
|
13844
13934
|
void refreshInstallSettingsRef.current();
|
|
13935
|
+
if (zcodeChanged) void refreshProbesRef.current();
|
|
13845
13936
|
});
|
|
13846
13937
|
}, [settingsScope]);
|
|
13847
13938
|
import_react5.default.useEffect(() => {
|
|
@@ -14016,7 +14107,16 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
|
|
|
14016
14107
|
const verified = Boolean(probe) && job?.status === "succeeded" && (job.operation === "uninstall" ? job.postInstallProbe?.installed === false : job.postInstallProbe?.installed === true);
|
|
14017
14108
|
const operation = job?.operation === "uninstall" ? "\u5378\u8F7D" : job?.operation === "repair" ? "\u4FEE\u590D" : "\u5B89\u88C5";
|
|
14018
14109
|
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";
|
|
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 ${
|
|
14110
|
+
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 ${tool.id === "zcode" ? "\u684C\u9762\u7248 " : ""}${probe.version}` : "", healthById[tool.id]?.latestVersion ? ` \xB7 \u6700\u65B0 ${healthById[tool.id].latestVersion}` : ""), /* @__PURE__ */ import_react5.default.createElement(ToolLoginLine, { entry: healthById[tool.id] }), tool.id === "zcode" && /* @__PURE__ */ import_react5.default.createElement(
|
|
14111
|
+
InstallSettings,
|
|
14112
|
+
{
|
|
14113
|
+
zcode: true,
|
|
14114
|
+
settingsScope,
|
|
14115
|
+
install: probeState.install,
|
|
14116
|
+
onPendingChange: handleZCodeSettingsPending,
|
|
14117
|
+
onMutationStart: beginSettingsMutation
|
|
14118
|
+
}
|
|
14119
|
+
), 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 === "signed-windows-installer" ? "\u5B98\u65B9\u684C\u9762\u5B89\u88C5\u5668" : tool.manager), " \xB7 \u5B9E\u9645\u5B89\u88C5\u76EE\u5F55\uFF1A", probe?.installDir || 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(
|
|
14020
14120
|
"select",
|
|
14021
14121
|
{
|
|
14022
14122
|
className: "mr-mini-select",
|
|
@@ -14399,7 +14499,14 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
|
|
|
14399
14499
|
void workbench.refreshHealth(true);
|
|
14400
14500
|
}
|
|
14401
14501
|
}
|
|
14402
|
-
), terminalApi && /* @__PURE__ */ import_react5.default.createElement(
|
|
14502
|
+
), terminalApi && /* @__PURE__ */ import_react5.default.createElement(
|
|
14503
|
+
CliTerminalCard,
|
|
14504
|
+
{
|
|
14505
|
+
api: terminalApi,
|
|
14506
|
+
health: workbench.health.report,
|
|
14507
|
+
settingsSignature: toolInstallSettingsSignature(settingsScope?.getSnapshot?.()?.value)
|
|
14508
|
+
}
|
|
14509
|
+
)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view mr-stack", role: "tabpanel", id: "mr-panel-controls", "aria-labelledby": "mr-tab-controls", hidden: view !== "controls" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-view-heading" }, /* @__PURE__ */ import_react5.default.createElement("h2", null, "\u9884\u7B97\u4E0E\u5B89\u5168"), /* @__PURE__ */ import_react5.default.createElement("p", null, "\u8BBE\u7F6E\u6210\u672C\u4E0E\u8D28\u91CF\u7B56\u7565\uFF0C\u6838\u5BF9\u8BA2\u9605\u8BA1\u8D39\u548C\u6267\u884C\u8FB9\u754C\u3002")), /* @__PURE__ */ import_react5.default.createElement(
|
|
14403
14510
|
CostControlCard,
|
|
14404
14511
|
{
|
|
14405
14512
|
ledger: workbench.ledger.value,
|
|
@@ -14699,6 +14806,17 @@ function installDirField() {
|
|
|
14699
14806
|
}
|
|
14700
14807
|
};
|
|
14701
14808
|
}
|
|
14809
|
+
function zcodeInstallDirField() {
|
|
14810
|
+
const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("zcodeInstallDir");
|
|
14811
|
+
return { ...field2, parse: (text7) => {
|
|
14812
|
+
try {
|
|
14813
|
+
parseInstallPreferences({ zcodeInstallDir: text7 }, { tools: OFFICIAL_TOOLS });
|
|
14814
|
+
} catch {
|
|
14815
|
+
return void 0;
|
|
14816
|
+
}
|
|
14817
|
+
return field2.parse(text7);
|
|
14818
|
+
} };
|
|
14819
|
+
}
|
|
14702
14820
|
function npmRegistryField() {
|
|
14703
14821
|
const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("toolNpmRegistry");
|
|
14704
14822
|
return {
|
|
@@ -14760,6 +14878,7 @@ var RouterSettingsCardController = class {
|
|
|
14760
14878
|
modelProfilesField(),
|
|
14761
14879
|
quotaPatternsField(),
|
|
14762
14880
|
installDirField(),
|
|
14881
|
+
zcodeInstallDirField(),
|
|
14763
14882
|
npmRegistryField(),
|
|
14764
14883
|
installMethodsField(),
|
|
14765
14884
|
scriptUrlsField()
|
|
@@ -14775,6 +14894,7 @@ var RouterSettingsCardController = class {
|
|
|
14775
14894
|
modelProfilesJson: this.form.field("modelProfilesJson"),
|
|
14776
14895
|
quotaPatternsJson: this.form.field("quotaPatternsJson"),
|
|
14777
14896
|
toolInstallDir: this.form.field("toolInstallDir"),
|
|
14897
|
+
zcodeInstallDir: this.form.field("zcodeInstallDir"),
|
|
14778
14898
|
toolNpmRegistry: this.form.field("toolNpmRegistry"),
|
|
14779
14899
|
toolInstallMethodsJson: this.form.field("toolInstallMethodsJson"),
|
|
14780
14900
|
toolScriptUrlsJson: this.form.field("toolScriptUrlsJson")
|
|
@@ -14937,6 +15057,24 @@ function RouterSettingsCard(props) {
|
|
|
14937
15057
|
props.resetField("toolNpmRegistry");
|
|
14938
15058
|
}
|
|
14939
15059
|
}
|
|
15060
|
+
), /* @__PURE__ */ import_react6.default.createElement(
|
|
15061
|
+
import_dsh_client_ui_primitives.SettingsValueField,
|
|
15062
|
+
{
|
|
15063
|
+
id: "model-router-zcode-install-dir",
|
|
15064
|
+
label: "ZCode \u684C\u9762\u76EE\u5F55\u4E0E TUI",
|
|
15065
|
+
hint: "Windows \u5DF2\u5B89\u88C5 ZCode \u684C\u9762\u7248\u5373\u53EF\u4F7F\u7528\u5185\u7F6E TUI\u3002\u586B\u5199\u5176\u72EC\u7ACB\u76EE\u5F55\uFF08\u4F8B\u5982 D:/Program Files/ZCode\uFF09\uFF0C\u7559\u7A7A\u81EA\u52A8\u68C0\u6D4B\u3002\u4FDD\u5B58\u540E\u4F53\u68C0\u4E0E\u5B98\u65B9\u5DE5\u5177\u7EC8\u7AEF\u5171\u7528\u6B64\u5165\u53E3\uFF1B\u5185\u7F6E CLI \u968F\u684C\u9762\u7248\u66F4\u65B0\uFF0C\u767B\u5F55\u4E0E\u6A21\u578B\u5728 TUI \u4E2D\u914D\u7F6E\u3002",
|
|
15066
|
+
disabled,
|
|
15067
|
+
...state.zcodeInstallDir,
|
|
15068
|
+
overriddenLabel: FIELD_COPY.overridden,
|
|
15069
|
+
resetLabel: FIELD_COPY.reset,
|
|
15070
|
+
invalidLabel: "\u8BF7\u8F93\u5165 Windows \u672C\u5730\u7EDD\u5BF9\u684C\u9762\u76EE\u5F55\uFF0C\u6216\u7559\u7A7A\u81EA\u52A8\u68C0\u6D4B\u3002",
|
|
15071
|
+
onEdit: (value) => {
|
|
15072
|
+
props.edit("zcodeInstallDir", value);
|
|
15073
|
+
},
|
|
15074
|
+
onReset: () => {
|
|
15075
|
+
props.resetField("zcodeInstallDir");
|
|
15076
|
+
}
|
|
15077
|
+
}
|
|
14940
15078
|
), /* @__PURE__ */ import_react6.default.createElement(
|
|
14941
15079
|
import_dsh_client_ui_primitives.SettingsValueField,
|
|
14942
15080
|
{
|
package/.dsh-plugin/index.mjs
CHANGED
|
@@ -95,6 +95,7 @@ export const Config = z.object({
|
|
|
95
95
|
toolInstallMethodsJson: z.string().max(8_000).default('{}').volatile(),
|
|
96
96
|
toolScriptUrlsJson: z.string().max(8_000).default('{}').volatile(),
|
|
97
97
|
toolAllowScriptInstall: z.boolean().default(true).volatile(),
|
|
98
|
+
zcodeInstallDir: z.string().max(4_096).default('').volatile(),
|
|
98
99
|
})
|
|
99
100
|
|
|
100
101
|
const JSON_OUTPUT = {
|
|
@@ -1387,6 +1388,8 @@ export async function startWorkbenchRun(ctx, config, request = {}, options = {})
|
|
|
1387
1388
|
export function createRouterTerminals(options = {}) {
|
|
1388
1389
|
return createTerminalManager({
|
|
1389
1390
|
prepare: () => ensureNpmPrefixOnPath(),
|
|
1391
|
+
preferences: () => installPreferences(),
|
|
1392
|
+
launchOptions: () => currentInstallOptions(),
|
|
1390
1393
|
onSessionEnd: record => { void routerStateStore().appendTerminalSession(record).catch(() => {}) },
|
|
1391
1394
|
...options,
|
|
1392
1395
|
})
|
|
@@ -1397,11 +1400,14 @@ async function terminalHistory(limit = 20) {
|
|
|
1397
1400
|
return (saved.terminalSessions ?? []).slice(-limit).reverse()
|
|
1398
1401
|
}
|
|
1399
1402
|
|
|
1400
|
-
function terminalServices(terminals) {
|
|
1403
|
+
function terminalServices(terminals, assertPreferences = () => {}) {
|
|
1401
1404
|
if (!terminals) return {}
|
|
1402
1405
|
return {
|
|
1403
|
-
terminalInfo: async () =>
|
|
1404
|
-
|
|
1406
|
+
terminalInfo: async () => {
|
|
1407
|
+
const tools = await probeAllTools({ fresh: true })
|
|
1408
|
+
return { ...terminals.info(), tools, toolsCheckedAt: Date.now(), history: await terminalHistory() }
|
|
1409
|
+
},
|
|
1410
|
+
terminalStart: async request => { assertPreferences(); return terminals.start(parseTerminalStart(request)) },
|
|
1405
1411
|
terminalRead: async request => terminals.read(parseTerminalRead(request)),
|
|
1406
1412
|
terminalWrite: async request => terminals.write(parseTerminalWrite(request)),
|
|
1407
1413
|
terminalResize: async request => terminals.resize(parseTerminalResize(request)),
|
|
@@ -1409,9 +1415,9 @@ function terminalServices(terminals) {
|
|
|
1409
1415
|
}
|
|
1410
1416
|
}
|
|
1411
1417
|
|
|
1412
|
-
export function routerRemoteServices(ctx, config, { terminals = null } = {}) {
|
|
1418
|
+
export function routerRemoteServices(ctx, config, { terminals = null, assertPreferences } = {}) {
|
|
1413
1419
|
return {
|
|
1414
|
-
...terminalServices(terminals),
|
|
1420
|
+
...terminalServices(terminals, assertPreferences),
|
|
1415
1421
|
health: async fresh => {
|
|
1416
1422
|
const report = await toolHealthReport({ fresh: fresh === true })
|
|
1417
1423
|
const saved = await savedState()
|
|
@@ -1444,7 +1450,7 @@ export function apply(ctx, config = {}) {
|
|
|
1444
1450
|
installPreferenceError = null
|
|
1445
1451
|
} catch (error) { installPreferenceError = errorText(error) }
|
|
1446
1452
|
}
|
|
1447
|
-
const installFields = new Set(['toolInstallDir', 'toolNpmRegistry', 'toolInstallMethodsJson', 'toolScriptUrlsJson', 'toolAllowScriptInstall'])
|
|
1453
|
+
const installFields = new Set(['toolInstallDir', 'toolNpmRegistry', 'toolInstallMethodsJson', 'toolScriptUrlsJson', 'toolAllowScriptInstall', 'zcodeInstallDir'])
|
|
1448
1454
|
syncInstallPreferences()
|
|
1449
1455
|
// Loader scopes this event to the fiber whose refs were committed.
|
|
1450
1456
|
ctx.on('loader/volatile-update', paths => {
|
|
@@ -1464,9 +1470,10 @@ export function apply(ctx, config = {}) {
|
|
|
1464
1470
|
return () => { process.off('exit', onExit); terminals.disposeAll('dispose') }
|
|
1465
1471
|
}, 'model-router-galgame: interactive terminals')
|
|
1466
1472
|
registerOfficialToolsRemote(ctx, {
|
|
1467
|
-
...routerRemoteServices(ctx, config, { terminals }),
|
|
1473
|
+
...routerRemoteServices(ctx, config, { terminals, assertPreferences: assertInstallPreferences }),
|
|
1468
1474
|
installSettingsError: () => installPreferenceError,
|
|
1469
1475
|
installRequestedDirectory: () => valueOf(config, 'toolInstallDir', ''),
|
|
1476
|
+
zcodeRequestedDirectory: () => valueOf(config, 'zcodeInstallDir', ''),
|
|
1470
1477
|
})
|
|
1471
1478
|
}
|
|
1472
1479
|
ctx.on('tools/pre-execute', async (exec, next) => {
|