micro-models-agent 0.45.0 → 0.46.2

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/cli/commands.js +323 -0
  3. package/dist/cli/completer.js +167 -0
  4. package/dist/cli/index.js +2 -0
  5. package/dist/cli/main.js +165 -0
  6. package/dist/cli/plugin-commands.js +36 -0
  7. package/dist/cli/repl-commands.js +661 -0
  8. package/dist/cli/repl.js +616 -0
  9. package/dist/cli/run-result.js +22 -0
  10. package/dist/cli/security-commands.js +164 -0
  11. package/dist/cli/setup.js +231 -0
  12. package/dist/config/config.js +249 -0
  13. package/dist/config/defaults.js +124 -0
  14. package/dist/config/experts.js +15 -0
  15. package/dist/config/index.js +3 -0
  16. package/dist/config/security.js +193 -0
  17. package/dist/config/types.js +1 -0
  18. package/dist/core/agent-moe.js +102 -0
  19. package/dist/core/agent.js +886 -0
  20. package/dist/core/bootstrap.js +404 -0
  21. package/dist/core/index.js +2 -0
  22. package/dist/core/prompt-builder.js +76 -0
  23. package/dist/core/session-logger.js +197 -0
  24. package/dist/core/types.js +1 -0
  25. package/dist/core/version.js +24 -0
  26. package/dist/core/workspace.js +76 -0
  27. package/dist/i18n/en.json +598 -0
  28. package/dist/i18n/index.js +46 -0
  29. package/dist/i18n/ru.json +598 -0
  30. package/dist/index.js +22 -0
  31. package/dist/llm/image-utils.js +143 -0
  32. package/dist/llm/index.js +4 -0
  33. package/dist/llm/model-loader.js +78 -0
  34. package/dist/llm/openai-compat.js +359 -0
  35. package/dist/llm/orchestrator.js +198 -0
  36. package/dist/llm/provider.js +10 -0
  37. package/dist/llm/response.js +39 -0
  38. package/dist/llm/token-counter.js +39 -0
  39. package/dist/llm/types.js +1 -0
  40. package/dist/logger/app-logger.js +143 -0
  41. package/dist/logger/file-log.js +151 -0
  42. package/dist/logger/index.js +1 -0
  43. package/dist/main.js +690 -168
  44. package/dist/migration/backup.js +45 -0
  45. package/dist/migration/detect.js +50 -0
  46. package/dist/migration/index.js +2 -0
  47. package/dist/modules/artifacts/store.js +61 -0
  48. package/dist/modules/browser/actions.js +76 -0
  49. package/dist/modules/browser/bridge-client.js +199 -0
  50. package/dist/modules/browser/bridge-path.js +10 -0
  51. package/dist/modules/browser/bridge-server.mjs +202 -202
  52. package/dist/modules/browser/cookie-store.js +24 -0
  53. package/dist/modules/browser/driver.js +136 -0
  54. package/dist/modules/browser/index.js +7 -0
  55. package/dist/modules/browser/module.js +29 -0
  56. package/dist/modules/browser/session.js +338 -0
  57. package/dist/modules/browser/snapshot.js +148 -0
  58. package/dist/modules/browser/types.js +12 -0
  59. package/dist/modules/certification/cli.js +174 -0
  60. package/dist/modules/certification/fact-checker.js +82 -0
  61. package/dist/modules/certification/loader.js +105 -0
  62. package/dist/modules/certification/manifest.js +50 -0
  63. package/dist/modules/certification/runner.js +159 -0
  64. package/dist/modules/certification/scenarios.js +124 -0
  65. package/dist/modules/certification/types.js +1 -0
  66. package/dist/modules/context/chunk-query.js +100 -0
  67. package/dist/modules/context/fact-extractor.js +162 -0
  68. package/dist/modules/context/history.js +15 -0
  69. package/dist/modules/context/index.js +1 -0
  70. package/dist/modules/context/manager.js +423 -0
  71. package/dist/modules/execution/audit-runners.js +152 -0
  72. package/dist/modules/execution/auditor.js +218 -0
  73. package/dist/modules/execution/execution-plugin.js +272 -0
  74. package/dist/modules/execution/index.js +8 -0
  75. package/dist/modules/execution/module.js +436 -0
  76. package/dist/modules/execution/moe-executor.js +291 -0
  77. package/dist/modules/execution/plan-coverage.js +68 -0
  78. package/dist/modules/execution/plan-persister.js +46 -0
  79. package/dist/modules/execution/plan-store.js +157 -0
  80. package/dist/modules/execution/plan-tool.js +508 -0
  81. package/dist/modules/execution/plan-validator.js +153 -0
  82. package/dist/modules/execution/planner.js +90 -0
  83. package/dist/modules/execution/stuck-detector.js +510 -0
  84. package/dist/modules/execution/tracker.js +67 -0
  85. package/dist/modules/execution/types.js +1 -0
  86. package/dist/modules/execution/verifier.js +222 -0
  87. package/dist/modules/execution/windows-commands.js +41 -0
  88. package/dist/modules/hallucination/confidence.js +66 -0
  89. package/dist/modules/hallucination/consistency.js +26 -0
  90. package/dist/modules/hallucination/detector.js +43 -0
  91. package/dist/modules/hallucination/factual.js +129 -0
  92. package/dist/modules/hallucination/index.js +5 -0
  93. package/dist/modules/hallucination/js-identifiers.js +262 -0
  94. package/dist/modules/hallucination/llm-judge.js +101 -0
  95. package/dist/modules/index.js +5 -0
  96. package/dist/modules/indexer/cache.js +40 -0
  97. package/dist/modules/indexer/index.js +3 -0
  98. package/dist/modules/indexer/module.js +245 -0
  99. package/dist/modules/indexer/project-profile.js +183 -0
  100. package/dist/modules/indexer/walker.js +101 -0
  101. package/dist/modules/lsp/check-tool.js +58 -0
  102. package/dist/modules/lsp/client.js +278 -0
  103. package/dist/modules/lsp/command.js +60 -0
  104. package/dist/modules/lsp/config.js +135 -0
  105. package/dist/modules/lsp/index.js +3 -0
  106. package/dist/modules/lsp/module.js +232 -0
  107. package/dist/modules/lsp/probe.js +76 -0
  108. package/dist/modules/lsp/project-root.js +32 -0
  109. package/dist/modules/lsp/startup-check.js +141 -0
  110. package/dist/modules/lsp/types.js +1 -0
  111. package/dist/modules/mcp/client.js +399 -0
  112. package/dist/modules/mcp/index.js +3 -0
  113. package/dist/modules/mcp/module.js +142 -0
  114. package/dist/modules/mcp/registry.js +15 -0
  115. package/dist/modules/memory/index.js +1 -0
  116. package/dist/modules/memory/module.js +96 -0
  117. package/dist/modules/memory/search.js +42 -0
  118. package/dist/modules/memory/store.js +69 -0
  119. package/dist/modules/pipelines/engine.js +60 -0
  120. package/dist/modules/pipelines/index.js +3 -0
  121. package/dist/modules/pipelines/parser.js +56 -0
  122. package/dist/modules/pipelines/template.js +14 -0
  123. package/dist/modules/plugins/builtin/lint-on-write.js +231 -0
  124. package/dist/modules/plugins/builtin/notify.js +9 -0
  125. package/dist/modules/plugins/index.js +1 -0
  126. package/dist/modules/plugins/loader.js +70 -0
  127. package/dist/modules/plugins/manager.js +217 -0
  128. package/dist/modules/plugins/types.js +1 -0
  129. package/dist/modules/processes/detect.js +34 -0
  130. package/dist/modules/processes/index.js +2 -0
  131. package/dist/modules/processes/registry.js +327 -0
  132. package/dist/modules/processes/runner.js +23 -0
  133. package/dist/modules/registry.js +47 -0
  134. package/dist/modules/security/audit-log.js +136 -0
  135. package/dist/modules/security/audit-notifier.js +292 -0
  136. package/dist/modules/security/command-validator.js +205 -0
  137. package/dist/modules/security/content-scanner.js +53 -0
  138. package/dist/modules/security/data-sanitizer.js +89 -0
  139. package/dist/modules/security/encryption.js +242 -0
  140. package/dist/modules/security/index.js +14 -0
  141. package/dist/modules/security/network-validator.js +71 -0
  142. package/dist/modules/security/path-validator.js +207 -0
  143. package/dist/modules/security/rate-limiter.js +119 -0
  144. package/dist/modules/security/security-policies.js +531 -0
  145. package/dist/modules/security/session-encryption.js +210 -0
  146. package/dist/modules/security/session-isolation.js +95 -0
  147. package/dist/modules/session/index.js +3 -0
  148. package/dist/modules/session/manager.js +172 -0
  149. package/dist/modules/session/module.js +24 -0
  150. package/dist/modules/session/store.js +222 -0
  151. package/dist/modules/session/types.js +1 -0
  152. package/dist/modules/skills/index.js +2 -0
  153. package/dist/modules/skills/loader.js +72 -0
  154. package/dist/modules/skills/matcher.js +27 -0
  155. package/dist/modules/skills/module.js +129 -0
  156. package/dist/modules/types.js +1 -0
  157. package/dist/modules/updater/checker.js +96 -0
  158. package/dist/modules/updater/index.js +2 -0
  159. package/dist/modules/updater/module.js +116 -0
  160. package/dist/modules/user-profile/compressor.js +16 -0
  161. package/dist/modules/user-profile/index.js +1 -0
  162. package/dist/modules/user-profile/profile.js +68 -0
  163. package/dist/skills/builtin/git.md +36 -36
  164. package/dist/skills/builtin/typescript.md +35 -35
  165. package/dist/tools/approve.js +32 -0
  166. package/dist/tools/attach-image.js +89 -0
  167. package/dist/tools/bash.js +496 -0
  168. package/dist/tools/browser.js +114 -0
  169. package/dist/tools/chunk-query.js +99 -0
  170. package/dist/tools/create-dir.js +55 -0
  171. package/dist/tools/delete-file.js +62 -0
  172. package/dist/tools/download-file.js +116 -0
  173. package/dist/tools/edit-file.js +79 -0
  174. package/dist/tools/enable-tools.js +58 -0
  175. package/dist/tools/executor.js +144 -0
  176. package/dist/tools/file-info.js +46 -0
  177. package/dist/tools/filter-tools.js +17 -0
  178. package/dist/tools/glob-tool.js +26 -0
  179. package/dist/tools/grep-tool.js +84 -0
  180. package/dist/tools/hidden-tools-block.js +37 -0
  181. package/dist/tools/index.js +78 -0
  182. package/dist/tools/list-dir.js +48 -0
  183. package/dist/tools/load-skill.js +42 -0
  184. package/dist/tools/mcp-call.js +68 -0
  185. package/dist/tools/move-file.js +85 -0
  186. package/dist/tools/path-utils.js +51 -0
  187. package/dist/tools/pipeline-run.js +144 -0
  188. package/dist/tools/preview.js +2 -0
  189. package/dist/tools/process-kill.js +29 -0
  190. package/dist/tools/process-list.js +36 -0
  191. package/dist/tools/process-log.js +45 -0
  192. package/dist/tools/question.js +140 -0
  193. package/dist/tools/read-file.js +91 -0
  194. package/dist/tools/recall.js +117 -0
  195. package/dist/tools/registry.js +47 -0
  196. package/dist/tools/remember.js +67 -0
  197. package/dist/tools/scope-check.js +30 -0
  198. package/dist/tools/search-history.js +84 -0
  199. package/dist/tools/subagent.js +196 -0
  200. package/dist/tools/types.js +1 -0
  201. package/dist/tools/user-input.js +123 -0
  202. package/dist/tools/web-browse.js +86 -0
  203. package/dist/tools/web-fetch.js +98 -0
  204. package/dist/tools/web-search.js +78 -0
  205. package/dist/tools/write-file.js +81 -0
  206. package/dist/ui/box.js +77 -0
  207. package/dist/ui/colors.js +4 -0
  208. package/dist/ui/diff.js +178 -0
  209. package/dist/ui/index.js +6 -0
  210. package/dist/ui/line-editor.js +703 -0
  211. package/dist/ui/line-math.js +69 -0
  212. package/dist/ui/md-formatter.js +212 -0
  213. package/dist/ui/output.js +13 -0
  214. package/dist/ui/plan-view.js +103 -0
  215. package/dist/ui/renderer.js +209 -0
  216. package/dist/ui/spinner.js +70 -0
  217. package/dist/ui/table.js +144 -0
  218. package/package.json +48 -48
