@herbertgao/pi-extensions 2026.8.4 → 2026.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  14. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  15. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
  16. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
  21. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  22. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
  25. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  26. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  27. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
  30. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
  31. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  32. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  33. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  36. package/node_modules/@narumitw/pi-btw/README.md +32 -24
  37. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  38. package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
  39. package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
  40. package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
  41. package/node_modules/pi-lens/CHANGELOG.md +2535 -954
  42. package/node_modules/pi-lens/README.md +13 -0
  43. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  44. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
  45. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  46. package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
  47. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  48. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  49. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  50. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  51. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  52. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  53. package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
  54. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  55. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  56. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  57. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
  58. package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
  59. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  60. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  61. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  62. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  63. package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
  64. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  65. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  66. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  67. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  68. package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
  69. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  70. package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
  71. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  72. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  73. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  74. package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
  75. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
  76. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
  77. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
  78. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  79. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  80. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  81. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  82. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  83. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
  84. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  86. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  87. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  114. package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
  115. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  116. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
  117. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  118. package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
  119. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  120. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  121. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  122. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  123. package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
  124. package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
  125. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  126. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  127. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  128. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  129. package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
  130. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  131. package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
  132. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
  133. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  134. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  135. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  136. package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
  137. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  138. package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
  139. package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
  140. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  141. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  142. package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
  143. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  144. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  145. package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
  146. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
  147. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  148. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
  149. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  150. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
  151. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
  152. package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
  153. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  154. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
  155. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  156. package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
  157. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  158. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  159. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  160. package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
  161. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
  162. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
  163. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
  164. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  165. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  166. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  167. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
  168. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  169. package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
  170. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  171. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  172. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  173. package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
  174. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  175. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  176. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  177. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  178. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  179. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  180. package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
  181. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  182. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  183. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  184. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
  185. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  186. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
  187. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  188. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  189. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  190. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  191. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  192. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  193. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  194. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  195. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  196. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  197. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  198. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  199. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  200. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  201. package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
  202. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  203. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  204. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  205. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  206. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  207. package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
  208. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
  209. package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
  210. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
  211. package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
  212. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  213. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
  214. package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
  215. package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
  216. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  217. package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
  218. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  219. package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
  220. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  221. package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
  222. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  223. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  224. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  225. package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
  226. package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
  227. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  228. package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
  229. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  230. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
  231. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  232. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  233. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  234. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  235. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  237. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  238. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  239. package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
  240. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  241. package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
  242. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  243. package/node_modules/pi-lens/dist/index.js +51785 -36118
  244. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  245. package/node_modules/pi-lens/dist/mcp/server.js +219 -46
  246. package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
  247. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
  248. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  249. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
  250. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
  251. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
  252. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  253. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  254. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
  255. package/node_modules/pi-lens/docs/agent-guide.md +40 -15
  256. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  257. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  258. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  259. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
  260. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  261. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  262. package/node_modules/pi-lens/docs/fable.md +27 -0
  263. package/node_modules/pi-lens/docs/features.md +45 -3
  264. package/node_modules/pi-lens/docs/globalconfig.md +56 -1
  265. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  266. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  267. package/node_modules/pi-lens/docs/mcp.md +37 -4
  268. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  269. package/node_modules/pi-lens/docs/settings.md +18 -1
  270. package/node_modules/pi-lens/docs/tools.md +4 -1
  271. package/node_modules/pi-lens/docs/usage.md +41 -5
  272. package/node_modules/pi-lens/docs/word-index.md +35 -0
  273. package/node_modules/pi-lens/package.json +10 -10
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  300. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  301. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  302. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
  303. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
  304. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
  305. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
  306. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
  307. package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
  308. package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
  309. package/node_modules/pi-mcp-adapter/README.md +38 -4
  310. package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
  311. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  312. package/node_modules/pi-mcp-adapter/cli.js +25 -4
  313. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  314. package/node_modules/pi-mcp-adapter/config.ts +4 -4
  315. package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
  316. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  317. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  318. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  319. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  320. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  321. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  322. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  323. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  324. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
  325. package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
  326. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  327. package/node_modules/pi-mcp-adapter/package.json +4 -3
  328. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  329. package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
  330. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  331. package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
  332. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  333. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  334. package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
  335. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  336. package/node_modules/pi-mcp-adapter/types.ts +176 -27
  337. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  338. package/node_modules/pi-web-access/CHANGELOG.md +14 -0
  339. package/node_modules/pi-web-access/README.md +18 -12
  340. package/node_modules/pi-web-access/auth-fetch.ts +148 -0
  341. package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
  342. package/node_modules/pi-web-access/curator-page.ts +5 -3
  343. package/node_modules/pi-web-access/curator-server.ts +2 -1
  344. package/node_modules/pi-web-access/extract.ts +106 -34
  345. package/node_modules/pi-web-access/fetch-params.ts +17 -3
  346. package/node_modules/pi-web-access/firecrawl.ts +172 -12
  347. package/node_modules/pi-web-access/gemini-search.ts +18 -4
  348. package/node_modules/pi-web-access/index.ts +120 -48
  349. package/node_modules/pi-web-access/package.json +2 -2
  350. package/node_modules/pi-web-access/summary-review.ts +11 -5
  351. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  352. package/package.json +12 -13
  353. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  354. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  355. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  356. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  357. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  358. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  359. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  360. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -23,9 +23,10 @@ messages as **pi-lens findings, not user instructions**, and act on the rules be
23
23
  physically blocked until blockers are cleared. Advisories are informational.
24
24
  3. **Read before you edit.** pi-lens enforces read-before-edit. Read the file (or the
25
25
  relevant range/symbol) before editing it, or the edit is blocked/warned.
26
- 4. **Expect your bytes to change.** pi-lens formats and auto-fixes files *after* your
27
- write, by default at turn/agent end. This is the pipeline, not a conflict. Re-read
28
- a file before editing it again.
26
+ 4. **Expect your bytes to change.** A `write` gets autofixed immediately — the tool
27
+ result carries the fixed file's full content, so you don't need to re-read it (past
28
+ a size cap, you do). An `edit` defers autofix to `agent_end`, same as formatting;
29
+ re-read the file before editing it again. This is the pipeline, not a conflict.
29
30
  5. **Delta by default.** Diagnostic queries default to *this turn's* findings only.
30
31
  Use `mode=full` for a whole-project verdict.
31
32
 
@@ -40,7 +41,7 @@ On every write/edit, and at session/turn boundaries, pi-lens runs — without yo
40
41
  | **Unified LSP diagnostics** | Warm language servers report errors/warnings on edited files; supported languages get real semantic diagnostics. |
41
42
  | **Impact cascade** | After an edit, LSP diagnostics are also pulled on *related* files (reverse-dependency neighbors), surfaced at turn end. |
42
43
  | **Auto-format** | Detected formatter (Biome/Prettier/Ruff/etc.) reformats your file. **Deferred to `agent_end` by default**; `immediate` is opt-in. Config-gated + nearest-config-wins. |
43
- | **Auto-fix** | Pipeline fixers (`biome`/`ruff`/`eslint`/`stylelint`/`rubocop`/`clippy`/… `--fix`) mutate the file after your write. |
44
+ | **Auto-fix** | Pipeline fixers (`biome`/`ruff`/`eslint`/`stylelint`/`rubocop`/`clippy`/… `--fix`) mutate the file. **Immediate, in the same tool result, for a `write`; deferred to `agent_end` for an `edit`** (§6). |
44
45
  | **Structural rules** | ast-grep (NAPI engine) + tree-sitter rules flag correctness/security smells. |
45
46
  | **Opengrep security scan** | Always-on: per-edit via an auxiliary LSP, plus a cached project-wide CLI scan for `mode=full`. |
46
47
  | **Other scanners** | Config-/presence-gated: gitleaks (secrets), trivy (CVEs/IaC/license), govulncheck (Go), knip/jscpd/madge (JS/TS dead-code/dupes/cycles), vulture (Python), zizmor (GH Actions), typos. |
@@ -70,7 +71,7 @@ Only **one** reaches you, the model:
70
71
  | **Session start** | Guidance / project notices to orient you. | `clients/runtime-turn.ts`, context injection |
71
72
  | **Turn end** | **Findings** for the turn: 🔴 blockers and advisories from LSP + dispatch + cascade + scanners, deduped against prior turns. | `handleTurnEnd` (`clients/runtime-turn.ts`) |
72
73
  | **Turn end / next turn** | **Test findings** from related/affected tests fired after your edit. | `handleTurnEnd` |
