@herbertgao/pi-extensions 2026.8.3 → 2026.8.5

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 (408) hide show
  1. package/README.md +45 -4
  2. package/examples/pi-footer.json +275 -0
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
  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 +5 -8
  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 +8 -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 +15 -2
  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/schedule-menu.ts +9 -8
  25. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  26. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  27. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  30. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  31. package/node_modules/@narumitw/pi-btw/README.md +8 -7
  32. package/node_modules/@narumitw/pi-btw/package.json +2 -2
  33. package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
  34. package/node_modules/pi-footer/CHANGELOG.md +145 -0
  35. package/node_modules/pi-footer/LICENSE +21 -0
  36. package/node_modules/pi-footer/README.md +354 -0
  37. package/node_modules/pi-footer/package.json +68 -0
  38. package/node_modules/pi-footer/src/cache.ts +106 -0
  39. package/node_modules/pi-footer/src/colors.ts +237 -0
  40. package/node_modules/pi-footer/src/config.ts +202 -0
  41. package/node_modules/pi-footer/src/event-widgets.ts +41 -0
  42. package/node_modules/pi-footer/src/extension-statuses.ts +102 -0
  43. package/node_modules/pi-footer/src/git.ts +135 -0
  44. package/node_modules/pi-footer/src/index.ts +268 -0
  45. package/node_modules/pi-footer/src/metrics.ts +141 -0
  46. package/node_modules/pi-footer/src/presets.ts +383 -0
  47. package/node_modules/pi-footer/src/render.ts +114 -0
  48. package/node_modules/pi-footer/src/separators.ts +52 -0
  49. package/node_modules/pi-footer/src/types.ts +122 -0
  50. package/node_modules/pi-footer/src/ui/color-level-confirm.ts +22 -0
  51. package/node_modules/pi-footer/src/ui/color-options.ts +195 -0
  52. package/node_modules/pi-footer/src/ui/config-lifecycle.ts +61 -0
  53. package/node_modules/pi-footer/src/ui/edit-colors.ts +13 -0
  54. package/node_modules/pi-footer/src/ui/events.ts +35 -0
  55. package/node_modules/pi-footer/src/ui/extension-status-picker.ts +60 -0
  56. package/node_modules/pi-footer/src/ui/extension-statuses.ts +73 -0
  57. package/node_modules/pi-footer/src/ui/fields.ts +252 -0
  58. package/node_modules/pi-footer/src/ui/global-menu.ts +126 -0
  59. package/node_modules/pi-footer/src/ui/helpers.ts +44 -0
  60. package/node_modules/pi-footer/src/ui/layout.ts +17 -0
  61. package/node_modules/pi-footer/src/ui/line-list.ts +19 -0
  62. package/node_modules/pi-footer/src/ui/model.ts +64 -0
  63. package/node_modules/pi-footer/src/ui/navigation.ts +29 -0
  64. package/node_modules/pi-footer/src/ui/option-edit.ts +93 -0
  65. package/node_modules/pi-footer/src/ui/overlay-render.ts +103 -0
  66. package/node_modules/pi-footer/src/ui/screen-context.ts +18 -0
  67. package/node_modules/pi-footer/src/ui/screen-controller.ts +27 -0
  68. package/node_modules/pi-footer/src/ui/screen-render.ts +32 -0
  69. package/node_modules/pi-footer/src/ui/screen-state.ts +20 -0
  70. package/node_modules/pi-footer/src/ui/screen.ts +243 -0
  71. package/node_modules/pi-footer/src/ui/screens/add-widget.ts +92 -0
  72. package/node_modules/pi-footer/src/ui/screens/confirm-exit.ts +52 -0
  73. package/node_modules/pi-footer/src/ui/screens/controller.ts +12 -0
  74. package/node_modules/pi-footer/src/ui/screens/edit-colors.ts +68 -0
  75. package/node_modules/pi-footer/src/ui/screens/edit-widget.ts +115 -0
  76. package/node_modules/pi-footer/src/ui/screens/extension-status-row.ts +61 -0
  77. package/node_modules/pi-footer/src/ui/screens/global.ts +75 -0
  78. package/node_modules/pi-footer/src/ui/screens/line-list.ts +108 -0
  79. package/node_modules/pi-footer/src/ui/screens/main.ts +99 -0
  80. package/node_modules/pi-footer/src/ui/screens/terminal.ts +121 -0
  81. package/node_modules/pi-footer/src/ui/screens/widget-list.ts +154 -0
  82. package/node_modules/pi-footer/src/ui/terminal-menu.ts +32 -0
  83. package/node_modules/pi-footer/src/ui/theme.ts +48 -0
  84. package/node_modules/pi-footer/src/ui/title-bar.ts +100 -0
  85. package/node_modules/pi-footer/src/ui/widget-actions.ts +76 -0
  86. package/node_modules/pi-footer/src/ui.ts +66 -0
  87. package/node_modules/pi-footer/src/widgets/context.ts +28 -0
  88. package/node_modules/pi-footer/src/widgets/core/active-tools.ts +17 -0
  89. package/node_modules/pi-footer/src/widgets/core/context-window.ts +24 -0
  90. package/node_modules/pi-footer/src/widgets/core/cwd-basename.ts +19 -0
  91. package/node_modules/pi-footer/src/widgets/core/cwd.ts +108 -0
  92. package/node_modules/pi-footer/src/widgets/core/event.ts +34 -0
  93. package/node_modules/pi-footer/src/widgets/core/external-status.ts +102 -0
  94. package/node_modules/pi-footer/src/widgets/core/model-provider.ts +20 -0
  95. package/node_modules/pi-footer/src/widgets/core/model.ts +35 -0
  96. package/node_modules/pi-footer/src/widgets/core/provider.ts +17 -0
  97. package/node_modules/pi-footer/src/widgets/core/session-name.ts +17 -0
  98. package/node_modules/pi-footer/src/widgets/core/text-verbosity.ts +17 -0
  99. package/node_modules/pi-footer/src/widgets/core/thinking-level.ts +17 -0
  100. package/node_modules/pi-footer/src/widgets/git/ahead-behind.ts +17 -0
  101. package/node_modules/pi-footer/src/widgets/git/branch.ts +81 -0
  102. package/node_modules/pi-footer/src/widgets/git/clean.ts +19 -0
  103. package/node_modules/pi-footer/src/widgets/git/deletions.ts +17 -0
  104. package/node_modules/pi-footer/src/widgets/git/diff.ts +38 -0
  105. package/node_modules/pi-footer/src/widgets/git/insertions.ts +17 -0
  106. package/node_modules/pi-footer/src/widgets/git/remote.ts +17 -0
  107. package/node_modules/pi-footer/src/widgets/git/root.ts +17 -0
  108. package/node_modules/pi-footer/src/widgets/git/sha.ts +17 -0
  109. package/node_modules/pi-footer/src/widgets/git/staged.ts +17 -0
  110. package/node_modules/pi-footer/src/widgets/git/status.ts +19 -0
  111. package/node_modules/pi-footer/src/widgets/git/unstaged.ts +17 -0
  112. package/node_modules/pi-footer/src/widgets/git/untracked.ts +17 -0
  113. package/node_modules/pi-footer/src/widgets/instance.ts +118 -0
  114. package/node_modules/pi-footer/src/widgets/layout/custom-text.ts +18 -0
  115. package/node_modules/pi-footer/src/widgets/layout/flex-separator.ts +32 -0
  116. package/node_modules/pi-footer/src/widgets/layout/separator.ts +57 -0
  117. package/node_modules/pi-footer/src/widgets/layout/spacer.ts +31 -0
  118. package/node_modules/pi-footer/src/widgets/options.ts +122 -0
  119. package/node_modules/pi-footer/src/widgets/project/runtime.ts +361 -0
  120. package/node_modules/pi-footer/src/widgets/registry.ts +223 -0
  121. package/node_modules/pi-footer/src/widgets/session/assistant-messages.ts +17 -0
  122. package/node_modules/pi-footer/src/widgets/session/compactions.ts +17 -0
  123. package/node_modules/pi-footer/src/widgets/session/elapsed.ts +18 -0
  124. package/node_modules/pi-footer/src/widgets/session/last-activity.ts +18 -0
  125. package/node_modules/pi-footer/src/widgets/session/messages.ts +19 -0
  126. package/node_modules/pi-footer/src/widgets/session/session-id.ts +17 -0
  127. package/node_modules/pi-footer/src/widgets/session/session-start.ts +18 -0
  128. package/node_modules/pi-footer/src/widgets/session/tool-results.ts +17 -0
  129. package/node_modules/pi-footer/src/widgets/session/total-messages.ts +19 -0
  130. package/node_modules/pi-footer/src/widgets/session/total-time.ts +18 -0
  131. package/node_modules/pi-footer/src/widgets/session/user-messages.ts +17 -0
  132. package/node_modules/pi-footer/src/widgets/store.ts +26 -0
  133. package/node_modules/pi-footer/src/widgets/tokens/cache-hit-rate.ts +55 -0
  134. package/node_modules/pi-footer/src/widgets/tokens/cache-read.ts +18 -0
  135. package/node_modules/pi-footer/src/widgets/tokens/cache-write.ts +18 -0
  136. package/node_modules/pi-footer/src/widgets/tokens/context-bar.ts +108 -0
  137. package/node_modules/pi-footer/src/widgets/tokens/context-length.ts +26 -0
  138. package/node_modules/pi-footer/src/widgets/tokens/context-remaining.ts +29 -0
  139. package/node_modules/pi-footer/src/widgets/tokens/context.ts +29 -0
  140. package/node_modules/pi-footer/src/widgets/tokens/cost.ts +51 -0
  141. package/node_modules/pi-footer/src/widgets/tokens/input-speed.ts +25 -0
  142. package/node_modules/pi-footer/src/widgets/tokens/input-tokens.ts +18 -0
  143. package/node_modules/pi-footer/src/widgets/tokens/output-speed.ts +25 -0
  144. package/node_modules/pi-footer/src/widgets/tokens/output-tokens.ts +18 -0
  145. package/node_modules/pi-footer/src/widgets/tokens/tokens.ts +20 -0
  146. package/node_modules/pi-footer/src/widgets/tokens/total-speed.ts +25 -0
  147. package/node_modules/pi-footer/src/widgets/tokens/total-tokens.ts +18 -0
  148. package/node_modules/pi-footer/src/widgets/types.ts +181 -0
  149. package/node_modules/pi-footer/src/widgets/utils/colors.ts +11 -0
  150. package/node_modules/pi-footer/src/widgets/utils/context.ts +112 -0
  151. package/node_modules/pi-footer/src/widgets/utils/session.ts +19 -0
  152. package/node_modules/pi-footer/src/widgets/utils/token-format.ts +78 -0
  153. package/node_modules/pi-lens/CHANGELOG.md +2440 -954
  154. package/node_modules/pi-lens/README.md +13 -0
  155. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  156. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  157. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  158. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  159. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  160. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  161. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  162. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  163. package/node_modules/pi-lens/dist/clients/biome-client.js +29 -25
  164. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  165. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  166. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  167. package/node_modules/pi-lens/dist/clients/bus-publish.js +10 -3
  168. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  169. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  170. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  171. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  172. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  173. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  174. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  175. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  176. package/node_modules/pi-lens/dist/clients/console-guard-install.js +14 -0
  177. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  178. package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
  179. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  180. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  181. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  182. package/node_modules/pi-lens/dist/clients/dependency-checker.js +347 -75
  183. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
  184. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
  185. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
  186. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  187. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  188. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  189. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  190. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  191. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1085 -681
  192. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  193. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  194. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  195. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  196. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  197. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  198. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  199. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  200. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  201. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  202. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  203. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +14 -6
  204. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  205. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  206. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  207. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  208. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  209. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  210. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  211. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  212. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  213. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  214. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  215. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  216. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
  217. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  218. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  219. package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
  220. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  221. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  222. package/node_modules/pi-lens/dist/clients/extension-log.js +139 -0
  223. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  224. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  225. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  226. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  227. package/node_modules/pi-lens/dist/clients/format-events-publish.js +16 -3
  228. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  229. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  230. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  231. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  232. package/node_modules/pi-lens/dist/clients/git-guard.js +681 -11
  233. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  234. package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
  235. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
  236. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  237. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  238. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  239. package/node_modules/pi-lens/dist/clients/installer/index.js +390 -99
  240. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  241. package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
  242. package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
  243. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  244. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  245. package/node_modules/pi-lens/dist/clients/latency-logger.js +23 -1
  246. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  247. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  248. package/node_modules/pi-lens/dist/clients/lens-events.js +27 -4
  249. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  250. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  251. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
  252. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  253. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
  254. package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
  255. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  256. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
  257. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  258. package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
  259. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  260. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  261. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  262. package/node_modules/pi-lens/dist/clients/lsp/server.js +196 -32
  263. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  264. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  265. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  266. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +123 -32
  267. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  268. package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
  269. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  270. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  271. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  272. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  273. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  274. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  275. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  276. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  277. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  278. package/node_modules/pi-lens/dist/clients/pipeline.js +47 -13
  279. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  280. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  281. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  282. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  283. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  284. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  285. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  286. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  287. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  288. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  289. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  290. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  291. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  292. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  293. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  294. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  295. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  296. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  297. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  298. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  299. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  300. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  301. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  302. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +107 -73
  303. package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
  304. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
  305. package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -117
  306. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  307. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +218 -23
  308. package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
  309. package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
  310. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  311. package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
  312. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  313. package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
  314. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  315. package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -0
  316. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  317. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  318. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  319. package/node_modules/pi-lens/dist/clients/startup-timing.js +1 -1
  320. package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
  321. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  322. package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
  323. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  324. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  325. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  326. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  327. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  328. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  329. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  330. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  331. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  332. package/node_modules/pi-lens/dist/clients/warm-attach.js +33 -13
  333. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  334. package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
  335. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  336. package/node_modules/pi-lens/dist/index.js +49361 -36888
  337. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  338. package/node_modules/pi-lens/dist/mcp/server.js +211 -44
  339. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  340. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
  341. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
  342. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  343. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  344. package/node_modules/pi-lens/docs/agent-guide.md +2 -2
  345. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  346. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  347. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  348. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -2
  349. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  350. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  351. package/node_modules/pi-lens/docs/fable.md +27 -0
  352. package/node_modules/pi-lens/docs/features.md +31 -2
  353. package/node_modules/pi-lens/docs/globalconfig.md +45 -1
  354. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  355. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  356. package/node_modules/pi-lens/docs/mcp.md +37 -4
  357. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  358. package/node_modules/pi-lens/docs/settings.md +12 -1
  359. package/node_modules/pi-lens/docs/tools.md +4 -1
  360. package/node_modules/pi-lens/docs/usage.md +18 -0
  361. package/node_modules/pi-lens/package.json +10 -10
  362. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  363. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  364. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  365. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  366. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  367. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  368. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  369. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  370. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  371. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  372. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  373. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  374. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +55 -2
  375. package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
  376. package/node_modules/pi-mcp-adapter/README.md +34 -3
  377. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  378. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  379. package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
  380. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  381. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  382. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  383. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  384. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  385. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  386. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  387. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  388. package/node_modules/pi-mcp-adapter/metadata-cache.ts +27 -4
  389. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  390. package/node_modules/pi-mcp-adapter/package.json +3 -3
  391. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  392. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  393. package/node_modules/pi-mcp-adapter/server-manager.ts +36 -7
  394. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  395. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  396. package/node_modules/pi-mcp-adapter/tool-metadata.ts +42 -4
  397. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  398. package/node_modules/pi-mcp-adapter/types.ts +93 -27
  399. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  400. package/package.json +17 -13
  401. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  402. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  403. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  404. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  405. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  406. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  407. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  408. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  <!-- GENERATED by scripts/gen-rule-catalogs.mjs — do not edit by hand. Run `npm run docs:rule-catalogs` after changing rules. -->
