mu-agent 0.1.8 → 0.1.13

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.
Files changed (176) hide show
  1. package/CHANGELOG.md +121 -0
  2. package/README.md +34 -30
  3. package/dist/bundle/chunks/anthropic-messages-4PAJY4R6.js +6 -0
  4. package/dist/bundle/chunks/anthropic.js +1 -1
  5. package/dist/bundle/chunks/azure-openai-responses-Y4BBWQ3N.js +2 -0
  6. package/dist/bundle/chunks/bedrock-converse-stream.js +12 -9
  7. package/dist/bundle/chunks/{chunk-NG4PO5FP.js → chunk-3J3HSHLX.js} +128 -110
  8. package/dist/bundle/chunks/{chunk-TRDNDS6A.js → chunk-3V45WARH.js} +6 -3
  9. package/dist/bundle/chunks/{chunk-S3GGRYIO.js → chunk-5AGIVGSV.js} +1 -1
  10. package/dist/bundle/chunks/chunk-6QGV3IWD.js +6 -0
  11. package/dist/bundle/chunks/{chunk-4OBXYPH4.js → chunk-6Z2347ML.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-F5ZABL6Z.js → chunk-7CBJINYJ.js} +2 -2
  13. package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-7DDKXS2Q.js} +1 -1
  14. package/dist/bundle/chunks/{chunk-H3QXYIF7.js → chunk-CF5GWZHW.js} +1 -1
  15. package/dist/bundle/chunks/{chunk-RLZVFGW4.js → chunk-DYTENXHX.js} +29 -92
  16. package/dist/bundle/chunks/{chunk-NTSWBG4X.js → chunk-FLHKNMLQ.js} +1 -1
  17. package/dist/bundle/chunks/chunk-FTJT2X6E.js +2 -0
  18. package/dist/bundle/chunks/{chunk-4L3WN2XY.js → chunk-JXWJOIH4.js} +1 -1
  19. package/dist/bundle/chunks/{chunk-TAOL3JFA.js → chunk-KIDDRTZP.js} +4 -4
  20. package/dist/bundle/chunks/chunk-LHRPMXVI.js +2 -0
  21. package/dist/bundle/chunks/chunk-LMNWTX2L.js +11 -0
  22. package/dist/bundle/chunks/chunk-LPXNMA2W.js +2 -0
  23. package/dist/bundle/chunks/chunk-LT2C56HV.js +130 -0
  24. package/dist/bundle/chunks/{chunk-6CYCI3EJ.js → chunk-LVVZS2NO.js} +1 -1
  25. package/dist/bundle/chunks/chunk-MF3VB62R.js +91 -0
  26. package/dist/bundle/chunks/chunk-NN4BEPYX.js +2 -0
  27. package/dist/bundle/chunks/{chunk-LD2P6SFZ.js → chunk-PMRZO46Y.js} +1 -1
  28. package/dist/bundle/chunks/chunk-R4VPBBDS.js +2 -0
  29. package/dist/bundle/chunks/chunk-RDZVAGPR.js +2 -0
  30. package/dist/bundle/chunks/chunk-TMTOQ7H7.js +2 -0
  31. package/dist/bundle/chunks/chunk-UKVNB6C4.js +2 -0
  32. package/dist/bundle/chunks/chunk-URBBMV3M.js +9 -0
  33. package/dist/bundle/chunks/chunk-WCGU75WO.js +11 -0
  34. package/dist/bundle/chunks/chunk-WCJNJQO5.js +9 -0
  35. package/dist/bundle/chunks/chunk-WDURT4ZM.js +2 -0
  36. package/dist/bundle/chunks/{cli-AOVD3SSZ.js → cli-M4YBZZ6Q.js} +4 -4
  37. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-MEZHQVNP.js +2 -0
  38. package/dist/bundle/chunks/codemode-worker.js +117 -13
  39. package/dist/bundle/chunks/easter-egg-3d-VFY3YRQR.js +2 -0
  40. package/dist/bundle/chunks/execute-FKI7Y4XR.js +499 -0
  41. package/dist/bundle/chunks/github-copilot.js +1 -1
  42. package/dist/bundle/chunks/{google-generative-ai-XMFHGQC5.js → google-generative-ai-D2VJQBTK.js} +1 -1
  43. package/dist/bundle/chunks/{google-vertex-4XRRNP74.js → google-vertex-SQG2BO6C.js} +1 -1
  44. package/dist/bundle/chunks/https-proxy-agent-LVOO5TPL.js +13 -0
  45. package/dist/bundle/chunks/image-resize-worker.js +1 -1
  46. package/dist/bundle/chunks/{jiti-loader-C3NU2SDH.js → jiti-loader-GL4HJFAD.js} +1 -1
  47. package/dist/bundle/chunks/{jiti-static-loader-E6ANQD5T.js → jiti-static-loader-2RCDI6B4.js} +1 -1
  48. package/dist/bundle/chunks/{lib-TEDK3E5I.js → lib-4AVRLBHM.js} +1 -1
  49. package/dist/bundle/chunks/{llama-cpp-classify-XT44PI3C.js → llama-cpp-classify-5YHLY3RC.js} +2 -2
  50. package/dist/bundle/chunks/mistral-conversations-BDARVJTT.js +5 -0
  51. package/dist/bundle/chunks/{multipart-parser-SQ6GDJL7.js → multipart-parser-FMGQ7342.js} +1 -1
  52. package/dist/bundle/chunks/{node-TWVVAGPO.js → node-AUOGOBCN.js} +1 -1
  53. package/dist/bundle/chunks/{node-N5BSDOA5.js → node-KCMANYC2.js} +1 -1
  54. package/dist/bundle/chunks/openai-chatgpt.js +1 -1
  55. package/dist/bundle/chunks/openai-codex-responses-CECGTDYD.js +10 -0
  56. package/dist/bundle/chunks/openai-codex.js +1 -1
  57. package/dist/bundle/chunks/openai-completions-UOA7MELD.js +7 -0
  58. package/dist/bundle/chunks/openai-decisions-HLM372N6.js +5 -0
  59. package/dist/bundle/chunks/openai-responses-TII7ZY5X.js +3 -0
  60. package/dist/bundle/chunks/{openrouter-images-ZVXWCSIM.js → openrouter-images-7T452AS5.js} +1 -1
  61. package/dist/bundle/chunks/{pi-messages-TM5SOOIW.js → pi-messages-2UDKLKOO.js} +1 -1
  62. package/dist/bundle/chunks/runtime-IKE5OQIW.js +2 -0
  63. package/dist/bundle/chunks/{src-UK77SYZE.js → src-QKGKDFSU.js} +1 -1
  64. package/dist/bundle/chunks/typesafe-system-one-KNCICMO5.js +2 -0
  65. package/dist/bundle/chunks/virtual-modules-TJPHLTRT.js +2 -0
  66. package/dist/bundle/cli-runtime.js +1 -1
  67. package/dist/bundle/index.js +1 -1
  68. package/dist/bundle/rpc-entry.js +1 -1
  69. package/dist/core/export-html/template.js +21 -16
  70. package/dist/modes/interactive/theme/dark.json +1 -1
  71. package/dist/modes/interactive/theme/light.json +1 -1
  72. package/dist/modes/interactive/theme/theme-schema.d.ts +28 -0
  73. package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
  74. package/dist/modes/interactive/theme/theme-schema.js +105 -0
  75. package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
  76. package/dist/modes/interactive/theme/theme-tokens.d.ts +257 -0
  77. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -0
  78. package/dist/modes/interactive/theme/theme-tokens.js +94 -0
  79. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -0
  80. package/dist/modes/interactive/theme/theme.d.ts +13 -16
  81. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  82. package/dist/modes/interactive/theme/theme.js +22 -29
  83. package/dist/modes/interactive/theme/theme.js.map +1 -1
  84. package/docs/cli-integration.md +1 -1
  85. package/docs/cli.md +22 -10
  86. package/docs/codemode.md +29 -6
  87. package/docs/compaction.md +5 -5
  88. package/docs/custom-provider.md +53 -1
  89. package/docs/docs.json +8 -0
  90. package/docs/environment-variables.md +3 -1
  91. package/docs/extensions.md +122 -13
  92. package/docs/json.md +3 -3
  93. package/docs/keybindings.md +5 -4
  94. package/docs/llama-cpp.md +9 -2
  95. package/docs/mcp.md +4 -2
  96. package/docs/message-types.md +22 -4
  97. package/docs/models-configuration.md +187 -0
  98. package/docs/models.md +18 -2
  99. package/docs/nvidia-rtx-llama-cpp.md +96 -0
  100. package/docs/providers.md +47 -0
  101. package/docs/sessions.md +1 -1
  102. package/docs/settings.md +9 -6
  103. package/docs/terminal-setup.md +14 -0
  104. package/docs/themes.md +4 -2
  105. package/docs/tui.md +71 -1
  106. package/docs/usage.md +1 -1
  107. package/examples/README.md +0 -3
  108. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  109. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  110. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  111. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  112. package/examples/extensions/gondolin/package-lock.json +2 -2
  113. package/examples/extensions/gondolin/package.json +1 -1
  114. package/examples/extensions/minimal-mode.ts +4 -5
  115. package/examples/extensions/overlay-test.ts +2 -2
  116. package/examples/extensions/plan-mode/index.ts +6 -2
  117. package/examples/extensions/sandbox/package-lock.json +2 -2
  118. package/examples/extensions/sandbox/package.json +1 -1
  119. package/examples/extensions/subagent/index.ts +4 -6
  120. package/examples/extensions/with-deps/package-lock.json +2 -2
  121. package/examples/extensions/with-deps/package.json +1 -1
  122. package/judge/dist/auth.js +91 -35
  123. package/judge/dist/chrome.js +2 -2
  124. package/judge/dist/import.js +852 -175
  125. package/judge/dist/setup.js +240 -153
  126. package/judge/manifest.json +2512 -546
  127. package/judge/mu/chunk-3NQ5BIBI.js +4773 -0
  128. package/judge/mu/chunk-SKGYWHW6.js +51 -0
  129. package/judge/mu/chunk-WQM4MV6L.js +58 -0
  130. package/judge/mu/cloud-code-V7FOGB4J.js +22802 -0
  131. package/judge/mu/dist-75PS4OC4.js +1283 -0
  132. package/judge/{dist/kyrn-judge.js → mu/index.js} +5365 -32809
  133. package/judge/mu/multipart-parser-ZDXVIOOP.js +372 -0
  134. package/judge/mu/src-TVVA5ZK2.js +1409 -0
  135. package/judge/themes/mu-dark.json +80 -0
  136. package/judge/themes/mu-light.json +80 -0
  137. package/kyrn/bin/kyrn-doctor +44 -19
  138. package/kyrn/bin/kyrn-judge-local +43 -14
  139. package/kyrn/bin/kyrn-ledger +16 -1
  140. package/kyrn/bin/mu.mjs +142 -61
  141. package/kyrn/local-judge/server.py +26 -14
  142. package/package.json +8 -6
  143. package/dist/bundle/chunks/anthropic-messages-MI4QHRXW.js +0 -6
  144. package/dist/bundle/chunks/azure-openai-responses-E3QGN4VN.js +0 -2
  145. package/dist/bundle/chunks/chunk-33KL6IIQ.js +0 -20
  146. package/dist/bundle/chunks/chunk-A3JYRWB6.js +0 -2
  147. package/dist/bundle/chunks/chunk-C47CLQZK.js +0 -2
  148. package/dist/bundle/chunks/chunk-HQHD6PZI.js +0 -2
  149. package/dist/bundle/chunks/chunk-KJUDFE6Y.js +0 -11
  150. package/dist/bundle/chunks/chunk-TE3GUV6H.js +0 -9
  151. package/dist/bundle/chunks/chunk-VIV3CWXG.js +0 -2
  152. package/dist/bundle/chunks/chunk-WE4MXUQS.js +0 -11
  153. package/dist/bundle/chunks/chunk-Y2PP32XV.js +0 -2
  154. package/dist/bundle/chunks/chunk-YLY6CKPK.js +0 -132
  155. package/dist/bundle/chunks/chunk-ZE5FMF3V.js +0 -99
  156. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NM3JRRWQ.js +0 -2
  157. package/dist/bundle/chunks/easter-egg-3d-G2LUBEMZ.js +0 -2
  158. package/dist/bundle/chunks/execute-MZVUC6BB.js +0 -388
  159. package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +0 -13
  160. package/dist/bundle/chunks/mistral-conversations-Q22M3IBG.js +0 -5
  161. package/dist/bundle/chunks/openai-codex-responses-4MYQSO5E.js +0 -10
  162. package/dist/bundle/chunks/openai-completions-OSRCWAAA.js +0 -7
  163. package/dist/bundle/chunks/openai-responses-UHF3DHNG.js +0 -3
  164. package/dist/bundle/chunks/runtime-VJMMDLVH.js +0 -2
  165. package/dist/bundle/chunks/typesafe-system-one-PRR5K6CI.js +0 -2
  166. package/dist/bundle/chunks/virtual-modules-RJXJGCPI.js +0 -2
  167. package/dist/modes/interactive/theme/theme-json.d.ts +0 -85
  168. package/dist/modes/interactive/theme/theme-json.d.ts.map +0 -1
  169. package/dist/modes/interactive/theme/theme-json.js +0 -132
  170. package/dist/modes/interactive/theme/theme-json.js.map +0 -1
  171. package/dist/modes/interactive/theme/theme-schema.json +0 -361
  172. package/examples/plugins/pi-example-plugin/README.md +0 -38
  173. package/examples/plugins/pi-example-plugin/package.json +0 -10
  174. package/examples/plugins/pi-example-plugin/src/contract.ts +0 -13
  175. package/examples/plugins/pi-example-plugin/src/session.ts +0 -24
  176. package/examples/plugins/pi-example-plugin/src/tui.ts +0 -31