package/dist/main.js CHANGED
@@ -2263,7 +2263,9 @@ var init_defaults = __esm(() => {
2263
2263
  retry: {
2264
2264
  maxRetries: 3,
2265
2265
  baseDelay: 1000,
2266
- maxDelay: 30000
2266
+ maxDelay: 30000,
2267
+ maxStreamRetries: 2,
2268
+ noDataTimeoutMs: 60000
2267
2269
  },
2268
2270
  maxToolIterations: 1000,
2269
2271
  stuckThreshold: 6,
@@ -2396,6 +2398,14 @@ Use read_file on {path} to see the current content before editing — the target
2396
2398
  "error.llm_retries": "LLM request failed after retries",
2397
2399
  "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}",
2398
2400
  "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
+ "env.runtime_node": "Running under Node (v{version}) — clipboard image paste, subagent performance and LSP spawn on Windows degrade. Install Bun (https://bun.sh) for full features.",
2404
+ "env.runtime_old": "Runtime version {version} is below the required engines {engine}.",
2405
+ "env.tool_missing": "Tool not found on PATH: {tool}",
2406
+ "env.playwright_missing": "Playwright package is not installed — the browser tool will fail. Install with: bun add playwright",
2407
+ "env.playwright_browsers_missing": "Playwright browsers not downloaded ({dir}). The browser tool will fail. Install with: bunx playwright install chromium",
2408
+ "env.crash_stderr": "MMA crashed ({type}): {message} — crash report written to ~/.mma/logs/crash.jsonl",
2399
2409
  "session.started": "Session started: {id}",
2400
2410
  "session.ended": "Session ended: {id}",
2401
2411
  "session.not_found": "Session not found: {id}",
@@ -2779,6 +2789,19 @@ Available commands:`,
2779
2789
  "repl.lsp_timeout": "timeout",
2780
2790
  "repl.lsp_failed": "did not start",
2781
2791
  "repl.lsp_unknown": "unknown",
2792
+ "repl.lsp": "LSP server management (status, restart, check)",
2793
+ "repl.lsp_usage": "Usage: /lsp [status|restart|check <path>]",
2794
+ "repl.lsp_not_available": "LSP module not available",
2795
+ "repl.lsp_status_header": "LSP Status:",
2796
+ "repl.lsp_enabled": "Enabled:",
2797
+ "repl.lsp_disabled_servers": "Disabled servers:",
2798
+ "repl.lsp_failure_counts": "Failure counts:",
2799
+ "repl.lsp_all_ok": "All servers operational",
2800
+ "repl.lsp_restarting": "Resetting LSP server state...",
2801
+ "repl.lsp_restarted": "LSP servers reset. Failed servers will be retried on next use.",
2802
+ "repl.lsp_check_usage": "Usage: /lsp check <file-or-directory>",
2803
+ "repl.lsp_checking": "Running LSP check on {path}...",
2804
+ "repl.lsp_check_error": "LSP check failed: {error}",
2782
2805
  "repl.work_dir": "Dir:",
2783
2806
  "repl.agents_label": "Instructions:",
2784
2807
  "repl.not_found": "not found",
@@ -3059,6 +3082,14 @@ var init_ru = __esm(() => {
3059
3082
  "error.llm_retries": "Запрос LLM не удался после повторов",
3060
3083
  "error.llm_429": "Превышен лимит запросов (HTTP 429) для {model} на {baseUrl}. Провайдер ограничивает трафик — особенно строгие free-модели. Получите API-ключ или переключитесь на платную/быструю модель: {baseUrl}",
3061
3084
  "error.no_response_body": "Нет потока тела ответа",
3085
+ "error.llm_stream_idle": "Поток LLM завис — нет данных {timeout}мс",
3086
+ "error.llm_timeout": "Время запроса LLM истекло ({timeout}мс)",
3087
+ "env.runtime_node": "Запущено под Node (v{version}) — вставка изображений из буфера и LSP на Windows работают урезанно. Установите Bun (https://bun.sh) для полного функционала.",
3088
+ "env.runtime_old": "Версия рантайма {version} ниже требуемой engines {engine}.",
3089
+ "env.tool_missing": "Инструмент не найден в PATH: {tool}",
3090
+ "env.playwright_missing": "Пакет Playwright не установлен — браузерный инструмент не будет работать. Установите: bun add playwright",
3091
+ "env.playwright_browsers_missing": "Браузеры Playwright не скачаны ({dir}). Браузерный инструмент не будет работать. Установите: bunx playwright install chromium",
3092
+ "env.crash_stderr": "MMA упал ({type}): {message} — отчёт о падении записан в ~/.mma/logs/crash.jsonl",
3062
3093
  "session.started": "Сессия начата: {id}",
3063
3094
  "session.ended": "Сессия завершена: {id}",
3064
3095
  "session.not_found": "Сессия не найдена: {id}",
@@ -3437,6 +3468,19 @@ var init_ru = __esm(() => {
3437
3468
  "repl.lsp_timeout": "таймаут",
3438
3469
  "repl.lsp_failed": "не стартовал",
3439
3470
  "repl.lsp_unknown": "неизвестно",
3471
+ "repl.lsp": "Управление LSP-серверами (status, restart, check)",
3472
+ "repl.lsp_usage": "Использование: /lsp [status|restart|check <путь>]",
3473
+ "repl.lsp_not_available": "Модуль LSP недоступен",
3474
+ "repl.lsp_status_header": "Статус LSP:",
3475
+ "repl.lsp_enabled": "Включён:",
3476
+ "repl.lsp_disabled_servers": "Отключённые серверы:",
3477
+ "repl.lsp_failure_counts": "Количество ошибок:",
3478
+ "repl.lsp_all_ok": "Все серверы работают",
3479
+ "repl.lsp_restarting": "Сброс состояния LSP-серверов...",
3480
+ "repl.lsp_restarted": "LSP-серверы сброшены. Упавшие серверы будут повторно запущены при следующем использовании.",
3481
+ "repl.lsp_check_usage": "Использование: /lsp check <файл-или-каталог>",
3482
+ "repl.lsp_checking": "Запуск LSP-проверки {path}...",
3483
+ "repl.lsp_check_error": "LSP-проверка не удалась: {error}",
3440
3484
  "repl.work_dir": "Директория:",
3441
3485
  "repl.agents_label": "Инструкции:",
3442
3486
  "repl.not_found": "не найден",
@@ -4596,6 +4640,20 @@ class Logger {
4596
4640
  }
4597
4641
  return sanitized;
4598
4642
  }
4643
+ logStructured(type, data) {
4644
+ const logTarget = this.sessionDir ?? this.logDir;
4645
+ if (!logTarget)
4646
+ return;
4647
+ try {
4648
+ appendFileSync2(join6(logTarget, "app.jsonl"), JSON.stringify({
4649
+ level: "info",
4650
+ ts: new Date().toISOString(),
4651
+ type,
4652
+ meta: this.sanitizeMeta(data)
4653
+ }) + `
4654
+ `, "utf-8");
4655
+ } catch {}
4656
+ }
4599
4657
  }
4600
4658
  var import_picocolors, LEVELS, LEVEL_COLORS;
4601
4659
  var init_app_logger = __esm(() => {
@@ -5172,7 +5230,9 @@ class OpenAICompatProvider {
5172
5230
  this.retryConfig = config.retry ?? {
5173
5231
  maxRetries: 3,
5174
5232
  baseDelay: 1000,
5175
- maxDelay: 30000
5233
+ maxDelay: 30000,
5234
+ maxStreamRetries: 2,
5235
+ noDataTimeoutMs: 60000
5176
5236
  };
5177
5237
  this.rateLimiter = createRateLimiter(config.rateLimits);
5178
5238
  }
@@ -5203,6 +5263,32 @@ class OpenAICompatProvider {
5203
5263
  }
5204
5264
  }
5205
5265
  async* doStream(messages, tools, signal, options) {
5266
+ const { baseDelay, maxDelay, maxStreamRetries, noDataTimeoutMs } = this.retryConfig;
5267
+ const streamRetries = maxStreamRetries ?? 2;
5268
+ const idleTimeoutMs = noDataTimeoutMs ?? 60000;
5269
+ for (let attempt = 0;; attempt++) {
5270
+ let emitted = false;
5271
+ const onEmit = () => {
5272
+ emitted = true;
5273
+ };
5274
+ try {
5275
+ const sawDone = yield* this.streamOnce(messages, tools, signal, options, onEmit, idleTimeoutMs);
5276
+ if (sawDone || emitted)
5277
+ return;
5278
+ if (attempt >= streamRetries)
5279
+ return;
5280
+ } catch (err) {
5281
+ if (err?.name === "AbortError" || err?.llmTerminal || signal?.aborted)
5282
+ throw err;
5283
+ if (emitted || attempt >= streamRetries)
5284
+ throw err;
5285
+ }
5286
+ const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
5287
+ const jitter = Math.random() * baseDelay * 0.1;
5288
+ await this.sleep(delay + jitter, signal);
5289
+ }
5290
+ }
5291
+ async* streamOnce(messages, tools, signal, options, onEmit, idleTimeoutMs) {
5206
5292
  const body = buildRequestBody({
5207
5293
  model: this.model,
5208
5294
  messages,
@@ -5218,8 +5304,11 @@ class OpenAICompatProvider {
5218
5304
  headers["Authorization"] = `Bearer ${this.config.apiKey}`;
5219
5305
  }
5220
5306
  const controller = new AbortController;
5221
- const totalTimeoutMs = 120000;
5222
- const timeoutId = setTimeout(() => controller.abort(), totalTimeoutMs);
5307
+ let timedOut = false;
5308
+ const timeoutId = setTimeout(() => {
5309
+ timedOut = true;
5310
+ controller.abort();
5311
+ }, REQUEST_TIMEOUT_MS);
5223
5312
  const abortSignal = (() => {
5224
5313
  if (!signal)
5225
5314
  return controller.signal;
@@ -5232,20 +5321,31 @@ class OpenAICompatProvider {
5232
5321
  return controller.signal;
5233
5322
  }
5234
5323
  })();
5235
- const response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
5236
- method: "POST",
5237
- headers,
5238
- body: JSON.stringify(body),
5239
- signal: abortSignal
5240
- });
5324
+ let response;
5325
+ try {
5326
+ response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
5327
+ method: "POST",
5328
+ headers,
5329
+ body: JSON.stringify(body),
5330
+ signal: abortSignal
5331
+ });
5332
+ } catch (err) {
5333
+ if (err?.name === "AbortError")
5334
+ throw err;
5335
+ const wrapped = err instanceof Error ? err : new Error(String(err));
5336
+ wrapped.llmTerminal = true;
5337
+ throw wrapped;
5338
+ }
5241
5339
  if (!response.ok) {
5242
5340
  clearTimeout(timeoutId);
5243
5341
  const errorText = await response.text();
5244
- throw new Error(t("error.llm_api", {
5342
+ const err = new Error(t("error.llm_api", {
5245
5343
  status: response.status,
5246
5344
  statusText: response.statusText,
5247
5345
  errorText
5248
5346
  }));
5347
+ err.llmTerminal = true;
5348
+ throw err;
5249
5349
  }
5250
5350
  const reader = response.body?.getReader();
5251
5351
  if (!reader) {
@@ -5256,9 +5356,29 @@ class OpenAICompatProvider {
5256
5356
  let buffer = "";
5257
5357
  const toolCallAccs = new Map;
5258
5358
  let usage;
5359
+ let sawDone = false;
5360
+ const readIdle = () => new Promise((resolve, reject) => {
5361
+ const idleTimer = setTimeout(() => {
5362
+ timedOut = true;
5363
+ controller.abort();
5364
+ }, idleTimeoutMs);
5365
+ reader.read().then((result) => {
5366
+ clearTimeout(idleTimer);
5367
+ if (timedOut)
5368
+ reject(new Error(t("error.llm_stream_idle", { timeout: idleTimeoutMs })));
5369
+ else
5370
+ resolve(result);
5371
+ }, (err) => {
5372
+ clearTimeout(idleTimer);
5373
+ if (timedOut)
5374
+ reject(new Error(t("error.llm_stream_idle", { timeout: idleTimeoutMs })));
5375
+ else
5376
+ reject(err);
5377
+ });
5378
+ });
5259
5379
  try {
5260
5380
  while (true) {
5261
- const { done, value } = await reader.read();
5381
+ const { done, value } = await readIdle();
5262
5382
  if (done)
5263
5383
  break;
5264
5384
  buffer += decoder.decode(value, { stream: true });
@@ -5270,8 +5390,10 @@ class OpenAICompatProvider {
5270
5390
  if (!trimmed || !trimmed.startsWith("data: "))
5271
5391
  continue;
5272
5392
  const data = trimmed.slice(6);
5273
- if (data === "[DONE]")
5393
+ if (data === "[DONE]") {
5394
+ sawDone = true;
5274
5395
  continue;
5396
+ }
5275
5397
  try {
5276
5398
  const parsed = JSON.parse(data);
5277
5399
  const choice = parsed.choices?.[0];
@@ -5288,6 +5410,7 @@ class OpenAICompatProvider {
5288
5410
  const delta = choice.delta || {};
5289
5411
  const finishReason = choice.finish_reason;
5290
5412
  if (delta.reasoning_content) {
5413
+ onEmit();
5291
5414
  yield { type: "reasoning", content: delta.reasoning_content };
5292
5415
  }
5293
5416
  if (delta.tool_calls) {
@@ -5307,11 +5430,13 @@ class OpenAICompatProvider {
5307
5430
  }
5308
5431
  }
5309
5432
  if (delta.content) {
5433
+ onEmit();
5310
5434
  yield { type: "text", content: delta.content };
5311
5435
  }
5312
5436
  if (finishReason === "tool_calls" && toolCallAccs.size > 0) {
5313
5437
  for (const [, acc] of toolCallAccs) {
5314
5438
  if (acc.name) {
5439
+ onEmit();
5315
5440
  yield {
5316
5441
  type: "tool_call",
5317
5442
  toolCall: {
@@ -5328,12 +5453,14 @@ class OpenAICompatProvider {
5328
5453
  }
5329
5454
  }
5330
5455
  if (usage) {
5456
+ onEmit();
5331
5457
  yield { type: "done", usage };
5332
5458
  }
5333
5459
  } finally {
5334
5460
  clearTimeout(timeoutId);
5335
5461
  reader.releaseLock();
5336
5462
  }
5463
+ return sawDone;
5337
5464
  }
5338
5465
  async doNonStreaming(messages, tools, signal, options) {
5339
5466
  const body = buildRequestBody({
@@ -5350,12 +5477,30 @@ class OpenAICompatProvider {
5350
5477
  if (this.config.apiKey && this.config.apiKey !== "not-needed") {
5351
5478
  headers["Authorization"] = `Bearer ${this.config.apiKey}`;
5352
5479
  }
5480
+ const controller = new AbortController;
5481
+ let timedOut = false;
5482
+ const timeoutId = setTimeout(() => {
5483
+ timedOut = true;
5484
+ controller.abort();
5485
+ }, REQUEST_TIMEOUT_MS);
5486
+ const abortSignal = (() => {
5487
+ if (!signal)
5488
+ return controller.signal;
5489
+ try {
5490
+ return AbortSignal.any([controller.signal, signal]);
5491
+ } catch {
5492
+ signal.addEventListener("abort", () => controller.abort(), {
5493
+ once: true
5494
+ });
5495
+ return controller.signal;
5496
+ }
5497
+ })();
5353
5498
  try {
5354
5499
  const response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
5355
5500
  method: "POST",
5356
5501
  headers,
5357
5502
  body: JSON.stringify(body),
5358
- signal
5503
+ signal: abortSignal
5359
5504
  });
5360
5505
  if (!response.ok) {
5361
5506
  const errorText = await response.text();
@@ -5402,7 +5547,12 @@ class OpenAICompatProvider {
5402
5547
  }
5403
5548
  return chunks;
5404
5549
  } catch (err) {
5550
+ if (timedOut && err?.name === "AbortError") {
5551
+ throw new Error(t("error.llm_timeout", { timeout: REQUEST_TIMEOUT_MS }));
5552
+ }
5405
5553
  throw err instanceof Error ? err : new Error(String(err));
5554
+ } finally {
5555
+ clearTimeout(timeoutId);
5406
5556
  }
5407
5557
  }
5408
5558
  countTokens(text) {
@@ -5486,6 +5636,7 @@ class OpenAICompatProvider {
5486
5636
  });
5487
5637
  }
5488
5638
  }
5639
+ var REQUEST_TIMEOUT_MS = 120000;
5489
5640
  var init_openai_compat = __esm(() => {
5490
5641
  init_token_counter();
5491
5642
  init_i18n();
@@ -11587,6 +11738,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
11587
11738
  onPhase?.(phase);
11588
11739
  }
11589
11740
  async run(input, onChunk, onMeta, onTool, onPhase) {
11741
+ this.shutdownRequested = false;
11590
11742
  this.setScope();
11591
11743
  const {
11592
11744
  config,
@@ -12259,7 +12411,6 @@ ${warnLine}
12259
12411
  if (killed > 0) {
12260
12412
  logger.info(`Killed ${killed} background process(es) on shutdown`);
12261
12413
  }
12262
- logger.closeSessionLog();
12263
12414
  pluginManager.runOnSessionEnd({
12264
12415
  logger,
12265
12416
  sessionManager: sessionManager?.getActiveMeta(),
@@ -19915,6 +20066,10 @@ import { resolve as resolve20 } from "path";
19915
20066
  import { platform as platform8 } from "os";
19916
20067
 
19917
20068
  class LspClient {
20069
+ logger = null;
20070
+ setLogger(logger) {
20071
+ this.logger = logger;
20072
+ }
19918
20073
  process = null;
19919
20074
  requestId = 0;
19920
20075
  pending = new Map;
@@ -19974,11 +20129,25 @@ class LspClient {
19974
20129
  try {
19975
20130
  await this.sendRequest("initialize", initParams, timeout);
19976
20131
  } catch (e) {
20132
+ const msg = e instanceof Error ? e.message : String(e);
20133
+ this.logger?.warn(`LSP initialize failed (attempt 1): ${msg}`, {
20134
+ command: config.command,
20135
+ projectRoot
20136
+ });
19977
20137
  if (!(e instanceof Error) || !e.message.includes("initialize"))
19978
20138
  throw e;
19979
20139
  await this.shutdown();
19980
20140
  await this.startServer(config, projectRoot);
19981
- await this.sendRequest("initialize", initParams, timeout);
20141
+ try {
20142
+ await this.sendRequest("initialize", initParams, timeout);
20143
+ } catch (retryErr) {
20144
+ const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
20145
+ this.logger?.error(`LSP initialize failed (attempt 2, giving up): ${retryMsg}`, {
20146
+ command: config.command,
20147
+ projectRoot
20148
+ });
20149
+ throw retryErr;
20150
+ }
19982
20151
  }
19983
20152
  this.initialized = true;
19984
20153
  }
@@ -20016,8 +20185,11 @@ class LspClient {
20016
20185
  });
20017
20186
  this.process = proc;
20018
20187
  setTimeout(() => {
20019
- if (!this.initialized && this.process)
20020
- reject(new Error("LSP server start timeout"));
20188
+ if (!this.initialized && this.process) {
20189
+ const msg = "LSP server start timeout";
20190
+ this.logger?.error(msg, { command: config.command, projectRoot, timeout: config.timeout ?? 1e4 });
20191
+ reject(new Error(msg));
20192
+ }
20021
20193
  }, config.timeout ?? 1e4);
20022
20194
  });
20023
20195
  }
@@ -20056,7 +20228,9 @@ class LspClient {
20056
20228
  try {
20057
20229
  const msg = JSON.parse(body);
20058
20230
  this.handleMessage(msg);
20059
- } catch {}
20231
+ } catch (e) {
20232
+ this.logger?.debug(`LSP JSON parse error: ${e instanceof Error ? e.message : String(e)}`);
20233
+ }
20060
20234
  }
20061
20235
  }
20062
20236
  handleMessage(msg) {
@@ -20094,7 +20268,9 @@ class LspClient {
20094
20268
  setTimeout(() => {
20095
20269
  if (this.pending.has(id)) {
20096
20270
  this.pending.delete(id);
20097
- reject(new Error(`LSP request timeout: ${method}`));
20271
+ const msg = `LSP request timeout: ${method}`;
20272
+ this.logger?.warn(msg, { method, timeout });
20273
+ reject(new Error(msg));
20098
20274
  }
20099
20275
  }, timeout);
20100
20276
  });
@@ -20104,27 +20280,37 @@ class LspClient {
20104
20280
  this.write(message);
20105
20281
  }
20106
20282
  write(message) {
20107
- if (!this.process?.stdin?.writable)
20283
+ if (!this.process?.stdin?.writable) {
20284
+ this.logger?.debug("LSP write failed: process stdin not writable");
20108
20285
  return;
20286
+ }
20109
20287
  const header = `Content-Length: ${Buffer.byteLength(message)}\r
20110
20288
  \r
20111
20289
  `;
20112
20290
  try {
20113
20291
  this.process.stdin.write(header + message);
20114
- } catch {}
20292
+ } catch (e) {
20293
+ this.logger?.debug(`LSP write error: ${e instanceof Error ? e.message : String(e)}`);
20294
+ }
20115
20295
  }
20116
20296
  async shutdown() {
20117
20297
  try {
20118
20298
  if (this.process && this.initialized && this.process.stdin?.writable) {
20119
- this.sendRequest("shutdown", null, 3000).catch(() => {});
20299
+ this.sendRequest("shutdown", null, 3000).catch((e) => {
20300
+ this.logger?.debug(`LSP shutdown request failed: ${e instanceof Error ? e.message : String(e)}`);
20301
+ });
20120
20302
  this.sendNotification("exit", null);
20121
20303
  await new Promise((r) => setTimeout(r, 200));
20122
20304
  }
20123
- } catch {} finally {
20305
+ } catch (e) {
20306
+ this.logger?.debug(`LSP shutdown error: ${e instanceof Error ? e.message : String(e)}`);
20307
+ } finally {
20124
20308
  if (this.process) {
20125
20309
  try {
20126
20310
  killTree(this.process);
20127
- } catch {}
20311
+ } catch (e) {
20312
+ this.logger?.debug(`LSP killTree error: ${e instanceof Error ? e.message : String(e)}`);
20313
+ }
20128
20314
  this.process = null;
20129
20315
  }
20130
20316
  this.initialized = false;
@@ -20232,9 +20418,26 @@ class LspModule {
20232
20418
  client;
20233
20419
  failuresByServer = new Map;
20234
20420
  disabledServers = new Set;
20235
- constructor(config, client) {
20421
+ logger = null;
20422
+ constructor(config, client, logger) {
20236
20423
  this.config = { ...DEFAULT_LSP_CONFIG, ...config };
20237
20424
  this.client = client ?? new LspClient;
20425
+ this.logger = logger ?? null;
20426
+ this.client.setLogger(this.logger);
20427
+ }
20428
+ setLogger(logger) {
20429
+ this.logger = logger;
20430
+ this.client.setLogger(logger);
20431
+ }
20432
+ resetDisabledServers() {
20433
+ this.failuresByServer.clear();
20434
+ this.disabledServers.clear();
20435
+ }
20436
+ getDisabledServers() {
20437
+ return Array.from(this.disabledServers);
20438
+ }
20439
+ getFailureCounts() {
20440
+ return new Map(this.failuresByServer);
20238
20441
  }
20239
20442
  isLspDisabled() {
20240
20443
  return this.disabledServers.size > 0;
@@ -20505,7 +20708,9 @@ async function runCheck(config, baseDir, deps) {
20505
20708
  lines.push(formatStartupError(file, baseDir, d));
20506
20709
  }
20507
20710
  }
20508
- } catch {}
20711
+ } catch (e) {
20712
+ deps.logger?.debug(`Startup LSP check failed for ${file}: ${e instanceof Error ? e.message : String(e)}`);
20713
+ }
20509
20714
  }
20510
20715
  if (checked === 0 || lines.length === 0)
20511
20716
  return null;
@@ -21395,15 +21600,197 @@ function readMmaVersion() {
21395
21600
  }
21396
21601
  var init_version = () => {};
21397
21602
 
21603
+ // src/core/environment.ts
21604
+ import { existsSync as existsSync44, readFileSync as readFileSync27, readdirSync as readdirSync15 } from "fs";
21605
+ import { spawnSync as spawnSync2 } from "child_process";
21606
+ import { createRequire as createRequire2 } from "module";
21607
+ import { join as join37, dirname as dirname14 } from "path";
21608
+ import { fileURLToPath as fileURLToPath3 } from "url";
21609
+ import { arch, homedir as homedir11, hostname as hostname2, platform as platform9, release } from "os";
21610
+ import { env as env2 } from "process";
21611
+ function readEngineRequirement() {
21612
+ const here = dirname14(fileURLToPath3(import.meta.url));
21613
+ const candidates = [join37(here, "..", "..", "package.json"), join37(here, "..", "package.json")];
21614
+ for (const p of candidates) {
21615
+ if (!existsSync44(p))
21616
+ continue;
21617
+ try {
21618
+ const raw = JSON.parse(readFileSync27(p, "utf8"));
21619
+ if (raw.engines?.node)
21620
+ return String(raw.engines.node);
21621
+ } catch {}
21622
+ }
21623
+ return ">=20";
21624
+ }
21625
+ function satisfiesMinimum(version, requirement) {
21626
+ const minMatch = requirement.match(/(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
21627
+ if (!minMatch)
21628
+ return true;
21629
+ const min = [
21630
+ parseInt(minMatch[1], 10),
21631
+ minMatch[2] ? parseInt(minMatch[2], 10) : 0,
21632
+ minMatch[3] ? parseInt(minMatch[3], 10) : 0
21633
+ ];
21634
+ const parts = version.replace(/^v/i, "").split(".");
21635
+ const got = [
21636
+ parts[0] ? parseInt(parts[0], 10) : 0,
21637
+ parts[1] ? parseInt(parts[1], 10) : 0,
21638
+ parts[2] ? parseInt(parts[2], 10) : 0
21639
+ ];
21640
+ for (let i = 0;i < 3; i++) {
21641
+ if (got[i] > min[i])
21642
+ return true;
21643
+ if (got[i] < min[i])
21644
+ return false;
21645
+ }
21646
+ return true;
21647
+ }
21648
+ function detectRuntime() {
21649
+ const bun = globalThis.Bun;
21650
+ const isBun = typeof bun !== "undefined" && typeof bun?.version !== "undefined";
21651
+ const engine2 = readEngineRequirement();
21652
+ const runtime = isBun ? "bun" : "node";
21653
+ const runtimeVersion = isBun ? String(bun.version) : process.version;
21654
+ return {
21655
+ runtime,
21656
+ runtimeVersion,
21657
+ nodeVersion: process.version,
21658
+ engine: engine2,
21659
+ engineOk: satisfiesMinimum(process.version, engine2)
21660
+ };
21661
+ }
21662
+ function toolVersion(cmd) {
21663
+ try {
21664
+ const res = spawnSync2(cmd, ["--version"], {
21665
+ encoding: "utf8",
21666
+ timeout: 3000,
21667
+ windowsHide: true,
21668
+ stdio: ["ignore", "pipe", "pipe"]
21669
+ });
21670
+ if (res.error || res.status !== 0)
21671
+ return "missing";
21672
+ const out = ((res.stdout || "") + (res.stderr || "")).trim();
21673
+ return out.split(/\r?\n/)[0].slice(0, 40) || "ok";
21674
+ } catch {
21675
+ return "missing";
21676
+ }
21677
+ }
21678
+ function playwrightBrowsersDir() {
21679
+ if (process.env.PLAYWRIGHT_BROWSERS_PATH)
21680
+ return process.env.PLAYWRIGHT_BROWSERS_PATH;
21681
+ return process.platform === "win32" ? join37(homedir11(), "AppData", "Local", "ms-playwright") : join37(homedir11(), ".cache", "ms-playwright");
21682
+ }
21683
+ function playwrightInfo() {
21684
+ let installed = false;
21685
+ let version = "";
21686
+ const browsersDir = playwrightBrowsersDir();
21687
+ try {
21688
+ const require2 = createRequire2(import.meta.url);
21689
+ const pkgPath = require2.resolve("playwright/package.json");
21690
+ installed = existsSync44(pkgPath);
21691
+ version = JSON.parse(readFileSync27(pkgPath, "utf8")).version || "";
21692
+ } catch {
21693
+ installed = false;
21694
+ }
21695
+ let browsersInstalled = false;
21696
+ try {
21697
+ if (existsSync44(browsersDir)) {
21698
+ browsersInstalled = readdirSync15(browsersDir).some((d) => /chrom/i.test(d));
21699
+ }
21700
+ } catch {
21701
+ browsersInstalled = false;
21702
+ }
21703
+ return { installed, version, browsersDir, browsersInstalled };
21704
+ }
21705
+ function checkEnvironmentRequirements(report) {
21706
+ const warnings = [];
21707
+ if (report.runtime.runtime === "node") {
21708
+ warnings.push(t("env.runtime_node", { version: report.runtime.nodeVersion }));
21709
+ }
21710
+ if (!report.runtime.engineOk) {
21711
+ warnings.push(t("env.runtime_old", {
21712
+ version: report.runtime.nodeVersion,
21713
+ engine: report.runtime.engine
21714
+ }));
21715
+ }
21716
+ if (report.tools.bun === "missing") {
21717
+ warnings.push(t("env.tool_missing", { tool: "bun" }));
21718
+ }
21719
+ if (report.tools.git === "missing") {
21720
+ warnings.push(t("env.tool_missing", { tool: "git" }));
21721
+ }
21722
+ if (report.features.browser && report.playwright) {
21723
+ if (!report.playwright.installed) {
21724
+ warnings.push(t("env.playwright_missing"));
21725
+ } else if (!report.playwright.browsersInstalled) {
21726
+ warnings.push(t("env.playwright_browsers_missing", { dir: report.playwright.browsersDir }));
21727
+ }
21728
+ }
21729
+ return warnings;
21730
+ }
21731
+ function collectEnvironment(opts) {
21732
+ const runtime = detectRuntime();
21733
+ const tools = {};
21734
+ if (opts.scanTools) {
21735
+ for (const tool of TOOL_CHECKS)
21736
+ tools[tool] = toolVersion(tool);
21737
+ }
21738
+ const provider = opts.config ? {
21739
+ model: opts.config.model,
21740
+ baseUrl: sanitizeUrl(opts.config.provider?.baseUrl || ""),
21741
+ contextWindow: opts.config.contextWindow,
21742
+ retry: {
21743
+ maxRetries: opts.config.retry?.maxRetries ?? 0,
21744
+ baseDelay: opts.config.retry?.baseDelay ?? 0,
21745
+ maxDelay: opts.config.retry?.maxDelay ?? 0,
21746
+ maxStreamRetries: opts.config.retry?.maxStreamRetries ?? 0,
21747
+ noDataTimeoutMs: opts.config.retry?.noDataTimeoutMs ?? 0
21748
+ }
21749
+ } : null;
21750
+ const report = {
21751
+ ts: new Date().toISOString(),
21752
+ mmaVersion: readMmaVersion(),
21753
+ runtime,
21754
+ os: {
21755
+ platform: platform9(),
21756
+ arch: arch(),
21757
+ release: release(),
21758
+ hostname: hostname2(),
21759
+ shell: env2.SHELL || env2.ComSpec || "unknown",
21760
+ home: homedir11(),
21761
+ cwd: process.cwd()
21762
+ },
21763
+ paths: { configDir: opts.configDir, baseDir: opts.baseDir || process.cwd() },
21764
+ tools,
21765
+ provider,
21766
+ features: { browser: Boolean(opts.config?.browser?.enabled) },
21767
+ playwright: playwrightInfo(),
21768
+ warnings: []
21769
+ };
21770
+ report.warnings = checkEnvironmentRequirements(report);
21771
+ return report;
21772
+ }
21773
+ function logEnvironment(report, logger) {
21774
+ logger.info(`Environment: ${report.os.platform} ${report.os.arch} | ${report.runtime.runtime} ${report.runtime.runtimeVersion} (node ${report.runtime.nodeVersion}) | mma ${report.mmaVersion} | ${report.provider?.model ?? "no provider"}`);
21775
+ logger.logStructured("environment", report);
21776
+ }
21777
+ var TOOL_CHECKS;
21778
+ var init_environment = __esm(() => {
21779
+ init_version();
21780
+ init_network_validator();
21781
+ init_i18n();
21782
+ TOOL_CHECKS = ["bun", "node", "git", "python"];
21783
+ });
21784
+
21398
21785
  // src/core/bootstrap.ts
21399
21786
  var exports_bootstrap = {};
21400
21787
  __export(exports_bootstrap, {
21401
21788
  buildSystemInfo: () => buildSystemInfo,
21402
21789
  bootstrap: () => bootstrap
21403
21790
  });
21404
- import { homedir as homedir11 } from "os";
21405
- import { join as join37, resolve as resolve23 } from "path";
21406
- import { existsSync as existsSync44, readFileSync as readFileSync27, writeFileSync as writeFileSync15 } from "fs";
21791
+ import { homedir as homedir12 } from "os";
21792
+ import { join as join38, resolve as resolve23 } from "path";
21793
+ import { existsSync as existsSync45, readFileSync as readFileSync28, writeFileSync as writeFileSync15 } from "fs";
21407
21794
  function buildSystemInfo(config, baseDir, profileCompressed) {
21408
21795
  const now = new Date().toISOString().replace("T", " ").slice(0, 19);
21409
21796
  const isWin = profileCompressed.toLowerCase().includes("win32");
@@ -21429,8 +21816,8 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
21429
21816
  `);
21430
21817
  }
