@ljwei-stak/dsh-model-router 0.18.1 → 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.
@@ -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"]
@@ -451,12 +480,12 @@ var OFFICIAL_TOOLS = Object.freeze([
451
480
  id: "zcode",
452
481
  label: "ZCode",
453
482
  vendor: "Z.ai",
454
- purpose: "\u667A\u8C31\u5B98\u65B9 ZCode \u684C\u9762\u7248\uFF0C\u5185\u542B GLM \u7F16\u7A0B\u4EE3\u7406\u3002Windows \u5B89\u88C5\u5668\u53EF\u9009\u62E9 D \u76D8\u76EE\u5F55\u3002",
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",
455
484
  manager: "signed-windows-installer",
456
485
  installArgs: [],
457
486
  uninstallArgs: [],
458
487
  probeExecutables: [],
459
- 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",
460
489
  providerHints: ["zai", "z.ai", "zcode", "glm", "zhipu", "bigmodel"]
461
490
  })
462
491
  ]);
@@ -784,6 +813,25 @@ function expandInstallDir(value, { home = "", env = {} } = {}) {
784
813
  if (/^\\\\[^\\]+\\[^\\]+$/.test(withoutTrailing)) throw new Error("\u5B89\u88C5\u76EE\u5F55\u4E0D\u80FD\u662F\u7F51\u7EDC\u5171\u4EAB\u6839\u76EE\u5F55\u3002");
785
814
  return expanded;
786
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
+ }
787
835
  function normalizeSourceUrl(value, subject) {
788
836
  const raw = String(value ?? "").trim();
789
837
  if (!raw) return "";
@@ -827,6 +875,7 @@ function keepKnownToolIds(raw, known, subject) {
827
875
  function parseInstallPreferences(config = {}, { tools = [], home = "", env = {} } = {}) {
828
876
  const known = new Set(tools.map((tool) => tool.id));
829
877
  const installDir = expandInstallDir(valueOf(config, "toolInstallDir", ""), { home, env });
878
+ const zcodeInstallDir = normalizeZCodeInstallDir(valueOf(config, "zcodeInstallDir", ""), { home, env });
830
879
  const registry = normalizeSourceUrl(valueOf(config, "toolNpmRegistry", DEFAULT_NPM_REGISTRY), "npm \u6E90") || DEFAULT_NPM_REGISTRY;
831
880
  const methodRaw = keepKnownToolIds(
832
881
  parseJsonObject(valueOf(config, "toolInstallMethodsJson", "{}"), "\u5B89\u88C5\u65B9\u5F0F\u8986\u76D6"),
@@ -851,6 +900,7 @@ function parseInstallPreferences(config = {}, { tools = [], home = "", env = {}
851
900
  }
852
901
  return {
853
902
  installDir,
903
+ zcodeInstallDir,
854
904
  registry,
855
905
  methods,
856
906
  scriptUrls,
@@ -2346,18 +2396,20 @@ var INSTALL_DEFAULTS = Object.freeze({
2346
2396
  toolInstallDir: "",
2347
2397
  toolNpmRegistry: DEFAULT_NPM_REGISTRY,
2348
2398
  toolScriptUrlsJson: "{}",
2349
- toolAllowScriptInstall: true
2399
+ toolAllowScriptInstall: true,
2400
+ zcodeInstallDir: ""
2350
2401
  });
2351
2402
  function toolInstallSettingsSignature(value = {}) {
2352
2403
  try {
2353
- const preferences = parseInstallPreferences({ ...value, toolInstallDir: "" }, { tools: OFFICIAL_TOOLS });
2404
+ const preferences = parseInstallPreferences({ ...value, toolInstallDir: "", zcodeInstallDir: "" }, { tools: OFFICIAL_TOOLS });
2354
2405
  const sorted = (map) => Object.entries(map).sort(([left], [right]) => left.localeCompare(right));
2355
2406
  return JSON.stringify([
2356
2407
  String(value.toolInstallDir ?? "").trim(),
2357
2408
  preferences.registry,
2358
2409
  sorted(preferences.methods),
2359
2410
  sorted(preferences.scriptUrls),
2360
- preferences.allowScriptInstall
2411
+ preferences.allowScriptInstall,
2412
+ String(value.zcodeInstallDir ?? "").trim()
2361
2413
  ]);
2362
2414
  } catch {
2363
2415
  return JSON.stringify([
@@ -2366,7 +2418,8 @@ function toolInstallSettingsSignature(value = {}) {
2366
2418
  value.toolNpmRegistry,
2367
2419
  value.toolInstallMethodsJson,
2368
2420
  value.toolScriptUrlsJson,
2369
- value.toolAllowScriptInstall
2421
+ value.toolAllowScriptInstall,
2422
+ value.zcodeInstallDir
2370
2423
  ]);
2371
2424
  }
2372
2425
  }
@@ -2377,7 +2430,8 @@ function installSummaryMatchesSettings(summary, value) {
2377
2430
  toolNpmRegistry: summary.registry || DEFAULT_NPM_REGISTRY,
2378
2431
  toolInstallMethodsJson: JSON.stringify(summary.methods ?? {}),
2379
2432
  toolScriptUrlsJson: JSON.stringify(summary.scriptUrls ?? {}),
2380
- toolAllowScriptInstall: summary.allowScriptInstall !== false
2433
+ toolAllowScriptInstall: summary.allowScriptInstall !== false,
2434
+ zcodeInstallDir: summary.requestedZCodeInstallDir ?? summary.zcodeInstallDir ?? ""
2381
2435
  });
2382
2436
  }
2383
2437
  function savedToolInstallMethods(value = {}) {
@@ -2423,6 +2477,10 @@ function toolInstallAction({ tool, probe, readiness, job, probeStatus, latestVer
2423
2477
  const installed = probe?.installed === true;
2424
2478
  const order = installed && latestVersion ? compareReleaseVersions(probe.version, latestVersion) : null;
2425
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
+ };
2426
2484
  const noRunner = desktop || tool.headlessAdapter === true;
2427
2485
  const repair = installed && !noRunner && readiness?.ready === false && order !== 0;
2428
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";
@@ -2441,9 +2499,9 @@ function toolMaintenanceActions({ tool, probe, job, probeStatus, summary }) {
2441
2499
  const busy = running || !interactive;
2442
2500
  return {
2443
2501
  repair: {
2444
- label: "\u4E00\u952E\u4FEE\u590D",
2445
- 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",
2446
- disabled: busy || desktop || summary?.installable === false
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
2447
2505
  },
2448
2506
  uninstall: {
2449
2507
  label: "\u4E00\u952E\u5378\u8F7D",
@@ -2455,7 +2513,7 @@ function toolMaintenanceActions({ tool, probe, job, probeStatus, summary }) {
2455
2513
  function installClickRefusal({ tool, submitting = false, running = false, operation = "install", pendingSettings = false, installError = "" } = {}) {
2456
2514
  if (!tool) return "\u672A\u77E5\u5B98\u65B9\u5DE5\u5177\uFF0C\u65E0\u6CD5\u5F00\u59CB\u5B89\u88C5\u3002";
2457
2515
  if (tool.unsupported) return String(tool.unsupportedReason ?? "").trim() || "\u6B64\u5DE5\u5177\u6682\u4E0D\u652F\u6301\u4E00\u952E\u5B89\u88C5\u3002";
2458
- if (tool.manager === "signed-windows-installer" && operation !== "install") {
2516
+ if (tool.manager === "signed-windows-installer" && operation === "uninstall") {
2459
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`;
2460
2518
  }
2461
2519
  if (submitting || running) {
@@ -12704,7 +12762,7 @@ var xterm_default = `/**
12704
12762
  `;
12705
12763
 
12706
12764
  // .dsh-plugin/client/host-version.mjs
12707
- var ROUTER_CLIENT_VERSION = true ? "0.18.1" : "";
12765
+ var ROUTER_CLIENT_VERSION = true ? "0.19.0" : "";
12708
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";
12709
12767
  function isMissingRemoteMethod(message) {
12710
12768
  const value = String(message ?? "");
@@ -12722,7 +12780,7 @@ function staleHostNotice({ hostVersion, clientVersion = ROUTER_CLIENT_VERSION, l
12722
12780
  }
12723
12781
 
12724
12782
  // .dsh-plugin/shared/cli-terminal-protocol.mjs
12725
- var TERMINAL_TOOL_IDS = Object.freeze(["codex", "claude-code", "kimi-code", "minimax-code", "mimo-code", "grok-build", "gemini"]);
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));
12726
12784
  var TERMINAL_SHELL_ID = "shell";
12727
12785
  var TERMINAL_TARGETS = Object.freeze([TERMINAL_SHELL_ID, ...TERMINAL_TOOL_IDS]);
12728
12786
  var TERMINAL_MODES = Object.freeze(["interactive", "login"]);
@@ -12752,8 +12810,14 @@ var TERMINAL_LOGIN_ARGS = Object.freeze({
12752
12810
  "minimax-code": Object.freeze(["login"]),
12753
12811
  "mimo-code": Object.freeze(["auth", "login"]),
12754
12812
  "grok-build": Object.freeze(["login"]),
12755
- gemini: Object.freeze([])
12813
+ gemini: Object.freeze([]),
12814
+ opencode: Object.freeze(["auth", "login"]),
12815
+ stepcode: Object.freeze(["login"]),
12816
+ zcode: Object.freeze([])
12756
12817
  });
12818
+ function terminalCanLogin(target) {
12819
+ return Boolean(TERMINAL_LOGIN_ARGS[target]?.length);
12820
+ }
12757
12821
  var SESSION_ID = /^term-[a-z0-9]{6,40}$/;
12758
12822
  function plainObject(value, subject) {
12759
12823
  if (value === null || typeof value !== "object" || Array.isArray(value)) throw new TypeError(`${subject} must be an object`);
@@ -12779,7 +12843,7 @@ function terminalTargetLabel(target) {
12779
12843
  function terminalCommandPreview(target, mode = "interactive", platform = "win32") {
12780
12844
  if (target === TERMINAL_SHELL_ID) return platform === "win32" ? "powershell.exe -NoLogo" : "$SHELL -l";
12781
12845
  const tool = getOfficialTool(target);
12782
- const executable = tool?.probeExecutables?.[0] ?? String(target);
12846
+ const executable = target === "zcode" ? "ZCode \u684C\u9762\u7248\u5185\u7F6E TUI" : tool?.probeExecutables?.[0] ?? String(target);
12783
12847
  const args = mode === "login" ? TERMINAL_LOGIN_ARGS[target] ?? [] : [];
12784
12848
  return [executable, ...args].join(" ");
12785
12849
  }
@@ -12788,7 +12852,7 @@ function parseTerminalStart(value) {
12788
12852
  if (!TERMINAL_TARGETS.includes(request.target)) throw new TypeError("target must be the shell or a fixed official CLI");
12789
12853
  const mode = request.mode === void 0 ? "interactive" : request.mode;
12790
12854
  if (!TERMINAL_MODES.includes(mode)) throw new TypeError("mode must be interactive or login");
12791
- if (mode === "login" && request.target === TERMINAL_SHELL_ID) throw new TypeError("the shell has no login mode");
12855
+ if (mode === "login" && !terminalCanLogin(request.target)) throw new TypeError("this target has no login mode");
12792
12856
  if (!isAbsoluteDirectoryText(request.cwd)) throw new TypeError("cwd must be an absolute directory path");
12793
12857
  if (request.confirmed !== true) throw new TypeError("starting a terminal requires the user's confirmation");
12794
12858
  return {
@@ -12838,7 +12902,11 @@ function terminalTargets(healthTools = [], platform = "win32") {
12838
12902
  const installed = new Set((Array.isArray(healthTools) ? healthTools : []).filter((item) => item?.installed).map((item) => item.id));
12839
12903
  return [
12840
12904
  { id: TERMINAL_SHELL_ID, label: platform === "win32" ? "PowerShell\uFF08\u7CFB\u7EDF\u7EC8\u7AEF\uFF09" : "Shell\uFF08\u7CFB\u7EDF\u7EC8\u7AEF\uFF09", canLogin: false },
12841
- ...TERMINAL_TOOL_IDS.filter((id2) => installed.has(id2)).map((id2) => ({ id: id2, label: terminalTargetLabel(id2), canLogin: id2 !== "gemini" }))
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
+ }))
12842
12910
  ];
12843
12911
  }
12844
12912
  function startProblem({ target, cwd, targets }) {
@@ -12898,6 +12966,26 @@ async function loadTerminalInfo(api) {
12898
12966
  if (!info || typeof info !== "object" || !["pty", "pipe"].includes(info.backend)) throw new Error("\u7EC8\u7AEF\u72B6\u6001\u683C\u5F0F\u65E0\u6548\u3002");
12899
12967
  return info;
12900
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
+ }
12901
12989
  async function startTerminal(api, request) {
12902
12990
  const session = unwrap(await api.terminalStart({ ...request, confirmed: true }), "\u7EC8\u7AEF\u542F\u52A8\u5931\u8D25\u3002");
12903
12991
  if (!isTerminalSessionId(session?.sessionId)) throw new Error("\u7EC8\u7AEF\u542F\u52A8\u7ED3\u679C\u7F3A\u5C11\u6709\u6548\u7684\u4F1A\u8BDD ID\u3002");
@@ -13091,7 +13179,7 @@ function TerminalPane({ api, session, active, onEnded }) {
13091
13179
  }, [session.sessionId]);
13092
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 }));
13093
13181
  }
13094
- function CliTerminalCard({ api, health }) {
13182
+ function CliTerminalCard({ api, health, settingsSignature = "" }) {
13095
13183
  const [info, setInfo] = import_react4.default.useState({ status: "loading", value: null, error: "" });
13096
13184
  const [target, setTarget] = import_react4.default.useState("shell");
13097
13185
  const [mode, setMode] = import_react4.default.useState("interactive");
@@ -13101,29 +13189,38 @@ function CliTerminalCard({ api, health }) {
13101
13189
  const [startError, setStartError] = import_react4.default.useState("");
13102
13190
  const [sessions, setSessions] = import_react4.default.useState([]);
13103
13191
  const [activeId, setActiveId] = import_react4.default.useState("");
13192
+ const [tools, setTools] = import_react4.default.useState(health?.tools ?? []);
13104
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 });
13105
13199
  const loadInfo = import_react4.default.useCallback(async () => {
13106
- try {
13107
- const value = await loadTerminalInfo(api);
13108
- if (!mounted.current) return;
13109
- setInfo({ status: "ready", value, error: "" });
13110
- } catch (error) {
13111
- if (mounted.current) setInfo({ status: "error", value: null, error: errorText(error, "\u65E0\u6CD5\u8BFB\u53D6\u7EC8\u7AEF\u72B6\u6001\u3002") });
13112
- }
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));
13113
13204
  }, [api]);
13114
13205
  import_react4.default.useEffect(() => {
13115
13206
  mounted.current = true;
13116
13207
  void loadInfo();
13117
13208
  return () => {
13118
13209
  mounted.current = false;
13210
+ refresher.current.invalidate();
13119
13211
  };
13120
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]);
13121
13218
  const platform = info.value?.platform ?? clientPlatform();
13122
- const targets = terminalTargets(health?.tools ?? [], platform);
13219
+ const targets = terminalTargets(tools, platform);
13123
13220
  const selected = targets.find((item) => item.id === target) ?? targets[0];
13124
13221
  import_react4.default.useEffect(() => {
13125
13222
  if (!targets.some((item) => item.id === target)) setTarget("shell");
13126
- }, [targets.length]);
13223
+ }, [tools, target]);
13127
13224
  import_react4.default.useEffect(() => {
13128
13225
  if (!selected?.canLogin && mode === "login") setMode("interactive");
13129
13226
  }, [selected?.id]);
@@ -13167,7 +13264,7 @@ function CliTerminalCard({ api, health }) {
13167
13264
  };
13168
13265
  const active = sessions.find((item) => item.sessionId === activeId);
13169
13266
  const history = info.value?.history ?? [];
13170
- 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 \u6216\u5DF2\u5B89\u88C5\u7684\u5B98\u65B9 CLI\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\u7EC8\u7AEF\u4E0D\u7ECF\u8FC7 Harness \u6C99\u7BB1\uFF0C\u4F7F\u7528\u4F60\u81EA\u5DF1\u7684 CLI \u767B\u5F55\u548C\u73AF\u5883\u53D8\u91CF\u3002")), /* @__PURE__ */ import_react4.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", onClick: () => {
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: () => {
13171
13268
  void loadInfo();
13172
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) => {
13173
13270
  setTarget(event.target.value);
@@ -13191,7 +13288,7 @@ function CliTerminalCard({ api, health }) {
13191
13288
  setConfirming(false);
13192
13289
  }
13193
13290
  }
13194
- ))), targets.length === 1 && /* @__PURE__ */ import_react4.default.createElement("p", { className: "mr-caption" }, "\u4F53\u68C0\u5C1A\u672A\u53D1\u73B0\u5DF2\u5B89\u88C5\u7684\u5B98\u65B9 CLI\uFF1B\u5B89\u88C5\u540E\u70B9\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: () => {
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: () => {
13195
13292
  setStartError("");
13196
13293
  setConfirming(true);
13197
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: () => {
@@ -13537,10 +13634,10 @@ function probeLabel(probe) {
13537
13634
  var INSTALL_SETTING_FIELDS = [
13538
13635
  {
13539
13636
  key: "toolInstallDir",
13540
- label: "\u7EDF\u4E00\u5B89\u88C5\u76EE\u5F55",
13637
+ label: "\u7EDF\u4E00\u5B89\u88C5\u6839\u76EE\u5F55",
13541
13638
  fallback: "",
13542
13639
  placeholder: "\u7559\u7A7A = \u5404\u5382\u5546\u9ED8\u8BA4\u76EE\u5F55",
13543
- hint: "\u586B\u5199\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 D:/AI/tools\u3002\u5404\u65B9\u5F0F\u7684\u5B9E\u9645\u76EE\u5F55\u4F1A\u663E\u793A\u5728\u5DE5\u5177\u547D\u4EE4\u65C1\uFF1B\u4E0D\u652F\u6301\u7EDF\u4E00\u76EE\u5F55\u7684\u65B9\u5F0F\u4F1A\u8BF4\u660E\u539F\u56E0\u3002"
13640
+ 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"
13544
13641
  },
13545
13642
  {
13546
13643
  key: "toolNpmRegistry",
@@ -13557,7 +13654,14 @@ var INSTALL_SETTING_FIELDS = [
13557
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"
13558
13655
  }
13559
13656
  ];
13560
- function InstallSettings({ settingsScope, install, onPendingChange, onMutationStart }) {
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 }) {
13561
13665
  const [snapshot, setSnapshot] = import_react5.default.useState(() => settingsScope?.getSnapshot?.() ?? { value: {}, writable: false });
13562
13666
  const [drafts, setDrafts] = import_react5.default.useState({});
13563
13667
  const [saving, setSaving] = import_react5.default.useState(false);
@@ -13579,7 +13683,8 @@ function InstallSettings({ settingsScope, install, onPendingChange, onMutationSt
13579
13683
  if (!settingsScope) return null;
13580
13684
  const writable = snapshot.writable === true && !saving;
13581
13685
  const shown = (field2) => drafts[field2.key] ?? String(snapshot.value?.[field2.key] ?? field2.fallback);
13582
- const errors = Object.fromEntries(INSTALL_SETTING_FIELDS.map((field2) => [field2.key, validateToolInstallSetting(field2.key, shown(field2))]));
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))]));
13583
13688
  const invalid = Object.values(errors).some(Boolean);
13584
13689
  const edit = (key, value) => {
13585
13690
  const next = retainToolInstallDrafts({ ...drafts, [key]: value }, snapshot.value);
@@ -13611,7 +13716,7 @@ function InstallSettings({ settingsScope, install, onPendingChange, onMutationSt
13611
13716
  setSaving(false);
13612
13717
  }
13613
13718
  };
13614
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-install-settings", "aria-label": "\u7EDF\u4E00\u5B89\u88C5\u8BBE\u7F6E" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-install-settings-head" }, /* @__PURE__ */ import_react5.default.createElement("strong", null, "\u7EDF\u4E00\u5B89\u88C5\u8BBE\u7F6E"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-caption" }, "\u4FDD\u5B58\u540E\u7528\u4E8E\u540E\u7EED\u5B89\u88C5\u4E0E\u66F4\u65B0\u3002\u6BCF\u4E2A\u5DE5\u5177\u4E0B\u65B9\u663E\u793A\u5B9E\u9645\u65B9\u5F0F\u548C\u76EE\u5F55\uFF0C\u63D2\u4EF6\u8BBE\u7F6E\u9875\u91CC\u4E5F\u80FD\u4FEE\u6539\u3002")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-install-grid" }, INSTALL_SETTING_FIELDS.map((field2) => /* @__PURE__ */ import_react5.default.createElement("label", { className: "mr-install-field", key: field2.key }, /* @__PURE__ */ import_react5.default.createElement("span", null, field2.label), /* @__PURE__ */ import_react5.default.createElement(
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(
13615
13720
  "input",
13616
13721
  {
13617
13722
  className: "mr-input",
@@ -13621,7 +13726,7 @@ function InstallSettings({ settingsScope, install, onPendingChange, onMutationSt
13621
13726
  "aria-invalid": Boolean(errors[field2.key]),
13622
13727
  onChange: (event) => edit(field2.key, event.target.value)
13623
13728
  }
13624
- ), errors[field2.key] ? /* @__PURE__ */ import_react5.default.createElement("small", { className: "mr-install-error", role: "alert" }, errors[field2.key]) : /* @__PURE__ */ import_react5.default.createElement("small", null, field2.hint))), /* @__PURE__ */ import_react5.default.createElement("label", { className: "mr-install-field" }, /* @__PURE__ */ import_react5.default.createElement("span", null, "\u5B89\u88C5\u811A\u672C\u65B9\u5F0F"), /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-install-toggle-row" }, /* @__PURE__ */ import_react5.default.createElement(
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(
13625
13730
  "input",
13626
13731
  {
13627
13732
  type: "checkbox",
@@ -13633,11 +13738,11 @@ function InstallSettings({ settingsScope, install, onPendingChange, onMutationSt
13633
13738
  }
13634
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: () => {
13635
13740
  void apply2();
13636
- } }, saving ? "\u4FDD\u5B58\u4E2D\u2026" : "\u4FDD\u5B58\u5B89\u88C5\u8BBE\u7F6E"), dirty && /* @__PURE__ */ import_react5.default.createElement("button", { className: "mr-button mr-button-secondary", type: "button", disabled: saving, onClick: () => {
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: () => {
13637
13742
  setDrafts({});
13638
13743
  setNotice("");
13639
13744
  onPendingChange?.(false);
13640
- } }, "\u653E\u5F03\u66F4\u6539"), dirty && /* @__PURE__ */ import_react5.default.createElement("span", { className: "mr-caption" }, invalid ? "\u8BF7\u4FEE\u6B63\u8F93\u5165\u540E\u4FDD\u5B58\u3002" : "\u66F4\u6539\u5C1A\u672A\u4FDD\u5B58\uFF0C\u5B89\u88C5\u4E0E\u66F4\u65B0\u6682\u4E0D\u53EF\u7528\u3002")), /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { marginTop: 8 }, role: notice ? "status" : void 0 }, "\u5F53\u524D\u751F\u6548\uFF1A\u5B89\u88C5\u76EE\u5F55 ", install?.installDir || "\uFF08\u5404\u5382\u5546\u9ED8\u8BA4\uFF09", " \xB7 npm \u6E90 ", install?.registry || "\uFF08\u9ED8\u8BA4\uFF09", notice ? ` \xB7 ${notice}` : ""));
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}` : ""));
13641
13746
  }
13642
13747
  function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, installOfficialTool, uninstallOfficialTool, repairOfficialTool, cancelOfficialToolInstall, officialToolInstallStatus, onProbes, health, onRefreshHealth, settingsScope }) {
13643
13748
  const healthById = Object.fromEntries((health?.tools ?? []).map((item) => [item.id, item]));
@@ -13661,9 +13766,18 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
13661
13766
  const submitting = import_react5.default.useRef(/* @__PURE__ */ new Set());
13662
13767
  const polling = import_react5.default.useRef(/* @__PURE__ */ new Set());
13663
13768
  const jobsRef = import_react5.default.useRef({});
13769
+ const settingsPendingBySection = import_react5.default.useRef({ shared: false, zcode: false });
13664
13770
  const handleSettingsPending = import_react5.default.useCallback((value) => {
13665
- settingsPendingRef.current = value;
13666
- setSettingsPending(value);
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);
13667
13781
  }, []);
13668
13782
  const rememberJobs = (updater) => {
13669
13783
  setJobs((previous) => {
@@ -13784,6 +13898,8 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
13784
13898
  }, []);
13785
13899
  const refreshInstallSettingsRef = import_react5.default.useRef(refreshInstallSettings);
13786
13900
  refreshInstallSettingsRef.current = refreshInstallSettings;
13901
+ const refreshProbesRef = import_react5.default.useRef(refresh);
13902
+ refreshProbesRef.current = refresh;
13787
13903
  const beginSettingsMutation = import_react5.default.useCallback((operations) => {
13788
13904
  const generation = ++mutationGeneration.current;
13789
13905
  mutationPendingRef.current = { generation, operations };
@@ -13800,12 +13916,15 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
13800
13916
  if (typeof settingsScope?.subscribe !== "function") return void 0;
13801
13917
  const signature2 = (snapshot) => toolInstallSettingsSignature(snapshot?.value);
13802
13918
  let previous = signature2(settingsScope.getSnapshot());
13919
+ let previousZCode = settingsScope.getSnapshot()?.value?.zcodeInstallDir ?? "";
13803
13920
  return settingsScope.subscribe(() => {
13804
13921
  const snapshot = settingsScope.getSnapshot();
13805
13922
  setSettingsSnapshot(snapshot);
13806
13923
  const next = signature2(snapshot);
13807
13924
  if (next === previous) return;
13808
13925
  previous = next;
13926
+ const zcodeChanged = previousZCode !== (snapshot?.value?.zcodeInstallDir ?? "");
13927
+ previousZCode = snapshot?.value?.zcodeInstallDir ?? "";
13809
13928
  request.current += 1;
13810
13929
  setProbeSettingsStale(true);
13811
13930
  setProbeState((previous2) => ({ ...previous2, status: "ready", probes: [], readiness: [], error: "" }));
@@ -13813,6 +13932,7 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
13813
13932
  previewPendingRef.current = true;
13814
13933
  setPreviewPending(true);
13815
13934
  void refreshInstallSettingsRef.current();
13935
+ if (zcodeChanged) void refreshProbesRef.current();
13816
13936
  });
13817
13937
  }, [settingsScope]);
13818
13938
  import_react5.default.useEffect(() => {
@@ -13987,7 +14107,16 @@ function OfficialToolsCard({ listOfficialTools, loadOfficialInstallSettings, ins
13987
14107
  const verified = Boolean(probe) && job?.status === "succeeded" && (job.operation === "uninstall" ? job.postInstallProbe?.installed === false : job.postInstallProbe?.installed === true);
13988
14108
  const operation = job?.operation === "uninstall" ? "\u5378\u8F7D" : job?.operation === "repair" ? "\u4FEE\u590D" : "\u5B89\u88C5";
13989
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";
13990
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool", role: "listitem", key: tool.id }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-info" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-route-name", title: tool.purpose }, tool.label), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-route-provider" }, tool.vendor, " \xB7 ", tool.id), /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-status", role: "status" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: `mr-tool-dot ${running ? "running" : probe?.installed ? "installed" : "missing"}` }), status, probe?.installed && probe.version ? ` \xB7 ${probe.version}` : "", healthById[tool.id]?.latestVersion ? ` \xB7 \u6700\u65B0 ${healthById[tool.id].latestVersion}` : ""), /* @__PURE__ */ import_react5.default.createElement(ToolLoginLine, { entry: healthById[tool.id] }), probe?.installed && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, tool.headlessAdapter ? "\u5DF2\u53EF\u7531 model_router_execute \u4EE5\u65E0\u754C\u9762\u65B9\u5F0F\u8C03\u7528\u3002\u547D\u4EE4\u7F3A\u5931\u6216\u5931\u8D25\u65F6\u56DE\u9000\u6A21\u578B\u76EE\u5F55 API\u3002\u7B7E\u540D\u6C99\u7BB1\u5165\u53E3\u4E0D\u542F\u52A8\u6B64 CLI\u3002" : readiness?.ready ? `\u5B98\u65B9\u6267\u884C\u5165\u53E3\u5DF2\u6838\u9A8C\uFF0C\u53EF\u5728\u4F1A\u8BDD\u4E2D\u8C03\u7528 model_router_tool_run\uFF1B${capability?.modes?.includes("read-only") ? "\u652F\u6301\u53EA\u8BFB\u548C\u7ECF\u5BA1\u6279\u7684\u53EF\u7F16\u8F91\u4EFB\u52A1" : "\u4EC5\u652F\u6301\u7ECF\u5BA1\u6279\u7684\u53EF\u7F16\u8F91\u9694\u79BB\u5DE5\u4F5C\u533A\u4EFB\u52A1"}\uFF0C\u8D26\u53F7\u53CA\u6A21\u578B\u4ECD\u9700\u5B9E\u6D4B\u3002` : `\u5DF2\u5B89\u88C5\uFF0C\u4F46\u5F53\u524D\u4E0D\u53EF\u6258\u7BA1\u6267\u884C\uFF1A${readiness?.reason || capability?.reason || "\u6267\u884C\u5165\u53E3\u5C1A\u672A\u6838\u9A8C\u3002"}`), command ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, "\u5B89\u88C5\u65B9\u5F0F\uFF1A", methods.find((method) => method.id === summary?.methodId)?.label ?? tool.manager, " \xB7 \u5B9E\u9645\u5B89\u88C5\u76EE\u5F55\uFF1A", summary?.installDir || "\u5404\u5382\u5546\u9ED8\u8BA4\u76EE\u5F55"), /* @__PURE__ */ import_react5.default.createElement("code", { className: "mr-tool-command", "aria-label": `${tool.label} \u5B89\u88C5\u547D\u4EE4` }, command), updateCommand !== command && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, "\u66F4\u65B0\u6CBF\u7528\u539F\u5B89\u88C5\u4F4D\u7F6E\uFF1A", summary?.updateInstallDir || "\u5404\u5382\u5546\u9ED8\u8BA4\u76EE\u5F55"), /* @__PURE__ */ import_react5.default.createElement("code", { className: "mr-tool-command", "aria-label": `${tool.label} \u66F4\u65B0\u547D\u4EE4` }, updateCommand))) : /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption", style: { margin: "6px 0 0" } }, summary?.error ?? tool.unsupportedReason), (summary?.notices ?? []).map((notice) => /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail", key: notice }, notice)), probe?.detail && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-caption mr-tool-detail" }, probe.detail), (rowErrors[tool.id] || job?.error) && /* @__PURE__ */ import_react5.default.createElement("p", { className: "mr-error mr-tool-error", role: "alert" }, rowErrors[tool.id] || job.error), Array.isArray(job?.outputTail) && job.outputTail.length > 0 && /* @__PURE__ */ import_react5.default.createElement("details", { className: "mr-tool-log" }, /* @__PURE__ */ import_react5.default.createElement("summary", null, "\u5B89\u88C5\u65E5\u5FD7"), /* @__PURE__ */ import_react5.default.createElement("pre", null, job.outputTail.slice(-6).join("\n")))), (command || methods.length > 0) && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-actions" }, methods.length > 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "mr-tool-methods" }, /* @__PURE__ */ import_react5.default.createElement("label", null, /* @__PURE__ */ import_react5.default.createElement("span", null, "\u5B89\u88C5\u65B9\u5F0F"), /* @__PURE__ */ import_react5.default.createElement(
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(
13991
14120
  "select",
13992
14121
  {
13993
14122
  className: "mr-mini-select",
@@ -14370,7 +14499,14 @@ function RouterMainPage({ loadCatalog, settingsScope, listOfficialTools, loadOff
14370
14499
  void workbench.refreshHealth(true);
14371
14500
  }
14372
14501
  }
14373
- ), terminalApi && /* @__PURE__ */ import_react5.default.createElement(CliTerminalCard, { api: terminalApi, health: workbench.health.report })), /* @__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(
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(
14374
14510
  CostControlCard,
14375
14511
  {
14376
14512
  ledger: workbench.ledger.value,
@@ -14670,6 +14806,17 @@ function installDirField() {
14670
14806
  }
14671
14807
  };
14672
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
+ }
14673
14820
  function npmRegistryField() {
14674
14821
  const field2 = (0, import_dsh_client_ui_primitives.settingsTextField)("toolNpmRegistry");
14675
14822
  return {
@@ -14731,6 +14878,7 @@ var RouterSettingsCardController = class {
14731
14878
  modelProfilesField(),
14732
14879
  quotaPatternsField(),
14733
14880
  installDirField(),
14881
+ zcodeInstallDirField(),
14734
14882
  npmRegistryField(),
14735
14883
  installMethodsField(),
14736
14884
  scriptUrlsField()
@@ -14746,6 +14894,7 @@ var RouterSettingsCardController = class {
14746
14894
  modelProfilesJson: this.form.field("modelProfilesJson"),
14747
14895
  quotaPatternsJson: this.form.field("quotaPatternsJson"),
14748
14896
  toolInstallDir: this.form.field("toolInstallDir"),
14897
+ zcodeInstallDir: this.form.field("zcodeInstallDir"),
14749
14898
  toolNpmRegistry: this.form.field("toolNpmRegistry"),
14750
14899
  toolInstallMethodsJson: this.form.field("toolInstallMethodsJson"),
14751
14900
  toolScriptUrlsJson: this.form.field("toolScriptUrlsJson")
@@ -14876,8 +15025,8 @@ function RouterSettingsCard(props) {
14876
15025
  import_dsh_client_ui_primitives.SettingsValueField,
14877
15026
  {
14878
15027
  id: "model-router-tool-install-dir",
14879
- label: "\u7EDF\u4E00\u5B89\u88C5\u76EE\u5F55",
14880
- hint: "\u586B\u5199\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u7559\u7A7A\u4F7F\u7528\u5382\u5546\u9ED8\u8BA4\u4F4D\u7F6E\u3002npm / pnpm \u4F7F\u7528\u8BE5\u76EE\u5F55\u5B89\u88C5\uFF1B\u5382\u5546\u811A\u672C\u4E0D\u652F\u6301\u81EA\u5B9A\u4E49\u76EE\u5F55\u65F6\uFF0C\u5B98\u65B9\u5DE5\u5177\u9875\u4F1A\u663E\u793A\u5B9E\u9645\u76EE\u5F55\u4E0E\u539F\u56E0\u3002\u66F4\u65B0\u4F7F\u7528\u540C\u4E00\u5B89\u88C5\u65B9\u5F0F\u3001\u76EE\u5F55\u4E0E\u4E0B\u8F7D\u6E90\u3002",
15028
+ label: "\u7EDF\u4E00\u5B89\u88C5\u6839\u76EE\u5F55",
15029
+ 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",
14881
15030
  disabled,
14882
15031
  ...state.toolInstallDir,
14883
15032
  overriddenLabel: FIELD_COPY.overridden,
@@ -14908,6 +15057,24 @@ function RouterSettingsCard(props) {
14908
15057
  props.resetField("toolNpmRegistry");
14909
15058
  }
14910
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
+ }
14911
15078
  ), /* @__PURE__ */ import_react6.default.createElement(
14912
15079
  import_dsh_client_ui_primitives.SettingsValueField,
14913
15080
  {