micro-models-agent 0.41.2 → 0.43.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 (171) hide show
  1. package/bin/mma.mjs +41 -41
  2. package/dist/cli/commands.js +19 -9
  3. package/dist/cli/completer.js +37 -36
  4. package/dist/cli/index.js +2 -2
  5. package/dist/cli/main.js +23 -48
  6. package/dist/cli/repl-commands.js +12 -40
  7. package/dist/cli/repl.js +87 -217
  8. package/dist/cli/security-commands.js +7 -5
  9. package/dist/cli/setup.js +26 -8
  10. package/dist/config/config.js +5 -52
  11. package/dist/config/defaults.js +5 -29
  12. package/dist/config/experts.js +1 -1
  13. package/dist/config/index.js +3 -3
  14. package/dist/config/security.js +10 -3
  15. package/dist/core/agent-moe.js +10 -2
  16. package/dist/core/agent.js +82 -273
  17. package/dist/core/bootstrap.js +13 -80
  18. package/dist/core/index.js +2 -2
  19. package/dist/core/prompt-builder.js +2 -23
  20. package/dist/core/session-logger.js +4 -46
  21. package/dist/i18n/en.json +2 -75
  22. package/dist/i18n/ru.json +1 -74
  23. package/dist/index.js +1 -1
  24. package/dist/llm/image-utils.js +5 -4
  25. package/dist/llm/index.js +4 -4
  26. package/dist/llm/model-loader.js +6 -6
  27. package/dist/llm/openai-compat.js +34 -40
  28. package/dist/llm/orchestrator.js +29 -33
  29. package/dist/llm/response.js +9 -9
  30. package/dist/logger/app-logger.js +1 -1
  31. package/dist/logger/index.js +1 -1
  32. package/dist/main.js +648 -183
  33. package/dist/migration/backup.js +13 -13
  34. package/dist/migration/detect.js +11 -11
  35. package/dist/migration/index.js +2 -2
  36. package/dist/modules/browser/actions.js +4 -34
  37. package/dist/modules/browser/bridge-server.mjs +202 -202
  38. package/dist/modules/browser/cookie-store.js +6 -6
  39. package/dist/modules/browser/index.js +5 -7
  40. package/dist/modules/browser/module.js +7 -8
  41. package/dist/modules/browser/session.js +84 -87
  42. package/dist/modules/browser/snapshot.js +58 -92
  43. package/dist/modules/browser/types.js +1 -4
  44. package/dist/modules/certification/cli.js +4 -2
  45. package/dist/modules/certification/fact-checker.js +3 -1
  46. package/dist/modules/certification/loader.js +9 -3
  47. package/dist/modules/certification/runner.js +4 -1
  48. package/dist/modules/context/index.js +1 -1
  49. package/dist/modules/context/manager.js +86 -160
  50. package/dist/modules/execution/auditor.js +25 -177
  51. package/dist/modules/execution/module.js +544 -201
  52. package/dist/modules/execution/moe-executor.js +0 -25
  53. package/dist/modules/execution/plan-store.js +3 -1
  54. package/dist/modules/execution/plan-validator.js +10 -10
  55. package/dist/modules/execution/planner.js +1 -6
  56. package/dist/modules/execution/stuck-detector.js +10 -173
  57. package/dist/modules/execution/verifier.js +42 -86
  58. package/dist/modules/hallucination/confidence.js +1 -8
  59. package/dist/modules/hallucination/detector.js +5 -2
  60. package/dist/modules/hallucination/factual.js +64 -3
  61. package/dist/modules/hallucination/index.js +1 -1
  62. package/dist/modules/hallucination/js-identifiers.js +0 -190
  63. package/dist/modules/hallucination/llm-judge.js +3 -1
  64. package/dist/modules/indexer/cache.js +7 -9
  65. package/dist/modules/indexer/index.js +3 -3
  66. package/dist/modules/indexer/module.js +42 -95
  67. package/dist/modules/indexer/walker.js +17 -17
  68. package/dist/modules/lsp/client.js +31 -74
  69. package/dist/modules/lsp/config.js +33 -87
  70. package/dist/modules/lsp/index.js +3 -3
  71. package/dist/modules/lsp/module.js +21 -185
  72. package/dist/modules/mcp/module.js +6 -2
  73. package/dist/modules/memory/index.js +1 -1
  74. package/dist/modules/memory/module.js +23 -71
  75. package/dist/modules/memory/search.js +9 -11
  76. package/dist/modules/memory/store.js +13 -13
  77. package/dist/modules/pipelines/engine.js +10 -10
  78. package/dist/modules/pipelines/index.js +3 -3
  79. package/dist/modules/pipelines/parser.js +14 -17
  80. package/dist/modules/pipelines/template.js +1 -1
  81. package/dist/modules/plugins/builtin/lint-on-write.js +16 -21
  82. package/dist/modules/plugins/builtin/notify.js +2 -3
  83. package/dist/modules/plugins/index.js +1 -1
  84. package/dist/modules/plugins/loader.js +17 -59
  85. package/dist/modules/plugins/manager.js +17 -73
  86. package/dist/modules/processes/index.js +1 -1
  87. package/dist/modules/processes/registry.js +46 -135
  88. package/dist/modules/registry.js +2 -4
  89. package/dist/modules/security/audit-notifier.js +39 -39
  90. package/dist/modules/security/command-validator.js +8 -2
  91. package/dist/modules/security/data-sanitizer.js +9 -1
  92. package/dist/modules/security/encryption.js +56 -58
  93. package/dist/modules/security/network-validator.js +9 -1
  94. package/dist/modules/security/path-validator.js +3 -1
  95. package/dist/modules/security/security-policies.js +19 -3
  96. package/dist/modules/security/session-encryption.js +1 -1
  97. package/dist/modules/security/session-isolation.js +8 -8
  98. package/dist/modules/session/index.js +3 -3
  99. package/dist/modules/session/module.js +5 -5
  100. package/dist/modules/session/store.js +9 -3
  101. package/dist/modules/skills/module.js +2 -1
  102. package/dist/modules/updater/checker.js +6 -70
  103. package/dist/modules/updater/index.js +1 -2
  104. package/dist/modules/user-profile/compressor.js +2 -2
  105. package/dist/modules/user-profile/index.js +1 -1
  106. package/dist/modules/user-profile/profile.js +9 -9
  107. package/dist/tools/attach-image.js +1 -1
  108. package/dist/tools/bash.js +19 -178
  109. package/dist/tools/browser.js +29 -46
  110. package/dist/tools/executor.js +5 -4
  111. package/dist/tools/file-info.js +12 -13
  112. package/dist/tools/filter-tools.js +2 -9
  113. package/dist/tools/glob-tool.js +11 -11
  114. package/dist/tools/grep-tool.js +3 -1
  115. package/dist/tools/index.js +2 -13
  116. package/dist/tools/list-dir.js +17 -18
  117. package/dist/tools/load-skill.js +3 -1
  118. package/dist/tools/path-utils.js +4 -4
  119. package/dist/tools/pipeline-run.js +25 -25
  120. package/dist/tools/process-kill.js +11 -11
  121. package/dist/tools/process-list.js +22 -20
  122. package/dist/tools/process-log.js +18 -22
  123. package/dist/tools/question.js +3 -1
  124. package/dist/tools/read-file.js +2 -10
  125. package/dist/tools/recall.js +37 -44
  126. package/dist/tools/registry.js +4 -15
  127. package/dist/tools/remember.js +29 -29
  128. package/dist/tools/scope-check.js +9 -9
  129. package/dist/tools/subagent.js +9 -54
  130. package/dist/tools/user-input.js +1 -1
  131. package/dist/tools/web-browse.js +3 -3
  132. package/dist/tools/web-fetch.js +3 -3
  133. package/dist/tools/web-search.js +3 -3
  134. package/dist/tools/write-file.js +3 -1
  135. package/dist/ui/box.js +5 -1
  136. package/dist/ui/index.js +6 -6
  137. package/dist/ui/md-formatter.js +33 -33
  138. package/dist/ui/output.js +5 -5
  139. package/dist/ui/renderer.js +10 -15
  140. package/dist/ui/table.js +1 -1
  141. package/package.json +48 -48
  142. package/dist/cli/plugin-commands.js +0 -36
  143. package/dist/cli/run-result.js +0 -22
  144. package/dist/core/version.js +0 -24
  145. package/dist/modules/artifacts/store.js +0 -61
  146. package/dist/modules/browser/bridge-client.js +0 -199
  147. package/dist/modules/browser/bridge-path.js +0 -10
  148. package/dist/modules/browser/driver.js +0 -136
  149. package/dist/modules/context/chunk-query.js +0 -100
  150. package/dist/modules/context/fact-extractor.js +0 -162
  151. package/dist/modules/context/history.js +0 -15
  152. package/dist/modules/execution/audit-runners.js +0 -152
  153. package/dist/modules/execution/execution-plugin.js +0 -272
  154. package/dist/modules/execution/plan-tool.js +0 -508
  155. package/dist/modules/execution/windows-commands.js +0 -41
  156. package/dist/modules/indexer/project-profile.js +0 -183
  157. package/dist/modules/lsp/check-tool.js +0 -58
  158. package/dist/modules/lsp/command.js +0 -60
  159. package/dist/modules/lsp/probe.js +0 -76
  160. package/dist/modules/lsp/project-root.js +0 -32
  161. package/dist/modules/lsp/startup-check.js +0 -141
  162. package/dist/modules/processes/detect.js +0 -34
  163. package/dist/modules/skills/matcher.js +0 -27
  164. package/dist/modules/updater/module.js +0 -116
  165. package/dist/tools/chunk-query.js +0 -99
  166. package/dist/tools/download-file.js +0 -116
  167. package/dist/tools/enable-tools.js +0 -58
  168. package/dist/tools/hidden-tools-block.js +0 -37
  169. package/dist/ui/line-editor.js +0 -703
  170. package/dist/ui/line-math.js +0 -69
  171. package/dist/ui/plan-view.js +0 -103