21431
21818
  async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21432
- const dir = configDir || join37(homedir11(), ".mma");
21433
- const projectConfigPath = projectDir ? join37(projectDir, ".mmrc") : join37(process.cwd(), ".mmrc");
21819
+ const dir = configDir || join38(homedir12(), ".mma");
21820
+ const projectConfigPath = projectDir ? join38(projectDir, ".mmrc") : join38(process.cwd(), ".mmrc");
21434
21821
  const config = loadConfig({ configDir: dir, projectConfigPath });
21435
21822
  setLocale(config.locale);
21436
21823
  try {
@@ -21440,7 +21827,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21440
21827
  }
21441
21828
  } catch {}
21442
21829
  const logger = new Logger(config.logLevel);
21443
- logger.setLogDir(join37(dir, "logs"));
21830
+ logger.setLogDir(join38(dir, "logs"));
21444
21831
  logger.debug("MMA bootstrap", {
21445
21832
  version: config.version,
21446
21833
  model: config.model
@@ -21462,7 +21849,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21462
21849
  logger.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
21463
21850
  }
21464
21851
  }
21465
- const profile = new UserProfile(join37(dir));
21852
+ const profile = new UserProfile(join38(dir));
21466
21853
  profile.load() || profile.collect();
21467
21854
  profile.save();
