mu-agent 0.1.7 → 0.1.10

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 (198) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +34 -29
  3. package/dist/bundle/chunks/anthropic-messages-4PAJY4R6.js +6 -0
  4. package/dist/bundle/chunks/anthropic.js +2 -2
  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-TRDNDS6A.js → chunk-3V45WARH.js} +6 -3
  8. package/dist/bundle/chunks/{chunk-XDUWOHPL.js → chunk-5AGIVGSV.js} +3 -3
  9. package/dist/bundle/chunks/chunk-6QGV3IWD.js +6 -0
  10. package/dist/bundle/chunks/chunk-7CBJINYJ.js +20 -0
  11. package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-7DDKXS2Q.js} +1 -1
  12. package/dist/bundle/chunks/chunk-BSS6T6KQ.js +2 -0
  13. package/dist/bundle/chunks/chunk-CF5GWZHW.js +31 -0
  14. package/dist/bundle/chunks/chunk-DNNHZBQR.js +4 -0
  15. package/dist/bundle/chunks/chunk-FN6OEZYR.js +2 -0
  16. package/dist/bundle/chunks/chunk-FTJT2X6E.js +2 -0
  17. package/dist/bundle/chunks/chunk-HZNN636Z.js +130 -0
  18. package/dist/bundle/chunks/{chunk-4L3WN2XY.js → chunk-JXWJOIH4.js} +1 -1
  19. package/dist/bundle/chunks/{chunk-4O2SCVYF.js → chunk-KIDDRTZP.js} +4 -4
  20. package/dist/bundle/chunks/chunk-LMNWTX2L.js +11 -0
  21. package/dist/bundle/chunks/chunk-LPXNMA2W.js +2 -0
  22. package/dist/bundle/chunks/{chunk-6CYCI3EJ.js → chunk-LVVZS2NO.js} +1 -1
  23. package/dist/bundle/chunks/chunk-NN4BEPYX.js +2 -0
  24. package/dist/bundle/chunks/chunk-O7IPTASE.js +1221 -0
  25. package/dist/bundle/chunks/chunk-PMRZO46Y.js +2 -0
  26. package/dist/bundle/chunks/chunk-QOEEJKS4.js +9 -0
  27. package/dist/bundle/chunks/chunk-R4VPBBDS.js +2 -0
  28. package/dist/bundle/chunks/chunk-RAQ6TU76.js +2 -0
  29. package/dist/bundle/chunks/chunk-RDZVAGPR.js +2 -0
  30. package/dist/bundle/chunks/chunk-SGOTYFMT.js +91 -0
  31. package/dist/bundle/chunks/chunk-TMTOQ7H7.js +2 -0
  32. package/dist/bundle/chunks/chunk-UKVNB6C4.js +2 -0
  33. package/dist/bundle/chunks/chunk-VJLOQZKR.js +9 -0
  34. package/dist/bundle/chunks/chunk-WCGU75WO.js +11 -0
  35. package/dist/bundle/chunks/chunk-X234222Q.js +64 -0
  36. package/dist/bundle/chunks/cli-722OL3K5.js +51 -0
  37. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-MEZHQVNP.js +2 -0
  38. package/dist/bundle/chunks/codemode-worker.js +478 -0
  39. package/dist/bundle/chunks/easter-egg-3d-6H34EDGX.js +2 -0
  40. package/dist/bundle/chunks/execute-KVSEIDWL.js +499 -0
  41. package/dist/bundle/chunks/github-copilot.js +1 -1
  42. package/dist/bundle/chunks/{google-generative-ai-C44KRRZ4.js → google-generative-ai-D2VJQBTK.js} +1 -1
  43. package/dist/bundle/chunks/{google-vertex-25DUXPTJ.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-HGQMNYVT.js → lib-4AVRLBHM.js} +2 -2
  49. package/dist/bundle/chunks/llama-cpp-classify-5YHLY3RC.js +22 -0
  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-KCMANYC2.js +16 -0
  54. package/dist/bundle/chunks/openai-chatgpt.js +86 -0
  55. package/dist/bundle/chunks/openai-codex-responses-CECGTDYD.js +10 -0
  56. package/dist/bundle/chunks/openai-codex.js +2 -2
  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-JVEJN44Q.js → openrouter-images-7T452AS5.js} +1 -1
  61. package/dist/bundle/chunks/openrouter.js +2 -2
  62. package/dist/bundle/chunks/{pi-messages-TM5SOOIW.js → pi-messages-2UDKLKOO.js} +1 -1
  63. package/dist/bundle/chunks/radius.js +2 -2
  64. package/dist/bundle/chunks/runtime-O3ELDOM7.js +2 -0
  65. package/dist/bundle/chunks/{src-UK77SYZE.js → src-QKGKDFSU.js} +1 -1
  66. package/dist/bundle/chunks/typesafe-system-one-KNCICMO5.js +2 -0
  67. package/dist/bundle/chunks/virtual-modules-IKEARUOZ.js +2 -0
  68. package/dist/bundle/cli-runtime.js +1 -1
  69. package/dist/bundle/index.js +1 -1
  70. package/dist/bundle/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
  71. package/dist/bundle/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
  72. package/dist/bundle/rpc-entry.js +1 -1
  73. package/dist/core/export-html/template.js +37 -16
  74. package/dist/modes/interactive/theme/dark.json +60 -73
  75. package/dist/modes/interactive/theme/light.json +58 -70
  76. package/dist/modes/interactive/theme/system-theme.d.ts +55 -0
  77. package/dist/modes/interactive/theme/system-theme.d.ts.map +1 -0
  78. package/dist/modes/interactive/theme/system-theme.js +546 -0
  79. package/dist/modes/interactive/theme/system-theme.js.map +1 -0
  80. package/dist/modes/interactive/theme/theme-controller.d.ts +43 -9
  81. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  82. package/dist/modes/interactive/theme/theme-controller.js +121 -79
  83. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  84. package/dist/modes/interactive/theme/theme-schema.d.ts +28 -0
  85. package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
  86. package/dist/modes/interactive/theme/theme-schema.js +105 -0
  87. package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
  88. package/dist/modes/interactive/theme/theme-tokens.d.ts +257 -0
  89. package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -0
  90. package/dist/modes/interactive/theme/theme-tokens.js +94 -0
  91. package/dist/modes/interactive/theme/theme-tokens.js.map +1 -0
  92. package/dist/modes/interactive/theme/theme.d.ts +47 -56
  93. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  94. package/dist/modes/interactive/theme/theme.js +149 -143
  95. package/dist/modes/interactive/theme/theme.js.map +1 -1
  96. package/dist/native/darwin/prebuilds/darwin-arm64/darwin-platform.node +0 -0
  97. package/dist/native/darwin/prebuilds/darwin-x64/darwin-platform.node +0 -0
  98. package/docs/cli-integration.md +1 -1
  99. package/docs/cli.md +78 -13
  100. package/docs/codemode.md +230 -0
  101. package/docs/compaction.md +5 -5
  102. package/docs/configuration.md +2 -0
  103. package/docs/custom-provider.md +53 -1
  104. package/docs/docs.json +21 -1
  105. package/docs/environment-variables.md +5 -3
  106. package/docs/extensions.md +172 -10
  107. package/docs/index.md +1 -1
  108. package/docs/json.md +3 -3
  109. package/docs/keybindings.md +7 -6
  110. package/docs/llama-cpp.md +21 -1
  111. package/docs/mcp.md +272 -0
  112. package/docs/message-types.md +22 -4
  113. package/docs/models-configuration.md +187 -0
  114. package/docs/models.md +100 -2
  115. package/docs/nvidia-rtx-llama-cpp.md +96 -0
  116. package/docs/packages.md +1 -1
  117. package/docs/providers.md +66 -6
  118. package/docs/quickstart.md +16 -2
  119. package/docs/rpc-commands.md +9 -3
  120. package/docs/rpc.md +3 -1
  121. package/docs/sdk.md +8 -3
  122. package/docs/security.md +2 -0
  123. package/docs/session-format.md +5 -1
  124. package/docs/sessions.md +1 -1
  125. package/docs/settings.md +30 -8
  126. package/docs/terminal-setup.md +14 -0
  127. package/docs/themes.md +31 -7
  128. package/docs/tui.md +71 -1
  129. package/docs/usage.md +2 -2
  130. package/docs/virtual-models.md +114 -0
  131. package/docs/windows.md +2 -0
  132. package/examples/README.md +1 -4
  133. package/examples/extensions/README.md +1 -0
  134. package/examples/extensions/built-in-tool-renderer.ts +16 -40
  135. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  136. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  137. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  138. package/examples/extensions/custom-provider-gitlab-duo/test.ts +5 -5
  139. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  140. package/examples/extensions/gondolin/package-lock.json +2 -2
  141. package/examples/extensions/gondolin/package.json +1 -1
  142. package/examples/extensions/jev-router.ts +113 -0
  143. package/examples/extensions/minimal-mode.ts +28 -101
  144. package/examples/extensions/overlay-test.ts +2 -2
  145. package/examples/extensions/plan-mode/index.ts +6 -2
  146. package/examples/extensions/sandbox/package-lock.json +2 -2
  147. package/examples/extensions/sandbox/package.json +1 -1
  148. package/examples/extensions/subagent/index.ts +4 -6
  149. package/examples/extensions/with-deps/package-lock.json +2 -2
  150. package/examples/extensions/with-deps/package.json +1 -1
  151. package/examples/rpc-client.ts +1 -1
  152. package/examples/rpc-extension-ui.ts +1 -1
  153. package/examples/sdk/14-codemode-mcp.ts +61 -0
  154. package/examples/sdk/README.md +2 -1
  155. package/judge/THIRD_PARTY_NOTICES.md +63 -0
  156. package/judge/dist/auth.js +169 -123
  157. package/judge/dist/import.js +36 -30
  158. package/judge/dist/setup.js +250 -120
  159. package/judge/manifest.json +1008 -316
  160. package/judge/{dist/kyrn-judge.js → mu/index.js} +6933 -5995
  161. package/judge/themes/mu-dark.json +80 -0
  162. package/judge/themes/mu-light.json +80 -0
  163. package/kyrn/bin/kyrn-doctor +75 -25
  164. package/kyrn/bin/kyrn-judge-local +2 -2
  165. package/kyrn/bin/kyrn-ledger +1 -1
  166. package/kyrn/bin/mu.mjs +149 -107
  167. package/package.json +4 -5
  168. package/dist/bundle/chunks/anthropic-messages-VMESUHQ7.js +0 -6
  169. package/dist/bundle/chunks/azure-openai-responses-K232MQFF.js +0 -2
  170. package/dist/bundle/chunks/chunk-A3JYRWB6.js +0 -2
  171. package/dist/bundle/chunks/chunk-AYFRR3OD.js +0 -2
  172. package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +0 -42
  173. package/dist/bundle/chunks/chunk-FU4XQUSL.js +0 -11
  174. package/dist/bundle/chunks/chunk-GNYZK6XN.js +0 -2
  175. package/dist/bundle/chunks/chunk-HEMXN7VJ.js +0 -1653
  176. package/dist/bundle/chunks/chunk-MVPXOVOJ.js +0 -2
  177. package/dist/bundle/chunks/chunk-NUHFSC37.js +0 -25
  178. package/dist/bundle/chunks/chunk-V7IXECST.js +0 -11
  179. package/dist/bundle/chunks/chunk-XNGRGP62.js +0 -2
  180. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-NR2TDCXU.js +0 -2
  181. package/dist/bundle/chunks/https-proxy-agent-2VXB7436.js +0 -13
  182. package/dist/bundle/chunks/mistral-conversations-6IHQOR4R.js +0 -5
  183. package/dist/bundle/chunks/node-O3RIBJRH.js +0 -16
  184. package/dist/bundle/chunks/openai-codex-responses-3UAYOSSR.js +0 -10
  185. package/dist/bundle/chunks/openai-completions-FIEQGWAH.js +0 -7
  186. package/dist/bundle/chunks/openai-responses-OZJXLHFC.js +0 -2
  187. package/dist/bundle/chunks/typesafe-system-one-VKYX4OGY.js +0 -2
  188. package/dist/bundle/chunks/virtual-modules-V7SXVVLP.js +0 -2
  189. package/dist/modes/interactive/theme/theme-json.d.ts +0 -85
  190. package/dist/modes/interactive/theme/theme-json.d.ts.map +0 -1
  191. package/dist/modes/interactive/theme/theme-json.js +0 -132
  192. package/dist/modes/interactive/theme/theme-json.js.map +0 -1
  193. package/dist/modes/interactive/theme/theme-schema.json +0 -361
  194. package/examples/plugins/pi-example-plugin/README.md +0 -38
  195. package/examples/plugins/pi-example-plugin/package.json +0 -10
  196. package/examples/plugins/pi-example-plugin/src/contract.ts +0 -13
  197. package/examples/plugins/pi-example-plugin/src/session.ts +0 -24
  198. 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