package/dist/i18n/ru.json CHANGED
@@ -27,7 +27,6 @@
27
27
  "error.response_blocked": "Ответ заблокирован: {reason}",
28
28
  "error.max_iters": "Достигнут максимум итераций ({max})",
29
29
  "error.empty_response": "Модель вернула пустой ответ после повторных попыток",
30
- "error.audit_failed": "Задача не может быть подтверждена как выполненная: {summary}",
31
30
  "error.grep_failed": "Ошибка grep: {message}",
32
31
  "error.search_failed": "Ошибка поиска: {message}",
33
32
  "error.fetch_failed": "Ошибка загрузки: {message}",
@@ -85,12 +84,9 @@
85
84
  "tool.friendly.web_search": "Поиск в интернете",
86
85
  "tool.friendly.web_fetch": "Загрузка страницы",
87
86
  "tool.friendly.web_browse": "Просмотр страницы",
88
- "tool.friendly.download_file": "Скачивание файла",
89
87
  "tool.web_fetch_result": "Загружена страница: {url} — {chars} симв., {lines} строк{truncated}",
90
88
  "tool.web_browse_result": "Просмотрена страница: {url} — {chars} симв., {lines} строк{truncated}",
91
89
  "tool.web_search_result": "Результаты поиска \"{query}\" — {count} результатов",
92
- "tool.downloaded": "Скачано {url} \u2192 {path} ({size} байт, {type})",
93
- "tool.download_too_large": "Скачивание заблокировано: файл превышает лимит {max} байт",
94
90
  "tool.friendly.browser": "Браузер",
95
91
  "tool.friendly.subagent": "Задача подагенту",
96
92
  "tool.friendly.question": "Вопрос пользователю",
@@ -98,10 +94,8 @@
98
94
  "tool.friendly.search_history": "Поиск в истории",
99
95
  "tool.friendly.pipeline_run": "Запуск пайплайна",
100
96
  "tool.friendly.mcp_call": "MCP вызов",
101
- "tool.friendly.lsp_check": "Проверка кода",
102
97
  "tool.truncated": "[Обрезано: удалено {tokens} токенов]",
103
98
  "tool.subagent_queued": "Задача подагенту добавлена: {task}",
