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
@@ -0,0 +1,80 @@
1
+ {
2
+ "$schema": "https://pi.dev/schemas/theme.schema.json",
3
+ "name": "mu-dark",
4
+ "appearance": "dark",
5
+ "vars": {
6
+ "text": "#e6e6ec",
7
+ "muted": "#a1a1ad",
8
+ "dim": "#6e6e7a",
9
+ "violet": "#b2a4ff",
10
+ "pink": "#ff8ad8",
11
+ "blue": "#8fa2ff",
12
+ "green": "#4ade9b",
13
+ "red": "#ff6b81",
14
+ "amber": "#f5b544",
15
+ "rule": "#3a3a46"
16
+ },
17
+ "colors": {
18
+ "accent": "violet",
19
+ "border": "rule",
20
+ "borderAccent": "#8f7cf7",
21
+ "borderMuted": "#2a2a33",
22
+ "success": "green",
23
+ "error": "red",
24
+ "warning": "amber",
25
+ "muted": "muted",
26
+ "dim": "dim",
27
+ "text": "text",
28
+ "thinkingText": "#9a9aa6",
29
+ "selectedBg": "#2a2550",
30
+ "scrollbarTrack": "#26262e",
31
+ "scrollbarThumb": "dim",
32
+ "searchMatchBg": "#4a3a12",
33
+ "searchMatchText": "text",
34
+ "userMessageBg": "#17171d",
35
+ "userMessageText": "text",
36
+ "customMessageBg": "#1c1119",
37
+ "customMessageText": "muted",
38
+ "customMessageLabel": "pink",
39
+ "toolPendingBg": "#16161c",
40
+ "toolSuccessBg": "#10201a",
41
+ "toolErrorBg": "#2a1317",
42
+ "toolTitle": "text",
43
+ "toolOutput": "muted",
44
+ "mdHeading": "#d3caff",
45
+ "mdLink": "blue",
46
+ "mdLinkUrl": "dim",
47
+ "mdCode": "#c9beff",
48
+ "mdCodeBlock": "#d7d7df",
49
+ "mdCodeBlockBorder": "rule",
50
+ "mdQuote": "muted",
51
+ "mdQuoteBorder": "rule",
52
+ "mdHr": "rule",
53
+ "mdListBullet": "violet",
54
+ "toolDiffAdded": "green",
55
+ "toolDiffRemoved": "red",
56
+ "toolDiffContext": "dim",
57
+ "syntaxComment": "#7a7a86",
58
+ "syntaxKeyword": "#b9abff",
59
+ "syntaxFunction": "#9fb0ff",
60
+ "syntaxVariable": "text",
61
+ "syntaxString": "#ff9fdf",
62
+ "syntaxNumber": "#ffbd7a",
63
+ "syntaxType": "#6fd6d0",
64
+ "syntaxOperator": "muted",
65
+ "syntaxPunctuation": "muted",
66
+ "thinkingOff": "#5c5c66",
67
+ "thinkingMinimal": "#6e6e8a",
68
+ "thinkingLow": "#8585b8",
69
+ "thinkingMedium": "#9d8cff",
70
+ "thinkingHigh": "#c58cff",
71
+ "thinkingXhigh": "pink",
72
+ "thinkingMax": "red",
73
+ "bashMode": "green"
74
+ },
75
+ "export": {
76
+ "pageBg": "#0b0b0e",
77
+ "cardBg": "#121217",
78
+ "infoBg": "#2a2410"
79
+ }
80
+ }
@@ -0,0 +1,80 @@
1
+ {
2
+ "$schema": "https://pi.dev/schemas/theme.schema.json",
3
+ "name": "mu-light",
4
+ "appearance": "light",
5
+ "vars": {
6
+ "text": "#18181c",
7
+ "muted": "#55555f",
8
+ "dim": "#85858f",
9
+ "violet": "#5b45db",
10
+ "pink": "#b42d86",
11
+ "blue": "#3d55c9",
12
+ "green": "#0e7f55",
13
+ "red": "#cc2f55",
14
+ "amber": "#9a5a06",
15
+ "rule": "#d4d4da"
16
+ },
17
+ "colors": {
18
+ "accent": "violet",
19
+ "border": "rule",
20
+ "borderAccent": "#7f6af0",
21
+ "borderMuted": "#e6e6ea",
22
+ "success": "green",
23
+ "error": "red",
24
+ "warning": "amber",
25
+ "muted": "muted",
26
+ "dim": "dim",
27
+ "text": "text",
28
+ "thinkingText": "#6a6a74",
29
+ "selectedBg": "#e6e1ff",
30
+ "scrollbarTrack": "#ececf0",
31
+ "scrollbarThumb": "#a6a6b0",
32
+ "searchMatchBg": "#fff0c2",
33
+ "searchMatchText": "text",
34
+ "userMessageBg": "#f3f3f0",
35
+ "userMessageText": "text",
36
+ "customMessageBg": "#fff4fb",
37
+ "customMessageText": "muted",
38
+ "customMessageLabel": "pink",
39
+ "toolPendingBg": "#f6f6f4",
40
+ "toolSuccessBg": "#eef8f2",
41
+ "toolErrorBg": "#fdf0f2",
42
+ "toolTitle": "text",
43
+ "toolOutput": "muted",
44
+ "mdHeading": "#3a2a96",
45
+ "mdLink": "blue",
46
+ "mdLinkUrl": "dim",
47
+ "mdCode": "violet",
48
+ "mdCodeBlock": "#2a2a30",
49
+ "mdCodeBlockBorder": "rule",
50
+ "mdQuote": "muted",
51
+ "mdQuoteBorder": "rule",
52
+ "mdHr": "rule",
53
+ "mdListBullet": "violet",
54
+ "toolDiffAdded": "green",
55
+ "toolDiffRemoved": "red",
56
+ "toolDiffContext": "dim",
57
+ "syntaxComment": "#6a6a73",
58
+ "syntaxKeyword": "violet",
59
+ "syntaxFunction": "#3f4dc0",
60
+ "syntaxVariable": "text",
61
+ "syntaxString": "pink",
62
+ "syntaxNumber": "#9a5208",
63
+ "syntaxType": "#0b767c",
64
+ "syntaxOperator": "muted",
65
+ "syntaxPunctuation": "muted",
66
+ "thinkingOff": "#a6a6b0",
67
+ "thinkingMinimal": "#8a8ab0",
68
+ "thinkingLow": "#6a6ad0",
69
+ "thinkingMedium": "violet",
70
+ "thinkingHigh": "#8a2fc0",
71
+ "thinkingXhigh": "pink",
72
+ "thinkingMax": "red",
73
+ "bashMode": "green"
74
+ },
75
+ "export": {
76
+ "pageBg": "#ffffff",
77
+ "cardBg": "#f7f7f5",
78
+ "infoBg": "#fff6dc"
79
+ }
80
+ }
@@ -87,13 +87,13 @@ if (layout === "package") {
87
87
  row(
88
88
  linked ? "ok" : "--",
89
89
  "command",
90
- linked ? linked.replaceAll(homedir(), "~") : `not on PATH yet: ${join(root, "kyrn", "bin", process.platform === "win32" ? "mu.cmd" : "mu")} link`,
90
+ linked ? linked.replaceAll(homedir(), "~") : `not on your PATH yet: run ${join(root, "kyrn", "bin", process.platform === "win32" ? "mu.cmd" : "mu")} link`,
91
91
  );
92
92
  }
