@herbertgao/pi-extensions 2026.9.2 → 2026.9.3
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/README.md +3 -2
- package/THIRD_PARTY_NOTICES.md +24 -0
- package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
- package/node_modules/@herbertgao/sol-pi/README.md +159 -0
- package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
- package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
- package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
- package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
- package/node_modules/@herbertgao/sol-pi/package.json +76 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
- package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts +12 -2
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +2 -2
- package/node_modules/@narumitw/pi-btw/package.json +1 -1
- package/node_modules/@narumitw/pi-btw/src/btw.ts +13 -2
- package/node_modules/pi-lens/CHANGELOG.md +176 -0
- package/node_modules/pi-lens/README.md +13 -8
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
- package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -1
- package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +2 -0
- package/node_modules/pi-lens/dist/clients/config-resolve.js +6 -3
- package/node_modules/pi-lens/dist/clients/config-schema.js +17 -0
- package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -15
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +4 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +12 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +4 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
- package/node_modules/pi-lens/dist/clients/extension-log.js +2 -0
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +54 -188
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
- package/node_modules/pi-lens/dist/clients/installer/index.js +196 -52
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +12 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/lens-config.js +4 -0
- package/node_modules/pi-lens/dist/clients/lsp/config.js +36 -7
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +78 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +281 -45
- package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
- package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
- package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +8 -3
- package/node_modules/pi-lens/dist/clients/pipeline.js +3 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +9 -0
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +13 -4
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
- package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
- package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
- package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
- package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
- package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
- package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
- package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
- package/node_modules/pi-lens/dist/index.js +21969 -20005
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
- package/node_modules/pi-lens/dist/mcp/server.js +135 -159
- package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
- package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
- package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +353 -85
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +21 -110
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
- package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
- package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
- package/node_modules/pi-lens/dist/tools/render-compact.js +280 -1
- package/node_modules/pi-lens/dist/tools/symbol-search.js +2 -2
- package/node_modules/pi-lens/docs/agent-guide.md +3 -4
- package/node_modules/pi-lens/docs/agent-tools.md +46 -22
- package/node_modules/pi-lens/docs/configuration.md +9 -0
- package/node_modules/pi-lens/docs/environment-variables.md +0 -5
- package/node_modules/pi-lens/docs/features.md +5 -5
- package/node_modules/pi-lens/docs/globalconfig.md +11 -1
- package/node_modules/pi-lens/docs/mcp.md +13 -1
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
- package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +35 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +12 -4
- package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
- package/node_modules/pi-lens/docs/real-harness.md +46 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +5 -1
- package/node_modules/pi-lens/docs/servercapabilities.md +1 -6
- package/node_modules/pi-lens/docs/settings.md +37 -2
- package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
- package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
- package/node_modules/pi-lens/docs/usage.md +13 -3
- package/node_modules/pi-lens/package.json +10 -1
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
- package/node_modules/pi-web-access/CHANGELOG.md +29 -0
- package/node_modules/pi-web-access/README.md +33 -22
- package/node_modules/pi-web-access/abortable.ts +17 -0
- package/node_modules/pi-web-access/crawl4ai.ts +204 -0
- package/node_modules/pi-web-access/credential-source.ts +1 -0
- package/node_modules/pi-web-access/curator-page.ts +20 -2
- package/node_modules/pi-web-access/curator-run.ts +44 -0
- package/node_modules/pi-web-access/curator-server.ts +3 -1
- package/node_modules/pi-web-access/duckduckgo.ts +1 -1
- package/node_modules/pi-web-access/extract.ts +57 -12
- package/node_modules/pi-web-access/fetch-params.ts +1 -1
- package/node_modules/pi-web-access/gemini-search.ts +9 -5
- package/node_modules/pi-web-access/index.ts +25 -18
- package/node_modules/pi-web-access/openai-search.ts +35 -13
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/page-query.ts +5 -2
- package/node_modules/pi-web-access/query-rewrite.ts +5 -2
- package/node_modules/pi-web-access/serpapi.ts +220 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
- package/node_modules/pi-web-access/storage.ts +10 -0
- package/node_modules/pi-web-access/summary-review.ts +34 -21
- package/node_modules/pi-web-access/utils.ts +6 -4
- package/package.json +7 -4
- package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
|
@@ -126,6 +126,7 @@ const lspRunner = {
|
|
|
126
126
|
// so this is tracked separately: the only claim it invalidates is "0
|
|
127
127
|
// diagnostics means clean".
|
|
128
128
|
let unconfirmedServerIds = [];
|
|
129
|
+
let deferredServerIds = [];
|
|
129
130
|
let usedWarmAttach = false;
|
|
130
131
|
let failureReason = "";
|
|
131
132
|
const content = readFileContent(ctx.filePath);
|
|
@@ -180,6 +181,7 @@ const lspRunner = {
|
|
|
180
181
|
lspDiags = touched.diags;
|
|
181
182
|
diagnosticsInconclusive = touched.inconclusive === true;
|
|
182
183
|
unconfirmedServerIds = touchCoverageGap(touched);
|
|
184
|
+
deferredServerIds = touched.deferredServerIds ?? [];
|
|
183
185
|
}
|
|
184
186
|
}
|
|
185
187
|
catch (err) {
|
|
@@ -237,6 +239,15 @@ const lspRunner = {
|
|
|
237
239
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
238
240
|
}
|
|
239
241
|
if (lspDiags.length === 0) {
|
|
242
|
+
if (deferredServerIds.length > 0) {
|
|
243
|
+
return {
|
|
244
|
+
status: "deferred",
|
|
245
|
+
diagnostics: [],
|
|
246
|
+
semantic: "none",
|
|
247
|
+
unconfirmedServerIds: [...unconfirmedServerIds],
|
|
248
|
+
deferredServerIds: [...deferredServerIds],
|
|
249
|
+
};
|
|
250
|
+
}
|
|
240
251
|
if (unconfirmedServerIds.length > 0) {
|
|
241
252
|
// #1470/#1493: an auxiliary never reported — cut off by the aux grace
|
|
242
253
|
// timer, or silent with nothing published for this content — so this
|
|
@@ -345,7 +356,11 @@ const lspRunner = {
|
|
|
345
356
|
? "warning"
|
|
346
357
|
: "none";
|
|
347
358
|
return {
|
|
348
|
-
status: hasErrors
|
|
359
|
+
status: hasErrors
|
|
360
|
+
? "failed"
|
|
361
|
+
: deferredServerIds.length > 0
|
|
362
|
+
? "deferred"
|
|
363
|
+
: "succeeded",
|
|
349
364
|
// "failed" here means the file has blocking type errors — the check ran
|
|
350
365
|
// fine. Tag it so the smell analyzer doesn't read it as a runner crash.
|
|
351
366
|
failureKind: hasErrors ? "blocking_diagnostics" : undefined,
|
|
@@ -354,6 +369,9 @@ const lspRunner = {
|
|
|
354
369
|
...(unconfirmedServerIds.length > 0 && {
|
|
355
370
|
unconfirmedServerIds: [...unconfirmedServerIds],
|
|
356
371
|
}),
|
|
372
|
+
...(deferredServerIds.length > 0 && {
|
|
373
|
+
deferredServerIds: [...deferredServerIds],
|
|
374
|
+
}),
|
|
357
375
|
};
|
|
358
376
|
},
|
|
359
377
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
2
|
+
import { logRunnerAdvisoryOnce, resolveRunnerCwd } from "../../tool-cwd.js";
|
|
2
3
|
import { getLinterPolicyForCwd, markdownlintConfigArgs, } from "../../tool-policy.js";
|
|
3
4
|
import { PRIORITY } from "../priorities.js";
|
|
4
5
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
@@ -96,7 +97,7 @@ const markdownlintRunner = {
|
|
|
96
97
|
priority: PRIORITY.DOC_QUALITY,
|
|
97
98
|
skipTestFiles: false,
|
|
98
99
|
async run(ctx) {
|
|
99
|
-
const cwd = ctx
|
|
100
|
+
const cwd = resolveRunnerCwd(ctx, "markdownlint");
|
|
100
101
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
101
102
|
if (policy && !policy.preferredRunners.includes("markdownlint")) {
|
|
102
103
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -114,7 +115,7 @@ const markdownlintRunner = {
|
|
|
114
115
|
// its budget in another lane (availability verify, autofix --fix). Skip
|
|
115
116
|
// without spawning — "not checked", never re-reported as clean.
|
|
116
117
|
if (isInSpawnTimeoutCooldown(cmd)) {
|
|
117
|
-
ctx
|
|
118
|
+
logRunnerAdvisoryOnce(ctx, "markdownlint", cwd, `markdownlint: ${cmd} is cooling down after a spawn timeout — skipping (one bounded failure budget per edit)`);
|
|
118
119
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
119
120
|
}
|
|
120
121
|
// Shared config-args seam (#1247): the autofix path consumes the same
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
3
4
|
import { hasMypyConfig } from "../../tool-policy.js";
|
|
4
5
|
import { PRIORITY } from "../priorities.js";
|
|
5
6
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
@@ -61,7 +62,7 @@ const mypyRunner = {
|
|
|
61
62
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
62
63
|
skipTestFiles: false,
|
|
63
64
|
async run(ctx) {
|
|
64
|
-
const cwd = ctx
|
|
65
|
+
const cwd = resolveRunnerCwd(ctx, "mypy");
|
|
65
66
|
// Only run if mypy config exists — avoids false positives in untyped projects
|
|
66
67
|
if (!hasMypyConfig(cwd)) {
|
|
67
68
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { findLocalBinUpwards } from "../../package-manager.js";
|
|
10
10
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
11
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
11
12
|
import { truncatedByOutputCap } from "../../spawn-output-cap.js";
|
|
12
13
|
import { getJstsLintPolicyForCwd, hasVitePlusConfig, } from "../../tool-policy.js";
|
|
13
14
|
import { PRIORITY } from "../priorities.js";
|
|
@@ -58,7 +59,7 @@ const oxlintRunner = {
|
|
|
58
59
|
priority: PRIORITY.LINT_SECONDARY,
|
|
59
60
|
skipTestFiles: false,
|
|
60
61
|
async run(ctx) {
|
|
61
|
-
const cwd = ctx
|
|
62
|
+
const cwd = resolveRunnerCwd(ctx, "oxlint");
|
|
62
63
|
const policy = getJstsLintPolicyForCwd(cwd);
|
|
63
64
|
if (!policy.preferredRunners.includes("oxlint")) {
|
|
64
65
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
3
4
|
import { PRIORITY } from "../priorities.js";
|
|
4
5
|
import { createAvailabilityChecker } from "./utils/runner-helpers.js";
|
|
5
6
|
const php = createAvailabilityChecker("php", ".exe");
|
|
@@ -31,7 +32,7 @@ const phpLintRunner = {
|
|
|
31
32
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
32
33
|
skipTestFiles: false,
|
|
33
34
|
async run(ctx) {
|
|
34
|
-
const cwd = ctx
|
|
35
|
+
const cwd = resolveRunnerCwd(ctx, "php-lint");
|
|
35
36
|
if (!(await php.isAvailableAsync(cwd))) {
|
|
36
37
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
37
38
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
3
4
|
import { getLinterPolicyForCwd, hasPhpstanConfig } from "../../tool-policy.js";
|
|
4
5
|
import { PRIORITY } from "../priorities.js";
|
|
5
6
|
import { createAvailabilityChecker, resolveVendorToolCommand, } from "./utils/runner-helpers.js";
|
|
@@ -84,7 +85,7 @@ const phpstanRunner = {
|
|
|
84
85
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
85
86
|
skipTestFiles: false,
|
|
86
87
|
async run(ctx) {
|
|
87
|
-
const cwd = ctx
|
|
88
|
+
const cwd = resolveRunnerCwd(ctx, "phpstan");
|
|
88
89
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
89
90
|
if (policy && !policy.preferredRunners.includes("phpstan")) {
|
|
90
91
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
3
4
|
import { PRIORITY } from "../priorities.js";
|
|
4
5
|
import { resolveLocalFirstAsync } from "./utils/runner-helpers.js";
|
|
5
6
|
function parsePrismaValidateOutput(raw, filePath) {
|
|
@@ -37,7 +38,7 @@ const prismaValidateRunner = {
|
|
|
37
38
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
38
39
|
skipTestFiles: false,
|
|
39
40
|
async run(ctx) {
|
|
40
|
-
const cwd = ctx
|
|
41
|
+
const cwd = resolveRunnerCwd(ctx, "prisma-validate");
|
|
41
42
|
const resolved = await resolveLocalFirstAsync("prisma", cwd);
|
|
42
43
|
const absPath = path.resolve(cwd, ctx.filePath);
|
|
43
44
|
const result = await safeSpawnAsync(resolved.cmd, [...resolved.args, "validate", "--schema", absPath], { timeout: 20000, cwd });
|
|
@@ -3,6 +3,8 @@ import * as os from "node:os";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { incrementDegradationCount } from "../../degradation-ledger.js";
|
|
5
5
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
6
|
+
import { probeToolAsync } from "../../tool-probe.js";
|
|
7
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
6
8
|
import { PRIORITY } from "../priorities.js";
|
|
7
9
|
import { classifyProbeFailure, createAvailabilityLatch, isLatchingOutcome, logAvailabilityDecision, startHostStallSampler, } from "./utils/availability-policy.js";
|
|
8
10
|
// The PS script written to a temp file each run. `-File` with a temp script
|
|
@@ -25,8 +27,13 @@ const PS_TIMEOUT_MS = 30000;
|
|
|
25
27
|
* available". `safeSpawnAsync` carries the standard taxonomy — `failure`,
|
|
26
28
|
* `spawnFailure.kind` and the errno on `error` — which is what lets the
|
|
27
29
|
* availability policy tell a stall from an absence.
|
|
30
|
+
*
|
|
31
|
+
* The two presence probes that used to share this wrapper now go through
|
|
32
|
+
* `probeToolAsync` (#2894), so the only spawn left here is the ANALYSIS pass
|
|
33
|
+
* — which always has a project to resolve `PSScriptAnalyzerSettings.psd1`
|
|
34
|
+
* against. `cwd` is required to keep it that way.
|
|
28
35
|
*/
|
|
29
|
-
function spawnPs(cmd, args, options
|
|
36
|
+
function spawnPs(cmd, args, options) {
|
|
30
37
|
const { timeoutMs = PS_TIMEOUT_MS, cwd } = options;
|
|
31
38
|
return safeSpawnAsync(cmd, args, {
|
|
32
39
|
cwd,
|
|
@@ -126,13 +133,7 @@ async function resolvePowerShellCmd() {
|
|
|
126
133
|
for (const candidate of ["pwsh", "powershell"]) {
|
|
127
134
|
const sampler = startHostStallSampler();
|
|
128
135
|
const startedAt = Date.now();
|
|
129
|
-
|
|
130
|
-
const result = await spawnPs(candidate, [
|
|
131
|
-
"-NoProfile",
|
|
132
|
-
"-NonInteractive",
|
|
133
|
-
"-Command",
|
|
134
|
-
"exit 0",
|
|
135
|
-
]);
|
|
136
|
+
const result = await probeToolAsync(candidate, ["-NoProfile", "-NonInteractive", "-Command", "exit 0"], { timeout: PS_TIMEOUT_MS, resourceLabel: "psscriptanalyzer" });
|
|
136
137
|
const hostStallMs = sampler.stop();
|
|
137
138
|
const elapsedMs = Date.now() - startedAt;
|
|
138
139
|
elapsedTotalMs += elapsedMs;
|
|
@@ -178,13 +179,12 @@ async function checkModuleAvailable(cmd) {
|
|
|
178
179
|
return memo;
|
|
179
180
|
const sampler = startHostStallSampler();
|
|
180
181
|
const startedAt = Date.now();
|
|
181
|
-
|
|
182
|
-
const result = await spawnPs(cmd, [
|
|
182
|
+
const result = await probeToolAsync(cmd, [
|
|
183
183
|
"-NoProfile",
|
|
184
184
|
"-NonInteractive",
|
|
185
185
|
"-Command",
|
|
186
186
|
"if (Get-Module -ListAvailable PSScriptAnalyzer) { exit 0 } else { exit 1 }",
|
|
187
|
-
]);
|
|
187
|
+
], { timeout: PS_TIMEOUT_MS, resourceLabel: "psscriptanalyzer" });
|
|
188
188
|
const hostStallMs = sampler.stop();
|
|
189
189
|
const elapsedMs = Date.now() - startedAt;
|
|
190
190
|
if (!result.error && result.status === 0) {
|
|
@@ -292,7 +292,7 @@ const psScriptAnalyzerRunner = {
|
|
|
292
292
|
if (execLatch.read() === false) {
|
|
293
293
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
294
294
|
}
|
|
295
|
-
const cwd = ctx
|
|
295
|
+
const cwd = resolveRunnerCwd(ctx, "psscriptanalyzer");
|
|
296
296
|
const absPath = path.resolve(cwd, ctx.filePath);
|
|
297
297
|
// Write script to temp file so we avoid cmd.exe quoting entirely
|
|
298
298
|
const tmpScript = path.join(os.tmpdir(), `pi-lens-psa-${process.pid}.ps1`);
|
|
@@ -10,6 +10,7 @@ import { logExtension } from "../../extension-log.js";
|
|
|
10
10
|
import { getLSPService } from "../../lsp/index.js";
|
|
11
11
|
import { augmentPythonEnvironment, detectPythonEnvironment, } from "../../python-environment.js";
|
|
12
12
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
13
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
13
14
|
import { PRIORITY } from "../priorities.js";
|
|
14
15
|
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
15
16
|
import { finishParsedRun } from "./utils/tool-failure.js";
|
|
@@ -28,7 +29,7 @@ const pyrightRunner = {
|
|
|
28
29
|
const lspService = getLSPService();
|
|
29
30
|
await lspService.getClientForFile(ctx.filePath);
|
|
30
31
|
}
|
|
31
|
-
const cwd = ctx
|
|
32
|
+
const cwd = resolveRunnerCwd(ctx, "pyright");
|
|
32
33
|
// Get pyright command - try multiple strategies
|
|
33
34
|
let cmd = null;
|
|
34
35
|
// Strategy 1: Check cached availability (fast path)
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* Supports bundle exec (preferred in Bundler projects).
|
|
9
9
|
*/
|
|
10
10
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
11
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
11
12
|
import { getAutofixCapability, getLinterPolicyForCwd, getRubocopCommand, } from "../../tool-policy.js";
|
|
12
13
|
import { PRIORITY } from "../priorities.js";
|
|
13
14
|
import { resolveCommandArgsWithInstallFallback } from "./utils/runner-helpers.js";
|
|
@@ -55,7 +56,7 @@ const rubocopRunner = {
|
|
|
55
56
|
appliesTo: ["ruby"],
|
|
56
57
|
priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
|
|
57
58
|
async run(ctx) {
|
|
58
|
-
const cwd = ctx
|
|
59
|
+
const cwd = resolveRunnerCwd(ctx, "rubocop");
|
|
59
60
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
60
61
|
if (policy && !policy.preferredRunners.includes("rubocop")) {
|
|
61
62
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -11,7 +11,7 @@ import { stripAnsi } from "../../sanitize.js";
|
|
|
11
11
|
import { getAutofixCapability, getLinterPolicyForCwd, ruffConfigArgs, } from "../../tool-policy.js";
|
|
12
12
|
import { PRIORITY } from "../priorities.js";
|
|
13
13
|
import { parseRuffOutput } from "./utils/diagnostic-parsers.js";
|
|
14
|
-
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
14
|
+
import { createAvailabilityChecker, resolveAvailableOrInstall, resolveRunnerCwd, } from "./utils/runner-helpers.js";
|
|
15
15
|
const ruff = createAvailabilityChecker("ruff", ".exe");
|
|
16
16
|
function parseRuffJson(raw, filePath) {
|
|
17
17
|
try {
|
|
@@ -50,7 +50,7 @@ const ruffRunner = {
|
|
|
50
50
|
appliesTo: ["python"],
|
|
51
51
|
priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
|
|
52
52
|
async run(ctx) {
|
|
53
|
-
const cwd = ctx
|
|
53
|
+
const cwd = resolveRunnerCwd(ctx, "ruff");
|
|
54
54
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
55
55
|
if (policy && !policy.preferredRunners.includes("ruff-lint")) {
|
|
56
56
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -3,14 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Runs `cargo clippy` for Rust files to catch common mistakes.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
8
8
|
import { rustClient } from "../../rust-client.js";
|
|
9
9
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
10
10
|
import { stripAnsi } from "../../sanitize.js";
|
|
11
11
|
import { getLazyInstallAttempt, tryLazyInstall, } from "./utils/lazy-installer.js";
|
|
12
12
|
import { describeInstallAttempt, logAvailabilityDecision, } from "./utils/availability-policy.js";
|
|
13
13
|
import { PRIORITY } from "../priorities.js";
|
|
14
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
14
15
|
import { createCwdCachedProbe } from "./utils/runner-helpers.js";
|
|
15
16
|
// Cached per-cwd `cargo clippy --version` probe (#120). Before this, the
|
|
16
17
|
// probe fired on every Rust file save in a project where clippy was already
|
|
@@ -89,15 +90,20 @@ const rustClippyRunner = {
|
|
|
89
90
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
// The package root (where Cargo.toml is), through the shared cwd seam
|
|
94
|
+
// (#2894): `RUNNER_MARKERS["rust-clippy"]` is `["Cargo.toml"]`, so this
|
|
95
|
+
// IS the walk this runner used to do with `findNearestContaining` — plus
|
|
96
|
+
// the seam's dispatch-root and `$HOME` ceilings, which the hand-rolled
|
|
97
|
+
// walk had neither of. The gate then asks about exactly the directory
|
|
98
|
+
// cargo will run in, rather than about a separately-derived one.
|
|
99
|
+
const cargoDir = resolveRunnerCwd(ctx, "rust-clippy");
|
|
100
|
+
if (!existsSync(join(cargoDir, "Cargo.toml"))) {
|
|
95
101
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
96
102
|
}
|
|
97
103
|
// Run cargo clippy on the package
|
|
98
104
|
const result = await safeSpawnAsync(cargoExe, ["clippy", "--message-format=json", "-q"], {
|
|
99
105
|
timeout: 60000,
|
|
100
|
-
cwd:
|
|
106
|
+
cwd: cargoDir,
|
|
101
107
|
});
|
|
102
108
|
const raw = stripAnsi(result.stdout + result.stderr);
|
|
103
109
|
if (result.status === 0 && !raw.trim()) {
|
|
@@ -105,7 +111,6 @@ const rustClippyRunner = {
|
|
|
105
111
|
}
|
|
106
112
|
// Parse JSON output. span.file is relative to the package root, so pass
|
|
107
113
|
// the cargo dir to resolve diagnostics to absolute paths for filtering.
|
|
108
|
-
const cargoDir = cargoToml.replace("Cargo.toml", "");
|
|
109
114
|
const allDiagnostics = parseClippyOutput(raw, ctx.filePath, cargoDir);
|
|
110
115
|
if (allDiagnostics.length === 0) {
|
|
111
116
|
// Non-parseable output
|
|
@@ -134,10 +139,6 @@ const rustClippyRunner = {
|
|
|
134
139
|
};
|
|
135
140
|
},
|
|
136
141
|
};
|
|
137
|
-
function findCargoToml(filePath) {
|
|
138
|
-
const dir = findNearestContaining(dirname(filePath), ["Cargo.toml"]);
|
|
139
|
-
return dir ? join(dir, "Cargo.toml") : undefined;
|
|
140
|
-
}
|
|
141
142
|
/**
|
|
142
143
|
* #1802 fix round: the original review claimed rustc/clippy's top-level
|
|
143
144
|
* `compiler-message.level` is genuinely two-valued (error/warning). A live
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
import * as fs from "node:fs";
|
|
23
23
|
import * as path from "node:path";
|
|
24
24
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
25
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
25
26
|
import { PRIORITY } from "../priorities.js";
|
|
26
27
|
import { createAvailabilityChecker, lspPrimaryCoversFile, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
27
28
|
import { finishParsedRun } from "./utils/tool-failure.js";
|
|
@@ -110,7 +111,7 @@ const shellcheckRunner = {
|
|
|
110
111
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
111
112
|
skipTestFiles: false, // Shell scripts in test directories should still be checked
|
|
112
113
|
async run(ctx) {
|
|
113
|
-
const cwd = ctx
|
|
114
|
+
const cwd = resolveRunnerCwd(ctx, "shellcheck");
|
|
114
115
|
// #233: bash-language-server runs shellcheck internally. When the `bash` LSP
|
|
115
116
|
// covers this file AND shellcheck is on PATH (so the LSP actually emits its
|
|
116
117
|
// findings), the warm server already produces these diagnostics — skip the
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
4
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
4
5
|
import { PRIORITY } from "../priorities.js";
|
|
5
6
|
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
6
7
|
const shfmt = createAvailabilityChecker("shfmt", ".exe");
|
|
@@ -31,7 +32,7 @@ const shfmtRunner = {
|
|
|
31
32
|
priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
|
|
32
33
|
skipTestFiles: false,
|
|
33
34
|
async run(ctx) {
|
|
34
|
-
const cwd = ctx
|
|
35
|
+
const cwd = resolveRunnerCwd(ctx, "shfmt");
|
|
35
36
|
let cmd = null;
|
|
36
37
|
if (await shfmt.isAvailableAsync(cwd)) {
|
|
37
38
|
cmd = shfmt.getCommand(cwd);
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
22
22
|
import { PRIORITY } from "../priorities.js";
|
|
23
|
-
import { createAvailabilityChecker } from "./utils/runner-helpers.js";
|
|
23
|
+
import { createAvailabilityChecker, resolveRunnerCwd, } from "./utils/runner-helpers.js";
|
|
24
24
|
import { parseToolRun } from "./utils/tool-failure.js";
|
|
25
25
|
const typos = createAvailabilityChecker("typos", ".exe");
|
|
26
26
|
// typos-cli exit codes: 0 = no typos, 2 = typos found, 1 = an error that
|
|
@@ -82,7 +82,7 @@ const spellcheckRunner = {
|
|
|
82
82
|
priority: PRIORITY.DOC_QUALITY,
|
|
83
83
|
skipTestFiles: false, // Check docs in test files too
|
|
84
84
|
async run(ctx) {
|
|
85
|
-
const cwd = ctx
|
|
85
|
+
const cwd = resolveRunnerCwd(ctx, "spellcheck/typos");
|
|
86
86
|
// Skip if typos-cli is not installed
|
|
87
87
|
if (!(await typos.isAvailableAsync(cwd))) {
|
|
88
88
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -3,6 +3,7 @@ import * as os from "node:os";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { BoundedLruCache } from "../../bounded-cache.js";
|
|
5
5
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
6
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
6
7
|
import { findCompiledClassesDir } from "../../tool-policy.js";
|
|
7
8
|
import { PRIORITY } from "../priorities.js";
|
|
8
9
|
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
@@ -191,7 +192,7 @@ const spotbugsRunner = {
|
|
|
191
192
|
appliesTo: ["java", "kotlin"],
|
|
192
193
|
priority: PRIORITY.DEEP_LANGUAGE_ANALYSIS,
|
|
193
194
|
async run(ctx) {
|
|
194
|
-
const cwd = ctx
|
|
195
|
+
const cwd = resolveRunnerCwd(ctx, "spotbugs");
|
|
195
196
|
const classesDir = findCompiledClassesDir(cwd);
|
|
196
197
|
if (!classesDir) {
|
|
197
198
|
ctx.log?.("spotbugs: Java project detected but no compiled .class files found — run `mvn compile` / `gradle build` first");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
2
|
+
import { logRunnerAdvisoryOnce, resolveRunnerCwd } from "../../tool-cwd.js";
|
|
2
3
|
import { getLinterPolicyForCwd, hasSqlfluffConfig } from "../../tool-policy.js";
|
|
3
4
|
import { PRIORITY } from "../priorities.js";
|
|
4
5
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
@@ -117,14 +118,14 @@ const sqlfluffRunner = {
|
|
|
117
118
|
priority: PRIORITY.SQL_LINT,
|
|
118
119
|
skipTestFiles: false,
|
|
119
120
|
async run(ctx) {
|
|
120
|
-
const cwd = ctx
|
|
121
|
+
const cwd = resolveRunnerCwd(ctx, "sqlfluff");
|
|
121
122
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
122
123
|
if (policy && !policy.preferredRunners.includes("sqlfluff")) {
|
|
123
124
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
124
125
|
}
|
|
125
126
|
const hasConfig = hasSqlfluffConfig(cwd);
|
|
126
127
|
if (!hasConfig) {
|
|
127
|
-
ctx
|
|
128
|
+
logRunnerAdvisoryOnce(ctx, "sqlfluff", cwd, "sqlfluff: no config detected, using ANSI dialect defaults");
|
|
128
129
|
}
|
|
129
130
|
let cmd = null;
|
|
130
131
|
if (await sqlfluff.isAvailableAsync(cwd)) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
|
+
import { logRunnerAdvisoryOnce, resolveRunnerCwd } from "../../tool-cwd.js";
|
|
3
4
|
import { getLinterPolicyForCwd, hasStylelintConfig, } from "../../tool-policy.js";
|
|
4
5
|
import { PRIORITY } from "../priorities.js";
|
|
5
6
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
@@ -116,7 +117,7 @@ const stylelintRunner = {
|
|
|
116
117
|
priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
|
|
117
118
|
skipTestFiles: false,
|
|
118
119
|
async run(ctx) {
|
|
119
|
-
const cwd = ctx
|
|
120
|
+
const cwd = resolveRunnerCwd(ctx, "stylelint");
|
|
120
121
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
121
122
|
if (policy && !policy.preferredRunners.includes("stylelint")) {
|
|
122
123
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -124,7 +125,7 @@ const stylelintRunner = {
|
|
|
124
125
|
const fileDir = path.dirname(path.resolve(cwd, ctx.filePath));
|
|
125
126
|
const hasConfig = hasStylelintConfig(fileDir) || hasStylelintConfig(cwd);
|
|
126
127
|
if (!hasConfig) {
|
|
127
|
-
ctx
|
|
128
|
+
logRunnerAdvisoryOnce(ctx, "stylelint", cwd, "stylelint: no config detected, running with default rules");
|
|
128
129
|
}
|
|
129
130
|
let cmd = null;
|
|
130
131
|
if (await stylelint.isAvailableAsync(cwd)) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
3
4
|
import { PRIORITY } from "../priorities.js";
|
|
4
5
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
5
6
|
import { parseToolRun } from "./utils/tool-failure.js";
|
|
@@ -115,7 +116,7 @@ const swiftlintRunner = {
|
|
|
115
116
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
116
117
|
skipTestFiles: false,
|
|
117
118
|
async run(ctx) {
|
|
118
|
-
const cwd = ctx
|
|
119
|
+
const cwd = resolveRunnerCwd(ctx, "swiftlint");
|
|
119
120
|
let cmd = null;
|
|
120
121
|
if (await swiftlint.isAvailableAsync(cwd)) {
|
|
121
122
|
cmd = swiftlint.getCommand(cwd);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { findLocalBinUpwards } from "../../package-manager.js";
|
|
3
3
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
4
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
4
5
|
import { getLinterPolicyForCwd } from "../../tool-policy.js";
|
|
5
6
|
import { PRIORITY } from "../priorities.js";
|
|
6
7
|
import { createAvailabilityChecker, lspPrimaryCoversFile, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
@@ -106,7 +107,7 @@ const taploRunner = {
|
|
|
106
107
|
priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
|
|
107
108
|
skipTestFiles: false,
|
|
108
109
|
async run(ctx) {
|
|
109
|
-
const cwd = ctx
|
|
110
|
+
const cwd = resolveRunnerCwd(ctx, "taplo");
|
|
110
111
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
111
112
|
if (policy && !policy.preferredRunners.includes("taplo")) {
|
|
112
113
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
3
4
|
import { pathsEqual } from "../../path-utils.js";
|
|
4
5
|
import { getLinterPolicyForCwd } from "../../tool-policy.js";
|
|
5
6
|
import { PRIORITY } from "../priorities.js";
|
|
@@ -128,7 +129,7 @@ const terragruntRunner = {
|
|
|
128
129
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
129
130
|
skipTestFiles: false,
|
|
130
131
|
async run(ctx) {
|
|
131
|
-
const cwd = ctx
|
|
132
|
+
const cwd = resolveRunnerCwd(ctx, "terragrunt");
|
|
132
133
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
133
134
|
if (policy && !policy.preferredRunners.includes("terragrunt"))
|
|
134
135
|
return SKIPPED;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
3
4
|
import { getLinterPolicyForCwd } from "../../tool-policy.js";
|
|
4
5
|
import { findNearestDirWithAnyBasename } from "../../workspace-topology.js";
|
|
5
6
|
import { PRIORITY } from "../priorities.js";
|
|
@@ -52,7 +53,7 @@ const tflintRunner = {
|
|
|
52
53
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
53
54
|
skipTestFiles: false,
|
|
54
55
|
async run(ctx) {
|
|
55
|
-
const cwd = ctx
|
|
56
|
+
const cwd = resolveRunnerCwd(ctx, "tflint");
|
|
56
57
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
57
58
|
if (policy && !policy.preferredRunners.includes("tflint")) {
|
|
58
59
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -40,6 +40,7 @@ import * as fs from "node:fs";
|
|
|
40
40
|
import * as path from "node:path";
|
|
41
41
|
import { incrementDegradationCount } from "../../degradation-ledger.js";
|
|
42
42
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
43
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
43
44
|
import { isTrivyEnabled, resolveSeverityFloor, } from "../../trivy-client.js";
|
|
44
45
|
import { PRIORITY } from "../priorities.js";
|
|
45
46
|
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
@@ -148,7 +149,7 @@ const trivyConfigRunner = {
|
|
|
148
149
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
149
150
|
skipTestFiles: false,
|
|
150
151
|
async run(ctx) {
|
|
151
|
-
const cwd = ctx
|
|
152
|
+
const cwd = resolveRunnerCwd(ctx, "trivy-config");
|
|
152
153
|
// Single opt-in switch — trivy is opt-in across all modes.
|
|
153
154
|
if (!isTrivyEnabled(cwd)) {
|
|
154
155
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -75,6 +75,11 @@ export function describeInstallAttempt(attempt, options = {}) {
|
|
|
75
75
|
return { install: "succeeded", ...(reason && { installReason: reason }) };
|
|
76
76
|
case "failed":
|
|
77
77
|
return { install: "failed", ...(reason && { installReason: reason }) };
|
|
78
|
+
case "unavailable":
|
|
79
|
+
return {
|
|
80
|
+
install: "unavailable",
|
|
81
|
+
...(reason && { installReason: reason }),
|
|
82
|
+
};
|
|
78
83
|
default:
|
|
79
84
|
return {
|
|
80
85
|
install: "not-attempted",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* Complexity limit. This is that sweep, written once.
|
|
12
12
|
*/
|
|
13
13
|
import * as fs from "node:fs";
|
|
14
|
-
import {
|
|
14
|
+
import { probeToolAsync } from "../../../tool-probe.js";
|
|
15
15
|
import { classifyProbeFailure, startHostStallSampler, } from "./availability-policy.js";
|
|
16
16
|
/**
|
|
17
17
|
* Walk `candidates` in order. A candidate containing a path separator is
|
|
@@ -45,7 +45,7 @@ export async function probeAvailabilityCandidates(candidates, probeArgs, timeout
|
|
|
45
45
|
let result;
|
|
46
46
|
let stallMs;
|
|
47
47
|
try {
|
|
48
|
-
result = await
|
|
48
|
+
result = await probeToolAsync(candidate, probeArgs, {
|
|
49
49
|
timeout: timeoutMs,
|
|
50
50
|
});
|
|
51
51
|
}
|
|
@@ -20,9 +20,11 @@ import { getServersForFileWithConfig, isServerDisabled, } from "../../../lsp/con
|
|
|
20
20
|
import { findGlobalBinary, findLocalBinAt, findLocalBinsUpwards, findLocalBinUpwards, VENDOR_BIN_DIRS, VENV_BIN_DIRS, } from "../../../package-manager.js";
|
|
21
21
|
import { logLatency } from "../../../latency-logger.js";
|
|
22
22
|
import { safeSpawnAsync } from "../../../safe-spawn.js";
|
|
23
|
+
import { probeToolAsync } from "../../../tool-probe.js";
|
|
23
24
|
import { compareOrdinal } from "../../../string-utils.js";
|
|
24
25
|
import { getToolCommandSpec, shouldAutoInstallTool, } from "../../../tool-policy.js";
|
|
25
26
|
import { isInSpawnTimeoutCooldown } from "../../../spawn-timeout-cooldown.js";
|
|
27
|
+
import { resolveToolCwd } from "../../../tool-cwd.js";
|
|
26
28
|
import { createAvailabilityProbeFlight } from "../../../availability-probe-flight.js";
|
|
27
29
|
import { classifyProbeFailure, createAvailabilityLatch, describeInstallAttempt, describeProbeEvidence, isLatchingOutcome, logAvailabilityDecision, startHostStallSampler, transientRetryDelayMs, } from "./availability-policy.js";
|
|
28
30
|
export { createAvailabilityLatch, classifyProbeFailure, describeProbeEvidence, describeUnavailability, isTransientDecision, logAvailabilityDecision, startHostStallSampler, } from "./availability-policy.js";
|
|
@@ -1390,7 +1392,7 @@ async function probeAstGrepCommandAsync(cmd, argsPrefix = []) {
|
|
|
1390
1392
|
let check;
|
|
1391
1393
|
let hostStallMs;
|
|
1392
1394
|
try {
|
|
1393
|
-
check = await
|
|
1395
|
+
check = await probeToolAsync(cmd, [...argsPrefix, "--version"], {
|
|
1394
1396
|
timeout: 5000,
|
|
1395
1397
|
});
|
|
1396
1398
|
}
|
|
@@ -1674,7 +1676,7 @@ export async function resolveLocalFirstAsync(toolName, cwd, windowsExt = ".cmd")
|
|
|
1674
1676
|
if (globalBin)
|
|
1675
1677
|
return { cmd: globalBin, args: [] };
|
|
1676
1678
|
// 3. Global PATH (already installed system-wide, on PATH)
|
|
1677
|
-
const globalCheck = await
|
|
1679
|
+
const globalCheck = await probeToolAsync(toolName, ["--version"], {
|
|
1678
1680
|
timeout: 3000,
|
|
1679
1681
|
});
|
|
1680
1682
|
if (!globalCheck.error && globalCheck.status === 0) {
|
|
@@ -1693,3 +1695,7 @@ export const sg = {
|
|
|
1693
1695
|
isAvailableAsync: isSgAvailableAsync,
|
|
1694
1696
|
getCommand: getSgCommand,
|
|
1695
1697
|
};
|
|
1698
|
+
/** Shared cwd seam for runner probes and analysis children (#2777). */
|
|
1699
|
+
export function resolveRunnerCwd(ctx, tool) {
|
|
1700
|
+
return resolveToolCwd("runner", tool, ctx.filePath, ctx);
|
|
1701
|
+
}
|