21468
21855
  const llmProvider = new OpenAICompatProvider({
@@ -21474,7 +21861,17 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21474
21861
  rateLimits: config.security?.rateLimits
21475
21862
  });
21476
21863
  const baseDir = projectDir ? resolve23(projectDir) : process.cwd();
21477
- const projectMapCacheDir = join37(baseDir, ".mma");
21864
+ const envReport = collectEnvironment({
21865
+ configDir: dir,
21866
+ baseDir,
21867
+ config,
21868
+ scanTools: true
21869
+ });
21870
+ logEnvironment(envReport, logger);
21871
+ for (const warning of envReport.warnings) {
21872
+ logger.warn(warning);
21873
+ }
21874
+ const projectMapCacheDir = join38(baseDir, ".mma");
21478
21875
  const indexerModule = new IndexerModule({
21479
21876
  baseDir,
21480
21877
  cacheDir: projectMapCacheDir
@@ -21485,9 +21882,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21485
21882
  logger.warn(`Project indexing failed: ${err.message}`);
21486
21883
  }
21487
21884
  const skillsLoader = new SkillsLoader;
21488
- const builtinDir = join37(import.meta.dirname, "skills", "builtin");
21489
- const globalDir = join37(homedir11(), ".agents", "skills");
21490
- const projectSkillsDir = join37(baseDir, ".mma", "skills");
21885
+ const builtinDir = join38(import.meta.dirname, "skills", "builtin");
21886
+ const globalDir = join38(homedir12(), ".agents", "skills");
21887
+ const projectSkillsDir = join38(baseDir, ".mma", "skills");
21491
21888
  const availableSkills = skillsLoader.loadFromAllSources(builtinDir, globalDir, projectSkillsDir);
21492
21889
  const skillsBudget = Math.floor(config.contextWindow * config.skills.budget);
21493
21890
  const skillsModule = new SkillsModule(availableSkills, skillsBudget);
@@ -21503,11 +21900,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21503
21900
  essential: true,
21504
21901
  estimatedTokens: Math.ceil(systemInfoContent.length / 4)
21505
21902
  };