93
93
 
94
94
  row("--", "home", tilde(agentDir));
95
95
  if (home === ".kyrn" && agentDir.startsWith(join(homedir(), ".kyrn"))) {
96
- row("--", "", "this home is from before the rename: `mu migrate` moves it to ~/.mu (`--dry-run` to look first)");
96
+ row("--", "", "this home folder predates the rename: `mu migrate` moves it to ~/.mu (add `--dry-run` to preview)");
97
97
  }
98
98
  // Only the size is looked at: pi writes an empty `{}` at its first start, and any stored login is far longer.
99
99
  let authBytes = 0;
@@ -112,23 +112,23 @@ row(
112
112
  "model",
113
113
  settings.defaultModel
114
114
  ? `${settings.defaultProvider ?? "?"}/${settings.defaultModel}${settings.defaultThinkingLevel ? ` · thinking ${settings.defaultThinkingLevel}` : ""}`
115
- : "no default: the first provider with credentials is used. Pick one with /model, save with ctrl+s",
115
+ : "no default: mu uses the first provider with credentials. Pick one with /model and save it with ctrl+s",
116
116
  );
117
117
 
118
118
  const config = readJson(join(agentDir, "mu.json")) ?? readJson(join(agentDir, "kyrn.json"));
119
119
  const tiers = (env("JUDGE") ? env("JUDGE").split(",") : (config?.tiers ?? ["jev"])).map((tier) => tier.trim());