104
- "tool.subagent_artifact": "Суб-агент завершён. Полный результат сохранён в артефакт: {path}\nИтераций: {iterations}\nСводка:\n{summary}",
105
99
  "tool.pipeline_started": "Пайплайн \"{name}\" запущен. Движок пайплайнов — заглушка, задача отправлена.",
106
100
  "tool.mcp_call": "MCP вызов: {server}/{tool} с {args}",
107
101
  "tool.action_required": "Требуется действие.",
@@ -122,8 +116,6 @@
122
116
  "tool.question.unanswered": "Без ответа",
123
117
  "tool.question.answered": "Пользователь ответил на ваши вопросы: {formatted}. Теперь продолжайте с учётом ответов.",
124
118
  "tool.name_or_task": "Укажите параметр \"name\" или \"task\"",
125
- "tool.chunk_query_no_query": "chunk_query: требуется строка запроса.",
126
- "tool.chunk_query_no_input": "chunk_query: укажите input_path или text.",
127
119
  "tool.invalid_params": "Неверные параметры",
128
120
  "tool.skill_budget": "Скилл \"{name}\" загружен ({tokens} токенов, осталось {remaining} в бюджете скиллов). Контент скилла теперь в системном промпте — перезагрузка после компрессии не нужна.",
129
121
  "tool.skill_available_hint": "Доступные скиллы",
@@ -141,7 +133,6 @@
141
133
  "proc.started": "Фоновый процесс запущен: {id} (PID {pid}).\nКоманда: {command}",
142
134
  "proc.promoted_hint": "Команда всё ещё выполняется через {ms} мс — переведена в фоновый режим",
143
135
  "proc.manage_hint": "Проверить вывод: process_log id={id}. Остановить: process_kill id={id}. Список всех: process_list.",
144
- "proc.output_preview": "Первые строки вывода:\n{lines}",
145
136
  "proc.none": "Фоновых процессов нет.",
146
137
  "proc.not_found": "Процесс не найден: {id}",
147
138
  "proc.killed": "Процесс {id} (PID {pid}) остановлен.",
@@ -164,20 +155,12 @@
164
155
  "plan.title_steps": "План \"{title}\" создан с {count} шагами",
165
156
  "plan.step_marked": "Шаг {step} отмечен как {status}",
166
157
  "plan.aborted": "План отменён",
167
- "plan.completed_archived": "План {id} завершён ({done}/{total} шагов) — архивирован. Для новой задачи создай новый план (plan create) или дай финальный ответ.",
168
158
  "plan.unknown_action": "Неизвестное действие плана: {action}",
169
159
  "plan.updated": "План обновлён: {title} ({steps} шагов)",
170
160
  "plan.acknowledged": "План {action}: принято",
171
161
  "plan.step_status": "Шаг {step}: {status}",
172
162
  "plan.no_active": "Нет активного плана",
173
163
  "plan.step_not_found": "Шаг не найден",
174
- "plan.step_already_done": "Шаг {step} уже выполнен — ничего делать не нужно. Прогресс плана:",
175
- "plan.order_blocked": "Нельзя отметить шаг {step} выполненным: шаг {first} («{desc}») ещё не завершён. Сначала завершите предыдущие шаги или отметьте шаг {first} status=skipped, если он не нужен.",
176
- "plan.deliverables_missing": "Нельзя отметить шаг {step} выполненным: указанные в нём файлы ещё не существуют: {files}. Сначала создайте эти файлы (или отметьте шаг status=skipped, если они на самом деле не нужны).",
177
- "plan.kinds_mismatch": "Длина kinds должна совпадать с числом шагов",
178
- "plan.kinds_invalid": "Недопустимый kind шага: {kinds}. Используй \"create\" или \"delete\".",
179
- "plan.kinds_not_array": "kinds должен быть массивом значений \"create\" или \"delete\"",
180
- "plan.deliverables_remain": "Нельзя пометить шаг {step} как выполненный: указанные файлы всё ещё существуют: {files}. Шаг имеет kind=delete — сначала удали их (или поставь status=skipped, если они должны остаться).",
181
164
  "plan.show_header": "Статус плана:",
182
165
  "plan.show_empty": "(в плане нет шагов)",
183
166
  "plan.list_header": "Планы:",
@@ -187,14 +170,9 @@
187
170
  "plan.switched": "Переключено на план {id}: {title}",
188
171
  "plan.replanned": "План перепланирован: {kept} выполненных шагов сохранено, {steps} новых шагов добавлено",
189
172
  "plan.replan_no_steps": "Укажите новые шаги для перепланирования",
190
- "plan.active_in_progress": "Нельзя создать новый план: активный план {id} уже имеет прогресс ({done}/{total} выполнено, текущий: шаг {current}). Продолжай его — вызови \"plan show\", чтобы увидеть, и продолжай работу. Чтобы заменить план, сначала вызови \"plan abort\", затем \"plan create\".",
191
- "plan.id_ignored": "примечание: id плана генерируется автоматически; используй \"plan switch\", чтобы активировать существующий план по id.",
192
- "plan.existing_fresh": "примечание: предыдущий активный план не имел прогресса и сохранён как черновик.",
193
173
  "todo.added": "Добавлено {count} задач: {items}",
194
174
  "todo.marked_done": "Отмечено выполненными: {count}",
195
175
  "todo.no_active": "Нет активных задач",
196
- "todo.no_items": "Не указаны подзадачи — укажите items для отметки выполненными",
197
- "todo.subtask_not_found": "Подзадачи не найдены: {items}",
198
176
  "todo.unknown_action": "Неизвестное действие todo: {action}",
199
177
  "todo.acknowledged": "Todo принято",
200
178
  "verify.passed": "Проверка пройдена",
@@ -204,14 +182,6 @@
204
182
  "verify.script_passed": "Скрипт '{script}' пройден",
205
183
  "verify.script_failed": "Скрипт '{script}' не пройден: {message}",
206
184
  "verify.syntax_error": "Синтаксическая ошибка в: {path}",
