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
@@ -25,15 +25,18 @@ import { buildNativeChatSlashCommands } from "./slash/commands/index.js";
25
25
  import { parseSlashInput } from "./slash/parser.js";
26
26
  import { createSlashCommandRegistry } from "./slash/registry.js";
27
27
  import { emitSlashResult, okSlashResult, printSlashResult, } from "./slash/result.js";
28
- async function runSlashHandler(handler, parsed, ctx) {
28
+ async function runSlashHandler(handler, parsed, ctx, options = {}) {
29
29
  const result = await handler.handler(ctx, parsed.args);
30
30
  const normalized = result ?? okSlashResult();
31
31
  if (normalized.statePatch)
32
32
  Object.assign(ctx.state, normalized.statePatch);
33
+ const visibleResult = options.suppressOutput
34
+ ? { ...normalized, text: undefined, json: undefined, events: [] }
35
+ : normalized;
33
36
  if (ctx.renderer)
34
- emitSlashResult(normalized, ctx.renderer);
37
+ emitSlashResult(visibleResult, ctx.renderer);
35
38
  else
36
- printSlashResult(normalized);
39
+ printSlashResult(visibleResult);
37
40
  return normalized;
38
41
  }
39
42
  function isModelSlashCommand(parsed) {
@@ -76,7 +79,112 @@ function explicitProviderTabFromModelLine(line, providerIds) {
76
79
  function isModelPickerLine(line, state) {
77
80
  const trimmed = line.trim();
78
81
  return /^\/(?:model|m)(?:\s|$)/.test(trimmed)
79
- || (state.modelPickerOpen === true && trimmed.length === 0);
82
+ || (state.modelPickerOpen === true && state.thinkingPickerOpen !== true && trimmed.length === 0);
83
+ }
84
+ function isThinkingPickerLine(line, state) {
85
+ const trimmed = line.trim();
86
+ return (state.thinkingPickerOpen === true && trimmed.length === 0)
87
+ || (state.modelPickerOpen !== true && trimmed.length === 0);
88
+ }
89
+ function isThinkingSlashCommand(parsed) {
90
+ return parsed.command === "/think" || parsed.command === "/thinking" || parsed.command === ":think";
91
+ }
92
+ function isThinkingShowSlash(parsed) {
93
+ return isThinkingSlashCommand(parsed)
94
+ && parsed.args.positional.length === 0
95
+ && parsed.args.flags.json !== true;
96
+ }
97
+ function isThinkingFollowupSlash(parsed) {
98
+ return parsed.command === "/model"
99
+ || parsed.command === "/m"
100
+ || parsed.command === "/use"
101
+ || parsed.command === ":use";
102
+ }
103
+ function shouldOpenThinkingPickerAfterSlash(parsed, result) {
104
+ if (!result.ok || !isThinkingFollowupSlash(parsed))
105
+ return false;
106
+ if (parsed.args.positional.length === 0)
107
+ return false;
108
+ if (result.statePatch?.thinking)
109
+ return false;
110
+ return Boolean(result.statePatch?.model || result.statePatch?.provider || result.statePatch?.bootstrap);
111
+ }
112
+ function renderThinkingPickerText(state) {
113
+ const levels = thinkingLevelsFor(state.provider, state.model);
114
+ const current = state.thinking;
115
+ const levelLine = levels
116
+ .map((level) => {
117
+ const label = `${level === current ? "●" : "○"} ${level}`;
118
+ if (level === current)
119
+ return style.mintBold(label);
120
+ if (level === "max" || level === "xhigh")
121
+ return style.cyanBold(label);
122
+ return style.gray(label);
123
+ })
124
+ .join(style.gray(" "));
125
+ const active = current
126
+ ? `${current} (${formatThinkingModelVariant(state.model, current)})`
127
+ : "not selected";
128
+ const firstLevel = levels[0] ?? "medium";
129
+ return [
130
+ style.phosphorBold("\n OMK Thinking Control · choose level"),
131
+ style.phosphorDim(` Target: ${state.provider ?? "auto"}/${state.model ?? "auto"}`),
132
+ ` ${levelLine}`,
133
+ style.phosphorDim(" Press Tab on an empty prompt to cycle, or run /think <level>."),
134
+ style.phosphorDim(` Shortcut: /model ${state.provider ?? "auto"}/${state.model ?? "auto"}:${firstLevel}`),
135
+ style.phosphorDim(` Active: ${active}\n`),
136
+ ].join("\n");
137
+ }
138
+ function canUseInteractiveThinkingSelector(input, renderer) {
139
+ if (renderer)
140
+ return false;
141
+ if (isDisabledEnvValue(input.env.OMK_INTERACTIVE_THINKING_SELECT))
142
+ return false;
143
+ return process.stdin.isTTY === true && process.stderr.isTTY === true;
144
+ }
145
+ function applyThinkingLevelToNativeState(input, state, level) {
146
+ state.thinking = level;
147
+ state.thinkingPickerOpen = true;
148
+ state.modelPickerOpen = false;
149
+ state.updatedAt = new Date().toISOString();
150
+ input.env.OMK_THINKING = level;
151
+ input.env.OMK_MODEL_VARIANT = formatThinkingModelVariant(state.model, level);
152
+ }
153
+ async function promptThinkingSelection(input, state, renderer) {
154
+ if (!canUseInteractiveThinkingSelector(input, renderer))
155
+ return false;
156
+ const levels = thinkingLevelsFor(state.provider, state.model);
157
+ if (levels.length === 0)
158
+ return false;
159
+ try {
160
+ const { select } = await import("@inquirer/prompts");
161
+ const selected = await select({
162
+ message: `Select thinking level for ${state.provider ?? "auto"}/${state.model ?? "auto"}`,
163
+ choices: levels.map((level) => ({
164
+ value: level,
165
+ name: `${level === state.thinking ? "● " : ""}${level}`,
166
+ description: formatThinkingModelVariant(state.model, level),
167
+ })),
168
+ pageSize: Math.min(levels.length, 8),
169
+ loop: true,
170
+ default: state.thinking ?? input.env.OMK_THINKING ?? levels[0],
171
+ }, {
172
+ input: process.stdin,
173
+ output: process.stderr,
174
+ clearPromptOnDone: true,
175
+ });
176
+ applyThinkingLevelToNativeState(input, state, selected);
177
+ process.stderr.write(style.phosphorDim(`\n Thinking variant: ${selected}\n Active: ${input.env.OMK_MODEL_VARIANT}\n`));
178
+ return true;
179
+ }
180
+ catch (err) {
181
+ const name = err instanceof Error ? err.name : "Error";
182
+ if (name === "ExitPromptError") {
183
+ process.stderr.write(style.phosphorDim("\n Thinking selection cancelled.\n"));
184
+ return true;
185
+ }
186
+ return false;
187
+ }
80
188
  }
81
189
  function countModelPickerRows(registry, activeProviderTab) {
82
190
  return registry
@@ -690,6 +798,7 @@ export async function runNativeOmkRootLoop(input) {
690
798
  root: input.root,
691
799
  cwd: input.activeCwd,
692
800
  rootSource: input.rootSource,
801
+ brandLabel: input.env.OMK_ENTRY_DISPLAY_NAME,
693
802
  });
694
803
  // opencode-style: banner handled by PlainModernRenderer session:start event
695
804
  const modelProviderRegistry = await readProviderRegistry({ env: input.env }).catch(() => []);
@@ -719,6 +828,13 @@ export async function runNativeOmkRootLoop(input) {
719
828
  else
720
829
  process.stdout.write(`${text}\n`);
721
830
  };
831
+ const renderThinkingPicker = () => {
832
+ const text = renderThinkingPickerText(state);
833
+ if (renderer)
834
+ renderer.emit({ type: "control:output", text });
835
+ else
836
+ process.stdout.write(`${text}\n`);
837
+ };
722
838
  // Defensive stdin re-validation before the chat readline takes ownership.
723
839
  // The first-run GitHub-star / update prompts (@inquirer/prompts) can take
724
840
  // over raw mode and leave the shared interactive stdin paused; a paused TTY
@@ -742,6 +858,7 @@ export async function runNativeOmkRootLoop(input) {
742
858
  explicitProviderTab,
743
859
  });
744
860
  state.modelPickerOpen = true;
861
+ state.thinkingPickerOpen = false;
745
862
  state.activeProviderTab = modelPickerState.activeProviderTab;
746
863
  modelPickerState.query = line;
747
864
  renderModelPicker(explicitProviderTab ? "/model explicit" : "/model");
@@ -752,24 +869,28 @@ export async function runNativeOmkRootLoop(input) {
752
869
  providerIds: modelProviderIds,
753
870
  })) {
754
871
  state.modelPickerOpen = true;
872
+ state.thinkingPickerOpen = false;
755
873
  state.activeProviderTab = modelPickerState.activeProviderTab;
756
874
  modelPickerState.query = line;
757
875
  renderModelPicker("\t", previousActiveProviderTab);
758
876
  }
