micro-models-agent 2.11.0 → 2.12.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 (347) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/assets/js/tabs.js +22 -3
  3. package/dist/cli/cache-line.js +1 -0
  4. package/dist/cli/command-suggest.js +5 -4
  5. package/dist/cli/commands.js +231 -122
  6. package/dist/cli/completer.js +132 -31
  7. package/dist/cli/index.js +1 -0
  8. package/dist/cli/json-payload.js +4 -4
  9. package/dist/cli/main.js +166 -61
  10. package/dist/cli/onboarding-commands.js +126 -0
  11. package/dist/cli/plugin-commands.js +2 -1
  12. package/dist/cli/relaunch.js +16 -13
  13. package/dist/cli/repl-commands-lsp.js +75 -0
  14. package/dist/cli/repl-commands-skills.js +105 -0
  15. package/dist/cli/repl-commands.js +589 -266
  16. package/dist/cli/repl.js +436 -177
  17. package/dist/cli/run-result.js +5 -6
  18. package/dist/cli/security-commands.js +37 -28
  19. package/dist/cli/setup-order.js +4 -55
  20. package/dist/cli/setup-prompt.js +3 -2
  21. package/dist/cli/setup.js +27 -107
  22. package/dist/cli/web-command.js +98 -0
  23. package/dist/config/budget.js +5 -5
  24. package/dist/config/config.js +103 -96
  25. package/dist/config/defaults.js +38 -8
  26. package/dist/config/domains.js +24 -27
  27. package/dist/config/env.js +46 -0
  28. package/dist/config/experts.js +2 -0
  29. package/dist/config/index.js +1 -0
  30. package/dist/config/paths.js +56 -0
  31. package/dist/config/redact.js +44 -0
  32. package/dist/config/registry-extra.js +334 -0
  33. package/dist/config/registry.js +584 -0
  34. package/dist/config/security.js +35 -36
  35. package/dist/config/timeouts.js +74 -0
  36. package/dist/config/utils.js +16 -15
  37. package/dist/core/agent/artifact-progress.js +59 -0
  38. package/dist/core/agent/artifact-resolve.js +79 -0
  39. package/dist/core/agent/audit-gate.js +7 -3
  40. package/dist/core/agent/compaction.js +2 -2
  41. package/dist/core/agent/constants.js +33 -4
  42. package/dist/core/agent/context-log.js +454 -0
  43. package/dist/core/agent/context-renderer.js +5 -0
  44. package/dist/core/agent/critic-gate.js +132 -0
  45. package/dist/core/agent/hallucination-gate.js +148 -38
  46. package/dist/core/agent/loop-state.js +15 -0
  47. package/dist/core/agent/prefix-monitor.js +1 -1
  48. package/dist/core/agent/reasoning-resolver.js +10 -1
  49. package/dist/core/agent/token-tracker.js +7 -4
  50. package/dist/core/agent/tool-batch.js +93 -18
  51. package/dist/core/agent/tool-images.js +18 -0
  52. package/dist/core/agent/tool-output.js +65 -11
  53. package/dist/core/agent/tool-pairing.js +60 -0
  54. package/dist/core/agent-moe.js +25 -24
  55. package/dist/core/agent.js +429 -108
  56. package/dist/core/bootstrap/agent-phase.js +66 -0
  57. package/dist/core/bootstrap/config-phase.js +86 -0
  58. package/dist/core/bootstrap/modules-phase.js +269 -0
  59. package/dist/core/bootstrap/provider-phase.js +183 -0
  60. package/dist/core/bootstrap/session-phase.js +204 -0
  61. package/dist/core/bootstrap/state.js +94 -0
  62. package/dist/core/bootstrap/workspace-phase.js +115 -0
  63. package/dist/core/bootstrap.js +92 -660
  64. package/dist/core/crash-handler.js +17 -7
  65. package/dist/core/environment.js +37 -12
  66. package/dist/core/host-plan.js +43 -0
  67. package/dist/core/host.js +23 -0
  68. package/dist/core/index.js +1 -0
  69. package/dist/core/prompt-builder.js +17 -1
  70. package/dist/core/prompt-overflow.js +42 -43
  71. package/dist/core/session-logger.js +122 -30
  72. package/dist/core/system-prompt.js +117 -0
  73. package/dist/core/version.js +6 -4
  74. package/dist/core/web-host.js +34 -0
  75. package/dist/core/workspace.js +19 -15
  76. package/dist/i18n/index.js +37 -3
  77. package/dist/index.js +7 -3
  78. package/dist/llm/image-utils.js +55 -64
  79. package/dist/llm/llm-errors.js +9 -0
  80. package/dist/llm/model-loader.js +10 -32
  81. package/dist/llm/models-dev.js +121 -0
  82. package/dist/llm/openai-compat.js +146 -73
  83. package/dist/llm/orchestrator.js +33 -11
  84. package/dist/llm/provider-budget.js +2 -2
  85. package/dist/llm/provider-context.js +233 -0
  86. package/dist/llm/provider.js +1 -1
  87. package/dist/llm/response.js +5 -0
  88. package/dist/llm/token-counter.js +27 -11
  89. package/dist/logger/app-logger.js +48 -22
  90. package/dist/logger/file-log.js +28 -19
  91. package/dist/logger/index.js +1 -0
  92. package/dist/main.js +273 -47
  93. package/dist/migration/backup.js +14 -3
  94. package/dist/migration/detect.js +12 -3
  95. package/dist/migration/index.js +1 -0
  96. package/dist/modules/artifacts/store.js +9 -8
  97. package/dist/modules/browser/actions.js +6 -0
  98. package/dist/modules/browser/bridge-client.js +14 -12
  99. package/dist/modules/browser/bridge-path.js +4 -4
  100. package/dist/modules/browser/console-buffer.js +37 -0
  101. package/dist/modules/browser/cookie-store.js +5 -0
  102. package/dist/modules/browser/driver-types.js +1 -0
  103. package/dist/modules/browser/driver.js +19 -11
  104. package/dist/modules/browser/index.js +3 -1
  105. package/dist/modules/browser/module.js +2 -1
  106. package/dist/modules/browser/session.js +10 -30
  107. package/dist/modules/browser/snapshot.js +19 -13
  108. package/dist/modules/browser/types.js +1 -0
  109. package/dist/modules/certification/cli.js +28 -20
  110. package/dist/modules/certification/fact-checker.js +9 -1
  111. package/dist/modules/certification/loader.js +9 -2
  112. package/dist/modules/certification/manifest.js +83 -21
  113. package/dist/modules/certification/runner.js +23 -13
  114. package/dist/modules/certification/scenarios.js +20 -20
  115. package/dist/modules/certification/syntax-scenarios.js +1 -2
  116. package/dist/modules/context/chunk-query.js +11 -9
  117. package/dist/modules/context/fact-extractor.js +37 -39
  118. package/dist/modules/context/index.js +1 -0
  119. package/dist/modules/context/manager.js +106 -80
  120. package/dist/modules/critic/client.js +176 -0
  121. package/dist/modules/critic/evidence.js +81 -0
  122. package/dist/modules/critic/provider.js +45 -0
  123. package/dist/modules/critic/tools.js +78 -0
  124. package/dist/modules/critic/types.js +1 -0
  125. package/dist/modules/execution/audit-runners.js +28 -34
  126. package/dist/modules/execution/auditor.js +53 -49
  127. package/dist/modules/execution/execution-plugin.js +142 -102
  128. package/dist/modules/execution/index.js +1 -1
  129. package/dist/modules/execution/input-from.js +37 -13
  130. package/dist/modules/execution/module.js +368 -191
  131. package/dist/modules/execution/moe-executor.js +53 -26
  132. package/dist/modules/execution/plan-actions.js +320 -202
  133. package/dist/modules/execution/plan-checks.js +35 -0
  134. package/dist/modules/execution/plan-coverage.js +36 -33
  135. package/dist/modules/execution/plan-steps.js +11 -3
  136. package/dist/modules/execution/plan-store.js +83 -17
  137. package/dist/modules/execution/plan-tool.js +89 -35
  138. package/dist/modules/execution/plan-validator.js +30 -10
  139. package/dist/modules/execution/planner.js +22 -13
  140. package/dist/modules/execution/stuck-detector.js +196 -93
  141. package/dist/modules/execution/tracker.js +22 -8
  142. package/dist/modules/execution/verifier.js +69 -48
  143. package/dist/modules/execution/windows-commands.js +12 -12
  144. package/dist/modules/hallucination/artifact-claim.js +93 -0
  145. package/dist/modules/hallucination/confidence.js +13 -11
  146. package/dist/modules/hallucination/consistency.js +10 -2
  147. package/dist/modules/hallucination/detector.js +10 -5
  148. package/dist/modules/hallucination/factual.js +43 -26
  149. package/dist/modules/hallucination/index.js +1 -0
  150. package/dist/modules/hallucination/js-identifiers.js +44 -45
  151. package/dist/modules/hallucination/llm-judge.js +17 -12
  152. package/dist/modules/hallucination/success-claim.js +59 -0
  153. package/dist/modules/indexer/cache.js +52 -4
  154. package/dist/modules/indexer/index.js +1 -0
  155. package/dist/modules/indexer/map-command.js +2 -4
  156. package/dist/modules/indexer/map-select.js +16 -16
  157. package/dist/modules/indexer/module.js +47 -12
  158. package/dist/modules/indexer/project-profile.js +8 -7
  159. package/dist/modules/indexer/symbols.js +15 -15
  160. package/dist/modules/indexer/walker.js +159 -29
  161. package/dist/modules/lsp/check-tool.js +7 -5
  162. package/dist/modules/lsp/client.js +39 -39
  163. package/dist/modules/lsp/command.js +17 -24
  164. package/dist/modules/lsp/config.js +12 -11
  165. package/dist/modules/lsp/index.js +1 -0
  166. package/dist/modules/lsp/module.js +48 -46
  167. package/dist/modules/lsp/probe.js +13 -14
  168. package/dist/modules/lsp/project-root.js +14 -17
  169. package/dist/modules/lsp/startup-check.js +18 -16
  170. package/dist/modules/mcp/client.js +59 -62
  171. package/dist/modules/mcp/index.js +1 -0
  172. package/dist/modules/mcp/module.js +66 -37
  173. package/dist/modules/mcp/registry.js +5 -0
  174. package/dist/modules/memory/index.js +1 -0
  175. package/dist/modules/memory/module.js +12 -8
  176. package/dist/modules/memory/search.js +4 -1
  177. package/dist/modules/memory/store.js +40 -2
  178. package/dist/modules/onboarding/init.js +47 -0
  179. package/dist/modules/onboarding/meet.js +30 -0
  180. package/dist/modules/onboarding/mode.js +30 -0
  181. package/dist/modules/onboarding/prompts.js +43 -0
  182. package/dist/modules/pipelines/engine.js +10 -0
  183. package/dist/modules/pipelines/index.js +1 -0
  184. package/dist/modules/pipelines/parser.js +4 -1
  185. package/dist/modules/pipelines/template.js +4 -0
  186. package/dist/modules/plugins/builtin/lint-on-write.js +80 -67
  187. package/dist/modules/plugins/builtin/notify.js +2 -0
  188. package/dist/modules/plugins/index.js +1 -0
  189. package/dist/modules/plugins/loader.js +18 -3
  190. package/dist/modules/plugins/manager.js +37 -17
  191. package/dist/modules/pricing/index.js +10 -11
  192. package/dist/modules/pricing/prices.js +12 -12
  193. package/dist/modules/processes/index.js +1 -0
  194. package/dist/modules/processes/kill-tree.js +27 -31
  195. package/dist/modules/processes/registry.js +44 -25
  196. package/dist/modules/processes/runner.js +4 -4
  197. package/dist/modules/providers/capabilities.js +28 -0
  198. package/dist/modules/providers/create.js +3 -4
  199. package/dist/modules/providers/factory.js +7 -7
  200. package/dist/modules/providers/fallback.js +12 -12
  201. package/dist/modules/providers/health.js +4 -4
  202. package/dist/modules/providers/manager.js +50 -19
  203. package/dist/modules/providers/naming.js +15 -0
  204. package/dist/modules/providers/preflight.js +71 -0
  205. package/dist/modules/providers/presets.js +39 -8
  206. package/dist/modules/providers/registry.js +7 -2
  207. package/dist/modules/reasoning/policy.js +8 -6
  208. package/dist/modules/reasoning/probe.js +30 -25
  209. package/dist/modules/security/audit-log.js +19 -36
  210. package/dist/modules/security/audit-notifier.js +35 -75
  211. package/dist/modules/security/command-validator.js +99 -51
  212. package/dist/modules/security/content-scanner.js +8 -8
  213. package/dist/modules/security/data-sanitizer.js +9 -16
  214. package/dist/modules/security/encryption.js +32 -52
  215. package/dist/modules/security/index.js +2 -1
  216. package/dist/modules/security/network-validator.js +120 -43
  217. package/dist/modules/security/path-validator.js +61 -46
  218. package/dist/modules/security/protected-paths.js +73 -0
  219. package/dist/modules/security/rate-limiter.js +17 -49
  220. package/dist/modules/security/security-policies.js +25 -57
  221. package/dist/modules/security/session-encryption.js +32 -71
  222. package/dist/modules/security/session-isolation.js +15 -28
  223. package/dist/modules/session/auto-name.js +63 -0
  224. package/dist/modules/session/export.js +98 -0
  225. package/dist/modules/session/index.js +1 -0
  226. package/dist/modules/session/manager.js +79 -28
  227. package/dist/modules/session/module.js +4 -3
  228. package/dist/modules/session/store.js +57 -20
  229. package/dist/modules/setup/answers.js +35 -0
  230. package/dist/modules/setup/apply.js +79 -0
  231. package/dist/modules/setup/discovery.js +72 -0
  232. package/dist/modules/skills/index.js +1 -0
  233. package/dist/modules/skills/loader.js +9 -1
  234. package/dist/modules/skills/module.js +11 -0
  235. package/dist/modules/updater/changelog-reader.js +15 -16
  236. package/dist/modules/updater/checker.js +9 -4
  237. package/dist/modules/updater/dev-detect.js +7 -6
  238. package/dist/modules/updater/index.js +1 -0
  239. package/dist/modules/updater/module.js +17 -15
  240. package/dist/modules/user-profile/compressor.js +2 -0
  241. package/dist/modules/user-profile/index.js +1 -0
  242. package/dist/modules/user-profile/profile.js +10 -1
  243. package/dist/modules/webui/answer-api.js +29 -0
  244. package/dist/modules/webui/assets.js +50 -0
  245. package/dist/modules/webui/body.js +21 -0
  246. package/dist/modules/webui/commands-settings.js +209 -0
  247. package/dist/modules/webui/commands-shared.js +60 -0
  248. package/dist/modules/webui/commands.js +174 -0
  249. package/dist/modules/webui/config-api.js +134 -0
  250. package/dist/modules/webui/file-api.js +202 -0
  251. package/dist/modules/webui/forward.js +159 -0
  252. package/dist/modules/webui/history-api.js +112 -0
  253. package/dist/modules/webui/host-state.js +60 -0
  254. package/dist/modules/webui/i18n-api.js +9 -0
  255. package/dist/modules/webui/limits.js +6 -0
  256. package/dist/modules/webui/log-forward.js +20 -0
  257. package/dist/modules/webui/memory-commands.js +64 -0
  258. package/dist/modules/webui/model-cache.js +18 -0
  259. package/dist/modules/webui/module.js +148 -0
  260. package/dist/modules/webui/persist.js +24 -0
  261. package/dist/modules/webui/prompt-io.js +97 -0
  262. package/dist/modules/webui/providers-api.js +337 -0
  263. package/dist/modules/webui/providers-view.js +56 -0
  264. package/dist/modules/webui/reasoning-view.js +15 -0
  265. package/dist/modules/webui/run-agent.js +81 -0
  266. package/dist/modules/webui/server.js +284 -0
  267. package/dist/modules/webui/sessions-api.js +178 -0
  268. package/dist/modules/webui/settings-api.js +561 -0
  269. package/dist/modules/webui/setup-api.js +201 -0
  270. package/dist/modules/webui/state.js +74 -0
  271. package/dist/modules/webui/util.js +261 -0
  272. package/dist/output/bus.js +7 -2
  273. package/dist/output/channel.js +80 -28
  274. package/dist/output/format.js +2 -1
  275. package/dist/output/index.js +1 -0
  276. package/dist/output/json-sink.js +5 -3
  277. package/dist/output/machine.js +4 -3
  278. package/dist/output/session-sink.js +4 -4
  279. package/dist/tools/approve.js +4 -0
  280. package/dist/tools/attach-image.js +5 -4
  281. package/dist/tools/auto-fixer.js +26 -44
  282. package/dist/tools/auto-tags.js +83 -0
  283. package/dist/tools/bash.js +193 -116
  284. package/dist/tools/browser.js +76 -31
  285. package/dist/tools/chunk-query.js +14 -6
  286. package/dist/tools/create-dir.js +9 -5
  287. package/dist/tools/delete-file.js +9 -5
  288. package/dist/tools/download-file.js +32 -7
  289. package/dist/tools/edit-file.js +52 -14
  290. package/dist/tools/enable-tools.js +6 -6
  291. package/dist/tools/executor.js +132 -27
  292. package/dist/tools/file-info.js +3 -1
  293. package/dist/tools/filter-tools.js +3 -3
  294. package/dist/tools/glob-tool.js +4 -1
  295. package/dist/tools/grep-tool.js +13 -10
  296. package/dist/tools/hidden-tools-block.js +6 -6
  297. package/dist/tools/index.js +16 -8
  298. package/dist/tools/list-dir.js +4 -2
  299. package/dist/tools/load-skill.js +7 -0
  300. package/dist/tools/mcp-call.js +15 -4
  301. package/dist/tools/meet-done.js +14 -0
  302. package/dist/tools/move-file.js +14 -7
  303. package/dist/tools/path-utils.js +29 -29
  304. package/dist/tools/pipeline-run.js +29 -7
  305. package/dist/tools/preview.js +1 -1
  306. package/dist/tools/process-ids.js +31 -0
  307. package/dist/tools/process-kill.js +9 -16
  308. package/dist/tools/process-list.js +1 -0
  309. package/dist/tools/process-log.js +11 -16
  310. package/dist/tools/process-wait.js +63 -0
  311. package/dist/tools/prompt-io.js +4 -3
  312. package/dist/tools/question.js +172 -25
  313. package/dist/tools/read-file.js +55 -34
  314. package/dist/tools/recall.js +14 -8
  315. package/dist/tools/registry.js +6 -5
  316. package/dist/tools/remember.js +8 -4
  317. package/dist/tools/scope-request.js +11 -6
  318. package/dist/tools/search-history.js +5 -2
  319. package/dist/tools/session-info.js +2 -0
  320. package/dist/tools/set-thinking.js +8 -4
  321. package/dist/tools/subagent.js +59 -39
  322. package/dist/tools/syntax-validator.js +292 -90
  323. package/dist/tools/user-input.js +22 -18
  324. package/dist/tools/web-browse.js +9 -3
  325. package/dist/tools/web-fetch.js +12 -23
  326. package/dist/tools/web-search.js +7 -5
  327. package/dist/tools/write-file.js +45 -15
  328. package/dist/ui/action-log.js +13 -0
  329. package/dist/ui/box.js +4 -3
  330. package/dist/ui/colors.js +2 -0
  331. package/dist/ui/diff.js +6 -5
  332. package/dist/ui/index.js +1 -0
  333. package/dist/ui/line-editor.js +230 -122
  334. package/dist/ui/line-math.js +10 -2
  335. package/dist/ui/md-formatter.js +57 -37
  336. package/dist/ui/output.js +8 -3
  337. package/dist/ui/plan-view.js +21 -10
  338. package/dist/ui/renderer.js +393 -67
  339. package/dist/ui/spinner.js +16 -5
  340. package/dist/ui/table.js +15 -17
  341. package/dist/ui/theme.js +143 -0
  342. package/dist/utils/child-run.js +20 -0
  343. package/dist/utils/error.js +1 -1
  344. package/dist/utils/index.js +2 -0
  345. package/dist/utils/retry.js +2 -2
  346. package/dist/utils/truncate.js +1 -1
  347. package/package.json +1 -1
