micro-models-agent 0.46.1 → 0.46.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/README.md +312 -312
  2. package/dist/main.js +724 -530
  3. package/dist/modules/browser/bridge-server.mjs +202 -202
  4. package/dist/skills/builtin/git.md +36 -36
  5. package/dist/skills/builtin/typescript.md +35 -35
  6. package/package.json +48 -48
  7. package/dist/cli/commands.js +0 -323
  8. package/dist/cli/completer.js +0 -167
  9. package/dist/cli/index.js +0 -2
  10. package/dist/cli/main.js +0 -165
  11. package/dist/cli/plugin-commands.js +0 -36
  12. package/dist/cli/repl-commands.js +0 -661
  13. package/dist/cli/repl.js +0 -616
  14. package/dist/cli/run-result.js +0 -22
  15. package/dist/cli/security-commands.js +0 -164
  16. package/dist/cli/setup.js +0 -231
  17. package/dist/config/config.js +0 -249
  18. package/dist/config/defaults.js +0 -124
  19. package/dist/config/experts.js +0 -15
  20. package/dist/config/index.js +0 -3
  21. package/dist/config/security.js +0 -193
  22. package/dist/config/types.js +0 -1
  23. package/dist/core/agent-moe.js +0 -102
  24. package/dist/core/agent.js +0 -886
  25. package/dist/core/bootstrap.js +0 -404
  26. package/dist/core/index.js +0 -2
  27. package/dist/core/prompt-builder.js +0 -76
  28. package/dist/core/session-logger.js +0 -197
  29. package/dist/core/types.js +0 -1
  30. package/dist/core/version.js +0 -24
  31. package/dist/core/workspace.js +0 -76
  32. package/dist/i18n/en.json +0 -598
  33. package/dist/i18n/index.js +0 -46
  34. package/dist/i18n/ru.json +0 -598
  35. package/dist/index.js +0 -22
  36. package/dist/llm/image-utils.js +0 -143
  37. package/dist/llm/index.js +0 -4
  38. package/dist/llm/model-loader.js +0 -78
  39. package/dist/llm/openai-compat.js +0 -359
  40. package/dist/llm/orchestrator.js +0 -198
  41. package/dist/llm/provider.js +0 -10
  42. package/dist/llm/response.js +0 -39
  43. package/dist/llm/token-counter.js +0 -39
  44. package/dist/llm/types.js +0 -1
  45. package/dist/logger/app-logger.js +0 -143
  46. package/dist/logger/file-log.js +0 -151
  47. package/dist/logger/index.js +0 -1
  48. package/dist/migration/backup.js +0 -45
  49. package/dist/migration/detect.js +0 -50
  50. package/dist/migration/index.js +0 -2
  51. package/dist/modules/artifacts/store.js +0 -61
  52. package/dist/modules/browser/actions.js +0 -76
  53. package/dist/modules/browser/bridge-client.js +0 -199
  54. package/dist/modules/browser/bridge-path.js +0 -10
  55. package/dist/modules/browser/cookie-store.js +0 -24
  56. package/dist/modules/browser/driver.js +0 -136
  57. package/dist/modules/browser/index.js +0 -7
  58. package/dist/modules/browser/module.js +0 -29
  59. package/dist/modules/browser/session.js +0 -338
  60. package/dist/modules/browser/snapshot.js +0 -148
  61. package/dist/modules/browser/types.js +0 -12
  62. package/dist/modules/certification/cli.js +0 -174
  63. package/dist/modules/certification/fact-checker.js +0 -82
  64. package/dist/modules/certification/loader.js +0 -105
  65. package/dist/modules/certification/manifest.js +0 -50
  66. package/dist/modules/certification/runner.js +0 -159
  67. package/dist/modules/certification/scenarios.js +0 -124
  68. package/dist/modules/certification/types.js +0 -1
  69. package/dist/modules/context/chunk-query.js +0 -100
  70. package/dist/modules/context/fact-extractor.js +0 -162
  71. package/dist/modules/context/history.js +0 -15
  72. package/dist/modules/context/index.js +0 -1
  73. package/dist/modules/context/manager.js +0 -423
  74. package/dist/modules/execution/audit-runners.js +0 -152
  75. package/dist/modules/execution/auditor.js +0 -218
  76. package/dist/modules/execution/execution-plugin.js +0 -272
  77. package/dist/modules/execution/index.js +0 -8
  78. package/dist/modules/execution/module.js +0 -436
  79. package/dist/modules/execution/moe-executor.js +0 -291
  80. package/dist/modules/execution/plan-coverage.js +0 -68
  81. package/dist/modules/execution/plan-persister.js +0 -46
  82. package/dist/modules/execution/plan-store.js +0 -157
  83. package/dist/modules/execution/plan-tool.js +0 -508
  84. package/dist/modules/execution/plan-validator.js +0 -153
  85. package/dist/modules/execution/planner.js +0 -90
  86. package/dist/modules/execution/stuck-detector.js +0 -510
  87. package/dist/modules/execution/tracker.js +0 -67
  88. package/dist/modules/execution/types.js +0 -1
  89. package/dist/modules/execution/verifier.js +0 -222
  90. package/dist/modules/execution/windows-commands.js +0 -41
  91. package/dist/modules/hallucination/confidence.js +0 -66
  92. package/dist/modules/hallucination/consistency.js +0 -26
  93. package/dist/modules/hallucination/detector.js +0 -43
  94. package/dist/modules/hallucination/factual.js +0 -129
  95. package/dist/modules/hallucination/index.js +0 -5
  96. package/dist/modules/hallucination/js-identifiers.js +0 -262
  97. package/dist/modules/hallucination/llm-judge.js +0 -101
  98. package/dist/modules/index.js +0 -5
  99. package/dist/modules/indexer/cache.js +0 -40
  100. package/dist/modules/indexer/index.js +0 -3
  101. package/dist/modules/indexer/module.js +0 -245
  102. package/dist/modules/indexer/project-profile.js +0 -183
  103. package/dist/modules/indexer/walker.js +0 -101
  104. package/dist/modules/lsp/check-tool.js +0 -58
  105. package/dist/modules/lsp/client.js +0 -278
  106. package/dist/modules/lsp/command.js +0 -60
  107. package/dist/modules/lsp/config.js +0 -135
  108. package/dist/modules/lsp/index.js +0 -3
  109. package/dist/modules/lsp/module.js +0 -232
  110. package/dist/modules/lsp/probe.js +0 -76
  111. package/dist/modules/lsp/project-root.js +0 -32
  112. package/dist/modules/lsp/startup-check.js +0 -141
  113. package/dist/modules/lsp/types.js +0 -1
  114. package/dist/modules/mcp/client.js +0 -399
  115. package/dist/modules/mcp/index.js +0 -3
  116. package/dist/modules/mcp/module.js +0 -142
  117. package/dist/modules/mcp/registry.js +0 -15
  118. package/dist/modules/memory/index.js +0 -1
  119. package/dist/modules/memory/module.js +0 -96
  120. package/dist/modules/memory/search.js +0 -42
  121. package/dist/modules/memory/store.js +0 -69
  122. package/dist/modules/pipelines/engine.js +0 -60
  123. package/dist/modules/pipelines/index.js +0 -3
  124. package/dist/modules/pipelines/parser.js +0 -56
  125. package/dist/modules/pipelines/template.js +0 -14
  126. package/dist/modules/plugins/builtin/lint-on-write.js +0 -231
  127. package/dist/modules/plugins/builtin/notify.js +0 -9
  128. package/dist/modules/plugins/index.js +0 -1
  129. package/dist/modules/plugins/loader.js +0 -70
  130. package/dist/modules/plugins/manager.js +0 -217
  131. package/dist/modules/plugins/types.js +0 -1
  132. package/dist/modules/processes/detect.js +0 -34
  133. package/dist/modules/processes/index.js +0 -2
  134. package/dist/modules/processes/registry.js +0 -327
  135. package/dist/modules/processes/runner.js +0 -23
  136. package/dist/modules/registry.js +0 -47
  137. package/dist/modules/security/audit-log.js +0 -136
  138. package/dist/modules/security/audit-notifier.js +0 -292
  139. package/dist/modules/security/command-validator.js +0 -205
  140. package/dist/modules/security/content-scanner.js +0 -53
  141. package/dist/modules/security/data-sanitizer.js +0 -89
  142. package/dist/modules/security/encryption.js +0 -242
  143. package/dist/modules/security/index.js +0 -14
  144. package/dist/modules/security/network-validator.js +0 -71
  145. package/dist/modules/security/path-validator.js +0 -207
  146. package/dist/modules/security/rate-limiter.js +0 -119
  147. package/dist/modules/security/security-policies.js +0 -531
  148. package/dist/modules/security/session-encryption.js +0 -210
  149. package/dist/modules/security/session-isolation.js +0 -95
  150. package/dist/modules/session/index.js +0 -3
  151. package/dist/modules/session/manager.js +0 -172
  152. package/dist/modules/session/module.js +0 -24
  153. package/dist/modules/session/store.js +0 -222
  154. package/dist/modules/session/types.js +0 -1
  155. package/dist/modules/skills/index.js +0 -2
  156. package/dist/modules/skills/loader.js +0 -72
  157. package/dist/modules/skills/matcher.js +0 -27
  158. package/dist/modules/skills/module.js +0 -129
  159. package/dist/modules/types.js +0 -1
  160. package/dist/modules/updater/checker.js +0 -96
  161. package/dist/modules/updater/index.js +0 -2
  162. package/dist/modules/updater/module.js +0 -116
  163. package/dist/modules/user-profile/compressor.js +0 -16
  164. package/dist/modules/user-profile/index.js +0 -1
  165. package/dist/modules/user-profile/profile.js +0 -68
  166. package/dist/tools/approve.js +0 -32
  167. package/dist/tools/attach-image.js +0 -89
  168. package/dist/tools/bash.js +0 -496
  169. package/dist/tools/browser.js +0 -114
  170. package/dist/tools/chunk-query.js +0 -99
  171. package/dist/tools/create-dir.js +0 -55
  172. package/dist/tools/delete-file.js +0 -62
  173. package/dist/tools/download-file.js +0 -116
  174. package/dist/tools/edit-file.js +0 -79
  175. package/dist/tools/enable-tools.js +0 -58
  176. package/dist/tools/executor.js +0 -144
  177. package/dist/tools/file-info.js +0 -46
  178. package/dist/tools/filter-tools.js +0 -17
  179. package/dist/tools/glob-tool.js +0 -26
  180. package/dist/tools/grep-tool.js +0 -84
  181. package/dist/tools/hidden-tools-block.js +0 -37
  182. package/dist/tools/index.js +0 -78
  183. package/dist/tools/list-dir.js +0 -48
  184. package/dist/tools/load-skill.js +0 -42
  185. package/dist/tools/mcp-call.js +0 -68
  186. package/dist/tools/move-file.js +0 -85
  187. package/dist/tools/path-utils.js +0 -51
  188. package/dist/tools/pipeline-run.js +0 -144
  189. package/dist/tools/preview.js +0 -2
  190. package/dist/tools/process-kill.js +0 -29
  191. package/dist/tools/process-list.js +0 -36
  192. package/dist/tools/process-log.js +0 -45
  193. package/dist/tools/question.js +0 -140
  194. package/dist/tools/read-file.js +0 -91
  195. package/dist/tools/recall.js +0 -117
  196. package/dist/tools/registry.js +0 -47
  197. package/dist/tools/remember.js +0 -67
  198. package/dist/tools/scope-check.js +0 -30
  199. package/dist/tools/search-history.js +0 -84
  200. package/dist/tools/subagent.js +0 -196
  201. package/dist/tools/types.js +0 -1
  202. package/dist/tools/user-input.js +0 -123
  203. package/dist/tools/web-browse.js +0 -86
  204. package/dist/tools/web-fetch.js +0 -98
  205. package/dist/tools/web-search.js +0 -78
  206. package/dist/tools/write-file.js +0 -81
  207. package/dist/ui/box.js +0 -77
  208. package/dist/ui/colors.js +0 -4
  209. package/dist/ui/diff.js +0 -178
  210. package/dist/ui/index.js +0 -6
  211. package/dist/ui/line-editor.js +0 -703
  212. package/dist/ui/line-math.js +0 -69
  213. package/dist/ui/md-formatter.js +0 -212
  214. package/dist/ui/output.js +0 -13
  215. package/dist/ui/plan-view.js +0 -103
  216. package/dist/ui/renderer.js +0 -209
  217. package/dist/ui/spinner.js +0 -70
  218. package/dist/ui/table.js +0 -144