759
877
  return [[], line];
760
878
  }
761
- if (line.trim().length === 0 || line.trimStart().startsWith("/think")) {
879
+ if (/^\/(?:think|thinking)\s*$/.test(line.trim()) && state.thinkingPickerOpen !== true) {
880
+ state.thinkingPickerOpen = true;
881
+ state.modelPickerOpen = false;
882
+ renderThinkingPicker();
883
+ return [[], line];
884
+ }
885
+ if (isThinkingPickerLine(line, state)) {
762
886
  const next = nextThinkingLevel(state.thinking ?? input.env.OMK_THINKING, state.provider, state.model);
763
887
  state.thinking = next;
888
+ state.thinkingPickerOpen = true;
889
+ state.modelPickerOpen = false;
764
890
  state.updatedAt = new Date().toISOString();
765
891
  input.env.OMK_THINKING = next;
766
892
  input.env.OMK_MODEL_VARIANT = formatThinkingModelVariant(state.model, next);
767
- const levels = thinkingLevelsFor(state.provider, state.model).join(" → ");
768
- const message = `\n Thinking: ${next} (${levels}) · ${input.env.OMK_MODEL_VARIANT}\n`;
769
- if (renderer)
770
- renderer.emit({ type: "control:output", text: style.phosphorDim(message) });
771
- else
772
- process.stdout.write(style.phosphorDim(message));
893
+ renderThinkingPicker();
773
894
  }
774
895
  return [[], line];
775
896
  },
