micro-models-agent 2.11.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 +10 -0
- package/dist/assets/js/tabs.js +22 -3
- 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/index.js +37 -3
- 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 +273 -47
- 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
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
// lsp_check: сбор файлов для проверки и форматирование диагностик.
|
|
1
2
|
import { readdir, stat } from "fs/promises";
|
|
2
3
|
import { resolve, relative } from "path";
|
|
3
4
|
import { getServerForFile } from "./config";
|
|
4
5
|
import { toForwardSlash } from "../../tools/path-utils";
|
|
5
|
-
/**
|
|
6
|
+
/** Режим каталога lsp_check: глубина обхода и кап файлов на вызов. */
|
|
6
7
|
export const MAX_LSP_CHECK_FILES = 15;
|
|
7
8
|
const MAX_LSP_WALK_DEPTH = 4;
|
|
8
9
|
const SKIP_DIRS = new Set(["node_modules", ".git", ".mma", "dist"]);
|
|
10
|
+
/** Подписи severity диагностик. */
|
|
9
11
|
export const severityLabels = {
|
|
10
12
|
1: "error",
|
|
11
13
|
2: "warning",
|
|
@@ -13,10 +15,9 @@ export const severityLabels = {
|
|
|
13
15
|
4: "hint",
|
|
14
16
|
};
|
|
15
17
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* not checked rather than producing noise.
|
|
18
|
+
* Резолв цели: файл (точечная проверка) или ограниченный список исходников
|
|
19
|
+
* (проверка каталога, кап MAX_LSP_CHECK_FILES). Собираются только файлы с
|
|
20
|
+
* настроенным LSP-сервером — неподдерживаемые расширения молча не проверяются.
|
|
20
21
|
*/
|
|
21
22
|
export async function collectCheckFiles(resolved, config) {
|
|
22
23
|
const info = await stat(resolved).catch(() => null);
|
|
@@ -45,6 +46,7 @@ async function walkDir(dir, depth, out, config) {
|
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
}
|
|
49
|
+
/** Форматировать диагностики списком `файл(стр,кол): severity: текст` (первые 40). */
|
|
48
50
|
export function formatCheckDiagnostics(items, baseDir) {
|
|
49
51
|
return items
|
|
50
52
|
.slice(0, 40)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// LSP-клиент: spawn сервера, JSON-RPC поверх stdio, диагностики, tree-kill при shutdown.
|
|
1
2
|
import { spawn, execSync } from "child_process";
|
|
2
3
|
import { resolve } from "path";
|
|
3
4
|
import { platform } from "os";
|
|
@@ -5,11 +6,11 @@ import { resolveSpawnCommand, buildWinCommandLine } from "./command";
|
|
|
5
6
|
import { killTree } from "../processes/registry";
|
|
6
7
|
import { toForwardSlash } from "../../tools/path-utils";
|
|
7
8
|
import { errMsg } from "../../utils";
|
|
9
|
+
import { LSP_DEFAULT_TIMEOUT_MS as DEFAULT_TIMEOUT } from "../../config/timeouts";
|
|
8
10
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* the user's chat.
|
|
11
|
+
* Логгер-адаптер: LSP-диагностику только в app.jsonl, никогда в консоль/терминал.
|
|
12
|
+
* LSP-предупреждения шумные (таймаут на первом запуске, установка npx) и должны
|
|
13
|
+
* диагностироваться из файлов сессии, не мусор в чате пользователя.
|
|
13
14
|
*/
|
|
14
15
|
export class FileOnlyLogger {
|
|
15
16
|
logger;
|
|
@@ -29,9 +30,10 @@ export class FileOnlyLogger {
|
|
|
29
30
|
this.logger.logSilent("error", msg, meta);
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
/** LSP-клиент: checkFile/probe поверх spawn + initialize + shutdown. */
|
|
33
34
|
export class LspClient {
|
|
34
35
|
logger = null;
|
|
36
|
+
/** Назначить логгер (null — молчать). */
|
|
35
37
|
setLogger(logger) {
|
|
36
38
|
this.logger = logger;
|
|
37
39
|
}
|
|
@@ -44,6 +46,7 @@ export class LspClient {
|
|
|
44
46
|
diagnosticsResolve = null;
|
|
45
47
|
diagnosticsTimer = null;
|
|
46
48
|
initialized = false;
|
|
49
|
+
/** Проверить файл: открыть в сервере, дождаться publishDiagnostics, вернуть их. */
|
|
47
50
|
async checkFile(filePath, baseDir, config, projectRoot = baseDir) {
|
|
48
51
|
const timeout = config.timeout ?? DEFAULT_TIMEOUT;
|
|
49
52
|
try {
|
|
@@ -71,7 +74,7 @@ export class LspClient {
|
|
|
71
74
|
return await diagPromise;
|
|
72
75
|
}
|
|
73
76
|
catch (e) {
|
|
74
|
-
//
|
|
77
|
+
// Пробросить наружу, чтобы LspModule показал падение, а не спрятал.
|
|
75
78
|
throw e instanceof Error ? e : new Error(String(e));
|
|
76
79
|
}
|
|
77
80
|
finally {
|
|
@@ -79,10 +82,9 @@ export class LspClient {
|
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
84
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* of the first write_file timing out.
|
|
85
|
+
* Лёгкая проба «сервер реально стартует»: spawn + initialize + shutdown.
|
|
86
|
+
* Для баннера REPL — мёртвый сервер (упавшая npx-автоустановка, неверное имя
|
|
87
|
+
* пакета, нет бинарника) виден заранее, а не таймаутом первого write_file.
|
|
86
88
|
*/
|
|
87
89
|
async probe(config, projectRoot, timeout) {
|
|
88
90
|
try {
|
|
@@ -110,7 +112,7 @@ export class LspClient {
|
|
|
110
112
|
command: config.command,
|
|
111
113
|
projectRoot,
|
|
112
114
|
});
|
|
113
|
-
// npx
|
|
115
|
+
// npx-автоустановка может вылететь за таймаут initialize на первом запуске — один ретрай.
|
|
114
116
|
if (!(e instanceof Error) || !e.message.includes("initialize"))
|
|
115
117
|
throw e;
|
|
116
118
|
await this.shutdown();
|
|
@@ -138,9 +140,9 @@ export class LspClient {
|
|
|
138
140
|
throw new Error(`${config.command} not found in PATH`);
|
|
139
141
|
}
|
|
140
142
|
}
|
|
141
|
-
//
|
|
142
|
-
// npx
|
|
143
|
-
//
|
|
143
|
+
// Команда npx — сначала ищем реальный бинарник глобально.
|
|
144
|
+
// npx качает пакеты на каждый вызов (на Windows медленно, ~8-15с),
|
|
145
|
+
// даже если бинарник уже стоит глобально.
|
|
144
146
|
let effectiveCommand = config.command;
|
|
145
147
|
let effectiveArgs = config.args ?? [];
|
|
146
148
|
if (config.command === "npx" && effectiveArgs.length > 0) {
|
|
@@ -149,13 +151,13 @@ export class LspClient {
|
|
|
149
151
|
const whichCmd = platform() === "win32" ? `where ${binaryName}` : `which ${binaryName}`;
|
|
150
152
|
try {
|
|
151
153
|
execSync(whichCmd, { stdio: "pipe", timeout: 3000 });
|
|
152
|
-
//
|
|
154
|
+
// Бинарник есть глобально — напрямую, без npx.
|
|
153
155
|
effectiveCommand = binaryName;
|
|
154
156
|
effectiveArgs = effectiveArgs.filter((a) => a !== "--yes" && a !== "--package" && a !== binaryName && !this.isPackageVersion(a));
|
|
155
157
|
this.logger?.debug(`LSP: using globally installed ${binaryName} (skipped npx)`);
|
|
156
158
|
}
|
|
157
159
|
catch {
|
|
158
|
-
//
|
|
160
|
+
// Глобально нет — фолбэк на npx (самоустановится).
|
|
159
161
|
this.logger?.debug(`LSP: ${binaryName} not found globally, falling back to npx`);
|
|
160
162
|
}
|
|
161
163
|
}
|
|
@@ -169,14 +171,13 @@ export class LspClient {
|
|
|
169
171
|
stdio: ["pipe", "pipe", "pipe"],
|
|
170
172
|
env: { ...process.env, ...config.env },
|
|
171
173
|
cwd: projectRoot,
|
|
172
|
-
// POSIX:
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
// survive as orphans. Windows relies on taskkill /T instead.
|
|
174
|
+
// POSIX: потомок — лидер группы, чтобы `kill(-pid)` killTree() доставал
|
|
175
|
+
// всю цепочку (npx → node → tsserver). Без этого групповой kill падает
|
|
176
|
+
// с ESRCH, а внуки выживают сиротами. Windows — taskkill /T.
|
|
176
177
|
detached: !isWin,
|
|
177
178
|
};
|
|
178
179
|
if (isWin) {
|
|
179
|
-
//
|
|
180
|
+
// `.cmd`-шим напрямую под Node не спавнится (`spawn npx EINVAL`) — через cmd.exe.
|
|
180
181
|
spawnCommand = buildWinCommandLine(spawnCommand, args);
|
|
181
182
|
spawnArgs = [];
|
|
182
183
|
spawnOpts.shell = true;
|
|
@@ -210,7 +211,7 @@ export class LspClient {
|
|
|
210
211
|
const headerEnd = this.buffer.indexOf("\r\n\r\n");
|
|
211
212
|
if (headerEnd === -1)
|
|
212
213
|
return;
|
|
213
|
-
//
|
|
214
|
+
// Заголовки — ASCII: декодим только срез заголовка.
|
|
214
215
|
const header = this.buffer.subarray(0, headerEnd).toString("utf8");
|
|
215
216
|
const match = header.match(/Content-Length: (\d+)/i);
|
|
216
217
|
if (!match) {
|
|
@@ -218,7 +219,7 @@ export class LspClient {
|
|
|
218
219
|
continue;
|
|
219
220
|
}
|
|
220
221
|
this.contentLength = parseInt(match[1], 10);
|
|
221
|
-
//
|
|
222
|
+
// Защита от злонамеренных/битых серверов с абсурдным Content-Length
|
|
222
223
|
if (this.contentLength > 10 * 1024 * 1024) {
|
|
223
224
|
this.buffer = this.buffer.subarray(headerEnd + 4);
|
|
224
225
|
this.contentLength = -1;
|
|
@@ -226,9 +227,9 @@ export class LspClient {
|
|
|
226
227
|
}
|
|
227
228
|
this.buffer = this.buffer.subarray(headerEnd + 4);
|
|
228
229
|
}
|
|
229
|
-
// Content-Length
|
|
230
|
-
//
|
|
231
|
-
//
|
|
230
|
+
// Content-Length считает БАЙТЫ, не JS-символы. Нарезка декодированной
|
|
231
|
+
// строки по числу символов портит фреймы с многобайтным UTF-8
|
|
232
|
+
// (напр. кириллические диагностики) — остаток держим сырыми байтами.
|
|
232
233
|
if (this.buffer.length < this.contentLength)
|
|
233
234
|
return;
|
|
234
235
|
const body = this.buffer.subarray(0, this.contentLength).toString("utf8");
|
|
@@ -306,10 +307,9 @@ export class LspClient {
|
|
|
306
307
|
async shutdown() {
|
|
307
308
|
try {
|
|
308
309
|
if (this.process && this.initialized && this.process.stdin?.writable) {
|
|
309
|
-
//
|
|
310
|
-
//
|
|
311
|
-
//
|
|
312
|
-
// server never had a chance to reply, producing spurious timeout warnings.
|
|
310
|
+
// Ответ shutdown ждём (с таймаутом), чтобы сервер успел подтвердить до
|
|
311
|
+
// exit и kill. Старый код слал shutdown fire-and-forget и тут же убивал —
|
|
312
|
+
// сервер ответить не успевал, сыпались ложные timeout-предупреждения.
|
|
313
313
|
try {
|
|
314
314
|
await this.sendRequest("shutdown", null, 3000);
|
|
315
315
|
}
|
|
@@ -325,9 +325,9 @@ export class LspClient {
|
|
|
325
325
|
}
|
|
326
326
|
finally {
|
|
327
327
|
if (this.process) {
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
//
|
|
328
|
+
// Прямой потомок на win32 — cmd.exe-обёртка; её убийство в одиночку
|
|
329
|
+
// сиротит дерево npx → node → tsserver (наблюдались текущие node после
|
|
330
|
+
// каждого чека). Tree-kill — умирает вся цепочка.
|
|
331
331
|
try {
|
|
332
332
|
killTree(this.process);
|
|
333
333
|
}
|
|
@@ -374,11 +374,11 @@ export class LspClient {
|
|
|
374
374
|
return map[ext ?? ""] ?? "plaintext";
|
|
375
375
|
}
|
|
376
376
|
/**
|
|
377
|
-
*
|
|
378
|
-
* `[--yes] [--package X]... <binary> --stdio`.
|
|
379
|
-
*
|
|
380
|
-
* null
|
|
381
|
-
*
|
|
377
|
+
* Имя реального бинарника из npx-args — только строгий layout
|
|
378
|
+
* `[--yes] [--package X]... <binary> --stdio`. Серверы с хвостовыми
|
|
379
|
+
* серверными аргументами (напр. angular `ngserver --stdio --tsProbeLocations …`)
|
|
380
|
+
* дают null и всегда идут через npx — их флаги не принять за бинарник
|
|
381
|
+
* и не вырезать.
|
|
382
382
|
*/
|
|
383
383
|
extractBinaryFromNpxArgs(args) {
|
|
384
384
|
const stdioIdx = args.lastIndexOf("--stdio");
|
|
@@ -399,7 +399,7 @@ export class LspClient {
|
|
|
399
399
|
}
|
|
400
400
|
return binary;
|
|
401
401
|
}
|
|
402
|
-
/**
|
|
402
|
+
/** Похоже ли на спецификатор версии пакета (напр. "typescript@5"). */
|
|
403
403
|
isPackageVersion(s) {
|
|
404
404
|
return /^[\w-]+@[\d.+*-]/.test(s);
|
|
405
405
|
}
|
|
@@ -1,23 +1,20 @@
|
|
|
1
|
+
// Запуск LSP-серверов на Windows: резолв shim (.cmd/.bat) и строка для cmd.exe.
|
|
1
2
|
import { delimiter, join } from "path";
|
|
2
3
|
import { existsSync } from "fs";
|
|
3
4
|
import { platform } from "os";
|
|
4
5
|
const WIN_EXTS = [".cmd", ".bat", ".exe", ".com"];
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* when nothing exists (the spawn will then fail with a meaningful ENOENT).
|
|
13
|
-
*
|
|
14
|
-
* Non-Windows platforms and commands that already carry an extension or a
|
|
15
|
-
* path separator are returned unchanged.
|
|
7
|
+
* Резолв команды для `child_process.spawn` на Windows.
|
|
8
|
+
* Node-`spawn` не исполняет `.cmd`/`.bat`-шимы напрямую без shell, а голый
|
|
9
|
+
* `npx` падает с `spawn npx ENOENT` — на Windows реальный бинарник это
|
|
10
|
+
* `npx.cmd`. Возвращает первый найденный на PATH шим (`npx.cmd`, `npx.bat`,
|
|
11
|
+
* `npx.exe`, …), а если ничего нет — голую команду (spawn упадёт с понятным
|
|
12
|
+
* ENOENT). Не-Windows и команды с расширением/сепаратором — как есть.
|
|
16
13
|
*/
|
|
17
14
|
export function resolveSpawnCommand(command, platformName = platform(), pathEnv = process.env.PATH ?? "") {
|
|
18
15
|
if (platformName !== "win32")
|
|
19
16
|
return command;
|
|
20
|
-
//
|
|
17
|
+
// Уже путь или с расширением — пропустить как есть.
|
|
21
18
|
if (command.includes("/") ||
|
|
22
19
|
command.includes("\\") ||
|
|
23
20
|
WIN_EXTS.some((ext) => command.toLowerCase().endsWith(ext))) {
|
|
@@ -34,19 +31,15 @@ export function resolveSpawnCommand(command, platformName = platform(), pathEnv
|
|
|
34
31
|
return command;
|
|
35
32
|
}
|
|
36
33
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* `
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* `pyright --stdio`) survive the round-trip.
|
|
47
|
-
*
|
|
48
|
-
* Non-Windows platforms never call this (they spawn the resolved command +
|
|
49
|
-
* args directly, no shell).
|
|
34
|
+
* Склейка резолвленной команды и args в одну строку для cmd.exe.
|
|
35
|
+
* Под Node на Windows `spawn` `.cmd`/`.bat`-шима БЕЗ shell бросает
|
|
36
|
+
* `spawn EINVAL` (CreateProcess не запускает батники напрямую). Резолв
|
|
37
|
+
* `npx` → `npx.cmd` чинит старый `ENOENT`, но не `EINVAL` — shell'а всё равно
|
|
38
|
+
* нет. Надёжный фикс — гнать всю строку через `cmd.exe /d /s /c`
|
|
39
|
+
* (т.е. `spawn(line, { shell: true })`). Хелпер строит строку, квотируя
|
|
40
|
+
* аргументы с cmd-метасимволами, чтобы имена пакетов и флаги LSP-конфигов
|
|
41
|
+
* (`typescript-language-server --stdio`, `pyright --stdio`) пережили round-trip.
|
|
42
|
+
* Не-Windows сюда не ходят (спавнят команду + args напрямую, без shell).
|
|
50
43
|
*/
|
|
51
44
|
export function buildWinCommandLine(command, args) {
|
|
52
45
|
const quote = (part) => {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
// Дефолтные LSP-серверы и выбор сервера по файлу (язык, Angular-исключение).
|
|
1
2
|
import { existsSync } from "fs";
|
|
2
3
|
import { dirname, join } from "path";
|
|
3
4
|
/**
|
|
4
|
-
* LSP
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* and are skipped silently when not found.
|
|
5
|
+
* Дефолты LSP-серверов.
|
|
6
|
+
* Стратегия: предпочитать `npx` (самодокачка) глобальным бинарникам.
|
|
7
|
+
* Серверы на системных тулах (rust-analyzer, gopls) — `autoInstall: false`,
|
|
8
|
+
* при отсутствии молча скипаются.
|
|
9
9
|
*/
|
|
10
10
|
export const DEFAULT_LSP_CONFIG = {
|
|
11
11
|
enabled: true,
|
|
@@ -141,7 +141,7 @@ const LANGUAGE_MAP = {
|
|
|
141
141
|
css: "css",
|
|
142
142
|
scss: "css",
|
|
143
143
|
};
|
|
144
|
-
/**
|
|
144
|
+
/** Id языка по расширению файла (через LANGUAGE_MAP), неподдерживаемое — null. */
|
|
145
145
|
export function getLanguageForFile(filePath) {
|
|
146
146
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
147
147
|
if (!ext)
|
|
@@ -151,8 +151,8 @@ export function getLanguageForFile(filePath) {
|
|
|
151
151
|
const ANGULAR_MARKER = "angular.json";
|
|
152
152
|
const ANGULAR_LOOKUP_DEPTH = 10;
|
|
153
153
|
/**
|
|
154
|
-
*
|
|
155
|
-
*
|
|
154
|
+
* Лежит ли файл внутри Angular-workspace (маркер `angular.json` в одном из
|
|
155
|
+
* предков, поиск ограничен глубиной).
|
|
156
156
|
*/
|
|
157
157
|
function isAngularProject(filePath) {
|
|
158
158
|
let dir = dirname(filePath);
|
|
@@ -167,9 +167,9 @@ function isAngularProject(filePath) {
|
|
|
167
167
|
return false;
|
|
168
168
|
}
|
|
169
169
|
/**
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
170
|
+
* Ключ конфига LSP-сервера для файла. `.html` идёт на сервер `angular` внутри
|
|
171
|
+
* Angular-workspace (шаблонам с биндингами нужен Angular language service),
|
|
172
|
+
* везде иначе — на generic `html`.
|
|
173
173
|
*/
|
|
174
174
|
export function getServerKeyForFile(filePath, config) {
|
|
175
175
|
const lang = getLanguageForFile(filePath);
|
|
@@ -180,6 +180,7 @@ export function getServerKeyForFile(filePath, config) {
|
|
|
180
180
|
}
|
|
181
181
|
return lang;
|
|
182
182
|
}
|
|
183
|
+
/** Конфиг LSP-сервера для файла (null — не поддерживается). */
|
|
183
184
|
export function getServerForFile(filePath, config) {
|
|
184
185
|
const key = getServerKeyForFile(filePath, config);
|
|
185
186
|
if (!key)
|
|
@@ -12,23 +12,22 @@ import { severityLabels, collectCheckFiles, formatCheckDiagnostics } from "./che
|
|
|
12
12
|
import { errMsg } from "../../utils";
|
|
13
13
|
import { join } from "path";
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
15
|
+
* Подряд идущих падений LSP до отключения сервера на сессию. Мёртвый сервер
|
|
16
|
+
* (не стоит, упала npx-автоустановка, нет пути) иначе спамит `[LSP check failed]`
|
|
17
|
+
* на КАЖДУЮ запись, приучая модель игнорировать сигнал целиком (наблюдалось:
|
|
18
|
+
* ses_mst2r0r5 — LSP мёртв всю сессию, модель не реагировала). После порога —
|
|
19
|
+
* одно громкое сообщение и тишина по этому серверу: таймаут CSS не должен
|
|
20
|
+
* ронять проверки TypeScript.
|
|
21
21
|
*/
|
|
22
22
|
const MAX_CONSECUTIVE_LSP_FAILURES = 3;
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* note when no type env exists near the project root.
|
|
24
|
+
* Диагностики резолва модулей, бессмысленные без type-окружения. В голом
|
|
25
|
+
* каталоге (без tsconfig.json / node_modules) TS-сервер рапортует
|
|
26
|
+
* `Cannot find module 'fs'` и `Cannot find name '__dirname'` на валидный
|
|
27
|
+
* Node-код — модель бросает рабочий подход из-за фантомных ошибок (наблюдалось
|
|
28
|
+
* ses_mtho2oab: LSP-"ошибки" столкнули модель с планового .ts на .js и в
|
|
29
|
+
* спираль plan-drift). Душатся с явной пометкой inconclusive, если рядом с
|
|
30
|
+
* корнем проекта нет type-окружения.
|
|
32
31
|
*/
|
|
33
32
|
const TYPE_ENV_DIAG_PATTERN = /Cannot find module ['"][^'"]+['"] or its corresponding type declarations|Cannot find name '(__dirname|__filename|require|process|Buffer|console)'|Do you need to install type definitions/;
|
|
34
33
|
function hasTypeEnvironment(projectRoot) {
|
|
@@ -36,6 +35,7 @@ function hasTypeEnvironment(projectRoot) {
|
|
|
36
35
|
existsSync(join(projectRoot, "jsconfig.json")) ||
|
|
37
36
|
existsSync(join(projectRoot, "node_modules")));
|
|
38
37
|
}
|
|
38
|
+
/** Модуль LSP: пост-проверки записи, тул lsp_check, учёт мёртвых серверов. */
|
|
39
39
|
export class LspModule {
|
|
40
40
|
name = "lsp";
|
|
41
41
|
config;
|
|
@@ -49,43 +49,42 @@ export class LspModule {
|
|
|
49
49
|
this.logger = logger ?? null;
|
|
50
50
|
this.client.setLogger(this.logger);
|
|
51
51
|
}
|
|
52
|
-
/**
|
|
52
|
+
/** Обновить логгер (напр. после смены сессии). */
|
|
53
53
|
setLogger(logger) {
|
|
54
54
|
this.logger = logger;
|
|
55
55
|
this.client.setLogger(logger);
|
|
56
56
|
}
|
|
57
|
-
/**
|
|
57
|
+
/** Сбросить отключённые серверы (напр. после /lsp restart). */
|
|
58
58
|
resetDisabledServers() {
|
|
59
59
|
this.failuresByServer.clear();
|
|
60
60
|
this.disabledServers.clear();
|
|
61
61
|
}
|
|
62
|
-
/**
|
|
62
|
+
/** Список отключённых ключей серверов. */
|
|
63
63
|
getDisabledServers() {
|
|
64
64
|
return Array.from(this.disabledServers);
|
|
65
65
|
}
|
|
66
|
-
/**
|
|
66
|
+
/** Счётчики падений по серверам. */
|
|
67
67
|
getFailureCounts() {
|
|
68
68
|
return new Map(this.failuresByServer);
|
|
69
69
|
}
|
|
70
|
-
/**
|
|
70
|
+
/** Тест-хук: отключал ли модуль какой-то LSP-сервер на сессии. */
|
|
71
71
|
isLspDisabled() {
|
|
72
72
|
return this.disabledServers.size > 0;
|
|
73
73
|
}
|
|
74
|
-
/**
|
|
74
|
+
/** Тест-хук: отключён ли сервер (ключ из конфига). */
|
|
75
75
|
isServerDisabled(key) {
|
|
76
76
|
return this.disabledServers.has(key);
|
|
77
77
|
}
|
|
78
|
-
/**
|
|
78
|
+
/** Стабильная идентичность сервера из конфига. */
|
|
79
79
|
serverKey(server) {
|
|
80
80
|
return `${server.command}:${(server.args ?? []).join(" ")}`;
|
|
81
81
|
}
|
|
82
82
|
getPlugin() {
|
|
83
|
-
const self = this;
|
|
84
83
|
return {
|
|
85
84
|
name: "lsp-check",
|
|
86
85
|
priority: 15,
|
|
87
86
|
onAfterTool: async (_ctx, call, result) => {
|
|
88
|
-
if (!
|
|
87
|
+
if (!this.config.enabled)
|
|
89
88
|
return;
|
|
90
89
|
if (call.name !== "write_file" && call.name !== "edit_file")
|
|
91
90
|
return;
|
|
@@ -97,16 +96,16 @@ export class LspModule {
|
|
|
97
96
|
const fullPath = resolve(_ctx.baseDir, filePath);
|
|
98
97
|
if (!existsSync(fullPath))
|
|
99
98
|
return;
|
|
100
|
-
const serverConfig = getServerForFile(fullPath,
|
|
99
|
+
const serverConfig = getServerForFile(fullPath, this.config);
|
|
101
100
|
if (!serverConfig)
|
|
102
101
|
return;
|
|
103
|
-
const key =
|
|
104
|
-
if (
|
|
102
|
+
const key = this.serverKey(serverConfig);
|
|
103
|
+
if (this.disabledServers.has(key))
|
|
105
104
|
return;
|
|
106
105
|
const projectRoot = findProjectRoot(fullPath, _ctx.baseDir, serverConfig.workspaceMarkers ?? []);
|
|
107
106
|
try {
|
|
108
|
-
const diagnostics = await
|
|
109
|
-
|
|
107
|
+
const diagnostics = await this.client.checkFile(fullPath, _ctx.baseDir, serverConfig, projectRoot);
|
|
108
|
+
this.failuresByServer.set(key, 0);
|
|
110
109
|
const errors = diagnostics.filter((d) => d.severity === 1);
|
|
111
110
|
const warnings = diagnostics.filter((d) => d.severity === 2);
|
|
112
111
|
if (errors.length > 0) {
|
|
@@ -119,20 +118,22 @@ export class LspModule {
|
|
|
119
118
|
}
|
|
120
119
|
}
|
|
121
120
|
catch (e) {
|
|
122
|
-
//
|
|
123
|
-
//
|
|
124
|
-
//
|
|
121
|
+
// Падения — наружу, а не молчаливый []: мёртвый LSP раньше давал
|
|
122
|
+
// НОЛЬ диагностик целыми сессиями, и модель находила ошибки типов
|
|
123
|
+
// лишь реактивно через `bun run build`.
|
|
125
124
|
const msg = errMsg(e);
|
|
126
|
-
const failures = (
|
|
127
|
-
|
|
125
|
+
const failures = (this.failuresByServer.get(key) ?? 0) + 1;
|
|
126
|
+
this.failuresByServer.set(key, failures);
|
|
128
127
|
try {
|
|
129
128
|
_ctx.logger?.warn(`LSP check failed for ${filePath}: ${msg}`);
|
|
130
129
|
}
|
|
131
|
-
catch {
|
|
130
|
+
catch {
|
|
131
|
+
// Падающий логгер не должен ломать путь проверки.
|
|
132
|
+
}
|
|
132
133
|
if (failures >= MAX_CONSECUTIVE_LSP_FAILURES) {
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
|
|
134
|
+
// Одно громкое actionable-сообщение, дальше — без шума на каждую
|
|
135
|
+
// запись до конца сессии. Модель не должна учиться игнорить LSP.
|
|
136
|
+
this.disabledServers.add(key);
|
|
136
137
|
result.output += `\n\n[LSP disabled: ${t("lsp.unavailable")}]`;
|
|
137
138
|
}
|
|
138
139
|
else {
|
|
@@ -143,15 +144,14 @@ export class LspModule {
|
|
|
143
144
|
};
|
|
144
145
|
}
|
|
145
146
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
147
|
+
* Тул диагностики по требованию. Проверки LSP шли только после write/edit
|
|
148
|
+
* (плагин выше), и read-only задача «проверь проект на ошибки» получала
|
|
149
|
+
* НОЛЬ фидбэка от компилятора — модель сканировала файлы через read_file и
|
|
150
|
+
* не узнавала, компилируется ли код (наблюдалось: ses_msvuao0h — задача
|
|
151
|
+
* "проверь на ошибки" без build, без lsp, с декларацией успеха). `lsp_check`
|
|
152
|
+
* даёт модели способ спросить статические диагностики по требованию.
|
|
152
153
|
*/
|
|
153
154
|
getToolDefinitions() {
|
|
154
|
-
const self = this;
|
|
155
155
|
return [
|
|
156
156
|
{
|
|
157
157
|
name: "lsp_check",
|
|
@@ -171,7 +171,7 @@ export class LspModule {
|
|
|
171
171
|
},
|
|
172
172
|
required: ["path"],
|
|
173
173
|
},
|
|
174
|
-
handler: async (ctx, args) =>
|
|
174
|
+
handler: async (ctx, args) => this.runCheck(ctx, args),
|
|
175
175
|
},
|
|
176
176
|
];
|
|
177
177
|
}
|
|
@@ -240,7 +240,9 @@ export class LspModule {
|
|
|
240
240
|
try {
|
|
241
241
|
ctx.logger?.warn(`LSP check failed for ${file}: ${msg}`);
|
|
242
242
|
}
|
|
243
|
-
catch {
|
|
243
|
+
catch {
|
|
244
|
+
// Падающий логгер не должен ломать путь проверки.
|
|
245
|
+
}
|
|
244
246
|
if (failures >= MAX_CONSECUTIVE_LSP_FAILURES) {
|
|
245
247
|
this.disabledServers.add(key);
|
|
246
248
|
notes.push(`[LSP disabled: ${t("lsp.unavailable")}]`);
|
|
@@ -3,13 +3,12 @@ import { getServerKeyForFile } from "./config";
|
|
|
3
3
|
import { collectCheckFiles } from "./check-tool";
|
|
4
4
|
import { findProjectRoot } from "./project-root";
|
|
5
5
|
import { errMsg } from "../../utils";
|
|
6
|
-
|
|
7
|
-
const DEFAULT_PROBE_DEADLINE_MS = 60_000;
|
|
6
|
+
import { LSP_PROBE_TIMEOUT_MS as DEFAULT_PROBE_TIMEOUT_MS, LSP_PROBE_DEADLINE_MS as DEFAULT_PROBE_DEADLINE_MS, } from "../../config/timeouts";
|
|
8
7
|
const DEFAULT_MAX_PARALLEL = 3;
|
|
9
8
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* Выяснить, какие LSP-серверы применимы к проекту (тот же ограниченный обход,
|
|
10
|
+
* что в lsp_check), и пробить каждый: spawn + initialize + shutdown.
|
|
11
|
+
* Для баннера REPL — мёртвый сервер виден до первой записи.
|
|
13
12
|
*/
|
|
14
13
|
export async function probeLspServers(config, baseDir, deps = {}) {
|
|
15
14
|
if (!config.enabled)
|
|
@@ -33,15 +32,15 @@ export async function probeLspServers(config, baseDir, deps = {}) {
|
|
|
33
32
|
}
|
|
34
33
|
if (servers.length === 0)
|
|
35
34
|
return { ok: [], failed: [], noneApplicable: true };
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
// request timeout: initialize`
|
|
39
|
-
//
|
|
40
|
-
// `maxParallel`
|
|
41
|
-
//
|
|
42
|
-
// stateful —
|
|
43
|
-
//
|
|
44
|
-
//
|
|
35
|
+
// Проба ограниченными волнами. Параллельная проба всего на холодном
|
|
36
|
+
// npx-кеше заставляет серверы драться за общий лок кеша — наблюдалось как
|
|
37
|
+
// `LSP request timeout: initialize` у половины серверов. Чисто
|
|
38
|
+
// последовательная проба убирает драку, но удваивает ожидание баннера REPL
|
|
39
|
+
// (сервер ~2с). Волна `maxParallel` держит баннер быстрым на тёплом кеше и
|
|
40
|
+
// режет конкуренцию на холодном; у каждого сервера в волне свой LspClient
|
|
41
|
+
// (клиент stateful — процесс, id запросов, буфер ответов, — конкурентные
|
|
42
|
+
// пробы на общем инстансе кросс-токали бы). Инжектированный клиент (тесты)
|
|
43
|
+
// переиспользуется на все серверы.
|
|
45
44
|
const ok = [];
|
|
46
45
|
const failed = [];
|
|
47
46
|
const deadline = Date.now() + deadlineMs;
|