micro-models-agent 2.11.0 → 2.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/assets/app.js +22 -2
  3. package/dist/assets/index.html +39 -9
  4. package/dist/assets/js/dom.js +15 -0
  5. package/dist/assets/js/feed.js +129 -10
  6. package/dist/assets/js/sidebar.js +512 -0
  7. package/dist/assets/js/tabs.js +30 -5
  8. package/dist/assets/setup.js +267 -8
  9. package/dist/assets/styles.css +168 -3
  10. package/dist/cli/cache-line.js +1 -0
  11. package/dist/cli/command-suggest.js +5 -4
  12. package/dist/cli/commands.js +231 -122
  13. package/dist/cli/completer.js +132 -31
  14. package/dist/cli/index.js +1 -0
  15. package/dist/cli/json-payload.js +4 -4
  16. package/dist/cli/main.js +166 -61
  17. package/dist/cli/onboarding-commands.js +126 -0
  18. package/dist/cli/plugin-commands.js +2 -1
  19. package/dist/cli/relaunch.js +16 -13
  20. package/dist/cli/repl-commands-lsp.js +75 -0
  21. package/dist/cli/repl-commands-skills.js +105 -0
  22. package/dist/cli/repl-commands.js +589 -266
  23. package/dist/cli/repl.js +436 -177
  24. package/dist/cli/run-result.js +5 -6
  25. package/dist/cli/security-commands.js +37 -28
  26. package/dist/cli/setup-order.js +4 -55
  27. package/dist/cli/setup-prompt.js +3 -2
  28. package/dist/cli/setup.js +27 -107
  29. package/dist/cli/web-command.js +98 -0
  30. package/dist/config/budget.js +5 -5
  31. package/dist/config/config.js +103 -96
  32. package/dist/config/defaults.js +38 -8
  33. package/dist/config/domains.js +24 -27
  34. package/dist/config/env.js +46 -0
  35. package/dist/config/experts.js +2 -0
  36. package/dist/config/index.js +1 -0
  37. package/dist/config/paths.js +56 -0
  38. package/dist/config/redact.js +44 -0
  39. package/dist/config/registry-extra.js +334 -0
  40. package/dist/config/registry.js +584 -0
  41. package/dist/config/security.js +35 -36
  42. package/dist/config/timeouts.js +74 -0
  43. package/dist/config/utils.js +16 -15
  44. package/dist/core/agent/artifact-progress.js +59 -0
  45. package/dist/core/agent/artifact-resolve.js +79 -0
  46. package/dist/core/agent/audit-gate.js +7 -3
  47. package/dist/core/agent/compaction.js +2 -2
  48. package/dist/core/agent/constants.js +33 -4
  49. package/dist/core/agent/context-log.js +454 -0
  50. package/dist/core/agent/context-renderer.js +5 -0
  51. package/dist/core/agent/critic-gate.js +132 -0
  52. package/dist/core/agent/hallucination-gate.js +148 -38
  53. package/dist/core/agent/loop-state.js +15 -0
  54. package/dist/core/agent/prefix-monitor.js +1 -1
  55. package/dist/core/agent/reasoning-resolver.js +10 -1
  56. package/dist/core/agent/token-tracker.js +7 -4
  57. package/dist/core/agent/tool-batch.js +93 -18
  58. package/dist/core/agent/tool-images.js +18 -0
  59. package/dist/core/agent/tool-output.js +65 -11
  60. package/dist/core/agent/tool-pairing.js +60 -0
  61. package/dist/core/agent-moe.js +25 -24
  62. package/dist/core/agent.js +429 -108
  63. package/dist/core/bootstrap/agent-phase.js +66 -0
  64. package/dist/core/bootstrap/config-phase.js +86 -0
  65. package/dist/core/bootstrap/modules-phase.js +269 -0
  66. package/dist/core/bootstrap/provider-phase.js +183 -0
  67. package/dist/core/bootstrap/session-phase.js +204 -0
  68. package/dist/core/bootstrap/state.js +94 -0
  69. package/dist/core/bootstrap/workspace-phase.js +115 -0
  70. package/dist/core/bootstrap.js +92 -660
  71. package/dist/core/crash-handler.js +17 -7
  72. package/dist/core/environment.js +37 -12
  73. package/dist/core/host-plan.js +43 -0
  74. package/dist/core/host.js +23 -0
  75. package/dist/core/index.js +1 -0
  76. package/dist/core/prompt-builder.js +17 -1
  77. package/dist/core/prompt-overflow.js +42 -43
  78. package/dist/core/session-logger.js +122 -30
  79. package/dist/core/system-prompt.js +117 -0
  80. package/dist/core/version.js +6 -4
  81. package/dist/core/web-host.js +34 -0
  82. package/dist/core/workspace.js +19 -15
  83. package/dist/i18n/en.json +89 -3
  84. package/dist/i18n/index.js +37 -3
  85. package/dist/i18n/ru.json +89 -3
  86. package/dist/index.js +7 -3
  87. package/dist/llm/image-utils.js +55 -64
  88. package/dist/llm/llm-errors.js +9 -0
  89. package/dist/llm/model-loader.js +10 -32
  90. package/dist/llm/models-dev.js +121 -0
  91. package/dist/llm/openai-compat.js +146 -73
  92. package/dist/llm/orchestrator.js +33 -11
  93. package/dist/llm/provider-budget.js +2 -2
  94. package/dist/llm/provider-context.js +233 -0
  95. package/dist/llm/provider.js +1 -1
  96. package/dist/llm/response.js +5 -0
  97. package/dist/llm/token-counter.js +27 -11
  98. package/dist/logger/app-logger.js +48 -22
  99. package/dist/logger/file-log.js +28 -19
  100. package/dist/logger/index.js +1 -0
  101. package/dist/main.js +888 -139
  102. package/dist/migration/backup.js +14 -3
  103. package/dist/migration/detect.js +12 -3
  104. package/dist/migration/index.js +1 -0
  105. package/dist/modules/artifacts/store.js +9 -8
  106. package/dist/modules/browser/actions.js +6 -0
  107. package/dist/modules/browser/bridge-client.js +14 -12
  108. package/dist/modules/browser/bridge-path.js +4 -4
  109. package/dist/modules/browser/console-buffer.js +37 -0
  110. package/dist/modules/browser/cookie-store.js +5 -0
  111. package/dist/modules/browser/driver-types.js +1 -0
  112. package/dist/modules/browser/driver.js +19 -11
  113. package/dist/modules/browser/index.js +3 -1
  114. package/dist/modules/browser/module.js +2 -1
  115. package/dist/modules/browser/session.js +10 -30
  116. package/dist/modules/browser/snapshot.js +19 -13
  117. package/dist/modules/browser/types.js +1 -0
  118. package/dist/modules/certification/cli.js +28 -20
  119. package/dist/modules/certification/fact-checker.js +9 -1
  120. package/dist/modules/certification/loader.js +9 -2
  121. package/dist/modules/certification/manifest.js +83 -21
  122. package/dist/modules/certification/runner.js +23 -13
  123. package/dist/modules/certification/scenarios.js +20 -20
  124. package/dist/modules/certification/syntax-scenarios.js +1 -2
  125. package/dist/modules/context/chunk-query.js +11 -9
  126. package/dist/modules/context/fact-extractor.js +37 -39
  127. package/dist/modules/context/index.js +1 -0
  128. package/dist/modules/context/manager.js +106 -80
  129. package/dist/modules/critic/client.js +176 -0
  130. package/dist/modules/critic/evidence.js +81 -0
  131. package/dist/modules/critic/provider.js +45 -0
  132. package/dist/modules/critic/tools.js +78 -0
  133. package/dist/modules/critic/types.js +1 -0
  134. package/dist/modules/execution/audit-runners.js +28 -34
  135. package/dist/modules/execution/auditor.js +53 -49
  136. package/dist/modules/execution/execution-plugin.js +142 -102
  137. package/dist/modules/execution/index.js +1 -1
  138. package/dist/modules/execution/input-from.js +37 -13
  139. package/dist/modules/execution/module.js +368 -191
  140. package/dist/modules/execution/moe-executor.js +53 -26
  141. package/dist/modules/execution/plan-actions.js +320 -202
  142. package/dist/modules/execution/plan-checks.js +35 -0
  143. package/dist/modules/execution/plan-coverage.js +36 -33
  144. package/dist/modules/execution/plan-steps.js +11 -3
  145. package/dist/modules/execution/plan-store.js +83 -17
  146. package/dist/modules/execution/plan-tool.js +89 -35
  147. package/dist/modules/execution/plan-validator.js +30 -10
  148. package/dist/modules/execution/planner.js +22 -13
  149. package/dist/modules/execution/stuck-detector.js +196 -93
  150. package/dist/modules/execution/tracker.js +22 -8
  151. package/dist/modules/execution/verifier.js +69 -48
  152. package/dist/modules/execution/windows-commands.js +12 -12
  153. package/dist/modules/hallucination/artifact-claim.js +93 -0
  154. package/dist/modules/hallucination/confidence.js +13 -11
  155. package/dist/modules/hallucination/consistency.js +10 -2
  156. package/dist/modules/hallucination/detector.js +10 -5
  157. package/dist/modules/hallucination/factual.js +43 -26
  158. package/dist/modules/hallucination/index.js +1 -0
  159. package/dist/modules/hallucination/js-identifiers.js +44 -45
  160. package/dist/modules/hallucination/llm-judge.js +17 -12
  161. package/dist/modules/hallucination/success-claim.js +59 -0
  162. package/dist/modules/indexer/cache.js +52 -4
  163. package/dist/modules/indexer/index.js +1 -0
  164. package/dist/modules/indexer/map-command.js +2 -4
  165. package/dist/modules/indexer/map-select.js +16 -16
  166. package/dist/modules/indexer/module.js +47 -12
  167. package/dist/modules/indexer/project-profile.js +8 -7
  168. package/dist/modules/indexer/symbols.js +15 -15
  169. package/dist/modules/indexer/walker.js +159 -29
  170. package/dist/modules/lsp/check-tool.js +7 -5
  171. package/dist/modules/lsp/client.js +39 -39
  172. package/dist/modules/lsp/command.js +17 -24
  173. package/dist/modules/lsp/config.js +12 -11
  174. package/dist/modules/lsp/index.js +1 -0
  175. package/dist/modules/lsp/module.js +48 -46
  176. package/dist/modules/lsp/probe.js +13 -14
  177. package/dist/modules/lsp/project-root.js +14 -17
  178. package/dist/modules/lsp/startup-check.js +18 -16
  179. package/dist/modules/mcp/client.js +59 -62
  180. package/dist/modules/mcp/index.js +1 -0
  181. package/dist/modules/mcp/module.js +66 -37
  182. package/dist/modules/mcp/registry.js +5 -0
  183. package/dist/modules/memory/index.js +1 -0
  184. package/dist/modules/memory/module.js +12 -8
  185. package/dist/modules/memory/search.js +4 -1
  186. package/dist/modules/memory/store.js +40 -2
  187. package/dist/modules/onboarding/init.js +47 -0
  188. package/dist/modules/onboarding/meet.js +30 -0
  189. package/dist/modules/onboarding/mode.js +30 -0
  190. package/dist/modules/onboarding/prompts.js +43 -0
  191. package/dist/modules/pipelines/engine.js +10 -0
  192. package/dist/modules/pipelines/index.js +1 -0
  193. package/dist/modules/pipelines/parser.js +4 -1
  194. package/dist/modules/pipelines/template.js +4 -0
  195. package/dist/modules/plugins/builtin/lint-on-write.js +80 -67
  196. package/dist/modules/plugins/builtin/notify.js +2 -0
  197. package/dist/modules/plugins/index.js +1 -0
  198. package/dist/modules/plugins/loader.js +18 -3
  199. package/dist/modules/plugins/manager.js +37 -17
  200. package/dist/modules/pricing/index.js +10 -11
  201. package/dist/modules/pricing/prices.js +12 -12
  202. package/dist/modules/processes/index.js +1 -0
  203. package/dist/modules/processes/kill-tree.js +27 -31
  204. package/dist/modules/processes/registry.js +44 -25
  205. package/dist/modules/processes/runner.js +4 -4
  206. package/dist/modules/providers/capabilities.js +28 -0
  207. package/dist/modules/providers/create.js +3 -4
  208. package/dist/modules/providers/factory.js +7 -7
  209. package/dist/modules/providers/fallback.js +12 -12
  210. package/dist/modules/providers/health.js +4 -4
  211. package/dist/modules/providers/manager.js +50 -19
  212. package/dist/modules/providers/naming.js +15 -0
  213. package/dist/modules/providers/preflight.js +71 -0
  214. package/dist/modules/providers/presets.js +39 -8
  215. package/dist/modules/providers/registry.js +7 -2
  216. package/dist/modules/reasoning/policy.js +8 -6
  217. package/dist/modules/reasoning/probe.js +30 -25
  218. package/dist/modules/security/audit-log.js +19 -36
  219. package/dist/modules/security/audit-notifier.js +35 -75
  220. package/dist/modules/security/command-validator.js +99 -51
  221. package/dist/modules/security/content-scanner.js +8 -8
  222. package/dist/modules/security/data-sanitizer.js +9 -16
  223. package/dist/modules/security/encryption.js +32 -52
  224. package/dist/modules/security/index.js +2 -1
  225. package/dist/modules/security/network-validator.js +120 -43
  226. package/dist/modules/security/path-validator.js +61 -46
  227. package/dist/modules/security/protected-paths.js +73 -0
  228. package/dist/modules/security/rate-limiter.js +17 -49
  229. package/dist/modules/security/security-policies.js +25 -57
  230. package/dist/modules/security/session-encryption.js +32 -71
  231. package/dist/modules/security/session-isolation.js +15 -28
  232. package/dist/modules/session/auto-name.js +63 -0
  233. package/dist/modules/session/export.js +98 -0
  234. package/dist/modules/session/index.js +1 -0
  235. package/dist/modules/session/manager.js +79 -28
  236. package/dist/modules/session/module.js +4 -3
  237. package/dist/modules/session/store.js +57 -20
  238. package/dist/modules/setup/answers.js +35 -0
  239. package/dist/modules/setup/apply.js +79 -0
  240. package/dist/modules/setup/discovery.js +72 -0
  241. package/dist/modules/skills/index.js +1 -0
  242. package/dist/modules/skills/loader.js +9 -1
  243. package/dist/modules/skills/module.js +11 -0
  244. package/dist/modules/updater/changelog-reader.js +15 -16
  245. package/dist/modules/updater/checker.js +9 -4
  246. package/dist/modules/updater/dev-detect.js +7 -6
  247. package/dist/modules/updater/index.js +1 -0
  248. package/dist/modules/updater/module.js +17 -15
  249. package/dist/modules/user-profile/compressor.js +2 -0
  250. package/dist/modules/user-profile/index.js +1 -0
  251. package/dist/modules/user-profile/profile.js +10 -1
  252. package/dist/modules/webui/answer-api.js +29 -0
  253. package/dist/modules/webui/assets.js +50 -0
  254. package/dist/modules/webui/body.js +21 -0
  255. package/dist/modules/webui/commands-settings.js +209 -0
  256. package/dist/modules/webui/commands-shared.js +60 -0
  257. package/dist/modules/webui/commands.js +174 -0
  258. package/dist/modules/webui/config-api.js +134 -0
  259. package/dist/modules/webui/file-api.js +202 -0
  260. package/dist/modules/webui/forward.js +159 -0
  261. package/dist/modules/webui/history-api.js +112 -0
  262. package/dist/modules/webui/host-state.js +60 -0
  263. package/dist/modules/webui/i18n-api.js +9 -0
  264. package/dist/modules/webui/limits.js +6 -0
  265. package/dist/modules/webui/log-forward.js +20 -0
  266. package/dist/modules/webui/memory-commands.js +64 -0
  267. package/dist/modules/webui/model-cache.js +18 -0
  268. package/dist/modules/webui/module.js +148 -0
  269. package/dist/modules/webui/persist.js +24 -0
  270. package/dist/modules/webui/prompt-io.js +97 -0
  271. package/dist/modules/webui/providers-api.js +337 -0
  272. package/dist/modules/webui/providers-view.js +56 -0
  273. package/dist/modules/webui/reasoning-view.js +15 -0
  274. package/dist/modules/webui/run-agent.js +81 -0
  275. package/dist/modules/webui/server.js +284 -0
  276. package/dist/modules/webui/sessions-api.js +178 -0
  277. package/dist/modules/webui/settings-api.js +561 -0
  278. package/dist/modules/webui/setup-api.js +201 -0
  279. package/dist/modules/webui/state.js +74 -0
  280. package/dist/modules/webui/util.js +261 -0
  281. package/dist/output/bus.js +7 -2
  282. package/dist/output/channel.js +80 -28
  283. package/dist/output/format.js +2 -1
  284. package/dist/output/index.js +1 -0
  285. package/dist/output/json-sink.js +5 -3
  286. package/dist/output/machine.js +4 -3
  287. package/dist/output/session-sink.js +4 -4
  288. package/dist/tools/approve.js +4 -0
  289. package/dist/tools/attach-image.js +5 -4
  290. package/dist/tools/auto-fixer.js +26 -44
  291. package/dist/tools/auto-tags.js +83 -0
  292. package/dist/tools/bash.js +193 -116
  293. package/dist/tools/browser.js +76 -31
  294. package/dist/tools/chunk-query.js +14 -6
  295. package/dist/tools/create-dir.js +9 -5
  296. package/dist/tools/delete-file.js +9 -5
  297. package/dist/tools/download-file.js +32 -7
  298. package/dist/tools/edit-file.js +52 -14
  299. package/dist/tools/enable-tools.js +6 -6
  300. package/dist/tools/executor.js +132 -27
  301. package/dist/tools/file-info.js +3 -1
  302. package/dist/tools/filter-tools.js +3 -3
  303. package/dist/tools/glob-tool.js +4 -1
  304. package/dist/tools/grep-tool.js +13 -10
  305. package/dist/tools/hidden-tools-block.js +6 -6
  306. package/dist/tools/index.js +16 -8
  307. package/dist/tools/list-dir.js +4 -2
  308. package/dist/tools/load-skill.js +7 -0
  309. package/dist/tools/mcp-call.js +15 -4
  310. package/dist/tools/meet-done.js +14 -0
  311. package/dist/tools/move-file.js +14 -7
  312. package/dist/tools/path-utils.js +29 -29
  313. package/dist/tools/pipeline-run.js +29 -7
  314. package/dist/tools/preview.js +1 -1
  315. package/dist/tools/process-ids.js +31 -0
  316. package/dist/tools/process-kill.js +9 -16
  317. package/dist/tools/process-list.js +1 -0
  318. package/dist/tools/process-log.js +11 -16
  319. package/dist/tools/process-wait.js +63 -0
  320. package/dist/tools/prompt-io.js +4 -3
  321. package/dist/tools/question.js +172 -25
  322. package/dist/tools/read-file.js +55 -34
  323. package/dist/tools/recall.js +14 -8
  324. package/dist/tools/registry.js +6 -5
  325. package/dist/tools/remember.js +8 -4
  326. package/dist/tools/scope-request.js +11 -6
  327. package/dist/tools/search-history.js +5 -2
  328. package/dist/tools/session-info.js +2 -0
  329. package/dist/tools/set-thinking.js +8 -4
  330. package/dist/tools/subagent.js +59 -39
  331. package/dist/tools/syntax-validator.js +292 -90
  332. package/dist/tools/user-input.js +22 -18
  333. package/dist/tools/web-browse.js +9 -3
  334. package/dist/tools/web-fetch.js +12 -23
  335. package/dist/tools/web-search.js +7 -5
  336. package/dist/tools/write-file.js +45 -15
  337. package/dist/ui/action-log.js +13 -0
  338. package/dist/ui/box.js +4 -3
  339. package/dist/ui/colors.js +2 -0
  340. package/dist/ui/diff.js +6 -5
  341. package/dist/ui/index.js +1 -0
  342. package/dist/ui/line-editor.js +230 -122
  343. package/dist/ui/line-math.js +10 -2
  344. package/dist/ui/md-formatter.js +57 -37
  345. package/dist/ui/output.js +8 -3
  346. package/dist/ui/plan-view.js +21 -10
  347. package/dist/ui/renderer.js +393 -67
  348. package/dist/ui/spinner.js +16 -5
  349. package/dist/ui/table.js +15 -17
  350. package/dist/ui/theme.js +143 -0
  351. package/dist/utils/child-run.js +20 -0
  352. package/dist/utils/error.js +1 -1
  353. package/dist/utils/index.js +2 -0
  354. package/dist/utils/retry.js +2 -2
  355. package/dist/utils/truncate.js +1 -1
  356. package/package.json +1 -1
