@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
|
@@ -18,17 +18,34 @@ pi-lens hooks into the pi agent lifecycle:
|
|
|
18
18
|
|
|
19
19
|
## On-write pipeline
|
|
20
20
|
|
|
21
|
-
For each write/edit, pi-lens runs a language-aware pipeline
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
For each write/edit, pi-lens runs a language-aware pipeline. Format and safe
|
|
22
|
+
autofix (steps 1–2) run on different schedules depending on the tool:
|
|
23
|
+
|
|
24
|
+
- **`write`** (new file, full overwrite, bash-authored write): autofix runs
|
|
25
|
+
immediately, in the same tool result, carrying the fixed file's full content
|
|
26
|
+
back to the agent when it fits under the per-file cap.
|
|
27
|
+
- **`edit`**: autofix defers to `agent_end`, joining the same per-file queue as
|
|
28
|
+
deferred formatting; autofix drains before format so the final state is
|
|
29
|
+
formatter-stable. A `write` followed by an `edit` on the same file in the
|
|
30
|
+
same turn demotes the write's autofix to deferred too.
|
|
31
|
+
|
|
32
|
+
1. Format queue / immediate formatting when configured (deferred to
|
|
33
|
+
`agent_end` for an `edit` even under `--immediate-format`, so it lands
|
|
34
|
+
after autofix reformats the file).
|
|
35
|
+
2. Safe autofix from tools with deterministic fix support — immediate for
|
|
36
|
+
`write`, deferred to `agent_end` for `edit` (see above).
|
|
25
37
|
3. LSP file sync and diagnostic wait.
|
|
26
38
|
4. Parallel dispatch runners: LSP, ast-grep, tree-sitter, fact rules, and
|
|
27
|
-
language-specific linters/security scanners.
|
|
39
|
+
language-specific linters/security scanners. For a deferred `edit`, these
|
|
40
|
+
run against the not-yet-autofixed disk state, so a lint finding autofix
|
|
41
|
+
would have cleared may appear here and resolve itself at `agent_end`.
|
|
28
42
|
5. Cascade diagnostics for likely affected neighbors.
|
|
29
43
|
6. Deduplication and routing to blockers, actionable warnings, or code-quality
|
|
30
44
|
history.
|
|
31
45
|
|
|
46
|
+
See [`docs/agent-guide.md`](agent-guide.md#6-auto-format--auto-fix-timing--dont-be-surprised)
|
|
47
|
+
for the consumer-facing version of this routing.
|
|
48
|
+
|
|
32
49
|
## Agent tools
|
|
33
50
|
|
|
34
51
|
pi-lens exposes these high-value tools to agents:
|
|
@@ -91,6 +108,8 @@ pi --lens-guard # Block git commit/push when unresolved blockers exist
|
|
|
91
108
|
pi --no-opengrep # Disable the Opengrep security scanner (default-on auxiliary LSP)
|
|
92
109
|
pi --no-read-guard # Disable the read-before-edit behavior monitor
|
|
93
110
|
pi --lens-turn-summary # Persist a per-turn summary of diagnostics, autofixes, and autoformats
|
|
111
|
+
pi --lens-compact-tool-line # Render tool results as one compact, theme-aware line (closes #1327)
|
|
112
|
+
pi --no-lazy-tools # Keep every pi-lens tool active instead of activating the situational ones on demand
|
|
94
113
|
|
|
95
114
|
# Actionable warnings (all default off)
|
|
96
115
|
pi --lens-actionable-warnings # Report fixable warnings at turn end
|
|
@@ -141,6 +160,23 @@ second host adapter that calls the same `clients/lens-engine.ts` seam as the pi
|
|
|
141
160
|
extension. Use `npm run build:dist` after MCP/engine changes so the user-scoped
|
|
142
161
|
server loads fresh compiled code.
|
|
143
162
|
|
|
163
|
+
Two Claude Code hooks give the MCP mirror the same automatic cadence the pi
|
|
164
|
+
extension has. PostToolUse runs the per-edit pass, `Stop` runs the per-turn one:
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{ "hooks": {
|
|
168
|
+
"PostToolUse": [
|
|
169
|
+
{ "matcher": "Edit|Write",
|
|
170
|
+
"hooks": [ { "type": "command", "command": "pi-lens-analyze --hook" } ] } ],
|
|
171
|
+
"Stop": [
|
|
172
|
+
{ "hooks": [ { "type": "command", "command": "pi-lens-analyze --turn-end", "timeout": 60 } ] } ]
|
|
173
|
+
} }
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The `Stop` hook only works against a running MCP server because only that
|
|
177
|
+
process owns the session state and pending turn work. With no warm server the
|
|
178
|
+
turn-end is skipped, not faked: one line on stderr and nothing on stdout.
|
|
179
|
+
|
|
144
180
|
## Troubleshooting
|
|
145
181
|
|
|
146
182
|
- Run `npm run build` before tests after editing TypeScript; tests import
|
|
@@ -42,6 +42,41 @@ HTTPServer → httpserver, http, server
|
|
|
42
42
|
each through `splitIdentifier`; queries are tokenized the same way so
|
|
43
43
|
`"authenticate user"` matches `authenticateUser`, `auth_user`, etc.
|
|
44
44
|
|
|
45
|
+
## Query prefix filters (#1450)
|
|
46
|
+
|
|
47
|
+
The query string can mix plain terms with composable `key:value` filters,
|
|
48
|
+
parsed by `parseWordIndexQuery` (`clients/word-index.ts`) before tokenization:
|
|
49
|
+
|
|
50
|
+
- `lang:<kind>` — restrict to a file kind's extensions, drawn from
|
|
51
|
+
`KIND_EXTENSIONS` (`clients/file-kinds.ts`) — the single source of truth
|
|
52
|
+
(#894 invariant), so there is no second, hand-maintained language list here.
|
|
53
|
+
- `file:<substr>` — path substring match against the index's own stored path,
|
|
54
|
+
normalized through `wordIndexKey` (case-folded on win32 only, matching how
|
|
55
|
+
the index's own path-keyed maps already fold win32 paths, #1025).
|
|
56
|
+
- `ext:<ext>` — literal extension match (`ext:ts` and `ext:.ts` are
|
|
57
|
+
equivalent).
|
|
58
|
+
- Any filter may be negated with a leading `-` (`-file:test`).
|
|
59
|
+
|
|
60
|
+
Example: `lang:jsts file:clients/ -file:test rank`. Multiple positive filters
|
|
61
|
+
of the SAME key OR together; different keys AND; negations always subtract.
|
|
62
|
+
Filters are applied as a `fileFilter` predicate BEFORE BM25/priors/centrality
|
|
63
|
+
scoring (same seam as the pre-existing `paths`/`lang` structured options,
|
|
64
|
+
#771), so a surviving file's score is unaffected by filtering. An unrecognized
|
|
65
|
+
`key:` token passes through as an ordinary search term (colon-bearing terms
|
|
66
|
+
like `std::vector`, URLs, and Windows paths search normally). Only a
|
|
67
|
+
recognized key with a bad value — an unrecognized `lang:` kind — throws
|
|
68
|
+
`WordIndexQueryError`
|
|
69
|
+
naming the supported list — never silently falls through as a literal search
|
|
70
|
+
term. Both the pi `symbol_search` tool and the MCP `pilens_symbol_search`
|
|
71
|
+
mirror inherit the syntax for free since both pass their `query` argument
|
|
72
|
+
straight through to `searchWordIndex` (the entry point where parsing happens).
|
|
73
|
+
|
|
74
|
+
DF-normalization: BM25's per-token `idf` is computed from the FULL,
|
|
75
|
+
unfiltered posting for that token before `fileFilter` is applied per
|
|
76
|
+
candidate file — a filtered query reuses the global, corpus-wide document
|
|
77
|
+
frequency rather than recomputing it over the filtered subset. Documented as
|
|
78
|
+
an acceptable approximation (see the doc comment on `searchWordIndex`).
|
|
79
|
+
|
|
45
80
|
## Lifecycle
|
|
46
81
|
|
|
47
82
|
The index is built/refreshed in **every** startup mode: load the persisted
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lens",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo",
|
|
6
6
|
"repository": {
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"prepare": "npm run build:dist && node scripts/download-grammars.js --core --dest grammars",
|
|
21
21
|
"lint": "tsc --project tsconfig.json",
|
|
22
22
|
"watch": "tsc --watch",
|
|
23
|
-
"test": "vitest run",
|
|
24
|
-
"test:unit": "
|
|
25
|
-
"test:integration": "vitest run tests/index-integration.test.ts tests/clients/lsp/integration.test.ts",
|
|
23
|
+
"test": "node scripts/with-test-lock.mjs -- vitest run",
|
|
24
|
+
"test:unit": "node scripts/with-test-lock.mjs -- vitest run",
|
|
25
|
+
"test:integration": "node scripts/with-test-lock.mjs -- vitest run tests/index-integration.test.ts tests/clients/lsp/integration.test.ts",
|
|
26
26
|
"test:watch": "vitest",
|
|
27
27
|
"check": "node scripts/check-extensions.mjs",
|
|
28
28
|
"selftest:install": "node scripts/install-selftest.mjs",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"audit:astgrep-rule-pairs": "node scripts/audit-astgrep-rule-pairs.mjs",
|
|
35
35
|
"audit:playground": "node scripts/playground-verify-rule.mjs",
|
|
36
36
|
"logs:smells": "node scripts/analyze-pi-lens-logs.mjs",
|
|
37
|
-
"changelog:check": "node scripts/changelog
|
|
37
|
+
"changelog:check": "node scripts/rollup-changelog.mjs --check",
|
|
38
38
|
"changelog:release": "node scripts/changelog-release.mjs",
|
|
39
39
|
"changelog:extract": "node scripts/changelog-extract.mjs",
|
|
40
40
|
"release:backfill-notes": "node scripts/backfill-github-releases.mjs",
|
|
@@ -85,9 +85,9 @@
|
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"@ast-grep/cli": "^0.45.0",
|
|
87
87
|
"@ast-grep/napi": "^0.45.0",
|
|
88
|
-
"@earendil-works/pi-tui": "^0.
|
|
88
|
+
"@earendil-works/pi-tui": "^0.84.1",
|
|
89
89
|
"js-yaml": "^5.2.2",
|
|
90
|
-
"minimatch": "^10.2.
|
|
90
|
+
"minimatch": "^10.2.6",
|
|
91
91
|
"pidusage": "^4.0.1",
|
|
92
92
|
"typebox": "^1.0.0",
|
|
93
93
|
"vscode-jsonrpc": "^9.0.0"
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
},
|
|
106
106
|
"devDependencies": {
|
|
107
107
|
"@biomejs/biome": "^2.4.10",
|
|
108
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
108
|
+
"@earendil-works/pi-coding-agent": "^0.84.1",
|
|
109
109
|
"@types/node": "^26.0.0",
|
|
110
110
|
"@types/pidusage": "^2.0.5",
|
|
111
111
|
"@vitest/coverage-v8": "^4.1.5",
|
|
@@ -134,8 +134,8 @@
|
|
|
134
134
|
]
|
|
135
135
|
},
|
|
136
136
|
"allowScripts": {
|
|
137
|
-
"@ast-grep/cli@0.
|
|
137
|
+
"@ast-grep/cli@0.45.1": true,
|
|
138
138
|
"@google/genai@1.52.0": true,
|
|
139
|
-
"protobufjs@7.6.
|
|
139
|
+
"protobufjs@7.6.5": true
|
|
140
140
|
}
|
|
141
141
|
}
|
|
@@ -15,6 +15,55 @@ valid:
|
|
|
15
15
|
doThing()
|
|
16
16
|
except Exception as e:
|
|
17
17
|
handle(e)
|
|
18
|
+
- |
|
|
19
|
+
# dotted/qualified name (#1031)
|
|
20
|
+
try:
|
|
21
|
+
doThing()
|
|
22
|
+
except asyncio.TimeoutError:
|
|
23
|
+
handle()
|
|
24
|
+
- |
|
|
25
|
+
# parenthesized single name (mirrors #1026's tree-sitter spec set)
|
|
26
|
+
try:
|
|
27
|
+
doThing()
|
|
28
|
+
except (ValueError):
|
|
29
|
+
handle()
|
|
30
|
+
- |
|
|
31
|
+
# subscripted generic (#1244)
|
|
32
|
+
try:
|
|
33
|
+
doThing()
|
|
34
|
+
except dict[str, int]:
|
|
35
|
+
handle()
|
|
36
|
+
- |
|
|
37
|
+
# subscripted PEP 654 exception group (#1244)
|
|
38
|
+
try:
|
|
39
|
+
doThing()
|
|
40
|
+
except BaseExceptionGroup[TypeError, ValueError]:
|
|
41
|
+
handle()
|
|
42
|
+
- |
|
|
43
|
+
try:
|
|
44
|
+
doThing()
|
|
45
|
+
except ValueError | TypeError:
|
|
46
|
+
handle()
|
|
47
|
+
- |
|
|
48
|
+
try:
|
|
49
|
+
doThing()
|
|
50
|
+
except cache[key]:
|
|
51
|
+
handle()
|
|
52
|
+
- |
|
|
53
|
+
try:
|
|
54
|
+
doThing()
|
|
55
|
+
except (ValueError,):
|
|
56
|
+
handle()
|
|
57
|
+
- |
|
|
58
|
+
try:
|
|
59
|
+
doThing()
|
|
60
|
+
except (mod.E1, E2) as error:
|
|
61
|
+
handle(error)
|
|
62
|
+
- |
|
|
63
|
+
try:
|
|
64
|
+
doThing()
|
|
65
|
+
except* ValueError:
|
|
66
|
+
handle()
|
|
18
67
|
invalid:
|
|
19
68
|
- |
|
|
20
69
|
try:
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
id: no-bare-host-path-in-win32-branch
|
|
2
|
+
valid:
|
|
3
|
+
# DOCUMENTED LIMITATION (#1339 review): the exact pre-fix #1150 shape --
|
|
4
|
+
# bare dirname in an unguarded helper CALLED FROM the guarded branch.
|
|
5
|
+
# ast-grep has no cross-function reach, so this is deliberately a
|
|
6
|
+
# negative fixture; it exists so a future strengthening flips it to a
|
|
7
|
+
# positive consciously, not accidentally. Review-enforced meanwhile
|
|
8
|
+
# (AGENTS.md defect-shape 2).
|
|
9
|
+
- |
|
|
10
|
+
import * as path from "node:path";
|
|
11
|
+
import { isWindowsPath } from "./path-utils.js";
|
|
12
|
+
function resolveNonExisting(filePath: string) {
|
|
13
|
+
return path.dirname(filePath);
|
|
14
|
+
}
|
|
15
|
+
function normalize(filePath: string) {
|
|
16
|
+
if (isWindowsPath(filePath)) {
|
|
17
|
+
return resolveNonExisting(filePath);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
- |
|
|
21
|
+
import * as path from "node:path";
|
|
22
|
+
import { isWindowsPath } from "./path-utils.js";
|
|
23
|
+
function f(filePath: string) {
|
|
24
|
+
if (isWindowsPath(filePath)) {
|
|
25
|
+
return path.win32.dirname(filePath);
|
|
26
|
+
}
|
|
27
|
+
return path.dirname(filePath);
|
|
28
|
+
}
|
|
29
|
+
- |
|
|
30
|
+
import * as path from "node:path";
|
|
31
|
+
import { isWindowsPath } from "./path-utils.js";
|
|
32
|
+
function f(filePath: string) {
|
|
33
|
+
return isWindowsPath(filePath)
|
|
34
|
+
? path.win32.basename(filePath)
|
|
35
|
+
: path.basename(filePath);
|
|
36
|
+
}
|
|
37
|
+
- |
|
|
38
|
+
import { dirname } from "node:path";
|
|
39
|
+
function f(filePath: string) {
|
|
40
|
+
if (someOtherPredicate(filePath)) {
|
|
41
|
+
return dirname(filePath);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
invalid:
|
|
45
|
+
# Fresh probes from the #1339 review, encoded so they stay covered.
|
|
46
|
+
- |
|
|
47
|
+
import * as path from "node:path";
|
|
48
|
+
import { isWindowsPath } from "./path-utils.js";
|
|
49
|
+
function f(filePath: string) {
|
|
50
|
+
if (isWindowsPath(filePath)) {
|
|
51
|
+
for (const part of parts) {
|
|
52
|
+
const nested = path.join(filePath, part);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
- |
|
|
57
|
+
import * as path from "node:path";
|
|
58
|
+
import { isWindowsPath } from "./path-utils.js";
|
|
59
|
+
function f(filePath: string) {
|
|
60
|
+
if (isWindowsPath(filePath)) {
|
|
61
|
+
return filePath.split(path.sep);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
- |
|
|
65
|
+
import * as path from "node:path";
|
|
66
|
+
import { isFullyQualifiedWin32 } from "./path-utils.js";
|
|
67
|
+
function f(filePath: string, other: boolean) {
|
|
68
|
+
if (isFullyQualifiedWin32(filePath) && other) {
|
|
69
|
+
return path.basename(filePath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
- |
|
|
73
|
+
import * as path from "node:path";
|
|
74
|
+
import { isWindowsPath } from "./path-utils.js";
|
|
75
|
+
function f(filePath: string) {
|
|
76
|
+
if (isWindowsPath(filePath)) {
|
|
77
|
+
return path.dirname(filePath);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
- |
|
|
81
|
+
import { join, sep } from "node:path";
|
|
82
|
+
import { isFullyQualifiedWin32 } from "./path-utils.js";
|
|
83
|
+
function f(filePath: string) {
|
|
84
|
+
if (isFullyQualifiedWin32(filePath)) {
|
|
85
|
+
return join(filePath, sep);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
id: no-conditional-empty-object-spread-js
|
|
2
|
+
valid:
|
|
3
|
+
- 'const o = {...(cond ? {a: 1} : {b: 2})}'
|
|
4
|
+
- 'const o = {...base}'
|
|
5
|
+
- 'const o = {...(cond ? extra : other)}'
|
|
6
|
+
invalid:
|
|
7
|
+
- 'const o = {...(cond ? {} : {x})}'
|
|
8
|
+
- 'const o = {...(cond ? {y} : {})}'
|
|
9
|
+
- 'const o = {...cond ? {} : {x}}'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
id: no-conditional-empty-object-spread
|
|
2
|
+
valid:
|
|
3
|
+
- 'const o = {...(cond ? {a: 1} : {b: 2})}'
|
|
4
|
+
- 'const o = {...base}'
|
|
5
|
+
- 'const o = {...(cond ? extra : other)}'
|
|
6
|
+
invalid:
|
|
7
|
+
- 'const o = {...(cond ? {} : {x})}'
|
|
8
|
+
- 'const o = {...(cond ? {y} : {})}'
|
|
9
|
+
- 'const o = {...cond ? {} : {x}}'
|
|
@@ -2,7 +2,17 @@ id: no-nested-links
|
|
|
2
2
|
valid:
|
|
3
3
|
- '<a href="/x">link</a>'
|
|
4
4
|
- '<a href="/x"><span>nested</span></a>'
|
|
5
|
+
- '<div><a href="/x">link</a></div>'
|
|
6
|
+
- '<div><a href="/x">first</a><a href="/y">second</a></div>'
|
|
5
7
|
invalid:
|
|
6
8
|
- '<a href="/x">outer <a href="/y">inner</a></a>'
|
|
7
9
|
- '<a><a>double</a></a>'
|
|
8
|
-
- '<
|
|
10
|
+
- '<a href="/x"><span><a href="/y">inner</a></span></a>'
|
|
11
|
+
- |
|
|
12
|
+
<a href="/outer">
|
|
13
|
+
<span>
|
|
14
|
+
<a href="/middle">
|
|
15
|
+
<em><a href="/inner">deep</a></em>
|
|
16
|
+
</a>
|
|
17
|
+
</span>
|
|
18
|
+
</a>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
id: no-raw-json-store-write
|
|
2
|
+
valid:
|
|
3
|
+
- "writeFileAtomic(file, JSON.stringify(data))"
|
|
4
|
+
- "writeFileSync(file, text)"
|
|
5
|
+
invalid:
|
|
6
|
+
# #1349 review: encoding/replacer/indent variants are the same raw write.
|
|
7
|
+
- "writeFileSync(file, JSON.stringify(data), 'utf8')"
|
|
8
|
+
- "writeFileSync(file, JSON.stringify(data, null, 2))"
|
|
9
|
+
- "fs.writeFileSync(file, JSON.stringify(data, replacer), { encoding: 'utf8' })"
|
|
10
|
+
- "writeFileSync(file, JSON.stringify(data))"
|
|
11
|
+
- "fs.writeFileSync(file, JSON.stringify(data))"
|
|
12
|
+
- |
|
|
13
|
+
const payload = JSON.stringify(data)
|
|
14
|
+
writeFileSync(file, payload)
|
|
15
|
+
- |
|
|
16
|
+
const payload = JSON.stringify(data)
|
|
17
|
+
fs.writeFileSync(file, payload)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
id: no-unknown-laundering
|
|
2
|
+
valid:
|
|
3
|
+
- 'const x: unknown = foo()'
|
|
4
|
+
- 'function f(x: unknown) {}'
|
|
5
|
+
- 'function isValidPayload(data: unknown): data is Foo { return true; }'
|
|
6
|
+
- 'function f(cause: unknown) {}'
|
|
7
|
+
- 'type X = { a: unknown }'
|
|
8
|
+
- 'type Y = Record<string, unknown>'
|
|
9
|
+
invalid:
|
|
10
|
+
- 'type X = unknown'
|
|
11
|
+
- 'type LooseHandler = unknown'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
id: no-win32-isabsolute-for-qualification
|
|
2
|
+
valid:
|
|
3
|
+
# DOCUMENTED LIMITATION (#1349 review): the aliased parser -- the shape
|
|
4
|
+
# the actual pre-#1330 defect used -- is beyond ast-grep's reach and is
|
|
5
|
+
# deliberately a negative; flipping it to invalid requires an engine
|
|
6
|
+
# capability decision. Review-enforced meanwhile (AGENTS.md shape 2).
|
|
7
|
+
- |
|
|
8
|
+
const w = path.win32;
|
|
9
|
+
if (w.isAbsolute(filePath)) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
- "isFullyQualified(filePath)"
|
|
13
|
+
- "path.posix.isAbsolute(filePath)"
|
|
14
|
+
invalid:
|
|
15
|
+
- "path.win32.isAbsolute(filePath)"
|
|
16
|
+
- "win32.isAbsolute(filePath)"
|
|
@@ -12,20 +12,8 @@ note: |
|
|
|
12
12
|
identifier, making it fire only for empty bodies or `pass`/`raise`
|
|
13
13
|
(where there are no function-call identifiers).
|
|
14
14
|
|
|
15
|
-
The
|
|
16
|
-
|
|
17
|
-
`except (E, F)`, or `as` pattern `except E as e`). The original missed
|
|
18
|
-
the tuple and `as_pattern` forms — a tuple like `(ValueError, KeyError)`
|
|
19
|
-
has no direct `identifier` child (the identifiers are inside the
|
|
20
|
-
tuple), and `except Exception as e` has `e` as an identifier child
|
|
21
|
-
even though the type is specified.
|
|
15
|
+
The rule now matches the grammar's bare `except:` syntax directly, so
|
|
16
|
+
newly introduced exception-spec node kinds cannot become false positives.
|
|
22
17
|
rule:
|
|
23
18
|
kind: except_clause
|
|
24
|
-
|
|
25
|
-
any:
|
|
26
|
-
- has:
|
|
27
|
-
kind: identifier
|
|
28
|
-
- has:
|
|
29
|
-
kind: tuple
|
|
30
|
-
- has:
|
|
31
|
-
kind: as_pattern
|
|
19
|
+
pattern: "except:"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
id: no-bare-host-path-in-win32-branch
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: warning
|
|
4
|
+
message: "Use win32 path operations inside a branch committed to Windows path semantics"
|
|
5
|
+
note: |
|
|
6
|
+
A branch guarded by isWindowsPath/isFullyQualifiedWin32 has committed to
|
|
7
|
+
Windows path parsing. Host-default dirname/basename/join/relative/sep
|
|
8
|
+
follows the process OS and is wrong for a Windows-shaped path on POSIX.
|
|
9
|
+
|
|
10
|
+
SCOPE (review-verified, #1339): same-function consequence only. The
|
|
11
|
+
original #1150 defect — a bare dirname inside an UNGUARDED helper that
|
|
12
|
+
the guarded branch calls (cross-function) — is NOT reachable by this
|
|
13
|
+
engine and stays review-enforced via AGENTS.md defect-shape 2. The
|
|
14
|
+
rule's fixture file encodes that miss as a documented negative; flip it
|
|
15
|
+
to a positive only if cross-function reach is ever added. What this
|
|
16
|
+
rule does catch is the in-branch shape (#1152 class).
|
|
17
|
+
rule:
|
|
18
|
+
all:
|
|
19
|
+
- kind: if_statement
|
|
20
|
+
- has:
|
|
21
|
+
field: condition
|
|
22
|
+
regex: "\\b(isWindowsPath|isFullyQualifiedWin32)\\s*\\("
|
|
23
|
+
- has:
|
|
24
|
+
field: consequence
|
|
25
|
+
regex: "(?s)\\bpath\\.(dirname|basename|join|relative)\\s*\\(|\\bpath\\.sep\\b|(^|[^.])\\b(dirname|basename|join|relative)\\s*\\("
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
id: no-chained-type-assertions
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: warning
|
|
4
|
+
message: "Chained type assertion (x as A as B) — stacking assertions with no runtime check between them"
|
|
5
|
+
note: |
|
|
6
|
+
`x as A as B` stacks two assertions with no runtime check between
|
|
7
|
+
them, so the compiler can't verify either hop. Narrow with a type
|
|
8
|
+
guard, or assert once to the type you actually need. `as const`
|
|
9
|
+
chains are allowed — they don't launder the value's type, they just
|
|
10
|
+
freeze a literal. `as unknown as B` chains are also allowed: routing
|
|
11
|
+
a cast through `unknown` (rather than through an unrelated concrete
|
|
12
|
+
type) is the standard, TypeScript-endorsed way to perform a cast that
|
|
13
|
+
the compiler can't otherwise verify as safe — see no-as-any.yml's own
|
|
14
|
+
note, which recommends this exact form as the safe replacement for
|
|
15
|
+
`as any`. An FP-scan of the pi-lens codebase found 22 chained-assertion
|
|
16
|
+
hits and all 22 were `as unknown as`; none were a genuine two
|
|
17
|
+
concrete-type stack.
|
|
18
|
+
rule:
|
|
19
|
+
pattern: $X as $A as $B
|
|
20
|
+
not:
|
|
21
|
+
pattern: "$X as unknown as $B"
|
package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
id: no-conditional-empty-object-spread-js
|
|
2
|
+
language: JavaScript
|
|
3
|
+
severity: hint
|
|
4
|
+
message: "Conditional empty-object spread — use an explicit if/else to omit fields"
|
|
5
|
+
note: |
|
|
6
|
+
`{...(cond ? {} : {x})}` hides field omission behind a ternary — an
|
|
7
|
+
explicit `if` reads better. Matched structurally (spread of a ternary
|
|
8
|
+
whose consequence or alternative is an empty object literal), not by
|
|
9
|
+
exact source text, so it also catches the un-parenthesized form.
|
|
10
|
+
|
|
11
|
+
Kept at `hint` to match no-conditional-empty-object-spread.yml — see
|
|
12
|
+
that rule's note for the FP-scan finding (147 hits, all a deliberate
|
|
13
|
+
existing idiom).
|
|
14
|
+
rule:
|
|
15
|
+
kind: spread_element
|
|
16
|
+
has:
|
|
17
|
+
stopBy: end
|
|
18
|
+
kind: ternary_expression
|
|
19
|
+
any:
|
|
20
|
+
- has: { field: consequence, stopBy: neighbor, kind: object, regex: '^\{\s*\}$' }
|
|
21
|
+
- has: { field: alternative, stopBy: neighbor, kind: object, regex: '^\{\s*\}$' }
|
package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
id: no-conditional-empty-object-spread
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: hint
|
|
4
|
+
message: "Conditional empty-object spread — use an explicit if/else to omit fields"
|
|
5
|
+
note: |
|
|
6
|
+
`{...(cond ? {} : {x})}` hides field omission behind a ternary — an
|
|
7
|
+
explicit `if` reads better and lets the object's shape stay typed.
|
|
8
|
+
Matched structurally (spread of a ternary whose consequence or
|
|
9
|
+
alternative is an empty object literal), not by exact source text, so
|
|
10
|
+
it also catches the un-parenthesized and multi-property-spread forms.
|
|
11
|
+
|
|
12
|
+
FP-scan finding (pi-lens codebase, clients/ tools/ mcp/ index.ts): 147
|
|
13
|
+
hits, and every sampled hit is this exact shape used deliberately to
|
|
14
|
+
build an optional-field object (`...(hit.annotations ? {
|
|
15
|
+
annotations: hit.annotations } : {})`). That is a real, established
|
|
16
|
+
idiom here, not a shape mismatch — so the rule stays at `hint` rather
|
|
17
|
+
than `warning`: still discoverable in a scan, but it does not read as
|
|
18
|
+
a call to fix 147 existing sites.
|
|
19
|
+
rule:
|
|
20
|
+
kind: spread_element
|
|
21
|
+
has:
|
|
22
|
+
# the ternary sits under a parenthesized_expression when the source
|
|
23
|
+
# parenthesizes it, so this needs stopBy: end — spread_element's
|
|
24
|
+
# DIRECT child is not the ternary in that (common) form.
|
|
25
|
+
stopBy: end
|
|
26
|
+
kind: ternary_expression
|
|
27
|
+
any:
|
|
28
|
+
- has: { field: consequence, stopBy: neighbor, kind: object, regex: '^\{\s*\}$' }
|
|
29
|
+
- has: { field: alternative, stopBy: neighbor, kind: object, regex: '^\{\s*\}$' }
|
|
@@ -8,6 +8,12 @@ note: |
|
|
|
8
8
|
rule:
|
|
9
9
|
all:
|
|
10
10
|
- kind: jsx_element
|
|
11
|
+
- has:
|
|
12
|
+
field: open_tag
|
|
13
|
+
kind: jsx_opening_element
|
|
14
|
+
has:
|
|
15
|
+
field: name
|
|
16
|
+
regex: "^a$"
|
|
11
17
|
- has:
|
|
12
18
|
kind: jsx_element
|
|
13
19
|
stopBy: end
|
|
@@ -20,6 +26,7 @@ rule:
|
|
|
20
26
|
not:
|
|
21
27
|
inside:
|
|
22
28
|
kind: jsx_element
|
|
29
|
+
stopBy: end
|
|
23
30
|
has:
|
|
24
31
|
field: open_tag
|
|
25
32
|
kind: jsx_opening_element
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
id: no-raw-json-store-write
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: warning
|
|
4
|
+
message: "Use the atomic write seam for JSON stores instead of writeFileSync"
|
|
5
|
+
note: |
|
|
6
|
+
JSON-backed durable state must be committed through clients/durable-store.ts
|
|
7
|
+
when read-modify-write isolation is required; that seam publishes through
|
|
8
|
+
clients/atomic-write.ts. This rule covers the direct
|
|
9
|
+
writeFileSync(path, JSON.stringify(data)) shape. Build scripts and the
|
|
10
|
+
installer's wx lock writes are intentionally outside this rule's scope.
|
|
11
|
+
ignores:
|
|
12
|
+
- "**/clients/atomic-write.ts"
|
|
13
|
+
- "**/clients/installer/index.ts"
|
|
14
|
+
- "**/scripts/**"
|
|
15
|
+
rule:
|
|
16
|
+
any:
|
|
17
|
+
- pattern: writeFileSync($PATH, JSON.stringify($$$ARGS))
|
|
18
|
+
- pattern: $FS.writeFileSync($PATH, JSON.stringify($$$ARGS))
|
|
19
|
+
- pattern: writeFileSync($PATH, JSON.stringify($$$ARGS), $OPTS)
|
|
20
|
+
- pattern: $FS.writeFileSync($PATH, JSON.stringify($$$ARGS), $OPTS)
|
|
21
|
+
- kind: expression_statement
|
|
22
|
+
has:
|
|
23
|
+
pattern: writeFileSync($PATH, $PAYLOAD)
|
|
24
|
+
follows:
|
|
25
|
+
pattern: const $PAYLOAD = JSON.stringify($DATA)
|
|
26
|
+
- kind: expression_statement
|
|
27
|
+
has:
|
|
28
|
+
pattern: $FS.writeFileSync($PATH, $PAYLOAD)
|
|
29
|
+
follows:
|
|
30
|
+
pattern: const $PAYLOAD = JSON.stringify($DATA)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
id: no-reflect-apply-js
|
|
2
|
+
language: JavaScript
|
|
3
|
+
severity: warning
|
|
4
|
+
message: "Reflect.apply() — use a typed call (fn.apply(...) or fn(...args)) instead"
|
|
5
|
+
note: |
|
|
6
|
+
Reflect.apply reaches for reflection where a typed call already works.
|
|
7
|
+
Prefer Function#apply or a direct call with spread arguments.
|
|
8
|
+
rule:
|
|
9
|
+
pattern: Reflect.apply($$$ARGS)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
id: no-reflect-apply
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: warning
|
|
4
|
+
message: "Reflect.apply() — use a typed call (fn.apply(...) or fn(...args)) instead"
|
|
5
|
+
note: |
|
|
6
|
+
Reflect.apply reaches for reflection where a typed call already works.
|
|
7
|
+
Prefer Function#apply or a direct call with spread arguments.
|
|
8
|
+
rule:
|
|
9
|
+
pattern: Reflect.apply($$$ARGS)
|