207
- "verify.no_files": "Шаг {step} не содержит именованных файлов для проверки — выполни реальную проверку (bun run build / bun test / lsp_check) и подтверди результат.",
208
- "lsp.unavailable": "статические проверки недоступны (сервер не найден). Проверяйте через собственный build/test проекта.",
209
- "lsp.check_disabled": "LSP-проверки отключены в конфигурации.",
210
- "lsp.check_no_path": "Укажите путь (файл или каталог) для проверки.",
211
- "lsp.check_notfound": "Путь не найден: {path}",
212
- "lsp.check_unsupported": "Для файла не настроен LSP-сервер: {path}",
213
- "lsp.check_clean": "Ошибок и предупреждений не обнаружено (проверено файлов: {count}).",
214
- "lsp.startup_header": "[Существующие ошибки проекта (проверено при старте сессии) — исправьте их перед продолжением]:",
215
185
  "cli.description": "Micro Models Agent — ИИ-агент для кодинга на малых моделях",
216
186
  "cli.init": "Запустить мастер настройки",
217
187
  "cli.config_saved": "Конфигурация сохранена в ~/.mma/config.json",
@@ -320,13 +290,6 @@
320
290
  "cli.security.recommended_for": "Рекомендуется для",
321
291
  "cli.yes": "Да",
322
292
  "cli.no": "Нет",
323
- "cli.plugins.description": "Управление плагинами",
324
- "cli.plugins.list": "Список загруженных плагинов (имя, версия, источник)",
325
- "cli.plugins.all": "Включить встроенные плагины",
326
- "cli.plugins.only_external": "(встроенные плагины скрыты — используйте --all)",
327
- "cli.plugins.none": "Плагины не загружены",
328
- "cli.plugins.header": "Плагины: {count} загружено (MMA v{mma})",
329
- "cli.plugins.builtin_mark": "●",
330
293
  "repl.help": "Показать доступные команды",
331
294
  "repl.help_usage": "Использование: /help",
332
295
  "repl.exit": "Выйти из REPL",
@@ -341,8 +304,6 @@
341
304
  "repl.reasoning_usage": "Использование: /reasoning",
342
305
  "repl.status": "Показать статус агента",
343
306
  "repl.status_usage": "Использование: /status",
344
- "repl.plugins": "Список загруженных плагинов",
345
- "repl.plugins_usage": "Использование: /plugins [--all]",
346
307
  "repl.sessions": "Список всех сессий (* активная)",
347
308
  "repl.sessions_usage": "Использование: /sessions",
348
309
  "repl.new": "Создать новую сессию",
@@ -369,7 +330,6 @@
369
330
  "repl.skill_unknown_sub": "Неизвестная подкоманда скилла: {subcmd}",
370
331
  "repl.skill_usage": "Использование: /skill [list|loaded|load|unload|search]",
371
332
  "repl.agent": "Агент: ",
372
- "repl.you": "Вы: ",
373
333
  "repl.interrupt": "Прервано (Esc)",
374
334
  "repl.title": "MMA REPL v{version}",
375
335
  "repl.model": "Модель:",
@@ -387,10 +347,6 @@
387
347
  "repl.skills_label": "Скиллы:",
388
348
  "repl.plugins_label": "Плагины:",
389
349
  "repl.mcp_label": "MCP:",
390
- "repl.lsp_label": "LSP:",
391
- "repl.lsp_timeout": "таймаут",
392
- "repl.lsp_failed": "не стартовал",
393
- "repl.lsp_unknown": "неизвестно",
394
350
  "repl.work_dir": "Директория:",
395
351
  "repl.agents_label": "Инструкции:",
396
352
  "repl.not_found": "не найден",
@@ -469,8 +425,6 @@
469
425
  "exec.tool_errors_recovery": "Инструмент {tool} упал {count} раз подряд. Попробуйте альтернативу: создайте файлы напрямую через write_file, используйте другую команду, или пропустите этот шаг через plan update step=N status=skipped с пометкой почему.",
470
426
  "exec.repetitive_tool": "Инструмент {tool} вызван {count} раз с одинаковыми аргументами и результатом. Попробуйте другой подход — создайте файлы напрямую, измените аргументы или проверьте статус процесса через process_log.",
471
427
  "exec.consecutive_failures_recovery": "{count} инструментов подряд упали. Создавайте файлы напрямую через write_file вместо команд терминала. Проверьте что зависимости установлены (npm install). Не запускайте сборку/тесты пока не созданы все файлы.",
472
- "exec.read_only_loop": "Нет записи/выполнения за {count} вызовов — агент только читает/исследует.",
473
- "exec.read_only_loop_recovery": "{count} вызовов только для чтения подряд (read_file/glob/grep/browser) без записи. Хватит исследовать — внесите правку, которую требует задача: прочитайте файл, затем вызовите write_file или edit_file. Если не можете завершить задачу — спросите пользователя, а не перечитывайте одни и те же файлы.",
474
428
  "exec.plan_warning": "Текущий шаг плана {step} — \"{description}\", но вызывается {tool} для файлов вне этого шага. Завершите текущий шаг, вызовите plan update step={step} status=done, затем переходите к следующему.",
475
429
  "exec.plan_blocked": "{max} вызовов подряд вне текущего шага. Завершите шаг {step} — остальные шаги ждут пока этот не будет выполнен.",
476
430
  "exec.off_track": "Шаг {stepId} — \"{description}\", но используется {tool} для другого пути. Вернитесь к текущему шагу.",
@@ -480,18 +434,13 @@
480
434
  "exec.step_gate_ok": "[✓] Шаг {step} завершён и проверен. ПЕРЕХОДИМ к шагу {nextStep}: \"{nextDesc}\". Работайте ТОЛЬКО над этим шагом.",
481
435
  "exec.step_gate_last": "[✓] Шаг {step} завершён — это был последний шаг. Проверьте всё вместе и предоставьте финальный ответ.]",
482
436
  "exec.audit_pass": "[✓] Задача выполнена: {done}/{total} шагов, {files} файлов проверено",
483
- "exec.audit_pending": "[✗] Задача не выполнена: {done}/{total} шагов — оставшиеся шаги не отмечены выполненными",
484
437
  "exec.audit_fail": "[✗] Задача не выполнена: {done}/{total} шагов, {files} файлов отсутствует",