4
4
 
5
- pi-lens bundles **435 enabled** ast-grep rules (251 pi-lens-authored + 184 vendored from CodeRabbit) across **16 languages**, plus 16 disabled.
5
+ pi-lens bundles **438 enabled** ast-grep rules (254 pi-lens-authored + 184 vendored from CodeRabbit) across **16 languages**, plus 16 disabled.
6
6
 
7
7
  See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `rules/ast-grep-rules/rules/` (pi-lens), `rules/ast-grep-rules/coderabbit/rules/` (vendored).
8
8
 
@@ -401,7 +401,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
401
401
  | `redundant-usestate-type` | info | pi-lens | `useState<TYPE>(...)` where TYPE is a primitive redundant — TS can infer it from the initial value |
402
402
  | `unnecessary-react-hook` | warning | pi-lens | Function with a `use*` name does not call any other React hook — rename to a plain function |
403
403
 
404
- ### TypeScript (117)
404
+ ### TypeScript (120)
405
405
 
406
406
  | Rule | Severity | Source | Description |
407
407
  |---|---|---|---|
@@ -429,6 +429,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
429
429
  | `no-await-expression-member` | hint | pi-lens | Unnecessary parentheses around await — write await expr.prop directly |
430
430
  | `no-await-in-promise-all` | error | pi-lens | Avoid await inside Promise.all — use Promise.all with an array of promises instead |
