micro-models-agent 2.12.0 → 2.14.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/CHANGELOG.md +35 -0
- package/dist/assets/app.js +22 -2
- package/dist/assets/index.html +39 -9
- package/dist/assets/js/dom.js +15 -0
- package/dist/assets/js/feed.js +199 -45
- package/dist/assets/js/sidebar.js +512 -0
- package/dist/assets/js/tabs.js +8 -2
- package/dist/assets/setup.js +267 -8
- package/dist/assets/styles.css +185 -28
- package/dist/i18n/en.json +92 -7
- package/dist/i18n/ru.json +92 -7
- package/dist/main.js +634 -101
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2609,6 +2609,8 @@ The path was joined onto the working directory because it does not exist as give
|
|
|
2609
2609
|
{issues}
|
|
2610
2610
|
Summary: {summary}`,
|
|
2611
2611
|
"critic.advice": `A verifier flagged issues worth checking before you finish:
|
|
2612
|
+
{issues}`,
|
|
2613
|
+
"critic.repeat": `The verifier repeats a previously flagged problem — do not produce the same answer again. Change the approach, or finish honestly if the complaint does not apply:
|
|
2612
2614
|
{issues}`,
|
|
2613
2615
|
"tool.subagent_queued": "Sub-agent task queued: {task}",
|
|
2614
2616
|
"tool.subagent_artifact": `Sub-agent completed. Full result saved to artifact: {path}
|
|
@@ -3404,6 +3406,7 @@ Apply a matching solution from these results. If none is relevant — do NOT rep
|
|
|
3404
3406
|
"ui.todo_action": "{action} · {count}",
|
|
3405
3407
|
"ui.tool_running": "{tool}…",
|
|
3406
3408
|
"ui.step_context": "step {id}: {desc}",
|
|
3409
|
+
"ui.draft_retracted": "↳ draft rejected by verification, refining…",
|
|
3407
3410
|
"indexer.map_header": "Project map",
|
|
3408
3411
|
"indexer.top_directories": "Top directories",
|
|
3409
3412
|
"indexer.files": "Files",
|
|
@@ -3578,6 +3581,46 @@ Updated: {updatedAt}`,
|
|
|
3578
3581
|
"web.sidebar.session": "session",
|
|
3579
3582
|
"web.sidebar.usage": "usage",
|
|
3580
3583
|
"web.sidebar.env": "environment",
|
|
3584
|
+
"web.sidebar.tab_session": "Session",
|
|
3585
|
+
"web.sidebar.tab_map": "Map",
|
|
3586
|
+
"web.sidebar.tab_trace": "Trace",
|
|
3587
|
+
"web.sidebar.map_status": "status",
|
|
3588
|
+
"web.sidebar.map_ready": "ready",
|
|
3589
|
+
"web.sidebar.map_indexing": "indexing…",
|
|
3590
|
+
"web.sidebar.map_stale": "stale",
|
|
3591
|
+
"web.sidebar.map_updated": "updated",
|
|
3592
|
+
"web.sidebar.map_never": "never",
|
|
3593
|
+
"web.sidebar.map_today": "today, {time}",
|
|
3594
|
+
"web.sidebar.map_watcher": "watcher",
|
|
3595
|
+
"web.sidebar.map_on": "on",
|
|
3596
|
+
"web.sidebar.map_off": "off",
|
|
3597
|
+
"web.sidebar.map_files": "files",
|
|
3598
|
+
"web.sidebar.map_symbols": "symbols",
|
|
3599
|
+
"web.sidebar.map_tokens": "tokens",
|
|
3600
|
+
"web.sidebar.map_root": "root",
|
|
3601
|
+
"web.sidebar.map_languages": "languages",
|
|
3602
|
+
"web.sidebar.map_reindex": "Re-index",
|
|
3603
|
+
"web.sidebar.map_reindexing": "re-indexing…",
|
|
3604
|
+
"web.sidebar.map_reindex_failed": "re-index failed",
|
|
3605
|
+
"web.sidebar.trace_empty": "no events yet",
|
|
3606
|
+
"web.sidebar.trace_turn": "turn {n}",
|
|
3607
|
+
"web.sidebar.trace_text": "composing… {count} chars",
|
|
3608
|
+
"web.sidebar.trace_plan": "plan update",
|
|
3609
|
+
"web.sidebar.trace_question": "question",
|
|
3610
|
+
"web.sidebar.detail_metadata": "metadata",
|
|
3611
|
+
"web.sidebar.detail_arguments": "arguments",
|
|
3612
|
+
"web.sidebar.detail_output": "output",
|
|
3613
|
+
"web.sidebar.detail_error": "error",
|
|
3614
|
+
"web.sidebar.detail_text": "text",
|
|
3615
|
+
"web.sidebar.detail_plan": "plan",
|
|
3616
|
+
"web.sidebar.detail_reasoning": "reasoning",
|
|
3617
|
+
"web.sidebar.detail_status": "status",
|
|
3618
|
+
"web.sidebar.detail_ok": "ok",
|
|
3619
|
+
"web.sidebar.detail_fail": "failed",
|
|
3620
|
+
"web.sidebar.detail_duration": "duration",
|
|
3621
|
+
"web.sidebar.detail_time": "time",
|
|
3622
|
+
"web.sidebar.detail_tool_call": "tool call",
|
|
3623
|
+
"web.sidebar.detail_session": "session",
|
|
3581
3624
|
"web.env.dir": "dir",
|
|
3582
3625
|
"web.env.agents": "AGENTS.md",
|
|
3583
3626
|
"web.env.map": "map",
|
|
@@ -3972,6 +4015,7 @@ Updated: {updatedAt}`,
|
|
|
3972
4015
|
"web.history.loading": "loading…",
|
|
3973
4016
|
"web.history.unavailable": "— history unavailable",
|
|
3974
4017
|
"web.history.empty": "— empty session —",
|
|
4018
|
+
"web.scroll.latest": "latest",
|
|
3975
4019
|
"web.tool.output_one": "output · {count} char",
|
|
3976
4020
|
"web.tool.output_few": "output · {count} chars",
|
|
3977
4021
|
"web.tool.output_many": "output · {count} chars",
|
|
@@ -3981,13 +4025,12 @@ Updated: {updatedAt}`,
|
|
|
3981
4025
|
"web.code.copy_failed": "copy failed",
|
|
3982
4026
|
"web.msg.copy": "copy",
|
|
3983
4027
|
"web.msg.copy_md": "copy as markdown",
|
|
3984
|
-
"web.card.open": "open ↗",
|
|
3985
|
-
"web.card.download": "download ⤓",
|
|
3986
|
-
"web.card.copy_path": "copy path",
|
|
3987
4028
|
"web.card.open_title": "Preview in a browser tab",
|
|
3988
|
-
"web.card.download_title": "Download the file",
|
|
3989
4029
|
"web.card.copy_title": "Copy the workspace path",
|
|
3990
4030
|
"web.card.drawio_hint": "Draw.io diagram is XML — preview shows code; open it in draw.io / VS Code to see the scheme.",
|
|
4031
|
+
"web.card.files_one": "{count} file",
|
|
4032
|
+
"web.card.files_few": "{count} files",
|
|
4033
|
+
"web.card.files_many": "{count} files",
|
|
3991
4034
|
"web.card.screenshot": "screenshot",
|
|
3992
4035
|
"web.card.attached_image": "attached image",
|
|
3993
4036
|
"web.card.browser_viewport": "browser · viewport",
|
|
@@ -4015,7 +4058,7 @@ Updated: {updatedAt}`,
|
|
|
4015
4058
|
"web.setup.language.title": "Choose your language",
|
|
4016
4059
|
"web.setup.language.hint": "Used for the interface.",
|
|
4017
4060
|
"web.setup.provider.title": "Choose a provider",
|
|
4018
|
-
"web.setup.provider.hint": "For a local model pick the OpenAI-compatible option
|
|
4061
|
+
"web.setup.provider.hint": "For a local model pick the OpenAI-compatible option, scan for your server, then test the connection before continuing.",
|
|
4019
4062
|
"web.setup.provider.base_url": "Base URL",
|
|
4020
4063
|
"web.setup.provider.scan": "Scan for local servers",
|
|
4021
4064
|
"web.setup.provider.scan_found_one": "Found {count} server",
|
|
@@ -4024,6 +4067,10 @@ Updated: {updatedAt}`,
|
|
|
4024
4067
|
"web.setup.provider.scan_none": "No local servers found — enter the URL manually.",
|
|
4025
4068
|
"web.setup.provider.scan_failed": "Scan failed. Enter the URL manually.",
|
|
4026
4069
|
"web.setup.provider.required": "Please enter a base URL.",
|
|
4070
|
+
"web.setup.provider.test": "Test connection",
|
|
4071
|
+
"web.setup.provider.testing": "Testing…",
|
|
4072
|
+
"web.setup.provider.test_ok": "Server reachable.",
|
|
4073
|
+
"web.setup.provider.test_fail": "Could not reach the server at this URL.",
|
|
4027
4074
|
"web.setup.key.title": "API key",
|
|
4028
4075
|
"web.setup.key.hint": "Leave empty for local servers. Stored only in your config file and never shown again.",
|
|
4029
4076
|
"web.setup.key.label": "Key",
|
|
@@ -4042,15 +4089,54 @@ Updated: {updatedAt}`,
|
|
|
4042
4089
|
"web.setup.model.test_fail": "Could not reach the model.",
|
|
4043
4090
|
"web.setup.model.required": "Please choose or type a model.",
|
|
4044
4091
|
"web.setup.context.title": "Context & iterations",
|
|
4045
|
-
"web.setup.context.hint": "
|
|
4092
|
+
"web.setup.context.hint": "Must match the context your provider gives this model. Press Detect, or copy the value from LM Studio / Ollama / provider docs.",
|
|
4046
4093
|
"web.setup.context.contextWindow": "Context window (tokens)",
|
|
4047
4094
|
"web.setup.context.maxToolIterations": "Max tool iterations",
|
|
4048
4095
|
"web.setup.context.required": "Enter a positive number.",
|
|
4096
|
+
"web.setup.context.detect": "Detect from provider",
|
|
4097
|
+
"web.setup.context.detecting": "Detecting…",
|
|
4098
|
+
"web.setup.context.detect_ok": "Context set from provider: {count} tokens.",
|
|
4099
|
+
"web.setup.context.detect_fail": "Could not detect context — enter it manually.",
|
|
4049
4100
|
"web.setup.security.title": "Security",
|
|
4050
|
-
"web.setup.security.hint": "Safe defaults are on; turn off only what you need.",
|
|
4101
|
+
"web.setup.security.hint": "Safe defaults are on; turn off only what you need. Nothing is blocked silently — each toggle only asks the agent to confirm first.",
|
|
4051
4102
|
"web.setup.security.paths": "Restrict file access to the workspace",
|
|
4103
|
+
"web.setup.security.paths_desc": "The agent reads and writes only inside the workspace, and asks before touching .git, .env, keys and other sensitive paths.",
|
|
4052
4104
|
"web.setup.security.bash": "Block dangerous shell commands",
|
|
4105
|
+
"web.setup.security.bash_desc": "Blocks destructive commands (rm, sudo, ssh, curl, shutdown, …). The agent asks instead of running them.",
|
|
4053
4106
|
"web.setup.security.flags": "Block dangerous command flags",
|
|
4107
|
+
"web.setup.security.flags_desc": "Blocks risky flags (--force, -rf, …) that make safe commands dangerous. Works together with the command block.",
|
|
4108
|
+
"web.setup.security.configure": "Configure",
|
|
4109
|
+
"web.setup.security.advanced": "Advanced security settings",
|
|
4110
|
+
"web.setup.security.popup_hint": "One item per line. Empty list = disabled. Changes apply only to this install; you can edit them later in Settings → Security.",
|
|
4111
|
+
"web.setup.security.popup_done": "Done",
|
|
4112
|
+
"web.setup.security.reset": "Reset to defaults",
|
|
4113
|
+
"web.setup.security.denied": "Always denied paths",
|
|
4114
|
+
"web.setup.security.allowed": "Only allowed paths (empty = all except denied)",
|
|
4115
|
+
"web.setup.security.blacklist": "Always blocked commands",
|
|
4116
|
+
"web.setup.security.whitelist": "Only allowed commands (empty = all except blocked)",
|
|
4117
|
+
"web.setup.security.log_commands": "Log every executed command to the audit log",
|
|
4118
|
+
"web.setup.security.dangerous_flags": "Blocked command flags",
|
|
4119
|
+
"web.setup.security.dangerous_operators": "Blocked shell operators",
|
|
4120
|
+
"web.setup.security.network_enabled": "Network protection (block private/internal addresses)",
|
|
4121
|
+
"web.setup.security.denied_domains": "Always denied domains",
|
|
4122
|
+
"web.setup.security.allowed_domains": "Only allowed domains (empty = all except denied)",
|
|
4123
|
+
"web.setup.security.request_timeout": "Network request timeout (ms)",
|
|
4124
|
+
"web.setup.security.max_response_size": "Max response size (bytes)",
|
|
4125
|
+
"web.setup.security.max_recursion": "Max subagent recursion depth",
|
|
4126
|
+
"web.setup.security.max_file_ops": "Max file operations per session",
|
|
4127
|
+
"web.setup.security.rate_rpm": "Max LLM requests per minute",
|
|
4128
|
+
"web.setup.security.rate_parallel": "Max parallel tasks",
|
|
4129
|
+
"web.setup.security.content_scan": "Scan file content for dangerous patterns",
|
|
4130
|
+
"web.setup.security.session_encryption": "Encrypt session logs on disk",
|
|
4131
|
+
"web.setup.security.audit_enabled": "Send security events to the audit notifier",
|
|
4132
|
+
"web.setup.security.audit_severity": "Minimum severity to notify",
|
|
4133
|
+
"web.setup.security.audit_events": "Notified event types",
|
|
4134
|
+
"web.setup.security.audit_retries": "Webhook max retries",
|
|
4135
|
+
"web.setup.security.audit_timeout": "Webhook timeout (ms)",
|
|
4136
|
+
"web.setup.security.severity.low": "low",
|
|
4137
|
+
"web.setup.security.severity.medium": "medium",
|
|
4138
|
+
"web.setup.security.severity.high": "high",
|
|
4139
|
+
"web.setup.security.severity.critical": "critical",
|
|
4054
4140
|
"web.setup.review.title": "Review",
|
|
4055
4141
|
"web.setup.review.hint": "Check the values, then finish. Settings are saved to your config.",
|
|
4056
4142
|
"web.setup.review.provider": "Provider",
|
|
@@ -4423,6 +4509,8 @@ var init_ru = __esm(() => {
|
|
|
4423
4509
|
{issues}
|
|
4424
4510
|
Сводка: {summary}`,
|
|
4425
4511
|
"critic.advice": `Верификатор отметил проблемы, которые стоит проверить до завершения:
|
|
4512
|
+
{issues}`,
|
|
4513
|
+
"critic.repeat": `Верификатор повторяет уже отмеченную проблему — не выдавай тот же ответ снова. Смени подход или заверши честно, если жалоба неприменима:
|
|
4426
4514
|
{issues}`,
|
|
4427
4515
|
"tool.subagent_queued": "Задача подагенту добавлена: {task}",
|
|
4428
4516
|
"tool.subagent_artifact": `Суб-агент завершён. Полный результат сохранён в артефакт: {path}
|
|
@@ -5221,6 +5309,7 @@ var init_ru = __esm(() => {
|
|
|
5221
5309
|
"ui.todo_action": "{action} · {count}",
|
|
5222
5310
|
"ui.tool_running": "{tool}…",
|
|
5223
5311
|
"ui.step_context": "шаг {id}: {desc}",
|
|
5312
|
+
"ui.draft_retracted": "↳ черновик отклонён проверкой, уточняю…",
|
|
5224
5313
|
"indexer.map_header": "Карта проекта",
|
|
5225
5314
|
"indexer.top_directories": "Основные директории",
|
|
5226
5315
|
"indexer.files": "Файлы",
|
|
@@ -5398,6 +5487,46 @@ var init_ru = __esm(() => {
|
|
|
5398
5487
|
"web.sidebar.session": "сессия",
|
|
5399
5488
|
"web.sidebar.usage": "использование",
|
|
5400
5489
|
"web.sidebar.env": "окружение",
|
|
5490
|
+
"web.sidebar.tab_session": "Сессия",
|
|
5491
|
+
"web.sidebar.tab_map": "Карта",
|
|
5492
|
+
"web.sidebar.tab_trace": "Трассировка",
|
|
5493
|
+
"web.sidebar.map_status": "статус",
|
|
5494
|
+
"web.sidebar.map_ready": "готово",
|
|
5495
|
+
"web.sidebar.map_indexing": "индексация…",
|
|
5496
|
+
"web.sidebar.map_stale": "устарело",
|
|
5497
|
+
"web.sidebar.map_updated": "обновлено",
|
|
5498
|
+
"web.sidebar.map_never": "никогда",
|
|
5499
|
+
"web.sidebar.map_today": "сегодня, {time}",
|
|
5500
|
+
"web.sidebar.map_watcher": "вотчер",
|
|
5501
|
+
"web.sidebar.map_on": "вкл.",
|
|
5502
|
+
"web.sidebar.map_off": "выкл.",
|
|
5503
|
+
"web.sidebar.map_files": "файлы",
|
|
5504
|
+
"web.sidebar.map_symbols": "символы",
|
|
5505
|
+
"web.sidebar.map_tokens": "токены",
|
|
5506
|
+
"web.sidebar.map_root": "корень",
|
|
5507
|
+
"web.sidebar.map_languages": "языки",
|
|
5508
|
+
"web.sidebar.map_reindex": "Переиндексировать",
|
|
5509
|
+
"web.sidebar.map_reindexing": "переиндексация…",
|
|
5510
|
+
"web.sidebar.map_reindex_failed": "не удалось переиндексировать",
|
|
5511
|
+
"web.sidebar.trace_empty": "событий пока нет",
|
|
5512
|
+
"web.sidebar.trace_turn": "ход {n}",
|
|
5513
|
+
"web.sidebar.trace_text": "печатает… {count} симв.",
|
|
5514
|
+
"web.sidebar.trace_plan": "обновление плана",
|
|
5515
|
+
"web.sidebar.trace_question": "вопрос",
|
|
5516
|
+
"web.sidebar.detail_metadata": "метаданные",
|
|
5517
|
+
"web.sidebar.detail_arguments": "аргументы",
|
|
5518
|
+
"web.sidebar.detail_output": "вывод",
|
|
5519
|
+
"web.sidebar.detail_error": "ошибка",
|
|
5520
|
+
"web.sidebar.detail_text": "текст",
|
|
5521
|
+
"web.sidebar.detail_plan": "план",
|
|
5522
|
+
"web.sidebar.detail_reasoning": "размышление",
|
|
5523
|
+
"web.sidebar.detail_status": "статус",
|
|
5524
|
+
"web.sidebar.detail_ok": "ok",
|
|
5525
|
+
"web.sidebar.detail_fail": "ошибка",
|
|
5526
|
+
"web.sidebar.detail_duration": "длительность",
|
|
5527
|
+
"web.sidebar.detail_time": "время",
|
|
5528
|
+
"web.sidebar.detail_tool_call": "вызов тула",
|
|
5529
|
+
"web.sidebar.detail_session": "сессия",
|
|
5401
5530
|
"web.env.dir": "директория",
|
|
5402
5531
|
"web.env.agents": "AGENTS.md",
|
|
5403
5532
|
"web.env.map": "карта",
|
|
@@ -5765,6 +5894,7 @@ var init_ru = __esm(() => {
|
|
|
5765
5894
|
"web.history.loading": "загрузка…",
|
|
5766
5895
|
"web.history.unavailable": "— история недоступна",
|
|
5767
5896
|
"web.history.empty": "— пустая сессия —",
|
|
5897
|
+
"web.scroll.latest": "к новому",
|
|
5768
5898
|
"web.tool.output_one": "вывод · {count} символ",
|
|
5769
5899
|
"web.tool.output_few": "вывод · {count} символа",
|
|
5770
5900
|
"web.tool.output_many": "вывод · {count} символов",
|
|
@@ -5774,13 +5904,12 @@ var init_ru = __esm(() => {
|
|
|
5774
5904
|
"web.code.copy_failed": "не скопировано",
|
|
5775
5905
|
"web.msg.copy": "копировать",
|
|
5776
5906
|
"web.msg.copy_md": "копировать как markdown",
|
|
5777
|
-
"web.card.open": "открыть ↗",
|
|
5778
|
-
"web.card.download": "скачать ⤓",
|
|
5779
|
-
"web.card.copy_path": "путь",
|
|
5780
5907
|
"web.card.open_title": "Предпросмотр во вкладке браузера",
|
|
5781
|
-
"web.card.download_title": "Скачать файл",
|
|
5782
5908
|
"web.card.copy_title": "Скопировать путь в рабочей папке",
|
|
5783
5909
|
"web.card.drawio_hint": "Диаграмма draw.io — это XML: предпросмотр покажет код, схему смотри в draw.io / VS Code.",
|
|
5910
|
+
"web.card.files_one": "{count} файл",
|
|
5911
|
+
"web.card.files_few": "{count} файла",
|
|
5912
|
+
"web.card.files_many": "{count} файлов",
|
|
5784
5913
|
"web.card.screenshot": "снимок экрана",
|
|
5785
5914
|
"web.card.attached_image": "прикреплённое изображение",
|
|
5786
5915
|
"web.card.browser_viewport": "браузер · область просмотра",
|
|
@@ -5835,7 +5964,7 @@ var init_ru = __esm(() => {
|
|
|
5835
5964
|
"web.setup.language.title": "Выберите язык",
|
|
5836
5965
|
"web.setup.language.hint": "Используется для интерфейса.",
|
|
5837
5966
|
"web.setup.provider.title": "Выберите провайдера",
|
|
5838
|
-
"web.setup.provider.hint": "Для локальной модели выберите OpenAI-совместимый
|
|
5967
|
+
"web.setup.provider.hint": "Для локальной модели выберите OpenAI-совместимый вариант, просканируйте сервер и проверьте подключение перед продолжением.",
|
|
5839
5968
|
"web.setup.provider.base_url": "Базовый URL",
|
|
5840
5969
|
"web.setup.provider.scan": "Найти локальные серверы",
|
|
5841
5970
|
"web.setup.provider.scan_found_one": "Найден {count} сервер",
|
|
@@ -5844,6 +5973,10 @@ var init_ru = __esm(() => {
|
|
|
5844
5973
|
"web.setup.provider.scan_none": "Локальные серверы не найдены — введите URL вручную.",
|
|
5845
5974
|
"web.setup.provider.scan_failed": "Сканирование не удалось. Введите URL вручную.",
|
|
5846
5975
|
"web.setup.provider.required": "Укажите базовый URL.",
|
|
5976
|
+
"web.setup.provider.test": "Проверить подключение",
|
|
5977
|
+
"web.setup.provider.testing": "Проверка…",
|
|
5978
|
+
"web.setup.provider.test_ok": "Сервер отвечает.",
|
|
5979
|
+
"web.setup.provider.test_fail": "Не удалось связаться с сервером по этому URL.",
|
|
5847
5980
|
"web.setup.key.title": "API-ключ",
|
|
5848
5981
|
"web.setup.key.hint": "Для локальных серверов можно оставить пустым. Хранится только в файле конфигурации и больше не показывается.",
|
|
5849
5982
|
"web.setup.key.label": "Ключ",
|
|
@@ -5862,15 +5995,54 @@ var init_ru = __esm(() => {
|
|
|
5862
5995
|
"web.setup.model.test_fail": "Не удалось связаться с моделью.",
|
|
5863
5996
|
"web.setup.model.required": "Выберите или введите модель.",
|
|
5864
5997
|
"web.setup.context.title": "Контекст и итерации",
|
|
5865
|
-
"web.setup.context.hint": "
|
|
5998
|
+
"web.setup.context.hint": "Должно совпадать с контекстом, который провайдер выделяет этой модели. Нажмите «Определить» либо сверьтесь с LM Studio / Ollama / документацией провайдера.",
|
|
5866
5999
|
"web.setup.context.contextWindow": "Окно контекста (токены)",
|
|
5867
6000
|
"web.setup.context.maxToolIterations": "Максимум итераций тулов",
|
|
5868
6001
|
"web.setup.context.required": "Введите положительное число.",
|
|
6002
|
+
"web.setup.context.detect": "Определить у провайдера",
|
|
6003
|
+
"web.setup.context.detecting": "Определение…",
|
|
6004
|
+
"web.setup.context.detect_ok": "Контекст от провайдера: {count} токенов.",
|
|
6005
|
+
"web.setup.context.detect_fail": "Не удалось определить контекст — введите вручную.",
|
|
5869
6006
|
"web.setup.security.title": "Безопасность",
|
|
5870
|
-
"web.setup.security.hint": "Безопасные значения включены; отключайте только нужное.",
|
|
6007
|
+
"web.setup.security.hint": "Безопасные значения включены; отключайте только нужное. Ничего не блокируется молча — каждый переключатель лишь требует подтверждения перед опасным действием.",
|
|
5871
6008
|
"web.setup.security.paths": "Ограничить доступ к файлам рабочей папкой",
|
|
6009
|
+
"web.setup.security.paths_desc": "Агент читает и пишет только внутри рабочей папки, а перед доступом к .git, .env, ключам и другим чувствительным путям спросит подтверждения.",
|
|
5872
6010
|
"web.setup.security.bash": "Блокировать опасные shell-команды",
|
|
6011
|
+
"web.setup.security.bash_desc": "Блокирует разрушительные команды (rm, sudo, ssh, curl, shutdown, …). Вместо запуска агент спросит подтверждения.",
|
|
5873
6012
|
"web.setup.security.flags": "Блокировать опасные флаги команд",
|
|
6013
|
+
"web.setup.security.flags_desc": "Блокирует рискованные флаги (--force, -rf, …), которые делают безопасные команды опасными. Работает вместе с блокировкой команд.",
|
|
6014
|
+
"web.setup.security.configure": "Настроить",
|
|
6015
|
+
"web.setup.security.advanced": "Расширенные настройки безопасности",
|
|
6016
|
+
"web.setup.security.popup_hint": "По одному элементу в строке. Пустой список = выключено. Изменения применяются только к этой установке; позже их можно править в Настройках → Безопасность.",
|
|
6017
|
+
"web.setup.security.popup_done": "Готово",
|
|
6018
|
+
"web.setup.security.reset": "Сбросить к значениям по умолчанию",
|
|
6019
|
+
"web.setup.security.denied": "Всегда запрещённые пути",
|
|
6020
|
+
"web.setup.security.allowed": "Разрешены только эти пути (пусто = все, кроме запрещённых)",
|
|
6021
|
+
"web.setup.security.blacklist": "Всегда блокируемые команды",
|
|
6022
|
+
"web.setup.security.whitelist": "Разрешены только эти команды (пусто = все, кроме блокируемых)",
|
|
6023
|
+
"web.setup.security.log_commands": "Писать каждую выполненную команду в аудит-лог",
|
|
6024
|
+
"web.setup.security.dangerous_flags": "Блокируемые флаги команд",
|
|
6025
|
+
"web.setup.security.dangerous_operators": "Блокируемые shell-операторы",
|
|
6026
|
+
"web.setup.security.network_enabled": "Сетевая защита (блокировать приватные/внутренние адреса)",
|
|
6027
|
+
"web.setup.security.denied_domains": "Всегда запрещённые домены",
|
|
6028
|
+
"web.setup.security.allowed_domains": "Разрешены только эти домены (пусто = все, кроме запрещённых)",
|
|
6029
|
+
"web.setup.security.request_timeout": "Таймаут сетевых запросов (мс)",
|
|
6030
|
+
"web.setup.security.max_response_size": "Максимум размера ответа (байты)",
|
|
6031
|
+
"web.setup.security.max_recursion": "Максимум глубины рекурсии субагентов",
|
|
6032
|
+
"web.setup.security.max_file_ops": "Максимум файловых операций за сессию",
|
|
6033
|
+
"web.setup.security.rate_rpm": "Максимум LLM-запросов в минуту",
|
|
6034
|
+
"web.setup.security.rate_parallel": "Максимум параллельных задач",
|
|
6035
|
+
"web.setup.security.content_scan": "Сканировать содержимое файлов на опасные паттерны",
|
|
6036
|
+
"web.setup.security.session_encryption": "Шифровать логи сессий на диске",
|
|
6037
|
+
"web.setup.security.audit_enabled": "Отправлять события безопасности в аудит-нотификатор",
|
|
6038
|
+
"web.setup.security.audit_severity": "Минимальная severity для уведомления",
|
|
6039
|
+
"web.setup.security.audit_events": "Типы событий для уведомления",
|
|
6040
|
+
"web.setup.security.audit_retries": "Повторы вебхука",
|
|
6041
|
+
"web.setup.security.audit_timeout": "Таймаут вебхука (мс)",
|
|
6042
|
+
"web.setup.security.severity.low": "низкая",
|
|
6043
|
+
"web.setup.security.severity.medium": "средняя",
|
|
6044
|
+
"web.setup.security.severity.high": "высокая",
|
|
6045
|
+
"web.setup.security.severity.critical": "критическая",
|
|
5874
6046
|
"web.setup.review.title": "Проверка",
|
|
5875
6047
|
"web.setup.review.hint": "Проверьте значения и завершите. Настройки сохранятся в конфиг.",
|
|
5876
6048
|
"web.setup.review.provider": "Провайдер",
|
|
@@ -9465,6 +9637,9 @@ class OpenAICompatProvider {
|
|
|
9465
9637
|
this.userAgent = config.userAgent ?? defaultUserAgent();
|
|
9466
9638
|
this.debug = config.logger ? config.logger.debug.bind(config.logger) : null;
|
|
9467
9639
|
}
|
|
9640
|
+
get idleTimeoutMs() {
|
|
9641
|
+
return this.retryConfig.noDataTimeoutMs ?? 180000;
|
|
9642
|
+
}
|
|
9468
9643
|
async* chat(messages, tools, signal, options) {
|
|
9469
9644
|
if (!this.rateLimiter.canMakeRequest()) {
|
|
9470
9645
|
const waitMs = Math.min(this.rateLimiter.msUntilRequest(), LLM_MAX_RATE_WAIT_MS);
|
|
@@ -9495,7 +9670,7 @@ class OpenAICompatProvider {
|
|
|
9495
9670
|
}
|
|
9496
9671
|
if (!hasToolCall && !hasText) {
|
|
9497
9672
|
this.debug?.("LLM streaming produced no text/tool_call — falling back to non-streaming");
|
|
9498
|
-
const fallback = await this.doNonStreaming(effectiveMessages, tools, signal, options);
|
|
9673
|
+
const fallback = await this.doNonStreaming(effectiveMessages, tools, signal, options, this.idleTimeoutMs);
|
|
9499
9674
|
this.debug?.("LLM non-streaming fallback result", { chunks: fallback.length });
|
|
9500
9675
|
for (const chunk of fallback) {
|
|
9501
9676
|
if (hasReasoning && chunk.type === "reasoning")
|
|
@@ -9522,9 +9697,9 @@ ${tag}`;
|
|
|
9522
9697
|
return copy;
|
|
9523
9698
|
}
|
|
9524
9699
|
async* doStream(messages, tools, signal, options) {
|
|
9525
|
-
const { baseDelay, maxDelay, maxStreamRetries
|
|
9700
|
+
const { baseDelay, maxDelay, maxStreamRetries } = this.retryConfig;
|
|
9526
9701
|
const streamRetries = maxStreamRetries ?? 2;
|
|
9527
|
-
const idleTimeoutMs =
|
|
9702
|
+
const idleTimeoutMs = this.idleTimeoutMs;
|
|
9528
9703
|
let usedNonStreamingFallback = false;
|
|
9529
9704
|
for (let attempt = 0;; attempt++) {
|
|
9530
9705
|
let emitted = false;
|
|
@@ -9543,7 +9718,7 @@ ${tag}`;
|
|
|
9543
9718
|
if (err?.stalledAfterToolCall === true && !usedNonStreamingFallback) {
|
|
9544
9719
|
usedNonStreamingFallback = true;
|
|
9545
9720
|
this.debug?.("LLM stream stalled after tool_call — falling back to non-streaming request");
|
|
9546
|
-
const fallback = await this.doNonStreaming(messages, tools, signal, options);
|
|
9721
|
+
const fallback = await this.doNonStreaming(messages, tools, signal, options, idleTimeoutMs);
|
|
9547
9722
|
this.debug?.("LLM non-streaming fallback result", { chunks: fallback.length });
|
|
9548
9723
|
for (const chunk of fallback) {
|
|
9549
9724
|
if (chunk.type === "reasoning")
|
|
@@ -9590,8 +9765,12 @@ ${tag}`;
|
|
|
9590
9765
|
signal: abortSignal
|
|
9591
9766
|
});
|
|
9592
9767
|
} catch (err) {
|
|
9593
|
-
if (err?.name === "AbortError")
|
|
9768
|
+
if (err?.name === "AbortError") {
|
|
9769
|
+
if (isTimeout()) {
|
|
9770
|
+
throw new Error(t("error.llm_timeout", { timeout: LLM_REQUEST_TIMEOUT_MS }));
|
|
9771
|
+
}
|
|
9594
9772
|
throw err;
|
|
9773
|
+
}
|
|
9595
9774
|
const wrapped = err instanceof Error ? err : new Error(String(err));
|
|
9596
9775
|
if (wrapped instanceof LlmError) {
|
|
9597
9776
|
wrapped.markTerminal();
|
|
@@ -9618,6 +9797,7 @@ ${tag}`;
|
|
|
9618
9797
|
cleanup();
|
|
9619
9798
|
throw new Error(t("error.no_response_body"));
|
|
9620
9799
|
}
|
|
9800
|
+
cleanup();
|
|
9621
9801
|
const decoder = new TextDecoder;
|
|
9622
9802
|
let buffer = "";
|
|
9623
9803
|
const toolCallAccs = new Map;
|
|
@@ -9783,7 +9963,7 @@ ${tag}`;
|
|
|
9783
9963
|
streamUsage: this.cache?.requestStreamUsage === true
|
|
9784
9964
|
};
|
|
9785
9965
|
}
|
|
9786
|
-
buildRequestSetup(signal) {
|
|
9966
|
+
buildRequestSetup(signal, totalTimeoutMs = LLM_REQUEST_TIMEOUT_MS) {
|
|
9787
9967
|
const headers = {
|
|
9788
9968
|
"Content-Type": "application/json",
|
|
9789
9969
|
"User-Agent": this.userAgent
|
|
@@ -9800,7 +9980,7 @@ ${tag}`;
|
|
|
9800
9980
|
const timeoutId = setTimeout(() => {
|
|
9801
9981
|
timedOut = true;
|
|
9802
9982
|
controller.abort();
|
|
9803
|
-
},
|
|
9983
|
+
}, totalTimeoutMs);
|
|
9804
9984
|
const abortSignal = (() => {
|
|
9805
9985
|
if (!signal)
|
|
9806
9986
|
return controller.signal;
|
|
@@ -9824,7 +10004,7 @@ ${tag}`;
|
|
|
9824
10004
|
controller
|
|
9825
10005
|
};
|
|
9826
10006
|
}
|
|
9827
|
-
async doNonStreaming(messages, tools, signal, options) {
|
|
10007
|
+
async doNonStreaming(messages, tools, signal, options, totalTimeoutMs = LLM_REQUEST_TIMEOUT_MS) {
|
|
9828
10008
|
const maxTokens = options?.maxTokens ?? this.config.maxCompletionTokens ?? DEFAULT_MAX_COMPLETION_TOKENS;
|
|
9829
10009
|
const body = buildRequestBody({
|
|
9830
10010
|
model: this.model,
|
|
@@ -9836,7 +10016,7 @@ ${tag}`;
|
|
|
9836
10016
|
reasoningStrategy: options?.reasoningStrategy,
|
|
9837
10017
|
...this.cacheHints()
|
|
9838
10018
|
});
|
|
9839
|
-
const { headers, abortSignal, cleanup, isTimeout } = this.buildRequestSetup(signal);
|
|
10019
|
+
const { headers, abortSignal, cleanup, isTimeout } = this.buildRequestSetup(signal, totalTimeoutMs);
|
|
9840
10020
|
try {
|
|
9841
10021
|
const response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
|
|
9842
10022
|
method: "POST",
|
|
@@ -9901,7 +10081,7 @@ ${tag}`;
|
|
|
9901
10081
|
return chunks;
|
|
9902
10082
|
} catch (err) {
|
|
9903
10083
|
if (isTimeout() && err?.name === "AbortError") {
|
|
9904
|
-
throw new Error(t("error.llm_timeout", { timeout:
|
|
10084
|
+
throw new Error(t("error.llm_timeout", { timeout: totalTimeoutMs }));
|
|
9905
10085
|
}
|
|
9906
10086
|
throw err instanceof Error ? err : new Error(String(err));
|
|
9907
10087
|
} finally {
|
|
@@ -11726,10 +11906,23 @@ var init_walker = __esm(() => {
|
|
|
11726
11906
|
// src/modules/indexer/cache.ts
|
|
11727
11907
|
import { readFileSync as readFileSync14, writeFileSync as writeFileSync10, existsSync as existsSync18, mkdirSync as mkdirSync11, rmSync } from "fs";
|
|
11728
11908
|
import { join as join20 } from "path";
|
|
11909
|
+
function isIndexedFile(v) {
|
|
11910
|
+
if (typeof v !== "object" || v === null)
|
|
11911
|
+
return false;
|
|
11912
|
+
const f = v;
|
|
11913
|
+
return typeof f.path === "string" && typeof f.language === "string" && Array.isArray(f.exports) && typeof f.size === "number";
|
|
11914
|
+
}
|
|
11915
|
+
function isIndexResult(v) {
|
|
11916
|
+
if (typeof v !== "object" || v === null)
|
|
11917
|
+
return false;
|
|
11918
|
+
const r = v;
|
|
11919
|
+
return Array.isArray(r.files) && r.files.every(isIndexedFile) && typeof r.totalSize === "number";
|
|
11920
|
+
}
|
|
11729
11921
|
|
|
11730
11922
|
class IndexCache {
|
|
11731
11923
|
cachePath;
|
|
11732
11924
|
cache = null;
|
|
11925
|
+
cachedBuiltAt = null;
|
|
11733
11926
|
root;
|
|
11734
11927
|
signature;
|
|
11735
11928
|
constructor(cacheDir, opts = {}) {
|
|
@@ -11744,24 +11937,28 @@ class IndexCache {
|
|
|
11744
11937
|
return null;
|
|
11745
11938
|
try {
|
|
11746
11939
|
const parsed = JSON.parse(readFileSync14(this.cachePath, "utf-8"));
|
|
11747
|
-
if (parsed.version !== CACHE_VERSION || !parsed.result)
|
|
11940
|
+
if (parsed.version !== CACHE_VERSION || !isIndexResult(parsed.result))
|
|
11748
11941
|
return null;
|
|
11749
11942
|
if (this.root !== undefined && parsed.root !== this.root)
|
|
11750
11943
|
return null;
|
|
11751
11944
|
if (this.signature && parsed.signature !== this.currentSignature())
|
|
11752
11945
|
return null;
|
|
11753
11946
|
this.cache = parsed.result;
|
|
11947
|
+
this.cachedBuiltAt = typeof parsed.builtAt === "number" ? parsed.builtAt : null;
|
|
11754
11948
|
return this.cache;
|
|
11755
11949
|
} catch {
|
|
11756
11950
|
return null;
|
|
11757
11951
|
}
|
|
11758
11952
|
}
|
|
11759
11953
|
save(result) {
|
|
11954
|
+
const now = Date.now();
|
|
11760
11955
|
this.cache = result;
|
|
11956
|
+
this.cachedBuiltAt = now;
|
|
11761
11957
|
const envelope = {
|
|
11762
11958
|
version: CACHE_VERSION,
|
|
11763
11959
|
root: this.root ?? "",
|
|
11764
11960
|
signature: this.currentSignature(),
|
|
11961
|
+
builtAt: now,
|
|
11765
11962
|
result
|
|
11766
11963
|
};
|
|
11767
11964
|
const dir = join20(this.cachePath, "..");
|
|
@@ -11771,12 +11968,16 @@ class IndexCache {
|
|
|
11771
11968
|
}
|
|
11772
11969
|
invalidate() {
|
|
11773
11970
|
this.cache = null;
|
|
11971
|
+
this.cachedBuiltAt = null;
|
|
11774
11972
|
if (existsSync18(this.cachePath)) {
|
|
11775
11973
|
try {
|
|
11776
11974
|
rmSync(this.cachePath);
|
|
11777
11975
|
} catch {}
|
|
11778
11976
|
}
|
|
11779
11977
|
}
|
|
11978
|
+
getBuiltAt() {
|
|
11979
|
+
return this.cachedBuiltAt;
|
|
11980
|
+
}
|
|
11780
11981
|
currentSignature() {
|
|
11781
11982
|
if (!this.signature)
|
|
11782
11983
|
return "";
|
|
@@ -12104,7 +12305,11 @@ class IndexerModule {
|
|
|
12104
12305
|
cache;
|
|
12105
12306
|
baseDir;
|
|
12106
12307
|
index = null;
|
|
12107
|
-
|
|
12308
|
+
mapCache = null;
|
|
12309
|
+
buildPromise = null;
|
|
12310
|
+
indexing = false;
|
|
12311
|
+
builtAt = null;
|
|
12312
|
+
watcherActive = false;
|
|
12108
12313
|
rebuildTimeout = null;
|
|
12109
12314
|
constructor(opts) {
|
|
12110
12315
|
this.baseDir = opts.baseDir;
|
|
@@ -12114,26 +12319,38 @@ class IndexerModule {
|
|
|
12114
12319
|
signature: () => this.indexer.scanSignature()
|
|
12115
12320
|
});
|
|
12116
12321
|
}
|
|
12117
|
-
|
|
12322
|
+
buildIndex() {
|
|
12118
12323
|
if (this.index)
|
|
12119
|
-
return this.index;
|
|
12324
|
+
return Promise.resolve(this.index);
|
|
12325
|
+
if (this.buildPromise)
|
|
12326
|
+
return this.buildPromise;
|
|
12120
12327
|
const cached = this.cache.load();
|
|
12121
12328
|
if (cached) {
|
|
12122
12329
|
this.index = cached;
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
try {
|
|
12126
|
-
const result = await this.indexer.walk();
|
|
12127
|
-
this.cache.save(result);
|
|
12128
|
-
this.index = result;
|
|
12129
|
-
return result;
|
|
12130
|
-
} catch {
|
|
12131
|
-
return null;
|
|
12330
|
+
this.builtAt = this.cache.getBuiltAt();
|
|
12331
|
+
return Promise.resolve(cached);
|
|
12132
12332
|
}
|
|
12333
|
+
this.indexing = true;
|
|
12334
|
+
this.buildPromise = (async () => {
|
|
12335
|
+
try {
|
|
12336
|
+
const result = await this.indexer.walk();
|
|
12337
|
+
this.cache.save(result);
|
|
12338
|
+
this.index = result;
|
|
12339
|
+
this.builtAt = Date.now();
|
|
12340
|
+
return result;
|
|
12341
|
+
} catch {
|
|
12342
|
+
return null;
|
|
12343
|
+
} finally {
|
|
12344
|
+
this.indexing = false;
|
|
12345
|
+
this.buildPromise = null;
|
|
12346
|
+
}
|
|
12347
|
+
})();
|
|
12348
|
+
return this.buildPromise;
|
|
12133
12349
|
}
|
|
12134
12350
|
async refresh() {
|
|
12135
12351
|
this.cache.invalidate();
|
|
12136
12352
|
this.index = null;
|
|
12353
|
+
this.builtAt = null;
|
|
12137
12354
|
return this.buildIndex();
|
|
12138
12355
|
}
|
|
12139
12356
|
find(query) {
|
|
@@ -12173,9 +12390,11 @@ class IndexerModule {
|
|
|
12173
12390
|
this.refresh().catch(() => {});
|
|
12174
12391
|
}, 2000);
|
|
12175
12392
|
});
|
|
12393
|
+
this.watcherActive = true;
|
|
12176
12394
|
} catch {}
|
|
12177
12395
|
}
|
|
12178
12396
|
unwatch() {
|
|
12397
|
+
this.watcherActive = false;
|
|
12179
12398
|
if (this.rebuildTimeout) {
|
|
12180
12399
|
clearTimeout(this.rebuildTimeout);
|
|
12181
12400
|
this.rebuildTimeout = null;
|
|
@@ -12194,19 +12413,47 @@ class IndexerModule {
|
|
|
12194
12413
|
kind: "project-map"
|
|
12195
12414
|
};
|
|
12196
12415
|
}
|
|
12197
|
-
|
|
12198
|
-
if (!this.index)
|
|
12199
|
-
return
|
|
12200
|
-
|
|
12201
|
-
|
|
12416
|
+
mapInfo() {
|
|
12417
|
+
if (!this.index) {
|
|
12418
|
+
return {
|
|
12419
|
+
indexed: false,
|
|
12420
|
+
indexing: this.indexing,
|
|
12421
|
+
files: 0,
|
|
12422
|
+
symbols: 0,
|
|
12423
|
+
tokens: 0,
|
|
12424
|
+
updatedAt: this.builtAt,
|
|
12425
|
+
languages: [],
|
|
12426
|
+
watcher: this.watcherActive
|
|
12427
|
+
};
|
|
12428
|
+
}
|
|
12429
|
+
if (this.mapCache && this.mapCache.index === this.index) {
|
|
12430
|
+
return { ...this.mapCache.value, indexing: this.indexing, watcher: this.watcherActive };
|
|
12431
|
+
}
|
|
12202
12432
|
const symbols = this.index.files.reduce((n, f) => n + f.exports.length, 0);
|
|
12433
|
+
const langMap = new Map;
|
|
12434
|
+
for (const f of this.index.files) {
|
|
12435
|
+
const lang = f.language;
|
|
12436
|
+
const cur = langMap.get(lang) ?? { files: 0, symbols: 0 };
|
|
12437
|
+
cur.files += 1;
|
|
12438
|
+
cur.symbols += f.exports.length;
|
|
12439
|
+
langMap.set(lang, cur);
|
|
12440
|
+
}
|
|
12441
|
+
const languages = [...langMap.entries()].map(([language, v]) => ({ language, ...v })).sort((a, b) => b.files - a.files || a.language.localeCompare(b.language)).slice(0, 8);
|
|
12203
12442
|
const value = {
|
|
12443
|
+
indexed: true,
|
|
12204
12444
|
files: this.index.files.length,
|
|
12205
12445
|
symbols,
|
|
12206
|
-
tokens: this.estimateTokens(this.formatMap(this.index))
|
|
12446
|
+
tokens: this.estimateTokens(this.formatMap(this.index)),
|
|
12447
|
+
updatedAt: this.builtAt,
|
|
12448
|
+
languages,
|
|
12449
|
+
watcher: this.watcherActive
|
|
12207
12450
|
};
|
|
12208
|
-
this.
|
|
12209
|
-
return value;
|
|
12451
|
+
this.mapCache = { index: this.index, value };
|
|
12452
|
+
return { ...value, indexing: this.indexing };
|
|
12453
|
+
}
|
|
12454
|
+
stats() {
|
|
12455
|
+
const info = this.mapInfo();
|
|
12456
|
+
return info.indexed ? { files: info.files, symbols: info.symbols, tokens: info.tokens } : null;
|
|
12210
12457
|
}
|
|
12211
12458
|
getToolDefinitions() {
|
|
12212
12459
|
return [this.createProjectMapTool()];
|
|
@@ -16828,6 +17075,15 @@ class SessionLogger {
|
|
|
16828
17075
|
...data
|
|
16829
17076
|
});
|
|
16830
17077
|
}
|
|
17078
|
+
logClaimRetry(data) {
|
|
17079
|
+
this.session?.appendLog({
|
|
17080
|
+
ts: new Date().toISOString(),
|
|
17081
|
+
type: "claim_retry",
|
|
17082
|
+
content: data.reason,
|
|
17083
|
+
kind: data.kind,
|
|
17084
|
+
iteration: data.iteration
|
|
17085
|
+
});
|
|
17086
|
+
}
|
|
16831
17087
|
logCritic(event, data = {}) {
|
|
16832
17088
|
this.session?.appendLog({
|
|
16833
17089
|
ts: new Date().toISOString(),
|
|
@@ -19418,8 +19674,17 @@ function isFilePathLike(s) {
|
|
|
19418
19674
|
return true;
|
|
19419
19675
|
}
|
|
19420
19676
|
function extractFileLikeTokens(text) {
|
|
19421
|
-
const
|
|
19422
|
-
|
|
19677
|
+
const out = new Set;
|
|
19678
|
+
const re = new RegExp(FILE_TOKEN_RE.source, "gi");
|
|
19679
|
+
for (const m of text.matchAll(re)) {
|
|
19680
|
+
const token = m[0];
|
|
19681
|
+
const after = text[(m.index ?? 0) + token.length];
|
|
19682
|
+
if (after === "(")
|
|
19683
|
+
continue;
|
|
19684
|
+
if (isFilePathLike(token))
|
|
19685
|
+
out.add(token);
|
|
19686
|
+
}
|
|
19687
|
+
return [...out];
|
|
19423
19688
|
}
|
|
19424
19689
|
function stripUrls(text) {
|
|
19425
19690
|
return text.replace(/\bhttps?:\/\/[^\s"'<>]+/gi, " ");
|
|
@@ -20747,6 +21012,7 @@ function createLoopState() {
|
|
|
20747
21012
|
criticCalls: 0,
|
|
20748
21013
|
criticRepairCycles: 0,
|
|
20749
21014
|
mutationsSinceCritic: 0,
|
|
21015
|
+
criticHistoryMark: 0,
|
|
20750
21016
|
seenCriticIssues: new Set,
|
|
20751
21017
|
emptyResponseRetries: 0,
|
|
20752
21018
|
emptyResponseExhausted: false,
|
|
@@ -21557,6 +21823,7 @@ class HallucinationGate {
|
|
|
21557
21823
|
return { action: "warn" };
|
|
21558
21824
|
}
|
|
21559
21825
|
if (result.status === "retry") {
|
|
21826
|
+
this.retractDraft(deps, result.kind ?? "retry", result.reason ?? "");
|
|
21560
21827
|
return this.applyRetry(deps, textContent, result);
|
|
21561
21828
|
}
|
|
21562
21829
|
const claimRetry = this.checkSuccessClaim(deps, textContent);
|
|
@@ -21605,30 +21872,35 @@ class HallucinationGate {
|
|
|
21605
21872
|
return this.retryClaim(deps, textContent, t("hall.claim_contradiction", {
|
|
21606
21873
|
tool: contradiction.tool,
|
|
21607
21874
|
snippet: contradiction.snippet
|
|
21608
|
-
}), `Success-claim contradiction: ${contradiction.tool}: ${contradiction.snippet}
|
|
21875
|
+
}), `Success-claim contradiction: ${contradiction.tool}: ${contradiction.snippet}`, "success");
|
|
21609
21876
|
}
|
|
21610
21877
|
}
|
|
21611
21878
|
if (state.artifactClaimRetries < MAX_CLAIM_CHECK_RETRIES && deps.artifacts && deps.artifacts.length > 0) {
|
|
21612
21879
|
const artifact = checkArtifactClaims(text, deps.artifacts);
|
|
21613
21880
|
if (artifact) {
|
|
21614
21881
|
state.artifactClaimRetries++;
|
|
21615
|
-
return this.retryClaim(deps, textContent, t("hall.claim_artifact", { path: artifact.path, detail: artifact.snippet }), `Artifact-claim contradiction: ${artifact.snippet}
|
|
21882
|
+
return this.retryClaim(deps, textContent, t("hall.claim_artifact", { path: artifact.path, detail: artifact.snippet }), `Artifact-claim contradiction: ${artifact.snippet}`, "artifact");
|
|
21616
21883
|
}
|
|
21617
21884
|
}
|
|
21618
21885
|
if (state.outputClaimRetries < MAX_CLAIM_CHECK_RETRIES) {
|
|
21619
21886
|
const unverified = checkUnverifiedOutput(text, evidence);
|
|
21620
21887
|
if (unverified) {
|
|
21621
21888
|
state.outputClaimRetries++;
|
|
21622
|
-
return this.retryClaim(deps, textContent, t("hall.claim_output_unverified", { detail: unverified.snippet }), `Unverified output: ${unverified.snippet}
|
|
21889
|
+
return this.retryClaim(deps, textContent, t("hall.claim_output_unverified", { detail: unverified.snippet }), `Unverified output: ${unverified.snippet}`, "output");
|
|
21623
21890
|
}
|
|
21624
21891
|
}
|
|
21625
21892
|
return null;
|
|
21626
21893
|
}
|
|
21627
|
-
|
|
21894
|
+
retractDraft(deps, kind, reason) {
|
|
21895
|
+
deps.onMeta?.(t("ui.draft_retracted"), "retract");
|
|
21896
|
+
deps.slog?.logClaimRetry({ kind, reason, iteration: deps.state.iteration });
|
|
21897
|
+
}
|
|
21898
|
+
retryClaim(deps, textContent, reason, logLine, kind) {
|
|
21628
21899
|
const { state, logger: logger3 } = deps;
|
|
21629
21900
|
state.iterHallucinationRetry = true;
|
|
21630
21901
|
state.suppressRepetitionRetry = true;
|
|
21631
21902
|
logger3.diagnostic("warn", logLine);
|
|
21903
|
+
this.retractDraft(deps, kind, reason);
|
|
21632
21904
|
if (textContent) {
|
|
21633
21905
|
deps.contextManager.addMessage({ role: "assistant", content: textContent });
|
|
21634
21906
|
}
|
|
@@ -21687,27 +21959,30 @@ function resolveArtifactStates(baseDir, response) {
|
|
|
21687
21959
|
const rel = relative6(baseDir, abs);
|
|
21688
21960
|
if (rel.startsWith("..") || isAbsolute4(rel))
|
|
21689
21961
|
continue;
|
|
21690
|
-
const state = resolveOneArtifact(token,
|
|
21962
|
+
const state = resolveOneArtifact(token, baseDir);
|
|
21691
21963
|
if (state)
|
|
21692
21964
|
out.push(state);
|
|
21693
21965
|
}
|
|
21694
21966
|
return out;
|
|
21695
21967
|
}
|
|
21696
|
-
function resolveOneArtifact(token,
|
|
21968
|
+
function resolveOneArtifact(token, baseDir) {
|
|
21969
|
+
const found = findExistingFile(baseDir, token);
|
|
21970
|
+
if (!found)
|
|
21971
|
+
return { path: token, exists: false };
|
|
21697
21972
|
let size;
|
|
21698
21973
|
try {
|
|
21699
|
-
const st = statSync8(
|
|
21974
|
+
const st = statSync8(found);
|
|
21700
21975
|
if (!st.isFile())
|
|
21701
21976
|
return { path: token, exists: false };
|
|
21702
21977
|
size = st.size;
|
|
21703
21978
|
} catch {
|
|
21704
|
-
return { path: token, exists:
|
|
21979
|
+
return { path: token, exists: true };
|
|
21705
21980
|
}
|
|
21706
21981
|
if (size > MAX_BYTES)
|
|
21707
21982
|
return { path: token, exists: true };
|
|
21708
21983
|
let content;
|
|
21709
21984
|
try {
|
|
21710
|
-
content = readFileSync25(
|
|
21985
|
+
content = readFileSync25(found, "utf-8");
|
|
21711
21986
|
} catch {
|
|
21712
21987
|
return { path: token, exists: true };
|
|
21713
21988
|
}
|
|
@@ -21717,6 +21992,7 @@ var MAX_PATHS = 10, MAX_BYTES, JSON_EXTS, XML_EXTS;
|
|
|
21717
21992
|
var init_artifact_resolve = __esm(() => {
|
|
21718
21993
|
init_js_identifiers();
|
|
21719
21994
|
init_syntax_validator();
|
|
21995
|
+
init_auditor();
|
|
21720
21996
|
MAX_BYTES = 500 * 1024;
|
|
21721
21997
|
JSON_EXTS = new Set([".json", ".jsonc"]);
|
|
21722
21998
|
XML_EXTS = new Set([".xml", ".drawio", ".svg", ".xaml", ".plist", ".iml"]);
|
|
@@ -21754,6 +22030,7 @@ class AuditGate {
|
|
|
21754
22030
|
return { action: "exhausted", summary: audit.summary };
|
|
21755
22031
|
}
|
|
21756
22032
|
state.suppressRepetitionRetry = true;
|
|
22033
|
+
deps.onMeta?.(t("ui.draft_retracted"), "retract");
|
|
21757
22034
|
return { action: "reject" };
|
|
21758
22035
|
}
|
|
21759
22036
|
}
|
|
@@ -21765,10 +22042,17 @@ var init_audit_gate = __esm(() => {
|
|
|
21765
22042
|
function issueSignature(issue) {
|
|
21766
22043
|
return `${issue.severity}:${issue.claim}`.toLowerCase().replace(/\s+/g, " ").slice(0, 120);
|
|
21767
22044
|
}
|
|
22045
|
+
function normalizedSignature(issue) {
|
|
22046
|
+
const body = `${issue.severity}:${issue.claim}`.toLowerCase().replace(/[^a-z0-9а-яё\s]/gi, " ").replace(/\s+/g, " ").trim().slice(0, 120);
|
|
22047
|
+
return `~${body}`;
|
|
22048
|
+
}
|
|
21768
22049
|
function renderIssues(issues) {
|
|
21769
22050
|
return issues.slice(0, 5).map((i) => `- [${i.severity}] ${i.problem || i.claim}${i.suggestion ? ` → ${i.suggestion}` : ""}`).join(`
|
|
21770
22051
|
`);
|
|
21771
22052
|
}
|
|
22053
|
+
function isRepeatedVerdict(state, issues) {
|
|
22054
|
+
return issues.length > 0 && issues.every((i) => state.seenCriticIssues.has(normalizedSignature(i)));
|
|
22055
|
+
}
|
|
21772
22056
|
|
|
21773
22057
|
class CriticGate {
|
|
21774
22058
|
opts;
|
|
@@ -21784,18 +22068,26 @@ class CriticGate {
|
|
|
21784
22068
|
const verdict = await this.verifySafely(deps);
|
|
21785
22069
|
if (!verdict || verdict.status === "ok")
|
|
21786
22070
|
return "pass";
|
|
22071
|
+
const isRepeat = isRepeatedVerdict(deps.state, verdict.issues);
|
|
21787
22072
|
const fresh = this.takeFreshIssues(deps.state, verdict.issues);
|
|
21788
22073
|
if (fresh.length === 0)
|
|
21789
22074
|
return "pass";
|
|
21790
22075
|
this.logVerdict(deps, verdict, fresh.length);
|
|
21791
|
-
|
|
21792
|
-
|
|
22076
|
+
if (!this.shouldRepair(deps, verdict, isRepeat)) {
|
|
22077
|
+
this.injectRepeatOrAdvice(deps, fresh, isRepeat);
|
|
22078
|
+
return "pass";
|
|
22079
|
+
}
|
|
22080
|
+
this.injectRepair(deps, verdict, fresh);
|
|
21793
22081
|
return "retry";
|
|
21794
22082
|
}
|
|
22083
|
+
shouldRepair(deps, verdict, isRepeat) {
|
|
22084
|
+
return verdict.status === "critical" && deps.beforeFinish && deps.state.criticRepairCycles < this.opts.maxRepairCycles && !isRepeat;
|
|
22085
|
+
}
|
|
21795
22086
|
async verifySafely(deps) {
|
|
21796
22087
|
try {
|
|
21797
22088
|
return await this.opts.verify(this.opts.buildPack(deps), this.opts.signal);
|
|
21798
|
-
} catch {
|
|
22089
|
+
} catch (err) {
|
|
22090
|
+
deps.logger.diagnostic("warn", `Critic verify failed (fail-open): ${String(err?.message ?? err)}`);
|
|
21799
22091
|
return null;
|
|
21800
22092
|
}
|
|
21801
22093
|
}
|
|
@@ -21804,9 +22096,8 @@ class CriticGate {
|
|
|
21804
22096
|
return false;
|
|
21805
22097
|
if (deps.state.criticCalls >= this.opts.maxCalls)
|
|
21806
22098
|
return false;
|
|
21807
|
-
if (!deps.beforeFinish
|
|
22099
|
+
if (!deps.beforeFinish)
|
|
21808
22100
|
return false;
|
|
21809
|
-
}
|
|
21810
22101
|
return deps.toolEvents.length !== 0;
|
|
21811
22102
|
}
|
|
21812
22103
|
takeFreshIssues(state, issues) {
|
|
@@ -21816,6 +22107,7 @@ class CriticGate {
|
|
|
21816
22107
|
if (state.seenCriticIssues.has(sig))
|
|
21817
22108
|
continue;
|
|
21818
22109
|
state.seenCriticIssues.add(sig);
|
|
22110
|
+
state.seenCriticIssues.add(normalizedSignature(issue));
|
|
21819
22111
|
fresh.push(issue);
|
|
21820
22112
|
}
|
|
21821
22113
|
return fresh;
|
|
@@ -21836,15 +22128,15 @@ class CriticGate {
|
|
|
21836
22128
|
});
|
|
21837
22129
|
deps.logger.diagnostic("info", `Critic ${verdict.status}: ${verdict.summary} (${count} issue(s))`);
|
|
21838
22130
|
}
|
|
21839
|
-
|
|
21840
|
-
|
|
21841
|
-
|
|
21842
|
-
|
|
21843
|
-
|
|
21844
|
-
|
|
21845
|
-
|
|
21846
|
-
}
|
|
22131
|
+
injectRepeatOrAdvice(deps, fresh, isRepeat) {
|
|
22132
|
+
deps.contextManager.addMessage({
|
|
22133
|
+
role: "user",
|
|
22134
|
+
content: `<system-summary>${isRepeat ? t("critic.repeat", { issues: renderIssues(fresh) }) : t("critic.advice", { issues: renderIssues(fresh) })}</system-summary>`
|
|
22135
|
+
});
|
|
22136
|
+
}
|
|
22137
|
+
injectRepair(deps, verdict, fresh) {
|
|
21847
22138
|
deps.state.criticRepairCycles++;
|
|
22139
|
+
deps.onMeta?.(t("ui.draft_retracted"), "retract");
|
|
21848
22140
|
deps.slog.logCritic("critic_escalation", {
|
|
21849
22141
|
summary: verdict.summary,
|
|
21850
22142
|
cycle: deps.state.criticRepairCycles
|
|
@@ -21858,9 +22150,11 @@ class CriticGate {
|
|
|
21858
22150
|
});
|
|
21859
22151
|
}
|
|
21860
22152
|
}
|
|
21861
|
-
function gatherTurnToolEvents(contextManager) {
|
|
22153
|
+
function gatherTurnToolEvents(contextManager, fromIndex = 0) {
|
|
21862
22154
|
const events = [];
|
|
21863
|
-
|
|
22155
|
+
const history = contextManager.getActiveHistory();
|
|
22156
|
+
const start = Math.max(0, Math.min(fromIndex, history.length));
|
|
22157
|
+
for (const m of history.slice(start)) {
|
|
21864
22158
|
if (m.role !== "tool" || !m.name)
|
|
21865
22159
|
continue;
|
|
21866
22160
|
const output = typeof m.content === "string" ? m.content.slice(-MAX_EVENT_OUTPUT_CHARS) : undefined;
|
|
@@ -21868,7 +22162,7 @@ function gatherTurnToolEvents(contextManager) {
|
|
|
21868
22162
|
}
|
|
21869
22163
|
return events;
|
|
21870
22164
|
}
|
|
21871
|
-
var
|
|
22165
|
+
var MAX_EVENT_OUTPUT_CHARS = 600;
|
|
21872
22166
|
var init_critic_gate = __esm(() => {
|
|
21873
22167
|
init_i18n();
|
|
21874
22168
|
});
|
|
@@ -22055,7 +22349,9 @@ ${f.excerpt}`);
|
|
|
22055
22349
|
pack.toolDigest || "(empty)",
|
|
22056
22350
|
files.length > 0 ? `FILE CONTENTS:
|
|
22057
22351
|
${files.join(`
|
|
22058
|
-
`)}` : ""
|
|
22352
|
+
`)}` : "",
|
|
22353
|
+
pack.answerExcerpt ? `ANSWER (the agent's chat delivery — may satisfy the task without files):
|
|
22354
|
+
${pack.answerExcerpt}` : ""
|
|
22059
22355
|
].filter(Boolean).join(`
|
|
22060
22356
|
`);
|
|
22061
22357
|
}
|
|
@@ -22109,6 +22405,7 @@ Rules:
|
|
|
22109
22405
|
- Flag ONLY issues that can be verified from the evidence provided. Do not speculate or invent.
|
|
22110
22406
|
- Do not nitpick style, wording, or preferences unless the user's task demanded it.
|
|
22111
22407
|
- If the evidence is insufficient to judge, return status "ok" (prefer silence over noise).
|
|
22408
|
+
- A chat-delivered answer (ANSWER section) can fully satisfy the task without any files or commands; absence of changed files is NOT itself an issue when ANSWER contains the requested result.
|
|
22112
22409
|
- "critical" = the task's stated result is demonstrably not delivered. "concern" = a concrete, checkable gap. "info" = minor.
|
|
22113
22410
|
- Every issue must reference concrete evidence (file, command, output).
|
|
22114
22411
|
Reply with JSON ONLY:
|
|
@@ -22123,8 +22420,12 @@ var init_client = __esm(() => {
|
|
|
22123
22420
|
// src/modules/critic/provider.ts
|
|
22124
22421
|
function buildCriticProvider(critic, config, defaultProvider, deps) {
|
|
22125
22422
|
const model = critic?.model?.trim();
|
|
22126
|
-
if (!model)
|
|
22423
|
+
if (!model) {
|
|
22424
|
+
if (critic?.provider && Object.keys(critic.provider).length > 0) {
|
|
22425
|
+
deps?.logger?.warn("critic.provider is set without critic.model — provider ignored, using active provider");
|
|
22426
|
+
}
|
|
22127
22427
|
return defaultProvider;
|
|
22428
|
+
}
|
|
22128
22429
|
try {
|
|
22129
22430
|
const providerCfg = critic?.provider ?? {
|
|
22130
22431
|
type: "openai-compat",
|
|
@@ -22182,7 +22483,8 @@ function buildEvidencePack(input) {
|
|
|
22182
22483
|
commands,
|
|
22183
22484
|
toolDigest: digest.slice(-MAX_DIGEST_LINES).join(`
|
|
22184
22485
|
`),
|
|
22185
|
-
fileExcerpts: input.baseDir ? readExcerpts(input.baseDir, [...changedFiles]) : undefined
|
|
22486
|
+
fileExcerpts: input.baseDir ? readExcerpts(input.baseDir, [...changedFiles]) : undefined,
|
|
22487
|
+
answerExcerpt: input.answerText ? redactContextSecrets(input.answerText).slice(0, MAX_ANSWER_CHARS) : undefined
|
|
22186
22488
|
};
|
|
22187
22489
|
}
|
|
22188
22490
|
function digestLine(ev) {
|
|
@@ -22203,7 +22505,7 @@ function commandOf(ev) {
|
|
|
22203
22505
|
return;
|
|
22204
22506
|
return {
|
|
22205
22507
|
command: ev.args.command,
|
|
22206
|
-
exitCode: ev.ok === false ? 1 :
|
|
22508
|
+
exitCode: ev.ok === false ? 1 : undefined,
|
|
22207
22509
|
output: ev.output?.slice(-MAX_DIGEST_OUTPUT_CHARS)
|
|
22208
22510
|
};
|
|
22209
22511
|
}
|
|
@@ -22221,9 +22523,10 @@ function readExcerpts(baseDir, paths) {
|
|
|
22221
22523
|
}
|
|
22222
22524
|
return out;
|
|
22223
22525
|
}
|
|
22224
|
-
var MUTATING_TOOLS, MAX_DIGEST_LINES = 40, MAX_DIGEST_OUTPUT_CHARS = 300, MAX_EXCERPT_FILES = 5, MAX_EXCERPT_CHARS = 1200;
|
|
22526
|
+
var MUTATING_TOOLS, MAX_DIGEST_LINES = 40, MAX_DIGEST_OUTPUT_CHARS = 300, MAX_EXCERPT_FILES = 5, MAX_EXCERPT_CHARS = 1200, MAX_ANSWER_CHARS = 2000;
|
|
22225
22527
|
var init_evidence = __esm(() => {
|
|
22226
22528
|
init_tool_output();
|
|
22529
|
+
init_context_log();
|
|
22227
22530
|
MUTATING_TOOLS = new Set(["write_file", "edit_file", "delete_file", "move_file", "create_dir"]);
|
|
22228
22531
|
});
|
|
22229
22532
|
|
|
@@ -22918,6 +23221,7 @@ class Agent {
|
|
|
22918
23221
|
} = this.deps;
|
|
22919
23222
|
this.abortController = new AbortController;
|
|
22920
23223
|
const state = createLoopState();
|
|
23224
|
+
state.criticHistoryMark = contextManager.getActiveHistory().length;
|
|
22921
23225
|
const compactionService = new CompactionService({
|
|
22922
23226
|
contextManager,
|
|
22923
23227
|
logger: logger3,
|
|
@@ -22975,7 +23279,8 @@ class Agent {
|
|
|
22975
23279
|
task: d.task,
|
|
22976
23280
|
planSummary: d.planSummary,
|
|
22977
23281
|
toolEvents: d.toolEvents,
|
|
22978
|
-
baseDir: this.deps.baseDir
|
|
23282
|
+
baseDir: this.deps.baseDir,
|
|
23283
|
+
answerText: d.answerText
|
|
22979
23284
|
}),
|
|
22980
23285
|
signal: this.abortController?.signal
|
|
22981
23286
|
});
|
|
@@ -23256,7 +23561,8 @@ class Agent {
|
|
|
23256
23561
|
onMeta,
|
|
23257
23562
|
onChunk,
|
|
23258
23563
|
verbose: resolveVerbosity(this.deps.config.ui) === "verbose",
|
|
23259
|
-
artifacts: resolveArtifactStates(this.deps.baseDir, textContent)
|
|
23564
|
+
artifacts: resolveArtifactStates(this.deps.baseDir, textContent),
|
|
23565
|
+
slog
|
|
23260
23566
|
});
|
|
23261
23567
|
if (verdict.action === "block") {
|
|
23262
23568
|
return {
|
|
@@ -23309,8 +23615,10 @@ class Agent {
|
|
|
23309
23615
|
slog,
|
|
23310
23616
|
task: input,
|
|
23311
23617
|
planSummary: this.deps.planSummary?.() ?? undefined,
|
|
23312
|
-
toolEvents: gatherTurnToolEvents(contextManager),
|
|
23313
|
-
beforeFinish: true
|
|
23618
|
+
toolEvents: gatherTurnToolEvents(contextManager, state.criticHistoryMark),
|
|
23619
|
+
beforeFinish: true,
|
|
23620
|
+
answerText: state.mutationsSinceCritic === 0 ? textContent : undefined,
|
|
23621
|
+
onMeta
|
|
23314
23622
|
});
|
|
23315
23623
|
if (criticAction === "retry") {
|
|
23316
23624
|
state.suppressRepetitionRetry = true;
|
|
@@ -23322,7 +23630,8 @@ class Agent {
|
|
|
23322
23630
|
maxIterations: config.maxToolIterations,
|
|
23323
23631
|
logger: logger3,
|
|
23324
23632
|
contextManager,
|
|
23325
|
-
slog
|
|
23633
|
+
slog,
|
|
23634
|
+
onMeta
|
|
23326
23635
|
});
|
|
23327
23636
|
if (auditVerdict === null || auditVerdict.action === "pass") {
|
|
23328
23637
|
state.finalAnswerAccepted = true;
|
|
@@ -34932,6 +35241,40 @@ var init_box = __esm(() => {
|
|
|
34932
35241
|
});
|
|
34933
35242
|
|
|
34934
35243
|
// src/modules/setup/answers.ts
|
|
35244
|
+
function securityDetailFromConfig(s) {
|
|
35245
|
+
return {
|
|
35246
|
+
bash: {
|
|
35247
|
+
blacklist: [...s.bash.blacklist],
|
|
35248
|
+
whitelist: [...s.bash.whitelist],
|
|
35249
|
+
logCommands: s.bash.logCommands
|
|
35250
|
+
},
|
|
35251
|
+
paths: { denied: [...s.paths.denied], allowed: [...s.paths.allowed] },
|
|
35252
|
+
flags: {
|
|
35253
|
+
dangerousFlags: [...s.bash.dangerousFlags],
|
|
35254
|
+
dangerousOperators: [...s.bash.dangerousOperators]
|
|
35255
|
+
},
|
|
35256
|
+
network: {
|
|
35257
|
+
enabled: s.network.enabled,
|
|
35258
|
+
deniedDomains: [...s.network.deniedDomains],
|
|
35259
|
+
allowedDomains: [...s.network.allowedDomains],
|
|
35260
|
+
requestTimeout: s.network.requestTimeout,
|
|
35261
|
+
maxResponseSize: s.network.maxResponseSize
|
|
35262
|
+
},
|
|
35263
|
+
advanced: {
|
|
35264
|
+
maxRecursionDepth: s.maxRecursionDepth,
|
|
35265
|
+
maxFileOperations: s.maxFileOperations,
|
|
35266
|
+
maxRequestsPerMinute: s.rateLimits.maxRequestsPerMinute,
|
|
35267
|
+
maxParallelTasks: s.rateLimits.maxParallelTasks,
|
|
35268
|
+
contentScanEnabled: s.contentScan.enabled,
|
|
35269
|
+
sessionEncryptionEnabled: s.sessionEncryption.enabled,
|
|
35270
|
+
auditNotifierEnabled: s.auditNotifier.enabled,
|
|
35271
|
+
auditNotifierMinSeverity: s.auditNotifier.minSeverity ?? "medium",
|
|
35272
|
+
auditNotifierEventTypes: [...s.auditNotifier.eventTypes ?? []],
|
|
35273
|
+
auditNotifierMaxRetries: s.auditNotifier.maxRetries ?? 3,
|
|
35274
|
+
auditNotifierWebhookTimeout: s.auditNotifier.webhookTimeout ?? 5000
|
|
35275
|
+
}
|
|
35276
|
+
};
|
|
35277
|
+
}
|
|
34935
35278
|
function buildSetupDisplay() {
|
|
34936
35279
|
const providers = BUILTIN_PROVIDERS.map((spec) => {
|
|
34937
35280
|
const option = { type: spec.type, label: spec.label };
|
|
@@ -35321,20 +35664,62 @@ function applyAnswersToConfig(config, a) {
|
|
|
35321
35664
|
config.provider.entries = next;
|
|
35322
35665
|
config.provider.active = updated.label || updated.type;
|
|
35323
35666
|
}
|
|
35324
|
-
|
|
35325
|
-
config.security.enabled = true;
|
|
35326
|
-
config.security.bash.enabled = true;
|
|
35327
|
-
config.security.bash.blockDangerousFlags = a.securityFlagsBlock || config.security.bash.blockDangerousFlags;
|
|
35328
|
-
if (a.securityBashBlock) {
|
|
35329
|
-
config.security.bash.blacklist = [
|
|
35330
|
-
...new Set([...config.security.bash.blacklist, ...SECURITY_BASH_BLOCKLIST])
|
|
35331
|
-
];
|
|
35332
|
-
}
|
|
35333
|
-
config.security.paths.enabled = a.securityPathsRestrict;
|
|
35334
|
-
}
|
|
35667
|
+
applySecurityAnswers(config, a);
|
|
35335
35668
|
return config;
|
|
35336
35669
|
}
|
|
35337
|
-
|
|
35670
|
+
function applySecurityAnswers(config, a) {
|
|
35671
|
+
if (!config.security)
|
|
35672
|
+
return;
|
|
35673
|
+
config.security.enabled = true;
|
|
35674
|
+
config.security.bash.enabled = true;
|
|
35675
|
+
config.security.bash.blockDangerousFlags = a.securityFlagsBlock || config.security.bash.blockDangerousFlags;
|
|
35676
|
+
if (a.securityBashBlock) {
|
|
35677
|
+
config.security.bash.blacklist = [
|
|
35678
|
+
...new Set([...config.security.bash.blacklist, ...SECURITY_BASH_BLOCKLIST])
|
|
35679
|
+
];
|
|
35680
|
+
}
|
|
35681
|
+
config.security.paths.enabled = a.securityPathsRestrict;
|
|
35682
|
+
if (a.securityDetail)
|
|
35683
|
+
applySecurityDetail(config.security, a.securityDetail);
|
|
35684
|
+
}
|
|
35685
|
+
function readPath(obj, path) {
|
|
35686
|
+
let cur = obj;
|
|
35687
|
+
for (const key of path.split(".")) {
|
|
35688
|
+
if (cur === null || typeof cur !== "object")
|
|
35689
|
+
return;
|
|
35690
|
+
cur = cur[key];
|
|
35691
|
+
}
|
|
35692
|
+
return cur;
|
|
35693
|
+
}
|
|
35694
|
+
function writePath(obj, path, value) {
|
|
35695
|
+
const keys = path.split(".");
|
|
35696
|
+
let cur = obj;
|
|
35697
|
+
for (let i = 0;i < keys.length - 1; i++) {
|
|
35698
|
+
if (cur[keys[i]] === null || typeof cur[keys[i]] !== "object")
|
|
35699
|
+
cur[keys[i]] = {};
|
|
35700
|
+
cur = cur[keys[i]];
|
|
35701
|
+
}
|
|
35702
|
+
cur[keys[keys.length - 1]] = value;
|
|
35703
|
+
}
|
|
35704
|
+
function isFieldValue(v, kind) {
|
|
35705
|
+
if (kind === "list")
|
|
35706
|
+
return Array.isArray(v) && v.every((x) => typeof x === "string");
|
|
35707
|
+
if (kind === "bool")
|
|
35708
|
+
return typeof v === "boolean";
|
|
35709
|
+
if (kind === "int")
|
|
35710
|
+
return typeof v === "number" && Number.isInteger(v) && v > 0;
|
|
35711
|
+
return typeof v === "string" && SEVERITIES2.includes(v);
|
|
35712
|
+
}
|
|
35713
|
+
function applySecurityDetail(security, detail) {
|
|
35714
|
+
const target = security;
|
|
35715
|
+
for (const field of DETAIL_FIELDS) {
|
|
35716
|
+
const value = readPath(detail, field.from);
|
|
35717
|
+
if (!isFieldValue(value, field.kind))
|
|
35718
|
+
continue;
|
|
35719
|
+
writePath(target, field.to, Array.isArray(value) ? [...value] : value);
|
|
35720
|
+
}
|
|
35721
|
+
}
|
|
35722
|
+
var SECURITY_BASH_BLOCKLIST, SEVERITIES2, DETAIL_FIELDS;
|
|
35338
35723
|
var init_apply = __esm(() => {
|
|
35339
35724
|
SECURITY_BASH_BLOCKLIST = [
|
|
35340
35725
|
"rm",
|
|
@@ -35354,6 +35739,32 @@ var init_apply = __esm(() => {
|
|
|
35354
35739
|
"shutdown",
|
|
35355
35740
|
"reboot"
|
|
35356
35741
|
];
|
|
35742
|
+
SEVERITIES2 = ["low", "medium", "high", "critical"];
|
|
35743
|
+
DETAIL_FIELDS = [
|
|
35744
|
+
{ from: "bash.blacklist", to: "bash.blacklist", kind: "list" },
|
|
35745
|
+
{ from: "bash.whitelist", to: "bash.whitelist", kind: "list" },
|
|
35746
|
+
{ from: "bash.logCommands", to: "bash.logCommands", kind: "bool" },
|
|
35747
|
+
{ from: "paths.denied", to: "paths.denied", kind: "list" },
|
|
35748
|
+
{ from: "paths.allowed", to: "paths.allowed", kind: "list" },
|
|
35749
|
+
{ from: "flags.dangerousFlags", to: "bash.dangerousFlags", kind: "list" },
|
|
35750
|
+
{ from: "flags.dangerousOperators", to: "bash.dangerousOperators", kind: "list" },
|
|
35751
|
+
{ from: "network.enabled", to: "network.enabled", kind: "bool" },
|
|
35752
|
+
{ from: "network.deniedDomains", to: "network.deniedDomains", kind: "list" },
|
|
35753
|
+
{ from: "network.allowedDomains", to: "network.allowedDomains", kind: "list" },
|
|
35754
|
+
{ from: "network.requestTimeout", to: "network.requestTimeout", kind: "int" },
|
|
35755
|
+
{ from: "network.maxResponseSize", to: "network.maxResponseSize", kind: "int" },
|
|
35756
|
+
{ from: "advanced.maxRecursionDepth", to: "maxRecursionDepth", kind: "int" },
|
|
35757
|
+
{ from: "advanced.maxFileOperations", to: "maxFileOperations", kind: "int" },
|
|
35758
|
+
{ from: "advanced.maxRequestsPerMinute", to: "rateLimits.maxRequestsPerMinute", kind: "int" },
|
|
35759
|
+
{ from: "advanced.maxParallelTasks", to: "rateLimits.maxParallelTasks", kind: "int" },
|
|
35760
|
+
{ from: "advanced.contentScanEnabled", to: "contentScan.enabled", kind: "bool" },
|
|
35761
|
+
{ from: "advanced.sessionEncryptionEnabled", to: "sessionEncryption.enabled", kind: "bool" },
|
|
35762
|
+
{ from: "advanced.auditNotifierEnabled", to: "auditNotifier.enabled", kind: "bool" },
|
|
35763
|
+
{ from: "advanced.auditNotifierMinSeverity", to: "auditNotifier.minSeverity", kind: "severity" },
|
|
35764
|
+
{ from: "advanced.auditNotifierEventTypes", to: "auditNotifier.eventTypes", kind: "list" },
|
|
35765
|
+
{ from: "advanced.auditNotifierMaxRetries", to: "auditNotifier.maxRetries", kind: "int" },
|
|
35766
|
+
{ from: "advanced.auditNotifierWebhookTimeout", to: "auditNotifier.webhookTimeout", kind: "int" }
|
|
35767
|
+
];
|
|
35357
35768
|
});
|
|
35358
35769
|
|
|
35359
35770
|
// src/cli/setup-order.ts
|
|
@@ -51823,6 +52234,11 @@ function makeForwarder(s, sink = (ev) => broadcast(ev, s), opts = {}) {
|
|
|
51823
52234
|
schedule();
|
|
51824
52235
|
},
|
|
51825
52236
|
onMeta(chunk, kind) {
|
|
52237
|
+
if (kind === "retract") {
|
|
52238
|
+
flush();
|
|
52239
|
+
sink({ type: "retract", ts: Date.now(), reason: stripAnsi2(chunk) });
|
|
52240
|
+
return;
|
|
52241
|
+
}
|
|
51826
52242
|
const next = kind ?? "status";
|
|
51827
52243
|
if (buf.meta && (buf.metaKind ?? "status") !== next)
|
|
51828
52244
|
flush();
|
|
@@ -53633,9 +54049,11 @@ function servePreview(res, absReal, buf) {
|
|
|
53633
54049
|
|
|
53634
54050
|
// src/modules/webui/setup-api.ts
|
|
53635
54051
|
init_i18n();
|
|
54052
|
+
init_registry_extra();
|
|
53636
54053
|
init_apply();
|
|
53637
54054
|
init_answers();
|
|
53638
54055
|
init_discovery();
|
|
54056
|
+
init_provider_context();
|
|
53639
54057
|
function str3(rec, key) {
|
|
53640
54058
|
const v = rec[key];
|
|
53641
54059
|
return typeof v === "string" ? v.trim() : "";
|
|
@@ -53645,6 +54063,76 @@ function positiveInt(rec, key) {
|
|
|
53645
54063
|
const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
|
|
53646
54064
|
return Number.isInteger(n) && n > 0 ? n : null;
|
|
53647
54065
|
}
|
|
54066
|
+
var SEVERITIES3 = ["low", "medium", "high", "critical"];
|
|
54067
|
+
var MAX_DETAIL_LIST = 200;
|
|
54068
|
+
var MAX_DETAIL_ITEM = 200;
|
|
54069
|
+
function strList(v) {
|
|
54070
|
+
if (!Array.isArray(v))
|
|
54071
|
+
return;
|
|
54072
|
+
const out = v.filter((x) => typeof x === "string").map((x) => x.trim()).filter((x) => x !== "" && x.length <= MAX_DETAIL_ITEM).slice(0, MAX_DETAIL_LIST);
|
|
54073
|
+
return out;
|
|
54074
|
+
}
|
|
54075
|
+
function optBool(v) {
|
|
54076
|
+
return typeof v === "boolean" ? v : undefined;
|
|
54077
|
+
}
|
|
54078
|
+
function optInt(v) {
|
|
54079
|
+
const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
|
|
54080
|
+
return Number.isInteger(n) && n > 0 ? n : undefined;
|
|
54081
|
+
}
|
|
54082
|
+
function parseSecurityDetail(v) {
|
|
54083
|
+
if (!v || typeof v !== "object")
|
|
54084
|
+
return;
|
|
54085
|
+
const rec = v;
|
|
54086
|
+
const detail = {};
|
|
54087
|
+
const bash = rec.bash;
|
|
54088
|
+
if (bash && typeof bash === "object") {
|
|
54089
|
+
detail.bash = {
|
|
54090
|
+
blacklist: strList(bash.blacklist),
|
|
54091
|
+
whitelist: strList(bash.whitelist),
|
|
54092
|
+
logCommands: optBool(bash.logCommands)
|
|
54093
|
+
};
|
|
54094
|
+
}
|
|
54095
|
+
const paths = rec.paths;
|
|
54096
|
+
if (paths && typeof paths === "object") {
|
|
54097
|
+
detail.paths = { denied: strList(paths.denied), allowed: strList(paths.allowed) };
|
|
54098
|
+
}
|
|
54099
|
+
const flags = rec.flags;
|
|
54100
|
+
if (flags && typeof flags === "object") {
|
|
54101
|
+
detail.flags = {
|
|
54102
|
+
dangerousFlags: strList(flags.dangerousFlags),
|
|
54103
|
+
dangerousOperators: strList(flags.dangerousOperators)
|
|
54104
|
+
};
|
|
54105
|
+
}
|
|
54106
|
+
const network = rec.network;
|
|
54107
|
+
if (network && typeof network === "object") {
|
|
54108
|
+
detail.network = {
|
|
54109
|
+
enabled: optBool(network.enabled),
|
|
54110
|
+
deniedDomains: strList(network.deniedDomains),
|
|
54111
|
+
allowedDomains: strList(network.allowedDomains),
|
|
54112
|
+
requestTimeout: optInt(network.requestTimeout),
|
|
54113
|
+
maxResponseSize: optInt(network.maxResponseSize)
|
|
54114
|
+
};
|
|
54115
|
+
}
|
|
54116
|
+
const adv = rec.advanced;
|
|
54117
|
+
if (adv && typeof adv === "object") {
|
|
54118
|
+
const rawSev = adv.auditNotifierMinSeverity;
|
|
54119
|
+
const sev = typeof rawSev === "string" && SEVERITIES3.includes(rawSev) ? rawSev : undefined;
|
|
54120
|
+
detail.advanced = {
|
|
54121
|
+
maxRecursionDepth: optInt(adv.maxRecursionDepth),
|
|
54122
|
+
maxFileOperations: optInt(adv.maxFileOperations),
|
|
54123
|
+
maxRequestsPerMinute: optInt(adv.maxRequestsPerMinute),
|
|
54124
|
+
maxParallelTasks: optInt(adv.maxParallelTasks),
|
|
54125
|
+
contentScanEnabled: optBool(adv.contentScanEnabled),
|
|
54126
|
+
sessionEncryptionEnabled: optBool(adv.sessionEncryptionEnabled),
|
|
54127
|
+
auditNotifierEnabled: optBool(adv.auditNotifierEnabled),
|
|
54128
|
+
auditNotifierMinSeverity: sev,
|
|
54129
|
+
auditNotifierEventTypes: strList(adv.auditNotifierEventTypes)?.filter((e) => AUDIT_EVENT_TYPES.includes(e)),
|
|
54130
|
+
auditNotifierMaxRetries: optInt(adv.auditNotifierMaxRetries),
|
|
54131
|
+
auditNotifierWebhookTimeout: optInt(adv.auditNotifierWebhookTimeout)
|
|
54132
|
+
};
|
|
54133
|
+
}
|
|
54134
|
+
return detail;
|
|
54135
|
+
}
|
|
53648
54136
|
function parseSetupAnswers(rec) {
|
|
53649
54137
|
const provider = str3(rec, "provider");
|
|
53650
54138
|
const apiBase = str3(rec, "apiBase");
|
|
@@ -53674,15 +54162,17 @@ function parseSetupAnswers(rec) {
|
|
|
53674
54162
|
locale,
|
|
53675
54163
|
securityBashBlock: rec.securityBashBlock,
|
|
53676
54164
|
securityFlagsBlock: rec.securityFlagsBlock,
|
|
53677
|
-
securityPathsRestrict: rec.securityPathsRestrict
|
|
54165
|
+
securityPathsRestrict: rec.securityPathsRestrict,
|
|
54166
|
+
securityDetail: parseSecurityDetail(rec.securityDetail)
|
|
53678
54167
|
};
|
|
53679
54168
|
}
|
|
53680
54169
|
function handleSetupGet(res, s) {
|
|
54170
|
+
const defaults = s.setup?.defaults ?? { contextWindow: 0, maxToolIterations: 0 };
|
|
53681
54171
|
sendJson(res, 200, {
|
|
53682
54172
|
required: s.setupRequired,
|
|
53683
54173
|
languages: s.setup?.languages ?? [],
|
|
53684
54174
|
providers: s.setup?.providers ?? [],
|
|
53685
|
-
defaults: s.
|
|
54175
|
+
defaults: s.config?.security ? { ...defaults, security: securityDetailFromConfig(s.config.security) } : defaults
|
|
53686
54176
|
});
|
|
53687
54177
|
}
|
|
53688
54178
|
function handleSetupScan(req, res, s) {
|
|
@@ -53728,6 +54218,31 @@ function handleSetupTest(req, res, s) {
|
|
|
53728
54218
|
readBodyError(req, res, err);
|
|
53729
54219
|
});
|
|
53730
54220
|
}
|
|
54221
|
+
function handleSetupContext(req, res, s) {
|
|
54222
|
+
readJsonBody(req, s.maxBodyBytes).then(async (rec) => {
|
|
54223
|
+
if (!rec) {
|
|
54224
|
+
sendJson(res, 400, { ok: false, error: "invalid JSON" });
|
|
54225
|
+
return;
|
|
54226
|
+
}
|
|
54227
|
+
const baseUrl = str3(rec, "baseUrl");
|
|
54228
|
+
const model = str3(rec, "model");
|
|
54229
|
+
if (!baseUrl || !model) {
|
|
54230
|
+
sendJson(res, 400, { ok: false, error: "invalid-context-request" });
|
|
54231
|
+
return;
|
|
54232
|
+
}
|
|
54233
|
+
const probe = await probeProviderContext(baseUrl, model, {
|
|
54234
|
+
apiKey: str3(rec, "apiKey") || undefined,
|
|
54235
|
+
providerType: str3(rec, "providerType") || undefined
|
|
54236
|
+
});
|
|
54237
|
+
if (!probe) {
|
|
54238
|
+
sendJson(res, 200, { ok: false });
|
|
54239
|
+
return;
|
|
54240
|
+
}
|
|
54241
|
+
sendJson(res, 200, { ok: true, contextWindow: probe.actual, model: probe.model });
|
|
54242
|
+
}).catch((err) => {
|
|
54243
|
+
readBodyError(req, res, err);
|
|
54244
|
+
});
|
|
54245
|
+
}
|
|
53731
54246
|
function handleSetupLocale(req, res, s) {
|
|
53732
54247
|
readJsonBody(req, s.maxBodyBytes).then((rec) => {
|
|
53733
54248
|
if (!rec) {
|
|
@@ -53800,6 +54315,10 @@ function handleSetupApi(req, res, reqUrl, s) {
|
|
|
53800
54315
|
handleSetupTest(req, res, s);
|
|
53801
54316
|
return true;
|
|
53802
54317
|
}
|
|
54318
|
+
if (p === "/api/setup/context" && req.method === "POST") {
|
|
54319
|
+
handleSetupContext(req, res, s);
|
|
54320
|
+
return true;
|
|
54321
|
+
}
|
|
53803
54322
|
if (p === "/api/setup/locale" && req.method === "POST") {
|
|
53804
54323
|
handleSetupLocale(req, res, s);
|
|
53805
54324
|
return true;
|
|
@@ -53877,6 +54396,7 @@ var API_ROUTES = {
|
|
|
53877
54396
|
"GET /api/models": (_req, res, s) => handleModelsGet(res, s),
|
|
53878
54397
|
"POST /api/command": (req, res, s) => handleCommandPost(req, res, s),
|
|
53879
54398
|
"POST /api/interrupt": (_req, res, s) => handleInterruptPost(res, s),
|
|
54399
|
+
"POST /api/index": (_req, res, s) => handleIndexPost(res, s),
|
|
53880
54400
|
"POST /api/mcp": (req, res, s) => handleMcpCreate(req, res, s),
|
|
53881
54401
|
"GET /api/lsp": (_req, res, s) => handleLspGet(res, s)
|
|
53882
54402
|
};
|
|
@@ -53918,6 +54438,14 @@ function handleInterruptPost(res, s) {
|
|
|
53918
54438
|
s.bridge?.interrupt();
|
|
53919
54439
|
sendJson(res, 200, { ok: true });
|
|
53920
54440
|
}
|
|
54441
|
+
function handleIndexPost(res, s) {
|
|
54442
|
+
if (!s.refreshIndex) {
|
|
54443
|
+
sendJson(res, 503, { error: "unavailable" });
|
|
54444
|
+
return;
|
|
54445
|
+
}
|
|
54446
|
+
Promise.resolve(s.refreshIndex()).catch(() => {});
|
|
54447
|
+
sendJson(res, 202, { ok: true });
|
|
54448
|
+
}
|
|
53921
54449
|
function handleRequest(req, res, assets, s) {
|
|
53922
54450
|
let reqUrl;
|
|
53923
54451
|
try {
|
|
@@ -54178,8 +54706,16 @@ async function startWebUi(deps) {
|
|
|
54178
54706
|
state.plugins = deps.plugins;
|
|
54179
54707
|
state.workspace = deps.baseDir;
|
|
54180
54708
|
state.agentsMd = deps.agentsMd;
|
|
54181
|
-
if (deps.indexer)
|
|
54709
|
+
if (deps.indexer) {
|
|
54182
54710
|
state.projectMapStats = () => deps.indexer?.stats() ?? null;
|
|
54711
|
+
if (deps.indexer.refresh) {
|
|
54712
|
+
const refresh = deps.indexer.refresh.bind(deps.indexer);
|
|
54713
|
+
state.refreshIndex = async () => {
|
|
54714
|
+
await refresh();
|
|
54715
|
+
broadcast({ type: "state", ts: Date.now(), busy: state.busy, usage: state.usage }, state);
|
|
54716
|
+
};
|
|
54717
|
+
}
|
|
54718
|
+
}
|
|
54183
54719
|
state.saveConfig = (config) => saveConfig(config, CONFIG_FILE, deps.configDir);
|
|
54184
54720
|
installWebPromptIO({
|
|
54185
54721
|
state,
|
|
@@ -54223,10 +54759,7 @@ async function startWebUi(deps) {
|
|
|
54223
54759
|
contextProbe: probe,
|
|
54224
54760
|
workspace: deps.baseDir,
|
|
54225
54761
|
instructions: deps.agentsMd,
|
|
54226
|
-
projectMap: (
|
|
54227
|
-
const s = deps.indexer?.stats();
|
|
54228
|
-
return s ? { indexed: true, ...s } : { indexed: false, files: 0, symbols: 0, tokens: 0 };
|
|
54229
|
-
})()
|
|
54762
|
+
projectMap: deps.indexer?.mapInfo?.()
|
|
54230
54763
|
}, state.busy),
|
|
54231
54764
|
addPendingImage: (url2) => {
|
|
54232
54765
|
deps.agent.contextManager?.addPendingImage?.({
|