micro-models-agent 0.59.0 → 0.60.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 (233) hide show
  1. package/CHANGELOG.md +584 -564
  2. package/README.md +358 -358
  3. package/dist/certification/certifications.json +493 -493
  4. package/dist/i18n/en.json +746 -718
  5. package/dist/i18n/ru.json +746 -718
  6. package/dist/main.js +566 -70
  7. package/dist/modules/browser/bridge-server.mjs +219 -219
  8. package/dist/skills/builtin/git.md +36 -36
  9. package/dist/skills/builtin/typescript.md +35 -35
  10. package/package.json +51 -51
  11. package/dist/cli/commands.js +0 -447
  12. package/dist/cli/completer.js +0 -167
  13. package/dist/cli/index.js +0 -2
  14. package/dist/cli/main.js +0 -153
  15. package/dist/cli/plugin-commands.js +0 -36
  16. package/dist/cli/repl-commands.js +0 -761
  17. package/dist/cli/repl.js +0 -702
  18. package/dist/cli/run-result.js +0 -33
  19. package/dist/cli/security-commands.js +0 -164
  20. package/dist/cli/setup.js +0 -237
  21. package/dist/config/config.js +0 -276
  22. package/dist/config/defaults.js +0 -141
  23. package/dist/config/domains.js +0 -179
  24. package/dist/config/experts.js +0 -15
  25. package/dist/config/index.js +0 -4
  26. package/dist/config/security.js +0 -213
  27. package/dist/config/types.js +0 -1
  28. package/dist/core/agent-moe.js +0 -102
  29. package/dist/core/agent.js +0 -1018
  30. package/dist/core/bootstrap.js +0 -481
  31. package/dist/core/crash-handler.js +0 -51
  32. package/dist/core/environment.js +0 -199
  33. package/dist/core/index.js +0 -2
  34. package/dist/core/prompt-builder.js +0 -76
  35. package/dist/core/session-logger.js +0 -251
  36. package/dist/core/types.js +0 -1
  37. package/dist/core/version.js +0 -26
  38. package/dist/core/workspace.js +0 -76
  39. package/dist/i18n/index.js +0 -46
  40. package/dist/index.js +0 -22
  41. package/dist/llm/image-utils.js +0 -143
  42. package/dist/llm/index.js +0 -4
  43. package/dist/llm/model-loader.js +0 -78
  44. package/dist/llm/openai-compat.js +0 -497
  45. package/dist/llm/orchestrator.js +0 -200
  46. package/dist/llm/provider.js +0 -10
  47. package/dist/llm/response.js +0 -39
  48. package/dist/llm/token-counter.js +0 -39
  49. package/dist/llm/types.js +0 -1
  50. package/dist/logger/app-logger.js +0 -189
  51. package/dist/logger/file-log.js +0 -151
  52. package/dist/logger/index.js +0 -1
  53. package/dist/migration/backup.js +0 -45
  54. package/dist/migration/detect.js +0 -50
  55. package/dist/migration/index.js +0 -2
  56. package/dist/modules/artifacts/store.js +0 -61
  57. package/dist/modules/browser/actions.js +0 -76
  58. package/dist/modules/browser/bridge-client.js +0 -199
  59. package/dist/modules/browser/bridge-path.js +0 -10
  60. package/dist/modules/browser/cookie-store.js +0 -24
  61. package/dist/modules/browser/driver.js +0 -136
  62. package/dist/modules/browser/index.js +0 -7
  63. package/dist/modules/browser/module.js +0 -29
  64. package/dist/modules/browser/session.js +0 -342
  65. package/dist/modules/browser/snapshot.js +0 -148
  66. package/dist/modules/browser/types.js +0 -12
  67. package/dist/modules/certification/cli.js +0 -213
  68. package/dist/modules/certification/fact-checker.js +0 -82
  69. package/dist/modules/certification/loader.js +0 -106
  70. package/dist/modules/certification/manifest.js +0 -58
  71. package/dist/modules/certification/runner.js +0 -245
  72. package/dist/modules/certification/scenarios.js +0 -407
  73. package/dist/modules/certification/types.js +0 -1
  74. package/dist/modules/context/chunk-query.js +0 -100
  75. package/dist/modules/context/fact-extractor.js +0 -168
  76. package/dist/modules/context/history.js +0 -15
  77. package/dist/modules/context/index.js +0 -1
  78. package/dist/modules/context/manager.js +0 -440
  79. package/dist/modules/execution/audit-runners.js +0 -206
  80. package/dist/modules/execution/auditor.js +0 -218
  81. package/dist/modules/execution/execution-plugin.js +0 -431
  82. package/dist/modules/execution/index.js +0 -8
  83. package/dist/modules/execution/module.js +0 -625
  84. package/dist/modules/execution/moe-executor.js +0 -304
  85. package/dist/modules/execution/plan-coverage.js +0 -68
  86. package/dist/modules/execution/plan-persister.js +0 -46
  87. package/dist/modules/execution/plan-store.js +0 -196
  88. package/dist/modules/execution/plan-tool.js +0 -677
  89. package/dist/modules/execution/plan-validator.js +0 -153
  90. package/dist/modules/execution/planner.js +0 -94
  91. package/dist/modules/execution/stuck-detector.js +0 -746
  92. package/dist/modules/execution/tracker.js +0 -69
  93. package/dist/modules/execution/types.js +0 -1
  94. package/dist/modules/execution/verifier.js +0 -235
  95. package/dist/modules/execution/windows-commands.js +0 -41
  96. package/dist/modules/hallucination/confidence.js +0 -66
  97. package/dist/modules/hallucination/consistency.js +0 -26
  98. package/dist/modules/hallucination/detector.js +0 -47
  99. package/dist/modules/hallucination/factual.js +0 -169
  100. package/dist/modules/hallucination/index.js +0 -5
  101. package/dist/modules/hallucination/js-identifiers.js +0 -262
  102. package/dist/modules/hallucination/llm-judge.js +0 -101
  103. package/dist/modules/index.js +0 -5
  104. package/dist/modules/indexer/cache.js +0 -40
  105. package/dist/modules/indexer/index.js +0 -3
  106. package/dist/modules/indexer/module.js +0 -246
  107. package/dist/modules/indexer/project-profile.js +0 -183
  108. package/dist/modules/indexer/walker.js +0 -101
  109. package/dist/modules/lsp/check-tool.js +0 -58
  110. package/dist/modules/lsp/client.js +0 -389
  111. package/dist/modules/lsp/command.js +0 -60
  112. package/dist/modules/lsp/config.js +0 -135
  113. package/dist/modules/lsp/index.js +0 -3
  114. package/dist/modules/lsp/module.js +0 -260
  115. package/dist/modules/lsp/probe.js +0 -86
  116. package/dist/modules/lsp/project-root.js +0 -32
  117. package/dist/modules/lsp/startup-check.js +0 -144
  118. package/dist/modules/lsp/types.js +0 -1
  119. package/dist/modules/mcp/client.js +0 -399
  120. package/dist/modules/mcp/index.js +0 -3
  121. package/dist/modules/mcp/module.js +0 -142
  122. package/dist/modules/mcp/registry.js +0 -15
  123. package/dist/modules/memory/index.js +0 -1
  124. package/dist/modules/memory/module.js +0 -96
  125. package/dist/modules/memory/search.js +0 -42
  126. package/dist/modules/memory/store.js +0 -69
  127. package/dist/modules/pipelines/engine.js +0 -60
  128. package/dist/modules/pipelines/index.js +0 -3
  129. package/dist/modules/pipelines/parser.js +0 -56
  130. package/dist/modules/pipelines/template.js +0 -14
  131. package/dist/modules/plugins/builtin/lint-on-write.js +0 -334
  132. package/dist/modules/plugins/builtin/notify.js +0 -9
  133. package/dist/modules/plugins/index.js +0 -1
  134. package/dist/modules/plugins/loader.js +0 -70
  135. package/dist/modules/plugins/manager.js +0 -261
  136. package/dist/modules/plugins/types.js +0 -1
  137. package/dist/modules/pricing/index.js +0 -61
  138. package/dist/modules/pricing/prices.js +0 -129
  139. package/dist/modules/processes/detect.js +0 -34
  140. package/dist/modules/processes/index.js +0 -2
  141. package/dist/modules/processes/registry.js +0 -327
  142. package/dist/modules/processes/runner.js +0 -23
  143. package/dist/modules/providers/create.js +0 -22
  144. package/dist/modules/providers/fallback.js +0 -79
  145. package/dist/modules/providers/health.js +0 -46
  146. package/dist/modules/providers/index.js +0 -5
  147. package/dist/modules/providers/manager.js +0 -161
  148. package/dist/modules/providers/presets.js +0 -128
  149. package/dist/modules/providers/registry.js +0 -22
  150. package/dist/modules/providers/types.js +0 -1
  151. package/dist/modules/registry.js +0 -48
  152. package/dist/modules/security/audit-log.js +0 -136
  153. package/dist/modules/security/audit-notifier.js +0 -292
  154. package/dist/modules/security/command-validator.js +0 -219
  155. package/dist/modules/security/content-scanner.js +0 -53
  156. package/dist/modules/security/data-sanitizer.js +0 -89
  157. package/dist/modules/security/encryption.js +0 -242
  158. package/dist/modules/security/index.js +0 -14
  159. package/dist/modules/security/network-validator.js +0 -88
  160. package/dist/modules/security/path-validator.js +0 -203
  161. package/dist/modules/security/rate-limiter.js +0 -119
  162. package/dist/modules/security/security-policies.js +0 -531
  163. package/dist/modules/security/session-encryption.js +0 -210
  164. package/dist/modules/security/session-isolation.js +0 -95
  165. package/dist/modules/session/index.js +0 -3
  166. package/dist/modules/session/manager.js +0 -172
  167. package/dist/modules/session/module.js +0 -24
  168. package/dist/modules/session/store.js +0 -222
  169. package/dist/modules/session/types.js +0 -1
  170. package/dist/modules/skills/index.js +0 -2
  171. package/dist/modules/skills/loader.js +0 -72
  172. package/dist/modules/skills/matcher.js +0 -27
  173. package/dist/modules/skills/module.js +0 -129
  174. package/dist/modules/types.js +0 -1
  175. package/dist/modules/updater/checker.js +0 -96
  176. package/dist/modules/updater/index.js +0 -2
  177. package/dist/modules/updater/module.js +0 -116
  178. package/dist/modules/user-profile/compressor.js +0 -16
  179. package/dist/modules/user-profile/index.js +0 -1
  180. package/dist/modules/user-profile/profile.js +0 -68
  181. package/dist/tools/approve.js +0 -33
  182. package/dist/tools/attach-image.js +0 -101
  183. package/dist/tools/bash.js +0 -519
  184. package/dist/tools/browser.js +0 -115
  185. package/dist/tools/chunk-query.js +0 -100
  186. package/dist/tools/create-dir.js +0 -56
  187. package/dist/tools/delete-file.js +0 -63
  188. package/dist/tools/download-file.js +0 -117
  189. package/dist/tools/edit-file.js +0 -80
  190. package/dist/tools/enable-tools.js +0 -59
  191. package/dist/tools/executor.js +0 -154
  192. package/dist/tools/file-info.js +0 -47
  193. package/dist/tools/filter-tools.js +0 -17
  194. package/dist/tools/glob-tool.js +0 -27
  195. package/dist/tools/grep-tool.js +0 -125
  196. package/dist/tools/hidden-tools-block.js +0 -37
  197. package/dist/tools/index.js +0 -78
  198. package/dist/tools/list-dir.js +0 -49
  199. package/dist/tools/load-skill.js +0 -43
  200. package/dist/tools/mcp-call.js +0 -69
  201. package/dist/tools/move-file.js +0 -86
  202. package/dist/tools/path-utils.js +0 -101
  203. package/dist/tools/pipeline-run.js +0 -145
  204. package/dist/tools/preview.js +0 -2
  205. package/dist/tools/process-kill.js +0 -40
  206. package/dist/tools/process-list.js +0 -37
  207. package/dist/tools/process-log.js +0 -54
  208. package/dist/tools/question.js +0 -141
  209. package/dist/tools/read-file.js +0 -179
  210. package/dist/tools/recall.js +0 -118
  211. package/dist/tools/registry.js +0 -47
  212. package/dist/tools/remember.js +0 -68
  213. package/dist/tools/scope-check.js +0 -32
  214. package/dist/tools/search-history.js +0 -85
  215. package/dist/tools/subagent.js +0 -196
  216. package/dist/tools/types.js +0 -1
  217. package/dist/tools/user-input.js +0 -123
  218. package/dist/tools/web-browse.js +0 -87
  219. package/dist/tools/web-fetch.js +0 -119
  220. package/dist/tools/web-search.js +0 -105
  221. package/dist/tools/write-file.js +0 -82
  222. package/dist/ui/box.js +0 -77
  223. package/dist/ui/colors.js +0 -4
  224. package/dist/ui/diff.js +0 -178
  225. package/dist/ui/index.js +0 -6
  226. package/dist/ui/line-editor.js +0 -822
  227. package/dist/ui/line-math.js +0 -73
  228. package/dist/ui/md-formatter.js +0 -212
  229. package/dist/ui/output.js +0 -13
  230. package/dist/ui/plan-view.js +0 -103
  231. package/dist/ui/renderer.js +0 -259
  232. package/dist/ui/spinner.js +0 -70
  233. package/dist/ui/table.js +0 -144
