pi-lens 4.1.0 → 4.1.2

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/CHANGELOG.md +185 -0
  2. package/README.md +106 -0
  3. package/dist/clients/actionable-warnings-logger.js +2 -1
  4. package/dist/clients/actionable-warnings.js +14 -5
  5. package/dist/clients/advisory-provenance.js +48 -18
  6. package/dist/clients/ast-grep-client.js +1 -3
  7. package/dist/clients/atomic-write-staging.js +16 -4
  8. package/dist/clients/bash-file-access.js +99 -6
  9. package/dist/clients/biome-client.js +1 -3
  10. package/dist/clients/blocker-freshness.js +21 -8
  11. package/dist/clients/blocker-past-eof.js +16 -6
  12. package/dist/clients/bounded-cache.js +24 -8
  13. package/dist/clients/bounded-pid-file-lock.js +4 -3
  14. package/dist/clients/bounded-telemetry.js +14 -0
  15. package/dist/clients/cache-manager.js +6 -7
  16. package/dist/clients/cache-observability.js +782 -110
  17. package/dist/clients/call-graph.js +238 -63
  18. package/dist/clients/codebase-model.js +13 -5
  19. package/dist/clients/complexity-client.js +1 -3
  20. package/dist/clients/dead-code-client.js +19 -8
  21. package/dist/clients/dead-code-logger.js +1 -2
  22. package/dist/clients/deadline-utils.js +3 -1
  23. package/dist/clients/debug-heap.js +8 -1
  24. package/dist/clients/degradation-ledger.js +22 -1
  25. package/dist/clients/demoted-finding-render.js +155 -0
  26. package/dist/clients/dependency-checker.js +11 -7
  27. package/dist/clients/deps/pi-tui.js +8 -2
  28. package/dist/clients/deps/typebox.js +8 -3
  29. package/dist/clients/diagnostic-dispositions.js +39 -2
  30. package/dist/clients/diagnostic-line-freshness.js +5 -1
  31. package/dist/clients/dispatch/auxiliary-lsp.js +2 -3
  32. package/dist/clients/dispatch/dispatcher.js +13 -1
  33. package/dist/clients/dispatch/facts/function-facts.js +3 -1
  34. package/dist/clients/dispatch/facts/import-facts.js +2 -1
  35. package/dist/clients/dispatch/facts/tree-sitter-facts.js +1 -1
  36. package/dist/clients/dispatch/integration.js +9 -4
  37. package/dist/clients/dispatch/rules/error-swallowing.js +3 -1
  38. package/dist/clients/dispatch/rules/pass-through-wrappers.js +6 -2
  39. package/dist/clients/dispatch/rules/unsafe-boundary.js +31 -7
  40. package/dist/clients/dispatch/runners/actionlint.js +5 -2
  41. package/dist/clients/dispatch/runners/biome-check.js +10 -14
  42. package/dist/clients/dispatch/runners/cpp-check.js +5 -1
  43. package/dist/clients/dispatch/runners/detekt.js +9 -6
  44. package/dist/clients/dispatch/runners/dotnet-build.js +1 -1
  45. package/dist/clients/dispatch/runners/elixir-check.js +3 -1
  46. package/dist/clients/dispatch/runners/eslint.js +25 -6
  47. package/dist/clients/dispatch/runners/fish-indent.js +1 -1
  48. package/dist/clients/dispatch/runners/gleam-check.js +1 -1
  49. package/dist/clients/dispatch/runners/golangci-lint.js +3 -1
  50. package/dist/clients/dispatch/runners/hadolint.js +22 -15
  51. package/dist/clients/dispatch/runners/helm-lint.js +4 -1
  52. package/dist/clients/dispatch/runners/htmlhint.js +33 -16
  53. package/dist/clients/dispatch/runners/javac.js +1 -1
  54. package/dist/clients/dispatch/runners/ktlint.js +1 -1
  55. package/dist/clients/dispatch/runners/lsp.js +1 -1
  56. package/dist/clients/dispatch/runners/markdownlint.js +34 -12
  57. package/dist/clients/dispatch/runners/mypy.js +15 -17
  58. package/dist/clients/dispatch/runners/oxlint.js +231 -15
  59. package/dist/clients/dispatch/runners/php-lint.js +1 -1
  60. package/dist/clients/dispatch/runners/phpstan.js +52 -15
  61. package/dist/clients/dispatch/runners/psscriptanalyzer.js +10 -6
  62. package/dist/clients/dispatch/runners/pyright.js +23 -14
  63. package/dist/clients/dispatch/runners/rust-clippy.js +1 -1
  64. package/dist/clients/dispatch/runners/shellcheck.js +7 -9
  65. package/dist/clients/dispatch/runners/shfmt.js +5 -2
  66. package/dist/clients/dispatch/runners/spellcheck.js +10 -15
  67. package/dist/clients/dispatch/runners/sqlfluff.js +25 -17
  68. package/dist/clients/dispatch/runners/stylelint.js +40 -20
  69. package/dist/clients/dispatch/runners/swiftlint.js +8 -8
  70. package/dist/clients/dispatch/runners/taplo.js +110 -23
  71. package/dist/clients/dispatch/runners/terragrunt.js +13 -8
  72. package/dist/clients/dispatch/runners/tflint.js +25 -15
  73. package/dist/clients/dispatch/runners/tree-sitter.js +17 -3
  74. package/dist/clients/dispatch/runners/utils/candidate-probe.js +7 -1
  75. package/dist/clients/dispatch/runners/utils/runner-helpers.js +24 -1
  76. package/dist/clients/dispatch/runners/utils/tool-failure.js +152 -1
  77. package/dist/clients/dispatch/runners/vale.js +16 -14
  78. package/dist/clients/dispatch/runners/yaml-rule-parser.js +1 -3
  79. package/dist/clients/dispatch/runners/yamllint.js +13 -16
  80. package/dist/clients/dispatch/runners/zig-check.js +1 -1
  81. package/dist/clients/dispatch/suppress-writer.js +2 -1
  82. package/dist/clients/dispatch/types.js +6 -1
  83. package/dist/clients/dispatch/utils/lsp-diagnostics.js +6 -2
  84. package/dist/clients/extension-log.js +5 -3
  85. package/dist/clients/feature-hints.js +8 -1
  86. package/dist/clients/file-kinds.js +34 -129
  87. package/dist/clients/file-utils.js +17 -1
  88. package/dist/clients/finding-delivery-gate.js +79 -2
  89. package/dist/clients/formatters.js +144 -27
  90. package/dist/clients/freshness.js +38 -0
  91. package/dist/clients/git-guard.js +43 -13
  92. package/dist/clients/go-client.js +1 -3
  93. package/dist/clients/grammar-source.js +1 -1
  94. package/dist/clients/gzip-stage-write.js +30 -4
  95. package/dist/clients/host-edit-normalize.js +1 -3
  96. package/dist/clients/install-diagnostics.js +4 -2
  97. package/dist/clients/installer/index.js +86 -77
  98. package/dist/clients/instance-reaper.js +5 -2
  99. package/dist/clients/instance-registry.js +4 -2
  100. package/dist/clients/jscpd-client.js +11 -3
  101. package/dist/clients/knip-client.js +29 -15
  102. package/dist/clients/language-profile.js +11 -3
  103. package/dist/clients/latency-logger.js +13 -2
  104. package/dist/clients/lens-config.js +1 -1
  105. package/dist/clients/lens-map.js +8 -3
  106. package/dist/clients/live-bus-emitter.js +1 -1
  107. package/dist/clients/lsp/cascade-tier.js +27 -2
  108. package/dist/clients/lsp/client.js +144 -5
  109. package/dist/clients/lsp/config.js +4 -6
  110. package/dist/clients/lsp/edits.js +119 -32
  111. package/dist/clients/lsp/index.js +245 -41
  112. package/dist/clients/lsp/inferred-project.js +2 -1
  113. package/dist/clients/lsp/jvm-runtime.js +4 -1
  114. package/dist/clients/lsp/launch.js +11 -3
  115. package/dist/clients/lsp/pending-aux-coverage.js +152 -0
  116. package/dist/clients/lsp/server.js +19 -7
  117. package/dist/clients/lsp/tsserver-sync.js +10 -2
  118. package/dist/clients/lsp/workspace-diagnostics-cache.js +9 -4
  119. package/dist/clients/lsp-document-symbols.js +1 -3
  120. package/dist/clients/lsp-mutation.js +10 -20
  121. package/dist/clients/mcp/host-shim.js +1 -1
  122. package/dist/clients/memory-sampler.js +73 -7
  123. package/dist/clients/metrics-client.js +1 -3
  124. package/dist/clients/middle-man-analysis.js +8 -3
  125. package/dist/clients/module-report-lsp.js +7 -1
  126. package/dist/clients/module-report.js +28 -18
  127. package/dist/clients/ndjson-logger.js +117 -28
  128. package/dist/clients/opaque-mutation-scan.js +220 -0
  129. package/dist/clients/package-manager.js +6 -1
  130. package/dist/clients/pipeline.js +57 -9
  131. package/dist/clients/project-conventions.js +2 -8
  132. package/dist/clients/project-diagnostics/cache.js +10 -7
  133. package/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +2 -1
  134. package/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +3 -1
  135. package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +13 -9
  136. package/dist/clients/project-diagnostics/runner-adapters/trivy.js +3 -1
  137. package/dist/clients/project-diagnostics/scanner.js +22 -10
  138. package/dist/clients/project-lens-config.js +12 -5
  139. package/dist/clients/project-report.js +62 -27
  140. package/dist/clients/project-snapshot-fingerprint.js +48 -0
  141. package/dist/clients/project-snapshot-persist-worker.js +15 -1
  142. package/dist/clients/project-snapshot.js +472 -66
  143. package/dist/clients/read-expansion.js +12 -2
  144. package/dist/clients/read-guard-logger.js +12 -6
  145. package/dist/clients/read-guard-tool-lines.js +5 -2
  146. package/dist/clients/read-guard.js +88 -19
  147. package/dist/clients/resource-sampler.js +1 -1
  148. package/dist/clients/reverse-deps.js +6 -5
  149. package/dist/clients/review-graph/builder.js +236 -48
  150. package/dist/clients/review-graph/git-identity.js +8 -2
  151. package/dist/clients/review-graph/import-resolvers.js +10 -1
  152. package/dist/clients/review-graph/query.js +2 -1
  153. package/dist/clients/review-graph/revision-drift.js +21 -0
  154. package/dist/clients/review-graph/tsconfig-paths.js +4 -2
  155. package/dist/clients/review-graph/workspace-modules.js +8 -5
  156. package/dist/clients/ruff-client.js +6 -5
  157. package/dist/clients/runtime-agent-end.js +63 -31
  158. package/dist/clients/runtime-context.js +12 -4
  159. package/dist/clients/runtime-coordinator.js +127 -4
  160. package/dist/clients/runtime-session.js +55 -0
  161. package/dist/clients/runtime-tool-call.js +59 -3
  162. package/dist/clients/runtime-tool-result.js +148 -34
  163. package/dist/clients/runtime-turn.js +194 -8
  164. package/dist/clients/rust-client.js +1 -3
  165. package/dist/clients/safe-spawn.js +150 -11
  166. package/dist/clients/security-scan-client.js +1 -3
  167. package/dist/clients/session-event-guard.js +184 -0
  168. package/dist/clients/session-summary.js +3 -1
  169. package/dist/clients/sg-runner.js +1 -3
  170. package/dist/clients/source-filter.js +16 -8
  171. package/dist/clients/source-walker.js +1 -1
  172. package/dist/clients/spawn-timeout-cooldown.js +96 -0
  173. package/dist/clients/startup-scan.js +9 -3
  174. package/dist/clients/tool-definition.js +7 -0
  175. package/dist/clients/tool-policy.js +26 -11
  176. package/dist/clients/tool-render.js +2 -1
  177. package/dist/clients/tree-sitter-client.js +10 -4
  178. package/dist/clients/tree-sitter-logger.js +2 -1
  179. package/dist/clients/tree-sitter-symbol-extractor.js +12 -5
  180. package/dist/clients/warm-attach.js +12 -5
  181. package/dist/clients/widget-state.js +27 -11
  182. package/dist/clients/word-index.js +3 -1
  183. package/dist/clients/workspace-topology.js +8 -2
  184. package/dist/clients/zizmor-config.js +9 -1
  185. package/dist/i18n.js +13 -5
  186. package/dist/index.js +15811 -12810
  187. package/dist/mcp/server.js +3 -1
  188. package/dist/tools/ast-grep-replace.js +68 -12
  189. package/dist/tools/lens-diagnostic-mark.js +21 -7
  190. package/dist/tools/lens-diagnostics.js +174 -38
  191. package/dist/tools/lsp-diagnostics.js +24 -7
  192. package/dist/tools/lsp-navigation.js +3 -1
  193. package/dist/tools/module-report.js +1 -1
  194. package/dist/tools/project-report.js +1 -1
  195. package/dist/tools/symbol-search.js +5 -2
  196. package/docs/durable-store-audit-1202.md +1 -1
  197. package/docs/servercapabilities.md +1 -1
  198. package/package.json +160 -143
  199. package/rules/typos/_typos.toml +2 -2
  200. package/scripts/analyze-pi-lens-logs.mjs +31 -13
  201. package/scripts/download-grammars.js +9 -3
  202. package/scripts/install-selftest.mjs +99 -11
  203. package/scripts/lib/host-provided-deps.mjs +75 -0
  204. package/scripts/lib/warm-loader-cache.mjs +285 -0
  205. package/scripts/rpc-load-check.mjs +30 -9
  206. package/scripts/warm-loader-cache.mjs +233 -0
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env node
2
+ // scripts/warm-loader-cache.mjs (#1926)
3
+ //
4
+ // Pay pi's jiti transform of dist/index.js at install time, so no interactive
5
+ // session pays it.
6
+ //
7
+ // pi loads an extension with jiti, which Babel-transforms the entry and caches
8
+ // the result under <tmpdir>/jiti. pi-lens's entry is a ~4MB esbuild bundle, so
9
+ // the transform is the dominant startup cost exactly once per build: the first
10
+ // session after a `git:` install or update measured 4847ms of `module import`,
11
+ // against 138ms once the cache is warm. `prepare` has just built that bundle,
12
+ // so this script transforms it through the same jiti and writes the same cache
13
+ // entry pi will read.
14
+ //
15
+ // See scripts/lib/warm-loader-cache.mjs for why the entry this writes is the
16
+ // entry pi reads — the cache key, the transform-version marker that makes a
17
+ // mismatch a miss instead of a corruption, and the measurement that proved the
18
+ // output byte-identical to pi's own.
19
+ //
20
+ // POSTURE: best-effort, last in the chain, always exit 0. `prepare` also runs
21
+ // `build:dist` and `download-grammars`, which consumers depend on and which
22
+ // MUST fail loudly. A cache warm is an optimisation and must never share their
23
+ // failure path — the same split `scripts/setup-git-hooks.mjs` makes (#1804).
24
+ import * as fs from "node:fs";
25
+ import { createRequire } from "node:module";
26
+ import * as os from "node:os";
27
+ import * as path from "node:path";
28
+ import { fileURLToPath, pathToFileURL } from "node:url";
29
+ import { HOST_PROVIDED_PACKAGES } from "./lib/host-provided-deps.mjs";
30
+ import {
31
+ appendBounded,
32
+ buildStubAliases,
33
+ expectedCacheFileName,
34
+ resolveJitiCacheDir,
35
+ verifyCacheEntry,
36
+ warmSkipReason,
37
+ } from "./lib/warm-loader-cache.mjs";
38
+
39
+ const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
40
+ const require = createRequire(import.meta.url);
41
+
42
+ function log(message) {
43
+ process.stderr.write(`[warm-loader-cache] ${message}\n`);
44
+ }
45
+
46
+ /**
47
+ * Append one JSONL record to ~/.pi-lens/install.log.
48
+ *
49
+ * pi's install output scrolls away, so without this there is no record that the
50
+ * warm ran, was skipped, or failed. One bounded line per install keeps the
51
+ * question answerable after the fact. `PI_LENS_INSTALL_LOG` redirects the file,
52
+ * which is how the tests read the record back.
53
+ */
54
+ function record(entry) {
55
+ try {
56
+ const override = process.env.PI_LENS_INSTALL_LOG;
57
+ const file =
58
+ typeof override === "string" && override.length > 0
59
+ ? override
60
+ : path.join(os.homedir(), ".pi-lens", "install.log");
61
+ fs.mkdirSync(path.dirname(file), { recursive: true });
62
+ const existing = fs.existsSync(file)
63
+ ? fs.readFileSync(file, "utf8").split("\n")
64
+ : [];
65
+ const line = JSON.stringify({
66
+ ts: new Date().toISOString(),
67
+ event: "warm_loader_cache",
68
+ ...entry,
69
+ });
70
+ fs.writeFileSync(file, `${appendBounded(existing, line).join("\n")}\n`);
71
+ } catch {
72
+ // The log is diagnostic. Losing it must not change the install outcome.
73
+ }
74
+ }
75
+
76
+ /** Entries pi will load, read from the manifest rather than hardcoded. */
77
+ function extensionEntries() {
78
+ try {
79
+ const pkg = JSON.parse(
80
+ fs.readFileSync(path.join(root, "package.json"), "utf8"),
81
+ );
82
+ return (pkg.pi?.extensions ?? []).map((entry) => path.resolve(root, entry));
83
+ } catch {
84
+ return [];
85
+ }
86
+ }
87
+
88
+ async function loadCreateJiti() {
89
+ // `jiti/static` is the subpath pi's loader imports, and it is export-mapped
90
+ // for `import` only — `require.resolve` reports it as not exported. Resolve
91
+ // it the ESM way, and fall back to the package root for older runtimes.
92
+ for (const specifier of ["jiti/static", "jiti"]) {
93
+ try {
94
+ const url = import.meta.resolve
95
+ ? import.meta.resolve(specifier)
96
+ : pathToFileURL(require.resolve(specifier)).href;
97
+ const mod = await import(url);
98
+ if (typeof mod.createJiti === "function") return mod.createJiti;
99
+ } catch {
100
+ // Try the next specifier; absence is a skip, not a failure.
101
+ }
102
+ }
103
+ return undefined;
104
+ }
105
+
106
+ /**
107
+ * The installed jiti's version, so a host jiti bump — which changes the marker
108
+ * and silently turns every warm into a cold session — is diagnosable from the
109
+ * record rather than from a bisect.
110
+ */
111
+ function jitiVersion() {
112
+ try {
113
+ const url = import.meta.resolve
114
+ ? import.meta.resolve("jiti/package.json")
115
+ : pathToFileURL(require.resolve("jiti/package.json")).href;
116
+ return JSON.parse(fs.readFileSync(fileURLToPath(url), "utf8")).version;
117
+ } catch {
118
+ return null;
119
+ }
120
+ }
121
+
122
+ /** Real-filesystem probes for `verifyCacheEntry`. */
123
+ const fsDeps = {
124
+ existsSync: (p) => fs.existsSync(p),
125
+ readFileSync: (p) => fs.readFileSync(p, "utf8"),
126
+ isWritable: (p) => {
127
+ try {
128
+ fs.accessSync(p, fs.constants.W_OK);
129
+ return true;
130
+ } catch {
131
+ return false;
132
+ }
133
+ },
134
+ };
135
+
136
+ export async function main() {
137
+ const entries = extensionEntries();
138
+ const createJiti = await loadCreateJiti();
139
+ const skip = warmSkipReason({
140
+ env: process.env,
141
+ distEntryExists:
142
+ entries.length > 0 && entries.every((e) => fs.existsSync(e)),
143
+ jitiResolvable: typeof createJiti === "function",
144
+ });
145
+ if (skip) {
146
+ log(`skipped: ${skip}`);
147
+ record({ status: "skipped", reason: skip });
148
+ return;
149
+ }
150
+
151
+ const cacheDir = resolveJitiCacheDir({
152
+ tmpdir: os.tmpdir,
153
+ env: process.env,
154
+ cwd: process.cwd,
155
+ join: path.join,
156
+ });
157
+ const alias = buildStubAliases(HOST_PROVIDED_PACKAGES);
158
+ const version = jitiVersion();
159
+
160
+ for (const entry of entries) {
161
+ const started = Date.now();
162
+ const cacheFile = expectedCacheFileName(entry);
163
+ const jiti = createJiti(pathToFileURL(entry).href, {
164
+ // Mirror pi's loader: no in-process module cache, aliases present.
165
+ // Neither affects the transform or the cache key, but staying close to
166
+ // pi's call keeps the two easy to compare.
167
+ moduleCache: false,
168
+ fsCache: cacheDir,
169
+ alias,
170
+ });
171
+ try {
172
+ // jiti writes the cache entry BEFORE it evaluates the module, so the
173
+ // warm is complete even though evaluation then fails on the first
174
+ // host-provided import — those only resolve inside pi.
175
+ await jiti.import(entry, { default: true });
176
+ } catch {
177
+ // Expected. Evaluation is not the goal; the transform is.
178
+ }
179
+ const ms = Date.now() - started;
180
+ const relative = path.relative(root, entry);
181
+
182
+ // The import returning proves nothing. Several exit-0 paths leave no usable
183
+ // entry — an unwritable cache directory, an import that never reached the
184
+ // transform, a stale file that fails jiti's marker check — so read the file
185
+ // back before claiming anything was cached.
186
+ const verdict = verifyCacheEntry({
187
+ cacheDir,
188
+ fileName: cacheFile,
189
+ source: fs.readFileSync(entry, "utf8"),
190
+ fsDeps,
191
+ });
192
+ const common = {
193
+ entry: relative,
194
+ ms,
195
+ cacheDir,
196
+ cacheFile,
197
+ jitiVersion: version,
198
+ };
199
+ if (verdict.ok) {
200
+ log(`warmed ${relative} in ${ms}ms (cache: ${cacheDir}/${cacheFile})`);
201
+ record({
202
+ status: "warmed",
203
+ ...common,
204
+ transformVersion: verdict.transformVersion,
205
+ });
206
+ continue;
207
+ }
208
+ log(`not cached: ${relative} after ${ms}ms — ${verdict.reason}`);
209
+ record({ status: "not_cached", ...common, reason: verdict.reason });
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Run `work`, absorbing any failure. Exported so a test can inject a throwing
215
+ * body and assert the process still exits 0 and still leaves a record.
216
+ */
217
+ export async function run(work = main) {
218
+ try {
219
+ await work();
220
+ } catch (err) {
221
+ const message = err instanceof Error ? err.message : String(err);
222
+ log(`failed: ${message}`);
223
+ record({ status: "failed", reason: message });
224
+ }
225
+ }
226
+
227
+ const invokedPath = process.argv[1];
228
+ const invokedDirectly =
229
+ typeof invokedPath === "string" &&
230
+ pathToFileURL(path.resolve(invokedPath)).href === import.meta.url;
231
+ if (invokedDirectly) {
232
+ await run();
233
+ }