pi-lens 4.1.5 → 4.2.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 (219) hide show
  1. package/CHANGELOG.md +415 -0
  2. package/README.md +13 -8
  3. package/config/dependency-cruiser-eager-allowlist.json +6 -1
  4. package/dist/clients/actionable-warnings.js +30 -4
  5. package/dist/clients/agent-behavior-client.js +2 -0
  6. package/dist/clients/analysed-root.js +1 -0
  7. package/dist/clients/ast-grep-tool-logger.js +1 -1
  8. package/dist/clients/bash-file-access.js +26 -0
  9. package/dist/clients/biome-client.js +13 -2
  10. package/dist/clients/blocker-freshness.js +403 -35
  11. package/dist/clients/bootstrap.js +6 -1
  12. package/dist/clients/bounded-telemetry.js +2 -0
  13. package/dist/clients/cache-observability.js +122 -1
  14. package/dist/clients/cascade-format.js +200 -4
  15. package/dist/clients/code-quality-warnings.js +10 -2
  16. package/dist/clients/complexity-client.js +5 -0
  17. package/dist/clients/config-diagnostic-codes.js +2 -0
  18. package/dist/clients/config-resolve.js +6 -3
  19. package/dist/clients/config-schema.js +17 -0
  20. package/dist/clients/config-warn.js +2 -2
  21. package/dist/clients/dead-code-client.js +8 -1
  22. package/dist/clients/degradation-ledger.js +16 -1
  23. package/dist/clients/dependency-checker.js +5 -1
  24. package/dist/clients/diagnostic-dispositions.js +12 -1
  25. package/dist/clients/dispatch/ast-grep-catalog.js +65 -0
  26. package/dist/clients/dispatch/auxiliary-lsp.js +28 -0
  27. package/dist/clients/dispatch/dispatcher.js +47 -17
  28. package/dist/clients/dispatch/facts/function-facts.js +1 -1
  29. package/dist/clients/dispatch/facts/import-facts.js +5 -1
  30. package/dist/clients/dispatch/finding-policy.js +222 -0
  31. package/dist/clients/dispatch/indent-detect.js +389 -13
  32. package/dist/clients/dispatch/integration.js +175 -25
  33. package/dist/clients/dispatch/rule-ignores.js +62 -0
  34. package/dist/clients/dispatch/runners/actionlint.js +2 -1
  35. package/dist/clients/dispatch/runners/ast-grep-napi.js +21 -41
  36. package/dist/clients/dispatch/runners/biome-check.js +8 -4
  37. package/dist/clients/dispatch/runners/cpp-check.js +4 -3
  38. package/dist/clients/dispatch/runners/credo.js +2 -1
  39. package/dist/clients/dispatch/runners/cue-vet.js +2 -1
  40. package/dist/clients/dispatch/runners/dart-analyze.js +2 -1
  41. package/dist/clients/dispatch/runners/detekt.js +2 -1
  42. package/dist/clients/dispatch/runners/dotnet-build.js +2 -1
  43. package/dist/clients/dispatch/runners/elixir-check.js +2 -1
  44. package/dist/clients/dispatch/runners/eslint.js +2 -1
  45. package/dist/clients/dispatch/runners/fish-indent.js +2 -1
  46. package/dist/clients/dispatch/runners/gleam-check.js +2 -1
  47. package/dist/clients/dispatch/runners/go-vet.js +2 -1
  48. package/dist/clients/dispatch/runners/golangci-lint.js +2 -1
  49. package/dist/clients/dispatch/runners/hadolint.js +2 -1
  50. package/dist/clients/dispatch/runners/helm-lint.js +3 -1
  51. package/dist/clients/dispatch/runners/helm-render.js +2 -1
  52. package/dist/clients/dispatch/runners/htmlhint.js +2 -1
  53. package/dist/clients/dispatch/runners/javac.js +2 -1
  54. package/dist/clients/dispatch/runners/ktlint.js +2 -1
  55. package/dist/clients/dispatch/runners/lsp.js +19 -1
  56. package/dist/clients/dispatch/runners/markdownlint.js +3 -2
  57. package/dist/clients/dispatch/runners/mypy.js +2 -1
  58. package/dist/clients/dispatch/runners/oxlint.js +2 -1
  59. package/dist/clients/dispatch/runners/php-lint.js +2 -1
  60. package/dist/clients/dispatch/runners/phpstan.js +2 -1
  61. package/dist/clients/dispatch/runners/prisma-validate.js +2 -1
  62. package/dist/clients/dispatch/runners/psscriptanalyzer.js +12 -12
  63. package/dist/clients/dispatch/runners/pyright.js +2 -1
  64. package/dist/clients/dispatch/runners/rubocop.js +2 -1
  65. package/dist/clients/dispatch/runners/ruff.js +2 -2
  66. package/dist/clients/dispatch/runners/rust-clippy.js +12 -11
  67. package/dist/clients/dispatch/runners/shellcheck.js +2 -1
  68. package/dist/clients/dispatch/runners/shfmt.js +4 -13
  69. package/dist/clients/dispatch/runners/spellcheck.js +2 -2
  70. package/dist/clients/dispatch/runners/spotbugs.js +2 -1
  71. package/dist/clients/dispatch/runners/sqlfluff.js +3 -2
  72. package/dist/clients/dispatch/runners/stylelint.js +3 -2
  73. package/dist/clients/dispatch/runners/swiftlint.js +2 -1
  74. package/dist/clients/dispatch/runners/taplo.js +2 -1
  75. package/dist/clients/dispatch/runners/terragrunt.js +2 -1
  76. package/dist/clients/dispatch/runners/tflint.js +2 -1
  77. package/dist/clients/dispatch/runners/tree-sitter.js +2 -21
  78. package/dist/clients/dispatch/runners/trivy-config.js +2 -1
  79. package/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
  80. package/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
  81. package/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
  82. package/dist/clients/dispatch/runners/vale.js +2 -1
  83. package/dist/clients/dispatch/runners/yamllint.js +4 -3
  84. package/dist/clients/dispatch/runners/zig-check.js +2 -1
  85. package/dist/clients/dispatch/types.js +4 -1
  86. package/dist/clients/disposition-publish.js +1 -0
  87. package/dist/clients/effective-config.js +12 -2
  88. package/dist/clients/extension-log.js +2 -0
  89. package/dist/clients/file-kinds.js +26 -1
  90. package/dist/clients/file-role.js +23 -6
  91. package/dist/clients/file-utils.js +156 -10
  92. package/dist/clients/finding-delivery-gate.js +60 -9
  93. package/dist/clients/format-service.js +39 -21
  94. package/dist/clients/formatters.js +113 -200
  95. package/dist/clients/generation-guard.js +6 -2
  96. package/dist/clients/git-guard.js +11 -3
  97. package/dist/clients/gitleaks-client.js +42 -6
  98. package/dist/clients/govulncheck-client.js +48 -7
  99. package/dist/clients/indent-retarget.js +78 -8
  100. package/dist/clients/installer/index.js +524 -161
  101. package/dist/clients/instance-reaper-state.js +7 -0
  102. package/dist/clients/instance-reaper.js +20 -10
  103. package/dist/clients/jscpd-client.js +9 -1
  104. package/dist/clients/knip-client.js +9 -2
  105. package/dist/clients/language-profile.js +35 -3
  106. package/dist/clients/language-registry.js +5 -1
  107. package/dist/clients/latency-logger.js +6 -1
  108. package/dist/clients/lens-config.js +4 -0
  109. package/dist/clients/lens-engine.js +12 -3
  110. package/dist/clients/lens-events.js +2 -1
  111. package/dist/clients/lens-flag-registry.js +79 -0
  112. package/dist/clients/live-bus-emitter.js +2 -1
  113. package/dist/clients/lsp/client.js +25 -21
  114. package/dist/clients/lsp/config.js +36 -7
  115. package/dist/clients/lsp/diagnostic-binding.js +24 -1
  116. package/dist/clients/lsp/document-drift.js +78 -0
  117. package/dist/clients/lsp/index.js +288 -45
  118. package/dist/clients/lsp/launch.js +16 -4
  119. package/dist/clients/lsp/server.js +79 -15
  120. package/dist/clients/lsp/workspace-diagnostics-cache.js +39 -5
  121. package/dist/clients/lsp-mutation.js +5 -3
  122. package/dist/clients/map-with-concurrency.js +12 -8
  123. package/dist/clients/mcp/analyze.js +3 -0
  124. package/dist/clients/mcp/session.js +38 -4
  125. package/dist/clients/ndjson-logger.js +24 -7
  126. package/dist/clients/observed-mutation.js +40 -2
  127. package/dist/clients/opaque-mutation-scan.js +23 -3
  128. package/dist/clients/opengrep-client.js +111 -14
  129. package/dist/clients/package-manager.js +2 -1
  130. package/dist/clients/path-utils.js +123 -3
  131. package/dist/clients/performance-report.js +5 -1
  132. package/dist/clients/php-cs-fixer-config.js +8 -3
  133. package/dist/clients/pipeline.js +77 -7
  134. package/dist/clients/project-diagnostics/cache.js +37 -5
  135. package/dist/clients/project-diagnostics/fresh-fetch.js +173 -18
  136. package/dist/clients/project-diagnostics/runner-adapters/dead-code.js +4 -1
  137. package/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
  138. package/dist/clients/project-diagnostics/scanner.js +59 -3
  139. package/dist/clients/project-lens-config.js +48 -2
  140. package/dist/clients/read-guard-logger.js +2 -0
  141. package/dist/clients/read-guard.js +70 -11
  142. package/dist/clients/resource-sampler.js +147 -9
  143. package/dist/clients/review-graph-logger.js +2 -0
  144. package/dist/clients/ruff-client.js +18 -9
  145. package/dist/clients/runtime-agent-end.js +42 -5
  146. package/dist/clients/runtime-context.js +6 -2
  147. package/dist/clients/runtime-coordinator.js +82 -7
  148. package/dist/clients/runtime-session.js +33 -5
  149. package/dist/clients/runtime-tool-call.js +43 -12
  150. package/dist/clients/runtime-tool-result.js +334 -86
  151. package/dist/clients/runtime-turn.js +195 -18
  152. package/dist/clients/safe-spawn.js +258 -5
  153. package/dist/clients/scratch-tree-policy.js +6 -0
  154. package/dist/clients/security-scan-client.js +2 -2
  155. package/dist/clients/session-event-guard.js +119 -6
  156. package/dist/clients/sg-runner.js +25 -12
  157. package/dist/clients/sgconfig.js +79 -2
  158. package/dist/clients/situational-tool-telemetry.js +108 -0
  159. package/dist/clients/test-runner-client.js +258 -78
  160. package/dist/clients/test-runner-delivery.js +43 -0
  161. package/dist/clients/tool-agreement.js +423 -0
  162. package/dist/clients/tool-config.js +249 -0
  163. package/dist/clients/tool-cwd.js +270 -0
  164. package/dist/clients/tool-policy.js +163 -7
  165. package/dist/clients/tool-probe.js +53 -0
  166. package/dist/clients/tool-set-policy.js +42 -0
  167. package/dist/clients/tree-sitter-client.js +120 -0
  168. package/dist/clients/tree-sitter-query-loader.js +127 -189
  169. package/dist/clients/trivy-client.js +9 -1
  170. package/dist/clients/turn-context.js +52 -0
  171. package/dist/clients/widget-state.js +102 -3
  172. package/dist/clients/word-index.js +5 -2
  173. package/dist/clients/write-ordering-guard.js +7 -0
  174. package/dist/index.js +26968 -21741
  175. package/dist/mcp/analyze-cli.js +3 -2
  176. package/dist/mcp/server.js +140 -161
  177. package/dist/tools/activate-tools.js +10 -7
  178. package/dist/tools/ast-grep-outline.js +2 -13
  179. package/dist/tools/ast-grep-replace.js +8 -13
  180. package/dist/tools/ast-grep-search.js +83 -39
  181. package/dist/tools/effective-config.js +4 -3
  182. package/dist/tools/lens-diagnostic-mark.js +8 -11
  183. package/dist/tools/lens-diagnostics.js +516 -133
  184. package/dist/tools/lsp-diagnostics.js +265 -182
  185. package/dist/tools/lsp-navigation.js +20 -44
  186. package/dist/tools/module-report.js +5 -9
  187. package/dist/tools/project-report.js +9 -17
  188. package/dist/tools/render-compact.js +280 -1
  189. package/dist/tools/symbol-search.js +2 -2
  190. package/docs/agent-guide.md +3 -4
  191. package/docs/agent-tools.md +46 -22
  192. package/docs/audit1.md +5 -5
  193. package/docs/configuration.md +9 -0
  194. package/docs/dependencies.md +11 -0
  195. package/docs/dispositions.md +52 -0
  196. package/docs/environment-variables.md +2 -7
  197. package/docs/features.md +7 -7
  198. package/docs/globalconfig.md +14 -2
  199. package/docs/language-coverage.md +1 -0
  200. package/docs/mcp.md +13 -1
  201. package/docs/pi-lens-fixer.md +48 -18
  202. package/docs/pi-lens-investigator.md +38 -18
  203. package/docs/pi-lens-monitor.md +88 -0
  204. package/docs/pi-lens-retro.md +97 -0
  205. package/docs/pi-lens-reviewer.md +53 -31
  206. package/docs/pi-lens-subagent.md +12 -4
  207. package/docs/public-api-stability.md +1 -0
  208. package/docs/real-harness.md +46 -0
  209. package/docs/release-qa-baseline.md +27 -1
  210. package/docs/servercapabilities.md +1 -6
  211. package/docs/settings.md +44 -6
  212. package/docs/tools_improvement2.md +4 -4
  213. package/docs/usage.md +15 -3
  214. package/package.json +10 -1
  215. package/rules/tree-sitter-queries/typescript/sql-injection.yml +23 -7
  216. package/scripts/analyze-pi-lens-logs.mjs +40 -0
  217. package/skills/pi-lens-ast-grep/SKILL.md +23 -6
  218. package/skills/pi-lens-lsp-navigation/SKILL.md +26 -9
  219. package/dist/tools/ast-dump.js +0 -103
