pi-lens 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (650) hide show
  1. package/CHANGELOG.md +1064 -0
  2. package/README.md +115 -25
  3. package/config/dependency-cruiser-eager-allowlist.json +6 -2
  4. package/dist/chunk-22AVIGXS.js +560 -0
  5. package/dist/chunk-27BBHSZC.js +106 -0
  6. package/dist/chunk-2BEMIWEW.js +51 -0
  7. package/dist/chunk-2EECBNC5.js +89 -0
  8. package/dist/chunk-34U7PLGE.js +23 -0
  9. package/dist/chunk-3I5QFT3N.js +181 -0
  10. package/dist/chunk-3MED75HT.js +37 -0
  11. package/dist/chunk-47D2BO4S.js +87 -0
  12. package/dist/chunk-4RERDEXR.js +348 -0
  13. package/dist/chunk-4W2PLC4J.js +27 -0
  14. package/dist/chunk-52H5B5TC.js +202 -0
  15. package/dist/chunk-54B42YRX.js +27 -0
  16. package/dist/chunk-5RXBNSW2.js +266 -0
  17. package/dist/chunk-5THXD6X5.js +201 -0
  18. package/dist/chunk-5W3R6LFT.js +24 -0
  19. package/dist/chunk-5ZEJHV35.js +341 -0
  20. package/dist/chunk-6P62QVEA.js +118 -0
  21. package/dist/chunk-6QIUX4EP.js +459 -0
  22. package/dist/chunk-6VCD4VKZ.js +78 -0
  23. package/dist/chunk-7F72PXY2.js +326 -0
  24. package/dist/chunk-7FBF7NPR.js +998 -0
  25. package/dist/chunk-7U2IDNXN.js +37 -0
  26. package/dist/chunk-ABBOA7UD.js +157 -0
  27. package/dist/chunk-AHDW3GPE.js +50 -0
  28. package/dist/chunk-AJ3QXTRQ.js +756 -0
  29. package/dist/chunk-AJVLWNFN.js +1610 -0
  30. package/dist/chunk-AJXODZY6.js +112 -0
  31. package/dist/chunk-ARFCXG7S.js +84 -0
  32. package/dist/chunk-AS44CFQ4.js +708 -0
  33. package/dist/chunk-AWE5TMPO.js +38 -0
  34. package/dist/chunk-B3I2UUT4.js +4692 -0
  35. package/dist/chunk-BRJKOBZP.js +331 -0
  36. package/dist/chunk-BW5KFIQC.js +59 -0
  37. package/dist/chunk-C2AUYXQH.js +149 -0
  38. package/dist/chunk-CGGAIP7J.js +29 -0
  39. package/dist/chunk-D6QS3U6M.js +30 -0
  40. package/dist/chunk-DFVMIKMQ.js +349 -0
  41. package/dist/chunk-DIULIWKU.js +169 -0
  42. package/dist/chunk-DQ2NZ7C4.js +2317 -0
  43. package/dist/chunk-E2WFBRHM.js +213 -0
  44. package/dist/chunk-E4MAEDPM.js +50 -0
  45. package/dist/chunk-EOKRQ3SA.js +30 -0
  46. package/dist/chunk-F3AU2TMM.js +2626 -0
  47. package/dist/chunk-F3P7VQ7H.js +170 -0
  48. package/dist/chunk-FC4RP4I2.js +12 -0
  49. package/dist/chunk-FJNKANOS.js +32 -0
  50. package/dist/chunk-GUOGVTCQ.js +146 -0
  51. package/dist/chunk-GVXA6CCE.js +18 -0
  52. package/dist/chunk-HHYAELLJ.js +2334 -0
  53. package/dist/chunk-HMFXILPV.js +83 -0
  54. package/dist/chunk-HVUZXSWK.js +421 -0
  55. package/dist/chunk-HWBZIGMJ.js +62 -0
  56. package/dist/chunk-I3R7GKDR.js +17 -0
  57. package/dist/chunk-I7SPGOWI.js +55 -0
  58. package/dist/chunk-IIXOAGHR.js +38 -0
  59. package/dist/chunk-IVP5KAB7.js +2250 -0
  60. package/dist/chunk-IXEBJSUE.js +22 -0
  61. package/dist/chunk-JOLITGCC.js +27 -0
  62. package/dist/chunk-K6VYLB2U.js +145 -0
  63. package/dist/chunk-LJDODBBZ.js +78 -0
  64. package/dist/chunk-LNAKEO63.js +78 -0
  65. package/dist/chunk-LSMJ6KBE.js +4139 -0
  66. package/dist/chunk-LW6XKDZQ.js +5565 -0
  67. package/dist/chunk-N3YQJI6O.js +899 -0
  68. package/dist/chunk-NABLC7W3.js +148 -0
  69. package/dist/chunk-NKOUFPQF.js +659 -0
  70. package/dist/chunk-NL5GLMFI.js +211 -0
  71. package/dist/chunk-NMABWBZN.js +327 -0
  72. package/dist/chunk-NTHH2J74.js +27 -0
  73. package/dist/chunk-NTUJEGDZ.js +59 -0
  74. package/dist/chunk-NXL4FFQQ.js +47 -0
  75. package/dist/chunk-NXPS2L6U.js +466 -0
  76. package/dist/chunk-O5WILGMI.js +42 -0
  77. package/dist/chunk-O6TQT6RI.js +48 -0
  78. package/dist/chunk-OAXNDZJ7.js +323 -0
  79. package/dist/chunk-ODEEOXPH.js +44 -0
  80. package/dist/chunk-OQGFCZJ4.js +4533 -0
  81. package/dist/chunk-ORTMY4Q4.js +282 -0
  82. package/dist/chunk-OS32RNR2.js +442 -0
  83. package/dist/chunk-PAK6IDME.js +189 -0
  84. package/dist/chunk-PWFHBTSF.js +406 -0
  85. package/dist/chunk-Q5U6FMDI.js +2352 -0
  86. package/dist/chunk-QOZXJ4NA.js +3364 -0
  87. package/dist/chunk-QYF5S6P6.js +45 -0
  88. package/dist/chunk-RIISMHKN.js +36 -0
  89. package/dist/chunk-RPD4ZSB7.js +25 -0
  90. package/dist/chunk-RPD5K5NC.js +79 -0
  91. package/dist/chunk-RUOG5D2C.js +262 -0
  92. package/dist/chunk-T4ERT73Y.js +599 -0
  93. package/dist/chunk-T6D4Q4AQ.js +54 -0
  94. package/dist/chunk-TGPXLY2J.js +391 -0
  95. package/dist/chunk-TLGFBM3F.js +12116 -0
  96. package/dist/chunk-TO6WL3GM.js +88 -0
  97. package/dist/chunk-TT22N74J.js +517 -0
  98. package/dist/chunk-TVN5N6GY.js +21216 -0
  99. package/dist/chunk-U3VGR4VU.js +308 -0
  100. package/dist/chunk-UK3CMEAL.js +1250 -0
  101. package/dist/chunk-UOPVJQ4N.js +103 -0
  102. package/dist/chunk-UXVNL3D7.js +23 -0
  103. package/dist/chunk-UY752QSN.js +45 -0
  104. package/dist/chunk-V5PXFSZK.js +188 -0
  105. package/dist/chunk-V7R425XG.js +398 -0
  106. package/dist/chunk-VCSRSYLF.js +81 -0
  107. package/dist/chunk-VD4JQCQC.js +162 -0
  108. package/dist/chunk-VDBPVIKD.js +62 -0
  109. package/dist/chunk-VHQLPIRJ.js +114 -0
  110. package/dist/chunk-VN2AXLEX.js +5414 -0
  111. package/dist/chunk-VNMT7C64.js +478 -0
  112. package/dist/chunk-WONERJTP.js +309 -0
  113. package/dist/chunk-XECLWQZN.js +85 -0
  114. package/dist/chunk-XIMYZ3JA.js +27 -0
  115. package/dist/chunk-XK4CIILI.js +144 -0
  116. package/dist/chunk-Y4T27COV.js +562 -0
  117. package/dist/chunk-YGVYKNSN.js +1860 -0
  118. package/dist/chunk-YLF3PPT5.js +308 -0
  119. package/dist/chunk-YSNFMJKN.js +14 -0
  120. package/dist/chunk-Z3CCVDUB.js +76 -0
  121. package/dist/chunk-Z54ZSOBZ.js +61 -0
  122. package/dist/chunk-ZAWW3AF6.js +97 -0
  123. package/dist/chunk-ZMOL6RQC.js +167 -0
  124. package/dist/index.js +16456 -8335
  125. package/dist/mcp/analyze-cli.js +186 -232
  126. package/dist/mcp/cli.js +137 -98
  127. package/dist/mcp/server.js +22589 -1573
  128. package/dist/mcp/worker.js +97 -38
  129. package/dist/probes/installer.js +135 -0
  130. package/dist/workers/project-snapshot-persist-worker.js +22 -0
  131. package/dist/workers/review-graph-persist-worker.js +15 -0
  132. package/docs/agent-guide.md +13 -4
  133. package/docs/agent-tools.md +42 -0
  134. package/docs/ast-grep_rules_catalog.md +3 -2
  135. package/docs/configuration.md +20 -1
  136. package/docs/environment-variables.md +52 -2
  137. package/docs/features.md +8 -4
  138. package/docs/globalconfig.md +1 -0
  139. package/docs/io-bridge-v2-migration.md +94 -0
  140. package/docs/lsp-capability-matrix.md +36 -4
  141. package/docs/lsp-idle-eviction.md +124 -0
  142. package/docs/mcp.md +21 -5
  143. package/docs/merge-queue-rollout.md +77 -0
  144. package/docs/pi-lens-fixer.md +156 -88
  145. package/docs/pi-lens-investigator.md +74 -26
  146. package/docs/pi-lens-merge-policy.md +694 -0
  147. package/docs/pi-lens-monitor.md +73 -7
  148. package/docs/pi-lens-retro.md +6 -4
  149. package/docs/pi-lens-reviewer.md +188 -48
  150. package/docs/pi-lens-subagent.md +246 -45
  151. package/docs/pi-lens-warden.md +18 -7
  152. package/docs/public-api-stability.md +55 -0
  153. package/docs/release-qa-baseline.md +84 -17
  154. package/docs/rfcs/3654-unified-io-bridge-v2.md +316 -0
  155. package/docs/servercapabilities.md +53 -49
  156. package/docs/settings.md +1 -0
  157. package/docs/usage.md +5 -1
  158. package/grammars/tree-sitter-bash.wasm +0 -0
  159. package/grammars/tree-sitter-bash.wasm.json +3 -3
  160. package/package.json +19 -7
  161. package/rules/ast-grep-rules/rule-tests/advisory-registry-subset-test.yml +41 -0
  162. package/rules/ast-grep-rules/rules/advisory-registry-subset.yml +50 -0
  163. package/scripts/analyze-pi-lens-logs.mjs +1275 -62
  164. package/scripts/download-grammars.js +5 -0
  165. package/scripts/grammars.lock.json +6 -1
  166. package/scripts/install-selftest.mjs +33 -34
  167. package/scripts/lib/host-provided-deps.mjs +13 -4
  168. package/scripts/lib/web-tree-sitter-dir.mjs +18 -0
  169. package/dist/clients/actionable-warnings-logger.js +0 -35
  170. package/dist/clients/actionable-warnings.js +0 -1610
  171. package/dist/clients/advisory-provenance.js +0 -593
  172. package/dist/clients/agent-behavior-client.js +0 -147
  173. package/dist/clients/agent-nudge.js +0 -325
  174. package/dist/clients/analysed-root.js +0 -1
  175. package/dist/clients/ast-grep-client.js +0 -731
  176. package/dist/clients/ast-grep-rule-manager.js +0 -146
  177. package/dist/clients/ast-grep-tool-logger.js +0 -118
  178. package/dist/clients/ast-grep-types.js +0 -10
  179. package/dist/clients/ast-grep-yaml-synth.js +0 -154
  180. package/dist/clients/atomic-write-staging.js +0 -75
  181. package/dist/clients/atomic-write.js +0 -189
  182. package/dist/clients/availability-probe-flight.js +0 -12
  183. package/dist/clients/bash-file-access.js +0 -1056
  184. package/dist/clients/biome-client.js +0 -357
  185. package/dist/clients/blocker-freshness.js +0 -837
  186. package/dist/clients/blocker-past-eof.js +0 -129
  187. package/dist/clients/bootstrap.js +0 -569
  188. package/dist/clients/bounded-cache.js +0 -190
  189. package/dist/clients/bounded-pid-file-lock.js +0 -202
  190. package/dist/clients/bounded-telemetry.js +0 -295
  191. package/dist/clients/build-identity.js +0 -95
  192. package/dist/clients/bundled-resource-health.js +0 -113
  193. package/dist/clients/bus-events-logger.js +0 -105
  194. package/dist/clients/bus-publish.js +0 -171
  195. package/dist/clients/cache/rule-cache.js +0 -190
  196. package/dist/clients/cache-manager.js +0 -524
  197. package/dist/clients/cache-observability.js +0 -1313
  198. package/dist/clients/call-graph.js +0 -852
  199. package/dist/clients/cargo-manifest.js +0 -422
  200. package/dist/clients/cascade-budget.js +0 -196
  201. package/dist/clients/cascade-format.js +0 -315
  202. package/dist/clients/cascade-logger.js +0 -31
  203. package/dist/clients/cascade-types.js +0 -9
  204. package/dist/clients/child-unref.js +0 -124
  205. package/dist/clients/code-quality-warnings.js +0 -286
  206. package/dist/clients/codebase-model.js +0 -173
  207. package/dist/clients/collateral-test-role.js +0 -40
  208. package/dist/clients/complexity-client.js +0 -462
  209. package/dist/clients/config-core/deny.js +0 -221
  210. package/dist/clients/config-core/index.js +0 -50
  211. package/dist/clients/config-core/merge.js +0 -357
  212. package/dist/clients/config-core/normalize.js +0 -340
  213. package/dist/clients/config-core/process-spec.js +0 -248
  214. package/dist/clients/config-core/provenance.js +0 -164
  215. package/dist/clients/config-core/records.js +0 -218
  216. package/dist/clients/config-core/resolve.js +0 -125
  217. package/dist/clients/config-core/safe-object.js +0 -78
  218. package/dist/clients/config-core/schema.js +0 -165
  219. package/dist/clients/config-diagnostic-codes.js +0 -285
  220. package/dist/clients/config-locations.js +0 -388
  221. package/dist/clients/config-resolve.js +0 -798
  222. package/dist/clients/config-schema.js +0 -251
  223. package/dist/clients/config-warn.js +0 -407
  224. package/dist/clients/console-guard-install.js +0 -26
  225. package/dist/clients/cooperative-budget.js +0 -42
  226. package/dist/clients/dead-code-client.js +0 -510
  227. package/dist/clients/dead-code-logger.js +0 -30
  228. package/dist/clients/deadline-utils.js +0 -280
  229. package/dist/clients/debug-handles.js +0 -211
  230. package/dist/clients/debug-heap.js +0 -174
  231. package/dist/clients/deferred-lsp-work.js +0 -106
  232. package/dist/clients/degradation-ledger.js +0 -426
  233. package/dist/clients/demoted-finding-render.js +0 -169
  234. package/dist/clients/dependency-checker.js +0 -885
  235. package/dist/clients/deps/ast-grep-napi.js +0 -22
  236. package/dist/clients/deps/js-yaml.js +0 -9
  237. package/dist/clients/deps/minimatch.js +0 -4
  238. package/dist/clients/deps/pi-tui.js +0 -14
  239. package/dist/clients/deps/typebox.js +0 -14
  240. package/dist/clients/deps/vscode-jsonrpc.js +0 -1
  241. package/dist/clients/deps/web-tree-sitter.js +0 -24
  242. package/dist/clients/diagnostic-dispositions.js +0 -630
  243. package/dist/clients/diagnostic-line-freshness.js +0 -305
  244. package/dist/clients/diagnostic-logger.js +0 -73
  245. package/dist/clients/diagnostic-tracker.js +0 -105
  246. package/dist/clients/diagnostics-publish.js +0 -230
  247. package/dist/clients/dispatch/ast-grep-catalog.js +0 -65
  248. package/dist/clients/dispatch/auxiliary-lsp.js +0 -343
  249. package/dist/clients/dispatch/collect-later-tier.js +0 -35
  250. package/dist/clients/dispatch/diagnostic-taxonomy.js +0 -66
  251. package/dist/clients/dispatch/dispatcher.js +0 -1269
  252. package/dist/clients/dispatch/fact-provider-types.js +0 -1
  253. package/dist/clients/dispatch/fact-rule-runner.js +0 -17
  254. package/dist/clients/dispatch/fact-runner.js +0 -30
  255. package/dist/clients/dispatch/fact-scheduler.js +0 -68
  256. package/dist/clients/dispatch/fact-store.js +0 -377
  257. package/dist/clients/dispatch/facts/comment-facts.js +0 -22
  258. package/dist/clients/dispatch/facts/file-content.js +0 -19
  259. package/dist/clients/dispatch/facts/function-facts.js +0 -348
  260. package/dist/clients/dispatch/facts/import-facts.js +0 -204
  261. package/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -34
  262. package/dist/clients/dispatch/facts/try-catch-facts.js +0 -119
  263. package/dist/clients/dispatch/finding-policy.js +0 -339
  264. package/dist/clients/dispatch/indent-detect.js +0 -417
  265. package/dist/clients/dispatch/inline-suppressions.js +0 -89
  266. package/dist/clients/dispatch/integration.js +0 -2377
  267. package/dist/clients/dispatch/lazy.js +0 -11
  268. package/dist/clients/dispatch/pending-runner-findings.js +0 -87
  269. package/dist/clients/dispatch/plan.js +0 -278
  270. package/dist/clients/dispatch/priorities.js +0 -20
  271. package/dist/clients/dispatch/rule-id-normalize.js +0 -50
  272. package/dist/clients/dispatch/rule-ignores.js +0 -69
  273. package/dist/clients/dispatch/rule-policy.js +0 -135
  274. package/dist/clients/dispatch/rules/async-noise.js +0 -40
  275. package/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
  276. package/dist/clients/dispatch/rules/cors-wildcard.js +0 -54
  277. package/dist/clients/dispatch/rules/error-obscuring.js +0 -32
  278. package/dist/clients/dispatch/rules/error-swallowing.js +0 -31
  279. package/dist/clients/dispatch/rules/framework-call-noise.js +0 -67
  280. package/dist/clients/dispatch/rules/high-complexity.js +0 -72
  281. package/dist/clients/dispatch/rules/high-fan-out.js +0 -74
  282. package/dist/clients/dispatch/rules/high-import-coupling.js +0 -37
  283. package/dist/clients/dispatch/rules/missing-error-propagation.js +0 -62
  284. package/dist/clients/dispatch/rules/no-commented-credentials.js +0 -52
  285. package/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -42
  286. package/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
  287. package/dist/clients/dispatch/rules/unsafe-boundary.js +0 -126
  288. package/dist/clients/dispatch/runner-context.js +0 -52
  289. package/dist/clients/dispatch/runners/actionlint.js +0 -111
  290. package/dist/clients/dispatch/runners/ast-grep-napi.js +0 -1196
  291. package/dist/clients/dispatch/runners/biome-check.js +0 -296
  292. package/dist/clients/dispatch/runners/cpp-check.js +0 -219
  293. package/dist/clients/dispatch/runners/credo.js +0 -82
  294. package/dist/clients/dispatch/runners/cue-vet.js +0 -416
  295. package/dist/clients/dispatch/runners/dart-analyze.js +0 -183
  296. package/dist/clients/dispatch/runners/detekt.js +0 -176
  297. package/dist/clients/dispatch/runners/dotnet-build.js +0 -164
  298. package/dist/clients/dispatch/runners/elixir-check.js +0 -195
  299. package/dist/clients/dispatch/runners/eslint.js +0 -137
  300. package/dist/clients/dispatch/runners/fact-rules.js +0 -29
  301. package/dist/clients/dispatch/runners/fish-indent.js +0 -69
  302. package/dist/clients/dispatch/runners/gleam-check.js +0 -167
  303. package/dist/clients/dispatch/runners/go-vet.js +0 -104
  304. package/dist/clients/dispatch/runners/golangci-lint.js +0 -135
  305. package/dist/clients/dispatch/runners/hadolint.js +0 -91
  306. package/dist/clients/dispatch/runners/helm-lint.js +0 -171
  307. package/dist/clients/dispatch/runners/helm-render.js +0 -940
  308. package/dist/clients/dispatch/runners/htmlhint.js +0 -117
  309. package/dist/clients/dispatch/runners/index.js +0 -108
  310. package/dist/clients/dispatch/runners/javac.js +0 -99
  311. package/dist/clients/dispatch/runners/ktlint.js +0 -110
  312. package/dist/clients/dispatch/runners/lsp.js +0 -379
  313. package/dist/clients/dispatch/runners/markdownlint.js +0 -167
  314. package/dist/clients/dispatch/runners/mypy.js +0 -102
  315. package/dist/clients/dispatch/runners/oxlint.js +0 -414
  316. package/dist/clients/dispatch/runners/php-lint.js +0 -85
  317. package/dist/clients/dispatch/runners/phpstan.js +0 -120
  318. package/dist/clients/dispatch/runners/prisma-validate.js +0 -62
  319. package/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -445
  320. package/dist/clients/dispatch/runners/pyright.js +0 -169
  321. package/dist/clients/dispatch/runners/rubocop.js +0 -99
  322. package/dist/clients/dispatch/runners/ruff.js +0 -88
  323. package/dist/clients/dispatch/runners/rust-clippy.js +0 -256
  324. package/dist/clients/dispatch/runners/shellcheck.js +0 -173
  325. package/dist/clients/dispatch/runners/shfmt.js +0 -102
  326. package/dist/clients/dispatch/runners/spellcheck.js +0 -128
  327. package/dist/clients/dispatch/runners/spotbugs.js +0 -259
  328. package/dist/clients/dispatch/runners/sqlfluff.js +0 -183
  329. package/dist/clients/dispatch/runners/stylelint.js +0 -166
  330. package/dist/clients/dispatch/runners/swiftlint.js +0 -163
  331. package/dist/clients/dispatch/runners/taplo.js +0 -174
  332. package/dist/clients/dispatch/runners/terragrunt.js +0 -168
  333. package/dist/clients/dispatch/runners/tflint.js +0 -125
  334. package/dist/clients/dispatch/runners/tree-sitter.js +0 -643
  335. package/dist/clients/dispatch/runners/trivy-config.js +0 -253
  336. package/dist/clients/dispatch/runners/utils/availability-policy.js +0 -496
  337. package/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -90
  338. package/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -95
  339. package/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -274
  340. package/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1701
  341. package/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -101
  342. package/dist/clients/dispatch/runners/utils/tool-failure.js +0 -235
  343. package/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -169
  344. package/dist/clients/dispatch/runners/utils.js +0 -15
  345. package/dist/clients/dispatch/runners/vale.js +0 -128
  346. package/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -242
  347. package/dist/clients/dispatch/runners/yamllint.js +0 -95
  348. package/dist/clients/dispatch/runners/zig-check.js +0 -79
  349. package/dist/clients/dispatch/suppress-writer.js +0 -79
  350. package/dist/clients/dispatch/tool-profile.js +0 -30
  351. package/dist/clients/dispatch/types.js +0 -21
  352. package/dist/clients/dispatch/utils/format-utils.js +0 -45
  353. package/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -35
  354. package/dist/clients/disposition-logger.js +0 -32
  355. package/dist/clients/disposition-publish.js +0 -124
  356. package/dist/clients/durable-store.js +0 -97
  357. package/dist/clients/effective-config.js +0 -415
  358. package/dist/clients/env-utils.js +0 -83
  359. package/dist/clients/error-class.js +0 -23
  360. package/dist/clients/eval-timestamp.js +0 -17
  361. package/dist/clients/event-loop-hold.js +0 -274
  362. package/dist/clients/event-loop-monitor.js +0 -250
  363. package/dist/clients/extension-log.js +0 -504
  364. package/dist/clients/extension-mode.js +0 -73
  365. package/dist/clients/feature-hints.js +0 -103
  366. package/dist/clients/file-kinds.js +0 -412
  367. package/dist/clients/file-role.js +0 -134
  368. package/dist/clients/file-time.js +0 -160
  369. package/dist/clients/file-utils.js +0 -1032
  370. package/dist/clients/finding-delivery-gate.js +0 -494
  371. package/dist/clients/finding-identity.js +0 -88
  372. package/dist/clients/fix-worklog.js +0 -103
  373. package/dist/clients/format-events-publish.js +0 -343
  374. package/dist/clients/format-service.js +0 -222
  375. package/dist/clients/formatters-lazy.js +0 -9
  376. package/dist/clients/formatters.js +0 -2032
  377. package/dist/clients/freshness-cadence.js +0 -17
  378. package/dist/clients/freshness.js +0 -38
  379. package/dist/clients/generated-artifacts.js +0 -394
  380. package/dist/clients/generation-guard.js +0 -215
  381. package/dist/clients/git-guard.js +0 -1136
  382. package/dist/clients/git-tracked-ignore.js +0 -243
  383. package/dist/clients/gitleaks-client.js +0 -509
  384. package/dist/clients/go-client.js +0 -104
  385. package/dist/clients/govulncheck-client.js +0 -605
  386. package/dist/clients/gradle-ktfmt-style.js +0 -348
  387. package/dist/clients/grammar-source.js +0 -465
  388. package/dist/clients/gzip-stage-write.js +0 -135
  389. package/dist/clients/hashline-anchor.js +0 -424
  390. package/dist/clients/hook-budgets.js +0 -76
  391. package/dist/clients/host-edit-normalize.js +0 -140
  392. package/dist/clients/host-ports.js +0 -39
  393. package/dist/clients/indent-retarget.js +0 -154
  394. package/dist/clients/inline-blocker-dispositions.js +0 -186
  395. package/dist/clients/install-diagnostics.js +0 -156
  396. package/dist/clients/installer/index.js +0 -5416
  397. package/dist/clients/installer/managed-tool-refresh-session.js +0 -58
  398. package/dist/clients/installer/managed-tool-refresh.js +0 -783
  399. package/dist/clients/instance-reaper-state.js +0 -7
  400. package/dist/clients/instance-reaper.js +0 -1137
  401. package/dist/clients/instance-registry-lock.js +0 -145
  402. package/dist/clients/instance-registry.js +0 -773
  403. package/dist/clients/jscpd-client.js +0 -378
  404. package/dist/clients/json-cache-read.js +0 -65
  405. package/dist/clients/knip-client.js +0 -788
  406. package/dist/clients/language-policy.js +0 -252
  407. package/dist/clients/language-profile.js +0 -361
  408. package/dist/clients/language-registry.js +0 -603
  409. package/dist/clients/latency-logger.js +0 -727
  410. package/dist/clients/lazy-import.js +0 -21
  411. package/dist/clients/ledger-bounds.js +0 -54
  412. package/dist/clients/lens-config.js +0 -404
  413. package/dist/clients/lens-engine.js +0 -358
  414. package/dist/clients/lens-events.js +0 -125
  415. package/dist/clients/lens-flag-registry.js +0 -467
  416. package/dist/clients/lens-map.js +0 -1156
  417. package/dist/clients/live-bus-emitter.js +0 -74
  418. package/dist/clients/log-cleanup.js +0 -222
  419. package/dist/clients/lsp/aggregation.js +0 -178
  420. package/dist/clients/lsp/cascade-tier.js +0 -421
  421. package/dist/clients/lsp/client.js +0 -4593
  422. package/dist/clients/lsp/config.js +0 -691
  423. package/dist/clients/lsp/content-limits.js +0 -41
  424. package/dist/clients/lsp/diagnostic-binding.js +0 -225
  425. package/dist/clients/lsp/document-drift.js +0 -467
  426. package/dist/clients/lsp/edits.js +0 -1219
  427. package/dist/clients/lsp/index.js +0 -8305
  428. package/dist/clients/lsp/inferred-project.js +0 -216
  429. package/dist/clients/lsp/jvm-runtime.js +0 -298
  430. package/dist/clients/lsp/language.js +0 -63
  431. package/dist/clients/lsp/launch.js +0 -746
  432. package/dist/clients/lsp/lombok.js +0 -158
  433. package/dist/clients/lsp/path-utils.js +0 -5
  434. package/dist/clients/lsp/pending-aux-coverage.js +0 -251
  435. package/dist/clients/lsp/position-encoding.js +0 -61
  436. package/dist/clients/lsp/ruby-drive-dirs.js +0 -83
  437. package/dist/clients/lsp/server.js +0 -3290
  438. package/dist/clients/lsp/session-roots.js +0 -192
  439. package/dist/clients/lsp/spawn-history.js +0 -17
  440. package/dist/clients/lsp/sync-kind.js +0 -56
  441. package/dist/clients/lsp/tsserver-sync.js +0 -332
  442. package/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
  443. package/dist/clients/lsp/wait-policy/classification.js +0 -85
  444. package/dist/clients/lsp/wait-policy/index.js +0 -10
  445. package/dist/clients/lsp/wait-policy/strategies.js +0 -392
  446. package/dist/clients/lsp/watch-queue.js +0 -61
  447. package/dist/clients/lsp/workspace-diagnostics-cache.js +0 -639
  448. package/dist/clients/lsp/workspace-diagnostics-session.js +0 -30
  449. package/dist/clients/lsp/workspace-sweep-hold.js +0 -184
  450. package/dist/clients/lsp-budget.js +0 -186
  451. package/dist/clients/lsp-document-symbols.js +0 -110
  452. package/dist/clients/lsp-lazy.js +0 -9
  453. package/dist/clients/lsp-mutation.js +0 -396
  454. package/dist/clients/lsp-status.js +0 -59
  455. package/dist/clients/map-with-concurrency.js +0 -40
  456. package/dist/clients/mcp/analyze.js +0 -420
  457. package/dist/clients/mcp/host-shim.js +0 -31
  458. package/dist/clients/mcp/ipc.js +0 -523
  459. package/dist/clients/mcp/review.js +0 -197
  460. package/dist/clients/mcp/session.js +0 -412
  461. package/dist/clients/memory-sampler.js +0 -208
  462. package/dist/clients/message-end-attribution.js +0 -30
  463. package/dist/clients/metrics-client.js +0 -107
  464. package/dist/clients/metrics-history.js +0 -327
  465. package/dist/clients/middle-man-analysis.js +0 -263
  466. package/dist/clients/model-provider.js +0 -53
  467. package/dist/clients/module-report-lsp.js +0 -189
  468. package/dist/clients/module-report.js +0 -2150
  469. package/dist/clients/mutating-tool.js +0 -651
  470. package/dist/clients/mutation-attribution.js +0 -368
  471. package/dist/clients/mutation-bridge.js +0 -240
  472. package/dist/clients/ndjson-logger.js +0 -734
  473. package/dist/clients/observed-mutation-sources.js +0 -101
  474. package/dist/clients/observed-mutation.js +0 -1253
  475. package/dist/clients/oldtext-autopatch.js +0 -128
  476. package/dist/clients/opaque-mutation-scan.js +0 -496
  477. package/dist/clients/opengrep-client.js +0 -333
  478. package/dist/clients/opengrep-config.js +0 -76
  479. package/dist/clients/package-manager.js +0 -607
  480. package/dist/clients/package-root.js +0 -38
  481. package/dist/clients/partial-edit-apply.js +0 -439
  482. package/dist/clients/path-attribution-telemetry.js +0 -43
  483. package/dist/clients/path-keyed-map.js +0 -108
  484. package/dist/clients/path-utils.js +0 -1244
  485. package/dist/clients/performance-report.js +0 -331
  486. package/dist/clients/persist-debounce.js +0 -70
  487. package/dist/clients/persistent-reverify.js +0 -271
  488. package/dist/clients/php-cs-fixer-config.js +0 -119
  489. package/dist/clients/pipeline.js +0 -1480
  490. package/dist/clients/post-autofix-notice.js +0 -37
  491. package/dist/clients/print-mode.js +0 -21
  492. package/dist/clients/probe-home-state.js +0 -228
  493. package/dist/clients/process-bridge.js +0 -66
  494. package/dist/clients/process-singletons.js +0 -210
  495. package/dist/clients/process-snapshot.js +0 -68
  496. package/dist/clients/project-changes.js +0 -181
  497. package/dist/clients/project-conventions.js +0 -171
  498. package/dist/clients/project-diagnostics/cache.js +0 -137
  499. package/dist/clients/project-diagnostics/extractors.js +0 -109
  500. package/dist/clients/project-diagnostics/fresh-fetch.js +0 -668
  501. package/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -118
  502. package/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -47
  503. package/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -40
  504. package/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -34
  505. package/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -38
  506. package/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -47
  507. package/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -48
  508. package/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -40
  509. package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -127
  510. package/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -81
  511. package/dist/clients/project-diagnostics/scanner.js +0 -520
  512. package/dist/clients/project-diagnostics/types.js +0 -1
  513. package/dist/clients/project-lens-config.js +0 -807
  514. package/dist/clients/project-report.js +0 -701
  515. package/dist/clients/project-scale.js +0 -237
  516. package/dist/clients/project-scan-policy.js +0 -11
  517. package/dist/clients/project-snapshot-fingerprint.js +0 -48
  518. package/dist/clients/project-snapshot-persist-worker.js +0 -20
  519. package/dist/clients/project-snapshot.js +0 -1653
  520. package/dist/clients/project-trust.js +0 -181
  521. package/dist/clients/python-environment.js +0 -217
  522. package/dist/clients/python-provenance.js +0 -639
  523. package/dist/clients/quiet-window-config.js +0 -47
  524. package/dist/clients/quiet-window.js +0 -236
  525. package/dist/clients/read-bridge.js +0 -139
  526. package/dist/clients/read-expansion.js +0 -266
  527. package/dist/clients/read-guard-logger.js +0 -251
  528. package/dist/clients/read-guard-tool-lines.js +0 -1306
  529. package/dist/clients/read-guard.js +0 -1561
  530. package/dist/clients/recent-touches.js +0 -240
  531. package/dist/clients/redact/secrets.js +0 -449
  532. package/dist/clients/resource-sampler.js +0 -628
  533. package/dist/clients/reverse-deps.js +0 -270
  534. package/dist/clients/review-graph/builder.js +0 -5126
  535. package/dist/clients/review-graph/format.js +0 -33
  536. package/dist/clients/review-graph/git-identity.js +0 -163
  537. package/dist/clients/review-graph/import-resolvers.js +0 -481
  538. package/dist/clients/review-graph/persist-worker.js +0 -10
  539. package/dist/clients/review-graph/query.js +0 -244
  540. package/dist/clients/review-graph/revision-drift.js +0 -21
  541. package/dist/clients/review-graph/service.js +0 -96
  542. package/dist/clients/review-graph/shared-extraction-ir.js +0 -82
  543. package/dist/clients/review-graph/symbol-id.js +0 -103
  544. package/dist/clients/review-graph/tsconfig-paths.js +0 -299
  545. package/dist/clients/review-graph/types.js +0 -1
  546. package/dist/clients/review-graph/workspace-modules.js +0 -449
  547. package/dist/clients/review-graph-logger.js +0 -81
  548. package/dist/clients/ruff-client.js +0 -179
  549. package/dist/clients/rules-scanner.js +0 -131
  550. package/dist/clients/run-duration.js +0 -55
  551. package/dist/clients/runtime-agent-end.js +0 -746
  552. package/dist/clients/runtime-config.js +0 -77
  553. package/dist/clients/runtime-context.js +0 -211
  554. package/dist/clients/runtime-coordinator.js +0 -1324
  555. package/dist/clients/runtime-session.js +0 -2485
  556. package/dist/clients/runtime-tool-call.js +0 -1295
  557. package/dist/clients/runtime-tool-result.js +0 -2049
  558. package/dist/clients/runtime-turn.js +0 -3767
  559. package/dist/clients/rust-client.js +0 -97
  560. package/dist/clients/safe-spawn.js +0 -2357
  561. package/dist/clients/sanitize.js +0 -286
  562. package/dist/clients/scan-utils.js +0 -25
  563. package/dist/clients/scratch-tree-policy.js +0 -165
  564. package/dist/clients/search-read-registration.js +0 -94
  565. package/dist/clients/secret-findings.js +0 -114
  566. package/dist/clients/security-scan-client.js +0 -352
  567. package/dist/clients/session-event-guard.js +0 -297
  568. package/dist/clients/session-lifecycle.js +0 -484
  569. package/dist/clients/session-start-observability.js +0 -94
  570. package/dist/clients/session-state-store.js +0 -101
  571. package/dist/clients/session-summary.js +0 -15
  572. package/dist/clients/sessionstart-logger.js +0 -27
  573. package/dist/clients/sg-runner.js +0 -876
  574. package/dist/clients/sgconfig.js +0 -347
  575. package/dist/clients/shared-checkout-guard.js +0 -338
  576. package/dist/clients/single-flight.js +0 -158
  577. package/dist/clients/situational-tool-telemetry.js +0 -108
  578. package/dist/clients/skills-resolver.js +0 -141
  579. package/dist/clients/slow-fs.js +0 -138
  580. package/dist/clients/smells-rollup.js +0 -231
  581. package/dist/clients/source-filter.js +0 -596
  582. package/dist/clients/source-walker.js +0 -211
  583. package/dist/clients/spawn-output-cap.js +0 -120
  584. package/dist/clients/spawn-timeout-cooldown.js +0 -110
  585. package/dist/clients/stale-marker.js +0 -17
  586. package/dist/clients/startup-scan.js +0 -400
  587. package/dist/clients/startup-timing.js +0 -130
  588. package/dist/clients/string-utils.js +0 -33
  589. package/dist/clients/subagent-mode.js +0 -111
  590. package/dist/clients/symbol-containment.js +0 -24
  591. package/dist/clients/symbol-types.js +0 -5
  592. package/dist/clients/test-runner-client.js +0 -2507
  593. package/dist/clients/test-runner-delivery.js +0 -287
  594. package/dist/clients/todo-scanner.js +0 -229
  595. package/dist/clients/tool-agreement.js +0 -423
  596. package/dist/clients/tool-config.js +0 -249
  597. package/dist/clients/tool-cwd.js +0 -270
  598. package/dist/clients/tool-definition.js +0 -47
  599. package/dist/clients/tool-event.js +0 -105
  600. package/dist/clients/tool-policy.js +0 -2755
  601. package/dist/clients/tool-probe.js +0 -53
  602. package/dist/clients/tool-render.js +0 -156
  603. package/dist/clients/tool-set-policy.js +0 -118
  604. package/dist/clients/tree-sitter-cache.js +0 -364
  605. package/dist/clients/tree-sitter-client.js +0 -4195
  606. package/dist/clients/tree-sitter-logger.js +0 -100
  607. package/dist/clients/tree-sitter-navigator.js +0 -269
  608. package/dist/clients/tree-sitter-query-loader.js +0 -569
  609. package/dist/clients/tree-sitter-shared.js +0 -158
  610. package/dist/clients/tree-sitter-symbol-extractor.js +0 -1265
  611. package/dist/clients/trivy-client.js +0 -467
  612. package/dist/clients/tui-fit.js +0 -50
  613. package/dist/clients/turn-context.js +0 -52
  614. package/dist/clients/turn-end/lane.js +0 -51
  615. package/dist/clients/turn-end/lanes/govulncheck.js +0 -112
  616. package/dist/clients/turn-end/lanes/secrets.js +0 -204
  617. package/dist/clients/turn-summary-render.js +0 -72
  618. package/dist/clients/turn-summary.js +0 -132
  619. package/dist/clients/typos-config.js +0 -29
  620. package/dist/clients/user-notify.js +0 -51
  621. package/dist/clients/vanished-instance-marker.js +0 -57
  622. package/dist/clients/warm-attach.js +0 -305
  623. package/dist/clients/widget-state.js +0 -1808
  624. package/dist/clients/word-index-logger.js +0 -49
  625. package/dist/clients/word-index-store.js +0 -459
  626. package/dist/clients/word-index.js +0 -2080
  627. package/dist/clients/workspace-topology.js +0 -443
  628. package/dist/clients/write-ordering-guard.js +0 -65
  629. package/dist/clients/zizmor-config.js +0 -340
  630. package/dist/i18n.js +0 -69
  631. package/dist/mcp/build-staleness.js +0 -124
  632. package/dist/scripts/lib/process-scan.mjs +0 -583
  633. package/dist/scripts/lib/skills-predicate.mjs +0 -129
  634. package/dist/scripts/lib/web-tree-sitter-dir.mjs +0 -123
  635. package/dist/tools/activate-tools.js +0 -87
  636. package/dist/tools/ast-grep-outline.js +0 -137
  637. package/dist/tools/ast-grep-replace.js +0 -244
  638. package/dist/tools/ast-grep-search.js +0 -762
  639. package/dist/tools/effective-config.js +0 -90
  640. package/dist/tools/lens-diagnostic-mark.js +0 -375
  641. package/dist/tools/lens-diagnostics.js +0 -2571
  642. package/dist/tools/lsp-diagnostics.js +0 -1745
  643. package/dist/tools/lsp-navigation.js +0 -1367
  644. package/dist/tools/lsp-structured-output.js +0 -294
  645. package/dist/tools/module-report.js +0 -382
  646. package/dist/tools/project-report.js +0 -86
  647. package/dist/tools/render-compact.js +0 -374
  648. package/dist/tools/scan-progress.js +0 -53
  649. package/dist/tools/shared.js +0 -29
  650. package/dist/tools/symbol-search.js +0 -155