120
120
  const mode = env("JUDGE_MODE") ?? config?.modes?.default ?? "active";
121
- row("--", "judges", `${tiers.join(" > ")} · decisions ${mode}${env("JUDGE") ? " (from MU_JUDGE)" : ""}`);
121
+ row("--", "judges", `${tiers.join(" > ")} · default mode ${mode}${env("JUDGE") ? " (from MU_JUDGE)" : ""}`);
122
122
  const overrides = Object.entries(config?.modes ?? {}).filter(([id]) => id !== "default");
123
123
  if (overrides.length > 0) row("--", "modes", overrides.map(([id, value]) => `${id}=${value}`).join(" "));
124
124
  const ladder = config?.features?.swarm?.models ?? [];
125
- row("--", "sub-agents", ladder.length > 0 ? `model ladder ${ladder.join(" < ")}` : "use the session's model (no ladder configured)");
125
+ row("--", "subagents", ladder.length > 0 ? `model ladder ${ladder.join(" < ")}` : "use the session's model (no ladder configured)");
126
126
 
127
127
  const judgeSupport = localJudgeSupport({ platform: process.platform, env: process.env, wsl });
128
128
  if (tiers.some((tier) => tier.startsWith("laya")) && !judgeSupport.runs && !judgeSupport.url) {
129
129
  // Not a failure of this installation: the sidecar is Core ML, and there is none for this platform.
130
- row("--", "local judge", `not available on ${platformName({ platform: process.platform, wsl })}: the Laya sidecar is Core ML (macOS, Apple Silicon).`);
131
- row("--", "", "laya's decisions fall back to the next judge or to pi's behaviour. Use jev, an llm judge, or MU_LOCAL_JUDGE_URL=<a server with the same contract>");
130
+ row("--", "local judge", `not available on ${platformName({ platform: process.platform, wsl })}: the Laya sidecar needs Core ML (macOS on Apple silicon)`);
131
+ row("--", "", "Laya's decision points use the next judge or their fallbacks. Use Jev, an LLM judge or MU_LOCAL_JUDGE_URL=<a server with the same API>");
132
132
  } else if (tiers.some((tier) => tier.startsWith("laya"))) {
133
133
  const base = env("LOCAL_JUDGE_URL") ?? `http://127.0.0.1:${env("LOCAL_JUDGE_PORT") ?? 47823}`;
134
134
  const startedAt = performance.now();
@@ -142,8 +142,8 @@ if (tiers.some((tier) => tier.startsWith("laya")) && !judgeSupport.runs && !judg
142
142
  "fix",
143
143
  "local judge",
144
144
  judgeSupport.runs
145
- ? `${base} does not answer: mu judge start (first time: mu judge setup)`
146
- : `${base} (MU_LOCAL_JUDGE_URL) does not answer`,
145
+ ? `${base} isn't answering: run mu judge start (first time: mu judge setup)`
146
+ : `${base} (MU_LOCAL_JUDGE_URL) isn't answering`,
147
147
  );
148
148
  }
