@herbertgao/pi-extensions 2026.8.15 → 2026.9.1

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 (351) hide show
  1. package/README.md +4 -1
  2. package/THIRD_PARTY_NOTICES.md +26 -0
  3. package/node_modules/@czottmann/pi-automode/CHANGELOG.md +13 -1
  4. package/node_modules/@czottmann/pi-automode/README.md +20 -0
  5. package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +1 -1
  6. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +2 -1
  7. package/node_modules/@czottmann/pi-automode/docs/defaults.md +3 -2
  8. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +38 -2
  9. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +5 -3
  10. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +11 -3
  11. package/node_modules/@czottmann/pi-automode/package.json +1 -1
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +20 -0
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +46 -3
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -17
  15. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/packets.ts +6 -0
  16. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/scroll.ts +5 -0
  17. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +34 -30
  18. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  19. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  20. package/node_modules/@narumitw/pi-btw/README.md +5 -1
  21. package/node_modules/@narumitw/pi-btw/dist/index.ts +143 -14
  22. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  23. package/node_modules/@narumitw/pi-btw/package.json +4 -4
  24. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +158 -7
  25. package/node_modules/@narumitw/pi-btw/src/text.ts +18 -0
  26. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +5 -16
  27. package/node_modules/@narumitw/pi-caffeinate/LICENSE +21 -0
  28. package/node_modules/@narumitw/pi-caffeinate/README.md +224 -0
  29. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts +1112 -0
  30. package/node_modules/@narumitw/pi-caffeinate/dist/index.ts.map +7 -0
  31. package/node_modules/@narumitw/pi-caffeinate/package.json +53 -0
  32. package/node_modules/@narumitw/pi-caffeinate/src/caffeinate.ts +811 -0
  33. package/node_modules/@narumitw/pi-caffeinate/src/dbus-inhibit.ts +153 -0
  34. package/node_modules/@narumitw/pi-caffeinate/src/index.ts +1 -0
  35. package/node_modules/@narumitw/pi-caffeinate/src/inhibitor-process.ts +43 -0
  36. package/node_modules/@narumitw/pi-caffeinate/src/inhibitors.ts +167 -0
  37. package/node_modules/@narumitw/pi-caffeinate/src/settings.ts +202 -0
  38. package/node_modules/@pi-plugins/fast-mode/README.md +5 -3
  39. package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -1
  40. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +20 -55
  41. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  42. package/node_modules/@pi-plugins/fast-mode/package.json +1 -1
  43. package/node_modules/@tifan/pi-handoff/README.md +6 -3
  44. package/node_modules/@tifan/pi-handoff/package.json +1 -1
  45. package/node_modules/@tifan/pi-handoff/src/index.ts +8 -3
  46. package/node_modules/pi-lens/CHANGELOG.md +988 -0
  47. package/node_modules/pi-lens/README.md +3 -0
  48. package/node_modules/pi-lens/config/biome/core.jsonc +11 -2
  49. package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +13 -1
  50. package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -2
  51. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +927 -80
  52. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +13 -4
  53. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +123 -3
  54. package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +60 -5
  55. package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +2 -2
  56. package/node_modules/pi-lens/dist/clients/bash-file-access.js +1 -3
  57. package/node_modules/pi-lens/dist/clients/biome-client.js +9 -2
  58. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +14 -0
  59. package/node_modules/pi-lens/dist/clients/bootstrap.js +509 -73
  60. package/node_modules/pi-lens/dist/clients/bounded-cache.js +152 -12
  61. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +59 -4
  62. package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +113 -0
  63. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +2 -2
  64. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +31 -4
  65. package/node_modules/pi-lens/dist/clients/cache-manager.js +105 -6
  66. package/node_modules/pi-lens/dist/clients/cache-observability.js +44 -18
  67. package/node_modules/pi-lens/dist/clients/cargo-manifest.js +422 -0
  68. package/node_modules/pi-lens/dist/clients/cascade-logger.js +2 -2
  69. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +13 -3
  70. package/node_modules/pi-lens/dist/clients/complexity-client.js +16 -5
  71. package/node_modules/pi-lens/dist/clients/config-core/deny.js +221 -0
  72. package/node_modules/pi-lens/dist/clients/config-core/index.js +47 -0
  73. package/node_modules/pi-lens/dist/clients/config-core/merge.js +357 -0
  74. package/node_modules/pi-lens/dist/clients/config-core/normalize.js +340 -0
  75. package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +248 -0
  76. package/node_modules/pi-lens/dist/clients/config-core/provenance.js +171 -0
  77. package/node_modules/pi-lens/dist/clients/config-core/records.js +218 -0
  78. package/node_modules/pi-lens/dist/clients/config-core/resolve.js +125 -0
  79. package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +78 -0
  80. package/node_modules/pi-lens/dist/clients/config-core/schema.js +167 -0
  81. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +281 -0
  82. package/node_modules/pi-lens/dist/clients/config-locations.js +160 -0
  83. package/node_modules/pi-lens/dist/clients/config-resolve.js +789 -0
  84. package/node_modules/pi-lens/dist/clients/config-schema.js +197 -0
  85. package/node_modules/pi-lens/dist/clients/config-warn.js +407 -0
  86. package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -14
  87. package/node_modules/pi-lens/dist/clients/dead-code-logger.js +2 -2
  88. package/node_modules/pi-lens/dist/clients/deadline-utils.js +178 -0
  89. package/node_modules/pi-lens/dist/clients/debug-handles.js +2 -2
  90. package/node_modules/pi-lens/dist/clients/debug-heap.js +3 -3
  91. package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +106 -0
  92. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +113 -7
  93. package/node_modules/pi-lens/dist/clients/dependency-checker.js +8 -19
  94. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +12 -9
  95. package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +14 -4
  96. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +162 -18
  97. package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +97 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -7
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -1
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +380 -26
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +0 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -1
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -1
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -1
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -1
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -1
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -1
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -1
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -1
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -1
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +1 -3
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -1
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -1
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -1
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +0 -1
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -1
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -1
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -1
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -1
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -1
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -1
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +13 -18
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -1
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -1
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -1
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -1
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +7 -4
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -1
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +0 -1
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -3
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +0 -1
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -1
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -1
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -1
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -1
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -1
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -1
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -1
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -1
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -1
  143. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -1
  144. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -1
  145. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +3 -0
  146. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +3 -4
  147. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +194 -80
  148. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +84 -15
  149. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -1
  150. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -1
  151. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -1
  152. package/node_modules/pi-lens/dist/clients/disposition-logger.js +3 -3
  153. package/node_modules/pi-lens/dist/clients/effective-config.js +403 -0
  154. package/node_modules/pi-lens/dist/clients/error-class.js +23 -0
  155. package/node_modules/pi-lens/dist/clients/event-loop-hold.js +274 -0
  156. package/node_modules/pi-lens/dist/clients/extension-log.js +2 -2
  157. package/node_modules/pi-lens/dist/clients/feature-hints.js +2 -1
  158. package/node_modules/pi-lens/dist/clients/file-time.js +6 -1
  159. package/node_modules/pi-lens/dist/clients/file-utils.js +112 -9
  160. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +50 -13
  161. package/node_modules/pi-lens/dist/clients/format-service.js +6 -1
  162. package/node_modules/pi-lens/dist/clients/formatters.js +276 -102
  163. package/node_modules/pi-lens/dist/clients/freshness-cadence.js +17 -0
  164. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +114 -19
  165. package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -9
  166. package/node_modules/pi-lens/dist/clients/git-guard.js +1 -1
  167. package/node_modules/pi-lens/dist/clients/go-client.js +39 -0
  168. package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +252 -0
  169. package/node_modules/pi-lens/dist/clients/hashline-anchor.js +424 -0
  170. package/node_modules/pi-lens/dist/clients/hook-budgets.js +76 -0
  171. package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +5 -2
  172. package/node_modules/pi-lens/dist/clients/host-ports.js +1 -1
  173. package/node_modules/pi-lens/dist/clients/installer/index.js +71 -52
  174. package/node_modules/pi-lens/dist/clients/instance-reaper.js +104 -230
  175. package/node_modules/pi-lens/dist/clients/instance-registry.js +6 -3
  176. package/node_modules/pi-lens/dist/clients/language-registry.js +595 -0
  177. package/node_modules/pi-lens/dist/clients/latency-logger.js +160 -2
  178. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +13 -0
  179. package/node_modules/pi-lens/dist/clients/lens-config.js +141 -30
  180. package/node_modules/pi-lens/dist/clients/lens-engine.js +30 -37
  181. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +59 -6
  182. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -2
  183. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +3 -1
  184. package/node_modules/pi-lens/dist/clients/lsp/client.js +168 -30
  185. package/node_modules/pi-lens/dist/clients/lsp/config.js +483 -158
  186. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +1 -1
  187. package/node_modules/pi-lens/dist/clients/lsp/edits.js +15 -2
  188. package/node_modules/pi-lens/dist/clients/lsp/index.js +676 -71
  189. package/node_modules/pi-lens/dist/clients/lsp/language.js +18 -169
  190. package/node_modules/pi-lens/dist/clients/lsp/launch.js +2 -1
  191. package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +5 -16
  192. package/node_modules/pi-lens/dist/clients/lsp/server.js +284 -147
  193. package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +116 -23
  194. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +2 -7
  195. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +9 -2
  196. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +1 -1
  197. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +163 -21
  198. package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +36 -0
  199. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +33 -4
  200. package/node_modules/pi-lens/dist/clients/mcp/session.js +5 -16
  201. package/node_modules/pi-lens/dist/clients/memory-sampler.js +8 -3
  202. package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +2 -4
  203. package/node_modules/pi-lens/dist/clients/module-report.js +20 -45
  204. package/node_modules/pi-lens/dist/clients/mutating-tool.js +651 -0
  205. package/node_modules/pi-lens/dist/clients/mutation-attribution.js +368 -0
  206. package/node_modules/pi-lens/dist/clients/mutation-bridge.js +240 -0
  207. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +247 -20
  208. package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +101 -0
  209. package/node_modules/pi-lens/dist/clients/observed-mutation.js +1215 -0
  210. package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +68 -22
  211. package/node_modules/pi-lens/dist/clients/opengrep-config.js +4 -0
  212. package/node_modules/pi-lens/dist/clients/package-manager.js +195 -26
  213. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +359 -80
  214. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +23 -7
  215. package/node_modules/pi-lens/dist/clients/path-keyed-map.js +21 -2
  216. package/node_modules/pi-lens/dist/clients/path-utils.js +428 -13
  217. package/node_modules/pi-lens/dist/clients/persist-debounce.js +8 -1
  218. package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +114 -0
  219. package/node_modules/pi-lens/dist/clients/pipeline.js +77 -16
  220. package/node_modules/pi-lens/dist/clients/probe-home-state.js +228 -0
  221. package/node_modules/pi-lens/dist/clients/process-bridge.js +66 -0
  222. package/node_modules/pi-lens/dist/clients/process-snapshot.js +68 -0
  223. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +4 -3
  224. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +27 -3
  225. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +51 -20
  226. package/node_modules/pi-lens/dist/clients/project-lens-config.js +393 -122
  227. package/node_modules/pi-lens/dist/clients/project-snapshot.js +52 -24
  228. package/node_modules/pi-lens/dist/clients/python-environment.js +217 -0
  229. package/node_modules/pi-lens/dist/clients/python-provenance.js +639 -0
  230. package/node_modules/pi-lens/dist/clients/quiet-window.js +6 -1
  231. package/node_modules/pi-lens/dist/clients/read-bridge.js +13 -21
  232. package/node_modules/pi-lens/dist/clients/read-expansion.js +9 -46
  233. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +15 -4
  234. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +364 -212
  235. package/node_modules/pi-lens/dist/clients/read-guard.js +21 -0
  236. package/node_modules/pi-lens/dist/clients/resource-sampler.js +195 -96
  237. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +152 -109
  238. package/node_modules/pi-lens/dist/clients/review-graph/service.js +55 -3
  239. package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +7 -15
  240. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +10 -74
  241. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +9 -3
  242. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +18 -2
  243. package/node_modules/pi-lens/dist/clients/runtime-context.js +49 -16
  244. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +25 -6
  245. package/node_modules/pi-lens/dist/clients/runtime-session.js +139 -22
  246. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +168 -35
  247. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +797 -243
  248. package/node_modules/pi-lens/dist/clients/runtime-turn.js +1028 -53
  249. package/node_modules/pi-lens/dist/clients/rust-client.js +31 -0
  250. package/node_modules/pi-lens/dist/clients/safe-spawn.js +33 -10
  251. package/node_modules/pi-lens/dist/clients/sanitize.js +7 -1
  252. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +1 -3
  253. package/node_modules/pi-lens/dist/clients/security-scan-client.js +3 -0
  254. package/node_modules/pi-lens/dist/clients/session-lifecycle.js +1 -1
  255. package/node_modules/pi-lens/dist/clients/session-start-observability.js +79 -0
  256. package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +12 -3
  257. package/node_modules/pi-lens/dist/clients/sgconfig.js +6 -1
  258. package/node_modules/pi-lens/dist/clients/skills-resolver.js +105 -0
  259. package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
  260. package/node_modules/pi-lens/dist/clients/string-utils.js +13 -0
  261. package/node_modules/pi-lens/dist/clients/subagent-mode.js +17 -4
  262. package/node_modules/pi-lens/dist/clients/test-runner-client.js +176 -39
  263. package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +239 -0
  264. package/node_modules/pi-lens/dist/clients/tool-definition.js +41 -1
  265. package/node_modules/pi-lens/dist/clients/tool-policy.js +91 -21
  266. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +40 -40
  267. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +86 -48
  268. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
  269. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +81 -1
  270. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +51 -46
  271. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +28 -0
  272. package/node_modules/pi-lens/dist/clients/typos-config.js +5 -0
  273. package/node_modules/pi-lens/dist/clients/user-notify.js +6 -2
  274. package/node_modules/pi-lens/dist/clients/widget-state.js +191 -26
  275. package/node_modules/pi-lens/dist/clients/word-index-logger.js +2 -2
  276. package/node_modules/pi-lens/dist/clients/word-index-store.js +20 -5
  277. package/node_modules/pi-lens/dist/clients/word-index.js +243 -31
  278. package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -1
  279. package/node_modules/pi-lens/dist/clients/zizmor-config.js +3 -0
  280. package/node_modules/pi-lens/dist/index.js +64335 -54300
  281. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -1
  282. package/node_modules/pi-lens/dist/mcp/server.js +127 -5
  283. package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +583 -0
  284. package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +129 -0
  285. package/node_modules/pi-lens/dist/tools/effective-config.js +89 -0
  286. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +95 -24
  287. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +67 -80
  288. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +37 -16
  289. package/node_modules/pi-lens/dist/tools/shared.js +0 -1
  290. package/node_modules/pi-lens/docs/agent-guide.md +64 -1
  291. package/node_modules/pi-lens/docs/configuration.md +222 -0
  292. package/node_modules/pi-lens/docs/dependencies.md +3 -3
  293. package/node_modules/pi-lens/docs/features.md +44 -5
  294. package/node_modules/pi-lens/docs/language-coverage.md +2 -2
  295. package/node_modules/pi-lens/docs/pi-lens-fixer.md +25 -0
  296. package/node_modules/pi-lens/docs/pi-lens-investigator.md +25 -0
  297. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +27 -0
  298. package/node_modules/pi-lens/docs/pi-lens-subagent.md +38 -0
  299. package/node_modules/pi-lens/docs/pi-lens-warden.md +55 -0
  300. package/node_modules/pi-lens/docs/public-api-stability.md +359 -0
  301. package/node_modules/pi-lens/docs/release-qa-baseline.md +182 -0
  302. package/node_modules/pi-lens/docs/subagent-compat.md +110 -30
  303. package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +2 -2
  304. package/node_modules/pi-lens/package.json +15 -23
  305. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-cross-language-method.yml +3 -3
  306. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-hallucinated-import.yml +2 -2
  307. package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-sql-injection.yml +12 -2
  308. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +192 -1
  309. package/node_modules/pi-lens/scripts/install-selftest.mjs +58 -2
  310. package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +129 -0
  311. package/node_modules/pi-lens/scripts/rpc-load-check.mjs +3 -1
  312. package/node_modules/pi-mcp-adapter/CHANGELOG.md +27 -0
  313. package/node_modules/pi-mcp-adapter/README.md +13 -13
  314. package/node_modules/pi-mcp-adapter/commands.ts +58 -21
  315. package/node_modules/pi-mcp-adapter/config.ts +18 -4
  316. package/node_modules/pi-mcp-adapter/direct-tools.ts +26 -6
  317. package/node_modules/pi-mcp-adapter/dist/config.d.ts +4 -0
  318. package/node_modules/pi-mcp-adapter/dist/config.js +13 -4
  319. package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
  320. package/node_modules/pi-mcp-adapter/dist/types.d.ts +11 -3
  321. package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -1
  322. package/node_modules/pi-mcp-adapter/error-signal.ts +15 -4
  323. package/node_modules/pi-mcp-adapter/errors.ts +141 -0
  324. package/node_modules/pi-mcp-adapter/host-html-template.ts +58 -5
  325. package/node_modules/pi-mcp-adapter/index.ts +2 -3
  326. package/node_modules/pi-mcp-adapter/init.ts +5 -0
  327. package/node_modules/pi-mcp-adapter/mcp-panel.ts +30 -9
  328. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +66 -28
  329. package/node_modules/pi-mcp-adapter/mcp-status.ts +2 -0
  330. package/node_modules/pi-mcp-adapter/package.json +2 -1
  331. package/node_modules/pi-mcp-adapter/proxy-modes.ts +66 -13
  332. package/node_modules/pi-mcp-adapter/sandbox-proxy-template.ts +217 -0
  333. package/node_modules/pi-mcp-adapter/server-manager.ts +337 -6
  334. package/node_modules/pi-mcp-adapter/skills/mcp-scripting/SKILL.md +1 -0
  335. package/node_modules/pi-mcp-adapter/types.ts +18 -3
  336. package/node_modules/pi-mcp-adapter/ui-resource-handler.ts +18 -2
  337. package/node_modules/pi-mcp-adapter/ui-server.ts +179 -54
  338. package/node_modules/pi-mcp-adapter/ui-session.ts +28 -8
  339. package/node_modules/pi-web-access/CHANGELOG.md +28 -0
  340. package/node_modules/pi-web-access/README.md +62 -15
  341. package/node_modules/pi-web-access/curator-page.ts +3 -1
  342. package/node_modules/pi-web-access/curator-server.ts +5 -1
  343. package/node_modules/pi-web-access/gemini-search.ts +8 -4
  344. package/node_modules/pi-web-access/github-extract.ts +242 -1
  345. package/node_modules/pi-web-access/index.ts +118 -64
  346. package/node_modules/pi-web-access/mistral-search.ts +281 -0
  347. package/node_modules/pi-web-access/package.json +2 -2
  348. package/node_modules/pi-web-access/perplexity.ts +14 -1
  349. package/node_modules/pi-web-access/utils.ts +23 -6
  350. package/node_modules/pi-web-access/xai-search.ts +96 -33
  351. package/package.json +15 -11
