open-multi-agent-kit 0.78.5 → 0.78.7

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/AGENTS.md +1 -1
  2. package/CHANGELOG.md +64 -0
  3. package/MATURITY.md +2 -2
  4. package/README.md +20 -5
  5. package/dist/brand/night-city.theme.json +80 -0
  6. package/dist/brand/palette.d.ts +73 -177
  7. package/dist/brand/palette.js +115 -39
  8. package/dist/brand/rust-forge.theme.json +216 -0
  9. package/dist/brand/theme-compiled.d.ts +61 -0
  10. package/dist/brand/theme-compiled.js +241 -0
  11. package/dist/brand/theme.js +50 -37
  12. package/dist/cli/release-promotion-gate.d.ts +8 -1
  13. package/dist/cli/release-promotion-gate.js +23 -11
  14. package/dist/cli/root.d.ts +1 -0
  15. package/dist/cli/root.js +2 -1
  16. package/dist/cli/theme/index.d.ts +11 -2
  17. package/dist/cli/theme/index.js +6 -1
  18. package/dist/cli/theme/oklab-quantize.d.ts +29 -0
  19. package/dist/cli/theme/oklab-quantize.js +105 -0
  20. package/dist/cli/theme/render-table.d.ts +59 -0
  21. package/dist/cli/theme/render-table.js +112 -0
  22. package/dist/cli/theme/status-frame.d.ts +10 -0
  23. package/dist/cli/theme/status-frame.js +22 -0
  24. package/dist/cli/theme/terminal-capability.d.ts +6 -1
  25. package/dist/cli/theme/terminal-capability.js +20 -4
  26. package/dist/cli/theme/theme-doc.d.ts +22 -0
  27. package/dist/cli/theme/theme-doc.js +97 -0
  28. package/dist/cli/theme/theme-registry.js +39 -18
  29. package/dist/cli/theme/tier-explain.d.ts +21 -0
  30. package/dist/cli/theme/tier-explain.js +60 -0
  31. package/dist/cli/ui/green-rain-renderer.js +3 -2
  32. package/dist/cli/ui/neon-grid-renderer.js +4 -3
  33. package/dist/cli/ui/rust-forge-renderer.js +17 -3
  34. package/dist/cli/ui/system24-renderer.d.ts +18 -1
  35. package/dist/cli/ui/system24-renderer.js +39 -16
  36. package/dist/cli/v2/chat-repl.js +3 -1
  37. package/dist/cli/v2/cli-v2-skeleton.d.ts +6 -0
  38. package/dist/cli/v2/cli-v2-skeleton.js +121 -9
  39. package/dist/cli/v2/interactive-prompt.d.ts +1 -0
  40. package/dist/cli/v2/interactive-prompt.js +6 -2
  41. package/dist/commands/chat/core.js +2 -2
  42. package/dist/commands/chat/runtime.js +2 -0
  43. package/dist/commands/chat/utils.js +12 -4
  44. package/dist/commands/cockpit/render.js +102 -64
  45. package/dist/commands/cockpit/utils.d.ts +2 -0
  46. package/dist/commands/design.js +18 -16
  47. package/dist/commands/doctor/checks.d.ts +0 -1
  48. package/dist/commands/doctor/checks.js +1 -36
  49. package/dist/commands/doctor/report.js +0 -11
  50. package/dist/commands/init/content.d.ts +1 -1
  51. package/dist/commands/init/content.js +3 -11
  52. package/dist/commands/init.js +2 -2
  53. package/dist/commands/mcp/config.d.ts +32 -0
  54. package/dist/commands/mcp/config.js +264 -0
  55. package/dist/commands/mcp/doctor-fix.d.ts +12 -0
  56. package/dist/commands/mcp/doctor-fix.js +261 -0
  57. package/dist/commands/mcp/doctor.d.ts +55 -0
  58. package/dist/commands/mcp/doctor.js +401 -0
  59. package/dist/commands/mcp/list.d.ts +1 -0
  60. package/dist/commands/mcp/list.js +56 -0
  61. package/dist/commands/mcp/shared.d.ts +47 -0
  62. package/dist/commands/mcp/shared.js +192 -0
  63. package/dist/commands/mcp/test.d.ts +5 -0
  64. package/dist/commands/mcp/test.js +457 -0
  65. package/dist/commands/mcp.d.ts +8 -104
  66. package/dist/commands/mcp.js +5 -1603
  67. package/dist/contracts/proof.d.ts +1 -1
  68. package/dist/goal/control-loop.d.ts +15 -0
  69. package/dist/goal/control-loop.js +39 -5
  70. package/dist/hud/render.d.ts +2 -0
  71. package/dist/hud/render.js +7 -1
  72. package/dist/mcp/secret-scanner.d.ts +6 -0
  73. package/dist/mcp/secret-scanner.js +44 -11
  74. package/dist/memory/graph-delta-log.d.ts +137 -0
  75. package/dist/memory/graph-delta-log.js +650 -0
  76. package/dist/memory/graph-viewer.js +13 -32
  77. package/dist/memory/local-graph-memory-store.d.ts +36 -3
  78. package/dist/memory/local-graph-memory-store.js +255 -10
  79. package/dist/orchestration/log-streamer.js +13 -8
  80. package/dist/orchestration/routing.d.ts +4 -0
  81. package/dist/orchestration/routing.js +28 -3
  82. package/dist/orchestration/state-persister.js +8 -1
  83. package/dist/providers/anthropic-messages-runner.d.ts +17 -0
  84. package/dist/providers/anthropic-messages-runner.js +197 -0
  85. package/dist/providers/model-registry.d.ts +1 -1
  86. package/dist/providers/model-registry.js +37 -3
  87. package/dist/providers/provider-runtime.js +27 -11
  88. package/dist/providers/thinking-levels.js +4 -1
  89. package/dist/providers/types.d.ts +3 -3
  90. package/dist/runtime/contracts/weakness-remediation.d.ts +11 -1
  91. package/dist/runtime/contracts/weakness-remediation.js +9 -1
  92. package/dist/runtime/router-v2-scoring.d.ts +8 -3
  93. package/dist/runtime/router-v2-scoring.js +27 -22
  94. package/dist/runtime/runtime-router.d.ts +5 -0
  95. package/dist/runtime/runtime-router.js +40 -8
  96. package/dist/runtime/sandbox-profile.d.ts +29 -0
  97. package/dist/runtime/sandbox-profile.js +101 -0
  98. package/dist/runtime/slash-commands.js +300 -2
  99. package/dist/runtime/tool-dispatch-contracts.d.ts +15 -0
  100. package/dist/runtime/tool-dispatch-contracts.js +12 -0
  101. package/dist/runtime/weights-config.d.ts +90 -0
  102. package/dist/runtime/weights-config.js +249 -0
  103. package/dist/schema/envelope.schema.d.ts +18 -18
  104. package/dist/schema/evidence.schema.d.ts +2 -2
  105. package/dist/schema/proof-bundle.schema.d.ts +6 -6
  106. package/dist/schema/proof-bundle.schema.js +0 -1
  107. package/dist/schema/provider.schema.d.ts +2 -2
  108. package/dist/schema/run-manifest.schema.d.ts +16 -16
  109. package/dist/theme/ansi.js +9 -2
  110. package/dist/theme/extended-palette.d.ts +85 -0
  111. package/dist/theme/extended-palette.js +108 -0
  112. package/dist/theme/layout.js +29 -8
  113. package/dist/theme/metrics.js +5 -5
  114. package/dist/theme/parallel.js +25 -15
  115. package/dist/ui/omk-sigil.js +5 -14
  116. package/dist/ui/omk-working-sweep.js +5 -15
  117. package/dist/util/chat-agent-mode.d.ts +11 -0
  118. package/dist/util/chat-agent-mode.js +41 -8
  119. package/dist/util/chat-cockpit.d.ts +9 -0
  120. package/dist/util/chat-cockpit.js +77 -20
  121. package/dist/util/fs/core.d.ts +5 -0
  122. package/dist/util/fs/core.js +35 -0
  123. package/dist/util/fs/internal.d.ts +14 -0
  124. package/dist/util/fs/internal.js +169 -0
  125. package/dist/util/fs/kimi-sync.d.ts +41 -0
  126. package/dist/util/fs/kimi-sync.js +495 -0
  127. package/dist/util/fs/logo.d.ts +2 -0
  128. package/dist/util/fs/logo.js +78 -0
  129. package/dist/util/fs/manifest.d.ts +6 -0
  130. package/dist/util/fs/manifest.js +40 -0
  131. package/dist/util/fs/mcp-diagnose.d.ts +15 -0
  132. package/dist/util/fs/mcp-diagnose.js +204 -0
  133. package/dist/util/fs/mcp-runtime-config.d.ts +23 -0
  134. package/dist/util/fs/mcp-runtime-config.js +412 -0
  135. package/dist/util/fs/paths.d.ts +13 -0
  136. package/dist/util/fs/paths.js +82 -0
  137. package/dist/util/fs/preflight.d.ts +27 -0
  138. package/dist/util/fs/preflight.js +271 -0
  139. package/dist/util/fs.d.ts +8 -128
  140. package/dist/util/fs.js +8 -1757
  141. package/dist/util/terminal-layout.js +5 -1
  142. package/dist/util/version.js +2 -1
  143. package/docs/2026-06-10/critical-issues.md +20 -0
  144. package/docs/2026-06-10/improvements.md +14 -0
  145. package/docs/2026-06-10/init-checklist.md +25 -0
  146. package/docs/2026-06-10/plan.md +20 -0
  147. package/docs/2026-06-11/critical-issues.md +20 -0
  148. package/docs/2026-06-11/improvements.md +14 -0
  149. package/docs/2026-06-11/init-checklist.md +25 -0
  150. package/docs/2026-06-11/plan.md +20 -0
  151. package/docs/ARCHITECTURE_ANALYSIS_CODEGRAPH.md +223 -0
  152. package/docs/adr/0001-no-native-rust-lane.md +52 -0
  153. package/docs/codex-oauth-setup.md +14 -0
  154. package/docs/decisions/2026-06-10-git-history-bloat.md +61 -0
  155. package/docs/decisions/ADR-theme-dark-only-assets.md +43 -0
  156. package/docs/getting-started.md +1 -1
  157. package/docs/headroom-omk-final-summary.md +188 -0
  158. package/docs/headroom-omk-integration.md +394 -0
  159. package/docs/headroom-omk-setup-guide.md +422 -0
  160. package/docs/headroom-omk-usage-examples.md +371 -0
  161. package/docs/provider-maturity.md +1 -1
  162. package/docs/versioning.md +3 -3
  163. package/package.json +10 -10
  164. package/readmeasset/.npmignore +2 -0
  165. package/readmeasset/ASSET_INDEX.md +7 -5
  166. package/readmeasset/ASSET_PROVENANCE.md +21 -5
  167. package/readmeasset/omk-control-surfaces.svg +55 -0
  168. package/readmeasset/omk-core-loop.svg +1 -0
  169. package/readmeasset/omk-logo-mark.svg +1 -0
  170. package/readmeasset/omk-release-assertions.svg +51 -0
  171. package/dist/native/linux-x64/omk-safety +0 -0
  172. package/dist/util/native-safety.d.ts +0 -28
  173. package/dist/util/native-safety.js +0 -118
  174. package/templates/skills/agents/omk-adaptorch-orchestration-review/SKILL.md +0 -52
  175. package/templates/skills/kimi/mcp-install/SKILL.md +0 -66
  176. package/templates/skills/kimi/omk-adaptorch-orchestration-review/SKILL.md +0 -52
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * Panels:
12
12
  * ┌─ session ──────────────────────────────────────┐
