pi-lens 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CHANGELOG.md +543 -0
  2. package/README.md +45 -2
  3. package/dist/clients/actionable-warnings.js +44 -16
  4. package/dist/clients/advisory-provenance.js +187 -51
  5. package/dist/clients/cache-manager.js +64 -5
  6. package/dist/clients/cascade-format.js +24 -0
  7. package/dist/clients/child-unref.js +17 -8
  8. package/dist/clients/config-diagnostic-codes.js +2 -0
  9. package/dist/clients/config-locations.js +237 -9
  10. package/dist/clients/config-resolve.js +7 -1
  11. package/dist/clients/degradation-ledger.js +33 -3
  12. package/dist/clients/dependency-checker.js +87 -64
  13. package/dist/clients/diagnostic-dispositions.js +39 -3
  14. package/dist/clients/dispatch/finding-policy.js +118 -1
  15. package/dist/clients/dispatch/indent-detect.js +8 -2
  16. package/dist/clients/dispatch/inline-suppressions.js +23 -4
  17. package/dist/clients/dispatch/rule-ignores.js +14 -7
  18. package/dist/clients/dispatch/runners/actionlint.js +26 -28
  19. package/dist/clients/dispatch/runners/biome-check.js +38 -25
  20. package/dist/clients/dispatch/runners/cpp-check.js +32 -49
  21. package/dist/clients/dispatch/runners/credo.js +16 -14
  22. package/dist/clients/dispatch/runners/cue-vet.js +25 -7
  23. package/dist/clients/dispatch/runners/dart-analyze.js +28 -47
  24. package/dist/clients/dispatch/runners/detekt.js +11 -4
  25. package/dist/clients/dispatch/runners/dotnet-build.js +27 -22
  26. package/dist/clients/dispatch/runners/elixir-check.js +31 -46
  27. package/dist/clients/dispatch/runners/eslint.js +29 -46
  28. package/dist/clients/dispatch/runners/gleam-check.js +91 -11
  29. package/dist/clients/dispatch/runners/go-vet.js +16 -2
  30. package/dist/clients/dispatch/runners/golangci-lint.js +38 -23
  31. package/dist/clients/dispatch/runners/hadolint.js +27 -15
  32. package/dist/clients/dispatch/runners/htmlhint.js +17 -8
  33. package/dist/clients/dispatch/runners/javac.js +31 -21
  34. package/dist/clients/dispatch/runners/ktlint.js +34 -60
  35. package/dist/clients/dispatch/runners/lsp.js +6 -5
  36. package/dist/clients/dispatch/runners/markdownlint.js +12 -5
  37. package/dist/clients/dispatch/runners/mypy.js +2 -1
  38. package/dist/clients/dispatch/runners/oxlint.js +22 -6
  39. package/dist/clients/dispatch/runners/php-lint.js +39 -16
  40. package/dist/clients/dispatch/runners/phpstan.js +1 -1
  41. package/dist/clients/dispatch/runners/rubocop.js +27 -18
  42. package/dist/clients/dispatch/runners/ruff.js +18 -19
  43. package/dist/clients/dispatch/runners/rust-clippy.js +6 -1
  44. package/dist/clients/dispatch/runners/shellcheck.js +6 -2
  45. package/dist/clients/dispatch/runners/spellcheck.js +10 -3
  46. package/dist/clients/dispatch/runners/sqlfluff.js +11 -2
  47. package/dist/clients/dispatch/runners/stylelint.js +10 -2
  48. package/dist/clients/dispatch/runners/swiftlint.js +11 -2
  49. package/dist/clients/dispatch/runners/taplo.js +12 -6
  50. package/dist/clients/dispatch/runners/tflint.js +30 -15
  51. package/dist/clients/dispatch/runners/tree-sitter.js +23 -0
  52. package/dist/clients/dispatch/runners/trivy-config.js +8 -2
  53. package/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +11 -1
  54. package/dist/clients/dispatch/runners/vale.js +15 -3
  55. package/dist/clients/dispatch/runners/yamllint.js +12 -2
  56. package/dist/clients/dispatch/runners/zig-check.js +27 -39
  57. package/dist/clients/dispatch/suppress-writer.js +13 -3
  58. package/dist/clients/effective-config.js +3 -1
  59. package/dist/clients/extension-log.js +48 -1
  60. package/dist/clients/finding-delivery-gate.js +53 -23
  61. package/dist/clients/formatters.js +49 -11
  62. package/dist/clients/git-guard.js +247 -34
  63. package/dist/clients/gradle-ktfmt-style.js +121 -25
  64. package/dist/clients/inline-blocker-dispositions.js +186 -0
  65. package/dist/clients/install-diagnostics.js +19 -6
  66. package/dist/clients/installer/index.js +281 -32
  67. package/dist/clients/jscpd-client.js +8 -0
  68. package/dist/clients/latency-logger.js +8 -0
  69. package/dist/clients/lens-config.js +66 -8
  70. package/dist/clients/lsp/cascade-tier.js +3 -0
  71. package/dist/clients/lsp/client.js +139 -11
  72. package/dist/clients/lsp/config.js +9 -7
  73. package/dist/clients/lsp/content-limits.js +41 -0
  74. package/dist/clients/lsp/index.js +42 -8
  75. package/dist/clients/lsp/launch.js +23 -2
  76. package/dist/clients/lsp/server.js +106 -25
  77. package/dist/clients/lsp/sync-kind.js +14 -0
  78. package/dist/clients/lsp/wait-policy/strategies.js +105 -16
  79. package/dist/clients/mcp/analyze.js +9 -2
  80. package/dist/clients/mcp/ipc.js +232 -44
  81. package/dist/clients/mcp/review.js +53 -7
  82. package/dist/clients/opengrep-client.js +11 -6
  83. package/dist/clients/path-utils.js +51 -9
  84. package/dist/clients/persistent-reverify.js +271 -0
  85. package/dist/clients/pipeline.js +136 -67
  86. package/dist/clients/project-diagnostics/fresh-fetch.js +21 -3
  87. package/dist/clients/project-lens-config.js +11 -3
  88. package/dist/clients/review-graph/builder.js +34 -26
  89. package/dist/clients/review-graph/git-identity.js +16 -10
  90. package/dist/clients/ruff-client.js +31 -4
  91. package/dist/clients/runtime-coordinator.js +38 -4
  92. package/dist/clients/runtime-tool-call.js +16 -5
  93. package/dist/clients/runtime-tool-result.js +27 -12
  94. package/dist/clients/runtime-turn.js +571 -287
  95. package/dist/clients/safe-spawn.js +256 -65
  96. package/dist/clients/skills-resolver.js +38 -2
  97. package/dist/clients/spawn-output-cap.js +84 -1
  98. package/dist/clients/tree-sitter-client.js +119 -58
  99. package/dist/clients/turn-end/lane.js +51 -0
  100. package/dist/clients/turn-end/lanes/govulncheck.js +112 -0
  101. package/dist/clients/turn-end/lanes/secrets.js +204 -0
  102. package/dist/clients/warm-attach.js +59 -0
  103. package/dist/clients/widget-state.js +294 -17
  104. package/dist/clients/workspace-topology.js +57 -3
  105. package/dist/clients/zizmor-config.js +26 -13
  106. package/dist/index.js +6342 -3995
  107. package/dist/mcp/analyze-cli.js +4 -0
  108. package/dist/mcp/server.js +33 -21
  109. package/dist/scripts/lib/web-tree-sitter-dir.mjs +123 -0
  110. package/dist/tools/lens-diagnostic-mark.js +14 -2
  111. package/dist/tools/lens-diagnostics.js +127 -33
  112. package/dist/tools/lsp-diagnostics.js +150 -12
  113. package/docs/adr/0001-stale-advisory-live-arm.md +29 -0
  114. package/docs/adr/0002-workspace-hash-rendezvous.md +30 -0
  115. package/docs/adr/0003-git-guard-latch-writer.md +203 -0
  116. package/docs/adr/0004-disposition-policy-seam.md +38 -0
  117. package/docs/adr/0005-tool-availability-enforcement-seam.md +29 -0
  118. package/docs/adr/0006-derived-state-benchmark-first.md +31 -0
  119. package/docs/adr/0007-end-to-end-witness-per-seam-slice.md +38 -0
  120. package/docs/adr/0008-turn-end-lane-interface.md +165 -0
  121. package/docs/adr/0009-reported-path-attribution.md +114 -0
  122. package/docs/adr/README.md +26 -0
  123. package/docs/agent-tools.md +18 -1
  124. package/docs/ast-grep_rules_catalog.md +4 -3
  125. package/docs/configuration.md +55 -1
  126. package/docs/engineering-principles.md +202 -0
  127. package/docs/environment-variables.md +61 -4
  128. package/docs/features.md +2 -2
  129. package/docs/globalconfig.md +6 -1
  130. package/docs/language-coverage.md +17 -0
  131. package/docs/lsp-capability-matrix.md +98 -31
  132. package/docs/pi-lens-fixer.md +57 -3
  133. package/docs/pi-lens-investigator.md +9 -0
  134. package/docs/pi-lens-reviewer.md +16 -0
  135. package/docs/pi-lens-subagent.md +9 -0
  136. package/docs/public-api-stability.md +1 -0
  137. package/docs/release-qa-baseline.md +2 -0
  138. package/docs/servercapabilities.md +21 -11
  139. package/docs/settings.md +12 -3
  140. package/docs/subagent-compat.md +1 -1
  141. package/package.json +5 -3
  142. package/rules/ast-grep-rules/rule-tests/no-assert-tuple-test.yml +13 -0
  143. package/rules/ast-grep-rules/rule-tests/no-boolean-in-except-test.yml +26 -0
  144. package/rules/ast-grep-rules/rule-tests/no-http-headers-bracket-access-test.yml +10 -0
  145. package/rules/ast-grep-rules/rule-tests/unchecked-numeric-parse-python-test.yml +18 -0
  146. package/rules/ast-grep-rules/rule-tests/unchecked-throwing-call-python-test.yml +4 -3
  147. package/rules/ast-grep-rules/rules/go-no-fmt-println.yml +2 -2
  148. package/rules/ast-grep-rules/rules/no-assert-tuple.yml +23 -13
  149. package/rules/ast-grep-rules/rules/no-boolean-in-except.yml +7 -3
  150. package/rules/ast-grep-rules/rules/no-console-except-error-js.yml +2 -2
  151. package/rules/ast-grep-rules/rules/no-console-except-error.yml +2 -2
  152. package/rules/ast-grep-rules/rules/no-http-headers-bracket-access.yml +12 -7
  153. package/rules/ast-grep-rules/rules/unchecked-numeric-parse-python.yml +44 -0
  154. package/rules/ast-grep-rules/rules/unchecked-throwing-call-python.yml +5 -3
  155. package/rules/tree-sitter-queries/typescript/console-statement.yml +2 -2
  156. package/scripts/install-selftest.mjs +21 -17
  157. package/scripts/lib/web-tree-sitter-dir.mjs +123 -0