485
- "exec.audit_leftovers": "[✗] Задача не выполнена: {done}/{total} шагов, {files} файлов из delete-шагов всё ещё существуют",
486
- "exec.audit_fail_tests": "[✗] Задача не выполнена: {done}/{total} шагов, тесты ПАДАЮТ: {failed} failed / {passed} passed — {detail}",
487
438
  "exec.audit_fail_typecheck": "[✗] Задача не выполнена: {done}/{total} шагов, {missing} файлов отсутствует, ошибка typecheck: {typeError}",
488
439
  "exec.audit_incomplete": "[⚠ Финальная проверка не пройдена: {summary}. Задача НЕ завершена — продолжайте работу. Оставшиеся шаги: {steps}]",
489
440
  "exec.mass_edit_warning": "⚠️ План затрагивает {count} файлов — проверьте полный список перед продолжением.",
490
441
  "exec.escalation": "\n\n⚠️ Агент застрял на шаге {stepId} ({description}). Эскалация к пользователю — пожалуйста, подскажите как действовать.",
491
442
  "exec.hints": "\n[Подсказки]\n{hints}",
492
443
  "exec.file_rewrite_warning": "⚠️ Файл {file} был перезаписан {count} раз. Попробуйте другой подход — текущая стратегия исправлений не работает.",
493
- "exec.forbidden_cmd": "ПРЕКРАТИ использовать \"{cmd}\" через bash — это не команда Windows cmd.exe, и она уже неоднократно падала в этой сессии. Используй предназначенный тул: grep → тул grep, ls/dir → list_dir, find → glob, rm → delete_file, sed → edit_file, touch → write_file, which → `where`, cp/mv → move_file, diff → read_file. Больше не вызывай bash для этого.",
494
- "exec.npm_exec_hint": "\"could not determine executable to run\" — у пакета/скрипта нет \"bin\". Используй \"npm run <script>\" (скрипт должен быть в package.json) или \"bunx <pkg>\" для пакета с объявленным bin.",
495
444
  "hall.max_retries_exhausted": "Модель вернула пустой или недостаточный ответ после нескольких попыток",
496
445
  "hall.short_response": "Слишком короткий или пустой ответ",
497
446
  "hall.repetitive": "Слишком повторяющийся ответ ({pct}% совпадение)",
@@ -517,17 +466,11 @@
517
466
  "browser.no_page_short": "Нет страницы",
518
467
  "browser.no_elements": "(нет интерактивных элементов на странице)",
519
468
  "browser.more_elements": "... и другие элементы не показаны. Используйте прокрутку или поиск.",
520
- "browser.content_header": "Содержимое:",
521
- "browser.console_header": "Консоль:",
522
- "browser.network_errors_header": "Сетевые ошибки:",
523
- "browser.truncated": "... (обрезано)",
524
469
  "pipeline.invalid": "Невалидный пайплайн: требуются name и steps",
525
470
  "pipeline.step_missing_fields": "Шаг не содержит обязательных полей (id, agent, prompt): {step}",
526
471
  "pipeline.circular": "Циклическая зависимость: {stepId}",
527
472
  "plugin.loaded": "Загружен плагин: {name}",
528
473
  "plugin.skipped": "Пропущен несовместимый плагин: {entry} ({message})",
529
- "plugin.incompatible": "Пропущен плагин {name}: требуется MMA v{min}, текущая v{current}",
530
- "plugin.dedup_older": "Плагин {name} v{version} пропущен: уже загружена более новая версия",
531
474
  "migration.detected": "[MMA] Обнаружен старый конфиг. {summary}",
532
475
  "migration.summary": "[MMA] {summary}",
533
476
  "migration.config_bak": "- config → config.json.bak",
@@ -538,7 +481,6 @@
538
481
  "ui.success_prefix": "✓ ",
539
482
  "ui.warning_prefix": "⚠ ",
540
483
  "ui.thinking": "Думаю…",
541
- "ui.step_context": "шаг {id}: {desc}",
542
484
  "indexer.map_header": "Карта проекта",
543
485
  "indexer.top_directories": "Основные директории",
544
486
  "indexer.files": "Файлы",
@@ -552,10 +494,6 @@
552
494
  "indexer.not_indexed": "Проект ещё не проиндексирован",
553
495
  "indexer.find_results": "Найдено {count} совпадающих файлов:\n{results}",
554
496
  "indexer.no_matches": "Нет совпадающих файлов для \"{query}\"",
555
- "indexer.duplicates": "Дубликаты basename (проверьте, какой файл реально используется): {names}",
556
- "indexer.stack_deps": "зависимости",
557
- "indexer.stack_dev": "dev",
558
- "indexer.stack_scripts": "скрипты",
559
497
  "tool.friendly.project_map": "Карта проекта",
560
498
  "config.decryption_warning": "Предупреждение: не удалось расшифровать конфигурацию: {error}",
561
499
  "config.encryption_warning": "Предупреждение: не удалось зашифровать конфигурацию: {error}",
@@ -583,16 +521,5 @@
583
521
  "ctx.delta_neg": "контекст -{tokens} ↓",
584
522
  "ctx.delta_zero": "контекст ±0",
585
523
  "file.notfound_resolved": "Файл не найден: {path} (резолвится в {resolved})",
586
- "bash.echo_write_blocked": "Запись файлов через echo/printf ненадёжна в Windows cmd.exe (кавычки и многострочность ломаются). Используй инструмент write_file вместо этого (цель: {path}).",
587
- "updater.check_error": "[updater] Ошибка проверки обновления: {error}",
588
- "updater.available": "[updater] Доступно обновление: {current} → {latest}. Выполните `npm install -g micro-models-agent` для обновления.",
589
- "updater.installing": "[updater] Установка {latest} глобально (текущая: {current})…",
590
- "updater.installed": "[updater] Установлена {latest}. Перезапустите MMA для применения (была {current}).",
591
- "updater.install_failed": "[updater] Не удалось установить {latest}: {error}. Обновите вручную: `npm install -g micro-models-agent`.",
592
- "tools.enable_no_tags": "enable_tools требует хотя бы один тег в массиве \"tags\".",
593
- "tools.enable_no_executor": "Исполнитель тулов недоступен — невозможно перечислить включённые тулы.",
594
- "tools.enable_already_active": "Теги тулов уже активны: {tags}.",
595
- "tools.enable_added": "Включены теги тулов: {tags}. Теперь доступны тулы: {tools}",
596
- "tools.hidden_header": "Дополнительные тулы (включите по требованию через enable_tools или маршрутизируйте через subagent tool_tags):",
597
- "tool.friendly.enable_tools": "Включить тулы"
524
+ "bash.echo_write_blocked": "Запись файлов через echo/printf ненадёжна в Windows cmd.exe (кавычки и многострочность ломаются). Используй инструмент write_file вместо этого (цель: {path})."
598
525
  }
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { DEFAULTS, loadConfig } from "./config/index";
2
2
  export { Logger } from "./logger/index";