@@ -1,15 +1,19 @@
1
+ // Commander-программа: setup/meet/init/web/agents/config/session/* и фабрика createProgram.
1
2
  import { Command } from "commander";
2
3
  import { bootstrap } from "../core/bootstrap";
3
4
  import { saveConfig } from "../config/config";
4
5
  import { runSetup } from "./setup";
6
+ import { applyAnswersToConfig } from "./setup-order";
5
7
  import { t } from "../i18n/index";
6
8
  import { pc } from "../ui/colors";
7
9
  import { join, dirname } from "path";
8
10
  import { homedir } from "os";
9
- import { existsSync } from "fs";
11
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
12
+ import { formatExport, redactExport, sanitizeFileName, extensionFor, } from "../modules/session/export";
10
13
  import { createSecurityCommand } from "./security-commands";
11
14
  import { createPluginCommand } from "./plugin-commands";
12
15
  import { HOSTED_BASE_URLS } from "../modules/providers/presets";
16
+ import { providerNameTaken } from "../modules/providers/naming";
13
17
  import { probeProviders, targetsFromProviders } from "../modules/providers/health";
14
18
  import { readMmaVersion } from "../core/version";
15
19
  import { runMapAction } from "../modules/indexer/map-command";
@@ -18,97 +22,107 @@ import { fetchProviderBudget } from "../llm/provider-budget";
18
22
  import { formatCost } from "../modules/pricing/prices";
