@herbertgao/pi-extensions 2026.9.2 → 2026.9.4
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 +4 -2
- package/THIRD_PARTY_NOTICES.md +49 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +3 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +16 -11
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +20 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +12 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +98 -0
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- 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-antigravity/LICENSE +21 -0
- package/node_modules/pi-antigravity/README.md +194 -0
- package/node_modules/pi-antigravity/package.json +67 -0
- package/node_modules/pi-antigravity/src/auth/index.ts +14 -0
- package/node_modules/pi-antigravity/src/auth/oauth.ts +442 -0
- package/node_modules/pi-antigravity/src/client/client.ts +561 -0
- package/node_modules/pi-antigravity/src/client/index.ts +1 -0
- package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +96 -0
- package/node_modules/pi-antigravity/src/diagnostics/index.ts +1 -0
- package/node_modules/pi-antigravity/src/image/image.ts +336 -0
- package/node_modules/pi-antigravity/src/image/index.ts +1 -0
- package/node_modules/pi-antigravity/src/index.ts +280 -0
- package/node_modules/pi-antigravity/src/models/discovery.ts +154 -0
- package/node_modules/pi-antigravity/src/models/grouping.ts +424 -0
- package/node_modules/pi-antigravity/src/models/index.ts +3 -0
- package/node_modules/pi-antigravity/src/models/models.ts +500 -0
- package/node_modules/pi-antigravity/src/stream/index.ts +1 -0
- package/node_modules/pi-antigravity/src/stream/stream.ts +1460 -0
- package/node_modules/pi-antigravity/src/types/enums.ts +42 -0
- package/node_modules/pi-antigravity/src/types/index.ts +2 -0
- package/node_modules/pi-antigravity/src/types/types.ts +292 -0
- package/node_modules/pi-antigravity/src/usage/index.ts +1 -0
- package/node_modules/pi-antigravity/src/usage/usage.ts +371 -0
- package/node_modules/pi-antigravity/src/utils/http.ts +91 -0
- package/node_modules/pi-antigravity/src/utils/index.ts +3 -0
- package/node_modules/pi-antigravity/src/utils/security.ts +73 -0
- package/node_modules/pi-antigravity/src/utils/util.ts +132 -0
- package/node_modules/pi-antigravity/tsconfig.json +21 -0
- 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 +11 -5
- package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
|
@@ -2,6 +2,7 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { getProjectDataDir } from "../../file-utils.js";
|
|
4
4
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
5
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
5
6
|
import { PRIORITY } from "../priorities.js";
|
|
6
7
|
import { createAvailabilityChecker } from "./utils/runner-helpers.js";
|
|
7
8
|
// Per-cwd cached `--version` probes (#120). Before this, each dispatch
|
|
@@ -141,7 +142,7 @@ const elixirCheckRunner = {
|
|
|
141
142
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
142
143
|
skipTestFiles: false,
|
|
143
144
|
async run(ctx) {
|
|
144
|
-
const cwd = ctx
|
|
145
|
+
const cwd = resolveRunnerCwd(ctx, "elixir-check");
|
|
145
146
|
const absPath = path.resolve(cwd, ctx.filePath);
|
|
146
147
|
let command;
|
|
147
148
|
let args = [];
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Gate: skips when no ESLint config is detected (project uses Biome/OxLint instead).
|
|
8
8
|
*/
|
|
9
9
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
10
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
10
11
|
import { getAutofixCapability, hasEslintConfig } from "../../tool-policy.js";
|
|
11
12
|
import { PRIORITY } from "../priorities.js";
|
|
12
13
|
import { createCwdCachedProbe, resolveToolCommand, } from "./utils/runner-helpers.js";
|
|
@@ -79,7 +80,7 @@ const eslintRunner = {
|
|
|
79
80
|
appliesTo: ["jsts"],
|
|
80
81
|
priority: PRIORITY.LINT_SECONDARY,
|
|
81
82
|
async run(ctx) {
|
|
82
|
-
const cwd = ctx
|
|
83
|
+
const cwd = resolveRunnerCwd(ctx, "eslint");
|
|
83
84
|
const userHasConfig = hasEslintConfig(cwd);
|
|
84
85
|
// Only run if project has an ESLint config.
|
|
85
86
|
if (!userHasConfig) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
2
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
2
3
|
import { PRIORITY } from "../priorities.js";
|
|
3
4
|
import { createAvailabilityChecker } from "./utils/runner-helpers.js";
|
|
4
5
|
// fish_indent ships with fish — not separately installable, no managed fallback
|
|
@@ -9,7 +10,7 @@ const fishIndentRunner = {
|
|
|
9
10
|
priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
|
|
10
11
|
skipTestFiles: false,
|
|
11
12
|
async run(ctx) {
|
|
12
|
-
const cwd = ctx
|
|
13
|
+
const cwd = resolveRunnerCwd(ctx, "fish-indent");
|
|
13
14
|
const available = await fishIndent.isAvailableAsync(cwd);
|
|
14
15
|
if (!available)
|
|
15
16
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
2
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
2
3
|
import { createAvailabilityChecker } from "./utils/runner-helpers.js";
|
|
3
4
|
import { PRIORITY } from "../priorities.js";
|
|
4
5
|
const gleam = createAvailabilityChecker("gleam", ".exe");
|
|
@@ -41,7 +42,7 @@ const gleamCheckRunner = {
|
|
|
41
42
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
42
43
|
skipTestFiles: false,
|
|
43
44
|
async run(ctx) {
|
|
44
|
-
const cwd = ctx
|
|
45
|
+
const cwd = resolveRunnerCwd(ctx, "gleam-check");
|
|
45
46
|
if (!(await gleam.isAvailableAsync(cwd))) {
|
|
46
47
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
47
48
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { relative, resolve, sep, posix } from "node:path";
|
|
7
7
|
import { goClient } from "../../go-client.js";
|
|
8
8
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
9
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
9
10
|
import { stripAnsi } from "../../sanitize.js";
|
|
10
11
|
import { skipUnlessToolRan } from "./utils/tool-failure.js";
|
|
11
12
|
import { parseGoVetOutput } from "./utils/diagnostic-parsers.js";
|
|
@@ -29,7 +30,7 @@ const goVetRunner = {
|
|
|
29
30
|
// `go.mod file not found` (#263). ctx.cwd is the go.mod module root
|
|
30
31
|
// (resolveLanguageRootForFile, markers ["go.mod"]), so vet the file's
|
|
31
32
|
// package from there.
|
|
32
|
-
const cwd = ctx
|
|
33
|
+
const cwd = resolveRunnerCwd(ctx, "go-vet");
|
|
33
34
|
const fileRel = relative(cwd, ctx.filePath).split(sep).join(posix.sep);
|
|
34
35
|
const pkgPath = fileRel.startsWith("../")
|
|
35
36
|
? // File isn't under ctx.cwd (unexpected — ctx.cwd is the go.mod root).
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import * as path from "node:path";
|
|
13
13
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
14
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
14
15
|
import { getLinterPolicyForCwd, hasGolangciConfig } from "../../tool-policy.js";
|
|
15
16
|
import { PRIORITY } from "../priorities.js";
|
|
16
17
|
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
@@ -80,7 +81,7 @@ const golangciRunner = {
|
|
|
80
81
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
81
82
|
timeoutMs: 90_000,
|
|
82
83
|
async run(ctx) {
|
|
83
|
-
const cwd = ctx
|
|
84
|
+
const cwd = resolveRunnerCwd(ctx, "golangci-lint");
|
|
84
85
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
85
86
|
if (policy && !policy.preferredRunners.includes("golangci-lint")) {
|
|
86
87
|
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 { getLinterPolicyForCwd } from "../../tool-policy.js";
|
|
4
5
|
import { PRIORITY } from "../priorities.js";
|
|
5
6
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
@@ -37,7 +38,7 @@ const hadolintRunner = {
|
|
|
37
38
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
38
39
|
skipTestFiles: false,
|
|
39
40
|
async run(ctx) {
|
|
40
|
-
const cwd = ctx
|
|
41
|
+
const cwd = resolveRunnerCwd(ctx, "hadolint");
|
|
41
42
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
42
43
|
if (policy && !policy.preferredRunners.includes("hadolint")) {
|
|
43
44
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -3,6 +3,7 @@ import { PathKeyedMap } from "../../path-keyed-map.js";
|
|
|
3
3
|
import { normalizeMapKey } from "../../path-utils.js";
|
|
4
4
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
5
5
|
import { truncatedByOutputCap } from "../../spawn-output-cap.js";
|
|
6
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
6
7
|
import { findNearestDirWithMarker } from "../../workspace-topology.js";
|
|
7
8
|
import { PRIORITY } from "../priorities.js";
|
|
8
9
|
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
@@ -147,6 +148,7 @@ const helmLintRunner = {
|
|
|
147
148
|
skipTestFiles: false,
|
|
148
149
|
timeoutMs: 35_000,
|
|
149
150
|
async run(ctx) {
|
|
151
|
+
const cwd = resolveRunnerCwd(ctx, "helm");
|
|
150
152
|
const workspaceRoot = path.resolve(ctx.projectRoot ?? ctx.cwd);
|
|
151
153
|
const startDir = path.dirname(path.resolve(ctx.filePath));
|
|
152
154
|
const discovered = findNearestDirWithMarker(startDir, "chartYamlPath");
|
|
@@ -158,7 +160,7 @@ const helmLintRunner = {
|
|
|
158
160
|
const existing = inFlightByChartRoot.get(chartRoot);
|
|
159
161
|
if (existing)
|
|
160
162
|
return existing;
|
|
161
|
-
const promise = lintChart(chartRoot,
|
|
163
|
+
const promise = lintChart(chartRoot, cwd).finally(() => {
|
|
162
164
|
if (inFlightByChartRoot.get(chartRoot) === promise)
|
|
163
165
|
inFlightByChartRoot.delete(chartRoot);
|
|
164
166
|
});
|
|
@@ -78,6 +78,7 @@ import { normalizeMapKey } from "../../path-utils.js";
|
|
|
78
78
|
import { loadPiLensProjectConfig } from "../../project-lens-config.js";
|
|
79
79
|
import { getProjectTrustState, projectTrustDenialReason, } from "../../project-trust.js";
|
|
80
80
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
81
|
+
import { resolveRunnerCwd } from "../../tool-cwd.js";
|
|
81
82
|
import { killedForOutputCap, truncatedByOutputCap, } from "../../spawn-output-cap.js";
|
|
82
83
|
import { isTrivyEnabled, resolveSeverityFloor } from "../../trivy-client.js";
|
|
83
84
|
import { findNearestDirWithMarker } from "../../workspace-topology.js";
|
|
@@ -896,7 +897,7 @@ const helmRenderRunner = {
|
|
|
896
897
|
skipTestFiles: false,
|
|
897
898
|
timeoutMs: RENDER_TIMEOUT_MS + TRIVY_TIMEOUT_MS + 10_000,
|
|
898
899
|
async run(ctx) {
|
|
899
|
-
const cwd = ctx
|
|
900
|
+
const cwd = resolveRunnerCwd(ctx, "helm-render");
|
|
900
901
|
const workspaceRoot = path.resolve(ctx.projectRoot ?? cwd);
|
|
901
902
|
// Gate 1 — consent, read from the project whose chart would run. Keying
|
|
902
903
|
// this on `cwd` let an opt-in in one directory authorize a DIFFERENT
|
|
@@ -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 { PRIORITY } from "../priorities.js";
|
|
5
6
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
@@ -49,7 +50,7 @@ const htmlhintRunner = {
|
|
|
49
50
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
50
51
|
skipTestFiles: false,
|
|
51
52
|
async run(ctx) {
|
|
52
|
-
const cwd = ctx
|
|
53
|
+
const cwd = resolveRunnerCwd(ctx, "htmlhint");
|
|
53
54
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
54
55
|
if (policy && !policy.preferredRunners.includes("htmlhint")) {
|
|
55
56
|
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 { hasJavaBuildDescriptor } from "../../tool-policy.js";
|
|
4
5
|
import { PRIORITY } from "../priorities.js";
|
|
5
6
|
import { createAvailabilityChecker } from "./utils/runner-helpers.js";
|
|
@@ -41,7 +42,7 @@ const javacRunner = {
|
|
|
41
42
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
42
43
|
skipTestFiles: false,
|
|
43
44
|
async run(ctx) {
|
|
44
|
-
const cwd = ctx
|
|
45
|
+
const cwd = resolveRunnerCwd(ctx, "javac");
|
|
45
46
|
const absPath = path.resolve(cwd, ctx.filePath);
|
|
46
47
|
// Inside a Maven/Gradle project a classpath-less single-file compile
|
|
47
48
|
// cannot produce a valid verdict: every non-JDK import becomes a
|
|
@@ -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 { getAutofixCapability, getLinterPolicyForCwd, } from "../../tool-policy.js";
|
|
4
5
|
import { PRIORITY } from "../priorities.js";
|
|
5
6
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
@@ -58,7 +59,7 @@ const ktlintRunner = {
|
|
|
58
59
|
priority: PRIORITY.FORMAT_AND_LINT_PRIMARY,
|
|
59
60
|
skipTestFiles: false,
|
|
60
61
|
async run(ctx) {
|
|
61
|
-
const cwd = ctx
|
|
62
|
+
const cwd = resolveRunnerCwd(ctx, "ktlint");
|
|
62
63
|
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
63
64
|
if (policy && !policy.preferredRunners.includes("ktlint")) {
|
|
64
65
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
@@ -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");
|