pi-lens 3.8.69 → 3.8.71

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 (147) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/README.md +31 -13
  3. package/dist/clients/bootstrap.js +3 -1
  4. package/dist/clients/bus-events-logger.js +53 -0
  5. package/dist/clients/bus-publish.js +45 -2
  6. package/dist/clients/cache/rule-cache.js +9 -5
  7. package/dist/clients/cache-manager.js +19 -13
  8. package/dist/clients/code-quality-warnings.js +27 -0
  9. package/dist/clients/dead-code-client.js +5 -23
  10. package/dist/clients/diagnostic-dispositions.js +298 -0
  11. package/dist/clients/diagnostics-publish.js +38 -2
  12. package/dist/clients/dispatch/auxiliary-lsp.js +144 -6
  13. package/dist/clients/dispatch/dispatcher.js +6 -1
  14. package/dist/clients/dispatch/facts/function-facts.js +83 -0
  15. package/dist/clients/dispatch/integration.js +19 -4
  16. package/dist/clients/dispatch/rules/async-noise.js +1 -1
  17. package/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +1 -1
  18. package/dist/clients/dispatch/rules/cors-wildcard.js +1 -1
  19. package/dist/clients/dispatch/rules/error-obscuring.js +2 -1
  20. package/dist/clients/dispatch/rules/error-swallowing.js +2 -1
  21. package/dist/clients/dispatch/rules/framework-call-noise.js +67 -0
  22. package/dist/clients/dispatch/rules/high-complexity.js +12 -1
  23. package/dist/clients/dispatch/rules/high-fan-out.js +14 -3
  24. package/dist/clients/dispatch/rules/high-import-coupling.js +1 -1
  25. package/dist/clients/dispatch/rules/missing-error-propagation.js +1 -1
  26. package/dist/clients/dispatch/rules/no-commented-credentials.js +1 -1
  27. package/dist/clients/dispatch/rules/pass-through-wrappers.js +1 -1
  28. package/dist/clients/dispatch/rules/placeholder-comments.js +1 -1
  29. package/dist/clients/dispatch/rules/unsafe-boundary.js +1 -1
  30. package/dist/clients/dispatch/runners/ast-grep-napi.js +75 -18
  31. package/dist/clients/dispatch/runners/lsp.js +23 -34
  32. package/dist/clients/dispatch/runners/oxlint.js +1 -1
  33. package/dist/clients/dispatch/suppress-writer.js +68 -0
  34. package/dist/clients/dispatch/utils/lsp-diagnostics.js +4 -1
  35. package/dist/clients/disposition-logger.js +39 -0
  36. package/dist/clients/disposition-publish.js +109 -0
  37. package/dist/clients/file-utils.js +94 -33
  38. package/dist/clients/format-events-publish.js +299 -0
  39. package/dist/clients/git-tracked-ignore.js +208 -0
  40. package/dist/clients/gitleaks-client.js +40 -5
  41. package/dist/clients/installer/index.js +123 -6
  42. package/dist/clients/instance-reaper.js +229 -2
  43. package/dist/clients/instance-registry.js +141 -2
  44. package/dist/clients/json-cache-read.js +65 -0
  45. package/dist/clients/knip-client.js +35 -38
  46. package/dist/clients/language-profile.js +11 -11
  47. package/dist/clients/lens-engine.js +12 -0
  48. package/dist/clients/lens-map.js +1079 -0
  49. package/dist/clients/log-cleanup.js +61 -19
  50. package/dist/clients/lsp/aggregation.js +69 -2
  51. package/dist/clients/lsp/cascade-tier.js +31 -19
  52. package/dist/clients/lsp/client.js +124 -14
  53. package/dist/clients/lsp/config.js +27 -1
  54. package/dist/clients/lsp/index.js +1028 -68
  55. package/dist/clients/lsp/server-strategies.js +17 -8
  56. package/dist/clients/lsp/server.js +80 -28
  57. package/dist/clients/lsp/tsserver-sync.js +145 -0
  58. package/dist/clients/lsp/workspace-diagnostics-cache.js +172 -0
  59. package/dist/clients/lsp-budget.js +148 -0
  60. package/dist/clients/mcp/session.js +9 -0
  61. package/dist/clients/middle-man-analysis.js +260 -0
  62. package/dist/clients/module-report.js +173 -11
  63. package/dist/clients/ndjson-logger.js +24 -0
  64. package/dist/clients/opengrep-client.js +217 -0
  65. package/dist/clients/opengrep-config.js +2 -10
  66. package/dist/clients/path-utils.js +66 -0
  67. package/dist/clients/pipeline.js +5 -1
  68. package/dist/clients/project-diagnostics/cache.js +5 -12
  69. package/dist/clients/project-diagnostics/extractors.js +21 -1
  70. package/dist/clients/project-diagnostics/fresh-fetch.js +275 -0
  71. package/dist/clients/project-diagnostics/runner-adapters/opengrep.js +40 -0
  72. package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +46 -0
  73. package/dist/clients/project-snapshot.js +3 -6
  74. package/dist/clients/quiet-window.js +57 -2
  75. package/dist/clients/read-expansion.js +2 -3
  76. package/dist/clients/read-guard-tool-lines.js +10 -0
  77. package/dist/clients/read-guard.js +1 -1
  78. package/dist/clients/resource-sampler.js +254 -0
  79. package/dist/clients/review-graph/builder.js +322 -42
  80. package/dist/clients/review-graph/import-resolvers.js +53 -19
  81. package/dist/clients/review-graph/symbol-id.js +57 -0
  82. package/dist/clients/runtime-agent-end.js +26 -0
  83. package/dist/clients/runtime-coordinator.js +9 -1
  84. package/dist/clients/runtime-session.js +93 -17
  85. package/dist/clients/runtime-tool-call.js +789 -0
  86. package/dist/clients/runtime-tool-result.js +15 -2
  87. package/dist/clients/runtime-turn.js +62 -13
  88. package/dist/clients/safe-spawn.js +48 -2
  89. package/dist/clients/session-state-store.js +6 -9
  90. package/dist/clients/sgconfig.js +2 -9
  91. package/dist/clients/source-filter.js +17 -25
  92. package/dist/clients/source-walker.js +66 -0
  93. package/dist/clients/startup-scan.js +105 -43
  94. package/dist/clients/symbol-containment.js +24 -0
  95. package/dist/clients/test-runner-client.js +544 -29
  96. package/dist/clients/tree-sitter-symbol-extractor.js +12 -5
  97. package/dist/clients/typos-config.js +2 -11
  98. package/dist/clients/widget-state.js +83 -1
  99. package/dist/clients/write-ordering-guard.js +58 -0
  100. package/dist/clients/zizmor-config.js +29 -10
  101. package/dist/index.js +25511 -19414
  102. package/dist/mcp/server.js +95 -19
  103. package/dist/tools/activate-tools.js +72 -0
  104. package/dist/tools/ast-dump.js +2 -8
  105. package/dist/tools/lens-diagnostic-mark.js +158 -0
  106. package/dist/tools/lens-diagnostics.js +327 -33
  107. package/dist/tools/lsp-diagnostics.js +525 -105
  108. package/dist/tools/module-report.js +18 -5
  109. package/docs/agent-tools.md +136 -0
  110. package/docs/ast-grep_rules_catalog.md +564 -0
  111. package/docs/astplayground.md +178 -0
  112. package/docs/audit1.md +177 -0
  113. package/docs/custom-rules.md +231 -0
  114. package/docs/dependencies.md +54 -0
  115. package/docs/dispositions.md +85 -0
  116. package/docs/env_variables.md +10 -0
  117. package/docs/environment-variables.md +83 -0
  118. package/docs/fable.md +140 -0
  119. package/docs/features.md +338 -0
  120. package/docs/globalconfig.md +79 -0
  121. package/docs/language-coverage.md +48 -0
  122. package/docs/lsp-capability-matrix.md +157 -0
  123. package/docs/lsp-latency-benchmark.md +169 -0
  124. package/docs/mcp.md +438 -0
  125. package/docs/module-report-read-symbol.md +258 -0
  126. package/docs/servercapabilities.md +118 -0
  127. package/docs/subagent-compat.md +281 -0
  128. package/docs/tools.md +16 -0
  129. package/docs/tools_improvement2.md +345 -0
  130. package/docs/tree-sitter_rules_catalog.md +296 -0
  131. package/docs/usage.md +129 -0
  132. package/docs/word-index.md +150 -0
  133. package/package.json +10 -1
  134. package/rules/ast-grep-rules/rule-tests/find-import-file-without-extension-test.yml +4 -0
  135. package/rules/ast-grep-rules/rule-tests/no-javascript-url-js-test.yml +5 -0
  136. package/rules/ast-grep-rules/rule-tests/no-javascript-url-test.yml +9 -0
  137. package/rules/ast-grep-rules/rules/array-callback-return-js.yml +1 -1
  138. package/rules/ast-grep-rules/rules/find-import-file-without-extension.yml +3 -1
  139. package/rules/ast-grep-rules/rules/jwt-no-verify-js.yml +1 -1
  140. package/rules/ast-grep-rules/rules/no-extra-boolean-cast-js.yml +1 -1
  141. package/rules/ast-grep-rules/rules/no-implied-eval-js.yml +1 -1
  142. package/rules/ast-grep-rules/rules/no-javascript-url-js.yml +13 -1
  143. package/rules/ast-grep-rules/rules/no-javascript-url.yml +12 -0
  144. package/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +1 -1
  145. package/rules/ast-grep-rules/rules/weak-rsa-key-js.yml +1 -1
  146. package/skills/pi-lens-ast-grep/SKILL.md +3 -1
  147. package/dist/clients/production-readiness.js +0 -493