@@ -0,0 +1,79 @@
1
+ /** Команды в довесок к bash-blacklist, если визард включил блок. */
2
+ export const SECURITY_BASH_BLOCKLIST = [
3
+ "rm",
4
+ "dd",
5
+ "chmod",
6
+ "wget",
7
+ "curl",
8
+ "scp",
9
+ "ssh",
10
+ "nc",
11
+ "netcat",
12
+ "sudo",
13
+ "su",
14
+ "kill",
15
+ "pkill",
16
+ "killall",
17
+ "shutdown",
18
+ "reboot",
19
+ ];
20
+ /**
21
+ * Применить ответы first-run визарда на загруженный конфиг.
22
+ * Провайдер заменяется **новым объектом**, а не мутируется на месте: `loadConfig`
23
+ * может повесить сессионный `MMA_PROVIDER_*` env-оверрайд, чей `envValue`
24
+ * указывает на загруженный объект `config.provider`. `stripEnvOverrides` в
25
+ * `saveConfig` матчит этот объект по identity и откатил бы весь провайдер к
26
+ * env/дефолту, молча потеряв провайдер/URL/ключ визарда. Замена объекта
27
+ * сохраняет протухшую identity оверрайда — вычищается только env-ключ, а ответы
28
+ * персистятся. Активная запись `provider.entries[]` тоже переписывается
29
+ * (type/baseUrl/apiKey и окно контекста), соседи и их тюнинг целы.
30
+ */
31
+ export function applyAnswersToConfig(config, a) {
32
+ config.provider = {
33
+ ...config.provider,
34
+ type: a.provider,
35
+ baseUrl: a.apiBase,
36
+ apiKey: a.apiKey,
37
+ };
38
+ config.model = a.model;
39
+ config.contextWindow = a.contextWindow;
40
+ config.maxToolIterations = a.maxToolIterations;
41
+ config.locale = a.locale;
42
+ // Мультиконфиги резолвят активный провайдер из `entries[]`, так что ответы
43
+ // пишутся на активную запись — без потери соседей и тюнинга записи
44
+ // (cache, retry, rateLimits). Осознанный кастомный label сохраняется,
45
+ // generic/дефолтный заменяется.
46
+ if ((config.provider.entries?.length ?? 0) > 0) {
47
+ const entries = config.provider.entries ?? [];
48
+ const activeName = config.provider.active || entries[0]?.label || entries[0]?.type;
49
+ const idx = entries.findIndex((e) => e.label === activeName || e.type === activeName);
50
+ const target = idx >= 0 ? idx : 0;
51
+ const current = entries[target];
52
+ const keepLabel = Boolean(current.label && current.label !== current.type);
53
+ const updated = {
54
+ ...current,
55
+ type: a.provider,
56
+ baseUrl: a.apiBase,
57
+ apiKey: a.apiKey,
58
+ contextWindow: a.contextWindow,
59
+ ...(keepLabel ? {} : { label: a.provider }),
60
+ };
61
+ const next = entries.slice();
62
+ next[target] = updated;
63
+ config.provider.entries = next;
64
+ config.provider.active = updated.label || updated.type;
65
+ }
66
+ if (config.security) {
67
+ config.security.enabled = true;
68
+ config.security.bash.enabled = true;
69
+ config.security.bash.blockDangerousFlags =
70
+ a.securityFlagsBlock || config.security.bash.blockDangerousFlags;
71
+ if (a.securityBashBlock) {
72
+ config.security.bash.blacklist = [
73
+ ...new Set([...config.security.bash.blacklist, ...SECURITY_BASH_BLOCKLIST]),
74
+ ];
75
+ }
76
+ config.security.paths.enabled = a.securityPathsRestrict;
77
+ }
78
+ return config;
79
+ }
@@ -0,0 +1,72 @@
1
+ // Discovery провайдеров для first-run визарда: скан локальных портов, модели, chat-проба.
2
+ /**
3
+ * Хелперы discovery провайдеров для first-run визарда.
4
+ * Вынесены как есть (минус терминальный UI) из `src/cli/setup.ts`, чтобы
5
+ * браузерный визард переиспользовал ту же логику проб. Чисто сетевые хелперы:
6
+ * ни терминала, ни output-канала.
7
+ */
8
+ import { probeChat } from "../providers/preflight";
9
+ import { SETUP_SCAN_TIMEOUT_MS as SCAN_TIMEOUT_MS, SETUP_MODELS_TIMEOUT_MS as MODELS_TIMEOUT_MS, SETUP_CHAT_TIMEOUT_MS as CHAT_TIMEOUT_MS, } from "../../config/timeouts";
10
+ /** Локальные серверы для скана. */
11
+ const KNOWN_PORTS = [
12
+ { port: 1234, label: "LM Studio" },
13
+ { port: 11434, label: "Ollama" },
14
+ { port: 8080, label: "vLLM / custom" },
15
+ { port: 4891, label: "GPT4All" },
16
+ ];
17
+ /** Проба известных локальных портов на OpenAI-совместимый `/v1/models`. */
18
+ export async function scanLocalServers() {
19
+ const found = [];
20
+ for (const { port, label } of KNOWN_PORTS) {
21
+ try {
22
+ const controller = new AbortController();
23
+ const timeout = setTimeout(() => controller.abort(), SCAN_TIMEOUT_MS);
24
+ const resp = await fetch(`http://localhost:${port}/v1/models`, {
25
+ signal: controller.signal,
26
+ });
27
+ clearTimeout(timeout);
28
+ if (resp.ok) {
29
+ found.push({ label, url: `http://localhost:${port}/v1` });
30
+ }
31
+ }
32
+ catch {
33
+ /* порт недоступен */
34
+ }
35
+ }
36
+ return found;
37
+ }
38
+ /** Id моделей из OpenAI-совместимого `/models`; любая неудача — []. */
39
+ export async function fetchProviderModels(apiBase, apiKey) {
40
+ try {
41
+ const url = `${apiBase.replace(/\/+$/, "")}/models`;
42
+ const controller = new AbortController();
43
+ const timeout = setTimeout(() => controller.abort(), MODELS_TIMEOUT_MS);
44
+ const resp = await fetch(url, {
45
+ headers: {
46
+ Authorization: `Bearer ${apiKey}`,
47
+ "Content-Type": "application/json",
48
+ },
49
+ signal: controller.signal,
50
+ });
51
+ clearTimeout(timeout);
52
+ if (!resp.ok)
53
+ return [];
54
+ const data = (await resp.json());
55
+ const list = Array.isArray(data.data) ? data.data : [];
56
+ return list
57
+ .map((m) => m.id || m.name || m.model || "")
58
+ .filter((id) => Boolean(id));
59
+ }
60
+ catch {
61
+ return [];
62
+ }
63
+ }
64
+ /** Дешёвая chat-проба: `true`, если модель отвечает. Не бросает. */
65
+ export async function testProviderChat(apiBase, apiKey, model) {
66
+ try {
67
+ return (await probeChat({ baseUrl: apiBase, apiKey, model }, CHAT_TIMEOUT_MS)) !== "";
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ }
@@ -1,2 +1,3 @@
1
+ // Публичная поверхность скиллов: загрузчик, модуль и типы метаданных.
1
2
  export { SkillsLoader } from "./loader";
2
3
  export { SkillsModule } from "./module";
@@ -1,6 +1,9 @@
1
+ // Загрузчик скиллов: рекурсивный скан .md-файлов с frontmatter-метаданными.
1
2
  import { readdirSync, readFileSync, existsSync, statSync } from "fs";
2
3
  import { join } from "path";
4
+ /** Загрузчик скиллов из каталогов (встроенные, глобальные, проектные). */
3
5
  export class SkillsLoader {
6
+ /** Рекурсивно грузит все скиллы из каталога; нет каталога — пусто. */
4
7
  loadFromDir(dirPath) {
5
8
  if (!existsSync(dirPath))
6
9
  return [];
@@ -32,7 +35,11 @@ export class SkillsLoader {
32
35
  }
33
36
  }
34
37
  parseSkillFile(content, sourcePath) {
35
- const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
38
+ // Сначала нормализуем CRLF: у Windows-чекаута/авторского скилла разделитель
39
+ // `---\r\n`, который LF-паттерн молча не матчил (все bundled-скиллы
40
+ // отбрасывались без предупреждения).
41
+ const normalized = content.replace(/\r\n/g, "\n");
42
+ const match = normalized.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
36
43
  if (!match)
37
44
  return null;
38
45
  const frontmatter = this.parseFrontmatter(match[1]);
@@ -68,6 +75,7 @@ export class SkillsLoader {
68
75
  }
69
76
  return result;
70
77
  }
78
+ /** Грузит скиллы из трёх источников по приоритету: встроенные, глобальные, проектные. */
71
79
  loadFromAllSources(builtinDir, globalDir, projectDir) {
72
80
  return [
73
81
  ...this.loadFromDir(builtinDir),
@@ -1,5 +1,6 @@
1
1
  import { t } from "../../i18n/index";
2
2
  import { estimateTokens } from "../../llm/token-counter";
3
+ /** Модуль скиллов: каталог доступных, загрузка в бюджет, промпт-блок. */
3
4
  export class SkillsModule {
4
5
  name = "skills";
5
6
  availableSkills;
@@ -10,6 +11,7 @@ export class SkillsModule {
10
11
  this.availableSkills = availableSkills;
11
12
  this.budget = budget;
12
13
  }
14
+ /** Загружает скилл по имени с проверкой бюджета токенов. */
13
15
  loadByName(name) {
14
16
  if (this.loadedSkills.has(name)) {
15
17
  return { success: false, message: t("skill.already_loaded", { name }) };
@@ -20,6 +22,7 @@ export class SkillsModule {
20
22
  }
21
23
  return this.tryLoad(skill);
22
24
  }
25
+ /** Выгружает скилл и возвращает его токены в бюджет. */
23
26
  unload(name) {
24
27
  const skill = this.loadedSkills.get(name);
25
28
  if (!skill)
@@ -28,19 +31,24 @@ export class SkillsModule {
28
31
  this.currentTokens -= this.estimateTokens(skill.content);
29
32
  return true;
30
33
  }
34
+ /** Загруженные скиллы. */
31
35
  getLoaded() {
32
36
  return Array.from(this.loadedSkills.values());
33
37
  }
38
+ /** Все доступные (загруженные и нет) скиллы. */
34
39
  getAvailable() {
35
40
  return this.availableSkills;
36
41
  }
42
+ /** Ищет скилл по точному имени среди доступных. */
37
43
  findByName(name) {
38
44
  return this.availableSkills.find((s) => s.name === name);
39
45
  }
46
+ /** Подстрочный поиск по именам и описаниям (без учёта регистра). */
40
47
  search(query) {
41
48
  const q = query.toLowerCase();
42
49
  return this.availableSkills.filter((s) => s.name.toLowerCase().includes(q) || s.description.toLowerCase().includes(q));
43
50
  }
51
+ /** Бюджет токенов: занято, всего, остаток. */
44
52
  getBudget() {
45
53
  return {
46
54
  used: this.currentTokens,
@@ -48,10 +56,12 @@ export class SkillsModule {
48
56
  remaining: this.budget - this.currentTokens,
49
57
  };
50
58
  }
59
+ /** Тело загруженного скилла; null, если не загружен. */
51
60
  getSkillContent(name) {
52
61
  const skill = this.loadedSkills.get(name);
53
62
  return skill ? skill.content : null;
54
63
  }
64
+ /** Системный блок: каталог доступных + тела загруженных скиллов. */
55
65
  getSystemPromptBlock() {
56
66
  const lines = [];
57
67
  if (this.availableSkills.length > 0) {
@@ -82,6 +92,7 @@ export class SkillsModule {
82
92
  estimatedTokens: tokens,
83
93
  };
84
94
  }
95
+ /** Плагин-заглушка: модуль работает через системный блок, хуки не нужны. */
85
96
  getPlugin() {
86
97
  return {
87
98
  name: "skills",
@@ -1,19 +1,20 @@
1
+ // Чтение CHANGELOG.md из установленного пакета и вырезка секций версий.
1
2
  import { readFileSync, existsSync } from "fs";
2
3
  import { dirname, join } from "path";
3
4
  /**
4
- * Read the bundled CHANGELOG.md from the installed npm package.
5
- * Resolves relative to this file's location (dist/modules/updater/) going up
6
- * to the package root.
5
+ * Читает bundled CHANGELOG.md из установленного npm-пакета.
6
+ * Резолвится от местоположения этого файла (dist/modules/updater/) вверх
7
+ * до корня пакета.
7
8
  */
8
9
  export function readChangelog(packageName) {
9
10
  try {
10
- // Walk up from this file to find package.json
11
+ // Идём вверх от этого файла в поисках package.json
11
12
  let dir = dirname(import.meta.url);
12
- // Convert file:// URL to path on POSIX, or just use the path directly
13
+ // file:// URL в путь на POSIX, иначе используем путь как есть
13
14
  if (dir.startsWith("file://")) {
14
15
  dir = decodeURIComponent(dir.slice(7));
15
16
  }
16
- // Find package root (contains package.json with matching name)
17
+ // Ищем корень пакета (package.json с совпадающим именем)
17
18
  for (let i = 0; i < 10; i++) {
18
19
  const pkgPath = join(dir, "package.json");
19
20
  if (existsSync(pkgPath)) {
@@ -35,13 +36,13 @@ export function readChangelog(packageName) {
35
36
  }
36
37
  }
37
38
  /**
38
- * Extract changelog entries between two versions (exclusive old, inclusive new).
39
- * Returns the raw markdown sections.
39
+ * Вырезает записи между версиями (старая эксклюзивно, новая инклюзивно).
40
+ * Возвращает сырые markdown-секции.
40
41
  *
41
42
  * parseChangelog(changelog, "0.55.1", "0.56.1") =>
42
43
  * "## [0.56.1] - ...\n...\n## [0.56.0] - ...\n..."
43
44
  */
44
- export function extractChangelogRange(changelog, fromVersion, toVersion) {
45
+ export function extractChangelogRange(changelog, fromVersion, _toVersion) {
45
46
  const lines = changelog.split("\n");
46
47
  const sections = [];
47
48
  let capturing = false;
@@ -51,12 +52,12 @@ export function extractChangelogRange(changelog, fromVersion, toVersion) {
51
52
  if (match) {
52
53
  const ver = match[1];
53
54
  if (ver === fromVersion) {
54
- // Stop before this section (exclusive).
55
+ // Стоп перед этой секцией (эксклюзивно).
55
56
  foundFrom = true;
56
57
  break;
57
58
  }
58
59
  if (capturing) {
59
- // New section header — separate with blank line.
60
+ // Новый заголовок секции — отделяем пустой строкой.
60
61
  sections.push("");
61
62
  }
62
63
  capturing = true;
@@ -65,14 +66,12 @@ export function extractChangelogRange(changelog, fromVersion, toVersion) {
65
66
  sections.push(line);
66
67
  }
67
68
  }
68
- // If the "from" version was never found, return null (no valid range).
69
+ // Версия "from" так и не нашлась — валидного диапазона нет, возвращаем null.
69
70
  if (!foundFrom)
70
71
  return null;
71
72
  return sections.length > 0 ? sections.join("\n").trim() : null;
72
73
  }
73
- /**
74
- * Get the latest changelog entry (most recent version).
75
- */
74
+ /** Берёт свежайшую запись changelog (самая верхняя версия). */
76
75
  export function extractLatestChangelog(changelog) {
77
76
  const lines = changelog.split("\n");
78
77
  const sections = [];
@@ -82,7 +81,7 @@ export function extractLatestChangelog(changelog) {
82
81
  const match = line.match(/^## \[(\d+\.\d+\.\d+)\]/);
83
82
  if (match) {
84
83
  if (found)
85
- break; // Stop at second section header.
84
+ break; // Стоп на втором заголовке секции.
86
85
  capturing = true;
87
86
  found = true;
88
87
  }
@@ -1,6 +1,7 @@
1
+ // Проверка обновлений в npm-реестре и установка свежей версии глобально.
1
2
  import { platform } from "os";
2
3
  import { resolveSpawnCommand } from "../lsp/command";
3
- /** Numeric semver comparison (x.y.z, prerelease ignored). */
4
+ /** Численное сравнение semver (x.y.z, пререлизы игнорируются). */
4
5
  export function semverGt(a, b) {
5
6
  const pa = a
6
7
  .replace(/^v/, "")
@@ -24,6 +25,7 @@ const defaultRunner = async (command, args, options) => {
24
25
  execFile(command, args, options, (err) => resolve({ error: err?.message }));
25
26
  });
26
27
  };
28
+ /** Апдейтер пакета: опрос npm-реестра и глобальная установка. */
27
29
  export class Updater {
28
30
  currentVersion;
29
31
  packageName;
@@ -33,12 +35,15 @@ export class Updater {
33
35
  this.packageName = packageName;
34
36
  this.runner = runner ?? defaultRunner;
35
37
  }
38
+ /** Текущая версия пакета. */
36
39
  getCurrentVersion() {
37
40
  return this.currentVersion;
38
41
  }
42
+ /** Имя пакета в реестре. */
39
43
  getPackageName() {
40
44
  return this.packageName;
41
45
  }
46
+ /** Спрашивает реестр о latest-теге; офлайн/ошибка — флаг false с причиной. */
42
47
  async check() {
43
48
  try {
44
49
  const response = await fetch(`https://registry.npmjs.org/${this.packageName}`, {
@@ -65,8 +70,8 @@ export class Updater {
65
70
  }
66
71
  }
67
72
  /**
68
- * Install the latest version globally via `npm install -g`.
69
- * Returns an InstallResult (never throws).
73
+ * Ставит свежую версию глобально через `npm install -g`.
74
+ * Возвращает InstallResult (не бросает).
70
75
  */
71
76
  async install(latest) {
72
77
  try {
@@ -88,7 +93,7 @@ export class Updater {
88
93
  const npmArgs = ["install", "-g", `${this.packageName}@${latest}`];
89
94
  const command = resolveSpawnCommand("npm");
90
95
  if (platform() === "win32" && /\.(cmd|bat)$/i.test(command)) {
91
- // Node cannot spawn .cmd/.bat shims directly (spawn EINVAL) — route via cmd.exe.
96
+ // Node не спавнит .cmd/.bat-шимы напрямую (spawn EINVAL) — идём через cmd.exe.
92
97
  return { command: "cmd.exe", args: ["/c", command, ...npmArgs] };
93
98
  }
94
99
  return { command, args: npmArgs };
@@ -1,12 +1,13 @@
1
+ // Детект dev-запуска по расширению точки входа (для запрета самообновления из чекаута).
1
2
  /**
2
- * True when the running entry is a TypeScript source file — i.e. a dev run
3
+ * True, когда запущенная точка входа — TypeScript-исходник, т.е. dev-прогон
3
4
  * (`bun run src/cli/main.ts`, `bun --watch src/cli/main.ts`, tsx/ts-node).
4
- * The published package is loaded as bundled `dist/main.js` via `bin/mma.mjs`,
5
- * so this is false for real installs.
5
+ * Опубликованный пакет грузится как сбандленный `dist/main.js` через
6
+ * `bin/mma.mjs`, так что для реальных установок это false.
6
7
  *
7
- * Dev runs MUST NOT self-update: a checkout's package.json version can
8
- * legitimately trail npm, and silently `npm install -g`-ing over the user's
9
- * global install from a dev working tree is destructive and surprising.
8
+ * Dev-прогоны НЕ должны самообновляться: версия package.json в чекауте вправе
9
+ * отставать от npm, а молча `npm install -g`-шить поверх пользовательского
10
+ * глобала из dev-дерева — деструктивно и неожиданно.
10
11
  */
11
12
  export function isDevEntryPath(path) {
12
13
  const clean = path.split(/[?#]/)[0];
@@ -1,3 +1,4 @@
1
+ // Публичная поверхность самообновления: проверка, установка, модуль, dev-детект.
1
2
  export { Updater } from "./checker";
2
3
  export { UpdaterModule } from "./module";
3
4
  export { isDevEntryPath } from "./dev-detect";
@@ -4,11 +4,10 @@ import { t } from "../../i18n/index";
4
4
  import { pc } from "../../ui/colors";
5
5
  import { defaultOutputBus } from "../../output";
6
6
  /**
7
- * Self-update module. Fires an ASYNC (non-blocking) check at startup so the
8
- * agent never waits on the network. When `autoInstall` is enabled, a newer
9
- * version is installed globally via `npm install -g` in the background and
10
- * the user is notified; the running process keeps working on the old version
11
- * until the next launch.
7
+ * Модуль самообновления. При старте — АСИНХРОННАЯ (неблокирующая) проверка,
8
+ * чтобы агент никогда не ждал сеть. При включённом `autoInstall` свежая версия
9
+ * ставится глобально через `npm install -g` в фоне, пользователь уведомляется;
10
+ * запущенный процесс до следующего старта работает на старой версии.
12
11
  */
13
12
  export class UpdaterModule {
14
13
  name = "updater";
@@ -17,9 +16,9 @@ export class UpdaterModule {
17
16
  logger;
18
17
  started = false;
19
18
  timer = null;
20
- /** Promise of the current run-loop pass (resolves when it settles). */
19
+ /** Промис текущего витка run-loop (резолвится по устаканиванию). */
21
20
  idlePromise = null;
22
- /** Test hook: disable real npm installs. */
21
+ /** Тест-хук: отключает реальные npm-установки. */
23
22
  installEnabled = true;
24
23
  constructor(config, currentVersion, packageName, logger, installRunner) {
25
24
  this.config = config;
@@ -30,20 +29,22 @@ export class UpdaterModule {
30
29
  error: (m) => defaultOutputBus.log("error", "updater", m),
31
30
  };
32
31
  }
33
- /** Test hook: prevent the module from actually running npm install. */
32
+ /** Тест-хук: запрещает модулю реально гонять npm install. */
34
33
  setInstallEnabled(enabled) {
35
34
  this.installEnabled = enabled;
36
35
  }
36
+ /** Доступ к underlying-апдейтеру (версия, пакет). */
37
37
  getUpdater() {
38
38
  return this.updater;
39
39
  }
40
+ /** True, если фоновая проверка запущена. */
40
41
  isStarted() {
41
42
  return this.started;
42
43
  }
43
44
  /**
44
- * Start the background check. Returns immediately (fire-and-forget) so the
45
- * caller never blocks on the registry. Use `intervalMs > 0` for a permanent
46
- * re-check loop (the "auto-update daemon" behavior).
45
+ * Стартует фоновую проверку. Возвращается сразу (fire-and-forget), чтобы
46
+ * вызывающий не ждал реестр. `intervalMs > 0` — вечный цикл перепроверок
47
+ * (поведение "auto-update daemon").
47
48
  */
48
49
  start() {
49
50
  if (this.started || !this.config.enabled)
@@ -51,6 +52,7 @@ export class UpdaterModule {
51
52
  this.started = true;
52
53
  this.idlePromise = this.runLoop();
53
54
  }
55
+ /** Останавливает фоновый цикл и снимает таймер. */
54
56
  stop() {
55
57
  this.started = false;
56
58
  if (this.timer) {
@@ -59,9 +61,9 @@ export class UpdaterModule {
59
61
  }
60
62
  }
61
63
  /**
62
- * Wait for the current check/install cycle to settle, bounded by timeoutMs.
63
- * Used by one-shot CLI runs so a background `npm install -g` isn't killed by
64
- * process.exit() before it completes. No-op when the module never started.
64
+ * Ждёт устаканивания текущего цикла check/install, но не дольше timeoutMs.
65
+ * Нужно one-shot CLI-прогонам, чтобы фоновый `npm install -g` не убивался
66
+ * process.exit() до завершения. No-op, если модуль не стартовал.
65
67
  */
66
68
  async waitForIdle(timeoutMs = 130000) {
67
69
  const idle = this.idlePromise;
@@ -82,7 +84,7 @@ export class UpdaterModule {
82
84
  }
83
85
  }
84
86
  }
85
- /** Perform a single check; if an update is available, optionally install it. */
87
+ /** Одна проверка; при доступном апдейте — опциональная установка. */
86
88
  async runOnce() {
87
89
  const result = await this.updater.check();
88
90
  if (result.error) {
@@ -1,4 +1,6 @@
1
+ /** Сворачивает профиль в компактную строку `OS/Shell/Platform/Prefs`. */
1
2
  export class ProfileCompressor {
3
+ /** Сжимает инфо профиля в одну строку; пустые преференсы опускаются. */
2
4
  compress(info) {
3
5
  const parts = [
4
6
  `OS: ${info.os}`,
@@ -1 +1,2 @@
1
+ // Публичная поверхность профиля пользователя: класс и тип инфо.
1
2
  export { UserProfile } from "./profile";
@@ -1,8 +1,10 @@
1
+ // Профиль пользователя: сбор фактов окружения, персист в profile.json, преференсы.
1
2
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
2
3
  import { join } from "path";
3
- import { homedir, hostname, platform, type } from "os";
4
+ import { homedir, hostname, platform, type, } from "os";
4
5
  import { env } from "process";
5
6
  import { ProfileCompressor } from "./compressor";
7
+ /** Профиль пользователя с персистом в `<dir>/profile.json`. */
6
8
  export class UserProfile {
7
9
  profileDir;
8
10
  info = null;
@@ -10,6 +12,7 @@ export class UserProfile {
10
12
  constructor(profileDir) {
11
13
  this.profileDir = profileDir;
12
14
  }
15
+ /** Собирает факты окружения (ОС, шелл, дом, node) в свежий снимок. */
13
16
  collect() {
14
17
  this.info = {
15
18
  platform: platform(),
@@ -22,12 +25,14 @@ export class UserProfile {
22
25
  };
23
26
  return this.info;
24
27
  }
28
+ /** Сохраняет текущий снимок и преференсы в profile.json. */
25
29
  save() {
26
30
  if (!existsSync(this.profileDir)) {
27
31
  mkdirSync(this.profileDir, { recursive: true });
28
32
  }
29
33
  writeFileSync(join(this.profileDir, "profile.json"), JSON.stringify({ ...this.info, preferences: this.preferences }, null, 2), "utf-8");
30
34
  }
35
+ /** Загружает снимок из profile.json; null, если файла нет или он бит. */
31
36
  load() {
32
37
  const path = join(this.profileDir, "profile.json");
33
38
  if (!existsSync(path))
@@ -50,15 +55,19 @@ export class UserProfile {
50
55
  return null;
51
56
  }
52
57
  }
58
+ /** Последний собранный/загруженный снимок (null до collect/load). */
53
59
  getInfo() {
54
60
  return this.info;
55
61
  }
62
+ /** Записывает преференс (в файл попадёт при save). */
56
63
  setPreference(key, value) {
57
64
  this.preferences[key] = value;
58
65
  }
66
+ /** Читает преференс; undefined, если не задан. */
59
67
  getPreference(key) {
60
68
  return this.preferences[key];
61
69
  }
70
+ /** Компактная строка профиля для промпта (собирает снимок при нужде). */
62
71
  compress() {
63
72
  if (!this.info)
64
73
  this.collect();
@@ -0,0 +1,29 @@
1
+ import { readBodyError, sendJson } from "./util";
2
+ import { readJsonBody } from "./body";
3
+ import { resolveAnswer } from "./prompt-io";
4
+ /**
5
+ * Тело: `{ id: string, value: unknown }`. `value` — строка для free-text
6
+ * вопросов и `number[]` индексов опций для вопросов с выбором.
7
+ */
8
+ export function handleAnswerPost(req, res, s) {
9
+ readJsonBody(req, s.maxBodyBytes)
10
+ .then((rec) => {
11
+ if (!rec) {
12
+ sendJson(res, 400, { error: "invalid body" });
13
+ return;
14
+ }
15
+ const id = typeof rec.id === "string" ? rec.id : "";
16
+ if (!id) {
17
+ sendJson(res, 400, { error: "invalid body" });
18
+ return;
19
+ }
20
+ if (!resolveAnswer(s, id, rec.value)) {
21
+ sendJson(res, 404, { error: "unknown id" });
22
+ return;
23
+ }
24
+ sendJson(res, 200, { ok: true });
25
+ })
26
+ .catch((err) => {
27
+ readBodyError(req, res, err);
28
+ });
29
+ }