package/dist/main.js CHANGED
@@ -2492,6 +2492,16 @@ The path was joined onto the working directory because it does not exist as give
2492
2492
  "env.playwright_missing": "Playwright package is not installed — the browser tool will fail. Install with: bun add playwright",
2493
2493
  "env.playwright_browsers_missing": "Playwright browsers not downloaded ({dir}). The browser tool will fail. Install with: bunx playwright install chromium",
2494
2494
  "env.crash_stderr": "MMA crashed ({type}): {message} — crash report written to ~/.mma/logs/crash.jsonl",
2495
+ "env.model_autoload_failed": "Model auto-load failed: {error}. Continuing with manual load.",
2496
+ "env.model_loaded": "Model {model} loaded in {seconds}s",
2497
+ "env.reasoning_probe": "Reasoning probe: strategy={strategy} → {result}",
2498
+ "env.reasoning_respected": "mechanism respected",
2499
+ "env.reasoning_ignored": "mechanism IGNORED",
2500
+ "env.indexing": "Indexing project files…",
2501
+ "env.indexed": "Indexed {files} file(s) for the project map",
2502
+ "env.indexing_failed": "Project indexing failed: {error}",
2503
+ "env.index_skip_unreadable": 'indexer: skipping unreadable entry "{path}"',
2504
+ "env.killed_processes": "Killed {count} background process(es) on shutdown",
2495
2505
  "session.started": "Session started: {id}",
2496
2506
  "session.ended": "Session ended: {id}",
2497
2507
  "session.not_found": "Session not found: {id}",
@@ -2511,7 +2521,7 @@ The path was joined onto the working directory because it does not exist as give
2511
2521
  "session.available": "Available sessions:",
2512
2522
  "session.no_match": 'No session matching "{query}"',
2513
2523
  "session.default_name": "Session {date}",
2514
- "session.info": '[Session: "{name}" ({id}) {count} messages so far]',
2524
+ "session.info_full": '[Session: "{name}" ({id}) | model: {model} | context: {contextWindow} tokens]',
2515
2525
  "session.col_active": "",
2516
2526
  "session.col_id": "ID",
2517
2527
  "session.col_name": "Name",
@@ -3191,7 +3201,31 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
3191
3201
  "moe.cycles_exhausted": "Max re-plan cycles ({max}) reached — returning partial results",
3192
3202
  "moe.partial_result": "Partial result",
3193
3203
  "moe.scope_approved": '🔓 Scope expanded for "{subtask}": {files}',