@@ -13,6 +13,8 @@ import { toRunnerDisplayPath } from "./dispatch/runner-context.js";
13
13
  import { logActionableWarningsEvent } from "./actionable-warnings-logger.js";
14
14
  import { displayProjectDataPath, getProjectDataDir } from "./file-utils.js";
15
15
  import { commitDurableStore } from "./durable-store.js";
16
+ import { establishToolAgreement } from "./tool-agreement.js";
17
+ import { resolveLensToolName } from "./tool-config.js";
16
18
  let beforeWarningStateLockForTests = null;
17
19
  /** Test seam for a sibling process commit immediately before lock acquisition. */
18
20
  export function _setBeforeWarningStateLockForTests(hook) {
@@ -252,11 +254,15 @@ function lineInModifiedRanges(line, ranges) {
252
254
  function recordFromLspDiagnostic(diag, filePath, cwd) {
253
255
  const line = diag.range.start.line + 1;
254
256
  const column = diag.range.start.character + 1;
257
+ // Keep agreement keyed to the producer that supplied the diagnostic. The
258
+ // generic `lsp` label is only a last-resort identity: treating it as a
259
+ // registered writer would establish every LSP quickfix without evidence.
260
+ const producer = diag.source && diag.source !== "lsp" ? diag.source : diag.serverId;
255
261
  const source = diag.source ?? "lsp";
256
262
  const code = diag.code === undefined ? undefined : String(diag.code);
257
263
  const identityArgs = {
258
264
  filePath,
259
- tool: "lsp",
265
+ tool: producer ?? "lsp",
260
266
  source,
261
267
  code,
262
268
  message: diag.message,
@@ -271,7 +277,7 @@ function recordFromLspDiagnostic(diag, filePath, cwd) {
271
277
  line,
272
278
  column,
273
279
  severity: "warning",
274
- tool: "lsp",
280
+ tool: producer ?? "lsp",
275
281
  source,
276
282
  code,
277
283
  rule: code ? `${source}:${code}` : source,
@@ -1428,6 +1434,19 @@ export async function applyConservativeActionableWarningFixes(args) {
1428
1434
  continue;
1429
1435
  }
1430
1436
  summary.considered++;
1437
+ const agreement = establishToolAgreement(warning.tool, args.cwd);
1438
+ if (agreement.decision === "decline") {
1439
+ recordDegradationOnce({
1440
+ kind: "autofix-agreement-unavailable",
1441
+ subject: agreement.subject,
1442
+ reason: agreement.reason,
1443
+ });
1444
+ summary.skipped.push({
1445
+ id: warning.id,
1446
+ reason: "tool_agreement_unavailable",
1447
+ });
1448
+ continue;
1449
+ }
1431
1450
  if (!warning.line || !warning.column) {
1432
1451
  summary.skipped.push({ id: warning.id, reason: "missing_position" });
1433
1452
  continue;
@@ -1516,7 +1535,7 @@ export async function applyConservativeActionableWarningFixes(args) {
1516
1535
  * unread under `~/.pi-lens/projects/<slug>/cache/`. An OPTIONAL `cwd` would
1517
1536
  * have kept that bug alive behind a default, so callers must pass it.
1518
1537
  */
1519
- export function formatActionableWarningsAdvisory(report, cwd) {
1538
+ export function formatActionableWarningsAdvisory(report, cwd, host = "pi") {
1520
1539
  if (report.summary.unsuppressed === 0)
1521
1540
  return undefined;
1522
1541
  const files = report.files.filter((file) => file.warnings.some((warning) => !warning.suppressed));
@@ -1543,10 +1562,17 @@ export function formatActionableWarningsAdvisory(report, cwd) {
1543
1562
  // reading the transcript, rendered through the one helper that cannot
1544
1563
  // disagree with the writer.
1545
1564
  const reportPath = displayProjectDataPath(cwd, "cache", "actionable-warnings.json");
1565
+ // #2535 F3: a known tool with no mapping on this host resolves to
1566
+ // undefined — omit the instruction rather than naming a dead tool.
1567
+ // `lens_diagnostics` is pinned available on both hosts, so this is
1568
+ // defensive only.
1569
+ const diagnosticsTool = resolveLensToolName("lens_diagnostics", host);
1546
1570
  return [
1547
1571
  `🟡 Fixable warnings introduced this turn: ${report.summary.unsuppressed}.${safe}`,
1548
1572
  tierLine,
1549
- "Use lens_diagnostics with mode=delta to inspect these warnings.",
1573
+ diagnosticsTool
1574
+ ? `Use ${diagnosticsTool} with mode=delta to inspect these warnings.`
1575
+ : undefined,
1550
1576
  fileList ? `Files:\n${fileList}${more}` : undefined,
1551
1577
  "If continuing in these files, resolve warnings that are safe and relevant. Do not apply broad refactors unless requested.",
1552
1578
  `Raw report (only if you need the JSON): ${reportPath}`,
@@ -143,3 +143,5 @@ export class AgentBehaviorClient {
143
143
  this.fileEditCount.clear();
144
144
  }
145
145
  }
146
+ /** Process-wide behaviour history, independent of analyzer bootstrap residency. */
147
+ export const agentBehaviorClient = new AgentBehaviorClient();
@@ -0,0 +1 @@
1
+ export {};
@@ -99,7 +99,7 @@ export function astGrepRemediationHint(kind) {
99
99
  case "json_parse_failed":
100
100
  return "Hint: ast-grep produced output that could not be parsed — retry with a simpler pattern; the installed CLI version may be incompatible.";
101
101
  default:
102
- return "Hint: verify the pattern is a single valid AST node for this `lang` (use ast_grep_dump to discover node kinds), or fall back to grep for plain-text search.";
102
+ return "Hint: verify the pattern is a single valid AST node for this `lang` (use ast_grep_search with dump=true to discover node kinds), or fall back to grep for plain-text search.";
103
103
  }
104
104
  }
105
105
  export function logAstGrepToolEvent(event) {
@@ -17,6 +17,7 @@
17
17
  import * as nodeFs from "node:fs";
18
18
  import * as path from "node:path";
19
19
  import { isReadableSourceFile } from "./file-kinds.js";
20
+ import { classifyMutatingTool } from "./mutating-tool.js";
20
21
  import { countFileLines } from "./read-guard-tool-lines.js";
21
22
  import { stripAnsi } from "./sanitize.js";
22
23
  function stripQuotes(token) {
@@ -1028,3 +1029,28 @@ export function extractDeletedPathsFromCommand(command, cwd) {
1028
1029
  }
1029
1030
  return Array.from(out);
1030
1031
  }
1032
+ /**
1033
+ * One edit-class predicate for the `tool_result` path (#2939 F3).
1034
+ *
1035
+ * `index.ts` used to answer "is this an edit-class result" twice — once in
1036
+ * the handler body (gated on `toolName === "bash"`) and once in the
1037
+ * `budgetKey` callback (no tool gate) — and the copies disagreed on the
1038
+ * first third-party case tried (`mcp__acme__shell` with `input.command`:
1039
+ * wrapper said edit, handler said read-only). Both call sites now share
1040
+ * this function, so the answer is written once — but the call sites
1041
+ * themselves are not yet pinned (W4/M8, #2939), so a future tool-name gate
1042
+ * re-introduced at one of them would still pass the suite.
1043
+ *
1044
+ * A result is edit-class when the mutation seam classifies it, or when its
1045
+ * `input.command` names written files. The command half carries no tool-name
1046
+ * gate on purpose: a shell that wrote files runs the same pipeline whatever
1047
+ * its tool is named, and the edit budget must cover that work.
1048
+ */
1049
+ export function isEditClassToolResult(event, cwd) {
1050
+ if (classifyMutatingTool(event, { recognizeOnly: true }) !== undefined) {
1051
+ return true;
1052
+ }
1053
+ const command = event?.input?.command;
1054
+ return (typeof command === "string" &&
1055
+ extractWrittenPathsFromCommand(command, cwd).length > 0);
1056
+ }
@@ -14,8 +14,10 @@ import { isFileKind } from "./file-kinds.js";
14
14
  import { getGlobalPiLensDir } from "./file-utils.js";
15
15
  import { findGlobalBinary } from "./package-manager.js";
16
16
  import { safeSpawnAsync } from "./safe-spawn.js";
17
+ import { probeToolAsync } from "./tool-probe.js";
17
18
  import { createSingleFlight } from "./single-flight.js";
18
19
  import { biomeConfigArgs } from "./tool-policy.js";
20
+ import { resolveToolCwd } from "./tool-cwd.js";
19
21
  import { resolveManagedToolClient, } from "./dispatch/runners/utils/runner-helpers.js";
20
22
  import { classifyProbeFailure, describeInstallAttempt, createAvailabilityLatch, logAvailabilityDecision, startHostStallSampler, } from "./dispatch/runners/utils/availability-policy.js";
21
23
  // --- Client ---
@@ -169,7 +171,14 @@ export class BiomeClient {
169
171
  let result;
170
172
  let hostStallMs;
171
173
  try {
172
- result = await this.spawnBiomeAsync(["--version"], PROBE_TIMEOUT_MS);
174
+ // The presence probe asks whether biome answers at all, so it goes
175
+ // through the probe seam (no cwd) rather than through
176
+ // `spawnBiomeAsync`, whose optional `cwd` exists for the analysis
177
+ // spawns that DO resolve a project config (#2894).
178
+ const { cmd, args: prefix } = await this.getBiomeBinary();
179
+ result = await probeToolAsync(cmd, [...prefix, "--version"], {
180
+ timeout: PROBE_TIMEOUT_MS,
181
+ });
173
182
  }
174
183
  finally {
175
184
  hostStallMs = sampler.stop();
@@ -314,7 +323,9 @@ export class BiomeClient {
314
323
  }
315
324
  try {
316
325
  const before = await fs.promises.readFile(absolutePath, "utf-8");
317
- const configCwd = cwd ?? path.dirname(absolutePath);
326
+ const configCwd = resolveToolCwd("runner", "biome", absolutePath, {
327
+ ...(cwd !== undefined && { cwd }),
328
+ }).cwd;
318
329
  // Shared config-args seam (#1247): the lint runner consumes the same
319
330
  // builder, so `lint --write` can never drift to biome's default
320
331
  // config when a user config or the package fallback exists.