431
431
  | `no-await-in-promise-methods` | warning | pi-lens | Do not await inside Promise.all/allSettled — pass the promises directly |
432
+ | `no-bare-host-path-in-win32-branch` | warning | pi-lens | Use win32 path operations inside a branch committed to Windows path semantics |
432
433
  | `no-case-declarations` | error | pi-lens | Unexpected lexical declaration in case block — wrap in braces to restrict scope |
433
434
  | `no-compare-neg-zero` | error | pi-lens | Disallow comparing against -0 |
434
435
  | `no-cond-assign` | error | pi-lens | Expected a conditional expression and instead saw an assignment. |
@@ -456,6 +457,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
456
457
  | `no-open-redirect` | error | pi-lens | Potential open redirect vulnerability — validate redirect URLs |
457
458
  | `no-prototype-builtins` | error | pi-lens | Use Object.hasOwn() or Object.prototype.hasOwnProperty.call() instead of calling methods directly on the object |
458
459
  | `no-prototype-builtins-native` | hint | pi-lens | Use Object.hasOwn() instead of hasOwnProperty() — ES2022 standard |
460
+ | `no-raw-json-store-write` | warning | pi-lens | Use the atomic write seam for JSON stores instead of writeFileSync |
459
461
  | `no-relative-cross-package-import` | info | pi-lens | Avoid relative imports across package boundaries (../../). Use absolute imports (@app/..., @components/...) for better agent reasoning abou… |
