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
package/kyrn/bin/mu.mjs CHANGED
@@ -94,26 +94,28 @@ export function platformName({ platform, wsl }) {
94
94
  export function usage(platform) {
95
95
  const linkDir = platform === "win32" ? "%USERPROFILE%\\.local\\bin" : "~/.local/bin";
96
96
  return [
97
- "mu command line. (The project was called KYRN until 2026-09-21; the old spellings below still work.)",
97
+ "mu: a coding agent with a judgment kernel, built on pi.",
98
98
  "",
99
- " mu interactive session in the current directory",
100
- ' mu "prompt" interactive, starting with this prompt',
101
- ' mu -p "prompt" one-shot: print the answer and exit',
102
- " mu -c | -r continue the last session | pick one to resume",
103
- " mu setup connect a model (an API key, or a service from a list) and choose the judge",
104
- " (mu setup --help: scripts, a key from stdin, the services it knows)",
105
- " mu judge <cmd> the local judge (Laya): setup | start | stop | status | run",
106
- " mu ledger [n] [--json] what the judge decided in the last n sessions",
107
- " mu import --list | <file>... bring Claude Code and Codex conversations into mu (mu import --help)",
108
- " mu doctor check the installation",
109
- " mu auth <cmd> subscription sign-in for the desktop app, as JSON lines:",
99
+ " mu start a session in the current directory",
100
+ ' mu "prompt" start a session with this prompt',
101
+ ' mu -p "prompt" run one prompt, print the answer and exit',
102
+ " mu -c | -r continue the last session | pick a session to resume",
103
+ " mu setup connect a model (paste an API key or pick a service) and choose a judge",
104
+ " (see mu setup --help for scripting, reading a key from stdin and the supported services)",
105
+ " mu judge <cmd> manage the local judge, Laya (macOS on Apple silicon): setup | start | stop | status | run",
106
+ " mu ledger [n] [--json] print the judge's verdicts from the last n sessions",
107
+ " mu import <file>... import Claude Code, Codex and ZCode conversations; --list shows them (mu import --help)",
108
+ " mu doctor check the installation, the judges and the connections",
109
+ " mu auth <cmd> sign-in helper for the desktop app (JSON lines):",
110
110
  " status | login <provider> | logout <provider>",
111
- ` mu link | unlink put the \`mu\` command on your PATH (${linkDir}) | remove it`,
112
- " mu migrate [--dry-run] once: move the home from before the rename, ~/.kyrn, to ~/.mu",
113
- " mu help | version",
111
+ ` mu link | unlink put the mu command on your PATH (${linkDir}) | remove it`,
112
+ " mu migrate [--dry-run] move the old home folder, ~/.kyrn, to ~/.mu (once)",
113
+ " mu help | version show this help | print the version",
114
114
  "",
115
- "Everything else goes to the agent unchanged: `mu --help` lists every flag,",
116
- "and `mu install|remove|update|list|config` manage pi packages.",
115
+ "Everything else goes to pi unchanged: mu --help also shows pi's options,",
116
+ "and mu install|remove|update|list|config manage pi packages.",
117
+ "",
118
+ "Formerly KYRN: the kyrn commands still work.",
117
119
  ].join("\n");
118
120
  }
119
121
 
@@ -310,7 +312,7 @@ export function ensureAppView({ platform, app, upstream, fs = realFs }) {
310
312
  /**
311
313
  * Where this mu comes from: "repo", a checkout that runs the TypeScript sources (sourceRuntime), or "package", the
312
314
  * npm package mu-agent, which carries pi's bundle (dist/bundle/cli.js) and the judgment layer built to
313
- * JavaScript (judge/dist/kyrn-judge.js). A checkout without its dependencies is still a checkout.
315
+ * JavaScript (judge/mu/index.js). A checkout without its dependencies is still a checkout.
314
316
  */
315
317
  export function layoutOf({ root, platform, exists }) {
316
318
  const path = pathFor(platform);
@@ -326,7 +328,7 @@ export function packageEntries({ root, platform }) {
326
328
  const path = pathFor(platform);
327
329
  return {
328
330
  cli: path.join(root, "dist", "bundle", "cli.js"),
329
- extension: path.join(root, "judge", "dist", "kyrn-judge.js"),
331
+ extension: path.join(root, "judge", "mu", "index.js"),
330
332
  auth: path.join(root, "judge", "dist", "auth.js"),
331
333
  import: path.join(root, "judge", "dist", "import.js"),
332
334
  setup: path.join(root, "judge", "dist", "setup.js"),
@@ -356,13 +358,13 @@ export function installHint({ root, platform }) {
356
358
  const steps = [`cd ${root}`, "npm ci --ignore-scripts", "npm run hydrate:model-data"];
357
359
  // Windows PowerShell 5 has no `&&`.
358
360
  return platform === "win32"
359
- ? `mu's dependencies are not installed. Run:\n${steps.map((step) => ` ${step}`).join("\n")}`
360
- : `mu's dependencies are not installed. Run: ${steps.join(" && ")}`;
361
+ ? `mu's dependencies aren't installed. Run:\n${steps.map((step) => ` ${step}`).join("\n")}`
362
+ : `mu's dependencies aren't installed. Run: ${steps.join(" && ")}`;
361
363
  }
362
364
 
363
365
  /** What mu says on a Node that does not strip TypeScript types, which a checkout cannot run on. */
364
366
  const NO_TYPE_STRIPPING =
365
- "mu runs a checkout's TypeScript with Node's own type stripping (on by default from Node 22.18), and this Node does not strip types";
367
+ "mu runs a source checkout's TypeScript with Node's built-in type stripping (on by default since Node 22.18), but this Node doesn't strip types. Use Node 22.19 or newer.";
366
368
 
367
369
  /**
368
370
  * Node's arguments for running a checkout's TypeScript, up to the entry file. Node strips the types itself (on by
@@ -428,10 +430,10 @@ export function localJudgeSupport({ platform, env, wsl = false }) {
428
430
  runs: false,
429
431
  url,
430
432
  message: [
431
- `The local judge (Laya) is a Core ML sidecar: it runs on macOS with Apple Silicon only, not on ${where}.`,
432
- "mu works without it: use Jev (TYPESAFE_API_KEY or AI_GATEWAY_API_KEY) or an llm judge in mu.json;",
433
- "the desktop app's own local judge is being built. Decisions without a judge fall back to pi's behaviour.",
434
- "A server that speaks the same contract (GET /health, POST /evaluate) can be used from here:",
433
+ `The local judge (Laya) is a Core ML sidecar that runs only on macOS on Apple silicon, not on ${where}.`,
434
+ "mu works without it: Jev, the default hosted judge, answers instead (free on OpenCode Zen, or with your own key via mu setup); you can also set an LLM judge in mu.json.",
435
+ "A local judge for the desktop app is in progress. Without a judge, decision points use their fallbacks.",
436
+ "To use a server that implements the same API (GET /health, POST /evaluate), set:",
435
437
  " MU_LOCAL_JUDGE_URL=http://host:port",
436
438
  ].join("\n"),
437
439
  };
@@ -447,12 +449,39 @@ export function launchStrategy({ platform, env, canExec }) {
447
449
  /** How the judgment layer's extension joins pi's arguments: in front for a session, never in front of pi's own
448
450
  * commands (PI_COMMANDS), which pi reads as its first argument — an -e before them would turn them into a prompt.
449
451
  * The judgment layer never runs for them, so its extension stays out of their way. */
450
- function judgeArgs({ argv, layout, root, platform }) {
452
+ function judgeArgs({ argv, layout, root, platform, agentDir, readFile }) {
451
453
  if (PI_COMMANDS.has(argv[0])) return [];
452
- const path = pathFor(platform);
454
+ return ["-e", judgeExtension({ layout, root, platform }), ...themeArgs({ argv, layout, root, platform, agentDir, readFile })];
455
+ }
456
+
457
+ /** The judgment layer's extension file: the package's build, or a checkout's source. */
458
+ function judgeExtension({ layout, root, platform }) {
453
459
  return layout === "package"
454
- ? ["-e", packageEntries({ root, platform }).extension]
455
- : ["-e", path.join(root, "packages", "kyrn-judge", "src", "extension", "kyrn-judge.ts")];
460
+ ? packageEntries({ root, platform }).extension
461
+ : pathFor(platform).join(root, "packages", "kyrn-judge", "src", "extension", "kyrn-judge.ts");
462
+ }
463
+
464
+ /** mu's own terminal themes, beside the judgment layer's files. */
465
+ export function themesDir({ layout, root, platform }) {
466
+ const path = pathFor(platform);
467
+ return layout === "package" ? path.join(root, "judge", "themes") : path.join(root, "packages", "kyrn-judge", "themes");
468
+ }
469
+
470
+ /**
471
+ * An interactive session gets mu's themes (mu-light and mu-dark, which /settings then lists beside pi's) and, while the
472
+ * person has chosen no theme of their own, starts in them: light or dark as the terminal is. A theme chosen in
473
+ * /settings is saved in settings.json and wins; so does --use-theme. Print and RPC modes draw nothing and get neither.
474
+ */
475
+ function themeArgs({ argv, layout, root, platform, agentDir, readFile }) {
476
+ if (argv.includes("--mode") || argv.includes("-p") || argv.includes("--print")) return [];
477
+ const args = ["--theme", themesDir({ layout, root, platform })];
478
+ if (argv.includes("--use-theme") || !agentDir || !readFile) return args;
479
+ let chosen = false;
480
+ try {
481
+ const settings = JSON.parse(readFile(pathFor(platform).join(agentDir, "settings.json")));
482
+ chosen = typeof settings?.theme === "string" && settings.theme !== "";
483
+ } catch {}
484
+ return chosen ? args : [...args, "--use-theme", "mu-light/mu-dark"];
456
485
  }
457
486
 
458
487
  /**
@@ -485,7 +514,7 @@ export function planLaunch({
485
514
  } else {
486
515
  const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists });
487
516
  if (runtime.error) return { error: runtime.error };
488
- entry = [...runtime.args, path.join(root, "packages", "coding-agent", "src", "experimental", "cli.ts")];
517
+ entry = [...runtime.args, path.join(root, "packages", "coding-agent", "src", "cli.ts")];
489
518
  }
490
519
 
491
520
  const muDir = muHome({ home, platform, isDir: fs.isDir });
@@ -503,7 +532,7 @@ export function planLaunch({
503
532
  const parsed = parseEnvFile(envText);
504
533
  fromFile = envFileAdditions({ env, entries: parsed.entries, platform });
505
534
  // Line numbers only: the text of a line that did not parse may well be a secret.
506
- if (parsed.problems.length > 0) notes.push(`mu: .env: skipped line ${parsed.problems.join(", ")} (not KEY=VALUE)`);
535
+ if (parsed.problems.length > 0) notes.push(`mu: .env: skipped ${parsed.problems.length === 1 ? "line" : "lines"} ${parsed.problems.join(", ")} (expected KEY=VALUE)`);
507
536
  }
508
537
 
509
538
  const childEnv = {};
@@ -511,6 +540,8 @@ export function planLaunch({
511
540
  if (typeof value === "string") childEnv[key] = value;
512
541
  }
513
542
  childEnv.PI_PACKAGE_DIR = appDir;
543
+ // The judgment layer is part of mu, not an extension loaded for this run: pi shows its commands without [t].
544
+ childEnv.PI_APP_EXTENSIONS = judgeExtension({ layout, root, platform });
514
545
  childEnv.MU_CODING_AGENT_DIR = agentDir;
515
546
  childEnv.KYRN_CODING_AGENT_DIR = agentDir;
516
547
  childEnv.PI_CODING_AGENT_DIR = agentDir;
@@ -526,14 +557,14 @@ export function planLaunch({
526
557
  if (support.runs) startJudge = true;
527
558
  else if (!support.url) {
528
559
  notes.push(
529
- `mu: the configuration asks for the local judge (laya), which runs on macOS only; on ${platformName({ platform, wsl })} its decisions fall back to the next judge or to pi's behaviour (mu judge status)`,
560
+ `mu: the configuration asks for the local judge (Laya), which runs on macOS only; on ${platformName({ platform, wsl })}, the decision points it would answer use the next judge or their fallbacks (mu judge status)`,
530
561
  );
531
562
  }
532
563
  }
533
564
 
534
565
  return {
535
566
  command: execPath,
536
- args: [...entry, ...judgeArgs({ argv, layout, root, platform }), ...argv],
567
+ args: [...entry, ...judgeArgs({ argv, layout, root, platform, agentDir, readFile: fs.readFile }), ...argv],
537
568
  env: childEnv,
538
569
  strategy: launchStrategy({ platform, env, canExec }),
539
570
  layout,
@@ -542,7 +573,7 @@ export function planLaunch({
542
573
  agentDir,
543
574
  startJudge,
544
575
  notes,
545
- preface: argv[0] === "-h" || argv[0] === "--help" ? `${usage(platform)}\n\nAgent flags:\n` : undefined,
576
+ preface: argv[0] === "-h" || argv[0] === "--help" ? `${usage(platform)}\n\npi's help (mu passes all of this through):\n` : undefined,
546
577
  };
547
578
  }
548
579
 
@@ -552,6 +583,9 @@ export function planLaunch({
552
583
  * Node flags that process starts with, pi's arguments (the judgment layer, then `argv`) and its whole environment.
553
584
  * The app's pi and the command line's are then one: the same files, settings, sign-ins and keys.
554
585
  *
586
+ * `cli` is the script the command line runs pi with. pi starts its sub-agents (swarm, hive, delegate) by running
587
+ * `process.argv[1]` again, which inside the host is the host's own file: the host hands pi this script there instead.
588
+ *
555
589
  * A checkout runs there as it runs on the command line (sourceRuntime). Returns { error } when pi cannot run.
556
590
  */
557
591
  export function planHost({ platform, env, argv, root, home, fs, wsl = false, stripsTypes = true }) {
@@ -571,8 +605,9 @@ export function planHost({ platform, env, argv, root, home, fs, wsl = false, str
571
605
  return {
572
606
  ...common,
573
607
  module: path.join(root, "dist", "bundle", "index.js"),
608
+ cli: packageEntries({ root, platform }).cli,
574
609
  execArgv: [],
575
- args: [...judgeArgs({ argv, layout: launch.layout, root, platform }), ...argv],
610
+ args: [...judgeArgs({ argv, layout: launch.layout, root, platform, agentDir: launch.agentDir, readFile: fs.readFile }), ...argv],
576
611
  };
577
612
  }
578
613
  const runtime = sourceRuntime({ root, platform, stripsTypes, exists: fs.exists });
@@ -580,14 +615,15 @@ export function planHost({ platform, env, argv, root, home, fs, wsl = false, str
580
615
  return {
581
616
  ...common,
582
617
  module: path.join(root, "packages", "coding-agent", "src", "index.ts"),
618
+ cli: path.join(root, "packages", "coding-agent", "src", "cli.ts"),
583
619
  execArgv: runtime.args,
584
- args: [...judgeArgs({ argv, layout: launch.layout, root, platform }), ...argv],
620
+ args: [...judgeArgs({ argv, layout: launch.layout, root, platform, agentDir: launch.agentDir, readFile: fs.readFile }), ...argv],
585
621
  };
586
622
  }
587
623
 
588
624
  /** What mu says when the local judge does not come up. */
589
625
  const LOCAL_JUDGE_NOT_STARTED =
590
- "mu: the local judge did not start (mu judge status); decisions fall back to pi's behaviour";
626
+ "mu: the local judge (Laya) didn't start; decision points use the next judge or their fallbacks. Run mu judge status for details.";
591
627
 
592
628
  /** The part of the preparation that is files: the app view of a checkout, mu's agent folder, the configuration's notes. */
593
629
  function prepareFiles({ plan, platform, root, err }) {
@@ -641,6 +677,29 @@ export async function prepareLaunchAsync({ plan, platform, root, bin, err }) {
641
677
  /** What `mu auth` answers itself. Every other `auth` command (check, print-api-key, ...) is pi's own. */
642
678
  export const AUTH_COMMANDS = ["status", "login", "logout"];
643
679
 
680
+ /** `mu link --help` and `mu unlink --help`. */
681
+ export const LINK_USAGE = [
682
+ "mu link: put this mu on your PATH, as a link in ~/.local/bin (on Windows, a small mu.cmd there). MU_LINK_DIR",
683
+ "names another folder.",
684
+ "",
685
+ " mu link link this mu, unless another mu is already on your PATH",
686
+ " mu link --force link it anyway (it comes first only if its folder comes first on your PATH)",
687
+ " mu unlink remove the link mu link made",
688
+ "",
689
+ "A mu installed with npm is already on your PATH and needs neither.",
690
+ ].join("\n");
691
+
692
+ /** What `mu auth --help` (or a bare `mu auth`) says before pi's own auth commands. */
693
+ export const AUTH_USAGE = [
694
+ "mu's sign-in, which the desktop app runs (JSON lines on stdout):",
695
+ " mu auth status",
696
+ " mu auth login <provider>",
697
+ " mu auth logout <provider>",
698
+ "In a terminal, /login inside mu signs in the same way.",
699
+ "",
700
+ "pi's auth commands:",
701
+ ].join("\n");
702
+
644
703
  /**
645
704
  * `mu auth status | login <provider> | logout <provider>`: the sign-in the desktop app runs, with pi's own OAuth
646
705
  * flows and credential store (packages/kyrn-judge/src/auth). It is pi's code, so it runs the way pi does here:
@@ -688,7 +747,7 @@ export function planJudge({ platform, env, argv, bin, wsl = false }) {
688
747
  // ---------------------------------------------------------------------------------------------------------
689
748
 
690
749
  /**
691
- * `mu import`: Claude Code and Codex conversations into mu's sessions (packages/kyrn-judge/src/import). The importer
750
+ * `mu import`: Claude Code, Codex and ZCode conversations into mu's sessions (packages/kyrn-judge/src/import). The importer
692
751
  * needs nothing but Node: the npm package runs its build, judge/dist/import.js, and a checkout its TypeScript with
693
752
  * Node's own type stripping (on by default from 22.18).
694
753
  */
@@ -726,6 +785,17 @@ export const SETUP_DECLINED_FILE = "setup-declined";
726
785
  /** How `mu setup` says: set up, and start a session now. */
727
786
  export const SETUP_EXIT_START = 3;
728
787
 
788
+ /** How `mu setup` says: a subscription was chosen, so start a session that opens on /login. */
789
+ export const SETUP_EXIT_SIGN_IN = 4;
790
+
791
+ /**
792
+ * What the session is started with after the wizard ended with `code`: /login after a subscription was chosen, unless
793
+ * the command line already says what to do.
794
+ */
795
+ export function afterSetup(code, argv) {
796
+ return code === SETUP_EXIT_SIGN_IN && argv.length === 0 ? ["/login"] : argv;
797
+ }
798
+
729
799
  /** How `mu setup` says it was cancelled (ctrl+c): a first start then goes no further. */
730
800
  export const SETUP_EXIT_CANCELLED = 130;
731
801
 
@@ -1003,7 +1073,7 @@ export function planLink({ platform, env, home, bin, argv, fs }) {
1003
1073
  return {
1004
1074
  action: "refuse",
1005
1075
  errors: [
1006
- `${link} already exists and is not this mu; it was left alone. Choose another folder: MU_LINK_DIR=<dir> mu link`,
1076
+ `${link} already exists and is not this mu, so it was left alone. To use another folder: MU_LINK_DIR=<dir> mu link`,
1007
1077
  ],
1008
1078
  };
1009
1079
  }
@@ -1031,7 +1101,7 @@ export function planLink({ platform, env, home, bin, argv, fs }) {
1031
1101
  if (windows && /[^\x00-\x7f]/.test(content)) {
1032
1102
  notes.push(
1033
1103
  "Note: the path from that folder to this repository has non-ASCII characters in it, and cmd reads a batch file in the",
1034
- "console's code page. If `mu` then cannot find its target, choose a folder on the same drive (MU_LINK_DIR), or put",
1104
+ "console's code page. If mu then can't find its target, choose a folder on the same drive (MU_LINK_DIR), or put",
1035
1105
  `${bin} on your PATH instead.`,
1036
1106
  );
1037
1107
  }
@@ -1046,12 +1116,12 @@ export function planUnlink({ platform, env, home, fs }) {
1046
1116
  text = fs.readFile(link);
1047
1117
  } catch {}
1048
1118
  return text?.includes(SHIM_MARK)
1049
- ? { remove: link, message: `removed ${link}` }
1050
- : { message: `${link} is not a shim written by mu link; nothing removed` };
1119
+ ? { remove: link, message: `Removed ${link}.` }
1120
+ : { message: `${link} is not a shim written by mu link; nothing removed.` };
1051
1121
  }
1052
1122
  return fs.isLink(link)
1053
- ? { remove: link, message: `removed ${link}` }
1054
- : { message: `${link} is not a link; nothing removed` };
1123
+ ? { remove: link, message: `Removed ${link}.` }
1124
+ : { message: `${link} is not a link; nothing removed.` };
1055
1125
  }
1056
1126
 
1057
1127
  /** What `mu doctor` says about the command. */
@@ -1200,8 +1270,8 @@ export function migrate({ platform, home, argv, fs, run, alive, self, out, err }
1200
1270
  return 0;
1201
1271
  }
1202
1272
  if (fs.exists(next) || fs.isLink(next)) {
1203
- err(`${next} already exists, so nothing was moved. Two homes are never merged or overwritten here:`);
1204
- err("look at both folders and decide which one is the real one.");
1273
+ err(`${next} already exists, so nothing was moved. mu never merges or overwrites two home folders:`);
1274
+ err("look at both and decide which one to keep.");
1205
1275
  return 1;
1206
1276
  }
1207
1277
  // Whatever is running would write into the gap between the rename and the link, and split the home in two.
@@ -1210,10 +1280,10 @@ export function migrate({ platform, home, argv, fs, run, alive, self, out, err }
1210
1280
  try {
1211
1281
  pid = Number.parseInt(fs.readFile(path.join(old, "local-judge", "judge.pid")).trim(), 10);
1212
1282
  } catch {}
1213
- if (pid > 0 && alive(pid)) busy.push(` the local judge (pid ${pid}). Stop it: mu judge stop`);
1283
+ if (pid > 0 && alive(pid)) busy.push(` the local judge (pid ${pid}). Stop it with mu judge stop`);
1214
1284
  const found = findBusy({ platform, old, run, self });
1215
1285
  if (!found) {
1216
- err("Nothing was moved: the list of running processes could not be read (tasklist, powershell), so it is not known whether mu is still running.");
1286
+ err("Nothing was moved: mu couldn't read the list of running processes (tasklist, powershell), so it can't tell whether mu is still running.");
1217
1287
  return 1;
1218
1288
  }
1219
1289
  const list = (pids) => pids.join(" ");
@@ -1222,7 +1292,7 @@ export function migrate({ platform, home, argv, fs, run, alive, self, out, err }
1222
1292
  }
1223
1293
  if (found.browser.length > 0) busy.push(` the mu browser (pid ${list(found.browser)}). Close it.`);
1224
1294
  if (found.desktop.length > 0) {
1225
- busy.push(` the desktop app's backend (pid ${list(found.desktop)}). Quit the desktop app.`);
1295
+ busy.push(` the desktop app's local service (pid ${list(found.desktop)}). Quit the desktop app.`);
1226
1296
  }
1227
1297
  if (busy.length > 0) {
1228
1298
  err(`Nothing was moved, because these are still using ${old}:`);
@@ -1247,7 +1317,7 @@ export function migrate({ platform, home, argv, fs, run, alive, self, out, err }
1247
1317
  out(`renamed ${path.join(next, config)} -> mu.json`);
1248
1318
  }
1249
1319
  out(`linked ${old} -> ${next} (paths stored from before the rename keep working)`);
1250
- out("Check it: mu doctor");
1320
+ out("To check it, run mu doctor");
1251
1321
  return 0;
1252
1322
  }
1253
1323
 
@@ -1329,7 +1399,7 @@ function handOver({ command, args, env, strategy }) {
1329
1399
  for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) process.on(signal, () => relay(signal));
1330
1400
  if (process.platform === "win32") process.on("SIGBREAK", () => {});
1331
1401
  child.on("error", (error) => {
1332
- err(`mu: could not start ${command}: ${error.message}`);
1402
+ err(`mu: couldn't start ${command}: ${error.message}`);
1333
1403
  resolve(1);
1334
1404
  });
1335
1405
  child.on("exit", (code, signal) => resolve(code ?? 128 + (osConstants.signals[signal] ?? 0)));
@@ -1363,6 +1433,8 @@ export async function main(argv = process.argv.slice(2)) {
1363
1433
  out(usage(platform));
1364
1434
  return 0;
1365
1435
  }
1436
+ // mu's own auth commands first; pi prints its own after them.
1437
+ if (command === "auth" && (rest.length === 0 || rest[0] === "--help" || rest[0] === "-h")) out(AUTH_USAGE);
1366
1438
  if (command === "auth" && AUTH_COMMANDS.includes(rest[0])) {
1367
1439
  const plan = planAuth({
1368
1440
  platform,
@@ -1426,7 +1498,7 @@ export async function main(argv = process.argv.slice(2)) {
1426
1498
  out(await response.text());
1427
1499
  return 0;
1428
1500
  } catch {
1429
- out(`the judge server does not answer at ${plan.url}`);
1501
+ out(`The local judge server isn't answering at ${plan.url}. Check that it's running.`);
1430
1502
  return 1;
1431
1503
  }
1432
1504
  }
@@ -1471,8 +1543,8 @@ export async function main(argv = process.argv.slice(2)) {
1471
1543
  if (plan.keyGiven) process.title = "mu setup";
1472
1544
  mkdirSync(plan.agentDir, { recursive: true });
1473
1545
  const code = await handOver(plan);
1474
- if (code !== SETUP_EXIT_START) return code;
1475
- sessionArgv = [];
1546
+ if (code !== SETUP_EXIT_START && code !== SETUP_EXIT_SIGN_IN) return code;
1547
+ sessionArgv = afterSetup(code, []);
1476
1548
  }
1477
1549
  if (command === "doctor") {
1478
1550
  const link = linkPath({ platform, env, home });
@@ -1483,8 +1555,12 @@ export async function main(argv = process.argv.slice(2)) {
1483
1555
  strategy,
1484
1556
  });
1485
1557
  }
1558
+ if ((command === "link" || command === "unlink") && (rest[0] === "--help" || rest[0] === "-h")) {
1559
+ out(LINK_USAGE);
1560
+ return 0;
1561
+ }
1486
1562
  if ((command === "link" || command === "unlink") && layout === "package") {
1487
- out("This mu was installed with npm, which already put `mu` on your PATH (npm i -g mu-agent); nothing to link.");
1563
+ out("This mu was installed with npm, which already put `mu` on your PATH (npm i -g mu-agent); nothing to do.");
1488
1564
  return 0;
1489
1565
  }
1490
1566
  if (command === "link") {
@@ -1517,9 +1593,10 @@ export async function main(argv = process.argv.slice(2)) {
1517
1593
  return 0;
1518
1594
  }
1519
1595
 
1520
- if (layout === "package" && command === "version") {
1596
+ // --version is the bare number, in the npm package as in a checkout (below).
1597
+ if (layout === "package" && (command === "version" || command === "--version" || command === "-v")) {
1521
1598
  const pkg = JSON.parse(readText(path.join(root, "package.json")));
1522
- out(`mu ${pkg.version} (pi ${pkg.muBuild?.pi ?? "?"}, npm package ${pkg.name})`);
1599
+ out(command === "version" ? `mu ${pkg.version} (pi ${pkg.muBuild?.pi ?? "?"}, npm package ${pkg.name})` : pkg.version);
1523
1600
  return 0;
1524
1601
  }
1525
1602
  // Asked before `version` too, as it always was: a checkout without its dependencies says so at the first command.
@@ -1527,10 +1604,12 @@ export async function main(argv = process.argv.slice(2)) {
1527
1604
  err(installHint({ root, platform }));
1528
1605
  return 1;
1529
1606
  }
1530
- if (command === "version") {
1607
+ if (command === "version" || command === "--version" || command === "-v") {
1531
1608
  // mu's version is the one this tree is released as; the judgment layer's own package.json is never released.
1532
1609
  const version = (file) => JSON.parse(readText(path.join(root, ...file.split("/")))).version;
1533
- out(`mu ${version("kyrn/npm/package.template.json")} (pi ${version("packages/coding-agent/package.json")})`);
1610
+ const mu = version("kyrn/npm/package.template.json");
1611
+ // --version is the bare number, as the npm package's pi bundle prints it; pi's own here would be pi's version.
1612
+ out(command === "version" ? `mu ${mu} (pi ${version("packages/coding-agent/package.json")})` : mu);
1534
1613
  return 0;
1535
1614
  }
1536
1615
 
@@ -1564,7 +1643,9 @@ export async function main(argv = process.argv.slice(2)) {
1564
1643
  if (!setup.error) {
1565
1644
  mkdirSync(setup.agentDir, { recursive: true });
1566
1645
  // Whatever the wizard ends with, the session follows (pi says itself when there is no model), unless it was cancelled.
1567
- if ((await handOver(setup)) === SETUP_EXIT_CANCELLED) return SETUP_EXIT_CANCELLED;
1646
+ const code = await handOver(setup);
1647
+ if (code === SETUP_EXIT_CANCELLED) return SETUP_EXIT_CANCELLED;
1648
+ sessionArgv = afterSetup(code, sessionArgv);
1568
1649
  }
1569
1650
  }
1570
1651
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  Serves a Laya Core ML checkpoint (https://github.com/mizorewww/laya-coreml) over
5
5
  the same wire contract as the AI Gateway `evaluation-model` endpoint, so the
6
- mu kernel can swap Jev for a local model without translating anything:
6
+ mu kernel can swap the hosted judge model for a local one without translating anything:
7
7
 
8
8
  POST /evaluate {"state": ..., "questions": {id: {type, instructions, criteria?}}}
9
9
  -> {"answers": {...}, "usage": {...}, "warnings": [...], "providerMetadata": {"laya": {...}}}
@@ -27,9 +27,16 @@ from pathlib import Path
27
27
  DEFAULT_HOST = "127.0.0.1"
28
28
  DEFAULT_PORT = 47823
29
29
  MAX_BODY_BYTES = 1024 * 1024
30
- # Measured on an M3 Max with 10-question preflights: no floor p50 411 ms (one shape switch per request),
31
- # 256 -> 124 ms, 384 -> 155 ms. Requests longer than the floor still work; they just pay the switch.
32
- DEFAULT_MIN_LENGTH = 256
30
+ # Every request is padded to at least this many tokens; by default (None) to the checkpoint's whole window, so that
31
+ # after warm-up the input length never changes. A change of length is what crashed the sidecar: Core ML re-specializes
32
+ # the GPU program from its compiled copy of the model in ~/Library/Caches/<process>/com.apple.e5rt.e5bundlecache,
33
+ # which it marks APFS-purgeable, and macOS deletes those files whenever the disk runs low. The next change of length
34
+ # then recompiles the model (3-36 s, 644 MB written again) or, when the purge lands mid-load, aborts the process with
35
+ # "MPSGraphTensorData.mm: failed assertion `shape.count = 0 != strides.count = 2'". Measured on an M6 under load:
36
+ # 1024 tokens cost ~34 ms a question at a steady length against ~23-32 ms for 384-768, while a change of length
37
+ # cost 0.4-1.1 s at p50 and up to 18 s at p90. A lower floor (MU_LOCAL_JUDGE_MIN_LENGTH=256) is faster for short
38
+ # requests and brings the changes of length back.
39
+ DEFAULT_MIN_LENGTH = None
33
40
  DEFAULT_MODEL_DIR = Path(__file__).resolve().parent / "models" / "laya-multilingual-coreml"
34
41
 
35
42
 
@@ -88,11 +95,10 @@ def from_laya_answer(answer):
88
95
 
89
96
 
90
97
  class LocalJudge:
91
- def __init__(self, model_dir, compute_units=None, min_length=0):
98
+ def __init__(self, model_dir, compute_units=None, min_length=DEFAULT_MIN_LENGTH):
92
99
  import laya_coreml as laya
93
100
 
94
101
  self.model_dir = Path(model_dir)
95
- self.min_length = min_length
96
102
  started = time.perf_counter()
97
103
  self.agent = laya.load(str(self.model_dir), local_files_only=True, compute_units=compute_units)
98
104
  self.load_seconds = time.perf_counter() - started
@@ -103,15 +109,19 @@ class LocalJudge:
103
109
  manifest = getattr(self.agent, "manifest", {})
104
110
  self.model_id = "laya:" + str(manifest.get("repository") or self.model_dir.name)
105
111
  self.shape = getattr(self.agent, "shape", {})
112
+ if min_length is None:
113
+ min_length = getattr(self.agent, "cfg", {}).get("max_len") or self.shape.get("max_length") or 0
114
+ self.min_length = int(min_length)
106
115
 
107
116
  def uniform_shape(self, state, laya_questions):
108
117
  """Pad every question of a request to one input length.
109
118
 
110
119
  Core ML re-specializes the GPU program whenever the enumerated length
111
- changes (about 350 ms on an M3 Max, against 40 ms for a steady shape),
112
- and the questions of one request differ in length because their
113
- options do. One bucket per request removes those switches; the floor
114
- keeps consecutive requests on the same bucket too.
120
+ changes (0.3-1 s, against ~30 ms for a steady shape), reading the
121
+ compiled model back from a cache macOS may have purged (see
122
+ DEFAULT_MIN_LENGTH). The questions of one request differ in length
123
+ because their options do, so one bucket per request removes the
124
+ changes within it; the floor keeps every request in the same bucket.
115
125
  """
116
126
  lengths = self.agent.shape.get("lengths")
117
127
  if not lengths:
@@ -199,9 +209,10 @@ class LocalJudge:
199
209
  def warm_up(self):
200
210
  """Core ML compiles each enumerated input length on first use (seconds). Pay that before real traffic."""
201
211
  lengths = list(self.shape.get("lengths") or [self.shape.get("default_length", 128)])
202
- # Finish on the bucket real traffic starts in, so the first request does not pay a shape switch.
212
+ # Requests are padded to at least the floor's bucket, so no request uses a shorter one: warm only the lengths
213
+ # traffic can reach, and finish on the floor's bucket, so the first request does not pay a shape switch.
203
214
  resting = next((n for n in lengths if n >= self.min_length), lengths[-1])
204
- lengths = [n for n in lengths if n != resting] + [resting]
215
+ lengths = [n for n in lengths if n > resting] + [resting]
205
216
  question = {"warm": {"type": "noul", "instructions": "Is this a warm-up request?"}}
206
217
  started = time.perf_counter()
207
218
  for length in lengths:
@@ -299,8 +310,9 @@ def main():
299
310
  parser.add_argument(
300
311
  "--min-length",
301
312
  type=int,
302
- default=int(setting("LOCAL_JUDGE_MIN_LENGTH", DEFAULT_MIN_LENGTH)),
303
- help="Smallest input length to pad to. A floor above the usual request size avoids shape switches between requests.",
313
+ default=setting("LOCAL_JUDGE_MIN_LENGTH", DEFAULT_MIN_LENGTH),
314
+ help="Smallest input length to pad to. Default: the checkpoint's window, so the length never changes after "
315
+ "warm-up; a change of length is slow and, when macOS has purged Core ML's cache, can crash the sidecar.",
304
316
  )
305
317
  args = parser.parse_args()
306
318
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mu-agent",
3
- "version": "0.1.8",
4
- "description": "mu: a coding agent that thinks before it acts. A small, fast judge makes the routine calls; the big model keeps its attention for the work. Built on pi.",
3
+ "version": "0.1.13",
4
+ "description": "mu: a coding agent that hands its routine decisions to a small, fast judge model, so the main model can keep its attention on the work. Built on pi.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "mu": "kyrn/bin/mu.mjs"
@@ -12,13 +12,16 @@
12
12
  },
13
13
  "keywords": [
14
14
  "coding-agent",
15
+ "pi-coding-agent",
15
16
  "ai",
16
17
  "llm",
17
18
  "cli",
18
19
  "terminal",
19
20
  "agent",
20
21
  "judge",
21
- "pi"
22
+ "pi",
23
+ "mcp",
24
+ "prompt-injection"
22
25
  ],
23
26
  "homepage": "https://github.com/qybaihe/mu",
24
27
  "repository": {
@@ -33,13 +36,12 @@
33
36
  "node": ">=22.19.0"
34
37
  },
35
38
  "dependencies": {
36
- "@earendil-works/chord": "1.0.2",
37
39
  "@silvia-odwyer/photon-node": "0.3.4",
38
40
  "jiti": "2.7.0"
39
41
  },
40
42
  "muBuild": {
41
- "pi": "1.0.2",
43
+ "pi": "1.3.0",
42
44
  "judge": "0.1.0",
43
- "commit": "a63b81be9"
45
+ "commit": "47bdfac19"
44
46
  }
45
47
  }