@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
|
@@ -13,6 +13,7 @@ import { getKnipIgnorePatterns } from "./file-utils.js";
|
|
|
13
13
|
import { formatCacheAgeLabel } from "./finding-delivery-gate.js";
|
|
14
14
|
import { getFullScanWallClockMs, isWorkspaceSweepActive, runWhenWorkspaceSweepIdle, SWEEP_IDLE_SAFETY_MARGIN_MS, } from "./lsp/workspace-sweep-hold.js";
|
|
15
15
|
import { isTestRoleCollateral } from "./collateral-test-role.js";
|
|
16
|
+
import { classifyAndFilterFindings, } from "./gitleaks-client.js";
|
|
16
17
|
import { dedupeSecretFindings, fromAstGrepWarnings, fromGitleaks, fromTrivySecrets, isSecretWarning, secretLocationKey, } from "./secret-findings.js";
|
|
17
18
|
import { deadCodeIssueKey, deadCodeIssues, formatDeadCodeDelta, stableFindingKey, } from "./dead-code-client.js";
|
|
18
19
|
import { logDeadCodeScan } from "./dead-code-logger.js";
|
|
@@ -49,6 +50,8 @@ import { emitBounded } from "./bounded-telemetry.js";
|
|
|
49
50
|
import { degradeDemotedFindingBody, formatDeliveryCapNote, formatRetirementNote, } from "./demoted-finding-render.js";
|
|
50
51
|
import { STALE_LINE_MARKER } from "./stale-marker.js";
|
|
51
52
|
import { getActiveSessionId } from "./session-lifecycle.js";
|
|
53
|
+
import { bounded } from "./deadline-utils.js";
|
|
54
|
+
import { HOOK_WALL_BUDGET_MS } from "./hook-budgets.js";
|
|
52
55
|
import { drainRenderedDependencyDriftFilePaths, getWidgetBlockingFilesForSweep, incrementWidgetDependencyDriftDelivery, markWidgetFileBlockersStale, recordRunner, retireWidgetDependencyDriftBlockers, } from "./widget-state.js";
|
|
53
56
|
/** Maximum detailed notify-stall coverage-gap rows emitted in one turn. */
|
|
54
57
|
const LATE_AUX_COVERAGE_GAP_DETAIL_CAP_PER_TURN = 20;
|
|
@@ -1483,6 +1486,26 @@ export async function handleTurnEnd(deps) {
|
|
|
1483
1486
|
// provenance) — a blocker, since credentials need rotation before merge.
|
|
1484
1487
|
const gitleaksData = cacheManager.readCache("gitleaks", cwd)?.data;
|
|
1485
1488
|
const trivySecretsData = trivyCacheEntry?.data;
|
|
1489
|
+
// Gitleaks deliberately scans gitignored local files and nested repositories
|
|
1490
|
+
// so an explicit security audit can still inspect them. The adapter is the
|
|
1491
|
+
// source of truth for whether a finding belongs in a blocking delivery lane;
|
|
1492
|
+
// filter here before freshness handling so demoted findings cannot leak into
|
|
1493
|
+
// either the blocker or stale-secret turn context.
|
|
1494
|
+
const boundedClassification = await bounded(classifyAndFilterFindings(gitleaksData?.findings ?? [], cwd), {
|
|
1495
|
+
ms: HOOK_WALL_BUDGET_MS.turn_end,
|
|
1496
|
+
signal: deps.signal,
|
|
1497
|
+
hook: "turn_end",
|
|
1498
|
+
label: "classifyAndFilterFindings",
|
|
1499
|
+
});
|
|
1500
|
+
const classifiedGitleaksFindings = boundedClassification ?? gitleaksData?.findings ?? [];
|
|
1501
|
+
if (boundedClassification === undefined) {
|
|
1502
|
+
recordDegradationOnce({
|
|
1503
|
+
kind: "gitleaks_classification_timeout",
|
|
1504
|
+
subject: cwd,
|
|
1505
|
+
reason: "gitleaks classification exceeded the turn_end budget; retained raw findings to fail open",
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
const blockingGitleaksFindings = classifiedGitleaksFindings.filter((finding) => gitleaksFindingToProjectDiagnostic(cwd, finding).semantic === "blocking");
|
|
1486
1509
|
// #1461 slice 1 (#1460): the gitleaks cache is TTL-only, so a finding for a
|
|
1487
1510
|
// file deleted after the scan is still served as a 🔴 blocker for the rest
|
|
1488
1511
|
// of the 30-minute window — the live case, and 119 of 126 findings in
|
|
@@ -1497,7 +1520,7 @@ export async function handleTurnEnd(deps) {
|
|
|
1497
1520
|
// would let any edit — malicious or accidental — mute a real secret.
|
|
1498
1521
|
const gitleaksGate = gateFindingsByPathFreshness({
|
|
1499
1522
|
store: "gitleaks",
|
|
1500
|
-
findings:
|
|
1523
|
+
findings: blockingGitleaksFindings,
|
|
1501
1524
|
cwd,
|
|
1502
1525
|
scannedAt: gitleaksData?.scannedAt,
|
|
1503
1526
|
citedPath: (finding) => finding.file,
|
|
@@ -2882,6 +2905,7 @@ export async function handleTurnEnd(deps) {
|
|
|
2882
2905
|
let lateAuxCoverageGapDropCount = 0;
|
|
2883
2906
|
const lateAuxStuckPairs = [];
|
|
2884
2907
|
if (drainedPairs.length > 0) {
|
|
2908
|
+
const lateObserverDeadline = Date.now() + HOOK_WALL_BUDGET_MS.turn_end;
|
|
2885
2909
|
const byFile = new Map();
|
|
2886
2910
|
for (const pair of drainedPairs) {
|
|
2887
2911
|
const list = byFile.get(pair.filePath);
|
|
@@ -2993,6 +3017,19 @@ export async function handleTurnEnd(deps) {
|
|
|
2993
3017
|
}
|
|
2994
3018
|
continue;
|
|
2995
3019
|
}
|
|
3020
|
+
// A demoted auxiliary still answers through this late path. Feed the
|
|
3021
|
+
// publication-minus-mark interval into the re-promotion streak. This is
|
|
3022
|
+
// delivery latency observed by the drain, not the scanner's total scan
|
|
3023
|
+
// latency. Cache priming is
|
|
3024
|
+
// below the freshness gate so a changed file cannot resurrect stale data.
|
|
3025
|
+
if (typeof service.observeLateAuxiliaryAnswer === "function") {
|
|
3026
|
+
await bounded(service.observeLateAuxiliaryAnswer(lateAuxPath, pair.serverId, cachedEntry.publishedAt - pair.markedAtMs), {
|
|
3027
|
+
ms: Math.max(1, lateObserverDeadline - Date.now()),
|
|
3028
|
+
signal: deps.signal /* late observer */,
|
|
3029
|
+
hook: "turn_end",
|
|
3030
|
+
label: "observeLateAuxiliaryAnswer",
|
|
3031
|
+
});
|
|
3032
|
+
}
|
|
2996
3033
|
if (rawDiags.length === 0) {
|
|
2997
3034
|
lateAuxCleanConfirmed += 1;
|
|
2998
3035
|
continue;
|
|
@@ -3045,6 +3082,16 @@ export async function handleTurnEnd(deps) {
|
|
|
3045
3082
|
}
|
|
3046
3083
|
continue;
|
|
3047
3084
|
}
|
|
3085
|
+
// #2810 round 4: this drain does NOT write the hash-bound
|
|
3086
|
+
// last-known record. The prime it used to call could only fire when
|
|
3087
|
+
// a record already existed at the pair's hash — which requires a
|
|
3088
|
+
// FULLY covered touch of those exact bytes, the one case where the
|
|
3089
|
+
// scanner's findings are already in the record — so it was a no-op
|
|
3090
|
+
// in the demoted steady state it was added for, and a #570/#1470
|
|
3091
|
+
// hazard everywhere else (an auxiliary-only array replacing the
|
|
3092
|
+
// merged one). Late findings reach the agent as the gated advisory
|
|
3093
|
+
// below; the turn-end hash-guarded fast path stays cold for a file
|
|
3094
|
+
// whose touch was partial, which is exactly what #1470 requires.
|
|
3048
3095
|
const lines = gate.live.map((f) => ` ${displayLateAuxPath}:${f.line}:${f.column} [${f.rule}] ${f.message}`);
|
|
3049
3096
|
lateAuxDelivered += gate.live.length;
|
|
3050
3097
|
lateAuxAnswered += 1;
|
|
@@ -43,17 +43,6 @@ const DETAIL_PATTERNS = [
|
|
|
43
43
|
export function stripAnsi(text) {
|
|
44
44
|
return text.replace(ANSI_ESCAPE, "").replace(ANSI_ESCAPE_EXTENDED, "");
|
|
45
45
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Normalize whitespace in a string.
|
|
48
|
-
* Collapses multiple spaces/tabs to single space, trims lines.
|
|
49
|
-
*/
|
|
50
|
-
export function normalizeWhitespace(text) {
|
|
51
|
-
return text
|
|
52
|
-
.split(/\r?\n/)
|
|
53
|
-
.map((line) => line.replace(/\s+/g, " ").trim())
|
|
54
|
-
.filter((line) => line.length > 0)
|
|
55
|
-
.join("\n");
|
|
56
|
-
}
|
|
57
46
|
/**
|
|
58
47
|
* Check if a line contains error indicators.
|
|
59
48
|
*/
|
|
@@ -1,59 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { collectSourceFiles, collectSourceFilesAsync, isBuildArtifact, } from "./source-filter.js";
|
|
3
|
-
/**
|
|
4
|
-
* Common parsing logic for ast-grep JSON output (handles both array and NDJSON).
|
|
5
|
-
*/
|
|
6
|
-
// biome-ignore lint/suspicious/noExplicitAny: ast-grep JSON output is untyped
|
|
7
|
-
export function parseAstGrepJson(raw) {
|
|
8
|
-
if (!raw)
|
|
9
|
-
return [];
|
|
10
|
-
const trimmed = raw.trim();
|
|
11
|
-
if (trimmed.startsWith("[")) {
|
|
12
|
-
try {
|
|
13
|
-
return JSON.parse(trimmed);
|
|
14
|
-
}
|
|
15
|
-
catch {
|
|
16
|
-
return [];
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return trimmed.split("\n").flatMap((l) => {
|
|
20
|
-
try {
|
|
21
|
-
return [JSON.parse(l)];
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
return [];
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Check if a file should be ignored based on project type and common patterns.
|
|
30
|
-
*
|
|
31
|
-
* @deprecated Use `isBuildArtifact()` from `source-filter.js` instead for artifact
|
|
32
|
-
* detection, or compose your own filter using `collectSourceFiles()`. This function
|
|
33
|
-
* is kept for backward compatibility.
|
|
34
|
-
*/
|
|
35
|
-
export function shouldIgnoreFile(filePath, isTsProject) {
|
|
36
|
-
const relPath = filePath.replace(/\\/g, "/");
|
|
37
|
-
// Use new source-filter module for artifact detection
|
|
38
|
-
if (isTsProject && isBuildArtifact(filePath))
|
|
39
|
-
return true;
|
|
40
|
-
// Legacy: simple JS check for non-TS projects (hand-written JS)
|
|
41
|
-
const isJs = relPath.endsWith(".js") ||
|
|
42
|
-
relPath.endsWith(".mjs") ||
|
|
43
|
-
relPath.endsWith(".cjs");
|
|
44
|
-
if (isTsProject && isJs)
|
|
45
|
-
return true;
|
|
46
|
-
// Ignore test scripts and common test patterns
|
|
47
|
-
if (isTestFile(filePath))
|
|
48
|
-
return true;
|
|
49
|
-
// Ignore hidden directories and common build outputs
|
|
50
|
-
const pathParts = relPath.split("/").filter(Boolean);
|
|
51
|
-
for (const segment of pathParts.slice(0, -1)) {
|
|
52
|
-
if (isExcludedDirName(segment))
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
1
|
+
import { collectSourceFiles, collectSourceFilesAsync, } from "./source-filter.js";
|
|
57
2
|
/**
|
|
58
3
|
* Recursively find source files in a directory, respecting common excludes.
|
|
59
4
|
*
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import * as path from "node:path";
|
|
16
16
|
import { createSubsystemLogger } from "./extension-log.js";
|
|
17
|
-
import {
|
|
17
|
+
import { probeToolAsync } from "./tool-probe.js";
|
|
18
18
|
import { classifyProbeFailure, createAvailabilityLatch, describeInstallAttempt, describeProbeEvidence, logAvailabilityDecision, startHostStallSampler, } from "./dispatch/runners/utils/availability-policy.js";
|
|
19
19
|
import { createAvailabilityProbeFlight } from "./availability-probe-flight.js";
|
|
20
20
|
import { createSingleFlight } from "./single-flight.js";
|
|
@@ -132,7 +132,7 @@ export class SecurityScanClient {
|
|
|
132
132
|
const { findManagedToolBinary } = await import("./installer/index.js");
|
|
133
133
|
const managed = await findManagedToolBinary(this.toolName);
|
|
134
134
|
return {
|
|
135
|
-
probe: await
|
|
135
|
+
probe: await probeToolAsync(managed ?? this.toolName, versionArgs, {
|
|
136
136
|
timeout: 5000,
|
|
137
137
|
}),
|
|
138
138
|
binaryPath: managed ?? null,
|
|
@@ -64,7 +64,22 @@
|
|
|
64
64
|
* wrapper narrows nothing else: a handler bug must stay as loud as it was.
|
|
65
65
|
*/
|
|
66
66
|
import { emitBounded } from "./bounded-telemetry.js";
|
|
67
|
+
import { recordDegradationOnce } from "./degradation-ledger.js";
|
|
67
68
|
import { probeCtxActive } from "./session-lifecycle.js";
|
|
69
|
+
import { runWithTurnContext } from "./turn-context.js";
|
|
70
|
+
function stableSessionId(ctx) {
|
|
71
|
+
try {
|
|
72
|
+
return ctx?.sessionManager?.getSessionId?.();
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
recordDegradationOnce({
|
|
76
|
+
kind: "turn-context-identity-fallback",
|
|
77
|
+
subject: "session-event-guard",
|
|
78
|
+
reason: "stable session identity resolution failed; using detached turn context",
|
|
79
|
+
});
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
68
83
|
/**
|
|
69
84
|
* The pi SDK invalidates a captured `pi`/command ctx after a session
|
|
70
85
|
* replacement or reload; every later `pi.*` call then throws with this
|
|
@@ -99,6 +114,59 @@ function recordStaleSkip(eventName, detectedAt) {
|
|
|
99
114
|
reason: `${eventName} skipped: extension ctx is stale (${detectedAt})`,
|
|
100
115
|
});
|
|
101
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* The one policy for "a pi hook handler threw and production swallows it"
|
|
119
|
+
* (#2884).
|
|
120
|
+
*
|
|
121
|
+
* Nine catch sites in `index.ts` absorb a crashed handler so a pi-lens bug
|
|
122
|
+
* can never take down the host's session. Each of them used to write only
|
|
123
|
+
* `dbg(...)`, and `dbg` writes nothing under vitest — so a crashed handler was
|
|
124
|
+
* indistinguishable from a completed one. #2859 is what that costs: fourteen
|
|
125
|
+
* `session_start` awaits in `tests/index-integration.test.ts` rejected into
|
|
126
|
+
* one of those catches, every assertion after them was vacuous, and the file
|
|
127
|
+
* stayed green. #2866 closed the hole for `session_start` with an inline
|
|
128
|
+
* `if (process.env.VITEST) throw`; this function is that guard folded into one
|
|
129
|
+
* place so the remaining eight cannot drift from it.
|
|
130
|
+
*
|
|
131
|
+
* Two things happen on every crash, in this order:
|
|
132
|
+
*
|
|
133
|
+
* 1. **The production record.** One bounded `hook-handler-crash` row per
|
|
134
|
+
* handler per session (`recordDegradationOnce`), so a handler that crashes
|
|
135
|
+
* on every turn leaves one durable row and an exact ledger tally instead of
|
|
136
|
+
* a silent no-op. It is written BEFORE the rethrow, so a test can assert the
|
|
137
|
+
* production observability the runner path would otherwise hide.
|
|
138
|
+
* 2. **The runner rethrow.** Under vitest the crash is rethrown, so the test
|
|
139
|
+
* whose `await` caused it fails with the real error instead of resolving.
|
|
140
|
+
* In production nothing is rethrown and the caller's swallow stands.
|
|
141
|
+
*
|
|
142
|
+
* Deliberately `process.env.VITEST` and not `isTestMode()` (kept from #2859):
|
|
143
|
+
* the question is whether a TEST is awaiting this handler, and the #2815 R7
|
|
144
|
+
* case runs under vitest with `PI_LENS_TEST_MODE=0`.
|
|
145
|
+
*
|
|
146
|
+
* The stale-ctx class is NOT this function's business. Callers that classify
|
|
147
|
+
* it (`session_start`, `agent_end`, `turn_end`, the `agent_settled` drain)
|
|
148
|
+
* rethrow `isStaleExtensionCtxError` themselves BEFORE calling in, so a benign
|
|
149
|
+
* session swap keeps its own single record and never lands here as a crash.
|
|
150
|
+
* The quiet-window site is intentionally the exception to the test-runner
|
|
151
|
+
* rethrow: it is fire-and-forget, so a rethrow would be an unhandled rejection
|
|
152
|
+
* that can terminate the pi host before its caller can observe the failure.
|
|
153
|
+
*/
|
|
154
|
+
export function surfaceHandlerCrash(handler, err, options = {}) {
|
|
155
|
+
try {
|
|
156
|
+
options.dbg?.(`${handler} crashed: ${err}`);
|
|
157
|
+
options.dbg?.(`${handler} crash stack: ${err?.stack}`);
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// A debug sink must never decide whether a crash is recorded.
|
|
161
|
+
}
|
|
162
|
+
recordDegradationOnce({
|
|
163
|
+
kind: "hook-handler-crash",
|
|
164
|
+
subject: handler,
|
|
165
|
+
reason: `${handler} handler crashed and was swallowed: ${String(err)}`,
|
|
166
|
+
});
|
|
167
|
+
if (process.env.VITEST && options.rethrow !== false)
|
|
168
|
+
throw err;
|
|
169
|
+
}
|
|
102
170
|
function isThenable(value) {
|
|
103
171
|
return (typeof value?.then === "function");
|
|
104
172
|
}
|
|
@@ -131,7 +199,7 @@ function guardSessionEvent(eventName, handler, onStaleResult, options) {
|
|
|
131
199
|
// below.
|
|
132
200
|
return skip(event, "pre-dispatch");
|
|
133
201
|
try {
|
|
134
|
-
const result = handler(event, ctx);
|
|
202
|
+
const result = runWithTurnContext(stableSessionId(ctx), () => handler(event, ctx));
|
|
135
203
|
if (isThenable(result)) {
|
|
136
204
|
// Recover the rejection in place. The host awaits the same promise
|
|
137
205
|
// it would have awaited anyway; it just resolves instead.
|
|
@@ -1,30 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Session Summary — generates turn_end and session-end summaries
|
|
3
3
|
*/
|
|
4
|
-
export function formatSessionSummary(stats) {
|
|
5
|
-
if (stats.totalShown === 0)
|
|
6
|
-
return "";
|
|
7
|
-
const lines = [
|
|
8
|
-
"## Diagnostic Summary",
|
|
9
|
-
"",
|
|
10
|
-
`Shown to agent: ${stats.totalShown}`,
|
|
11
|
-
`Auto-fixed: ${stats.totalAutoFixed} (${pct(stats.totalAutoFixed, stats.totalShown)}%)`,
|
|
12
|
-
`Fixed by agent: ${stats.totalAgentFixed} (${pct(stats.totalAgentFixed, stats.totalShown)}%)`,
|
|
13
|
-
"",
|
|
14
|
-
];
|
|
15
|
-
if (stats.topViolations.length > 0) {
|
|
16
|
-
lines.push("Top violations:");
|
|
17
|
-
for (const { ruleId, count } of stats.topViolations.slice(0, 5)) {
|
|
18
|
-
lines.push(` - ${ruleId} (${count}x)`);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return lines.join("\n");
|
|
22
|
-
}
|
|
23
|
-
function pct(part, total) {
|
|
24
|
-
if (total === 0)
|
|
25
|
-
return "0";
|
|
26
|
-
return Math.round((part / total) * 100).toString();
|
|
27
|
-
}
|
|
28
4
|
export function formatSlopScoreSummary(summary) {
|
|
29
5
|
if (summary.totalRuleDiagnostics === 0 || summary.totalKlocWritten <= 0) {
|
|
30
6
|
return "";
|
|
@@ -12,6 +12,7 @@ import { getSgCommand, resolveManagedToolClient, } from "./dispatch/runners/util
|
|
|
12
12
|
import { getProjectIgnoreGlobs } from "./file-utils.js";
|
|
13
13
|
import { findGlobalBinary } from "./package-manager.js";
|
|
14
14
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
15
|
+
import { probeToolAsync } from "./tool-probe.js";
|
|
15
16
|
import { truncatedByOutputCap } from "./spawn-output-cap.js";
|
|
16
17
|
import { createSingleFlight } from "./single-flight.js";
|
|
17
18
|
import { classifyProbeFailure, describeInstallAttempt, createAvailabilityLatch, logAvailabilityDecision, startHostStallSampler, } from "./dispatch/runners/utils/availability-policy.js";
|
|
@@ -459,7 +460,7 @@ export class SgRunner {
|
|
|
459
460
|
let result;
|
|
460
461
|
let hostStallMs;
|
|
461
462
|
try {
|
|
462
|
-
result = await
|
|
463
|
+
result = await probeToolAsync(cmd, [...argsPrefix, "--version"], {
|
|
463
464
|
timeout: PROBE_TIMEOUT_MS,
|
|
464
465
|
});
|
|
465
466
|
}
|
|
@@ -8,7 +8,7 @@ import { findLocalToolConfig } from "./path-utils.js";
|
|
|
8
8
|
// ast-grep's root config marker. The `ast-grep lsp` server is workspace-gated:
|
|
9
9
|
// it only operates in a project that has an `sgconfig.y[a]ml` at (or above) the
|
|
10
10
|
// file. These are the names ast-grep itself looks for as root markers.
|
|
11
|
-
|
|
11
|
+
const SGCONFIG_NAMES = ["sgconfig.yml", "sgconfig.yaml"];
|
|
12
12
|
/**
|
|
13
13
|
* Nearest `sgconfig.y[a]ml` walking up from `startDir`, or undefined if none.
|
|
14
14
|
* Deliberately UNCEILINGED at $HOME (refs #2472 review round 3, F1): ast-grep
|
|
@@ -65,10 +65,6 @@ export function getAstGrepRuleSources(projectRoot = process.cwd()) {
|
|
|
65
65
|
return true;
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
|
-
/** Compatibility export retained for callers that only need ordered dirs. */
|
|
69
|
-
export function shippedRuleDirsInPrecedenceOrder(projectRoot = process.cwd()) {
|
|
70
|
-
return getAstGrepRuleSources(projectRoot).map((source) => source.dir);
|
|
71
|
-
}
|
|
72
68
|
function findYamlFiles(dir) {
|
|
73
69
|
const files = [];
|
|
74
70
|
let entries;
|
|
@@ -115,7 +115,7 @@ function isCleanDryRun(argsAfterVerb) {
|
|
|
115
115
|
* replacement for the forbidden `git stash`. Blocking it would push
|
|
116
116
|
* operators back toward stash.
|
|
117
117
|
*/
|
|
118
|
-
|
|
118
|
+
const WORKTREE_MUTATING_GIT_MATCHER = {
|
|
119
119
|
id: "worktree-mutating",
|
|
120
120
|
indirectAlwaysMatches: false,
|
|
121
121
|
// `git checkout --help` opens documentation and changes nothing. This
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { logExtension } from "./extension-log.js";
|
|
2
|
+
import { TOOL_REGISTRY } from "./tool-config.js";
|
|
3
|
+
const situationalTools = TOOL_REGISTRY.filter((tool) => "situational" in tool && tool.situational === true).map((tool) => tool.name);
|
|
4
|
+
const situationalToolSet = new Set(situationalTools);
|
|
5
|
+
const activated = new Set();
|
|
6
|
+
const called = new Set();
|
|
7
|
+
let sessionStarted = false;
|
|
8
|
+
let emitted = false;
|
|
9
|
+
// MCP-only connection-terminal latch: once the connection's row is recorded,
|
|
10
|
+
// repeated initialize/tool-call starts must not reopen the session.
|
|
11
|
+
let connectionEnded = false;
|
|
12
|
+
// Which host owns the open session; only MCP may arm connectionEnded. Pi state
|
|
13
|
+
// belongs to the conversation and survives in-process session rebuilds.
|
|
14
|
+
let sessionHost = "mcp";
|
|
15
|
+
function observe(set, name) {
|
|
16
|
+
if (situationalToolSet.has(name)) {
|
|
17
|
+
set.add(name);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function clearObservations() {
|
|
21
|
+
activated.clear();
|
|
22
|
+
called.clear();
|
|
23
|
+
}
|
|
24
|
+
export function observeSituationalToolActivation(names) {
|
|
25
|
+
for (const name of names)
|
|
26
|
+
observe(activated, name);
|
|
27
|
+
}
|
|
28
|
+
export function observeSituationalToolCall(name) {
|
|
29
|
+
observe(called, name);
|
|
30
|
+
}
|
|
31
|
+
export function resetSituationalToolTelemetry() {
|
|
32
|
+
// A live telemetry session owns its observation sets: both hosts open the
|
|
33
|
+
// session (which resets the sets) BEFORE handleSessionStart runs, and a
|
|
34
|
+
// repeated MCP session_start refresh legitimately re-runs that handler —
|
|
35
|
+
// clearing here would wipe the calls recorded before the refresh. This
|
|
36
|
+
// registered reset therefore only acts when no session is open.
|
|
37
|
+
if (sessionStarted)
|
|
38
|
+
return;
|
|
39
|
+
clearObservations();
|
|
40
|
+
emitted = false;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Open the telemetry session for one host.
|
|
44
|
+
*
|
|
45
|
+
* Pi owns one observation set per session file. A shutdown with a
|
|
46
|
+
* `targetSessionFile` emits the conversation that is ending before the host
|
|
47
|
+
* opens the replacement. Reload keeps the same file, so its factory rebuild
|
|
48
|
+
* does not split the row. A process restart opens an empty set and recovers nothing:
|
|
49
|
+
* pi-lens's own activation memory (`rememberedLazyTools` in `index.ts`) is
|
|
50
|
+
* empty in a new process, so the restore deactivates every situational tool,
|
|
51
|
+
* and the host's restored active set is evidence of REGISTRATION, not of
|
|
52
|
+
* model activation (#2866 review F1). MCP remains connection-scoped.
|
|
53
|
+
*/
|
|
54
|
+
export function startSituationalToolTelemetrySession(host) {
|
|
55
|
+
if (host === "mcp") {
|
|
56
|
+
if (connectionEnded)
|
|
57
|
+
return;
|
|
58
|
+
if (sessionStarted)
|
|
59
|
+
return;
|
|
60
|
+
sessionHost = "mcp";
|
|
61
|
+
clearObservations();
|
|
62
|
+
emitted = false;
|
|
63
|
+
sessionStarted = true;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (sessionStarted) {
|
|
67
|
+
sessionHost = "pi";
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
sessionHost = "pi";
|
|
71
|
+
clearObservations();
|
|
72
|
+
emitted = false;
|
|
73
|
+
sessionStarted = true;
|
|
74
|
+
}
|
|
75
|
+
/** Emit the one session-end row and make repeated shutdown calls harmless. */
|
|
76
|
+
export function endSituationalToolTelemetry() {
|
|
77
|
+
if (!sessionStarted)
|
|
78
|
+
return;
|
|
79
|
+
emitSituationalDeadWeight();
|
|
80
|
+
if (sessionHost === "mcp")
|
|
81
|
+
connectionEnded = true;
|
|
82
|
+
clearObservations();
|
|
83
|
+
emitted = false;
|
|
84
|
+
sessionStarted = false;
|
|
85
|
+
}
|
|
86
|
+
export function emitSituationalDeadWeight() {
|
|
87
|
+
if (emitted)
|
|
88
|
+
return;
|
|
89
|
+
emitted = true;
|
|
90
|
+
const used = new Set([...activated, ...called]);
|
|
91
|
+
logExtension({
|
|
92
|
+
subsystem: "tools",
|
|
93
|
+
level: "debug",
|
|
94
|
+
message: "situational tool dead weight",
|
|
95
|
+
metadata: {
|
|
96
|
+
tools: situationalTools.filter((name) => !used.has(name)),
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/** Test-only view of the module's state, for the #1635 session-state registry probe. */
|
|
101
|
+
export function _getSituationalToolTelemetryStateForTests() {
|
|
102
|
+
return {
|
|
103
|
+
activated: activated.size,
|
|
104
|
+
called: called.size,
|
|
105
|
+
emitted,
|
|
106
|
+
sessionStarted,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
@@ -58,11 +58,11 @@ import * as path from "node:path";
|
|
|
58
58
|
import { getGlobalPiLensLogDir } from "./probe-home-state.js";
|
|
59
59
|
/** Bounded tail-read budget PER source log file — never a full-file scan. */
|
|
60
60
|
export const SMELLS_TAIL_BYTES_PER_FILE = 64 * 1024;
|
|
61
|
-
|
|
61
|
+
const SMELLS_ROLLING_WINDOW_MS = 24 * 60 * 60_000;
|
|
62
62
|
/** Re-check cadence at `turn_end`, mirroring `memory-sampler.ts`'s pattern —
|
|
63
63
|
* cheap enough (bounded ~128KB I/O) not to need finer throttling, but a
|
|
64
64
|
* fixed interval keeps it from running on every single turn. */
|
|
65
|
-
|
|
65
|
+
const SMELLS_TURN_CHECK_INTERVAL = 20;
|
|
66
66
|
/** Trivial threshold constants (#1123 item 3's explicit design ask). Counts
|
|
67
67
|
* strictly below these never surface anywhere. */
|
|
68
68
|
export const SMELLS_THRESHOLDS = {
|
|
@@ -16,7 +16,7 @@ import { isAtOrAboveHomeDir } from "./path-utils.js";
|
|
|
16
16
|
import { getStartupScanMaxSourceFilesDerived } from "./project-scale.js";
|
|
17
17
|
import { shouldRecurseIntoDir, walkTreeStackAsync, walkTreeStackSync, } from "./source-walker.js";
|
|
18
18
|
import { getDirectoryMarkers, registerWorkspaceTopologyReset, } from "./workspace-topology.js";
|
|
19
|
-
|
|
19
|
+
const PROJECT_ROOT_MARKERS = [
|
|
20
20
|
".git",
|
|
21
21
|
"package.json",
|
|
22
22
|
"pyproject.toml",
|
|
@@ -24,16 +24,8 @@ export const PROJECT_ROOT_MARKERS = [
|
|
|
24
24
|
"go.mod",
|
|
25
25
|
"composer.json",
|
|
26
26
|
];
|
|
27
|
-
// Deprecated (#776): no longer read directly below — `computeStartupScanContext`
|
|
28
|
-
// / `resolveStartupScanContextAsync` now default `maxSourceFiles` to
|
|
29
|
-
// `getStartupScanMaxSourceFilesDerived(cwd)` (project-scale.ts's
|
|
30
|
-
// `maxProjectFiles` knob), which reproduces this same 2,000 value at the
|
|
31
|
-
// default base. Kept exported for tests/callers that still reference the
|
|
32
|
-
// literal.
|
|
33
|
-
export const MAX_STARTUP_SOURCE_FILES = 2000;
|
|
34
27
|
// #758: hard ceiling on the number of directory entries the startup source
|
|
35
28
|
// count walk will visit before it gives up and declares the tree too big to
|
|
36
|
-
// warm. The source-file early-exit (MAX_STARTUP_SOURCE_FILES) only fires when
|
|
37
29
|
// a project has MANY source files — a repo with FEW source files but a huge
|
|
38
30
|
// pile of non-source files (e.g. a game mod: 300 scripts among 84k data files)
|
|
39
31
|
// never trips it, so the pre-#758 walk traversed the entire tree, dominated by
|
|
@@ -77,7 +69,7 @@ export const _resetStartupScanMaxEntriesForTests = _maxEntries._resetForTests;
|
|
|
77
69
|
*
|
|
78
70
|
* The content-derived reasons `too-many-source-files` and `too-many-entries`
|
|
79
71
|
* (#758) are the ones that are TTL'd. They can go stale on their own: the repo
|
|
80
|
-
* can shrink below
|
|
72
|
+
* can shrink below the source-file cap (or below the entry ceiling)
|
|
81
73
|
* between sessions, and nothing else would notice
|
|
82
74
|
* — the seq-based freshness check that guards every other
|
|
83
75
|
* `project-snapshot.json` field never fires for them, because pi-lens never
|