+ }
@@ -8,6 +8,7 @@ import { homedir } from "node:os";
8
8
  import { join } from "node:path";
9
9
  import { pathToFileURL } from "node:url";
10
10
  import {
11
+ dependenciesInstalled,
11
12
  detectWsl,
12
13
  envFilePath,
13
14
  findOnPath,
@@ -17,7 +18,6 @@ import {
17
18
  packageEntries,
18
19
  parseEnvFile,
19
20
  platformName,
20
- resolveTsx,
21
21
  } from "./mu.mjs";
22
22
 
23
23
  const [root, link] = process.argv.slice(2);
@@ -68,12 +68,11 @@ if (layout === "package") {
68
68
  });
69
69
  row(onPath ? "ok" : "fix", "command", onPath ? tilde(onPath) : "`mu` is not on PATH: add npm's global bin folder (npm prefix -g) to it");
70
70
  } else {
71
- // The JavaScript behind tsx, which is what the launcher runs: node_modules/.bin holds a .cmd shim on Windows.
72
- const tsx = resolveTsx({ root, platform: process.platform, exists: existsSync, readFile: (path) => readFileSync(path, "utf8") });
71
+ const installed = dependenciesInstalled({ root, platform: process.platform, exists: existsSync });
73
72
  row(
74
- tsx ? "ok" : "fix",
73
+ installed ? "ok" : "fix",
75
74
  "dependencies",
76
- tsx
75
+ installed
77
76
  ? "installed"
78
77
  : `missing: cd ${root} && npm ci --ignore-scripts && npm run hydrate:model-data`,
79
78
  );
@@ -88,13 +87,13 @@ if (layout === "package") {
88
87
  row(
89
88
  linked ? "ok" : "--",
90
89
  "command",
91
- 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`,
92
91
  );
93
92
  }
94
93
 
95
94
  row("--", "home", tilde(agentDir));
96
95
  if (home === ".kyrn" && agentDir.startsWith(join(homedir(), ".kyrn"))) {
97
- 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)");
98
97
  }
99
98
  // Only the size is looked at: pi writes an empty `{}` at its first start, and any stored login is far longer.
100
99
  let authBytes = 0;
@@ -113,23 +112,23 @@ row(
113
112
  "model",
114
113
  settings.defaultModel
115
114
  ? `${settings.defaultProvider ?? "?"}/${settings.defaultModel}${settings.defaultThinkingLevel ? ` · thinking ${settings.defaultThinkingLevel}` : ""}`
116
- : "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",
117
116
  );
118
117
 
119
118
  const config = readJson(join(agentDir, "mu.json")) ?? readJson(join(agentDir, "kyrn.json"));
120
119
  const tiers = (env("JUDGE") ? env("JUDGE").split(",") : (config?.tiers ?? ["jev"])).map((tier) => tier.trim());
121
- const mode = env("JUDGE_MODE") ?? config?.modes?.default ?? "shadow";
122
- row("--", "judges", `${tiers.join(" > ")} · decisions ${mode}${env("JUDGE") ? " (from MU_JUDGE)" : ""}`);
120
+ const mode = env("JUDGE_MODE") ?? config?.modes?.default ?? "active";
121
+ row("--", "judges", `${tiers.join(" > ")} · default mode ${mode}${env("JUDGE") ? " (from MU_JUDGE)" : ""}`);
123
122
  const overrides = Object.entries(config?.modes ?? {}).filter(([id]) => id !== "default");
124
123
  if (overrides.length > 0) row("--", "modes", overrides.map(([id, value]) => `${id}=${value}`).join(" "));
125
124
  const ladder = config?.features?.swarm?.models ?? [];
126
- 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)");
127
126
 
128
127
  const judgeSupport = localJudgeSupport({ platform: process.platform, env: process.env, wsl });
129
128
  if (tiers.some((tier) => tier.startsWith("laya")) && !judgeSupport.runs && !judgeSupport.url) {
130
129
  // Not a failure of this installation: the sidecar is Core ML, and there is none for this platform.
131
- row("--", "local judge", `not available on ${platformName({ platform: process.platform, wsl })}: the Laya sidecar is Core ML (macOS, Apple Silicon).`);
132
- 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>");
133
132
  } else if (tiers.some((tier) => tier.startsWith("laya"))) {
134
133
  const base = env("LOCAL_JUDGE_URL") ?? `http://127.0.0.1:${env("LOCAL_JUDGE_PORT") ?? 47823}`;
135
134
  const startedAt = performance.now();
@@ -143,8 +142,8 @@ if (tiers.some((tier) => tier.startsWith("laya")) && !judgeSupport.runs && !judg
143
142
  "fix",
144
143
  "local judge",
145
144
  judgeSupport.runs
146
- ? `${base} does not answer: mu judge start (first time: mu judge setup)`
147
- : `${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`,
148
147
  );
149
148
  }
150
149
  }
@@ -155,6 +154,21 @@ const JEV_ROUTES = {
155
154
  "jev-openrouter": { type: "typesafe", baseUrl: "https://openrouter.ai/api/v1/systemone", apiKeyEnv: "MU_JUDGE_OPENROUTER_API_KEY" },
156
155
  "jev-gateway": { type: "gateway" },
157
156
  gateway: { type: "gateway" },
157
+ "jev-opencode": { type: "classifier", model: "opencode/jev-1.13" },
158
+ "jev-opencode-free": { type: "classifier", model: "opencode/jev-1.13-free" },
159
+ "jev-cloudflare": { type: "classifier", model: "cloudflare-workers-ai/typesafe/jev" },
160
+ clef: { type: "classifier", model: "cloudflare-workers-ai/@cf/cloudflare/clef" },
161
+ "clef-flash": { type: "classifier", model: "cloudflare-workers-ai/@cf/cloudflare/clef-flash" },
162
+ };
163
+ // The variables pi reads a classifier provider's credentials from (packages/ai/src/env-api-keys.ts); a key stored
164
+ // with /login or `mu auth` works as well. llama.cpp on this machine needs none.
165
+ const CLASSIFIER_KEYS = {
166
+ opencode: ["OPENCODE_API_KEY"],
167
+ "cloudflare-workers-ai": ["CLOUDFLARE_API_KEY", "CLOUDFLARE_ACCOUNT_ID"],
168
+ openrouter: ["OPENROUTER_API_KEY"],
169
+ typesafe: ["TYPESAFE_API_KEY"],
170
+ "vercel-ai-gateway": ["AI_GATEWAY_API_KEY"],
171
+ "llama.cpp": [],
158
172
  };
159
173
  // Parsed the way the launcher parses it (quotes, `export `), and only asked whether a name has a value.
160
174
  const fromFile = existsSync(envFile) ? parseEnvFile(readFileSync(envFile, "utf8")).entries : [];
@@ -164,18 +178,21 @@ const jevTier = tiers.find((tier) => ["jev", "typesafe", "gateway"].includes((co
164
178
  if (jevTier) {
165
179
  const judge = config?.judges?.[jevTier] ?? JEV_ROUTES[jevTier];
166
180
  if (judge.type === "jev") {
167
- // The order the registry tries: TypeSafe directly, Jev on OpenRouter, the Vercel AI Gateway.
181
+ // The order the registry tries: TypeSafe directly, Jev on OpenRouter, the Vercel AI Gateway, OpenCode Zen,
182
+ // Cloudflare Workers AI (key and account). With none of them, a gateway key kept with /login, else the free Jev.
168
183
  const route = [
169
184
  ["TYPESAFE_API_KEY", "Jev is called directly at api.typesafe.ai"],
170
185
  ["MU_JUDGE_OPENROUTER_API_KEY", "Jev is called through OpenRouter"],
171
186
  ["AI_GATEWAY_API_KEY", "Jev is called through the Vercel AI Gateway"],
172
- ].find(([name]) => has(name));
187
+ ["OPENCODE_API_KEY", "Jev is called on OpenCode Zen (jev-1.13)"],
188
+ ["CLOUDFLARE_API_KEY", "Jev is called on Cloudflare Workers AI", "CLOUDFLARE_ACCOUNT_ID"],
189
+ ].find(([name, , also]) => has(name) && (!also || has(also)));
173
190
  row(
174
- route ? "ok" : "fix",
191
+ route ? "ok" : "--",
175
192
  "jev key",
176
193
  route
177
194
  ? `${route[0]} is set: ${route[1]} (value not shown)`
178
- : `missing: add TYPESAFE_API_KEY (or MU_JUDGE_OPENROUTER_API_KEY, or AI_GATEWAY_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}`,
179
196
  );
180
197
  } else {
181
198
  const name = judge.apiKeyEnv ?? (judge.type === "gateway" ? "AI_GATEWAY_API_KEY" : "TYPESAFE_API_KEY");
@@ -190,7 +207,7 @@ if (jevTier) {
190
207
  has(name) && !unsent ? "ok" : "fix",
191
208
  "jev key",
192
209
  unsent
193
- ? `${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`
194
211
  : has(name)
195
212
  ? `${name} is set: Jev is called ${via} (value not shown)`
196
213
  : `missing: add ${name} ${where} (Jev is called ${via})`,
@@ -198,6 +215,35 @@ if (jevTier) {
198
215
  }
199
216
  }
200
217
 
218
+ // Classifier models of pi's catalog (Jev on OpenCode Zen or Cloudflare, Clef, …), for the tiers and routes that use them.
219
+ const classifierOf = (tier) =>
220
+ tier.startsWith("classifier:")
221
+ ? { type: "classifier", model: tier.slice("classifier:".length) }
222
+ : (config?.judges?.[tier] ?? JEV_ROUTES[tier]);
223
+ const askedTiers = [
224
+ ...tiers,
225
+ ...Object.values(config?.routes ?? {}).flatMap((value) => (Array.isArray(value) ? value : String(value).split(","))),
226
+ ].map((tier) => String(tier).trim());
227
+ for (const model of new Set(askedTiers.map(classifierOf).filter((judge) => judge?.type === "classifier").map((judge) => judge.model))) {
228
+ const provider = String(model ?? "").split("/")[0];
229
+ // OpenCode's free models answer without a key (the client sends "public", as OpenCode's own does).
230
+ const names = provider === "opencode" && String(model).endsWith("-free") ? [] : CLASSIFIER_KEYS[provider];
231
+ if (!model?.includes("/")) {
232
+ row("fix", "classifier", `${model ?? "a classifier judge"} needs a model in the form provider/model-id`);
233
+ } else if (!names) {
234
+ row("--", "classifier", `${model}: a provider of your own: mu uses the key models.json names for it`);
235
+ } else if (names.every(has)) {
236
+ row("ok", "classifier", `${model}: ${names.length > 0 ? `${names.join(", ")} set (value not shown)` : "no key needed"}`);
237
+ } else {
238
+ const unset = names.filter((name) => !has(name));
239
+ row(
240
+ authBytes > 8 ? "--" : "fix",
241
+ "classifier",
242
+ `${model}: ${unset.join(" and ")} not set${authBytes > 8 ? `; a key stored with /login ${provider} works too (not read here)` : `: add ${unset.join(", ")} ${where}, or store a key with /login ${provider}`}`,
243
+ );
244
+ }
245
+ }
246
+
201
247
  // CLM-8B behind `clm-serve` (github.com/Contrastive-LM/CLM), for the tiers and routes that use it.
202
248
  /** As packages/kyrn-judge/src/providers/typesafe.ts reads a CLM address: `http://host:8700` is enough. */
203
249
  function clmEndpoint(baseUrl) {
@@ -222,15 +268,15 @@ for (const endpoint of new Set(clmJudges.map((judge) => clmEndpoint(judge.baseUr
222
268
  } catch {}
223
269
  const ms = Math.round(performance.now() - startedAt);
224
270
  if (health?.ok !== true) {
225
- 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`);
226
272
  continue;
227
273
  }
228
274
  const served = Array.isArray(health.models) ? health.models : [];
229
275
  const missing = [...new Set(judges.map((judge) => judge.model || "clm-latest"))].filter((model) => !served.includes(model));
230
276
  if (health.embedder === false) {
231
- 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`);
232
278
  } else if (missing.length > 0) {
233
- 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(", ")})`);
234
280
  } else {
235
281
  row("ok", "clm", `${host} · ${served.join(", ")} · ${ms} ms`);
236
282
  }
@@ -271,7 +317,11 @@ row(
271
317
  );
272
318
  for (const line of moreAdvice) row("--", "", line);
273
319
  const canRelate = (tier) =>
274
- tier.startsWith("jev") || tier === "gateway" || tier.startsWith("llm:") || ["llm", "clm"].includes(judgeOf(tier)?.type);
320
+ tier.startsWith("jev") ||
321
+ tier === "gateway" ||
322
+ tier.startsWith("llm:") ||
323
+ tier.startsWith("classifier:") ||
324
+ ["llm", "clm", "classifier"].includes(judgeOf(tier)?.type);
275
325
  const browseTiers = config?.routes?.["browser.step"] ?? tiers;
276
326
  const routed = Object.entries(config?.routes ?? {});
277
327
  if (routed.length > 0) row("--", "routes", routed.map(([id, value]) => `${id} -> ${[value].flat().join(" > ")}`).join(" · "));
@@ -280,7 +330,7 @@ row(
280
330
  "browse",
281
331
  [browseTiers].flat().some(canRelate)
282
332
  ? `driven by ${[browseTiers].flat().join(" > ")}`
283
- : '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-codex/gpt-5.6-luna"] }',
284
334
  );
285
335
 
286
336
  const marks = { ok: "\x1b[32m ok\x1b[0m", fix: "\x1b[33mfix\x1b[0m", "--": "\x1b[2m ·\x1b[0m" };
@@ -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
@@ -41,7 +41,7 @@ require_setup() {
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 "laya-coreml needs Apple silicon and macOS 15+." >&2
45
45
  exit 1
46
46
  fi
47
47
  command -v uv >/dev/null || { echo "uv is required: https://docs.astral.sh/uv/" >&2; exit 1; }
@@ -87,4 +87,4 @@ for (const file of files) {
87
87
  }
88
88
  }
89
89
 
90
- if (!asJson) console.log(count === 0 ? `No decisions found under ${sessionsDir}` : `\n${count} decisions from ${files.length} sessions`);
90
+ if (!asJson) console.log(count === 0 ? `No verdicts found under ${sessionsDir}` : `\n${count} ${count === 1 ? "verdict" : "verdicts"} from ${files.length} ${files.length === 1 ? "session" : "sessions"}`);