@@ -1,400 +0,0 @@
1
- /**
2
- * Startup scan safety — gates eager cache warmups to real project roots.
3
- *
4
- * Prevents pi-lens from scanning $HOME or generic directories at session
5
- * start, which would hang or produce meaningless results.
6
- *
7
- * Credit: alexx-ftw (PR #1)
8
- */
9
- import * as os from "node:os";
10
- import * as path from "node:path";
11
- import { BoundedLruCache } from "./bounded-cache.js";
12
- import { normalizeMapKey } from "./path-utils.js";
13
- import { lazyEnvNumber } from "./env-utils.js";
14
- import { getProjectIgnoreMatcher, } from "./file-utils.js";
15
- import { isAtOrAboveHomeDir } from "./path-utils.js";
16
- import { getStartupScanMaxSourceFilesDerived } from "./project-scale.js";
17
- import { shouldRecurseIntoDir, walkTreeStackAsync, walkTreeStackSync, } from "./source-walker.js";
18
- import { getDirectoryMarkers, registerWorkspaceTopologyReset, } from "./workspace-topology.js";
19
- const PROJECT_ROOT_MARKERS = [
20
- ".git",
21
- "package.json",
22
- "pyproject.toml",
23
- "Cargo.toml",
24
- "go.mod",
25
- "composer.json",
26
- ];
27
- // #758: hard ceiling on the number of directory entries the startup source
28
- // count walk will visit before it gives up and declares the tree too big to
29
- // a project has MANY source files — a repo with FEW source files but a huge
30
- // pile of non-source files (e.g. a game mod: 300 scripts among 84k data files)
31
- // never trips it, so the pre-#758 walk traversed the entire tree, dominated by
32
- // one ignoreMatcher.isIgnored() call per entry, blocking session_start for
33
- // seconds. Capping total entries bounds that worst case deterministically. The
34
- // same pattern already guards jscpd-client.ts's hasSourceFilesRecursive walk.
35
- export const MAX_STARTUP_SCAN_ENTRIES = 50_000;
36
- const SOURCE_FILE_PATTERN = /\.(ts|tsx|js|jsx|py|go|rs|rb)$/;
37
- // Default TTL for a persisted `too-many-source-files` verdict (#699): 24h.
38
- const DEFAULT_STARTUP_SCAN_VERDICT_TTL_MS = 24 * 60 * 60 * 1000;
39
- /**
40
- * How long a persisted `too-many-source-files` verdict stays reusable before
41
- * a session re-walks the tree to refresh it (#699).
42
- *
43
- * Resolution order: `PI_LENS_STARTUP_SCAN_VERDICT_TTL_MS` env var, else the
44
- * 24h default. Lazy + memoized (via `lazyEnvNumber`, #763) so importing this
45
- * module never touches `process.env` at load time (house style — see
46
- * `runtime-config.ts` / `slow-fs.ts` / `subagent-mode.ts`).
47
- */
48
- const _ttl = lazyEnvNumber("PI_LENS_STARTUP_SCAN_VERDICT_TTL_MS", DEFAULT_STARTUP_SCAN_VERDICT_TTL_MS);
49
- export const getStartupScanVerdictTtlMs = _ttl.get;
50
- /** Test-only: clears the memoized TTL so a subsequent call re-reads the env
51
- * var (matching the `_resetForTests` convention). */
52
- export const _resetStartupScanVerdictTtlForTests = _ttl._resetForTests;
53
- /**
54
- * Total directory-entry ceiling for the startup source-count walk (#758).
55
- *
56
- * Resolution order: `PI_LENS_STARTUP_SCAN_MAX_ENTRIES` env var, else the
57
- * `MAX_STARTUP_SCAN_ENTRIES` default. Lazy + memoized (via `lazyEnvNumber`,
58
- * #763) so importing this module never touches `process.env` at load time
59
- * (same house style as `getStartupScanVerdictTtlMs`).
60
- */
61
- const _maxEntries = lazyEnvNumber("PI_LENS_STARTUP_SCAN_MAX_ENTRIES", MAX_STARTUP_SCAN_ENTRIES);
62
- export const getStartupScanMaxEntries = _maxEntries.get;
63
- /** Test-only: clears the memoized entry cap so a subsequent call re-reads the
64
- * env var (matching the `_resetForTests` convention). */
65
- export const _resetStartupScanMaxEntriesForTests = _maxEntries._resetForTests;
66
- /**
67
- * Whether a persisted startup-scan verdict is still safe to reuse without
68
- * re-walking the project tree (#699).
69
- *
70
- * The content-derived reasons `too-many-source-files` and `too-many-entries`
71
- * (#758) are the ones that are TTL'd. They can go stale on their own: the repo
72
- * can shrink below the source-file cap (or below the entry ceiling)
73
- * between sessions, and nothing else would notice
74
- * — the seq-based freshness check that guards every other
75
- * `project-snapshot.json` field never fires for them, because pi-lens never
76
- * writes anything while `canWarmCaches` is false, so the snapshot's seq
77
- * never advances on its own. Trade-off, by design: a shrunk repo recovers
78
- * automatically once the TTL expires and the next session re-walks, in
79
- * exchange for skipping a walk that (per #699) can cost 17s+ on a large
80
- * monorepo, on every single process start, for a result nothing could use.
81
- *
82
- * `home-dir` / `no-project-root` describe the resolved root's location
83
- * relative to $HOME, not its contents, so they don't drift the same way —
84
- * reused indefinitely here (still gated by the snapshot's own seq-freshness
85
- * check upstream). `canWarmCaches: true` verdicts aren't TTL'd by this
86
- * function either; a fresh snapshot's `seq` match already implies the
87
- * project state hasn't moved since it warmed successfully.
88
- *
89
- * Fails closed on a verdict with no `computedAt` (e.g. hand-written test
90
- * fixture, or a pre-#699 snapshot) — treated as stale so it gets refreshed
91
- * rather than trusted indefinitely.
92
- */
93
- export function isStartupScanVerdictFresh(verdict, now = Date.now()) {
94
- if (verdict.reason !== "too-many-source-files" &&
95
- verdict.reason !== "too-many-entries")
96
- return true;
97
- if (typeof verdict.computedAt !== "number")
98
- return false;
99
- return now - verdict.computedAt < getStartupScanVerdictTtlMs();
100
- }
101
- /**
102
- * Nearest ancestor (inclusive) of `startDir` containing any of
103
- * `PROJECT_ROOT_MARKERS`, or `null` if none found before the filesystem root.
104
- *
105
- * #807: the per-directory marker check now reads through
106
- * `workspace-topology.ts`'s `getDirectoryMarkers` (one cached `readdir` per
107
- * directory) instead of doing `PROJECT_ROOT_MARKERS.length` separate
108
- * `existsSync` stats per directory — same dedup win as the rest of the #806
109
- * migration. Deliberately NOT routed through the topology service's
110
- * home-guarded `findNearestDirWithMarker`/`findNearestDirWithAnyBasename`
111
- * walkers, though: this function's callers (`computeStartupScanContext` /
112
- * `resolveStartupScanContextAsync`, below) need the ACTUAL directory a marker
113
- * resolved to — including one AT or ABOVE `$HOME` — to tell the
114
- * `"home-dir"` verdict apart from `"no-project-root"` and to populate
115
- * `scanRoot`/`projectRoot` for diagnostics (see the `startup-scan-home-ceiling`
116
- * tests: a marker found in an ancestor of `$HOME` must still be *returned*
117
- * here, with the home rejection applied by the caller). A guarded walker that
118
- * stops before ever looking at/above `$HOME` would go blind exactly where
119
- * this function's contract requires it to keep looking, silently turning a
120
- * `"home-dir"` verdict into `"no-project-root"`. The walk-UP loop itself
121
- * therefore stays hand-written, unbounded by `$HOME`/depth, matching its
122
- * pre-#807 behavior exactly.
123
- */
124
- export function findNearestProjectRoot(startDir) {
125
- let current = path.resolve(startDir);
126
- while (true) {
127
- const entryNames = getDirectoryMarkers(current).entryNames;
128
- if (PROJECT_ROOT_MARKERS.some((marker) => entryNames.has(marker))) {
129
- return current;
130
- }
131
- const parent = path.dirname(current);
132
- if (parent === current)
133
- return null;
134
- current = parent;
135
- }
136
- }
137
- /**
138
- * Per-entry step of the source-count walk (#761), plugged into both the sync
139
- * and async {@link walkTreeStackSync}/`Async` drivers, which differ only in
140
- * yield cadence. Applies both bounds in their historical order:
141
- * - `limit`: source-file early-exit (existing behavior) — fires as soon as
142
- * more than `limit` source files are seen.
143
- * - `maxEntries`: total directory-entry ceiling (#758) — fires as soon as
144
- * `maxEntries` entries have been visited (`visited >= maxEntries`, checked
145
- * AFTER classification), flagging `entryBudgetExceeded` so a mixed
146
- * source/non-source tree can't drag the walk across the whole tree.
147
- * The source-limit check precedes the entry-budget check, so an entry that
148
- * trips both stops as a source-limit hit (`entryBudgetExceeded` stays false).
149
- *
150
- * Directories here never check for generated-artifact names. Symlinked
151
- * directories are NEVER traversed — not by policy but by classification
152
- * (#775 audit follow-up): `fs.Dirent` reports a symlink-to-directory as
153
- * `isSymbolicLink() === true` / `isDirectory() === false` (junctions
154
- * included), so such entries fall through to the file branch below and are
155
- * merely counted as entries. The `followSymlinks: true` passed to
156
- * `shouldRecurseIntoDir` is therefore inert here; a symlink cycle cannot
157
- * hang this walk. Pinned by tests/clients/startup-scan-symlink-cycle.test.ts.
158
- */
159
- function makeSourceCountVisitor(state, ignoreMatcher, limit, maxEntries) {
160
- return (entry, fullPath) => {
161
- state.visited += 1;
162
- if (entry.isDirectory()) {
163
- const recurse = shouldRecurseIntoDir(entry, fullPath, {
164
- ignoreMatcher,
165
- followSymlinks: true,
166
- });
167
- if (state.visited >= maxEntries) {
168
- state.entryBudgetExceeded = true;
169
- return "stop";
170
- }
171
- return recurse ? "recurse" : "skip";
172
- }
173
- // #1974: extension-pattern gate before isIgnored — isIgnored recompiles
174
- // minimatch patterns per ancestor dir per call, so it should only run for
175
- // entries the cheap regex already flags as source.
176
- if (entry.isFile() &&
177
- SOURCE_FILE_PATTERN.test(entry.name) &&
178
- !ignoreMatcher.isIgnored(fullPath, false)) {
179
- state.count += 1;
180
- if (state.count > limit)
181
- return "stop";
182
- }
183
- if (state.visited >= maxEntries) {
184
- state.entryBudgetExceeded = true;
185
- return "stop";
186
- }
187
- return "skip";
188
- };
189
- }
190
- /**
191
- * Core synchronous source-count walk shared by the public
192
- * `countSourceFilesWithinLimit` wrapper and `computeStartupScanContext`.
193
- * Bounds are documented on `makeSourceCountVisitor`.
194
- */
195
- function walkSourceCount(dir, limit, maxEntries) {
196
- const state = {
197
- count: 0,
198
- visited: 0,
199
- entryBudgetExceeded: false,
200
- };
201
- const rootDir = path.resolve(dir);
202
- const ignoreMatcher = getProjectIgnoreMatcher(rootDir);
203
- walkTreeStackSync(rootDir, makeSourceCountVisitor(state, ignoreMatcher, limit, maxEntries));
204
- return { count: state.count, entryBudgetExceeded: state.entryBudgetExceeded };
205
- }
206
- export function countSourceFilesWithinLimit(dir, limit) {
207
- // Public wrapper keeps its pre-#758 contract: only the source-file limit
208
- // bounds it (no entry ceiling). The #758 entry budget applies solely to the
209
- // startup-scan verdict path via `walkSourceCount`.
210
- return walkSourceCount(dir, limit, Number.POSITIVE_INFINITY).count;
211
- }
212
- // Session-lifetime memo for the (cwd, homeDir, maxSourceFiles) tuple. The
213
- // underlying computation walks the entire project root counting source
214
- // files and is dominated by ignoreMatcher.isIgnored() calls; on a 2k-file
215
- // project it costs ~2-3s the first time. The topology-reset registry clears
216
- // this memo at session start, so each session re-derives its answer. The memo
217
- // remains valid until the next session-start reset.
218
- const startupScanContextCache = new BoundedLruCache(32);
219
- registerWorkspaceTopologyReset(() => startupScanContextCache.clear());
220
- function startupScanCacheKey(cwd, options) {
221
- return [
222
- normalizeMapKey(path.resolve(cwd)),
223
- options.homeDir ? normalizeMapKey(path.resolve(options.homeDir)) : "",
224
- options.maxSourceFiles ?? "",
225
- options.maxScanEntries ?? "",
226
- ].join("|");
227
- }
228
- export const __testing = { startupScanCacheKey };
229
- export function resolveStartupScanContext(cwd, options = {}) {
230
- const cacheKey = startupScanCacheKey(cwd, options);
231
- const cached = startupScanContextCache.get(cacheKey);
232
- if (cached)
233
- return cached;
234
- const result = {
235
- ...computeStartupScanContext(cwd, options),
236
- computedAt: Date.now(),
237
- };
238
- startupScanContextCache.set(cacheKey, result);
239
- return result;
240
- }
241
- function computeStartupScanContext(cwd, options = {}) {
242
- const resolvedCwd = path.resolve(cwd);
243
- const homeDir = path.resolve(options.homeDir ?? os.homedir());
244
- const maxSourceFiles = options.maxSourceFiles ?? getStartupScanMaxSourceFilesDerived(resolvedCwd);
245
- const maxScanEntries = options.maxScanEntries ?? getStartupScanMaxEntries();
246
- const projectRoot = findNearestProjectRoot(resolvedCwd);
247
- if (!projectRoot) {
248
- return {
249
- cwd: resolvedCwd,
250
- scanRoot: resolvedCwd,
251
- projectRoot: null,
252
- canWarmCaches: false,
253
- reason: isAtOrAboveHomeDir(resolvedCwd, homeDir)
254
- ? "home-dir"
255
- : "no-project-root",
256
- };
257
- }
258
- // A marker resolved at $HOME — OR at an ancestor of it (e.g. /home,
259
- // C:\Users) — means the upward search escaped the workspace; warming caches
260
- // would walk an unrelated tree (#250/#253). The old exact `=== homeDir`
261
- // check missed the above-home case.
262
- if (isAtOrAboveHomeDir(projectRoot, homeDir)) {
263
- return {
264
- cwd: resolvedCwd,
265
- scanRoot: projectRoot,
266
- projectRoot,
267
- canWarmCaches: false,
268
- reason: "home-dir",
269
- };
270
- }
271
- const { count: sourceFileCount, entryBudgetExceeded } = walkSourceCount(projectRoot, maxSourceFiles, maxScanEntries);
272
- if (sourceFileCount > maxSourceFiles || entryBudgetExceeded) {
273
- return {
274
- cwd: resolvedCwd,
275
- scanRoot: projectRoot,
276
- projectRoot,
277
- canWarmCaches: false,
278
- reason: entryBudgetExceeded
279
- ? "too-many-entries"
280
- : "too-many-source-files",
281
- sourceFileCount,
282
- };
283
- }
284
- return {
285
- cwd: resolvedCwd,
286
- scanRoot: projectRoot,
287
- projectRoot,
288
- canWarmCaches: true,
289
- sourceFileCount,
290
- };
291
- }
292
- // ---------------------------------------------------------------------------
293
- // Async, chunked-yield counterparts used by the cold-start warmup pipeline
294
- // (see runtime-session.ts handleSessionStart). The synchronous variants above
295
- // block the Node event loop for the full duration of the project walk, which
296
- // is fine when called from a non-interactive code path but freezes the TUI
297
- // when called during `session_start`. These async variants do the same work
298
- // but yield control via `await new Promise(setImmediate)` every N directory
299
- // entries, so stdin handlers (i.e. keystrokes) stay responsive.
300
- //
301
- // They share the same memo (`startupScanContextCache`) as their sync siblings,
302
- // so whichever runs first warms the cache for the other. By design the
303
- // warmup pipeline runs the async version 2s after a cold-start "quick" return,
304
- // then the user's first /new sees a sync-path cache hit and skips the work
305
- // entirely.
306
- // ---------------------------------------------------------------------------
307
- /**
308
- * Async core of the source-count walk (the yield-cadence twin of
309
- * `walkSourceCount`). Same visitor and two bounds — `limit` (source files) and
310
- * `maxEntries` (total entries, #758) — driven through the shared
311
- * {@link walkTreeStackAsync} engine (#761), which yields via `setImmediate`
312
- * every `yieldEvery` entries to keep `session_start` keystrokes responsive.
313
- */
314
- async function walkSourceCountAsync(dir, limit, maxEntries, opts = {}) {
315
- const state = {
316
- count: 0,
317
- visited: 0,
318
- entryBudgetExceeded: false,
319
- };
320
- const rootDir = path.resolve(dir);
321
- const ignoreMatcher = getProjectIgnoreMatcher(rootDir);
322
- await walkTreeStackAsync(rootDir, makeSourceCountVisitor(state, ignoreMatcher, limit, maxEntries), {
323
- // Yield every 100 entries by default. Empirically each yield costs
324
- // ~0.1ms of overhead and a 2k-file project produces ~20 yields, so the
325
- // total async overhead is well under 5ms while keeping per-burst sync
326
- // work under 50ms (the perceptual threshold for "instant" keystrokes).
327
- budgetMs: opts.budgetMs ?? 8,
328
- // #703: prime the tracked-files set ONCE before the walk (not per file)
329
- // so a tracked file matching a `.gitignore`/global pattern isn't dropped
330
- // from the startup source-file count. Fail-open: resolves even when git
331
- // is absent, and `isIgnored` degrades to pattern-only if this never
332
- // resolves before a caller inspects results.
333
- beforeWalk: () => ignoreMatcher.ensureTrackedIndex(),
334
- });
335
- return { count: state.count, entryBudgetExceeded: state.entryBudgetExceeded };
336
- }
337
- export async function countSourceFilesWithinLimitAsync(dir, limit, opts = {}) {
338
- // Public wrapper keeps its pre-#758 contract: only the source-file limit
339
- // bounds it (no entry ceiling).
340
- return (await walkSourceCountAsync(dir, limit, Number.POSITIVE_INFINITY, opts)).count;
341
- }
342
- export async function resolveStartupScanContextAsync(cwd, options = {}) {
343
- const cacheKey = startupScanCacheKey(cwd, options);
344
- const cached = startupScanContextCache.get(cacheKey);
345
- if (cached)
346
- return cached;
347
- const resolvedCwd = path.resolve(cwd);
348
- const homeDir = path.resolve(options.homeDir ?? os.homedir());
349
- const maxSourceFiles = options.maxSourceFiles ?? getStartupScanMaxSourceFilesDerived(resolvedCwd);
350
- const maxScanEntries = options.maxScanEntries ?? getStartupScanMaxEntries();
351
- const projectRoot = findNearestProjectRoot(resolvedCwd);
352
- let result;
353
- if (!projectRoot) {
354
- result = {
355
- cwd: resolvedCwd,
356
- scanRoot: resolvedCwd,
357
- projectRoot: null,
358
- canWarmCaches: false,
359
- reason: isAtOrAboveHomeDir(resolvedCwd, homeDir)
360
- ? "home-dir"
361
- : "no-project-root",
362
- };
363
- }
364
- else if (isAtOrAboveHomeDir(projectRoot, homeDir)) {
365
- result = {
366
- cwd: resolvedCwd,
367
- scanRoot: projectRoot,
368
- projectRoot,
369
- canWarmCaches: false,
370
- reason: "home-dir",
371
- };
372
- }
373
- else {
374
- const { count: sourceFileCount, entryBudgetExceeded } = await walkSourceCountAsync(projectRoot, maxSourceFiles, maxScanEntries);
375
- if (sourceFileCount > maxSourceFiles || entryBudgetExceeded) {
376
- result = {
377
- cwd: resolvedCwd,
378
- scanRoot: projectRoot,
379
- projectRoot,
380
- canWarmCaches: false,
381
- reason: entryBudgetExceeded
382
- ? "too-many-entries"
383
- : "too-many-source-files",
384
- sourceFileCount,
385
- };
386
- }
387
- else {
388
- result = {
389
- cwd: resolvedCwd,
390
- scanRoot: projectRoot,
391
- projectRoot,
392
- canWarmCaches: true,
393
- sourceFileCount,
394
- };
395
- }
396
- }
397
- result = { ...result, computedAt: Date.now() };
398
- startupScanContextCache.set(cacheKey, result);
399
- return result;
400
- }
@@ -1,130 +0,0 @@
1
- import { performance } from "node:perf_hooks";
2
- // #1434 S3d: import the constant from the side-effect-free module, not from
3
- // `console-guard-install.ts` — that module installs the console guard as an
4
- // import side effect, so importing it here (for a single constant, from a
5
- // module measuring load time) would have silently installed the guard
6
- // wherever this file is imported, including test-only measurement code that
7
- // has no business flipping a global switch.
8
- import { PI_LENS_EVAL_STARTED_MS } from "./eval-timestamp.js";
9
- import { getProcessSingleton, nextModuleEvaluationOrdinal, } from "./process-singletons.js";
10
- /**
11
- * Startup timing for pi-lens.
12
- *
13
- * `performance.now()` is measured relative to `performance.timeOrigin`, which
14
- * is the moment the host pi process started. Capturing it the instant pi-lens
15
- * has finished loading therefore yields the wall-clock cost of pi loading +
16
- * (under source mode) jiti-transpiling every pi-lens module before any of our
17
- * code runs. With the precompiled `dist/` (#182) that transpile cost is gone,
18
- * so this number is how we verify the startup win instead of guessing at it.
19
- */
20
- /** "dist" when pi-lens loaded from compiled JS, "source" when jiti-transpiled. */
21
- export const PI_LENS_LOADED_FROM = import.meta.url.endsWith(".js")
22
- ? "dist"
23
- : "source";
24
- // `loadMs`/`loadedAtMs` deliberately stay at module scope: they measure THIS
25
- // evaluation's own load cost, so a second evaluation must get its own numbers
26
- // rather than adopt the first's (#2146 class sweep — per-evaluation by design).
27
- let loadMs;
28
- let loadedAtMs;
29
- /**
30
- * The host-ready anchor is a once-PER-PROCESS latch, so it lives on the shared
31
- * process singleton (#2146). Left at module scope it was consumed once per
32
- * module evaluation, which meant a nine-evaluation process could emit the
33
- * "first session" host-ready delay nine times.
34
- */
35
- const HOST_READY_ANCHOR_FAMILY = "startup-timing.host-ready-anchor";
36
- const HOST_READY_ANCHOR_VERSION = 1;
37
- function hostReadyAnchorState() {
38
- return getProcessSingleton(HOST_READY_ANCHOR_FAMILY, HOST_READY_ANCHOR_VERSION, () => ({ consumed: false }));
39
- }
40
- /**
41
- * 1-based count of pi-lens module-graph evaluations in this process (#2146).
42
- *
43
- * Captured at module scope so it advances exactly once per evaluation, and
44
- * carried on `host_boot.metadata.evaluationOrdinal` so multi-evaluation hosts
45
- * are greppable in `latency.log`.
46
- */
47
- export const PI_LENS_EVALUATION_ORDINAL = nextModuleEvaluationOrdinal();
48
- /**
49
- * Record the load-complete time. Call once, as the first statement in the
50
- * extension entry's module body — by then every import has been evaluated, so
51
- * the full transpile/load cost has been paid. Idempotent: later calls return
52
- * the first captured value.
53
- */
54
- export function markPiLensLoaded() {
55
- if (loadMs === undefined) {
56
- loadedAtMs = performance.now();
57
- loadMs = Math.round(loadedAtMs);
58
- }
59
- return loadMs;
60
- }
61
- /** Monotonic instant when pi-lens finished loading, for cross-hook spans. */
62
- export function getPiLensLoadedAtMs() {
63
- return loadedAtMs;
64
- }
65
- /** Consume the process-lifetime first-session host-ready anchor exactly once. */
66
- export function consumeHostReadyDelayAnchor() {
67
- const state = hostReadyAnchorState();
68
- if (state.consumed)
69
- return false;
70
- state.consumed = true;
71
- return true;
72
- }
73
- /** Test seam for the process-lifetime session-state registry probe boundary. */
74
- export function resetHostReadyDelayAnchorForTests() {
75
- hostReadyAnchorState().consumed = false;
76
- }
77
- /** ms from pi process start to pi-lens load-complete, or undefined if unmarked. */
78
- export function getPiLensLoadMs() {
79
- return loadMs;
80
- }
81
- /** ms from host process start until pi-lens evaluation began. */
82
- export const PI_LENS_HOST_BOOT_MS = Math.round(PI_LENS_EVAL_STARTED_MS);
83
- /** pi-lens module-graph evaluation time once markPiLensLoaded() has run. */
84
- export function getPiLensEvalMs() {
85
- return loadMs === undefined
86
- ? undefined
87
- : Math.max(0, loadMs - PI_LENS_HOST_BOOT_MS);
88
- }
89
- /**
90
- * Build the three startup latency records the extension entry emits at module
91
- * scope (`extension_loaded`, `host_boot`, `extension_eval`).
92
- *
93
- * A builder rather than three inline `logLatency` calls in `index.ts` so the
94
- * record CONTENT is testable: `logLatency` is a no-op under `PI_LENS_TEST_MODE`,
95
- * and `index.ts`'s module body cannot be re-run per assertion. `index.ts` maps
96
- * the returned records straight into `logLatency`, so this is the production
97
- * shape, not a parallel path.
98
- *
99
- * `host_boot` carries `evaluationOrdinal` (#2146): one `host_boot` line is one
100
- * module-graph evaluation, and the ordinal makes a multi-evaluation host
101
- * greppable instead of inferable by counting lines per pid.
102
- */
103
- export function buildStartupTimingRecords(input) {
104
- return [
105
- {
106
- type: "phase",
107
- filePath: "<pi-lens>",
108
- phase: "extension_loaded",
109
- durationMs: input.loadMs,
110
- metadata: { loadedFrom: PI_LENS_LOADED_FROM },
111
- },
112
- {
113
- type: "phase",
114
- filePath: "<pi-lens>",
115
- phase: "host_boot",
116
- durationMs: PI_LENS_HOST_BOOT_MS,
117
- metadata: {
118
- loadedFrom: PI_LENS_LOADED_FROM,
119
- evaluationOrdinal: PI_LENS_EVALUATION_ORDINAL,
120
- },
121
- },
122
- {
123
- type: "phase",
124
- filePath: "<pi-lens>",
125
- phase: "extension_eval",
126
- durationMs: input.evalMs,
127
- metadata: { loadedFrom: PI_LENS_LOADED_FROM },
128
- },
129
- ];
130
- }
@@ -1,33 +0,0 @@
1
- /**
2
- * Ordinal (code-unit) string comparator for identity-feeding sorts — cache
3
- * keys, dedupe keys, hashes, and signatures. Refs #2155, #2165.
4
- *
5
- * `localeCompare` orders strings by locale-dependent collation (the DEFAULT
6
- * `Array.prototype.sort`, with no comparator, does not — it compares UTF-16
7
- * code units, which is already ordinal). Locale-dependent order is fine for
8
- * a list a human reads. It is a bug (SonarCloud S2871) when the sorted
9
- * result feeds an identity: two processes — or one process whose locale
10
- * changes — can order the same input differently under `localeCompare` and
11
- * mint different keys for equivalent state, producing a silent cache or
12
- * dedupe miss.
13
- *
14
- * Use this comparator whenever a sort's output becomes a key, a hash input,
15
- * or a signature compared for equality later. Keep `localeCompare` for
16
- * sorting that only affects what a person reads.
17
- */
18
- export function compareOrdinal(a, b) {
19
- return a < b ? -1 : a > b ? 1 : 0;
20
- }
21
- /**
22
- * Escape a string for safe interpolation into a `RegExp` source, so every
23
- * regex metacharacter it contains is matched literally instead of taking on
24
- * its regex meaning. This is the ONE runtime copy (#2558) — string-utils.ts
25
- * is a leaf (no imports of its own), so importing it never creates a cycle.
26
- * Before #2558 this same body was hand-copied under this name (and as
27
- * `escapeRegExpChar`/`escapeRegExpLiteral`) into ~8 production modules and 3
28
- * test helpers; fold new call sites onto this export instead of re-copying
29
- * it.
30
- */
31
- export function escapeRegExp(value) {
32
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
33
- }
@@ -1,111 +0,0 @@
1
- /**
2
- * Subagent light mode (#449 slice 0; broadened #507).
3
- *
4
- * Two known subagent-spawning ecosystems set different env vocabularies in
5
- * every spawned child's environment:
6
- *
7
- * - nicobailon/pi-subagents sets `PI_SUBAGENT_CHILD=1` unconditionally on
8
- * every process that hosts a child session — the only var light mode keys
9
- * on for this vocabulary. It ALSO used to set `PI_SUBAGENT_RUN_ID` /
10
- * `PI_SUBAGENT_CHILD_AGENT` alongside it for best-effort identity, but
11
- * removed both entirely in `pi-subagents@0.65.0`'s native-AgentSession
12
- * rewrite (grep-verified absent from the whole 0.66.0 source tree, #2581/
13
- * #2680) — child identity now travels through an in-process object, not
14
- * env vars. `getSubagentIdentity()` below already treats identity as
15
- * optional best-effort metadata, so this permanent absence for the
16
- * nicobailon vocabulary needed no behavior change, only the doc update.
17
- * - avtc-pi-subagent (the spawn engine under avtc-pi-feature-flow) is the same
18
- * execution model — real child-process `pi --mode rpc` / `--mode json -p`
19
- * spawns, full env inheritance — but never sets `PI_SUBAGENT_CHILD`. It sets
20
- * `PI_SUBAGENT_CHILD_AGENT` + `PI_SUBAGENT_PARENT_PID` instead (#507,
21
- * grep-verified against avtc-pi-subagent@1.0.3).
22
- *
23
- * Every child currently loads pi-lens fully by default, so a fan-out of N
24
- * subagents pays N full LSP pre-warms + N sets of heavyweight startup scans
25
- * in the same cwd — mostly wasted on short-lived task agents.
26
- *
27
- * Detection requires the avtc PAIR (`PI_SUBAGENT_CHILD_AGENT` AND
28
- * `PI_SUBAGENT_PARENT_PID`, both non-empty) rather than either var alone —
29
- * deliberate false-positive protection, since a lone var set by some
30
- * unrelated tool must not trigger light mode.
31
- *
32
- * This module only classifies the session; it does not change any behavior
33
- * itself. Callers (`runtime-session.ts`) gate the LSP pre-warm and the seven
34
- * heavyweight external-CLI startup scans on `isSubagentSession()`. Per-edit
35
- * LSP dispatch is untouched — light mode must not disable diagnostics.
36
- *
37
- * Escape hatch: `PI_LENS_SUBAGENT_FULL=1` forces full (non-light) behavior
38
- * even inside a detected subagent session, for either vocabulary.
39
- *
40
- * Follows the lazy-memoized-config house style (see `runtime-config.ts` /
41
- * `slow-fs.ts`): env values are read lazily at call time, not module load.
42
- */
43
- /** Lazily computed once per process (until `_resetSubagentModeForTests`),
44
- * matching the memoized-getter house style. */
45
- let cachedClassification;
46
- function classifySubagentSession() {
47
- if (cachedClassification !== undefined)
48
- return cachedClassification;
49
- if (process.env.PI_SUBAGENT_CHILD === "1") {
50
- cachedClassification = { isSubagent: true, marker: "pi-subagents" };
51
- return cachedClassification;
52
- }
53
- const childAgent = process.env.PI_SUBAGENT_CHILD_AGENT || undefined;
54
- const parentPid = process.env.PI_SUBAGENT_PARENT_PID || undefined;
55
- if (childAgent !== undefined && parentPid !== undefined) {
56
- cachedClassification = { isSubagent: true, marker: "avtc-pi-subagent" };
57
- return cachedClassification;
58
- }
59
- cachedClassification = { isSubagent: false };
60
- return cachedClassification;
61
- }
62
- /** True iff pi-lens is running inside a detected subagent child `pi` process
63
- * (nicobailon/pi-subagents' `PI_SUBAGENT_CHILD=1`, or avtc-pi-subagent's
64
- * `PI_SUBAGENT_CHILD_AGENT` + `PI_SUBAGENT_PARENT_PID` pair), and the caller
65
- * has not forced full behavior via the escape hatch. */
66
- export function isSubagentSession() {
67
- if (process.env.PI_LENS_SUBAGENT_FULL === "1")
68
- return false;
69
- return classifySubagentSession().isSubagent;
70
- }
71
- /**
72
- * Best-effort identity of the current subagent, read from the env vars the
73
- * detected extension sets alongside its subagent marker. Returns `undefined`
74
- * when neither identity var is present — not a subagent session, an
75
- * extension that never set them, OR nicobailon/pi-subagents@0.65.0+, which
76
- * removed both identity vars upstream while still setting `PI_SUBAGENT_CHILD`
77
- * (#2581/#2680): light mode still engages via `isSubagentSession()` alone,
78
- * `marker` is still populated, only `runId`/`agentName` degrade to
79
- * `undefined`. Identity is metadata for observability, never a light-mode
80
- * gate — callers must not treat its absence as "not a subagent".
81
- */
82
- export function getSubagentIdentity() {
83
- const runId = process.env.PI_SUBAGENT_RUN_ID || undefined;
84
- const agentName = process.env.PI_SUBAGENT_CHILD_AGENT || undefined;
85
- const parentPidRaw = process.env.PI_SUBAGENT_PARENT_PID || undefined;
86
- const parsedParentPid = parentPidRaw === undefined ? undefined : Number(parentPidRaw);
87
- const parentPid = parsedParentPid !== undefined &&
88
- Number.isSafeInteger(parsedParentPid) &&
89
- parsedParentPid > 0
90
- ? parsedParentPid
91
- : undefined;
92
- const classification = classifySubagentSession();
93
- if (runId === undefined &&
94
- agentName === undefined &&
95
- parentPid === undefined &&
96
- !classification.isSubagent) {
97
- return undefined;
98
- }
99
- return { runId, agentName, marker: classification.marker, parentPid };
100
- }
101
- /** Human-readable degradation notice surfaced once per session when subagent
102
- * light mode engages, so a subagent never sees a silently-empty scan result. */
103
- export function subagentLightModeNotice() {
104
- return "subagent session — skipped background code-quality scans (set PI_LENS_SUBAGENT_FULL=1 to override)";
105
- }
106
- /** Test-only: clears the memoized classification so tests can flip env vars
107
- * between cases (matching the `_resetForTests` convention used by
108
- * `runtime-config.ts` / `slow-fs.ts`). */
109
- export function _resetSubagentModeForTests() {
110
- cachedClassification = undefined;
111
- }