@herbertgao/pi-extensions 2026.9.14 → 2026.9.16

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 (206) hide show
  1. package/README.md +8 -3
  2. package/THIRD_PARTY_NOTICES.md +28 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/package.json +1 -1
  4. package/node_modules/@narumitw/pi-btw/dist/index.ts +12 -6
  5. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +3 -3
  6. package/node_modules/@narumitw/pi-btw/package.json +4 -4
  7. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +2 -0
  8. package/node_modules/@narumitw/pi-btw/src/side-thread.ts +16 -4
  9. package/node_modules/pi-jev-auto-mode/CHANGELOG.md +8 -0
  10. package/node_modules/pi-jev-auto-mode/README.md +7 -0
  11. package/node_modules/pi-jev-auto-mode/package.json +1 -1
  12. package/node_modules/pi-jev-auto-mode/src/extension.ts +21 -2
  13. package/node_modules/pi-jev-auto-mode/src/records.ts +68 -2
  14. package/node_modules/pi-jev-auto-mode/src/settings.ts +22 -0
  15. package/node_modules/pi-jev-auto-mode/src/ui.ts +10 -0
  16. package/node_modules/pi-lens/CHANGELOG.md +498 -0
  17. package/node_modules/pi-lens/README.md +45 -2
  18. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +23 -7
  19. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +187 -51
  20. package/node_modules/pi-lens/dist/clients/cache-manager.js +64 -5
  21. package/node_modules/pi-lens/dist/clients/child-unref.js +17 -8
  22. package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +2 -0
  23. package/node_modules/pi-lens/dist/clients/config-locations.js +237 -9
  24. package/node_modules/pi-lens/dist/clients/config-resolve.js +7 -1
  25. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +33 -3
  26. package/node_modules/pi-lens/dist/clients/dependency-checker.js +87 -64
  27. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +39 -3
  28. package/node_modules/pi-lens/dist/clients/dispatch/finding-policy.js +118 -1
  29. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +8 -2
  30. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +23 -4
  31. package/node_modules/pi-lens/dist/clients/dispatch/rule-ignores.js +14 -7
  32. package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +26 -28
  33. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +38 -25
  34. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +32 -49
  35. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +16 -14
  36. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +25 -7
  37. package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +28 -47
  38. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +11 -4
  39. package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +27 -22
  40. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +31 -46
  41. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +29 -46
  42. package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +91 -11
  43. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +16 -2
  44. package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +38 -23
  45. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +27 -15
  46. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +17 -8
  47. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +31 -21
  48. package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +34 -60
  49. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +6 -5
  50. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +12 -5
  51. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
  52. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +22 -6
  53. package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +39 -16
  54. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +1 -1
  55. package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +27 -18
  56. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +18 -19
  57. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +6 -1
  58. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +6 -2
  59. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +10 -3
  60. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +11 -2
  61. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +10 -2
  62. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +11 -2
  63. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +12 -6
  64. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +30 -15
  65. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +23 -0
  66. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +8 -2
  67. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +11 -1
  68. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +15 -3
  69. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +12 -2
  70. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +27 -39
  71. package/node_modules/pi-lens/dist/clients/dispatch/suppress-writer.js +13 -3
  72. package/node_modules/pi-lens/dist/clients/effective-config.js +3 -1
  73. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +42 -11
  74. package/node_modules/pi-lens/dist/clients/formatters.js +49 -11
  75. package/node_modules/pi-lens/dist/clients/git-guard.js +247 -34
  76. package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +121 -25
  77. package/node_modules/pi-lens/dist/clients/inline-blocker-dispositions.js +186 -0
  78. package/node_modules/pi-lens/dist/clients/install-diagnostics.js +19 -6
  79. package/node_modules/pi-lens/dist/clients/installer/index.js +281 -32
  80. package/node_modules/pi-lens/dist/clients/jscpd-client.js +8 -0
  81. package/node_modules/pi-lens/dist/clients/latency-logger.js +8 -0
  82. package/node_modules/pi-lens/dist/clients/lens-config.js +66 -8
  83. package/node_modules/pi-lens/dist/clients/lsp/client.js +139 -11
  84. package/node_modules/pi-lens/dist/clients/lsp/config.js +9 -7
  85. package/node_modules/pi-lens/dist/clients/lsp/content-limits.js +41 -0
  86. package/node_modules/pi-lens/dist/clients/lsp/index.js +1 -1
  87. package/node_modules/pi-lens/dist/clients/lsp/launch.js +23 -2
  88. package/node_modules/pi-lens/dist/clients/lsp/server.js +106 -25
  89. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +14 -0
  90. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +105 -16
  91. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +232 -44
  92. package/node_modules/pi-lens/dist/clients/mcp/review.js +53 -7
  93. package/node_modules/pi-lens/dist/clients/opengrep-client.js +11 -6
  94. package/node_modules/pi-lens/dist/clients/pipeline.js +121 -66
  95. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +21 -3
  96. package/node_modules/pi-lens/dist/clients/project-lens-config.js +11 -3
  97. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +34 -26
  98. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +16 -10
  99. package/node_modules/pi-lens/dist/clients/ruff-client.js +31 -4
  100. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +38 -4
  101. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +16 -5
  102. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +27 -12
  103. package/node_modules/pi-lens/dist/clients/runtime-turn.js +447 -280
  104. package/node_modules/pi-lens/dist/clients/safe-spawn.js +256 -65
  105. package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +84 -1
  106. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +119 -58
  107. package/node_modules/pi-lens/dist/clients/turn-end/lane.js +51 -0
  108. package/node_modules/pi-lens/dist/clients/turn-end/lanes/govulncheck.js +112 -0
  109. package/node_modules/pi-lens/dist/clients/turn-end/lanes/secrets.js +204 -0
  110. package/node_modules/pi-lens/dist/clients/warm-attach.js +59 -0
  111. package/node_modules/pi-lens/dist/clients/widget-state.js +145 -14
  112. package/node_modules/pi-lens/dist/clients/workspace-topology.js +57 -3
  113. package/node_modules/pi-lens/dist/clients/zizmor-config.js +26 -13
  114. package/node_modules/pi-lens/dist/index.js +5695 -3733
  115. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +4 -0
  116. package/node_modules/pi-lens/dist/mcp/server.js +33 -21
  117. package/node_modules/pi-lens/dist/scripts/lib/web-tree-sitter-dir.mjs +123 -0
  118. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +43 -16
  119. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +118 -7
  120. package/node_modules/pi-lens/docs/adr/0001-stale-advisory-live-arm.md +29 -0
  121. package/node_modules/pi-lens/docs/adr/0002-workspace-hash-rendezvous.md +30 -0
  122. package/node_modules/pi-lens/docs/adr/0003-git-guard-latch-writer.md +203 -0
  123. package/node_modules/pi-lens/docs/adr/0004-disposition-policy-seam.md +38 -0
  124. package/node_modules/pi-lens/docs/adr/0005-tool-availability-enforcement-seam.md +29 -0
  125. package/node_modules/pi-lens/docs/adr/0006-derived-state-benchmark-first.md +31 -0
  126. package/node_modules/pi-lens/docs/adr/0007-end-to-end-witness-per-seam-slice.md +38 -0
  127. package/node_modules/pi-lens/docs/adr/0008-turn-end-lane-interface.md +165 -0
  128. package/node_modules/pi-lens/docs/adr/0009-reported-path-attribution.md +114 -0
  129. package/node_modules/pi-lens/docs/adr/README.md +26 -0
  130. package/node_modules/pi-lens/docs/agent-tools.md +18 -1
  131. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +4 -3
  132. package/node_modules/pi-lens/docs/configuration.md +55 -1
  133. package/node_modules/pi-lens/docs/engineering-principles.md +202 -0
  134. package/node_modules/pi-lens/docs/environment-variables.md +61 -4
  135. package/node_modules/pi-lens/docs/features.md +2 -2
  136. package/node_modules/pi-lens/docs/globalconfig.md +6 -1
  137. package/node_modules/pi-lens/docs/language-coverage.md +17 -0
  138. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +98 -31
  139. package/node_modules/pi-lens/docs/pi-lens-fixer.md +57 -3
  140. package/node_modules/pi-lens/docs/pi-lens-investigator.md +9 -0
  141. package/node_modules/pi-lens/docs/pi-lens-reviewer.md +16 -0
  142. package/node_modules/pi-lens/docs/pi-lens-subagent.md +9 -0
  143. package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
  144. package/node_modules/pi-lens/docs/release-qa-baseline.md +2 -0
  145. package/node_modules/pi-lens/docs/servercapabilities.md +21 -11
  146. package/node_modules/pi-lens/docs/settings.md +12 -3
  147. package/node_modules/pi-lens/docs/subagent-compat.md +1 -1
  148. package/node_modules/pi-lens/package.json +5 -3
  149. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-assert-tuple-test.yml +13 -0
  150. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-boolean-in-except-test.yml +26 -0
  151. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-http-headers-bracket-access-test.yml +10 -0
  152. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/unchecked-numeric-parse-python-test.yml +18 -0
  153. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/unchecked-throwing-call-python-test.yml +4 -3
  154. package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-fmt-println.yml +2 -2
  155. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-assert-tuple.yml +23 -13
  156. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-boolean-in-except.yml +7 -3
  157. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-console-except-error-js.yml +2 -2
  158. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-console-except-error.yml +2 -2
  159. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-http-headers-bracket-access.yml +12 -7
  160. package/node_modules/pi-lens/rules/ast-grep-rules/rules/unchecked-numeric-parse-python.yml +44 -0
  161. package/node_modules/pi-lens/rules/ast-grep-rules/rules/unchecked-throwing-call-python.yml +5 -3
  162. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/console-statement.yml +2 -2
  163. package/node_modules/pi-lens/scripts/install-selftest.mjs +21 -17
  164. package/node_modules/pi-lens/scripts/lib/web-tree-sitter-dir.mjs +123 -0
  165. package/node_modules/pi-mcp-adapter/CHANGELOG.md +29 -0
  166. package/node_modules/pi-mcp-adapter/OAUTH.md +369 -0
  167. package/node_modules/pi-mcp-adapter/README.md +12 -5
  168. package/node_modules/pi-mcp-adapter/config.ts +31 -8
  169. package/node_modules/pi-mcp-adapter/direct-tool-surface.ts +1 -1
  170. package/node_modules/pi-mcp-adapter/dist/config.js +33 -8
  171. package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
  172. package/node_modules/pi-mcp-adapter/dist/json-schema-validator.js +15 -2
  173. package/node_modules/pi-mcp-adapter/dist/json-schema-validator.js.map +1 -1
  174. package/node_modules/pi-mcp-adapter/dist/mcp-auth.d.ts +2 -0
  175. package/node_modules/pi-mcp-adapter/dist/mcp-auth.js +27 -2
  176. package/node_modules/pi-mcp-adapter/dist/mcp-auth.js.map +1 -1
  177. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js +1 -1
  178. package/node_modules/pi-mcp-adapter/dist/metadata-cache.js.map +1 -1
  179. package/node_modules/pi-mcp-adapter/dist/server-manager.js +6 -4
  180. package/node_modules/pi-mcp-adapter/dist/server-manager.js.map +1 -1
  181. package/node_modules/pi-mcp-adapter/dist/types.d.ts +2 -2
  182. package/node_modules/pi-mcp-adapter/dist/utils.d.ts +2 -0
  183. package/node_modules/pi-mcp-adapter/dist/utils.js +10 -3
  184. package/node_modules/pi-mcp-adapter/dist/utils.js.map +1 -1
  185. package/node_modules/pi-mcp-adapter/index.ts +37 -20
  186. package/node_modules/pi-mcp-adapter/init.ts +14 -15
  187. package/node_modules/pi-mcp-adapter/json-schema-validator.ts +16 -2
  188. package/node_modules/pi-mcp-adapter/mcp-auth.ts +27 -2
  189. package/node_modules/pi-mcp-adapter/metadata-cache.ts +1 -1
  190. package/node_modules/pi-mcp-adapter/package.json +3 -2
  191. package/node_modules/pi-mcp-adapter/proxy-modes.ts +1 -1
  192. package/node_modules/pi-mcp-adapter/server-manager.ts +6 -3
  193. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +99 -6
  194. package/node_modules/pi-mcp-adapter/types.ts +2 -2
  195. package/node_modules/pi-mcp-adapter/ui-session.ts +60 -27
  196. package/node_modules/pi-mcp-adapter/utils.ts +11 -3
  197. package/node_modules/pi-multi-account/CHANGELOG.md +6 -0
  198. package/node_modules/pi-multi-account/README.md +15 -1
  199. package/node_modules/pi-multi-account/index.ts +295 -41
  200. package/node_modules/pi-multi-account/package.json +1 -1
  201. package/node_modules/pi-next-cue/.github/workflows/publish.yml +20 -0
  202. package/node_modules/pi-next-cue/LICENSE +21 -0
  203. package/node_modules/pi-next-cue/README.md +81 -0
  204. package/node_modules/pi-next-cue/index.ts +358 -0
  205. package/node_modules/pi-next-cue/package.json +28 -0
  206. package/package.json +10 -7
