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.
- package/CHANGELOG.md +99 -0
- package/README.md +31 -13
- package/dist/clients/bootstrap.js +3 -1
- package/dist/clients/bus-events-logger.js +53 -0
- package/dist/clients/bus-publish.js +45 -2
- package/dist/clients/cache/rule-cache.js +9 -5
- package/dist/clients/cache-manager.js +19 -13
- package/dist/clients/code-quality-warnings.js +27 -0
- package/dist/clients/dead-code-client.js +5 -23
- package/dist/clients/diagnostic-dispositions.js +298 -0
- package/dist/clients/diagnostics-publish.js +38 -2
- package/dist/clients/dispatch/auxiliary-lsp.js +144 -6
- package/dist/clients/dispatch/dispatcher.js +6 -1
- package/dist/clients/dispatch/facts/function-facts.js +83 -0
- package/dist/clients/dispatch/integration.js +19 -4
- package/dist/clients/dispatch/rules/async-noise.js +1 -1
- package/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +1 -1
- package/dist/clients/dispatch/rules/cors-wildcard.js +1 -1
- package/dist/clients/dispatch/rules/error-obscuring.js +2 -1
- package/dist/clients/dispatch/rules/error-swallowing.js +2 -1
- package/dist/clients/dispatch/rules/framework-call-noise.js +67 -0
- package/dist/clients/dispatch/rules/high-complexity.js +12 -1
- package/dist/clients/dispatch/rules/high-fan-out.js +14 -3
- package/dist/clients/dispatch/rules/high-import-coupling.js +1 -1
- package/dist/clients/dispatch/rules/missing-error-propagation.js +1 -1
- package/dist/clients/dispatch/rules/no-commented-credentials.js +1 -1
- package/dist/clients/dispatch/rules/pass-through-wrappers.js +1 -1
- package/dist/clients/dispatch/rules/placeholder-comments.js +1 -1
- package/dist/clients/dispatch/rules/unsafe-boundary.js +1 -1
- package/dist/clients/dispatch/runners/ast-grep-napi.js +75 -18
- package/dist/clients/dispatch/runners/lsp.js +23 -34
- package/dist/clients/dispatch/runners/oxlint.js +1 -1
- package/dist/clients/dispatch/suppress-writer.js +68 -0
- package/dist/clients/dispatch/utils/lsp-diagnostics.js +4 -1
- package/dist/clients/disposition-logger.js +39 -0
- package/dist/clients/disposition-publish.js +109 -0
- package/dist/clients/file-utils.js +94 -33
- package/dist/clients/format-events-publish.js +299 -0
- package/dist/clients/git-tracked-ignore.js +208 -0
- package/dist/clients/gitleaks-client.js +40 -5
- package/dist/clients/installer/index.js +123 -6
- package/dist/clients/instance-reaper.js +229 -2
- package/dist/clients/instance-registry.js +141 -2
- package/dist/clients/json-cache-read.js +65 -0
- package/dist/clients/knip-client.js +35 -38
- package/dist/clients/language-profile.js +11 -11
- package/dist/clients/lens-engine.js +12 -0
- package/dist/clients/lens-map.js +1079 -0
- package/dist/clients/log-cleanup.js +61 -19
- package/dist/clients/lsp/aggregation.js +69 -2
- package/dist/clients/lsp/cascade-tier.js +31 -19
- package/dist/clients/lsp/client.js +124 -14
- package/dist/clients/lsp/config.js +27 -1
- package/dist/clients/lsp/index.js +1028 -68
- package/dist/clients/lsp/server-strategies.js +17 -8
- package/dist/clients/lsp/server.js +80 -28
- package/dist/clients/lsp/tsserver-sync.js +145 -0
- package/dist/clients/lsp/workspace-diagnostics-cache.js +172 -0
- package/dist/clients/lsp-budget.js +148 -0
- package/dist/clients/mcp/session.js +9 -0
- package/dist/clients/middle-man-analysis.js +260 -0
- package/dist/clients/module-report.js +173 -11
- package/dist/clients/ndjson-logger.js +24 -0
- package/dist/clients/opengrep-client.js +217 -0
- package/dist/clients/opengrep-config.js +2 -10
- package/dist/clients/path-utils.js +66 -0
- package/dist/clients/pipeline.js +5 -1
- package/dist/clients/project-diagnostics/cache.js +5 -12
- package/dist/clients/project-diagnostics/extractors.js +21 -1
- package/dist/clients/project-diagnostics/fresh-fetch.js +275 -0
- package/dist/clients/project-diagnostics/runner-adapters/opengrep.js +40 -0
- package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +46 -0
- package/dist/clients/project-snapshot.js +3 -6
- package/dist/clients/quiet-window.js +57 -2
- package/dist/clients/read-expansion.js +2 -3
- package/dist/clients/read-guard-tool-lines.js +10 -0
- package/dist/clients/read-guard.js +1 -1
- package/dist/clients/resource-sampler.js +254 -0
- package/dist/clients/review-graph/builder.js +322 -42
- package/dist/clients/review-graph/import-resolvers.js +53 -19
- package/dist/clients/review-graph/symbol-id.js +57 -0
- package/dist/clients/runtime-agent-end.js +26 -0
- package/dist/clients/runtime-coordinator.js +9 -1
- package/dist/clients/runtime-session.js +93 -17
- package/dist/clients/runtime-tool-call.js +789 -0
- package/dist/clients/runtime-tool-result.js +15 -2
- package/dist/clients/runtime-turn.js +62 -13
- package/dist/clients/safe-spawn.js +48 -2
- package/dist/clients/session-state-store.js +6 -9
- package/dist/clients/sgconfig.js +2 -9
- package/dist/clients/source-filter.js +17 -25
- package/dist/clients/source-walker.js +66 -0
- package/dist/clients/startup-scan.js +105 -43
- package/dist/clients/symbol-containment.js +24 -0
- package/dist/clients/test-runner-client.js +544 -29
- package/dist/clients/tree-sitter-symbol-extractor.js +12 -5
- package/dist/clients/typos-config.js +2 -11
- package/dist/clients/widget-state.js +83 -1
- package/dist/clients/write-ordering-guard.js +58 -0
- package/dist/clients/zizmor-config.js +29 -10
- package/dist/index.js +25511 -19414
- package/dist/mcp/server.js +95 -19
- package/dist/tools/activate-tools.js +72 -0
- package/dist/tools/ast-dump.js +2 -8
- package/dist/tools/lens-diagnostic-mark.js +158 -0
- package/dist/tools/lens-diagnostics.js +327 -33
- package/dist/tools/lsp-diagnostics.js +525 -105
- package/dist/tools/module-report.js +18 -5
- package/docs/agent-tools.md +136 -0
- package/docs/ast-grep_rules_catalog.md +564 -0
- package/docs/astplayground.md +178 -0
- package/docs/audit1.md +177 -0
- package/docs/custom-rules.md +231 -0
- package/docs/dependencies.md +54 -0
- package/docs/dispositions.md +85 -0
- package/docs/env_variables.md +10 -0
- package/docs/environment-variables.md +83 -0
- package/docs/fable.md +140 -0
- package/docs/features.md +338 -0
- package/docs/globalconfig.md +79 -0
- package/docs/language-coverage.md +48 -0
- package/docs/lsp-capability-matrix.md +157 -0
- package/docs/lsp-latency-benchmark.md +169 -0
- package/docs/mcp.md +438 -0
- package/docs/module-report-read-symbol.md +258 -0
- package/docs/servercapabilities.md +118 -0
- package/docs/subagent-compat.md +281 -0
- package/docs/tools.md +16 -0
- package/docs/tools_improvement2.md +345 -0
- package/docs/tree-sitter_rules_catalog.md +296 -0
- package/docs/usage.md +129 -0
- package/docs/word-index.md +150 -0
- package/package.json +10 -1
- package/rules/ast-grep-rules/rule-tests/find-import-file-without-extension-test.yml +4 -0
- package/rules/ast-grep-rules/rule-tests/no-javascript-url-js-test.yml +5 -0
- package/rules/ast-grep-rules/rule-tests/no-javascript-url-test.yml +9 -0
- package/rules/ast-grep-rules/rules/array-callback-return-js.yml +1 -1
- package/rules/ast-grep-rules/rules/find-import-file-without-extension.yml +3 -1
- package/rules/ast-grep-rules/rules/jwt-no-verify-js.yml +1 -1
- package/rules/ast-grep-rules/rules/no-extra-boolean-cast-js.yml +1 -1
- package/rules/ast-grep-rules/rules/no-implied-eval-js.yml +1 -1
- package/rules/ast-grep-rules/rules/no-javascript-url-js.yml +13 -1
- package/rules/ast-grep-rules/rules/no-javascript-url.yml +12 -0
- package/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +1 -1
- package/rules/ast-grep-rules/rules/weak-rsa-key-js.yml +1 -1
- package/skills/pi-lens-ast-grep/SKILL.md +3 -1
- package/dist/clients/production-readiness.js +0 -493
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared "read a JSON cache file off disk" boilerplate (#676).
|
|
3
|
+
*
|
|
4
|
+
* At least 7 sites across the codebase hand-duplicated the same shape:
|
|
5
|
+
* `JSON.parse(fs.readFileSync(path, "utf-8"))` → structural/version guard →
|
|
6
|
+
* return the parsed value, or `undefined`/`null` on ANY throw (missing file,
|
|
7
|
+
* unreadable, corrupt JSON, or a `validate` callback itself throwing). This
|
|
8
|
+
* module extracts only that read/parse/try-catch mechanics; every call
|
|
9
|
+
* site's own "is this actually a valid, current-version cache?" logic stays
|
|
10
|
+
* put, as the `validate` callback — consolidation is only meant to remove
|
|
11
|
+
* the duplicated plumbing, not to unify subtly different validation rules
|
|
12
|
+
* that call sites had for good reason (e.g. a second `ruleHash` field check
|
|
13
|
+
* alongside the version check).
|
|
14
|
+
*
|
|
15
|
+
* `validate` returning `undefined` means "treat this like a parse failure" —
|
|
16
|
+
* the same fail-open posture every existing site already had for a
|
|
17
|
+
* wrong-version/wrong-shape cache.
|
|
18
|
+
*/
|
|
19
|
+
import * as fs from "node:fs";
|
|
20
|
+
import { promises as fsPromises } from "node:fs";
|
|
21
|
+
/**
|
|
22
|
+
* Synchronous read: `JSON.parse(fs.readFileSync(path, "utf-8"))`, run through
|
|
23
|
+
* `validate`, with any failure (missing file, unreadable, corrupt JSON,
|
|
24
|
+
* `validate` throwing) swallowed to `undefined`.
|
|
25
|
+
*
|
|
26
|
+
* `onError`, when provided, is invoked with the caught error BEFORE
|
|
27
|
+
* `undefined` is returned — for sites that log a read failure today (e.g.
|
|
28
|
+
* `CacheManager`'s verbose `this.log(...)`) rather than silently swallowing
|
|
29
|
+
* it. `onError` itself is never allowed to throw the failure back out.
|
|
30
|
+
*/
|
|
31
|
+
export function readJsonCache(path, validate, onError) {
|
|
32
|
+
try {
|
|
33
|
+
const parsed = JSON.parse(fs.readFileSync(path, "utf-8"));
|
|
34
|
+
return validate(parsed);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
try {
|
|
38
|
+
onError?.(err);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
/* onError must never mask the original fail-open behavior */
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Async sibling of {@link readJsonCache}, for call sites already on the
|
|
48
|
+
* `fs.promises` API (e.g. `session-state-store.ts`). Same fail-open contract.
|
|
49
|
+
*/
|
|
50
|
+
export async function readJsonCacheAsync(path, validate, onError) {
|
|
51
|
+
try {
|
|
52
|
+
const raw = await fsPromises.readFile(path, "utf-8");
|
|
53
|
+
const parsed = JSON.parse(raw);
|
|
54
|
+
return validate(parsed);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
try {
|
|
58
|
+
onError?.(err);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
/* onError must never mask the original fail-open behavior */
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* Docs: https://knip.dev/
|
|
10
10
|
*/
|
|
11
11
|
import * as fs from "node:fs";
|
|
12
|
-
import * as os from "node:os";
|
|
13
12
|
import * as path from "node:path";
|
|
14
|
-
import {
|
|
13
|
+
import { getProjectDataDir } from "./file-utils.js";
|
|
14
|
+
import { findNearestMarkerRoot } from "./path-utils.js";
|
|
15
15
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
16
16
|
const EMPTY_RESULT = {
|
|
17
17
|
success: false,
|
|
@@ -54,44 +54,15 @@ export class KnipClient {
|
|
|
54
54
|
* previously this fell back to `startDir`, which on a bare cwd like
|
|
55
55
|
* `/home/v` caused knip to recurse through every project and balloon
|
|
56
56
|
* memory/CPU.
|
|
57
|
+
*
|
|
58
|
+
* Delegates to the shared path-utils helper (refs #625) — never treats a
|
|
59
|
+
* package/knip config at or above $HOME as the project (escapes the
|
|
60
|
+
* workspace, #296/#250), and never walks past a `.git`/`.hg`/`.svn`
|
|
61
|
+
* boundary to pick up an unrelated parent's package.json (Unity/non-JS
|
|
62
|
+
* repos often have no package.json at their own root).
|
|
57
63
|
*/
|
|
58
64
|
resolveProjectRoot(startDir, homeDirOverride) {
|
|
59
|
-
|
|
60
|
-
"package.json",
|
|
61
|
-
"knip.json",
|
|
62
|
-
"knip.ts",
|
|
63
|
-
"knip.config.js",
|
|
64
|
-
"knip.config.ts",
|
|
65
|
-
];
|
|
66
|
-
const boundaries = [".git", ".hg", ".svn"];
|
|
67
|
-
const homeDir = path.resolve(homeDirOverride ?? os.homedir());
|
|
68
|
-
let current = path.resolve(startDir);
|
|
69
|
-
// Safety bound: in practice depths are ~10. This cap just prevents a
|
|
70
|
-
// pathological symlink loop from hanging the search.
|
|
71
|
-
for (let depth = 0; depth < 64; depth++) {
|
|
72
|
-
// Never treat a package/knip config at $HOME — or above it, such as
|
|
73
|
-
// /home/package.json from a shared parent — as the project for startup
|
|
74
|
-
// analysis. That escapes the workspace and can make knip scan the whole
|
|
75
|
-
// home tree from an empty folder (#296/#250).
|
|
76
|
-
if (isAtOrAboveHomeDir(current, homeDir)) {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
if (markers.some((m) => fs.existsSync(path.join(current, m)))) {
|
|
80
|
-
return current;
|
|
81
|
-
}
|
|
82
|
-
// Do not escape the current repository just to find an unrelated parent
|
|
83
|
-
// package.json. Unity/non-JS repos often have no package.json at their
|
|
84
|
-
// root; walking past their .git boundary can accidentally pick up
|
|
85
|
-
// ~/package.json and make knip scan the entire home directory.
|
|
86
|
-
if (boundaries.some((m) => fs.existsSync(path.join(current, m)))) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
const parent = path.dirname(current);
|
|
90
|
-
if (parent === current)
|
|
91
|
-
return null;
|
|
92
|
-
current = parent;
|
|
93
|
-
}
|
|
94
|
-
return null;
|
|
65
|
+
return findNearestMarkerRoot(startDir, ["package.json", "knip.json", "knip.ts", "knip.config.js", "knip.config.ts"], { boundaries: [".git", ".hg", ".svn"], homeDir: homeDirOverride });
|
|
95
66
|
}
|
|
96
67
|
/**
|
|
97
68
|
* Check if knip CLI is available, auto-install if not
|
|
@@ -175,6 +146,29 @@ export class KnipClient {
|
|
|
175
146
|
return promise;
|
|
176
147
|
}
|
|
177
148
|
async runAnalyze(targetDir) {
|
|
149
|
+
// Cache dir is routed through pi-lens's project-data-dir convention (NOT
|
|
150
|
+
// knip's own default `./node_modules/.cache/knip`) so it lives alongside
|
|
151
|
+
// every other project cache (see cache-manager.ts, call-graph.ts) and is
|
|
152
|
+
// covered by the existing `.pi-lens/` gitignore entry.
|
|
153
|
+
//
|
|
154
|
+
// Caveat (per knip's docs): a cached run does NOT pick up newly-added
|
|
155
|
+
// `.gitignore` files automatically — the cache must be deleted to detect
|
|
156
|
+
// them. Not auto-handled here; this is a documented tradeoff, not a bug.
|
|
157
|
+
const cacheLocation = path.join(getProjectDataDir(targetDir), "cache", "knip");
|
|
158
|
+
// knip (verified against 6.26.0) silently fails to persist the cache when
|
|
159
|
+
// `--cache-location` points at a directory that doesn't exist yet: its
|
|
160
|
+
// internal auto-mkdir throws ENOENT (swallowed internally, debug-logged
|
|
161
|
+
// only) on Windows, so the very first run — and every run after, since the
|
|
162
|
+
// dir never gets created — degrades to an uncached scan with no error
|
|
163
|
+
// surfaced. Pre-creating the dir avoids that path entirely; matches the
|
|
164
|
+
// mkdirSync-before-spawn convention call-graph.ts already uses for its
|
|
165
|
+
// cache file's parent dir.
|
|
166
|
+
try {
|
|
167
|
+
fs.mkdirSync(cacheLocation, { recursive: true });
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
this.log(`Failed to pre-create knip cache dir ${cacheLocation}: ${err}`);
|
|
171
|
+
}
|
|
178
172
|
const args = [
|
|
179
173
|
"--reporter=json",
|
|
180
174
|
"--include",
|
|
@@ -183,6 +177,9 @@ export class KnipClient {
|
|
|
183
177
|
// it makes knip exit 2 with zero output, silently disabling the scan —
|
|
184
178
|
// verified against knip 6.20. Valid member-level type here is enumMembers.)
|
|
185
179
|
"files,exports,types,dependencies,unlisted,enumMembers",
|
|
180
|
+
"--cache",
|
|
181
|
+
"--cache-location",
|
|
182
|
+
cacheLocation,
|
|
186
183
|
];
|
|
187
184
|
const result = await safeSpawnAsync("knip", args, {
|
|
188
185
|
timeout: ANALYSIS_TIMEOUT_MS,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { detectFileKind } from "./file-kinds.js";
|
|
4
|
-
import { getProjectIgnoreMatcher
|
|
4
|
+
import { getProjectIgnoreMatcher } from "./file-utils.js";
|
|
5
5
|
import { LANGUAGE_POLICY, } from "./language-policy.js";
|
|
6
6
|
import { getSourceFiles } from "./scan-utils.js";
|
|
7
|
+
import { readDirEntriesSafe, shouldRecurseIntoDir } from "./source-walker.js";
|
|
7
8
|
export const SUPPORTED_FILE_KINDS = [
|
|
8
9
|
"jsts",
|
|
9
10
|
"python",
|
|
@@ -281,6 +282,10 @@ const MAX_WARMUP_SOURCE_FILES = 2000;
|
|
|
281
282
|
export async function collectSourceFilesForWarmup(rootDir, maxFiles = MAX_WARMUP_SOURCE_FILES, yieldEvery = 100) {
|
|
282
283
|
const root = path.resolve(rootDir);
|
|
283
284
|
const ignoreMatcher = getProjectIgnoreMatcher(root);
|
|
285
|
+
// #703: prime the tracked-files set once before the walk so a tracked file
|
|
286
|
+
// matching a `.gitignore`/global pattern still counts toward language
|
|
287
|
+
// detection. Fail-open on no-git/spawn failure.
|
|
288
|
+
await ignoreMatcher.ensureTrackedIndex();
|
|
284
289
|
const stack = [root];
|
|
285
290
|
const out = [];
|
|
286
291
|
let processedSinceYield = 0;
|
|
@@ -288,20 +293,15 @@ export async function collectSourceFilesForWarmup(rootDir, maxFiles = MAX_WARMUP
|
|
|
288
293
|
const current = stack.pop();
|
|
289
294
|
if (!current)
|
|
290
295
|
continue;
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
entries = fs.readdirSync(current, { withFileTypes: true });
|
|
294
|
-
}
|
|
295
|
-
catch {
|
|
296
|
-
continue;
|
|
297
|
-
}
|
|
296
|
+
const entries = readDirEntriesSafe(current);
|
|
298
297
|
for (const entry of entries) {
|
|
299
298
|
const fullPath = path.join(current, entry.name);
|
|
300
299
|
if (entry.isDirectory()) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if (
|
|
300
|
+
// Never checked symlinks — always follows them (unlike
|
|
301
|
+
// source-filter.ts's collectSourceFiles*, refs #191).
|
|
302
|
+
if (!shouldRecurseIntoDir(entry, fullPath, { ignoreMatcher, followSymlinks: true })) {
|
|
304
303
|
continue;
|
|
304
|
+
}
|
|
305
305
|
stack.push(fullPath);
|
|
306
306
|
}
|
|
307
307
|
else if (entry.isFile()) {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { getDiagnosticTracker } from "./diagnostic-tracker.js";
|
|
17
17
|
import { getLatencyReports, } from "./dispatch/integration.js";
|
|
18
|
+
import { getResourceFootprint as getResourceFootprintSnapshot, } from "./instance-registry.js";
|
|
18
19
|
import { initLSPConfig } from "./lsp/config.js";
|
|
19
20
|
import { getLSPService } from "./lsp/index.js";
|
|
20
21
|
import { getOrLoadWarmWordIndex } from "./mcp/analyze.js";
|
|
@@ -57,6 +58,17 @@ export function diagnosticStats() {
|
|
|
57
58
|
export function ensureLspConfig(cwd) {
|
|
58
59
|
return initLSPConfig(cwd);
|
|
59
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* #620: total CPU/RAM footprint attributable to pi-lens across every process
|
|
63
|
+
* it owns — every registered instance's host, plus that instance's live LSP
|
|
64
|
+
* children. Reads the machine-global `~/.pi-lens/instances.json` registry, so
|
|
65
|
+
* this answers across ALL concurrent pi-lens sessions/worktrees on the box,
|
|
66
|
+
* not just this one. Best-effort: reflects whatever heartbeats have landed so
|
|
67
|
+
* far — a stale-heartbeat instance simply reports its last-sampled numbers.
|
|
68
|
+
*/
|
|
69
|
+
export function resourceFootprint() {
|
|
70
|
+
return getResourceFootprintSnapshot();
|
|
71
|
+
}
|
|
60
72
|
function toSymbolSearchHit(result) {
|
|
61
73
|
const line = result.lines[0] ?? 1;
|
|
62
74
|
return {
|