micro-models-agent 0.56.5 → 0.57.1

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 (233) hide show
  1. package/CHANGELOG.md +481 -463
  2. package/README.md +358 -358
  3. package/dist/certification/certifications.json +493 -493
  4. package/dist/cli/commands.js +447 -0
  5. package/dist/cli/completer.js +167 -0
  6. package/dist/cli/index.js +2 -0
  7. package/dist/cli/main.js +153 -0
  8. package/dist/cli/plugin-commands.js +36 -0
  9. package/dist/cli/repl-commands.js +761 -0
  10. package/dist/cli/repl.js +702 -0
  11. package/dist/cli/run-result.js +33 -0
  12. package/dist/cli/security-commands.js +164 -0
  13. package/dist/cli/setup.js +237 -0
  14. package/dist/config/config.js +276 -0
  15. package/dist/config/defaults.js +141 -0
  16. package/dist/config/domains.js +179 -0
  17. package/dist/config/experts.js +15 -0
  18. package/dist/config/index.js +4 -0
  19. package/dist/config/security.js +213 -0
  20. package/dist/config/types.js +1 -0
  21. package/dist/core/agent-moe.js +102 -0
  22. package/dist/core/agent.js +1018 -0
  23. package/dist/core/bootstrap.js +481 -0
  24. package/dist/core/crash-handler.js +51 -0
  25. package/dist/core/environment.js +199 -0
  26. package/dist/core/index.js +2 -0
  27. package/dist/core/prompt-builder.js +76 -0
  28. package/dist/core/session-logger.js +251 -0
  29. package/dist/core/types.js +1 -0
  30. package/dist/core/version.js +26 -0
  31. package/dist/core/workspace.js +76 -0
  32. package/dist/i18n/en.json +679 -0
  33. package/dist/i18n/index.js +46 -0
  34. package/dist/i18n/ru.json +679 -0
  35. package/dist/index.js +22 -0
  36. package/dist/llm/image-utils.js +143 -0
  37. package/dist/llm/index.js +4 -0
  38. package/dist/llm/model-loader.js +78 -0
  39. package/dist/llm/openai-compat.js +497 -0
  40. package/dist/llm/orchestrator.js +200 -0
  41. package/dist/llm/provider.js +10 -0
  42. package/dist/llm/response.js +39 -0
  43. package/dist/llm/token-counter.js +39 -0
  44. package/dist/llm/types.js +1 -0
  45. package/dist/logger/app-logger.js +189 -0
  46. package/dist/logger/file-log.js +151 -0
  47. package/dist/logger/index.js +1 -0
  48. package/dist/main.js +457 -324
  49. package/dist/migration/backup.js +45 -0
  50. package/dist/migration/detect.js +50 -0
  51. package/dist/migration/index.js +2 -0
  52. package/dist/modules/artifacts/store.js +61 -0
  53. package/dist/modules/browser/actions.js +76 -0
  54. package/dist/modules/browser/bridge-client.js +199 -0
  55. package/dist/modules/browser/bridge-path.js +10 -0
  56. package/dist/modules/browser/bridge-server.mjs +219 -219
  57. package/dist/modules/browser/cookie-store.js +24 -0
  58. package/dist/modules/browser/driver.js +136 -0
  59. package/dist/modules/browser/index.js +7 -0
  60. package/dist/modules/browser/module.js +29 -0
  61. package/dist/modules/browser/session.js +342 -0
  62. package/dist/modules/browser/snapshot.js +148 -0
  63. package/dist/modules/browser/types.js +12 -0
  64. package/dist/modules/certification/cli.js +213 -0
  65. package/dist/modules/certification/fact-checker.js +82 -0
  66. package/dist/modules/certification/loader.js +106 -0
  67. package/dist/modules/certification/manifest.js +58 -0
  68. package/dist/modules/certification/runner.js +245 -0
  69. package/dist/modules/certification/scenarios.js +407 -0
  70. package/dist/modules/certification/types.js +1 -0
  71. package/dist/modules/context/chunk-query.js +100 -0
  72. package/dist/modules/context/fact-extractor.js +168 -0
  73. package/dist/modules/context/history.js +15 -0
  74. package/dist/modules/context/index.js +1 -0
  75. package/dist/modules/context/manager.js +440 -0
  76. package/dist/modules/execution/audit-runners.js +206 -0
  77. package/dist/modules/execution/auditor.js +218 -0
  78. package/dist/modules/execution/execution-plugin.js +431 -0
  79. package/dist/modules/execution/index.js +8 -0
  80. package/dist/modules/execution/module.js +625 -0
  81. package/dist/modules/execution/moe-executor.js +304 -0
  82. package/dist/modules/execution/plan-coverage.js +68 -0
  83. package/dist/modules/execution/plan-persister.js +46 -0
  84. package/dist/modules/execution/plan-store.js +196 -0
  85. package/dist/modules/execution/plan-tool.js +677 -0
  86. package/dist/modules/execution/plan-validator.js +153 -0
  87. package/dist/modules/execution/planner.js +94 -0
  88. package/dist/modules/execution/stuck-detector.js +746 -0
  89. package/dist/modules/execution/tracker.js +69 -0
  90. package/dist/modules/execution/types.js +1 -0
  91. package/dist/modules/execution/verifier.js +235 -0
  92. package/dist/modules/execution/windows-commands.js +41 -0
  93. package/dist/modules/hallucination/confidence.js +66 -0
  94. package/dist/modules/hallucination/consistency.js +26 -0
  95. package/dist/modules/hallucination/detector.js +47 -0
  96. package/dist/modules/hallucination/factual.js +169 -0
  97. package/dist/modules/hallucination/index.js +5 -0
  98. package/dist/modules/hallucination/js-identifiers.js +262 -0
  99. package/dist/modules/hallucination/llm-judge.js +101 -0
  100. package/dist/modules/index.js +5 -0
  101. package/dist/modules/indexer/cache.js +40 -0
  102. package/dist/modules/indexer/index.js +3 -0
  103. package/dist/modules/indexer/module.js +246 -0
  104. package/dist/modules/indexer/project-profile.js +183 -0
  105. package/dist/modules/indexer/walker.js +101 -0
  106. package/dist/modules/lsp/check-tool.js +58 -0
  107. package/dist/modules/lsp/client.js +389 -0
  108. package/dist/modules/lsp/command.js +60 -0
  109. package/dist/modules/lsp/config.js +135 -0
  110. package/dist/modules/lsp/index.js +3 -0
  111. package/dist/modules/lsp/module.js +260 -0
  112. package/dist/modules/lsp/probe.js +86 -0
  113. package/dist/modules/lsp/project-root.js +32 -0
  114. package/dist/modules/lsp/startup-check.js +144 -0
  115. package/dist/modules/lsp/types.js +1 -0
  116. package/dist/modules/mcp/client.js +399 -0
  117. package/dist/modules/mcp/index.js +3 -0
  118. package/dist/modules/mcp/module.js +142 -0
  119. package/dist/modules/mcp/registry.js +15 -0
  120. package/dist/modules/memory/index.js +1 -0
  121. package/dist/modules/memory/module.js +96 -0
  122. package/dist/modules/memory/search.js +42 -0
  123. package/dist/modules/memory/store.js +69 -0
  124. package/dist/modules/pipelines/engine.js +60 -0
  125. package/dist/modules/pipelines/index.js +3 -0
  126. package/dist/modules/pipelines/parser.js +56 -0
  127. package/dist/modules/pipelines/template.js +14 -0
  128. package/dist/modules/plugins/builtin/lint-on-write.js +334 -0
  129. package/dist/modules/plugins/builtin/notify.js +9 -0
  130. package/dist/modules/plugins/index.js +1 -0
  131. package/dist/modules/plugins/loader.js +70 -0
  132. package/dist/modules/plugins/manager.js +261 -0
  133. package/dist/modules/plugins/types.js +1 -0
  134. package/dist/modules/pricing/index.js +61 -0
  135. package/dist/modules/pricing/prices.js +129 -0
  136. package/dist/modules/processes/detect.js +34 -0
  137. package/dist/modules/processes/index.js +2 -0
  138. package/dist/modules/processes/registry.js +327 -0
  139. package/dist/modules/processes/runner.js +23 -0
  140. package/dist/modules/providers/create.js +22 -0
  141. package/dist/modules/providers/fallback.js +79 -0
  142. package/dist/modules/providers/health.js +46 -0
  143. package/dist/modules/providers/index.js +5 -0
  144. package/dist/modules/providers/manager.js +161 -0
  145. package/dist/modules/providers/presets.js +128 -0
  146. package/dist/modules/providers/registry.js +22 -0
  147. package/dist/modules/providers/types.js +1 -0
  148. package/dist/modules/registry.js +48 -0
  149. package/dist/modules/security/audit-log.js +136 -0
  150. package/dist/modules/security/audit-notifier.js +292 -0
  151. package/dist/modules/security/command-validator.js +219 -0
  152. package/dist/modules/security/content-scanner.js +53 -0
  153. package/dist/modules/security/data-sanitizer.js +89 -0
  154. package/dist/modules/security/encryption.js +242 -0
  155. package/dist/modules/security/index.js +14 -0
  156. package/dist/modules/security/network-validator.js +88 -0
  157. package/dist/modules/security/path-validator.js +203 -0
  158. package/dist/modules/security/rate-limiter.js +119 -0
  159. package/dist/modules/security/security-policies.js +531 -0
  160. package/dist/modules/security/session-encryption.js +210 -0
  161. package/dist/modules/security/session-isolation.js +95 -0
  162. package/dist/modules/session/index.js +3 -0
  163. package/dist/modules/session/manager.js +172 -0
  164. package/dist/modules/session/module.js +24 -0
  165. package/dist/modules/session/store.js +222 -0
  166. package/dist/modules/session/types.js +1 -0
  167. package/dist/modules/skills/index.js +2 -0
  168. package/dist/modules/skills/loader.js +72 -0
  169. package/dist/modules/skills/matcher.js +27 -0
  170. package/dist/modules/skills/module.js +129 -0
  171. package/dist/modules/types.js +1 -0
  172. package/dist/modules/updater/checker.js +96 -0
  173. package/dist/modules/updater/index.js +2 -0
  174. package/dist/modules/updater/module.js +116 -0
  175. package/dist/modules/user-profile/compressor.js +16 -0
  176. package/dist/modules/user-profile/index.js +1 -0
  177. package/dist/modules/user-profile/profile.js +68 -0
  178. package/dist/skills/builtin/git.md +36 -36
  179. package/dist/skills/builtin/typescript.md +35 -35
  180. package/dist/tools/approve.js +33 -0
  181. package/dist/tools/attach-image.js +101 -0
  182. package/dist/tools/bash.js +519 -0
  183. package/dist/tools/browser.js +115 -0
  184. package/dist/tools/chunk-query.js +100 -0
  185. package/dist/tools/create-dir.js +56 -0
  186. package/dist/tools/delete-file.js +63 -0
  187. package/dist/tools/download-file.js +117 -0
  188. package/dist/tools/edit-file.js +80 -0
  189. package/dist/tools/enable-tools.js +59 -0
  190. package/dist/tools/executor.js +154 -0
  191. package/dist/tools/file-info.js +47 -0
  192. package/dist/tools/filter-tools.js +17 -0
  193. package/dist/tools/glob-tool.js +27 -0
  194. package/dist/tools/grep-tool.js +125 -0
  195. package/dist/tools/hidden-tools-block.js +37 -0
  196. package/dist/tools/index.js +78 -0
  197. package/dist/tools/list-dir.js +49 -0
  198. package/dist/tools/load-skill.js +43 -0
  199. package/dist/tools/mcp-call.js +69 -0
  200. package/dist/tools/move-file.js +86 -0
  201. package/dist/tools/path-utils.js +101 -0
  202. package/dist/tools/pipeline-run.js +145 -0
  203. package/dist/tools/preview.js +2 -0
  204. package/dist/tools/process-kill.js +40 -0
  205. package/dist/tools/process-list.js +37 -0
  206. package/dist/tools/process-log.js +54 -0
  207. package/dist/tools/question.js +141 -0
  208. package/dist/tools/read-file.js +179 -0
  209. package/dist/tools/recall.js +118 -0
  210. package/dist/tools/registry.js +47 -0
  211. package/dist/tools/remember.js +68 -0
  212. package/dist/tools/scope-check.js +32 -0
  213. package/dist/tools/search-history.js +85 -0
  214. package/dist/tools/subagent.js +196 -0
  215. package/dist/tools/types.js +1 -0
  216. package/dist/tools/user-input.js +123 -0
  217. package/dist/tools/web-browse.js +87 -0
  218. package/dist/tools/web-fetch.js +119 -0
  219. package/dist/tools/web-search.js +105 -0
  220. package/dist/tools/write-file.js +82 -0
  221. package/dist/ui/box.js +77 -0
  222. package/dist/ui/colors.js +4 -0
  223. package/dist/ui/diff.js +178 -0
  224. package/dist/ui/index.js +6 -0
  225. package/dist/ui/line-editor.js +822 -0
  226. package/dist/ui/line-math.js +73 -0
  227. package/dist/ui/md-formatter.js +212 -0
  228. package/dist/ui/output.js +13 -0
  229. package/dist/ui/plan-view.js +103 -0
  230. package/dist/ui/renderer.js +259 -0
  231. package/dist/ui/spinner.js +70 -0
  232. package/dist/ui/table.js +144 -0
  233. package/package.json +51 -51