13
- * │ ◆ OMK · mimo · mimo-v2.5-pro run#abc123
13
+ * │ ◆ OMK · mimo · mimo-v2.5-pro run id ab12
14
14
  * └────────────────────────────────────────────────┘
15
15
  * ┌─ turn ─────────────────────────────────────────┐
16
16
  * │ ▸ user input │
@@ -26,12 +26,29 @@
26
26
  import type { CliUiEvent } from "./event.js";
27
27
  import type { CliRenderer } from "./renderer.js";
28
28
  import type { OmkBrandTheme } from "../../brand/theme.js";
29
+ interface System24Palette {
30
+ bg3: string;
31
+ text1: string;
32
+ text2: string;
33
+ text3: string;
34
+ text5: string;
35
+ accent: string;
36
+ green: string;
37
+ amber: string;
38
+ red: string;
39
+ cyan: string;
40
+ border: string;
41
+ borderHL: string;
42
+ }
29
43
  interface WritableStreamLike {
30
44
  write(chunk: string): unknown;
31
45
  isTTY?: boolean;
32
46
  columns?: number;
33
47
  rows?: number;
34
48
  }
49
+ export declare function visibleLenForTest(s: string): number;
50
+ export declare function renderPanelLineForTest(c: System24Palette, content: string, width: number): string;
51
+ export declare function renderInlineForTest(c: System24Palette, text: string): string;
35
52
  export interface System24RendererStreams {
36
53
  stdout?: WritableStreamLike;
37
54
  stderr?: WritableStreamLike;
@@ -31,6 +31,15 @@ const BORDER_BL = "└";
31
31
  const BORDER_BR = "┘";
32
32
  const BORDER_ML = "├";
33
33
  const BORDER_MR = "┤";
34
+ // ── Hoisted regex constants (avoid per-call compilation) ───────────────────
35
+ const RE_HEADER = /^(#{1,3})\s+(.+)$/;
36
+ const RE_LIST_ITEM = /^(\s*)[-*]\s+(.+)$/;
37
+ const RE_HR = /^[-*_]{3,}$/;
38
+ const RE_BOLD_STAR = /\*\*(.+?)\*\*/g;
39
+ const RE_BOLD_UNDER = /__(.+?)__/g;
40
+ const RE_ITALIC = /(?<!\w)\*(.+?)\*(?!\w)/g;
41
+ const RE_INLINE_CODE = /`([^`]+)`/g;
42
+ const RE_LINK = /\[([^\]]+)\]\([^)]+\)/g;
34
43
  function termWidth(stream) {
35
44
  const width = stream.columns ?? process.stdout.columns ?? 80;
36
45
  return Number.isFinite(width) ? Math.max(40, width) : 80;
@@ -48,6 +57,9 @@ function countRows(chunk) {
48
57
  function stripAnsi(s) {
49
58
  return s.replace(/\x1b\[[0-9;]*m/g, "");
50
59
  }
60
+ export function visibleLenForTest(s) {
61
+ return stripAnsi(s).length;
62
+ }
51
63
  function visibleLen(s) {
52
64
  return stripAnsi(s).length;
53
65
  }
@@ -92,12 +104,24 @@ function renderPanelDivider(c, width, label) {
92
104
  }
93
105
  return c.border + BORDER_ML + SEP_CHAR.repeat(inner) + BORDER_MR + RST;
94
106
  }
107
+ export function renderPanelLineForTest(c, content, width) {
108
+ return renderPanelLine(c, content, width);
109
+ }
95
110
  function renderPanelLine(c, content, width) {
96
111
  const inner = width - 2;
97
- const safeContent = visibleLen(content) > inner
98
- ? `${stripAnsi(content).slice(0, Math.max(0, inner - 1))}…`
99
- : content;
100
- const padded = padRight(safeContent, inner);
112
+ const plain = stripAnsi(content);
113
+ const vLen = plain.length;
114
+ let safeContent;
115
+ let safeVLen;
116
+ if (vLen > inner) {
117
+ safeContent = plain.slice(0, Math.max(0, inner - 1)) + "…";
118
+ safeVLen = inner; // inner-1 chars + "…" (1 wide) = inner
119
+ }
120
+ else {
121
+ safeContent = content;
122
+ safeVLen = vLen;
123
+ }
124
+ const padded = safeVLen < inner ? safeContent + " ".repeat(inner - safeVLen) : safeContent;
101
125
  return c.border + BORDER_V + RST + padded + c.border + BORDER_V + RST;
102
126
  }
103
127
  // ── Code Block Rendering ───────────────────────────────────────────────────
@@ -119,16 +143,15 @@ function renderCodeBlock(c, codeLines, lang, width) {
119
143
  return result;
120
144
  }
121
145
  // ── Inline Markdown (system24 style) ───────────────────────────────────────
146
+ export function renderInlineForTest(c, text) {
147
+ return renderInline(c, text);
148
+ }
122
149
  function renderInline(c, text) {
123
- // Bold
124
- let s = text.replace(/\*\*(.+?)\*\*/g, (_, m) => BOLD + c.text1 + m + RST);
125
- s = s.replace(/__(.+?)__/g, (_, m) => BOLD + c.text1 + m + RST);
126
- // Italic
127
- s = s.replace(/(?<!\w)\*(.+?)\*(?!\w)/g, (_, m) => ITALIC + c.text3 + m + RST);
128
- // Inline code
129
- s = s.replace(/`([^`]+)`/g, (_, m) => c.bg3 + c.text1 + " " + m + " " + RST);
130
- // Links
131
- s = s.replace(/\[([^\]]+)\]\([^)]+\)/g, (_, m) => c.cyan + m + RST);
150
+ let s = text.replace(RE_BOLD_STAR, (_, m) => BOLD + c.text1 + m + RST);
151
+ s = s.replace(RE_BOLD_UNDER, (_, m) => BOLD + c.text1 + m + RST);
152
+ s = s.replace(RE_ITALIC, (_, m) => ITALIC + c.text3 + m + RST);
153
+ s = s.replace(RE_INLINE_CODE, (_, m) => c.bg3 + c.text1 + " " + m + " " + RST);
154
+ s = s.replace(RE_LINK, (_, m) => c.cyan + m + RST);
132
155
  return s;
