mu-agent 0.1.10 → 0.1.14

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 (41) hide show
  1. package/CHANGELOG.md +122 -0
  2. package/README.md +7 -7
  3. package/dist/bundle/chunks/{chunk-DNNHZBQR.js → chunk-6Z2347ML.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-FN6OEZYR.js → chunk-AN7MSYCK.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-O7IPTASE.js → chunk-BK7M6BDT.js} +22 -21
  6. package/dist/bundle/chunks/{chunk-X234222Q.js → chunk-DYTENXHX.js} +2 -2
  7. package/dist/bundle/chunks/{chunk-RAQ6TU76.js → chunk-FLHKNMLQ.js} +1 -1
  8. package/dist/bundle/chunks/chunk-LHRPMXVI.js +2 -0
  9. package/dist/bundle/chunks/{chunk-HZNN636Z.js → chunk-LT2C56HV.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-SGOTYFMT.js → chunk-MF3VB62R.js} +1 -1
  11. package/dist/bundle/chunks/{chunk-QOEEJKS4.js → chunk-URBBMV3M.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-VJLOQZKR.js → chunk-WCJNJQO5.js} +1 -1
  13. package/dist/bundle/chunks/{cli-722OL3K5.js → cli-M4YBZZ6Q.js} +1 -1
  14. package/dist/bundle/chunks/{easter-egg-3d-6H34EDGX.js → easter-egg-3d-VFY3YRQR.js} +1 -1
  15. package/dist/bundle/chunks/{execute-KVSEIDWL.js → execute-FKI7Y4XR.js} +1 -1
  16. package/dist/bundle/chunks/{runtime-O3ELDOM7.js → runtime-IKE5OQIW.js} +1 -1
  17. package/dist/bundle/chunks/{virtual-modules-IKEARUOZ.js → virtual-modules-U6MRV5BC.js} +1 -1
  18. package/dist/bundle/cli-runtime.js +1 -1
  19. package/dist/bundle/index.js +1 -1
  20. package/dist/bundle/rpc-entry.js +1 -1
  21. package/docs/settings.md +1 -1
  22. package/judge/dist/auth.js +54 -26
  23. package/judge/dist/chrome.js +2 -2
  24. package/judge/dist/import.js +833 -161
  25. package/judge/dist/setup.js +142 -48
  26. package/judge/manifest.json +2048 -394
  27. package/judge/mu/chunk-3NQ5BIBI.js +4773 -0
  28. package/judge/mu/chunk-6XRUK3PM.js +51 -0
  29. package/judge/mu/chunk-WQM4MV6L.js +58 -0
  30. package/judge/mu/cloud-code-XR7SZMJC.js +22802 -0
  31. package/judge/mu/dist-75PS4OC4.js +1283 -0
  32. package/judge/mu/index.js +4949 -32969
  33. package/judge/mu/multipart-parser-ZDXVIOOP.js +372 -0
  34. package/judge/mu/src-TVVA5ZK2.js +1409 -0
  35. package/kyrn/bin/kyrn-doctor +67 -14
  36. package/kyrn/bin/kyrn-judge-local +42 -13
  37. package/kyrn/bin/kyrn-ledger +16 -1
  38. package/kyrn/bin/mu.mjs +101 -29
  39. package/kyrn/local-judge/server.py +26 -14
  40. package/package.json +6 -3
  41. package/dist/bundle/chunks/chunk-BSS6T6KQ.js +0 -2
@@ -200,6 +200,13 @@ function backupStamp(now) {
200
200
  const two = (value) => String(value).padStart(2, "0");
201
201
  return `${now.getFullYear()}-${two(now.getMonth() + 1)}-${two(now.getDate())}T${two(now.getHours())}-${two(now.getMinutes())}-${two(now.getSeconds())}`;
202
202
  }