package/dist/main.js CHANGED
@@ -2329,7 +2329,7 @@ var init_defaults = __esm(() => {
2329
2329
  maxToolIterations: 1000,
2330
2330
  stuckThreshold: 6,
2331
2331
  autoPlan: true,
2332
- showReasoning: false,
2332
+ showReasoning: true,
2333
2333
  logLevel: "info",
2334
2334
  locale: "en",
2335
2335
  session: {
@@ -2365,8 +2365,6 @@ var init_defaults = __esm(() => {
2365
2365
  },
2366
2366
  ui: {
2367
2367
  spinner: true,
2368
- toolStyle: "inline",
2369
- toolComments: true,
2370
2368
  showContextStats: false,
2371
2369
  showCompaction: true
2372
2370
  },
@@ -2401,8 +2399,8 @@ var init_defaults = __esm(() => {
2401
2399
  lsp: DEFAULT_LSP_CONFIG,
2402
2400
  updater: {
2403
2401
  enabled: true,
2404
- checkOnStart: true,
2405
- autoInstall: true,
2402
+ checkOnStart: false,
2403
+ autoInstall: false,
2406
2404
  intervalMs: 0
2407
2405
  },
2408
2406
  reasoning: {
@@ -2533,6 +2531,7 @@ The path was joined onto the working directory because it does not exist as give
2533
2531
  "tool.friendly.web_fetch": "Fetching page",
2534
2532
  "tool.friendly.web_browse": "Browsing page",
2535
2533
  "tool.friendly.download_file": "Downloading file",
2534
+ "tool.friendly.chunk_query": "Querying chunks",
2536
2535
  "tool.web_fetch_result": "Fetched page: {url} — {chars} chars, {lines} lines{truncated}",
2537
2536
  "tool.web_browse_result": "Browsed page: {url} — {chars} chars, {lines} lines{truncated}",
2538
2537
  "tool.web_search_result": 'Search results for "{query}" — {count} results',
@@ -3297,6 +3296,7 @@ var init_ru = __esm(() => {
3297
3296
  "tool.friendly.web_fetch": "Загрузка страницы",
3298
3297
  "tool.friendly.web_browse": "Просмотр страницы",
3299
3298
  "tool.friendly.download_file": "Скачивание файла",
3299
+ "tool.friendly.chunk_query": "Запрос чанков",
3300
3300
  "tool.web_fetch_result": "Загружена страница: {url} — {chars} симв., {lines} строк{truncated}",
3301
3301
  "tool.web_browse_result": "Просмотрена страница: {url} — {chars} симв., {lines} строк{truncated}",
3302
3302
  "tool.web_search_result": 'Результаты поиска "{query}" — {count} результатов',
@@ -13453,18 +13453,6 @@ function evaluateReasoningPolicy(input, state) {
13453
13453
  var DECAY_THRESHOLD = 5;
13454
13454
 
13455
13455
  // src/core/agent.ts
13456
- function isToolCallJson(text) {
13457
- const trimmed = text.trim();
13458
- if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
13459
- try {
13460
- JSON.parse(trimmed);
13461
- return true;
13462
- } catch {
13463
- return false;
13464
- }
13465
- }
13466
- return false;
13467
- }
13468
13456
  function toolOutputCharLimit(remainingBudget, historyBudget, bounded) {
13469
13457
  if (bounded)
13470
13458
  return Number.MAX_SAFE_INTEGER;
@@ -13687,6 +13675,10 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
13687
13675
  onPhase,
13688
13676
  signal: this.abortController.signal
13689
13677
  }) : await this.executeSingleAgentLoop(input, onChunk, onMeta, countTool, onPhase);
13678
+ const provenance = this.callerProvenance();
13679
+ result.provider = provenance.provider;
13680
+ result.model = provenance.model;
13681
+ result.durationMs = Date.now() - startedAt;
13690
13682
  emitTurnEnd(result);
13691
13683
  return result;
13692
13684
  } catch (err) {
@@ -13730,6 +13722,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
13730
13722
  let emptyResponseExhausted = false;
13731
13723
  let auditFailed = false;
13732
13724
  let lastAuditSummary = "";
13725
+ let totalLlmDuration = 0;
13733
13726
  let suppressRepetitionRetry = false;
13734
13727
  let repeatedToolCount = 0;
13735
13728
  const MAX_REPEATED_TOOL_CALLS = 2;
@@ -13868,6 +13861,8 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
13868
13861
  }
13869
13862
  textContent += chunk.content;
13870
13863
  textChunks.push(chunk.content);
13864
+ const textOut = pluginManager.runOnText({ iteration, logger, contextManager }, chunk.content);
13865
+ onChunk?.(textOut);
13871
13866
  }
13872
13867
  if (chunk.type === "reasoning" && chunk.content) {
13873
13868
  reasoningContent += chunk.content;
@@ -13930,6 +13925,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
13930
13925
  }
13931
13926
  apiCompletionChars += (textContent || reasoningContent).length;
13932
13927
  logger.logLLMResponse(config.model, (textContent || reasoningContent).length, Date.now() - llmStart, undefined, "agent");
13928
+ totalLlmDuration += Date.now() - llmStart;
13933
13929
  {
13934
13930
  const usagePrompt = apiPromptTokens - promptBefore;
13935
13931
  const usageCompletion = apiCompletionTokens - completionBefore;
@@ -13948,14 +13944,6 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
13948
13944
  if (this.shutdownRequested) {
13949
13945
  break;
13950
13946
  }
13951
- const toolComments = this.deps.config.ui?.toolComments ?? true;
13952
- const showText = textChunks.length > 0 && (!sawToolCall || toolComments && !isToolCallJson(textContent));
13953
- if (showText) {
13954
- for (const chunk of textChunks) {
13955
- const textOut = pluginManager.runOnText({ iteration, logger, contextManager }, chunk);
13956
- onChunk?.(textOut);
13957
- }
13958
- }
13959
13947
  let llmResponse = null;
13960
13948
  if (sawToolCall) {
13961
13949
  llmResponse = { type: "tool_call", calls: toolCalls };
@@ -14349,7 +14337,8 @@ ${warnLine}
14349
14337
  totalCost: this.costTracker.total,
14350
14338
  costBreakdown: this.costTracker.breakdown(),
14351
14339
  compactionCount: contextManager.getCompactionCount(),
14352
- contextQuality: contextManager.getQuality()
14340
+ contextQuality: contextManager.getQuality(),
14341
+ llmDurationMs: totalLlmDuration
14353
14342
  };
14354
14343
  }
14355
14344
  clearContext() {
@@ -16957,22 +16946,29 @@ class MCPClient {
16957
16946
  if (!url)
16958
16947
  throw new Error("SSE transport requires a url");
16959
16948
  this.abortController = new AbortController;
16960
- const response = await fetch(url, {
16961
- method: "GET",
16962
- headers: {
16963
- Accept: "text/event-stream",
16964
- ...this.config.headers
16965
- },
16966
- signal: this.abortController.signal
16967
- });
16968
- if (!response.ok) {
16969
- throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);
16949
+ const timeout = setTimeout(() => this.abortController?.abort(), this.config.timeout || HTTP_TIMEOUT_MS);
16950
+ try {
16951
+ const response = await fetch(url, {
16952
+ method: "GET",
16953
+ headers: {
16954
+ Accept: "text/event-stream",
16955
+ ...this.config.headers
16956
+ },
16957
+ signal: this.abortController.signal
16958
+ });
16959
+ clearTimeout(timeout);
16960
+ if (!response.ok) {
16961
+ throw new Error(`SSE connection failed: ${response.status} ${response.statusText}`);
16962
+ }
16963
+ this._connected = true;
16964
+ const reader = response.body.getReader();
16965
+ const decoder = new TextDecoder;
16966
+ let buffer = "";
16967
+ this.readSSE(reader, decoder, buffer);
16968
+ } catch (err) {
16969
+ clearTimeout(timeout);
16970
+ throw err;
16970
16971
  }
16971
- this._connected = true;
16972
- const reader = response.body.getReader();
16973
- const decoder = new TextDecoder;
16974
- let buffer = "";
16975
- this.readSSE(reader, decoder, buffer);
16976
16972
  }
16977
16973
  async readSSE(reader, decoder, buffer) {
16978
16974
  try {
@@ -17166,7 +17162,8 @@ class MCPClient {
17166
17162
  "Content-Type": "application/json",
17167
17163
  ...this.config.headers
17168
17164
  },
17169
- body: JSON.stringify(request)
17165
+ body: JSON.stringify(request),
17166
+ signal: AbortSignal.timeout(this.config.timeout || HTTP_TIMEOUT_MS)
17170
17167
  });
17171
17168
  if (!response.ok) {
17172
17169
  const text = await response.text().catch(() => "");
@@ -17252,7 +17249,8 @@ class MCPClient {
17252
17249
  "Content-Type": "application/json",
17253
17250
  ...this.config.headers
17254
17251
  },
17255
- body: JSON.stringify(request)
17252
+ body: JSON.stringify(request),
17253
+ signal: AbortSignal.timeout(this.config.timeout || HTTP_TIMEOUT_MS)
17256
17254
  });
17257
17255
  if (!response.ok) {
17258
17256
  const text = await response.text().catch(() => "");
@@ -17329,6 +17327,7 @@ class MCPClient {
17329
17327
  });
17330
17328
  }
17331
17329
  }
17330
+ var HTTP_TIMEOUT_MS = 1e4;
17332
17331
  var init_client = () => {};
17333
17332
 
17334
17333
  // src/modules/mcp/registry.ts
@@ -23982,9 +23981,11 @@ class MCPModule {
23982
23981
  config;
23983
23982
  name = "mcp";
23984
23983
  connections = new Map;
23984
+ serverConfigs = new Map;
23985
23985
  discovered = [];
23986
23986
  initialized = false;
23987
23987
  initError = null;
23988
+ failedServers = new Set;
23988
23989
  constructor(config) {
23989
23990
  this.config = config;
23990
23991
  }
@@ -24011,13 +24012,58 @@ class MCPModule {
24011
24012
  registry2.register(serverConfig);
24012
24013
  }
24013
24014
  for (const serverName of registry2.list()) {
24014
- const serverConfig = registry2.get(serverName);
24015
+ this.serverConfigs.set(serverName, registry2.get(serverName));
24016
+ }
24017
+ this.discoverAllTools();
24018
+ }
24019
+ async discoverAllTools() {
24020
+ for (const [serverName, serverConfig] of this.serverConfigs) {
24021
+ if (this.failedServers.has(serverName))
24022
+ continue;
24015
24023
  const client = new MCPClient(serverConfig);
24016
24024
  try {
24017
- await client.connect();
24018
- const tools = await client.listTools();
24019
- this.connections.set(serverName, client);
24020
- for (const tool of tools) {
24025
+ await Promise.race([
24026
+ (async () => {
24027
+ await client.connect();
24028
+ const tools = await client.listTools();
24029
+ this.connections.set(serverName, client);
24030
+ for (const tool of tools) {
24031
+ this.discovered.push({
24032
+ serverName,
24033
+ toolName: tool.name,
24034
+ description: tool.description || `Tool on MCP server "${serverName}"`,
24035
+ inputSchema: tool.inputSchema || {}
24036
+ });
24037
+ }
24038
+ })(),
24039
+ new Promise((_, reject) => setTimeout(() => reject(new Error("discovery timeout")), DISCOVERY_TIMEOUT_MS))
24040
+ ]);
24041
+ } catch (e) {
24042
+ this.failedServers.add(serverName);
24043
+ this.initError = `MCP server "${serverName}" init failed: ${e.message}`;
24044
+ await client.disconnect().catch((err) => {
24045
+ logger3.warn(`cleanup disconnect for "${serverName}" failed`, { error: String(err) });
24046
+ });
24047
+ }
24048
+ }
24049
+ }
24050
+ async ensureConnected(serverName) {
24051
+ const existing = this.connections.get(serverName);
24052
+ if (existing?.isConnected())
24053
+ return existing;
24054
+ if (this.failedServers.has(serverName))
24055
+ return null;
24056
+ const serverConfig = this.serverConfigs.get(serverName);
24057
+ if (!serverConfig)
24058
+ return null;
24059
+ const client = new MCPClient(serverConfig);
24060
+ try {
24061
+ await client.connect();
24062
+ const tools = await client.listTools();
24063
+ this.connections.set(serverName, client);
24064
+ for (const tool of tools) {
24065
+ const alreadyDiscovered = this.discovered.some((d) => d.serverName === serverName && d.toolName === tool.name);
24066
+ if (!alreadyDiscovered) {
24021
24067
  this.discovered.push({
24022
24068
  serverName,
24023
24069
  toolName: tool.name,
@@ -24025,16 +24071,18 @@ class MCPModule {
24025
24071
  inputSchema: tool.inputSchema || {}
24026
24072
  });
24027
24073
  }
24028
- } catch (e) {
24029
- this.initError = `MCP server "${serverName}" init failed: ${e.message}`;
24030
- await client.disconnect().catch((err) => {
24031
- logger3.warn(`cleanup disconnect for "${serverName}" failed`, { error: String(err) });
24032
- });
24033
24074
  }
24075
+ return client;
24076
+ } catch (e) {
24077
+ this.failedServers.add(serverName);
24078
+ logger3.warn(`MCP connect failed for "${serverName}": ${e.message}`);
24079
+ await client.disconnect().catch(() => {});
24080
+ return null;
24034
24081
  }
24035
24082
  }
24036
24083
  getSystemPromptBlock() {
24037
- if (this.discovered.length === 0)
24084
+ const serverNames = [...this.serverConfigs.keys()];
24085
+ if (serverNames.length === 0)
24038
24086
  return null;
24039
24087
  const lines = ["---", "MCP servers available:"];
24040
24088
  const byServer = new Map;
@@ -24043,11 +24091,16 @@ class MCPModule {
24043
24091
  list.push(d);
24044
24092
  byServer.set(d.serverName, list);
24045
24093
  }
24046
- for (const [server, tools] of byServer) {
24047
- lines.push(` [${server}]`);
24048
- for (const t2 of tools) {
24049
- const toolRef = sanitizeToolName(server, t2.toolName);
24050
- lines.push(` - ${toolRef}: ${t2.description}`);
24094
+ for (const serverName of serverNames) {
24095
+ lines.push(` [${serverName}]`);
24096
+ const tools = byServer.get(serverName);
24097
+ if (tools && tools.length > 0) {
24098
+ for (const t2 of tools) {
24099
+ const toolRef = sanitizeToolName(serverName, t2.toolName);
24100
+ lines.push(` - ${toolRef}: ${t2.description}`);
24101
+ }
24102
+ } else {
24103
+ lines.push(` (not yet connected — use mcp__${serverName}__connect to discover tools)`);
24051
24104
  }
24052
24105
  }
24053
24106
  lines.push("---");
@@ -24060,33 +24113,60 @@ class MCPModule {
24060
24113
  };
24061
24114
  }
24062
24115
  getToolDefinitions() {
24063
- return this.discovered.map((d) => ({
24064
- name: sanitizeToolName(d.serverName, d.toolName),
24065
- description: `${d.description} [MCP server: ${d.serverName}]`,
24066
- parameters: convertInputSchema(d.inputSchema),
24067
- tags: ["code", "research"],
24068
- handler: async (_ctx, args) => {
24069
- const client = this.connections.get(d.serverName);
24070
- if (!client) {
24071
- return {
24072
- success: false,
24073
- output: `MCP server "${d.serverName}" not connected`
24074
- };
24116
+ const defs = [];
24117
+ for (const d of this.discovered) {
24118
+ defs.push({
24119
+ name: sanitizeToolName(d.serverName, d.toolName),
24120
+ description: `${d.description} [MCP server: ${d.serverName}]`,
24121
+ parameters: convertInputSchema(d.inputSchema),
24122
+ tags: ["code", "research"],
24123
+ handler: async (_ctx, args) => {
24124
+ const client = this.connections.get(d.serverName);
24125
+ if (!client?.isConnected()) {
24126
+ return {
24127
+ success: false,
24128
+ output: `MCP server "${d.serverName}" not connected`
24129
+ };
24130
+ }
24131
+ try {
24132
+ const result = await client.callTool(d.toolName, args);
24133
+ return {
24134
+ success: true,
24135
+ output: typeof result === "string" ? result : JSON.stringify(result, null, 2)
24136
+ };
24137
+ } catch (e) {
24138
+ return { success: false, output: `MCP call failed: ${e.message}` };
24139
+ }
24075
24140
  }
24076
- try {
24077
- if (!client.isConnected()) {
24078
- await client.connect();
24141
+ });
24142
+ }
24143
+ for (const [serverName] of this.serverConfigs) {
24144
+ if (this.failedServers.has(serverName))
24145
+ continue;
24146
+ const alreadyDiscovered = this.discovered.some((d) => d.serverName === serverName);
24147
+ if (alreadyDiscovered)
24148
+ continue;
24149
+ defs.push({
24150
+ name: sanitizeToolName(serverName, "connect"),
24151
+ description: `Connect to MCP server "${serverName}" and discover its tools`,
24152
+ parameters: { type: "object", properties: {} },
24153
+ tags: ["code", "research"],
24154
+ handler: async (_ctx, _args) => {
24155
+ const client = await this.ensureConnected(serverName);
24156
+ if (!client) {
24157
+ return { success: false, output: `MCP server "${serverName}" connection failed` };
24079
24158
  }
24080
- const result = await client.callTool(d.toolName, args);
24159
+ const tools = this.discovered.filter((d) => d.serverName === serverName).map((d) => ` - ${sanitizeToolName(serverName, d.toolName)}: ${d.description}`);
24081
24160
  return {
24082
24161
  success: true,
24083
- output: typeof result === "string" ? result : JSON.stringify(result, null, 2)
24162
+ output: tools.length > 0 ? `Connected to "${serverName}". Tools:
24163
+ ${tools.join(`
24164
+ `)}` : `Connected to "${serverName}" (no tools discovered)`
24084
24165
  };
24085
- } catch (e) {
24086
- return { success: false, output: `MCP call failed: ${e.message}` };
24087
24166
  }
24088
- }
24089
- }));
24167
+ });
24168
+ }
24169
+ return defs;
24090
24170
  }
24091
24171
  getPlugin() {
24092
24172
  return {
@@ -24104,7 +24184,7 @@ class MCPModule {
24104
24184
  };
24105
24185
  }
24106
24186
  }
24107
- var logger3;
24187
+ var logger3, DISCOVERY_TIMEOUT_MS = 5000;
24108
24188
  var init_module7 = __esm(() => {
24109
24189
  init_client();
24110
24190
  init_app_logger();
@@ -24584,6 +24664,12 @@ __export(exports_probe, {
24584
24664
  getCachedProbeResult: () => getCachedProbeResult,
24585
24665
  cacheKey: () => cacheKey
24586
24666
  });
24667
+ import { existsSync as existsSync50, readFileSync as readFileSync31, writeFileSync as writeFileSync19, mkdirSync as mkdirSync20 } from "fs";
24668
+ import { join as join42, dirname as dirname18 } from "path";
24669
+ import { homedir as homedir14 } from "os";
24670
+ function cachePath() {
24671
+ return join42(homedir14(), ".mma", "reasoning-cache.json");
24672
+ }
24587
24673
  async function probeReasoningSupport(provider, strategy, signal) {
24588
24674
  if (strategy === "none")
24589
24675
  return false;
@@ -24606,20 +24692,58 @@ function cacheKey(baseUrl, model) {
24606
24692
  return `${baseUrl}|${model}`;
24607
24693
  }
24608
24694
  function getCachedProbeResult(key) {
24609
- return probeCache.get(key);
24695
+ const mem = memCache.get(key);
24696
+ if (mem && Date.now() - mem.ts < CACHE_TTL_MS) {
24697
+ return mem.result;
24698
+ }
24699
+ const disk = readDiskCache();
24700
+ const entry = disk[key];
24701
+ if (entry) {
24702
+ const age = Date.now() - new Date(entry.ts).getTime();
24703
+ if (age < CACHE_TTL_MS) {
24704
+ memCache.set(key, { result: entry.result, ts: Date.now() });
24705
+ return entry.result;
24706
+ }
24707
+ }
24708
+ return;
24610
24709
  }
24611
24710
  function setCachedProbeResult(key, result) {
24612
- probeCache.set(key, result);
24711
+ const now = new Date().toISOString();
24712
+ memCache.set(key, { result, ts: Date.now() });
24713
+ const disk = readDiskCache();
24714
+ disk[key] = { result, ts: now };
24715
+ writeDiskCache(disk);
24613
24716
  }
24614
24717
  function resetProbeCache() {
24615
- probeCache.clear();
24718
+ memCache.clear();
24719
+ const path = cachePath();
24720
+ if (existsSync50(path)) {
24721
+ writeFileSync19(path, "{}", "utf-8");
24722
+ }
24723
+ }
24724
+ function readDiskCache() {
24725
+ try {
24726
+ const path = cachePath();
24727
+ if (existsSync50(path)) {
24728
+ return JSON.parse(readFileSync31(path, "utf-8"));
24729
+ }
24730
+ } catch {}
24731
+ return {};
24616
24732
  }
24617
- var PROBE_MESSAGES, probeCache;
24733
+ function writeDiskCache(data) {
24734
+ try {
24735
+ const path = cachePath();
24736
+ mkdirSync20(dirname18(path), { recursive: true });
24737
+ writeFileSync19(path, JSON.stringify(data, null, 2), "utf-8");
24738
+ } catch {}
24739
+ }
24740
+ var PROBE_MESSAGES, CACHE_TTL_MS, memCache;
24618
24741
  var init_probe = __esm(() => {
24619
24742
  PROBE_MESSAGES = [
24620
24743
  { role: "user", content: "Reply with exactly: ok" }
24621
24744
  ];
24622
- probeCache = new Map;
24745
+ CACHE_TTL_MS = 24 * 60 * 60 * 1000;
24746
+ memCache = new Map;
24623
24747
  });
24624
24748
 
24625
24749
  // src/tools/set-thinking.ts
@@ -24701,9 +24825,9 @@ __export(exports_bootstrap, {
24701
24825
  buildSystemInfo: () => buildSystemInfo,
24702
24826
  bootstrap: () => bootstrap
24703
24827
  });
24704
- import { homedir as homedir14 } from "os";
24705
- import { join as join42, resolve as resolve22 } from "path";
24706
- import { existsSync as existsSync50, readFileSync as readFileSync31, writeFileSync as writeFileSync19 } from "fs";
24828
+ import { homedir as homedir15 } from "os";
24829
+ import { join as join43, resolve as resolve22 } from "path";
24830
+ import { existsSync as existsSync51, readFileSync as readFileSync32, writeFileSync as writeFileSync20 } from "fs";
24707
24831
  function buildSystemInfo(config, baseDir, profileCompressed) {
24708
24832
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
24709
24833
  const isWin = profileCompressed.toLowerCase().includes("win32");
@@ -24756,8 +24880,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
24756
24880
  `);
24757
24881
  }
24758
24882
  async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reasoningLevel) {
24759
- const dir = configDir || process.env.MMA_CONFIG_DIR || join42(homedir14(), ".mma");
24760
- const projectConfigPath = projectDir ? join42(projectDir, ".mmrc") : join42(process.cwd(), ".mmrc");
24883
+ const dir = configDir || process.env.MMA_CONFIG_DIR || join43(homedir15(), ".mma");
24884
+ const projectConfigPath = projectDir ? join43(projectDir, ".mmrc") : join43(process.cwd(), ".mmrc");
24761
24885
  const { config, legacyDetected } = loadConfig({ configDir: dir, projectConfigPath });
24762
24886
  setLocale(config.locale);
24763
24887
  if (reasoningLevel && reasoningLevel !== "auto") {
@@ -24773,7 +24897,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
24773
24897
  }
24774
24898
  } catch {}
24775
24899
  const logger4 = new Logger(config.logLevel);
24776
- logger4.setLogDir(join42(dir, "logs"));
24900
+ logger4.setLogDir(join43(dir, "logs"));
24777
24901
  logger4.debug("MMA bootstrap", {
24778
24902
  version: config.version,
24779
24903
  model: config.model
@@ -24802,7 +24926,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
24802
24926
  logger4.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
24803
24927
  }
24804
24928
  }
24805
- const profile = new UserProfile(join42(dir));
24929
+ const profile = new UserProfile(join43(dir));
24806
24930
  profile.load() || profile.collect();
24807
24931
  profile.save();
24808
24932
  const providerManager = new ProviderManager(config.provider, {
@@ -24852,7 +24976,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
24852
24976
  for (const warning of envReport.warnings) {
24853
24977
  logger4.warn(warning);
24854
24978
  }
24855
- const projectMapCacheDir = join42(baseDir, ".mma");
24979
+ const projectMapCacheDir = join43(baseDir, ".mma");
24856
24980
  const indexerModule = new IndexerModule({
24857
24981
  baseDir,
24858
24982
  cacheDir: projectMapCacheDir
@@ -24863,9 +24987,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
24863
24987
  logger4.warn(`Project indexing failed: ${err.message}`);
24864
24988
  }
24865
24989
  const skillsLoader = new SkillsLoader;
24866
- const builtinDir = join42(import.meta.dirname, "skills", "builtin");
24867
- const globalDir = join42(homedir14(), ".agents", "skills");
24868
- const projectSkillsDir = join42(baseDir, ".mma", "skills");
24990
+ const builtinDir = join43(import.meta.dirname, "skills", "builtin");
24991
+ const globalDir = join43(homedir15(), ".agents", "skills");
24992
+ const projectSkillsDir = join43(baseDir, ".mma", "skills");
24869
24993
  const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
24870
24994
  const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
24871
24995
  const skillsModule = new SkillsModule(availableSkills, skillsBudget);
@@ -24881,11 +25005,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
24881
25005
  essential: true,
24882
25006
  estimatedTokens: Math.ceil(systemInfoContent.length / 4)
24883
25007
  };
24884
- const agentsMdGlobal = join42(dir, "AGENTS.md");
24885
- if (!existsSync50(agentsMdGlobal)) {
24886
- writeFileSync19(agentsMdGlobal, "", "utf-8");
25008
+ const agentsMdGlobal = join43(dir, "AGENTS.md");
25009
+ if (!existsSync51(agentsMdGlobal)) {
25010
+ writeFileSync20(agentsMdGlobal, "", "utf-8");
24887
25011
  }
24888
- const sessionDir = join42(dir, "sessions");
25012
+ const sessionDir = join43(dir, "sessions");
24889
25013
  const sessionStore = new SessionStore(sessionDir);
24890
25014
  sessionStore.init();
24891
25015
  const sessionManager = new SessionManager(sessionStore, {
@@ -24959,7 +25083,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
24959
25083
  const mcpModule = new MCPModule(config);
24960
25084
  await mcpModule.initialize();
24961
25085
  moduleRegistry.register(mcpModule);
24962
- const memoryStore = new MemoryStore(join42(dir, "memory"));
25086
+ const memoryStore = new MemoryStore(join43(dir, "memory"));
24963
25087
  const memoryModule = new MemoryModule(memoryStore);
24964
25088
  moduleRegistry.register(memoryModule);
24965
25089
  if (config.browser.enabled) {
@@ -25013,8 +25137,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
25013
25137
  pluginManager.register(plugin);
25014
25138
  pluginManager.register(plugin2);
25015
25139
  const pluginLoader = new PluginLoader;
25016
- const globalPluginsDir = join42(homedir14(), ".mma", "plugins");
25017
- const projectPluginsDir = join42(baseDir, ".mma", "plugins");
25140
+ const globalPluginsDir = join43(homedir15(), ".mma", "plugins");
25141
+ const projectPluginsDir = join43(baseDir, ".mma", "plugins");
25018
25142
  const mmaVersion = readMmaVersion();
25019
25143
  pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger4, {
25020
25144
  source: "global",
@@ -25040,13 +25164,13 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
25040
25164
  const skipAgentsMd = noAgentsMd === true;
25041
25165
  if (!skipAgentsMd) {
25042
25166
  const agentsMdCandidates = [
25043
- join42(baseDir, "AGENTS.md"),
25044
- join42(baseDir, ".mma", "AGENTS.md"),
25045
- join42(dir, "AGENTS.md")
25167
+ join43(baseDir, "AGENTS.md"),
25168
+ join43(baseDir, ".mma", "AGENTS.md"),
25169
+ join43(dir, "AGENTS.md")
25046
25170
  ];
25047
25171
  for (const p of agentsMdCandidates) {
25048
- if (existsSync50(p)) {
25049
- const content = readFileSync31(p, "utf-8").trim();
25172
+ if (existsSync51(p)) {
25173
+ const content = readFileSync32(p, "utf-8").trim();
25050
25174
  if (content) {
25051
25175
  agentsMdBlocks.push({
25052
25176
  content,
@@ -33432,8 +33556,8 @@ var init_scenarios = __esm(() => {
33432
33556
  });
33433
33557
 
33434
33558
  // src/modules/certification/loader.ts
33435
- import { existsSync as existsSync52, readdirSync as readdirSync17, readFileSync as readFileSync33 } from "fs";
33436
- import { join as join45 } from "path";
33559
+ import { existsSync as existsSync53, readdirSync as readdirSync17, readFileSync as readFileSync34 } from "fs";
33560
+ import { join as join46 } from "path";
33437
33561
  function validateScenario(s) {
33438
33562
  const errors2 = [];
33439
33563
  const isSkip = s.mode === "skip";
@@ -33485,12 +33609,12 @@ function loadScenarios(userDir) {
33485
33609
  else
33486
33610
  scenarios.push(s);
33487
33611
  }
33488
- if (userDir && existsSync52(userDir)) {
33612
+ if (userDir && existsSync53(userDir)) {
33489
33613
  for (const file of readdirSync17(userDir)) {
33490
33614
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
33491
33615
  continue;
33492
33616
  try {
33493
- const raw = readFileSync33(join45(userDir, file), "utf-8");
33617
+ const raw = readFileSync34(join46(userDir, file), "utf-8");
33494
33618
  const data = $parse(raw);
33495
33619
  const parsed = normalizeScenario(data, file);
33496
33620
  const errs = validateScenario(parsed);
@@ -33553,8 +33677,8 @@ var init_loader3 = __esm(() => {
33553
33677
  });
33554
33678
 
33555
33679
  // src/modules/certification/fact-checker.ts
33556
- import { existsSync as existsSync53, readFileSync as readFileSync34, statSync as statSync9 } from "fs";
33557
- import { join as join46 } from "path";
33680
+ import { existsSync as existsSync54, readFileSync as readFileSync35, statSync as statSync9 } from "fs";
33681
+ import { join as join47 } from "path";
33558
33682
  function checkSandbox(sandboxDir, checks, exitCode, output) {
33559
33683
  const failures = [];
33560
33684
  for (const check of checks) {
@@ -33571,16 +33695,16 @@ function runCheck2(sandboxDir, check, exitCode, output) {
33571
33695
  case "outputContains":
33572
33696
  return output.includes(check.text);
33573
33697
  case "fileExists":
33574
- return isFile(join46(sandboxDir, check.path));
33698
+ return isFile(join47(sandboxDir, check.path));
33575
33699
  case "fileNotExists":
33576
- return !existsSync53(join46(sandboxDir, check.path));
33700
+ return !existsSync54(join47(sandboxDir, check.path));
33577
33701
  case "dirExists":
33578
- return isDir(join46(sandboxDir, check.path));
33702
+ return isDir(join47(sandboxDir, check.path));
33579
33703
  case "fileContent": {
33580
- const abs = join46(sandboxDir, check.path);
33704
+ const abs = join47(sandboxDir, check.path);
33581
33705
  if (!isFile(abs))
33582
33706
  return false;
33583
- const content = readFileSync34(abs, "utf-8");
33707
+ const content = readFileSync35(abs, "utf-8");
33584
33708
  if (check.contains !== undefined)
33585
33709
  return content.includes(check.contains);
33586
33710
  if (check.equals !== undefined)
@@ -33588,10 +33712,10 @@ function runCheck2(sandboxDir, check, exitCode, output) {
33588
33712
  return false;
33589
33713
  }
33590
33714
  case "fileRegex": {
33591
- const abs = join46(sandboxDir, check.path);
33715
+ const abs = join47(sandboxDir, check.path);
33592
33716
  if (!isFile(abs))
33593
33717
  return false;
33594
- return new RegExp(check.pattern).test(readFileSync34(abs, "utf-8"));
33718
+ return new RegExp(check.pattern).test(readFileSync35(abs, "utf-8"));
33595
33719
  }
33596
33720
  default:
33597
33721
  return false;
@@ -33599,14 +33723,14 @@ function runCheck2(sandboxDir, check, exitCode, output) {
33599
33723
  }
33600
33724
  function isFile(p) {
33601
33725
  try {
33602
- return existsSync53(p) && statSync9(p).isFile();
33726
+ return existsSync54(p) && statSync9(p).isFile();
33603
33727
  } catch {
33604
33728
  return false;
33605
33729
  }
33606
33730
  }
33607
33731
  function isDir(p) {
33608
33732
  try {
33609
- return existsSync53(p) && statSync9(p).isDirectory();
33733
+ return existsSync54(p) && statSync9(p).isDirectory();
33610
33734
  } catch {
33611
33735
  return false;
33612
33736
  }
@@ -33637,8 +33761,8 @@ var init_fact_checker = () => {};
33637
33761
 
33638
33762
  // src/modules/certification/runner.ts
33639
33763
  import { spawn as spawn10 } from "child_process";
33640
- import { existsSync as existsSync54, mkdirSync as mkdirSync20, rmSync as rmSync4, cpSync as cpSync2, writeFileSync as writeFileSync20, readdirSync as readdirSync18, readFileSync as readFileSync35 } from "fs";
33641
- import { join as join47, resolve as resolve23, dirname as dirname20, relative as relative7 } from "path";
33764
+ import { existsSync as existsSync55, mkdirSync as mkdirSync21, rmSync as rmSync4, cpSync as cpSync2, writeFileSync as writeFileSync21, readdirSync as readdirSync18, readFileSync as readFileSync36 } from "fs";
33765
+ import { join as join48, resolve as resolve23, dirname as dirname21, relative as relative7 } from "path";
33642
33766
  async function runScenario(scenario, opts) {
33643
33767
  if (scenario.mode === "skip") {
33644
33768
  return {
@@ -33658,7 +33782,7 @@ async function runScenario(scenario, opts) {
33658
33782
  let firstError;
33659
33783
  let lastFailedSandbox;
33660
33784
  for (let i = 1;i <= reps; i++) {
33661
- const sandbox = join47(opts.sandboxBase, `run-${scenario.id}-${i}`);
33785
+ const sandbox = join48(opts.sandboxBase, `run-${scenario.id}-${i}`);
33662
33786
  let failures = [];
33663
33787
  let exitCode = -1;
33664
33788
  let output = "";
@@ -33682,9 +33806,9 @@ async function runScenario(scenario, opts) {
33682
33806
  env3.MMA_PROVIDER_APIKEY = opts.providerKey;
33683
33807
  if (scenario.config && opts.baseConfig) {
33684
33808
  const merged = deepMergeAny(opts.baseConfig, scenario.config);
33685
- const certConfigDir = join47(sandbox, ".mma");
33686
- mkdirSync20(certConfigDir, { recursive: true });
33687
- writeFileSync20(join47(certConfigDir, "config.json"), JSON.stringify(merged, null, 2), "utf-8");
33809
+ const certConfigDir = join48(sandbox, ".mma");
33810
+ mkdirSync21(certConfigDir, { recursive: true });
33811
+ writeFileSync21(join48(certConfigDir, "config.json"), JSON.stringify(merged, null, 2), "utf-8");
33688
33812
  env3.MMA_CONFIG_DIR = certConfigDir;
33689
33813
  }
33690
33814
  const res = await runner(env3, opts.mmaRoot, args, timeoutMs);
@@ -33729,14 +33853,14 @@ ${res.stderr}`;
33729
33853
  }
33730
33854
  function prepareSandbox(sandbox, scenario, mmaRoot) {
33731
33855
  rmSync4(sandbox, { recursive: true, force: true });
33732
- mkdirSync20(sandbox, { recursive: true });
33856
+ mkdirSync21(sandbox, { recursive: true });
33733
33857
  for (const f of scenario.fixtures ?? []) {
33734
- const src = join47(mmaRoot, f.source);
33735
- if (!existsSync54(src)) {
33858
+ const src = join48(mmaRoot, f.source);
33859
+ if (!existsSync55(src)) {
33736
33860
  throw new Error(`fixture missing: ${f.source}`);
33737
33861
  }
33738
- const dest = join47(sandbox, f.dest);
33739
- mkdirSync20(dirname20(dest), { recursive: true });
33862
+ const dest = join48(sandbox, f.dest);
33863
+ mkdirSync21(dirname21(dest), { recursive: true });
33740
33864
  cpSync2(src, dest);
33741
33865
  }
33742
33866
  }
@@ -33748,10 +33872,10 @@ function collectDiagnostics(sandbox) {
33748
33872
  } else {
33749
33873
  lines.push(" Files created: (none)");
33750
33874
  }
33751
- const planPath = join47(sandbox, ".mma", "plans", "active.json");
33752
- if (existsSync54(planPath)) {
33875
+ const planPath = join48(sandbox, ".mma", "plans", "active.json");
33876
+ if (existsSync55(planPath)) {
33753
33877
  try {
33754
- const plan = JSON.parse(readFileSync35(planPath, "utf-8"));
33878
+ const plan = JSON.parse(readFileSync36(planPath, "utf-8"));
33755
33879
  const steps = plan.steps ?? [];
33756
33880
  const done = steps.filter((s) => s.status === "done").length;
33757
33881
  const pending = steps.filter((s) => s.status === "pending" || s.status === "in_progress");
@@ -33770,7 +33894,7 @@ function listFiles(dir, root) {
33770
33894
  for (const entry of readdirSync18(dir, { withFileTypes: true })) {
33771
33895
  if (entry.name === ".mma")
33772
33896
  continue;
33773
- const abs = join47(dir, entry.name);
33897
+ const abs = join48(dir, entry.name);
33774
33898
  const rel = toForwardSlash(relative7(root, abs));
33775
33899
  if (entry.isDirectory()) {
33776
33900
  result.push(...listFiles(abs, root));
@@ -33782,15 +33906,15 @@ function listFiles(dir, root) {
33782
33906
  return result;
33783
33907
  }
33784
33908
  function resolveMmaEntry(mmaRoot) {
33785
- const dev = join47(mmaRoot, "src", "cli", "main.ts");
33786
- if (existsSync54(dev))
33909
+ const dev = join48(mmaRoot, "src", "cli", "main.ts");
33910
+ if (existsSync55(dev))
33787
33911
  return dev;
33788
- return join47(mmaRoot, "dist", "main.js");
33912
+ return join48(mmaRoot, "dist", "main.js");
33789
33913
  }
33790
33914
  function findMmaRoot(fromDir) {
33791
33915
  const candidates = [resolve23(fromDir, "..", "..", ".."), resolve23(fromDir, "..")];
33792
33916
  for (const c of candidates) {
33793
- if (existsSync54(join47(c, "package.json")))
33917
+ if (existsSync55(join48(c, "package.json")))
33794
33918
  return c;
33795
33919
  }
33796
33920
  return process.cwd();
@@ -33857,16 +33981,16 @@ __export(exports_cli, {
33857
33981
  certStatus: () => certStatus,
33858
33982
  certList: () => certList
33859
33983
  });
33860
- import { rmSync as rmSync5, writeFileSync as writeFileSync21 } from "fs";
33861
- import { join as join48, dirname as dirname21 } from "path";
33984
+ import { rmSync as rmSync5, writeFileSync as writeFileSync22 } from "fs";
33985
+ import { join as join49, dirname as dirname22 } from "path";
33862
33986
  import { fileURLToPath as fileURLToPath5 } from "url";
33863
- import { existsSync as existsSync55, readFileSync as readFileSync36 } from "fs";
33987
+ import { existsSync as existsSync56, readFileSync as readFileSync37 } from "fs";
33864
33988
  function readVersion() {
33865
- const candidates = [join48(MMA_ROOT, "package.json")];
33989
+ const candidates = [join49(MMA_ROOT, "package.json")];
33866
33990
  for (const p of candidates) {
33867
- if (existsSync55(p)) {
33991
+ if (existsSync56(p)) {
33868
33992
  try {
33869
- const raw = JSON.parse(readFileSync36(p, "utf-8"));
33993
+ const raw = JSON.parse(readFileSync37(p, "utf-8"));
33870
33994
  if (raw.version)
33871
33995
  return raw.version;
33872
33996
  } catch {}
@@ -33879,7 +34003,7 @@ function parseTags(s) {
33879
34003
  }
33880
34004
  async function certify(opts) {
33881
34005
  const providerUrl = opts.providerUrl || opts.config.provider.baseUrl;
33882
- const { scenarios, errors: errors2 } = loadScenarios(join48(opts.projectDir, ".mma", "certification", "scenarios"));
34006
+ const { scenarios, errors: errors2 } = loadScenarios(join49(opts.projectDir, ".mma", "certification", "scenarios"));
33883
34007
  for (const e of errors2)
33884
34008
  console.error(pc2.yellow(` ${e}`));
33885
34009
  let selected = filterByTags(scenarios, opts.tags);
@@ -33910,7 +34034,7 @@ async function certify(opts) {
33910
34034
  return;
33911
34035
  }
33912
34036
  console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
33913
- const sandboxBase = join48(process.cwd(), ".mma", "certification");
34037
+ const sandboxBase = join49(process.cwd(), ".mma", "certification");
33914
34038
  const results = [];
33915
34039
  const total = selected.length;
33916
34040
  let idx = 0;
@@ -34043,10 +34167,10 @@ function printResults(results) {
34043
34167
  }
34044
34168
  }
34045
34169
  function writeReport(entry, projectDir) {
34046
- const reportDir = join48(projectDir, "certification");
34170
+ const reportDir = join49(projectDir, "certification");
34047
34171
  const ts = entry.certifiedAt.replace(/[:.]/g, "-").slice(0, 19);
34048
34172
  const filename = `report-${entry.model.replace(/[/\\:]/g, "_")}-${ts}.json`;
34049
- const reportPath = join48(reportDir, filename);
34173
+ const reportPath = join49(reportDir, filename);
34050
34174
  const report = {
34051
34175
  model: entry.model,
34052
34176
  providerUrl: entry.providerUrl,
@@ -34065,7 +34189,7 @@ function writeReport(entry, projectDir) {
34065
34189
  }))
34066
34190
  };
34067
34191
  try {
34068
- writeFileSync21(reportPath, JSON.stringify(report, null, 2), "utf-8");
34192
+ writeFileSync22(reportPath, JSON.stringify(report, null, 2), "utf-8");
34069
34193
  console.log(pc2.dim(`
34070
34194
  Report: ${reportPath}`));
34071
34195
  } catch (e) {
@@ -34079,7 +34203,7 @@ var init_cli = __esm(() => {
34079
34203
  init_loader3();
34080
34204
  init_runner2();
34081
34205
  init_manifest();
34082
- HERE = dirname21(fileURLToPath5(import.meta.url));
34206
+ HERE = dirname22(fileURLToPath5(import.meta.url));
34083
34207
  MMA_ROOT = findMmaRoot(HERE);
34084
34208
  });
34085
34209
 
@@ -34089,8 +34213,8 @@ __export(exports_repl_commands, {
34089
34213
  registerAllCommands: () => registerAllCommands,
34090
34214
  COMMAND_GROUPS: () => COMMAND_GROUPS
34091
34215
  });
34092
- import { join as join50, dirname as dirname23 } from "path";
34093
- import { existsSync as existsSync57 } from "fs";
34216
+ import { join as join51, dirname as dirname24 } from "path";
34217
+ import { existsSync as existsSync58 } from "fs";
34094
34218
  function registerAllCommands(ctx) {
34095
34219
  registerBuiltinCommands(ctx);
34096
34220
  registerMmaCommands(ctx);
@@ -34147,7 +34271,7 @@ function registerMmaCommands(ctx) {
34147
34271
  }
34148
34272
  try {
34149
34273
  const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
34150
- const { existsSync: existsSync58 } = await import("fs");
34274
+ const { existsSync: existsSync59 } = await import("fs");
34151
34275
  const { resolve: resolve24 } = await import("path");
34152
34276
  let dataUrl;
34153
34277
  let label;
@@ -34167,7 +34291,7 @@ function registerMmaCommands(ctx) {
34167
34291
  label = source;
34168
34292
  } else {
34169
34293
  const absPath = resolve24(process.cwd(), source);
34170
- if (!existsSync58(absPath)) {
34294
+ if (!existsSync59(absPath)) {
34171
34295
  console.log(pc2.red(t("image.not_found", { path: source })));
34172
34296
  return;
34173
34297
  }
@@ -34270,7 +34394,7 @@ function registerMmaCommands(ctx) {
34270
34394
  console.log(pc2.yellow(t("repl.wizard_running")));
34271
34395
  await ctx.withExclusiveInput(async () => {
34272
34396
  const answers = await runSetup(ctx.rl);
34273
- const configPath = join50(ctx.configDir, "config.json");
34397
+ const configPath = join51(ctx.configDir, "config.json");
34274
34398
  ctx.config.provider.type = answers.provider;
34275
34399
  ctx.config.provider.baseUrl = answers.apiBase;
34276
34400
  ctx.config.provider.apiKey = answers.apiKey;
@@ -34278,7 +34402,7 @@ function registerMmaCommands(ctx) {
34278
34402
  ctx.config.contextWindow = answers.contextWindow;
34279
34403
  ctx.config.maxToolIterations = answers.maxToolIterations;
34280
34404
  ctx.config.locale = answers.locale;
34281
- saveConfig(ctx.config, configPath, dirname23(configPath));
34405
+ saveConfig(ctx.config, configPath, dirname24(configPath));
34282
34406
  await ctx.agent.reconfigure(ctx.config);
34283
34407
  console.log(pc2.green(t("cli.config_saved")));
34284
34408
  });
@@ -34392,8 +34516,8 @@ function registerMmaCommands(ctx) {
34392
34516
  return;
34393
34517
  }
34394
34518
  ctx.config.model = name;
34395
- const configPath = join50(ctx.configDir, "config.json");
34396
- saveConfig(ctx.config, configPath, dirname23(configPath));
34519
+ const configPath = join51(ctx.configDir, "config.json");
34520
+ saveConfig(ctx.config, configPath, dirname24(configPath));
34397
34521
  await ctx.agent.reconfigure(ctx.config);
34398
34522
  console.log(pc2.green(t("repl.model_set", { name })));
34399
34523
  return;
@@ -34417,8 +34541,8 @@ function registerMmaCommands(ctx) {
34417
34541
  return;
34418
34542
  }
34419
34543
  ctx.config.contextWindow = size;
34420
- const configPath = join50(ctx.configDir, "config.json");
34421
- saveConfig(ctx.config, configPath, dirname23(configPath));
34544
+ const configPath = join51(ctx.configDir, "config.json");
34545
+ saveConfig(ctx.config, configPath, dirname24(configPath));
34422
34546
  await ctx.agent.reconfigure(ctx.config);
34423
34547
  console.log(pc2.green(t("cli.context_set", { size })));
34424
34548
  }
@@ -34432,10 +34556,10 @@ function registerMmaCommands(ctx) {
34432
34556
  if (ctx.sessionManager && ctx.config.session.autoSave) {}
34433
34557
  ctx.agent.shutdown();
34434
34558
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
34435
- const { join: join51 } = await import("path");
34559
+ const { join: join52 } = await import("path");
34436
34560
  const configDir = ctx.configDir;
34437
34561
  const baseDir = ctx.baseDir;
34438
- const projectConfigPath = join51(baseDir, ".mmrc");
34562
+ const projectConfigPath = join52(baseDir, ".mmrc");
34439
34563
  const { config: freshConfig } = loadConfig2({ configDir, projectConfigPath });
34440
34564
  Object.assign(ctx.config, freshConfig);
34441
34565
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
@@ -34789,21 +34913,21 @@ async function runConfigMigrate(ctx) {
34789
34913
  const { hasDomainFiles: hasDomainFiles3 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
34790
34914
  const { loadConfig: loadCfg } = await Promise.resolve().then(() => (init_config2(), exports_config));
34791
34915
  const configDir = ctx.configDir;
34792
- const configPath = join50(configDir, "config.json");
34916
+ const configPath = join51(configDir, "config.json");
34793
34917
  if (hasDomainFiles3(configDir)) {
34794
34918
  console.log(pc2.yellow(t("config.migrate_no_legacy")));
34795
34919
  return;
34796
34920
  }
34797
- if (!existsSync57(configPath)) {
34921
+ if (!existsSync58(configPath)) {
34798
34922
  console.log(pc2.yellow(t("config.migrate_no_legacy")));
34799
34923
  return;
34800
34924
  }
34801
34925
  console.log(t("config.migrate_start"));
34802
- const { config } = loadCfg({ configDir, projectConfigPath: join50(configDir, ".mmrc") });
34926
+ const { config } = loadCfg({ configDir, projectConfigPath: join51(configDir, ".mmrc") });
34803
34927
  saveConfig(config, configPath, configDir);
34804
34928
  const { renameSync: renameSync4, readdirSync: readdirSync19 } = await import("fs");
34805
34929
  renameSync4(configPath, configPath + ".bak");
34806
- const domainFiles = readdirSync19(join50(configDir, "config")).filter((f) => f.endsWith(".json"));
34930
+ const domainFiles = readdirSync19(join51(configDir, "config")).filter((f) => f.endsWith(".json"));
34807
34931
  console.log(pc2.green(t("config.migrate_done", { count: String(domainFiles.length) })));
34808
34932
  }
34809
34933
  var version2, COMMAND_GROUPS;
@@ -34863,15 +34987,15 @@ init_config2();
34863
34987
  init_setup();
34864
34988
  init_i18n();
34865
34989
  init_colors();
34866
- import { join as join49, dirname as dirname22 } from "path";
34867
- import { homedir as homedir16 } from "os";
34868
- import { existsSync as existsSync56 } from "fs";
34990
+ import { join as join50, dirname as dirname23 } from "path";
34991
+ import { homedir as homedir17 } from "os";
34992
+ import { existsSync as existsSync57 } from "fs";
34869
34993
 
34870
34994
  // src/cli/security-commands.ts
34871
34995
  init_bootstrap();
34872
34996
  init_config2();
34873
- import { join as join43, dirname as dirname18 } from "path";
34874
- import { homedir as homedir15 } from "os";
34997
+ import { join as join44, dirname as dirname19 } from "path";
34998
+ import { homedir as homedir16 } from "os";
34875
34999
 
34876
35000
  // src/modules/security/security-policies.ts
34877
35001
  init_security();
@@ -35396,7 +35520,7 @@ function createSecurityCommand(program2) {
35396
35520
  }
35397
35521
  });
35398
35522
  securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
35399
- const configPath = join43(homedir15(), ".mma", "config.json");
35523
+ const configPath = join44(homedir16(), ".mma", "config.json");
35400
35524
  const { config: appConfig } = await bootstrap();
35401
35525
  const validPresets = ["strict", "balanced", "permissive"];
35402
35526
  if (!validPresets.includes(preset)) {
@@ -35406,40 +35530,40 @@ function createSecurityCommand(program2) {
35406
35530
  const policy = getSecurityPolicy(preset);
35407
35531
  const newSecurityConfig = applySecurityPolicy(preset);
35408
35532
  appConfig.security = newSecurityConfig;
35409
- saveConfig(appConfig, configPath, dirname18(configPath));
35533
+ saveConfig(appConfig, configPath, dirname19(configPath));
35410
35534
  console.log(t("cli.security.policy_applied", { name: policy.name }));
35411
35535
  console.log(t("cli.security.policy_description", { description: policy.description }));
35412
35536
  });
35413
35537
  securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
35414
- const configPath = join43(homedir15(), ".mma", "config.json");
35538
+ const configPath = join44(homedir16(), ".mma", "config.json");
35415
35539
  const { config: appConfig } = await bootstrap();
35416
35540
  const security = appConfig.security = appConfig.security || {};
35417
35541
  toggleSessionEncryption(security, true);
35418
- saveConfig(appConfig, configPath, dirname18(configPath));
35542
+ saveConfig(appConfig, configPath, dirname19(configPath));
35419
35543
  console.log(t("cli.security.encryption_enabled"));
35420
35544
  });
35421
35545
  securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
35422
- const configPath = join43(homedir15(), ".mma", "config.json");
35546
+ const configPath = join44(homedir16(), ".mma", "config.json");
35423
35547
  const { config: appConfig } = await bootstrap();
35424
35548
  const security = appConfig.security = appConfig.security || {};
35425
35549
  toggleSessionEncryption(security, false);
35426
- saveConfig(appConfig, configPath, dirname18(configPath));
35550
+ saveConfig(appConfig, configPath, dirname19(configPath));
35427
35551
  console.log(t("cli.security.encryption_disabled"));
35428
35552
  });
35429
35553
  securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
35430
- const configPath = join43(homedir15(), ".mma", "config.json");
35554
+ const configPath = join44(homedir16(), ".mma", "config.json");
35431
35555
  const { config: appConfig } = await bootstrap();
35432
35556
  const security = appConfig.security = appConfig.security || {};
35433
35557
  toggleAuditNotifier(security, true);
35434
- saveConfig(appConfig, configPath, dirname18(configPath));
35558
+ saveConfig(appConfig, configPath, dirname19(configPath));
35435
35559
  console.log(t("cli.security.audit_enabled"));
35436
35560
  });
35437
35561
  securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
35438
- const configPath = join43(homedir15(), ".mma", "config.json");
35562
+ const configPath = join44(homedir16(), ".mma", "config.json");
35439
35563
  const { config: appConfig } = await bootstrap();
35440
35564
  const security = appConfig.security = appConfig.security || {};
35441
35565
  toggleAuditNotifier(security, false);
35442
- saveConfig(appConfig, configPath, dirname18(configPath));
35566
+ saveConfig(appConfig, configPath, dirname19(configPath));
35443
35567
  console.log(t("cli.security.audit_disabled"));
35444
35568
  });
35445
35569
  securityCmd.command("audit-stats").description(t("cli.security.audit_stats")).action(async () => {
@@ -35498,27 +35622,27 @@ init_presets();
35498
35622
  init_version();
35499
35623
 
35500
35624
  // src/modules/updater/changelog-reader.ts
35501
- import { readFileSync as readFileSync32, existsSync as existsSync51 } from "fs";
35502
- import { dirname as dirname19, join as join44 } from "path";
35625
+ import { readFileSync as readFileSync33, existsSync as existsSync52 } from "fs";
35626
+ import { dirname as dirname20, join as join45 } from "path";
35503
35627
  function readChangelog(packageName) {
35504
35628
  try {
35505
- let dir = dirname19(import.meta.url);
35629
+ let dir = dirname20(import.meta.url);
35506
35630
  if (dir.startsWith("file://")) {
35507
35631
  dir = decodeURIComponent(dir.slice(7));
35508
35632
  }
35509
35633
  for (let i = 0;i < 10; i++) {
35510
- const pkgPath = join44(dir, "package.json");
35511
- if (existsSync51(pkgPath)) {
35512
- const pkg = JSON.parse(readFileSync32(pkgPath, "utf-8"));
35634
+ const pkgPath = join45(dir, "package.json");
35635
+ if (existsSync52(pkgPath)) {
35636
+ const pkg = JSON.parse(readFileSync33(pkgPath, "utf-8"));
35513
35637
  if (pkg.name === packageName) {
35514
- const changelogPath = join44(dir, "CHANGELOG.md");
35515
- if (existsSync51(changelogPath)) {
35516
- return readFileSync32(changelogPath, "utf-8");
35638
+ const changelogPath = join45(dir, "CHANGELOG.md");
35639
+ if (existsSync52(changelogPath)) {
35640
+ return readFileSync33(changelogPath, "utf-8");
35517
35641
  }
35518
35642
  return null;
35519
35643
  }
35520
35644
  }
35521
- dir = dirname19(dir);
35645
+ dir = dirname20(dir);
35522
35646
  }
35523
35647
  return null;
35524
35648
  } catch {
@@ -35581,7 +35705,7 @@ function createProgram() {
35581
35705
  const program2 = new Command().name("mma").description(t("cli.description")).version(version).option("--no-agents-md", t("cli.no_agents_md")).option("-d, --dir <path>", t("cli.dir")).option("-e, --exit-on-complete", t("cli.exit_on_complete")).option("-j, --json", t("cli.json")).option("--reasoning <level>", t("cli.reasoning_level"), "auto");
35582
35706
  program2.command("init").description(t("cli.init")).action(async () => {
35583
35707
  const answers = await runSetup();
35584
- const configPath = join49(homedir16(), ".mma", "config.json");
35708
+ const configPath = join50(homedir17(), ".mma", "config.json");
35585
35709
  const { config } = await bootstrap();
35586
35710
  config.provider.type = answers.provider;
35587
35711
  config.provider.baseUrl = answers.apiBase;
@@ -35621,12 +35745,12 @@ function createProgram() {
35621
35745
  config.security.paths.denied = [];
35622
35746
  }
35623
35747
  }
35624
- saveConfig(config, configPath, dirname22(configPath));
35748
+ saveConfig(config, configPath, dirname23(configPath));
35625
35749
  console.log(t("cli.config_saved"));
35626
35750
  });
35627
35751
  const configCmd = program2.command("config").description(t("cli.manage_config"));
35628
35752
  configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
35629
- const configPath = join49(homedir16(), ".mma", "config.json");
35753
+ const configPath = join50(homedir17(), ".mma", "config.json");
35630
35754
  const { config } = await bootstrap();
35631
35755
  const keys = key.split(".");
35632
35756
  let obj = config;
@@ -35646,7 +35770,7 @@ function createProgram() {
35646
35770
  obj[lastKey] = parseFloat(value);
35647
35771
  else
35648
35772
  obj[lastKey] = value;
35649
- saveConfig(config, configPath, dirname22(configPath));
35773
+ saveConfig(config, configPath, dirname23(configPath));
35650
35774
  console.log(t("cli.set_done", { key, value }));
35651
35775
  });
35652
35776
  configCmd.command("show").description(t("cli.show_config")).action(async () => {
@@ -35656,24 +35780,24 @@ function createProgram() {
35656
35780
  configCmd.command("migrate").description(t("cli.migrate_config")).action(async () => {
35657
35781
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
35658
35782
  const { hasDomainFiles: hasDomainFiles3 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
35659
- const configDir = join49(homedir16(), ".mma");
35660
- const configPath = join49(configDir, "config.json");
35783
+ const configDir = join50(homedir17(), ".mma");
35784
+ const configPath = join50(configDir, "config.json");
35661
35785
  if (hasDomainFiles3(configDir)) {
35662
35786
  console.log(pc2.yellow(t("config.migrate_no_legacy")));
35663
35787
  return;
35664
35788
  }
35665
- if (!existsSync56(configPath)) {
35789
+ if (!existsSync57(configPath)) {
35666
35790
  console.log(pc2.yellow(t("config.migrate_no_legacy")));
35667
35791
  return;
35668
35792
  }
35669
35793
  console.log(t("config.migrate_start"));
35670
- const { config } = loadConfig2({ configDir, projectConfigPath: join49(configDir, ".mmrc") });
35794
+ const { config } = loadConfig2({ configDir, projectConfigPath: join50(configDir, ".mmrc") });
35671
35795
  saveConfig(config, configPath, configDir);
35672
35796
  const bakPath = configPath + ".bak";
35673
35797
  const { renameSync: renameSync4 } = await import("fs");
35674
35798
  renameSync4(configPath, bakPath);
35675
35799
  const { readdirSync: readdirSync19 } = await import("fs");
35676
- const domainFiles = readdirSync19(join49(configDir, "config")).filter((f) => f.endsWith(".json"));
35800
+ const domainFiles = readdirSync19(join50(configDir, "config")).filter((f) => f.endsWith(".json"));
35677
35801
  console.log(pc2.green(t("config.migrate_done", { count: String(domainFiles.length) })));
35678
35802
  });
35679
35803
  const model = program2.command("model").description(t("cli.manage_models"));
@@ -35713,10 +35837,10 @@ function createProgram() {
35713
35837
  console.log(t("cli.model_hint"));
35714
35838
  });
35715
35839
  model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
35716
- const configPath = join49(homedir16(), ".mma", "config.json");
35840
+ const configPath = join50(homedir17(), ".mma", "config.json");
35717
35841
  const { config } = await bootstrap();
35718
35842
  config.model = name;
35719
- saveConfig(config, configPath, dirname22(configPath));
35843
+ saveConfig(config, configPath, dirname23(configPath));
35720
35844
  console.log(t("cli.model_set", { name }));
35721
35845
  });
35722
35846
  model.command("certify").argument("<name>", "Model name").option("--provider-url <url>", t("cli.cert_provider_url")).option("--provider-key <key>", t("cli.cert_provider_key")).option("--context-window <n>", t("cli.cert_context_window")).option("--tags <tags>", t("cli.cert_tags"), "core").option("--scenarios <ids>", t("cli.cert_scenarios")).option("--timeout <ms>", t("cli.cert_timeout")).option("--reps <n>", t("cli.cert_reps")).option("--force", t("cli.cert_force")).option("--clean", t("cli.cert_clean")).description(t("cli.certify")).action(async (name, cmdOpts) => {
@@ -35752,7 +35876,7 @@ function createProgram() {
35752
35876
  await uncertify2(name, config, process.cwd());
35753
35877
  });
35754
35878
  program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
35755
- const configPath = join49(homedir16(), ".mma", "config.json");
35879
+ const configPath = join50(homedir17(), ".mma", "config.json");
35756
35880
  const { config } = await bootstrap();
35757
35881
  const contextWindow = parseInt(size, 10);
35758
35882
  if (isNaN(contextWindow) || contextWindow < 1024) {
@@ -35760,7 +35884,7 @@ function createProgram() {
35760
35884
  return;
35761
35885
  }
35762
35886
  config.contextWindow = contextWindow;
35763
- saveConfig(config, configPath, dirname22(configPath));
35887
+ saveConfig(config, configPath, dirname23(configPath));
35764
35888
  console.log(t("cli.context_set", { size: contextWindow }));
35765
35889
  });
35766
35890
  const provider = program2.command("provider").description(t("cli.manage_providers"));
@@ -35798,7 +35922,7 @@ function createProgram() {
35798
35922
  console.log(t("cli.base_url"), config.provider.baseUrl);
35799
35923
  });
35800
35924
  provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
35801
- const configPath = join49(homedir16(), ".mma", "config.json");
35925
+ const configPath = join50(homedir17(), ".mma", "config.json");
35802
35926
  const { config, agent } = await bootstrap();
35803
35927
  if (config.provider.entries && config.provider.entries.length > 0) {
35804
35928
  try {
@@ -35814,14 +35938,14 @@ function createProgram() {
35814
35938
  if (baseUrl) {
35815
35939
  config.provider.baseUrl = baseUrl;
35816
35940
  }
35817
- saveConfig(config, configPath, dirname22(configPath));
35941
+ saveConfig(config, configPath, dirname23(configPath));
35818
35942
  console.log(t("cli.provider_set", { name }));
35819
35943
  if (baseUrl) {
35820
35944
  console.log(t("cli.provider_base_hint", { baseUrl }));
35821
35945
  }
35822
35946
  });
35823
35947
  provider.command("add").argument("<name>", "Provider type or label").option("--url <url>", "Base URL").option("--key <key>", "API key").option("--priority <n>", "Fallback priority (lower = tried first)").option("--context-window <n>", "Context window override for this entry").option("--rpm <n>", "Max requests per minute for this entry").option("--parallel <n>", "Max parallel tasks for this entry").description(t("cli.add_provider")).action(async (name, opts) => {
35824
- const configPath = join49(homedir16(), ".mma", "config.json");
35948
+ const configPath = join50(homedir17(), ".mma", "config.json");
35825
35949
  const { config } = await bootstrap();
35826
35950
  const entries = Array.isArray(config.provider.entries) ? config.provider.entries : [];
35827
35951
  if (entries.length === 0) {
@@ -35853,7 +35977,7 @@ function createProgram() {
35853
35977
  });
35854
35978
  config.provider.entries = entries;
35855
35979
  config.provider.active = config.provider.active || config.provider.type;
35856
- saveConfig(config, configPath, dirname22(configPath));
35980
+ saveConfig(config, configPath, dirname23(configPath));
35857
35981
  console.log(pc2.green(t("cli.provider_added", { name })));
35858
35982
  console.log(t("cli.provider_switch_hint"));
35859
35983
  });
@@ -36795,9 +36919,9 @@ class LineEditor {
36795
36919
  }
36796
36920
 
36797
36921
  // src/cli/repl.ts
36798
- import { existsSync as existsSync58, readFileSync as readFileSync39, writeFileSync as writeFileSync22 } from "fs";
36799
- import { join as join51 } from "path";
36800
- import { homedir as homedir17 } from "os";
36922
+ import { existsSync as existsSync59, readFileSync as readFileSync40, writeFileSync as writeFileSync23 } from "fs";
36923
+ import { join as join52 } from "path";
36924
+ import { homedir as homedir18 } from "os";
36801
36925
 
36802
36926
  // src/cli/completer.ts
36803
36927
  class SlashCommandProvider {
@@ -36983,9 +37107,12 @@ class FormattingStream {
36983
37107
  codeLines = [];
36984
37108
  tableBuffer = [];
36985
37109
  onWrite;
37110
+ onRawWrite;
36986
37111
  width;
36987
- constructor(onWrite, width) {
37112
+ partialWritten = 0;
37113
+ constructor(onWrite, width, onRawWrite) {
36988
37114
  this.onWrite = onWrite;
37115
+ this.onRawWrite = onRawWrite ?? onWrite;
36989
37116
  this.width = width ?? getTerminalWidth();
36990
37117
  }
36991
37118
  write(chunk) {
@@ -36995,8 +37122,20 @@ class FormattingStream {
36995
37122
  `)) !== -1) {
36996
37123
  const line = this.buffer.slice(0, idx);
36997
37124
  this.buffer = this.buffer.slice(idx + 1);
37125
+ this.emitPartialRewind();
36998
37126
  this.processLine(line);
36999
37127
  }
37128
+ if (this.buffer.length > 0 && !this.inCodeBlock) {
37129
+ this.onRawWrite(this.buffer);
37130
+ this.partialWritten = this.buffer.length;
37131
+ this.buffer = "";
37132
+ }
37133
+ }
37134
+ emitPartialRewind() {
37135
+ if (this.partialWritten > 0) {
37136
+ this.onRawWrite(`\x1B[${this.partialWritten}D`);
37137
+ this.partialWritten = 0;
37138
+ }
37000
37139
  }
37001
37140
  flush() {
37002
37141
  if (this.tableBuffer.length > 0) {
@@ -37133,7 +37272,6 @@ function formatWarning(text) {
37133
37272
 
37134
37273
  // src/ui/renderer.ts
37135
37274
  init_spinner();
37136
- init_box();
37137
37275
  init_table();
37138
37276
  init_i18n();
37139
37277
  init_prices();
@@ -37160,6 +37298,7 @@ function toDisplayPath(baseDir, p) {
37160
37298
  return rel.split(sep2).join("/");
37161
37299
  }
37162
37300
  var GUTTER = " ";
37301
+ var MAX_OUTPUT_LINES = 50;
37163
37302
  var BUSY_TOOLS = new Set(["lsp_check"]);
37164
37303
  function toolMarker(tool) {
37165
37304
  switch (tool) {
@@ -37211,15 +37350,19 @@ class Renderer {
37211
37350
  out;
37212
37351
  err;
37213
37352
  width;
37214
- toolStyle;
37215
37353
  baseDir;
37216
37354
  card = null;
37355
+ thoughtStarted = false;
37356
+ thoughtStartMs = 0;
37357
+ thoughtHeaderPrinted = false;
37358
+ textStarted = false;
37359
+ outputLineCount = 0;
37360
+ outputSuppressed = false;
37217
37361
  constructor(opts = {}) {
37218
37362
  this.rich = opts.rich ?? isRichTerminal();
37219
37363
  this.out = opts.out ?? process.stdout;
37220
37364
  this.err = opts.err ?? process.stderr;
37221
37365
  this.width = opts.width ?? getTerminalWidth();
37222
- this.toolStyle = opts.toolStyle ?? "inline";
37223
37366
  this.baseDir = opts.baseDir;
37224
37367
  this.spinner = new Spinner({
37225
37368
  enabled: this.rich && (opts.spinner ?? true),
@@ -37227,21 +37370,32 @@ class Renderer {
37227
37370
  width: this.width
37228
37371
  });
37229
37372
  this.fmt = new FormattingStream((line) => this.out.write(`${line}
37230
- `), this.width);
37373
+ `), this.width, (text) => this.out.write(text));
37374
+ }
37375
+ showLoader() {
37376
+ this.spinner.start("thinking");
37231
37377
  }
37232
37378
  text(chunk) {
37233
37379
  this.endCard();
37234
37380
  this.spinner.stop();
37381
+ if (!this.textStarted) {
37382
+ this.textStarted = true;
37383
+ this.out.write(`
37384
+ ${pc2.dim("-")} `);
37385
+ }
37235
37386
  this.fmt.write(chunk);
37236
37387
  }
37237
37388
  meta(chunk) {
37238
37389
  this.spinner.stop();
37239
- if (this.card) {
37240
- if (this.toolStyle === "inline") {
37241
- this.writeInlineBody(chunk);
37242
- } else {
37243
- this.card.body.push(chunk);
37244
- }
37390
+ if (this.thoughtStarted) {
37391
+ if (!this.thoughtHeaderPrinted) {
37392
+ this.out.write(`
37393
+ ${pc2.dim("→")} Thought: `);
37394
+ this.thoughtHeaderPrinted = true;
37395
+ }
37396
+ this.out.write(pc2.dim(chunk));
37397
+ } else if (this.card) {
37398
+ this.writeInlineBody(chunk);
37245
37399
  } else {
37246
37400
  this.out.write(chunk);
37247
37401
  }
@@ -37251,44 +37405,55 @@ class Renderer {
37251
37405
  `)) {
37252
37406
  if (line.trim() === "")
37253
37407
  continue;
37408
+ this.outputLineCount++;
37409
+ if (this.outputLineCount > MAX_OUTPUT_LINES) {
37410
+ this.outputSuppressed = true;
37411
+ continue;
37412
+ }
37254
37413
  this.out.write(`${GUTTER}${line}
37255
37414
  `);
37256
37415
  }
37257
37416
  }
37258
37417
  reasoning(chunk) {
37259
37418
  this.spinner.stop();
37419
+ if (this.thoughtStarted && !this.thoughtHeaderPrinted) {
37420
+ this.out.write(`
37421
+ ${pc2.dim("→")} Thought: `);
37422
+ this.thoughtHeaderPrinted = true;
37423
+ }
37260
37424
  this.out.write(pc2.dim(chunk));
37261
37425
  }
37262
37426
  thinkingStart() {
37263
- this.spinner.start(t("ui.thinking"));
37427
+ this.thoughtStarted = true;
37428
+ this.thoughtStartMs = Date.now();
37429
+ this.thoughtHeaderPrinted = false;
37264
37430
  }
37265
37431
  thinkingEnd() {
37266
37432
  this.spinner.stop();
37433
+ if (this.thoughtStarted && this.thoughtHeaderPrinted) {
37434
+ const duration = Date.now() - this.thoughtStartMs;
37435
+ this.out.write(pc2.dim(` ${duration}ms
37436
+ `));
37437
+ }
37438
+ this.thoughtStarted = false;
37439
+ this.thoughtHeaderPrinted = false;
37267
37440
  }
37268
37441
  toolStart(tool, args, stepContext, icon) {
37269
37442
  this.endCard();
37270
37443
  this.spinner.stop();
37444
+ this.outputLineCount = 0;
37445
+ this.outputSuppressed = false;
37271
37446
  const displayArgs = PATH_TOOLS.has(tool) && typeof args.path === "string" ? { ...args, path: toDisplayPath(this.baseDir, args.path) } : args;
37272
37447
  const summary = summarizeArgs2(displayArgs);
37273
- const step = stepContext ? ` ${pc2.cyan(`← ${stepContext}`)}` : "";
37274
37448
  const marker = icon || toolMarker(tool);
37275
- if (!this.rich) {
37449
+ this.card = { tool, args, start: Date.now() };
37450
+ if (stepContext) {
37276
37451
  this.out.write(`
37277
- ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}
37452
+ ${pc2.dim("↓")} ${pc2.cyan(stepContext)}
37278
37453
  `);
37279
- return;
37280
37454
  }
37281
- this.card = { tool, args, body: [], start: Date.now() };
37282
- if (this.toolStyle === "inline") {
37283
- this.out.write(`
37284
- ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}
37455
+ this.out.write(`${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
37285
37456
  `);
37286
- if (BUSY_TOOLS.has(tool)) {
37287
- this.spinner.start(t("ui.tool_running", { tool: friendlyTool(tool) }));
37288
- }
37289
- return;
37290
- }
37291
- this.spinner.start(`${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}`);
37292
37457
  }
37293
37458
  planBlock(lines) {
37294
37459
  this.endCard();
@@ -37298,30 +37463,12 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
37298
37463
  `);
37299
37464
  }
37300
37465
  }
37301
- toolEnd(_tool, duration, error, ctxDelta, costUsd, provider, model) {
37466
+ toolEnd(_tool, duration, error, ctxDelta, costUsd) {
37302
37467
  this.spinner.stop();
37303
- const prov = provider && model ? `${pc2.dim(`${provider}·${model}`)}` : undefined;
37304
- if (!this.rich) {
37305
- const parts = [];
37306
- if (ctxDelta !== undefined && ctxDelta !== 0) {
37307
- const deltaStr = ctxDelta > 0 ? pc2.green(`+${ctxDelta}`) : pc2.yellow(`${ctxDelta} ↓`);
37308
- parts.push(`${pc2.dim("ctx")} ${deltaStr}`);
37309
- }
37310
- if (costUsd !== undefined && costUsd > 0) {
37311
- parts.push(`${pc2.dim("cost")} ${pc2.yellow(formatUsd(costUsd))}`);
37312
- }
37313
- if (prov)
37314
- parts.push(prov);
37315
- if (parts.length > 0)
37316
- this.out.write(`${parts.join(" ")}
37317
- `);
37318
- return;
37319
- }
37320
37468
  if (!this.card)
37321
37469
  return;
37322
- const { tool, args, body } = this.card;
37323
37470
  const marker = error ? pc2.red("✗") : pc2.green("✓");
37324
- let footer = `${marker} ${pc2.dim(`${duration}ms`)}`;
37471
+ let footer = `${GUTTER}${marker} ${pc2.dim(`${duration}ms`)}`;
37325
37472
  if (ctxDelta !== undefined && ctxDelta !== 0) {
37326
37473
  const deltaStr = ctxDelta > 0 ? pc2.green(`+${ctxDelta}`) : pc2.yellow(`${ctxDelta} ↓`);
37327
37474
  footer += ` ${pc2.dim("ctx")} ${deltaStr}`;
@@ -37329,32 +37476,10 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
37329
37476
  if (costUsd !== undefined && costUsd > 0) {
37330
37477
  footer += ` ${pc2.dim("cost")} ${pc2.yellow(formatUsd(costUsd))}`;
37331
37478
  }
37332
- if (prov) {
37333
- footer += ` ${pc2.dim("via")} ${prov}`;
37334
- }
37335
- if (this.toolStyle === "inline") {
37336
- this.out.write(`${GUTTER}${footer}
37479
+ this.out.write(`${footer}
37337
37480
  `);
37338
- this.out.write(`${divider(this.width)}
37339
- `);
37340
- this.card = null;
37341
- return;
37342
- }
37343
- const lines = [];
37344
- const summary = summarizeArgs2(args);
37345
- if (summary)
37346
- lines.push(pc2.dim(summary));
37347
- for (const chunk of body) {
37348
- for (const line of chunk.split(`
37349
- `)) {
37350
- if (line.trim() !== "")
37351
- lines.push(line);
37352
- }
37353
- }
37354
- lines.push(footer);
37355
- const title = `${marker} ${friendlyTool(tool)}`;
37356
- for (const line of box(lines, { title, width: this.width })) {
37357
- this.out.write(`${line}
37481
+ if (this.outputSuppressed) {
37482
+ this.out.write(`${GUTTER}${pc2.dim(`... (${this.outputLineCount - MAX_OUTPUT_LINES} more lines)`)}
37358
37483
  `);
37359
37484
  }
37360
37485
  this.card = null;
@@ -37374,6 +37499,12 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
37374
37499
  this.endCard();
37375
37500
  this.spinner.stop();
37376
37501
  this.fmt.flush();
37502
+ this.textStarted = false;
37503
+ }
37504
+ footer(model, provider, durationMs) {
37505
+ this.out.write(`
37506
+ ${pc2.dim("▣")} ${model} · ${provider} · ${pc2.dim(`${durationMs}ms`)}
37507
+ `);
37377
37508
  }
37378
37509
  endCard() {
37379
37510
  if (!this.card)
@@ -37527,20 +37658,16 @@ function stepContextForTool(plan, tool, args) {
37527
37658
  const argStr = JSON.stringify(args);
37528
37659
  const callPaths = extractFileLikeTokens(stripUrls(argStr)).map((p) => p.toLowerCase());
37529
37660
  if (callPaths.length > 0) {
37530
- for (const step2 of plan.steps) {
37531
- if (step2.status === "done" || step2.status === "skipped")
37661
+ for (const step of plan.steps) {
37662
+ if (step.status === "done" || step.status === "skipped")
37532
37663
  continue;
37533
- const stepPaths = extractFileLikeTokens(stripUrls(step2.description)).map((p) => p.toLowerCase());
37664
+ const stepPaths = extractFileLikeTokens(stripUrls(step.description)).map((p) => p.toLowerCase());
37534
37665
  if (stepPaths.length > 0 && stepPaths.some((s) => callPaths.some((c) => c.includes(s) || s.includes(c)))) {
37535
- return t("ui.step_context", { id: step2.id, desc: truncate4(step2.description) });
37666
+ return t("ui.step_context", { id: step.id, desc: truncate4(step.description) });
37536
37667
  }
37537
37668
  }
37538
37669
  }
37539
- const cur = currentStepIndex(plan);
37540
- const step = plan.steps[cur];
37541
- if (!step)
37542
- return null;
37543
- return t("ui.step_context", { id: step.id, desc: truncate4(step.description) });
37670
+ return null;
37544
37671
  }
37545
37672
 
37546
37673
  // src/cli/repl.ts
@@ -37623,10 +37750,10 @@ class Repl {
37623
37750
  this.envReport = envReport;
37624
37751
  this.execModule = execModule;
37625
37752
  this.slog = new SessionLogger(sessionManager, logger4);
37626
- this.configDir = configDir || join51(homedir17(), ".mma");
37753
+ this.configDir = configDir || join52(homedir18(), ".mma");
37627
37754
  this.baseDir = baseDir || process.cwd();
37628
37755
  this.noAgentsMd = noAgentsMd === true;
37629
- this.historyPath = historyPath ?? join51(homedir17(), ".mma", "repl-history");
37756
+ this.historyPath = historyPath ?? join52(homedir18(), ".mma", "repl-history");
37630
37757
  this.loadHistory();
37631
37758
  this.rl = process.stdin.isTTY ? new LineEditor({
37632
37759
  input: process.stdin,
@@ -37678,9 +37805,9 @@ class Repl {
37678
37805
  }));
37679
37806
  }
37680
37807
  loadHistory() {
37681
- if (existsSync58(this.historyPath)) {
37808
+ if (existsSync59(this.historyPath)) {
37682
37809
  try {
37683
- const raw = readFileSync39(this.historyPath, "utf-8");
37810
+ const raw = readFileSync40(this.historyPath, "utf-8");
37684
37811
  this.history = raw.split(`
37685
37812
  `).filter(Boolean).slice(-this.maxHistory);
37686
37813
  } catch {
@@ -37690,7 +37817,7 @@ class Repl {
37690
37817
  }
37691
37818
  saveHistory() {
37692
37819
  const allHistory = this.history.slice(-this.maxHistory);
37693
- writeFileSync22(this.historyPath, allHistory.join(`
37820
+ writeFileSync23(this.historyPath, allHistory.join(`
37694
37821
  `), "utf-8");
37695
37822
  }
37696
37823
  setupCompleter() {
@@ -37907,14 +38034,14 @@ ${t("image.clipboard_empty")}`));
37907
38034
  ` + pc2.green(t("repl.agent")));
37908
38035
  const renderer = new Renderer({
37909
38036
  spinner: this.config.ui?.spinner ?? true,
37910
- toolStyle: this.config.ui?.toolStyle ?? "inline",
37911
38037
  baseDir: this.baseDir
37912
38038
  });
38039
+ renderer.showLoader();
37913
38040
  const result = await this.agent.run(input, (c) => renderer.text(c), (m) => renderer.meta(m), (ev) => {
37914
38041
  if (ev.type === "start") {
37915
38042
  renderer.toolStart(ev.tool, ev.args, stepContextForTool(this.execModule?.getActivePlan() ?? null, ev.tool, ev.args), ev.icon);
37916
38043
  } else {
37917
- renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta, ev.costUsd, ev.provider, ev.model);
38044
+ renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta, ev.costUsd);
37918
38045
  if (ev.tool === "plan" || ev.tool === "todo") {
37919
38046
  this.renderPlan(renderer);
37920
38047
  }
@@ -37927,6 +38054,9 @@ ${t("image.clipboard_empty")}`));
37927
38054
  }
37928
38055
  });
37929
38056
  renderer.flush();
38057
+ if (result.provider && result.model) {
38058
+ renderer.footer(result.model, result.provider, result.llmDurationMs ?? result.durationMs ?? 0);
38059
+ }
37930
38060
  process.stdout.write(`
37931
38061
  `);
37932
38062
  this.logger?.logREPL(result.success ? "assistant" : "system", result.text?.slice(0, 400) || result.error || "");
@@ -38078,11 +38208,11 @@ ${t("image.clipboard_empty")}`));
38078
38208
  row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
38079
38209
  } else {
38080
38210
  const agentsMdCandidates = [
38081
- join51(this.baseDir, "AGENTS.md"),
38082
- join51(this.baseDir, ".mma", "AGENTS.md"),
38083
- join51(this.configDir, "AGENTS.md")
38211
+ join52(this.baseDir, "AGENTS.md"),
38212
+ join52(this.baseDir, ".mma", "AGENTS.md"),
38213
+ join52(this.configDir, "AGENTS.md")
38084
38214
  ];
38085
- const foundAgents = agentsMdCandidates.filter((p) => existsSync58(p));
38215
+ const foundAgents = agentsMdCandidates.filter((p) => existsSync59(p));
38086
38216
  if (foundAgents.length > 0) {
38087
38217
  for (const p of foundAgents) {
38088
38218
  row(t("repl.agents_label"), pc2.dim(p));
@@ -38093,7 +38223,7 @@ ${t("image.clipboard_empty")}`));
38093
38223
  }
38094
38224
  const meta = this.sessionManager?.getActiveMeta();
38095
38225
  if (meta) {
38096
- const sessionPath = join51(this.configDir, "sessions", meta.id);
38226
+ const sessionPath = join52(this.configDir, "sessions", meta.id);
38097
38227
  row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
38098
38228
  }
38099
38229
  const isTty2 = process.stdout.isTTY === true;
@@ -38208,9 +38338,9 @@ init_setup();
38208
38338
  init_config2();
38209
38339
  init_i18n();
38210
38340
  init_colors();
38211
- import { existsSync as existsSync59 } from "fs";
38212
- import { join as join53, dirname as dirname24 } from "path";
38213
- import { homedir as homedir19 } from "os";
38341
+ import { existsSync as existsSync60 } from "fs";
38342
+ import { join as join54, dirname as dirname25 } from "path";
38343
+ import { homedir as homedir20 } from "os";
38214
38344
 
38215
38345
  // src/modules/updater/index.ts
38216
38346
  init_checker();
@@ -38322,10 +38452,10 @@ ${t("cli.changelog_title", { version: result.latest })}
38322
38452
  init_environment();
38323
38453
  init_data_sanitizer();
38324
38454
  init_i18n();
38325
- import { appendFileSync as appendFileSync7, mkdirSync as mkdirSync21 } from "fs";
38326
- import { join as join52 } from "path";
38327
- import { homedir as homedir18 } from "os";
38328
- var CRASH_LOG_DIR = join52(homedir18(), ".mma", "logs");
38455
+ import { appendFileSync as appendFileSync7, mkdirSync as mkdirSync22 } from "fs";
38456
+ import { join as join53 } from "path";
38457
+ import { homedir as homedir19 } from "os";
38458
+ var CRASH_LOG_DIR = join53(homedir19(), ".mma", "logs");
38329
38459
  var CRASH_LOG_FILE = "crash.jsonl";
38330
38460
  function formatCrashEntry(type2, err) {
38331
38461
  const message = err instanceof Error ? err.message : String(err);
@@ -38335,13 +38465,13 @@ function formatCrashEntry(type2, err) {
38335
38465
  type: type2,
38336
38466
  message: sanitizeLogMessage(message),
38337
38467
  stack: sanitizeLogMessage(stack),
38338
- environment: collectEnvironment({ configDir: homedir18(), scanTools: false })
38468
+ environment: collectEnvironment({ configDir: homedir19(), scanTools: false })
38339
38469
  };
38340
38470
  }
38341
38471
  function writeCrashEntry(dir, entry) {
38342
38472
  try {
38343
- mkdirSync21(dir, { recursive: true });
38344
- appendFileSync7(join52(dir, CRASH_LOG_FILE), JSON.stringify(entry) + `
38473
+ mkdirSync22(dir, { recursive: true });
38474
+ appendFileSync7(join53(dir, CRASH_LOG_FILE), JSON.stringify(entry) + `
38345
38475
  `, "utf-8");
38346
38476
  } catch {}
38347
38477
  }
@@ -38423,14 +38553,14 @@ async function main() {
38423
38553
  }, null, 2));
38424
38554
  process.stdout.write(`
38425
38555
  `);
38426
- await updater?.waitForIdle();
38556
+ await updater?.waitForIdle(1e4);
38427
38557
  process.exit(result2.success ? 0 : 1);
38428
38558
  }
38429
38559
  const renderer = new Renderer({
38430
38560
  spinner: config.ui?.spinner ?? true,
38431
- toolStyle: config.ui?.toolStyle ?? "inline",
38432
38561
  baseDir
38433
38562
  });
38563
+ renderer.showLoader();
38434
38564
  const result = await agent.run(prompt, (chunk) => renderer.text(chunk), (meta) => renderer.meta(meta), (ev) => {
38435
38565
  if (ev.type === "start") {
38436
38566
  renderer.toolStart(ev.tool, ev.args, undefined, ev.icon);
@@ -38445,14 +38575,17 @@ async function main() {
38445
38575
  }
38446
38576
  });
38447
38577
  renderer.flush();
38578
+ if (result.provider && result.model) {
38579
+ renderer.footer(result.model, result.provider, result.llmDurationMs ?? result.durationMs ?? 0);
38580
+ }
38448
38581
  const exitCode = printRunResult(result, () => renderer.flush());
38449
38582
  agent.shutdown();
38450
38583
  await updater?.waitForIdle();
38451
38584
  process.exit(exitCode);
38452
38585
  } else {
38453
- const mmaDir = join53(homedir19(), ".mma");
38454
- const legacyConfigPath = join53(mmaDir, "config.json");
38455
- let hasAnyConfig = existsSync59(legacyConfigPath);
38586
+ const mmaDir = join54(homedir20(), ".mma");
38587
+ const legacyConfigPath = join54(mmaDir, "config.json");
38588
+ let hasAnyConfig = existsSync60(legacyConfigPath);
38456
38589
  if (!hasAnyConfig) {
38457
38590
  try {
38458
38591
  const { hasDomainFiles: hasDomainFiles3 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
@@ -38515,7 +38648,7 @@ async function main() {
38515
38648
  config.security.paths.denied = [];
38516
38649
  }
38517
38650
  }
38518
- saveConfig(config, legacyConfigPath, dirname24(legacyConfigPath));
38651
+ saveConfig(config, legacyConfigPath, dirname25(legacyConfigPath));
38519
38652
  await agent.reconfigure(config);
38520
38653
  }
38521
38654
  startAutoUpdate(config);