pi-lens 3.8.68 → 3.8.70
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 +114 -0
- package/README.md +53 -34
- package/dist/clients/agent-nudge.js +262 -0
- package/dist/clients/biome-client.js +2 -2
- package/dist/clients/bootstrap.js +3 -1
- package/dist/clients/bus-events-logger.js +51 -0
- package/dist/clients/bus-publish.js +153 -0
- package/dist/clients/code-quality-warnings.js +27 -0
- package/dist/clients/dead-code-client.js +5 -23
- package/dist/clients/diagnostic-logger.js +2 -2
- package/dist/clients/diagnostics-publish.js +216 -0
- package/dist/clients/dispatch/auxiliary-lsp.js +62 -6
- package/dist/clients/dispatch/dispatcher.js +2 -0
- package/dist/clients/dispatch/facts/function-facts.js +83 -0
- package/dist/clients/dispatch/integration.js +153 -2
- 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 +133 -31
- package/dist/clients/dispatch/runners/lsp.js +22 -6
- package/dist/clients/dispatch/runners/yaml-rule-parser.js +68 -19
- package/dist/clients/file-utils.js +20 -7
- package/dist/clients/gitleaks-client.js +40 -5
- package/dist/clients/installer/index.js +155 -7
- package/dist/clients/instance-reaper.js +343 -18
- package/dist/clients/instance-registry.js +71 -2
- package/dist/clients/jscpd-client.js +2 -2
- package/dist/clients/knip-client.js +35 -38
- package/dist/clients/language-profile.js +7 -11
- package/dist/clients/lens-config.js +17 -0
- package/dist/clients/lens-engine.js +56 -10
- package/dist/clients/log-cleanup.js +61 -19
- package/dist/clients/lsp/cascade-tier.js +266 -0
- package/dist/clients/lsp/client.js +57 -8
- package/dist/clients/lsp/config.js +27 -1
- package/dist/clients/lsp/index.js +550 -59
- package/dist/clients/lsp/server-strategies.js +19 -0
- package/dist/clients/lsp/server.js +174 -32
- package/dist/clients/lsp-budget.js +148 -0
- package/dist/clients/mcp/analyze.js +110 -1
- package/dist/clients/mcp/session.js +1 -0
- package/dist/clients/middle-man-analysis.js +260 -0
- package/dist/clients/module-report.js +333 -26
- package/dist/clients/ndjson-logger.js +24 -0
- package/dist/clients/opengrep-client.js +217 -0
- package/dist/clients/path-utils.js +65 -0
- package/dist/clients/persist-debounce.js +63 -0
- package/dist/clients/pipeline.js +83 -3
- package/dist/clients/project-diagnostics/extractors.js +50 -4
- 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 +7 -2
- package/dist/clients/quiet-window.js +223 -0
- package/dist/clients/read-expansion.js +2 -3
- package/dist/clients/read-guard-tool-lines.js +10 -0
- package/dist/clients/recent-touches.js +233 -0
- package/dist/clients/resource-sampler.js +254 -0
- package/dist/clients/review-graph/builder.js +265 -11
- package/dist/clients/review-graph/symbol-id.js +57 -0
- package/dist/clients/runtime-agent-end.js +51 -1
- package/dist/clients/runtime-coordinator.js +21 -0
- package/dist/clients/runtime-session.js +106 -47
- package/dist/clients/runtime-tool-result.js +46 -0
- package/dist/clients/runtime-turn.js +53 -11
- package/dist/clients/safe-spawn.js +48 -2
- package/dist/clients/sgconfig.js +230 -52
- package/dist/clients/source-filter.js +56 -34
- package/dist/clients/source-walker.js +66 -0
- package/dist/clients/startup-scan.js +37 -42
- package/dist/clients/subagent-mode.js +54 -20
- 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 +115 -0
- package/dist/clients/tui-fit.js +54 -0
- package/dist/clients/turn-summary-render.js +72 -0
- package/dist/clients/turn-summary.js +132 -0
- package/dist/clients/widget-state.js +88 -31
- package/dist/clients/word-index.js +296 -1
- package/dist/clients/write-ordering-guard.js +58 -0
- package/dist/clients/zizmor-config.js +27 -0
- package/dist/index.js +20060 -14142
- package/dist/mcp/build-staleness.js +123 -0
- package/dist/mcp/server.js +470 -60
- package/dist/tools/activate-tools.js +72 -0
- package/dist/tools/ast-dump.js +2 -8
- package/dist/tools/ast-grep-search.js +1 -1
- package/dist/tools/lens-diagnostics.js +317 -27
- package/dist/tools/lsp-diagnostics.js +617 -64
- package/dist/tools/module-report.js +32 -16
- package/dist/tools/symbol-search.js +110 -0
- package/docs/agent-tooling-improvement-plan.md +660 -0
- package/docs/agent-tools.md +129 -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/env_variables.md +10 -0
- package/docs/environment-variables.md +67 -0
- package/docs/fable.md +139 -0
- package/docs/features.md +338 -0
- package/docs/globalconfig.md +79 -0
- package/docs/inspiration_gograph.md +601 -0
- package/docs/inspiration_neovim.md +1795 -0
- package/docs/inspiration_neovim2.md +402 -0
- package/docs/inspiration_tree_sitter_rules.md +369 -0
- package/docs/inspiration_tree_sitter_rules_investigation.md +328 -0
- package/docs/inspiration_tree_sitter_rules_round2.md +470 -0
- package/docs/language-coverage.md +48 -0
- package/docs/lsp-bridge-analysis.md +444 -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/newinspiration.md +338 -0
- package/docs/servercapabilities.md +118 -0
- package/docs/subagent-compat.md +281 -0
- package/docs/tools.md +13 -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/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-c_sharp.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-dart.wasm +0 -0
- package/grammars/tree-sitter-elixir.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-lua.wasm +0 -0
- package/grammars/tree-sitter-ocaml.wasm +0 -0
- package/grammars/tree-sitter-php.wasm +0 -0
- package/grammars/tree-sitter-ruby.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/grammars/tree-sitter-toml.wasm +0 -0
- package/grammars/tree-sitter-vue.wasm +0 -0
- package/grammars/tree-sitter-zig.wasm +0 -0
- package/package.json +5 -1
- package/rules/ast-grep-rules/rule-tests/hardcoded-url-js-test.yml +1 -0
- package/rules/ast-grep-rules/rule-tests/no-typeof-undefined-js-test.yml +8 -0
- package/rules/ast-grep-rules/rule-tests/no-typeof-undefined-test.yml +8 -0
- package/rules/ast-grep-rules/rules/array-callback-return-js.yml +1 -1
- package/rules/ast-grep-rules/rules/hardcoded-url-js.yml +1 -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 +1 -1
- package/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +1 -1
- package/rules/ast-grep-rules/rules/no-typeof-undefined-js.yml +9 -7
- package/rules/ast-grep-rules/rules/no-typeof-undefined.yml +9 -7
- package/rules/ast-grep-rules/rules/weak-rsa-key-js.yml +1 -1
- package/skills/{ast-grep → pi-lens-ast-grep}/SKILL.md +4 -2
- package/skills/{lsp-navigation → pi-lens-lsp-navigation}/SKILL.md +1 -1
- package/skills/{write-ast-grep-rule → pi-lens-write-ast-grep-rule}/SKILL.md +1 -1
- package/skills/{write-tree-sitter-rule → pi-lens-write-tree-sitter-rule}/SKILL.md +1 -1
- package/dist/clients/production-readiness.js +0 -493
- package/dist/clients/tree-sitter-fixer.js +0 -127
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ pi-lens gives AI coding agents fast, language-aware feedback while they write/ed
|
|
|
16
16
|
- Agent-facing tools for LSP navigation/diagnostics, AST search/replace,
|
|
17
17
|
diagnostics state, and project intelligence
|
|
18
18
|
- Review-graph intelligence for supported languages via bundled tree-sitter WASMs
|
|
19
|
+
- Ranked identifier search (`symbol_search`) over an always-warm word index,
|
|
20
|
+
feeding the discovery funnel (symbol_search → module_report → read_symbol)
|
|
19
21
|
- Read-guard and edit-autopatch support to reduce bad edits
|
|
20
22
|
- Background security/dependency scans for opted-in projects
|
|
21
23
|
|
|
@@ -37,6 +39,8 @@ pi install git:github.com/apmantza/pi-lens
|
|
|
37
39
|
- [Usage guide](docs/usage.md) — lifecycle, tool behavior, MCP notes, and
|
|
38
40
|
troubleshooting
|
|
39
41
|
- [Features](docs/features.md) — detailed feature reference
|
|
42
|
+
- [Word index](docs/word-index.md) — identifier search (`symbol_search`) and
|
|
43
|
+
the discovery funnel
|
|
40
44
|
- [Tools and commands](docs/tools.md) — runtime flags and slash commands
|
|
41
45
|
- [Configuration](docs/globalconfig.md) — global and project config files
|
|
42
46
|
- [Environment variables](docs/env_variables.md) — common env vars and full
|
|
@@ -63,94 +67,109 @@ Thanks goes to these wonderful people:
|
|
|
63
67
|
<table>
|
|
64
68
|
<tbody>
|
|
65
69
|
<tr>
|
|
66
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wastedC"><img src="https://avatars.githubusercontent.com/u/917574?v=4" width="100px;" alt=""/><br /><sub><b>wastedC</b></sub></a><br /><a href="#code-wastedC" title="Code">💻</a> <a href="#ideas-wastedC" title="Ideas & Planning">🤔</a> <a href="#maintenance-wastedC" title="Maintenance">🚧</a> <a href="#review-wastedC" title="Reviewed Pull Requests">👀</a></td>
|
|
67
70
|
<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>
|
|
68
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/apps/dependabot"><img src="https://avatars.githubusercontent.com/in/29110?v=4" width="100px;" alt=""/><br /><sub><b>Dependabot</b></sub></a><br /><a href="#maintenance-dependabot[bot]" title="Maintenance">🚧</a></td>
|
|
69
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/silvanshade"><img src="https://avatars.githubusercontent.com/u/11022302?v=4" width="100px;" alt=""/><br /><sub><b>silvanshade</b></sub></a><br /><a href="#code-silvanshade" title="Code">💻</a></td>
|
|
70
71
|
<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>
|
|
71
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
72
|
+
<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>
|
|
73
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/silvanshade"><img src="https://avatars.githubusercontent.com/u/11022302?v=4" width="100px;" alt=""/><br /><sub><b>silvanshade</b></sub></a><br /><a href="#code-silvanshade" title="Code">💻</a></td>
|
|
72
74
|
<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
|
+
<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
|
+
<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><br />
|
|
78
|
+
<tr>
|
|
79
|
+
<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
|
+
<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>
|
|
81
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fabio-dee"><img src="https://avatars.githubusercontent.com/u/10808443?v=4" width="100px;" alt=""/><br /><sub><b>Fabio Dee</b></sub></a><br /><a href="#code-fabio-dee" title="Code">💻</a></td>
|
|
82
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/moj02090"><img src="https://avatars.githubusercontent.com/u/57255166?v=4" width="100px;" alt=""/><br /><sub><b>moj02090</b></sub></a><br /><a href="#code-moj02090" title="Code">💻</a></td>
|
|
83
|
+
<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
|
+
<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
|
+
<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>
|
|
73
86
|
</tr><br />
|
|
74
87
|
<tr>
|
|
75
|
-
<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>
|
|
76
88
|
<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>
|
|
77
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
78
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
79
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
80
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
81
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
89
|
+
<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>
|
|
90
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cmptr"><img src="https://avatars.githubusercontent.com/u/32746889?v=4" width="100px;" alt=""/><br /><sub><b>Aaron Bell</b></sub></a><br /><a href="#code-cmptr" title="Code">💻</a> <a href="#bug-cmptr" title="Bug reports">🐛</a></td>
|
|
91
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/StartupBros"><img src="https://avatars.githubusercontent.com/u/16693591?v=4" width="100px;" alt=""/><br /><sub><b>Will Mitchell</b></sub></a><br /><a href="#code-StartupBros" title="Code">💻</a></td>
|
|
92
|
+
<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
|
+
<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
|
+
<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>
|
|
82
95
|
</tr><br />
|
|
83
96
|
<tr>
|
|
84
97
|
<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>
|
|
85
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
86
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
87
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
98
|
+
<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>
|
|
99
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JayceFreeman"><img src="https://avatars.githubusercontent.com/u/92962110?v=4" width="100px;" alt=""/><br /><sub><b>JayceFreeman</b></sub></a><br /><a href="#code-JayceFreeman" title="Code">💻</a></td>
|
|
100
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bloodf"><img src="https://avatars.githubusercontent.com/u/1626923?v=4" width="100px;" alt=""/><br /><sub><b>Heitor Ramon Ribeiro</b></sub></a><br /><a href="#code-bloodf" title="Code">💻</a></td>
|
|
101
|
+
<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
|
+
<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>
|
|
88
103
|
<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>
|
|
89
|
-
<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>
|
|
90
|
-
<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>
|
|
91
104
|
</tr><br />
|
|
92
105
|
<tr>
|
|
93
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
94
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
106
|
+
<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
|
+
<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>
|
|
108
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jsmestad"><img src="https://avatars.githubusercontent.com/u/16150?v=4" width="100px;" alt=""/><br /><sub><b>Justin Smestad</b></sub></a><br /><a href="#code-jsmestad" title="Code">💻</a></td>
|
|
109
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/anasalsbey-glitch"><img src="https://avatars.githubusercontent.com/u/283609702?v=4" width="100px;" alt=""/><br /><sub><b>anasalsbey-glitch</b></sub></a><br /><a href="#code-anasalsbey-glitch" title="Code">💻</a> <a href="#bug-anasalsbey-glitch" title="Bug reports">🐛</a></td>
|
|
110
|
+
<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>
|
|
95
111
|
<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>
|
|
96
112
|
<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><br />
|
|
114
|
+
<tr>
|
|
97
115
|
<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>
|
|
98
116
|
<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>
|
|
99
117
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/grodingo"><img src="https://avatars.githubusercontent.com/u/244184972?v=4" width="100px;" alt=""/><br /><sub><b>Virgile</b></sub></a><br /><a href="#bug-grodingo" title="Bug reports">🐛</a></td>
|
|
100
|
-
</tr><br />
|
|
101
|
-
<tr>
|
|
102
118
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/finnvyrn"><img src="https://avatars.githubusercontent.com/u/90801772?v=4" width="100px;" alt=""/><br /><sub><b>Finn</b></sub></a><br /><a href="#ideas-finnvyrn" title="Ideas & Planning">🤔</a></td>
|
|
103
119
|
<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>
|
|
104
120
|
<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>
|
|
105
121
|
<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><br />
|
|
123
|
+
<tr>
|
|
106
124
|
<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>
|
|
107
125
|
<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>
|
|
108
126
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tackleberrybey"><img src="https://avatars.githubusercontent.com/u/156954032?v=4" width="100px;" alt=""/><br /><sub><b>tackleberrybey</b></sub></a><br /><a href="#bug-tackleberrybey" title="Bug reports">🐛</a></td>
|
|
109
|
-
</tr><br />
|
|
110
|
-
<tr>
|
|
111
127
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/TaterDoge"><img src="https://avatars.githubusercontent.com/u/121467933?v=4" width="100px;" alt=""/><br /><sub><b>Mariann Abshire</b></sub></a><br /><a href="#bug-TaterDoge" title="Bug reports">🐛</a></td>
|
|
112
128
|
<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>
|
|
113
129
|
<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>
|
|
114
130
|
<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><br />
|
|
132
|
+
<tr>
|
|
115
133
|
<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>
|
|
116
134
|
<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>
|
|
117
135
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/av1155"><img src="https://avatars.githubusercontent.com/u/117413846?v=4" width="100px;" alt=""/><br /><sub><b>Andrea Arturo Venti Fuentes</b></sub></a><br /><a href="#bug-av1155" title="Bug reports">🐛</a></td>
|
|
118
|
-
</tr><br />
|
|
119
|
-
<tr>
|
|
120
136
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/dacec354"><img src="https://avatars.githubusercontent.com/u/90093629?v=4" width="100px;" alt=""/><br /><sub><b>dacec354</b></sub></a><br /><a href="#bug-dacec354" title="Bug reports">🐛</a></td>
|
|
121
|
-
<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>
|
|
122
137
|
<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>
|
|
123
138
|
<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>
|
|
124
139
|
<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>
|
|
125
|
-
<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>
|
|
126
|
-
<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>
|
|
127
140
|
</tr><br />
|
|
128
141
|
<tr>
|
|
142
|
+
<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
|
+
<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>
|
|
129
144
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/JohannesKlauss"><img src="https://avatars.githubusercontent.com/u/6214415?v=4" width="100px;" alt=""/><br /><sub><b>Johannes Klauss</b></sub></a><br /><a href="#ideas-JohannesKlauss" title="Ideas & Planning">🤔</a></td>
|
|
130
145
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tan-yong-sheng"><img src="https://avatars.githubusercontent.com/u/64836390?v=4" width="100px;" alt=""/><br /><sub><b>Tan Yong Sheng</b></sub></a><br /><a href="#ideas-tan-yong-sheng" title="Ideas & Planning">🤔</a></td>
|
|
131
146
|
<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>
|
|
132
147
|
<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>
|
|
133
148
|
<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>
|
|
134
|
-
<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>
|
|
135
|
-
<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>
|
|
136
149
|
</tr><br />
|
|
137
150
|
<tr>
|
|
151
|
+
<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
|
+
<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>
|
|
138
153
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/quantfiction"><img src="https://avatars.githubusercontent.com/u/49965454?v=4" width="100px;" alt=""/><br /><sub><b>quantfiction</b></sub></a><br /><a href="#bug-quantfiction" title="Bug reports">🐛</a></td>
|
|
139
154
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Artawower"><img src="https://avatars.githubusercontent.com/u/16963833?v=4" width="100px;" alt=""/><br /><sub><b>Art</b></sub></a><br /><a href="#bug-Artawower" title="Bug reports">🐛</a></td>
|
|
140
155
|
<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>
|
|
141
156
|
<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>
|
|
142
157
|
<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>
|
|
143
|
-
<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>
|
|
144
|
-
<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>
|
|
145
158
|
</tr><br />
|
|
146
159
|
<tr>
|
|
160
|
+
<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
|
+
<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>
|
|
147
162
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/smaharnav"><img src="https://avatars.githubusercontent.com/u/263328627?v=4" width="100px;" alt=""/><br /><sub><b>smaharnav</b></sub></a><br /><a href="#bug-smaharnav" title="Bug reports">🐛</a></td>
|
|
148
163
|
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MzaGuille"><img src="https://avatars.githubusercontent.com/u/151482698?v=4" width="100px;" alt=""/><br /><sub><b>Mza.Guille</b></sub></a><br /><a href="#bug-MzaGuille" title="Bug reports">🐛</a></td>
|
|
149
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cmptr"><img src="https://avatars.githubusercontent.com/u/32746889?v=4" width="100px;" alt=""/><br /><sub><b>Aaron Bell</b></sub></a><br /><a href="#code-cmptr" title="Code">💻</a> <a href="#bug-cmptr" title="Bug reports">🐛</a></td>
|
|
150
164
|
<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>
|
|
151
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
152
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/
|
|
153
|
-
|
|
165
|
+
<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
|
+
<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><br />
|
|
168
|
+
<tr>
|
|
169
|
+
<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
|
+
<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
|
+
<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>
|
|
172
|
+
<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>
|
|
154
173
|
</tr>
|
|
155
174
|
</tbody>
|
|
156
175
|
</table>
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { logLatency } from "./latency-logger.js";
|
|
2
|
+
import { normalizeMapKey } from "./path-utils.js";
|
|
3
|
+
const BUS_FILES_TOUCHED_EVENT = "pilens:files:touched";
|
|
4
|
+
const MAX_NAMES_SHOWN = 5;
|
|
5
|
+
// Module-level accumulator: one process/session, so a plain map keyed via
|
|
6
|
+
// normalizeMapKey (house style — every map/set key in this module MUST go
|
|
7
|
+
// through it; a hand-rolled replace() is the exact trap that cost two red CI
|
|
8
|
+
// rounds on #458's reconcile tests, PR #491) is sufficient. Cleared ONLY
|
|
9
|
+
// inside consumeAgentNudge() (i.e. only at actual injection into a `context`
|
|
10
|
+
// call) — deliberately NOT tied to turn_start/agent_end/agent_settled, so
|
|
11
|
+
// entries accumulated during run A's turn_end survive until run B's first
|
|
12
|
+
// `context` call in the same session (the cross-run `git status` case).
|
|
13
|
+
const _touched = new Map();
|
|
14
|
+
// Count of bus-reported paths dropped by the relevance filter (file never
|
|
15
|
+
// read/edited this session) since the last consume — drained alongside the
|
|
16
|
+
// accumulator so the `agent_nudge` phase can report how much the filter
|
|
17
|
+
// actually suppresses, which is the metric that validates (or indicts) the
|
|
18
|
+
// "only nudge for files the session saw" rule.
|
|
19
|
+
let _relevanceFilteredCount = 0;
|
|
20
|
+
/** Test-only: clear accumulator state between test files/cases. */
|
|
21
|
+
export function _resetAgentNudgeForTests() {
|
|
22
|
+
_touched.clear();
|
|
23
|
+
_relevanceFilteredCount = 0;
|
|
24
|
+
_enabledCache = undefined;
|
|
25
|
+
}
|
|
26
|
+
// --- Kill switch (lazy, memoized — house style per clients/quiet-window.ts) ---
|
|
27
|
+
let _enabledCache;
|
|
28
|
+
/** `PI_LENS_AGENT_NUDGE=0` disables accumulation and injection outright. */
|
|
29
|
+
export function isAgentNudgeEnabled() {
|
|
30
|
+
if (_enabledCache === undefined) {
|
|
31
|
+
_enabledCache = process.env.PI_LENS_AGENT_NUDGE !== "0";
|
|
32
|
+
}
|
|
33
|
+
return _enabledCache;
|
|
34
|
+
}
|
|
35
|
+
function isValidPayload(data) {
|
|
36
|
+
if (!data || typeof data !== "object")
|
|
37
|
+
return false;
|
|
38
|
+
const p = data;
|
|
39
|
+
return (p.v === 1 &&
|
|
40
|
+
p.source === "pi-lens" &&
|
|
41
|
+
(p.reason === "autofix" || p.reason === "format") &&
|
|
42
|
+
Array.isArray(p.paths));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Record a `pilens:files:touched` event into the accumulator, filtered to
|
|
46
|
+
* files the session has actually read or edited (read-guard is the source of
|
|
47
|
+
* truth — `getReadHistory`/`getEditHistory` both key internally via
|
|
48
|
+
* `normalizeFilePath`, so either separator form on the incoming bus payload
|
|
49
|
+
* or the guard's stored records resolves to the same record regardless of
|
|
50
|
+
* which form was recorded first).
|
|
51
|
+
*/
|
|
52
|
+
function recordTouchedEvent(payload, getReadGuard) {
|
|
53
|
+
const readGuard = getReadGuard();
|
|
54
|
+
if (!readGuard)
|
|
55
|
+
return;
|
|
56
|
+
for (const rawPath of payload.paths) {
|
|
57
|
+
const isRelevant = readGuard.getReadHistory(rawPath).length > 0 ||
|
|
58
|
+
readGuard.getEditHistory(rawPath).length > 0;
|
|
59
|
+
if (!isRelevant) {
|
|
60
|
+
_relevanceFilteredCount++;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const mapKey = normalizeMapKey(rawPath);
|
|
64
|
+
const existing = _touched.get(mapKey);
|
|
65
|
+
if (existing) {
|
|
66
|
+
existing.reasons.add(payload.reason);
|
|
67
|
+
// "local" is sticky — see AccumulatedFileOrigin doc. A file already
|
|
68
|
+
// recorded via the cross-process feed, now also reported by this
|
|
69
|
+
// session's own bus, upgrades to "local".
|
|
70
|
+
existing.origin = "local";
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
_touched.set(mapKey, {
|
|
74
|
+
displayPath: rawPath,
|
|
75
|
+
reasons: new Set([payload.reason]),
|
|
76
|
+
origin: "local",
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Feed entries read from the cross-process `recent-touches.json` record
|
|
83
|
+
* (#492, clients/recent-touches.ts) into the SAME accumulator #485 uses for
|
|
84
|
+
* in-process bus events — one accumulator, one `consumeAgentNudge` call, one
|
|
85
|
+
* batched context message regardless of how many files came from which
|
|
86
|
+
* channel.
|
|
87
|
+
*
|
|
88
|
+
* Relevance filtering differs by call site (#492 point 6) and is therefore
|
|
89
|
+
* the CALLER's responsibility, not this function's:
|
|
90
|
+
* - parent at turn_start: read-guard history FIRST (a parent usually has
|
|
91
|
+
* one), falling back to recency-only for files it hasn't read (a parent
|
|
92
|
+
* about to `git commit` needs attribution even for unread files);
|
|
93
|
+
* - child at session_start: recency + file-existence only (no read
|
|
94
|
+
* history exists yet this early).
|
|
95
|
+
* `readCrossProcessTouchesForTurnStart` / `...ForSessionStart` in
|
|
96
|
+
* recent-touches.ts already apply their own recency/existence/self-pid
|
|
97
|
+
* filtering before entries reach here — this function does not re-derive
|
|
98
|
+
* relevance, it only merges into the accumulator and marks provenance.
|
|
99
|
+
*
|
|
100
|
+
* Self-exclusion (an entry this process itself published never nudges
|
|
101
|
+
* itself) and path+ts dedup across repeated reads of the record are both
|
|
102
|
+
* handled upstream in recent-touches.ts (pid filter + last-consumed cursor),
|
|
103
|
+
* so entries reaching this function are already the "new, foreign" set.
|
|
104
|
+
*/
|
|
105
|
+
export function recordCrossProcessTouches(entries) {
|
|
106
|
+
if (!isAgentNudgeEnabled())
|
|
107
|
+
return;
|
|
108
|
+
for (const entry of entries) {
|
|
109
|
+
const mapKey = normalizeMapKey(entry.path);
|
|
110
|
+
const existing = _touched.get(mapKey);
|
|
111
|
+
if (existing) {
|
|
112
|
+
existing.reasons.add(entry.reason);
|
|
113
|
+
// "local" is sticky (see AccumulatedFileOrigin) — never downgrade an
|
|
114
|
+
// already-local entry back to cross-process.
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
_touched.set(mapKey, {
|
|
118
|
+
displayPath: entry.path,
|
|
119
|
+
reasons: new Set([entry.reason]),
|
|
120
|
+
origin: "cross-process",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Subscribe to `pilens:files:touched` on pi's shared event bus. Called once
|
|
127
|
+
* at extension factory time from index.ts, mirroring `wireBusEmitter`'s
|
|
128
|
+
* placement (clients/bus-publish.ts). No-ops silently when `pi.events` or
|
|
129
|
+
* `.on` is unavailable (older pi host) — never throws.
|
|
130
|
+
*/
|
|
131
|
+
export function wireAgentNudgeSubscriber(args) {
|
|
132
|
+
const { events, getReadGuard, dbg } = args;
|
|
133
|
+
if (!events?.on)
|
|
134
|
+
return;
|
|
135
|
+
try {
|
|
136
|
+
events.on(BUS_FILES_TOUCHED_EVENT, (data) => {
|
|
137
|
+
if (!isAgentNudgeEnabled())
|
|
138
|
+
return;
|
|
139
|
+
if (!isValidPayload(data))
|
|
140
|
+
return;
|
|
141
|
+
try {
|
|
142
|
+
recordTouchedEvent(data, getReadGuard);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
dbg?.(`agent-nudge: failed to record touched event: ${err}`);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
dbg?.(`agent-nudge: subscribe failed (older pi host?): ${err}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Consume the accumulated touched-file set and produce (at most) one context
|
|
155
|
+
* message, e.g.:
|
|
156
|
+
* "pi-lens: 2 file(s) were autoformatted after your last turn: a.ts, b.ts —
|
|
157
|
+
* working-tree changes to these are expected; re-read before editing."
|
|
158
|
+
* The provenance framing ("pi-lens ... expected") matters: the primary pain
|
|
159
|
+
* case is an agent running `git status` (often at the START of a brand-new
|
|
160
|
+
* run/session, not just mid-run) and burning turns investigating diffs it
|
|
161
|
+
* did not knowingly make. Naming pi-lens as the source lets the agent act
|
|
162
|
+
* (re-read, proceed) instead of investigating.
|
|
163
|
+
*
|
|
164
|
+
* #492: attribution is three-way by the batch's origin mix (see
|
|
165
|
+
* AccumulatedFileOrigin) — still ONE message total (never split local vs.
|
|
166
|
+
* cross-process into two separate injections; the agent gets one coherent
|
|
167
|
+
* picture of everything unexplained in the working tree), but the wording
|
|
168
|
+
* must never assign a LOCAL file to another instance:
|
|
169
|
+
* - all local → "after your last turn" (the original #485 wording,
|
|
170
|
+
* unchanged — verified by the pre-existing #485
|
|
171
|
+
* tests);
|
|
172
|
+
* - all cross-process → "by another pi-lens instance (e.g. a subagent's)";
|
|
173
|
+
* - mixed → "after your last turn (N of them by another
|
|
174
|
+
* pi-lens instance)" — the base framing stays local
|
|
175
|
+
* and the cross-process portion is counted out
|
|
176
|
+
* precisely, so no local file is ever misattributed
|
|
177
|
+
* to another instance.
|
|
178
|
+
*
|
|
179
|
+
* Clears the accumulator ONLY here, on actual injection — never on
|
|
180
|
+
* agent_end/agent_settled/turn_start. Files formatted at the last turn_end of
|
|
181
|
+
* a PREVIOUS run must still nudge at the first turn of the NEXT run in the
|
|
182
|
+
* same session: this function is invoked from the `context` extension event
|
|
183
|
+
* (index.ts), which fires before every provider/LLM call — including the
|
|
184
|
+
* very first call of a fresh `agent_start` — so the accumulator surviving
|
|
185
|
+
* across run boundaries is exactly what makes that cross-run delivery work.
|
|
186
|
+
* Empty accumulator ⇒ returns undefined ⇒ zero bytes injected.
|
|
187
|
+
*/
|
|
188
|
+
export function consumeAgentNudge(dbg) {
|
|
189
|
+
const entries = Array.from(_touched.values());
|
|
190
|
+
_touched.clear();
|
|
191
|
+
const filesFiltered = _relevanceFilteredCount;
|
|
192
|
+
_relevanceFilteredCount = 0;
|
|
193
|
+
if (!isAgentNudgeEnabled())
|
|
194
|
+
return undefined;
|
|
195
|
+
if (entries.length === 0)
|
|
196
|
+
return undefined;
|
|
197
|
+
try {
|
|
198
|
+
const filesTotal = entries.length;
|
|
199
|
+
const shown = entries.slice(0, MAX_NAMES_SHOWN);
|
|
200
|
+
const remaining = filesTotal - shown.length;
|
|
201
|
+
// Determine a single verb covering every reason seen across all
|
|
202
|
+
// accumulated files (not just the shown subset) — most turns will have
|
|
203
|
+
// a single uniform reason, so keep that common case terse; a mix of
|
|
204
|
+
// autofix + format across the batch falls back to a combined verb.
|
|
205
|
+
const allReasons = new Set();
|
|
206
|
+
for (const e of entries) {
|
|
207
|
+
for (const r of e.reasons)
|
|
208
|
+
allReasons.add(r);
|
|
209
|
+
}
|
|
210
|
+
const verbLabel = allReasons.size > 1
|
|
211
|
+
? "autofixed/reformatted"
|
|
212
|
+
: allReasons.has("format")
|
|
213
|
+
? "reformatted"
|
|
214
|
+
: "autofixed";
|
|
215
|
+
const names = shown.map((e) => e.displayPath);
|
|
216
|
+
const nameList = remaining > 0
|
|
217
|
+
? `${names.join(", ")}, and ${remaining} more`
|
|
218
|
+
: names.join(", ");
|
|
219
|
+
const crossProcessCount = entries.filter((e) => e.origin === "cross-process").length;
|
|
220
|
+
const localCount = filesTotal - crossProcessCount;
|
|
221
|
+
// Three-way attribution (see the function doc): never assign a local
|
|
222
|
+
// file to another instance — a mixed batch keeps the local base framing
|
|
223
|
+
// and calls out the cross-process portion by exact count.
|
|
224
|
+
const attribution = localCount === 0
|
|
225
|
+
? "by another pi-lens instance (e.g. a subagent's)"
|
|
226
|
+
: crossProcessCount === 0
|
|
227
|
+
? "after your last turn"
|
|
228
|
+
: `after your last turn (${crossProcessCount} of them by another pi-lens instance)`;
|
|
229
|
+
const message = `pi-lens: ${filesTotal} file(s) were ${verbLabel} ${attribution}: ${nameList} — working-tree changes to these are expected; re-read before editing.`;
|
|
230
|
+
logLatency({
|
|
231
|
+
type: "phase",
|
|
232
|
+
filePath: "<pi-lens>",
|
|
233
|
+
phase: "agent_nudge",
|
|
234
|
+
durationMs: 0,
|
|
235
|
+
metadata: {
|
|
236
|
+
filesTotal,
|
|
237
|
+
filesShown: shown.length,
|
|
238
|
+
// Relevance-filter drops since the last consume (files the session
|
|
239
|
+
// never read/edited) — NOT the display overflow, which is
|
|
240
|
+
// filesTotal - filesShown.
|
|
241
|
+
filesFiltered,
|
|
242
|
+
reasonMix: Array.from(allReasons),
|
|
243
|
+
// #492: origin mix so cross-process pickup rate is observable
|
|
244
|
+
// alongside the existing relevance-filter metric.
|
|
245
|
+
originLocal: localCount,
|
|
246
|
+
originCrossProcess: crossProcessCount,
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
return {
|
|
250
|
+
messages: [
|
|
251
|
+
{
|
|
252
|
+
role: "user",
|
|
253
|
+
content: `[pi-lens automated context — not a user request] ${message}`,
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
dbg?.(`agent-nudge: consume failed: ${err}`);
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* Docs: https://biomejs.dev/
|
|
9
9
|
*/
|
|
10
10
|
import * as fs from "node:fs";
|
|
11
|
-
import * as os from "node:os";
|
|
12
11
|
import * as path from "node:path";
|
|
13
12
|
import { isFileKind } from "./file-kinds.js";
|
|
13
|
+
import { getGlobalPiLensDir } from "./file-utils.js";
|
|
14
14
|
import { findGlobalBinary } from "./package-manager.js";
|
|
15
15
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
16
16
|
// --- Client ---
|
|
@@ -56,7 +56,7 @@ export class BiomeClient {
|
|
|
56
56
|
// the tool is already installed but not in the project's node_modules.
|
|
57
57
|
// On Windows prefer .cmd (native batch) over the sh wrapper — 2x faster.
|
|
58
58
|
const isWin = process.platform === "win32";
|
|
59
|
-
const piLensBin = path.join(
|
|
59
|
+
const piLensBin = path.join(getGlobalPiLensDir(), "tools", "node_modules", ".bin");
|
|
60
60
|
const candidates = isWin
|
|
61
61
|
? [
|
|
62
62
|
path.join(resolveCwd, "node_modules", ".bin", "biome.cmd"),
|
|
@@ -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,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent NDJSON trace of `pi.events` bus publish attempts
|
|
3
|
+
* (`pilens:files:touched` #482 / `pilens:diagnostics` #502).
|
|
4
|
+
*
|
|
5
|
+
* Both producers (clients/bus-publish.ts, clients/diagnostics-publish.ts) are
|
|
6
|
+
* fire-and-forget: on failure or on a structural no-op (never wired, kill
|
|
7
|
+
* switch off) they only invoke an optional `dbg` callback, which varies by
|
|
8
|
+
* host and is a documented no-op in the MCP host (clients/mcp/session.ts's
|
|
9
|
+
* `dbg: noop`). That leaves bus-publish outcomes invisible in exactly the
|
|
10
|
+
* context where they matter most — same failure shape as the #544 MCP
|
|
11
|
+
* session_start incident this repo already fixed once.
|
|
12
|
+
*
|
|
13
|
+
* This module gives bus events the same durable trace every other pi-lens
|
|
14
|
+
* subsystem already has (latency.log, cascade.log, read-guard.log, ...) —
|
|
15
|
+
* see clients/latency-logger.ts for the house pattern this mirrors exactly:
|
|
16
|
+
* one shared `createNdjsonLogger` writer, `isTestMode()` no-op guard,
|
|
17
|
+
* `getBusEventsLogPath()` for testability.
|
|
18
|
+
*
|
|
19
|
+
* Logging volume: `emitted` and `emit_failed` are logged on every call —
|
|
20
|
+
* they're the two outcomes an operator actually needs a per-event trace for.
|
|
21
|
+
* `skipped_unwired` and `skipped_disabled` are process-lifetime-static facts
|
|
22
|
+
* (wiring happens once at extension factory time; the kill switch is an env
|
|
23
|
+
* var read once at startup) — logging them on every publish attempt would
|
|
24
|
+
* spam one identical line per write batch for an entire session with zero
|
|
25
|
+
* new information after the first. Both are gated log-once-per-process, the
|
|
26
|
+
* same `hasLoggedFailure` shape the producers already use for emit_failed.
|
|
27
|
+
* The empty-batch branch (`paths.length === 0` / `files.length === 0`) is
|
|
28
|
+
* NOT logged at all: every call site already guards against invoking these
|
|
29
|
+
* functions with nothing to report (see clients/pipeline.ts,
|
|
30
|
+
* clients/runtime-agent-end.ts), so it's a normal, frequent no-op rather
|
|
31
|
+
* than a real event worth a log line.
|
|
32
|
+
*/
|
|
33
|
+
import * as path from "node:path";
|
|
34
|
+
import { isTestMode } from "./env-utils.js";
|
|
35
|
+
import { getGlobalPiLensDir } from "./file-utils.js";
|
|
36
|
+
import { createNdjsonLogger } from "./ndjson-logger.js";
|
|
37
|
+
const BUS_EVENTS_LOG_FILE = path.join(getGlobalPiLensDir(), "bus-events.log");
|
|
38
|
+
const writer = createNdjsonLogger({ filePath: BUS_EVENTS_LOG_FILE });
|
|
39
|
+
export function logBusEvent(entry) {
|
|
40
|
+
if (isTestMode()) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
writer.log({ ts: new Date().toISOString(), ...entry });
|
|
44
|
+
}
|
|
45
|
+
export function getBusEventsLogPath() {
|
|
46
|
+
return BUS_EVENTS_LOG_FILE;
|
|
47
|
+
}
|
|
48
|
+
/** Resolve once all enqueued bus-event writes are on disk (tests/shutdown). */
|
|
49
|
+
export function flushBusEventsLog() {
|
|
50
|
+
return writer.flush();
|
|
51
|
+
}
|