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
package/README.md
CHANGED
|
@@ -18,6 +18,10 @@ pi-lens gives AI coding agents fast, language-aware feedback while they write/ed
|
|
|
18
18
|
- Review-graph intelligence for supported languages via bundled tree-sitter WASMs
|
|
19
19
|
- Ranked identifier search (`symbol_search`) over an always-warm word index,
|
|
20
20
|
feeding the discovery funnel (symbol_search → module_report → read_symbol)
|
|
21
|
+
- Diagnostic triage (`lens_diagnostic_mark`): findings can be marked
|
|
22
|
+
false-positive, suppressed in source, deferred, or flagged-to-fix — honored
|
|
23
|
+
across all surfaces
|
|
24
|
+
- `/lens-map` — interactive HTML dependency map of the project
|
|
21
25
|
- Read-guard and edit-autopatch support to reduce bad edits
|
|
22
26
|
- Background security/dependency scans for opted-in projects
|
|
23
27
|
|
|
@@ -33,6 +37,14 @@ Or from git:
|
|
|
33
37
|
pi install git:github.com/apmantza/pi-lens
|
|
34
38
|
```
|
|
35
39
|
|
|
40
|
+
> **npm v12 users:** dependency lifecycle scripts (e.g. `@ast-grep/cli`'s
|
|
41
|
+
> `postinstall`) now require explicit approval — if `npm install` warns about
|
|
42
|
+
> unreviewed install scripts, review and allow them with
|
|
43
|
+
> `npm approve-scripts`, or trust the `allowScripts` entries already declared
|
|
44
|
+
> in this package's `package.json`. Installing from a git source (`pi install
|
|
45
|
+
> git:...` / `pi update --extension git:...`) may similarly prompt for
|
|
46
|
+
> git-dependency approval; accept it to let the `prepare` build step run.
|
|
47
|
+
|
|
36
48
|
## Documentation
|
|
37
49
|
|
|
38
50
|
- [Agent tools](docs/agent-tools.md) — pi tool names, scopes, and arguments
|
|
@@ -42,6 +54,8 @@ pi install git:github.com/apmantza/pi-lens
|
|
|
42
54
|
- [Word index](docs/word-index.md) — identifier search (`symbol_search`) and
|
|
43
55
|
the discovery funnel
|
|
44
56
|
- [Tools and commands](docs/tools.md) — runtime flags and slash commands
|
|
57
|
+
- [Diagnostic dispositions](docs/dispositions.md) — triage: false-positive,
|
|
58
|
+
suppress, defer, flagged-to-fix
|
|
45
59
|
- [Configuration](docs/globalconfig.md) — global and project config files
|
|
46
60
|
- [Environment variables](docs/env_variables.md) — common env vars and full
|
|
47
61
|
reference link
|
|
@@ -66,7 +80,7 @@ Thanks goes to these wonderful people:
|
|
|
66
80
|
<!-- markdownlint-disable -->
|
|
67
81
|
<table>
|
|
68
82
|
<tbody>
|
|
69
|
-
|
|
83
|
+
<tr>
|
|
70
84
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/apmantza"><img src="https://avatars.githubusercontent.com/u/247365598?v=4" width="100px;" alt=""/><br /><sub><b>Apostolos Mantzaris</b></sub></a><br /><a href="#code-apmantza" title="Code">💻</a> <a href="#doc-apmantza" title="Documentation">📖</a> <a href="#ideas-apmantza" title="Ideas & Planning">🤔</a> <a href="#maintenance-apmantza" title="Maintenance">🚧</a> <a href="#review-apmantza" title="Reviewed Pull Requests">👀</a></td>
|
|
71
85
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/anh-chu"><img src="https://avatars.githubusercontent.com/u/34973633?v=4" width="100px;" alt=""/><br /><sub><b>Anh Chu</b></sub></a><br /><a href="#code-anh-chu" title="Code">💻</a></td>
|
|
72
86
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/loss-and-quick"><img src="https://avatars.githubusercontent.com/u/39405619?v=4" width="100px;" alt=""/><br /><sub><b>minicx</b></sub></a><br /><a href="#code-loss-and-quick" title="Code">💻</a></td>
|
|
@@ -74,7 +88,7 @@ Thanks goes to these wonderful people:
|
|
|
74
88
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tifandotme"><img src="https://avatars.githubusercontent.com/u/33323177?v=4" width="100px;" alt=""/><br /><sub><b>Tifan Dwi Avianto</b></sub></a><br /><a href="#code-tifandotme" title="Code">💻</a></td>
|
|
75
89
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/amit-gshe"><img src="https://avatars.githubusercontent.com/u/7383028?v=4" width="100px;" alt=""/><br /><sub><b>Amit</b></sub></a><br /><a href="#code-amit-gshe" title="Code">💻</a> <a href="#bug-amit-gshe" title="Bug reports">🐛</a></td>
|
|
76
90
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fractiunate"><img src="https://avatars.githubusercontent.com/u/78024279?v=4" width="100px;" alt=""/><br /><sub><b>Fractiunate // David Rahäuser</b></sub></a><br /><a href="#code-fractiunate" title="Code">💻</a></td>
|
|
77
|
-
</tr
|
|
91
|
+
</tr><br />
|
|
78
92
|
<tr>
|
|
79
93
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/vkarasen"><img src="https://avatars.githubusercontent.com/u/7932536?v=4" width="100px;" alt=""/><br /><sub><b>Vitali Karasenko</b></sub></a><br /><a href="#code-vkarasen" title="Code">💻</a></td>
|
|
80
94
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rfxlamia"><img src="https://avatars.githubusercontent.com/u/222023708?v=4" width="100px;" alt=""/><br /><sub><b>V</b></sub></a><br /><a href="#code-rfxlamia" title="Code">💻</a></td>
|
|
@@ -83,7 +97,7 @@ Thanks goes to these wonderful people:
|
|
|
83
97
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mehalter"><img src="https://avatars.githubusercontent.com/u/1591837?v=4" width="100px;" alt=""/><br /><sub><b>Micah Halter</b></sub></a><br /><a href="#code-mehalter" title="Code">💻</a></td>
|
|
84
98
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JulienEllie"><img src="https://avatars.githubusercontent.com/u/670518?v=4" width="100px;" alt=""/><br /><sub><b>Julien Ellie</b></sub></a><br /><a href="#code-JulienEllie" title="Code">💻</a></td>
|
|
85
99
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Istar-Eldritch"><img src="https://avatars.githubusercontent.com/u/3746468?v=4" width="100px;" alt=""/><br /><sub><b>Ruben Paz</b></sub></a><br /><a href="#code-Istar-Eldritch" title="Code">💻</a> <a href="#bug-Istar-Eldritch" title="Bug reports">🐛</a></td>
|
|
86
|
-
</tr
|
|
100
|
+
</tr><br />
|
|
87
101
|
<tr>
|
|
88
102
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cjunxiang"><img src="https://avatars.githubusercontent.com/u/26619858?v=4" width="100px;" alt=""/><br /><sub><b>C.Junxiang</b></sub></a><br /><a href="#code-cjunxiang" title="Code">💻</a> <a href="#bug-cjunxiang" title="Bug reports">🐛</a></td>
|
|
89
103
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/trvon"><img src="https://avatars.githubusercontent.com/u/6031322?v=4" width="100px;" alt=""/><br /><sub><b>Trevon</b></sub></a><br /><a href="#code-trvon" title="Code">💻</a></td>
|
|
@@ -92,7 +106,7 @@ Thanks goes to these wonderful people:
|
|
|
92
106
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/spyrosbazios"><img src="https://avatars.githubusercontent.com/u/37960233?v=4" width="100px;" alt=""/><br /><sub><b>spyrosbazios</b></sub></a><br /><a href="#code-spyrosbazios" title="Code">💻</a></td>
|
|
93
107
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Roman-Galeev"><img src="https://avatars.githubusercontent.com/u/40388226?v=4" width="100px;" alt=""/><br /><sub><b>Roman Galeev</b></sub></a><br /><a href="#code-Roman-Galeev" title="Code">💻</a></td>
|
|
94
108
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jerryfan"><img src="https://avatars.githubusercontent.com/u/2540814?v=4" width="100px;" alt=""/><br /><sub><b>jerryfan</b></sub></a><br /><a href="#code-jerryfan" title="Code">💻</a></td>
|
|
95
|
-
</tr
|
|
109
|
+
</tr><br />
|
|
96
110
|
<tr>
|
|
97
111
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/shaDmx"><img src="https://avatars.githubusercontent.com/u/91132641?v=4" width="100px;" alt=""/><br /><sub><b>Max L.</b></sub></a><br /><a href="#code-shaDmx" title="Code">💻</a></td>
|
|
98
112
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/radge"><img src="https://avatars.githubusercontent.com/u/129205?v=4" width="100px;" alt=""/><br /><sub><b>David Ryan</b></sub></a><br /><a href="#code-radge" title="Code">💻</a></td>
|
|
@@ -101,7 +115,7 @@ Thanks goes to these wonderful people:
|
|
|
101
115
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/feoh"><img src="https://avatars.githubusercontent.com/u/330070?v=4" width="100px;" alt=""/><br /><sub><b>Chris Patti</b></sub></a><br /><a href="#code-feoh" title="Code">💻</a> <a href="#bug-feoh" title="Bug reports">🐛</a></td>
|
|
102
116
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chenxin-yan"><img src="https://avatars.githubusercontent.com/u/71162231?v=4" width="100px;" alt=""/><br /><sub><b>Chenxin Yan</b></sub></a><br /><a href="#code-chenxin-yan" title="Code">💻</a> <a href="#doc-chenxin-yan" title="Documentation">📖</a> <a href="#bug-chenxin-yan" title="Bug reports">🐛</a></td>
|
|
103
117
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/flowing-abyss"><img src="https://avatars.githubusercontent.com/u/98622217?v=4" width="100px;" alt=""/><br /><sub><b>flowing-abyss</b></sub></a><br /><a href="#code-flowing-abyss" title="Code">💻</a></td>
|
|
104
|
-
</tr
|
|
118
|
+
</tr><br />
|
|
105
119
|
<tr>
|
|
106
120
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xuli500177"><img src="https://avatars.githubusercontent.com/u/62830942?v=4" width="100px;" alt=""/><br /><sub><b>Xu Yili</b></sub></a><br /><a href="#bug-xuli500177" title="Bug reports">🐛</a></td>
|
|
107
121
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ricardoraposo"><img src="https://avatars.githubusercontent.com/u/50217712?v=4" width="100px;" alt=""/><br /><sub><b>Ricardo Raposo</b></sub></a><br /><a href="#code-ricardoraposo" title="Code">💻</a></td>
|
|
@@ -110,7 +124,7 @@ Thanks goes to these wonderful people:
|
|
|
110
124
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PeraSite"><img src="https://avatars.githubusercontent.com/u/19837403?v=4" width="100px;" alt=""/><br /><sub><b>정제훈</b></sub></a><br /><a href="#code-PeraSite" title="Code">💻</a></td>
|
|
111
125
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/carolitascl"><img src="https://avatars.githubusercontent.com/u/26188349?v=4" width="100px;" alt=""/><br /><sub><b>Carolina</b></sub></a><br /><a href="#bug-carolitascl" title="Bug reports">🐛</a></td>
|
|
112
126
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/leakedby"><img src="https://avatars.githubusercontent.com/u/4213260?v=4" width="100px;" alt=""/><br /><sub><b>LeakedBy</b></sub></a><br /><a href="#bug-leakedby" title="Bug reports">🐛</a></td>
|
|
113
|
-
</tr
|
|
127
|
+
</tr><br />
|
|
114
128
|
<tr>
|
|
115
129
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/mdbooth"><img src="https://avatars.githubusercontent.com/u/1318691?v=4" width="100px;" alt=""/><br /><sub><b>Matthew Booth</b></sub></a><br /><a href="#bug-mdbooth" title="Bug reports">🐛</a></td>
|
|
116
130
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Wiedzmin89"><img src="https://avatars.githubusercontent.com/u/61706855?v=4" width="100px;" alt=""/><br /><sub><b>Wiedzmin89</b></sub></a><br /><a href="#ideas-Wiedzmin89" title="Ideas & Planning">🤔</a></td>
|
|
@@ -119,7 +133,7 @@ Thanks goes to these wonderful people:
|
|
|
119
133
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ywh555hhh"><img src="https://avatars.githubusercontent.com/u/121592812?v=4" width="100px;" alt=""/><br /><sub><b>Wayne E</b></sub></a><br /><a href="#bug-ywh555hhh" title="Bug reports">🐛</a></td>
|
|
120
134
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/RimuruW"><img src="https://avatars.githubusercontent.com/u/59136309?v=4" width="100px;" alt=""/><br /><sub><b>RimuruW</b></sub></a><br /><a href="#ideas-RimuruW" title="Ideas & Planning">🤔</a></td>
|
|
121
135
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Bjynt"><img src="https://avatars.githubusercontent.com/u/22177300?v=4" width="100px;" alt=""/><br /><sub><b>Bjynt</b></sub></a><br /><a href="#bug-Bjynt" title="Bug reports">🐛</a> <a href="#ideas-Bjynt" title="Ideas & Planning">🤔</a></td>
|
|
122
|
-
</tr
|
|
136
|
+
</tr><br />
|
|
123
137
|
<tr>
|
|
124
138
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/pvtri96"><img src="https://avatars.githubusercontent.com/u/28696888?v=4" width="100px;" alt=""/><br /><sub><b>Tri Van Pham</b></sub></a><br /><a href="#bug-pvtri96" title="Bug reports">🐛</a></td>
|
|
125
139
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BingWuJ"><img src="https://avatars.githubusercontent.com/u/117666511?v=4" width="100px;" alt=""/><br /><sub><b>BingWuJ</b></sub></a><br /><a href="#bug-BingWuJ" title="Bug reports">🐛</a></td>
|
|
@@ -128,7 +142,7 @@ Thanks goes to these wonderful people:
|
|
|
128
142
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ProbabilityEngineer"><img src="https://avatars.githubusercontent.com/u/38498804?v=4" width="100px;" alt=""/><br /><sub><b>ProbabilityEngineer</b></sub></a><br /><a href="#ideas-ProbabilityEngineer" title="Ideas & Planning">🤔</a></td>
|
|
129
143
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/LeonardoRick"><img src="https://avatars.githubusercontent.com/u/17517057?v=4" width="100px;" alt=""/><br /><sub><b>Leonardo Rick</b></sub></a><br /><a href="#bug-LeonardoRick" title="Bug reports">🐛</a> <a href="#ideas-LeonardoRick" title="Ideas & Planning">🤔</a></td>
|
|
130
144
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kenbanks-peng"><img src="https://avatars.githubusercontent.com/u/26904200?v=4" width="100px;" alt=""/><br /><sub><b>Ken Banks</b></sub></a><br /><a href="#bug-kenbanks-peng" title="Bug reports">🐛</a></td>
|
|
131
|
-
</tr
|
|
145
|
+
</tr><br />
|
|
132
146
|
<tr>
|
|
133
147
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/rstacruz"><img src="https://avatars.githubusercontent.com/u/74385?v=4" width="100px;" alt=""/><br /><sub><b>Rico Sta. Cruz</b></sub></a><br /><a href="#ideas-rstacruz" title="Ideas & Planning">🤔</a></td>
|
|
134
148
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/acidnik"><img src="https://avatars.githubusercontent.com/u/1227955?v=4" width="100px;" alt=""/><br /><sub><b>Nikita Bilous</b></sub></a><br /><a href="#bug-acidnik" title="Bug reports">🐛</a></td>
|
|
@@ -137,7 +151,7 @@ Thanks goes to these wonderful people:
|
|
|
137
151
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/nodnarbnitram"><img src="https://avatars.githubusercontent.com/u/44812862?v=4" width="100px;" alt=""/><br /><sub><b>Brandon Martin</b></sub></a><br /><a href="#bug-nodnarbnitram" title="Bug reports">🐛</a></td>
|
|
138
152
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/alpertarhan"><img src="https://avatars.githubusercontent.com/u/50966980?v=4" width="100px;" alt=""/><br /><sub><b>Alper Tarhan</b></sub></a><br /><a href="#bug-alpertarhan" title="Bug reports">🐛</a></td>
|
|
139
153
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/asolopovas"><img src="https://avatars.githubusercontent.com/u/6893216?v=4" width="100px;" alt=""/><br /><sub><b>Andrius Solopovas</b></sub></a><br /><a href="#bug-asolopovas" title="Bug reports">🐛</a></td>
|
|
140
|
-
</tr
|
|
154
|
+
</tr><br />
|
|
141
155
|
<tr>
|
|
142
156
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/GrahamJenkins"><img src="https://avatars.githubusercontent.com/u/6607975?v=4" width="100px;" alt=""/><br /><sub><b>Graham Jenkins</b></sub></a><br /><a href="#bug-GrahamJenkins" title="Bug reports">🐛</a></td>
|
|
143
157
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wings1848"><img src="https://avatars.githubusercontent.com/u/120104016?v=4" width="100px;" alt=""/><br /><sub><b>Wings Butterfly</b></sub></a><br /><a href="#bug-wings1848" title="Bug reports">🐛</a></td>
|
|
@@ -146,7 +160,7 @@ Thanks goes to these wonderful people:
|
|
|
146
160
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fmatray"><img src="https://avatars.githubusercontent.com/u/8267716?v=4" width="100px;" alt=""/><br /><sub><b>Frédéric</b></sub></a><br /><a href="#bug-fmatray" title="Bug reports">🐛</a></td>
|
|
147
161
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fuentesjr"><img src="https://avatars.githubusercontent.com/u/9240?v=4" width="100px;" alt=""/><br /><sub><b>Salvador Fuentes Jr</b></sub></a><br /><a href="#bug-fuentesjr" title="Bug reports">🐛</a></td>
|
|
148
162
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Viterkim"><img src="https://avatars.githubusercontent.com/u/17838985?v=4" width="100px;" alt=""/><br /><sub><b>Viktor</b></sub></a><br /><a href="#bug-Viterkim" title="Bug reports">🐛</a></td>
|
|
149
|
-
</tr
|
|
163
|
+
</tr><br />
|
|
150
164
|
<tr>
|
|
151
165
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ortonomy"><img src="https://avatars.githubusercontent.com/u/6688676?v=4" width="100px;" alt=""/><br /><sub><b>Gregory Orton</b></sub></a><br /><a href="#bug-ortonomy" title="Bug reports">🐛</a></td>
|
|
152
166
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jimallen"><img src="https://avatars.githubusercontent.com/u/868773?v=4" width="100px;" alt=""/><br /><sub><b>Jim Allen</b></sub></a><br /><a href="#bug-jimallen" title="Bug reports">🐛</a></td>
|
|
@@ -155,7 +169,7 @@ Thanks goes to these wonderful people:
|
|
|
155
169
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/chozandrias76"><img src="https://avatars.githubusercontent.com/u/2087677?v=4" width="100px;" alt=""/><br /><sub><b>Colin Swenson-Healey</b></sub></a><br /><a href="#bug-chozandrias76" title="Bug reports">🐛</a></td>
|
|
156
170
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JustlyAI"><img src="https://avatars.githubusercontent.com/u/12634140?v=4" width="100px;" alt=""/><br /><sub><b>Laurent Wiesel</b></sub></a><br /><a href="#bug-JustlyAI" title="Bug reports">🐛</a></td>
|
|
157
171
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/stark-bit"><img src="https://avatars.githubusercontent.com/u/44064758?v=4" width="100px;" alt=""/><br /><sub><b>Rei Starks</b></sub></a><br /><a href="#bug-stark-bit" title="Bug reports">🐛</a></td>
|
|
158
|
-
</tr
|
|
172
|
+
</tr><br />
|
|
159
173
|
<tr>
|
|
160
174
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/robertoecf"><img src="https://avatars.githubusercontent.com/u/54923863?v=4" width="100px;" alt=""/><br /><sub><b>Roberto Freitas</b></sub></a><br /><a href="#bug-robertoecf" title="Bug reports">🐛</a></td>
|
|
161
175
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tmttodd"><img src="https://avatars.githubusercontent.com/u/160077416?v=4" width="100px;" alt=""/><br /><sub><b>tmttodd</b></sub></a><br /><a href="#bug-tmttodd" title="Bug reports">🐛</a></td>
|
|
@@ -164,15 +178,19 @@ Thanks goes to these wonderful people:
|
|
|
164
178
|
<td align="center" valign="top" width="14.28%"><a href="http://jasonrimmer.com/"><img src="https://avatars.githubusercontent.com/u/629?v=4" width="100px;" alt=""/><br /><sub><b>Jason Rimmer</b></sub></a><br /><a href="#bug-jrimmer" title="Bug reports">🐛</a></td>
|
|
165
179
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ArthurHeymans"><img src="https://avatars.githubusercontent.com/u/15137817?v=4" width="100px;" alt=""/><br /><sub><b>Arthur Heymans</b></sub></a><br /><a href="#ideas-ArthurHeymans" title="Ideas & Planning">🤔</a></td>
|
|
166
180
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Blue-B"><img src="https://avatars.githubusercontent.com/u/55532956?v=4" width="100px;" alt=""/><br /><sub><b>Blue-B</b></sub></a><br /><a href="#bug-Blue-B" title="Bug reports">🐛</a></td>
|
|
167
|
-
</tr
|
|
181
|
+
</tr><br />
|
|
168
182
|
<tr>
|
|
169
183
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bisko"><img src="https://avatars.githubusercontent.com/u/184938?v=4" width="100px;" alt=""/><br /><sub><b>Biser Perchinkov</b></sub></a><br /><a href="#bug-bisko" title="Bug reports">🐛</a></td>
|
|
170
184
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xificurC"><img src="https://avatars.githubusercontent.com/u/4800719?v=4" width="100px;" alt=""/><br /><sub><b>Peter Nagy</b></sub></a><br /><a href="#bug-xificurC" title="Bug reports">🐛</a></td>
|
|
171
185
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/orest-tokovenko-block"><img src="https://avatars.githubusercontent.com/u/190554467?v=4" width="100px;" alt=""/><br /><sub><b>Orest Tokovenko</b></sub></a><br /><a href="#bug-orest-tokovenko-block" title="Bug reports">🐛</a></td>
|
|
186
|
+
<td align="center" valign="top" width="14.28%"><a href="https://eisterman.dev/"><img src="https://avatars.githubusercontent.com/u/3028953?v=4" width="100px;" alt=""/><br /><sub><b>Federico Pasqua</b></sub></a><br /><a href="#bug-eisterman" title="Bug reports">🐛</a></td>
|
|
187
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ymek"><img src="https://avatars.githubusercontent.com/u/300569?v=4" width="100px;" alt=""/><br /><sub><b>Myke Stubbs</b></sub></a><br /><a href="#code-ymek" title="Code">💻</a> <a href="#bug-ymek" title="Bug reports">🐛</a></td>
|
|
188
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/black-snow"><img src="https://avatars.githubusercontent.com/u/579733?v=4" width="100px;" alt=""/><br /><sub><b>Ronald</b></sub></a><br /><a href="#bug-black-snow" title="Bug reports">🐛</a></td>
|
|
172
189
|
</tr>
|
|
173
|
-
|
|
190
|
+
</tbody>
|
|
174
191
|
</table>
|
|
175
192
|
|
|
193
|
+
|
|
176
194
|
<!-- markdownlint-restore -->
|
|
177
195
|
<!-- prettier-ignore-end -->
|
|
178
196
|
|
|
@@ -63,7 +63,7 @@ export function loadBootstrapClients() {
|
|
|
63
63
|
return [];
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
const [ruffClient, biomeClient, knipClient, todoScanner, jscpdClient, depChecker, testRunnerClient, metricsClient, complexityClient, goClient, govulncheckClient, gitleaksClient, trivyClient, rustClient, agentBehaviorClient, deadCodeClients,] = await Promise.all([
|
|
66
|
+
const [ruffClient, biomeClient, knipClient, todoScanner, jscpdClient, depChecker, testRunnerClient, metricsClient, complexityClient, goClient, govulncheckClient, gitleaksClient, trivyClient, opengrepClient, rustClient, agentBehaviorClient, deadCodeClients,] = await Promise.all([
|
|
67
67
|
load("ruff", async () => new (await import("./ruff-client.js")).RuffClient()),
|
|
68
68
|
load("biome", async () => new (await import("./biome-client.js")).BiomeClient()),
|
|
69
69
|
load("knip", async () => new (await import("./knip-client.js")).KnipClient()),
|
|
@@ -77,6 +77,7 @@ export function loadBootstrapClients() {
|
|
|
77
77
|
load("govulncheck", async () => new (await import("./govulncheck-client.js")).GovulncheckClient()),
|
|
78
78
|
load("gitleaks", async () => new (await import("./gitleaks-client.js")).GitleaksClient()),
|
|
79
79
|
load("trivy", async () => new (await import("./trivy-client.js")).TrivyClient()),
|
|
80
|
+
load("opengrep", async () => new (await import("./opengrep-client.js")).OpengrepClient()),
|
|
80
81
|
load("rust", async () => new (await import("./rust-client.js")).RustClient()),
|
|
81
82
|
load("agent-behavior", async () => new (await import("./agent-behavior-client.js")).AgentBehaviorClient()),
|
|
82
83
|
loadList("dead-code", async () => (await import("./dead-code-client.js")).getDeadCodeClients()),
|
|
@@ -97,6 +98,7 @@ export function loadBootstrapClients() {
|
|
|
97
98
|
govulncheckClient,
|
|
98
99
|
gitleaksClient,
|
|
99
100
|
trivyClient,
|
|
101
|
+
opengrepClient,
|
|
100
102
|
rustClient,
|
|
101
103
|
agentBehaviorClient,
|
|
102
104
|
deadCodeClients,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent NDJSON trace of `pi.events` bus publish attempts
|
|
3
|
+
* (`pilens:files:touched` #482 / `pilens:diagnostics` #502 /
|
|
4
|
+
* `pilens:format:queued` + `pilens:format:start` #673).
|
|
5
|
+
*
|
|
6
|
+
* All four producers (clients/bus-publish.ts, clients/diagnostics-publish.ts,
|
|
7
|
+
* clients/format-events-publish.ts) are fire-and-forget: on failure or on a
|
|
8
|
+
* structural no-op (never wired, kill switch off) they only invoke an
|
|
9
|
+
* optional `dbg` callback, which varies by host and is a documented no-op in
|
|
10
|
+
* the MCP host (clients/mcp/session.ts's `dbg: noop`). That leaves
|
|
11
|
+
* bus-publish outcomes invisible in exactly the context where they matter
|
|
12
|
+
* most — same failure shape as the #544 MCP session_start incident this repo
|
|
13
|
+
* already fixed once.
|
|
14
|
+
*
|
|
15
|
+
* This module gives bus events the same durable trace every other pi-lens
|
|
16
|
+
* subsystem already has (latency.log, cascade.log, read-guard.log, ...) —
|
|
17
|
+
* see clients/latency-logger.ts for the house pattern this mirrors exactly:
|
|
18
|
+
* one shared `createNdjsonLogger` writer, `isTestMode()` no-op guard,
|
|
19
|
+
* `getBusEventsLogPath()` for testability.
|
|
20
|
+
*
|
|
21
|
+
* Logging volume: `emitted` and `emit_failed` are logged on every call —
|
|
22
|
+
* they're the two outcomes an operator actually needs a per-event trace for.
|
|
23
|
+
* `skipped_unwired` and `skipped_disabled` are process-lifetime-static facts
|
|
24
|
+
* (wiring happens once at extension factory time; the kill switch is an env
|
|
25
|
+
* var read once at startup) — logging them on every publish attempt would
|
|
26
|
+
* spam one identical line per write batch for an entire session with zero
|
|
27
|
+
* new information after the first. Both are gated log-once-per-process, the
|
|
28
|
+
* same `hasLoggedFailure` shape the producers already use for emit_failed.
|
|
29
|
+
* The empty-batch branch (`paths.length === 0` / `files.length === 0`) is
|
|
30
|
+
* NOT logged at all: every call site already guards against invoking these
|
|
31
|
+
* functions with nothing to report (see clients/pipeline.ts,
|
|
32
|
+
* clients/runtime-agent-end.ts), so it's a normal, frequent no-op rather
|
|
33
|
+
* than a real event worth a log line.
|
|
34
|
+
*/
|
|
35
|
+
import * as path from "node:path";
|
|
36
|
+
import { isTestMode } from "./env-utils.js";
|
|
37
|
+
import { getGlobalPiLensDir } from "./file-utils.js";
|
|
38
|
+
import { createNdjsonLogger } from "./ndjson-logger.js";
|
|
39
|
+
const BUS_EVENTS_LOG_FILE = path.join(getGlobalPiLensDir(), "bus-events.log");
|
|
40
|
+
const writer = createNdjsonLogger({ filePath: BUS_EVENTS_LOG_FILE });
|
|
41
|
+
export function logBusEvent(entry) {
|
|
42
|
+
if (isTestMode()) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
writer.log({ ts: new Date().toISOString(), ...entry });
|
|
46
|
+
}
|
|
47
|
+
export function getBusEventsLogPath() {
|
|
48
|
+
return BUS_EVENTS_LOG_FILE;
|
|
49
|
+
}
|
|
50
|
+
/** Resolve once all enqueued bus-event writes are on disk (tests/shutdown). */
|
|
51
|
+
export function flushBusEventsLog() {
|
|
52
|
+
return writer.flush();
|
|
53
|
+
}
|
|
@@ -17,12 +17,19 @@
|
|
|
17
17
|
* callback is invoked at most once on first failure so a wired caller can log
|
|
18
18
|
* it without spamming.
|
|
19
19
|
*/
|
|
20
|
+
import { logBusEvent } from "./bus-events-logger.js";
|
|
20
21
|
import { normalizeFilePath } from "./path-utils.js";
|
|
21
22
|
import { appendRecentTouches } from "./recent-touches.js";
|
|
22
23
|
export const BUS_FILES_TOUCHED_EVENT = "pilens:files:touched";
|
|
23
24
|
export const BUS_FILES_TOUCHED_VERSION = 1;
|
|
24
25
|
let busEmit;
|
|
25
26
|
let hasLoggedFailure = false;
|
|
27
|
+
// Log-once-per-process guards for the two structural-no-op outcomes below
|
|
28
|
+
// (see bus-events-logger.ts's module doc for why these aren't logged on
|
|
29
|
+
// every call — both are static, session-lifetime facts, not transient
|
|
30
|
+
// per-event failures).
|
|
31
|
+
let hasLoggedUnwired = false;
|
|
32
|
+
let hasLoggedDisabled = false;
|
|
26
33
|
/**
|
|
27
34
|
* Wire the emit function from pi's `pi.events` bus. Called once at extension
|
|
28
35
|
* factory time from index.ts (module-level singleton, same pattern as
|
|
@@ -37,6 +44,8 @@ export function wireBusEmitter(emitFn) {
|
|
|
37
44
|
export function _resetForTests() {
|
|
38
45
|
busEmit = undefined;
|
|
39
46
|
hasLoggedFailure = false;
|
|
47
|
+
hasLoggedUnwired = false;
|
|
48
|
+
hasLoggedDisabled = false;
|
|
40
49
|
_envCache = undefined;
|
|
41
50
|
}
|
|
42
51
|
let _envCache;
|
|
@@ -73,8 +82,18 @@ export function publishFilesTouched(args) {
|
|
|
73
82
|
return;
|
|
74
83
|
if (args.paths.length === 0)
|
|
75
84
|
return;
|
|
76
|
-
if (!isBusPublishEnabled())
|
|
85
|
+
if (!isBusPublishEnabled()) {
|
|
86
|
+
if (!hasLoggedDisabled) {
|
|
87
|
+
hasLoggedDisabled = true;
|
|
88
|
+
logBusEvent({
|
|
89
|
+
event: BUS_FILES_TOUCHED_EVENT,
|
|
90
|
+
outcome: "skipped_disabled",
|
|
91
|
+
cwd: normalizeFilePath(args.cwd),
|
|
92
|
+
reason: args.reason,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
77
95
|
return;
|
|
96
|
+
}
|
|
78
97
|
void appendRecentTouches({
|
|
79
98
|
cwd: args.cwd,
|
|
80
99
|
reason: args.reason,
|
|
@@ -83,8 +102,18 @@ export function publishFilesTouched(args) {
|
|
|
83
102
|
}).catch((err) => {
|
|
84
103
|
args.dbg?.(`bus-publish: recent-touches append failed: ${err}`);
|
|
85
104
|
});
|
|
86
|
-
if (!busEmit)
|
|
105
|
+
if (!busEmit) {
|
|
106
|
+
if (!hasLoggedUnwired) {
|
|
107
|
+
hasLoggedUnwired = true;
|
|
108
|
+
logBusEvent({
|
|
109
|
+
event: BUS_FILES_TOUCHED_EVENT,
|
|
110
|
+
outcome: "skipped_unwired",
|
|
111
|
+
cwd: normalizeFilePath(args.cwd),
|
|
112
|
+
reason: args.reason,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
87
115
|
return;
|
|
116
|
+
}
|
|
88
117
|
try {
|
|
89
118
|
const payload = {
|
|
90
119
|
v: BUS_FILES_TOUCHED_VERSION,
|
|
@@ -100,8 +129,22 @@ export function publishFilesTouched(args) {
|
|
|
100
129
|
}));
|
|
101
130
|
}
|
|
102
131
|
busEmit(BUS_FILES_TOUCHED_EVENT, payload);
|
|
132
|
+
logBusEvent({
|
|
133
|
+
event: BUS_FILES_TOUCHED_EVENT,
|
|
134
|
+
outcome: "emitted",
|
|
135
|
+
cwd: payload.cwd,
|
|
136
|
+
reason: args.reason,
|
|
137
|
+
fileCount: payload.paths.length,
|
|
138
|
+
});
|
|
103
139
|
}
|
|
104
140
|
catch (err) {
|
|
141
|
+
logBusEvent({
|
|
142
|
+
event: BUS_FILES_TOUCHED_EVENT,
|
|
143
|
+
outcome: "emit_failed",
|
|
144
|
+
cwd: normalizeFilePath(args.cwd),
|
|
145
|
+
reason: args.reason,
|
|
146
|
+
error: String(err),
|
|
147
|
+
});
|
|
105
148
|
if (!hasLoggedFailure) {
|
|
106
149
|
hasLoggedFailure = true;
|
|
107
150
|
args.dbg?.(`bus-publish: pilens:files:touched emit failed (further failures suppressed): ${err}`);
|
|
@@ -8,6 +8,7 @@ import * as crypto from "node:crypto";
|
|
|
8
8
|
import * as fs from "node:fs";
|
|
9
9
|
import * as path from "node:path";
|
|
10
10
|
import { getProjectDataDir } from "../file-utils.js";
|
|
11
|
+
import { readJsonCache } from "../json-cache-read.js";
|
|
11
12
|
const CACHE_VERSION = "v3";
|
|
12
13
|
export class RuleCache {
|
|
13
14
|
cacheFile;
|
|
@@ -36,12 +37,15 @@ export class RuleCache {
|
|
|
36
37
|
this.ensureCacheDir();
|
|
37
38
|
if (!fs.existsSync(this.cacheFile))
|
|
38
39
|
return null;
|
|
39
|
-
const cached = JSON.parse(fs.readFileSync(this.cacheFile, "utf-8"));
|
|
40
40
|
const currentHash = this.computeRuleHash(ruleFiles);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
const cached = readJsonCache(this.cacheFile, (parsed) => {
|
|
42
|
+
const entry = parsed;
|
|
43
|
+
if (entry.version !== CACHE_VERSION || entry.ruleHash !== currentHash) {
|
|
44
|
+
return undefined; // Cache invalid
|
|
45
|
+
}
|
|
46
|
+
return entry;
|
|
47
|
+
});
|
|
48
|
+
return cached ?? null;
|
|
45
49
|
}
|
|
46
50
|
catch {
|
|
47
51
|
return null;
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import * as fs from "node:fs";
|
|
12
12
|
import * as path from "node:path";
|
|
13
13
|
import { getProjectDataDir } from "./file-utils.js";
|
|
14
|
+
import { readJsonCache } from "./json-cache-read.js";
|
|
14
15
|
import { normalizeMapKey } from "./path-utils.js";
|
|
15
16
|
// --- Defaults ---
|
|
16
17
|
const DEFAULT_MAX_AGE_MS = 30 * 60 * 1000; // 30 minutes
|
|
@@ -72,13 +73,20 @@ export class CacheManager {
|
|
|
72
73
|
return null;
|
|
73
74
|
}
|
|
74
75
|
try {
|
|
75
|
-
const
|
|
76
|
+
const onReadError = (err) => {
|
|
77
|
+
this.log(`Cache read error: ${scanner} — ${err}`);
|
|
78
|
+
};
|
|
79
|
+
const meta = readJsonCache(metaPath, (parsed) => parsed, onReadError);
|
|
80
|
+
if (meta === undefined)
|
|
81
|
+
return null;
|
|
76
82
|
const age = Date.now() - new Date(meta.timestamp).getTime();
|
|
77
83
|
if (age > maxAgeMs) {
|
|
78
84
|
this.log(`Cache stale: ${scanner} (age: ${Math.round(age / 1000)}s, max: ${maxAgeMs / 1000}s)`);
|
|
79
85
|
return null;
|
|
80
86
|
}
|
|
81
|
-
const data =
|
|
87
|
+
const data = readJsonCache(cachePath, (parsed) => parsed, onReadError);
|
|
88
|
+
if (data === undefined)
|
|
89
|
+
return null;
|
|
82
90
|
this.log(`Cache hit: ${scanner} (age: ${Math.round(age / 1000)}s)`);
|
|
83
91
|
return { data, meta };
|
|
84
92
|
}
|
|
@@ -111,7 +119,9 @@ export class CacheManager {
|
|
|
111
119
|
if (!fs.existsSync(metaPath))
|
|
112
120
|
return false;
|
|
113
121
|
try {
|
|
114
|
-
const meta =
|
|
122
|
+
const meta = readJsonCache(metaPath, (parsed) => parsed);
|
|
123
|
+
if (meta === undefined)
|
|
124
|
+
return false;
|
|
115
125
|
const age = Date.now() - new Date(meta.timestamp).getTime();
|
|
116
126
|
return age <= maxAgeMs;
|
|
117
127
|
}
|
|
@@ -150,16 +160,12 @@ export class CacheManager {
|
|
|
150
160
|
lastUpdated: new Date().toISOString(),
|
|
151
161
|
};
|
|
152
162
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
files: {},
|
|
160
|
-
lastUpdated: new Date().toISOString(),
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
+
const state = readJsonCache(statePath, (parsed) => parsed);
|
|
164
|
+
return (state ?? {
|
|
165
|
+
...DEFAULT_TURN_STATE,
|
|
166
|
+
files: {},
|
|
167
|
+
lastUpdated: new Date().toISOString(),
|
|
168
|
+
});
|
|
163
169
|
}
|
|
164
170
|
/**
|
|
165
171
|
* Write turn state.
|
|
@@ -135,6 +135,33 @@ export function buildCodeQualityWarningsReport(args) {
|
|
|
135
135
|
},
|
|
136
136
|
};
|
|
137
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* #557 audit (same race class as #555's LSP client fix and #560's
|
|
140
|
+
* `widget-state.ts` `recordDiagnostics` fix): pi-lens deliberately allows
|
|
141
|
+
* concurrent pipeline runs for the SAME file across DIFFERENT same-turn
|
|
142
|
+
* edits (dedupe key is `filePath + contentHash`, not just `filePath` — see
|
|
143
|
+
* `clients/runtime-tool-result.ts`), so a per-key cache fed directly from
|
|
144
|
+
* those concurrent pipeline runs needs an ordering guard (`WriteOrderingGuard`
|
|
145
|
+
* from `clients/write-ordering-guard.ts`) or an older edit's slower pipeline
|
|
146
|
+
* can silently overwrite a newer edit's fresher write.
|
|
147
|
+
*
|
|
148
|
+
* This call site is NOT exposed to that race. Unlike `widget-state.ts`'s
|
|
149
|
+
* `recordDiagnostics` (called directly from `clients/pipeline.ts`, once per
|
|
150
|
+
* pipeline run — i.e. potentially several times per turn, out of completion
|
|
151
|
+
* order), `writeCodeQualityWarningsReport` has exactly one caller:
|
|
152
|
+
* `handleTurnEnd` in `clients/runtime-turn.ts`, which per-edit pipeline runs
|
|
153
|
+
* never call directly — they only feed `runtime.recordCodeQualityWarnings`
|
|
154
|
+
* (an accumulating, order-independent Map). `handleTurnEnd` itself reads that
|
|
155
|
+
* accumulator once via `runtime.peekCodeQualityWarnings()` and writes the
|
|
156
|
+
* aggregate report exactly once per turn-end invocation — the same single
|
|
157
|
+
* sequential turn-end-only shape already confirmed safe for
|
|
158
|
+
* `writeActionableWarningsReport` in `clients/actionable-warnings.ts`, right
|
|
159
|
+
* next to this call site in `handleTurnEnd`. No second writer, so no
|
|
160
|
+
* ordering token to guard against — see
|
|
161
|
+
* `tests/clients/code-quality-warnings.test.ts`'s
|
|
162
|
+
* "single sequential caller" test, which pins this invariant so a future
|
|
163
|
+
* change that adds a second call site has a better chance of being caught.
|
|
164
|
+
*/
|
|
138
165
|
export function writeCodeQualityWarningsReport(cacheManager, cwd, report) {
|
|
139
166
|
cacheManager.writeCache("code-quality-warnings", report, cwd);
|
|
140
167
|
}
|
|
@@ -11,10 +11,8 @@
|
|
|
11
11
|
* Phase 1 ships Python via `vulture`. Future phases add Go/Rust/etc. by
|
|
12
12
|
* implementing DeadCodeClient and adding to getDeadCodeClients().
|
|
13
13
|
*/
|
|
14
|
-
import * as fs from "node:fs";
|
|
15
|
-
import * as os from "node:os";
|
|
16
14
|
import * as path from "node:path";
|
|
17
|
-
import {
|
|
15
|
+
import { findNearestMarkerRoot } from "./path-utils.js";
|
|
18
16
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
19
17
|
function emptyResult(language) {
|
|
20
18
|
return {
|
|
@@ -108,34 +106,18 @@ export class PythonDeadCodeClient {
|
|
|
108
106
|
* Nearest dir with a Python project marker, never at/above $HOME and never
|
|
109
107
|
* escaping a VCS boundary — same containment rules as KnipClient so a scan
|
|
110
108
|
* launched from a bare cwd can't recurse the whole home tree (#250/#296).
|
|
109
|
+
* Delegates to the shared path-utils helper (refs #625) rather than
|
|
110
|
+
* hand-rolling the climb; only the marker list differs from KnipClient's.
|
|
111
111
|
*/
|
|
112
112
|
resolveProjectRoot(startDir, homeDirOverride) {
|
|
113
|
-
|
|
113
|
+
return findNearestMarkerRoot(startDir, [
|
|
114
114
|
"pyproject.toml",
|
|
115
115
|
"setup.py",
|
|
116
116
|
"setup.cfg",
|
|
117
117
|
"requirements.txt",
|
|
118
118
|
"Pipfile",
|
|
119
119
|
"tox.ini",
|
|
120
|
-
];
|
|
121
|
-
const boundaries = [".git", ".hg", ".svn"];
|
|
122
|
-
const homeDir = path.resolve(homeDirOverride ?? os.homedir());
|
|
123
|
-
let current = path.resolve(startDir);
|
|
124
|
-
for (let depth = 0; depth < 64; depth++) {
|
|
125
|
-
if (isAtOrAboveHomeDir(current, homeDir))
|
|
126
|
-
return null;
|
|
127
|
-
if (markers.some((m) => fs.existsSync(path.join(current, m)))) {
|
|
128
|
-
return current;
|
|
129
|
-
}
|
|
130
|
-
if (boundaries.some((m) => fs.existsSync(path.join(current, m)))) {
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
const parent = path.dirname(current);
|
|
134
|
-
if (parent === current)
|
|
135
|
-
return null;
|
|
136
|
-
current = parent;
|
|
137
|
-
}
|
|
138
|
-
return null;
|
|
120
|
+
], { boundaries: [".git", ".hg", ".svn"], homeDir: homeDirOverride });
|
|
139
121
|
}
|
|
140
122
|
async ensureAvailable() {
|
|
141
123
|
if (this.available !== null)
|