@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,1480 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Post-write pipeline for pi-lens
|
|
3
|
-
*
|
|
4
|
-
* Extracted from index.ts tool_result handler.
|
|
5
|
-
* Runs sequentially on every file write/edit:
|
|
6
|
-
* 1. Secrets scan (blocking — early exit)
|
|
7
|
-
* 2. Auto-format (Biome, Prettier, Ruff, gofmt, etc.)
|
|
8
|
-
* 3. Auto-fix (Biome --write, Ruff --fix, ESLint --fix)
|
|
9
|
-
* 4. LSP file sync (open/update in LSP servers)
|
|
10
|
-
* 5. Dispatch lint (type errors, security rules)
|
|
11
|
-
* 6. Test runner (run corresponding test file)
|
|
12
|
-
* 7. Cascade diagnostics (other files with errors, LSP only)
|
|
13
|
-
*/
|
|
14
|
-
import { createHash } from "node:crypto";
|
|
15
|
-
import * as nodeFs from "node:fs";
|
|
16
|
-
import * as nodeCrypto from "node:crypto";
|
|
17
|
-
import * as path from "node:path";
|
|
18
|
-
import { findNearestContaining, normalizeEphemeralMapKey, } from "./path-utils.js";
|
|
19
|
-
import { recordFromDispatchDiagnostic, } from "./actionable-warnings.js";
|
|
20
|
-
import { recordFromCodeQualityDiagnostic, } from "./code-quality-warnings.js";
|
|
21
|
-
import { admitWidgetDiagnosticsWrite, recordDiagnostics, } from "./widget-state.js";
|
|
22
|
-
import { getDiagnosticLogger } from "./diagnostic-logger.js";
|
|
23
|
-
import { getDiagnosticTracker } from "./diagnostic-tracker.js";
|
|
24
|
-
import { loadDispatchIntegration } from "./dispatch/lazy.js";
|
|
25
|
-
import { toRunnerDisplayPath } from "./dispatch/runner-context.js";
|
|
26
|
-
import { classifyProbeFailure, createAvailabilityChecker, createAvailabilityLatch, describeProbeEvidence, logAvailabilityDecision, startHostStallSampler, resolveAvailableOrInstall, resolveCommandArgsWithInstallFallback, resolveToolCommand, resolveToolCommandWithInstallFallback, } from "./dispatch/runners/utils/runner-helpers.js";
|
|
27
|
-
import { findDetektConfig } from "./dispatch/runners/detekt.js";
|
|
28
|
-
import { formatDiagnostics } from "./dispatch/utils/format-utils.js";
|
|
29
|
-
import { detectFileKind, getFileKindLabel } from "./file-kinds.js";
|
|
30
|
-
import { detectFileChangedAfterCommand, getProjectIgnoreMatcher, isExcludedDirName, } from "./file-utils.js";
|
|
31
|
-
import { logLatency } from "./latency-logger.js";
|
|
32
|
-
import { emitLensAnalysisComplete } from "./lens-events.js";
|
|
33
|
-
import { publishFilesTouched } from "./bus-publish.js";
|
|
34
|
-
import { publishDiagnostics, wasPreviouslyReportedDirty, } from "./diagnostics-publish.js";
|
|
35
|
-
import { loadLspService } from "./lsp-lazy.js";
|
|
36
|
-
import { clearGraphCache } from "./review-graph/builder.js";
|
|
37
|
-
import { BoundedLruCache } from "./bounded-cache.js";
|
|
38
|
-
import { RUNTIME_CONFIG } from "./runtime-config.js";
|
|
39
|
-
import { getAmbientAbortSignal, safeSpawnAsync } from "./safe-spawn.js";
|
|
40
|
-
import { probeToolAsync } from "./tool-probe.js";
|
|
41
|
-
import { bounded } from "./deadline-utils.js";
|
|
42
|
-
import { HOOK_WALL_BUDGET_MS } from "./hook-budgets.js";
|
|
43
|
-
import { enabledAuxiliaryLspServerIds } from "./dispatch/auxiliary-lsp.js";
|
|
44
|
-
import { incrementDegradationCount, recordDegradationOnce, } from "./degradation-ledger.js";
|
|
45
|
-
import { establishToolAgreement } from "./tool-agreement.js";
|
|
46
|
-
import { dropFindingsForMissingPaths } from "./advisory-provenance.js";
|
|
47
|
-
import { getAutofixPolicyForFile, getPreferredAutofixTools, getRubocopCommand, hasBiomeConfig, hasDetektConfig, hasEslintConfig, hasGolangciConfig, hasKtfmtConfig, hasKtlintConfig, hasOxlintConfig, hasRubocopConfig, hasSqlfluffConfig, hasStylelintConfig, markdownlintConfigArgs, } from "./tool-policy.js";
|
|
48
|
-
import { exceedsLspSyncLimits } from "./lsp/content-limits.js";
|
|
49
|
-
const LSP_SPAWN_BUDGET_MS = RUNTIME_CONFIG.pipeline.lspSpawnBudgetMs;
|
|
50
|
-
const AUTOFIX_CHANGED_FILE_SCAN_LIMIT = 5000;
|
|
51
|
-
/**
|
|
52
|
-
* Hard ceiling for the pre-dispatch LSP sync (`resyncLspFile`). The sync sends a
|
|
53
|
-
* didChange/didOpen; that write can backpressure indefinitely when the language
|
|
54
|
-
* server's stdin isn't being drained (a wedged/CPU-bound server), which would
|
|
55
|
-
* hang the whole edit with no per-call bound — client acquisition is capped, but
|
|
56
|
-
* the notify write is not. So the sync is abandoned after this budget (the edit
|
|
57
|
-
* proceeds; the dispatch LSP runner, which has its own 30s cap, still tries).
|
|
58
|
-
*/
|
|
59
|
-
function lspSyncBudgetMs() {
|
|
60
|
-
const raw = Number(process.env.PI_LENS_LSP_SYNC_BUDGET_MS);
|
|
61
|
-
return Number.isFinite(raw) && raw > 0 ? raw : 3000;
|
|
62
|
-
}
|
|
63
|
-
// Files stat'd between event-loop yields. The walk stays on the tool_result
|
|
64
|
-
// hot path; yielding every N keeps its longest synchronous stretch well under
|
|
65
|
-
// the <50ms hook-burst budget even at the AUTOFIX_CHANGED_FILE_SCAN_LIMIT cap.
|
|
66
|
-
const SNAPSHOT_YIELD_EVERY = 500;
|
|
67
|
-
// Scan one directory's entries into `snapshot`, pushing walkable subdirs onto
|
|
68
|
-
// `stack`. Yields to the event loop every SNAPSHOT_YIELD_EVERY files (shared
|
|
69
|
-
// `counter`) so a single huge directory can't hold the loop. Excluded/ignored
|
|
70
|
-
// dirs are not descended; ignored/vanished files are skipped.
|
|
71
|
-
async function snapshotDirInto(dir, ignoreMatcher, stack, snapshot, counter) {
|
|
72
|
-
let entries;
|
|
73
|
-
try {
|
|
74
|
-
// Async (#1137): a synchronous per-directory read blocks the loop for the
|
|
75
|
-
// whole stall on a slow cloud-backed (OneDrive) directory; fs.promises
|
|
76
|
-
// keeps this tool_result-path walk off the event loop.
|
|
77
|
-
entries = await nodeFs.promises.readdir(dir, { withFileTypes: true });
|
|
78
|
-
}
|
|
79
|
-
catch {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
for (const entry of entries) {
|
|
83
|
-
const fullPath = path.join(dir, entry.name);
|
|
84
|
-
if (entry.isDirectory()) {
|
|
85
|
-
if (!isExcludedDirName(entry.name) &&
|
|
86
|
-
!ignoreMatcher.isIgnored(fullPath, true)) {
|
|
87
|
-
stack.push(fullPath);
|
|
88
|
-
}
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
if (!entry.isFile())
|
|
92
|
-
continue;
|
|
93
|
-
if (ignoreMatcher.isIgnored(fullPath, false))
|
|
94
|
-
continue;
|
|
95
|
-
try {
|
|
96
|
-
const stat = await nodeFs.promises.stat(fullPath);
|
|
97
|
-
snapshot.set(path.resolve(fullPath), {
|
|
98
|
-
mtimeMs: stat.mtimeMs,
|
|
99
|
-
size: stat.size,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
// ignore vanished files
|
|
104
|
-
}
|
|
105
|
-
if (++counter.n % SNAPSHOT_YIELD_EVERY === 0) {
|
|
106
|
-
await new Promise((resolve) => setImmediate(resolve));
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
// Exported for the event-loop occupancy guard (#361/#368): an O(files) walk on
|
|
111
|
-
// the tool_result autofix path, bounded by AUTOFIX_CHANGED_FILE_SCAN_LIMIT and
|
|
112
|
-
// chunk-yielding every SNAPSHOT_YIELD_EVERY files so it never blocks the TUI.
|
|
113
|
-
export async function snapshotProjectFiles(root) {
|
|
114
|
-
const snapshot = new Map();
|
|
115
|
-
const projectRoot = path.resolve(root);
|
|
116
|
-
const ignoreMatcher = getProjectIgnoreMatcher(projectRoot);
|
|
117
|
-
// #703: prime the tracked-files set once before the walk so a tracked file
|
|
118
|
-
// matching a `.gitignore`/global pattern still shows up in the autofix
|
|
119
|
-
// snapshot. Fail-open on no-git/spawn failure.
|
|
120
|
-
await ignoreMatcher.ensureTrackedIndex();
|
|
121
|
-
const stack = [projectRoot];
|
|
122
|
-
const counter = { n: 0 };
|
|
123
|
-
while (stack.length > 0 && snapshot.size < AUTOFIX_CHANGED_FILE_SCAN_LIMIT) {
|
|
124
|
-
await snapshotDirInto(stack.pop(), ignoreMatcher, stack, snapshot, counter);
|
|
125
|
-
}
|
|
126
|
-
return snapshot;
|
|
127
|
-
}
|
|
128
|
-
async function diffProjectSnapshot(root, before) {
|
|
129
|
-
const after = await snapshotProjectFiles(root);
|
|
130
|
-
const changed = new Set();
|
|
131
|
-
for (const [filePath, next] of after) {
|
|
132
|
-
const prev = before.get(filePath);
|
|
133
|
-
if (prev?.mtimeMs !== next.mtimeMs || prev?.size !== next.size) {
|
|
134
|
-
changed.add(filePath);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
for (const filePath of before.keys()) {
|
|
138
|
-
if (!after.has(filePath))
|
|
139
|
-
changed.add(filePath);
|
|
140
|
-
}
|
|
141
|
-
return [...changed].sort((a, b) => a.localeCompare(b));
|
|
142
|
-
}
|
|
143
|
-
function createPhaseTracker(toolName, filePath) {
|
|
144
|
-
const phases = [];
|
|
145
|
-
return {
|
|
146
|
-
start(name) {
|
|
147
|
-
phases.push({ name, startTime: Date.now(), ended: false });
|
|
148
|
-
},
|
|
149
|
-
end(name, metadata) {
|
|
150
|
-
const p = phases.find((x) => x.name === name && !x.ended);
|
|
151
|
-
if (p) {
|
|
152
|
-
p.ended = true;
|
|
153
|
-
logLatency({
|
|
154
|
-
type: "phase",
|
|
155
|
-
toolName,
|
|
156
|
-
filePath,
|
|
157
|
-
phase: name,
|
|
158
|
-
durationMs: Date.now() - p.startTime,
|
|
159
|
-
metadata,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
// --- ESLint autofix helpers ---
|
|
166
|
-
export { hasEslintConfig, hasSqlfluffConfig, hasStylelintConfig };
|
|
167
|
-
/**
|
|
168
|
-
* eslint autofix availability, per cwd + PATH. The verdict is owned by the
|
|
169
|
-
* shared availability latch (#1494): a `missing` / `non-installable` outcome
|
|
170
|
-
* sticks for the session, a timeout expires on a cooldown and is re-probed, so
|
|
171
|
-
* one stalled probe cannot silently stop autofixing a project's JS/TS.
|
|
172
|
-
*/
|
|
173
|
-
const ESLINT_FIX_PROBE_BUDGET_MS = 5000;
|
|
174
|
-
const _eslintCache = new BoundedLruCache(32);
|
|
175
|
-
/**
|
|
176
|
-
* Run eslint --fix on a file. Runs a single spawn and diffs the file before/after,
|
|
177
|
-
* same idiom as the other autofix helpers below. Exit code 1 (unfixable problems
|
|
178
|
-
* remain) is allowed because fixes may still have been applied; only exit code 2
|
|
179
|
-
* (config/fatal error) is treated as failure.
|
|
180
|
-
* Returns 1 if the file changed, 0 if ESLint is not configured / not available /
|
|
181
|
-
* made no changes.
|
|
182
|
-
*/
|
|
183
|
-
async function tryEslintFix(filePath, cwd) {
|
|
184
|
-
const userHasConfig = hasEslintConfig(cwd);
|
|
185
|
-
if (!userHasConfig)
|
|
186
|
-
return 0;
|
|
187
|
-
// PATH is part of command resolution; include it so an install or PATH
|
|
188
|
-
// refresh cannot leave a negative eslint result live for the session.
|
|
189
|
-
const cacheKey = `${path.resolve(cwd)}|${process.env.PATH ?? ""}`;
|
|
190
|
-
let cached = _eslintCache.get(cacheKey);
|
|
191
|
-
if (!cached) {
|
|
192
|
-
cached = { latch: createAvailabilityLatch(), bin: null };
|
|
193
|
-
_eslintCache.set(cacheKey, cached);
|
|
194
|
-
}
|
|
195
|
-
if (cached.latch.read() === null) {
|
|
196
|
-
const candidate = resolveToolCommand(cwd, "eslint") ?? "eslint";
|
|
197
|
-
// The budget is enforced by a HOST-side timer, so a stalled event loop
|
|
198
|
-
// expires it while eslint is still healthy. Measure the overlapping stall
|
|
199
|
-
// and hand it to the classifier, exactly like the runner path: without it a
|
|
200
|
-
// host-stall timeout is re-caused as `probe-timeout` and gets the escalating
|
|
201
|
-
// 30s→300s cooldown instead of the 5s host-stall one (#1467).
|
|
202
|
-
const stallSampler = startHostStallSampler();
|
|
203
|
-
const startedAt = Date.now();
|
|
204
|
-
let check;
|
|
205
|
-
let hostStallMs;
|
|
206
|
-
try {
|
|
207
|
-
check = await safeSpawnAsync(candidate, ["--version"], {
|
|
208
|
-
timeout: ESLINT_FIX_PROBE_BUDGET_MS,
|
|
209
|
-
cwd,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
finally {
|
|
213
|
-
hostStallMs = stallSampler.stop();
|
|
214
|
-
}
|
|
215
|
-
const elapsedMs = Date.now() - startedAt;
|
|
216
|
-
const decisionCwd = path.resolve(cwd);
|
|
217
|
-
if (!check.error && check.status === 0) {
|
|
218
|
-
cached.bin = candidate;
|
|
219
|
-
cached.latch.noteAvailable();
|
|
220
|
-
logAvailabilityDecision({
|
|
221
|
-
tool: "eslint",
|
|
222
|
-
verdict: "available",
|
|
223
|
-
outcome: "success",
|
|
224
|
-
cause: "ok",
|
|
225
|
-
elapsedMs,
|
|
226
|
-
latched: true,
|
|
227
|
-
hostStallMs,
|
|
228
|
-
budgetMs: ESLINT_FIX_PROBE_BUDGET_MS,
|
|
229
|
-
classifiedBy: "probe",
|
|
230
|
-
evidence: describeProbeEvidence(check, "eslint"),
|
|
231
|
-
}, decisionCwd);
|
|
232
|
-
}
|
|
233
|
-
else {
|
|
234
|
-
cached.bin = null;
|
|
235
|
-
const { outcome, cause, evidence } = classifyProbeFailure(check, {
|
|
236
|
-
hostStallMs,
|
|
237
|
-
command: "eslint",
|
|
238
|
-
});
|
|
239
|
-
const retryAfterMs = cached.latch.noteUnavailable(outcome, cause);
|
|
240
|
-
logAvailabilityDecision({
|
|
241
|
-
tool: "eslint",
|
|
242
|
-
verdict: "unavailable",
|
|
243
|
-
outcome,
|
|
244
|
-
cause,
|
|
245
|
-
elapsedMs,
|
|
246
|
-
latched: retryAfterMs === 0,
|
|
247
|
-
hostStallMs,
|
|
248
|
-
...(retryAfterMs > 0 && { retryAfterMs }),
|
|
249
|
-
budgetMs: ESLINT_FIX_PROBE_BUDGET_MS,
|
|
250
|
-
classifiedBy: "probe",
|
|
251
|
-
evidence,
|
|
252
|
-
}, decisionCwd);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
if (cached.latch.read() !== true || !cached.bin)
|
|
256
|
-
return 0;
|
|
257
|
-
const cmd = cached.bin;
|
|
258
|
-
return detectFileChangedAfterCommand(filePath, cmd, ["--fix", "--no-error-on-unmatched-pattern", filePath], cwd, [1]);
|
|
259
|
-
}
|
|
260
|
-
async function tryStylelintFix(filePath, cwd) {
|
|
261
|
-
const cmd = await resolveToolCommandWithInstallFallback(cwd, "stylelint");
|
|
262
|
-
if (!cmd)
|
|
263
|
-
return 0;
|
|
264
|
-
return detectFileChangedAfterCommand(filePath, cmd, ["--fix", "--allow-empty-input", filePath], cwd, [2]);
|
|
265
|
-
}
|
|
266
|
-
async function trySqlfluffFix(filePath, cwd) {
|
|
267
|
-
const cmd = await resolveToolCommandWithInstallFallback(cwd, "sqlfluff");
|
|
268
|
-
if (!cmd)
|
|
269
|
-
return 0;
|
|
270
|
-
const args = ["fix", "--force", filePath];
|
|
271
|
-
if (!hasSqlfluffConfig(cwd)) {
|
|
272
|
-
args.splice(2, 0, "--dialect", "ansi");
|
|
273
|
-
}
|
|
274
|
-
return detectFileChangedAfterCommand(filePath, cmd, args, cwd);
|
|
275
|
-
}
|
|
276
|
-
async function tryRubocopFix(filePath, cwd) {
|
|
277
|
-
const resolved = await resolveCommandArgsWithInstallFallback(getRubocopCommand(cwd), "rubocop", cwd, ["--version"], 10000);
|
|
278
|
-
if (!resolved)
|
|
279
|
-
return 0;
|
|
280
|
-
return detectFileChangedAfterCommand(filePath, resolved.cmd, [...resolved.args, "-a", "--no-color", filePath], cwd, [1]);
|
|
281
|
-
}
|
|
282
|
-
async function tryKtlintFix(filePath, cwd) {
|
|
283
|
-
const cmd = await resolveToolCommandWithInstallFallback(cwd, "ktlint");
|
|
284
|
-
if (!cmd)
|
|
285
|
-
return 0;
|
|
286
|
-
return detectFileChangedAfterCommand(filePath, cmd, ["-F", filePath], cwd, [1]);
|
|
287
|
-
}
|
|
288
|
-
// golangci-lint/detekt/ktfmt have no TOOL_COMMAND_SPEC; resolve via availability
|
|
289
|
-
// checkers like their runners do.
|
|
290
|
-
const golangciAutofixChecker = createAvailabilityChecker("golangci-lint", ".exe");
|
|
291
|
-
const detektAutofixChecker = createAvailabilityChecker("detekt", ".bat");
|
|
292
|
-
const ktfmtAutofixChecker = createAvailabilityChecker("ktfmt", ".bat");
|
|
293
|
-
async function tryKtfmtFix(filePath, cwd) {
|
|
294
|
-
// Config-first: the autofix policy only reaches here when the project opted
|
|
295
|
-
// into ktfmt, so resolveAvailableOrInstall honors that gate. ktfmt writes the
|
|
296
|
-
// formatted file in place and exits 0; treat any byte change as the fix.
|
|
297
|
-
const cmd = await resolveAvailableOrInstall(ktfmtAutofixChecker, "ktfmt", cwd);
|
|
298
|
-
if (!cmd)
|
|
299
|
-
return 0;
|
|
300
|
-
const absPath = path.resolve(cwd, filePath);
|
|
301
|
-
return detectFileChangedAfterCommand(filePath, cmd, [absPath], cwd, [0]);
|
|
302
|
-
}
|
|
303
|
-
async function tryGolangciLintFix(filePath, cwd) {
|
|
304
|
-
// Config-first: the autofix policy only reaches here when a .golangci.* config
|
|
305
|
-
// exists. resolveAvailableOrInstall honors that gate (won't auto-install a
|
|
306
|
-
// config-first tool). golangci-lint exits non-zero when issues remain after
|
|
307
|
-
// --fix, so allow its issue-found codes.
|
|
308
|
-
const cmd = await resolveAvailableOrInstall(golangciAutofixChecker, "golangci-lint", cwd);
|
|
309
|
-
if (!cmd)
|
|
310
|
-
return 0;
|
|
311
|
-
return detectFileChangedAfterCommand(filePath, cmd, ["run", "--fix", filePath], cwd, [1, 7]);
|
|
312
|
-
}
|
|
313
|
-
async function tryDetektFix(filePath, cwd) {
|
|
314
|
-
const configPath = findDetektConfig(cwd);
|
|
315
|
-
if (!configPath)
|
|
316
|
-
return 0;
|
|
317
|
-
if (!(await detektAutofixChecker.isAvailableAsync(cwd)))
|
|
318
|
-
return 0;
|
|
319
|
-
const cmd = detektAutofixChecker.getCommand(cwd);
|
|
320
|
-
if (!cmd)
|
|
321
|
-
return 0;
|
|
322
|
-
const absPath = path.resolve(cwd, filePath);
|
|
323
|
-
return detectFileChangedAfterCommand(filePath, cmd, ["--auto-correct", "--input", absPath, "--config", configPath], cwd, [1, 2]);
|
|
324
|
-
}
|
|
325
|
-
async function tryMarkdownlintFix(filePath, cwd) {
|
|
326
|
-
const cmd = await resolveToolCommandWithInstallFallback(cwd, "markdownlint");
|
|
327
|
-
if (!cmd)
|
|
328
|
-
return 0;
|
|
329
|
-
// Shared config-args seam (#1247): the lint runner consumes the same
|
|
330
|
-
// builder, so the bare --fix here can never fall back to markdownlint's
|
|
331
|
-
// default all-rules-on config again (the whole-file CHANGELOG/AGENTS
|
|
332
|
-
// reformat + `#946` → `# 946` corruption).
|
|
333
|
-
// markdownlint-cli2 --fix exits non-zero when unfixable violations remain.
|
|
334
|
-
return detectFileChangedAfterCommand(filePath, cmd, [...markdownlintConfigArgs(cwd), "--fix", filePath], cwd, [1]);
|
|
335
|
-
}
|
|
336
|
-
async function tryOxlintFix(filePath, cwd) {
|
|
337
|
-
const cmd = await resolveToolCommandWithInstallFallback(cwd, "oxlint");
|
|
338
|
-
if (!cmd)
|
|
339
|
-
return 0;
|
|
340
|
-
return detectFileChangedAfterCommand(filePath, cmd, ["--fix", filePath], cwd, [1]);
|
|
341
|
-
}
|
|
342
|
-
async function tryRustClippyFix(filePath) {
|
|
343
|
-
const check = await probeToolAsync("cargo", ["--version"], { timeout: 5000 });
|
|
344
|
-
if (check.error || check.status !== 0)
|
|
345
|
-
return [];
|
|
346
|
-
const cargoDir = findNearestContaining(path.dirname(path.resolve(filePath)), [
|
|
347
|
-
"Cargo.toml",
|
|
348
|
-
]);
|
|
349
|
-
if (!cargoDir)
|
|
350
|
-
return [];
|
|
351
|
-
const before = await snapshotProjectFiles(cargoDir);
|
|
352
|
-
const result = await safeSpawnAsync("cargo", ["clippy", "--fix", "--allow-dirty", "--allow-staged", "-q"], { timeout: 30000, cwd: cargoDir });
|
|
353
|
-
if (result.error || result.status !== 0)
|
|
354
|
-
return [];
|
|
355
|
-
return diffProjectSnapshot(cargoDir, before);
|
|
356
|
-
}
|
|
357
|
-
async function tryDartFix(filePath) {
|
|
358
|
-
const check = await probeToolAsync("dart", ["--version"], { timeout: 5000 });
|
|
359
|
-
if (check.error || check.status !== 0)
|
|
360
|
-
return [];
|
|
361
|
-
const pubspecDir = findNearestContaining(path.dirname(path.resolve(filePath)), ["pubspec.yaml"]);
|
|
362
|
-
if (!pubspecDir)
|
|
363
|
-
return [];
|
|
364
|
-
const before = await snapshotProjectFiles(pubspecDir);
|
|
365
|
-
const result = await safeSpawnAsync("dart", ["fix", "--apply"], {
|
|
366
|
-
timeout: 30000,
|
|
367
|
-
cwd: pubspecDir,
|
|
368
|
-
});
|
|
369
|
-
if (result.error || result.status !== 0)
|
|
370
|
-
return [];
|
|
371
|
-
return diffProjectSnapshot(pubspecDir, before);
|
|
372
|
-
}
|
|
373
|
-
// --- Pipeline phase helpers ---
|
|
374
|
-
export async function runAutofix(filePath, cwd, getFlag, dbg, deps, getFlagSource) {
|
|
375
|
-
const { biomeClient, ruffClient, fixedThisTurn } = deps;
|
|
376
|
-
const noAutofix = getFlag("no-autofix", filePath);
|
|
377
|
-
let fixedCount = 0;
|
|
378
|
-
const autofixTools = [];
|
|
379
|
-
const attemptedTools = [];
|
|
380
|
-
const changedFiles = new Set();
|
|
381
|
-
const markTargetChanged = () => changedFiles.add(path.resolve(filePath));
|
|
382
|
-
let needsContentRefresh = false;
|
|
383
|
-
if (fixedThisTurn.has(filePath)) {
|
|
384
|
-
dbg(`autofix: skipped for ${filePath} (already fixed this turn)`);
|
|
385
|
-
return {
|
|
386
|
-
fixedCount,
|
|
387
|
-
autofixTools,
|
|
388
|
-
attemptedTools,
|
|
389
|
-
changedFiles: [],
|
|
390
|
-
needsContentRefresh,
|
|
391
|
-
skipReason: "already_fixed_this_turn",
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
if (noAutofix) {
|
|
395
|
-
const source = getFlagSource?.("no-autofix", filePath);
|
|
396
|
-
dbg(`autofix: skipped for ${filePath} (--no-autofix${source ? `, source=${source}` : ""})`);
|
|
397
|
-
return {
|
|
398
|
-
fixedCount,
|
|
399
|
-
autofixTools,
|
|
400
|
-
attemptedTools,
|
|
401
|
-
changedFiles: [],
|
|
402
|
-
needsContentRefresh,
|
|
403
|
-
skipReason: "disabled_by_flag",
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
const autofixContext = {
|
|
407
|
-
hasEslintConfig: hasEslintConfig(cwd),
|
|
408
|
-
hasStylelintConfig: hasStylelintConfig(cwd),
|
|
409
|
-
hasSqlfluffConfig: hasSqlfluffConfig(cwd),
|
|
410
|
-
hasRubocopConfig: hasRubocopConfig(cwd),
|
|
411
|
-
hasBiomeConfig: hasBiomeConfig(cwd),
|
|
412
|
-
hasGolangciConfig: hasGolangciConfig(cwd),
|
|
413
|
-
hasDetektConfig: hasDetektConfig(cwd),
|
|
414
|
-
hasKtfmtConfig: hasKtfmtConfig(cwd),
|
|
415
|
-
hasKtlintConfig: hasKtlintConfig(cwd),
|
|
416
|
-
hasOxlintConfig: hasOxlintConfig(cwd),
|
|
417
|
-
};
|
|
418
|
-
const autofixPolicy = getAutofixPolicyForFile(filePath, autofixContext);
|
|
419
|
-
const preferredAutofixTools = autofixPolicy?.safe
|
|
420
|
-
? getPreferredAutofixTools(filePath, autofixContext)
|
|
421
|
-
: [];
|
|
422
|
-
dbg(`autofix: policy for ${filePath} -> ${autofixPolicy?.defaultTool ?? "none"} ` +
|
|
423
|
-
`(preferred: ${preferredAutofixTools.join(",") || "none"}, gate: ${autofixPolicy?.gate ?? "none"}, safe: ${autofixPolicy?.safe ? "yes" : "no"})`);
|
|
424
|
-
if (!autofixPolicy) {
|
|
425
|
-
dbg(`autofix: no policy for ${filePath}`);
|
|
426
|
-
return {
|
|
427
|
-
fixedCount,
|
|
428
|
-
autofixTools,
|
|
429
|
-
attemptedTools,
|
|
430
|
-
changedFiles: [],
|
|
431
|
-
needsContentRefresh,
|
|
432
|
-
skipReason: "no_policy",
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
if (!autofixPolicy.safe || preferredAutofixTools.length === 0) {
|
|
436
|
-
dbg(`autofix: no safe preferred tools for ${filePath}`);
|
|
437
|
-
return {
|
|
438
|
-
fixedCount,
|
|
439
|
-
autofixTools,
|
|
440
|
-
attemptedTools,
|
|
441
|
-
changedFiles: [],
|
|
442
|
-
needsContentRefresh,
|
|
443
|
-
skipReason: "no_safe_tools",
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
for (const toolName of preferredAutofixTools) {
|
|
447
|
-
attemptedTools.push(toolName);
|
|
448
|
-
const agreement = establishToolAgreement(toolName, cwd);
|
|
449
|
-
if (agreement.decision === "decline") {
|
|
450
|
-
const reason = agreement.reason;
|
|
451
|
-
dbg(`autofix: ${toolName} declined (${reason})`);
|
|
452
|
-
recordDegradationOnce({
|
|
453
|
-
kind: "autofix-agreement-unavailable",
|
|
454
|
-
subject: agreement.subject,
|
|
455
|
-
reason,
|
|
456
|
-
});
|
|
457
|
-
continue;
|
|
458
|
-
}
|
|
459
|
-
if (toolName === "ruff") {
|
|
460
|
-
const ruffReady = ruffClient.isPythonFile(filePath)
|
|
461
|
-
? await ruffClient.ensureAvailable()
|
|
462
|
-
: false;
|
|
463
|
-
if (!ruffReady) {
|
|
464
|
-
dbg(`autofix: ruff unavailable for ${filePath}`);
|
|
465
|
-
continue;
|
|
466
|
-
}
|
|
467
|
-
const result = await ruffClient.fixFileAsync(filePath, cwd);
|
|
468
|
-
if (result.success && result.fixed > 0) {
|
|
469
|
-
fixedCount += result.fixed;
|
|
470
|
-
autofixTools.push(`ruff:${result.fixed}`);
|
|
471
|
-
fixedThisTurn.add(filePath);
|
|
472
|
-
markTargetChanged();
|
|
473
|
-
dbg(`autofix: ruff fixed ${result.fixed} issue(s) in ${filePath}`);
|
|
474
|
-
needsContentRefresh = true;
|
|
475
|
-
}
|
|
476
|
-
continue;
|
|
477
|
-
}
|
|
478
|
-
if (toolName === "biome") {
|
|
479
|
-
const biomeReady = biomeClient.isSupportedFile(filePath)
|
|
480
|
-
? await biomeClient.ensureAvailable()
|
|
481
|
-
: false;
|
|
482
|
-
if (!biomeReady) {
|
|
483
|
-
dbg(`autofix: biome unavailable or unsupported for ${filePath}`);
|
|
484
|
-
continue;
|
|
485
|
-
}
|
|
486
|
-
const result = await biomeClient.fixFileAsync(filePath, cwd);
|
|
487
|
-
if (result.success && result.fixed > 0) {
|
|
488
|
-
fixedCount += result.fixed;
|
|
489
|
-
autofixTools.push(`biome:${result.fixed}`);
|
|
490
|
-
fixedThisTurn.add(filePath);
|
|
491
|
-
markTargetChanged();
|
|
492
|
-
dbg(`autofix: biome fixed ${result.fixed} issue(s) in ${filePath}`);
|
|
493
|
-
needsContentRefresh = true;
|
|
494
|
-
}
|
|
495
|
-
continue;
|
|
496
|
-
}
|
|
497
|
-
if (toolName === "eslint") {
|
|
498
|
-
const eslintFixed = await tryEslintFix(filePath, cwd);
|
|
499
|
-
if (eslintFixed > 0) {
|
|
500
|
-
fixedCount += eslintFixed;
|
|
501
|
-
autofixTools.push(`eslint:${eslintFixed}`);
|
|
502
|
-
fixedThisTurn.add(filePath);
|
|
503
|
-
markTargetChanged();
|
|
504
|
-
dbg(`autofix: eslint fixed ${eslintFixed} issue(s) in ${filePath}`);
|
|
505
|
-
needsContentRefresh = true;
|
|
506
|
-
}
|
|
507
|
-
continue;
|
|
508
|
-
}
|
|
509
|
-
if (toolName === "stylelint") {
|
|
510
|
-
const stylelintFixed = await tryStylelintFix(filePath, cwd);
|
|
511
|
-
if (stylelintFixed > 0) {
|
|
512
|
-
fixedCount += stylelintFixed;
|
|
513
|
-
autofixTools.push(`stylelint:${stylelintFixed}`);
|
|
514
|
-
fixedThisTurn.add(filePath);
|
|
515
|
-
markTargetChanged();
|
|
516
|
-
dbg(`autofix: stylelint fixed ${stylelintFixed} issue(s) in ${filePath}`);
|
|
517
|
-
needsContentRefresh = true;
|
|
518
|
-
}
|
|
519
|
-
continue;
|
|
520
|
-
}
|
|
521
|
-
if (toolName === "sqlfluff") {
|
|
522
|
-
const sqlfluffFixed = await trySqlfluffFix(filePath, cwd);
|
|
523
|
-
if (sqlfluffFixed > 0) {
|
|
524
|
-
fixedCount += sqlfluffFixed;
|
|
525
|
-
autofixTools.push(`sqlfluff:${sqlfluffFixed}`);
|
|
526
|
-
fixedThisTurn.add(filePath);
|
|
527
|
-
markTargetChanged();
|
|
528
|
-
dbg(`autofix: sqlfluff fixed ${sqlfluffFixed} issue(s) in ${filePath}`);
|
|
529
|
-
needsContentRefresh = true;
|
|
530
|
-
}
|
|
531
|
-
continue;
|
|
532
|
-
}
|
|
533
|
-
if (toolName === "rubocop") {
|
|
534
|
-
const rubocopFixed = await tryRubocopFix(filePath, cwd);
|
|
535
|
-
if (rubocopFixed > 0) {
|
|
536
|
-
fixedCount += rubocopFixed;
|
|
537
|
-
autofixTools.push(`rubocop:${rubocopFixed}`);
|
|
538
|
-
fixedThisTurn.add(filePath);
|
|
539
|
-
markTargetChanged();
|
|
540
|
-
dbg(`autofix: rubocop fixed ${rubocopFixed} issue(s) in ${filePath}`);
|
|
541
|
-
needsContentRefresh = true;
|
|
542
|
-
}
|
|
543
|
-
continue;
|
|
544
|
-
}
|
|
545
|
-
if (toolName === "ktlint") {
|
|
546
|
-
const ktlintFixed = await tryKtlintFix(filePath, cwd);
|
|
547
|
-
if (ktlintFixed > 0) {
|
|
548
|
-
fixedCount += ktlintFixed;
|
|
549
|
-
autofixTools.push(`ktlint:${ktlintFixed}`);
|
|
550
|
-
fixedThisTurn.add(filePath);
|
|
551
|
-
markTargetChanged();
|
|
552
|
-
dbg(`autofix: ktlint fixed ${ktlintFixed} issue(s) in ${filePath}`);
|
|
553
|
-
needsContentRefresh = true;
|
|
554
|
-
}
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
if (toolName === "rust-clippy") {
|
|
558
|
-
const clippyChangedFiles = await tryRustClippyFix(filePath);
|
|
559
|
-
if (clippyChangedFiles.length > 0) {
|
|
560
|
-
fixedCount += clippyChangedFiles.length;
|
|
561
|
-
autofixTools.push(`rust-clippy:${clippyChangedFiles.length}`);
|
|
562
|
-
fixedThisTurn.add(filePath);
|
|
563
|
-
for (const changedFile of clippyChangedFiles)
|
|
564
|
-
changedFiles.add(changedFile);
|
|
565
|
-
dbg(`autofix: rust-clippy changed ${clippyChangedFiles.length} file(s) from ${filePath}`);
|
|
566
|
-
needsContentRefresh = true;
|
|
567
|
-
}
|
|
568
|
-
continue;
|
|
569
|
-
}
|
|
570
|
-
if (toolName === "dart-analyze") {
|
|
571
|
-
const dartChangedFiles = await tryDartFix(filePath);
|
|
572
|
-
if (dartChangedFiles.length > 0) {
|
|
573
|
-
fixedCount += dartChangedFiles.length;
|
|
574
|
-
autofixTools.push(`dart-analyze:${dartChangedFiles.length}`);
|
|
575
|
-
fixedThisTurn.add(filePath);
|
|
576
|
-
for (const changedFile of dartChangedFiles)
|
|
577
|
-
changedFiles.add(changedFile);
|
|
578
|
-
dbg(`autofix: dart fix changed ${dartChangedFiles.length} file(s) from ${filePath}`);
|
|
579
|
-
needsContentRefresh = true;
|
|
580
|
-
}
|
|
581
|
-
continue;
|
|
582
|
-
}
|
|
583
|
-
if (toolName === "golangci-lint") {
|
|
584
|
-
const fixed = await tryGolangciLintFix(filePath, cwd);
|
|
585
|
-
if (fixed > 0) {
|
|
586
|
-
fixedCount += fixed;
|
|
587
|
-
autofixTools.push(`golangci-lint:${fixed}`);
|
|
588
|
-
fixedThisTurn.add(filePath);
|
|
589
|
-
markTargetChanged();
|
|
590
|
-
dbg(`autofix: golangci-lint fixed ${filePath}`);
|
|
591
|
-
needsContentRefresh = true;
|
|
592
|
-
}
|
|
593
|
-
continue;
|
|
594
|
-
}
|
|
595
|
-
if (toolName === "detekt") {
|
|
596
|
-
const fixed = await tryDetektFix(filePath, cwd);
|
|
597
|
-
if (fixed > 0) {
|
|
598
|
-
fixedCount += fixed;
|
|
599
|
-
autofixTools.push(`detekt:${fixed}`);
|
|
600
|
-
fixedThisTurn.add(filePath);
|
|
601
|
-
markTargetChanged();
|
|
602
|
-
dbg(`autofix: detekt --auto-correct fixed ${filePath}`);
|
|
603
|
-
needsContentRefresh = true;
|
|
604
|
-
}
|
|
605
|
-
continue;
|
|
606
|
-
}
|
|
607
|
-
if (toolName === "ktfmt") {
|
|
608
|
-
const fixed = await tryKtfmtFix(filePath, cwd);
|
|
609
|
-
if (fixed > 0) {
|
|
610
|
-
fixedCount += fixed;
|
|
611
|
-
autofixTools.push(`ktfmt:${fixed}`);
|
|
612
|
-
fixedThisTurn.add(filePath);
|
|
613
|
-
markTargetChanged();
|
|
614
|
-
dbg(`autofix: ktfmt formatted ${filePath}`);
|
|
615
|
-
needsContentRefresh = true;
|
|
616
|
-
}
|
|
617
|
-
continue;
|
|
618
|
-
}
|
|
619
|
-
if (toolName === "markdownlint") {
|
|
620
|
-
const fixed = await tryMarkdownlintFix(filePath, cwd);
|
|
621
|
-
if (fixed > 0) {
|
|
622
|
-
fixedCount += fixed;
|
|
623
|
-
autofixTools.push(`markdownlint:${fixed}`);
|
|
624
|
-
fixedThisTurn.add(filePath);
|
|
625
|
-
markTargetChanged();
|
|
626
|
-
dbg(`autofix: markdownlint --fix fixed ${filePath}`);
|
|
627
|
-
needsContentRefresh = true;
|
|
628
|
-
}
|
|
629
|
-
continue;
|
|
630
|
-
}
|
|
631
|
-
if (toolName === "oxlint") {
|
|
632
|
-
const fixed = await tryOxlintFix(filePath, cwd);
|
|
633
|
-
if (fixed > 0) {
|
|
634
|
-
fixedCount += fixed;
|
|
635
|
-
autofixTools.push(`oxlint:${fixed}`);
|
|
636
|
-
fixedThisTurn.add(filePath);
|
|
637
|
-
markTargetChanged();
|
|
638
|
-
dbg(`autofix: oxlint --fix fixed ${filePath}`);
|
|
639
|
-
needsContentRefresh = true;
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
if (attemptedTools.length > 0 && autofixTools.length === 0) {
|
|
644
|
-
dbg(`autofix: attempted ${attemptedTools.join(",")} for ${filePath}, but no fixes were applied`);
|
|
645
|
-
}
|
|
646
|
-
return {
|
|
647
|
-
fixedCount,
|
|
648
|
-
autofixTools,
|
|
649
|
-
attemptedTools,
|
|
650
|
-
changedFiles: [...changedFiles],
|
|
651
|
-
needsContentRefresh,
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
export async function resyncLspFile(filePath, fileContent, needsContentRefresh, lspSyncCompleted, getFlag, dbg) {
|
|
655
|
-
if (getFlag("no-lsp"))
|
|
656
|
-
return;
|
|
657
|
-
if (!needsContentRefresh && lspSyncCompleted)
|
|
658
|
-
return;
|
|
659
|
-
// #3405 r2: the bound is `clients/lsp/content-limits.ts` now, shared with the
|
|
660
|
-
// dispatch runner and the didSave payload. THIS call stays: a file past the
|
|
661
|
-
// bound is not synced to the server AT ALL, which is a stricter policy than
|
|
662
|
-
// the save seam's (drop the redundant text, still send the save) and the one
|
|
663
|
-
// a post-write sync owes — removing it would start writing whole-file
|
|
664
|
-
// didOpen frames for files this pipeline has always refused.
|
|
665
|
-
const limitCheck = exceedsLspSyncLimits(fileContent);
|
|
666
|
-
if (limitCheck.tooLarge)
|
|
667
|
-
return;
|
|
668
|
-
try {
|
|
669
|
-
const lspService = (await loadLspService()).getLSPService();
|
|
670
|
-
if (lspService.supportsLSP(filePath)) {
|
|
671
|
-
// Push the final post-format/post-fix content through touchFile (not the
|
|
672
|
-
// bare openFile) so it registers in the touch-debounce map via
|
|
673
|
-
// markTouched. The dispatch-lsp-runner's touchFile fires ~80ms later with
|
|
674
|
-
// identical content; registering this push makes its shouldSkipNotify
|
|
675
|
-
// return true, so it reuses the diagnostics THIS push triggers instead of
|
|
676
|
-
// re-clearing the cache and forcing the server to recompute from scratch —
|
|
677
|
-
// the dominant per-edit LSP latency (#203). diagnostics:"none" keeps this
|
|
678
|
-
// call non-blocking; the dispatch runner owns the diagnostics wait. We let
|
|
679
|
-
// the cache clear (no preserveDiagnostics) so the wait resolves on fresh,
|
|
680
|
-
// correctly-positioned diagnostics rather than stale pre-edit ones — the
|
|
681
|
-
// didChange triggers a server recompute regardless of cache preservation.
|
|
682
|
-
//
|
|
683
|
-
// The touch is client-wait-capped, but its didChange/didOpen *write* can
|
|
684
|
-
// backpressure forever on a wedged server (stdin not drained), which would
|
|
685
|
-
// hang the whole edit with no bound and — until this — no log. Race it
|
|
686
|
-
// against a hard budget + the turn's abort signal (Escape): whichever wins,
|
|
687
|
-
// the edit proceeds. A wedged server no longer parks the pipeline.
|
|
688
|
-
const budgetMs = lspSyncBudgetMs();
|
|
689
|
-
const abort = getAmbientAbortSignal();
|
|
690
|
-
if (abort?.aborted)
|
|
691
|
-
return;
|
|
692
|
-
const startedAt = Date.now();
|
|
693
|
-
const touch = lspService
|
|
694
|
-
.touchFile(filePath, fileContent, {
|
|
695
|
-
diagnostics: "none",
|
|
696
|
-
source: "lsp_sync",
|
|
697
|
-
clientScope: "primary",
|
|
698
|
-
maxClientWaitMs: LSP_SPAWN_BUDGET_MS,
|
|
699
|
-
// #3405: pi-lens just wrote these bytes to disk, so this is the one
|
|
700
|
-
// touch that is a save. A save-triggered server (Expert recompiles
|
|
701
|
-
// the project on didSave and on nothing else) publishes for the edit
|
|
702
|
-
// only because of this flag.
|
|
703
|
-
saved: true,
|
|
704
|
-
})
|
|
705
|
-
.then(() => "done")
|
|
706
|
-
.catch((err) => {
|
|
707
|
-
dbg(`LSP resync after autofix error: ${err}`);
|
|
708
|
-
return "done";
|
|
709
|
-
});
|
|
710
|
-
// #2540: Kick off auxiliary server acquisition concurrently and unawaited
|
|
711
|
-
// with the ambient turn signal so auxiliary warmup overlaps with the primary
|
|
712
|
-
// server during resync. Leaves the single-occupancy deferred slot (#2509)
|
|
713
|
-
// free for actionable-warnings while Escape mid-turn abandons the wait.
|
|
714
|
-
//
|
|
715
|
-
// #2582 F3 — the #1766 F3 invariant re-opened for a different method.
|
|
716
|
-
// #2540 placed this kick-off BEFORE the primary touch, inside
|
|
717
|
-
// resyncLspFile's swallow-all catch, so anything that threw out of
|
|
718
|
-
// auxiliary acquisition abandoned the PRIMARY sync before it started:
|
|
719
|
-
// no touchFile, and no lsp_sync_abandoned record for the stall.
|
|
720
|
-
// Auxiliary warmup is a best-effort OVERLAP, never a precondition:
|
|
721
|
-
// the primary touch is already in flight above, and the async IIFE
|
|
722
|
-
// turns a synchronous throw out of the call into a rejection so
|
|
723
|
-
// `.catch` covers both failure directions. Order and containment are
|
|
724
|
-
// the invariant; do not hoist this back above the touch.
|
|
725
|
-
const auxServerIds = enabledAuxiliaryLspServerIds(getFlag);
|
|
726
|
-
if (auxServerIds.length > 0) {
|
|
727
|
-
void (async () => lspService.getAuxiliaryClientsForFile(filePath, new Set(auxServerIds), undefined, LSP_SPAWN_BUDGET_MS, abort, "tool_result_edit"))().catch(() => { });
|
|
728
|
-
}
|
|
729
|
-
// #2523 slice 2: this was `combineAbortSignals(abort,
|
|
730
|
-
// AbortSignal.timeout(budgetMs))` fed into a hand-rolled
|
|
731
|
-
// `Promise.race` — a private fifth copy of "deadline AND signal".
|
|
732
|
-
// `bounded()` is the same thing with the abandonment recorded, and
|
|
733
|
-
// without the composite signal that #2530 review F4 measured
|
|
734
|
-
// accumulating on the SOURCE.
|
|
735
|
-
//
|
|
736
|
-
// `touch` never rejects (it catches above) and never resolves
|
|
737
|
-
// `undefined`, so `undefined` here means exactly "a bound fired".
|
|
738
|
-
const outcome = await bounded(touch, {
|
|
739
|
-
ms: budgetMs,
|
|
740
|
-
// The ambient turn signal: set for the whole tool_result path and
|
|
741
|
-
// absent only in a bare unit harness, where the wall budget is
|
|
742
|
-
// still live (`bounded()` reads a missing signal as one that
|
|
743
|
-
// never aborts).
|
|
744
|
-
signal: abort,
|
|
745
|
-
hook: "tool_result_edit",
|
|
746
|
-
label: "resyncLspFile",
|
|
747
|
-
});
|
|
748
|
-
if (outcome === undefined) {
|
|
749
|
-
// Abandon the still-pending write; the edit continues. Log it so this
|
|
750
|
-
// stall — previously an invisible hang — is queryable in latency.log.
|
|
751
|
-
//
|
|
752
|
-
// #1766: a resync deadline can expire while the target server's FIRST
|
|
753
|
-
// spawn is still in flight (cold spawn > budget). That is not the same
|
|
754
|
-
// state as a running server that stalled on a write — the server the
|
|
755
|
-
// old wording blamed as "slow/wedged" did not exist yet. Distinguish
|
|
756
|
-
// the two via a fresh, synchronous inFlight lookup so the record keeps
|
|
757
|
-
// the discriminating identity (which server, which lifecycle state).
|
|
758
|
-
// #2592: the `typeof lspService.isSpawnInFlight === "function"`
|
|
759
|
-
// hedge that used to wrap this call is GONE. It existed for one
|
|
760
|
-
// reason — 19 hand-rolled `getLSPService` doubles that lacked the
|
|
761
|
-
// method, whose TypeError would have landed in the catch below and
|
|
762
|
-
// suppressed this record entirely (#1766 F3) — and that population
|
|
763
|
-
// is now zero: every double is seeded from
|
|
764
|
-
// `makeLspServiceDouble`, `tests/support/lsp-double-baseline.json`
|
|
765
|
-
// is `{}`, and `tests/config/lsp-service-double-sweep.test.ts` reds
|
|
766
|
-
// on a fresh hand-rolled one. The real `LSPService` has always had
|
|
767
|
-
// the method (clients/lsp/index.ts), so the fallback was a test
|
|
768
|
-
// shape leaking into production — AGENTS.md shape 7.
|
|
769
|
-
const spawnInFlight = !abort?.aborted && lspService.isSpawnInFlight(filePath);
|
|
770
|
-
const reason = abort?.aborted
|
|
771
|
-
? "aborted"
|
|
772
|
-
: spawnInFlight
|
|
773
|
-
? "spawn-in-flight"
|
|
774
|
-
: "timeout";
|
|
775
|
-
logLatency({
|
|
776
|
-
type: "phase",
|
|
777
|
-
phase: "lsp_sync_abandoned",
|
|
778
|
-
filePath,
|
|
779
|
-
durationMs: Date.now() - startedAt,
|
|
780
|
-
metadata: {
|
|
781
|
-
source: "lsp_sync",
|
|
782
|
-
reason,
|
|
783
|
-
budgetMs,
|
|
784
|
-
},
|
|
785
|
-
});
|
|
786
|
-
const cause = abort?.aborted
|
|
787
|
-
? "aborted (Escape)"
|
|
788
|
-
: spawnInFlight
|
|
789
|
-
? `timed out after ${budgetMs}ms; reason: spawn-in-flight (server still cold-spawning)`
|
|
790
|
-
: `timed out after ${budgetMs}ms; server slow/wedged`;
|
|
791
|
-
dbg(`LSP resync ${cause} for ${filePath}`);
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
catch (err) {
|
|
796
|
-
dbg(`LSP resync after autofix error: ${err}`);
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
/** Maps a dispatch `Diagnostic` (clients/dispatch/types.ts) to the #502 bus payload shape. */
|
|
800
|
-
function toPilensDiagnosticEntry(d) {
|
|
801
|
-
const entry = {
|
|
802
|
-
severity: d.severity,
|
|
803
|
-
message: d.message,
|
|
804
|
-
tool: d.tool,
|
|
805
|
-
};
|
|
806
|
-
if (d.rule !== undefined)
|
|
807
|
-
entry.ruleId = d.rule;
|
|
808
|
-
if (d.line !== undefined)
|
|
809
|
-
entry.line = d.line;
|
|
810
|
-
if (d.column !== undefined)
|
|
811
|
-
entry.col = d.column;
|
|
812
|
-
if (d.fixable !== undefined)
|
|
813
|
-
entry.fixable = d.fixable;
|
|
814
|
-
return entry;
|
|
815
|
-
}
|
|
816
|
-
function buildAllClearOutput(_dispatchResult, elapsed, filePath) {
|
|
817
|
-
const kind = detectFileKind(filePath);
|
|
818
|
-
const langLabel = kind ? getFileKindLabel(kind) : path.extname(filePath);
|
|
819
|
-
const parts = [];
|
|
820
|
-
if (kind) {
|
|
821
|
-
parts.push(`${langLabel} clean`);
|
|
822
|
-
}
|
|
823
|
-
parts.push(`${elapsed}ms`);
|
|
824
|
-
return `checkmark ${parts.join(" · ")}`.replace("checkmark", "\u2713");
|
|
825
|
-
}
|
|
826
|
-
export async function runFormatPhase(filePath, getFormatService, dbg, signal, budgetMs = HOOK_WALL_BUDGET_MS.tool_result_edit, hook = "tool_result_edit") {
|
|
827
|
-
let formatChanged = false;
|
|
828
|
-
let formattersUsed = [];
|
|
829
|
-
const formatFailures = [];
|
|
830
|
-
const formatUnavailable = [];
|
|
831
|
-
let fileContent;
|
|
832
|
-
const formatService = getFormatService();
|
|
833
|
-
try {
|
|
834
|
-
formatService.recordRead(filePath);
|
|
835
|
-
const result = await formatService.formatFile(filePath, {
|
|
836
|
-
signal,
|
|
837
|
-
budgetMs,
|
|
838
|
-
hook,
|
|
839
|
-
});
|
|
840
|
-
// An unavailable tool is NOT a formatter that ran (#2413): keep it out of
|
|
841
|
-
// `formattersUsed` (which drives change bookkeeping / turn summaries) and
|
|
842
|
-
// out of `formatFailures` (which requeues). Record it once, distinctly.
|
|
843
|
-
for (const f of result.formatters) {
|
|
844
|
-
if (f.outcome !== "unavailable")
|
|
845
|
-
continue;
|
|
846
|
-
if (f.error?.includes("project tool agreement could not be established"))
|
|
847
|
-
continue;
|
|
848
|
-
const reason = f.error ?? "formatter executable not found";
|
|
849
|
-
formatUnavailable.push({ formatter: f.name, reason });
|
|
850
|
-
recordDegradationOnce({
|
|
851
|
-
kind: "formatter-unavailable",
|
|
852
|
-
subject: `${f.name}:${path.basename(filePath)}`,
|
|
853
|
-
reason,
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
formattersUsed = result.formatters
|
|
857
|
-
.filter((f) => f.outcome !== "unavailable")
|
|
858
|
-
.map((f) => f.name);
|
|
859
|
-
if (result.anyChanged) {
|
|
860
|
-
formatChanged = true;
|
|
861
|
-
dbg("autoformat: " +
|
|
862
|
-
result.formatters
|
|
863
|
-
.map((f) => f.name + "(" + (f.changed ? "changed" : "unchanged") + ")")
|
|
864
|
-
.join(", "));
|
|
865
|
-
}
|
|
866
|
-
if (!result.allSucceeded) {
|
|
867
|
-
const failures = result.formatters.filter((f) => !f.success);
|
|
868
|
-
for (const failure of failures) {
|
|
869
|
-
recordDegradationOnce({
|
|
870
|
-
kind: "formatter-failure",
|
|
871
|
-
subject: `${failure.name}:${path.basename(filePath)}`,
|
|
872
|
-
reason: failure.error ?? "unknown error",
|
|
873
|
-
});
|
|
874
|
-
}
|
|
875
|
-
formatFailures.push(...failures.map((f) => `${f.name}: ${f.error ?? "unknown error"}`));
|
|
876
|
-
dbg("autoformat: " +
|
|
877
|
-
failures
|
|
878
|
-
.map((f) => f.name + " failed: " + (f.error ?? "unknown error"))
|
|
879
|
-
.join("; "));
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
catch (err) {
|
|
883
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
884
|
-
recordDegradationOnce({
|
|
885
|
-
kind: "formatter-failure",
|
|
886
|
-
subject: `format-service:${path.basename(filePath)}`,
|
|
887
|
-
reason: message,
|
|
888
|
-
});
|
|
889
|
-
formatFailures.push(message);
|
|
890
|
-
dbg(`autoformat error: ${err}`);
|
|
891
|
-
}
|
|
892
|
-
try {
|
|
893
|
-
fileContent = nodeFs.readFileSync(filePath, "utf-8");
|
|
894
|
-
}
|
|
895
|
-
catch {
|
|
896
|
-
fileContent = undefined;
|
|
897
|
-
}
|
|
898
|
-
return {
|
|
899
|
-
formatChanged,
|
|
900
|
-
formattersUsed,
|
|
901
|
-
formatFailures,
|
|
902
|
-
formatUnavailable,
|
|
903
|
-
fileContent,
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
/**
|
|
907
|
-
* Build the 🔴 STOP blocker output with an inline code snippet for each
|
|
908
|
-
* diagnostic so the agent can see the exact line it wrote without re-reading
|
|
909
|
-
* the file.
|
|
910
|
-
*
|
|
911
|
-
* Example:
|
|
912
|
-
* L4: 'randomInt' is declared but its value is never read.
|
|
913
|
-
* → const randomInt = Math.floor(result);
|
|
914
|
-
*/
|
|
915
|
-
function buildEnrichedBlockerOutput(blockers, fileContent = "") {
|
|
916
|
-
// #3188: no blockers, no banner. The delivery gate above can retract every
|
|
917
|
-
// blocker (all cited files deleted), and the header interpolates the count,
|
|
918
|
-
// so without this the agent reads "🔴 STOP — 0 issue(s) must be fixed:" with
|
|
919
|
-
// nothing under it. Same guard, same reason, as `formatDiagnostics` in
|
|
920
|
-
// dispatch/utils/format-utils.ts — it belongs to the renderer, not to each
|
|
921
|
-
// call site, because the #2028 branch below cannot gate on the count without
|
|
922
|
-
// falling through to the UNGATED raw output.
|
|
923
|
-
if (blockers.length === 0)
|
|
924
|
-
return "";
|
|
925
|
-
// Empty fileContent (readback failed, e.g. deleted-file race) still
|
|
926
|
-
// renders the gated blocker list - just without per-line snippets.
|
|
927
|
-
const fileLines = fileContent ? fileContent.split("\n") : [];
|
|
928
|
-
const MAX_SNIPPET = 120; // chars — keep it tight in context
|
|
929
|
-
let out = `\n\n🔴 STOP — ${blockers.length} issue(s) must be fixed:\n`;
|
|
930
|
-
const shown = blockers.slice(0, 10);
|
|
931
|
-
for (const d of shown) {
|
|
932
|
-
const lineNo = d.line ?? 1;
|
|
933
|
-
const nodeCtx = d.astNodeType ? ` (${d.astNodeType})` : "";
|
|
934
|
-
out += ` L${lineNo}: ${d.message}${nodeCtx}\n`;
|
|
935
|
-
// Prefer the exact matched node text (tree-sitter); fall back to the
|
|
936
|
-
// full source line (LSP / other runners).
|
|
937
|
-
const snippet = d.matchedText
|
|
938
|
-
? d.matchedText.trim().split("\n")[0]?.slice(0, MAX_SNIPPET)
|
|
939
|
-
: fileLines[lineNo - 1]?.trim().slice(0, MAX_SNIPPET);
|
|
940
|
-
if (snippet)
|
|
941
|
-
out += ` → ${snippet}\n`;
|
|
942
|
-
if (d.fixSuggestion)
|
|
943
|
-
out += ` 💡 ${d.fixSuggestion}\n`;
|
|
944
|
-
}
|
|
945
|
-
if (blockers.length > 10) {
|
|
946
|
-
out += ` ... and ${blockers.length - 10} more\n`;
|
|
947
|
-
}
|
|
948
|
-
return out;
|
|
949
|
-
}
|
|
950
|
-
// --- Main Pipeline ---
|
|
951
|
-
export async function runPipeline(ctx, deps) {
|
|
952
|
-
const { filePath, cwd, toolName, getFlag, getFlagSource, dbg } = ctx;
|
|
953
|
-
const { getFormatService } = deps;
|
|
954
|
-
const allowAutonomousWriters = ctx.allowAutonomousWriters !== false;
|
|
955
|
-
if (!allowAutonomousWriters) {
|
|
956
|
-
incrementDegradationCount({
|
|
957
|
-
kind: "opaque-mutation-ownership-boundary",
|
|
958
|
-
subject: "pipeline",
|
|
959
|
-
reason: `observed mutation is not evidence of agent authorship (${filePath})`,
|
|
960
|
-
});
|
|
961
|
-
}
|
|
962
|
-
admitWidgetDiagnosticsWrite(filePath, ctx.telemetry?.writeIndex);
|
|
963
|
-
const phase = createPhaseTracker(toolName, filePath);
|
|
964
|
-
const pipelineStart = Date.now();
|
|
965
|
-
clearGraphCache();
|
|
966
|
-
phase.start("total");
|
|
967
|
-
// --- 1. Read file content ---
|
|
968
|
-
phase.start("read_file");
|
|
969
|
-
let fileContent;
|
|
970
|
-
try {
|
|
971
|
-
fileContent = nodeFs.readFileSync(filePath, "utf-8");
|
|
972
|
-
}
|
|
973
|
-
catch {
|
|
974
|
-
// File may not exist (e.g., deleted)
|
|
975
|
-
}
|
|
976
|
-
phase.end("read_file");
|
|
977
|
-
// --- 2. Auto-format ---
|
|
978
|
-
phase.start("format");
|
|
979
|
-
let formatChanged = false;
|
|
980
|
-
let formattersUsed = [];
|
|
981
|
-
let formatFailures = [];
|
|
982
|
-
const piChangedFiles = new Set();
|
|
983
|
-
const autoformatDisabled = !!getFlag("no-autoformat", filePath);
|
|
984
|
-
const immediateFormat = !!getFlag("immediate-format");
|
|
985
|
-
const formatDeferred = allowAutonomousWriters &&
|
|
986
|
-
!autoformatDisabled &&
|
|
987
|
-
!immediateFormat &&
|
|
988
|
-
!!fileContent;
|
|
989
|
-
if (allowAutonomousWriters &&
|
|
990
|
-
!autoformatDisabled &&
|
|
991
|
-
immediateFormat &&
|
|
992
|
-
fileContent) {
|
|
993
|
-
const formatResult = await runFormatPhase(filePath, getFormatService, dbg, ctx.signal);
|
|
994
|
-
formatChanged = formatResult.formatChanged;
|
|
995
|
-
formattersUsed = formatResult.formattersUsed;
|
|
996
|
-
formatFailures = formatResult.formatFailures;
|
|
997
|
-
fileContent = formatResult.fileContent;
|
|
998
|
-
if (formatChanged) {
|
|
999
|
-
const absPath = path.resolve(filePath);
|
|
1000
|
-
piChangedFiles.add(absPath);
|
|
1001
|
-
publishFilesTouched({
|
|
1002
|
-
reason: "format",
|
|
1003
|
-
paths: [absPath],
|
|
1004
|
-
cwd,
|
|
1005
|
-
dbg,
|
|
1006
|
-
fixes: formattersUsed.map((tool) => ({
|
|
1007
|
-
path: absPath,
|
|
1008
|
-
tool,
|
|
1009
|
-
kind: "format",
|
|
1010
|
-
})),
|
|
1011
|
-
});
|
|
1012
|
-
}
|
|
1013
|
-
}
|
|
1014
|
-
else if (formatDeferred) {
|
|
1015
|
-
dbg(`autoformat: deferred until agent_end for ${filePath}`);
|
|
1016
|
-
}
|
|
1017
|
-
else if (!allowAutonomousWriters) {
|
|
1018
|
-
dbg(`autoformat: skipped for ${filePath} (mutation ownership is unproven)`);
|
|
1019
|
-
}
|
|
1020
|
-
else if (autoformatDisabled) {
|
|
1021
|
-
const source = getFlagSource?.("no-autoformat", filePath);
|
|
1022
|
-
dbg(`autoformat: skipped for ${filePath} (--no-autoformat${source ? `, source=${source}` : ""})`);
|
|
1023
|
-
}
|
|
1024
|
-
phase.end("format", {
|
|
1025
|
-
formattersUsed,
|
|
1026
|
-
formatChanged,
|
|
1027
|
-
deferred: formatDeferred,
|
|
1028
|
-
});
|
|
1029
|
-
// --- 3. Auto-fix ---
|
|
1030
|
-
phase.start("autofix");
|
|
1031
|
-
let fixedCount = 0;
|
|
1032
|
-
let autofixTools = [];
|
|
1033
|
-
let attemptedTools = [];
|
|
1034
|
-
let autofixChangedFiles = [];
|
|
1035
|
-
let fixRefresh = false;
|
|
1036
|
-
let autofixSkipReason;
|
|
1037
|
-
if (!allowAutonomousWriters) {
|
|
1038
|
-
autofixSkipReason = "mutation_ownership_unproven";
|
|
1039
|
-
dbg(`autofix: skipped for ${filePath} (mutation ownership is unproven)`);
|
|
1040
|
-
}
|
|
1041
|
-
else if (ctx.autofixMode === "deferred") {
|
|
1042
|
-
autofixSkipReason = "deferred_to_agent_end";
|
|
1043
|
-
dbg(`autofix: deferred until agent_end for ${filePath}`);
|
|
1044
|
-
}
|
|
1045
|
-
else
|
|
1046
|
-
({
|
|
1047
|
-
fixedCount,
|
|
1048
|
-
autofixTools,
|
|
1049
|
-
attemptedTools,
|
|
1050
|
-
changedFiles: autofixChangedFiles,
|
|
1051
|
-
needsContentRefresh: fixRefresh,
|
|
1052
|
-
skipReason: autofixSkipReason,
|
|
1053
|
-
} = await runAutofix(filePath, cwd, getFlag, dbg, deps, getFlagSource));
|
|
1054
|
-
for (const changedFile of autofixChangedFiles) {
|
|
1055
|
-
piChangedFiles.add(path.resolve(changedFile));
|
|
1056
|
-
}
|
|
1057
|
-
if (autofixChangedFiles.length > 0) {
|
|
1058
|
-
// autofixTools entries are "tool:count" (e.g. "ruff:3"); runAutofix runs
|
|
1059
|
-
// against ONE target filePath per call, so every tool that fired in this
|
|
1060
|
-
// batch applies to every file the batch changed — best-effort attribution
|
|
1061
|
-
// (not per-file precision) since the underlying tool runners don't report
|
|
1062
|
-
// per-changed-file breakdown. Good enough for the "was this hunk
|
|
1063
|
-
// mechanical" use case the fix-provenance field exists for.
|
|
1064
|
-
const absChangedFiles = autofixChangedFiles.map((f) => path.resolve(f));
|
|
1065
|
-
const toolNames = autofixTools.map((t) => t.split(":")[0]);
|
|
1066
|
-
publishFilesTouched({
|
|
1067
|
-
reason: "autofix",
|
|
1068
|
-
paths: absChangedFiles,
|
|
1069
|
-
cwd,
|
|
1070
|
-
dbg,
|
|
1071
|
-
fixes: absChangedFiles.flatMap((p) => toolNames.map((tool) => ({ path: p, tool, kind: "autofix" }))),
|
|
1072
|
-
});
|
|
1073
|
-
}
|
|
1074
|
-
if (fixRefresh) {
|
|
1075
|
-
try {
|
|
1076
|
-
fileContent = nodeFs.readFileSync(filePath, "utf-8");
|
|
1077
|
-
}
|
|
1078
|
-
catch {
|
|
1079
|
-
fileContent = undefined;
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
phase.end("autofix", {
|
|
1083
|
-
fixedCount,
|
|
1084
|
-
tools: autofixTools,
|
|
1085
|
-
attemptedTools,
|
|
1086
|
-
skipReason: autofixSkipReason,
|
|
1087
|
-
});
|
|
1088
|
-
// Capture the target's bytes immediately after pi-lens writes and before any
|
|
1089
|
-
// awaitable LSP or dispatch work. `fileModified` also covers side-effect
|
|
1090
|
-
// files, so target membership is the discriminator for pipeline ownership
|
|
1091
|
-
// (#2499).
|
|
1092
|
-
const fileModified = formatChanged || fixedCount > 0;
|
|
1093
|
-
const targetFileModified = piChangedFiles.has(path.resolve(filePath));
|
|
1094
|
-
const postWriteStateHash = fileModified && targetFileModified
|
|
1095
|
-
? (() => {
|
|
1096
|
-
try {
|
|
1097
|
-
return nodeCrypto
|
|
1098
|
-
.createHash("sha256")
|
|
1099
|
-
.update(nodeFs.readFileSync(filePath))
|
|
1100
|
-
.digest("hex");
|
|
1101
|
-
}
|
|
1102
|
-
catch (error) {
|
|
1103
|
-
recordDegradationOnce({
|
|
1104
|
-
kind: "pipeline-post-write-hash-unavailable",
|
|
1105
|
-
subject: filePath,
|
|
1106
|
-
reason: error instanceof Error ? error.message : String(error),
|
|
1107
|
-
});
|
|
1108
|
-
return undefined;
|
|
1109
|
-
}
|
|
1110
|
-
})()
|
|
1111
|
-
: undefined;
|
|
1112
|
-
// --- 4. LSP file sync ---
|
|
1113
|
-
// Sync once with final post-format/post-fix content so dispatch and cascade
|
|
1114
|
-
// diagnostics do not observe stale pre-format text.
|
|
1115
|
-
phase.start("lsp_sync");
|
|
1116
|
-
let lspSyncCompleted = false;
|
|
1117
|
-
if (fileContent) {
|
|
1118
|
-
await resyncLspFile(filePath, fileContent, true, false, getFlag, dbg);
|
|
1119
|
-
lspSyncCompleted = true;
|
|
1120
|
-
}
|
|
1121
|
-
phase.end("lsp_sync", { completed: lspSyncCompleted, finalContent: true });
|
|
1122
|
-
// --- 5. Dispatch lint ---
|
|
1123
|
-
phase.start("dispatch_lint");
|
|
1124
|
-
dbg(`dispatch: running lint tools for ${filePath}`);
|
|
1125
|
-
const piApi = {
|
|
1126
|
-
getFlag: getFlag,
|
|
1127
|
-
};
|
|
1128
|
-
const { dispatchLintWithResult, computeCascadeForFile } = await loadDispatchIntegration();
|
|
1129
|
-
// Capture the bytes the pipeline presents to analysis before the dispatch
|
|
1130
|
-
// promise can yield to another writer. The blocker evidence below belongs to
|
|
1131
|
-
// this analysis input, not to whatever happens to be on disk when the whole
|
|
1132
|
-
// pipeline returns.
|
|
1133
|
-
const inlineBlockerFileContent = fileContent
|
|
1134
|
-
? (() => {
|
|
1135
|
-
const content = Buffer.from(fileContent, "utf8");
|
|
1136
|
-
return content.byteLength <= 2 * 1024 * 1024
|
|
1137
|
-
? {
|
|
1138
|
-
size: content.byteLength,
|
|
1139
|
-
sha256: createHash("sha256").update(content).digest("hex"),
|
|
1140
|
-
}
|
|
1141
|
-
: undefined;
|
|
1142
|
-
})()
|
|
1143
|
-
: undefined;
|
|
1144
|
-
const dispatchResult = await dispatchLintWithResult(filePath, cwd, piApi, ctx.modifiedRanges, {
|
|
1145
|
-
model: ctx.telemetry?.model ?? "unknown",
|
|
1146
|
-
sessionId: ctx.telemetry?.sessionId ?? "unknown",
|
|
1147
|
-
turnIndex: ctx.telemetry?.turnIndex ?? 0,
|
|
1148
|
-
writeIndex: ctx.telemetry?.writeIndex ?? 0,
|
|
1149
|
-
}, {
|
|
1150
|
-
projectRoot: ctx.projectRoot,
|
|
1151
|
-
writeIndex: ctx.telemetry?.writeIndex,
|
|
1152
|
-
telemetryModel: ctx.telemetry?.modelId,
|
|
1153
|
-
telemetryProvider: ctx.telemetry?.provider,
|
|
1154
|
-
});
|
|
1155
|
-
recordDiagnostics(filePath, dispatchResult.diagnostics, ctx.telemetry?.writeIndex);
|
|
1156
|
-
// #502: emit the write batch's FINAL diagnostic state immediately after
|
|
1157
|
-
// recordDiagnostics commits it — this call site runs after format,
|
|
1158
|
-
// autofix, and dispatch have all completed for this batch (see the phase
|
|
1159
|
-
// order above), so dispatchResult.diagnostics IS the latest post-batch
|
|
1160
|
-
// picture, not an intermediate runner result. Full-replace semantics: we
|
|
1161
|
-
// always pass the complete current set for this file, including an
|
|
1162
|
-
// explicit `[]` on the transition from a previously-reported-dirty state
|
|
1163
|
-
// to clean (see clients/diagnostics-publish.ts for the contract).
|
|
1164
|
-
{
|
|
1165
|
-
const absPath = path.resolve(filePath);
|
|
1166
|
-
const wasDirty = wasPreviouslyReportedDirty(absPath);
|
|
1167
|
-
if (dispatchResult.diagnostics.length > 0 || wasDirty) {
|
|
1168
|
-
publishDiagnostics({
|
|
1169
|
-
cwd,
|
|
1170
|
-
files: [
|
|
1171
|
-
{
|
|
1172
|
-
path: absPath,
|
|
1173
|
-
diagnostics: dispatchResult.diagnostics.map(toPilensDiagnosticEntry),
|
|
1174
|
-
},
|
|
1175
|
-
],
|
|
1176
|
-
dbg,
|
|
1177
|
-
});
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
// Opaque recovery is a valid analysis input, but its bytes are not an agent
|
|
1181
|
-
// authored surface. Keep diagnostics and advisory output visible while
|
|
1182
|
-
// withholding the edit-directed channels that would tell the agent to mutate
|
|
1183
|
-
// the observed artifact (#3226).
|
|
1184
|
-
const hasBlockers = allowAutonomousWriters && dispatchResult.hasBlockers;
|
|
1185
|
-
const actionableWarnings = allowAutonomousWriters
|
|
1186
|
-
? dispatchResult.warnings
|
|
1187
|
-
.map((diagnostic) => recordFromDispatchDiagnostic(diagnostic, cwd))
|
|
1188
|
-
.filter((warning) => Boolean(warning))
|
|
1189
|
-
: [];
|
|
1190
|
-
const codeQualityWarnings = dispatchResult.warnings
|
|
1191
|
-
.map((diagnostic) => recordFromCodeQualityDiagnostic(diagnostic, cwd))
|
|
1192
|
-
.filter((warning) => Boolean(warning));
|
|
1193
|
-
if (dispatchResult.diagnostics.length > 0) {
|
|
1194
|
-
const tracker = getDiagnosticTracker();
|
|
1195
|
-
tracker.trackShown(dispatchResult.diagnostics);
|
|
1196
|
-
}
|
|
1197
|
-
if (fixedCount > 0)
|
|
1198
|
-
getDiagnosticTracker().trackAutoFixed(fixedCount);
|
|
1199
|
-
if (dispatchResult.resolvedCount > 0)
|
|
1200
|
-
getDiagnosticTracker().trackAgentFixed(dispatchResult.resolvedCount);
|
|
1201
|
-
let output = "";
|
|
1202
|
-
// #2028: the 🔴 STOP block is an agent-facing delivery surface
|
|
1203
|
-
// (finding-delivery-gate.ts's `tool-call:stop-blocker`), so it routes through
|
|
1204
|
-
// the shared deleted-path gate before rendering: a blocker whose cited file
|
|
1205
|
-
// no longer exists has no remediation the agent can perform (the finding IS
|
|
1206
|
-
// the deleted file's content), so it is dropped here rather than re-asserted.
|
|
1207
|
-
// One bounded stat per unique cited path, only when blockers exist — zero
|
|
1208
|
-
// cost on the clean/fast paths.
|
|
1209
|
-
const deliverableBlockers = hasBlockers
|
|
1210
|
-
? dropFindingsForMissingPaths({
|
|
1211
|
-
store: "stop-blocker",
|
|
1212
|
-
findings: dispatchResult.blockers,
|
|
1213
|
-
cwd,
|
|
1214
|
-
citedPath: (b) => b.filePath || undefined,
|
|
1215
|
-
})
|
|
1216
|
-
: [];
|
|
1217
|
-
// #3190: ONE gate, applied once here, for EVERY surface. The durable record
|
|
1218
|
-
// this function hands `runtime.recordInlineBlockers` (and through it the
|
|
1219
|
-
// turn-end `Unresolved from this turn` re-serve) used to be built from the
|
|
1220
|
-
// UNGATED `dispatchResult.blockerOutput`/`blockers`, so a blocker retracted
|
|
1221
|
-
// from the tool result above was re-delivered at turn end — and the ungated
|
|
1222
|
-
// verdict still latched the commit gate through `updateGitGuardStatus`. It is
|
|
1223
|
-
// exactly `hasBlockers && nothing-survived-the-gate` inverted: the gate
|
|
1224
|
-
// returns `[]` whenever `hasBlockers` is false, so this one expression is the
|
|
1225
|
-
// whole condition.
|
|
1226
|
-
const hasDeliverableBlockers = deliverableBlockers.length > 0;
|
|
1227
|
-
if (dispatchResult.diagnostics.length > 0) {
|
|
1228
|
-
const logger = getDiagnosticLogger();
|
|
1229
|
-
const toKey = (d) => [
|
|
1230
|
-
d.tool || "",
|
|
1231
|
-
d.id || "",
|
|
1232
|
-
d.rule || "",
|
|
1233
|
-
d.filePath || "",
|
|
1234
|
-
d.line || 0,
|
|
1235
|
-
d.column || 0,
|
|
1236
|
-
].join("|");
|
|
1237
|
-
const inlineKeys = new Set([...deliverableBlockers, ...dispatchResult.fixed].map(toKey));
|
|
1238
|
-
for (const d of dispatchResult.diagnostics) {
|
|
1239
|
-
logger.logCaught(d, {
|
|
1240
|
-
model: ctx.telemetry?.model ?? "unknown",
|
|
1241
|
-
sessionId: ctx.telemetry?.sessionId ?? "unknown",
|
|
1242
|
-
turnIndex: ctx.telemetry?.turnIndex ?? 0,
|
|
1243
|
-
writeIndex: ctx.telemetry?.writeIndex ?? 0,
|
|
1244
|
-
}, inlineKeys.has(toKey(d)));
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
const deliveredOutput = !allowAutonomousWriters && dispatchResult.hasBlockers
|
|
1248
|
-
? dispatchResult.output.slice(dispatchResult.blockerOutput.length)
|
|
1249
|
-
: dispatchResult.output;
|
|
1250
|
-
if (hasBlockers && fileContent) {
|
|
1251
|
-
// Enrich blocker output with a code snippet so the agent can see the
|
|
1252
|
-
// exact line it wrote that caused each violation — no re-read needed.
|
|
1253
|
-
if (deliverableBlockers.length > 0) {
|
|
1254
|
-
output += buildEnrichedBlockerOutput(deliverableBlockers, fileContent);
|
|
1255
|
-
}
|
|
1256
|
-
// Append fixed/coverage parts from the original output (slice off the
|
|
1257
|
-
// blocker section we're replacing).
|
|
1258
|
-
const rest = dispatchResult.output.slice(dispatchResult.blockerOutput.length);
|
|
1259
|
-
if (rest)
|
|
1260
|
-
output += rest;
|
|
1261
|
-
}
|
|
1262
|
-
else if (deliveredOutput) {
|
|
1263
|
-
// #2028 review P3: this path fires when readback FAILED - raw output
|
|
1264
|
-
// still cites possibly-deleted files. Re-render from the gated set
|
|
1265
|
-
// (no snippets without fileContent) and keep the post-blocker slice.
|
|
1266
|
-
if (hasBlockers &&
|
|
1267
|
-
deliverableBlockers.length !== dispatchResult.blockers.length) {
|
|
1268
|
-
let gatedOut = buildEnrichedBlockerOutput(deliverableBlockers);
|
|
1269
|
-
const rest = dispatchResult.output.slice(dispatchResult.blockerOutput.length);
|
|
1270
|
-
if (rest)
|
|
1271
|
-
gatedOut += rest;
|
|
1272
|
-
// #3188: every blocker retracted and nothing after the blocker
|
|
1273
|
-
// section leaves nothing to say — appending the separator alone would
|
|
1274
|
-
// still deliver a (whitespace-only) tool-result block, because
|
|
1275
|
-
// `handleToolResult` decides delivery on `output` truthiness.
|
|
1276
|
-
if (gatedOut)
|
|
1277
|
-
output += `\n\n${gatedOut}`;
|
|
1278
|
-
}
|
|
1279
|
-
else {
|
|
1280
|
-
output += `\n\n${deliveredOutput}`;
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1283
|
-
if (fixedCount > 0) {
|
|
1284
|
-
const detail = autofixTools.length > 0 ? ` (${autofixTools.join(", ")})` : "";
|
|
1285
|
-
output += `\n\n✅ Auto-fixed ${fixedCount} issue(s)${detail}`;
|
|
1286
|
-
}
|
|
1287
|
-
if (formatFailures.length > 0) {
|
|
1288
|
-
const details = formatFailures.slice(0, 3).join("; ");
|
|
1289
|
-
const suffix = formatFailures.length > 3
|
|
1290
|
-
? `; ... and ${formatFailures.length - 3} more`
|
|
1291
|
-
: "";
|
|
1292
|
-
output += `\n\n⚠️ Auto-format failed: ${details}${suffix}`;
|
|
1293
|
-
}
|
|
1294
|
-
// #1590: the notice sentence itself is NOT rendered here. This layer cannot
|
|
1295
|
-
// see the attachment cap or the aggregate budget, so it hands the display
|
|
1296
|
-
// paths to `handleToolResult`, which owns the decision and renders the one
|
|
1297
|
-
// sentence with `renderPostAutofixNotice`.
|
|
1298
|
-
const postAutofixNotice = formatChanged || fixedCount > 0
|
|
1299
|
-
? {
|
|
1300
|
-
targetPath: toRunnerDisplayPath(cwd, filePath),
|
|
1301
|
-
changedFiles: [...piChangedFiles].map((changedFile) => toRunnerDisplayPath(cwd, changedFile)),
|
|
1302
|
-
}
|
|
1303
|
-
: undefined;
|
|
1304
|
-
phase.end("dispatch_lint", {
|
|
1305
|
-
hasOutput: !!dispatchResult.output,
|
|
1306
|
-
diagnosticCount: dispatchResult.diagnostics.length,
|
|
1307
|
-
});
|
|
1308
|
-
// --- 6. Cascade diagnostics (LSP only) ---
|
|
1309
|
-
// Kicked off UNAWAITED so the graph rebuild + neighbor LSP pulls run
|
|
1310
|
-
// concurrently after the edit returns rather than blocking it (#450). The
|
|
1311
|
-
// result is never shown inline — settled (bounded) and surfaced at turn_end.
|
|
1312
|
-
// The stored promise must never reject: an unhandled rejection is fatal, so a
|
|
1313
|
-
// failing compute resolves to an "error" skip-run instead.
|
|
1314
|
-
const cascadeOrigin = {
|
|
1315
|
-
turnSeq: ctx.telemetry?.turnIndex,
|
|
1316
|
-
writeSeq: ctx.telemetry?.writeIndex,
|
|
1317
|
-
projectSeq: ctx.seqState?.projectSeq(),
|
|
1318
|
-
};
|
|
1319
|
-
const cascadePromise = getFlag("no-lsp")
|
|
1320
|
-
? undefined
|
|
1321
|
-
: computeCascadeForFile(filePath, cwd, {
|
|
1322
|
-
hasBlockers,
|
|
1323
|
-
dbg,
|
|
1324
|
-
turnSeq: ctx.telemetry?.turnIndex,
|
|
1325
|
-
writeSeq: ctx.telemetry?.writeIndex,
|
|
1326
|
-
// #3157: `cwd` here is the LANGUAGE root. The cascade's display
|
|
1327
|
-
// filter reads the disposition store and the `.pi-lens.json` rule
|
|
1328
|
-
// policy, both written under the PROJECT root (#1030) — the same
|
|
1329
|
-
// pair the dispatcher is handed above.
|
|
1330
|
-
projectRoot: ctx.projectRoot,
|
|
1331
|
-
seqState: ctx.seqState,
|
|
1332
|
-
turnEndCascadeSettleStart: ctx.turnEndCascadeSettleStart,
|
|
1333
|
-
fileContent,
|
|
1334
|
-
wordIndex: ctx.wordIndex,
|
|
1335
|
-
onWordIndexUpdated: ctx.onWordIndexUpdated,
|
|
1336
|
-
})
|
|
1337
|
-
.then((run) => ({ ...run, origin: cascadeOrigin }))
|
|
1338
|
-
.catch((err) => {
|
|
1339
|
-
dbg(`cascade compute failed for ${filePath}: ${err}`);
|
|
1340
|
-
return {
|
|
1341
|
-
filePath,
|
|
1342
|
-
origin: cascadeOrigin,
|
|
1343
|
-
result: undefined,
|
|
1344
|
-
neighborCount: 0,
|
|
1345
|
-
diagnosticCount: 0,
|
|
1346
|
-
skipReason: "error",
|
|
1347
|
-
// #1023: a thrown compute is ALSO "couldn't compute downstream
|
|
1348
|
-
// impact" — carry an indeterminate marker so turn_end surfaces an
|
|
1349
|
-
// honest advisory instead of the error skip being logs-only.
|
|
1350
|
-
indeterminate: {
|
|
1351
|
-
reason: "error",
|
|
1352
|
-
detail: "cascade computation failed",
|
|
1353
|
-
},
|
|
1354
|
-
};
|
|
1355
|
-
});
|
|
1356
|
-
// --- Final timing + all-clear ---
|
|
1357
|
-
const elapsed = Date.now() - pipelineStart;
|
|
1358
|
-
// #1590: `postAutofixNotice` is output this run produces, just rendered a
|
|
1359
|
-
// layer up. Treat it as output here, or a format-only change would newly
|
|
1360
|
-
// gain an "all clear" line it never had while the sentence lived inline.
|
|
1361
|
-
if (!output && !postAutofixNotice) {
|
|
1362
|
-
output = buildAllClearOutput(dispatchResult, elapsed, filePath);
|
|
1363
|
-
}
|
|
1364
|
-
phase.end("total", { hasOutput: !!output });
|
|
1365
|
-
const changedFiles = [...piChangedFiles];
|
|
1366
|
-
emitLensAnalysisComplete({
|
|
1367
|
-
cwd,
|
|
1368
|
-
filePath,
|
|
1369
|
-
toolName,
|
|
1370
|
-
model: ctx.telemetry?.model ?? "unknown",
|
|
1371
|
-
sessionId: ctx.telemetry?.sessionId ?? "unknown",
|
|
1372
|
-
turnIndex: ctx.telemetry?.turnIndex ?? 0,
|
|
1373
|
-
writeIndex: ctx.telemetry?.writeIndex ?? 0,
|
|
1374
|
-
diagnostics: dispatchResult.diagnostics,
|
|
1375
|
-
blockers: hasBlockers ? dispatchResult.blockers : [],
|
|
1376
|
-
warnings: dispatchResult.warnings,
|
|
1377
|
-
fixed: dispatchResult.fixed,
|
|
1378
|
-
resolvedCount: dispatchResult.resolvedCount,
|
|
1379
|
-
hasBlockers,
|
|
1380
|
-
fileModified,
|
|
1381
|
-
changedFiles,
|
|
1382
|
-
durationMs: elapsed,
|
|
1383
|
-
});
|
|
1384
|
-
return {
|
|
1385
|
-
output,
|
|
1386
|
-
// #3190: the verdict every consumer reads — `updateGitGuardStatus`'s commit
|
|
1387
|
-
// latch above all — is what was DELIVERED, not what the dispatch found. The
|
|
1388
|
-
// two disagreed whenever the deleted-path gate retracted every blocker: the
|
|
1389
|
-
// tool result said `✓ clean` while the commit gate stayed latched, its
|
|
1390
|
-
// summary falling back to that very all-clear line. `emitLensAnalysisComplete`
|
|
1391
|
-
// above deliberately keeps the raw dispatch counts — it records what was
|
|
1392
|
-
// observed, not what was served.
|
|
1393
|
-
hasBlockers: hasDeliverableBlockers,
|
|
1394
|
-
cascadePromise,
|
|
1395
|
-
isError: false,
|
|
1396
|
-
fileModified,
|
|
1397
|
-
postWriteStateHash,
|
|
1398
|
-
changedFiles,
|
|
1399
|
-
// #3190: re-rendered from the GATED set with `formatDiagnostics(...,
|
|
1400
|
-
// "blocking")` — the very expression `dispatcher.ts:1409` builds
|
|
1401
|
-
// `blockerOutput` with, over a subset of the very array it rendered. When
|
|
1402
|
-
// the gate drops nothing the two are byte-identical (same renderer, same
|
|
1403
|
-
// array, same display cap), so an unretracted record is unchanged; when it
|
|
1404
|
-
// drops something the stored text can no longer disagree with the tool
|
|
1405
|
-
// result, and `inline-blocker-dispositions.ts`' re-render at turn end still
|
|
1406
|
-
// matches this string exactly.
|
|
1407
|
-
inlineBlockerSummary: hasDeliverableBlockers
|
|
1408
|
-
? formatDiagnostics(deliverableBlockers, "blocking").trim() || undefined
|
|
1409
|
-
: undefined,
|
|
1410
|
-
// #1561 F1: taken from the very diagnostics `blockerOutput` was rendered
|
|
1411
|
-
// from, so the provenance can never disagree with the text it guards. An
|
|
1412
|
-
// untagged diagnostic contributes the literal "unknown", which no verdict
|
|
1413
|
-
// claims coverage for — it pins the entry rather than silently widening
|
|
1414
|
-
// what an LSP check is allowed to clear.
|
|
1415
|
-
inlineBlockerSources: hasDeliverableBlockers
|
|
1416
|
-
? [
|
|
1417
|
-
...new Set(deliverableBlockers.map((d) => d.tool?.trim() || "unknown")),
|
|
1418
|
-
]
|
|
1419
|
-
: undefined,
|
|
1420
|
-
inlineBlockerLines: hasDeliverableBlockers
|
|
1421
|
-
? deliverableBlockers
|
|
1422
|
-
// #1641 review F2: the blocker array (#3190: the deliverable subset
|
|
1423
|
-
// of `dispatchResult.blockers`) is NOT guaranteed to be
|
|
1424
|
-
// scoped to THIS file — a chart-wide runner (helm-lint, helm-render)
|
|
1425
|
-
// reports blocking diagnostics against other files in the chart
|
|
1426
|
-
// (e.g. `values.yaml`) alongside `ctx.filePath`. The precedent every
|
|
1427
|
-
// per-file runner already follows (dotnet-build.ts, javac.ts) is to
|
|
1428
|
-
// drop cross-file rows before they reach a per-file record; this is
|
|
1429
|
-
// that same filter applied at the aggregation point instead, since
|
|
1430
|
-
// `blockers` is pooled across every runner dispatched for this file.
|
|
1431
|
-
// Without it, a cross-file line count gets attributed to THIS
|
|
1432
|
-
// file's past-EOF check and can demote an in-bounds, fully valid
|
|
1433
|
-
// blocker for content the diagnostic never described.
|
|
1434
|
-
//
|
|
1435
|
-
// #1641 review round 2 (LOW): `path.resolve` equality doesn't fold
|
|
1436
|
-
// case, and an LSP-sourced diagnostic's `filePath` is stamped with
|
|
1437
|
-
// realpath canonical casing (dispatch/runners/lsp.ts ->
|
|
1438
|
-
// normalizeMapKey) while `ctx.filePath` can arrive lowercase-drive
|
|
1439
|
-
// on Windows — the drive-letter class from #1139/#1150. A bare
|
|
1440
|
-
// `path.resolve` equality then drops EVERY LSP blocker line and
|
|
1441
|
-
// this record silently skips the past-EOF gate (fail-open, but
|
|
1442
|
-
// exactly the pre-fix behavior on the surface #1641 targets).
|
|
1443
|
-
// `normalizeEphemeralMapKey` slash-folds and (on win32)
|
|
1444
|
-
// lowercase-folds both sides with no filesystem I/O — cheap enough
|
|
1445
|
-
// for this per-blocker hot-path filter. `pathsEqual` was
|
|
1446
|
-
// deliberately NOT used here: it calls `realpathSync` per
|
|
1447
|
-
// comparison, which this filter cannot afford per blocker.
|
|
1448
|
-
.filter((d) => normalizeEphemeralMapKey(d.filePath) ===
|
|
1449
|
-
normalizeEphemeralMapKey(filePath))
|
|
1450
|
-
.map((d) => d.line)
|
|
1451
|
-
.filter((line) => typeof line === "number")
|
|
1452
|
-
: undefined,
|
|
1453
|
-
actionableWarnings,
|
|
1454
|
-
codeQualityWarnings,
|
|
1455
|
-
diagnostics: dispatchResult.diagnostics,
|
|
1456
|
-
formattersUsed,
|
|
1457
|
-
fixedCount,
|
|
1458
|
-
autofixTools,
|
|
1459
|
-
postAutofixNotice,
|
|
1460
|
-
postMutation: ctx.autofixMode !== "deferred" &&
|
|
1461
|
-
autofixChangedFiles.some((f) => path.resolve(f) === path.resolve(filePath)) &&
|
|
1462
|
-
fileContent !== undefined
|
|
1463
|
-
? {
|
|
1464
|
-
filePath: path.resolve(filePath),
|
|
1465
|
-
content: fileContent,
|
|
1466
|
-
source: "autofix",
|
|
1467
|
-
}
|
|
1468
|
-
: undefined,
|
|
1469
|
-
inlineBlockerFileContent: hasBlockers
|
|
1470
|
-
? inlineBlockerFileContent
|
|
1471
|
-
: undefined,
|
|
1472
|
-
// #3246: the very array `blockerOutput` above was rendered from, so the
|
|
1473
|
-
// turn-end policy filter and its re-render can never disagree with the
|
|
1474
|
-
// text they guard — the same provenance argument `inlineBlockerSources`
|
|
1475
|
-
// makes one field up.
|
|
1476
|
-
inlineBlockerDiagnostics: hasDeliverableBlockers
|
|
1477
|
-
? deliverableBlockers
|
|
1478
|
-
: undefined,
|
|
1479
|
-
};
|
|
1480
|
-
}
|