open-multi-agent-kit 0.78.8 → 0.79.3

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 (162) hide show
  1. package/AGENTS.md +131 -2
  2. package/CHANGELOG.md +32 -0
  3. package/CLAUDE.md +105 -3
  4. package/DESIGN.md +141 -117
  5. package/MATURITY.md +7 -12
  6. package/README.md +66 -347
  7. package/ROADMAP.md +33 -47
  8. package/dist/adapters/kimi/runner.js +2 -2
  9. package/dist/brand/theme.js +2 -2
  10. package/dist/cli/register-basic-commands.js +3 -2
  11. package/dist/cli/register-mcp-dag-cron-screenshot-commands.js +1 -1
  12. package/dist/cli/root.d.ts +1 -0
  13. package/dist/cli/root.js +2 -0
  14. package/dist/cli/runtime/command-bus.js +14 -1
  15. package/dist/cli/theme/terminal-capability.js +1 -1
  16. package/dist/cli/theme/theme-registry.js +90 -2
  17. package/dist/cli/ui/event.d.ts +1 -0
  18. package/dist/cli/ui/neon-grid-renderer.d.ts +8 -0
  19. package/dist/cli/ui/neon-grid-renderer.js +84 -14
  20. package/dist/cli/ui/plain-renderer.js +3 -1
  21. package/dist/cli/ui/system24-renderer.js +3 -1
  22. package/dist/cli/v2/chat-repl.d.ts +2 -1
  23. package/dist/cli/v2/chat-repl.js +58 -2
  24. package/dist/cli/v2/cli-v2-skeleton.js +7 -4
  25. package/dist/cli/v2/interactive-prompt.js +4 -3
  26. package/dist/commands/auth.js +2 -0
  27. package/dist/commands/chat/native-root-loop.d.ts +1 -0
  28. package/dist/commands/chat/native-root-loop.js +162 -13
  29. package/dist/commands/chat/runtime.js +9 -0
  30. package/dist/commands/chat/slash/commands/routing.js +31 -1
  31. package/dist/commands/chat/utils.js +3 -1
  32. package/dist/commands/cockpit/render.js +2 -1
  33. package/dist/commands/doctor/checks.js +2 -2
  34. package/dist/commands/init/core.js +2 -2
  35. package/dist/commands/init.js +2 -2
  36. package/dist/commands/mcp/config.js +38 -16
  37. package/dist/commands/mcp/doctor.js +7 -8
  38. package/dist/commands/mcp/list.js +4 -3
  39. package/dist/commands/mcp/shared.d.ts +4 -1
  40. package/dist/commands/mcp/shared.js +21 -3
  41. package/dist/commands/mcp/test.js +13 -12
  42. package/dist/commands/model.js +4 -0
  43. package/dist/commands/provider.js +5 -1
  44. package/dist/commands/version.d.ts +1 -0
  45. package/dist/commands/version.js +18 -0
  46. package/dist/contracts/command.d.ts +25 -0
  47. package/dist/contracts/command.js +1 -0
  48. package/dist/contracts/evidence-bundle.d.ts +52 -0
  49. package/dist/contracts/evidence-bundle.js +1 -0
  50. package/dist/contracts/index.d.ts +2 -0
  51. package/dist/contracts/index.js +2 -0
  52. package/dist/contracts/web-bridge.d.ts +1 -1
  53. package/dist/contracts/web-bridge.js +1 -1
  54. package/dist/evidence/bundle-validator.d.ts +7 -0
  55. package/dist/evidence/bundle-validator.js +103 -0
  56. package/dist/evidence/index.d.ts +5 -0
  57. package/dist/evidence/index.js +2 -0
  58. package/dist/evidence/proof-trust.js +2 -10
  59. package/dist/evidence/trust-calibration.d.ts +25 -0
  60. package/dist/evidence/trust-calibration.js +151 -0
  61. package/dist/mcp/omk-project-server.js +1 -1
  62. package/dist/metrics/provenance-ratio.d.ts +16 -0
  63. package/dist/metrics/provenance-ratio.js +33 -0
  64. package/dist/orchestration/dag.d.ts +17 -0
  65. package/dist/orchestration/ensemble-decision.d.ts +2 -0
  66. package/dist/orchestration/ensemble-decision.js +4 -0
  67. package/dist/orchestration/hedge-persona-weights.d.ts +25 -0
  68. package/dist/orchestration/hedge-persona-weights.js +43 -0
  69. package/dist/orchestration/parallel-ui.d.ts +1 -0
  70. package/dist/orchestration/parallel-ui.js +12 -3
  71. package/dist/orchestration/route-calibration.d.ts +27 -0
  72. package/dist/orchestration/route-calibration.js +123 -0
  73. package/dist/orchestration/routing/mcp-config.js +5 -1
  74. package/dist/orchestration/routing/types.d.ts +21 -0
  75. package/dist/orchestration/routing.d.ts +10 -0
  76. package/dist/orchestration/routing.js +89 -3
  77. package/dist/providers/model-registry.d.ts +2 -1
  78. package/dist/providers/model-registry.js +76 -4
  79. package/dist/providers/provider-runtime.js +9 -1
  80. package/dist/providers/thinking-levels.js +2 -0
  81. package/dist/providers/types.d.ts +1 -1
  82. package/dist/runtime/glm-api-runtime.d.ts +4 -0
  83. package/dist/runtime/glm-api-runtime.js +15 -0
  84. package/dist/runtime/index.d.ts +1 -0
  85. package/dist/runtime/index.js +1 -0
  86. package/dist/runtime/kimi-api-runtime.d.ts +6 -1
  87. package/dist/runtime/kimi-api-runtime.js +10 -4
  88. package/dist/runtime/recovery-artifact-store.d.ts +39 -0
  89. package/dist/runtime/recovery-artifact-store.js +111 -0
  90. package/dist/runtime/runtime-backed-task-runner.js +10 -0
  91. package/dist/runtime/runtime-bootstrap.js +17 -1
  92. package/dist/runtime/slash-commands.js +38 -5
  93. package/dist/schema/command.schema.d.ts +121 -0
  94. package/dist/schema/command.schema.js +25 -0
  95. package/dist/schema/envelope.schema.d.ts +2 -2
  96. package/dist/schema/evidence-bundle.schema.d.ts +196 -0
  97. package/dist/schema/evidence-bundle.schema.js +38 -0
  98. package/dist/schema/index.d.ts +2 -0
  99. package/dist/schema/index.js +2 -0
  100. package/dist/schema/proof-bundle.schema.d.ts +2 -2
  101. package/dist/theme/external-theme-adapters.d.ts +27 -0
  102. package/dist/theme/external-theme-adapters.js +52 -0
  103. package/dist/theme/library-effects.d.ts +12 -0
  104. package/dist/theme/library-effects.js +47 -0
  105. package/dist/theme/parallel.js +3 -2
  106. package/dist/tui/terminal-frame-renderer.d.ts +9 -1
  107. package/dist/tui/terminal-frame-renderer.js +77 -7
  108. package/dist/util/chat-cockpit.d.ts +3 -1
  109. package/dist/util/chat-cockpit.js +44 -5
  110. package/dist/util/command-envelope.d.ts +19 -0
  111. package/dist/util/command-envelope.js +31 -0
  112. package/dist/util/events-logger.d.ts +1 -1
  113. package/dist/util/events-logger.js +23 -16
  114. package/dist/util/fs/mcp-diagnose.js +2 -1
  115. package/dist/util/fs/mcp-runtime-config.js +14 -2
  116. package/dist/util/i18n.js +2 -2
  117. package/dist/util/screenshot-store.d.ts +7 -0
  118. package/dist/util/screenshot-store.js +30 -0
  119. package/dist/util/terminal-kit-bridge.d.ts +24 -0
  120. package/dist/util/terminal-kit-bridge.js +60 -0
  121. package/dist/util/terminal-owner.d.ts +1 -0
  122. package/dist/util/terminal-owner.js +31 -0
  123. package/dist/version.d.ts +3 -1
  124. package/dist/version.js +4 -0
  125. package/docs/2026-05-18-project-direction.md +1 -1
  126. package/docs/2026-06-14/critical-issues.md +19 -0
  127. package/docs/2026-06-14/improvements.md +15 -0
  128. package/docs/2026-06-14/init-checklist.md +25 -0
  129. package/docs/2026-06-14/plan.md +20 -0
  130. package/docs/2026-06-15/critical-issues.md +19 -0
  131. package/docs/2026-06-15/improvements.md +15 -0
  132. package/docs/2026-06-15/init-checklist.md +25 -0
  133. package/docs/2026-06-15/plan.md +20 -0
  134. package/docs/claims.md +85 -0
  135. package/docs/comparisons/omk-vs-claude-code.md +31 -0
  136. package/docs/comparisons/omk-vs-codex.md +33 -0
  137. package/docs/comparisons/omk-vs-mcp-agent.md +33 -0
  138. package/docs/comparisons/omk-vs-opencode.md +32 -0
  139. package/docs/decision-layer-calibration.md +20 -0
  140. package/docs/geo-eval-prompts.md +53 -0
  141. package/docs/getting-started.md +3 -31
  142. package/docs/headroom-omk-setup-guide.md +2 -2
  143. package/docs/integrations/adaptorch.md +46 -0
  144. package/docs/native-root-runtime-algorithms.md +2 -303
  145. package/docs/native-root-runtime-hardening.md +1 -1
  146. package/docs/provider-maturity.md +1 -1
  147. package/docs/use-cases/evidence-gated-coding-agents.md +52 -0
  148. package/docs/use-cases/no-kimi-mode.md +38 -0
  149. package/docs/use-cases/provider-routing-for-ai-coding.md +36 -0
  150. package/docs/use-cases/replayable-agent-runs.md +40 -0
  151. package/docs/use-cases/scoped-mcp-for-coding-agents.md +34 -0
  152. package/docs/versioning.md +9 -3
  153. package/docs/what-is-omk.md +64 -0
  154. package/llms.txt +28 -18
  155. package/package.json +7 -2
  156. package/readmeasset/.npmignore +3 -0
  157. package/readmeasset/ASSET_INDEX.md +3 -0
  158. package/readmeasset/ASSET_PROVENANCE.md +6 -0
  159. package/readmeasset/omk-adaptorch-ouroboros-supermemory.svg +95 -0
  160. package/readmeasset/omk-init-control-loop.svg +118 -0
  161. package/readmeasset/omk-parallel-subagents.svg +97 -0
  162. package/templates/web-bridge/chrome-extension/background.js +1 -1
