micro-models-agent 0.63.3 → 1.1.0

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 (185) hide show
  1. package/CHANGELOG.md +148 -1
  2. package/dist/cli/cache-line.js +30 -0
  3. package/dist/cli/command-suggest.js +38 -0
  4. package/dist/cli/commands.js +285 -60
  5. package/dist/cli/completer.js +16 -16
  6. package/dist/cli/json-payload.js +32 -0
  7. package/dist/cli/main.js +165 -77
  8. package/dist/cli/plugin-commands.js +5 -4
  9. package/dist/cli/relaunch.js +37 -0
  10. package/dist/cli/repl-commands.js +441 -307
  11. package/dist/cli/repl.js +360 -83
  12. package/dist/cli/run-result.js +12 -6
  13. package/dist/cli/security-commands.js +64 -60
  14. package/dist/cli/setup-order.js +57 -0
  15. package/dist/cli/setup-prompt.js +49 -0
  16. package/dist/cli/setup.js +52 -48
  17. package/dist/config/budget.js +48 -0
  18. package/dist/config/config.js +132 -70
  19. package/dist/config/defaults.js +37 -11
  20. package/dist/config/domains.js +9 -50
  21. package/dist/config/utils.js +56 -0
  22. package/dist/core/agent/audit-gate.js +49 -0
  23. package/dist/core/agent/compaction.js +89 -0
  24. package/dist/core/agent/constants.js +61 -0
  25. package/dist/core/agent/context-renderer.js +40 -0
  26. package/dist/core/agent/hallucination-gate.js +87 -0
  27. package/dist/core/agent/loop-state.js +53 -0
  28. package/dist/core/agent/prefix-monitor.js +101 -0
  29. package/dist/core/agent/reasoning-resolver.js +56 -0
  30. package/dist/core/agent/token-tracker.js +96 -0
  31. package/dist/core/agent/tool-batch.js +237 -0
  32. package/dist/core/agent/tool-output.js +62 -0
  33. package/dist/core/agent-moe.js +214 -69
  34. package/dist/core/agent.js +506 -546
  35. package/dist/core/bootstrap.js +297 -98
  36. package/dist/core/crash-handler.js +2 -1
  37. package/dist/core/prompt-builder.js +3 -0
  38. package/dist/core/prompt-overflow.js +307 -0
  39. package/dist/core/session-logger.js +34 -2
  40. package/dist/i18n/en.json +7 -4
  41. package/dist/i18n/ru.json +7 -4
  42. package/dist/index.js +5 -1
  43. package/dist/llm/cache-usage.js +76 -0
  44. package/dist/llm/image-utils.js +20 -16
  45. package/dist/llm/llm-errors.js +41 -0
  46. package/dist/llm/model-loader.js +30 -0
  47. package/dist/llm/openai-compat.js +287 -101
  48. package/dist/llm/orchestrator.js +140 -68
  49. package/dist/llm/provider-budget.js +68 -0
  50. package/dist/llm/provider.js +0 -1
  51. package/dist/llm/stream-state.js +26 -0
  52. package/dist/llm/token-counter.js +28 -0
  53. package/dist/logger/app-logger.js +12 -15
  54. package/dist/main.js +1606 -800
  55. package/dist/migration/detect.js +3 -1
  56. package/dist/modules/browser/actions.js +0 -3
  57. package/dist/modules/browser/bridge-client.js +2 -0
  58. package/dist/modules/browser/driver.js +46 -4
  59. package/dist/modules/certification/cli.js +85 -42
  60. package/dist/modules/certification/loader.js +15 -1
  61. package/dist/modules/certification/manifest.js +126 -15
  62. package/dist/modules/certification/runner.js +4 -26
  63. package/dist/modules/certification/scenarios.js +184 -5
  64. package/dist/modules/certification/syntax-scenarios.js +51 -0
  65. package/dist/modules/context/chunk-query.js +25 -5
  66. package/dist/modules/context/fact-extractor.js +6 -2
  67. package/dist/modules/context/manager.js +23 -7
  68. package/dist/modules/execution/audit-runners.js +7 -1
  69. package/dist/modules/execution/auditor.js +3 -3
  70. package/dist/modules/execution/execution-plugin.js +22 -15
  71. package/dist/modules/execution/input-from.js +46 -0
  72. package/dist/modules/execution/module.js +107 -18
  73. package/dist/modules/execution/moe-executor.js +166 -54
  74. package/dist/modules/execution/plan-actions.js +524 -0
  75. package/dist/modules/execution/plan-steps.js +23 -0
  76. package/dist/modules/execution/plan-store.js +15 -3
  77. package/dist/modules/execution/plan-tool.js +6 -488
  78. package/dist/modules/execution/plan-validator.js +24 -0
  79. package/dist/modules/execution/stuck-detector.js +3 -18
  80. package/dist/modules/execution/tracker.js +14 -5
  81. package/dist/modules/execution/transient-error.js +30 -0
  82. package/dist/modules/execution/verifier.js +94 -7
  83. package/dist/modules/execution/windows-commands.js +11 -0
  84. package/dist/modules/hallucination/confidence.js +36 -23
  85. package/dist/modules/hallucination/consistency.js +3 -0
  86. package/dist/modules/hallucination/detector.js +8 -3
  87. package/dist/modules/hallucination/factual.js +26 -7
  88. package/dist/modules/hallucination/llm-judge.js +12 -2
  89. package/dist/modules/indexer/map-command.js +35 -0
  90. package/dist/modules/indexer/map-select.js +87 -0
  91. package/dist/modules/indexer/module.js +34 -22
  92. package/dist/modules/indexer/symbols.js +189 -0
  93. package/dist/modules/indexer/walker.js +96 -42
  94. package/dist/modules/lsp/check-tool.js +2 -1
  95. package/dist/modules/lsp/client.js +49 -32
  96. package/dist/modules/lsp/config.js +55 -2
  97. package/dist/modules/lsp/module.js +38 -5
  98. package/dist/modules/lsp/probe.js +4 -3
  99. package/dist/modules/lsp/project-root.js +41 -1
  100. package/dist/modules/lsp/startup-check.js +12 -4
  101. package/dist/modules/mcp/client.js +153 -104
  102. package/dist/modules/mcp/module.js +165 -41
  103. package/dist/modules/memory/module.js +4 -3
  104. package/dist/modules/plugins/builtin/lint-on-write.js +36 -6
  105. package/dist/modules/plugins/manager.js +47 -84
  106. package/dist/modules/pricing/index.js +17 -7
  107. package/dist/modules/pricing/prices.js +30 -12
  108. package/dist/modules/processes/index.js +1 -0
  109. package/dist/modules/processes/kill-tree.js +56 -0
  110. package/dist/modules/processes/registry.js +2 -54
  111. package/dist/modules/providers/cache.js +23 -0
  112. package/dist/modules/providers/factory.js +28 -0
  113. package/dist/modules/providers/fallback.js +7 -5
  114. package/dist/modules/providers/health.js +2 -1
  115. package/dist/modules/providers/index.js +1 -0
  116. package/dist/modules/providers/manager.js +17 -2
  117. package/dist/modules/providers/presets.js +79 -6
  118. package/dist/modules/reasoning/policy.js +40 -0
  119. package/dist/modules/reasoning/probe.js +111 -0
  120. package/dist/modules/security/audit-notifier.js +42 -27
  121. package/dist/modules/security/command-validator.js +25 -20
  122. package/dist/modules/security/encryption.js +6 -12
  123. package/dist/modules/security/network-validator.js +76 -5
  124. package/dist/modules/security/path-validator.js +77 -34
  125. package/dist/modules/security/rate-limiter.js +11 -0
  126. package/dist/modules/security/security-policies.js +1 -1
  127. package/dist/modules/security/session-encryption.js +13 -2
  128. package/dist/modules/security/session-isolation.js +2 -9
  129. package/dist/modules/session/manager.js +11 -0
  130. package/dist/modules/session/module.js +11 -3
  131. package/dist/modules/session/store.js +41 -5
  132. package/dist/modules/skills/loader.js +7 -1
  133. package/dist/modules/skills/module.js +2 -1
  134. package/dist/modules/updater/changelog-reader.js +94 -0
  135. package/dist/modules/updater/dev-detect.js +17 -0
  136. package/dist/modules/updater/index.js +1 -0
  137. package/dist/modules/updater/module.js +14 -3
  138. package/dist/output/bus.js +32 -0
  139. package/dist/output/channel.js +233 -0
  140. package/dist/output/format.js +14 -0
  141. package/dist/output/index.js +7 -0
  142. package/dist/output/json-sink.js +22 -0
  143. package/dist/output/machine.js +8 -0
  144. package/dist/output/session-sink.js +27 -0
  145. package/dist/output/types.js +1 -0
  146. package/dist/tools/approve.js +6 -2
  147. package/dist/tools/attach-image.js +11 -11
  148. package/dist/tools/auto-fixer.js +198 -0
  149. package/dist/tools/bash.js +142 -89
  150. package/dist/tools/chunk-query.js +10 -6
  151. package/dist/tools/download-file.js +1 -1
  152. package/dist/tools/edit-file.js +20 -2
  153. package/dist/tools/executor.js +54 -9
  154. package/dist/tools/glob-tool.js +7 -0
  155. package/dist/tools/grep-tool.js +15 -1
  156. package/dist/tools/index.js +3 -1
  157. package/dist/tools/list-dir.js +3 -1
  158. package/dist/tools/load-skill.js +2 -1
  159. package/dist/tools/mcp-call.js +1 -1
  160. package/dist/tools/move-file.js +5 -4
  161. package/dist/tools/path-utils.js +7 -0
  162. package/dist/tools/pipeline-run.js +1 -1
  163. package/dist/tools/prompt-io.js +28 -0
  164. package/dist/tools/question.js +12 -12
  165. package/dist/tools/scope-request.js +91 -0
  166. package/dist/tools/session-info.js +44 -0
  167. package/dist/tools/set-thinking.js +71 -0
  168. package/dist/tools/subagent.js +50 -9
  169. package/dist/tools/syntax-validator.js +177 -0
  170. package/dist/tools/user-input.js +16 -9
  171. package/dist/tools/write-file.js +17 -1
  172. package/dist/ui/diff.js +10 -0
  173. package/dist/ui/line-editor.js +179 -26
  174. package/dist/ui/line-math.js +20 -3
  175. package/dist/ui/md-formatter.js +100 -10
  176. package/dist/ui/output.js +5 -4
  177. package/dist/ui/plan-view.js +2 -7
  178. package/dist/ui/renderer.js +89 -85
  179. package/dist/ui/spinner.js +14 -4
  180. package/dist/utils/error.js +4 -0
  181. package/dist/utils/index.js +4 -0
  182. package/dist/utils/retry.js +17 -0
  183. package/dist/utils/sleep.js +23 -0
  184. package/dist/utils/truncate.js +9 -0
  185. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -2790,6 +2790,7 @@ Fix the error and re-edit the file (a clean write clears the failure), or mark t
2790
2790
  "cli.show_details": "Show session details",
2791
2791
  "cli.delete_session": "Delete a session",
2792
2792
  "cli.first_run": "First run detected. Running setup wizard...",
2793
+ "cli.setup_saved_restart": "Settings saved. Restarting with the new configuration...",
2793
2794
  "cli.unknown_cmd": "Unknown command: {name}.",
2794
2795
  "cli.unknown_command": 'Unknown command "{input}". Did you mean "{suggestion}"?',
2795
2796
  "cli.help_hint": "Type /help for available commands.",
@@ -2892,6 +2893,8 @@ Available commands:`,
2892
2893
  "repl.skill_usage": "Usage: /skill [list|loaded|load|unload|search]",
2893
2894
  "repl.agent": "Agent: ",
2894
2895
  "repl.you": "You: ",
2896
+ "repl.you_reasoning": "You [{level}]: ",
2897
+ "repl.you_reasoning_cont": "You [{level}]… ",
2895
2898
  "repl.interrupt": "Interrupted (Esc)",
2896
2899
  "repl.title": "MMA REPL v{version}",
2897
2900
  "repl.model": "Model:",
@@ -2965,6 +2968,8 @@ Excluded blocks: {count}`,
2965
2968
  Select provider type:`,
2966
2969
  "setup.select_provider_num": `
2967
2970
  Select provider (1-{max})`,
2971
+ "setup.select_language_num": `
2972
+ Select language (1-{max})`,
2968
2973
  "setup.scanning": " Scanning local LLM servers...",
2969
2974
  "setup.found_servers": " Found {count} server(s):",
2970
2975
  "setup.no_servers": " No local servers found. Enter URL manually.",
@@ -2995,8 +3000,6 @@ Excluded blocks: {count}`,
2995
3000
  "setup.scanning_spinner": "Scanning local LLM servers…",
2996
3001
  "setup.fetching_spinner": "Fetching model list…",
2997
3002
  "setup.testing_spinner": 'Testing chat with "{model}"…',
2998
- "setup.summary_setting": "Setting",
2999
- "setup.summary_value": "Value",
3000
3003
  "setup.security_header": `
3001
3004
  --- Security ---`,
3002
3005
  "setup.security_status_off": " Security: OFF (default — all commands allowed)",
@@ -3057,6 +3060,7 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
3057
3060
  "exec.error_search_failed": 'Web search returned nothing for "{query}".',
3058
3061
  "exec.error_search_no_query": "Error output is not meaningful — skipping the web search.",
3059
3062
  "exec.npm_exec_hint": '"could not determine executable to run" — no "bin" for that package/script. Use "npm run <script>" (script must exist in package.json) or "bunx <pkg>" for a package that declares a bin.',
3063
+ "exec.interactive_hint": "the command needed interactive input but the shell has no TTY (prompt aborted). Re-run it non-interactively — pass every required flag/argument (e.g. `bun create vite <name> --template react-ts` instead of a bare interactive scaffold).",
3060
3064
  "exec.hidden_tool_hint": '"{tool}" is not a shell command — it is an MMA tool that is currently hidden. Call the enable_tools tool with tags ["shell"] to unlock it; it becomes available on the next iteration.',
3061
3065
  "exec.task_reminder": "Task: {task}. Continue making progress — do not repeat failed actions.",
3062
3066
  "hall.max_retries_exhausted": "Model returned empty or insufficient responses after multiple retries",
@@ -3240,9 +3244,9 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
3240
3244
  "prompt.overflow.hint_needed": "the prompt needs ~{needed} system tokens (current budget: {window} × {fraction} = {budget})",
3241
3245
  "prompt.overflow.hint_window": "raise contextWindow to at least {required} (standard size {recommended}) — {how}",
3242
3246
  "prompt.overflow.hint_fraction": "or keep the window and raise contextBudget.systemPrompt to ~{fraction} (run: mma context --system {fraction})",
3243
- "prompt.overflow.exceeded": 'Prompt overflow: "{label}" ({original} tok) exceeded the system-prompt budget ({budget} tok) {mode} to {resolved} tok. To fit fully, {hint}.',
3247
+ "prompt.overflow.exceeded": 'Prompt overflow: the system prompt needs ~{needed} tok (budget {budget} tok); "{label}" ({original} tok) was {mode} to {resolved} tok. To fit everything fully, {hint}.',
3244
3248
  "prompt.overflow.failed": "Prompt overflow resolution failed: {error} — oversized blocks will be dropped.",
3245
- "prompt.overflow.startup": "Startup check: {block} ({original} tok) exceeds the system-prompt budget ({budget} tok) — it will be summarized/truncated before the first run. To include it fully, {hint}.",
3249
+ "prompt.overflow.startup": "Startup check: the system prompt needs ~{needed} tok (budget: {budget} tok); {block} ({original} tok) will be summarized/truncated before the first run. To include everything fully, {hint}.",
3246
3250
  "tool.session_info.no_active": "No active session",
3247
3251
  "tool.session_info.result": `Session: "{name}" ({id})
3248
3252
  Model: {model}
@@ -3622,6 +3626,7 @@ var init_ru = __esm(() => {
3622
3626
  "cli.show_details": "Показать детали сессии",
3623
3627
  "cli.delete_session": "Удалить сессию",
3624
3628
  "cli.first_run": "Первый запуск. Запускаем мастер настройки...",
3629
+ "cli.setup_saved_restart": "Настройки сохранены. Перезапуск с новой конфигурацией...",
3625
3630
  "cli.unknown_cmd": "Неизвестная команда: {name}.",
3626
3631
  "cli.unknown_command": 'Неизвестная команда "{input}". Возможно, вы имели в виду "{suggestion}"?',
3627
3632
  "cli.help_hint": "Введите /help для списка команд.",
@@ -3724,6 +3729,8 @@ var init_ru = __esm(() => {
3724
3729
  "repl.skill_usage": "Использование: /skill [list|loaded|load|unload|search]",
3725
3730
  "repl.agent": "Агент: ",
3726
3731
  "repl.you": "Вы: ",
3732
+ "repl.you_reasoning": "Вы [{level}]: ",
3733
+ "repl.you_reasoning_cont": "Вы [{level}]… ",
3727
3734
  "repl.interrupt": "Прервано (Esc)",
3728
3735
  "repl.title": "MMA REPL v{version}",
3729
3736
  "repl.model": "Модель:",
@@ -3801,6 +3808,8 @@ var init_ru = __esm(() => {
3801
3808
  Выберите тип провайдера:`,
3802
3809
  "setup.select_provider_num": `
3803
3810
  Выберите провайдер (1-{max})`,
3811
+ "setup.select_language_num": `
3812
+ Выберите язык (1-{max})`,
3804
3813
  "setup.scanning": " Сканирование локальных LLM-серверов...",
3805
3814
  "setup.found_servers": " Найдено серверов: {count}",
3806
3815
  "setup.no_servers": " Локальные серверы не найдены. Введите URL вручную.",
