@herbertgao/pi-extensions 2026.8.4 → 2026.8.6
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 +5 -5
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
- package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
- package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
- package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
- package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
- package/node_modules/@narumitw/pi-btw/README.md +32 -24
- package/node_modules/@narumitw/pi-btw/package.json +6 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
- package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
- package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
- package/node_modules/pi-lens/CHANGELOG.md +2535 -954
- package/node_modules/pi-lens/README.md +13 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
- package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
- package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
- package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
- package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
- package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
- package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
- package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
- package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
- package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
- package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
- package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
- package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
- package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
- package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
- package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
- package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
- package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
- package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
- package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
- 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 +154 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.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 +163 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
- package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
- package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
- package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
- package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
- package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
- package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
- package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
- package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
- package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
- package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
- package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
- package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
- package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
- package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
- package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
- package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
- package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
- package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
- package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
- package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
- package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
- package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
- package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
- package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
- package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
- package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
- package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
- package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
- package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
- package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
- package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
- package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
- package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
- package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
- package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
- package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
- package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
- package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
- package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
- package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
- package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
- package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
- package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
- package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
- package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
- package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
- package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
- package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
- package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
- package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
- package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
- package/node_modules/pi-lens/dist/index.js +51785 -36118
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
- package/node_modules/pi-lens/dist/mcp/server.js +219 -46
- package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
- package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
- package/node_modules/pi-lens/docs/agent-guide.md +40 -15
- package/node_modules/pi-lens/docs/agent-tools.md +21 -10
- package/node_modules/pi-lens/docs/analysisall.md +192 -0
- package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
- package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
- package/node_modules/pi-lens/docs/environment-variables.md +44 -0
- package/node_modules/pi-lens/docs/fable.md +27 -0
- package/node_modules/pi-lens/docs/features.md +45 -3
- package/node_modules/pi-lens/docs/globalconfig.md +56 -1
- package/node_modules/pi-lens/docs/language-coverage.md +4 -3
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
- package/node_modules/pi-lens/docs/mcp.md +37 -4
- package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
- package/node_modules/pi-lens/docs/settings.md +18 -1
- package/node_modules/pi-lens/docs/tools.md +4 -1
- package/node_modules/pi-lens/docs/usage.md +41 -5
- package/node_modules/pi-lens/docs/word-index.md +35 -0
- package/node_modules/pi-lens/package.json +10 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
- package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
- package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
- package/node_modules/pi-mcp-adapter/README.md +38 -4
- package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
- package/node_modules/pi-mcp-adapter/cli.js +25 -4
- package/node_modules/pi-mcp-adapter/commands.ts +15 -7
- package/node_modules/pi-mcp-adapter/config.ts +4 -4
- package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
- package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
- package/node_modules/pi-mcp-adapter/index.ts +8 -3
- package/node_modules/pi-mcp-adapter/init.ts +29 -5
- package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
- package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
- package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
- package/node_modules/pi-mcp-adapter/package.json +4 -3
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
- package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
- package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
- package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
- package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
- package/node_modules/pi-mcp-adapter/types.ts +176 -27
- package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
- package/node_modules/pi-web-access/CHANGELOG.md +14 -0
- package/node_modules/pi-web-access/README.md +18 -12
- package/node_modules/pi-web-access/auth-fetch.ts +148 -0
- package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
- package/node_modules/pi-web-access/curator-page.ts +5 -3
- package/node_modules/pi-web-access/curator-server.ts +2 -1
- package/node_modules/pi-web-access/extract.ts +106 -34
- package/node_modules/pi-web-access/fetch-params.ts +17 -3
- package/node_modules/pi-web-access/firecrawl.ts +172 -12
- package/node_modules/pi-web-access/gemini-search.ts +18 -4
- package/node_modules/pi-web-access/index.ts +120 -48
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/summary-review.ts +11 -5
- package/node_modules/pi-web-access/youtube-extract.ts +2 -2
- package/package.json +12 -13
- package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
- package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
- package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
- package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
- package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
- package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
- package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
- package/node_modules/pi-lens/dist/clients/types.js +0 -11
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* Replaces language-specific runners (pyright, etc.) with a single
|
|
12
12
|
* unified runner that delegates to the LSP service.
|
|
13
13
|
*/
|
|
14
|
+
import { logExtension } from "../../extension-log.js";
|
|
15
|
+
import { touchCoverageGap } from "../../lsp/diagnostic-binding.js";
|
|
14
16
|
import { getLSPService } from "../../lsp/index.js";
|
|
15
17
|
import { RUNTIME_CONFIG } from "../../runtime-config.js";
|
|
16
18
|
import { PRIORITY } from "../priorities.js";
|
|
@@ -110,6 +112,11 @@ const lspRunner = {
|
|
|
110
112
|
// one spawned server) — an empty `lspDiags` in that case is NOT a
|
|
111
113
|
// confirmed clean result and must not be reported as one (#570).
|
|
112
114
|
let diagnosticsInconclusive = false;
|
|
115
|
+
// #1470: server ids the touch carries no evidence for — an auxiliary whose
|
|
116
|
+
// push wait our aux grace timer cut off. The touch is NOT inconclusive (the
|
|
117
|
+
// primary answered, and its findings below are real), so this is tracked
|
|
118
|
+
// separately: the only claim it invalidates is "0 diagnostics means clean".
|
|
119
|
+
let unconfirmedServerIds = [];
|
|
113
120
|
let usedWarmAttach = false;
|
|
114
121
|
let failureReason = "";
|
|
115
122
|
const content = readFileContent(ctx.filePath);
|
|
@@ -128,8 +135,25 @@ const lspRunner = {
|
|
|
128
135
|
try {
|
|
129
136
|
const attached = await tryWarmAttachedDiagnostics(ctx.filePath, content, Math.max(LSP_SPAWN_BUDGET_MS, LSP_DIAGNOSTICS_WAIT_MS));
|
|
130
137
|
usedWarmAttach = attached?.available === true;
|
|
138
|
+
// #1179 (shape-5 structural fix): both branches normalize to the
|
|
139
|
+
// `touchFile` wrapper shape. The warm-attach IPC branch resolves a plain
|
|
140
|
+
// diagnostics array — `available` no longer implies a fully confirmed
|
|
141
|
+
// answer: a `partial` confirmation (an auxiliary cut off by the grace
|
|
142
|
+
// timer) is served as `available: true` too (the IPC gate at
|
|
143
|
+
// `clients/mcp/ipc.ts:248` rejects only `inconclusive`). Carry the
|
|
144
|
+
// incumbent's `unconfirmedServerIds` onto the wrapper so
|
|
145
|
+
// `touchCoverageGap` below sees it — dropping it here is the same
|
|
146
|
+
// false-clean defect already fixed at `clients/lsp/index.ts` (the
|
|
147
|
+
// workspace sweep wrapper) and `tools/lsp-diagnostics.ts` (the tool
|
|
148
|
+
// consumer); wrap it as `{ diags }`; the incumbent branch already
|
|
149
|
+
// returns the wrapper.
|
|
131
150
|
const touched = attached?.available
|
|
132
|
-
?
|
|
151
|
+
? {
|
|
152
|
+
diags: attached.response.diagnostics,
|
|
153
|
+
...(attached.response.unconfirmedServerIds !== undefined && {
|
|
154
|
+
unconfirmedServerIds: attached.response.unconfirmedServerIds,
|
|
155
|
+
}),
|
|
156
|
+
}
|
|
133
157
|
: await lspService.touchFile(ctx.filePath, content, {
|
|
134
158
|
diagnostics: "document",
|
|
135
159
|
collectDiagnostics: true,
|
|
@@ -143,10 +167,9 @@ const lspRunner = {
|
|
|
143
167
|
lspClientReady = false;
|
|
144
168
|
}
|
|
145
169
|
else {
|
|
146
|
-
lspDiags = touched;
|
|
147
|
-
diagnosticsInconclusive =
|
|
148
|
-
|
|
149
|
-
.inconclusive === true;
|
|
170
|
+
lspDiags = touched.diags;
|
|
171
|
+
diagnosticsInconclusive = touched.inconclusive === true;
|
|
172
|
+
unconfirmedServerIds = touchCoverageGap(touched);
|
|
150
173
|
}
|
|
151
174
|
}
|
|
152
175
|
catch (err) {
|
|
@@ -156,7 +179,11 @@ const lspRunner = {
|
|
|
156
179
|
failureReason.includes("exited") ||
|
|
157
180
|
failureReason.includes("connection") ||
|
|
158
181
|
failureReason.includes("JSON RPC")) {
|
|
159
|
-
|
|
182
|
+
logExtension({
|
|
183
|
+
subsystem: "lsp-runner",
|
|
184
|
+
message: `LSP server failed for ${diagnosticPath}: ${failureReason}`,
|
|
185
|
+
metadata: { filePath: diagnosticPath },
|
|
186
|
+
});
|
|
160
187
|
}
|
|
161
188
|
}
|
|
162
189
|
if (serverFailed) {
|
|
@@ -200,6 +227,20 @@ const lspRunner = {
|
|
|
200
227
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
201
228
|
}
|
|
202
229
|
if (lspDiags.length === 0) {
|
|
230
|
+
if (unconfirmedServerIds.length > 0) {
|
|
231
|
+
// #1470: an auxiliary was cut off by the aux grace timer, so this empty
|
|
232
|
+
// merged result is missing whatever that scanner would have said — a
|
|
233
|
+
// hung opengrep must not read as a clean bill of health on the security
|
|
234
|
+
// lane. `RunnerResult` has no channel for "clean for these servers,
|
|
235
|
+
// unknown for those", so the only honest verdict this seam can express
|
|
236
|
+
// for an EMPTY result is "not checked" — which is what "skipped" means
|
|
237
|
+
// here, and it lets the coverage notice say so once. Nothing is thrown
|
|
238
|
+
// away: the primary answered with zero findings, so there is nothing to
|
|
239
|
+
// report; when it DOES have findings the branches below still report
|
|
240
|
+
// them (see the non-empty path), which is how a trustworthy primary
|
|
241
|
+
// stays trustworthy under a cut-off auxiliary.
|
|
242
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
243
|
+
}
|
|
203
244
|
return {
|
|
204
245
|
status: "succeeded",
|
|
205
246
|
diagnostics: [],
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { resolvePackagePath } from "../../package-root.js";
|
|
2
1
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
|
-
import { getLinterPolicyForCwd,
|
|
2
|
+
import { getLinterPolicyForCwd, markdownlintConfigArgs, } from "../../tool-policy.js";
|
|
4
3
|
import { PRIORITY } from "../priorities.js";
|
|
5
4
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
6
5
|
const markdownlint = createAvailabilityChecker("markdownlint-cli2", ".cmd");
|
|
@@ -93,7 +92,6 @@ const markdownlintRunner = {
|
|
|
93
92
|
if (policy && !policy.preferredRunners.includes("markdownlint")) {
|
|
94
93
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
95
94
|
}
|
|
96
|
-
const hasConfig = hasMarkdownlintConfig(cwd);
|
|
97
95
|
let cmd = null;
|
|
98
96
|
if (await (markdownlint.isAvailableAsync(cwd))) {
|
|
99
97
|
cmd = markdownlint.getCommand(cwd);
|
|
@@ -103,12 +101,9 @@ const markdownlintRunner = {
|
|
|
103
101
|
}
|
|
104
102
|
if (!cmd)
|
|
105
103
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"--config",
|
|
110
|
-
resolvePackagePath(import.meta.url, "config/markdownlint/core.json"),
|
|
111
|
-
];
|
|
104
|
+
// Shared config-args seam (#1247): the autofix path consumes the same
|
|
105
|
+
// builder, so the package-owned fallback config can never drift.
|
|
106
|
+
const configArgs = markdownlintConfigArgs(cwd);
|
|
112
107
|
const result = await safeSpawnAsync(cmd, [...configArgs, ctx.filePath], {
|
|
113
108
|
timeout: 15000,
|
|
114
109
|
cwd,
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Requires: pyright (pip install pyright or npm install -g pyright)
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { logExtension } from "../../extension-log.js";
|
|
10
10
|
import { getLSPService } from "../../lsp/index.js";
|
|
11
11
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
12
12
|
import { PRIORITY } from "../priorities.js";
|
|
13
|
-
import { createAvailabilityChecker } from "./utils/runner-helpers.js";
|
|
13
|
+
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
14
14
|
const pyright = createAvailabilityChecker("pyright", ".exe");
|
|
15
15
|
const pyrightRunner = {
|
|
16
16
|
id: "pyright",
|
|
@@ -34,9 +34,9 @@ const pyrightRunner = {
|
|
|
34
34
|
if (await (pyright.isAvailableAsync(cwd))) {
|
|
35
35
|
cmd = pyright.getCommand(cwd);
|
|
36
36
|
}
|
|
37
|
-
// Strategy 2:
|
|
37
|
+
// Strategy 2: use the shared availability taxonomy and install suppression.
|
|
38
38
|
if (!cmd) {
|
|
39
|
-
const installedPath = await
|
|
39
|
+
const installedPath = await resolveAvailableOrInstall(pyright, "pyright", cwd);
|
|
40
40
|
if (installedPath)
|
|
41
41
|
cmd = installedPath;
|
|
42
42
|
}
|
|
@@ -85,7 +85,11 @@ const pyrightRunner = {
|
|
|
85
85
|
// pi-lens-ignore: missing-error-propagation
|
|
86
86
|
}
|
|
87
87
|
catch {
|
|
88
|
-
|
|
88
|
+
logExtension({
|
|
89
|
+
subsystem: "runner:pyright",
|
|
90
|
+
message: `JSON parse failed for ${ctx.filePath} — raw output: ${output.slice(0, 200)}`,
|
|
91
|
+
metadata: { filePath: ctx.filePath },
|
|
92
|
+
});
|
|
89
93
|
return {
|
|
90
94
|
status: "failed",
|
|
91
95
|
diagnostics: [],
|
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
* mutating files mid-dispatch after LSP sync has already happened.
|
|
7
7
|
* Supports venv-local installations.
|
|
8
8
|
*/
|
|
9
|
-
import { resolvePackagePath } from "../../package-root.js";
|
|
10
9
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
11
10
|
import { stripAnsi } from "../../sanitize.js";
|
|
12
|
-
import { getAutofixCapability, getLinterPolicyForCwd,
|
|
11
|
+
import { getAutofixCapability, getLinterPolicyForCwd, ruffConfigArgs, } from "../../tool-policy.js";
|
|
13
12
|
import { PRIORITY } from "../priorities.js";
|
|
14
13
|
import { parseRuffOutput } from "./utils/diagnostic-parsers.js";
|
|
15
14
|
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
@@ -61,12 +60,9 @@ const ruffRunner = {
|
|
|
61
60
|
if (!cmd) {
|
|
62
61
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
63
62
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
"--config",
|
|
68
|
-
resolvePackagePath(import.meta.url, "config/ruff/core.toml"),
|
|
69
|
-
];
|
|
63
|
+
// Shared config-args seam (#1247): the autofix path consumes the same
|
|
64
|
+
// builder, so the package-owned fallback config can never drift.
|
|
65
|
+
const configArgs = ruffConfigArgs(cwd);
|
|
70
66
|
// Step 1: Capture diagnostics (before fixing) — teaching signal for the agent
|
|
71
67
|
const checkResult = await safeSpawnAsync(cmd, ["check", "--output-format", "json", ...configArgs, ctx.filePath], { timeout: 30000 });
|
|
72
68
|
const raw = stripAnsi(checkResult.stdout + checkResult.stderr);
|
|
@@ -21,10 +21,9 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import * as fs from "node:fs";
|
|
23
23
|
import * as path from "node:path";
|
|
24
|
-
import { ensureTool } from "../../installer/index.js";
|
|
25
24
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
26
25
|
import { PRIORITY } from "../priorities.js";
|
|
27
|
-
import { createAvailabilityChecker, lspPrimaryCoversFile, } from "./utils/runner-helpers.js";
|
|
26
|
+
import { createAvailabilityChecker, lspPrimaryCoversFile, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
28
27
|
const shellcheck = createAvailabilityChecker("shellcheck", ".exe");
|
|
29
28
|
function findShellcheckConfig(cwd) {
|
|
30
29
|
const local = path.join(cwd, ".shellcheckrc");
|
|
@@ -127,7 +126,7 @@ const shellcheckRunner = {
|
|
|
127
126
|
cmd = shellcheck.getCommand(cwd);
|
|
128
127
|
}
|
|
129
128
|
else {
|
|
130
|
-
const managed = await
|
|
129
|
+
const managed = await resolveAvailableOrInstall(shellcheck, "shellcheck", cwd);
|
|
131
130
|
if (managed)
|
|
132
131
|
cmd = managed;
|
|
133
132
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { ensureTool } from "../../installer/index.js";
|
|
4
3
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
5
4
|
import { PRIORITY } from "../priorities.js";
|
|
6
|
-
import { createAvailabilityChecker } from "./utils/runner-helpers.js";
|
|
5
|
+
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
7
6
|
const shfmt = createAvailabilityChecker("shfmt", ".exe");
|
|
8
7
|
// shfmt's only config source is .editorconfig. We treat its presence as the
|
|
9
8
|
// opt-in for the (non-error) format-diff warning, so out of the box shfmt only
|
|
@@ -39,7 +38,7 @@ const shfmtRunner = {
|
|
|
39
38
|
cmd = shfmt.getCommand(cwd);
|
|
40
39
|
}
|
|
41
40
|
else {
|
|
42
|
-
const installed = await
|
|
41
|
+
const installed = await resolveAvailableOrInstall(shfmt, "shfmt", cwd);
|
|
43
42
|
if (!installed) {
|
|
44
43
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
45
44
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import { BoundedLruCache } from "../../bounded-cache.js";
|
|
4
5
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
5
6
|
import { findCompiledClassesDir } from "../../tool-policy.js";
|
|
6
7
|
import { PRIORITY } from "../priorities.js";
|
|
@@ -11,7 +12,7 @@ const java = createAvailabilityChecker("java", ".exe", ["-version"]);
|
|
|
11
12
|
const spotbugs = createAvailabilityChecker("spotbugs", ".bat", ["-version"]);
|
|
12
13
|
const MAX_DIAGNOSTICS = 50;
|
|
13
14
|
const MAX_XML_BYTES = 4 * 1024 * 1024;
|
|
14
|
-
const scanCache = new
|
|
15
|
+
const scanCache = new BoundedLruCache(32);
|
|
15
16
|
/** Reset the SpotBugs scan cache (tests). */
|
|
16
17
|
export function _resetSpotbugsCacheForTests() {
|
|
17
18
|
scanCache.clear();
|
|
@@ -3,6 +3,7 @@ import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
|
3
3
|
import { getLinterPolicyForCwd } from "../../tool-policy.js";
|
|
4
4
|
import { PRIORITY } from "../priorities.js";
|
|
5
5
|
import { createAvailabilityChecker, lspPrimaryCoversFile, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
6
|
+
import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
|
|
6
7
|
const taplo = createAvailabilityChecker("taplo", ".exe");
|
|
7
8
|
function parseTaploOutput(raw, filePath) {
|
|
8
9
|
try {
|
|
@@ -55,7 +56,7 @@ const taploRunner = {
|
|
|
55
56
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
56
57
|
const absPath = path.resolve(cwd, ctx.filePath);
|
|
57
58
|
const result = await safeSpawnAsync(cmd, ["check", "--output=json", absPath], { cwd, timeout: 15000 });
|
|
58
|
-
if (result
|
|
59
|
+
if (spawnFailedWithNoOutput(result)) {
|
|
59
60
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
60
61
|
}
|
|
61
62
|
const diagnostics = parseTaploOutput(result.stdout || "", ctx.filePath);
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
|
+
import { pathsEqual } from "../../path-utils.js";
|
|
4
|
+
import { getLinterPolicyForCwd } from "../../tool-policy.js";
|
|
5
|
+
import { PRIORITY } from "../priorities.js";
|
|
6
|
+
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
7
|
+
import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
|
|
8
|
+
const terragrunt = createAvailabilityChecker("terragrunt", ".exe");
|
|
9
|
+
function normalizeSeverity(raw) {
|
|
10
|
+
if (typeof raw === "number")
|
|
11
|
+
return raw === 1 ? "error" : "warning";
|
|
12
|
+
if (typeof raw === "string" && raw.toLowerCase() === "error")
|
|
13
|
+
return "error";
|
|
14
|
+
return "warning";
|
|
15
|
+
}
|
|
16
|
+
function toRawDiagnostics(parsed) {
|
|
17
|
+
if (Array.isArray(parsed))
|
|
18
|
+
return parsed;
|
|
19
|
+
if (!parsed || typeof parsed !== "object")
|
|
20
|
+
return [];
|
|
21
|
+
const invalidFiles = parsed.invalid_files;
|
|
22
|
+
if (!Array.isArray(invalidFiles))
|
|
23
|
+
return [];
|
|
24
|
+
return invalidFiles.flatMap((f) => Array.isArray(f?.diagnostics) ? f.diagnostics : []);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parse `terragrunt hcl validate --json` output.
|
|
28
|
+
*
|
|
29
|
+
* OBSERVED CONTRACT (captured empirically from terragrunt v1.1.2, win-x64):
|
|
30
|
+
* the payload is a FLAT JSON array of diagnostic objects on stdout, e.g.
|
|
31
|
+
*
|
|
32
|
+
* [{"range":{"filename":"<ABSOLUTE path>","start":{"line":1,"column":8,...},
|
|
33
|
+
* "end":{...}},"snippet":{...},"summary":"Unclosed configuration block",
|
|
34
|
+
* "detail":"...","severity":"error"}]
|
|
35
|
+
*
|
|
36
|
+
* Key facts: `severity` is a STRING ("error"), `range.filename` is an ABSOLUTE
|
|
37
|
+
* path (host separator), and a CLEAN unit prints NOTHING (empty stdout, exit 0)
|
|
38
|
+
* — not `[]`. The nested `{invalid_files:[{diagnostics:[...]}]}` wrapper and the
|
|
39
|
+
* numeric (1=error/2=warning) severity encoding were NOT observed on v1.1.2 and
|
|
40
|
+
* are retained only as a tolerant fallback for other/older shapes.
|
|
41
|
+
* Malformed/unparseable input returns [].
|
|
42
|
+
*/
|
|
43
|
+
export function parseTerragruntOutput(raw, filePath, absPath = path.resolve(filePath)) {
|
|
44
|
+
if (!raw.trim())
|
|
45
|
+
return [];
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = JSON.parse(raw);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
// Resolved against the unit dir, not compared by basename: a unit that
|
|
54
|
+
// includes its parent via find_in_parent_folders() gets diagnostics from a
|
|
55
|
+
// parent terragrunt.hcl, whose basename matches but whose lines do not.
|
|
56
|
+
const unitDir = path.dirname(absPath);
|
|
57
|
+
const diagnostics = [];
|
|
58
|
+
for (const d of toRawDiagnostics(parsed)) {
|
|
59
|
+
if (!d || typeof d !== "object")
|
|
60
|
+
continue;
|
|
61
|
+
const diagFile = d.range?.filename;
|
|
62
|
+
if (diagFile && !pathsEqual(path.resolve(unitDir, diagFile), absPath))
|
|
63
|
+
continue;
|
|
64
|
+
const line = d.range?.start?.line ?? 1;
|
|
65
|
+
const column = d.range?.start?.column ?? 1;
|
|
66
|
+
const severity = normalizeSeverity(d.severity);
|
|
67
|
+
const message = d.summary ?? d.detail ?? "terragrunt hcl validate error";
|
|
68
|
+
// No rule code in hcl validate output, so the message carries the identity.
|
|
69
|
+
const idMessage = message
|
|
70
|
+
.toLowerCase()
|
|
71
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
72
|
+
.slice(0, 80);
|
|
73
|
+
diagnostics.push({
|
|
74
|
+
id: `terragrunt-hclvalidate-${line}-${column}-${idMessage}`,
|
|
75
|
+
message,
|
|
76
|
+
filePath,
|
|
77
|
+
line,
|
|
78
|
+
column,
|
|
79
|
+
severity,
|
|
80
|
+
semantic: severity === "error" ? "blocking" : "warning",
|
|
81
|
+
tool: "terragrunt",
|
|
82
|
+
fixable: false,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return diagnostics;
|
|
86
|
+
}
|
|
87
|
+
const SKIPPED = {
|
|
88
|
+
status: "skipped",
|
|
89
|
+
diagnostics: [],
|
|
90
|
+
semantic: "none",
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Runner for `terragrunt hcl validate --json`, the linter for terragrunt units.
|
|
94
|
+
*
|
|
95
|
+
* REQUIRES the redesigned terragrunt CLI: the `terragrunt hcl validate` /
|
|
96
|
+
* `terragrunt hcl fmt` command group replaced the old `hclvalidate`/`hclfmt`
|
|
97
|
+
* top-level commands in the CLI redesign (~terragrunt v0.75; the legacy names
|
|
98
|
+
* were removed in v1.0). Contract verified empirically on terragrunt v1.1.2.
|
|
99
|
+
*
|
|
100
|
+
* Observed exit-code / output table (terragrunt v1.1.2, win-x64):
|
|
101
|
+
* - clean unit ............ exit 0, EMPTY stdout (no `[]`)
|
|
102
|
+
* - validation findings ... exit 1, flat JSON array on stdout (+ a log line
|
|
103
|
+
* "N HCL validation error(s) found" on stderr)
|
|
104
|
+
* - unknown command ....... an older binary that predates `hcl validate`
|
|
105
|
+
* exits non-zero with the error on STDERR and EMPTY
|
|
106
|
+
* stdout; `spawnFailedWithNoOutput` classifies that
|
|
107
|
+
* as SKIPPED (never a false blocker, and never a
|
|
108
|
+
* false CLEAN — a nonzero exit carries no
|
|
109
|
+
* `SpawnResult.error`, so the status has to be part
|
|
110
|
+
* of the test).
|
|
111
|
+
*
|
|
112
|
+
* `hcl validate` recursively validates the unit(s) at its working dir; it has no
|
|
113
|
+
* per-file flag (`--filter` takes component filter-syntax, NOT a filename — a
|
|
114
|
+
* bare basename silently matches zero components and suppresses ALL findings,
|
|
115
|
+
* verified on v1.1.2). So we validate the edited file's unit directory and
|
|
116
|
+
* attribute findings back to the edited file by absolute path in
|
|
117
|
+
* parseTerragruntOutput.
|
|
118
|
+
*
|
|
119
|
+
* Misdetection edge: `root.hcl` is filename-detected as terragrunt, so a
|
|
120
|
+
* `root.hcl` that is NOT a terragrunt file still gets validated here — `hcl
|
|
121
|
+
* validate` just checks generic HCL, so a non-terragrunt file fails soft
|
|
122
|
+
* (either clean or a plain HCL diagnostic, never a spurious hard blocker).
|
|
123
|
+
*/
|
|
124
|
+
const terragruntRunner = {
|
|
125
|
+
id: "terragrunt",
|
|
126
|
+
appliesTo: ["terragrunt"],
|
|
127
|
+
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
128
|
+
enabledByDefault: true,
|
|
129
|
+
skipTestFiles: false,
|
|
130
|
+
async run(ctx) {
|
|
131
|
+
const cwd = ctx.cwd || process.cwd();
|
|
132
|
+
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
133
|
+
if (policy && !policy.preferredRunners.includes("terragrunt"))
|
|
134
|
+
return SKIPPED;
|
|
135
|
+
let cmd = null;
|
|
136
|
+
if (await terragrunt.isAvailableAsync(cwd)) {
|
|
137
|
+
cmd = terragrunt.getCommand(cwd);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const managed = await resolveAvailableOrInstall(terragrunt, "terragrunt", cwd);
|
|
141
|
+
if (managed)
|
|
142
|
+
cmd = managed;
|
|
143
|
+
}
|
|
144
|
+
if (!cmd)
|
|
145
|
+
return SKIPPED;
|
|
146
|
+
const absPath = path.resolve(cwd, ctx.filePath);
|
|
147
|
+
const fileDir = path.dirname(absPath);
|
|
148
|
+
const result = await safeSpawnAsync(cmd, ["hcl", "validate", "--json", "--non-interactive"], { cwd: fileDir, timeout: 30000 });
|
|
149
|
+
if (spawnFailedWithNoOutput(result))
|
|
150
|
+
return SKIPPED;
|
|
151
|
+
const diagnostics = parseTerragruntOutput(result.stdout || "", ctx.filePath, absPath);
|
|
152
|
+
if (diagnostics.length === 0) {
|
|
153
|
+
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
154
|
+
}
|
|
155
|
+
const hasErrors = diagnostics.some((d) => d.severity === "error");
|
|
156
|
+
return {
|
|
157
|
+
status: hasErrors ? "failed" : "succeeded",
|
|
158
|
+
diagnostics,
|
|
159
|
+
semantic: hasErrors ? "blocking" : "warning",
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
export default terragruntRunner;
|
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
-
import { ensureTool } from "../../installer/index.js";
|
|
3
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
4
|
-
import {
|
|
3
|
+
import { getLinterPolicyForCwd } from "../../tool-policy.js";
|
|
4
|
+
import { findNearestDirWithAnyBasename } from "../../workspace-topology.js";
|
|
5
|
+
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
6
|
+
import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
|
|
5
7
|
import { PRIORITY } from "../priorities.js";
|
|
6
8
|
const tflint = createAvailabilityChecker("tflint", ".exe");
|
|
9
|
+
const TFLINT_CONFIG = ".tflint.hcl";
|
|
10
|
+
/**
|
|
11
|
+
* tflint resolves `.tflint.hcl` from its own working directory and never walks
|
|
12
|
+
* parents (its only fallback is `~/.tflint.hcl`). We run it from the edited
|
|
13
|
+
* file's directory, so a repo-root config would govern nothing beneath the
|
|
14
|
+
* root unless we name it explicitly. Returns null when `TFLINT_CONFIG_FILE` is
|
|
15
|
+
* set: `--config` outranks the env var in tflint's own precedence, so passing
|
|
16
|
+
* one would override a deliberate choice.
|
|
17
|
+
*/
|
|
18
|
+
function findTflintConfig(fileDir) {
|
|
19
|
+
if (process.env.TFLINT_CONFIG_FILE)
|
|
20
|
+
return null;
|
|
21
|
+
const dir = findNearestDirWithAnyBasename(fileDir, [TFLINT_CONFIG]);
|
|
22
|
+
return dir ? path.join(dir, TFLINT_CONFIG) : null;
|
|
23
|
+
}
|
|
7
24
|
function parseTflintOutput(raw, filePath) {
|
|
8
25
|
try {
|
|
9
26
|
const parsed = JSON.parse(raw);
|
|
@@ -36,12 +53,16 @@ const tflintRunner = {
|
|
|
36
53
|
skipTestFiles: false,
|
|
37
54
|
async run(ctx) {
|
|
38
55
|
const cwd = ctx.cwd || process.cwd();
|
|
56
|
+
const policy = getLinterPolicyForCwd(ctx.filePath, cwd);
|
|
57
|
+
if (policy && !policy.preferredRunners.includes("tflint")) {
|
|
58
|
+
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
59
|
+
}
|
|
39
60
|
let cmd = null;
|
|
40
61
|
if (await (tflint.isAvailableAsync(cwd))) {
|
|
41
62
|
cmd = tflint.getCommand(cwd);
|
|
42
63
|
}
|
|
43
64
|
else {
|
|
44
|
-
const managed = await
|
|
65
|
+
const managed = await resolveAvailableOrInstall(tflint, "tflint", cwd);
|
|
45
66
|
if (managed)
|
|
46
67
|
cmd = managed;
|
|
47
68
|
}
|
|
@@ -49,8 +70,19 @@ const tflintRunner = {
|
|
|
49
70
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
50
71
|
const absPath = path.resolve(cwd, ctx.filePath);
|
|
51
72
|
const fileDir = path.dirname(absPath);
|
|
52
|
-
const
|
|
53
|
-
|
|
73
|
+
const args = [
|
|
74
|
+
"--format=json",
|
|
75
|
+
"--no-color",
|
|
76
|
+
`--filter=${path.basename(absPath)}`,
|
|
77
|
+
];
|
|
78
|
+
const configPath = findTflintConfig(fileDir);
|
|
79
|
+
if (configPath)
|
|
80
|
+
args.push(`--config=${configPath}`);
|
|
81
|
+
const result = await safeSpawnAsync(cmd, args, {
|
|
82
|
+
cwd: fileDir,
|
|
83
|
+
timeout: 30000,
|
|
84
|
+
});
|
|
85
|
+
if (spawnFailedWithNoOutput(result)) {
|
|
54
86
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
55
87
|
}
|
|
56
88
|
const diagnostics = parseTflintOutput(result.stdout || "", ctx.filePath);
|
|
@@ -525,7 +525,9 @@ const treeSitterRunner = {
|
|
|
525
525
|
});
|
|
526
526
|
}
|
|
527
527
|
else {
|
|
528
|
-
|
|
528
|
+
// #1333: the logTreeSitter call below already carries this failure to
|
|
529
|
+
// tree-sitter.log — the console.error was a duplicate RAW write into
|
|
530
|
+
// pi's frame, not a second destination. Sink kept, write dropped.
|
|
529
531
|
logTreeSitter({
|
|
530
532
|
phase: "query_error",
|
|
531
533
|
filePath,
|
|
@@ -15,8 +15,14 @@
|
|
|
15
15
|
* reports at the same line (`suppressTrivyConfigDockerOverlap`), so trivy
|
|
16
16
|
* only adds the security checks hadolint lacks.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
18
|
+
* - **Terraform**: the `.tf` language files themselves — trivy evaluates
|
|
19
|
+
* the Terraform language directly, so no content gate is needed (unlike
|
|
20
|
+
* the yaml/k8s heuristic above). Terragrunt (`.hcl`) is deliberately
|
|
21
|
+
* excluded: trivy has no terragrunt support, and terragrunt config is
|
|
22
|
+
* covered by the terragrunt runner instead.
|
|
23
|
+
*
|
|
24
|
+
* Deferred (tracked on #131): Helm chart rendering, Docker Compose,
|
|
25
|
+
* CloudFormation.
|
|
20
26
|
*
|
|
21
27
|
* Gating: the same explicit `trivy.enabled` opt-in as the session-scan modes —
|
|
22
28
|
* trivy is opt-in, period. (Misconfig needs only the small policy bundle, not
|
|
@@ -30,7 +36,8 @@ import * as path from "node:path";
|
|
|
30
36
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
31
37
|
import { isTrivyEnabled, resolveSeverityFloor, } from "../../trivy-client.js";
|
|
32
38
|
import { PRIORITY } from "../priorities.js";
|
|
33
|
-
import { createAvailabilityChecker } from "./utils/runner-helpers.js";
|
|
39
|
+
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
40
|
+
import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
|
|
34
41
|
const trivy = createAvailabilityChecker("trivy", ".exe");
|
|
35
42
|
/**
|
|
36
43
|
* Heuristic: does this YAML look like a Kubernetes manifest (vs a CI workflow,
|
|
@@ -115,7 +122,7 @@ export function parseTrivyConfigOutput(raw, filePath) {
|
|
|
115
122
|
}
|
|
116
123
|
const trivyConfigRunner = {
|
|
117
124
|
id: "trivy-config",
|
|
118
|
-
appliesTo: ["docker", "yaml"],
|
|
125
|
+
appliesTo: ["docker", "yaml", "terraform"],
|
|
119
126
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
120
127
|
enabledByDefault: true,
|
|
121
128
|
skipTestFiles: false,
|
|
@@ -144,8 +151,7 @@ const trivyConfigRunner = {
|
|
|
144
151
|
cmd = trivy.getCommand(cwd);
|
|
145
152
|
}
|
|
146
153
|
else {
|
|
147
|
-
const
|
|
148
|
-
const managed = await ensureTool("trivy");
|
|
154
|
+
const managed = await resolveAvailableOrInstall(trivy, "trivy", cwd);
|
|
149
155
|
if (managed)
|
|
150
156
|
cmd = managed;
|
|
151
157
|
}
|
|
@@ -162,7 +168,7 @@ const trivyConfigRunner = {
|
|
|
162
168
|
severities,
|
|
163
169
|
absPath,
|
|
164
170
|
], { cwd, timeout: 60_000 });
|
|
165
|
-
if (result
|
|
171
|
+
if (spawnFailedWithNoOutput(result)) {
|
|
166
172
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
167
173
|
}
|
|
168
174
|
const diagnostics = parseTrivyConfigOutput(result.stdout || "", ctx.filePath);
|