@herbertgao/pi-extensions 2026.9.1 → 2026.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/THIRD_PARTY_NOTICES.md +24 -0
- package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
- package/node_modules/@herbertgao/sol-pi/README.md +159 -0
- package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
- package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
- package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
- package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
- package/node_modules/@herbertgao/sol-pi/package.json +76 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
- package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
- package/node_modules/@narumitw/pi-btw/README.md +57 -141
- package/node_modules/@narumitw/pi-btw/dist/index.ts +478 -43
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
- package/node_modules/@narumitw/pi-btw/docs/workflows.md +74 -0
- package/node_modules/@narumitw/pi-btw/package.json +2 -1
- package/node_modules/@narumitw/pi-btw/src/btw.ts +28 -3
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +32 -2
- package/node_modules/@narumitw/pi-btw/src/keybindings.ts +330 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +136 -19
- package/node_modules/@narumitw/pi-btw/src/settings.ts +32 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +57 -5
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +52 -30
- package/node_modules/pi-lens/CHANGELOG.md +260 -0
- package/node_modules/pi-lens/README.md +13 -8
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +1 -1
- package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -8
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +2 -0
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +133 -1
- package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -6
- package/node_modules/pi-lens/dist/clients/bootstrap.js +4 -4
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +1 -1
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -5
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +1 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -6
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +2 -2
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/child-unref.js +1 -19
- package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
- package/node_modules/pi-lens/dist/clients/config-core/index.js +11 -8
- package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-core/provenance.js +2 -9
- package/node_modules/pi-lens/dist/clients/config-core/records.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-core/schema.js +3 -5
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +3 -1
- package/node_modules/pi-lens/dist/clients/config-resolve.js +10 -7
- package/node_modules/pi-lens/dist/clients/config-schema.js +56 -2
- package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
- package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -4
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +1 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -41
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +18 -1
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -6
- package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -3
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +7 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +15 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +3 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +5 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +1 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -21
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +2 -20
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +5 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +2 -2
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +2 -2
- package/node_modules/pi-lens/dist/clients/extension-log.js +2 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +1 -38
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
- package/node_modules/pi-lens/dist/clients/file-time.js +1 -1
- package/node_modules/pi-lens/dist/clients/file-utils.js +5 -1
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
- package/node_modules/pi-lens/dist/clients/format-service.js +0 -1
- package/node_modules/pi-lens/dist/clients/formatters.js +66 -93
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +3 -4
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +5 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
- package/node_modules/pi-lens/dist/clients/grammar-source.js +3 -3
- package/node_modules/pi-lens/dist/clients/installer/index.js +416 -61
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +84 -18
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +6 -6
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +12 -11
- package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
- package/node_modules/pi-lens/dist/clients/latency-logger.js +7 -7
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +23 -0
- package/node_modules/pi-lens/dist/clients/lens-engine.js +3 -4
- package/node_modules/pi-lens/dist/clients/lens-events.js +1 -1
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +18 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +1 -1
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -36
- package/node_modules/pi-lens/dist/clients/lsp/client.js +4 -3
- package/node_modules/pi-lens/dist/clients/lsp/config.js +37 -7
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +79 -1
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +3 -3
- package/node_modules/pi-lens/dist/clients/lsp/index.js +491 -64
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -8
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -2
- package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -1
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +5 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +6 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
- package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -1
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
- package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
- package/node_modules/pi-lens/dist/clients/metrics-history.js +28 -107
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +1 -1
- package/node_modules/pi-lens/dist/clients/module-report.js +1 -1
- package/node_modules/pi-lens/dist/clients/mutating-tool.js +3 -3
- package/node_modules/pi-lens/dist/clients/mutation-attribution.js +3 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -4
- package/node_modules/pi-lens/dist/clients/observed-mutation.js +9 -9
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +2 -6
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +1 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
- package/node_modules/pi-lens/dist/clients/path-utils.js +23 -2
- package/node_modules/pi-lens/dist/clients/performance-report.js +2 -2
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +9 -4
- package/node_modules/pi-lens/dist/clients/pipeline.js +5 -4
- package/node_modules/pi-lens/dist/clients/project-changes.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +49 -1
- package/node_modules/pi-lens/dist/clients/project-scan-policy.js +3 -51
- package/node_modules/pi-lens/dist/clients/python-provenance.js +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +3 -1
- package/node_modules/pi-lens/dist/clients/read-guard.js +5 -2
- package/node_modules/pi-lens/dist/clients/recent-touches.js +2 -2
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +3 -5
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +1 -1
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +10 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +58 -14
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +11 -1
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
- package/node_modules/pi-lens/dist/clients/sanitize.js +0 -11
- package/node_modules/pi-lens/dist/clients/scan-utils.js +1 -56
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
- package/node_modules/pi-lens/dist/clients/session-summary.js +0 -24
- package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
- package/node_modules/pi-lens/dist/clients/sgconfig.js +1 -5
- package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +1 -1
- package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
- package/node_modules/pi-lens/dist/clients/startup-scan.js +2 -10
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
- package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +77 -72
- package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
- package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
- package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +1 -52
- package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -4
- package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
- package/node_modules/pi-lens/dist/clients/user-notify.js +0 -4
- package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/word-index-store.js +3 -7
- package/node_modules/pi-lens/dist/clients/word-index.js +9 -16
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +1 -1
- package/node_modules/pi-lens/dist/index.js +19969 -17481
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
- package/node_modules/pi-lens/dist/mcp/build-staleness.js +1 -1
- package/node_modules/pi-lens/dist/mcp/server.js +135 -159
- package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +1 -1
- package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +1 -1
- package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
- package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
- package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +354 -86
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +54 -112
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
- package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +3 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
- package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
- package/node_modules/pi-lens/dist/tools/render-compact.js +281 -2
- package/node_modules/pi-lens/dist/tools/symbol-search.js +3 -4
- package/node_modules/pi-lens/docs/agent-guide.md +3 -4
- package/node_modules/pi-lens/docs/agent-tools.md +46 -22
- package/node_modules/pi-lens/docs/configuration.md +9 -0
- package/node_modules/pi-lens/docs/environment-variables.md +0 -5
- package/node_modules/pi-lens/docs/features.md +5 -5
- package/node_modules/pi-lens/docs/globalconfig.md +31 -1
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +9 -1
- package/node_modules/pi-lens/docs/mcp.md +13 -1
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
- package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +41 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +21 -2
- package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
- package/node_modules/pi-lens/docs/real-harness.md +46 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +17 -5
- package/node_modules/pi-lens/docs/servercapabilities.md +2 -3
- package/node_modules/pi-lens/docs/settings.md +37 -2
- package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
- package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
- package/node_modules/pi-lens/docs/usage.md +13 -3
- package/node_modules/pi-lens/docs/word-index.md +1 -1
- package/node_modules/pi-lens/package.json +15 -15
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
- package/node_modules/pi-lens/rules/typos/_typos.toml +4 -2
- package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +1 -1
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +1 -1
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +4 -2
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
- package/node_modules/pi-web-access/CHANGELOG.md +29 -0
- package/node_modules/pi-web-access/README.md +33 -22
- package/node_modules/pi-web-access/abortable.ts +17 -0
- package/node_modules/pi-web-access/crawl4ai.ts +204 -0
- package/node_modules/pi-web-access/credential-source.ts +1 -0
- package/node_modules/pi-web-access/curator-page.ts +20 -2
- package/node_modules/pi-web-access/curator-run.ts +44 -0
- package/node_modules/pi-web-access/curator-server.ts +3 -1
- package/node_modules/pi-web-access/duckduckgo.ts +1 -1
- package/node_modules/pi-web-access/extract.ts +57 -12
- package/node_modules/pi-web-access/fetch-params.ts +1 -1
- package/node_modules/pi-web-access/gemini-search.ts +9 -5
- package/node_modules/pi-web-access/index.ts +25 -18
- package/node_modules/pi-web-access/openai-search.ts +35 -13
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/page-query.ts +5 -2
- package/node_modules/pi-web-access/query-rewrite.ts +5 -2
- package/node_modules/pi-web-access/serpapi.ts +220 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
- package/node_modules/pi-web-access/storage.ts +10 -0
- package/node_modules/pi-web-access/summary-review.ts +34 -21
- package/node_modules/pi-web-access/utils.ts +6 -4
- package/package.json +7 -4
- package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
|
@@ -45,7 +45,7 @@ import { BoundedFifoMap } from "./bounded-cache.js";
|
|
|
45
45
|
import { getProjectDataDir } from "./file-utils.js";
|
|
46
46
|
import { getProcessSingleton } from "./process-singletons.js";
|
|
47
47
|
/** Persisted-file schema version. A file of any other version is ignored. */
|
|
48
|
-
|
|
48
|
+
const MUTATION_ATTRIBUTION_FILE_VERSION = 1;
|
|
49
49
|
/** File under `getProjectDataDir(cwd)` holding the learned attributions. */
|
|
50
50
|
export const MUTATION_ATTRIBUTION_FILE = "observed-mutating-tools.json";
|
|
51
51
|
/**
|
|
@@ -55,7 +55,7 @@ export const MUTATION_ATTRIBUTION_FILE = "observed-mutating-tools.json";
|
|
|
55
55
|
* co-occurrence — an unrelated tool call that happened to overlap a background
|
|
56
56
|
* write — cannot durably mislabel a tool for every future session.
|
|
57
57
|
*/
|
|
58
|
-
|
|
58
|
+
const PERSIST_AFTER_OBSERVATIONS = 2;
|
|
59
59
|
/**
|
|
60
60
|
* Consecutive clean observations after which an UNATTRIBUTED tool stops being
|
|
61
61
|
* armed for the session. Two, not one: a mutating tool whose FIRST call
|
|
@@ -88,7 +88,7 @@ export const CLEAN_OBSERVATION_ARM_LIMIT = 2;
|
|
|
88
88
|
*/
|
|
89
89
|
export const DEATTRIBUTE_AFTER_CLEAN_OBSERVATIONS = 3;
|
|
90
90
|
/** Bound on distinct tool names remembered, in-memory and on disk. */
|
|
91
|
-
|
|
91
|
+
const MUTATION_ATTRIBUTION_MAX_TOOLS = 64;
|
|
92
92
|
const ATTRIBUTION_FAMILY = "mutation-attribution";
|
|
93
93
|
/**
|
|
94
94
|
* Bumped to 2 (#2449 review round 5, F3): `session` changed shape from a
|
|
@@ -127,10 +127,6 @@ export function _exitFlushersForTest() {
|
|
|
127
127
|
export function getRegisteredLogFiles() {
|
|
128
128
|
return registeredLogFiles;
|
|
129
129
|
}
|
|
130
|
-
/** Test-only reset — each test file gets a clean registry (see ndjson-logger.test.ts). */
|
|
131
|
-
export function _resetRegisteredLogFilesForTest() {
|
|
132
|
-
registeredLogFiles.clear();
|
|
133
|
-
}
|
|
134
130
|
/**
|
|
135
131
|
* Snapshot of unrecovered write losses, one entry per sink that has any
|
|
136
132
|
* (#1970). Pure in-memory read — no I/O, so a caller (`degradation-ledger.ts`)
|
|
@@ -119,7 +119,7 @@ import { lineContentHash } from "./read-guard.js";
|
|
|
119
119
|
* must not turn every first observation into a timeout, which is the least
|
|
120
120
|
* useful possible outcome.
|
|
121
121
|
*/
|
|
122
|
-
|
|
122
|
+
const OBSERVED_CAPTURE_BUDGET_MS = 200;
|
|
123
123
|
/**
|
|
124
124
|
* Cumulative ceiling for every ARMED capture in one turn. A turn that calls
|
|
125
125
|
* twenty unclassified tools pays this once, not twenty times. The SETTLE does
|
|
@@ -141,7 +141,7 @@ export const OBSERVED_TURN_BUDGET_MS = 600;
|
|
|
141
141
|
* holds regardless of the clock. What it CAN cut is a directory target's tail,
|
|
142
142
|
* and that is reported as `stoppedEarly` rather than scored as clean.
|
|
143
143
|
*/
|
|
144
|
-
|
|
144
|
+
const OBSERVED_SETTLE_DEADLINE_MS = 50;
|
|
145
145
|
/**
|
|
146
146
|
* Entries taken from a DIRECTORY-shaped target path, non-recursively.
|
|
147
147
|
*
|
|
@@ -175,7 +175,7 @@ export const OBSERVED_TRACKED_MAX_FILES = 400;
|
|
|
175
175
|
* closes it as soon as anything moves the size or the tick, and the armed
|
|
176
176
|
* observation (which hashes the target unconditionally) never depended on it.
|
|
177
177
|
*/
|
|
178
|
-
|
|
178
|
+
const OBSERVED_LEDGER_SETTLE_MS = 150;
|
|
179
179
|
/**
|
|
180
180
|
* Path keys the "pi-lens already recorded this" set may hold.
|
|
181
181
|
*
|
|
@@ -198,19 +198,19 @@ export const OBSERVED_HANDLED_MAX = 1000;
|
|
|
198
198
|
*/
|
|
199
199
|
export const OBSERVED_SWEEP_STAT_WINDOW = 128;
|
|
200
200
|
/** Cumulative content-hash budget for ONE capture. */
|
|
201
|
-
|
|
201
|
+
const OBSERVED_HASH_BUDGET_BYTES = 2 * 1024 * 1024;
|
|
202
202
|
/** Cumulative bytes ONE settled sweep may read to seed or verify a hash. */
|
|
203
203
|
export const OBSERVED_SWEEP_HASH_BUDGET_BYTES = 2 * 1024 * 1024;
|
|
204
204
|
/** Cumulative bytes ONE settled sweep may read to derive edit RANGES. */
|
|
205
|
-
|
|
205
|
+
const OBSERVED_SWEEP_RANGE_BUDGET_BYTES = 1024 * 1024;
|
|
206
206
|
/** Largest file whose per-line hashes are captured for range derivation. */
|
|
207
|
-
|
|
207
|
+
const OBSERVED_LINE_HASH_MAX_BYTES = 512 * 1024;
|
|
208
208
|
/** Ranges reported per file before they collapse to one bounding box. */
|
|
209
|
-
|
|
209
|
+
const OBSERVED_MAX_EDIT_RANGES = 32;
|
|
210
210
|
/** Pending baselines held between `tool_call` and `tool_result`. */
|
|
211
|
-
|
|
211
|
+
const OBSERVED_PENDING_MAX = 32;
|
|
212
212
|
/** Files remembered by the settled-sweep content ledger. */
|
|
213
|
-
|
|
213
|
+
const OBSERVED_LEDGER_MAX = 1000;
|
|
214
214
|
const OBSERVED_FAMILY = "observed-mutation-net";
|
|
215
215
|
const OBSERVED_VERSION = 3;
|
|
216
216
|
function state() {
|
|
@@ -43,11 +43,11 @@ import { freshnessFromMtime } from "./freshness.js";
|
|
|
43
43
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
44
44
|
import { truncatedByOutputCap } from "./spawn-output-cap.js";
|
|
45
45
|
/** Stop hashing once this many cumulative bytes were read (per capture). */
|
|
46
|
-
|
|
46
|
+
const OPAQUE_HASH_BUDGET_BYTES = 8 * 1024 * 1024;
|
|
47
47
|
/** Hard cap on scanned files — beyond it the verdict is coverage-unknown. */
|
|
48
48
|
export const OPAQUE_SCAN_MAX_FILES = 2000;
|
|
49
49
|
/** How far before recorded start an earlier write may still be attributed. */
|
|
50
|
-
|
|
50
|
+
const OPAQUE_MTIME_TOLERANCE_MS = 150;
|
|
51
51
|
// `--untracked-files=all` lists untracked files individually instead of
|
|
52
52
|
// collapsing them per directory (it does NOT add ignored paths — that needs
|
|
53
53
|
// `--ignored`), so the worst realistic case is a working tree with a large
|
|
@@ -220,10 +220,6 @@ export async function isGitWorktree(root) {
|
|
|
220
220
|
gitRepoMemo.set(key, isRepo === true);
|
|
221
221
|
return isRepo === true;
|
|
222
222
|
}
|
|
223
|
-
export function _resetGitWorktreeMemoForTests() {
|
|
224
|
-
gitRepoMemo.clear();
|
|
225
|
-
gitToplevelMemo.clear();
|
|
226
|
-
}
|
|
227
223
|
const gitToplevelMemo = new Map();
|
|
228
224
|
/**
|
|
229
225
|
* The root of the working tree `root` belongs to, or `undefined` when it is
|
|
@@ -148,8 +148,10 @@ export class OpengrepClient extends SecurityScanClient {
|
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
150
|
const findings = parseOpengrepReport(fs.readFileSync(reportPath, "utf-8"));
|
|
151
|
+
// #2154: the one opengrep site that parsed a scan of this root.
|
|
151
152
|
return {
|
|
152
153
|
success: true,
|
|
154
|
+
analyzed: true,
|
|
153
155
|
findings,
|
|
154
156
|
scannedAt,
|
|
155
157
|
};
|
|
@@ -3,7 +3,7 @@ import { findLocalToolConfig } from "./path-utils.js";
|
|
|
3
3
|
// Opengrep is a fork of Semgrep and natively consumes the same rule format, so
|
|
4
4
|
// we discover both `.opengrep.*` (preferred) and the de-facto `.semgrep.*` rule
|
|
5
5
|
// files an existing repo may already carry.
|
|
6
|
-
|
|
6
|
+
const LOCAL_OPENGREP_CONFIG_NAMES = [
|
|
7
7
|
".opengrep.yml",
|
|
8
8
|
".opengrep.yaml",
|
|
9
9
|
"opengrep.yml",
|
|
@@ -18,6 +18,7 @@ import * as os from "node:os";
|
|
|
18
18
|
import * as path from "node:path";
|
|
19
19
|
import { classifyProbeFailure, createAvailabilityLatch, isTransientDecision, logAvailabilityDecision, startHostStallSampler, } from "./dispatch/runners/utils/availability-policy.js";
|
|
20
20
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
21
|
+
import { probeToolAsync } from "./tool-probe.js";
|
|
21
22
|
import { createAvailabilityProbeFlight } from "./availability-probe-flight.js";
|
|
22
23
|
import { createGenerationSource, } from "./generation-guard.js";
|
|
23
24
|
import { isAtOrAboveHomeDir, walkUpDirs } from "./path-utils.js";
|
|
@@ -114,7 +115,7 @@ async function probeAvailability(pm) {
|
|
|
114
115
|
let result;
|
|
115
116
|
let hostStallMs;
|
|
116
117
|
try {
|
|
117
|
-
result = await
|
|
118
|
+
result = await probeToolAsync(finder, [pm], { timeout: PROBE_TIMEOUT_MS });
|
|
118
119
|
}
|
|
119
120
|
finally {
|
|
120
121
|
hostStallMs = sampler.stop();
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - On non-Windows: return path as-is (case-sensitive filesystem)
|
|
11
11
|
* - Always convert backslashes to forward slashes for Map key consistency
|
|
12
12
|
*/
|
|
13
|
-
import { existsSync, realpathSync } from "node:fs";
|
|
13
|
+
import { existsSync, readFileSync, realpathSync, statSync, } from "node:fs";
|
|
14
14
|
import * as os from "node:os";
|
|
15
15
|
import * as path from "node:path";
|
|
16
16
|
import { win32 } from "node:path";
|
|
@@ -413,6 +413,25 @@ export function findLocalToolConfig(startDir, names, options = {}) {
|
|
|
413
413
|
}
|
|
414
414
|
return undefined;
|
|
415
415
|
}
|
|
416
|
+
/**
|
|
417
|
+
* Accept only a real Git repository marker: a directory with HEAD, or a
|
|
418
|
+
* worktree/submodule marker file whose first line starts with `gitdir:`.
|
|
419
|
+
*/
|
|
420
|
+
export function isRealGitMarker(markerPath) {
|
|
421
|
+
try {
|
|
422
|
+
const marker = statSync(markerPath);
|
|
423
|
+
if (marker.isDirectory())
|
|
424
|
+
return existsSync(path.join(markerPath, "HEAD"));
|
|
425
|
+
if (!marker.isFile())
|
|
426
|
+
return false;
|
|
427
|
+
return readFileSync(markerPath, "utf8")
|
|
428
|
+
.split(/\r?\n/, 1)[0]
|
|
429
|
+
.startsWith("gitdir:");
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
416
435
|
/**
|
|
417
436
|
* Walk up from `startDir` looking for a directory containing any of
|
|
418
437
|
* `markers`, the same containment-aware climb `knip-client.ts` and
|
|
@@ -438,11 +457,13 @@ export function findLocalToolConfig(startDir, names, options = {}) {
|
|
|
438
457
|
export function findNearestMarkerRoot(startDir, markers, options = {}) {
|
|
439
458
|
const boundaries = options.boundaries ?? [];
|
|
440
459
|
const homeDir = path.resolve(options.homeDir ?? os.homedir());
|
|
460
|
+
const markerPredicate = options.markerPredicate ?? (() => true);
|
|
441
461
|
let current = path.resolve(startDir);
|
|
442
462
|
for (let depth = 0; depth < 64; depth++) {
|
|
443
463
|
if (isAtOrAboveHomeDir(current, homeDir))
|
|
444
464
|
return null;
|
|
445
|
-
if (markers.some((m) => existsSync(path.join(current, m))
|
|
465
|
+
if (markers.some((m) => existsSync(path.join(current, m)) &&
|
|
466
|
+
markerPredicate(path.join(current, m))))
|
|
446
467
|
return current;
|
|
447
468
|
if (boundaries.some((m) => existsSync(path.join(current, m))))
|
|
448
469
|
return null;
|
|
@@ -2,8 +2,8 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as readline from "node:readline";
|
|
3
3
|
import { flushLatencyLog, getLatencyLogPath, } from "./latency-logger.js";
|
|
4
4
|
import { getMaxLogSizeMB } from "./log-cleanup.js";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const DEFAULT_PERF_TOP_N = 5;
|
|
6
|
+
const MAX_PERF_TOP_N = 50;
|
|
7
7
|
export const MAX_PERF_PHASE_SAMPLES = 20_000;
|
|
8
8
|
const PARSE_YIELD_EVERY = 500;
|
|
9
9
|
// The window follows the same threshold that rotates the log out from under it.
|
|
@@ -91,14 +91,15 @@
|
|
|
91
91
|
* gate says "config exists" while the carriage says "not found", silently
|
|
92
92
|
* dropping the `--config` argv this module exists to carry.
|
|
93
93
|
*/
|
|
94
|
+
import { existsSync } from "node:fs";
|
|
94
95
|
import * as path from "node:path";
|
|
95
|
-
import {
|
|
96
|
+
import { resolveToolCwd } from "./tool-cwd.js";
|
|
96
97
|
/**
|
|
97
98
|
* In `computeConfigFiles()`'s own precedence order — `.php-cs-fixer.php`
|
|
98
99
|
* before `.php-cs-fixer.dist.php` — so a same-directory precedence check can
|
|
99
100
|
* just take the first existing name.
|
|
100
101
|
*/
|
|
101
|
-
|
|
102
|
+
const PHP_CS_FIXER_CONFIG_NAMES = [
|
|
102
103
|
".php-cs-fixer.php",
|
|
103
104
|
".php-cs-fixer.dist.php",
|
|
104
105
|
];
|
|
@@ -109,6 +110,10 @@ export const PHP_CS_FIXER_CONFIG_NAMES = [
|
|
|
109
110
|
* agreeing with this tool's own (unceilinged) detection gates.
|
|
110
111
|
*/
|
|
111
112
|
export function resolvePhpCsFixerConfig(filePath) {
|
|
112
|
-
const
|
|
113
|
-
|
|
113
|
+
const absolute = path.resolve(filePath);
|
|
114
|
+
const startDir = resolveToolCwd("formatter", "php-cs-fixer", absolute, {
|
|
115
|
+
cwd: path.parse(absolute).root,
|
|
116
|
+
allowHomeMarker: true,
|
|
117
|
+
});
|
|
118
|
+
return PHP_CS_FIXER_CONFIG_NAMES.map((name) => path.join(startDir, name)).find(existsSync);
|
|
114
119
|
}
|
|
@@ -34,6 +34,7 @@ import { clearGraphCache } from "./review-graph/builder.js";
|
|
|
34
34
|
import { BoundedLruCache } from "./bounded-cache.js";
|
|
35
35
|
import { RUNTIME_CONFIG } from "./runtime-config.js";
|
|
36
36
|
import { getAmbientAbortSignal, safeSpawnAsync } from "./safe-spawn.js";
|
|
37
|
+
import { probeToolAsync } from "./tool-probe.js";
|
|
37
38
|
import { bounded } from "./deadline-utils.js";
|
|
38
39
|
import { enabledAuxiliaryLspServerIds } from "./dispatch/auxiliary-lsp.js";
|
|
39
40
|
import { recordDegradationOnce } from "./degradation-ledger.js";
|
|
@@ -179,7 +180,7 @@ function createPhaseTracker(toolName, filePath) {
|
|
|
179
180
|
};
|
|
180
181
|
}
|
|
181
182
|
// --- ESLint autofix helpers ---
|
|
182
|
-
export { hasEslintConfig,
|
|
183
|
+
export { hasEslintConfig, hasSqlfluffConfig, hasStylelintConfig };
|
|
183
184
|
/**
|
|
184
185
|
* eslint autofix availability, per cwd + PATH. The verdict is owned by the
|
|
185
186
|
* shared availability latch (#1494): a `missing` / `non-installable` outcome
|
|
@@ -338,7 +339,7 @@ async function tryDetektFix(filePath, cwd) {
|
|
|
338
339
|
const absPath = path.resolve(cwd, filePath);
|
|
339
340
|
return detectFileChangedAfterCommand(filePath, cmd, ["--auto-correct", "--input", absPath, "--config", configPath], cwd, [1, 2]);
|
|
340
341
|
}
|
|
341
|
-
|
|
342
|
+
async function tryMarkdownlintFix(filePath, cwd) {
|
|
342
343
|
const cmd = await resolveToolCommandWithInstallFallback(cwd, "markdownlint");
|
|
343
344
|
if (!cmd)
|
|
344
345
|
return 0;
|
|
@@ -356,7 +357,7 @@ async function tryOxlintFix(filePath, cwd) {
|
|
|
356
357
|
return detectFileChangedAfterCommand(filePath, cmd, ["--fix", filePath], cwd, [1]);
|
|
357
358
|
}
|
|
358
359
|
async function tryRustClippyFix(filePath) {
|
|
359
|
-
const check = await
|
|
360
|
+
const check = await probeToolAsync("cargo", ["--version"], { timeout: 5000 });
|
|
360
361
|
if (check.error || check.status !== 0)
|
|
361
362
|
return [];
|
|
362
363
|
const cargoDir = findNearestContaining(path.dirname(path.resolve(filePath)), [
|
|
@@ -371,7 +372,7 @@ async function tryRustClippyFix(filePath) {
|
|
|
371
372
|
return diffProjectSnapshot(cargoDir, before);
|
|
372
373
|
}
|
|
373
374
|
async function tryDartFix(filePath) {
|
|
374
|
-
const check = await
|
|
375
|
+
const check = await probeToolAsync("dart", ["--version"], { timeout: 5000 });
|
|
375
376
|
if (check.error || check.status !== 0)
|
|
376
377
|
return [];
|
|
377
378
|
const pubspecDir = findNearestContaining(path.dirname(path.resolve(filePath)), ["pubspec.yaml"]);
|
|
@@ -54,7 +54,7 @@ export function readProjectChanges(cwd) {
|
|
|
54
54
|
* version — a missing/corrupt log is the normal cold-start case, not a
|
|
55
55
|
* caller-visible error.
|
|
56
56
|
*/
|
|
57
|
-
|
|
57
|
+
async function readProjectChangesAsync(cwd) {
|
|
58
58
|
const logPath = getProjectChangeLogPath(cwd);
|
|
59
59
|
try {
|
|
60
60
|
const content = await fs.promises.readFile(logPath, "utf-8");
|
|
@@ -15,7 +15,7 @@ const WARM_TRIGGER = {
|
|
|
15
15
|
"dead-code": "runs at session-start (Python projects only)",
|
|
16
16
|
"test-runner": "fires per-edit at turn_end (only after a source file with a discoverable test companion is edited)",
|
|
17
17
|
};
|
|
18
|
-
|
|
18
|
+
function warmTriggerFor(analyzerId) {
|
|
19
19
|
return WARM_TRIGGER[analyzerId] ?? "runs at session-start";
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
@@ -149,6 +149,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
149
149
|
return {
|
|
150
150
|
diagnostics: [],
|
|
151
151
|
runners: [],
|
|
152
|
+
analyzed: [],
|
|
152
153
|
cold: [...ANALYZER_IDS],
|
|
153
154
|
coldReasons: Object.fromEntries(ANALYZER_IDS.map((id) => [id, unsafeRootReason])),
|
|
154
155
|
failed: [],
|
|
@@ -158,6 +159,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
158
159
|
}
|
|
159
160
|
const diagnostics = [];
|
|
160
161
|
const runners = [];
|
|
162
|
+
const analyzed = [];
|
|
161
163
|
const cold = [];
|
|
162
164
|
// #1623: the specific reason each `cold` id was skipped, captured at the
|
|
163
165
|
// gate that decided it — see FreshProjectDiagnosticsResult.coldReasons.
|
|
@@ -188,7 +190,17 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
188
190
|
pushUnique(cold, id);
|
|
189
191
|
coldReasons[id] = reason;
|
|
190
192
|
}
|
|
191
|
-
|
|
193
|
+
/**
|
|
194
|
+
* `analysedRoot` is the client's own opt-in `AnalysedRootSignal` (#2154),
|
|
195
|
+
* never a property of reaching this function: `success: true` is also what
|
|
196
|
+
* a skipped, crashed-before-reporting or memoised run returns, and only the
|
|
197
|
+
* client knows which of those it is. Findings are recorded either way — an
|
|
198
|
+
* id that did not analyse the root simply carries no authority to retire a
|
|
199
|
+
* retained finding.
|
|
200
|
+
*/
|
|
201
|
+
function record(id, adapted, elapsedMs, analysedRoot) {
|
|
202
|
+
if (analysedRoot)
|
|
203
|
+
pushUnique(analyzed, id);
|
|
192
204
|
timings[id] = (timings[id] ?? 0) + elapsedMs;
|
|
193
205
|
const kept = applyDispositionsMultiFile(adapted, analysisRoot, (d) => d.filePath);
|
|
194
206
|
const suppressedHere = adapted.length - kept.length;
|
|
@@ -223,10 +235,17 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
223
235
|
recordFailed("knip", result);
|
|
224
236
|
return;
|
|
225
237
|
}
|
|
238
|
+
// knip reports `success: true` for a run that never happened (no
|
|
239
|
+
// project root, a memo hit, an unparseable exit-0). Those belong in
|
|
240
|
+
// the honest `cold` channel, not in "fetched fresh this call".
|
|
241
|
+
if (result.analyzed !== true) {
|
|
242
|
+
markCold("knip", result.summary ?? "knip did not analyse this root");
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
226
245
|
cacheManager.writeCache("knip", result, analysisRoot, {
|
|
227
246
|
scanDurationMs: Date.now() - startMs,
|
|
228
247
|
});
|
|
229
|
-
record("knip", knipIssuesToProjectDiagnostics(analysisRoot, result.issues ?? []), Date.now() - startMs);
|
|
248
|
+
record("knip", knipIssuesToProjectDiagnostics(analysisRoot, result.issues ?? []), Date.now() - startMs, true);
|
|
230
249
|
}),
|
|
231
250
|
// jscpd — duplicate code detection. Cache key varies with TS-project
|
|
232
251
|
// detection, exactly mirroring session_start's own logic.
|
|
@@ -243,10 +262,14 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
243
262
|
recordFailed("jscpd", result);
|
|
244
263
|
return;
|
|
245
264
|
}
|
|
265
|
+
if (result.analyzed !== true) {
|
|
266
|
+
markCold("jscpd", "jscpd did not analyse this root (no source files, or the scan produced no report)");
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
246
269
|
cacheManager.writeCache(scannerKey, result, analysisRoot, {
|
|
247
270
|
scanDurationMs: Date.now() - startMs,
|
|
248
271
|
});
|
|
249
|
-
record("jscpd", jscpdResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs);
|
|
272
|
+
record("jscpd", jscpdResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, true);
|
|
250
273
|
}),
|
|
251
274
|
// madge — circular-dependency detection.
|
|
252
275
|
task("madge", async () => {
|
|
@@ -259,7 +282,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
259
282
|
cacheManager.writeCache("madge", result, analysisRoot, {
|
|
260
283
|
scanDurationMs: Date.now() - startMs,
|
|
261
284
|
});
|
|
262
|
-
record("madge", circularDepsToProjectDiagnostics(analysisRoot, result.circular ?? []), Date.now() - startMs);
|
|
285
|
+
record("madge", circularDepsToProjectDiagnostics(analysisRoot, result.circular ?? []), Date.now() - startMs, result.analyzed === true);
|
|
263
286
|
}),
|
|
264
287
|
// gitleaks — committed-secrets detection. session_start/per-edit stay
|
|
265
288
|
// config-gated per #130's strict default (GitleaksClient.hasGitleaksSignal),
|
|
@@ -290,7 +313,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
290
313
|
cacheManager.writeCache("gitleaks", result, analysisRoot, {
|
|
291
314
|
scanDurationMs: Date.now() - startMs,
|
|
292
315
|
});
|
|
293
|
-
record("gitleaks", gitleaksResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs);
|
|
316
|
+
record("gitleaks", gitleaksResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true);
|
|
294
317
|
}),
|
|
295
318
|
// govulncheck — Go module CVE detection. Go-module-gated per #132.
|
|
296
319
|
task("govulncheck", async () => {
|
|
@@ -322,7 +345,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
322
345
|
cacheManager.writeCache("govulncheck", result, analysisRoot, {
|
|
323
346
|
scanDurationMs: Date.now() - startMs,
|
|
324
347
|
});
|
|
325
|
-
record("govulncheck", govulncheckResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs);
|
|
348
|
+
record("govulncheck", govulncheckResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true);
|
|
326
349
|
}),
|
|
327
350
|
// opengrep — full-workspace semgrep-grade security/quality findings via a
|
|
328
351
|
// single project-wide CLI scan (#584). Structurally always-on: mirrors
|
|
@@ -352,7 +375,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
352
375
|
cacheManager.writeCache("opengrep", result, analysisRoot, {
|
|
353
376
|
scanDurationMs: Date.now() - startMs,
|
|
354
377
|
});
|
|
355
|
-
record("opengrep", opengrepResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs);
|
|
378
|
+
record("opengrep", opengrepResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true);
|
|
356
379
|
}),
|
|
357
380
|
// trivy — dependency CVE detection. Explicit opt-in per #131.
|
|
358
381
|
task("trivy", async () => {
|
|
@@ -373,7 +396,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
373
396
|
cacheManager.writeCache("trivy", result, analysisRoot, {
|
|
374
397
|
scanDurationMs: Date.now() - startMs,
|
|
375
398
|
});
|
|
376
|
-
record("trivy", trivyResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs);
|
|
399
|
+
record("trivy", trivyResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true);
|
|
377
400
|
}),
|
|
378
401
|
// dead-code — cross-file dead-code for non-JS/TS languages (#127).
|
|
379
402
|
// Each client self-gates via detect(); only matching-language projects
|
|
@@ -395,7 +418,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
395
418
|
cacheManager.writeCache(cacheKey, result, analysisRoot, {
|
|
396
419
|
scanDurationMs: Date.now() - startMs,
|
|
397
420
|
});
|
|
398
|
-
record("dead-code", deadCodeResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs);
|
|
421
|
+
record("dead-code", deadCodeResultToProjectDiagnostics(analysisRoot, result), Date.now() - startMs, result.analyzed === true);
|
|
399
422
|
}));
|
|
400
423
|
}),
|
|
401
424
|
// test-runner — CACHE-READ only, unlike every task above (#1004). Its
|
|
@@ -440,7 +463,10 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
440
463
|
// looking indistinguishable from a lane that just executed.
|
|
441
464
|
cachedAgeMs["test-runner"] =
|
|
442
465
|
Date.now() - new Date(cached.meta.timestamp).getTime();
|
|
443
|
-
record("test-runner", testRunnerFindingsToProjectDiagnostics(cached.data, analysisRoot, options.runtime), Date.now() - startMs
|
|
466
|
+
record("test-runner", testRunnerFindingsToProjectDiagnostics(cached.data, analysisRoot, options.runtime), Date.now() - startMs,
|
|
467
|
+
// Never authoritative: this lane reads the cache turn_end wrote,
|
|
468
|
+
// it never runs a suite over the root this call (#2154).
|
|
469
|
+
false);
|
|
444
470
|
}),
|
|
445
471
|
];
|
|
446
472
|
// Swallow any later rejection so an aborted-and-abandoned task can never
|
|
@@ -470,6 +496,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
470
496
|
return {
|
|
471
497
|
diagnostics,
|
|
472
498
|
runners,
|
|
499
|
+
analyzed,
|
|
473
500
|
cold,
|
|
474
501
|
coldReasons,
|
|
475
502
|
failed,
|
|
@@ -484,6 +511,7 @@ export async function fetchFreshProjectDiagnostics(cacheManager, cwd, clients, s
|
|
|
484
511
|
return {
|
|
485
512
|
diagnostics,
|
|
486
513
|
runners,
|
|
514
|
+
analyzed,
|
|
487
515
|
cold,
|
|
488
516
|
coldReasons,
|
|
489
517
|
failed,
|
|
@@ -3,12 +3,11 @@ import * as path from "node:path";
|
|
|
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
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* "leaked secret" alarm, while remaining visible for an audit read.
|
|
6
|
+
* Findings in scratch trees, gitignored files, and nested repositories are
|
|
7
|
+
* retained for explicit audit but demoted to `severity: "info"` / `semantic:
|
|
8
|
+
* "none"`. They are outside the current repository's shippable source, so they
|
|
9
|
+
* must never read as blocking leaked-secret alarms. Tracked files and ordinary
|
|
10
|
+
* untracked files remain blocking.
|
|
12
11
|
*/
|
|
13
12
|
export function gitleaksFindingToProjectDiagnostic(cwd, finding) {
|
|
14
13
|
// #1562 observability criterion: surface the git status right in the
|
|
@@ -17,14 +16,16 @@ export function gitleaksFindingToProjectDiagnostic(cwd, finding) {
|
|
|
17
16
|
const statusSuffix = finding.pathStatus
|
|
18
17
|
? ` [git: ${finding.pathStatus}]`
|
|
19
18
|
: "";
|
|
20
|
-
const
|
|
19
|
+
const isBlocking = finding.pathStatus !== "scratch" &&
|
|
20
|
+
finding.pathStatus !== "ignored" &&
|
|
21
|
+
finding.pathStatus !== "nested-repository";
|
|
21
22
|
return {
|
|
22
23
|
filePath: path.isAbsolute(finding.file)
|
|
23
24
|
? finding.file
|
|
24
25
|
: path.resolve(cwd, finding.file),
|
|
25
26
|
line: finding.startLine,
|
|
26
|
-
severity:
|
|
27
|
-
semantic:
|
|
27
|
+
severity: isBlocking ? "error" : "info",
|
|
28
|
+
semantic: isBlocking ? "blocking" : "none",
|
|
28
29
|
tool: "gitleaks",
|
|
29
30
|
runner: "gitleaks",
|
|
30
31
|
rule: `gitleaks:${finding.ruleId}`,
|
|
@@ -8,7 +8,7 @@ function resolveClonePath(cwd, file) {
|
|
|
8
8
|
* BOTH ends so the duplication surfaces on whichever file the agent is looking
|
|
9
9
|
* at, each one naming the other end.
|
|
10
10
|
*/
|
|
11
|
-
|
|
11
|
+
function jscpdCloneToProjectDiagnostics(cwd, clone) {
|
|
12
12
|
const a = resolveClonePath(cwd, clone.fileA);
|
|
13
13
|
const b = resolveClonePath(cwd, clone.fileB);
|
|
14
14
|
const make = (filePath, line, otherFile, otherLine) => ({
|
|
@@ -27,7 +27,7 @@ function knipIssueMessage(issue) {
|
|
|
27
27
|
}
|
|
28
28
|
return `${issue.type}: ${issue.name}`;
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
function knipIssueToProjectDiagnostic(cwd, issue) {
|
|
31
31
|
const blocking = issue.type === "unlisted" || issue.type === "bin";
|
|
32
32
|
return {
|
|
33
33
|
filePath: knipIssueFile(cwd, issue),
|
|
@@ -12,7 +12,7 @@ function cycleMembers(dep) {
|
|
|
12
12
|
* single-point knip finding. Emit a diagnostic on EACH file in the cycle so it
|
|
13
13
|
* surfaces wherever the agent is looking, each one rendering the whole cycle.
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
function circularDepToProjectDiagnostics(cwd, dep) {
|
|
16
16
|
const members = cycleMembers(dep);
|
|
17
17
|
const rendered = `${members.map((f) => path.basename(f)).join(" → ")} → ${path.basename(members[0] ?? "")}`;
|
|
18
18
|
return members.map((file) => ({
|
|
@@ -15,7 +15,7 @@ function severityFor(raw) {
|
|
|
15
15
|
return { severity: "warning", blocking: false };
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
function opengrepFindingToProjectDiagnostic(cwd, finding) {
|
|
19
19
|
const { severity, blocking } = severityFor(finding.severity);
|
|
20
20
|
const cweSuffix = finding.cwe?.length ? ` (${finding.cwe[0]})` : "";
|
|
21
21
|
return {
|
package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js
CHANGED
|
@@ -43,7 +43,7 @@ function parseLocation(location) {
|
|
|
43
43
|
* caller deserves the same "this may already be superseded" honesty the
|
|
44
44
|
* per-edit path already gives.
|
|
45
45
|
*/
|
|
46
|
-
|
|
46
|
+
function testResultToProjectDiagnostics(result, stale = false) {
|
|
47
47
|
if (result.failed === 0 && !result.error)
|
|
48
48
|
return [];
|
|
49
49
|
const stalePrefix = stale ? "[stale — from a prior turn] " : "";
|
|
@@ -69,6 +69,7 @@ import { deprecationRecords, ignoredRecordCollector, projectLocationFor, readCon
|
|
|
69
69
|
import { finalizeRecords, } from "./config-core/records.js";
|
|
70
70
|
import { homeRelativePath, isAtOrAboveHomeDir, walkUpDirs, } from "./path-utils.js";
|
|
71
71
|
import { findPiLensConfigMarkerInDir } from "./workspace-topology.js";
|
|
72
|
+
import { readToolConfig } from "./tool-config.js";
|
|
72
73
|
/**
|
|
73
74
|
* Project config basenames, in DESCENDING precedence (first match wins), for
|
|
74
75
|
* this loader's own discovery.
|
|
@@ -162,8 +163,15 @@ export function loadPiLensProjectConfig(startDir, preloadedInfo) {
|
|
|
162
163
|
// a pi-lens-owned file were then produced by nobody at all. The pi-lens
|
|
163
164
|
// loader now enumerates those documents itself, for records only: nothing
|
|
164
165
|
// here is merged, and which file supplies a VALUE is unchanged.
|
|
165
|
-
reportPiLensConfigRecords(entry.legacyRecords);
|
|
166
166
|
const configInfo = preloadedInfo ?? freshInfoFor(entry);
|
|
167
|
+
// The selected legacy document is resolved below and its bounded migration
|
|
168
|
+
// records are cached with that projection. Reporting the discovery copy as
|
|
169
|
+
// well would produce two suppression records with different totals, because
|
|
170
|
+
// the discovery walk and the single-document resolution see different
|
|
171
|
+
// record populations. Keep discovery-only documents here; the selected file
|
|
172
|
+
// is reported by `loadCachedConfigFile`.
|
|
173
|
+
const selectedLegacyPath = configInfo?.path;
|
|
174
|
+
reportPiLensConfigRecords(entry.legacyRecords.filter((record) => record.file !== selectedLegacyPath));
|
|
167
175
|
if (!configInfo)
|
|
168
176
|
return EMPTY_PROJECT_CONFIG;
|
|
169
177
|
return loadCachedConfigFile(configInfo);
|
|
@@ -556,6 +564,7 @@ function parseConfigFile(configPath) {
|
|
|
556
564
|
for (const spec of PROJECT_SCOPED_LENS_FLAGS) {
|
|
557
565
|
assignFlagConfigSection(obj, mutations, spec.configKey, note);
|
|
558
566
|
}
|
|
567
|
+
const toolConfig = readToolConfig(obj, note);
|
|
559
568
|
const rules = {};
|
|
560
569
|
if (obj.rules && typeof obj.rules === "object" && !Array.isArray(obj.rules)) {
|
|
561
570
|
const rawRules = obj.rules;
|
|
@@ -634,6 +643,43 @@ function parseConfigFile(configPath) {
|
|
|
634
643
|
}
|
|
635
644
|
}
|
|
636
645
|
}
|
|
646
|
+
let startup;
|
|
647
|
+
if (obj.startup !== undefined) {
|
|
648
|
+
if (!obj.startup ||
|
|
649
|
+
typeof obj.startup !== "object" ||
|
|
650
|
+
Array.isArray(obj.startup)) {
|
|
651
|
+
note("startup must be an object");
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
const section = obj.startup;
|
|
655
|
+
if (section.mode === "quick" ||
|
|
656
|
+
section.mode === "full" ||
|
|
657
|
+
section.mode === "minimal") {
|
|
658
|
+
startup = { mode: section.mode };
|
|
659
|
+
}
|
|
660
|
+
else if ("mode" in section) {
|
|
661
|
+
note('startup.mode must be "quick", "full", or "minimal"');
|
|
662
|
+
}
|
|
663
|
+
if (section.scans !== undefined) {
|
|
664
|
+
if (!section.scans ||
|
|
665
|
+
typeof section.scans !== "object" ||
|
|
666
|
+
Array.isArray(section.scans)) {
|
|
667
|
+
note("startup.scans must be an object");
|
|
668
|
+
}
|
|
669
|
+
else if (typeof section.scans.enabled ===
|
|
670
|
+
"boolean") {
|
|
671
|
+
startup ??= {};
|
|
672
|
+
startup.scans = {
|
|
673
|
+
enabled: section.scans
|
|
674
|
+
.enabled,
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
else if ("enabled" in section.scans) {
|
|
678
|
+
note("startup.scans.enabled must be a boolean");
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
637
683
|
// #533 hygiene: mirror the global loader's unknown-key warn so a typo in a
|
|
638
684
|
// shared `.pi-lens.json` (e.g. `maxProjectFile`, `lps`) produces a signal
|
|
639
685
|
// instead of silently doing nothing. The recognized set is single-sourced
|
|
@@ -694,6 +740,8 @@ function parseConfigFile(configPath) {
|
|
|
694
740
|
}
|
|
695
741
|
return {
|
|
696
742
|
config: {
|
|
743
|
+
...(toolConfig === undefined ? {} : { tools: toolConfig }),
|
|
744
|
+
...(startup === undefined ? {} : { startup }),
|
|
697
745
|
ignore,
|
|
698
746
|
rules,
|
|
699
747
|
...mutations,
|