133
156
  }
134
157
  // ── Thinking Animation ─────────────────────────────────────────────────────
@@ -368,7 +391,7 @@ export class System24Renderer {
368
391
  continue;
369
392
  }
370
393
  // Headers
371
- const hMatch = line.match(/^(#{1,3})\s+(.+)$/);
394
+ const hMatch = line.match(RE_HEADER);
372
395
  if (hMatch) {
373
396
  const level = hMatch[1].length;
374
397
  const text = hMatch[2];
@@ -381,13 +404,13 @@ export class System24Renderer {
381
404
  continue;
382
405
  }
383
406
  // List items
384
- const lMatch = line.match(/^(\s*)[-*]\s+(.+)$/);
407
+ const lMatch = line.match(RE_LIST_ITEM);
385
408
  if (lMatch) {
386
409
  this.writeOut(renderPanelLine(c, " " + c.accent + "◆" + RST + " " + renderInline(c, lMatch[2]), w) + "\n");
387
410
  continue;
388
411
  }
389
412
  // Horizontal rule
390
- if (/^[-*_]{3,}$/.test(line.trim())) {
413
+ if (RE_HR.test(line.trim())) {
391
414
  this.writeOut(renderPanelLine(c, " " + c.text5 + SEP_CHAR.repeat(Math.min(w - 6, 40)) + RST, w) + "\n");
392
415
  continue;
393
416
  }
@@ -112,7 +112,9 @@ export async function startChatRepl(options) {
112
112
  const rl = readline.createInterface({
113
113
  input: process.stdin,
114
114
  output: process.stdout,
115
- prompt: options.json ? "omk> " : "\x1b[36momk>\x1b[0m ",
115
+ // ANSI-16 cyan (conceptually night-city route.active) assembled from a CSI
116
+ // prefix so color:gate stays literal-free; the rendered bytes are unchanged.
117
+ prompt: options.json ? "omk> " : `${"\x1b["}36momk>${"\x1b["}0m `,
116
118
  completer: (line) => {
117
119
  const trimmed = line.trim();
118
120
  if (/^\/(?:model|m)(?:\s|$)/.test(trimmed) || (trimmed.length === 0 && replState.activeProviderTab)) {
@@ -68,6 +68,9 @@ export declare class ModelCommand extends OmkCommand {
68
68
  export declare class DoctorCommand extends OmkCommand {
69
69
  static paths: string[][];
70
70
  static usage: import("clipanion").Usage;
71
+ noColor: boolean;
72
+ /** Color-tier / theme / NO_COLOR diagnostic section (theme contract T5a). */
73
+ private writeColorThemeSection;
71
74
  execute(): Promise<number>;
72
75
  }
73
76
  /**
@@ -86,6 +89,9 @@ export declare class ThemeCommand extends OmkCommand {
86
89
  static paths: string[][];
87
90
  static usage: import("clipanion").Usage;
88
91
  nameArgs: string[];
92
+ noColor: boolean;
93
+ /** Detect the degradation tier, honoring the command's --no-color flag. */
94
+ private detectTier;
89
95
  execute(): Promise<number>;
90
96
  }
91
97
  /**
@@ -16,6 +16,8 @@ import { registerSlashCommands } from "../../runtime/slash-commands.js";
16
16
  import { registerProviderCommandsV2 } from "./provider-commands.js";
17
17
  import { registerWorkflowCommandsV2 } from "./workflow-commands.js";
18
18
  import { DEFAULT_AUTHORITY_PROVIDER } from "../../providers/types.js";
19
+ import { getOmkVersionSync } from "../../util/version.js";
20
+ import { OMK_RUNTIME_VERSION } from "../../version.js";
19
21
  /**
20
22
  * Base class for all OMK v2 commands.
21
23
  * Provides common pipeline execution helpers.
@@ -201,7 +203,47 @@ export class DoctorCommand extends OmkCommand {
201
203
  static usage = Command.Usage({
202
204
  description: "Run OMK health checks",
203
205
  });
206
+ noColor = Option.Boolean("--no-color", false, { description: "Disable color output (NO_COLOR equivalent)" });
207
+ /** Color-tier / theme / NO_COLOR diagnostic section (theme contract T5a). */
208
+ async writeColorThemeSection() {
209
+ const { explainColorTier } = await import("../theme/tier-explain.js");
210
+ const { resolveTheme } = await import("../theme/theme-resolver.js");
211
+ const { loadThemeDocument, validateThemeDocument } = await import("../theme/theme-doc.js");
212
+ const argv = this.noColor ? ["--no-color"] : [];
213
+ const explanation = explainColorTier(argv);
214
+ const active = resolveTheme({ cwd: this.cwd, flagTheme: this.theme || undefined });
215
+ const doc = loadThemeDocument(active.name, this.cwd);
216
+ const schemaStatus = doc === undefined
217
+ ? "builtin palette (no omk.theme.v1 document)"
218
+ : (() => {
219
+ const errors = validateThemeDocument(doc);
220
+ return errors.length === 0 ? "omk.theme.v1 document: valid" : `omk.theme.v1 document: INVALID (${errors.length} error(s): ${errors[0]})`;
221
+ })();
222
+ if (this.json) {
223
+ this.context.stdout.write(JSON.stringify({
224
+ section: "color-theme",
225
+ tier: explanation.tier,
226
+ reasons: explanation.reasons,
227
+ noColorRequested: explanation.noColorRequested,
228
+ noColorHonored: explanation.noColorHonored,
229
+ activeTheme: active.name,
230
+ themeMode: active.mode,
231
+ schema: schemaStatus,
232
+ }) + "\n");
233
+ return;
234
+ }
235
+ this.context.stdout.write([
236
+ "Color tier & theme",
237
+ ` detected tier : ${explanation.tier}`,
238
+ ` why : ${explanation.reasons.join("; ")}`,
239
+ ` NO_COLOR : requested=${explanation.noColorRequested ? "yes" : "no"} honored=${explanation.noColorHonored ? "yes" : "no"}`,
240
+ ` active theme : ${active.name} (mode ${active.mode})`,
241
+ ` theme schema : ${schemaStatus}`,
242
+ "",
243
+ ].join("\n"));
244
+ }
204
245
  async execute() {
246
+ await this.writeColorThemeSection();
205
247
  return this.executePipeline("run health checks", "doctor");
206
248
  }
207
249
  }
@@ -265,36 +307,105 @@ export class ThemeCommand extends OmkCommand {
265
307
  ],
266
308
  });
267
309
  nameArgs = Option.Rest({ required: 0 });
310
+ noColor = Option.Boolean("--no-color", false, { description: "Disable color output (NO_COLOR equivalent)" });
311
+ /** Detect the degradation tier, honoring the command's --no-color flag. */
312
+ async detectTier() {
313
+ const { detectColorTier } = await import("../theme/terminal-capability.js");
314
+ return detectColorTier(this.noColor ? ["--no-color"] : []);
315
+ }
268
316
  async execute() {
269
317
  const name = this.nameArgs.join(" ").trim();
270
318
  const subcommand = this.nameArgs[0] ?? "";
271
319
  const target = this.nameArgs.slice(1).join(" ").trim();
272
- // omk theme list — show all themes with color swatches
320
+ // omk theme list — active theme + omk.theme.v1 documents + builtin swatches
273
321
  if (subcommand === "list") {
274
322
  const { renderAllThemePreviews, getBuiltinTheme } = await import("../theme/theme-registry.js");
275
- const current = process.env.OMK_THEME ?? "omk";
276
- const currentPalette = getBuiltinTheme(current) ?? getBuiltinTheme("omk");
277
- this.context.stdout.write((currentPalette?.render("header", `Current theme: ${current}`) ?? `Current theme: ${current}`) + "\n\n");
323
+ const { resolveTheme } = await import("../theme/theme-resolver.js");
324
+ const { listThemeDocuments, loadThemeDocument, validateThemeDocument } = await import("../theme/theme-doc.js");
325
+ const active = resolveTheme({ cwd: this.cwd, flagTheme: this.theme || undefined });
326
+ const tier = await this.detectTier();
327
+ const currentPalette = getBuiltinTheme(active.name) ?? getBuiltinTheme("omk");
328
+ this.context.stdout.write((currentPalette?.render("header", `Active theme: ${active.name}`) ?? `Active theme: ${active.name}`)
329
+ + ` (mode ${active.mode}, tier ${tier})\n\n`);
330
+ const docs = listThemeDocuments(this.cwd);
331
+ if (docs.length > 0) {
332
+ this.context.stdout.write("Theme documents (omk.theme.v1):\n");
333
+ for (const ref of docs) {
334
+ const doc = loadThemeDocument(ref.name, this.cwd);
335
+ const valid = doc !== undefined && validateThemeDocument(doc).length === 0;
336
+ const marker = ref.name === active.name ? "●" : "○";
337
+ this.context.stdout.write(` ${marker} ${ref.name} — ${ref.path} (${valid ? "valid" : "INVALID"})\n`);
338
+ }
339
+ this.context.stdout.write("\n");
340
+ }
341
+ this.context.stdout.write("Built-in palettes:\n");
278
342
  this.context.stdout.write(renderAllThemePreviews() + "\n");
279
343
  return 0;
280
344
  }
281
- // omk theme preview <name> — show color swatch without switching
345
+ // omk theme set <name> — validate + persist choice to project config
346
+ if (subcommand === "set") {
347
+ if (!target) {
348
+ this.context.stderr.write("Usage: omk theme set <name>\n");
349
+ return 2;
350
+ }
351
+ const { getBuiltinTheme, listBuiltinThemes } = await import("../theme/theme-registry.js");
352
+ const { listThemeDocuments } = await import("../theme/theme-doc.js");
353
+ const docNames = listThemeDocuments(this.cwd).map((r) => r.name);
354
+ const known = getBuiltinTheme(target) !== undefined || docNames.includes(target);
355
+ if (!known) {
356
+ this.context.stderr.write(`Unknown theme: ${target}\n`);
357
+ this.context.stderr.write(`Available: ${[...new Set([...docNames, ...listBuiltinThemes()])].join(", ")}\n`);
358
+ return 2;
359
+ }
360
+ const { readFile, writeFile } = await import("node:fs/promises");
361
+ const { resolve } = await import("node:path");
362
+ const cfgPath = resolve(this.cwd, ".omkrc.json");
363
+ let existing = {};
364
+ try {
365
+ existing = JSON.parse(await readFile(cfgPath, "utf8"));
366
+ }
367
+ catch {
368
+ existing = {};
369
+ }
370
+ const next = { ...existing, theme: target };
371
+ await writeFile(cfgPath, JSON.stringify(next, null, 2) + "\n");
372
+ process.env.OMK_THEME = target;
373
+ this.context.stdout.write(`Theme set to: ${target} (persisted to ${cfgPath})\n`);
374
+ return 0;
375
+ }
376
+ // omk theme preview <name> — representative status frame at detected tier
377
+ // (same frame as test/theme-degradation.test.mjs) for omk.theme.v1 docs;
378
+ // falls back to the builtin palette swatch for registry-only themes.
282
379
  if (subcommand === "preview") {
283
380
  if (!target) {
284
381
  this.context.stderr.write("Usage: omk theme preview <name>\n");
285
382
  return 2;
286
383
  }
384
+ const { loadThemeDocument, listThemeDocuments } = await import("../theme/theme-doc.js");
385
+ const doc = loadThemeDocument(target, this.cwd);
386
+ if (doc !== undefined) {
387
+ const { compileTheme } = await import("../theme/render-table.js");
388
+ const { renderStatusFrame } = await import("../theme/status-frame.js");
389
+ const tier = await this.detectTier();
390
+ const compiled = compileTheme(doc, tier);
391
+ this.context.stdout.write(`${doc.displayName ?? doc.name} — tier ${tier}\n\n`);
392
+ this.context.stdout.write(renderStatusFrame(compiled) + "\n");
393
+ const current = process.env.OMK_THEME ?? "omk";
394
+ this.context.stdout.write(`\nCurrent theme: ${current}. Use \`omk theme set ${target}\` to switch.\n`);
395
+ return 0;
396
+ }
287
397
  const { renderThemePreview, getBuiltinTheme, listBuiltinThemes } = await import("../theme/theme-registry.js");
288
398
  const palette = getBuiltinTheme(target);
289
399
  if (!palette) {
290
- const available = listBuiltinThemes().join(", ");
400
+ const docNames = listThemeDocuments(this.cwd).map((r) => r.name);
401
+ const available = [...new Set([...docNames, ...listBuiltinThemes()])].join(", ");
291
402
  this.context.stderr.write(`Unknown theme: ${target}\n`);
292
403
  this.context.stderr.write(`Available: ${available}\n`);
293
404
  return 2;
294
405
  }
295
406
  this.context.stdout.write(renderThemePreview(palette) + "\n");
296
407
  const current = process.env.OMK_THEME ?? "omk";
297
- this.context.stdout.write(`\nCurrent theme: ${current}. Use \`omk theme ${target}\` to switch.\n`);
408
+ this.context.stdout.write(`\nCurrent theme: ${current}. Use \`omk theme set ${target}\` to switch.\n`);
298
409
  return 0;
299
410
  }
300
411
  // omk theme <name> — set theme
@@ -321,10 +432,11 @@ export class ThemeCommand extends OmkCommand {
321
432
  * Register all v2 commands on a Clipanion CLI instance.
322
433
  */
323
434
  export function createCliV2() {
435
+ const packageVersion = getOmkVersionSync();
324
436
  const cli = new Cli({
325
- binaryLabel: "OMK CLI",
437
+ binaryLabel: "OMK root orchestrator",
326
438
  binaryName: "omk",
327
- binaryVersion: "1.1.18",
439
+ binaryVersion: `${packageVersion} (${OMK_RUNTIME_VERSION})`,
328
440
  });
329
441
  cli.register(ChatCommand);
330
442
  cli.register(RunCommand);
@@ -47,5 +47,6 @@ export declare function withSpinner<T>(message: string, fn: () => Promise<T>): P
47
47
  /**
48
48
  * Intro/outro for OMK session.
49
49
  */
50
+ export declare function formatOmkIntroTitle(version: string): string;
50
51
  export declare function omkIntro(version: string): void;
51
52
  export declare function omkOutro(message: string): void;
@@ -8,6 +8,7 @@
8
8
  * - Progress feedback during long operations
9
9
  */
10
10
  import * as clack from "@clack/prompts";
11
+ import { OMK_RUNTIME_VERSION } from "../../version.js";
11
12
  /**
12
13
  * Interactive provider selection.
13
14
  * Returns selected provider/model string.
@@ -49,7 +50,7 @@ export async function promptThemeSelection(currentTheme) {
49
50
  { value: "omk", label: "OMK", hint: "Default colorful theme" },
50
51
  { value: "night-city", label: "Night City", hint: "README control image palette" },
51
52
  { value: "green-rain", label: "Green Rain", hint: "Phosphor signal console" },
52
- { value: "rust-forge", label: "Rust Forge", hint: "Rust/native safety console" },
53
+ { value: "rust-forge", label: "Rust Forge", hint: "Oxidized forge control console" },
53
54
  { value: "neon-circuit", label: "Neon Circuit", hint: "High-energy neon terminal" },
54
55
  { value: "matrix", label: "Matrix", hint: "Classic green-on-black phosphor" },
55
56
  { value: "minimal", label: "Minimal", hint: "Clean, few colors" },
@@ -167,8 +168,11 @@ export async function withSpinner(message, fn) {
167
168
  /**
168
169
  * Intro/outro for OMK session.
169
170
  */
171
+ export function formatOmkIntroTitle(version) {
172
+ return `OMK root orchestrator · package v${version} · runtime ${OMK_RUNTIME_VERSION}`;
173
+ }
170
174
  export function omkIntro(version) {
171
- clack.intro(`OMK v${version}`);
175
+ clack.intro(formatOmkIntroTitle(version));
172
176
  }
173
177
  export function omkOutro(message) {
174
178
  clack.outro(message);
@@ -300,7 +300,7 @@ export async function chatCommand(options) {
300
300
  }
301
301
  // ── plain / inline: run OMK native chat loop ──
302
302
  const isPlain = layout === "plain";
303
- const isPiOmkEntry = process.env.OMK_ENTRY_SURFACE === "pi-omk";
303
+ const isOmkRootEntry = process.env.OMK_ENTRY_SURFACE === "omk-root-orchestrator";
304
304
  if (!isPlain && ui !== "green-rain" && ui !== "neon-grid" && ui !== "rust-forge") {
305
305
  const trust = `${effectiveResources.mcpScope} MCP / ${effectiveResources.skillsScope} skills`;
306
306
  const agentDisplay = relative(root, effectiveAgentFile);
@@ -316,7 +316,7 @@ export async function chatCommand(options) {
316
316
  }) + "\n");
317
317
  }
318
318
  // ── Deferred HUD + history: fire-and-forget, let the agent loop start immediately ──
319
- if (!isPlain && !isPiOmkEntry) {
319
+ if (!isPlain && !isOmkRootEntry) {
320
320
  // Show a minimal status line while we defer the full HUD
321
321
  const providerLabel = providerPolicy === "auto" ? "auto-detect" : providerPolicy;
322
322
  const modeLabel = currentMode;
@@ -18,6 +18,7 @@ import { GreenRainRenderer } from "../../cli/ui/green-rain-renderer.js";
18
18
  import { NeonGridRenderer } from "../../cli/ui/neon-grid-renderer.js";
19
19
  import { RustForgeRenderer } from "../../cli/ui/rust-forge-renderer.js";
20
20
  import { sanitizeUserVisibleOutput } from "../../util/user-visible-output.js";
21
+ import { setBrandPaletteTheme } from "../../brand/palette.js";
21
22
  export function shouldUseDirectKimiFallback() {
22
23
  return false;
23
24
  }
@@ -237,6 +238,7 @@ export async function runChatRuntime(options, input) {
237
238
  process.stdout.write(sanitizeUserVisibleOutput(text));
238
239
  },
239
240
  });
241
+ setBrandPaletteTheme(ui === "rust-forge" ? "rust-forge" : process.env.OMK_THEME);
240
242
  const renderer = ui === "neon-grid"
241
243
  ? new NeonGridRenderer()
242
244
  : ui === "green-rain"
@@ -8,6 +8,9 @@ import { readFile, readdir } from "fs/promises";
8
8
  import YAML from "yaml";
9
9
  import { t } from "../../util/i18n.js";
10
10
  import { getActiveRuntimePreset } from "../../util/resource-profile.js";
11
+ import { setBrandPaletteTheme } from "../../brand/palette.js";
12
+ import { getOmkVersionSync } from "../../util/version.js";
13
+ import { OMK_RUNTIME_VERSION } from "../../version.js";
11
14
  export function mergeTodos(existing, incoming) {
12
15
  const map = new Map();
13
16
  for (const t of existing) {
@@ -79,6 +82,7 @@ export function resolveChatWorkerCount(requested, fallback) {
79
82
  return trimmed;
80
83
  }
81
84
  export function renderChatIntro(brand, meta) {
85
+ setBrandPaletteTheme(brand === "rust-forge" ? "rust-forge" : process.env.OMK_THEME);
82
86
  const titleKey = {
83
87
  omk: "chat.intro.omk",
84
88
  "green-rain": "chat.intro.greenRain",
@@ -102,20 +106,24 @@ export function renderChatIntro(brand, meta) {
102
106
  lines.push("");
103
107
  }
104
108
  else if (brand === "rust-forge") {
105
- lines.push(style.rustBold("▣ OMK//RUST-FORGE"));
106
- lines.push(style.gray(" CARGO SAFETY ONLINE"));
107
- lines.push(style.gray(" Native: hot · Verify: armed · Loop: controlled."));
109
+ lines.push(style.rustBold("▣ OMK//RUST-FORGE · ROOT ORCHESTRATOR"));
110
+ lines.push(style.gray(" OXIDIZED FORGE ONLINE"));
111
+ lines.push(style.gray(" OMK independent control: adapters are lanes, evidence is authority."));
112
+ lines.push(style.gray(" Heat: hot · Anvil: locked · Quench: ready · Loop: controlled."));
108
113
  for (const artLine of OMK_SIMPLE_ASCII_ART.split("\n")) {
109
114
  lines.push(style.rust(artLine));
110
115
  }
111
116
  lines.push("");
112
117
  }
113
118
  else if (brand !== "plain") {
114
- lines.push(style.phosphorBold("◇ OMK//CONTROL"));
119
+ lines.push(style.phosphorBold("◇ OMK//CONTROL · ROOT ORCHESTRATOR"));
115
120
  lines.push(style.gray(" OMK ONLINE"));
116
121
  lines.push(style.gray(" Route: online · Verify: armed · Loop: controlled."));
117
122
  lines.push("");
118
123
  }
124
+ if (brand !== "plain") {
125
+ lines.push(style.gray(` package v${getOmkVersionSync()} · runtime ${OMK_RUNTIME_VERSION}`));
126
+ }
119
127
  lines.push(style.phosphorBold(`▸ ${title}`));
120
128
  if (brand !== "plain") {
121
129
  lines.push(` ${style.gray(t("chat.intro.agent") + ":")} ${style.cream(meta.agent)}`);