3194
- "moe.scope_rejected": '⛔ Scope request rejected for "{subtask}"'
3204
+ "moe.scope_rejected": '⛔ Scope request rejected for "{subtask}"',
3205
+ "prompt.overflow.compressing": "System prompt overflow: compressing {count} block(s) before the first run — this may take a while on a local model.",
3206
+ "prompt.overflow.summarizing": 'System prompt overflow: summarizing "{label}" ({original} tok → {budget} tok budget) with the model…',
3207
+ "prompt.overflow.truncating": 'System prompt overflow: truncating "{label}" ({original} tok) — summarization unavailable.',
3208
+ "prompt.overflow.summarize_failed": 'System prompt overflow: summarization failed for "{label}": {error} — falling back to truncation.',
3209
+ "prompt.overflow.exceeded": 'Prompt overflow: "{label}" ({original} tok) exceeded the system-prompt budget ({budget} tok) — {mode} to {resolved} tok. To fit fully, {hint}.',
3210
+ "prompt.overflow.failed": "Prompt overflow resolution failed: {error} — oversized blocks will be dropped.",
3211
+ "prompt.overflow.startup": "Startup check: {block} ({original} tok) exceeds the system-prompt budget ({budget} tok) — it will be summarized/truncated before the first run. To include it fully, {hint}.",
3212
+ "tool.session_info.no_active": "No active session",
3213
+ "tool.session_info.result": `Session: "{name}" ({id})
3214
+ Model: {model}
3215
+ Provider: {provider}
3216
+ Context window: {contextWindow} tokens
3217
+ Messages: {messages}
3218
+ Created: {createdAt}
3219
+ Updated: {updatedAt}`,
3220
+ "tool.session_info.context": "Context used: {used} / {budget} tokens ({percent}%)",
3221
+ "tool.friendly.session_info": "Session info",
3222
+ "cli.map.description": "Work with the project index / map",
3223
+ "cli.map.action": "Action: summary (default), refresh, find",
3224
+ "cli.map.query": "Search query for the find action",
3225
+ "repl.map": "Show the project map / index (summary, refresh, find)",
3226
+ "repl.map_usage": "Usage: /map [summary|refresh|find <query>]",
3227
+ "map.refreshed": "Project map refreshed",
3228
+ "map.find_usage": "Usage: map find <query>"
3195
3229
  };
3196
3230
  });
3197
3231
 