3
3
  export { PromptBuilder } from "./core/index";
4
- export { OpenAICompatProvider, TokenCounter, parseChunks, OrchestratorClient } from "./llm/index";
4
+ export { OpenAICompatProvider, TokenCounter, parseChunks, OrchestratorClient, } from "./llm/index";
5
5
  export { ToolRegistry, ToolExecutor, readFileTool, writeFileTool, editFileTool, globTool, grepTool, listDirTool, createDirTool, deleteFileTool, moveFileTool, fileInfoTool, bashTool, subagentTool, webSearchTool, webFetchTool, webBrowseTool, createLoadSkillTool, pipelineRunTool, mcpCallTool, searchHistoryTool, registerAllTools, } from "./tools/index";
6
6
  export { MigrationDetector, BackupManager } from "./migration/index";
7
7
  import { MigrationDetector } from "./migration/detect";
@@ -25,7 +25,10 @@ export async function readClipboardImage() {
25
25
  try {
26
26
  const img = Bun.Image.fromClipboard();
27
27
  if (img) {
28
- const buf = await img.resize(800, 800, { fit: "inside" }).jpeg({ quality: 60 }).buffer();
28
+ const buf = await img
29
+ .resize(800, 800, { fit: "inside" })
30
+ .jpeg({ quality: 60 })
31
+ .buffer();
29
32
  return Buffer.from(buf);
30
33
  }
31
34
  }
@@ -44,9 +47,7 @@ async function readClipboardFallback() {
44
47
  const tmpPath = join(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
45
48
  try {
46
49
  if (platform() === "linux") {
47
- execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, {
48
- timeout: 5000,
49
- });
50
+ execSync(`xclip -selection clipboard -t image/png -o > "${tmpPath}" 2>/dev/null`, { timeout: 5000 });
50
51
  }
51
52
  else {
52
53
  return null; // macOS/Windows should use Bun.Image
package/dist/llm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { OpenAICompatProvider } from "./openai-compat";
2
- export { TokenCounter } from "./token-counter";
3
- export { parseChunks } from "./response";
4
- export { OrchestratorClient } from "./orchestrator";
1
+ export { OpenAICompatProvider } from './openai-compat';
2
+ export { TokenCounter } from './token-counter';
3
+ export { parseChunks } from './response';
4
+ export { OrchestratorClient } from './orchestrator';
@@ -2,8 +2,8 @@ export class ModelLoader {
2
2
  baseUrl;
3
3
  logger;
4
4
  constructor(baseUrl, logger) {
5
- const url = baseUrl.replace(/\/$/, "");
6
- this.baseUrl = url.replace(/\/v1\/?$/, "");
5
+ const url = baseUrl.replace(/\/$/, '');
6
+ this.baseUrl = url.replace(/\/v1\/?$/, '');
7
7
  this.logger = logger;
8
8
  }
9
9
  async ensureModelLoaded(config) {
@@ -30,7 +30,7 @@ export class ModelLoader {
30
30
  });
31
31
  if (!response.ok)
32
32
  return false;
33
- const data = (await response.json());
33
+ const data = await response.json();
34
34
  const models = data.models || [];
35
35
  const found = models.find((m) => m.key === model || m.name === model);
36
36
  if (!found)
@@ -56,8 +56,8 @@ export class ModelLoader {
56
56
  this.logger.info(`Loading model ${config.model} with context_length=${config.contextLength}`);
57
57
  this.logger.debug(`POST ${this.baseUrl}/api/v1/models/load`);
58
58
  const response = await fetch(`${this.baseUrl}/api/v1/models/load`, {
59
- method: "POST",
60
- headers: { "Content-Type": "application/json" },
59
+ method: 'POST',
60
+ headers: { 'Content-Type': 'application/json' },
61
61
  body: JSON.stringify(body),
62
62
  signal: AbortSignal.timeout(120000),
63
63
  });
@@ -66,7 +66,7 @@ export class ModelLoader {
66
66
  this.logger.error(`Model load failed: HTTP ${response.status}: ${error}`);
67
67
  return { success: false, error: `HTTP ${response.status}: ${error}` };
68
68
  }
69
- const result = (await response.json());
69
+ const result = await response.json();
70
70
  this.logger.debug(`Model load response: ${JSON.stringify(result)}`);
71
71
  const loadTime = result.load_time_seconds ?? result.loadTime;
72
72
  return {
@@ -1,30 +1,6 @@
1
1
  import { TokenCounter } from "./token-counter";
2
2
  import { t } from "../i18n/index";
3
- import { createRateLimiter } from "../modules/security/rate-limiter";
4
- function buildRequestBody(opts) {
5
- const body = {
6
- model: opts.model,
7
- messages: opts.messages,
8
- stream: opts.stream,
9
- };
10
- if (opts.maxTokens !== undefined)
11
- body.max_tokens = opts.maxTokens;
12
- if (opts.reasoningEffort) {
13
- body.reasoning_effort = opts.reasoningEffort;
14
- }
15
- if (opts.tools && opts.tools.length > 0) {
16
- body.tools = opts.tools.map((t) => ({
17
- type: "function",
18
- function: {
19
- name: t.name,
20
- description: t.description,
21
- parameters: t.parameters,
22
- },
23
- }));
24
- body.tool_choice = "auto";
25
- }
26
- return body;
27
- }
3
+ import { createRateLimiter, } from "../modules/security/rate-limiter";
28
4
  export class OpenAICompatProvider {
29
5
  model;
30
6
  contextWindow;
@@ -44,14 +20,14 @@ export class OpenAICompatProvider {
44
20
  };
45
21
  this.rateLimiter = createRateLimiter(config.rateLimits);
46
22
  }
47
- async *chat(messages, tools, signal, options) {
23
+ async *chat(messages, tools, signal) {
48
24
  // Check rate limit before making request
49
25
  if (!this.rateLimiter.canMakeRequest()) {
50
26
  throw new Error(`Rate limit exceeded: ${this.rateLimiter.getConfig().maxRequestsPerMinute} requests per minute`);
51
27
  }
52
28
  // Record this request
53
29
  this.rateLimiter.recordRequest();
54
- const streamResult = this.doStream(messages, tools, signal, options);
30
+ const streamResult = this.doStream(messages, tools, signal);
55
31
  let hasToolCall = false;
56
32
  let hasText = false;
57
33
  let reasoningAcc = "";
@@ -66,21 +42,30 @@ export class OpenAICompatProvider {
66
42
  yield chunk;
67
43
  }
68
44
  if (!hasToolCall && !hasText) {
69
- const fallback = await this.doNonStreaming(messages, tools, signal, options);
45
+ const fallback = await this.doNonStreaming(messages, tools, signal);
70
46
  for (const chunk of fallback) {
71
47
  yield chunk;
72
48
  }
73
49
  }
74
50
  }
75
- async *doStream(messages, tools, signal, options) {
76
- const body = buildRequestBody({
51
+ async *doStream(messages, tools, signal) {
52
+ const body = {
77
53
  model: this.model,
78
54
  messages,
79
- tools,
80
55
  stream: true,
81
- maxTokens: options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096,
82
- reasoningEffort: options?.reasoningEffort,
83
- });
56
+ max_tokens: this.config.maxCompletionTokens ?? 4096,
57
+ };
58
+ if (tools && tools.length > 0) {
59
+ body.tools = tools.map((t) => ({
60
+ type: "function",
61
+ function: {
62
+ name: t.name,
63
+ description: t.description,
64
+ parameters: t.parameters,
65
+ },
66
+ }));
67
+ body.tool_choice = "auto";
68
+ }
84
69
  const headers = {
85
70
  "Content-Type": "application/json",
86
71
  };
@@ -210,15 +195,24 @@ export class OpenAICompatProvider {
210
195
  reader.releaseLock();
211
196
  }
212
197
  }
213
- async doNonStreaming(messages, tools, signal, options) {
214
- const body = buildRequestBody({
198
+ async doNonStreaming(messages, tools, signal) {
199
+ const body = {
215
200
  model: this.model,
216
201
  messages,
217
- tools,
218
202
  stream: false,
219
- maxTokens: options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096,
220
- reasoningEffort: options?.reasoningEffort,
221
- });
203
+ max_tokens: this.config.maxCompletionTokens ?? 4096,
204
+ };
205
+ if (tools && tools.length > 0) {
206
+ body.tools = tools.map((t) => ({
207
+ type: "function",
208
+ function: {
209
+ name: t.name,
210
+ description: t.description,
211
+ parameters: t.parameters,
212
+ },
213
+ }));
214
+ body.tool_choice = "auto";
215
+ }
222
216
  const headers = {
223
217
  "Content-Type": "application/json",
224
218
  };
@@ -1,5 +1,5 @@
1
- import { OpenAICompatProvider } from "./openai-compat";
2
- import { jsonrepair } from "jsonrepair";
1
+ import { OpenAICompatProvider } from './openai-compat';
2
+ import { jsonrepair } from 'jsonrepair';
3
3
  const PLAN_SYSTEM_PROMPT = `You are a planning assistant for an agent system with multiple expert sub-agents.
4
4
  Break down the user's task into subtasks that can be executed by different expert agents.
5
5
 
@@ -58,7 +58,7 @@ export class OrchestratorClient {
58
58
  if (config.provider) {
59
59
  this.provider = new OpenAICompatProvider({
60
60
  model: config.model,
61
- baseUrl: config.provider.baseUrl || "http://localhost:1234/v1",
61
+ baseUrl: config.provider.baseUrl || 'http://localhost:1234/v1',
62
62
  apiKey: config.provider.apiKey,
63
63
  retry: config.retry,
64
64
  });
@@ -69,7 +69,7 @@ export class OrchestratorClient {
69
69
  else {
70
70
  this.provider = new OpenAICompatProvider({
71
71
  model: config.model,
72
- baseUrl: "http://localhost:1234/v1",
72
+ baseUrl: 'http://localhost:1234/v1',
73
73
  retry: config.retry,
74
74
  });
75
75
  }
@@ -83,15 +83,15 @@ export class OrchestratorClient {
83
83
  }
84
84
  async chat(messages) {
85
85
  if (!this.provider)
86
- throw new Error("Orchestrator not enabled");
86
+ throw new Error('Orchestrator not enabled');
87
87
  const chunks = [];
88
88
  for await (const chunk of this.provider.chat(messages)) {
89
89
  chunks.push(chunk);
90
90
  }
91
91
  return chunks
92
- .filter((c) => c.type === "text")
92
+ .filter((c) => c.type === 'text')
93
93
  .map((c) => c.content)
94
- .join("");
94
+ .join('');
95
95
  }
96
96
  parseJSON(text) {
97
97
  try {
@@ -109,9 +109,7 @@ export class OrchestratorClient {
109
109
  const repaired = jsonrepair(jsonMatch[0]);
110
110
  return JSON.parse(repaired);
111
111
  }
112
- catch {
113
- /* fall through */
114
- }
112
+ catch { /* fall through */ }
115
113
  }
116
114
  return null;
117
115
  }
@@ -119,10 +117,10 @@ export class OrchestratorClient {
119
117
  }
120
118
  async plan(userPrompt, _context) {
121
119
  if (!this.provider)
122
- return { error: "Orchestrator not enabled — no orchestrator model configured" };
120
+ return { error: 'Orchestrator not enabled — no orchestrator model configured' };
123
121
  const messages = [
124
- { role: "system", content: PLAN_SYSTEM_PROMPT },
125
- { role: "user", content: userPrompt },
122
+ { role: 'system', content: PLAN_SYSTEM_PROMPT },
123
+ { role: 'user', content: userPrompt },
126
124
  ];
127
125
  const text = await this.chat(messages);
128
126
  const parsed = this.parseJSON(text);
@@ -133,21 +131,19 @@ export class OrchestratorClient {
133
131
  }
134
132
  async verifyAndMerge(input) {
135
133
  if (!this.provider)
136
- return { type: "final", finalAnswer: input.results.map((r) => r.summary).join("\n") };
134
+ return { type: 'final', finalAnswer: input.results.map(r => r.summary).join('\n') };
137
135
  this.replanCycle++;
138
136
  if (this.replanCycle > 3) {
139
137
  return {
140
- type: "final",
141
- finalAnswer: input.results
142
- .map((r) => `${r.subtaskId}: ${r.success ? "OK" : "FAIL"} — ${r.summary}`)
143
- .join("\n"),
144
- explanation: "Max re-plan cycles (3) reached. Returning partial results.",
138
+ type: 'final',
139
+ finalAnswer: input.results.map(r => `${r.subtaskId}: ${r.success ? 'OK' : 'FAIL'} — ${r.summary}`).join('\n'),
140
+ explanation: 'Max re-plan cycles (3) reached. Returning partial results.',
145
141
  };
146
142
  }
147
143
  const context = JSON.stringify(input, null, 2);
148
144
  const messages = [
149
- { role: "system", content: VERIFY_SYSTEM_PROMPT },
150
- { role: "user", content: context },
145
+ { role: 'system', content: VERIFY_SYSTEM_PROMPT },
146
+ { role: 'user', content: context },
151
147
  ];
152
148
  const text = await this.chat(messages);
153
149
  const parsed = this.parseJSON(text);
@@ -155,20 +151,20 @@ export class OrchestratorClient {
155
151
  return parsed;
156
152
  }
157
153
  return {
158
- type: "final",
159
- finalAnswer: input.results.map((r) => r.summary).join("\n"),
160
- explanation: "Failed to parse verifier output, returning collected results.",
154
+ type: 'final',
155
+ finalAnswer: input.results.map(r => r.summary).join('\n'),
156
+ explanation: 'Failed to parse verifier output, returning collected results.',
161
157
  };
162
158
  }
163
159
  async createPlan(task) {
164
160
  if (!this.provider)
165
- throw new Error("Orchestrator not enabled");
161
+ throw new Error('Orchestrator not enabled');
166
162
  const messages = [
167
163
  {
168
- role: "system",
164
+ role: 'system',
169
165
  content: 'You are a planning assistant. Break down tasks into steps. Respond with JSON only: {"steps": ["step 1", "step 2", ...]}',
170
166
  },
171
- { role: "user", content: task },
167
+ { role: 'user', content: task },
172
168
  ];
173
169
  const text = await this.chat(messages);
174
170
  try {
@@ -180,17 +176,17 @@ export class OrchestratorClient {
180
176
  }
181
177
  async resolveConflict(context) {
182
178
  if (!this.provider)
183
- throw new Error("Orchestrator not enabled");
179
+ throw new Error('Orchestrator not enabled');
184
180
  const messages = [
185
181
  {
186
- role: "system",
187
- content: "You are a conflict resolution assistant. Analyze the situation and recommend the best path forward.",
182
+ role: 'system',
183
+ content: 'You are a conflict resolution assistant. Analyze the situation and recommend the best path forward.',
188
184
  },
189
- { role: "user", content: context },
185
+ { role: 'user', content: context },
190
186
  ];
191
- let result = "";
187
+ let result = '';
192
188
  for await (const chunk of this.provider.chat(messages)) {
193
- if (chunk.type === "text" && chunk.content)
189
+ if (chunk.type === 'text' && chunk.content)
194
190
  result += chunk.content;
195
191
  }
196
192
  return result;
@@ -1,16 +1,16 @@
1
1
  export function parseChunks(chunks) {
2
- let text = "";
2
+ let text = '';
3
3
  let reasoning;
4
4
  const toolCalls = [];
5
5
  let hasToolCalls = false;
6
6
  for (const chunk of chunks) {
7
- if (chunk.type === "text" && chunk.content) {
7
+ if (chunk.type === 'text' && chunk.content) {
8
8
  text += chunk.content;
9
9
  }
10
- if (chunk.type === "reasoning" && chunk.content) {
11
- reasoning = (reasoning || "") + chunk.content;
10
+ if (chunk.type === 'reasoning' && chunk.content) {
11
+ reasoning = (reasoning || '') + chunk.content;
12
12
  }
13
- if (chunk.type === "tool_call" && chunk.toolCall) {
13
+ if (chunk.type === 'tool_call' && chunk.toolCall) {
14
14
  hasToolCalls = true;
15
15
  let parsedArgs;
16
16
  try {
@@ -27,13 +27,13 @@ export function parseChunks(chunks) {
27
27
  }
28
28
  }
29
29
  if (hasToolCalls) {
30
- return { type: "tool_call", calls: toolCalls, reasoning };
30
+ return { type: 'tool_call', calls: toolCalls, reasoning };
31
31
  }
32
32
  if (reasoning && !text) {
33
- return { type: "reasoning", content: reasoning };
33
+ return { type: 'reasoning', content: reasoning };
34
34
  }
35
35
  if (!text && !reasoning) {
36
- return { type: "empty" };
36
+ return { type: 'empty' };
37
37
  }
38
- return { type: "text", content: text || "", reasoning };
38
+ return { type: 'text', content: text || '', reasoning };
39
39
  }
@@ -11,7 +11,7 @@ const LEVEL_COLORS = {
11
11
  error: (s) => pc.red(s),
12
12
  };
13
13
  function isColorEnabled() {
14
- return !process.env.NO_COLOR && !process.env.CI && process.stdout.isTTY === true;
14
+ return (!process.env.NO_COLOR && !process.env.CI && process.stdout.isTTY === true);
15
15
  }
16
16
  export class Logger {
17
17
  level;
@@ -1 +1 @@
1
- export { Logger } from "./app-logger";
1
+ export { Logger } from './app-logger';