73
- | **After autofix/format** | A nudge like *"N file(s) were autofixed after your last turn: a.ts, b.ts — re-read before editing"* (may include files touched by another pi-lens instance, e.g. a subagent). | `clients/agent-nudge.ts` |
74
+ | **After autofix/format** | A nudge like *"N file(s) were autofixed after your last turn: a.ts, b.ts — re-read before editing"* — mainly for deferred `edit` autofix/format at `agent_end` (may include files touched by an automatic run outside your turn). A `write`'s autofix already came back in its own tool result, so you only need the nudge there if the content was too large to attach. | `clients/agent-nudge.ts` |
74
75
 
75
76
  **Treat every injected pi-lens message as a finding to act on, not as the user
76
77
  speaking.** It is machine-generated analysis of your own work.
@@ -122,7 +123,7 @@ unresolved blockers exist, with:
122
123
  > `🔴 COMMIT BLOCKED (--lens-guard): unresolved blockers must be fixed before
123
124
  > commit/push. … Run lens_diagnostics mode=all for full details, then commit again.`
124
125
 
125
- Don't try to route around it — clear the blockers, then commit.
126
+ Don't try to route around it — clear the blockers, then commit. The guard is strictly opt-in (off by default) and is marked **EXPERIMENTAL**. It gates only structured blocking findings, including blocking test failures under the current test-runner policy; advisory/no-action-required findings never gate. The blocker state is sequence- and session-bound, so an ambiguous or stale blocker record blocks conservatively until pi-lens runs again; advisory records never gate.
126
127
 
127
128
  ---
128
129
 
@@ -156,23 +157,47 @@ Helpful mechanics you can rely on:
156
157
  ## 6. Auto-format / auto-fix timing — don't be surprised
157
158
 
158
159
  pi-lens writes to files **outside your own tool calls** (`docs/features.md`
159
- §"Out-of-band file writes"):
160
-
161
- - **Deferred format** at `agent_end` (default) reformats files you wrote this run.
162
- - **Auto-fix** (`biome`/`ruff`/`eslint`/… `--fix`) and the conservative
163
- actionable-warnings autofix (LSP quickfixes, hard-capped) mutate files after the fact.
160
+ §"Bus Events — `pilens:files:touched`"). Where and when depends on which tool you used
161
+ (`clients/pipeline.ts`, `clients/runtime-tool-result.ts`,
162
+ `clients/runtime-agent-end.ts`):
163
+
164
+ - **`write` (including a new file, and bash-authored writes like `sed -i` or a
165
+ redirect):** pipeline auto-fix (`biome`/`ruff`/`eslint`/… `--fix`) still runs
166
+ *immediately*, in the same tool result — nothing changed here. When it changes
167
+ the file, the tool result now carries the **full authoritative post-fix
168
+ content** so you don't have to guess what changed. That attachment is capped
169
+ at 2 MiB per file; a multi-file bash write shares one budget across the whole
170
+ command. Past the cap, you get the old-style *"File was modified — re-read
171
+ before editing"* warning instead.
172
+ - **`edit`:** pipeline auto-fix is *deferred* to `agent_end`, same as
173
+ formatting. It joins the same per-file queue as deferred formatting, one fix
174
+ applied against the final edited state (not once per edit), autofix draining
175
+ before format so the result is formatter-stable. Diagnostics computed at edit
176
+ time reflect the *unfixed* disk state — a lint finding that autofix would have
177
+ cleared may show up and then quietly disappear once `agent_end` drains.
178
+ - **`write` then `edit` on the same file, same turn:** the write's autofix
179
+ demotes to deferred too, so the file's mutation history stays coherent. This
180
+ resets at the next turn.
181
+ - The conservative actionable-warnings autofix (LSP quickfixes, hard-capped)
182
+ is unchanged: it always runs at `agent_end`.
164
183
 
165
184
  Consequences for you:
166
185
 
167
186
  - Your exact written bytes may be reformatted/fixed. **This is expected pipeline
168
187
  behavior, not a conflict or a failed write.**
169
- - A file you wrote last turn may have changed on disk. **Re-read before editing it
170
- again** (this also keeps the read-guard happy — the autofix nudge tells you which
171
- files changed).
188
+ - **`write`:** trust the authoritative content attached to the tool result; only
189
+ re-read if you see the size-cap warning, or if a *different* file (a side
190
+ effect of the same bash command) was touched.
191
+ - **`edit`:** the file may change on disk after your turn ends. **Re-read before
192
+ editing it again** (this also keeps the read-guard happy — the autofix nudge
193
+ tells you which files changed).
172
194
  - **Delta mode:** `lens_diagnostics` shows only diagnostics *introduced this turn* by
173
195
  default (`mode=delta`). Use `mode=all` (cache-wide) or `mode=full` (fresh scan) for
174
196
  the complete picture.
175
197
 
198
+ See `AGENTS.md`'s "Per-edit autofix mutation boundary (#1414)" invariant for the
199
+ authoritative routing rules.
200
+
176
201
  ---
177
202
 
178
203
  ## 7. Tools & commands you can use
@@ -207,7 +232,7 @@ Verified in `index.ts`:
207
232
  | `/lens-toggle` | Turn pi-lens on/off for the session. |
208
233
  | `/lens-context-toggle` | Toggle context injection (tools/LSP/read-guard/formatting stay active). |
209
234
  | `/lens-widget-toggle` | Show/hide the diagnostics footer widget. |
210
- | `/lens-health` | Runtime health: pipeline crashes, slow runners, last dispatch latency. |
235
+ | `/lens-health` | Runtime health: pipeline crashes, slow runners, last dispatch latency, and a bounded degradation-ledger summary (trust refusals, LSP breakers, formatter skips/failures, idle evictions, WASM aborts, timeout tallies). |
211
236
  | `/lens-perf` | Slowest latency-log phases (p50/p99). |
212
237
  | `/lens-tools` | Tool installation status (global / auto-installed / npx fallback). |
213
238
  | `/lens-tdi` | Technical Debt Index and project health trend. |
@@ -14,9 +14,11 @@ share) — current exceptions: `ast_grep_outline` and `ast_grep_dump`
14
14
  are registered but
15
15
  inactive by default; the model activates the ones it needs via the always-active
16
16
  loader tool `pi_lens_activate_tools`, per pi's dynamic-tool-loading API
17
- (`pi.setActiveTools`/`pi.getActiveTools`). Feature-detected: on hosts without
18
- that API, the five situational tools fall back to being statically active,
19
- exactly as before (`tools/activate-tools.ts`, wired in `index.ts`).
17
+ (`pi.setActiveTools`/`pi.getActiveTools`). The loader explicitly reports
18
+ "Available starting next turn"; do not retry the tool in the same turn.
19
+ Feature-detected: on hosts without that API, the six situational tools fall back
20
+ to being statically active, exactly as before (`tools/activate-tools.ts`, wired
21
+ in `index.ts`).
20
22
 
21
23
  ## Per-edit
22
24
 
@@ -40,13 +42,22 @@ exactly as before (`tools/activate-tools.ts`, wired in `index.ts`).
40
42
  - **`ast_grep_search`** — AST-aware structural search across ~40 languages via
41
43
  the `sg` CLI. Supports metavariables (`$VAR`, `$$$ARGS`), `strictness`
42
44
  modes (`smart`, `relaxed`, `ast`, `cst`, `signature`, `template`), structural
43
- constraints (`insideKind`, `hasKind`, `follows`, `precedes`), raw YAML `rule`
44
- passthrough, `validateOnly` for compile/shape checks without scanning project
45
- files, and pagination via `skip` / `maxMatches` (per-call cap, default 50,
46
- max 200; also sets the pagination step). `groupByFile: true` renders a compact
47
- one-line-per-file distribution (`L<line>:<col>` locations) instead of each
48
- match body — for high-volume searches. `pattern` is optional when a `rule` is
49
- given.
45
+ constraints (`insideKind`, `hasKind`, `hasDescendantKind`, `follows`,
46
+ `precedes`), raw YAML `rule` passthrough, `validateOnly` for compile/shape
47
+ checks without scanning project files, and pagination via `skip` / `maxMatches`
48
+ (per-call cap, default 50, max 200; also sets the pagination step).
49
+ `nodeKind` is an expert grammar-specific escape hatch: it finds every node of
50
+ the exact kind used by the target grammar. Node kinds are not universal across
51
+ languages; use `ast_grep_dump` to discover the kind in the target language. It is mutually exclusive with `pattern` and `rule`.
52
+ `hasKind` retains ast-grep's immediate-child semantics; use
53
+ `hasDescendantKind` for an explicit recursive descendant search. A future
54
+ canonical `find`/`query` facade (call/function/import/etc.) should map to
55
+ this same synthesized YAML path, with per-language templates and a clear
56
+ unsupported-concept error — it is intentionally not a second search engine
57
+ in this patch.
58
+ `groupByFile: true` renders a compact one-line-per-file distribution
59
+ (`L<line>:<col>` locations) instead of each match body — for high-volume
60
+ searches. `pattern` is optional when a `rule` or `nodeKind` is given.
50
61
  Results include `details.matchLocations[]` — each hit carries a ready