21506
- const agentsMdGlobal = join37(dir, "AGENTS.md");
21507
- if (!existsSync44(agentsMdGlobal)) {
21903
+ const agentsMdGlobal = join38(dir, "AGENTS.md");
21904
+ if (!existsSync45(agentsMdGlobal)) {
21508
21905
  writeFileSync15(agentsMdGlobal, "", "utf-8");
21509
21906
  }
21510
- const sessionDir = join37(dir, "sessions");
21907
+ const sessionDir = join38(dir, "sessions");
21511
21908
  const sessionStore = new SessionStore(sessionDir);
21512
21909
  sessionStore.init();
21513
21910
  const sessionManager = new SessionManager(sessionStore, {
@@ -21584,7 +21981,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21584
21981
  const mcpModule = new MCPModule(config);
21585
21982
  await mcpModule.initialize();
21586
21983
  moduleRegistry.register(mcpModule);
21587
- const memoryStore = new MemoryStore(join37(dir, "memory"));
21984
+ const memoryStore = new MemoryStore(join38(dir, "memory"));
21588
21985
  const memoryModule = new MemoryModule(memoryStore);
21589
21986
  moduleRegistry.register(memoryModule);
21590
21987
  if (config.browser.enabled) {
@@ -21596,7 +21993,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21596
21993
  pluginManager.register(browserPlugin);
21597
21994
  }
21598
21995
  }
21599
- const lspModule = new LspModule(config.lsp);
21996
+ const lspModule = new LspModule(config.lsp, undefined, logger);
21600
21997
  moduleRegistry.register(lspModule);
21601
21998
  const lspPlugin = lspModule.getPlugin();
21602
21999
  if (lspPlugin) {
@@ -21637,8 +22034,8 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21637
22034
  pluginManager.register(plugin);
21638
22035
  pluginManager.register(plugin2);
21639
22036
  const pluginLoader = new PluginLoader;
21640
- const globalPluginsDir = join37(homedir11(), ".mma", "plugins");
21641
- const projectPluginsDir = join37(baseDir, ".mma", "plugins");
22037
+ const globalPluginsDir = join38(homedir12(), ".mma", "plugins");
22038
+ const projectPluginsDir = join38(baseDir, ".mma", "plugins");
21642
22039
  const mmaVersion = readMmaVersion();
21643
22040
  pluginLoader.loadFromDir(globalPluginsDir, pluginManager, logger, {
21644
22041
  source: "global",
@@ -21664,13 +22061,13 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
21664
22061
  const skipAgentsMd = noAgentsMd === true;
21665
22062
  if (!skipAgentsMd) {
21666
22063
  const agentsMdCandidates = [
21667
- join37(baseDir, "AGENTS.md"),
21668
- join37(baseDir, ".mma", "AGENTS.md"),
21669
- join37(dir, "AGENTS.md")
22064
+ join38(baseDir, "AGENTS.md"),
22065
+ join38(baseDir, ".mma", "AGENTS.md"),
22066
+ join38(dir, "AGENTS.md")
21670
22067
  ];
21671
22068
  for (const p of agentsMdCandidates) {
21672
- if (existsSync44(p)) {
21673
- const content = readFileSync27(p, "utf-8").trim();
22069
+ if (existsSync45(p)) {
22070
+ const content = readFileSync28(p, "utf-8").trim();
21674
22071
  if (content) {
21675
22072
  agentsMdBlocks.push({
21676
22073
  content,
@@ -21773,6 +22170,7 @@ var init_bootstrap = __esm(() => {
21773
22170
  init_i18n();
21774
22171
  init_agent();
21775
22172
  init_version();
22173
+ init_environment();
21776
22174
  });
21777
22175
 
21778
22176
  // node_modules/ansi-regex/index.js
@@ -22541,20 +22939,20 @@ __export(exports_manifest, {
22541
22939
  getCertMark: () => getCertMark,
22542
22940
  MANIFEST_PATH: () => MANIFEST_PATH
22543
22941
  });
22544
- import { existsSync as existsSync45, readFileSync as readFileSync28, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
22545
- import { homedir as homedir13 } from "os";
22546
- import { join as join39 } from "path";
22942
+ import { existsSync as existsSync46, readFileSync as readFileSync29, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
22943
+ import { homedir as homedir14 } from "os";
22944
+ import { join as join40 } from "path";
22547
22945
  function readManifest(path = MANIFEST_PATH) {
22548
22946
  try {
22549
- if (existsSync45(path)) {
22550
- const raw = JSON.parse(readFileSync28(path, "utf-8"));
22947
+ if (existsSync46(path)) {
22948
+ const raw = JSON.parse(readFileSync29(path, "utf-8"));
22551
22949
  return { version: 1, certifications: raw.certifications ?? [] };
22552
22950
  }
22553
22951
  } catch {}
22554
22952
  return { version: 1, certifications: [] };
22555
22953
  }
22556
22954
  function saveManifest(m, path = MANIFEST_PATH) {
22557
- mkdirSync18(join39(homedir13(), ".mma"), { recursive: true });
22955
+ mkdirSync18(join40(homedir14(), ".mma"), { recursive: true });
22558
22956
  writeFileSync16(path, JSON.stringify(m, null, 2), "utf-8");
22559
22957
  }
22560
22958
  function upsertCertification(entry, path = MANIFEST_PATH) {
@@ -22589,7 +22987,7 @@ function getCertMark(model, providerUrl, currentVersion, path = MANIFEST_PATH) {
22589
22987
  }
22590
22988
  var MANIFEST_PATH;
22591
22989
  var init_manifest = __esm(() => {
22592
- MANIFEST_PATH = join39(homedir13(), ".mma", "certifications.json");
22990
+ MANIFEST_PATH = join40(homedir14(), ".mma", "certifications.json");
22593
22991
  });
22594
22992
 
22595
22993
  // node_modules/yaml/dist/nodes/identity.js
@@ -29712,8 +30110,8 @@ var init_scenarios = __esm(() => {
29712
30110
  });
29713
30111
 
29714
30112
  // src/modules/certification/loader.ts
29715
- import { existsSync as existsSync46, readdirSync as readdirSync15, readFileSync as readFileSync29 } from "fs";
29716
- import { join as join40 } from "path";
30113
+ import { existsSync as existsSync47, readdirSync as readdirSync16, readFileSync as readFileSync30 } from "fs";
30114
+ import { join as join41 } from "path";
29717
30115
  function validateScenario(s) {
29718
30116
  const errors2 = [];
29719
30117
  const isSkip = s.mode === "skip";
@@ -29762,12 +30160,12 @@ function loadScenarios(userDir) {
29762
30160
  else
29763
30161
  scenarios.push(s);
29764
30162
  }
29765
- if (userDir && existsSync46(userDir)) {
29766
- for (const file of readdirSync15(userDir)) {
30163
+ if (userDir && existsSync47(userDir)) {
30164
+ for (const file of readdirSync16(userDir)) {
29767
30165
  if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
29768
30166
  continue;
29769
30167
  try {
29770
- const raw = readFileSync29(join40(userDir, file), "utf-8");
30168
+ const raw = readFileSync30(join41(userDir, file), "utf-8");
29771
30169
  const data = $parse(raw);
29772
30170
  const parsed = normalizeScenario(data, file);
29773
30171
  const errs = validateScenario(parsed);
@@ -29820,8 +30218,8 @@ var init_loader3 = __esm(() => {
29820
30218
  });
29821
30219
 
29822
30220
  // src/modules/certification/fact-checker.ts
29823
- import { existsSync as existsSync47, readFileSync as readFileSync30, statSync as statSync8 } from "fs";
29824
- import { join as join41 } from "path";
30221
+ import { existsSync as existsSync48, readFileSync as readFileSync31, statSync as statSync8 } from "fs";
30222
+ import { join as join42 } from "path";
29825
30223
  function checkSandbox(sandboxDir, checks, exitCode, output) {
29826
30224
  const failures = [];
29827
30225
  for (const check of checks) {
@@ -29838,16 +30236,16 @@ function runCheck2(sandboxDir, check, exitCode, output) {
29838
30236
  case "outputContains":
29839
30237
  return output.includes(check.text);
29840
30238
  case "fileExists":
29841
- return isFile(join41(sandboxDir, check.path));
30239
+ return isFile(join42(sandboxDir, check.path));
29842
30240
  case "fileNotExists":
29843
- return !existsSync47(join41(sandboxDir, check.path));
30241
+ return !existsSync48(join42(sandboxDir, check.path));
29844
30242
  case "dirExists":
29845
- return isDir(join41(sandboxDir, check.path));
30243
+ return isDir(join42(sandboxDir, check.path));
29846
30244
  case "fileContent": {
29847
- const abs = join41(sandboxDir, check.path);
30245
+ const abs = join42(sandboxDir, check.path);
29848
30246
  if (!isFile(abs))
29849
30247
  return false;
29850
- const content = readFileSync30(abs, "utf-8");
30248
+ const content = readFileSync31(abs, "utf-8");
29851
30249
  if (check.contains !== undefined)
29852
30250
  return content.includes(check.contains);
29853
30251
  if (check.equals !== undefined)
@@ -29855,10 +30253,10 @@ function runCheck2(sandboxDir, check, exitCode, output) {
29855
30253
  return false;
29856
30254
  }
29857
30255
  case "fileRegex": {
29858
- const abs = join41(sandboxDir, check.path);
30256
+ const abs = join42(sandboxDir, check.path);
29859
30257
  if (!isFile(abs))
29860
30258
  return false;
29861
- return new RegExp(check.pattern).test(readFileSync30(abs, "utf-8"));
30259
+ return new RegExp(check.pattern).test(readFileSync31(abs, "utf-8"));
29862
30260
  }
29863
30261
  default:
29864
30262
  return false;
@@ -29866,14 +30264,14 @@ function runCheck2(sandboxDir, check, exitCode, output) {
29866
30264
  }
29867
30265
  function isFile(p) {
29868
30266
  try {
29869
- return existsSync47(p) && statSync8(p).isFile();
30267
+ return existsSync48(p) && statSync8(p).isFile();
29870
30268
  } catch {
29871
30269
  return false;
29872
30270
  }
29873
30271
  }
29874
30272
  function isDir(p) {
29875
30273
  try {
29876
- return existsSync47(p) && statSync8(p).isDirectory();
30274
+ return existsSync48(p) && statSync8(p).isDirectory();
29877
30275
  } catch {
29878
30276
  return false;
29879
30277
  }
@@ -29904,9 +30302,9 @@ var init_fact_checker = () => {};
29904
30302
 
29905
30303
  // src/modules/certification/runner.ts
29906
30304
  import { spawn as spawn8 } from "child_process";
29907
- import { existsSync as existsSync48, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
29908
- import { platform as platform9 } from "os";
29909
- import { join as join42, resolve as resolve24, dirname as dirname14 } from "path";
30305
+ import { existsSync as existsSync49, mkdirSync as mkdirSync19, rmSync as rmSync4, cpSync as cpSync2 } from "fs";
30306
+ import { platform as platform10 } from "os";
30307
+ import { join as join43, resolve as resolve24, dirname as dirname15 } from "path";
29910
30308
  async function runScenario(scenario, opts) {
29911
30309
  if (scenario.mode === "skip") {
29912
30310
  return {
@@ -29925,7 +30323,7 @@ async function runScenario(scenario, opts) {
29925
30323
  let passed = 0;
29926
30324
  let firstError;
29927
30325
  for (let i = 1;i <= reps; i++) {
29928
- const sandbox = join42(opts.sandboxBase, `run-${scenario.id}-${i}`);
30326
+ const sandbox = join43(opts.sandboxBase, `run-${scenario.id}-${i}`);
29929
30327
  let failures = [];
29930
30328
  let exitCode = -1;
29931
30329
  let output = "";
@@ -29939,15 +30337,15 @@ async function runScenario(scenario, opts) {
29939
30337
  sandbox,
29940
30338
  scenario.prompt
29941
30339
  ];
29942
- const env2 = {
30340
+ const env3 = {
29943
30341
  ...process.env,
29944
30342
  MMA_MODEL: opts.model,
29945
30343
  MMA_PROVIDER_BASEURL: opts.providerUrl,
29946
30344
  MMA_CONTEXT_WINDOW: String(opts.contextWindow ?? 32000)
29947
30345
  };
29948
30346
  if (opts.providerKey)
29949
- env2.MMA_PROVIDER_APIKEY = opts.providerKey;
29950
- const res = await runner(env2, opts.mmaRoot, args, timeoutMs);
30347
+ env3.MMA_PROVIDER_APIKEY = opts.providerKey;
30348
+ const res = await runner(env3, opts.mmaRoot, args, timeoutMs);
29951
30349
  output = `${res.stdout}
29952
30350
  ${res.stderr}`;
29953
30351
  exitCode = res.code ?? -1;
@@ -29986,25 +30384,25 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
29986
30384
  rmSync4(sandbox, { recursive: true, force: true });
29987
30385
  mkdirSync19(sandbox, { recursive: true });
29988
30386
  for (const f of scenario.fixtures ?? []) {
29989
- const src = join42(mmaRoot, f.source);
29990
- if (!existsSync48(src)) {
30387
+ const src = join43(mmaRoot, f.source);
30388
+ if (!existsSync49(src)) {
29991
30389
  throw new Error(`fixture missing: ${f.source}`);
29992
30390
  }
29993
- const dest = join42(sandbox, f.dest);
29994
- mkdirSync19(dirname14(dest), { recursive: true });
30391
+ const dest = join43(sandbox, f.dest);
30392
+ mkdirSync19(dirname15(dest), { recursive: true });
29995
30393
  cpSync2(src, dest);
29996
30394
  }
29997
30395
  }
29998
30396
  function resolveMmaEntry(mmaRoot) {
29999
- const dev = join42(mmaRoot, "src", "cli", "main.ts");
30000
- if (existsSync48(dev))
30397
+ const dev = join43(mmaRoot, "src", "cli", "main.ts");
30398
+ if (existsSync49(dev))
30001
30399
  return dev;
30002
- return join42(mmaRoot, "dist", "main.js");
30400
+ return join43(mmaRoot, "dist", "main.js");
30003
30401
  }
30004
30402
  function findMmaRoot(fromDir) {
30005
30403
  const candidates = [resolve24(fromDir, "..", "..", ".."), resolve24(fromDir, "..")];
30006
30404
  for (const c of candidates) {
30007
- if (existsSync48(join42(c, "package.json")))
30405
+ if (existsSync49(join43(c, "package.json")))
30008
30406
  return c;
30009
30407
  }
30010
30408
  return process.cwd();
@@ -30013,7 +30411,7 @@ function killTree2(child) {
30013
30411
  const pid = child.pid;
30014
30412
  if (!pid)
30015
30413
  return;
30016
- if (platform9() === "win32") {
30414
+ if (platform10() === "win32") {
30017
30415
  spawn8("taskkill", ["/pid", String(pid), "/T", "/F"], {
30018
30416
  windowsHide: true,
30019
30417
  stdio: "ignore"
@@ -30028,10 +30426,10 @@ function killTree2(child) {
30028
30426
  } catch {}
30029
30427
  }
30030
30428
  }
30031
- var defaultRunner2 = (env2, cwd, args, timeoutMs) => new Promise((resolvePromise) => {
30429
+ var defaultRunner2 = (env3, cwd, args, timeoutMs) => new Promise((resolvePromise) => {
30032
30430
  const child = spawn8(process.execPath, args, {
30033
30431
  cwd,
30034
- env: env2,
30432
+ env: env3,
30035
30433
  windowsHide: true,
30036
30434
  stdio: ["ignore", "pipe", "pipe"]
30037
30435
  });
@@ -30071,16 +30469,16 @@ __export(exports_cli, {
30071
30469
  certList: () => certList
30072
30470
  });
30073
30471
  import { rmSync as rmSync5 } from "fs";
30074
- import { homedir as homedir14 } from "os";
30075
- import { join as join43, dirname as dirname15 } from "path";
30076
- import { fileURLToPath as fileURLToPath3 } from "url";
30077
- import { existsSync as existsSync49, readFileSync as readFileSync31 } from "fs";
30472
+ import { homedir as homedir15 } from "os";
30473
+ import { join as join44, dirname as dirname16 } from "path";
30474
+ import { fileURLToPath as fileURLToPath4 } from "url";
30475
+ import { existsSync as existsSync50, readFileSync as readFileSync32 } from "fs";
30078
30476
  function readVersion() {
30079
- const candidates = [join43(MMA_ROOT, "package.json")];
30477
+ const candidates = [join44(MMA_ROOT, "package.json")];
30080
30478
  for (const p of candidates) {
30081
- if (existsSync49(p)) {
30479
+ if (existsSync50(p)) {
30082
30480
  try {
30083
- const raw = JSON.parse(readFileSync31(p, "utf-8"));
30481
+ const raw = JSON.parse(readFileSync32(p, "utf-8"));
30084
30482
  if (raw.version)
30085
30483
  return raw.version;
30086
30484
  } catch {}
@@ -30116,7 +30514,7 @@ async function certify(opts) {
30116
30514
  return;
30117
30515
  }
30118
30516
  console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
30119
- const sandboxBase = join43(process.cwd(), ".mma", "certification");
30517
+ const sandboxBase = join44(process.cwd(), ".mma", "certification");
30120
30518
  const results = [];
30121
30519
  const total = selected.length;
30122
30520
  let idx = 0;
@@ -30228,9 +30626,9 @@ var init_cli = __esm(() => {
30228
30626
  init_loader3();
30229
30627
  init_runner2();
30230
30628
  init_manifest();
30231
- HERE = dirname15(fileURLToPath3(import.meta.url));
30629
+ HERE = dirname16(fileURLToPath4(import.meta.url));
30232
30630
  MMA_ROOT = findMmaRoot(HERE);
30233
- USER_SCENARIO_DIR = join43(homedir14(), ".mma", "certification", "scenarios");
30631
+ USER_SCENARIO_DIR = join44(homedir15(), ".mma", "certification", "scenarios");
30234
30632
  });
30235
30633
 
30236
30634
  // src/cli/repl-commands.ts
@@ -30239,17 +30637,17 @@ __export(exports_repl_commands, {
30239
30637
  registerAllCommands: () => registerAllCommands,
30240
30638
  COMMAND_GROUPS: () => COMMAND_GROUPS
30241
30639
  });
30242
- import { join as join45, dirname as dirname17 } from "path";
30243
- import { homedir as homedir16 } from "os";
30244
- import { existsSync as existsSync51, readFileSync as readFileSync33 } from "fs";
30245
- import { fileURLToPath as fileURLToPath5 } from "url";
30640
+ import { join as join46, dirname as dirname18 } from "path";
30641
+ import { homedir as homedir17 } from "os";
30642
+ import { existsSync as existsSync52, readFileSync as readFileSync34 } from "fs";
30643
+ import { fileURLToPath as fileURLToPath6 } from "url";
30246
30644
  function readVersion3() {
30247
- const here = dirname17(fileURLToPath5(import.meta.url));
30248
- const candidates = [join45(here, "..", "..", "package.json"), join45(here, "..", "package.json")];
30645
+ const here = dirname18(fileURLToPath6(import.meta.url));
30646
+ const candidates = [join46(here, "..", "..", "package.json"), join46(here, "..", "package.json")];
30249
30647
  for (const p of candidates) {
30250
- if (existsSync51(p)) {
30648
+ if (existsSync52(p)) {
30251
30649
  try {
30252
- const raw = JSON.parse(readFileSync33(p, "utf8"));
30650
+ const raw = JSON.parse(readFileSync34(p, "utf8"));
30253
30651
  if (raw.version)
30254
30652
  return raw.version;
30255
30653
  } catch {}
@@ -30313,7 +30711,7 @@ function registerMmaCommands(ctx) {
30313
30711
  }
30314
30712
  try {
30315
30713
  const { loadFileAsDataUrl: loadFileAsDataUrl2, loadUrlAsDataUrl: loadUrlAsDataUrl2, readClipboardImage: readClipboardImage2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
30316
- const { existsSync: existsSync52 } = await import("fs");
30714
+ const { existsSync: existsSync53 } = await import("fs");
30317
30715
  const { resolve: resolve25 } = await import("path");
30318
30716
  let dataUrl;
30319
30717
  let label;
@@ -30333,7 +30731,7 @@ function registerMmaCommands(ctx) {
30333
30731
  label = source;
30334
30732
  } else {
30335
30733
  const absPath = resolve25(process.cwd(), source);
30336
- if (!existsSync52(absPath)) {
30734
+ if (!existsSync53(absPath)) {
30337
30735
  console.log(pc2.red(t("image.not_found", { path: source })));
30338
30736
  return;
30339
30737
  }
@@ -30412,7 +30810,7 @@ function registerMmaCommands(ctx) {
30412
30810
  console.log(pc2.yellow(t("repl.wizard_running")));
30413
30811
  await ctx.withExclusiveInput(async () => {
30414
30812
  const answers = await runSetup(ctx.rl);
30415
- const configPath = join45(homedir16(), ".mma", "config.json");
30813
+ const configPath = join46(homedir17(), ".mma", "config.json");
30416
30814
  ctx.config.provider.type = answers.provider;
30417
30815
  ctx.config.provider.baseUrl = answers.apiBase;
30418
30816
  ctx.config.provider.apiKey = answers.apiKey;
@@ -30466,7 +30864,7 @@ Excluded blocks: ${info.excluded.length}`));
30466
30864
  return;
30467
30865
  }
30468
30866
  ctx.config.provider.type = name;
30469
- const configPath = join45(homedir16(), ".mma", "config.json");
30867
+ const configPath = join46(homedir17(), ".mma", "config.json");
30470
30868
  saveConfig(ctx.config, configPath);
30471
30869
  await ctx.agent.reconfigure(ctx.config);
30472
30870
  console.log(pc2.green(t("repl.provider_set", { name })));
@@ -30522,7 +30920,7 @@ Excluded blocks: ${info.excluded.length}`));
30522
30920
  return;
30523
30921
  }
30524
30922
  ctx.config.model = name;
30525
- const configPath = join45(homedir16(), ".mma", "config.json");
30923
+ const configPath = join46(homedir17(), ".mma", "config.json");
30526
30924
  saveConfig(ctx.config, configPath);
30527
30925
  await ctx.agent.reconfigure(ctx.config);
30528
30926
  console.log(pc2.green(t("repl.model_set", { name })));
@@ -30547,7 +30945,7 @@ Excluded blocks: ${info.excluded.length}`));
30547
30945
  return;
30548
30946
  }
30549
30947
  ctx.config.contextWindow = size;
30550
- const configPath = join45(homedir16(), ".mma", "config.json");
30948
+ const configPath = join46(homedir17(), ".mma", "config.json");
30551
30949
  saveConfig(ctx.config, configPath);
30552
30950
  await ctx.agent.reconfigure(ctx.config);
30553
30951
  console.log(pc2.green(t("cli.context_set", { size })));
@@ -30565,11 +30963,11 @@ Excluded blocks: ${info.excluded.length}`));
30565
30963
  }
30566
30964
  ctx.agent.shutdown();
30567
30965
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
30568
- const { homedir: homedir17 } = await import("os");
30569
- const { join: join46 } = await import("path");
30966
+ const { homedir: homedir18 } = await import("os");
30967
+ const { join: join47 } = await import("path");
30570
30968
  const configDir = ctx.configDir;
30571
30969
  const baseDir = ctx.baseDir;
30572
- const projectConfigPath = join46(baseDir, ".mmrc");
30970
+ const projectConfigPath = join47(baseDir, ".mmrc");
30573
30971
  const freshConfig = loadConfig2({ configDir, projectConfigPath });
30574
30972
  Object.assign(ctx.config, freshConfig);
30575
30973
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
@@ -30620,6 +31018,70 @@ Excluded blocks: ${info.excluded.length}`));
30620
31018
  }
30621
31019
  }
30622
31020
  });
31021
+ ctx.registerCommand({
31022
+ name: "lsp",
31023
+ description: t("repl.lsp"),
31024
+ usage: t("repl.lsp_usage"),
31025
+ action: async (args) => {
31026
+ const subcommand = args[0] || "status";
31027
+ const lspModule = ctx.agent.deps?.moduleRegistry?.getModules?.()?.find((m) => m.name === "lsp");
31028
+ if (!lspModule) {
31029
+ console.log(pc2.yellow(t("repl.lsp_not_available")));
31030
+ return;
31031
+ }
31032
+ switch (subcommand) {
31033
+ case "status": {
31034
+ const disabled = lspModule.getDisabledServers();
31035
+ const failures = lspModule.getFailureCounts();
31036
+ const config = ctx.config.lsp;
31037
+ console.log(pc2.bold(t("repl.lsp_status_header")));
31038
+ console.log(`${t("repl.lsp_enabled")} ${config?.enabled ? pc2.green("yes") : pc2.red("no")}`);
31039
+ if (disabled.length > 0) {
31040
+ console.log(pc2.yellow(`${t("repl.lsp_disabled_servers")} ${disabled.join(", ")}`));
31041
+ }
31042
+ if (failures.size > 0) {
31043
+ console.log(pc2.dim(t("repl.lsp_failure_counts")));
31044
+ for (const [server, count] of failures) {
31045
+ console.log(pc2.dim(` ${server}: ${count}`));
31046
+ }
31047
+ }
31048
+ if (disabled.length === 0 && failures.size === 0) {
31049
+ console.log(pc2.green(t("repl.lsp_all_ok")));
31050
+ }
31051
+ break;
31052
+ }
31053
+ case "restart": {
31054
+ console.log(pc2.yellow(t("repl.lsp_restarting")));
31055
+ lspModule.resetDisabledServers();
31056
+ console.log(pc2.green(t("repl.lsp_restarted")));
31057
+ break;
31058
+ }
31059
+ case "check": {
31060
+ const path = args[1];
31061
+ if (!path) {
31062
+ console.log(pc2.yellow(t("repl.lsp_check_usage")));
31063
+ return;
31064
+ }
31065
+ console.log(pc2.dim(t("repl.lsp_checking", { path })));
31066
+ try {
31067
+ const result = await ctx.agent.deps?.toolExecutor?.execute("lsp_check", { path }, ctx.agent.deps?.toolCtx);
31068
+ if (result?.output) {
31069
+ console.log(result.output);
31070
+ }
31071
+ } catch (e) {
31072
+ console.log(pc2.red(t("repl.lsp_check_error", {
31073
+ error: e instanceof Error ? e.message : String(e)
31074
+ })));
31075
+ }
31076
+ break;
31077
+ }
31078
+ default: {
31079
+ console.log(pc2.dim(t("repl.lsp_usage")));
31080
+ break;
31081
+ }
31082
+ }
31083
+ }
31084
+ });
30623
31085
  }
30624
31086
  function registerSessionCommands(ctx) {
30625
31087
  if (!ctx.sessionManager)
@@ -30874,6 +31336,7 @@ var init_repl_commands = __esm(() => {
30874
31336
  reload: "agent",
30875
31337
  wizard: "agent",
30876
31338
  sysprompt: "agent",
31339
+ lsp: "agent",
30877
31340
  sessions: "session",
30878
31341
  new: "session",
30879
31342
  resume: "session",
@@ -30905,15 +31368,15 @@ init_bootstrap();
30905
31368
  init_config2();
30906
31369
  init_setup();
30907
31370
  init_i18n();
30908
- import { join as join44, dirname as dirname16 } from "path";
30909
- import { homedir as homedir15 } from "os";
30910
- import { existsSync as existsSync50, readFileSync as readFileSync32 } from "fs";
31371
+ import { join as join45, dirname as dirname17 } from "path";
31372
+ import { homedir as homedir16 } from "os";
31373
+ import { existsSync as existsSync51, readFileSync as readFileSync33 } from "fs";
30911
31374
 
30912
31375
  // src/cli/security-commands.ts
30913
31376
  init_bootstrap();
30914
31377
  init_config2();
30915
- import { join as join38 } from "path";
30916
- import { homedir as homedir12 } from "os";
31378
+ import { join as join39 } from "path";
31379
+ import { homedir as homedir13 } from "os";
30917
31380
 
30918
31381
  // src/modules/security/security-policies.ts
30919
31382
  init_security();
@@ -31426,7 +31889,7 @@ function createSecurityCommand(program2) {
31426
31889
  }
31427
31890
  });
31428
31891
  securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
31429
- const configPath = join38(homedir12(), ".mma", "config.json");
31892
+ const configPath = join39(homedir13(), ".mma", "config.json");
31430
31893
  const { config: appConfig } = await bootstrap();
31431
31894
  const validPresets = ["strict", "balanced", "permissive"];
31432
31895
  if (!validPresets.includes(preset)) {
@@ -31441,7 +31904,7 @@ function createSecurityCommand(program2) {
31441
31904
  console.log(t("cli.security.policy_description", { description: policy.description }));
31442
31905
  });
31443
31906
  securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
31444
- const configPath = join38(homedir12(), ".mma", "config.json");
31907
+ const configPath = join39(homedir13(), ".mma", "config.json");
31445
31908
  const { config: appConfig } = await bootstrap();
31446
31909
  appConfig.security = appConfig.security || {};
31447
31910
  appConfig.security.sessionEncryption = {
@@ -31453,7 +31916,7 @@ function createSecurityCommand(program2) {
31453
31916
  console.log(t("cli.security.encryption_enabled"));
31454
31917
  });
31455
31918
  securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
31456
- const configPath = join38(homedir12(), ".mma", "config.json");
31919
+ const configPath = join39(homedir13(), ".mma", "config.json");
31457
31920
  const { config: appConfig } = await bootstrap();
31458
31921
  appConfig.security = appConfig.security || {};
31459
31922
  appConfig.security.sessionEncryption = {
@@ -31465,7 +31928,7 @@ function createSecurityCommand(program2) {
31465
31928
  console.log(t("cli.security.encryption_disabled"));
31466
31929
  });
31467
31930
  securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
31468
- const configPath = join38(homedir12(), ".mma", "config.json");
31931
+ const configPath = join39(homedir13(), ".mma", "config.json");
31469
31932
  const { config: appConfig } = await bootstrap();
31470
31933
  appConfig.security = appConfig.security || {};
31471
31934
  appConfig.security.auditNotifier = {
@@ -31479,7 +31942,7 @@ function createSecurityCommand(program2) {
31479
31942
  console.log(t("cli.security.audit_enabled"));
31480
31943
  });
31481
31944
  securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
31482
- const configPath = join38(homedir12(), ".mma", "config.json");
31945
+ const configPath = join39(homedir13(), ".mma", "config.json");
31483
31946
  const { config: appConfig } = await bootstrap();
31484
31947
  appConfig.security = appConfig.security || {};
31485
31948
  appConfig.security.auditNotifier = {
@@ -31543,14 +32006,14 @@ function createPluginCommand(program2) {
31543
32006
 
31544
32007
  // src/cli/commands.ts
31545
32008
  init_setup();
31546
- import { fileURLToPath as fileURLToPath4 } from "url";
32009
+ import { fileURLToPath as fileURLToPath5 } from "url";
31547
32010
  function readVersion2() {
31548
- const here = dirname16(fileURLToPath4(import.meta.url));
31549
- const candidates = [join44(here, "..", "..", "package.json"), join44(here, "..", "package.json")];
32011
+ const here = dirname17(fileURLToPath5(import.meta.url));
32012
+ const candidates = [join45(here, "..", "..", "package.json"), join45(here, "..", "package.json")];
31550
32013
  for (const p of candidates) {
31551
- if (existsSync50(p)) {
32014
+ if (existsSync51(p)) {
31552
32015
  try {
31553
- const raw = JSON.parse(readFileSync32(p, "utf8"));
32016
+ const raw = JSON.parse(readFileSync33(p, "utf8"));
31554
32017
  if (raw.version)
31555
32018
  return raw.version;
31556
32019
  } catch {}
@@ -31563,7 +32026,7 @@ function createProgram() {
31563
32026
  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"));
31564
32027
  program2.command("init").description(t("cli.init")).action(async () => {
31565
32028
  const answers = await runSetup();
31566
- const configPath = join44(homedir15(), ".mma", "config.json");
32029
+ const configPath = join45(homedir16(), ".mma", "config.json");
31567
32030
  const { config } = await bootstrap();
31568
32031
  config.provider.type = answers.provider;
31569
32032
  config.provider.baseUrl = answers.apiBase;
@@ -31608,7 +32071,7 @@ function createProgram() {
31608
32071
  });
31609
32072
  const configCmd = program2.command("config").description(t("cli.manage_config"));
31610
32073
  configCmd.command("set").argument("<key>", t("cli.config_key")).argument("<value>", "Config value").description(t("cli.set_value")).action(async (key, value) => {
31611
- const configPath = join44(homedir15(), ".mma", "config.json");
32074
+ const configPath = join45(homedir16(), ".mma", "config.json");
31612
32075
  const { config } = await bootstrap();
31613
32076
  const keys = key.split(".");
31614
32077
  let obj = config;
@@ -31671,7 +32134,7 @@ function createProgram() {
31671
32134
  console.log(t("cli.model_hint"));
31672
32135
  });
31673
32136
  model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
31674
- const configPath = join44(homedir15(), ".mma", "config.json");
32137
+ const configPath = join45(homedir16(), ".mma", "config.json");
31675
32138
  const { config } = await bootstrap();
31676
32139
  config.model = name;
31677
32140
  saveConfig(config, configPath);
@@ -31707,7 +32170,7 @@ function createProgram() {
31707
32170
  await uncertify2(name, config);
31708
32171
  });
31709
32172
  program2.command("context").description(t("cli.manage_context")).argument("<size>", "Context window size in tokens").action(async (size) => {
31710
- const configPath = join44(homedir15(), ".mma", "config.json");
32173
+ const configPath = join45(homedir16(), ".mma", "config.json");
31711
32174
  const { config } = await bootstrap();
31712
32175
  const contextWindow = parseInt(size, 10);
31713
32176
  if (isNaN(contextWindow) || contextWindow < 1024) {
@@ -31725,7 +32188,7 @@ function createProgram() {
31725
32188
  console.log(t("cli.base_url"), config.provider.baseUrl);
31726
32189
  });
31727
32190
  provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
31728
- const configPath = join44(homedir15(), ".mma", "config.json");
32191
+ const configPath = join45(homedir16(), ".mma", "config.json");
31729
32192
  const { config } = await bootstrap();
31730
32193
  config.provider.type = name;
31731
32194
  const baseUrl = HOSTED_BASE_URLS[name];
@@ -32540,9 +33003,9 @@ class LineEditor {
32540
33003
  }
32541
33004
 
32542
33005
  // src/cli/repl.ts
32543
- import { existsSync as existsSync53, readFileSync as readFileSync35, writeFileSync as writeFileSync17 } from "fs";
32544
- import { join as join47 } from "path";
32545
- import { homedir as homedir17 } from "os";
33006
+ import { existsSync as existsSync54, readFileSync as readFileSync36, writeFileSync as writeFileSync17 } from "fs";
33007
+ import { join as join48 } from "path";
33008
+ import { homedir as homedir18 } from "os";
32546
33009
 
32547
33010
  // src/cli/completer.ts
32548
33011
  class SlashCommandProvider {
@@ -33113,16 +33576,24 @@ async function probeLspServers(config, baseDir, deps = {}) {
33113
33576
  await probeClient.probe(server, projectRoot, serverTimeout);
33114
33577
  ok.push({ language, ok: true, durationMs: Date.now() - started });
33115
33578
  } catch (e) {
33579
+ const errorMsg = e instanceof Error ? e.message : String(e);
33580
+ deps.logger?.warn(`LSP probe failed for ${language}: ${errorMsg}`, {
33581
+ command: server.command,
33582
+ timeout: serverTimeout,
33583
+ durationMs: Date.now() - started
33584
+ });
33116
33585
  failed.push({
33117
33586
  language,
33118
33587
  ok: false,
33119
- error: e instanceof Error ? e.message : String(e),
33588
+ error: errorMsg,
33120
33589
  durationMs: Date.now() - started
33121
33590
  });
33122
33591
  }
33123
33592
  };
33124
33593
  for (let i = 0;i < servers.length; i += maxParallel) {
33125
33594
  if (Date.now() >= deadline) {
33595
+ const remaining = servers.slice(i).map((s) => s.language);
33596
+ deps.logger?.warn(`LSP probe deadline reached, skipping: ${remaining.join(", ")}`);
33126
33597
  for (const { language } of servers.slice(i)) {
33127
33598
  failed.push({ language, ok: false, error: "timeout", durationMs: 0 });
33128
33599
  }
@@ -33141,14 +33612,14 @@ init_config();
33141
33612
  init_colors();
33142
33613
  init_js_identifiers();
33143
33614
  init_i18n();
33144
- import { existsSync as existsSync52, readFileSync as readFileSync34 } from "fs";
33145
- import { join as join46 } from "path";
33615
+ import { existsSync as existsSync53, readFileSync as readFileSync35 } from "fs";
33616
+ import { join as join47 } from "path";
33146
33617
  function readActivePlan(baseDir) {
33147
- const p = join46(baseDir, ".mma", "plans", "active.json");
33148
- if (!existsSync52(p))
33618
+ const p = join47(baseDir, ".mma", "plans", "active.json");
33619
+ if (!existsSync53(p))
33149
33620
  return null;
33150
33621
  try {
33151
- const raw = readFileSync34(p, "utf-8");
33622
+ const raw = readFileSync35(p, "utf-8");
33152
33623
  if (!raw.trim())
33153
33624
  return null;
33154
33625
  const parsed = JSON.parse(raw);
@@ -33291,10 +33762,10 @@ class Repl {
33291
33762
  this.skillsModule = skillsModule;
33292
33763
  this.pluginManager = pluginManager;
33293
33764
  this.logger = logger;
33294
- this.configDir = configDir || join47(homedir17(), ".mma");
33765
+ this.configDir = configDir || join48(homedir18(), ".mma");
33295
33766
  this.baseDir = baseDir || process.cwd();
33296
33767
  this.noAgentsMd = noAgentsMd === true;
33297
- this.historyPath = join47(homedir17(), ".mma", "repl-history");
33768
+ this.historyPath = join48(homedir18(), ".mma", "repl-history");
33298
33769
  this.loadHistory();
33299
33770
  this.rl = process.stdin.isTTY ? new LineEditor({
33300
33771
  input: process.stdin,
@@ -33327,9 +33798,9 @@ class Repl {
33327
33798
  this.setupListeners();
33328
33799
  }
33329
33800
  loadHistory() {
33330
- if (existsSync53(this.historyPath)) {
33801
+ if (existsSync54(this.historyPath)) {
33331
33802
  try {
33332
- const raw = readFileSync35(this.historyPath, "utf-8");
33803
+ const raw = readFileSync36(this.historyPath, "utf-8");
33333
33804
  this.history = raw.split(`
33334
33805
  `).filter(Boolean).slice(-this.maxHistory);
33335
33806
  } catch {
@@ -33421,6 +33892,7 @@ class Repl {
33421
33892
  this.running = false;
33422
33893
  this.saveHistory();
33423
33894
  this.agent.shutdown();
33895
+ this.logger?.closeSessionLog();
33424
33896
  if (this.exitOnClose)
33425
33897
  process.exit(0);
33426
33898
  });
@@ -33429,6 +33901,7 @@ class Repl {
33429
33901
  this.running = false;
33430
33902
  this.saveHistory();
33431
33903
  this.agent.shutdown();
33904
+ this.logger?.closeSessionLog();
33432
33905
  process.exit(0);
33433
33906
  });
33434
33907
  }
@@ -33705,11 +34178,11 @@ ${t("image.clipboard_empty")}`));
33705
34178
  row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
33706
34179
  } else {
33707
34180
  const agentsMdCandidates = [
33708
- join47(this.baseDir, "AGENTS.md"),
33709
- join47(this.baseDir, ".mma", "AGENTS.md"),
33710
- join47(this.configDir, "AGENTS.md")
34181
+ join48(this.baseDir, "AGENTS.md"),
34182
+ join48(this.baseDir, ".mma", "AGENTS.md"),
34183
+ join48(this.configDir, "AGENTS.md")
33711
34184
  ];
33712
- const foundAgents = agentsMdCandidates.filter((p) => existsSync53(p));
34185
+ const foundAgents = agentsMdCandidates.filter((p) => existsSync54(p));
33713
34186
  if (foundAgents.length > 0) {
33714
34187
  for (const p of foundAgents) {
33715
34188
  row(t("repl.agents_label"), pc2.dim(p));
@@ -33720,7 +34193,7 @@ ${t("image.clipboard_empty")}`));
33720
34193
  }
33721
34194
  const meta = this.sessionManager?.getActiveMeta();
33722
34195
  if (meta) {
33723
- const sessionPath = join47(this.configDir, "sessions", meta.id);
34196
+ const sessionPath = join48(this.configDir, "sessions", meta.id);
33724
34197
  row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
33725
34198
  }
33726
34199
  const headerWidth = Math.max(50, Math.min(96, process.stdout.columns || 96));
@@ -33775,6 +34248,7 @@ ${t("image.clipboard_empty")}`));
33775
34248
  this.running = false;
33776
34249
  this.saveHistory();
33777
34250
  this.agent.shutdown();
34251
+ this.logger?.closeSessionLog();
33778
34252
  this.rl.close();
33779
34253
  }
33780
34254
  }
@@ -33805,10 +34279,10 @@ init_setup();
33805
34279
  init_config2();
33806
34280
  init_i18n();
33807
34281
  init_colors();
33808
- import { existsSync as existsSync54, readFileSync as readFileSync36 } from "fs";
33809
- import { join as join48, dirname as dirname18 } from "path";
33810
- import { homedir as homedir18 } from "os";
33811
- import { fileURLToPath as fileURLToPath6 } from "url";
34282
+ import { existsSync as existsSync55, readFileSync as readFileSync37 } from "fs";
34283
+ import { join as join50, dirname as dirname19 } from "path";
34284
+ import { homedir as homedir20 } from "os";
34285
+ import { fileURLToPath as fileURLToPath7 } from "url";
33812
34286
 
33813
34287
  // src/modules/updater/index.ts
33814
34288
  init_checker();
@@ -33907,14 +34381,61 @@ class UpdaterModule {
33907
34381
  await this.runOnce();
33908
34382
  }
33909
34383
  }
34384
+ // src/core/crash-handler.ts
34385
+ init_environment();
34386
+ init_data_sanitizer();
34387
+ init_i18n();
34388
+ import { appendFileSync as appendFileSync7, mkdirSync as mkdirSync20 } from "fs";
34389
+ import { join as join49 } from "path";
34390
+ import { homedir as homedir19 } from "os";
34391
+ var CRASH_LOG_DIR = join49(homedir19(), ".mma", "logs");
34392
+ var CRASH_LOG_FILE = "crash.jsonl";
34393
+ function formatCrashEntry(type2, err) {
34394
+ const message = err instanceof Error ? err.message : String(err);
34395
+ const stack = err instanceof Error && err.stack ? err.stack : message;
34396
+ return {
34397
+ ts: new Date().toISOString(),
34398
+ type: type2,
34399
+ message: sanitizeLogMessage(message),
34400
+ stack: sanitizeLogMessage(stack),
34401
+ environment: collectEnvironment({ configDir: homedir19(), scanTools: false })
34402
+ };
34403
+ }
34404
+ function writeCrashEntry(dir, entry) {
34405
+ try {
34406
+ mkdirSync20(dir, { recursive: true });
34407
+ appendFileSync7(join49(dir, CRASH_LOG_FILE), JSON.stringify(entry) + `
34408
+ `, "utf-8");
34409
+ } catch {}
34410
+ }
34411
+ var installed = false;
34412
+ function installCrashHandlers() {
34413
+ if (installed)
34414
+ return;
34415
+ installed = true;
34416
+ process.on("uncaughtException", (err) => {
34417
+ const entry = formatCrashEntry("uncaughtException", err);
34418
+ writeCrashEntry(CRASH_LOG_DIR, entry);
34419
+ process.stderr.write(`${t("env.crash_stderr", { type: entry.type, message: entry.message })}
34420
+ `);
34421
+ process.exit(1);
34422
+ });
34423
+ process.on("unhandledRejection", (reason) => {
34424
+ const entry = formatCrashEntry("unhandledRejection", reason);
34425
+ writeCrashEntry(CRASH_LOG_DIR, entry);
34426
+ process.stderr.write(`${t("env.crash_stderr", { type: entry.type, message: entry.message })}
34427
+ `);
34428
+ });
34429
+ }
34430
+
33910
34431
  // src/cli/main.ts
33911
34432
  function readVersion4() {
33912
- const here = dirname18(fileURLToPath6(import.meta.url));
33913
- const candidates = [join48(here, "..", "..", "package.json"), join48(here, "..", "package.json")];
34433
+ const here = dirname19(fileURLToPath7(import.meta.url));
34434
+ const candidates = [join50(here, "..", "..", "package.json"), join50(here, "..", "package.json")];
33914
34435
  for (const p of candidates) {
33915
- if (existsSync54(p)) {
34436
+ if (existsSync55(p)) {
33916
34437
  try {
33917
- const raw = JSON.parse(readFileSync36(p, "utf8"));
34438
+ const raw = JSON.parse(readFileSync37(p, "utf8"));
33918
34439
  if (raw.version)
33919
34440
  return raw.version;
33920
34441
  } catch {}
@@ -33939,6 +34460,7 @@ function startAutoUpdate(config) {
33939
34460
  }
33940
34461
  }
33941
34462
  async function main() {
34463
+ installCrashHandlers();
33942
34464
  const program2 = createProgram();
33943
34465
  program2.parse(process.argv);
33944
34466
  const cmdNames = new Set(program2.commands.map((c) => c.name()));
@@ -33998,15 +34520,15 @@ async function main() {
33998
34520
  await updater?.waitForIdle();
33999
34521
  process.exit(exitCode);
34000
34522
  } else {
34001
- const configPath = join48(homedir18(), ".mma", "config.json");
34002
- if (!existsSync54(configPath)) {
34523
+ const configPath = join50(homedir20(), ".mma", "config.json");
34524
+ if (!existsSync55(configPath)) {
34003
34525
  console.log(pc2.yellow(`
34004
34526
  ` + t("cli.first_run") + `
34005
34527
  `));
34006
34528
  const answers = await runSetup();
34007
34529
  const config2 = loadConfig({
34008
- configDir: join48(homedir18(), ".mma"),
34009
- projectConfigPath: projectDir ? join48(projectDir, ".mmrc") : join48(process.cwd(), ".mmrc")
34530
+ configDir: join50(homedir20(), ".mma"),
34531
+ projectConfigPath: projectDir ? join50(projectDir, ".mmrc") : join50(process.cwd(), ".mmrc")
34010
34532
  });
34011
34533
  config2.provider.type = answers.provider;
34012
34534
  config2.provider.baseUrl = answers.apiBase;