460
462
  | `no-return-await` | warning | pi-lens | Unnecessary 'await' in return statement — use direct return instead |
461
463
  | `no-single-promise-in-promise-methods` | warning | pi-lens | Promise.all/race with a single promise is unnecessary — await it directly |
@@ -468,6 +470,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
468
470
  | `no-useless-length-check` | warning | pi-lens | Use .some() instead of .filter().length check — short-circuits at first match |
469
471
  | `no-useless-promise-resolve-reject` | warning | pi-lens | Unnecessary Promise.resolve/reject wrapping — return the value directly |
470
472
  | `no-useless-rest-spread` | warning | pi-lens | Redundant spread into same container type — remove the extra spread |
473
+ | `no-win32-isabsolute-for-qualification` | warning | pi-lens | Use isFullyQualified for path qualification instead of win32.isAbsolute |
471
474
  | `node-rsa-weak-key-typescript` | warning | CodeRabbit | Use of RSA-$BITS, which is considered weak. Based on NIST standards, RSA keys should be at least 2048 bits. |
472
475
  | `node-sequelize-empty-password-argument-typescript` | warning | CodeRabbit | The application creates a database connection with an empty password. This can lead to unauthorized access by either an internal or externa… |
473
476
  | `node-sequelize-hardcoded-secret-argument-typescript` | warning | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