51
62
  `readSlice` (`path`/`offset`/`limit`) for a bounded context read; zero-match
52
63
  results include a `suggestedDump` hint pointing at `ast_grep_dump`.
@@ -0,0 +1,192 @@
1
+ # Graph and code-understanding inspiration for pi-lens
2
+
3
+ **Date:** 2026-08-02
4
+ **Scope:** Source-oriented review of four public repositories, followed by a comparison with the existing pi-lens review graph, Tree-sitter extraction, word index, report tools, snapshot lifecycle, and MCP seam. This is a research document, not an endorsement of any upstream implementation.
5
+
6
+ I inspected repository maps, manifests, architecture/design documentation, agent skills and CLI references, core extraction/resolution/query code, persistence and watch/update code, representative tests, examples, and security material. Claims marked **Observed** are supported by the cited upstream source. Claims marked **Recommendation** are judgments for pi-lens. A README benchmark or product statement is not treated as an implementation fact unless the source or tests support it. “Graph” is used carefully: Graphify and Code-Graph-RAG combine source graphs with documents or workflow/agent surfaces, while codegraph and Compass are primarily structural code/project graphs.
7
+
8
+ ## Sources consulted
9
+
10
+ The primary sources are listed here so later readers can reproduce the review:
11
+
12
+ - [Code-Graph-RAG README](https://github.com/vitali87/code-graph-rag/blob/main/README.md), [`pyproject.toml`](https://github.com/vitali87/code-graph-rag/blob/main/pyproject.toml), [architecture overview](https://github.com/vitali87/code-graph-rag/blob/main/docs/architecture/overview.md), [graph schema](https://github.com/vitali87/code-graph-rag/blob/main/docs/architecture/graph-schema.md), [language support](https://github.com/vitali87/code-graph-rag/blob/main/docs/architecture/language-support.md), [CLI reference](https://github.com/vitali87/code-graph-rag/blob/main/docs/guide/cli-reference.md), [real-time updates](https://github.com/vitali87/code-graph-rag/blob/main/docs/guide/realtime-updates.md), [`codebase_rag/graph_updater.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/graph_updater.py), [`models.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/models.py), [`tools/code_retrieval.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/tools/code_retrieval.py), [`tools/semantic_search.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/tools/semantic_search.py), [`mcp/tools.py`](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/mcp/tools.py), and incremental/cross-project tests [1](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/tests/integration/test_incremental_external_prune_e2e.py) [2](https://github.com/vitali87/code-graph-rag/blob/main/codebase_rag/tests/integration/test_cross_project_retrieval_e2e.py).
13
+ - [SylphAI codegraph README](https://github.com/SylphAI-Inc/skills/blob/main/skills/codegraph/README.md), [agent `SKILL.md`](https://github.com/SylphAI-Inc/skills/blob/main/skills/codegraph/SKILL.md), [`scripts/scan.py`](https://github.com/SylphAI-Inc/skills/blob/main/skills/codegraph/scripts/scan.py), [`scripts/overview.py`](https://github.com/SylphAI-Inc/skills/blob/main/skills/codegraph/scripts/overview.py), [`scripts/render.py`](https://github.com/SylphAI-Inc/skills/blob/main/skills/codegraph/scripts/render.py), [`scripts/viewer.html`](https://github.com/SylphAI-Inc/skills/blob/main/skills/codegraph/scripts/viewer.html), and [`scripts/test_codegraph.py`](https://github.com/SylphAI-Inc/skills/blob/main/skills/codegraph/scripts/test_codegraph.py).
14
+ - [Compass README](https://github.com/crabbuild/compass/blob/main/README.md), [`Cargo.toml`](https://github.com/crabbuild/compass/blob/main/Cargo.toml), [How Compass works](https://github.com/crabbuild/compass/blob/main/docs/concepts/how-it-works.md), [graph model](https://github.com/crabbuild/compass/blob/main/docs/concepts/graph-model.md), [extraction pipeline](https://github.com/crabbuild/compass/blob/main/docs/implementation/extraction-pipeline.md), [CompassQL](https://github.com/crabbuild/compass/blob/main/docs/COMPASSQL.md), agent [`SKILL.md`](https://github.com/crabbuild/compass/blob/main/crates/compass-cli/assets/compass-skill/SKILL.md), [query reference](https://github.com/crabbuild/compass/blob/main/crates/compass-cli/assets/compass-skill/references/query.md), [`compass-model/src/graph.rs`](https://github.com/crabbuild/compass/blob/main/crates/compass-model/src/graph.rs), [`query_index.rs`](https://github.com/crabbuild/compass/blob/main/crates/compass-model/src/query_index.rs), [`compass-files/src/manifest.rs`](https://github.com/crabbuild/compass/blob/main/crates/compass-files/src/manifest.rs), and [`compass-core/src/watch.rs`](https://github.com/crabbuild/compass/blob/main/crates/compass-core/src/watch.rs).
15
+ - [Graphify README](https://github.com/Graphify-Labs/graphify/blob/v8/README.md), [`ARCHITECTURE.md`](https://github.com/Graphify-Labs/graphify/blob/v8/ARCHITECTURE.md), [`pyproject.toml`](https://github.com/Graphify-Labs/graphify/blob/v8/pyproject.toml), [`graphify/extract.py`](https://github.com/Graphify-Labs/graphify/blob/v8/graphify/extract.py), [`build.py`](https://github.com/Graphify-Labs/graphify/blob/v8/graphify/build.py), [`cache.py`](https://github.com/Graphify-Labs/graphify/blob/v8/graphify/cache.py), [`watch.py`](https://github.com/Graphify-Labs/graphify/blob/v8/graphify/watch.py), [`symbol_resolution.py`](https://github.com/Graphify-Labs/graphify/blob/v8/graphify/symbol_resolution.py), [`resolver_registry.py`](https://github.com/Graphify-Labs/graphify/blob/v8/graphify/resolver_registry.py), [`analyze.py`](https://github.com/Graphify-Labs/graphify/blob/v8/graphify/analyze.py), [`skill-pi.md`](https://github.com/Graphify-Labs/graphify/blob/v8/graphify/skill-pi.md), [`serve.py`](https://github.com/Graphify-Labs/graphify/blob/v8/graphify/serve.py), [`security.py`](https://github.com/Graphify-Labs/graphify/blob/v8/graphify/security.py), and representative tests [incremental](https://github.com/Graphify-Labs/graphify/blob/v8/tests/test_incremental.py), [query CLI](https://github.com/Graphify-Labs/graphify/blob/v8/tests/test_query_cli.py), [security](https://github.com/Graphify-Labs/graphify/blob/v8/tests/test_security.py), and [benchmark](https://github.com/Graphify-Labs/graphify/blob/v8/tests/test_benchmark.py).
16
+
17
+ ## Executive summary
18
+
19
+ The strongest shared lesson is not “add a graph.” It is **separate authoritative structure from interpretation and presentation, then make uncertainty and freshness visible**. Compass is the most disciplined reference for this: immutable graph snapshots, explicit `EXTRACTED`/`INFERRED`/`AMBIGUOUS` provenance, bounded queries, quarantine of invalid records, and atomic publication. SylphAI’s codegraph is the best reference for agent ergonomics: a compact digest, progressive disclosure, importance-ranked files, guided reading tours, and a self-contained offline artifact. Graphify shows how to make a graph a practical agent workflow with `query`, `path`, `explain`, `affected`, hooks, and MCP, but its broad graph includes documents and model-generated concepts and therefore cannot be treated as a pure code-graph precedent. Code-Graph-RAG has the richest language-specific semantic ambition—Memgraph, multi-pass resolution, data-flow edges, AST editing, and optional embeddings—but also the heaviest operational and provider surface.
20
+
21
+ pi-lens already has the core ingredients these projects repeatedly rediscover: a shared TreeSitterClient and extractor; an immutable-by-replacement review graph with file/symbol/edge indexes; sequence-aware and content-hash-aware incremental paths; a persisted graph with explicit partial coverage; reverse dependencies; a bounded BM25 word index; `project_report`, `module_report`, `read_symbol`, and `read_enclosing`; and a host-neutral `lens-engine`/MCP seam. The real opportunity is not parallel storage or a second parser. It is to improve **evidence-aware context packing and reading order over those existing seams**.
22
+
23
+ ### Concise comparison matrix
24
+
25
+ | Project | Primary artifact | Structural truth | Retrieval/agent surface | Update/persistence | Main caution |
26
+ | --- | --- | --- | --- | --- | --- |
27
+ | Code-Graph-RAG | Memgraph graph plus CLI/MCP | Tree-sitter, multi-pass language handlers, resolved calls/imports, optional flows/findings | Natural language to Cypher, snippet retrieval, semantic search, AST edit/optimization tools | Hash/parser caches, incremental graph updater, file watcher; calls are recalculated broadly | Memgraph/Docker and optional Qdrant/ML/provider dependencies make it operationally large |
28
+ | SylphAI codegraph | `graph.json` + `digest.md` + one offline HTML | Stdlib regex extraction; imports reliable, calls unique-name heuristics | Agent writes `enrich.json`; tours and copied “ask” prompts; three visual views | Re-scan preserves enrichment by stable IDs; no live incremental graph | Calls/layers are explicitly approximate; semantic meaning is manual enrichment |
29
+ | Compass | `compass-out/graph.json`, report, manifest, optional history | Native Rust/tree-sitter extraction plus resolvers, typed evidence/provenance | Bounded natural query, `search`, `callers`, `path`, `affected`, CompassQL, MCP/skill | Hash manifest, atomic generation, watch/reconciliation, immutable Git realizations | Broad product scope and a large native dependency/build surface |
30
+ | Graphify | NetworkX-derived `graph.json`, report, HTML, optional exports | Tree-sitter code graph plus semantic document/media graph; confidence labels | `/graphify`, query/path/explain, hooks, MCP, optional semantic extraction | Per-file AST/semantic caches, tier-aware merge, watch reconciliation | Generic document/semantic edges and optional LLM output must not be confused with verified code edges |
31
+
32
+ ## 1. Code-Graph-RAG
33
+
34
+ ### Purpose and architecture
35
+
36
+ **Observed:** Code-Graph-RAG is a multi-language codebase assistant. Its documented pipeline is Tree-sitter parser → AST analysis → Memgraph, followed by an interactive RAG CLI that generates Cypher, retrieves source, and drives editing/optimization. The schema is unusually expressive: Project/Package/Folder/File/Module, Class/Function/Method and type nodes, external modules, resources, findings, and relationship families including `DEFINES`, `IMPORTS`, `EXPORTS`, `INHERITS`, `CALLS`, `REFERENCES`, `INSTANTIATES`, `READS_FROM`, `WRITES_TO`, and opt-in `FLOWS_TO`. Resource/data-flow edges are conservatively intra-procedural with limited caller/callee handoff, not general whole-program taint proof.
37
+
38
+ `graph_updater.py` implements multiple passes: structure, optional C/C++ libclang/hybrid and C# Roslyn frontends, per-file extraction, deferred parent/import/call resolution, endpoint and finding passes, pruning, then optional embeddings. The language table and package extras cover a wide set of languages. The graph model in `models.py` is deliberately generic (`GraphNode` labels/properties and `GraphRelationship` source/target/type/properties), while language-specific handlers carry the difficult resolution logic.
39
+
40
+ ### Interfaces, retrieval, and agent behavior
41
+
42
+ **Observed:** `cgr start --update-graph`, `export`, `optimize`, `watch`, and language grammar commands are the principal CLI surfaces. Natural-language questions are converted into Cypher by an LLM/provider path; exact source retrieval is separate and uses qualified name plus recorded line range. `CodeRetriever` gives the recorded absolute path precedence, checks project roots, and returns a bounded source slice with location/docstring. Optional semantic search embeds a query, searches Qdrant or another configured vector backend, then resolves node IDs back through the graph and source locations. The MCP registry exposes graph query, retrieval, semantic/structural search, read/write/edit, directory, shell, and agent tools.
43
+
44
+ This is a useful separation between **graph selection** and **source reading**: a graph answer is not itself a source body. It also validates cross-project retrieval: the integration test indexes two repositories and proves a retriever rooted in one can retrieve a symbol from the other using stored absolute paths.
45
+
46
+ ### Incremental and scale evidence
47
+
48
+ **Observed:** The updater maintains per-file hashes, directory mtimes, parser fingerprints, a bounded AST cache, a function registry, and rehydrated definitions for unchanged files. The graph updater test suite includes orphaned external-module pruning and the implementation checks that a shared graph still contains the project before trusting a local sync cache. The realtime watcher debounces saves but explicitly recalculates all `CALLS` relationships for each processed change; its own documentation calls this a correctness choice that can hurt large, frequently edited repositories. That is an important negative lesson: local file reparse and global relationship repair are different costs.
49
+
50
+ ### Strongest ideas and limitations
51
+
52
+ **Recommendation for inspiration:** borrow the distinction between local extraction facts, deferred resolution facts, and optional high-value edge families. A pi-lens “evidence tier” could expose why an edge is present without pretending to be a compiler. The source-retrieval contract—stable identity, path validation, line range, and failure when the source is missing—is also aligned with `read_symbol`/`read_enclosing`.
53
+
54
+ **Observed limitation:** the dependency stack includes Python 3.12+, Memgraph client/Docker, many grammar packages, optional Qdrant/Torch/Transformers, and provider integrations. This is not a fit for pi-lens’s lightweight, host-extension, install-safe hot path. Its Cypher generation also places a model/provider in query planning; that is unsuitable as an authoritative answer path unless every result is bounded and source-verified.
55
+
56
+ ## 2. SylphAI `skills/codegraph`
57
+
58
+ ### Purpose and architecture
59
+
60
+ **Observed:** This is an agent skill, not a daemon or graph database. It has a strict three-stage contract:
61
+
62
+ 1. `scan.py` deterministically produces `graph.json` and a compact `digest.md`.
63
+ 2. The agent reads the digest and writes only `enrich.json` with summaries, layer corrections, and 3–6-step tours.
64
+ 3. `render.py` validates and atomically emits one self-contained offline HTML artifact; `overview.py` derives the coarse architecture view.
65
+
66
+ `scan.py` is standard-library-only, uses Git’s tracked/untracked-with-ignore listing when available, caps files and per-file size, avoids minified files, extracts docstrings/comments, uses hand-written import resolution, computes PageRank plus fan-in and size, detects cycles, and extracts symbols only for the most important files. Its cross-file calls are intentionally constrained to unique non-stopword names. The actual graph schema has typed IDs (`mod:`, `file:`, `sym:`, `ext:`), containment/import/call/inheritance/dependency edges, line ranges, importance, layers, entry status, and summaries.
67
+
68
+ ### Agent-facing commands and context packing
69
+
70
+ **Observed:** The skill tells an agent to read `digest.md`, not a potentially megabyte-sized `graph.json`, and to summarize the top 30–60 ranked files first. It requires IDs to be copied verbatim and drops unknown enrichment IDs with warnings. Tours encode reading order, something a dependency graph does not supply. Each rendered node can copy a complete prompt containing path, summary, LOC, fan-in/fan-out, symbols, and both edge directions—an offline context handoff rather than an embedded chat client.
71
+
72
+ The viewer has overview, orbitable starmap, and expandable folder→file→symbol views. It hides tests, folds hub edges, disables calls by default, supports neighborhood focus, and caps animated packets. `render.py` validates duplicate IDs and dangling edges before an atomic same-directory replacement. The tests assert deterministic graphs, real module/path references, cycle detection, docstring provenance, enrichment behavior, tour validation, geometry, and declutter controls.
73
+
74
+ ### Limitations and pi-lens fit
75
+
76
+ **Observed limitation:** the skill states plainly that extraction is regex-based, imports are trustworthy, calls are hints, dynamic imports/DI/reflection/runtime registration are invisible, layers are path heuristics, and generated/minified/lock files are excluded. Its reported speed and 60fps claims are demonstrations, not a general guarantee. It has no durable graph freshness protocol beyond re-running scan/render.
77
+
78
+ **Recommendation:** adopt the *shape* of digest-plus-progressive-disclosure, not its parser. `project_report` already gives ranked hubs, entry points, subsystems, risk, dead-weight caveats, and trust/provenance; `module_report` already gives summaries, callbacks, imports, used-by, recommended reads, compact output, and blast radius. The gap is a deterministic, bounded reading tour or context pack over these existing reports. Use TreeSitter ranges and the word index; do not add a `digest` database or regex extractor.
79
+
80
+ ## 3. Compass
81
+
82
+ ### Purpose, model, and pipeline
83
+
84
+ **Observed:** Compass is a native Rust, local-first knowledge graph for source code and project artifacts. The README says structural extraction and queries need no Python, embeddings, vector database, model credentials, or runtime parser downloads. The workspace manifest shows a large but deliberately native product: Tree-sitter language pack, SQLite/Prolly history storage, query engine, MCP, exports, optional semantic/media/integration crates, and strict Rust lints.
85
+
86
+ Its documented pipeline is discover → extract → resolve → analyze → publish → query. `compass-model/src/graph.rs` loads a directed graph, preserves insertion order and multigraph semantics, builds incoming/outgoing adjacency and query indexes, and can create minimal endpoint nodes during loading. `query_index.rs` indexes labels, display labels, source files, edge types, typed adjacency, and a schema fingerprint. The graph model treats IDs as opaque stable strings, retains open-ended node/edge attributes, and keeps parallel edges distinct.
87
+
88
+ The most valuable model detail is provenance: `EXTRACTED`, `INFERRED`, or `AMBIGUOUS`, with source locations and an explicit warning that inferred or extracted does not equal runtime truth. Invalid records are quarantined, partial publication carries omission diagnostics and `incomplete_coverage`, and document-level or empty-graph failures preserve the last good generation.
89
+
90
+ ### Incremental, history, and scale bounds
91
+
92
+ **Observed:** The manifest tracks mtime plus AST and semantic hashes. It distinguishes unchanged, changed, new, renamed/deleted/excluded files, and only reuses extraction when content, cache format, parser/extractor configuration, and relevant project-wide inputs are compatible. The extraction-pipeline documentation requires cold/warm/change/rename/delete equivalence testing. Watch mode debounces events, supports native or polling backends, filters scope, retries failures, and performs periodic reconciliation. Atomic publication advances graph and manifest together. Exact Git history is represented as immutable realizations with a commit/profile/extraction fingerprint, not as mutable “current” data.
93
+
94
+ Queries are explicitly bounded by row, path, expansion, memory, response, and deadline limits. CompassQL is a deterministic read-only openCypher subset with parameter files and table/JSON/JSONL outputs. The source query engine uses SQLite full-text ranking and typed response limits, while the graph indexes support exact adjacency operations.
95
+
96
+ ### Agent and integration surface
97
+
98
+ **Observed:** The Compass skill routes architecture to `query` then `explain`, impact to `affected`, exact automation to `query --cql`, source relationships to `path`/`callers`/`callees`, and revision questions to history/diff. It says to use the graph to select a small source set and verify decisive facts in source. `--budget` bounds rendered context, not graph truth. The skill includes on-demand references for commands, query, update, semantic extraction, history, hooks, exports, MCP, security, and operations.
99
+
100
+ ### Strongest ideas, limitations, and fit
101
+
102
+ **Recommendation:** Compass is the clearest inspiration for pi-lens’s honesty contract: every graph-backed report should expose completeness, provenance, current-vs-historical state, direction, and bounds. Its immutable snapshot/atomic generation discipline closely validates pi-lens’s existing replacement-based graph and worker persistence design. Its query index also supports investing in task-specific indexes rather than one generic “graph search.”
103
+
104
+ **Observed limitation:** Compass’s native binary and extensive workspace are much larger than pi-lens needs. Its semantic and integration capabilities are optional but broaden the trust boundary. Its communities are useful hypotheses, not stable architecture labels; its own docs say IDs and clusters must not be treated as business truth. Pi-lens should adapt contracts and tests, not import CompassQL, Prolly storage, or a second native graph runtime.
105
+
106
+ ## 4. Graphify
107
+
108
+ ### Purpose and graph boundaries
109
+
110
+ **Observed:** Graphify is both a Python library and an agent skill. Its pipeline is `detect → extract → build_graph → cluster → analyze → report → export`, communicating through dicts and NetworkX. The graph can contain code, Markdown/docs, SQL schemas, configs, PDFs/images/media, rationale nodes, and model-generated concepts. That makes it a **general knowledge/workflow graph**, not only a source-code graph. Code extraction is local Tree-sitter; semantic document/media extraction may call the assistant or a configured provider.
111
+
112
+ The common extraction contract is nodes with `id`, `label`, `source_file`, `source_location` and edges with source/target/relation/confidence. `EXTRACTED`, `INFERRED`, and `AMBIGUOUS` are persisted. `ids.py` centralizes Unicode/path-independent ID normalization because AST and semantic producers otherwise create ghost nodes. `symbol_resolution.py` and `resolver_registry.py` provide conservative cross-file resolution and language-specific passes; the resolver defers receiver/member calls rather than binding every same-named method.
113
+
114
+ ### Queries, skills, and context
115
+
116
+ **Observed:** The `/graphify` skill uses `query` for bounded BFS/DFS context, `path` for shortest known connection, `explain` for a node, and `affected` for incoming impact. It has a fast path that reuses an existing graph, a token budget, source-location citations, and an explicit rule not to invent edges. A hook can softly nudge an agent to query first; opt-in strict mode blocks at most the first raw read per session and then allows it. The MCP server supports stdio by default and optional HTTP, with bounded graph contexts/LRU behavior and optional API-key protection. These are workflow controls, not graph facts.
117
+
118
+ ### Freshness, semantic cache, and security
119
+
120
+ **Observed:** `cache.py` stores per-file AST and semantic results keyed by content, with semantic prompt fingerprints to prevent replaying old extraction instructions. Semantic chunks checkpoint incrementally, preserve partial markers, and constrain model output to dispatched files. `build.py` replaces the changed file’s contribution and uses tier-aware AST versus semantic ownership; `watch.py` debounces code changes, rebuilds code locally, flags non-code changes for semantic re-extraction, distinguishes deleted from newly excluded files, and atomically replaces accepted graph output. Tests cover stale import pruning, direction preservation, oversized graph rejection, query context filtering, and benchmark subgraph token counts.
121
+
122
+ `security.py` is a strong boundary: HTTP(S)-only URLs, DNS/private-IP/metadata protection and redirect revalidation, fetch size/time limits, graph path confinement, graph file size caps before JSON parsing, control-character/length-limited labels, and no source execution. The README’s privacy section is more nuanced than “local”: code-only is local, but docs/PDFs/images can leave the machine according to selected provider; query logging is opt-in in the current source despite older/common descriptions of logging.
123
+
124
+ ### Limitations and fit
125
+
126
+ **Observed limitation:** NetworkX and plain JSON are approachable but can duplicate memory and do not themselves provide query indexes or immutable generations. The generic semantic graph can introduce relationships that are not compiler-backed. Hook strictness can also redirect agent behavior without proving a graph is complete. Provider selection, media extras, HTTP serving, and many platform skills enlarge installation and privacy complexity.
127
+
128
+ **Recommendation:** borrow Graphify’s provenance-aware IDs, source-location-first query output, tier-aware invalidation, and “query before broad read” skill wording. Reject its generic document graph as a pi-lens core model; pi-lens can already attach diagnostics and docs through separate surfaces, and merging model-generated concepts into the immutable review graph would make code answers less trustworthy.
129
+
130
+ ## Cross-project patterns
131
+
132
+ 1. **Two layers beat one “smart graph.”** Deterministic extraction should own identity, locations, imports, containment, and explicit syntax. A separate layer may add summaries, tours, semantic edges, or provider results. The boundary must preserve source ownership and provenance.
133
+ 2. **Agent value comes from context selection, not graph size.** Digests, PageRank/centrality, hubs, entry points, `affected`, neighborhood focus, query budgets, and compact JSON/JSONL all reduce the source set before reading bodies.
134
+ 3. **Reading order is a first-class product.** Sylph tours and Graphify’s query-first skill make explicit what raw edges omit. Compass’s “query then verify source” workflow is the safest formulation.
135
+ 4. **Freshness is part of every answer.** Hashes, parser/prompt fingerprints, sequence hints, manifests, periodic reconciliation, atomic publication, partial flags, and current-vs-history separation prevent a plausible stale graph from masquerading as truth.
136
+ 5. **Resolution should expose uncertainty.** Name-only calls, inferred edges, ambiguous targets, missing endpoints, quarantined records, and incomplete coverage are useful if surfaced; silently dropping or upgrading them is not.
137
+ 6. **The graph and retrieval index are complementary.** BM25/FTS is good at finding vocabulary; graph traversal is good at explaining relationships; source ranges are the final evidence. Embeddings are optional and should never replace structural evidence for code navigation.
138
+ 7. **Presentation must be bounded independently of storage.** Interactive views fold hubs and cap animated edges; query engines cap rows/paths/bytes; reports use compact views. A graph can be complete while a response is intentionally a projection.
139
+
140
+ ## Pi-lens fit matrix
141
+
142
+ | Upstream idea | Existing pi-lens equivalent | Real gap/overlap | Fit and likely seam |
143
+ | --- | --- | --- | --- |
144
+ | Provenance per relationship | Review-graph edge `resolution`, report section provenance, capped-coverage fields | More edge-level evidence/locations could be surfaced consistently | **Adapt** in `clients/review-graph/types.ts`, `module-report.ts`, `project-report.ts`; no new graph |
145
+ | Digest of top architecture | `project_report` compact view, word-index ranking, `recommendedReads` | No single persisted digest/tour artifact | **Adapt** as a bounded report/context mode, not a second cache; `clients/project-report.ts` |
146
+ | Guided tours/read order | Entry points, hubs, recommended reads, blast radius | No explicit multi-step tour contract | **Adapt** deterministically first; later optional agent-authored notes in reports/docs, not graph truth |
147
+ | Query-first agent workflow | Pi tools plus MCP mirrored engine; read guard tracks coverage | Could nudge toward `project_report`/`symbol_search` before broad reads | **Adapt** in a skill/docs surface; do not block native reads like Graphify strict mode |
148
+ | FTS/BM25 plus graph centrality | Persisted word index already uses BM25, reverse-dep centrality, graph annotations | Strong overlap; validate ranking quality rather than add embeddings | **Keep/adapt** in `clients/word-index.ts` and `lens-engine.ts` |
149
+ | Typed graph query language | `computeTransitiveImpact`, module/project reports, MCP tools | No arbitrary read-only graph query; current bounded tools are safer | **Reject for now**; add narrowly scoped query operations only if telemetry shows demand |
150
+ | Hash/prompt/parser-aware cache | Project snapshot/sequence/content hash, graph version, word-index metadata | Semantic prompt versioning is not a core pi-lens graph concern | **Keep existing**; extend snapshot metadata only for a demonstrated new derived index |
151
+ | Atomic immutable publication | Immutable graph-by-replacement, persist worker/generation, partial coverage | This is already stronger than several upstream paths | **Preserve**, do not copy mutable NetworkX/JSON merge semantics |
152
+ | Semantic/vector retrieval | Optional upstream embeddings | Pi-lens has no evidence of a semantic-search gap; external provider/privacy cost is high | **Reject until measured**; use TreeSitter/BM25/graph first |
153
+ | Offline interactive map | `lens-map` already produces deterministic self-contained HTML | Graphify/Sylph offer useful declutter and progressive UI patterns | **Adapt** in `clients/lens-map.ts`; no new graph/index |
154
+ | Tier-aware replacement of changed-file data | `updateGraphFiles`, reverse-deps, sequence fast path | Existing implementation is immutable and graph-specific | **Keep**, audit only when a new fact tier is added |
155
+ | Cross-project graph | Upstream CGR/Graphify support it | pi-lens is project-scoped by design and path-keyed caches are safety-sensitive | **Reject** unless a concrete MCP use case funds identity/privacy design |
156
+
157
+ ## Top eight prioritized inspirations
158
+
159
+ 1. **Evidence-aware compact context pack.** User value: fewer exploratory reads with explicit file, symbol, edge, line-range, provenance, and truncation evidence. Cost/risk: medium; must avoid claiming body coverage from an outline and must respect read-guard semantics. Performance/token impact: bounded by top-N hits and line ranges; reuses BM25, immutable graph, and TreeSitter extraction. Surface: agent tool first, then MCP mirror through `lens-engine`; likely `clients/word-index.ts`, `module-report.ts`, `lens-engine.ts`.
160
+ 2. **Deterministic guided reading path.** User value: answer “where do I start?” as a 3–6-step path from entry point through important dependencies. Cost: low-medium; path choice needs transparent tie-breaking and must distinguish shortest from important. Token impact: small compact output. Surface: `project_report`/`module_report` and MCP mirror, computed from existing graph BFS/centrality; no persisted tour graph.
161
+ 3. **Uniform edge evidence and completeness display.** User value: agents can tell exact/import/receiver-type/name-only and partial/capped/unavailable apart. Cost: medium, mostly output-contract and tests. Cache impact: none. Surface: existing reports/tools and MCP; extend only fields already derivable from graph nodes/edges.
162
+ 4. **Query-first skill guidance without hard blocking.** User value: agents orient with `project_report`/`symbol_search` before flooding context. Cost: low; risk is friction and stale-cache overconfidence. Token impact: saves broad reads. Surface: docs/skill, perhaps a soft tool description; explicitly not a strict read guard.
163
+ 5. **Declutter policy for `lens-map`.** User value: human architecture map remains readable at hub-heavy scale. Cost: low-medium; implement only view-level folding/LOD, preserve underlying graph. Performance: fewer DOM/SVG/canvas operations. Surface: `clients/lens-map.ts` and its viewer assets; no agent/MCP contract change.
164
+ 6. **Freshness telemetry for retrieval answers.** User value: expose index age, graph generation, source cap, reverse-dependency availability, and whether a result was disk or warm memory. Cost: low; no new storage. Surface: `symbol_search`/MCP health and logs; use existing snapshot and graph metadata.
165
+ 7. **Failure/quarantine vocabulary for graph-backed answers.** User value: “not found” is not confused with “not indexed” or “incomplete.” Cost: medium; align existing `available`, `coverage`, `unavailable:file-cap`, and indeterminate cascade statuses. Surface: engine/report contracts and tests.
166
+ 8. **Design-only evaluation corpus for ranking and context.** User value: measurable recall and token reduction without provider dependence. Cost: medium in tests/fixtures, low runtime risk. Cache impact: none. Surface: tests and documentation; use real pi-lens fixtures, not an external graph store.
167
+
168
+ ## Do not copy
169
+
170
+ - **Duplicate graph/index/parser storage.** Do not add a Memgraph/NetworkX/SQLite graph or a second Tree-sitter extractor when pi-lens already has immutable review-graph, reverse-deps, BM25, and shared `TreeSitterClient` seams. A new representation would create path, schema, freshness, and graph-generation disagreement.
171
+ - **Stale graph claims.** Do not infer “zero results means no relationship,” serve a partial/capped graph as complete, or upgrade name-only/inferred calls to fact. Preserve pi-lens’s existing indeterminate cascade and coverage language.
172
+ - **Synchronous or unbounded walks.** Upstream examples that scan or recompute all calls on every save are useful cautionary evidence, not a hot-path design. Keep file caps, chunked yields, deadlines, abort behavior, and async persistence. This is especially important on the TUI event loop.
173
+ - **Provider/network coupling.** Do not make agent navigation depend on Qdrant, an LLM Cypher planner, remote semantic extraction, or runtime grammar downloads. Structural tools must work offline and degrade honestly.
174
+ - **Project-controlled code execution.** Never execute source to discover calls, load arbitrary project plugins, or permit graph queries to become shell commands. Parsing and query tools remain read-only unless an explicit existing mutation path is used.
175
+ - **Privacy/security regressions.** Do not embed credentials in HTML, log proprietary prompts/results by default, fetch arbitrary URLs without SSRF/size/timeout guards, or expose an HTTP MCP endpoint without explicit authentication/bind warnings.
176
+ - **OS/install incompatibilities.** Do not assume POSIX paths, case-insensitive filesystems, Unix process groups, a global Python/Rust toolchain, or postinstall network access. Any implementation must honor pi-lens’s path normalization, project/global data directories, Windows tree-kill and install-lock rules, Linux CI, and no-install ordinary tests.
177
+
178
+ ## Design-only experiment plan and issue-sized follow-ups
179
+
180
+ 1. **Ranking replay:** build a fixture set of 20–30 real pi-lens questions with expected files/symbols. Compare current BM25, BM25+reverse-dependency centrality, and graph-only baselines. Record top-k recall, ties, false positives from tests/vendor/docs, and token cost. No production changes.
181
+ 2. **Reading-path prototype:** as a pure function over a frozen `ReviewGraph`, choose entry → hub/dependency paths under a 3–6 node cap. Compare shortest path, centrality-weighted path, and `project_report` recommendations. Validate deterministic output and missing/partial graph behavior.
182
+ 3. **Context-pack prototype:** compose existing `symbol_search` hits with `module_report` read handles and TreeSitter line ranges under a hard byte/token budget. Verify it never marks an outline as a body read, never returns files outside `paths`, and reports graph/index generations and truncation.
183
+ 4. **Staleness telemetry:** log (or expose in a report only) graph generation, snapshot sequence, word-index file count/truncation, source mtimes checked, and cache source. Validate warm/disk/cold behavior and Windows separator/case forms without adding a cache.
184
+ 5. **Map declutter experiment:** measure `lens-map` render size and interaction latency with hub folding/edge caps, comparing visual loss against current file/node caps. Do not change graph data.
185
+
186
+ Issue-sized follow-ups should be: (a) context-pack contract and unit tests; (b) reading-path tie-breaking and evidence tests; (c) ranking fixture/evaluation harness; (d) freshness fields in tool responses; and (e) lens-map declutter only if measurements show a real bottleneck. Claims needing validation telemetry include whether agents actually need semantic embeddings, whether recommended-read paths reduce rereads, how often persisted graph/index caps are hit, and whether graph centrality improves top-k recall enough to justify its cost.
187
+
188
+ ## Final recommendation
189
+
190
+ The next smallest contained improvement should be a **read-only, bounded “recommended context path” design on top of `symbol_search` and `module_report`**, implemented first as a pure function and fixture evaluation—not as a new graph or index. Start with existing BM25 hits, existing reverse-dependency/immutable graph annotations, and TreeSitter-derived symbol line ranges; return at most a few ranked files/read handles with explicit `provenance`, graph/index freshness, and truncation. Keep `read_symbol`/`read_enclosing` as the only body-coverage authorities, and expose the same result through the existing `lens-engine` seam only after the pi tool contract is proven.
191
+
192
+ This captures the best upstream idea—progressive, task-focused reading order—while respecting pi-lens’s stronger existing invariants: one shared parser, one immutable graph, one persisted BM25 index, bounded event-loop work, honest partiality, and a single MCP mirror seam. It should be rejected or narrowed if ranking telemetry does not show a measurable reduction in source reads or context tokens.
@@ -0,0 +1,165 @@
1
+ # API ports inventory — S1 of #1358
2
+
3
+ This is a read-only inventory of host state crossing into the engine. The scope is `clients/` and `tools/`; `index.ts` is listed separately as the current pi adapter. A `DispatchContext` is engine-owned, but its `cwd`, `pi.getFlag`, `hasTool`, and `log` members are projections of the host tool context and are therefore included. Engine fields such as `filePath`, facts, project configuration, and runtime state are not host ports.
4
+
5
+ The sweep used the requested `ctx.`, `pi.`, `ExtensionContext`, and `ExtensionAPI` searches, then followed the named seams and their consumers. There are **84 inventory rows** below. Line numbers refer to the S1 branch at commit time.
6
+
7
+ ## Inventory
8
+
9
+ | file:line | capability | current mechanism | proposed port name |
10
+ |---|---|---|---|
11
+ | `tools/ast-grep-outline.ts:144` | workspace cwd | direct `ctx.cwd` read | `workspace.cwd` |
12
+ | `tools/ast-grep-replace.ts:181` | workspace cwd | direct `ctx.cwd` read | `workspace.cwd` |
13
+ | `tools/ast-grep-search.ts:437,652,661,687` | abort + workspace cwd | direct `ctx.signal`/`ctx.cwd` reads | `lifecycle.abortSignal`, `workspace.cwd` |
14
+ | `tools/lens-diagnostic-mark.ts:253` | workspace cwd | direct `ctx.cwd` read | `workspace.cwd` |
15
+ | `tools/lens-diagnostics.ts:376,398` | workspace cwd + abort | direct `ctx.cwd`/`ctx.signal` reads | `workspace.cwd`, `lifecycle.abortSignal` |
16
+ | `tools/lsp-diagnostics.ts:521,534` | abort + workspace cwd | direct `ctx.signal`/`ctx.cwd` reads | `lifecycle.abortSignal`, `workspace.cwd` |
17
+ | `tools/lsp-navigation.ts:992,1084,1128,1490,1496,1516,1521` | flags, workspace cwd, edit cwd | direct `ctx.cwd`; flag closure receives cwd | `flags.get`, `workspace.cwd` (path RESOLUTION is engine logic over `workspace.cwd` — review reclassification, #1360) |
18
+ | `tools/module-report.ts:130,131,282,283,438,439` | workspace cwd | direct `ctx.cwd` read | `workspace.cwd` |
19
+ | `tools/project-report.ts:76` | workspace cwd | direct `ctx.cwd` read | `workspace.cwd` |
20
+ | `tools/symbol-search.ts:73` | workspace cwd | direct `ctx.cwd` read | `workspace.cwd` |
21
+ | `tools/activate-tools.ts:87,89` | active-tool registry | direct `pi.getActiveTools`/`pi.setActiveTools` | `tools.active` |
22
+ | `clients/dispatch/dispatcher.ts:188,406` | feature flags | direct `pi.getFlag`/`ctx.pi.getFlag` | `flags.get` |
23
+ | `clients/dispatch/dispatcher.ts:607,979,1024` | diagnostic logging | direct `ctx.log` | `log.debug` |
24
+ | `clients/dispatch/dispatcher.ts:750,780,818,859,867,982,985` | cwd/project root | direct `ctx.cwd`/`ctx.projectRoot` | `workspace.cwd`, `workspace.projectRoot` |
25
+ | `clients/dispatch/integration.ts:337,359,394` | feature flags | direct `ctx.pi.getFlag`/`pi.getFlag` | `flags.get` |
26
+ | `clients/dispatch/auxiliary-lsp.ts:367` | cwd policy input | direct `ctx.cwd` | `workspace.cwd` |
27
+ | `clients/runtime-tool-call.ts:344,357,365,639` | workspace cwd | direct tool-context projection | `workspace.cwd` |
28
+ | `clients/runtime-tool-call.ts:452,453` | LSP status UI | direct `ctx.ui.setStatus`/`ctx.ui.theme` | `status.set` |
29
+ | `clients/dispatch/runners/actionlint.ts:92` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
30
+ | `clients/dispatch/runners/ast-grep-napi.ts:556,618,623` | tool availability, cwd, logging | direct `ctx.hasTool`, `ctx.cwd`, `ctx.log` | `tools.has`, `workspace.cwd`, `log.debug` |
31
+ | `clients/dispatch/runners/biome-check.ts:83` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
32
+ | `clients/dispatch/runners/cpp-check.ts:210` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
33
+ | `clients/dispatch/runners/credo.ts:81` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
34
+ | `clients/dispatch/runners/dart-analyze.ts:167` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
35
+ | `clients/dispatch/runners/detekt.ts:148` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
36
+ | `clients/dispatch/runners/dotnet-build.ts:147` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
37
+ | `clients/dispatch/runners/elixir-check.ts:166` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
38
+ | `clients/dispatch/runners/eslint.ts:110` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
39
+ | `clients/dispatch/runners/fish-indent.ts:22` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
40
+ | `clients/dispatch/runners/gleam-check.ts:57` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
41
+ | `clients/dispatch/runners/go-vet.ts:44` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
42
+ | `clients/dispatch/runners/golangci-lint.ts:129` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
43
+ | `clients/dispatch/runners/hadolint.ts:61` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
44
+ | `clients/dispatch/runners/helm-lint.ts:180,188` | project/cwd | direct `ctx.projectRoot`/`ctx.cwd` | `workspace.projectRoot`, `workspace.cwd` |
45
+ | `clients/dispatch/runners/htmlhint.ts:69` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
46
+ | `clients/dispatch/runners/javac.ts:55` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
47
+ | `clients/dispatch/runners/ktlint.ts:93` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
48
+ | `clients/dispatch/runners/lsp.ts:119,121,163` | cwd, flags | direct `ctx.cwd`, `ctx.pi.getFlag` | `workspace.cwd`, `flags.get` |
49
+ | `clients/dispatch/runners/markdownlint.ts:107` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
50
+ | `clients/dispatch/runners/mypy.ts:69` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
51
+ | `clients/dispatch/runners/oxlint.ts:64,82` | runner cwd, tool availability | direct `ctx.cwd`, `ctx.hasTool` | `workspace.cwd`, `tools.has` |
52
+ | `clients/dispatch/runners/php-lint.ts:47` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
53
+ | `clients/dispatch/runners/phpstan.ts:90` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
54
+ | `clients/dispatch/runners/prisma-validate.ts:56` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
55
+ | `clients/dispatch/runners/psscriptanalyzer.ts:148` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
56
+ | `clients/dispatch/runners/pyright.ts:39,44` | flags, runner cwd | direct `ctx.pi.getFlag`, `ctx.cwd` | `flags.get`, `workspace.cwd` |
57
+ | `clients/dispatch/runners/rubocop.ts:97` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
58
+ | `clients/dispatch/runners/ruff.ts:80` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
59
+ | `clients/dispatch/runners/rust-clippy.ts:66,67,70` | cwd for probe/install | direct `ctx.cwd` | `workspace.cwd` |
60
+ | `clients/dispatch/runners/shellcheck.ts:144,153,154,182` | cwd, tool availability | direct `ctx.cwd`, `ctx.hasTool` | `workspace.cwd`, `tools.has` |
61
+ | `clients/dispatch/runners/shfmt.ts:46` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
62
+ | `clients/dispatch/runners/spellcheck.ts:105,115` | cwd for probe/command | direct `ctx.cwd` | `workspace.cwd` |
63
+ | `clients/dispatch/runners/spotbugs.ts:218,222` | cwd, logging | direct `ctx.cwd`, `ctx.log` | `workspace.cwd`, `log.debug` |
64
+ | `clients/dispatch/runners/sqlfluff.ts:133,140` | cwd, logging | direct `ctx.cwd`, `ctx.log` | `workspace.cwd`, `log.debug` |
65
+ | `clients/dispatch/runners/stylelint.ts:112,120` | cwd, logging | direct `ctx.cwd`, `ctx.log` | `workspace.cwd`, `log.debug` |
66
+ | `clients/dispatch/runners/swiftlint.ts:161` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
67
+ | `clients/dispatch/runners/taplo.ts:60,70` | cwd, tool availability | direct `ctx.cwd`, `ctx.hasTool` | `workspace.cwd`, `tools.has` |
68
+ | `clients/dispatch/runners/terragrunt.ts:159` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
69
+ | `clients/dispatch/runners/tflint.ts:83` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
70
+ | `clients/dispatch/runners/tree-sitter.ts:429,435,458,522,713` | cwd/config/ignore root | direct dispatch-context `ctx.cwd`/`ctx.projectRoot` | `workspace.cwd`, `workspace.projectRoot` |
71
+ | `clients/dispatch/runners/trivy-config.ts:149` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
72
+ | `clients/dispatch/runners/vale.ts:135` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
73
+ | `clients/dispatch/runners/yamllint.ts:52,59` | cwd, logging | direct `ctx.cwd`, `ctx.log` | `workspace.cwd`, `log.debug` |
74
+ | `clients/dispatch/runners/zig-check.ts:61` | runner cwd | direct dispatch-context `ctx.cwd` | `workspace.cwd` |
75
+ | `clients/project-trust.ts:51,86` | project trust | host accessor read, then latched singleton | `trust.isProjectTrusted` |
76
+ | `clients/extension-mode.ts:50` | run mode | host accessor read at call site | `mode.current` |
77
+ | `clients/user-notify.ts:30,50` | human notification | live getter seam over `ctx.ui.notify` | `notify.user` |
78
+ | `clients/lens-events.ts:66,111` | event emission | live bus getter, resolved at deferred delivery | `emit.lens` |
79
+ | `clients/bus-publish.ts:83,196` | files-touched event | live emitter getter | `emit.bus` |
80
+ | `clients/diagnostics-publish.ts:130` | diagnostics event | live emitter getter | `emit.bus` |
81
+ | `clients/disposition-publish.ts:62` | disposition event | live emitter getter | `emit.bus` |
82
+ | `clients/format-events-publish.ts:130` | format/autofix events | live emitter getter | `emit.bus` |
83
+ | `clients/safe-spawn.ts:322,987` | turn cancellation for children | ambient abort signal set by adapter, read deep by spawn helper | `spawn.abortSignal` |
84
+ | `clients/widget-state.ts:142,205` | TUI invalidation | callback setter invoked by adapter; engine calls callback | `render.invalidate` |
85
+ | `clients/runtime-session.ts:104,970,1755` | session-start user output | notifier passed as callback parameter | `notify.user` |
86
+ | `clients/runtime-agent-end.ts:44,97,512` | agent-end user output | notifier passed as callback parameter | `notify.user` |
87
+ | `clients/lsp/config.ts:119` | invalid-config user output | `notifyUserDegradation` getter seam plus log sink | `notify.user`, `log.extension` |
88
+ | `clients/dispatch/runners/tree-sitter.ts:429,458` | tree-sitter config degradation | parameterized cwd plus notifier from config loader | `workspace.cwd`, `notify.user` |
89
+ | `clients/runtime-tool-call.ts:559,597,791,822,923,1038,1070,1112` | stable session identity in telemetry | parameter threaded from adapter/runtime identity | `session.id` |
90
+ | `clients/session-lifecycle.ts:298,333` | primary/secondary session identity | adapter extracts host session id and passes it in | `session.id` |
91
+ | `clients/session-state-store.ts:79,144` | persisted session state namespace | session id parameter threaded from adapter | `session.id` |
92
+ | `clients/extension-log.ts:35` | extension log sink | process/global-dir-derived static NDJSON sink | `log.extension` |
93
+ | `clients/actionable-warnings-logger.ts:16`, `ast-grep-tool-logger.ts:28`, `bus-events-logger.ts:43`, `cascade-logger.ts:10`, `dead-code-logger.ts:22`, `diagnostic-logger.ts:90`, `disposition-logger.ts:32`, `latency-logger.ts:10`, `read-guard-logger.ts:17`, `review-graph-logger.ts:16`, `sessionstart-logger.ts:12`, `tree-sitter-logger.ts:11`, `word-index-logger.ts:30` | subsystem log sinks | `createNdjsonLogger` consumers; no ExtensionAPI read, but host-owned process/filesystem policy is implicit | `log.sink` |
94
+ | `clients/debug-handles.ts:153`, `clients/debug-heap.ts:77` | optional diagnostic log sinks | `createNdjsonLogger` consumers gated by environment | `log.sink` |
95
+
96
+ ## Draft `HostPorts` shape
97
+
98
+ This is intentionally an interface sketch for S2, not an implementation. It keeps host capabilities grouped by concern, makes live getters explicit where session replacement matters, and leaves engine data (`cwd`, file paths, and event payloads) as ordinary arguments rather than hiding them in a host object.
99
+
100
+ ```ts
101
+ export interface HostPorts {
102
+ readonly notify: {
103
+ user(message: string, level?: "info" | "warning" | "error"): void;
104
+ };
105
+ readonly trust: {
106
+ isProjectTrusted(): "trusted" | "untrusted" | "unknown";
107
+ };
108
+ readonly mode: {
109
+ current(): "tui" | "rpc" | "json" | "print" | "unknown";
110
+ supportsTuiWidget(): boolean;
111
+ suppressesUserNotify(): boolean;
112
+ };
113
+ readonly log: {
114
+ extension(entry: { subsystem: string; message: string; level?: string; metadata?: Record<string, unknown> }): void;
115
+ debug(message: string, metadata?: Record<string, unknown>): void;
116
+ /** Subsystem NDJSON sink factory (the 13 subsystem-logger rows + debug
117
+ * sinks) — host owns the directory/retention policy. */
118
+ sink(subsystem: string): (entry: object) => void;
119
+ };
120
+ readonly emit: {
121
+ bus(channel: string, payload: unknown): void;
122
+ lens(channel: string, payload: unknown): void;
123
+ };
124
+ readonly status: {
125
+ set(name: string, value: string): void;
126
+ };
127
+ readonly spawn: {
128
+ abortSignal(): AbortSignal | undefined;
129
+ /** Trust-gated install/materialization policy (clients/project-trust.ts assertInstallAllowed; adapter-surface today -- callers in index.ts). */
130
+ isAllowed(context: string): boolean;
131
+ };
132
+ readonly render: {
133
+ invalidate(): void;
134
+ };
135
+ readonly session: {
136
+ id(): string | undefined;
137
+ };
138
+ readonly workspace: {
139
+ cwd(): string | undefined;
140
+ projectRoot(): string | undefined;
141
+ };
142
+ readonly flags: {
143
+ get(name: string, filePath?: string): string | boolean | undefined;
144
+ };
145
+ readonly tools: {
146
+ has(name: string): Promise<boolean>;
147
+ getActive(): string[];
148
+ setActive(names: string[]): void;
149
+ };
150
+ }
151
+ ```
152
+
153
+ ## Four hardest migrations
154
+
155
+ 1. **Dispatch runner context fan-out (`clients/dispatch/runners/*`, especially `tree-sitter.ts`, `lsp.ts`, and `ast-grep-napi.ts`).** Dozens of runners read `cwd`, availability, flags, and logging through `DispatchContext`; replacing these safely requires separating engine context from host projections without changing runner scheduling or fallback semantics. The existing `PiAgentAPI` is only a flag fragment, so this is the largest mechanical and typing migration.
156
+
157
+ 2. **Turn-scoped abort propagation (`index.ts` → `setAmbientAbortSignal` → `clients/safe-spawn.ts`).** The ambient signal is intentionally available deep inside arbitrary child-spawn paths, and its correctness depends on lifecycle ordering and clearing every settle path. A port must preserve cancellation, session replacement, and print-mode handle behavior without reintroducing captured-context races.
158
+
159
+ 3. **Session-bound UI/status and event delivery (`clients/runtime-tool-call.ts`, `clients/widget-state.ts`, and the bus/event publishers).** UI getters, status setters, render invalidation, and event emitters can all outlive the context that supplied them. The existing getter seams solve some cases, but consolidating them requires preserving delivery-time resolution, dropped-event observability, and no-throw behavior across TUI/RPC/MCP hosts.
160
+
161
+ 4. **Read-guard tool-event seam** (`index.ts:1722-1734` → `clients/runtime-tool-call.ts`; `index.ts:1739-1745` → `clients/runtime-tool-result.ts`): the tool-call/tool-result coupling and strict ordering make this at least as hard as the UI/event migration — the port must preserve event order and the paired-call identity across session replacement (#1360 review addition).
162
+
163
+ ## S2 recommendation
164
+
165
+ Implement `HostPorts` as a host-neutral capability object assembled by each adapter, but migrate one capability family at a time behind the existing seams: first notify/trust/mode, then emit/log/status/render, then workspace/flags/tools/session/spawn. Keep current getters as canonical adapter implementations during the transition, and add a contract test that the MCP and pi adapters provide the same defaults (no-op notify/emit/status/render, unknown trust/mode, and no ambient abort) before changing engine call signatures.