@@ -3831,8 +3840,6 @@ var init_ru = __esm(() => {
3831
3840
  "setup.scanning_spinner": "Сканирование локальных LLM-серверов…",
3832
3841
  "setup.fetching_spinner": "Загрузка списка моделей…",
3833
3842
  "setup.testing_spinner": 'Проверка чата с "{model}"…',
3834
- "setup.summary_setting": "Параметр",
3835
- "setup.summary_value": "Значение",
3836
3843
  "setup.security_header": `
3837
3844
  --- Безопасность ---`,
3838
3845
  "setup.security_status_off": " Безопасность: ВЫКЛ (по умолчанию — все команды разрешены)",
@@ -3893,6 +3900,7 @@ var init_ru = __esm(() => {
3893
3900
  "exec.error_search_failed": 'Поиск в интернете для "{query}" ничего не дал.',
3894
3901
  "exec.error_search_no_query": "Текст ошибки незначимый — поиск в интернете пропущен.",
3895
3902
  "exec.npm_exec_hint": '"could not determine executable to run" — у пакета/скрипта нет "bin". Используй "npm run <script>" (скрипт должен быть в package.json) или "bunx <pkg>" для пакета с объявленным bin.',
3903
+ "exec.interactive_hint": "команде нужен интерактивный ввод, но у шелла нет TTY (запрос отменён). Запусти её неинтерактивно — передай все нужные флаги/аргументы (например, `bun create vite <name> --template react-ts` вместо голого интерактивного скаффолда).",
3896
3904
  "exec.hidden_tool_hint": '"{tool}" — не команда оболочки, это инструмент MMA, который сейчас скрыт. Вызови тул enable_tools с tags ["shell"], чтобы включить его; он станет доступен на следующей итерации.',
3897
3905
  "exec.task_reminder": "Задача: {task}. Продолжай работу — не повторяй неудачные действия.",
3898
3906
  "hall.max_retries_exhausted": "Модель вернула пустой или недостаточный ответ после нескольких попыток",
@@ -4079,9 +4087,9 @@ var init_ru = __esm(() => {
4079
4087
  "prompt.overflow.hint_needed": "промпту нужно ~{needed} токенов системного бюджета (сейчас: {window} × {fraction} = {budget})",
4080
4088
  "prompt.overflow.hint_window": "подними contextWindow минимум до {required} (стандартный размер {recommended}) — {how}",
4081
4089
  "prompt.overflow.hint_fraction": "или оставь окно и подними contextBudget.systemPrompt до ~{fraction} (выполни: mma context --system {fraction})",
4082
- "prompt.overflow.exceeded": 'Промпт переполнен: "{label}" ({original} токенов) превысил бюджет системного промпта ({budget} токенов) {mode} до {resolved} токенов. Чтобы включить полностью, {hint}.',
4090
+ "prompt.overflow.exceeded": 'Промпт переполнен: системному промпту нужно ~{needed} токенов (бюджет {budget} токенов); "{label}" ({original} токенов) было {mode} до {resolved} токенов. Чтобы включить всё полностью, {hint}.',
4083
4091
  "prompt.overflow.failed": "Не удалось разрешить переполнение промпта: {error} — слишком большие блоки будут отброшены.",
4084
- "prompt.overflow.startup": "Проверка при старте: {block} ({original} токенов) превышает бюджет системного промпта ({budget} токенов) будет суммаризован/обрезан перед первым запуском. Чтобы включить полностью, {hint}.",
4092
+ "prompt.overflow.startup": "Проверка при старте: системному промпту нужно ~{needed} токенов (бюджет: {budget} токенов); {block} ({original} токенов) будет суммаризован/обрезан перед первым запуском. Чтобы включить всё полностью, {hint}.",
4085
4093
  "tool.session_info.no_active": "Нет активной сессии",
4086
4094
  "tool.session_info.result": `Сессия: "{name}" ({id})
4087
4095
  Модель: {model}
@@ -4513,6 +4521,398 @@ var init_encryption = __esm(() => {
4513
4521
  "key"
4514
4522
  ];
4515
4523
  });
4524
+ // src/output/bus.ts
4525
+ class OutputBus {
4526
+ seq = 0;
4527
+ subs = new Set;
4528
+ subscribe(fn) {
4529
+ this.subs.add(fn);
4530
+ return () => this.subs.delete(fn);
4531
+ }
4532
+ emit(ev) {
4533
+ const full = { ...ev, id: ++this.seq, ts: Date.now() };
4534
+ for (const fn of [...this.subs]) {
4535
+ try {
4536
+ fn(full);
4537
+ } catch {}
4538
+ }
4539
+ return full;
4540
+ }
4541
+ log(level, source, text, data) {
4542
+ return this.emit({ level, source, kind: "log", text, data });
4543
+ }
4544
+ reset() {
4545
+ this.subs.clear();
4546
+ this.seq = 0;
4547
+ }
4548
+ }
4549
+ var defaultOutputBus;
4550
+ var init_bus = __esm(() => {
4551
+ defaultOutputBus = new OutputBus;
4552
+ });
4553
+
4554
+ // node_modules/picocolors/picocolors.js
4555
+ var require_picocolors = __commonJS((exports, module) => {
4556
+ var p = process || {};
4557
+ var argv = p.argv || [];
4558
+ var env = p.env || {};
4559
+ var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
4560
+ var formatter = (open, close, replace = open) => (input) => {
4561
+ let string = "" + input, index = string.indexOf(close, open.length);
4562
+ return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
4563
+ };
4564
+ var replaceClose = (string, close, replace, index) => {
4565
+ let result = "", cursor = 0;
4566
+ do {
4567
+ result += string.substring(cursor, index) + replace;
4568
+ cursor = index + close.length;
4569
+ index = string.indexOf(close, cursor);
4570
+ } while (~index);
4571
+ return result + string.substring(cursor);
4572
+ };
4573
+ var createColors = (enabled = isColorSupported) => {
4574
+ let f = enabled ? formatter : () => String;
4575
+ return {
4576
+ isColorSupported: enabled,
4577
+ reset: f("\x1B[0m", "\x1B[0m"),
4578
+ bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
4579
+ dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
4580
+ italic: f("\x1B[3m", "\x1B[23m"),
4581
+ underline: f("\x1B[4m", "\x1B[24m"),
4582
+ inverse: f("\x1B[7m", "\x1B[27m"),
4583
+ hidden: f("\x1B[8m", "\x1B[28m"),
4584
+ strikethrough: f("\x1B[9m", "\x1B[29m"),
4585
+ black: f("\x1B[30m", "\x1B[39m"),
4586
+ red: f("\x1B[31m", "\x1B[39m"),
4587
+ green: f("\x1B[32m", "\x1B[39m"),
4588
+ yellow: f("\x1B[33m", "\x1B[39m"),
4589
+ blue: f("\x1B[34m", "\x1B[39m"),
4590
+ magenta: f("\x1B[35m", "\x1B[39m"),
4591
+ cyan: f("\x1B[36m", "\x1B[39m"),
4592
+ white: f("\x1B[37m", "\x1B[39m"),
4593
+ gray: f("\x1B[90m", "\x1B[39m"),
4594
+ bgBlack: f("\x1B[40m", "\x1B[49m"),
4595
+ bgRed: f("\x1B[41m", "\x1B[49m"),
4596
+ bgGreen: f("\x1B[42m", "\x1B[49m"),
4597
+ bgYellow: f("\x1B[43m", "\x1B[49m"),
4598
+ bgBlue: f("\x1B[44m", "\x1B[49m"),
4599
+ bgMagenta: f("\x1B[45m", "\x1B[49m"),
4600
+ bgCyan: f("\x1B[46m", "\x1B[49m"),
4601
+ bgWhite: f("\x1B[47m", "\x1B[49m"),
4602
+ blackBright: f("\x1B[90m", "\x1B[39m"),
4603
+ redBright: f("\x1B[91m", "\x1B[39m"),
4604
+ greenBright: f("\x1B[92m", "\x1B[39m"),
4605
+ yellowBright: f("\x1B[93m", "\x1B[39m"),
4606
+ blueBright: f("\x1B[94m", "\x1B[39m"),
4607
+ magentaBright: f("\x1B[95m", "\x1B[39m"),
4608
+ cyanBright: f("\x1B[96m", "\x1B[39m"),
4609
+ whiteBright: f("\x1B[97m", "\x1B[39m"),
4610
+ bgBlackBright: f("\x1B[100m", "\x1B[49m"),
4611
+ bgRedBright: f("\x1B[101m", "\x1B[49m"),
4612
+ bgGreenBright: f("\x1B[102m", "\x1B[49m"),
4613
+ bgYellowBright: f("\x1B[103m", "\x1B[49m"),
4614
+ bgBlueBright: f("\x1B[104m", "\x1B[49m"),
4615
+ bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
4616
+ bgCyanBright: f("\x1B[106m", "\x1B[49m"),
4617
+ bgWhiteBright: f("\x1B[107m", "\x1B[49m")
4618
+ };
4619
+ };
4620
+ module.exports = createColors();
4621
+ module.exports.createColors = createColors;
4622
+ });
4623
+
4624
+ // src/output/format.ts
4625
+ function formatEventLine(ev, color) {
4626
+ const prefix = ev.source ? ` [${ev.source}]` : "";
4627
+ const line = `[${ev.level.toUpperCase()}]${prefix} ${new Date(ev.ts).toISOString()} — ${ev.text}`;
4628
+ return color ? LEVEL_COLORS[ev.level](line) : line;
4629
+ }
4630
+ var import_picocolors, colored, LEVEL_COLORS;
4631
+ var init_format = __esm(() => {
4632
+ import_picocolors = __toESM(require_picocolors(), 1);
4633
+ colored = import_picocolors.createColors(true);
4634
+ LEVEL_COLORS = {
4635
+ debug: (s) => colored.dim(s),
4636
+ info: (s) => s,
4637
+ warn: (s) => colored.yellow(s),
4638
+ error: (s) => colored.red(s)
4639
+ };
4640
+ });
4641
+
4642
+ // src/output/json-sink.ts
4643
+ class JsonOutputSink {
4644
+ events = [];
4645
+ unsub;
4646
+ constructor(bus) {
4647
+ this.unsub = bus.subscribe((ev) => {
4648
+ this.events.push(ev);
4649
+ });
4650
+ }
4651
+ diagnostics() {
4652
+ return this.events.filter((e) => e.level === "warn" || e.level === "error").map((e) => ({ level: e.level, source: e.source, text: e.text }));
4653
+ }
4654
+ dispose() {
4655
+ this.unsub();
4656
+ }
4657
+ }
4658
+
4659
+ // src/output/session-sink.ts
4660
+ class SessionOutputSink {
4661
+ session;
4662
+ unsub;
4663
+ constructor(bus, session) {
4664
+ this.session = session;
4665
+ this.unsub = bus.subscribe((ev) => {
4666
+ if (ev.data?.persist !== true)
4667
+ return;
4668
+ this.session.appendLog({
4669
+ ts: new Date(ev.ts).toISOString(),
4670
+ type: "output",
4671
+ level: ev.level,
4672
+ source: ev.source,
4673
+ content: ev.text
4674
+ });
4675
+ });
4676
+ }
4677
+ dispose() {
4678
+ this.unsub();
4679
+ }
4680
+ }
4681
+
4682
+ // src/output/channel.ts
4683
+ class OutputChannel {
4684
+ bus;
4685
+ out;
4686
+ err;
4687
+ color;
4688
+ mode = "idle";
4689
+ modeBeforeQuiet = "idle";
4690
+ modeBeforeModal = "idle";
4691
+ modalDepth = 0;
4692
+ sink = null;
4693
+ queue = [];
4694
+ pending = null;
4695
+ partialOpen = false;
4696
+ blockLines = null;
4697
+ blockFlushScheduled = false;
4698
+ unsub;
4699
+ constructor(bus = defaultOutputBus, opts = {}) {
4700
+ this.bus = bus;
4701
+ this.out = opts.out ?? process.stdout;
4702
+ this.err = opts.err ?? process.stderr;
4703
+ const outTTY = this.out.isTTY === true;
4704
+ this.color = opts.color ?? (!process.env.NO_COLOR && !process.env.CI && outTTY);
4705
+ this.unsub = this.bus.subscribe((ev) => this.onEvent(ev));
4706
+ }
4707
+ dispose() {
4708
+ this.flushBlocks();
4709
+ this.unsub();
4710
+ this.queue = [];
4711
+ this.pending = null;
4712
+ this.partialOpen = false;
4713
+ this.sink = null;
4714
+ this.mode = "idle";
4715
+ }
4716
+ attachPrompt(sink) {
4717
+ this.sink = sink;
4718
+ }
4719
+ getMode() {
4720
+ return this.mode;
4721
+ }
4722
+ beginStreaming() {
4723
+ if (this.mode === "quiet")
4724
+ return;
4725
+ this.flushBlocks();
4726
+ this.flushPendingAsBlock();
4727
+ this.mode = "streaming";
4728
+ }
4729
+ endStreaming() {
4730
+ if (this.mode === "quiet")
4731
+ return;
4732
+ this.closePartial();
4733
+ this.mode = "idle";
4734
+ }
4735
+ beginModal() {
4736
+ this.flushBlocks();
4737
+ this.flushPendingAsBlock();
4738
+ if (this.mode === "quiet")
4739
+ return;
4740
+ if (this.modalDepth === 0)
4741
+ this.modeBeforeModal = this.mode;
4742
+ this.modalDepth++;
4743
+ this.mode = "modal";
4744
+ }
4745
+ endModal() {
4746
+ if (this.modalDepth > 0)
4747
+ this.modalDepth--;
4748
+ if (this.mode === "modal" && this.modalDepth === 0)
4749
+ this.mode = this.modeBeforeModal;
4750
+ const q = this.queue;
4751
+ this.queue = [];
4752
+ for (const ev of q)
4753
+ this.onEvent(ev);
4754
+ }
4755
+ setQuiet(quiet) {
4756
+ this.flushBlocks();
4757
+ if (quiet) {
4758
+ if (this.mode !== "quiet") {
4759
+ this.modeBeforeQuiet = this.mode;
4760
+ this.mode = "quiet";
4761
+ }
4762
+ } else if (this.mode === "quiet") {
4763
+ this.mode = this.modeBeforeQuiet;
4764
+ }
4765
+ }
4766
+ writeRaw(text, stream = "stdout") {
4767
+ this.flushBlocks();
4768
+ if (this.mode === "modal" || this.mode === "quiet")
4769
+ return;
4770
+ if (this.mode === "idle" && this.sink?.isActive() && stream === "stdout") {
4771
+ const prev = this.pending?.stream === "stdout" ? this.pending.text : "";
4772
+ this.pending = { stream, text: prev + text };
4773
+ this.drainPending();
4774
+ return;
4775
+ }
4776
+ if (stream === "stdout")
4777
+ this.partialOpen = !text.endsWith(`
4778
+ `);
4779
+ (stream === "stderr" ? this.err : this.out).write(text);
4780
+ }
4781
+ writeLine(text, stream = "stdout") {
4782
+ this.bus.emit({ level: "info", source: "", kind: "block", text, stream });
4783
+ }
4784
+ clearScreen() {
4785
+ this.flushBlocks();
4786
+ this.flushPendingAsBlock();
4787
+ this.partialOpen = false;
4788
+ if (this.mode === "quiet")
4789
+ return;
4790
+ if (this.sink?.isActive() && this.sink.clearScreen) {
4791
+ this.sink.clearScreen();
4792
+ return;
4793
+ }
4794
+ this.out.write("\x1B[2J\x1B[H");
4795
+ }
4796
+ writeOverlay(text) {
4797
+ if (this.mode === "modal" || this.mode === "quiet")
4798
+ return;
4799
+ if (this.mode === "idle" && this.sink?.isActive())
4800
+ return;
4801
+ this.err.write(text);
4802
+ }
4803
+ onEvent(ev) {
4804
+ if (this.mode === "quiet")
4805
+ return;
4806
+ if (this.mode === "modal") {
4807
+ this.queue.push(ev);
4808
+ return;
4809
+ }
4810
+ if (ev.kind === "raw") {
4811
+ this.writeRaw(ev.text, ev.stream);
4812
+ return;
4813
+ }
4814
+ const stream = ev.stream ?? "stdout";
4815
+ const line = ev.kind === "block" ? ev.text : formatEventLine(ev, this.color);
4816
+ if (this.mode === "idle" && this.sink?.isActive()) {
4817
+ if (this.blockLines === null)
4818
+ this.blockLines = [];
4819
+ this.blockLines.push(line);
4820
+ if (!this.blockFlushScheduled) {
4821
+ this.blockFlushScheduled = true;
4822
+ queueMicrotask(() => this.flushBlocks());
4823
+ }
4824
+ return;
4825
+ }
4826
+ this.flushBlocks();
4827
+ if (this.mode === "streaming")
4828
+ this.closePartial();
4829
+ (stream === "stderr" ? this.err : this.out).write(`${line}
4830
+ `);
4831
+ }
4832
+ flushBlocks() {
4833
+ this.blockFlushScheduled = false;
4834
+ const lines = this.blockLines;
4835
+ this.blockLines = null;
4836
+ if (!lines || lines.length === 0)
4837
+ return;
4838
+ const text = lines.join(`
4839
+ `);
4840
+ if (this.sink?.isActive()) {
4841
+ this.sink.printAbove(text);
4842
+ } else {
4843
+ this.out.write(`${text}
4844
+ `);
4845
+ }
4846
+ }
4847
+ closePartial() {
4848
+ if (this.partialOpen) {
4849
+ this.out.write(`
4850
+ `);
4851
+ this.partialOpen = false;
4852
+ }
4853
+ }
4854
+ drainPending() {
4855
+ if (!this.pending)
4856
+ return;
4857
+ const { stream, text } = this.pending;
4858
+ const idx = text.lastIndexOf(`
4859
+ `);
4860
+ if (idx < 0)
4861
+ return;
4862
+ const head = text.slice(0, idx + 1);
4863
+ this.pending = { stream, text: text.slice(idx + 1) };
4864
+ const lines = head.replace(/\n$/, "").split(`
4865
+ `);
4866
+ if (this.sink?.isActive())
4867
+ this.sink.printAbove(lines.join(`
4868
+ `));
4869
+ else
4870
+ this.out.write(head);
4871
+ }
4872
+ flushPendingAsBlock() {
4873
+ this.flushBlocks();
4874
+ if (!this.pending)
4875
+ return;
4876
+ const text = this.pending.text;
4877
+ const { stream } = this.pending;
4878
+ this.pending = null;
4879
+ if (this.sink?.isActive()) {
4880
+ this.sink.printAbove(text);
4881
+ this.partialOpen = false;
4882
+ } else {
4883
+ (stream === "stderr" ? this.err : this.out).write(text);
4884
+ this.partialOpen = stream === "stdout" ? !text.endsWith(`
4885
+ `) : this.partialOpen;
4886
+ }
4887
+ }
4888
+ }
4889
+ function getDefaultChannel() {
4890
+ if (!defaultChannel)
4891
+ defaultChannel = new OutputChannel(defaultOutputBus);
4892
+ return defaultChannel;
4893
+ }
4894
+ var defaultChannel = null;
4895
+ var init_channel = __esm(() => {
4896
+ init_bus();
4897
+ init_format();
4898
+ });
4899
+
4900
+ // src/output/machine.ts
4901
+ function writeMachineJson(value) {
4902
+ process.stdout.write(`${JSON.stringify(value, null, 2)}
4903
+ `);
4904
+ }
4905
+ function writeNonTtyLine(text) {
4906
+ process.stdout.write(text + `
4907
+ `);
4908
+ }
4909
+
4910
+ // src/output/index.ts
4911
+ var init_output = __esm(() => {
4912
+ init_bus();
4913
+ init_format();
4914
+ init_channel();
4915
+ });
4516
4916
 
4517
4917
  // src/config/domains.ts
4518
4918
  var exports_domains = {};
@@ -4569,7 +4969,7 @@ function loadDomainFiles(configDir) {
4569
4969
  result = deepMerge(result, data);
4570
4970
  anyLoaded = true;
4571
4971
  } catch {
4572
- console.warn(t("config.parse_failed", { path: filePath }));
4972
+ defaultOutputBus.log("warn", "config", t("config.parse_failed", { path: filePath }));
4573
4973
  }
4574
4974
  }
4575
4975
  return anyLoaded ? result : null;
@@ -4602,6 +5002,7 @@ function domainForKey(key) {
4602
5002
  var CONFIG_DOMAINS;
4603
5003
  var init_domains = __esm(() => {
4604
5004
  init_i18n();
5005
+ init_output();
4605
5006
  CONFIG_DOMAINS = {
4606
5007
  core: [
4607
5008
  "version",
@@ -4690,7 +5091,7 @@ function loadJSON(path) {
4690
5091
  try {
4691
5092
  return JSON.parse(readFileSync4(path, "utf-8"), regexReviver);
4692
5093
  } catch {
4693
- console.warn(t("config.parse_failed", { path }));
5094
+ defaultOutputBus.log("warn", "config", t("config.parse_failed", { path }));
4694
5095
  }
4695
5096
  return null;
4696
5097
  }
@@ -4803,11 +5204,11 @@ function loadConfig(options) {
4803
5204
  backup.backupAll();
4804
5205
  backup.backupConfig();
4805
5206
  const summary = backup.getBackupSummary();
4806
- console.log(t("migration.detected", { summary }));
5207
+ defaultOutputBus.log("info", "config", t("migration.detected", { summary }));
4807
5208
  try {
4808
5209
  unlinkSync(globalPath);
4809
5210
  } catch (e) {
4810
- console.error("[config] failed to remove legacy config.json:", e);
5211
+ defaultOutputBus.log("error", "config", `[config] failed to remove legacy config.json: ${e instanceof Error ? e.message : String(e)}`);
4811
5212
  }
4812
5213
  }
4813
5214
  let config = structuredClone(DEFAULTS);
@@ -4845,7 +5246,7 @@ function loadConfig(options) {
4845
5246
  if (providerOverride)
4846
5247
  providerOverride.envValue = config.provider;
4847
5248
  } catch (e) {
4848
- console.warn(t("config.decryption_warning", { error: e.message }));
5249
+ defaultOutputBus.log("warn", "config", t("config.decryption_warning", { error: e.message }));
4849
5250
  }
4850
5251
  if (overrides.length > 0)
4851
5252
  envOverrideMap.set(config, overrides);
@@ -4880,7 +5281,7 @@ function saveConfig(config, configPath, configDir) {
4880
5281
  });
4881
5282
  writeFileSync4(configPath, JSON.stringify(encryptedConfig, regexReplacer, 2), "utf-8");
4882
5283
  } catch (e) {
4883
- console.warn(t("config.encryption_warning", { error: e.message }));
5284
+ defaultOutputBus.log("warn", "config", t("config.encryption_warning", { error: e.message }));
4884
5285
  writeFileSync4(configPath, JSON.stringify(toWrite, regexReplacer, 2), "utf-8");
4885
5286
  }
4886
5287
  }
@@ -4894,6 +5295,7 @@ var init_config2 = __esm(() => {
4894
5295
  init_backup();
4895
5296
  init_encryption();
4896
5297
  init_domains();
5298
+ init_output();
4897
5299
  CONFIG_DIR = join6(homedir2(), ".mma");
4898
5300
  CONFIG_FILE = join6(CONFIG_DIR, "config.json");
4899
5301
  CONFIG_DOMAIN_DIR = join6(CONFIG_DIR, "config");
@@ -5091,82 +5493,9 @@ var init_file_log = __esm(() => {
5091
5493
  MAX_LOG_SIZE = 5 * 1024 * 1024;
5092
5494
  });
5093
5495
 
5094
- // node_modules/picocolors/picocolors.js
5095
- var require_picocolors = __commonJS((exports, module) => {
5096
- var p = process || {};
5097
- var argv = p.argv || [];
5098
- var env = p.env || {};
5099
- var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
5100
- var formatter = (open, close, replace = open) => (input) => {
5101
- let string = "" + input, index = string.indexOf(close, open.length);
5102
- return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
5103
- };
5104
- var replaceClose = (string, close, replace, index) => {
5105
- let result = "", cursor = 0;
5106
- do {
5107
- result += string.substring(cursor, index) + replace;
5108
- cursor = index + close.length;
5109
- index = string.indexOf(close, cursor);
5110
- } while (~index);
5111
- return result + string.substring(cursor);
5112
- };
5113
- var createColors = (enabled = isColorSupported) => {
5114
- let f = enabled ? formatter : () => String;
5115
- return {
5116
- isColorSupported: enabled,
5117
- reset: f("\x1B[0m", "\x1B[0m"),
5118
- bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
5119
- dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
5120
- italic: f("\x1B[3m", "\x1B[23m"),
5121
- underline: f("\x1B[4m", "\x1B[24m"),
5122
- inverse: f("\x1B[7m", "\x1B[27m"),
5123
- hidden: f("\x1B[8m", "\x1B[28m"),
5124
- strikethrough: f("\x1B[9m", "\x1B[29m"),
5125
- black: f("\x1B[30m", "\x1B[39m"),
5126
- red: f("\x1B[31m", "\x1B[39m"),
5127
- green: f("\x1B[32m", "\x1B[39m"),
5128
- yellow: f("\x1B[33m", "\x1B[39m"),
5129
- blue: f("\x1B[34m", "\x1B[39m"),
5130
- magenta: f("\x1B[35m", "\x1B[39m"),
5131
- cyan: f("\x1B[36m", "\x1B[39m"),
5132
- white: f("\x1B[37m", "\x1B[39m"),
5133
- gray: f("\x1B[90m", "\x1B[39m"),
5134
- bgBlack: f("\x1B[40m", "\x1B[49m"),
5135
- bgRed: f("\x1B[41m", "\x1B[49m"),
5136
- bgGreen: f("\x1B[42m", "\x1B[49m"),
5137
- bgYellow: f("\x1B[43m", "\x1B[49m"),
5138
- bgBlue: f("\x1B[44m", "\x1B[49m"),
5139
- bgMagenta: f("\x1B[45m", "\x1B[49m"),
5140
- bgCyan: f("\x1B[46m", "\x1B[49m"),
5141
- bgWhite: f("\x1B[47m", "\x1B[49m"),
5142
- blackBright: f("\x1B[90m", "\x1B[39m"),
5143
- redBright: f("\x1B[91m", "\x1B[39m"),
5144
- greenBright: f("\x1B[92m", "\x1B[39m"),
5145
- yellowBright: f("\x1B[93m", "\x1B[39m"),
5146
- blueBright: f("\x1B[94m", "\x1B[39m"),
5147
- magentaBright: f("\x1B[95m", "\x1B[39m"),
5148
- cyanBright: f("\x1B[96m", "\x1B[39m"),
5149
- whiteBright: f("\x1B[97m", "\x1B[39m"),
5150
- bgBlackBright: f("\x1B[100m", "\x1B[49m"),
5151
- bgRedBright: f("\x1B[101m", "\x1B[49m"),
5152
- bgGreenBright: f("\x1B[102m", "\x1B[49m"),
5153
- bgYellowBright: f("\x1B[103m", "\x1B[49m"),
5154
- bgBlueBright: f("\x1B[104m", "\x1B[49m"),
5155
- bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
5156
- bgCyanBright: f("\x1B[106m", "\x1B[49m"),
5157
- bgWhiteBright: f("\x1B[107m", "\x1B[49m")
5158
- };
5159
- };
5160
- module.exports = createColors();
5161
- module.exports.createColors = createColors;
5162
- });
5163
-
5164
5496
  // src/logger/app-logger.ts
5165
5497
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync5, existsSync as existsSync8 } from "fs";
5166
5498
  import { join as join8 } from "path";
5167
- function isColorEnabled() {
5168
- return !process.env.NO_COLOR && !process.env.CI && process.stdout.isTTY === true;
5169
- }
5170
5499
 
5171
5500
  class Logger {
5172
5501
  level;
@@ -5174,9 +5503,11 @@ class Logger {
5174
5503
  logDir = null;
5175
5504
  sessionDir = null;
5176
5505
  fileLog;
5177
- constructor(level = "info", prefix = "") {
5506
+ sink;
5507
+ constructor(level = "info", prefix = "", sink = defaultOutputBus) {
5178
5508
  this.level = level;
5179
5509
  this.prefix = prefix;
5510
+ this.sink = sink;
5180
5511
  this.fileLog = new FileLogWriter;
5181
5512
  }
5182
5513
  setLevel(level) {
@@ -5226,7 +5557,7 @@ class Logger {
5226
5557
  this.fileLog.logREPL(tag, sanitizeLogMessage(content));
5227
5558
  }
5228
5559
  child(prefix) {
5229
- const childLogger = new Logger(this.level, this.prefix ? `${this.prefix}:${prefix}` : prefix);
5560
+ const childLogger = new Logger(this.level, this.prefix ? `${this.prefix}:${prefix}` : prefix, this.sink);
5230
5561
  if (this.logDir)
5231
5562
  childLogger.setLogDir(this.logDir);
5232
5563
  if (this.sessionDir)
@@ -5251,10 +5582,11 @@ class Logger {
5251
5582
  const sanitizedMsg = sanitizeLogMessage(msg);
5252
5583
  const sanitizedMeta = meta ? this.sanitizeMeta(meta) : undefined;
5253
5584
  const ts = new Date().toISOString();
5254
- const prefix = this.prefix ? ` [${this.prefix}]` : "";
5255
5585
  const metaStr = sanitizedMeta ? ` ${JSON.stringify(sanitizedMeta)}` : "";
5256
- const line = `[${level.toUpperCase()}]${prefix} ${ts} — ${sanitizedMsg}${metaStr}`;
5257
- console.log(isColorEnabled() ? LEVEL_COLORS[level](line) : line);
5586
+ const line = `${sanitizedMsg}${metaStr}`;
5587
+ try {
5588
+ this.sink.emit({ level, source: this.prefix || "mma", kind: "log", text: line });
5589
+ } catch {}
5258
5590
  this.fileLog.log(level.toUpperCase(), this.prefix || "MMA", `${ts} — ${sanitizedMsg}${metaStr}`);
5259
5591
  const logTarget = this.sessionDir ?? this.logDir;
5260
5592
  if (logTarget) {
@@ -5316,18 +5648,12 @@ class Logger {
5316
5648
  } catch {}
5317
5649
  }
5318
5650
  }
5319
- var import_picocolors, LEVELS, LEVEL_COLORS;
5651
+ var LEVELS;
5320
5652
  var init_app_logger = __esm(() => {
5321
5653
  init_data_sanitizer();
5322
5654
  init_file_log();
5323
- import_picocolors = __toESM(require_picocolors(), 1);
5655
+ init_output();
5324
5656
  LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
5325
- LEVEL_COLORS = {
5326
- debug: (s) => import_picocolors.default.dim(s),
5327
- info: (s) => s,
5328
- warn: (s) => import_picocolors.default.yellow(s),
5329
- error: (s) => import_picocolors.default.red(s)
5330
- };
5331
5657
  });
5332
5658
 
5333
5659
  // node_modules/base64-js/index.js
@@ -7401,6 +7727,9 @@ class ToolExecutor {
7401
7727
  setScope(scope) {
7402
7728
  this.ctx.scope = scope;
7403
7729
  }
7730
+ setPromptIO(io) {
7731
+ this.ctx.promptIO = io;
7732
+ }
7404
7733
  getRecursionDepth() {
7405
7734
  return this.ctx.recursionDepth ?? 0;
7406
7735
  }
@@ -7765,7 +8094,7 @@ class AuditNotifier {
7765
8094
  try {
7766
8095
  await this.sendToWebhook(notification);
7767
8096
  } catch (error) {
7768
- console.error("[AuditNotifier] Webhook failed, adding to retry queue:", error);
8097
+ defaultOutputBus.log("warn", "audit", `[AuditNotifier] Webhook failed, adding to retry queue: ${error instanceof Error ? error.message : String(error)}`, { persist: true });
7769
8098
  this.addToRetryQueue(notification);
7770
8099
  }
7771
8100
  }
@@ -7803,7 +8132,7 @@ class AuditNotifier {
7803
8132
  appendFileSync3(this.config.filePath, line + `
7804
8133
  `, "utf8");
7805
8134
  } catch (error) {
7806
- console.error("[AuditNotifier] Failed to write to file:", error);
8135
+ defaultOutputBus.log("error", "audit", `[AuditNotifier] Failed to write to file: ${error instanceof Error ? error.message : String(error)}`, { persist: true });
7807
8136
  }
7808
8137
  }
7809
8138
  async sendToWebhook(notification) {
@@ -7839,7 +8168,7 @@ class AuditNotifier {
7839
8168
  while (this.retryQueue.length > 0) {
7840
8169
  const item = this.retryQueue[0];
7841
8170
  if (item.retries >= (this.config.maxRetries ?? 3)) {
7842
- console.error("[AuditNotifier] Max retries exceeded for notification:", item.entry);
8171
+ defaultOutputBus.log("error", "audit", `[AuditNotifier] Max retries exceeded for notification: ${JSON.stringify(item.entry)}`, { persist: true });
7843
8172
  this.retryQueue.shift();
7844
8173
  continue;
7845
8174
  }
@@ -7848,7 +8177,7 @@ class AuditNotifier {
7848
8177
  this.retryQueue.shift();
7849
8178
  } catch (error) {
7850
8179
  item.retries++;
7851
- console.error(`[AuditNotifier] Webhook retry ${item.retries} failed:`, error instanceof Error ? error.message : error);
8180
+ defaultOutputBus.log("warn", "audit", `[AuditNotifier] Webhook retry ${item.retries} failed: ${error instanceof Error ? error.message : String(error)}`, { persist: true });
7852
8181
  const delay = backoffDelay(item.retries, 1000);
7853
8182
  await new Promise((resolve3) => setTimeout(resolve3, delay));
7854
8183
  }
@@ -7867,7 +8196,7 @@ class AuditNotifier {
7867
8196
  `).filter(Boolean);
7868
8197
  return lines.slice(-limit).map((line) => JSON.parse(line));
7869
8198
  } catch (error) {
7870
- console.error("[AuditNotifier] Failed to read notifications:", error);
8199
+ defaultOutputBus.log("error", "audit", `[AuditNotifier] Failed to read notifications: ${error instanceof Error ? error.message : String(error)}`, { persist: true });
7871
8200
  return [];
7872
8201
  }
7873
8202
  }
@@ -7908,6 +8237,7 @@ function createAuditNotifier(config) {
7908
8237
  }
7909
8238
  var SEVERITY_WEIGHTS, DEFAULT_AUDIT_NOTIFIER_CONFIG, globalAuditNotifier;
7910
8239
  var init_audit_notifier = __esm(() => {
8240
+ init_output();
7911
8241
  SEVERITY_WEIGHTS = {
7912
8242
  low: 1,
7913
8243
  medium: 2,
@@ -8287,11 +8617,11 @@ var init_session_isolation = __esm(() => {
8287
8617
  });
8288
8618
 
8289
8619
  // src/ui/colors.ts
8290
- var import_picocolors2, isTty = () => process.stdout.isTTY === true, enabled, pc2;
8620
+ var import_picocolors2, isTty = () => process.stdout.isTTY === true, enabled, pc;
8291
8621
  var init_colors = __esm(() => {
8292
8622
  import_picocolors2 = __toESM(require_picocolors(), 1);
8293
8623
  enabled = isTty() && !process.env.CI && !process.env.NO_COLOR;
8294
- pc2 = import_picocolors2.createColors(enabled);
8624
+ pc = import_picocolors2.createColors(enabled);
8295
8625
  });
8296
8626
 
8297
8627
  // src/ui/diff.ts
@@ -8401,11 +8731,11 @@ function formatLine(line, maxNumWidth) {
8401
8731
  const num2 = line.type === "remove" ? line.oldNum : line.newNum;
8402
8732
  const numStr = num2 !== null ? String(num2).padStart(maxNumWidth) : " ".repeat(maxNumWidth);
8403
8733
  if (line.type === "remove") {
8404
- return `${numStr} ${pc2.red("-")} ${line.content}`;
8734
+ return `${numStr} ${pc.red("-")} ${line.content}`;
8405
8735
  } else if (line.type === "add") {
8406
- return `${numStr} ${pc2.green("+")} ${line.content}`;
8736
+ return `${numStr} ${pc.green("+")} ${line.content}`;
8407
8737
  } else if (line.content === "...") {
8408
- return pc2.dim(` ${" ".repeat(maxNumWidth)}...`);
8738
+ return pc.dim(` ${" ".repeat(maxNumWidth)}...`);
8409
8739
  } else {
8410
8740
  return ` ${numStr} ${line.content}`;
8411
8741
  }
@@ -8418,7 +8748,7 @@ function generateDiff(oldContent, newContent) {
8418
8748
  const newLines = newContent.split(`
8419
8749
  `);
8420
8750
  if (oldLines.length > MAX_LCS_INPUT_LINES || newLines.length > MAX_LCS_INPUT_LINES) {
8421
- return pc2.dim(` ... (file too large for line diff: ${oldLines.length} -> ${newLines.length} lines)`);
8751
+ return pc.dim(` ... (file too large for line diff: ${oldLines.length} -> ${newLines.length} lines)`);
8422
8752
  }
8423
8753
  const diff = buildDiff(oldLines, newLines);
8424
8754
  if (diff.length === 0)
@@ -8431,7 +8761,7 @@ function generateDiff(oldContent, newContent) {
8431
8761
  let lines = diff.map((l) => formatLine(l, maxNumWidth));
8432
8762
  if (lines.length > MAX_DIFF_LINES) {
8433
8763
  const truncated = lines.slice(0, MAX_DIFF_LINES);
8434
- truncated.push(pc2.dim(` ... (${lines.length - MAX_DIFF_LINES} more lines)`));
8764
+ truncated.push(pc.dim(` ... (${lines.length - MAX_DIFF_LINES} more lines)`));
8435
8765
  lines = truncated;
8436
8766
  }
8437
8767
  return lines.join(`
@@ -8444,11 +8774,11 @@ function generateNewFileDiff(content) {
8444
8774
  const diffLines = [];
8445
8775
  for (let i = 0;i < lines.length; i++) {
8446
8776
  const numStr = String(i + 1).padStart(maxNumWidth);
8447
- diffLines.push(`${numStr} ${pc2.green("+")} ${lines[i]}`);
8777
+ diffLines.push(`${numStr} ${pc.green("+")} ${lines[i]}`);
8448
8778
  }
8449
8779
  if (diffLines.length > MAX_DIFF_LINES) {
8450
8780
  const truncated = diffLines.slice(0, MAX_DIFF_LINES);
8451
- truncated.push(pc2.dim(` ... (${diffLines.length - MAX_DIFF_LINES} more lines)`));
8781
+ truncated.push(pc.dim(` ... (${diffLines.length - MAX_DIFF_LINES} more lines)`));
8452
8782
  return truncated.join(`
8453
8783
  `);
8454
8784
  }
@@ -8462,11 +8792,11 @@ function generateDeleteDiff(content) {
8462
8792
  const diffLines = [];
8463
8793
  for (let i = 0;i < lines.length; i++) {
8464
8794
  const numStr = String(i + 1).padStart(maxNumWidth);
8465
- diffLines.push(`${numStr} ${pc2.red("-")} ${lines[i]}`);
8795
+ diffLines.push(`${numStr} ${pc.red("-")} ${lines[i]}`);
8466
8796
  }
8467
8797
  if (diffLines.length > MAX_DIFF_LINES) {
8468
8798
  const truncated = diffLines.slice(0, MAX_DIFF_LINES);
8469
- truncated.push(pc2.dim(` ... (${diffLines.length - MAX_DIFF_LINES} more lines)`));
8799
+ truncated.push(pc.dim(` ... (${diffLines.length - MAX_DIFF_LINES} more lines)`));
8470
8800
  return truncated.join(`
8471
8801
  `);
8472
8802
  }
@@ -8474,7 +8804,7 @@ function generateDeleteDiff(content) {
8474
8804
  `);
8475
8805
  }
8476
8806
  function generateMoveDiff(fromPath, toPath) {
8477
- return [pc2.red(` - ${fromPath}`), pc2.green(` + ${toPath}`)].join(`
8807
+ return [pc.red(` - ${fromPath}`), pc.green(` + ${toPath}`)].join(`
8478
8808
  `);
8479
8809
  }
8480
8810
  var CONTEXT_LINES = 3, MAX_DIFF_LINES = 100, MAX_LCS_INPUT_LINES = 2000;
@@ -9877,6 +10207,7 @@ ${output}`;
9877
10207
  output = `(exit code ${code})`;
9878
10208
  }
9879
10209
  output = npmExecHint(output);
10210
+ output = interactivePromptHint(output);
9880
10211
  if (platform3() === "win32") {
9881
10212
  const originalFirstWord = originalCommand.trim().split(/\s+/)[0]?.split(/[\\/]/).pop();
9882
10213
  if (originalFirstWord && originalFirstWord in UNIX_TO_WIN_HINTS) {
@@ -9922,7 +10253,15 @@ Hint: ${t("exec.npm_exec_hint")}`;
9922
10253
  }
9923
10254
  return output;
9924
10255
  }
9925
- var BASH_GRACE_MS = 5000, SPAWN_SETTLE_MS = 100, BG_OUTPUT_PREVIEW_LINES = 15, bashGraceMs, FAILING_FIRST_WORDS, HARD_BLOCK_THRESHOLD = 3, UNIX_TO_WIN_HINTS, UNIX_TO_WIN_TRANSLATE, NEVER_TOOL_CALLS, CLI_FILE_RUN_RE, NPM_EXEC_RE, HIDDEN_PROCESS_TOOLS, bashTool;
10256
+ function interactivePromptHint(output) {
10257
+ if (INTERACTIVE_PROMPT_RE.test(output)) {
10258
+ return `${output}
10259
+
10260
+ Hint: ${t("exec.interactive_hint")}`;
10261
+ }
10262
+ return output;
10263
+ }
10264
+ var BASH_GRACE_MS = 5000, SPAWN_SETTLE_MS = 100, BG_OUTPUT_PREVIEW_LINES = 15, bashGraceMs, FAILING_FIRST_WORDS, HARD_BLOCK_THRESHOLD = 3, UNIX_TO_WIN_HINTS, UNIX_TO_WIN_TRANSLATE, NEVER_TOOL_CALLS, CLI_FILE_RUN_RE, NPM_EXEC_RE, INTERACTIVE_PROMPT_RE, HIDDEN_PROCESS_TOOLS, bashTool;
9926
10265
  var init_bash = __esm(() => {
9927
10266
  init_command_validator();
9928
10267
  init_audit_log();
@@ -10000,6 +10339,7 @@ var init_bash = __esm(() => {
10000
10339
  ]);
10001
10340
  CLI_FILE_RUN_RE = /\b(bun|node|deno|python|python3|tsx|ts-node|php|ruby|go\s+run)\S*\s+(run\s+)?["']?[\w./\\-]+\.(ts|js|tsx|jsx|mjs|cjs|py)\b/;
10002
10341
  NPM_EXEC_RE = /could not determine executable to run/i;
10342
+ INTERACTIVE_PROMPT_RE = /operation (?:cancelled|canceled|aborted)|stdin is not a tty|not a tty|cannot prompt without a tty/i;
10003
10343
  HIDDEN_PROCESS_TOOLS = ["process_list", "process_log", "process_kill"];
10004
10344
  bashTool = {
10005
10345
  name: "bash",
@@ -14351,7 +14691,7 @@ function evaluateReasoningPolicy(input, state) {
14351
14691
  var DECAY_THRESHOLD = 5;
14352
14692
 
14353
14693
  // src/core/agent/constants.ts
14354
- var TOOL_RESULT_MAX_TOKENS_RATIO = 0.3, TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000, QUALITY_TRIGGER_THRESHOLD = 40, TOOL_ARGS_SUMMARY_MAX_CHARS = 240, FORCED_COMPACTION_COOLDOWN = 3, MAX_LLM_ERROR_RETRIES = 2, MAX_HALLUCINATION_RETRIES = 3, MAX_CONSECUTIVE_TOOL_FAILURES = 5, MIN_REPEATED_TOOL_FAILURES = 3, MAX_AUDIT_RETRIES = 3, MAX_EMPTY_RESPONSE_RETRIES = 2, MAX_REPEATED_TOOL_CALLS = 2, MUTATION_CYCLE_NUDGE_THRESHOLD = 5;
14694
+ var TOOL_RESULT_MAX_TOKENS_RATIO = 0.3, TOOL_RESULT_ABSOLUTE_MAX_CHARS = 15000, QUALITY_TRIGGER_THRESHOLD = 40, TOOL_ARGS_SUMMARY_MAX_CHARS = 240, FORCED_COMPACTION_COOLDOWN = 3, MAX_LLM_ERROR_RETRIES = 2, MAX_HALLUCINATION_RETRIES = 3, MAX_CONSECUTIVE_TOOL_FAILURES = 5, MIN_REPEATED_TOOL_FAILURES = 3, MAX_AUDIT_RETRIES = 3, MAX_EMPTY_RESPONSE_RETRIES = 2, MAX_REPEATED_TOOL_CALLS = 2, MAX_REPEATED_TOOL_CALLS_INTERACTIVE = 5, MUTATION_CYCLE_NUDGE_THRESHOLD = 5;
14355
14695
 
14356
14696
  // src/core/agent/loop-state.ts
14357
14697
  function createLoopState() {
@@ -14617,7 +14957,10 @@ class ReasoningEffortResolver {
14617
14957
  const overrideCooldown = reasoningConfig?.overrideCooldown ?? 0;
14618
14958
  const overrideAge = state.iteration - reasoningState.overrideIteration;
14619
14959
  const overrideActive = overrideCooldown > 0 && reasoningState.overrideIteration >= 0 && overrideAge > 0 && overrideAge <= overrideCooldown;
14620
- if (overrideActive) {
14960
+ if (reasoningState.manual) {
14961
+ level = reasoningState.level;
14962
+ source = "agent_override";
14963
+ } else if (overrideActive) {
14621
14964
  level = reasoningState.level;
14622
14965
  source = "agent_override";
14623
14966
  } else if (reasoningConfig && reasoningConfig.mode === "auto" && deps.probePassed) {
@@ -14657,20 +15000,20 @@ class ContextRenderer {
14657
15000
  const ctxPct = Math.min(100, Math.round(ctxTokens / ctxBudget.history * 100));
14658
15001
  const barLen = 10;
14659
15002
  const filled = Math.round(ctxPct / 100 * barLen);
14660
- const ctxBar = pc2.green("█".repeat(filled)) + pc2.dim("░".repeat(barLen - filled));
14661
- const pctColor = ctxPct >= 75 ? pc2.yellow : pc2.dim;
15003
+ const ctxBar = pc.green("█".repeat(filled)) + pc.dim("░".repeat(barLen - filled));
15004
+ const pctColor = ctxPct >= 75 ? pc.yellow : pc.dim;
14662
15005
  const compCount = contextManager.getCompactionCount();
14663
15006
  const quality = contextManager.getQuality();
14664
- const qualityColor = quality >= 70 ? pc2.green : quality >= 40 ? pc2.yellow : pc2.red;
15007
+ const qualityColor = quality >= 70 ? pc.green : quality >= 40 ? pc.yellow : pc.red;
14665
15008
  onMeta?.(`
14666
- ${ctxBar} ${pctColor(`${ctxPct}%`)} ${pc2.dim(`ctx: ${ctxTokens}/${ctxBudget.history}`)} ${pc2.dim(`compactions: ${compCount}`)} ${qualityColor(`quality: ${quality}%`)}
15009
+ ${ctxBar} ${pctColor(`${ctxPct}%`)} ${pc.dim(`ctx: ${ctxTokens}/${ctxBudget.history}`)} ${pc.dim(`compactions: ${compCount}`)} ${qualityColor(`quality: ${quality}%`)}
14667
15010
  `);
14668
15011
  }
14669
15012
  renderCompaction(contextManager, onMeta) {
14670
15013
  const compCount = contextManager.getCompactionCount();
14671
15014
  if (compCount > this.lastCompactionShown) {
14672
15015
  this.lastCompactionShown = compCount;
14673
- onMeta?.(pc2.dim(`
15016
+ onMeta?.(pc.dim(`
14674
15017
  ⟳ Context compacted (${compCount})
14675
15018
  `));
14676
15019
  }
@@ -14822,14 +15165,14 @@ class ToolBatchExecutor {
14822
15165
  } else if (result.success) {
14823
15166
  const metaOut = pluginManager.runOnMeta({ iteration, logger, contextManager }, result.output);
14824
15167
  onMeta?.(`
14825
- ` + pc2.dim(metaOut) + `
15168
+ ` + pc.dim(metaOut) + `
14826
15169
  `);
14827
15170
  } else {
14828
15171
  const line = compactToolError(result.output);
14829
15172
  const metaOut = line ? pluginManager.runOnMeta({ iteration, logger, contextManager }, line) : "";
14830
15173
  if (metaOut)
14831
15174
  onMeta?.(`
14832
- ` + pc2.red(metaOut) + `
15175
+ ` + pc.red(metaOut) + `
14833
15176
  `);
14834
15177
  }
14835
15178
  if (result.diff) {
@@ -14983,7 +15326,7 @@ class HallucinationGate {
14983
15326
  const warnLine = `${t("hall.uncertainty_prefix").trim()} ${reason ?? ""}`;
14984
15327
  if (deps.onMeta) {
14985
15328
  deps.onMeta(`
14986
- ${pc2.yellow(warnLine)}
15329
+ ${pc.yellow(warnLine)}
14987
15330
  `);
14988
15331
  } else if (deps.onChunk) {
14989
15332
  deps.onChunk(`
@@ -15341,7 +15684,12 @@ class Agent {
15341
15684
  return this.reasoningState.level;
15342
15685
  }
15343
15686
  setReasoningLevel(level) {
15687
+ if (level === "auto") {
15688
+ this.reasoningState.manual = false;
15689
+ return;
15690
+ }
15344
15691
  this.reasoningState.level = level;
15692
+ this.reasoningState.manual = true;
15345
15693
  }
15346
15694
  get currentIteration() {
15347
15695
  return this._currentIteration;
@@ -15367,6 +15715,9 @@ class Agent {
15367
15715
  this.deps.toolExecutor.setScope(this.deps.scope);
15368
15716
  }
15369
15717
  }
15718
+ setPromptIO(io) {
15719
+ this.deps.toolExecutor.setPromptIO(io);
15720
+ }
15370
15721
  buildSystemPrompt() {
15371
15722
  const systemBudget = Math.floor(this.deps.config.contextWindow * this.deps.config.contextBudget.systemPrompt);
15372
15723
  const builder = new PromptBuilder(systemBudget);
@@ -15453,6 +15804,7 @@ class Agent {
15453
15804
  this.deps.logger.warn(t("prompt.overflow.exceeded", {
15454
15805
  label: w.label,
15455
15806
  original: String(w.originalTokens),
15807
+ needed: String(needed),
15456
15808
  budget: String(systemBudget),
15457
15809
  mode: w.mode === "summary" ? "summarized" : "truncated",
15458
15810
  resolved: String(w.resolvedTokens),
@@ -15714,7 +16066,7 @@ class Agent {
15714
16066
  if (config.showReasoning) {
15715
16067
  const metaOut = pluginManager.runOnMeta({ iteration: state.iteration, logger, contextManager }, chunk.content);
15716
16068
  if (metaOut) {
15717
- onMeta?.(pc2.dim(metaOut));
16069
+ onMeta?.(pc.dim(metaOut));
15718
16070
  }
15719
16071
  emittedReasoning = true;
15720
16072
  }
@@ -15799,12 +16151,15 @@ class Agent {
15799
16151
  role: "user",
15800
16152
  content: `<system-summary>You just called the same tool with identical arguments. If the task is done, answer with a final text response NOW. If the command failed, try a different approach.</system-summary>`
15801
16153
  });
16154
+ state.repeatedToolCount++;
15802
16155
  if (this.deps.exitOnComplete) {
15803
- state.repeatedToolCount++;
15804
16156
  if (state.repeatedToolCount >= MAX_REPEATED_TOOL_CALLS) {
15805
16157
  logger.debug("Exit-on-complete: repeated identical tool call, stopping");
15806
16158
  break;
15807
16159
  }
16160
+ } else if (state.repeatedToolCount >= MAX_REPEATED_TOOL_CALLS_INTERACTIVE && toolCalls.every((tc) => LOOP_PRONE_STATUS_TOOLS.has(tc.name))) {
16161
+ logger.warn(`Repeated identical status tool ${state.repeatedToolCount}× (iteration ${state.iteration}) — stopping to avoid an infinite loop`);
16162
+ break;
15808
16163
  }
15809
16164
  } else {
15810
16165
  state.repeatedToolCount = 0;
@@ -16058,6 +16413,7 @@ class Agent {
16058
16413
  });
16059
16414
  }
16060
16415
  }
16416
+ var LOOP_PRONE_STATUS_TOOLS;
16061
16417
  var init_agent = __esm(() => {
16062
16418
  init_manager();
16063
16419
  init_factory();
@@ -16081,6 +16437,13 @@ var init_agent = __esm(() => {
16081
16437
  init_audit_gate();
16082
16438
  init_prompt_overflow();
16083
16439
  init_tool_output();
16440
+ LOOP_PRONE_STATUS_TOOLS = new Set([
16441
+ "session_info",
16442
+ "process_list",
16443
+ "process_log",
16444
+ "file_info",
16445
+ "project_map"
16446
+ ]);
16084
16447
  });
16085
16448
 
16086
16449
  // src/modules/context/fact-extractor.ts
@@ -16602,14 +16965,6 @@ class ConfidenceCheck {
16602
16965
  };
16603
16966
  }
16604
16967
  const wordCount = response.split(/\s+/).filter(Boolean).length;
16605
- const hasStructure = /```|^\s*[-*]\s|^\s*\d+\.\s|<[^>]+>/m.test(response);
16606
- if (wordCount < MIN_WORDS && !hasStructure) {
16607
- return {
16608
- status: "warn",
16609
- kind: "short",
16610
- reason: t("hall.short_response")
16611
- };
16612
- }
16613
16968
  if (this.previousResponse) {
16614
16969
  const prevWords = this.previousResponse.split(/\s+/).filter(Boolean).length;
16615
16970
  const bothSubstantive = response.length >= MIN_REPEAT_CHARS && this.previousResponse.length >= MIN_REPEAT_CHARS && wordCount >= MIN_REPEAT_WORDS && prevWords >= MIN_REPEAT_WORDS;
@@ -16653,7 +17008,7 @@ class ConfidenceCheck {
16653
17008
  return matches / smaller;
16654
17009
  }
16655
17010
  }
16656
- var MIN_CHARS = 1, MIN_WORDS = 5, MIN_REPEAT_CHARS = 120, MIN_REPEAT_WORDS = 20, REPEAT_OVERLAP_THRESHOLD = 0.8;
17011
+ var MIN_CHARS = 1, MIN_REPEAT_CHARS = 120, MIN_REPEAT_WORDS = 20, REPEAT_OVERLAP_THRESHOLD = 0.8;
16657
17012
  var init_confidence = __esm(() => {
16658
17013
  init_i18n();
16659
17014
  });
@@ -18695,7 +19050,7 @@ class MCPClient {
18695
19050
  this.pendingReject = null;
18696
19051
  }
18697
19052
  } catch (e) {
18698
- console.error("[MCPClient] Unparseable SSE message:", String(data).slice(0, 120), e instanceof Error ? e.message : e);
19053
+ defaultOutputBus.log("error", "mcp", `[MCPClient] Unparseable SSE message: ${String(data).slice(0, 120)} ${e instanceof Error ? e.message : String(e)}`, { persist: true });
18699
19054
  }
18700
19055
  }
18701
19056
  handleSSEError(err) {
@@ -19010,7 +19365,9 @@ class MCPClient {
19010
19365
  }
19011
19366
  }
19012
19367
  var HTTP_TIMEOUT_MS = 1e4, MCP_ACCEPT_HEADER = "application/json, text/event-stream";
19013
- var init_client = () => {};
19368
+ var init_client = __esm(() => {
19369
+ init_output();
19370
+ });
19014
19371
 
19015
19372
  // src/modules/mcp/registry.ts
19016
19373
  class MCPRegistry {
@@ -23641,7 +23998,7 @@ class SessionFileEncryptor {
23641
23998
  try {
23642
23999
  return [this.decryptFileContent(line)];
23643
24000
  } catch (e) {
23644
- console.error("[session-encryption] failed to decrypt JSONL line — skipping it:", e instanceof Error ? e.message : e);
24001
+ defaultOutputBus.log("error", "security", `[session-encryption] failed to decrypt JSONL line — skipping it: ${e instanceof Error ? e.message : String(e)}`, { persist: true });
23645
24002
  return [];
23646
24003
  }
23647
24004
  });
@@ -23720,6 +24077,7 @@ class SessionFileEncryptor {
23720
24077
  var DEFAULT_SESSION_ENCRYPTION, globalSessionEncryptor;
23721
24078
  var init_session_encryption = __esm(() => {
23722
24079
  init_encryption();
24080
+ init_output();
23723
24081
  DEFAULT_SESSION_ENCRYPTION = {
23724
24082
  enabled: false,
23725
24083
  encryptHistory: true,
@@ -23788,7 +24146,10 @@ class SessionStore {
23788
24146
  mkdirSync17(dir, { recursive: true, mode: 448 });
23789
24147
  const content = JSON.stringify(meta, null, 2);
23790
24148
  if (this.encryptor) {
23791
- writeFileSync16(this.metaPath(id), this.encryptor.encryptFileContent(content), { encoding: "utf-8", mode: 384 });
24149
+ writeFileSync16(this.metaPath(id), this.encryptor.encryptFileContent(content), {
24150
+ encoding: "utf-8",
24151
+ mode: 384
24152
+ });
23792
24153
  } else {
23793
24154
  writeFileSync16(this.metaPath(id), content, { encoding: "utf-8", mode: 384 });
23794
24155
  }
@@ -23828,7 +24189,10 @@ class SessionStore {
23828
24189
  const line = JSON.stringify(msg);
23829
24190
  if (this.encryptor?.isEnabled()) {
23830
24191
  appendFileSync6(this.historyPath(id), this.encryptor.encryptFileContent(line) + `
23831
- `, { encoding: "utf-8", mode: 384 });
24192
+ `, {
24193
+ encoding: "utf-8",
24194
+ mode: 384
24195
+ });
23832
24196
  } else {
23833
24197
  appendFileSync6(this.historyPath(id), line + `
23834
24198
  `, { encoding: "utf-8", mode: 384 });
@@ -23875,7 +24239,10 @@ class SessionStore {
23875
24239
  const line = JSON.stringify(entry);
23876
24240
  if (this.encryptor?.isEnabled()) {
23877
24241
  appendFileSync6(this.sessionLogPath(id), this.encryptor.encryptFileContent(line) + `
23878
- `, { encoding: "utf-8", mode: 384 });
24242
+ `, {
24243
+ encoding: "utf-8",
24244
+ mode: 384
24245
+ });
23879
24246
  } else {
23880
24247
  appendFileSync6(this.sessionLogPath(id), line + `
23881
24248
  `, { encoding: "utf-8", mode: 384 });
@@ -26833,7 +27200,7 @@ import { existsSync as existsSync51, readFileSync as readFileSync33, writeFileSy
26833
27200
  import { join as join45, dirname as dirname18 } from "path";
26834
27201
  import { homedir as homedir14 } from "os";
26835
27202
  function cachePath() {
26836
- return join45(homedir14(), ".mma", "reasoning-cache.json");
27203
+ return process.env.MMA_REASONING_CACHE ?? join45(homedir14(), ".mma", "reasoning-cache.json");
26837
27204
  }
26838
27205
  async function probeReasoningSupport(provider, strategy, signal) {
26839
27206
  if (strategy === "none")
@@ -26989,7 +27356,8 @@ var exports_bootstrap = {};
26989
27356
  __export(exports_bootstrap, {
26990
27357
  setOneShotMode: () => setOneShotMode,
26991
27358
  buildSystemInfo: () => buildSystemInfo,
26992
- bootstrap: () => bootstrap
27359
+ bootstrap: () => bootstrap,
27360
+ applyReasoningCliOverride: () => applyReasoningCliOverride
26993
27361
  });
26994
27362
  import { homedir as homedir15 } from "os";
26995
27363
  import { join as join46, resolve as resolve22 } from "path";
@@ -27154,11 +27522,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
27154
27522
  if (!probe)
27155
27523
  return null;
27156
27524
  if (probe.actual < config.contextWindow) {
27157
- logger4.warn(`Context probe: model "${probe.model}" is loaded with ${probe.actual} tokens, but contextWindow is configured as ${config.contextWindow} — overflow/429 risk. Lower contextWindow or reload the model with a larger context.`);
27525
+ logger4.logSilent("warn", `Context probe: model "${probe.model}" is loaded with ${probe.actual} tokens, but contextWindow is configured as ${config.contextWindow} — overflow/429 risk. Lower contextWindow or reload the model with a larger context.`);
27158
27526
  } else if (probe.actual > config.contextWindow) {
27159
- logger4.info(`Context probe: model "${probe.model}" supports ${probe.actual} tokens — consider "mma context ${probe.actual}" to use the full window.`);
27527
+ logger4.logSilent("info", `Context probe: model "${probe.model}" supports ${probe.actual} tokens — consider "mma context ${probe.actual}" to use the full window.`);
27160
27528
  } else {
27161
- logger4.debug(`Context probe: configured contextWindow matches loaded context (${probe.actual})`);
27529
+ logger4.logSilent("debug", `Context probe: configured contextWindow matches loaded context (${probe.actual})`);
27162
27530
  }
27163
27531
  return probe;
27164
27532
  } catch {
@@ -27183,7 +27551,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
27183
27551
  const passed = cached !== undefined ? cached : await probeReasoningSupport2(llmProvider, reasoningStrategy);
27184
27552
  if (cached === undefined && passed !== null)
27185
27553
  setCachedProbeResult2(cacheK, passed);
27186
- logger4.info(t("env.reasoning_probe", {
27554
+ logger4.logSilent("info", t("env.reasoning_probe", {
27187
27555
  strategy: reasoningStrategy,
27188
27556
  result: passed === true ? t("env.reasoning_respected") : t("env.reasoning_ignored")
27189
27557
  }));
@@ -27411,11 +27779,13 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
27411
27779
  const dry = dryRunOverflow([...promptBlocks, ...dynamicBlocks], systemBudget);
27412
27780
  if (dry.overflow.length > 0) {
27413
27781
  const overflowTokens = dry.overflow.reduce((s, b) => s + b.estimatedTokens, 0);
27414
- const hint = overflowHint(config, dir, dry.includedTokens + overflowTokens);
27782
+ const needed = dry.includedTokens + overflowTokens;
27783
+ const hint = overflowHint(config, dir, needed);
27415
27784
  for (const b of dry.overflow) {
27416
27785
  logger4.warn(t("prompt.overflow.startup", {
27417
27786
  block: b.kind === "instructions" ? "AGENTS.md" : "project map",
27418
27787
  original: String(b.estimatedTokens),
27788
+ needed: String(needed),
27419
27789
  budget: String(systemBudget),
27420
27790
  hint
27421
27791
  }));
@@ -27871,12 +28241,12 @@ function formatTable(tableLines, opts = {}) {
27871
28241
  const a = isHeader && align[c] === undefined ? "center" : align[c] ?? "left";
27872
28242
  cells.push(pad(cell, widths[c], a));
27873
28243
  }
27874
- const content = cells.map((c) => pc2.dim("│ ") + c).join("") + pc2.dim("│");
27875
- return isHeader ? pc2.bold(content) : content;
28244
+ const content = cells.map((c) => pc.dim("│ ") + c).join("") + pc.dim("│");
28245
+ return isHeader ? pc.bold(content) : content;
27876
28246
  };
27877
28247
  const border = (l, m, r) => {
27878
28248
  const seg = widths.map((w) => "─".repeat(w + 2)).join(m);
27879
- return pc2.dim(l + seg + r);
28249
+ return pc.dim(l + seg + r);
27880
28250
  };
27881
28251
  const out = [];
27882
28252
  out.push(border("┌", "┬", "┐"));
@@ -27925,12 +28295,14 @@ class Spinner {
27925
28295
  frame = 0;
27926
28296
  message = "";
27927
28297
  enabled;
28298
+ channel;
27928
28299
  stream;
27929
28300
  intervalMs;
27930
28301
  width;
27931
28302
  constructor(opts = {}) {
27932
- this.stream = opts.stream ?? process.stderr;
27933
- this.enabled = opts.enabled ?? isSpinnerSupported(this.stream);
28303
+ this.channel = opts.channel;
28304
+ this.stream = process.stderr;
28305
+ this.enabled = opts.enabled ?? isSpinnerSupported();
27934
28306
  this.intervalMs = opts.intervalMs ?? 80;
27935
28307
  this.width = opts.width ?? getTerminalWidth();
27936
28308
  }
@@ -27955,7 +28327,11 @@ class Spinner {
27955
28327
  if (this.timer) {
27956
28328
  clearInterval(this.timer);
27957
28329
  this.timer = null;
27958
- this.stream.write("\r\x1B[K");
28330
+ const clear = "\r\x1B[K";
28331
+ if (this.channel)
28332
+ this.channel.writeOverlay(clear);
28333
+ else
28334
+ this.stream.write(clear);
27959
28335
  }
27960
28336
  }
27961
28337
  truncate(text) {
@@ -27974,7 +28350,11 @@ class Spinner {
27974
28350
  return;
27975
28351
  const frame2 = FRAMES[this.frame % FRAMES.length];
27976
28352
  this.frame++;
27977
- this.stream.write("\r" + pc2.cyan(frame2) + " " + this.message + "\x1B[K");
28353
+ const text = "\r" + pc.cyan(frame2) + " " + this.message + "\x1B[K";
28354
+ if (this.channel)
28355
+ this.channel.writeOverlay(text);
28356
+ else
28357
+ this.stream.write(text);
27978
28358
  }
27979
28359
  }
27980
28360
  var FRAMES;
@@ -28041,19 +28421,19 @@ function box(lines, opts = {}) {
28041
28421
  const title = opts.title ?? "";
28042
28422
  if (title) {
28043
28423
  const head = `─ ${title} `;
28044
- out.push(pc2.dim(`┌${head}${"─".repeat(Math.max(0, width - 2 - stringWidth(head)))}┐`));
28424
+ out.push(pc.dim(`┌${head}${"─".repeat(Math.max(0, width - 2 - stringWidth(head)))}┐`));
28045
28425
  } else {
28046
- out.push(pc2.dim(`┌${"─".repeat(width - 2)}┐`));
28426
+ out.push(pc.dim(`┌${"─".repeat(width - 2)}┐`));
28047
28427
  }
28048
28428
  for (const line of wrapped) {
28049
- out.push(pc2.dim("│") + " ".repeat(pad2) + padTo(line, inner) + " ".repeat(pad2) + pc2.dim("│"));
28429
+ out.push(pc.dim("│") + " ".repeat(pad2) + padTo(line, inner) + " ".repeat(pad2) + pc.dim("│"));
28050
28430
  }
28051
- out.push(pc2.dim(`└${"─".repeat(width - 2)}┘`));
28431
+ out.push(pc.dim(`└${"─".repeat(width - 2)}┘`));
28052
28432
  return out;
28053
28433
  }
28054
28434
  function divider(width) {
28055
28435
  const w = Math.min(width ?? getTerminalWidth(), 60);
28056
- return pc2.dim("─".repeat(w));
28436
+ return pc.dim("─".repeat(w));
28057
28437
  }
28058
28438
  var init_box = __esm(() => {
28059
28439
  init_string_width();
@@ -28061,10 +28441,59 @@ var init_box = __esm(() => {
28061
28441
  init_table();
28062
28442
  });
28063
28443
 
28444
+ // src/cli/setup-prompt.ts
28445
+ class SetupPrompt {
28446
+ input;
28447
+ output;
28448
+ pending = null;
28449
+ buffer = "";
28450
+ closed = false;
28451
+ onData;
28452
+ constructor(input = process.stdin, output = process.stdout) {
28453
+ this.input = input;
28454
+ this.output = output;
28455
+ if (typeof this.input.setRawMode === "function")
28456
+ this.input.setRawMode(false);
28457
+ this.onData = (buf) => this.consume(buf.toString("utf-8"));
28458
+ this.input.on("data", this.onData);
28459
+ this.input.resume?.();
28460
+ }
28461
+ question(query, cb) {
28462
+ if (this.closed)
28463
+ return;
28464
+ this.buffer = "";
28465
+ this.pending = cb;
28466
+ this.output.write(query);
28467
+ }
28468
+ close() {
28469
+ if (this.closed)
28470
+ return;
28471
+ this.closed = true;
28472
+ this.pending = null;
28473
+ this.input.removeListener("data", this.onData);
28474
+ this.input.pause?.();
28475
+ }
28476
+ consume(text) {
28477
+ if (!this.pending || this.closed)
28478
+ return;
28479
+ this.buffer += text;
28480
+ const idx = this.buffer.search(/[\r\n]/);
28481
+ if (idx === -1)
28482
+ return;
28483
+ const answer = this.buffer.slice(0, idx);
28484
+ this.buffer = "";
28485
+ const cb = this.pending;
28486
+ this.pending = null;
28487
+ if (!this.output.isTTY)
28488
+ this.output.write(`
28489
+ `);
28490
+ cb(answer);
28491
+ }
28492
+ }
28493
+
28064
28494
  // src/cli/setup.ts
28065
- import * as readline from "readline";
28066
28495
  async function withSpinner(message, fn) {
28067
- const spinner = new Spinner;
28496
+ const spinner = new Spinner({ channel: getDefaultChannel() });
28068
28497
  spinner.start(message);
28069
28498
  try {
28070
28499
  return await fn();
@@ -28073,9 +28502,9 @@ async function withSpinner(message, fn) {
28073
28502
  }
28074
28503
  }
28075
28504
  function menuList(items) {
28076
- const lines = items.map((it, i) => ` ${pc2.cyan(`[${i + 1}]`)} ${it.label}${it.url ? ` ${pc2.dim(it.url)}` : ""}`);
28505
+ const lines = items.map((it, i) => ` ${pc.cyan(`[${i + 1}]`)} ${it.label}${it.url ? ` ${pc.dim(it.url)}` : ""}`);
28077
28506
  for (const l of box(lines, { width: 72 }))
28078
- console.log(l);
28507
+ getDefaultChannel().writeLine(l);
28079
28508
  }
28080
28509
  function ask(rl, question, defaultValue) {
28081
28510
  return new Promise((resolve23) => {
@@ -28085,6 +28514,12 @@ function ask(rl, question, defaultValue) {
28085
28514
  });
28086
28515
  });
28087
28516
  }
28517
+ function askInt(rl, question, defaultValue) {
28518
+ return ask(rl, question, String(defaultValue)).then((raw) => {
28519
+ const n = parseInt(raw, 10);
28520
+ return Number.isFinite(n) && n > 0 ? n : defaultValue;
28521
+ });
28522
+ }
28088
28523
  async function scanPorts() {
28089
28524
  const found = [];
28090
28525
  for (const { port, label } of KNOWN_PORTS) {
@@ -28154,16 +28589,17 @@ async function testChat(apiBase, apiKey, model) {
28154
28589
  }
28155
28590
  }
28156
28591
  async function runSetup(externalRl) {
28157
- console.log(t("setup.title"));
28158
- const rl = externalRl || readline.createInterface({
28159
- input: process.stdin,
28160
- output: process.stdout
28161
- });
28592
+ getDefaultChannel().writeLine(t("setup.title"));
28593
+ const rl = externalRl ?? new SetupPrompt;
28162
28594
  const ownRl = !externalRl;
28163
- console.log(t("setup.language"));
28164
- const locale = await ask(rl, t("setup.ui_lang"), "en");
28595
+ getDefaultChannel().writeLine(t("setup.language"));
28596
+ menuList(LANGUAGES);
28597
+ const languageChoice = await ask(rl, t("setup.select_language_num", { max: LANGUAGES.length }), "1");
28598
+ const typedLang = languageChoice.trim().toLowerCase();
28599
+ const byCode = LANGUAGES.find((l) => l.value === typedLang);
28600
+ const locale = byCode ? byCode.value : LANGUAGES[Math.max(0, Math.min(LANGUAGES.length - 1, (parseInt(languageChoice) || 1) - 1))].value;
28165
28601
  setLocale(locale);
28166
- console.log(t("setup.select_provider"));
28602
+ getDefaultChannel().writeLine(t("setup.select_provider"));
28167
28603
  menuList(PROVIDER_TYPES);
28168
28604
  const providerChoice = await ask(rl, t("setup.select_provider_num", { max: PROVIDER_TYPES.length }), "1");
28169
28605
  const providerIdx = Math.max(0, Math.min(PROVIDER_TYPES.length - 1, (parseInt(providerChoice) || 1) - 1));
@@ -28172,7 +28608,7 @@ async function runSetup(externalRl) {
28172
28608
  if (provider === "openai-compat") {
28173
28609
  const found = await withSpinner(t("setup.scanning_spinner"), async () => scanPorts());
28174
28610
  if (found.length > 0) {
28175
- console.log(t("setup.found_servers", { count: found.length }));
28611
+ getDefaultChannel().writeLine(t("setup.found_servers", { count: found.length }));
28176
28612
  menuList([
28177
28613
  ...found.map((f) => ({ label: f.label, url: f.url })),
28178
28614
  { label: t("setup.custom_url") }
@@ -28185,7 +28621,7 @@ async function runSetup(externalRl) {
28185
28621
  apiBase = found[Math.max(0, Math.min(found.length - 1, idx))].url;
28186
28622
  }
28187
28623
  } else {
28188
- console.log(t("setup.no_servers"));
28624
+ getDefaultChannel().writeLine(t("setup.no_servers"));
28189
28625
  apiBase = await ask(rl, t("setup.api_base"), "http://localhost:1234/v1");
28190
28626
  }
28191
28627
  } else {
@@ -28196,7 +28632,7 @@ async function runSetup(externalRl) {
28196
28632
  const models = await withSpinner(t("setup.fetching_spinner"), () => fetchModels(apiBase, apiKey));
28197
28633
  let model = "";
28198
28634
  if (models.length > 0) {
28199
- console.log(t("setup.available_models"));
28635
+ getDefaultChannel().writeLine(t("setup.available_models"));
28200
28636
  menuList(models.slice(0, 10).map((m) => ({ label: m })));
28201
28637
  const choice = await ask(rl, t("setup.select_model", { max: Math.min(models.length, 10) }), "1");
28202
28638
  const idx = Math.max(0, Math.min(models.length - 1, (parseInt(choice) || 1) - 1));
@@ -28206,15 +28642,15 @@ async function runSetup(externalRl) {
28206
28642
  }
28207
28643
  const connected = await withSpinner(t("setup.testing_spinner", { model }), () => testChat(apiBase, apiKey, model));
28208
28644
  if (connected) {
28209
- console.log(pc2.green(t("setup.ok")));
28645
+ getDefaultChannel().writeLine(pc.green(t("setup.ok")));
28210
28646
  } else {
28211
- console.log(pc2.yellow(t("setup.warning")));
28647
+ getDefaultChannel().writeLine(pc.yellow(t("setup.warning")));
28212
28648
  }
28213
- console.log(t("setup.agent_settings"));
28214
- const contextWindow = parseInt(await ask(rl, t("setup.context_window"), "32768"));
28215
- const maxIterations = parseInt(await ask(rl, t("setup.max_iters"), "1000"));
28216
- console.log(t("setup.security_header"));
28217
- console.log(pc2.dim(t("setup.security_status_on")));
28649
+ getDefaultChannel().writeLine(t("setup.agent_settings"));
28650
+ const contextWindow = await askInt(rl, t("setup.context_window"), 32768);
28651
+ const maxIterations = await askInt(rl, t("setup.max_iters"), 1000);
28652
+ getDefaultChannel().writeLine(t("setup.security_header"));
28653
+ getDefaultChannel().writeLine(pc.dim(t("setup.security_status_on")));
28218
28654
  const configureSecurity = await ask(rl, t("setup.security_configure"), "n");
28219
28655
  let securityBashBlock = false;
28220
28656
  let securityFlagsBlock = false;
@@ -28226,13 +28662,6 @@ async function runSetup(externalRl) {
28226
28662
  }
28227
28663
  if (ownRl) {
28228
28664
  rl.close();
28229
- process.stdin.removeAllListeners("data");
28230
- process.stdin.removeAllListeners("keypress");
28231
- if (typeof process.stdin.setRawMode === "function") {
28232
- process.stdin.setRawMode(false);
28233
- }
28234
- process.stdin.pause();
28235
- process.stdin.resume();
28236
28665
  }
28237
28666
  const answers = {
28238
28667
  provider,
@@ -28246,34 +28675,37 @@ async function runSetup(externalRl) {
28246
28675
  securityFlagsBlock,
28247
28676
  securityPathsDeny
28248
28677
  };
28249
- console.log(pc2.green(pc2.bold(t("setup.complete"))));
28250
- const summary = renderTable([
28251
- t("setup.summary_setting"),
28252
- t("setup.summary_value"),
28253
- t("setup.summary_setting"),
28254
- t("setup.summary_value")
28255
- ], [
28256
- [t("setup.provider_type"), provider, t("setup.model_name"), model],
28257
- ["API Base URL", apiBase, t("setup.context_window"), String(contextWindow)],
28258
- [t("setup.api_key"), apiKey || "not-needed", t("setup.max_iters"), String(maxIterations)],
28259
- [t("setup.ui_lang"), locale, "", ""]
28260
- ], { maxColumns: 4 });
28261
- for (const l of summary)
28262
- console.log(l);
28678
+ getDefaultChannel().writeLine(pc.green(pc.bold(t("setup.complete"))));
28679
+ const summary = [
28680
+ [t("setup.provider_type"), provider],
28681
+ [t("setup.model_name"), model],
28682
+ [t("setup.api_base"), apiBase],
28683
+ [t("setup.api_key"), apiKey || "not-needed"],
28684
+ [t("setup.context_window"), String(contextWindow)],
28685
+ [t("setup.max_iters"), String(maxIterations)],
28686
+ [t("setup.ui_lang"), locale]
28687
+ ];
28688
+ for (const [label, value] of summary) {
28689
+ getDefaultChannel().writeLine(` ${pc.yellow(label.trim())}: ${pc.white(value)}`);
28690
+ }
28263
28691
  return answers;
28264
28692
  }
28265
- var PROVIDER_TYPES, KNOWN_PORTS;
28693
+ var PROVIDER_TYPES, LANGUAGES, KNOWN_PORTS;
28266
28694
  var init_setup = __esm(() => {
28267
28695
  init_colors();
28268
28696
  init_i18n();
28269
28697
  init_spinner();
28270
28698
  init_presets();
28271
28699
  init_box();
28272
- init_table();
28700
+ init_output();
28273
28701
  PROVIDER_TYPES = BUILTIN_PROVIDERS.map((spec) => ({
28274
28702
  value: spec.type,
28275
28703
  label: spec.label
28276
28704
  }));
28705
+ LANGUAGES = [
28706
+ { value: "en", label: "English" },
28707
+ { value: "ru", label: "Русский" }
28708
+ ];
28277
28709
  KNOWN_PORTS = [
28278
28710
  { port: 1234, label: "LM Studio" },
28279
28711
  { port: 11434, label: "Ollama" },
@@ -36368,35 +36800,35 @@ async function certify(opts) {
36368
36800
  const providerUrl = opts.providerUrl || opts.config.provider.baseUrl;
36369
36801
  const { scenarios, errors: errors2 } = loadScenarios(join52(opts.projectDir, ".mma", "certification", "scenarios"));
36370
36802
  for (const e of errors2)
36371
- console.error(pc2.yellow(` ${e}`));
36803
+ getDefaultChannel().writeLine(pc.yellow(` ${e}`), "stderr");
36372
36804
  let selected = filterByTags(scenarios, opts.tags);
36373
36805
  const isPartial = Array.isArray(opts.scenarios) && opts.scenarios.length > 0;
36374
36806
  if (isPartial) {
36375
36807
  const unknown = unknownScenarioIds(scenarios, opts.scenarios);
36376
36808
  if (unknown.length > 0) {
36377
- console.error(pc2.red(t("cli.cert_scenarios_unknown", {
36809
+ getDefaultChannel().writeLine(pc.red(t("cli.cert_scenarios_unknown", {
36378
36810
  ids: unknown.join(", "),
36379
36811
  available: scenarios.map((s) => s.id).join(", ")
36380
- })));
36812
+ })), "stderr");
36381
36813
  process.exitCode = 1;
36382
36814
  return;
36383
36815
  }
36384
36816
  selected = filterByScenarios(scenarios, opts.scenarios);
36385
36817
  }
36386
36818
  if (selected.length === 0) {
36387
- console.error(pc2.red(t("cli.cert_no_scenarios", { tags: opts.tags.join(",") })));
36819
+ getDefaultChannel().writeLine(pc.red(t("cli.cert_no_scenarios", { tags: opts.tags.join(",") })), "stderr");
36388
36820
  process.exitCode = 1;
36389
36821
  return;
36390
36822
  }
36391
36823
  const manifest = readMergedManifest(opts.projectDir);
36392
36824
  const existing = manifest.certifications.find((e) => e.model === opts.name && e.providerUrl === providerUrl);
36393
36825
  if (existing && !opts.force && !isPartial) {
36394
- console.error(pc2.yellow(t("cli.cert_exists", { model: opts.name })));
36395
- console.error(pc2.yellow(t("cli.cert_exists_hint")));
36826
+ getDefaultChannel().writeLine(pc.yellow(t("cli.cert_exists", { model: opts.name })), "stderr");
36827
+ getDefaultChannel().writeLine(pc.yellow(t("cli.cert_exists_hint")), "stderr");
36396
36828
  process.exitCode = 1;
36397
36829
  return;
36398
36830
  }
36399
- console.log(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
36831
+ getDefaultChannel().writeLine(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
36400
36832
  const sandboxBase = join52(process.cwd(), ".mma", "certification");
36401
36833
  const results = [];
36402
36834
  const total = selected.length;
@@ -36404,7 +36836,7 @@ async function certify(opts) {
36404
36836
  for (const scenario of selected) {
36405
36837
  idx++;
36406
36838
  if (scenario.mode === "skip") {
36407
- console.log(pc2.dim(`[${idx}/${total}] ${scenario.id} ... skipped`));
36839
+ getDefaultChannel().writeLine(pc.dim(`[${idx}/${total}] ${scenario.id} ... skipped`));
36408
36840
  results.push({
36409
36841
  id: scenario.id,
36410
36842
  title: scenario.title,
@@ -36426,10 +36858,10 @@ async function certify(opts) {
36426
36858
  timeoutMs: opts.timeout,
36427
36859
  baseConfig: opts.config,
36428
36860
  onRep: (id, rep, reps, passed, failures) => {
36429
- const word = passed ? pc2.green(t("cli.cert_rep_pass")) : pc2.red(t("cli.cert_rep_fail"));
36430
- console.log(`[${idx}/${total}] ${id} (${rep}/${reps})... ${word}`);
36861
+ const word = passed ? pc.green(t("cli.cert_rep_pass")) : pc.red(t("cli.cert_rep_fail"));
36862
+ getDefaultChannel().writeLine(`[${idx}/${total}] ${id} (${rep}/${reps})... ${word}`);
36431
36863
  if (!passed)
36432
- console.log(` ${pc2.dim(failures.join("; "))}`);
36864
+ getDefaultChannel().writeLine(` ${pc.dim(failures.join("; "))}`);
36433
36865
  }
36434
36866
  });
36435
36867
  results.push(res);
@@ -36452,7 +36884,7 @@ async function certify(opts) {
36452
36884
  results: finalResults
36453
36885
  };
36454
36886
  upsertCertification(entry);
36455
- console.log(t("cli.cert_done", {
36887
+ getDefaultChannel().writeLine(t("cli.cert_done", {
36456
36888
  passed: String(suite.passed),
36457
36889
  failed: String(suite.failed),
36458
36890
  skipped: String(suite.skipped),
@@ -36460,10 +36892,10 @@ async function certify(opts) {
36460
36892
  }));
36461
36893
  printResults(finalResults);
36462
36894
  if (isFullyPassed(entry)) {
36463
- console.log(pc2.green(`
36895
+ getDefaultChannel().writeLine(pc.green(`
36464
36896
  ✔ ${opts.name} is certified`));
36465
36897
  } else {
36466
- console.log(pc2.yellow(`
36898
+ getDefaultChannel().writeLine(pc.yellow(`
36467
36899
  ⚠ ${opts.name} is NOT certified — all scenarios must pass`));
36468
36900
  }
36469
36901
  writeReport(entry, opts.projectDir);
@@ -36473,25 +36905,25 @@ async function certStatus(name, config, projectDir) {
36473
36905
  const providerUrl = config.provider.baseUrl;
36474
36906
  const entry = m.certifications.find((e) => e.model === name && e.providerUrl === providerUrl);
36475
36907
  if (!entry) {
36476
- console.log(t("cli.cert_not_found", { model: name }));
36908
+ getDefaultChannel().writeLine(t("cli.cert_not_found", { model: name }));
36477
36909
  return;
36478
36910
  }
36479
- console.log(`${t("cli.cert_provider_col")}: ${entry.providerUrl}`);
36480
- console.log(`${t("cli.cert_version_col")}: ${entry.mmaVersion} ${t("cli.cert_date_col")}: ${entry.certifiedAt.slice(0, 10)}`);
36481
- console.log(`${t("cli.cert_suite_col")}: ${entry.suite.passed} pass / ${entry.suite.failed} fail / ${entry.suite.skipped} skipped`);
36482
- const status = isFullyPassed(entry) ? pc2.green("✔ certified") : pc2.yellow("⚠ NOT certified");
36483
- console.log(`Status: ${status}`);
36911
+ getDefaultChannel().writeLine(`${t("cli.cert_provider_col")}: ${entry.providerUrl}`);
36912
+ getDefaultChannel().writeLine(`${t("cli.cert_version_col")}: ${entry.mmaVersion} ${t("cli.cert_date_col")}: ${entry.certifiedAt.slice(0, 10)}`);
36913
+ getDefaultChannel().writeLine(`${t("cli.cert_suite_col")}: ${entry.suite.passed} pass / ${entry.suite.failed} fail / ${entry.suite.skipped} skipped`);
36914
+ const status = isFullyPassed(entry) ? pc.green("✔ certified") : pc.yellow("⚠ NOT certified");
36915
+ getDefaultChannel().writeLine(`Status: ${status}`);
36484
36916
  printResults(entry.results);
36485
36917
  }
36486
36918
  async function certList(projectDir) {
36487
36919
  const m = readMergedManifest(projectDir);
36488
36920
  if (m.certifications.length === 0) {
36489
- console.log(t("cli.cert_empty"));
36921
+ getDefaultChannel().writeLine(t("cli.cert_empty"));
36490
36922
  return;
36491
36923
  }
36492
36924
  for (const e of m.certifications) {
36493
- const mark = isFullyPassed(e) ? pc2.green("✔") : pc2.red("✘");
36494
- console.log(` ${mark} ${e.model} ${pc2.dim(e.providerUrl)} ${e.mmaVersion} ${e.certifiedAt.slice(0, 10)} ${e.suite.passed}/${e.suite.total} pass`);
36925
+ const mark = isFullyPassed(e) ? pc.green("✔") : pc.red("✘");
36926
+ getDefaultChannel().writeLine(` ${mark} ${e.model} ${pc.dim(e.providerUrl)} ${e.mmaVersion} ${e.certifiedAt.slice(0, 10)} ${e.suite.passed}/${e.suite.total} pass`);
36495
36927
  }
36496
36928
  }
36497
36929
  async function uncertify(name, config, projectDir) {
@@ -36499,9 +36931,9 @@ async function uncertify(name, config, projectDir) {
36499
36931
  projectDir
36500
36932
  });
36501
36933
  if (removed.global || removed.project)
36502
- console.log(t("cli.cert_uncertified", { model: name }));
36934
+ getDefaultChannel().writeLine(t("cli.cert_uncertified", { model: name }));
36503
36935
  else
36504
- console.log(t("cli.cert_not_found", { model: name }));
36936
+ getDefaultChannel().writeLine(t("cli.cert_not_found", { model: name }));
36505
36937
  }
36506
36938
  function summarize(results) {
36507
36939
  return {
@@ -36514,19 +36946,19 @@ function summarize(results) {
36514
36946
  function mergePartialResults(fresh, previous, rerunIds) {
36515
36947
  const preserved = previous.filter((r) => !rerunIds.has(r.id));
36516
36948
  if (preserved.length > 0) {
36517
- console.log(pc2.dim(t("cli.cert_partial_merge", { kept: String(preserved.length) })));
36949
+ getDefaultChannel().writeLine(pc.dim(t("cli.cert_partial_merge", { kept: String(preserved.length) })));
36518
36950
  }
36519
36951
  return [...fresh, ...preserved];
36520
36952
  }
36521
36953
  function printResults(results) {
36522
36954
  for (const r of results) {
36523
- const icon = r.status === "pass" ? pc2.green("✔") : r.status === "fail" ? pc2.red("✘") : r.status === "skipped" ? pc2.dim("–") : pc2.yellow("!");
36524
- const detail = r.status === "skipped" ? pc2.dim(r.title) : `${r.passed}/${r.of}`;
36525
- console.log(` ${icon} ${r.id} ${detail}`);
36955
+ const icon = r.status === "pass" ? pc.green("✔") : r.status === "fail" ? pc.red("✘") : r.status === "skipped" ? pc.dim("–") : pc.yellow("!");
36956
+ const detail = r.status === "skipped" ? pc.dim(r.title) : `${r.passed}/${r.of}`;
36957
+ getDefaultChannel().writeLine(` ${icon} ${r.id} ${detail}`);
36526
36958
  if (r.error)
36527
- console.log(` ${pc2.dim(r.error)}`);
36959
+ getDefaultChannel().writeLine(` ${pc.dim(r.error)}`);
36528
36960
  if (r.diagnostics)
36529
- console.log(r.diagnostics);
36961
+ getDefaultChannel().writeLine(r.diagnostics);
36530
36962
  }
36531
36963
  }
36532
36964
  function writeReport(entry, projectDir) {
@@ -36553,10 +36985,10 @@ function writeReport(entry, projectDir) {
36553
36985
  };
36554
36986
  try {
36555
36987
  writeFileSync23(reportPath, JSON.stringify(report, null, 2), "utf-8");
36556
- console.log(pc2.dim(`
36988
+ getDefaultChannel().writeLine(pc.dim(`
36557
36989
  Report: ${reportPath}`));
36558
36990
  } catch (e) {
36559
- console.error(pc2.yellow(` Failed to write report: ${e.message}`));
36991
+ getDefaultChannel().writeLine(pc.yellow(` Failed to write report: ${e.message}`), "stderr");
36560
36992
  }
36561
36993
  }
36562
36994
  var HERE, MMA_ROOT;
@@ -36566,6 +36998,7 @@ var init_cli = __esm(() => {
36566
36998
  init_loader3();
36567
36999
  init_runner2();
36568
37000
  init_manifest();
37001
+ init_output();
36569
37002
  HERE = dirname22(fileURLToPath5(import.meta.url));
36570
37003
  MMA_ROOT = findMmaRoot(HERE);
36571
37004
  });
@@ -36603,7 +37036,7 @@ function registerBuiltinCommands(ctx) {
36603
37036
  description: t("repl.clear"),
36604
37037
  usage: t("repl.clear_usage"),
36605
37038
  action: () => {
36606
- console.clear();
37039
+ ctx.output.clearScreen();
36607
37040
  }
36608
37041
  });
36609
37042
  }
@@ -36614,7 +37047,7 @@ function registerRunCommands(ctx) {
36614
37047
  usage: t("repl.run_usage"),
36615
37048
  action: async (args) => {
36616
37049
  if (args.length === 0) {
36617
- console.log(t("repl.run_usage"));
37050
+ ctx.output.writeLine(t("repl.run_usage"));
36618
37051
  return;
36619
37052
  }
36620
37053
  const prompt = args.join(" ");
@@ -36629,7 +37062,7 @@ function registerRunCommands(ctx) {
36629
37062
  action: async (args) => {
36630
37063
  const source = args.join(" ");
36631
37064
  if (!source) {
36632
- console.log(t("repl.image_usage"));
37065
+ ctx.output.writeLine(t("repl.image_usage"));
36633
37066
  return;
36634
37067
  }
36635
37068
  try {
@@ -36641,7 +37074,7 @@ function registerRunCommands(ctx) {
36641
37074
  if (source.toLowerCase() === "clipboard") {
36642
37075
  const clipBuf = await readClipboardImage2();
36643
37076
  if (!clipBuf) {
36644
- console.log(pc2.yellow(t("image.clipboard_empty")));
37077
+ ctx.output.writeLine(pc.yellow(t("image.clipboard_empty")));
36645
37078
  return;
36646
37079
  }
36647
37080
  const { bufferToDataUrl: bufferToDataUrl2 } = await Promise.resolve().then(() => (init_image_utils(), exports_image_utils));
@@ -36655,7 +37088,7 @@ function registerRunCommands(ctx) {
36655
37088
  } else {
36656
37089
  const absPath = resolve24(process.cwd(), source);
36657
37090
  if (!existsSync60(absPath)) {
36658
- console.log(pc2.red(t("image.not_found", { path: source })));
37091
+ ctx.output.writeLine(pc.red(t("image.not_found", { path: source })), "stderr");
36659
37092
  return;
36660
37093
  }
36661
37094
  const result = await loadFileAsDataUrl2(absPath);
@@ -36664,7 +37097,7 @@ function registerRunCommands(ctx) {
36664
37097
  }
36665
37098
  const contextManager = ctx.agent.contextManager;
36666
37099
  if (!contextManager) {
36667
- console.log(pc2.red(t("image.no_context")));
37100
+ ctx.output.writeLine(pc.red(t("image.no_context")), "stderr");
36668
37101
  return;
36669
37102
  }
36670
37103
  contextManager.addPendingImage({
@@ -36672,9 +37105,9 @@ function registerRunCommands(ctx) {
36672
37105
  image_url: { url: dataUrl }
36673
37106
  });
36674
37107
  const sizeKb = Math.round(dataUrl.length * 3 / 4 / 1024);
36675
- console.log(pc2.green(t("image.attached", { source: label, size: `${sizeKb} KB` })));
37108
+ ctx.output.writeLine(pc.green(t("image.attached", { source: label, size: `${sizeKb} KB` })));
36676
37109
  } catch (err) {
36677
- console.log(pc2.red(t("image.error", { message: err.message })));
37110
+ ctx.output.writeLine(pc.red(t("image.error", { message: err.message })), "stderr");
36678
37111
  }
36679
37112
  }
36680
37113
  });
@@ -36692,23 +37125,23 @@ function registerConfigCommands(ctx) {
36692
37125
  const ctxW = cfg.contextWindow;
36693
37126
  const sys = Math.floor(ctxW * cfg.contextBudget.systemPrompt);
36694
37127
  const res = Math.floor(ctxW * cfg.contextBudget.responseReserve);
36695
- console.log(`${t("repl.model")} ${cfg.model}`);
37128
+ ctx.output.writeLine(`${t("repl.model")} ${cfg.model}`);
36696
37129
  const providers = ctx.agent.listProviders();
36697
37130
  const active = providers.find((p) => p.active);
36698
37131
  if (active) {
36699
- console.log(`${t("repl.provider")} ${active.label} (${pc2.dim(active.type)}) → ${pc2.dim(active.baseUrl)}`);
37132
+ ctx.output.writeLine(`${t("repl.provider")} ${active.label} (${pc.dim(active.type)}) → ${pc.dim(active.baseUrl)}`);
36700
37133
  } else {
36701
- console.log(`${t("repl.provider")} ${cfg.provider.type} → ${cfg.provider.baseUrl}`);
36702
- }
36703
- console.log(`${t("repl.context")} ${ctxW} (sys:${sys} res:${res} hist:${ctxW - sys - res})`);
36704
- console.log(`${t("repl.max_iters")} ${cfg.maxToolIterations}`);
36705
- console.log(`${t("repl.stuck_thresh")} ${cfg.stuckThreshold}`);
36706
- console.log(`${t("repl.reasoning_label")} ${cfg.showReasoning ? pc2.green(t("repl.show")) : pc2.dim(t("repl.hide"))}`);
36707
- console.log(`${t("repl.log_level")} ${cfg.logLevel}`);
36708
- console.log(`${t("repl.locale")} ${cfg.locale}`);
37134
+ ctx.output.writeLine(`${t("repl.provider")} ${cfg.provider.type} → ${cfg.provider.baseUrl}`);
37135
+ }
37136
+ ctx.output.writeLine(`${t("repl.context")} ${ctxW} (sys:${sys} res:${res} hist:${ctxW - sys - res})`);
37137
+ ctx.output.writeLine(`${t("repl.max_iters")} ${cfg.maxToolIterations}`);
37138
+ ctx.output.writeLine(`${t("repl.stuck_thresh")} ${cfg.stuckThreshold}`);
37139
+ ctx.output.writeLine(`${t("repl.reasoning_label")} ${cfg.showReasoning ? pc.green(t("repl.show")) : pc.dim(t("repl.hide"))}`);
37140
+ ctx.output.writeLine(`${t("repl.log_level")} ${cfg.logLevel}`);
37141
+ ctx.output.writeLine(`${t("repl.locale")} ${cfg.locale}`);
36709
37142
  const meta = ctx.sessionManager?.getActiveMeta();
36710
37143
  if (meta) {
36711
- console.log(`${t("repl.session_label")} ${meta.name} (${meta.id}) — ${meta.messageCount} msgs`);
37144
+ ctx.output.writeLine(`${t("repl.session_label")} ${meta.name} (${meta.id}) — ${meta.messageCount} msgs`);
36712
37145
  }
36713
37146
  }
36714
37147
  });
@@ -36721,13 +37154,13 @@ function registerConfigCommands(ctx) {
36721
37154
  const VALID_LEVELS2 = ["auto", "none", "low", "medium", "high", "max"];
36722
37155
  if (!level) {
36723
37156
  ctx.config.showReasoning = !ctx.config.showReasoning;
36724
- const status = ctx.config.showReasoning ? pc2.green(t("repl.show")) : pc2.dim(t("repl.hide"));
36725
- console.log(t("repl.reasoning_status", { status }));
37157
+ const status = ctx.config.showReasoning ? pc.green(t("repl.show")) : pc.dim(t("repl.hide"));
37158
+ ctx.output.writeLine(t("repl.reasoning_status", { status }));
36726
37159
  } else if (VALID_LEVELS2.includes(level)) {
36727
37160
  ctx.agent.setReasoningLevel(level);
36728
- console.log(pc2.green(t("repl.reasoning_level_set", { level })));
37161
+ ctx.output.writeLine(pc.green(t("repl.reasoning_level_set", { level })));
36729
37162
  } else {
36730
- console.log(pc2.yellow(t("repl.reasoning_invalid_level", { level, valid: VALID_LEVELS2.join(", ") })));
37163
+ ctx.output.writeLine(pc.yellow(t("repl.reasoning_invalid_level", { level, valid: VALID_LEVELS2.join(", ") })));
36731
37164
  }
36732
37165
  }
36733
37166
  });
@@ -36738,15 +37171,15 @@ function registerConfigCommands(ctx) {
36738
37171
  action: () => {
36739
37172
  const providers = ctx.agent.listProviders();
36740
37173
  const active = providers.find((p) => p.active);
36741
- console.log(`${t("repl.model")} ${ctx.config.model}`);
37174
+ ctx.output.writeLine(`${t("repl.model")} ${ctx.config.model}`);
36742
37175
  if (active) {
36743
- console.log(`${t("repl.provider")} ${active.label} (${pc2.dim(active.type)}) @ ${pc2.dim(active.baseUrl)}`);
37176
+ ctx.output.writeLine(`${t("repl.provider")} ${active.label} (${pc.dim(active.type)}) @ ${pc.dim(active.baseUrl)}`);
36744
37177
  } else {
36745
- console.log(`${t("repl.provider")} ${ctx.config.provider.type} @ ${ctx.config.provider.baseUrl}`);
37178
+ ctx.output.writeLine(`${t("repl.provider")} ${ctx.config.provider.type} @ ${ctx.config.provider.baseUrl}`);
36746
37179
  }
36747
37180
  const meta = ctx.sessionManager?.getActiveMeta();
36748
37181
  if (meta) {
36749
- console.log(`${t("repl.session_label")} ${meta.name} (${meta.id}) — ${meta.messageCount} messages`);
37182
+ ctx.output.writeLine(`${t("repl.session_label")} ${meta.name} (${meta.id}) — ${meta.messageCount} messages`);
36750
37183
  }
36751
37184
  }
36752
37185
  });
@@ -36756,7 +37189,7 @@ function registerConfigCommands(ctx) {
36756
37189
  aliases: ["setup"],
36757
37190
  usage: t("repl.wizard_usage"),
36758
37191
  action: async () => {
36759
- console.log(pc2.yellow(t("repl.wizard_running")));
37192
+ ctx.output.writeLine(pc.yellow(t("repl.wizard_running")));
36760
37193
  await ctx.withExclusiveInput(async () => {
36761
37194
  const answers = await runSetup(ctx.rl);
36762
37195
  const configPath = join54(ctx.configDir, "config.json");
@@ -36769,7 +37202,7 @@ function registerConfigCommands(ctx) {
36769
37202
  ctx.config.locale = answers.locale;
36770
37203
  saveConfig(ctx.config, configPath, dirname24(configPath));
36771
37204
  await ctx.agent.reconfigure(ctx.config);
36772
- console.log(pc2.green(t("cli.config_saved")));
37205
+ ctx.output.writeLine(pc.green(t("cli.config_saved")));
36773
37206
  });
36774
37207
  }
36775
37208
  });
@@ -36779,17 +37212,17 @@ function registerConfigCommands(ctx) {
36779
37212
  usage: t("repl.sysprompt_desc"),
36780
37213
  action: () => {
36781
37214
  const info = ctx.agent.getSystemPromptInfo();
36782
- console.log(pc2.bold(t("repl.sysprompt_tokens", { count: String(info.tokenCount) })));
36783
- console.log(pc2.dim("─".repeat(60)));
37215
+ ctx.output.writeLine(pc.bold(t("repl.sysprompt_tokens", { count: String(info.tokenCount) })));
37216
+ ctx.output.writeLine(pc.dim("─".repeat(60)));
36784
37217
  for (const line of info.text.split(`
36785
37218
  `)) {
36786
- console.log(line);
37219
+ ctx.output.writeLine(line);
36787
37220
  }
36788
- console.log(pc2.dim("─".repeat(60)));
37221
+ ctx.output.writeLine(pc.dim("─".repeat(60)));
36789
37222
  if (info.excluded.length > 0) {
36790
- console.log(pc2.yellow(t("repl.excluded_blocks", { count: String(info.excluded.length) })));
37223
+ ctx.output.writeLine(pc.yellow(t("repl.excluded_blocks", { count: String(info.excluded.length) })));
36791
37224
  for (const e of info.excluded) {
36792
- console.log(pc2.dim(` - ${e.slice(0, 80)}${e.length > 80 ? "..." : ""}`));
37225
+ ctx.output.writeLine(pc.dim(` - ${e.slice(0, 80)}${e.length > 80 ? "..." : ""}`));
36793
37226
  }
36794
37227
  }
36795
37228
  }
@@ -36801,13 +37234,13 @@ function registerConfigCommands(ctx) {
36801
37234
  action: async (args) => {
36802
37235
  const indexer = ctx.agent.getModule("indexer");
36803
37236
  if (!indexer) {
36804
- console.log(pc2.yellow(t("indexer.not_indexed")));
37237
+ ctx.output.writeLine(pc.yellow(t("indexer.not_indexed")));
36805
37238
  return;
36806
37239
  }
36807
37240
  const action = args[0] || "summary";
36808
37241
  const query = args.slice(1).join(" ");
36809
37242
  const result = await runMapAction(indexer, action, query);
36810
- console.log(result.output);
37243
+ ctx.output.writeLine(result.output);
36811
37244
  }
36812
37245
  });
36813
37246
  }
@@ -36815,28 +37248,28 @@ function registerProviderCommands(ctx) {
36815
37248
  const list = () => {
36816
37249
  const providers = ctx.agent.listProviders();
36817
37250
  if (providers.length === 0) {
36818
- console.log(`${t("repl.provider_current")} ${ctx.config.provider.type}`);
36819
- console.log(` ${ctx.config.provider.baseUrl}`);
37251
+ ctx.output.writeLine(`${t("repl.provider_current")} ${ctx.config.provider.type}`);
37252
+ ctx.output.writeLine(` ${ctx.config.provider.baseUrl}`);
36820
37253
  return;
36821
37254
  }
36822
- console.log(t("repl.provider_current"));
37255
+ ctx.output.writeLine(t("repl.provider_current"));
36823
37256
  for (const p of providers) {
36824
- const marker = p.active ? pc2.green("* ") : " ";
36825
- console.log(` ${marker}${p.label} (${pc2.dim(p.type)}) ${pc2.dim(p.baseUrl)}`);
37257
+ const marker = p.active ? pc.green("* ") : " ";
37258
+ ctx.output.writeLine(` ${marker}${p.label} (${pc.dim(p.type)}) ${pc.dim(p.baseUrl)}`);
36826
37259
  }
36827
37260
  };
36828
37261
  const use = async (args) => {
36829
37262
  const name = args[0];
36830
37263
  if (!name) {
36831
- console.log(t("repl.provider_usage"));
37264
+ ctx.output.writeLine(t("repl.provider_usage"));
36832
37265
  return;
36833
37266
  }
36834
37267
  try {
36835
37268
  await ctx.agent.setProvider(name);
36836
37269
  ctx.refreshModelCache();
36837
- console.log(pc2.green(t("repl.provider_set", { name })));
37270
+ ctx.output.writeLine(pc.green(t("repl.provider_set", { name })));
36838
37271
  } catch (e) {
36839
- console.log(pc2.red(e.message));
37272
+ ctx.output.writeLine(pc.red(e.message), "stderr");
36840
37273
  }
36841
37274
  };
36842
37275
  const add = async (args) => {
@@ -36847,7 +37280,7 @@ function registerProviderCommands(ctx) {
36847
37280
  if (arg.startsWith("--")) {
36848
37281
  const value = args[i + 1];
36849
37282
  if (value === undefined || value.startsWith("--")) {
36850
- console.log(pc2.red(t("repl.provider_add_missing_value", { flag: arg })));
37283
+ ctx.output.writeLine(pc.red(t("repl.provider_add_missing_value", { flag: arg })), "stderr");
36851
37284
  return;
36852
37285
  }
36853
37286
  flags[arg.slice(2)] = value;
@@ -36857,7 +37290,7 @@ function registerProviderCommands(ctx) {
36857
37290
  }
36858
37291
  }
36859
37292
  if (!name) {
36860
- console.log(t("repl.provider_usage"));
37293
+ ctx.output.writeLine(t("repl.provider_usage"));
36861
37294
  return;
36862
37295
  }
36863
37296
  const entries = Array.isArray(ctx.config.provider.entries) ? ctx.config.provider.entries : [];
@@ -36871,7 +37304,7 @@ function registerProviderCommands(ctx) {
36871
37304
  }
36872
37305
  const baseUrl = flags.url || HOSTED_BASE_URLS[name] || HOSTED_BASE_URLS[`opencode-${name}`] || "";
36873
37306
  if (!baseUrl) {
36874
- console.log(pc2.red(t("cli.provider_no_url", { name })));
37307
+ ctx.output.writeLine(pc.red(t("cli.provider_no_url", { name })), "stderr");
36875
37308
  return;
36876
37309
  }
36877
37310
  entries.push({
@@ -36893,8 +37326,8 @@ function registerProviderCommands(ctx) {
36893
37326
  const configPath = join54(ctx.configDir, "config.json");
36894
37327
  saveConfig(ctx.config, configPath, dirname24(configPath));
36895
37328
  await ctx.agent.reconfigure(ctx.config);
36896
- console.log(pc2.green(t("cli.provider_added", { name })));
36897
- console.log(t("repl.provider_switch_hint", { name }));
37329
+ ctx.output.writeLine(pc.green(t("cli.provider_added", { name })));
37330
+ ctx.output.writeLine(t("repl.provider_switch_hint", { name }));
36898
37331
  };
36899
37332
  const handlers = {
36900
37333
  list,
@@ -36909,14 +37342,14 @@ function registerProviderCommands(ctx) {
36909
37342
  const subcmd = args[0];
36910
37343
  const handler = subcmd ? handlers[subcmd] : handlers.list;
36911
37344
  if (!handler) {
36912
- console.log(t("repl.provider_usage"));
37345
+ ctx.output.writeLine(t("repl.provider_usage"));
36913
37346
  return;
36914
37347
  }
36915
37348
  await handler(args.slice(1));
36916
37349
  }
36917
37350
  });
36918
37351
  const listModels = async () => {
36919
- console.log(`${t("repl.model_current")} ${ctx.config.model}`);
37352
+ ctx.output.writeLine(`${t("repl.model_current")} ${ctx.config.model}`);
36920
37353
  const { OpenAICompatProvider: OpenAICompatProvider2 } = await Promise.resolve().then(() => (init_openai_compat(), exports_openai_compat));
36921
37354
  const provider = new OpenAICompatProvider2({
36922
37355
  model: ctx.config.model,
@@ -36925,42 +37358,42 @@ function registerProviderCommands(ctx) {
36925
37358
  contextWindow: ctx.config.contextWindow
36926
37359
  });
36927
37360
  const { Spinner: Spinner2 } = await Promise.resolve().then(() => (init_spinner(), exports_spinner));
36928
- const s = new Spinner2;
37361
+ const s = new Spinner2({ channel: ctx.output });
36929
37362
  s.start(t("cli.fetching_models"));
36930
37363
  try {
36931
37364
  const models = await provider.listModels();
36932
37365
  s.stop();
36933
37366
  if (models.length > 0) {
36934
37367
  ctx.refreshModelCache();
36935
- console.log(t("cli.available_models"));
37368
+ ctx.output.writeLine(t("cli.available_models"));
36936
37369
  const { getCertMark: getCertMark2 } = await Promise.resolve().then(() => (init_manifest(), exports_manifest));
36937
37370
  for (const m of models) {
36938
- const marker = m === ctx.config.model ? pc2.green("* ") : " ";
37371
+ const marker = m === ctx.config.model ? pc.green("* ") : " ";
36939
37372
  const mark = getCertMark2(m, ctx.config.provider.baseUrl, version2, process.cwd());
36940
- const cert = mark === "certified" ? pc2.green("✔") : mark === "stale" ? pc2.yellow("○") : pc2.dim("·");
36941
- const label = mark === "certified" ? ` ${pc2.green(t("cli.cert_label"))}` : mark === "stale" ? ` ${pc2.yellow(t("cli.cert_stale_label"))}` : "";
36942
- console.log(` ${marker}${cert} ${m}${label}`);
37373
+ const cert = mark === "certified" ? pc.green("✔") : mark === "stale" ? pc.yellow("○") : pc.dim("·");
37374
+ const label = mark === "certified" ? ` ${pc.green(t("cli.cert_label"))}` : mark === "stale" ? ` ${pc.yellow(t("cli.cert_stale_label"))}` : "";
37375
+ ctx.output.writeLine(` ${marker}${cert} ${m}${label}`);
36943
37376
  }
36944
37377
  } else {
36945
- console.log(t("cli.no_models_found"));
37378
+ ctx.output.writeLine(t("cli.no_models_found"));
36946
37379
  }
36947
37380
  } catch (err) {
36948
37381
  s.stop();
36949
- console.log(t("cli.model_fetch_failed", { error: String(err) }));
37382
+ ctx.output.writeLine(t("cli.model_fetch_failed", { error: String(err) }), "stderr");
36950
37383
  }
36951
- console.log(t("cli.model_hint"));
37384
+ ctx.output.writeLine(t("cli.model_hint"));
36952
37385
  };
36953
37386
  const useModel = async (args) => {
36954
37387
  const name = args[0];
36955
37388
  if (!name) {
36956
- console.log(t("repl.model_usage"));
37389
+ ctx.output.writeLine(t("repl.model_usage"));
36957
37390
  return;
36958
37391
  }
36959
37392
  ctx.config.model = name;
36960
37393
  const configPath = join54(ctx.configDir, "config.json");
36961
37394
  saveConfig(ctx.config, configPath, dirname24(configPath));
36962
37395
  await ctx.agent.reconfigure(ctx.config);
36963
- console.log(pc2.green(t("repl.model_set", { name })));
37396
+ ctx.output.writeLine(pc.green(t("repl.model_set", { name })));
36964
37397
  };
36965
37398
  const modelHandlers = {
36966
37399
  list: listModels,
@@ -36974,7 +37407,7 @@ function registerProviderCommands(ctx) {
36974
37407
  const subcmd = args[0];
36975
37408
  const handler = subcmd ? modelHandlers[subcmd] : modelHandlers.list;
36976
37409
  if (!handler) {
36977
- console.log(t("repl.model_usage"));
37410
+ ctx.output.writeLine(t("repl.model_usage"));
36978
37411
  return;
36979
37412
  }
36980
37413
  await handler(args.slice(1));
@@ -36992,29 +37425,29 @@ function registerProviderCommands(ctx) {
36992
37425
  };
36993
37426
  if (args.length === 0) {
36994
37427
  for (const line of budgetBreakdownLines(ctx.config))
36995
- console.log(line);
36996
- console.log(pc2.dim(t("repl.context_usage")));
37428
+ ctx.output.writeLine(line);
37429
+ ctx.output.writeLine(pc.dim(t("repl.context_usage")));
36997
37430
  return;
36998
37431
  }
36999
37432
  if (args[0] === "system" || args[0] === "reserve") {
37000
37433
  const key = args[0];
37001
37434
  const value = Number(args[1]);
37002
37435
  if (setBudgetShare(ctx.config, key, value) !== null) {
37003
- console.log(pc2.yellow(t("cli.context_invalid_fraction")));
37436
+ ctx.output.writeLine(pc.yellow(t("cli.context_invalid_fraction")));
37004
37437
  return;
37005
37438
  }
37006
37439
  await save();
37007
- console.log(pc2.green(t("cli.context_fraction_set", { key, value })));
37440
+ ctx.output.writeLine(pc.green(t("cli.context_fraction_set", { key, value })));
37008
37441
  return;
37009
37442
  }
37010
37443
  const size = parseInt(args[0], 10);
37011
37444
  if (isNaN(size) || size < 1024) {
37012
- console.log(t("cli.invalid_context_size"));
37445
+ ctx.output.writeLine(t("cli.invalid_context_size"));
37013
37446
  return;
37014
37447
  }
37015
37448
  ctx.config.contextWindow = size;
37016
37449
  await save();
37017
- console.log(pc2.green(t("cli.context_set", { size })));
37450
+ ctx.output.writeLine(pc.green(t("cli.context_set", { size })));
37018
37451
  }
37019
37452
  });
37020
37453
  }
@@ -37024,12 +37457,12 @@ function registerAgentCommands(ctx) {
37024
37457
  description: t("repl.reload"),
37025
37458
  usage: t("repl.reload_usage"),
37026
37459
  action: async () => {
37027
- console.log(pc2.yellow(t("repl.reloading")));
37460
+ ctx.output.writeLine(pc.yellow(t("repl.reloading")));
37028
37461
  await ctx.reload();
37029
- console.log(pc2.green(t("repl.reloaded")));
37030
- console.log(`${t("repl.model")} ${ctx.config.model}`);
37031
- console.log(`${t("repl.context")} ${ctx.config.contextWindow}`);
37032
- console.log(`${t("repl.provider")} ${ctx.config.provider.type} @ ${ctx.config.provider.baseUrl}`);
37462
+ ctx.output.writeLine(pc.green(t("repl.reloaded")));
37463
+ ctx.output.writeLine(`${t("repl.model")} ${ctx.config.model}`);
37464
+ ctx.output.writeLine(`${t("repl.context")} ${ctx.config.contextWindow}`);
37465
+ ctx.output.writeLine(`${t("repl.provider")} ${ctx.config.provider.type} @ ${ctx.config.provider.baseUrl}`);
37033
37466
  }
37034
37467
  });
37035
37468
  ctx.registerCommand({
@@ -37038,18 +37471,18 @@ function registerAgentCommands(ctx) {
37038
37471
  usage: t("repl.plugins_usage"),
37039
37472
  action: (args) => {
37040
37473
  if (!ctx.pluginManager) {
37041
- console.log(t("cli.plugins.none"));
37474
+ ctx.output.writeLine(t("cli.plugins.none"));
37042
37475
  return;
37043
37476
  }
37044
37477
  const showAll = args.includes("--all");
37045
37478
  const infos = ctx.pluginManager.getPluginInfos();
37046
37479
  const filtered = showAll ? infos : infos.filter(({ plugin: plugin3 }) => !plugin3.isBuiltin);
37047
37480
  if (filtered.length === 0) {
37048
- console.log(t("cli.plugins.none"));
37481
+ ctx.output.writeLine(t("cli.plugins.none"));
37049
37482
  return;
37050
37483
  }
37051
37484
  const mmaVersion = version2;
37052
- console.log(t("cli.plugins.header", {
37485
+ ctx.output.writeLine(t("cli.plugins.header", {
37053
37486
  count: String(filtered.length),
37054
37487
  mma: mmaVersion
37055
37488
  }));
@@ -37057,12 +37490,12 @@ function registerAgentCommands(ctx) {
37057
37490
  const v = plugin3.version || "-";
37058
37491
  const origin = source || "builtin";
37059
37492
  const mark = plugin3.isBuiltin ? t("cli.plugins.builtin_mark") : " ";
37060
- console.log(` ${mark} ${plugin3.name} v${v} [${origin}]`);
37493
+ ctx.output.writeLine(` ${mark} ${plugin3.name} v${v} [${origin}]`);
37061
37494
  }
37062
37495
  if (!showAll) {
37063
37496
  const builtinCount = infos.filter(({ plugin: plugin3 }) => plugin3.isBuiltin).length;
37064
37497
  if (builtinCount > 0) {
37065
- console.log(pc2.dim(` (${builtinCount} builtin hidden — /plugins --all to show)`));
37498
+ ctx.output.writeLine(pc.dim(` (${builtinCount} builtin hidden — /plugins --all to show)`));
37066
37499
  }
37067
37500
  }
37068
37501
  }
@@ -37077,7 +37510,7 @@ function registerLspCommands(ctx) {
37077
37510
  const subcommand = args[0] || "status";
37078
37511
  const lspModule = ctx.agent.getModule("lsp");
37079
37512
  if (!lspModule) {
37080
- console.log(pc2.yellow(t("repl.lsp_not_available")));
37513
+ ctx.output.writeLine(pc.yellow(t("repl.lsp_not_available")));
37081
37514
  return;
37082
37515
  }
37083
37516
  switch (subcommand) {
@@ -37085,49 +37518,47 @@ function registerLspCommands(ctx) {
37085
37518
  const disabled = lspModule.getDisabledServers();
37086
37519
  const failures = lspModule.getFailureCounts();
37087
37520
  const config = ctx.config.lsp;
37088
- console.log(pc2.bold(t("repl.lsp_status_header")));
37089
- console.log(`${t("repl.lsp_enabled")} ${config?.enabled ? pc2.green("yes") : pc2.red("no")}`);
37521
+ ctx.output.writeLine(pc.bold(t("repl.lsp_status_header")));
37522
+ ctx.output.writeLine(`${t("repl.lsp_enabled")} ${config?.enabled ? pc.green("yes") : pc.red("no")}`);
37090
37523
  if (disabled.length > 0) {
37091
- console.log(pc2.yellow(`${t("repl.lsp_disabled_servers")} ${disabled.join(", ")}`));
37524
+ ctx.output.writeLine(pc.yellow(`${t("repl.lsp_disabled_servers")} ${disabled.join(", ")}`));
37092
37525
  }
37093
37526
  if (failures.size > 0) {
37094
- console.log(pc2.dim(t("repl.lsp_failure_counts")));
37527
+ ctx.output.writeLine(pc.dim(t("repl.lsp_failure_counts")));
37095
37528
  for (const [server, count] of failures) {
37096
- console.log(pc2.dim(` ${server}: ${count}`));
37529
+ ctx.output.writeLine(pc.dim(` ${server}: ${count}`));
37097
37530
  }
37098
37531
  }
37099
37532
  if (disabled.length === 0 && failures.size === 0) {
37100
- console.log(pc2.green(t("repl.lsp_all_ok")));
37533
+ ctx.output.writeLine(pc.green(t("repl.lsp_all_ok")));
37101
37534
  }
37102
37535
  break;
37103
37536
  }
37104
37537
  case "restart": {
37105
- console.log(pc2.yellow(t("repl.lsp_restarting")));
37538
+ ctx.output.writeLine(pc.yellow(t("repl.lsp_restarting")));
37106
37539
  lspModule.resetDisabledServers();
37107
- console.log(pc2.green(t("repl.lsp_restarted")));
37540
+ ctx.output.writeLine(pc.green(t("repl.lsp_restarted")));
37108
37541
  break;
37109
37542
  }
37110
37543
  case "check": {
37111
37544
  const path = args[1];
37112
37545
  if (!path) {
37113
- console.log(pc2.yellow(t("repl.lsp_check_usage")));
37546
+ ctx.output.writeLine(pc.yellow(t("repl.lsp_check_usage")));
37114
37547
  return;
37115
37548
  }
37116
- console.log(pc2.dim(t("repl.lsp_checking", { path })));
37549
+ ctx.output.writeLine(pc.dim(t("repl.lsp_checking", { path })));
37117
37550
  try {
37118
37551
  const result = await ctx.agent.runTool("lsp_check", { path });
37119
37552
  if (result?.output) {
37120
- console.log(result.output);
37553
+ ctx.output.writeLine(result.output);
37121
37554
  }
37122
37555
  } catch (e) {
37123
- console.log(pc2.red(t("repl.lsp_check_error", {
37124
- error: errMsg(e)
37125
- })));
37556
+ ctx.output.writeLine(pc.red(t("repl.lsp_check_error", { error: errMsg(e) })), "stderr");
37126
37557
  }
37127
37558
  break;
37128
37559
  }
37129
37560
  default: {
37130
- console.log(pc2.dim(t("repl.lsp_usage")));
37561
+ ctx.output.writeLine(pc.dim(t("repl.lsp_usage")));
37131
37562
  break;
37132
37563
  }
37133
37564
  }
@@ -37153,11 +37584,11 @@ function registerSessionCommands(ctx) {
37153
37584
  const sessions = ctx.sessionManager.list();
37154
37585
  const active = ctx.sessionManager.getActive();
37155
37586
  if (sessions.length === 0) {
37156
- console.log(t("session.no_sessions_hint"));
37587
+ ctx.output.writeLine(t("session.no_sessions_hint"));
37157
37588
  return;
37158
37589
  }
37159
37590
  const rows = sessions.map((s) => [
37160
- s.id === active ? pc2.green("●") : "",
37591
+ s.id === active ? pc.green("●") : "",
37161
37592
  s.id.slice(0, 12),
37162
37593
  s.name,
37163
37594
  s.updatedAt.slice(0, 19).replace("T", " "),
@@ -37170,9 +37601,9 @@ function registerSessionCommands(ctx) {
37170
37601
  t("session.col_updated"),
37171
37602
  t("session.col_msgs")
37172
37603
  ], rows)) {
37173
- console.log(line);
37604
+ ctx.output.writeLine(line);
37174
37605
  }
37175
- console.log(pc2.dim(`
37606
+ ctx.output.writeLine(pc.dim(`
37176
37607
  ${t("repl.resume_hint")}`));
37177
37608
  }
37178
37609
  });
@@ -37185,9 +37616,9 @@ function registerSessionCommands(ctx) {
37185
37616
  const name = args.join(" ") || undefined;
37186
37617
  const meta = ctx.sessionManager.create(name);
37187
37618
  ctx.agent.clearContext();
37188
- console.clear();
37189
- console.log(`${t("session.created", { name: meta.name })} (${pc2.dim(meta.id.slice(0, 12))})`);
37190
- console.log(pc2.dim(` ${t("session.chat_cleared")}
37619
+ ctx.output.clearScreen();
37620
+ ctx.output.writeLine(`${t("session.created", { name: meta.name })} (${pc.dim(meta.id.slice(0, 12))})`);
37621
+ ctx.output.writeLine(pc.dim(` ${t("session.chat_cleared")}
37191
37622
  `));
37192
37623
  }
37193
37624
  });
@@ -37200,46 +37631,46 @@ function registerSessionCommands(ctx) {
37200
37631
  const query = args.join(" ");
37201
37632
  const sessions = ctx.sessionManager.list();
37202
37633
  if (!query) {
37203
- console.log(pc2.dim(t("session.available")));
37634
+ ctx.output.writeLine(pc.dim(t("session.available")));
37204
37635
  const active = ctx.sessionManager.getActive();
37205
37636
  for (const s of sessions) {
37206
- const marker = s.id === active ? pc2.green(" *") : " ";
37207
- console.log(pc2.dim(` ${marker} ${s.id.slice(0, 12)} ${s.name}`));
37637
+ const marker = s.id === active ? pc.green(" *") : " ";
37638
+ ctx.output.writeLine(pc.dim(` ${marker} ${s.id.slice(0, 12)} ${s.name}`));
37208
37639
  }
37209
- console.log(pc2.dim(`
37640
+ ctx.output.writeLine(pc.dim(`
37210
37641
  ${t("repl.resume_usage")}`));
37211
37642
  return;
37212
37643
  }
37213
37644
  const match = sessions.find((s) => s.id === query || s.id.startsWith(query) || s.name.toLowerCase().includes(query.toLowerCase()));
37214
37645
  if (!match) {
37215
- console.log(t("session.no_match", { query }));
37646
+ ctx.output.writeLine(t("session.no_match", { query }));
37216
37647
  return;
37217
37648
  }
37218
37649
  ctx.sessionManager.setActive(match.id);
37219
37650
  const history = ctx.sessionManager.loadHistory();
37220
37651
  ctx.agent.setContext(history);
37221
- console.clear();
37222
- console.log(pc2.bold(pc2.green(t("session.resumed", { name: match.name }))) + " " + pc2.dim(`(${match.id.slice(0, 12)})`) + " — " + match.messageCount + " " + t("repl.msgs"));
37223
- console.log(pc2.dim("─".repeat(50)));
37652
+ ctx.output.clearScreen();
37653
+ ctx.output.writeLine(pc.bold(pc.green(t("session.resumed", { name: match.name }))) + " " + pc.dim(`(${match.id.slice(0, 12)})`) + " — " + match.messageCount + " " + t("repl.msgs"));
37654
+ ctx.output.writeLine(pc.dim("─".repeat(50)));
37224
37655
  if (history.length === 0) {
37225
- console.log(pc2.dim(t("session.no_history")));
37656
+ ctx.output.writeLine(pc.dim(t("session.no_history")));
37226
37657
  } else {
37227
- console.log(pc2.dim(t("session.chat_history")));
37228
- console.log();
37658
+ ctx.output.writeLine(pc.dim(t("session.chat_history")));
37659
+ ctx.output.writeLine("");
37229
37660
  for (const msg of history) {
37230
37661
  if (msg.role === "user") {
37231
- console.log(pc2.cyan(t("session.user_label") + ":"));
37232
- console.log(getMessageText(msg.content));
37233
- console.log();
37662
+ ctx.output.writeLine(pc.cyan(t("session.user_label") + ":"));
37663
+ ctx.output.writeLine(getMessageText(msg.content));
37664
+ ctx.output.writeLine("");
37234
37665
  } else if (msg.role === "assistant") {
37235
- console.log(pc2.green(t("session.assistant_label") + ":"));
37236
- console.log(getMessageText(msg.content));
37237
- console.log();
37666
+ ctx.output.writeLine(pc.green(t("session.assistant_label") + ":"));
37667
+ ctx.output.writeLine(getMessageText(msg.content));
37668
+ ctx.output.writeLine("");
37238
37669
  }
37239
37670
  }
37240
37671
  }
37241
- console.log(pc2.dim("─".repeat(50)));
37242
- console.log(pc2.dim(` ${t("session.chat_loaded")}`));
37672
+ ctx.output.writeLine(pc.dim("─".repeat(50)));
37673
+ ctx.output.writeLine(pc.dim(` ${t("session.chat_loaded")}`));
37243
37674
  }
37244
37675
  });
37245
37676
  ctx.registerCommand({
@@ -37249,16 +37680,16 @@ function registerSessionCommands(ctx) {
37249
37680
  action: (args) => {
37250
37681
  const name = args.join(" ");
37251
37682
  if (!name) {
37252
- console.log(t("repl.rename_usage"));
37683
+ ctx.output.writeLine(t("repl.rename_usage"));
37253
37684
  return;
37254
37685
  }
37255
37686
  const active = ctx.sessionManager.getActive();
37256
37687
  if (!active) {
37257
- console.log(t("session.no_active"));
37688
+ ctx.output.writeLine(t("session.no_active"));
37258
37689
  return;
37259
37690
  }
37260
37691
  ctx.sessionManager.rename(active, name);
37261
- console.log(t("session.renamed", { name }));
37692
+ ctx.output.writeLine(t("session.renamed", { name }));
37262
37693
  }
37263
37694
  });
37264
37695
  ctx.registerCommand({
@@ -37269,17 +37700,17 @@ function registerSessionCommands(ctx) {
37269
37700
  action: (args) => {
37270
37701
  const query = args[0];
37271
37702
  if (!query) {
37272
- console.log(t("repl.delete_usage"));
37703
+ ctx.output.writeLine(t("repl.delete_usage"));
37273
37704
  return;
37274
37705
  }
37275
37706
  const sessions = ctx.sessionManager.list();
37276
37707
  const match = sessions.find((s) => s.id === query || s.id.startsWith(query));
37277
37708
  if (!match) {
37278
- console.log(t("session.no_match", { query }));
37709
+ ctx.output.writeLine(t("session.no_match", { query }));
37279
37710
  return;
37280
37711
  }
37281
37712
  ctx.sessionManager.delete(match.id);
37282
- console.log(`${t("session.deleted", { id: match.id })}: ${match.name}`);
37713
+ ctx.output.writeLine(`${t("session.deleted", { id: match.id })}: ${match.name}`);
37283
37714
  }
37284
37715
  });
37285
37716
  }
@@ -37289,72 +37720,72 @@ function registerSkillCommands(ctx) {
37289
37720
  const listSkills = () => {
37290
37721
  const available = ctx.skillsModule.getAvailable();
37291
37722
  if (available.length === 0) {
37292
- console.log(t("repl.no_skills"));
37723
+ ctx.output.writeLine(t("repl.no_skills"));
37293
37724
  return;
37294
37725
  }
37295
- console.log(pc2.bold(t("repl.available_skills")));
37726
+ ctx.output.writeLine(pc.bold(t("repl.available_skills")));
37296
37727
  for (const skill of available) {
37297
37728
  const tokens = estimateTokens(skill.content);
37298
37729
  const loaded = ctx.skillsModule.getLoaded().some((s) => s.name === skill.name);
37299
- const marker = loaded ? pc2.green(" [loaded]") : "";
37300
- console.log(` ${pc2.cyan(skill.name)}${marker} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37730
+ const marker = loaded ? pc.green(" [loaded]") : "";
37731
+ ctx.output.writeLine(` ${pc.cyan(skill.name)}${marker} ${pc.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37301
37732
  }
37302
37733
  };
37303
37734
  const listLoaded = () => {
37304
37735
  const loaded = ctx.skillsModule.getLoaded();
37305
37736
  const budget = ctx.skillsModule.getBudget();
37306
37737
  if (loaded.length === 0) {
37307
- console.log(t("repl.no_loaded"));
37738
+ ctx.output.writeLine(t("repl.no_loaded"));
37308
37739
  return;
37309
37740
  }
37310
- console.log(pc2.bold(t("repl.loaded_skills")));
37741
+ ctx.output.writeLine(pc.bold(t("repl.loaded_skills")));
37311
37742
  for (const skill of loaded) {
37312
37743
  const tokens = estimateTokens(skill.content);
37313
- console.log(` ${pc2.cyan(skill.name)} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37744
+ ctx.output.writeLine(` ${pc.cyan(skill.name)} ${pc.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37314
37745
  }
37315
- console.log(pc2.dim(`
37746
+ ctx.output.writeLine(pc.dim(`
37316
37747
  ${t("repl.budget", { used: budget.used, total: budget.total, remaining: budget.remaining })}`));
37317
37748
  };
37318
37749
  const loadSkill = (args) => {
37319
37750
  const arg = args.join(" ");
37320
37751
  if (!arg) {
37321
- console.log(t("repl.skill_load_usage"));
37752
+ ctx.output.writeLine(t("repl.skill_load_usage"));
37322
37753
  return;
37323
37754
  }
37324
37755
  const result = ctx.skillsModule.loadByName(arg);
37325
37756
  if (result.success) {
37326
- console.log(pc2.green(result.message));
37757
+ ctx.output.writeLine(pc.green(result.message));
37327
37758
  } else {
37328
- console.log(pc2.red(result.message));
37759
+ ctx.output.writeLine(pc.red(result.message), "stderr");
37329
37760
  }
37330
37761
  };
37331
37762
  const unloadSkill = (args) => {
37332
37763
  const arg = args.join(" ");
37333
37764
  if (!arg) {
37334
- console.log(t("repl.skill_unload_usage"));
37765
+ ctx.output.writeLine(t("repl.skill_unload_usage"));
37335
37766
  return;
37336
37767
  }
37337
37768
  if (ctx.skillsModule.unload(arg)) {
37338
- console.log(pc2.green(t("repl.skill_unloaded", { name: arg })));
37769
+ ctx.output.writeLine(pc.green(t("repl.skill_unloaded", { name: arg })));
37339
37770
  } else {
37340
- console.log(pc2.red(t("repl.skill_not_loaded", { name: arg })));
37771
+ ctx.output.writeLine(pc.red(t("repl.skill_not_loaded", { name: arg })), "stderr");
37341
37772
  }
37342
37773
  };
37343
37774
  const searchSkills = (args) => {
37344
37775
  const arg = args.join(" ");
37345
37776
  if (!arg) {
37346
- console.log(t("repl.skill_search_usage"));
37777
+ ctx.output.writeLine(t("repl.skill_search_usage"));
37347
37778
  return;
37348
37779
  }
37349
37780
  const results = ctx.skillsModule.search(arg);
37350
37781
  if (results.length === 0) {
37351
- console.log(t("repl.no_skill_match", { query: arg }));
37782
+ ctx.output.writeLine(t("repl.no_skill_match", { query: arg }));
37352
37783
  return;
37353
37784
  }
37354
- console.log(pc2.bold(t("repl.skills_matching", { query: arg })));
37785
+ ctx.output.writeLine(pc.bold(t("repl.skills_matching", { query: arg })));
37355
37786
  for (const skill of results) {
37356
37787
  const tokens = estimateTokens(skill.content);
37357
- console.log(` ${pc2.cyan(skill.name)} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37788
+ ctx.output.writeLine(` ${pc.cyan(skill.name)} ${pc.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37358
37789
  }
37359
37790
  };
37360
37791
  const skillHandlers = {
@@ -37372,8 +37803,8 @@ function registerSkillCommands(ctx) {
37372
37803
  const subcmd = args[0];
37373
37804
  const handler = subcmd ? skillHandlers[subcmd] : skillHandlers.list;
37374
37805
  if (!handler) {
37375
- console.log(pc2.red(t("repl.skill_unknown_sub", { subcmd })));
37376
- console.log(t("repl.skill_usage"));
37806
+ ctx.output.writeLine(pc.red(t("repl.skill_unknown_sub", { subcmd })), "stderr");
37807
+ ctx.output.writeLine(t("repl.skill_usage"));
37377
37808
  return;
37378
37809
  }
37379
37810
  handler(args.slice(1));
@@ -37386,20 +37817,20 @@ async function runConfigMigrate(ctx) {
37386
37817
  const configDir = ctx.configDir;
37387
37818
  const configPath = join54(configDir, "config.json");
37388
37819
  if (hasDomainFiles3(configDir)) {
37389
- console.log(pc2.yellow(t("config.migrate_no_legacy")));
37820
+ ctx.output.writeLine(pc.yellow(t("config.migrate_no_legacy")));
37390
37821
  return;
37391
37822
  }
37392
37823
  if (!existsSync59(configPath)) {
37393
- console.log(pc2.yellow(t("config.migrate_no_legacy")));
37824
+ ctx.output.writeLine(pc.yellow(t("config.migrate_no_legacy")));
37394
37825
  return;
37395
37826
  }
37396
- console.log(t("config.migrate_start"));
37827
+ ctx.output.writeLine(t("config.migrate_start"));
37397
37828
  const { config } = loadCfg({ configDir, projectConfigPath: join54(configDir, ".mmrc") });
37398
37829
  saveConfig(config, configPath, configDir);
37399
37830
  const { renameSync: renameSync4, readdirSync: readdirSync19 } = await import("fs");
37400
37831
  renameSync4(configPath, configPath + ".bak");
37401
37832
  const domainFiles = readdirSync19(join54(configDir, "config")).filter((f) => f.endsWith(".json"));
37402
- console.log(pc2.green(t("config.migrate_done", { count: String(domainFiles.length) })));
37833
+ ctx.output.writeLine(pc.green(t("config.migrate_done", { count: String(domainFiles.length) })));
37403
37834
  }
37404
37835
  var version2, COMMAND_GROUPS;
37405
37836
  var init_repl_commands = __esm(() => {
@@ -37948,6 +38379,7 @@ function applySecurityPolicy(preset, customOverrides) {
37948
38379
  // src/cli/security-commands.ts
37949
38380
  init_audit_notifier();
37950
38381
  init_i18n();
38382
+ init_output();
37951
38383
  function toggleSessionEncryption(security, enabled2) {
37952
38384
  const enc = security.sessionEncryption ?? {};
37953
38385
  enc.enabled = enabled2;
@@ -37972,28 +38404,28 @@ function createSecurityCommand(program2) {
37972
38404
  const rateLimits = security.rateLimits || {};
37973
38405
  const sessionEncryption = security.sessionEncryption || {};
37974
38406
  const auditNotifier = security.auditNotifier || {};
37975
- console.log(t("cli.security.current_policy"));
37976
- console.log(` ${t("cli.security.bash_enabled")}: ${bash.blacklist?.length > 0 ? t("cli.yes") : t("cli.no")}`);
37977
- console.log(` ${t("cli.security.path_validation")}: ${paths.denied?.length > 0 ? t("cli.yes") : t("cli.no")}`);
37978
- console.log(` ${t("cli.security.network_validation")}: ${network.deniedDomains?.length > 0 || network.allowedDomains?.length > 0 ? t("cli.yes") : t("cli.no")}`);
37979
- console.log(` ${t("cli.security.content_scanning")}: ${contentScan.enabled ? t("cli.yes") : t("cli.no")}`);
37980
- console.log(` ${t("cli.security.max_recursion")}: ${security.maxRecursionDepth ?? 3}`);
37981
- console.log(` ${t("cli.security.max_file_ops")}: ${security.maxFileOperations ?? 100}`);
37982
- console.log(` ${t("cli.security.rate_limit")}: ${rateLimits.maxRequestsPerMinute ?? 60}/min`);
37983
- console.log(` ${t("cli.security.session_encryption")}: ${sessionEncryption.enabled ? t("cli.yes") : t("cli.no")}`);
37984
- console.log(` ${t("cli.security.audit_notifier")}: ${auditNotifier.enabled ? t("cli.yes") : t("cli.no")}`);
38407
+ getDefaultChannel().writeLine(t("cli.security.current_policy"));
38408
+ getDefaultChannel().writeLine(` ${t("cli.security.bash_enabled")}: ${bash.blacklist?.length > 0 ? t("cli.yes") : t("cli.no")}`);
38409
+ getDefaultChannel().writeLine(` ${t("cli.security.path_validation")}: ${paths.denied?.length > 0 ? t("cli.yes") : t("cli.no")}`);
38410
+ getDefaultChannel().writeLine(` ${t("cli.security.network_validation")}: ${network.deniedDomains?.length > 0 || network.allowedDomains?.length > 0 ? t("cli.yes") : t("cli.no")}`);
38411
+ getDefaultChannel().writeLine(` ${t("cli.security.content_scanning")}: ${contentScan.enabled ? t("cli.yes") : t("cli.no")}`);
38412
+ getDefaultChannel().writeLine(` ${t("cli.security.max_recursion")}: ${security.maxRecursionDepth ?? 3}`);
38413
+ getDefaultChannel().writeLine(` ${t("cli.security.max_file_ops")}: ${security.maxFileOperations ?? 100}`);
38414
+ getDefaultChannel().writeLine(` ${t("cli.security.rate_limit")}: ${rateLimits.maxRequestsPerMinute ?? 60}/min`);
38415
+ getDefaultChannel().writeLine(` ${t("cli.security.session_encryption")}: ${sessionEncryption.enabled ? t("cli.yes") : t("cli.no")}`);
38416
+ getDefaultChannel().writeLine(` ${t("cli.security.audit_notifier")}: ${auditNotifier.enabled ? t("cli.yes") : t("cli.no")}`);
37985
38417
  });
37986
38418
  securityCmd.command("policies").description(t("cli.security.policies")).action(async () => {
37987
- console.log(t("cli.security.available_policies"));
37988
- console.log("");
38419
+ getDefaultChannel().writeLine(t("cli.security.available_policies"));
38420
+ getDefaultChannel().writeLine("");
37989
38421
  for (const [preset, policy] of Object.entries(SECURITY_POLICIES)) {
37990
38422
  if (preset === "custom")
37991
38423
  continue;
37992
38424
  const marker = " ";
37993
- console.log(` ${marker}${preset.padEnd(12)} ${policy.name}`);
37994
- console.log(` ${policy.description}`);
37995
- console.log(` ${t("cli.security.recommended_for")}: ${policy.recommendedFor.join(", ")}`);
37996
- console.log("");
38425
+ getDefaultChannel().writeLine(` ${marker}${preset.padEnd(12)} ${policy.name}`);
38426
+ getDefaultChannel().writeLine(` ${policy.description}`);
38427
+ getDefaultChannel().writeLine(` ${t("cli.security.recommended_for")}: ${policy.recommendedFor.join(", ")}`);
38428
+ getDefaultChannel().writeLine("");
37997
38429
  }
37998
38430
  });
37999
38431
  securityCmd.command("set-policy").argument("<preset>", t("cli.security.preset")).description(t("cli.security.set_policy")).action(async (preset) => {
@@ -38001,15 +38433,15 @@ function createSecurityCommand(program2) {
38001
38433
  const { config: appConfig } = await bootstrap();
38002
38434
  const validPresets = ["strict", "balanced", "permissive"];
38003
38435
  if (!validPresets.includes(preset)) {
38004
- console.log(t("cli.security.invalid_preset", { presets: validPresets.join(", ") }));
38436
+ getDefaultChannel().writeLine(t("cli.security.invalid_preset", { presets: validPresets.join(", ") }));
38005
38437
  return;
38006
38438
  }
38007
38439
  const policy = getSecurityPolicy(preset);
38008
38440
  const newSecurityConfig = applySecurityPolicy(preset);
38009
38441
  appConfig.security = newSecurityConfig;
38010
38442
  saveConfig(appConfig, configPath, dirname19(configPath));
38011
- console.log(t("cli.security.policy_applied", { name: policy.name }));
38012
- console.log(t("cli.security.policy_description", { description: policy.description }));
38443
+ getDefaultChannel().writeLine(t("cli.security.policy_applied", { name: policy.name }));
38444
+ getDefaultChannel().writeLine(t("cli.security.policy_description", { description: policy.description }));
38013
38445
  });
38014
38446
  securityCmd.command("enable-encryption").description(t("cli.security.enable_encryption")).action(async () => {
38015
38447
  const configPath = join47(homedir16(), ".mma", "config.json");
@@ -38017,7 +38449,7 @@ function createSecurityCommand(program2) {
38017
38449
  const security = appConfig.security = appConfig.security || {};
38018
38450
  toggleSessionEncryption(security, true);
38019
38451
  saveConfig(appConfig, configPath, dirname19(configPath));
38020
- console.log(t("cli.security.encryption_enabled"));
38452
+ getDefaultChannel().writeLine(t("cli.security.encryption_enabled"));
38021
38453
  });
38022
38454
  securityCmd.command("disable-encryption").description(t("cli.security.disable_encryption")).action(async () => {
38023
38455
  const configPath = join47(homedir16(), ".mma", "config.json");
@@ -38025,7 +38457,7 @@ function createSecurityCommand(program2) {
38025
38457
  const security = appConfig.security = appConfig.security || {};
38026
38458
  toggleSessionEncryption(security, false);
38027
38459
  saveConfig(appConfig, configPath, dirname19(configPath));
38028
- console.log(t("cli.security.encryption_disabled"));
38460
+ getDefaultChannel().writeLine(t("cli.security.encryption_disabled"));
38029
38461
  });
38030
38462
  securityCmd.command("enable-audit").description(t("cli.security.enable_audit")).action(async () => {
38031
38463
  const configPath = join47(homedir16(), ".mma", "config.json");
@@ -38033,7 +38465,7 @@ function createSecurityCommand(program2) {
38033
38465
  const security = appConfig.security = appConfig.security || {};
38034
38466
  toggleAuditNotifier(security, true);
38035
38467
  saveConfig(appConfig, configPath, dirname19(configPath));
38036
- console.log(t("cli.security.audit_enabled"));
38468
+ getDefaultChannel().writeLine(t("cli.security.audit_enabled"));
38037
38469
  });
38038
38470
  securityCmd.command("disable-audit").description(t("cli.security.disable_audit")).action(async () => {
38039
38471
  const configPath = join47(homedir16(), ".mma", "config.json");
@@ -38041,23 +38473,23 @@ function createSecurityCommand(program2) {
38041
38473
  const security = appConfig.security = appConfig.security || {};
38042
38474
  toggleAuditNotifier(security, false);
38043
38475
  saveConfig(appConfig, configPath, dirname19(configPath));
38044
- console.log(t("cli.security.audit_disabled"));
38476
+ getDefaultChannel().writeLine(t("cli.security.audit_disabled"));
38045
38477
  });
38046
38478
  securityCmd.command("audit-stats").description(t("cli.security.audit_stats")).action(async () => {
38047
38479
  const stats = globalAuditNotifier.getStats();
38048
- console.log(t("cli.security.audit_stats_title"));
38049
- console.log(` ${t("cli.security.total_notifications")}: ${stats.total}`);
38050
- console.log("");
38051
- console.log(t("cli.security.by_severity"));
38052
- console.log(` ${t("cli.security.low")}: ${stats.bySeverity.low}`);
38053
- console.log(` ${t("cli.security.medium")}: ${stats.bySeverity.medium}`);
38054
- console.log(` ${t("cli.security.high")}: ${stats.bySeverity.high}`);
38055
- console.log(` ${t("cli.security.critical")}: ${stats.bySeverity.critical}`);
38056
- console.log("");
38057
- console.log(t("cli.security.by_type"));
38480
+ getDefaultChannel().writeLine(t("cli.security.audit_stats_title"));
38481
+ getDefaultChannel().writeLine(` ${t("cli.security.total_notifications")}: ${stats.total}`);
38482
+ getDefaultChannel().writeLine("");
38483
+ getDefaultChannel().writeLine(t("cli.security.by_severity"));
38484
+ getDefaultChannel().writeLine(` ${t("cli.security.low")}: ${stats.bySeverity.low}`);
38485
+ getDefaultChannel().writeLine(` ${t("cli.security.medium")}: ${stats.bySeverity.medium}`);
38486
+ getDefaultChannel().writeLine(` ${t("cli.security.high")}: ${stats.bySeverity.high}`);
38487
+ getDefaultChannel().writeLine(` ${t("cli.security.critical")}: ${stats.bySeverity.critical}`);
38488
+ getDefaultChannel().writeLine("");
38489
+ getDefaultChannel().writeLine(t("cli.security.by_type"));
38058
38490
  for (const [type2, count] of Object.entries(stats.byType)) {
38059
38491
  if (count > 0) {
38060
- console.log(` ${type2}: ${count}`);
38492
+ getDefaultChannel().writeLine(` ${type2}: ${count}`);
38061
38493
  }
38062
38494
  }
38063
38495
  });
@@ -38067,6 +38499,7 @@ function createSecurityCommand(program2) {
38067
38499
  init_bootstrap();
38068
38500
  init_version();
38069
38501
  init_i18n();
38502
+ init_output();
38070
38503
  function createPluginCommand(program2) {
38071
38504
  const pluginsCmd = program2.command("plugins").description(t("cli.plugins.description"));
38072
38505
  pluginsCmd.command("list").description(t("cli.plugins.list")).option("-a, --all", t("cli.plugins.all")).action(async (cmdOpts) => {
@@ -38077,19 +38510,19 @@ function createPluginCommand(program2) {
38077
38510
  infos = infos.filter(({ plugin: plugin3 }) => !plugin3.isBuiltin);
38078
38511
  }
38079
38512
  if (infos.length === 0) {
38080
- console.log(t("cli.plugins.none"));
38513
+ getDefaultChannel().writeLine(t("cli.plugins.none"));
38081
38514
  return;
38082
38515
  }
38083
38516
  const mmaVersion = readMmaVersion();
38084
- console.log(t("cli.plugins.header", { count: String(infos.length), mma: mmaVersion }));
38517
+ getDefaultChannel().writeLine(t("cli.plugins.header", { count: String(infos.length), mma: mmaVersion }));
38085
38518
  for (const { plugin: plugin3, source } of infos) {
38086
38519
  const version = plugin3.version || "-";
38087
38520
  const origin = source || "builtin";
38088
38521
  const builtin = plugin3.isBuiltin ? t("cli.plugins.builtin_mark") : " ";
38089
- console.log(` ${builtin} ${plugin3.name} v${version} [${origin}]`);
38522
+ getDefaultChannel().writeLine(` ${builtin} ${plugin3.name} v${version} [${origin}]`);
38090
38523
  }
38091
38524
  if (!all) {
38092
- console.log(t("cli.plugins.only_external"));
38525
+ getDefaultChannel().writeLine(t("cli.plugins.only_external"));
38093
38526
  }
38094
38527
  });
38095
38528
  }
@@ -38280,6 +38713,7 @@ function extractLatestChangelog(changelog) {
38280
38713
  }
38281
38714
 
38282
38715
  // src/cli/commands.ts
38716
+ init_output();
38283
38717
  var version = readMmaVersion();
38284
38718
  function buildInitCommand(program2) {
38285
38719
  program2.command("init").description(t("cli.init")).action(async () => {
@@ -38325,7 +38759,7 @@ function buildInitCommand(program2) {
38325
38759
  }
38326
38760
  }
38327
38761
  saveConfig(config, configPath, dirname23(configPath));
38328
- console.log(t("cli.config_saved"));
38762
+ getDefaultChannel().writeLine(t("cli.config_saved"));
38329
38763
  });
38330
38764
  }
38331
38765
  function buildConfigCommands(program2) {
@@ -38352,11 +38786,11 @@ function buildConfigCommands(program2) {
38352
38786
  else
38353
38787
  obj[lastKey] = value;
38354
38788
  saveConfig(config, configPath, dirname23(configPath));
38355
- console.log(t("cli.set_done", { key, value }));
38789
+ getDefaultChannel().writeLine(t("cli.set_done", { key, value }));
38356
38790
  });
38357
38791
  configCmd.command("show").description(t("cli.show_config")).action(async () => {
38358
38792
  const { config } = await bootstrap();
38359
- console.log(JSON.stringify(config, null, 2));
38793
+ writeMachineJson(config);
38360
38794
  });
38361
38795
  configCmd.command("migrate").description(t("cli.migrate_config")).action(async () => {
38362
38796
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
@@ -38364,14 +38798,14 @@ function buildConfigCommands(program2) {
38364
38798
  const configDir = join53(homedir17(), ".mma");
38365
38799
  const configPath = join53(configDir, "config.json");
38366
38800
  if (hasDomainFiles3(configDir)) {
38367
- console.log(pc2.yellow(t("config.migrate_no_legacy")));
38801
+ getDefaultChannel().writeLine(pc.yellow(t("config.migrate_no_legacy")));
38368
38802
  return;
38369
38803
  }
38370
38804
  if (!existsSync58(configPath)) {
38371
- console.log(pc2.yellow(t("config.migrate_no_legacy")));
38805
+ getDefaultChannel().writeLine(pc.yellow(t("config.migrate_no_legacy")));
38372
38806
  return;
38373
38807
  }
38374
- console.log(t("config.migrate_start"));
38808
+ getDefaultChannel().writeLine(t("config.migrate_start"));
38375
38809
  const { config } = loadConfig2({ configDir, projectConfigPath: join53(configDir, ".mmrc") });
38376
38810
  saveConfig(config, configPath, configDir);
38377
38811
  const bakPath = configPath + ".bak";
@@ -38379,14 +38813,14 @@ function buildConfigCommands(program2) {
38379
38813
  renameSync4(configPath, bakPath);
38380
38814
  const { readdirSync: readdirSync19 } = await import("fs");
38381
38815
  const domainFiles = readdirSync19(join53(configDir, "config")).filter((f) => f.endsWith(".json"));
38382
- console.log(pc2.green(t("config.migrate_done", { count: String(domainFiles.length) })));
38816
+ getDefaultChannel().writeLine(pc.green(t("config.migrate_done", { count: String(domainFiles.length) })));
38383
38817
  });
38384
38818
  }
38385
38819
  function buildModelCommands(program2) {
38386
38820
  const model = program2.command("model").description(t("cli.manage_models"));
38387
38821
  model.command("list").description(t("cli.list_models")).action(async () => {
38388
38822
  const { config } = await bootstrap();
38389
- console.log(t("cli.current_model"), config.model);
38823
+ getDefaultChannel().writeLine(`${t("cli.current_model")} ${config.model}`);
38390
38824
  const { createProvider: createProvider2 } = await Promise.resolve().then(() => (init_create(), exports_create));
38391
38825
  const provider = createProvider2(config.provider.type, {
38392
38826
  model: config.model,
@@ -38401,30 +38835,30 @@ function buildModelCommands(program2) {
38401
38835
  const models = await provider.listModels();
38402
38836
  s.stop();
38403
38837
  if (models.length > 0) {
38404
- console.log(t("cli.available_models"));
38838
+ getDefaultChannel().writeLine(t("cli.available_models"));
38405
38839
  const { getCertMark: getCertMark2 } = await Promise.resolve().then(() => (init_manifest(), exports_manifest));
38406
38840
  for (const m of models) {
38407
38841
  const marker = m === config.model ? "* " : " ";
38408
38842
  const mark = getCertMark2(m, config.provider.baseUrl, version, process.cwd());
38409
38843
  const cert = mark === "certified" ? "✔" : mark === "stale" ? "○" : "·";
38410
- const label = mark === "certified" ? ` ${pc2.green(t("cli.cert_label"))}` : mark === "stale" ? ` ${pc2.yellow(t("cli.cert_stale_label"))}` : "";
38411
- console.log(` ${marker}${cert} ${m}${label}`);
38844
+ const label = mark === "certified" ? ` ${pc.green(t("cli.cert_label"))}` : mark === "stale" ? ` ${pc.yellow(t("cli.cert_stale_label"))}` : "";
38845
+ getDefaultChannel().writeLine(` ${marker}${cert} ${m}${label}`);
38412
38846
  }
38413
38847
  } else {
38414
- console.log(t("cli.no_models_found"));
38848
+ getDefaultChannel().writeLine(t("cli.no_models_found"));
38415
38849
  }
38416
38850
  } catch (err) {
38417
38851
  s.stop();
38418
- console.log(t("cli.model_fetch_failed", { error: String(err) }));
38852
+ getDefaultChannel().writeLine(t("cli.model_fetch_failed", { error: String(err) }));
38419
38853
  }
38420
- console.log(t("cli.model_hint"));
38854
+ getDefaultChannel().writeLine(t("cli.model_hint"));
38421
38855
  });
38422
38856
  model.command("use").argument("<name>", "Model name").description(t("cli.set_model")).action(async (name) => {
38423
38857
  const configPath = join53(homedir17(), ".mma", "config.json");
38424
38858
  const { config } = await bootstrap();
38425
38859
  config.model = name;
38426
38860
  saveConfig(config, configPath, dirname23(configPath));
38427
- console.log(t("cli.model_set", { name }));
38861
+ getDefaultChannel().writeLine(t("cli.model_set", { name }));
38428
38862
  });
38429
38863
  model.command("certify").argument("<name>", "Model name").option("--provider-url <url>", t("cli.cert_provider_url")).option("--provider-key <key>", t("cli.cert_provider_key")).option("--context-window <n>", t("cli.cert_context_window")).option("--tags <tags>", t("cli.cert_tags"), "core").option("--scenarios <ids>", t("cli.cert_scenarios")).option("--timeout <ms>", t("cli.cert_timeout")).option("--reps <n>", t("cli.cert_reps")).option("--force", t("cli.cert_force")).option("--clean", t("cli.cert_clean")).description(t("cli.certify")).action(async (name, cmdOpts) => {
38430
38864
  const { config } = await bootstrap();
@@ -38467,26 +38901,26 @@ function buildContextCommand(program2) {
38467
38901
  const key = opts.system !== undefined ? "system" : "reserve";
38468
38902
  const value = Number(opts.system ?? opts.reserve);
38469
38903
  if (setBudgetShare(config, key, value) !== null) {
38470
- console.log(t("cli.context_invalid_fraction"));
38904
+ getDefaultChannel().writeLine(t("cli.context_invalid_fraction"));
38471
38905
  return;
38472
38906
  }
38473
38907
  saveConfig(config, configPath, dirname23(configPath));
38474
- console.log(t("cli.context_fraction_set", { key, value }));
38908
+ getDefaultChannel().writeLine(t("cli.context_fraction_set", { key, value }));
38475
38909
  return;
38476
38910
  }
38477
38911
  if (size === undefined) {
38478
38912
  for (const line of budgetBreakdownLines(config))
38479
- console.log(line);
38913
+ getDefaultChannel().writeLine(line);
38480
38914
  return;
38481
38915
  }
38482
38916
  const contextWindow = parseInt(size, 10);
38483
38917
  if (isNaN(contextWindow) || contextWindow < 1024) {
38484
- console.log(t("cli.invalid_context_size"));
38918
+ getDefaultChannel().writeLine(t("cli.invalid_context_size"));
38485
38919
  return;
38486
38920
  }
38487
38921
  config.contextWindow = contextWindow;
38488
38922
  saveConfig(config, configPath, dirname23(configPath));
38489
- console.log(t("cli.context_set", { size: contextWindow }));
38923
+ getDefaultChannel().writeLine(t("cli.context_set", { size: contextWindow }));
38490
38924
  });
38491
38925
  }
38492
38926
  function buildUsageCommand(program2) {
@@ -38497,43 +38931,43 @@ function buildUsageCommand(program2) {
38497
38931
  log: (level, message) => level === "warn" ? logger4.warn(message) : logger4.debug(message)
38498
38932
  });
38499
38933
  if (result.reason === "unsupported") {
38500
- console.log(t("cli.usage_unsupported", { provider }));
38934
+ getDefaultChannel().writeLine(t("cli.usage_unsupported", { provider }));
38501
38935
  return;
38502
38936
  }
38503
38937
  if (result.reason === "no-key") {
38504
- console.log(t("cli.usage_no_key"));
38938
+ getDefaultChannel().writeLine(t("cli.usage_no_key"));
38505
38939
  return;
38506
38940
  }
38507
38941
  if (result.reason === "error" || !result.budget) {
38508
- console.log(t("cli.usage_error", { error: result.error ?? "" }));
38942
+ getDefaultChannel().writeLine(t("cli.usage_error", { error: result.error ?? "" }));
38509
38943
  return;
38510
38944
  }
38511
38945
  const b = result.budget;
38512
38946
  let printed = false;
38513
38947
  if (b.keyUsageUsd !== undefined) {
38514
- console.log(t("cli.usage_key_usage", { usage: formatCost(b.keyUsageUsd) }));
38948
+ getDefaultChannel().writeLine(t("cli.usage_key_usage", { usage: formatCost(b.keyUsageUsd) }));
38515
38949
  printed = true;
38516
38950
  }
38517
38951
  if (b.keyLimitUsd !== undefined && b.keyRemainingUsd !== undefined) {
38518
- console.log(t("cli.usage_key_limit", {
38952
+ getDefaultChannel().writeLine(t("cli.usage_key_limit", {
38519
38953
  limit: formatCost(b.keyLimitUsd),
38520
38954
  remaining: formatCost(b.keyRemainingUsd)
38521
38955
  }));
38522
38956
  printed = true;
38523
38957
  }
38524
38958
  if (b.balanceUsd !== undefined) {
38525
- console.log(t("cli.usage_balance", { balance: formatCost(b.balanceUsd) }));
38959
+ getDefaultChannel().writeLine(t("cli.usage_balance", { balance: formatCost(b.balanceUsd) }));
38526
38960
  printed = true;
38527
38961
  }
38528
38962
  if (b.totalCreditsUsd !== undefined && b.totalUsageUsd !== undefined) {
38529
- console.log(t("cli.usage_account", {
38963
+ getDefaultChannel().writeLine(t("cli.usage_account", {
38530
38964
  credits: formatCost(b.totalCreditsUsd),
38531
38965
  used: formatCost(b.totalUsageUsd)
38532
38966
  }));
38533
38967
  printed = true;
38534
38968
  }
38535
38969
  if (!printed)
38536
- console.log(t("cli.usage_empty"));
38970
+ getDefaultChannel().writeLine(t("cli.usage_empty"));
38537
38971
  });
38538
38972
  }
38539
38973
  function buildMapCommand(program2) {
@@ -38541,11 +38975,11 @@ function buildMapCommand(program2) {
38541
38975
  const { agent } = await bootstrap();
38542
38976
  const indexer = agent.getModule("indexer");
38543
38977
  if (!indexer) {
38544
- console.log(t("indexer.not_indexed"));
38978
+ getDefaultChannel().writeLine(t("indexer.not_indexed"));
38545
38979
  return;
38546
38980
  }
38547
38981
  const result = await runMapAction(indexer, action, query);
38548
- console.log(result.output);
38982
+ getDefaultChannel().writeLine(result.output);
38549
38983
  });
38550
38984
  }
38551
38985
  function buildProviderCommands(program2) {
@@ -38563,25 +38997,25 @@ function buildProviderCommands(program2) {
38563
38997
  timeoutMs: opts.timeout ? Number(opts.timeout) : 5000
38564
38998
  });
38565
38999
  for (const r of results) {
38566
- const mark = r.ok ? pc2.green("✓") : pc2.red("✗");
38567
- const detail = r.ok ? pc2.dim(`${r.ms}ms, ${r.models} models`) : pc2.red(r.error ?? "failed");
38568
- console.log(` ${mark} ${r.name.padEnd(16)} ${detail}`);
39000
+ const mark = r.ok ? pc.green("✓") : pc.red("✗");
39001
+ const detail = r.ok ? pc.dim(`${r.ms}ms, ${r.models} models`) : pc.red(r.error ?? "failed");
39002
+ getDefaultChannel().writeLine(` ${mark} ${r.name.padEnd(16)} ${detail}`);
38569
39003
  }
38570
39004
  });
38571
39005
  provider.command("list").description(t("cli.list_providers")).action(async () => {
38572
39006
  const { config, agent } = await bootstrap();
38573
39007
  const providers = agent.listProviders();
38574
39008
  if (providers.length > 0) {
38575
- console.log(t("cli.current_provider"));
39009
+ getDefaultChannel().writeLine(t("cli.current_provider"));
38576
39010
  for (const p of providers) {
38577
- const marker = p.active ? pc2.green("* ") : " ";
38578
- const prio = p.priority !== undefined ? ` ${pc2.dim(`prio=${p.priority}`)}` : "";
38579
- console.log(` ${marker}${p.label} (${pc2.dim(p.type)}) ${pc2.dim(p.baseUrl)}${prio}`);
39011
+ const marker = p.active ? pc.green("* ") : " ";
39012
+ const prio = p.priority !== undefined ? ` ${pc.dim(`prio=${p.priority}`)}` : "";
39013
+ getDefaultChannel().writeLine(` ${marker}${p.label} (${pc.dim(p.type)}) ${pc.dim(p.baseUrl)}${prio}`);
38580
39014
  }
38581
39015
  return;
38582
39016
  }
38583
- console.log(t("cli.current_provider"), config.provider.type);
38584
- console.log(t("cli.base_url"), config.provider.baseUrl);
39017
+ getDefaultChannel().writeLine(`${t("cli.current_provider")} ${config.provider.type}`);
39018
+ getDefaultChannel().writeLine(`${t("cli.base_url")} ${config.provider.baseUrl}`);
38585
39019
  });
38586
39020
  provider.command("use").argument("<name>", "Provider name").description(t("cli.set_provider")).action(async (name) => {
38587
39021
  const configPath = join53(homedir17(), ".mma", "config.json");
@@ -38589,9 +39023,9 @@ function buildProviderCommands(program2) {
38589
39023
  if (config.provider.entries && config.provider.entries.length > 0) {
38590
39024
  try {
38591
39025
  await agent.setProvider(name);
38592
- console.log(t("cli.provider_set", { name }));
39026
+ getDefaultChannel().writeLine(t("cli.provider_set", { name }));
38593
39027
  } catch (e) {
38594
- console.log(pc2.red(e.message));
39028
+ getDefaultChannel().writeLine(pc.red(e.message));
38595
39029
  }
38596
39030
  return;
38597
39031
  }
@@ -38601,9 +39035,9 @@ function buildProviderCommands(program2) {
38601
39035
  config.provider.baseUrl = baseUrl;
38602
39036
  }
38603
39037
  saveConfig(config, configPath, dirname23(configPath));
38604
- console.log(t("cli.provider_set", { name }));
39038
+ getDefaultChannel().writeLine(t("cli.provider_set", { name }));
38605
39039
  if (baseUrl) {
38606
- console.log(t("cli.provider_base_hint", { baseUrl }));
39040
+ getDefaultChannel().writeLine(t("cli.provider_base_hint", { baseUrl }));
38607
39041
  }
38608
39042
  });
38609
39043
  provider.command("add").argument("<name>", "Provider type or label").option("--url <url>", "Base URL").option("--key <key>", "API key").option("--priority <n>", "Fallback priority (lower = tried first)").option("--context-window <n>", "Context window override for this entry").option("--rpm <n>", "Max requests per minute for this entry").option("--parallel <n>", "Max parallel tasks for this entry").description(t("cli.add_provider")).action(async (name, opts) => {
@@ -38620,7 +39054,7 @@ function buildProviderCommands(program2) {
38620
39054
  }
38621
39055
  const baseUrl = opts.url || HOSTED_BASE_URLS[name] || HOSTED_BASE_URLS[`opencode-${name}`] || "";
38622
39056
  if (!baseUrl) {
38623
- console.log(pc2.red(t("cli.provider_no_url", { name })));
39057
+ getDefaultChannel().writeLine(pc.red(t("cli.provider_no_url", { name })));
38624
39058
  return;
38625
39059
  }
38626
39060
  entries.push({
@@ -38640,8 +39074,8 @@ function buildProviderCommands(program2) {
38640
39074
  config.provider.entries = entries;
38641
39075
  config.provider.active = config.provider.active || config.provider.type;
38642
39076
  saveConfig(config, configPath, dirname23(configPath));
38643
- console.log(pc2.green(t("cli.provider_added", { name })));
38644
- console.log(t("cli.provider_switch_hint"));
39077
+ getDefaultChannel().writeLine(pc.green(t("cli.provider_added", { name })));
39078
+ getDefaultChannel().writeLine(t("cli.provider_switch_hint"));
38645
39079
  });
38646
39080
  }
38647
39081
  function buildSessionCommands(program2) {
@@ -38650,45 +39084,45 @@ function buildSessionCommands(program2) {
38650
39084
  const { sessionManager } = await bootstrap();
38651
39085
  const sessions = sessionManager.list();
38652
39086
  if (sessions.length === 0) {
38653
- console.log(t("session.no_sessions"));
39087
+ getDefaultChannel().writeLine(t("session.no_sessions"));
38654
39088
  return;
38655
39089
  }
38656
39090
  const active = sessionManager.getActive();
38657
39091
  for (const s of sessions) {
38658
39092
  const marker = s.id === active ? "*" : " ";
38659
- console.log(` ${marker} ${s.id.slice(0, 12)} ${s.name} ${s.messageCount} msgs ${s.updatedAt.slice(0, 10)}`);
39093
+ getDefaultChannel().writeLine(` ${marker} ${s.id.slice(0, 12)} ${s.name} ${s.messageCount} msgs ${s.updatedAt.slice(0, 10)}`);
38660
39094
  }
38661
39095
  });
38662
39096
  session2.command("show").argument("<id>", "Session id").description(t("cli.show_details")).action(async (id) => {
38663
39097
  const { sessionManager } = await bootstrap();
38664
39098
  const meta = sessionManager.get(id);
38665
39099
  if (!meta) {
38666
- console.log(t("session.not_found", { id }));
39100
+ getDefaultChannel().writeLine(t("session.not_found", { id }));
38667
39101
  return;
38668
39102
  }
38669
- console.log(`ID: ${meta.id}`);
38670
- console.log(`Name: ${meta.name}`);
38671
- console.log(`Created: ${meta.createdAt}`);
38672
- console.log(`Updated: ${meta.updatedAt}`);
38673
- console.log(`Messages: ${meta.messageCount}`);
38674
- console.log(`Model: ${meta.model}`);
38675
- console.log(`Context: ${meta.contextWindow}`);
38676
- console.log(`Project: ${meta.projectDir}`);
39103
+ getDefaultChannel().writeLine(`ID: ${meta.id}`);
39104
+ getDefaultChannel().writeLine(`Name: ${meta.name}`);
39105
+ getDefaultChannel().writeLine(`Created: ${meta.createdAt}`);
39106
+ getDefaultChannel().writeLine(`Updated: ${meta.updatedAt}`);
39107
+ getDefaultChannel().writeLine(`Messages: ${meta.messageCount}`);
39108
+ getDefaultChannel().writeLine(`Model: ${meta.model}`);
39109
+ getDefaultChannel().writeLine(`Context: ${meta.contextWindow}`);
39110
+ getDefaultChannel().writeLine(`Project: ${meta.projectDir}`);
38677
39111
  const moeEvents = sessionManager.loadSessionLog(id).filter((e) => e.type.startsWith("moe_"));
38678
39112
  if (moeEvents.length > 0) {
38679
- console.log("");
38680
- console.log(pc2.cyan("MoE events:"));
39113
+ getDefaultChannel().writeLine("");
39114
+ getDefaultChannel().writeLine(pc.cyan("MoE events:"));
38681
39115
  for (const e of moeEvents) {
38682
39116
  const ts = e.ts.slice(11, 19);
38683
39117
  if (e.type === "moe_subtask") {
38684
- console.log(` ${pc2.dim(ts)} [subtask] ${e.subtaskId} (${e.expertTag}) ${e.status ?? ""}${e.durationMs !== undefined ? ` ${e.durationMs}ms` : ""}`);
39118
+ getDefaultChannel().writeLine(` ${pc.dim(ts)} [subtask] ${e.subtaskId} (${e.expertTag}) ${e.status ?? ""}${e.durationMs !== undefined ? ` ${e.durationMs}ms` : ""}`);
38685
39119
  } else if (e.type === "moe_plan") {
38686
- console.log(` ${pc2.dim(ts)} [plan] ${e.status === "ok" ? e.subtaskIds?.join(", ") : e.status}`);
39120
+ getDefaultChannel().writeLine(` ${pc.dim(ts)} [plan] ${e.status === "ok" ? e.subtaskIds?.join(", ") : e.status}`);
38687
39121
  } else if (e.type === "moe_replan") {
38688
- console.log(` ${pc2.dim(ts)} [replan] cycle ${e.cycle}: ${e.subtaskIds?.join(", ")}`);
39122
+ getDefaultChannel().writeLine(` ${pc.dim(ts)} [replan] cycle ${e.cycle}: ${e.subtaskIds?.join(", ")}`);
38689
39123
  } else {
38690
39124
  const usage = e.usageByTag ? " | usage: " + Object.entries(e.usageByTag).map(([tag, u]) => `${tag}=${u.totalTokens}t`).join(", ") : "";
38691
- console.log(` ${pc2.dim(ts)} [verify] ${e.decision ?? e.status ?? "?"}${e.explanation ? ` — ${e.explanation}` : ""}${usage}`);
39125
+ getDefaultChannel().writeLine(` ${pc.dim(ts)} [verify] ${e.decision ?? e.status ?? "?"}${e.explanation ? ` — ${e.explanation}` : ""}${usage}`);
38692
39126
  }
38693
39127
  }
38694
39128
  }
@@ -38702,15 +39136,15 @@ function buildSessionCommands(program2) {
38702
39136
  completion += e.completionTokens ?? 0;
38703
39137
  cached += e.cachedTokens ?? 0;
38704
39138
  }
38705
- console.log("");
38706
- console.log(pc2.cyan(t("cli.session_usage", {
39139
+ getDefaultChannel().writeLine("");
39140
+ getDefaultChannel().writeLine(pc.cyan(t("cli.session_usage", {
38707
39141
  prompt,
38708
39142
  completion,
38709
39143
  total: prompt + completion
38710
39144
  })));
38711
39145
  if (cached > 0 && prompt > 0) {
38712
39146
  const hit = Math.round(cached / prompt * 100);
38713
- console.log(pc2.dim(t("cli.session_cache", {
39147
+ getDefaultChannel().writeLine(pc.dim(t("cli.session_cache", {
38714
39148
  hit,
38715
39149
  cached,
38716
39150
  uncached: Math.max(0, prompt - cached)
@@ -38721,32 +39155,32 @@ function buildSessionCommands(program2) {
38721
39155
  session2.command("delete").argument("<id>", "Session id").description(t("cli.delete_session")).action(async (id) => {
38722
39156
  const { sessionManager } = await bootstrap();
38723
39157
  sessionManager.delete(id);
38724
- console.log(t("session.deleted", { id }));
39158
+ getDefaultChannel().writeLine(t("session.deleted", { id }));
38725
39159
  });
38726
39160
  }
38727
39161
  function buildChangelogCommand(program2) {
38728
39162
  program2.command("changelog").description(t("cli.changelog_title", { version })).option("--from <version>", t("cli.changelog_range", { from: "..." })).action((opts) => {
38729
39163
  const changelog = readChangelog("micro-models-agent");
38730
39164
  if (!changelog) {
38731
- console.log(pc2.yellow(t("cli.changelog_not_found")));
39165
+ getDefaultChannel().writeLine(pc.yellow(t("cli.changelog_not_found")));
38732
39166
  return;
38733
39167
  }
38734
39168
  if (opts.from) {
38735
39169
  const range = extractChangelogRange(changelog, opts.from, version);
38736
39170
  if (!range) {
38737
- console.log(pc2.yellow(t("cli.changelog_not_found")));
39171
+ getDefaultChannel().writeLine(pc.yellow(t("cli.changelog_not_found")));
38738
39172
  return;
38739
39173
  }
38740
- console.log(pc2.cyan(t("cli.changelog_range", { from: opts.from })));
38741
- console.log(range);
39174
+ getDefaultChannel().writeLine(pc.cyan(t("cli.changelog_range", { from: opts.from })));
39175
+ getDefaultChannel().writeLine(range);
38742
39176
  } else {
38743
39177
  const latest = extractLatestChangelog(changelog);
38744
39178
  if (!latest) {
38745
- console.log(pc2.yellow(t("cli.changelog_not_found")));
39179
+ getDefaultChannel().writeLine(pc.yellow(t("cli.changelog_not_found")));
38746
39180
  return;
38747
39181
  }
38748
- console.log(pc2.cyan(t("cli.changelog_title", { version })));
38749
- console.log(latest);
39182
+ getDefaultChannel().writeLine(pc.cyan(t("cli.changelog_title", { version })));
39183
+ getDefaultChannel().writeLine(latest);
38750
39184
  }
38751
39185
  });
38752
39186
  }
@@ -38781,11 +39215,11 @@ init_bootstrap();
38781
39215
 
38782
39216
  // src/cli/repl.ts
38783
39217
  init_colors();
38784
- import * as readline3 from "readline";
39218
+ import * as readline2 from "readline";
38785
39219
 
38786
39220
  // src/ui/line-editor.ts
38787
39221
  init_string_width();
38788
- import * as readline2 from "readline";
39222
+ import * as readline from "readline";
38789
39223
 
38790
39224
  // src/ui/line-math.ts
38791
39225
  init_string_width();
@@ -38907,6 +39341,10 @@ class LineEditor {
38907
39341
  frameTopAbs = null;
38908
39342
  dsrPending = false;
38909
39343
  dsrTail = "";
39344
+ dsrQueryRow = 0;
39345
+ inputEnabled = true;
39346
+ frameSuspended = false;
39347
+ dsrTimer = null;
38910
39348
  constructor(opts) {
38911
39349
  this.input = opts.input;
38912
39350
  this.output = opts.output;
@@ -38925,9 +39363,10 @@ class LineEditor {
38925
39363
  this.enableTerminalProtocols();
38926
39364
  this.dsrDataHandler = (buf) => this.consumeDsrReplies(buf.toString("utf-8"));
38927
39365
  this.input.on("data", this.dsrDataHandler);
38928
- readline2.emitKeypressEvents(this.input);
39366
+ readline.emitKeypressEvents(this.input);
38929
39367
  this.keypressHandler = (str, key) => this.onKey(str, key);
38930
39368
  this.input.on("keypress", this.keypressHandler);
39369
+ this.input.resume?.();
38931
39370
  } else {
38932
39371
  this.dataHandler = (buf) => this.onData(buf);
38933
39372
  this.input.on("data", this.dataHandler);
@@ -38964,6 +39403,61 @@ class LineEditor {
38964
39403
  write(s) {
38965
39404
  this.insertText(s);
38966
39405
  }
39406
+ setInputEnabled(enabled2) {
39407
+ this.inputEnabled = enabled2;
39408
+ }
39409
+ isInputEnabled() {
39410
+ return this.inputEnabled;
39411
+ }
39412
+ isFrameSuspended() {
39413
+ return this.frameSuspended;
39414
+ }
39415
+ suspendFrame() {
39416
+ if (!this.input.isTTY || this.isDone)
39417
+ return;
39418
+ const out = [];
39419
+ if (this.frameTopAbs !== null)
39420
+ out.push(`\x1B[${this.frameTopAbs};1H`);
39421
+ else if (this.prevCursorRow > 0)
39422
+ out.push(`\x1B[${this.prevCursorRow}A`);
39423
+ out.push("\r\x1B[J");
39424
+ this.output.write(out.join(""));
39425
+ this.invalidateAnchor();
39426
+ this.frameSuspended = true;
39427
+ }
39428
+ resumeFrame() {
39429
+ this.frameSuspended = false;
39430
+ this.invalidateAnchor();
39431
+ this.render();
39432
+ }
39433
+ printAbove(text) {
39434
+ if (!this.input.isTTY || this.isDone) {
39435
+ this.output.write(text.endsWith(`
39436
+ `) ? text : `${text}
39437
+ `);
39438
+ return;
39439
+ }
39440
+ const wasSuspended = this.frameSuspended;
39441
+ this.frameSuspended = false;
39442
+ const out = [];
39443
+ if (this.frameTopAbs !== null)
39444
+ out.push(`\x1B[${this.frameTopAbs};1H`);
39445
+ else if (this.prevCursorRow > 0)
39446
+ out.push(`\x1B[${this.prevCursorRow}A`);
39447
+ out.push("\r\x1B[J");
39448
+ out.push(text.replace(/\r\n/g, `
39449
+ `).replace(/\n$/, "").split(`
39450
+ `).join(`\r
39451
+ `));
39452
+ out.push(`\r
39453
+ `);
39454
+ this.output.write(out.join(""));
39455
+ this.invalidateAnchor();
39456
+ if (wasSuspended)
39457
+ this.frameSuspended = true;
39458
+ else
39459
+ this.render();
39460
+ }
38967
39461
  reset() {
38968
39462
  this.lines = [""];
38969
39463
  this.row = 0;
@@ -39001,6 +39495,10 @@ class LineEditor {
39001
39495
  if (this.rawMode && this.input.setRawMode) {
39002
39496
  this.input.setRawMode(false);
39003
39497
  }
39498
+ if (this.dsrTimer) {
39499
+ clearTimeout(this.dsrTimer);
39500
+ this.dsrTimer = null;
39501
+ }
39004
39502
  this.emitClose();
39005
39503
  }
39006
39504
  onData(buf) {
@@ -39029,6 +39527,18 @@ class LineEditor {
39029
39527
  onKey(str, key) {
39030
39528
  if (this.isDone)
39031
39529
  return;
39530
+ if (!this.inputEnabled) {
39531
+ const k2 = key;
39532
+ if (k2?.ctrl && k2.name === "c") {
39533
+ this.ctrlC();
39534
+ return;
39535
+ }
39536
+ if (k2?.name === "escape") {
39537
+ this.onKeyInput?.(str, key);
39538
+ return;
39539
+ }
39540
+ return;
39541
+ }
39032
39542
  if (this.onKeyInput && this.onKeyInput(str, key))
39033
39543
  return;
39034
39544
  const k = key;
@@ -39041,6 +39551,8 @@ class LineEditor {
39041
39551
  }
39042
39552
  return;
39043
39553
  }
39554
+ if (/^\x1b\[\d+;\d+R$/.test(seq2))
39555
+ return;
39044
39556
  if (name === "paste-start" || seq2 === "\x1B[200~") {
39045
39557
  this.isPaste = true;
39046
39558
  this.pasteBuffer = "";
@@ -39557,6 +40069,13 @@ class LineEditor {
39557
40069
  const r = this.output.rows;
39558
40070
  return typeof r === "number" && r > 3 ? r : null;
39559
40071
  }
40072
+ dsrEnabled() {
40073
+ if (process.env.MMA_DSR === "1")
40074
+ return true;
40075
+ if (process.env.MMA_DSR === "0")
40076
+ return false;
40077
+ return process.platform !== "win32";
40078
+ }
39560
40079
  visibleLayout() {
39561
40080
  const layout = this.layout();
39562
40081
  const H = this.screenRows();
@@ -39571,6 +40090,10 @@ class LineEditor {
39571
40090
  this.dsrPending = false;
39572
40091
  this.dsrTail = "";
39573
40092
  this.prevCursorRow = 0;
40093
+ if (this.dsrTimer) {
40094
+ clearTimeout(this.dsrTimer);
40095
+ this.dsrTimer = null;
40096
+ }
39574
40097
  }
39575
40098
  consumeDsrReplies(chunk) {
39576
40099
  this.dsrTail = (this.dsrTail + chunk).slice(-80);
@@ -39582,13 +40105,17 @@ class LineEditor {
39582
40105
  return;
39583
40106
  this.dsrPending = false;
39584
40107
  const row = Number(m[1]);
39585
- const idx = Number(m[2]);
39586
- const top = row - this.prevCursorRow;
39587
- if (top >= 1)
40108
+ if (this.dsrTimer) {
40109
+ clearTimeout(this.dsrTimer);
40110
+ this.dsrTimer = null;
40111
+ }
40112
+ const top = row - this.dsrQueryRow;
40113
+ const H = this.screenRows();
40114
+ if (top >= 1 && (H === null || top <= H))
39588
40115
  this.frameTopAbs = top;
39589
40116
  }
39590
40117
  render() {
39591
- if (!this.input.isTTY || this.isDone)
40118
+ if (!this.input.isTTY || this.isDone || this.frameSuspended)
39592
40119
  return;
39593
40120
  const layout = this.visibleLayout();
39594
40121
  const promptWidth = stringWidth(stripAnsi2(this.promptStr));
@@ -39621,6 +40148,7 @@ class LineEditor {
39621
40148
  if (ccol > 0)
39622
40149
  out.push(`\x1B[${ccol}C`);
39623
40150
  this.output.write(out.join(""));
40151
+ this.prevCursorRow = idx;
39624
40152
  if (this.frameTopAbs !== null) {
39625
40153
  const H = this.screenRows();
39626
40154
  if (H) {
@@ -39629,8 +40157,17 @@ class LineEditor {
39629
40157
  if (T + L - 1 > H)
39630
40158
  this.frameTopAbs = H - L + 1;
39631
40159
  }
39632
- } else if (!this.dsrPending) {}
39633
- this.prevCursorRow = idx;
40160
+ } else if (!this.dsrPending && this.questionCb === null && this.dsrEnabled()) {
40161
+ this.dsrPending = true;
40162
+ this.dsrQueryRow = idx;
40163
+ this.output.write("\x1B[6n");
40164
+ if (this.dsrTimer)
40165
+ clearTimeout(this.dsrTimer);
40166
+ this.dsrTimer = setTimeout(() => {
40167
+ this.dsrPending = false;
40168
+ this.dsrTimer = null;
40169
+ }, 150);
40170
+ }
39634
40171
  }
39635
40172
  enableTerminalProtocols() {
39636
40173
  this.output.write("\x1B[?2004h");
@@ -39649,8 +40186,8 @@ class LineEditor {
39649
40186
  }
39650
40187
 
39651
40188
  // src/cli/repl.ts
39652
- import { existsSync as existsSync60, readFileSync as readFileSync41, writeFileSync as writeFileSync24 } from "fs";
39653
- import { join as join55 } from "path";
40189
+ import { existsSync as existsSync60, mkdirSync as mkdirSync23, readFileSync as readFileSync41, writeFileSync as writeFileSync24 } from "fs";
40190
+ import { dirname as dirname25, join as join55 } from "path";
39654
40191
  import { homedir as homedir18 } from "os";
39655
40192
 
39656
40193
  // src/cli/completer.ts
@@ -39783,6 +40320,7 @@ init_colors();
39783
40320
 
39784
40321
  // src/ui/md-formatter.ts
39785
40322
  init_colors();
40323
+ init_string_width();
39786
40324
  init_i18n();
39787
40325
  init_table();
39788
40326
  var KW = /\b(import|export|from|const|let|var|function|return|if|else|for|while|do|switch|case|break|continue|new|class|extends|implements|interface|type|enum|namespace|module|declare|abstract|async|await|yield|throw|try|catch|finally|typeof|instanceof|in|of|as|is|keyof|readonly|static|private|public|protected|get|set|constructor|this|super|void|never|any|unknown|boolean|string|number|symbol|object|true|false|null|undefined|default)\b/g;
@@ -39793,24 +40331,24 @@ var TAG = /<\/?([A-Z][a-zA-Z0-9]*|[a-z][a-zA-Z0-9-]*)/g;
39793
40331
  var ATTR = /\b([a-zA-Z-]+=)"([^"]*)"/g;
39794
40332
  function highlight(code, lang) {
39795
40333
  if (lang === "html" || lang === "xml" || lang === "svg") {
39796
- code = code.replace(COMMENT, (m) => pc2.dim(pc2.green(m)));
39797
- code = code.replace(ATTR, (_m, attr, val) => pc2.yellow(attr) + "=" + pc2.green('"' + val + '"'));
39798
- code = code.replace(TAG, (_m, tag) => "<" + pc2.cyan(tag));
40334
+ code = code.replace(COMMENT, (m) => pc.dim(pc.green(m)));
40335
+ code = code.replace(ATTR, (_m, attr, val) => pc.yellow(attr) + "=" + pc.green('"' + val + '"'));
40336
+ code = code.replace(TAG, (_m, tag) => "<" + pc.cyan(tag));
39799
40337
  } else if (lang === "css" || lang === "scss" || lang === "less") {
39800
- code = code.replace(COMMENT, (m) => pc2.dim(pc2.green(m)));
39801
- code = code.replace(STRING, (m) => pc2.green(m));
39802
- code = code.replace(NUMBER, (m) => pc2.yellow(m));
40338
+ code = code.replace(COMMENT, (m) => pc.dim(pc.green(m)));
40339
+ code = code.replace(STRING, (m) => pc.green(m));
40340
+ code = code.replace(NUMBER, (m) => pc.yellow(m));
39803
40341
  } else if (lang === "bash" || lang === "sh" || lang === "shell" || lang === "zsh") {
39804
- code = code.replace(COMMENT, (m) => pc2.dim(pc2.green(m)));
39805
- code = code.replace(STRING, (m) => pc2.green(m));
40342
+ code = code.replace(COMMENT, (m) => pc.dim(pc.green(m)));
40343
+ code = code.replace(STRING, (m) => pc.green(m));
39806
40344
  } else if (lang === "json") {
39807
- code = code.replace(STRING, (m) => pc2.green(m));
39808
- code = code.replace(NUMBER, (m) => pc2.yellow(m));
40345
+ code = code.replace(STRING, (m) => pc.green(m));
40346
+ code = code.replace(NUMBER, (m) => pc.yellow(m));
39809
40347
  } else {
39810
- code = code.replace(COMMENT, (m) => pc2.dim(pc2.green(m)));
39811
- code = code.replace(STRING, (m) => pc2.green(m));
39812
- code = code.replace(KW, (m) => pc2.magenta(m));
39813
- code = code.replace(NUMBER, (m) => pc2.yellow(m));
40348
+ code = code.replace(COMMENT, (m) => pc.dim(pc.green(m)));
40349
+ code = code.replace(STRING, (m) => pc.green(m));
40350
+ code = code.replace(KW, (m) => pc.magenta(m));
40351
+ code = code.replace(NUMBER, (m) => pc.yellow(m));
39814
40352
  }
39815
40353
  return code;
39816
40354
  }
@@ -39835,10 +40373,15 @@ class FormattingStream {
39835
40373
  onRawWrite;
39836
40374
  width;
39837
40375
  partialWritten = 0;
39838
- constructor(onWrite, width, onRawWrite) {
40376
+ streamedChars = 0;
40377
+ reservedCols;
40378
+ streamPartials;
40379
+ constructor(onWrite, width, onRawWrite, opts = {}) {
39839
40380
  this.onWrite = onWrite;
39840
40381
  this.onRawWrite = onRawWrite ?? onWrite;
39841
40382
  this.width = width ?? getTerminalWidth();
40383
+ this.reservedCols = opts.reservedCols ?? 0;
40384
+ this.streamPartials = opts.streamPartials ?? false;
39842
40385
  }
39843
40386
  write(chunk) {
39844
40387
  this.buffer += chunk;
@@ -39851,15 +40394,47 @@ class FormattingStream {
39851
40394
  this.processLine(line);
39852
40395
  }
39853
40396
  if (this.buffer.length > 0 && !this.inCodeBlock) {
39854
- this.onRawWrite(this.buffer);
39855
- this.partialWritten = this.buffer.length;
39856
- this.buffer = "";
40397
+ this.streamPartial();
39857
40398
  }
39858
40399
  }
40400
+ streamPartial() {
40401
+ if (!this.streamPartials)
40402
+ return;
40403
+ const available = Math.max(1, this.width - this.reservedCols);
40404
+ if (stringWidth(this.buffer) > available)
40405
+ return;
40406
+ const delta = this.buffer.slice(this.streamedChars);
40407
+ if (!delta)
40408
+ return;
40409
+ this.onRawWrite(delta);
40410
+ this.streamedChars = this.buffer.length;
40411
+ this.partialWritten = stringWidth(this.buffer);
40412
+ }
39859
40413
  emitPartialRewind() {
39860
40414
  if (this.partialWritten > 0) {
39861
- this.onRawWrite(`\x1B[${this.partialWritten}D`);
40415
+ this.onRawWrite(`\x1B[${this.partialWritten}D\x1B[K`);
40416
+ this.partialWritten = 0;
40417
+ }
40418
+ this.streamedChars = 0;
40419
+ }
40420
+ hasPartial() {
40421
+ return this.partialWritten > 0 || this.buffer.length > 0 || this.tableBuffer.length > 0;
40422
+ }
40423
+ flushPartialNow() {
40424
+ if (this.partialWritten > 0) {
40425
+ this.onRawWrite(`
40426
+ `);
39862
40427
  this.partialWritten = 0;
40428
+ this.streamedChars = 0;
40429
+ this.buffer = "";
40430
+ } else if (this.buffer.length > 0 && !this.inCodeBlock) {
40431
+ const line = this.buffer;
40432
+ this.buffer = "";
40433
+ this.streamedChars = 0;
40434
+ this.onWrite(this.formatLine(line));
40435
+ }
40436
+ if (this.tableBuffer.length > 0) {
40437
+ this.flushTable();
39863
40438
  }
39864
40439
  }
39865
40440
  flush() {
@@ -39874,13 +40449,16 @@ class FormattingStream {
39874
40449
  if (this.codeLines.length > 0) {
39875
40450
  this.emitCodeBlock();
39876
40451
  }
40452
+ this.streamedChars = 0;
39877
40453
  return;
39878
40454
  }
39879
40455
  if (this.buffer.length > 0) {
39880
40456
  const line = this.buffer;
39881
40457
  this.buffer = "";
40458
+ this.emitPartialRewind();
39882
40459
  this.onWrite(this.formatLine(line));
39883
40460
  }
40461
+ this.streamedChars = 0;
39884
40462
  }
39885
40463
  processLine(line) {
39886
40464
  if (line.trim() === "```" || line.trim().startsWith("```")) {
@@ -39927,13 +40505,13 @@ class FormattingStream {
39927
40505
  `);
39928
40506
  const highlighted = highlight(code, this.codeLang);
39929
40507
  const lang = this.codeLang ? ` ${this.codeLang} ` : " ";
39930
- const top = pc2.dim(`┌─${lang}${"─".repeat(Math.max(0, this.width - 3 - lang.length))}┐`);
40508
+ const top = pc.dim(`┌─${lang}${"─".repeat(Math.max(0, this.width - 3 - lang.length))}┐`);
39931
40509
  this.onWrite(top);
39932
40510
  for (const l of highlighted.split(`
39933
40511
  `)) {
39934
- this.onWrite(pc2.dim("│ ") + l);
40512
+ this.onWrite(pc.dim("│ ") + l);
39935
40513
  }
39936
- this.onWrite(pc2.dim(`└${"─".repeat(Math.max(0, this.width - 1))}┘`));
40514
+ this.onWrite(pc.dim(`└${"─".repeat(Math.max(0, this.width - 1))}┘`));
39937
40515
  }
39938
40516
  this.codeLines = [];
39939
40517
  this.codeLang = "";
@@ -39945,54 +40523,54 @@ class FormattingStream {
39945
40523
  const level = heading[1].length;
39946
40524
  const content = this.formatInline(heading[2]);
39947
40525
  if (level === 1)
39948
- return pc2.cyan(pc2.bold(pc2.underline(content)));
39949
- return pc2.cyan(pc2.bold(content));
40526
+ return pc.cyan(pc.bold(pc.underline(content)));
40527
+ return pc.cyan(pc.bold(content));
39950
40528
  }
39951
40529
  if (isHorizontalRule(result)) {
39952
- return pc2.dim("─".repeat(Math.max(0, Math.min(this.width, 60))));
40530
+ return pc.dim("─".repeat(Math.max(0, Math.min(this.width, 60))));
39953
40531
  }
39954
40532
  const quote = result.match(/^(>+)\s?(.*)$/);
39955
40533
  if (quote) {
39956
40534
  const depth = Math.min(quote[1].length, 4);
39957
- const marker = pc2.dim("▍".repeat(depth));
40535
+ const marker = pc.dim("▍".repeat(depth));
39958
40536
  return `${marker} ${this.formatInline(quote[2])}`;
39959
40537
  }
39960
40538
  const checkbox = result.match(/^[-*]\s+\[([ xX])\]\s+(.+)$/);
39961
40539
  if (checkbox) {
39962
40540
  const checked = checkbox[1].toLowerCase() === "x";
39963
- const mark = checked ? pc2.green("✓") : pc2.dim("☐");
40541
+ const mark = checked ? pc.green("✓") : pc.dim("☐");
39964
40542
  return ` ${mark} ${this.formatInline(checkbox[2])}`;
39965
40543
  }
39966
40544
  const ordered = result.match(/^(\d+)[.)]\s+(.+)$/);
39967
40545
  if (ordered) {
39968
- return ` ${pc2.yellow(ordered[1])}. ${this.formatInline(ordered[2])}`;
40546
+ return ` ${pc.yellow(ordered[1])}. ${this.formatInline(ordered[2])}`;
39969
40547
  }
39970
40548
  const bullet = result.match(/^[-*]\s+(.+)$/);
39971
40549
  if (bullet) {
39972
- return ` ${pc2.dim("•")} ${this.formatInline(bullet[1])}`;
40550
+ return ` ${pc.dim("•")} ${this.formatInline(bullet[1])}`;
39973
40551
  }
39974
40552
  return this.formatInline(result);
39975
40553
  }
39976
40554
  formatInline(text) {
39977
40555
  const codeSpans = [];
39978
40556
  let result = text.replace(/`([^`]+)`/g, (_m, c) => {
39979
- codeSpans.push(pc2.yellow(c));
40557
+ codeSpans.push(pc.yellow(c));
39980
40558
  return `\x00${codeSpans.length - 1}\x00`;
39981
40559
  });
39982
- result = result.replace(/\*\*(.+?)\*\*/g, (_, s) => pc2.bold(s));
39983
- result = result.replace(/~~(.+?)~~/g, (_, s) => pc2.strikethrough(s));
39984
- result = result.replace(/\*([^*]+)\*/g, (_, s) => pc2.italic(s));
39985
- result = result.replace(/(^|\s)_([^_\n]+)_(?=\s|$)/g, (_m, pre, s) => pre + pc2.italic(s));
40560
+ result = result.replace(/\*\*(.+?)\*\*/g, (_, s) => pc.bold(s));
40561
+ result = result.replace(/~~(.+?)~~/g, (_, s) => pc.strikethrough(s));
40562
+ result = result.replace(/\*([^*]+)\*/g, (_, s) => pc.italic(s));
40563
+ result = result.replace(/(^|\s)_([^_\n]+)_(?=\s|$)/g, (_m, pre, s) => pre + pc.italic(s));
39986
40564
  result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, url) => {
39987
40565
  const short = url.length > 80 ? url.slice(0, 77) + "…" : url;
39988
- return `${pc2.cyan(label)} ${pc2.dim(`(${short})`)}`;
40566
+ return `${pc.cyan(label)} ${pc.dim(`(${short})`)}`;
39989
40567
  });
39990
40568
  result = result.replace(/\u0000(\d+)\u0000/g, (_m, i) => codeSpans[Number(i)]);
39991
40569
  return result;
39992
40570
  }
39993
40571
  }
39994
40572
  function formatWarning(text) {
39995
- return pc2.yellow(pc2.bold(t("ui.warning_prefix")) + text);
40573
+ return pc.yellow(pc.bold(t("ui.warning_prefix")) + text);
39996
40574
  }
39997
40575
 
39998
40576
  // src/ui/renderer.ts
@@ -40000,6 +40578,7 @@ init_spinner();
40000
40578
  init_table();
40001
40579
  init_i18n();
40002
40580
  init_prices();
40581
+ init_output();
40003
40582
  import { isAbsolute as isAbsolute5, relative as relative8, sep as sep2 } from "path";
40004
40583
  function formatUsd(cost) {
40005
40584
  return formatCost(cost);
@@ -40072,8 +40651,7 @@ class Renderer {
40072
40651
  rich;
40073
40652
  spinner;
40074
40653
  fmt;
40075
- out;
40076
- err;
40654
+ channel;
40077
40655
  width;
40078
40656
  baseDir;
40079
40657
  card = null;
@@ -40085,17 +40663,16 @@ class Renderer {
40085
40663
  outputSuppressed = false;
40086
40664
  constructor(opts = {}) {
40087
40665
  this.rich = opts.rich ?? isRichTerminal();
40088
- this.out = opts.out ?? process.stdout;
40089
- this.err = opts.err ?? process.stderr;
40090
40666
  this.width = opts.width ?? getTerminalWidth();
40091
40667
  this.baseDir = opts.baseDir;
40668
+ this.channel = opts.channel ?? getDefaultChannel();
40092
40669
  this.spinner = new Spinner({
40093
40670
  enabled: this.rich && (opts.spinner ?? true),
40094
- stream: this.err,
40671
+ channel: this.channel,
40095
40672
  width: this.width
40096
40673
  });
40097
- this.fmt = new FormattingStream((line) => this.out.write(`${line}
40098
- `), this.width, (text) => this.out.write(text));
40674
+ this.fmt = new FormattingStream((line) => this.channel.writeRaw(`${line}
40675
+ `), this.width, (text) => this.channel.writeRaw(text), { reservedCols: 2, streamPartials: this.rich });
40099
40676
  }
40100
40677
  showLoader() {
40101
40678
  this.spinner.start(t("ui.thinking"));
@@ -40105,8 +40682,8 @@ class Renderer {
40105
40682
  this.spinner.stop();
40106
40683
  if (!this.textStarted) {
40107
40684
  this.textStarted = true;
40108
- this.out.write(`
40109
- ${pc2.dim("-")} `);
40685
+ this.channel.writeRaw(`
40686
+ ${pc.dim("-")} `);
40110
40687
  }
40111
40688
  this.fmt.write(chunk);
40112
40689
  }
@@ -40114,15 +40691,15 @@ ${pc2.dim("-")} `);
40114
40691
  this.spinner.stop();
40115
40692
  if (this.thoughtStarted) {
40116
40693
  if (!this.thoughtHeaderPrinted) {
40117
- this.out.write(`
40118
- ${pc2.dim("→")} Thought: `);
40694
+ this.channel.writeRaw(`
40695
+ ${pc.dim("→")} Thought: `);
40119
40696
  this.thoughtHeaderPrinted = true;
40120
40697
  }
40121
- this.out.write(pc2.dim(chunk));
40698
+ this.channel.writeRaw(pc.dim(chunk));
40122
40699
  } else if (this.card) {
40123
40700
  this.writeInlineBody(chunk);
40124
40701
  } else {
40125
- this.out.write(chunk);
40702
+ this.channel.writeRaw(chunk);
40126
40703
  }
40127
40704
  }
40128
40705
  writeInlineBody(chunk) {
@@ -40135,18 +40712,18 @@ ${pc2.dim("→")} Thought: `);
40135
40712
  this.outputSuppressed = true;
40136
40713
  continue;
40137
40714
  }
40138
- this.out.write(`${GUTTER}${line}
40715
+ this.channel.writeRaw(`${GUTTER}${line}
40139
40716
  `);
40140
40717
  }
40141
40718
  }
40142
40719
  reasoning(chunk) {
40143
40720
  this.spinner.stop();
40144
40721
  if (this.thoughtStarted && !this.thoughtHeaderPrinted) {
40145
- this.out.write(`
40146
- ${pc2.dim("→")} Thought: `);
40722
+ this.channel.writeRaw(`
40723
+ ${pc.dim("→")} Thought: `);
40147
40724
  this.thoughtHeaderPrinted = true;
40148
40725
  }
40149
- this.out.write(pc2.dim(chunk));
40726
+ this.channel.writeRaw(pc.dim(chunk));
40150
40727
  }
40151
40728
  thinkingStart() {
40152
40729
  this.thoughtStarted = true;
@@ -40158,15 +40735,16 @@ ${pc2.dim("→")} Thought: `);
40158
40735
  this.spinner.stop();
40159
40736
  if (this.thoughtStarted && this.thoughtHeaderPrinted) {
40160
40737
  const duration = Date.now() - this.thoughtStartMs;
40161
- this.out.write(pc2.dim(` ${duration}ms
40738
+ this.channel.writeRaw(pc.dim(` ${duration}ms
40162
40739
  `));
40163
40740
  }
40164
40741
  this.thoughtStarted = false;
40165
40742
  this.thoughtHeaderPrinted = false;
40166
40743
  }
40167
40744
  toolStart(tool, args, stepContext, icon) {
40168
- this.endCard();
40169
40745
  this.spinner.stop();
40746
+ this.fmt.flushPartialNow();
40747
+ this.endCard();
40170
40748
  this.outputLineCount = 0;
40171
40749
  this.outputSuppressed = false;
40172
40750
  const displayArgs = PATH_TOOLS.has(tool) && typeof args.path === "string" ? { ...args, path: toDisplayPath(this.baseDir, args.path) } : args;
@@ -40175,65 +40753,70 @@ ${pc2.dim("→")} Thought: `);
40175
40753
  const label = friendlyTool(tool);
40176
40754
  this.card = { tool, args, start: Date.now() };
40177
40755
  if (stepContext) {
40178
- this.out.write(`
40179
- ${pc2.dim("↓")} ${pc2.cyan(stepContext)}
40756
+ this.channel.writeRaw(`
40757
+ ${pc.dim("↓")} ${pc.cyan(stepContext)}
40180
40758
  `);
40181
40759
  }
40182
- this.out.write(`${pc2.dim(marker)} ${label}${summary ? ` ${pc2.dim(summary)}` : ""}
40760
+ this.channel.writeRaw(`${pc.dim(marker)} ${label}${summary ? ` ${pc.dim(summary)}` : ""}
40183
40761
  `);
40184
40762
  if (!SPINNERLESS_TOOLS.has(tool)) {
40185
40763
  this.spinner.start(`${label}${summary ? ` ${summary}` : ""}`);
40186
40764
  }
40187
40765
  }
40188
40766
  planBlock(lines) {
40189
- this.endCard();
40190
40767
  this.spinner.stop();
40768
+ this.fmt.flushPartialNow();
40769
+ this.endCard();
40191
40770
  for (const line of lines) {
40192
- this.out.write(`${line}
40771
+ this.channel.writeRaw(`${line}
40193
40772
  `);
40194
40773
  }
40195
40774
  }
40196
40775
  toolEnd(_tool, duration, error, ctxDelta, costUsd) {
40197
40776
  this.spinner.stop();
40777
+ this.fmt.flushPartialNow();
40198
40778
  if (!this.card)
40199
40779
  return;
40200
- const marker = error ? pc2.red("✗") : pc2.green("✓");
40201
- let footer = `${GUTTER}${marker} ${pc2.dim(`${duration}ms`)}`;
40780
+ const marker = error ? pc.red("✗") : pc.green("✓");
40781
+ let footer = `${GUTTER}${marker} ${pc.dim(`${duration}ms`)}`;
40202
40782
  if (ctxDelta !== undefined && ctxDelta !== 0) {
40203
- const deltaStr = ctxDelta > 0 ? pc2.green(`+${ctxDelta}`) : pc2.yellow(`${ctxDelta} ↓`);
40204
- footer += ` ${pc2.dim("ctx")} ${deltaStr}`;
40783
+ const deltaStr = ctxDelta > 0 ? pc.green(`+${ctxDelta}`) : pc.yellow(`${ctxDelta} ↓`);
40784
+ footer += ` ${pc.dim("ctx")} ${deltaStr}`;
40205
40785
  }
40206
40786
  if (costUsd !== undefined && costUsd > 0) {
40207
- footer += ` ${pc2.dim("cost")} ${pc2.yellow(formatUsd(costUsd))}`;
40787
+ footer += ` ${pc.dim("cost")} ${pc.yellow(formatUsd(costUsd))}`;
40208
40788
  }
40209
- this.out.write(`${footer}
40789
+ this.channel.writeRaw(`${footer}
40210
40790
  `);
40211
40791
  if (this.outputSuppressed) {
40212
- this.out.write(`${GUTTER}${pc2.dim(`... (${this.outputLineCount - MAX_OUTPUT_LINES} more lines)`)}
40792
+ this.channel.writeRaw(`${GUTTER}${pc.dim(`... (${this.outputLineCount - MAX_OUTPUT_LINES} more lines)`)}
40213
40793
  `);
40214
40794
  }
40215
40795
  this.card = null;
40216
40796
  }
40217
40797
  raw(text) {
40218
- this.endCard();
40219
40798
  this.spinner.stop();
40220
- this.out.write(text);
40799
+ this.fmt.flushPartialNow();
40800
+ this.endCard();
40801
+ this.channel.writeRaw(text);
40221
40802
  }
40222
40803
  error(text) {
40223
- this.endCard();
40224
40804
  this.spinner.stop();
40225
- this.err.write(`${pc2.red(text)}
40226
- `);
40805
+ this.fmt.flushPartialNow();
40806
+ this.endCard();
40807
+ this.channel.writeRaw(`${pc.red(text)}
40808
+ `, "stderr");
40227
40809
  }
40228
40810
  flush() {
40229
40811
  this.endCard();
40230
40812
  this.spinner.stop();
40813
+ this.fmt.flushPartialNow();
40231
40814
  this.fmt.flush();
40232
40815
  this.textStarted = false;
40233
40816
  }
40234
40817
  footer(model, provider, durationMs) {
40235
- this.out.write(`
40236
- ${pc2.dim("▣")} ${model} · ${provider} · ${pc2.dim(`${durationMs}ms`)}
40818
+ this.channel.writeRaw(`
40819
+ ${pc.dim("▣")} ${model} · ${provider} · ${pc.dim(`${durationMs}ms`)}
40237
40820
  `);
40238
40821
  }
40239
40822
  endCard() {
@@ -40339,15 +40922,15 @@ function currentStepIndex(plan) {
40339
40922
  function stepMark(step) {
40340
40923
  switch (step.status) {
40341
40924
  case "done":
40342
- return pc2.green("[x]");
40925
+ return pc.green("[x]");
40343
40926
  case "in_progress":
40344
- return pc2.yellow("[*]");
40927
+ return pc.yellow("[*]");
40345
40928
  case "failed":
40346
- return pc2.red("[!]");
40929
+ return pc.red("[!]");
40347
40930
  case "skipped":
40348
- return pc2.dim("[-]");
40931
+ return pc.dim("[-]");
40349
40932
  default:
40350
- return pc2.dim("[ ]");
40933
+ return pc.dim("[ ]");
40351
40934
  }
40352
40935
  }
40353
40936
  function formatPlanChecklist(plan) {
@@ -40357,18 +40940,18 @@ function formatPlanChecklist(plan) {
40357
40940
  const cur = currentStepIndex(plan);
40358
40941
  const barLen = 15;
40359
40942
  const filled = Math.round(pct / 100 * barLen);
40360
- const bar = pc2.green("█".repeat(filled)) + pc2.dim("░".repeat(barLen - filled));
40943
+ const bar = pc.green("█".repeat(filled)) + pc.dim("░".repeat(barLen - filled));
40361
40944
  const title = plan.title.replace(/^\[\d+[^]]*\]\s*/, "");
40362
40945
  const lines = [
40363
- `${pc2.cyan(`[${plan.id}]`)} ${pc2.bold(title)} ${bar} ${pc2.dim(`${done}/${total} ${pct}%`)}`
40946
+ `${pc.cyan(`[${plan.id}]`)} ${pc.bold(title)} ${bar} ${pc.dim(`${done}/${total} ${pct}%`)}`
40364
40947
  ];
40365
40948
  for (let i = 0;i < plan.steps.length; i++) {
40366
40949
  const step = plan.steps[i];
40367
40950
  const active = i === cur;
40368
- const desc = active ? pc2.yellow(step.description) : pc2.dim(step.description);
40951
+ const desc = active ? pc.yellow(step.description) : pc.dim(step.description);
40369
40952
  lines.push(` ${stepMark(step)} ${step.id}. ${desc}`);
40370
40953
  for (const sub of step.subtasks ?? []) {
40371
- lines.push(` ${sub.done ? pc2.green("[x]") : pc2.dim("[ ]")} ${sub.text}`);
40954
+ lines.push(` ${sub.done ? pc.green("[x]") : pc.dim("[ ]")} ${sub.text}`);
40372
40955
  }
40373
40956
  }
40374
40957
  return lines;
@@ -40427,25 +41010,87 @@ function formatCacheLine(cache) {
40427
41010
  return;
40428
41011
  }
40429
41012
 
40430
- // src/ui/output.ts
40431
- function writeWarning(text) {
40432
- process.stdout.write(formatWarning(text) + `
41013
+ // src/cli/repl.ts
41014
+ init_output();
41015
+
41016
+ // src/tools/user-input.ts
41017
+ init_i18n();
41018
+ init_output();
41019
+ var CUSTOM_INDEX = -1;
41020
+ function parseSelection(input, optionCount, multiple) {
41021
+ const trimmed = input.trim();
41022
+ if (!trimmed)
41023
+ return null;
41024
+ const parts = trimmed.split(",").map((p) => p.trim());
41025
+ if (!multiple && parts.length > 1)
41026
+ return null;
41027
+ const indexes = [];
41028
+ for (const part of parts) {
41029
+ if (!/^\d+$/.test(part))
41030
+ return null;
41031
+ const idx = Number(part) - 1;
41032
+ if (idx < 0 || idx >= optionCount)
41033
+ return null;
41034
+ if (indexes.includes(idx))
41035
+ return null;
41036
+ indexes.push(idx);
41037
+ }
41038
+ return indexes.length ? indexes : null;
41039
+ }
41040
+ function formatMenu(question, options, opts = {}) {
41041
+ const lines = [question];
41042
+ options.forEach((opt, i) => {
41043
+ lines.push(` [${i + 1}] ${opt.label} — ${opt.description}`);
41044
+ });
41045
+ if (opts.allowCustom) {
41046
+ lines.push(` [${options.length + 1}] ${t("tool.user_input.custom_option")}`);
41047
+ }
41048
+ return lines.join(`
40433
41049
  `);
40434
41050
  }
41051
+ function choicePrompt(optionCount, multiple) {
41052
+ return multiple ? t("tool.user_input.choice_multiple") : t("tool.user_input.choice_single", { max: optionCount });
41053
+ }
41054
+
41055
+ // src/tools/prompt-io.ts
41056
+ init_i18n();
41057
+ function createPromptIO(deps) {
41058
+ return {
41059
+ async askText(question) {
41060
+ return (await deps.ask(`${question} `)).trim();
41061
+ },
41062
+ async askChoice(question, options, opts = {}) {
41063
+ const multiple = opts.multiple ?? false;
41064
+ const entryCount = options.length + (opts.allowCustom ? 1 : 0);
41065
+ if (entryCount === 0)
41066
+ return [];
41067
+ const customEntry = options.length;
41068
+ deps.print(formatMenu(question, options, opts));
41069
+ for (;; ) {
41070
+ const answer = await deps.ask(choicePrompt(entryCount, multiple));
41071
+ const parsed = parseSelection(answer, entryCount, multiple);
41072
+ if (parsed) {
41073
+ return parsed.map((i) => opts.allowCustom && i === customEntry ? CUSTOM_INDEX : i);
41074
+ }
41075
+ deps.print(t("tool.user_input.invalid"));
41076
+ }
41077
+ }
41078
+ };
41079
+ }
40435
41080
 
40436
41081
  // src/cli/repl.ts
40437
41082
  function formatContextBar(used, limit, compactions, quality) {
40438
41083
  const pct = Math.min(100, Math.round(used / limit * 100));
40439
41084
  const barLen = 20;
40440
41085
  const filled = Math.round(pct / 100 * barLen);
40441
- const bar = pc2.green("█".repeat(filled)) + pc2.dim("░".repeat(barLen - filled));
40442
- const pctStr = pct >= 75 ? pc2.yellow(`${pct}%`) : pc2.dim(`${pct}%`);
40443
- let line = ` ${bar} ${pctStr} ${pc2.dim(`(${used} / ${limit} tokens)`)}`;
41086
+ const bar = pc.green("█".repeat(filled)) + pc.dim("░".repeat(barLen - filled));
41087
+ const pctStr = pct >= 75 ? pc.yellow(`${pct}%`) : pc.dim(`${pct}%`);
41088
+ let line = ` ${bar} ${pctStr} ${pc.dim(`(${used} / ${limit} tokens)`)}`;
40444
41089
  if (compactions !== undefined) {
40445
- line += pc2.dim(` compactions: ${compactions}`);
41090
+ line += pc.dim(` compactions: ${compactions}`);
40446
41091
  }
40447
41092
  if (quality !== undefined) {
40448
- const qColor = quality >= 70 ? pc2.green : quality >= 40 ? pc2.yellow : pc2.red;
41093
+ const qColor = quality >= 70 ? pc.green : quality >= 40 ? pc.yellow : pc.red;
40449
41094
  line += ` ${qColor(`quality: ${quality}%`)}`;
40450
41095
  }
40451
41096
  return line;
@@ -40463,7 +41108,8 @@ function createHostBridge(opts) {
40463
41108
  interrupt() {
40464
41109
  if (opts.isBusy())
40465
41110
  opts.interruptRun();
40466
- }
41111
+ },
41112
+ subscribeOutput: (fn) => defaultOutputBus.subscribe(fn)
40467
41113
  };
40468
41114
  }
40469
41115
 
@@ -40484,6 +41130,8 @@ class Repl {
40484
41130
  pendingClipboardImage = null;
40485
41131
  exitOnClose = false;
40486
41132
  execModule;
41133
+ promptPresented = false;
41134
+ runHandledPrompt = false;
40487
41135
  rl;
40488
41136
  agent;
40489
41137
  config;
@@ -40492,9 +41140,13 @@ class Repl {
40492
41140
  pluginManager;
40493
41141
  logger;
40494
41142
  slog;
41143
+ sessionOutput;
40495
41144
  envReport;
40496
41145
  contextProbe;
40497
- constructor(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger4, exitOnClose, envReport, historyPath, execModule, contextProbe) {
41146
+ output;
41147
+ promptSink;
41148
+ promptIO;
41149
+ constructor(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger4, exitOnClose, envReport, historyPath, execModule, contextProbe, output) {
40498
41150
  this.agent = agent;
40499
41151
  this.config = config;
40500
41152
  this.exitOnClose = exitOnClose === true;
@@ -40506,37 +41158,59 @@ class Repl {
40506
41158
  this.contextProbe = contextProbe;
40507
41159
  this.execModule = execModule;
40508
41160
  this.slog = new SessionLogger(sessionManager, logger4);
41161
+ this.bindSessionOutput();
40509
41162
  this.configDir = configDir || join55(homedir18(), ".mma");
40510
41163
  this.baseDir = baseDir || process.cwd();
40511
41164
  this.noAgentsMd = noAgentsMd === true;
40512
41165
  this.historyPath = historyPath ?? join55(homedir18(), ".mma", "repl-history");
40513
41166
  this.loadHistory();
40514
- this.rl = process.stdin.isTTY ? new LineEditor({
40515
- input: process.stdin,
40516
- output: process.stdout,
40517
- prompt: pc2.cyan(t("repl.you")),
40518
- history: this.history,
40519
- historySize: this.maxHistory,
40520
- completer: (line) => {
40521
- const [matches, partial] = this.completer.complete(line);
40522
- if (matches.length > 0)
40523
- return [matches, partial];
40524
- return [[], line];
40525
- }
40526
- }) : readline3.createInterface({
40527
- input: process.stdin,
40528
- output: process.stdout,
40529
- prompt: pc2.cyan(t("repl.you")),
40530
- history: this.history,
40531
- historySize: this.maxHistory,
40532
- tabSize: 2,
40533
- completer: (line) => {
40534
- const [matches, partial] = this.completer.complete(line);
40535
- if (matches.length > 0)
40536
- return [matches, partial];
40537
- return [[], line];
41167
+ const editorCompleter = (line) => {
41168
+ const [matches, partial] = this.completer.complete(line);
41169
+ if (matches.length > 0)
41170
+ return [matches, partial];
41171
+ return [[], line];
41172
+ };
41173
+ if (process.stdin.isTTY) {
41174
+ this.rl = new LineEditor({
41175
+ input: process.stdin,
41176
+ output: process.stdout,
41177
+ prompt: this.inputPrompt(),
41178
+ history: this.history,
41179
+ historySize: this.maxHistory,
41180
+ completer: editorCompleter
41181
+ });
41182
+ } else {
41183
+ this.rl = readline2.createInterface({
41184
+ input: process.stdin,
41185
+ output: process.stdout,
41186
+ prompt: this.inputPrompt(),
41187
+ history: this.history,
41188
+ historySize: this.maxHistory,
41189
+ tabSize: 2,
41190
+ completer: editorCompleter
41191
+ });
41192
+ }
41193
+ this.output = output ?? getDefaultChannel();
41194
+ this.promptSink = {
41195
+ isActive: () => this.rl instanceof LineEditor && this.promptPresented && !this.agentRunning && !this.inputLocked,
41196
+ printAbove: (text) => {
41197
+ if (this.rl instanceof LineEditor) {
41198
+ this.rl.printAbove(text);
41199
+ return;
41200
+ }
41201
+ writeNonTtyLine(text);
41202
+ },
41203
+ clearScreen: () => {
41204
+ if (this.rl instanceof LineEditor)
41205
+ this.rl.clearScreen();
40538
41206
  }
41207
+ };
41208
+ this.output.attachPrompt(this.promptSink);
41209
+ this.promptIO = createPromptIO({
41210
+ ask: (prompt) => this.askViaEditor(prompt),
41211
+ print: (line) => this.output.writeLine(line)
40539
41212
  });
41213
+ this.agent.setPromptIO?.(this.promptIO);
40540
41214
  registerAllCommands(this);
40541
41215
  this.setupCompleter();
40542
41216
  this.setupListeners();
@@ -40560,6 +41234,10 @@ class Repl {
40560
41234
  interruptRun: () => this.agent.shutdown()
40561
41235
  }));
40562
41236
  }
41237
+ bindSessionOutput() {
41238
+ this.sessionOutput?.dispose();
41239
+ this.sessionOutput = this.sessionManager ? new SessionOutputSink(defaultOutputBus, this.sessionManager) : undefined;
41240
+ }
40563
41241
  async reload() {
40564
41242
  const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config2(), exports_config));
40565
41243
  const { bootstrap: bootstrap2 } = await Promise.resolve().then(() => (init_bootstrap(), exports_bootstrap));
@@ -40572,10 +41250,12 @@ class Repl {
40572
41250
  Object.assign(this.config, freshConfig);
40573
41251
  const result = await bootstrap2(this.configDir, this.baseDir, false, false);
40574
41252
  this.agent = result.agent;
41253
+ this.agent.setPromptIO?.(this.promptIO);
40575
41254
  this.sessionManager = result.sessionManager;
40576
41255
  this.skillsModule = result.skillsModule;
40577
41256
  this.pluginManager = result.pluginManager;
40578
41257
  this.execModule = result.execModule;
41258
+ this.bindSessionOutput();
40579
41259
  this.attachHostBridge(result.pluginManager);
40580
41260
  this.setupCompleter();
40581
41261
  }
@@ -40591,9 +41271,14 @@ class Repl {
40591
41271
  }
40592
41272
  }
40593
41273
  saveHistory() {
40594
- const allHistory = this.history.slice(-this.maxHistory);
40595
- writeFileSync24(this.historyPath, allHistory.join(`
41274
+ try {
41275
+ mkdirSync23(dirname25(this.historyPath), { recursive: true });
41276
+ const allHistory = this.history.slice(-this.maxHistory);
41277
+ writeFileSync24(this.historyPath, allHistory.join(`
40596
41278
  `), "utf-8");
41279
+ } catch (e) {
41280
+ this.logger?.debug(`Failed to save REPL history: ${e.message}`);
41281
+ }
40597
41282
  }
40598
41283
  setupCompleter() {
40599
41284
  this.completer.reset();
@@ -40659,16 +41344,13 @@ class Repl {
40659
41344
  if (fullInput) {
40660
41345
  if (fullInput.startsWith("/")) {
40661
41346
  await this.executeCommand(fullInput);
41347
+ this.afterCommand();
40662
41348
  } else {
40663
41349
  await this.runAgent(fullInput);
40664
41350
  }
40665
41351
  }
40666
- if (this.running) {
40667
- this.rl.setPrompt(pc2.cyan(t("repl.you")));
40668
- this.rl.prompt();
40669
- }
40670
41352
  } else {
40671
- this.rl.setPrompt(pc2.cyan(t("repl.you") + "… "));
41353
+ this.rl.setPrompt(this.inputPrompt(true));
40672
41354
  this.rl.prompt();
40673
41355
  }
40674
41356
  return;
@@ -40676,24 +41358,21 @@ class Repl {
40676
41358
  if (this.isMultiLineInput(trimmed)) {
40677
41359
  inMultiLine = true;
40678
41360
  multiLineBuffer = trimmed;
40679
- this.rl.setPrompt(pc2.cyan(t("repl.you") + "… "));
41361
+ this.rl.setPrompt(this.inputPrompt(true));
40680
41362
  this.rl.prompt();
40681
41363
  return;
40682
41364
  }
40683
41365
  if (!trimmed) {
40684
- this.rl.setPrompt(pc2.cyan(t("repl.you")));
41366
+ this.rl.setPrompt(this.inputPrompt());
40685
41367
  this.rl.prompt();
40686
41368
  return;
40687
41369
  }
40688
41370
  if (trimmed.startsWith("/")) {
40689
41371
  await this.executeCommand(trimmed);
41372
+ this.afterCommand();
40690
41373
  } else {
40691
41374
  await this.runAgent(trimmed);
40692
41375
  }
40693
- if (this.running) {
40694
- this.rl.setPrompt(pc2.cyan(t("repl.you")));
40695
- this.rl.prompt();
40696
- }
40697
41376
  });
40698
41377
  this.rl.on("close", () => {
40699
41378
  this.running = false;
@@ -40721,7 +41400,7 @@ class Repl {
40721
41400
  }
40722
41401
  Repl.sigintHandler = () => {
40723
41402
  if (this.agentRunning) {
40724
- console.log(pc2.yellow(t("repl.ctrl_c_interrupt")));
41403
+ this.output.writeLine(pc.yellow(t("repl.ctrl_c_interrupt")));
40725
41404
  this.agent.shutdown();
40726
41405
  this.agentRunning = false;
40727
41406
  if (forceExitTimer)
@@ -40733,6 +41412,35 @@ class Repl {
40733
41412
  };
40734
41413
  process.on("SIGINT", Repl.sigintHandler);
40735
41414
  }
41415
+ presentPrompt() {
41416
+ if (!this.running)
41417
+ return;
41418
+ this.rl.setPrompt(this.inputPrompt());
41419
+ this.rl.prompt();
41420
+ this.promptPresented = true;
41421
+ }
41422
+ reasoningLabel() {
41423
+ const mode = this.config.reasoning?.mode ?? "default";
41424
+ if (mode !== "auto")
41425
+ return this.agent.reasoningLevel ?? mode;
41426
+ const rs = this.agent.reasoningState;
41427
+ const cooldown = this.config.reasoning?.overrideCooldown ?? 0;
41428
+ const transientActive = rs.overrideIteration >= 0 && this.agent.currentIteration - rs.overrideIteration <= cooldown;
41429
+ if (rs.manual || transientActive)
41430
+ return `auto→${this.agent.reasoningLevel}`;
41431
+ return "auto";
41432
+ }
41433
+ inputPrompt(continuation = false) {
41434
+ const key = continuation ? "repl.you_reasoning_cont" : "repl.you_reasoning";
41435
+ return pc.cyan(t(key, { level: this.reasoningLabel() }));
41436
+ }
41437
+ afterCommand() {
41438
+ if (this.runHandledPrompt) {
41439
+ this.runHandledPrompt = false;
41440
+ return;
41441
+ }
41442
+ this.presentPrompt();
41443
+ }
40736
41444
  handleSpecialKey(str, key) {
40737
41445
  if (key.name === "escape") {
40738
41446
  const escBytes = key.sequence ? (key.sequence.match(/\x1b/g) || []).length : 1;
@@ -40742,9 +41450,8 @@ class Repl {
40742
41450
  if (escBytes >= 2 || withinWindow) {
40743
41451
  this.lastEscTime = 0;
40744
41452
  if (this.agentRunning) {
40745
- process.stdout.write(pc2.yellow(`
40746
- ${t("repl.interrupt")}
40747
- `));
41453
+ this.output.writeLine(pc.yellow(`
41454
+ ${t("repl.interrupt")}`));
40748
41455
  this.agent.shutdown();
40749
41456
  }
40750
41457
  }
@@ -40764,13 +41471,13 @@ ${t("repl.interrupt")}
40764
41471
  const { dataUrl } = await bufferToDataUrl2(clipBuf);
40765
41472
  this.pendingClipboardImage = dataUrl;
40766
41473
  const sizeKb = Math.round(dataUrl.length * 3 / 4 / 1024);
40767
- console.log(pc2.green(`
41474
+ this.output.writeLine(pc.green(`
40768
41475
  ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
40769
41476
  if (this.rl instanceof LineEditor)
40770
41477
  this.rl.reset();
40771
41478
  this.rl.prompt();
40772
41479
  } else {
40773
- console.log(pc2.yellow(`
41480
+ this.output.writeLine(pc.yellow(`
40774
41481
  ${t("image.clipboard_empty")}`));
40775
41482
  if (this.rl instanceof LineEditor)
40776
41483
  this.rl.reset();
@@ -40803,13 +41510,19 @@ ${t("image.clipboard_empty")}`));
40803
41510
  this.pendingClipboardImage = null;
40804
41511
  }
40805
41512
  this.logger?.logREPL("user", input);
40806
- if (this.rl instanceof LineEditor)
41513
+ this.promptPresented = false;
41514
+ if (this.rl instanceof LineEditor) {
41515
+ this.rl.suspendFrame();
41516
+ this.rl.setInputEnabled(false);
40807
41517
  this.rl.reset();
40808
- process.stdout.write("\r" + divider() + `
40809
- ` + pc2.green(t("repl.agent")));
41518
+ }
41519
+ this.output.beginStreaming();
41520
+ this.output.writeRaw(`\r${divider()}
41521
+ ${pc.green(t("repl.agent"))}`);
40810
41522
  const renderer = new Renderer({
40811
41523
  spinner: this.config.ui?.spinner ?? true,
40812
- baseDir: this.baseDir
41524
+ baseDir: this.baseDir,
41525
+ channel: this.output
40813
41526
  });
40814
41527
  renderer.showLoader();
40815
41528
  const result = await this.agent.run(input, (c) => renderer.text(c), (m) => renderer.meta(m), (ev) => {
@@ -40832,18 +41545,26 @@ ${t("image.clipboard_empty")}`));
40832
41545
  if (result.provider && result.model) {
40833
41546
  renderer.footer(result.model, result.provider, result.llmDurationMs ?? result.durationMs ?? 0);
40834
41547
  }
40835
- process.stdout.write(`
40836
- `);
41548
+ this.output.writeLine("");
40837
41549
  this.logger?.logREPL(result.success ? "assistant" : "system", result.text?.slice(0, 400) || result.error || "");
40838
41550
  if (!result.success) {
40839
- console.error(pc2.red(`${t("error.prefix")}${result.error}`));
41551
+ this.output.writeLine(pc.red(`${t("error.prefix")}${result.error}`), "stderr");
40840
41552
  }
40841
41553
  this.showContextBar(result);
40842
- process.stdout.write(`
40843
- ` + divider() + `
40844
- `);
41554
+ this.output.writeLine(`
41555
+ ${divider()}`);
40845
41556
  } finally {
40846
41557
  this.agentRunning = false;
41558
+ this.output.endStreaming();
41559
+ if (this.rl instanceof LineEditor) {
41560
+ this.rl.setInputEnabled(true);
41561
+ this.rl.setPrompt(this.inputPrompt());
41562
+ this.rl.resumeFrame();
41563
+ this.promptPresented = true;
41564
+ } else {
41565
+ this.presentPrompt();
41566
+ }
41567
+ this.runHandledPrompt = true;
40847
41568
  }
40848
41569
  }
40849
41570
  renderPlan(renderer) {
@@ -40869,21 +41590,44 @@ ${t("image.clipboard_empty")}`));
40869
41590
  this.inputLocked = false;
40870
41591
  }
40871
41592
  }
41593
+ async askViaEditor(prompt) {
41594
+ const editor = this.rl instanceof LineEditor ? this.rl : null;
41595
+ const wasSuspended = editor ? editor.isFrameSuspended() : true;
41596
+ const wasEnabled = editor ? editor.isInputEnabled() : false;
41597
+ this.output.beginModal();
41598
+ if (editor) {
41599
+ editor.setInputEnabled(true);
41600
+ editor.resumeFrame();
41601
+ }
41602
+ try {
41603
+ return await new Promise((resolve24) => this.rl.question(prompt, resolve24));
41604
+ } finally {
41605
+ if (editor) {
41606
+ editor.setInputEnabled(wasEnabled);
41607
+ if (wasSuspended)
41608
+ editor.suspendFrame();
41609
+ else
41610
+ editor.resumeFrame();
41611
+ }
41612
+ this.output.endModal();
41613
+ }
41614
+ }
40872
41615
  async executeCommand(input) {
40873
41616
  const parts = input.split(/\s+/);
40874
41617
  const name = parts[0].slice(1);
40875
41618
  const args = parts.slice(1);
41619
+ this.runHandledPrompt = false;
40876
41620
  const cmd = this.commands.get(name);
40877
41621
  if (!cmd) {
40878
- console.log(pc2.red(t("cli.unknown_cmd", { name })), t("cli.help_hint"));
41622
+ this.output.writeLine(`${pc.red(t("cli.unknown_cmd", { name }))} ${t("cli.help_hint")}`);
40879
41623
  return;
40880
41624
  }
40881
41625
  try {
40882
41626
  await cmd.action(args);
40883
41627
  } catch (err) {
40884
- console.error(pc2.red(t("error.command_error", {
41628
+ this.output.writeLine(pc.red(t("error.command_error", {
40885
41629
  message: errMsg(err)
40886
- })));
41630
+ })), "stderr");
40887
41631
  }
40888
41632
  }
40889
41633
  showHelp() {
@@ -40905,15 +41649,15 @@ ${t("image.clipboard_empty")}`));
40905
41649
  }
40906
41650
  if (cmds.length === 0)
40907
41651
  continue;
40908
- console.log(pc2.bold(t(`repl.group.${groupKey}`)));
41652
+ this.output.writeLine(pc.bold(t(`repl.group.${groupKey}`)));
40909
41653
  for (const cmd of cmds) {
40910
- const aliases = cmd.aliases?.length ? ` (${pc2.dim(cmd.aliases.join(", "))})` : "";
40911
- console.log(` ${pc2.cyan("/" + cmd.name)}${aliases} ${pc2.dim(cmd.description)}`);
41654
+ const aliases = cmd.aliases?.length ? ` (${pc.dim(cmd.aliases.join(", "))})` : "";
41655
+ this.output.writeLine(` ${pc.cyan("/" + cmd.name)}${aliases} ${pc.dim(cmd.description)}`);
40912
41656
  if (cmd.usage) {
40913
- console.log(` ${pc2.dim(cmd.usage)}`);
41657
+ this.output.writeLine(` ${pc.dim(cmd.usage)}`);
40914
41658
  }
40915
41659
  }
40916
- console.log();
41660
+ this.output.writeLine("");
40917
41661
  }
40918
41662
  }
40919
41663
  lastCompactionShown = 0;
@@ -40923,24 +41667,24 @@ ${t("image.clipboard_empty")}`));
40923
41667
  }
40924
41668
  const ui = this.config.ui;
40925
41669
  if (ui?.showContextStats) {
40926
- console.log();
41670
+ this.output.writeLine("");
40927
41671
  const ctxLine = formatContextBar(result.contextUsed, result.contextLimit, result.compactionCount, result.contextQuality);
40928
- console.log(ctxLine);
41672
+ this.output.writeLine(ctxLine);
40929
41673
  if (result.totalTokens !== undefined && result.totalTokens > 0) {
40930
- const apiLine = pc2.dim(` API: ${result.promptTokens} prompt + ${result.completionTokens} completion = ${result.totalTokens} total`);
40931
- console.log(apiLine);
41674
+ const apiLine = pc.dim(` API: ${result.promptTokens} prompt + ${result.completionTokens} completion = ${result.totalTokens} total`);
41675
+ this.output.writeLine(apiLine);
40932
41676
  }
40933
41677
  if (result.totalCost !== undefined && result.totalCost > 0) {
40934
- console.log(pc2.yellow(` ${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
41678
+ this.output.writeLine(pc.yellow(` ${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
40935
41679
  }
40936
41680
  const cacheLine = formatCacheLine(result.cache);
40937
41681
  if (cacheLine) {
40938
- console.log(pc2.dim(` ${cacheLine}`));
41682
+ this.output.writeLine(pc.dim(` ${cacheLine}`));
40939
41683
  }
40940
41684
  } else if (ui?.showCompaction && result.compactionCount !== undefined) {
40941
41685
  if (result.compactionCount > this.lastCompactionShown) {
40942
41686
  this.lastCompactionShown = result.compactionCount;
40943
- console.log(pc2.dim(`
41687
+ this.output.writeLine(pc.dim(`
40944
41688
  ⟳ Context compacted (${result.compactionCount})`));
40945
41689
  }
40946
41690
  }
@@ -40949,42 +41693,41 @@ ${t("image.clipboard_empty")}`));
40949
41693
  this.running = true;
40950
41694
  const info = [];
40951
41695
  const row = (label, value) => {
40952
- info.push(` ${pc2.yellow(label)} ${value}`);
41696
+ info.push(` ${pc.yellow(label)} ${value}`);
40953
41697
  };
40954
41698
  const ctx = this.config.contextWindow;
40955
41699
  const sysBudget = Math.floor(ctx * this.config.contextBudget.systemPrompt);
40956
41700
  const resBudget = Math.floor(ctx * this.config.contextBudget.responseReserve);
40957
41701
  const histBudget = ctx - sysBudget - resBudget;
40958
- row(t("repl.model"), pc2.white(this.config.model));
40959
- row(t("repl.provider"), `${this.config.provider.type} → ${pc2.dim(this.config.provider.baseUrl)}`);
40960
- row(t("repl.context"), `${pc2.white(String(ctx))} ${pc2.dim(`(sys:${sysBudget} res:${resBudget} hist:${histBudget})`)}`);
41702
+ row(t("repl.model"), pc.white(this.config.model));
41703
+ row(t("repl.provider"), `${this.config.provider.type} → ${pc.dim(this.config.provider.baseUrl)}`);
41704
+ row(t("repl.context"), `${pc.white(String(ctx))} ${pc.dim(`(sys:${sysBudget} res:${resBudget} hist:${histBudget})`)}`);
40961
41705
  const si = this.agent.getSystemPromptInfo();
40962
- row(t("repl.sysprompt_label"), pc2.dim(t("repl.sysprompt_size", { used: si.tokenCount, budget: sysBudget })));
41706
+ row(t("repl.sysprompt_label"), pc.dim(t("repl.sysprompt_size", { used: si.tokenCount, budget: sysBudget })));
40963
41707
  if (this.skillsModule) {
40964
41708
  const budget = this.skillsModule.getBudget();
40965
- row(t("repl.skills_label"), `${pc2.white(String(this.skillsModule.getAvailable().length))} available, ${pc2.dim(`budget: ${budget.total} tokens`)}`);
41709
+ row(t("repl.skills_label"), `${pc.white(String(this.skillsModule.getAvailable().length))} available, ${pc.dim(`budget: ${budget.total} tokens`)}`);
40966
41710
  }
40967
41711
  if (this.pluginManager) {
40968
41712
  const infos = this.pluginManager.getPluginInfos().filter(({ plugin: plugin3 }) => !plugin3.isBuiltin);
40969
41713
  if (infos.length > 0) {
40970
41714
  const pluginNames = infos.map(({ plugin: plugin3, source }) => {
40971
- const version3 = plugin3.version ? `${pc2.dim(plugin3.version)}` : "";
40972
- const origin = source ? pc2.dim(` [${source}]`) : "";
41715
+ const version3 = plugin3.version ? `${pc.dim(plugin3.version)}` : "";
41716
+ const origin = source ? pc.dim(` [${source}]`) : "";
40973
41717
  return `${plugin3.name}${version3}${origin}`;
40974
41718
  }).join(", ");
40975
- row(t("repl.plugins_label"), `${pc2.white(String(infos.length))} active ${pc2.dim(`(${pluginNames})`)}`);
41719
+ row(t("repl.plugins_label"), `${pc.white(String(infos.length))} active ${pc.dim(`(${pluginNames})`)}`);
40976
41720
  }
40977
41721
  }
40978
41722
  const mcpServers = this.config.mcpServers || {};
40979
41723
  const enabledServers = Object.entries(mcpServers).filter(([, s]) => s.enabled !== false);
40980
41724
  if (enabledServers.length > 0) {
40981
41725
  const names = enabledServers.map(([name]) => name).join(", ");
40982
- row(t("repl.mcp_label"), `${pc2.white(String(enabledServers.length))} ${pc2.dim(`(${names})`)}`);
41726
+ row(t("repl.mcp_label"), `${pc.white(String(enabledServers.length))} ${pc.dim(`(${names})`)}`);
40983
41727
  }
40984
- const cwd = process.cwd();
40985
- row(t("repl.work_dir"), pc2.dim(cwd));
41728
+ row(t("repl.work_dir"), pc.dim(this.baseDir));
40986
41729
  if (this.noAgentsMd) {
40987
- row(t("repl.agents_label"), pc2.red(t("repl.disabled")));
41730
+ row(t("repl.agents_label"), pc.red(t("repl.disabled")));
40988
41731
  } else {
40989
41732
  const agentsMdCandidates = [
40990
41733
  join55(this.baseDir, "AGENTS.md"),
@@ -40994,42 +41737,41 @@ ${t("image.clipboard_empty")}`));
40994
41737
  const foundAgents = agentsMdCandidates.filter((p) => existsSync60(p));
40995
41738
  if (foundAgents.length > 0) {
40996
41739
  for (const p of foundAgents) {
40997
- row(t("repl.agents_label"), pc2.dim(p));
41740
+ row(t("repl.agents_label"), pc.dim(p));
40998
41741
  }
40999
41742
  } else {
41000
- row(t("repl.agents_label"), pc2.dim(t("repl.not_found")));
41743
+ row(t("repl.agents_label"), pc.dim(t("repl.not_found")));
41001
41744
  }
41002
41745
  }
41003
41746
  const meta = this.sessionManager?.getActiveMeta();
41004
41747
  if (meta) {
41005
41748
  const sessionPath = join55(this.configDir, "sessions", meta.id);
41006
- row(t("repl.session_label"), `${pc2.cyan(meta.name)} ${pc2.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc2.dim(sessionPath)}`);
41749
+ row(t("repl.session_label"), `${pc.cyan(meta.name)} ${pc.dim(`(${meta.id.slice(0, 12)})`)} — ${meta.messageCount} msgs ${pc.dim(sessionPath)}`);
41007
41750
  }
41008
41751
  const isTty2 = process.stdout.isTTY === true;
41009
41752
  const lspEnabled = isTty2 && (this.config.lsp ?? DEFAULT_LSP_CONFIG).enabled !== false;
41010
41753
  for (const line of info) {
41011
- console.log(pc2.dim(line).trimEnd());
41754
+ this.output.writeLine(pc.dim(line).trimEnd());
41012
41755
  }
41013
- console.log();
41756
+ this.output.writeLine("");
41014
41757
  try {
41015
41758
  const { existsSync: exists } = await import("fs");
41016
41759
  const { join: pathJoin } = await import("path");
41017
41760
  const { hasDomainFiles: hasDomainFiles3 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
41018
41761
  const legacyPath = pathJoin(this.configDir, "config.json");
41019
41762
  if (exists(legacyPath) && !hasDomainFiles3(this.configDir)) {
41020
- console.log(pc2.yellow(` ${t("config.legacy_hint")}`));
41021
- console.log();
41763
+ this.output.writeLine(pc.yellow(` ${t("config.legacy_hint")}`));
41764
+ this.output.writeLine("");
41022
41765
  }
41023
41766
  } catch {}
41024
41767
  this.rl.prompt();
41768
+ this.promptPresented = true;
41025
41769
  if (lspEnabled) {
41026
41770
  this.probeLspBanner().then((lspSummary) => {
41027
41771
  if (lspSummary) {
41028
- const line = `${pc2.green(t("repl.agent"))}${pc2.yellow(t("repl.lsp_label"))} ${lspSummary}`;
41029
- process.stdout.write(`\x1B[2K\r${divider()}
41030
- ${line}
41031
- `);
41032
- this.rl.prompt();
41772
+ const line = `${pc.green(t("repl.agent"))}${pc.yellow(t("repl.lsp_label"))} ${lspSummary}`;
41773
+ this.output.writeLine(`${divider()}
41774
+ ${line}`);
41033
41775
  }
41034
41776
  }).catch(() => {});
41035
41777
  }
@@ -41040,7 +41782,7 @@ ${line}
41040
41782
  })).filter((x) => Boolean(x.provider))), { timeoutMs: 5000 }).then((results) => {
41041
41783
  for (const r of results) {
41042
41784
  if (!r.ok && r.name !== this.config.provider.active) {
41043
- writeWarning(t("repl.provider_down", { name: r.name, error: r.error ?? "" }));
41785
+ this.output.writeLine(formatWarning(t("repl.provider_down", { name: r.name, error: r.error ?? "" })));
41044
41786
  }
41045
41787
  }
41046
41788
  }).catch(() => {});
@@ -41054,12 +41796,10 @@ ${line}
41054
41796
  type: "context_probe",
41055
41797
  content: `model=${probe.model} actual=${probe.actual} configured=${this.config.contextWindow}`
41056
41798
  });
41057
- const line = probe.actual < this.config.contextWindow ? `${pc2.yellow("⚠")} ${t("repl.context_probe_small", { model: probe.model, actual: probe.actual, configured: this.config.contextWindow })}` : probe.actual > this.config.contextWindow ? `${pc2.dim(t("repl.context_probe_big", { model: probe.model, actual: probe.actual }))}` : null;
41799
+ const line = probe.actual < this.config.contextWindow ? `${pc.yellow("⚠")} ${t("repl.context_probe_small", { model: probe.model, actual: probe.actual, configured: this.config.contextWindow })}` : probe.actual > this.config.contextWindow ? `${pc.dim(t("repl.context_probe_big", { model: probe.model, actual: probe.actual }))}` : null;
41058
41800
  if (line) {
41059
- process.stdout.write(`\x1B[2K\r${divider()}
41060
- ${line}
41061
- `);
41062
- this.rl.prompt();
41801
+ this.output.writeLine(`${divider()}
41802
+ ${line}`);
41063
41803
  }
41064
41804
  }).catch(() => {});
41065
41805
  }
@@ -41085,21 +41825,23 @@ ${line}
41085
41825
  return null;
41086
41826
  const parts = [];
41087
41827
  for (const r of summary.ok) {
41088
- parts.push(pc2.green(`✓ ${r.language}${pc2.dim(` (${(r.durationMs / 1000).toFixed(1)}s)`)}`));
41828
+ parts.push(pc.green(`✓ ${r.language}${pc.dim(` (${(r.durationMs / 1000).toFixed(1)}s)`)}`));
41089
41829
  }
41090
41830
  for (const r of summary.failed) {
41091
41831
  const reason = r.error?.includes("timeout") ? t("repl.lsp_timeout") : t("repl.lsp_failed");
41092
- parts.push(pc2.red(`✗ ${r.language}${pc2.dim(` — ${reason}`)}`));
41832
+ parts.push(pc.red(`✗ ${r.language}${pc.dim(` — ${reason}`)}`));
41093
41833
  }
41094
41834
  return parts.join(" ");
41095
41835
  } catch {
41096
- return pc2.yellow(t("repl.lsp_unknown"));
41836
+ return pc.yellow(t("repl.lsp_unknown"));
41097
41837
  }
41098
41838
  }
41099
41839
  stop() {
41100
41840
  this.running = false;
41101
41841
  this.saveHistory();
41102
41842
  this.agent.shutdown();
41843
+ this.sessionOutput?.dispose();
41844
+ this.sessionOutput = undefined;
41103
41845
  this.logger?.closeSessionLog();
41104
41846
  this.rl.close();
41105
41847
  }
@@ -41109,38 +41851,139 @@ ${line}
41109
41851
  init_i18n();
41110
41852
  init_colors();
41111
41853
  init_prices();
41112
- function printRunResult(result, flush) {
41854
+ init_output();
41855
+ function printRunResult(result, flush, channel = getDefaultChannel()) {
41113
41856
  flush();
41114
41857
  if (result.success) {
41115
41858
  if (result.totalCost !== undefined && result.totalCost > 0) {
41116
- console.log(pc2.dim(`${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
41859
+ channel.writeLine(pc.dim(`${t("repl.cost", { cost: formatCost(result.totalCost) })}`));
41117
41860
  if (result.costBreakdown && result.costBreakdown.length > 1) {
41118
41861
  const parts = result.costBreakdown.map((e) => `${e.provider} ${formatCost(e.cost)}`);
41119
- console.log(pc2.dim(` ${t("repl.cost_breakdown", { breakdown: parts.join(", ") })}`));
41862
+ channel.writeLine(pc.dim(` ${t("repl.cost_breakdown", { breakdown: parts.join(", ") })}`));
41120
41863
  }
41121
41864
  } else if (result.totalTokens !== undefined && result.totalTokens > 0) {
41122
- console.log(pc2.dim(`${t("repl.tokens", { tokens: result.totalTokens })}`));
41865
+ channel.writeLine(pc.dim(`${t("repl.tokens", { tokens: result.totalTokens })}`));
41123
41866
  }
41124
41867
  const cacheLine = formatCacheLine(result.cache);
41125
41868
  if (cacheLine) {
41126
- console.log(pc2.dim(` ${cacheLine}`));
41869
+ channel.writeLine(pc.dim(` ${cacheLine}`));
41127
41870
  }
41128
41871
  if (!result.text) {
41129
- console.log(pc2.yellow(t("cli.no_output")));
41872
+ channel.writeLine(pc.yellow(t("cli.no_output")));
41130
41873
  }
41131
41874
  return 0;
41132
41875
  }
41133
- console.error(`${t("error.prefix")}${result.error}`);
41876
+ channel.writeLine(`${t("error.prefix")}${result.error}`, "stderr");
41134
41877
  return 1;
41135
41878
  }
41136
41879
 
41137
41880
  // src/cli/main.ts
41138
41881
  init_setup();
41882
+
41883
+ // src/cli/setup-order.ts
41884
+ var SECURITY_BASH_BLOCKLIST = [
41885
+ "rm",
41886
+ "dd",
41887
+ "chmod",
41888
+ "wget",
41889
+ "curl",
41890
+ "scp",
41891
+ "ssh",
41892
+ "nc",
41893
+ "netcat",
41894
+ "sudo",
41895
+ "su",
41896
+ "kill",
41897
+ "pkill",
41898
+ "killall",
41899
+ "shutdown",
41900
+ "reboot"
41901
+ ];
41902
+ function applyAnswersToConfig(config, a) {
41903
+ config.provider = {
41904
+ ...config.provider,
41905
+ type: a.provider,
41906
+ baseUrl: a.apiBase,
41907
+ apiKey: a.apiKey
41908
+ };
41909
+ config.model = a.model;
41910
+ config.contextWindow = a.contextWindow;
41911
+ config.maxToolIterations = a.maxToolIterations;
41912
+ config.locale = a.locale;
41913
+ if (config.security) {
41914
+ config.security.enabled = true;
41915
+ config.security.bash.enabled = true;
41916
+ config.security.bash.blockDangerousFlags = a.securityFlagsBlock || config.security.bash.blockDangerousFlags;
41917
+ if (a.securityBashBlock) {
41918
+ config.security.bash.blacklist = [
41919
+ ...new Set([...config.security.bash.blacklist, ...SECURITY_BASH_BLOCKLIST])
41920
+ ];
41921
+ }
41922
+ if (!a.securityPathsDeny)
41923
+ config.security.paths.denied = [];
41924
+ }
41925
+ return config;
41926
+ }
41927
+
41928
+ // src/cli/relaunch.ts
41929
+ init_output();
41930
+ import { spawnSync as spawnSync4 } from "node:child_process";
41931
+ function relaunchArgs(argv) {
41932
+ return argv.slice(1);
41933
+ }
41934
+ function relaunchCli() {
41935
+ const args = relaunchArgs(process.argv);
41936
+ const entry = args[0];
41937
+ if (!entry)
41938
+ process.exit(0);
41939
+ const child = spawnSync4(process.execPath, args, {
41940
+ stdio: "inherit",
41941
+ env: { ...process.env, MMA_POST_SETUP: "1" }
41942
+ });
41943
+ if (child.error) {
41944
+ getDefaultChannel().writeLine(`Failed to relaunch the CLI: ${child.error.message}`, "stderr");
41945
+ process.exit(1);
41946
+ }
41947
+ process.exit(child.status ?? 0);
41948
+ }
41949
+
41950
+ // src/cli/main.ts
41951
+ init_output();
41952
+
41953
+ // src/cli/json-payload.ts
41954
+ function buildJsonResult(result, diagnostics) {
41955
+ return {
41956
+ success: result.success,
41957
+ text: result.text,
41958
+ error: result.error ?? null,
41959
+ iterationCount: result.iterationCount,
41960
+ contextUsed: result.contextUsed ?? null,
41961
+ contextLimit: result.contextLimit ?? null,
41962
+ promptTokens: result.promptTokens ?? null,
41963
+ completionTokens: result.completionTokens ?? null,
41964
+ totalTokens: result.totalTokens ?? null,
41965
+ totalCost: result.totalCost ?? null,
41966
+ costBreakdown: result.costBreakdown ?? [],
41967
+ cache: result.cache ?? null,
41968
+ diagnostics
41969
+ };
41970
+ }
41971
+ function buildJsonError(error, diagnostics = []) {
41972
+ return {
41973
+ success: false,
41974
+ text: "",
41975
+ error,
41976
+ iterationCount: 0,
41977
+ diagnostics
41978
+ };
41979
+ }
41980
+
41981
+ // src/cli/main.ts
41139
41982
  init_config2();
41140
41983
  init_i18n();
41141
41984
  init_colors();
41142
41985
  import { existsSync as existsSync61 } from "fs";
41143
- import { join as join57, dirname as dirname25 } from "path";
41986
+ import { join as join57, dirname as dirname26 } from "path";
41144
41987
  import { homedir as homedir20 } from "os";
41145
41988
  import { fileURLToPath as fileURLToPath6 } from "url";
41146
41989
 
@@ -41151,6 +41994,7 @@ init_checker();
41151
41994
  init_checker();
41152
41995
  init_i18n();
41153
41996
  init_colors();
41997
+ init_output();
41154
41998
 
41155
41999
  class UpdaterModule {
41156
42000
  name = "updater";
@@ -41166,8 +42010,8 @@ class UpdaterModule {
41166
42010
  this.updater = new Updater(currentVersion, packageName, installRunner);
41167
42011
  this.logger = logger4 ?? {
41168
42012
  info: () => {},
41169
- warn: (m) => console.warn(pc2.yellow(m)),
41170
- error: (m) => console.error(pc2.red(m))
42013
+ warn: (m) => defaultOutputBus.log("warn", "updater", m),
42014
+ error: (m) => defaultOutputBus.log("error", "updater", m)
41171
42015
  };
41172
42016
  }
41173
42017
  setInstallEnabled(enabled2) {
@@ -41227,7 +42071,7 @@ class UpdaterModule {
41227
42071
  if (install.success) {
41228
42072
  const changelog = readChangelog("micro-models-agent");
41229
42073
  const latestEntry = changelog ? extractLatestChangelog(changelog) : null;
41230
- const changelogBlock = latestEntry ? pc2.cyan(`
42074
+ const changelogBlock = latestEntry ? pc.cyan(`
41231
42075
  ${t("cli.changelog_title", { version: result.latest })}
41232
42076
  `) + latestEntry : "";
41233
42077
  this.logger.info(t("updater.installed", {
@@ -41260,7 +42104,7 @@ init_environment();
41260
42104
  init_data_sanitizer();
41261
42105
  init_i18n();
41262
42106
  init_utils();
41263
- import { appendFileSync as appendFileSync7, mkdirSync as mkdirSync23 } from "fs";
42107
+ import { appendFileSync as appendFileSync7, mkdirSync as mkdirSync24 } from "fs";
41264
42108
  import { join as join56 } from "path";
41265
42109
  import { homedir as homedir19 } from "os";
41266
42110
  var CRASH_LOG_DIR = join56(homedir19(), ".mma", "logs");
@@ -41278,7 +42122,7 @@ function formatCrashEntry(type2, err) {
41278
42122
  }
41279
42123
  function writeCrashEntry(dir, entry) {
41280
42124
  try {
41281
- mkdirSync23(dir, { recursive: true });
42125
+ mkdirSync24(dir, { recursive: true });
41282
42126
  appendFileSync7(join56(dir, CRASH_LOG_FILE), JSON.stringify(entry) + `
41283
42127
  `, "utf-8");
41284
42128
  } catch {}
@@ -41342,17 +42186,15 @@ function closestCommand(input, known, maxDistance = 2) {
41342
42186
 
41343
42187
  // src/cli/main.ts
41344
42188
  init_utils();
42189
+ var jsonMode = false;
41345
42190
  function startAutoUpdate(config) {
41346
42191
  if (isDevEntryPath(fileURLToPath6(import.meta.url)))
41347
42192
  return;
41348
42193
  try {
41349
42194
  const module = new UpdaterModule(config.updater, readMmaVersion(), "micro-models-agent", {
41350
- info: (m) => process.stderr.write(pc2.dim(m) + `
41351
- `),
41352
- warn: (m) => process.stderr.write(pc2.yellow(m) + `
41353
- `),
41354
- error: (m) => process.stderr.write(pc2.red(m) + `
41355
- `)
42195
+ info: (m) => defaultOutputBus.log("info", "updater", m),
42196
+ warn: (m) => defaultOutputBus.log("warn", "updater", m),
42197
+ error: (m) => defaultOutputBus.log("error", "updater", m)
41356
42198
  });
41357
42199
  module.start();
41358
42200
  return module;
@@ -41362,6 +42204,7 @@ function startAutoUpdate(config) {
41362
42204
  }
41363
42205
  async function main() {
41364
42206
  installCrashHandlers();
42207
+ getDefaultChannel();
41365
42208
  const program2 = createProgram();
41366
42209
  const valueOpts = new Set(["-d", "--dir", "--reasoning"]);
41367
42210
  const argv = process.argv.slice(2);
@@ -41385,7 +42228,7 @@ async function main() {
41385
42228
  const noAgentsMd = opts.noAgentsMd === true;
41386
42229
  const projectDir = opts.dir;
41387
42230
  const exitOnComplete = opts.exitOnComplete === true;
41388
- const jsonMode = opts.json === true;
42231
+ const jsonOpt = opts.json === true;
41389
42232
  const reasoningLevel = opts.reasoning;
41390
42233
  const isSubcommand = program2.args.length > 0 && cmdNames.has(program2.args[0]);
41391
42234
  if (isSubcommand) {
@@ -41394,15 +42237,20 @@ async function main() {
41394
42237
  if (program2.args.length > 0) {
41395
42238
  const suggestion = closestCommand(program2.args[0], [...cmdNames]);
41396
42239
  if (suggestion && suggestion !== program2.args[0]) {
41397
- console.error(pc2.yellow(`${t("cli.unknown_command", { input: program2.args[0], suggestion })}`));
42240
+ getDefaultChannel().writeLine(pc.yellow(`${t("cli.unknown_command", { input: program2.args[0], suggestion })}`), "stderr");
41398
42241
  process.exit(2);
41399
42242
  }
41400
42243
  }
41401
42244
  if (program2.args.length > 0) {
42245
+ if (jsonOpt) {
42246
+ jsonMode = true;
42247
+ getDefaultChannel().setQuiet(true);
42248
+ }
42249
+ const jsonSink = jsonOpt ? new JsonOutputSink(defaultOutputBus) : undefined;
41402
42250
  const prompt = program2.args.join(" ");
41403
42251
  const { agent, config, baseDir, legacyDetected } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete, reasoningLevel);
41404
42252
  if (legacyDetected) {
41405
- console.error(pc2.yellow(` ${t("config.legacy_hint")}`));
42253
+ getDefaultChannel().writeLine(pc.yellow(` ${t("config.legacy_hint")}`), "stderr");
41406
42254
  }
41407
42255
  const updater = exitOnComplete ? undefined : startAutoUpdate(config);
41408
42256
  if (jsonMode) {
@@ -41411,30 +42259,17 @@ async function main() {
41411
42259
  result2 = await agent.run(prompt);
41412
42260
  } catch (err) {
41413
42261
  const message = errMsg(err);
41414
- process.stdout.write(JSON.stringify({ success: false, text: "", error: message, iterationCount: 0 }, null, 2));
41415
- process.stdout.write(`
41416
- `);
41417
42262
  agent.shutdown();
42263
+ const diagnostics2 = jsonSink?.diagnostics() ?? [];
42264
+ jsonSink?.dispose();
42265
+ writeMachineJson(buildJsonError(message, diagnostics2));
41418
42266
  await updater?.waitForIdle(1e4);
41419
42267
  process.exit(1);
41420
42268
  }
41421
42269
  agent.shutdown();
41422
- process.stdout.write(JSON.stringify({
41423
- success: result2.success,
41424
- text: result2.text,
41425
- error: result2.error ?? null,
41426
- iterationCount: result2.iterationCount,
41427
- contextUsed: result2.contextUsed ?? null,
41428
- contextLimit: result2.contextLimit ?? null,
41429
- promptTokens: result2.promptTokens ?? null,
41430
- completionTokens: result2.completionTokens ?? null,
41431
- totalTokens: result2.totalTokens ?? null,
41432
- totalCost: result2.totalCost ?? null,
41433
- costBreakdown: result2.costBreakdown ?? [],
41434
- cache: result2.cache ?? null
41435
- }, null, 2));
41436
- process.stdout.write(`
41437
- `);
42270
+ const diagnostics = jsonSink?.diagnostics() ?? [];
42271
+ jsonSink?.dispose();
42272
+ writeMachineJson(buildJsonResult(result2, diagnostics));
41438
42273
  await updater?.waitForIdle(1e4);
41439
42274
  process.exit(result2.success ? 0 : 1);
41440
42275
  }
@@ -41484,6 +42319,19 @@ async function main() {
41484
42319
  hasAnyConfig = hasDomainFiles3(mmaDir);
41485
42320
  } catch {}
41486
42321
  }
42322
+ const projectConfigPath = projectDir ? join57(projectDir, ".mmrc") : join57(process.cwd(), ".mmrc");
42323
+ if (!hasAnyConfig && !exitOnComplete && process.env.MMA_POST_SETUP !== "1") {
42324
+ getDefaultChannel().writeLine(`
42325
+ ` + t("cli.first_run") + `
42326
+ `);
42327
+ const answers = await runSetup();
42328
+ const { config: config2 } = loadConfig({ configDir: mmaDir, projectConfigPath });
42329
+ applyReasoningCliOverride(config2, reasoningLevel);
42330
+ applyAnswersToConfig(config2, answers);
42331
+ saveConfig(config2, legacyConfigPath, dirname26(legacyConfigPath));
42332
+ getDefaultChannel().writeLine(pc.dim(` ${t("cli.setup_saved_restart")}`));
42333
+ relaunchCli();
42334
+ }
41487
42335
  const {
41488
42336
  agent,
41489
42337
  config,
@@ -41498,58 +42346,16 @@ async function main() {
41498
42346
  contextProbe
41499
42347
  } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete, reasoningLevel);
41500
42348
  const repl = new Repl(agent, config, sessionManager, skillsModule, pluginManager, configDir, baseDir, noAgentsMd, logger4, true, envReport, undefined, execModule, contextProbe);
41501
- if (!hasAnyConfig && !exitOnComplete) {
41502
- console.log(pc2.yellow(`
41503
- ` + t("cli.first_run") + `
41504
- `));
41505
- const answers = await runSetup(repl.rl);
41506
- config.provider.type = answers.provider;
41507
- config.provider.baseUrl = answers.apiBase;
41508
- config.provider.apiKey = answers.apiKey;
41509
- config.model = answers.model;
41510
- config.contextWindow = answers.contextWindow;
41511
- config.maxToolIterations = answers.maxToolIterations;
41512
- config.locale = answers.locale;
41513
- if (config.security) {
41514
- config.security.enabled = true;
41515
- config.security.bash.enabled = true;
41516
- config.security.bash.blockDangerousFlags = answers.securityFlagsBlock || config.security.bash.blockDangerousFlags;
41517
- if (answers.securityBashBlock) {
41518
- config.security.bash.blacklist = [
41519
- ...new Set([
41520
- ...config.security.bash.blacklist,
41521
- "rm",
41522
- "dd",
41523
- "chmod",
41524
- "wget",
41525
- "curl",
41526
- "scp",
41527
- "ssh",
41528
- "nc",
41529
- "netcat",
41530
- "sudo",
41531
- "su",
41532
- "kill",
41533
- "pkill",
41534
- "killall",
41535
- "shutdown",
41536
- "reboot"
41537
- ])
41538
- ];
41539
- }
41540
- if (!answers.securityPathsDeny) {
41541
- config.security.paths.denied = [];
41542
- }
41543
- }
41544
- saveConfig(config, legacyConfigPath, dirname25(legacyConfigPath));
41545
- await agent.reconfigure(config);
41546
- }
41547
42349
  startAutoUpdate(config);
41548
42350
  await repl.start();
41549
42351
  }
41550
42352
  }
41551
42353
  main().catch((err) => {
41552
- console.error(err);
42354
+ if (jsonMode) {
42355
+ writeMachineJson(buildJsonError(errMsg(err)));
42356
+ } else {
42357
+ getDefaultChannel().writeLine(err instanceof Error ? err.stack ?? err.message : String(err), "stderr");
42358
+ }
41553
42359
  process.exit(1);
41554
42360
  });
41555
42361
  export {