@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
|
@@ -79,6 +79,7 @@ async function main() {
|
|
|
79
79
|
analyzeActionableWarnings(files.actionableWarnings, state),
|
|
80
80
|
analyzeAstGrepTools(files.astGrepTools, state),
|
|
81
81
|
analyzeWorklog(files.worklog, state),
|
|
82
|
+
analyzeExtension(files.extension, state),
|
|
82
83
|
]);
|
|
83
84
|
|
|
84
85
|
const report = buildReport(state);
|
|
@@ -165,18 +166,34 @@ function discoverLogFiles(logRoot, archived) {
|
|
|
165
166
|
});
|
|
166
167
|
|
|
167
168
|
return {
|
|
168
|
-
latency: byPrefix("latency"),
|
|
169
|
-
sessionStart: byPrefix("sessionstart"),
|
|
170
|
-
cascade: byPrefix("cascade"),
|
|
171
|
-
readGuard: byPrefix("read-guard"),
|
|
172
|
-
treeSitter: byPrefix("tree-sitter"),
|
|
173
|
-
actionableWarnings: byPrefix("actionable-warnings"),
|
|
174
|
-
astGrepTools: byPrefix("ast-grep-tools"),
|
|
169
|
+
latency: chronologicalFiles(byPrefix("latency")),
|
|
170
|
+
sessionStart: chronologicalFiles(byPrefix("sessionstart")),
|
|
171
|
+
cascade: chronologicalFiles(byPrefix("cascade")),
|
|
172
|
+
readGuard: chronologicalFiles(byPrefix("read-guard")),
|
|
173
|
+
treeSitter: chronologicalFiles(byPrefix("tree-sitter")),
|
|
174
|
+
actionableWarnings: chronologicalFiles(byPrefix("actionable-warnings")),
|
|
175
|
+
astGrepTools: chronologicalFiles(byPrefix("ast-grep-tools")),
|
|
176
|
+
extension: chronologicalFiles(byPrefix("extension")),
|
|
175
177
|
diagnostics: dailyLogs,
|
|
176
178
|
worklog: worklogs,
|
|
177
179
|
};
|
|
178
180
|
}
|
|
179
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Rotated siblings (`x.log.1`) carry older rows than the active `x.log`. The
|
|
184
|
+
* run-splitting detectors (D3/D4/D5) and the read-guard evidence walk (D10)
|
|
185
|
+
* only read correctly in chronological order, so order every multi-file stream
|
|
186
|
+
* oldest-first with the active file last.
|
|
187
|
+
*/
|
|
188
|
+
function chronologicalFiles(files) {
|
|
189
|
+
return [...files].sort((a, b) => {
|
|
190
|
+
const activeA = path.basename(a).endsWith(".log");
|
|
191
|
+
const activeB = path.basename(b).endsWith(".log");
|
|
192
|
+
if (activeA !== activeB) return activeA ? 1 : -1;
|
|
193
|
+
return a.localeCompare(b);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
180
197
|
function safeReaddir(dir) {
|
|
181
198
|
try {
|
|
182
199
|
return fs.readdirSync(dir);
|
|
@@ -205,6 +222,45 @@ function createState(files) {
|
|
|
205
222
|
toolResults: counter(),
|
|
206
223
|
phaseCounts: counter(),
|
|
207
224
|
phaseTimeouts: counter(),
|
|
225
|
+
// D1: every latency row timestamp (ms) in window, for the coverage-gap
|
|
226
|
+
// scan. Sorted after all files are read.
|
|
227
|
+
rowTs: [],
|
|
228
|
+
cascadeTs: [],
|
|
229
|
+
// D2: real-log pollution — rows whose filePath points at a test
|
|
230
|
+
// home, grouped by pid.
|
|
231
|
+
scratchRows: new Map(),
|
|
232
|
+
// D5: test_runner_delivery outcomes per session, joined with the
|
|
233
|
+
// sessionstart firing/stale text into one delivery-health verdict.
|
|
234
|
+
testRunnerDelivery: new Map(),
|
|
235
|
+
// D6: `phase: knip` executed rows per pid, for the drift and cost rules.
|
|
236
|
+
knip: new Map(),
|
|
237
|
+
// D7: hook-await-exceeded overruns plus the per-pid degradation census.
|
|
238
|
+
hookAwaitExceeded: [],
|
|
239
|
+
degradationKinds: new Map(),
|
|
240
|
+
// D8: turn_end `tool_result` summaries per pid, and the retained-state text.
|
|
241
|
+
turnEndTools: new Map(),
|
|
242
|
+
retainingNewerTurn: [],
|
|
243
|
+
// D9: empty-candidate LSP waits, edit touches that saw no client, and
|
|
244
|
+
// warm-reuse selections, joined into the wait/contradiction verdict.
|
|
245
|
+
lspWaitEmpty: new Map(),
|
|
246
|
+
lspTouchEdit: new Map(),
|
|
247
|
+
lspTouchNoClients: [],
|
|
248
|
+
lspClientSelectedWarm: [],
|
|
249
|
+
// D11: read-set carry outcomes at a restart boundary.
|
|
250
|
+
carryRestart: [],
|
|
251
|
+
// D12: nudges and scope transitions, joined by pid + wall clock.
|
|
252
|
+
agentNudges: [],
|
|
253
|
+
sessionScopeTransitions: [],
|
|
254
|
+
// D13: deferred runner failures joined to their delivery row by (pid, turnId).
|
|
255
|
+
deferredRunnerFailed: [],
|
|
256
|
+
lateRunnerFindings: [],
|
|
257
|
+
// D14: auxiliary stuck pair (pid, filePath, serverId) recurrence.
|
|
258
|
+
auxStuck: new Map(),
|
|
259
|
+
// D15: advisory provenance decisions with unknown provenance.
|
|
260
|
+
advisoryProvenance: [],
|
|
261
|
+
// D8/D15: first latency row timestamp per pid (lifetime base).
|
|
262
|
+
pidFirstTs: new Map(),
|
|
263
|
+
pidLastTs: new Map(),
|
|
208
264
|
workspace: {
|
|
209
265
|
started: 0,
|
|
210
266
|
completed: 0,
|
|
@@ -280,6 +336,24 @@ function createState(files) {
|
|
|
280
336
|
staleRanges: [],
|
|
281
337
|
zeroReads: [],
|
|
282
338
|
unavailableSnapshots: [],
|
|
339
|
+
// E2: the block/warn split. These rows do not carry a host-side
|
|
340
|
+
// decision, so the analyzer must not invent one.
|
|
341
|
+
blocks: [],
|
|
342
|
+
warns: [],
|
|
343
|
+
blockByKind: counter(),
|
|
344
|
+
bypassedMismatch: 0,
|
|
345
|
+
// D10: per-(session,file) evidence that a read or a committed edit
|
|
346
|
+
// happened earlier in the session, so a later `zero_read` block is a
|
|
347
|
+
// lost read-set rather than a genuine cold edit.
|
|
348
|
+
fileEvidence: new Map(),
|
|
349
|
+
stateLost: [],
|
|
350
|
+
genuineZeroRead: [],
|
|
351
|
+
},
|
|
352
|
+
extension: {
|
|
353
|
+
// D2: extension.log rows whose payload names a test home
|
|
354
|
+
// directory, grouped by pid, plus the warn/error census.
|
|
355
|
+
scratchRows: new Map(),
|
|
356
|
+
warnErrorGroups: counter(),
|
|
283
357
|
},
|
|
284
358
|
treeSitter: {
|
|
285
359
|
phases: counter(),
|
|
@@ -292,12 +366,26 @@ function createState(files) {
|
|
|
292
366
|
session: {
|
|
293
367
|
starts: 0,
|
|
294
368
|
cwds: counter(),
|
|
369
|
+
// E4: per-start build identity (`commit=`), so every rate can be split
|
|
370
|
+
// by build. Keyed by commit, with the start timestamps that carried it.
|
|
371
|
+
commits: counter(),
|
|
295
372
|
slowStarts: [],
|
|
296
373
|
slowTasks: [],
|
|
297
374
|
toolNoise: counter(),
|
|
298
375
|
lspNoise: counter(),
|
|
299
376
|
errors: [],
|
|
300
|
-
|
|
377
|
+
// D1: every sessionstart line timestamp (ms) in window.
|
|
378
|
+
rowTs: [],
|
|
379
|
+
// D16: `pi-lens loaded: Nms` lines, with their wall clock so a short
|
|
380
|
+
// lived pid can be marked.
|
|
381
|
+
slowLoads: [],
|
|
382
|
+
// D16: the wall clock of every `session_start fired`, so a load with no
|
|
383
|
+
// session start within 60 s (a short-lived pid) is visible.
|
|
384
|
+
firedTs: [],
|
|
385
|
+
// D3/D4/D5/D8: one run per `session_start fired`. Run splitting is the
|
|
386
|
+
// only way to attribute a turn-end test decision to the session that made it.
|
|
387
|
+
runs: [],
|
|
388
|
+
currentRun: newRun(),
|
|
301
389
|
},
|
|
302
390
|
actionable: {
|
|
303
391
|
events: counter(),
|
|
@@ -329,13 +417,26 @@ function createState(files) {
|
|
|
329
417
|
};
|
|
330
418
|
}
|
|
331
419
|
|
|
420
|
+
/**
|
|
421
|
+
* The failure kind of a `failed` or `crashed` runner row. `metadata.failureKind`
|
|
422
|
+
* is exact: inline rows carry it (#3781) and collect-later rows too (#3796).
|
|
423
|
+
* Rows written by released versions never carry it, so the count heuristic
|
|
424
|
+
* (a failure with diagnostics is found-errors) stays only as that fallback.
|
|
425
|
+
*/
|
|
426
|
+
function runnerFailureKind(entry) {
|
|
427
|
+
if (entry.metadata?.failureKind) return entry.metadata.failureKind;
|
|
428
|
+
if (entry.status === "crashed") return "crashed";
|
|
429
|
+
return (entry.diagnosticCount ?? 0) > 0 ? "blocking_diagnostics" : "unknown";
|
|
430
|
+
}
|
|
431
|
+
|
|
332
432
|
async function analyzeLatency(files, state) {
|
|
333
433
|
for (const file of files) {
|
|
334
434
|
await forEachJsonLine(file, "latency", state, (entry) => {
|
|
335
435
|
const ts = dateOf(entry.ts);
|
|
336
436
|
if (!inWindow(ts)) return;
|
|
337
437
|
state.seen.inc("latency");
|
|
338
|
-
|
|
438
|
+
trackLatencyProject(state, entry);
|
|
439
|
+
trackLatencySignals(state, entry, ts);
|
|
339
440
|
|
|
340
441
|
if (entry.type === "runner") {
|
|
341
442
|
const status = entry.status ?? "unknown";
|
|
@@ -344,15 +445,8 @@ async function analyzeLatency(files, state) {
|
|
|
344
445
|
if (status === "failed" || status === "crashed") {
|
|
345
446
|
// Separate a genuine runner breakage from "the check ran and found
|
|
346
447
|
// blocking issues" (e.g. the LSP runner reports status:failed when a
|
|
347
|
-
// file has type errors).
|
|
348
|
-
|
|
349
|
-
const kind =
|
|
350
|
-
entry.metadata?.failureKind ??
|
|
351
|
-
(status === "crashed"
|
|
352
|
-
? "crashed"
|
|
353
|
-
: (entry.diagnosticCount ?? 0) > 0
|
|
354
|
-
? "blocking_diagnostics"
|
|
355
|
-
: "unknown");
|
|
448
|
+
// file has type errors).
|
|
449
|
+
const kind = runnerFailureKind(entry);
|
|
356
450
|
state.latency.runnerFailureKinds.inc(`${runner}:${kind}`);
|
|
357
451
|
if (kind === "blocking_diagnostics") {
|
|
358
452
|
state.latency.runnerBlockingFindings.inc(runner);
|
|
@@ -543,6 +637,7 @@ async function analyzeCascade(files, state) {
|
|
|
543
637
|
const ts = dateOf(entry.ts);
|
|
544
638
|
if (!inWindow(ts)) return;
|
|
545
639
|
state.seen.inc("cascade");
|
|
640
|
+
if (ts) state.latency.cascadeTs.push(ts.getTime());
|
|
546
641
|
trackProject(state, entry.filePath);
|
|
547
642
|
const phase = entry.phase ?? "unknown";
|
|
548
643
|
state.cascade.phases.inc(phase);
|
|
@@ -589,24 +684,76 @@ async function analyzeReadGuard(files, state) {
|
|
|
589
684
|
for (const file of files) {
|
|
590
685
|
await forEachJsonLine(file, "read-guard", state, (entry) => {
|
|
591
686
|
const ts = dateOf(entry.ts);
|
|
592
|
-
if (!inWindow(ts))
|
|
687
|
+
if (!inWindow(ts)) {
|
|
688
|
+
// D10 needs evidence that may precede a live-monitor window.
|
|
689
|
+
// Keep this lookback state private; outside rows never affect counts.
|
|
690
|
+
if (hasReadEvidence(entry)) {
|
|
691
|
+
const key = `${readGuardSessionOf(entry) ?? "?"}\u0000${entry.filePath ?? "?"}`;
|
|
692
|
+
state.readGuard.fileEvidence.set(key, true);
|
|
693
|
+
}
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
593
696
|
state.seen.inc("read-guard");
|
|
594
697
|
trackProject(state, entry.filePath);
|
|
595
698
|
const event = entry.event ?? "unknown";
|
|
699
|
+
const md = entry.metadata ?? {};
|
|
596
700
|
state.readGuard.events.inc(event);
|
|
597
701
|
state.readGuard.byFile.inc(shortPath(entry.filePath));
|
|
598
|
-
const reasonKind =
|
|
702
|
+
const reasonKind = md.reasonKind;
|
|
599
703
|
if (reasonKind) state.readGuard.byReason.inc(reasonKind);
|
|
704
|
+
|
|
705
|
+
// D10: evidence that this file was read or edited earlier in the
|
|
706
|
+
// SAME session. Read before this row's own evidence is recorded, so a
|
|
707
|
+
// later `zero_read` block sees only the prior rows. An
|
|
708
|
+
// `edit_batch_summary` carries no sessionId, so its session is the
|
|
709
|
+
// turnId prefix before the last `:`.
|
|
710
|
+
const evidenceKey = `${readGuardSessionOf(entry) ?? "?"}\u0000${entry.filePath ?? "?"}`;
|
|
711
|
+
const hadEvidence =
|
|
712
|
+
state.readGuard.fileEvidence.get(evidenceKey) === true;
|
|
713
|
+
|
|
600
714
|
if (event === "edit_preflight_blocked") {
|
|
601
715
|
state.readGuard.preflightReasons.inc(reasonKind ?? "unknown");
|
|
716
|
+
registerBlock(state, entry, "preflight");
|
|
717
|
+
}
|
|
718
|
+
if (event === "edit_blocked") {
|
|
719
|
+
const summary = registerBlock(state, entry, "blocked");
|
|
720
|
+
if (reasonKind === "zero_read") {
|
|
721
|
+
pushTop(state.readGuard.zeroReads, summary, limit * 3, byLine);
|
|
722
|
+
if (hadEvidence) {
|
|
723
|
+
pushTop(
|
|
724
|
+
state.readGuard.stateLost,
|
|
725
|
+
{ ...summary, classification: "state-lost" },
|
|
726
|
+
limit * 3,
|
|
727
|
+
byLine,
|
|
728
|
+
);
|
|
729
|
+
} else {
|
|
730
|
+
pushTop(
|
|
731
|
+
state.readGuard.genuineZeroRead,
|
|
732
|
+
{ ...summary, classification: "genuine" },
|
|
733
|
+
limit * 3,
|
|
734
|
+
byLine,
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
if (event === "edit_warned") {
|
|
740
|
+
pushTop(
|
|
741
|
+
state.readGuard.warns,
|
|
742
|
+
summarizeReadGuard(entry),
|
|
743
|
+
limit * 3,
|
|
744
|
+
byLine,
|
|
745
|
+
);
|
|
602
746
|
}
|
|
603
747
|
if (event === "range_snapshot_validation") {
|
|
604
|
-
const status =
|
|
748
|
+
const status = md.status ?? "unknown";
|
|
749
|
+
const outcome = String(md.outcome ?? "");
|
|
605
750
|
state.readGuard.snapshotStatus.inc(status);
|
|
606
751
|
state.readGuard.snapshotEnforcement.inc(
|
|
607
|
-
|
|
752
|
+
md.enforced ? "enforced" : "not_enforced",
|
|
608
753
|
);
|
|
609
|
-
|
|
754
|
+
// E3: `bypassed-content-match` is an allowed edit, not a stale
|
|
755
|
+
// read. Only a mismatch the caller did NOT bypass is a smell.
|
|
756
|
+
if (status === "mismatch" && !outcome.startsWith("bypassed")) {
|
|
610
757
|
state.smellTotals.inc("read-guard-stale-ranges");
|
|
611
758
|
pushTop(
|
|
612
759
|
state.readGuard.staleRanges,
|
|
@@ -614,6 +761,8 @@ async function analyzeReadGuard(files, state) {
|
|
|
614
761
|
limit * 3,
|
|
615
762
|
byLine,
|
|
616
763
|
);
|
|
764
|
+
} else if (status === "mismatch") {
|
|
765
|
+
state.readGuard.bypassedMismatch += 1;
|
|
617
766
|
} else if (status === "unavailable") {
|
|
618
767
|
pushTop(
|
|
619
768
|
state.readGuard.unavailableSnapshots,
|
|
@@ -623,21 +772,11 @@ async function analyzeReadGuard(files, state) {
|
|
|
623
772
|
);
|
|
624
773
|
}
|
|
625
774
|
}
|
|
626
|
-
if (event === "edit_blocked" || event === "edit_warned") {
|
|
627
|
-
state.smellTotals.inc("read-guard-friction");
|
|
628
|
-
const summary = summarizeReadGuard(entry);
|
|
629
|
-
pushTop(state.readGuard.blocked, summary, limit * 3, byLine);
|
|
630
|
-
if (reasonKind === "zero_read") {
|
|
631
|
-
pushTop(state.readGuard.zeroReads, summary, limit * 3, byLine);
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
775
|
if (
|
|
635
776
|
event === "oldtext_not_found" ||
|
|
636
777
|
event === "oldtext_duplicate" ||
|
|
637
|
-
event === "touched_lines_missing"
|
|
638
|
-
event === "edit_preflight_blocked"
|
|
778
|
+
event === "touched_lines_missing"
|
|
639
779
|
) {
|
|
640
|
-
state.smellTotals.inc("read-guard-friction");
|
|
641
780
|
pushTop(
|
|
642
781
|
state.readGuard.oldTextIssues,
|
|
643
782
|
summarizeReadGuard(entry),
|
|
@@ -645,10 +784,48 @@ async function analyzeReadGuard(files, state) {
|
|
|
645
784
|
byLine,
|
|
646
785
|
);
|
|
647
786
|
}
|
|
787
|
+
|
|
788
|
+
if (hasReadEvidence(entry))
|
|
789
|
+
state.readGuard.fileEvidence.set(evidenceKey, true);
|
|
648
790
|
});
|
|
649
791
|
}
|
|
650
792
|
}
|
|
651
793
|
|
|
794
|
+
/** D10: a row proving the file was read or edited earlier in its session. */
|
|
795
|
+
function hasReadEvidence(entry) {
|
|
796
|
+
const md = entry.metadata ?? {};
|
|
797
|
+
return (
|
|
798
|
+
entry.event === "edit_batch_summary" ||
|
|
799
|
+
(entry.event === "range_snapshot_validation" &&
|
|
800
|
+
Number(md.candidateReadCount ?? 0) > 0) ||
|
|
801
|
+
(entry.event === "edit_warned" && Number(md.readCount ?? 0) > 0)
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* D10: the session a read-guard row belongs to. `edit_batch_summary` rows carry
|
|
807
|
+
* no `sessionId`, so fall back to the turnId prefix before the last `:` (the
|
|
808
|
+
* report's own join instruction).
|
|
809
|
+
*/
|
|
810
|
+
function readGuardSessionOf(entry) {
|
|
811
|
+
if (typeof entry.sessionId === "string" && entry.sessionId)
|
|
812
|
+
return entry.sessionId;
|
|
813
|
+
const turnId = entry.turnId;
|
|
814
|
+
if (typeof turnId === "string" && turnId.includes(":"))
|
|
815
|
+
return turnId.slice(0, turnId.lastIndexOf(":"));
|
|
816
|
+
return null;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/** E2: one blocked edit. Host/model provenance is not present on this row. */
|
|
820
|
+
function registerBlock(state, entry, source) {
|
|
821
|
+
const summary = summarizeReadGuard(entry);
|
|
822
|
+
pushTop(state.readGuard.blocks, summary, limit * 3, byLine);
|
|
823
|
+
state.readGuard.blockByKind.inc(
|
|
824
|
+
`${source}:${entry.metadata?.reasonKind ?? "unknown"}`,
|
|
825
|
+
);
|
|
826
|
+
return summary;
|
|
827
|
+
}
|
|
828
|
+
|
|
652
829
|
async function analyzeTreeSitter(files, state) {
|
|
653
830
|
for (const file of files) {
|
|
654
831
|
await forEachJsonLine(file, "tree-sitter", state, (entry) => {
|
|
@@ -704,21 +881,48 @@ async function analyzeSessionStart(files, state) {
|
|
|
704
881
|
const match = lineRe.exec(line);
|
|
705
882
|
if (!match) return;
|
|
706
883
|
const ts = dateOf(match[1]);
|
|
707
|
-
if (!inWindow(ts)) return;
|
|
708
884
|
const message = match[2];
|
|
885
|
+
if (!inWindow(ts)) {
|
|
886
|
+
// A --since window can begin after the session_start that owns its
|
|
887
|
+
// rows. Carry only that run anchor into the visible window.
|
|
888
|
+
if (message.startsWith("session_start fired")) {
|
|
889
|
+
state.session.currentRun = newRun();
|
|
890
|
+
state.session.currentRun.startTs = iso(ts);
|
|
891
|
+
}
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
709
894
|
if (isExcludedText(message)) {
|
|
710
895
|
state.excludedRows++;
|
|
711
896
|
return;
|
|
712
897
|
}
|
|
713
898
|
state.seen.inc("sessionstart");
|
|
899
|
+
if (ts) state.session.rowTs.push(ts.getTime());
|
|
900
|
+
|
|
901
|
+
// E4: starts are counted from `session_start fired`, which every mode
|
|
902
|
+
// writes, instead of the dead `session_start cwd:` full-mode line. The
|
|
903
|
+
// same line opens a D3/D4/D5/D8 run.
|
|
904
|
+
if (message.startsWith("session_start fired")) {
|
|
905
|
+
state.session.starts++;
|
|
906
|
+
if (ts) state.session.firedTs.push(ts.getTime());
|
|
907
|
+
state.session.runs.push(state.session.currentRun);
|
|
908
|
+
state.session.currentRun = newRun();
|
|
909
|
+
state.session.currentRun.startTs = iso(ts);
|
|
910
|
+
}
|
|
714
911
|
|
|
715
912
|
const cwd = /session_start cwd:\s*(.*)$/.exec(message)?.[1];
|
|
716
913
|
if (cwd) {
|
|
717
|
-
state.session.starts++;
|
|
718
914
|
state.session.cwds.inc(projectOf(cwd));
|
|
719
915
|
trackProject(state, cwd);
|
|
720
916
|
}
|
|
721
917
|
|
|
918
|
+
// E4: build identity for the session that just started.
|
|
919
|
+
const buildIdentity =
|
|
920
|
+
/session_start: build identity [—-] commit=(\w+)/.exec(message);
|
|
921
|
+
if (buildIdentity) {
|
|
922
|
+
state.session.commits.inc(buildIdentity[1]);
|
|
923
|
+
state.session.currentRun.commit = buildIdentity[1];
|
|
924
|
+
}
|
|
925
|
+
|
|
722
926
|
// #2526 R3 S1: this session's config-resolution PENDING mark, published
|
|
723
927
|
// by `loadLSPConfig` itself at the instant a resolution is actually
|
|
724
928
|
// attempted — never a start-line prediction from `no-lsp`/subagent/
|
|
@@ -780,8 +984,49 @@ async function analyzeSessionStart(files, state) {
|
|
|
780
984
|
);
|
|
781
985
|
}
|
|
782
986
|
|
|
783
|
-
|
|
784
|
-
|
|
987
|
+
// D16: extension load time is invisible to `slow-session-start`, which
|
|
988
|
+
// reads `session_start total:` (a quick-mode total of tens of ms).
|
|
989
|
+
const load = /pi-lens loaded: (\d+)ms after process start/.exec(message);
|
|
990
|
+
if (load) {
|
|
991
|
+
state.session.slowLoads.push({
|
|
992
|
+
ts: iso(ts),
|
|
993
|
+
ms: ts ? ts.getTime() : null,
|
|
994
|
+
durationMs: Number(load[1]),
|
|
995
|
+
message,
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
const run = state.session.currentRun;
|
|
1000
|
+
const modified = /turn_end: (\d+) file\(s\) modified/.exec(message);
|
|
1001
|
+
if (modified) run.edits += 1;
|
|
1002
|
+
if (message.includes("excluded by the built-in turn-end policy")) {
|
|
1003
|
+
run.excluded += 1;
|
|
1004
|
+
const excludedPath = /turn_end:\s*(\S+)\s+→ test target excluded/.exec(
|
|
1005
|
+
message,
|
|
1006
|
+
)?.[1];
|
|
1007
|
+
if (excludedPath) run.excludedTestFiles.push(excludedPath);
|
|
1008
|
+
}
|
|
1009
|
+
if (message.includes("→ no test file found")) run.noTestFile += 1;
|
|
1010
|
+
const vitest =
|
|
1011
|
+
/^turn_end:\s+(.+?)\s+→\s+test vitest\s+(\S+)\s+\(([^)]+)\)/.exec(
|
|
1012
|
+
message,
|
|
1013
|
+
);
|
|
1014
|
+
if (vitest) {
|
|
1015
|
+
run.ran += 1;
|
|
1016
|
+
const [, src, tgt, mode] = vitest;
|
|
1017
|
+
if (mode.includes("failed-first")) {
|
|
1018
|
+
run.failedFirst += 1;
|
|
1019
|
+
const a = checkoutOf(src);
|
|
1020
|
+
const b = checkoutOf(tgt);
|
|
1021
|
+
if (a && b && a !== b) run.crossCheckout += 1;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
if (/turn_end: firing \d+ test target\(s\) async/.test(message))
|
|
1025
|
+
run.testFirings += 1;
|
|
1026
|
+
if (/\(stale\s*[—-]\s*turn advanced while tests ran\)/.test(message))
|
|
1027
|
+
run.testStale += 1;
|
|
1028
|
+
if (/turn_end: retaining newer turn state/.test(message))
|
|
1029
|
+
run.retainingNewerTurn += 1;
|
|
785
1030
|
|
|
786
1031
|
const lower = message.toLowerCase();
|
|
787
1032
|
if (
|
|
@@ -792,8 +1037,16 @@ async function analyzeSessionStart(files, state) {
|
|
|
792
1037
|
state.smellTotals.inc("tool-install-noise");
|
|
793
1038
|
state.session.toolNoise.inc(normalizeSessionNoise(message));
|
|
794
1039
|
}
|
|
1040
|
+
// E1: anchor to the production failure emitters so a worktree name
|
|
1041
|
+
// such as `468-wait-timeout` inside a `cwd=`/`command=` token cannot
|
|
1042
|
+
// match (the 20 false positives in the live session). Every emitter
|
|
1043
|
+
// puts the failure word before any `key=` token: `lsp spawn <id>:
|
|
1044
|
+
// unavailable|failed` (clients/lsp/index.ts) and `lsp launch
|
|
1045
|
+
// candidate|managed|bundle|tree-bin failed` (clients/lsp/server.ts).
|
|
1046
|
+
// `lsp read warm unavailable` is informational, and `lsp process
|
|
1047
|
+
// <cmd>:` only ever logs `spawn-error` or `closed` (clients/lsp/launch.ts).
|
|
795
1048
|
if (
|
|
796
|
-
|
|
1049
|
+
/^lsp (?:spawn [^:]+: (?:unavailable|failed)|launch (?:candidate|managed|bundle|tree-bin) failed)/.test(
|
|
797
1050
|
message,
|
|
798
1051
|
)
|
|
799
1052
|
) {
|
|
@@ -814,6 +1067,9 @@ async function analyzeSessionStart(files, state) {
|
|
|
814
1067
|
}
|
|
815
1068
|
});
|
|
816
1069
|
}
|
|
1070
|
+
// Close the final run so the last `session_start fired` block is analyzed.
|
|
1071
|
+
if (state.session.currentRun.startTs)
|
|
1072
|
+
state.session.runs.push(state.session.currentRun);
|
|
817
1073
|
}
|
|
818
1074
|
|
|
819
1075
|
async function analyzeActionableWarnings(files, state) {
|
|
@@ -984,12 +1240,18 @@ function pathValues(value, key = "") {
|
|
|
984
1240
|
}
|
|
985
1241
|
|
|
986
1242
|
function isExcludedText(text) {
|
|
1243
|
+
// E4: the old match only ever saw the dead `session_start cwd:` line. The
|
|
1244
|
+
// live cwd/root carriers are the pending-resolution mark and the spawn lines.
|
|
1245
|
+
const values = [];
|
|
987
1246
|
const cwd = /session_start cwd:\s*(.*)$/.exec(text)?.[1];
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1247
|
+
if (cwd) values.push(cwd);
|
|
1248
|
+
for (const match of text.matchAll(/\b(?:cwd|root)=(\S+)/g))
|
|
1249
|
+
values.push(match[1]);
|
|
1250
|
+
return values.some((value) =>
|
|
1251
|
+
excludeGlobs.some((glob) =>
|
|
1252
|
+
minimatch(normalizePath(value), glob, { nocase: true, dot: true }),
|
|
1253
|
+
),
|
|
1254
|
+
);
|
|
993
1255
|
}
|
|
994
1256
|
|
|
995
1257
|
async function forEachLine(file, visitor) {
|
|
@@ -1200,19 +1462,18 @@ function summarizeCascade(entry) {
|
|
|
1200
1462
|
}
|
|
1201
1463
|
|
|
1202
1464
|
function summarizeReadGuard(entry) {
|
|
1465
|
+
const md = entry.metadata ?? {};
|
|
1466
|
+
// R2: the old offset/limit/symbol fields were undefined on 100% of rows.
|
|
1467
|
+
// `touchedLines[0]`/`range[0]` are the real line identity the rows carry.
|
|
1468
|
+
const touched = Array.isArray(md.touchedLines) ? md.touchedLines : [];
|
|
1469
|
+
const range = Array.isArray(md.range) ? md.range : [];
|
|
1203
1470
|
return {
|
|
1204
1471
|
ts: entry.ts,
|
|
1205
1472
|
event: entry.event,
|
|
1206
1473
|
filePath: shortPath(entry.filePath),
|
|
1207
1474
|
project: projectOf(entry.filePath),
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
effectiveOffset: entry.effectiveOffset,
|
|
1211
|
-
effectiveLimit: entry.effectiveLimit,
|
|
1212
|
-
symbol: entry.symbol,
|
|
1213
|
-
symbolKind: entry.symbolKind,
|
|
1214
|
-
line: entry.symbolStartLine,
|
|
1215
|
-
metadata: entry.metadata,
|
|
1475
|
+
line: touched[0] ?? range[0],
|
|
1476
|
+
metadata: md,
|
|
1216
1477
|
};
|
|
1217
1478
|
}
|
|
1218
1479
|
|
|
@@ -1295,9 +1556,613 @@ function normalizePath(filePath) {
|
|
|
1295
1556
|
return String(filePath).replace(/\\/g, "/");
|
|
1296
1557
|
}
|
|
1297
1558
|
|
|
1559
|
+
/** One D3/D4/D5/D8 run, opened by a `session_start fired` line. */
|
|
1560
|
+
function newRun() {
|
|
1561
|
+
return {
|
|
1562
|
+
startTs: null,
|
|
1563
|
+
commit: null,
|
|
1564
|
+
edits: 0,
|
|
1565
|
+
ran: 0,
|
|
1566
|
+
failedFirst: 0,
|
|
1567
|
+
crossCheckout: 0,
|
|
1568
|
+
excluded: 0,
|
|
1569
|
+
excludedTestFiles: [],
|
|
1570
|
+
noTestFile: 0,
|
|
1571
|
+
retainingNewerTurn: 0,
|
|
1572
|
+
testFirings: 0,
|
|
1573
|
+
testStale: 0,
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
/** The checkout a turn-end path belongs to (`.worktrees/<id>/` or the main `src/`). */
|
|
1578
|
+
function checkoutOf(p) {
|
|
1579
|
+
const m = /\.worktrees\/([^/]+)\//.exec(p);
|
|
1580
|
+
if (m) return m[1];
|
|
1581
|
+
if (/^(?:src|tests?)\//.test(p)) return "main";
|
|
1582
|
+
return null;
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
/**
|
|
1586
|
+
* D2: the markers only a test home carries: the #3521 fork-tree witness home
|
|
1587
|
+
* and the suite's `pi-lens-test-*` temp dirs. `pi-lens-worktrees`,
|
|
1588
|
+
* `pi-lens-orchestrator/tmp` and `.probe-home/` are not markers: real
|
|
1589
|
+
* sessions edit there (the orchestrator writes its task files under
|
|
1590
|
+
* `.probe-home/orchestration/`).
|
|
1591
|
+
*/
|
|
1592
|
+
const SCRATCH_PATH_RE = /(witness-home|pi-lens-test-)/;
|
|
1593
|
+
|
|
1594
|
+
/**
|
|
1595
|
+
* E5/D2: the `opaque_mutation_*` phases log the bash command as `filePath`
|
|
1596
|
+
* (clients/runtime-tool-call.ts, clients/runtime-tool-result.ts), except
|
|
1597
|
+
* `opaque_mutation_recovered`, which logs the recovered paths.
|
|
1598
|
+
*/
|
|
1599
|
+
function isCommandTextRow(entry) {
|
|
1600
|
+
const phase = String(entry.phase ?? "");
|
|
1601
|
+
return (
|
|
1602
|
+
phase.startsWith("opaque_mutation_") &&
|
|
1603
|
+
phase !== "opaque_mutation_recovered"
|
|
1604
|
+
);
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
/** E5: track a latency row's project unless its `filePath` is a shell command. */
|
|
1608
|
+
function trackLatencyProject(state, entry) {
|
|
1609
|
+
const filePath = entry?.filePath;
|
|
1610
|
+
if (typeof filePath !== "string" || filePath.length === 0) return;
|
|
1611
|
+
if (isCommandTextRow(entry)) return;
|
|
1612
|
+
// The `<pi-lens>` sentinel is never a project path.
|
|
1613
|
+
if (filePath.startsWith("<")) return;
|
|
1614
|
+
state.projects.inc(projectOf(filePath));
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
function trackLatencyPollution(state, entry) {
|
|
1618
|
+
if (isCommandTextRow(entry)) return;
|
|
1619
|
+
const hit = pathValues(entry).some((value) => SCRATCH_PATH_RE.test(value));
|
|
1620
|
+
if (!hit) return;
|
|
1621
|
+
const pid = String(entry.pid ?? "unknown");
|
|
1622
|
+
state.latency.scratchRows.set(
|
|
1623
|
+
pid,
|
|
1624
|
+
(state.latency.scratchRows.get(pid) ?? 0) + 1,
|
|
1625
|
+
);
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
/**
|
|
1629
|
+
* Every latency signal the D5/D6/D7/D9/D11-D15 detectors read. Kept in one
|
|
1630
|
+
* function so the streaming visitor stays a thin fan-out.
|
|
1631
|
+
*/
|
|
1632
|
+
function trackLatencySignals(state, entry, ts) {
|
|
1633
|
+
const ms = ts instanceof Date ? ts.getTime() : null;
|
|
1634
|
+
if (ms != null && Number.isFinite(ms)) state.latency.rowTs.push(ms);
|
|
1635
|
+
const pid = String(entry.pid ?? "unknown");
|
|
1636
|
+
if (ms != null && Number.isFinite(ms)) {
|
|
1637
|
+
const first = state.latency.pidFirstTs.get(pid);
|
|
1638
|
+
if (first == null || ms < first) state.latency.pidFirstTs.set(pid, ms);
|
|
1639
|
+
const last = state.latency.pidLastTs.get(pid);
|
|
1640
|
+
if (last == null || ms > last) state.latency.pidLastTs.set(pid, ms);
|
|
1641
|
+
}
|
|
1642
|
+
trackLatencyPollution(state, entry);
|
|
1643
|
+
|
|
1644
|
+
if (entry.type === "runner") {
|
|
1645
|
+
const md = entry.metadata ?? {};
|
|
1646
|
+
if (
|
|
1647
|
+
entry.status === "failed" &&
|
|
1648
|
+
md.tier === "collect-later" &&
|
|
1649
|
+
Number(entry.diagnosticCount ?? 0) > 0 &&
|
|
1650
|
+
runnerFailureKind(entry) === "blocking_diagnostics"
|
|
1651
|
+
) {
|
|
1652
|
+
state.latency.deferredRunnerFailed.push({
|
|
1653
|
+
ts: entry.ts,
|
|
1654
|
+
ms,
|
|
1655
|
+
pid,
|
|
1656
|
+
turnId: entry.turnId,
|
|
1657
|
+
runnerId: entry.runnerId,
|
|
1658
|
+
diagnosticCount: Number(entry.diagnosticCount ?? 0),
|
|
1659
|
+
filePath: entry.filePath,
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1662
|
+
return;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
if (entry.type === "tool_result") {
|
|
1666
|
+
// D8: the turn_end summary row carries `blockerSections`; the existing
|
|
1667
|
+
// tool_result branch only counts `result`, so it never saw this duration.
|
|
1668
|
+
if (entry.metadata && entry.metadata.blockerSections != null) {
|
|
1669
|
+
const rows = state.latency.turnEndTools.get(pid) ?? [];
|
|
1670
|
+
rows.push({
|
|
1671
|
+
ts: entry.ts,
|
|
1672
|
+
ms,
|
|
1673
|
+
durationMs: Number(entry.durationMs ?? 0),
|
|
1674
|
+
});
|
|
1675
|
+
state.latency.turnEndTools.set(pid, rows);
|
|
1676
|
+
}
|
|
1677
|
+
return;
|
|
1678
|
+
}
|
|
1679
|
+
if (entry.type !== "phase") return;
|
|
1680
|
+
|
|
1681
|
+
const phase = entry.phase ?? "unknown";
|
|
1682
|
+
const md = entry.metadata ?? {};
|
|
1683
|
+
const nowIso = entry.ts;
|
|
1684
|
+
|
|
1685
|
+
if (phase === "test_runner_delivery") {
|
|
1686
|
+
const sid = md.sessionId ?? pid;
|
|
1687
|
+
const c = state.latency.testRunnerDelivery.get(sid) ?? counter();
|
|
1688
|
+
c.inc(md.outcome ?? "unknown");
|
|
1689
|
+
state.latency.testRunnerDelivery.set(sid, c);
|
|
1690
|
+
} else if (phase === "knip") {
|
|
1691
|
+
if (
|
|
1692
|
+
md.execution === "executed" &&
|
|
1693
|
+
Number.isFinite(Number(md.totalIssues))
|
|
1694
|
+
) {
|
|
1695
|
+
const rows = state.latency.knip.get(pid) ?? [];
|
|
1696
|
+
rows.push({
|
|
1697
|
+
ts: nowIso,
|
|
1698
|
+
ms,
|
|
1699
|
+
durationMs: Number(entry.durationMs ?? 0),
|
|
1700
|
+
totalIssues: Number(md.totalIssues),
|
|
1701
|
+
});
|
|
1702
|
+
state.latency.knip.set(pid, rows);
|
|
1703
|
+
}
|
|
1704
|
+
} else if (phase === "degradation_ledger") {
|
|
1705
|
+
const kind = md.kind ?? "unknown";
|
|
1706
|
+
const perPid = state.latency.degradationKinds.get(pid) ?? new Map();
|
|
1707
|
+
perPid.set(kind, Math.max(perPid.get(kind) ?? 0, Number(md.count ?? 0)));
|
|
1708
|
+
state.latency.degradationKinds.set(pid, perPid);
|
|
1709
|
+
if (kind === "hook-await-exceeded") {
|
|
1710
|
+
const budgetMs = Number(md.budgetMs);
|
|
1711
|
+
const elapsedMs = Number(md.elapsedMs);
|
|
1712
|
+
state.latency.hookAwaitExceeded.push({
|
|
1713
|
+
ts: nowIso,
|
|
1714
|
+
pid,
|
|
1715
|
+
hook: md.hook,
|
|
1716
|
+
label: md.label,
|
|
1717
|
+
budgetMs,
|
|
1718
|
+
elapsedMs,
|
|
1719
|
+
cause: md.cause,
|
|
1720
|
+
ratio: budgetMs > 0 ? elapsedMs / budgetMs : 0,
|
|
1721
|
+
});
|
|
1722
|
+
}
|
|
1723
|
+
} else if (phase === "lsp_client_wait_timeout") {
|
|
1724
|
+
const serverIds = Array.isArray(md.serverIds) ? md.serverIds : [];
|
|
1725
|
+
if (serverIds.length === 0) {
|
|
1726
|
+
const cur = state.latency.lspWaitEmpty.get(pid) ?? { ms: 0, rows: 0 };
|
|
1727
|
+
cur.ms += Number(entry.durationMs ?? 0);
|
|
1728
|
+
cur.rows += 1;
|
|
1729
|
+
state.latency.lspWaitEmpty.set(pid, cur);
|
|
1730
|
+
}
|
|
1731
|
+
} else if (phase === "lsp_touch_file") {
|
|
1732
|
+
const cur = state.latency.lspTouchEdit.get(pid) ?? {
|
|
1733
|
+
rows: 0,
|
|
1734
|
+
noClients: 0,
|
|
1735
|
+
};
|
|
1736
|
+
if (md.source === "tool_call:edit") {
|
|
1737
|
+
cur.rows += 1;
|
|
1738
|
+
if (md.failureKind === "no_clients_none_spawning") cur.noClients += 1;
|
|
1739
|
+
}
|
|
1740
|
+
state.latency.lspTouchEdit.set(pid, cur);
|
|
1741
|
+
if (
|
|
1742
|
+
md.source === "tool_call:edit" &&
|
|
1743
|
+
md.failureKind === "no_clients_none_spawning"
|
|
1744
|
+
) {
|
|
1745
|
+
state.latency.lspTouchNoClients.push({
|
|
1746
|
+
ts: nowIso,
|
|
1747
|
+
ms,
|
|
1748
|
+
pid,
|
|
1749
|
+
filePath: entry.filePath,
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
} else if (phase === "lsp_client_selected") {
|
|
1753
|
+
if (md.outcome === "warm-reuse") {
|
|
1754
|
+
state.latency.lspClientSelectedWarm.push({
|
|
1755
|
+
ts: nowIso,
|
|
1756
|
+
ms,
|
|
1757
|
+
pid,
|
|
1758
|
+
filePath: entry.filePath,
|
|
1759
|
+
});
|
|
1760
|
+
}
|
|
1761
|
+
} else if (phase === "read_guard_branch_retained") {
|
|
1762
|
+
state.latency.carryRestart.push({
|
|
1763
|
+
ts: nowIso,
|
|
1764
|
+
pid,
|
|
1765
|
+
trigger: md.trigger,
|
|
1766
|
+
source: md.source,
|
|
1767
|
+
kept: Number(md.kept ?? 0),
|
|
1768
|
+
dropped: Number(md.dropped ?? 0),
|
|
1769
|
+
branchToolResults: Number(md.branchToolResults ?? 0),
|
|
1770
|
+
branchReadable: md.branchReadable === true,
|
|
1771
|
+
});
|
|
1772
|
+
} else if (phase === "agent_nudge") {
|
|
1773
|
+
state.latency.agentNudges.push({
|
|
1774
|
+
ts: nowIso,
|
|
1775
|
+
ms,
|
|
1776
|
+
pid,
|
|
1777
|
+
originCrossProcess: Number(md.originCrossProcess ?? 0),
|
|
1778
|
+
originLocal: Number(md.originLocal ?? 0),
|
|
1779
|
+
reasonMix: md.reasonMix,
|
|
1780
|
+
});
|
|
1781
|
+
} else if (phase === "session_scope_transition") {
|
|
1782
|
+
state.latency.sessionScopeTransitions.push({
|
|
1783
|
+
ts: nowIso,
|
|
1784
|
+
ms,
|
|
1785
|
+
pid,
|
|
1786
|
+
handoffSource: md.handoffSource,
|
|
1787
|
+
sessionId: md.sessionId,
|
|
1788
|
+
});
|
|
1789
|
+
} else if (phase === "late_runner_findings") {
|
|
1790
|
+
state.latency.lateRunnerFindings.push({
|
|
1791
|
+
ts: nowIso,
|
|
1792
|
+
ms,
|
|
1793
|
+
pid,
|
|
1794
|
+
turnId: entry.turnId,
|
|
1795
|
+
failed: Number(md.failed ?? 0),
|
|
1796
|
+
delivered: Number(md.delivered ?? 0),
|
|
1797
|
+
dropped: Number(md.dropped ?? 0),
|
|
1798
|
+
pending: Number(md.pending ?? 0),
|
|
1799
|
+
});
|
|
1800
|
+
} else if (phase === "late_auxiliary_findings") {
|
|
1801
|
+
const pairs = Array.isArray(md.stuckPairs) ? md.stuckPairs : [];
|
|
1802
|
+
for (const pair of pairs) {
|
|
1803
|
+
if (!pair?.filePath || !pair?.serverId) continue;
|
|
1804
|
+
const key = `${pid}\u0000${pair.filePath}\u0000${pair.serverId}`;
|
|
1805
|
+
state.latency.auxStuck.set(
|
|
1806
|
+
key,
|
|
1807
|
+
(state.latency.auxStuck.get(key) ?? 0) + 1,
|
|
1808
|
+
);
|
|
1809
|
+
}
|
|
1810
|
+
} else if (phase === "advisory_provenance_decision") {
|
|
1811
|
+
const reasons = Array.isArray(md.reasons) ? md.reasons : [];
|
|
1812
|
+
// The malformed reason implies decision "historical": the validator
|
|
1813
|
+
// returns status "unknown" with it (clients/advisory-provenance.ts) and
|
|
1814
|
+
// the row logs every non-current status as historical
|
|
1815
|
+
// (clients/runtime-context.ts), so the reason alone is the rule.
|
|
1816
|
+
if (reasons.includes("malformed-or-legacy-provenance")) {
|
|
1817
|
+
state.latency.advisoryProvenance.push({
|
|
1818
|
+
ts: nowIso,
|
|
1819
|
+
ms,
|
|
1820
|
+
pid,
|
|
1821
|
+
reasons,
|
|
1822
|
+
provenanceStamp: md.provenanceStamp,
|
|
1823
|
+
advisoryKind: md.advisoryKind,
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
/** D2: extension.log rows that name a test home. */
|
|
1830
|
+
async function analyzeExtension(files, state) {
|
|
1831
|
+
for (const file of files) {
|
|
1832
|
+
await forEachJsonLine(file, "extension", state, (entry) => {
|
|
1833
|
+
const ts = dateOf(entry.ts);
|
|
1834
|
+
if (!inWindow(ts)) return;
|
|
1835
|
+
state.seen.inc("extension");
|
|
1836
|
+
if (SCRATCH_PATH_RE.test(JSON.stringify(entry))) {
|
|
1837
|
+
const pid = String(entry.pid ?? "unknown");
|
|
1838
|
+
state.extension.scratchRows.set(
|
|
1839
|
+
pid,
|
|
1840
|
+
(state.extension.scratchRows.get(pid) ?? 0) + 1,
|
|
1841
|
+
);
|
|
1842
|
+
}
|
|
1843
|
+
const level = String(entry.level ?? "").toLowerCase();
|
|
1844
|
+
if (level === "warn" || level === "error") {
|
|
1845
|
+
const message = String(entry.message ?? "").slice(0, 80);
|
|
1846
|
+
state.extension.warnErrorGroups.inc(
|
|
1847
|
+
`${entry.subsystem ?? "unknown"}: ${message}`,
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
function countBetween(sorted, a, b) {
|
|
1855
|
+
let n = 0;
|
|
1856
|
+
for (const value of sorted) {
|
|
1857
|
+
if (value > a && value < b) n += 1;
|
|
1858
|
+
else if (value >= b) break;
|
|
1859
|
+
}
|
|
1860
|
+
return n;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
/** D1: latency gaps >= 10 min that a live session filled with >= 20 rows. */
|
|
1864
|
+
function computeCoverageGaps(state) {
|
|
1865
|
+
const lat = [...state.latency.rowTs].sort((a, b) => a - b);
|
|
1866
|
+
const ss = [...state.session.rowTs].sort((a, b) => a - b);
|
|
1867
|
+
const cas = [...state.latency.cascadeTs].sort((a, b) => a - b);
|
|
1868
|
+
const gaps = [];
|
|
1869
|
+
for (let i = 1; i < lat.length; i += 1) {
|
|
1870
|
+
const a = lat[i - 1];
|
|
1871
|
+
const b = lat[i];
|
|
1872
|
+
const minutes = (b - a) / 60000;
|
|
1873
|
+
if (minutes < 10) continue;
|
|
1874
|
+
const sessionstartRows = countBetween(ss, a, b);
|
|
1875
|
+
if (sessionstartRows < 20) continue;
|
|
1876
|
+
gaps.push({
|
|
1877
|
+
start: new Date(a).toISOString(),
|
|
1878
|
+
end: new Date(b).toISOString(),
|
|
1879
|
+
minutes: Math.round(minutes),
|
|
1880
|
+
sessionstartRows,
|
|
1881
|
+
cascadeRows: countBetween(cas, a, b),
|
|
1882
|
+
});
|
|
1883
|
+
}
|
|
1884
|
+
return gaps;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
/** D5: per-session firing/stale text and per-session delivery outcomes. */
|
|
1888
|
+
function computeTestRunnerHealth(state) {
|
|
1889
|
+
const runs = state.session.runs.map((r) => ({
|
|
1890
|
+
startTs: r.startTs,
|
|
1891
|
+
firings: r.testFirings,
|
|
1892
|
+
stale: r.testStale,
|
|
1893
|
+
}));
|
|
1894
|
+
const staleRuns = runs.filter(
|
|
1895
|
+
(r) => r.firings >= 10 && r.stale / r.firings >= 0.5,
|
|
1896
|
+
);
|
|
1897
|
+
const firings = runs.reduce((n, r) => n + r.firings, 0);
|
|
1898
|
+
const stale = runs.reduce((n, r) => n + r.stale, 0);
|
|
1899
|
+
const sessions = [];
|
|
1900
|
+
for (const [sessionId, c] of state.latency.testRunnerDelivery) {
|
|
1901
|
+
const total = c.entries().reduce((n, [, v]) => n + v, 0);
|
|
1902
|
+
const delivered = c.get("delivered");
|
|
1903
|
+
sessions.push({
|
|
1904
|
+
sessionId,
|
|
1905
|
+
total,
|
|
1906
|
+
staged: c.get("staged"),
|
|
1907
|
+
eligible: c.get("eligible"),
|
|
1908
|
+
delivered,
|
|
1909
|
+
superseded: c.get("superseded"),
|
|
1910
|
+
deliveredShare: total ? delivered / total : 0,
|
|
1911
|
+
});
|
|
1912
|
+
}
|
|
1913
|
+
const lowDelivery = sessions.filter(
|
|
1914
|
+
(s) => s.total >= 10 && s.deliveredShare < 0.25,
|
|
1915
|
+
);
|
|
1916
|
+
return {
|
|
1917
|
+
firings,
|
|
1918
|
+
stale,
|
|
1919
|
+
staleShare: firings ? stale / firings : 0,
|
|
1920
|
+
staleRuns,
|
|
1921
|
+
sessions,
|
|
1922
|
+
lowDelivery,
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
/** D6: scanner issue-count drift and turn-end knip wall cost, per pid. */
|
|
1927
|
+
function computeKnip(state) {
|
|
1928
|
+
const drift = [];
|
|
1929
|
+
const cost = [];
|
|
1930
|
+
for (const [pid, rowsRaw] of state.latency.knip) {
|
|
1931
|
+
const rows = [...rowsRaw]
|
|
1932
|
+
.filter((r) => r.ms != null)
|
|
1933
|
+
.sort((a, b) => a.ms - b.ms);
|
|
1934
|
+
if (rows.length >= 10) {
|
|
1935
|
+
const issues = rows.map((r) => r.totalIssues);
|
|
1936
|
+
let increments = 0;
|
|
1937
|
+
for (let i = 1; i < issues.length; i += 1)
|
|
1938
|
+
if (issues[i] - issues[i - 1] >= 100) increments += 1;
|
|
1939
|
+
const min = Math.min(...issues);
|
|
1940
|
+
const max = Math.max(...issues);
|
|
1941
|
+
const spread = min > 0 ? (max - min) / min : 0;
|
|
1942
|
+
if (increments >= 5 || spread >= 0.25)
|
|
1943
|
+
drift.push({ pid, rows: rows.length, increments, min, max, spread });
|
|
1944
|
+
}
|
|
1945
|
+
const first = state.latency.pidFirstTs.get(pid);
|
|
1946
|
+
const last = state.latency.pidLastTs.get(pid);
|
|
1947
|
+
const hours = first != null && last != null ? (last - first) / 3600000 : 0;
|
|
1948
|
+
const totalMs = rows.reduce((n, r) => n + r.durationMs, 0);
|
|
1949
|
+
const maxRow = rows.reduce((n, r) => Math.max(n, r.durationMs), 0);
|
|
1950
|
+
// A lifetime under an hour counts as one hour, so a short pid's few
|
|
1951
|
+
// seconds of knip cannot extrapolate to a large hourly rate.
|
|
1952
|
+
const perHour = totalMs / Math.max(hours, 1);
|
|
1953
|
+
if (perHour >= 30000 || maxRow >= 5000)
|
|
1954
|
+
cost.push({ pid, rows: rows.length, totalMs, hours, perHour, maxRow });
|
|
1955
|
+
}
|
|
1956
|
+
return { drift, cost };
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
/** D7: hook deopts that overran their budget, plus the degradation census. */
|
|
1960
|
+
function computeHookAwait(state) {
|
|
1961
|
+
const rows = [...state.latency.hookAwaitExceeded].sort((a, b) =>
|
|
1962
|
+
String(b.ts).localeCompare(String(a.ts)),
|
|
1963
|
+
);
|
|
1964
|
+
const census = [];
|
|
1965
|
+
for (const [pid, kinds] of state.latency.degradationKinds) {
|
|
1966
|
+
census.push({
|
|
1967
|
+
pid,
|
|
1968
|
+
kinds: [...kinds.entries()]
|
|
1969
|
+
.sort((a, b) => b[1] - a[1])
|
|
1970
|
+
.slice(0, 12)
|
|
1971
|
+
.map(([kind, count]) => `${kind}=${count}`),
|
|
1972
|
+
});
|
|
1973
|
+
}
|
|
1974
|
+
return { rows, over: rows.filter((r) => r.ratio >= 1.1).length, census };
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
/** D8: turn_end hook duration per pid, and the retained-turn-state runs. */
|
|
1978
|
+
function computeTurnEndSlow(state) {
|
|
1979
|
+
const flagged = [];
|
|
1980
|
+
for (const [pid, rows] of state.latency.turnEndTools) {
|
|
1981
|
+
const slow = rows.filter((r) => r.durationMs > 3000).length;
|
|
1982
|
+
const max = rows.reduce((n, r) => Math.max(n, r.durationMs), 0);
|
|
1983
|
+
const share = rows.length ? slow / rows.length : 0;
|
|
1984
|
+
if ((rows.length >= 20 && share >= 0.1) || max >= 8000)
|
|
1985
|
+
flagged.push({ pid, rows: rows.length, slow, share, max });
|
|
1986
|
+
}
|
|
1987
|
+
const retainRuns = state.session.runs
|
|
1988
|
+
.filter((r) => r.retainingNewerTurn >= 5)
|
|
1989
|
+
.map((r) => ({ start: r.startTs, count: r.retainingNewerTurn }));
|
|
1990
|
+
return { flagged, retainRuns };
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
/** D9: empty-candidate waits, edit touches with no client, warm-reuse clashes. */
|
|
1994
|
+
function computeLspWait(state) {
|
|
1995
|
+
const empty = [];
|
|
1996
|
+
for (const [pid, cur] of state.latency.lspWaitEmpty)
|
|
1997
|
+
if (cur.ms >= 5000) empty.push({ pid, ms: cur.ms, rows: cur.rows });
|
|
1998
|
+
const noClients = [];
|
|
1999
|
+
for (const [pid, cur] of state.latency.lspTouchEdit)
|
|
2000
|
+
if (cur.rows >= 20 && cur.noClients / cur.rows >= 0.2)
|
|
2001
|
+
noClients.push({
|
|
2002
|
+
pid,
|
|
2003
|
+
rows: cur.rows,
|
|
2004
|
+
noClients: cur.noClients,
|
|
2005
|
+
share: cur.noClients / cur.rows,
|
|
2006
|
+
});
|
|
2007
|
+
const contradictions = [];
|
|
2008
|
+
for (const touch of state.latency.lspTouchNoClients) {
|
|
2009
|
+
const match = state.latency.lspClientSelectedWarm.find(
|
|
2010
|
+
(w) =>
|
|
2011
|
+
w.pid === touch.pid &&
|
|
2012
|
+
w.filePath === touch.filePath &&
|
|
2013
|
+
touch.ms != null &&
|
|
2014
|
+
w.ms != null &&
|
|
2015
|
+
Math.abs(w.ms - touch.ms) <= 500,
|
|
2016
|
+
);
|
|
2017
|
+
if (match)
|
|
2018
|
+
contradictions.push({
|
|
2019
|
+
pid: touch.pid,
|
|
2020
|
+
filePath: touch.filePath,
|
|
2021
|
+
touchTs: touch.ts,
|
|
2022
|
+
selectedTs: match.ts,
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
2025
|
+
const pids = new Set([
|
|
2026
|
+
...empty.map((e) => e.pid),
|
|
2027
|
+
...noClients.map((e) => e.pid),
|
|
2028
|
+
...contradictions.map((c) => c.pid),
|
|
2029
|
+
]);
|
|
2030
|
+
return { empty, noClients, contradictions, pidCount: pids.size };
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
/** D11: a restart kept nothing while the branch held a populated read set. */
|
|
2034
|
+
function computeCarryRestart(state) {
|
|
2035
|
+
return state.latency.carryRestart.filter(
|
|
2036
|
+
(r) =>
|
|
2037
|
+
["startup", "resume", "fork", "reload"].includes(r.trigger) &&
|
|
2038
|
+
r.source !== "none" &&
|
|
2039
|
+
r.kept + r.dropped === 0 &&
|
|
2040
|
+
r.branchToolResults >= 50 &&
|
|
2041
|
+
r.branchReadable,
|
|
2042
|
+
);
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
/** D12: a cross-process nudge right after a sidecar handoff (suspect grade). */
|
|
2046
|
+
function computeRestartSelfNudge(state) {
|
|
2047
|
+
const flags = [];
|
|
2048
|
+
for (const nudge of state.latency.agentNudges) {
|
|
2049
|
+
if (nudge.originCrossProcess < 1) continue;
|
|
2050
|
+
const transition = state.latency.sessionScopeTransitions.find(
|
|
2051
|
+
(t) =>
|
|
2052
|
+
t.pid === nudge.pid &&
|
|
2053
|
+
["own-sidecar", "parent-sidecar"].includes(t.handoffSource) &&
|
|
2054
|
+
nudge.ms != null &&
|
|
2055
|
+
t.ms != null &&
|
|
2056
|
+
nudge.ms >= t.ms &&
|
|
2057
|
+
nudge.ms - t.ms <= 300000,
|
|
2058
|
+
);
|
|
2059
|
+
if (transition) flags.push({ ...nudge, transitionTs: transition.ts });
|
|
2060
|
+
}
|
|
2061
|
+
return flags;
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
/** D13: a collect-later runner failed with findings and nothing was delivered. */
|
|
2065
|
+
function computeDeferredRunner(state) {
|
|
2066
|
+
const flags = [];
|
|
2067
|
+
for (const runner of state.latency.deferredRunnerFailed) {
|
|
2068
|
+
const delivery = state.latency.lateRunnerFindings.find(
|
|
2069
|
+
(f) =>
|
|
2070
|
+
f.pid === runner.pid &&
|
|
2071
|
+
f.turnId === runner.turnId &&
|
|
2072
|
+
(runner.ms == null || f.ms == null || f.ms >= runner.ms),
|
|
2073
|
+
);
|
|
2074
|
+
if (
|
|
2075
|
+
delivery &&
|
|
2076
|
+
delivery.failed >= 1 &&
|
|
2077
|
+
delivery.delivered === 0 &&
|
|
2078
|
+
delivery.dropped === 0
|
|
2079
|
+
)
|
|
2080
|
+
flags.push({
|
|
2081
|
+
...runner,
|
|
2082
|
+
deliveryTs: delivery.ts,
|
|
2083
|
+
pending: delivery.pending,
|
|
2084
|
+
});
|
|
2085
|
+
}
|
|
2086
|
+
return flags;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
/** D14: an auxiliary (file, server) pair stuck in two or more turn ends. */
|
|
2090
|
+
function computeAuxStuck(state) {
|
|
2091
|
+
const flagged = [];
|
|
2092
|
+
for (const [key, count] of state.latency.auxStuck) {
|
|
2093
|
+
if (count < 2) continue;
|
|
2094
|
+
const [pid, filePath, serverId] = key.split("\u0000");
|
|
2095
|
+
flagged.push({ pid, filePath, serverId, count });
|
|
2096
|
+
}
|
|
2097
|
+
flagged.sort((a, b) => b.count - a.count);
|
|
2098
|
+
return flagged;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
/** D15: `historical` provenance with a malformed/legacy stamp. */
|
|
2102
|
+
function computeAdvisoryProvenance(state) {
|
|
2103
|
+
return state.latency.advisoryProvenance.map((row) => {
|
|
2104
|
+
const first = state.latency.pidFirstTs.get(row.pid);
|
|
2105
|
+
const seconds =
|
|
2106
|
+
first != null && row.ms != null
|
|
2107
|
+
? Math.round((row.ms - first) / 1000)
|
|
2108
|
+
: null;
|
|
2109
|
+
return { ...row, secondsSinceFirstRow: seconds };
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
/** D16: `pi-lens loaded: Nms` loads over 2 s. A load with no
|
|
2114
|
+
* `session_start fired` within the next 60 s is a short-lived pid. */
|
|
2115
|
+
function computeSlowExtensionLoad(state) {
|
|
2116
|
+
const fired = state.session.firedTs;
|
|
2117
|
+
return state.session.slowLoads
|
|
2118
|
+
.filter((l) => l.durationMs >= 2000)
|
|
2119
|
+
.map((l) => ({
|
|
2120
|
+
...l,
|
|
2121
|
+
shortLived: !(
|
|
2122
|
+
Number.isFinite(l.ms) &&
|
|
2123
|
+
fired.some((f) => f >= l.ms && f - l.ms <= 60000)
|
|
2124
|
+
),
|
|
2125
|
+
}));
|
|
2126
|
+
}
|
|
2127
|
+
|
|
1298
2128
|
function buildReport(state) {
|
|
1299
2129
|
const smells = [];
|
|
1300
2130
|
const smellCount = (id) => state.smellTotals.get(id);
|
|
2131
|
+
|
|
2132
|
+
// D1-D16 detector computations. Kept out of the smell list so every value
|
|
2133
|
+
// they produce is assertable on its own, not only through a smell count.
|
|
2134
|
+
const coverageGaps = computeCoverageGaps(state);
|
|
2135
|
+
const testRunnerHealth = computeTestRunnerHealth(state);
|
|
2136
|
+
const knip = computeKnip(state);
|
|
2137
|
+
const hookAwait = computeHookAwait(state);
|
|
2138
|
+
const turnEndSlow = computeTurnEndSlow(state);
|
|
2139
|
+
const lspWait = computeLspWait(state);
|
|
2140
|
+
const carryRestart = computeCarryRestart(state);
|
|
2141
|
+
const restartSelfNudge = computeRestartSelfNudge(state);
|
|
2142
|
+
const deferredRunner = computeDeferredRunner(state);
|
|
2143
|
+
const auxStuck = computeAuxStuck(state);
|
|
2144
|
+
const advisoryProvenance = computeAdvisoryProvenance(state);
|
|
2145
|
+
const slowExtensionLoad = computeSlowExtensionLoad(state);
|
|
2146
|
+
const latencyScratch = [...state.latency.scratchRows.values()].reduce(
|
|
2147
|
+
(n, v) => n + v,
|
|
2148
|
+
0,
|
|
2149
|
+
);
|
|
2150
|
+
const extensionScratch = [...state.extension.scratchRows.values()].reduce(
|
|
2151
|
+
(n, v) => n + v,
|
|
2152
|
+
0,
|
|
2153
|
+
);
|
|
2154
|
+
const d3Runs = state.session.runs.filter((r) => {
|
|
2155
|
+
const excludedTest = r.excludedTestFiles.some((p) =>
|
|
2156
|
+
/\.(test|spec)\.|\/tests?\//.test(p),
|
|
2157
|
+
);
|
|
2158
|
+
return (r.excluded >= 1 && excludedTest) || (r.edits >= 10 && r.ran === 0);
|
|
2159
|
+
});
|
|
2160
|
+
const d4Cross = state.session.runs.reduce(
|
|
2161
|
+
(n, r) => n + (r.crossCheckout >= 3 ? r.crossCheckout : 0),
|
|
2162
|
+
0,
|
|
2163
|
+
);
|
|
2164
|
+
const testRunnerSmellCount =
|
|
2165
|
+
testRunnerHealth.staleRuns.length + testRunnerHealth.lowDelivery.length;
|
|
1301
2166
|
addSmell(
|
|
1302
2167
|
smells,
|
|
1303
2168
|
"diagnostic-blockers",
|
|
@@ -1407,19 +2272,17 @@ function buildReport(state) {
|
|
|
1407
2272
|
);
|
|
1408
2273
|
addSmell(
|
|
1409
2274
|
smells,
|
|
1410
|
-
"read-guard-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
limit,
|
|
1416
|
-
),
|
|
2275
|
+
"read-guard-blocks",
|
|
2276
|
+
state.readGuard.events.get("edit_blocked") +
|
|
2277
|
+
state.readGuard.events.get("edit_preflight_blocked"),
|
|
2278
|
+
"Read-guard blocked edits; host/model provenance is not present on the block rows, and warns and exact-replacement misses are informational",
|
|
2279
|
+
state.readGuard.blocks.slice(0, limit),
|
|
1417
2280
|
);
|
|
1418
2281
|
addSmell(
|
|
1419
2282
|
smells,
|
|
1420
2283
|
"read-guard-stale-ranges",
|
|
1421
2284
|
smellCount("read-guard-stale-ranges"),
|
|
1422
|
-
|
|
2285
|
+
`Enforced range mismatches whose read snapshot no longer matched (bypassed-content-match ${state.readGuard.bypassedMismatch} excluded as an allowed edit)`,
|
|
1423
2286
|
state.readGuard.staleRanges.slice(0, limit),
|
|
1424
2287
|
);
|
|
1425
2288
|
addSmell(
|
|
@@ -1479,6 +2342,258 @@ function buildReport(state) {
|
|
|
1479
2342
|
ws.sweeps.slice(0, limit),
|
|
1480
2343
|
);
|
|
1481
2344
|
|
|
2345
|
+
// D1: a latency gap a live session filled.
|
|
2346
|
+
addSmell(
|
|
2347
|
+
smells,
|
|
2348
|
+
"log-coverage-gap",
|
|
2349
|
+
coverageGaps.length,
|
|
2350
|
+
"Latency stream gap >= 10 min that a live session filled with >= 20 sessionstart rows",
|
|
2351
|
+
coverageGaps.slice(0, limit).map((g) => ({
|
|
2352
|
+
ts: g.start,
|
|
2353
|
+
message: `${g.minutes} min gap ${g.start} -> ${g.end}; sessionstartRows=${g.sessionstartRows}; cascadeRows=${g.cascadeRows}`,
|
|
2354
|
+
})),
|
|
2355
|
+
);
|
|
2356
|
+
// D2: test home markers in a real log. Never added to the
|
|
2357
|
+
// default denylist so the pollution stays visible.
|
|
2358
|
+
addSmell(
|
|
2359
|
+
smells,
|
|
2360
|
+
"real-log-test-pollution",
|
|
2361
|
+
latencyScratch + extensionScratch,
|
|
2362
|
+
`Rows naming a test home (witness-home, pi-lens-test-*) (latency ${latencyScratch}, extension ${extensionScratch}); these never belong in a real log`,
|
|
2363
|
+
[
|
|
2364
|
+
...[...state.latency.scratchRows.entries()].map(([pid, count]) => ({
|
|
2365
|
+
key: `latency pid ${pid}`,
|
|
2366
|
+
count,
|
|
2367
|
+
})),
|
|
2368
|
+
...[...state.extension.scratchRows.entries()].map(([pid, count]) => ({
|
|
2369
|
+
key: `extension pid ${pid}`,
|
|
2370
|
+
count,
|
|
2371
|
+
})),
|
|
2372
|
+
].slice(0, limit),
|
|
2373
|
+
);
|
|
2374
|
+
addSmell(
|
|
2375
|
+
smells,
|
|
2376
|
+
"extension-warn-errors",
|
|
2377
|
+
state.extension.warnErrorGroups.size,
|
|
2378
|
+
"extension.log warn/error groups by subsystem and message prefix",
|
|
2379
|
+
state.extension.warnErrorGroups.top(limit),
|
|
2380
|
+
);
|
|
2381
|
+
// D3: a run that excluded its own test files, or edited without running one.
|
|
2382
|
+
addSmell(
|
|
2383
|
+
smells,
|
|
2384
|
+
"turn-end-tests-excluded",
|
|
2385
|
+
d3Runs.length,
|
|
2386
|
+
"Turn-end runs that skipped test files by policy, or edited >= 10 files and ran no test",
|
|
2387
|
+
d3Runs.slice(0, limit).map((r) => ({
|
|
2388
|
+
ts: r.startTs,
|
|
2389
|
+
message: `edits=${r.edits} ran=${r.ran} excluded=${r.excluded} noTestFile=${r.noTestFile}${
|
|
2390
|
+
r.excludedTestFiles.length ? `: ${r.excludedTestFiles.join(", ")}` : ""
|
|
2391
|
+
}`,
|
|
2392
|
+
})),
|
|
2393
|
+
);
|
|
2394
|
+
// D4: a failed-first target that resolved to a different checkout (#3649).
|
|
2395
|
+
addSmell(
|
|
2396
|
+
smells,
|
|
2397
|
+
"test-target-cross-checkout",
|
|
2398
|
+
d4Cross,
|
|
2399
|
+
"Failed-first test targets resolved to a different checkout than the edited source (regression guard for #3649)",
|
|
2400
|
+
state.session.runs
|
|
2401
|
+
.filter((r) => r.crossCheckout >= 3)
|
|
2402
|
+
.slice(0, limit)
|
|
2403
|
+
.map((r) => ({
|
|
2404
|
+
ts: r.startTs,
|
|
2405
|
+
message: `${r.crossCheckout} cross-checkout of ${r.failedFirst} failed-first`,
|
|
2406
|
+
})),
|
|
2407
|
+
);
|
|
2408
|
+
// D5: sessions whose turn-end verdicts went stale, or were rarely delivered.
|
|
2409
|
+
addSmell(
|
|
2410
|
+
smells,
|
|
2411
|
+
"test-runner-stale-verdicts",
|
|
2412
|
+
testRunnerSmellCount,
|
|
2413
|
+
`Sessions with >= 10 test firings and >= 50% stale (${testRunnerHealth.staleRuns.length}), or >= 10 delivery rows and < 25% delivered (${testRunnerHealth.lowDelivery.length}); window firings ${testRunnerHealth.firings}, stale ${testRunnerHealth.stale}`,
|
|
2414
|
+
[
|
|
2415
|
+
...testRunnerHealth.staleRuns.map((r) => ({
|
|
2416
|
+
ts: r.startTs,
|
|
2417
|
+
count: r.stale,
|
|
2418
|
+
message: `firings=${r.firings} stale=${r.stale}`,
|
|
2419
|
+
})),
|
|
2420
|
+
...testRunnerHealth.lowDelivery.map((s) => ({
|
|
2421
|
+
key: s.sessionId,
|
|
2422
|
+
count: s.delivered,
|
|
2423
|
+
message: `delivered ${s.delivered}/${s.total} (${Math.round(
|
|
2424
|
+
s.deliveredShare * 100,
|
|
2425
|
+
)}%), staged ${s.staged}, eligible ${s.eligible}, superseded ${s.superseded}`,
|
|
2426
|
+
})),
|
|
2427
|
+
].slice(0, limit),
|
|
2428
|
+
);
|
|
2429
|
+
// D6: scanner-count drift and knip wall cost.
|
|
2430
|
+
addSmell(
|
|
2431
|
+
smells,
|
|
2432
|
+
"scanner-count-drift",
|
|
2433
|
+
knip.drift.length,
|
|
2434
|
+
"knip totalIssues rose by >= 100 between consecutive executed runs at least 5 times, or its spread >= 25% (pids with >= 10 executed runs)",
|
|
2435
|
+
knip.drift.slice(0, limit).map((d) => ({
|
|
2436
|
+
key: `pid ${d.pid}`,
|
|
2437
|
+
count: d.increments,
|
|
2438
|
+
message: `issues ${d.min} -> ${d.max} (+${Math.round(
|
|
2439
|
+
d.spread * 100,
|
|
2440
|
+
)}%), ${d.increments} increments >= 100`,
|
|
2441
|
+
})),
|
|
2442
|
+
);
|
|
2443
|
+
addSmell(
|
|
2444
|
+
smells,
|
|
2445
|
+
"turn-end-knip-cost",
|
|
2446
|
+
knip.cost.length,
|
|
2447
|
+
"knip consumed >= 30 s per hour of pid lifetime (a lifetime under an hour counts as one hour), or a single run took >= 5 s",
|
|
2448
|
+
knip.cost.slice(0, limit).map((c) => ({
|
|
2449
|
+
key: `pid ${c.pid}`,
|
|
2450
|
+
count: Math.round(c.perHour),
|
|
2451
|
+
message: `${c.totalMs}ms over ${c.hours.toFixed(2)}h = ${Math.round(
|
|
2452
|
+
c.perHour,
|
|
2453
|
+
)}ms/h, max ${c.maxRow}ms`,
|
|
2454
|
+
})),
|
|
2455
|
+
);
|
|
2456
|
+
// D7: hook deopts that overran their budget.
|
|
2457
|
+
addSmell(
|
|
2458
|
+
smells,
|
|
2459
|
+
"hook-await-exceeded",
|
|
2460
|
+
hookAwait.rows.length,
|
|
2461
|
+
`Hook awaits that overran their budget (${hookAwait.over} with ratio >= 1.1)`,
|
|
2462
|
+
hookAwait.rows.slice(0, limit).map((r) => ({
|
|
2463
|
+
ts: r.ts,
|
|
2464
|
+
message: `${r.hook}:${r.label} ${r.elapsedMs}/${r.budgetMs}ms (${r.ratio.toFixed(
|
|
2465
|
+
3,
|
|
2466
|
+
)}) pid=${r.pid} cause=${r.cause}`,
|
|
2467
|
+
})),
|
|
2468
|
+
);
|
|
2469
|
+
// D8: turn_end hook duration and retained-state churn.
|
|
2470
|
+
addSmell(
|
|
2471
|
+
smells,
|
|
2472
|
+
"turn-end-slow",
|
|
2473
|
+
turnEndSlow.flagged.length,
|
|
2474
|
+
"turn_end hook duration over budget (a pid with >= 10% of summaries > 3 s, or one >= 8 s)",
|
|
2475
|
+
turnEndSlow.flagged.slice(0, limit).map((f) => ({
|
|
2476
|
+
key: `pid ${f.pid}`,
|
|
2477
|
+
count: f.slow,
|
|
2478
|
+
message: `${f.slow}/${f.rows} over 3s (${Math.round(
|
|
2479
|
+
f.share * 100,
|
|
2480
|
+
)}%), max ${f.max}ms`,
|
|
2481
|
+
})),
|
|
2482
|
+
);
|
|
2483
|
+
addSmell(
|
|
2484
|
+
smells,
|
|
2485
|
+
"turn-end-retained-state",
|
|
2486
|
+
turnEndSlow.retainRuns.length,
|
|
2487
|
+
"Turn-end retained newer turn state at least 5 times in one session",
|
|
2488
|
+
turnEndSlow.retainRuns.slice(0, limit).map((r) => ({
|
|
2489
|
+
ts: r.start,
|
|
2490
|
+
count: r.count,
|
|
2491
|
+
})),
|
|
2492
|
+
);
|
|
2493
|
+
// D9: empty-candidate waits and no-client/edit warm-reuse contradictions.
|
|
2494
|
+
addSmell(
|
|
2495
|
+
smells,
|
|
2496
|
+
"lsp-wait-empty-candidates",
|
|
2497
|
+
lspWait.pidCount,
|
|
2498
|
+
`LSP touch saw no client while a warm client was selected, or waited with an empty candidate set (empty ${lspWait.empty.length}, noClients ${lspWait.noClients.length}, contradictions ${lspWait.contradictions.length})`,
|
|
2499
|
+
[
|
|
2500
|
+
...lspWait.empty.map((e) => ({
|
|
2501
|
+
key: `pid ${e.pid}`,
|
|
2502
|
+
count: e.rows,
|
|
2503
|
+
message: `${e.ms}ms waiting with no candidate server`,
|
|
2504
|
+
})),
|
|
2505
|
+
...lspWait.noClients.map((e) => ({
|
|
2506
|
+
key: `pid ${e.pid}`,
|
|
2507
|
+
count: Math.round(e.share * 100),
|
|
2508
|
+
message: `${e.noClients}/${e.rows} edits saw no client (${Math.round(
|
|
2509
|
+
e.share * 100,
|
|
2510
|
+
)}%)`,
|
|
2511
|
+
})),
|
|
2512
|
+
...lspWait.contradictions.map((c) => ({
|
|
2513
|
+
key: `pid ${c.pid}`,
|
|
2514
|
+
count: 1,
|
|
2515
|
+
message: `${c.filePath}: no-client touch at ${c.touchTs}, warm-reuse at ${c.selectedTs}`,
|
|
2516
|
+
})),
|
|
2517
|
+
].slice(0, limit),
|
|
2518
|
+
);
|
|
2519
|
+
// D10: a zero_read block that contradicts earlier read/edit evidence.
|
|
2520
|
+
addSmell(
|
|
2521
|
+
smells,
|
|
2522
|
+
"resume-state-loss",
|
|
2523
|
+
state.readGuard.stateLost.length,
|
|
2524
|
+
`zero_read edits blocked despite earlier read/edit evidence in the same session (genuine ${state.readGuard.genuineZeroRead.length})`,
|
|
2525
|
+
state.readGuard.stateLost.slice(0, limit),
|
|
2526
|
+
);
|
|
2527
|
+
// D11: a restart whose read-set carry was empty while the branch was populated.
|
|
2528
|
+
addSmell(
|
|
2529
|
+
smells,
|
|
2530
|
+
"carry-empty-restart",
|
|
2531
|
+
carryRestart.length,
|
|
2532
|
+
"Restart carry kept and dropped nothing while the branch held a populated read set",
|
|
2533
|
+
carryRestart.slice(0, limit).map((r) => ({
|
|
2534
|
+
key: `pid ${r.pid}`,
|
|
2535
|
+
count: r.branchToolResults,
|
|
2536
|
+
message: `trigger=${r.trigger} source=${r.source} kept=${r.kept} dropped=${r.dropped} branchToolResults=${r.branchToolResults}`,
|
|
2537
|
+
})),
|
|
2538
|
+
);
|
|
2539
|
+
// D12: a cross-process nudge right after a sidecar handoff (suspect until O7).
|
|
2540
|
+
addSmell(
|
|
2541
|
+
smells,
|
|
2542
|
+
"restart-self-nudge",
|
|
2543
|
+
restartSelfNudge.length,
|
|
2544
|
+
"Cross-process nudge within 300 s of a sidecar handoff (suspect-grade until the nudge carries a file id, O7)",
|
|
2545
|
+
restartSelfNudge.slice(0, limit).map((r) => ({
|
|
2546
|
+
key: `pid ${r.pid}`,
|
|
2547
|
+
count: r.originCrossProcess,
|
|
2548
|
+
message: `${JSON.stringify(r.reasonMix)} crossProcess=${r.originCrossProcess} after ${r.transitionTs}`,
|
|
2549
|
+
})),
|
|
2550
|
+
);
|
|
2551
|
+
// D13: a collect-later runner failed with findings and none were delivered.
|
|
2552
|
+
addSmell(
|
|
2553
|
+
smells,
|
|
2554
|
+
"deferred-runner-failed-undelivered",
|
|
2555
|
+
deferredRunner.length,
|
|
2556
|
+
"collect-later runner failed with findings and the delivery row shows failed>=1, delivered=0, dropped=0 (#3796 witness)",
|
|
2557
|
+
deferredRunner.slice(0, limit).map((r) => ({
|
|
2558
|
+
ts: r.ts,
|
|
2559
|
+
message: `${r.runnerId} pid=${r.pid} turnId=${r.turnId} diagnostics=${r.diagnosticCount} delivery=${r.deliveryTs}`,
|
|
2560
|
+
})),
|
|
2561
|
+
);
|
|
2562
|
+
// D14: an auxiliary (file, server) pair stuck in >= 2 turn ends.
|
|
2563
|
+
addSmell(
|
|
2564
|
+
smells,
|
|
2565
|
+
"aux-stuck-pair",
|
|
2566
|
+
auxStuck.length,
|
|
2567
|
+
"Auxiliary (file, server) pair stuck in >= 2 turn ends",
|
|
2568
|
+
auxStuck.slice(0, limit).map((p) => ({
|
|
2569
|
+
key: p.serverId,
|
|
2570
|
+
count: p.count,
|
|
2571
|
+
message: `${p.filePath} pid=${p.pid}`,
|
|
2572
|
+
})),
|
|
2573
|
+
);
|
|
2574
|
+
// D15: historical provenance with a malformed/legacy stamp.
|
|
2575
|
+
addSmell(
|
|
2576
|
+
smells,
|
|
2577
|
+
"advisory-provenance-unknown",
|
|
2578
|
+
advisoryProvenance.length,
|
|
2579
|
+
"Advisory provenance resolved to historical with a malformed-or-legacy stamp",
|
|
2580
|
+
advisoryProvenance.slice(0, limit).map((r) => ({
|
|
2581
|
+
ts: r.ts,
|
|
2582
|
+
message: `${r.provenanceStamp} (${r.advisoryKind}) ${r.secondsSinceFirstRow}s after pid start`,
|
|
2583
|
+
})),
|
|
2584
|
+
);
|
|
2585
|
+
// D16: extension load time over 2 s.
|
|
2586
|
+
addSmell(
|
|
2587
|
+
smells,
|
|
2588
|
+
"slow-extension-load",
|
|
2589
|
+
slowExtensionLoad.length,
|
|
2590
|
+
"pi-lens loaded >= 2000ms after process start (short-lived: no session_start fired within 60 s)",
|
|
2591
|
+
slowExtensionLoad.slice(0, limit).map((l) => ({
|
|
2592
|
+
...l,
|
|
2593
|
+
message: `${l.message}${l.shortLived ? " [short-lived]" : ""}`,
|
|
2594
|
+
})),
|
|
2595
|
+
);
|
|
2596
|
+
|
|
1482
2597
|
return {
|
|
1483
2598
|
window: state.window,
|
|
1484
2599
|
filesScanned: Object.fromEntries(
|
|
@@ -1549,6 +2664,12 @@ function buildReport(state) {
|
|
|
1549
2664
|
0,
|
|
1550
2665
|
limit,
|
|
1551
2666
|
),
|
|
2667
|
+
// E2/D10: the block/warn split and the lost-read-set classification.
|
|
2668
|
+
warns: state.readGuard.warns.slice(0, limit),
|
|
2669
|
+
blockByKind: state.readGuard.blockByKind.toJSON(),
|
|
2670
|
+
bypassedMismatch: state.readGuard.bypassedMismatch,
|
|
2671
|
+
stateLost: state.readGuard.stateLost.slice(0, limit),
|
|
2672
|
+
genuineZeroRead: state.readGuard.genuineZeroRead.slice(0, limit),
|
|
1552
2673
|
},
|
|
1553
2674
|
treeSitter: {
|
|
1554
2675
|
phases: state.treeSitter.phases.toJSON(),
|
|
@@ -1559,7 +2680,8 @@ function buildReport(state) {
|
|
|
1559
2680
|
session: {
|
|
1560
2681
|
starts: state.session.starts,
|
|
1561
2682
|
cwds: state.session.cwds.top(limit),
|
|
1562
|
-
|
|
2683
|
+
commits: state.session.commits.toJSON(),
|
|
2684
|
+
slowLoads: state.session.slowLoads.slice(0, limit),
|
|
1563
2685
|
errors: state.session.errors.slice(0, limit),
|
|
1564
2686
|
},
|
|
1565
2687
|
// #2526: the positive-observability counters behind the
|
|
@@ -1602,6 +2724,43 @@ function buildReport(state) {
|
|
|
1602
2724
|
.sort((a, b) => b.total - a.total)
|
|
1603
2725
|
.slice(0, limit * 3),
|
|
1604
2726
|
},
|
|
2727
|
+
// D1-D16: the per-detector values behind the smells above, so a test can
|
|
2728
|
+
// pin the rule (not only the rendered count) and a reader can see WHY.
|
|
2729
|
+
detectors: {
|
|
2730
|
+
logCoverageGap: { gaps: coverageGaps },
|
|
2731
|
+
realLogTestPollution: {
|
|
2732
|
+
latencyByPid: Object.fromEntries(state.latency.scratchRows),
|
|
2733
|
+
extensionByPid: Object.fromEntries(state.extension.scratchRows),
|
|
2734
|
+
latencyTotal: latencyScratch,
|
|
2735
|
+
extensionTotal: extensionScratch,
|
|
2736
|
+
},
|
|
2737
|
+
turnEndTestsExcluded: {
|
|
2738
|
+
runs: d3Runs.map((r) => ({ ...r })),
|
|
2739
|
+
},
|
|
2740
|
+
testTargetCrossCheckout: {
|
|
2741
|
+
runs: state.session.runs.map((r) => ({
|
|
2742
|
+
startTs: r.startTs,
|
|
2743
|
+
crossCheckout: r.crossCheckout,
|
|
2744
|
+
failedFirst: r.failedFirst,
|
|
2745
|
+
})),
|
|
2746
|
+
},
|
|
2747
|
+
testRunnerStaleVerdicts: testRunnerHealth,
|
|
2748
|
+
knip,
|
|
2749
|
+
hookAwait,
|
|
2750
|
+
turnEndSlow,
|
|
2751
|
+
lspWait,
|
|
2752
|
+
resumeStateLoss: {
|
|
2753
|
+
stateLost: state.readGuard.stateLost,
|
|
2754
|
+
genuine: state.readGuard.genuineZeroRead,
|
|
2755
|
+
},
|
|
2756
|
+
carryEmptyRestart: carryRestart,
|
|
2757
|
+
restartSelfNudge,
|
|
2758
|
+
deferredRunnerFailedUndelivered: deferredRunner,
|
|
2759
|
+
auxStuckPairs: auxStuck,
|
|
2760
|
+
advisoryProvenanceUnknown: advisoryProvenance,
|
|
2761
|
+
slowExtensionLoad,
|
|
2762
|
+
extensionWarnErrors: state.extension.warnErrorGroups.toJSON(),
|
|
2763
|
+
},
|
|
1605
2764
|
};
|
|
1606
2765
|
}
|
|
1607
2766
|
|
|
@@ -1649,6 +2808,60 @@ function printReport(report) {
|
|
|
1649
2808
|
}
|
|
1650
2809
|
}
|
|
1651
2810
|
|
|
2811
|
+
// D1/D2/D5/D6/D7: the non-smell breakdown behind the new detectors.
|
|
2812
|
+
const det = report.detectors ?? {};
|
|
2813
|
+
const gap = det.logCoverageGap;
|
|
2814
|
+
if (gap?.gaps?.length) {
|
|
2815
|
+
console.log("\nLog coverage");
|
|
2816
|
+
for (const g of gap.gaps ?? [])
|
|
2817
|
+
console.log(
|
|
2818
|
+
` gap ${g.minutes}min ${g.start} → ${g.end} sessionstart=${g.sessionstartRows} cascade=${g.cascadeRows}`,
|
|
2819
|
+
);
|
|
2820
|
+
}
|
|
2821
|
+
const warnErrors = Object.entries(det.extensionWarnErrors ?? {});
|
|
2822
|
+
if (warnErrors.length) {
|
|
2823
|
+
console.log("\nExtension diagnostics");
|
|
2824
|
+
for (const [k, v] of warnErrors.slice(0, limit))
|
|
2825
|
+
console.log(` ${String(v).padStart(5)} ${k}`);
|
|
2826
|
+
}
|
|
2827
|
+
const deg = det.hookAwait?.census ?? [];
|
|
2828
|
+
if (deg.length) {
|
|
2829
|
+
console.log("\nDegradation ledger census (max count per pid)");
|
|
2830
|
+
for (const row of deg.slice(0, limit))
|
|
2831
|
+
console.log(` pid ${row.pid}: ${row.kinds.join(", ")}`);
|
|
2832
|
+
}
|
|
2833
|
+
const delivery = det.testRunnerStaleVerdicts;
|
|
2834
|
+
if (delivery) {
|
|
2835
|
+
console.log("\nTest-runner delivery");
|
|
2836
|
+
console.log(
|
|
2837
|
+
` firings=${delivery.firings} stale=${delivery.stale} (${(
|
|
2838
|
+
delivery.staleShare * 100
|
|
2839
|
+
).toFixed(1)}%)`,
|
|
2840
|
+
);
|
|
2841
|
+
for (const s of delivery.sessions ?? [])
|
|
2842
|
+
console.log(
|
|
2843
|
+
` ${s.sessionId}: delivered ${s.delivered}/${s.total} staged=${s.staged} eligible=${s.eligible} superseded=${s.superseded}`,
|
|
2844
|
+
);
|
|
2845
|
+
}
|
|
2846
|
+
const knip = det.knip;
|
|
2847
|
+
if (knip && (knip.drift.length || knip.cost.length)) {
|
|
2848
|
+
console.log("\nknip drift and cost");
|
|
2849
|
+
for (const d of knip.drift)
|
|
2850
|
+
console.log(
|
|
2851
|
+
` pid ${d.pid}: issues ${d.min} → ${d.max} (${d.increments} increments >= 100)`,
|
|
2852
|
+
);
|
|
2853
|
+
for (const c of knip.cost)
|
|
2854
|
+
console.log(
|
|
2855
|
+
` pid ${c.pid}: ${Math.round(c.perHour)}ms/h, max ${c.maxRow}ms`,
|
|
2856
|
+
);
|
|
2857
|
+
}
|
|
2858
|
+
const extLoads = det.slowExtensionLoad ?? [];
|
|
2859
|
+
if (extLoads.length) {
|
|
2860
|
+
const shortLived = extLoads.filter((l) => l.shortLived).length;
|
|
2861
|
+
console.log("\nExtension loads");
|
|
2862
|
+
console.log(` slow=${extLoads.length} shortLived=${shortLived}`);
|
|
2863
|
+
}
|
|
2864
|
+
|
|
1652
2865
|
section(
|
|
1653
2866
|
"Diagnostic rules",
|
|
1654
2867
|
report.diagnostics.byRule,
|
|
@@ -1705,7 +2918,7 @@ function printReport(report) {
|
|
|
1705
2918
|
report.latency.testRunnerVerdicts ?? {},
|
|
1706
2919
|
);
|
|
1707
2920
|
if (verdictSessions.length) {
|
|
1708
|
-
console.log("\nTest-runner stale verdicts per session");
|
|
2921
|
+
console.log("\nTest-runner stale verdicts per session (verdict rows only)");
|
|
1709
2922
|
for (const [sessionId, summary] of verdictSessions) {
|
|
1710
2923
|
console.log(
|
|
1711
2924
|
` ${sessionId}: ${summary.stale}/${summary.total} stale (${(summary.rate * 100).toFixed(1)}%)`,
|