package/dist/main.js CHANGED
@@ -2263,9 +2263,7 @@ var init_defaults = __esm(() => {
2263
2263
  retry: {
2264
2264
  maxRetries: 3,
2265
2265
  baseDelay: 1000,
2266
- maxDelay: 30000,
2267
- maxStreamRetries: 2,
2268
- noDataTimeoutMs: 60000
2266
+ maxDelay: 30000
2269
2267
  },
2270
2268
  maxToolIterations: 1000,
2271
2269
  stuckThreshold: 6,
@@ -2398,8 +2396,6 @@ Use read_file on {path} to see the current content before editing — the target
2398
2396
  "error.llm_retries": "LLM request failed after retries",
2399
2397
  "error.llm_429": "Rate limit exceeded (HTTP 429) for {model} on {baseUrl}. The provider is throttling requests — free models are especially strict. Get an API key or switch to a paid/faster model: {baseUrl}",
2400
2398
  "error.no_response_body": "No response body stream",
2401
- "error.llm_stream_idle": "LLM stream stalled — no data for {timeout}ms",
2402
- "error.llm_timeout": "LLM request timed out ({timeout}ms)",
2403
2399
  "session.started": "Session started: {id}",
2404
2400
  "session.ended": "Session ended: {id}",
2405
2401
  "session.not_found": "Session not found: {id}",
@@ -2783,19 +2779,6 @@ Available commands:`,
2783
2779
  "repl.lsp_timeout": "timeout",
2784
2780
  "repl.lsp_failed": "did not start",
2785
2781
  "repl.lsp_unknown": "unknown",
2786
- "repl.lsp": "LSP server management (status, restart, check)",
2787
- "repl.lsp_usage": "Usage: /lsp [status|restart|check <path>]",
2788
- "repl.lsp_not_available": "LSP module not available",
2789
- "repl.lsp_status_header": "LSP Status:",
2790
- "repl.lsp_enabled": "Enabled:",
2791
- "repl.lsp_disabled_servers": "Disabled servers:",
2792
- "repl.lsp_failure_counts": "Failure counts:",
2793
- "repl.lsp_all_ok": "All servers operational",
2794
- "repl.lsp_restarting": "Resetting LSP server state...",
2795
- "repl.lsp_restarted": "LSP servers reset. Failed servers will be retried on next use.",
2796
- "repl.lsp_check_usage": "Usage: /lsp check <file-or-directory>",
2797
- "repl.lsp_checking": "Running LSP check on {path}...",
2798
- "repl.lsp_check_error": "LSP check failed: {error}",
2799
2782
  "repl.work_dir": "Dir:",
2800
2783
  "repl.agents_label": "Instructions:",
2801
2784
  "repl.not_found": "not found",
@@ -3023,6 +3006,10 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
3023
3006
  "tools.hidden_header": "Additional tools (enable on demand via enable_tools or route to subagent tool_tags):",
3024
3007
  "tool.friendly.enable_tools": "Enable tools",
3025
3008
  "cli.provider_base_hint": "Base URL set to: {baseUrl}",
3009
+ "cli.add_provider": "Add a provider to the config",
3010
+ "cli.provider_no_url": 'No base URL for provider "{name}". Pass --url.',
3011
+ "cli.provider_added": "Provider added: {name}",
3012
+ "cli.provider_switch_hint": "Switch to it with: mma provider use <name>",
3026
3013
  "repl.cost": "Total cost: {cost}",
3027
3014
  "repl.tokens": "Tokens used: {tokens}"
3028
3015
  };
@@ -3076,8 +3063,6 @@ var init_ru = __esm(() => {
3076
3063
  "error.llm_retries": "Запрос LLM не удался после повторов",
3077
3064
  "error.llm_429": "Превышен лимит запросов (HTTP 429) для {model} на {baseUrl}. Провайдер ограничивает трафик — особенно строгие free-модели. Получите API-ключ или переключитесь на платную/быструю модель: {baseUrl}",
3078
3065
  "error.no_response_body": "Нет потока тела ответа",
3079
- "error.llm_stream_idle": "Поток LLM завис — нет данных {timeout}мс",
3080
- "error.llm_timeout": "Время запроса LLM истекло ({timeout}мс)",
3081
3066
  "session.started": "Сессия начата: {id}",
3082
3067
  "session.ended": "Сессия завершена: {id}",
3083
3068
  "session.not_found": "Сессия не найдена: {id}",
@@ -3456,19 +3441,6 @@ var init_ru = __esm(() => {
3456
3441
  "repl.lsp_timeout": "таймаут",
3457
3442
  "repl.lsp_failed": "не стартовал",
3458
3443
  "repl.lsp_unknown": "неизвестно",
3459
- "repl.lsp": "Управление LSP-серверами (status, restart, check)",
3460
- "repl.lsp_usage": "Использование: /lsp [status|restart|check <путь>]",
3461
- "repl.lsp_not_available": "Модуль LSP недоступен",
3462
- "repl.lsp_status_header": "Статус LSP:",
3463
- "repl.lsp_enabled": "Включён:",
3464
- "repl.lsp_disabled_servers": "Отключённые серверы:",
3465
- "repl.lsp_failure_counts": "Количество ошибок:",
3466
- "repl.lsp_all_ok": "Все серверы работают",
3467
- "repl.lsp_restarting": "Сброс состояния LSP-серверов...",
3468
- "repl.lsp_restarted": "LSP-серверы сброшены. Упавшие серверы будут повторно запущены при следующем использовании.",
3469
- "repl.lsp_check_usage": "Использование: /lsp check <файл-или-каталог>",
3470
- "repl.lsp_checking": "Запуск LSP-проверки {path}...",
3471
- "repl.lsp_check_error": "LSP-проверка не удалась: {error}",
3472
3444
  "repl.work_dir": "Директория:",
3473
3445
  "repl.agents_label": "Инструкции:",
3474
3446
  "repl.not_found": "не найден",
@@ -3702,6 +3674,10 @@ var init_ru = __esm(() => {
3702
3674
  "tools.hidden_header": "Дополнительные тулы (включите по требованию через enable_tools или маршрутизируйте через subagent tool_tags):",
3703
3675
  "tool.friendly.enable_tools": "Включить тулы",
3704
3676
  "cli.provider_base_hint": "Базовый URL установлен: {baseUrl}",
3677
+ "cli.add_provider": "Добавить провайдера в конфиг",
3678
+ "cli.provider_no_url": 'Нет базового URL для провайдера "{name}". Укажите --url.',
3679
+ "cli.provider_added": "Провайдер добавлен: {name}",
3680
+ "cli.provider_switch_hint": "Переключитесь на него: mma provider use <имя>",
3705
3681
  "repl.cost": "Итого потрачено: {cost}",
3706
3682
  "repl.tokens": "Потрачено токенов: {tokens}"
3707
3683
  };
@@ -4643,6 +4619,26 @@ var init_app_logger = __esm(() => {
4643
4619
  };
4644
4620
  });
4645
4621
 
4622
+ // src/modules/providers/registry.ts
4623
+ class ProviderRegistry {
4624
+ specs = new Map;
4625
+ register(spec) {
4626
+ this.specs.set(spec.type, spec);
4627
+ }
4628
+ get(type) {
4629
+ return this.specs.get(type);
4630
+ }
4631
+ has(type) {
4632
+ return this.specs.has(type);
4633
+ }
4634
+ list() {
4635
+ return [...this.specs.values()];
4636
+ }
4637
+ types() {
4638
+ return [...this.specs.keys()];
4639
+ }
4640
+ }
4641
+
4646
4642
  // node_modules/base64-js/index.js
4647
4643
  var require_base64_js = __commonJS((exports) => {
4648
4644
  exports.byteLength = byteLength;
@@ -5204,9 +5200,7 @@ class OpenAICompatProvider {
5204
5200
  this.retryConfig = config.retry ?? {
5205
5201
  maxRetries: 3,
5206
5202
  baseDelay: 1000,
5207
- maxDelay: 30000,
5208
- maxStreamRetries: 2,
5209
- noDataTimeoutMs: 60000
5203
+ maxDelay: 30000
5210
5204
  };
5211
5205
  this.rateLimiter = createRateLimiter(config.rateLimits);
5212
5206
  }
@@ -5237,32 +5231,6 @@ class OpenAICompatProvider {
5237
5231
  }
5238
5232
  }
5239
5233
  async* doStream(messages, tools, signal, options) {
5240
- const { baseDelay, maxDelay, maxStreamRetries, noDataTimeoutMs } = this.retryConfig;
5241
- const streamRetries = maxStreamRetries ?? 2;
5242
- const idleTimeoutMs = noDataTimeoutMs ?? 60000;
5243
- for (let attempt = 0;; attempt++) {
5244
- let emitted = false;
5245
- const onEmit = () => {
5246
- emitted = true;
5247
- };
5248
- try {
5249
- const sawDone = yield* this.streamOnce(messages, tools, signal, options, onEmit, idleTimeoutMs);
5250
- if (sawDone || emitted)
5251
- return;
5252
- if (attempt >= streamRetries)
5253
- return;
5254
- } catch (err) {
5255
- if (err?.name === "AbortError" || err?.llmTerminal || signal?.aborted)
5256
- throw err;
5257
- if (emitted || attempt >= streamRetries)
5258
- throw err;
5259
- }
5260
- const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
5261
- const jitter = Math.random() * baseDelay * 0.1;
5262
- await this.sleep(delay + jitter, signal);
5263
- }
5264
- }
5265
- async* streamOnce(messages, tools, signal, options, onEmit, idleTimeoutMs) {
5266
5234
  const body = buildRequestBody({
5267
5235
  model: this.model,
5268
5236
  messages,
@@ -5278,11 +5246,8 @@ class OpenAICompatProvider {
5278
5246
  headers["Authorization"] = `Bearer ${this.config.apiKey}`;
5279
5247
  }
5280
5248
  const controller = new AbortController;
5281
- let timedOut = false;
5282
- const timeoutId = setTimeout(() => {
5283
- timedOut = true;
5284
- controller.abort();
5285
- }, REQUEST_TIMEOUT_MS);
5249
+ const totalTimeoutMs = 120000;
5250
+ const timeoutId = setTimeout(() => controller.abort(), totalTimeoutMs);
5286
5251
  const abortSignal = (() => {
5287
5252
  if (!signal)
5288
5253
  return controller.signal;
@@ -5295,31 +5260,20 @@ class OpenAICompatProvider {
5295
5260
  return controller.signal;
5296
5261
  }
5297
5262
  })();
5298
- let response;
5299
- try {
5300
- response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
5301
- method: "POST",
5302
- headers,
5303
- body: JSON.stringify(body),
5304
- signal: abortSignal
5305
- });
5306
- } catch (err) {
5307
- if (err?.name === "AbortError")
5308
- throw err;
5309
- const wrapped = err instanceof Error ? err : new Error(String(err));
5310
- wrapped.llmTerminal = true;
5311
- throw wrapped;
5312
- }
5263
+ const response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
5264
+ method: "POST",
5265
+ headers,
5266
+ body: JSON.stringify(body),
5267
+ signal: abortSignal
5268
+ });
5313
5269
  if (!response.ok) {
5314
5270
  clearTimeout(timeoutId);
5315
5271
  const errorText = await response.text();
5316
- const err = new Error(t("error.llm_api", {
5272
+ throw new Error(t("error.llm_api", {
5317
5273
  status: response.status,
5318
5274
  statusText: response.statusText,
5319
5275
  errorText
5320
5276
  }));
5321
- err.llmTerminal = true;
5322
- throw err;
5323
5277
  }
5324
5278
  const reader = response.body?.getReader();
5325
5279
  if (!reader) {
@@ -5330,29 +5284,9 @@ class OpenAICompatProvider {
5330
5284
  let buffer = "";
5331
5285
  const toolCallAccs = new Map;
5332
5286
  let usage;
5333
- let sawDone = false;
5334
- const readIdle = () => new Promise((resolve, reject) => {
5335
- const idleTimer = setTimeout(() => {
5336
- timedOut = true;
5337
- controller.abort();
5338
- }, idleTimeoutMs);
5339
- reader.read().then((result) => {
5340
- clearTimeout(idleTimer);
5341
- if (timedOut)
5342
- reject(new Error(t("error.llm_stream_idle", { timeout: idleTimeoutMs })));
5343
- else
5344
- resolve(result);
5345
- }, (err) => {
5346
- clearTimeout(idleTimer);
5347
- if (timedOut)
5348
- reject(new Error(t("error.llm_stream_idle", { timeout: idleTimeoutMs })));
5349
- else
5350
- reject(err);
5351
- });
5352
- });
5353
5287
  try {
5354
5288
  while (true) {
5355
- const { done, value } = await readIdle();
5289
+ const { done, value } = await reader.read();
5356
5290
  if (done)
5357
5291
  break;
5358
5292
  buffer += decoder.decode(value, { stream: true });
@@ -5364,10 +5298,8 @@ class OpenAICompatProvider {
5364
5298
  if (!trimmed || !trimmed.startsWith("data: "))
5365
5299
  continue;
5366
5300
  const data = trimmed.slice(6);
5367
- if (data === "[DONE]") {
5368
- sawDone = true;
5301
+ if (data === "[DONE]")
5369
5302
  continue;
5370
- }
5371
5303
  try {
5372
5304
  const parsed = JSON.parse(data);
5373
5305
  const choice = parsed.choices?.[0];
@@ -5384,7 +5316,6 @@ class OpenAICompatProvider {
5384
5316
  const delta = choice.delta || {};
5385
5317
  const finishReason = choice.finish_reason;
5386
5318
  if (delta.reasoning_content) {
5387
- onEmit();
5388
5319
  yield { type: "reasoning", content: delta.reasoning_content };
5389
5320
  }
5390
5321
  if (delta.tool_calls) {
@@ -5404,13 +5335,11 @@ class OpenAICompatProvider {
5404
5335
  }
5405
5336
  }
5406
5337
  if (delta.content) {
5407
- onEmit();
5408
5338
  yield { type: "text", content: delta.content };
5409
5339
  }
5410
5340
  if (finishReason === "tool_calls" && toolCallAccs.size > 0) {
5411
5341
  for (const [, acc] of toolCallAccs) {
5412
5342
  if (acc.name) {
5413
- onEmit();
5414
5343
  yield {
5415
5344
  type: "tool_call",
5416
5345
  toolCall: {
@@ -5427,14 +5356,12 @@ class OpenAICompatProvider {
5427
5356
  }
5428
5357
  }
5429
5358
  if (usage) {
5430
- onEmit();
5431
5359
  yield { type: "done", usage };
5432
5360
  }
5433
5361
  } finally {
5434
5362
  clearTimeout(timeoutId);
5435
5363
  reader.releaseLock();
5436
5364
  }
5437
- return sawDone;
5438
5365
  }
5439
5366
  async doNonStreaming(messages, tools, signal, options) {
5440
5367
  const body = buildRequestBody({
@@ -5451,30 +5378,12 @@ class OpenAICompatProvider {
5451
5378
  if (this.config.apiKey && this.config.apiKey !== "not-needed") {
5452
5379
  headers["Authorization"] = `Bearer ${this.config.apiKey}`;
5453
5380
  }
5454
- const controller = new AbortController;
5455
- let timedOut = false;
5456
- const timeoutId = setTimeout(() => {
5457
- timedOut = true;
5458
- controller.abort();
5459
- }, REQUEST_TIMEOUT_MS);
5460
- const abortSignal = (() => {
5461
- if (!signal)
5462
- return controller.signal;
5463
- try {
5464
- return AbortSignal.any([controller.signal, signal]);
5465
- } catch {
5466
- signal.addEventListener("abort", () => controller.abort(), {
5467
- once: true
5468
- });
5469
- return controller.signal;
5470
- }
5471
- })();
5472
5381
  try {
5473
5382
  const response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
5474
5383
  method: "POST",
5475
5384
  headers,
5476
5385
  body: JSON.stringify(body),
5477
- signal: abortSignal
5386
+ signal
5478
5387
  });
5479
5388
  if (!response.ok) {
5480
5389
  const errorText = await response.text();
@@ -5521,12 +5430,7 @@ class OpenAICompatProvider {
5521
5430
  }
5522
5431
  return chunks;
5523
5432
  } catch (err) {
5524
- if (timedOut && err?.name === "AbortError") {
5525
- throw new Error(t("error.llm_timeout", { timeout: REQUEST_TIMEOUT_MS }));
5526
- }
5527
5433
  throw err instanceof Error ? err : new Error(String(err));
5528
- } finally {
5529
- clearTimeout(timeoutId);
5530
5434
  }
5531
5435
  }
5532
5436
  countTokens(text) {
@@ -5610,13 +5514,281 @@ class OpenAICompatProvider {
5610
5514
  });
5611
5515
  }
5612
5516
  }
5613
- var REQUEST_TIMEOUT_MS = 120000;
5614
5517
  var init_openai_compat = __esm(() => {
5615
5518
  init_token_counter();
5616
5519
  init_i18n();
5617
5520
  init_rate_limiter();
5618
5521
  });
5619
5522
 
5523
+ // src/modules/providers/presets.ts
5524
+ function openaiCompat(opts) {
5525
+ const retry = opts.retry ?? {
5526
+ maxRetries: 3,
5527
+ baseDelay: 1000,
5528
+ maxDelay: 30000
5529
+ };
5530
+ const rateLimits = opts.rateLimits;
5531
+ return new OpenAICompatProvider({
5532
+ model: opts.model,
5533
+ baseUrl: opts.baseUrl,
5534
+ apiKey: opts.apiKey,
5535
+ contextWindow: opts.contextWindow,
5536
+ retry,
5537
+ rateLimits
5538
+ });
5539
+ }
5540
+ var OPENAI_COMPAT, OPENROUTER, OPENAI, ANTHROPIC, OPENCODE_ZEN, OPENCODE_GO, BUILTIN_PROVIDERS, HOSTED_BASE_URLS;
5541
+ var init_presets = __esm(() => {
5542
+ init_openai_compat();
5543
+ OPENAI_COMPAT = {
5544
+ type: "openai-compat",
5545
+ label: "OpenAI-compatible (LM Studio, Ollama, vLLM, etc.)",
5546
+ baseUrl: "",
5547
+ capabilities: {
5548
+ streaming: true,
5549
+ tools: true,
5550
+ vision: false,
5551
+ reasoningEffort: false,
5552
+ listModels: true,
5553
+ requiresKey: false,
5554
+ auth: "bearer"
5555
+ },
5556
+ create: openaiCompat
5557
+ };
5558
+ OPENROUTER = {
5559
+ type: "openrouter",
5560
+ label: "OpenRouter (openrouter.ai)",
5561
+ baseUrl: "https://openrouter.ai/api/v1",
5562
+ capabilities: {
5563
+ streaming: true,
5564
+ tools: true,
5565
+ vision: true,
5566
+ reasoningEffort: false,
5567
+ listModels: true,
5568
+ requiresKey: true,
5569
+ auth: "bearer"
5570
+ },
5571
+ create: openaiCompat
5572
+ };
5573
+ OPENAI = {
5574
+ type: "openai",
5575
+ label: "OpenAI API",
5576
+ baseUrl: "https://api.openai.com/v1",
5577
+ capabilities: {
5578
+ streaming: true,
5579
+ tools: true,
5580
+ vision: true,
5581
+ reasoningEffort: true,
5582
+ listModels: true,
5583
+ requiresKey: true,
5584
+ auth: "bearer"
5585
+ },
5586
+ create: openaiCompat
5587
+ };
5588
+ ANTHROPIC = {
5589
+ type: "anthropic",
5590
+ label: "Anthropic Claude",
5591
+ baseUrl: "https://api.anthropic.com",
5592
+ capabilities: {
5593
+ streaming: false,
5594
+ tools: false,
5595
+ vision: true,
5596
+ reasoningEffort: false,
5597
+ listModels: false,
5598
+ requiresKey: true,
5599
+ auth: "header"
5600
+ },
5601
+ create: openaiCompat
5602
+ };
5603
+ OPENCODE_ZEN = {
5604
+ type: "opencode-zen",
5605
+ label: "OpenCode Zen (opencode.ai/zen)",
5606
+ baseUrl: "https://opencode.ai/zen/v1",
5607
+ capabilities: {
5608
+ streaming: true,
5609
+ tools: true,
5610
+ vision: false,
5611
+ reasoningEffort: false,
5612
+ listModels: true,
5613
+ requiresKey: false,
5614
+ auth: "bearer"
5615
+ },
5616
+ create: openaiCompat
5617
+ };
5618
+ OPENCODE_GO = {
5619
+ type: "opencode-go",
5620
+ label: "OpenCode Go (opencode.ai/go)",
5621
+ baseUrl: "https://opencode.ai/zen/go/v1",
5622
+ capabilities: {
5623
+ streaming: true,
5624
+ tools: true,
5625
+ vision: false,
5626
+ reasoningEffort: false,
5627
+ listModels: true,
5628
+ requiresKey: false,
5629
+ auth: "bearer"
5630
+ },
5631
+ create: openaiCompat
5632
+ };
5633
+ BUILTIN_PROVIDERS = [
5634
+ OPENAI_COMPAT,
5635
+ OPENROUTER,
5636
+ OPENAI,
5637
+ ANTHROPIC,
5638
+ OPENCODE_ZEN,
5639
+ OPENCODE_GO
5640
+ ];
5641
+ HOSTED_BASE_URLS = {};
5642
+ for (const spec of BUILTIN_PROVIDERS) {
5643
+ if (spec.baseUrl)
5644
+ HOSTED_BASE_URLS[spec.type] = spec.baseUrl;
5645
+ }
5646
+ });
5647
+
5648
+ // src/modules/providers/create.ts
5649
+ var exports_create = {};
5650
+ __export(exports_create, {
5651
+ defaultRegistry: () => defaultRegistry,
5652
+ createProvider: () => createProvider
5653
+ });
5654
+ function createProvider(type, opts, registry = defaultRegistry()) {
5655
+ const spec = registry.get(type);
5656
+ if (!spec) {
5657
+ return BUILTIN_PROVIDERS[0].create(opts);
5658
+ }
5659
+ return spec.create(opts);
5660
+ }
5661
+ function defaultRegistry() {
5662
+ const registry = new ProviderRegistry;
5663
+ for (const spec of BUILTIN_PROVIDERS) {
5664
+ registry.register(spec);
5665
+ }
5666
+ return registry;
5667
+ }
5668
+ var init_create = __esm(() => {
5669
+ init_presets();
5670
+ });
5671
+
5672
+ // src/modules/providers/manager.ts
5673
+ class ProviderManager {
5674
+ entries;
5675
+ activeProviderName;
5676
+ model;
5677
+ opts;
5678
+ registry;
5679
+ cache = new Map;
5680
+ constructor(config, opts) {
5681
+ this.opts = opts;
5682
+ this.registry = opts.registry ?? defaultRegistry();
5683
+ this.entries = this.normalizeEntries(config);
5684
+ this.activeProviderName = this.resolveActive(config);
5685
+ this.model = "";
5686
+ }
5687
+ get activeModel() {
5688
+ return this.model;
5689
+ }
5690
+ get activeName() {
5691
+ return this.activeProviderName;
5692
+ }
5693
+ get active() {
5694
+ return this.build(this.activeProviderName);
5695
+ }
5696
+ get activeEntry() {
5697
+ const entry = this.entryByName(this.activeProviderName);
5698
+ if (!entry)
5699
+ throw new Error(`Unknown active provider "${this.activeProviderName}"`);
5700
+ return entry;
5701
+ }
5702
+ list() {
5703
+ return this.entries.map((e) => {
5704
+ const preset = this.registry.get(e.type);
5705
+ return { ...e, label: e.label || preset?.label || e.type };
5706
+ });
5707
+ }
5708
+ listNames() {
5709
+ return this.list().map((e) => e.label);
5710
+ }
5711
+ switch(name, model) {
5712
+ if (!this.entryByName(name)) {
5713
+ throw new Error(`Unknown provider "${name}"`);
5714
+ }
5715
+ this.activeProviderName = name;
5716
+ if (model !== undefined)
5717
+ this.model = model;
5718
+ return this.active;
5719
+ }
5720
+ setModel(model) {
5721
+ this.model = model;
5722
+ return this.active;
5723
+ }
5724
+ toConfig() {
5725
+ const active = this.activeEntry;
5726
+ return {
5727
+ active: this.activeProviderName,
5728
+ entries: this.entries,
5729
+ fallback: false,
5730
+ type: active.type,
5731
+ baseUrl: active.baseUrl,
5732
+ apiKey: active.apiKey
5733
+ };
5734
+ }
5735
+ normalizeEntries(config) {
5736
+ if (Array.isArray(config.entries) && config.entries.length > 0) {
5737
+ return config.entries.map((e) => ({ ...e, label: e.label || e.type }));
5738
+ }
5739
+ return [
5740
+ {
5741
+ type: config.type ?? "openai-compat",
5742
+ label: config.type ?? "openai-compat",
5743
+ baseUrl: config.baseUrl ?? "",
5744
+ apiKey: config.apiKey
5745
+ }
5746
+ ];
5747
+ }
5748
+ resolveActive(config) {
5749
+ if (config.active && this.entryByName(config.active))
5750
+ return config.active;
5751
+ const first = this.entries[0];
5752
+ return first ? first.label ?? "openai-compat" : "openai-compat";
5753
+ }
5754
+ entryByName(name) {
5755
+ return this.entries.find((e) => e.label === name || e.type === name);
5756
+ }
5757
+ build(name) {
5758
+ const entry = this.entryByName(name);
5759
+ if (!entry)
5760
+ throw new Error(`Unknown provider "${name}"`);
5761
+ const key = `${name}|${this.model}`;
5762
+ const cached = this.cache.get(key);
5763
+ if (cached)
5764
+ return cached;
5765
+ const provider = createProvider(entry.type, {
5766
+ model: this.model,
5767
+ baseUrl: entry.baseUrl,
5768
+ apiKey: entry.apiKey,
5769
+ contextWindow: entry.contextWindow ?? this.opts.contextWindow,
5770
+ retry: entry.retry ?? this.opts.retry,
5771
+ rateLimits: entry.rateLimits ?? this.opts.rateLimits
5772
+ }, this.registry);
5773
+ this.cache.set(key, provider);
5774
+ return provider;
5775
+ }
5776
+ resetCache() {
5777
+ this.cache.clear();
5778
+ }
5779
+ }
5780
+ var init_manager = __esm(() => {
5781
+ init_create();
5782
+ init_presets();
5783
+ });
5784
+
5785
+ // src/modules/providers/index.ts
5786
+ var init_providers = __esm(() => {
5787
+ init_create();
5788
+ init_manager();
5789
+ init_presets();
5790
+ });
5791
+
5620
5792
  // src/llm/model-loader.ts
5621
5793
  class ModelLoader {
5622
5794
  baseUrl;
@@ -6388,10 +6560,20 @@ var init_audit_log = __esm(() => {
6388
6560
  });
6389
6561
 
6390
6562
  // src/tools/path-utils.ts
6391
- import { resolve as resolve3, normalize as normalize2, dirname as dirname3, basename, sep } from "path";
6563
+ import { resolve as resolve3, normalize as normalize2, dirname as dirname3, basename, sep, isAbsolute } from "path";
6392
6564
  import { existsSync as existsSync9 } from "fs";
6393
6565
  function safeResolvePath(baseDir, userPath) {
6394
6566
  const norm = normalize2(userPath);
6567
+ if (isAbsolute(norm)) {
6568
+ if (existsSync9(norm) || existsSync9(dirname3(norm)))
6569
+ return norm;
6570
+ const stripped2 = norm.replace(/^[/\\]/, "");
6571
+ const relativeCandidate = resolve3(baseDir, stripped2);
6572
+ if (existsSync9(relativeCandidate) || existsSync9(dirname3(relativeCandidate))) {
6573
+ return relativeCandidate;
6574
+ }
6575
+ return norm;
6576
+ }
6395
6577
  const stripped = norm.replace(/^[/\\]/, "");
6396
6578
  const resolved = resolve3(baseDir, stripped);
6397
6579
  if (existsSync9(resolved) || existsSync9(dirname3(resolved)))
@@ -8375,9 +8557,11 @@ var init_prompt_builder = __esm(() => {
8375
8557
  // src/core/session-logger.ts
8376
8558
  class SessionLogger {
8377
8559
  session;
8560
+ getCaller;
8378
8561
  logger;
8379
- constructor(session, logger) {
8562
+ constructor(session, logger, getCaller) {
8380
8563
  this.session = session;
8564
+ this.getCaller = getCaller;
8381
8565
  this.logger = logger;
8382
8566
  this.bindSessionDir();
8383
8567
  }
@@ -8415,12 +8599,15 @@ class SessionLogger {
8415
8599
  });
8416
8600
  }
8417
8601
  logAssistant(content, reasoning, toolCalls, iteration) {
8602
+ const caller = this.getCaller?.();
8418
8603
  if (reasoning) {
8419
8604
  this.session?.appendLog({
8420
8605
  ts: new Date().toISOString(),
8421
8606
  type: "reasoning",
8422
8607
  content: reasoning,
8423
- iteration
8608
+ iteration,
8609
+ provider: caller?.provider,
8610
+ model: caller?.model
8424
8611
  });
8425
8612
  }
8426
8613
  this.session?.appendLog({
@@ -8434,14 +8621,19 @@ class SessionLogger {
8434
8621
  arguments: tc.arguments
8435
8622
  }))
8436
8623
  } : {},
8437
- iteration
8624
+ iteration,
8625
+ provider: caller?.provider,
8626
+ model: caller?.model
8438
8627
  });
8439
8628
  }
8440
8629
  saveAssistantMessage(content) {
8630
+ const caller = this.getCaller?.();
8441
8631
  this.session?.appendMessage({
8442
8632
  role: "assistant",
8443
8633
  content: content.slice(0, 500),
8444
- timestamp: new Date().toISOString()
8634
+ timestamp: new Date().toISOString(),
8635
+ provider: caller?.provider,
8636
+ model: caller?.model
8445
8637
  });
8446
8638
  }
8447
8639
  logToolDefs(toolCount, toolNames, iteration) {
@@ -8464,11 +8656,14 @@ class SessionLogger {
8464
8656
  });
8465
8657
  }
8466
8658
  logToolResult(call, result, duration, iteration) {
8659
+ const caller = this.getCaller?.();
8467
8660
  this.session?.appendMessage({
8468
8661
  role: "tool",
8469
8662
  content: result.output.slice(0, 500),
8470
8663
  name: call.name,
8471
- timestamp: new Date().toISOString()
8664
+ timestamp: new Date().toISOString(),
8665
+ provider: caller?.provider,
8666
+ model: caller?.model
8472
8667
  });
8473
8668
  this.session?.appendLog({
8474
8669
  ts: new Date().toISOString(),
@@ -8479,7 +8674,9 @@ class SessionLogger {
8479
8674
  content: result.output.slice(0, 1000),
8480
8675
  diff: result.diff,
8481
8676
  duration,
8482
- iteration
8677
+ iteration,
8678
+ provider: caller?.provider,
8679
+ model: caller?.model
8483
8680
  });
8484
8681
  }
8485
8682
  logCompaction(info) {
@@ -8506,6 +8703,8 @@ class SessionLogger {
8506
8703
  type: "context",
8507
8704
  content: info.kind === "start" ? "context snapshot at session start" : `context at iteration ${info.iteration}`,
8508
8705
  iteration: info.iteration,
8706
+ provider: info.provider,
8707
+ model: info.model,
8509
8708
  window: info.window,
8510
8709
  systemBudget: info.systemBudget,
8511
8710
  reserveBudget: info.reserveBudget,
@@ -8525,6 +8724,8 @@ class SessionLogger {
8525
8724
  ts: new Date().toISOString(),
8526
8725
  type: "llm_usage",
8527
8726
  iteration,
8727
+ provider: usage.provider,
8728
+ model: usage.model,
8528
8729
  promptTokens: usage.promptTokens,
8529
8730
  completionTokens: usage.completionTokens,
8530
8731
  totalTokens: usage.totalTokens,
@@ -9337,18 +9538,20 @@ class OrchestratorClient {
9337
9538
  this.config = config;
9338
9539
  if (config.model) {
9339
9540
  if (config.provider) {
9340
- this.provider = new OpenAICompatProvider({
9541
+ this.provider = createProvider(config.provider.type ?? "openai-compat", {
9341
9542
  model: config.model,
9342
9543
  baseUrl: config.provider.baseUrl || "http://localhost:1234/v1",
9343
9544
  apiKey: config.provider.apiKey,
9545
+ contextWindow: 32768,
9344
9546
  retry: config.retry
9345
9547
  });
9346
9548
  } else if (defaultProvider) {
9347
9549
  this.provider = defaultProvider;
9348
9550
  } else {
9349
- this.provider = new OpenAICompatProvider({
9551
+ this.provider = createProvider("openai-compat", {
9350
9552
  model: config.model,
9351
9553
  baseUrl: "http://localhost:1234/v1",
9554
+ contextWindow: 32768,
9352
9555
  retry: config.retry
9353
9556
  });
9354
9557
  }
@@ -9515,7 +9718,7 @@ Respond with JSON only:
9515
9718
 
9516
9719
  Max 3 re-plan cycles. After 3 cycles, return partial result.`;
9517
9720
  var init_orchestrator = __esm(() => {
9518
- init_openai_compat();
9721
+ init_create();
9519
9722
  init_esm();
9520
9723
  });
9521
9724
 
@@ -10213,7 +10416,7 @@ var init_stuck_detector = __esm(() => {
10213
10416
 
10214
10417
  // src/modules/artifacts/store.ts
10215
10418
  import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "node:fs";
10216
- import { resolve as resolve10, relative, isAbsolute } from "node:path";
10419
+ import { resolve as resolve10, relative, isAbsolute as isAbsolute2 } from "node:path";
10217
10420
 
10218
10421
  class ArtifactStore {
10219
10422
  root;
@@ -10233,7 +10436,7 @@ class ArtifactStore {
10233
10436
  const rel = relative(root, candidate);
10234
10437
  if (rel === "")
10235
10438
  return true;
10236
- return !rel.startsWith("..") && !isAbsolute(rel);
10439
+ return !rel.startsWith("..") && !isAbsolute2(rel);
10237
10440
  }
10238
10441
  save(name, content, ext = "md") {
10239
10442
  const safe = ArtifactStore.sanitizeName(name);
@@ -11580,6 +11783,8 @@ var init_pricing = __esm(() => {
11580
11783
  });
11581
11784
 
11582
11785
  // src/core/agent.ts
11786
+ import { join as join14 } from "path";
11787
+ import { homedir as homedir5 } from "os";
11583
11788
  function isToolCallJson(text) {
11584
11789
  const trimmed = text.trim();
11585
11790
  if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
@@ -11644,6 +11849,17 @@ class Agent {
11644
11849
  blocks: result.blocks
11645
11850
  };
11646
11851
  }
11852
+ callerProvenance() {
11853
+ const manager = this.deps.providerManager;
11854
+ if (manager) {
11855
+ return {
11856
+ provider: manager.activeName,
11857
+ model: manager.activeModel || this.deps.config.model
11858
+ };
11859
+ }
11860
+ const p = this.deps.config.provider;
11861
+ return { provider: p.type, model: this.deps.config.model };
11862
+ }
11647
11863
  logContextStat(kind, iteration, slog, blocks) {
11648
11864
  const cm = this.deps.contextManager;
11649
11865
  if (typeof cm.getSnapshot !== "function")
@@ -11651,9 +11867,12 @@ class Agent {
11651
11867
  const snap = cm.getSnapshot();
11652
11868
  const history = cm.getActiveHistory();
11653
11869
  const systemMsg = history.find((m) => m.role === "system");
11870
+ const caller = this.callerProvenance();
11654
11871
  slog.logContext({
11655
11872
  kind,
11656
11873
  iteration,
11874
+ provider: caller.provider,
11875
+ model: caller.model,
11657
11876
  window: snap.window,
11658
11877
  systemBudget: snap.budget.systemPrompt,
11659
11878
  reserveBudget: snap.budget.responseReserve,
@@ -11712,7 +11931,6 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
11712
11931
  onPhase?.(phase);
11713
11932
  }
11714
11933
  async run(input, onChunk, onMeta, onTool, onPhase) {
11715
- this.shutdownRequested = false;
11716
11934
  this.setScope();
11717
11935
  const {
11718
11936
  config,
@@ -11724,7 +11942,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
11724
11942
  sessionManager,
11725
11943
  baseDir
11726
11944
  } = this.deps;
11727
- const slog = new SessionLogger(sessionManager, logger);
11945
+ const slog = new SessionLogger(sessionManager, logger, () => this.callerProvenance());
11728
11946
  if (sessionManager && !sessionManager.getActive()) {
11729
11947
  sessionManager.create();
11730
11948
  logger.debug(`Session started: ${sessionManager.getActive()}`);
@@ -11786,7 +12004,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
11786
12004
  sessionManager,
11787
12005
  baseDir
11788
12006
  } = this.deps;
11789
- const slog = new SessionLogger(sessionManager, logger);
12007
+ const slog = new SessionLogger(sessionManager, logger, () => this.callerProvenance());
11790
12008
  this.abortController = new AbortController;
11791
12009
  let iteration = 0;
11792
12010
  let lastText = "";
@@ -11889,7 +12107,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
11889
12107
  const llmStart = Date.now();
11890
12108
  const promptBefore = apiPromptTokens;
11891
12109
  const completionBefore = apiCompletionTokens;
11892
- logger.logLLMRequest(config.model, history.length, input, "agent");
12110
+ logger.logLLMRequest(config.model, history.length, input, this.callerProvenance().provider);
11893
12111
  try {
11894
12112
  for await (const chunk of llmProvider.chat(history, allToolsForBudget, this.abortController?.signal)) {
11895
12113
  if (this.shutdownRequested)
@@ -11951,14 +12169,17 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
11951
12169
  this.emitPhase(iteration, "done", onPhase);
11952
12170
  }
11953
12171
  apiCompletionChars += (textContent || reasoningContent).length;
11954
- logger.logLLMResponse(config.model, (textContent || reasoningContent).length, Date.now() - llmStart, undefined, "agent");
12172
+ logger.logLLMResponse(config.model, (textContent || reasoningContent).length, Date.now() - llmStart, undefined, this.callerProvenance().provider);
11955
12173
  {
11956
12174
  const usagePrompt = apiPromptTokens - promptBefore;
11957
12175
  const usageCompletion = apiCompletionTokens - completionBefore;
11958
12176
  const source = usagePrompt > 0 || usageCompletion > 0 ? "api" : "estimate";
11959
12177
  const prompt = source === "api" ? usagePrompt : contextManager.getEstimatedTokens();
11960
12178
  const completion = source === "api" ? usageCompletion : Math.ceil((textContent || reasoningContent).length / 4);
12179
+ const caller = this.callerProvenance();
11961
12180
  slog.logLlmUsage(iteration, {
12181
+ provider: caller.provider,
12182
+ model: caller.model,
11962
12183
  promptTokens: prompt,
11963
12184
  completionTokens: completion,
11964
12185
  totalTokens: prompt + completion,
@@ -12075,6 +12296,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
12075
12296
  arguments: call.arguments
12076
12297
  });
12077
12298
  const tokensAfterTool = contextManager.getEstimatedTokens();
12299
+ const caller = this.callerProvenance();
12078
12300
  onTool?.({
12079
12301
  type: "end",
12080
12302
  tool: call.name,
@@ -12082,7 +12304,9 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
12082
12304
  duration,
12083
12305
  error: !result.success,
12084
12306
  ctxDelta: tokensAfterTool - tokensBeforeTool,
12085
- costUsd: this.costTracker.total
12307
+ costUsd: this.costTracker.total,
12308
+ provider: caller.provider,
12309
+ model: caller.model
12086
12310
  });
12087
12311
  summaries.push(`[Tool: ${call.name} (${JSON.stringify(call.arguments)}) → ${truncatedOutput.slice(0, 200)}]`);
12088
12312
  if (config.session.autoSave) {
@@ -12342,23 +12566,57 @@ ${warnLine}
12342
12566
  this.systemPromptAdded = false;
12343
12567
  }
12344
12568
  async reconfigure(config) {
12345
- const { OpenAICompatProvider: OpenAICompatProvider2 } = await Promise.resolve().then(() => (init_openai_compat(), exports_openai_compat));
12346
12569
  const { TokenCounter: TokenCounter2 } = await Promise.resolve().then(() => (init_token_counter(), exports_token_counter));
12347
- const newProvider = new OpenAICompatProvider2({
12348
- model: config.model,
12349
- baseUrl: config.provider.baseUrl,
12570
+ const manager = this.deps.providerManager;
12571
+ const newProvider = manager ? manager.setModel(config.model) : await this.buildLegacyProvider(config, config.model);
12572
+ this.deps.llmProvider = newProvider;
12573
+ this.deps.toolExecutor.updateProvider(newProvider);
12574
+ this.deps.toolExecutor.ctx.llmProvider = newProvider;
12575
+ const newTokenCounter = new TokenCounter2(config.model);
12576
+ this.deps.contextManager.resize(config.contextWindow, config.contextBudget, newTokenCounter);
12577
+ this.deps.config = config;
12578
+ this.costTracker.setModel(config.model);
12579
+ }
12580
+ async buildLegacyProvider(config, model) {
12581
+ const { createProvider: createProvider2 } = await Promise.resolve().then(() => (init_create(), exports_create));
12582
+ return createProvider2(config.provider.type ?? "openai-compat", {
12583
+ model,
12584
+ baseUrl: config.provider.baseUrl ?? "",
12350
12585
  apiKey: config.provider.apiKey,
12351
12586
  contextWindow: config.contextWindow,
12352
12587
  retry: config.retry,
12353
12588
  rateLimits: config.security?.rateLimits
12354
12589
  });
12590
+ }
12591
+ async setProvider(name, model) {
12592
+ const manager = this.deps.providerManager;
12593
+ if (!manager) {
12594
+ throw new Error("ProviderManager is not available (legacy single-provider config)");
12595
+ }
12596
+ const newProvider = manager.switch(name, model ?? this.deps.config.model);
12597
+ const config = this.deps.config;
12598
+ config.provider.active = name;
12599
+ config.provider.type = manager.activeEntry.type;
12600
+ config.provider.baseUrl = manager.activeEntry.baseUrl;
12601
+ config.provider.apiKey = manager.activeEntry.apiKey;
12355
12602
  this.deps.llmProvider = newProvider;
12356
12603
  this.deps.toolExecutor.updateProvider(newProvider);
12357
12604
  this.deps.toolExecutor.ctx.llmProvider = newProvider;
12358
- const newTokenCounter = new TokenCounter2(config.model);
12359
- this.deps.contextManager.resize(config.contextWindow, config.contextBudget, newTokenCounter);
12360
- this.deps.config = config;
12361
- this.costTracker.setModel(config.model);
12605
+ this.costTracker.setModel(newProvider.model);
12606
+ const configPath = join14(homedir5(), ".mma", "config.json");
12607
+ const { saveConfig: saveConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
12608
+ saveConfig2(config, configPath);
12609
+ }
12610
+ listProviders() {
12611
+ const manager = this.deps.providerManager;
12612
+ if (!manager)
12613
+ return [];
12614
+ return manager.list().map((e) => ({
12615
+ type: e.type,
12616
+ label: e.label,
12617
+ baseUrl: e.baseUrl,
12618
+ active: e.label === manager.activeName
12619
+ }));
12362
12620
  }
12363
12621
  setContext(messages) {
12364
12622
  const { contextManager } = this.deps;
@@ -12385,6 +12643,7 @@ ${warnLine}
12385
12643
  if (killed > 0) {
12386
12644
  logger.info(`Killed ${killed} background process(es) on shutdown`);
12387
12645
  }
12646
+ logger.closeSessionLog();
12388
12647
  pluginManager.runOnSessionEnd({
12389
12648
  logger,
12390
12649
  sessionManager: sessionManager?.getActiveMeta(),
@@ -12861,7 +13120,7 @@ ${lines.join(`
12861
13120
  }
12862
13121
  }
12863
13122
  var COMPACTION_INTERVAL = 15, KEEP_LAST_N = 6;
12864
- var init_manager = __esm(() => {
13123
+ var init_manager2 = __esm(() => {
12865
13124
  init_fact_extractor();
12866
13125
  });
12867
13126
 
@@ -12958,7 +13217,7 @@ var init_confidence = __esm(() => {
12958
13217
 
12959
13218
  // src/modules/hallucination/factual.ts
12960
13219
  import { existsSync as existsSync23, readdirSync as readdirSync7 } from "fs";
12961
- import { resolve as resolve14, isAbsolute as isAbsolute2, join as join14 } from "path";
13220
+ import { resolve as resolve14, isAbsolute as isAbsolute3, join as join15 } from "path";
12962
13221
 
12963
13222
  class FactualCheck {
12964
13223
  baseDir;
@@ -12997,7 +13256,7 @@ class FactualCheck {
12997
13256
  return { status: "pass" };
12998
13257
  }
12999
13258
  pathExists(fp) {
13000
- if (isAbsolute2(fp))
13259
+ if (isAbsolute3(fp))
13001
13260
  return existsSync23(fp);
13002
13261
  if (this.knownFiles.has(fp))
13003
13262
  return true;
@@ -13052,7 +13311,7 @@ class FactualCheck {
13052
13311
  for (const entry of entries) {
13053
13312
  if (count >= FactualCheck.MAX_INDEXED_FILES)
13054
13313
  break;
13055
- const full = join14(dir, entry.name);
13314
+ const full = join15(dir, entry.name);
13056
13315
  if (entry.isDirectory()) {
13057
13316
  if (!IGNORED_DIRS.has(entry.name)) {
13058
13317
  count = this.scanDir(full, index, count);
@@ -13226,7 +13485,7 @@ var init_detector = __esm(() => {
13226
13485
  });
13227
13486
 
13228
13487
  // src/modules/lsp/command.ts
13229
- import { delimiter, join as join15 } from "path";
13488
+ import { delimiter, join as join16 } from "path";
13230
13489
  import { existsSync as existsSync24 } from "fs";
13231
13490
  import { platform as platform3 } from "os";
13232
13491
  function resolveSpawnCommand(command, platformName = platform3(), pathEnv = process.env.PATH ?? "") {
@@ -13238,7 +13497,7 @@ function resolveSpawnCommand(command, platformName = platform3(), pathEnv = proc
13238
13497
  const dirs = pathEnv.split(delimiter).filter(Boolean);
13239
13498
  for (const dir of dirs) {
13240
13499
  for (const ext of WIN_EXTS) {
13241
- const candidate = join15(dir, `${command}${ext}`);
13500
+ const candidate = join16(dir, `${command}${ext}`);
13242
13501
  if (existsSync24(candidate))
13243
13502
  return `${command}${ext}`;
13244
13503
  }
@@ -13516,7 +13775,7 @@ class PluginManager {
13516
13775
  return chunk;
13517
13776
  }
13518
13777
  }
13519
- var init_manager2 = __esm(() => {
13778
+ var init_manager3 = __esm(() => {
13520
13779
  init_checker();
13521
13780
  });
13522
13781
 
@@ -13536,9 +13795,9 @@ Workflow rules:
13536
13795
  var init_subagent = __esm(() => {
13537
13796
  init_i18n();
13538
13797
  init_agent();
13539
- init_manager();
13540
- init_detector();
13541
13798
  init_manager2();
13799
+ init_detector();
13800
+ init_manager3();
13542
13801
  init_audit_log();
13543
13802
  init_session_isolation();
13544
13803
  init_store();
@@ -14611,8 +14870,8 @@ var init_pipeline_run = __esm(() => {
14611
14870
  init_engine();
14612
14871
  init_parser();
14613
14872
  init_agent();
14614
- init_manager();
14615
14873
  init_manager2();
14874
+ init_manager3();
14616
14875
  init_detector();
14617
14876
  init_audit_log();
14618
14877
  init_session_isolation();
@@ -15198,8 +15457,8 @@ ${JSON.stringify(result, null, 2)}`
15198
15457
 
15199
15458
  // src/tools/search-history.ts
15200
15459
  import * as fs from "fs";
15201
- import { join as join16 } from "path";
15202
- import { homedir as homedir5 } from "os";
15460
+ import { join as join17 } from "path";
15461
+ import { homedir as homedir6 } from "os";
15203
15462
  function searchFile(filePath, query, maxResults, results) {
15204
15463
  if (!fs.existsSync(filePath))
15205
15464
  return;
@@ -15243,7 +15502,7 @@ var init_search_history = __esm(() => {
15243
15502
  const query = String(args.query || "").toLowerCase();
15244
15503
  const maxResults = Number(args.maxResults) || 5;
15245
15504
  const sessionId = args.sessionId ? String(args.sessionId) : null;
15246
- const sessionDir = join16(homedir5(), ".mma", "sessions");
15505
+ const sessionDir = join17(homedir6(), ".mma", "sessions");
15247
15506
  const results = [];
15248
15507
  try {
15249
15508
  if (!fs.existsSync(sessionDir)) {
@@ -15258,7 +15517,7 @@ var init_search_history = __esm(() => {
15258
15517
  continue;
15259
15518
  if (sessionId && entry.name !== sessionId)
15260
15519
  continue;
15261
- const historyFile = join16(sessionDir, entry.name, "history.jsonl");
15520
+ const historyFile = join17(sessionDir, entry.name, "history.jsonl");
15262
15521
  searchFile(historyFile, query, maxResults, results);
15263
15522
  if (results.length >= maxResults)
15264
15523
  break;
@@ -15286,7 +15545,7 @@ var init_search_history = __esm(() => {
15286
15545
 
15287
15546
  // src/modules/memory/search.ts
15288
15547
  import { readFileSync as readFileSync13, existsSync as existsSync26 } from "fs";
15289
- import { join as join17 } from "path";
15548
+ import { join as join18 } from "path";
15290
15549
 
15291
15550
  class MemorySearch {
15292
15551
  memoryDir;
@@ -15297,7 +15556,7 @@ class MemorySearch {
15297
15556
  const results = [];
15298
15557
  const lowerQuery = query.toLowerCase();
15299
15558
  for (const name of MEMORY_FILES) {
15300
- const path = join17(this.memoryDir, `${name}.md`);
15559
+ const path = join18(this.memoryDir, `${name}.md`);
15301
15560
  if (!existsSync26(path))
15302
15561
  continue;
15303
15562
  const content = readFileSync13(path, "utf-8");
@@ -15309,7 +15568,7 @@ class MemorySearch {
15309
15568
  }
15310
15569
  }
15311
15570
  }
15312
- const prefsPath = join17(this.memoryDir, "preferences.json");
15571
+ const prefsPath = join18(this.memoryDir, "preferences.json");
15313
15572
  if (existsSync26(prefsPath)) {
15314
15573
  try {
15315
15574
  const prefs = JSON.parse(readFileSync13(prefsPath, "utf-8"));
@@ -15331,7 +15590,7 @@ var init_search = __esm(() => {
15331
15590
 
15332
15591
  // src/modules/memory/store.ts
15333
15592
  import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, existsSync as existsSync27, mkdirSync as mkdirSync13 } from "fs";
15334
- import { join as join18 } from "path";
15593
+ import { join as join19 } from "path";
15335
15594
 
15336
15595
  class MemoryStore {
15337
15596
  memoryDir;
@@ -15339,7 +15598,7 @@ class MemoryStore {
15339
15598
  this.memoryDir = memoryDir;
15340
15599
  this.ensureDir();
15341
15600
  for (const name of MEMORY_FILES2) {
15342
- const path = join18(this.memoryDir, `${name}.md`);
15601
+ const path = join19(this.memoryDir, `${name}.md`);
15343
15602
  if (!existsSync27(path)) {
15344
15603
  writeFileSync9(path, `# ${name.charAt(0).toUpperCase() + name.slice(1)}
15345
15604
 
@@ -15353,13 +15612,13 @@ class MemoryStore {
15353
15612
  }
15354
15613
  }
15355
15614
  read(name) {
15356
- const path = join18(this.memoryDir, `${name}.md`);
15615
+ const path = join19(this.memoryDir, `${name}.md`);
15357
15616
  if (!existsSync27(path))
15358
15617
  return "";
15359
15618
  return readFileSync14(path, "utf-8");
15360
15619
  }
15361
15620
  append(name, entry) {
15362
- const path = join18(this.memoryDir, `${name}.md`);
15621
+ const path = join19(this.memoryDir, `${name}.md`);
15363
15622
  const timestamp = new Date().toISOString().replace("T", " ").slice(0, 19);
15364
15623
  const formatted = `- **${timestamp}** — ${entry}
15365
15624
  `;
@@ -15370,7 +15629,7 @@ class MemoryStore {
15370
15629
  return searchModule.query(query);
15371
15630
  }
15372
15631
  prefsPath() {
15373
- return join18(this.memoryDir, "preferences.json");
15632
+ return join19(this.memoryDir, "preferences.json");
15374
15633
  }
15375
15634
  getPreferences() {
15376
15635
  const path = this.prefsPath();
@@ -15409,8 +15668,8 @@ var init_store2 = __esm(() => {
15409
15668
  });
15410
15669
 
15411
15670
  // src/tools/remember.ts
15412
- import { homedir as homedir6 } from "os";
15413
- import { join as join19 } from "path";
15671
+ import { homedir as homedir7 } from "os";
15672
+ import { join as join20 } from "path";
15414
15673
  var CATEGORIES, rememberTool;
15415
15674
  var init_remember = __esm(() => {
15416
15675
  init_i18n();
@@ -15449,7 +15708,7 @@ var init_remember = __esm(() => {
15449
15708
  if (!CATEGORIES.includes(category)) {
15450
15709
  return { success: false, output: t("tool.invalid_params") };
15451
15710
  }
15452
- const memoryDir = join19(homedir6(), ".mma", "memory");
15711
+ const memoryDir = join20(homedir7(), ".mma", "memory");
15453
15712
  const store = new MemoryStore(memoryDir);
15454
15713
  try {
15455
15714
  if (category === "preferences") {
@@ -15481,8 +15740,8 @@ var init_remember = __esm(() => {
15481
15740
  });
15482
15741
 
15483
15742
  // src/tools/recall.ts
15484
- import { homedir as homedir7 } from "os";
15485
- import { join as join20 } from "path";
15743
+ import { homedir as homedir8 } from "os";
15744
+ import { join as join21 } from "path";
15486
15745
  function formatAll(store) {
15487
15746
  const parts = [];
15488
15747
  const prefs = store.getPreferences();
@@ -15566,7 +15825,7 @@ var init_recall = __esm(() => {
15566
15825
  handler: async (_ctx, args) => {
15567
15826
  const query = args.query ? String(args.query) : "";
15568
15827
  const category = args.category ? String(args.category) : "";
15569
- const memoryDir = join20(homedir7(), ".mma", "memory");
15828
+ const memoryDir = join21(homedir8(), ".mma", "memory");
15570
15829
  const store = new MemoryStore(memoryDir);
15571
15830
  try {
15572
15831
  if (!query && !category) {
@@ -15617,13 +15876,13 @@ __export(exports_bridge_client, {
15617
15876
  });
15618
15877
  import { spawn as spawn4 } from "child_process";
15619
15878
  import { createInterface } from "readline";
15620
- import { dirname as dirname10, join as join21 } from "path";
15879
+ import { dirname as dirname10, join as join22 } from "path";
15621
15880
  import { fileURLToPath } from "url";
15622
15881
  function bridgeScriptPath() {
15623
15882
  const dir = dirname10(fileURLToPath(import.meta.url));
15624
15883
  const candidates = [
15625
- join21(dir, "bridge-server.mjs"),
15626
- join21(dir, "modules", "browser", "bridge-server.mjs")
15884
+ join22(dir, "bridge-server.mjs"),
15885
+ join22(dir, "modules", "browser", "bridge-server.mjs")
15627
15886
  ];
15628
15887
  return pickExistingPath(candidates);
15629
15888
  }
@@ -16177,15 +16436,15 @@ function buildTextExtractionScript() {
16177
16436
 
16178
16437
  // src/modules/browser/cookie-store.ts
16179
16438
  import { readFile, writeFile, mkdir } from "fs/promises";
16180
- import { join as join22 } from "path";
16439
+ import { join as join23 } from "path";
16181
16440
 
16182
16441
  class CookieStore {
16183
16442
  filePath;
16184
16443
  constructor(cookieDir) {
16185
- this.filePath = join22(cookieDir, "cookies.json");
16444
+ this.filePath = join23(cookieDir, "cookies.json");
16186
16445
  }
16187
16446
  async save(cookies) {
16188
- await mkdir(join22(this.filePath, ".."), { recursive: true });
16447
+ await mkdir(join23(this.filePath, ".."), { recursive: true });
16189
16448
  await writeFile(this.filePath, JSON.stringify(cookies, null, 2), "utf-8");
16190
16449
  }
16191
16450
  async load() {
@@ -16540,10 +16799,10 @@ var init_session = __esm(() => {
16540
16799
  });
16541
16800
 
16542
16801
  // src/tools/browser.ts
16543
- import { join as join23 } from "path";
16802
+ import { join as join24 } from "path";
16544
16803
  function getSession(ctx) {
16545
16804
  if (!session) {
16546
- const cookieDir = join23(ctx.baseDir, ".mma", "browser");
16805
+ const cookieDir = join24(ctx.baseDir, ".mma", "browser");
16547
16806
  session = new BrowserSession({
16548
16807
  ...DEFAULT_BROWSER_CONFIG,
16549
16808
  headless: ctx.config.browser?.headless ?? true,
@@ -16691,8 +16950,8 @@ async function readClipboardFallback() {
16691
16950
  const { platform: platform5 } = await import("os");
16692
16951
  const { execSync } = await import("child_process");
16693
16952
  const { readFileSync: readFileSync16, unlinkSync: unlinkSync4 } = await import("fs");
16694
- const { join: join24 } = await import("path");
16695
- const tmpPath = join24(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
16953
+ const { join: join25 } = await import("path");
16954
+ const tmpPath = join25(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
16696
16955
  try {
16697
16956
  if (platform5() === "linux") {
16698
16957
  execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, {
@@ -17074,7 +17333,7 @@ class ModuleRegistry {
17074
17333
 
17075
17334
  // src/modules/plugins/loader.ts
17076
17335
  import { readdirSync as readdirSync9, existsSync as existsSync30, statSync as statSync5 } from "fs";
17077
- import { join as join24, basename as basename3 } from "path";
17336
+ import { join as join25, basename as basename3 } from "path";
17078
17337
 
17079
17338
  class PluginLoader {
17080
17339
  loadFromDir(dirPath, pluginManager, logger, options) {
@@ -17082,7 +17341,7 @@ class PluginLoader {
17082
17341
  return;
17083
17342
  const entries = readdirSync9(dirPath).sort();
17084
17343
  for (const entry of entries) {
17085
- const fullPath = join24(dirPath, entry);
17344
+ const fullPath = join25(dirPath, entry);
17086
17345
  const stat = statSync5(fullPath);
17087
17346
  if (stat.isFile()) {
17088
17347
  if (!entry.endsWith(".ts") && !entry.endsWith(".js"))
@@ -17098,7 +17357,7 @@ class PluginLoader {
17098
17357
  }
17099
17358
  findEntryFile(dir) {
17100
17359
  for (const name of FOLDER_ENTRY_NAMES) {
17101
- const candidate = join24(dir, name);
17360
+ const candidate = join25(dir, name);
17102
17361
  if (existsSync30(candidate))
17103
17362
  return candidate;
17104
17363
  }
@@ -17142,7 +17401,7 @@ var init_loader = __esm(() => {
17142
17401
  // src/modules/plugins/builtin/lint-on-write.ts
17143
17402
  import { spawn as spawn5, execSync } from "child_process";
17144
17403
  import { existsSync as existsSync31, readFileSync as readFileSync16 } from "fs";
17145
- import { resolve as resolve18, extname as extname4, join as join25 } from "path";
17404
+ import { resolve as resolve18, extname as extname4, join as join26 } from "path";
17146
17405
  import { platform as platform5 } from "os";
17147
17406
  function contentHash(content) {
17148
17407
  let h = 5381;
@@ -17254,7 +17513,7 @@ class LintOnWritePlugin {
17254
17513
  }
17255
17514
  async runProjectLint(ctx, result, signal) {
17256
17515
  try {
17257
- const packageJsonPath = join25(ctx.baseDir, "package.json");
17516
+ const packageJsonPath = join26(ctx.baseDir, "package.json");
17258
17517
  if (!existsSync31(packageJsonPath)) {
17259
17518
  return;
17260
17519
  }
@@ -17280,7 +17539,7 @@ class LintOnWritePlugin {
17280
17539
  }
17281
17540
  async runProjectTypeCheck(filePath, baseDir, result, signal) {
17282
17541
  const projectRoot = findProjectRoot(filePath, baseDir, ["tsconfig.json", "package.json"]);
17283
- const tsconfigPath = join25(projectRoot, "tsconfig.json");
17542
+ const tsconfigPath = join26(projectRoot, "tsconfig.json");
17284
17543
  if (!existsSync31(tsconfigPath)) {
17285
17544
  return;
17286
17545
  }
@@ -17528,7 +17787,7 @@ var init_tracker = () => {};
17528
17787
 
17529
17788
  // src/modules/execution/plan-store.ts
17530
17789
  import { readFileSync as readFileSync17, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync32, readdirSync as readdirSync10, rmSync } from "fs";
17531
- import { join as join26 } from "path";
17790
+ import { join as join27 } from "path";
17532
17791
  function readPlanFile(path, fallbackBaseDir) {
17533
17792
  try {
17534
17793
  const raw = readFileSync17(path, "utf-8");
@@ -17556,7 +17815,7 @@ function listDir(dir, baseDir) {
17556
17815
  if (!existsSync32(dir))
17557
17816
  return [];
17558
17817
  const files = readdirSync10(dir).filter((f) => f.endsWith(".json"));
17559
- return files.map((f) => readPlanFile(join26(dir, f), baseDir)).filter((p) => p !== null);
17818
+ return files.map((f) => readPlanFile(join27(dir, f), baseDir)).filter((p) => p !== null);
17560
17819
  }
17561
17820
  function toMeta(plan, status) {
17562
17821
  return {
@@ -17577,21 +17836,21 @@ class PlanStore {
17577
17836
  archiveDir;
17578
17837
  legacyPath;
17579
17838
  constructor(baseDir) {
17580
- const mmaDir = join26(baseDir, ".mma");
17839
+ const mmaDir = join27(baseDir, ".mma");
17581
17840
  if (!existsSync32(mmaDir))
17582
17841
  mkdirSync14(mmaDir, { recursive: true });
17583
17842
  this.baseDir = baseDir;
17584
- this.plansDir = join26(mmaDir, "plans");
17585
- this.draftsDir = join26(this.plansDir, "drafts");
17586
- this.archiveDir = join26(this.plansDir, "archive");
17587
- this.legacyPath = join26(mmaDir, LEGACY_FILE);
17843
+ this.plansDir = join27(mmaDir, "plans");
17844
+ this.draftsDir = join27(this.plansDir, "drafts");
17845
+ this.archiveDir = join27(this.plansDir, "archive");
17846
+ this.legacyPath = join27(mmaDir, LEGACY_FILE);
17588
17847
  for (const dir of [this.plansDir, this.draftsDir, this.archiveDir]) {
17589
17848
  if (!existsSync32(dir))
17590
17849
  mkdirSync14(dir, { recursive: true });
17591
17850
  }
17592
17851
  }
17593
17852
  activePath() {
17594
- return join26(this.plansDir, "active.json");
17853
+ return join27(this.plansDir, "active.json");
17595
17854
  }
17596
17855
  saveActive(plan) {
17597
17856
  writePlanFile(this.activePath(), plan);
@@ -17621,14 +17880,14 @@ class PlanStore {
17621
17880
  rmSync(p, { force: true });
17622
17881
  }
17623
17882
  saveDraft(plan) {
17624
- writePlanFile(join26(this.draftsDir, `${plan.id}.json`), plan);
17883
+ writePlanFile(join27(this.draftsDir, `${plan.id}.json`), plan);
17625
17884
  }
17626
17885
  loadDraft(id) {
17627
- const p = join26(this.draftsDir, `${id}.json`);
17886
+ const p = join27(this.draftsDir, `${id}.json`);
17628
17887
  return existsSync32(p) ? readPlanFile(p, this.baseDir) : null;
17629
17888
  }
17630
17889
  removeDraft(id) {
17631
- const p = join26(this.draftsDir, `${id}.json`);
17890
+ const p = join27(this.draftsDir, `${id}.json`);
17632
17891
  if (existsSync32(p))
17633
17892
  rmSync(p, { force: true });
17634
17893
  }
@@ -17636,7 +17895,7 @@ class PlanStore {
17636
17895
  return listDir(this.draftsDir, this.baseDir);
17637
17896
  }
17638
17897
  archivePlan(plan) {
17639
- writePlanFile(join26(this.archiveDir, `${plan.id}.json`), plan);
17898
+ writePlanFile(join27(this.archiveDir, `${plan.id}.json`), plan);
17640
17899
  this.removeDraft(plan.id);
17641
17900
  const active = this.loadActive();
17642
17901
  if (active && active.id === plan.id) {
@@ -17647,7 +17906,7 @@ class PlanStore {
17647
17906
  return listDir(this.archiveDir, this.baseDir);
17648
17907
  }
17649
17908
  removeArchived(id) {
17650
- const p = join26(this.archiveDir, `${id}.json`);
17909
+ const p = join27(this.archiveDir, `${id}.json`);
17651
17910
  if (existsSync32(p))
17652
17911
  rmSync(p, { force: true });
17653
17912
  }
@@ -17680,12 +17939,12 @@ class PlanStore {
17680
17939
  this.clearActive();
17681
17940
  return "active";
17682
17941
  }
17683
- const draftPath = join26(this.draftsDir, `${id}.json`);
17942
+ const draftPath = join27(this.draftsDir, `${id}.json`);
17684
17943
  if (existsSync32(draftPath)) {
17685
17944
  rmSync(draftPath, { force: true });
17686
17945
  return "draft";
17687
17946
  }
17688
- const archivedPath = join26(this.archiveDir, `${id}.json`);
17947
+ const archivedPath = join27(this.archiveDir, `${id}.json`);
17689
17948
  if (existsSync32(archivedPath)) {
17690
17949
  rmSync(archivedPath, { force: true });
17691
17950
  return "archived";
@@ -19159,8 +19418,8 @@ var init_module = __esm(() => {
19159
19418
 
19160
19419
  // src/modules/security/session-encryption.ts
19161
19420
  import { readFileSync as readFileSync19, writeFileSync as writeFileSync11, existsSync as existsSync34, readdirSync as readdirSync11, unlinkSync as unlinkSync4 } from "fs";
19162
- import { join as join27 } from "path";
19163
- import { homedir as homedir8 } from "os";
19421
+ import { join as join28 } from "path";
19422
+ import { homedir as homedir9 } from "os";
19164
19423
 
19165
19424
  class SessionFileEncryptor {
19166
19425
  config;
@@ -19168,7 +19427,7 @@ class SessionFileEncryptor {
19168
19427
  constructor(config) {
19169
19428
  this.config = { ...DEFAULT_SESSION_ENCRYPTION, ...config };
19170
19429
  this.encryptor = new ConfigEncryptor({
19171
- keyPath: config?.keyPath || join27(homedir8(), ".mma", ".session-encryption-key")
19430
+ keyPath: config?.keyPath || join28(homedir9(), ".mma", ".session-encryption-key")
19172
19431
  });
19173
19432
  }
19174
19433
  isEnabled() {
@@ -19254,7 +19513,7 @@ class SessionFileEncryptor {
19254
19513
  return;
19255
19514
  const files = readdirSync11(sessionDir);
19256
19515
  for (const file of files) {
19257
- const filePath = join27(sessionDir, file);
19516
+ const filePath = join28(sessionDir, file);
19258
19517
  if (existsSync34(filePath) && !file.endsWith(".enc")) {
19259
19518
  try {
19260
19519
  const content = readFileSync19(filePath, "utf8");
@@ -19271,7 +19530,7 @@ class SessionFileEncryptor {
19271
19530
  const files = readdirSync11(sessionDir);
19272
19531
  for (const file of files) {
19273
19532
  if (file.endsWith(".enc")) {
19274
- const encFilePath = join27(sessionDir, file);
19533
+ const encFilePath = join28(sessionDir, file);
19275
19534
  const decFilePath = encFilePath.slice(0, -4);
19276
19535
  try {
19277
19536
  const content = readFileSync19(encFilePath, "utf8");
@@ -19304,7 +19563,7 @@ import {
19304
19563
  writeFileSync as writeFileSync12,
19305
19564
  appendFileSync as appendFileSync6
19306
19565
  } from "fs";
19307
- import { join as join28 } from "path";
19566
+ import { join as join29 } from "path";
19308
19567
  import { gzipSync } from "zlib";
19309
19568
 
19310
19569
  class SessionStore {
@@ -19318,7 +19577,7 @@ class SessionStore {
19318
19577
  }
19319
19578
  }
19320
19579
  getSessionDir(id) {
19321
- return join28(this.baseDir, id);
19580
+ return join29(this.baseDir, id);
19322
19581
  }
19323
19582
  updateEncryption(config) {
19324
19583
  if (config?.enabled) {
@@ -19334,16 +19593,16 @@ class SessionStore {
19334
19593
  mkdirSync15(this.baseDir, { recursive: true });
19335
19594
  }
19336
19595
  sessionDir(id) {
19337
- return join28(this.baseDir, id);
19596
+ return join29(this.baseDir, id);
19338
19597
  }
19339
19598
  metaPath(id) {
19340
- return join28(this.sessionDir(id), "meta.json");
19599
+ return join29(this.sessionDir(id), "meta.json");
19341
19600
  }
19342
19601
  historyPath(id) {
19343
- return join28(this.sessionDir(id), "history.jsonl");
19602
+ return join29(this.sessionDir(id), "history.jsonl");
19344
19603
  }
19345
19604
  sessionLogPath(id) {
19346
- return join28(this.sessionDir(id), "session.jsonl");
19605
+ return join29(this.sessionDir(id), "session.jsonl");
19347
19606
  }
19348
19607
  sessionExists(id) {
19349
19608
  return existsSync35(this.metaPath(id));
@@ -19497,7 +19756,7 @@ class SessionStore {
19497
19756
  if (existsSync35(historyPath)) {
19498
19757
  const content = readFileSync20(historyPath, "utf-8");
19499
19758
  const compressed = gzipSync(content);
19500
- const gzPath = join28(this.baseDir, `${session2.id}.jsonl.gz`);
19759
+ const gzPath = join29(this.baseDir, `${session2.id}.jsonl.gz`);
19501
19760
  writeFileSync12(gzPath, compressed);
19502
19761
  rmSync2(historyPath);
19503
19762
  }
@@ -19650,7 +19909,7 @@ class SessionManager {
19650
19909
  }
19651
19910
  }
19652
19911
  }
19653
- var init_manager3 = __esm(() => {
19912
+ var init_manager4 = __esm(() => {
19654
19913
  init_i18n();
19655
19914
  init_session_isolation();
19656
19915
  });
@@ -19686,7 +19945,7 @@ var init_module2 = __esm(() => {
19686
19945
  // src/modules/session/index.ts
19687
19946
  var init_session2 = __esm(() => {
19688
19947
  init_store3();
19689
- init_manager3();
19948
+ init_manager4();
19690
19949
  init_module2();
19691
19950
  });
19692
19951
 
@@ -19708,8 +19967,8 @@ class ProfileCompressor {
19708
19967
 
19709
19968
  // src/modules/user-profile/profile.ts
19710
19969
  import { readFileSync as readFileSync21, writeFileSync as writeFileSync13, existsSync as existsSync36, mkdirSync as mkdirSync16 } from "fs";
19711
- import { join as join29 } from "path";
19712
- import { homedir as homedir9, hostname, platform as platform7, type } from "os";
19970
+ import { join as join30 } from "path";
19971
+ import { homedir as homedir10, hostname, platform as platform7, type } from "os";
19713
19972
  import { env } from "process";
19714
19973
 
19715
19974
  class UserProfile {
@@ -19725,7 +19984,7 @@ class UserProfile {
19725
19984
  os: `${type()} ${hostname()}`,
19726
19985
  hostname: hostname(),
19727
19986
  shell: env.SHELL || env.ComSpec || "unknown",
19728
- home: homedir9(),
19987
+ home: homedir10(),
19729
19988
  nodeVersion: process.version,
19730
19989
  preferences: { ...this.preferences }
19731
19990
  };
@@ -19735,10 +19994,10 @@ class UserProfile {
19735
19994
  if (!existsSync36(this.profileDir)) {
19736
19995
  mkdirSync16(this.profileDir, { recursive: true });
19737
19996
  }
19738
- writeFileSync13(join29(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
19997
+ writeFileSync13(join30(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
19739
19998
  }
19740
19999
  load() {
19741
- const path = join29(this.profileDir, "profile.json");
20000
+ const path = join30(this.profileDir, "profile.json");
19742
20001
  if (!existsSync36(path))
19743
20002
  return null;
19744
20003
  try {
@@ -19778,7 +20037,7 @@ var init_profile = () => {};
19778
20037
 
19779
20038
  // src/modules/skills/loader.ts
19780
20039
  import { readdirSync as readdirSync13, readFileSync as readFileSync22, existsSync as existsSync37, statSync as statSync6 } from "fs";
19781
- import { join as join30 } from "path";
20040
+ import { join as join31 } from "path";
19782
20041
 
19783
20042
  class SkillsLoader {
19784
20043
  loadFromDir(dirPath) {
@@ -19791,7 +20050,7 @@ class SkillsLoader {
19791
20050
  scanDir(dirPath, skills) {
19792
20051
  const entries = readdirSync13(dirPath);
19793
20052
  for (const entry of entries) {
19794
- const fullPath = join30(dirPath, entry);
20053
+ const fullPath = join31(dirPath, entry);
19795
20054
  const stat = statSync6(fullPath);
19796
20055
  if (stat.isDirectory()) {
19797
20056
  this.scanDir(fullPath, skills);
@@ -20040,10 +20299,6 @@ import { resolve as resolve20 } from "path";
20040
20299
  import { platform as platform8 } from "os";
20041
20300
 
20042
20301
  class LspClient {
20043
- logger = null;
20044
- setLogger(logger) {
20045
- this.logger = logger;
20046
- }
20047
20302
  process = null;
20048
20303
  requestId = 0;
20049
20304
  pending = new Map;
@@ -20103,25 +20358,11 @@ class LspClient {
20103
20358
  try {
20104
20359
  await this.sendRequest("initialize", initParams, timeout);
20105
20360
  } catch (e) {
20106
- const msg = e instanceof Error ? e.message : String(e);
20107
- this.logger?.warn(`LSP initialize failed (attempt 1): ${msg}`, {
20108
- command: config.command,
20109
- projectRoot
20110
- });
20111
20361
  if (!(e instanceof Error) || !e.message.includes("initialize"))
20112
20362
  throw e;
20113
20363
  await this.shutdown();
20114
20364
  await this.startServer(config, projectRoot);
20115
- try {
20116
- await this.sendRequest("initialize", initParams, timeout);
20117
- } catch (retryErr) {
20118
- const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
20119
- this.logger?.error(`LSP initialize failed (attempt 2, giving up): ${retryMsg}`, {
20120
- command: config.command,
20121
- projectRoot
20122
- });
20123
- throw retryErr;
20124
- }
20365
+ await this.sendRequest("initialize", initParams, timeout);
20125
20366
  }
20126
20367
  this.initialized = true;
20127
20368
  }
@@ -20159,11 +20400,8 @@ class LspClient {
20159
20400
  });
20160
20401
  this.process = proc;
20161
20402
  setTimeout(() => {
20162
- if (!this.initialized && this.process) {
20163
- const msg = "LSP server start timeout";
20164
- this.logger?.error(msg, { command: config.command, projectRoot, timeout: config.timeout ?? 1e4 });
20165
- reject(new Error(msg));
20166
- }
20403
+ if (!this.initialized && this.process)
20404
+ reject(new Error("LSP server start timeout"));
20167
20405
  }, config.timeout ?? 1e4);
20168
20406
  });
20169
20407
  }
@@ -20202,9 +20440,7 @@ class LspClient {
20202
20440
  try {
20203
20441
  const msg = JSON.parse(body);
20204
20442
  this.handleMessage(msg);
20205
- } catch (e) {
20206
- this.logger?.debug(`LSP JSON parse error: ${e instanceof Error ? e.message : String(e)}`);
20207
- }
20443
+ } catch {}
20208
20444
  }
20209
20445
  }
20210
20446
  handleMessage(msg) {
@@ -20242,9 +20478,7 @@ class LspClient {
20242
20478
  setTimeout(() => {
20243
20479
  if (this.pending.has(id)) {
20244
20480
  this.pending.delete(id);
20245
- const msg = `LSP request timeout: ${method}`;
20246
- this.logger?.warn(msg, { method, timeout });
20247
- reject(new Error(msg));
20481
+ reject(new Error(`LSP request timeout: ${method}`));
20248
20482
  }
20249
20483
  }, timeout);
20250
20484
  });
@@ -20254,37 +20488,27 @@ class LspClient {
20254
20488
  this.write(message);
20255
20489
  }
20256
20490
  write(message) {
20257
- if (!this.process?.stdin?.writable) {
20258
- this.logger?.debug("LSP write failed: process stdin not writable");
20491
+ if (!this.process?.stdin?.writable)
20259
20492
  return;
20260
- }
20261
20493
  const header = `Content-Length: ${Buffer.byteLength(message)}\r
20262
20494
  \r
20263
20495
  `;
20264
20496
  try {
20265
20497
  this.process.stdin.write(header + message);
20266
- } catch (e) {
20267
- this.logger?.debug(`LSP write error: ${e instanceof Error ? e.message : String(e)}`);
20268
- }
20498
+ } catch {}
20269
20499
  }
20270
20500
  async shutdown() {
20271
20501
  try {
20272
20502
  if (this.process && this.initialized && this.process.stdin?.writable) {
20273
- this.sendRequest("shutdown", null, 3000).catch((e) => {
20274
- this.logger?.debug(`LSP shutdown request failed: ${e instanceof Error ? e.message : String(e)}`);
20275
- });
20503
+ this.sendRequest("shutdown", null, 3000).catch(() => {});
20276
20504
  this.sendNotification("exit", null);
20277
20505
  await new Promise((r) => setTimeout(r, 200));
20278
20506
  }
20279
- } catch (e) {
20280
- this.logger?.debug(`LSP shutdown error: ${e instanceof Error ? e.message : String(e)}`);
20281
- } finally {
20507
+ } catch {} finally {
20282
20508
  if (this.process) {
20283
20509
  try {
20284
20510
  killTree(this.process);
20285
- } catch (e) {
20286
- this.logger?.debug(`LSP killTree error: ${e instanceof Error ? e.message : String(e)}`);
20287
- }
20511
+ } catch {}
20288
20512
  this.process = null;
20289
20513
  }
20290
20514
  this.initialized = false;
@@ -20392,26 +20616,9 @@ class LspModule {
20392
20616
  client;
20393
20617
  failuresByServer = new Map;
20394
20618
  disabledServers = new Set;
20395
- logger = null;
20396
- constructor(config, client, logger) {
20619
+ constructor(config, client) {
20397
20620
  this.config = { ...DEFAULT_LSP_CONFIG, ...config };
20398
20621
  this.client = client ?? new LspClient;
20399
- this.logger = logger ?? null;
20400
- this.client.setLogger(this.logger);
20401
- }
20402
- setLogger(logger) {
20403
- this.logger = logger;
20404
- this.client.setLogger(logger);
20405
- }
20406
- resetDisabledServers() {
20407
- this.failuresByServer.clear();
20408
- this.disabledServers.clear();
20409
- }
20410
- getDisabledServers() {
20411
- return Array.from(this.disabledServers);
20412
- }
20413
- getFailureCounts() {
20414
- return new Map(this.failuresByServer);
20415
20622
  }
20416
20623
  isLspDisabled() {
20417
20624
  return this.disabledServers.size > 0;
@@ -20631,7 +20838,7 @@ var init_lsp = __esm(() => {
20631
20838
 
20632
20839
  // src/modules/lsp/startup-check.ts
20633
20840
  import { existsSync as existsSync39 } from "fs";
20634
- import { join as join31 } from "path";
20841
+ import { join as join32 } from "path";
20635
20842
  import { spawn as spawn7 } from "child_process";
20636
20843
  async function runStartupHealthCheck(config, baseDir, deps = {}) {
20637
20844
  if (!config.enabled)
@@ -20658,7 +20865,7 @@ ${result.lines.join(`
20658
20865
  }
20659
20866
  async function runCheck(config, baseDir, deps) {
20660
20867
  const projectRoot = findProjectRoot(baseDir, baseDir, ["tsconfig.json", "package.json"]);
20661
- if (existsSync39(join31(projectRoot, "tsconfig.json"))) {
20868
+ if (existsSync39(join32(projectRoot, "tsconfig.json"))) {
20662
20869
  const runTsc = deps.runTsc ?? runTscDefault;
20663
20870
  const errors = await runTsc(projectRoot, STARTUP_CHECK_TIMEOUT_MS);
20664
20871
  if (errors.length === 0)
@@ -20682,9 +20889,7 @@ async function runCheck(config, baseDir, deps) {
20682
20889
  lines.push(formatStartupError(file, baseDir, d));
20683
20890
  }
20684
20891
  }
20685
- } catch (e) {
20686
- deps.logger?.debug(`Startup LSP check failed for ${file}: ${e instanceof Error ? e.message : String(e)}`);
20687
- }
20892
+ } catch {}
20688
20893
  }
20689
20894
  if (checked === 0 || lines.length === 0)
20690
20895
  return null;
@@ -20757,7 +20962,7 @@ var init_startup_check = __esm(() => {
20757
20962
 
20758
20963
  // src/modules/indexer/walker.ts
20759
20964
  import { readdirSync as readdirSync14, readFileSync as readFileSync23, statSync as statSync7, existsSync as existsSync40, watch } from "fs";
20760
- import { join as join32, relative as relative4, extname as extname5 } from "path";
20965
+ import { join as join33, relative as relative4, extname as extname5 } from "path";
20761
20966
 
20762
20967
  class Indexer {
20763
20968
  baseDir;
@@ -20795,7 +21000,7 @@ class Indexer {
20795
21000
  for (const entry of entries) {
20796
21001
  if (count >= this.MAX_FILES)
20797
21002
  return;
20798
- const fullPath = join32(dir, entry);
21003
+ const fullPath = join33(dir, entry);
20799
21004
  const relPath = relative4(this.baseDir, fullPath);
20800
21005
  const stat2 = statSync7(fullPath);
20801
21006
  if (stat2.isDirectory()) {
@@ -20859,13 +21064,13 @@ var init_walker = __esm(() => {
20859
21064
 
20860
21065
  // src/modules/indexer/cache.ts
20861
21066
  import { readFileSync as readFileSync24, writeFileSync as writeFileSync14, existsSync as existsSync41, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
20862
- import { join as join33 } from "path";
21067
+ import { join as join34 } from "path";
20863
21068
 
20864
21069
  class IndexCache {
20865
21070
  cachePath;
20866
21071
  cache = null;
20867
21072
  constructor(cacheDir) {
20868
- this.cachePath = join33(cacheDir, "index-cache.json");
21073
+ this.cachePath = join34(cacheDir, "index-cache.json");
20869
21074
  }
20870
21075
  load() {
20871
21076
  if (this.cache)
@@ -20881,7 +21086,7 @@ class IndexCache {
20881
21086
  }
20882
21087
  save(result) {
20883
21088
  this.cache = result;
20884
- const dir = join33(this.cachePath, "..");
21089
+ const dir = join34(this.cachePath, "..");
20885
21090
  if (!existsSync41(dir))
20886
21091
  mkdirSync17(dir, { recursive: true });
20887
21092
  writeFileSync14(this.cachePath, JSON.stringify(result), "utf-8");
@@ -20899,10 +21104,10 @@ var init_cache = () => {};
20899
21104
 
20900
21105
  // src/modules/indexer/project-profile.ts
20901
21106
  import { readFileSync as readFileSync25, existsSync as existsSync42 } from "fs";
20902
- import { join as join34 } from "path";
21107
+ import { join as join35 } from "path";
20903
21108
  function detectManifest(baseDir) {
20904
21109
  for (const manifest of MANIFEST_ORDER) {
20905
- if (existsSync42(join34(baseDir, manifest)))
21110
+ if (existsSync42(join35(baseDir, manifest)))
20906
21111
  return manifest;
20907
21112
  }
20908
21113
  return null;
@@ -20919,7 +21124,7 @@ function cleanDependency(entry) {
20919
21124
  }
20920
21125
  function readPackageJson(baseDir) {
20921
21126
  try {
20922
- const raw = JSON.parse(readFileSync25(join34(baseDir, "package.json"), "utf-8"));
21127
+ const raw = JSON.parse(readFileSync25(join35(baseDir, "package.json"), "utf-8"));
20923
21128
  if (!raw || typeof raw !== "object")
20924
21129
  return null;
20925
21130
  const profile = {
@@ -20943,7 +21148,7 @@ function readPackageJson(baseDir) {
20943
21148
  }
20944
21149
  function readPyproject(baseDir) {
20945
21150
  try {
20946
- const content = readFileSync25(join34(baseDir, "pyproject.toml"), "utf-8");
21151
+ const content = readFileSync25(join35(baseDir, "pyproject.toml"), "utf-8");
20947
21152
  const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
20948
21153
  const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
20949
21154
  if (nameMatch)
@@ -20959,7 +21164,7 @@ function readPyproject(baseDir) {
20959
21164
  }
20960
21165
  function readCargo(baseDir) {
20961
21166
  try {
20962
- const content = readFileSync25(join34(baseDir, "Cargo.toml"), "utf-8");
21167
+ const content = readFileSync25(join35(baseDir, "Cargo.toml"), "utf-8");
20963
21168
  const profile = { runtime: "rust", deps: [], devDeps: [], scripts: {} };
20964
21169
  const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
20965
21170
  if (nameMatch)
@@ -20983,7 +21188,7 @@ function readCargo(baseDir) {
20983
21188
  }
20984
21189
  function readGoMod(baseDir) {
20985
21190
  try {
20986
- const content = readFileSync25(join34(baseDir, "go.mod"), "utf-8");
21191
+ const content = readFileSync25(join35(baseDir, "go.mod"), "utf-8");
20987
21192
  const profile = { runtime: "go", deps: [], devDeps: [], scripts: {} };
20988
21193
  const moduleMatch = content.match(/^module\s+(\S+)/m);
20989
21194
  if (moduleMatch)
@@ -21001,7 +21206,7 @@ function readGoMod(baseDir) {
21001
21206
  }
21002
21207
  function readRequirements(baseDir) {
21003
21208
  try {
21004
- const content = readFileSync25(join34(baseDir, "requirements.txt"), "utf-8");
21209
+ const content = readFileSync25(join35(baseDir, "requirements.txt"), "utf-8");
21005
21210
  const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
21006
21211
  for (const line of content.split(`
21007
21212
  `)) {
@@ -21459,8 +21664,8 @@ var init_mcp = __esm(() => {
21459
21664
  });
21460
21665
 
21461
21666
  // src/modules/memory/module.ts
21462
- import { homedir as homedir10 } from "os";
21463
- import { join as join35 } from "path";
21667
+ import { homedir as homedir11 } from "os";
21668
+ import { join as join36 } from "path";
21464
21669
 
21465
21670
  class MemoryModule {
21466
21671
  name = "memory";
@@ -21469,7 +21674,7 @@ class MemoryModule {
21469
21674
  if (storeOrDir instanceof MemoryStore) {
21470
21675
  this.store = storeOrDir;
21471
21676
  } else {
21472
- const dir = storeOrDir || join35(homedir10(), ".mma", "memory");
21677
+ const dir = storeOrDir || join36(homedir11(), ".mma", "memory");
21473
21678
  this.store = new MemoryStore(dir);
21474
21679
  }
21475
21680
  }
@@ -21556,11 +21761,11 @@ var init_module8 = __esm(() => {
21556
21761
 
21557
21762
  // src/core/version.ts
21558
21763
  import { existsSync as existsSync43, readFileSync as readFileSync26 } from "fs";
21559
- import { join as join36, dirname as dirname13 } from "path";
21764
+ import { join as join37, dirname as dirname13 } from "path";
21560
21765
  import { fileURLToPath as fileURLToPath2 } from "url";
21561
21766
  function readMmaVersion() {
21562
21767
  const here = dirname13(fileURLToPath2(import.meta.url));
21563
- const candidates = [join36(here, "..", "..", "package.json"), join36(here, "..", "package.json")];
21768
+ const candidates = [join37(here, "..", "..", "package.json"), join37(here, "..", "package.json")];
21564
21769
  for (const p of candidates) {
21565
21770
  if (existsSync43(p)) {
21566
21771
  try {
@@ -21580,8 +21785,8 @@ __export(exports_bootstrap, {
21580
21785
  buildSystemInfo: () => buildSystemInfo,
21581
21786
  bootstrap: () => bootstrap
21582
21787
  });
21583
- import { homedir as homedir11 } from "os";
21584
- import { join as join37, resolve as resolve23 } from "path";
21788
+ import { homedir as homedir12 } from "os";
21789
+ import { join as join38, resolve as resolve23 } from "path";
21585
21790
  import { existsSync as existsSync44, readFileSync as readFileSync27, writeFileSync as writeFileSync15 } from "fs";
21586
21791
  function buildSystemInfo(config, baseDir, profileCompressed) {
21587
21792
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
@@ -21608,8 +21813,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
21608
21813
  `);
21609
21814
  }
21610
21815
  async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21611
- const dir = configDir || join37(homedir11(), ".mma");
21612
- const projectConfigPath = projectDir ? join37(projectDir, ".mmrc") : join37(process.cwd(), ".mmrc");
21816
+ const dir = configDir || join38(homedir12(), ".mma");
21817
+ const projectConfigPath = projectDir ? join38(projectDir, ".mmrc") : join38(process.cwd(), ".mmrc");
21613
21818
  const config = loadConfig({ configDir: dir, projectConfigPath });
21614
21819
  setLocale(config.locale);
21615
21820
  try {
@@ -21619,7 +21824,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21619
21824
  }
21620
21825
  } catch {}
21621
21826
  const logger = new Logger(config.logLevel);
21622
- logger.setLogDir(join37(dir, "logs"));
21827
+ logger.setLogDir(join38(dir, "logs"));
21623
21828
  logger.debug("MMA bootstrap", {
21624
21829
  version: config.version,
21625
21830
  model: config.model
@@ -21641,19 +21846,18 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21641
21846
  logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
21642
21847
  }
21643
21848
  }
21644
- const profile = new UserProfile(join37(dir));
21849
+ const profile = new UserProfile(join38(dir));
21645
21850
  profile.load() || profile.collect();
21646
21851
  profile.save();
21647
- const llmProvider = new OpenAICompatProvider({
21648
- model: config.model,
21649
- baseUrl: config.provider.baseUrl,
21650
- apiKey: config.provider.apiKey,
21852
+ const providerManager = new ProviderManager(config.provider, {
21651
21853
  contextWindow: config.contextWindow,
21652
21854
  retry: config.retry,
21653
21855
  rateLimits: config.security?.rateLimits
21654
21856
  });
21857
+ providerManager.setModel(config.model);
21858
+ const llmProvider = providerManager.active;
21655
21859
  const baseDir = projectDir ? resolve23(projectDir) : process.cwd();
21656
- const projectMapCacheDir = join37(baseDir, ".mma");
21860
+ const projectMapCacheDir = join38(baseDir, ".mma");
21657
21861
  const indexerModule = new IndexerModule({
21658
21862
  baseDir,
21659
21863
  cacheDir: projectMapCacheDir
@@ -21664,9 +21868,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21664
21868
  logger.warn(`Project indexing failed: ${err.message}`);
21665
21869
  }
21666
21870
  const skillsLoader = new SkillsLoader;
21667
- const builtinDir = join37(import.meta.dirname, "skills", "builtin");
21668
- const globalDir = join37(homedir11(), ".agents", "skills");
21669
- const projectSkillsDir = join37(baseDir, ".mma", "skills");
21871
+ const builtinDir = join38(import.meta.dirname, "skills", "builtin");
21872
+ const globalDir = join38(homedir12(), ".agents", "skills");
21873
+ const projectSkillsDir = join38(baseDir, ".mma", "skills");
21670
21874
  const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
21671
21875
  const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
21672
21876
  const skillsModule = new SkillsModule(availableSkills, skillsBudget);
@@ -21682,11 +21886,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21682
21886
  essential: true,
21683
21887
  estimatedTokens: Math.ceil(systemInfoContent.length / 4)
21684
21888
  };
21685
- const agentsMdGlobal = join37(dir, "AGENTS.md");
21889
+ const agentsMdGlobal = join38(dir, "AGENTS.md");
21686
21890
  if (!existsSync44(agentsMdGlobal)) {
21687
21891
  writeFileSync15(agentsMdGlobal, "", "utf-8");
21688
21892
  }
21689
- const sessionDir = join37(dir, "sessions");
21893
+ const sessionDir = join38(dir, "sessions");
21690
21894
  const sessionStore = new SessionStore(sessionDir);
21691
21895
  sessionStore.init();
21692
21896
  const sessionManager = new SessionManager(sessionStore, {
@@ -21763,7 +21967,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21763
21967
  const mcpModule = new MCPModule(config);
21764
21968
  await mcpModule.initialize();
21765
21969
  moduleRegistry.register(mcpModule);
21766
- const memoryStore = new MemoryStore(join37(dir, "memory"));
21970
+ const memoryStore = new MemoryStore(join38(dir, "memory"));
21767
21971
  const memoryModule = new MemoryModule(memoryStore);
21768
21972
  moduleRegistry.register(memoryModule);
21769
21973
  if (config.browser.enabled) {
@@ -21775,7 +21979,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21775
21979
  pluginManager.register(browserPlugin);
21776
21980
  }
21777
21981
  }
21778
- const lspModule = new LspModule(config.lsp, undefined, logger);
21982
+ const lspModule = new LspModule(config.lsp);
21779
21983
  moduleRegistry.register(lspModule);
21780
21984
  const lspPlugin = lspModule.getPlugin();
21781
21985
  if (lspPlugin) {
@@ -21816,8 +22020,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21816
22020
  pluginManager.register(plugin);
21817
22021
  pluginManager.register(plugin2);
21818
22022
  const pluginLoader = new PluginLoader;
21819
- const globalPluginsDir = join37(homedir11(), ".mma", "plugins");
21820
- const projectPluginsDir = join37(baseDir, ".mma", "plugins");
22023
+ const globalPluginsDir = join38(homedir12(), ".mma", "plugins");
22024
+ const projectPluginsDir = join38(baseDir, ".mma", "plugins");
21821
22025
  const mmaVersion = readMmaVersion();
21822
22026
  pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger, {
21823
22027
  source: "global",
@@ -21843,9 +22047,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21843
22047
  const skipAgentsMd = noAgentsMd === true;
21844
22048
  if (!skipAgentsMd) {
21845
22049
  const agentsMdCandidates = [
21846
- join37(baseDir, "AGENTS.md"),
21847
- join37(baseDir, ".mma", "AGENTS.md"),
21848
- join37(dir, "AGENTS.md")
22050
+ join38(baseDir, "AGENTS.md"),
22051
+ join38(baseDir, ".mma", "AGENTS.md"),
22052
+ join38(dir, "AGENTS.md")
21849
22053
  ];
21850
22054
  for (const p of agentsMdCandidates) {
21851
22055
  if (existsSync44(p)) {
@@ -21869,6 +22073,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21869
22073
  const agentDeps = {
21870
22074
  config,
21871
22075
  llmProvider,
22076
+ providerManager,
21872
22077
  toolExecutor,
21873
22078
  pluginManager,
21874
22079
  contextManager,
@@ -21927,15 +22132,15 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21927
22132
  var init_bootstrap = __esm(() => {
21928
22133
  init_config2();
21929
22134
  init_app_logger();
21930
- init_openai_compat();
22135
+ init_providers();
21931
22136
  init_tools();
21932
22137
  init_hidden_tools_block();
21933
22138
  init_executor();
21934
- init_manager2();
22139
+ init_manager3();
21935
22140
  init_loader();
21936
22141
  init_lint_on_write();
21937
22142
  init_notify();
21938
- init_manager();
22143
+ init_manager2();
21939
22144
  init_token_counter();
21940
22145
  init_detector();
21941
22146
  init_module();
@@ -22678,35 +22883,24 @@ async function runSetup(externalRl) {
22678
22883
  console.log(l);
22679
22884
  return answers;
22680
22885
  }
22681
- var PROVIDER_TYPES, KNOWN_PORTS, HOSTED_BASE_URLS;
22886
+ var PROVIDER_TYPES, KNOWN_PORTS;
22682
22887
  var init_setup = __esm(() => {
22683
22888
  init_colors();
22684
22889
  init_i18n();
22685
22890
  init_spinner();
22891
+ init_presets();
22686
22892
  init_box();
22687
22893
  init_table();
22688
- PROVIDER_TYPES = [
22689
- {
22690
- value: "openai-compat",
22691
- label: "OpenAI-compatible (LM Studio, Ollama, vLLM, etc.)"
22692
- },
22693
- { value: "openai", label: "OpenAI API" },
22694
- { value: "anthropic", label: "Anthropic Claude" },
22695
- { value: "opencode-zen", label: "OpenCode Zen (opencode.ai/zen)" },
22696
- { value: "opencode-go", label: "OpenCode Go (opencode.ai/go)" }
22697
- ];
22894
+ PROVIDER_TYPES = BUILTIN_PROVIDERS.map((spec) => ({
22895
+ value: spec.type,
22896
+ label: spec.label
22897
+ }));
22698
22898
  KNOWN_PORTS = [
22699
22899
  { port: 1234, label: "LM Studio" },
22700
22900
  { port: 11434, label: "Ollama" },
22701
22901
  { port: 8080, label: "vLLM / custom" },
22702
22902
  { port: 4891, label: "GPT4All" }
22703
22903
  ];
22704
- HOSTED_BASE_URLS = {
22705
- openai: "https://api.openai.com/v1",
22706
- anthropic: "https://api.anthropic.com",
22707
- "opencode-zen": "https://opencode.ai/zen/v1",
22708
- "opencode-go": "https://opencode.ai/zen/go/v1"
22709
- };
22710
22904
  });
22711
22905
 
22712
22906
  // src/modules/certification/manifest.ts
@@ -22721,8 +22915,8 @@ __export(exports_manifest, {
22721
22915
  MANIFEST_PATH: () => MANIFEST_PATH
22722
22916
  });
22723
22917
  import { existsSync as existsSync45, readFileSync as readFileSync28, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
22724
- import { homedir as homedir13 } from "os";
22725
- import { join as join39 } from "path";
22918
+ import { homedir as homedir14 } from "os";
22919
+ import { join as join40 } from "path";
22726
22920
  function readManifest(path = MANIFEST_PATH) {
22727
22921
  try {
22728
22922
  if (existsSync45(path)) {
@@ -22733,7 +22927,7 @@ function readManifest(path = MANIFEST_PATH) {
22733
22927
  return { version: 1, certifications: [] };
22734
22928
  }
22735
22929
  function saveManifest(m, path = MANIFEST_PATH) {
22736
- mkdirSync18(join39(homedir13(), ".mma"), { recursive: true });
22930
+ mkdirSync18(join40(homedir14(), ".mma"), { recursive: true });
22737
22931
  writeFileSync16(path, JSON.stringify(m, null, 2), "utf-8");
22738
22932
  }
22739
22933
  function upsertCertification(entry, path = MANIFEST_PATH) {
@@ -22768,7 +22962,7 @@ function getCertMark(model, providerUrl, currentVersion, path = MANIFEST_PATH) {
22768
22962
  }
22769
22963
  var MANIFEST_PATH;
22770
22964
  var init_manifest = __esm(() => {
22771
- MANIFEST_PATH = join39(homedir13(), ".mma", "certifications.json");
22965
+ MANIFEST_PATH = join40(homedir14(), ".mma", "certifications.json");
22772
22966
  });
22773
22967
 
22774
22968
  // node_modules/yaml/dist/nodes/identity.js
@@ -29892,7 +30086,7 @@ var init_scenarios = __esm(() => {
29892
30086
 
29893
30087
  // src/modules/certification/loader.ts
29894
30088
  import { existsSync as existsSync46, readdirSync as readdirSync15, readFileSync as readFileSync29 } from "fs";
29895
- import { join as join40 } from "path";
30089
+ import { join as join41 } from "path";
29896
30090
  function validateScenario(s) {
29897
30091
  const errors2 = [];
29898
30092
  const isSkip = s.mode === "skip";
@@ -29946,7 +30140,7 @@ function loadScenarios(userDir) {
29946
30140
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
29947
30141
  continue;
29948
30142
  try {
29949
- const raw = readFileSync29(join40(userDir, file), "utf-8");
30143
+ const raw = readFileSync29(join41(userDir, file), "utf-8");
29950
30144
  const data = $parse(raw);
29951
30145
  const parsed = normalizeScenario(data, file);
29952
30146
  const errs = validateScenario(parsed);
@@ -30000,7 +30194,7 @@ var init_loader3 = __esm(() => {
30000
30194
 
30001
30195
  // src/modules/certification/fact-checker.ts
30002
30196
  import { existsSync as existsSync47, readFileSync as readFileSync30, statSync as statSync8 } from "fs";
30003
- import { join as join41 } from "path";
30197
+ import { join as join42 } from "path";
30004
30198
  function checkSandbox(sandboxDir, checks, exitCode, output) {
30005
30199
  const failures = [];
30006
30200
  for (const check of checks) {
@@ -30017,13 +30211,13 @@ function runCheck2(sandboxDir, check, exitCode, output) {
30017
30211
  case "outputContains":
30018
30212
  return output.includes(check.text);
30019
30213
  case "fileExists":
30020
- return isFile(join41(sandboxDir, check.path));
30214
+ return isFile(join42(sandboxDir, check.path));
30021
30215
  case "fileNotExists":
30022
- return !existsSync47(join41(sandboxDir, check.path));
30216
+ return !existsSync47(join42(sandboxDir, check.path));
30023
30217
  case "dirExists":
30024
- return isDir(join41(sandboxDir, check.path));
30218
+ return isDir(join42(sandboxDir, check.path));
30025
30219
  case "fileContent": {
30026
- const abs = join41(sandboxDir, check.path);
30220
+ const abs = join42(sandboxDir, check.path);
30027
30221
  if (!isFile(abs))
30028
30222
  return false;
30029
30223
  const content = readFileSync30(abs, "utf-8");
@@ -30034,7 +30228,7 @@ function runCheck2(sandboxDir, check, exitCode, output) {
30034
30228
  return false;
30035
30229
  }
30036
30230
  case "fileRegex": {
30037
- const abs = join41(sandboxDir, check.path);
30231
+ const abs = join42(sandboxDir, check.path);
30038
30232
  if (!isFile(abs))
30039
30233
  return false;
30040
30234
  return new RegExp(check.pattern).test(readFileSync30(abs, "utf-8"));
@@ -30085,7 +30279,7 @@ var init_fact_checker = () => {};
30085
30279
  import { spawn as spawn8 } from "child_process";
30086
30280
  import { existsSync as existsSync48, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
30087
30281
  import { platform as platform9 } from "os";
30088
- import { join as join42, resolve as resolve24, dirname as dirname14 } from "path";
30282
+ import { join as join43, resolve as resolve24, dirname as dirname14 } from "path";
30089
30283
  async function runScenario(scenario, opts) {
30090
30284
  if (scenario.mode === "skip") {
30091
30285
  return {
@@ -30104,7 +30298,7 @@ async function runScenario(scenario, opts) {
30104
30298
  let passed = 0;
30105
30299
  let firstError;
30106
30300
  for (let i = 1;i <= reps; i++) {
30107
- const sandbox = join42(opts.sandboxBase, `run-${scenario.id}-${i}`);
30301
+ const sandbox = join43(opts.sandboxBase, `run-${scenario.id}-${i}`);
30108
30302
  let failures = [];
30109
30303
  let exitCode = -1;
30110
30304
  let output = "";
@@ -30165,25 +30359,25 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
30165
30359
  rmSync4(sandbox, { recursive: true, force: true });
30166
30360
  mkdirSync19(sandbox, { recursive: true });
30167
30361
  for (const f of scenario.fixtures ?? []) {
30168
- const src = join42(mmaRoot, f.source);
30362
+ const src = join43(mmaRoot, f.source);
30169
30363
  if (!existsSync48(src)) {
30170
30364
  throw new Error(`fixture missing: ${f.source}`);
30171
30365
  }
30172
- const dest = join42(sandbox, f.dest);
30366
+ const dest = join43(sandbox, f.dest);
30173
30367
  mkdirSync19(dirname14(dest), { recursive: true });
30174
30368
  cpSync2(src, dest);
30175
30369
  }
30176
30370
  }
30177
30371
  function resolveMmaEntry(mmaRoot) {
30178
- const dev = join42(mmaRoot, "src", "cli", "main.ts");
30372
+ const dev = join43(mmaRoot, "src", "cli", "main.ts");
30179
30373
  if (existsSync48(dev))
30180
30374
  return dev;
30181
- return join42(mmaRoot, "dist", "main.js");
30375
+ return join43(mmaRoot, "dist", "main.js");
30182
30376
  }
30183
30377
  function findMmaRoot(fromDir) {
30184
30378
  const candidates = [resolve24(fromDir, "..", "..", ".."), resolve24(fromDir, "..")];
30185
30379
  for (const c of candidates) {
30186
- if (existsSync48(join42(c, "package.json")))
30380
+ if (existsSync48(join43(c, "package.json")))
30187
30381
  return c;
30188
30382
  }
30189
30383
  return process.cwd();
@@ -30250,12 +30444,12 @@ __export(exports_cli, {
30250
30444
  certList: () => certList
30251
30445
  });
30252
30446
  import { rmSync as rmSync5 } from "fs";
30253
- import { homedir as homedir14 } from "os";
30254
- import { join as join43, dirname as dirname15 } from "path";
30447
+ import { homedir as homedir15 } from "os";
30448
+ import { join as join44, dirname as dirname15 } from "path";
30255
30449
  import { fileURLToPath as fileURLToPath3 } from "url";
30256
30450
  import { existsSync as existsSync49, readFileSync as readFileSync31 } from "fs";
30257
30451
  function readVersion() {
30258
- const candidates = [join43(MMA_ROOT, "package.json")];
30452
+ const candidates = [join44(MMA_ROOT, "package.json")];
30259
30453
  for (const p of candidates) {
30260
30454
  if (existsSync49(p)) {
30261
30455
  try {
@@ -30295,7 +30489,7 @@ async function certify(opts) {
30295
30489
  return;
30296
30490
  }
30297
30491
  console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
30298
- const sandboxBase = join43(process.cwd(), ".mma", "certification");
30492
+ const sandboxBase = join44(process.cwd(), ".mma", "certification");
30299
30493
  const results = [];
30300
30494
  const total = selected.length;
30301
30495
  let idx = 0;
@@ -30409,7 +30603,7 @@ var init_cli = __esm(() => {
30409
30603
  init_manifest();
30410
30604
  HERE = dirname15(fileURLToPath3(import.meta.url));
30411
30605
  MMA_ROOT = findMmaRoot(HERE);
30412
- USER_SCENARIO_DIR = join43(homedir14(), ".mma", "certification", "scenarios");
30606
+ USER_SCENARIO_DIR = join44(homedir15(), ".mma", "certification", "scenarios");
30413
30607
  });
30414
30608
 
30415
30609
  // src/cli/repl-commands.ts
@@ -30418,13 +30612,13 @@ __export(exports_repl_commands, {
30418
30612
  registerAllCommands: () => registerAllCommands,
30419
30613
  COMMAND_GROUPS: () => COMMAND_GROUPS
30420
30614
  });
30421
- import { join as join45, dirname as dirname17 } from "path";
30422
- import { homedir as homedir16 } from "os";
30615
+ import { join as join46, dirname as dirname17 } from "path";
30616
+ import { homedir as homedir17 } from "os";
30423
30617
  import { existsSync as existsSync51, readFileSync as readFileSync33 } from "fs";
30424
30618
  import { fileURLToPath as fileURLToPath5 } from "url";
30425
30619
  function readVersion3() {
30426
30620
  const here = dirname17(fileURLToPath5(import.meta.url));
30427
- const candidates = [join45(here, "..", "..", "package.json"), join45(here, "..", "package.json")];
30621
+ const candidates = [join46(here, "..", "..", "package.json"), join46(here, "..", "package.json")];
30428
30622
  for (const p of candidates) {
30429
30623
  if (existsSync51(p)) {
30430
30624
  try {
@@ -30546,7 +30740,13 @@ function registerMmaCommands(ctx) {
30546
30740
  const sys = Math.floor(ctxW * cfg.contextBudget.systemPrompt);
30547
30741
  const res = Math.floor(ctxW * cfg.contextBudget.responseReserve);
30548
30742
  console.log(`${t("repl.model")} ${cfg.model}`);
30549
- console.log(`${t("repl.provider")} ${cfg.provider.type} → ${cfg.provider.baseUrl}`);
30743
+ const providers = ctx.agent.listProviders();
30744
+ const active = providers.find((p) => p.active);
30745
+ if (active) {
30746
+ console.log(`${t("repl.provider")} ${active.label} (${pc2.dim(active.type)}) → ${pc2.dim(active.baseUrl)}`);
30747
+ } else {
30748
+ console.log(`${t("repl.provider")} ${cfg.provider.type} → ${cfg.provider.baseUrl}`);
30749
+ }
30550
30750
  console.log(`${t("repl.context")} ${ctxW} (sys:${sys} res:${res} hist:${ctxW - sys - res})`);
30551
30751
  console.log(`${t("repl.max_iters")} ${cfg.maxToolIterations}`);
30552
30752
  console.log(`${t("repl.stuck_thresh")} ${cfg.stuckThreshold}`);
@@ -30574,8 +30774,14 @@ function registerMmaCommands(ctx) {
30574
30774
  description: t("repl.status"),
30575
30775
  usage: t("repl.status_usage"),
30576
30776
  action: () => {
30777
+ const providers = ctx.agent.listProviders();
30778
+ const active = providers.find((p) => p.active);
30577
30779
  console.log(`${t("repl.model")} ${ctx.config.model}`);
30578
- console.log(`${t("repl.provider")} ${ctx.config.provider.type} @ ${ctx.config.provider.baseUrl}`);
30780
+ if (active) {
30781
+ console.log(`${t("repl.provider")} ${active.label} (${pc2.dim(active.type)}) @ ${pc2.dim(active.baseUrl)}`);
30782
+ } else {
30783
+ console.log(`${t("repl.provider")} ${ctx.config.provider.type} @ ${ctx.config.provider.baseUrl}`);
30784
+ }
30579
30785
  const meta = ctx.sessionManager?.getActiveMeta();
30580
30786
  if (meta) {
30581
30787
  console.log(`${t("repl.session_label")} ${meta.name} (${meta.id}) — ${meta.messageCount} messages`);
@@ -30591,7 +30797,7 @@ function registerMmaCommands(ctx) {
30591
30797
  console.log(pc2.yellow(t("repl.wizard_running")));
30592
30798
  await ctx.withExclusiveInput(async () => {
30593
30799
  const answers = await runSetup(ctx.rl);
30594
- const configPath = join45(homedir16(), ".mma", "config.json");
30800
+ const configPath = join46(homedir17(), ".mma", "config.json");
30595
30801
  ctx.config.provider.type = answers.provider;
30596
30802
  ctx.config.provider.baseUrl = answers.apiBase;
30597
30803
  ctx.config.provider.apiKey = answers.apiKey;
@@ -30634,8 +30840,17 @@ Excluded blocks: ${info.excluded.length}`));
30634
30840
  action: async (args) => {
30635
30841
  const subcmd = args[0];
30636
30842
  if (!subcmd || subcmd === "list") {
30637
- console.log(`${t("repl.provider_current")} ${ctx.config.provider.type}`);
30638
- console.log(` ${ctx.config.provider.baseUrl}`);
30843
+ const providers = ctx.agent.listProviders();
30844
+ if (providers.length === 0) {
30845
+ console.log(`${t("repl.provider_current")} ${ctx.config.provider.type}`);
30846
+ console.log(` ${ctx.config.provider.baseUrl}`);
30847
+ } else {
30848
+ console.log(t("repl.provider_current"));
30849
+ for (const p of providers) {
30850
+ const marker = p.active ? pc2.green("* ") : " ";
30851
+ console.log(` ${marker}${p.label} (${pc2.dim(p.type)}) ${pc2.dim(p.baseUrl)}`);
30852
+ }
30853
+ }
30639
30854
  return;
30640
30855
  }
30641
30856
  if (subcmd === "use") {
@@ -30644,11 +30859,12 @@ Excluded blocks: ${info.excluded.length}`));
30644
30859
  console.log(t("repl.provider_usage"));
30645
30860
  return;
30646
30861
  }
30647
- ctx.config.provider.type = name;
30648
- const configPath = join45(homedir16(), ".mma", "config.json");
30649
- saveConfig(ctx.config, configPath);
30650
- await ctx.agent.reconfigure(ctx.config);
30651
- console.log(pc2.green(t("repl.provider_set", { name })));
30862
+ try {
30863
+ await ctx.agent.setProvider(name);
30864
+ console.log(pc2.green(t("repl.provider_set", { name })));
30865
+ } catch (e) {
30866
+ console.log(pc2.red(e.message));
30867
+ }
30652
30868
  return;
30653
30869
  }
30654
30870
  console.log(t("repl.provider_usage"));
@@ -30701,7 +30917,7 @@ Excluded blocks: ${info.excluded.length}`));
30701
30917
  return;
30702
30918
  }
30703
30919
  ctx.config.model = name;
30704
- const configPath = join45(homedir16(), ".mma", "config.json");
30920
+ const configPath = join46(homedir17(), ".mma", "config.json");
30705
30921
  saveConfig(ctx.config, configPath);
30706
30922
  await ctx.agent.reconfigure(ctx.config);
30707
30923
  console.log(pc2.green(t("repl.model_set", { name })));
@@ -30726,7 +30942,7 @@ Excluded blocks: ${info.excluded.length}`));
30726
30942
  return;
30727
30943
  }
30728
30944
  ctx.config.contextWindow = size;
30729
- const configPath = join45(homedir16(), ".mma", "config.json");
30945
+ const configPath = join46(homedir17(), ".mma", "config.json");
30730
30946
  saveConfig(ctx.config, configPath);
30731
30947
  await ctx.agent.reconfigure(ctx.config);
30732
30948
  console.log(pc2.green(t("cli.context_set", { size })));
@@ -30744,11 +30960,11 @@ Excluded blocks: ${info.excluded.length}`));
30744
30960
  }
30745
30961
  ctx.agent.shutdown();
30746
30962
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
30747
- const { homedir: homedir17 } = await import("os");
30748
- const { join: join46 } = await import("path");
30963
+ const { homedir: homedir18 } = await import("os");
30964
+ const { join: join47 } = await import("path");
30749
30965
  const configDir = ctx.configDir;
30750
30966
  const baseDir = ctx.baseDir;
30751
- const projectConfigPath = join46(baseDir, ".mmrc");
30967
+ const projectConfigPath = join47(baseDir, ".mmrc");
30752
30968
  const freshConfig = loadConfig2({ configDir, projectConfigPath });
30753
30969
  Object.assign(ctx.config, freshConfig);
30754
30970
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
@@ -30799,70 +31015,6 @@ Excluded blocks: ${info.excluded.length}`));
30799
31015
  }
30800
31016
  }
30801
31017
  });
30802
- ctx.registerCommand({
30803
- name: "lsp",
30804
- description: t("repl.lsp"),
30805
- usage: t("repl.lsp_usage"),
30806
- action: async (args) => {
30807
- const subcommand = args[0] || "status";
30808
- const lspModule = ctx.agent.deps?.moduleRegistry?.getModules?.()?.find((m) => m.name === "lsp");
30809
- if (!lspModule) {
30810
- console.log(pc2.yellow(t("repl.lsp_not_available")));
30811
- return;
30812
- }
30813
- switch (subcommand) {
30814
- case "status": {
30815
- const disabled = lspModule.getDisabledServers();
30816
- const failures = lspModule.getFailureCounts();
30817
- const config = ctx.config.lsp;
30818
- console.log(pc2.bold(t("repl.lsp_status_header")));
30819
- console.log(`${t("repl.lsp_enabled")} ${config?.enabled ? pc2.green("yes") : pc2.red("no")}`);
30820
- if (disabled.length > 0) {
30821
- console.log(pc2.yellow(`${t("repl.lsp_disabled_servers")} ${disabled.join(", ")}`));
30822
- }
30823
- if (failures.size > 0) {
30824
- console.log(pc2.dim(t("repl.lsp_failure_counts")));
30825
- for (const [server, count] of failures) {
30826
- console.log(pc2.dim(` ${server}: ${count}`));
30827
- }
30828
- }
30829
- if (disabled.length === 0 && failures.size === 0) {
30830
- console.log(pc2.green(t("repl.lsp_all_ok")));
30831
- }
30832
- break;
30833
- }
30834
- case "restart": {
30835
- console.log(pc2.yellow(t("repl.lsp_restarting")));
30836
- lspModule.resetDisabledServers();
30837
- console.log(pc2.green(t("repl.lsp_restarted")));
30838
- break;
30839
- }
30840
- case "check": {
30841
- const path = args[1];
30842
- if (!path) {
30843
- console.log(pc2.yellow(t("repl.lsp_check_usage")));
30844
- return;
30845
- }
30846
- console.log(pc2.dim(t("repl.lsp_checking", { path })));
30847
- try {
30848
- const result = await ctx.agent.deps?.toolExecutor?.execute("lsp_check", { path }, ctx.agent.deps?.toolCtx);
30849
- if (result?.output) {
30850
- console.log(result.output);
30851
- }
30852
- } catch (e) {
30853
- console.log(pc2.red(t("repl.lsp_check_error", {
30854
- error: e instanceof Error ? e.message : String(e)
30855
- })));
30856
- }
30857
- break;
30858
- }
30859
- default: {
30860
- console.log(pc2.dim(t("repl.lsp_usage")));
30861
- break;
30862
- }
30863
- }
30864
- }
30865
- });
30866
31018
  }
30867
31019
  function registerSessionCommands(ctx) {
30868
31020
  if (!ctx.sessionManager)
@@ -31117,7 +31269,6 @@ var init_repl_commands = __esm(() => {
31117
31269
  reload: "agent",
31118
31270
  wizard: "agent",
31119
31271
  sysprompt: "agent",
31120
- lsp: "agent",
31121
31272
  sessions: "session",
31122
31273
  new: "session",
31123
31274
  resume: "session",
@@ -31149,15 +31300,16 @@ init_bootstrap();
31149
31300
  init_config2();
31150
31301
  init_setup();
31151
31302
  init_i18n();
31152
- import { join as join44, dirname as dirname16 } from "path";
31153
- import { homedir as homedir15 } from "os";
31303
+ init_colors();
31304
+ import { join as join45, dirname as dirname16 } from "path";
31305
+ import { homedir as homedir16 } from "os";
31154
31306
  import { existsSync as existsSync50, readFileSync as readFileSync32 } from "fs";
31155
31307
 
31156
31308
  // src/cli/security-commands.ts
31157
31309
  init_bootstrap();
31158
31310
  init_config2();
31159
- import { join as join38 } from "path";
31160
- import { homedir as homedir12 } from "os";
31311
+ import { join as join39 } from "path";
31312
+ import { homedir as homedir13 } from "os";
31161
31313
 
31162
31314
  // src/modules/security/security-policies.ts
31163
31315
  init_security();
@@ -31670,7 +31822,7 @@ function createSecurityCommand(program2) {
31670
31822
  }
31671
31823
  });
31672
31824
  securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
31673
- const configPath = join38(homedir12(), ".mma", "config.json");
31825
+ const configPath = join39(homedir13(), ".mma", "config.json");
31674
31826
  const { config: appConfig } = await bootstrap();
31675
31827
  const validPresets = ["strict", "balanced", "permissive"];
31676
31828
  if (!validPresets.includes(preset)) {
@@ -31685,7 +31837,7 @@ function createSecurityCommand(program2) {
31685
31837
  console.log(t("cli.security.policy_description", { description: policy.description }));
31686
31838
  });
31687
31839
  securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
31688
- const configPath = join38(homedir12(), ".mma", "config.json");
31840
+ const configPath = join39(homedir13(), ".mma", "config.json");
31689
31841
  const { config: appConfig } = await bootstrap();
31690
31842
  appConfig.security = appConfig.security || {};
31691
31843
  appConfig.security.sessionEncryption = {
@@ -31697,7 +31849,7 @@ function createSecurityCommand(program2) {
31697
31849
  console.log(t("cli.security.encryption_enabled"));
31698
31850
  });
31699
31851
  securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
31700
- const configPath = join38(homedir12(), ".mma", "config.json");
31852
+ const configPath = join39(homedir13(), ".mma", "config.json");
31701
31853
  const { config: appConfig } = await bootstrap();
31702
31854
  appConfig.security = appConfig.security || {};
31703
31855
  appConfig.security.sessionEncryption = {
@@ -31709,7 +31861,7 @@ function createSecurityCommand(program2) {
31709
31861
  console.log(t("cli.security.encryption_disabled"));
31710
31862
  });
31711
31863
  securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
31712
- const configPath = join38(homedir12(), ".mma", "config.json");
31864
+ const configPath = join39(homedir13(), ".mma", "config.json");
31713
31865
  const { config: appConfig } = await bootstrap();
31714
31866
  appConfig.security = appConfig.security || {};
31715
31867
  appConfig.security.auditNotifier = {
@@ -31723,7 +31875,7 @@ function createSecurityCommand(program2) {
31723
31875
  console.log(t("cli.security.audit_enabled"));
31724
31876
  });
31725
31877
  securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
31726
- const configPath = join38(homedir12(), ".mma", "config.json");
31878
+ const configPath = join39(homedir13(), ".mma", "config.json");
31727
31879
  const { config: appConfig } = await bootstrap();
31728
31880
  appConfig.security = appConfig.security || {};
31729
31881
  appConfig.security.auditNotifier = {
@@ -31786,11 +31938,11 @@ function createPluginCommand(program2) {
31786
31938
  }
31787
31939
 
31788
31940
  // src/cli/commands.ts
31789
- init_setup();
31941
+ init_presets();
31790
31942
  import { fileURLToPath as fileURLToPath4 } from "url";
31791
31943
  function readVersion2() {
31792
31944
  const here = dirname16(fileURLToPath4(import.meta.url));
31793
- const candidates = [join44(here, "..", "..", "package.json"), join44(here, "..", "package.json")];
31945
+ const candidates = [join45(here, "..", "..", "package.json"), join45(here, "..", "package.json")];
31794
31946
  for (const p of candidates) {
31795
31947
  if (existsSync50(p)) {
31796
31948
  try {
@@ -31807,7 +31959,7 @@ function createProgram() {
31807
31959
  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"));
31808
31960
  program2.command("init").description(t("cli.init")).action(async () => {
31809
31961
  const answers = await runSetup();
31810
- const configPath = join44(homedir15(), ".mma", "config.json");
31962
+ const configPath = join45(homedir16(), ".mma", "config.json");
31811
31963
  const { config } = await bootstrap();
31812
31964
  config.provider.type = answers.provider;
31813
31965
  config.provider.baseUrl = answers.apiBase;
@@ -31852,7 +32004,7 @@ function createProgram() {
31852
32004
  });
31853
32005
  const configCmd = program2.command("config").description(t("cli.manage_config"));
31854
32006
  configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
31855
- const configPath = join44(homedir15(), ".mma", "config.json");
32007
+ const configPath = join45(homedir16(), ".mma", "config.json");
31856
32008
  const { config } = await bootstrap();
31857
32009
  const keys = key.split(".");
31858
32010
  let obj = config;
@@ -31883,8 +32035,8 @@ function createProgram() {
31883
32035
  model.command("list").description(t("cli.list_models")).action(async () => {
31884
32036
  const { config } = await bootstrap();
31885
32037
  console.log(t("cli.current_model"), config.model);
31886
- const { OpenAICompatProvider: OpenAICompatProvider2 } = await Promise.resolve().then(() => (init_openai_compat(), exports_openai_compat));
31887
- const provider2 = new OpenAICompatProvider2({
32038
+ const { createProvider: createProvider2 } = await Promise.resolve().then(() => (init_create(), exports_create));
32039
+ const provider2 = createProvider2(config.provider.type, {
31888
32040
  model: config.model,
31889
32041
  baseUrl: config.provider.baseUrl,
31890
32042
  apiKey: config.provider.apiKey,
@@ -31915,7 +32067,7 @@ function createProgram() {
31915
32067
  console.log(t("cli.model_hint"));
31916
32068
  });
31917
32069
  model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
31918
- const configPath = join44(homedir15(), ".mma", "config.json");
32070
+ const configPath = join45(homedir16(), ".mma", "config.json");
31919
32071
  const { config } = await bootstrap();
31920
32072
  config.model = name;
31921
32073
  saveConfig(config, configPath);
@@ -31951,7 +32103,7 @@ function createProgram() {
31951
32103
  await uncertify2(name, config);
31952
32104
  });
31953
32105
  program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
31954
- const configPath = join44(homedir15(), ".mma", "config.json");
32106
+ const configPath = join45(homedir16(), ".mma", "config.json");
31955
32107
  const { config } = await bootstrap();
31956
32108
  const contextWindow = parseInt(size, 10);
31957
32109
  if (isNaN(contextWindow) || contextWindow < 1024) {
@@ -31964,13 +32116,31 @@ function createProgram() {
31964
32116
  });
31965
32117
  const provider = program2.command("provider").description(t("cli.manage_providers"));
31966
32118
  provider.command("list").description(t("cli.list_providers")).action(async () => {
31967
- const { config } = await bootstrap();
32119
+ const { config, agent } = await bootstrap();
32120
+ const providers = agent.listProviders();
32121
+ if (providers.length > 0) {
32122
+ console.log(t("cli.current_provider"));
32123
+ for (const p of providers) {
32124
+ const marker = p.active ? pc2.green("* ") : " ";
32125
+ console.log(` ${marker}${p.label} (${pc2.dim(p.type)}) ${pc2.dim(p.baseUrl)}`);
32126
+ }
32127
+ return;
32128
+ }
31968
32129
  console.log(t("cli.current_provider"), config.provider.type);
31969
32130
  console.log(t("cli.base_url"), config.provider.baseUrl);
31970
32131
  });
31971
32132
  provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
31972
- const configPath = join44(homedir15(), ".mma", "config.json");
31973
- const { config } = await bootstrap();
32133
+ const configPath = join45(homedir16(), ".mma", "config.json");
32134
+ const { config, agent } = await bootstrap();
32135
+ if (config.provider.entries && config.provider.entries.length > 0) {
32136
+ try {
32137
+ await agent.setProvider(name);
32138
+ console.log(t("cli.provider_set", { name }));
32139
+ } catch (e) {
32140
+ console.log(pc2.red(e.message));
32141
+ }
32142
+ return;
32143
+ }
31974
32144
  config.provider.type = name;
31975
32145
  const baseUrl = HOSTED_BASE_URLS[name];
31976
32146
  if (baseUrl) {
@@ -31982,6 +32152,35 @@ function createProgram() {
31982
32152
  console.log(t("cli.provider_base_hint", { baseUrl }));
31983
32153
  }
31984
32154
  });
32155
+ provider.command("add").argument("<name>", "Provider type or label").option("--url <url>", "Base URL").option("--key <key>", "API key").description(t("cli.add_provider")).action(async (name, opts) => {
32156
+ const configPath = join45(homedir16(), ".mma", "config.json");
32157
+ const { config } = await bootstrap();
32158
+ const entries = Array.isArray(config.provider.entries) ? config.provider.entries : [];
32159
+ if (entries.length === 0) {
32160
+ entries.push({
32161
+ type: config.provider.type,
32162
+ label: config.provider.type,
32163
+ baseUrl: config.provider.baseUrl,
32164
+ apiKey: config.provider.apiKey
32165
+ });
32166
+ }
32167
+ const baseUrl = opts.url || HOSTED_BASE_URLS[name] || HOSTED_BASE_URLS[`opencode-${name}`] || "";
32168
+ if (!baseUrl) {
32169
+ console.log(pc2.red(t("cli.provider_no_url", { name })));
32170
+ return;
32171
+ }
32172
+ entries.push({
32173
+ type: name,
32174
+ label: name,
32175
+ baseUrl,
32176
+ apiKey: opts.key
32177
+ });
32178
+ config.provider.entries = entries;
32179
+ config.provider.active = config.provider.active || config.provider.type;
32180
+ saveConfig(config, configPath);
32181
+ console.log(pc2.green(t("cli.provider_added", { name })));
32182
+ console.log(t("cli.provider_switch_hint"));
32183
+ });
31985
32184
  const session2 = program2.command("session").description(t("cli.manage_sessions"));
31986
32185
  session2.command("list").description(t("cli.list_sessions")).action(async () => {
31987
32186
  const { sessionManager } = await bootstrap();
@@ -32785,8 +32984,8 @@ class LineEditor {
32785
32984
 
32786
32985
  // src/cli/repl.ts
32787
32986
  import { existsSync as existsSync53, readFileSync as readFileSync35, writeFileSync as writeFileSync17 } from "fs";
32788
- import { join as join47 } from "path";
32789
- import { homedir as homedir17 } from "os";
32987
+ import { join as join48 } from "path";
32988
+ import { homedir as homedir18 } from "os";
32790
32989
 
32791
32990
  // src/cli/completer.ts
32792
32991
  class SlashCommandProvider {
@@ -33230,8 +33429,9 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
33230
33429
  `);
33231
33430
  }
33232
33431
  }
33233
- toolEnd(_tool, duration, error, ctxDelta, costUsd) {
33432
+ toolEnd(_tool, duration, error, ctxDelta, costUsd, provider, model) {
33234
33433
  this.spinner.stop();
33434
+ const prov = provider && model ? `${pc2.dim(`${provider}·${model}`)}` : undefined;
33235
33435
  if (!this.rich) {
33236
33436
  const parts = [];
33237
33437
  if (ctxDelta !== undefined && ctxDelta !== 0) {
@@ -33241,6 +33441,8 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
33241
33441
  if (costUsd !== undefined && costUsd > 0) {
33242
33442
  parts.push(`${pc2.dim("cost")} ${pc2.yellow(formatUsd(costUsd))}`);
33243
33443
  }
33444
+ if (prov)
33445
+ parts.push(prov);
33244
33446
  if (parts.length > 0)
33245
33447
  this.out.write(`${parts.join(" ")}
33246
33448
  `);
@@ -33258,6 +33460,9 @@ ${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}
33258
33460
  if (costUsd !== undefined && costUsd > 0) {
33259
33461
  footer += ` ${pc2.dim("cost")} ${pc2.yellow(formatUsd(costUsd))}`;
33260
33462
  }
33463
+ if (prov) {
33464
+ footer += ` ${pc2.dim("via")} ${prov}`;
33465
+ }
33261
33466
  if (this.toolStyle === "inline") {
33262
33467
  this.out.write(`${GUTTER}${footer}
33263
33468
  `);
@@ -33357,24 +33562,16 @@ async function probeLspServers(config, baseDir, deps = {}) {
33357
33562
  await probeClient.probe(server, projectRoot, serverTimeout);
33358
33563
  ok.push({ language, ok: true, durationMs: Date.now() - started });
33359
33564
  } catch (e) {
33360
- const errorMsg = e instanceof Error ? e.message : String(e);
33361
- deps.logger?.warn(`LSP probe failed for ${language}: ${errorMsg}`, {
33362
- command: server.command,
33363
- timeout: serverTimeout,
33364
- durationMs: Date.now() - started
33365
- });
33366
33565
  failed.push({
33367
33566
  language,
33368
33567
  ok: false,
33369
- error: errorMsg,
33568
+ error: e instanceof Error ? e.message : String(e),
33370
33569
  durationMs: Date.now() - started
33371
33570
  });
33372
33571
  }
33373
33572
  };
33374
33573
  for (let i = 0;i < servers.length; i += maxParallel) {
33375
33574
  if (Date.now() >= deadline) {
33376
- const remaining = servers.slice(i).map((s) => s.language);
33377
- deps.logger?.warn(`LSP probe deadline reached, skipping: ${remaining.join(", ")}`);
33378
33575
  for (const { language } of servers.slice(i)) {
33379
33576
  failed.push({ language, ok: false, error: "timeout", durationMs: 0 });
33380
33577
  }
@@ -33394,9 +33591,9 @@ init_colors();
33394
33591
  init_js_identifiers();
33395
33592
  init_i18n();
33396
33593
  import { existsSync as existsSync52, readFileSync as readFileSync34 } from "fs";
33397
- import { join as join46 } from "path";
33594
+ import { join as join47 } from "path";
33398
33595
  function readActivePlan(baseDir) {
33399
- const p = join46(baseDir, ".mma", "plans", "active.json");
33596
+ const p = join47(baseDir, ".mma", "plans", "active.json");
33400
33597
  if (!existsSync52(p))
33401
33598
  return null;
33402
33599
  try {
@@ -33543,10 +33740,10 @@ class Repl {
33543
33740
  this.skillsModule = skillsModule;
33544
33741
  this.pluginManager = pluginManager;
33545
33742
  this.logger = logger;
33546
- this.configDir = configDir || join47(homedir17(), ".mma");
33743
+ this.configDir = configDir || join48(homedir18(), ".mma");
33547
33744
  this.baseDir = baseDir || process.cwd();
33548
33745
  this.noAgentsMd = noAgentsMd === true;
33549
- this.historyPath = join47(homedir17(), ".mma", "repl-history");
33746
+ this.historyPath = join48(homedir18(), ".mma", "repl-history");
33550
33747
  this.loadHistory();
33551
33748
  this.rl = process.stdin.isTTY ? new LineEditor({
33552
33749
  input: process.stdin,
@@ -33673,7 +33870,6 @@ class Repl {
33673
33870
  this.running = false;
33674
33871
  this.saveHistory();
33675
33872
  this.agent.shutdown();
33676
- this.logger?.closeSessionLog();
33677
33873
  if (this.exitOnClose)
33678
33874
  process.exit(0);
33679
33875
  });
@@ -33682,7 +33878,6 @@ class Repl {
33682
33878
  this.running = false;
33683
33879
  this.saveHistory();
33684
33880
  this.agent.shutdown();
33685
- this.logger?.closeSessionLog();
33686
33881
  process.exit(0);
33687
33882
  });
33688
33883
  }
@@ -33787,7 +33982,7 @@ ${t("image.clipboard_empty")}`));
33787
33982
  if (ev.type === "start") {
33788
33983
  renderer.toolStart(ev.tool, ev.args, stepContextForTool(this.activePlan, ev.tool, ev.args), ev.icon);
33789
33984
  } else {
33790
- renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta, ev.costUsd);
33985
+ renderer.toolEnd(ev.tool, ev.duration ?? 0, ev.error, ev.ctxDelta, ev.costUsd, ev.provider, ev.model);
33791
33986
  if (ev.tool === "plan" || ev.tool === "todo") {
33792
33987
  this.refreshActivePlan(renderer);
33793
33988
  }
@@ -33959,9 +34154,9 @@ ${t("image.clipboard_empty")}`));
33959
34154
  row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
33960
34155
  } else {
33961
34156
  const agentsMdCandidates = [
33962
- join47(this.baseDir, "AGENTS.md"),
33963
- join47(this.baseDir, ".mma", "AGENTS.md"),
33964
- join47(this.configDir, "AGENTS.md")
34157
+ join48(this.baseDir, "AGENTS.md"),
34158
+ join48(this.baseDir, ".mma", "AGENTS.md"),
34159
+ join48(this.configDir, "AGENTS.md")
33965
34160
  ];
33966
34161
  const foundAgents = agentsMdCandidates.filter((p) => existsSync53(p));
33967
34162
  if (foundAgents.length > 0) {
@@ -33974,7 +34169,7 @@ ${t("image.clipboard_empty")}`));
33974
34169
  }
33975
34170
  const meta = this.sessionManager?.getActiveMeta();
33976
34171
  if (meta) {
33977
- const sessionPath = join47(this.configDir, "sessions", meta.id);
34172
+ const sessionPath = join48(this.configDir, "sessions", meta.id);
33978
34173
  row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
33979
34174
  }
33980
34175
  const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
@@ -34029,7 +34224,6 @@ ${t("image.clipboard_empty")}`));
34029
34224
  this.running = false;
34030
34225
  this.saveHistory();
34031
34226
  this.agent.shutdown();
34032
- this.logger?.closeSessionLog();
34033
34227
  this.rl.close();
34034
34228
  }
34035
34229
  }
@@ -34061,8 +34255,8 @@ init_config2();
34061
34255
  init_i18n();
34062
34256
  init_colors();
34063
34257
  import { existsSync as existsSync54, readFileSync as readFileSync36 } from "fs";
34064
- import { join as join48, dirname as dirname18 } from "path";
34065
- import { homedir as homedir18 } from "os";
34258
+ import { join as join49, dirname as dirname18 } from "path";
34259
+ import { homedir as homedir19 } from "os";
34066
34260
  import { fileURLToPath as fileURLToPath6 } from "url";
34067
34261
 
34068
34262
  // src/modules/updater/index.ts
@@ -34165,7 +34359,7 @@ class UpdaterModule {
34165
34359
  // src/cli/main.ts
34166
34360
  function readVersion4() {
34167
34361
  const here = dirname18(fileURLToPath6(import.meta.url));
34168
- const candidates = [join48(here, "..", "..", "package.json"), join48(here, "..", "package.json")];
34362
+ const candidates = [join49(here, "..", "..", "package.json"), join49(here, "..", "package.json")];
34169
34363
  for (const p of candidates) {
34170
34364
  if (existsSync54(p)) {
34171
34365
  try {
@@ -34253,15 +34447,15 @@ async function main() {
34253
34447
  await updater?.waitForIdle();
34254
34448
  process.exit(exitCode);
34255
34449
  } else {
34256
- const configPath = join48(homedir18(), ".mma", "config.json");
34450
+ const configPath = join49(homedir19(), ".mma", "config.json");
34257
34451
  if (!existsSync54(configPath)) {
34258
34452
  console.log(pc2.yellow(`
34259
34453
  ` + t("cli.first_run") + `
34260
34454
  `));
34261
34455
  const answers = await runSetup();
34262
34456
  const config2 = loadConfig({
34263
- configDir: join48(homedir18(), ".mma"),
34264
- projectConfigPath: projectDir ? join48(projectDir, ".mmrc") : join48(process.cwd(), ".mmrc")
34457
+ configDir: join49(homedir19(), ".mma"),
34458
+ projectConfigPath: projectDir ? join49(projectDir, ".mmrc") : join49(process.cwd(), ".mmrc")
34265
34459
  });
34266
34460
  config2.provider.type = answers.provider;
34267
34461
  config2.provider.baseUrl = answers.apiBase;