@herbertgao/pi-extensions 2026.8.3 → 2026.8.5
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 +45 -4
- package/examples/pi-footer.json +275 -0
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
- 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/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 +5 -8
- 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 +8 -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 +15 -2
- 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/schedule-menu.ts +9 -8
- package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -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 +8 -7
- package/node_modules/@narumitw/pi-btw/package.json +2 -2
- package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
- package/node_modules/pi-footer/CHANGELOG.md +145 -0
- package/node_modules/pi-footer/LICENSE +21 -0
- package/node_modules/pi-footer/README.md +354 -0
- package/node_modules/pi-footer/package.json +68 -0
- package/node_modules/pi-footer/src/cache.ts +106 -0
- package/node_modules/pi-footer/src/colors.ts +237 -0
- package/node_modules/pi-footer/src/config.ts +202 -0
- package/node_modules/pi-footer/src/event-widgets.ts +41 -0
- package/node_modules/pi-footer/src/extension-statuses.ts +102 -0
- package/node_modules/pi-footer/src/git.ts +135 -0
- package/node_modules/pi-footer/src/index.ts +268 -0
- package/node_modules/pi-footer/src/metrics.ts +141 -0
- package/node_modules/pi-footer/src/presets.ts +383 -0
- package/node_modules/pi-footer/src/render.ts +114 -0
- package/node_modules/pi-footer/src/separators.ts +52 -0
- package/node_modules/pi-footer/src/types.ts +122 -0
- package/node_modules/pi-footer/src/ui/color-level-confirm.ts +22 -0
- package/node_modules/pi-footer/src/ui/color-options.ts +195 -0
- package/node_modules/pi-footer/src/ui/config-lifecycle.ts +61 -0
- package/node_modules/pi-footer/src/ui/edit-colors.ts +13 -0
- package/node_modules/pi-footer/src/ui/events.ts +35 -0
- package/node_modules/pi-footer/src/ui/extension-status-picker.ts +60 -0
- package/node_modules/pi-footer/src/ui/extension-statuses.ts +73 -0
- package/node_modules/pi-footer/src/ui/fields.ts +252 -0
- package/node_modules/pi-footer/src/ui/global-menu.ts +126 -0
- package/node_modules/pi-footer/src/ui/helpers.ts +44 -0
- package/node_modules/pi-footer/src/ui/layout.ts +17 -0
- package/node_modules/pi-footer/src/ui/line-list.ts +19 -0
- package/node_modules/pi-footer/src/ui/model.ts +64 -0
- package/node_modules/pi-footer/src/ui/navigation.ts +29 -0
- package/node_modules/pi-footer/src/ui/option-edit.ts +93 -0
- package/node_modules/pi-footer/src/ui/overlay-render.ts +103 -0
- package/node_modules/pi-footer/src/ui/screen-context.ts +18 -0
- package/node_modules/pi-footer/src/ui/screen-controller.ts +27 -0
- package/node_modules/pi-footer/src/ui/screen-render.ts +32 -0
- package/node_modules/pi-footer/src/ui/screen-state.ts +20 -0
- package/node_modules/pi-footer/src/ui/screen.ts +243 -0
- package/node_modules/pi-footer/src/ui/screens/add-widget.ts +92 -0
- package/node_modules/pi-footer/src/ui/screens/confirm-exit.ts +52 -0
- package/node_modules/pi-footer/src/ui/screens/controller.ts +12 -0
- package/node_modules/pi-footer/src/ui/screens/edit-colors.ts +68 -0
- package/node_modules/pi-footer/src/ui/screens/edit-widget.ts +115 -0
- package/node_modules/pi-footer/src/ui/screens/extension-status-row.ts +61 -0
- package/node_modules/pi-footer/src/ui/screens/global.ts +75 -0
- package/node_modules/pi-footer/src/ui/screens/line-list.ts +108 -0
- package/node_modules/pi-footer/src/ui/screens/main.ts +99 -0
- package/node_modules/pi-footer/src/ui/screens/terminal.ts +121 -0
- package/node_modules/pi-footer/src/ui/screens/widget-list.ts +154 -0
- package/node_modules/pi-footer/src/ui/terminal-menu.ts +32 -0
- package/node_modules/pi-footer/src/ui/theme.ts +48 -0
- package/node_modules/pi-footer/src/ui/title-bar.ts +100 -0
- package/node_modules/pi-footer/src/ui/widget-actions.ts +76 -0
- package/node_modules/pi-footer/src/ui.ts +66 -0
- package/node_modules/pi-footer/src/widgets/context.ts +28 -0
- package/node_modules/pi-footer/src/widgets/core/active-tools.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/context-window.ts +24 -0
- package/node_modules/pi-footer/src/widgets/core/cwd-basename.ts +19 -0
- package/node_modules/pi-footer/src/widgets/core/cwd.ts +108 -0
- package/node_modules/pi-footer/src/widgets/core/event.ts +34 -0
- package/node_modules/pi-footer/src/widgets/core/external-status.ts +102 -0
- package/node_modules/pi-footer/src/widgets/core/model-provider.ts +20 -0
- package/node_modules/pi-footer/src/widgets/core/model.ts +35 -0
- package/node_modules/pi-footer/src/widgets/core/provider.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/session-name.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/text-verbosity.ts +17 -0
- package/node_modules/pi-footer/src/widgets/core/thinking-level.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/ahead-behind.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/branch.ts +81 -0
- package/node_modules/pi-footer/src/widgets/git/clean.ts +19 -0
- package/node_modules/pi-footer/src/widgets/git/deletions.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/diff.ts +38 -0
- package/node_modules/pi-footer/src/widgets/git/insertions.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/remote.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/root.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/sha.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/staged.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/status.ts +19 -0
- package/node_modules/pi-footer/src/widgets/git/unstaged.ts +17 -0
- package/node_modules/pi-footer/src/widgets/git/untracked.ts +17 -0
- package/node_modules/pi-footer/src/widgets/instance.ts +118 -0
- package/node_modules/pi-footer/src/widgets/layout/custom-text.ts +18 -0
- package/node_modules/pi-footer/src/widgets/layout/flex-separator.ts +32 -0
- package/node_modules/pi-footer/src/widgets/layout/separator.ts +57 -0
- package/node_modules/pi-footer/src/widgets/layout/spacer.ts +31 -0
- package/node_modules/pi-footer/src/widgets/options.ts +122 -0
- package/node_modules/pi-footer/src/widgets/project/runtime.ts +361 -0
- package/node_modules/pi-footer/src/widgets/registry.ts +223 -0
- package/node_modules/pi-footer/src/widgets/session/assistant-messages.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/compactions.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/elapsed.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/last-activity.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/messages.ts +19 -0
- package/node_modules/pi-footer/src/widgets/session/session-id.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/session-start.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/tool-results.ts +17 -0
- package/node_modules/pi-footer/src/widgets/session/total-messages.ts +19 -0
- package/node_modules/pi-footer/src/widgets/session/total-time.ts +18 -0
- package/node_modules/pi-footer/src/widgets/session/user-messages.ts +17 -0
- package/node_modules/pi-footer/src/widgets/store.ts +26 -0
- package/node_modules/pi-footer/src/widgets/tokens/cache-hit-rate.ts +55 -0
- package/node_modules/pi-footer/src/widgets/tokens/cache-read.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/cache-write.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/context-bar.ts +108 -0
- package/node_modules/pi-footer/src/widgets/tokens/context-length.ts +26 -0
- package/node_modules/pi-footer/src/widgets/tokens/context-remaining.ts +29 -0
- package/node_modules/pi-footer/src/widgets/tokens/context.ts +29 -0
- package/node_modules/pi-footer/src/widgets/tokens/cost.ts +51 -0
- package/node_modules/pi-footer/src/widgets/tokens/input-speed.ts +25 -0
- package/node_modules/pi-footer/src/widgets/tokens/input-tokens.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/output-speed.ts +25 -0
- package/node_modules/pi-footer/src/widgets/tokens/output-tokens.ts +18 -0
- package/node_modules/pi-footer/src/widgets/tokens/tokens.ts +20 -0
- package/node_modules/pi-footer/src/widgets/tokens/total-speed.ts +25 -0
- package/node_modules/pi-footer/src/widgets/tokens/total-tokens.ts +18 -0
- package/node_modules/pi-footer/src/widgets/types.ts +181 -0
- package/node_modules/pi-footer/src/widgets/utils/colors.ts +11 -0
- package/node_modules/pi-footer/src/widgets/utils/context.ts +112 -0
- package/node_modules/pi-footer/src/widgets/utils/session.ts +19 -0
- package/node_modules/pi-footer/src/widgets/utils/token-format.ts +78 -0
- package/node_modules/pi-lens/CHANGELOG.md +2440 -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/agent-behavior-client.js +21 -4
- 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 +29 -25
- 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-publish.js +10 -3
- 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/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 +14 -0
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
- 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 +347 -75
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
- 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 +1085 -681
- 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 +14 -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/lazy-installer.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -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 +10 -3
- package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
- package/node_modules/pi-lens/dist/clients/extension-log.js +139 -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/format-events-publish.js +16 -3
- 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 +681 -11
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
- package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
- 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 +390 -99
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
- package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
- 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 +23 -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 +27 -4
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
- package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
- package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
- 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 +196 -32
- 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 +123 -32
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
- package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
- 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/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 +47 -13
- 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/runner-adapters/call-graph-impact.js +8 -0
- 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/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/runtime-agent-end.js +107 -73
- package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
- package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -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 +218 -23
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
- package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
- package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
- package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
- package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -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 +1 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
- package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
- package/node_modules/pi-lens/dist/clients/tool-render.js +155 -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 +33 -13
- package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
- package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
- package/node_modules/pi-lens/dist/index.js +49361 -36888
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
- package/node_modules/pi-lens/dist/mcp/server.js +211 -44
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
- 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/docs/agent-guide.md +2 -2
- 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 +5 -2
- 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 +31 -2
- package/node_modules/pi-lens/docs/globalconfig.md +45 -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 +12 -1
- package/node_modules/pi-lens/docs/tools.md +4 -1
- package/node_modules/pi-lens/docs/usage.md +18 -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-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-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-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-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 +55 -2
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
- package/node_modules/pi-mcp-adapter/README.md +34 -3
- package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
- package/node_modules/pi-mcp-adapter/commands.ts +15 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
- 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/metadata-cache.ts +27 -4
- package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
- package/node_modules/pi-mcp-adapter/package.json +3 -3
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
- package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
- package/node_modules/pi-mcp-adapter/server-manager.ts +36 -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 +42 -4
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
- package/node_modules/pi-mcp-adapter/types.ts +93 -27
- package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
- package/package.json +17 -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. */
|
|
@@ -274,19 +325,17 @@ export function markDisposition(cwd, target, disposition, reason) {
|
|
|
274
325
|
// entry can already exist at the same weak anchor (a prior flagged/suppress
|
|
275
326
|
// mark) — the log should record what this mark shadowed either way.
|
|
276
327
|
const existing = readState(cwd).dispositions?.[anchor];
|
|
277
|
-
emitMarkTelemetry(cwd, target, disposition, anchor, reason, existing);
|
|
278
328
|
if (disposition === "defer") {
|
|
279
329
|
deferredThisSession.add(anchor);
|
|
330
|
+
emitMarkTelemetry(cwd, target, disposition, anchor, reason, existing);
|
|
280
331
|
return anchor;
|
|
281
332
|
}
|
|
282
|
-
const state = readState(cwd);
|
|
283
|
-
state.dispositions ??= {};
|
|
284
333
|
const now = new Date().toISOString();
|
|
285
334
|
const capturesFixContext = disposition === "flagged";
|
|
286
335
|
const lineText = capturesFixContext
|
|
287
336
|
? (target.content?.split(/\r?\n/)[target.line !== undefined ? target.line - 1 : -1] ?? existing?.lineText)?.trim()
|
|
288
337
|
: existing?.lineText;
|
|
289
|
-
|
|
338
|
+
const entry = {
|
|
290
339
|
disposition,
|
|
291
340
|
reason: reason ?? existing?.reason,
|
|
292
341
|
createdAt: existing?.createdAt ?? now,
|
|
@@ -294,7 +343,8 @@ export function markDisposition(cwd, target, disposition, reason) {
|
|
|
294
343
|
line: capturesFixContext ? (target.line ?? existing?.line) : existing?.line,
|
|
295
344
|
lineText,
|
|
296
345
|
};
|
|
297
|
-
|
|
346
|
+
commitDisposition(cwd, anchor, entry);
|
|
347
|
+
emitMarkTelemetry(cwd, target, disposition, anchor, reason, existing);
|
|
298
348
|
return anchor;
|
|
299
349
|
}
|
|
300
350
|
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, } 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,6 +149,7 @@ export function publishDiagnostics(args) {
|
|
|
145
149
|
}
|
|
146
150
|
return;
|
|
147
151
|
}
|
|
152
|
+
const busEmit = liveEmitter.get();
|
|
148
153
|
if (!busEmit) {
|
|
149
154
|
if (!hasLoggedUnwired) {
|
|
150
155
|
hasLoggedUnwired = true;
|
|
@@ -184,6 +189,7 @@ export function publishDiagnostics(args) {
|
|
|
184
189
|
files: fileEntries,
|
|
185
190
|
};
|
|
186
191
|
busEmit(BUS_DIAGNOSTICS_EVENT, payload);
|
|
192
|
+
hasLoggedFailure = false;
|
|
187
193
|
logBusEvent({
|
|
188
194
|
event: BUS_DIAGNOSTICS_EVENT,
|
|
189
195
|
outcome: "emitted",
|
|
@@ -201,6 +207,7 @@ export function publishDiagnostics(args) {
|
|
|
201
207
|
});
|
|
202
208
|
if (!hasLoggedFailure) {
|
|
203
209
|
hasLoggedFailure = true;
|
|
210
|
+
recordStaleBusFailure(BUS_DIAGNOSTICS_EVENT, err);
|
|
204
211
|
args.dbg?.(`diagnostics-publish: pilens:diagnostics emit failed (further failures suppressed): ${err}`);
|
|
205
212
|
}
|
|
206
213
|
}
|
|
@@ -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";
|
|
@@ -32,6 +33,7 @@ import { applyDispositions } from "../diagnostic-dispositions.js";
|
|
|
32
33
|
import { applyInlineSuppressions } from "./inline-suppressions.js";
|
|
33
34
|
import { getToolPlan } from "./plan.js";
|
|
34
35
|
import { resolveRunnerPath } from "./runner-context.js";
|
|
36
|
+
import { applyRulePolicy, rulePolicyMapFromConfig } from "./rule-policy.js";
|
|
35
37
|
import { getToolProfile } from "./tool-profile.js";
|
|
36
38
|
import { formatDiagnostics } from "./utils/format-utils.js";
|
|
37
39
|
// --- Runner Registry ---
|
|
@@ -122,9 +124,13 @@ function readFilePrefix(filePath, maxBytes = 4096) {
|
|
|
122
124
|
}
|
|
123
125
|
}
|
|
124
126
|
}
|
|
125
|
-
export function createDispatchContext(filePath, cwd, pi, facts, blockingOnly, modifiedRanges
|
|
127
|
+
export function createDispatchContext(filePath, cwd, pi, facts, blockingOnly, modifiedRanges,
|
|
128
|
+
/** Authoritative workspace root; `cwd` may be a nested language root. */
|
|
129
|
+
projectRoot,
|
|
130
|
+
/** Ordered per-file pipeline token, when this is a post-write dispatch. */
|
|
131
|
+
writeIndex) {
|
|
126
132
|
const absoluteFilePath = resolveRunnerPath(cwd, filePath);
|
|
127
|
-
const normalizedProjectRoot = normalizeMapKey(path.resolve(cwd));
|
|
133
|
+
const normalizedProjectRoot = normalizeMapKey(path.resolve(projectRoot ?? cwd));
|
|
128
134
|
const normalizedCwd = normalizeMapKey(resolveLanguageRootForFile(absoluteFilePath, cwd));
|
|
129
135
|
const normalizedFilePath = normalizeMapKey(absoluteFilePath);
|
|
130
136
|
const kind = detectFileKind(normalizedFilePath);
|
|
@@ -143,11 +149,18 @@ export function createDispatchContext(filePath, cwd, pi, facts, blockingOnly, mo
|
|
|
143
149
|
projectConfig,
|
|
144
150
|
blockingOnly,
|
|
145
151
|
modifiedRanges,
|
|
152
|
+
writeIndex,
|
|
146
153
|
async hasTool(command) {
|
|
147
154
|
return checkToolAvailability(command, facts);
|
|
148
155
|
},
|
|
149
156
|
log(message) {
|
|
150
|
-
|
|
157
|
+
// #1333: pi owns the terminal — a runner advisory must never be a raw
|
|
158
|
+
// write. Every DispatchContext.log line lands in extension.log instead.
|
|
159
|
+
logExtension({
|
|
160
|
+
subsystem: "dispatch",
|
|
161
|
+
message,
|
|
162
|
+
metadata: { filePath: normalizedFilePath, kind },
|
|
163
|
+
});
|
|
151
164
|
},
|
|
152
165
|
};
|
|
153
166
|
}
|
|
@@ -493,7 +506,7 @@ async function runGroup(ctx, group, registry, onRunnerResult) {
|
|
|
493
506
|
}
|
|
494
507
|
: undefined,
|
|
495
508
|
});
|
|
496
|
-
recordRunner(ctx.filePath, runnerId, result.status, result.diagnostics.length, duration);
|
|
509
|
+
recordRunner(ctx.filePath, runnerId, result.status, result.diagnostics.length, duration, ctx.writeIndex);
|
|
497
510
|
diagnostics.push(...result.diagnostics);
|
|
498
511
|
const resultSemantic = result.semantic ?? semantic;
|
|
499
512
|
if ((resultSemantic === "blocking" && result.diagnostics.length > 0) ||
|
|
@@ -563,26 +576,56 @@ export async function dispatchForFile(ctx, groups, registry, onRunnerResult) {
|
|
|
563
576
|
// Apply delta mode ONCE across the full diagnostic set.
|
|
564
577
|
// This avoids partial-baseline corruption when processing multiple groups.
|
|
565
578
|
const dedupedDiagnostics = dedupeOverlappingDiagnostics(allDiagnostics);
|
|
566
|
-
const dockerOverlapSuppressed = suppressTrivyConfigDockerOverlap(dedupedDiagnostics);
|
|
567
|
-
const overlapSuppressed = suppressLintOverlapsWithLsp(dockerOverlapSuppressed);
|
|
568
579
|
const fileContent = ctx.facts.getFileFact(ctx.filePath, "file.content") ?? "";
|
|
569
|
-
|
|
570
|
-
//
|
|
571
|
-
//
|
|
572
|
-
//
|
|
580
|
+
// Project rule policy (`.pi-lens.json` `rules.<id>.disable`/`select`).
|
|
581
|
+
//
|
|
582
|
+
// Resolved from `ctx.projectRoot` (falling back to `ctx.cwd`), NOT
|
|
583
|
+
// `ctx.projectConfig` — `ctx.projectConfig` is loaded from the nested
|
|
584
|
+
// LANGUAGE root (`resolveLanguageRootForFile`), so in a monorepo where a
|
|
585
|
+
// package directory has its own `.pi-lens.json`, `discoverPiLensProjectConfig`'s
|
|
586
|
+
// upward walk stops there and never sees a repo-root policy.
|
|
587
|
+
// `lens_diagnostics` loads its policy map from `runtime.projectRoot`; using
|
|
588
|
+
// the same root here keeps the two surfaces in agreement. `ctx.projectConfig`
|
|
589
|
+
// itself is untouched — thresholds and mutation flags keep their existing
|
|
590
|
+
// language-root resolution.
|
|
591
|
+
const rulePolicy = rulePolicyMapFromConfig(loadPiLensProjectConfig(ctx.projectRoot ?? ctx.cwd).rules);
|
|
592
|
+
// The output-only filter pipeline: LSP/docker overlap suppression + inline
|
|
593
|
+
// `pi-lens-ignore` + agent/user dispositions + project rule policy. Applied
|
|
594
|
+
// AFTER dedupe so the pi renderer, widget, and delta all see one filtered
|
|
595
|
+
// set. #690: dispositions drop false-positive/suppress marks and anything
|
|
596
|
+
// deferred this session (flagged marks stay; lens_diagnostics tags them at
|
|
597
|
+
// render time). #1030: the disposition anchor + store MUST key off the
|
|
598
|
+
// PROJECT ROOT, not ctx.cwd — the mark tool writes dispositions under
|
|
599
|
+
// runtime.projectRoot, so reading from ctx.cwd (the nested language root in
|
|
600
|
+
// a monorepo) opened a different diagnostic-dispositions.json and silently
|
|
601
|
+
// no-op'd every mark under a nested marker.
|
|
573
602
|
//
|
|
574
|
-
// #
|
|
575
|
-
//
|
|
576
|
-
//
|
|
577
|
-
//
|
|
578
|
-
//
|
|
579
|
-
//
|
|
580
|
-
//
|
|
581
|
-
|
|
582
|
-
|
|
603
|
+
// #1087: "silencing is not fixing" applies to the WHOLE class, not just the
|
|
604
|
+
// policy member. This single pipeline is applied identically to the live set
|
|
605
|
+
// AND (below) to the delta baseline, so a finding persistently dropped by
|
|
606
|
+
// ANY layer — overlap, inline suppression, disposition, or policy — is
|
|
607
|
+
// absent from both sides of the delta and never oscillates into `fixed`
|
|
608
|
+
// (which `trackAgentFixed` would otherwise inflate forever). The stored
|
|
609
|
+
// baseline remains the unfiltered `dedupedDiagnostics`, so editing a
|
|
610
|
+
// project's policy/suppressions never resets or corrupts the user-authored
|
|
611
|
+
// delta baseline — the filtering is re-derived on read for both sides.
|
|
612
|
+
const applyOutputFilters = (diags) => {
|
|
613
|
+
const dockerOverlap = suppressTrivyConfigDockerOverlap(diags);
|
|
614
|
+
const overlap = suppressLintOverlapsWithLsp(dockerOverlap);
|
|
615
|
+
const inline = applyInlineSuppressions(overlap, fileContent);
|
|
616
|
+
const disposition = applyDispositions(inline, ctx.projectRoot ?? ctx.cwd, ctx.filePath, fileContent);
|
|
617
|
+
return applyRulePolicy(disposition, rulePolicy);
|
|
618
|
+
};
|
|
619
|
+
let visibleDiagnostics = applyOutputFilters(dedupedDiagnostics);
|
|
583
620
|
let resolvedCount = 0;
|
|
584
621
|
if (ctx.deltaMode && previousBaseline) {
|
|
585
|
-
|
|
622
|
+
// Silencing a rule is not fixing it. The stored baseline is deliberately
|
|
623
|
+
// unfiltered (below), so compare against a fully-filtered view of it
|
|
624
|
+
// through the SAME pipeline — otherwise every persistently-suppressed
|
|
625
|
+
// finding sits in `fixed` on every dispatch and inflates the agent's
|
|
626
|
+
// resolved tally (trackAgentFixed) forever. Only `fixed` changes:
|
|
627
|
+
// filtered-out ids are absent from `after` either way.
|
|
628
|
+
const filtered = filterDelta(visibleDiagnostics, applyOutputFilters(previousBaseline), (d) => d.id);
|
|
586
629
|
visibleDiagnostics = promoteDeltaUnusedToBlockers(filtered.new);
|
|
587
630
|
resolvedCount = filtered.fixed.length;
|
|
588
631
|
}
|
|
@@ -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
|
};
|
|
@@ -17,15 +17,18 @@ export const withFactTree = withTreeSitterRoot;
|
|
|
17
17
|
* (there is no typescript-compiler fallback by design, #402). Centralising this
|
|
18
18
|
* keeps each provider to just its extraction logic (and de-duplicates the prologue).
|
|
19
19
|
*/
|
|
20
|
-
export async function extractFactsFromTree(ctx, store, defaults, extract) {
|
|
21
|
-
const writeAll = (facts) => {
|
|
20
|
+
export async function extractFactsFromTree(ctx, store, defaults, extract, coverageFact) {
|
|
21
|
+
const writeAll = (facts, complete) => {
|
|
22
22
|
for (const key of Object.keys(defaults)) {
|
|
23
23
|
store.setFileFact(ctx.filePath, key, facts[key] ?? defaults[key]);
|
|
24
24
|
}
|
|
25
|
+
if (coverageFact) {
|
|
26
|
+
store.setFileFact(ctx.filePath, coverageFact, complete ? "complete" : "unavailable");
|
|
27
|
+
}
|
|
25
28
|
};
|
|
26
29
|
const content = store.getFileFact(ctx.filePath, "file.content");
|
|
27
|
-
if (
|
|
28
|
-
return writeAll(defaults);
|
|
30
|
+
if (content == null)
|
|
31
|
+
return writeAll(defaults, false);
|
|
29
32
|
const parsed = await withFactTree(ctx.filePath, content, (root) => extract(root, content));
|
|
30
|
-
writeAll(parsed.parsed ? parsed.value : defaults);
|
|
33
|
+
writeAll(parsed.parsed ? parsed.value : defaults, parsed.parsed);
|
|
31
34
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const DEFAULT_INDENTATION = { style: "space", width: 2 };
|
|
2
|
+
/**
|
|
3
|
+
* Infer the prevailing indentation convention from lines that are indented.
|
|
4
|
+
* The detector deliberately has no language knowledge: formatter callers use
|
|
5
|
+
* it only as a conservative fallback when the repository has no config.
|
|
6
|
+
*/
|
|
7
|
+
export function detectIndentation(content) {
|
|
8
|
+
const lines = content.split(/\r?\n/);
|
|
9
|
+
const tabs = lines.filter((line) => /^\t+\S/.test(line)).length;
|
|
10
|
+
const spaceCounts = lines
|
|
11
|
+
.map((line) => line.match(/^ +(?=\S)/)?.[0].length ?? 0)
|
|
12
|
+
.filter((count) => count > 0);
|
|
13
|
+
if (tabs === 0 && spaceCounts.length === 0)
|
|
14
|
+
return DEFAULT_INDENTATION;
|
|
15
|
+
if (tabs > spaceCounts.length)
|
|
16
|
+
return { style: "tab", width: 1 };
|
|
17
|
+
if (spaceCounts.length > tabs) {
|
|
18
|
+
const counts = new Map();
|
|
19
|
+
for (const count of spaceCounts) {
|
|
20
|
+
for (const other of spaceCounts) {
|
|
21
|
+
if (other > count) {
|
|
22
|
+
const delta = other - count;
|
|
23
|
+
counts.set(delta, (counts.get(delta) ?? 0) + 1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const inferredWidth = [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0] - b[0])[0]?.[0] ?? Math.min(...spaceCounts);
|
|
28
|
+
return { style: "space", width: inferredWidth <= 8 ? inferredWidth : 2 };
|
|
29
|
+
}
|
|
30
|
+
return DEFAULT_INDENTATION;
|
|
31
|
+
}
|
|
32
|
+
/** Whether the content supplied evidence from which a style can be inferred. */
|
|
33
|
+
export function hasDetectableIndentation(content) {
|
|
34
|
+
return /^(?:\t+| {1,})\S/m.test(content);
|
|
35
|
+
}
|
|
@@ -9,17 +9,17 @@
|
|
|
9
9
|
* (Python/Ruby/…), comma-separated for multiple rules, on the same line as the
|
|
10
10
|
* diagnostic or the line immediately above it.
|
|
11
11
|
*/
|
|
12
|
+
import { normalizeRuleId } from "./rule-id-normalize.js";
|
|
12
13
|
const SUPPRESS_RE = /(?:\/\/|#)\s*pi-lens-ignore:\s*(.+)/;
|
|
13
14
|
/**
|
|
14
15
|
* Normalize a rule id to the form a user writes in a `pi-lens-ignore` comment.
|
|
15
16
|
* The napi scan and the ast-grep LSP tag the same rule as `ast-grep:<id>` /
|
|
16
|
-
* `<id>-js` in some surfaces (see
|
|
17
|
+
* `<id>-js` in some surfaces (see the dedup key in lens-diagnostics);
|
|
17
18
|
* a user's bare `<id>` must still suppress those, so we match the normalized form
|
|
18
|
-
* as well as the raw one.
|
|
19
|
+
* as well as the raw one. Shared via `rule-id-normalize.ts` so the inline
|
|
20
|
+
* suppression parser and the project rule policy matcher apply the same
|
|
21
|
+
* normalization.
|
|
19
22
|
*/
|
|
20
|
-
function normalizeSuppressRule(ruleId) {
|
|
21
|
-
return ruleId.replace(/^ast-grep:/, "").replace(/-js$/, "");
|
|
22
|
-
}
|
|
23
23
|
/**
|
|
24
24
|
* Drop diagnostics suppressed by an inline `pi-lens-ignore: <rule[,rule2]>`
|
|
25
25
|
* comment in `content` (the file the diagnostics belong to). A diagnostic is
|
|
@@ -44,8 +44,17 @@ export function applyInlineSuppressions(diagnostics, content) {
|
|
|
44
44
|
const suppressedLine = i + 1; // same line (1-based)
|
|
45
45
|
const nextLine = i + 2; // next line (1-based)
|
|
46
46
|
for (const ruleId of rules) {
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
// #1087: normalize the COMMENT token too, not just the diagnostic id.
|
|
48
|
+
// The diagnostic side below matches raw OR normalized, so storing only
|
|
49
|
+
// the raw comment token made `// pi-lens-ignore: no-eval-js` fail to
|
|
50
|
+
// suppress a finding surfaced under the normalized `no-eval`, while the
|
|
51
|
+
// identical `disable: ["no-eval-js"]` config key worked (rule-policy
|
|
52
|
+
// normalizes both sides). Add the normalized form so the two suppression
|
|
53
|
+
// surfaces stay symmetric.
|
|
54
|
+
for (const key of new Set([ruleId, normalizeRuleId(ruleId)])) {
|
|
55
|
+
suppressed.add(`${suppressedLine}:${key}`);
|
|
56
|
+
suppressed.add(`${nextLine}:${key}`);
|
|
57
|
+
}
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
60
|
if (suppressed.size === 0)
|
|
@@ -55,7 +64,7 @@ export function applyInlineSuppressions(diagnostics, content) {
|
|
|
55
64
|
const line = d.line ?? 1;
|
|
56
65
|
if (suppressed.has(`${line}:${rawId}`))
|
|
57
66
|
return false;
|
|
58
|
-
const normId =
|
|
67
|
+
const normId = normalizeRuleId(rawId);
|
|
59
68
|
return normId === rawId || !suppressed.has(`${line}:${normId}`);
|
|
60
69
|
});
|
|
61
70
|
}
|