149
149
  }
@@ -192,7 +192,7 @@ if (jevTier) {
192
192
  "jev key",
193
193
  route
194
194
  ? `${route[0]} is set: ${route[1]} (value not shown)`
195
- : `none set: Jev 1.13 on OpenCode Zen answers, free for a limited time (what it judges goes to OpenCode). For your own key, add TYPESAFE_API_KEY (or MU_JUDGE_OPENROUTER_API_KEY, AI_GATEWAY_API_KEY, OPENCODE_API_KEY) ${where}`,
195
+ : `none set: using Jev 1.13 on OpenCode Zen, free for a limited time (what the judge reads goes to OpenCode). To use your own key, add TYPESAFE_API_KEY (or MU_JUDGE_OPENROUTER_API_KEY, AI_GATEWAY_API_KEY, OPENCODE_API_KEY) ${where}`,
196
196
  );
197
197
  } else {
198
198
  const name = judge.apiKeyEnv ?? (judge.type === "gateway" ? "AI_GATEWAY_API_KEY" : "TYPESAFE_API_KEY");
@@ -207,7 +207,7 @@ if (jevTier) {
207
207
  has(name) && !unsent ? "ok" : "fix",
208
208
  "jev key",
209
209
  unsent
210
- ? `${jevTier} has no baseUrl: its key ${name} is only sent to the address it was set up for`
210
+ ? `${jevTier} has no baseUrl, so its key ${name} isn't sent anywhere: add the address the key is for`
211
211
  : has(name)
212
212
  ? `${name} is set: Jev is called ${via} (value not shown)`
213
213
  : `missing: add ${name} ${where} (Jev is called ${via})`,
@@ -229,9 +229,9 @@ for (const model of new Set(askedTiers.map(classifierOf).filter((judge) => judge
229
229
  // OpenCode's free models answer without a key (the client sends "public", as OpenCode's own does).
230
230
  const names = provider === "opencode" && String(model).endsWith("-free") ? [] : CLASSIFIER_KEYS[provider];
231
231
  if (!model?.includes("/")) {
232
- row("fix", "classifier", `${model ?? "a classifier judge"} needs a model written "provider/model-id"`);
232
+ row("fix", "classifier", `${model ?? "a classifier judge"} needs a model in the form provider/model-id`);
233
233
  } else if (!names) {
234
- row("--", "classifier", `${model}: a provider of your own; its key is the one models.json names`);
234
+ row("--", "classifier", `${model}: a provider of your own: mu uses the key models.json names for it`);
235
235
  } else if (names.every(has)) {
236
236
  row("ok", "classifier", `${model}: ${names.length > 0 ? `${names.join(", ")} set (value not shown)` : "no key needed"}`);
237
237
  } else {
@@ -268,15 +268,15 @@ for (const endpoint of new Set(clmJudges.map((judge) => clmEndpoint(judge.baseUr
268
268
  } catch {}
269
269
  const ms = Math.round(performance.now() - startedAt);
270
270
  if (health?.ok !== true) {
271
- row("fix", "clm", `${base} does not answer: start clm-serve there, or point the judge's baseUrl in mu.json at one`);
271
+ row("fix", "clm", `${base} isn't answering: start clm-serve there, or point the judge's baseUrl in mu.json at a running one`);
272
272
  continue;
273
273
  }
274
274
  const served = Array.isArray(health.models) ? health.models : [];
275
275
  const missing = [...new Set(judges.map((judge) => judge.model || "clm-latest"))].filter((model) => !served.includes(model));
276
276
  if (health.embedder === false) {
277
- row("fix", "clm", `${host} answers, but its encoder does not: every question fails until the embedding server is up`);
277
+ row("fix", "clm", `${host} answers, but its encoder doesn't: every question fails until the embedding server is up`);
278
278
  } else if (missing.length > 0) {
279
- row("fix", "clm", `${host} does not serve ${missing.join(", ")} (it serves ${served.join(", ")})`);
279
+ row("fix", "clm", `${host} doesn't serve ${missing.join(", ")} (it serves ${served.join(", ")})`);
280
280
  } else {
281
281
  row("ok", "clm", `${host} · ${served.join(", ")} · ${ms} ms`);
282
282
  }
@@ -330,12 +330,37 @@ row(
330
330
  "browse",
331
331
  [browseTiers].flat().some(canRelate)
332
332
  ? `driven by ${[browseTiers].flat().join(" > ")}`
333
- : 'needs a judge that can relate a goal to a page. In mu.json: "routes": { "browser.step": ["luna"] }',
333
+ : 'needs a judge that can match a goal to a page. In mu.json: "routes": { "browser.step": ["llm:openai/gpt-5.6-luna"] }',
334
334
  );
335
335
 
336
336
  const marks = { ok: "\x1b[32m ok\x1b[0m", fix: "\x1b[33mfix\x1b[0m", "--": "\x1b[2m ·\x1b[0m" };
337
337
  const plain = !process.stdout.isTTY;
338
+ /** Where a row's text starts: the mark, two spaces, the name's column. */
339
+ const TEXT_COLUMN = 18;
340
+ /** `text` broken between words into lines at most `size` wide; without a terminal, one line. */
341
+ function wrap(text, size) {
342
+ if (!size || size < 20) return [text];
343
+ const lines = [];
344
+ let line = "";
345
+ for (const word of text.split(" ")) {
346
+ if (line && line.length + 1 + word.length > size) {
347
+ lines.push(line);
348
+ line = word;
349
+ } else line = line ? `${line} ${word}` : word;
350
+ }
351
+ return [...lines, line];
352
+ }
353
+ // In a terminal, what needs doing comes first, as in /doctor inside mu; piped, every line is a row.
354
+ const fixes = rows.filter(([state]) => state === "fix").length;
355
+ if (!plain) {
356
+ console.log(
357
+ fixes > 0 ? `mu doctor found ${fixes} ${fixes === 1 ? "thing" : "things"} to fix` : "mu doctor: everything is set up",
358
+ );
359
+ }
338
360
  for (const [state, name, text] of rows) {
339
- console.log(`${plain ? state.padStart(3) : marks[state]} ${name.padEnd(13)}${text}`);
361
+ // In a terminal, a long row continues under its own text rather than at the left edge.
362
+ const [first, ...rest] = wrap(text, plain ? undefined : process.stdout.columns - TEXT_COLUMN - 1);
363
+ console.log(`${plain ? state.padStart(3) : marks[state]} ${name.padEnd(13)}${first}`);
364
+ for (const line of rest) console.log(`${" ".repeat(TEXT_COLUMN)}${line}`);
340
365
  }
341
- process.exit(rows.some(([state]) => state === "fix") ? 1 : 0);
366
+ process.exit(fixes > 0 ? 1 : 0);
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # Manage the mu local judge sidecar (Laya on Core ML, Apple Silicon only).
2
+ # Manage the mu local judge sidecar (Laya on Core ML, Apple silicon only).
3
3
  #
4
4
  # kyrn/bin/kyrn-judge-local setup create the venv, install pinned deps, download the weights (~680 MB)
5
5
  # kyrn/bin/kyrn-judge-local start start in the background if it is not already running
@@ -34,17 +34,17 @@ is_up() { [[ "$(health)" == *'"status"'* ]]; }
34
34
 
35
35
  require_setup() {
36
36
  if [[ ! -x "$PYTHON" || ! -f "$MODEL_DIR/coreml_config.json" ]]; then
37
- echo "The local judge is not installed. Run: mu judge setup" >&2
37
+ echo "The local judge isn't installed yet. Run: mu judge setup" >&2
38
38
  exit 1
39
39
  fi
40
40
  }
41
41
 
42
42
  cmd_setup() {
43
43
  if [[ "$(uname -s)-$(uname -m)" != "Darwin-arm64" ]]; then
44
- echo "laya-coreml needs Apple Silicon and macOS 15+." >&2
44
+ echo "The local judge needs a Mac with Apple silicon and macOS 15 or later." >&2
45
45
  exit 1
46
46
  fi
47
- command -v uv >/dev/null || { echo "uv is required: https://docs.astral.sh/uv/" >&2; exit 1; }
47
+ command -v uv >/dev/null || { echo "mu judge setup needs uv: https://docs.astral.sh/uv/" >&2; exit 1; }
48
48
  mkdir -p "$STATE_DIR"
49
49
  [[ -x "$PYTHON" ]] || uv venv --python 3.12 "$STATE_DIR/.venv"
50
50
  # The official index on purpose: mirrors lag behind new releases.
@@ -72,7 +72,7 @@ from laya_coreml.artifacts import verify_files
72
72
  directory = Path(sys.argv[1])
73
73
  manifest = json.loads((directory / "coreml_config.json").read_text())
74
74
  verify_files(directory, manifest["files"])
75
- print(f"weights verified against the bundle manifest ({len(manifest['files'])} files)")
75
+ print(f"Weights checked against the bundle's manifest ({len(manifest['files'])} files).")
76
76
  PY
77
77
  }
78
78
 
@@ -84,7 +84,7 @@ cmd_run() {
84
84
  cmd_start() {
85
85
  require_setup
86
86
  if is_up; then
87
- echo "local judge already running at $URL"
87
+ echo "The local judge is already running at $URL."
88
88
  return 0
89
89
  fi
90
90
  mkdir -p "$RUN_DIR"
@@ -92,25 +92,25 @@ cmd_start() {
92
92
  echo $! >"$PID_FILE"
93
93
  for _ in $(seq 1 120); do
94
94
  if is_ready; then
95
- echo "local judge ready at $URL (pid $(cat "$PID_FILE"), log $LOG_FILE)"
95
+ echo "The local judge is ready at $URL (pid $(cat "$PID_FILE"), log $LOG_FILE)."
96
96
  return 0
97
97
  fi
98
98
  if ! kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
99
- echo "local judge exited during startup; see $LOG_FILE" >&2
99
+ echo "The local judge stopped while starting; see $LOG_FILE" >&2
100
100
  tail -5 "$LOG_FILE" >&2 || true
101
101
  return 1
102
102
  fi
103
103
  sleep 0.5
104
104
  done
105
- echo "local judge is still warming up; see $LOG_FILE" >&2
105
+ echo "The local judge is still warming up; see $LOG_FILE" >&2
106
106
  }
107
107
 
108
108
  cmd_stop() {
109
109
  if [[ -f "$PID_FILE" ]] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
110
110
  kill "$(cat "$PID_FILE")"
111
- echo "stopped local judge (pid $(cat "$PID_FILE"))"
111
+ echo "Stopped the local judge (pid $(cat "$PID_FILE"))."
112
112
  else
113
- echo "local judge is not running"
113
+ echo "The local judge isn't running."
114
114
  fi
115
115
  rm -f "$PID_FILE"
116
116
  }
@@ -118,7 +118,35 @@ cmd_stop() {
118
118
  cmd_status() {
119
119
  local body
120
120
  body="$(health)"
121
- if [[ -n "$body" ]]; then echo "$body"; else echo "local judge is not running at $URL"; return 1; fi
121
+ if [[ -z "$body" ]]; then echo "The local judge isn't running at $URL."; return 1; fi
122
+ # --json: the server's own answer, for scripts.
123
+ if [[ "${1:-}" == "--json" ]]; then echo "$body"; return 0; fi
124
+ URL="$URL" node -e '
125
+ let text = "";
126
+ process.stdin.on("data", (chunk) => (text += chunk)).on("end", () => {
127
+ let health;
128
+ try { health = JSON.parse(text); } catch { console.log(text.trim()); return; }
129
+ const up = Math.round((health.uptimeSeconds ?? 0) / 60);
130
+ const uptime = up < 60 ? `${up} min` : `${Math.floor(up / 60)} h ${up % 60} min`;
131
+ const state = health.status === "ok" ? "running" : `starting (${health.status})`;
132
+ const model = String(health.model ?? "").split("/").pop();
133
+ console.log(`The local judge is ${state} at ${process.env.URL}: ${model} on ${health.computeUnits}, pid ${health.pid}, up ${uptime}, ${health.requests} requests.`);
134
+ });' <<<"$body"
135
+ }
136
+
137
+ usage() {
138
+ cat <<'USAGE'
139
+ mu judge: the local judge, Laya, on Core ML (macOS on Apple silicon).
140
+
141
+ mu judge setup install it: a Python environment and the weights (about 680 MB)
142
+ mu judge start start it in the background, unless it's already running
143
+ mu judge stop stop it
144
+ mu judge status [--json] whether it's running, and what it serves
145
+ mu judge run run it in the foreground
146
+
147
+ One local judge serves every mu session on this machine. To have mu ask it, add "laya" to "tiers" in
148
+ mu.json, or start mu with MU_JUDGE=laya.
149
+ USAGE
122
150
  }
123
151
 
124
152
  case "${1:-status}" in
@@ -126,6 +154,7 @@ case "${1:-status}" in
126
154
  run) shift; cmd_run "$@" ;;
127
155
  start) cmd_start ;;
128
156
  stop) cmd_stop ;;
129
- status) cmd_status ;;
130
- *) echo "usage: mu judge setup|start|stop|status|run" >&2; exit 2 ;;
157
+ status) shift; cmd_status "$@" ;;
158
+ help | -h | --help) usage ;;
159
+ *) usage >&2; exit 2 ;;
131
160
  esac
@@ -12,6 +12,20 @@ import { homedir } from "node:os";
12
12
  import { join } from "node:path";
13
13
 
14
14
  const args = process.argv.slice(2);
15
+ if (args.includes("--help") || args.includes("-h")) {
16
+ console.log(
17
+ [
18
+ "mu ledger: the judge's verdicts from your recent sessions, each with the message it judged.",
19
+ "",
20
+ " mu ledger verdicts from the 5 most recent sessions",
21
+ " mu ledger <n> from the n most recent",
22
+ " mu ledger --json one JSON object per verdict, for scripts",
23
+ "",
24
+ "It reads the session files mu keeps on this machine; nothing is sent anywhere.",
25
+ ].join("\n"),
26
+ );
27
+ process.exit(0);
28
+ }
15
29
  const asJson = args.includes("--json");
16
30
  const limit = Number(args.find((arg) => /^\d+$/.test(arg)) ?? 5);
17
31
  /** `MU_<name>`, or the `KYRN_<name>` spelling from before the rename. */
@@ -87,4 +101,5 @@ for (const file of files) {
87
101
  }
88
102
  }
89
103
 
90
- if (!asJson) console.log(count === 0 ? `No decisions found under ${sessionsDir}` : `\n${count} decisions from ${files.length} sessions`);
104
+ const tilde = (path) => (path.startsWith(homedir()) ? `~${path.slice(homedir().length)}` : path);
105
+ if (!asJson) console.log(count === 0 ? `No verdicts found under ${tilde(sessionsDir)}` : `\n${count} ${count === 1 ? "verdict" : "verdicts"} from ${files.length} ${files.length === 1 ? "session" : "sessions"}`);