@@ -1,29 +1,35 @@
1
+ function useScrollSafe(optionsScrollSafe) {
2
+ if (optionsScrollSafe !== undefined)
3
+ return optionsScrollSafe;
4
+ const env = process.env.OMK_TUI_ALT_SCREEN ?? process.env.PI_TUI_ALT_SCREEN ?? "";
5
+ return !/^(1|true|yes|on|full|alt-screen)$/i.test(env);
6
+ }
1
7
  export class TerminalFrameRenderer {
2
8
  prevLines = [];
3
9
  mode;
4
10
  height;
5
11
  write;
6
12
  clearFrame;
13
+ scrollSafe;
7
14
  constructor(modeOrOptions = "diff", height) {
8
15
  if (typeof modeOrOptions === "string") {
9
16
  this.mode = modeOrOptions;
10
17
  this.height = height;
11
18
  this.write = (chunk) => process.stdout.write(chunk);
12
- this.clearFrame = () => clearTerminalScreen(this.write);
19
+ this.scrollSafe = useScrollSafe(undefined);
20
+ this.clearFrame = () => clearTerminalScreen(this.write, this.scrollSafe);
13
21
  return;
14
22
  }
15
23
  this.mode = modeOrOptions.mode ?? "diff";
16
24
  this.height = modeOrOptions.height;
17
25
  this.write = modeOrOptions.write ?? ((chunk) => process.stdout.write(chunk));
18
- this.clearFrame = modeOrOptions.clear ?? (() => clearTerminalScreen(this.write));
26
+ this.scrollSafe = useScrollSafe(modeOrOptions.scrollSafe);
27
+ this.clearFrame = modeOrOptions.clear ?? (() => clearTerminalScreen(this.write, this.scrollSafe));
19
28
  }
20
29
  render(frame) {
21
30
  const newLines = frame.split("\n");
22
31
  if (this.mode === "full") {
23
- this.clear();
24
- const fillsFixedFrame = this.height != null && newLines.length >= Math.max(1, Math.floor(this.height));
25
- this.write(fillsFixedFrame ? frame : `${frame}\n`);
26
- this.prevLines = [...newLines];
32
+ this.renderFull(newLines, frame);
27
33
  return;
28
34
  }
29
35
  if (this.mode === "append") {
@@ -31,6 +37,63 @@ export class TerminalFrameRenderer {
31
37
  this.prevLines = [...newLines];
32
38
  return;
33
39
  }
40
+ if (this.scrollSafe) {
41
+ this.renderDiffScrollSafe(newLines);
42
+ }
43
+ else {
44
+ this.renderDiffAltScreen(newLines);
45
+ }
46
+ }
47
+ renderFull(newLines, frame) {
48
+ if (this.scrollSafe) {
49
+ // On the main screen, do not clear+home. Start a fresh frame below the
50
+ // current cursor so the user's scrollback position is preserved.
51
+ if (this.prevLines.length > 0) {
52
+ this.write("\n\n");
53
+ }
54
+ }
55
+ else {
56
+ this.clear();
57
+ }
58
+ const fillsFixedFrame = this.height != null && newLines.length >= Math.max(1, Math.floor(this.height));
59
+ this.write(fillsFixedFrame ? frame : `${frame}\n`);
60
+ this.prevLines = [...newLines];
61
+ }
62
+ renderDiffScrollSafe(newLines) {
63
+ // First render: just output the frame and remember its line count.
64
+ if (this.prevLines.length === 0) {
65
+ this.write(newLines.join("\r\n") + "\r\n");
66
+ this.prevLines = [...newLines];
67
+ return;
68
+ }
69
+ // Move cursor from the end of the previous frame back to its first line.
70
+ const parts = [];
71
+ const moveUp = this.prevLines.length - 1;
72
+ if (moveUp > 0) {
73
+ parts.push(`\x1b[${moveUp}A`);
74
+ }
75
+ parts.push("\r");
76
+ const maxLen = Math.max(newLines.length, this.prevLines.length);
77
+ for (let i = 0; i < maxLen; i++) {
78
+ const newLine = newLines[i] ?? "";
79
+ const oldLine = this.prevLines[i] ?? "";
80
+ if (i < newLines.length) {
81
+ if (newLine !== oldLine) {
82
+ parts.push(`${newLine}\x1b[K`);
83
+ }
84
+ }
85
+ else {
86
+ // Old line no longer exists: clear it.
87
+ parts.push("\x1b[K");
88
+ }
89
+ if (i < maxLen - 1) {
90
+ parts.push("\r\n");
91
+ }
92
+ }
93
+ this.write(parts.join(""));
94
+ this.prevLines = [...newLines];
95
+ }
96
+ renderDiffAltScreen(newLines) {
34
97
  const parts = ["\x1b[H"];
35
98
  const maxLen = Math.max(newLines.length, this.prevLines.length);
36
99
  for (let i = 0; i < maxLen; i++) {
@@ -55,6 +118,13 @@ export class TerminalFrameRenderer {
55
118
  this.clearFrame();
56
119
  }
57
120
  }
58
- export function clearTerminalScreen(write = (chunk) => process.stdout.write(chunk)) {
121
+ export function clearTerminalScreen(write = (chunk) => process.stdout.write(chunk), scrollSafe) {
122
+ const safe = scrollSafe ?? useScrollSafe(undefined);
123
+ if (safe) {
124
+ // Main-screen safe: append blank lines to push old content up instead of
125
+ // snapping the viewport to the top with clear+home.
126
+ write("\n\n");
127
+ return;
128
+ }
59
129
  write("\x1b[2J\x1b[H");
60
130
  }
@@ -32,7 +32,7 @@ export declare function buildRightPaneCommand(options: {
32
32
  height?: number;
33
33
  theme?: string;
34
34
  }): string;
35
- export declare function buildTmuxBrandChromeOptions(brand?: string): {
35
+ export declare function buildTmuxBrandChromeOptions(brand?: string, entryDisplayName?: string): {
36
36
  sessionOptions: Array<readonly [string, string]>;
37
37
  windowOptions: Array<readonly [string, string]>;
38
38
  };
@@ -50,5 +50,7 @@ export declare function buildLeftPaneCommand(options: {
50
50
  model?: string;
51
51
  execution?: string;
52
52
  ui?: string;
53
+ entryDisplayName?: string;
54
+ entrySurface?: string;
53
55
  }): string;
54
56
  export declare function shellQuote(value: string): string;
@@ -119,6 +119,18 @@ export function resolveCockpitChromeTheme(options) {
119
119
  return normalizeBrandChromeTheme(options.env?.OMK_THEME)
120
120
  ?? normalizeBrandChromeTheme(options.brand);
121
121
  }
122
+ function normalizeEntryDisplayName(value) {
123
+ const normalized = value
124
+ ?.replace(/[^A-Za-z0-9+:/._ -]/g, "")
125
+ .trim();
126
+ return normalized && normalized.length > 0 ? normalized.slice(0, 20) : undefined;
127
+ }
128
+ function normalizeEntrySurface(value) {
129
+ const normalized = value
130
+ ?.replace(/[^A-Za-z0-9._:-]/g, "")
131
+ .trim();
132
+ return normalized && normalized.length > 0 ? normalized.slice(0, 64) : undefined;
133
+ }
122
134
  export function buildRightPaneCommand(options) {
123
135
  let cmd = `${options.nodeCmd} ${options.cliCmd} cockpit --run-id ${shellQuote(options.runId)} --watch --refresh ${options.refreshMs}`;
124
136
  const theme = normalizeBrandChromeTheme(options.theme);
@@ -135,9 +147,10 @@ export function buildRightPaneCommand(options) {
135
147
  }
136
148
  // Active brand tmux chrome. Values are built at launch time so P/BRAND_HEX
137
149
  // mutations from setBrandPaletteTheme() are reflected without changing imports.
138
- export function buildTmuxBrandChromeOptions(brand) {
150
+ export function buildTmuxBrandChromeOptions(brand, entryDisplayName) {
139
151
  setBrandPaletteTheme(brand);
140
- const statusLeft = `#[fg=${BRAND_HEX.mint},bold] OMK//CONTROL #[fg=${BRAND_HEX.gray}]${getActiveBrandChromeLabel()}`;
152
+ const controlLabel = normalizeEntryDisplayName(entryDisplayName) ?? "OMK//CONTROL";
153
+ const statusLeft = `#[fg=${BRAND_HEX.mint},bold] ${controlLabel} #[fg=${BRAND_HEX.gray}]${getActiveBrandChromeLabel()}`;
141
154
  const statusRight = `#[fg=${BRAND_HEX.cyan}]#S #[fg=${BRAND_HEX.gray}]%H:%M`;
142
155
  return {
143
156
  sessionOptions: [
@@ -156,7 +169,7 @@ export function buildTmuxBrandChromeOptions(brand) {
156
169
  };
157
170
  }
158
171
  async function applyTmuxBrandTheme(session, cwd, brand) {
159
- const chrome = buildTmuxBrandChromeOptions(brand);
172
+ const chrome = buildTmuxBrandChromeOptions(brand, process.env.OMK_ENTRY_DISPLAY_NAME);
160
173
  for (const [option, value] of chrome.sessionOptions) {
161
174
  const result = await runShell("tmux", ["set-option", "-t", session, option, value], { cwd, timeout: 5000 });
162
175
  if (result.failed) {
@@ -232,7 +245,24 @@ export async function launchChatCockpit(options = {}) {
232
245
  terminalWidth >= 80 &&
233
246
  terminalHeight >= MIN_CHAT_COCKPIT_HEIGHT + minHistoryPaneHeight;
234
247
  const chromeTheme = resolveCockpitChromeTheme({ brand, env: process.env });
235
- const leftCmd = buildLeftPaneCommand({ nodeCmd, cliCmd, runId, brand, agentFile: options.agentFile, workers: options.workers, maxStepsPerTurn: options.maxStepsPerTurn, mcpScope: options.mcpScope, provider: options.provider, model: options.model, execution: options.execution, ui: options.ui });
248
+ const entryDisplayName = normalizeEntryDisplayName(process.env.OMK_ENTRY_DISPLAY_NAME);
249
+ const entrySurface = normalizeEntrySurface(process.env.OMK_ENTRY_SURFACE);
250
+ const leftCmd = buildLeftPaneCommand({
251
+ nodeCmd,
252
+ cliCmd,
253
+ runId,
254
+ brand,
255
+ agentFile: options.agentFile,
256
+ workers: options.workers,
257
+ maxStepsPerTurn: options.maxStepsPerTurn,
258
+ mcpScope: options.mcpScope,
259
+ provider: options.provider,
260
+ model: options.model,
261
+ execution: options.execution,
262
+ ui: options.ui,
263
+ entrySurface,
264
+ entryDisplayName,
265
+ });
236
266
  // When no explicit --cockpit-height is provided, pass undefined so the child
237
267
  // measures its actual tmux pane after splits/resizes and keeps the right rail pinned.
238
268
  const rightTopCmd = buildRightPaneCommand({
@@ -325,7 +355,7 @@ export async function launchChatCockpit(options = {}) {
325
355
  }
326
356
  }
327
357
  export function buildLeftPaneCommand(options) {
328
- const { nodeCmd, cliCmd, runId, brand, agentFile, workers, maxStepsPerTurn, mcpScope, provider, model, execution, ui } = options;
358
+ const { nodeCmd, cliCmd, runId, brand, agentFile, workers, maxStepsPerTurn, mcpScope, provider, model, execution, ui, entrySurface, entryDisplayName, } = options;
329
359
  let cmd = `${nodeCmd} ${cliCmd} chat --layout plain --run-id ${shellQuote(runId)} --brand ${shellQuote(brand)}`;
330
360
  if (agentFile)
331
361
  cmd += ` --agent-file ${shellQuote(agentFile)}`;
@@ -343,6 +373,15 @@ export function buildLeftPaneCommand(options) {
343
373
  cmd += ` --execution ${shellQuote(execution)}`;
344
374
  if (ui)
345
375
  cmd += ` --ui ${shellQuote(ui)}`;
376
+ const envAssignments = [];
377
+ const normalizedEntrySurface = normalizeEntrySurface(entrySurface);
378
+ if (normalizedEntrySurface)
379
+ envAssignments.push(`OMK_ENTRY_SURFACE=${shellQuote(normalizedEntrySurface)}`);
380
+ const normalizedEntryDisplayName = normalizeEntryDisplayName(entryDisplayName);
381
+ if (normalizedEntryDisplayName)
382
+ envAssignments.push(`OMK_ENTRY_DISPLAY_NAME=${shellQuote(normalizedEntryDisplayName)}`);
383
+ if (envAssignments.length > 0)
384
+ cmd = `${envAssignments.join(" ")} ${cmd}`;
346
385
  return cmd;
347
386
  }
348
387
  export function shellQuote(value) {
@@ -0,0 +1,19 @@
1
+ import type { OmkCommandDiagnostic, OmkCommandEnvelope, OmkCommandEnvelopeStatus } from "../contracts/command.js";
2
+ import type { EvidenceRef } from "../contracts/evidence.js";
3
+ export type CreateOmkCommandEnvelopeOptions<TData> = {
4
+ command: string;
5
+ status: OmkCommandEnvelopeStatus;
6
+ data: TData;
7
+ diagnostics?: OmkCommandDiagnostic[];
8
+ evidenceRefs?: EvidenceRef[];
9
+ exitCode?: number;
10
+ runId?: string;
11
+ commit?: string;
12
+ startedAt?: string;
13
+ finishedAt?: string;
14
+ };
15
+ export declare function createOmkCommandEnvelope<TData>(options: CreateOmkCommandEnvelopeOptions<TData>): OmkCommandEnvelope<TData>;
16
+ export declare function commandDiagnostic(severity: OmkCommandDiagnostic["severity"], code: string, message: string, options?: Partial<Omit<OmkCommandDiagnostic, "severity" | "code" | "message" | "redacted">> & {
17
+ redacted?: boolean;
18
+ }): OmkCommandDiagnostic;
19
+ export declare function createCommandRunId(prefix?: string): string;
@@ -0,0 +1,31 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { OMK_COMMAND_SCHEMA_VERSION } from "../version.js";
3
+ export function createOmkCommandEnvelope(options) {
4
+ const startedAt = options.startedAt ?? new Date().toISOString();
5
+ return {
6
+ schemaVersion: OMK_COMMAND_SCHEMA_VERSION,
7
+ command: options.command,
8
+ status: options.status,
9
+ ...(options.runId ? { runId: options.runId } : {}),
10
+ ...(options.commit ? { commit: options.commit } : {}),
11
+ startedAt,
12
+ finishedAt: options.finishedAt ?? startedAt,
13
+ data: options.data,
14
+ diagnostics: options.diagnostics ?? [],
15
+ evidenceRefs: options.evidenceRefs ?? [],
16
+ exitCode: options.exitCode ?? (options.status === "fail" ? 1 : 0),
17
+ };
18
+ }
19
+ export function commandDiagnostic(severity, code, message, options = {}) {
20
+ return {
21
+ severity,
22
+ code,
23
+ message,
24
+ redacted: options.redacted ?? true,
25
+ ...(options.remediation ? { remediation: options.remediation } : {}),
26
+ ...(options.path ? { path: options.path } : {}),
27
+ };
28
+ }
29
+ export function createCommandRunId(prefix = "cmd") {
30
+ return `${prefix}-${randomUUID()}`;
31
+ }
@@ -1,5 +1,5 @@
1
1
  export type ReplayEventType = "replay-start" | "replay-end" | "node-start" | "node-complete" | "node-fallback" | "state-change";
2
- export type TelemetryEventType = ReplayEventType | "lane.started" | "lane.activity" | "lane.heartbeat" | "lane.completed" | "lane.failed" | "lane.stalled" | "agent.spawned" | "tool.started" | "tool.completed" | "mcp.started" | "mcp.completed" | "mcp.failed" | "hook.started" | "hook.completed" | "provider.route" | "provider.fallback" | "provider.request.started" | "provider.request.completed" | "provider.request.failed" | "provider.advisory.started" | "provider.advisory.completed" | "provider.advisory.failed" | "evidence.result";
2
+ export type TelemetryEventType = ReplayEventType | "lane.started" | "lane.activity" | "lane.heartbeat" | "lane.completed" | "lane.failed" | "lane.stalled" | "agent.spawned" | "tool.started" | "tool.completed" | "mcp.started" | "mcp.completed" | "mcp.failed" | "hook.started" | "hook.completed" | "provider.route" | "provider.fallback" | "provider.request.started" | "provider.request.completed" | "provider.request.failed" | "provider.advisory.started" | "provider.advisory.completed" | "provider.advisory.failed" | "evidence.result" | "run.started" | "run.completed" | "dag.node.started" | "dag.node.completed" | "provider.selected" | "tool.allowed" | "tool.denied" | "evidence.attached" | "verifier.verdict";
3
3
  export interface TelemetryEvent {
4
4
  schemaVersion: "telemetry.v1";
5
5
  type: TelemetryEventType;
@@ -98,32 +98,39 @@ export async function appendEvent(runDir, event) {
98
98
  const write = previous.then(async () => {
99
99
  const seq = await nextSeq(runDir, event.seq);
100
100
  const line = JSON.stringify(sanitizeTelemetryEvent({ ...event, timestamp: event.timestamp ?? new Date().toISOString() }, seq)) + "\n";
101
+ await appendFile(join(runDir, "events.ndjson"), line, "utf-8");
101
102
  await appendFile(join(runDir, "events.jsonl"), line, "utf-8");
102
103
  });
103
104
  appendQueueByRunDir.set(runDir, write.catch(() => { }));
104
105
  await write;
105
106
  }
106
107
  export async function readEvents(runDir) {
108
+ let content;
107
109
  try {
108
- const content = await readFile(join(runDir, "events.jsonl"), "utf-8");
109
- const events = [];
110
- for (const line of content.split("\n")) {
111
- if (!line.trim())
112
- continue;
113
- try {
114
- const parsed = JSON.parse(line);
115
- const seq = typeof parsed.seq === "number" && Number.isFinite(parsed.seq) ? parsed.seq : events.length + 1;
116
- events.push(sanitizeTelemetryEvent(parsed, seq));
117
- }
118
- catch {
119
- // Keep append-only logs readable even if one line is corrupt.
120
- }
121
- }
122
- return events;
110
+ content = await readFile(join(runDir, "events.ndjson"), "utf-8");
123
111
  }
124
112
  catch {
125
- return [];
113
+ try {
114
+ content = await readFile(join(runDir, "events.jsonl"), "utf-8");
115
+ }
116
+ catch {
117
+ return [];
118
+ }
119
+ }
120
+ const events = [];
121
+ for (const line of content.split("\n")) {
122
+ if (!line.trim())
123
+ continue;
124
+ try {
125
+ const parsed = JSON.parse(line);
126
+ const seq = typeof parsed.seq === "number" && Number.isFinite(parsed.seq) ? parsed.seq : events.length + 1;
127
+ events.push(sanitizeTelemetryEvent(parsed, seq));
128
+ }
129
+ catch {
130
+ // Keep append-only logs readable even if one line is corrupt.
131
+ }
126
132
  }
133
+ return events;
127
134
  }
128
135
  export async function tailEvents(runDir, options = {}) {
129
136
  const afterSeq = options.afterSeq ?? 0;
@@ -12,6 +12,7 @@ export async function collectMcpConfigs(scope = "project") {
12
12
  const home = getUserHome();
13
13
  const projectOmkMcp = join(root, ".omk", "mcp.json");
14
14
  const projectKimiMcp = join(root, ".kimi", "mcp.json");
15
+ const globalAgentMcp = join(home, ".omk", "agent", "mcp.json");
15
16
  const globalOmkMcp = join(home, ".omk", "mcp.json");
16
17
  const globalKimiMcp = join(home, ".kimi", "mcp.json");
17
18
  // Precedence is left-to-right with later files winning during runtime merge:
@@ -19,7 +20,7 @@ export async function collectMcpConfigs(scope = "project") {
19
20
  // compatibility surface; `.omk/mcp.json` is used only as a project fallback
20
21
  // when the `.kimi` companion does not exist.
21
22
  if (scope === "all") {
22
- for (const candidate of [globalOmkMcp, globalKimiMcp]) {
23
+ for (const candidate of [globalAgentMcp, globalOmkMcp, globalKimiMcp]) {
23
24
  if (await pathExists(candidate))
24
25
  configs.push(candidate);
25
26
  }
@@ -140,11 +140,23 @@ function normalizeRuntimeMcpServer(name, server) {
140
140
  }],
141
141
  };
142
142
  }
143
+ function normalizeRuntimeMcpEnv(env) {
144
+ if (Array.isArray(env)) {
145
+ return Object.fromEntries(env
146
+ .filter((key) => typeof key === "string" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
147
+ .map((key) => [key, `\${${key}}`]));
148
+ }
149
+ return isRecord(env) ? env : {};
150
+ }
143
151
  function prepareRuntimeMcpServer(server) {
144
- if (!isRecord(server) || typeof server.url === "string" || !isPackageManagerRuntimeServer(server)) {
152
+ if (!isRecord(server) || typeof server.url === "string") {
145
153
  return server;
146
154
  }
147
- const existingEnv = isRecord(server.env) ? server.env : {};
155
+ const existingEnv = normalizeRuntimeMcpEnv(server.env);
156
+ const hasEnvArray = Array.isArray(server.env);
157
+ if (!isPackageManagerRuntimeServer(server)) {
158
+ return hasEnvArray ? { ...server, env: existingEnv } : server;
159
+ }
148
160
  const env = { ...QUIET_PACKAGE_MANAGER_ENV, ...existingEnv };
149
161
  return { ...server, env };
150
162
  }
package/dist/util/i18n.js CHANGED
@@ -77,7 +77,7 @@ const en = {
77
77
  "cli.menuExit": "exit — Exit",
78
78
  "cli.menuUnavailable": "\n (Cannot display menu in this environment. Type a command below.)\n",
79
79
  "cli.unknownChoice": "Unknown choice: {0}, proceeding to chat.",
80
- "cli.description": "open-multi-agent-kit: multi-agent control plane for AI coding teams",
80
+ "cli.description": "omk: multi-agent control plane for AI coding teams",
81
81
  "cli.runIdOption": "run ID (resume / reference)",
82
82
  "cli.sudoOption": "Run shell commands with sudo (admin privileges)",
83
83
  // Command descriptions (cli.ts)
@@ -485,7 +485,7 @@ const ko = {
485
485
  "cli.menuExit": "exit — 종료",
486
486
  "cli.menuUnavailable": "\n (메뉴를 표시할 수 없는 환경입니다. 아래 명령어를 직접 입력하세요.)\n",
487
487
  "cli.unknownChoice": "알 수 없는 선택: {0}, chat으로 진행합니다.",
488
- "cli.description": "open-multi-agent-kit: AI 코딩 팀용 멀티 에이전트 컨트롤 플레인",
488
+ "cli.description": "omk: AI 코딩 팀용 멀티 에이전트 컨트롤 플레인",
489
489
  "cli.runIdOption": "run ID 지정 (resume / 참조)",
490
490
  "cli.sudoOption": "셸 명령어를 sudo로 실행 (관리자 권한)",
491
491
  // Command descriptions
@@ -12,6 +12,13 @@ export interface PasteScreenshotOptions {
12
12
  timeoutMs?: number;
13
13
  procVersion?: string;
14
14
  }
15
+ export interface ScreenshotCaptureCapability {
16
+ readonly name: string;
17
+ readonly supported: boolean;
18
+ readonly mode: "image" | "text" | "raw-key";
19
+ readonly note: string;
20
+ }
21
+ export declare function listScreenshotCaptureCapabilities(options?: PasteScreenshotOptions): ScreenshotCaptureCapability[];
15
22
  export declare function validateMagicBytes(buf: Buffer): {
16
23
  ok: boolean;
17
24
  ext: string;
@@ -14,6 +14,36 @@ export const SCREENSHOT_DIR = ".omk/screenshots";
14
14
  export const MAX_SIZE_BYTES = 20 * 1024 * 1024;
15
15
  const CLIPBOARD_TIMEOUT_MS = 5000;
16
16
  const CLIPBOARD_MAX_BUFFER_BYTES = MAX_SIZE_BYTES * 2;
17
+ export function listScreenshotCaptureCapabilities(options = {}) {
18
+ const platform = options.platform ?? process.platform;
19
+ const wsl = platform === "linux" && isWslEnvironment(options.env, options.procVersion);
20
+ return [
21
+ {
22
+ name: "windows-clipboard-image",
23
+ supported: platform === "win32" || wsl,
24
+ mode: "image",
25
+ note: "PowerShell STA bridge reads Snipping Tool / Ctrl+V image clipboard data.",
26
+ },
27
+ {
28
+ name: "macos-clipboard-image",
29
+ supported: platform === "darwin",
30
+ mode: "image",
31
+ note: "pngpaste or osascript reads image clipboard data.",
32
+ },
33
+ {
34
+ name: "linux-clipboard-image",
35
+ supported: platform === "linux",
36
+ mode: "image",
37
+ note: "wl-paste/xclip reads image clipboard data; WSL tries Windows first.",
38
+ },
39
+ {
40
+ name: "terminal-kit-ctrl-v-text",
41
+ supported: true,
42
+ mode: "raw-key",
43
+ note: "terminal-kit can capture Ctrl+V-style raw key/text clipboard hooks, not image screenshots.",
44
+ },
45
+ ];
46
+ }
17
47
  const IMAGE_MAGIC = new Map([
18
48
  ["png", [0x89, 0x50, 0x4e, 0x47]],
19
49
  ["jpg", [0xff, 0xd8, 0xff]],
@@ -0,0 +1,24 @@
1
+ export interface TerminalKitBridgeCapabilities {
2
+ readonly available: boolean;
3
+ readonly rawInput: boolean;
4
+ readonly ctrlVPasteKey: boolean;
5
+ readonly textClipboard: boolean;
6
+ readonly imageClipboard: false;
7
+ readonly windowsImageCapture: false;
8
+ readonly reason?: string;
9
+ }
10
+ export declare function getTerminalKitBridgeCapabilities(): TerminalKitBridgeCapabilities;
11
+ export declare function isTerminalKitPasteKey(key: string | undefined): boolean;
12
+ export declare function readTerminalKitClipboardText(source?: string): Promise<{
13
+ ok: true;
14
+ text: string;
15
+ } | {
16
+ ok: false;
17
+ error: string;
18
+ }>;
19
+ export declare function writeTerminalKitClipboardText(text: string, source?: string): Promise<{
20
+ ok: true;
21
+ } | {
22
+ ok: false;
23
+ error: string;
24
+ }>;
@@ -0,0 +1,60 @@
1
+ import { createRequire } from "node:module";
2
+ const require = createRequire(import.meta.url);
3
+ function loadTerminalKit() {
4
+ try {
5
+ return require("terminal-kit");
6
+ }
7
+ catch {
8
+ return undefined;
9
+ }
10
+ }
11
+ export function getTerminalKitBridgeCapabilities() {
12
+ const terminal = loadTerminalKit()?.terminal;
13
+ if (!terminal) {
14
+ return {
15
+ available: false,
16
+ rawInput: false,
17
+ ctrlVPasteKey: false,
18
+ textClipboard: false,
19
+ imageClipboard: false,
20
+ windowsImageCapture: false,
21
+ reason: "terminal-kit is not available",
22
+ };
23
+ }
24
+ return {
25
+ available: true,
26
+ rawInput: typeof terminal.grabInput === "function" && typeof terminal.on === "function",
27
+ ctrlVPasteKey: typeof terminal.grabInput === "function" && typeof terminal.on === "function",
28
+ textClipboard: typeof terminal.getClipboard === "function" && typeof terminal.setClipboard === "function",
29
+ imageClipboard: false,
30
+ windowsImageCapture: false,
31
+ reason: "terminal-kit supports raw key and text clipboard bridges; image/window capture remains OMK platform-specific",
32
+ };
33
+ }
34
+ export function isTerminalKitPasteKey(key) {
35
+ return key === "CTRL_V" || key === "META_P" || key === "CTRL_P";
36
+ }
37
+ export async function readTerminalKitClipboardText(source = "c") {
38
+ const terminal = loadTerminalKit()?.terminal;
39
+ if (!terminal?.getClipboard)
40
+ return { ok: false, error: "terminal-kit clipboard is unavailable" };
41
+ try {
42
+ const text = await terminal.getClipboard(source);
43
+ return { ok: true, text };
44
+ }
45
+ catch (err) {
46
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
47
+ }
48
+ }
49
+ export async function writeTerminalKitClipboardText(text, source = "c") {
50
+ const terminal = loadTerminalKit()?.terminal;
51
+ if (!terminal?.setClipboard)
52
+ return { ok: false, error: "terminal-kit clipboard is unavailable" };
53
+ try {
54
+ await terminal.setClipboard(text, source);
55
+ return { ok: true };
56
+ }
57
+ catch (err) {
58
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
59
+ }
60
+ }
@@ -15,5 +15,6 @@ export declare class TerminalOwner {
15
15
  get state(): TerminalOwnerState;
16
16
  claimReadline(): () => void;
17
17
  withChildProcess<T>(readline: ReadlineOwnerLike | undefined, fn: () => Promise<T>): Promise<T>;
18
+ withRawSelector<T>(readline: ReadlineOwnerLike | undefined, fn: () => Promise<T>): Promise<T>;
18
19
  private assertCanOwn;
19
20
  }
@@ -56,6 +56,37 @@ export class TerminalOwner {
56
56
  this.active = previous;
57
57
  }
58
58
  }
59
+ async withRawSelector(readline, fn) {
60
+ if (this.active !== "idle" && this.active !== "readline") {
61
+ throw new Error(`Terminal already owned by ${this.active}; cannot start raw selector`);
62
+ }
63
+ const previous = this.active;
64
+ this.active = "raw-selector";
65
+ try {
66
+ try {
67
+ readline?.pause();
68
+ }
69
+ catch {
70
+ // Piped input can close readline before queued work finishes.
71
+ }
72
+ try {
73
+ this.input.resume();
74
+ }
75
+ catch {
76
+ // Non-standard test streams may already be closed.
77
+ }
78
+ return await fn();
79
+ }
80
+ finally {
81
+ try {
82
+ readline?.resume();
83
+ }
84
+ catch {
85
+ // Readline may already be closed; ownership must still reset.
86
+ }
87
+ this.active = previous;
88
+ }
89
+ }
59
90
  assertCanOwn(next) {
60
91
  if (this.active !== "idle") {
61
92
  throw new Error(`Terminal already owned by ${this.active}; cannot start ${next}`);
package/dist/version.d.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  export declare const OMK_PACKAGE_NAME = "open-multi-agent-kit";
2
2
  export declare const OMK_RUNTIME_VERSION = "v1.2";
3
3
  export declare const OMK_CONTRACT_VERSION = "omk.contract.v1";
4
+ export declare const OMK_COMMAND_SCHEMA_VERSION = "omk.command.v1";
4
5
  export declare const OMK_EVIDENCE_SCHEMA_VERSION = "omk.evidence.v1";
6
+ export declare const OMK_EVIDENCE_BUNDLE_SCHEMA_VERSION = "omk.evidence-bundle.v1";
5
7
  export declare const OMK_DECISION_SCHEMA_VERSION = "omk.decision.v1";
6
8
  export declare const OMK_RUN_MANIFEST_SCHEMA_VERSION = "omk.run-manifest.v1";
7
9
  export declare const OMK_PROVIDER_SCHEMA_VERSION = "omk.provider.v1";
8
10
  export declare const OMK_VERSION_SCHEMA_VERSION = "omk.version.v1";
9
11
  export declare const OMK_PROOF_BUNDLE_SCHEMA_VERSION = "omk.proof-bundle.v1";
10
12
  export declare const OMK_RELEASE_CHANNEL = "pre-1.0";
11
- export declare const OMK_SCHEMA_VERSIONS: readonly ["omk.evidence.v1", "omk.decision.v1", "omk.run-manifest.v1", "omk.provider.v1", "omk.version.v1", "omk.proof-bundle.v1"];
13
+ export declare const OMK_SCHEMA_VERSIONS: readonly ["omk.command.v1", "omk.evidence.v1", "omk.evidence-bundle.v1", "omk.decision.v1", "omk.run-manifest.v1", "omk.provider.v1", "omk.version.v1", "omk.proof-bundle.v1"];
package/dist/version.js CHANGED
@@ -1,7 +1,9 @@
1
1
  export const OMK_PACKAGE_NAME = "open-multi-agent-kit";
2
2
  export const OMK_RUNTIME_VERSION = "v1.2";
3
3
  export const OMK_CONTRACT_VERSION = "omk.contract.v1";
4
+ export const OMK_COMMAND_SCHEMA_VERSION = "omk.command.v1";
4
5
  export const OMK_EVIDENCE_SCHEMA_VERSION = "omk.evidence.v1";
6
+ export const OMK_EVIDENCE_BUNDLE_SCHEMA_VERSION = "omk.evidence-bundle.v1";
5
7
  export const OMK_DECISION_SCHEMA_VERSION = "omk.decision.v1";
6
8
  export const OMK_RUN_MANIFEST_SCHEMA_VERSION = "omk.run-manifest.v1";
7
9
  export const OMK_PROVIDER_SCHEMA_VERSION = "omk.provider.v1";
@@ -9,7 +11,9 @@ export const OMK_VERSION_SCHEMA_VERSION = "omk.version.v1";
9
11
  export const OMK_PROOF_BUNDLE_SCHEMA_VERSION = "omk.proof-bundle.v1";
10
12
  export const OMK_RELEASE_CHANNEL = "pre-1.0";
11
13
  export const OMK_SCHEMA_VERSIONS = [
14
+ OMK_COMMAND_SCHEMA_VERSION,
12
15
  OMK_EVIDENCE_SCHEMA_VERSION,
16
+ OMK_EVIDENCE_BUNDLE_SCHEMA_VERSION,
13
17
  OMK_DECISION_SCHEMA_VERSION,
14
18
  OMK_RUN_MANIFEST_SCHEMA_VERSION,
15
19
  OMK_PROVIDER_SCHEMA_VERSION,
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Summary
4
4
 
5
- open-multi-agent-kit(OMK)의 현재 방향성은 **provider-neutral verified agent runtime**이다. Kimi 하나의 강한 adapter/provider lane일 뿐이며, OMK는 그 주변의 실행 제어면을 담당한다: DAG 실행, evidence gate, 로컬 그래프 메모리, MCP/skills/hooks 라우팅, provider fallback, run replay/inspect, HUD/cockpit 가시성, worktree 격리.
5
+ open-multi-agent-kit(OMK)의 현재 방향성은 **Kimi-native verified agent runtime**이다. Kimi 작성·병합·최종 판단 권한을 유지하고, OMK는 그 주변의 실행 제어면을 담당한다: DAG 실행, evidence gate, 로컬 그래프 메모리, MCP/skills/hooks 라우팅, provider fallback, run replay/inspect, HUD/cockpit 가시성, worktree 격리.
6
6
 
7
7
  핵심 문장:
8
8