@@ -46,7 +46,24 @@ same gate rather than bypassing it.
46
46
  `workspace`; explicit `paths` always win over `scope`). `severity` is a
47
47
  threshold, not an exact filter: `error` shows only errors; `warning` adds
48
48
  warnings; `information` adds information; `hint`/`all` (default) show every
49
- tier. Legacy `mode`: `delta` (current turn), `all` (resurfaces stale
49
+ tier. `source=lsp` reads a file's on-disk content and will not sync it to a
50
+ language server past **2 MiB or 5000 lines** (`clients/runtime-config.ts`
51
+ `pipeline.lspMaxFileBytes`/`lspMaxFileLines`, checked in
52
+ `clients/lsp/content-limits.ts`) — not env-tunable today. A file over that
53
+ bound gets an explicit `file too large for LSP diagnostics (<N> bytes/lines
54
+ > <limit>)` result instead of stale or partial diagnostics. This is a
55
+ *different* 2 MiB from the auto-fix full-content attachment cap described in
56
+ [agent-guide.md](agent-guide.md), section 6 ("Auto-format / auto-fix
57
+ timing") — the two caps currently share one constant
58
+ (`RUNTIME_CONFIG.pipeline.lspMaxFileBytes`) but gate unrelated behaviors
59
+ (LSP sync vs. tool-result content attachment) and can diverge independently
60
+ in the future. Separately, every save-triggered edit now sends the server a
61
+ `textDocument/didSave` when it declared `textDocumentSync.save` — with the
62
+ file text when the server asked for it (`includeText`) and the file is
63
+ within the same bound, otherwise the save is still sent but without `text`
64
+ (never dropped outright); this is what makes save-triggered servers like
65
+ Expert (Elixir) re-diagnose an edit made through pi-lens (refs #3405,
66
+ #3408). Legacy `mode`: `delta` (current turn), `all` (resurfaces stale
50
67
  blockers dropped from turn context), `full` (project-wide scan).
51
68
  - **`lens_diagnostic_mark`** — Triage a diagnostic: `false-positive` /
52
69
  `suppress` (writes an inline `pi-lens-ignore` comment) / `defer`
@@ -2,7 +2,7 @@
2
2
 
3
3
  <!-- GENERATED by scripts/gen-rule-catalogs.mjs — do not edit by hand. Run `npm run docs:rule-catalogs` after changing rules. -->
4
4
 
5
- pi-lens bundles **481 enabled** ast-grep rules (297 pi-lens-authored + 184 vendored from CodeRabbit) across **17 languages**, plus 16 disabled.
5
+ pi-lens bundles **482 enabled** ast-grep rules (298 pi-lens-authored + 184 vendored from CodeRabbit) across **17 languages**, plus 16 disabled.
6
6
 
7
7
  See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `rules/ast-grep-rules/rules/` (pi-lens), `rules/ast-grep-rules/coderabbit/rules/` (vendored).
8
8
 
@@ -260,7 +260,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
260
260
  | `openssl-cbc-static-iv-php` | warning | no | CodeRabbit | Static IV used with AES in CBC mode. Static IVs enable chosen-plaintext attacks against encrypted data. |
261
261
  | `search-active-debug-php` | warning | no | CodeRabbit | Debug logging is explicitly enabled. This can potentially disclose sensitive information and should never be active on production systems. |
262
262
 
263
- ### Python (98)
263
+ ### Python (99)
264
264
 
265
265
  | Rule | Severity | Fixable | Source | Description |
266
266
  |---|---|---|---|---|
@@ -271,7 +271,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
271
271
  | `hashids-with-flask-secret-python` | warning | no | CodeRabbit | The Flask secret key is used as salt in HashIDs. The HashID mechanism is not secure. By observing sufficient HashIDs, the salt used to cons… |
272
272
  | `insecure-cipher-algorithm-rc4-python` | warning | no | CodeRabbit | Detected ARC4 cipher algorithm which is considered insecure. This algorithm is not cryptographically secure and can be reversed easily. Use… |
273
273
  | `jwt-python-hardcoded-secret-python` | warning | no | CodeRabbit | Hardcoded JWT secret or private key is used. This is a Insufficiently Protected Credentials weakness: https://cwe.mitre.org/data/definition… |
274
- | `no-assert-tuple` | error | no | pi-lens | Assert should not be called on a tuple literal |
274
+ | `no-assert-tuple` | warning | no | pi-lens | Assert should not be called on a tuple literal |
275
275
  | `no-aws-access-key-literal` | error | no | pi-lens | AWS access keys should not be hardcoded — use IAM roles, environment variables, or AWS Secrets Manager |
276
276
  | `no-aws-apigateway-no-auth` | error | no | pi-lens | AWS API Gateway should require authentication |
277
277
  | `no-aws-s3-public-access` | error | no | pi-lens | S3 buckets should not grant access to all users or authenticated users |
@@ -361,6 +361,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
361
361
  | `python-webrepl-empty-password-python` | warning | no | CodeRabbit | The application creates a database connection with an empty password. This can lead to unauthorized access by either an internal or externa… |
362
362
  | `python-webrepl-hardcoded-secret-python` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
363
363
  | `reducible-list-comprehension` | warning | yes | pi-lens | A list comprehension is unnecessary here; use a generator expression |
364
+ | `unchecked-numeric-parse-python` | warning | no | pi-lens | int()/float() without try/except — raises ValueError on non-numeric input |
364
365
  | `unchecked-throwing-call-python` | error | no | pi-lens | Call without try/except — throws on invalid input or missing file |
365
366
 
366
367
  ### Ruby (20)
@@ -5,7 +5,7 @@ There are **two** pi-lens config files:
5
5
  | File | Scope | Notes |
6
6
  | --- | --- | --- |
7
7
  | `.pi-lens.json` | the project | Committed or not, your call. Nearest one wins **per field** — a package can override one setting without restating the repo root's. |
8
- | `~/.pi-lens/config.json` | the machine | Your defaults across every project. `PI_LENS_CONFIG_PATH` relocates it. |
8
+ | `~/.pi-lens/config.json` | the machine | Your defaults across every project. The winning global location is selected by the [global-location table](#global-config-location); see [environment variables](environment-variables.md) for the knobs. |
9
9
 
10
10
  Both files have the same shape, with one exception noted below the example:
11
11
  everything LSP-related lives under an `lsp` namespace inside them.
@@ -86,6 +86,60 @@ Subsystem-specific env overrides follow the same shape: a
86
86
  `reviewGraph.maxFiles`. `docs/environment-variables.md` and `docs/settings.md`
87
87
  are the per-setting references.
88
88
 
89
+ ### Global config location
90
+
91
+ The global file is selected by this order, highest precedence first. The
92
+ canonical default is still `~/.pi-lens/config.json`; `PI_LENS_HOME` relocates
93
+ machine-generated data and state, not this file. This is the complete truth
94
+ table for the three existence axes.
95
+
96
+ | `PI_LENS_CONFIG_PATH` | `~/.pi-lens/config.json` exists | `PI_CODING_AGENT_DIR` set and `extensions/pi-lens.json` exists | Winner |
97
+ | --- | --- | --- | --- |
98
+ | unset | no | no | `~/.pi-lens/config.json` (canonical default) |
99
+ | unset | no | yes | `$PI_CODING_AGENT_DIR/extensions/pi-lens.json` |
100
+ | unset | yes | no | `~/.pi-lens/config.json` (grandfathered existing file) |
101
+ | unset | yes | yes | `~/.pi-lens/config.json` (the host file is shadowed; shadowed file reported once per session (#3299)) |
102
+ | set | no | no | the explicit `PI_LENS_CONFIG_PATH` file |
103
+ | set | no | yes | the explicit `PI_LENS_CONFIG_PATH` file |
104
+ | set | yes | no | the explicit `PI_LENS_CONFIG_PATH` file |
105
+ | set | yes | yes | the explicit `PI_LENS_CONFIG_PATH` file |
106
+
107
+ If an existence probe for a recognized candidate errors (for example,
108
+ `ENOTDIR`, `EACCES`, or `ELOOP`), that candidate's tier is retained rather
109
+ than falling through to a lower location. The subsequent read reports the
110
+ degraded config under `PILENS_CFG_0001`; a probe error is not treated as
111
+ absence.
112
+
113
+ pi-lens does not write this file. Create or edit it yourself, then start a new
114
+ process. For an XDG-like setup, put generated data and state at a durable data
115
+ root and choose one config surface:
116
+
117
+ ```sh
118
+ export PI_LENS_HOME="$HOME/.local/share/pi-lens"
119
+
120
+ # XDG-shaped host: use its config directory.
121
+ export PI_CODING_AGENT_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/pi"
122
+ mkdir -p "$PI_CODING_AGENT_DIR/extensions"
123
+ ```
124
+
125
+ For hosts without `PI_CODING_AGENT_DIR`, use an explicit config path instead:
126
+
127
+ ```sh
128
+ export PI_LENS_CONFIG_PATH="${XDG_CONFIG_HOME:-$HOME/.config}/pi-lens/config.json"
129
+ mkdir -p "$(dirname "$PI_LENS_CONFIG_PATH")"
130
+ ```
131
+
132
+ When migrating an existing `~/.pi-lens/config.json`, create the new file first
133
+ and delete the old file second. While both exist, the old file wins by design;
134
+ deleting it first would leave the process without the intended settings. Copy
135
+ the file (or hand-author it, since pi-lens has no writer), verify the new
136
+ location, then run `rm "$HOME/.pi-lens/config.json"` to opt out of
137
+ grandfathering. If the new host file is later deleted, the old file wins again
138
+ while it exists; with neither file present, the canonical default path is used.
139
+
140
+ See also the [environment-variable reference](environment-variables.md#config-location)
141
+ and [settings overview](settings.md#the-three-ways-to-configure-pi-lens).
142
+
89
143
  ### One exception: `lsp.disabledServers` is a denial, not a value
90
144
 
91
145
  Ordinary settings are last-tier-wins. A **denial** is not, because the tier
@@ -0,0 +1,202 @@
1
+ # Engineering principles
2
+
3
+ Source of truth: https://github.com/apmantza/engineering-principles (private), file PRINCIPLES.md. Verbatim copy; the repo wins on drift. Project-level AGENTS.md / CLAUDE.md add the project catalog and win on conflict.
4
+
5
+ Project-neutral rules distilled from the pi-lens contracts, playbooks and merge
6
+ train (2026-08 to 2026-09). Each rule is imperative and carries the reason it
7
+ exists. Projects keep their own catalog of defect shapes, registries, and
8
+ commands; this file is what stays the same across them.
9
+
10
+ Read order for any agent starting work: this file, then the project's own
11
+ AGENTS.md or CLAUDE.md, then the role contract for the task (fixer, reviewer,
12
+ investigator). Project instructions win on conflict.
13
+
14
+ ## 1. Building
15
+
16
+ **Premise first.** Reproduce a reported defect through the production call
17
+ path before writing a fix. Drive the real dispatcher, loader, or builder; never
18
+ a hand-shaped input that exists only to hit the bug. If it does not reproduce,
19
+ the deliverable is the recorded refutation (which invariant covers it, with the
20
+ probe) and, where cheap, an assertion that pins it, not machinery for a
21
+ collision that cannot occur.
22
+
23
+ **Climb the minimalism ladder before writing code.** Be lazy about the
24
+ solution, never about reading. Trace the real flow, then ask in order: does this
25
+ need to exist at all; does the codebase already do it (reuse the seam); does the
26
+ platform or stdlib do it; does an installed dependency do it; is it one line.
27
+ Only then write the minimum that works. Validation, error handling, security and
28
+ bounded observability are never skipped in the name of minimalism.
29
+
30
+ **Net-count rule for shared helpers.** A change that introduces a shared helper
31
+ while same-shape siblings exist deletes at least one sibling in the same change.
32
+ The helper count never goes up. Deferring the fold is allowed only when the
33
+ brief names every sibling, states why folding them together is unsafe, and
34
+ links the follow-up. This binds whoever writes the brief as much as whoever
35
+ implements it.
36
+
37
+ **A fix's pattern matters more than its instance.** When a root cause is
38
+ understood, name the defect shape and sweep the whole tree for other members
39
+ before closing. Fix the contained siblings in the same change; file the rest
40
+ with the member list; record what was grepped and what was found clean. Seeing
41
+ without recording is indistinguishable from not looking. Every sweep ends with
42
+ a consolidation verdict: fold onto one seam (name it) or stay distributed (say
43
+ why). The deciding test is deletion: would removing the shared module
44
+ concentrate complexity back into callers (fold) or merely relocate the same
45
+ lines (stay)?
46
+
47
+ **Design shared state once, at design time.** Before adding a second writer to
48
+ any shared record (a cache entry, a latch, a ledger, a mirror, a counter) decide
49
+ whether every actor needs one canonical object or each can own its record and
50
+ merge at read. Refresh mirrors inside the guard that published the durable
51
+ state. A resource bounded along one axis and unbounded along another is a leak.
52
+
53
+ **Every new failure path gets bounded observability.** One record per distinct
54
+ event per session, never one per occurrence in a loop; repeated degradations go
55
+ through a once-only or counted record. A discriminator nothing can observe is a
56
+ vacuous guard and does not ship.
57
+
58
+ **Blast radius as a call-tree diff.** For any change to a shared seam, list the
59
+ changed symbol, its callers above, its callees below, with plus and minus on the
60
+ lines that moved. Prose keeps missing callers; a tree the reviewer can grep does
61
+ not. Name every strict consumer of a durable record whose shape changes, and
62
+ prove old records still parse.
63
+
64
+ **Deletion sweeps dependents first.** Before removing a guard, a defensive
65
+ branch, or a field, grep every caller and every test double. Correct-looking
66
+ deletion asks have redded CI because dozens of doubles depended on the removed
67
+ line.
68
+
69
+ **Identity and lifecycle rules are stated before the first edit.** When a change
70
+ touches session, ownership, or resume semantics, write the invariants and the
71
+ writers-by-axis table (which actor, which identity, which timing) first, and
72
+ choose the simplest identity rule that satisfies every cell. Adding a second
73
+ identity clause "to be safe" produced two consecutive regressions on one seam.
74
+
75
+ ## 2. Testing
76
+
77
+ **Red first, and keep the transcript.** Every regression test is shown failing
78
+ on the pre-fix code with the failure that matches the defect, and the output is
79
+ pasted into the change description. A test that passes pre-fix is a finding.
80
+
81
+ **Tests ship with the code, in the same commit.** A change and the tests that
82
+ prove it land together; a test-only follow-up round means the first commit
83
+ shipped unproven. The failure list is written before the first edit, and the
84
+ mutation table is that list with transcripts, never a list invented after the
85
+ code.
86
+
87
+ **Keep fixture corpora from every supported version.** Every durable record,
88
+ config file, cache entry or wire message the project still reads has a fixture
89
+ from each version that produced it, and the parser is run over all of them. An
90
+ old-record parse proof is a fixture in the corpus, not a sentence in a PR body.
91
+
92
+ **Mutation output is quoted, not ticked.** For every new guard, branch, filter,
93
+ cap or fallback: neuter it in the built output, run the suite that should catch
94
+ it, and paste the red. A checked box with no transcript is treated as false. A
95
+ mutation that fails to compile proves nothing about the test; redo it as a
96
+ compile-valid change. A guard that cannot be made to red does not need to exist.
97
+
98
+ **Tautological tests are harmful.** A test observes behaviour through the real
99
+ seam and asserts an independent effect. It never restates the implementation,
100
+ never asserts a value its own setup supplied, and never swaps a real in-process
101
+ store, sink, coordinator or registry for a fake. Mocks belong only at true
102
+ process or host boundaries.
103
+
104
+ **Every guard test names the recurrence it prevents** in its own comment: the
105
+ shipped defect or the concrete drift it would catch. A guard with no named
106
+ recurrence is speculative and does not ship.
107
+
108
+ **Detectors match code, not prose.** Any test-side scan that regexes source
109
+ must run over comment-and-string-blanked text, with a per-needle policy for the
110
+ rare needle whose evidence is a string literal. A comment quoting the needle
111
+ must never satisfy a requirement or an exemption. The self-excuse direction
112
+ (prose makes a guard pass) is the dangerous one; the false-positive direction
113
+ reds loudly and is lower priority.
114
+
115
+ **Ratchets and baselines are admissions, not loosening.** A new real spawn,
116
+ timer, or wall-clock assertion is admitted with a header stating why the real
117
+ thing is required, a registry entry, a baseline row and lane membership. A
118
+ mocked seam is not a real spawn and gets an exemption with its reason, never an
119
+ admission.
120
+
121
+ **Run targeted files while iterating; the full suite runs once.** Build before
122
+ testing when tests execute compiled output, and rebuild between mutations. A red
123
+ is environmental only when the same test is red on the base branch in the same
124
+ environment; say so with the evidence.
125
+
126
+ **Probe hygiene.** Every probe, test run and child process pins its home,
127
+ data and log directories under the working tree. Nothing an agent runs writes
128
+ to the maintainer's real home.
129
+
130
+ ## 3. Reviewing and delegating
131
+
132
+ **Every change is reviewed adversarially, including small and self-authored
133
+ ones.** Depth follows what the diff touches, never the priority label: runtime,
134
+ tooling, CI and manifests get full adversarial review; test-only diffs that are
135
+ not ratchets get one scoped pass; docs and renames get an orchestrator read plus
136
+ CI on the exact head.
137
+
138
+ **A finding is real when a probe proves it; a fix is real when the same probe
139
+ passes.** Reviewers attack with throwaway probes and quote the output. They
140
+ reproduce the red run themselves (keep the tests, revert the source), mutate
141
+ every new guard, check merge state first (a conflicted change silently skips
142
+ its gates), and read CI on the exact head. Reviewer prescriptions are
143
+ hypotheses: the verify round attacks them as a rival's.
144
+
145
+ **The same reviewer verifies each fix round.** Continuity is the reviewer's
146
+ judgment and probe set; the checkout under it is rebuilt fresh at the new head
147
+ every round. When a review or verify names a new defect on the same seam, the
148
+ next fix opens with the state-space table written before any edit, on the
149
+ strongest available model. Never send a third patch-only round on one seam.
150
+
151
+ **Round routing.** A round that only applies a prescribed remedy with quoted
152
+ reds merges on green. A round that adds mechanism, touches lifecycle or session
153
+ semantics, or rewrites a guard gets a fresh verify. Classify by the worst
154
+ finding, not the count. Intent-free findings (a body sentence, a comment, a
155
+ literal, a changelog line) are applied by the orchestrator as trailing commits
156
+ and never re-verified; anything that changes what code means goes through a
157
+ round, however small it looks.
158
+
159
+ **Merge gate.** Merge only when the verdict is merge-ready, every gating check
160
+ genuinely executed and passed on the exact head, and every failing check was
161
+ read and judged. Absent is not green. Read exit codes directly, never after a
162
+ pipe. After a merge, check the other open changes for conflicts and prune only
163
+ the merged lane's worktrees.
164
+
165
+ **Delegation contract.** Every delegation names the role, the absolute worktree,
166
+ branch, base, acceptance criteria, non-goals, sibling files to avoid, and Git
167
+ authority. A role never grants Git authority by itself. A worker without it
168
+ leaves changes uncommitted and hands off through a PR body and a commit message
169
+ at the worktree root; the orchestrator commits. Implementation and review are
170
+ never mixed in one delegation. Scope changes are mirrored on the tracking issue
171
+ before they are sent, so the worker can verify them.
172
+
173
+ **No manufactured work.** An idle worker is cheaper than fake work. Delegate
174
+ when a real producer, consumer, probe or diagnosis is unresolved, never to keep
175
+ a pool busy. The same applies to status artifacts: they exist for coordination
176
+ someone consumes.
177
+
178
+ ## 4. Honesty and records
179
+
180
+ **Closes versus refs follows delivery, not optimism.** Close only when every
181
+ acceptance criterion is met; otherwise reference the issue and post the named
182
+ remainder before anything merges. After merging a referencing change, verify the
183
+ issue carries that comment or close it crediting the change.
184
+
185
+ **Report what ran, what was skipped, and what CI must still confirm.** A
186
+ skipped suite, an environment-blocked file, a mutation that could not be
187
+ executed: each is named, never implied green.
188
+
189
+ **Contracts move in the same session.** When a review or an incident reveals a
190
+ defect class rather than an instance, the rule enters the project's catalog with
191
+ the reference and a one-line screen before the next dispatch. Two rounds on the
192
+ same shape in one session is the trigger.
193
+
194
+ **Detection retrospective on every merged bug fix.** Record which verification
195
+ layer caught it and which layer should have caught it earlier and at what cost.
196
+ If that layer does not exist, file it with the bug as its named recurrence.
197
+
198
+ **Keep a lane ledger.** One row per lane with a fixed state vocabulary (not
199
+ started, fixing rN, waiting on CI, waiting on review, waiting on verify,
200
+ blocked, ready to merge, merged, needs user decision, held). It is what survives
201
+ a context reset, and it lets a different orchestrator build the status table
202
+ without reading transcripts.
@@ -30,13 +30,36 @@ config JSON) and how they interact, see [Settings](settings.md).
30
30
 
31
31
  ### `PI_LENS_CONFIG_PATH`
32
32
 
33
- Override the path of the global config file. **Default:** `~/.pi-lens/config.json`
34
- (`%USERPROFILE%\.pi-lens\config.json` on Windows). When set, the value is
35
- resolved to an absolute path and used verbatim.
33
+ Override the path of the global config file. **Default:** the resolution order
34
+ below. When set, the value is resolved to an absolute path and used verbatim;
35
+ it wins over every other location. See the [winning-location table](configuration.md#global-config-location).
36
36
 
37
37
  **When to set it:** keeping the config under version control or a dotfiles
38
38
  manager at a non-default location, or pointing CI at a fixture config.
39
39
 
40
+ ### `PI_CODING_AGENT_DIR`
41
+
42
+ Host-relative global config location, honored by pi-lens when pi sets it.
43
+ **Resolved path:** `$PI_CODING_AGENT_DIR/extensions/pi-lens.json`. The tier is
44
+ opt-in by creation: the file is read when it EXISTS and the legacy default
45
+ does not. Absent, nothing changes.
46
+
47
+ The full resolution order for the global config file, highest first:
48
+
49
+ 1. `PI_LENS_CONFIG_PATH` — an explicit file override, used verbatim.
50
+ 2. `~/.pi-lens/config.json` — **only when it already exists**; current users
51
+ never move.
52
+ 3. `$PI_CODING_AGENT_DIR/extensions/pi-lens.json` — **only when it exists**
53
+ and step 2 missed.
54
+ 4. `~/.pi-lens/config.json` — the canonical default (unchanged).
55
+
56
+ pi-lens does not write the global config; there is no settings writer in this
57
+ repository. Create or edit the selected file by hand. `effective_config` shows
58
+ which file supplies the global tier. If an existence probe errors (a file where
59
+ a directory belongs, permission errors, or a symlink loop), the errored tier is
60
+ retained and the read failure is reported under `PILENS_CFG_0001`; it is not
61
+ treated as absent. See the [XDG-like recipe](configuration.md#global-config-location).
62
+
40
63
  ## Data directory
41
64
 
42
65
  ### `PILENS_DATA_DIR`
@@ -260,12 +283,46 @@ Days to keep rotated logs before cleanup. **Default:** `7`.
260
283
 
261
284
  Maximum log size (MB) before rotation. **Default:** `10`.
262
285
 
286
+ ## Diagnostic-only knobs
287
+
288
+ These use the `PILENS_` (no underscore after `PI`) prefix, so they are
289
+ invisible to a `grep PI_LENS_` sweep — use the wider `grep -E 'PI_?LENS_'`
290
+ below to find them and anything like them. Not part of the supported surface;
291
+ each exists for a narrow diagnostic or escape-hatch purpose, not everyday
292
+ tuning.
293
+
294
+ ### `PILENS_PROBE`
295
+
296
+ Set to `1` to force an ad-hoc probe (a bare `node -e` or throwaway script
297
+ against built `clients/*.js`, run outside a test harness and without
298
+ `PI_LENS_HOME` set) to redirect its home/log directory away from the real
299
+ `~/.pi-lens`, the same way running from an agent worktree or `os.tmpdir()`
300
+ already does automatically (`clients/probe-home-state.ts`). Prefer setting
301
+ `PI_LENS_HOME` explicitly; this is the forced opt-in for a probe run from an
302
+ ordinary project checkout, where the automatic detection would not fire.
303
+
304
+ ### `PILENS_UNSAFE_FORCE_GRAMMAR_LOAD`
305
+
306
+ Diagnostic escape hatch for the grammar-health probe only (`clients/grammar-source.ts`).
307
+ Set to `1` to force-load a tree-sitter grammar this runtime has blocklisted,
308
+ to test whether a newer build/runtime lifts the block. Disables the crash
309
+ protection the blocklist provides and can abort the process. Never set in
310
+ normal operation.
311
+
312
+ ### `PILENS_PUB_DEBUG`
313
+
314
+ Set to `1` to trace each LSP server's `publishDiagnostics` behavior (version +
315
+ diagnostic count) to diagnose the clean-file affirmative-signal question:
316
+ which servers publish an empty-with-version set on a clean scan vs. go silent
317
+ (`clients/lsp/client.ts`). Off by default.
318
+
263
319
  ## Advanced tuning knobs
264
320
 
265
321
  pi-lens also has many advanced/internal tuning variables — LSP timeouts and
266
322
  memory budgets, debounce intervals (`PI_LENS_LSP_*`, and others). These are for
267
323
  edge-case tuning, are not part of the supported surface above, and are documented
268
- in the source; enumerate them with `grep PI_LENS_ clients/`.
324
+ in the source; enumerate them with `grep -E 'PI_?LENS_' clients/` (the wider
325
+ pattern catches the `PILENS_` diagnostic-only knobs above too).
269
326
 
270
327
  ## Related
271
328
 
@@ -316,7 +316,7 @@ Covers JavaScript/TypeScript, Python, Go, Rust, Ruby, Shell, and CMake. A TypeSc
316
316
 
317
317
  Structural rules organized by language in `rules/tree-sitter-queries/<language>/`. Rules marked **🔴** block the agent inline at write time (only for lines in the current edit); others are advisory.
318
318
 
319
- **Suppressing a finding:** add `// pi-lens-ignore: rule-id` on the flagged line or the line above (JS/TS), or `# pi-lens-ignore: rule-id` for Python/Ruby/Shell. This suppresses that specific rule at that location only.
319
+ **Suppressing a finding:** add `// pi-lens-ignore: rule-id` on the flagged line or the line above (JS/TS), or `# pi-lens-ignore: rule-id` for Python/Ruby/Shell. Rule ids are comma-separated. A supported separator (` -- `, ` — `, or `: `) starts one trailing reason suffix for the whole payload; all remaining text, including commas, stays in the reason and is not parsed as another rule id. This suppresses each listed rule at that location only.
320
320
 
321
321
  **Bring your own rules:** drop YAML query files into `rules/tree-sitter-queries/<language>/` in your project — pi-lens merges them with the built-ins on session start. The schema, predicates (`eq`, `match`, `any-of`), and `inline_tier` (`blocking` | `warning` | `review`) are documented in [`custom-rules.md`](custom-rules.md). A `rules/tree-sitter-queries/rule-schema.json` JSON Schema is bundled for editor autocomplete via `.vscode/settings.json`.
322
322
 
@@ -401,7 +401,7 @@ pi-lens ships an MCP (Model Context Protocol) server so Claude Code — or any M
401
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`. |
402
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. |
403
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. |
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`. |
404
+ | **Lifecycle / loop** | `pilens_rebuild`, `pilens_session_end` | `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`. `pilens_session_end` ends the MCP connection's telemetry session and writes its bounded situational-tool telemetry line; terminal for the connection. |
405
405
 
406
406
  **Honest limits** (live-tested, documented in `mcp.md`):
407
407
 
@@ -1,6 +1,11 @@
1
1
  # Configuration
2
2
 
3
- pi-lens reads optional user preferences from `~/.pi-lens/config.json` (`%USERPROFILE%\\.pi-lens\\config.json` on Windows). An unrecognized top-level key is logged once (to surface a typo like `lps` for `lsp`) and then ignored; `$schema` is always allowed for editor JSON-schema association. Missing or invalid config falls back to defaults.
3
+ pi-lens reads optional user preferences from the global file selected by the
4
+ [winning-location table](configuration.md#global-config-location) (`~/.pi-lens/config.json`
5
+ by default; `%USERPROFILE%\\.pi-lens\\config.json` on Windows). An unrecognized
6
+ top-level key is logged once (to surface a typo like `lps` for `lsp`) and then
7
+ ignored; `$schema` is always allowed for editor JSON-schema association. Missing
8
+ or invalid config falls back to defaults.
4
9
 
5
10
  ## Every toggle, both ways
6
11
 
@@ -50,6 +50,8 @@ Dispatch is diagnostics-oriented: automatic formatting and safe autofix happen i
50
50
  | CMake | ✓ (cmake-language-server) | lsp | cmake-format |
51
51
  | CUE | ✓ (syntax via cue lsp, evaluation via cue vet) | lsp, cue-vet | cue fmt |
52
52
 
53
+ ### CUE tree-sitter grammar
54
+
53
55
  `cue lsp` reports load and parse errors as you type but leaves conflicting
54
56
  values and failed constraints to `cue vet` — the `cue-vet` auxiliary runner
55
57
  (#1522) covers that gap, so together they give full coverage: syntax/parse
@@ -79,6 +81,21 @@ Both are upstream grammar limitations (tracked among
79
81
  [eonpatapon/tree-sitter-cue](https://github.com/eonpatapon/tree-sitter-cue)'s
80
82
  open issues), not something a query change here can fix.
81
83
 
84
+ ## Non-core grammars
85
+
86
+ The `tree-sitter` runner and `symbol_search`/`module_report` structural
87
+ extraction ship a fixed set of core grammars; grammars for the other
88
+ languages in the table above (CUE included) are fetched lazily on first use
89
+ into web-tree-sitter's resolved package directory, verified against
90
+ `scripts/grammars.lock.json`. This resolution works on a runtime that cannot
91
+ resolve a bare package specifier — pi shipped as a `bun build --compile`
92
+ binary — via one shared subpath-based ladder
93
+ (`scripts/lib/web-tree-sitter-dir.mjs`, #3409); before that fix, non-core
94
+ languages could never be analysed on those hosts. A grammar that never loads
95
+ (fetch failure, unwritable target, an unsupported runtime) is recorded as a
96
+ `grammar_unavailable` **skip**, never a clean pass
97
+ (`clients/dispatch/runners/tree-sitter.ts`).
98
+
82
99
  ## Considered and skipped (2026-08-20 survey, closed out by #1757)
83
100
 
84
101
  Recorded so these are not re-litigated. The 2026-08-20 survey's first pass