@herbertgao/pi-extensions 2026.8.6 → 2026.8.8
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 +8 -6
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +320 -22
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
- package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
- package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
- package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
- package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
- package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
- package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +5 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +140 -97
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
- package/node_modules/@narumitw/pi-btw/README.md +120 -111
- package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
- package/node_modules/@narumitw/pi-btw/package.json +10 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
- package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
- package/node_modules/pi-lens/CHANGELOG.md +999 -0
- package/node_modules/pi-lens/README.md +117 -3
- package/node_modules/pi-lens/config/ruff/core.toml +42 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
- package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +381 -13
- package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -0
- package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +206 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
- package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
- package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
- package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
- package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +84 -14
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
- package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
- package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +188 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
- package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
- package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
- package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
- package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
- package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
- package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
- package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +87 -8
- package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
- package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
- package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
- package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
- package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
- package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
- package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
- package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
- package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
- package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
- package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +8 -3
- package/node_modules/pi-lens/dist/clients/read-guard.js +253 -10
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
- package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
- package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
- package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
- package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
- package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
- package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
- package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
- package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
- package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
- package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
- package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
- package/node_modules/pi-lens/dist/index.js +61407 -48577
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
- package/node_modules/pi-lens/docs/agent-guide.md +6 -1
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
- package/node_modules/pi-lens/docs/dispositions.md +21 -0
- package/node_modules/pi-lens/docs/features.md +19 -5
- package/node_modules/pi-lens/docs/globalconfig.md +3 -0
- package/node_modules/pi-lens/docs/language-coverage.md +71 -5
- package/node_modules/pi-lens/docs/mcp.md +2 -2
- package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
- package/node_modules/pi-lens/docs/settings.md +19 -1
- package/node_modules/pi-lens/docs/usage.md +1 -0
- package/node_modules/pi-lens/package.json +27 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
- package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
- package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
- package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
- package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
- package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
- package/node_modules/pi-mcp-adapter/README.md +47 -5
- package/node_modules/pi-mcp-adapter/cli.js +163 -1
- package/node_modules/pi-mcp-adapter/commands.ts +128 -22
- package/node_modules/pi-mcp-adapter/config.ts +25 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
- package/node_modules/pi-mcp-adapter/index.ts +219 -32
- package/node_modules/pi-mcp-adapter/init.ts +36 -4
- package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
- package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
- package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
- package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
- package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
- package/node_modules/pi-mcp-adapter/package.json +3 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
- package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
- package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
- package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
- package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
- package/node_modules/pi-mcp-adapter/types.ts +2 -0
- package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
- package/node_modules/pi-mcp-adapter/utils.ts +70 -0
- package/node_modules/pi-web-access/CHANGELOG.md +37 -0
- package/node_modules/pi-web-access/README.md +32 -13
- package/node_modules/pi-web-access/anysearch.ts +4 -2
- package/node_modules/pi-web-access/brave.ts +16 -4
- package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
- package/node_modules/pi-web-access/curator-page.ts +6 -3
- package/node_modules/pi-web-access/curator-server.ts +4 -1
- package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +40 -5
- package/node_modules/pi-web-access/firecrawl.ts +18 -2
- package/node_modules/pi-web-access/gemini-search.ts +16 -4
- package/node_modules/pi-web-access/github-extract.ts +65 -36
- package/node_modules/pi-web-access/index.ts +60 -61
- package/node_modules/pi-web-access/openai-search.ts +17 -6
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/page-query.ts +4 -2
- package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
- package/node_modules/pi-web-access/parallel.ts +2 -2
- package/node_modules/pi-web-access/pdf-extract.ts +18 -5
- package/node_modules/pi-web-access/query-rewrite.ts +51 -0
- package/node_modules/pi-web-access/serper.ts +211 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
- package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
- package/node_modules/pi-web-access/summary-review.ts +44 -22
- package/node_modules/pi-web-access/tavily.ts +16 -4
- package/node_modules/pi-web-access/utils.ts +87 -0
- package/node_modules/pi-web-access/valyu.ts +199 -0
- package/package.json +14 -14
|
@@ -21,7 +21,11 @@
|
|
|
21
21
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
22
22
|
import { PRIORITY } from "../priorities.js";
|
|
23
23
|
import { createAvailabilityChecker } from "./utils/runner-helpers.js";
|
|
24
|
+
import { parseToolRun } from "./utils/tool-failure.js";
|
|
24
25
|
const typos = createAvailabilityChecker("typos", ".exe");
|
|
26
|
+
// typos-cli exit codes: 0 = no typos, 2 = typos found, 1 = an error that
|
|
27
|
+
// stopped the scan. Anything nonzero outside {2} is a rejected invocation.
|
|
28
|
+
const TYPOS_EXIT_CODES = { ran: [2] };
|
|
25
29
|
/**
|
|
26
30
|
* Parse typos-cli JSON output (JSON Lines format)
|
|
27
31
|
*
|
|
@@ -90,14 +94,19 @@ const spellcheckRunner = {
|
|
|
90
94
|
const result = await safeSpawnAsync(typos.getCommand(ctx.cwd || process.cwd()), args, {
|
|
91
95
|
timeout: 15000,
|
|
92
96
|
});
|
|
93
|
-
// typos-cli exits
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
// #1816: typos-cli exits 0 clean, 2 with typos found, and 1 on an ERROR
|
|
98
|
+
// (unreadable config, bad argument). The `status === 2 || stdout` test
|
|
99
|
+
// below is false for exit 1 with an empty stdout, so a failed run was
|
|
100
|
+
// reported as a clean file. Only 0 and 2 are runs.
|
|
101
|
+
//
|
|
102
|
+
// #1948: parse through the shared seam so an exit-2 run whose JSON lines
|
|
103
|
+
// yield nothing leaves a record. `parseOutput` keeps the historical
|
|
104
|
+
// split: the gate judges "did it run" on stdout, the parser reads both
|
|
105
|
+
// streams.
|
|
106
|
+
const run = parseToolRun("spellcheck", { result, exitCodes: TYPOS_EXIT_CODES }, (out) => parseTyposOutput(out, ctx.filePath), { parseOutput: `${result.stdout ?? ""}${result.stderr ?? ""}` });
|
|
107
|
+
if (run.skipped)
|
|
108
|
+
return run.skipped;
|
|
109
|
+
const diagnostics = run.diagnostics;
|
|
101
110
|
if (diagnostics.length === 0) {
|
|
102
111
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
103
112
|
}
|
|
@@ -2,7 +2,17 @@ import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
|
2
2
|
import { getLinterPolicyForCwd, hasSqlfluffConfig } from "../../tool-policy.js";
|
|
3
3
|
import { PRIORITY } from "../priorities.js";
|
|
4
4
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
5
|
+
import { parseToolRun } from "./utils/tool-failure.js";
|
|
5
6
|
const sqlfluff = createAvailabilityChecker("sqlfluff", ".exe");
|
|
7
|
+
// sqlfluff exit codes (its CLI docs): 0 = clean, 1 = violations found, 2 = a
|
|
8
|
+
// user error that stopped the lint (unknown dialect, unreadable config).
|
|
9
|
+
// Only 2 is a rejected invocation.
|
|
10
|
+
//
|
|
11
|
+
// The exit TABLE is what protects this runner, not the nothing-to-parse rule:
|
|
12
|
+
// sqlfluff writes its user errors to STDOUT, not stderr (live: an unknown
|
|
13
|
+
// dialect prints the error there), so stdout is non-empty and the fallback
|
|
14
|
+
// rule would read the failed run as a run that found nothing.
|
|
15
|
+
const SQLFLUFF_EXIT_CODES = { ran: [1] };
|
|
6
16
|
export { hasSqlfluffConfig };
|
|
7
17
|
// sqlfluff's JSON lint output does not carry a per-violation fixable flag —
|
|
8
18
|
// `sqlfluff fix` is a separate command and the lint surface doesn't tell us
|
|
@@ -117,7 +127,7 @@ const sqlfluffRunner = {
|
|
|
117
127
|
ctx.log("sqlfluff: no config detected, using ANSI dialect defaults");
|
|
118
128
|
}
|
|
119
129
|
let cmd = null;
|
|
120
|
-
if (await
|
|
130
|
+
if (await sqlfluff.isAvailableAsync(cwd)) {
|
|
121
131
|
cmd = sqlfluff.getCommand(cwd);
|
|
122
132
|
}
|
|
123
133
|
else {
|
|
@@ -125,14 +135,32 @@ const sqlfluffRunner = {
|
|
|
125
135
|
}
|
|
126
136
|
if (!cmd)
|
|
127
137
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
128
|
-
|
|
138
|
+
// #1937: this used to be `args.splice(2, 0, "--dialect", "ansi")` on
|
|
139
|
+
// `["lint", "--format", "json", file]`, which inserts BETWEEN the flag
|
|
140
|
+
// and its value and yields `lint --format --dialect ansi json file`.
|
|
141
|
+
// sqlfluff rejects `--dialect` as the value of `--format` and exits 2,
|
|
142
|
+
// so every SQL project WITHOUT a .sqlfluff — exactly the case this
|
|
143
|
+
// dialect default exists to serve — was never linted. Built in order
|
|
144
|
+
// rather than patched by index, and pinned by the argv-tie assertion
|
|
145
|
+
// in runners/captured-real-output.test.ts.
|
|
146
|
+
const args = ["lint", "--format", "json"];
|
|
129
147
|
if (!hasConfig) {
|
|
130
|
-
args.
|
|
148
|
+
args.push("--dialect", "ansi");
|
|
131
149
|
}
|
|
150
|
+
args.push(ctx.filePath);
|
|
132
151
|
const result = await safeSpawnAsync(cmd, args, {
|
|
133
152
|
timeout: 20000,
|
|
153
|
+
cwd,
|
|
134
154
|
});
|
|
135
|
-
|
|
155
|
+
// #1816: this runner read `result.status` zero times, so a user error
|
|
156
|
+
// fell through `parseSqlfluffOutput`'s JSON catch to zero violations and
|
|
157
|
+
// reported the SQL file as clean.
|
|
158
|
+
// #1948: sqlfluff exit 1 with a JSON report we read nothing out of is a
|
|
159
|
+
// parser break, not a clean file.
|
|
160
|
+
const run = parseToolRun("sqlfluff", { result, exitCodes: SQLFLUFF_EXIT_CODES }, (out) => parseSqlfluffOutput(out, ctx.filePath), { parseOutput: result.stdout ?? "" });
|
|
161
|
+
if (run.skipped)
|
|
162
|
+
return run.skipped;
|
|
163
|
+
const diagnostics = run.diagnostics;
|
|
136
164
|
if (diagnostics.length === 0) {
|
|
137
165
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
138
166
|
}
|
|
@@ -3,7 +3,43 @@ import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
|
3
3
|
import { getLinterPolicyForCwd, hasStylelintConfig, } from "../../tool-policy.js";
|
|
4
4
|
import { PRIORITY } from "../priorities.js";
|
|
5
5
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
6
|
+
import { parseToolRun } from "./utils/tool-failure.js";
|
|
6
7
|
const stylelint = createAvailabilityChecker("stylelint", ".cmd");
|
|
8
|
+
// stylelint exit codes (its "Exit codes" docs page): 0 = no problems, 1 = a
|
|
9
|
+
// fatal error, 2 = lint problems found, 78 = a configuration error.
|
|
10
|
+
//
|
|
11
|
+
// 1 is listed as a run here rather than a rejection. The evidence for that is
|
|
12
|
+
// NOT a live stylelint: it is this repo's own hand-written fixture
|
|
13
|
+
// (tests/clients/dispatch/runners/stylelint-fixable.test.ts), which reports
|
|
14
|
+
// findings under exit 1. Rather than rewrite a fixture whose provenance is
|
|
15
|
+
// unknown, the table keeps 1 permissive. 78 is the rejection this table
|
|
16
|
+
// exists to name.
|
|
17
|
+
//
|
|
18
|
+
// #1937 corrected the safety argument that used to sit here: it claimed a
|
|
19
|
+
// fatal stylelint "writes nothing to stdout", which is true but useless,
|
|
20
|
+
// because a stylelint that DID find problems writes nothing to stdout either.
|
|
21
|
+
// `stylelintReport` below is what now separates the two.
|
|
22
|
+
const STYLELINT_EXIT_CODES = { ran: [1, 2] };
|
|
23
|
+
/**
|
|
24
|
+
* The JSON report out of a stylelint run, whichever stream carried it (#1937).
|
|
25
|
+
*
|
|
26
|
+
* stylelint 16+ writes the formatted report to STDERR whenever the run
|
|
27
|
+
* "errored" — which is every run that found an error-severity warning, i.e.
|
|
28
|
+
* every run with something to say. Reading stdout alone parsed nothing and
|
|
29
|
+
* called the stylesheet clean, the #1933 vale shape. Verified against
|
|
30
|
+
* stylelint 17.8.0 in tests/fixtures/runner-output/stylelint/.
|
|
31
|
+
*
|
|
32
|
+
* Only a stream that actually starts a JSON array counts. A crash's stack
|
|
33
|
+
* trace on stderr must stay "nothing to parse" so #1816's empty-result skip
|
|
34
|
+
* still fires instead of reporting a clean file.
|
|
35
|
+
*/
|
|
36
|
+
export function stylelintReport(stdout, stderr) {
|
|
37
|
+
for (const stream of [stdout, stderr]) {
|
|
38
|
+
if (stream?.trimStart().startsWith("["))
|
|
39
|
+
return stream;
|
|
40
|
+
}
|
|
41
|
+
return "";
|
|
42
|
+
}
|
|
7
43
|
// Stylelint's standard JSON output reports only aggregate fixableErrorCount /
|
|
8
44
|
// fixableWarningCount per file — there is no per-warning fix flag in the CLI
|
|
9
45
|
// surface. To route the actionable warnings here without a tool rewrite, we
|
|
@@ -91,7 +127,7 @@ const stylelintRunner = {
|
|
|
91
127
|
ctx.log("stylelint: no config detected, running with default rules");
|
|
92
128
|
}
|
|
93
129
|
let cmd = null;
|
|
94
|
-
if (await
|
|
130
|
+
if (await stylelint.isAvailableAsync(cwd)) {
|
|
95
131
|
cmd = stylelint.getCommand(cwd);
|
|
96
132
|
}
|
|
97
133
|
else {
|
|
@@ -100,8 +136,16 @@ const stylelintRunner = {
|
|
|
100
136
|
if (!cmd)
|
|
101
137
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
102
138
|
const result = await safeSpawnAsync(cmd, ["--formatter", "json", ctx.filePath], { timeout: 20000, cwd });
|
|
103
|
-
|
|
104
|
-
|
|
139
|
+
// #1816: this runner read `result.status` zero times, so an exit-78
|
|
140
|
+
// config error (or an exit-1 crash) fell through parseStylelintJson's
|
|
141
|
+
// catch to zero diagnostics and reported a clean stylesheet.
|
|
142
|
+
const raw = stylelintReport(result.stdout, result.stderr);
|
|
143
|
+
// #1948: the stdout-vs-stderr report bug landed here as exit 2 plus a
|
|
144
|
+
// full JSON report and zero parsed warnings. That now leaves a record.
|
|
145
|
+
const run = parseToolRun("stylelint", { result, output: raw, exitCodes: STYLELINT_EXIT_CODES }, (out) => parseStylelintJson(out, ctx.filePath));
|
|
146
|
+
if (run.skipped)
|
|
147
|
+
return run.skipped;
|
|
148
|
+
const diagnostics = run.diagnostics;
|
|
105
149
|
if (diagnostics.length === 0) {
|
|
106
150
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
107
151
|
}
|
|
@@ -2,6 +2,7 @@ import * as path from "node:path";
|
|
|
2
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
3
|
import { PRIORITY } from "../priorities.js";
|
|
4
4
|
import { createAvailabilityChecker, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
5
|
+
import { parseToolRun } from "./utils/tool-failure.js";
|
|
5
6
|
const swiftlint = createAvailabilityChecker("swiftlint", ".exe");
|
|
6
7
|
// SwiftLint rules whose rule class declares a `corrector` — i.e. rules that
|
|
7
8
|
// `swiftlint --fix` rewrites deterministically. The JSON reporter does not
|
|
@@ -117,7 +118,7 @@ const swiftlintRunner = {
|
|
|
117
118
|
async run(ctx) {
|
|
118
119
|
const cwd = ctx.cwd || process.cwd();
|
|
119
120
|
let cmd = null;
|
|
120
|
-
if (await
|
|
121
|
+
if (await swiftlint.isAvailableAsync(cwd)) {
|
|
121
122
|
cmd = swiftlint.getCommand(cwd);
|
|
122
123
|
}
|
|
123
124
|
else {
|
|
@@ -126,9 +127,18 @@ const swiftlintRunner = {
|
|
|
126
127
|
if (!cmd)
|
|
127
128
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
128
129
|
const result = await safeSpawnAsync(cmd, ["--reporter", "json", path.resolve(cwd, ctx.filePath)], { cwd, timeout: 15000 });
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
// #1816: this runner read `result.status` zero times, so a SwiftLint
|
|
131
|
+
// that refused the invocation reported a clean Swift file. No exit-code
|
|
132
|
+
// table is declared: SwiftLint's nonzero codes are not documented
|
|
133
|
+
// stably enough to call any of them a rejection, so classification
|
|
134
|
+
// rests on the conservative rule — a nonzero exit with nothing to parse
|
|
135
|
+
// never ran.
|
|
136
|
+
// SwiftLint exits non-zero on violations — stdout still has the JSON, so
|
|
137
|
+
// a nonzero exit whose JSON yields nothing is a parser break (#1948).
|
|
138
|
+
const run = parseToolRun("swiftlint", { result }, (out) => parseSwiftLintOutput(out, ctx.filePath));
|
|
139
|
+
if (run.skipped)
|
|
140
|
+
return run.skipped;
|
|
141
|
+
const diagnostics = run.diagnostics;
|
|
132
142
|
if (diagnostics.length === 0) {
|
|
133
143
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
134
144
|
}
|
|
@@ -1,30 +1,104 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
+
import { findLocalBinUpwards } from "../../package-manager.js";
|
|
2
3
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
4
|
import { getLinterPolicyForCwd } from "../../tool-policy.js";
|
|
4
5
|
import { PRIORITY } from "../priorities.js";
|
|
5
6
|
import { createAvailabilityChecker, lspPrimaryCoversFile, resolveToolCommandWithInstallFallback, } from "./utils/runner-helpers.js";
|
|
6
|
-
import {
|
|
7
|
+
import { parseToolRun } from "./utils/tool-failure.js";
|
|
7
8
|
const taplo = createAvailabilityChecker("taplo", ".exe");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
// Verified against taplo 0.10.0: 0 = clean, 1 = the file is invalid (lint
|
|
10
|
+
// findings, or a schema it could not load), 2 = clap rejected the invocation.
|
|
11
|
+
//
|
|
12
|
+
// #1937 round 2: the parser fix alone turned the old silent-clean into a false
|
|
13
|
+
// BLOCKING diagnostic. clap prints `error: unexpected argument '--output'
|
|
14
|
+
// found`, which starts with the same lowercase `error:` a real taplo
|
|
15
|
+
// diagnostic does, so a mistyped flag would have reddened every valid TOML
|
|
16
|
+
// file. Both readings are wrong; the exit code is what separates them.
|
|
17
|
+
const TAPLO_EXIT_CODES = { ran: [1] };
|
|
18
|
+
/** `error: <summary>` or `warning: <summary>` at the head of a codespan block. */
|
|
19
|
+
const HEADER_PATTERN = /^\s*(error|warning):(.*)$/;
|
|
20
|
+
/** The box-drawing lead taplo puts on a codespan location line. */
|
|
21
|
+
const LOCATION_LEAD = "┌─";
|
|
22
|
+
/** The `:line:column` tail of a codespan location line. */
|
|
23
|
+
const LOCATION_PATTERN = /:(\d+):(\d+)$/;
|
|
24
|
+
/**
|
|
25
|
+
* Parse `taplo lint` output (#1937).
|
|
26
|
+
*
|
|
27
|
+
* This parser used to `JSON.parse` a `{ errors: [{ range, message, kind }] }`
|
|
28
|
+
* envelope that taplo has never emitted, fed by a `--output=json` flag taplo
|
|
29
|
+
* has never accepted. Real taplo rejected the flag with exit 2 and a usage
|
|
30
|
+
* error, the JSON parse threw, the catch returned [], and malformed TOML was
|
|
31
|
+
* reported clean. Same shape as the vale parser in #1933.
|
|
32
|
+
*
|
|
33
|
+
* Real taplo 0.10.0 writes codespan diagnostics to STDERR, interleaved with
|
|
34
|
+
* uppercase tracing lines:
|
|
35
|
+
*
|
|
36
|
+
* error: invalid TOML
|
|
37
|
+
* ┌─ /path/to/bad.toml:2:9
|
|
38
|
+
* │
|
|
39
|
+
* 2 │ [package
|
|
40
|
+
*
|
|
41
|
+
* Verified against tests/fixtures/runner-output/taplo/real.captured.json.
|
|
42
|
+
*
|
|
43
|
+
* A header alone is NOT enough to emit a diagnostic. The codespan location
|
|
44
|
+
* line must follow it. clap's own failures start with the same lowercase
|
|
45
|
+
* `error:` and carry no location, so without that requirement a rejected
|
|
46
|
+
* invocation becomes a blocking finding on line 1 of a perfectly valid file
|
|
47
|
+
* (#1937 round 2). The exit-code table in the runner is the primary guard;
|
|
48
|
+
* this is the structural one, and each covers a case the other does not.
|
|
49
|
+
*/
|
|
50
|
+
export function parseTaploOutput(raw, filePath) {
|
|
51
|
+
const diagnostics = [];
|
|
52
|
+
const lines = (raw ?? "").split(/\r?\n/);
|
|
53
|
+
for (let i = 0; i < lines.length; i++) {
|
|
54
|
+
// Lowercase `error:`/`warning:` starts a diagnostic. taplo's tracing
|
|
55
|
+
// lines are uppercase (`ERROR taplo:lint_files: ...`), so a
|
|
56
|
+
// case-sensitive match keeps them out.
|
|
57
|
+
//
|
|
58
|
+
// Both patterns below trim in code rather than with a trailing `\s*`,
|
|
59
|
+
// and the location one tests for its box-drawing lead separately
|
|
60
|
+
// instead of skipping to it with `.*`. Either shape backtracks
|
|
61
|
+
// super-linearly on a long line, and this parser reads bytes a third
|
|
62
|
+
// party wrote.
|
|
63
|
+
const header = HEADER_PATTERN.exec(lines[i].trimEnd());
|
|
64
|
+
if (!header)
|
|
65
|
+
continue;
|
|
66
|
+
const severityWord = header[1];
|
|
67
|
+
const summary = header[2].trim();
|
|
68
|
+
if (!summary)
|
|
69
|
+
continue;
|
|
70
|
+
// The location arrives on a following `┌─ file:line:col` line. Scan a
|
|
71
|
+
// short window rather than assuming adjacency: taplo puts a gutter line
|
|
72
|
+
// between them in some layouts.
|
|
73
|
+
let line = null;
|
|
74
|
+
let column = 1;
|
|
75
|
+
for (let j = i + 1; j < Math.min(i + 4, lines.length); j++) {
|
|
76
|
+
if (!lines[j].includes(LOCATION_LEAD))
|
|
77
|
+
continue;
|
|
78
|
+
const location = LOCATION_PATTERN.exec(lines[j].trimEnd());
|
|
79
|
+
if (!location)
|
|
80
|
+
continue;
|
|
81
|
+
line = Number.parseInt(location[1], 10) || 1;
|
|
82
|
+
column = Number.parseInt(location[2], 10) || 1;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
if (line === null)
|
|
86
|
+
continue;
|
|
87
|
+
const severity = severityWord === "warning" ? "warning" : "error";
|
|
88
|
+
diagnostics.push({
|
|
89
|
+
id: `taplo-${severity}-${line}-${column}`,
|
|
90
|
+
message: summary,
|
|
15
91
|
filePath,
|
|
16
|
-
line
|
|
17
|
-
column
|
|
18
|
-
severity
|
|
19
|
-
semantic: "blocking",
|
|
92
|
+
line,
|
|
93
|
+
column,
|
|
94
|
+
severity,
|
|
95
|
+
semantic: severity === "error" ? "blocking" : "warning",
|
|
20
96
|
tool: "taplo",
|
|
21
|
-
rule:
|
|
97
|
+
rule: `taplo/${severity}`,
|
|
22
98
|
fixable: false,
|
|
23
|
-
})
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
return [];
|
|
99
|
+
});
|
|
27
100
|
}
|
|
101
|
+
return diagnostics;
|
|
28
102
|
}
|
|
29
103
|
const taploRunner = {
|
|
30
104
|
id: "taplo",
|
|
@@ -45,21 +119,46 @@ const taploRunner = {
|
|
|
45
119
|
if (lspPrimaryCoversFile(ctx, "toml") && (await ctx.hasTool("taplo"))) {
|
|
46
120
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
47
121
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
122
|
+
// Project binary first (#1731, discipline B): `taplo.isAvailableAsync`
|
|
123
|
+
// resolves through `findManagedNodeToolBinary`, pi-lens's own managed
|
|
124
|
+
// shim — checked BEFORE any project-local candidate, so a project's own
|
|
125
|
+
// `node_modules/.bin/taplo` (npm `@taplo/cli`) never won once the managed
|
|
126
|
+
// copy answered. `findLocalBinUpwards` defaults to `.cmd` on Windows,
|
|
127
|
+
// matching that npm shim; the availability checker's `.exe` extension is
|
|
128
|
+
// correct for pi-lens's OWN managed install (a GitHub-release binary,
|
|
129
|
+
// `clients/installer/index.ts` taplo entry), a different artifact with a
|
|
130
|
+
// different extension, so it stays as the checker's fallback only.
|
|
131
|
+
let cmd = findLocalBinUpwards("taplo", cwd) ?? null;
|
|
132
|
+
if (!cmd) {
|
|
133
|
+
if (await taplo.isAvailableAsync(cwd)) {
|
|
134
|
+
cmd = taplo.getCommand(cwd);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
cmd = await resolveToolCommandWithInstallFallback(cwd, "taplo");
|
|
138
|
+
}
|
|
54
139
|
}
|
|
55
140
|
if (!cmd)
|
|
56
141
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
57
142
|
const absPath = path.resolve(cwd, ctx.filePath);
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
143
|
+
// #1937: `--output=json` is not a taplo flag. taplo rejected it with a
|
|
144
|
+
// usage error, so this runner never linted anything. `--colors never`
|
|
145
|
+
// keeps ANSI escapes out of the bytes the parser reads.
|
|
146
|
+
const result = await safeSpawnAsync(cmd, ["check", "--colors", "never", absPath], { cwd, timeout: 15000 });
|
|
147
|
+
// taplo reports on stderr and leaves stdout empty, so the
|
|
148
|
+
// "nothing to parse" test must read the same string the parser gets —
|
|
149
|
+
// otherwise every real run looks like a failed spawn.
|
|
150
|
+
const raw = result.stderr?.trim() ? result.stderr : (result.stdout ?? "");
|
|
151
|
+
//
|
|
152
|
+
// taplo exits 1 only when a file is INVALID, and it does not always draw
|
|
153
|
+
// a codespan block when it does: a schema it could not load is reported
|
|
154
|
+
// through its tracing output alone. Claiming that file clean would be an
|
|
155
|
+
// outright lie, so taplo opts into `skipWhenParsedNothing` (#1948). This
|
|
156
|
+
// replaces a hand-rolled per-runner copy of the same rule, which wrote
|
|
157
|
+
// its own `runner-empty-result` row with its own wording.
|
|
158
|
+
const run = parseToolRun("taplo", { result, output: raw, exitCodes: TAPLO_EXIT_CODES }, (out) => parseTaploOutput(out, ctx.filePath), { skipWhenParsedNothing: true });
|
|
159
|
+
if (run.skipped)
|
|
160
|
+
return run.skipped;
|
|
161
|
+
const diagnostics = run.diagnostics;
|
|
63
162
|
if (diagnostics.length === 0) {
|
|
64
163
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
65
164
|
}
|
|
@@ -2,9 +2,9 @@ import * as path from "node:path";
|
|
|
2
2
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
3
3
|
import { getLinterPolicyForCwd } from "../../tool-policy.js";
|
|
4
4
|
import { findNearestDirWithAnyBasename } from "../../workspace-topology.js";
|
|
5
|
-
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
6
|
-
import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
|
|
7
5
|
import { PRIORITY } from "../priorities.js";
|
|
6
|
+
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
7
|
+
import { parseToolRun } from "./utils/tool-failure.js";
|
|
8
8
|
const tflint = createAvailabilityChecker("tflint", ".exe");
|
|
9
9
|
const TFLINT_CONFIG = ".tflint.hcl";
|
|
10
10
|
/**
|
|
@@ -58,7 +58,7 @@ const tflintRunner = {
|
|
|
58
58
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
59
59
|
}
|
|
60
60
|
let cmd = null;
|
|
61
|
-
if (await
|
|
61
|
+
if (await tflint.isAvailableAsync(cwd)) {
|
|
62
62
|
cmd = tflint.getCommand(cwd);
|
|
63
63
|
}
|
|
64
64
|
else {
|
|
@@ -82,10 +82,15 @@ const tflintRunner = {
|
|
|
82
82
|
cwd: fileDir,
|
|
83
83
|
timeout: 30000,
|
|
84
84
|
});
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
// #1948: tflint exits nonzero and writes its JSON report to stdout, so a
|
|
86
|
+
// nonzero exit whose report yields zero diagnostics is a parser break,
|
|
87
|
+
// not a clean file. No exit-code table: tflint's nonzero codes are not
|
|
88
|
+
// verified against a real binary here, so the conservative
|
|
89
|
+
// nothing-to-parse rule stays the only discriminator.
|
|
90
|
+
const run = parseToolRun("tflint", { result }, (out) => parseTflintOutput(out, ctx.filePath));
|
|
91
|
+
if (run.skipped)
|
|
92
|
+
return run.skipped;
|
|
93
|
+
const diagnostics = run.diagnostics;
|
|
89
94
|
if (diagnostics.length === 0) {
|
|
90
95
|
return { status: "succeeded", diagnostics: [], semantic: "none" };
|
|
91
96
|
}
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
* v1 scope — the highest-value, lowest-overlap surface:
|
|
11
11
|
* - **Kubernetes manifests** (yaml with an `apiVersion:` + `kind:` signature):
|
|
12
12
|
* zero existing coverage in pi-lens, so no dedup needed.
|
|
13
|
+
* - **CloudFormation templates** (yaml OR json with an
|
|
14
|
+
* `AWSTemplateFormatVersion` key, or a `Resources` map whose entries carry
|
|
15
|
+
* an `AWS::`/`Custom::`-namespaced `Type`; refs #1757): same zero-overlap
|
|
16
|
+
* rationale as Kubernetes — trivy's `cloudformation` misconfig scanner is
|
|
17
|
+
* the only IaC-misconfig coverage pi-lens has for CFN.
|
|
13
18
|
* - **Dockerfiles**: overlaps hadolint on a few rules (`:latest`, root, …);
|
|
14
19
|
* the dispatcher suppresses trivy-config findings that hadolint already
|
|
15
20
|
* reports at the same line (`suppressTrivyConfigDockerOverlap`), so trivy
|
|
@@ -17,12 +22,11 @@
|
|
|
17
22
|
*
|
|
18
23
|
* - **Terraform**: the `.tf` language files themselves — trivy evaluates
|
|
19
24
|
* the Terraform language directly, so no content gate is needed (unlike
|
|
20
|
-
* the yaml/k8s
|
|
21
|
-
* excluded: trivy has no terragrunt support, and terragrunt
|
|
22
|
-
* covered by the terragrunt runner instead.
|
|
25
|
+
* the yaml/k8s/CloudFormation heuristics above). Terragrunt (`.hcl`) is
|
|
26
|
+
* deliberately excluded: trivy has no terragrunt support, and terragrunt
|
|
27
|
+
* config is covered by the terragrunt runner instead.
|
|
23
28
|
*
|
|
24
|
-
* Deferred (tracked on #131): Helm chart rendering, Docker Compose
|
|
25
|
-
* CloudFormation.
|
|
29
|
+
* Deferred (tracked on #131): Helm chart rendering, Docker Compose.
|
|
26
30
|
*
|
|
27
31
|
* Gating: the same explicit `trivy.enabled` opt-in as the session-scan modes —
|
|
28
32
|
* trivy is opt-in, period. (Misconfig needs only the small policy bundle, not
|
|
@@ -31,13 +35,14 @@
|
|
|
31
35
|
*
|
|
32
36
|
* Refs: #131 (Mode 2)
|
|
33
37
|
*/
|
|
38
|
+
import { formatToolFailure } from "./utils/tool-failure.js";
|
|
34
39
|
import * as fs from "node:fs";
|
|
35
40
|
import * as path from "node:path";
|
|
41
|
+
import { incrementDegradationCount } from "../../degradation-ledger.js";
|
|
36
42
|
import { safeSpawnAsync } from "../../safe-spawn.js";
|
|
37
43
|
import { isTrivyEnabled, resolveSeverityFloor, } from "../../trivy-client.js";
|
|
38
44
|
import { PRIORITY } from "../priorities.js";
|
|
39
45
|
import { createAvailabilityChecker, resolveAvailableOrInstall, } from "./utils/runner-helpers.js";
|
|
40
|
-
import { spawnFailedWithNoOutput } from "./utils/spawn-outcome.js";
|
|
41
46
|
const trivy = createAvailabilityChecker("trivy", ".exe");
|
|
42
47
|
/**
|
|
43
48
|
* Heuristic: does this YAML look like a Kubernetes manifest (vs a CI workflow,
|
|
@@ -53,6 +58,23 @@ export function looksLikeKubernetesManifest(content) {
|
|
|
53
58
|
}
|
|
54
59
|
return false;
|
|
55
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Heuristic: does this file (yaml OR json) look like a CloudFormation
|
|
63
|
+
* template? The unambiguous signal is the `AWSTemplateFormatVersion` key,
|
|
64
|
+
* present on the vast majority of real templates; SAM templates instead
|
|
65
|
+
* declare `Transform: AWS::Serverless-2016-10-31` (or an array containing
|
|
66
|
+
* it). Templates that skip both still always declare a `Resources` map whose
|
|
67
|
+
* entries carry a `Type` in the `AWS::`/`Custom::`/`Alexa::` namespaces — the
|
|
68
|
+
* one field CFN mandates on every resource. Any one signal qualifies (refs
|
|
69
|
+
* #1757).
|
|
70
|
+
*/
|
|
71
|
+
export function looksLikeCloudFormationTemplate(content) {
|
|
72
|
+
if (/AWSTemplateFormatVersion/.test(content))
|
|
73
|
+
return true;
|
|
74
|
+
if (/Transform:\s*(\[.*)?["']?AWS::Serverless/.test(content))
|
|
75
|
+
return true;
|
|
76
|
+
return /Type["']?\s*:\s*["']?(AWS|Custom|Alexa)::/.test(content);
|
|
77
|
+
}
|
|
56
78
|
function normalizeSeverity(raw) {
|
|
57
79
|
const s = typeof raw === "string" ? raw.toUpperCase() : "";
|
|
58
80
|
if (s === "CRITICAL" || s === "HIGH" || s === "MEDIUM" || s === "LOW") {
|
|
@@ -122,7 +144,7 @@ export function parseTrivyConfigOutput(raw, filePath) {
|
|
|
122
144
|
}
|
|
123
145
|
const trivyConfigRunner = {
|
|
124
146
|
id: "trivy-config",
|
|
125
|
-
appliesTo: ["docker", "yaml", "terraform"],
|
|
147
|
+
appliesTo: ["docker", "yaml", "terraform", "json"],
|
|
126
148
|
priority: PRIORITY.GENERAL_ANALYSIS,
|
|
127
149
|
enabledByDefault: true,
|
|
128
150
|
skipTestFiles: false,
|
|
@@ -133,8 +155,10 @@ const trivyConfigRunner = {
|
|
|
133
155
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
134
156
|
}
|
|
135
157
|
const absPath = path.resolve(cwd, ctx.filePath);
|
|
136
|
-
// YAML is far broader than k8s;
|
|
137
|
-
|
|
158
|
+
// YAML is far broader than k8s/CloudFormation; JSON is far broader than
|
|
159
|
+
// CloudFormation — only scan files that look like one of the IaC
|
|
160
|
+
// manifest shapes trivy's misconfig scanners understand (refs #1757).
|
|
161
|
+
if (ctx.kind === "yaml" || ctx.kind === "json") {
|
|
138
162
|
let content = "";
|
|
139
163
|
try {
|
|
140
164
|
content = fs.readFileSync(absPath, "utf-8");
|
|
@@ -142,7 +166,11 @@ const trivyConfigRunner = {
|
|
|
142
166
|
catch {
|
|
143
167
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
144
168
|
}
|
|
145
|
-
|
|
169
|
+
const isManifest = ctx.kind === "yaml"
|
|
170
|
+
? looksLikeKubernetesManifest(content) ||
|
|
171
|
+
looksLikeCloudFormationTemplate(content)
|
|
172
|
+
: looksLikeCloudFormationTemplate(content);
|
|
173
|
+
if (!isManifest) {
|
|
146
174
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
147
175
|
}
|
|
148
176
|
}
|
|
@@ -160,15 +188,48 @@ const trivyConfigRunner = {
|
|
|
160
188
|
const severities = resolveSeverityFloor(cwd).join(",");
|
|
161
189
|
const result = await safeSpawnAsync(cmd, [
|
|
162
190
|
"config",
|
|
191
|
+
// `--quiet` alone suppresses both the progress bar and log output.
|
|
192
|
+
// `--no-progress` is NOT a `config` subcommand flag (unlike `fs`,
|
|
193
|
+
// which does accept it) — trivy 0.73.0 exits 1 on the rejected
|
|
194
|
+
// flag, but prints its full usage/help text (thousands of bytes)
|
|
195
|
+
// to STDOUT before the FATAL line on stderr. That stdout is
|
|
196
|
+
// non-empty, so an empty-output-only guard did not catch it: the
|
|
197
|
+
// help text failed to JSON-parse, `parseTrivyConfigOutput`
|
|
198
|
+
// returned `[]`, and this reported `{ status: "succeeded",
|
|
199
|
+
// diagnostics: [] }` — a clean scan — on every single real
|
|
200
|
+
// invocation (refs #1757; verified against the real installed
|
|
201
|
+
// binary, not assumed).
|
|
163
202
|
"--quiet",
|
|
164
|
-
"--no-progress",
|
|
165
203
|
"--format",
|
|
166
204
|
"json",
|
|
167
205
|
"--severity",
|
|
168
206
|
severities,
|
|
169
207
|
absPath,
|
|
170
208
|
], { cwd, timeout: 60_000 });
|
|
171
|
-
|
|
209
|
+
// `trivy config` is not given `--exit-code`, so it exits 0 whenever it
|
|
210
|
+
// completed (findings included — see parseTrivyConfigOutput's severity
|
|
211
|
+
// mapping for how CRITICAL becomes blocking). ANY nonzero status is
|
|
212
|
+
// therefore a real error, WITH or WITHOUT something on stdout — mirrors
|
|
213
|
+
// the model already in clients/dispatch/runners/helm-render.ts's
|
|
214
|
+
// runIacPass, which has the same "trivy prints usage text on a bad
|
|
215
|
+
// flag" exposure and already got this right. A bounded ledger record
|
|
216
|
+
// means a broken trivy invocation can no longer go unnoticed for an
|
|
217
|
+
// entire lane's lifetime the way this one did (refs #1757).
|
|
218
|
+
if (result.error || result.status !== 0) {
|
|
219
|
+
// #1816: one shared wording, one truncation, signal named. `subject`
|
|
220
|
+
// stays the file path — the discriminating identity a reader needs
|
|
221
|
+
// is WHICH file trivy stopped covering.
|
|
222
|
+
incrementDegradationCount({
|
|
223
|
+
kind: "runner-empty-result",
|
|
224
|
+
subject: absPath,
|
|
225
|
+
reason: formatToolFailure({
|
|
226
|
+
tool: "trivy config",
|
|
227
|
+
status: result.status,
|
|
228
|
+
signal: result.signal,
|
|
229
|
+
stderr: result.stderr || result.error?.message,
|
|
230
|
+
stdout: result.stdout,
|
|
231
|
+
}),
|
|
232
|
+
});
|
|
172
233
|
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
173
234
|
}
|
|
174
235
|
const diagnostics = parseTrivyConfigOutput(result.stdout || "", ctx.filePath);
|