@@ -882,6 +1003,7 @@ export async function runNativeOmkRootLoop(input) {
882
1003
  });
883
1004
  modelPickerState.query = "";
884
1005
  state.modelPickerOpen = true;
1006
+ state.thinkingPickerOpen = false;
885
1007
  state.activeProviderTab = modelPickerState.activeProviderTab;
886
1008
  const tabs = buildProviderTabs(modelProviderIds);
887
1009
  debugModelTabs({
@@ -899,8 +1021,12 @@ export async function runNativeOmkRootLoop(input) {
899
1021
  state.activeProviderTab = ALL_PROVIDER_TAB;
900
1022
  }
901
1023
  try {
1024
+ let slashResult;
1025
+ const thinkingShow = isThinkingShowSlash(parsedSlash);
1026
+ const interactiveThinkingSelector = canUseInteractiveThinkingSelector(input, renderer);
902
1027
  await terminalOwner.withChildProcess(rl, async () => {
903
- const result = await runSlashHandler(handler, parsedSlash, slashContext);
1028
+ const result = await runSlashHandler(handler, parsedSlash, slashContext, { suppressOutput: thinkingShow && interactiveThinkingSelector });
1029
+ slashResult = result;
904
1030
  if (parsedSlash.command === "/paste" && result.ok) {
905
1031
  const pasteLine = result.text?.trim();
906
1032
  if (pasteLine) {
@@ -912,8 +1038,28 @@ export async function runNativeOmkRootLoop(input) {
912
1038
  if (result.exit)
913
1039
  running = false;
914
1040
  });
915
- if (!modelShow && !isModelSlashCommand(parsedSlash)) {
1041
+ const shouldSelectThinking = slashResult
1042
+ ? (thinkingShow && interactiveThinkingSelector) || shouldOpenThinkingPickerAfterSlash(parsedSlash, slashResult)
1043
+ : false;
1044
+ if (shouldSelectThinking) {
1045
+ state.modelPickerOpen = false;
1046
+ state.thinkingPickerOpen = true;
1047
+ state.activeProviderTab = ALL_PROVIDER_TAB;
1048
+ const selected = await terminalOwner.withRawSelector(rl, () => promptThinkingSelection(input, state, renderer));
1049
+ if (!selected)
1050
+ renderThinkingPicker();
1051
+ }
1052
+ else if (isThinkingSlashCommand(parsedSlash)) {
1053
+ state.modelPickerOpen = false;
1054
+ state.thinkingPickerOpen = true;
1055
+ }
1056
+ else if (!modelShow && isThinkingFollowupSlash(parsedSlash)) {
1057
+ state.modelPickerOpen = false;
1058
+ state.thinkingPickerOpen = false;
1059
+ }
1060
+ else if (!modelShow && !isModelSlashCommand(parsedSlash)) {
916
1061
  state.modelPickerOpen = false;
1062
+ state.thinkingPickerOpen = false;
917
1063
  }
918
1064
  }
919
1065
  catch (err) {
@@ -930,6 +1076,8 @@ export async function runNativeOmkRootLoop(input) {
930
1076
  }
931
1077
  continue;
932
1078
  }
1079
+ state.modelPickerOpen = false;
1080
+ state.thinkingPickerOpen = false;
933
1081
  const message = `Unknown command: ${parsedSlash.command}. Type /help for commands.`;
934
1082
  if (renderer) {
935
1083
  renderer.emit({ type: "turn:error", message });
@@ -940,6 +1088,7 @@ export async function runNativeOmkRootLoop(input) {
940
1088
  continue;
941
1089
  }
942
1090
  state.modelPickerOpen = false;
1091
+ state.thinkingPickerOpen = false;
943
1092
  if (shouldRunNativeParallelTurn(state.approvalPolicy)) {
944
1093
  const turnStartedAt = Date.now();
945
1094
  try {
@@ -48,6 +48,8 @@ function buildBaseChatRuntimeEnv(root, sessionId) {
48
48
  const omkNames = [
49
49
  "OMK_AUTHORITY_PROVIDER",
50
50
  "OMK_CHAT_NO_BANNER",
51
+ "OMK_ENTRY_DISPLAY_NAME",
52
+ "OMK_ENTRY_SURFACE",
51
53
  "OMK_DEBUG",
52
54
  "OMK_DEFAULT_PROVIDER",
53
55
  "OMK_MCP_PREFLIGHT",
@@ -92,6 +94,13 @@ function attachSelectedProviderEnv(env, provider, source = process.env) {
92
94
  add("KIMI_MODEL");
93
95
  add("KIMI_BASE_URL");
94
96
  }
97
+ if (provider === "glm" || provider === "auto") {
98
+ add("BIGMODEL_API_KEY");
99
+ add("GLM_API_KEY");
100
+ add("GLM_MODEL");
101
+ add("GLM_BASE_URL");
102
+ add("BIGMODEL_BASE_URL");
103
+ }
95
104
  return next;
96
105
  }
97
106
  function formatRuntimeBootstrapFailure(bootstrap) {
@@ -152,7 +152,13 @@ export function buildRoutingSlashCommands() {
152
152
  ].join("\n"),
153
153
  });
154
154
  }
155
- const level = !requested || requested === "next" || requested === "tab"
155
+ if (!requested) {
156
+ return okSlashResult({
157
+ statePatch: { thinkingPickerOpen: true, updatedAt: new Date().toISOString() },
158
+ text: renderThinkingLevelList(ctx, levels),
159
+ });
160
+ }
161
+ const level = requested === "next" || requested === "tab"
156
162
  ? nextThinkingLevel(ctx.state.thinking ?? ctx.env.OMK_THINKING, ctx.state.provider, ctx.state.model)
157
163
  : normalizeThinkingLevel(requested);
158
164
  if (!level || !levels.includes(level)) {
@@ -202,6 +208,30 @@ export function buildRoutingSlashCommands() {
202
208
  },
203
209
  ];
204
210
  }
211
+ function renderThinkingLevelList(ctx, levels) {
212
+ const current = ctx.state.thinking ?? ctx.env.OMK_THINKING;
213
+ const levelLine = levels
214
+ .map((level) => {
215
+ const label = `${level === current ? "●" : "○"} ${level}`;
216
+ if (level === current)
217
+ return style.mintBold(label);
218
+ if (level === "max" || level === "xhigh")
219
+ return style.cyanBold(label);
220
+ return style.gray(label);
221
+ })
222
+ .join(style.gray(" "));
223
+ const active = current
224
+ ? `${current} (${formatThinkingModelVariant(ctx.state.model, current)})`
225
+ : "not selected";
226
+ return [
227
+ style.phosphorBold("\n OMK Thinking Control · choose level"),
228
+ style.phosphorDim(` Target: ${ctx.state.provider ?? "auto"}/${ctx.state.model ?? "auto"}`),
229
+ ` ${levelLine}`,
230
+ style.phosphorDim(` Choose directly: /think ${levels.join(" | /think ")}`),
231
+ style.phosphorDim(" Cycle only when explicit: /think next"),
232
+ style.phosphorDim(` Active: ${active}\n`),
233
+ ].join("\n");
234
+ }
205
235
  function modelRefFromParsed(parsed, raw) {
206
236
  return `${parsed.provider ? `${parsed.provider}/` : ""}${parsed.model ?? raw}`;
207
237
  }
@@ -55,10 +55,12 @@ export function resolveLayout(requested) {
55
55
  export function defaultChatUiForBrand(brand) {
56
56
  if (brand === "green-rain" || brand === "neon-grid" || brand === "rust-forge")
57
57
  return brand;
58
+ if (brand === undefined || brand === "omk")
59
+ return "neon-grid";
58
60
  return undefined;
59
61
  }
60
62
  export function resolveChatUi(requested, env = process.env) {
61
- const raw = requested ?? env.OMK_UI ?? env.OMK_CHAT_UI ?? "system24";
63
+ const raw = requested ?? env.OMK_UI ?? env.OMK_CHAT_UI ?? "neon-grid";
62
64
  const normalized = raw.trim().toLowerCase();
63
65
  if (normalized === "plain-modern" || normalized === "modern" || normalized === "agent-console")
64
66
  return "plain-modern";
@@ -325,7 +325,8 @@ export async function renderCockpit(options = {}) {
325
325
  let latestRunName = options.runId ?? null;
326
326
  let stateContent = null;
327
327
  let sessionMeta = null;
328
- if (await pathExists(runsDir)) {
328
+ const shouldLoadRunState = !quick || Boolean(latestRunName);
329
+ if (shouldLoadRunState && await pathExists(runsDir)) {
329
330
  if (!latestRunName) {
330
331
  const entries = await readdir(runsDir, { withFileTypes: true });
331
332
  const dirs = entries.filter((e) => e.isDirectory());
@@ -179,7 +179,7 @@ export async function runtimeChecks(resources) {
179
179
  });
180
180
  const currentVersion = getOmkVersionSync();
181
181
  try {
182
- const latest = execSync("npm view @omk/cli version", {
182
+ const latest = execSync("npm view open-multi-agent-kit version", {
183
183
  encoding: "utf-8",
184
184
  stdio: ["pipe", "pipe", "ignore"],
185
185
  timeout: 5000,
@@ -188,7 +188,7 @@ export async function runtimeChecks(resources) {
188
188
  results.push({
189
189
  name: "OMK Version",
190
190
  status: "warn",
191
- message: `${currentVersion} → ${latest} available. Run: npm i -g @omk/cli`,
191
+ message: `${currentVersion} → ${latest} available. Run: npm i -g open-multi-agent-kit`,
192
192
  });
193
193
  }
194
194
  else {
@@ -286,9 +286,9 @@ export async function initCommand(options) {
286
286
  console.log("");
287
287
  console.log(style.orange("⚠️ omk is not in PATH."));
288
288
  console.log(style.gray(" Run one of the following:"));
289
- console.log(style.gray(" 1) npm install -g @omk/cli"));
289
+ console.log(style.gray(" 1) npm install -g open-multi-agent-kit"));
290
290
  console.log(style.gray(" 2) npm link (for development)"));
291
- console.log(style.gray(" 3) alias omk='npx -p @omk/cli omk'"));
291
+ console.log(style.gray(" 3) alias omk='npx -p open-multi-agent-kit omk'"));
292
292
  }
293
293
  else {
294
294
  await maybeInstallShellCompletion(root);
@@ -2366,9 +2366,9 @@ export async function initCommand(options) {
2366
2366
  console.log("");
2367
2367
  console.log(style.orange("⚠️ omk is not in PATH."));
2368
2368
  console.log(style.gray(" Run one of the following:"));
2369
- console.log(style.gray(" 1) npm install -g @omk/cli"));
2369
+ console.log(style.gray(" 1) npm install -g open-multi-agent-kit"));
2370
2370
  console.log(style.gray(" 2) npm link (for development)"));
2371
- console.log(style.gray(" 3) alias omk='npx -p @omk/cli omk'"));
2371
+ console.log(style.gray(" 3) alias omk='npx -p open-multi-agent-kit omk'"));
2372
2372
  }
2373
2373
  else {
2374
2374
  await maybeInstallShellCompletion(root);
@@ -3,14 +3,19 @@ import { join } from "path";
3
3
  import { getProjectRoot, pathExists, getUserHome, STALE_PACKAGE_NAMES, } from "../../util/fs.js";
4
4
  import { style, header, status, label } from "../../util/theme.js";
5
5
  import { maskSensitiveText } from "../../util/secret-mask.js";
6
- import { formatArgsForDisplay, isHttpUrl, isSecretEnvName, loadConfig, RAILWAY_REMOTE_MCP_URL, sanitizeMcpServerForProject, sanitizeMcpUrlForDisplay, } from "./shared.js";
6
+ import { formatArgsForDisplay, isHttpUrl, isSecretEnvName, loadConfig, normalizeMcpServerName, RAILWAY_REMOTE_MCP_URL, sanitizeMcpServerForProject, sanitizeMcpUrlForDisplay, } from "./shared.js";
7
7
  export async function mcpRemoveCommand(serverName, options = {}) {
8
+ const normalizedServerName = normalizeMcpServerName(serverName);
8
9
  const root = getProjectRoot();
9
10
  const localPath = join(root, ".kimi", "mcp.json");
10
11
  const omkPath = join(root, ".omk", "mcp.json");
11
12
  const globalPath = join(getUserHome(), ".kimi", "mcp.json");
12
13
  const sources = options.global
13
- ? [{ path: globalPath, label: "global" }]
14
+ ? [
15
+ { path: join(getUserHome(), ".omk", "agent", "mcp.json"), label: "global-agent" },
16
+ { path: globalPath, label: "global" },
17
+ { path: join(getUserHome(), ".omk", "mcp.json"), label: "global-omk" },
18
+ ]
14
19
  : [
15
20
  { path: localPath, label: "project-local" },
16
21
  { path: omkPath, label: "omk-project" },
@@ -18,50 +23,67 @@ export async function mcpRemoveCommand(serverName, options = {}) {
18
23
  let removed = false;
19
24
  for (const src of sources) {
20
25
  const cfg = await loadConfig(src.path);
21
- if (!cfg.parsed || !cfg.config.mcpServers || !(serverName in cfg.config.mcpServers)) {
26
+ if (!cfg.parsed || !cfg.config.mcpServers || !(normalizedServerName in cfg.config.mcpServers)) {
22
27
  continue;
23
28
  }
24
29
  const next = { ...cfg.config.mcpServers };
25
- delete next[serverName];
30
+ delete next[normalizedServerName];
26
31
  await writeFile(src.path, JSON.stringify({ mcpServers: next }, null, 2) + "\n", "utf-8");
27
- console.log(status.ok(`Removed "${serverName}" from ${src.label} MCP config: ${src.path}`));
32
+ console.log(status.ok(`Removed "${normalizedServerName}" from ${src.label} MCP config: ${src.path}`));
28
33
  removed = true;
29
34
  break;
30
35
  }
31
36
  if (!removed) {
32
- console.log(status.error(`Server "${serverName}" not found in ${options.global ? "global" : "project-local"} MCP configs.`));
37
+ console.log(status.error(`Server "${normalizedServerName}" not found in ${options.global ? "global" : "project-local"} MCP configs.`));
33
38
  console.log(style.gray(`Checked: ${sources.map((s) => s.path).join(", ")}`));
34
39
  if (!options.global) {
35
- console.log(style.gray(`To remove from global config, run \`omk mcp remove ${serverName} --global\`, or edit ~/.kimi/mcp.json manually.`));
40
+ console.log(style.gray(`To remove from global config, run \`omk mcp remove ${normalizedServerName} --global\`, or edit ~/.kimi/mcp.json manually.`));
36
41
  }
37
42
  else {
38
- console.log(style.gray(`To remove from project-local configs, run \`omk mcp remove ${serverName}\`.`));
43
+ console.log(style.gray(`To remove from project-local configs, run \`omk mcp remove ${normalizedServerName}\`.`));
39
44
  }
40
45
  process.exit(1);
41
46
  }
42
47
  }
43
48
  export async function mcpAddCommand(serverName) {
49
+ const normalizedServerName = normalizeMcpServerName(serverName);
44
50
  const root = getProjectRoot();
45
- const globalPath = join(getUserHome(), ".kimi", "mcp.json");
51
+ const home = getUserHome();
52
+ const globalPaths = [
53
+ join(home, ".omk", "agent", "mcp.json"),
54
+ join(home, ".kimi", "mcp.json"),
55
+ join(home, ".omk", "mcp.json"),
56
+ ];
46
57
  const projectMcpPath = join(root, ".kimi", "mcp.json");
47
- const globalSource = await loadConfig(globalPath);
48
- if (!globalSource.parsed || !globalSource.config.mcpServers || !(serverName in globalSource.config.mcpServers)) {
49
- console.log(status.error(`Server "${serverName}" not found in global MCP config: ${globalPath}`));
58
+ let selected;
59
+ let selectedPath = "";
60
+ for (const globalPath of globalPaths) {
61
+ const globalSource = await loadConfig(globalPath);
62
+ if (globalSource.parsed && globalSource.config.mcpServers && normalizedServerName in globalSource.config.mcpServers) {
63
+ selected = globalSource.config.mcpServers[normalizedServerName];
64
+ selectedPath = globalPath;
65
+ break;
66
+ }
67
+ }
68
+ if (!selected) {
69
+ console.log(status.error(`Server "${normalizedServerName}" not found in trusted global MCP configs.`));
70
+ console.log(style.gray(`Checked: ${globalPaths.join(", ")}`));
50
71
  process.exit(1);
51
72
  }
52
73
  const projectMcpSource = await loadConfig(projectMcpPath);
53
74
  const projectMcpServers = projectMcpSource.parsed && projectMcpSource.config.mcpServers
54
75
  ? { ...projectMcpSource.config.mcpServers }
55
76
  : {};
56
- if (serverName in projectMcpServers) {
57
- console.log(status.error(`Server "${serverName}" already exists in ${projectMcpPath}`));
77
+ if (normalizedServerName in projectMcpServers) {
78
+ console.log(status.error(`Server "${normalizedServerName}" already exists in ${projectMcpPath}`));
58
79
  process.exit(1);
59
80
  }
60
- projectMcpServers[serverName] = sanitizeMcpServerForProject(globalSource.config.mcpServers[serverName]);
81
+ projectMcpServers[normalizedServerName] = sanitizeMcpServerForProject(selected);
61
82
  await mkdir(join(root, ".kimi"), { recursive: true });
62
83
  await writeFile(projectMcpPath, JSON.stringify({ mcpServers: projectMcpServers }, null, 2) + "\n", "utf-8");
63
84
  console.log(header("MCP Add"));
64
- console.log(status.ok(`Added "${serverName}" to ${projectMcpPath}`));
85
+ console.log(status.ok(`Added "${normalizedServerName}" to ${projectMcpPath}`));
86
+ console.log(label("Source", selectedPath));
65
87
  }
66
88
  export async function mcpInstallCommand(name, command, args, options = {}) {
67
89
  const root = getProjectRoot();
@@ -4,7 +4,7 @@ import { collectMcpConfigs, diagnoseRuntimeMcpServer, pathExists, getUserHome, p
4
4
  import { getOmkResourceSettings } from "../../util/resource-profile.js";
5
5
  import { style, header, status, label } from "../../util/theme.js";
6
6
  import { maskSensitiveText } from "../../util/secret-mask.js";
7
- import { basenameOfCommand, collectServers, isHttpUrl, isRailwayMcpServer, isSupabaseMcpServer, RAILWAY_REMOTE_MCP_URL, resolveAllConfigs, sanitizeMcpUrlForDisplay, selectEffectiveServer, serverTargetText, validateRemoteMcpUrl, } from "./shared.js";
7
+ import { basenameOfCommand, collectServers, isHttpUrl, isRailwayMcpServer, isSupabaseMcpServer, normalizeMcpEnv, RAILWAY_REMOTE_MCP_URL, resolveAllConfigs, sanitizeMcpUrlForDisplay, selectEffectiveServer, serverTargetText, validateRemoteMcpUrl, } from "./shared.js";
8
8
  import { repairMcpDoctorIssues } from "./doctor-fix.js";
9
9
  export async function mcpDoctorCommand(options = {}) {
10
10
  const fixes = options.fix
@@ -149,13 +149,12 @@ export async function buildMcpDoctorReport() {
149
149
  : { severity: "error", kind: "arg-path-not-found", message: `arg path not found: ${displayArg}` });
150
150
  }
151
151
  }
152
- if (server.env) {
153
- for (const [key, value] of Object.entries(server.env)) {
154
- if (value.startsWith("${") && value.endsWith("}")) {
155
- const envName = value.slice(2, -1);
156
- if (!process.env[envName]) {
157
- checks.push({ severity: "warn", kind: "env-reference-undefined", message: `env reference undefined: ${key} → ${envName}` });
158
- }
152
+ const env = normalizeMcpEnv(server.env);
153
+ for (const [key, value] of Object.entries(env)) {
154
+ if (value.startsWith("${") && value.endsWith("}")) {
155
+ const envName = value.slice(2, -1);
156
+ if (!process.env[envName]) {
157
+ checks.push({ severity: "warn", kind: "env-reference-undefined", message: `env reference undefined: ${key} → ${envName}` });
159
158
  }
160
159
  }
161
160
  }
@@ -2,7 +2,7 @@ import { collectMcpConfigs } from "../../util/fs.js";
2
2
  import { getOmkResourceSettings } from "../../util/resource-profile.js";
3
3
  import { style, header, bullet } from "../../util/theme.js";
4
4
  import { maskSensitiveText } from "../../util/secret-mask.js";
5
- import { collectServers, formatArgsForDisplay, resolveAllConfigs, sanitizeMcpUrlForDisplay, selectEffectiveServer, } from "./shared.js";
5
+ import { collectServers, formatArgsForDisplay, formatMcpEnvKeys, resolveAllConfigs, sanitizeMcpUrlForDisplay, selectEffectiveServer, } from "./shared.js";
6
6
  export async function mcpListCommand() {
7
7
  const sources = await resolveAllConfigs();
8
8
  const servers = collectServers(sources);
@@ -41,8 +41,9 @@ export async function mcpListCommand() {
41
41
  if (server.args && server.args.length > 0) {
42
42
  console.log(` ${style.gray("args:")} ${formatArgsForDisplay(server.args)}`);
43
43
  }
44
- if (server.env && Object.keys(server.env).length > 0) {
45
- console.log(` ${style.gray("env:")} ${Object.keys(server.env).join(", ")}`);
44
+ const envKeys = formatMcpEnvKeys(server.env);
45
+ if (envKeys.length > 0) {
46
+ console.log(` ${style.gray("env:")} ${envKeys.join(", ")}`);
46
47
  }
47
48
  console.log(` ${style.gray("from:")} ${info.sources.join(", ")}`);
48
49
  if (activeSources.length > 0) {
@@ -2,7 +2,7 @@ export interface McpServerConfig {
2
2
  url?: string;
3
3
  command?: string;
4
4
  args?: string[];
5
- env?: Record<string, string>;
5
+ env?: Record<string, string> | string[];
6
6
  headers?: Record<string, string>;
7
7
  http_headers?: Record<string, string>;
8
8
  startup_timeout_sec?: number;
@@ -25,6 +25,7 @@ export interface CollectedMcpServer {
25
25
  }
26
26
  export declare const RAILWAY_REMOTE_MCP_URL = "https://mcp.railway.com";
27
27
  export declare function loadConfig(filePath: string): Promise<ConfigSource>;
28
+ export declare function normalizeMcpServerName(name: string): string;
28
29
  export declare function resolveAllConfigs(): Promise<ConfigSource[]>;
29
30
  export declare function collectServers(sources: ConfigSource[]): Map<string, CollectedMcpServer>;
30
31
  export declare function selectEffectiveServer(info: CollectedMcpServer, activePathOrder: string[]): McpServerConfig;
@@ -41,6 +42,8 @@ export declare function serverTargetText(server: McpServerConfig): string;
41
42
  export declare function isRailwayMcpServer(name: string, server: McpServerConfig): boolean;
42
43
  export declare function isSupabaseMcpServer(name: string, server: McpServerConfig): boolean;
43
44
  export declare function formatArgsForDisplay(args: string[]): string;
45
+ export declare function normalizeMcpEnv(env: McpServerConfig["env"]): Record<string, string>;
46
+ export declare function formatMcpEnvKeys(env: McpServerConfig["env"]): string[];
44
47
  export declare function sanitizeMcpServerForProject(server: McpServerConfig): McpServerConfig;
45
48
  export declare function sanitizeMcpArgsForProject(args: string[]): string[];
46
49
  export declare function isHttpUrl(value: string): boolean;
@@ -17,13 +17,18 @@ export async function loadConfig(filePath) {
17
17
  return { path: filePath, config: {}, exists: true, parsed: false, error: `Invalid JSON: ${message}` };
18
18
  }
19
19
  }
20
+ export function normalizeMcpServerName(name) {
21
+ return name.trim().toLowerCase() === "adptorch" ? "adaptorch" : name;
22
+ }
20
23
  export async function resolveAllConfigs() {
21
24
  const root = getProjectRoot();
25
+ const home = getUserHome();
22
26
  const paths = [
23
27
  join(root, ".omk", "mcp.json"),
24
28
  join(root, ".kimi", "mcp.json"),
25
- join(getUserHome(), ".kimi", "mcp.json"),
26
- join(getUserHome(), ".omk", "mcp.json"),
29
+ join(home, ".omk", "agent", "mcp.json"),
30
+ join(home, ".kimi", "mcp.json"),
31
+ join(home, ".omk", "mcp.json"),
27
32
  ];
28
33
  const results = [];
29
34
  for (const p of paths) {
@@ -116,6 +121,19 @@ export function isSupabaseMcpServer(name, server) {
116
121
  export function formatArgsForDisplay(args) {
117
122
  return sanitizeMcpArgsForProject(args).join(" ");
118
123
  }
124
+ export function normalizeMcpEnv(env) {
125
+ if (!env)
126
+ return {};
127
+ if (Array.isArray(env)) {
128
+ return Object.fromEntries(env
129
+ .filter((key) => typeof key === "string" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
130
+ .map((key) => [key, `\${${key}}`]));
131
+ }
132
+ return env;
133
+ }
134
+ export function formatMcpEnvKeys(env) {
135
+ return Object.keys(normalizeMcpEnv(env));
136
+ }
119
137
  export function sanitizeMcpServerForProject(server) {
120
138
  const cleaned = JSON.parse(JSON.stringify(server));
121
139
  if (typeof cleaned.url === "string") {
@@ -129,7 +147,7 @@ export function sanitizeMcpServerForProject(server) {
129
147
  }
130
148
  if (cleaned.env && typeof cleaned.env === "object") {
131
149
  const env = {};
132
- for (const [key, value] of Object.entries(cleaned.env)) {
150
+ for (const [key, value] of Object.entries(normalizeMcpEnv(cleaned.env))) {
133
151
  env[key] = isSecretEnvName(key) ? `\${${key}}` : value;
134
152
  }
135
153
  cleaned.env = env;