203
+ var holdsNothing = (file) => {
204
+ try {
205
+ return /^\s*(\{\s*\})?\s*$/.test(readFileSync(file, "utf8"));
206
+ } catch {
207
+ return false;
208
+ }
209
+ };
203
210
  var Backups = class {
204
211
  root;
205
212
  stamp;
@@ -209,9 +216,13 @@ var Backups = class {
209
216
  this.root = join2(home2, "backups");
210
217
  this.stamp = backupStamp(now);
211
218
  }
212
- /** Copies `file` the first time it is about to change in this run. A file that does not exist has nothing to keep. */
219
+ /**
220
+ * Copies `file` the first time it is about to change in this run. A file that does not exist, or holds nothing (empty,
221
+ * or the `{}` pi writes to auth.json when it first starts), has nothing to keep: a first setup makes no backup folder
222
+ * and does not say it kept the previous files.
223
+ */
213
224
  save(file) {
214
- if (this.saved.has(file) || !existsSync2(file)) return;
225
+ if (this.saved.has(file) || !existsSync2(file) || holdsNothing(file)) return;
215
226
  const folder = this.folder();
216
227
  const copy = join2(folder, basename(file));
217
228
  copyFileSync(file, copy);
@@ -328,6 +339,16 @@ function tiersOf(config) {
328
339
  function withTiers(config, tiers) {
329
340
  return { ...config, tiers: [...tiers] };
330
341
  }
342
+ function judgeOff(config) {
343
+ return isRecord(config?.modes) && config.modes.default === "off";
344
+ }
345
+ function withJudge(config, on) {
346
+ const { default: _default, ...modes } = isRecord(config.modes) ? config.modes : {};
347
+ if (!on) return { ...config, modes: { default: "off", ...modes } };
348
+ if (!judgeOff(config)) return config;
349
+ const { modes: _modes, ...rest } = config;
350
+ return Object.keys(modes).length > 0 ? { ...rest, modes } : rest;
351
+ }
331
352
  function readTextFile(path) {
332
353
  try {
333
354
  return readFileSync(path, "utf8");
@@ -378,14 +399,17 @@ function piAccess(runtime, agentDir2) {
378
399
  storeKey: async (provider, key) => {
379
400
  await runtime.refresh({ allowNetwork: false, providers: [provider] });
380
401
  if (!runtime.getProvider(provider)) {
381
- throw new Error(`pi has no provider ${provider}${runtime.getError() ? `: ${runtime.getError()}` : ""}`);
402
+ throw new Error(
403
+ `mu has no provider named ${provider}${runtime.getError() ? `: ${runtime.getError()}` : ""}`
404
+ );
382
405
  }
383
406
  let asked = false;
384
407
  try {
385
408
  await runtime.login(provider, "api_key", {
386
409
  // pi's key login asks one question, the key. Anything else is not answered, and nothing is guessed.
387
410
  prompt: async (prompt) => {
388
- if (asked || prompt.type !== "secret") throw new Error(`pi asked ${provider} for more than a key`);
411
+ if (asked || prompt.type !== "secret")
412
+ throw new Error(`the sign-in for ${provider} asked for more than a key`);
389
413
  asked = true;
390
414
  return key;
391
415
  },
@@ -459,11 +483,31 @@ function askSecret(input, output, question) {
459
483
  input.resume();
460
484
  });
461
485
  }
486
+ var columnsOf = (char) => /[\u1100-\u115f\u2e80-\ua4cf\uac00-\ud7a3\uf900-\ufaff\ufe30-\ufe4f\uff00-\uff60\uffe0-\uffe6]/u.test(char) ? 2 : 1;
487
+ var widthOf = (text) => Array.from(text).reduce((sum, char) => sum + columnsOf(char), 0);
488
+ function wrapToWidth(text, width) {
489
+ if (!width || width < 20) return text;
490
+ return text.split("\n").map((line) => {
491
+ if (widthOf(line) <= width) return line;
492
+ const indent = " ".repeat(/^\s*(?:\d+\)\s+)?/.exec(line)?.[0].length ?? 0);
493
+ const out = [];
494
+ let current = "";
495
+ for (const word of line.trimEnd().split(/(?<=\S) (?=\S)/)) {
496
+ const next = current ? `${current} ${word}` : word;
497
+ if (current && widthOf(next) > width) {
498
+ out.push(current);
499
+ current = `${indent}${word.trimStart()}`;
500
+ } else current = next;
501
+ }
502
+ out.push(current);
503
+ return out.join("\n");
504
+ }).join("\n");
505
+ }
462
506
  function terminalPrompter(input = process.stdin, output = process.stdout, errors = process.stderr) {
463
507
  return {
464
- say: (text) => output.write(`${text}
508
+ say: (text) => output.write(`${wrapToWidth(text, output.isTTY ? output.columns : void 0)}
465
509
  `),
466
- warn: (text) => errors.write(`${text}
510
+ warn: (text) => errors.write(`${wrapToWidth(text, errors.isTTY ? errors.columns : void 0)}
467
511
  `),
468
512
  ask: (question) => askLine(input, output, question),
469
513
  secret: (question) => askSecret(input, output, question)
@@ -885,6 +929,12 @@ var SETUP_SERVICES = [
885
929
  keyOptional: true
886
930
  }
887
931
  ];
932
+ var FIRST_IN_ENGLISH = ["openai", "anthropic", "google", "xai", "openrouter", "opencode"];
933
+ function servicesInOrder(language) {
934
+ if (language === "zh") return SETUP_SERVICES;
935
+ const first = FIRST_IN_ENGLISH.flatMap((id) => SETUP_SERVICES.filter((service) => service.id === id));
936
+ return [...first, ...SETUP_SERVICES.filter((service) => !FIRST_IN_ENGLISH.includes(service.id))];
937
+ }
888
938
  function serviceById(id) {
889
939
  return SETUP_SERVICES.find((service) => service.id === id);
890
940
  }
@@ -893,6 +943,9 @@ function cleanKey(raw) {
893
943
  if (key.length >= 2 && (key[0] === '"' || key[0] === "'") && key.at(-1) === key[0]) key = key.slice(1, -1).trim();
894
944
  return key;
895
945
  }
946
+ function isClaudeSubscriptionToken(key) {
947
+ return cleanKey(key).startsWith("sk-ant-oat");
948
+ }
896
949
  function servicesForKey(key) {
897
950
  const clean = cleanKey(key);
898
951
  return clean ? SETUP_SERVICES.filter((service) => service.keyShape?.test(clean)) : [];
@@ -939,7 +992,7 @@ function namedModel(service) {
939
992
 
940
993
  // packages/kyrn-judge/src/setup/wizard.ts
941
994
  var SETUP_DECLINED_FILE = "setup-declined";
942
- var SETUP_EXIT = { done: 0, failed: 1, usage: 2, start: 3, cancelled: 130 };
995
+ var SETUP_EXIT = { done: 0, failed: 1, usage: 2, start: 3, signIn: 4, cancelled: 130 };
943
996
  var SETUP_VALUE_FLAGS = [
944
997
  "--service",
945
998
  "--model",
@@ -970,6 +1023,10 @@ var JEV_TIERS = /* @__PURE__ */ new Set([
970
1023
  ]);
971
1024
  var OPENCODE_KEY = "OPENCODE_API_KEY";
972
1025
  var JEV_PAGE = "https://typesafe.ai";
1026
+ var CLAUDE_TOKEN = {
1027
+ 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",
1028
+ 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"
1029
+ };
973
1030
  var BRANDED = /* @__PURE__ */ new Set(["openai", "anthropic", "openrouter", "google", "xai"]);
974
1031
  var OTHER = {
975
1032
  zh: "\u5176\u4ED6 OpenAI \u6216 Anthropic \u517C\u5BB9\u7684\u670D\u52A1",
@@ -1003,11 +1060,11 @@ function parseSetupArgs(argv) {
1003
1060
  return { error: { zh: "--api \u53EA\u80FD\u662F openai \u6216 anthropic", en: "--api must be openai or anthropic" } };
1004
1061
  }
1005
1062
  const judge = values.get("--judge");
1006
- if (judge !== void 0 && !["jev", "opencode", "free", "model", "none"].includes(judge)) {
1063
+ if (judge !== void 0 && !["jev", "opencode", "free", "model", "off", "none"].includes(judge)) {
1007
1064
  return {
1008
1065
  error: {
1009
- zh: "--judge \u53EA\u80FD\u662F jev\u3001opencode\u3001free\u3001model \u6216 none",
1010
- en: "--judge must be jev, opencode, free, model or none"
1066
+ zh: "--judge \u53EA\u80FD\u662F jev\u3001opencode\u3001free\u3001model\u3001off \u6216 none",
1067
+ en: "--judge must be jev, opencode, free, model, off or none"
1011
1068
  }
1012
1069
  };
1013
1070
  }
@@ -1050,13 +1107,14 @@ function setupUsage(language) {
1050
1107
  "\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
1108
  "\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
1109
  "",
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",
1110
+ " --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
1111
  " --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",
1112
+ " --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",
1113
+ " --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",
1114
+ " --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",
1115
+ " --judge none \u4E0D\u6539\u5224\u5B9A\u5668\uFF1B\u4E0D\u5199 --judge \u65F6\u4E5F\u4E0D\u6539",
1116
+ " --api, --name \u670D\u52A1 other \u7684\u63A5\u53E3\uFF08openai \u6216 anthropic\uFF09\u548C\u5B83\u5728 mu \u91CC\u7684\u540D\u5B57",
1117
+ " --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
1118
  "",
1061
1119
  "\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
1120
  "\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"
@@ -1075,14 +1133,15 @@ function setupUsage(language) {
1075
1133
  "computer that lists processes can read it. `mu setup <key>` is a shortcut for getting started; paste the key",
1076
1134
  "at the prompt when you can.",
1077
1135
  "",
1078
- " --judge jev read the Jev key (TypeSafe) from stdin's second line, unless TYPESAFE_API_KEY is already set",
1136
+ " --judge jev read the Jev key (TypeSafe) from stdin's second line, unless TYPESAFE_API_KEY is already set",
1079
1137
  " --judge opencode use Jev on OpenCode Zen with an OpenCode key (--service opencode or OPENCODE_API_KEY)",
1080
- " --judge free use the free Jev on OpenCode Zen (limited time, no key; the default while no key is set)",
1081
- " --judge model use the model you just set up as the judge (slower, and every verdict costs tokens)",
1082
- " --judge none leave the judge unchanged (the same as omitting --judge)",
1083
- " --api, --name for the service `other`: its API (openai or anthropic) and its name in mu",
1084
- " --yes don't ask; replace what's already set up (a subscription sign-in, a provider's address,",
1085
- " the Jev key)",
1138
+ " --judge free use the free Jev on OpenCode Zen (limited time, no key; the default while no key is set)",
1139
+ " --judge model use the model you just set up as the judge (slower, and every verdict costs tokens)",
1140
+ " --judge off no judge: every decision point is off, and nothing is sent to a judge",
1141
+ " --judge none leave the judge unchanged (the same as omitting --judge)",
1142
+ " --api, --name for the service `other`: its API (openai or anthropic) and its name in mu",
1143
+ " --yes don't ask; replace what's already set up (a subscription sign-in, a provider's",
1144
+ " address, the Jev key)",
1086
1145
  "",
1087
1146
  "Files it changes: auth.json (keys), models.json, settings.json and mu.json in ~/.mu/agent, and the .env",
1088
1147
  "mu reads (the Jev key). Each one is backed up to ~/.mu/backups/<time>/ before it changes."
@@ -1093,7 +1152,7 @@ function label(service, language) {
1093
1152
  }
1094
1153
  function serviceList(language) {
1095
1154
  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");
1155
+ return servicesInOrder(language).map((service) => ` ${service.id.padEnd(width)} ${label(service, language)}`).join("\n");
1097
1156
  }
1098
1157
  function providerIdFor(baseUrl) {
1099
1158
  let host;
@@ -1202,10 +1261,14 @@ var Setup = class {
1202
1261
  if (key || allowEmpty) return key;
1203
1262
  }
1204
1263
  }
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 won't be shown): " })
1208
- );
1264
+ async pasteKey() {
1265
+ for (; ; ) {
1266
+ const key = await this.secret(
1267
+ 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): " })
1268
+ );
1269
+ if (!isClaudeSubscriptionToken(key)) return key;
1270
+ this.io.warn(this.t(CLAUDE_TOKEN));
1271
+ }
1209
1272
  }
1210
1273
  async choose(question, choices) {
1211
1274
  this.io.say(question);
@@ -1245,6 +1308,7 @@ var Setup = class {
1245
1308
  key = modelKey;
1246
1309
  this.jevFromStdin = jevKey;
1247
1310
  }
1311
+ if (key !== void 0 && isClaudeSubscriptionToken(key)) throw this.fail(CLAUDE_TOKEN, SETUP_EXIT.usage);
1248
1312
  if (this.scripted && key === void 0 && args.service === void 0) {
1249
1313
  throw this.fail(
1250
1314
  deps.interactive ? { zh: "\u6CA1\u6709\u5BC6\u94A5\uFF0C\u4E5F\u6CA1\u6709 --service", en: "no key or --service given" } : {
@@ -1265,7 +1329,7 @@ var Setup = class {
1265
1329
  const start = await this.start(key === void 0 ? void 0 : cleanKey(key));
1266
1330
  if (start === "subscription") {
1267
1331
  const code2 = await this.write(void 0, void 0, await this.judge(void 0));
1268
- return code2 === SETUP_EXIT.done ? this.offerSession() : code2;
1332
+ return code2 === SETUP_EXIT.done ? this.offerSession(true) : code2;
1269
1333
  }
1270
1334
  const target = await this.checked(start.service, start.key);
1271
1335
  this.modelKey = target.key;
@@ -1321,8 +1385,8 @@ var Setup = class {
1321
1385
  { label: this.t({ zh: "\u4ECE\u5217\u8868\u91CC\u9009\u4E00\u4E2A\u670D\u52A1", en: "Choose a service from the list" }), value: "list" },
1322
1386
  {
1323
1387
  label: this.t({
1324
- zh: "\u7528\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\uFF1AChatGPT\u3001Claude\u3001Grok \u6216 Google",
1325
- en: "Sign in with a subscription: ChatGPT, Claude, Grok or Google"
1388
+ zh: "\u7528\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\uFF1AChatGPT\u3001Grok \u6216 Google",
1389
+ en: "Sign in with a subscription: ChatGPT, Grok or Google"
1326
1390
  }),
1327
1391
  value: "subscription"
1328
1392
  }
@@ -1332,13 +1396,13 @@ var Setup = class {
1332
1396
  const auth = this.path(join3(this.deps.paths.agentDir, "auth.json"));
1333
1397
  this.io.say(
1334
1398
  this.t({
1335
- 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`,
1336
- en: `Subscriptions sign in from inside mu: start mu, type /login, choose ChatGPT (OpenAI Codex), Claude, Grok or Google, and finish in the browser. The sign-in is saved in ${auth}.`
1399
+ zh: `\u8BA2\u9605\u8D26\u53F7\u5728 mu \u91CC\u7528 /login \u767B\u5F55\uFF1A\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\u3002setup \u63A5\u7740\u542F\u52A8 mu \u65F6\uFF0C/login \u5DF2\u7ECF\u6253\u5F00\u3002\u767B\u5F55\u4FE1\u606F\u4FDD\u5B58\u5728 ${auth}\u3002`,
1400
+ en: `You sign in to a subscription inside mu, with /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. When setup starts mu, /login is already open. The sign-in is saved in ${auth}.`
1337
1401
  })
1338
1402
  );
1339
1403
  return "subscription";
1340
1404
  }
1341
- if (route === "list") return this.keyFor(await this.pickService(SETUP_SERVICES), void 0);
1405
+ if (route === "list") return this.keyFor(await this.pickService(servicesInOrder(this.language)), void 0);
1342
1406
  const pasted = await this.pasteKey();
1343
1407
  return { service: await this.serviceOf(pasted), key: pasted };
1344
1408
  }
@@ -1385,7 +1449,7 @@ var Setup = class {
1385
1449
  );
1386
1450
  }
1387
1451
  return this.pickService(
1388
- SETUP_SERVICES.filter((service) => !service.keyless),
1452
+ servicesInOrder(this.language).filter((service) => !service.keyless),
1389
1453
  this.t({
1390
1454
  zh: "mu \u8BA4\u4E0D\u51FA\u8FD9\u4E2A\u5BC6\u94A5\u3002\u5B83\u662F\u54EA\u4E2A\u670D\u52A1\u7684\uFF1F",
1391
1455
  en: "mu doesn't recognize this key. Which service is it for?"
@@ -1607,7 +1671,7 @@ var Setup = class {
1607
1671
  if (this.scripted) {
1608
1672
  throw this.fail({
1609
1673
  zh: `${this.name(service)} \u5DF2\u7ECF\u7528\u8BA2\u9605\u8D26\u53F7\u767B\u5F55\u4E86\u3002\u8981\u6539\u5B58\u5BC6\u94A5\uFF0C\u52A0\u4E0A --yes`,
1610
- en: `${this.name(service)} is signed in with a subscription. To use a key instead, add --yes`
1674
+ en: `You're signed in to ${this.name(service)} with a subscription. To use a key instead, add --yes`
1611
1675
  });
1612
1676
  }
1613
1677
  const replace = await this.confirm(
@@ -1796,8 +1860,8 @@ var Setup = class {
1796
1860
  }
1797
1861
  choices.push({
1798
1862
  label: this.t({
1799
- zh: "\u6682\u65F6\u4E0D\u8981\uFF1Amu \u5C31\u50CF pi \u4E00\u6837\u5DE5\u4F5C\uFF0C\u6CA1\u6709\u5224\u5B9A\u5668\u56DE\u7B54",
1800
- en: "Not now: mu works like plain pi, with no judge"
1863
+ 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",
1864
+ en: "Not now: no judge is asked and nothing is sent to one; mu uses its fallbacks"
1801
1865
  }),
1802
1866
  value: "none"
1803
1867
  });
@@ -1826,6 +1890,8 @@ var Setup = class {
1826
1890
  return { kind: "opencode" };
1827
1891
  case "free":
1828
1892
  return { kind: "free" };
1893
+ case "off":
1894
+ return { kind: "none" };
1829
1895
  case "jev": {
1830
1896
  const key = this.jevFromStdin;
1831
1897
  if (!key) {
@@ -1971,14 +2037,15 @@ var Setup = class {
1971
2037
  );
1972
2038
  }
1973
2039
  }
1974
- if (judge && judge.kind !== "none") this.writeJudge(judge, target, model, backups, saved, notes);
2040
+ if (judge?.kind === "none") this.writeNoJudge(backups, saved, notes);
2041
+ else if (judge) this.writeJudge(judge, target, model, backups, saved, notes);
1975
2042
  } catch (error) {
1976
2043
  if (error instanceof Stop) throw error;
1977
2044
  let reason = error instanceof Error ? error.message : String(error);
1978
2045
  for (const secret of [target?.key, judge?.kind === "jev" ? judge.key : void 0]) {
1979
2046
  if (secret) reason = reason.replaceAll(secret, "\u2026");
1980
2047
  }
1981
- this.io.warn(this.t({ zh: `mu setup\uFF1A\u4FDD\u5B58\u65F6\u51FA\u9519\uFF1A${reason}`, en: `mu setup: saving failed: ${reason}` }));
2048
+ this.io.warn(this.t({ zh: `mu setup\uFF1A\u4FDD\u5B58\u65F6\u51FA\u9519\uFF1A${reason}`, en: `mu setup: couldn't save: ${reason}` }));
1982
2049
  if (saved.length > 0) {
1983
2050
  this.io.warn(this.t({ zh: "\u51FA\u9519\u524D\u5DF2\u7ECF\u4FDD\u5B58\u7684\uFF1A", en: "Saved before the error:" }));
1984
2051
  for (const entry of saved) this.io.warn(entry);
@@ -2012,6 +2079,25 @@ var Setup = class {
2012
2079
  savedLine(path, what) {
2013
2080
  return ` ${this.path(path).padEnd(30)} ${what}`;
2014
2081
  }
2082
+ /** "Not now": no decision point asks a judge (the default mode "off"), so nothing goes to one. */
2083
+ writeNoJudge(backups, saved, notes) {
2084
+ const configPath = judgeConfigPath(this.deps.paths.agentDir);
2085
+ const config = readJsonFile(configPath);
2086
+ if (config.state === "unreadable") {
2087
+ notes.push(
2088
+ this.t({
2089
+ zh: `${this.path(configPath)} \u4E0D\u662F\u7EAF JSON\uFF0C\u6CA1\u6709\u6539\u5B83\u3002\u8BF7\u624B\u52A8\u52A0\u4E0A "modes": { "default": "off" }`,
2090
+ en: `${this.path(configPath)} isn't plain JSON, so it was left unchanged. Add "modes": { "default": "off" } by hand.`
2091
+ })
2092
+ );
2093
+ return;
2094
+ }
2095
+ const current = config.state === "ok" ? config.value : void 0;
2096
+ if (judgeOff(current)) return;
2097
+ backups.save(configPath);
2098
+ writeJsonFile(configPath, withJudge(current ?? {}, false));
2099
+ saved.push(this.savedLine(configPath, this.t({ zh: "\u5224\u5B9A\u5668\uFF1A\u5173\u95ED", en: "judge: off" })));
2100
+ }
2015
2101
  writeJudge(judge, target, model, backups, saved, notes) {
2016
2102
  const { env, paths } = this.deps;
2017
2103
  const configPath = judgeConfigPath(paths.agentDir);
@@ -2024,6 +2110,7 @@ var Setup = class {
2024
2110
  else if (judge.kind === "free") {
2025
2111
  if (!tiersOf(current).some((tier) => tier === "jev" || tier === "jev-opencode-free")) tiers = ["jev"];
2026
2112
  } else if (!tiersOf(current).some((tier) => JEV_TIERS.has(tier))) tiers = ["jev"];
2113
+ const turnOn = judgeOff(current);
2027
2114
  if (tiers && config.state === "unreadable") {
2028
2115
  notes.push(
2029
2116
  this.t({
@@ -2031,11 +2118,13 @@ var Setup = class {
2031
2118
  en: `${this.path(configPath)} isn't plain JSON, so it was left unchanged. Add "tiers": ${JSON.stringify(tiers)} by hand.`
2032
2119
  })
2033
2120
  );
2034
- } else if (tiers) {
2121
+ } else if (tiers || turnOn) {
2035
2122
  backups.save(configPath);
2036
- writeJsonFile(configPath, withTiers(current ?? {}, tiers));
2123
+ const next = tiers ? withTiers(current ?? {}, tiers) : current ?? {};
2124
+ writeJsonFile(configPath, turnOn ? withJudge(next, true) : next);
2125
+ const named2 = tiers ?? tiersOf(current);
2037
2126
  saved.push(
2038
- this.savedLine(configPath, this.t({ zh: `\u5224\u5B9A\u5668 ${tiers.join(", ")}`, en: `judge: ${tiers.join(", ")}` }))
2127
+ this.savedLine(configPath, this.t({ zh: `\u5224\u5B9A\u5668 ${named2.join(", ")}`, en: `judge: ${named2.join(", ")}` }))
2039
2128
  );
2040
2129
  }
2041
2130
  if (judge.kind === "jev") {
@@ -2081,14 +2170,19 @@ var Setup = class {
2081
2170
  target ? this.t({
2082
2171
  zh: "\u5728 mu \u91CC\u7528 /model \u6362\u6A21\u578B\uFF1B\u968F\u65F6\u53EF\u4EE5\u518D\u8FD0\u884C mu setup\u3002",
2083
2172
  en: "Switch models inside mu with /model, and run mu setup again any time."
2084
- }) : this.t({ zh: "\u542F\u52A8 mu \u540E\u8F93\u5165 /login \u767B\u5F55\u3002", en: "Start mu and type /login to sign in." })
2173
+ }) : this.t({ zh: "\u63A5\u4E0B\u6765\u5728 mu \u91CC\u7528 /login \u767B\u5F55\u3002", en: "Next, sign in with /login in mu." })
2085
2174
  );
2086
2175
  }
2087
- /** On its own, a finished setup offers a session; on a first start the launcher goes on into one anyway. */
2088
- async offerSession() {
2089
- if (this.args.firstRun || this.scripted) return SETUP_EXIT.done;
2176
+ /**
2177
+ * On its own, a finished setup offers a session; on a first start the launcher goes on into one anyway. After a
2178
+ * subscription was chosen (`signIn`), that session opens on /login: SETUP_EXIT.signIn.
2179
+ */
2180
+ async offerSession(signIn = false) {
2181
+ if (this.scripted) return SETUP_EXIT.done;
2182
+ if (this.args.firstRun) return signIn ? SETUP_EXIT.signIn : SETUP_EXIT.done;
2090
2183
  const start = await this.confirm(this.t({ zh: "\u73B0\u5728\u542F\u52A8 mu \u5417\uFF1F[Y/n] ", en: "Start mu now? [Y/n] " }), true);
2091
- return start ? SETUP_EXIT.start : SETUP_EXIT.done;
2184
+ if (!start) return SETUP_EXIT.done;
2185
+ return signIn ? SETUP_EXIT.signIn : SETUP_EXIT.start;
2092
2186
  }
2093
2187
  };
2094
2188
  function existingProviders(models) {