@@ -328,6 +328,16 @@ function tiersOf(config) {
328
328
  function withTiers(config, tiers) {
329
329
  return { ...config, tiers: [...tiers] };
330
330
  }
331
+ function judgeOff(config) {
332
+ return isRecord(config?.modes) && config.modes.default === "off";
333
+ }
334
+ function withJudge(config, on) {
335
+ const { default: _default, ...modes } = isRecord(config.modes) ? config.modes : {};
336
+ if (!on) return { ...config, modes: { default: "off", ...modes } };
337
+ if (!judgeOff(config)) return config;
338
+ const { modes: _modes, ...rest } = config;
339
+ return Object.keys(modes).length > 0 ? { ...rest, modes } : rest;
340
+ }
331
341
  function readTextFile(path) {
332
342
  try {
333
343
  return readFileSync(path, "utf8");
@@ -378,14 +388,17 @@ function piAccess(runtime, agentDir2) {
378
388
  storeKey: async (provider, key) => {
379
389
  await runtime.refresh({ allowNetwork: false, providers: [provider] });
380
390
  if (!runtime.getProvider(provider)) {
381
- throw new Error(`pi has no provider ${provider}${runtime.getError() ? `: ${runtime.getError()}` : ""}`);
391
+ throw new Error(
392
+ `mu has no provider named ${provider}${runtime.getError() ? `: ${runtime.getError()}` : ""}`
393
+ );
382
394
  }
383
395
  let asked = false;
384
396
  try {
385
397
  await runtime.login(provider, "api_key", {
386
398
  // pi's key login asks one question, the key. Anything else is not answered, and nothing is guessed.
387
399
  prompt: async (prompt) => {
388
- if (asked || prompt.type !== "secret") throw new Error(`pi asked ${provider} for more than a key`);
400
+ if (asked || prompt.type !== "secret")
401
+ throw new Error(`the sign-in for ${provider} asked for more than a key`);
389
402
  asked = true;
390
403
  return key;
391
404
  },
@@ -459,11 +472,31 @@ function askSecret(input, output, question) {
459
472
  input.resume();
460
473
  });
461
474
  }
475
+ var columnsOf = (char) => /[\u1100-\u115f\u2e80-\ua4cf\uac00-\ud7a3\uf900-\ufaff\ufe30-\ufe4f\uff00-\uff60\uffe0-\uffe6]/u.test(char) ? 2 : 1;
476
+ var widthOf = (text) => Array.from(text).reduce((sum, char) => sum + columnsOf(char), 0);
477
+ function wrapToWidth(text, width) {
478
+ if (!width || width < 20) return text;
479
+ return text.split("\n").map((line) => {
480
+ if (widthOf(line) <= width) return line;
481
+ const indent = " ".repeat(/^\s*(?:\d+\)\s+)?/.exec(line)?.[0].length ?? 0);
482
+ const out = [];
483
+ let current = "";
484
+ for (const word of line.trimEnd().split(/(?<=\S) (?=\S)/)) {
485
+ const next = current ? `${current} ${word}` : word;
486
+ if (current && widthOf(next) > width) {
487
+ out.push(current);
488
+ current = `${indent}${word.trimStart()}`;
489
+ } else current = next;
490
+ }
491
+ out.push(current);
492
+ return out.join("\n");
493
+ }).join("\n");
494
+ }
462
495
  function terminalPrompter(input = process.stdin, output = process.stdout, errors = process.stderr) {
463
496
  return {
464
- say: (text) => output.write(`${text}
497
+ say: (text) => output.write(`${wrapToWidth(text, output.isTTY ? output.columns : void 0)}
465
498
  `),
466
- warn: (text) => errors.write(`${text}
499
+ warn: (text) => errors.write(`${wrapToWidth(text, errors.isTTY ? errors.columns : void 0)}
467
500
  `),
468
501
  ask: (question) => askLine(input, output, question),
469
502
  secret: (question) => askSecret(input, output, question)
@@ -641,41 +674,41 @@ function explainProblem(problem, context, language) {
641
674
  const host = hostOf(problem.url);
642
675
  const seconds = Math.round((context.timeoutMs ?? CHECK_TIMEOUT_MS) / 1e3);
643
676
  const local = /^(localhost|127\.|\[::1\])/.test(host);
644
- const proxyHint = language === "zh" ? context.proxy ? `\u8FD9\u6B21\u8BF7\u6C42\u8D70\u4E86\u4EE3\u7406\uFF08${context.proxy}\uFF09\uFF0C\u786E\u8BA4\u4EE3\u7406\u6B63\u5728\u8FD0\u884C\u3002` : "\u5982\u679C\u9700\u8981\u4EE3\u7406\uFF1A\u8BBE\u7F6E HTTPS_PROXY\uFF0C\u6216\u5728 ~/.mu/agent/settings.json \u91CC\u5199 httpProxy\uFF0C\u7136\u540E\u91CD\u65B0\u8FD0\u884C mu setup\u3002" : context.proxy ? `The request went through your proxy (${context.proxy}): check that it is running.` : "If you need a proxy, set HTTPS_PROXY (or httpProxy in ~/.mu/agent/settings.json) and run mu setup again.";
677
+ const proxyHint = language === "zh" ? context.proxy ? `\u8FD9\u6B21\u8BF7\u6C42\u8D70\u4E86\u4EE3\u7406\uFF08${context.proxy}\uFF09\uFF0C\u786E\u8BA4\u4EE3\u7406\u6B63\u5728\u8FD0\u884C\u3002` : "\u5982\u679C\u9700\u8981\u4EE3\u7406\uFF1A\u8BBE\u7F6E HTTPS_PROXY\uFF0C\u6216\u5728 ~/.mu/agent/settings.json \u91CC\u5199 httpProxy\uFF0C\u7136\u540E\u91CD\u65B0\u8FD0\u884C mu setup\u3002" : context.proxy ? `The request went through your proxy (${context.proxy}). Check that it's running.` : "If you need a proxy, set HTTPS_PROXY (or httpProxy in ~/.mu/agent/settings.json) and run mu setup again.";
645
678
  const said = problem.said ? language === "zh" ? `\uFF08\u670D\u52A1\u7684\u539F\u8BDD\uFF1A${problem.said}\uFF09` : ` (The service said: ${problem.said})` : "";
646
679
  const zh = language === "zh";
647
680
  switch (problem.kind) {
648
681
  case "key":
649
- return zh ? `${service} \u4E0D\u63A5\u53D7\u8FD9\u4E2A\u5BC6\u94A5\u3002\u68C0\u67E5\u662F\u5426\u5B8C\u6574\u590D\u5236\uFF0C\u4EE5\u53CA\u5B83\u786E\u5B9E\u662F ${service} \u7684\u5BC6\u94A5\u3002` : `${service} does not accept this key. Check that you copied all of it, and that it is ${article(service)} key.`;
682
+ return zh ? `${service} \u4E0D\u63A5\u53D7\u8FD9\u4E2A\u5BC6\u94A5\u3002\u68C0\u67E5\u662F\u5426\u5B8C\u6574\u590D\u5236\uFF0C\u4EE5\u53CA\u5B83\u786E\u5B9E\u662F ${service} \u7684\u5BC6\u94A5\u3002` : `${service} didn't accept this key. Check that you copied all of it and that it's ${article(service)} key.`;
650
683
  case "refused":
651
- return zh ? `${service} \u62D2\u7EDD\u4E86\u8FD9\u4E2A\u5BC6\u94A5\uFF08HTTP 403\uFF09\uFF1A\u53EF\u80FD\u662F\u5BC6\u94A5\u4E0D\u5BF9\uFF0C\u6216\u5B83\u6CA1\u6709\u8BBF\u95EE\u6743\u9650\u3002${said}` : `${service} refused this key (HTTP 403): it may be wrong, or not allowed access.${said}`;
684
+ return zh ? `${service} \u62D2\u7EDD\u4E86\u8FD9\u4E2A\u5BC6\u94A5\uFF08HTTP 403\uFF09\uFF1A\u53EF\u80FD\u662F\u5BC6\u94A5\u4E0D\u5BF9\uFF0C\u6216\u5B83\u6CA1\u6709\u8BBF\u95EE\u6743\u9650\u3002${said}` : `${service} refused this key (HTTP 403). The key may be wrong or lack access.${said}`;
652
685
  case "permission":
653
- return zh ? "\u8FD9\u4E2A\u5BC6\u94A5\u6709\u6548\uFF0C\u4F46\u6CA1\u6709\u8BFB\u53D6\u6A21\u578B\u5217\u8868\u7684\u6743\u9650\uFF08\u53D7\u9650\u5BC6\u94A5\uFF09\u3002\u7ED9\u5B83\u8BFB\u53D6\u6A21\u578B\u7684\u6743\u9650\uFF0C\u6216\u6362\u4E00\u4E2A\u5BC6\u94A5\u3002" : "The key works, but may not read the list of models (a restricted key). Allow it to read models, or use another key.";
686
+ return zh ? "\u8FD9\u4E2A\u5BC6\u94A5\u6709\u6548\uFF0C\u4F46\u6CA1\u6709\u8BFB\u53D6\u6A21\u578B\u5217\u8868\u7684\u6743\u9650\uFF08\u53D7\u9650\u5BC6\u94A5\uFF09\u3002\u7ED9\u5B83\u8BFB\u53D6\u6A21\u578B\u7684\u6743\u9650\uFF0C\u6216\u6362\u4E00\u4E2A\u5BC6\u94A5\u3002" : "The key works but can't list models (it's a restricted key). Give it permission to read models, or use another key.";
654
687
  case "balance":
655
688
  return zh ? `${service} \u7684\u8D26\u6237\u6CA1\u6709\u4F59\u989D\u6216\u989D\u5EA6\u4E86\u3002\u5145\u503C\u540E\u91CD\u65B0\u8FD0\u884C mu setup\u3002` : `The ${service} account has no balance or quota left. Top it up, then run mu setup again.`;
656
689
  case "region":
657
- return zh ? `${service} \u4E0D\u5411\u4F60\u6240\u5728\u7684\u5730\u533A\u63D0\u4F9B\u670D\u52A1\u3002\u9700\u8981\u4E00\u4E2A\u4F4D\u4E8E\u652F\u6301\u5730\u533A\u7684\u4EE3\u7406\u6216 VPN\u3002${proxyHint}` : `${service} does not serve the region this request came from. A proxy or VPN in a supported region is needed. ${proxyHint}`;
690
+ return zh ? `${service} \u4E0D\u5411\u4F60\u6240\u5728\u7684\u5730\u533A\u63D0\u4F9B\u670D\u52A1\u3002\u9700\u8981\u4E00\u4E2A\u4F4D\u4E8E\u652F\u6301\u5730\u533A\u7684\u4EE3\u7406\u6216 VPN\u3002${proxyHint}` : `${service} isn't available in the region this request came from. You need a proxy or VPN in a supported region. ${proxyHint}`;
658
691
  case "rate":
659
- return zh ? `${service} \u8BF4\u8BF7\u6C42\u592A\u9891\u7E41\u3002\u7B49\u4E00\u5206\u949F\u518D\u8BD5\u3002` : `${service} says there were too many requests. Wait a minute and try again.`;
692
+ return zh ? `${service} \u8BF4\u8BF7\u6C42\u592A\u9891\u7E41\u3002\u7B49\u4E00\u5206\u949F\u518D\u8BD5\u3002` : `${service} is getting too many requests from you. Wait a minute and try again.`;
660
693
  case "address":
661
- return zh ? `${problem.url} \u8FD9\u4E2A\u5730\u5740\u4E0D\u5B58\u5728\uFF08HTTP 404\uFF09\uFF1A\u5730\u5740\u586B\u9519\u4E86\u3002` : `Nothing answers at ${problem.url} (HTTP 404): the address is wrong.`;
694
+ return zh ? `${problem.url} \u8FD9\u4E2A\u5730\u5740\u4E0D\u5B58\u5728\uFF08HTTP 404\uFF09\uFF1A\u5730\u5740\u586B\u9519\u4E86\u3002` : `Nothing was found at ${problem.url} (HTTP 404). Check the address.`;
662
695
  case "server":
663
- return zh ? `${service} \u81EA\u5DF1\u51FA\u9519\u4E86\uFF08HTTP ${problem.status}\uFF09\u3002\u8FC7\u4E00\u4F1A\u513F\u518D\u8BD5\u3002` : `${service} had an error of its own (HTTP ${problem.status}). Try again in a while.`;
696
+ return zh ? `${service} \u81EA\u5DF1\u51FA\u9519\u4E86\uFF08HTTP ${problem.status}\uFF09\u3002\u8FC7\u4E00\u4F1A\u513F\u518D\u8BD5\u3002` : `${service} returned a server error (HTTP ${problem.status}). Try again later.`;
664
697
  case "response":
665
- return zh ? `${problem.url} \u6709\u56DE\u5E94\uFF0C\u4F46\u4E0D\u662F\u6A21\u578B\u5217\u8868\uFF1A\u68C0\u67E5\u5730\u5740\u548C\u63A5\u53E3\u7C7B\u578B\u3002` : `${problem.url} answered, but not with a list of models: check the address and the API type.`;
698
+ return zh ? `${problem.url} \u6709\u56DE\u5E94\uFF0C\u4F46\u4E0D\u662F\u6A21\u578B\u5217\u8868\uFF1A\u68C0\u67E5\u5730\u5740\u548C\u63A5\u53E3\u7C7B\u578B\u3002` : `${problem.url} responded, but not with a list of models. Check the address and the API type.`;
666
699
  case "timeout":
667
- return zh ? `${seconds} \u79D2\u5185 ${host} \u6CA1\u6709\u56DE\u5E94\u3002\u7F51\u7EDC\u53EF\u80FD\u4E0D\u901A\uFF1A\u6709\u4E9B\u5730\u533A\u8981\u7528\u4EE3\u7406\u6216 VPN \u624D\u80FD\u8BBF\u95EE\u3002${proxyHint}` : `No answer from ${host} within ${seconds} s. The network may block it: in some regions a proxy or VPN is needed. ${proxyHint}`;
700
+ return zh ? `${seconds} \u79D2\u5185 ${host} \u6CA1\u6709\u56DE\u5E94\u3002\u7F51\u7EDC\u53EF\u80FD\u4E0D\u901A\uFF1A\u6709\u4E9B\u5730\u533A\u8981\u7528\u4EE3\u7406\u6216 VPN \u624D\u80FD\u8BBF\u95EE\u3002${proxyHint}` : `No response from ${host} within ${seconds} s. The network may be blocking it; some regions need a proxy or VPN. ${proxyHint}`;
668
701
  case "dns":
669
- return zh ? `\u627E\u4E0D\u5230 ${host}\uFF1A\u6CA1\u6709\u8054\u7F51\uFF0C\u6216\u8FD9\u91CC\u89E3\u6790\u4E0D\u4E86\u8FD9\u4E2A\u57DF\u540D\u3002${proxyHint}` : `Could not find ${host}: there is no internet connection, or the name cannot be resolved here. ${proxyHint}`;
702
+ return zh ? `\u627E\u4E0D\u5230 ${host}\uFF1A\u6CA1\u6709\u8054\u7F51\uFF0C\u6216\u8FD9\u91CC\u89E3\u6790\u4E0D\u4E86\u8FD9\u4E2A\u57DF\u540D\u3002${proxyHint}` : `Couldn't resolve ${host}. Check your internet connection and DNS. ${proxyHint}`;
670
703
  case "connection":
671
704
  if (local) {
672
- return zh ? `${host} \u4E0A\u6CA1\u6709\u670D\u52A1\u5728\u76D1\u542C\uFF1A\u5B83\u542F\u52A8\u4E86\u5417\uFF1F` : `Nothing is listening at ${host}: is the service running?`;
705
+ return zh ? `${host} \u4E0A\u6CA1\u6709\u670D\u52A1\u5728\u76D1\u542C\uFF1A\u5B83\u542F\u52A8\u4E86\u5417\uFF1F` : `Nothing is listening at ${host}. Is the service running?`;
673
706
  }
674
- return zh ? `\u8FDE\u4E0D\u4E0A ${host}\u3002${proxyHint}` : `Could not connect to ${host}. ${proxyHint}`;
707
+ return zh ? `\u8FDE\u4E0D\u4E0A ${host}\u3002${proxyHint}` : `Couldn't connect to ${host}. ${proxyHint}`;
675
708
  case "tls":
676
- return zh ? `\u548C ${host} \u7684\u5B89\u5168\u8FDE\u63A5\u5931\u8D25\u4E86\uFF1A\u53EF\u80FD\u6709\u4EE3\u7406\u6216\u9632\u706B\u5899\u5728\u62E6\u622A HTTPS\u3002` : `The secure connection to ${host} failed: a proxy or firewall may be intercepting HTTPS.`;
709
+ return zh ? `\u548C ${host} \u7684\u5B89\u5168\u8FDE\u63A5\u5931\u8D25\u4E86\uFF1A\u53EF\u80FD\u6709\u4EE3\u7406\u6216\u9632\u706B\u5899\u5728\u62E6\u622A HTTPS\u3002` : `The secure connection to ${host} failed. A proxy or firewall may be intercepting HTTPS.`;
677
710
  default:
678
- return zh ? `${service} \u62D2\u7EDD\u4E86\u8FD9\u6B21\u68C0\u67E5\uFF08HTTP ${problem.status ?? "?"}\uFF09\u3002${said}` : `${service} refused the check (HTTP ${problem.status ?? "?"}).${said}`;
711
+ return zh ? `${service} \u62D2\u7EDD\u4E86\u8FD9\u6B21\u68C0\u67E5\uFF08HTTP ${problem.status ?? "?"}\uFF09\u3002${said}` : `${service} rejected the check (HTTP ${problem.status ?? "?"}).${said}`;
679
712
  }
680
713
  }
681
714
  async function opencodeRefuses(baseUrl, key, fetch, timeoutMs) {
@@ -809,7 +842,7 @@ var SETUP_SERVICES = [
809
842
  {
810
843
  id: "opencode",
811
844
  name: "OpenCode Zen",
812
- baseUrls: ["https://opencode.ai/zen/v1"],
845
+ baseUrls: ["https://opencode.ai/inference/v1"],
813
846
  api: "openai-completions",
814
847
  models: ["kimi-k2.6"],
815
848
  keyPage: "https://opencode.ai/auth",
@@ -885,6 +918,12 @@ var SETUP_SERVICES = [
885
918
  keyOptional: true
886
919
  }
887
920
  ];
921
+ var FIRST_IN_ENGLISH = ["openai", "anthropic", "google", "xai", "openrouter", "opencode"];
922
+ function servicesInOrder(language) {
923
+ if (language === "zh") return SETUP_SERVICES;
924
+ const first = FIRST_IN_ENGLISH.flatMap((id) => SETUP_SERVICES.filter((service) => service.id === id));
925
+ return [...first, ...SETUP_SERVICES.filter((service) => !FIRST_IN_ENGLISH.includes(service.id))];
926
+ }
888
927
  function serviceById(id) {
889
928
  return SETUP_SERVICES.find((service) => service.id === id);
890
929
  }
@@ -893,6 +932,9 @@ function cleanKey(raw) {
893
932
  if (key.length >= 2 && (key[0] === '"' || key[0] === "'") && key.at(-1) === key[0]) key = key.slice(1, -1).trim();
894
933
  return key;
895
934
  }
935
+ function isClaudeSubscriptionToken(key) {
936
+ return cleanKey(key).startsWith("sk-ant-oat");
937
+ }
896
938
  function servicesForKey(key) {
897
939
  const clean = cleanKey(key);
898
940
  return clean ? SETUP_SERVICES.filter((service) => service.keyShape?.test(clean)) : [];
@@ -939,7 +981,7 @@ function namedModel(service) {
939
981
 
940
982
  // packages/kyrn-judge/src/setup/wizard.ts
941
983
  var SETUP_DECLINED_FILE = "setup-declined";
942
- var SETUP_EXIT = { done: 0, failed: 1, usage: 2, start: 3, cancelled: 130 };
984
+ var SETUP_EXIT = { done: 0, failed: 1, usage: 2, start: 3, signIn: 4, cancelled: 130 };
943
985
  var SETUP_VALUE_FLAGS = [
944
986
  "--service",
945
987
  "--model",
@@ -970,6 +1012,10 @@ var JEV_TIERS = /* @__PURE__ */ new Set([
970
1012
  ]);
971
1013
  var OPENCODE_KEY = "OPENCODE_API_KEY";
972
1014
  var JEV_PAGE = "https://typesafe.ai";
1015
+ var CLAUDE_TOKEN = {
1016
+ zh: "\u8FD9\u662F Claude \u8BA2\u9605\u4EE4\u724C\uFF08claude setup-token \u751F\u6210\u7684\uFF09\uFF0C\u4E0D\u662F API \u5BC6\u94A5\u3002Anthropic \u4E0D\u5141\u8BB8\u5176\u4ED6\u5E94\u7528\u4F7F\u7528 Claude \u8BA2\u9605\uFF0C\u6240\u4EE5 mu \u7528\u4E0D\u4E86\u5B83\u3002\u8BF7\u6539\u7528 Anthropic API \u5BC6\u94A5\uFF08sk-ant-api\u2026\uFF09\uFF0C\u5728\u8FD9\u91CC\u521B\u5EFA\uFF1Ahttps://platform.claude.com/settings/keys",
1017
+ en: "That's a Claude subscription token (from claude setup-token), not an API key. Anthropic doesn't allow other apps to use a Claude subscription, so mu can't use it. Use an Anthropic API key (sk-ant-api\u2026) instead; create one at https://platform.claude.com/settings/keys"
1018
+ };
973
1019
  var BRANDED = /* @__PURE__ */ new Set(["openai", "anthropic", "openrouter", "google", "xai"]);
974
1020
  var OTHER = {
975
1021
  zh: "\u5176\u4ED6 OpenAI \u6216 Anthropic \u517C\u5BB9\u7684\u670D\u52A1",
@@ -977,7 +1023,7 @@ var OTHER = {
977
1023
  };
978
1024
  var NOT_READY = {
979
1025
  zh: "Ollama \u8FD8\u6CA1\u51C6\u5907\u597D\uFF08\u7528 `ollama serve` \u542F\u52A8\u5B83\uFF0C\u518D\u62C9\u53D6\u4E00\u4E2A\u6A21\u578B\uFF09\u3002",
980
- en: "Ollama is not ready yet (start it with `ollama serve`, pull a model)."
1026
+ en: "Ollama isn't ready yet. Start it with `ollama serve`, then pull a model."
981
1027
  };
982
1028
  function parseSetupArgs(argv) {
983
1029
  const values = /* @__PURE__ */ new Map();
@@ -1000,14 +1046,14 @@ function parseSetupArgs(argv) {
1000
1046
  }
1001
1047
  const api = values.get("--api");
1002
1048
  if (api !== void 0 && api !== "openai" && api !== "anthropic") {
1003
- return { error: { zh: "--api \u53EA\u80FD\u662F openai \u6216 anthropic", en: "--api is openai or anthropic" } };
1049
+ return { error: { zh: "--api \u53EA\u80FD\u662F openai \u6216 anthropic", en: "--api must be openai or anthropic" } };
1004
1050
  }
1005
1051
  const judge = values.get("--judge");
1006
- if (judge !== void 0 && !["jev", "opencode", "free", "model", "none"].includes(judge)) {
1052
+ if (judge !== void 0 && !["jev", "opencode", "free", "model", "off", "none"].includes(judge)) {
1007
1053
  return {
1008
1054
  error: {
1009
- zh: "--judge \u53EA\u80FD\u662F jev\u3001opencode\u3001free\u3001model \u6216 none",
1010
- en: "--judge is jev, opencode, free, model or none"
1055
+ zh: "--judge \u53EA\u80FD\u662F jev\u3001opencode\u3001free\u3001model\u3001off \u6216 none",
1056
+ en: "--judge must be jev, opencode, free, model, off or none"
1011
1057
  }
1012
1058
  };
1013
1059
  }
@@ -1016,11 +1062,11 @@ function parseSetupArgs(argv) {
1016
1062
  return {
1017
1063
  error: {
1018
1064
  zh: `\u6CA1\u6709\u53EB ${service} \u7684\u670D\u52A1\uFF08mu setup --list \u5217\u51FA\u5168\u90E8\uFF09`,
1019
- en: `there is no service called ${service} (mu setup --list shows them)`
1065
+ en: `no service named ${service} (mu setup --list shows them all)`
1020
1066
  }
1021
1067
  };
1022
1068
  }
1023
- if (words.length > 1) return { error: { zh: "\u53EA\u80FD\u7ED9\u4E00\u4E2A\u5BC6\u94A5", en: "give one key at most" } };
1069
+ if (words.length > 1) return { error: { zh: "\u53EA\u80FD\u7ED9\u4E00\u4E2A\u5BC6\u94A5", en: "give at most one key" } };
1024
1070
  return {
1025
1071
  help: flags.has("help"),
1026
1072
  list: flags.has("list"),
@@ -1050,42 +1096,44 @@ function setupUsage(language) {
1050
1096
  "\u4E3A\u4EC0\u4E48\u811A\u672C\u8981\u4ECE\u6807\u51C6\u8F93\u5165\u7ED9\u5BC6\u94A5\uFF1A\u5199\u5728\u547D\u4EE4\u884C\u4E0A\u7684\u5BC6\u94A5\u4F1A\u7559\u5728 shell \u7684\u5386\u53F2\u8BB0\u5F55\u91CC\uFF0C",
1051
1097
  "\u8FD9\u53F0\u7535\u8111\u4E0A\u80FD\u5217\u51FA\u8FDB\u7A0B\u7684\u7A0B\u5E8F\u4E5F\u90FD\u770B\u5F97\u5230\u5B83\u3002mu setup <\u5BC6\u94A5> \u53EA\u662F\u4E3A\u4E86\u4E0A\u624B\u5FEB\uFF1B\u80FD\u5728\u63D0\u793A\u91CC\u7C98\u8D34\u5C31\u7C98\u8D34\u3002",
1052
1098
  "",
1053
- " --judge jev Jev \u5BC6\u94A5\uFF08TypeSafe\uFF09\u5199\u5728\u6807\u51C6\u8F93\u5165\u7684\u7B2C\u4E8C\u884C\uFF1B\u5DF2\u7ECF\u8BBE\u7F6E\u4E86 TYPESAFE_API_KEY \u5C31\u4E0D\u7528",
1099
+ " --judge jev Jev \u5BC6\u94A5\uFF08TypeSafe\uFF09\u5199\u5728\u6807\u51C6\u8F93\u5165\u7684\u7B2C\u4E8C\u884C\uFF1B\u5DF2\u7ECF\u8BBE\u7F6E\u4E86 TYPESAFE_API_KEY \u5C31\u4E0D\u7528",
1054
1100
  " --judge opencode OpenCode Zen \u4E0A\u7684 Jev\uFF0C\u7528 OpenCode \u7684\u5BC6\u94A5\uFF08--service opencode \u6216 OPENCODE_API_KEY\uFF09",
1055
- " --judge free OpenCode Zen \u4E0A\u9650\u65F6\u514D\u8D39\u7684 Jev\uFF0C\u4E0D\u7528\u5BC6\u94A5\uFF08\u6CA1\u6709\u5BC6\u94A5\u65F6\u672C\u6765\u5C31\u7528\u5B83\uFF09",
1056
- " --judge model \u7528\u521A\u8BBE\u7F6E\u7684\u6A21\u578B\u5F53\u5224\u5B9A\u5668\uFF08\u66F4\u6162\uFF0C\u6BCF\u6B21\u5224\u65AD\u90FD\u82B1 token\uFF09",
1057
- " --judge none \u4E0D\u6539\u5224\u5B9A\u5668\uFF1B\u4E0D\u5199 --judge \u65F6\u4E5F\u4E0D\u6539",
1058
- " --api, --name \u670D\u52A1 other \u7684\u63A5\u53E3\uFF08openai \u6216 anthropic\uFF09\u548C\u5B83\u5728 mu \u91CC\u7684\u540D\u5B57",
1059
- " --yes \u4E0D\u63D0\u95EE\uFF1B\u66FF\u6362\u5DF2\u6709\u7684\u8BBE\u7F6E\uFF08\u8BA2\u9605\u767B\u5F55\u3001\u540C\u540D\u670D\u52A1\u7684\u5730\u5740\u3001Jev \u5BC6\u94A5\uFF09",
1101
+ " --judge free OpenCode Zen \u4E0A\u9650\u65F6\u514D\u8D39\u7684 Jev\uFF0C\u4E0D\u7528\u5BC6\u94A5\uFF08\u6CA1\u6709\u5BC6\u94A5\u65F6\u672C\u6765\u5C31\u7528\u5B83\uFF09",
1102
+ " --judge model \u7528\u521A\u8BBE\u7F6E\u7684\u6A21\u578B\u5F53\u5224\u5B9A\u5668\uFF08\u66F4\u6162\uFF0C\u6BCF\u6B21\u5224\u65AD\u90FD\u82B1 token\uFF09",
1103
+ " --judge off \u4E0D\u7528\u5224\u5B9A\u5668\uFF1A\u6240\u6709\u5224\u5B9A\u70B9\u5173\u95ED\uFF0C\u4EC0\u4E48\u90FD\u4E0D\u53D1\u7ED9\u5224\u5B9A\u5668",
1104
+ " --judge none \u4E0D\u6539\u5224\u5B9A\u5668\uFF1B\u4E0D\u5199 --judge \u65F6\u4E5F\u4E0D\u6539",
1105
+ " --api, --name \u670D\u52A1 other \u7684\u63A5\u53E3\uFF08openai \u6216 anthropic\uFF09\u548C\u5B83\u5728 mu \u91CC\u7684\u540D\u5B57",
1106
+ " --yes \u4E0D\u63D0\u95EE\uFF1B\u66FF\u6362\u5DF2\u6709\u7684\u8BBE\u7F6E\uFF08\u8BA2\u9605\u767B\u5F55\u3001\u540C\u540D\u670D\u52A1\u7684\u5730\u5740\u3001Jev \u5BC6\u94A5\uFF09",
1060
1107
  "",
1061
1108
  "\u4F1A\u6539\u52A8\u7684\u6587\u4EF6\uFF1A~/.mu/agent \u91CC\u7684 auth.json\uFF08\u5BC6\u94A5\uFF09\u3001models.json\u3001settings.json\u3001mu.json\uFF0C",
1062
1109
  "\u4EE5\u53CA mu \u8BFB\u53D6\u7684 .env\uFF08Jev \u5BC6\u94A5\uFF09\u3002\u6BCF\u4E2A\u6587\u4EF6\u6539\u52A8\u524D\u90FD\u4F1A\u5148\u590D\u5236\u5230 ~/.mu/backups/<\u65F6\u95F4>/\u3002"
1063
1110
  ].join("\n");
1064
1111
  }
1065
1112
  return [
1066
- "mu setup: connect a model for mu to work with, and choose its judge.",
1113
+ "mu setup: connect a model for mu to work with, and choose a judge.",
1067
1114
  "",
1068
- " mu setup asks step by step, in a terminal",
1069
- " mu setup <key> starts from an API key: mu tells by its shape which service it belongs to",
1115
+ " mu setup walks you through it, one question at a time",
1116
+ " mu setup <key> starts from an API key and detects its service from the key's format",
1070
1117
  " mu setup --service <id> --key-stdin [--model <id>] [--base-url <url>] [--judge <judge>] [--yes]",
1071
- " for scripts: the key is read from stdin",
1072
- " mu setup --list the services mu knows, with their ids",
1118
+ " for scripts: reads the key from stdin",
1119
+ " mu setup --list lists the services mu knows and their ids",
1073
1120
  "",
1074
- "Why stdin for scripts: a key on the command line stays in your shell's history, and every program on this",
1075
- "computer that lists processes can read it. `mu setup <key>` is there for a quick start; paste the key at the",
1076
- "prompt when you can.",
1121
+ "Why stdin for scripts: a key on the command line stays in your shell history, and any program on this",
1122
+ "computer that lists processes can read it. `mu setup <key>` is a shortcut for getting started; paste the key",
1123
+ "at the prompt when you can.",
1077
1124
  "",
1078
- " --judge jev the Jev key (TypeSafe) is the second line of stdin, unless TYPESAFE_API_KEY is set already",
1079
- " --judge opencode Jev on OpenCode Zen, with OpenCode's key (--service opencode, or OPENCODE_API_KEY)",
1080
- " --judge free Jev on OpenCode Zen, free for a limited time, with no key (what jev uses while no key is set)",
1081
- " --judge model the model just set up answers as the judge (slower, and every decision costs tokens)",
1082
- " --judge none leaves the judge as it is, as leaving out --judge does",
1083
- " --api, --name for the service `other`: its API (openai or anthropic) and its name in mu",
1084
- " --yes no questions; replaces what is set up already (a subscription sign-in, a provider's",
1085
- " address, the Jev key)",
1125
+ " --judge jev read the Jev key (TypeSafe) from stdin's second line, unless TYPESAFE_API_KEY is already set",
1126
+ " --judge opencode use Jev on OpenCode Zen with an OpenCode key (--service opencode or OPENCODE_API_KEY)",
1127
+ " --judge free use the free Jev on OpenCode Zen (limited time, no key; the default while no key is set)",
1128
+ " --judge model use the model you just set up as the judge (slower, and every verdict costs tokens)",
1129
+ " --judge off no judge: every decision point is off, and nothing is sent to a judge",
1130
+ " --judge none leave the judge unchanged (the same as omitting --judge)",
1131
+ " --api, --name for the service `other`: its API (openai or anthropic) and its name in mu",
1132
+ " --yes don't ask; replace what's already set up (a subscription sign-in, a provider's",
1133
+ " address, the Jev key)",
1086
1134
  "",
1087
- "Files: auth.json (keys), models.json, settings.json and mu.json in ~/.mu/agent, and the .env mu reads",
1088
- "(the Jev key). Each is copied to ~/.mu/backups/<time>/ before it changes."
1135
+ "Files it changes: auth.json (keys), models.json, settings.json and mu.json in ~/.mu/agent, and the .env",
1136
+ "mu reads (the Jev key). Each one is backed up to ~/.mu/backups/<time>/ before it changes."
1089
1137
  ].join("\n");
1090
1138
  }
1091
1139
  function label(service, language) {
@@ -1093,7 +1141,7 @@ function label(service, language) {
1093
1141
  }
1094
1142
  function serviceList(language) {
1095
1143
  const width = Math.max(...SETUP_SERVICES.map((service) => service.id.length));
1096
- return SETUP_SERVICES.map((service) => ` ${service.id.padEnd(width)} ${label(service, language)}`).join("\n");
1144
+ return servicesInOrder(language).map((service) => ` ${service.id.padEnd(width)} ${label(service, language)}`).join("\n");
1097
1145
  }
1098
1146
  function providerIdFor(baseUrl) {
1099
1147
  let host;
@@ -1202,10 +1250,14 @@ var Setup = class {
1202
1250
  if (key || allowEmpty) return key;
1203
1251
  }
1204
1252
  }
1205
- pasteKey() {
1206
- return this.secret(
1207
- this.t({ zh: "\u7C98\u8D34 API \u5BC6\u94A5\uFF08\u4E0D\u4F1A\u663E\u793A\u51FA\u6765\uFF09\uFF1A", en: "Paste the API key (it is not shown): " })
1208
- );
1253
+ async pasteKey() {
1254
+ for (; ; ) {
1255
+ const key = await this.secret(
1256
+ this.t({ zh: "\u7C98\u8D34 API \u5BC6\u94A5\uFF08\u4E0D\u4F1A\u663E\u793A\u51FA\u6765\uFF09\uFF1A", en: "Paste the API key (it won't be shown): " })
1257
+ );
1258
+ if (!isClaudeSubscriptionToken(key)) return key;
1259
+ this.io.warn(this.t(CLAUDE_TOKEN));
1260
+ }
1209
1261
  }
1210
1262
  async choose(question, choices) {
1211
1263
  this.io.say(question);
@@ -1216,7 +1268,7 @@ var Setup = class {
1216
1268
  if (answer === "") return choices[0].value;
1217
1269
  const number = Number(answer);
1218
1270
  if (Number.isInteger(number) && number >= 1 && number <= choices.length) return choices[number - 1].value;
1219
- this.io.say(this.t({ zh: `\u8BF7\u8F93\u5165 ${range} \u4E4B\u95F4\u7684\u6570\u5B57\u3002`, en: `Type a number from ${range}.` }));
1271
+ this.io.say(this.t({ zh: `\u8BF7\u8F93\u5165 ${range} \u4E4B\u95F4\u7684\u6570\u5B57\u3002`, en: `Type a number from 1 to ${choices.length}.` }));
1220
1272
  }
1221
1273
  }
1222
1274
  async confirm(question, yes) {
@@ -1236,7 +1288,7 @@ var Setup = class {
1236
1288
  throw this.fail(
1237
1289
  {
1238
1290
  zh: "--key-stdin \u4ECE\u7BA1\u9053\u8BFB\u5BC6\u94A5\u3002\u5728\u7EC8\u7AEF\u91CC\u8BF7\u76F4\u63A5\u8FD0\u884C mu setup\uFF0C\u5728\u63D0\u793A\u91CC\u7C98\u8D34\u5BC6\u94A5\uFF08\u4E0D\u4F1A\u663E\u793A\uFF09\u3002",
1239
- en: "--key-stdin reads the key from a pipe. In a terminal, run mu setup and paste the key at its prompt (it is not shown)."
1291
+ en: "--key-stdin reads the key from a pipe. In a terminal, run mu setup and paste the key at the prompt (it won't be shown)."
1240
1292
  },
1241
1293
  SETUP_EXIT.usage
1242
1294
  );
@@ -1245,11 +1297,12 @@ var Setup = class {
1245
1297
  key = modelKey;
1246
1298
  this.jevFromStdin = jevKey;
1247
1299
  }
1300
+ if (key !== void 0 && isClaudeSubscriptionToken(key)) throw this.fail(CLAUDE_TOKEN, SETUP_EXIT.usage);
1248
1301
  if (this.scripted && key === void 0 && args.service === void 0) {
1249
1302
  throw this.fail(
1250
- deps.interactive ? { zh: "\u6CA1\u6709\u5BC6\u94A5\uFF0C\u4E5F\u6CA1\u6709 --service", en: "no key and no --service were given" } : {
1303
+ deps.interactive ? { zh: "\u6CA1\u6709\u5BC6\u94A5\uFF0C\u4E5F\u6CA1\u6709 --service", en: "no key or --service given" } : {
1251
1304
  zh: "\u95EE\u9898\u8981\u5728\u7EC8\u7AEF\u91CC\u56DE\u7B54\u3002\u811A\u672C\u91CC\u7528\uFF1Amu setup --service <id> --key-stdin\uFF08\u89C1 mu setup --help\uFF09",
1252
- en: "its questions need a terminal. For a script: mu setup --service <id> --key-stdin (see mu setup --help)"
1305
+ en: "no terminal to ask in. In a script, use mu setup --service <id> --key-stdin (see mu setup --help)"
1253
1306
  },
1254
1307
  SETUP_EXIT.usage
1255
1308
  );
@@ -1258,14 +1311,14 @@ var Setup = class {
1258
1311
  this.io.say(
1259
1312
  this.t({
1260
1313
  zh: "mu setup\uFF1A\u7ED9 mu \u63A5\u4E0A\u4E00\u4E2A\u5E72\u6D3B\u7684\u6A21\u578B\uFF0C\u518D\u9009\u4E00\u4E2A\u5224\u5B9A\u5668\u3002",
1261
- en: "mu setup: connect a model for mu to work with, and choose its judge."
1314
+ en: "mu setup: connect a model for mu to work with, and choose a judge."
1262
1315
  })
1263
1316
  );
1264
1317
  }
1265
1318
  const start = await this.start(key === void 0 ? void 0 : cleanKey(key));
1266
1319
  if (start === "subscription") {
1267
1320
  const code2 = await this.write(void 0, void 0, await this.judge(void 0));
1268
- return code2 === SETUP_EXIT.done ? this.offerSession() : code2;
1321
+ return code2 === SETUP_EXIT.done ? this.offerSession(true) : code2;
1269
1322
  }
1270
1323
  const target = await this.checked(start.service, start.key);
1271
1324
  this.modelKey = target.key;
@@ -1296,7 +1349,7 @@ var Setup = class {
1296
1349
  this.io.say(
1297
1350
  this.t({
1298
1351
  zh: "\u597D\u7684\uFF0C\u4EE5\u540E\u4E0D\u518D\u95EE\u4E86\u3002\u9700\u8981\u65F6\u8FD0\u884C mu setup\uFF0C\u6216\u5728 mu \u91CC\u8F93\u5165 /login\u3002",
1299
- en: "OK, mu will not ask again. Run mu setup when you want, or type /login inside mu."
1352
+ en: "OK, mu won't ask again. Run mu setup whenever you're ready, or type /login inside mu."
1300
1353
  })
1301
1354
  );
1302
1355
  return false;
@@ -1308,34 +1361,37 @@ var Setup = class {
1308
1361
  const named2 = this.args.service === void 0 ? void 0 : serviceById(this.args.service);
1309
1362
  if (named2) return this.keyFor(named2, key);
1310
1363
  if (key !== void 0) return { service: await this.serviceOf(key), key };
1311
- const route = await this.choose(this.t({ zh: "mu \u7528\u4EC0\u4E48\u65B9\u5F0F\u8FDE\u63A5\u6A21\u578B\uFF1F", en: "How should mu reach a model?" }), [
1312
- {
1313
- label: this.t({
1314
- zh: "\u7C98\u8D34 API \u5BC6\u94A5\uFF08mu \u4F1A\u8BA4\u51FA\u5B83\u5C5E\u4E8E\u54EA\u4E2A\u670D\u52A1\uFF09",
1315
- en: "Paste an API key (mu tells which service it belongs to)"
1316
- }),
1317
- value: "key"
1318
- },
1319
- { label: this.t({ zh: "\u4ECE\u5217\u8868\u91CC\u9009\u4E00\u4E2A\u670D\u52A1", en: "Choose a service from the list" }), value: "list" },
1320
- {
1321
- label: this.t({
1322
- zh: "\u7528\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\uFF1AChatGPT\u3001Claude\u3001Grok \u6216 Google",
1323
- en: "Sign in with a subscription: ChatGPT, Claude, Grok or Google"
1324
- }),
1325
- value: "subscription"
1326
- }
1327
- ]);
1364
+ const route = await this.choose(
1365
+ this.t({ zh: "mu \u7528\u4EC0\u4E48\u65B9\u5F0F\u8FDE\u63A5\u6A21\u578B\uFF1F", en: "How should mu connect to a model?" }),
1366
+ [
1367
+ {
1368
+ label: this.t({
1369
+ zh: "\u7C98\u8D34 API \u5BC6\u94A5\uFF08mu \u4F1A\u8BA4\u51FA\u5B83\u5C5E\u4E8E\u54EA\u4E2A\u670D\u52A1\uFF09",
1370
+ en: "Paste an API key (mu detects which service it belongs to)"
1371
+ }),
1372
+ value: "key"
1373
+ },
1374
+ { label: this.t({ zh: "\u4ECE\u5217\u8868\u91CC\u9009\u4E00\u4E2A\u670D\u52A1", en: "Choose a service from the list" }), value: "list" },
1375
+ {
1376
+ label: this.t({
1377
+ zh: "\u7528\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\uFF1AChatGPT\u3001Grok \u6216 Google",
1378
+ en: "Sign in with a subscription: ChatGPT, Grok or Google"
1379
+ }),
1380
+ value: "subscription"
1381
+ }
1382
+ ]
1383
+ );
1328
1384
  if (route === "subscription") {
1329
1385
  const auth = this.path(join3(this.deps.paths.agentDir, "auth.json"));
1330
1386
  this.io.say(
1331
1387
  this.t({
1332
- zh: `\u8BA2\u9605\u8D26\u53F7\u5728 mu \u91CC\u9762\u767B\u5F55\uFF1A\u542F\u52A8 mu\uFF0C\u8F93\u5165 /login\uFF0C\u9009 ChatGPT\uFF08OpenAI Codex\uFF09\u3001Claude\u3001Grok \u6216 Google\uFF0C\u6309\u63D0\u793A\u5728\u6D4F\u89C8\u5668\u91CC\u5B8C\u6210\u3002\u767B\u5F55\u4FE1\u606F\u4FDD\u5B58\u5728 ${auth}\u3002`,
1333
- en: `A subscription signs in inside mu: start mu, type /login, choose ChatGPT (OpenAI Codex), Claude, Grok or Google, and finish in the browser. The sign-in is kept in ${auth}.`
1388
+ zh: `\u8BA2\u9605\u8D26\u53F7\u5728 mu \u91CC\u9762\u767B\u5F55\uFF1A\u542F\u52A8 mu\uFF0C\u8F93\u5165 /login\uFF0C\u9009 Sign in with an account\uFF0C\u518D\u9009 OpenAI\uFF08ChatGPT\uFF09\u3001xAI\uFF08Grok\uFF09\u6216 Google \u7684\u4E00\u9879\uFF0C\u6309\u63D0\u793A\u5728\u6D4F\u89C8\u5668\u91CC\u5B8C\u6210\u3002\u767B\u5F55\u4FE1\u606F\u4FDD\u5B58\u5728 ${auth}\u3002`,
1389
+ en: `To use a subscription, sign in from inside mu: start mu, type /login, choose Sign in with an account, then OpenAI for ChatGPT, xAI for Grok, or one of the Google sign-ins, and finish in the browser. The sign-in is saved in ${auth}.`
1334
1390
  })
1335
1391
  );
1336
1392
  return "subscription";
1337
1393
  }
1338
- if (route === "list") return this.keyFor(await this.pickService(SETUP_SERVICES), void 0);
1394
+ if (route === "list") return this.keyFor(await this.pickService(servicesInOrder(this.language)), void 0);
1339
1395
  const pasted = await this.pasteKey();
1340
1396
  return { service: await this.serviceOf(pasted), key: pasted };
1341
1397
  }
@@ -1364,10 +1420,10 @@ var Setup = class {
1364
1420
  throw this.fail(
1365
1421
  matches.length > 1 ? {
1366
1422
  zh: `${this.names(matches)} \u7684\u5BC6\u94A5\u957F\u5F97\u4E00\u6837\u3002\u7528 --service \u8BF4\u660E\u662F\u54EA\u5BB6\uFF1A${matches.map((service) => service.id).join(" \u6216 ")}`,
1367
- en: `keys of ${this.names(matches)} look the same. Say which with --service ${matches.map((service) => service.id).join(" or ")}`
1423
+ en: `${this.names(matches)} keys look the same. Choose one with --service ${matches.map((service) => service.id).join(" or ")}`
1368
1424
  } : {
1369
1425
  zh: "\u8BA4\u4E0D\u51FA\u8FD9\u4E2A\u5BC6\u94A5\u5C5E\u4E8E\u54EA\u4E2A\u670D\u52A1\u3002\u7528 --service <id> \u8BF4\u660E\uFF08mu setup --list \u5217\u51FA\u5168\u90E8\uFF09",
1370
- en: "this key's shape names no service mu knows. Say which with --service <id> (mu setup --list)"
1426
+ en: "mu doesn't recognize this key's format. Say which service it's for with --service <id> (mu setup --list)"
1371
1427
  },
1372
1428
  SETUP_EXIT.usage
1373
1429
  );
@@ -1377,15 +1433,15 @@ var Setup = class {
1377
1433
  matches,
1378
1434
  this.t({
1379
1435
  zh: `${this.names(matches)} \u7684\u5BC6\u94A5\u957F\u5F97\u4E00\u6837\u3002\u8FD9\u4E2A\u5BC6\u94A5\u662F\u54EA\u5BB6\u7684\uFF1Fmu \u53EA\u628A\u5BC6\u94A5\u53D1\u7ED9\u5B83\u6240\u5C5E\u7684\u670D\u52A1\u3002`,
1380
- en: `Keys of ${this.names(matches)} look the same. Which service is this key for? mu sends a key only to the service it belongs to.`
1436
+ en: `${this.names(matches)} keys look the same. Which service is this key for? mu only sends a key to the service it belongs to.`
1381
1437
  })
1382
1438
  );
1383
1439
  }
1384
1440
  return this.pickService(
1385
- SETUP_SERVICES.filter((service) => !service.keyless),
1441
+ servicesInOrder(this.language).filter((service) => !service.keyless),
1386
1442
  this.t({
1387
1443
  zh: "mu \u8BA4\u4E0D\u51FA\u8FD9\u4E2A\u5BC6\u94A5\u3002\u5B83\u662F\u54EA\u4E2A\u670D\u52A1\u7684\uFF1F",
1388
- en: "mu does not recognise this key. Which service is it for?"
1444
+ en: "mu doesn't recognize this key. Which service is it for?"
1389
1445
  })
1390
1446
  );
1391
1447
  }
@@ -1396,9 +1452,7 @@ var Setup = class {
1396
1452
  let key = given;
1397
1453
  if (key === void 0 && !this.scripted) {
1398
1454
  if (service.keyPage) {
1399
- this.io.say(
1400
- this.t({ zh: `\u5BC6\u94A5\u5728\u8FD9\u91CC\u521B\u5EFA\uFF1A${service.keyPage}`, en: `Keys are made at ${service.keyPage}` })
1401
- );
1455
+ this.io.say(this.t({ zh: `\u5BC6\u94A5\u5728\u8FD9\u91CC\u521B\u5EFA\uFF1A${service.keyPage}`, en: `Create a key at ${service.keyPage}` }));
1402
1456
  }
1403
1457
  key = await this.pasteKey();
1404
1458
  }
@@ -1416,7 +1470,7 @@ var Setup = class {
1416
1470
  this.io.warn(
1417
1471
  this.t({
1418
1472
  zh: `\u6CE8\u610F\uFF1A\u8FD9\u4E2A\u5BC6\u94A5\u770B\u8D77\u6765\u662F ${this.names(matches)} \u7684\uFF1B\u6309 --service \u53D1\u7ED9 ${this.name(service)}\u3002`,
1419
- en: `Note: this key looks like ${article(this.names(matches))} key; it goes to ${this.name(service)}, as --service says.`
1473
+ en: `Note: this key looks like ${article(this.names(matches))} key; sending it to ${this.name(service)}, as --service says.`
1420
1474
  })
1421
1475
  );
1422
1476
  return { service, key };
@@ -1463,11 +1517,14 @@ var Setup = class {
1463
1517
  );
1464
1518
  if (/^https?:\/\/[^\s/]+/i.test(baseUrl)) break;
1465
1519
  this.io.say(
1466
- this.t({ zh: "\u5730\u5740\u4EE5 http:// \u6216 https:// \u5F00\u5934\u3002", en: "The address starts with http:// or https://." })
1520
+ this.t({
1521
+ zh: "\u5730\u5740\u4EE5 http:// \u6216 https:// \u5F00\u5934\u3002",
1522
+ en: "The address must start with http:// or https://."
1523
+ })
1467
1524
  );
1468
1525
  }
1469
1526
  }
1470
- const api = args.api === "anthropic" ? "anthropic-messages" : args.api === "openai" || this.scripted ? "openai-completions" : await this.choose(this.t({ zh: "\u5B83\u7528\u54EA\u79CD\u63A5\u53E3\uFF1F", en: "Which API does it speak?" }), [
1527
+ const api = args.api === "anthropic" ? "anthropic-messages" : args.api === "openai" || this.scripted ? "openai-completions" : await this.choose(this.t({ zh: "\u5B83\u7528\u54EA\u79CD\u63A5\u53E3\uFF1F", en: "Which API does it use?" }), [
1471
1528
  {
1472
1529
  label: this.t({
1473
1530
  zh: "OpenAI \u517C\u5BB9\uFF08chat completions\uFF09",
@@ -1489,7 +1546,7 @@ var Setup = class {
1489
1546
  const typed = await this.ask(
1490
1547
  this.t({
1491
1548
  zh: `\u7ED9\u5B83\u8D77\u4E2A\u7B80\u77ED\u7684\u540D\u5B57\uFF08\u5B57\u6BCD\u3001\u6570\u5B57\u3001-\uFF09[${provider}]\uFF1A`,
1492
- en: `A short name for it in mu (letters, digits, -) [${provider}]: `
1549
+ en: `A short name for it in mu (letters, digits and -) [${provider}]: `
1493
1550
  })
1494
1551
  );
1495
1552
  if (typed) provider = typed.toLowerCase().replace(/[^a-z0-9-]+/g, "-");
@@ -1518,7 +1575,7 @@ var Setup = class {
1518
1575
  key = await this.secret(
1519
1576
  this.t({
1520
1577
  zh: "\u7C98\u8D34\u5B83\u7684 API \u5BC6\u94A5\uFF1B\u4E0D\u9700\u8981\u5BC6\u94A5\u5C31\u76F4\u63A5\u56DE\u8F66\uFF08\u4E0D\u4F1A\u663E\u793A\uFF09\uFF1A",
1521
- en: "Paste its API key, or press Enter if it takes none (not shown): "
1578
+ en: "Paste its API key, or press Enter if it doesn't need one (it won't be shown): "
1522
1579
  }),
1523
1580
  true
1524
1581
  ) || void 0;
@@ -1537,15 +1594,15 @@ var Setup = class {
1537
1594
  choices.push({ label: this.t({ zh: "\u518D\u8BD5\u4E00\u6B21", en: "Try again" }), value: "again" });
1538
1595
  if (result.problem.kind !== "key") {
1539
1596
  choices.push({
1540
- label: this.t({ zh: "\u4E0D\u68C0\u67E5\u4E86\uFF0C\u7167\u6837\u4FDD\u5B58", en: "Save it without the check" }),
1597
+ label: this.t({ zh: "\u4E0D\u68C0\u67E5\u4E86\uFF0C\u7167\u6837\u4FDD\u5B58", en: "Save it without checking" }),
1541
1598
  value: "unchecked"
1542
1599
  });
1543
1600
  }
1544
1601
  choices.push({
1545
- label: this.t({ zh: "\u5230\u6B64\u4E3A\u6B62\uFF08\u4EC0\u4E48\u90FD\u4E0D\u6539\uFF09", en: "Stop here (nothing is changed)" }),
1602
+ label: this.t({ zh: "\u5230\u6B64\u4E3A\u6B62\uFF08\u4EC0\u4E48\u90FD\u4E0D\u6539\uFF09", en: "Stop here (change nothing)" }),
1546
1603
  value: "stop"
1547
1604
  });
1548
- const next = await this.choose(this.t({ zh: "\u63A5\u4E0B\u6765\u600E\u4E48\u529E\uFF1F", en: "What now?" }), choices);
1605
+ const next = await this.choose(this.t({ zh: "\u63A5\u4E0B\u6765\u600E\u4E48\u529E\uFF1F", en: "What next?" }), choices);
1549
1606
  if (next === "stop") throw this.cancelled();
1550
1607
  if (next === "unchecked") return { service, reach: reaches[0], key };
1551
1608
  if (next === "key") key = await this.pasteKey();
@@ -1561,10 +1618,10 @@ var Setup = class {
1561
1618
  this.io.say(
1562
1619
  key ? this.t({
1563
1620
  zh: `\u6B63\u5728\u7528 ${where}\u68C0\u67E5\u5BC6\u94A5\u2026\u2026`,
1564
- en: `Checking the key with ${this.name(service)} (${hostOf2(reach.baseUrl)})...`
1621
+ en: `Checking the key with ${this.name(service)} (${hostOf2(reach.baseUrl)})\u2026`
1565
1622
  }) : this.t({
1566
1623
  zh: `\u6B63\u5728\u68C0\u67E5 ${where}\u2026\u2026`,
1567
- en: `Checking ${this.name(service)} (${hostOf2(reach.baseUrl)})...`
1624
+ en: `Checking ${this.name(service)} (${hostOf2(reach.baseUrl)})\u2026`
1568
1625
  })
1569
1626
  );
1570
1627
  const result = await checkKey({
@@ -1579,7 +1636,7 @@ var Setup = class {
1579
1636
  this.io.say(
1580
1637
  count === void 0 ? this.t({ zh: "\u5BC6\u94A5\u53EF\u4EE5\u7528\u3002", en: "The key works." }) : this.t({
1581
1638
  zh: `\u53EF\u4EE5\u7528\uFF1A\u5217\u51FA\u4E86 ${count} \u4E2A\u6A21\u578B\u3002`,
1582
- en: `It works: ${count} model${count === 1 ? "" : "s"} listed.`
1639
+ en: `It works: ${count} model${count === 1 ? "" : "s"} available.`
1583
1640
  })
1584
1641
  );
1585
1642
  return { ok: true, reach, listed: result.models };
@@ -1603,13 +1660,13 @@ var Setup = class {
1603
1660
  if (this.scripted) {
1604
1661
  throw this.fail({
1605
1662
  zh: `${this.name(service)} \u5DF2\u7ECF\u7528\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\u4E86\u3002\u8981\u6539\u5B58\u5BC6\u94A5\uFF0C\u52A0\u4E0A --yes`,
1606
- en: `${this.name(service)} is signed in with a subscription. To store a key instead, add --yes`
1663
+ en: `You're signed in to ${this.name(service)} with a subscription. To use a key instead, add --yes`
1607
1664
  });
1608
1665
  }
1609
1666
  const replace = await this.confirm(
1610
1667
  this.t({
1611
1668
  zh: `\u4F60\u5DF2\u7ECF\u7528\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\u4E86 ${this.name(service)}\u3002\u6539\u7528\u8FD9\u4E2A\u5BC6\u94A5\u5417\uFF1F\u767B\u5F55\u4F1A\u88AB\u66FF\u6362\uFF08\u7559\u6709\u5907\u4EFD\uFF09\u3002[y/N] `,
1612
- en: `You are signed in to ${this.name(service)} with a subscription. Use this key instead? The sign-in is replaced (a copy is kept). [y/N] `
1669
+ en: `You're signed in to ${this.name(service)} with a subscription. Use this key instead? It replaces the sign-in (a backup is kept). [y/N] `
1613
1670
  }),
1614
1671
  false
1615
1672
  );
@@ -1622,7 +1679,7 @@ var Setup = class {
1622
1679
  if (readJsonFile(path).state !== "unreadable") return;
1623
1680
  throw this.fail({
1624
1681
  zh: `${this.path(path)} \u4E0D\u662F\u7EAF JSON\uFF08\u4E5F\u8BB8\u6709\u6CE8\u91CA\u6216\u5199\u9519\u4E86\uFF09\uFF0Cmu setup \u4E0D\u6539\u5199\u5B83\u3002\u5148\u4FEE\u597D\u5B83\uFF0C\u6216\u624B\u52A8\u628A\u670D\u52A1\u52A0\u8FDB\u53BB\u3002`,
1625
- en: `${this.path(path)} is not plain JSON (it may have comments, or a typo), and mu setup does not rewrite it. Fix it, or add the service by hand.`
1682
+ en: `${this.path(path)} isn't plain JSON (it may have comments or a typo), so mu setup won't rewrite it. Fix it, or add the service by hand.`
1626
1683
  });
1627
1684
  }
1628
1685
  // -----------------------------------------------------------------------------------------------------------
@@ -1635,7 +1692,7 @@ var Setup = class {
1635
1692
  this.io.say(
1636
1693
  this.t({
1637
1694
  zh: `\u6CE8\u610F\uFF1A${this.name(service)} \u6CA1\u6709\u5217\u51FA ${this.args.model}\uFF0C\u7167\u6837\u4F7F\u7528\u3002`,
1638
- en: `Note: ${this.name(service)} does not list ${this.args.model}; it is used anyway.`
1695
+ en: `Note: ${this.name(service)} doesn't list ${this.args.model}; using it anyway.`
1639
1696
  })
1640
1697
  );
1641
1698
  }
@@ -1651,14 +1708,14 @@ var Setup = class {
1651
1708
  if (options.length === 0) {
1652
1709
  const none = service.keyless ? NOT_READY : {
1653
1710
  zh: `${this.name(service)} \u6CA1\u6709\u5217\u51FA\u6A21\u578B\u3002`,
1654
- en: `${this.name(service)} lists no models.`
1711
+ en: `${this.name(service)} doesn't list any models.`
1655
1712
  };
1656
1713
  if (this.scripted) {
1657
- throw this.fail({ zh: `${none.zh}\u53EF\u4EE5\u7528 --model \u6307\u5B9A\u4E00\u4E2A\u3002`, en: `${none.en} Name one with --model.` });
1714
+ throw this.fail({ zh: `${none.zh}\u53EF\u4EE5\u7528 --model \u6307\u5B9A\u4E00\u4E2A\u3002`, en: `${none.en} Specify one with --model.` });
1658
1715
  }
1659
1716
  this.io.say(this.t(none));
1660
1717
  for (; ; ) {
1661
- const typed = await this.ask(this.t({ zh: "\u8981\u7528\u7684\u6A21\u578B\u540D\uFF1A", en: "The name of the model to use: " }));
1718
+ const typed = await this.ask(this.t({ zh: "\u8981\u7528\u7684\u6A21\u578B\u540D\uFF1A", en: "Name of the model to use: " }));
1662
1719
  if (typed) return typed;
1663
1720
  }
1664
1721
  }
@@ -1674,7 +1731,7 @@ var Setup = class {
1674
1731
  this.io.say(
1675
1732
  this.t({
1676
1733
  zh: ` \uFF08\u8FD8\u6709 ${more} \u4E2A\uFF0C\u8F93\u5165\u540D\u5B57\u4E5F\u53EF\u4EE5\uFF09`,
1677
- en: ` (${more} more: type a name to use one of them)`
1734
+ en: ` (${more} more; type a name to use one of them)`
1678
1735
  })
1679
1736
  );
1680
1737
  }
@@ -1692,7 +1749,7 @@ var Setup = class {
1692
1749
  this.io.say(
1693
1750
  this.t({
1694
1751
  zh: `\u8BF7\u8F93\u5165 1-${shown.length} \u4E4B\u95F4\u7684\u6570\u5B57\uFF0C\u6216\u6A21\u578B\u540D\u3002`,
1695
- en: `Type a number from 1-${shown.length}, or a model name.`
1752
+ en: `Type a number from 1 to ${shown.length}, or a model name.`
1696
1753
  })
1697
1754
  );
1698
1755
  }
@@ -1708,13 +1765,13 @@ var Setup = class {
1708
1765
  if (this.scripted) {
1709
1766
  throw this.fail({
1710
1767
  zh: `models.json \u91CC\u7684 ${target.reach.provider} \u6307\u5411 ${old}\u3002\u8981\u6539\u6210 ${target.reach.baseUrl}\uFF0C\u52A0\u4E0A --yes`,
1711
- en: `models.json has ${target.reach.provider} at ${old}. To point it at ${target.reach.baseUrl}, add --yes`
1768
+ en: `models.json already points ${target.reach.provider} at ${old}. To point it at ${target.reach.baseUrl}, add --yes`
1712
1769
  });
1713
1770
  }
1714
1771
  const move = await this.confirm(
1715
1772
  this.t({
1716
1773
  zh: `models.json \u91CC\u5DF2\u7ECF\u6709 ${target.reach.provider}\uFF0C\u5730\u5740\u662F ${old}\u3002\u6539\u6210 ${target.reach.baseUrl} \u5417\uFF1F[y/N] `,
1717
- en: `models.json already has ${target.reach.provider}, at ${old}. Point it at ${target.reach.baseUrl}? [y/N] `
1774
+ en: `models.json already points ${target.reach.provider} at ${old}. Point it at ${target.reach.baseUrl} instead? [y/N] `
1718
1775
  }),
1719
1776
  false
1720
1777
  );
@@ -1739,7 +1796,7 @@ var Setup = class {
1739
1796
  choices.push({
1740
1797
  label: this.t({
1741
1798
  zh: "Jev \u514D\u8D39\u7248\uFF08\u63A8\u8350\uFF09\uFF0C\u5728 OpenCode Zen \u4E0A\uFF1A\u4E0D\u7528\u5BC6\u94A5\uFF0C\u9650\u65F6\u514D\u8D39\uFF1B\u4EE5\u540E\u52A0\u4E86\u5BC6\u94A5\u81EA\u52A8\u6362\u7528",
1742
- en: "Jev for free (recommended) on OpenCode Zen: no key, free for a limited time; a key added later takes over"
1799
+ en: "Free Jev on OpenCode Zen (recommended): no key needed, free for a limited time; a key you add later takes over"
1743
1800
  }),
1744
1801
  value: "free"
1745
1802
  });
@@ -1748,7 +1805,7 @@ var Setup = class {
1748
1805
  choices.push({
1749
1806
  label: this.t({
1750
1807
  zh: "Jev\uFF08\u63A8\u8350\uFF09\uFF0C\u5728 OpenCode Zen \u4E0A\uFF0C\u7528\u4F60\u7684 OpenCode \u5BC6\u94A5\uFF0C\u6309\u6B21\u8BA1\u8D39",
1751
- en: "Jev (recommended) on OpenCode Zen, with your OpenCode key, billed per call"
1808
+ en: "Jev on OpenCode Zen with your OpenCode key (recommended), billed per call"
1752
1809
  }),
1753
1810
  value: "opencode"
1754
1811
  });
@@ -1757,18 +1814,18 @@ var Setup = class {
1757
1814
  choices.push({
1758
1815
  label: this.t({
1759
1816
  zh: `Jev\uFF08\u63A8\u8350\uFF09\uFF0C\u7528\u5DF2\u7ECF\u8BBE\u7F6E\u7684\u5BC6\u94A5\uFF08${where}\uFF09`,
1760
- en: `Jev (recommended), with the key already set (${where})`
1817
+ en: `Jev with the key that's already set (recommended): ${where}`
1761
1818
  }),
1762
1819
  value: "keep"
1763
1820
  });
1764
1821
  }
1765
1822
  choices.push({
1766
- label: where ? this.t({ zh: "Jev\uFF0C\u6362\u4E00\u4E2A\u65B0\u5BC6\u94A5", en: "Jev, with a new key" }) : opencode ? this.t({
1823
+ label: where ? this.t({ zh: "Jev\uFF0C\u6362\u4E00\u4E2A\u65B0\u5BC6\u94A5", en: "Jev with a new key" }) : opencode ? this.t({
1767
1824
  zh: `Jev\uFF0C\u7528 TypeSafe \u7684\u5BC6\u94A5\uFF1A${JEV_PAGE}`,
1768
1825
  en: `Jev with a TypeSafe key: ${JEV_PAGE}`
1769
1826
  }) : this.t({
1770
- zh: `Jev\uFF0C\u7528\u81EA\u5DF1\u7684\u5BC6\u94A5\uFF1A\u53C8\u5FEB\u53C8\u51C6\uFF0C\u6309\u6B21\u8BA1\u8D39\u3002\u5BC6\u94A5\u5728 TypeSafe \u7533\u8BF7\uFF1A${JEV_PAGE}`,
1771
- en: `Jev with a key of your own: fast and accurate, billed per call. Get a key from TypeSafe: ${JEV_PAGE}`
1827
+ zh: `Jev\uFF0C\u7528\u81EA\u5DF1\u7684\u5BC6\u94A5\uFF1A\u6BCF\u4E2A\u95EE\u9898\u7EA6 0.3 \u79D2\uFF0C\u6309\u6B21\u8BA1\u8D39\u3002\u5BC6\u94A5\u5728 TypeSafe \u7533\u8BF7\uFF1A${JEV_PAGE}`,
1828
+ en: `Jev with your own key: about 0.3 s per question, billed per call. Get a key from TypeSafe: ${JEV_PAGE}`
1772
1829
  }),
1773
1830
  value: "jev"
1774
1831
  });
@@ -1776,7 +1833,7 @@ var Setup = class {
1776
1833
  choices.push({
1777
1834
  label: this.t({
1778
1835
  zh: "Jev \u514D\u8D39\u7248\uFF0C\u5728 OpenCode Zen \u4E0A\uFF1A\u4E0D\u7528\u5BC6\u94A5\uFF0C\u9650\u65F6\u514D\u8D39",
1779
- en: "Jev for free on OpenCode Zen: no key, free for a limited time"
1836
+ en: "Free Jev on OpenCode Zen: no key needed, free for a limited time"
1780
1837
  }),
1781
1838
  value: "free"
1782
1839
  });
@@ -1785,22 +1842,22 @@ var Setup = class {
1785
1842
  choices.push({
1786
1843
  label: this.t({
1787
1844
  zh: `\u521A\u8BBE\u7F6E\u7684\u6A21\u578B\uFF08${model.provider}/${model.model}\uFF09\uFF1A\u66F4\u6162\uFF0C\u800C\u4E14\u6BCF\u6B21\u5224\u65AD\u90FD\u8981\u82B1 token`,
1788
- en: `The model you just set up (${model.provider}/${model.model}): slower, and every decision costs tokens`
1845
+ en: `The model you just set up (${model.provider}/${model.model}): slower, and every verdict costs tokens`
1789
1846
  }),
1790
1847
  value: "model"
1791
1848
  });
1792
1849
  }
1793
1850
  choices.push({
1794
1851
  label: this.t({
1795
- zh: "\u6682\u65F6\u4E0D\u8981\uFF1Amu \u5C31\u50CF pi \u4E00\u6837\u5DE5\u4F5C\uFF0C\u6CA1\u6709\u5224\u5B9A\u5668\u56DE\u7B54",
1796
- en: "Not now: mu then works like pi, with no judge answering"
1852
+ zh: "\u6682\u65F6\u4E0D\u8981\uFF1A\u4E0D\u95EE\u5224\u5B9A\u5668\uFF0C\u4EC0\u4E48\u90FD\u4E0D\u53D1\u7ED9\u5B83\uFF0Cmu \u6309\u9ED8\u8BA4\u89C4\u5219\u5DE5\u4F5C",
1853
+ en: "Not now: no judge is asked and nothing is sent to one; mu uses its fallbacks"
1797
1854
  }),
1798
1855
  value: "none"
1799
1856
  });
1800
1857
  const picked = await this.choose(
1801
1858
  this.t({
1802
1859
  zh: "mu \u5DE5\u4F5C\u65F6\u8981\u505A\u5F88\u591A\u5C0F\u5224\u65AD\uFF1A\u8FD9\u6761\u6D88\u606F\u8BE5\u600E\u4E48\u5904\u7406\u3001\u8FD9\u4E00\u6B65\u4F1A\u4E0D\u4F1A\u8FDD\u53CD\u4F60\u5B9A\u7684\u89C4\u5219\u2026\u2026\u5224\u5B9A\u5668\u8D1F\u8D23\u56DE\u7B54\u3002\u9009\u54EA\u4E2A\u5224\u5B9A\u5668\uFF1F",
1803
- en: "mu makes many small decisions as it works: how to take a message, whether a step breaks your rules. A judge answers them. Which judge?"
1860
+ en: "As it works, mu faces many small decisions: how to handle a message, whether a step breaks your rules. A judge answers them. Which judge do you want?"
1804
1861
  }),
1805
1862
  choices
1806
1863
  );
@@ -1814,7 +1871,7 @@ var Setup = class {
1814
1871
  throw this.fail(
1815
1872
  {
1816
1873
  zh: "--judge opencode \u9700\u8981 OpenCode \u7684\u5BC6\u94A5\uFF1A\u7528 --service opencode \u8BBE\u7F6E\u5B83\uFF0C\u6216\u5148\u8BBE\u7F6E OPENCODE_API_KEY",
1817
- en: "--judge opencode needs an OpenCode key: set it up with --service opencode, or set OPENCODE_API_KEY first"
1874
+ en: "--judge opencode needs an OpenCode key: set one up with --service opencode, or set OPENCODE_API_KEY first"
1818
1875
  },
1819
1876
  SETUP_EXIT.usage
1820
1877
  );
@@ -1822,6 +1879,8 @@ var Setup = class {
1822
1879
  return { kind: "opencode" };
1823
1880
  case "free":
1824
1881
  return { kind: "free" };
1882
+ case "off":
1883
+ return { kind: "none" };
1825
1884
  case "jev": {
1826
1885
  const key = this.jevFromStdin;
1827
1886
  if (!key) {
@@ -1829,14 +1888,14 @@ var Setup = class {
1829
1888
  throw this.fail(
1830
1889
  {
1831
1890
  zh: "--judge jev \u9700\u8981 Jev \u5BC6\u94A5\uFF1A\u5199\u5728\u6807\u51C6\u8F93\u5165\u7684\u7B2C\u4E8C\u884C\uFF0C\u6216\u5148\u8BBE\u7F6E TYPESAFE_API_KEY",
1832
- en: "--judge jev needs a Jev key: the second line of stdin, or TYPESAFE_API_KEY set beforehand"
1891
+ en: "--judge jev needs a Jev key: put it on the second line of stdin, or set TYPESAFE_API_KEY first"
1833
1892
  },
1834
1893
  SETUP_EXIT.usage
1835
1894
  );
1836
1895
  }
1837
1896
  if (key === this.modelKey) {
1838
1897
  throw this.fail(
1839
- { zh: "Jev \u5BC6\u94A5\u548C\u6A21\u578B\u7684\u5BC6\u94A5\u662F\u540C\u4E00\u4E2A", en: "the Jev key is the same as the model's key" },
1898
+ { zh: "Jev \u5BC6\u94A5\u548C\u6A21\u578B\u7684\u5BC6\u94A5\u662F\u540C\u4E00\u4E2A", en: "the Jev key is the same as the model key" },
1840
1899
  SETUP_EXIT.usage
1841
1900
  );
1842
1901
  }
@@ -1844,7 +1903,7 @@ var Setup = class {
1844
1903
  if (current && current !== key && !this.args.yes) {
1845
1904
  throw this.fail({
1846
1905
  zh: `${this.path(this.deps.paths.envFile)} \u91CC\u5DF2\u7ECF\u6709 TYPESAFE_API_KEY\u3002\u8981\u66FF\u6362\u5B83\uFF0C\u52A0\u4E0A --yes`,
1847
- en: `${this.path(this.deps.paths.envFile)} has a TYPESAFE_API_KEY already. To replace it, add --yes`
1906
+ en: `${this.path(this.deps.paths.envFile)} already has a TYPESAFE_API_KEY. To replace it, add --yes`
1848
1907
  });
1849
1908
  }
1850
1909
  return { kind: "jev", key };
@@ -1860,14 +1919,14 @@ var Setup = class {
1860
1919
  const key = await this.secret(
1861
1920
  this.t({
1862
1921
  zh: "\u7C98\u8D34 Jev \u5BC6\u94A5\uFF08TYPESAFE_API_KEY\uFF0C\u4E0D\u4F1A\u663E\u793A\uFF09\uFF1A",
1863
- en: "Paste the Jev key (TYPESAFE_API_KEY, not shown): "
1922
+ en: "Paste the Jev key (TYPESAFE_API_KEY; it won't be shown): "
1864
1923
  })
1865
1924
  );
1866
1925
  if (key === this.modelKey) {
1867
1926
  this.io.say(
1868
1927
  this.t({
1869
1928
  zh: `\u8FD9\u662F\u521A\u624D\u7ED9\u6A21\u578B\u7684\u5BC6\u94A5\u3002Jev \u7684\u5BC6\u94A5\u5728 TypeSafe \u7533\u8BF7\uFF1A${JEV_PAGE}`,
1870
- en: `That is the key you gave for the model. A Jev key comes from TypeSafe: ${JEV_PAGE}`
1929
+ en: `That's the key you gave for the model. Get a Jev key from TypeSafe: ${JEV_PAGE}`
1871
1930
  })
1872
1931
  );
1873
1932
  continue;
@@ -1935,7 +1994,7 @@ var Setup = class {
1935
1994
  saved.push(
1936
1995
  this.savedLine(
1937
1996
  modelsPath,
1938
- custom || moved ? this.t({ zh: `${provider}\uFF1A${reach.baseUrl}`, en: `${provider} at ${reach.baseUrl}` }) : this.t({ zh: `\u7ED9 ${provider} \u52A0\u4E0A ${model}`, en: `${model} added to ${provider}` })
1997
+ custom || moved ? this.t({ zh: `${provider}\uFF1A${reach.baseUrl}`, en: `${provider} at ${reach.baseUrl}` }) : this.t({ zh: `\u7ED9 ${provider} \u52A0\u4E0A ${model}`, en: `added ${model} to ${provider}` })
1939
1998
  )
1940
1999
  );
1941
2000
  }
@@ -1955,35 +2014,36 @@ var Setup = class {
1955
2014
  saved.push(
1956
2015
  this.savedLine(
1957
2016
  settingsPath,
1958
- this.t({ zh: `\u9ED8\u8BA4\u6A21\u578B ${provider}/${model}`, en: `start on ${provider}/${model}` })
2017
+ this.t({ zh: `\u9ED8\u8BA4\u6A21\u578B ${provider}/${model}`, en: `default model ${provider}/${model}` })
1959
2018
  )
1960
2019
  );
1961
2020
  } catch {
1962
2021
  notes.push(
1963
2022
  this.t({
1964
2023
  zh: `${this.path(settingsPath)} \u8BFB\u4E0D\u4E86\uFF0C\u9ED8\u8BA4\u6A21\u578B\u6CA1\u6709\u4FDD\u5B58\u3002\u5728 mu \u91CC\u7528 /model \u9009\u5B83\u3002`,
1965
- en: `${this.path(settingsPath)} could not be read, so the default model was not saved. Choose it inside mu with /model.`
2024
+ en: `Couldn't read ${this.path(settingsPath)}, so the default model wasn't saved. Choose it inside mu with /model.`
1966
2025
  })
1967
2026
  );
1968
2027
  }
1969
2028
  }
1970
- if (judge && judge.kind !== "none") this.writeJudge(judge, target, model, backups, saved, notes);
2029
+ if (judge?.kind === "none") this.writeNoJudge(backups, saved, notes);
2030
+ else if (judge) this.writeJudge(judge, target, model, backups, saved, notes);
1971
2031
  } catch (error) {
1972
2032
  if (error instanceof Stop) throw error;
1973
2033
  let reason = error instanceof Error ? error.message : String(error);
1974
2034
  for (const secret of [target?.key, judge?.kind === "jev" ? judge.key : void 0]) {
1975
2035
  if (secret) reason = reason.replaceAll(secret, "\u2026");
1976
2036
  }
1977
- this.io.warn(this.t({ zh: `mu setup\uFF1A\u4FDD\u5B58\u65F6\u51FA\u9519\uFF1A${reason}`, en: `mu setup: saving failed: ${reason}` }));
2037
+ this.io.warn(this.t({ zh: `mu setup\uFF1A\u4FDD\u5B58\u65F6\u51FA\u9519\uFF1A${reason}`, en: `mu setup: couldn't save: ${reason}` }));
1978
2038
  if (saved.length > 0) {
1979
- this.io.warn(this.t({ zh: "\u51FA\u9519\u524D\u5DF2\u7ECF\u4FDD\u5B58\u7684\uFF1A", en: "Saved before that:" }));
2039
+ this.io.warn(this.t({ zh: "\u51FA\u9519\u524D\u5DF2\u7ECF\u4FDD\u5B58\u7684\uFF1A", en: "Saved before the error:" }));
1980
2040
  for (const entry of saved) this.io.warn(entry);
1981
2041
  }
1982
2042
  if (backups.path) {
1983
2043
  this.io.warn(
1984
2044
  this.t({
1985
2045
  zh: `\u539F\u6765\u7684\u6587\u4EF6\u5728 ${this.path(backups.path)}`,
1986
- en: `The earlier versions are in ${this.path(backups.path)}`
2046
+ en: `The previous versions are in ${this.path(backups.path)}`
1987
2047
  })
1988
2048
  );
1989
2049
  }
@@ -1997,7 +2057,7 @@ var Setup = class {
1997
2057
  this.io.say(
1998
2058
  this.t({
1999
2059
  zh: `\u6539\u52A8\u524D\u7684\u6587\u4EF6\u5DF2\u590D\u5236\u5230 ${this.path(backups.path)}`,
2000
- en: `The files as they were are copied to ${this.path(backups.path)}`
2060
+ en: `Backed up the previous files to ${this.path(backups.path)}`
2001
2061
  })
2002
2062
  );
2003
2063
  }
@@ -2008,6 +2068,25 @@ var Setup = class {
2008
2068
  savedLine(path, what) {
2009
2069
  return ` ${this.path(path).padEnd(30)} ${what}`;
2010
2070
  }
2071
+ /** "Not now": no decision point asks a judge (the default mode "off"), so nothing goes to one. */
2072
+ writeNoJudge(backups, saved, notes) {
2073
+ const configPath = judgeConfigPath(this.deps.paths.agentDir);
2074
+ const config = readJsonFile(configPath);
2075
+ if (config.state === "unreadable") {
2076
+ notes.push(
2077
+ this.t({
2078
+ zh: `${this.path(configPath)} \u4E0D\u662F\u7EAF JSON\uFF0C\u6CA1\u6709\u6539\u5B83\u3002\u8BF7\u624B\u52A8\u52A0\u4E0A "modes": { "default": "off" }`,
2079
+ en: `${this.path(configPath)} isn't plain JSON, so it was left unchanged. Add "modes": { "default": "off" } by hand.`
2080
+ })
2081
+ );
2082
+ return;
2083
+ }
2084
+ const current = config.state === "ok" ? config.value : void 0;
2085
+ if (judgeOff(current)) return;
2086
+ backups.save(configPath);
2087
+ writeJsonFile(configPath, withJudge(current ?? {}, false));
2088
+ saved.push(this.savedLine(configPath, this.t({ zh: "\u5224\u5B9A\u5668\uFF1A\u5173\u95ED", en: "judge: off" })));
2089
+ }
2011
2090
  writeJudge(judge, target, model, backups, saved, notes) {
2012
2091
  const { env, paths } = this.deps;
2013
2092
  const configPath = judgeConfigPath(paths.agentDir);
@@ -2020,18 +2099,21 @@ var Setup = class {
2020
2099
  else if (judge.kind === "free") {
2021
2100
  if (!tiersOf(current).some((tier) => tier === "jev" || tier === "jev-opencode-free")) tiers = ["jev"];
2022
2101
  } else if (!tiersOf(current).some((tier) => JEV_TIERS.has(tier))) tiers = ["jev"];
2102
+ const turnOn = judgeOff(current);
2023
2103
  if (tiers && config.state === "unreadable") {
2024
2104
  notes.push(
2025
2105
  this.t({
2026
2106
  zh: `${this.path(configPath)} \u4E0D\u662F\u7EAF JSON\uFF0C\u6CA1\u6709\u6539\u5B83\u3002\u8BF7\u624B\u52A8\u52A0\u4E0A "tiers": ${JSON.stringify(tiers)}`,
2027
- en: `${this.path(configPath)} is not plain JSON and was left as it is. Add "tiers": ${JSON.stringify(tiers)} by hand.`
2107
+ en: `${this.path(configPath)} isn't plain JSON, so it was left unchanged. Add "tiers": ${JSON.stringify(tiers)} by hand.`
2028
2108
  })
2029
2109
  );
2030
- } else if (tiers) {
2110
+ } else if (tiers || turnOn) {
2031
2111
  backups.save(configPath);
2032
- writeJsonFile(configPath, withTiers(current ?? {}, tiers));
2112
+ const next = tiers ? withTiers(current ?? {}, tiers) : current ?? {};
2113
+ writeJsonFile(configPath, turnOn ? withJudge(next, true) : next);
2114
+ const named2 = tiers ?? tiersOf(current);
2033
2115
  saved.push(
2034
- this.savedLine(configPath, this.t({ zh: `\u5224\u5B9A\u5668 ${tiers.join(", ")}`, en: `judge: ${tiers.join(", ")}` }))
2116
+ this.savedLine(configPath, this.t({ zh: `\u5224\u5B9A\u5668 ${named2.join(", ")}`, en: `judge: ${named2.join(", ")}` }))
2035
2117
  );
2036
2118
  }
2037
2119
  if (judge.kind === "jev") {
@@ -2047,7 +2129,7 @@ var Setup = class {
2047
2129
  notes.push(
2048
2130
  this.t({
2049
2131
  zh: `\u6CE8\u610F\uFF1A\u73AF\u5883\u53D8\u91CF\u91CC\u4E5F\u6709 TYPESAFE_API_KEY\uFF0C\u5B83\u6BD4 ${this.path(paths.envFile)} \u4F18\u5148\u3002\u5230\u8BBE\u7F6E\u5B83\u7684\u5730\u65B9\uFF08\u4F8B\u5982 ~/.zshrc\uFF09\u6539\u6389\u6216\u5220\u6389\u3002`,
2050
- en: `Note: TYPESAFE_API_KEY is also set in your environment, and it wins over ${this.path(paths.envFile)}. Change or remove it where it is set (~/.zshrc, for example).`
2132
+ en: `Note: TYPESAFE_API_KEY is also set in your environment and takes precedence over ${this.path(paths.envFile)}. Change or remove it where it's set (~/.zshrc, for example).`
2051
2133
  })
2052
2134
  );
2053
2135
  }
@@ -2057,7 +2139,7 @@ var Setup = class {
2057
2139
  notes.push(
2058
2140
  this.t({
2059
2141
  zh: `\u6CE8\u610F\uFF1A\u73AF\u5883\u53D8\u91CF MU_JUDGE=${override} \u6BD4 mu.json \u4F18\u5148\uFF0C\u7531\u5B83\u51B3\u5B9A\u5224\u5B9A\u5668\u3002`,
2060
- en: `Note: MU_JUDGE=${override} is set in your environment; it decides the judge over mu.json.`
2142
+ en: `Note: MU_JUDGE=${override} is set in your environment and takes precedence over mu.json for the judge.`
2061
2143
  })
2062
2144
  );
2063
2145
  }
@@ -2065,26 +2147,31 @@ var Setup = class {
2065
2147
  summary(target, model, judge) {
2066
2148
  const done = target && model ? this.t({
2067
2149
  zh: `\u5B8C\u6210\u3002mu \u4F1A\u7528 ${this.name(target.service)} \xB7 ${model} \u5F00\u59CB\u5DE5\u4F5C\u3002`,
2068
- en: `Done. mu starts on ${this.name(target.service)} \xB7 ${model}.`
2150
+ en: `Done. mu will start on ${this.name(target.service)} \xB7 ${model}.`
2069
2151
  }) : this.t({ zh: "\u5B8C\u6210\u3002", en: "Done." });
2070
2152
  const judged = judge === void 0 ? "" : judge.kind === "model" ? this.t({ zh: "\u5224\u5B9A\u5668\uFF1A\u540C\u4E00\u4E2A\u6A21\u578B\u3002", en: " Judge: the same model." }) : judge.kind === "none" ? this.t({ zh: "\u5224\u5B9A\u5668\uFF1A\u6682\u65F6\u6CA1\u6709\u3002", en: " Judge: none for now." }) : judge.kind === "opencode" ? this.t({ zh: "\u5224\u5B9A\u5668\uFF1AOpenCode Zen \u4E0A\u7684 Jev\u3002", en: " Judge: Jev on OpenCode Zen." }) : judge.kind === "free" ? this.t({
2071
2153
  zh: "\u5224\u5B9A\u5668\uFF1AJev\uFF0C\u52A0\u5BC6\u94A5\u4E4B\u524D\u7528 OpenCode Zen \u4E0A\u9650\u65F6\u514D\u8D39\u7684\u7248\u672C\u3002",
2072
- en: " Judge: Jev, free on OpenCode Zen for a limited time until you add a key."
2154
+ en: " Judge: Jev, using the free version on OpenCode Zen until you add a key."
2073
2155
  }) : this.t({ zh: "\u5224\u5B9A\u5668\uFF1AJev\u3002", en: " Judge: Jev." });
2074
2156
  this.io.say("");
2075
2157
  this.io.say(`${done}${judged}`);
2076
2158
  this.io.say(
2077
2159
  target ? this.t({
2078
2160
  zh: "\u5728 mu \u91CC\u7528 /model \u6362\u6A21\u578B\uFF1B\u968F\u65F6\u53EF\u4EE5\u518D\u8FD0\u884C mu setup\u3002",
2079
- en: "Switch models inside mu with /model; run mu setup again any time."
2080
- }) : this.t({ zh: "\u542F\u52A8 mu \u540E\u8F93\u5165 /login \u767B\u5F55\u3002", en: "Start mu and type /login to sign in." })
2161
+ en: "Switch models inside mu with /model, and run mu setup again any time."
2162
+ }) : this.t({ zh: "\u63A5\u4E0B\u6765\u5728 mu \u91CC\u7528 /login \u767B\u5F55\u3002", en: "Next, sign in with /login in mu." })
2081
2163
  );
2082
2164
  }
2083
- /** On its own, a finished setup offers a session; on a first start the launcher goes on into one anyway. */
2084
- async offerSession() {
2085
- if (this.args.firstRun || this.scripted) return SETUP_EXIT.done;
2165
+ /**
2166
+ * On its own, a finished setup offers a session; on a first start the launcher goes on into one anyway. After a
2167
+ * subscription was chosen (`signIn`), that session opens on /login: SETUP_EXIT.signIn.
2168
+ */
2169
+ async offerSession(signIn = false) {
2170
+ if (this.scripted) return SETUP_EXIT.done;
2171
+ if (this.args.firstRun) return signIn ? SETUP_EXIT.signIn : SETUP_EXIT.done;
2086
2172
  const start = await this.confirm(this.t({ zh: "\u73B0\u5728\u542F\u52A8 mu \u5417\uFF1F[Y/n] ", en: "Start mu now? [Y/n] " }), true);
2087
- return start ? SETUP_EXIT.start : SETUP_EXIT.done;
2173
+ if (!start) return SETUP_EXIT.done;
2174
+ return signIn ? SETUP_EXIT.signIn : SETUP_EXIT.start;
2088
2175
  }
2089
2176
  };
2090
2177
  function existingProviders(models) {