micro-models-agent 2.10.0 → 2.12.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 +33 -0
- package/dist/assets/app.js +22 -4
- package/dist/assets/index.html +29 -0
- package/dist/assets/js/dom.js +2 -1
- package/dist/assets/js/feed.js +38 -26
- package/dist/assets/js/format.js +1 -1
- package/dist/assets/js/rail.js +114 -0
- package/dist/assets/js/settings-controls.js +2 -2
- package/dist/assets/js/settings.js +246 -51
- package/dist/assets/js/store.js +3 -0
- package/dist/assets/js/tabs.js +104 -2
- package/dist/assets/styles.css +215 -66
- package/dist/cli/cache-line.js +1 -0
- package/dist/cli/command-suggest.js +5 -4
- package/dist/cli/commands.js +231 -122
- package/dist/cli/completer.js +132 -31
- package/dist/cli/index.js +1 -0
- package/dist/cli/json-payload.js +4 -4
- package/dist/cli/main.js +166 -61
- package/dist/cli/onboarding-commands.js +126 -0
- package/dist/cli/plugin-commands.js +2 -1
- package/dist/cli/relaunch.js +16 -13
- package/dist/cli/repl-commands-lsp.js +75 -0
- package/dist/cli/repl-commands-skills.js +105 -0
- package/dist/cli/repl-commands.js +589 -266
- package/dist/cli/repl.js +436 -177
- package/dist/cli/run-result.js +5 -6
- package/dist/cli/security-commands.js +37 -28
- package/dist/cli/setup-order.js +4 -55
- package/dist/cli/setup-prompt.js +3 -2
- package/dist/cli/setup.js +27 -107
- package/dist/cli/web-command.js +98 -0
- package/dist/config/budget.js +5 -5
- package/dist/config/config.js +103 -96
- package/dist/config/defaults.js +38 -8
- package/dist/config/domains.js +24 -27
- package/dist/config/env.js +46 -0
- package/dist/config/experts.js +2 -0
- package/dist/config/index.js +1 -0
- package/dist/config/paths.js +56 -0
- package/dist/config/redact.js +44 -0
- package/dist/config/registry-extra.js +334 -0
- package/dist/config/registry.js +584 -0
- package/dist/config/security.js +35 -36
- package/dist/config/timeouts.js +74 -0
- package/dist/config/utils.js +16 -15
- package/dist/core/agent/artifact-progress.js +59 -0
- package/dist/core/agent/artifact-resolve.js +79 -0
- package/dist/core/agent/audit-gate.js +7 -3
- package/dist/core/agent/compaction.js +2 -2
- package/dist/core/agent/constants.js +33 -4
- package/dist/core/agent/context-log.js +454 -0
- package/dist/core/agent/context-renderer.js +5 -0
- package/dist/core/agent/critic-gate.js +132 -0
- package/dist/core/agent/hallucination-gate.js +148 -38
- package/dist/core/agent/loop-state.js +15 -0
- package/dist/core/agent/prefix-monitor.js +1 -1
- package/dist/core/agent/reasoning-resolver.js +10 -1
- package/dist/core/agent/token-tracker.js +7 -4
- package/dist/core/agent/tool-batch.js +93 -18
- package/dist/core/agent/tool-images.js +18 -0
- package/dist/core/agent/tool-output.js +65 -11
- package/dist/core/agent/tool-pairing.js +60 -0
- package/dist/core/agent-moe.js +25 -24
- package/dist/core/agent.js +429 -108
- package/dist/core/bootstrap/agent-phase.js +66 -0
- package/dist/core/bootstrap/config-phase.js +86 -0
- package/dist/core/bootstrap/modules-phase.js +269 -0
- package/dist/core/bootstrap/provider-phase.js +183 -0
- package/dist/core/bootstrap/session-phase.js +204 -0
- package/dist/core/bootstrap/state.js +94 -0
- package/dist/core/bootstrap/workspace-phase.js +115 -0
- package/dist/core/bootstrap.js +92 -660
- package/dist/core/crash-handler.js +17 -7
- package/dist/core/environment.js +37 -12
- package/dist/core/host-plan.js +43 -0
- package/dist/core/host.js +23 -0
- package/dist/core/index.js +1 -0
- package/dist/core/prompt-builder.js +17 -1
- package/dist/core/prompt-overflow.js +42 -43
- package/dist/core/session-logger.js +122 -30
- package/dist/core/system-prompt.js +117 -0
- package/dist/core/version.js +6 -4
- package/dist/core/web-host.js +34 -0
- package/dist/core/workspace.js +19 -15
- package/dist/i18n/en.json +106 -21
- package/dist/i18n/index.js +37 -3
- package/dist/i18n/ru.json +109 -21
- package/dist/index.js +7 -3
- package/dist/llm/image-utils.js +55 -64
- package/dist/llm/llm-errors.js +9 -0
- package/dist/llm/model-loader.js +10 -32
- package/dist/llm/models-dev.js +121 -0
- package/dist/llm/openai-compat.js +146 -73
- package/dist/llm/orchestrator.js +33 -11
- package/dist/llm/provider-budget.js +2 -2
- package/dist/llm/provider-context.js +233 -0
- package/dist/llm/provider.js +1 -1
- package/dist/llm/response.js +5 -0
- package/dist/llm/token-counter.js +27 -11
- package/dist/logger/app-logger.js +48 -22
- package/dist/logger/file-log.js +28 -19
- package/dist/logger/index.js +1 -0
- package/dist/main.js +24285 -22447
- package/dist/migration/backup.js +14 -3
- package/dist/migration/detect.js +12 -3
- package/dist/migration/index.js +1 -0
- package/dist/modules/artifacts/store.js +9 -8
- package/dist/modules/browser/actions.js +6 -0
- package/dist/modules/browser/bridge-client.js +14 -12
- package/dist/modules/browser/bridge-path.js +4 -4
- package/dist/modules/browser/console-buffer.js +37 -0
- package/dist/modules/browser/cookie-store.js +5 -0
- package/dist/modules/browser/driver-types.js +1 -0
- package/dist/modules/browser/driver.js +19 -11
- package/dist/modules/browser/index.js +3 -1
- package/dist/modules/browser/module.js +2 -1
- package/dist/modules/browser/session.js +10 -30
- package/dist/modules/browser/snapshot.js +19 -13
- package/dist/modules/browser/types.js +1 -0
- package/dist/modules/certification/cli.js +28 -20
- package/dist/modules/certification/fact-checker.js +9 -1
- package/dist/modules/certification/loader.js +9 -2
- package/dist/modules/certification/manifest.js +83 -21
- package/dist/modules/certification/runner.js +23 -13
- package/dist/modules/certification/scenarios.js +20 -20
- package/dist/modules/certification/syntax-scenarios.js +1 -2
- package/dist/modules/context/chunk-query.js +11 -9
- package/dist/modules/context/fact-extractor.js +37 -39
- package/dist/modules/context/index.js +1 -0
- package/dist/modules/context/manager.js +106 -80
- package/dist/modules/critic/client.js +176 -0
- package/dist/modules/critic/evidence.js +81 -0
- package/dist/modules/critic/provider.js +45 -0
- package/dist/modules/critic/tools.js +78 -0
- package/dist/modules/critic/types.js +1 -0
- package/dist/modules/execution/audit-runners.js +28 -34
- package/dist/modules/execution/auditor.js +53 -49
- package/dist/modules/execution/execution-plugin.js +142 -102
- package/dist/modules/execution/index.js +1 -1
- package/dist/modules/execution/input-from.js +37 -13
- package/dist/modules/execution/module.js +368 -191
- package/dist/modules/execution/moe-executor.js +53 -26
- package/dist/modules/execution/plan-actions.js +320 -202
- package/dist/modules/execution/plan-checks.js +35 -0
- package/dist/modules/execution/plan-coverage.js +36 -33
- package/dist/modules/execution/plan-steps.js +11 -3
- package/dist/modules/execution/plan-store.js +83 -17
- package/dist/modules/execution/plan-tool.js +89 -35
- package/dist/modules/execution/plan-validator.js +30 -10
- package/dist/modules/execution/planner.js +22 -13
- package/dist/modules/execution/stuck-detector.js +196 -93
- package/dist/modules/execution/tracker.js +22 -8
- package/dist/modules/execution/verifier.js +69 -48
- package/dist/modules/execution/windows-commands.js +12 -12
- package/dist/modules/hallucination/artifact-claim.js +93 -0
- package/dist/modules/hallucination/confidence.js +13 -11
- package/dist/modules/hallucination/consistency.js +10 -2
- package/dist/modules/hallucination/detector.js +10 -5
- package/dist/modules/hallucination/factual.js +43 -26
- package/dist/modules/hallucination/index.js +1 -0
- package/dist/modules/hallucination/js-identifiers.js +44 -45
- package/dist/modules/hallucination/llm-judge.js +17 -12
- package/dist/modules/hallucination/success-claim.js +59 -0
- package/dist/modules/indexer/cache.js +52 -4
- package/dist/modules/indexer/index.js +1 -0
- package/dist/modules/indexer/map-command.js +2 -4
- package/dist/modules/indexer/map-select.js +16 -16
- package/dist/modules/indexer/module.js +47 -12
- package/dist/modules/indexer/project-profile.js +8 -7
- package/dist/modules/indexer/symbols.js +15 -15
- package/dist/modules/indexer/walker.js +159 -29
- package/dist/modules/lsp/check-tool.js +7 -5
- package/dist/modules/lsp/client.js +39 -39
- package/dist/modules/lsp/command.js +17 -24
- package/dist/modules/lsp/config.js +12 -11
- package/dist/modules/lsp/index.js +1 -0
- package/dist/modules/lsp/module.js +48 -46
- package/dist/modules/lsp/probe.js +13 -14
- package/dist/modules/lsp/project-root.js +14 -17
- package/dist/modules/lsp/startup-check.js +18 -16
- package/dist/modules/mcp/client.js +59 -62
- package/dist/modules/mcp/index.js +1 -0
- package/dist/modules/mcp/module.js +66 -37
- package/dist/modules/mcp/registry.js +5 -0
- package/dist/modules/memory/index.js +1 -0
- package/dist/modules/memory/module.js +12 -8
- package/dist/modules/memory/search.js +4 -1
- package/dist/modules/memory/store.js +40 -2
- package/dist/modules/onboarding/init.js +47 -0
- package/dist/modules/onboarding/meet.js +30 -0
- package/dist/modules/onboarding/mode.js +30 -0
- package/dist/modules/onboarding/prompts.js +43 -0
- package/dist/modules/pipelines/engine.js +10 -0
- package/dist/modules/pipelines/index.js +1 -0
- package/dist/modules/pipelines/parser.js +4 -1
- package/dist/modules/pipelines/template.js +4 -0
- package/dist/modules/plugins/builtin/lint-on-write.js +80 -67
- package/dist/modules/plugins/builtin/notify.js +2 -0
- package/dist/modules/plugins/index.js +1 -0
- package/dist/modules/plugins/loader.js +18 -3
- package/dist/modules/plugins/manager.js +37 -17
- package/dist/modules/pricing/index.js +10 -11
- package/dist/modules/pricing/prices.js +12 -12
- package/dist/modules/processes/index.js +1 -0
- package/dist/modules/processes/kill-tree.js +27 -31
- package/dist/modules/processes/registry.js +44 -25
- package/dist/modules/processes/runner.js +4 -4
- package/dist/modules/providers/capabilities.js +28 -0
- package/dist/modules/providers/create.js +3 -4
- package/dist/modules/providers/factory.js +7 -7
- package/dist/modules/providers/fallback.js +12 -12
- package/dist/modules/providers/health.js +4 -4
- package/dist/modules/providers/manager.js +50 -19
- package/dist/modules/providers/naming.js +15 -0
- package/dist/modules/providers/preflight.js +71 -0
- package/dist/modules/providers/presets.js +39 -8
- package/dist/modules/providers/registry.js +7 -2
- package/dist/modules/reasoning/policy.js +8 -6
- package/dist/modules/reasoning/probe.js +30 -25
- package/dist/modules/security/audit-log.js +19 -36
- package/dist/modules/security/audit-notifier.js +35 -75
- package/dist/modules/security/command-validator.js +99 -51
- package/dist/modules/security/content-scanner.js +8 -8
- package/dist/modules/security/data-sanitizer.js +9 -16
- package/dist/modules/security/encryption.js +32 -52
- package/dist/modules/security/index.js +2 -1
- package/dist/modules/security/network-validator.js +120 -43
- package/dist/modules/security/path-validator.js +61 -46
- package/dist/modules/security/protected-paths.js +73 -0
- package/dist/modules/security/rate-limiter.js +17 -49
- package/dist/modules/security/security-policies.js +25 -57
- package/dist/modules/security/session-encryption.js +32 -71
- package/dist/modules/security/session-isolation.js +15 -28
- package/dist/modules/session/auto-name.js +63 -0
- package/dist/modules/session/export.js +98 -0
- package/dist/modules/session/index.js +1 -0
- package/dist/modules/session/manager.js +79 -28
- package/dist/modules/session/module.js +4 -3
- package/dist/modules/session/store.js +57 -20
- package/dist/modules/setup/answers.js +35 -0
- package/dist/modules/setup/apply.js +79 -0
- package/dist/modules/setup/discovery.js +72 -0
- package/dist/modules/skills/index.js +1 -0
- package/dist/modules/skills/loader.js +9 -1
- package/dist/modules/skills/module.js +11 -0
- package/dist/modules/updater/changelog-reader.js +15 -16
- package/dist/modules/updater/checker.js +9 -4
- package/dist/modules/updater/dev-detect.js +7 -6
- package/dist/modules/updater/index.js +1 -0
- package/dist/modules/updater/module.js +17 -15
- package/dist/modules/user-profile/compressor.js +2 -0
- package/dist/modules/user-profile/index.js +1 -0
- package/dist/modules/user-profile/profile.js +10 -1
- package/dist/modules/webui/answer-api.js +29 -0
- package/dist/modules/webui/assets.js +50 -0
- package/dist/modules/webui/body.js +21 -0
- package/dist/modules/webui/commands-settings.js +209 -0
- package/dist/modules/webui/commands-shared.js +60 -0
- package/dist/modules/webui/commands.js +174 -0
- package/dist/modules/webui/config-api.js +134 -0
- package/dist/modules/webui/file-api.js +202 -0
- package/dist/modules/webui/forward.js +159 -0
- package/dist/modules/webui/history-api.js +112 -0
- package/dist/modules/webui/host-state.js +60 -0
- package/dist/modules/webui/i18n-api.js +9 -0
- package/dist/modules/webui/limits.js +6 -0
- package/dist/modules/webui/log-forward.js +20 -0
- package/dist/modules/webui/memory-commands.js +64 -0
- package/dist/modules/webui/model-cache.js +18 -0
- package/dist/modules/webui/module.js +148 -0
- package/dist/modules/webui/persist.js +24 -0
- package/dist/modules/webui/prompt-io.js +97 -0
- package/dist/modules/webui/providers-api.js +337 -0
- package/dist/modules/webui/providers-view.js +56 -0
- package/dist/modules/webui/reasoning-view.js +15 -0
- package/dist/modules/webui/run-agent.js +81 -0
- package/dist/modules/webui/server.js +284 -0
- package/dist/modules/webui/sessions-api.js +178 -0
- package/dist/modules/webui/settings-api.js +561 -0
- package/dist/modules/webui/setup-api.js +201 -0
- package/dist/modules/webui/state.js +74 -0
- package/dist/modules/webui/util.js +261 -0
- package/dist/output/bus.js +7 -2
- package/dist/output/channel.js +80 -28
- package/dist/output/format.js +2 -1
- package/dist/output/index.js +1 -0
- package/dist/output/json-sink.js +5 -3
- package/dist/output/machine.js +4 -3
- package/dist/output/session-sink.js +4 -4
- package/dist/tools/approve.js +4 -0
- package/dist/tools/attach-image.js +5 -4
- package/dist/tools/auto-fixer.js +26 -44
- package/dist/tools/auto-tags.js +83 -0
- package/dist/tools/bash.js +193 -116
- package/dist/tools/browser.js +76 -31
- package/dist/tools/chunk-query.js +14 -6
- package/dist/tools/create-dir.js +9 -5
- package/dist/tools/delete-file.js +9 -5
- package/dist/tools/download-file.js +32 -7
- package/dist/tools/edit-file.js +52 -14
- package/dist/tools/enable-tools.js +6 -6
- package/dist/tools/executor.js +132 -27
- package/dist/tools/file-info.js +3 -1
- package/dist/tools/filter-tools.js +3 -3
- package/dist/tools/glob-tool.js +4 -1
- package/dist/tools/grep-tool.js +13 -10
- package/dist/tools/hidden-tools-block.js +6 -6
- package/dist/tools/index.js +16 -8
- package/dist/tools/list-dir.js +4 -2
- package/dist/tools/load-skill.js +7 -0
- package/dist/tools/mcp-call.js +15 -4
- package/dist/tools/meet-done.js +14 -0
- package/dist/tools/move-file.js +14 -7
- package/dist/tools/path-utils.js +29 -29
- package/dist/tools/pipeline-run.js +29 -7
- package/dist/tools/preview.js +1 -1
- package/dist/tools/process-ids.js +31 -0
- package/dist/tools/process-kill.js +9 -16
- package/dist/tools/process-list.js +1 -0
- package/dist/tools/process-log.js +11 -16
- package/dist/tools/process-wait.js +63 -0
- package/dist/tools/prompt-io.js +4 -3
- package/dist/tools/question.js +172 -25
- package/dist/tools/read-file.js +55 -34
- package/dist/tools/recall.js +14 -8
- package/dist/tools/registry.js +6 -5
- package/dist/tools/remember.js +8 -4
- package/dist/tools/scope-request.js +11 -6
- package/dist/tools/search-history.js +5 -2
- package/dist/tools/session-info.js +2 -0
- package/dist/tools/set-thinking.js +8 -4
- package/dist/tools/subagent.js +59 -39
- package/dist/tools/syntax-validator.js +292 -90
- package/dist/tools/user-input.js +22 -18
- package/dist/tools/web-browse.js +9 -3
- package/dist/tools/web-fetch.js +12 -23
- package/dist/tools/web-search.js +7 -5
- package/dist/tools/write-file.js +45 -15
- package/dist/ui/action-log.js +13 -0
- package/dist/ui/box.js +4 -3
- package/dist/ui/colors.js +2 -0
- package/dist/ui/diff.js +6 -5
- package/dist/ui/index.js +1 -0
- package/dist/ui/line-editor.js +230 -122
- package/dist/ui/line-math.js +10 -2
- package/dist/ui/md-formatter.js +57 -37
- package/dist/ui/output.js +8 -3
- package/dist/ui/plan-view.js +21 -10
- package/dist/ui/renderer.js +393 -67
- package/dist/ui/spinner.js +16 -5
- package/dist/ui/table.js +15 -17
- package/dist/ui/theme.js +143 -0
- package/dist/utils/child-run.js +20 -0
- package/dist/utils/error.js +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/retry.js +2 -2
- package/dist/utils/truncate.js +1 -1
- package/package.json +1 -1
package/dist/output/channel.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
// Канал вывода: единственный владелец терминала (режимы idle/stream/modal/quiet).
|
|
1
2
|
import { defaultOutputBus } from "./bus";
|
|
2
3
|
import { formatEventLine } from "./format";
|
|
4
|
+
/** Единственный писатель в терминал; подписывается на шину и рендерит события. */
|
|
3
5
|
export class OutputChannel {
|
|
4
6
|
bus;
|
|
5
7
|
out;
|
|
@@ -14,14 +16,26 @@ export class OutputChannel {
|
|
|
14
16
|
pending = null;
|
|
15
17
|
partialOpen = false;
|
|
16
18
|
/**
|
|
17
|
-
* Log/block stdout
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* Log/block-события stdout, пойманные при активном промпте. Сбрасываются раз
|
|
20
|
+
* в микротаску, чтобы синхронный всплеск (например, 20-строчный результат
|
|
21
|
+
* команды) дал один `printAbove` + один ререндер кадра, а не по одному на
|
|
22
|
+
* строку (каждый стирал/перерисовывал кадр и слал DSR-запрос).
|
|
21
23
|
*/
|
|
22
24
|
blockLines = null;
|
|
23
25
|
blockFlushScheduled = false;
|
|
24
26
|
unsub;
|
|
27
|
+
/**
|
|
28
|
+
* Глушит `info`-логи на человеческом терминале. Структурные логи — это
|
|
29
|
+
* диагностика, а не чат: quiet оставляет только warn/error. `writeLine`-блоки
|
|
30
|
+
* (help, status, вывод команд) не затрагиваются.
|
|
31
|
+
*/
|
|
32
|
+
suppressInfoLogs = false;
|
|
33
|
+
/**
|
|
34
|
+
* Показ `data.diagnostic`-событий (внутренняя диагностика петли) в терминале.
|
|
35
|
+
* По умолчанию выкл: диагностика живёт в `.log`/`app.jsonl` и выходит в чат
|
|
36
|
+
* только при `ui.verbosity === "verbose"`.
|
|
37
|
+
*/
|
|
38
|
+
showDiagnostics = false;
|
|
25
39
|
constructor(bus = defaultOutputBus, opts = {}) {
|
|
26
40
|
this.bus = bus;
|
|
27
41
|
this.out = opts.out ?? process.stdout;
|
|
@@ -30,6 +44,7 @@ export class OutputChannel {
|
|
|
30
44
|
this.color = opts.color ?? (!process.env.NO_COLOR && !process.env.CI && outTTY);
|
|
31
45
|
this.unsub = this.bus.subscribe((ev) => this.onEvent(ev));
|
|
32
46
|
}
|
|
47
|
+
/** Отписка от шины и сброс состояния. */
|
|
33
48
|
dispose() {
|
|
34
49
|
this.flushBlocks();
|
|
35
50
|
this.unsub();
|
|
@@ -39,40 +54,46 @@ export class OutputChannel {
|
|
|
39
54
|
this.sink = null;
|
|
40
55
|
this.mode = "idle";
|
|
41
56
|
}
|
|
57
|
+
/** Привязка/отвязка промпта (null — терминал свободен). */
|
|
42
58
|
attachPrompt(sink) {
|
|
43
59
|
this.sink = sink;
|
|
44
60
|
}
|
|
61
|
+
/** Текущий режим канала. */
|
|
45
62
|
getMode() {
|
|
46
63
|
return this.mode;
|
|
47
64
|
}
|
|
65
|
+
/** Начало стрима ответа. Quiet не сбрасывается: `--json` молчит весь прогон. */
|
|
48
66
|
beginStreaming() {
|
|
49
|
-
//
|
|
50
|
-
//
|
|
67
|
+
// Переход в стрим не должен сбрасывать quiet: `--json` ставит quiet на весь
|
|
68
|
+
// прогон, и стримящиеся прогоны обязаны молчать.
|
|
51
69
|
if (this.mode === "quiet")
|
|
52
70
|
return;
|
|
53
71
|
this.flushBlocks();
|
|
54
72
|
this.flushPendingAsBlock();
|
|
55
73
|
this.mode = "streaming";
|
|
56
74
|
}
|
|
75
|
+
/** Конец стрима. Симметрично beginStreaming: quiet владеет режимом до setQuiet(false). */
|
|
57
76
|
endStreaming() {
|
|
58
|
-
//
|
|
77
|
+
// Симметрично beginStreaming: quiet владеет режимом до setQuiet(false).
|
|
59
78
|
if (this.mode === "quiet")
|
|
60
79
|
return;
|
|
61
80
|
this.closePartial();
|
|
62
81
|
this.mode = "idle";
|
|
63
82
|
}
|
|
83
|
+
/** Вход в модалку: события копятся в очередь до endModal. */
|
|
64
84
|
beginModal() {
|
|
65
85
|
this.flushBlocks();
|
|
66
86
|
this.flushPendingAsBlock();
|
|
67
87
|
if (this.mode === "quiet")
|
|
68
|
-
return; //
|
|
69
|
-
//
|
|
70
|
-
//
|
|
88
|
+
return; // quiet владеет setQuiet
|
|
89
|
+
// Вложенные модалки (визард внутри другой эксклюзивной области) не должны
|
|
90
|
+
// затирать режим, сохранённый самой внешней beginModal.
|
|
71
91
|
if (this.modalDepth === 0)
|
|
72
92
|
this.modeBeforeModal = this.mode;
|
|
73
93
|
this.modalDepth++;
|
|
74
94
|
this.mode = "modal";
|
|
75
95
|
}
|
|
96
|
+
/** Выход из модалки: сброс очереди накопленных событий в onEvent. */
|
|
76
97
|
endModal() {
|
|
77
98
|
if (this.modalDepth > 0)
|
|
78
99
|
this.modalDepth--;
|
|
@@ -83,6 +104,7 @@ export class OutputChannel {
|
|
|
83
104
|
for (const ev of q)
|
|
84
105
|
this.onEvent(ev);
|
|
85
106
|
}
|
|
107
|
+
/** Вкл/выкл quiet (`--json`): человеческий вывод дропается. */
|
|
86
108
|
setQuiet(quiet) {
|
|
87
109
|
this.flushBlocks();
|
|
88
110
|
if (quiet) {
|
|
@@ -95,10 +117,19 @@ export class OutputChannel {
|
|
|
95
117
|
this.mode = this.modeBeforeQuiet;
|
|
96
118
|
}
|
|
97
119
|
}
|
|
120
|
+
/** Скрыть `info`-логи терминала (warn/error остаются). */
|
|
121
|
+
setSuppressInfoLogs(suppress) {
|
|
122
|
+
this.suppressInfoLogs = suppress;
|
|
123
|
+
}
|
|
124
|
+
/** Показать внутреннюю диагностику (`Logger.diagnostic`) — только verbose. */
|
|
125
|
+
setShowDiagnostics(show) {
|
|
126
|
+
this.showDiagnostics = show;
|
|
127
|
+
}
|
|
128
|
+
/** Сырая запись в поток. В modal/quiet дропается, в idle идёт поверх промпта. */
|
|
98
129
|
writeRaw(text, stream = "stdout") {
|
|
99
|
-
//
|
|
130
|
+
// Сырой вывод не должен обгонять очередь блочных строк.
|
|
100
131
|
this.flushBlocks();
|
|
101
|
-
// modal
|
|
132
|
+
// modal осознанно дропает прямые записи: рендерер в модальном промпте не работает.
|
|
102
133
|
if (this.mode === "modal" || this.mode === "quiet")
|
|
103
134
|
return;
|
|
104
135
|
if (this.mode === "idle" && this.sink?.isActive() && stream === "stdout") {
|
|
@@ -111,12 +142,14 @@ export class OutputChannel {
|
|
|
111
142
|
this.partialOpen = !text.endsWith("\n");
|
|
112
143
|
(stream === "stderr" ? this.err : this.out).write(text);
|
|
113
144
|
}
|
|
145
|
+
/** Блочная запись через шину (help, status, вывод команд). */
|
|
114
146
|
writeLine(text, stream = "stdout") {
|
|
115
147
|
this.bus.emit({ level: "info", source: "", kind: "block", text, stream });
|
|
116
148
|
}
|
|
149
|
+
/** Очистка экрана через промпт или ANSI. Буферный raw-партиал сбрасывается первым. */
|
|
117
150
|
clearScreen() {
|
|
118
151
|
this.flushBlocks();
|
|
119
|
-
//
|
|
152
|
+
// Иначе буферная raw-частичная строка всплывёт после очистки.
|
|
120
153
|
this.flushPendingAsBlock();
|
|
121
154
|
this.partialOpen = false;
|
|
122
155
|
if (this.mode === "quiet")
|
|
@@ -127,17 +160,43 @@ export class OutputChannel {
|
|
|
127
160
|
}
|
|
128
161
|
this.out.write("\x1b[2J\x1b[H");
|
|
129
162
|
}
|
|
163
|
+
/** Оверлей (спиннер) в stderr. В modal/quiet и при активном промпте дропается. */
|
|
130
164
|
writeOverlay(text) {
|
|
131
|
-
// modal
|
|
132
|
-
//
|
|
165
|
+
// modal осознанно дропает оверлеи: рендерер в модальном промпте не работает.
|
|
166
|
+
// Спиннер обязан остановиться до любого лога, иначе оверлей делит строку с логом.
|
|
133
167
|
if (this.mode === "modal" || this.mode === "quiet")
|
|
134
168
|
return;
|
|
135
169
|
if (this.mode === "idle" && this.sink?.isActive())
|
|
136
170
|
return;
|
|
137
171
|
this.err.write(text);
|
|
138
172
|
}
|
|
139
|
-
|
|
173
|
+
/** Режимы и фильтры, держащие событие вне терминала. */
|
|
174
|
+
shouldDrop(ev) {
|
|
140
175
|
if (this.mode === "quiet")
|
|
176
|
+
return true;
|
|
177
|
+
// Структурные info-логи — диагностика, а не чат: quiet их прячет.
|
|
178
|
+
if (this.suppressInfoLogs && ev.kind === "log" && ev.level === "info")
|
|
179
|
+
return true;
|
|
180
|
+
// Внутренняя диагностика петли — материал логов сессии, а не чата: в терминал
|
|
181
|
+
// только через verbose (setShowDiagnostics).
|
|
182
|
+
if (!this.showDiagnostics && ev.kind === "log" && ev.data?.diagnostic === true)
|
|
183
|
+
return true;
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
/** Пакует синхронный всплеск в один printAbove/рендер (см. blockLines). */
|
|
187
|
+
queueBlockLine(line) {
|
|
188
|
+
// Оба потока идут поверх промпта, иначе stderr-лог ляжет прямо на кадр
|
|
189
|
+
// ввода в обход порядка flushBlocks.
|
|
190
|
+
if (this.blockLines === null)
|
|
191
|
+
this.blockLines = [];
|
|
192
|
+
this.blockLines.push(line);
|
|
193
|
+
if (this.blockFlushScheduled)
|
|
194
|
+
return;
|
|
195
|
+
this.blockFlushScheduled = true;
|
|
196
|
+
queueMicrotask(() => this.flushBlocks());
|
|
197
|
+
}
|
|
198
|
+
onEvent(ev) {
|
|
199
|
+
if (this.shouldDrop(ev))
|
|
141
200
|
return;
|
|
142
201
|
if (this.mode === "modal") {
|
|
143
202
|
this.queue.push(ev);
|
|
@@ -150,20 +209,11 @@ export class OutputChannel {
|
|
|
150
209
|
const stream = ev.stream ?? "stdout";
|
|
151
210
|
const line = ev.kind === "block" ? ev.text : formatEventLine(ev, this.color);
|
|
152
211
|
if (this.mode === "idle" && this.sink?.isActive()) {
|
|
153
|
-
|
|
154
|
-
// Both streams route above the prompt, otherwise a stderr log writes
|
|
155
|
-
// directly over the active input frame and skips flushBlocks ordering.
|
|
156
|
-
if (this.blockLines === null)
|
|
157
|
-
this.blockLines = [];
|
|
158
|
-
this.blockLines.push(line);
|
|
159
|
-
if (!this.blockFlushScheduled) {
|
|
160
|
-
this.blockFlushScheduled = true;
|
|
161
|
-
queueMicrotask(() => this.flushBlocks());
|
|
162
|
-
}
|
|
212
|
+
this.queueBlockLine(line);
|
|
163
213
|
return;
|
|
164
214
|
}
|
|
165
|
-
//
|
|
166
|
-
//
|
|
215
|
+
// Сохраняем FIFO: буферные блоки не должен обгонять эвент, писанный
|
|
216
|
+
// напрямую в raw-поток (например, stderr-лог посреди стрима).
|
|
167
217
|
this.flushBlocks();
|
|
168
218
|
if (this.mode === "streaming")
|
|
169
219
|
this.closePartial();
|
|
@@ -222,11 +272,13 @@ export class OutputChannel {
|
|
|
222
272
|
}
|
|
223
273
|
}
|
|
224
274
|
let defaultChannel = null;
|
|
275
|
+
/** Канал-синглтон текущего процесса. */
|
|
225
276
|
export function getDefaultChannel() {
|
|
226
277
|
if (!defaultChannel)
|
|
227
278
|
defaultChannel = new OutputChannel(defaultOutputBus);
|
|
228
279
|
return defaultChannel;
|
|
229
280
|
}
|
|
281
|
+
/** Сброс синглтона (изоляция тестов). */
|
|
230
282
|
export function resetDefaultChannel() {
|
|
231
283
|
defaultChannel?.dispose();
|
|
232
284
|
defaultChannel = null;
|
package/dist/output/format.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Форматирование событий в строки вида `[LEVEL] [source] ISO — text`.
|
|
1
2
|
import { createColors } from "picocolors";
|
|
2
3
|
const colored = createColors(true);
|
|
3
4
|
const LEVEL_COLORS = {
|
|
@@ -6,7 +7,7 @@ const LEVEL_COLORS = {
|
|
|
6
7
|
warn: (s) => colored.yellow(s),
|
|
7
8
|
error: (s) => colored.red(s),
|
|
8
9
|
};
|
|
9
|
-
/**
|
|
10
|
+
/** Форматирует событие как в legacy-логере: `[LEVEL] [source] ISO — text`. */
|
|
10
11
|
export function formatEventLine(ev, color) {
|
|
11
12
|
const prefix = ev.source ? ` [${ev.source}]` : "";
|
|
12
13
|
const line = `[${ev.level.toUpperCase()}]${prefix} ${new Date(ev.ts).toISOString()} — ${ev.text}`;
|
package/dist/output/index.js
CHANGED
package/dist/output/json-sink.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* warn/error
|
|
4
|
-
* Info/debug
|
|
2
|
+
* Копит события шины, чтобы машиночитаемый прогон (`--json`) включил
|
|
3
|
+
* warn/error-диагностику, которую человеческий канал гасит через `setQuiet`.
|
|
4
|
+
* Info/debug игнорируются: это шум прогресса, а не диагностика.
|
|
5
5
|
*/
|
|
6
|
+
/** Сток warn/error-диагностики для `--json`. @param bus шина для подписки. */
|
|
6
7
|
export class JsonOutputSink {
|
|
7
8
|
events = [];
|
|
8
9
|
unsub;
|
|
@@ -11,6 +12,7 @@ export class JsonOutputSink {
|
|
|
11
12
|
this.events.push(ev);
|
|
12
13
|
});
|
|
13
14
|
}
|
|
15
|
+
/** Только warn/error события в виде плоских записей. */
|
|
14
16
|
diagnostics() {
|
|
15
17
|
return this.events
|
|
16
18
|
.filter((e) => e.level === "warn" || e.level === "error")
|
package/dist/output/machine.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
// Машиночитаемый вывод (JSON-контракты CLI). Единственное место с raw stdout.
|
|
2
|
+
/** Пишет JSON в stdout (контракт `--json`). @param value любой сериализуемый объект. */
|
|
2
3
|
export function writeMachineJson(value) {
|
|
3
4
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
4
5
|
}
|
|
5
|
-
/**
|
|
6
|
+
/** Строка в stdout для non-TTY фолбэка REPL (оговорённое исключение single-writer). */
|
|
6
7
|
export function writeNonTtyLine(text) {
|
|
7
|
-
process.stdout.write(text
|
|
8
|
+
process.stdout.write(`${text}\n`);
|
|
8
9
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* `
|
|
2
|
+
* Сохраняет в лог сессии только явно помеченные события (`data.persist === true`).
|
|
3
|
+
* Остальной вывод — транзиентный прогресс терминала и осознанно НЕ персистится;
|
|
4
|
+
* основной файловый путь долговечных записей — `SessionLogger.logSilent` /
|
|
5
|
+
* `logStructured`.
|
|
6
6
|
*/
|
|
7
7
|
export class SessionOutputSink {
|
|
8
8
|
session;
|
package/dist/tools/approve.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
/** Тул явного Yes/No-подтверждения действия (интерактивный, alwaysOn). */
|
|
1
2
|
import { t } from "../i18n/index";
|
|
2
3
|
import { askChoice } from "./user-input";
|
|
4
|
+
/** Просит подтверждение; reject — success:false (сигнал сбоя для цикла). */
|
|
3
5
|
export const approveTool = {
|
|
4
6
|
name: "approve",
|
|
5
7
|
icon: "🙋",
|
|
6
8
|
description: "Request user approval for an action. The user picks Yes or No from a menu.",
|
|
7
9
|
tags: ["core"],
|
|
10
|
+
// Как в question.ts: интерактивные тулы переживают сужение (P5).
|
|
11
|
+
alwaysOn: true,
|
|
8
12
|
interactive: true,
|
|
9
13
|
parameters: {
|
|
10
14
|
type: "object",
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
/** Тул аттача картинки в контекст (файл/URL/буфер обмена). */
|
|
1
2
|
import { existsSync } from "fs";
|
|
2
3
|
import { resolve } from "path";
|
|
3
4
|
import { t } from "../i18n/index";
|
|
4
5
|
import { loadFileAsDataUrl, loadUrlAsDataUrl, readClipboardImage, bufferToDataUrl, } from "../llm/image-utils";
|
|
5
6
|
import { logSecurityBlock } from "../modules/security/audit-log";
|
|
7
|
+
/** Кладёт картинку в pending-очередь контекста (PNG/JPEG/GIF/WebP). */
|
|
6
8
|
export const attachImageTool = {
|
|
7
9
|
name: "attach_image",
|
|
8
10
|
icon: "🖼️",
|
|
@@ -37,7 +39,7 @@ export const attachImageTool = {
|
|
|
37
39
|
dataUrl = result.dataUrl;
|
|
38
40
|
}
|
|
39
41
|
else if (source.startsWith("http://") || source.startsWith("https://")) {
|
|
40
|
-
//
|
|
42
|
+
// URL — по сетевой политике (SSRF).
|
|
41
43
|
const { isUrlAllowed } = await import("../modules/security/network-validator");
|
|
42
44
|
const { getSessionSecurityConfig } = await import("../modules/security/session-isolation");
|
|
43
45
|
const networkConfig = ctx.sessionContext
|
|
@@ -59,8 +61,7 @@ export const attachImageTool = {
|
|
|
59
61
|
output: t("image.not_found", { path: source }),
|
|
60
62
|
};
|
|
61
63
|
}
|
|
62
|
-
//
|
|
63
|
-
// combination as read_file).
|
|
64
|
+
// Пути: глобальная политика + скоуп субагента (та же связка, что у read_file).
|
|
64
65
|
const { isPathInScope } = await import("../modules/security/path-validator");
|
|
65
66
|
const { DEFAULT_SECURITY_CONFIG } = await import("../config/security");
|
|
66
67
|
const validation = isPathInScope(ctx.baseDir, absPath, ctx.scope, ctx.config?.security?.paths || DEFAULT_SECURITY_CONFIG.paths);
|
|
@@ -74,7 +75,7 @@ export const attachImageTool = {
|
|
|
74
75
|
const result = await loadFileAsDataUrl(absPath);
|
|
75
76
|
dataUrl = result.dataUrl;
|
|
76
77
|
}
|
|
77
|
-
//
|
|
78
|
+
// Картинка — pending content part на менеджере контекста.
|
|
78
79
|
if (!ctx.contextManager) {
|
|
79
80
|
return {
|
|
80
81
|
success: false,
|
package/dist/tools/auto-fixer.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
/** Автофиксы LSP-ошибок tsc (конфликты импортов, неиспользуемые). */
|
|
1
2
|
import { extname } from "path";
|
|
2
|
-
/**
|
|
3
|
-
* LSP error codes that can be auto-fixed.
|
|
4
|
-
*/
|
|
3
|
+
/** Коды LSP-ошибок, поддающиеся автофиксу. */
|
|
5
4
|
const AUTO_FIXABLE_CODES = new Set([
|
|
6
5
|
2307, // Cannot find module (import missing)
|
|
7
6
|
2440, // Import declaration conflicts with local declaration
|
|
@@ -9,8 +8,8 @@ const AUTO_FIXABLE_CODES = new Set([
|
|
|
9
8
|
2769, // No overload matches this call (simple type mismatches)
|
|
10
9
|
]);
|
|
11
10
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* Извлекает LSP-ошибки из вывода tsc.
|
|
12
|
+
* Формат: file(line,col): error TSxxxx: message. Возврат: список ошибок.
|
|
14
13
|
*/
|
|
15
14
|
export function parseTscOutput(output) {
|
|
16
15
|
const errors = [];
|
|
@@ -30,10 +29,9 @@ export function parseTscOutput(output) {
|
|
|
30
29
|
return errors;
|
|
31
30
|
}
|
|
32
31
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* -
|
|
36
|
-
* - TS6133: Unused import → remove from import list
|
|
32
|
+
* Пробует автофиксить LSP-ошибки в TS/JS. Только частые безопасные паттерны:
|
|
33
|
+
* - TS2440: конфликт импорта → переименование через `as`;
|
|
34
|
+
* - TS6133: неиспользуемый импорт → удаление из списка.
|
|
37
35
|
*/
|
|
38
36
|
export function autoFixErrors(filePath, content, errors) {
|
|
39
37
|
const ext = extname(filePath).toLowerCase();
|
|
@@ -71,16 +69,14 @@ export function autoFixErrors(filePath, content, errors) {
|
|
|
71
69
|
remaining,
|
|
72
70
|
};
|
|
73
71
|
}
|
|
74
|
-
/**
|
|
75
|
-
* Try to fix a single LSP error.
|
|
76
|
-
*/
|
|
72
|
+
/** Пробует починить одну LSP-ошибку. */
|
|
77
73
|
function fixError(content, error) {
|
|
78
74
|
const lines = content.split("\n");
|
|
79
75
|
const lineIndex = error.line - 1;
|
|
80
76
|
if (lineIndex < 0 || lineIndex >= lines.length) {
|
|
81
77
|
return { fixed: false, newContent: content };
|
|
82
78
|
}
|
|
83
|
-
const
|
|
79
|
+
const _line = lines[lineIndex];
|
|
84
80
|
switch (error.code) {
|
|
85
81
|
case 2440: // Import declaration conflicts with local declaration
|
|
86
82
|
return fixImportConflict(lines, lineIndex, error);
|
|
@@ -91,25 +87,18 @@ function fixError(content, error) {
|
|
|
91
87
|
}
|
|
92
88
|
}
|
|
93
89
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* Example:
|
|
98
|
-
* import { foo } from './module';
|
|
99
|
-
* export function foo() { ... }
|
|
100
|
-
* Becomes:
|
|
101
|
-
* import { foo as fooImport } from './module';
|
|
102
|
-
* export function foo() { ... }
|
|
90
|
+
* Фикс TS2440: конфликт импорта с локальной декларацией.
|
|
91
|
+
* Стратегия: добавить `as LocalName` к импорту (`foo` → `foo as fooImport`).
|
|
103
92
|
*/
|
|
104
93
|
function fixImportConflict(lines, lineIndex, error) {
|
|
105
|
-
const
|
|
106
|
-
//
|
|
94
|
+
const _line = lines[lineIndex];
|
|
95
|
+
// Конфликтное имя — из текста ошибки.
|
|
107
96
|
const nameMatch = error.message.match(/Import declaration conflicts with local declaration of '(\w+)'/);
|
|
108
97
|
if (!nameMatch) {
|
|
109
98
|
return { fixed: false, newContent: lines.join("\n") };
|
|
110
99
|
}
|
|
111
100
|
const conflictingName = nameMatch[1];
|
|
112
|
-
//
|
|
101
|
+
// Строка импорта (может быть выше текущей) — для TS2440-фикса.
|
|
113
102
|
let importLineIndex = lineIndex;
|
|
114
103
|
while (importLineIndex >= 0 && !lines[importLineIndex].includes("import")) {
|
|
115
104
|
importLineIndex--;
|
|
@@ -118,14 +107,14 @@ function fixImportConflict(lines, lineIndex, error) {
|
|
|
118
107
|
return { fixed: false, newContent: lines.join("\n") };
|
|
119
108
|
}
|
|
120
109
|
const importLine = lines[importLineIndex];
|
|
121
|
-
//
|
|
110
|
+
// Только именованный импорт вида import { ... } from '...'.
|
|
122
111
|
const namedImportMatch = importLine.match(/import\s+(?:type\s+)?\{([^}]+)\}\s+from/);
|
|
123
112
|
if (!namedImportMatch) {
|
|
124
113
|
return { fixed: false, newContent: lines.join("\n") };
|
|
125
114
|
}
|
|
126
115
|
const imports = namedImportMatch[1];
|
|
127
116
|
const importParts = imports.split(",").map((s) => s.trim());
|
|
128
|
-
//
|
|
117
|
+
// Конфликтное имя — в списке импортов?
|
|
129
118
|
const nameIndex = importParts.findIndex((part) => {
|
|
130
119
|
const baseName = part.split(/\s+as\s+/)[0].trim();
|
|
131
120
|
return baseName === conflictingName;
|
|
@@ -133,36 +122,29 @@ function fixImportConflict(lines, lineIndex, error) {
|
|
|
133
122
|
if (nameIndex === -1) {
|
|
134
123
|
return { fixed: false, newContent: lines.join("\n") };
|
|
135
124
|
}
|
|
136
|
-
//
|
|
125
|
+
// Алиас уже есть — не трогаем.
|
|
137
126
|
const currentImport = importParts[nameIndex];
|
|
138
127
|
if (currentImport.includes(" as ")) {
|
|
139
128
|
return { fixed: false, newContent: lines.join("\n") };
|
|
140
129
|
}
|
|
141
|
-
//
|
|
130
|
+
// Добавить алиас.
|
|
142
131
|
importParts[nameIndex] = `${conflictingName} as ${conflictingName}Import`;
|
|
143
132
|
lines[importLineIndex] = importLine.replace(namedImportMatch[1], importParts.join(", "));
|
|
144
133
|
return { fixed: true, newContent: lines.join("\n") };
|
|
145
134
|
}
|
|
146
135
|
/**
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
* Example:
|
|
151
|
-
* import { foo, bar } from './module';
|
|
152
|
-
* console.log(bar);
|
|
153
|
-
* Becomes:
|
|
154
|
-
* import { bar } from './module';
|
|
155
|
-
* console.log(bar);
|
|
136
|
+
* Фикс TS6133: объявлена, но не читается. Стратегия: выкинуть неиспользуемый
|
|
137
|
+
* импорт из списка (`{ foo, bar }` → `{ bar }`); пустой импорт — строкой целиком.
|
|
156
138
|
*/
|
|
157
139
|
function fixUnusedImport(lines, lineIndex, error) {
|
|
158
|
-
const
|
|
159
|
-
//
|
|
140
|
+
const _line = lines[lineIndex];
|
|
141
|
+
// Неиспользуемое имя — из текста ошибки.
|
|
160
142
|
const nameMatch = error.message.match(/'(\w+)' is declared but its value is never read/);
|
|
161
143
|
if (!nameMatch) {
|
|
162
144
|
return { fixed: false, newContent: lines.join("\n") };
|
|
163
145
|
}
|
|
164
146
|
const unusedName = nameMatch[1];
|
|
165
|
-
//
|
|
147
|
+
// Строка импорта (может быть выше текущей) — для TS6133-фикса.
|
|
166
148
|
let importLineIndex = lineIndex;
|
|
167
149
|
while (importLineIndex >= 0 && !lines[importLineIndex].includes("import")) {
|
|
168
150
|
importLineIndex--;
|
|
@@ -171,14 +153,14 @@ function fixUnusedImport(lines, lineIndex, error) {
|
|
|
171
153
|
return { fixed: false, newContent: lines.join("\n") };
|
|
172
154
|
}
|
|
173
155
|
const importLine = lines[importLineIndex];
|
|
174
|
-
//
|
|
156
|
+
// Только именованный импорт вида import { ... } from '...' (TS6133).
|
|
175
157
|
const namedImportMatch = importLine.match(/import\s+(?:type\s+)?\{([^}]+)\}\s+from/);
|
|
176
158
|
if (!namedImportMatch) {
|
|
177
159
|
return { fixed: false, newContent: lines.join("\n") };
|
|
178
160
|
}
|
|
179
161
|
const imports = namedImportMatch[1];
|
|
180
162
|
const importParts = imports.split(",").map((s) => s.trim());
|
|
181
|
-
//
|
|
163
|
+
// Найти и выкинуть неиспользуемый импорт.
|
|
182
164
|
const nameIndex = importParts.findIndex((part) => {
|
|
183
165
|
const baseName = part.split(/\s+as\s+/)[0].trim();
|
|
184
166
|
return baseName === unusedName;
|
|
@@ -187,7 +169,7 @@ function fixUnusedImport(lines, lineIndex, error) {
|
|
|
187
169
|
return { fixed: false, newContent: lines.join("\n") };
|
|
188
170
|
}
|
|
189
171
|
importParts.splice(nameIndex, 1);
|
|
190
|
-
//
|
|
172
|
+
// Импортов не осталось — снести строку целиком.
|
|
191
173
|
if (importParts.length === 0) {
|
|
192
174
|
lines.splice(importLineIndex, 1);
|
|
193
175
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Детерминированный вывод tool-тегов по типу задачи (P5 auto-narrowing).
|
|
3
|
+
*
|
|
4
|
+
* Главный цикл показывает LLM только `defaultTags` (+ структурные `alwaysOn`);
|
|
5
|
+
* остальное скрыто за `enable_tools`. Без preseed веб-задача тратит первый ход
|
|
6
|
+
* на поиск `enable_tools`, а 9B-модель иногда уходит в shell/MCP (из-за этого
|
|
7
|
+
* сужение и откатывали к `enableOnDemand: false`).
|
|
8
|
+
*
|
|
9
|
+
* Классификатор работает ДО первого LLM-вызова на сыром сообщении и только
|
|
10
|
+
* ДОБАВЛЯЕТ теги (дефолты не снимает): простой чат остаётся узким (file/code +
|
|
11
|
+
* alwaysOn), а research/browser/memory-задача сразу видит нужные тулы.
|
|
12
|
+
* Без LLM-вызова и затрат контекста.
|
|
13
|
+
*
|
|
14
|
+
* Правила — keyword-эвристики (en+ru): `research` со сдвигом в recall
|
|
15
|
+
* (пропуск веб-намерения стоит лишний enable_tools round-trip), `browser`/
|
|
16
|
+
* `shell`/`memory`/`vision` — в precision (простые ходы остаются узкими).
|
|
17
|
+
* Неизвестный текст — дефолты без изменений.
|
|
18
|
+
*/
|
|
19
|
+
/** Известные теги тулов. */
|
|
20
|
+
export const KNOWN_TOOL_TAGS = [
|
|
21
|
+
"file",
|
|
22
|
+
"code",
|
|
23
|
+
"shell",
|
|
24
|
+
"research",
|
|
25
|
+
"browser",
|
|
26
|
+
"vision",
|
|
27
|
+
"image",
|
|
28
|
+
"memory",
|
|
29
|
+
"core",
|
|
30
|
+
];
|
|
31
|
+
const RESEARCH_RE = /search|google|найди|найти|поиск|погод|новост|интернет|сайт|документ|стать|цен|стоим|курс|билет|рейтинг|обзор|рецепт|http|www\.|url|\bsite\b|\bweb\b|fetch|download|скача|загруз|stackoverflow|github\.com|wikipedia|википеди/i;
|
|
32
|
+
const BROWSER_RE = /screenshot|скриншот|playwright|browser|браузер|кликни|click\b|открой.*стран|automation|автоматизац.*браузер|селектор|selector/i;
|
|
33
|
+
const SHELL_RE = /process_|фонов|background|dev.?server|docker|deploy|депло|pipeline|пайплайн|контейнер|процесс/i;
|
|
34
|
+
const MEMORY_RE = /запомни|remember|recall|вспомни|память|\bmemory\b|мой день рождения|my birthday|мой рост|обо мне|preferences|предпочтени/i;
|
|
35
|
+
const VISION_RE = /image|картинк|фото|изображен|скрин|attach|vision|png|\bjpg\b|jpeg|сфотографируй|разбери.*фото/i;
|
|
36
|
+
const CODE_RE = /код|code|typescript|python|javascript|bun|npm|git|коммит|тест|lint|build|сборк|баг|ошибк.*код|файл|file|папк|директори|рефактор|refactor/i;
|
|
37
|
+
/**
|
|
38
|
+
* Дополнительные теги из сообщения пользователя. Всегда подмножество
|
|
39
|
+
* KNOWN_TOOL_TAGS, без `file`/`code` (это дефолты). Чистая функция —
|
|
40
|
+
* безопасно вызывать на каждом ходе.
|
|
41
|
+
*/
|
|
42
|
+
export function inferExtraToolTags(input) {
|
|
43
|
+
if (!input || !input.trim())
|
|
44
|
+
return [];
|
|
45
|
+
const extra = new Set();
|
|
46
|
+
if (RESEARCH_RE.test(input))
|
|
47
|
+
extra.add("research");
|
|
48
|
+
if (BROWSER_RE.test(input)) {
|
|
49
|
+
extra.add("browser");
|
|
50
|
+
extra.add("vision");
|
|
51
|
+
}
|
|
52
|
+
if (SHELL_RE.test(input))
|
|
53
|
+
extra.add("shell");
|
|
54
|
+
if (MEMORY_RE.test(input))
|
|
55
|
+
extra.add("memory");
|
|
56
|
+
if (VISION_RE.test(input)) {
|
|
57
|
+
extra.add("vision");
|
|
58
|
+
extra.add("image");
|
|
59
|
+
}
|
|
60
|
+
// Явное code/shell-намерение возвращает `shell` (bash виден и через `code`,
|
|
61
|
+
// но process_*/pipeline нужен именно shell-тег).
|
|
62
|
+
if (CODE_RE.test(input) && /process|фонов|background|pipeline|docker/i.test(input)) {
|
|
63
|
+
extra.add("shell");
|
|
64
|
+
}
|
|
65
|
+
return [...extra];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Аддитивный preseed: дописывает выведенные теги в `activeTags`, возвращает
|
|
69
|
+
* добавленные. Ничего не удаляет (гранты `enable_tools` сохраняются).
|
|
70
|
+
* No-op при выключенном сужении (`activeTags` undefined = legacy-режим).
|
|
71
|
+
*/
|
|
72
|
+
export function seedToolTags(activeTags, input) {
|
|
73
|
+
if (!activeTags)
|
|
74
|
+
return [];
|
|
75
|
+
const added = [];
|
|
76
|
+
for (const tag of inferExtraToolTags(input)) {
|
|
77
|
+
if (!activeTags.includes(tag)) {
|
|
78
|
+
activeTags.push(tag);
|
|
79
|
+
added.push(tag);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return added;
|
|
83
|
+
}
|