@herbertgao/pi-extensions 2026.10.0 → 2026.10.2
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 +16 -12
- package/THIRD_PARTY_NOTICES.md +3 -3
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +2 -2
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +2 -2
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +1 -1
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-help.md +1 -1
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +2 -2
- package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +1 -1
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/index.js +4 -0
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail-frontmatter.cjs +43 -3
- package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail.mjs +142 -59
- package/node_modules/@dietrichgebert/ponytail/.qoder/rules/ponytail.md +21 -21
- package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +1 -1
- package/node_modules/@dietrichgebert/ponytail/AGENTS.md +21 -21
- package/node_modules/@dietrichgebert/ponytail/README.md +52 -242
- package/node_modules/@dietrichgebert/ponytail/hooks/claude-codex-hooks.json +3 -3
- package/node_modules/@dietrichgebert/ponytail/hooks/copilot-hooks.json +4 -4
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +70 -16
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-config.js +8 -7
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-instructions.js +30 -30
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-map.js +103 -0
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-mode-tracker.js +46 -23
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-runtime.js +39 -7
- package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-subagent.js +20 -3
- package/node_modules/@dietrichgebert/ponytail/hooks/qoder-hooks.json +3 -3
- package/node_modules/@dietrichgebert/ponytail/package.json +3 -3
- package/node_modules/@dietrichgebert/ponytail/pi-extension/index.js +47 -17
- package/node_modules/@dietrichgebert/ponytail/scripts/uninstall.js +21 -7
- package/node_modules/@dietrichgebert/ponytail/skills/plugin.json +5 -0
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail/SKILL.md +33 -101
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +89 -27
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +13 -12
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +21 -18
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +12 -13
- package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +96 -52
- package/node_modules/@herbertgao/pi-agency/LICENSE +21 -0
- package/node_modules/@herbertgao/pi-agency/README.md +40 -0
- package/node_modules/@herbertgao/pi-agency/package.json +53 -0
- package/node_modules/@herbertgao/pi-agency/src/index.ts +441 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +12 -12
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +30 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +15 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +27 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/codemode.ts +4 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +2 -2
- package/node_modules/@narumitw/pi-caffeinate/package.json +4 -4
- package/node_modules/@tifan/pi-mermaid-open/package.json +5 -1
- package/node_modules/@tifan/pi-mermaid-open/src/index.ts +26 -9
- package/node_modules/@tifan/pi-recap/package.json +1 -1
- package/node_modules/@tifan/pi-recap/src/index.ts +104 -20
- package/node_modules/@tifan/pi-recap/src/models.ts +46 -4
- package/node_modules/pi-antigravity/README.md +23 -2
- package/node_modules/pi-antigravity/package.json +5 -3
- package/node_modules/pi-antigravity/src/diagnostics/diagnostics.ts +3 -2
- package/node_modules/pi-antigravity/src/features/generate-image.ts +72 -0
- package/node_modules/pi-antigravity/src/features/google-search.ts +71 -0
- package/node_modules/pi-antigravity/src/image/image.ts +86 -47
- package/node_modules/pi-antigravity/src/image/native.ts +69 -0
- package/node_modules/pi-antigravity/src/index.ts +52 -137
- package/node_modules/pi-antigravity/src/search/search.ts +130 -31
- package/node_modules/pi-antigravity/src/stream/stream.ts +162 -113
- package/node_modules/pi-antigravity/src/types/enums.ts +1 -0
- package/node_modules/pi-antigravity/src/types/types.ts +1 -1
- package/node_modules/pi-antigravity/src/utils/security.ts +47 -1
- package/node_modules/pi-antigravity/src/utils/util.ts +38 -6
- package/node_modules/pi-lens/CHANGELOG.md +1064 -0
- package/node_modules/pi-lens/README.md +115 -25
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +6 -2
- package/node_modules/pi-lens/dist/chunk-22AVIGXS.js +560 -0
- package/node_modules/pi-lens/dist/chunk-27BBHSZC.js +106 -0
- package/node_modules/pi-lens/dist/chunk-2BEMIWEW.js +51 -0
- package/node_modules/pi-lens/dist/chunk-2EECBNC5.js +89 -0
- package/node_modules/pi-lens/dist/chunk-34U7PLGE.js +23 -0
- package/node_modules/pi-lens/dist/chunk-3I5QFT3N.js +181 -0
- package/node_modules/pi-lens/dist/chunk-3MED75HT.js +37 -0
- package/node_modules/pi-lens/dist/chunk-47D2BO4S.js +87 -0
- package/node_modules/pi-lens/dist/chunk-4RERDEXR.js +348 -0
- package/node_modules/pi-lens/dist/chunk-4W2PLC4J.js +27 -0
- package/node_modules/pi-lens/dist/chunk-52H5B5TC.js +202 -0
- package/node_modules/pi-lens/dist/chunk-54B42YRX.js +27 -0
- package/node_modules/pi-lens/dist/chunk-5RXBNSW2.js +266 -0
- package/node_modules/pi-lens/dist/chunk-5THXD6X5.js +201 -0
- package/node_modules/pi-lens/dist/chunk-5W3R6LFT.js +24 -0
- package/node_modules/pi-lens/dist/chunk-5ZEJHV35.js +341 -0
- package/node_modules/pi-lens/dist/chunk-6P62QVEA.js +118 -0
- package/node_modules/pi-lens/dist/chunk-6QIUX4EP.js +459 -0
- package/node_modules/pi-lens/dist/chunk-6VCD4VKZ.js +78 -0
- package/node_modules/pi-lens/dist/chunk-7F72PXY2.js +326 -0
- package/node_modules/pi-lens/dist/chunk-7FBF7NPR.js +998 -0
- package/node_modules/pi-lens/dist/chunk-7U2IDNXN.js +37 -0
- package/node_modules/pi-lens/dist/chunk-ABBOA7UD.js +157 -0
- package/node_modules/pi-lens/dist/chunk-AHDW3GPE.js +50 -0
- package/node_modules/pi-lens/dist/chunk-AJ3QXTRQ.js +756 -0
- package/node_modules/pi-lens/dist/chunk-AJVLWNFN.js +1610 -0
- package/node_modules/pi-lens/dist/chunk-AJXODZY6.js +112 -0
- package/node_modules/pi-lens/dist/chunk-ARFCXG7S.js +84 -0
- package/node_modules/pi-lens/dist/chunk-AS44CFQ4.js +708 -0
- package/node_modules/pi-lens/dist/chunk-AWE5TMPO.js +38 -0
- package/node_modules/pi-lens/dist/chunk-B3I2UUT4.js +4692 -0
- package/node_modules/pi-lens/dist/chunk-BRJKOBZP.js +331 -0
- package/node_modules/pi-lens/dist/chunk-BW5KFIQC.js +59 -0
- package/node_modules/pi-lens/dist/chunk-C2AUYXQH.js +149 -0
- package/node_modules/pi-lens/dist/chunk-CGGAIP7J.js +29 -0
- package/node_modules/pi-lens/dist/chunk-D6QS3U6M.js +30 -0
- package/node_modules/pi-lens/dist/chunk-DFVMIKMQ.js +349 -0
- package/node_modules/pi-lens/dist/chunk-DIULIWKU.js +169 -0
- package/node_modules/pi-lens/dist/chunk-DQ2NZ7C4.js +2317 -0
- package/node_modules/pi-lens/dist/chunk-E2WFBRHM.js +213 -0
- package/node_modules/pi-lens/dist/chunk-E4MAEDPM.js +50 -0
- package/node_modules/pi-lens/dist/chunk-EOKRQ3SA.js +30 -0
- package/node_modules/pi-lens/dist/chunk-F3AU2TMM.js +2626 -0
- package/node_modules/pi-lens/dist/chunk-F3P7VQ7H.js +170 -0
- package/node_modules/pi-lens/dist/chunk-FC4RP4I2.js +12 -0
- package/node_modules/pi-lens/dist/chunk-FJNKANOS.js +32 -0
- package/node_modules/pi-lens/dist/chunk-GUOGVTCQ.js +146 -0
- package/node_modules/pi-lens/dist/chunk-GVXA6CCE.js +18 -0
- package/node_modules/pi-lens/dist/chunk-HHYAELLJ.js +2334 -0
- package/node_modules/pi-lens/dist/chunk-HMFXILPV.js +83 -0
- package/node_modules/pi-lens/dist/chunk-HVUZXSWK.js +421 -0
- package/node_modules/pi-lens/dist/chunk-HWBZIGMJ.js +62 -0
- package/node_modules/pi-lens/dist/chunk-I3R7GKDR.js +17 -0
- package/node_modules/pi-lens/dist/chunk-I7SPGOWI.js +55 -0
- package/node_modules/pi-lens/dist/chunk-IIXOAGHR.js +38 -0
- package/node_modules/pi-lens/dist/chunk-IVP5KAB7.js +2250 -0
- package/node_modules/pi-lens/dist/chunk-IXEBJSUE.js +22 -0
- package/node_modules/pi-lens/dist/chunk-JOLITGCC.js +27 -0
- package/node_modules/pi-lens/dist/chunk-K6VYLB2U.js +145 -0
- package/node_modules/pi-lens/dist/chunk-LJDODBBZ.js +78 -0
- package/node_modules/pi-lens/dist/chunk-LNAKEO63.js +78 -0
- package/node_modules/pi-lens/dist/chunk-LSMJ6KBE.js +4139 -0
- package/node_modules/pi-lens/dist/chunk-LW6XKDZQ.js +5565 -0
- package/node_modules/pi-lens/dist/chunk-N3YQJI6O.js +899 -0
- package/node_modules/pi-lens/dist/chunk-NABLC7W3.js +148 -0
- package/node_modules/pi-lens/dist/chunk-NKOUFPQF.js +659 -0
- package/node_modules/pi-lens/dist/chunk-NL5GLMFI.js +211 -0
- package/node_modules/pi-lens/dist/chunk-NMABWBZN.js +327 -0
- package/node_modules/pi-lens/dist/chunk-NTHH2J74.js +27 -0
- package/node_modules/pi-lens/dist/chunk-NTUJEGDZ.js +59 -0
- package/node_modules/pi-lens/dist/chunk-NXL4FFQQ.js +47 -0
- package/node_modules/pi-lens/dist/chunk-NXPS2L6U.js +466 -0
- package/node_modules/pi-lens/dist/chunk-O5WILGMI.js +42 -0
- package/node_modules/pi-lens/dist/chunk-O6TQT6RI.js +48 -0
- package/node_modules/pi-lens/dist/chunk-OAXNDZJ7.js +323 -0
- package/node_modules/pi-lens/dist/chunk-ODEEOXPH.js +44 -0
- package/node_modules/pi-lens/dist/chunk-OQGFCZJ4.js +4533 -0
- package/node_modules/pi-lens/dist/chunk-ORTMY4Q4.js +282 -0
- package/node_modules/pi-lens/dist/chunk-OS32RNR2.js +442 -0
- package/node_modules/pi-lens/dist/chunk-PAK6IDME.js +189 -0
- package/node_modules/pi-lens/dist/chunk-PWFHBTSF.js +406 -0
- package/node_modules/pi-lens/dist/chunk-Q5U6FMDI.js +2352 -0
- package/node_modules/pi-lens/dist/chunk-QOZXJ4NA.js +3364 -0
- package/node_modules/pi-lens/dist/chunk-QYF5S6P6.js +45 -0
- package/node_modules/pi-lens/dist/chunk-RIISMHKN.js +36 -0
- package/node_modules/pi-lens/dist/chunk-RPD4ZSB7.js +25 -0
- package/node_modules/pi-lens/dist/chunk-RPD5K5NC.js +79 -0
- package/node_modules/pi-lens/dist/chunk-RUOG5D2C.js +262 -0
- package/node_modules/pi-lens/dist/chunk-T4ERT73Y.js +599 -0
- package/node_modules/pi-lens/dist/chunk-T6D4Q4AQ.js +54 -0
- package/node_modules/pi-lens/dist/chunk-TGPXLY2J.js +391 -0
- package/node_modules/pi-lens/dist/chunk-TLGFBM3F.js +12116 -0
- package/node_modules/pi-lens/dist/chunk-TO6WL3GM.js +88 -0
- package/node_modules/pi-lens/dist/chunk-TT22N74J.js +517 -0
- package/node_modules/pi-lens/dist/chunk-TVN5N6GY.js +21216 -0
- package/node_modules/pi-lens/dist/chunk-U3VGR4VU.js +308 -0
- package/node_modules/pi-lens/dist/chunk-UK3CMEAL.js +1250 -0
- package/node_modules/pi-lens/dist/chunk-UOPVJQ4N.js +103 -0
- package/node_modules/pi-lens/dist/chunk-UXVNL3D7.js +23 -0
- package/node_modules/pi-lens/dist/chunk-UY752QSN.js +45 -0
- package/node_modules/pi-lens/dist/chunk-V5PXFSZK.js +188 -0
- package/node_modules/pi-lens/dist/chunk-V7R425XG.js +398 -0
- package/node_modules/pi-lens/dist/chunk-VCSRSYLF.js +81 -0
- package/node_modules/pi-lens/dist/chunk-VD4JQCQC.js +162 -0
- package/node_modules/pi-lens/dist/chunk-VDBPVIKD.js +62 -0
- package/node_modules/pi-lens/dist/chunk-VHQLPIRJ.js +114 -0
- package/node_modules/pi-lens/dist/chunk-VN2AXLEX.js +5414 -0
- package/node_modules/pi-lens/dist/chunk-VNMT7C64.js +478 -0
- package/node_modules/pi-lens/dist/chunk-WONERJTP.js +309 -0
- package/node_modules/pi-lens/dist/chunk-XECLWQZN.js +85 -0
- package/node_modules/pi-lens/dist/chunk-XIMYZ3JA.js +27 -0
- package/node_modules/pi-lens/dist/chunk-XK4CIILI.js +144 -0
- package/node_modules/pi-lens/dist/chunk-Y4T27COV.js +562 -0
- package/node_modules/pi-lens/dist/chunk-YGVYKNSN.js +1860 -0
- package/node_modules/pi-lens/dist/chunk-YLF3PPT5.js +308 -0
- package/node_modules/pi-lens/dist/chunk-YSNFMJKN.js +14 -0
- package/node_modules/pi-lens/dist/chunk-Z3CCVDUB.js +76 -0
- package/node_modules/pi-lens/dist/chunk-Z54ZSOBZ.js +61 -0
- package/node_modules/pi-lens/dist/chunk-ZAWW3AF6.js +97 -0
- package/node_modules/pi-lens/dist/chunk-ZMOL6RQC.js +167 -0
- package/node_modules/pi-lens/dist/index.js +16456 -8335
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +186 -232
- package/node_modules/pi-lens/dist/mcp/cli.js +137 -98
- package/node_modules/pi-lens/dist/mcp/server.js +22589 -1573
- package/node_modules/pi-lens/dist/mcp/worker.js +97 -38
- package/node_modules/pi-lens/dist/probes/installer.js +135 -0
- package/node_modules/pi-lens/dist/workers/project-snapshot-persist-worker.js +22 -0
- package/node_modules/pi-lens/dist/workers/review-graph-persist-worker.js +15 -0
- package/node_modules/pi-lens/docs/agent-guide.md +13 -4
- package/node_modules/pi-lens/docs/agent-tools.md +42 -0
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +3 -2
- package/node_modules/pi-lens/docs/configuration.md +20 -1
- package/node_modules/pi-lens/docs/environment-variables.md +52 -2
- package/node_modules/pi-lens/docs/features.md +8 -4
- package/node_modules/pi-lens/docs/globalconfig.md +1 -0
- package/node_modules/pi-lens/docs/io-bridge-v2-migration.md +94 -0
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +36 -4
- package/node_modules/pi-lens/docs/lsp-idle-eviction.md +124 -0
- package/node_modules/pi-lens/docs/mcp.md +21 -5
- package/node_modules/pi-lens/docs/merge-queue-rollout.md +77 -0
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +156 -88
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +74 -26
- package/node_modules/pi-lens/docs/pi-lens-merge-policy.md +694 -0
- package/node_modules/pi-lens/docs/pi-lens-monitor.md +73 -7
- package/node_modules/pi-lens/docs/pi-lens-retro.md +6 -4
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +188 -48
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +246 -45
- package/node_modules/pi-lens/docs/pi-lens-warden.md +18 -7
- package/node_modules/pi-lens/docs/public-api-stability.md +55 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +84 -17
- package/node_modules/pi-lens/docs/rfcs/3654-unified-io-bridge-v2.md +316 -0
- package/node_modules/pi-lens/docs/servercapabilities.md +53 -49
- package/node_modules/pi-lens/docs/settings.md +1 -0
- package/node_modules/pi-lens/docs/usage.md +5 -1
- package/node_modules/pi-lens/grammars/tree-sitter-bash.wasm +0 -0
- package/node_modules/pi-lens/grammars/tree-sitter-bash.wasm.json +3 -3
- package/node_modules/pi-lens/package.json +18 -6
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/advisory-registry-subset-test.yml +41 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/advisory-registry-subset.yml +50 -0
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +1275 -62
- package/node_modules/pi-lens/scripts/download-grammars.js +5 -0
- package/node_modules/pi-lens/scripts/grammars.lock.json +6 -1
- package/node_modules/pi-lens/scripts/install-selftest.mjs +33 -34
- package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +13 -4
- package/node_modules/pi-lens/scripts/lib/web-tree-sitter-dir.mjs +18 -0
- package/node_modules/pi-typesafe/README.md +1 -1
- package/node_modules/pi-typesafe/dist/backends.d.ts +15 -5
- package/node_modules/pi-typesafe/dist/backends.js +18 -0
- package/node_modules/pi-typesafe/dist/client.d.ts +4 -3
- package/node_modules/pi-typesafe/dist/client.js +22 -7
- package/node_modules/pi-typesafe/dist/index.d.ts +2 -2
- package/node_modules/pi-typesafe/dist/index.js +1 -1
- package/node_modules/pi-typesafe/dist/usage.d.ts +14 -4
- package/node_modules/pi-typesafe/dist/usage.js +147 -42
- package/node_modules/pi-typesafe/package.json +1 -1
- package/node_modules/pi-web-access/CHANGELOG.md +48 -0
- package/node_modules/pi-web-access/README.md +57 -11
- package/node_modules/pi-web-access/brave-rate-limit.ts +8 -2
- package/node_modules/pi-web-access/curator-page.ts +5 -1
- package/node_modules/pi-web-access/curator-server.ts +2 -0
- package/node_modules/pi-web-access/declared-web-links.ts +2 -2
- package/node_modules/pi-web-access/degoog.ts +323 -0
- package/node_modules/pi-web-access/dist/index.js +3483 -2745
- package/node_modules/pi-web-access/dist/mcp-cli.js +27443 -0
- package/node_modules/pi-web-access/exa.ts +5 -1
- package/node_modules/pi-web-access/extract.ts +41 -3
- package/node_modules/pi-web-access/firecrawl.ts +35 -4
- package/node_modules/pi-web-access/gemini-search.ts +34 -11
- package/node_modules/pi-web-access/gemini-web.ts +14 -9
- package/node_modules/pi-web-access/index.ts +153 -1202
- package/node_modules/pi-web-access/keenable.ts +221 -0
- package/node_modules/pi-web-access/mcp-cli.ts +40 -0
- package/node_modules/pi-web-access/mcp-server.ts +81 -0
- package/node_modules/pi-web-access/mcp-tool-definitions.ts +117 -0
- package/node_modules/pi-web-access/openai-search.ts +34 -1
- package/node_modules/pi-web-access/package.json +23 -5
- package/node_modules/pi-web-access/perplexity.ts +64 -56
- package/node_modules/pi-web-access/tool-arguments.ts +20 -0
- package/node_modules/pi-web-access/video-extract.ts +1 -1
- package/node_modules/pi-web-access/web-tool-contract.ts +86 -0
- package/node_modules/pi-web-access/web-tool-core.ts +1502 -0
- package/node_modules/pi-web-access/youtube-extract.ts +2 -5
- package/package.json +17 -12
- package/node_modules/@dietrichgebert/ponytail/README.es.md +0 -329
- package/node_modules/@dietrichgebert/ponytail/README.ko.md +0 -346
- package/node_modules/@dietrichgebert/ponytail/assets/benchmark-3model.svg +0 -21
- package/node_modules/@dietrichgebert/ponytail/assets/benchmark-agentic.svg +0 -62
- package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.svg +0 -115
- package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt-dark.svg +0 -27
- package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt.svg +0 -27
- package/node_modules/@dietrichgebert/ponytail/assets/logo.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/retriever-icon.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/retriever-logo-dark.svg +0 -4
- package/node_modules/@dietrichgebert/ponytail/assets/retriever-logo-light.svg +0 -4
- package/node_modules/@dietrichgebert/ponytail/assets/social-preview.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-es.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-ko.png +0 -0
- package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner.png +0 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -35
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +0 -1610
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +0 -593
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +0 -147
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +0 -325
- package/node_modules/pi-lens/dist/clients/analysed-root.js +0 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +0 -731
- package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +0 -146
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +0 -118
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -10
- package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +0 -154
- package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +0 -75
- package/node_modules/pi-lens/dist/clients/atomic-write.js +0 -189
- package/node_modules/pi-lens/dist/clients/availability-probe-flight.js +0 -12
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +0 -1056
- package/node_modules/pi-lens/dist/clients/biome-client.js +0 -357
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -837
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +0 -129
- package/node_modules/pi-lens/dist/clients/bootstrap.js +0 -569
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +0 -190
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +0 -202
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +0 -295
- package/node_modules/pi-lens/dist/clients/build-identity.js +0 -95
- package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +0 -113
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +0 -105
- package/node_modules/pi-lens/dist/clients/bus-publish.js +0 -171
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +0 -190
- package/node_modules/pi-lens/dist/clients/cache-manager.js +0 -524
- package/node_modules/pi-lens/dist/clients/cache-observability.js +0 -1313
- package/node_modules/pi-lens/dist/clients/call-graph.js +0 -852
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +0 -422
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +0 -196
- package/node_modules/pi-lens/dist/clients/cascade-format.js +0 -315
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -31
- package/node_modules/pi-lens/dist/clients/cascade-types.js +0 -9
- package/node_modules/pi-lens/dist/clients/child-unref.js +0 -124
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +0 -286
- package/node_modules/pi-lens/dist/clients/codebase-model.js +0 -173
- package/node_modules/pi-lens/dist/clients/collateral-test-role.js +0 -40
- package/node_modules/pi-lens/dist/clients/complexity-client.js +0 -462
- package/node_modules/pi-lens/dist/clients/config-core/deny.js +0 -221
- package/node_modules/pi-lens/dist/clients/config-core/index.js +0 -50
- package/node_modules/pi-lens/dist/clients/config-core/merge.js +0 -357
- package/node_modules/pi-lens/dist/clients/config-core/normalize.js +0 -340
- package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +0 -248
- package/node_modules/pi-lens/dist/clients/config-core/provenance.js +0 -164
- package/node_modules/pi-lens/dist/clients/config-core/records.js +0 -218
- package/node_modules/pi-lens/dist/clients/config-core/resolve.js +0 -125
- package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +0 -78
- package/node_modules/pi-lens/dist/clients/config-core/schema.js +0 -165
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +0 -285
- package/node_modules/pi-lens/dist/clients/config-locations.js +0 -388
- package/node_modules/pi-lens/dist/clients/config-resolve.js +0 -798
- package/node_modules/pi-lens/dist/clients/config-schema.js +0 -251
- package/node_modules/pi-lens/dist/clients/config-warn.js +0 -407
- package/node_modules/pi-lens/dist/clients/console-guard-install.js +0 -26
- package/node_modules/pi-lens/dist/clients/cooperative-budget.js +0 -42
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +0 -510
- package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -30
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +0 -280
- package/node_modules/pi-lens/dist/clients/debug-handles.js +0 -211
- package/node_modules/pi-lens/dist/clients/debug-heap.js +0 -174
- package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +0 -106
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +0 -426
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +0 -169
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +0 -885
- package/node_modules/pi-lens/dist/clients/deps/ast-grep-napi.js +0 -22
- package/node_modules/pi-lens/dist/clients/deps/js-yaml.js +0 -9
- package/node_modules/pi-lens/dist/clients/deps/minimatch.js +0 -4
- package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +0 -14
- package/node_modules/pi-lens/dist/clients/deps/typebox.js +0 -14
- package/node_modules/pi-lens/dist/clients/deps/vscode-jsonrpc.js +0 -1
- package/node_modules/pi-lens/dist/clients/deps/web-tree-sitter.js +0 -24
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +0 -630
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +0 -305
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +0 -73
- package/node_modules/pi-lens/dist/clients/diagnostic-tracker.js +0 -105
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +0 -230
- package/node_modules/pi-lens/dist/clients/dispatch/ast-grep-catalog.js +0 -65
- package/node_modules/pi-lens/dist/clients/dispatch/auxiliary-lsp.js +0 -343
- package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -35
- package/node_modules/pi-lens/dist/clients/dispatch/diagnostic-taxonomy.js +0 -66
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +0 -1269
- package/node_modules/pi-lens/dist/clients/dispatch/fact-provider-types.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/fact-rule-runner.js +0 -17
- package/node_modules/pi-lens/dist/clients/dispatch/fact-runner.js +0 -30
- package/node_modules/pi-lens/dist/clients/dispatch/fact-scheduler.js +0 -68
- package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +0 -377
- package/node_modules/pi-lens/dist/clients/dispatch/facts/comment-facts.js +0 -22
- package/node_modules/pi-lens/dist/clients/dispatch/facts/file-content.js +0 -19
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +0 -348
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +0 -204
- package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -34
- package/node_modules/pi-lens/dist/clients/dispatch/facts/try-catch-facts.js +0 -119
- package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +0 -339
- package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +0 -417
- package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +0 -89
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +0 -2377
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -11
- package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +0 -87
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -278
- package/node_modules/pi-lens/dist/clients/dispatch/priorities.js +0 -20
- package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +0 -50
- package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +0 -69
- package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +0 -135
- package/node_modules/pi-lens/dist/clients/dispatch/rules/async-noise.js +0 -40
- package/node_modules/pi-lens/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
- package/node_modules/pi-lens/dist/clients/dispatch/rules/cors-wildcard.js +0 -54
- package/node_modules/pi-lens/dist/clients/dispatch/rules/error-obscuring.js +0 -32
- package/node_modules/pi-lens/dist/clients/dispatch/rules/error-swallowing.js +0 -31
- package/node_modules/pi-lens/dist/clients/dispatch/rules/framework-call-noise.js +0 -67
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +0 -72
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +0 -74
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-import-coupling.js +0 -37
- package/node_modules/pi-lens/dist/clients/dispatch/rules/missing-error-propagation.js +0 -62
- package/node_modules/pi-lens/dist/clients/dispatch/rules/no-commented-credentials.js +0 -52
- package/node_modules/pi-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -42
- package/node_modules/pi-lens/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
- package/node_modules/pi-lens/dist/clients/dispatch/rules/unsafe-boundary.js +0 -126
- package/node_modules/pi-lens/dist/clients/dispatch/runner-context.js +0 -52
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -111
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +0 -1196
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -296
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +0 -219
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -82
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -416
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -183
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -176
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -164
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -195
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -137
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -29
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -69
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -167
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +0 -104
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -135
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -91
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -171
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +0 -940
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -117
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +0 -108
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -99
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -110
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -379
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -167
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -102
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +0 -414
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -85
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -120
- package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -62
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -445
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +0 -169
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -99
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +0 -88
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +0 -256
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +0 -173
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -102
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -128
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -259
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -183
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -166
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -163
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -174
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -168
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -125
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -643
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -253
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +0 -496
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -90
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -95
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -274
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1701
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -101
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +0 -235
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -169
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -15
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -128
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -242
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -95
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -79
- package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +0 -79
- package/node_modules/pi-lens/dist/clients/dispatch/tool-profile.js +0 -30
- package/node_modules/pi-lens/dist/clients/dispatch/types.js +0 -21
- package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +0 -45
- package/node_modules/pi-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -35
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -32
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +0 -124
- package/node_modules/pi-lens/dist/clients/durable-store.js +0 -97
- package/node_modules/pi-lens/dist/clients/effective-config.js +0 -415
- package/node_modules/pi-lens/dist/clients/env-utils.js +0 -83
- package/node_modules/pi-lens/dist/clients/error-class.js +0 -23
- package/node_modules/pi-lens/dist/clients/eval-timestamp.js +0 -17
- package/node_modules/pi-lens/dist/clients/event-loop-hold.js +0 -274
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +0 -250
- package/node_modules/pi-lens/dist/clients/extension-log.js +0 -504
- package/node_modules/pi-lens/dist/clients/extension-mode.js +0 -73
- package/node_modules/pi-lens/dist/clients/feature-hints.js +0 -103
- package/node_modules/pi-lens/dist/clients/file-kinds.js +0 -412
- package/node_modules/pi-lens/dist/clients/file-role.js +0 -134
- package/node_modules/pi-lens/dist/clients/file-time.js +0 -160
- package/node_modules/pi-lens/dist/clients/file-utils.js +0 -1032
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +0 -494
- package/node_modules/pi-lens/dist/clients/finding-identity.js +0 -88
- package/node_modules/pi-lens/dist/clients/fix-worklog.js +0 -103
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +0 -343
- package/node_modules/pi-lens/dist/clients/format-service.js +0 -222
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +0 -9
- package/node_modules/pi-lens/dist/clients/formatters.js +0 -2032
- package/node_modules/pi-lens/dist/clients/freshness-cadence.js +0 -17
- package/node_modules/pi-lens/dist/clients/freshness.js +0 -38
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +0 -394
- package/node_modules/pi-lens/dist/clients/generation-guard.js +0 -215
- package/node_modules/pi-lens/dist/clients/git-guard.js +0 -1136
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +0 -243
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +0 -509
- package/node_modules/pi-lens/dist/clients/go-client.js +0 -104
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +0 -605
- package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +0 -348
- package/node_modules/pi-lens/dist/clients/grammar-source.js +0 -465
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +0 -135
- package/node_modules/pi-lens/dist/clients/hashline-anchor.js +0 -424
- package/node_modules/pi-lens/dist/clients/hook-budgets.js +0 -76
- package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +0 -140
- package/node_modules/pi-lens/dist/clients/host-ports.js +0 -39
- package/node_modules/pi-lens/dist/clients/indent-retarget.js +0 -154
- package/node_modules/pi-lens/dist/clients/inline-blocker-dispositions.js +0 -186
- package/node_modules/pi-lens/dist/clients/install-diagnostics.js +0 -156
- package/node_modules/pi-lens/dist/clients/installer/index.js +0 -5416
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +0 -58
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +0 -783
- package/node_modules/pi-lens/dist/clients/instance-reaper-state.js +0 -7
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +0 -1137
- package/node_modules/pi-lens/dist/clients/instance-registry-lock.js +0 -145
- package/node_modules/pi-lens/dist/clients/instance-registry.js +0 -773
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +0 -378
- package/node_modules/pi-lens/dist/clients/json-cache-read.js +0 -65
- package/node_modules/pi-lens/dist/clients/knip-client.js +0 -788
- package/node_modules/pi-lens/dist/clients/language-policy.js +0 -252
- package/node_modules/pi-lens/dist/clients/language-profile.js +0 -361
- package/node_modules/pi-lens/dist/clients/language-registry.js +0 -603
- package/node_modules/pi-lens/dist/clients/latency-logger.js +0 -727
- package/node_modules/pi-lens/dist/clients/lazy-import.js +0 -21
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +0 -54
- package/node_modules/pi-lens/dist/clients/lens-config.js +0 -404
- package/node_modules/pi-lens/dist/clients/lens-engine.js +0 -358
- package/node_modules/pi-lens/dist/clients/lens-events.js +0 -125
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +0 -467
- package/node_modules/pi-lens/dist/clients/lens-map.js +0 -1156
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +0 -74
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -222
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +0 -178
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +0 -421
- package/node_modules/pi-lens/dist/clients/lsp/client.js +0 -4593
- package/node_modules/pi-lens/dist/clients/lsp/config.js +0 -691
- package/node_modules/pi-lens/dist/clients/lsp/content-limits.js +0 -41
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +0 -225
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +0 -467
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +0 -1219
- package/node_modules/pi-lens/dist/clients/lsp/index.js +0 -8305
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +0 -216
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +0 -298
- package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -63
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +0 -746
- package/node_modules/pi-lens/dist/clients/lsp/lombok.js +0 -158
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +0 -5
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -251
- package/node_modules/pi-lens/dist/clients/lsp/position-encoding.js +0 -61
- package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +0 -83
- package/node_modules/pi-lens/dist/clients/lsp/server.js +0 -3290
- package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +0 -192
- package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +0 -17
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -56
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +0 -332
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +0 -85
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/index.js +0 -10
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +0 -392
- package/node_modules/pi-lens/dist/clients/lsp/watch-queue.js +0 -61
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +0 -639
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +0 -30
- package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +0 -184
- package/node_modules/pi-lens/dist/clients/lsp-budget.js +0 -186
- package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +0 -110
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +0 -9
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +0 -396
- package/node_modules/pi-lens/dist/clients/lsp-status.js +0 -59
- package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +0 -40
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +0 -420
- package/node_modules/pi-lens/dist/clients/mcp/host-shim.js +0 -31
- package/node_modules/pi-lens/dist/clients/mcp/ipc.js +0 -523
- package/node_modules/pi-lens/dist/clients/mcp/review.js +0 -197
- package/node_modules/pi-lens/dist/clients/mcp/session.js +0 -412
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +0 -208
- package/node_modules/pi-lens/dist/clients/message-end-attribution.js +0 -30
- package/node_modules/pi-lens/dist/clients/metrics-client.js +0 -107
- package/node_modules/pi-lens/dist/clients/metrics-history.js +0 -327
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +0 -263
- package/node_modules/pi-lens/dist/clients/model-provider.js +0 -53
- package/node_modules/pi-lens/dist/clients/module-report-lsp.js +0 -189
- package/node_modules/pi-lens/dist/clients/module-report.js +0 -2150
- package/node_modules/pi-lens/dist/clients/mutating-tool.js +0 -651
- package/node_modules/pi-lens/dist/clients/mutation-attribution.js +0 -368
- package/node_modules/pi-lens/dist/clients/mutation-bridge.js +0 -240
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -734
- package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +0 -101
- package/node_modules/pi-lens/dist/clients/observed-mutation.js +0 -1253
- package/node_modules/pi-lens/dist/clients/oldtext-autopatch.js +0 -128
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +0 -496
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +0 -333
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +0 -76
- package/node_modules/pi-lens/dist/clients/package-manager.js +0 -607
- package/node_modules/pi-lens/dist/clients/package-root.js +0 -38
- package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +0 -439
- package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +0 -43
- package/node_modules/pi-lens/dist/clients/path-keyed-map.js +0 -108
- package/node_modules/pi-lens/dist/clients/path-utils.js +0 -1244
- package/node_modules/pi-lens/dist/clients/performance-report.js +0 -331
- package/node_modules/pi-lens/dist/clients/persist-debounce.js +0 -70
- package/node_modules/pi-lens/dist/clients/persistent-reverify.js +0 -271
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +0 -119
- package/node_modules/pi-lens/dist/clients/pipeline.js +0 -1480
- package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +0 -37
- package/node_modules/pi-lens/dist/clients/print-mode.js +0 -21
- package/node_modules/pi-lens/dist/clients/probe-home-state.js +0 -228
- package/node_modules/pi-lens/dist/clients/process-bridge.js +0 -66
- package/node_modules/pi-lens/dist/clients/process-singletons.js +0 -210
- package/node_modules/pi-lens/dist/clients/process-snapshot.js +0 -68
- package/node_modules/pi-lens/dist/clients/project-changes.js +0 -181
- package/node_modules/pi-lens/dist/clients/project-conventions.js +0 -171
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +0 -137
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +0 -109
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +0 -668
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -118
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -47
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -40
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -34
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -38
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -47
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -48
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -40
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -127
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -81
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +0 -520
- package/node_modules/pi-lens/dist/clients/project-diagnostics/types.js +0 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +0 -807
- package/node_modules/pi-lens/dist/clients/project-report.js +0 -701
- package/node_modules/pi-lens/dist/clients/project-scale.js +0 -237
- package/node_modules/pi-lens/dist/clients/project-scan-policy.js +0 -11
- package/node_modules/pi-lens/dist/clients/project-snapshot-fingerprint.js +0 -48
- package/node_modules/pi-lens/dist/clients/project-snapshot-persist-worker.js +0 -20
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +0 -1653
- package/node_modules/pi-lens/dist/clients/project-trust.js +0 -181
- package/node_modules/pi-lens/dist/clients/python-environment.js +0 -217
- package/node_modules/pi-lens/dist/clients/python-provenance.js +0 -639
- package/node_modules/pi-lens/dist/clients/quiet-window-config.js +0 -47
- package/node_modules/pi-lens/dist/clients/quiet-window.js +0 -236
- package/node_modules/pi-lens/dist/clients/read-bridge.js +0 -139
- package/node_modules/pi-lens/dist/clients/read-expansion.js +0 -266
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +0 -251
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +0 -1306
- package/node_modules/pi-lens/dist/clients/read-guard.js +0 -1561
- package/node_modules/pi-lens/dist/clients/recent-touches.js +0 -240
- package/node_modules/pi-lens/dist/clients/redact/secrets.js +0 -449
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +0 -628
- package/node_modules/pi-lens/dist/clients/reverse-deps.js +0 -270
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +0 -5126
- package/node_modules/pi-lens/dist/clients/review-graph/format.js +0 -33
- package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +0 -163
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +0 -481
- package/node_modules/pi-lens/dist/clients/review-graph/persist-worker.js +0 -10
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +0 -244
- package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +0 -21
- package/node_modules/pi-lens/dist/clients/review-graph/service.js +0 -96
- package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +0 -82
- package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +0 -103
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +0 -299
- package/node_modules/pi-lens/dist/clients/review-graph/types.js +0 -1
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +0 -449
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +0 -81
- package/node_modules/pi-lens/dist/clients/ruff-client.js +0 -179
- package/node_modules/pi-lens/dist/clients/rules-scanner.js +0 -131
- package/node_modules/pi-lens/dist/clients/run-duration.js +0 -55
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +0 -746
- package/node_modules/pi-lens/dist/clients/runtime-config.js +0 -77
- package/node_modules/pi-lens/dist/clients/runtime-context.js +0 -211
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +0 -1324
- package/node_modules/pi-lens/dist/clients/runtime-session.js +0 -2485
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +0 -1295
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +0 -2049
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +0 -3767
- package/node_modules/pi-lens/dist/clients/rust-client.js +0 -97
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +0 -2357
- package/node_modules/pi-lens/dist/clients/sanitize.js +0 -286
- package/node_modules/pi-lens/dist/clients/scan-utils.js +0 -25
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +0 -165
- package/node_modules/pi-lens/dist/clients/search-read-registration.js +0 -94
- package/node_modules/pi-lens/dist/clients/secret-findings.js +0 -114
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +0 -352
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +0 -297
- package/node_modules/pi-lens/dist/clients/session-lifecycle.js +0 -484
- package/node_modules/pi-lens/dist/clients/session-start-observability.js +0 -94
- package/node_modules/pi-lens/dist/clients/session-state-store.js +0 -101
- package/node_modules/pi-lens/dist/clients/session-summary.js +0 -15
- package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +0 -27
- package/node_modules/pi-lens/dist/clients/sg-runner.js +0 -876
- package/node_modules/pi-lens/dist/clients/sgconfig.js +0 -347
- package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +0 -338
- package/node_modules/pi-lens/dist/clients/single-flight.js +0 -158
- package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +0 -108
- package/node_modules/pi-lens/dist/clients/skills-resolver.js +0 -141
- package/node_modules/pi-lens/dist/clients/slow-fs.js +0 -138
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +0 -231
- package/node_modules/pi-lens/dist/clients/source-filter.js +0 -596
- package/node_modules/pi-lens/dist/clients/source-walker.js +0 -211
- package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +0 -120
- package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +0 -110
- package/node_modules/pi-lens/dist/clients/stale-marker.js +0 -17
- package/node_modules/pi-lens/dist/clients/startup-scan.js +0 -400
- package/node_modules/pi-lens/dist/clients/startup-timing.js +0 -130
- package/node_modules/pi-lens/dist/clients/string-utils.js +0 -33
- package/node_modules/pi-lens/dist/clients/subagent-mode.js +0 -111
- package/node_modules/pi-lens/dist/clients/symbol-containment.js +0 -24
- package/node_modules/pi-lens/dist/clients/symbol-types.js +0 -5
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +0 -2507
- package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +0 -287
- package/node_modules/pi-lens/dist/clients/todo-scanner.js +0 -229
- package/node_modules/pi-lens/dist/clients/tool-agreement.js +0 -423
- package/node_modules/pi-lens/dist/clients/tool-config.js +0 -249
- package/node_modules/pi-lens/dist/clients/tool-cwd.js +0 -270
- package/node_modules/pi-lens/dist/clients/tool-definition.js +0 -47
- package/node_modules/pi-lens/dist/clients/tool-event.js +0 -105
- package/node_modules/pi-lens/dist/clients/tool-policy.js +0 -2755
- package/node_modules/pi-lens/dist/clients/tool-probe.js +0 -53
- package/node_modules/pi-lens/dist/clients/tool-render.js +0 -156
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +0 -118
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +0 -364
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +0 -4195
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +0 -100
- package/node_modules/pi-lens/dist/clients/tree-sitter-navigator.js +0 -269
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +0 -569
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +0 -158
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +0 -1265
- package/node_modules/pi-lens/dist/clients/trivy-client.js +0 -467
- package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -50
- package/node_modules/pi-lens/dist/clients/turn-context.js +0 -52
- package/node_modules/pi-lens/dist/clients/turn-end/lane.js +0 -51
- package/node_modules/pi-lens/dist/clients/turn-end/lanes/govulncheck.js +0 -112
- package/node_modules/pi-lens/dist/clients/turn-end/lanes/secrets.js +0 -204
- package/node_modules/pi-lens/dist/clients/turn-summary-render.js +0 -72
- package/node_modules/pi-lens/dist/clients/turn-summary.js +0 -132
- package/node_modules/pi-lens/dist/clients/typos-config.js +0 -29
- package/node_modules/pi-lens/dist/clients/user-notify.js +0 -51
- package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +0 -57
- package/node_modules/pi-lens/dist/clients/warm-attach.js +0 -305
- package/node_modules/pi-lens/dist/clients/widget-state.js +0 -1808
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -49
- package/node_modules/pi-lens/dist/clients/word-index-store.js +0 -459
- package/node_modules/pi-lens/dist/clients/word-index.js +0 -2080
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +0 -443
- package/node_modules/pi-lens/dist/clients/write-ordering-guard.js +0 -65
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +0 -340
- package/node_modules/pi-lens/dist/i18n.js +0 -69
- package/node_modules/pi-lens/dist/mcp/build-staleness.js +0 -124
- package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +0 -583
- package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +0 -129
- package/node_modules/pi-lens/dist/scripts/lib/web-tree-sitter-dir.mjs +0 -123
- package/node_modules/pi-lens/dist/tools/activate-tools.js +0 -87
- package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +0 -137
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +0 -244
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +0 -762
- package/node_modules/pi-lens/dist/tools/effective-config.js +0 -90
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +0 -375
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +0 -2571
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +0 -1745
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +0 -1367
- package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +0 -294
- package/node_modules/pi-lens/dist/tools/module-report.js +0 -382
- package/node_modules/pi-lens/dist/tools/project-report.js +0 -86
- package/node_modules/pi-lens/dist/tools/render-compact.js +0 -374
- package/node_modules/pi-lens/dist/tools/scan-progress.js +0 -53
- package/node_modules/pi-lens/dist/tools/shared.js +0 -29
- package/node_modules/pi-lens/dist/tools/symbol-search.js +0 -155
|
@@ -1,1196 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ast-grep NAPI runner for dispatch system
|
|
3
|
-
*
|
|
4
|
-
* Uses @ast-grep/napi for programmatic parsing instead of CLI.
|
|
5
|
-
* The languages it can serve are exactly the grammars that addon bundles —
|
|
6
|
-
* see `NAPI_LANGUAGE_BINDINGS` for the matrix and for what the other twelve
|
|
7
|
-
* catalog languages deliver through instead.
|
|
8
|
-
*
|
|
9
|
-
* Replaces CLI-based runners for faster performance (100x speedup).
|
|
10
|
-
*/
|
|
11
|
-
import * as fs from "node:fs";
|
|
12
|
-
import * as path from "node:path";
|
|
13
|
-
import { incrementDegradationCount, recordDegradationOnce, } from "../../degradation-ledger.js";
|
|
14
|
-
import { loadAstGrepNapi, } from "../../deps/ast-grep-napi.js";
|
|
15
|
-
import { buildEffectiveAstGrepCatalog } from "../ast-grep-catalog.js";
|
|
16
|
-
import { isRuleIgnoredForPath } from "../rule-ignores.js";
|
|
17
|
-
import { logLatency } from "../../latency-logger.js";
|
|
18
|
-
import { hasAuxiliaryLspPublishedForRoot } from "../../lsp/index.js";
|
|
19
|
-
import { clearPendingAuxiliaryCoverage, hasPendingAuxiliaryCoverage, recordNapiFallbackCoverage, } from "../../lsp/pending-aux-coverage.js";
|
|
20
|
-
import { hasEslintConfig } from "../../tool-policy.js";
|
|
21
|
-
import { enabledAuxiliaryLspServerIds } from "../auxiliary-lsp.js";
|
|
22
|
-
import { classifyDefect } from "../diagnostic-taxonomy.js";
|
|
23
|
-
import { PRIORITY } from "../priorities.js";
|
|
24
|
-
import { calculateRuleComplexity, isOverlyBroadPattern, isStructuredRule, MAX_BLOCKING_RULE_COMPLEXITY, } from "./yaml-rule-parser.js";
|
|
25
|
-
const defaultUnsupportedLanguageLog = new Set();
|
|
26
|
-
const UNSUPPORTED_RULE_ID_SAMPLE_SIZE = 5;
|
|
27
|
-
/** Clear per-session unsupported-language telemetry dedupe. */
|
|
28
|
-
export function resetAstGrepUnsupportedLanguageLog() {
|
|
29
|
-
defaultUnsupportedLanguageLog.clear();
|
|
30
|
-
}
|
|
31
|
-
// Lazy load the napi package.
|
|
32
|
-
let sg;
|
|
33
|
-
/**
|
|
34
|
-
* In-flight load, shared by every caller (#1567). The per-edit fallback
|
|
35
|
-
* runner and the session-start scanner (clients/project-diagnostics/scanner.ts)
|
|
36
|
-
* both call `loadSg()` and can race. Pre-fix, the "attempted" flag was set
|
|
37
|
-
* before the load and read by the SECOND caller as "already tried" while the
|
|
38
|
-
* first load was still pending and about to succeed — a false-negative
|
|
39
|
-
* STARVATION, not a duplicate load: the second caller got back `undefined`
|
|
40
|
-
* for a load that was in flight and would have succeeded, not a second
|
|
41
|
-
* redundant `import()`. Sharing one promise means every concurrent caller
|
|
42
|
-
* observes the SAME outcome instead of a subset of them starving.
|
|
43
|
-
*
|
|
44
|
-
* Evicted on settle (#1536's pattern, see clients/tree-sitter-client.ts) — a
|
|
45
|
-
* rejected load must not be remembered as the permanent answer; only
|
|
46
|
-
* concurrent callers during the SAME attempt observe this promise.
|
|
47
|
-
*/
|
|
48
|
-
let sgLoadPromise;
|
|
49
|
-
/**
|
|
50
|
-
* Set on ANY load failure and cleared only by `resetAstGrepNapiLoadState()`
|
|
51
|
-
* at session_start (#1567 review round 2, F2).
|
|
52
|
-
*
|
|
53
|
-
* This holds for BOTH genuine and classified-transient failures, which is
|
|
54
|
-
* narrower than the original design (a cooldown-then-retry for transient
|
|
55
|
-
* failures within the same session). The reason: `loadAstGrepNapi()`
|
|
56
|
-
* (clients/deps/ast-grep-napi.ts) resolves the addon to a `file://` URL and
|
|
57
|
-
* dynamically `import()`s it. Node's ESM loader permanently memoizes a
|
|
58
|
-
* module record that threw during evaluation — re-importing the SAME
|
|
59
|
-
* resolved URL replays the cached rejection, it does not re-run the load.
|
|
60
|
-
* A cooldown-then-retry loop would therefore call `loadAstGrepNapi()` again
|
|
61
|
-
* after the cooldown and get back the identical cached rejection every
|
|
62
|
-
* time: a retry that LOOKS like it tries again but structurally cannot
|
|
63
|
-
* succeed within the process. Rather than ship that, every failure holds
|
|
64
|
-
* until the next `session_start`, which is the point this cache can
|
|
65
|
-
* actually be expected to have moved on (a fresh session re-arms the latch;
|
|
66
|
-
* whether the underlying Node module cache also gets a fresh start depends
|
|
67
|
-
* on whether the host recycles the process between sessions, but re-arming
|
|
68
|
-
* the latch is the most this in-process code can honestly promise).
|
|
69
|
-
*/
|
|
70
|
-
let sgSessionHold = false;
|
|
71
|
-
/**
|
|
72
|
-
* Why `sgSessionHold` was set — feeds the degradation-ledger message and log
|
|
73
|
-
* line only. It does not change retry behavior: both classes hold
|
|
74
|
-
* identically for the session, per `sgSessionHold`'s doc above.
|
|
75
|
-
*/
|
|
76
|
-
let sgHoldReason;
|
|
77
|
-
/** A positively-identified, narrow errno family for a native-addon load: the
|
|
78
|
-
* kind of momentary FS contention (too many open files, a file mid-write,
|
|
79
|
-
* a transient permission/resource block) that says nothing durable about
|
|
80
|
-
* whether the addon itself can load. Everything NOT in this allowlist is
|
|
81
|
-
* genuine by default (#1567 review round 2, F1) — the original classifier
|
|
82
|
-
* inverted this: it matched a handful of message patterns as "genuine" and
|
|
83
|
-
* treated every OTHER error, including the real native-binding failure
|
|
84
|
-
* family (ABI mismatch, a missing platform package, a napi version
|
|
85
|
-
* mismatch, an unsupported arch), as transient. None of those recover on
|
|
86
|
-
* their own; an unrecognized error is far more likely to be one of them
|
|
87
|
-
* than a genuine FS hiccup. */
|
|
88
|
-
const TRANSIENT_ERRNO_ALLOWLIST = new Set([
|
|
89
|
-
"EMFILE",
|
|
90
|
-
"EBUSY",
|
|
91
|
-
"EAGAIN",
|
|
92
|
-
"EPERM",
|
|
93
|
-
"ETXTBSY",
|
|
94
|
-
]);
|
|
95
|
-
/**
|
|
96
|
-
* `@ast-grep/napi`'s own terminal "this machine cannot run this addon"
|
|
97
|
-
* messages (from its `index.js` platform-detection shim). Already covered
|
|
98
|
-
* by the genuine-by-default policy above; listed explicitly so the
|
|
99
|
-
* classification is legible at the call site instead of an emergent
|
|
100
|
-
* property of "didn't match the allowlist".
|
|
101
|
-
*/
|
|
102
|
-
const KNOWN_GENUINE_NATIVE_LOAD_MESSAGES = [
|
|
103
|
-
/cannot find native binding/i,
|
|
104
|
-
/failed to load native binding/i,
|
|
105
|
-
];
|
|
106
|
-
/**
|
|
107
|
-
* Walk an error's `.cause` chain — Node/napi wrap the real dlopen/ABI
|
|
108
|
-
* failure there rather than on the top-level thrown Error — collecting
|
|
109
|
-
* every `code` and `message` seen along the way, so classification isn't
|
|
110
|
-
* blind to a nested cause (#1567 review round 2, F1).
|
|
111
|
-
*/
|
|
112
|
-
function collectErrorChain(err) {
|
|
113
|
-
const codes = [];
|
|
114
|
-
const messages = [];
|
|
115
|
-
let current = err;
|
|
116
|
-
const seen = new Set();
|
|
117
|
-
while (current !== undefined && current !== null && !seen.has(current)) {
|
|
118
|
-
seen.add(current);
|
|
119
|
-
if (current instanceof Error) {
|
|
120
|
-
messages.push(current.message);
|
|
121
|
-
const code = current.code;
|
|
122
|
-
if (typeof code === "string")
|
|
123
|
-
codes.push(code);
|
|
124
|
-
current = current.cause;
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
messages.push(String(current));
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return { codes, messages };
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Classify a `loadAstGrepNapi()` rejection. Transient requires a positively
|
|
135
|
-
* identified errno match somewhere in the cause chain AND no known-genuine
|
|
136
|
-
* native-load message anywhere in that same chain (an errno wrapping a
|
|
137
|
-
* "cannot find native binding" cause is genuine, not transient — the errno
|
|
138
|
-
* describes how the OS reported it, not what actually failed). Everything
|
|
139
|
-
* else — including an error with no `code` at all — is genuine.
|
|
140
|
-
*/
|
|
141
|
-
function classifyAstGrepLoadFailure(err) {
|
|
142
|
-
const { codes, messages } = collectErrorChain(err);
|
|
143
|
-
const hasKnownGenuineMessage = messages.some((message) => KNOWN_GENUINE_NATIVE_LOAD_MESSAGES.some((pattern) => pattern.test(message)));
|
|
144
|
-
if (hasKnownGenuineMessage)
|
|
145
|
-
return "genuine";
|
|
146
|
-
const hasTransientErrno = codes.some((code) => TRANSIENT_ERRNO_ALLOWLIST.has(code));
|
|
147
|
-
return hasTransientErrno ? "transient" : "genuine";
|
|
148
|
-
}
|
|
149
|
-
function recordAstGrepUnavailableOnce(reason) {
|
|
150
|
-
recordDegradationOnce({
|
|
151
|
-
kind: "ast-grep-napi-unavailable",
|
|
152
|
-
subject: "ast-grep-napi",
|
|
153
|
-
reason: reason === "genuine"
|
|
154
|
-
? "native addon failed to load (durable for this session)"
|
|
155
|
-
: "native addon load hit a transient error (durable for this session — see sgSessionHold doc)",
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
export async function loadSg() {
|
|
159
|
-
if (sg)
|
|
160
|
-
return sg;
|
|
161
|
-
if (sgLoadPromise)
|
|
162
|
-
return sgLoadPromise;
|
|
163
|
-
if (sgSessionHold) {
|
|
164
|
-
// #1567 review F4: a held/degraded load must be distinguishable from a
|
|
165
|
-
// clean scan that found nothing to report, not silently read as
|
|
166
|
-
// "skipped/empty" by every caller (clients/project-diagnostics/scanner.ts,
|
|
167
|
-
// this file's own runner) — otherwise the two are indistinguishable in
|
|
168
|
-
// the degradation ledger.
|
|
169
|
-
recordAstGrepUnavailableOnce(sgHoldReason ?? "genuine");
|
|
170
|
-
return undefined;
|
|
171
|
-
}
|
|
172
|
-
const task = (async () => {
|
|
173
|
-
try {
|
|
174
|
-
const loaded = await loadAstGrepNapi();
|
|
175
|
-
sg = loaded;
|
|
176
|
-
return loaded;
|
|
177
|
-
}
|
|
178
|
-
catch (err) {
|
|
179
|
-
const reason = classifyAstGrepLoadFailure(err);
|
|
180
|
-
sgSessionHold = true;
|
|
181
|
-
sgHoldReason = reason;
|
|
182
|
-
recordAstGrepUnavailableOnce(reason);
|
|
183
|
-
return undefined;
|
|
184
|
-
}
|
|
185
|
-
})();
|
|
186
|
-
sgLoadPromise = task;
|
|
187
|
-
// `task` never rejects (the IIFE catches), so the derived promise is inert;
|
|
188
|
-
// `void` records that no consumer awaits it (oxlint no-floating-promises).
|
|
189
|
-
void task.finally(() => {
|
|
190
|
-
if (sgLoadPromise === task)
|
|
191
|
-
sgLoadPromise = undefined;
|
|
192
|
-
});
|
|
193
|
-
return task;
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Re-arm the napi load latch for a new session (#1567). `sg` itself is left
|
|
197
|
-
* alone — a successful load stays valid and cached for the process — but a
|
|
198
|
-
* session hold (transient or genuine) is session-scoped state and must not
|
|
199
|
-
* outlive the session that set it. Called from `resetDispatchBaselines()`
|
|
200
|
-
* (clients/dispatch/integration.ts) beside `resetAstGrepUnsupportedLanguageLog`,
|
|
201
|
-
* this module's other session latch.
|
|
202
|
-
*/
|
|
203
|
-
export function resetAstGrepNapiLoadState() {
|
|
204
|
-
sgSessionHold = false;
|
|
205
|
-
sgHoldReason = undefined;
|
|
206
|
-
}
|
|
207
|
-
const NAPI_LANGUAGE_BINDINGS = [
|
|
208
|
-
// `.mts`/`.cts` and `.mjs`/`.cjs` are the same two grammars under a
|
|
209
|
-
// module-system-flavored extension; leaving them off the old hand list meant
|
|
210
|
-
// the whole catalog went dark on every ES/CommonJS module file (#2215).
|
|
211
|
-
{
|
|
212
|
-
ruleLanguage: "typescript",
|
|
213
|
-
napiExport: "ts",
|
|
214
|
-
extensions: [".ts", ".mts", ".cts"],
|
|
215
|
-
},
|
|
216
|
-
{ ruleLanguage: "tsx", napiExport: "tsx", extensions: [".tsx"] },
|
|
217
|
-
{
|
|
218
|
-
ruleLanguage: "javascript",
|
|
219
|
-
napiExport: "js",
|
|
220
|
-
// `.jsx` stays on the `js` grammar it has always used here. The addon
|
|
221
|
-
// also exports a separate `jsx`, but switching to it is a matching
|
|
222
|
-
// change, not a coverage one, and belongs with its own fixtures.
|
|
223
|
-
extensions: [".js", ".jsx", ".mjs", ".cjs"],
|
|
224
|
-
},
|
|
225
|
-
{ ruleLanguage: "css", napiExport: "css", extensions: [".css"] },
|
|
226
|
-
{ ruleLanguage: "html", napiExport: "html", extensions: [".html", ".htm"] },
|
|
227
|
-
];
|
|
228
|
-
const BINDING_BY_EXTENSION = new Map(NAPI_LANGUAGE_BINDINGS.flatMap((binding) => binding.extensions.map((ext) => [ext, binding])));
|
|
229
|
-
const SUPPORTED_RULE_LANGUAGES = NAPI_LANGUAGE_BINDINGS.map((binding) => binding.ruleLanguage);
|
|
230
|
-
/**
|
|
231
|
-
* Rule `language:` tokens the shipped catalog carries that NO bundled napi
|
|
232
|
-
* grammar can parse. Their rules deliver through the ast-grep LSP/CLI, which
|
|
233
|
-
* ships its own grammar set — never in-process. One shared reason, so this is
|
|
234
|
-
* a list of decisions rather than twelve copies of a sentence: the addon
|
|
235
|
-
* bundles six grammars (see `NAPI_LANGUAGE_BINDINGS`) and nothing registers
|
|
236
|
-
* more at runtime.
|
|
237
|
-
*
|
|
238
|
-
* The LSP/CLI half of that claim is measured, not assumed: every entry below
|
|
239
|
-
* was run through the real `ast-grep run -l <lang>` on 2026-08-26 and parsed,
|
|
240
|
-
* with `cobol` as the negative control (`cobol is not supported!`, exit 2). So
|
|
241
|
-
* no catalog language is unreachable by BOTH engines — the issue's
|
|
242
|
-
* "genuinely missing" bucket is empty, and this list is a routing fact rather
|
|
243
|
-
* than a coverage hole.
|
|
244
|
-
*
|
|
245
|
-
* This is the deliberate-exclusion half of the #2215 contract; the served half
|
|
246
|
-
* is derived from the addon itself. `ast-grep-napi-language-coverage.test.ts`
|
|
247
|
-
* reds when a catalog language with enabled rules is in neither half.
|
|
248
|
-
*/
|
|
249
|
-
export const AST_GREP_LSP_ONLY_RULE_LANGUAGES = [
|
|
250
|
-
"c",
|
|
251
|
-
"cpp",
|
|
252
|
-
"csharp",
|
|
253
|
-
"go",
|
|
254
|
-
"java",
|
|
255
|
-
"kotlin",
|
|
256
|
-
"php",
|
|
257
|
-
"python",
|
|
258
|
-
"ruby",
|
|
259
|
-
"rust",
|
|
260
|
-
"scala",
|
|
261
|
-
"swift",
|
|
262
|
-
];
|
|
263
|
-
const LSP_ONLY_RULE_LANGUAGES = new Set(AST_GREP_LSP_ONLY_RULE_LANGUAGES);
|
|
264
|
-
/**
|
|
265
|
-
* How a rule's declared language reaches the user. `unclassified` is the
|
|
266
|
-
* runtime signal that the #2215 class regrew: rules ship for a language nobody
|
|
267
|
-
* decided a delivery route for, so they may run nowhere at all.
|
|
268
|
-
*/
|
|
269
|
-
export function deliveryRouteForRuleLanguage(ruleLanguage) {
|
|
270
|
-
if (SUPPORTED_RULE_LANGUAGES.includes(ruleLanguage))
|
|
271
|
-
return "napi";
|
|
272
|
-
return LSP_ONLY_RULE_LANGUAGES.has(ruleLanguage)
|
|
273
|
-
? "ast-grep-lsp-cli"
|
|
274
|
-
: "unclassified";
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Delivery route for one aggregated skip key. A `mismatch:<rule>-><file>` key
|
|
278
|
-
* is a rule whose language this engine DOES serve and that simply isn't this
|
|
279
|
-
* file's grammar, so it still routes through napi on its own files.
|
|
280
|
-
*/
|
|
281
|
-
function skipRouteFor(key) {
|
|
282
|
-
return key.startsWith("mismatch:")
|
|
283
|
-
? "napi"
|
|
284
|
-
: deliveryRouteForRuleLanguage(key);
|
|
285
|
-
}
|
|
286
|
-
/** Maximum matches per rule to prevent excessive false positives */
|
|
287
|
-
const MAX_MATCHES_PER_RULE = 10;
|
|
288
|
-
/** Maximum total diagnostics per file to prevent output spam */
|
|
289
|
-
const MAX_TOTAL_DIAGNOSTICS = 50;
|
|
290
|
-
/**
|
|
291
|
-
* #660: this runner used to skip a hardcoded set of rule ids
|
|
292
|
-
* (`constructor-super`, `empty-catch`, `long-parameter-list`,
|
|
293
|
-
* `nested-ternary`, `no-dupe-class-members`) on the assumption that the
|
|
294
|
-
* tree-sitter query runner (priority 14) already covered them, to avoid
|
|
295
|
-
* double-reporting. That assumption was false for every entry: three of
|
|
296
|
-
* them (`nested-ternary`, `long-parameter-list`, `no-dupe-class-members`)
|
|
297
|
-
* have no active tree-sitter query — their would-be queries either live
|
|
298
|
-
* under `rules/tree-sitter-queries/typescript-disabled/` (excluded from
|
|
299
|
-
* loading, see clients/tree-sitter-query-loader.ts) or were never written —
|
|
300
|
-
* so those three rule ids had ZERO coverage in the NAPI fallback runner
|
|
301
|
-
* (used when the ast-grep binary isn't installed) despite having a
|
|
302
|
-
* perfectly good, shipped, active ast-grep rule sitting right there. The
|
|
303
|
-
* other two (`constructor-super`, `empty-catch`) are disabled everywhere
|
|
304
|
-
* (ast-grep AND tree-sitter, see rules-disabled/, #206), so skipping them
|
|
305
|
-
* was already a no-op. The whole skip-set has been removed; if tree-sitter
|
|
306
|
-
* coverage is ever added back for one of these rule ids, reintroduce a
|
|
307
|
-
* scoped skip alongside the query that actually covers it — don't recreate
|
|
308
|
-
* a blanket assumption-based list.
|
|
309
|
-
*
|
|
310
|
-
* Note: `no-dupe-class-members` didn't actually fire immediately
|
|
311
|
-
* post-removal — its rule YAML uses a top-level `utils:` block that this
|
|
312
|
-
* runner's native-config passthrough dropped entirely, a separate bug
|
|
313
|
-
* (affecting 5 shipped rules, not just this one) fixed in #663.
|
|
314
|
-
*/
|
|
315
|
-
/**
|
|
316
|
-
* Rules commonly covered by ESLint/Biome correctness checks.
|
|
317
|
-
* We can suppress these from ast-grep in lint-enabled projects to reduce noise.
|
|
318
|
-
*/
|
|
319
|
-
const LINTER_OVERLAP = new Set([
|
|
320
|
-
"getter-return",
|
|
321
|
-
"no-array-constructor",
|
|
322
|
-
"no-async-promise-executor",
|
|
323
|
-
"no-await-in-loop",
|
|
324
|
-
"no-case-declarations",
|
|
325
|
-
"no-compare-neg-zero",
|
|
326
|
-
"no-cond-assign",
|
|
327
|
-
"no-constant-condition",
|
|
328
|
-
"no-constructor-return",
|
|
329
|
-
"no-dupe-args",
|
|
330
|
-
"no-dupe-keys",
|
|
331
|
-
"no-extra-boolean-cast",
|
|
332
|
-
"no-new-symbol",
|
|
333
|
-
"no-new-wrappers",
|
|
334
|
-
"no-prototype-builtins",
|
|
335
|
-
]);
|
|
336
|
-
const NON_SUPPRESSIBLE = new Set([
|
|
337
|
-
"empty-catch",
|
|
338
|
-
"no-discarded-error",
|
|
339
|
-
"unchecked-throwing-call",
|
|
340
|
-
]);
|
|
341
|
-
function defaultFixSuggestion(defectClass, ruleId) {
|
|
342
|
-
if (defectClass === "silent-error") {
|
|
343
|
-
return "Handle the error path explicitly: log context and rethrow or return a typed error result.";
|
|
344
|
-
}
|
|
345
|
-
if (defectClass === "secrets") {
|
|
346
|
-
return "Remove hardcoded secret material and load values from env/secret manager.";
|
|
347
|
-
}
|
|
348
|
-
if (defectClass === "injection") {
|
|
349
|
-
return "Avoid dynamic execution/interpolation here; use parameterized APIs or strict allowlists.";
|
|
350
|
-
}
|
|
351
|
-
if (defectClass === "async-misuse") {
|
|
352
|
-
return "Make async flow explicit: await consistently and handle rejection/error paths.";
|
|
353
|
-
}
|
|
354
|
-
if (ruleId.includes("unsafe") || ruleId.includes("security")) {
|
|
355
|
-
return "Refactor to a safer API usage with explicit validation and bounded behavior.";
|
|
356
|
-
}
|
|
357
|
-
return "Refactor this pattern to the safer equivalent used in the codebase.";
|
|
358
|
-
}
|
|
359
|
-
function explicitRuleFixSuggestion(rule) {
|
|
360
|
-
const raw = (rule.fix ?? rule.note ?? "").trim();
|
|
361
|
-
if (!raw)
|
|
362
|
-
return undefined;
|
|
363
|
-
const oneLine = raw.replace(/\s+/g, " ").trim();
|
|
364
|
-
return oneLine.length > 240 ? `${oneLine.slice(0, 237)}...` : oneLine;
|
|
365
|
-
}
|
|
366
|
-
function normalizeRuleId(ruleId) {
|
|
367
|
-
return ruleId.replace(/-js$/, "");
|
|
368
|
-
}
|
|
369
|
-
export function canHandle(filePath) {
|
|
370
|
-
return BINDING_BY_EXTENSION.has(path.extname(filePath).toLowerCase());
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* The TypeScript grammar is a syntactic superset of JavaScript, so a
|
|
374
|
-
* `JavaScript`-tagged rule using generic node kinds (`variable_declarator`,
|
|
375
|
-
* `assignment_expression`, …) still matches against a parsed `.ts` root
|
|
376
|
-
* — and vice versa isn't an issue since JS files never parse
|
|
377
|
-
* TS-only syntax, but a `TypeScript`-tagged rule with a plain-JS-compatible
|
|
378
|
-
* body would equally double-fire alongside a `JavaScript` twin on a `.ts`
|
|
379
|
-
* file. Without this, `language:` reads as a real filter but isn't one for
|
|
380
|
-
* ts↔js pairs, so twin rules sharing a base name (e.g. `hardcoded-url` /
|
|
381
|
-
* `hardcoded-url-js`) both match the same construct in the SAME runner
|
|
382
|
-
* invocation (#657). TSX is its own grammar here too — the primary
|
|
383
|
-
* ast-grep CLI/LSP also treats `tsx` as distinct from `typescript` — but
|
|
384
|
-
* the caller's language-match check adds ONE deliberate exception on top
|
|
385
|
-
* of the exact-match rule: a `TypeScript`-tagged rule also runs against
|
|
386
|
-
* a `.tsx` file's fileLang (#1608). This is grounded empirically, not by
|
|
387
|
-
* analogy — tsx's grammar is a syntactic superset of typescript's for
|
|
388
|
-
* every construct the shipped catalog's rules target (JSX productions
|
|
389
|
-
* added, plus the removal of the `<T>expr` cast form, which cannot
|
|
390
|
-
* appear in valid `.tsx` source), and every `language: TypeScript`
|
|
391
|
-
* rule's fixture-test `invalid:` snippet is asserted to still match
|
|
392
|
-
* parsed as tsx (ast-grep-tsx-coverage.test.ts) rather than assumed.
|
|
393
|
-
* Without this exception the entire TS ruleset silently never runs on
|
|
394
|
-
* `.tsx` files. `TSX`-tagged rules stay `.tsx`-exclusive; the exception
|
|
395
|
-
* is TS→TSX only. Returns undefined for an extension outside the matrix.
|
|
396
|
-
*/
|
|
397
|
-
export function ruleLanguageForFile(filePath) {
|
|
398
|
-
return BINDING_BY_EXTENSION.get(path.extname(filePath).toLowerCase())
|
|
399
|
-
?.ruleLanguage;
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* The grammar for `filePath` on the addon that actually loaded, or undefined
|
|
403
|
-
* when there is none.
|
|
404
|
-
*
|
|
405
|
-
* Both callers (this file's runner and clients/project-diagnostics/scanner.ts)
|
|
406
|
-
* gate on `canHandle` first, so an undefined return HERE means the matrix
|
|
407
|
-
* admitted the file and the addon then dropped it — the silent skip #2215 is
|
|
408
|
-
* about, which is why it records instead of just returning. An extension
|
|
409
|
-
* outside the matrix was never admitted, so it records nothing.
|
|
410
|
-
*/
|
|
411
|
-
export function getLang(filePath, sgModule) {
|
|
412
|
-
const binding = BINDING_BY_EXTENSION.get(path.extname(filePath).toLowerCase());
|
|
413
|
-
if (!binding)
|
|
414
|
-
return undefined;
|
|
415
|
-
const lang = sgModule[binding.napiExport];
|
|
416
|
-
if (!lang) {
|
|
417
|
-
recordDegradationOnce({
|
|
418
|
-
kind: "ast-grep-napi-language-unavailable",
|
|
419
|
-
subject: binding.ruleLanguage,
|
|
420
|
-
reason: `@ast-grep/napi exposes no "${binding.napiExport}" grammar; every ${binding.ruleLanguage} rule is skipped in-process this session`,
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
return lang;
|
|
424
|
-
}
|
|
425
|
-
/**
|
|
426
|
-
* Budget for embedded-`<script>` evaluation (#2347 review F2/F4). Every nonempty
|
|
427
|
-
* script body is reparsed as JS and EVERY `language: JavaScript` rule runs
|
|
428
|
-
* against it, so the work is `rules * bodies * body-size`, all multiplied by
|
|
429
|
-
* the native addon's per-call overhead. Measured on this seam (full catalog,
|
|
430
|
-
* real addon, 2026-08-30): ~8.5 ms per small body, ~9 s for 500 blocks, and
|
|
431
|
-
* ~19.5 s for one ~1 MiB dense body (the shape that made the byte axis the
|
|
432
|
-
* real bound). The caps apply to EVERY body — first one included — so an
|
|
433
|
-
* oversized single inline script is omitted and recorded like any other
|
|
434
|
-
* over-budget body. Hand-authored HTML carries a handful of small inline
|
|
435
|
-
* scripts, so the caps only ever trip on generated/pathological pages, where a
|
|
436
|
-
* bounded, recorded partial evaluation beats a seconds-long synchronous stall
|
|
437
|
-
* on the per-edit hook. Budget truncation is a coverage loss and is recorded
|
|
438
|
-
* (see `emitHtmlScriptDegradations`).
|
|
439
|
-
*/
|
|
440
|
-
export const MAX_SCRIPT_BODIES_EVALUATED = 64;
|
|
441
|
-
/**
|
|
442
|
-
* Cumulative parsed script-body size cap; bounds the `rules * bytes` work.
|
|
443
|
-
* Every body — including the first — must fit within the running total.
|
|
444
|
-
*/
|
|
445
|
-
export const MAX_SCRIPT_BODY_BYTES_EVALUATED = 128 * 1024;
|
|
446
|
-
/**
|
|
447
|
-
* UTF-16 code-unit indexes, in the original file, of every line start, newest
|
|
448
|
-
* line last. `@ast-grep/napi` reports line/column/index in UTF-16 code units
|
|
449
|
-
* (verified against 0.45.1 with `é` and emoji), so the line table must be
|
|
450
|
-
* built in the SAME unit; a UTF-8 byte walk would shift every coordinate that
|
|
451
|
-
* follows a multibyte character.
|
|
452
|
-
*/
|
|
453
|
-
function computeLineStartsUtf16(content) {
|
|
454
|
-
const starts = [0];
|
|
455
|
-
for (let i = 0; i < content.length; i++) {
|
|
456
|
-
if (content.charCodeAt(i) === 0x0a)
|
|
457
|
-
starts.push(i + 1);
|
|
458
|
-
}
|
|
459
|
-
return starts;
|
|
460
|
-
}
|
|
461
|
-
/** 0-based line and code-unit column for a UTF-16 index, via binary search. */
|
|
462
|
-
function filePositionForIndex(lineStarts, index) {
|
|
463
|
-
let lo = 0;
|
|
464
|
-
let hi = lineStarts.length - 1;
|
|
465
|
-
while (lo < hi) {
|
|
466
|
-
const mid = (lo + hi + 1) >> 1;
|
|
467
|
-
if (lineStarts[mid] <= index)
|
|
468
|
-
lo = mid;
|
|
469
|
-
else
|
|
470
|
-
hi = mid - 1;
|
|
471
|
-
}
|
|
472
|
-
return { line: lo, column: index - lineStarts[lo] };
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Extract every `<script>` body from an HTML root and parse it as JavaScript
|
|
476
|
-
* (#2347). Mirrors the ast-grep CLI/LSP: the injection is unconditional —
|
|
477
|
-
* `type` and `src` attributes do not suppress it (verified against the 0.45.1
|
|
478
|
-
* CLI with `text/template`, `application/ld+json`, and `src`-bearing script
|
|
479
|
-
* tags, all injected). Whitespace-only bodies are skipped (nothing to match).
|
|
480
|
-
* A body the JS grammar cannot parse is dropped the way an unparseable `.js`
|
|
481
|
-
* file would be; the failure is counted, never silent. The evaluation budget
|
|
482
|
-
* (count + cumulative bytes) is applied BEFORE any grammar parse. The caller
|
|
483
|
-
* emits the bounded degradation records from the result — collection stays
|
|
484
|
-
* pure so the count evidence is directly testable.
|
|
485
|
-
*/
|
|
486
|
-
export function collectHtmlScriptInjections(htmlRoot, sgModule) {
|
|
487
|
-
// SAFETY: `AstGrepNapi` is the loaded addon module's own (typed) shape, so
|
|
488
|
-
// its `js` accessor is guaranteed present while the addon lives; this
|
|
489
|
-
// narrowing only names the subshape this helper consumes (a `js` grammar
|
|
490
|
-
// whose parses expose `findAll`), and the absence check right below
|
|
491
|
-
// degrades to "no embedded coverage" rather than throwing when the addon
|
|
492
|
-
// ever drops the grammar.
|
|
493
|
-
const addon = sgModule;
|
|
494
|
-
if (!addon.js) {
|
|
495
|
-
return {
|
|
496
|
-
injections: [],
|
|
497
|
-
scriptElementCount: 0,
|
|
498
|
-
bodiesEvaluated: 0,
|
|
499
|
-
truncatedBodies: 0,
|
|
500
|
-
parseFailures: 0,
|
|
501
|
-
missingJsGrammar: true,
|
|
502
|
-
htmlScanFailure: false,
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
let scripts;
|
|
506
|
-
try {
|
|
507
|
-
scripts = htmlRoot.findAll({ rule: { kind: "script_element" } });
|
|
508
|
-
}
|
|
509
|
-
catch {
|
|
510
|
-
return {
|
|
511
|
-
injections: [],
|
|
512
|
-
scriptElementCount: 0,
|
|
513
|
-
bodiesEvaluated: 0,
|
|
514
|
-
truncatedBodies: 0,
|
|
515
|
-
parseFailures: 0,
|
|
516
|
-
missingJsGrammar: false,
|
|
517
|
-
htmlScanFailure: true,
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
// Extract every nonempty body first (text extraction is cheap) so the raw
|
|
521
|
-
// script-element count is exact, then apply the budget BEFORE parsing any
|
|
522
|
-
// of them.
|
|
523
|
-
let scriptElementCount = 0;
|
|
524
|
-
const candidates = [];
|
|
525
|
-
for (const element of scripts) {
|
|
526
|
-
scriptElementCount += 1;
|
|
527
|
-
let raw;
|
|
528
|
-
for (const child of element.children()) {
|
|
529
|
-
if (child.kind() === "raw_text") {
|
|
530
|
-
raw = child;
|
|
531
|
-
break;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
if (!raw)
|
|
535
|
-
continue;
|
|
536
|
-
const body = raw.text();
|
|
537
|
-
if (!body.trim())
|
|
538
|
-
continue;
|
|
539
|
-
candidates.push({
|
|
540
|
-
body,
|
|
541
|
-
startIndex: raw.range().start.index,
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
let budgetedBytes = 0;
|
|
545
|
-
const selected = [];
|
|
546
|
-
let truncatedBodies = 0;
|
|
547
|
-
for (const candidate of candidates) {
|
|
548
|
-
const bytes = Buffer.byteLength(candidate.body, "utf8");
|
|
549
|
-
// EVERY body must fit inside both caps — including the first. There is
|
|
550
|
-
// no "one big script" allowance: a single over-cap body (a ~1 MiB dense
|
|
551
|
-
// inline script measured 19.5 s of synchronous rule traversal on this
|
|
552
|
-
// seam) is omitted like any other over-budget body, and the omission is
|
|
553
|
-
// recorded via `truncatedBodies`, so the bounded
|
|
554
|
-
// `ast-grep-napi-html-script-budget` degradation record always explains
|
|
555
|
-
// why that file lost embedded coverage.
|
|
556
|
-
if (selected.length >= MAX_SCRIPT_BODIES_EVALUATED ||
|
|
557
|
-
budgetedBytes + bytes > MAX_SCRIPT_BODY_BYTES_EVALUATED) {
|
|
558
|
-
truncatedBodies += 1;
|
|
559
|
-
continue;
|
|
560
|
-
}
|
|
561
|
-
selected.push(candidate);
|
|
562
|
-
budgetedBytes += bytes;
|
|
563
|
-
}
|
|
564
|
-
const injections = [];
|
|
565
|
-
let parseFailures = 0;
|
|
566
|
-
for (const candidate of selected) {
|
|
567
|
-
try {
|
|
568
|
-
const root = addon.js.parse(candidate.body).root();
|
|
569
|
-
injections.push({
|
|
570
|
-
body: candidate.body,
|
|
571
|
-
startIndex: candidate.startIndex,
|
|
572
|
-
root,
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
catch {
|
|
576
|
-
parseFailures += 1;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
return {
|
|
580
|
-
injections,
|
|
581
|
-
scriptElementCount,
|
|
582
|
-
bodiesEvaluated: selected.length,
|
|
583
|
-
truncatedBodies,
|
|
584
|
-
parseFailures,
|
|
585
|
-
missingJsGrammar: false,
|
|
586
|
-
htmlScanFailure: false,
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
/**
|
|
590
|
-
* Emit bounded, discriminating degradation records for every embedded-script
|
|
591
|
-
* coverage loss (#2347 review F3). Each failure mode keeps its own kind so the
|
|
592
|
-
* ledger answers WHICH failure and WHICH file; subjects are the normalized file
|
|
593
|
-
* path, bounded by the ledger's own per-kind window. Collection failures
|
|
594
|
-
* (`missingJsGrammar`, `htmlScanFailure`) are once-per-file-per-session
|
|
595
|
-
* categorical events; parse failures and budget truncation are counted per file
|
|
596
|
-
* so the EXACT totals survive past the retained-entry window.
|
|
597
|
-
*/
|
|
598
|
-
function emitHtmlScriptDegradations(filePath, result) {
|
|
599
|
-
if (result.missingJsGrammar) {
|
|
600
|
-
recordDegradationOnce({
|
|
601
|
-
kind: "ast-grep-napi-html-js-grammar-missing",
|
|
602
|
-
subject: filePath,
|
|
603
|
-
reason: "addon exposes no js grammar; embedded <script> coverage dropped",
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
|
-
if (result.htmlScanFailure) {
|
|
607
|
-
recordDegradationOnce({
|
|
608
|
-
kind: "ast-grep-napi-html-script-scan-failed",
|
|
609
|
-
subject: filePath,
|
|
610
|
-
reason: "script_element enumeration failed; embedded <script> coverage dropped",
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
if (result.parseFailures > 0) {
|
|
614
|
-
incrementDegradationCount({
|
|
615
|
-
kind: "ast-grep-napi-html-script-parse-failed",
|
|
616
|
-
subject: filePath,
|
|
617
|
-
reason: `${result.parseFailures} of ${result.bodiesEvaluated} script bodies refused to parse as JS`,
|
|
618
|
-
metadata: {
|
|
619
|
-
scriptElementCount: result.scriptElementCount,
|
|
620
|
-
parseFailures: result.parseFailures,
|
|
621
|
-
},
|
|
622
|
-
});
|
|
623
|
-
}
|
|
624
|
-
if (result.truncatedBodies > 0) {
|
|
625
|
-
incrementDegradationCount({
|
|
626
|
-
kind: "ast-grep-napi-html-script-budget",
|
|
627
|
-
subject: filePath,
|
|
628
|
-
reason: `script budget truncated coverage: ${result.bodiesEvaluated}/${result.scriptElementCount} bodies evaluated, ${result.truncatedBodies} dropped`,
|
|
629
|
-
metadata: {
|
|
630
|
-
scriptElementCount: result.scriptElementCount,
|
|
631
|
-
bodiesEvaluated: result.bodiesEvaluated,
|
|
632
|
-
truncatedBodies: result.truncatedBodies,
|
|
633
|
-
},
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
function duplicateRuleIds(rules) {
|
|
638
|
-
const counts = new Map();
|
|
639
|
-
for (const rule of rules) {
|
|
640
|
-
counts.set(rule.id, (counts.get(rule.id) ?? 0) + 1);
|
|
641
|
-
}
|
|
642
|
-
return Array.from(counts)
|
|
643
|
-
.filter(([, count]) => count > 1)
|
|
644
|
-
.map(([id]) => id)
|
|
645
|
-
.sort((a, b) => a.localeCompare(b));
|
|
646
|
-
}
|
|
647
|
-
function appendDuplicateRuleDiagnostics(diagnostics, duplicateIds, source, filePath, maxTotalDiagnostics) {
|
|
648
|
-
const sourceLabel = `${source.origin} ${source.tier} rules`;
|
|
649
|
-
for (const ruleId of duplicateIds) {
|
|
650
|
-
diagnostics.push({
|
|
651
|
-
id: `ast-grep-napi-config-duplicate-${source.origin}-${source.tier}-${ruleId}`,
|
|
652
|
-
message: `Duplicate ast-grep rule id "${ruleId}" in ${sourceLabel}`,
|
|
653
|
-
filePath,
|
|
654
|
-
line: 1,
|
|
655
|
-
column: 1,
|
|
656
|
-
severity: "error",
|
|
657
|
-
semantic: "blocking",
|
|
658
|
-
tool: "ast-grep-napi",
|
|
659
|
-
rule: ruleId,
|
|
660
|
-
defectClass: "correctness",
|
|
661
|
-
fixable: false,
|
|
662
|
-
autoFixAvailable: false,
|
|
663
|
-
fixSuggestion: `Give every rule in ${sourceLabel} a unique id`,
|
|
664
|
-
});
|
|
665
|
-
if (diagnostics.length >= maxTotalDiagnostics)
|
|
666
|
-
return true;
|
|
667
|
-
}
|
|
668
|
-
return false;
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* The four tiers `Diagnostic.severity` accepts (clients/dispatch/types.ts).
|
|
672
|
-
* `YamlRule.severity` is a free-form string straight off disk, so an unknown
|
|
673
|
-
* or missing value must land somewhere deliberate rather than being cast.
|
|
674
|
-
*/
|
|
675
|
-
const DIAGNOSTIC_SEVERITY_TIERS = new Set([
|
|
676
|
-
"error",
|
|
677
|
-
"warning",
|
|
678
|
-
"info",
|
|
679
|
-
"hint",
|
|
680
|
-
]);
|
|
681
|
-
/**
|
|
682
|
-
* Map a rule's declared YAML severity onto a `Diagnostic.severity` tier (#1777).
|
|
683
|
-
*
|
|
684
|
-
* A rule that declares nothing, or declares a value pi-lens does not model
|
|
685
|
-
* (ast-grep also accepts `off`), falls back to `warning` — the tier every such
|
|
686
|
-
* rule already reported at before #1777, so reviving hint/info never silently
|
|
687
|
-
* demotes an existing rule.
|
|
688
|
-
*/
|
|
689
|
-
export function normalizeRuleSeverity(raw) {
|
|
690
|
-
const tier = raw;
|
|
691
|
-
return tier && DIAGNOSTIC_SEVERITY_TIERS.has(tier) ? tier : "warning";
|
|
692
|
-
}
|
|
693
|
-
/**
|
|
694
|
-
* Run the shipped ast-grep YAML ruleset against a parsed file via napi's native
|
|
695
|
-
* engine, applying the same suppression policy (linter/tree-sitter overlap,
|
|
696
|
-
* overly-broad-pattern guard) as the per-edit runner. Extracted so the
|
|
697
|
-
* project-wide scanner can reuse the identical engine + rules WITHOUT the
|
|
698
|
-
* ast-grep binary — closing the no-binary gap (#308) — while the per-edit runner
|
|
699
|
-
* keeps its tight budgets. Callers pass the already-parsed `rootNode` so they
|
|
700
|
-
* control parsing/size gating.
|
|
701
|
-
*/
|
|
702
|
-
export function evaluateAstGrepRules(filePath, rootNode, cwd, kind, options = {}) {
|
|
703
|
-
const maxMatchesPerRule = options.maxMatchesPerRule ?? MAX_MATCHES_PER_RULE;
|
|
704
|
-
const maxTotalDiagnostics = options.maxTotalDiagnostics ?? MAX_TOTAL_DIAGNOSTICS;
|
|
705
|
-
const blockingOnly = options.blockingOnly === true;
|
|
706
|
-
const log = options.log;
|
|
707
|
-
const unsupportedLanguageLog = options.unsupportedLanguageLog ?? defaultUnsupportedLanguageLog;
|
|
708
|
-
const diagnostics = [];
|
|
709
|
-
const suppressLinterOverlap = kind === "jsts" && hasEslintConfig(cwd);
|
|
710
|
-
const fileLang = ruleLanguageForFile(filePath);
|
|
711
|
-
// Embedded `<script>` coverage (#2347): on an HTML file, every script body
|
|
712
|
-
// is parsed as JavaScript and `language: JavaScript` rules run inside it —
|
|
713
|
-
// the exact behavior the ast-grep CLI/LSP has (verified against 0.45.1).
|
|
714
|
-
// `content` + `sgModule` are only needed for HTML; other callers of this
|
|
715
|
-
// shared seam (the per-edit runner and the project scanner both now pass
|
|
716
|
-
// them) cost a no-op on non-HTML files. The collection is budget-bounded
|
|
717
|
-
// and every silent-failure mode plus the budget cut is recorded, so "no
|
|
718
|
-
// embedded findings" stays distinguishable from "coverage was dropped"
|
|
719
|
-
// (#2347 review F2/F3).
|
|
720
|
-
const htmlCollection = fileLang === "html" &&
|
|
721
|
-
options.content !== undefined &&
|
|
722
|
-
options.sgModule !== undefined
|
|
723
|
-
? collectHtmlScriptInjections(rootNode, options.sgModule)
|
|
724
|
-
: {
|
|
725
|
-
injections: [],
|
|
726
|
-
scriptElementCount: 0,
|
|
727
|
-
bodiesEvaluated: 0,
|
|
728
|
-
truncatedBodies: 0,
|
|
729
|
-
parseFailures: 0,
|
|
730
|
-
missingJsGrammar: false,
|
|
731
|
-
htmlScanFailure: false,
|
|
732
|
-
};
|
|
733
|
-
const htmlInjections = htmlCollection.injections;
|
|
734
|
-
emitHtmlScriptDegradations(filePath, htmlCollection);
|
|
735
|
-
// UTF-16 code-unit index of each line start in the ORIGINAL file, used to
|
|
736
|
-
// translate an injected match's body-relative UTF-16 index back to file
|
|
737
|
-
// line/column. The unit matters: napi positions are UTF-16, so a UTF-8 byte
|
|
738
|
-
// table would shift every coordinate after a multibyte character (#2347
|
|
739
|
-
// review F1).
|
|
740
|
-
const fileLineStarts = htmlInjections.length > 0 && options.content !== undefined
|
|
741
|
-
? computeLineStartsUtf16(options.content)
|
|
742
|
-
: [];
|
|
743
|
-
// Unsupported-language skips are expected in bulk (every non-jsts rule in the
|
|
744
|
-
// catalog, e.g. ~30 Python rules) — aggregate them into ONE latency-log entry
|
|
745
|
-
// per evaluation instead of per-rule terminal lines (#282 follow-up).
|
|
746
|
-
const newlyUnsupported = new Map();
|
|
747
|
-
const flushUnsupportedRuleSkips = () => {
|
|
748
|
-
if (newlyUnsupported.size === 0)
|
|
749
|
-
return;
|
|
750
|
-
const firstSeenLanguages = Array.from(newlyUnsupported.entries()).filter(([language]) => !unsupportedLanguageLog.has(language));
|
|
751
|
-
for (const [language] of firstSeenLanguages) {
|
|
752
|
-
unsupportedLanguageLog.add(language);
|
|
753
|
-
}
|
|
754
|
-
if (firstSeenLanguages.length === 0) {
|
|
755
|
-
newlyUnsupported.clear();
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
for (const [language] of firstSeenLanguages)
|
|
759
|
-
unsupportedLanguageLog.add(language);
|
|
760
|
-
logLatency({
|
|
761
|
-
type: "phase",
|
|
762
|
-
phase: "astgrep_napi_unsupported_rules_skipped",
|
|
763
|
-
filePath,
|
|
764
|
-
durationMs: 0,
|
|
765
|
-
metadata: {
|
|
766
|
-
skippedByLanguage: Object.fromEntries(firstSeenLanguages.map(([language, ruleIds]) => [
|
|
767
|
-
language,
|
|
768
|
-
{
|
|
769
|
-
count: ruleIds.length,
|
|
770
|
-
ruleIds: ruleIds.slice(0, UNSUPPORTED_RULE_ID_SAMPLE_SIZE),
|
|
771
|
-
// #2215: a skip count alone says a rule did not run and
|
|
772
|
-
// nothing about whether it runs anywhere else. `route` names
|
|
773
|
-
// the delivery path (`ast-grep-lsp-cli` for the twelve
|
|
774
|
-
// grammar-less catalog languages); `unclassified` means rules
|
|
775
|
-
// ship for a language nobody decided a route for, which is the
|
|
776
|
-
// class this issue closed regrowing.
|
|
777
|
-
route: skipRouteFor(language),
|
|
778
|
-
// #2347 observability: on an HTML file the per-language skip
|
|
779
|
-
// count is only part of the picture — `mismatch:*->html`
|
|
780
|
-
// entries name a rule family that never enters scripts, and
|
|
781
|
-
// `htmlInlineScriptCount` says whether the file offered any
|
|
782
|
-
// script bodies to enter. A `javascript->html` mismatch here
|
|
783
|
-
// is necessarily `0` (JS rules RUN when scripts exist), so the
|
|
784
|
-
// field makes "no injection target" distinguishable from the
|
|
785
|
-
// same key on a plain non-HTML file, keeping the residual
|
|
786
|
-
// coverage gap countable in production.
|
|
787
|
-
...(fileLang === "html"
|
|
788
|
-
? { htmlInlineScriptCount: htmlInjections.length }
|
|
789
|
-
: {}),
|
|
790
|
-
},
|
|
791
|
-
])),
|
|
792
|
-
},
|
|
793
|
-
});
|
|
794
|
-
newlyUnsupported.clear();
|
|
795
|
-
};
|
|
796
|
-
// Same walk and precedence the LSP-seam matcher uses
|
|
797
|
-
// (clients/dispatch/rule-ignores.ts), folded onto one derivation by #3053
|
|
798
|
-
// after #3046 shipped them as two independently-drifting copies.
|
|
799
|
-
const ignoreRoot = options.projectRoot ?? cwd;
|
|
800
|
-
const catalog = buildEffectiveAstGrepCatalog(ignoreRoot);
|
|
801
|
-
for (const { source, rules } of catalog.sources) {
|
|
802
|
-
const duplicates = duplicateRuleIds(rules);
|
|
803
|
-
if (appendDuplicateRuleDiagnostics(diagnostics, duplicates, source, filePath, maxTotalDiagnostics)) {
|
|
804
|
-
flushUnsupportedRuleSkips();
|
|
805
|
-
return diagnostics;
|
|
806
|
-
}
|
|
807
|
-
const duplicateSet = new Set(duplicates);
|
|
808
|
-
for (const rule of rules) {
|
|
809
|
-
if (duplicateSet.has(rule.id))
|
|
810
|
-
continue;
|
|
811
|
-
// Cross-layer collisions keep the first (higher-precedence) source —
|
|
812
|
-
// resolved once by `buildEffectiveAstGrepCatalog`, not per-rule here.
|
|
813
|
-
// Compares the winning DOCUMENT (object identity), not merely its
|
|
814
|
-
// source: comparing `.source` alone can't tell a within-source
|
|
815
|
-
// duplicate's two copies apart (they share one source), so it gave
|
|
816
|
-
// no defense if `duplicateSet.has` above were ever the only guard
|
|
817
|
-
// standing (#3053 round 2 F1). Every `rule` iterated here is the
|
|
818
|
-
// same object instance the catalog recorded, since both read the
|
|
819
|
-
// identical `rules` arrays off `catalog.sources`.
|
|
820
|
-
if (catalog.effectiveRules.get(rule.id)?.rule !== rule)
|
|
821
|
-
continue;
|
|
822
|
-
if (blockingOnly && rule.severity !== "error")
|
|
823
|
-
continue;
|
|
824
|
-
// Per-rule path carve-out (#965): a rule that's noise on CLI scripts or
|
|
825
|
-
// a project's own logging sink (e.g. no-console-except-error firing
|
|
826
|
-
// inside scripts/** or lib/logger.ts) opts out via `ignores`.
|
|
827
|
-
if (isRuleIgnoredForPath(filePath, ignoreRoot, rule.ignores))
|
|
828
|
-
continue;
|
|
829
|
-
if (suppressLinterOverlap &&
|
|
830
|
-
LINTER_OVERLAP.has(normalizeRuleId(rule.id)) &&
|
|
831
|
-
!NON_SUPPRESSIBLE.has(normalizeRuleId(rule.id))) {
|
|
832
|
-
continue;
|
|
833
|
-
}
|
|
834
|
-
// Skip rules whose top-level pattern is overly broad ($NAME, $X, etc.)
|
|
835
|
-
// without additional structural constraints to narrow matches.
|
|
836
|
-
if (rule.rule &&
|
|
837
|
-
isOverlyBroadPattern(rule.rule.pattern) &&
|
|
838
|
-
!isStructuredRule(rule)) {
|
|
839
|
-
continue;
|
|
840
|
-
}
|
|
841
|
-
// CSS and HTML rules are scoped to their parsed roots.
|
|
842
|
-
// Without this scope, language-tagged rules scan unrelated roots.
|
|
843
|
-
// The file-language mismatch check below enforces this scope.
|
|
844
|
-
// CSS rules therefore run only on CSS roots.
|
|
845
|
-
// This preserves CSS rule findings while avoiding unrelated scans.
|
|
846
|
-
// The fallback and LSP paths share the same parsed-language scope.
|
|
847
|
-
const lang = rule.language?.toLowerCase();
|
|
848
|
-
if (lang && !SUPPORTED_RULE_LANGUAGES.includes(lang)) {
|
|
849
|
-
if (!unsupportedLanguageLog.has(lang)) {
|
|
850
|
-
const ids = newlyUnsupported.get(lang) ?? [];
|
|
851
|
-
ids.push(rule.id);
|
|
852
|
-
newlyUnsupported.set(lang, ids);
|
|
853
|
-
}
|
|
854
|
-
continue;
|
|
855
|
-
}
|
|
856
|
-
// Scope TypeScript/JavaScript-tagged rules to the file's actual
|
|
857
|
-
// grammar (#657) — otherwise a `-js` twin sharing generic node
|
|
858
|
-
// kinds with its TS sibling double-fires on every .ts file. TSX
|
|
859
|
-
// is the one deliberate exception (#1608): the tsx grammar is a
|
|
860
|
-
// syntactic superset of typescript's for every non-JSX construct
|
|
861
|
-
// (the `<T>expr` cast form is the only TS-only production, and
|
|
862
|
-
// it can't appear in valid .tsx source anyway), so a
|
|
863
|
-
// `language: TypeScript` rule still matches a tsx-parsed root
|
|
864
|
-
// and must run there too, or the entire TS ruleset (120 of 263
|
|
865
|
-
// rules) goes dark on every .tsx file. `language: TSX` rules
|
|
866
|
-
// stay tsx-exclusive — they're already scoped to fileLang
|
|
867
|
-
// "tsx" by the exact-match check.
|
|
868
|
-
// #2347: `language: JavaScript` rules run INSIDE an HTML file's
|
|
869
|
-
// embedded `<script>` bodies instead of being filtered out as a
|
|
870
|
-
// language mismatch — that filter is what closed napi's embedded
|
|
871
|
-
// coverage entirely while the ast-grep CLI/LSP resolves the
|
|
872
|
-
// injections itself. Only when the file has at least one inline
|
|
873
|
-
// script body; with none, a `javascript->html` rule stays a
|
|
874
|
-
// genuine mismatch with nothing to run against (countable via
|
|
875
|
-
// `htmlInlineScriptCount` in the skip record).
|
|
876
|
-
const runsInsideHtmlScript = fileLang === "html" &&
|
|
877
|
-
lang === "javascript" &&
|
|
878
|
-
htmlInjections.length > 0;
|
|
879
|
-
if (lang && fileLang && lang !== fileLang) {
|
|
880
|
-
const runsAsTsOnTsx = fileLang === "tsx" && lang === "typescript";
|
|
881
|
-
if (!runsAsTsOnTsx && !runsInsideHtmlScript) {
|
|
882
|
-
const key = `mismatch:${lang}->${fileLang}`;
|
|
883
|
-
if (!unsupportedLanguageLog.has(key)) {
|
|
884
|
-
const ids = newlyUnsupported.get(key) ?? [];
|
|
885
|
-
ids.push(rule.id);
|
|
886
|
-
newlyUnsupported.set(key, ids);
|
|
887
|
-
}
|
|
888
|
-
continue;
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
if (blockingOnly && rule.rule) {
|
|
892
|
-
const complexity = calculateRuleComplexity(rule.rule);
|
|
893
|
-
if (complexity > MAX_BLOCKING_RULE_COMPLEXITY) {
|
|
894
|
-
continue;
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
if (!rule.rule)
|
|
898
|
-
continue;
|
|
899
|
-
try {
|
|
900
|
-
// A `language: JavaScript` rule on an HTML file with inline
|
|
901
|
-
// scripts runs against EACH parsed script body; every other rule
|
|
902
|
-
// runs against the file root. `scope.position` maps a match onto
|
|
903
|
-
// 0-based FILE line/column — injection matches are body-relative
|
|
904
|
-
// and must be translated via the injection's `startIndex` and the
|
|
905
|
-
// file's line-start table, all in UTF-16 code units (#2347); the
|
|
906
|
-
// file-root scope is the node's own range, so its derived
|
|
907
|
-
// id/diagnostic stay byte-identical to the pre-#2347 path.
|
|
908
|
-
const scopes = runsInsideHtmlScript
|
|
909
|
-
? htmlInjections.map((injection) => ({
|
|
910
|
-
root: injection.root,
|
|
911
|
-
position(match) {
|
|
912
|
-
const start = match.range().start;
|
|
913
|
-
return filePositionForIndex(fileLineStarts, injection.startIndex + start.index);
|
|
914
|
-
},
|
|
915
|
-
}))
|
|
916
|
-
: [
|
|
917
|
-
{
|
|
918
|
-
root: rootNode,
|
|
919
|
-
position(match) {
|
|
920
|
-
const start = match.range().start;
|
|
921
|
-
return { line: start.line, column: start.column };
|
|
922
|
-
},
|
|
923
|
-
},
|
|
924
|
-
];
|
|
925
|
-
// Delegate matching to napi's native engine, which handles the
|
|
926
|
-
// full ast-grep rule grammar (pattern, kind, has/inside/follows/
|
|
927
|
-
// precedes/stopBy/field/nthChild, any/all/not) plus metavariable
|
|
928
|
-
// `constraints` (#206) AND top-level `utils` — reusable named
|
|
929
|
-
// matchers referenced via `matches: <name>` inside `rule`
|
|
930
|
-
// (#663; `NapiConfig.utils: Record<string, Rule>` per
|
|
931
|
-
// @ast-grep/napi's types, same shape napi already expects for
|
|
932
|
-
// `rule`/`constraints`). A faithful js-yaml parse feeds the rule
|
|
933
|
-
// object straight through. If napi rejects the rule for a scope
|
|
934
|
-
// (a malformed or invalid-kind rule, or an unresolved `matches:`
|
|
935
|
-
// reference), skip that scope — never silently match nothing
|
|
936
|
-
// through a partial interpreter. The reject log fires once per
|
|
937
|
-
// rule; a grammar-level rejection is uniform across scopes.
|
|
938
|
-
const nativeConfig = { rule: rule.rule };
|
|
939
|
-
if (rule.constraints)
|
|
940
|
-
nativeConfig.constraints = rule.constraints;
|
|
941
|
-
if (rule.utils)
|
|
942
|
-
nativeConfig.utils = rule.utils;
|
|
943
|
-
const collected = [];
|
|
944
|
-
let rejectLogged = false;
|
|
945
|
-
for (const scope of scopes) {
|
|
946
|
-
let found;
|
|
947
|
-
try {
|
|
948
|
-
found = scope.root.findAll(nativeConfig);
|
|
949
|
-
}
|
|
950
|
-
catch (err) {
|
|
951
|
-
if (!rejectLogged) {
|
|
952
|
-
rejectLogged = true;
|
|
953
|
-
log?.(`ast-grep-napi: rule "${rule.id}" rejected by native engine (${err instanceof Error ? err.message : String(err)})`);
|
|
954
|
-
}
|
|
955
|
-
continue;
|
|
956
|
-
}
|
|
957
|
-
for (const match of found) {
|
|
958
|
-
if (collected.length >= maxMatchesPerRule)
|
|
959
|
-
break;
|
|
960
|
-
collected.push({ match, position: scope.position(match) });
|
|
961
|
-
}
|
|
962
|
-
if (collected.length >= maxMatchesPerRule)
|
|
963
|
-
break;
|
|
964
|
-
}
|
|
965
|
-
for (const { position } of collected) {
|
|
966
|
-
if (diagnostics.length >= maxTotalDiagnostics)
|
|
967
|
-
break;
|
|
968
|
-
// #1777: carry the rule's own tier through. The old collapse
|
|
969
|
-
// (`=== "error" ? "error" : "warning"`) erased hint and info,
|
|
970
|
-
// so the quiet tier the #1727 anti-slop rules ship at did not
|
|
971
|
-
// exist anywhere downstream. `Diagnostic.severity` has been
|
|
972
|
-
// 4-valued all along (clients/dispatch/types.ts). The BLOCKING
|
|
973
|
-
// gate is unchanged and deliberately narrower: only `error`
|
|
974
|
-
// blocks, so hint and info stay advisory exactly like warning.
|
|
975
|
-
const severity = normalizeRuleSeverity(rule.severity);
|
|
976
|
-
const semantic = severity === "error" ? "blocking" : "warning";
|
|
977
|
-
const defectClass = classifyDefect(rule.id, "ast-grep-napi", rule.message || rule.id);
|
|
978
|
-
const ruleFix = explicitRuleFixSuggestion(rule);
|
|
979
|
-
diagnostics.push({
|
|
980
|
-
id: `ast-grep-napi-${position.line}-${rule.id}`,
|
|
981
|
-
message: `[${rule.metadata?.category || "slop"}] ${rule.message || rule.id}`,
|
|
982
|
-
filePath,
|
|
983
|
-
line: position.line + 1,
|
|
984
|
-
column: position.column + 1,
|
|
985
|
-
severity,
|
|
986
|
-
semantic,
|
|
987
|
-
tool: "ast-grep-napi",
|
|
988
|
-
rule: rule.id,
|
|
989
|
-
defectClass,
|
|
990
|
-
fixable: !!ruleFix,
|
|
991
|
-
autoFixAvailable: false,
|
|
992
|
-
fixKind: ruleFix ? "suggestion" : undefined,
|
|
993
|
-
fixSuggestion: semantic === "blocking"
|
|
994
|
-
? (ruleFix ?? defaultFixSuggestion(defectClass, rule.id))
|
|
995
|
-
: ruleFix,
|
|
996
|
-
});
|
|
997
|
-
}
|
|
998
|
-
if (diagnostics.length >= maxTotalDiagnostics)
|
|
999
|
-
break;
|
|
1000
|
-
}
|
|
1001
|
-
catch {
|
|
1002
|
-
// Rule failed, skip
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
flushUnsupportedRuleSkips();
|
|
1007
|
-
return diagnostics;
|
|
1008
|
-
}
|
|
1009
|
-
// --- Runner Definition ---
|
|
1010
|
-
const astGrepNapiRunner = {
|
|
1011
|
-
id: "ast-grep-napi",
|
|
1012
|
-
appliesTo: ["jsts", "css", "html"],
|
|
1013
|
-
priority: PRIORITY.SPECIALIZED_ANALYSIS,
|
|
1014
|
-
skipTestFiles: true,
|
|
1015
|
-
async run(ctx) {
|
|
1016
|
-
if (!canHandle(ctx.filePath)) {
|
|
1017
|
-
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
1018
|
-
}
|
|
1019
|
-
// #239 Phase 2: the ast-grep LSP supersedes this in-process runner when its
|
|
1020
|
-
// binary is available — same Rust engine, plus codeAction fixes, and it runs
|
|
1021
|
-
// the shipped baseline ruleset via `--config`. Skip here so we don't double-
|
|
1022
|
-
// report against the LSP's `tool: ast-grep` diagnostics. Resume ONLY as the
|
|
1023
|
-
// fallback when the binary is absent / can't spawn (Gate B).
|
|
1024
|
-
const astGrepLspEnabled = enabledAuxiliaryLspServerIds((f) => ctx.pi?.getFlag?.(f)).includes("ast-grep");
|
|
1025
|
-
// Gate B asks whether the LSP has proved it can handle this root, not
|
|
1026
|
-
// whether an ast-grep process or binary merely exists.
|
|
1027
|
-
// A first publication covers the warm case. Process liveness and binary
|
|
1028
|
-
// resolution do not: both precede proof that this root can publish findings.
|
|
1029
|
-
const astGrepLspPublished = astGrepLspEnabled
|
|
1030
|
-
? await hasAuxiliaryLspPublishedForRoot("ast-grep", ctx.filePath)
|
|
1031
|
-
: false;
|
|
1032
|
-
if (astGrepLspEnabled && astGrepLspPublished) {
|
|
1033
|
-
// #2324 F2/R2-C: "has this server EVER published for this file" can go
|
|
1034
|
-
// stale — a LATER touch's aux-grace wait can find the server silent
|
|
1035
|
-
// for the CURRENT content while an OLDER revision's publication still
|
|
1036
|
-
// satisfies this per-file gate. Any pending late-aux entry visible
|
|
1037
|
-
// HERE is necessarily a LEFTOVER from an earlier touch, never this
|
|
1038
|
-
// one: the wait that marks a pair for THIS touch runs to completion
|
|
1039
|
-
// (up to its own grace budget, ~1800ms) strictly AFTER this
|
|
1040
|
-
// synchronous Gate-B check returns, so it cannot have marked
|
|
1041
|
-
// anything yet. Re-running napi here would risk the F3 duplicate
|
|
1042
|
-
// this fix closes, so the loss is made observable instead.
|
|
1043
|
-
if (hasPendingAuxiliaryCoverage(ctx.filePath, "ast-grep")) {
|
|
1044
|
-
incrementDegradationCount({
|
|
1045
|
-
kind: "aux-runner-findings-lost",
|
|
1046
|
-
subject: "ast-grep",
|
|
1047
|
-
reason: `Gate B skipped napi for ${ctx.filePath}: a pending late-auxiliary pair from an EARLIER touch is still undelivered while a prior publication satisfies the per-file gate`,
|
|
1048
|
-
});
|
|
1049
|
-
}
|
|
1050
|
-
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
1051
|
-
}
|
|
1052
|
-
const sgModule = await loadSg();
|
|
1053
|
-
if (!sgModule) {
|
|
1054
|
-
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
1055
|
-
}
|
|
1056
|
-
if (!fs.existsSync(ctx.filePath)) {
|
|
1057
|
-
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
1058
|
-
}
|
|
1059
|
-
const lang = getLang(ctx.filePath, sgModule);
|
|
1060
|
-
if (!lang) {
|
|
1061
|
-
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
1062
|
-
}
|
|
1063
|
-
let stats;
|
|
1064
|
-
try {
|
|
1065
|
-
stats = fs.statSync(ctx.filePath);
|
|
1066
|
-
}
|
|
1067
|
-
catch {
|
|
1068
|
-
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
1069
|
-
}
|
|
1070
|
-
if (stats.size > 1024 * 1024) {
|
|
1071
|
-
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
1072
|
-
}
|
|
1073
|
-
let content;
|
|
1074
|
-
const contentFromFacts = ctx.facts.getFileFact(ctx.filePath, "file.content");
|
|
1075
|
-
if (contentFromFacts !== undefined && contentFromFacts !== null) {
|
|
1076
|
-
content = contentFromFacts;
|
|
1077
|
-
}
|
|
1078
|
-
else {
|
|
1079
|
-
try {
|
|
1080
|
-
content = fs.readFileSync(ctx.filePath, "utf-8");
|
|
1081
|
-
}
|
|
1082
|
-
catch {
|
|
1083
|
-
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
let root;
|
|
1087
|
-
try {
|
|
1088
|
-
root = lang.parse(content);
|
|
1089
|
-
}
|
|
1090
|
-
catch {
|
|
1091
|
-
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
1092
|
-
}
|
|
1093
|
-
let rootNode;
|
|
1094
|
-
try {
|
|
1095
|
-
rootNode = root.root();
|
|
1096
|
-
}
|
|
1097
|
-
catch {
|
|
1098
|
-
return { status: "skipped", diagnostics: [], semantic: "none" };
|
|
1099
|
-
}
|
|
1100
|
-
// #2336: napi is standing in for the ast-grep auxiliary LSP exactly when
|
|
1101
|
-
// that server is expected but has not published for this root. Gate B
|
|
1102
|
-
// above already returned for the published case, so reaching here with
|
|
1103
|
-
// the auxiliary enabled IS the substitute role.
|
|
1104
|
-
const runningAsLspSubstitute = astGrepLspEnabled && !astGrepLspPublished;
|
|
1105
|
-
if (runningAsLspSubstitute) {
|
|
1106
|
-
// #2324 F3/R2-A/R2-B: napi is about to ACTUALLY EVALUATE RULES —
|
|
1107
|
-
// every early-return skip above (load failure, missing file,
|
|
1108
|
-
// unresolved language, stat/size/read/parse failure) is now behind
|
|
1109
|
-
// us, so this run genuinely covers the file rather than reporting a
|
|
1110
|
-
// zero-finding no-op. Placing this here (not at Gate-B's decision
|
|
1111
|
-
// point) matters twice over:
|
|
1112
|
-
// - R2-B: a napi run that never reached rule evaluation must NOT
|
|
1113
|
-
// consume anything — an unparseable .html file, say, would
|
|
1114
|
-
// otherwise silence the LSP's legitimate late delivery for a
|
|
1115
|
-
// file napi never actually covered.
|
|
1116
|
-
// - R2-A: recording coverage HERE, keyed by timestamp, lets the
|
|
1117
|
-
// aux-grace wait (clients/lsp/index.ts) — which decides whether
|
|
1118
|
-
// to mark a pending pair for THIS touch strictly AFTER this
|
|
1119
|
-
// synchronous call returns — see that napi already delivered
|
|
1120
|
-
// and skip marking, instead of racing a clear against a mark
|
|
1121
|
-
// that has not been written yet.
|
|
1122
|
-
// The clear below only ever removes a LEFTOVER pair from an
|
|
1123
|
-
// EARLIER touch (this touch's own pair, if the wait decides to
|
|
1124
|
-
// mark one, is marked strictly later) — that pair describes a
|
|
1125
|
-
// PREVIOUS revision this fresh evaluation supersedes, so dropping
|
|
1126
|
-
// it is safe. Unknown pairs are a no-op.
|
|
1127
|
-
recordNapiFallbackCoverage(ctx.filePath);
|
|
1128
|
-
clearPendingAuxiliaryCoverage(ctx.filePath, "ast-grep");
|
|
1129
|
-
}
|
|
1130
|
-
// #2336: the substitute runs at the severity floor the server it replaces
|
|
1131
|
-
// would have used. The ast-grep auxiliary profile states that floor in
|
|
1132
|
-
// words — "the rule severity is deliberate, so preserve ast-grep's
|
|
1133
|
-
// severity semantics: ERROR can block, WARNING/INFO stay advisory"
|
|
1134
|
-
// (clients/dispatch/auxiliary-lsp.ts:179-183). `blockingOnly` drops every
|
|
1135
|
-
// rule whose declared severity is not `error`, which is 380 of the 481
|
|
1136
|
-
// bundled rules, so the substitute delivered a fifth of the coverage the
|
|
1137
|
-
// LSP delivers and the runner reported zero diagnostics in all 255
|
|
1138
|
-
// retained dispatch records. Nothing downstream needs the filter for
|
|
1139
|
-
// noise control: `dispatcher.ts` already shows only `semantic:
|
|
1140
|
-
// "blocking"` diagnostics inline and routes warning-tier ones to
|
|
1141
|
-
// lens_diagnostics, and `tree-sitter.ts:525` already runs its full query
|
|
1142
|
-
// set under `blockingOnly` for the same reason.
|
|
1143
|
-
//
|
|
1144
|
-
// Scoped to the substitute role deliberately. Evaluating the full catalog
|
|
1145
|
-
// costs ~6x more per file (measured on this repo: 2.4 ms -> 23 ms at 68
|
|
1146
|
-
// lines, 19 ms -> 188 ms at 1275 lines), and outside the substitute role
|
|
1147
|
-
// either the LSP is publishing (Gate B skipped napi already) or the user
|
|
1148
|
-
// retired ast-grep with `no-ast-grep`. Paying the cost only when napi is
|
|
1149
|
-
// the sole ast-grep surface buys coverage that nothing else provides.
|
|
1150
|
-
const diagnostics = evaluateAstGrepRules(ctx.filePath, rootNode, ctx.cwd, ctx.kind, {
|
|
1151
|
-
blockingOnly: runningAsLspSubstitute ? false : ctx.blockingOnly,
|
|
1152
|
-
projectRoot: ctx.projectRoot,
|
|
1153
|
-
log: (message) => ctx.log(message),
|
|
1154
|
-
content,
|
|
1155
|
-
sgModule,
|
|
1156
|
-
});
|
|
1157
|
-
if (runningAsLspSubstitute) {
|
|
1158
|
-
// #2336 observability: the dispatcher's own runner record carries
|
|
1159
|
-
// `diagnosticCount`, which is what showed 0 of 255. It cannot say WHICH
|
|
1160
|
-
// severity floor produced that count. One line per substitute run —
|
|
1161
|
-
// the same cadence as the runner record it annotates — names the floor
|
|
1162
|
-
// and the tier mix, so a future "napi found nothing" reading can tell
|
|
1163
|
-
// an empty catalog pass from a filtered one.
|
|
1164
|
-
const bySeverity = {};
|
|
1165
|
-
for (const d of diagnostics) {
|
|
1166
|
-
bySeverity[d.severity] = (bySeverity[d.severity] ?? 0) + 1;
|
|
1167
|
-
}
|
|
1168
|
-
logLatency({
|
|
1169
|
-
type: "phase",
|
|
1170
|
-
phase: "astgrep_napi_substitute_floor",
|
|
1171
|
-
filePath: ctx.filePath,
|
|
1172
|
-
durationMs: 0,
|
|
1173
|
-
metadata: {
|
|
1174
|
-
floor: "lsp-equivalent",
|
|
1175
|
-
ctxBlockingOnly: ctx.blockingOnly === true,
|
|
1176
|
-
diagnosticCount: diagnostics.length,
|
|
1177
|
-
bySeverity,
|
|
1178
|
-
},
|
|
1179
|
-
});
|
|
1180
|
-
}
|
|
1181
|
-
const hasBlocking = diagnostics.some((d) => d.semantic === "blocking");
|
|
1182
|
-
let semantic = "none";
|
|
1183
|
-
if (hasBlocking) {
|
|
1184
|
-
semantic = "blocking";
|
|
1185
|
-
}
|
|
1186
|
-
else if (diagnostics.length > 0) {
|
|
1187
|
-
semantic = "warning";
|
|
1188
|
-
}
|
|
1189
|
-
return {
|
|
1190
|
-
status: hasBlocking ? "failed" : "succeeded",
|
|
1191
|
-
diagnostics,
|
|
1192
|
-
semantic,
|
|
1193
|
-
};
|
|
1194
|
-
},
|
|
1195
|
-
};
|
|
1196
|
-
export default astGrepNapiRunner;
|