pi-lens 4.2.1 → 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 (671) hide show
  1. package/CHANGELOG.md +1562 -0
  2. package/README.md +157 -24
  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 +19039 -8956
  125. package/dist/mcp/analyze-cli.js +186 -228
  126. package/dist/mcp/cli.js +137 -98
  127. package/dist/mcp/server.js +22592 -1564
  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/adr/0001-stale-advisory-live-arm.md +29 -0
  133. package/docs/adr/0002-workspace-hash-rendezvous.md +30 -0
  134. package/docs/adr/0003-git-guard-latch-writer.md +203 -0
  135. package/docs/adr/0004-disposition-policy-seam.md +38 -0
  136. package/docs/adr/0005-tool-availability-enforcement-seam.md +29 -0
  137. package/docs/adr/0006-derived-state-benchmark-first.md +31 -0
  138. package/docs/adr/0007-end-to-end-witness-per-seam-slice.md +38 -0
  139. package/docs/adr/0008-turn-end-lane-interface.md +165 -0
  140. package/docs/adr/0009-reported-path-attribution.md +114 -0
  141. package/docs/adr/README.md +26 -0
  142. package/docs/agent-guide.md +13 -4
  143. package/docs/agent-tools.md +60 -1
  144. package/docs/ast-grep_rules_catalog.md +6 -4
  145. package/docs/configuration.md +75 -2
  146. package/docs/engineering-principles.md +202 -0
  147. package/docs/environment-variables.md +113 -6
  148. package/docs/features.md +10 -6
  149. package/docs/globalconfig.md +7 -1
  150. package/docs/io-bridge-v2-migration.md +94 -0
  151. package/docs/language-coverage.md +17 -0
  152. package/docs/lsp-capability-matrix.md +131 -32
  153. package/docs/lsp-idle-eviction.md +124 -0
  154. package/docs/mcp.md +21 -5
  155. package/docs/merge-queue-rollout.md +77 -0
  156. package/docs/pi-lens-fixer.md +161 -39
  157. package/docs/pi-lens-investigator.md +77 -20
  158. package/docs/pi-lens-merge-policy.md +694 -0
  159. package/docs/pi-lens-monitor.md +73 -7
  160. package/docs/pi-lens-retro.md +6 -4
  161. package/docs/pi-lens-reviewer.md +190 -34
  162. package/docs/pi-lens-subagent.md +247 -37
  163. package/docs/pi-lens-warden.md +18 -7
  164. package/docs/public-api-stability.md +56 -0
  165. package/docs/release-qa-baseline.md +86 -17
  166. package/docs/rfcs/3654-unified-io-bridge-v2.md +316 -0
  167. package/docs/servercapabilities.md +66 -52
  168. package/docs/settings.md +13 -3
  169. package/docs/subagent-compat.md +1 -1
  170. package/docs/usage.md +5 -1
  171. package/grammars/tree-sitter-bash.wasm +0 -0
  172. package/grammars/tree-sitter-bash.wasm.json +3 -3
  173. package/package.json +23 -9
  174. package/rules/ast-grep-rules/rule-tests/advisory-registry-subset-test.yml +41 -0
  175. package/rules/ast-grep-rules/rule-tests/no-assert-tuple-test.yml +13 -0
  176. package/rules/ast-grep-rules/rule-tests/no-boolean-in-except-test.yml +26 -0
  177. package/rules/ast-grep-rules/rule-tests/no-http-headers-bracket-access-test.yml +10 -0
  178. package/rules/ast-grep-rules/rule-tests/unchecked-numeric-parse-python-test.yml +18 -0
  179. package/rules/ast-grep-rules/rule-tests/unchecked-throwing-call-python-test.yml +4 -3
  180. package/rules/ast-grep-rules/rules/advisory-registry-subset.yml +50 -0
  181. package/rules/ast-grep-rules/rules/go-no-fmt-println.yml +2 -2
  182. package/rules/ast-grep-rules/rules/no-assert-tuple.yml +23 -13
  183. package/rules/ast-grep-rules/rules/no-boolean-in-except.yml +7 -3
  184. package/rules/ast-grep-rules/rules/no-console-except-error-js.yml +2 -2
  185. package/rules/ast-grep-rules/rules/no-console-except-error.yml +2 -2
  186. package/rules/ast-grep-rules/rules/no-http-headers-bracket-access.yml +12 -7
  187. package/rules/ast-grep-rules/rules/unchecked-numeric-parse-python.yml +44 -0
  188. package/rules/ast-grep-rules/rules/unchecked-throwing-call-python.yml +5 -3
  189. package/rules/tree-sitter-queries/typescript/console-statement.yml +2 -2
  190. package/scripts/analyze-pi-lens-logs.mjs +1275 -62
  191. package/scripts/download-grammars.js +5 -0
  192. package/scripts/grammars.lock.json +6 -1
  193. package/scripts/install-selftest.mjs +38 -35
  194. package/scripts/lib/host-provided-deps.mjs +13 -4
  195. package/scripts/lib/web-tree-sitter-dir.mjs +141 -0
  196. package/dist/clients/actionable-warnings-logger.js +0 -35
  197. package/dist/clients/actionable-warnings.js +0 -1594
  198. package/dist/clients/advisory-provenance.js +0 -457
  199. package/dist/clients/agent-behavior-client.js +0 -147
  200. package/dist/clients/agent-nudge.js +0 -325
  201. package/dist/clients/analysed-root.js +0 -1
  202. package/dist/clients/ast-grep-client.js +0 -731
  203. package/dist/clients/ast-grep-rule-manager.js +0 -146
  204. package/dist/clients/ast-grep-tool-logger.js +0 -118
  205. package/dist/clients/ast-grep-types.js +0 -10
  206. package/dist/clients/ast-grep-yaml-synth.js +0 -154
  207. package/dist/clients/atomic-write-staging.js +0 -75
  208. package/dist/clients/atomic-write.js +0 -189
  209. package/dist/clients/availability-probe-flight.js +0 -12
  210. package/dist/clients/bash-file-access.js +0 -1056
  211. package/dist/clients/biome-client.js +0 -357
  212. package/dist/clients/blocker-freshness.js +0 -837
  213. package/dist/clients/blocker-past-eof.js +0 -129
  214. package/dist/clients/bootstrap.js +0 -569
  215. package/dist/clients/bounded-cache.js +0 -190
  216. package/dist/clients/bounded-pid-file-lock.js +0 -202
  217. package/dist/clients/bounded-telemetry.js +0 -295
  218. package/dist/clients/build-identity.js +0 -95
  219. package/dist/clients/bundled-resource-health.js +0 -113
  220. package/dist/clients/bus-events-logger.js +0 -105
  221. package/dist/clients/bus-publish.js +0 -171
  222. package/dist/clients/cache/rule-cache.js +0 -190
  223. package/dist/clients/cache-manager.js +0 -465
  224. package/dist/clients/cache-observability.js +0 -1313
  225. package/dist/clients/call-graph.js +0 -852
  226. package/dist/clients/cargo-manifest.js +0 -422
  227. package/dist/clients/cascade-budget.js +0 -196
  228. package/dist/clients/cascade-format.js +0 -315
  229. package/dist/clients/cascade-logger.js +0 -31
  230. package/dist/clients/cascade-types.js +0 -9
  231. package/dist/clients/child-unref.js +0 -115
  232. package/dist/clients/code-quality-warnings.js +0 -286
  233. package/dist/clients/codebase-model.js +0 -173
  234. package/dist/clients/collateral-test-role.js +0 -40
  235. package/dist/clients/complexity-client.js +0 -462
  236. package/dist/clients/config-core/deny.js +0 -221
  237. package/dist/clients/config-core/index.js +0 -50
  238. package/dist/clients/config-core/merge.js +0 -357
  239. package/dist/clients/config-core/normalize.js +0 -340
  240. package/dist/clients/config-core/process-spec.js +0 -248
  241. package/dist/clients/config-core/provenance.js +0 -164
  242. package/dist/clients/config-core/records.js +0 -218
  243. package/dist/clients/config-core/resolve.js +0 -125
  244. package/dist/clients/config-core/safe-object.js +0 -78
  245. package/dist/clients/config-core/schema.js +0 -165
  246. package/dist/clients/config-diagnostic-codes.js +0 -283
  247. package/dist/clients/config-locations.js +0 -160
  248. package/dist/clients/config-resolve.js +0 -792
  249. package/dist/clients/config-schema.js +0 -251
  250. package/dist/clients/config-warn.js +0 -407
  251. package/dist/clients/console-guard-install.js +0 -26
  252. package/dist/clients/cooperative-budget.js +0 -42
  253. package/dist/clients/dead-code-client.js +0 -510
  254. package/dist/clients/dead-code-logger.js +0 -30
  255. package/dist/clients/deadline-utils.js +0 -280
  256. package/dist/clients/debug-handles.js +0 -211
  257. package/dist/clients/debug-heap.js +0 -174
  258. package/dist/clients/deferred-lsp-work.js +0 -106
  259. package/dist/clients/degradation-ledger.js +0 -396
  260. package/dist/clients/demoted-finding-render.js +0 -169
  261. package/dist/clients/dependency-checker.js +0 -862
  262. package/dist/clients/deps/ast-grep-napi.js +0 -22
  263. package/dist/clients/deps/js-yaml.js +0 -9
  264. package/dist/clients/deps/minimatch.js +0 -4
  265. package/dist/clients/deps/pi-tui.js +0 -14
  266. package/dist/clients/deps/typebox.js +0 -14
  267. package/dist/clients/deps/vscode-jsonrpc.js +0 -1
  268. package/dist/clients/deps/web-tree-sitter.js +0 -24
  269. package/dist/clients/diagnostic-dispositions.js +0 -594
  270. package/dist/clients/diagnostic-line-freshness.js +0 -305
  271. package/dist/clients/diagnostic-logger.js +0 -73
  272. package/dist/clients/diagnostic-tracker.js +0 -105
  273. package/dist/clients/diagnostics-publish.js +0 -230
  274. package/dist/clients/dispatch/ast-grep-catalog.js +0 -65
  275. package/dist/clients/dispatch/auxiliary-lsp.js +0 -343
  276. package/dist/clients/dispatch/collect-later-tier.js +0 -35
  277. package/dist/clients/dispatch/diagnostic-taxonomy.js +0 -66
  278. package/dist/clients/dispatch/dispatcher.js +0 -1269
  279. package/dist/clients/dispatch/fact-provider-types.js +0 -1
  280. package/dist/clients/dispatch/fact-rule-runner.js +0 -17
  281. package/dist/clients/dispatch/fact-runner.js +0 -30
  282. package/dist/clients/dispatch/fact-scheduler.js +0 -68
  283. package/dist/clients/dispatch/fact-store.js +0 -377
  284. package/dist/clients/dispatch/facts/comment-facts.js +0 -22
  285. package/dist/clients/dispatch/facts/file-content.js +0 -19
  286. package/dist/clients/dispatch/facts/function-facts.js +0 -348
  287. package/dist/clients/dispatch/facts/import-facts.js +0 -204
  288. package/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -34
  289. package/dist/clients/dispatch/facts/try-catch-facts.js +0 -119
  290. package/dist/clients/dispatch/finding-policy.js +0 -222
  291. package/dist/clients/dispatch/indent-detect.js +0 -411
  292. package/dist/clients/dispatch/inline-suppressions.js +0 -70
  293. package/dist/clients/dispatch/integration.js +0 -2377
  294. package/dist/clients/dispatch/lazy.js +0 -11
  295. package/dist/clients/dispatch/pending-runner-findings.js +0 -87
  296. package/dist/clients/dispatch/plan.js +0 -278
  297. package/dist/clients/dispatch/priorities.js +0 -20
  298. package/dist/clients/dispatch/rule-id-normalize.js +0 -50
  299. package/dist/clients/dispatch/rule-ignores.js +0 -62
  300. package/dist/clients/dispatch/rule-policy.js +0 -135
  301. package/dist/clients/dispatch/rules/async-noise.js +0 -40
  302. package/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
  303. package/dist/clients/dispatch/rules/cors-wildcard.js +0 -54
  304. package/dist/clients/dispatch/rules/error-obscuring.js +0 -32
  305. package/dist/clients/dispatch/rules/error-swallowing.js +0 -31
  306. package/dist/clients/dispatch/rules/framework-call-noise.js +0 -67
  307. package/dist/clients/dispatch/rules/high-complexity.js +0 -72
  308. package/dist/clients/dispatch/rules/high-fan-out.js +0 -74
  309. package/dist/clients/dispatch/rules/high-import-coupling.js +0 -37
  310. package/dist/clients/dispatch/rules/missing-error-propagation.js +0 -62
  311. package/dist/clients/dispatch/rules/no-commented-credentials.js +0 -52
  312. package/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -42
  313. package/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
  314. package/dist/clients/dispatch/rules/unsafe-boundary.js +0 -126
  315. package/dist/clients/dispatch/runner-context.js +0 -52
  316. package/dist/clients/dispatch/runners/actionlint.js +0 -113
  317. package/dist/clients/dispatch/runners/ast-grep-napi.js +0 -1196
  318. package/dist/clients/dispatch/runners/biome-check.js +0 -283
  319. package/dist/clients/dispatch/runners/cpp-check.js +0 -236
  320. package/dist/clients/dispatch/runners/credo.js +0 -80
  321. package/dist/clients/dispatch/runners/cue-vet.js +0 -398
  322. package/dist/clients/dispatch/runners/dart-analyze.js +0 -202
  323. package/dist/clients/dispatch/runners/detekt.js +0 -169
  324. package/dist/clients/dispatch/runners/dotnet-build.js +0 -159
  325. package/dist/clients/dispatch/runners/elixir-check.js +0 -210
  326. package/dist/clients/dispatch/runners/eslint.js +0 -154
  327. package/dist/clients/dispatch/runners/fact-rules.js +0 -29
  328. package/dist/clients/dispatch/runners/fish-indent.js +0 -69
  329. package/dist/clients/dispatch/runners/gleam-check.js +0 -87
  330. package/dist/clients/dispatch/runners/go-vet.js +0 -90
  331. package/dist/clients/dispatch/runners/golangci-lint.js +0 -120
  332. package/dist/clients/dispatch/runners/hadolint.js +0 -79
  333. package/dist/clients/dispatch/runners/helm-lint.js +0 -171
  334. package/dist/clients/dispatch/runners/helm-render.js +0 -940
  335. package/dist/clients/dispatch/runners/htmlhint.js +0 -108
  336. package/dist/clients/dispatch/runners/index.js +0 -108
  337. package/dist/clients/dispatch/runners/javac.js +0 -89
  338. package/dist/clients/dispatch/runners/ktlint.js +0 -136
  339. package/dist/clients/dispatch/runners/lsp.js +0 -378
  340. package/dist/clients/dispatch/runners/markdownlint.js +0 -160
  341. package/dist/clients/dispatch/runners/mypy.js +0 -101
  342. package/dist/clients/dispatch/runners/oxlint.js +0 -398
  343. package/dist/clients/dispatch/runners/php-lint.js +0 -62
  344. package/dist/clients/dispatch/runners/phpstan.js +0 -120
  345. package/dist/clients/dispatch/runners/prisma-validate.js +0 -62
  346. package/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -445
  347. package/dist/clients/dispatch/runners/pyright.js +0 -169
  348. package/dist/clients/dispatch/runners/rubocop.js +0 -90
  349. package/dist/clients/dispatch/runners/ruff.js +0 -89
  350. package/dist/clients/dispatch/runners/rust-clippy.js +0 -251
  351. package/dist/clients/dispatch/runners/shellcheck.js +0 -169
  352. package/dist/clients/dispatch/runners/shfmt.js +0 -102
  353. package/dist/clients/dispatch/runners/spellcheck.js +0 -121
  354. package/dist/clients/dispatch/runners/spotbugs.js +0 -259
  355. package/dist/clients/dispatch/runners/sqlfluff.js +0 -174
  356. package/dist/clients/dispatch/runners/stylelint.js +0 -158
  357. package/dist/clients/dispatch/runners/swiftlint.js +0 -154
  358. package/dist/clients/dispatch/runners/taplo.js +0 -168
  359. package/dist/clients/dispatch/runners/terragrunt.js +0 -168
  360. package/dist/clients/dispatch/runners/tflint.js +0 -110
  361. package/dist/clients/dispatch/runners/tree-sitter.js +0 -620
  362. package/dist/clients/dispatch/runners/trivy-config.js +0 -247
  363. package/dist/clients/dispatch/runners/utils/availability-policy.js +0 -496
  364. package/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -90
  365. package/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -85
  366. package/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -274
  367. package/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1701
  368. package/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -101
  369. package/dist/clients/dispatch/runners/utils/tool-failure.js +0 -235
  370. package/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -169
  371. package/dist/clients/dispatch/runners/utils.js +0 -15
  372. package/dist/clients/dispatch/runners/vale.js +0 -116
  373. package/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -242
  374. package/dist/clients/dispatch/runners/yamllint.js +0 -85
  375. package/dist/clients/dispatch/runners/zig-check.js +0 -91
  376. package/dist/clients/dispatch/suppress-writer.js +0 -69
  377. package/dist/clients/dispatch/tool-profile.js +0 -30
  378. package/dist/clients/dispatch/types.js +0 -21
  379. package/dist/clients/dispatch/utils/format-utils.js +0 -45
  380. package/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -35
  381. package/dist/clients/disposition-logger.js +0 -32
  382. package/dist/clients/disposition-publish.js +0 -124
  383. package/dist/clients/durable-store.js +0 -97
  384. package/dist/clients/effective-config.js +0 -413
  385. package/dist/clients/env-utils.js +0 -83
  386. package/dist/clients/error-class.js +0 -23
  387. package/dist/clients/eval-timestamp.js +0 -17
  388. package/dist/clients/event-loop-hold.js +0 -274
  389. package/dist/clients/event-loop-monitor.js +0 -250
  390. package/dist/clients/extension-log.js +0 -504
  391. package/dist/clients/extension-mode.js +0 -73
  392. package/dist/clients/feature-hints.js +0 -103
  393. package/dist/clients/file-kinds.js +0 -412
  394. package/dist/clients/file-role.js +0 -134
  395. package/dist/clients/file-time.js +0 -160
  396. package/dist/clients/file-utils.js +0 -1032
  397. package/dist/clients/finding-delivery-gate.js +0 -463
  398. package/dist/clients/finding-identity.js +0 -88
  399. package/dist/clients/fix-worklog.js +0 -103
  400. package/dist/clients/format-events-publish.js +0 -343
  401. package/dist/clients/format-service.js +0 -222
  402. package/dist/clients/formatters-lazy.js +0 -9
  403. package/dist/clients/formatters.js +0 -1994
  404. package/dist/clients/freshness-cadence.js +0 -17
  405. package/dist/clients/freshness.js +0 -38
  406. package/dist/clients/generated-artifacts.js +0 -394
  407. package/dist/clients/generation-guard.js +0 -215
  408. package/dist/clients/git-guard.js +0 -923
  409. package/dist/clients/git-tracked-ignore.js +0 -243
  410. package/dist/clients/gitleaks-client.js +0 -509
  411. package/dist/clients/go-client.js +0 -104
  412. package/dist/clients/govulncheck-client.js +0 -605
  413. package/dist/clients/gradle-ktfmt-style.js +0 -252
  414. package/dist/clients/grammar-source.js +0 -465
  415. package/dist/clients/gzip-stage-write.js +0 -135
  416. package/dist/clients/hashline-anchor.js +0 -424
  417. package/dist/clients/hook-budgets.js +0 -76
  418. package/dist/clients/host-edit-normalize.js +0 -140
  419. package/dist/clients/host-ports.js +0 -39
  420. package/dist/clients/indent-retarget.js +0 -154
  421. package/dist/clients/install-diagnostics.js +0 -143
  422. package/dist/clients/installer/index.js +0 -5167
  423. package/dist/clients/installer/managed-tool-refresh-session.js +0 -58
  424. package/dist/clients/installer/managed-tool-refresh.js +0 -783
  425. package/dist/clients/instance-reaper-state.js +0 -7
  426. package/dist/clients/instance-reaper.js +0 -1137
  427. package/dist/clients/instance-registry-lock.js +0 -145
  428. package/dist/clients/instance-registry.js +0 -773
  429. package/dist/clients/jscpd-client.js +0 -370
  430. package/dist/clients/json-cache-read.js +0 -65
  431. package/dist/clients/knip-client.js +0 -788
  432. package/dist/clients/language-policy.js +0 -252
  433. package/dist/clients/language-profile.js +0 -361
  434. package/dist/clients/language-registry.js +0 -603
  435. package/dist/clients/latency-logger.js +0 -719
  436. package/dist/clients/lazy-import.js +0 -21
  437. package/dist/clients/ledger-bounds.js +0 -54
  438. package/dist/clients/lens-config.js +0 -346
  439. package/dist/clients/lens-engine.js +0 -358
  440. package/dist/clients/lens-events.js +0 -125
  441. package/dist/clients/lens-flag-registry.js +0 -467
  442. package/dist/clients/lens-map.js +0 -1156
  443. package/dist/clients/live-bus-emitter.js +0 -74
  444. package/dist/clients/log-cleanup.js +0 -222
  445. package/dist/clients/lsp/aggregation.js +0 -178
  446. package/dist/clients/lsp/cascade-tier.js +0 -421
  447. package/dist/clients/lsp/client.js +0 -4465
  448. package/dist/clients/lsp/config.js +0 -689
  449. package/dist/clients/lsp/diagnostic-binding.js +0 -225
  450. package/dist/clients/lsp/document-drift.js +0 -467
  451. package/dist/clients/lsp/edits.js +0 -1219
  452. package/dist/clients/lsp/index.js +0 -8305
  453. package/dist/clients/lsp/inferred-project.js +0 -216
  454. package/dist/clients/lsp/jvm-runtime.js +0 -298
  455. package/dist/clients/lsp/language.js +0 -63
  456. package/dist/clients/lsp/launch.js +0 -725
  457. package/dist/clients/lsp/lombok.js +0 -158
  458. package/dist/clients/lsp/path-utils.js +0 -5
  459. package/dist/clients/lsp/pending-aux-coverage.js +0 -251
  460. package/dist/clients/lsp/position-encoding.js +0 -61
  461. package/dist/clients/lsp/ruby-drive-dirs.js +0 -83
  462. package/dist/clients/lsp/server.js +0 -3209
  463. package/dist/clients/lsp/session-roots.js +0 -192
  464. package/dist/clients/lsp/spawn-history.js +0 -17
  465. package/dist/clients/lsp/sync-kind.js +0 -42
  466. package/dist/clients/lsp/tsserver-sync.js +0 -332
  467. package/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
  468. package/dist/clients/lsp/wait-policy/classification.js +0 -85
  469. package/dist/clients/lsp/wait-policy/index.js +0 -10
  470. package/dist/clients/lsp/wait-policy/strategies.js +0 -303
  471. package/dist/clients/lsp/watch-queue.js +0 -61
  472. package/dist/clients/lsp/workspace-diagnostics-cache.js +0 -639
  473. package/dist/clients/lsp/workspace-diagnostics-session.js +0 -30
  474. package/dist/clients/lsp/workspace-sweep-hold.js +0 -184
  475. package/dist/clients/lsp-budget.js +0 -186
  476. package/dist/clients/lsp-document-symbols.js +0 -110
  477. package/dist/clients/lsp-lazy.js +0 -9
  478. package/dist/clients/lsp-mutation.js +0 -396
  479. package/dist/clients/lsp-status.js +0 -59
  480. package/dist/clients/map-with-concurrency.js +0 -40
  481. package/dist/clients/mcp/analyze.js +0 -420
  482. package/dist/clients/mcp/host-shim.js +0 -31
  483. package/dist/clients/mcp/ipc.js +0 -335
  484. package/dist/clients/mcp/review.js +0 -151
  485. package/dist/clients/mcp/session.js +0 -412
  486. package/dist/clients/memory-sampler.js +0 -208
  487. package/dist/clients/message-end-attribution.js +0 -30
  488. package/dist/clients/metrics-client.js +0 -107
  489. package/dist/clients/metrics-history.js +0 -327
  490. package/dist/clients/middle-man-analysis.js +0 -263
  491. package/dist/clients/model-provider.js +0 -53
  492. package/dist/clients/module-report-lsp.js +0 -189
  493. package/dist/clients/module-report.js +0 -2150
  494. package/dist/clients/mutating-tool.js +0 -651
  495. package/dist/clients/mutation-attribution.js +0 -368
  496. package/dist/clients/mutation-bridge.js +0 -240
  497. package/dist/clients/ndjson-logger.js +0 -734
  498. package/dist/clients/observed-mutation-sources.js +0 -101
  499. package/dist/clients/observed-mutation.js +0 -1253
  500. package/dist/clients/oldtext-autopatch.js +0 -128
  501. package/dist/clients/opaque-mutation-scan.js +0 -496
  502. package/dist/clients/opengrep-client.js +0 -328
  503. package/dist/clients/opengrep-config.js +0 -76
  504. package/dist/clients/package-manager.js +0 -607
  505. package/dist/clients/package-root.js +0 -38
  506. package/dist/clients/partial-edit-apply.js +0 -439
  507. package/dist/clients/path-attribution-telemetry.js +0 -43
  508. package/dist/clients/path-keyed-map.js +0 -108
  509. package/dist/clients/path-utils.js +0 -1244
  510. package/dist/clients/performance-report.js +0 -331
  511. package/dist/clients/persist-debounce.js +0 -70
  512. package/dist/clients/persistent-reverify.js +0 -271
  513. package/dist/clients/php-cs-fixer-config.js +0 -119
  514. package/dist/clients/pipeline.js +0 -1425
  515. package/dist/clients/post-autofix-notice.js +0 -37
  516. package/dist/clients/print-mode.js +0 -21
  517. package/dist/clients/probe-home-state.js +0 -228
  518. package/dist/clients/process-bridge.js +0 -66
  519. package/dist/clients/process-singletons.js +0 -210
  520. package/dist/clients/process-snapshot.js +0 -68
  521. package/dist/clients/project-changes.js +0 -181
  522. package/dist/clients/project-conventions.js +0 -171
  523. package/dist/clients/project-diagnostics/cache.js +0 -137
  524. package/dist/clients/project-diagnostics/extractors.js +0 -109
  525. package/dist/clients/project-diagnostics/fresh-fetch.js +0 -650
  526. package/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -118
  527. package/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -47
  528. package/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -40
  529. package/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -34
  530. package/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -38
  531. package/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -47
  532. package/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -48
  533. package/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -40
  534. package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -127
  535. package/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -81
  536. package/dist/clients/project-diagnostics/scanner.js +0 -520
  537. package/dist/clients/project-diagnostics/types.js +0 -1
  538. package/dist/clients/project-lens-config.js +0 -799
  539. package/dist/clients/project-report.js +0 -701
  540. package/dist/clients/project-scale.js +0 -237
  541. package/dist/clients/project-scan-policy.js +0 -11
  542. package/dist/clients/project-snapshot-fingerprint.js +0 -48
  543. package/dist/clients/project-snapshot-persist-worker.js +0 -20
  544. package/dist/clients/project-snapshot.js +0 -1653
  545. package/dist/clients/project-trust.js +0 -181
  546. package/dist/clients/python-environment.js +0 -217
  547. package/dist/clients/python-provenance.js +0 -639
  548. package/dist/clients/quiet-window-config.js +0 -47
  549. package/dist/clients/quiet-window.js +0 -236
  550. package/dist/clients/read-bridge.js +0 -139
  551. package/dist/clients/read-expansion.js +0 -266
  552. package/dist/clients/read-guard-logger.js +0 -251
  553. package/dist/clients/read-guard-tool-lines.js +0 -1306
  554. package/dist/clients/read-guard.js +0 -1561
  555. package/dist/clients/recent-touches.js +0 -240
  556. package/dist/clients/redact/secrets.js +0 -449
  557. package/dist/clients/resource-sampler.js +0 -628
  558. package/dist/clients/reverse-deps.js +0 -270
  559. package/dist/clients/review-graph/builder.js +0 -5118
  560. package/dist/clients/review-graph/format.js +0 -33
  561. package/dist/clients/review-graph/git-identity.js +0 -157
  562. package/dist/clients/review-graph/import-resolvers.js +0 -481
  563. package/dist/clients/review-graph/persist-worker.js +0 -10
  564. package/dist/clients/review-graph/query.js +0 -244
  565. package/dist/clients/review-graph/revision-drift.js +0 -21
  566. package/dist/clients/review-graph/service.js +0 -96
  567. package/dist/clients/review-graph/shared-extraction-ir.js +0 -82
  568. package/dist/clients/review-graph/symbol-id.js +0 -103
  569. package/dist/clients/review-graph/tsconfig-paths.js +0 -299
  570. package/dist/clients/review-graph/types.js +0 -1
  571. package/dist/clients/review-graph/workspace-modules.js +0 -449
  572. package/dist/clients/review-graph-logger.js +0 -81
  573. package/dist/clients/ruff-client.js +0 -152
  574. package/dist/clients/rules-scanner.js +0 -131
  575. package/dist/clients/run-duration.js +0 -55
  576. package/dist/clients/runtime-agent-end.js +0 -746
  577. package/dist/clients/runtime-config.js +0 -77
  578. package/dist/clients/runtime-context.js +0 -211
  579. package/dist/clients/runtime-coordinator.js +0 -1290
  580. package/dist/clients/runtime-session.js +0 -2485
  581. package/dist/clients/runtime-tool-call.js +0 -1284
  582. package/dist/clients/runtime-tool-result.js +0 -2034
  583. package/dist/clients/runtime-turn.js +0 -3600
  584. package/dist/clients/rust-client.js +0 -97
  585. package/dist/clients/safe-spawn.js +0 -2166
  586. package/dist/clients/sanitize.js +0 -286
  587. package/dist/clients/scan-utils.js +0 -25
  588. package/dist/clients/scratch-tree-policy.js +0 -165
  589. package/dist/clients/search-read-registration.js +0 -94
  590. package/dist/clients/secret-findings.js +0 -114
  591. package/dist/clients/security-scan-client.js +0 -352
  592. package/dist/clients/session-event-guard.js +0 -297
  593. package/dist/clients/session-lifecycle.js +0 -484
  594. package/dist/clients/session-start-observability.js +0 -94
  595. package/dist/clients/session-state-store.js +0 -101
  596. package/dist/clients/session-summary.js +0 -15
  597. package/dist/clients/sessionstart-logger.js +0 -27
  598. package/dist/clients/sg-runner.js +0 -876
  599. package/dist/clients/sgconfig.js +0 -347
  600. package/dist/clients/shared-checkout-guard.js +0 -338
  601. package/dist/clients/single-flight.js +0 -158
  602. package/dist/clients/situational-tool-telemetry.js +0 -108
  603. package/dist/clients/skills-resolver.js +0 -141
  604. package/dist/clients/slow-fs.js +0 -138
  605. package/dist/clients/smells-rollup.js +0 -231
  606. package/dist/clients/source-filter.js +0 -596
  607. package/dist/clients/source-walker.js +0 -211
  608. package/dist/clients/spawn-output-cap.js +0 -37
  609. package/dist/clients/spawn-timeout-cooldown.js +0 -110
  610. package/dist/clients/stale-marker.js +0 -17
  611. package/dist/clients/startup-scan.js +0 -400
  612. package/dist/clients/startup-timing.js +0 -130
  613. package/dist/clients/string-utils.js +0 -33
  614. package/dist/clients/subagent-mode.js +0 -111
  615. package/dist/clients/symbol-containment.js +0 -24
  616. package/dist/clients/symbol-types.js +0 -5
  617. package/dist/clients/test-runner-client.js +0 -2507
  618. package/dist/clients/test-runner-delivery.js +0 -287
  619. package/dist/clients/todo-scanner.js +0 -229
  620. package/dist/clients/tool-agreement.js +0 -423
  621. package/dist/clients/tool-config.js +0 -249
  622. package/dist/clients/tool-cwd.js +0 -270
  623. package/dist/clients/tool-definition.js +0 -47
  624. package/dist/clients/tool-event.js +0 -105
  625. package/dist/clients/tool-policy.js +0 -2755
  626. package/dist/clients/tool-probe.js +0 -53
  627. package/dist/clients/tool-render.js +0 -156
  628. package/dist/clients/tool-set-policy.js +0 -118
  629. package/dist/clients/tree-sitter-cache.js +0 -364
  630. package/dist/clients/tree-sitter-client.js +0 -4134
  631. package/dist/clients/tree-sitter-logger.js +0 -100
  632. package/dist/clients/tree-sitter-navigator.js +0 -269
  633. package/dist/clients/tree-sitter-query-loader.js +0 -569
  634. package/dist/clients/tree-sitter-shared.js +0 -158
  635. package/dist/clients/tree-sitter-symbol-extractor.js +0 -1265
  636. package/dist/clients/trivy-client.js +0 -467
  637. package/dist/clients/tui-fit.js +0 -50
  638. package/dist/clients/turn-context.js +0 -52
  639. package/dist/clients/turn-summary-render.js +0 -72
  640. package/dist/clients/turn-summary.js +0 -132
  641. package/dist/clients/typos-config.js +0 -29
  642. package/dist/clients/user-notify.js +0 -51
  643. package/dist/clients/vanished-instance-marker.js +0 -57
  644. package/dist/clients/warm-attach.js +0 -246
  645. package/dist/clients/widget-state.js +0 -1677
  646. package/dist/clients/word-index-logger.js +0 -49
  647. package/dist/clients/word-index-store.js +0 -459
  648. package/dist/clients/word-index.js +0 -2080
  649. package/dist/clients/workspace-topology.js +0 -389
  650. package/dist/clients/write-ordering-guard.js +0 -65
  651. package/dist/clients/zizmor-config.js +0 -327
  652. package/dist/i18n.js +0 -69
  653. package/dist/mcp/build-staleness.js +0 -124
  654. package/dist/scripts/lib/process-scan.mjs +0 -583
  655. package/dist/scripts/lib/skills-predicate.mjs +0 -129
  656. package/dist/tools/activate-tools.js +0 -87
  657. package/dist/tools/ast-grep-outline.js +0 -137
  658. package/dist/tools/ast-grep-replace.js +0 -244
  659. package/dist/tools/ast-grep-search.js +0 -762
  660. package/dist/tools/effective-config.js +0 -90
  661. package/dist/tools/lens-diagnostic-mark.js +0 -375
  662. package/dist/tools/lens-diagnostics.js +0 -2544
  663. package/dist/tools/lsp-diagnostics.js +0 -1634
  664. package/dist/tools/lsp-navigation.js +0 -1367
  665. package/dist/tools/lsp-structured-output.js +0 -294
  666. package/dist/tools/module-report.js +0 -382
  667. package/dist/tools/project-report.js +0 -86
  668. package/dist/tools/render-compact.js +0 -374
  669. package/dist/tools/scan-progress.js +0 -53
  670. package/dist/tools/shared.js +0 -29
  671. package/dist/tools/symbol-search.js +0 -155