@@ -0,0 +1,32 @@
1
+ # Durable-store cross-process audit (#1202)
2
+
3
+ Atomic rename prevents torn files; it does not serialize read-modify-write. This
4
+ audit classifies stores reachable by extension, MCP, CLI, and subagent processes.
5
+ `<project>` means `getProjectDataDir(cwd)` and `<global>` means
6
+ `getGlobalPiLensDir()`.
7
+
8
+ | Store and path | Racing writers | Semantics | Risk | Existing mitigation / decision |
9
+ |---|---|---|---|---|
10
+ | Turn state — `<project>/turn-state.json` | extension, MCP, CLI; subagents use distinct owners | read-modify-write worklist | (a) impossible | **fixed here:** deferred-format writes now carry the pi session owner, and `clearTurnState` / `incrementTurnCycle` reject a foreign live owner just like `addModifiedRange`; MCP turn-end operations are FIFO-serialized. |
11
+ | Scanner caches — `<project>/cache/{scanner}.json` + `{scanner}.meta.json` | extension, MCP, CLI, subagents | overwrite-only scan result + freshness metadata | (b) possible, benign | none; a losing cache publication is recoverable on the next scan. Data is written before metadata, so interruption cannot make old data newly fresh; concurrent last-finisher wins. |
12
+ | Rule cache — `<project>/cache/{language}-rules-3.json` | all analysis processes | overwrite-only, content-hash validated | (a) impossible | rule hash rejects a cache for different inputs. |
13
+ | Workspace diagnostics — `<project>/cache/lsp-workspace-diagnostics.json` | extension/MCP/CLI sweeps and subagents | read-merge-overwrite cache | (b) possible, benign | mtime/content/dependency freshness rejects stale entries; a lost entry causes a rescan. Accepted benign. |
14
+ | Call graph — `<project>/cache/call-graph.json` + `.meta.json` | extension/MCP/CLI graph builds, subagents | overwrite-only derived graph | (b) possible, benign | source freshness validation; a loss rebuilds from source. Accepted benign. |
15
+ | Codebase model — `<project>/cache/codebase-model.json` + `.meta.json` | extension/MCP/CLI builds, subagents | overwrite-only derived model | (b) possible, benign | source/file-set validation; a loss rebuilds. Accepted benign. |
16
+ | Actionable-warning state — `<project>/cache/actionable-warning-state.json` | dispatches in every process | read-merge-overwrite behavior gate | (c) possible, harmful | **fixed here:** bounded exclusive pid lock, in-lock disk re-read, and per-warning merge preserve concurrent suppression fields before atomic replacement. |
17
+ | Actionable-warning history — `<project>/actionable-warnings.jsonl` | every dispatcher | append-only telemetry | (b) possible, benign | one append call per batch; malformed/truncated telemetry lines are ignored. Accepted benign. |
18
+ | Metrics history — `<project>/metrics-history.json` | session scans and `/lens-metrics` in every process | read-modify-overwrite trend cache | (c) possible, harmful | **accepted loss:** telemetry only; a race can leave a user-visible gap in trend history, but gaps are self-healing after the next scan restores the latest snapshot. Locking every passive capture or restructuring the established bounded JSON format is disproportionate to advisory history. |
19
+ | Project diagnostics — `<project>/cache/project-diagnostics.json` and `project-diagnostics-delta.json` | extension/MCP/CLI scans, subagents | overwrite-only derived snapshots | (b) possible, benign | per-file mtime filtering; next scan replaces loss. Accepted benign. |
20
+ | Worklog — `<project>/worklog.jsonl` | all dispatchers | append-only best-effort telemetry | (b) possible, benign | OS append operation per batch; readers skip malformed lines. Accepted benign. |
21
+ | Widget/read-guard session state — `<project>/sessions/{sessionId}.json` | one extension host per stable session id | overwrite-only session snapshot | (a) impossible | session-id sharding; read guard and widget are co-snapshotted atomically. |
22
+ | Diagnostic dispositions — `<project>/cache/diagnostic-dispositions.json` | extension, MCP, CLI tools, subagents | read-modify-write behavior gate | (c) possible, harmful | **fixed here:** exclusive pid lock, in-lock disk re-read, and per-anchor merge refuse stale whole-file promotion. |
23
+ | Recent touches — `<project>/recent-touches.json` | every extension/subagent publisher | read-append-overwrite bounded attribution ring | (b) possible, benign | explicitly best-effort nudge attribution; lost entries do not gate edits/checks and later touches replenish it. Accepted benign. |
24
+ | Instance registry — `<global>/instances.json` | every host/MCP/subagent process and reaper | read-modify-overwrite observability registry | (b) possible, benign | explicitly best-effort. Backstop orphan reaping intentionally kills untracked managed processes on dead-parent confirmation; missing registry entries allow this (intentional, #1267-adjacent; no fix needed). |
25
+ | Project snapshot — `<project>/cache/project-snapshot.json.gz` + `.meta.json` | extension/MCP/CLI builders, subagents | monotonic derived snapshot | (a) impossible | durable project sequence/source identity and generation-gated staged promotion; body embeds its seq so mismatched metadata is rejected. |
26
+ | Review graph + checkpoint — `<project>/cache/review-graph.json.gz`, `review-graph.checkpoint.json.gz` | extension/MCP/CLI builders, subagents | overwrite-only derived graph | (a) impossible | source signature/project-seq validation plus staged, generation-gated promotion; stale content is rejected on load. |
27
+ | Probe cache — `<global>/probe-cache.json` | every installer/prober | read-modify-write tool availability | (a) impossible | existing bounded cross-process lock + in-lock re-read/change merge (#1263). |
28
+ | Stop-hook status — OS temp `pi-lens-turn-end-*.json` | concurrent CLI Stop hooks | read-modify-overwrite counters | (b) possible, benign | atomic publication; explicitly bounded best-effort telemetry. Accepted benign. |
29
+
30
+ The grammar/WASM destination files are immutable content assets, not shared
31
+ mutable stores. Atomic staging artifacts are covered separately by the bounded
32
+ session-start stage GC and are not authoritative stores.
@@ -195,6 +195,33 @@ honored.
195
195
  Node cap for `/lens-map` (default 500). Graphs with more files keep only the
196
196
  highest-degree ones and render a visible truncation note.
197
197
 
198
+ ## Memory / idle eviction
199
+
200
+ Several in-memory caches release their contents after a period of inactivity so a
201
+ long-running session does not retain hydrated state indefinitely. Each has an
202
+ env-tunable window; all default to 20 minutes (`1200000` ms).
203
+
204
+ ### `PI_LENS_TS_IDLE_EVICT_MS`
205
+
206
+ Idle window (ms) after which TypeScript language-service clients release their
207
+ hydrated program and shut down, rebuilding transparently on the next request.
208
+ **Default:** 20 minutes (`1200000`).
209
+
210
+ ### `PI_LENS_WORD_INDEX_IDLE_EVICT_MS`
211
+
212
+ Idle window (ms) after which the persisted word index (`symbol_search`'s BM25
213
+ index) is released from memory. **Default:** 20 minutes (`1200000`).
214
+
215
+ ### `PI_LENS_PROJECT_SNAPSHOT_IDLE_EVICT_MS`
216
+
217
+ Idle window (ms) after which the cached project snapshot is released from
218
+ memory. **Default:** 20 minutes (`1200000`).
219
+
220
+ ### `PI_LENS_REVIEW_GRAPH_IDLE_EVICT_MS`
221
+
222
+ Idle window (ms) after which the in-memory review graph (`file → symbol →
223
+ dependency`) is released. **Default:** 20 minutes (`1200000`).
224
+
198
225
  ## Bus events
199
226
 
200
227
  ### `PI_LENS_BUS_PUBLISH`
@@ -213,6 +240,23 @@ misbehaves.
213
240
  Set to `1` for verbose installer/debug logging (same as `--debug`). Off by
214
241
  default.
215
242
 
243
+ ### `PI_LENS_DEBUG_HANDLES`
244
+
245
+ Set to `1` **before starting pi** to enable the handle-origin tracer
246
+ (institutionalized from the #1097 hand-rolled `async_hooks` investigation
247
+ that root-caused a leaked `setTimeout` keeping a `--print --no-session`
248
+ process alive). Read once at extension load — toggling it mid-session has no
249
+ effect. When set, pi-lens dumps `process.getActiveResourcesInfo()` counts by
250
+ resource type (plus per-type creation-site stack attribution, since the
251
+ `async_hooks` tracker only installs when the flag was already on at startup)
252
+ to `~/.pi-lens/debug-handles.log` at two points: `agent_settled` (after
253
+ quiet-window work is scheduled) and `session_shutdown` (after teardown —
254
+ whatever is still alive at that point is the leak). Off by default, and a
255
+ true no-op when unset — no writer, no `async_hooks` hook, zero overhead. Use
256
+ it to diagnose a pi process that won't exit: run once with the flag set,
257
+ reproduce the hang, then check `debug-handles.log`'s `session_shutdown`
258
+ entry for what's still holding the loop open.
259
+
216
260
  ### `PI_LENS_LOG_RETENTION_DAYS`
217
261
 
218
262
  Days to keep rotated logs before cleanup. **Default:** `7`.
@@ -138,3 +138,30 @@ inventory earning nothing. Feeding transitive impact into cascade neighbor
138
138
  selection is probably the highest-leverage *feature* work available — ideally
139
139
  paired with the #202 structural-hash short-circuit so the expansion prunes
140
140
  when a changed file's exported interface is unchanged.
141
+
142
+ ## OS-agnostic paths: classification is centralized, transformation isn't (#1193)
143
+
144
+ The path-*shape* layer is genuinely unified — `isWindowsPath`, the
145
+ `win32`-vs-`posix` shape-conditional idiom (confined to 4 files), `realpathSync`
146
+ (confined to `path-utils.ts`), `PathKeyedMap`, the `walkUpDirs` family, and the
147
+ `uriToPath`/`uriToDiskPath` LSP ingest boundary are all single-source and
148
+ defensively documented. The path-*transformation* layer is not: slash-folding
149
+ (`.replace(/\\/g, "/")`) is hand-rolled **138× across 83 files** with no shared
150
+ helper, `\r\n`-folding re-implements `normalizeToLF` in five files, and ephemeral
151
+ case/slash key-normalizers are copy-pasted in four (one of which case-folds but
152
+ forgets to slash-fold). That gap is why the *same* shape-2 defect keeps re-filing
153
+ under new numbers — #1150 → #1152 → #1161 → #1163 → #1194. Per-site
154
+ `isWindowsPath ? win32 : posix` conditionals treat symptoms; every new interior
155
+ `dirname`/`relative`/`isAbsolute` on a potentially-cross-shaped value is a fresh
156
+ latent instance. The tell: LSP URIs are the one axis with a real *ingest*
157
+ primitive, and the one axis not generating monthly bugs.
158
+
159
+ Highest-leverage move (**P1**, tracked in #1193): ship a `toPosix()` slash-fold
160
+ primitive and make it the only sanctioned form — it funnels the 138 sites *and*
161
+ makes a shape-2 ast-grep rule **possible** for the first time (today the idiom and
162
+ the bug are byte-identical, so #1158 can't distinguish them; an *un-migrated*
163
+ `.replace` after the primitive exists is detectable). Then push normalization to
164
+ the four ingest boundaries — **persisted-key rehydrate** (snapshot / word-index /
165
+ call-graph / review-graph symbol keys written on Windows, read on Linux CI) is the
166
+ hot one — so interior code can once again trust host-default `path` fns. Full P1–P5
167
+ plan + enforcement in #1193; the latest missed member fixed in #1194.