@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
|
@@ -82,11 +82,14 @@
|
|
|
82
82
|
*/
|
|
83
83
|
import * as fs from "node:fs";
|
|
84
84
|
import * as path from "node:path";
|
|
85
|
+
import { applyDispositionsMultiFile } from "../diagnostic-dispositions.js";
|
|
85
86
|
import { getKnipIgnorePatterns } from "../file-utils.js";
|
|
86
87
|
import { isAtOrAboveHomeDir } from "../path-utils.js";
|
|
87
88
|
import { GitleaksClient } from "../gitleaks-client.js";
|
|
88
89
|
import { GovulncheckClient } from "../govulncheck-client.js";
|
|
90
|
+
import { isToolInstallAllowedByTrust, projectTrustDenialReason, } from "../project-trust.js";
|
|
89
91
|
import { TrivyClient } from "../trivy-client.js";
|
|
92
|
+
import { reasonFromAvailabilityVerdict } from "./extractors.js";
|
|
90
93
|
import { deadCodeResultToProjectDiagnostics } from "./runner-adapters/dead-code.js";
|
|
91
94
|
import { gitleaksResultToProjectDiagnostics } from "./runner-adapters/gitleaks.js";
|
|
92
95
|
import { govulncheckResultToProjectDiagnostics } from "./runner-adapters/govulncheck.js";
|
|
@@ -141,11 +144,13 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
141
144
|
// / review-graph's buildOrUpdateGraph; like the latter, there is no safe
|
|
142
145
|
// substitute root to fall back to — the caller's `paths` scope only filters
|
|
143
146
|
// REPORTED results, it never narrows what these analyzers walk.
|
|
147
|
+
const unsafeRootReason = "the working directory resolves at or above the home directory; heavyweight analyzers refuse to walk from there (#747)";
|
|
144
148
|
if (isAtOrAboveHomeDir(analysisRoot, options.homeDir)) {
|
|
145
149
|
return {
|
|
146
150
|
diagnostics: [],
|
|
147
151
|
runners: [],
|
|
148
152
|
cold: [...ANALYZER_IDS],
|
|
153
|
+
coldReasons: Object.fromEntries(ANALYZER_IDS.map((id) => [id, unsafeRootReason])),
|
|
149
154
|
failed: [],
|
|
150
155
|
timings: {},
|
|
151
156
|
unsafeRoot: true,
|
|
@@ -154,13 +159,46 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
154
159
|
const diagnostics = [];
|
|
155
160
|
const runners = [];
|
|
156
161
|
const cold = [];
|
|
162
|
+
// #1623: the specific reason each `cold` id was skipped, captured at the
|
|
163
|
+
// gate that decided it — see FreshProjectDiagnosticsResult.coldReasons.
|
|
164
|
+
const coldReasons = {};
|
|
157
165
|
const failed = [];
|
|
158
166
|
const timings = {};
|
|
167
|
+
// #1623: ms-old each id's data was when this call read it, for lanes that
|
|
168
|
+
// are cache-reads by design (currently only test-runner — see its task
|
|
169
|
+
// below) rather than a fresh execution this call. Absent for every other
|
|
170
|
+
// key: this module's other lanes always trigger-or-join a genuine run
|
|
171
|
+
// when attempted (see the module header), so there is nothing to date.
|
|
172
|
+
const cachedAgeMs = {};
|
|
159
173
|
const settledIds = new Set();
|
|
174
|
+
let dispositionSuppressed = 0;
|
|
175
|
+
const dispositionSuppressedByLane = {};
|
|
176
|
+
// #1617: this is the ONE choke point every analyzer's findings pass
|
|
177
|
+
// through on the way into `diagnostics`, so applying the agent/user
|
|
178
|
+
// disposition filter HERE covers the whole mode=full class (knip/jscpd/
|
|
179
|
+
// madge/gitleaks/govulncheck/opengrep/trivy/dead-code) in one place — the
|
|
180
|
+
// same anchor derivation `dispatcher.ts:924` uses, via
|
|
181
|
+
// `applyDispositionsMultiFile` (`diagnostic-dispositions.ts`), not a
|
|
182
|
+
// second cloned filter. Unlike the dispatch path's one-file-at-a-time
|
|
183
|
+
// shape, a project-wide scan's findings span many files, so this groups by
|
|
184
|
+
// each diagnostic's own `filePath` and reads each file's current content
|
|
185
|
+
// once — see that function's doc for the fail-open contract when a file
|
|
186
|
+
// can't be read.
|
|
187
|
+
function markCold(id, reason) {
|
|
188
|
+
pushUnique(cold, id);
|
|
189
|
+
coldReasons[id] = reason;
|
|
190
|
+
}
|
|
160
191
|
function record(id, adapted, elapsedMs) {
|
|
161
192
|
timings[id] = (timings[id] ?? 0) + elapsedMs;
|
|
162
|
-
|
|
163
|
-
|
|
193
|
+
const kept = applyDispositionsMultiFile(adapted, analysisRoot, (d) => d.filePath);
|
|
194
|
+
const suppressedHere = adapted.length - kept.length;
|
|
195
|
+
dispositionSuppressed += suppressedHere;
|
|
196
|
+
if (suppressedHere > 0) {
|
|
197
|
+
dispositionSuppressedByLane[id] =
|
|
198
|
+
(dispositionSuppressedByLane[id] ?? 0) + suppressedHere;
|
|
199
|
+
}
|
|
200
|
+
if (kept.length > 0) {
|
|
201
|
+
diagnostics.push(...kept);
|
|
164
202
|
pushUnique(runners, id);
|
|
165
203
|
}
|
|
166
204
|
}
|
|
@@ -194,7 +232,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
194
232
|
// detection, exactly mirroring session_start's own logic.
|
|
195
233
|
task("jscpd", async () => {
|
|
196
234
|
if (!(await clients.jscpdClient.ensureAvailable())) {
|
|
197
|
-
|
|
235
|
+
markCold("jscpd", reasonFromAvailabilityVerdict("jscpd", clients.jscpdClient.getAvailabilityVerdict?.()));
|
|
198
236
|
return;
|
|
199
237
|
}
|
|
200
238
|
const isTsProject = fs.existsSync(path.join(analysisRoot, "tsconfig.json"));
|
|
@@ -213,7 +251,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
213
251
|
// madge — circular-dependency detection.
|
|
214
252
|
task("madge", async () => {
|
|
215
253
|
if (!(await clients.depChecker.ensureAvailable())) {
|
|
216
|
-
|
|
254
|
+
markCold("madge", reasonFromAvailabilityVerdict("madge", clients.depChecker.getAvailabilityVerdict?.()));
|
|
217
255
|
return;
|
|
218
256
|
}
|
|
219
257
|
const startMs = Date.now();
|
|
@@ -234,11 +272,11 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
234
272
|
// "cold" on a project with no explicit gitleaks config.
|
|
235
273
|
task("gitleaks", async () => {
|
|
236
274
|
if (!GitleaksClient.hasGitRepo(analysisRoot)) {
|
|
237
|
-
|
|
275
|
+
markCold("gitleaks", "not a git repository (no .git found)");
|
|
238
276
|
return;
|
|
239
277
|
}
|
|
240
278
|
if (!(await clients.gitleaksClient.ensureAvailable())) {
|
|
241
|
-
|
|
279
|
+
markCold("gitleaks", reasonFromAvailabilityVerdict("gitleaks", clients.gitleaksClient.getAvailabilityVerdict?.()));
|
|
242
280
|
return;
|
|
243
281
|
}
|
|
244
282
|
const startMs = Date.now();
|
|
@@ -257,11 +295,22 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
257
295
|
// govulncheck — Go module CVE detection. Go-module-gated per #132.
|
|
258
296
|
task("govulncheck", async () => {
|
|
259
297
|
if (!GovulncheckClient.hasGoModule(analysisRoot)) {
|
|
260
|
-
|
|
298
|
+
markCold("govulncheck", "no go.mod found (not a Go module)");
|
|
261
299
|
return;
|
|
262
300
|
}
|
|
263
301
|
if (!(await clients.govulncheckClient.ensureAvailable())) {
|
|
264
|
-
|
|
302
|
+
// #1623 fix-round F1: `GovulncheckClient.doEnsureAvailable` has a
|
|
303
|
+
// branch (`assertInstallAllowed`, govulncheck-client.ts) that returns
|
|
304
|
+
// false WITHOUT ever touching its availability latch — a
|
|
305
|
+
// project-trust install denial, deliberately not latched so a later
|
|
306
|
+
// trust grant can retry (see that file's own comment). The latch's
|
|
307
|
+
// verdict is genuinely absent in that case, not merely unread, so
|
|
308
|
+
// check trust denial FIRST via the same taxonomy project-trust.ts
|
|
309
|
+
// already exposes, and only fall back to the probe-based verdict
|
|
310
|
+
// (a real timeout/absence) when trust isn't the reason.
|
|
311
|
+
markCold("govulncheck", isToolInstallAllowedByTrust()
|
|
312
|
+
? reasonFromAvailabilityVerdict("govulncheck", clients.govulncheckClient.getAvailabilityVerdict?.())
|
|
313
|
+
: (projectTrustDenialReason() ?? "govulncheck binary unavailable"));
|
|
265
314
|
return;
|
|
266
315
|
}
|
|
267
316
|
const startMs = Date.now();
|
|
@@ -291,7 +340,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
291
340
|
// `lens_diagnostics mode=full` — the honesty gap (#533) this task closes.
|
|
292
341
|
task("opengrep", async () => {
|
|
293
342
|
if (!(await clients.opengrepClient.ensureAvailable())) {
|
|
294
|
-
|
|
343
|
+
markCold("opengrep", reasonFromAvailabilityVerdict("opengrep", clients.opengrepClient.getAvailabilityVerdict?.()));
|
|
295
344
|
return;
|
|
296
345
|
}
|
|
297
346
|
const startMs = Date.now();
|
|
@@ -308,11 +357,11 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
308
357
|
// trivy — dependency CVE detection. Explicit opt-in per #131.
|
|
309
358
|
task("trivy", async () => {
|
|
310
359
|
if (!TrivyClient.shouldScan(analysisRoot)) {
|
|
311
|
-
|
|
360
|
+
markCold("trivy", "not opted in (.pi-lens.json trivy.enabled) or no dependency manifest found");
|
|
312
361
|
return;
|
|
313
362
|
}
|
|
314
363
|
if (!(await clients.trivyClient.ensureAvailable())) {
|
|
315
|
-
|
|
364
|
+
markCold("trivy", reasonFromAvailabilityVerdict("trivy", clients.trivyClient.getAvailabilityVerdict?.()));
|
|
316
365
|
return;
|
|
317
366
|
}
|
|
318
367
|
const startMs = Date.now();
|
|
@@ -332,7 +381,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
332
381
|
task("dead-code", async () => {
|
|
333
382
|
const applicable = clients.deadCodeClients.filter((c) => c.detect(analysisRoot));
|
|
334
383
|
if (applicable.length === 0) {
|
|
335
|
-
|
|
384
|
+
markCold("dead-code", "no dead-code client detected an applicable language for this project");
|
|
336
385
|
return;
|
|
337
386
|
}
|
|
338
387
|
await Promise.all(applicable.map(async (client) => {
|
|
@@ -380,9 +429,16 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
380
429
|
const startMs = Date.now();
|
|
381
430
|
const cached = cacheManager.readCache("test-runner-findings", analysisRoot);
|
|
382
431
|
if (!cached?.data) {
|
|
383
|
-
|
|
432
|
+
markCold("test-runner", "no turn_end test-runner cache entry yet this session");
|
|
384
433
|
return;
|
|
385
434
|
}
|
|
435
|
+
// #1623: unlike every other lane in this module, test-runner is a
|
|
436
|
+
// cache-read BY DESIGN (see the task's own header comment above) — it
|
|
437
|
+
// never performs a fresh run this call, so its age must be surfaced
|
|
438
|
+
// the same way a genuinely-stale cache read would be, rather than
|
|
439
|
+
// looking indistinguishable from a lane that just executed.
|
|
440
|
+
cachedAgeMs["test-runner"] =
|
|
441
|
+
Date.now() - new Date(cached.meta.timestamp).getTime();
|
|
386
442
|
record("test-runner", testRunnerFindingsToProjectDiagnostics(cached.data, analysisRoot, options.runtime), Date.now() - startMs);
|
|
387
443
|
}),
|
|
388
444
|
];
|
|
@@ -414,11 +470,25 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
414
470
|
diagnostics,
|
|
415
471
|
runners,
|
|
416
472
|
cold,
|
|
473
|
+
coldReasons,
|
|
417
474
|
failed,
|
|
418
475
|
timings,
|
|
476
|
+
cachedAgeMs,
|
|
419
477
|
aborted: true,
|
|
420
478
|
abortedIds,
|
|
479
|
+
dispositionSuppressed,
|
|
480
|
+
dispositionSuppressedByLane,
|
|
421
481
|
};
|
|
422
482
|
}
|
|
423
|
-
return {
|
|
483
|
+
return {
|
|
484
|
+
diagnostics,
|
|
485
|
+
runners,
|
|
486
|
+
cold,
|
|
487
|
+
coldReasons,
|
|
488
|
+
failed,
|
|
489
|
+
timings,
|
|
490
|
+
cachedAgeMs,
|
|
491
|
+
dispositionSuppressed,
|
|
492
|
+
dispositionSuppressedByLane,
|
|
493
|
+
};
|
|
424
494
|
}
|
|
@@ -2,19 +2,31 @@ import * as path from "node:path";
|
|
|
2
2
|
/**
|
|
3
3
|
* A gitleaks finding is a leaked secret at a concrete `file:startLine`. Secrets
|
|
4
4
|
* are treated as **blocking** — a committed credential is not a style nit.
|
|
5
|
+
*
|
|
6
|
+
* Exception: `pathStatus: "scratch"` (#1562 review-round F2) — a finding
|
|
7
|
+
* `classifyAndFilterFindings` demoted rather than dropped, so the observability
|
|
8
|
+
* criterion ("record carries tracked/ignored/scratch status") stays honest
|
|
9
|
+
* about a fourth REACHABLE value instead of silently deleting it. Demoted to
|
|
10
|
+
* `severity: "info"`/`semantic: "none"` so it can never read as a blocking
|
|
11
|
+
* "leaked secret" alarm, while remaining visible for an audit read.
|
|
5
12
|
*/
|
|
6
13
|
export function gitleaksFindingToProjectDiagnostic(cwd, finding) {
|
|
14
|
+
// #1562 observability criterion: surface the git status right in the
|
|
15
|
+
// finding's message so a triage is a read, not a re-derivation. Omitted
|
|
16
|
+
// when git itself degraded (`pathStatus` undefined) rather than guessed.
|
|
17
|
+
const statusSuffix = finding.pathStatus ? ` [git: ${finding.pathStatus}]` : "";
|
|
18
|
+
const isScratch = finding.pathStatus === "scratch";
|
|
7
19
|
return {
|
|
8
20
|
filePath: path.isAbsolute(finding.file)
|
|
9
21
|
? finding.file
|
|
10
22
|
: path.resolve(cwd, finding.file),
|
|
11
23
|
line: finding.startLine,
|
|
12
|
-
severity: "error",
|
|
13
|
-
semantic: "blocking",
|
|
24
|
+
severity: isScratch ? "info" : "error",
|
|
25
|
+
semantic: isScratch ? "none" : "blocking",
|
|
14
26
|
tool: "gitleaks",
|
|
15
27
|
runner: "gitleaks",
|
|
16
28
|
rule: `gitleaks:${finding.ruleId}`,
|
|
17
|
-
message: `Potential secret: ${finding.description || finding.ruleId}`,
|
|
29
|
+
message: `Potential secret: ${finding.description || finding.ruleId}${statusSuffix}`,
|
|
18
30
|
source: "project-scan",
|
|
19
31
|
};
|
|
20
32
|
}
|
|
@@ -24,8 +24,56 @@ export function trivyFindingToProjectDiagnostic(cwd, finding) {
|
|
|
24
24
|
source: "project-scan",
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* A trivy *secret* finding (`TrivyResult.secrets`) is a leaked credential at a
|
|
29
|
+
* concrete `file:line` — the trivy-scanned sibling of
|
|
30
|
+
* `gitleaksFindingToProjectDiagnostic`, and treated the same way: **blocking**,
|
|
31
|
+
* since a committed credential is not a style nit.
|
|
32
|
+
*
|
|
33
|
+
* Rule id is namespaced `trivy-secret:<ruleId>`, deliberately distinct from the
|
|
34
|
+
* CVE lane's `trivy:<vulnerabilityId>` (#1628) — trivy's own rule-id spaces for
|
|
35
|
+
* secrets and CVEs are independent, so without this prefix a secret rule id
|
|
36
|
+
* could collide with a vulnerability id and silently share (or steal) that
|
|
37
|
+
* finding's disposition anchor.
|
|
38
|
+
*/
|
|
39
|
+
export function trivySecretFindingToProjectDiagnostic(cwd, finding) {
|
|
40
|
+
return {
|
|
41
|
+
filePath: path.isAbsolute(finding.file)
|
|
42
|
+
? finding.file
|
|
43
|
+
: path.resolve(cwd, finding.file),
|
|
44
|
+
line: finding.line,
|
|
45
|
+
severity: "error",
|
|
46
|
+
semantic: "blocking",
|
|
47
|
+
tool: "trivy",
|
|
48
|
+
runner: "trivy",
|
|
49
|
+
rule: `trivy-secret:${finding.ruleId}`,
|
|
50
|
+
message: `Potential secret: ${finding.title || finding.ruleId}`,
|
|
51
|
+
source: "project-scan",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function trivySecretsToProjectDiagnostics(cwd, secrets) {
|
|
55
|
+
return secrets.map((finding) => trivySecretFindingToProjectDiagnostic(cwd, finding));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Adapts BOTH of trivy's finding kinds from one scan pass — CVEs (`findings`)
|
|
59
|
+
* and secrets (`secrets`, #1628) — into the single `ProjectDiagnostic[]`
|
|
60
|
+
* `lens_diagnostics mode=full` surfaces. Before #1628, `secrets` was silently
|
|
61
|
+
* unread here: a trivy-only secret (no gitleaks/ast-grep corroboration) had no
|
|
62
|
+
* `lens_diagnostics`-visible identity at all for an agent to anchor a mark
|
|
63
|
+
* against, even though `runtime-turn.ts`'s turn_end gate already blocked on it.
|
|
64
|
+
*/
|
|
27
65
|
export function trivyResultToProjectDiagnostics(cwd, result) {
|
|
28
|
-
if (!result.success
|
|
66
|
+
if (!result.success)
|
|
29
67
|
return [];
|
|
30
|
-
return
|
|
68
|
+
return [
|
|
69
|
+
...(result.findings ?? []).map((finding) => trivyFindingToProjectDiagnostic(cwd, finding)),
|
|
70
|
+
// `secrets` defaults to `[]` here rather than assuming the field is
|
|
71
|
+
// always present: `fetchFreshProjectDiagnostics` swallows a task
|
|
72
|
+
// rejection into a silent "completed" outcome (its
|
|
73
|
+
// `.catch(() => "completed")`), so an unguarded `.map` on a missing
|
|
74
|
+
// field here would drop this lane's CVE diagnostics too, not just the
|
|
75
|
+
// secrets — a caller-visible regression for a field this adapter
|
|
76
|
+
// doesn't itself require.
|
|
77
|
+
...trivySecretsToProjectDiagnostics(cwd, result.secrets ?? []),
|
|
78
|
+
];
|
|
31
79
|
}
|
|
@@ -89,6 +89,11 @@ function fromDispatchDiagnostic(diagnostic, runner) {
|
|
|
89
89
|
*/
|
|
90
90
|
async function scanFileMajorRules(cwd, files, signal) {
|
|
91
91
|
const client = getSharedTreeSitterClient();
|
|
92
|
+
// #1715: grow the tree cache to span this scan's working set BEFORE
|
|
93
|
+
// parsing starts, so a project bigger than the interactive default (50
|
|
94
|
+
// entries) still gets cross-scan reuse instead of every file re-parsing
|
|
95
|
+
// on every scan.
|
|
96
|
+
client?.ensureTreeCacheCapacity(files.length);
|
|
92
97
|
const treeSitterReady = !!client && client.isAvailable() && (await client.init());
|
|
93
98
|
// Same singleton the dispatch runner uses (tree-sitter.ts:444) — memoized
|
|
94
99
|
// per root, so repeated scans stop re-reading the ~180 query YAMLs.
|
|
@@ -283,17 +288,26 @@ async function scanFileMajorRules(cwd, files, signal) {
|
|
|
283
288
|
// phase-major scans.
|
|
284
289
|
durationMs: Date.now() - startedAt - astGrepDurationMs,
|
|
285
290
|
stats,
|
|
291
|
+
// #1935 review: ast-grep's own cost is often a scan's most expensive
|
|
292
|
+
// phase (production evidence: 13168ms over 86 files, the single
|
|
293
|
+
// biggest contributor). Its duration is subtracted above so it stays
|
|
294
|
+
// comparable to the historical phase-major scans; carry it here too
|
|
295
|
+
// so it stays visible SOMEWHERE instead of disappearing when the
|
|
296
|
+
// vacuous `project_diagnostics_ast_grep_scan` cache_stats record
|
|
297
|
+
// (below) was removed.
|
|
298
|
+
astGrep: { durationMs: astGrepDurationMs, fileCount: astGrepFilesScanned },
|
|
286
299
|
});
|
|
287
300
|
});
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
301
|
+
// #1935: no `project_diagnostics_ast_grep_scan` cache_stats record here.
|
|
302
|
+
// `scanAstGrepFile` parses through ast-grep-napi's own `lang.parse()` — a
|
|
303
|
+
// separate native engine, not `TreeSitterClient`'s WASM `TreeCache` — so a
|
|
304
|
+
// cache_stats record for this scope would always read all-zero (0
|
|
305
|
+
// lookups, 0 hits, every counter 0) no matter how the scan behaves. That
|
|
306
|
+
// was a vacuous observability record, not a real one: it looked like a
|
|
307
|
+
// signal but could never carry information. `astGrepDurationMs` and
|
|
308
|
+
// `astGrepFilesScanned` still feed the `project_diagnostics_scan` record
|
|
309
|
+
// above (`astGrep` sub-field), so this cost stays observable without a
|
|
310
|
+
// second, always-zero record to carry it.
|
|
297
311
|
return { treeSitter, factRules, astGrep, filesScanned, wasmAborted };
|
|
298
312
|
}
|
|
299
313
|
export async function scanProjectDiagnostics(options) {
|
|
@@ -84,6 +84,9 @@ const PROJECT_OWN_CONFIG_KEYS = [
|
|
|
84
84
|
"maxProjectFiles",
|
|
85
85
|
"reviewGraph",
|
|
86
86
|
"trivy",
|
|
87
|
+
// `helm.renderValidation.enabled` — the opt-in for rendered-manifest
|
|
88
|
+
// validation, read via `.raw` in the helm-render runner (#1283).
|
|
89
|
+
"helm",
|
|
87
90
|
];
|
|
88
91
|
/** Clamp bounds for `reviewGraph.maxFiles` — see the field's doc comment above. */
|
|
89
92
|
const REVIEW_GRAPH_MAX_FILES_MIN = 100;
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
import * as path from "node:path";
|
|
37
37
|
import { normalizeMapKey, toProjectRelativePath } from "./path-utils.js";
|
|
38
38
|
import { loadProjectSnapshotWithoutWordIndex } from "./project-snapshot.js";
|
|
39
|
+
import { formatReviewGraphRevisionDriftNote, } from "./review-graph/revision-drift.js";
|
|
39
40
|
const DEFAULT_LIMIT = 10;
|
|
40
41
|
const STALE_THRESHOLD_MS = 15 * 60_000; // 15 minutes
|
|
41
42
|
const LOW_COVERAGE_THRESHOLD = 0.8;
|
|
@@ -113,7 +114,11 @@ function buildFileDegrees(graph) {
|
|
|
113
114
|
return { fanIn, fanOut };
|
|
114
115
|
}
|
|
115
116
|
// --- section 1: trust header --------------------------------------------------
|
|
116
|
-
function computeTrust(graph, cwd
|
|
117
|
+
function computeTrust(graph, cwd,
|
|
118
|
+
// Passed in rather than looked up here: the builder is imported dynamically
|
|
119
|
+
// by `projectReport` to keep the module graph acyclic, and the value must be
|
|
120
|
+
// computed per render, never cached (#1961 review F3).
|
|
121
|
+
drift) {
|
|
117
122
|
const filesCovered = graph.fileNodes.size;
|
|
118
123
|
const snapshot = loadProjectSnapshotWithoutWordIndex(cwd);
|
|
119
124
|
const snapshotFileCount = snapshot ? Object.keys(snapshot.files).length : 0;
|
|
@@ -151,6 +156,11 @@ function computeTrust(graph, cwd) {
|
|
|
151
156
|
const lowCoverage = coverage < LOW_COVERAGE_THRESHOLD ||
|
|
152
157
|
graph.persistCoverage?.partial === true;
|
|
153
158
|
const notes = [];
|
|
159
|
+
// #1961: the blind read now SERVES a snapshot stamped at a different HEAD
|
|
160
|
+
// rather than dropping it. Age alone would not catch a branch switch made
|
|
161
|
+
// minutes ago, so the revision difference gets its own note.
|
|
162
|
+
if (drift)
|
|
163
|
+
notes.push(formatReviewGraphRevisionDriftNote(drift));
|
|
154
164
|
if (stale) {
|
|
155
165
|
const ageMin = Math.round(ageMs / 60_000);
|
|
156
166
|
notes.push(`Graph is stale: built ${ageMin}m ago. Sections below may miss recent edits — run pilens_rebuild or re-analyze to refresh.`);
|
|
@@ -184,6 +194,7 @@ function computeTrust(graph, cwd) {
|
|
|
184
194
|
sampleSize,
|
|
185
195
|
},
|
|
186
196
|
stale,
|
|
197
|
+
...(drift ? { revisionDrift: drift } : {}),
|
|
187
198
|
lowCoverage,
|
|
188
199
|
persistCoverage: graph.persistCoverage?.partial
|
|
189
200
|
? graph.persistCoverage
|
|
@@ -493,25 +504,23 @@ const inFlightGraphBuilds = new Set();
|
|
|
493
504
|
export function _resetProjectReportBuildGuardForTests() {
|
|
494
505
|
inFlightGraphBuilds.clear();
|
|
495
506
|
}
|
|
496
|
-
function triggerBackgroundGraphBuild(cwd) {
|
|
507
|
+
function triggerBackgroundGraphBuild(cwd, deps) {
|
|
497
508
|
const key = normalizeMapKey(path.resolve(cwd));
|
|
498
509
|
if (inFlightGraphBuilds.has(key))
|
|
499
|
-
return
|
|
510
|
+
return "already_running";
|
|
511
|
+
// Ask the builder, not just this module's own guard: a build kicked off by
|
|
512
|
+
// the edit pipeline or another reader never touches `inFlightGraphBuilds`.
|
|
513
|
+
// The probe and the call are in ONE synchronous block on purpose — awaiting
|
|
514
|
+
// between them (the pre-#1962 dynamic imports did) reopens the race.
|
|
515
|
+
const deduped = deps.isGraphBuildInFlight(key, []);
|
|
500
516
|
inFlightGraphBuilds.add(key);
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
// buildOrUpdateGraph records the durable failure and surfaced status.
|
|
509
|
-
}
|
|
510
|
-
finally {
|
|
511
|
-
inFlightGraphBuilds.delete(key);
|
|
512
|
-
}
|
|
513
|
-
})();
|
|
514
|
-
return true;
|
|
517
|
+
const build = deps
|
|
518
|
+
.buildOrUpdateGraph(key, [], new deps.FactStore())
|
|
519
|
+
.catch(() => {
|
|
520
|
+
// buildOrUpdateGraph records the durable failure and surfaced status.
|
|
521
|
+
});
|
|
522
|
+
void build.finally(() => inFlightGraphBuilds.delete(key));
|
|
523
|
+
return deduped ? "already_running" : "started";
|
|
515
524
|
}
|
|
516
525
|
// --- entry point ---------------------------------------------------------------
|
|
517
526
|
/**
|
|
@@ -523,7 +532,7 @@ export async function projectReport(cwd, options) {
|
|
|
523
532
|
const limit = clampLimit(options?.limit);
|
|
524
533
|
const focusTerms = normalizeFocus(options?.focus);
|
|
525
534
|
const view = options?.view;
|
|
526
|
-
const { getCachedReviewGraph, getReviewGraphSizeSkipVerdict, getLastReviewGraphBuildAttempt, } = await import("./review-graph/builder.js");
|
|
535
|
+
const { getCachedReviewGraph, getReviewGraphSizeSkipVerdict, getLastReviewGraphBuildAttempt, buildOrUpdateGraph, isGraphBuildInFlight, getReviewGraphRevisionDrift, } = await import("./review-graph/builder.js");
|
|
527
536
|
let graph;
|
|
528
537
|
try {
|
|
529
538
|
graph = getCachedReviewGraph(cwd);
|
|
@@ -556,22 +565,48 @@ export async function projectReport(cwd, options) {
|
|
|
556
565
|
};
|
|
557
566
|
}
|
|
558
567
|
const previousAttempt = getLastReviewGraphBuildAttempt(cwd);
|
|
559
|
-
const
|
|
560
|
-
const
|
|
568
|
+
const { FactStore } = await import("./dispatch/fact-store.js");
|
|
569
|
+
const trigger = triggerBackgroundGraphBuild(cwd, {
|
|
570
|
+
buildOrUpdateGraph,
|
|
571
|
+
isGraphBuildInFlight,
|
|
572
|
+
FactStore,
|
|
573
|
+
});
|
|
574
|
+
const started = trigger === "started";
|
|
575
|
+
// #1962: report the attempt that is CURRENT. When this call started a
|
|
576
|
+
// build, `buildOrUpdateGraph` has already recorded a fresh `running`
|
|
577
|
+
// attempt synchronously, and the previous outcome belongs in the hint
|
|
578
|
+
// text, not in a field labelled "last attempt". When no build started,
|
|
579
|
+
// the earlier attempt genuinely IS the current one.
|
|
580
|
+
const lastBuildAttempt = started
|
|
581
|
+
? (getLastReviewGraphBuildAttempt(cwd) ?? previousAttempt)
|
|
582
|
+
: previousAttempt;
|
|
583
|
+
// A terminal previous outcome is the useful half of the message: it says
|
|
584
|
+
// WHY the graph is missing. It is prefixed to whichever verdict follows,
|
|
585
|
+
// rather than selecting between two parallel sentence pairs — the first
|
|
586
|
+
// version of this branch did that, and its terminal-plus-deduped arm was
|
|
587
|
+
// unreachable (#1962 review F1). A pending build always records a
|
|
588
|
+
// `running` attempt synchronously, so "terminal" and "not started" cannot
|
|
589
|
+
// both hold for the same key.
|
|
590
|
+
const terminal = previousAttempt?.outcome === "failed" ||
|
|
591
|
+
previousAttempt?.outcome === "skipped";
|
|
592
|
+
const cause = terminal
|
|
593
|
+
? `Review graph unavailable: ${previousAttempt?.reason ?? previousAttempt?.outcome}. `
|
|
594
|
+
: "";
|
|
561
595
|
return {
|
|
562
596
|
available: false,
|
|
563
|
-
hint:
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
: "No review graph cached for this workspace yet — the background build is still running; retry this call shortly.",
|
|
597
|
+
hint: started
|
|
598
|
+
? terminal
|
|
599
|
+
? `${cause}A retry was started.`
|
|
600
|
+
: "No review graph cached for this workspace yet — a build was kicked off in the background; retry this call shortly."
|
|
601
|
+
: `${cause}A build is already running for this workspace; retry this call shortly.`,
|
|
569
602
|
...(lastBuildAttempt ? { lastBuildAttempt } : {}),
|
|
570
603
|
...(view ? { view } : {}),
|
|
571
604
|
};
|
|
572
605
|
}
|
|
573
606
|
const degrees = buildFileDegrees(graph);
|
|
574
|
-
|
|
607
|
+
// Computed on THIS render, from the workspace entry's stamped commit and the
|
|
608
|
+
// worktree's HEAD right now — never from a value cached beside the graph.
|
|
609
|
+
const trust = computeTrust(graph, cwd, getReviewGraphRevisionDrift(cwd));
|
|
575
610
|
const hubs = await computeHubs(graph, degrees, cwd, limit, focusTerms);
|
|
576
611
|
const { entryPoints, entryPointFiles } = computeEntryPoints(graph, degrees, cwd, limit, focusTerms);
|
|
577
612
|
const subsystems = computeSubsystems(graph, cwd, limit);
|