19
23
  import { readChangelog, extractLatestChangelog, extractChangelogRange, } from "../modules/updater/changelog-reader";
20
24
  import { getDefaultChannel, writeMachineJson } from "../output";
25
+ import { setConfigValue } from "../config/registry";
26
+ import { redactConfigSecrets } from "../config/redact";
27
+ import { MMA_DIR_NAME, globalConfigFile, globalExportsDir } from "../config/paths";
21
28
  const version = readMmaVersion();
29
+ /** Конфиг для `mma config show`: секреты затёрты, если явно не просили. */
30
+ export function configForDisplay(config, showSecrets) {
31
+ return showSecrets ? config : redactConfigSecrets(config);
32
+ }
33
+ /** Общее тело визарда настройки провайдера (`mma setup` и устаревший `mma init`). */
34
+ async function runWizardCommand() {
35
+ const answers = await runSetup();
36
+ const configPath = globalConfigFile();
37
+ const { config } = await bootstrap();
38
+ applyAnswersToConfig(config, answers);
39
+ saveConfig(config, configPath, dirname(configPath));
40
+ getDefaultChannel().writeLine(t("cli.config_saved"));
41
+ }
42
+ function buildSetupCommand(program) {
43
+ program.command("setup").description(t("cli.setup")).action(runWizardCommand);
44
+ }
45
+ function buildMeetCommand(program) {
46
+ program.command("meet").description(t("cli.meet")).action(() => { });
47
+ }
22
48
  function buildInitCommand(program) {
23
49
  program
24
50
  .command("init")
25
51
  .description(t("cli.init"))
26
52
  .action(async () => {
27
- const answers = await runSetup();
28
- const configPath = join(homedir(), ".mma", "config.json");
29
- const { config } = await bootstrap();
30
- config.provider.type = answers.provider;
31
- config.provider.baseUrl = answers.apiBase;
32
- config.provider.apiKey = answers.apiKey;
33
- config.model = answers.model;
34
- config.contextWindow = answers.contextWindow;
35
- config.maxToolIterations = answers.maxToolIterations;
36
- config.locale = answers.locale;
37
- // Apply security settings from wizard.
38
- // Security is enabled by default (balanced); wizard answers only tighten it.
39
- if (config.security) {
40
- config.security.enabled = true;
41
- config.security.bash.enabled = true;
42
- config.security.bash.blockDangerousFlags =
43
- answers.securityFlagsBlock || config.security.bash.blockDangerousFlags;
44
- if (answers.securityBashBlock) {
45
- config.security.bash.blacklist = [
46
- ...new Set([
47
- ...config.security.bash.blacklist,
48
- "rm",
49
- "dd",
50
- "chmod",
51
- "wget",
52
- "curl",
53
- "scp",
54
- "ssh",
55
- "nc",
56
- "netcat",
57
- "sudo",
58
- "su",
59
- "kill",
60
- "pkill",
61
- "killall",
62
- "shutdown",
63
- "reboot",
64
- ]),
65
- ];
66
- }
67
- if (!answers.securityPathsDeny) {
68
- config.security.paths.denied = [];
69
- }
70
- }
71
- saveConfig(config, configPath, dirname(configPath));
72
- getDefaultChannel().writeLine(t("cli.config_saved"));
53
+ getDefaultChannel().writeLine(pc.yellow(t("cli.init_deprecated")));
54
+ await runWizardCommand();
55
+ });
56
+ }
57
+ function buildWebCommand(program) {
58
+ program
59
+ .command("web")
60
+ .description(t("cli.web.description"))
61
+ .option("-p, --port <n>", t("cli.web.port"))
62
+ .option("--host <addr>", t("cli.web.host"))
63
+ .option("--token <t>", t("cli.web.token"))
64
+ .option("--no-open", t("cli.web.no_open"))
65
+ .action(() => {
66
+ /* Диспатчится из main.ts после program.parse(): веб-сервер долгоживущий,
67
+ хук one-shot выхода его резать не должен. */
73
68
  });
74
69
  }