@@ -8,9 +8,25 @@
8
8
  - Reproduce the claimed behavior through the production entry point.
9
9
  - Report only proven findings; do not repair the author's branch.
10
10
 
11
+ ## Standard mechanics
12
+
13
+ - Write `REVIEW.md` as a file at the worktree root, not only in the final
14
+ answer. Two verifies this week (PR #3261 r3 and PR #3264 r3) delivered the
15
+ review only in the answer text.
16
+ - When the fixer settled before its evidence pass, run the mutation table
17
+ yourself and say so.
18
+
11
19
  ## Verification
12
20
 
13
21
  - Use `git diff origin/master...HEAD` or the merge-base equivalent.
22
+ - For any change involving the pinned retired-synonym identifier population,
23
+ run the exact-pin sweeps on the MERGE of `origin/master` + head, not only on
24
+ the head. `tests/config/glossary-synonym-sweep.test.ts` (#3279) asserts the
25
+ live (term, file) population exactly in both directions; require same-PR
26
+ re-pinning from its `UNPINNED`/`STALE` output. The 2026-09-23 evidence is
27
+ two green PRs merging red (#3279's pins predated #3283, fixed on master by
28
+ #3288), plus #3284's own `path` count red (cue-vet 5→6, dart-analyze 6→4)
29
+ until a trailing re-pin.
14
30
  - Build and run the targeted and required governance suites.
15
31
  - Revert or neuter the source fix and verify the red-first test fails.
16
32
  - Mutate every new guard, filter, cap, fallback, and lifecycle path.
@@ -51,6 +51,15 @@ runner's own notes say which mode lifts it). Run Vitest as
51
51
  tree-sitter grammar prefetch hangs offline, verify through direct probes of the
52
52
  built code and say so; the orchestrator re-runs the files outside the sandbox.
53
53
 
54
+ Every Vitest invocation on the maintainer host exports
55
+ `PI_LENS_TEST_MAX_WORKERS=6` and names its files; never the full suite. The
56
+ plegma daemon's cgroup holds every worker's child processes, and on 2026-09-19
57
+ one fixer's fan-out (16 forks on a 32-core host plus the real language servers
58
+ its probes spawned) took the unit to 64 GB, systemd-oomd killed the daemon, and
59
+ every live worker died with it. Kill every language server a probe spawns
60
+ before moving on; the previous worker's unkilled servers were part of that
61
+ footprint.
62
+
54
63
  When Git authority is granted, use one logical commit with an imperative,
55
64
  conventional-prefix subject of at most 50 characters, a blank line, and a
56
65
  72-column body that states what and why. Reference the issue. Open a PR, do not
@@ -108,6 +108,7 @@ this policy explicitly reserves the right to change.
108
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
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
110
  | `PILENS_CFG_0009` | A tool config key is unknown or names a required, non-disableable tool. | The shared model-facing tool registry (`clients/tool-config.ts`) and both pi/MCP registration surfaces. |
111
+ | `PILENS_CFG_0010` | A lower-precedence supported global config file exists but was shadowed by the winning file. | `reportGlobalConfigShadowing` (`clients/lens-config.ts`), recorded once through `recordDegradationOnce`. |
111
112
 
112
113
  A reserved code is registered and referenced by the deprecation registry, but
113
114
  nothing emits it today. That is deliberate: the number must be pinned before the
@@ -85,6 +85,8 @@ PR's packed tarball (#2700, the check #2587 was missing). `attw`
85
85
  | mcp-lsp-navigation | LSP navigation answers on a fixture | mcp-stdio | `tools/call` `pilens_lsp_navigation` with operation `documentSymbol` and the fixture path | result is not an error and names the fixture's exported `releaseQaFixtureSymbol` | tool result text | `scripts/smoke-tools.mjs --lsp` is the per-server sibling; this row is the packaged-path variant | #1829 lane 2/3 (gated real-binary + the rotating install lane): #1829 pins each tool's own contract, this row pins that the packaged LSP path answers |
86
86
  | config-provenance | a project config is LOADED and its provenance is reportable | mcp-stdio | `tools/call` `pilens_effective_config` with the fixture file | result names the fixture's `.pi-lens.json` as a contributing document | tool result text | new — `tests/config/pi-lens-config-schema.test.ts` covers the schema, not the packaged load | — |
87
87
  | degradation-visible | a silently-ignored input is RECORDED as a degradation instead of vanishing | mcp-stdio | `tools/call` `pilens_health` with the fixture's project-tier `lsp.enabled` (a global-only setting) loaded | health text carries a `config-ignored` degradation line naming the fixture's `.pi-lens.json` | health tool result text | `clients/degradation-ledger.ts` is the reused machinery; no smoke asserts it end to end | #1605 lane 2 (availability-lifecycle): the degradation-recorded half; #1605 additionally asserts RECOVERY, which this row does not |
88
+ | global-config-location | the agent-dir global config file supplies the global tier when it exists and the legacy default does not | mcp-stdio | `tools/call` `pilens_effective_config` on a real pi-lens MCP server whose env sets `PI_CODING_AGENT_DIR` at a scratch dir holding `extensions/pi-lens.json` | the tool result NAMES the agent-dir file as a contributing config document (the `pi-coding-agent-dir` winner) | tool result text | `tests/clients/global-config-location.test.ts` covers the resolution in-process; no smoke drives the packaged MCP path with the env set | — |
89
+ | config-shadow-record | a lower-precedence global config file beside the winner is recorded once per session | mcp-stdio | `tools/call` `pilens_effective_config` then `pilens_health` twice, on a real MCP server whose env has BOTH `~/.pi-lens/config.json` and `PI_CODING_AGENT_DIR/extensions/pi-lens.json` present | health carries a `config-location-shadowed: 1` line naming the shadowed agent-dir file, and the count stays 1 on a second health read after a further config load | the two health tool result texts | `clients/degradation-ledger.ts` `recordDegradationOnce` and `tests/clients/global-config-location.test.ts`; no smoke asserts the record end to end | #1605 lane 2 (availability-lifecycle): the degradation-recorded half, as `degradation-visible`; this row additionally pins the once-per-session count across two loads |
88
90
  | git-install-loads | a `git:` install of a pushed ref builds and loads in a real pi | git-install | `pi install git:github.com/apmantza/pi-lens@<ref>` then `get_commands` | at least 1 `lens-*` command and at least 4 skills | get_commands response JSON | `scripts/rpc-load-check.mjs` assertion, re-run against the git layout | — |
89
91
  | publish-toolchain-pinned | the RELEASE WORKFLOW's publish job runs the npm it pins, and that npm validates the tarball | npm-pack | `npx -y "npm@<packageManager pin>" --version` then `npx -y "npm@<packageManager pin>" publish --dry-run`, both in the scratch export | the pinned invocation reports the pin version AND the dry run exits 0, or npm reports the version is already published after packing; a pinned invocation resolution or registry failure leaves the row UNMEASURED | the two commands with their output | new — `tests/config/release-npm-pin-gate.test.ts` pins release.yml's TEXT; this row is the only thing that RUNS the publish job's toolchain before a tag exists (#2940) | — |
90
92
  | tool-smoke-install | every npm/pip entry in the installer registry resolves on a real install | npm-install | `node <export>/scripts/smoke-tools.mjs --install --install-registry --installer-root=<installed>/` (registry `<installed>/dist/clients/installer/index.js`; about 1m 29s cold on this box for 33 entries; harness from export root) | the report shows every npm/pip entry resolved or a named legitimate skip (toolchain absent, declined), and no genuine install failure; a registry-unreachable classification leaves the lane UNMEASURED; requires network access to the npm and pip registries | install-registry JSON report | `classifyInstallOutcome` from the #2661 fixture lanes — this lane sweeps the whole npm/pip registry, where fixture lanes exercise only the entries their fixtures name | — |
@@ -6,7 +6,7 @@ server's `initialize` handshake. Generated by `node scripts/server-capabilities.
6
6
  absent on the generating host are listed under *Unavailable* — run in a
7
7
  provisioned environment (the nightly) to capture those rows.
8
8
 
9
- _Last generated: 2026-09-09 on linux; 31 servers captured, 13 unavailable._
9
+ _Last generated: 2026-09-23 on linux; 37 servers captured, 9 unavailable._
10
10
 
11
11
  ## Diagnostic mode + navigation/edit operations
12
12
 
@@ -17,13 +17,16 @@ Legend: ✓ advertised, · not. **mode** = document diagnostics (`pull` = `textD
17
17
  | ast-grep | push-only | · | · | · | · | · | ✓ | · | · | · | ✓ | · | · | · | 1 |
18
18
  | bash | push-only | · | ✓ | · | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | · | · | 0 |
19
19
  | clojure | push-only | · | ✓ | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 62 |
20
+ | cpp | push-only | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 3 |
20
21
  | csharp | pull | ✓ | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 0 |
21
22
  | css | pull | · | ✓ | · | · | ✓ | ✓ | · | ✓ | · | ✓ | ✓ | · | · | 0 |
22
23
  | cue | push-only | · | ✓ | · | · | ✓ | ✓ | · | ✓ | · | ✓ | ✓ | · | · | 1 |
23
24
  | dart | push-only | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 18 |
24
25
  | deno | pull | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 2 |
25
26
  | docker | push-only | · | ✓ | · | · | · | ✓ | ✓ | ✓ | · | · | ✓ | · | · | 0 |
27
+ | emmylua | pull | · | ✓ | · | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | · | · | · | 4 |
26
28
  | expert | push-only | · | ✓ | · | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | · | · | · | 2 |
29
+ | fish | push-only | · | ✓ | · | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | · | 22 |
27
30
  | fsharp | push-only | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 0 |
28
31
  | gleam | push-only | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | · | ✓ | ✓ | · | · | 0 |
29
32
  | go | push-only | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 47 |
@@ -33,13 +36,15 @@ Legend: ✓ advertised, · not. **mode** = document diagnostics (`pull` = `textD
33
36
  | marksman | push-only | · | ✓ | · | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | · | · | 0 |
34
37
  | opengrep | push-only | · | · | · | · | · | ✓ | · | · | · | ✓ | · | · | · | 2 |
35
38
  | php | push-only | · | ✓ | · | · | ✓ | ✓ | ✓ | ✓ | ✓ | · | · | · | · | 0 |
36
- | prisma | push-only | · | ✓ | · | · | ✓ | ✓ | · | ✓ | · | · | ✓ | · | · | 0 |
39
+ | powershell | push-only | · | ✓ | · | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | · | · | 0 |
40
+ | prisma | push-only | · | ✓ | · | · | ✓ | ✓ | · | ✓ | · | ✓ | ✓ | · | · | 0 |
37
41
  | python | push-only | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | · | ✓ | 0 |
38
42
  | python-jedi | push-only | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | · | · | 0 |
39
43
  | ruby | pull | · | ✓ | · | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | · | · | 0 |
40
44
  | rust | pull | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 0 |
41
45
  | svelte | pull | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | 0 |
42
46
  | terraform | push-only | · | ✓ | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | · | · | · | 7 |
47
+ | tinymist | push-only | · | ✓ | · | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | · | · | 29 |
43
48
  | toml | push-only | · | · | · | · | · | ✓ | · | ✓ | · | · | ✓ | · | · | 0 |
44
49
  | typescript | push-only | · | ✓ | ✓ | · | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | · | 8 |
45
50
  | typos | push-only | · | · | · | · | · | · | · | · | · | ✓ | · | · | · | 1 |
@@ -53,13 +58,16 @@ Legend: ✓ advertised, · not. **mode** = document diagnostics (`pull` = `textD
53
58
  - **ast-grep**: codeActionProvider, executeCommandProvider, hoverProvider, textDocumentSync
54
59
  - **bash**: codeActionProvider, completionProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentSymbolProvider, hoverProvider, referencesProvider, renameProvider, textDocumentSync, workspaceSymbolProvider
55
60
  - **clojure**: callHierarchyProvider, codeActionProvider, codeLensProvider, completionProvider, declarationProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentRangeFormattingProvider, documentSymbolProvider, executeCommandProvider, experimental, foldingRangeProvider, hoverProvider, implementationProvider, linkedEditingRangeProvider, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, workspace, workspaceSymbolProvider
61
+ - **cpp**: astProvider, callHierarchyProvider, clangdInlayHintsProvider, codeActionProvider, compilationDatabase, completionProvider, declarationProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentLinkProvider, documentOnTypeFormattingProvider, documentRangeFormattingProvider, documentSymbolProvider, executeCommandProvider, foldingRangeProvider, hoverProvider, implementationProvider, inactiveRegionsProvider, inlayHintProvider, memoryUsageProvider, positionEncoding, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, standardTypeHierarchyProvider, textDocumentSync, typeDefinitionProvider, typeHierarchyProvider, workspaceSymbolProvider
56
62
  - **csharp**: callHierarchyProvider, codeActionProvider, codeLensProvider, completionProvider, definitionProvider, diagnosticProvider, documentFormattingProvider, documentHighlightProvider, documentOnTypeFormattingProvider, documentRangeFormattingProvider, documentSymbolProvider, foldingRangeProvider, hoverProvider, implementationProvider, inlayHintProvider, referencesProvider, renameProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, typeHierarchyProvider, workspace, workspaceSymbolProvider
57
63
  - **css**: codeActionProvider, colorProvider, definitionProvider, diagnosticProvider, documentFormattingProvider, documentHighlightProvider, documentLinkProvider, documentRangeFormattingProvider, documentSymbolProvider, foldingRangeProvider, hoverProvider, referencesProvider, renameProvider, selectionRangeProvider, textDocumentSync
58
64
  - **cue**: codeActionProvider, codeLensProvider, completionProvider, definitionProvider, documentFormattingProvider, documentSymbolProvider, executeCommandProvider, hoverProvider, referencesProvider, renameProvider, textDocumentSync, workspace
59
65
  - **dart**: callHierarchyProvider, codeActionProvider, codeLensProvider, colorProvider, completionProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentLinkProvider, documentOnTypeFormattingProvider, documentRangeFormattingProvider, documentSymbolProvider, executeCommandProvider, experimental, foldingRangeProvider, hoverProvider, implementationProvider, inlayHintProvider, inlineValueProvider, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, typeHierarchyProvider, workspace, workspaceSymbolProvider
60
66
  - **deno**: callHierarchyProvider, codeActionProvider, codeLensProvider, completionProvider, definitionProvider, diagnosticProvider, documentFormattingProvider, documentHighlightProvider, documentSymbolProvider, executeCommandProvider, experimental, foldingRangeProvider, hoverProvider, implementationProvider, inlayHintProvider, notebookDocumentSync, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, workspace, workspaceSymbolProvider
61
67
  - **docker**: codeActionProvider, completionProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentLinkProvider, documentOnTypeFormattingProvider, documentRangeFormattingProvider, documentSymbolProvider, foldingRangeProvider, hoverProvider, renameProvider, signatureHelpProvider, textDocumentSync
68
+ - **emmylua**: codeActionProvider, definitionProvider, diagnosticProvider, documentSymbolProvider, executeCommandProvider, hoverProvider, referencesProvider, textDocumentSync, workspaceSymbolProvider
62
69
  - **expert**: codeActionProvider, codeLensProvider, completionProvider, definitionProvider, documentFormattingProvider, documentSymbolProvider, executeCommandProvider, experimental, hoverProvider, referencesProvider, textDocumentSync, workspace, workspaceSymbolProvider
70
+ - **fish**: codeActionProvider, completionProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentOnTypeFormattingProvider, documentRangeFormattingProvider, documentSymbolProvider, executeCommandProvider, foldingRangeProvider, hoverProvider, implementationProvider, inlayHintProvider, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, workspace, workspaceSymbolProvider
63
71
  - **fsharp**: callHierarchyProvider, codeActionProvider, codeLensProvider, completionProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentRangeFormattingProvider, documentSymbolProvider, foldingRangeProvider, hoverProvider, implementationProvider, inlayHintProvider, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, workspaceSymbolProvider
64
72
  - **gleam**: codeActionProvider, completionProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentSymbolProvider, foldingRangeProvider, hoverProvider, referencesProvider, renameProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, workspace
65
73
  - **go**: callHierarchyProvider, codeActionProvider, codeLensProvider, completionProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentLinkProvider, documentSymbolProvider, executeCommandProvider, experimental, foldingRangeProvider, hoverProvider, implementationProvider, inlayHintProvider, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, typeHierarchyProvider, workspace, workspaceSymbolProvider
@@ -69,13 +77,15 @@ Legend: ✓ advertised, · not. **mode** = document diagnostics (`pull` = `textD
69
77
  - **marksman**: codeActionProvider, codeLensProvider, completionProvider, definitionProvider, documentSymbolProvider, executeCommandProvider, hoverProvider, referencesProvider, renameProvider, semanticTokensProvider, textDocumentSync, workspace, workspaceSymbolProvider
70
78
  - **opengrep**: codeActionProvider, executeCommandProvider, hoverProvider, textDocumentSync, workspace
71
79
  - **php**: codeActionProvider, completionProvider, declarationProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentRangeFormattingProvider, documentSymbolProvider, foldingRangeProvider, hoverProvider, implementationProvider, inlineValueProvider, referencesProvider, renameProvider, selectionRangeProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, typeHierarchyProvider, workspace, workspaceSymbolProvider
72
- - **prisma**: completionProvider, definitionProvider, documentFormattingProvider, documentSymbolProvider, hoverProvider, referencesProvider, renameProvider, textDocumentSync
80
+ - **powershell**: codeActionProvider, codeLensProvider, completionProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentRangeFormattingProvider, documentSymbolProvider, experimental, foldingRangeProvider, hoverProvider, referencesProvider, renameProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, workspace, workspaceSymbolProvider
81
+ - **prisma**: codeActionProvider, completionProvider, definitionProvider, documentFormattingProvider, documentSymbolProvider, hoverProvider, referencesProvider, renameProvider, textDocumentSync
73
82
  - **python**: callHierarchyProvider, codeActionProvider, completionProvider, declarationProvider, definitionProvider, documentHighlightProvider, documentSymbolProvider, executeCommandProvider, hoverProvider, referencesProvider, renameProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, workspace, workspaceSymbolProvider
74
83
  - **python-jedi**: codeActionProvider, completionProvider, declarationProvider, definitionProvider, documentHighlightProvider, documentSymbolProvider, executeCommandProvider, hoverProvider, positionEncoding, referencesProvider, renameProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, workspace, workspaceSymbolProvider
75
84
  - **ruby**: codeActionProvider, codeLensProvider, completionProvider, definitionProvider, diagnosticProvider, documentHighlightProvider, documentLinkProvider, documentOnTypeFormattingProvider, documentRangeFormattingProvider, documentSymbolProvider, experimental, foldingRangeProvider, hoverProvider, inlayHintProvider, positionEncoding, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, typeHierarchyProvider, workspaceSymbolProvider
76
85
  - **rust**: callHierarchyProvider, codeActionProvider, codeLensProvider, completionProvider, declarationProvider, definitionProvider, diagnosticProvider, documentFormattingProvider, documentHighlightProvider, documentOnTypeFormattingProvider, documentRangeFormattingProvider, documentSymbolProvider, experimental, foldingRangeProvider, hoverProvider, implementationProvider, inlayHintProvider, positionEncoding, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, workspace, workspaceSymbolProvider
77
86
  - **svelte**: callHierarchyProvider, codeActionProvider, codeLensProvider, colorProvider, completionProvider, definitionProvider, diagnosticProvider, documentFormattingProvider, documentHighlightProvider, documentSymbolProvider, foldingRangeProvider, hoverProvider, implementationProvider, inlayHintProvider, linkedEditingRangeProvider, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, workspaceSymbolProvider
78
87
  - **terraform**: codeActionProvider, codeLensProvider, completionProvider, declarationProvider, definitionProvider, documentFormattingProvider, documentLinkProvider, documentSymbolProvider, executeCommandProvider, experimental, hoverProvider, referencesProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, workspace, workspaceSymbolProvider
88
+ - **tinymist**: codeActionProvider, codeLensProvider, colorProvider, completionProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentLinkProvider, documentRangeFormattingProvider, documentSymbolProvider, executeCommandProvider, experimental, foldingRangeProvider, hoverProvider, inlayHintProvider, positionEncoding, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, workspace, workspaceSymbolProvider
79
89
  - **toml**: completionProvider, documentFormattingProvider, documentLinkProvider, documentSymbolProvider, foldingRangeProvider, hoverProvider, renameProvider, semanticTokensProvider, textDocumentSync, workspace
80
90
  - **typescript**: codeActionProvider, codeLensProvider, completionProvider, definitionProvider, documentFormattingProvider, documentHighlightProvider, documentRangeFormattingProvider, documentSymbolProvider, executeCommandProvider, foldingRangeProvider, hoverProvider, implementationProvider, inlayHintProvider, linkedEditingRangeProvider, referencesProvider, renameProvider, selectionRangeProvider, semanticTokensProvider, signatureHelpProvider, textDocumentSync, typeDefinitionProvider, workspace, workspaceSymbolProvider
81
91
  - **typos**: codeActionProvider, executeCommandProvider, positionEncoding, textDocumentSync, workspace
@@ -91,15 +101,19 @@ surface, including providers pi-lens does not yet consume.
91
101
 
92
102
  - **ast-grep** (1): ast-grep.applyAllFixes
93
103
  - **clojure** (62): add-import-to-namespace, add-missing-import, add-missing-libspec, add-require-suggestion, as-to-refer, backward, backward-barf, backward-select, backward-slurp, change-coll, clean-ns, cond->if-refactor, create-function, create-test, cursor-info, cycle-coll, cycle-keyword-auto-resolve, cycle-privacy, demote-fn, destructure-keys, drag-backward, drag-forward, drag-param-backward, drag-param-forward, expand-let, extract-function, extract-to-def, forward, forward-barf, forward-select, forward-slurp, get-in-all, get-in-less, get-in-more, get-in-none, if->cond-refactor, inline-function, inline-symbol, introduce-let, kill-sexp, …
104
+ - **cpp** (3): clangd.applyFix, clangd.applyRename, clangd.applyTweak
94
105
  - **cue** (1): cuelsp.externalvalidate
95
- - **dart** (18): dart.edit.codeAction.apply, dart.edit.sortMembers, dart.edit.organizeImports, dart.edit.fixAll, dart.edit.fixAllInWorkspace.preview, dart.edit.fixAllInWorkspace, dart.edit.sendWorkspaceEdit, refactor.perform, refactor.validate, dart.logAction, dart.refactor.add_constructor_name, dart.refactor_add.import_prefix, dart.refactor.convert_all_formal_parameters_to_named, dart.refactor.convert_selected_formal_parameters_to_named, dart.refactor.move_selected_formal_parameters_left, dart.refactor.move_top_level_to_file, dart.refactor.remove_constructor_name, dart.refactor.remove_import_prefix
106
+ - **dart** (18): dart.edit.codeAction.apply, dart.edit.fixAll, dart.edit.fixAllInWorkspace, dart.edit.fixAllInWorkspace.preview, dart.edit.organizeImports, dart.edit.sendWorkspaceEdit, dart.edit.sortMembers, dart.logAction, dart.refactor.add_constructor_name, dart.refactor.convert_all_formal_parameters_to_named, dart.refactor.convert_selected_formal_parameters_to_named, dart.refactor.move_selected_formal_parameters_left, dart.refactor.move_top_level_to_file, dart.refactor.remove_constructor_name, dart.refactor.remove_import_prefix, dart.refactor_add.import_prefix, refactor.perform, refactor.validate
96
107
  - **deno** (2): deno.cache, deno.reloadImportRegistries
108
+ - **emmylua** (4): fake.applyEdit, fake.applyEditDeferred, fake.doThing, fake.releaseDeferredApplyEdit
97
109
  - **expert** (2): Reindex, connectionDetails
110
+ - **fish** (22): fish-lsp.checkHealth, fish-lsp.createTheme, fish-lsp.execute, fish-lsp.executeBuffer, fish-lsp.executeLine, fish-lsp.executeRange, fish-lsp.fixAll, fish-lsp.generateEnvVariables, fish-lsp.showEnvVariables, fish-lsp.showInfo, fish-lsp.showReferences, fish-lsp.showStatusDocs, fish-lsp.showWorkspaceMessage, fish-lsp.toggleSingleWorkspaceSupport, fish-lsp.updateWorkspace, quickfix.delete, quickfix.disable, quickfix.fix, quickfix.fixAll, refactor.extract, refactor.rewrite, source.rename
98
111
  - **go** (47): gopls.add_dependency, gopls.add_import, gopls.add_telemetry_counters, gopls.add_test, gopls.apply_fix, gopls.assembly, gopls.change_signature, gopls.check_upgrades, gopls.client_open_url, gopls.diagnose_files, gopls.doc, gopls.edit_go_directive, gopls.extract_to_new_file, gopls.fetch_vulncheck_result, gopls.free_symbols, gopls.gc_details, gopls.generate, gopls.go_get_package, gopls.implement_interface, gopls.list_imports, gopls.list_known_packages, gopls.lsp, gopls.maybe_prompt_for_telemetry, gopls.mem_stats, gopls.modify_tags, gopls.modules, gopls.move_type, gopls.package_symbols, gopls.packages, gopls.regenerate_cgo, gopls.remove_dependency, gopls.reset_go_mod_diagnostics, gopls.run_go_work_command, gopls.run_govulncheck, gopls.run_tests, gopls.scan_imports, gopls.split_package, gopls.start_debugging, gopls.start_profile, gopls.stop_profile, …
99
- - **lua** (6): lua.removeSpace, lua.solve, lua.jsonToLua, lua.setConfig, lua.getConfig, lua.autoRequire
100
- - **opengrep** (2): semgrep/ignore, semgrep/autofix
112
+ - **lua** (6): lua.autoRequire, lua.getConfig, lua.jsonToLua, lua.removeSpace, lua.setConfig, lua.solve
113
+ - **opengrep** (2): semgrep/autofix, semgrep/ignore
101
114
  - **terraform** (7): terraform-ls.module.callers, terraform-ls.module.calls, terraform-ls.module.providers, terraform-ls.module.terraform, terraform-ls.rootmodules, terraform-ls.terraform.init, terraform-ls.terraform.validate
102
- - **typescript** (8): _typescript.applyRefactoring, _typescript.configurePlugin, _typescript.organizeImports, _typescript.applyRenameFile, _typescript.goToSourceDefinition, _typescript.applyCodeActionCommand, _typescript.applyFixAllCodeAction, typescript.tsserverRequest
115
+ - **tinymist** (29): tinymist.doClearCache, tinymist.doGetTemplateEntry, tinymist.doInitTemplate, tinymist.doKillPreview, tinymist.doStartBrowsingPreview, tinymist.doStartPreview, tinymist.exportAnsiHighlight, tinymist.exportAst, tinymist.exportBundle, tinymist.exportHtml, tinymist.exportMarkdown, tinymist.exportPdf, tinymist.exportPng, tinymist.exportQuery, tinymist.exportSvg, tinymist.exportTeX, tinymist.exportText, tinymist.focusMain, tinymist.getDocumentMetrics, tinymist.getDocumentTrace, tinymist.getResources, tinymist.getServerInfo, tinymist.getWorkspaceLabels, tinymist.interactCodeContext, tinymist.pinMain, tinymist.scrollPreview, tinymist.startDefaultPreview, tinymist.startServerProfiling, tinymist.stopServerProfiling
116
+ - **typescript** (8): _typescript.applyCodeActionCommand, _typescript.applyFixAllCodeAction, _typescript.applyRefactoring, _typescript.applyRenameFile, _typescript.configurePlugin, _typescript.goToSourceDefinition, _typescript.organizeImports, typescript.tsserverRequest
103
117
  - **typos** (1): ignore-in-project
104
118
  - **yaml** (1): jumpToSchema
105
119
 
@@ -108,11 +122,7 @@ surface, including providers pi-lens does not yet consume.
108
122
  Toolchain/binary not installed here, so capabilities weren't captured
109
123
  (many are the toolchain-gated family tracked in #241):
110
124
 
111
- - @prisma/language-server
112
- - PowerShell Editor Services (pwsh Start-EditorServices.ps1 -Stdio)
113
- - clangd
114
125
  - cmake-language-server
115
- - fish-lsp
116
126
  - haskell-language-server
117
127
  - jdtls
118
128
  - jdtls + lombok javaagent
package/docs/settings.md CHANGED
@@ -29,7 +29,8 @@ contract.
29
29
  CI-scoped switches and for the handful of tuning knobs that have no config key.
30
30
  2. **CLI flags** (`--no-lsp`, `--immediate-format`, …) — per-session, passed on
31
31
  the pi command line.
32
- 3. **Config JSON** — a per-user global file (`~/.pi-lens/config.json`) and an
32
+ 3. **Config JSON** — a per-user global file selected by the
33
+ [global-location table](configuration.md#global-config-location) and an
33
34
  optional per-project file (`.pi-lens.json` at the repo root).
34
35
 
35
36
  Every runtime toggle is settable **both** from the CLI and from `config.json`;
@@ -108,6 +109,9 @@ tool. The loader `pi_lens_activate_tools` and MCP lifecycle tools
108
109
  required by their host protocols and cannot be disabled. Unknown or
109
110
  non-disableable names emit `PILENS_CFG_0009`.
110
111
 
112
+ When a lower-precedence supported global config file is shadowed by the
113
+ winning file, pi-lens records the notice once with `PILENS_CFG_0010`.
114
+
111
115
  Valid names for `tools.<name>.enabled` include `ast_grep_search`,
112
116
  `ast_grep_replace`, `ast_grep_outline`, `lsp_navigation`,
113
117
  `lens_diagnostics`, `lens_diagnostic_mark`, `symbol_search`,
@@ -149,9 +153,10 @@ field docs.
149
153
 
150
154
  ## Global vs project config
151
155
 
152
- ### Global — `~/.pi-lens/config.json`
156
+ ### Global — winning location
153
157
 
154
- User-level. Applies to **every** project. Honors **all** flag keys from the
158
+ User-level. The file is selected by the [global-location table](configuration.md#global-config-location)
159
+ and applies to **every** project. It honors **all** flag keys from the
155
160
  table above plus the non-flag global knobs (`ignore`, `widget.visible`,
156
161
  `dispatch.runnerTimeoutFloorMs`, `format.mode`,
157
162
  `actionableWarnings.autoFix.maxFixes`). On Windows the path is
@@ -238,6 +243,10 @@ manager, or CI config. The handful you are most likely to reach for:
238
243
  review graph) out of the workspace.
239
244
  - `PI_LENS_HOME` — relocate the machine-global root (logs, tool binaries, install
240
245
  caches, instance registry).
246
+ - `PI_LENS_CONFIG_PATH` — point the global config file at an explicit path.
247
+ - `PI_CODING_AGENT_DIR` — when pi sets it, `$PI_CODING_AGENT_DIR/extensions/
248
+ pi-lens.json` is read when it exists and the default global config file does
249
+ not; pi-lens does not write the file.
241
250
  - `PI_LENS_MAX_PROJECT_FILES` — base project-size scale knob (default `2000`).
242
251
  - `PI_LENS_STARTUP_MODE` — force the startup path: `full`, `minimal`, or `quick`.
243
252
 
@@ -17,7 +17,7 @@ every run.
17
17
 
18
18
  | # | Contract | Depended on by | Third-party file (as of the versions below) | Verified against |
19
19
  |---|----------|-----------------|-------------------------------------------------|-------------------|
20
- | 1 | `PI_SUBAGENT_CHILD` is set to the literal string `"1"` on every process that hosts a child session. | `clients/subagent-mode.ts` (`isSubagentSession()`, `getSubagentIdentity()`) | `pi-subagents@0.34.0` — co-located in `src/runs/shared/pi-args.ts` (`SUBAGENT_CHILD_ENV` const + the `env[SUBAGENT_CHILD_ENV] = "1"` assignment); as of `pi-subagents@0.66.0` the const moved to `src/runs/shared/child-runtime-config.ts` and the assignment to `src/runs/background/subagent-runner.ts` (#2581) — `compat-contract-locator.mjs`'s `locateContractSources` tries both layouts and concatenates whichever resolves. | `checkNicobailonChildEnv` |
20
+ | 1 | `PI_SUBAGENT_CHILD` is set to the literal string `"1"` on every process that hosts a child session. | `clients/subagent-mode.ts` (`isSubagentSession()`, `getSubagentIdentity()`) | `pi-subagents@0.34.0` — co-located in `src/runs/shared/pi-args.ts` (`SUBAGENT_CHILD_ENV` const + the `env[SUBAGENT_CHILD_ENV] = "1"` assignment); as of `pi-subagents@0.66.0` the const moved to `src/runs/shared/child-runtime-config.ts` and the assignment to `src/runs/background/subagent-runner.ts` (#2581); as of `0.70.0`, the published files are `src/runs/shared/child-runtime-config.js` and `src/runs/background/subagent-runner.js` — `compat-contract-locator.mjs`'s `locateContractSources` tries all layouts and concatenates whichever resolves. | `checkNicobailonChildEnv` |
21
21
  | 1b | avtc-pi-subagent sets `PI_SUBAGENT_CHILD_AGENT` + `PI_SUBAGENT_PARENT_PID` (never `PI_SUBAGENT_CHILD`) on the per-spawn subagent env; `isSubagentSession()` treats the PAIR (both non-empty) as an additional subagent signal (#507). | `clients/subagent-mode.ts` (`isSubagentSession()`, `getSubagentIdentity()`) | `avtc-pi-subagent@1.0.3` — `src/process-runner.ts` (`subagentEnv.PI_SUBAGENT_CHILD_AGENT = agent.name` + `subagentEnv.PI_SUBAGENT_PARENT_PID = String(process.pid)`) | `checkAvtcChildEnv` |
22
22
  | 2a | The pi SDK's extension loader keeps a **process-global** cache (`extensionCache = new Map()`). This is what makes an in-process `bindExtensions()` reuse pi-lens's own module-scope singletons instead of a fresh isolated instance. | `clients/session-lifecycle.ts` (the whole premise of the concurrent-session guard) | `@earendil-works/pi-coding-agent@0.80.6` — `dist/core/extensions/loader.js` | `checkSdkExtensionCache` |
23
23
  | 2b | `AgentSession.bindExtensions()` **unconditionally** emits a `session_start`-typed event (`this._extensionRunner.emit(this._sessionStartEvent)`). | Same as 2a — this is why an in-process subagent bind re-triggers pi-lens's `session_start` handler at all. | `@earendil-works/pi-coding-agent@0.80.6` — `dist/core/agent-session.js` (`bindExtensions()`, ~line 1717) | `checkSdkBindExtensionsEmitsSessionStart` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-lens",
3
- "version": "4.2.0",
3
+ "version": "4.3.0",
4
4
  "type": "module",
5
5
  "description": "Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo",
6
6
  "repository": {
@@ -20,9 +20,10 @@
20
20
  "prepare": "npm run build:dist && node scripts/download-grammars.js --core --dest grammars && node scripts/setup-git-hooks.mjs && node scripts/warm-loader-cache.mjs",
21
21
  "prepack": "node scripts/strip-dev-deps-for-pack.mjs --strip",
22
22
  "postpack": "node scripts/strip-dev-deps-for-pack.mjs --restore",
23
- "lint": "tsc --project tsconfig.json && npm run lint:js",
23
+ "lint": "tsc --project tsconfig.json && npm run lint:js && npm run lint:js:tests",
24
24
  "lint:js": "oxlint --deny-warnings --import-plugin --promise-plugin -D block-scoped-var -D import/default -D import/namespace -D import/no-absolute-path -D import/no-empty-named-blocks -D import/no-named-as-default -D import/no-self-import -D no-extend-native -D no-extra-bind -D no-implied-eval -D no-new -D no-unexpected-multiline -D no-useless-constructor -D oxc/approx-constant -D oxc/misrefactored-assign-op -D oxc/no-accumulating-spread -D oxc/no-async-endpoint-handlers -D oxc/no-this-in-exported-function -D promise/no-callback-in-promise -D promise/no-multiple-resolved -D promise/no-new-statics -D promise/valid-params -D typescript/no-confusing-non-null-assertion -D typescript/no-extraneous-class -D typescript/no-unnecessary-type-constraint -D typescript/no-unsafe-enum-comparison -D unicorn/no-accessor-recursion -D unicorn/no-array-fill-with-reference-type -D unicorn/no-confusing-array-with -D unicorn/no-instanceof-builtins -D unicorn/prefer-array-flat-map -D unicorn/require-module-specifiers --ignore-pattern \"tests/**/*.ts\" --ignore-pattern \"tests/**/*.tsx\" --ignore-pattern \"**/*.d.mts\" --ignore-pattern \"tests/fixtures/autofix-smoke/**\" --ignore-pattern \"tests/fixtures/format-smoke/**\" --ignore-pattern \"tests/fixtures/tool-smoke/**\" --ignore-pattern \"tests/fixtures/call-graph/javascript/**\" --ignore-pattern \"tests/fixtures/function-facts/javascript-parameter.js\" .",
25
- "lint:js:advisory": "node scripts/lint-js-advisory.mjs --deny-warnings --format default -D correctness -D suspicious -D perf --import-plugin --promise-plugin --type-aware -A no-underscore-dangle -A no-await-in-loop -A unicorn/no-array-sort -A unicorn/consistent-function-scoping -A promise/no-promise-in-callback -A no-useless-call -A import/no-unassigned-import -A no-unmodified-loop-condition --ignore-pattern \"**/*.d.mts\" --ignore-pattern \"tests/fixtures/autofix-smoke/**\" --ignore-pattern \"tests/fixtures/format-smoke/**\" --ignore-pattern \"tests/fixtures/tool-smoke/**\" --ignore-pattern \"tests/fixtures/call-graph/javascript/**\" --ignore-pattern \"tests/fixtures/function-facts/javascript-parameter.js\" .",
25
+ "lint:js:advisory": "node scripts/lint-js-advisory.mjs --deny-warnings --format unix -D correctness -D suspicious -D perf --import-plugin --promise-plugin --type-aware -A no-underscore-dangle -A no-await-in-loop -A unicorn/no-array-sort -A unicorn/consistent-function-scoping -A promise/no-promise-in-callback -A no-useless-call -A import/no-unassigned-import -A no-unmodified-loop-condition --ignore-pattern \"**/*.d.mts\" --ignore-pattern \"tests/fixtures/autofix-smoke/**\" --ignore-pattern \"tests/fixtures/format-smoke/**\" --ignore-pattern \"tests/fixtures/tool-smoke/**\" --ignore-pattern \"tests/fixtures/call-graph/javascript/**\" --ignore-pattern \"tests/fixtures/function-facts/javascript-parameter.js\" .",
26
+ "lint:js:tests": "node scripts/lint-js-advisory.mjs --deny-warnings --format unix --type-aware -A correctness -A suspicious -A perf --ignore-pattern \"tests/fixtures/**\" tests",
26
27
  "depcruise:check": "depcruise --validate --config .dependency-cruiser.cjs --ignore-known .dependency-cruiser-known-violations.json --output-type err index.ts \"clients/**/*.ts\"",
27
28
  "fmt": "oxfmt",
28
29
  "fmt:check": "oxfmt --check",
@@ -103,6 +104,7 @@
103
104
  "scripts/install-selftest.mjs",
104
105
  "scripts/lib/host-provided-deps.mjs",
105
106
  "scripts/lib/skills-predicate.mjs",
107
+ "scripts/lib/web-tree-sitter-dir.mjs",
106
108
  "scripts/lib/warm-loader-cache.mjs",
107
109
  "scripts/warm-loader-cache.mjs",
108
110
  "scripts/rpc-load-check.mjs",
@@ -4,9 +4,22 @@ valid:
4
4
  - 'assert x == 1'
5
5
  - 'assert x, "message"'
6
6
  - 'assert (x == 1), "message"' # explicit grouping, not a tuple
7
+ - 'assert actual == (1, 2)'
8
+ - 'assert (actual == (1, 2))'
9
+ - 'assert (f((1, 2)))'
10
+ - 'assert (left, right) == expected'
11
+ - 'assert value in {(1, 2), (3, 4)}'
12
+ - 'assert {item for item in values if item != (1, 2)}'
13
+ - 'assert all(item in {(1, 2)} for item in values)'
14
+ - 'assert True, ("tuple", "message")'
15
+ - 'assert actual == (1, 2), ("tuple", "message")'
7
16
  invalid:
17
+ - 'assert ()'
8
18
  - 'assert (1, 2)'
9
19
  - 'assert (x, y)'
20
+ - 'assert ((x, y))'
21
+ - 'assert (((x, y)))'
22
+ - 'assert (x, y), ("tuple", "message")'
10
23
  - 'assert (1, 2, 3), "message"'
11
24
  - |
12
25
  def f():
@@ -15,6 +15,21 @@ valid:
15
15
  x()
16
16
  except:
17
17
  pass
18
+ - |
19
+ # #3211: body-only `or` must not be flagged — the handler condition
20
+ # itself is a plain exception type, only the return value uses `or`.
21
+ try:
22
+ x()
23
+ except Exception:
24
+ return 2 or 3
25
+ - |
26
+ # #3211: same shape one level deeper (an `if` inside the handler
27
+ # body) — still not a boolean-in-except-clause target.
28
+ try:
29
+ x()
30
+ except Exception:
31
+ if cond:
32
+ x = a or b
18
33
  invalid:
19
34
  - |
20
35
  try:
@@ -26,3 +41,14 @@ invalid:
26
41
  x()
27
42
  except ValueError and KeyError:
28
43
  pass
44
+ - |
45
+ # #3211: a nested try whose OWN except clause has the boolean
46
+ # condition must still be flagged, even though it sits inside an
47
+ # outer handler whose body also contains an `or`.
48
+ try:
49
+ outer()
50
+ except Exception:
51
+ try:
52
+ inner()
53
+ except (A or B):
54
+ return 3 or 4
@@ -2,6 +2,16 @@ id: no-http-headers-bracket-access
2
2
  valid:
3
3
  - "auth = request.headers.get('Authorization')"
4
4
  - "auth = request.headers.get('Authorization', '')"
5
+ - |
6
+ # #3211: a plain assignment through the bracket sets the header —
7
+ # it cannot raise KeyError, so it is not a read-site false positive.
8
+ resp.headers["X"] = "v"
9
+ - |
10
+ # #3211: augmented assignment is still a write, not a read.
11
+ resp.headers["X"] += "b"
12
+ - |
13
+ # #3211: `del` removes the key; it never raises KeyError either.
14
+ del resp.headers["Y"]
5
15
  invalid:
6
16
  - 'auth = request.headers["Authorization"]'
7
17
  - 'auth = response.headers["X-Request-Id"]'
@@ -0,0 +1,18 @@
1
+ id: unchecked-numeric-parse-python
2
+ valid:
3
+ - |
4
+ # #3211: already-converted-by-construction — Decimal raises
5
+ # decimal.InvalidOperation, not ValueError, and is excluded here.
6
+ x = float(Decimal("1.5"))
7
+ - |
8
+ # #3211: a numeric literal argument can never raise ValueError.
9
+ x = int(3.7)
10
+ - |
11
+ try:
12
+ g = int(s)
13
+ except ValueError:
14
+ pass
15
+ invalid:
16
+ - 'int("42")'
17
+ - 'float("3.14")'
18
+ - 'int(user_input)'
@@ -12,12 +12,13 @@ valid:
12
12
  except OSError:
13
13
  return None
14
14
  - 'CONSTANT = 42'
15
+ - |
16
+ # #3211: int()/float() moved to unchecked-numeric-parse-python — this
17
+ # rule no longer fires on the numeric-parse shape.
18
+ x = int(s)
15
19
  invalid:
16
20
  - 'data = json.loads(raw)'
17
21
  - 'f = open(path)'
18
22
  - 'os.remove(path)'
19
23
  - 'os.stat(path)'
20
24
  - 'shutil.rmtree(path)'
21
- - 'int("42")'
22
- - 'float("3.14")'
23
- - 'int(user_input)'
@@ -26,8 +26,8 @@ constraints:
26
26
  ignores:
27
27
  - "**/*_test.go"
28
28
  - "**/examples/**"
29
- - "tests/fixtures/**"
30
- - "cases/**"
29
+ - "**/tests/fixtures/**"
30
+ - "**/cases/**"
31
31
  tags:
32
32
  - go
33
33
  - idiom
@@ -1,24 +1,34 @@
1
1
  id: no-assert-tuple
2
2
  language: Python
3
3
  message: "Assert should not be called on a tuple literal"
4
- severity: error
4
+ severity: warning
5
5
  note: |
6
6
  Port of SonarCloud python:S5905.
7
7
 
8
8
  `assert (a, b)` is always truthy because the tuple `(a, b)` is a
9
- non-empty object. This is almost always a bug — the developer
10
- probably meant `assert a, b` (two separate arguments) or
11
- `assert (a == b)`.
9
+ non-empty object. The developer probably meant `assert a, b` (an
10
+ assertion with a message) or `assert (a == b)`.
12
11
 
13
- The rule matches `assert` followed by a tuple literal. In Python
14
- AST, `assert (1, 2)` parses as `assert_statement` whose test
15
- is a `tuple` node (not parenthesized — the parens are just
16
- grouping).
12
+ Bind the assertion's condition separately from its optional message,
13
+ then require that condition to be a tuple or a parentheses-only chain
14
+ ending in a tuple. Comparisons, calls, comprehensions, containers, and
15
+ tuple-valued assertion messages remain valid. The rule remains a
16
+ warning pending the multi-corpus false-positive audit required for
17
+ error severity.
17
18
  metadata:
18
19
  sonar: S5905
19
20
  rule:
20
- all:
21
- - kind: assert_statement
22
- - has:
23
- kind: tuple
24
- stopBy: end
21
+ pattern: assert $COND
22
+ constraints:
23
+ COND:
24
+ any:
25
+ - kind: tuple
26
+ - all:
27
+ - kind: parenthesized_expression
28
+ - has:
29
+ kind: tuple
30
+ stopBy:
31
+ not:
32
+ any:
33
+ - kind: parenthesized_expression
34
+ - kind: tuple
@@ -11,8 +11,12 @@ note: |
11
11
  developer meant `except (ValueError, KeyError):` (a tuple of
12
12
  exception types).
13
13
 
14
- Matches an `except_clause` whose direct children contain a
15
- `boolean_operator` (and/or) node.
14
+ Matches an `except_clause` whose search for a `boolean_operator`
15
+ (and/or) descendant stops at the handler's own `block` — the
16
+ clause's condition, not anything inside the handler's body (a
17
+ `return x or y` or an `x = a or b` in the body is not a false
18
+ target; a nested `try`'s own `except` clause is checked on its
19
+ own merits when the walk reaches it).
16
20
  metadata:
17
21
  sonar: S5714
18
22
  rule:
@@ -20,4 +24,4 @@ rule:
20
24
  - kind: except_clause
21
25
  - has:
22
26
  kind: boolean_operator
23
- stopBy: end
27
+ stopBy: { kind: block }
@@ -11,8 +11,8 @@ note: |
11
11
  just trains users to ignore the rule; `ignores` below carves those paths
12
12
  out while application/library code elsewhere still gets flagged (#965).
13
13
  ignores:
14
- - "scripts/**"
15
- - "bin/**"
14
+ - "**/scripts/**"
15
+ - "**/bin/**"
16
16
  - "**/logger.ts"
17
17
  - "**/logger.js"
18
18
  - "**/logger.mjs"
@@ -11,8 +11,8 @@ note: |
11
11
  just trains users to ignore the rule; `ignores` below carves those paths
12
12
  out while application/library code elsewhere still gets flagged (#965).
13
13
  ignores:
14
- - "scripts/**"
15
- - "bin/**"
14
+ - "**/scripts/**"
15
+ - "**/bin/**"
16
16
  - "**/logger.ts"
17
17
  - "**/logger.js"
18
18
  - "**/logger.mjs"
@@ -9,14 +9,19 @@ note: |
9
9
  missing. Use `request.headers.get("X-Foo")` (returns None) or
10
10
  `request.headers["X-Foo"]` after a guard check.
11
11
 
12
- Matches bracket-style subscript on a `headers` attribute. The
13
- call shape `request.headers[...]` and `response.headers[...]`
14
- are the most common cases.
12
+ Matches bracket-style subscript READS on a `headers` attribute
13
+ (`$REQ.headers[$KEY]` already subsumes the `request.`/`response.`-
14
+ named forms). A write through the same bracket syntax —
15
+ `resp.headers["X"] = v`, `resp.headers["X"] += v`, or
16
+ `del resp.headers["X"]` — sets or removes the header and can never
17
+ raise KeyError, so those are excluded.
15
18
  metadata:
16
19
  sonar: S8371
17
20
  rule:
18
- any:
21
+ all:
19
22
  - pattern: "$REQ.headers[$KEY]"
20
- - pattern: "$RES.headers[$KEY]"
21
- - pattern: "request.headers[$KEY]"
22
- - pattern: "response.headers[$KEY]"
23
+ - not:
24
+ any:
25
+ - inside: { kind: assignment, field: left }
26
+ - inside: { kind: augmented_assignment, field: left }
27
+ - inside: { kind: delete_statement }
@@ -0,0 +1,44 @@
1
+ id: unchecked-numeric-parse-python
2
+ language: Python
3
+ severity: warning
4
+ message: "int()/float() without try/except — raises ValueError on non-numeric input"
5
+ note: |
6
+ Split out of `unchecked-throwing-call-python` (#3211): `int()`/`float()`
7
+ raise `ValueError` on non-numeric strings, but whether a given call CAN
8
+ raise depends on the argument's runtime type — often undecidable from
9
+ syntax alone — so this ships at `warning`, separate from the
10
+ syntactically-certain `error`-level calls (open/json/os/shutil).
11
+
12
+ Excluded as already-safe by construction: a numeric literal argument
13
+ (`int(3.7)`), and an argument that is itself a call to `int()`/
14
+ `float()`/`Decimal()` (already-converted, or a `Decimal` — which raises
15
+ `decimal.InvalidOperation`, not `ValueError`, and is out of scope here).
16
+
17
+ Residual, undecidable false positive: a call whose argument is a typed
18
+ parameter already known to be numeric, e.g.
19
+
20
+ def f(valor: Decimal):
21
+ return float(valor) # valor is a Decimal, not a raw string
22
+
23
+ The rule cannot see the parameter's declared type from the call site.
24
+ Suppress that shape explicitly:
25
+
26
+ return float(valor) # pi-lens-ignore: unchecked-numeric-parse-python
27
+ rule:
28
+ any:
29
+ - pattern: int($EXPR)
30
+ - pattern: float($EXPR)
31
+ not:
32
+ any:
33
+ - inside:
34
+ stopBy: end
35
+ kind: try_statement
36
+ - has:
37
+ field: arguments
38
+ has:
39
+ any:
40
+ - kind: integer
41
+ - kind: float
42
+ - pattern: Decimal($$$)
43
+ - pattern: int($$$)
44
+ - pattern: float($$$)
@@ -9,7 +9,11 @@ note: |
9
9
  json.loads(): raises json.JSONDecodeError on malformed JSON
10
10
  os.stat(): raises FileNotFoundError, PermissionError
11
11
  os.remove(): raises FileNotFoundError, PermissionError
12
- int()/float():raises ValueError on non-numeric strings
12
+
13
+ `int()`/`float()` are a separate rule, `unchecked-numeric-parse-python`
14
+ (#3211): whether they can raise depends on the argument's runtime type,
15
+ which is often undecidable from syntax alone (a typed parameter, a prior
16
+ guard), so they ship at `warning` instead of `error` here.
13
17
 
14
18
  ✅ WRAP IN TRY/EXCEPT:
15
19
  try:
@@ -40,8 +44,6 @@ rule:
40
44
  - pattern: shutil.copy($$$)
41
45
  - pattern: shutil.move($$$)
42
46
  - pattern: shutil.rmtree($$$)
43
- - pattern: int($EXPR)
44
- - pattern: float($EXPR)
45
47
  not:
46
48
  inside:
47
49
  stopBy: end