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.
- package/bin/mma.mjs +41 -41
- package/dist/cli/commands.js +19 -9
- package/dist/cli/completer.js +37 -36
- package/dist/cli/index.js +2 -2
- package/dist/cli/main.js +23 -48
- package/dist/cli/repl-commands.js +12 -40
- package/dist/cli/repl.js +87 -217
- package/dist/cli/security-commands.js +7 -5
- package/dist/cli/setup.js +26 -8
- package/dist/config/config.js +5 -52
- package/dist/config/defaults.js +5 -29
- package/dist/config/experts.js +1 -1
- package/dist/config/index.js +3 -3
- package/dist/config/security.js +10 -3
- package/dist/core/agent-moe.js +10 -2
- package/dist/core/agent.js +82 -273
- package/dist/core/bootstrap.js +13 -80
- package/dist/core/index.js +2 -2
- package/dist/core/prompt-builder.js +2 -23
- package/dist/core/session-logger.js +4 -46
- package/dist/i18n/en.json +2 -75
- package/dist/i18n/ru.json +1 -74
- package/dist/index.js +1 -1
- package/dist/llm/image-utils.js +5 -4
- package/dist/llm/index.js +4 -4
- package/dist/llm/model-loader.js +6 -6
- package/dist/llm/openai-compat.js +34 -40
- package/dist/llm/orchestrator.js +29 -33
- package/dist/llm/response.js +9 -9
- package/dist/logger/app-logger.js +1 -1
- package/dist/logger/index.js +1 -1
- package/dist/main.js +648 -183
- package/dist/migration/backup.js +13 -13
- package/dist/migration/detect.js +11 -11
- package/dist/migration/index.js +2 -2
- package/dist/modules/browser/actions.js +4 -34
- package/dist/modules/browser/bridge-server.mjs +202 -202
- package/dist/modules/browser/cookie-store.js +6 -6
- package/dist/modules/browser/index.js +5 -7
- package/dist/modules/browser/module.js +7 -8
- package/dist/modules/browser/session.js +84 -87
- package/dist/modules/browser/snapshot.js +58 -92
- package/dist/modules/browser/types.js +1 -4
- package/dist/modules/certification/cli.js +4 -2
- package/dist/modules/certification/fact-checker.js +3 -1
- package/dist/modules/certification/loader.js +9 -3
- package/dist/modules/certification/runner.js +4 -1
- package/dist/modules/context/index.js +1 -1
- package/dist/modules/context/manager.js +86 -160
- package/dist/modules/execution/auditor.js +25 -177
- package/dist/modules/execution/module.js +544 -201
- package/dist/modules/execution/moe-executor.js +0 -25
- package/dist/modules/execution/plan-store.js +3 -1
- package/dist/modules/execution/plan-validator.js +10 -10
- package/dist/modules/execution/planner.js +1 -6
- package/dist/modules/execution/stuck-detector.js +10 -173
- package/dist/modules/execution/verifier.js +42 -86
- package/dist/modules/hallucination/confidence.js +1 -8
- package/dist/modules/hallucination/detector.js +5 -2
- package/dist/modules/hallucination/factual.js +64 -3
- package/dist/modules/hallucination/index.js +1 -1
- package/dist/modules/hallucination/js-identifiers.js +0 -190
- package/dist/modules/hallucination/llm-judge.js +3 -1
- package/dist/modules/indexer/cache.js +7 -9
- package/dist/modules/indexer/index.js +3 -3
- package/dist/modules/indexer/module.js +42 -95
- package/dist/modules/indexer/walker.js +17 -17
- package/dist/modules/lsp/client.js +31 -74
- package/dist/modules/lsp/config.js +33 -87
- package/dist/modules/lsp/index.js +3 -3
- package/dist/modules/lsp/module.js +21 -185
- package/dist/modules/mcp/module.js +6 -2
- package/dist/modules/memory/index.js +1 -1
- package/dist/modules/memory/module.js +23 -71
- package/dist/modules/memory/search.js +9 -11
- package/dist/modules/memory/store.js +13 -13
- package/dist/modules/pipelines/engine.js +10 -10
- package/dist/modules/pipelines/index.js +3 -3
- package/dist/modules/pipelines/parser.js +14 -17
- package/dist/modules/pipelines/template.js +1 -1
- package/dist/modules/plugins/builtin/lint-on-write.js +16 -21
- package/dist/modules/plugins/builtin/notify.js +2 -3
- package/dist/modules/plugins/index.js +1 -1
- package/dist/modules/plugins/loader.js +17 -59
- package/dist/modules/plugins/manager.js +17 -73
- package/dist/modules/processes/index.js +1 -1
- package/dist/modules/processes/registry.js +46 -135
- package/dist/modules/registry.js +2 -4
- package/dist/modules/security/audit-notifier.js +39 -39
- package/dist/modules/security/command-validator.js +8 -2
- package/dist/modules/security/data-sanitizer.js +9 -1
- package/dist/modules/security/encryption.js +56 -58
- package/dist/modules/security/network-validator.js +9 -1
- package/dist/modules/security/path-validator.js +3 -1
- package/dist/modules/security/security-policies.js +19 -3
- package/dist/modules/security/session-encryption.js +1 -1
- package/dist/modules/security/session-isolation.js +8 -8
- package/dist/modules/session/index.js +3 -3
- package/dist/modules/session/module.js +5 -5
- package/dist/modules/session/store.js +9 -3
- package/dist/modules/skills/module.js +2 -1
- package/dist/modules/updater/checker.js +6 -70
- package/dist/modules/updater/index.js +1 -2
- package/dist/modules/user-profile/compressor.js +2 -2
- package/dist/modules/user-profile/index.js +1 -1
- package/dist/modules/user-profile/profile.js +9 -9
- package/dist/tools/attach-image.js +1 -1
- package/dist/tools/bash.js +19 -178
- package/dist/tools/browser.js +29 -46
- package/dist/tools/executor.js +5 -4
- package/dist/tools/file-info.js +12 -13
- package/dist/tools/filter-tools.js +2 -9
- package/dist/tools/glob-tool.js +11 -11
- package/dist/tools/grep-tool.js +3 -1
- package/dist/tools/index.js +2 -13
- package/dist/tools/list-dir.js +17 -18
- package/dist/tools/load-skill.js +3 -1
- package/dist/tools/path-utils.js +4 -4
- package/dist/tools/pipeline-run.js +25 -25
- package/dist/tools/process-kill.js +11 -11
- package/dist/tools/process-list.js +22 -20
- package/dist/tools/process-log.js +18 -22
- package/dist/tools/question.js +3 -1
- package/dist/tools/read-file.js +2 -10
- package/dist/tools/recall.js +37 -44
- package/dist/tools/registry.js +4 -15
- package/dist/tools/remember.js +29 -29
- package/dist/tools/scope-check.js +9 -9
- package/dist/tools/subagent.js +9 -54
- package/dist/tools/user-input.js +1 -1
- package/dist/tools/web-browse.js +3 -3
- package/dist/tools/web-fetch.js +3 -3
- package/dist/tools/web-search.js +3 -3
- package/dist/tools/write-file.js +3 -1
- package/dist/ui/box.js +5 -1
- package/dist/ui/index.js +6 -6
- package/dist/ui/md-formatter.js +33 -33
- package/dist/ui/output.js +5 -5
- package/dist/ui/renderer.js +10 -15
- package/dist/ui/table.js +1 -1
- package/package.json +48 -48
- package/dist/cli/plugin-commands.js +0 -36
- package/dist/cli/run-result.js +0 -22
- package/dist/core/version.js +0 -24
- package/dist/modules/artifacts/store.js +0 -61
- package/dist/modules/browser/bridge-client.js +0 -199
- package/dist/modules/browser/bridge-path.js +0 -10
- package/dist/modules/browser/driver.js +0 -136
- package/dist/modules/context/chunk-query.js +0 -100
- package/dist/modules/context/fact-extractor.js +0 -162
- package/dist/modules/context/history.js +0 -15
- package/dist/modules/execution/audit-runners.js +0 -152
- package/dist/modules/execution/execution-plugin.js +0 -272
- package/dist/modules/execution/plan-tool.js +0 -508
- package/dist/modules/execution/windows-commands.js +0 -41
- package/dist/modules/indexer/project-profile.js +0 -183
- package/dist/modules/lsp/check-tool.js +0 -58
- package/dist/modules/lsp/command.js +0 -60
- package/dist/modules/lsp/probe.js +0 -76
- package/dist/modules/lsp/project-root.js +0 -32
- package/dist/modules/lsp/startup-check.js +0 -141
- package/dist/modules/processes/detect.js +0 -34
- package/dist/modules/skills/matcher.js +0 -27
- package/dist/modules/updater/module.js +0 -116
- package/dist/tools/chunk-query.js +0 -99
- package/dist/tools/download-file.js +0 -116
- package/dist/tools/enable-tools.js +0 -58
- package/dist/tools/hidden-tools-block.js +0 -37
- package/dist/ui/line-editor.js +0 -703
- package/dist/ui/line-math.js +0 -69
- package/dist/ui/plan-view.js +0 -103
package/dist/main.js
CHANGED
|
@@ -2287,6 +2287,17 @@ var init_defaults = __esm(() => {
|
|
|
2287
2287
|
viewportHeight: 720,
|
|
2288
2288
|
navigationTimeout: 15000
|
|
2289
2289
|
},
|
|
2290
|
+
webSearch: {
|
|
2291
|
+
enabled: true
|
|
2292
|
+
},
|
|
2293
|
+
errorWebSearch: {
|
|
2294
|
+
enabled: true,
|
|
2295
|
+
threshold: 5,
|
|
2296
|
+
maxResults: 5,
|
|
2297
|
+
maxQueryChars: 200,
|
|
2298
|
+
maxSearchesPerSession: 3,
|
|
2299
|
+
requestTimeoutMs: 1e4
|
|
2300
|
+
},
|
|
2290
2301
|
ui: {
|
|
2291
2302
|
spinner: true,
|
|
2292
2303
|
toolStyle: "inline",
|
|
@@ -2476,6 +2487,7 @@ Summary:
|
|
|
2476
2487
|
"tool.no_results": 'No results found for "{query}"',
|
|
2477
2488
|
"tool.search_results": `Search results for "{query}":
|
|
2478
2489
|
{results}`,
|
|
2490
|
+
"tool.web_search_disabled": "Web search is disabled (webSearch.enabled: false). Use file/system tools only.",
|
|
2479
2491
|
"tool.history_results": `History results for "{query}":
|
|
2480
2492
|
{results}`,
|
|
2481
2493
|
"tool.no_history": 'No history entries matching "{query}"',
|
|
@@ -2540,6 +2552,15 @@ Command: {command}`,
|
|
|
2540
2552
|
"plan.active_in_progress": 'Cannot create a new plan: active plan {id} already has progress ({done}/{total} done, current: step {current}). Resume it — use "plan show" to view, then continue working. To replace it, call "plan abort" first, then "plan create" again.',
|
|
2541
2553
|
"plan.id_ignored": 'note: plan ids are auto-generated; use "plan switch" to activate an existing plan by id.',
|
|
2542
2554
|
"plan.existing_fresh": "note: the previous active plan had no progress and was preserved as a draft.",
|
|
2555
|
+
"plan.already_active": "Plan {id} is already active — nothing to switch.",
|
|
2556
|
+
"plan.already_archived": "Plan {id} is already archived — nothing to abort.",
|
|
2557
|
+
"plan.aborted_id": "Plan {id} aborted and archived.",
|
|
2558
|
+
"plan.delete_no_id": "Provide a plan id to delete (plan delete id=plan_xxx).",
|
|
2559
|
+
"plan.deleted": "Plan {id} deleted permanently.",
|
|
2560
|
+
"plan.purged": "Deleted {count} plan(s). Plan storage is empty.",
|
|
2561
|
+
"plan.no_deliverables": "note: step {step} names no files — its completion cannot be auto-verified; run an explicit check (e.g. build/tests) before your final answer.",
|
|
2562
|
+
"plan.list_legend": "[*] active · [ ] draft · [-] archived",
|
|
2563
|
+
"exec.plan_nudge": "You made {count} file-changing tool call(s) without a plan. For tasks that create or modify files, or span multiple steps, create a plan first (plan create) with concrete steps (exact filenames, commands, deliverables), then continue.",
|
|
2543
2564
|
"todo.added": "Added {count} todo(s): {items}",
|
|
2544
2565
|
"todo.marked_done": "Marked {count} item(s) as done",
|
|
2545
2566
|
"todo.no_active": "No active todos",
|
|
@@ -2561,6 +2582,7 @@ Command: {command}`,
|
|
|
2561
2582
|
"lsp.check_notfound": "Path not found: {path}",
|
|
2562
2583
|
"lsp.check_unsupported": "No LSP server configured for: {path}",
|
|
2563
2584
|
"lsp.check_clean": "No errors or warnings detected ({count} file(s) checked).",
|
|
2585
|
+
"lsp.checked_files": "Checked {count} file(s):",
|
|
2564
2586
|
"lsp.startup_header": "[Existing project errors (checked at session start) — fix these before continuing]:",
|
|
2565
2587
|
"cli.description": "Micro Models Agent — AI coding agent for small models",
|
|
2566
2588
|
"cli.init": "Run interactive setup wizard",
|
|
@@ -2860,6 +2882,11 @@ Use this knowledge to answer the user's question.`,
|
|
|
2860
2882
|
{hints}`,
|
|
2861
2883
|
"exec.file_rewrite_warning": "⚠️ File {file} has been rewritten {count} times. Consider a different approach — the current fix strategy is not working.",
|
|
2862
2884
|
"exec.forbidden_cmd": 'STOP using "{cmd}" via the bash tool — it is not a native Windows cmd.exe command and has failed repeatedly this session. Use the dedicated tool instead: grep → the grep tool, ls/dir → list_dir, find → glob, rm → delete_file, sed → edit_file, touch → write_file, which → `where`, cp/mv → move_file, diff → read_file. Do NOT call bash for this purpose again.',
|
|
2885
|
+
"exec.error_search_results": `The error "{sig}" has occurred {count} times. Web search found:
|
|
2886
|
+
{results}
|
|
2887
|
+
Apply a matching solution from these results. If none is relevant — do NOT repeat the same approach; change strategy or honestly report being stuck.`,
|
|
2888
|
+
"exec.error_search_failed": 'Web search returned nothing for "{query}".',
|
|
2889
|
+
"exec.error_search_no_query": "Error output is not meaningful — skipping the web search.",
|
|
2863
2890
|
"exec.npm_exec_hint": '"could not determine executable to run" — no "bin" for that package/script. Use "npm run <script>" (script must exist in package.json) or "bunx <pkg>" for a package that declares a bin.',
|
|
2864
2891
|
"hall.max_retries_exhausted": "Model returned empty or insufficient responses after multiple retries",
|
|
2865
2892
|
"hall.short_response": "Response too short or empty",
|
|
@@ -2909,6 +2936,7 @@ Use this knowledge to answer the user's question.`,
|
|
|
2909
2936
|
"ui.success_prefix": "✓ ",
|
|
2910
2937
|
"ui.warning_prefix": "⚠ ",
|
|
2911
2938
|
"ui.thinking": "Thinking…",
|
|
2939
|
+
"ui.tool_running": "{tool}…",
|
|
2912
2940
|
"ui.step_context": "step {id}: {desc}",
|
|
2913
2941
|
"indexer.map_header": "Project map",
|
|
2914
2942
|
"indexer.top_directories": "Top directories",
|
|
@@ -3111,6 +3139,7 @@ var init_ru = __esm(() => {
|
|
|
3111
3139
|
"tool.no_results": 'Нет результатов по "{query}"',
|
|
3112
3140
|
"tool.search_results": `Результаты поиска "{query}":
|
|
3113
3141
|
{results}`,
|
|
3142
|
+
"tool.web_search_disabled": "Веб-поиск отключён (webSearch.enabled: false). Используй только файловые и системные инструменты.",
|
|
3114
3143
|
"tool.history_results": `Результаты истории "{query}":
|
|
3115
3144
|
{results}`,
|
|
3116
3145
|
"tool.no_history": 'Нет записей истории по "{query}"',
|
|
@@ -3175,6 +3204,15 @@ var init_ru = __esm(() => {
|
|
|
3175
3204
|
"plan.active_in_progress": 'Нельзя создать новый план: активный план {id} уже имеет прогресс ({done}/{total} выполнено, текущий: шаг {current}). Продолжай его — вызови "plan show", чтобы увидеть, и продолжай работу. Чтобы заменить план, сначала вызови "plan abort", затем "plan create".',
|
|
3176
3205
|
"plan.id_ignored": 'примечание: id плана генерируется автоматически; используй "plan switch", чтобы активировать существующий план по id.',
|
|
3177
3206
|
"plan.existing_fresh": "примечание: предыдущий активный план не имел прогресса и сохранён как черновик.",
|
|
3207
|
+
"plan.already_active": "План {id} уже активен — переключаться некуда.",
|
|
3208
|
+
"plan.already_archived": "План {id} уже в архиве — отменять нечего.",
|
|
3209
|
+
"plan.aborted_id": "План {id} отменён и архивирован.",
|
|
3210
|
+
"plan.delete_no_id": "Укажите id плана для удаления (plan delete id=plan_xxx).",
|
|
3211
|
+
"plan.deleted": "План {id} удалён окончательно.",
|
|
3212
|
+
"plan.purged": "Удалено планов: {count}. Хранилище планов пусто.",
|
|
3213
|
+
"plan.no_deliverables": "примечание: шаг {step} не называет файлов — его выполнение нельзя проверить автоматически; перед финальным ответом явно проверь результат (например, запусти сборку/тесты).",
|
|
3214
|
+
"plan.list_legend": "[*] активный · [ ] черновик · [-] архив",
|
|
3215
|
+
"exec.plan_nudge": "Ты сделал(а) {count} вызов(ов), изменяющих файлы, без плана. Для задач, создающих/изменяющих файлы или состоящих из нескольких шагов, сначала создай план (plan create) с конкретными шагами (точные имена файлов, команды, результаты), а потом продолжай.",
|
|
3178
3216
|
"todo.added": "Добавлено {count} задач: {items}",
|
|
3179
3217
|
"todo.marked_done": "Отмечено выполненными: {count}",
|
|
3180
3218
|
"todo.no_active": "Нет активных задач",
|
|
@@ -3196,6 +3234,7 @@ var init_ru = __esm(() => {
|
|
|
3196
3234
|
"lsp.check_notfound": "Путь не найден: {path}",
|
|
3197
3235
|
"lsp.check_unsupported": "Для файла не настроен LSP-сервер: {path}",
|
|
3198
3236
|
"lsp.check_clean": "Ошибок и предупреждений не обнаружено (проверено файлов: {count}).",
|
|
3237
|
+
"lsp.checked_files": "Проверено файлов: {count}:",
|
|
3199
3238
|
"lsp.startup_header": "[Существующие ошибки проекта (проверено при старте сессии) — исправьте их перед продолжением]:",
|
|
3200
3239
|
"cli.description": "Micro Models Agent — ИИ-агент для кодинга на малых моделях",
|
|
3201
3240
|
"cli.init": "Запустить мастер настройки",
|
|
@@ -3495,6 +3534,11 @@ var init_ru = __esm(() => {
|
|
|
3495
3534
|
{hints}`,
|
|
3496
3535
|
"exec.file_rewrite_warning": "⚠️ Файл {file} был перезаписан {count} раз. Попробуйте другой подход — текущая стратегия исправлений не работает.",
|
|
3497
3536
|
"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 для этого.',
|
|
3537
|
+
"exec.error_search_results": `Ошибка "{sig}" повторилась {count} раз. Поиск в интернете нашёл:
|
|
3538
|
+
{results}
|
|
3539
|
+
Примени подходящее решение из результатов. Если ни один результат не релевантен — НЕ повторяй тот же подход, смени стратегию или честно сообщи о застревании.`,
|
|
3540
|
+
"exec.error_search_failed": 'Поиск в интернете для "{query}" ничего не дал.',
|
|
3541
|
+
"exec.error_search_no_query": "Текст ошибки незначимый — поиск в интернете пропущен.",
|
|
3498
3542
|
"exec.npm_exec_hint": '"could not determine executable to run" — у пакета/скрипта нет "bin". Используй "npm run <script>" (скрипт должен быть в package.json) или "bunx <pkg>" для пакета с объявленным bin.',
|
|
3499
3543
|
"hall.max_retries_exhausted": "Модель вернула пустой или недостаточный ответ после нескольких попыток",
|
|
3500
3544
|
"hall.short_response": "Слишком короткий или пустой ответ",
|
|
@@ -3544,6 +3588,7 @@ var init_ru = __esm(() => {
|
|
|
3544
3588
|
"ui.success_prefix": "✓ ",
|
|
3545
3589
|
"ui.warning_prefix": "⚠ ",
|
|
3546
3590
|
"ui.thinking": "Думаю…",
|
|
3591
|
+
"ui.tool_running": "{tool}…",
|
|
3547
3592
|
"ui.step_context": "шаг {id}: {desc}",
|
|
3548
3593
|
"indexer.map_header": "Карта проекта",
|
|
3549
3594
|
"indexer.top_directories": "Основные директории",
|
|
@@ -9464,6 +9509,41 @@ function filterToolsByTags(tools, toolTags) {
|
|
|
9464
9509
|
}
|
|
9465
9510
|
|
|
9466
9511
|
// src/modules/execution/stuck-detector.ts
|
|
9512
|
+
function normalizeErrorSignature(toolName, output) {
|
|
9513
|
+
if (!output)
|
|
9514
|
+
return null;
|
|
9515
|
+
const cleaned = output.replace(ANSI_RE, "").replace(ERROR_LOC_RE, " <path>").split(`
|
|
9516
|
+
`).map((l) => l.trim()).filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
|
|
9517
|
+
if (!cleaned)
|
|
9518
|
+
return null;
|
|
9519
|
+
return `${toolName}::${cleaned.slice(0, SIGNATURE_MAX_CHARS)}`;
|
|
9520
|
+
}
|
|
9521
|
+
function isSearchableError(output) {
|
|
9522
|
+
if (!output || !output.trim())
|
|
9523
|
+
return false;
|
|
9524
|
+
const text = output.trim();
|
|
9525
|
+
return SEARCHABLE_PATTERNS.some((p) => p.test(text));
|
|
9526
|
+
}
|
|
9527
|
+
function buildSearchQuery(stepDescription, lastBashCommand, lastErrorOutput, toolName, maxQueryChars) {
|
|
9528
|
+
const errorText = (lastErrorOutput || "").replace(ANSI_RE, "").replace(ERROR_LOC_RE, " <path>").split(`
|
|
9529
|
+
`).map((l) => l.trim()).filter(Boolean).slice(0, 3).join(" ").replace(/\s+/g, " ").trim();
|
|
9530
|
+
const context = `${stepDescription} ${lastBashCommand}`.toLowerCase();
|
|
9531
|
+
const runtime = RUNTIME_WORDS.find((w) => context.includes(w)) || "";
|
|
9532
|
+
const framework = FRAMEWORK_WORDS.find((w) => context.includes(w)) || "";
|
|
9533
|
+
let query;
|
|
9534
|
+
if (errorText) {
|
|
9535
|
+
query = runtime && !errorText.toLowerCase().includes(runtime) ? `${runtime} ${errorText}` : errorText;
|
|
9536
|
+
if (framework && !query.toLowerCase().includes(framework))
|
|
9537
|
+
query = `${query} ${framework}`;
|
|
9538
|
+
query = `${query} how to fix`;
|
|
9539
|
+
} else if (runtime || framework) {
|
|
9540
|
+
query = `${[runtime, framework, "error", "how to fix"].filter(Boolean).join(" ")}`;
|
|
9541
|
+
} else {
|
|
9542
|
+
query = `${toolName} ${stepDescription} how to fix`;
|
|
9543
|
+
}
|
|
9544
|
+
return query.slice(0, maxQueryChars);
|
|
9545
|
+
}
|
|
9546
|
+
|
|
9467
9547
|
class StuckDetector {
|
|
9468
9548
|
threshold;
|
|
9469
9549
|
errorThreshold;
|
|
@@ -9485,9 +9565,13 @@ class StuckDetector {
|
|
|
9485
9565
|
lastBashOutput = "";
|
|
9486
9566
|
emptyBashRunCount = 0;
|
|
9487
9567
|
readOnlyStreak = 0;
|
|
9488
|
-
|
|
9568
|
+
errorSignatureCounts = new Map;
|
|
9569
|
+
searchedErrorSignatures = new Set;
|
|
9570
|
+
webSearchThreshold;
|
|
9571
|
+
constructor(threshold = 6, errorThreshold = 3, webSearchThreshold = 5) {
|
|
9489
9572
|
this.threshold = threshold;
|
|
9490
9573
|
this.errorThreshold = errorThreshold;
|
|
9574
|
+
this.webSearchThreshold = webSearchThreshold;
|
|
9491
9575
|
}
|
|
9492
9576
|
recordIteration(stepId) {
|
|
9493
9577
|
if (stepId === this.currentStepId) {
|
|
@@ -9517,6 +9601,10 @@ class StuckDetector {
|
|
|
9517
9601
|
this.lastFailedTool = toolName;
|
|
9518
9602
|
if (output)
|
|
9519
9603
|
this.lastErrorOutput = output;
|
|
9604
|
+
const sig = normalizeErrorSignature(toolName, output);
|
|
9605
|
+
if (sig) {
|
|
9606
|
+
this.errorSignatureCounts.set(sig, (this.errorSignatureCounts.get(sig) || 0) + 1);
|
|
9607
|
+
}
|
|
9520
9608
|
}
|
|
9521
9609
|
getLastErrorOutput() {
|
|
9522
9610
|
return this.lastErrorOutput;
|
|
@@ -9540,6 +9628,26 @@ class StuckDetector {
|
|
|
9540
9628
|
getLastFailedTool() {
|
|
9541
9629
|
return this.lastFailedTool;
|
|
9542
9630
|
}
|
|
9631
|
+
getRepeatedErrorSignature() {
|
|
9632
|
+
for (const [sig, count] of this.errorSignatureCounts) {
|
|
9633
|
+
if (count >= this.webSearchThreshold && !this.searchedErrorSignatures.has(sig)) {
|
|
9634
|
+
return sig;
|
|
9635
|
+
}
|
|
9636
|
+
}
|
|
9637
|
+
return null;
|
|
9638
|
+
}
|
|
9639
|
+
getErrorSignatureCount(sig) {
|
|
9640
|
+
return this.errorSignatureCounts.get(sig) || 0;
|
|
9641
|
+
}
|
|
9642
|
+
markErrorSearched(sig) {
|
|
9643
|
+
this.searchedErrorSignatures.add(sig);
|
|
9644
|
+
}
|
|
9645
|
+
unmarkErrorSearched(sig) {
|
|
9646
|
+
this.searchedErrorSignatures.delete(sig);
|
|
9647
|
+
}
|
|
9648
|
+
hasErrorSearched(sig) {
|
|
9649
|
+
return this.searchedErrorSignatures.has(sig);
|
|
9650
|
+
}
|
|
9543
9651
|
getIterationsOnCurrentStep() {
|
|
9544
9652
|
return this.iterationsOnCurrentStep;
|
|
9545
9653
|
}
|
|
@@ -9812,6 +9920,8 @@ class StuckDetector {
|
|
|
9812
9920
|
this.lastBashOutput = "";
|
|
9813
9921
|
this.emptyBashRunCount = 0;
|
|
9814
9922
|
this.readOnlyStreak = 0;
|
|
9923
|
+
this.errorSignatureCounts.clear();
|
|
9924
|
+
this.searchedErrorSignatures.clear();
|
|
9815
9925
|
}
|
|
9816
9926
|
resetStepProgress() {
|
|
9817
9927
|
this.currentStepId = null;
|
|
@@ -9825,6 +9935,8 @@ class StuckDetector {
|
|
|
9825
9935
|
this.lastBashCommand = "";
|
|
9826
9936
|
this.lastBashOutput = "";
|
|
9827
9937
|
this.emptyBashRunCount = 0;
|
|
9938
|
+
this.errorSignatureCounts.clear();
|
|
9939
|
+
this.searchedErrorSignatures.clear();
|
|
9828
9940
|
}
|
|
9829
9941
|
resetStepState(stepId) {
|
|
9830
9942
|
this.currentStepId = stepId;
|
|
@@ -9839,9 +9951,11 @@ class StuckDetector {
|
|
|
9839
9951
|
this.lastBashOutput = "";
|
|
9840
9952
|
this.emptyBashRunCount = 0;
|
|
9841
9953
|
this.readOnlyStreak = 0;
|
|
9954
|
+
this.errorSignatureCounts.clear();
|
|
9955
|
+
this.searchedErrorSignatures.clear();
|
|
9842
9956
|
}
|
|
9843
9957
|
}
|
|
9844
|
-
var READ_ONLY_TOOLS, READ_ONLY_LOOP_THRESHOLD = 10;
|
|
9958
|
+
var READ_ONLY_TOOLS, READ_ONLY_LOOP_THRESHOLD = 10, ANSI_RE, ERROR_LOC_RE, SIGNATURE_MAX_CHARS = 120, SEARCHABLE_PATTERNS, RUNTIME_WORDS, FRAMEWORK_WORDS;
|
|
9845
9959
|
var init_stuck_detector = __esm(() => {
|
|
9846
9960
|
init_i18n();
|
|
9847
9961
|
READ_ONLY_TOOLS = new Set([
|
|
@@ -9865,6 +9979,55 @@ var init_stuck_detector = __esm(() => {
|
|
|
9865
9979
|
"verify",
|
|
9866
9980
|
"load_skill"
|
|
9867
9981
|
]);
|
|
9982
|
+
ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
9983
|
+
ERROR_LOC_RE = /(?:[A-Za-z]:[\\/])?(?:[\w.@+-]+[\\/])+[\w.@+-]+\.[a-zA-Z0-9]{1,6}(?::\d+(?::\d+)?)?/g;
|
|
9984
|
+
SEARCHABLE_PATTERNS = [
|
|
9985
|
+
/error TS\d+/i,
|
|
9986
|
+
/ERR_[A-Z_]+/,
|
|
9987
|
+
/ENOENT|EACCES|EPERM|ECONNREFUSED|ETIMEDOUT|ECONNRESET|ENOTFOUND|EADDRINUSE/i,
|
|
9988
|
+
/Cannot find module|Module not found|ERR_MODULE_NOT_FOUND/i,
|
|
9989
|
+
/TypeError|ReferenceError|SyntaxError|RangeError/i,
|
|
9990
|
+
/is not a function|is not defined|is not a constructor/i,
|
|
9991
|
+
/Cannot read properties of/i,
|
|
9992
|
+
/failed to (compile|build|resolve|parse)/i,
|
|
9993
|
+
/fatal error|panic/i
|
|
9994
|
+
];
|
|
9995
|
+
RUNTIME_WORDS = [
|
|
9996
|
+
"bun",
|
|
9997
|
+
"node",
|
|
9998
|
+
"deno",
|
|
9999
|
+
"npm",
|
|
10000
|
+
"yarn",
|
|
10001
|
+
"pnpm",
|
|
10002
|
+
"pip",
|
|
10003
|
+
"pip3",
|
|
10004
|
+
"python",
|
|
10005
|
+
"python3",
|
|
10006
|
+
"tsc",
|
|
10007
|
+
"tsx",
|
|
10008
|
+
"npx",
|
|
10009
|
+
"go",
|
|
10010
|
+
"cargo",
|
|
10011
|
+
"gradle",
|
|
10012
|
+
"maven",
|
|
10013
|
+
"make"
|
|
10014
|
+
];
|
|
10015
|
+
FRAMEWORK_WORDS = [
|
|
10016
|
+
"react",
|
|
10017
|
+
"vue",
|
|
10018
|
+
"angular",
|
|
10019
|
+
"svelte",
|
|
10020
|
+
"vite",
|
|
10021
|
+
"next",
|
|
10022
|
+
"nest",
|
|
10023
|
+
"express",
|
|
10024
|
+
"fastify",
|
|
10025
|
+
"flask",
|
|
10026
|
+
"django",
|
|
10027
|
+
"spring",
|
|
10028
|
+
"webpack",
|
|
10029
|
+
"tailwind"
|
|
10030
|
+
];
|
|
9868
10031
|
});
|
|
9869
10032
|
|
|
9870
10033
|
// src/modules/artifacts/store.ts
|
|
@@ -10453,8 +10616,46 @@ var init_js_identifiers = __esm(() => {
|
|
|
10453
10616
|
});
|
|
10454
10617
|
|
|
10455
10618
|
// src/modules/execution/audit-runners.ts
|
|
10456
|
-
import { existsSync as existsSync20, readdirSync as readdirSync5 } from "fs";
|
|
10619
|
+
import { existsSync as existsSync20, readdirSync as readdirSync5, readFileSync as readFileSync10 } from "fs";
|
|
10457
10620
|
import { dirname as dirname7, join as join11, resolve as resolve11 } from "path";
|
|
10621
|
+
function resolveTestCommand(dir) {
|
|
10622
|
+
const pkgPath = join11(dir, "package.json");
|
|
10623
|
+
if (existsSync20(pkgPath)) {
|
|
10624
|
+
try {
|
|
10625
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
10626
|
+
const script = pkg?.scripts?.test;
|
|
10627
|
+
if (typeof script === "string" && script.trim())
|
|
10628
|
+
return script.trim();
|
|
10629
|
+
} catch {}
|
|
10630
|
+
}
|
|
10631
|
+
for (const f of [
|
|
10632
|
+
"vitest.config.ts",
|
|
10633
|
+
"vitest.config.js",
|
|
10634
|
+
"vitest.config.mjs",
|
|
10635
|
+
"jest.config.js",
|
|
10636
|
+
"jest.config.ts",
|
|
10637
|
+
"jest.config.mjs",
|
|
10638
|
+
"jest.config.cjs",
|
|
10639
|
+
"bunfig.toml"
|
|
10640
|
+
]) {
|
|
10641
|
+
if (existsSync20(join11(dir, f))) {
|
|
10642
|
+
if (f.startsWith("vitest"))
|
|
10643
|
+
return "bunx vitest run";
|
|
10644
|
+
if (f.startsWith("jest"))
|
|
10645
|
+
return "npx --no-install jest";
|
|
10646
|
+
if (f === "bunfig.toml")
|
|
10647
|
+
return "bun test";
|
|
10648
|
+
}
|
|
10649
|
+
}
|
|
10650
|
+
if (existsSync20(join11(dir, "pyproject.toml")) || existsSync20(join11(dir, "pytest.ini")) || existsSync20(join11(dir, "conftest.py"))) {
|
|
10651
|
+
return "python -m pytest -q";
|
|
10652
|
+
}
|
|
10653
|
+
if (existsSync20(join11(dir, "go.mod")))
|
|
10654
|
+
return "go test ./...";
|
|
10655
|
+
if (existsSync20(join11(dir, "Cargo.toml")))
|
|
10656
|
+
return "cargo test";
|
|
10657
|
+
return "bun test";
|
|
10658
|
+
}
|
|
10458
10659
|
function findTestFile(dir, depth = 0) {
|
|
10459
10660
|
if (depth > 5)
|
|
10460
10661
|
return null;
|
|
@@ -10472,7 +10673,7 @@ function findTestFile(dir, depth = 0) {
|
|
|
10472
10673
|
const found = findTestFile(full, depth + 1);
|
|
10473
10674
|
if (found)
|
|
10474
10675
|
return found;
|
|
10475
|
-
} else if (TEST_EXT_RE.test(e.name)) {
|
|
10676
|
+
} else if (TEST_EXT_RE.test(e.name) || PY_TEST_RE.test(e.name)) {
|
|
10476
10677
|
return full;
|
|
10477
10678
|
}
|
|
10478
10679
|
}
|
|
@@ -10493,7 +10694,8 @@ function extractFailingNames(output, limit = 5) {
|
|
|
10493
10694
|
return names;
|
|
10494
10695
|
}
|
|
10495
10696
|
async function runTests(baseDir) {
|
|
10496
|
-
const
|
|
10697
|
+
const command = resolveTestCommand(baseDir);
|
|
10698
|
+
const entry = processRegistry.start(command, baseDir);
|
|
10497
10699
|
const exited = await processRegistry.waitForExit(entry.id, 90000);
|
|
10498
10700
|
const output = entry.log.join(`
|
|
10499
10701
|
`);
|
|
@@ -10504,8 +10706,8 @@ async function runTests(baseDir) {
|
|
|
10504
10706
|
passed: true,
|
|
10505
10707
|
failed: 0,
|
|
10506
10708
|
passedCount: 0,
|
|
10507
|
-
detail:
|
|
10508
|
-
command
|
|
10709
|
+
detail: `test run timed out after 90s — result unknown`,
|
|
10710
|
+
command
|
|
10509
10711
|
};
|
|
10510
10712
|
}
|
|
10511
10713
|
const run = detectTestResults(output);
|
|
@@ -10516,7 +10718,7 @@ async function runTests(baseDir) {
|
|
|
10516
10718
|
failed: entry.exitCode === 0 ? 0 : 1,
|
|
10517
10719
|
passedCount: 0,
|
|
10518
10720
|
detail: output.slice(0, 200).trim(),
|
|
10519
|
-
command
|
|
10721
|
+
command
|
|
10520
10722
|
};
|
|
10521
10723
|
}
|
|
10522
10724
|
const names = extractFailingNames(output);
|
|
@@ -10526,7 +10728,7 @@ async function runTests(baseDir) {
|
|
|
10526
10728
|
failed: run.failed,
|
|
10527
10729
|
passedCount: run.passed,
|
|
10528
10730
|
detail: names.length ? names.join("; ") : run.summary || `${run.failed} failed / ${run.passed} passed`,
|
|
10529
|
-
command
|
|
10731
|
+
command
|
|
10530
10732
|
};
|
|
10531
10733
|
}
|
|
10532
10734
|
function parseTypecheckErrors(output) {
|
|
@@ -10563,7 +10765,7 @@ async function runTypecheck(baseDir) {
|
|
|
10563
10765
|
return null;
|
|
10564
10766
|
return parseTypecheckErrors(output);
|
|
10565
10767
|
}
|
|
10566
|
-
var SKIP_DIRS, TEST_EXT_RE, TEST_STEP_RE;
|
|
10768
|
+
var SKIP_DIRS, TEST_EXT_RE, PY_TEST_RE, TEST_STEP_RE;
|
|
10567
10769
|
var init_audit_runners = __esm(() => {
|
|
10568
10770
|
init_bash();
|
|
10569
10771
|
init_processes();
|
|
@@ -10579,6 +10781,7 @@ var init_audit_runners = __esm(() => {
|
|
|
10579
10781
|
"vendor"
|
|
10580
10782
|
]);
|
|
10581
10783
|
TEST_EXT_RE = /\.(test|spec)\.[jt]sx?$/i;
|
|
10784
|
+
PY_TEST_RE = /^test_.*\.py$|^.*_test\.py$/i;
|
|
10582
10785
|
TEST_STEP_RE = /\b(test(ing|s)?|тест(ы|ирование|ировать)?|провер\w*\s+тест|запустить\s+тест)\b|bun test|npm test|vitest|pytest|go test|jest|mocha/i;
|
|
10583
10786
|
});
|
|
10584
10787
|
|
|
@@ -13263,7 +13466,7 @@ ${joined}` }
|
|
|
13263
13466
|
var DEFAULT_CHUNK_SYSTEM_PROMPT = 'Answer the query using ONLY the provided text. Be concise. If the text does not contain the answer, say "NO_EVIDENCE".', DEFAULT_SYNTHESIS_SYSTEM_PROMPT = "You are given a query and per-chunk answers over a large text. Produce the final answer to the query, combining evidence from the chunks. If no chunk had evidence, say so.";
|
|
13264
13467
|
|
|
13265
13468
|
// src/tools/chunk-query.ts
|
|
13266
|
-
import { readFileSync as
|
|
13469
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
13267
13470
|
import { resolve as resolve16 } from "node:path";
|
|
13268
13471
|
var chunkQueryTool;
|
|
13269
13472
|
var init_chunk_query = __esm(() => {
|
|
@@ -13332,7 +13535,7 @@ var init_chunk_query = __esm(() => {
|
|
|
13332
13535
|
return { success: false, output: `[SCOPE] ${check.reason || "Path not allowed"}` };
|
|
13333
13536
|
}
|
|
13334
13537
|
try {
|
|
13335
|
-
content =
|
|
13538
|
+
content = readFileSync11(resolve16(ctx.baseDir, inputPath), "utf8");
|
|
13336
13539
|
} catch (e) {
|
|
13337
13540
|
return { success: false, output: `Cannot read ${inputPath}: ${e.message}` };
|
|
13338
13541
|
}
|
|
@@ -13425,6 +13628,43 @@ var init_network_validator = __esm(() => {
|
|
|
13425
13628
|
});
|
|
13426
13629
|
|
|
13427
13630
|
// src/tools/web-search.ts
|
|
13631
|
+
async function performWebSearch(query, numResults, networkConfig, requestTimeoutMs) {
|
|
13632
|
+
const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
|
|
13633
|
+
const validation = isUrlAllowed(url, networkConfig);
|
|
13634
|
+
if (!validation.allowed) {
|
|
13635
|
+
return {
|
|
13636
|
+
success: false,
|
|
13637
|
+
blocked: true,
|
|
13638
|
+
results: [],
|
|
13639
|
+
error: validation.reason || "URL blocked by security policy"
|
|
13640
|
+
};
|
|
13641
|
+
}
|
|
13642
|
+
try {
|
|
13643
|
+
const response = await fetch(url, {
|
|
13644
|
+
signal: AbortSignal.timeout(requestTimeoutMs ?? networkConfig?.requestTimeout ?? 1e4)
|
|
13645
|
+
});
|
|
13646
|
+
const html = await response.text();
|
|
13647
|
+
const results = [];
|
|
13648
|
+
const snippetRegex = /<a[^>]+class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/gi;
|
|
13649
|
+
let match;
|
|
13650
|
+
while ((match = snippetRegex.exec(html)) !== null && results.length < numResults) {
|
|
13651
|
+
results.push({
|
|
13652
|
+
url: match[1].trim(),
|
|
13653
|
+
title: match[2].replace(/<[^>]+>/g, "").trim(),
|
|
13654
|
+
snippet: match[3].replace(/<[^>]+>/g, "").trim()
|
|
13655
|
+
});
|
|
13656
|
+
}
|
|
13657
|
+
return { success: true, results };
|
|
13658
|
+
} catch (err) {
|
|
13659
|
+
return { success: false, results: [], error: err.message };
|
|
13660
|
+
}
|
|
13661
|
+
}
|
|
13662
|
+
function formatResults(results) {
|
|
13663
|
+
return results.map((r, i) => `${i + 1}. ${r.title}
|
|
13664
|
+
URL: ${r.url}
|
|
13665
|
+
${r.snippet}`).join(`
|
|
13666
|
+
`);
|
|
13667
|
+
}
|
|
13428
13668
|
var webSearchTool;
|
|
13429
13669
|
var init_web_search = __esm(() => {
|
|
13430
13670
|
init_i18n();
|
|
@@ -13447,59 +13687,42 @@ var init_web_search = __esm(() => {
|
|
|
13447
13687
|
required: ["query"]
|
|
13448
13688
|
},
|
|
13449
13689
|
handler: async (ctx, args) => {
|
|
13690
|
+
if (ctx.config?.webSearch?.enabled === false) {
|
|
13691
|
+
return { success: false, output: t("tool.web_search_disabled") };
|
|
13692
|
+
}
|
|
13450
13693
|
const query = String(args.query || "");
|
|
13451
13694
|
const numResults = Number(args.numResults) || 5;
|
|
13452
|
-
const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
|
|
13453
13695
|
const securityConfig = ctx.sessionContext ? getSessionSecurityConfig(ctx.config, ctx.sessionContext).network : ctx.config.security?.network;
|
|
13454
|
-
const
|
|
13455
|
-
|
|
13456
|
-
|
|
13696
|
+
const outcome = await performWebSearch(query, numResults, securityConfig);
|
|
13697
|
+
const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
|
|
13698
|
+
if (outcome.blocked) {
|
|
13699
|
+
logSecurityBlock(ctx.sessionId, "network_request", outcome.error || "URL blocked by security policy", sanitizeUrl(url));
|
|
13457
13700
|
return {
|
|
13458
13701
|
success: false,
|
|
13459
|
-
output:
|
|
13702
|
+
output: t("error.search_failed", { message: String(outcome.error) })
|
|
13460
13703
|
};
|
|
13461
13704
|
}
|
|
13462
|
-
|
|
13463
|
-
|
|
13464
|
-
signal: AbortSignal.timeout(securityConfig?.requestTimeout || 1e4)
|
|
13465
|
-
});
|
|
13466
|
-
const html = await response.text();
|
|
13467
|
-
const results = [];
|
|
13468
|
-
const snippetRegex = /<a[^>]+class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/gi;
|
|
13469
|
-
let match;
|
|
13470
|
-
let count = 0;
|
|
13471
|
-
while ((match = snippetRegex.exec(html)) !== null && count < numResults) {
|
|
13472
|
-
const href = match[1].trim();
|
|
13473
|
-
const title = match[2].replace(/<[^>]+>/g, "").trim();
|
|
13474
|
-
const snippet = match[3].replace(/<[^>]+>/g, "").trim();
|
|
13475
|
-
results.push(`${count + 1}. ${title}
|
|
13476
|
-
URL: ${href}
|
|
13477
|
-
${snippet}`);
|
|
13478
|
-
count++;
|
|
13479
|
-
}
|
|
13480
|
-
logNetworkRequest(ctx.sessionId, sanitizeUrl(url), true, `Results: ${results.length}`);
|
|
13481
|
-
if (results.length === 0) {
|
|
13482
|
-
return { success: true, output: t("tool.no_results", { query }) };
|
|
13483
|
-
}
|
|
13484
|
-
return {
|
|
13485
|
-
success: true,
|
|
13486
|
-
output: t("tool.search_results", {
|
|
13487
|
-
query,
|
|
13488
|
-
results: results.join(`
|
|
13489
|
-
`)
|
|
13490
|
-
}),
|
|
13491
|
-
display: t("tool.web_search_result", {
|
|
13492
|
-
query,
|
|
13493
|
-
count: String(results.length)
|
|
13494
|
-
})
|
|
13495
|
-
};
|
|
13496
|
-
} catch (err) {
|
|
13497
|
-
logNetworkRequest(ctx.sessionId, sanitizeUrl(url), false, `Error: ${err.message}`);
|
|
13705
|
+
logNetworkRequest(ctx.sessionId, sanitizeUrl(url), outcome.success, `Results: ${outcome.results.length}`);
|
|
13706
|
+
if (!outcome.success) {
|
|
13498
13707
|
return {
|
|
13499
13708
|
success: false,
|
|
13500
|
-
output: t("error.search_failed", { message:
|
|
13709
|
+
output: t("error.search_failed", { message: String(outcome.error) })
|
|
13501
13710
|
};
|
|
13502
13711
|
}
|
|
13712
|
+
if (outcome.results.length === 0) {
|
|
13713
|
+
return { success: true, output: t("tool.no_results", { query }) };
|
|
13714
|
+
}
|
|
13715
|
+
return {
|
|
13716
|
+
success: true,
|
|
13717
|
+
output: t("tool.search_results", {
|
|
13718
|
+
query,
|
|
13719
|
+
results: formatResults(outcome.results)
|
|
13720
|
+
}),
|
|
13721
|
+
display: t("tool.web_search_result", {
|
|
13722
|
+
query,
|
|
13723
|
+
count: String(outcome.results.length)
|
|
13724
|
+
})
|
|
13725
|
+
};
|
|
13503
13726
|
}
|
|
13504
13727
|
};
|
|
13505
13728
|
});
|
|
@@ -14684,7 +14907,7 @@ var init_search_history = __esm(() => {
|
|
|
14684
14907
|
});
|
|
14685
14908
|
|
|
14686
14909
|
// src/modules/memory/search.ts
|
|
14687
|
-
import { readFileSync as
|
|
14910
|
+
import { readFileSync as readFileSync13, existsSync as existsSync26 } from "fs";
|
|
14688
14911
|
import { join as join17 } from "path";
|
|
14689
14912
|
|
|
14690
14913
|
class MemorySearch {
|
|
@@ -14699,7 +14922,7 @@ class MemorySearch {
|
|
|
14699
14922
|
const path = join17(this.memoryDir, `${name}.md`);
|
|
14700
14923
|
if (!existsSync26(path))
|
|
14701
14924
|
continue;
|
|
14702
|
-
const content =
|
|
14925
|
+
const content = readFileSync13(path, "utf-8");
|
|
14703
14926
|
const lines = content.split(`
|
|
14704
14927
|
`);
|
|
14705
14928
|
for (const line of lines) {
|
|
@@ -14711,7 +14934,7 @@ class MemorySearch {
|
|
|
14711
14934
|
const prefsPath = join17(this.memoryDir, "preferences.json");
|
|
14712
14935
|
if (existsSync26(prefsPath)) {
|
|
14713
14936
|
try {
|
|
14714
|
-
const prefs = JSON.parse(
|
|
14937
|
+
const prefs = JSON.parse(readFileSync13(prefsPath, "utf-8"));
|
|
14715
14938
|
for (const [key, value] of Object.entries(prefs)) {
|
|
14716
14939
|
const searchStr = `${key}=${value}`;
|
|
14717
14940
|
if (searchStr.toLowerCase().includes(lowerQuery)) {
|
|
@@ -14729,7 +14952,7 @@ var init_search = __esm(() => {
|
|
|
14729
14952
|
});
|
|
14730
14953
|
|
|
14731
14954
|
// src/modules/memory/store.ts
|
|
14732
|
-
import { readFileSync as
|
|
14955
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, existsSync as existsSync27, mkdirSync as mkdirSync13 } from "fs";
|
|
14733
14956
|
import { join as join18 } from "path";
|
|
14734
14957
|
|
|
14735
14958
|
class MemoryStore {
|
|
@@ -14755,7 +14978,7 @@ class MemoryStore {
|
|
|
14755
14978
|
const path = join18(this.memoryDir, `${name}.md`);
|
|
14756
14979
|
if (!existsSync27(path))
|
|
14757
14980
|
return "";
|
|
14758
|
-
return
|
|
14981
|
+
return readFileSync14(path, "utf-8");
|
|
14759
14982
|
}
|
|
14760
14983
|
append(name, entry) {
|
|
14761
14984
|
const path = join18(this.memoryDir, `${name}.md`);
|
|
@@ -14776,7 +14999,7 @@ class MemoryStore {
|
|
|
14776
14999
|
if (!existsSync27(path))
|
|
14777
15000
|
return {};
|
|
14778
15001
|
try {
|
|
14779
|
-
return JSON.parse(
|
|
15002
|
+
return JSON.parse(readFileSync14(path, "utf-8"));
|
|
14780
15003
|
} catch {
|
|
14781
15004
|
return {};
|
|
14782
15005
|
}
|
|
@@ -16065,7 +16288,7 @@ __export(exports_image_utils, {
|
|
|
16065
16288
|
detectMime: () => detectMime,
|
|
16066
16289
|
bufferToDataUrl: () => bufferToDataUrl
|
|
16067
16290
|
});
|
|
16068
|
-
import { readFileSync as
|
|
16291
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
16069
16292
|
import { extname as extname3 } from "path";
|
|
16070
16293
|
function detectMime(filePath) {
|
|
16071
16294
|
const ext = extname3(filePath).toLowerCase();
|
|
@@ -16086,7 +16309,7 @@ async function readClipboardImage() {
|
|
|
16086
16309
|
async function readClipboardFallback() {
|
|
16087
16310
|
const { platform: platform5 } = await import("os");
|
|
16088
16311
|
const { execSync } = await import("child_process");
|
|
16089
|
-
const { readFileSync:
|
|
16312
|
+
const { readFileSync: readFileSync16, unlinkSync: unlinkSync4 } = await import("fs");
|
|
16090
16313
|
const { join: join24 } = await import("path");
|
|
16091
16314
|
const tmpPath = join24(process.env.TEMP || process.env.TMP || "/tmp", `mma-clip-${Date.now()}.png`);
|
|
16092
16315
|
try {
|
|
@@ -16097,7 +16320,7 @@ async function readClipboardFallback() {
|
|
|
16097
16320
|
} else {
|
|
16098
16321
|
return null;
|
|
16099
16322
|
}
|
|
16100
|
-
const buf =
|
|
16323
|
+
const buf = readFileSync16(tmpPath);
|
|
16101
16324
|
unlinkSync4(tmpPath);
|
|
16102
16325
|
return buf.length > 0 ? buf : null;
|
|
16103
16326
|
} catch {
|
|
@@ -16108,7 +16331,7 @@ async function readClipboardFallback() {
|
|
|
16108
16331
|
}
|
|
16109
16332
|
}
|
|
16110
16333
|
async function loadFileAsDataUrl(filePath) {
|
|
16111
|
-
const buf =
|
|
16334
|
+
const buf = readFileSync15(filePath);
|
|
16112
16335
|
if (typeof Bun !== "undefined" && typeof Bun.Image !== "undefined") {
|
|
16113
16336
|
try {
|
|
16114
16337
|
const img = new Bun.Image(buf);
|
|
@@ -16535,7 +16758,7 @@ var init_loader = __esm(() => {
|
|
|
16535
16758
|
|
|
16536
16759
|
// src/modules/plugins/builtin/lint-on-write.ts
|
|
16537
16760
|
import { spawn as spawn5, execSync } from "child_process";
|
|
16538
|
-
import { existsSync as existsSync31, readFileSync as
|
|
16761
|
+
import { existsSync as existsSync31, readFileSync as readFileSync16 } from "fs";
|
|
16539
16762
|
import { resolve as resolve18, extname as extname4, join as join25 } from "path";
|
|
16540
16763
|
import { platform as platform5 } from "os";
|
|
16541
16764
|
function contentHash(content) {
|
|
@@ -16600,7 +16823,7 @@ class LintOnWritePlugin {
|
|
|
16600
16823
|
if (ext === ".ts" || ext === ".tsx" || ext === ".cts" || ext === ".mts") {
|
|
16601
16824
|
let content = "";
|
|
16602
16825
|
try {
|
|
16603
|
-
content =
|
|
16826
|
+
content = readFileSync16(filePath, "utf-8");
|
|
16604
16827
|
} catch {
|
|
16605
16828
|
return null;
|
|
16606
16829
|
}
|
|
@@ -16643,7 +16866,7 @@ class LintOnWritePlugin {
|
|
|
16643
16866
|
if (!existsSync31(packageJsonPath)) {
|
|
16644
16867
|
return;
|
|
16645
16868
|
}
|
|
16646
|
-
const packageJson = JSON.parse(
|
|
16869
|
+
const packageJson = JSON.parse(readFileSync16(packageJsonPath, "utf-8"));
|
|
16647
16870
|
const lintScript = packageJson.scripts?.lint;
|
|
16648
16871
|
if (!lintScript) {
|
|
16649
16872
|
return;
|
|
@@ -16779,25 +17002,6 @@ function generatePlanId() {
|
|
|
16779
17002
|
}
|
|
16780
17003
|
|
|
16781
17004
|
class PlanCreator {
|
|
16782
|
-
static isMultiStep(task) {
|
|
16783
|
-
const fileCount = (task.match(/\b[\w./-]+\.[a-z]+\b/gi) || []).length;
|
|
16784
|
-
if (fileCount > 1)
|
|
16785
|
-
return true;
|
|
16786
|
-
const actionWords = [
|
|
16787
|
-
"implement",
|
|
16788
|
-
"create",
|
|
16789
|
-
"add",
|
|
16790
|
-
"build",
|
|
16791
|
-
"setup",
|
|
16792
|
-
"configure",
|
|
16793
|
-
"write",
|
|
16794
|
-
"make",
|
|
16795
|
-
"develop"
|
|
16796
|
-
];
|
|
16797
|
-
const words = task.split(/\s+/);
|
|
16798
|
-
const hasActionWord = actionWords.some((w) => task.toLowerCase().includes(w));
|
|
16799
|
-
return hasActionWord && words.length > 8;
|
|
16800
|
-
}
|
|
16801
17005
|
static createPlan(title, stepDescriptions, baseDir, kinds) {
|
|
16802
17006
|
const stepCount = stepDescriptions.length;
|
|
16803
17007
|
return {
|
|
@@ -16818,16 +17022,17 @@ class PlanCreator {
|
|
|
16818
17022
|
const baseTitle = plan.title.replace(/^\[\d+[^]]*\]\s*/, "");
|
|
16819
17023
|
const newTitle = title || baseTitle;
|
|
16820
17024
|
const totalSteps = kept.length + newSteps.length;
|
|
16821
|
-
const added = newSteps.map((desc
|
|
16822
|
-
id:
|
|
17025
|
+
const added = newSteps.map((desc) => ({
|
|
17026
|
+
id: -1,
|
|
16823
17027
|
description: desc,
|
|
16824
17028
|
status: "pending",
|
|
16825
17029
|
kind: "create"
|
|
16826
17030
|
}));
|
|
17031
|
+
const steps = [...kept, ...added].map((s, i) => ({ ...s, id: i + 1 }));
|
|
16827
17032
|
return {
|
|
16828
17033
|
id: plan.id,
|
|
16829
17034
|
title: `[${totalSteps}] ${newTitle}`,
|
|
16830
|
-
steps
|
|
17035
|
+
steps,
|
|
16831
17036
|
createdAt: plan.createdAt,
|
|
16832
17037
|
baseDir: plan.baseDir,
|
|
16833
17038
|
name: plan.name
|
|
@@ -16835,10 +17040,13 @@ class PlanCreator {
|
|
|
16835
17040
|
}
|
|
16836
17041
|
static toPromptBlock(plan, currentStepIndex) {
|
|
16837
17042
|
const date = plan.createdAt.slice(0, 10);
|
|
17043
|
+
const doneCount = plan.steps.filter((s) => s.status === "done").length;
|
|
17044
|
+
const terminal = plan.steps.every((s) => s.status === "done" || s.status === "skipped");
|
|
17045
|
+
const progress = terminal ? `${doneCount}/${plan.steps.length} done, complete` : `${doneCount}/${plan.steps.length} done, current: step ${currentStepIndex + 1}`;
|
|
16838
17046
|
const lines = [
|
|
16839
17047
|
`[${plan.id}] ${plan.title}`,
|
|
16840
17048
|
`Dir: ${plan.baseDir}`,
|
|
16841
|
-
`Created: ${date} | Progress: ${
|
|
17049
|
+
`Created: ${date} | Progress: ${progress}`,
|
|
16842
17050
|
``
|
|
16843
17051
|
];
|
|
16844
17052
|
for (const step of plan.steps) {
|
|
@@ -16915,11 +17123,11 @@ class PlanTracker {
|
|
|
16915
17123
|
var init_tracker = () => {};
|
|
16916
17124
|
|
|
16917
17125
|
// src/modules/execution/plan-store.ts
|
|
16918
|
-
import { readFileSync as
|
|
17126
|
+
import { readFileSync as readFileSync17, writeFileSync as writeFileSync10, mkdirSync as mkdirSync14, existsSync as existsSync32, readdirSync as readdirSync10, rmSync } from "fs";
|
|
16919
17127
|
import { join as join26 } from "path";
|
|
16920
17128
|
function readPlanFile(path, fallbackBaseDir) {
|
|
16921
17129
|
try {
|
|
16922
|
-
const raw =
|
|
17130
|
+
const raw = readFileSync17(path, "utf-8");
|
|
16923
17131
|
if (!raw.trim())
|
|
16924
17132
|
return null;
|
|
16925
17133
|
const parsed = JSON.parse(raw);
|
|
@@ -17062,6 +17270,41 @@ class PlanStore {
|
|
|
17062
17270
|
return { plan: archived, status: "archived" };
|
|
17063
17271
|
return null;
|
|
17064
17272
|
}
|
|
17273
|
+
deletePlan(id) {
|
|
17274
|
+
const active = this.loadActive();
|
|
17275
|
+
if (active && active.id === id) {
|
|
17276
|
+
this.clearActive();
|
|
17277
|
+
return "active";
|
|
17278
|
+
}
|
|
17279
|
+
const draftPath = join26(this.draftsDir, `${id}.json`);
|
|
17280
|
+
if (existsSync32(draftPath)) {
|
|
17281
|
+
rmSync(draftPath, { force: true });
|
|
17282
|
+
return "draft";
|
|
17283
|
+
}
|
|
17284
|
+
const archivedPath = join26(this.archiveDir, `${id}.json`);
|
|
17285
|
+
if (existsSync32(archivedPath)) {
|
|
17286
|
+
rmSync(archivedPath, { force: true });
|
|
17287
|
+
return "archived";
|
|
17288
|
+
}
|
|
17289
|
+
return null;
|
|
17290
|
+
}
|
|
17291
|
+
purgeAll() {
|
|
17292
|
+
let n = 0;
|
|
17293
|
+
const active = this.loadActive();
|
|
17294
|
+
if (active) {
|
|
17295
|
+
this.clearActive();
|
|
17296
|
+
n++;
|
|
17297
|
+
}
|
|
17298
|
+
for (const p of this.listDrafts()) {
|
|
17299
|
+
this.removeDraft(p.id);
|
|
17300
|
+
n++;
|
|
17301
|
+
}
|
|
17302
|
+
for (const p of this.listArchived()) {
|
|
17303
|
+
this.removeArchived(p.id);
|
|
17304
|
+
n++;
|
|
17305
|
+
}
|
|
17306
|
+
return n;
|
|
17307
|
+
}
|
|
17065
17308
|
}
|
|
17066
17309
|
var LEGACY_FILE = "plan.json";
|
|
17067
17310
|
var init_plan_store = () => {};
|
|
@@ -17135,16 +17378,18 @@ function createPlanToolDefinitions(deps) {
|
|
|
17135
17378
|
{
|
|
17136
17379
|
name: "plan",
|
|
17137
17380
|
alwaysOn: true,
|
|
17138
|
-
description: `Create, update, show, abort, list, switch, or re-plan multi-step plans.
|
|
17381
|
+
description: `Create, update, show, abort, list, switch, delete, purge, or re-plan multi-step plans.
|
|
17139
17382
|
|
|
17140
17383
|
Actions:
|
|
17141
17384
|
- create: Start a new plan. Previous active plan is auto-preserved: incomplete → draft, complete → archive.
|
|
17142
17385
|
- update: Mark step status (done/failed/skipped), or rebuild plan with new steps.
|
|
17143
17386
|
- show: Print current plan checklist.
|
|
17144
|
-
- abort: Archive current plan and clear active slot.
|
|
17387
|
+
- abort: Archive the current plan (or the plan given by id) and clear the active slot.
|
|
17145
17388
|
- list: Show all plans (active, drafts, archived) with progress.
|
|
17146
17389
|
- switch: Make a different plan active (by plan id).
|
|
17147
17390
|
- re-plan: Iterative replanning: keep completed steps, replace remaining with new steps.
|
|
17391
|
+
- delete: Permanently delete a plan by id (plan delete id=plan_xxx).
|
|
17392
|
+
- purge: Delete ALL plans (active, drafts, archived).
|
|
17148
17393
|
|
|
17149
17394
|
Write CONCRETE steps with exact file paths and commands:
|
|
17150
17395
|
- Specify WHICH files to create with exact paths (e.g. "create src/components/Header.tsx with navigation and logo")
|
|
@@ -17159,7 +17404,17 @@ Write CONCRETE steps with exact file paths and commands:
|
|
|
17159
17404
|
properties: {
|
|
17160
17405
|
action: {
|
|
17161
17406
|
type: "string",
|
|
17162
|
-
enum: [
|
|
17407
|
+
enum: [
|
|
17408
|
+
"create",
|
|
17409
|
+
"update",
|
|
17410
|
+
"show",
|
|
17411
|
+
"abort",
|
|
17412
|
+
"list",
|
|
17413
|
+
"switch",
|
|
17414
|
+
"re-plan",
|
|
17415
|
+
"delete",
|
|
17416
|
+
"purge"
|
|
17417
|
+
]
|
|
17163
17418
|
},
|
|
17164
17419
|
title: { type: "string" },
|
|
17165
17420
|
steps: { type: "array", items: { type: "string" } },
|
|
@@ -17187,6 +17442,8 @@ Write CONCRETE steps with exact file paths and commands:
|
|
|
17187
17442
|
const namePart = m.name ? ` (${m.name})` : "";
|
|
17188
17443
|
return `${icon} ${m.id}${namePart} — ${m.title} ${m.doneCount}/${m.stepCount}`;
|
|
17189
17444
|
});
|
|
17445
|
+
lines.push("");
|
|
17446
|
+
lines.push(t("plan.list_legend"));
|
|
17190
17447
|
return {
|
|
17191
17448
|
success: true,
|
|
17192
17449
|
output: `${t("plan.list_header")}
|
|
@@ -17206,6 +17463,16 @@ ${lines.join(`
|
|
|
17206
17463
|
output: t("plan.not_found", { id: planId })
|
|
17207
17464
|
};
|
|
17208
17465
|
}
|
|
17466
|
+
if (found.status === "active") {
|
|
17467
|
+
return {
|
|
17468
|
+
success: true,
|
|
17469
|
+
output: t("plan.already_active", {
|
|
17470
|
+
id: found.plan.id,
|
|
17471
|
+
title: found.plan.title
|
|
17472
|
+
}),
|
|
17473
|
+
display: deps.trackerRef.current?.toPromptBlock()
|
|
17474
|
+
};
|
|
17475
|
+
}
|
|
17209
17476
|
deps.preserveActive();
|
|
17210
17477
|
if (found.status === "draft") {
|
|
17211
17478
|
deps.store.removeDraft(found.plan.id);
|
|
@@ -17213,7 +17480,7 @@ ${lines.join(`
|
|
|
17213
17480
|
deps.store.removeArchived(found.plan.id);
|
|
17214
17481
|
}
|
|
17215
17482
|
deps.setPlan(found.plan);
|
|
17216
|
-
const display =
|
|
17483
|
+
const display = deps.trackerRef.current?.toPromptBlock();
|
|
17217
17484
|
return {
|
|
17218
17485
|
success: true,
|
|
17219
17486
|
output: t("plan.switched", {
|
|
@@ -17236,7 +17503,7 @@ ${lines.join(`
|
|
|
17236
17503
|
const replanned = PlanCreator.replan(oldPlan, newSteps, args.title ? String(args.title) : undefined);
|
|
17237
17504
|
const keptCount = replanned.steps.length - newSteps.length;
|
|
17238
17505
|
deps.setPlan(replanned);
|
|
17239
|
-
const display =
|
|
17506
|
+
const display = deps.trackerRef.current?.toPromptBlock();
|
|
17240
17507
|
return {
|
|
17241
17508
|
success: true,
|
|
17242
17509
|
output: t("plan.replanned", {
|
|
@@ -17349,6 +17616,7 @@ ${display}`,
|
|
|
17349
17616
|
if (tracker.isComplete()) {
|
|
17350
17617
|
const plan = tracker.getPlan();
|
|
17351
17618
|
deps.store.archivePlan(plan);
|
|
17619
|
+
deps.recordCompleted(plan);
|
|
17352
17620
|
deps.trackerRef.current = null;
|
|
17353
17621
|
const done = plan.steps.filter((s) => s.status === "done").length;
|
|
17354
17622
|
return {
|
|
@@ -17415,9 +17683,13 @@ ${progress2}`,
|
|
|
17415
17683
|
tracker.addNote(Number(args.step), String(args.note));
|
|
17416
17684
|
tracker.syncCurrentStep();
|
|
17417
17685
|
deps.store.saveActive(tracker.getPlan());
|
|
17686
|
+
const vacuousGate = status === "done" && !deps.hasStepDeliverables(target);
|
|
17687
|
+
const vacuousNote = vacuousGate ? `
|
|
17688
|
+
${t("plan.no_deliverables", { step: String(stepId) })}` : "";
|
|
17418
17689
|
if (tracker.isComplete()) {
|
|
17419
17690
|
const plan = tracker.getPlan();
|
|
17420
17691
|
deps.store.archivePlan(plan);
|
|
17692
|
+
deps.recordCompleted(plan);
|
|
17421
17693
|
deps.trackerRef.current = null;
|
|
17422
17694
|
const done = plan.steps.filter((s) => s.status === "done").length;
|
|
17423
17695
|
return {
|
|
@@ -17427,7 +17699,7 @@ ${t("plan.completed_archived", {
|
|
|
17427
17699
|
id: plan.id,
|
|
17428
17700
|
done: String(done),
|
|
17429
17701
|
total: String(plan.steps.length)
|
|
17430
|
-
})}`
|
|
17702
|
+
})}${vacuousNote}`
|
|
17431
17703
|
};
|
|
17432
17704
|
}
|
|
17433
17705
|
const progress = tracker.getProgressString();
|
|
@@ -17436,7 +17708,7 @@ ${t("plan.completed_archived", {
|
|
|
17436
17708
|
return {
|
|
17437
17709
|
success: true,
|
|
17438
17710
|
output: `${t("plan.step_status", { step: String(args.step), status: String(args.status || "done") })}
|
|
17439
|
-
${progress}`,
|
|
17711
|
+
${progress}${vacuousNote}`,
|
|
17440
17712
|
display
|
|
17441
17713
|
};
|
|
17442
17714
|
}
|
|
@@ -17450,7 +17722,7 @@ ${progress}`,
|
|
|
17450
17722
|
}
|
|
17451
17723
|
const plan = PlanCreator.createPlan(title, steps, deps.baseDir, parsed.kinds ?? []);
|
|
17452
17724
|
deps.setPlan(plan);
|
|
17453
|
-
const display =
|
|
17725
|
+
const display = deps.trackerRef.current?.toPromptBlock();
|
|
17454
17726
|
const output = t("plan.updated", {
|
|
17455
17727
|
title,
|
|
17456
17728
|
steps: String(steps.length)
|
|
@@ -17462,14 +17734,71 @@ ${progress}`,
|
|
|
17462
17734
|
};
|
|
17463
17735
|
}
|
|
17464
17736
|
if (action === "abort") {
|
|
17737
|
+
const planId = args.id ? String(args.id) : "";
|
|
17738
|
+
if (planId) {
|
|
17739
|
+
const found = deps.store.find(planId);
|
|
17740
|
+
if (!found) {
|
|
17741
|
+
return {
|
|
17742
|
+
success: false,
|
|
17743
|
+
output: t("plan.not_found", { id: planId })
|
|
17744
|
+
};
|
|
17745
|
+
}
|
|
17746
|
+
if (found.status === "archived") {
|
|
17747
|
+
return {
|
|
17748
|
+
success: false,
|
|
17749
|
+
output: t("plan.already_archived", { id: planId })
|
|
17750
|
+
};
|
|
17751
|
+
}
|
|
17752
|
+
deps.store.archivePlan(found.plan);
|
|
17753
|
+
if (found.status === "active") {
|
|
17754
|
+
deps.trackerRef.current = null;
|
|
17755
|
+
deps.clearCompleted();
|
|
17756
|
+
}
|
|
17757
|
+
return {
|
|
17758
|
+
success: true,
|
|
17759
|
+
output: t("plan.aborted_id", { id: found.plan.id })
|
|
17760
|
+
};
|
|
17761
|
+
}
|
|
17465
17762
|
const tracker = deps.trackerRef.current;
|
|
17466
|
-
if (tracker) {
|
|
17467
|
-
|
|
17763
|
+
if (!tracker) {
|
|
17764
|
+
return { success: false, output: t("plan.no_active") };
|
|
17468
17765
|
}
|
|
17766
|
+
deps.store.archivePlan(tracker.getPlan());
|
|
17469
17767
|
deps.trackerRef.current = null;
|
|
17470
17768
|
deps.store.clearActive();
|
|
17769
|
+
deps.clearCompleted();
|
|
17471
17770
|
return { success: true, output: t("plan.aborted") };
|
|
17472
17771
|
}
|
|
17772
|
+
if (action === "delete") {
|
|
17773
|
+
const planId = String(args.id || "");
|
|
17774
|
+
if (!planId) {
|
|
17775
|
+
return { success: false, output: t("plan.delete_no_id") };
|
|
17776
|
+
}
|
|
17777
|
+
const deleted = deps.store.deletePlan(planId);
|
|
17778
|
+
if (!deleted) {
|
|
17779
|
+
return {
|
|
17780
|
+
success: false,
|
|
17781
|
+
output: t("plan.not_found", { id: planId })
|
|
17782
|
+
};
|
|
17783
|
+
}
|
|
17784
|
+
if (deleted === "active") {
|
|
17785
|
+
deps.trackerRef.current = null;
|
|
17786
|
+
deps.clearCompleted();
|
|
17787
|
+
}
|
|
17788
|
+
return {
|
|
17789
|
+
success: true,
|
|
17790
|
+
output: t("plan.deleted", { id: planId })
|
|
17791
|
+
};
|
|
17792
|
+
}
|
|
17793
|
+
if (action === "purge") {
|
|
17794
|
+
const count = deps.store.purgeAll();
|
|
17795
|
+
deps.trackerRef.current = null;
|
|
17796
|
+
deps.clearCompleted();
|
|
17797
|
+
return {
|
|
17798
|
+
success: true,
|
|
17799
|
+
output: t("plan.purged", { count: String(count) })
|
|
17800
|
+
};
|
|
17801
|
+
}
|
|
17473
17802
|
if (!deps.trackerRef.current) {
|
|
17474
17803
|
return { success: false, output: t("plan.no_active") };
|
|
17475
17804
|
}
|
|
@@ -17660,6 +17989,8 @@ function createExecutionPlugin(deps) {
|
|
|
17660
17989
|
deps.state.consecutivePlanWarnings = 0;
|
|
17661
17990
|
deps.state.lastStepId = -1;
|
|
17662
17991
|
deps.state.stuckNotified = false;
|
|
17992
|
+
deps.state.mutationsWithoutPlan = 0;
|
|
17993
|
+
deps.state.planNudgeSent = false;
|
|
17663
17994
|
} else {
|
|
17664
17995
|
const step = deps.trackerRef.current?.getCurrentStep();
|
|
17665
17996
|
if (deps.trackerRef.current && step) {
|
|
@@ -17670,22 +18001,21 @@ function createExecutionPlugin(deps) {
|
|
|
17670
18001
|
}
|
|
17671
18002
|
deps.stuckDetector.setCurrentStep(step.id, step.description);
|
|
17672
18003
|
deps.stuckDetector.recordIteration(step.id);
|
|
18004
|
+
deps.state.mutationsWithoutPlan = 0;
|
|
18005
|
+
deps.state.planNudgeSent = false;
|
|
17673
18006
|
} else {
|
|
17674
18007
|
deps.stuckDetector.reset();
|
|
17675
18008
|
deps.state.consecutivePlanWarnings = 0;
|
|
17676
18009
|
deps.state.lastStepId = -1;
|
|
17677
18010
|
deps.state.stuckNotified = false;
|
|
17678
|
-
const
|
|
17679
|
-
if (
|
|
18011
|
+
const mutations = deps.state.mutationsWithoutPlan;
|
|
18012
|
+
if (mutations >= PLAN_NUDGE_THRESHOLD && !deps.state.planNudgeSent && ctx.contextManager) {
|
|
18013
|
+
deps.state.planNudgeSent = true;
|
|
17680
18014
|
ctx.contextManager.addMessage({
|
|
17681
18015
|
role: "user",
|
|
17682
|
-
content: `<system-summary
|
|
17683
|
-
|
|
17684
|
-
|
|
17685
|
-
if (iter >= 6 && !deps.trackerRef.current && ctx.contextManager) {
|
|
17686
|
-
ctx.contextManager.addMessage({
|
|
17687
|
-
role: "user",
|
|
17688
|
-
content: `<system-summary>STOP. ${iter} iterations without a plan. You MUST call plan create RIGHT NOW. No more tool calls until you create a plan.</system-summary>`
|
|
18016
|
+
content: `<system-summary>${t("exec.plan_nudge", {
|
|
18017
|
+
count: String(mutations)
|
|
18018
|
+
})}</system-summary>`
|
|
17689
18019
|
});
|
|
17690
18020
|
}
|
|
17691
18021
|
}
|
|
@@ -17778,6 +18108,9 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
17778
18108
|
const args = ctx?.args;
|
|
17779
18109
|
if (toolName && args) {
|
|
17780
18110
|
deps.stuckDetector.recordToolCall(toolName, args);
|
|
18111
|
+
if (!deps.trackerRef.current && (toolName === "write_file" || toolName === "edit_file" || toolName === "bash" || toolName === "download_file")) {
|
|
18112
|
+
deps.state.mutationsWithoutPlan++;
|
|
18113
|
+
}
|
|
17781
18114
|
}
|
|
17782
18115
|
},
|
|
17783
18116
|
onAfterTool: (ctx, call, result) => {
|
|
@@ -17785,7 +18118,8 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
17785
18118
|
deps.stuckDetector.recordBashOutput(String(call.arguments?.command ?? ""), String(result.output ?? ""));
|
|
17786
18119
|
}
|
|
17787
18120
|
const toolText = String(result.output ?? "");
|
|
17788
|
-
|
|
18121
|
+
const hasTypeError = /error TS\d+|\[Project typecheck failed\]|\[Syntax check failed\]/.test(toolText);
|
|
18122
|
+
if (hasTypeError) {
|
|
17789
18123
|
deps.stuckDetector.recordToolError(call.name, toolText.slice(0, 300));
|
|
17790
18124
|
}
|
|
17791
18125
|
if (!result.success) {
|
|
@@ -17803,7 +18137,9 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
17803
18137
|
}
|
|
17804
18138
|
}
|
|
17805
18139
|
}
|
|
17806
|
-
|
|
18140
|
+
if (!hasTypeError) {
|
|
18141
|
+
deps.stuckDetector.recordToolError(call.name, result.output);
|
|
18142
|
+
}
|
|
17807
18143
|
const actionableHints = deps.stuckDetector.getActionableHints();
|
|
17808
18144
|
const alternative = deps.stuckDetector.getToolAlternative();
|
|
17809
18145
|
if (actionableHints.length > 0 || alternative) {
|
|
@@ -17857,10 +18193,11 @@ Tool "${deps.stuckDetector.getLastFailedTool()}" is failing. Try "${alternative}
|
|
|
17857
18193
|
}
|
|
17858
18194
|
deps.advancePlanIfStepComplete(ctx.contextManager, ctx.sessionLog);
|
|
17859
18195
|
}
|
|
18196
|
+
deps.maybeSearchError(ctx, call);
|
|
17860
18197
|
}
|
|
17861
18198
|
};
|
|
17862
18199
|
}
|
|
17863
|
-
var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3, FORCE_SKIP_THRESHOLD = 10;
|
|
18200
|
+
var STUCK_RECOVERY_COOLDOWN = 5, MAX_PLAN_WARNINGS_BEFORE_BLOCK = 3, FORCE_SKIP_THRESHOLD = 10, PLAN_NUDGE_THRESHOLD = 2;
|
|
17864
18201
|
var init_execution_plugin = __esm(() => {
|
|
17865
18202
|
init_i18n();
|
|
17866
18203
|
init_bash();
|
|
@@ -17868,7 +18205,7 @@ var init_execution_plugin = __esm(() => {
|
|
|
17868
18205
|
});
|
|
17869
18206
|
|
|
17870
18207
|
// src/modules/execution/module.ts
|
|
17871
|
-
import { existsSync as existsSync33, readFileSync as
|
|
18208
|
+
import { existsSync as existsSync33, readFileSync as readFileSync18 } from "fs";
|
|
17872
18209
|
import { resolve as resolve19 } from "path";
|
|
17873
18210
|
|
|
17874
18211
|
class ExecutionModule {
|
|
@@ -17880,14 +18217,23 @@ class ExecutionModule {
|
|
|
17880
18217
|
store;
|
|
17881
18218
|
baseDir;
|
|
17882
18219
|
_auditSkipsRemaining = 0;
|
|
18220
|
+
completedPlan = null;
|
|
17883
18221
|
pendingMessages = [];
|
|
17884
18222
|
forbiddenBashFailures = new Map;
|
|
18223
|
+
searchRunner;
|
|
18224
|
+
webSearchThreshold;
|
|
18225
|
+
searchesThisSession = 0;
|
|
18226
|
+
retryWebSearchSignatures = new Set;
|
|
18227
|
+
lastErrorSearchAt = 0;
|
|
18228
|
+
errorSearchCooldownMs;
|
|
17885
18229
|
state = {
|
|
17886
18230
|
lastRecoveryIteration: -STUCK_RECOVERY_COOLDOWN,
|
|
17887
18231
|
consecutivePlanWarnings: 0,
|
|
17888
18232
|
lastStepId: -1,
|
|
17889
18233
|
stuckNotified: false,
|
|
17890
|
-
depsGateHints: new Map
|
|
18234
|
+
depsGateHints: new Map,
|
|
18235
|
+
mutationsWithoutPlan: 0,
|
|
18236
|
+
planNudgeSent: false
|
|
17891
18237
|
};
|
|
17892
18238
|
trackerRef = (() => {
|
|
17893
18239
|
const self = this;
|
|
@@ -17900,18 +18246,29 @@ class ExecutionModule {
|
|
|
17900
18246
|
}
|
|
17901
18247
|
};
|
|
17902
18248
|
})();
|
|
17903
|
-
constructor(baseDir, stuckThreshold = 6) {
|
|
18249
|
+
constructor(baseDir, stuckThreshold = 6, webSearchThreshold = 5, searchRunner = performWebSearch, errorSearchCooldownMs = ERROR_SEARCH_MIN_INTERVAL_MS) {
|
|
17904
18250
|
this.baseDir = baseDir;
|
|
17905
18251
|
this.verifier = new StepVerifier(baseDir);
|
|
17906
|
-
this.stuckDetector = new StuckDetector(stuckThreshold);
|
|
18252
|
+
this.stuckDetector = new StuckDetector(stuckThreshold, 3, webSearchThreshold);
|
|
17907
18253
|
this.auditor = new Auditor(baseDir);
|
|
17908
18254
|
this.store = new PlanStore(baseDir);
|
|
18255
|
+
this.webSearchThreshold = webSearchThreshold;
|
|
18256
|
+
this.searchRunner = searchRunner;
|
|
18257
|
+
this.errorSearchCooldownMs = errorSearchCooldownMs;
|
|
17909
18258
|
}
|
|
17910
18259
|
setPlan(plan) {
|
|
17911
18260
|
this.tracker = new PlanTracker(plan);
|
|
18261
|
+
this.tracker.syncCurrentStep();
|
|
17912
18262
|
this.store.saveActive(plan);
|
|
18263
|
+
this.completedPlan = null;
|
|
17913
18264
|
this._auditSkipsRemaining = 0;
|
|
17914
18265
|
}
|
|
18266
|
+
recordCompleted(plan) {
|
|
18267
|
+
this.completedPlan = plan;
|
|
18268
|
+
}
|
|
18269
|
+
clearCompleted() {
|
|
18270
|
+
this.completedPlan = null;
|
|
18271
|
+
}
|
|
17915
18272
|
restorePlan() {
|
|
17916
18273
|
const plan = this.store.loadActive();
|
|
17917
18274
|
if (!plan)
|
|
@@ -17936,9 +18293,75 @@ class ExecutionModule {
|
|
|
17936
18293
|
getStuckDetector() {
|
|
17937
18294
|
return this.stuckDetector;
|
|
17938
18295
|
}
|
|
18296
|
+
maybeSearchError(ctx, call) {
|
|
18297
|
+
if (ctx.config?.webSearch?.enabled === false)
|
|
18298
|
+
return;
|
|
18299
|
+
const cfg = ctx.config?.errorWebSearch;
|
|
18300
|
+
if (!cfg?.enabled)
|
|
18301
|
+
return;
|
|
18302
|
+
const sig = this.stuckDetector.getRepeatedErrorSignature();
|
|
18303
|
+
if (!sig)
|
|
18304
|
+
return;
|
|
18305
|
+
if (this.stuckDetector.hasErrorSearched(sig) && !this.retryWebSearchSignatures.has(sig))
|
|
18306
|
+
return;
|
|
18307
|
+
if (this.searchesThisSession >= (cfg.maxSearchesPerSession ?? 3))
|
|
18308
|
+
return;
|
|
18309
|
+
const lastError = this.stuckDetector.getLastErrorOutput();
|
|
18310
|
+
if (!isSearchableError(lastError)) {
|
|
18311
|
+
ctx.logger?.debug(t("exec.error_search_no_query"));
|
|
18312
|
+
return;
|
|
18313
|
+
}
|
|
18314
|
+
const now = Date.now();
|
|
18315
|
+
if (now - this.lastErrorSearchAt < this.errorSearchCooldownMs)
|
|
18316
|
+
return;
|
|
18317
|
+
const stepDesc = this.tracker?.getCurrentStep()?.description ?? "";
|
|
18318
|
+
const query = buildSearchQuery(stepDesc, this.stuckDetector.getLastBashCommand(), lastError, call.name, cfg.maxQueryChars ?? 200);
|
|
18319
|
+
const count = this.stuckDetector.getErrorSignatureCount(sig);
|
|
18320
|
+
this.stuckDetector.markErrorSearched(sig);
|
|
18321
|
+
this.searchesThisSession++;
|
|
18322
|
+
this.lastErrorSearchAt = now;
|
|
18323
|
+
const networkConfig = getSessionSecurityConfig(ctx.config, ctx.sessionContext).network;
|
|
18324
|
+
this.searchRunner(query, cfg.maxResults ?? 5, networkConfig, cfg.requestTimeoutMs ?? 1e4).then((res) => {
|
|
18325
|
+
if (!res.success || res.results.length === 0) {
|
|
18326
|
+
if (!this.retryWebSearchSignatures.has(sig)) {
|
|
18327
|
+
this.retryWebSearchSignatures.add(sig);
|
|
18328
|
+
this.stuckDetector.unmarkErrorSearched(sig);
|
|
18329
|
+
}
|
|
18330
|
+
ctx.logger?.warn(t("exec.error_search_failed", { query }));
|
|
18331
|
+
ctx.sessionLog?.plan("web-search", `empty/failed: ${query}`);
|
|
18332
|
+
return;
|
|
18333
|
+
}
|
|
18334
|
+
const resultsText = res.results.map((r, i) => `${i + 1}. ${r.title} — ${r.url}
|
|
18335
|
+
${r.snippet}`).join(`
|
|
18336
|
+
`);
|
|
18337
|
+
this.pendingMessages.push({
|
|
18338
|
+
role: "user",
|
|
18339
|
+
content: `<system-summary>${t("exec.error_search_results", {
|
|
18340
|
+
sig,
|
|
18341
|
+
count: String(count),
|
|
18342
|
+
query,
|
|
18343
|
+
results: resultsText
|
|
18344
|
+
})}</system-summary>`
|
|
18345
|
+
});
|
|
18346
|
+
}).catch((e) => ctx.logger?.warn(`error web search: ${e.message}`));
|
|
18347
|
+
}
|
|
17939
18348
|
async runFinalAudit() {
|
|
17940
|
-
if (!this.tracker)
|
|
17941
|
-
|
|
18349
|
+
if (!this.tracker) {
|
|
18350
|
+
if (!this.completedPlan)
|
|
18351
|
+
return null;
|
|
18352
|
+
const plan2 = this.completedPlan;
|
|
18353
|
+
const audit2 = await this.auditor.audit(plan2);
|
|
18354
|
+
const pendingSteps2 = plan2.steps.flatMap((s) => s.status !== "done" && s.status !== "skipped" ? [`${s.id}. ${s.description}`] : []);
|
|
18355
|
+
const done2 = plan2.steps.filter((s) => s.status === "done").length;
|
|
18356
|
+
return {
|
|
18357
|
+
passed: audit2.passed && pendingSteps2.length === 0,
|
|
18358
|
+
done: done2,
|
|
18359
|
+
total: plan2.steps.length,
|
|
18360
|
+
pendingSteps: pendingSteps2,
|
|
18361
|
+
missingFiles: audit2.missingFiles,
|
|
18362
|
+
summary: audit2.summary
|
|
18363
|
+
};
|
|
18364
|
+
}
|
|
17942
18365
|
if (this._auditSkipsRemaining > 0) {
|
|
17943
18366
|
this._auditSkipsRemaining--;
|
|
17944
18367
|
return null;
|
|
@@ -17986,6 +18409,9 @@ class ExecutionModule {
|
|
|
17986
18409
|
trackerRef: this.trackerRef,
|
|
17987
18410
|
preserveActive: () => this.preserveActive(),
|
|
17988
18411
|
setPlan: (p) => this.setPlan(p),
|
|
18412
|
+
recordCompleted: (p) => this.recordCompleted(p),
|
|
18413
|
+
clearCompleted: () => this.clearCompleted(),
|
|
18414
|
+
hasStepDeliverables: (s) => this.hasStepDeliverables(s),
|
|
17989
18415
|
missingStepDeliverables: (s) => this.missingStepDeliverables(s),
|
|
17990
18416
|
stillExistingDeliverables: (s) => this.stillExistingDeliverables(s),
|
|
17991
18417
|
parseKinds: (a, st) => this.parseKinds(a, st),
|
|
@@ -18001,7 +18427,8 @@ class ExecutionModule {
|
|
|
18001
18427
|
forbiddenBashFailures: this.forbiddenBashFailures,
|
|
18002
18428
|
state: this.state,
|
|
18003
18429
|
checkPlanAlignment: (call) => this.checkPlanAlignment(call),
|
|
18004
|
-
advancePlanIfStepComplete: (cm, sl) => this.advancePlanIfStepComplete(cm, sl)
|
|
18430
|
+
advancePlanIfStepComplete: (cm, sl) => this.advancePlanIfStepComplete(cm, sl),
|
|
18431
|
+
maybeSearchError: (ctx, call) => this.maybeSearchError(ctx, call)
|
|
18005
18432
|
});
|
|
18006
18433
|
}
|
|
18007
18434
|
preserveActive() {
|
|
@@ -18036,7 +18463,7 @@ class ExecutionModule {
|
|
|
18036
18463
|
const stepPaths = extractFileLikeTokens(stripUrls(step.description)).map((p) => p.toLowerCase());
|
|
18037
18464
|
if (stepPaths.length === 0)
|
|
18038
18465
|
return null;
|
|
18039
|
-
const argStr =
|
|
18466
|
+
const argStr = this.pathArgStrings(call.arguments).join(" ");
|
|
18040
18467
|
const callPaths = extractFileLikeTokens(stripUrls(argStr)).map((p) => p.toLowerCase());
|
|
18041
18468
|
if (callPaths.length === 0)
|
|
18042
18469
|
return null;
|
|
@@ -18061,13 +18488,31 @@ class ExecutionModule {
|
|
|
18061
18488
|
tool: call.name
|
|
18062
18489
|
});
|
|
18063
18490
|
}
|
|
18491
|
+
pathArgStrings(args) {
|
|
18492
|
+
if (!args)
|
|
18493
|
+
return [];
|
|
18494
|
+
const out = [];
|
|
18495
|
+
for (const [key, value] of Object.entries(args)) {
|
|
18496
|
+
if (!/path|file|dir|src|dst|source|target|input|output|destination|glob|workdir|cwd|command|pattern|query/i.test(key)) {
|
|
18497
|
+
continue;
|
|
18498
|
+
}
|
|
18499
|
+
if (typeof value === "string")
|
|
18500
|
+
out.push(value);
|
|
18501
|
+
else if (Array.isArray(value)) {
|
|
18502
|
+
for (const v of value)
|
|
18503
|
+
if (typeof v === "string")
|
|
18504
|
+
out.push(v);
|
|
18505
|
+
}
|
|
18506
|
+
}
|
|
18507
|
+
return out;
|
|
18508
|
+
}
|
|
18064
18509
|
advancePlanIfStepComplete(contextManager, sessionLog) {
|
|
18065
18510
|
const step = this.tracker?.getCurrentStep();
|
|
18066
18511
|
if (!step)
|
|
18067
18512
|
return;
|
|
18068
18513
|
const stepText = step.description.toLowerCase();
|
|
18069
18514
|
const stepPaths = extractFileLikeTokens(stripUrls(step.description)) || [];
|
|
18070
|
-
const isDepsStep =
|
|
18515
|
+
const isDepsStep = /(?:npm|bun|yarn|pnpm|pip|pip3|pipenv|poetry|composer|deno|go|gem|cargo)\s+(?:install|add|init|i|get)\b|bun\s+(?:add|install)|npm\s+(?:i|install|add)|(?:install|установ\w*)\s+(?:dependencies|зависимост\w*|пакет\w*|packages?)/i.test(stepText);
|
|
18071
18516
|
if (isDepsStep) {
|
|
18072
18517
|
const lockFiles = [
|
|
18073
18518
|
"package-lock.json",
|
|
@@ -18101,18 +18546,21 @@ class ExecutionModule {
|
|
|
18101
18546
|
}
|
|
18102
18547
|
if (stepPaths.length === 0)
|
|
18103
18548
|
return;
|
|
18104
|
-
const
|
|
18105
|
-
const
|
|
18549
|
+
const resolved = stepPaths.map((p) => findExistingFile(this.baseDir, p));
|
|
18550
|
+
const allExist = resolved.every((r) => r !== null);
|
|
18551
|
+
const allGone = resolved.every((r) => r === null);
|
|
18106
18552
|
const satisfied = step.kind === "delete" ? allGone && !allExist : allExist;
|
|
18107
18553
|
if (!satisfied)
|
|
18108
18554
|
return;
|
|
18109
18555
|
if (step.kind !== "delete") {
|
|
18110
18556
|
const emptyFiles = [];
|
|
18111
|
-
for (const
|
|
18557
|
+
for (const r of resolved) {
|
|
18558
|
+
if (!r)
|
|
18559
|
+
continue;
|
|
18112
18560
|
try {
|
|
18113
|
-
const content =
|
|
18561
|
+
const content = readFileSync18(r, "utf-8");
|
|
18114
18562
|
if (content.trim().length < 10) {
|
|
18115
|
-
emptyFiles.push(
|
|
18563
|
+
emptyFiles.push(r);
|
|
18116
18564
|
}
|
|
18117
18565
|
} catch {}
|
|
18118
18566
|
}
|
|
@@ -18145,6 +18593,7 @@ class ExecutionModule {
|
|
|
18145
18593
|
if (this.tracker?.isComplete()) {
|
|
18146
18594
|
const completed = this.tracker.getPlan();
|
|
18147
18595
|
this.store.archivePlan(completed);
|
|
18596
|
+
this.recordCompleted(completed);
|
|
18148
18597
|
this.tracker = null;
|
|
18149
18598
|
sessionLog?.plan("auto-archive", `Plan ${completed.id} complete — archived`);
|
|
18150
18599
|
}
|
|
@@ -18161,6 +18610,9 @@ class ExecutionModule {
|
|
|
18161
18610
|
return [];
|
|
18162
18611
|
return tokens.filter((p) => findExistingFile(this.baseDir, p));
|
|
18163
18612
|
}
|
|
18613
|
+
hasStepDeliverables(step) {
|
|
18614
|
+
return extractFileLikeTokens(stripUrls(step.description)).length > 0;
|
|
18615
|
+
}
|
|
18164
18616
|
parseKinds(args, steps) {
|
|
18165
18617
|
if (args.kinds === undefined)
|
|
18166
18618
|
return { kinds: null, error: null };
|
|
@@ -18198,6 +18650,7 @@ class ExecutionModule {
|
|
|
18198
18650
|
return getMessageText(firstUser.content).trim();
|
|
18199
18651
|
}
|
|
18200
18652
|
}
|
|
18653
|
+
var ERROR_SEARCH_MIN_INTERVAL_MS = 30000;
|
|
18201
18654
|
var init_module = __esm(() => {
|
|
18202
18655
|
init_i18n();
|
|
18203
18656
|
init_tracker();
|
|
@@ -18206,12 +18659,14 @@ var init_module = __esm(() => {
|
|
|
18206
18659
|
init_auditor();
|
|
18207
18660
|
init_plan_store();
|
|
18208
18661
|
init_js_identifiers();
|
|
18662
|
+
init_web_search();
|
|
18663
|
+
init_session_isolation();
|
|
18209
18664
|
init_plan_tool();
|
|
18210
18665
|
init_execution_plugin();
|
|
18211
18666
|
});
|
|
18212
18667
|
|
|
18213
18668
|
// src/modules/security/session-encryption.ts
|
|
18214
|
-
import { readFileSync as
|
|
18669
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync11, existsSync as existsSync34, readdirSync as readdirSync11, unlinkSync as unlinkSync4 } from "fs";
|
|
18215
18670
|
import { join as join27 } from "path";
|
|
18216
18671
|
import { homedir as homedir8 } from "os";
|
|
18217
18672
|
|
|
@@ -18266,7 +18721,7 @@ class SessionFileEncryptor {
|
|
|
18266
18721
|
return lines.map((line) => this.decryptFileContent(line));
|
|
18267
18722
|
}
|
|
18268
18723
|
readSessionFile(filePath) {
|
|
18269
|
-
const content =
|
|
18724
|
+
const content = readFileSync19(filePath, "utf8");
|
|
18270
18725
|
return this.decryptFileContent(content);
|
|
18271
18726
|
}
|
|
18272
18727
|
writeSessionFile(filePath, content) {
|
|
@@ -18274,7 +18729,7 @@ class SessionFileEncryptor {
|
|
|
18274
18729
|
writeFileSync11(filePath, encrypted, "utf8");
|
|
18275
18730
|
}
|
|
18276
18731
|
readSessionJSON(filePath) {
|
|
18277
|
-
const content =
|
|
18732
|
+
const content = readFileSync19(filePath, "utf8");
|
|
18278
18733
|
return this.decryptJSON(content);
|
|
18279
18734
|
}
|
|
18280
18735
|
writeSessionJSON(filePath, obj) {
|
|
@@ -18282,7 +18737,7 @@ class SessionFileEncryptor {
|
|
|
18282
18737
|
writeFileSync11(filePath, content, "utf8");
|
|
18283
18738
|
}
|
|
18284
18739
|
readSessionJSONL(filePath) {
|
|
18285
|
-
const content =
|
|
18740
|
+
const content = readFileSync19(filePath, "utf8");
|
|
18286
18741
|
const lines = content.split(`
|
|
18287
18742
|
`).filter((line) => line.trim());
|
|
18288
18743
|
const decryptedLines = this.decryptJSONL(lines);
|
|
@@ -18310,7 +18765,7 @@ class SessionFileEncryptor {
|
|
|
18310
18765
|
const filePath = join27(sessionDir, file);
|
|
18311
18766
|
if (existsSync34(filePath) && !file.endsWith(".enc")) {
|
|
18312
18767
|
try {
|
|
18313
|
-
const content =
|
|
18768
|
+
const content = readFileSync19(filePath, "utf8");
|
|
18314
18769
|
const encrypted = this.encryptFileContent(content);
|
|
18315
18770
|
writeFileSync11(filePath + ".enc", encrypted, "utf8");
|
|
18316
18771
|
unlinkSync4(filePath);
|
|
@@ -18327,7 +18782,7 @@ class SessionFileEncryptor {
|
|
|
18327
18782
|
const encFilePath = join27(sessionDir, file);
|
|
18328
18783
|
const decFilePath = encFilePath.slice(0, -4);
|
|
18329
18784
|
try {
|
|
18330
|
-
const content =
|
|
18785
|
+
const content = readFileSync19(encFilePath, "utf8");
|
|
18331
18786
|
const decrypted = this.decryptFileContent(content);
|
|
18332
18787
|
writeFileSync11(decFilePath, decrypted, "utf8");
|
|
18333
18788
|
unlinkSync4(encFilePath);
|
|
@@ -18352,7 +18807,7 @@ import {
|
|
|
18352
18807
|
existsSync as existsSync35,
|
|
18353
18808
|
mkdirSync as mkdirSync15,
|
|
18354
18809
|
readdirSync as readdirSync12,
|
|
18355
|
-
readFileSync as
|
|
18810
|
+
readFileSync as readFileSync20,
|
|
18356
18811
|
rmSync as rmSync2,
|
|
18357
18812
|
writeFileSync as writeFileSync12,
|
|
18358
18813
|
appendFileSync as appendFileSync6
|
|
@@ -18420,7 +18875,7 @@ class SessionStore {
|
|
|
18420
18875
|
if (!existsSync35(path))
|
|
18421
18876
|
return null;
|
|
18422
18877
|
try {
|
|
18423
|
-
const raw =
|
|
18878
|
+
const raw = readFileSync20(path, "utf-8");
|
|
18424
18879
|
const content = this.encryptor ? this.encryptor.decryptFileContent(raw) : raw;
|
|
18425
18880
|
const meta = JSON.parse(content);
|
|
18426
18881
|
this._metaCache.set(id, meta);
|
|
@@ -18452,7 +18907,7 @@ class SessionStore {
|
|
|
18452
18907
|
if (!existsSync35(path))
|
|
18453
18908
|
return [];
|
|
18454
18909
|
try {
|
|
18455
|
-
const raw =
|
|
18910
|
+
const raw = readFileSync20(path, "utf-8");
|
|
18456
18911
|
const lines = raw.split(`
|
|
18457
18912
|
`).filter(Boolean);
|
|
18458
18913
|
const parseLine = (line) => {
|
|
@@ -18493,7 +18948,7 @@ class SessionStore {
|
|
|
18493
18948
|
if (!existsSync35(path))
|
|
18494
18949
|
return [];
|
|
18495
18950
|
try {
|
|
18496
|
-
const raw =
|
|
18951
|
+
const raw = readFileSync20(path, "utf-8");
|
|
18497
18952
|
const lines = raw.split(`
|
|
18498
18953
|
`).filter(Boolean);
|
|
18499
18954
|
const parseLine = (line) => {
|
|
@@ -18548,7 +19003,7 @@ class SessionStore {
|
|
|
18548
19003
|
if (updatedAt < thirtyDaysAgo) {
|
|
18549
19004
|
const historyPath = this.historyPath(session2.id);
|
|
18550
19005
|
if (existsSync35(historyPath)) {
|
|
18551
|
-
const content =
|
|
19006
|
+
const content = readFileSync20(historyPath, "utf-8");
|
|
18552
19007
|
const compressed = gzipSync(content);
|
|
18553
19008
|
const gzPath = join28(this.baseDir, `${session2.id}.jsonl.gz`);
|
|
18554
19009
|
writeFileSync12(gzPath, compressed);
|
|
@@ -18760,7 +19215,7 @@ class ProfileCompressor {
|
|
|
18760
19215
|
}
|
|
18761
19216
|
|
|
18762
19217
|
// src/modules/user-profile/profile.ts
|
|
18763
|
-
import { readFileSync as
|
|
19218
|
+
import { readFileSync as readFileSync21, writeFileSync as writeFileSync13, existsSync as existsSync36, mkdirSync as mkdirSync16 } from "fs";
|
|
18764
19219
|
import { join as join29 } from "path";
|
|
18765
19220
|
import { homedir as homedir9, hostname, platform as platform7, type } from "os";
|
|
18766
19221
|
import { env } from "process";
|
|
@@ -18795,7 +19250,7 @@ class UserProfile {
|
|
|
18795
19250
|
if (!existsSync36(path))
|
|
18796
19251
|
return null;
|
|
18797
19252
|
try {
|
|
18798
|
-
const data = JSON.parse(
|
|
19253
|
+
const data = JSON.parse(readFileSync21(path, "utf-8"));
|
|
18799
19254
|
this.info = {
|
|
18800
19255
|
platform: data.platform,
|
|
18801
19256
|
os: data.os,
|
|
@@ -18830,7 +19285,7 @@ class UserProfile {
|
|
|
18830
19285
|
var init_profile = () => {};
|
|
18831
19286
|
|
|
18832
19287
|
// src/modules/skills/loader.ts
|
|
18833
|
-
import { readdirSync as readdirSync13, readFileSync as
|
|
19288
|
+
import { readdirSync as readdirSync13, readFileSync as readFileSync22, existsSync as existsSync37, statSync as statSync6 } from "fs";
|
|
18834
19289
|
import { join as join30 } from "path";
|
|
18835
19290
|
|
|
18836
19291
|
class SkillsLoader {
|
|
@@ -18852,7 +19307,7 @@ class SkillsLoader {
|
|
|
18852
19307
|
}
|
|
18853
19308
|
if (!entry.endsWith(".md") && !entry.endsWith(".skill.md"))
|
|
18854
19309
|
continue;
|
|
18855
|
-
const content =
|
|
19310
|
+
const content = readFileSync22(fullPath, "utf-8");
|
|
18856
19311
|
const parsed = this.parseSkillFile(content, fullPath);
|
|
18857
19312
|
if (parsed)
|
|
18858
19313
|
skills.push(parsed);
|
|
@@ -19402,7 +19857,7 @@ var init_check_tool = __esm(() => {
|
|
|
19402
19857
|
|
|
19403
19858
|
// src/modules/lsp/module.ts
|
|
19404
19859
|
import { existsSync as existsSync38 } from "fs";
|
|
19405
|
-
import { resolve as resolve22 } from "path";
|
|
19860
|
+
import { relative as relative3, resolve as resolve22 } from "path";
|
|
19406
19861
|
|
|
19407
19862
|
class LspModule {
|
|
19408
19863
|
name = "lsp";
|
|
@@ -19537,6 +19992,7 @@ ${items}`;
|
|
|
19537
19992
|
const errors = [];
|
|
19538
19993
|
const warnings = [];
|
|
19539
19994
|
const notes = [];
|
|
19995
|
+
const checkedFiles = [];
|
|
19540
19996
|
let checked = 0;
|
|
19541
19997
|
for (const file of files) {
|
|
19542
19998
|
const serverConfig = getServerForFile(file, this.config);
|
|
@@ -19550,6 +20006,7 @@ ${items}`;
|
|
|
19550
20006
|
const diags = await this.client.checkFile(file, ctx.baseDir, serverConfig, projectRoot);
|
|
19551
20007
|
this.failuresByServer.set(key, 0);
|
|
19552
20008
|
checked++;
|
|
20009
|
+
checkedFiles.push(relative3(ctx.baseDir, file).replace(/\\/g, "/"));
|
|
19553
20010
|
for (const d of diags) {
|
|
19554
20011
|
if (d.severity === 1)
|
|
19555
20012
|
errors.push({ file, diag: d });
|
|
@@ -19572,6 +20029,10 @@ ${items}`;
|
|
|
19572
20029
|
}
|
|
19573
20030
|
}
|
|
19574
20031
|
const lines = [];
|
|
20032
|
+
if (checked > 0) {
|
|
20033
|
+
lines.push(t("lsp.checked_files", { count: String(checked) }));
|
|
20034
|
+
lines.push(...checkedFiles.map((f) => ` ${f}`));
|
|
20035
|
+
}
|
|
19575
20036
|
if (errors.length > 0) {
|
|
19576
20037
|
lines.push(`[LSP errors] (${errors.length}):`);
|
|
19577
20038
|
lines.push(formatCheckDiagnostics(errors, ctx.baseDir));
|
|
@@ -19748,8 +20209,8 @@ var init_startup_check = __esm(() => {
|
|
|
19748
20209
|
});
|
|
19749
20210
|
|
|
19750
20211
|
// src/modules/indexer/walker.ts
|
|
19751
|
-
import { readdirSync as readdirSync14, readFileSync as
|
|
19752
|
-
import { join as join32, relative as
|
|
20212
|
+
import { readdirSync as readdirSync14, readFileSync as readFileSync23, statSync as statSync7, existsSync as existsSync40, watch } from "fs";
|
|
20213
|
+
import { join as join32, relative as relative4, extname as extname5 } from "path";
|
|
19753
20214
|
|
|
19754
20215
|
class Indexer {
|
|
19755
20216
|
baseDir;
|
|
@@ -19788,7 +20249,7 @@ class Indexer {
|
|
|
19788
20249
|
if (count >= this.MAX_FILES)
|
|
19789
20250
|
return;
|
|
19790
20251
|
const fullPath = join32(dir, entry);
|
|
19791
|
-
const relPath =
|
|
20252
|
+
const relPath = relative4(this.baseDir, fullPath);
|
|
19792
20253
|
const stat2 = statSync7(fullPath);
|
|
19793
20254
|
if (stat2.isDirectory()) {
|
|
19794
20255
|
if (!IGNORE_DIRS.has(entry)) {
|
|
@@ -19798,7 +20259,7 @@ class Indexer {
|
|
|
19798
20259
|
const ext = extname5(entry).toLowerCase();
|
|
19799
20260
|
const language = LANGUAGES[ext];
|
|
19800
20261
|
if (language) {
|
|
19801
|
-
const content =
|
|
20262
|
+
const content = readFileSync23(fullPath, "utf-8");
|
|
19802
20263
|
const exports = this.extractExports(content, language);
|
|
19803
20264
|
files.push({ path: relPath, language, exports, size: stat2.size });
|
|
19804
20265
|
totalSize += stat2.size;
|
|
@@ -19850,7 +20311,7 @@ var init_walker = __esm(() => {
|
|
|
19850
20311
|
});
|
|
19851
20312
|
|
|
19852
20313
|
// src/modules/indexer/cache.ts
|
|
19853
|
-
import { readFileSync as
|
|
20314
|
+
import { readFileSync as readFileSync24, writeFileSync as writeFileSync14, existsSync as existsSync41, mkdirSync as mkdirSync17, rmSync as rmSync3 } from "fs";
|
|
19854
20315
|
import { join as join33 } from "path";
|
|
19855
20316
|
|
|
19856
20317
|
class IndexCache {
|
|
@@ -19865,7 +20326,7 @@ class IndexCache {
|
|
|
19865
20326
|
if (!existsSync41(this.cachePath))
|
|
19866
20327
|
return null;
|
|
19867
20328
|
try {
|
|
19868
|
-
this.cache = JSON.parse(
|
|
20329
|
+
this.cache = JSON.parse(readFileSync24(this.cachePath, "utf-8"));
|
|
19869
20330
|
return this.cache;
|
|
19870
20331
|
} catch {
|
|
19871
20332
|
return null;
|
|
@@ -19890,7 +20351,7 @@ class IndexCache {
|
|
|
19890
20351
|
var init_cache = () => {};
|
|
19891
20352
|
|
|
19892
20353
|
// src/modules/indexer/project-profile.ts
|
|
19893
|
-
import { readFileSync as
|
|
20354
|
+
import { readFileSync as readFileSync25, existsSync as existsSync42 } from "fs";
|
|
19894
20355
|
import { join as join34 } from "path";
|
|
19895
20356
|
function detectManifest(baseDir) {
|
|
19896
20357
|
for (const manifest of MANIFEST_ORDER) {
|
|
@@ -19911,7 +20372,7 @@ function cleanDependency(entry) {
|
|
|
19911
20372
|
}
|
|
19912
20373
|
function readPackageJson(baseDir) {
|
|
19913
20374
|
try {
|
|
19914
|
-
const raw = JSON.parse(
|
|
20375
|
+
const raw = JSON.parse(readFileSync25(join34(baseDir, "package.json"), "utf-8"));
|
|
19915
20376
|
if (!raw || typeof raw !== "object")
|
|
19916
20377
|
return null;
|
|
19917
20378
|
const profile = {
|
|
@@ -19935,7 +20396,7 @@ function readPackageJson(baseDir) {
|
|
|
19935
20396
|
}
|
|
19936
20397
|
function readPyproject(baseDir) {
|
|
19937
20398
|
try {
|
|
19938
|
-
const content =
|
|
20399
|
+
const content = readFileSync25(join34(baseDir, "pyproject.toml"), "utf-8");
|
|
19939
20400
|
const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
|
|
19940
20401
|
const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
19941
20402
|
if (nameMatch)
|
|
@@ -19951,7 +20412,7 @@ function readPyproject(baseDir) {
|
|
|
19951
20412
|
}
|
|
19952
20413
|
function readCargo(baseDir) {
|
|
19953
20414
|
try {
|
|
19954
|
-
const content =
|
|
20415
|
+
const content = readFileSync25(join34(baseDir, "Cargo.toml"), "utf-8");
|
|
19955
20416
|
const profile = { runtime: "rust", deps: [], devDeps: [], scripts: {} };
|
|
19956
20417
|
const nameMatch = content.match(/^\s*name\s*=\s*"([^"]+)"/m);
|
|
19957
20418
|
if (nameMatch)
|
|
@@ -19975,7 +20436,7 @@ function readCargo(baseDir) {
|
|
|
19975
20436
|
}
|
|
19976
20437
|
function readGoMod(baseDir) {
|
|
19977
20438
|
try {
|
|
19978
|
-
const content =
|
|
20439
|
+
const content = readFileSync25(join34(baseDir, "go.mod"), "utf-8");
|
|
19979
20440
|
const profile = { runtime: "go", deps: [], devDeps: [], scripts: {} };
|
|
19980
20441
|
const moduleMatch = content.match(/^module\s+(\S+)/m);
|
|
19981
20442
|
if (moduleMatch)
|
|
@@ -19993,7 +20454,7 @@ function readGoMod(baseDir) {
|
|
|
19993
20454
|
}
|
|
19994
20455
|
function readRequirements(baseDir) {
|
|
19995
20456
|
try {
|
|
19996
|
-
const content =
|
|
20457
|
+
const content = readFileSync25(join34(baseDir, "requirements.txt"), "utf-8");
|
|
19997
20458
|
const profile = { runtime: "python", deps: [], devDeps: [], scripts: {} };
|
|
19998
20459
|
for (const line of content.split(`
|
|
19999
20460
|
`)) {
|
|
@@ -20546,7 +21007,7 @@ var init_module8 = __esm(() => {
|
|
|
20546
21007
|
});
|
|
20547
21008
|
|
|
20548
21009
|
// src/core/version.ts
|
|
20549
|
-
import { existsSync as existsSync43, readFileSync as
|
|
21010
|
+
import { existsSync as existsSync43, readFileSync as readFileSync26 } from "fs";
|
|
20550
21011
|
import { join as join36, dirname as dirname13 } from "path";
|
|
20551
21012
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20552
21013
|
function readMmaVersion() {
|
|
@@ -20555,7 +21016,7 @@ function readMmaVersion() {
|
|
|
20555
21016
|
for (const p of candidates) {
|
|
20556
21017
|
if (existsSync43(p)) {
|
|
20557
21018
|
try {
|
|
20558
|
-
const raw = JSON.parse(
|
|
21019
|
+
const raw = JSON.parse(readFileSync26(p, "utf8"));
|
|
20559
21020
|
if (raw.version)
|
|
20560
21021
|
return raw.version;
|
|
20561
21022
|
} catch {}
|
|
@@ -20573,7 +21034,7 @@ __export(exports_bootstrap, {
|
|
|
20573
21034
|
});
|
|
20574
21035
|
import { homedir as homedir11 } from "os";
|
|
20575
21036
|
import { join as join37, resolve as resolve23 } from "path";
|
|
20576
|
-
import { existsSync as existsSync44, readFileSync as
|
|
21037
|
+
import { existsSync as existsSync44, readFileSync as readFileSync27, writeFileSync as writeFileSync15 } from "fs";
|
|
20577
21038
|
function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
20578
21039
|
const now = new Date().toISOString().replace("T", " ").slice(0, 19);
|
|
20579
21040
|
const isWin = profileCompressed.toLowerCase().includes("win32");
|
|
@@ -20735,7 +21196,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20735
21196
|
toolCtx.toolExecutor = toolExecutor;
|
|
20736
21197
|
const hallucinationDetector = new HallucinationDetector(baseDir, llmProvider);
|
|
20737
21198
|
const moduleRegistry = new ModuleRegistry;
|
|
20738
|
-
const execModule = new ExecutionModule(baseDir, config.stuckThreshold);
|
|
21199
|
+
const execModule = new ExecutionModule(baseDir, config.stuckThreshold, config.errorWebSearch?.threshold ?? 5);
|
|
20739
21200
|
const activeMeta = sessionManager.getActiveMeta();
|
|
20740
21201
|
if (activeMeta && activeMeta.messageCount > 0) {
|
|
20741
21202
|
execModule.restorePlan();
|
|
@@ -20833,7 +21294,7 @@ async function bootstrap(configDir, projectDir, noAgentsMd, exitOnComplete) {
|
|
|
20833
21294
|
];
|
|
20834
21295
|
for (const p of agentsMdCandidates) {
|
|
20835
21296
|
if (existsSync44(p)) {
|
|
20836
|
-
const content =
|
|
21297
|
+
const content = readFileSync27(p, "utf-8").trim();
|
|
20837
21298
|
if (content) {
|
|
20838
21299
|
agentsMdBlocks.push({
|
|
20839
21300
|
content,
|
|
@@ -21697,13 +22158,13 @@ __export(exports_manifest, {
|
|
|
21697
22158
|
getCertMark: () => getCertMark,
|
|
21698
22159
|
MANIFEST_PATH: () => MANIFEST_PATH
|
|
21699
22160
|
});
|
|
21700
|
-
import { existsSync as existsSync45, readFileSync as
|
|
22161
|
+
import { existsSync as existsSync45, readFileSync as readFileSync28, mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
21701
22162
|
import { homedir as homedir13 } from "os";
|
|
21702
22163
|
import { join as join39 } from "path";
|
|
21703
22164
|
function readManifest(path = MANIFEST_PATH) {
|
|
21704
22165
|
try {
|
|
21705
22166
|
if (existsSync45(path)) {
|
|
21706
|
-
const raw = JSON.parse(
|
|
22167
|
+
const raw = JSON.parse(readFileSync28(path, "utf-8"));
|
|
21707
22168
|
return { version: 1, certifications: raw.certifications ?? [] };
|
|
21708
22169
|
}
|
|
21709
22170
|
} catch {}
|
|
@@ -28868,7 +29329,7 @@ var init_scenarios = __esm(() => {
|
|
|
28868
29329
|
});
|
|
28869
29330
|
|
|
28870
29331
|
// src/modules/certification/loader.ts
|
|
28871
|
-
import { existsSync as existsSync46, readdirSync as readdirSync15, readFileSync as
|
|
29332
|
+
import { existsSync as existsSync46, readdirSync as readdirSync15, readFileSync as readFileSync29 } from "fs";
|
|
28872
29333
|
import { join as join40 } from "path";
|
|
28873
29334
|
function validateScenario(s) {
|
|
28874
29335
|
const errors2 = [];
|
|
@@ -28923,7 +29384,7 @@ function loadScenarios(userDir) {
|
|
|
28923
29384
|
if (!file.endsWith(".yaml") && !file.endsWith(".yml"))
|
|
28924
29385
|
continue;
|
|
28925
29386
|
try {
|
|
28926
|
-
const raw =
|
|
29387
|
+
const raw = readFileSync29(join40(userDir, file), "utf-8");
|
|
28927
29388
|
const data = $parse(raw);
|
|
28928
29389
|
const parsed = normalizeScenario(data, file);
|
|
28929
29390
|
const errs = validateScenario(parsed);
|
|
@@ -28976,7 +29437,7 @@ var init_loader3 = __esm(() => {
|
|
|
28976
29437
|
});
|
|
28977
29438
|
|
|
28978
29439
|
// src/modules/certification/fact-checker.ts
|
|
28979
|
-
import { existsSync as existsSync47, readFileSync as
|
|
29440
|
+
import { existsSync as existsSync47, readFileSync as readFileSync30, statSync as statSync8 } from "fs";
|
|
28980
29441
|
import { join as join41 } from "path";
|
|
28981
29442
|
function checkSandbox(sandboxDir, checks, exitCode, output) {
|
|
28982
29443
|
const failures = [];
|
|
@@ -29003,7 +29464,7 @@ function runCheck2(sandboxDir, check, exitCode, output) {
|
|
|
29003
29464
|
const abs = join41(sandboxDir, check.path);
|
|
29004
29465
|
if (!isFile(abs))
|
|
29005
29466
|
return false;
|
|
29006
|
-
const content =
|
|
29467
|
+
const content = readFileSync30(abs, "utf-8");
|
|
29007
29468
|
if (check.contains !== undefined)
|
|
29008
29469
|
return content.includes(check.contains);
|
|
29009
29470
|
if (check.equals !== undefined)
|
|
@@ -29014,7 +29475,7 @@ function runCheck2(sandboxDir, check, exitCode, output) {
|
|
|
29014
29475
|
const abs = join41(sandboxDir, check.path);
|
|
29015
29476
|
if (!isFile(abs))
|
|
29016
29477
|
return false;
|
|
29017
|
-
return new RegExp(check.pattern).test(
|
|
29478
|
+
return new RegExp(check.pattern).test(readFileSync30(abs, "utf-8"));
|
|
29018
29479
|
}
|
|
29019
29480
|
default:
|
|
29020
29481
|
return false;
|
|
@@ -29230,13 +29691,13 @@ import { rmSync as rmSync5 } from "fs";
|
|
|
29230
29691
|
import { homedir as homedir14 } from "os";
|
|
29231
29692
|
import { join as join43, dirname as dirname15 } from "path";
|
|
29232
29693
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
29233
|
-
import { existsSync as existsSync49, readFileSync as
|
|
29694
|
+
import { existsSync as existsSync49, readFileSync as readFileSync31 } from "fs";
|
|
29234
29695
|
function readVersion() {
|
|
29235
29696
|
const candidates = [join43(MMA_ROOT, "package.json")];
|
|
29236
29697
|
for (const p of candidates) {
|
|
29237
29698
|
if (existsSync49(p)) {
|
|
29238
29699
|
try {
|
|
29239
|
-
const raw = JSON.parse(
|
|
29700
|
+
const raw = JSON.parse(readFileSync31(p, "utf-8"));
|
|
29240
29701
|
if (raw.version)
|
|
29241
29702
|
return raw.version;
|
|
29242
29703
|
} catch {}
|
|
@@ -29397,7 +29858,7 @@ __export(exports_repl_commands, {
|
|
|
29397
29858
|
});
|
|
29398
29859
|
import { join as join45, dirname as dirname17 } from "path";
|
|
29399
29860
|
import { homedir as homedir16 } from "os";
|
|
29400
|
-
import { existsSync as existsSync51, readFileSync as
|
|
29861
|
+
import { existsSync as existsSync51, readFileSync as readFileSync33 } from "fs";
|
|
29401
29862
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
29402
29863
|
function readVersion3() {
|
|
29403
29864
|
const here = dirname17(fileURLToPath5(import.meta.url));
|
|
@@ -29405,7 +29866,7 @@ function readVersion3() {
|
|
|
29405
29866
|
for (const p of candidates) {
|
|
29406
29867
|
if (existsSync51(p)) {
|
|
29407
29868
|
try {
|
|
29408
|
-
const raw = JSON.parse(
|
|
29869
|
+
const raw = JSON.parse(readFileSync33(p, "utf8"));
|
|
29409
29870
|
if (raw.version)
|
|
29410
29871
|
return raw.version;
|
|
29411
29872
|
} catch {}
|
|
@@ -30063,7 +30524,7 @@ init_setup();
|
|
|
30063
30524
|
init_i18n();
|
|
30064
30525
|
import { join as join44, dirname as dirname16 } from "path";
|
|
30065
30526
|
import { homedir as homedir15 } from "os";
|
|
30066
|
-
import { existsSync as existsSync50, readFileSync as
|
|
30527
|
+
import { existsSync as existsSync50, readFileSync as readFileSync32 } from "fs";
|
|
30067
30528
|
|
|
30068
30529
|
// src/cli/security-commands.ts
|
|
30069
30530
|
init_bootstrap();
|
|
@@ -30705,7 +31166,7 @@ function readVersion2() {
|
|
|
30705
31166
|
for (const p of candidates) {
|
|
30706
31167
|
if (existsSync50(p)) {
|
|
30707
31168
|
try {
|
|
30708
|
-
const raw = JSON.parse(
|
|
31169
|
+
const raw = JSON.parse(readFileSync32(p, "utf8"));
|
|
30709
31170
|
if (raw.version)
|
|
30710
31171
|
return raw.version;
|
|
30711
31172
|
} catch {}
|
|
@@ -30940,9 +31401,9 @@ import * as readline2 from "readline";
|
|
|
30940
31401
|
|
|
30941
31402
|
// src/ui/line-math.ts
|
|
30942
31403
|
init_string_width();
|
|
30943
|
-
var
|
|
31404
|
+
var ANSI_RE2 = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
30944
31405
|
function stripAnsi2(s) {
|
|
30945
|
-
return s.replace(
|
|
31406
|
+
return s.replace(ANSI_RE2, "");
|
|
30946
31407
|
}
|
|
30947
31408
|
function charLen(s) {
|
|
30948
31409
|
return Array.from(s).length;
|
|
@@ -31688,7 +32149,7 @@ class LineEditor {
|
|
|
31688
32149
|
}
|
|
31689
32150
|
|
|
31690
32151
|
// src/cli/repl.ts
|
|
31691
|
-
import { existsSync as existsSync53, readFileSync as
|
|
32152
|
+
import { existsSync as existsSync53, readFileSync as readFileSync35, writeFileSync as writeFileSync17 } from "fs";
|
|
31692
32153
|
import { join as join47, dirname as dirname18 } from "path";
|
|
31693
32154
|
import { homedir as homedir17 } from "os";
|
|
31694
32155
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
@@ -31996,6 +32457,7 @@ init_box();
|
|
|
31996
32457
|
init_table();
|
|
31997
32458
|
init_i18n();
|
|
31998
32459
|
var GUTTER = " ";
|
|
32460
|
+
var BUSY_TOOLS = new Set(["lsp_check"]);
|
|
31999
32461
|
function toolMarker(tool) {
|
|
32000
32462
|
switch (tool) {
|
|
32001
32463
|
case "write_file":
|
|
@@ -32115,6 +32577,9 @@ ${pc2.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}$
|
|
|
32115
32577
|
this.out.write(`
|
|
32116
32578
|
${pc2.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}
|
|
32117
32579
|
`);
|
|
32580
|
+
if (BUSY_TOOLS.has(tool)) {
|
|
32581
|
+
this.spinner.start(t("ui.tool_running", { tool: friendlyTool(tool) }));
|
|
32582
|
+
}
|
|
32118
32583
|
return;
|
|
32119
32584
|
}
|
|
32120
32585
|
this.spinner.start(`${pc2.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc2.dim(summary)}` : ""}${step}`);
|
|
@@ -32273,14 +32738,14 @@ init_config();
|
|
|
32273
32738
|
init_colors();
|
|
32274
32739
|
init_js_identifiers();
|
|
32275
32740
|
init_i18n();
|
|
32276
|
-
import { existsSync as existsSync52, readFileSync as
|
|
32741
|
+
import { existsSync as existsSync52, readFileSync as readFileSync34 } from "fs";
|
|
32277
32742
|
import { join as join46 } from "path";
|
|
32278
32743
|
function readActivePlan(baseDir) {
|
|
32279
32744
|
const p = join46(baseDir, ".mma", "plans", "active.json");
|
|
32280
32745
|
if (!existsSync52(p))
|
|
32281
32746
|
return null;
|
|
32282
32747
|
try {
|
|
32283
|
-
const raw =
|
|
32748
|
+
const raw = readFileSync34(p, "utf-8");
|
|
32284
32749
|
if (!raw.trim())
|
|
32285
32750
|
return null;
|
|
32286
32751
|
const parsed = JSON.parse(raw);
|
|
@@ -32379,7 +32844,7 @@ function readVersion4() {
|
|
|
32379
32844
|
for (const p of candidates) {
|
|
32380
32845
|
if (existsSync53(p)) {
|
|
32381
32846
|
try {
|
|
32382
|
-
const raw = JSON.parse(
|
|
32847
|
+
const raw = JSON.parse(readFileSync35(p, "utf8"));
|
|
32383
32848
|
if (raw.version)
|
|
32384
32849
|
return raw.version;
|
|
32385
32850
|
} catch {}
|
|
@@ -32475,7 +32940,7 @@ class Repl {
|
|
|
32475
32940
|
loadHistory() {
|
|
32476
32941
|
if (existsSync53(this.historyPath)) {
|
|
32477
32942
|
try {
|
|
32478
|
-
const raw =
|
|
32943
|
+
const raw = readFileSync35(this.historyPath, "utf-8");
|
|
32479
32944
|
this.history = raw.split(`
|
|
32480
32945
|
`).filter(Boolean).slice(-this.maxHistory);
|
|
32481
32946
|
} catch {
|
|
@@ -32948,7 +33413,7 @@ init_setup();
|
|
|
32948
33413
|
init_config2();
|
|
32949
33414
|
init_i18n();
|
|
32950
33415
|
init_colors();
|
|
32951
|
-
import { existsSync as existsSync54, readFileSync as
|
|
33416
|
+
import { existsSync as existsSync54, readFileSync as readFileSync36 } from "fs";
|
|
32952
33417
|
import { join as join48, dirname as dirname19 } from "path";
|
|
32953
33418
|
import { homedir as homedir18 } from "os";
|
|
32954
33419
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
@@ -33057,7 +33522,7 @@ function readVersion5() {
|
|
|
33057
33522
|
for (const p of candidates) {
|
|
33058
33523
|
if (existsSync54(p)) {
|
|
33059
33524
|
try {
|
|
33060
|
-
const raw = JSON.parse(
|
|
33525
|
+
const raw = JSON.parse(readFileSync36(p, "utf8"));
|
|
33061
33526
|
if (raw.version)
|
|
33062
33527
|
return raw.version;
|
|
33063
33528
|
} catch {}
|