@@ -3262,6 +3296,16 @@ var init_ru = __esm(() => {
3262
3296
  "env.playwright_missing": "Пакет Playwright не установлен — браузерный инструмент не будет работать. Установите: bun add playwright",
3263
3297
  "env.playwright_browsers_missing": "Браузеры Playwright не скачаны ({dir}). Браузерный инструмент не будет работать. Установите: bunx playwright install chromium",
3264
3298
  "env.crash_stderr": "MMA упал ({type}): {message} — отчёт о падении записан в ~/.mma/logs/crash.jsonl",
3299
+ "env.model_autoload_failed": "Не удалось автоматически загрузить модель: {error}. Продолжаю с ручной загрузкой.",
3300
+ "env.model_loaded": "Модель {model} загружена за {seconds}с",
3301
+ "env.reasoning_probe": "Проверка reasoning: стратегия={strategy} → {result}",
3302
+ "env.reasoning_respected": "механизм соблюдается",
3303
+ "env.reasoning_ignored": "механизм ИГНОРИРУЕТСЯ",
3304
+ "env.indexing": "Индексация файлов проекта…",
3305
+ "env.indexed": "Проиндексировано файлов: {files} (карта проекта)",
3306
+ "env.indexing_failed": "Ошибка индексации проекта: {error}",
3307
+ "env.index_skip_unreadable": 'индексатор: пропускаю недоступный файл "{path}"',
3308
+ "env.killed_processes": "Остановлено фоновых процессов при завершении: {count}",
3265
3309
  "session.started": "Сессия начата: {id}",
3266
3310
  "session.ended": "Сессия завершена: {id}",
3267
3311
  "session.not_found": "Сессия не найдена: {id}",
@@ -3281,7 +3325,7 @@ var init_ru = __esm(() => {
3281
3325
  "session.available": "Доступные сессии:",
3282
3326
  "session.no_match": 'Нет сессии подходящей по "{query}"',
3283
3327
  "session.default_name": "Сессия {date}",
3284
- "session.info": '[Сессия: "{name}" ({id}) {count} сообщений]',
3328
+ "session.info_full": '[Сессия: "{name}" ({id}) | модель: {model} | контекст: {contextWindow} токенов]',
3285
3329
  "session.col_active": "",
3286
3330
  "session.col_id": "ID",
3287
3331
  "session.col_name": "Имя",
@@ -3963,7 +4007,31 @@ var init_ru = __esm(() => {
3963
4007
  "moe.cycles_exhausted": "Достигнут лимит re-plan циклов ({max}) — возвращаю частичные результаты",
3964
4008
  "moe.partial_result": "Частичный результат",
3965
4009
  "moe.scope_approved": '🔓 Scope расширен для "{subtask}": {files}',
3966
- "moe.scope_rejected": '⛔ Запрос scope отклонён для "{subtask}"'
4010
+ "moe.scope_rejected": '⛔ Запрос scope отклонён для "{subtask}"',
4011
+ "prompt.overflow.compressing": "Переполнение системного промпта: сжимаю {count} блок(ов) перед первым запуском — на локальной модели это может занять время.",
4012
+ "prompt.overflow.summarizing": 'Переполнение системного промпта: суммаризирую "{label}" ({original} токенов → бюджет {budget} токенов) моделью…',
4013
+ "prompt.overflow.truncating": 'Переполнение системного промпта: обрезаю "{label}" ({original} токенов) — суммаризация недоступна.',
4014
+ "prompt.overflow.summarize_failed": 'Переполнение системного промпта: не удалось суммаризировать "{label}": {error} — перехожу к обрезке.',
4015
+ "prompt.overflow.exceeded": 'Промпт переполнен: "{label}" ({original} токенов) превысил бюджет системного промпта ({budget} токенов) — {mode} до {resolved} токенов. Чтобы включить полностью, {hint}.',
4016
+ "prompt.overflow.failed": "Не удалось разрешить переполнение промпта: {error} — слишком большие блоки будут отброшены.",
4017
+ "prompt.overflow.startup": "Проверка при старте: {block} ({original} токенов) превышает бюджет системного промпта ({budget} токенов) — будет суммаризован/обрезан перед первым запуском. Чтобы включить полностью, {hint}.",
4018
+ "tool.session_info.no_active": "Нет активной сессии",
4019
+ "tool.session_info.result": `Сессия: "{name}" ({id})
4020
+ Модель: {model}
4021
+ Провайдер: {provider}
4022
+ Контекстное окно: {contextWindow} токенов
4023
+ Сообщений: {messages}
4024
+ Создана: {createdAt}
4025
+ Обновлена: {updatedAt}`,
4026
+ "tool.session_info.context": "Использовано контекста: {used} / {budget} токенов ({percent}%)",
4027
+ "tool.friendly.session_info": "Информация о сессии",
4028
+ "cli.map.description": "Работа с индексом / картой проекта",
4029
+ "cli.map.action": "Действие: summary (по умолчанию), refresh, find",
4030
+ "cli.map.query": "Поисковый запрос для действия find",
4031
+ "repl.map": "Показать карту проекта / индекс (summary, refresh, find)",
4032
+ "repl.map_usage": "Использование: /map [summary|refresh|find <запрос>]",
4033
+ "map.refreshed": "Карта проекта обновлена",
4034
+ "map.find_usage": "Использование: map find <запрос>"
3967
4035
  };
3968
4036
  });
3969
4037
 
@@ -14589,6 +14657,9 @@ async function resolvePromptOverflow(opts) {
14589
14657
  const warnings = [];
14590
14658
  let used = includedTokens;
14591
14659
  let unresolved = [];
14660
+ if (sorted.length > 0) {
14661
+ logger?.warn(t("prompt.overflow.compressing", { count: String(sorted.length) }));
14662
+ }
14592
14663
  for (const block of sorted) {
14593
14664
  const kind = block.kind;
14594
14665
  const maxTokens = systemBudget - used - HINT_BLOCK_TOKENS;
@@ -14606,6 +14677,11 @@ async function resolvePromptOverflow(opts) {
14606
14677
  logger?.debug(`Prompt overflow: cache hit for ${kind} (${key}, ${mode})`);
14607
14678
  } else if (provider) {
14608
14679
  const targetChars = Math.floor(maxTokens * (CHARS_PER_TOKEN - 1));
14680
+ logger?.warn(t("prompt.overflow.summarizing", {
14681
+ label: blockLabel2(block.content),
14682
+ original: String(block.estimatedTokens),
14683
+ budget: String(maxTokens)
14684
+ }));
14609
14685
  try {
14610
14686
  const prompt = [
14611
14687
  `Summarize the following ${KIND_LABEL[kind]} document.`,
@@ -14635,12 +14711,19 @@ async function resolvePromptOverflow(opts) {
14635
14711
  `), maxTokens);
14636
14712
  }
14637
14713
  } catch (err) {
14638
- logger?.warn(`Prompt overflow: summarization failed for ${kind}: ${err?.message ?? err}`);
14714
+ logger?.warn(t("prompt.overflow.summarize_failed", {
14715
+ label: blockLabel2(block.content),
14716
+ error: String(err?.message ?? err)
14717
+ }));
14639
14718
  text = "";
14640
14719
  }
14641
14720
  }
14642
14721
  if (!text) {
14643
14722
  mode = "truncate";
14723
+ logger?.warn(t("prompt.overflow.truncating", {
14724
+ label: blockLabel2(block.content),
14725
+ original: String(block.estimatedTokens)
14726
+ }));
14644
14727
  text = truncateToTokens(block.content, maxTokens);
14645
14728
  }
14646
14729
  if (estimateTokens(text) > maxTokens) {
@@ -14705,6 +14788,7 @@ var HINT_BLOCK_TOKENS = 60, CHARS_PER_TOKEN = 4, KIND_ORDER, KIND_LABEL, KIND_SO
14705
14788
  var init_prompt_overflow = __esm(() => {
14706
14789
  init_prompt_builder();
14707
14790
  init_token_counter();
14791
+ init_i18n();
14708
14792
  KIND_ORDER = ["instructions", "project-map"];
14709
14793
  KIND_LABEL = {
14710
14794
  instructions: "project instructions (AGENTS.md)",
@@ -14883,7 +14967,14 @@ class Agent {
14883
14967
  const recommended = recommendContextSize(dry.blocks.filter((b) => b.included).reduce((s, b) => s + b.tokens, 0) + overflow.reduce((s, b) => s + b.estimatedTokens, 0) + HINT_BLOCK_TOKENS);
14884
14968
  const hint = this.deps.configDir ? contextWindowHint(cfg, this.deps.configDir, recommended) : `increase contextWindow (e.g. to ${recommended})`;
14885
14969
  for (const w of res.warnings) {
14886
- this.deps.logger.warn(`Prompt overflow: "${w.label}" (${w.originalTokens} tok) exceeded the system-prompt budget (${systemBudget} tok) — ${w.mode === "summary" ? "summarized" : "truncated"} to ${w.resolvedTokens} tok. To fit fully, ${hint}.`);
14970
+ this.deps.logger.warn(t("prompt.overflow.exceeded", {
14971
+ label: w.label,
14972
+ original: String(w.originalTokens),
14973
+ budget: String(systemBudget),
14974
+ mode: w.mode === "summary" ? "summarized" : "truncated",
14975
+ resolved: String(w.resolvedTokens),
14976
+ hint
14977
+ }));
14887
14978
  }
14888
14979
  }
14889
14980
  refreshSystemPrompt() {
@@ -14933,7 +15024,7 @@ class Agent {
14933
15024
  try {
14934
15025
  await this.resolvePromptOverflowOnce();
14935
15026
  } catch (err) {
14936
- this.deps.logger.warn(`Prompt overflow resolution failed: ${err?.message ?? err} — oversized blocks will be dropped.`);
15027
+ this.deps.logger.warn(t("prompt.overflow.failed", { error: String(err?.message ?? err) }));
14937
15028
  }
14938
15029
  }
14939
15030
  if (this.deps.reasoningProbe) {
@@ -15436,7 +15527,7 @@ class Agent {
15436
15527
  contextManager.onCompact = null;
15437
15528
  const killed = processRegistry.killAll();
15438
15529
  if (killed > 0) {
15439
- logger.info(`Killed ${killed} background process(es) on shutdown`);
15530
+ logger.info(t("env.killed_processes", { count: String(killed) }));
15440
15531
  }
15441
15532
  pluginManager.runOnSessionEnd({
15442
15533
  logger,
@@ -20218,6 +20309,56 @@ var init_enable_tools = __esm(() => {
20218
20309
  };
20219
20310
  });
20220
20311
 
20312
+ // src/tools/session-info.ts
20313
+ var sessionInfoTool;
20314
+ var init_session_info = __esm(() => {
20315
+ init_i18n();
20316
+ sessionInfoTool = {
20317
+ name: "session_info",
20318
+ icon: "ℹ️",
20319
+ description: "Show metadata about the current session: id, name, model, provider, context window, message count, and how much of the context budget is used. Use when the user asks which session this is or how much context is left.",
20320
+ alwaysOn: true,
20321
+ boundedOutput: true,
20322
+ parameters: {
20323
+ type: "object",
20324
+ properties: {}
20325
+ },
20326
+ handler: async (ctx) => {
20327
+ const meta = ctx.sessionManager?.getActiveMeta();
20328
+ if (!meta) {
20329
+ return { success: true, output: t("tool.session_info.no_active") };
20330
+ }
20331
+ const provider = ctx.config.provider;
20332
+ const providerName = provider.active ?? provider.type ?? "unknown";
20333
+ const lines = [
20334
+ t("tool.session_info.result", {
20335
+ id: meta.id,
20336
+ name: meta.name,
20337
+ model: meta.model ?? ctx.config.model ?? "unknown",
20338
+ provider: providerName,
20339
+ contextWindow: String(meta.contextWindow ?? ctx.config.contextWindow),
20340
+ messages: String(meta.messageCount),
20341
+ createdAt: meta.createdAt,
20342
+ updatedAt: meta.updatedAt
20343
+ })
20344
+ ];
20345
+ const snapshot = ctx.contextManager?.getSnapshot();
20346
+ if (snapshot) {
20347
+ const used = snapshot.tokens;
20348
+ const budget = snapshot.budget.history;
20349
+ const percent = budget > 0 ? Math.round(used / budget * 100) : 0;
20350
+ lines.push(t("tool.session_info.context", {
20351
+ used: String(used),
20352
+ budget: String(budget),
20353
+ percent: String(percent)
20354
+ }));
20355
+ }
20356
+ return { success: true, output: lines.join(`
20357
+ `) };
20358
+ }
20359
+ };
20360
+ });
20361
+
20221
20362
  // src/tools/index.ts
20222
20363
  function registerAllTools(registry2, skillsModule, opts) {
20223
20364
  const tools = [
@@ -20244,7 +20385,8 @@ function registerAllTools(registry2, skillsModule, opts) {
20244
20385
  pipelineRunTool,
20245
20386
  mcpCallTool,
20246
20387
  searchHistoryTool,
20247
- attachImageTool
20388
+ attachImageTool,
20389
+ sessionInfoTool
20248
20390
  ];
20249
20391
  if (opts?.enableOnDemand !== false) {
20250
20392
  tools.push(enableToolsTool);
@@ -20287,6 +20429,7 @@ var init_tools = __esm(() => {
20287
20429
  init_browser();
20288
20430
  init_attach_image();
20289
20431
  init_enable_tools();
20432
+ init_session_info();
20290
20433
  });
20291
20434
 
20292
20435
  // src/tools/hidden-tools-block.ts
@@ -23398,13 +23541,18 @@ class SessionModule {
23398
23541
  }
23399
23542
  getSystemPromptBlock() {
23400
23543
  const meta = this.manager.getActiveMeta();
23401
- if (!meta || meta.messageCount === 0)
23544
+ if (!meta)
23402
23545
  return null;
23403
23546
  return {
23404
- content: t("session.info", { name: meta.name, id: meta.id, count: meta.messageCount }),
23547
+ content: t("session.info_full", {
23548
+ name: meta.name,
23549
+ id: meta.id,
23550
+ model: meta.model,
23551
+ contextWindow: meta.contextWindow
23552
+ }),
23405
23553
  priority: "low",
23406
23554
  essential: false,
23407
- estimatedTokens: 20
23555
+ estimatedTokens: 30
23408
23556
  };
23409
23557
  }
23410
23558
  getPlugin() {
@@ -24582,9 +24730,186 @@ var init_startup_check = __esm(() => {
24582
24730
  init_utils();
24583
24731
  });
24584
24732
 
24733
+ // src/modules/indexer/symbols.ts
24734
+ function dedupe2(names) {
24735
+ const seen = new Set;
24736
+ const out = [];
24737
+ for (const name of names) {
24738
+ if (name && !seen.has(name)) {
24739
+ seen.add(name);
24740
+ out.push(name);
24741
+ }
24742
+ }
24743
+ return out;
24744
+ }
24745
+ function collect(content, patterns) {
24746
+ const names = [];
24747
+ for (const re of patterns) {
24748
+ re.lastIndex = 0;
24749
+ let match;
24750
+ while ((match = re.exec(content)) !== null) {
24751
+ if (match[1])
24752
+ names.push(match[1]);
24753
+ if (match.index === re.lastIndex)
24754
+ re.lastIndex++;
24755
+ }
24756
+ }
24757
+ return names;
24758
+ }
24759
+ function collectExportClauses(content) {
24760
+ const names = [];
24761
+ const re = /export\s+(?:type\s+)?\{([^}]*)\}/g;
24762
+ let match;
24763
+ while ((match = re.exec(content)) !== null) {
24764
+ for (const part of match[1].split(",")) {
24765
+ const cleaned = part.trim().replace(/^type\s+/, "");
24766
+ if (!cleaned || cleaned.startsWith("//"))
24767
+ continue;
24768
+ const alias = cleaned.split(/\s+as\s+/);
24769
+ const exported = (alias.length > 1 ? alias[1] : alias[0]).trim();
24770
+ if (/^\w+$/.test(exported))
24771
+ names.push(exported);
24772
+ }
24773
+ }
24774
+ return names;
24775
+ }
24776
+ function tsLike(content) {
24777
+ return dedupe2([...collect(content, TS_JS_PATTERNS), ...collectExportClauses(content)]);
24778
+ }
24779
+ function languageIdForExt(ext) {
24780
+ return EXT_TO_LANGUAGE[ext.toLowerCase()] ?? null;
24781
+ }
24782
+ function isCodeLanguage(languageId) {
24783
+ return RULES[languageId]?.code ?? false;
24784
+ }
24785
+ function extractSymbols(content, languageId) {
24786
+ const rule = RULES[languageId];
24787
+ if (!rule)
24788
+ return [];
24789
+ return dedupe2(rule.extract(content)).slice(0, MAX_SYMBOLS_PER_FILE);
24790
+ }
24791
+ var MAX_SYMBOLS_PER_FILE = 40, TS_JS_PATTERNS, PYTHON_PATTERNS, RUST_PATTERNS, GO_PATTERNS, JAVA_PATTERNS, KOTLIN_PATTERNS, CSHARP_PATTERNS, RUBY_PATTERNS, PHP_PATTERNS, SWIFT_PATTERNS, SCALA_PATTERNS, C_CPP_PATTERNS, SHELL_PATTERNS, LUA_PATTERNS, NO_SYMBOLS = () => [], RULES, EXT_TO_LANGUAGE;
24792
+ var init_symbols = __esm(() => {
24793
+ TS_JS_PATTERNS = [
24794
+ /^export\s+(?:default\s+)?(?:declare\s+)?(?:abstract\s+)?(?:async\s+)?(?:const|let|var|function|class|interface|type|enum)\s+(\w+)/gm,
24795
+ /^export\s+default\s+(?:class|function)\s+(\w+)/gm
24796
+ ];
24797
+ PYTHON_PATTERNS = [/^(?:async\s+)?def\s+(\w+)/gm, /^class\s+(\w+)/gm];
24798
+ RUST_PATTERNS = [
24799
+ /^\s*pub(?:\([^)]*\))?\s+(?:async\s+)?(?:unsafe\s+)?(?:fn|struct|enum|trait|const|static|type|mod)\s+(\w+)/gm,
24800
+ /macro_rules!\s+(\w+)/g
24801
+ ];
24802
+ GO_PATTERNS = [
24803
+ /^func\s+(\w+)\s*[([]/gm,
24804
+ /^func\s+\([^)]*\)\s+(\w+)\s*[([]/gm,
24805
+ /^type\s+(\w+)/gm,
24806
+ /^(?:var|const)\s+(\w+)/gm
24807
+ ];
24808
+ JAVA_PATTERNS = [
24809
+ /^\s*(?:(?:public|protected|private|final|abstract|static|sealed|non-sealed|strictfp)\s+)*(?:class|interface|enum|record)\s+(\w+)/gm
24810
+ ];
24811
+ KOTLIN_PATTERNS = [
24812
+ /^\s*(?:(?:public|internal|private|protected|open|abstract|sealed|data|enum|annotation|value|inline)\s+)*(?:class|interface|object)\s+(\w+)/gm,
24813
+ /^\s*(?:(?:public|internal|private|protected|open|override|suspend|inline|operator|infix|tailrec|external)\s+)*fun\s+(\w+)/gm
24814
+ ];
24815
+ CSHARP_PATTERNS = [
24816
+ /^\s*(?:(?:public|internal|private|protected|static|sealed|abstract|partial|readonly|unsafe|new|record)\s+)*(?:class|interface|struct|enum|record)\s+(\w+)/gm
24817
+ ];
24818
+ RUBY_PATTERNS = [/^\s*(?:def|class|module)\s+([A-Za-z_]\w*[?!]?)/gm];
24819
+ PHP_PATTERNS = [/\b(?:function|class|interface|trait|enum)\s+(\w+)/g];
24820
+ SWIFT_PATTERNS = [/\b(?:func|class|struct|enum|protocol|extension)\s+(\w+)/g];
24821
+ SCALA_PATTERNS = [
24822
+ /^\s*(?:(?:private|protected|final|abstract|sealed|implicit|lazy|override)\s+)*(?:def|class|object|trait)\s+(\w+)/gm
24823
+ ];
24824
+ C_CPP_PATTERNS = [
24825
+ /^\s*(?:typedef\s+)?(?:class|struct|enum|union|namespace)\s+(\w+)/gm,
24826
+ /\}\s*(\w+)\s*;/g
24827
+ ];
24828
+ SHELL_PATTERNS = [/^\s*(?:function\s+)?(\w+)\s*\(\s*\)\s*\{/gm];
24829
+ LUA_PATTERNS = [/^\s*(?:local\s+)?function\s+([\w.:]+)/gm];
24830
+ RULES = {
24831
+ typescript: { code: true, extract: tsLike },
24832
+ "typescript-react": { code: true, extract: tsLike },
24833
+ javascript: { code: true, extract: tsLike },
24834
+ "javascript-react": { code: true, extract: tsLike },
24835
+ python: { code: true, extract: (c) => collect(c, PYTHON_PATTERNS) },
24836
+ rust: { code: true, extract: (c) => collect(c, RUST_PATTERNS) },
24837
+ go: { code: true, extract: (c) => collect(c, GO_PATTERNS) },
24838
+ java: { code: true, extract: (c) => collect(c, JAVA_PATTERNS) },
24839
+ kotlin: { code: true, extract: (c) => collect(c, KOTLIN_PATTERNS) },
24840
+ csharp: { code: true, extract: (c) => collect(c, CSHARP_PATTERNS) },
24841
+ ruby: { code: true, extract: (c) => collect(c, RUBY_PATTERNS) },
24842
+ php: { code: true, extract: (c) => collect(c, PHP_PATTERNS) },
24843
+ swift: { code: true, extract: (c) => collect(c, SWIFT_PATTERNS) },
24844
+ scala: { code: true, extract: (c) => collect(c, SCALA_PATTERNS) },
24845
+ c: { code: true, extract: (c) => collect(c, C_CPP_PATTERNS) },
24846
+ cpp: { code: true, extract: (c) => collect(c, C_CPP_PATTERNS) },
24847
+ shell: { code: true, extract: (c) => collect(c, SHELL_PATTERNS) },
24848
+ lua: { code: true, extract: (c) => collect(c, LUA_PATTERNS) },
24849
+ json: { code: false, extract: NO_SYMBOLS },
24850
+ markdown: { code: false, extract: NO_SYMBOLS },
24851
+ yaml: { code: false, extract: NO_SYMBOLS },
24852
+ toml: { code: false, extract: NO_SYMBOLS },
24853
+ xml: { code: false, extract: NO_SYMBOLS },
24854
+ html: { code: false, extract: NO_SYMBOLS },
24855
+ css: { code: false, extract: NO_SYMBOLS }
24856
+ };
24857
+ EXT_TO_LANGUAGE = {
24858
+ ".ts": "typescript",
24859
+ ".mts": "typescript",
24860
+ ".cts": "typescript",
24861
+ ".tsx": "typescript-react",
24862
+ ".js": "javascript",
24863
+ ".mjs": "javascript",
24864
+ ".cjs": "javascript",
24865
+ ".jsx": "javascript-react",
24866
+ ".py": "python",
24867
+ ".pyi": "python",
24868
+ ".rs": "rust",
24869
+ ".go": "go",
24870
+ ".java": "java",
24871
+ ".kt": "kotlin",
24872
+ ".kts": "kotlin",
24873
+ ".cs": "csharp",
24874
+ ".rb": "ruby",
24875
+ ".php": "php",
24876
+ ".swift": "swift",
24877
+ ".scala": "scala",
24878
+ ".c": "c",
24879
+ ".h": "c",
24880
+ ".cpp": "cpp",
24881
+ ".cc": "cpp",
24882
+ ".cxx": "cpp",
24883
+ ".hpp": "cpp",
24884
+ ".hxx": "cpp",
24885
+ ".sh": "shell",
24886
+ ".bash": "shell",
24887
+ ".zsh": "shell",
24888
+ ".lua": "lua",
24889
+ ".json": "json",
24890
+ ".md": "markdown",
24891
+ ".markdown": "markdown",
24892
+ ".yaml": "yaml",
24893
+ ".yml": "yaml",
24894
+ ".toml": "toml",
24895
+ ".xml": "xml",
24896
+ ".html": "html",
24897
+ ".htm": "html",
24898
+ ".css": "css",
24899
+ ".scss": "css",
24900
+ ".less": "css"
24901
+ };
24902
+ });
24903
+
24585
24904
  // src/modules/indexer/walker.ts
24586
24905
  import { readdirSync as readdirSync15, readFileSync as readFileSync27, statSync as statSync8, lstatSync, existsSync as existsSync45, watch } from "fs";
24587
24906
  import { join as join38, relative as relative6, extname as extname7 } from "path";
24907
+ function isIgnoredDirName(name) {
24908
+ return IGNORE_DIRS.has(name.toLowerCase());
24909
+ }
24910
+ function isIgnoredPath(filename) {
24911
+ return filename.split(/[\\/]/).some((segment) => isIgnoredDirName(segment));
24912
+ }
24588
24913
 
24589
24914
  class Indexer {
24590
24915
  baseDir;
@@ -24595,7 +24920,7 @@ class Indexer {
24595
24920
  }
24596
24921
  watch(callback) {
24597
24922
  this.watcher = watch(this.baseDir, { recursive: true }, (event, filename) => {
24598
- if (filename && !Array.from(IGNORE_DIRS).some((dir) => filename.includes(dir))) {
24923
+ if (filename && !isIgnoredPath(filename)) {
24599
24924
  callback(event, filename);
24600
24925
  }
24601
24926
  });
@@ -24630,22 +24955,22 @@ class Indexer {
24630
24955
  continue;
24631
24956
  const stat2 = statSync8(fullPath);
24632
24957
  if (stat2.isDirectory()) {
24633
- if (!IGNORE_DIRS.has(entry)) {
24958
+ if (!isIgnoredDirName(entry)) {
24634
24959
  walkDir2(fullPath);
24635
24960
  }
24636
24961
  } else if (stat2.isFile()) {
24637
24962
  const ext = extname7(entry).toLowerCase();
24638
- const language = LANGUAGES[ext];
24963
+ const language = languageIdForExt(ext);
24639
24964
  if (language) {
24640
24965
  const content = readFileSync27(fullPath, "utf-8");
24641
- const exports = this.extractExports(content, language);
24966
+ const exports = extractSymbols(content, language);
24642
24967
  files.push({ path: relPath, language, exports, size: stat2.size });
24643
24968
  totalSize += stat2.size;
24644
24969
  count++;
24645
24970
  }
24646
24971
  }
24647
24972
  } catch (e) {
24648
- logger2.warn(`indexer: skipping unreadable entry "${relPath}"`, { error: String(e) });
24973
+ logger2.warn(t("env.index_skip_unreadable", { path: relPath }), { error: String(e) });
24649
24974
  continue;
24650
24975
  }
24651
24976
  }
@@ -24653,18 +24978,6 @@ class Indexer {
24653
24978
  walkDir2(this.baseDir);
24654
24979
  return { files, totalSize };
24655
24980
  }
24656
- extractExports(content, language) {
24657
- if (language === "typescript" || language === "javascript") {
24658
- const exports = [];
24659
- const exportRegex = /export\s+(?:const|function|class|interface|type|enum|default\s+(?:class|function))\s+(\w+)/g;
24660
- let match;
24661
- while ((match = exportRegex.exec(content)) !== null) {
24662
- exports.push(match[1]);
24663
- }
24664
- return exports;
24665
- }
24666
- return [];
24667
- }
24668
24981
  summarize(result) {
24669
24982
  const byLang = {};
24670
24983
  for (const f of result.files) {
@@ -24674,24 +24987,48 @@ class Indexer {
24674
24987
  return `[Index: ${result.files.length} files, ${(result.totalSize / 1024).toFixed(1)}KB (${langs})]`;
24675
24988
  }
24676
24989
  }
24677
- var logger2, LANGUAGES, IGNORE_DIRS;
24990
+ var logger2, IGNORE_DIRS;
24678
24991
  var init_walker = __esm(() => {
24679
24992
  init_app_logger();
24993
+ init_symbols();
24994
+ init_i18n();
24680
24995
  logger2 = new Logger("warn", "indexer");
24681
- LANGUAGES = {
24682
- ".ts": "typescript",
24683
- ".tsx": "typescript-react",
24684
- ".js": "javascript",
24685
- ".jsx": "javascript-react",
24686
- ".json": "json",
24687
- ".md": "markdown",
24688
- ".yaml": "yaml",
24689
- ".yml": "yaml",
24690
- ".py": "python",
24691
- ".rs": "rust",
24692
- ".go": "go"
24693
- };
24694
- IGNORE_DIRS = new Set(["node_modules", ".git", "dist", "build", ".mma", "coverage"]);
24996
+ IGNORE_DIRS = new Set([
24997
+ ".git",
24998
+ ".hg",
24999
+ ".svn",
25000
+ ".mma",
25001
+ "node_modules",
25002
+ "dist",
25003
+ "build",
25004
+ "coverage",
25005
+ ".next",
25006
+ ".nuxt",
25007
+ ".svelte-kit",
25008
+ ".turbo",
25009
+ ".parcel-cache",
25010
+ ".cache",
25011
+ "venv",
25012
+ ".venv",
25013
+ "env",
25014
+ "virtualenv",
25015
+ "__pycache__",
25016
+ ".pytest_cache",
25017
+ ".mypy_cache",
25018
+ ".ruff_cache",
25019
+ ".tox",
25020
+ "site-packages",
25021
+ "target",
25022
+ "vendor",
25023
+ ".bundle",
25024
+ ".gradle",
25025
+ "out",
25026
+ "obj",
25027
+ "pods",
25028
+ "deriveddata",
25029
+ ".idea",
25030
+ ".vscode"
25031
+ ]);
24695
25032
  });
24696
25033
 
24697
25034
  // src/modules/indexer/cache.ts
@@ -24734,6 +25071,71 @@ class IndexCache {
24734
25071
  }
24735
25072
  var init_cache = () => {};
24736
25073
 
25074
+ // src/modules/indexer/map-select.ts
25075
+ function isNoiseFile(file) {
25076
+ const base = toForwardSlash(file.path).split("/").pop()?.toLowerCase() ?? "";
25077
+ return NOISE_BASENAMES.has(base);
25078
+ }
25079
+ function isTestFile(path) {
25080
+ return path.startsWith("test/") || path.startsWith("tests/") || path.includes("/test/") || path.includes("/tests/") || path.includes("__tests__/") || /\.(test|spec)\.[a-z0-9]+$/i.test(path);
25081
+ }
25082
+ function rank(file) {
25083
+ const path = toForwardSlash(file.path).toLowerCase();
25084
+ if (isTestFile(path))
25085
+ return 1;
25086
+ if (isCodeLanguage(file.language))
25087
+ return 0;
25088
+ return 2;
25089
+ }
25090
+ function topDir(path) {
25091
+ const normalized = toForwardSlash(path);
25092
+ const slash = normalized.indexOf("/");
25093
+ return slash >= 0 ? normalized.slice(0, slash) : normalized;
25094
+ }
25095
+ function codeCountByTopDir(files) {
25096
+ const counts = new Map;
25097
+ for (const file of files) {
25098
+ if (isNoiseFile(file) || rank(file) !== 0)
25099
+ continue;
25100
+ const dir = topDir(file.path);
25101
+ counts.set(dir, (counts.get(dir) ?? 0) + 1);
25102
+ }
25103
+ return counts;
25104
+ }
25105
+ function selectMapFiles(files, max) {
25106
+ const codeByDir = codeCountByTopDir(files);
25107
+ return files.filter((file) => !isNoiseFile(file)).sort((a, b) => {
25108
+ const rankDiff = rank(a) - rank(b);
25109
+ if (rankDiff !== 0)
25110
+ return rankDiff;
25111
+ const densityDiff = (codeByDir.get(topDir(b.path)) ?? 0) - (codeByDir.get(topDir(a.path)) ?? 0);
25112
+ if (densityDiff !== 0)
25113
+ return densityDiff;
25114
+ const pathA = toForwardSlash(a.path);
25115
+ const pathB = toForwardSlash(b.path);
25116
+ const depthDiff = pathA.split("/").length - pathB.split("/").length;
25117
+ if (depthDiff !== 0)
25118
+ return depthDiff;
25119
+ return pathA < pathB ? -1 : pathA > pathB ? 1 : 0;
25120
+ }).slice(0, max);
25121
+ }
25122
+ var NOISE_BASENAMES;
25123
+ var init_map_select = __esm(() => {
25124
+ init_path_utils();
25125
+ init_symbols();
25126
+ NOISE_BASENAMES = new Set([
25127
+ "package-lock.json",
25128
+ "bun.lock",
25129
+ "bun.lockb",
25130
+ "yarn.lock",
25131
+ "pnpm-lock.yaml",
25132
+ "cargo.lock",
25133
+ "go.sum",
25134
+ "composer.lock",
25135
+ "poetry.lock"
25136
+ ]);
25137
+ });
25138
+
24737
25139
  // src/modules/indexer/project-profile.ts
24738
25140
  import { readFileSync as readFileSync29, existsSync as existsSync47 } from "fs";
24739
25141
  import { join as join40 } from "path";
@@ -24948,6 +25350,22 @@ class IndexerModule {
24948
25350
  return path.includes(q) || f.exports.some((e) => e.toLowerCase().includes(q));
24949
25351
  });
24950
25352
  }
25353
+ formatFind(query) {
25354
+ const matches = this.find(query);
25355
+ if (matches.length === 0) {
25356
+ return t("indexer.no_matches", { query });
25357
+ }
25358
+ const lines = matches.map((f) => {
25359
+ const path = toForwardSlash(f.path);
25360
+ const exports = f.exports.length > 0 ? `: ${f.exports.join(", ")}` : "";
25361
+ return `- ${path}${exports}`;
25362
+ }).join(`
25363
+ `);
25364
+ return t("indexer.find_results", { count: matches.length, results: lines });
25365
+ }
25366
+ getPromptMap() {
25367
+ return this.index ? this.formatMap(this.index) : null;
25368
+ }
24951
25369
  watch() {
24952
25370
  this.unwatch();
24953
25371
  try {
@@ -25001,13 +25419,14 @@ class IndexerModule {
25001
25419
  const stackLine = buildProjectProfileLine(this.baseDir);
25002
25420
  const dirCounts = this.getDirectoryCounts(result);
25003
25421
  const topDirs = Object.entries(dirCounts).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([dir, count]) => `${dir} (${count})`).join(", ") || "-";
25004
- const fileLines = result.files.slice(0, 100).map((f) => {
25422
+ const listed = selectMapFiles(result.files, MAP_FILE_LIMIT);
25423
+ const fileLines = listed.map((f) => {
25005
25424
  const path = toForwardSlash(f.path);
25006
25425
  const exports = f.exports.length > 0 ? `: ${f.exports.join(", ")}` : "";
25007
25426
  return `- ${path}${exports}`;
25008
25427
  });
25009
- const more = result.files.length > 100 ? `
25010
- ${t("indexer.and_more", { count: result.files.length - 100 })}` : "";
25428
+ const more = result.files.length > listed.length ? `
25429
+ ${t("indexer.and_more", { count: result.files.length - listed.length })}` : "";
25011
25430
  const duplicates = this.findDuplicateBasenames(result);
25012
25431
  return [
25013
25432
  `${t("indexer.map_header")} (${this.baseDir})`,
@@ -25099,20 +25518,7 @@ ${stackLine2}` : summary2;
25099
25518
  const query = String(args.query || "").toLowerCase();
25100
25519
  if (!query)
25101
25520
  return { success: false, output: t("tool.invalid_params") };
25102
- const matches = this.find(query);
25103
- if (matches.length === 0) {
25104
- return this.makeResult(t("indexer.no_matches", { query }));
25105
- }
25106
- const lines = matches.map((f) => {
25107
- const path = toForwardSlash(f.path);
25108
- const exports = f.exports.length > 0 ? `: ${f.exports.join(", ")}` : "";
25109
- return `- ${path}${exports}`;
25110
- }).join(`
25111
- `);
25112
- return this.makeResult(t("indexer.find_results", {
25113
- count: matches.length,
25114
- results: lines
25115
- }));
25521
+ return this.makeResult(this.formatFind(query));
25116
25522
  }
25117
25523
  if (!this.index) {
25118
25524
  await this.buildIndex();
@@ -25132,9 +25538,11 @@ ${stackLine}` : summary;
25132
25538
  return { success: true, output, display: output };
25133
25539
  }
25134
25540
  }
25541
+ var MAP_FILE_LIMIT = 80;
25135
25542
  var init_module6 = __esm(() => {
25136
25543
  init_walker();
25137
25544
  init_cache();
25545
+ init_map_select();
25138
25546
  init_project_profile();
25139
25547
  init_i18n();
25140
25548
  init_path_utils();
@@ -26161,11 +26569,11 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26161
26569
  autoLoad: config.modelLoad.autoLoad
26162
26570
  });
26163
26571
  if (!loadResult.success) {
26164
- logger4.warn(`Model auto-load failed: ${loadResult.error}. Continuing with manual load.`);
26572
+ logger4.warn(t("env.model_autoload_failed", { error: String(loadResult.error ?? "") }));
26165
26573
  } else if (loadResult.alreadyLoaded) {
26166
26574
  logger4.debug(`Model ${config.model} already loaded`);
26167
26575
  } else {
26168
- logger4.info(`Model ${config.model} loaded in ${loadResult.loadTime}s`);
26576
+ logger4.info(t("env.model_loaded", { model: config.model, seconds: String(loadResult.loadTime) }));
26169
26577
  }
26170
26578
  }
26171
26579
  const contextProbePromise = (async () => {
@@ -26201,7 +26609,10 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26201
26609
  const passed = cached !== undefined ? cached : await probeReasoningSupport2(llmProvider, reasoningStrategy);
26202
26610
  if (cached === undefined && passed !== null)
26203
26611
  setCachedProbeResult2(cacheK, passed);
26204
- logger4.info(`Reasoning probe: strategy=${reasoningStrategy} → ${passed === true ? "mechanism respected" : "mechanism IGNORED"}`);
26612
+ logger4.info(t("env.reasoning_probe", {
26613
+ strategy: reasoningStrategy,
26614
+ result: passed === true ? t("env.reasoning_respected") : t("env.reasoning_ignored")
26615
+ }));
26205
26616
  return passed === true;
26206
26617
  } catch {
26207
26618
  return false;
@@ -26225,9 +26636,15 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26225
26636
  cacheDir: projectMapCacheDir
26226
26637
  });
26227
26638
  try {
26228
- await indexerModule.buildIndex();
26639
+ logger4.info(t("env.indexing"));
26640
+ const index = await indexerModule.buildIndex();
26641
+ if (index) {
26642
+ logger4.info(t("env.indexed", { files: String(index.files.length) }));
26643
+ } else {
26644
+ logger4.warn(t("env.indexing_failed", { error: "no index produced" }));
26645
+ }
26229
26646
  } catch (err) {
26230
- logger4.warn(`Project indexing failed: ${err.message}`);
26647
+ logger4.warn(t("env.indexing_failed", { error: String(err?.message ?? err) }));
26231
26648
  }
26232
26649
  const skillsLoader = new SkillsLoader;
26233
26650
  const builtinDir = join46(import.meta.dirname, "skills", "builtin");
@@ -26311,6 +26728,10 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26311
26728
  get: () => sessionManager.getSessionContext() ?? undefined,
26312
26729
  configurable: true
26313
26730
  });
26731
+ Object.defineProperty(toolCtx, "sessionManager", {
26732
+ get: () => sessionManager,
26733
+ configurable: true
26734
+ });
26314
26735
  const toolExecutor = new ToolExecutor(toolRegistry, toolCtx, pluginManager);
26315
26736
  toolCtx.llmProvider = llmProvider;
26316
26737
  toolCtx.toolExecutor = toolExecutor;
@@ -26385,7 +26806,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26385
26806
  const agentsMdBlocks = loadAgentsMdBlocks(baseDir, dir, noAgentsMd === true);
26386
26807
  const promptBlocks = [
26387
26808
  systemInfoPrompt,
26388
- ...moduleRegistry.collectPromptBlocks(["indexer"]),
26809
+ ...moduleRegistry.collectPromptBlocks(["indexer", "session"]),
26389
26810
  ...agentsMdBlocks,
26390
26811
  {
26391
26812
  content: "[Plan Reminder] An active plan may exist for this session. Before creating a new plan, check with `plan show`. If a plan is active, continue it — do NOT create a new plan.",
@@ -26418,7 +26839,12 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26418
26839
  const recommended = recommendContextSize(dry.includedTokens + overflowTokens);
26419
26840
  const hint = contextWindowHint(config, dir, recommended);
26420
26841
  for (const b of dry.overflow) {
26421
- logger4.warn(`Startup check: ${b.kind === "instructions" ? "AGENTS.md" : "project map"} (${b.estimatedTokens} tok) exceeds the system-prompt budget (${systemBudget} tok) — it will be summarized/truncated before the first run. To include it fully, ${hint}.`);
26842
+ logger4.warn(t("prompt.overflow.startup", {
26843
+ block: b.kind === "instructions" ? "AGENTS.md" : "project map",
26844
+ original: String(b.estimatedTokens),
26845
+ budget: String(systemBudget),
26846
+ hint
26847
+ }));
26422
26848
  }
26423
26849
  }
26424
26850
  }
@@ -26441,6 +26867,9 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete, reas
26441
26867
  const skillsBlock = skillsModule.getSystemPromptBlock();
26442
26868
  if (skillsBlock)
26443
26869
  blocks.push(skillsBlock);
26870
+ const sessionBlock = sessionModule.getSystemPromptBlock();
26871
+ if (sessionBlock)
26872
+ blocks.push(sessionBlock);
26444
26873
  const mapBlock = indexerModule.getSystemPromptBlock();
26445
26874
  if (mapBlock)
26446
26875
  blocks.push(mapBlock);
@@ -27278,6 +27707,41 @@ var init_setup = __esm(() => {
27278
27707
  ];
27279
27708
  });
27280
27709
 
27710
+ // src/modules/indexer/map-command.ts
27711
+ async function runMapAction(module, action, query) {
27712
+ const summary = async () => {
27713
+ const result = await module.buildIndex();
27714
+ if (!result)
27715
+ return { ok: false, output: t("indexer.not_indexed") };
27716
+ return { ok: true, output: module.getPromptMap() ?? t("indexer.not_indexed") };
27717
+ };
27718
+ switch (action) {
27719
+ case "refresh": {
27720
+ const result = await module.refresh();
27721
+ if (!result)
27722
+ return { ok: false, output: t("indexer.not_indexed") };
27723
+ return {
27724
+ ok: true,
27725
+ output: `${t("map.refreshed")}
27726
+ ${module.getPromptMap() ?? ""}`.trimEnd()
27727
+ };
27728
+ }
27729
+ case "find": {
27730
+ const q = (query ?? "").trim();
27731
+ if (!q)
27732
+ return { ok: false, output: t("map.find_usage") };
27733
+ await module.buildIndex();
27734
+ return { ok: true, output: module.formatFind(q) };
27735
+ }
27736
+ case "summary":
27737
+ default:
27738
+ return summary();
27739
+ }
27740
+ }
27741
+ var init_map_command = __esm(() => {
27742
+ init_i18n();
27743
+ });
27744
+
27281
27745
  // node_modules/yaml/dist/nodes/identity.js
27282
27746
  var require_identity = __commonJS((exports) => {
27283
27747
  var ALIAS = Symbol.for("yaml.alias");
@@ -35712,6 +36176,22 @@ function registerConfigCommands(ctx) {
35712
36176
  }
35713
36177
  }
35714
36178
  });
36179
+ ctx.registerCommand({
36180
+ name: "map",
36181
+ description: t("repl.map"),
36182
+ usage: t("repl.map_usage"),
36183
+ action: async (args) => {
36184
+ const indexer = ctx.agent.getModule("indexer");
36185
+ if (!indexer) {
36186
+ console.log(pc2.yellow(t("indexer.not_indexed")));
36187
+ return;
36188
+ }
36189
+ const action = args[0] || "summary";
36190
+ const query = args.slice(1).join(" ");
36191
+ const result = await runMapAction(indexer, action, query);
36192
+ console.log(result.output);
36193
+ }
36194
+ });
35715
36195
  }
35716
36196
  function registerProviderCommands(ctx) {
35717
36197
  ctx.registerCommand({
@@ -36216,6 +36696,7 @@ var init_repl_commands = __esm(() => {
36216
36696
  init_setup();
36217
36697
  init_config2();
36218
36698
  init_token_counter();
36699
+ init_map_command();
36219
36700
  init_utils();
36220
36701
  version2 = readMmaVersion();
36221
36702
  COMMAND_GROUPS = {
@@ -36233,6 +36714,7 @@ var init_repl_commands = __esm(() => {
36233
36714
  reload: "agent",
36234
36715
  wizard: "agent",
36235
36716
  sysprompt: "agent",
36717
+ map: "agent",
36236
36718
  lsp: "agent",
36237
36719
  sessions: "session",
36238
36720
  new: "session",
@@ -36943,6 +37425,7 @@ function targetsFromProviders(entries) {
36943
37425
 
36944
37426
  // src/cli/commands.ts
36945
37427
  init_version();
37428
+ init_map_command();
36946
37429
 
36947
37430
  // src/modules/updater/changelog-reader.ts
36948
37431
  import { readFileSync as readFileSync35, existsSync as existsSync53 } from "fs";
@@ -37216,6 +37699,18 @@ function buildContextCommand(program2) {
37216
37699
  console.log(t("cli.context_set", { size: contextWindow }));
37217
37700
  });
37218
37701
  }
37702
+ function buildMapCommand(program2) {
37703
+ program2.command("map").description(t("cli.map.description")).argument("[action]", t("cli.map.action"), "summary").argument("[query]", t("cli.map.query")).action(async (action, query) => {
37704
+ const { agent } = await bootstrap();
37705
+ const indexer = agent.getModule("indexer");
37706
+ if (!indexer) {
37707
+ console.log(t("indexer.not_indexed"));
37708
+ return;
37709
+ }
37710
+ const result = await runMapAction(indexer, action, query);
37711
+ console.log(result.output);
37712
+ });
37713
+ }
37219
37714
  function buildProviderCommands(program2) {
37220
37715
  const provider = program2.command("provider").description(t("cli.manage_providers"));
37221
37716
  provider.command("check").description(t("cli.provider_check")).option("--timeout <ms>", "Per-provider probe timeout in ms").action(async (opts) => {
@@ -37399,6 +37894,7 @@ function createProgram() {
37399
37894
  buildConfigCommands(program2);
37400
37895
  buildModelCommands(program2);
37401
37896
  buildContextCommand(program2);
37897
+ buildMapCommand(program2);
37402
37898
  buildProviderCommands(program2);
37403
37899
  buildSessionCommands(program2);
37404
37900
  createSecurityCommand(program2);
@@ -38901,8 +39397,8 @@ async function probeLspServers(config, baseDir, deps = {}) {
38901
39397
  const timeoutCap = deps.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
38902
39398
  const deadlineMs = deps.deadlineMs ?? DEFAULT_PROBE_DEADLINE_MS;
38903
39399
  const maxParallel = deps.maxParallel ?? DEFAULT_MAX_PARALLEL;
38904
- const collect = deps.collectFiles ?? collectCheckFiles;
38905
- const files = await collect(baseDir, config);
39400
+ const collect2 = deps.collectFiles ?? collectCheckFiles;
39401
+ const files = await collect2(baseDir, config);
38906
39402
  const seen = new Set;
38907
39403
  const servers = [];
38908
39404
  for (const file of files) {