pi-lens 4.3.0 → 4.4.0
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/CHANGELOG.md +1064 -0
- package/README.md +115 -25
- package/config/dependency-cruiser-eager-allowlist.json +6 -2
- package/dist/chunk-22AVIGXS.js +560 -0
- package/dist/chunk-27BBHSZC.js +106 -0
- package/dist/chunk-2BEMIWEW.js +51 -0
- package/dist/chunk-2EECBNC5.js +89 -0
- package/dist/chunk-34U7PLGE.js +23 -0
- package/dist/chunk-3I5QFT3N.js +181 -0
- package/dist/chunk-3MED75HT.js +37 -0
- package/dist/chunk-47D2BO4S.js +87 -0
- package/dist/chunk-4RERDEXR.js +348 -0
- package/dist/chunk-4W2PLC4J.js +27 -0
- package/dist/chunk-52H5B5TC.js +202 -0
- package/dist/chunk-54B42YRX.js +27 -0
- package/dist/chunk-5RXBNSW2.js +266 -0
- package/dist/chunk-5THXD6X5.js +201 -0
- package/dist/chunk-5W3R6LFT.js +24 -0
- package/dist/chunk-5ZEJHV35.js +341 -0
- package/dist/chunk-6P62QVEA.js +118 -0
- package/dist/chunk-6QIUX4EP.js +459 -0
- package/dist/chunk-6VCD4VKZ.js +78 -0
- package/dist/chunk-7F72PXY2.js +326 -0
- package/dist/chunk-7FBF7NPR.js +998 -0
- package/dist/chunk-7U2IDNXN.js +37 -0
- package/dist/chunk-ABBOA7UD.js +157 -0
- package/dist/chunk-AHDW3GPE.js +50 -0
- package/dist/chunk-AJ3QXTRQ.js +756 -0
- package/dist/chunk-AJVLWNFN.js +1610 -0
- package/dist/chunk-AJXODZY6.js +112 -0
- package/dist/chunk-ARFCXG7S.js +84 -0
- package/dist/chunk-AS44CFQ4.js +708 -0
- package/dist/chunk-AWE5TMPO.js +38 -0
- package/dist/chunk-B3I2UUT4.js +4692 -0
- package/dist/chunk-BRJKOBZP.js +331 -0
- package/dist/chunk-BW5KFIQC.js +59 -0
- package/dist/chunk-C2AUYXQH.js +149 -0
- package/dist/chunk-CGGAIP7J.js +29 -0
- package/dist/chunk-D6QS3U6M.js +30 -0
- package/dist/chunk-DFVMIKMQ.js +349 -0
- package/dist/chunk-DIULIWKU.js +169 -0
- package/dist/chunk-DQ2NZ7C4.js +2317 -0
- package/dist/chunk-E2WFBRHM.js +213 -0
- package/dist/chunk-E4MAEDPM.js +50 -0
- package/dist/chunk-EOKRQ3SA.js +30 -0
- package/dist/chunk-F3AU2TMM.js +2626 -0
- package/dist/chunk-F3P7VQ7H.js +170 -0
- package/dist/chunk-FC4RP4I2.js +12 -0
- package/dist/chunk-FJNKANOS.js +32 -0
- package/dist/chunk-GUOGVTCQ.js +146 -0
- package/dist/chunk-GVXA6CCE.js +18 -0
- package/dist/chunk-HHYAELLJ.js +2334 -0
- package/dist/chunk-HMFXILPV.js +83 -0
- package/dist/chunk-HVUZXSWK.js +421 -0
- package/dist/chunk-HWBZIGMJ.js +62 -0
- package/dist/chunk-I3R7GKDR.js +17 -0
- package/dist/chunk-I7SPGOWI.js +55 -0
- package/dist/chunk-IIXOAGHR.js +38 -0
- package/dist/chunk-IVP5KAB7.js +2250 -0
- package/dist/chunk-IXEBJSUE.js +22 -0
- package/dist/chunk-JOLITGCC.js +27 -0
- package/dist/chunk-K6VYLB2U.js +145 -0
- package/dist/chunk-LJDODBBZ.js +78 -0
- package/dist/chunk-LNAKEO63.js +78 -0
- package/dist/chunk-LSMJ6KBE.js +4139 -0
- package/dist/chunk-LW6XKDZQ.js +5565 -0
- package/dist/chunk-N3YQJI6O.js +899 -0
- package/dist/chunk-NABLC7W3.js +148 -0
- package/dist/chunk-NKOUFPQF.js +659 -0
- package/dist/chunk-NL5GLMFI.js +211 -0
- package/dist/chunk-NMABWBZN.js +327 -0
- package/dist/chunk-NTHH2J74.js +27 -0
- package/dist/chunk-NTUJEGDZ.js +59 -0
- package/dist/chunk-NXL4FFQQ.js +47 -0
- package/dist/chunk-NXPS2L6U.js +466 -0
- package/dist/chunk-O5WILGMI.js +42 -0
- package/dist/chunk-O6TQT6RI.js +48 -0
- package/dist/chunk-OAXNDZJ7.js +323 -0
- package/dist/chunk-ODEEOXPH.js +44 -0
- package/dist/chunk-OQGFCZJ4.js +4533 -0
- package/dist/chunk-ORTMY4Q4.js +282 -0
- package/dist/chunk-OS32RNR2.js +442 -0
- package/dist/chunk-PAK6IDME.js +189 -0
- package/dist/chunk-PWFHBTSF.js +406 -0
- package/dist/chunk-Q5U6FMDI.js +2352 -0
- package/dist/chunk-QOZXJ4NA.js +3364 -0
- package/dist/chunk-QYF5S6P6.js +45 -0
- package/dist/chunk-RIISMHKN.js +36 -0
- package/dist/chunk-RPD4ZSB7.js +25 -0
- package/dist/chunk-RPD5K5NC.js +79 -0
- package/dist/chunk-RUOG5D2C.js +262 -0
- package/dist/chunk-T4ERT73Y.js +599 -0
- package/dist/chunk-T6D4Q4AQ.js +54 -0
- package/dist/chunk-TGPXLY2J.js +391 -0
- package/dist/chunk-TLGFBM3F.js +12116 -0
- package/dist/chunk-TO6WL3GM.js +88 -0
- package/dist/chunk-TT22N74J.js +517 -0
- package/dist/chunk-TVN5N6GY.js +21216 -0
- package/dist/chunk-U3VGR4VU.js +308 -0
- package/dist/chunk-UK3CMEAL.js +1250 -0
- package/dist/chunk-UOPVJQ4N.js +103 -0
- package/dist/chunk-UXVNL3D7.js +23 -0
- package/dist/chunk-UY752QSN.js +45 -0
- package/dist/chunk-V5PXFSZK.js +188 -0
- package/dist/chunk-V7R425XG.js +398 -0
- package/dist/chunk-VCSRSYLF.js +81 -0
- package/dist/chunk-VD4JQCQC.js +162 -0
- package/dist/chunk-VDBPVIKD.js +62 -0
- package/dist/chunk-VHQLPIRJ.js +114 -0
- package/dist/chunk-VN2AXLEX.js +5414 -0
- package/dist/chunk-VNMT7C64.js +478 -0
- package/dist/chunk-WONERJTP.js +309 -0
- package/dist/chunk-XECLWQZN.js +85 -0
- package/dist/chunk-XIMYZ3JA.js +27 -0
- package/dist/chunk-XK4CIILI.js +144 -0
- package/dist/chunk-Y4T27COV.js +562 -0
- package/dist/chunk-YGVYKNSN.js +1860 -0
- package/dist/chunk-YLF3PPT5.js +308 -0
- package/dist/chunk-YSNFMJKN.js +14 -0
- package/dist/chunk-Z3CCVDUB.js +76 -0
- package/dist/chunk-Z54ZSOBZ.js +61 -0
- package/dist/chunk-ZAWW3AF6.js +97 -0
- package/dist/chunk-ZMOL6RQC.js +167 -0
- package/dist/index.js +16456 -8335
- package/dist/mcp/analyze-cli.js +186 -232
- package/dist/mcp/cli.js +137 -98
- package/dist/mcp/server.js +22589 -1573
- package/dist/mcp/worker.js +97 -38
- package/dist/probes/installer.js +135 -0
- package/dist/workers/project-snapshot-persist-worker.js +22 -0
- package/dist/workers/review-graph-persist-worker.js +15 -0
- package/docs/agent-guide.md +13 -4
- package/docs/agent-tools.md +42 -0
- package/docs/ast-grep_rules_catalog.md +3 -2
- package/docs/configuration.md +20 -1
- package/docs/environment-variables.md +52 -2
- package/docs/features.md +8 -4
- package/docs/globalconfig.md +1 -0
- package/docs/io-bridge-v2-migration.md +94 -0
- package/docs/lsp-capability-matrix.md +36 -4
- package/docs/lsp-idle-eviction.md +124 -0
- package/docs/mcp.md +21 -5
- package/docs/merge-queue-rollout.md +77 -0
- package/docs/pi-lens-fixer.md +156 -88
- package/docs/pi-lens-investigator.md +74 -26
- package/docs/pi-lens-merge-policy.md +694 -0
- package/docs/pi-lens-monitor.md +73 -7
- package/docs/pi-lens-retro.md +6 -4
- package/docs/pi-lens-reviewer.md +188 -48
- package/docs/pi-lens-subagent.md +246 -45
- package/docs/pi-lens-warden.md +18 -7
- package/docs/public-api-stability.md +55 -0
- package/docs/release-qa-baseline.md +84 -17
- package/docs/rfcs/3654-unified-io-bridge-v2.md +316 -0
- package/docs/servercapabilities.md +53 -49
- package/docs/settings.md +1 -0
- package/docs/usage.md +5 -1
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-bash.wasm.json +3 -3
- package/package.json +19 -7
- package/rules/ast-grep-rules/rule-tests/advisory-registry-subset-test.yml +41 -0
- package/rules/ast-grep-rules/rules/advisory-registry-subset.yml +50 -0
- package/scripts/analyze-pi-lens-logs.mjs +1275 -62
- package/scripts/download-grammars.js +5 -0
- package/scripts/grammars.lock.json +6 -1
- package/scripts/install-selftest.mjs +33 -34
- package/scripts/lib/host-provided-deps.mjs +13 -4
- package/scripts/lib/web-tree-sitter-dir.mjs +18 -0
- package/dist/clients/actionable-warnings-logger.js +0 -35
- package/dist/clients/actionable-warnings.js +0 -1610
- package/dist/clients/advisory-provenance.js +0 -593
- package/dist/clients/agent-behavior-client.js +0 -147
- package/dist/clients/agent-nudge.js +0 -325
- package/dist/clients/analysed-root.js +0 -1
- package/dist/clients/ast-grep-client.js +0 -731
- package/dist/clients/ast-grep-rule-manager.js +0 -146
- package/dist/clients/ast-grep-tool-logger.js +0 -118
- package/dist/clients/ast-grep-types.js +0 -10
- package/dist/clients/ast-grep-yaml-synth.js +0 -154
- package/dist/clients/atomic-write-staging.js +0 -75
- package/dist/clients/atomic-write.js +0 -189
- package/dist/clients/availability-probe-flight.js +0 -12
- package/dist/clients/bash-file-access.js +0 -1056
- package/dist/clients/biome-client.js +0 -357
- package/dist/clients/blocker-freshness.js +0 -837
- package/dist/clients/blocker-past-eof.js +0 -129
- package/dist/clients/bootstrap.js +0 -569
- package/dist/clients/bounded-cache.js +0 -190
- package/dist/clients/bounded-pid-file-lock.js +0 -202
- package/dist/clients/bounded-telemetry.js +0 -295
- package/dist/clients/build-identity.js +0 -95
- package/dist/clients/bundled-resource-health.js +0 -113
- package/dist/clients/bus-events-logger.js +0 -105
- package/dist/clients/bus-publish.js +0 -171
- package/dist/clients/cache/rule-cache.js +0 -190
- package/dist/clients/cache-manager.js +0 -524
- package/dist/clients/cache-observability.js +0 -1313
- package/dist/clients/call-graph.js +0 -852
- package/dist/clients/cargo-manifest.js +0 -422
- package/dist/clients/cascade-budget.js +0 -196
- package/dist/clients/cascade-format.js +0 -315
- package/dist/clients/cascade-logger.js +0 -31
- package/dist/clients/cascade-types.js +0 -9
- package/dist/clients/child-unref.js +0 -124
- package/dist/clients/code-quality-warnings.js +0 -286
- package/dist/clients/codebase-model.js +0 -173
- package/dist/clients/collateral-test-role.js +0 -40
- package/dist/clients/complexity-client.js +0 -462
- package/dist/clients/config-core/deny.js +0 -221
- package/dist/clients/config-core/index.js +0 -50
- package/dist/clients/config-core/merge.js +0 -357
- package/dist/clients/config-core/normalize.js +0 -340
- package/dist/clients/config-core/process-spec.js +0 -248
- package/dist/clients/config-core/provenance.js +0 -164
- package/dist/clients/config-core/records.js +0 -218
- package/dist/clients/config-core/resolve.js +0 -125
- package/dist/clients/config-core/safe-object.js +0 -78
- package/dist/clients/config-core/schema.js +0 -165
- package/dist/clients/config-diagnostic-codes.js +0 -285
- package/dist/clients/config-locations.js +0 -388
- package/dist/clients/config-resolve.js +0 -798
- package/dist/clients/config-schema.js +0 -251
- package/dist/clients/config-warn.js +0 -407
- package/dist/clients/console-guard-install.js +0 -26
- package/dist/clients/cooperative-budget.js +0 -42
- package/dist/clients/dead-code-client.js +0 -510
- package/dist/clients/dead-code-logger.js +0 -30
- package/dist/clients/deadline-utils.js +0 -280
- package/dist/clients/debug-handles.js +0 -211
- package/dist/clients/debug-heap.js +0 -174
- package/dist/clients/deferred-lsp-work.js +0 -106
- package/dist/clients/degradation-ledger.js +0 -426
- package/dist/clients/demoted-finding-render.js +0 -169
- package/dist/clients/dependency-checker.js +0 -885
- package/dist/clients/deps/ast-grep-napi.js +0 -22
- package/dist/clients/deps/js-yaml.js +0 -9
- package/dist/clients/deps/minimatch.js +0 -4
- package/dist/clients/deps/pi-tui.js +0 -14
- package/dist/clients/deps/typebox.js +0 -14
- package/dist/clients/deps/vscode-jsonrpc.js +0 -1
- package/dist/clients/deps/web-tree-sitter.js +0 -24
- package/dist/clients/diagnostic-dispositions.js +0 -630
- package/dist/clients/diagnostic-line-freshness.js +0 -305
- package/dist/clients/diagnostic-logger.js +0 -73
- package/dist/clients/diagnostic-tracker.js +0 -105
- package/dist/clients/diagnostics-publish.js +0 -230
- package/dist/clients/dispatch/ast-grep-catalog.js +0 -65
- package/dist/clients/dispatch/auxiliary-lsp.js +0 -343
- package/dist/clients/dispatch/collect-later-tier.js +0 -35
- package/dist/clients/dispatch/diagnostic-taxonomy.js +0 -66
- package/dist/clients/dispatch/dispatcher.js +0 -1269
- package/dist/clients/dispatch/fact-provider-types.js +0 -1
- package/dist/clients/dispatch/fact-rule-runner.js +0 -17
- package/dist/clients/dispatch/fact-runner.js +0 -30
- package/dist/clients/dispatch/fact-scheduler.js +0 -68
- package/dist/clients/dispatch/fact-store.js +0 -377
- package/dist/clients/dispatch/facts/comment-facts.js +0 -22
- package/dist/clients/dispatch/facts/file-content.js +0 -19
- package/dist/clients/dispatch/facts/function-facts.js +0 -348
- package/dist/clients/dispatch/facts/import-facts.js +0 -204
- package/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -34
- package/dist/clients/dispatch/facts/try-catch-facts.js +0 -119
- package/dist/clients/dispatch/finding-policy.js +0 -339
- package/dist/clients/dispatch/indent-detect.js +0 -417
- package/dist/clients/dispatch/inline-suppressions.js +0 -89
- package/dist/clients/dispatch/integration.js +0 -2377
- package/dist/clients/dispatch/lazy.js +0 -11
- package/dist/clients/dispatch/pending-runner-findings.js +0 -87
- package/dist/clients/dispatch/plan.js +0 -278
- package/dist/clients/dispatch/priorities.js +0 -20
- package/dist/clients/dispatch/rule-id-normalize.js +0 -50
- package/dist/clients/dispatch/rule-ignores.js +0 -69
- package/dist/clients/dispatch/rule-policy.js +0 -135
- package/dist/clients/dispatch/rules/async-noise.js +0 -40
- package/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
- package/dist/clients/dispatch/rules/cors-wildcard.js +0 -54
- package/dist/clients/dispatch/rules/error-obscuring.js +0 -32
- package/dist/clients/dispatch/rules/error-swallowing.js +0 -31
- package/dist/clients/dispatch/rules/framework-call-noise.js +0 -67
- package/dist/clients/dispatch/rules/high-complexity.js +0 -72
- package/dist/clients/dispatch/rules/high-fan-out.js +0 -74
- package/dist/clients/dispatch/rules/high-import-coupling.js +0 -37
- package/dist/clients/dispatch/rules/missing-error-propagation.js +0 -62
- package/dist/clients/dispatch/rules/no-commented-credentials.js +0 -52
- package/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -42
- package/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
- package/dist/clients/dispatch/rules/unsafe-boundary.js +0 -126
- package/dist/clients/dispatch/runner-context.js +0 -52
- package/dist/clients/dispatch/runners/actionlint.js +0 -111
- package/dist/clients/dispatch/runners/ast-grep-napi.js +0 -1196
- package/dist/clients/dispatch/runners/biome-check.js +0 -296
- package/dist/clients/dispatch/runners/cpp-check.js +0 -219
- package/dist/clients/dispatch/runners/credo.js +0 -82
- package/dist/clients/dispatch/runners/cue-vet.js +0 -416
- package/dist/clients/dispatch/runners/dart-analyze.js +0 -183
- package/dist/clients/dispatch/runners/detekt.js +0 -176
- package/dist/clients/dispatch/runners/dotnet-build.js +0 -164
- package/dist/clients/dispatch/runners/elixir-check.js +0 -195
- package/dist/clients/dispatch/runners/eslint.js +0 -137
- package/dist/clients/dispatch/runners/fact-rules.js +0 -29
- package/dist/clients/dispatch/runners/fish-indent.js +0 -69
- package/dist/clients/dispatch/runners/gleam-check.js +0 -167
- package/dist/clients/dispatch/runners/go-vet.js +0 -104
- package/dist/clients/dispatch/runners/golangci-lint.js +0 -135
- package/dist/clients/dispatch/runners/hadolint.js +0 -91
- package/dist/clients/dispatch/runners/helm-lint.js +0 -171
- package/dist/clients/dispatch/runners/helm-render.js +0 -940
- package/dist/clients/dispatch/runners/htmlhint.js +0 -117
- package/dist/clients/dispatch/runners/index.js +0 -108
- package/dist/clients/dispatch/runners/javac.js +0 -99
- package/dist/clients/dispatch/runners/ktlint.js +0 -110
- package/dist/clients/dispatch/runners/lsp.js +0 -379
- package/dist/clients/dispatch/runners/markdownlint.js +0 -167
- package/dist/clients/dispatch/runners/mypy.js +0 -102
- package/dist/clients/dispatch/runners/oxlint.js +0 -414
- package/dist/clients/dispatch/runners/php-lint.js +0 -85
- package/dist/clients/dispatch/runners/phpstan.js +0 -120
- package/dist/clients/dispatch/runners/prisma-validate.js +0 -62
- package/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -445
- package/dist/clients/dispatch/runners/pyright.js +0 -169
- package/dist/clients/dispatch/runners/rubocop.js +0 -99
- package/dist/clients/dispatch/runners/ruff.js +0 -88
- package/dist/clients/dispatch/runners/rust-clippy.js +0 -256
- package/dist/clients/dispatch/runners/shellcheck.js +0 -173
- package/dist/clients/dispatch/runners/shfmt.js +0 -102
- package/dist/clients/dispatch/runners/spellcheck.js +0 -128
- package/dist/clients/dispatch/runners/spotbugs.js +0 -259
- package/dist/clients/dispatch/runners/sqlfluff.js +0 -183
- package/dist/clients/dispatch/runners/stylelint.js +0 -166
- package/dist/clients/dispatch/runners/swiftlint.js +0 -163
- package/dist/clients/dispatch/runners/taplo.js +0 -174
- package/dist/clients/dispatch/runners/terragrunt.js +0 -168
- package/dist/clients/dispatch/runners/tflint.js +0 -125
- package/dist/clients/dispatch/runners/tree-sitter.js +0 -643
- package/dist/clients/dispatch/runners/trivy-config.js +0 -253
- package/dist/clients/dispatch/runners/utils/availability-policy.js +0 -496
- package/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -90
- package/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -95
- package/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -274
- package/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1701
- package/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -101
- package/dist/clients/dispatch/runners/utils/tool-failure.js +0 -235
- package/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -169
- package/dist/clients/dispatch/runners/utils.js +0 -15
- package/dist/clients/dispatch/runners/vale.js +0 -128
- package/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -242
- package/dist/clients/dispatch/runners/yamllint.js +0 -95
- package/dist/clients/dispatch/runners/zig-check.js +0 -79
- package/dist/clients/dispatch/suppress-writer.js +0 -79
- package/dist/clients/dispatch/tool-profile.js +0 -30
- package/dist/clients/dispatch/types.js +0 -21
- package/dist/clients/dispatch/utils/format-utils.js +0 -45
- package/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -35
- package/dist/clients/disposition-logger.js +0 -32
- package/dist/clients/disposition-publish.js +0 -124
- package/dist/clients/durable-store.js +0 -97
- package/dist/clients/effective-config.js +0 -415
- package/dist/clients/env-utils.js +0 -83
- package/dist/clients/error-class.js +0 -23
- package/dist/clients/eval-timestamp.js +0 -17
- package/dist/clients/event-loop-hold.js +0 -274
- package/dist/clients/event-loop-monitor.js +0 -250
- package/dist/clients/extension-log.js +0 -504
- package/dist/clients/extension-mode.js +0 -73
- package/dist/clients/feature-hints.js +0 -103
- package/dist/clients/file-kinds.js +0 -412
- package/dist/clients/file-role.js +0 -134
- package/dist/clients/file-time.js +0 -160
- package/dist/clients/file-utils.js +0 -1032
- package/dist/clients/finding-delivery-gate.js +0 -494
- package/dist/clients/finding-identity.js +0 -88
- package/dist/clients/fix-worklog.js +0 -103
- package/dist/clients/format-events-publish.js +0 -343
- package/dist/clients/format-service.js +0 -222
- package/dist/clients/formatters-lazy.js +0 -9
- package/dist/clients/formatters.js +0 -2032
- package/dist/clients/freshness-cadence.js +0 -17
- package/dist/clients/freshness.js +0 -38
- package/dist/clients/generated-artifacts.js +0 -394
- package/dist/clients/generation-guard.js +0 -215
- package/dist/clients/git-guard.js +0 -1136
- package/dist/clients/git-tracked-ignore.js +0 -243
- package/dist/clients/gitleaks-client.js +0 -509
- package/dist/clients/go-client.js +0 -104
- package/dist/clients/govulncheck-client.js +0 -605
- package/dist/clients/gradle-ktfmt-style.js +0 -348
- package/dist/clients/grammar-source.js +0 -465
- package/dist/clients/gzip-stage-write.js +0 -135
- package/dist/clients/hashline-anchor.js +0 -424
- package/dist/clients/hook-budgets.js +0 -76
- package/dist/clients/host-edit-normalize.js +0 -140
- package/dist/clients/host-ports.js +0 -39
- package/dist/clients/indent-retarget.js +0 -154
- package/dist/clients/inline-blocker-dispositions.js +0 -186
- package/dist/clients/install-diagnostics.js +0 -156
- package/dist/clients/installer/index.js +0 -5416
- package/dist/clients/installer/managed-tool-refresh-session.js +0 -58
- package/dist/clients/installer/managed-tool-refresh.js +0 -783
- package/dist/clients/instance-reaper-state.js +0 -7
- package/dist/clients/instance-reaper.js +0 -1137
- package/dist/clients/instance-registry-lock.js +0 -145
- package/dist/clients/instance-registry.js +0 -773
- package/dist/clients/jscpd-client.js +0 -378
- package/dist/clients/json-cache-read.js +0 -65
- package/dist/clients/knip-client.js +0 -788
- package/dist/clients/language-policy.js +0 -252
- package/dist/clients/language-profile.js +0 -361
- package/dist/clients/language-registry.js +0 -603
- package/dist/clients/latency-logger.js +0 -727
- package/dist/clients/lazy-import.js +0 -21
- package/dist/clients/ledger-bounds.js +0 -54
- package/dist/clients/lens-config.js +0 -404
- package/dist/clients/lens-engine.js +0 -358
- package/dist/clients/lens-events.js +0 -125
- package/dist/clients/lens-flag-registry.js +0 -467
- package/dist/clients/lens-map.js +0 -1156
- package/dist/clients/live-bus-emitter.js +0 -74
- package/dist/clients/log-cleanup.js +0 -222
- package/dist/clients/lsp/aggregation.js +0 -178
- package/dist/clients/lsp/cascade-tier.js +0 -421
- package/dist/clients/lsp/client.js +0 -4593
- package/dist/clients/lsp/config.js +0 -691
- package/dist/clients/lsp/content-limits.js +0 -41
- package/dist/clients/lsp/diagnostic-binding.js +0 -225
- package/dist/clients/lsp/document-drift.js +0 -467
- package/dist/clients/lsp/edits.js +0 -1219
- package/dist/clients/lsp/index.js +0 -8305
- package/dist/clients/lsp/inferred-project.js +0 -216
- package/dist/clients/lsp/jvm-runtime.js +0 -298
- package/dist/clients/lsp/language.js +0 -63
- package/dist/clients/lsp/launch.js +0 -746
- package/dist/clients/lsp/lombok.js +0 -158
- package/dist/clients/lsp/path-utils.js +0 -5
- package/dist/clients/lsp/pending-aux-coverage.js +0 -251
- package/dist/clients/lsp/position-encoding.js +0 -61
- package/dist/clients/lsp/ruby-drive-dirs.js +0 -83
- package/dist/clients/lsp/server.js +0 -3290
- package/dist/clients/lsp/session-roots.js +0 -192
- package/dist/clients/lsp/spawn-history.js +0 -17
- package/dist/clients/lsp/sync-kind.js +0 -56
- package/dist/clients/lsp/tsserver-sync.js +0 -332
- package/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
- package/dist/clients/lsp/wait-policy/classification.js +0 -85
- package/dist/clients/lsp/wait-policy/index.js +0 -10
- package/dist/clients/lsp/wait-policy/strategies.js +0 -392
- package/dist/clients/lsp/watch-queue.js +0 -61
- package/dist/clients/lsp/workspace-diagnostics-cache.js +0 -639
- package/dist/clients/lsp/workspace-diagnostics-session.js +0 -30
- package/dist/clients/lsp/workspace-sweep-hold.js +0 -184
- package/dist/clients/lsp-budget.js +0 -186
- package/dist/clients/lsp-document-symbols.js +0 -110
- package/dist/clients/lsp-lazy.js +0 -9
- package/dist/clients/lsp-mutation.js +0 -396
- package/dist/clients/lsp-status.js +0 -59
- package/dist/clients/map-with-concurrency.js +0 -40
- package/dist/clients/mcp/analyze.js +0 -420
- package/dist/clients/mcp/host-shim.js +0 -31
- package/dist/clients/mcp/ipc.js +0 -523
- package/dist/clients/mcp/review.js +0 -197
- package/dist/clients/mcp/session.js +0 -412
- package/dist/clients/memory-sampler.js +0 -208
- package/dist/clients/message-end-attribution.js +0 -30
- package/dist/clients/metrics-client.js +0 -107
- package/dist/clients/metrics-history.js +0 -327
- package/dist/clients/middle-man-analysis.js +0 -263
- package/dist/clients/model-provider.js +0 -53
- package/dist/clients/module-report-lsp.js +0 -189
- package/dist/clients/module-report.js +0 -2150
- package/dist/clients/mutating-tool.js +0 -651
- package/dist/clients/mutation-attribution.js +0 -368
- package/dist/clients/mutation-bridge.js +0 -240
- package/dist/clients/ndjson-logger.js +0 -734
- package/dist/clients/observed-mutation-sources.js +0 -101
- package/dist/clients/observed-mutation.js +0 -1253
- package/dist/clients/oldtext-autopatch.js +0 -128
- package/dist/clients/opaque-mutation-scan.js +0 -496
- package/dist/clients/opengrep-client.js +0 -333
- package/dist/clients/opengrep-config.js +0 -76
- package/dist/clients/package-manager.js +0 -607
- package/dist/clients/package-root.js +0 -38
- package/dist/clients/partial-edit-apply.js +0 -439
- package/dist/clients/path-attribution-telemetry.js +0 -43
- package/dist/clients/path-keyed-map.js +0 -108
- package/dist/clients/path-utils.js +0 -1244
- package/dist/clients/performance-report.js +0 -331
- package/dist/clients/persist-debounce.js +0 -70
- package/dist/clients/persistent-reverify.js +0 -271
- package/dist/clients/php-cs-fixer-config.js +0 -119
- package/dist/clients/pipeline.js +0 -1480
- package/dist/clients/post-autofix-notice.js +0 -37
- package/dist/clients/print-mode.js +0 -21
- package/dist/clients/probe-home-state.js +0 -228
- package/dist/clients/process-bridge.js +0 -66
- package/dist/clients/process-singletons.js +0 -210
- package/dist/clients/process-snapshot.js +0 -68
- package/dist/clients/project-changes.js +0 -181
- package/dist/clients/project-conventions.js +0 -171
- package/dist/clients/project-diagnostics/cache.js +0 -137
- package/dist/clients/project-diagnostics/extractors.js +0 -109
- package/dist/clients/project-diagnostics/fresh-fetch.js +0 -668
- package/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -118
- package/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -47
- package/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -40
- package/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -34
- package/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -38
- package/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -47
- package/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -48
- package/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -40
- package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -127
- package/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -81
- package/dist/clients/project-diagnostics/scanner.js +0 -520
- package/dist/clients/project-diagnostics/types.js +0 -1
- package/dist/clients/project-lens-config.js +0 -807
- package/dist/clients/project-report.js +0 -701
- package/dist/clients/project-scale.js +0 -237
- package/dist/clients/project-scan-policy.js +0 -11
- package/dist/clients/project-snapshot-fingerprint.js +0 -48
- package/dist/clients/project-snapshot-persist-worker.js +0 -20
- package/dist/clients/project-snapshot.js +0 -1653
- package/dist/clients/project-trust.js +0 -181
- package/dist/clients/python-environment.js +0 -217
- package/dist/clients/python-provenance.js +0 -639
- package/dist/clients/quiet-window-config.js +0 -47
- package/dist/clients/quiet-window.js +0 -236
- package/dist/clients/read-bridge.js +0 -139
- package/dist/clients/read-expansion.js +0 -266
- package/dist/clients/read-guard-logger.js +0 -251
- package/dist/clients/read-guard-tool-lines.js +0 -1306
- package/dist/clients/read-guard.js +0 -1561
- package/dist/clients/recent-touches.js +0 -240
- package/dist/clients/redact/secrets.js +0 -449
- package/dist/clients/resource-sampler.js +0 -628
- package/dist/clients/reverse-deps.js +0 -270
- package/dist/clients/review-graph/builder.js +0 -5126
- package/dist/clients/review-graph/format.js +0 -33
- package/dist/clients/review-graph/git-identity.js +0 -163
- package/dist/clients/review-graph/import-resolvers.js +0 -481
- package/dist/clients/review-graph/persist-worker.js +0 -10
- package/dist/clients/review-graph/query.js +0 -244
- package/dist/clients/review-graph/revision-drift.js +0 -21
- package/dist/clients/review-graph/service.js +0 -96
- package/dist/clients/review-graph/shared-extraction-ir.js +0 -82
- package/dist/clients/review-graph/symbol-id.js +0 -103
- package/dist/clients/review-graph/tsconfig-paths.js +0 -299
- package/dist/clients/review-graph/types.js +0 -1
- package/dist/clients/review-graph/workspace-modules.js +0 -449
- package/dist/clients/review-graph-logger.js +0 -81
- package/dist/clients/ruff-client.js +0 -179
- package/dist/clients/rules-scanner.js +0 -131
- package/dist/clients/run-duration.js +0 -55
- package/dist/clients/runtime-agent-end.js +0 -746
- package/dist/clients/runtime-config.js +0 -77
- package/dist/clients/runtime-context.js +0 -211
- package/dist/clients/runtime-coordinator.js +0 -1324
- package/dist/clients/runtime-session.js +0 -2485
- package/dist/clients/runtime-tool-call.js +0 -1295
- package/dist/clients/runtime-tool-result.js +0 -2049
- package/dist/clients/runtime-turn.js +0 -3767
- package/dist/clients/rust-client.js +0 -97
- package/dist/clients/safe-spawn.js +0 -2357
- package/dist/clients/sanitize.js +0 -286
- package/dist/clients/scan-utils.js +0 -25
- package/dist/clients/scratch-tree-policy.js +0 -165
- package/dist/clients/search-read-registration.js +0 -94
- package/dist/clients/secret-findings.js +0 -114
- package/dist/clients/security-scan-client.js +0 -352
- package/dist/clients/session-event-guard.js +0 -297
- package/dist/clients/session-lifecycle.js +0 -484
- package/dist/clients/session-start-observability.js +0 -94
- package/dist/clients/session-state-store.js +0 -101
- package/dist/clients/session-summary.js +0 -15
- package/dist/clients/sessionstart-logger.js +0 -27
- package/dist/clients/sg-runner.js +0 -876
- package/dist/clients/sgconfig.js +0 -347
- package/dist/clients/shared-checkout-guard.js +0 -338
- package/dist/clients/single-flight.js +0 -158
- package/dist/clients/situational-tool-telemetry.js +0 -108
- package/dist/clients/skills-resolver.js +0 -141
- package/dist/clients/slow-fs.js +0 -138
- package/dist/clients/smells-rollup.js +0 -231
- package/dist/clients/source-filter.js +0 -596
- package/dist/clients/source-walker.js +0 -211
- package/dist/clients/spawn-output-cap.js +0 -120
- package/dist/clients/spawn-timeout-cooldown.js +0 -110
- package/dist/clients/stale-marker.js +0 -17
- package/dist/clients/startup-scan.js +0 -400
- package/dist/clients/startup-timing.js +0 -130
- package/dist/clients/string-utils.js +0 -33
- package/dist/clients/subagent-mode.js +0 -111
- package/dist/clients/symbol-containment.js +0 -24
- package/dist/clients/symbol-types.js +0 -5
- package/dist/clients/test-runner-client.js +0 -2507
- package/dist/clients/test-runner-delivery.js +0 -287
- package/dist/clients/todo-scanner.js +0 -229
- package/dist/clients/tool-agreement.js +0 -423
- package/dist/clients/tool-config.js +0 -249
- package/dist/clients/tool-cwd.js +0 -270
- package/dist/clients/tool-definition.js +0 -47
- package/dist/clients/tool-event.js +0 -105
- package/dist/clients/tool-policy.js +0 -2755
- package/dist/clients/tool-probe.js +0 -53
- package/dist/clients/tool-render.js +0 -156
- package/dist/clients/tool-set-policy.js +0 -118
- package/dist/clients/tree-sitter-cache.js +0 -364
- package/dist/clients/tree-sitter-client.js +0 -4195
- package/dist/clients/tree-sitter-logger.js +0 -100
- package/dist/clients/tree-sitter-navigator.js +0 -269
- package/dist/clients/tree-sitter-query-loader.js +0 -569
- package/dist/clients/tree-sitter-shared.js +0 -158
- package/dist/clients/tree-sitter-symbol-extractor.js +0 -1265
- package/dist/clients/trivy-client.js +0 -467
- package/dist/clients/tui-fit.js +0 -50
- package/dist/clients/turn-context.js +0 -52
- package/dist/clients/turn-end/lane.js +0 -51
- package/dist/clients/turn-end/lanes/govulncheck.js +0 -112
- package/dist/clients/turn-end/lanes/secrets.js +0 -204
- package/dist/clients/turn-summary-render.js +0 -72
- package/dist/clients/turn-summary.js +0 -132
- package/dist/clients/typos-config.js +0 -29
- package/dist/clients/user-notify.js +0 -51
- package/dist/clients/vanished-instance-marker.js +0 -57
- package/dist/clients/warm-attach.js +0 -305
- package/dist/clients/widget-state.js +0 -1808
- package/dist/clients/word-index-logger.js +0 -49
- package/dist/clients/word-index-store.js +0 -459
- package/dist/clients/word-index.js +0 -2080
- package/dist/clients/workspace-topology.js +0 -443
- package/dist/clients/write-ordering-guard.js +0 -65
- package/dist/clients/zizmor-config.js +0 -340
- package/dist/i18n.js +0 -69
- package/dist/mcp/build-staleness.js +0 -124
- package/dist/scripts/lib/process-scan.mjs +0 -583
- package/dist/scripts/lib/skills-predicate.mjs +0 -129
- package/dist/scripts/lib/web-tree-sitter-dir.mjs +0 -123
- package/dist/tools/activate-tools.js +0 -87
- package/dist/tools/ast-grep-outline.js +0 -137
- package/dist/tools/ast-grep-replace.js +0 -244
- package/dist/tools/ast-grep-search.js +0 -762
- package/dist/tools/effective-config.js +0 -90
- package/dist/tools/lens-diagnostic-mark.js +0 -375
- package/dist/tools/lens-diagnostics.js +0 -2571
- package/dist/tools/lsp-diagnostics.js +0 -1745
- package/dist/tools/lsp-navigation.js +0 -1367
- package/dist/tools/lsp-structured-output.js +0 -294
- package/dist/tools/module-report.js +0 -382
- package/dist/tools/project-report.js +0 -86
- package/dist/tools/render-compact.js +0 -374
- package/dist/tools/scan-progress.js +0 -53
- package/dist/tools/shared.js +0 -29
- package/dist/tools/symbol-search.js +0 -155
|
@@ -1,731 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AstGrep Client for pi-lens
|
|
3
|
-
*
|
|
4
|
-
* Structural code analysis using ast-grep CLI.
|
|
5
|
-
* Scans files against YAML rule definitions.
|
|
6
|
-
*
|
|
7
|
-
* Requires: npm install -D @ast-grep/cli
|
|
8
|
-
* Rules: ./rules/ directory
|
|
9
|
-
*/
|
|
10
|
-
import { createSubsystemLogger } from "./extension-log.js";
|
|
11
|
-
import * as fs from "node:fs";
|
|
12
|
-
import * as os from "node:os";
|
|
13
|
-
import * as path from "node:path";
|
|
14
|
-
import { AstGrepRuleManager, checkAstGrepRulesHealth, } from "./ast-grep-rule-manager.js";
|
|
15
|
-
import { reportBundledResourceDirHealth } from "./bundled-resource-health.js";
|
|
16
|
-
import { getDegradationLedgerGeneration } from "./degradation-ledger.js";
|
|
17
|
-
import { logLatency } from "./latency-logger.js";
|
|
18
|
-
import { getMutationBridge } from "./mutation-bridge.js";
|
|
19
|
-
import { resolvePackagePath } from "./package-root.js";
|
|
20
|
-
import { truncatedByOutputCap } from "./spawn-output-cap.js";
|
|
21
|
-
import { SgRunner, } from "./sg-runner.js";
|
|
22
|
-
/**
|
|
23
|
-
* #2636: `AstGrepClient`'s constructor falls back to the bundled `rules/`
|
|
24
|
-
* (`resolvePackagePath(import.meta.url, "rules")`) with no existence check
|
|
25
|
-
* when the project has none of its own — same managed-cache-relocation gap
|
|
26
|
-
* #2626 fixed for `skills/`. Purely observational: logs a `phase` record
|
|
27
|
-
* naming the resolved path + rule-description count on EVERY call that uses
|
|
28
|
-
* the bundled fallback (healthy or not, so an empty ledger is distinguishable
|
|
29
|
-
* from this never having run at all — #2626 review F5), and records a
|
|
30
|
-
* bounded `ast-grep-rules-dir-missing` degradation only when the bundled dir
|
|
31
|
-
* itself turns out absent, unreadable, or holds no `.yml` rule description.
|
|
32
|
-
* Called only when using the bundled fallback — never when the project
|
|
33
|
-
* provides its own `rules/` (a broken PROJECT override is a user config
|
|
34
|
-
* concern, not this bug's shape) — from `ensureRulesHealthReported` below,
|
|
35
|
-
* both at construction and again on the ledger's next generation (#2636
|
|
36
|
-
* review F3).
|
|
37
|
-
*/
|
|
38
|
-
function reportAstGrepRulesHealth(bundledRuleDir) {
|
|
39
|
-
const health = checkAstGrepRulesHealth(bundledRuleDir);
|
|
40
|
-
logLatency({
|
|
41
|
-
type: "phase",
|
|
42
|
-
phase: "ast_grep_rules_resolved",
|
|
43
|
-
filePath: bundledRuleDir,
|
|
44
|
-
durationMs: 0,
|
|
45
|
-
metadata: {
|
|
46
|
-
status: health.status,
|
|
47
|
-
entryCount: health.status === "healthy" ? health.entryCount : 0,
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
reportBundledResourceDirHealth("ast-grep-rules-dir-missing", bundledRuleDir, health, "ast-grep rule descriptions");
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Record an applied `ast_grep_replace` rewrite through the mutation bridge
|
|
54
|
-
* (#2423, acceptance criterion 3).
|
|
55
|
-
*
|
|
56
|
-
* ast-grep reports 0-based line numbers; the guard and the change log are
|
|
57
|
-
* 1-based, so every range is shifted by one. One record per FILE carries every
|
|
58
|
-
* range that file's matches covered, because the bridge's contract is
|
|
59
|
-
* per-file — the same shape a multi-hunk edit produces.
|
|
60
|
-
*
|
|
61
|
-
* Exported for tests: they drive it against a registered bridge instead of
|
|
62
|
-
* spawning ast-grep.
|
|
63
|
-
*/
|
|
64
|
-
function recordAstGrepApply(matches) {
|
|
65
|
-
const bridge = getMutationBridge();
|
|
66
|
-
if (!bridge || matches.length === 0)
|
|
67
|
-
return;
|
|
68
|
-
const rangesByFile = new Map();
|
|
69
|
-
for (const match of matches) {
|
|
70
|
-
const start = (match.range?.start?.line ?? 0) + 1;
|
|
71
|
-
const end = Math.max(start, (match.range?.end?.line ?? 0) + 1);
|
|
72
|
-
const existing = rangesByFile.get(match.file);
|
|
73
|
-
if (existing)
|
|
74
|
-
existing.push([start, end]);
|
|
75
|
-
else
|
|
76
|
-
rangesByFile.set(match.file, [[start, end]]);
|
|
77
|
-
}
|
|
78
|
-
for (const [filePath, editRanges] of rangesByFile) {
|
|
79
|
-
bridge.recordMutation({
|
|
80
|
-
filePath,
|
|
81
|
-
kind: "edit",
|
|
82
|
-
editRanges,
|
|
83
|
-
consumer: "ast_grep_replace",
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
// --- Client ---
|
|
88
|
-
function extractDebugAst(raw) {
|
|
89
|
-
const lines = raw.split(/\r?\n/);
|
|
90
|
-
const start = lines.findIndex((line) => /^Debug (?:A|C)ST:/.test(line.trim()));
|
|
91
|
-
if (start < 0)
|
|
92
|
-
return undefined;
|
|
93
|
-
const out = [];
|
|
94
|
-
for (const line of lines.slice(start + 1)) {
|
|
95
|
-
if (!line.trim())
|
|
96
|
-
break;
|
|
97
|
-
out.push(line);
|
|
98
|
-
}
|
|
99
|
-
return out.length > 0 ? out.join("\n") : undefined;
|
|
100
|
-
}
|
|
101
|
-
function lineStartOffsets(source) {
|
|
102
|
-
const offsets = [0];
|
|
103
|
-
for (let index = 0; index < source.length; index++) {
|
|
104
|
-
if (source.charCodeAt(index) === 10)
|
|
105
|
-
offsets.push(index + 1);
|
|
106
|
-
}
|
|
107
|
-
return offsets;
|
|
108
|
-
}
|
|
109
|
-
function snippetForRange(source, offsets, startLine0, startCol0, endLine0, endCol0) {
|
|
110
|
-
const start = (offsets[startLine0] ?? 0) + startCol0;
|
|
111
|
-
const end = (offsets[endLine0] ?? source.length) + endCol0;
|
|
112
|
-
const text = source.slice(start, end).replace(/\s+/g, " ").trim();
|
|
113
|
-
return text.length > 80 ? `${text.slice(0, 77)}...` : text;
|
|
114
|
-
}
|
|
115
|
-
const MAX_VALIDATE_PATTERN_CHARS = 20_000;
|
|
116
|
-
const MAX_VALIDATE_RULE_CHARS = 200_000;
|
|
117
|
-
const VALIDATION_SNIPPETS = {
|
|
118
|
-
bash: { ext: "sh", source: "echo pi_lens_validate\n" },
|
|
119
|
-
c: { ext: "c", source: "int main(void) { return 0; }\n" },
|
|
120
|
-
cpp: { ext: "cpp", source: "int main() { return 0; }\n" },
|
|
121
|
-
csharp: { ext: "cs", source: "class C { static void Main() {} }\n" },
|
|
122
|
-
css: { ext: "css", source: ".pi-lens { color: black; }\n" },
|
|
123
|
-
go: { ext: "go", source: "package main\nfunc main() {}\n" },
|
|
124
|
-
html: { ext: "html", source: "<main>pi-lens</main>\n" },
|
|
125
|
-
java: { ext: "java", source: "class Main { void run() {} }\n" },
|
|
126
|
-
javascript: { ext: "js", source: "const piLensValidate = 1;\n" },
|
|
127
|
-
json: { ext: "json", source: '{"piLensValidate":true}\n' },
|
|
128
|
-
kotlin: { ext: "kt", source: "fun main() {}\n" },
|
|
129
|
-
lua: { ext: "lua", source: "local pi_lens_validate = 1\n" },
|
|
130
|
-
php: { ext: "php", source: "<?php $piLensValidate = 1;\n" },
|
|
131
|
-
python: { ext: "py", source: "pi_lens_validate = 1\n" },
|
|
132
|
-
ruby: { ext: "rb", source: "pi_lens_validate = 1\n" },
|
|
133
|
-
rust: { ext: "rs", source: "fn main() {}\n" },
|
|
134
|
-
tsx: { ext: "tsx", source: "export function App() { return <div />; }\n" },
|
|
135
|
-
typescript: { ext: "ts", source: "const piLensValidate = 1;\n" },
|
|
136
|
-
yaml: { ext: "yaml", source: "piLensValidate: true\n" },
|
|
137
|
-
};
|
|
138
|
-
function validationSnippetFor(language) {
|
|
139
|
-
const key = language.toLowerCase().replace(/^"|"$/g, "");
|
|
140
|
-
return (VALIDATION_SNIPPETS[key] ?? {
|
|
141
|
-
ext: key.replace(/[^a-z0-9_-]/gi, "") || "txt",
|
|
142
|
-
source: "pi_lens_validate\n",
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
function validateInputShape(value, maxChars, label) {
|
|
146
|
-
if (value.includes("\0"))
|
|
147
|
-
return `${label} contains NUL bytes`;
|
|
148
|
-
if (value.length > maxChars) {
|
|
149
|
-
return `${label} is too large (${value.length} chars, max ${maxChars})`;
|
|
150
|
-
}
|
|
151
|
-
return undefined;
|
|
152
|
-
}
|
|
153
|
-
function stderrHasError(stderr) {
|
|
154
|
-
return stderr.split(/\r?\n/).some((line) => /^\s*(error|Error):/.test(line));
|
|
155
|
-
}
|
|
156
|
-
function formatDebugAst(tree, source) {
|
|
157
|
-
const offsets = lineStartOffsets(source);
|
|
158
|
-
return tree
|
|
159
|
-
.split(/\r\n|\n/)
|
|
160
|
-
.map((line) => {
|
|
161
|
-
const match = /^([ \t]*)([^ \t(][^(]*)? \((\d+),(\d+)\)-\((\d+),(\d+)\)$/.exec(line);
|
|
162
|
-
if (!match)
|
|
163
|
-
return line;
|
|
164
|
-
const [, indent = "", label = "", startLine, startCol, endLine, endCol] = match;
|
|
165
|
-
const sl = Number(startLine);
|
|
166
|
-
const sc = Number(startCol);
|
|
167
|
-
const el = Number(endLine);
|
|
168
|
-
const ec = Number(endCol);
|
|
169
|
-
const snippet = snippetForRange(source, offsets, sl, sc, el, ec);
|
|
170
|
-
return `${indent}${label} [${sl + 1},${sc + 1}] - [${el + 1},${ec + 1}] ${JSON.stringify(snippet)}`;
|
|
171
|
-
})
|
|
172
|
-
.join("\n");
|
|
173
|
-
}
|
|
174
|
-
export class AstGrepClient {
|
|
175
|
-
ruleDir;
|
|
176
|
-
log;
|
|
177
|
-
ruleManager;
|
|
178
|
-
runner;
|
|
179
|
-
// #2636 review F3/F7:
|
|
180
|
-
usingBundledRuleDirFallback;
|
|
181
|
-
rulesHealthReportedGeneration;
|
|
182
|
-
constructor(ruleDir, verbose = false) {
|
|
183
|
-
const projectRuleDir = path.join(process.cwd(), "rules");
|
|
184
|
-
// F7: ONE existsSync call, reused for both the fallback decision and the
|
|
185
|
-
// ruleDir choice — two separate calls let the directory appear (or a
|
|
186
|
-
// concurrent watcher/installer create it) between them, making
|
|
187
|
-
// `usingBundledRuleDirFallback` true while `this.ruleDir` ends up being
|
|
188
|
-
// the now-existing PROJECT dir: the health check would then classify a
|
|
189
|
-
// project override's own directory against `reportAstGrepRulesHealth`'s
|
|
190
|
-
// bundled-fallback doc contract.
|
|
191
|
-
const hasProjectRuleDir = fs.existsSync(projectRuleDir);
|
|
192
|
-
this.usingBundledRuleDirFallback = !ruleDir && !hasProjectRuleDir;
|
|
193
|
-
this.ruleDir =
|
|
194
|
-
ruleDir ||
|
|
195
|
-
(hasProjectRuleDir
|
|
196
|
-
? projectRuleDir
|
|
197
|
-
: resolvePackagePath(import.meta.url, "rules"));
|
|
198
|
-
this.log = verbose ? createSubsystemLogger("ast-grep") : () => { };
|
|
199
|
-
this.ensureRulesHealthReported();
|
|
200
|
-
this.ruleManager = new AstGrepRuleManager(this.ruleDir, this.log);
|
|
201
|
-
this.runner = new SgRunner(verbose);
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* #2636 review F3: `AstGrepClient` is a per-PROCESS singleton
|
|
205
|
-
* (`index.ts`/`mcp/server.ts`/`clients/mcp/session.ts` each construct it
|
|
206
|
-
* exactly once), but `resetDegradationLedger()` wipes the ledger's
|
|
207
|
-
* once-per-subject latch on EVERY `session_start`
|
|
208
|
-
* (`runtime-session.ts`'s `handleSessionStart`). A report that only ever
|
|
209
|
-
* fires at construction is therefore invisible after the first session
|
|
210
|
-
* boundary — `pilens_health` shows nothing for a bug that is still there
|
|
211
|
-
* (shape 17's inverse: `resolveSkillPaths`/`ruleFilesForLanguage` avoid
|
|
212
|
-
* this because pi calls them fresh per request, but `AstGrepClient` has
|
|
213
|
-
* no such per-request re-entry).
|
|
214
|
-
*
|
|
215
|
-
* Re-checked against the ledger's own generation counter at the START of
|
|
216
|
-
* every real scan entry point (`ensureAvailable`, called by every
|
|
217
|
-
* `tools/ast-grep-*`/`ast-dump` handler before doing any work) — the same
|
|
218
|
-
* pattern `clients/tree-sitter-client.ts`'s `refreshGrammarSessionLatches`
|
|
219
|
-
* uses for its own per-instance session latches, adapted here: the
|
|
220
|
-
* degradation ledger already re-arms its OWN once-per-subject dedup on
|
|
221
|
-
* reset, so this method only has to decide WHETHER to call
|
|
222
|
-
* `reportAstGrepRulesHealth` again, never re-implement the dedup itself.
|
|
223
|
-
*/
|
|
224
|
-
ensureRulesHealthReported() {
|
|
225
|
-
const generation = getDegradationLedgerGeneration();
|
|
226
|
-
if (this.rulesHealthReportedGeneration === generation)
|
|
227
|
-
return;
|
|
228
|
-
this.rulesHealthReportedGeneration = generation;
|
|
229
|
-
if (this.usingBundledRuleDirFallback) {
|
|
230
|
-
reportAstGrepRulesHealth(this.ruleDir);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Check if ast-grep CLI is available, auto-install if not
|
|
235
|
-
*/
|
|
236
|
-
ensureAvailable() {
|
|
237
|
-
this.ensureRulesHealthReported();
|
|
238
|
-
return this.runner.ensureAvailable();
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Replace using a raw YAML rule that includes a `fix:` field (Phase 3/4 of #125).
|
|
242
|
-
* Dry-run returns matches for preview; apply writes fixes to disk.
|
|
243
|
-
*/
|
|
244
|
-
async replaceWithRule(ruleYaml, paths, apply) {
|
|
245
|
-
const allMatches = [];
|
|
246
|
-
for (const scanPath of paths) {
|
|
247
|
-
if (apply) {
|
|
248
|
-
// Stale-preview check: dry-run first. Preserve CLI failures instead of
|
|
249
|
-
// treating an invalid rule as a stale, no-match preview.
|
|
250
|
-
const preCheck = await this.tempScanDetailed(scanPath, ruleYaml);
|
|
251
|
-
if (preCheck.failure || preCheck.error) {
|
|
252
|
-
return {
|
|
253
|
-
matches: allMatches,
|
|
254
|
-
totalMatches: allMatches.length,
|
|
255
|
-
applied: false,
|
|
256
|
-
error: preCheck.error ?? "ast-grep preview failed",
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
if (preCheck.matches.length === 0) {
|
|
260
|
-
return {
|
|
261
|
-
matches: [],
|
|
262
|
-
totalMatches: 0,
|
|
263
|
-
applied: false,
|
|
264
|
-
stalePreview: true,
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
const result = await this.runner.tempScanWithFixAsync(scanPath, "agent-rule", ruleYaml, apply);
|
|
269
|
-
if (result.error) {
|
|
270
|
-
return {
|
|
271
|
-
matches: allMatches,
|
|
272
|
-
totalMatches: allMatches.length,
|
|
273
|
-
applied: false,
|
|
274
|
-
error: result.error,
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
allMatches.push(...result.matches);
|
|
278
|
-
}
|
|
279
|
-
return {
|
|
280
|
-
matches: allMatches,
|
|
281
|
-
totalMatches: allMatches.length,
|
|
282
|
-
applied: apply,
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Search using a raw YAML rule (Phase 4 of #125).
|
|
287
|
-
* Routes through sg scan --config rather than sg run -p.
|
|
288
|
-
* Each path is scanned independently; results are merged.
|
|
289
|
-
*/
|
|
290
|
-
async tempScanDetailed(dir, ruleYaml, options = {}) {
|
|
291
|
-
// SAFETY: keep tests and older embedders that replace the runner with the
|
|
292
|
-
// historic match-only seam working. The cast only makes
|
|
293
|
-
// `tempScanDetailedAsync` OPTIONAL on the runner surface — it claims
|
|
294
|
-
// nothing about the method existing. The call site below checks for it
|
|
295
|
-
// before invoking, and the production SgRunner always has it, so a
|
|
296
|
-
// failure there cannot be mistaken for an empty result.
|
|
297
|
-
const detailed = this.runner.tempScanDetailedAsync;
|
|
298
|
-
if (detailed) {
|
|
299
|
-
return detailed.call(this.runner, dir, "agent-rule", ruleYaml, 30_000, options);
|
|
300
|
-
}
|
|
301
|
-
const matches = await this.runner.tempScanAsync(dir, "agent-rule", ruleYaml, 30_000, options);
|
|
302
|
-
return { matches, status: 0 };
|
|
303
|
-
}
|
|
304
|
-
async searchWithRule(ruleYaml, paths, options = {}) {
|
|
305
|
-
const allMatches = [];
|
|
306
|
-
for (const scanPath of paths) {
|
|
307
|
-
try {
|
|
308
|
-
const results = await this.tempScanDetailed(scanPath, ruleYaml, options);
|
|
309
|
-
if (results.failure || results.error) {
|
|
310
|
-
return {
|
|
311
|
-
matches: allMatches,
|
|
312
|
-
totalMatches: allMatches.length,
|
|
313
|
-
error: results.error ||
|
|
314
|
-
`ast-grep scan failed (${results.failure ?? "unknown failure"})`,
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
allMatches.push(...results.matches);
|
|
318
|
-
}
|
|
319
|
-
catch (err) {
|
|
320
|
-
return {
|
|
321
|
-
matches: allMatches,
|
|
322
|
-
totalMatches: allMatches.length,
|
|
323
|
-
error: String(err),
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return { matches: allMatches, totalMatches: allMatches.length };
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Dump the parsed tree-sitter AST for a snippet using ast-grep CLI.
|
|
331
|
-
*/
|
|
332
|
-
async dumpAst(source, lang, options = {}) {
|
|
333
|
-
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-lens-ast-dump-"));
|
|
334
|
-
const tmpFile = path.join(tmpDir, `snippet.${lang.replace(/[^a-z0-9_-]/gi, "") || "txt"}`);
|
|
335
|
-
try {
|
|
336
|
-
fs.writeFileSync(tmpFile, source, "utf-8");
|
|
337
|
-
const mode = options.includeAnonymous ? "cst" : "ast";
|
|
338
|
-
const result = await this.runner.execRaw([
|
|
339
|
-
"run",
|
|
340
|
-
"--lang",
|
|
341
|
-
lang,
|
|
342
|
-
"-p",
|
|
343
|
-
source,
|
|
344
|
-
`--debug-query=${mode}`,
|
|
345
|
-
tmpFile,
|
|
346
|
-
]);
|
|
347
|
-
const raw = result.stderr || result.stdout;
|
|
348
|
-
const tree = extractDebugAst(raw);
|
|
349
|
-
if (tree)
|
|
350
|
-
return { output: formatDebugAst(tree, source) };
|
|
351
|
-
return {
|
|
352
|
-
error: result.error ||
|
|
353
|
-
result.stderr.trim() ||
|
|
354
|
-
result.stdout.trim() ||
|
|
355
|
-
`ast-grep did not return a debug AST for language ${lang}`,
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
finally {
|
|
359
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
async validatePattern(pattern, lang, options) {
|
|
363
|
-
const shapeError = validateInputShape(pattern, MAX_VALIDATE_PATTERN_CHARS, "pattern");
|
|
364
|
-
if (shapeError)
|
|
365
|
-
return { valid: false, error: shapeError };
|
|
366
|
-
const snippet = validationSnippetFor(lang);
|
|
367
|
-
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-lens-sg-validate-"));
|
|
368
|
-
const tmpFile = path.join(tmpDir, `snippet.${snippet.ext}`);
|
|
369
|
-
try {
|
|
370
|
-
fs.writeFileSync(tmpFile, snippet.source, "utf-8");
|
|
371
|
-
const args = ["run", "-p", pattern, "--lang", lang, "--json=compact"];
|
|
372
|
-
if (options?.selector)
|
|
373
|
-
args.push("--selector", options.selector);
|
|
374
|
-
if (options?.strictness)
|
|
375
|
-
args.push("--strictness", options.strictness);
|
|
376
|
-
args.push(tmpFile);
|
|
377
|
-
const result = await this.runner.execRaw(args, 10_000, options);
|
|
378
|
-
const stderr = result.stderr.trim();
|
|
379
|
-
const stdout = result.stdout.trim();
|
|
380
|
-
// FIRST (#2100): hitting `execRaw`'s cap SIGTERMs ast-grep, so a
|
|
381
|
-
// truncated run also carries the kill's error message. Read after the
|
|
382
|
-
// two checks below, this guard could only ever describe a run that
|
|
383
|
-
// exited before the signal reached it. `execRaw` re-spells `failure`
|
|
384
|
-
// in its own vocabulary but keeps the timeout/aborted spellings, so
|
|
385
|
-
// those runs still fall through to the error branch below.
|
|
386
|
-
if (truncatedByOutputCap(result)) {
|
|
387
|
-
return {
|
|
388
|
-
valid: false,
|
|
389
|
-
error: "ast-grep validation output was truncated",
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
if (result.error)
|
|
393
|
-
return { valid: false, error: result.error };
|
|
394
|
-
if (result.status !== 0 && !(result.status === 1 && !stderr)) {
|
|
395
|
-
return {
|
|
396
|
-
valid: false,
|
|
397
|
-
error: stderr ||
|
|
398
|
-
`ast-grep validation failed with exit code ${result.status}`,
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
if (stderrHasError(stderr))
|
|
402
|
-
return { valid: false, error: stderr };
|
|
403
|
-
const warning = stderr || stdout || undefined;
|
|
404
|
-
return {
|
|
405
|
-
valid: true,
|
|
406
|
-
...(warning ? { warning } : {}),
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
finally {
|
|
410
|
-
try {
|
|
411
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
412
|
-
}
|
|
413
|
-
catch {
|
|
414
|
-
// Best-effort cleanup; never mask the validation result.
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
async validateRule(ruleYaml, options = {}) {
|
|
419
|
-
const shapeError = validateInputShape(ruleYaml, MAX_VALIDATE_RULE_CHARS, "rule");
|
|
420
|
-
if (shapeError)
|
|
421
|
-
return { valid: false, error: shapeError };
|
|
422
|
-
const language = /^\s*language:\s*([^\s#]+)/im.exec(ruleYaml)?.[1] ?? "typescript";
|
|
423
|
-
const snippet = validationSnippetFor(language);
|
|
424
|
-
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-lens-sg-rule-"));
|
|
425
|
-
try {
|
|
426
|
-
fs.writeFileSync(path.join(tmpDir, `snippet.${snippet.ext}`), snippet.source, "utf-8");
|
|
427
|
-
const result = await this.tempScanDetailed(tmpDir, ruleYaml, options);
|
|
428
|
-
if (result.failure || result.error) {
|
|
429
|
-
return {
|
|
430
|
-
valid: false,
|
|
431
|
-
error: result.error ||
|
|
432
|
-
`ast-grep rule validation failed (${result.failure ?? "unknown failure"})`,
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
return { valid: true };
|
|
436
|
-
}
|
|
437
|
-
catch (err) {
|
|
438
|
-
return { valid: false, error: String(err) };
|
|
439
|
-
}
|
|
440
|
-
finally {
|
|
441
|
-
try {
|
|
442
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
443
|
-
}
|
|
444
|
-
catch {
|
|
445
|
-
// Best-effort cleanup; never mask the validation result.
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
/**
|
|
450
|
-
* Syntax-only code outline via `ast-grep outline` (#311) — symbols, imports,
|
|
451
|
-
* exports, and members for file or directory input. Raw, fast, no index/LSP;
|
|
452
|
-
* complements module_report (which adds the cached graph's who-uses-this,
|
|
453
|
-
* complexity, and blast radius). Returns parsed JSON; args go through
|
|
454
|
-
* `execRaw` (execFile-style, no shell), so no interpolation risk.
|
|
455
|
-
*/
|
|
456
|
-
async outline(paths, options = {}) {
|
|
457
|
-
if (paths.length === 0)
|
|
458
|
-
return { error: "no paths provided" };
|
|
459
|
-
const args = ["outline", "--json=compact", "--color", "never"];
|
|
460
|
-
if (options.lang)
|
|
461
|
-
args.push("--lang", options.lang);
|
|
462
|
-
if (options.items)
|
|
463
|
-
args.push("--items", options.items);
|
|
464
|
-
if (options.view)
|
|
465
|
-
args.push("--view", options.view);
|
|
466
|
-
if (options.types?.length)
|
|
467
|
-
args.push("--type", options.types.join(","));
|
|
468
|
-
if (options.match)
|
|
469
|
-
args.push("--match", options.match);
|
|
470
|
-
if (options.pubMembers)
|
|
471
|
-
args.push("--pub-members");
|
|
472
|
-
for (const glob of options.globs ?? [])
|
|
473
|
-
args.push("--globs", glob);
|
|
474
|
-
args.push(...paths);
|
|
475
|
-
const result = await this.runner.execRaw(args);
|
|
476
|
-
const raw = (result.stdout ?? "").trim();
|
|
477
|
-
if (!raw) {
|
|
478
|
-
return {
|
|
479
|
-
error: result.error ||
|
|
480
|
-
result.stderr?.trim() ||
|
|
481
|
-
"ast-grep outline returned no output",
|
|
482
|
-
};
|
|
483
|
-
}
|
|
484
|
-
try {
|
|
485
|
-
return { output: JSON.parse(raw) };
|
|
486
|
-
}
|
|
487
|
-
catch (err) {
|
|
488
|
-
return {
|
|
489
|
-
error: `failed to parse ast-grep outline JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
490
|
-
};
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
/**
|
|
494
|
-
* Search for AST patterns in files
|
|
495
|
-
*/
|
|
496
|
-
async search(pattern, lang, paths, options) {
|
|
497
|
-
const args = ["run", "-p", pattern, "--lang", lang, "--json=compact"];
|
|
498
|
-
if (options?.selector) {
|
|
499
|
-
args.push("--selector", options.selector);
|
|
500
|
-
}
|
|
501
|
-
if (options?.context !== undefined) {
|
|
502
|
-
args.push("--context", String(options.context));
|
|
503
|
-
}
|
|
504
|
-
if (options?.strictness) {
|
|
505
|
-
args.push("--strictness", options.strictness);
|
|
506
|
-
}
|
|
507
|
-
args.push(...paths);
|
|
508
|
-
const result = await this.runner.exec(args, options);
|
|
509
|
-
return {
|
|
510
|
-
matches: result.matches,
|
|
511
|
-
totalMatches: result.totalMatches,
|
|
512
|
-
truncated: result.truncated,
|
|
513
|
-
error: result.error,
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
/**
|
|
517
|
-
* Search and replace AST patterns
|
|
518
|
-
*/
|
|
519
|
-
async replace(pattern, rewrite, lang, paths, apply = false, options) {
|
|
520
|
-
const baseArgs = ["run", "-p", pattern, "-r", rewrite, "--lang", lang];
|
|
521
|
-
if (options?.strictness) {
|
|
522
|
-
baseArgs.push("--strictness", options.strictness);
|
|
523
|
-
}
|
|
524
|
-
if (!apply) {
|
|
525
|
-
// Dry-run: --json=compact shows what would change without writing
|
|
526
|
-
const result = await this.runner.exec([
|
|
527
|
-
...baseArgs,
|
|
528
|
-
"--json=compact",
|
|
529
|
-
...paths,
|
|
530
|
-
]);
|
|
531
|
-
return {
|
|
532
|
-
matches: result.matches,
|
|
533
|
-
totalMatches: result.totalMatches,
|
|
534
|
-
truncated: result.truncated,
|
|
535
|
-
applied: false,
|
|
536
|
-
error: result.error,
|
|
537
|
-
};
|
|
538
|
-
}
|
|
539
|
-
// Stale-preview check: re-run dry-run before writing.
|
|
540
|
-
// If the pattern no longer matches, the files changed since the preview.
|
|
541
|
-
const preCheck = await this.runner.exec([
|
|
542
|
-
...baseArgs,
|
|
543
|
-
"--json=compact",
|
|
544
|
-
...paths,
|
|
545
|
-
]);
|
|
546
|
-
if (preCheck.error) {
|
|
547
|
-
return {
|
|
548
|
-
matches: [],
|
|
549
|
-
totalMatches: 0,
|
|
550
|
-
truncated: false,
|
|
551
|
-
applied: false,
|
|
552
|
-
error: preCheck.error,
|
|
553
|
-
};
|
|
554
|
-
}
|
|
555
|
-
if (preCheck.matches.length === 0) {
|
|
556
|
-
return {
|
|
557
|
-
matches: [],
|
|
558
|
-
totalMatches: 0,
|
|
559
|
-
truncated: false,
|
|
560
|
-
applied: false,
|
|
561
|
-
stalePreview: true,
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
|
-
// Apply: --update-all writes the files. We do NOT recount afterwards —
|
|
565
|
-
// the original pattern no longer matches post-rewrite, and searching for
|
|
566
|
-
// the rewrite as a pattern is unreliable (multi-line rewrites and
|
|
567
|
-
// metavariable substitutions don't round-trip into a valid search
|
|
568
|
-
// pattern, yielding a false "0 matches" even on a successful apply).
|
|
569
|
-
// preCheck above already captured exactly what matched and was rewritten.
|
|
570
|
-
const applyResult = await this.runner.exec([
|
|
571
|
-
...baseArgs,
|
|
572
|
-
"--update-all",
|
|
573
|
-
...paths,
|
|
574
|
-
]);
|
|
575
|
-
if (applyResult.error) {
|
|
576
|
-
return {
|
|
577
|
-
matches: [],
|
|
578
|
-
totalMatches: 0,
|
|
579
|
-
truncated: false,
|
|
580
|
-
applied: false,
|
|
581
|
-
error: applyResult.error,
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
// #2423: `--update-all` just rewrote these files, and no `tool_result`
|
|
585
|
-
// describes it — pi-lens's own tool was as invisible to the mutation
|
|
586
|
-
// bookkeeping as any third-party one. Record each rewritten file through
|
|
587
|
-
// the same seam an extension would use. Fire-and-forget: the bridge never
|
|
588
|
-
// throws, and a missing bridge (pi-lens not activated, guard disabled) is
|
|
589
|
-
// a silent no-op.
|
|
590
|
-
recordAstGrepApply(preCheck.matches);
|
|
591
|
-
return {
|
|
592
|
-
matches: preCheck.matches,
|
|
593
|
-
totalMatches: preCheck.totalMatches,
|
|
594
|
-
truncated: preCheck.truncated,
|
|
595
|
-
applied: true,
|
|
596
|
-
error: undefined,
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Run a one-off scan with a temporary rule and configuration
|
|
601
|
-
*/
|
|
602
|
-
async runTempScanAsync(dir, ruleId, ruleYaml, timeout = 30000) {
|
|
603
|
-
if (!(await this.ensureAvailable()))
|
|
604
|
-
return [];
|
|
605
|
-
return this.runner.tempScanAsync(dir, ruleId, ruleYaml, timeout);
|
|
606
|
-
}
|
|
607
|
-
/**
|
|
608
|
-
* Find similar functions by comparing normalized AST structure
|
|
609
|
-
*/
|
|
610
|
-
async findSimilarFunctions(dir, lang = "typescript") {
|
|
611
|
-
const ruleYaml = `id: find-functions
|
|
612
|
-
language: ${lang}
|
|
613
|
-
rule:
|
|
614
|
-
kind: function_declaration
|
|
615
|
-
severity: info
|
|
616
|
-
message: found
|
|
617
|
-
`;
|
|
618
|
-
const matches = await this.runTempScanAsync(dir, "find-functions", ruleYaml);
|
|
619
|
-
if (matches.length === 0)
|
|
620
|
-
return [];
|
|
621
|
-
return this.groupSimilarFunctions(matches);
|
|
622
|
-
}
|
|
623
|
-
groupSimilarFunctions(matches) {
|
|
624
|
-
const grouped = new Map();
|
|
625
|
-
for (const item of matches) {
|
|
626
|
-
const name = this.extractFunctionName(item.text);
|
|
627
|
-
if (!name)
|
|
628
|
-
continue;
|
|
629
|
-
const signature = this.normalizeFunction(item.text);
|
|
630
|
-
const line = (item.range?.start?.line || item.labels?.[0]?.range?.start?.line || 0) +
|
|
631
|
-
1;
|
|
632
|
-
const group = grouped.get(signature) ?? [];
|
|
633
|
-
group.push({ name, file: item.file, line });
|
|
634
|
-
grouped.set(signature, group);
|
|
635
|
-
}
|
|
636
|
-
return Array.from(grouped.entries())
|
|
637
|
-
.filter(([, functions]) => functions.length > 1)
|
|
638
|
-
.map(([pattern, functions]) => ({ pattern, functions }));
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Extract function name from match text
|
|
642
|
-
*/
|
|
643
|
-
extractFunctionName(text) {
|
|
644
|
-
return text.match(/function\s+(\w+)/)?.[1] ?? null;
|
|
645
|
-
}
|
|
646
|
-
normalizeFunction(text) {
|
|
647
|
-
const normalizedText = text
|
|
648
|
-
.replace(/function\s+\w+/, "function FN")
|
|
649
|
-
.replace(/\bconst\b|\blet\b|\bvar\b/g, "VAR")
|
|
650
|
-
.replace(/["'].*?["']/g, "STR")
|
|
651
|
-
.replace(/`[^`]*`/g, "TMPL")
|
|
652
|
-
.replace(/\b\d+\b/g, "NUM")
|
|
653
|
-
.replace(/\btrue\b|\bfalse\b/g, "BOOL")
|
|
654
|
-
.replace(/\/\/.*/g, "")
|
|
655
|
-
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
656
|
-
.replace(/\s+/g, " ")
|
|
657
|
-
.trim();
|
|
658
|
-
// Extract just the body structure
|
|
659
|
-
const bodyMatch = normalizedText.match(/\{(.*)\}/);
|
|
660
|
-
const body = bodyMatch ? bodyMatch[1].trim() : normalizedText;
|
|
661
|
-
// Use first 200 chars as signature
|
|
662
|
-
return body.slice(0, 200);
|
|
663
|
-
}
|
|
664
|
-
/**
|
|
665
|
-
* Scan for exported function names in a directory
|
|
666
|
-
*/
|
|
667
|
-
async scanExports(dir, lang = "typescript") {
|
|
668
|
-
const exports = new Map();
|
|
669
|
-
const ruleYaml = `id: find-functions
|
|
670
|
-
language: ${lang}
|
|
671
|
-
rule:
|
|
672
|
-
kind: function_declaration
|
|
673
|
-
severity: info
|
|
674
|
-
message: found
|
|
675
|
-
`;
|
|
676
|
-
const matches = await this.runTempScanAsync(dir, "find-functions", ruleYaml, 15000);
|
|
677
|
-
this.log(`scanExports output length: ${matches.length}`);
|
|
678
|
-
for (const item of matches) {
|
|
679
|
-
const text = item.text || "";
|
|
680
|
-
const nameMatch = text.match(/function\s+(\w+)/);
|
|
681
|
-
if (nameMatch?.[1]) {
|
|
682
|
-
this.log(`scanExports found: ${nameMatch[1]} in ${item.file}`);
|
|
683
|
-
exports.set(nameMatch[1], item.file);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
return exports;
|
|
687
|
-
}
|
|
688
|
-
formatMatches(matches, isDryRun = false, showModeIndicator = false, maxItems = 50) {
|
|
689
|
-
return this.runner.formatMatches(matches, isDryRun, maxItems, showModeIndicator);
|
|
690
|
-
}
|
|
691
|
-
/**
|
|
692
|
-
* Format diagnostics for LLM consumption
|
|
693
|
-
*/
|
|
694
|
-
formatDiagnostics(diags) {
|
|
695
|
-
if (diags.length === 0)
|
|
696
|
-
return "";
|
|
697
|
-
const errors = diags.filter((d) => d.severity === "error");
|
|
698
|
-
const warnings = diags.filter((d) => d.severity === "warning");
|
|
699
|
-
const infos = diags.filter((d) => d.severity === "info");
|
|
700
|
-
const hints = diags.filter((d) => d.severity === "hint");
|
|
701
|
-
let output = `[ast-grep] ${diags.length} structural issue(s)`;
|
|
702
|
-
if (errors.length)
|
|
703
|
-
output += ` — ${errors.length} error(s)`;
|
|
704
|
-
if (warnings.length)
|
|
705
|
-
output += ` — ${warnings.length} warning(s)`;
|
|
706
|
-
if (infos.length)
|
|
707
|
-
output += ` — ${infos.length} info(s)`;
|
|
708
|
-
if (hints.length)
|
|
709
|
-
output += ` — ${hints.length} hint(s)`;
|
|
710
|
-
output += ":\n";
|
|
711
|
-
for (const d of diags.slice(0, 10)) {
|
|
712
|
-
const loc = d.line === d.endLine ? `L${d.line}` : `L${d.line}-${d.endLine}`;
|
|
713
|
-
const ruleInfo = d.ruleDescription
|
|
714
|
-
? `${d.rule}: ${d.ruleDescription.message}`
|
|
715
|
-
: d.rule;
|
|
716
|
-
const fix = d.fix || d.ruleDescription?.note ? " [fixable]" : "";
|
|
717
|
-
output += ` ${ruleInfo} (${loc})${fix}\n`;
|
|
718
|
-
if (d.ruleDescription?.note) {
|
|
719
|
-
const shortNote = d.ruleDescription.note.split(/\r?\n/)[0];
|
|
720
|
-
output += ` → ${shortNote}\n`;
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
if (diags.length > 10) {
|
|
724
|
-
output += ` ... and ${diags.length - 10} more\n`;
|
|
725
|
-
}
|
|
726
|
-
return output;
|
|
727
|
-
}
|
|
728
|
-
getRuleDescription(ruleId) {
|
|
729
|
-
return this.ruleManager.loadRuleDescriptions().get(ruleId);
|
|
730
|
-
}
|
|
731
|
-
}
|