70
+ function buildAgentsCommand(program) {
71
+ const agents = program.command("agents").description(t("cli.agents"));
72
+ agents
73
+ .command("init")
74
+ .description(t("cli.agents_init"))
75
+ .action(() => { });
76
+ }
75
77
  function buildConfigCommands(program) {
76
78
  const configCmd = program.command("config").description(t("cli.manage_config"));
77
79
  configCmd
78
80
  .command("set")
79
81
  .argument("<key>", t("cli.config_key"))
80
- .argument("<value>", "Config value")
82
+ .argument("<value>", t("cli.config_value"))
81
83
  .description(t("cli.set_value"))
82
- .action(async (key, value) => {
83
- const configPath = join(homedir(), ".mma", "config.json");
84
+ .option("--force", t("cli.config_force"))
85
+ .action(async (key, value, opts) => {
86
+ const configPath = globalConfigFile();
84
87
  const { config } = await bootstrap();
85
- const keys = key.split(".");
86
- let obj = config;
87
- for (let i = 0; i < keys.length - 1; i++) {
88
- if (!(keys[i] in obj))
89
- obj[keys[i]] = {};
90
- obj = obj[keys[i]];
91
- }
92
- const lastKey = keys[keys.length - 1];
93
- if (value === "true")
94
- obj[lastKey] = true;
95
- else if (value === "false")
96
- obj[lastKey] = false;
97
- else if (/^\d+$/.test(value))
98
- obj[lastKey] = parseInt(value, 10);
99
- else if (/^\d+\.\d+$/.test(value))
100
- obj[lastKey] = parseFloat(value);
101
- else
102
- obj[lastKey] = value;
88
+ if (opts.force) {
89
+ const keys = key.split(".");
90
+ let obj = config;
91
+ for (let i = 0; i < keys.length - 1; i++) {
92
+ if (!(keys[i] in obj))
93
+ obj[keys[i]] = {};
94
+ obj = obj[keys[i]];
95
+ }
96
+ const lastKey = keys[keys.length - 1];
97
+ if (value === "true")
98
+ obj[lastKey] = true;
99
+ else if (value === "false")
100
+ obj[lastKey] = false;
101
+ else if (/^\d+$/.test(value))
102
+ obj[lastKey] = parseInt(value, 10);
103
+ else if (/^\d+\.\d+$/.test(value))
104
+ obj[lastKey] = parseFloat(value);
105
+ else
106
+ obj[lastKey] = value;
107
+ saveConfig(config, configPath, dirname(configPath));
108
+ getDefaultChannel().writeLine(t("cli.set_done", { key, value }));
109
+ return;
110
+ }
111
+ const r = setConfigValue(config, key, value);
112
+ if (!r.ok) {
113
+ getDefaultChannel().writeLine(pc.yellow(t("cli.config_invalid", { key: r.input, reason: r.reason })), "stderr");
114
+ return;
115
+ }
103
116
  saveConfig(config, configPath, dirname(configPath));
104
- getDefaultChannel().writeLine(t("cli.set_done", { key, value }));
117
+ getDefaultChannel().writeLine(t("cli.set_done", { key: r.key, value: r.display }));
105
118
  });
106
119
  configCmd
107
120
  .command("show")
108
121
  .description(t("cli.show_config"))
109
- .action(async () => {
122
+ .option("--show-secrets", t("cli.show_secrets"))
123
+ .action(async (opts) => {
110
124
  const { config } = await bootstrap();
111
- writeMachineJson(config);
125
+ writeMachineJson(configForDisplay(config, opts.showSecrets));
112
126
  });
113
127
  configCmd
114
128
  .command("migrate")
@@ -116,7 +130,7 @@ function buildConfigCommands(program) {
116
130
  .action(async () => {
117
131
  const { loadConfig } = await import("../config/config");
118
132
  const { hasDomainFiles } = await import("../config/domains");
119
- const configDir = join(homedir(), ".mma");
133
+ const configDir = join(homedir(), MMA_DIR_NAME);
120
134
  const configPath = join(configDir, "config.json");
121
135
  if (hasDomainFiles(configDir)) {
122
136
  getDefaultChannel().writeLine(pc.yellow(t("config.migrate_no_legacy")));
@@ -129,8 +143,8 @@ function buildConfigCommands(program) {
129
143
  getDefaultChannel().writeLine(t("config.migrate_start"));
130
144
  const { config } = loadConfig({ configDir, projectConfigPath: join(configDir, ".mmrc") });
131
145
  saveConfig(config, configPath, configDir);
132
- // Rename legacy file
133
- const bakPath = configPath + ".bak";
146
+ // Переименование legacy-файла.
147
+ const bakPath = `${configPath}.bak`;
134
148
  const { renameSync } = await import("fs");
135
149
  renameSync(configPath, bakPath);
136
150
  const { readdirSync } = await import("fs");
@@ -146,12 +160,14 @@ function buildModelCommands(program) {
146
160
  .action(async () => {
147
161
  const { config } = await bootstrap();
148
162
  getDefaultChannel().writeLine(`${t("cli.current_model")} ${config.model}`);
149
- // Fetch available models from provider
163
+ // Тянем доступные модели с провайдера.
150
164
  const { createProvider } = await import("../modules/providers/create");
151
- const provider = createProvider(config.provider.type, {
165
+ const { activeProviderEndpoint } = await import("../modules/providers/manager");
166
+ const endpoint = activeProviderEndpoint(config.provider);
167
+ const provider = createProvider(endpoint.type, {
152
168
  model: config.model,
153
- baseUrl: config.provider.baseUrl,
154
- apiKey: config.provider.apiKey,
169
+ baseUrl: endpoint.baseUrl,
170
+ apiKey: endpoint.apiKey,
155
171
  contextWindow: config.contextWindow,
156
172
  });
157
173
  const spinner = (await import("../ui/spinner")).Spinner;
@@ -187,10 +203,10 @@ function buildModelCommands(program) {
187
203
  });
188
204
  model
189
205
  .command("use")
190
- .argument("<name>", "Model name")
206
+ .argument("<name>", t("cli.model_name"))
191
207
  .description(t("cli.set_model"))
192
208
  .action(async (name) => {
193
- const configPath = join(homedir(), ".mma", "config.json");
209
+ const configPath = globalConfigFile();
194
210
  const { config } = await bootstrap();
195
211
  config.model = name;
196
212
  saveConfig(config, configPath, dirname(configPath));
@@ -198,7 +214,7 @@ function buildModelCommands(program) {
198
214
  });
199
215
  model
200
216
  .command("certify")
201
- .argument("<name>", "Model name")
217
+ .argument("<name>", t("cli.model_name"))
202
218
  .option("--provider-url <url>", t("cli.cert_provider_url"))
203
219
  .option("--provider-key <key>", t("cli.cert_provider_key"))
204
220
  .option("--context-window <n>", t("cli.cert_context_window"))
@@ -234,7 +250,7 @@ function buildModelCommands(program) {
234
250
  });
235
251
  model
236
252
  .command("cert-status")
237
- .argument("<name>", "Model name")
253
+ .argument("<name>", t("cli.model_name"))
238
254
  .description(t("cli.cert_status"))
239
255
  .action(async (name) => {
240
256
  const { config } = await bootstrap();
@@ -250,7 +266,7 @@ function buildModelCommands(program) {
250
266
  });
251
267
  model
252
268
  .command("uncertify")
253
- .argument("<name>", "Model name")
269
+ .argument("<name>", t("cli.model_name"))
254
270
  .description(t("cli.cert_uncertify"))
255
271
  .action(async (name) => {
256
272
  const { config } = await bootstrap();
@@ -262,7 +278,7 @@ function buildContextCommand(program) {
262
278
  program
263
279
  .command("context")
264
280
  .description(t("cli.manage_context"))
265
- .argument("[size]", "Context window size in tokens (omit to show the budget breakdown)")
281
+ .argument("[size]", t("cli.context_size_arg"))
266
282
  .option("--system <fraction>", t("cli.context_system_fraction"))
267
283
  .option("--reserve <fraction>", t("cli.context_reserve_fraction"))
268
284
  .action(async (size, opts) => {
@@ -285,7 +301,7 @@ function buildContextCommand(program) {
285
301
  return;
286
302
  }
287
303
  const contextWindow = parseInt(size, 10);
288
- if (isNaN(contextWindow) || contextWindow < 1024) {
304
+ if (Number.isNaN(contextWindow) || contextWindow < 1024) {
289
305
  getDefaultChannel().writeLine(t("cli.invalid_context_size"));
290
306
  return;
291
307
  }
@@ -366,7 +382,7 @@ function buildProviderCommands(program) {
366
382
  provider
367
383
  .command("check")
368
384
  .description(t("cli.provider_check"))
369
- .option("--timeout <ms>", "Per-provider probe timeout in ms")
385
+ .option("--timeout <ms>", t("cli.probe_timeout"))
370
386
  .action(async (opts) => {
371
387
  const { config, agent } = await bootstrap();
372
388
  const providers = agent.listProviders();
@@ -409,14 +425,17 @@ function buildProviderCommands(program) {
409
425
  });
410
426
  provider
411
427
  .command("use")
412
- .argument("<name>", "Provider name")
428
+ .argument("<name>", t("cli.provider_name"))
413
429
  .description(t("cli.set_provider"))
414
430
  .action(async (name) => {
415
- const configPath = join(homedir(), ".mma", "config.json");
431
+ const configPath = globalConfigFile();
416
432
  const { config, agent } = await bootstrap();
417
433
  if (config.provider.entries && config.provider.entries.length > 0) {
418
434
  try {
419
435
  await agent.setProvider(name);
436
+ // Персист: `agent.setProvider` мутит только in-memory конфиг, так что свитч
437
+ // молча терялся на выходе для мульти-записных конфигов.
438
+ saveConfig(config, configPath, dirname(configPath));
420
439
  getDefaultChannel().writeLine(t("cli.provider_set", { name }));
421
440
  }
422
441
  catch (e) {
@@ -437,19 +456,19 @@ function buildProviderCommands(program) {
437
456
  });
438
457
  provider
439
458
  .command("add")
440
- .argument("<name>", "Provider type or label")
441
- .option("--url <url>", "Base URL")
442
- .option("--key <key>", "API key")
443
- .option("--priority <n>", "Fallback priority (lower = tried first)")
444
- .option("--context-window <n>", "Context window override for this entry")
445
- .option("--rpm <n>", "Max requests per minute for this entry")
446
- .option("--parallel <n>", "Max parallel tasks for this entry")
459
+ .argument("<name>", t("cli.provider_type_label"))
460
+ .option("--url <url>", t("cli.provider_base_url"))
461
+ .option("--key <key>", t("cli.provider_api_key"))
462
+ .option("--priority <n>", t("cli.provider_priority"))
463
+ .option("--context-window <n>", t("cli.provider_context_window"))
464
+ .option("--rpm <n>", t("cli.provider_rpm"))
465
+ .option("--parallel <n>", t("cli.provider_parallel"))
447
466
  .description(t("cli.add_provider"))
448
467
  .action(async (name, opts) => {
449
- const configPath = join(homedir(), ".mma", "config.json");
468
+ const configPath = globalConfigFile();
450
469
  const { config } = await bootstrap();
451
470
  const entries = Array.isArray(config.provider.entries) ? config.provider.entries : [];
452
- // If a legacy single provider exists, seed the list with it first.
471
+ // Есть legacy-одиночка — сидим список сначала с него.
453
472
  if (entries.length === 0) {
454
473
  entries.push({
455
474
  type: config.provider.type,
@@ -463,6 +482,10 @@ function buildProviderCommands(program) {
463
482
  getDefaultChannel().writeLine(pc.red(t("cli.provider_no_url", { name })));
464
483
  return;
465
484
  }
485
+ if (providerNameTaken(entries, name)) {
486
+ getDefaultChannel().writeLine(pc.red(t("cli.provider_name_conflict", { name })));
487
+ return;
488
+ }
466
489
  entries.push({
467
490
  type: name,
468
491
  label: name,
@@ -503,12 +526,12 @@ function buildSessionCommands(program) {
503
526
  const active = sessionManager.getActive();
504
527
  for (const s of sessions) {
505
528
  const marker = s.id === active ? "*" : " ";
506
- getDefaultChannel().writeLine(` ${marker} ${s.id.slice(0, 12)} ${s.name} ${s.messageCount} msgs ${s.updatedAt.slice(0, 10)}`);
529
+ getDefaultChannel().writeLine(` ${marker} ${s.id.slice(0, 12)} ${s.name} ${s.messageCount} ${t("repl.msgs")} ${s.updatedAt.slice(0, 10)}`);
507
530
  }
508
531
  });
509
532
  session
510
533
  .command("show")
511
- .argument("<id>", "Session id")
534
+ .argument("<id>", t("cli.session_id"))
512
535
  .description(t("cli.show_details"))
513
536
  .action(async (id) => {
514
537
  const { sessionManager } = await bootstrap();
@@ -517,18 +540,18 @@ function buildSessionCommands(program) {
517
540
  getDefaultChannel().writeLine(t("session.not_found", { id }));
518
541
  return;
519
542
  }
520
- getDefaultChannel().writeLine(`ID: ${meta.id}`);
521
- getDefaultChannel().writeLine(`Name: ${meta.name}`);
522
- getDefaultChannel().writeLine(`Created: ${meta.createdAt}`);
523
- getDefaultChannel().writeLine(`Updated: ${meta.updatedAt}`);
524
- getDefaultChannel().writeLine(`Messages: ${meta.messageCount}`);
525
- getDefaultChannel().writeLine(`Model: ${meta.model}`);
526
- getDefaultChannel().writeLine(`Context: ${meta.contextWindow}`);
527
- getDefaultChannel().writeLine(`Project: ${meta.projectDir}`);
543
+ getDefaultChannel().writeLine(`${t("cli.session_field_id")} ${meta.id}`);
544
+ getDefaultChannel().writeLine(`${t("cli.session_field_name")} ${meta.name}`);
545
+ getDefaultChannel().writeLine(`${t("cli.session_field_created")} ${meta.createdAt}`);
546
+ getDefaultChannel().writeLine(`${t("cli.session_field_updated")} ${meta.updatedAt}`);
547
+ getDefaultChannel().writeLine(`${t("cli.session_field_messages")} ${meta.messageCount}`);
548
+ getDefaultChannel().writeLine(`${t("cli.session_field_model")} ${meta.model}`);
549
+ getDefaultChannel().writeLine(`${t("cli.session_field_context")} ${meta.contextWindow}`);
550
+ getDefaultChannel().writeLine(`${t("cli.session_field_project")} ${meta.projectDir}`);
528
551
  const moeEvents = sessionManager.loadSessionLog(id).filter((e) => e.type.startsWith("moe_"));
529
552
  if (moeEvents.length > 0) {
530
553
  getDefaultChannel().writeLine("");
531
- getDefaultChannel().writeLine(pc.cyan("MoE events:"));
554
+ getDefaultChannel().writeLine(pc.cyan(t("cli.session_moe_events")));
532
555
  for (const e of moeEvents) {
533
556
  const ts = e.ts.slice(11, 19);
534
557
  if (e.type === "moe_subtask") {
@@ -577,15 +600,87 @@ function buildSessionCommands(program) {
577
600
  }
578
601
  }
579
602
  });
603
+ session
604
+ .command("export")
605
+ .argument("<id>", t("cli.session_id_or_prefix"))
606
+ .description(t("cli.export_session"))
607
+ .option("--format <format>", t("cli.export_format"), "md")
608
+ .option("--out <path>", t("cli.export_out"))
609
+ .option("--no-redact", t("cli.export_no_redact"))
610
+ .option("--compact", t("cli.export_compact"))
611
+ .action(async (id, opts) => {
612
+ const { sessionManager } = await bootstrap();
613
+ const meta = sessionManager.get(id) ??
614
+ sessionManager.list().find((s) => s.id.startsWith(id)) ??
615
+ sessionManager.list().find((s) => s.name.toLowerCase().includes(id.toLowerCase()));
616
+ if (!meta) {
617
+ getDefaultChannel().writeLine(t("session.not_found", { id }));
618
+ return;
619
+ }
620
+ const format = opts.format;
621
+ if (format !== "md" && format !== "json" && format !== "jsonl") {
622
+ getDefaultChannel().writeLine(t("export.invalid_format", { format }));
623
+ return;
624
+ }
625
+ const messages = sessionManager.getHistory(meta.id);
626
+ const log = sessionManager.loadSessionLog(meta.id);
627
+ if (format === "jsonl" ? log.length === 0 : messages.length === 0) {
628
+ getDefaultChannel().writeLine(t("export.empty"));
629
+ return;
630
+ }
631
+ const text = redactExport(formatExport({ meta, messages, log }, format, { compact: opts.compact }), opts.redact);
632
+ if (opts.out === "-") {
633
+ getDefaultChannel().writeLine(text);
634
+ return;
635
+ }
636
+ const baseDir = opts.out ? dirname(opts.out) : globalExportsDir();
637
+ const path = opts.out ??
638
+ join(baseDir, `${sanitizeFileName(meta.name)}-${meta.id.slice(0, 8)}.${extensionFor(format)}`);
639
+ try {
640
+ mkdirSync(baseDir, { recursive: true });
641
+ writeFileSync(path, text, "utf-8");
642
+ }
643
+ catch (e) {
644
+ getDefaultChannel().writeLine(t("export.write_failed", { error: String(e) }));
645
+ return;
646
+ }
647
+ getDefaultChannel().writeLine(t("export.written", { path }));
648
+ getDefaultChannel().writeLine(t(opts.redact ? "export.redacted" : "export.raw"));
649
+ });
580
650
  session
581
651
  .command("delete")
582
- .argument("<id>", "Session id")
652
+ .argument("<id>", t("cli.session_id"))
583
653
  .description(t("cli.delete_session"))
584
654
  .action(async (id) => {
585
655
  const { sessionManager } = await bootstrap();
586
656
  sessionManager.delete(id);
587
657
  getDefaultChannel().writeLine(t("session.deleted", { id }));
588
658
  });
659
+ session
660
+ .command("prune")
661
+ .description(t("cli.prune_sessions"))
662
+ .option("--dry-run", t("cli.prune_dry_run"))
663
+ .action(async (opts) => {
664
+ const { sessionManager } = await bootstrap();
665
+ const active = sessionManager.getActive();
666
+ const candidates = sessionManager
667
+ .list()
668
+ .filter((s) => s.id !== active && sessionManager.isEmptySession(s.id));
669
+ if (candidates.length === 0) {
670
+ getDefaultChannel().writeLine(t("session.prune_empty"));
671
+ return;
672
+ }
673
+ if (opts.dryRun) {
674
+ getDefaultChannel().writeLine(t("session.prune_dry", { n: candidates.length }));
675
+ }
676
+ else {
677
+ const deleted = sessionManager.pruneEmpty(active ?? undefined);
678
+ getDefaultChannel().writeLine(t("session.pruned", { n: deleted.length }));
679
+ }
680
+ for (const s of candidates) {
681
+ getDefaultChannel().writeLine(` ${s.id.slice(0, 12)} ${s.name}`);
682
+ }
683
+ });
589
684
  }
590
685
  function buildChangelogCommand(program) {
591
686
  program
@@ -628,8 +723,14 @@ export function createProgram() {
628
723
  .option("-d, --dir <path>", t("cli.dir"))
629
724
  .option("-e, --exit-on-complete", t("cli.exit_on_complete"))
630
725
  .option("-j, --json", t("cli.json"))
631
- .option("--reasoning <level>", t("cli.reasoning_level"), "auto");
726
+ .option("--reasoning <level>", t("cli.reasoning_level"), "auto")
727
+ .option("--verbose", t("cli.verbose"))
728
+ .option("--context-log", t("cli.context_log"));
729
+ buildSetupCommand(program);
730
+ buildMeetCommand(program);
632
731
  buildInitCommand(program);
732
+ buildAgentsCommand(program);
733
+ buildWebCommand(program);
633
734
  buildConfigCommands(program);
634
735
  buildModelCommands(program);
635
736
  buildContextCommand(program);
@@ -637,22 +738,21 @@ export function createProgram() {
637
738
  buildMapCommand(program);
638
739
  buildProviderCommands(program);
639
740
  buildSessionCommands(program);
640
- // Add security commands
741
+ // Подключаем security-команды.
641
742
  createSecurityCommand(program);
642
- // Add plugin commands
743
+ // Подключаем plugin-команды.
643
744
  createPluginCommand(program);
644
745
  buildChangelogCommand(program);
645
746
  program
646
- .argument("[prompt...]", "Prompt to execute")
647
- .description("Run a single prompt")
648
- .action((prompt) => {
649
- /* Handled by main.ts after program.parse() */
747
+ .argument("[prompt...]", t("cli.prompt_arg"))
748
+ .description(t("cli.run_prompt"))
749
+ .action((_prompt) => {
750
+ /* Обрабатывает main.ts после program.parse(). */
650
751
  });
651
- // Subcommand actions run full bootstrap() (reasoning-probe fetch, indexer,
652
- // plugins…), which leaves open handles — without an explicit exit the
653
- // process hangs after printing its result ("config set" printed, never
654
- // exited). The prompt/REPL paths exit explicitly in main.ts; every
655
- // SUBCOMMAND is one-shot, so exit as soon as its action resolves.
752
+ // Экшены субкоманд гонят полный bootstrap() (reasoning-пробник, индексер,
753
+ // плагины…), оставляющий открытые хендлы: без явного exit процесс висит после
754
+ // печати результата ("config set" напечатал и не вышел). Prompt/REPL-пути
755
+ // выходят явно в main.ts; каждая СУБКОМАНДА — one-shot: выходим, как резолвнится action.
656
756
  //
657
757
  // Хук навешиваем РЕКУРСИВНО на все подкоманды (не только верхнего уровня):
658
758
  // у вложенных (`session show`, `model certify`, `provider use` …) родитель
@@ -666,7 +766,16 @@ export function createProgram() {
666
766
  for (const sub of cmd.commands)
667
767
  attachOneShotExit(sub);
668
768
  };
669
- for (const cmd of program.commands)
769
+ // `meet`/`agents` — не one-shot: их пустые action лишь маркируют намерение, и
770
+ // main.ts проваливается в интерактивный REPL. `web` долгоживущий (сервер
771
+ // стартует из main.ts после parse). Хук выхода сработал бы во время
772
+ // program.parse() и убил процесс до ветки. `mma init`/`mma setup` — one-shot
773
+ // визарды, обязаны выйти после прогона.
774
+ const longRunningCommands = new Set(["meet", "agents", "web"]);
775
+ for (const cmd of program.commands) {
776
+ if (longRunningCommands.has(cmd.name()))
777
+ continue;
670
778
  attachOneShotExit(cmd);
779
+ }
671
780
  return program;
672
781
  }