@herbertgao/pi-extensions 2026.8.4 → 2026.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
- package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
- package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
- package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
- package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
- package/node_modules/@narumitw/pi-btw/README.md +32 -24
- package/node_modules/@narumitw/pi-btw/package.json +6 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
- package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
- package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
- package/node_modules/pi-lens/CHANGELOG.md +2535 -954
- package/node_modules/pi-lens/README.md +13 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
- package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
- package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
- package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
- package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
- package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
- package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
- package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
- package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
- package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
- package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
- package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
- package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
- package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
- package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
- package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
- package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
- package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
- package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
- package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
- package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
- package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
- package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
- package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
- package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
- package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
- package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
- package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
- package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
- package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
- package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
- package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
- package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
- package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
- package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
- package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
- package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
- package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
- package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
- package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
- package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
- package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
- package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
- package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
- package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
- package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
- package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
- package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
- package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
- package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
- package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
- package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
- package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
- package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
- package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
- package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
- package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
- package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
- package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
- package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
- package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
- package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
- package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
- package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
- package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
- package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
- package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
- package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
- package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
- package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
- package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
- package/node_modules/pi-lens/dist/index.js +51785 -36118
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
- package/node_modules/pi-lens/dist/mcp/server.js +219 -46
- package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
- package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
- package/node_modules/pi-lens/docs/agent-guide.md +40 -15
- package/node_modules/pi-lens/docs/agent-tools.md +21 -10
- package/node_modules/pi-lens/docs/analysisall.md +192 -0
- package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
- package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
- package/node_modules/pi-lens/docs/environment-variables.md +44 -0
- package/node_modules/pi-lens/docs/fable.md +27 -0
- package/node_modules/pi-lens/docs/features.md +45 -3
- package/node_modules/pi-lens/docs/globalconfig.md +56 -1
- package/node_modules/pi-lens/docs/language-coverage.md +4 -3
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
- package/node_modules/pi-lens/docs/mcp.md +37 -4
- package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
- package/node_modules/pi-lens/docs/settings.md +18 -1
- package/node_modules/pi-lens/docs/tools.md +4 -1
- package/node_modules/pi-lens/docs/usage.md +41 -5
- package/node_modules/pi-lens/docs/word-index.md +35 -0
- package/node_modules/pi-lens/package.json +10 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
- package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
- package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
- package/node_modules/pi-mcp-adapter/README.md +38 -4
- package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
- package/node_modules/pi-mcp-adapter/cli.js +25 -4
- package/node_modules/pi-mcp-adapter/commands.ts +15 -7
- package/node_modules/pi-mcp-adapter/config.ts +4 -4
- package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
- package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
- package/node_modules/pi-mcp-adapter/index.ts +8 -3
- package/node_modules/pi-mcp-adapter/init.ts +29 -5
- package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
- package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
- package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
- package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
- package/node_modules/pi-mcp-adapter/package.json +4 -3
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
- package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
- package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
- package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
- package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
- package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
- package/node_modules/pi-mcp-adapter/types.ts +176 -27
- package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
- package/node_modules/pi-web-access/CHANGELOG.md +14 -0
- package/node_modules/pi-web-access/README.md +18 -12
- package/node_modules/pi-web-access/auth-fetch.ts +148 -0
- package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
- package/node_modules/pi-web-access/curator-page.ts +5 -3
- package/node_modules/pi-web-access/curator-server.ts +2 -1
- package/node_modules/pi-web-access/extract.ts +106 -34
- package/node_modules/pi-web-access/fetch-params.ts +17 -3
- package/node_modules/pi-web-access/firecrawl.ts +172 -12
- package/node_modules/pi-web-access/gemini-search.ts +18 -4
- package/node_modules/pi-web-access/index.ts +120 -48
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/summary-review.ts +11 -5
- package/node_modules/pi-web-access/youtube-extract.ts +2 -2
- package/package.json +12 -13
- package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
- package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
- package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
- package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
- package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
- package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
- package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
- package/node_modules/pi-lens/dist/clients/types.js +0 -11
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
import { createHash } from "node:crypto";
|
|
57
57
|
import * as fs from "node:fs";
|
|
58
58
|
import * as path from "node:path";
|
|
59
|
-
import {
|
|
59
|
+
import { commitDurableStore } from "./durable-store.js";
|
|
60
60
|
import { logDispositionEvent } from "./disposition-logger.js";
|
|
61
61
|
import { publishDisposition } from "./disposition-publish.js";
|
|
62
62
|
import { getProjectDataDir } from "./file-utils.js";
|
|
@@ -140,11 +140,27 @@ function statePath(cwd) {
|
|
|
140
140
|
return path.join(getProjectDataDir(cwd), "cache", "diagnostic-dispositions.json");
|
|
141
141
|
}
|
|
142
142
|
let stateCache = null;
|
|
143
|
+
const DISPOSITION_LOCK_WAIT_MS = 2_000;
|
|
144
|
+
const DISPOSITION_LOCK_RETRY_MS = 10;
|
|
145
|
+
let beforeDispositionCommitForTests = null;
|
|
146
|
+
let beforeDispositionCacheRefreshForTests = null;
|
|
147
|
+
let dispositionStatSync = fs.statSync;
|
|
148
|
+
/** Test seam after the caller's cached read and before commit lock acquisition. */
|
|
149
|
+
export function _setBeforeDispositionCommitForTests(hook) {
|
|
150
|
+
beforeDispositionCommitForTests = hook;
|
|
151
|
+
}
|
|
152
|
+
/** Test seam immediately before the committed state refreshes the cache. */
|
|
153
|
+
export function _setBeforeDispositionCacheRefreshForTests(hook) {
|
|
154
|
+
beforeDispositionCacheRefreshForTests = hook;
|
|
155
|
+
}
|
|
156
|
+
export function _setDispositionStatForTests(statSync) {
|
|
157
|
+
dispositionStatSync = statSync ?? fs.statSync;
|
|
158
|
+
}
|
|
143
159
|
function readState(cwd) {
|
|
144
160
|
const p = statePath(cwd);
|
|
145
161
|
let stat;
|
|
146
162
|
try {
|
|
147
|
-
stat =
|
|
163
|
+
stat = dispositionStatSync(p);
|
|
148
164
|
}
|
|
149
165
|
catch {
|
|
150
166
|
if (stateCache && stateCache.path === p && stateCache.missing) {
|
|
@@ -188,6 +204,17 @@ function readState(cwd) {
|
|
|
188
204
|
};
|
|
189
205
|
return state;
|
|
190
206
|
}
|
|
207
|
+
function deserializeState(contents) {
|
|
208
|
+
try {
|
|
209
|
+
const parsed = JSON.parse(contents ?? "");
|
|
210
|
+
return parsed && typeof parsed === "object"
|
|
211
|
+
? parsed
|
|
212
|
+
: {};
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
return {};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
191
218
|
// Atomic tmp+rename via clients/atomic-write.ts (#762; shared with
|
|
192
219
|
// instance-registry.ts / recent-touches.ts / review-graph/builder.ts): a
|
|
193
220
|
// cross-process reader must never observe a partially-written file —
|
|
@@ -198,10 +225,7 @@ function readState(cwd) {
|
|
|
198
225
|
// failure still propagates (matches the pre-atomic writeFileSync's behavior,
|
|
199
226
|
// which never swallowed errors either) — a disposition mark silently vanishing
|
|
200
227
|
// is a correctness bug for this store, not just a lost observability sample.
|
|
201
|
-
function
|
|
202
|
-
const p = statePath(cwd);
|
|
203
|
-
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
204
|
-
writeFileAtomic(p, JSON.stringify(state, null, 2), { bestEffort: false });
|
|
228
|
+
function refreshStateCache(p, state) {
|
|
205
229
|
// Refresh the cache from the write we just did instead of invalidating it —
|
|
206
230
|
// avoids an immediate re-stat+re-parse of the file we already have in hand,
|
|
207
231
|
// and guards against coarse filesystem mtime granularity making a
|
|
@@ -215,6 +239,33 @@ function writeState(cwd, state) {
|
|
|
215
239
|
state,
|
|
216
240
|
};
|
|
217
241
|
}
|
|
242
|
+
function commitDisposition(cwd, anchor, entry) {
|
|
243
|
+
const p = statePath(cwd);
|
|
244
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
245
|
+
const hook = beforeDispositionCommitForTests;
|
|
246
|
+
beforeDispositionCommitForTests = null;
|
|
247
|
+
hook?.();
|
|
248
|
+
commitDurableStore({
|
|
249
|
+
path: p,
|
|
250
|
+
deserialize: deserializeState,
|
|
251
|
+
merge: (state) => {
|
|
252
|
+
state.dispositions ??= {};
|
|
253
|
+
state.dispositions[anchor] = entry;
|
|
254
|
+
return state;
|
|
255
|
+
},
|
|
256
|
+
serialize: (state) => JSON.stringify(state, null, 2),
|
|
257
|
+
waitMs: DISPOSITION_LOCK_WAIT_MS,
|
|
258
|
+
retryMs: DISPOSITION_LOCK_RETRY_MS,
|
|
259
|
+
timeoutMessage: "timed out acquiring diagnostic disposition store lock",
|
|
260
|
+
onContention: "throw",
|
|
261
|
+
afterWriteLocked: (state) => {
|
|
262
|
+
const cacheHook = beforeDispositionCacheRefreshForTests;
|
|
263
|
+
beforeDispositionCacheRefreshForTests = null;
|
|
264
|
+
cacheHook?.();
|
|
265
|
+
refreshStateCache(p, state);
|
|
266
|
+
},
|
|
267
|
+
});
|
|
268
|
+
}
|
|
218
269
|
/** Test-only escape hatch — the state cache is module-level, so tests that
|
|
219
270
|
* write the store file out-of-band (or across separate cwds sharing a stat
|
|
220
271
|
* coincidence) need to reset it between cases. */
|
|
@@ -227,7 +278,7 @@ export function _resetStateCacheForTests() {
|
|
|
227
278
|
* Neither can throw into the mark path; both are already internally
|
|
228
279
|
* fail-safe, but the try/catch keeps a future regression in either from
|
|
229
280
|
* breaking a mark. */
|
|
230
|
-
function emitMarkTelemetry(cwd, target, disposition, anchor, reason, existing) {
|
|
281
|
+
function emitMarkTelemetry(cwd, target, disposition, anchor, reason, existing, identity) {
|
|
231
282
|
try {
|
|
232
283
|
logDispositionEvent({
|
|
233
284
|
event: "mark",
|
|
@@ -239,6 +290,8 @@ function emitMarkTelemetry(cwd, target, disposition, anchor, reason, existing) {
|
|
|
239
290
|
reason,
|
|
240
291
|
anchor,
|
|
241
292
|
previousDisposition: existing?.disposition,
|
|
293
|
+
model: identity?.model || undefined,
|
|
294
|
+
provider: identity?.provider || undefined,
|
|
242
295
|
});
|
|
243
296
|
publishDisposition({
|
|
244
297
|
cwd,
|
|
@@ -266,7 +319,7 @@ function emitMarkTelemetry(cwd, target, disposition, anchor, reason, existing) {
|
|
|
266
319
|
* hang off it, so the agent tool and any future UI caller are covered without
|
|
267
320
|
* per-caller wiring.
|
|
268
321
|
*/
|
|
269
|
-
export function markDisposition(cwd, target, disposition, reason) {
|
|
322
|
+
export function markDisposition(cwd, target, disposition, reason, identity) {
|
|
270
323
|
const anchor = disposition === "false-positive"
|
|
271
324
|
? computeStrictAnchor(target)
|
|
272
325
|
: computeWeakAnchor(target);
|
|
@@ -274,19 +327,17 @@ export function markDisposition(cwd, target, disposition, reason) {
|
|
|
274
327
|
// entry can already exist at the same weak anchor (a prior flagged/suppress
|
|
275
328
|
// mark) — the log should record what this mark shadowed either way.
|
|
276
329
|
const existing = readState(cwd).dispositions?.[anchor];
|
|
277
|
-
emitMarkTelemetry(cwd, target, disposition, anchor, reason, existing);
|
|
278
330
|
if (disposition === "defer") {
|
|
279
331
|
deferredThisSession.add(anchor);
|
|
332
|
+
emitMarkTelemetry(cwd, target, disposition, anchor, reason, existing, identity);
|
|
280
333
|
return anchor;
|
|
281
334
|
}
|
|
282
|
-
const state = readState(cwd);
|
|
283
|
-
state.dispositions ??= {};
|
|
284
335
|
const now = new Date().toISOString();
|
|
285
336
|
const capturesFixContext = disposition === "flagged";
|
|
286
337
|
const lineText = capturesFixContext
|
|
287
338
|
? (target.content?.split(/\r?\n/)[target.line !== undefined ? target.line - 1 : -1] ?? existing?.lineText)?.trim()
|
|
288
339
|
: existing?.lineText;
|
|
289
|
-
|
|
340
|
+
const entry = {
|
|
290
341
|
disposition,
|
|
291
342
|
reason: reason ?? existing?.reason,
|
|
292
343
|
createdAt: existing?.createdAt ?? now,
|
|
@@ -294,7 +345,8 @@ export function markDisposition(cwd, target, disposition, reason) {
|
|
|
294
345
|
line: capturesFixContext ? (target.line ?? existing?.line) : existing?.line,
|
|
295
346
|
lineText,
|
|
296
347
|
};
|
|
297
|
-
|
|
348
|
+
commitDisposition(cwd, anchor, entry);
|
|
349
|
+
emitMarkTelemetry(cwd, target, disposition, anchor, reason, existing, identity);
|
|
298
350
|
return anchor;
|
|
299
351
|
}
|
|
300
352
|
export function getDisposition(cwd, anchor) {
|
|
@@ -61,12 +61,13 @@
|
|
|
61
61
|
*/
|
|
62
62
|
import { logBusEvent } from "./bus-events-logger.js";
|
|
63
63
|
import { normalizeFilePath } from "./path-utils.js";
|
|
64
|
+
import { createLiveBusEmitter, recordStaleBusFailure, resolveLiveBusEmitter, } from "./live-bus-emitter.js";
|
|
64
65
|
import { isBusPublishEnabled } from "./bus-publish.js";
|
|
65
66
|
export const BUS_DIAGNOSTICS_EVENT = "pilens:diagnostics";
|
|
66
67
|
export const BUS_DIAGNOSTICS_VERSION = 1;
|
|
67
68
|
/** Max diagnostics carried per file per event — aligned with the widget's own per-file storage cap (`MAX_STORED_DIAGNOSTICS_PER_FILE`, clients/widget-state.ts). */
|
|
68
69
|
export const MAX_DIAGNOSTICS_PER_FILE_EVENT = 12;
|
|
69
|
-
|
|
70
|
+
const liveEmitter = createLiveBusEmitter();
|
|
70
71
|
let hasLoggedFailure = false;
|
|
71
72
|
let hasLoggedUnwired = false;
|
|
72
73
|
let hasLoggedDisabled = false;
|
|
@@ -79,11 +80,14 @@ const reportedDirtyPaths = new Set();
|
|
|
79
80
|
* producers share the identical `pi.events.emit` binding.
|
|
80
81
|
*/
|
|
81
82
|
export function wireDiagnosticsBusEmitter(emitFn) {
|
|
82
|
-
|
|
83
|
+
liveEmitter.wire(emitFn);
|
|
84
|
+
}
|
|
85
|
+
export function wireDiagnosticsBusEmitterGetter(getter) {
|
|
86
|
+
liveEmitter.wireGetter(getter);
|
|
83
87
|
}
|
|
84
88
|
/** Test-only: reset module state between test files. */
|
|
85
89
|
export function _resetDiagnosticsPublishForTests() {
|
|
86
|
-
|
|
90
|
+
liveEmitter.reset();
|
|
87
91
|
hasLoggedFailure = false;
|
|
88
92
|
hasLoggedUnwired = false;
|
|
89
93
|
hasLoggedDisabled = false;
|
|
@@ -145,7 +149,13 @@ export function publishDiagnostics(args) {
|
|
|
145
149
|
}
|
|
146
150
|
return;
|
|
147
151
|
}
|
|
148
|
-
|
|
152
|
+
const resolution = resolveLiveBusEmitter(liveEmitter, () => ({
|
|
153
|
+
event: BUS_DIAGNOSTICS_EVENT,
|
|
154
|
+
cwd: normalizeFilePath(args.cwd),
|
|
155
|
+
}));
|
|
156
|
+
if (resolution.outcome === "stale-session")
|
|
157
|
+
return;
|
|
158
|
+
if (resolution.outcome === "unwired") {
|
|
149
159
|
if (!hasLoggedUnwired) {
|
|
150
160
|
hasLoggedUnwired = true;
|
|
151
161
|
logBusEvent({
|
|
@@ -156,6 +166,7 @@ export function publishDiagnostics(args) {
|
|
|
156
166
|
}
|
|
157
167
|
return;
|
|
158
168
|
}
|
|
169
|
+
const busEmit = resolution.emit;
|
|
159
170
|
try {
|
|
160
171
|
const fileEntries = args.files.map((f) => {
|
|
161
172
|
const normPath = normalizeFilePath(f.path);
|
|
@@ -184,6 +195,7 @@ export function publishDiagnostics(args) {
|
|
|
184
195
|
files: fileEntries,
|
|
185
196
|
};
|
|
186
197
|
busEmit(BUS_DIAGNOSTICS_EVENT, payload);
|
|
198
|
+
hasLoggedFailure = false;
|
|
187
199
|
logBusEvent({
|
|
188
200
|
event: BUS_DIAGNOSTICS_EVENT,
|
|
189
201
|
outcome: "emitted",
|
|
@@ -198,9 +210,11 @@ export function publishDiagnostics(args) {
|
|
|
198
210
|
outcome: "emit_failed",
|
|
199
211
|
cwd: normalizeFilePath(args.cwd),
|
|
200
212
|
error: String(err),
|
|
213
|
+
ctxSource: resolution.ctxSource,
|
|
201
214
|
});
|
|
202
215
|
if (!hasLoggedFailure) {
|
|
203
216
|
hasLoggedFailure = true;
|
|
217
|
+
recordStaleBusFailure(BUS_DIAGNOSTICS_EVENT, err);
|
|
204
218
|
args.dbg?.(`diagnostics-publish: pilens:diagnostics emit failed (further failures suppressed): ${err}`);
|
|
205
219
|
}
|
|
206
220
|
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - OutputSemantic: How to display (blocking, warning, silent, etc.)
|
|
14
14
|
* - BaselineStore: Track pre-existing issues for delta mode
|
|
15
15
|
*/
|
|
16
|
+
import { logExtension } from "../extension-log.js";
|
|
16
17
|
import * as fs from "node:fs";
|
|
17
18
|
import * as path from "node:path";
|
|
18
19
|
import { recordRunner } from "../widget-state.js";
|
|
@@ -28,10 +29,12 @@ import { loadPiLensProjectConfig } from "../project-lens-config.js";
|
|
|
28
29
|
import { RUNTIME_CONFIG, getRunnerTimeoutFloorMs } from "../runtime-config.js";
|
|
29
30
|
import { safeSpawnAsync } from "../safe-spawn.js";
|
|
30
31
|
import { classifyDiagnostic } from "./diagnostic-taxonomy.js";
|
|
32
|
+
import { classifyProbeFailure, logAvailabilityDecision, startHostStallSampler, transientRetryDelayMs, } from "./runners/utils/availability-policy.js";
|
|
31
33
|
import { applyDispositions } from "../diagnostic-dispositions.js";
|
|
32
34
|
import { applyInlineSuppressions } from "./inline-suppressions.js";
|
|
33
35
|
import { getToolPlan } from "./plan.js";
|
|
34
36
|
import { resolveRunnerPath } from "./runner-context.js";
|
|
37
|
+
import { applyRulePolicy, rulePolicyMapFromConfig } from "./rule-policy.js";
|
|
35
38
|
import { getToolProfile } from "./tool-profile.js";
|
|
36
39
|
import { formatDiagnostics } from "./utils/format-utils.js";
|
|
37
40
|
// --- Runner Registry ---
|
|
@@ -74,12 +77,49 @@ export function normalizeCacheKey(cmd) {
|
|
|
74
77
|
const normalized = cmd.replace(/\.(cmd|exe)$/i, "").toLowerCase();
|
|
75
78
|
return `session.toolCache.${normalized}`;
|
|
76
79
|
}
|
|
77
|
-
|
|
80
|
+
/** Probe budget for the generic `hasTool` availability check, ms. */
|
|
81
|
+
const TOOL_PROBE_TIMEOUT_MS = 5000;
|
|
82
|
+
/**
|
|
83
|
+
* Session fact holding the epoch ms after which a TRANSIENT verdict for a
|
|
84
|
+
* command may be re-probed. Kept beside the boolean fact so both share the
|
|
85
|
+
* session's lifetime — no second global to reset (#1476).
|
|
86
|
+
*/
|
|
87
|
+
function transientRetryKey(command) {
|
|
88
|
+
return `${normalizeCacheKey(command)}.retryAt`;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Consecutive transient verdicts for a command, so the cooldown ESCALATES the
|
|
92
|
+
* way the policy documents (30 s, 60 s, 120 s … capped at 5 min) instead of
|
|
93
|
+
* sitting flat at 30 s.
|
|
94
|
+
*
|
|
95
|
+
* This is the highest-traffic availability consumer in the product. A flat
|
|
96
|
+
* cooldown here means a permanently sick host is re-probed every 30 s per
|
|
97
|
+
* command for the whole session — ten times the storm the policy claims to
|
|
98
|
+
* bound, and the one place the bound matters most. `createAvailabilityChecker`
|
|
99
|
+
* tracks the same counter; this keeps the two seams telling one story.
|
|
100
|
+
*/
|
|
101
|
+
function transientAttemptsKey(command) {
|
|
102
|
+
return `${normalizeCacheKey(command)}.transientAttempts`;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Is `command` usable right now? Cached per session.
|
|
106
|
+
*
|
|
107
|
+
* Latch policy (#1467/#1476): a `false` from a genuine absence is durable and
|
|
108
|
+
* is remembered for the session. A `false` from a TIMED-OUT probe is not — this
|
|
109
|
+
* is the highest-traffic availability consumer in the codebase, and caching a
|
|
110
|
+
* host stall here silently disabled a healthy tool for every later dispatch in
|
|
111
|
+
* the session. A transient verdict instead holds only for a bounded cooldown,
|
|
112
|
+
* which also stops a sick host from being re-probed on every dispatch.
|
|
113
|
+
*/
|
|
114
|
+
export async function checkToolAvailability(command, facts) {
|
|
78
115
|
const key = normalizeCacheKey(command);
|
|
79
116
|
const cached = facts.getSessionFact(key);
|
|
80
117
|
if (cached !== undefined) {
|
|
81
118
|
return cached;
|
|
82
119
|
}
|
|
120
|
+
const retryAt = facts.getSessionFact(transientRetryKey(command));
|
|
121
|
+
if (retryAt !== undefined && Date.now() < retryAt)
|
|
122
|
+
return false;
|
|
83
123
|
// A command that isn't even on disk can't pass a --version probe; the ~μs
|
|
84
124
|
// stat/PATH walk saves a guaranteed-to-fail spawn round-trip per cold tool.
|
|
85
125
|
if (!(await isSpawnableCommand(command))) {
|
|
@@ -87,12 +127,68 @@ async function checkToolAvailability(command, facts) {
|
|
|
87
127
|
return false;
|
|
88
128
|
}
|
|
89
129
|
try {
|
|
90
|
-
|
|
91
|
-
|
|
130
|
+
// The budget is enforced by a HOST-side timer, so measure the loop stall
|
|
131
|
+
// that overlapped the window and let the shared classifier read it.
|
|
132
|
+
const sampler = startHostStallSampler();
|
|
133
|
+
const startedAt = Date.now();
|
|
134
|
+
let result;
|
|
135
|
+
let hostStallMs;
|
|
136
|
+
try {
|
|
137
|
+
result = await safeSpawnAsync(command, ["--version"], {
|
|
138
|
+
timeout: TOOL_PROBE_TIMEOUT_MS,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
hostStallMs = sampler.stop();
|
|
143
|
+
}
|
|
144
|
+
const elapsedMs = Date.now() - startedAt;
|
|
145
|
+
if (result.status === 0) {
|
|
146
|
+
facts.setSessionFact(key, true);
|
|
147
|
+
// The tool answered: retire the cooldown facts rather than leaving a
|
|
148
|
+
// stale retry deadline behind a `true`.
|
|
149
|
+
facts.setSessionFact(transientRetryKey(command), 0);
|
|
150
|
+
facts.setSessionFact(transientAttemptsKey(command), 0);
|
|
151
|
+
logAvailabilityDecision({
|
|
152
|
+
tool: command,
|
|
153
|
+
verdict: "available",
|
|
154
|
+
outcome: "success",
|
|
155
|
+
cause: "ok",
|
|
156
|
+
elapsedMs,
|
|
157
|
+
latched: true,
|
|
158
|
+
hostStallMs,
|
|
159
|
+
budgetMs: TOOL_PROBE_TIMEOUT_MS,
|
|
160
|
+
});
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
// `missing` for anything unclassified preserves the pre-#1476 meaning of
|
|
164
|
+
// a non-zero exit: durable, cached for the session.
|
|
165
|
+
const { outcome, cause } = classifyProbeFailure(result, {
|
|
166
|
+
hostStallMs,
|
|
167
|
+
unclassifiedFailureOutcome: "missing",
|
|
168
|
+
});
|
|
169
|
+
let retryAfterMs;
|
|
170
|
+
if (outcome === "transient") {
|
|
171
|
+
const attempts = (facts.getSessionFact(transientAttemptsKey(command)) ?? 0) + 1;
|
|
172
|
+
facts.setSessionFact(transientAttemptsKey(command), attempts);
|
|
173
|
+
retryAfterMs = transientRetryDelayMs(attempts, cause);
|
|
174
|
+
facts.setSessionFact(transientRetryKey(command), Date.now() + retryAfterMs);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
facts.setSessionFact(key, false);
|
|
178
|
+
facts.setSessionFact(transientAttemptsKey(command), 0);
|
|
179
|
+
}
|
|
180
|
+
logAvailabilityDecision({
|
|
181
|
+
tool: command,
|
|
182
|
+
verdict: "unavailable",
|
|
183
|
+
outcome,
|
|
184
|
+
cause,
|
|
185
|
+
elapsedMs,
|
|
186
|
+
latched: outcome !== "transient",
|
|
187
|
+
hostStallMs,
|
|
188
|
+
...(retryAfterMs !== undefined && { retryAfterMs }),
|
|
189
|
+
budgetMs: TOOL_PROBE_TIMEOUT_MS,
|
|
92
190
|
});
|
|
93
|
-
|
|
94
|
-
facts.setSessionFact(key, available);
|
|
95
|
-
return available;
|
|
191
|
+
return false;
|
|
96
192
|
}
|
|
97
193
|
catch {
|
|
98
194
|
facts.setSessionFact(key, false);
|
|
@@ -122,9 +218,16 @@ function readFilePrefix(filePath, maxBytes = 4096) {
|
|
|
122
218
|
}
|
|
123
219
|
}
|
|
124
220
|
}
|
|
125
|
-
export function createDispatchContext(filePath, cwd, pi, facts, blockingOnly, modifiedRanges
|
|
221
|
+
export function createDispatchContext(filePath, cwd, pi, facts, blockingOnly, modifiedRanges,
|
|
222
|
+
/** Authoritative workspace root; `cwd` may be a nested language root. */
|
|
223
|
+
projectRoot,
|
|
224
|
+
/** Ordered per-file pipeline token, when this is a post-write dispatch. */
|
|
225
|
+
writeIndex,
|
|
226
|
+
/** Runtime telemetry identity, when known (#1448) — threaded to the
|
|
227
|
+
* worklog append; see DispatchContext.telemetryModel's doc. */
|
|
228
|
+
telemetryModel, telemetryProvider) {
|
|
126
229
|
const absoluteFilePath = resolveRunnerPath(cwd, filePath);
|
|
127
|
-
const normalizedProjectRoot = normalizeMapKey(path.resolve(cwd));
|
|
230
|
+
const normalizedProjectRoot = normalizeMapKey(path.resolve(projectRoot ?? cwd));
|
|
128
231
|
const normalizedCwd = normalizeMapKey(resolveLanguageRootForFile(absoluteFilePath, cwd));
|
|
129
232
|
const normalizedFilePath = normalizeMapKey(absoluteFilePath);
|
|
130
233
|
const kind = detectFileKind(normalizedFilePath);
|
|
@@ -143,11 +246,20 @@ export function createDispatchContext(filePath, cwd, pi, facts, blockingOnly, mo
|
|
|
143
246
|
projectConfig,
|
|
144
247
|
blockingOnly,
|
|
145
248
|
modifiedRanges,
|
|
249
|
+
writeIndex,
|
|
250
|
+
telemetryModel,
|
|
251
|
+
telemetryProvider,
|
|
146
252
|
async hasTool(command) {
|
|
147
253
|
return checkToolAvailability(command, facts);
|
|
148
254
|
},
|
|
149
255
|
log(message) {
|
|
150
|
-
|
|
256
|
+
// #1333: pi owns the terminal — a runner advisory must never be a raw
|
|
257
|
+
// write. Every DispatchContext.log line lands in extension.log instead.
|
|
258
|
+
logExtension({
|
|
259
|
+
subsystem: "dispatch",
|
|
260
|
+
message,
|
|
261
|
+
metadata: { filePath: normalizedFilePath, kind },
|
|
262
|
+
});
|
|
151
263
|
},
|
|
152
264
|
};
|
|
153
265
|
}
|
|
@@ -493,7 +605,7 @@ async function runGroup(ctx, group, registry, onRunnerResult) {
|
|
|
493
605
|
}
|
|
494
606
|
: undefined,
|
|
495
607
|
});
|
|
496
|
-
recordRunner(ctx.filePath, runnerId, result.status, result.diagnostics.length, duration);
|
|
608
|
+
recordRunner(ctx.filePath, runnerId, result.status, result.diagnostics.length, duration, ctx.writeIndex);
|
|
497
609
|
diagnostics.push(...result.diagnostics);
|
|
498
610
|
const resultSemantic = result.semantic ?? semantic;
|
|
499
611
|
if ((resultSemantic === "blocking" && result.diagnostics.length > 0) ||
|
|
@@ -563,26 +675,56 @@ export async function dispatchForFile(ctx, groups, registry, onRunnerResult) {
|
|
|
563
675
|
// Apply delta mode ONCE across the full diagnostic set.
|
|
564
676
|
// This avoids partial-baseline corruption when processing multiple groups.
|
|
565
677
|
const dedupedDiagnostics = dedupeOverlappingDiagnostics(allDiagnostics);
|
|
566
|
-
const dockerOverlapSuppressed = suppressTrivyConfigDockerOverlap(dedupedDiagnostics);
|
|
567
|
-
const overlapSuppressed = suppressLintOverlapsWithLsp(dockerOverlapSuppressed);
|
|
568
678
|
const fileContent = ctx.facts.getFileFact(ctx.filePath, "file.content") ?? "";
|
|
569
|
-
|
|
570
|
-
// #690: agent/user disposition layer — drop false-positive/suppress marks
|
|
571
|
-
// and anything deferred this session. flagged marks are left in place;
|
|
572
|
-
// lens_diagnostics tags them at render time via the same anchor.
|
|
679
|
+
// Project rule policy (`.pi-lens.json` `rules.<id>.disable`/`select`).
|
|
573
680
|
//
|
|
574
|
-
//
|
|
575
|
-
//
|
|
576
|
-
//
|
|
577
|
-
//
|
|
578
|
-
//
|
|
579
|
-
//
|
|
580
|
-
//
|
|
581
|
-
|
|
582
|
-
|
|
681
|
+
// Resolved from `ctx.projectRoot` (falling back to `ctx.cwd`), NOT
|
|
682
|
+
// `ctx.projectConfig` — `ctx.projectConfig` is loaded from the nested
|
|
683
|
+
// LANGUAGE root (`resolveLanguageRootForFile`), so in a monorepo where a
|
|
684
|
+
// package directory has its own `.pi-lens.json`, `discoverPiLensProjectConfig`'s
|
|
685
|
+
// upward walk stops there and never sees a repo-root policy.
|
|
686
|
+
// `lens_diagnostics` loads its policy map from `runtime.projectRoot`; using
|
|
687
|
+
// the same root here keeps the two surfaces in agreement. `ctx.projectConfig`
|
|
688
|
+
// itself is untouched — thresholds and mutation flags keep their existing
|
|
689
|
+
// language-root resolution.
|
|
690
|
+
const rulePolicy = rulePolicyMapFromConfig(loadPiLensProjectConfig(ctx.projectRoot ?? ctx.cwd).rules);
|
|
691
|
+
// The output-only filter pipeline: LSP/docker overlap suppression + inline
|
|
692
|
+
// `pi-lens-ignore` + agent/user dispositions + project rule policy. Applied
|
|
693
|
+
// AFTER dedupe so the pi renderer, widget, and delta all see one filtered
|
|
694
|
+
// set. #690: dispositions drop false-positive/suppress marks and anything
|
|
695
|
+
// deferred this session (flagged marks stay; lens_diagnostics tags them at
|
|
696
|
+
// render time). #1030: the disposition anchor + store MUST key off the
|
|
697
|
+
// PROJECT ROOT, not ctx.cwd — the mark tool writes dispositions under
|
|
698
|
+
// runtime.projectRoot, so reading from ctx.cwd (the nested language root in
|
|
699
|
+
// a monorepo) opened a different diagnostic-dispositions.json and silently
|
|
700
|
+
// no-op'd every mark under a nested marker.
|
|
701
|
+
//
|
|
702
|
+
// #1087: "silencing is not fixing" applies to the WHOLE class, not just the
|
|
703
|
+
// policy member. This single pipeline is applied identically to the live set
|
|
704
|
+
// AND (below) to the delta baseline, so a finding persistently dropped by
|
|
705
|
+
// ANY layer — overlap, inline suppression, disposition, or policy — is
|
|
706
|
+
// absent from both sides of the delta and never oscillates into `fixed`
|
|
707
|
+
// (which `trackAgentFixed` would otherwise inflate forever). The stored
|
|
708
|
+
// baseline remains the unfiltered `dedupedDiagnostics`, so editing a
|
|
709
|
+
// project's policy/suppressions never resets or corrupts the user-authored
|
|
710
|
+
// delta baseline — the filtering is re-derived on read for both sides.
|
|
711
|
+
const applyOutputFilters = (diags) => {
|
|
712
|
+
const dockerOverlap = suppressTrivyConfigDockerOverlap(diags);
|
|
713
|
+
const overlap = suppressLintOverlapsWithLsp(dockerOverlap);
|
|
714
|
+
const inline = applyInlineSuppressions(overlap, fileContent);
|
|
715
|
+
const disposition = applyDispositions(inline, ctx.projectRoot ?? ctx.cwd, ctx.filePath, fileContent);
|
|
716
|
+
return applyRulePolicy(disposition, rulePolicy);
|
|
717
|
+
};
|
|
718
|
+
let visibleDiagnostics = applyOutputFilters(dedupedDiagnostics);
|
|
583
719
|
let resolvedCount = 0;
|
|
584
720
|
if (ctx.deltaMode && previousBaseline) {
|
|
585
|
-
|
|
721
|
+
// Silencing a rule is not fixing it. The stored baseline is deliberately
|
|
722
|
+
// unfiltered (below), so compare against a fully-filtered view of it
|
|
723
|
+
// through the SAME pipeline — otherwise every persistently-suppressed
|
|
724
|
+
// finding sits in `fixed` on every dispatch and inflates the agent's
|
|
725
|
+
// resolved tally (trackAgentFixed) forever. Only `fixed` changes:
|
|
726
|
+
// filtered-out ids are absent from `after` either way.
|
|
727
|
+
const filtered = filterDelta(visibleDiagnostics, applyOutputFilters(previousBaseline), (d) => d.id);
|
|
586
728
|
visibleDiagnostics = promoteDeltaUnusedToBlockers(filtered.new);
|
|
587
729
|
resolvedCount = filtered.fixed.length;
|
|
588
730
|
}
|
|
@@ -595,11 +737,16 @@ export async function dispatchForFile(ctx, groups, registry, onRunnerResult) {
|
|
|
595
737
|
const blockers = visibleDiagnostics.filter((d) => d.semantic === "blocking");
|
|
596
738
|
const warnings = visibleDiagnostics.filter((d) => d.semantic === "warning" || d.semantic === "none");
|
|
597
739
|
const fixedItems = visibleDiagnostics.filter((d) => d.semantic === "fixed");
|
|
598
|
-
// Append fixed and fixable diagnostics to the persistent worklog
|
|
740
|
+
// Append fixed and fixable diagnostics to the persistent worklog, attributed
|
|
741
|
+
// to the runtime's active model/provider when known (#1448).
|
|
742
|
+
const worklogIdentity = {
|
|
743
|
+
model: ctx.telemetryModel,
|
|
744
|
+
provider: ctx.telemetryProvider,
|
|
745
|
+
};
|
|
599
746
|
if (fixedItems.length > 0) {
|
|
600
747
|
import("../fix-worklog.js")
|
|
601
748
|
.then(({ appendToWorklog }) => {
|
|
602
|
-
appendToWorklog(ctx.cwd, fixedItems, true);
|
|
749
|
+
appendToWorklog(ctx.cwd, fixedItems, true, worklogIdentity);
|
|
603
750
|
})
|
|
604
751
|
.catch(() => { });
|
|
605
752
|
}
|
|
@@ -607,7 +754,7 @@ export async function dispatchForFile(ctx, groups, registry, onRunnerResult) {
|
|
|
607
754
|
if (fixableWarnings.length > 0) {
|
|
608
755
|
import("../fix-worklog.js")
|
|
609
756
|
.then(({ appendToWorklog }) => {
|
|
610
|
-
appendToWorklog(ctx.cwd, fixableWarnings, false);
|
|
757
|
+
appendToWorklog(ctx.cwd, fixableWarnings, false, worklogIdentity);
|
|
611
758
|
})
|
|
612
759
|
.catch(() => { });
|
|
613
760
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isJstsFactFile } from "../../file-kinds.js";
|
|
1
2
|
import { findOwnerName } from "../../symbol-containment.js";
|
|
2
3
|
import { extractFactsFromTree, firstChildOfType, walk, } from "./tree-sitter-facts.js";
|
|
3
4
|
const BOUNDARY_PREFIXES = [
|
|
@@ -56,12 +57,26 @@ function getParameters(node) {
|
|
|
56
57
|
if (!fp)
|
|
57
58
|
return [];
|
|
58
59
|
return (fp.children ?? []).filter((c) => c &&
|
|
59
|
-
(c.type === "
|
|
60
|
+
(c.type === "identifier" ||
|
|
61
|
+
c.type === "required_parameter" ||
|
|
60
62
|
c.type === "optional_parameter" ||
|
|
61
|
-
c.type === "rest_pattern"
|
|
63
|
+
c.type === "rest_pattern" ||
|
|
64
|
+
c.type === "assignment_pattern" ||
|
|
65
|
+
// Plain JavaScript's grammar places a top-level destructured
|
|
66
|
+
// parameter directly as an object_pattern/array_pattern child
|
|
67
|
+
// of formal_parameters — no required_parameter wrapper (the TS
|
|
68
|
+
// grammar always wraps every parameter, destructured or not,
|
|
69
|
+
// which is why the wrapper types above already covered TS).
|
|
70
|
+
// Without this, `function f({a, b})` counted 0 params in JS
|
|
71
|
+
// while the TS-annotated equivalent counted correctly (#1089 P3-4).
|
|
72
|
+
c.type === "object_pattern" ||
|
|
73
|
+
c.type === "array_pattern"));
|
|
62
74
|
}
|
|
63
75
|
function parameterName(param) {
|
|
64
|
-
|
|
76
|
+
// JavaScript's grammar keeps a leaf parameter as the identifier itself;
|
|
77
|
+
// there is no named child to unwrap. TypeScript parameter wrapper nodes still
|
|
78
|
+
// use their first named child (type annotation/default/rest target).
|
|
79
|
+
return param.type === "identifier" ? param.text : firstNamedChild(param)?.text ?? "";
|
|
65
80
|
}
|
|
66
81
|
function getFunctionName(node) {
|
|
67
82
|
if (node.type === "function_declaration") {
|
|
@@ -254,10 +269,10 @@ function hasReturnAwaitCall(node) {
|
|
|
254
269
|
}
|
|
255
270
|
export const functionFactProvider = {
|
|
256
271
|
id: "fact.file.functions",
|
|
257
|
-
provides: ["file.functionSummaries"],
|
|
272
|
+
provides: ["file.functionSummaries", "file.functionFactsCoverage"],
|
|
258
273
|
requires: ["file.content"],
|
|
259
274
|
appliesTo(ctx) {
|
|
260
|
-
return
|
|
275
|
+
return isJstsFactFile(ctx.filePath);
|
|
261
276
|
},
|
|
262
277
|
async run(ctx, store) {
|
|
263
278
|
await extractFactsFromTree(ctx, store, { "file.functionSummaries": [] }, (root) => {
|
|
@@ -309,7 +324,8 @@ export const functionFactProvider = {
|
|
|
309
324
|
addSummary(node);
|
|
310
325
|
if (node.type === "class_declaration" ||
|
|
311
326
|
node.type === "interface_declaration") {
|
|
312
|
-
const nameNode = firstChildOfType(node, "type_identifier")
|
|
327
|
+
const nameNode = firstChildOfType(node, "type_identifier") ??
|
|
328
|
+
firstChildOfType(node, "identifier");
|
|
313
329
|
if (nameNode) {
|
|
314
330
|
containers.push({
|
|
315
331
|
name: nameNode.text,
|
|
@@ -325,6 +341,6 @@ export const functionFactProvider = {
|
|
|
325
341
|
summary.owner = owner;
|
|
326
342
|
}
|
|
327
343
|
return { "file.functionSummaries": summaries };
|
|
328
|
-
});
|
|
344
|
+
}, "file.functionFactsCoverage");
|
|
329
345
|
},
|
|
330
346
|
};
|
|
@@ -1,18 +1,6 @@
|
|
|
1
1
|
import { logLatency } from "../../latency-logger.js";
|
|
2
|
+
import { isJstsFactFile } from "../../file-kinds.js";
|
|
2
3
|
import { childrenOfType, firstChildOfType, withFactTree, walk, } from "./tree-sitter-facts.js";
|
|
3
|
-
// JS/TS extensions this provider handles (→ tree-sitter typescript/tsx/javascript
|
|
4
|
-
// grammars via resolveTreeSitterLanguage). Ported off the `typescript` compiler API
|
|
5
|
-
// onto tree-sitter (#402) — the parse is served from the shared, cached client.
|
|
6
|
-
const JSTS_EXTS = new Set([
|
|
7
|
-
".ts",
|
|
8
|
-
".tsx",
|
|
9
|
-
".mts",
|
|
10
|
-
".cts",
|
|
11
|
-
".js",
|
|
12
|
-
".jsx",
|
|
13
|
-
".mjs",
|
|
14
|
-
".cjs",
|
|
15
|
-
]);
|
|
16
4
|
function stripQuotes(raw) {
|
|
17
5
|
return raw.replace(/^["'`]+|["'`]+$/g, "");
|
|
18
6
|
}
|
|
@@ -78,19 +66,19 @@ function parseReExport(node) {
|
|
|
78
66
|
}
|
|
79
67
|
export const importFactProvider = {
|
|
80
68
|
id: "fact.file.imports",
|
|
81
|
-
provides: ["file.imports", "file.reexports"],
|
|
69
|
+
provides: ["file.imports", "file.reexports", "file.importFactsCoverage"],
|
|
82
70
|
requires: ["file.content"],
|
|
83
71
|
appliesTo(ctx) {
|
|
84
|
-
|
|
85
|
-
return JSTS_EXTS.has(ext);
|
|
72
|
+
return isJstsFactFile(ctx.filePath);
|
|
86
73
|
},
|
|
87
74
|
async run(ctx, store) {
|
|
88
75
|
const content = store.getFileFact(ctx.filePath, "file.content");
|
|
89
|
-
const setEmpty = () => {
|
|
76
|
+
const setEmpty = (complete = false) => {
|
|
90
77
|
store.setFileFact(ctx.filePath, "file.imports", []);
|
|
91
78
|
store.setFileFact(ctx.filePath, "file.reexports", []);
|
|
79
|
+
store.setFileFact(ctx.filePath, "file.importFactsCoverage", complete ? "complete" : "unavailable");
|
|
92
80
|
};
|
|
93
|
-
if (
|
|
81
|
+
if (content == null) {
|
|
94
82
|
setEmpty();
|
|
95
83
|
return;
|
|
96
84
|
}
|
|
@@ -205,5 +193,7 @@ export const importFactProvider = {
|
|
|
205
193
|
});
|
|
206
194
|
if (!parsed.parsed)
|
|
207
195
|
setEmpty();
|
|
196
|
+
else
|
|
197
|
+
store.setFileFact(ctx.filePath, "file.importFactsCoverage", "complete");
|
|
208
198
|
},
|
|
209
199
|
};
|