@@ -1,792 +0,0 @@
1
- /**
2
- * The ONE config resolution path (#2426).
3
- *
4
- * Every pi-lens config file — canonical or legacy, project or global — is read,
5
- * validated and layered here, through `config-core`'s `resolveConfig` over the
6
- * canonical schema in `config-schema.ts`. The three exported loaders
7
- * (`loadLSPConfig`, `loadPiLensGlobalConfig`, `loadPiLensProjectConfig`) keep
8
- * their names and return types and become PROJECTIONS of what this module
9
- * resolves, so their ~20 call sites are untouched.
10
- *
11
- * THE DOCUMENTED LOOKUP ORDER, lowest precedence first:
12
- *
13
- * builtin -> global -> project root -> nested-project -> env -> cli -> host
14
- *
15
- * It is `config-core`'s own `SOURCE_TIERS`, not a second ordering: this
16
- * module places files into tiers and the core sorts them. `docs/configuration.md`
17
- * documents the same order once, and `tests/clients/config-resolve.test.ts`
18
- * walks it.
19
- *
20
- * Only THREE of those tiers are populated here — `global`, `project` and
21
- * `nested-project` — because those are the tiers config FILES live in.
22
- * `builtin`, `env`, `cli` and `host` are reserved (#2427 wires env/CLI, #2416
23
- * the host tier); today's env vars and CLI flags reach a setting through their
24
- * own accessors, and `docs/configuration.md` states that precedence rather than
25
- * implying this resolution already carries it.
26
- *
27
- * WITHIN a tier, the canonical file is added LAST and therefore wins, because
28
- * `merge` keeps caller order on a precedence tie. That is the whole deprecation
29
- * story in one line: a legacy file is still read, and it loses to the file the
30
- * user is being told to move to.
31
- *
32
- * LEGACY ROOT LSP KEYS ARE NORMALIZED INTO THE `lsp` NAMESPACE HERE, at source
33
- * injection, and nowhere else (#2427 review round 2, F1). Every LSP setting has
34
- * two spellings during the deprecation window — `disabledServers` at a
35
- * document's root and `lsp.disabledServers` inside it — and leaving both in
36
- * place gave the schema TWO nodes for one setting. `merge()` then resolved each
37
- * node independently: two deny unions that never saw each other's tiers, and
38
- * two object merges that never saw each other's entries. A projection could
39
- * only pick one, and picking the canonical one meant a global denial written in
40
- * the legacy spelling disappeared the moment any project file mentioned the
41
- * canonical one — the operator-denial-lifted-by-repository-content defect
42
- * #2415 AC 3 forbids, arriving through the migration instead of through the
43
- * merge strategy.
44
- *
45
- * An earlier draft rejected this rewrite because it would inject an `lsp` key
46
- * into `PiLensProjectConfig.raw` that was never in the user's file. That
47
- * objection is why the normalization lives HERE and not in
48
- * `resolveOnePiLensConfigDocument`: `.raw` comes from the single-document path,
49
- * which still merges a document exactly as written. Only this multi-document
50
- * resolution — whose two consumers are `loadLSPConfig` and `effectiveConfig`,
51
- * both of which read the `lsp` section and nothing else — normalizes.
52
- *
53
- * The mapping is `canonicalKeyFor`'s, the one the deprecation records already
54
- * publish, so "where does this key move to" is answered once. Within a single
55
- * document the canonical spelling still wins a collision, which is the rule
56
- * `lspSectionOf` used to apply at projection time; across documents `merge()`
57
- * now applies the ordinary tier precedence and the deny union to ONE node.
58
- */
59
- import * as fs from "node:fs";
60
- import * as os from "node:os";
61
- import * as path from "node:path";
62
- import { DEPRECATED_CONFIG_SURFACES, } from "./config-diagnostic-codes.js";
63
- import { CANONICAL_GLOBAL_CONFIG_FILE, CANONICAL_PROJECT_CONFIG_FILE, GLOBAL_CONFIG_LOCATIONS, LEGACY_ROOT_LSP_KEYS, LSP_NAMESPACE_KEY, PROJECT_CONFIG_LOCATIONS, configSearchDirs, } from "./config-locations.js";
64
- // The core's halves are imported directly rather than through
65
- // `config-core/index.js` (#2426). The barrel re-exports the whole vocabulary
66
- // including `process-spec.js`, which reaches `project-trust.js` and the
67
- // degradation ledger; a module that only resolves a config has no use for that
68
- // and, sitting downstream of `file-utils.ts` as every config loader does, would
69
- // close three import cycles by importing it. `resolveConfig` is still the one
70
- // supported way into the pipeline — `merge()` is deliberately not imported here.
71
- import { resolveConfig } from "./config-core/resolve.js";
72
- import { finalizeRecords, migrationSubject, } from "./config-core/records.js";
73
- import { SOURCE_TIERS, } from "./config-core/provenance.js";
74
- import { PI_LENS_CONFIG_SCHEMA } from "./config-schema.js";
75
- import { normalizeParseErrorReason, warnIgnoredConfigOnce, } from "./config-warn.js";
76
- import { homeRelativePath } from "./path-utils.js";
77
- /**
78
- * Read and JSON-parse one config file.
79
- *
80
- * Deliberately does NOT warn: the three loaders each render their own prose
81
- * (`ignoring invalid LSP config …` / `… global config …` / `… project config …`)
82
- * and their tests assert on it, so the decision of what to say about a bad file
83
- * stays with the loader while the reading itself is shared.
84
- */
85
- export function readConfigDocument(file) {
86
- let text;
87
- try {
88
- text = fs.readFileSync(file, "utf-8");
89
- }
90
- catch (error) {
91
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {
92
- return { status: "missing" };
93
- }
94
- return { status: "error", error };
95
- }
96
- try {
97
- return { status: "ok", value: JSON.parse(text) };
98
- }
99
- catch (error) {
100
- return { status: "error", error, sourceText: text };
101
- }
102
- }
103
- /**
104
- * The canonical GLOBAL config path this resolution uses — for READING it and
105
- * for naming it in a migration notice, from one expression (#2426 review round
106
- * 2, F1).
107
- *
108
- * The two used to be computed separately: the read came from
109
- * `options.globalConfigPath` (`getPiLensGlobalConfigPath()`, `$HOME`-derived
110
- * unless `PI_LENS_CONFIG_PATH` overrides it) while the notice was recomputed as
111
- * `dirname(<legacy file>) + config.json` — and the legacy file lives under
112
- * `getGlobalPiLensDir()`, which `PI_LENS_HOME` relocates. Set `PI_LENS_HOME`
113
- * without `PI_LENS_CONFIG_PATH` and the two diverge, so the notice named a file
114
- * the resolver never reads: a user who followed it moved their settings into a
115
- * file that does nothing. Deriving both from here makes "the path we name" and
116
- * "the path we read" the same value by construction rather than by agreement.
117
- */
118
- function canonicalGlobalFile(options) {
119
- if (options.globalConfigPath !== undefined)
120
- return options.globalConfigPath;
121
- return options.globalDir === undefined
122
- ? undefined
123
- : path.join(options.globalDir, CANONICAL_GLOBAL_CONFIG_FILE);
124
- }
125
- function collectDocuments(dir, locations, tier, onReadError) {
126
- const documents = [];
127
- for (const location of locations) {
128
- const file = path.join(dir, location.relativePath);
129
- const outcome = readConfigDocument(file);
130
- if (outcome.status === "missing")
131
- continue;
132
- if (outcome.status === "error") {
133
- onReadError?.({
134
- file,
135
- location,
136
- tier,
137
- error: outcome.error,
138
- sourceText: outcome.sourceText,
139
- });
140
- continue;
141
- }
142
- documents.push({ tier, file, location, value: outcome.value });
143
- }
144
- return documents;
145
- }
146
- /**
147
- * Assemble every config document for a resolution, lowest precedence first.
148
- *
149
- * The project walk is ceiling-bounded by `configSearchDirs`. The OUTERMOST
150
- * config-bearing directory is the `project` tier and everything nearer the cwd
151
- * is `nested-project`, which is what makes "nearest wins, per field" fall out
152
- * of the core's tier precedence instead of being re-implemented here.
153
- */
154
- function collectPiLensConfigDocuments(options) {
155
- const documents = [];
156
- const { globalDir, onReadError } = options;
157
- const globalConfigPath = canonicalGlobalFile(options);
158
- if (globalDir !== undefined || globalConfigPath !== undefined) {
159
- for (const location of GLOBAL_CONFIG_LOCATIONS) {
160
- const file = location.relativePath === CANONICAL_GLOBAL_CONFIG_FILE
161
- ? globalConfigPath
162
- : globalDir === undefined
163
- ? undefined
164
- : path.join(globalDir, location.relativePath);
165
- if (file === undefined)
166
- continue;
167
- const outcome = readConfigDocument(file);
168
- if (outcome.status === "missing")
169
- continue;
170
- if (outcome.status === "error") {
171
- onReadError?.({
172
- file,
173
- location,
174
- tier: "global",
175
- error: outcome.error,
176
- sourceText: outcome.sourceText,
177
- });
178
- continue;
179
- }
180
- documents.push({ tier: "global", file, location, value: outcome.value });
181
- }
182
- }
183
- if (options.cwd !== undefined) {
184
- // Innermost first from the walk; reversed so the OUTERMOST directory is
185
- // emitted first and lands in the lower-precedence `project` tier.
186
- const dirs = configSearchDirs(options.cwd, options.homeDir ?? os.homedir()).reverse();
187
- const bearing = dirs
188
- .map((dir) => ({
189
- dir,
190
- found: collectDocuments(dir, PROJECT_CONFIG_LOCATIONS, "project", onReadError),
191
- }))
192
- .filter((entry) => entry.found.length > 0);
193
- bearing.forEach((entry, index) => {
194
- const tier = index === 0 ? "project" : "nested-project";
195
- for (const document of entry.found)
196
- documents.push({ ...document, tier });
197
- });
198
- }
199
- return documents;
200
- }
201
- /** A zero for every tier, so a consumer never has to test for an absent key. */
202
- function emptyTierCounts() {
203
- return Object.fromEntries(SOURCE_TIERS.map((tier) => [tier, 0]));
204
- }
205
- /**
206
- * Project a resolution onto its redacted summary.
207
- *
208
- * Values never appear: a document contributes its PATH (home-relative), its
209
- * tier and its legacy flag, and nothing else — the same structural redaction
210
- * `pilens_effective_config` applies, spelled once rather than twice (rule 3 of
211
- * `clients/effective-config.ts`: the redacted view is the only view).
212
- *
213
- * Pure and synchronous: it reads a resolution the caller already performed and
214
- * resolves nothing itself, so no caller can turn "report what we resolved"
215
- * into a second walk of the config tree (#2513's facade rule).
216
- */
217
- export function summarizeConfigResolution(resolution, homeDir) {
218
- const countsByTier = emptyTierCounts();
219
- for (const entry of resolution.provenance.values()) {
220
- countsByTier[entry.tier] += 1;
221
- }
222
- return {
223
- documents: resolution.documents.map((document) => ({
224
- tier: document.tier,
225
- file: homeRelativePath(document.file, homeDir),
226
- legacy: document.location.legacy,
227
- })),
228
- countsByTier,
229
- recordCount: resolution.records.length,
230
- };
231
- }
232
- /** Resolve every discovered document into one configuration. */
233
- export function resolvePiLensConfig(options) {
234
- const documents = collectPiLensConfigDocuments(options);
235
- const sources = configSources(documents);
236
- const resolution = resolveConfig({
237
- sources,
238
- schema: PI_LENS_CONFIG_SCHEMA,
239
- });
240
- return {
241
- value: resolution.resolved.value ?? {},
242
- provenance: resolution.resolved.provenance,
243
- records: finalizeRecords([
244
- ...resolution.records,
245
- ...deprecationRecords(documents, options.homeDir ?? os.homedir(), canonicalGlobalFile(options)),
246
- ], documentAnchor(documents),
247
- // The core ALREADY truncated (#2426 review round 6, F1). Its drop count
248
- // is seeded here so the one `PILENS_CFG_0007` a user reads names the
249
- // whole truncation rather than the part this bound performed.
250
- resolution.droppedRecordCount),
251
- documents,
252
- };
253
- }
254
- /**
255
- * Resolve ONE document — the shape both single-file loaders need.
256
- *
257
- * Still the core's pipeline, not a shortcut around it: the value is validated
258
- * against the canonical schema (depth bound, prototype-key policy, the declared
259
- * `lsp.*` types) and merged from one source, so a single-file loader and the
260
- * multi-file one cannot disagree about what a value means.
261
- *
262
- * It deliberately does NOT normalize legacy root LSP keys into the `lsp`
263
- * namespace the way `resolvePiLensConfig` does (#2427 review round 2, F1).
264
- * This path's two callers project the pi-lens sections of ONE file and hand
265
- * the resolved value out as `PiLensProjectConfig.raw`, which is documented and
266
- * tested as the parsed document; relocating a key inside it would put an `lsp`
267
- * section in `raw` that the user's file never contained. The relocation exists
268
- * so that ONE key seen at SEVERAL tiers reaches one schema node, and a
269
- * single-document resolution has no tiers to reconcile.
270
- *
271
- * The visible consequence is small and worth naming: a wrong-TYPED legacy root
272
- * LSP key (`warmFiles: true`) is validated against the typed `lsp.*` node only
273
- * in the multi-document path, so the LSP loader reports it and the two
274
- * single-file loaders do not. A session runs both, and the warn-once latch
275
- * unions their notices, so a user loses nothing — they gain one accurate
276
- * notice.
277
- */
278
- export function resolveOnePiLensConfigDocument(document, homeDir = os.homedir()) {
279
- const resolution = resolveConfig({
280
- sources: [
281
- { tier: document.tier, file: document.file, value: document.value },
282
- ],
283
- schema: PI_LENS_CONFIG_SCHEMA,
284
- });
285
- return {
286
- value: resolution.resolved.value ?? {},
287
- records: finalizeRecords([...resolution.records, ...deprecationRecords([document], homeDir)], documentAnchor([document]),
288
- // Same double bound as the multi-document path above (round 6, F1).
289
- resolution.droppedRecordCount),
290
- };
291
- }
292
- /**
293
- * The anchor for a record list produced from these documents: the
294
- * highest-precedence one — the file whose values would have won, and the one a
295
- * user reading a config notice is looking at.
296
- *
297
- * The list's BOUND, its overflow record, and the reserved slot that record
298
- * occupies all live in `config-core/records.ts` (#2426 review round 5,
299
- * F-A/F-B/S-A). This module used to carry its own copy of them, the project
300
- * loader carried a second, and the project loader's legacy path carried none
301
- * at all — the shape the single-source rule exists to catch. What is left here
302
- * is the one thing `config-core` cannot know: which of the caller's documents
303
- * is the anchor.
304
- */
305
- function documentAnchor(documents) {
306
- const last = documents[documents.length - 1];
307
- return last === undefined ? undefined : { file: last.file, tier: last.tier };
308
- }
309
- /**
310
- * The `ConfigLocation` for a project-relative basename, for a caller that
311
- * discovered the file through its own (cached) walk rather than through
312
- * `collectPiLensConfigDocuments`. Falls back to the canonical location so an
313
- * unrecognized basename is never reported as deprecated.
314
- */
315
- export function projectLocationFor(file) {
316
- const base = path.basename(file);
317
- return (PROJECT_CONFIG_LOCATIONS.find((candidate) => path.posix.basename(candidate.relativePath) === base) ?? PROJECT_CONFIG_LOCATIONS[PROJECT_CONFIG_LOCATIONS.length - 1]);
318
- }
319
- // --- deprecation records (#2418 codes 0002 / 0003, #2426 is their producer) ---
320
- const WINDOW_BY_SURFACE = new Map(DEPRECATED_CONFIG_SURFACES.map((row) => [row.surface, row]));
321
- function windowSuffix(surface) {
322
- const row = surface === undefined ? undefined : WINDOW_BY_SURFACE.get(surface);
323
- return row
324
- ? ` (deprecated since ${row.deprecatedSince}; read for the last time before ${row.removeNotBefore})`
325
- : "";
326
- }
327
- /**
328
- * The canonical file a legacy document's keys belong in.
329
- *
330
- * `globalFile` is THREADED from the resolution that read the legacy document,
331
- * never recomputed from that document's own directory (#2426 review round 2,
332
- * F1) — see `canonicalGlobalFile`. The sibling fallback survives only for a
333
- * caller that resolves ONE document in isolation and names no canonical global
334
- * (no production caller does; `resolveOnePiLensConfigDocument`'s two callers
335
- * pass a project document and a canonical global one respectively), and it is
336
- * the only path this module can name at all in that case.
337
- */
338
- function canonicalDestination(document, homeDir, globalFile) {
339
- if (document.tier === "global") {
340
- return homeRelativePath(globalFile ??
341
- path.join(path.dirname(document.file), CANONICAL_GLOBAL_CONFIG_FILE), homeDir);
342
- }
343
- return CANONICAL_PROJECT_CONFIG_FILE;
344
- }
345
- /**
346
- * The `lsp`-namespace key a document ROOT key normalizes to, or `undefined`
347
- * when the key stays where it is.
348
- *
349
- * THE mapping, shared with `canonicalKeyFor` below so the key a deprecation
350
- * record tells the user to move to and the key the resolution actually merges
351
- * under are the same key by construction. An LSP-SCOPED legacy file
352
- * (`pi-lsp.json`, `.pi-lens/lsp.json`) is wholly what a canonical file now
353
- * carries under `lsp`, so every RECOGNIZED root key of one moves; a canonical
354
- * or non-LSP legacy file moves only the four registry-derived legacy root keys.
355
- * An unrecognized key is left alone in both cases — it is not a pi-lens
356
- * setting, and relocating it would invent a meaning for it.
357
- */
358
- function lspNamespaceKeyFor(document, key) {
359
- if (key === LSP_NAMESPACE_KEY)
360
- return undefined;
361
- if (document.location.lspScoped) {
362
- return recognizedKeysFor(document.location).has(key) ? key : undefined;
363
- }
364
- return LEGACY_ROOT_LSP_KEYS.includes(key) ? key : undefined;
365
- }
366
- /**
367
- * Assign one raw, not-yet-validated value under a user-chosen key.
368
- *
369
- * `defineProperty` rather than `=` for the reason `config-core/safe-object.ts`
370
- * spells out: `out["__proto__"] = x` runs an inherited SETTER instead of
371
- * creating a property. This split runs BEFORE `validate()`, so it is the one
372
- * place in this module that touches user-chosen key names, and it hands every
373
- * such key through untouched for the core to reject and record.
374
- */
375
- function assignRaw(target, key, value) {
376
- Object.defineProperty(target, key, {
377
- value,
378
- writable: true,
379
- enumerable: true,
380
- configurable: true,
381
- });
382
- }
383
- /**
384
- * The sources a resolution merges, with every document's legacy root LSP keys
385
- * moved into the `lsp` namespace (#2427 review round 2, F1).
386
- *
387
- * A document that carries none is passed through UNCHANGED — the overwhelming
388
- * majority, and the case that must cost nothing. One that does becomes TWO
389
- * sources at the same tier and file: the relocated keys first, the rest of the
390
- * document (its own `lsp` namespace included) second. Two sources rather than
391
- * one merged object because the second still carries whatever the document
392
- * spelled at `lsp`, so a malformed `lsp` keeps producing its `PILENS_CFG_0004`
393
- * while the relocated keys survive beside it; and because caller order at an
394
- * equal tier is what `merge()` uses to break a tie, putting the canonical
395
- * spelling second is exactly the canonical-wins-per-key rule `lspSectionOf`
396
- * used to apply at projection time.
397
- *
398
- * The relocated keys are STRIPPED from the second source rather than left in
399
- * place. Leaving them would keep the legacy schema node populated, and a
400
- * malformed legacy key would then record the same `PILENS_CFG_0004` twice —
401
- * once per spelling — for one mistake in one file.
402
- *
403
- * A deny key is the one place the intra-document tie is not "canonical wins":
404
- * `merge()` sends `lsp.disabledServers` to `config-core/deny.ts`, which unions
405
- * every contribution. A file spelling BOTH `disabledServers` and
406
- * `lsp.disabledServers` therefore denies both lists. That is the monotonic
407
- * answer and the only safe one — a denial silently dropped because the user
408
- * half-migrated the file it was written in is the defect this whole change
409
- * exists to remove.
410
- */
411
- function configSources(documents) {
412
- const sources = [];
413
- for (const document of documents) {
414
- const value = document.value;
415
- const namespaced = {};
416
- const rest = {};
417
- for (const key of topLevelKeys(value)) {
418
- const entry = value[key];
419
- const target = lspNamespaceKeyFor(document, key);
420
- if (target === undefined)
421
- assignRaw(rest, key, entry);
422
- else
423
- assignRaw(namespaced, target, entry);
424
- }
425
- const base = { tier: document.tier, file: document.file };
426
- if (Object.keys(namespaced).length === 0) {
427
- sources.push({ ...base, value });
428
- continue;
429
- }
430
- sources.push({ ...base, value: { [LSP_NAMESPACE_KEY]: namespaced } });
431
- sources.push({ ...base, value: rest });
432
- }
433
- return sources;
434
- }
435
- /**
436
- * The canonical KEY a legacy key moves to.
437
- *
438
- * Carried on the record (`canonicalKey`) rather than only rendered into the
439
- * message, so the auto-migrator #2426 explicitly defers can be a pure function
440
- * over these records instead of re-parsing prose.
441
- */
442
- function canonicalKeyFor(document, key) {
443
- const namespaced = lspNamespaceKeyFor(document, key);
444
- return namespaced === undefined ? key : `${LSP_NAMESPACE_KEY}.${namespaced}`;
445
- }
446
- function topLevelKeys(value) {
447
- return value && typeof value === "object" && !Array.isArray(value)
448
- ? Object.keys(value)
449
- : [];
450
- }
451
- /** The `properties` key names of a JSON-Schema-shaped node. */
452
- function schemaPropertyKeys(node) {
453
- const properties = node?.properties;
454
- return properties !== null &&
455
- typeof properties === "object" &&
456
- !Array.isArray(properties)
457
- ? Object.keys(properties)
458
- : [];
459
- }
460
- /**
461
- * The top-level keys a pi-lens config document may legitimately carry — READ
462
- * OFF the canonical schema rather than restated, so a section added to a
463
- * registry is recognized here for free (`config-schema.ts` derives its property
464
- * list from those registries).
465
- */
466
- const CANONICAL_TOP_LEVEL_KEYS = new Set(schemaPropertyKeys(PI_LENS_CONFIG_SCHEMA));
467
- /**
468
- * The same, for an LSP-SCOPED legacy file (`pi-lsp.json`, `.pi-lens/lsp.json`,
469
- * `~/.pi-lens/lsp.json`): that whole file is what a canonical file now holds
470
- * under `lsp`, so its recognized ROOT keys are the `lsp` namespace's own.
471
- */
472
- const LSP_DOCUMENT_KEYS = new Set(schemaPropertyKeys(PI_LENS_CONFIG_SCHEMA
473
- .properties?.[LSP_NAMESPACE_KEY]));
474
- function recognizedKeysFor(location) {
475
- return location.lspScoped ? LSP_DOCUMENT_KEYS : CANONICAL_TOP_LEVEL_KEYS;
476
- }
477
- /**
478
- * One record per `(file, key)` — never one per nested leaf, and only for a key
479
- * pi-lens actually RECOGNIZES (#2426 review round 4, F2/F5).
480
- *
481
- * A per-leaf record would re-nag once per custom server. A record for every
482
- * top-level key, which is what this emitted before, was worse in both
483
- * directions: the count was user input, so a 100-key legacy file produced 100
484
- * "move it" notices on top of the 98 typo notices the project loader already
485
- * emits for the same keys; and each one told the user to MOVE a key that is
486
- * not a pi-lens setting at all, which is advice that cannot be followed. A key
487
- * no schema property claims gets the loaders' typo diagnostic and nothing
488
- * else.
489
- *
490
- * The unrecognized keys are still accounted for, in ONE whole-file record
491
- * naming their count — the file is at a deprecated location whatever its keys
492
- * spell, and a user who moves only the keys named here has to know the rest
493
- * were left behind deliberately.
494
- */
495
- export function deprecationRecords(documents, homeDir, globalFile) {
496
- const records = [];
497
- for (const document of documents) {
498
- if (document.location.legacy) {
499
- const destination = canonicalDestination(document, homeDir, globalFile);
500
- const recognized = recognizedKeysFor(document.location);
501
- let unrecognized = 0;
502
- for (const key of topLevelKeys(document.value)) {
503
- if (!recognized.has(key)) {
504
- unrecognized += 1;
505
- continue;
506
- }
507
- const canonicalKey = canonicalKeyFor(document, key);
508
- records.push(record({
509
- code: "PILENS_CFG_0003",
510
- file: document.file,
511
- key,
512
- canonicalKey,
513
- tier: document.tier,
514
- reason: `move "${key}" to ${destination}` +
515
- (canonicalKey === key ? "" : ` under "${canonicalKey}"`) +
516
- windowSuffix(document.location.surface),
517
- }));
518
- }
519
- if (unrecognized > 0) {
520
- const plural = unrecognized === 1 ? "it was" : "they were";
521
- records.push({
522
- code: "PILENS_CFG_0003",
523
- file: document.file,
524
- key: "",
525
- // An LSP-scoped legacy file moves WHOLESALE into the `lsp`
526
- // namespace, so naming that namespace is literally true here — and
527
- // it is what routes this record to the LSP loader's subsystem, the
528
- // same key-derived ownership every other record uses.
529
- ...(document.location.lspScoped
530
- ? { canonicalKey: LSP_NAMESPACE_KEY }
531
- : {}),
532
- subject: migrationSubject(document.file, ""),
533
- tier: document.tier,
534
- reason: `this file is at a deprecated location; move it to ${destination}. ` +
535
- (unrecognized === 1
536
- ? "1 of its top-level keys is not a recognized pi-lens setting"
537
- : `${unrecognized} of its top-level keys are not recognized pi-lens settings`) +
538
- `, and ${plural} not migrated${windowSuffix(document.location.surface)}`,
539
- });
540
- }
541
- continue;
542
- }
543
- // A CANONICAL file carrying legacy ROOT LSP keys: the file stays, the keys
544
- // move into the `lsp` namespace inside it.
545
- for (const key of topLevelKeys(document.value)) {
546
- if (!LEGACY_ROOT_LSP_KEYS.includes(key))
547
- continue;
548
- const canonicalKey = `${LSP_NAMESPACE_KEY}.${key}`;
549
- records.push(record({
550
- code: "PILENS_CFG_0002",
551
- file: document.file,
552
- key,
553
- canonicalKey,
554
- tier: document.tier,
555
- reason: `move "${key}" to "${canonicalKey}" in the same file${windowSuffix(key)}`,
556
- }));
557
- }
558
- }
559
- return records;
560
- }
561
- function record(input) {
562
- return {
563
- code: input.code,
564
- file: input.file,
565
- key: input.key,
566
- canonicalKey: input.canonicalKey,
567
- subject: migrationSubject(input.file, input.key),
568
- reason: input.reason,
569
- tier: input.tier,
570
- };
571
- }
572
- /**
573
- * `undefined` for a record no key can attribute — the whole-file/whole-document
574
- * failure records (`key: ""`) that both halves of the core emit when a resolution
575
- * fails internally. Those are reported by EVERY loader rather than by none: a
576
- * duplicate notice about a config that failed to load is noise, while silence
577
- * about it is the failure mode this module exists to prevent.
578
- */
579
- function configRecordOwner(record) {
580
- const key = record.canonicalKey ?? record.key;
581
- if (key.length === 0)
582
- return undefined;
583
- const head = (key.startsWith("/") ? key.slice(1) : key).split(/[./]/)[0] ?? "";
584
- if (head.length === 0)
585
- return undefined;
586
- return head === LSP_NAMESPACE_KEY || LEGACY_ROOT_LSP_KEYS.includes(head)
587
- ? "lsp"
588
- : "pi-lens";
589
- }
590
- /** The pi-lens-config subsystem a GLOBAL vs. PROJECT tier reports under. */
591
- function piLensSubsystemFor(tier) {
592
- if (tier === "global")
593
- return "lens-config";
594
- if (tier === "project" || tier === "nested-project") {
595
- return "project-lens-config";
596
- }
597
- // `builtin` / `env` / `cli` / `host` never produce a document today, and a
598
- // merge-level bound refusal (see `MigrationRecord.tier`'s doc comment) names
599
- // no single source at all — `undefined` in either case.
600
- return undefined;
601
- }
602
- /**
603
- * The subsystem(s) one record must be reported under (#2426 review round 3,
604
- * F1).
605
- *
606
- * DERIVED from the record itself — owner (`configRecordOwner`) plus, for a
607
- * pi-lens-owned record, the TIER it was read at — rather than from which
608
- * loader is calling. Before this, a caller filtered to the records it "owned"
609
- * with `recordsOwnedBy` before reporting, which meant a pi-lens-owned record
610
- * from a document only the LSP loader's multi-file resolution actually
611
- * discovered (a legacy sibling file `loadPiLensProjectConfig`'s single-nearest-
612
- * file walk never opens) was filtered OUT by the LSP loader and never produced
613
- * by the project loader either: dropped by construction, never reported by
614
- * anyone.
615
- *
616
- * Deriving the subsystem from the record instead of the caller fixes that:
617
- * EVERY loader that sees the record now reports it, always to the SAME
618
- * subsystem set, so the warn-once latch (keyed on `subsystem\0file\0key\0
619
- * reason`) naturally collapses duplicate reports from different callers into
620
- * one notice — the F2 behavior — while a record no caller happened to "own"
621
- * before is reported by whichever loader actually resolved it.
622
- *
623
- * An `lsp` owner always reports under `lsp-config`, regardless of tier — the
624
- * LSP loader is the one home for every LSP setting. A `pi-lens` owner reports
625
- * under the tier-appropriate pi-lens loader.
626
- *
627
- * An unattributable record (owner `undefined` — the whole-file failures both
628
- * halves of the core emit with `key: ""`) reports under the ONE subsystem its
629
- * TIER names, when a tier is known (#2426 review round 4, S1). Round 3 sent it
630
- * to every subsystem that could plausibly have produced it, which turned one
631
- * internal failure into three notices, one of them announcing an "LSP config"
632
- * problem in a file with no LSP settings in it. `config-core`'s own
633
- * `resolveConfig` anchors that record to the resolution's highest-precedence
634
- * source precisely so the tier is known; the report-by-all fallback survives only for
635
- * a record that names no source at all.
636
- */
637
- function configRecordSubsystems(record) {
638
- const owner = configRecordOwner(record);
639
- const piLens = piLensSubsystemFor(record.tier);
640
- const piLensSubsystems = piLens
641
- ? [piLens]
642
- : ["lens-config", "project-lens-config"];
643
- if (owner === "lsp")
644
- return ["lsp-config"];
645
- if (owner === "pi-lens")
646
- return piLensSubsystems;
647
- if (piLens)
648
- return [piLens];
649
- return ["lsp-config", ...piLensSubsystems];
650
- }
651
- /**
652
- * WHICH subsystem owns a config file that could not be read or parsed (#2445).
653
- *
654
- * Derived from the DOCUMENT — its location and its tier — for the same reason
655
- * `configRecordSubsystems` derives ownership from the record: `loadLSPConfig`
656
- * opens the pi-lens global and project configs too, and labelling their parse
657
- * failures "ignoring invalid LSP config" told a user to look at an LSP setting
658
- * when what they had broken was `~/.pi-lens/config.json`. An LSP-SCOPED file
659
- * (`pi-lsp.json`, `lsp.json`) is the LSP loader's whatever tier it sits at.
660
- */
661
- function configFileSubsystem(location, tier) {
662
- if (location.lspScoped)
663
- return "lsp-config";
664
- return tier === "global" ? "lens-config" : "project-lens-config";
665
- }
666
- /**
667
- * Report an unreadable/unparsable config document under its OWNING subsystem.
668
- *
669
- * `{ parseError }`, never a pre-stringified message: `warnIgnoredConfigOnce` is
670
- * the one seam that decides how much of a `JSON.parse` `SyntaxError#message`
671
- * (which embeds a snippet of the file being parsed, #2431) survives into the
672
- * log line, the ledger row and the notification.
673
- */
674
- export function reportConfigReadFailure(failure) {
675
- warnIgnoredConfigOnce({
676
- subsystem: configFileSubsystem(failure.location, failure.tier),
677
- file: failure.file,
678
- reason: { parseError: failure.error, sourceText: failure.sourceText },
679
- });
680
- }
681
- /**
682
- * Thread a resolution's records to the ONE config warning seam (#2418).
683
- *
684
- * Every caller passes every record its OWN resolution produced — no filtering
685
- * (#2426 review round 3, F1; see `subsystemsFor`). Calling this more than once
686
- * with overlapping records (the LSP loader and a pi-lens loader resolving the
687
- * same document) is by design: the warn-once latch dedupes across callers, so
688
- * the user still sees exactly one notice per `(subsystem, file, key, reason)`.
689
- *
690
- * It lives here rather than in `config-core/records.ts`, where #2425 first put
691
- * it (#2426). Putting the sink call inside the library contradicted the
692
- * library's own stated purity — `config-core` is documented as "no state, no
693
- * I/O, no ledger writes" — and the import it needed
694
- * (`records.ts` -> `config-warn.js` -> `degradation-ledger.js`) closed seven
695
- * cycles the moment a loader resolved through the core, because every config
696
- * loader sits downstream of `file-utils.ts`. Reporting is a loader decision;
697
- * this is the loaders' shared module.
698
- */
699
- export function reportPiLensConfigRecords(records) {
700
- for (const record of records) {
701
- for (const subsystem of configRecordSubsystems(record)) {
702
- warnIgnoredConfigOnce({
703
- subsystem,
704
- file: record.file,
705
- key: record.key.length > 0 ? record.key : undefined,
706
- reason: record.reason,
707
- code: record.code,
708
- });
709
- }
710
- }
711
- }
712
- /**
713
- * Buffer a loader's own ignored-config notices for one document, then bound
714
- * them once.
715
- *
716
- * A `NoteIgnored` COLLECTS rather than reports (#2426 review round 4, F3/F5).
717
- * Two things follow. The notice survives into a loader's cache entry, so a warm
718
- * cache HIT replays it instead of losing the whole `config-ignored` class from
719
- * session 2 onwards. And the count is bounded: the number of these a file can
720
- * produce is the number of keys the user typed — a 100-key file emitted 98
721
- * unknown-key notifications — so the buffered list goes through the same
722
- * `finalizeRecords` bound every other config record obeys, with one slot held
723
- * back to say how many were suppressed.
724
- *
725
- * ONE COPY, in the module both loaders already import (#2426 review round 7,
726
- * F2). Round 6 gave the global loader the bound the project loader already had
727
- * — by copying it — leaving two spellings of one record literal
728
- * (`PILENS_CFG_0001`, no key, `migrationSubject(configPath, "")`) and one flush,
729
- * differing only in a tier literal. Two copies of one policy is the shape round
730
- * 5 collapsed three copies of this same bound to avoid, so the tier is an
731
- * argument and the copy is gone. `tests/clients/config-notice-bounds.test.ts`
732
- * asserts on the SOURCE that no third copy grows back, because duplication is
733
- * invisible to a behavioral probe until one copy is edited.
734
- *
735
- * The buffer is a plain array (round 6, S2). It used to be a pre-subtracted
736
- * `finalizableCollector`, a second exported shape for the one policy round 5
737
- * had just collapsed; the notes a single parse can accumulate are bounded by
738
- * the document already in memory, which is a smaller cost than a second public
739
- * entry point onto the same arithmetic.
740
- */
741
- export function ignoredRecordCollector(configPath, tier) {
742
- const noted = [];
743
- const note = (reason, code = "PILENS_CFG_0001") => {
744
- let notedRecord = {
745
- code: "PILENS_CFG_0001",
746
- file: configPath,
747
- key: "",
748
- subject: migrationSubject(configPath, ""),
749
- reason: typeof reason === "string"
750
- ? reason
751
- : normalizeParseErrorReason(reason.parseError, {
752
- sourceText: reason.sourceText,
753
- }),
754
- tier,
755
- };
756
- if (code !== "PILENS_CFG_0001")
757
- notedRecord.code = code;
758
- noted.push(notedRecord);
759
- };
760
- return {
761
- note,
762
- records: () => finalizeRecords(noted, { file: configPath, tier }),
763
- };
764
- }
765
- /**
766
- * The effective `lsp` section of a resolved configuration.
767
- *
768
- * One lookup, because the combination it used to perform now happens at source
769
- * injection (`configSources`): by the time a value reaches here, every legacy
770
- * root LSP key a document carried is already inside the namespace and has been
771
- * resolved against every tier through the SAME schema node as its canonical
772
- * spelling. Canonical still wins a collision inside one document — that is
773
- * caller order in `configSources` — but the winner is now chosen by `merge()`,
774
- * which is the only place that can see all the tiers at once.
775
- *
776
- * "Wins" is PER LEAF, not per key. A document that spells both root `servers`
777
- * and `lsp.servers` no longer has one object replace the other: the two are
778
- * merged by server id, and canonical wins only the ids they both define. A
779
- * server defined only in the legacy root spelling therefore survives beside
780
- * the canonical ones instead of disappearing — which is the same fix, one
781
- * level down, as the vanishing legacy denial below (#2427 review round 3).
782
- *
783
- * The projection-time combination this used to do could only ever see two
784
- * independently resolved nodes, and picking one of them is how a global denial
785
- * written in the legacy spelling used to vanish (#2427 review round 2, F1).
786
- */
787
- export function lspSectionOf(value) {
788
- const namespace = value[LSP_NAMESPACE_KEY];
789
- return namespace && typeof namespace === "object" && !Array.isArray(namespace)
790
- ? namespace
791
- : {};
792
- }