@@ -53,6 +53,43 @@ so the final state is formatter-stable. A `write` immediately followed by an
53
53
  deferred too. See `clients/pipeline.ts`, `clients/runtime-tool-result.ts`, and
54
54
  `clients/runtime-agent-end.ts`.
55
55
 
56
+ A tool pi-lens does not name is classified by the SHAPE of its arguments
57
+ (`clients/mutating-tool.ts`). A host or extension edit tool called `replace` or
58
+ `insert` therefore gets a turn-state entry, a change-log receipt attributed to
59
+ the tool itself, and the deferred autofix and format pass — the same chain
60
+ `edit` gets. Its lines are resolved when the anchor is unambiguous (roughly
61
+ two-thirds of anchors in practice — `clients/hashline-anchor.ts`); otherwise
62
+ the mutation is recorded whole-file with lines unknown, and the
63
+ read-before-edit guard takes its no-line-info arm rather than guessing.
64
+ Deferred is the default for any edit-shaped tool pi-lens cannot place, because
65
+ formatting between the calls of a multi-step rewrite fights the tool that is
66
+ still writing. A tool whose SHAPE is unrecognized too is caught by observation:
67
+ pi-lens takes a bounded snapshot of the path that call names — and only that
68
+ path, so a change to a neighbouring file is never blamed on it — replays
69
+ whatever actually changed through the same chain, then remembers that tool as
70
+ mutating for the session, and on disk under the project's data directory once a
71
+ second observation confirms it, so later sessions classify it by name with no
72
+ snapshot at all. A tool that names no file is caught at `agent_settled` by an
73
+ incremental content check over the files pi-lens has already read, written,
74
+ diagnosed or opened on a language server: a rotating window of the set each
75
+ turn, reading only the files whose size or timestamp actually moved, so the
76
+ check stays affordable as the set grows. A file it has never seen has no
77
+ baseline and is therefore not covered, and a file it cannot verify is named
78
+ rather than reformatted on a timestamp alone
79
+ (`clients/observed-mutation.ts`).
80
+
81
+ **Bundled fallback lint configs stay conservative.** When a project ships no
82
+ tool config, the package-owned fallback configs set the rules (`config/biome/core.jsonc`,
83
+ `config/ruff/core.toml`, `config/markdownlint/core.json`). The biome fallback
84
+ disables `useImportType`: its safe fix rewrites a value import used only in
85
+ type positions into `import type`, which erases the runtime binding that
86
+ experimental decorator metadata (`emitDecoratorMetadata`) still needs and
87
+ breaks decorator-based dependency injection (refs #2385). Every other
88
+ recommended rule stays on, and an explicit project `biome.json(c)` remains
89
+ authoritative: if you enable `useImportType` there, pi-lens does not override
90
+ it. The ruff fallback selects no flake8-type-checking (TC) rules and applies
91
+ only safe fixes, so it never hoists imports into `TYPE_CHECKING` blocks.
92
+
56
93
  Deferred formatting (the `agent_end` default) runs with **bounded
57
94
  concurrency**: at most three formatter subprocesses in flight at once, with
58
95
  results applied in admission order and cooperative yields between files, so a
@@ -140,12 +177,14 @@ pi-lens MCP server expose the same shape to Claude Code / any MCP client.
140
177
 
141
178
  ### Actionable Warnings
142
179
 
143
- At `turn_end`, pi-lens writes `.pi-lens/cache/actionable-warnings.json` summarizing fixable warnings introduced by the current turn. This powers the optional conservative autofix at `agent_end`.
180
+ At `turn_end`, pi-lens writes `<project-data-dir>/cache/actionable-warnings.json` summarizing fixable warnings introduced by the current turn. This powers the optional conservative autofix at `agent_end`.
181
+
182
+ `<project-data-dir>` is whatever `getProjectDataDir(cwd)` resolves to: `<project>/.pi-lens` only when that legacy directory already exists, otherwise `~/.pi-lens/projects/<project-slug>` (or a `PILENS_DATA_DIR` location). The turn-end advisory points at `lens_diagnostics mode=delta` first and names the resolved file second, so you never have to work the layout out by hand (#2521).
144
183
 
145
184
  **Report contents:**
146
185
 
147
186
  - Warnings are delta-only by default: only diagnostics in lines touched during the current turn are included. Pass `--lens-actionable-warning-all` to report all warnings regardless of location
148
- - Each warning carries a stable `aw:<hash>` ID derived from file, rule, and message, so suppression state persists across turns in `.pi-lens/cache/actionable-warning-state.json`
187
+ - Each warning carries a stable `aw:<hash>` ID derived from file, rule, and message, so suppression state persists across turns in `<project-data-dir>/cache/actionable-warning-state.json`
149
188
  - Sources: pipeline `fixable` diagnostics (always included) and LSP code-action warnings when `--lens-actionable-warning-actions` is set
150
189
  - When warnings are present, a concise advisory is injected into the agent context (no blocker language)
151
190
 
@@ -354,14 +393,14 @@ pi-lens ships an MCP (Model Context Protocol) server so Claude Code — or any M
354
393
 
355
394
  **Why a second host:** the pi extension's tools are registered via the host SDK and run on pi's event loop. Claude Code lives in a different process with no SDK access. The MCP server sits in that gap, speaking JSON-RPC over stdio (or a warm Unix socket / Windows named pipe side-channel for the Claude Code PostToolUse hook). It's the easiest way to live-test, debug, and dogfood pi-lens — including running a **review loop** where Claude commits to pi-lens and re-measures.
356
395
 
357
- **16 tools, grouped by lifecycle layer** (the same three layers the pi agent hooks use):
396
+ **18 tools, grouped by lifecycle layer** (the same three layers the pi agent hooks use):
358
397
 
359
398
  | Layer | MCP tools | What they expose |
360
399
  |---|---|---|
361
- | **Per-edit** | `pilens_analyze`, `pilens_lsp_diagnostics`, `pilens_lsp_navigation`, `pilens_ast_grep_search`, `pilens_ast_grep_replace`, `pilens_module_report`, `pilens_read_symbol` | The fast pipeline (format → autofix → LSP diagnostics → parallel runners) plus the structured read-substitute pair. `analyze` accepts `mode: warm \| fresh` — `warm` reuses the server's in-process LSP, `fresh` forks a worker that loads freshly-built code from disk so the result reflects the latest commit. |
400
+ | **Per-edit** | `pilens_analyze`, `pilens_lsp_diagnostics`, `pilens_lsp_navigation`, `pilens_ast_grep_search`, `pilens_ast_grep_replace`, `pilens_module_report`, `pilens_read_symbol`, `pilens_read_enclosing` | The fast pipeline (format → autofix → LSP diagnostics → parallel runners) plus the structured read-substitute pair. `analyze` accepts `mode: warm \| fresh` — `warm` reuses the server's in-process LSP, `fresh` forks a worker that loads freshly-built code from disk so the result reflects the latest commit. |
362
401
  | **Per-turn** | `pilens_turn_end` | Drives the **real** `handleTurnEnd` (knip incremental, dep-circular, cascade, tests, actionable+code-quality warnings) — not a re-implementation. Caller-supplied edited files are auto-registered into turn-state via `addModifiedRange`. |
363
402
  | **Per-session** | `pilens_session_start` | Drives the **real** `handleSessionStart` — full jscpd/knip/madge/govulncheck/gitleaks/trivy scans + complexity baselines + LSP warm. The error-debt baseline is not currently populated by the production session-start path. |
364
- | **Project / observability** | `pilens_project_scan`, `pilens_diagnostics`, `pilens_health`, `pilens_latency`, `pilens_symbol_search` | Cheap project-wide scans, cached diagnostic state, latency telemetry, ranked identifier search (BM25 over the persisted word index — see [docs/word-index.md](word-index.md)). Cross-file blast radius now lives in `pilens_module_report`'s `blastRadius` option. `pilens_health` (and its pi-side `/lens-health` counterpart) also reports a bounded, process-local **degradation ledger** — trust refusals, mode suppressions, LSP breaker trips, formatter skips/failures, TypeScript/word-index/review-graph/project-snapshot idle evictions, WASM aborts, and diagnostics-timeout tallies — so silently degraded behavior stays visible instead of vanishing into a log. |
403
+ | **Project / observability** | `pilens_project_scan`, `pilens_project_report`, `pilens_diagnostics`, `pilens_health`, `pilens_latency`, `pilens_symbol_search`, `pilens_effective_config` | Cheap project-wide scans, cached diagnostic state, latency telemetry, ranked identifier search (BM25 over the persisted word index — see [docs/word-index.md](word-index.md)). Cross-file blast radius now lives in `pilens_module_report`'s `blastRadius` option. `pilens_health` (and its pi-side `/lens-health` counterpart) also reports a bounded, process-local **degradation ledger** — trust refusals, mode suppressions, LSP breaker trips, formatter skips/failures, TypeScript/word-index/review-graph/project-snapshot idle evictions, WASM aborts, and diagnostics-timeout tallies — so silently degraded behavior stays visible instead of vanishing into a log. `pilens_effective_config` answers **“why is X running / why is X not running”** from one query — the resolved configuration with the provenance of every setting, and for a file you name, its language plus every LSP server with the reason it was selected or denied and the runners that would dispatch. It reports sources, never values. |
365
404
  | **Lifecycle / loop** | `pilens_rebuild` | Runs `npm run build:dist` so `pilens_analyze mode=fresh` reflects the latest commit. Makes the review loop self-contained: commit → `pilens_rebuild` → `pilens_analyze mode=fresh` → `pilens_latency`. |
366
405
 
367
406
  **Honest limits** (live-tested, documented in `mcp.md`):
@@ -17,8 +17,8 @@ Dispatch is diagnostics-oriented: automatic formatting and safe autofix happen i
17
17
  | Shell | ✓ | lsp, shellcheck | shfmt |
18
18
  | Fish | ✓ (fish-lsp) | lsp, fish-indent | fish_indent |
19
19
  | CSS/SCSS/Less | ✓ | lsp, stylelint | biome, prettier |
20
- | HTML | ✓ | lsp, htmlhint | prettier |
21
- | YAML | ✓ | lsp, yamllint, actionlint (GitHub workflows), trivy-config (opt-in; Kubernetes manifests, CloudFormation) | prettier |
20
+ | HTML | ✓ | lsp, htmlhint | prettier (with project config) |
21
+ | YAML | ✓ | lsp, yamllint, actionlint (GitHub workflows), trivy-config (opt-in; Kubernetes manifests, CloudFormation) | prettier (with project config) |
22
22
  | JSON | ✓ | lsp, trivy-config (opt-in; CloudFormation templates only) | biome, prettier |
23
23
  | Svelte | ✓ | lsp | oxfmt (needs `svelte` pkg installed + config `svelte: true`) |
24
24
  | Vue | ✓ | lsp | prettier, oxfmt |
@@ -0,0 +1,25 @@
1
+ # Fixer contract
2
+
3
+ Deliver a root-caused fix with red proof and a reviewable handoff.
4
+
5
+ Read the issue, repository instructions, shared delegated worker contract, and
6
+ relevant architecture before editing. Reuse the shared seam and existing
7
+ machinery. Keep the change localized and compatible with concurrent branches.
8
+
9
+ Build the smallest faithful reproduction first. Preserve its pre-fix failure
10
+ output. After fixing, prove every new guard mutation-sensitive. Run a pattern
11
+ sweep and a population sweep for the defect class. Record per-member verdicts,
12
+ the blast radius, and bounded observability. Add a changelog fragment for a code
13
+ change.
14
+
15
+ ## Tautological tests considered harmful
16
+
17
+ Do not assert a value that the test setup already supplied, duplicate the source
18
+ predicate in the test, or replace a real in-process seam with a fake to keep the
19
+ test green. Drive the production path and assert an independent observable. If
20
+ the test passes after deleting the guard, it is tautological and must be
21
+ redesigned before the fix is complete.
22
+
23
+ Verify the build and every targeted or sibling suite required by repository
24
+ policy. Follow the shared contract's Git authority. Report what ran, what was
25
+ skipped, and why. Use active, plain prose.
@@ -0,0 +1,25 @@
1
+ # Investigator contract
2
+
3
+ Root-cause runtime behavior from reproducible and durable evidence.
4
+
5
+ Define the symptom as a question that evidence can answer. Name the time window,
6
+ sessions, and build in scope. Prefer a tight reproduction loop before code
7
+ reading. Correlate records by stable identifiers, not time alone. Read each
8
+ record's producer before trusting its labels. Count a representative population,
9
+ and separate worker behavior from daemon behavior.
10
+
11
+ Keep the investigation read-only. Rank falsifiable hypotheses with evidence for
12
+ and against each hypothesis and the observation that would settle it. Sweep the
13
+ tree for the root-cause pattern and every member of the affected population.
14
+ State the blast radius and any missing or unbounded observability.
15
+
16
+ Deliver a proven diagnosis and a concrete next step. If the task expands to an
17
+ implementation, stop and return it to the orchestrator for a fixer delegation.
18
+ Use concise, active, plain prose.
19
+
20
+ ## Tautological tests considered harmful
21
+
22
+ Treat a probe as evidence only when it can distinguish the competing hypotheses.
23
+ Do not seed the asserted outcome, mirror the production predicate, or rely on a
24
+ mock where the real in-process seam is available. Record the observation that
25
+ would turn the hypothesis red, and preserve that distinction in the handoff.
@@ -0,0 +1,27 @@
1
+ # Reviewer contract
2
+
3
+ Adversarially verify a change before merge and report proven findings.
4
+
5
+ Assume the implementation's claims are incomplete. Read the issue, full diff,
6
+ repository instructions, shared delegated worker contract, PR body, and merge
7
+ state. Keep the review read-only.
8
+
9
+ Reproduce the build and targeted tests. Verify quoted red-first evidence by
10
+ keeping the tests and removing the source fix. Mutate every new guard and demand
11
+ a red test. Probe inversions, concurrency, input channels, trust boundaries,
12
+ strict consumers, and durable-record compatibility. Repeat the pattern and
13
+ population sweeps. Check the stated blast radius, bounded observability,
14
+ changelog fragment, commit shape, and PR conventions.
15
+
16
+ Report `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, then `NITPICK` findings. Give the
17
+ file and line, a concrete failure, evidence, and a suggested fix. Separate issue
18
+ acceptance findings from repository-standard findings. List cleared categories,
19
+ then record one verdict: merge as-is, merge after fixes, or redesign. Never
20
+ merge or silently repair the author's branch. Use short, active, plain prose.
21
+
22
+ ## Tautological tests considered harmful
23
+
24
+ Check that each regression test reaches the real seam and observes an independent
25
+ effect. Remove or mutate the claimed guard and require the test to fail for the
26
+ intended reason. Flag tests that restate the implementation, assert setup data,
27
+ or swap a real in-process store, sink, coordinator, or registry for a fake.
@@ -0,0 +1,38 @@
1
+ # Delegated worker delivery contract
2
+
3
+ This contract applies to every delegated pi-lens worker, regardless of the
4
+ agent runner or model. Pair it with exactly one role contract: fixer, reviewer,
5
+ or investigator.
6
+
7
+ Work only in the assigned worktree. Before editing, verify its absolute path,
8
+ registered worktree entry, branch, and base. Preserve junctioned dependencies.
9
+ Never switch another checkout's branch, and never use `git stash`. Save a patch
10
+ before temporarily reverting work.
11
+
12
+ Treat the acceptance criteria as the contract. For a regression, prove the new
13
+ test red before the fix and green after it. Mutating or removing a new guard
14
+ must make at least one test fail. Sweep the whole tree for the same code pattern
15
+ and every member of any enumerable population. Record both sweeps.
16
+
17
+ State the blast radius, including callers, durable shapes, strict parsers, and
18
+ tool surfaces. Add bounded observability for every new failure path. Include the
19
+ required changelog fragment for a code change. Report verification honestly.
20
+ Write active, direct prose with short sentences and consistent terms.
21
+
22
+ ## Tautological tests considered harmful
23
+
24
+ A test must observe behavior through the real seam, not repeat the implementation
25
+ or feed the expected answer in through setup. Keep the red-first failure tied to
26
+ the defect, and mutate the guard or filter to prove the test can detect its loss.
27
+ Mocks belong only at true process or host boundaries. When a test can use the
28
+ real store, sink, coordinator, or registry, use it and assert the durable result.
29
+
30
+ Git authority is separate from the role. Commit, push, or open a PR only when
31
+ the delegation explicitly grants that authority after worktree verification.
32
+ Otherwise, edit and test with the assigned worktree as the command working
33
+ directory, then return the patch and evidence to the orchestrator. Never merge.
34
+
35
+ When Git authority is granted, use one logical commit with an imperative,
36
+ conventional-prefix subject of at most 50 characters, a blank line, and a
37
+ 72-column body that states what and why. Reference the issue. Open a PR, do not
38
+ merge it, and report its URL.
@@ -0,0 +1,55 @@
1
+ # PR warden contract
2
+
3
+ Keep every pull request moving through review, fix, verification, and merge.
4
+
5
+ The warden is a read-only workflow controller. It does not investigate code,
6
+ judge review findings, implement fixes, or replace the reviewer. Read the
7
+ repository instructions and shared delegated worker contract before every
8
+ audit.
9
+
10
+ Build the ledger from GitHub and registered worktree evidence. For every pull
11
+ request, record the exact head SHA, matching worktree, dirty or unpushed state,
12
+ mergeability, required checks on that SHA, review outcome, active owner, and
13
+ next action. Use one state from this closed set:
14
+
15
+ - `UNREVIEWED`
16
+ - `REVIEW_FINDINGS`
17
+ - `FIXING`
18
+ - `AWAITING_VERIFY`
19
+ - `AWAITING_COMMIT_PUSH`
20
+ - `CI_PENDING`
21
+ - `CI_REAL_FAILURE`
22
+ - `CI_INFRA_FAILURE`
23
+ - `READY_AUTOMERGE`
24
+ - `MERGED`
25
+
26
+ A worker result becomes durable workflow evidence only when the orchestrator
27
+ records its role, exact head or working-tree identity, verdict, dispositions,
28
+ and next owner on the pull request or another shared ledger. Chat-only results
29
+ cannot drive a later audit. Flag a missing durable handoff record instead of
30
+ guessing that review passed.
31
+
32
+ Assign an owner and next action whenever the state changes. Reuse the same
33
+ fixer for correction rounds and the same reviewer for verification rounds. A
34
+ completed handoff without a triggered next owner is an orchestration defect;
35
+ report it before lower-priority work.
36
+
37
+ Run the audit after every worker completion, push, review verdict, CI verdict,
38
+ merge, and user status request. Poll GitHub and persistent external-worker
39
+ handles when completion notifications are unavailable. Never infer completion
40
+ from a quiet worker or clean worktree.
41
+
42
+ Classify required CI from its log and exact head. Treat assertion failures and
43
+ `[mem-watch] done. exitCode=1` as real. Apply the repository's exit-137 rules
44
+ before calling a failure infrastructure. Do not treat SonarCloud or another
45
+ advisory lane as a merge gate. A skipped required job is not green.
46
+
47
+ Mark `READY_AUTOMERGE` only when the actual final head has passed required CI
48
+ and adversarial review, every material finding has a disposition, and every
49
+ substantive fix has passed the same-reviewer verification loop. The
50
+ orchestrator, not the warden, commits, pushes, comments, enables automerge, or
51
+ merges.
52
+
53
+ Return a compact transition table followed by a priority queue. Name
54
+ orchestration breaches separately. Provide exact safe commands when they help
55
+ the orchestrator, but make no repository or GitHub mutation.
@@ -0,0 +1,359 @@
1
+ # Public API stability and versioning policy
2
+
3
+ **Status:** normative. Landed by #2418; gates #2416.
4
+ **Enforced by:** `clients/config-diagnostic-codes.ts` (the data),
5
+ `tests/support/schema-stability.ts`, `tests/config/schema-stability-tiers.test.ts`,
6
+ `tests/clients/config-diagnostic-codes.test.ts`,
7
+ `tests/clients/config-deprecation-registry.test.ts` (the tests).
8
+
9
+ pi-lens ships to roughly 28k installs a month. A config field, a warning a user
10
+ greps for, or a tool id becomes a compatibility obligation the moment it ships —
11
+ whether or not anyone wrote that obligation down. This document writes it down,
12
+ and every clause below is backed by a test rather than by convention, because a
13
+ policy nobody can fail is not a policy.
14
+
15
+ Scope: the unified config schema (#2415/#2416/#2383/#195), the capability
16
+ facades, the MCP tool mirror, and the versioned `PiLensApi` (#1358). It does not
17
+ define any catalog schema; it constrains how those schemas evolve.
18
+
19
+ ## 1. Field stability tiers
20
+
21
+ Every property in a published pi-lens schema carries an `x-stability`
22
+ annotation, whose value is one of a closed vocabulary:
23
+
24
+ | Tier | Meaning |
25
+ | --- | --- |
26
+ | `experimental` | May change shape, semantics, or disappear in a **minor** release. Not covered by the compatibility guarantee. |
27
+ | `stable` | Covered by the guarantee. Shape and semantics change only in a **major**, through the checklist in section 4. |
28
+
29
+ Rules:
30
+
31
+ - **New fields default to `experimental`.** Shipping a field straight to
32
+ `stable` is a deliberate act, not a default.
33
+ - **Promotion `experimental` → `stable` is changelogged** under `Changed`,
34
+ naming the field. Demotion `stable` → `experimental` is a breaking change and
35
+ follows section 4.
36
+ - **A property with no tier fails CI.** `assertSchemaStabilityTiers` walks the
37
+ whole schema — `properties`, `patternProperties`, `items`, `prefixItems`,
38
+ `additionalProperties`, `oneOf`/`anyOf`/`allOf`, `not`, `if`/`then`/`else`,
39
+ `$defs`/`definitions` — so a field cannot hide from the tier requirement by
40
+ living inside a composition keyword.
41
+ - The **root schema** is not itself a property and carries no tier. Entries
42
+ under `$defs`/`definitions` are reusable subschemas, not published fields;
43
+ they need no tier, but every property *inside* them does.
44
+
45
+ The vocabulary lives in `STABILITY_TIERS` and the annotation key in
46
+ `STABILITY_TIER_KEY` (`clients/config-diagnostic-codes.ts`). #2416's first real
47
+ catalog schema asserts itself with the same two exported functions rather than
48
+ writing a second walker.
49
+
50
+ ## 2. Stable config diagnostic codes
51
+
52
+ Every user-facing config validation or migration warning carries a code from a
53
+ closed, **append-only** namespace, `PILENS_CFG_NNNN`, registered once in
54
+ `CONFIG_DIAGNOSTIC_CODES`.
55
+
56
+ - **The prose is not API; the code is.** Message text may be rewritten in any
57
+ release. A code is never renumbered, never removed, and a retired number is
58
+ never reused — a retired code keeps its registry entry with an amended
59
+ description.
60
+ - The code is threaded through the one durable choke point
61
+ (`recordDegradationOnce` / `incrementDegradationCount` in
62
+ `clients/degradation-ledger.ts`) and through `notifyUserDegradation`, so the
63
+ same code appears in the user-visible message, in `extension.log`, and in the
64
+ durable `latency.log` degradation row.
65
+ - The durable row writes `code` **after** the bounded caller metadata, so the
66
+ ledger's `MAX_METADATA_KEYS` cap can never evict the one field a user greps
67
+ on.
68
+ - A new `notifyUserDegradation` call from any `clients/**/*config*.ts` file
69
+ without a registered code fails CI
70
+ (`tests/clients/config-diagnostic-codes.test.ts` scans for it; it does not
71
+ keep a hand-maintained list of call sites).
72
+
73
+ ### How a user matches or suppresses a warning
74
+
75
+ **The match key is the bracketed suffix, not the prose.** Every coded warning is
76
+ rendered as:
77
+
78
+ ```
79
+ pi-lens: ignoring invalid LSP config .pi-lens/lsp.json: Unexpected token } [PILENS_CFG_0001]
80
+ ```
81
+
82
+ The trailing ` [PILENS_CFG_NNNN]` marker is appended by
83
+ `withConfigDiagnosticCode`, is idempotent, and is always last. Match on it:
84
+
85
+ ```sh
86
+ # every ignored-config warning this session, from the durable degradation log
87
+ grep 'PILENS_CFG_0001' ~/.pi-lens/latency.log
88
+
89
+ # suppress one code while keeping every other pi-lens warning
90
+ pi ... 2>&1 | grep -v 'PILENS_CFG_0001'
91
+ ```
92
+
93
+ The extraction pattern is exported as `CONFIG_DIAGNOSTIC_MARKER_PATTERN`
94
+ (capture group 1 is the code) so tooling need not re-derive it. Anything that
95
+ filters on the prose instead — `"ignoring invalid"` — is filtering on a string
96
+ this policy explicitly reserves the right to change.
97
+
98
+ ### Registered codes
99
+
100
+ | Code | Meaning | Emitter |
101
+ | --- | --- | --- |
102
+ | `PILENS_CFG_0001` | A config file exists but could not be read or parsed, so it is ignored. | `warnIgnoredConfigOnce` (`clients/config-warn.ts`), the single choke point behind the LSP, global, and project config loaders. |
103
+ | `PILENS_CFG_0002` | A deprecated config **key** was accepted inside its deprecation window. | `deprecationRecords` (`clients/config-resolve.ts`), one record per `(file, key)`, delivered by `reportPiLensConfigRecords` (#2426). |
104
+ | `PILENS_CFG_0003` | A deprecated config **file location** was read inside its window. | Same producer and same delivery path as `PILENS_CFG_0002`. |
105
+ | `PILENS_CFG_0004` | A config field no schema property claims was dropped. | `validate()` (`clients/config-core/normalize.ts`) produces the record; `reportPiLensConfigRecords` (`clients/config-resolve.ts`) delivers it through `warnIgnoredConfigOnce` (#2426). |
106
+ | `PILENS_CFG_0005` | A config field's value did not match its schema and was dropped. One FIELD; the rest of the file is in effect. | Same producer and same delivery path as `PILENS_CFG_0004`. |
107
+ | `PILENS_CFG_0006` | A config key that would modify an object's prototype (`__proto__`, `constructor`, `prototype`) was refused. | Both halves of the config core, through the shared policy in `clients/config-core/safe-object.ts`. |
108
+ | `PILENS_CFG_0007` | Further config notices were suppressed by a bound, and this one carries the count — the WHOLE count, including anything an earlier bound in the same pipeline dropped. Nothing about the config is wrong; the notice list was truncated. | `MigrationRecordCollector.finalize` (`clients/config-core/records.ts`) — the ONE producer, reached through `finalizeRecords` by every record list: the shared resolution, the global loader's unknown-key scan, the project loader's unknown-key scan, and its legacy-document enumeration. Rendered with neutral prose and recorded under the `config-notice-suppressed` degradation kind, never `config-ignored`. |
109
+ | `PILENS_CFG_0008` | Resolving a config failed internally, so the WHOLE file was ignored and pi-lens ran on defaults. | The two guards under the pipeline: `resolveConfig` (`clients/config-core/resolve.ts`) and the global loader's post-parse catch (`clients/lens-config.ts`). Carries the error class only, never its message. |
110
+
111
+ A reserved code is registered and referenced by the deprecation registry, but
112
+ nothing emits it today. That is deliberate: the number must be pinned before the
113
+ migration warning ships, because append-only means the number cannot be chosen
114
+ later.
115
+
116
+ ## 3. Config-envelope identity anchor
117
+
118
+ The unified config format reserves a `$schema` URL from its first published
119
+ version. Both halves are pinned in `clients/config-diagnostic-codes.ts`:
120
+
121
+ - `CONFIG_SCHEMA_ID` — the canonical schema URL. The published schema's own
122
+ `$id` must equal it.
123
+ - `CONFIG_SCHEMA_ANCHOR_KEY` (`"$schema"`) — the key a user's config file uses
124
+ to name the schema it was written against.
125
+
126
+ `assertSchemaIdentityAnchor` checks all three facts: the schema's `$id` matches,
127
+ the schema declares a meta-schema, and the root declares a `$schema` **instance**
128
+ property so a user's file can carry the anchor. Pinning the URL in one module is
129
+ what stops it drifting between the schema, the validator, and the docs.
130
+
131
+ ## 4. Deprecation window and removal checklist
132
+
133
+ ### The maintainer stance
134
+
135
+ **A legacy source is read for exactly one deprecation window, and then it is
136
+ actually removed.** pi-lens does not carry legacy config surfaces forever, and
137
+ it does not silently drop them either. Both failure modes are ruled out by the
138
+ same rule: while a surface is inside its window it is read and honored exactly
139
+ as before, with a bounded coded warning; at the next major it is removed through
140
+ the checklist below, announced in `Removed`. Nothing is ever dropped without an
141
+ announced window that preceded it.
142
+
143
+ ### The data
144
+
145
+ Every deprecated key or file location is a row in `DEPRECATED_CONFIG_SURFACES`
146
+ carrying `surface`, `kind`, `code`, `deprecatedSince`, `removeNotBefore`, and a
147
+ `reason`. The registry test enforces:
148
+
149
+ - `deprecatedSince` names the release that **announces** the deprecation — for a
150
+ row announced only in an unreleased `.changelog/` fragment, that must be a
151
+ version later than the newest release in `CHANGELOG.md` (you cannot back-date
152
+ a deprecation into a version that already shipped without it);
153
+ - `removeNotBefore` is a **later major**, `X.0.0` — removal never happens in a
154
+ minor;
155
+ - the row's code is registered, and matches its kind;
156
+ - the surface is announced in a Changelog `Deprecated` section as a delimited
157
+ token (`` `pi-lens.json` ``), so a substring of a longer filename does not
158
+ count as an announcement;
159
+ - FILE rows name a location a loader actually reads, and KEY rows name a key the
160
+ `LSPConfig` interface actually declares — both checked against the exported
161
+ constants and the real interface body, never a hand-copied list.
162
+
163
+ Note that a canonical file is not deprecated because some of its keys are.
164
+ `.pi-lens.json` is a canonical location (#2426); the deprecated surfaces are the
165
+ legacy top-level LSP keys read from it, which are `kind: "key"` rows.
166
+
167
+ ### The removal checklist
168
+
169
+ This is the checklist #2372 slice 5's "separately approved breaking-change plan"
170
+ instantiates. It does not invent a second process; slice 5 is one execution of
171
+ this list.
172
+
173
+ 1. **Window elapsed.** The current version is at or past the row's
174
+ `removeNotBefore`, and that version is a major.
175
+ 2. **Announced.** The surface has been in a shipped `Deprecated` changelog
176
+ section since `deprecatedSince`, continuously.
177
+ 3. **Warned in-product.** The migration warning has been emitting its stable
178
+ code for the whole window — the user has had a coded, greppable signal, not
179
+ only a release note.
180
+ 4. **Migration path documented and reachable.** The replacement surface exists,
181
+ is `stable`, and the `reason` field names it.
182
+ 5. **Canonical-wins collision behavior verified.** For the whole window, a
183
+ config setting both the legacy and the canonical surface resolved to the
184
+ canonical one, with the coded warning naming the ignored legacy value.
185
+ 6. **Removal PR does all four:** deletes the reader, deletes the registry row,
186
+ adds a `Removed` changelog entry naming the surface and the replacement, and
187
+ keeps the diagnostic code registered (codes outlive the surfaces they
188
+ described).
189
+ 7. **Approved as a breaking change.** A major-version bump plus explicit
190
+ maintainer approval on the plan; a removal never rides in on an unrelated PR.
191
+
192
+ Removing a row from `DEPRECATED_CONFIG_SURFACES` while the reader still exists,
193
+ or removing the reader while the row still exists, fails the registry test. The
194
+ two move together or not at all.
195
+
196
+ ## 5. The config core
197
+
198
+ `clients/config-core/` is the one place a pi-lens configuration is validated,
199
+ merged, and explained. Every loader, catalog, and selector resolves through it
200
+ (#2425); a fourth merge semantics is a defect, not a design choice.
201
+
202
+ The pipeline is `RawConfig -> validate(schema) -> NormalizedConfig ->
203
+ merge(sources) -> Resolved<T>`, and `resolveConfig` runs both halves. It is
204
+ pure: no file reads, no logging, no ledger writes. Reporting is the separate,
205
+ explicit `reportPiLensConfigRecords` step (`clients/config-resolve.ts`, which is
206
+ where the loaders share it — never inside the core), so the warn-once latch
207
+ stays with the loaders rather than with the library.
208
+
209
+ Every loader reports **every** record its own resolution produced — it does not
210
+ filter to the records it "owns". Ownership is a property of the RECORD, not of
211
+ the caller: `reportPiLensConfigRecords` derives the reporting subsystem from the
212
+ record's own owner and tier, so an `lsp.*` key always reports as an LSP setting
213
+ and a pi-lens key always reports under the loader for its tier, whichever loader
214
+ happened to open the file. A `(file, key)` that three loaders all resolve is
215
+ reported three times and the warn-once latch — keyed on
216
+ `(subsystem, file, key, reason)` — collapses those into the one notice the user
217
+ sees. Filtering by caller instead is what left a record no loader claimed
218
+ reported by nobody at all (#2426 review round 3, F1).
219
+
220
+ ### Source tiers
221
+
222
+ Seven tiers, lowest value-precedence first. A later tier's value replaces an
223
+ earlier one for the same leaf.
224
+
225
+ | Tier | Class | Meaning |
226
+ | --- | --- | --- |
227
+ | `builtin` | **default** | pi-lens's own shipped defaults. |
228
+ | `global` | operator | The user's machine-global config. |
229
+ | `project` | **repo** | A config file inside the checkout. |
230
+ | `nested-project` | **repo** | A config file in a nested package. |
231
+ | `env` | operator | Environment variables. |
232
+ | `cli` | operator | Command-line arguments. |
233
+ | `host` | operator | The host application's decision. |
234
+
235
+ The class column is a second, independent axis, and it has **three** values, not
236
+ two. `repo` tiers carry content that arrived with a checkout — content a user
237
+ may never have read. `operator` tiers are a deliberate act by the person running
238
+ pi-lens. `default` is pi-lens's own shipped opinion, which nobody chose. Only the
239
+ class decides who may lift a denial; `builtin` being its own class is what keeps
240
+ a shipped default overridable by the operator while still out of reach of
241
+ repository content.
242
+
243
+ ### Monotonic deny precedence
244
+
245
+ A schema node marked `x-deny` resolves by denial rules instead of
246
+ last-tier-wins:
247
+
248
+ - `x-deny: "boolean-false"` — a `false` from an **operator** tier is never
249
+ lifted, by anything. A `false` from a `default` or `repo` tier is lifted only
250
+ by an explicit `true` from an **operator** tier of higher precedence. A repo
251
+ tier never lifts a denial at all, its own class included.
252
+ - `x-deny: "array-union"` — the resolved list is the union of every tier's
253
+ members. There is no vocabulary for un-denying a member, so a nearer tier that
254
+ omits one is expressing nothing. This outranks the node's own
255
+ `x-merge-strategy`: a denial a merge strategy could erase would not be
256
+ monotonic.
257
+
258
+ Provenance for a denied leaf names the tier that **made** the denial, not the
259
+ last tier to restate it — the answer to "why can I not turn this back on".
260
+
261
+ Two consequences are deliberate rulings rather than accidents of the algorithm,
262
+ and both are load-bearing:
263
+
264
+ **A built-in denial is a default, not a law.** `builtin: false` plus
265
+ `global: true` resolves to `true`, attributed to `global`; `builtin: false` plus
266
+ `project: true` stays `false`, attributed to `builtin`. When `builtin` sat in the
267
+ operator class, a conservative default pi-lens shipped — an `enabled: false`, or
268
+ any member of a built-in deny list — could never be lifted by anyone, including
269
+ the person who installed pi-lens, and the only escape was editing pi-lens's
270
+ source. A default the operator cannot override is not a default.
271
+
272
+ **An operator denial is not liftable by a nearer operator tier.** `global: false`
273
+ plus `cli: true` stays `false`. This is the spec letter and it is kept on
274
+ purpose: a denial is a security decision, and letting one operator surface
275
+ out-shout another would make the guarantee depend on which surface an attacker
276
+ could reach (an inherited `PILENS_*` environment variable, a wrapper script's
277
+ argv) rather than on what the operator decided. The escape hatch is an
278
+ operator-tier **change** — edit the global config, unset the variable — never a
279
+ repo-tier one.
280
+
281
+ ### Prototype-safe keys
282
+
283
+ `__proto__`, `constructor`, and `prototype` are refused wherever a config
284
+ supplies a key, in both halves of the pipeline, with a `PILENS_CFG_0006` record
285
+ naming the key. No pi-lens setting is spelled that way, so there is nothing to
286
+ preserve, and assigning one would change an object's behavior rather than its
287
+ contents — a document that serializes as `{}` while answering an attacker's
288
+ value on every field read.
289
+
290
+ Both halves also bound their own recursion at `MAX_CONFIG_DEPTH` (32) and
291
+ `resolveConfig` never throws: a config that cannot be resolved degrades to
292
+ absent with records, never to a failed session.
293
+
294
+ A schema node that declares no `type` — or a `type` keyword the core does not
295
+ recognize — is **opaque**, and an opaque node is walked by the value's own
296
+ shape rather than passed through. Its children are kept (that is what an opaque
297
+ node means), but they are copied, depth-counted, key-checked, and recorded like
298
+ any other. A schema that wants a genuinely free-form subtree should still say
299
+ `additionalProperties: true`, which states the intent instead of relying on an
300
+ omission.
301
+
302
+ ### Merge strategies
303
+
304
+ Objects are always merged field-wise; a nearer tier setting one key never erases
305
+ its siblings. Arrays follow the node's `x-merge-strategy`:
306
+
307
+ | Value | Behavior |
308
+ | --- | --- |
309
+ | `replace` (default) | The highest-precedence tier that sets the array supplies all of it. |
310
+ | `append` | Every tier's entries, concatenated lowest precedence first. |
311
+ | `keyed:<field>` | Entries matched across tiers by `<field>` and merged field-wise; unmatched entries appended. |
312
+
313
+ ### The trust-gated `ProcessSpec`
314
+
315
+ A `ProcessSpec` carries a non-empty argv, a bounded env (count and bytes), a
316
+ closed `cwdMode`/`inputMode`, a timeout, its provenance, and the trust decision
317
+ that applied when it was read. `toSpawnArgs(spec)` is the only way to get
318
+ spawnable arguments out of one, and for a `project` or `nested-project` spec it
319
+ refuses unless **both** the spec's recorded trust and the host's current
320
+ `isProjectTrusted()` decision are `"trusted"`. Two conditions, because a session
321
+ can revoke trust after the config was read; one condition would make a spec a
322
+ permanent capability token.
323
+
324
+ `unknown` fails closed here, unlike `isToolInstallAllowedByTrust`. That gate
325
+ governs pi-lens's own managed tools; this one governs a command string a
326
+ repository wrote.
327
+
328
+ Refusals record under the existing `trust-refusal` degradation kind through
329
+ `incrementDegradationCount`, carrying the tier, `argv[0]`, and the trust
330
+ generation — never an argument or an env value.
331
+
332
+ ### Redaction
333
+
334
+ `redactProcessSpec` is the only projection of a spec for a diagnostic or
335
+ telemetry surface. It strips every env **value** and every argv entry after
336
+ `argv[0]`; env names survive, because a name is a label and "which variables did
337
+ this server get" is the question an operator asks.
338
+
339
+ `provenanceView(resolved)` is redacted by construction: it is built from the
340
+ provenance map alone and never reads the resolved value, so no un-redacted view
341
+ exists. Validation records are bounded and structural — a reason names a key, a
342
+ type, and a count, never a value or a source snippet.
343
+
344
+ ## Where each policy point is enforced
345
+
346
+ | Policy point | Data | Test |
347
+ | --- | --- | --- |
348
+ | 1. `x-stability` on every published field | `STABILITY_TIER_KEY`, `STABILITY_TIERS` | `tests/config/schema-stability-tiers.test.ts` via `assertSchemaStabilityTiers` |
349
+ | 2. Append-only `PILENS_CFG_*` codes | `CONFIG_DIAGNOSTIC_CODES` | `tests/clients/config-diagnostic-codes.test.ts` |
350
+ | 3. Reserved `$schema` identity anchor | `CONFIG_SCHEMA_ID`, `CONFIG_SCHEMA_ANCHOR_KEY` | `assertSchemaIdentityAnchor` |
351
+ | 4. Deprecation window + removal checklist | `DEPRECATED_CONFIG_SURFACES` | `tests/clients/config-deprecation-registry.test.ts` |
352
+ | 5. Config core: tiers, deny precedence, ProcessSpec trust | `clients/config-core/` | `tests/clients/config-core/*.test.ts`, `tests/config/config-core-schema-stability.test.ts` |
353
+
354
+ ## Related
355
+
356
+ #2415 (shared config core), #2416/#2372 (catalog schema and its compat
357
+ template), #2383, #195 (selector semantics), #1358 (facade versioning — a
358
+ separate version axis this policy only has to compose with), #2426 (canonical
359
+ config locations).