@@ -148,7 +148,7 @@ export function createReadSymbolTool(getProjectRoot, recordSymbolRead) {
148
148
  return {
149
149
  name: "read_symbol",
150
150
  label: "Read Symbol",
151
- description: "Return the verbatim source of a single named symbol or module_report callback handle in a file — a targeted, cheap alternative to reading the whole file. Pair with module_report: module_report finds the symbol/callback handle, read_symbol shows its body. Unlike an outline, this delivers the actual lines, so it counts as having read that symbol for the read-before-edit guard.",
151
+ description: "Return the verbatim source of a single named symbol or module_report callback handle in a file — a targeted, cheap alternative to reading the whole file. Pair with module_report: module_report finds the symbol/callback handle, read_symbol shows its body. Unlike an outline, this delivers the actual lines, so it counts as having read that symbol for the read-before-edit guard. The returned body includes an attached doc comment when one exists. Accepts a dotted `Class.method` name to resolve a member directly, falling back to a plain top-level lookup when the qualifier doesn't resolve. A miss embeds the ~3 nearest symbol names in the file so a typo self-corrects without a second call. When multiple same-file symbols share a name (overloads, a type and a value sharing a name), the first is returned with an `ambiguous` note; pass `kind` to pick a specific one.",
152
152
  promptSnippet: "Read one symbol's body instead of the whole file",
153
153
  renderResult: compactRenderResult(({ details, args, isError, lineCount }) => {
154
154
  const base = baseName(args.path);
@@ -166,15 +166,20 @@ export function createReadSymbolTool(getProjectRoot, recordSymbolRead) {
166
166
  description: "Absolute or workspace-relative path to the source file.",
167
167
  }),
168
168
  symbol: Type.String({
169
- description: "Exact symbol name or callback handle to read (e.g. a function, class, type, or module_report callbacks[].name).",
169
+ description: "Exact symbol name or callback handle to read (e.g. a function, class, type, or module_report callbacks[].name). Accepts a dotted `Class.method` name to resolve a member.",
170
170
  }),
171
+ kind: Type.Optional(Type.String({
172
+ description: "Optional kind filter (e.g. function, interface, class) to disambiguate when multiple same-file symbols share the requested name. Omitting it returns the first match, same as today.",
173
+ })),
171
174
  }),
172
175
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
173
176
  const absFile = resolveFile(params.path, ctx.cwd);
174
177
  const cwd = getProjectRoot() || ctx.cwd || ".";
175
178
  let result;
176
179
  try {
177
- result = await readSymbol(absFile, params.symbol, cwd);
180
+ result = await readSymbol(absFile, params.symbol, cwd, {
181
+ kind: params.kind,
182
+ });
178
183
  }
179
184
  catch (err) {
180
185
  return {
@@ -192,9 +197,12 @@ export function createReadSymbolTool(getProjectRoot, recordSymbolRead) {
192
197
  const warningSuffix = result.warnings?.length
193
198
  ? ` Warnings: ${result.warnings.join("; ")}`
194
199
  : "";
200
+ const suggestionSuffix = result.suggestions?.length
201
+ ? ` Did you mean: ${result.suggestions.join(", ")}?`
202
+ : " Use module_report to list available symbols.";
195
203
  const text = result.error
196
204
  ? `Could not inspect ${path.basename(absFile)}: ${result.error}${warningSuffix}`
197
- : `Symbol "${params.symbol}" not found in ${path.basename(absFile)}. Use module_report to list available symbols.${warningSuffix}`;
205
+ : `Symbol "${params.symbol}" not found in ${path.basename(absFile)}.${suggestionSuffix}${warningSuffix}`;
198
206
  return {
199
207
  content: [{ type: "text", text }],
200
208
  isError: true,
@@ -202,6 +210,7 @@ export function createReadSymbolTool(getProjectRoot, recordSymbolRead) {
202
210
  found: false,
203
211
  ...(result.error ? { error: result.error } : {}),
204
212
  ...(result.warnings ? { warnings: result.warnings } : {}),
213
+ ...(result.suggestions ? { suggestions: result.suggestions } : {}),
205
214
  },
206
215
  };
207
216
  }
@@ -210,7 +219,10 @@ export function createReadSymbolTool(getProjectRoot, recordSymbolRead) {
210
219
  // response useful even if the guard hook itself fails; surface that fact in
211
220
  // details so callers know the returned body may not unlock a later edit.
212
221
  const readRecorded = recordReadCoverage(recordSymbolRead, result, "read_symbol_guard_error");
213
- const header = `${result.kind} ${result.name} ${path.basename(result.path)}:${result.startLine}-${result.endLine}`;
222
+ const ambiguityNote = result.ambiguous
223
+ ? ` (${result.ambiguous.count} matches — returned the ${result.kind}; pass \`kind\` to disambiguate: ${result.ambiguous.kinds.join(", ")})`
224
+ : "";
225
+ const header = `${result.kind} ${result.name}${ambiguityNote} ${path.basename(result.path)}:${result.startLine}-${result.endLine}`;
214
226
  const guardWarning = readRecorded
215
227
  ? ""
216
228
  : "\n\nWarning: read coverage recording failed; the returned body may not satisfy the edit guard.";
@@ -228,6 +240,7 @@ export function createReadSymbolTool(getProjectRoot, recordSymbolRead) {
228
240
  startLine: result.startLine,
229
241
  endLine: result.endLine,
230
242
  readRecorded,
243
+ ...(result.ambiguous ? { ambiguous: result.ambiguous } : {}),
231
244
  },
232
245
  };
233
246
  },
@@ -0,0 +1,136 @@
1
+ # Agent-Facing Tools
2
+
3
+ pi-lens registers the following tools with the pi agent. Most are also exposed
4
+ through the MCP mirror (`clients/lens-engine.ts` is the seam both adapters
5
+ share) — current exceptions: `ast_grep_outline` and `ast_grep_dump`
6
+ (module_report supersedes them for discovery), and `lens_diagnostic_mark`
7
+ (pi-lens-internal for now). `read_enclosing` gained MCP parity
8
+ (`pilens_read_enclosing`) as of #536, closing #522 item 1.
9
+
10
+ **Dynamic tooling.** Six tools stay always-active: `lens_diagnostics`,
11
+ `lsp_diagnostics`, `module_report`, `read_symbol`, `read_enclosing`,
12
+ `symbol_search`. Six situational tools — `ast_grep_search`, `ast_grep_replace`,
13
+ `ast_grep_outline`, `ast_grep_dump`, `lsp_navigation`, `lens_diagnostic_mark` —
14
+ are registered but
15
+ inactive by default; the model activates the ones it needs via the always-active
16
+ loader tool `pi_lens_activate_tools`, per pi's dynamic-tool-loading API
17
+ (`pi.setActiveTools`/`pi.getActiveTools`). Feature-detected: on hosts without
18
+ that API, the five situational tools fall back to being statically active,
19
+ exactly as before (`tools/activate-tools.ts`, wired in `index.ts`).
20
+
21
+ ## Per-edit
22
+
23
+ - **`lens_diagnostics`** — Cached diagnostic state for the current session.
24
+ Modes: `delta` (current turn), `all` (resurfaces stale blockers dropped from
25
+ turn context), `full` (project-wide scan).
26
+ - **`lens_diagnostic_mark`** — Triage a diagnostic: `false-positive` /
27
+ `suppress` (writes an inline `pi-lens-ignore` comment) / `defer`
28
+ (session-only) / `flagged` (persists, rendered `📌 flagged-to-fix`).
29
+ Content-anchored so marks survive edits; every mark is logged and published
30
+ on the bus. See [dispositions.md](dispositions.md).
31
+ - **`lsp_diagnostics`** — File- or directory-scoped LSP diagnostics via the
32
+ active language server.
33
+ - **`lsp_navigation`** — IDE-style navigation: `definition`, `references`,
34
+ `implementation`, `typeDefinition`, `declaration`, `rename`, `rename_file`,
35
+ `hover`, `documentSymbol`, `workspaceSymbol`, `signatureHelp`,
36
+ `prepareCallHierarchy`, `incomingCalls`, `outgoingCalls`, `executeCommand`,
37
+ and `capabilities`. Position-based operations accept a `path`/`line`/`character`
38
+ triple. `documentSymbol` accepts a `kinds` filter (e.g. `function`, `class`)
39
+ and a `maxResults` cap (default 20, max 100) to keep large files bounded.
40
+ - **`ast_grep_search`** — AST-aware structural search across ~40 languages via
41
+ the `sg` CLI. Supports metavariables (`$VAR`, `$$$ARGS`), `strictness`
42
+ modes (`smart`, `relaxed`, `ast`, `cst`, `signature`, `template`), structural
43
+ constraints (`insideKind`, `hasKind`, `follows`, `precedes`), raw YAML `rule`
44
+ passthrough, `validateOnly` for compile/shape checks without scanning project
45
+ files, and pagination via `skip` / `maxMatches` (per-call cap, default 50,
46
+ max 200; also sets the pagination step). `groupByFile: true` renders a compact
47
+ one-line-per-file distribution (`L<line>:<col>` locations) instead of each
48
+ match body — for high-volume searches. `pattern` is optional when a `rule` is
49
+ given.
50
+ Results include `details.matchLocations[]` — each hit carries a ready
51
+ `readSlice` (`path`/`offset`/`limit`) for a bounded context read; zero-match
52
+ results include a `suggestedDump` hint pointing at `ast_grep_dump`.
53
+ - **`ast_grep_replace`** — AST-aware structural replace. Re-validates the pattern
54
+ against the current file before writing and reports a clear error if the
55
+ file changed since the preview.
56
+ - **`ast_grep_dump`** — Dumps the raw tree-sitter AST for a source snippet. Use
57
+ this when an `ast_grep_search` or `ast_grep_replace` pattern returns zero
58
+ matches and the correct node kind or field name is unknown. `includeAnonymous`
59
+ shows punctuation/CST nodes.
60
+ - **`ast_grep_outline`** — Syntax-only code structure (symbols, imports, exports,
61
+ members) for files or directories via `ast-grep outline`. Fast, local, no
62
+ index/LSP/cross-file semantics. Supports `items`/`view`/`type`/`match`/
63
+ `pubMembers`/`globs`; returns per-file `items[]` (nested `members[]`) with
64
+ ready `read` args. Prefer `module_report` for pi-lens-aware navigation; reach
65
+ for this when the syntax tree's own view is enough or pi-lens's extractor is
66
+ weak for a language.
67
+
68
+ ## Project intelligence
69
+
70
+ - **`symbol_search`** — Ranked identifier search over the persisted word index
71
+ (BM25 + priors demoting tests/vendor/docs, optional graph-centrality boost).
72
+ Answers "which files are most relevant to `<query>`" by identifier — the
73
+ first step of the discovery funnel: `symbol_search` finds candidates,
74
+ `module_report` explains one, `read_symbol` reads its body. Complements
75
+ `grep` (raw substrings) and `lsp_navigation` (exact references). Returns
76
+ `available: false` with a retry hint when the index isn't built yet — it
77
+ self-builds in the background and never blocks the call. See
78
+ [docs/word-index.md](word-index.md) for how the index is built and kept
79
+ warm.
80
+ - **`module_report`** — Navigable outline of a file: every symbol's name/kind/
81
+ startLine/endLine/signature, exported vs internal split, class/interface
82
+ member nesting, who-uses-this, fanout/complexity risk flags, and a
83
+ `recommendedReads` top-3 ranked by usage + complexity. No per-symbol `read`
84
+ block (#512) — `offset`/`limit` are pure derivations of `startLine`/`endLine`
85
+ on the report's own `path`; to read a symbol call `read`/`read_symbol` with
86
+ `offset=startLine, limit=endLine-startLine+1` on that path. Cross-file
87
+ entries (`blastRadius.files[].read`, `usedBy[].file`) keep their own path.
88
+ Each entry also carries a first-line `doc` summary (whitespace-collapsed,
89
+ ~120 chars) extracted from an attached doc comment when the language uses
90
+ tree-sitter's conventional `comment` node — JS/TS is the primary target;
91
+ languages sharing that node shape (confirmed: Python, and any grammar whose
92
+ comment nodes are plain preceding siblings) get it for free with no
93
+ per-grammar query work. `exported` stays a boolean field only — it is NOT
94
+ also repeated inside `flags` (#512); `flags` carries only non-derivable
95
+ signals (`async`, `high fanout`, `high complexity`, `boundary wrapper`).
96
+ Each entry carries a `decorators[]` array — the declaration's
97
+ decorators/attributes/annotations (`@app.get("/x")`, `#[tokio::main]`,
98
+ `@Override`) — so the agent reads a symbol's role (route/test/fixture/
99
+ entrypoint) without opening the body. Also emits a `callbacks[]` section for
100
+ high-signal inline executables (event handlers, timers, promise callbacks,
101
+ object/dict function props, assigned closures) with stable synthetic
102
+ handles and flags. The optional `focus` string re-ranks `recommendedReads`
103
+ without expanding scope. `callbackSupport` (`tuned`/`generic`) reports
104
+ whether language-specific callback rules applied — the callback *node
105
+ kinds* are language-uniform, but the semantics are per-language (JS/TS-tuned
106
+ by default, plus Go goroutine/defer, Python scheduler/future lambda, Rust
107
+ spawn/move-closure, Swift weak/strong-self capture, C++ by-reference-
108
+ capture, Kotlin coroutine-builder, Java thread/executor/listener, and C#
109
+ Task.Run/event-`+=` slices); named symbols span all tree-sitter
110
+ `SYMBOL_QUERIES` languages. Pass `view: "summary"` for a smaller orientation
111
+ payload (top-level entries + recommendations, heavy callback/usedBy/
112
+ blast-radius payloads omitted); pass `view: "compact"` for a line-oriented
113
+ TEXT rendering of the full report (cheapest option — roughly a quarter of
114
+ the JSON cost, same underlying data). Reports section-level `provenance`
115
+ for syntax, cached-graph, and heuristic sections. Pass `blastRadius: true`
116
+ for cross-file transitive dependents (read-only over the cached graph).
117
+ - **`read_symbol`** — One symbol's verbatim source body, by name or by a
118
+ `module_report` callback handle. Returned body is recorded as genuine
119
+ read-guard coverage for that symbol/callback's line range.
120
+ - **`read_enclosing`** — Maps a `path` + `line` (from `ast_grep_search`,
121
+ diagnostics, or LSP locations) to the verbatim body of the smallest enclosing
122
+ symbol or callback. Tree-sitter only — no LSP or graph build. Optional `kinds`
123
+ filter and `maxLines` cap; records read-guard coverage for the returned range.
124
+ When the body exceeds `maxLines`, `onOversize` controls the fallback: `error`
125
+ (default) returns metadata only, `slice` returns a bounded partial read around
126
+ the line (size via `aroundLine`, default `maxLines` then 80), and `outline`
127
+ returns the nested symbols/callbacks with read handles.
128
+
129
+ ## Session
130
+
131
+ - **`lens_health`** — Runtime health, latency telemetry, and current LSP
132
+ status.
133
+ - **`lens_project_scan`** — Cheap project-wide scans (knip, jscpd, duplicates).
134
+ - **`lens_diagnostics mode=full`** — full project-wide review: LSP + the cached
135
+ heavyweight analyzers (jscpd, madge, gitleaks, govulncheck, trivy, dead-code)
136
+ folded in via `refreshRunners`.