@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
@@ -31,6 +31,7 @@ import * as fs from "node:fs";
31
31
  import * as path from "node:path";
32
32
  import { isExcludedDirName } from "./file-utils.js";
33
33
  import { isGeneratedArtifactDirectoryName } from "./generated-artifacts.js";
34
+ import { createDeadline, yieldIfOverBudget, } from "./cooperative-budget.js";
34
35
  /**
35
36
  * Read a directory's entries, returning `[]` for a permission-denied or
36
37
  * missing directory instead of throwing. Shared by every walker below — a
@@ -46,12 +47,46 @@ export function readDirEntriesSafe(dirPath) {
46
47
  return [];
47
48
  }
48
49
  }
50
+ /**
51
+ * Async twin of {@link readDirEntriesSafe} (refs #1137) — the identical
52
+ * "unreadable directory yields no entries" contract, but the read itself
53
+ * happens off the event loop via `fs.promises.readdir`.
54
+ *
55
+ * Why this exists: chunked yielding is NOT sufficient to keep the loop free.
56
+ * `walkTreeStackAsync` already `setImmediate`-yielded every N entries, yet each
57
+ * per-directory read was still `readdirSync` — so on a cloud-backed tree
58
+ * (OneDrive, network drive) one stalled directory read blocked the Node loop,
59
+ * and pi's TUI, for the *entire* stall regardless of yield cadence. That is the
60
+ * exact shape #1170 already fixed in `pipeline.ts`'s autofix snapshot walk
61
+ * ("the walk was already async + chunk-yielding, but each synchronous per-dir
62
+ * read still blocked on a cloud stall"); #1170 deferred the SHARED engine, and
63
+ * this is that same fix applied here — so every async walker gets it at once.
64
+ */
65
+ export async function readDirEntriesSafeAsync(dirPath) {
66
+ try {
67
+ return await fs.promises.readdir(dirPath, { withFileTypes: true });
68
+ }
69
+ catch {
70
+ return [];
71
+ }
72
+ }
49
73
  /**
50
74
  * The one shared "should this directory be walked into" decision. Every
51
75
  * caller's own loop still owns *when* to call this (inline recursion vs. a
52
76
  * stack) and what to do with the answer.
77
+ *
78
+ * `onGeneratedDirSkip` (#1107 phase 2) fires exactly once when — and only
79
+ * when — the `isGeneratedArtifactDirectoryName` branch is the reason this
80
+ * directory is pruned, so a caller can count PRUNED DIRECTORIES (one event
81
+ * per directory, regardless of how many files it contains) without
82
+ * enumerating the directory's contents — doing that would defeat the whole
83
+ * point of pruning it. Optional and unused by every caller except
84
+ * `source-filter.ts`'s `classifyEntry`: the other two `shouldRecurseIntoDir`
85
+ * callers (`language-profile.ts`, `startup-scan.ts`) always pass
86
+ * `skipGeneratedArtifactDirs: false`, so this branch — and therefore the
87
+ * callback — never fires for them.
53
88
  */
54
- export function shouldRecurseIntoDir(entry, fullPath, policy) {
89
+ export function shouldRecurseIntoDir(entry, fullPath, policy, onGeneratedDirSkip) {
55
90
  if (isExcludedDirName(entry.name, policy.extraExcludeDirs ?? [])) {
56
91
  return false;
57
92
  }
@@ -59,6 +94,7 @@ export function shouldRecurseIntoDir(entry, fullPath, policy) {
59
94
  return false;
60
95
  if (policy.skipGeneratedArtifactDirs === true &&
61
96
  isGeneratedArtifactDirectoryName(entry.name)) {
97
+ onGeneratedDirSkip?.();
62
98
  return false;
63
99
  }
64
100
  if (policy.followSymlinks !== true && entry.isSymbolicLink())
@@ -83,15 +119,24 @@ function* walkTreeStackSteps(rootDir, visit, shouldStop) {
83
119
  const dir = stack.pop();
84
120
  if (dir === undefined)
85
121
  continue;
122
+ // Directory-read REQUEST (#1137): the generator never reads the
123
+ // filesystem itself — it yields the directory path and the driver
124
+ // supplies the entries. That is what lets the sync driver stay
125
+ // `readdirSync` while the async driver reads via `fs.promises.readdir`
126
+ // WITHOUT forking the traversal into two implementations that can
127
+ // drift (the invariant this generator exists to protect).
128
+ const entries = (yield dir) ?? [];
86
129
  const subDirs = [];
87
- for (const entry of readDirEntriesSafe(dir)) {
130
+ for (const entry of entries) {
88
131
  const fullPath = path.join(dir, entry.name);
89
132
  const disposition = visit(entry, fullPath);
90
133
  if (disposition === "stop")
91
134
  return true;
92
135
  if (disposition === "recurse")
93
136
  subDirs.push(fullPath);
94
- yield;
137
+ // Per-entry yield point: `undefined` distinguishes it from a
138
+ // directory-read request above.
139
+ yield undefined;
95
140
  }
96
141
  for (let i = subDirs.length - 1; i >= 0; i--)
97
142
  stack.push(subDirs[i]);
@@ -106,27 +151,38 @@ function* walkTreeStackSteps(rootDir, visit, shouldStop) {
106
151
  export function walkTreeStackSync(rootDir, visit, opts = {}) {
107
152
  const steps = walkTreeStackSteps(rootDir, visit, opts.shouldStop);
108
153
  let step = steps.next();
109
- while (!step.done)
110
- step = steps.next();
154
+ while (!step.done) {
155
+ step = steps.next(step.value === undefined ? undefined : readDirEntriesSafe(step.value));
156
+ }
111
157
  return step.value;
112
158
  }
113
159
  /**
114
160
  * Async, chunked-yield twin of {@link walkTreeStackSync} — the identical
115
161
  * {@link walkTreeStackSteps} traversal, plus a `setImmediate` yield every
116
- * `yieldEvery` processed entries so a large tree never holds the event loop in
162
+ * its monotonic budget so a large tree never holds the event loop in
117
163
  * one synchronous burst. Returns true iff the visitor stopped the walk via
118
164
  * `"stop"`.
165
+ *
166
+ * #1137: every per-directory read goes through {@link readDirEntriesSafeAsync},
167
+ * so the walk is non-blocking on BOTH axes — CPU (the `setImmediate` cadence)
168
+ * and I/O (the directory read itself). The yield cadence alone never covered
169
+ * the I/O axis: a stalled cloud-backed `readdirSync` held the loop for the full
170
+ * stall no matter how often the walk yielded around it.
119
171
  */
120
172
  export async function walkTreeStackAsync(rootDir, visit, opts) {
121
173
  await opts.beforeWalk?.();
122
174
  const steps = walkTreeStackSteps(rootDir, visit, opts.shouldStop);
123
- let processedSinceYield = 0;
175
+ const deadline = createDeadline(opts.budgetMs ?? 8);
124
176
  let step = steps.next();
125
177
  while (!step.done) {
126
- if (++processedSinceYield >= opts.yieldEvery) {
127
- processedSinceYield = 0;
128
- await new Promise((resolve) => setImmediate(resolve));
178
+ if (step.value !== undefined) {
179
+ // Directory-read request — satisfy it off the loop. No
180
+ step = steps.next(await readDirEntriesSafeAsync(step.value));
181
+ deadline.reset();
182
+ continue;
129
183
  }
184
+ if (deadline.expired())
185
+ await yieldIfOverBudget(deadline);
130
186
  step = steps.next();
131
187
  }
132
188
  return step.value;
@@ -8,6 +8,8 @@
8
8
  */
9
9
  import * as os from "node:os";
10
10
  import * as path from "node:path";
11
+ import { BoundedLruCache } from "./bounded-cache.js";
12
+ import { normalizeMapKey } from "./path-utils.js";
11
13
  import { lazyEnvNumber } from "./env-utils.js";
12
14
  import { getProjectIgnoreMatcher, } from "./file-utils.js";
13
15
  import { isAtOrAboveHomeDir } from "./path-utils.js";
@@ -220,15 +222,18 @@ export function countSourceFilesWithinLimit(dir, limit) {
220
222
  // depends only on the file tree shape and ignore rules — both of which
221
223
  // are also captured by the project snapshot freshness check upstream —
222
224
  // in-process memoisation is safe for the duration of a single pi process.
223
- const startupScanContextCache = new Map();
225
+ const startupScanContextCache = new BoundedLruCache(32);
226
+ function startupScanCacheKey(cwd, options) {
227
+ return [
228
+ normalizeMapKey(path.resolve(cwd)),
229
+ options.homeDir ? normalizeMapKey(path.resolve(options.homeDir)) : "",
230
+ options.maxSourceFiles ?? "",
231
+ options.maxScanEntries ?? "",
232
+ ].join("|");
233
+ }
234
+ export const __testing = { startupScanCacheKey };
224
235
  export function resolveStartupScanContext(cwd, options = {}) {
225
- const cacheKey = path.resolve(cwd) +
226
- "|" +
227
- (options.homeDir ?? "") +
228
- "|" +
229
- (options.maxSourceFiles ?? "") +
230
- "|" +
231
- (options.maxScanEntries ?? "");
236
+ const cacheKey = startupScanCacheKey(cwd, options);
232
237
  const cached = startupScanContextCache.get(cacheKey);
233
238
  if (cached)
234
239
  return cached;
@@ -322,7 +327,7 @@ async function walkSourceCountAsync(dir, limit, maxEntries, opts = {}) {
322
327
  // ~0.1ms of overhead and a 2k-file project produces ~20 yields, so the
323
328
  // total async overhead is well under 5ms while keeping per-burst sync
324
329
  // work under 50ms (the perceptual threshold for "instant" keystrokes).
325
- yieldEvery: opts.yieldEvery ?? 100,
330
+ budgetMs: opts.budgetMs ?? 8,
326
331
  // #703: prime the tracked-files set ONCE before the walk (not per file)
327
332
  // so a tracked file matching a `.gitignore`/global pattern isn't dropped
328
333
  // from the startup source-file count. Fail-open: resolves even when git
@@ -338,13 +343,7 @@ export async function countSourceFilesWithinLimitAsync(dir, limit, opts = {}) {
338
343
  return (await walkSourceCountAsync(dir, limit, Number.POSITIVE_INFINITY, opts)).count;
339
344
  }
340
345
  export async function resolveStartupScanContextAsync(cwd, options = {}) {
341
- const cacheKey = path.resolve(cwd) +
342
- "|" +
343
- (options.homeDir ?? "") +
344
- "|" +
345
- (options.maxSourceFiles ?? "") +
346
- "|" +
347
- (options.maxScanEntries ?? "");
346
+ const cacheKey = startupScanCacheKey(cwd, options);
348
347
  const cached = startupScanContextCache.get(cacheKey);
349
348
  if (cached)
350
349
  return cached;
@@ -1,5 +1,5 @@
1
1
  import { performance } from "node:perf_hooks";
2
- import { PI_LENS_EVAL_STARTED_MS } from "./startup-marker.js";
2
+ import { PI_LENS_EVAL_STARTED_MS } from "./console-guard-install.js";
3
3
  /**
4
4
  * Startup timing for pi-lens.
5
5
  *
@@ -10,6 +10,7 @@
10
10
  * Design: File-level targeted testing — only runs tests for the
11
11
  * specific file being edited, not the entire suite.
12
12
  */
13
+ import { createSubsystemLogger } from "./extension-log.js";
13
14
  import * as fs from "node:fs";
14
15
  import * as path from "node:path";
15
16
  import { minimatch } from "./deps/minimatch.js";
@@ -64,7 +65,7 @@ const MAX_NODE_MODULES_WALK_UP = 5;
64
65
  // unbounded walk of the whole tests tree.
65
66
  const MAX_PYTEST_RECURSE_DEPTH = 3;
66
67
  // --- Runner Detection ---
67
- const RUNNERS = {
68
+ export const RUNNERS = {
68
69
  vitest: {
69
70
  configFiles: ["vitest.config.ts", "vitest.config.js", "vitest.config.mjs"],
70
71
  command: "npx",
@@ -140,6 +141,11 @@ const RUNNERS = {
140
141
  rspec: {
141
142
  configFiles: [".rspec", "spec/spec_helper.rb"],
142
143
  command: "bundle",
144
+ // The real binary is "bundle" (the command runs `bundle exec rspec
145
+ // <file>`), NOT "rspec" — without this, binName defaulted to the
146
+ // runner key "rspec" and local/global resolution looked for the wrong
147
+ // binary name (#1098).
148
+ binName: "bundle",
143
149
  args: (testFile, _cwd) => ["exec", "rspec", testFile],
144
150
  parseJson: false,
145
151
  },
@@ -166,6 +172,26 @@ const RUNNERS = {
166
172
  parseJson: false, // mix test's default output is text-based
167
173
  },
168
174
  };
175
+ /**
176
+ * Drop the leading arg(s) of a runner's args() that merely NAME the binary
177
+ * being invoked (the npx-wrapper convention: `npx vitest run …` → once
178
+ * `vitest` becomes the resolved command itself, the leading "vitest" arg is
179
+ * redundant). This must NOT strip a real subcommand.
180
+ *
181
+ * Two wrapper shapes are recognized:
182
+ * - `[binName, ...rest]` (vitest/jest-style: `npx <bin> ...`) → drop 1.
183
+ * - `["-m", binName, ...rest]` (pytest-style: `python -m <bin> ...`) → drop 2.
184
+ * Anything else (cargo's `["test", "--no-fail-fast"]`, go's
185
+ * `["test", "-run", …]`, rspec's `["exec", "rspec", file]` once binName is
186
+ * "bundle", etc.) is a real subcommand/argv and is returned unchanged (#1098).
187
+ */
188
+ export function stripWrapperArgs(binName, args) {
189
+ if (args[0] === binName)
190
+ return args.slice(1);
191
+ if (args[0] === "-m" && args[1] === binName)
192
+ return args.slice(2);
193
+ return args;
194
+ }
169
195
  // --- Client ---
170
196
  export class TestRunnerClient {
171
197
  log;
@@ -180,7 +206,7 @@ export class TestRunnerClient {
180
206
  vitestTestGlobsCache = new Map();
181
207
  constructor(verbose = false) {
182
208
  this.log = verbose
183
- ? (msg) => console.error(`[test-runner] ${msg}`)
209
+ ? createSubsystemLogger("test-runner")
184
210
  : () => { };
185
211
  }
186
212
  /**
@@ -1213,8 +1239,12 @@ export class TestRunnerClient {
1213
1239
  * Resolve the executable and args for a runner, preferring a local
1214
1240
  * node_modules/.bin binary over npx to avoid the ~150ms npx startup cost.
1215
1241
  *
1216
- * When a local binary is used, args()[0] (the runner name that npx needs)
1217
- * is dropped since it becomes the command itself.
1242
+ * When a resolved binary becomes the command itself, `stripWrapperArgs`
1243
+ * drops ONLY the leading arg(s) that named the wrapped binary — never a
1244
+ * real subcommand (#1098: `cargo test --no-fail-fast` unconditionally lost
1245
+ * `test` here because the old code assumed every runner's args() started
1246
+ * with an npx-style runner-name arg, which only holds for wrapper-style
1247
+ * runners like vitest/jest/pytest).
1218
1248
  */
1219
1249
  async resolveExec(runner, config, testFile, cwd) {
1220
1250
  // PHPUnit has no npx-style automatic local-binary resolution — Composer's
@@ -1232,15 +1262,15 @@ export class TestRunnerClient {
1232
1262
  const suffix = process.platform === "win32" ? ".cmd" : "";
1233
1263
  const localBin = path.join(cwd, "node_modules", ".bin", binName + suffix);
1234
1264
  // A resolved binary (local, or any manager's global bin) becomes the command
1235
- // itself, so the leading runner-name arg (e.g. "vitest") that npx needs is
1236
- // dropped from args().
1265
+ // itself, so the leading wrapper-name arg(s) that named it (e.g. "vitest",
1266
+ // or "-m pytest") are stripped from args() — see stripWrapperArgs.
1237
1267
  if (fs.existsSync(localBin)) {
1238
- return { command: localBin, args: config.args(testFile, cwd).slice(1) };
1268
+ return { command: localBin, args: stripWrapperArgs(binName, config.args(testFile, cwd)) };
1239
1269
  }
1240
1270
  // Any package manager's global bin dir (npm/pnpm/yarn/bun) before npx (#375).
1241
1271
  const globalBin = await findGlobalBinary(binName);
1242
1272
  if (globalBin) {
1243
- return { command: globalBin, args: config.args(testFile, cwd).slice(1) };
1273
+ return { command: globalBin, args: stripWrapperArgs(binName, config.args(testFile, cwd)) };
1244
1274
  }
1245
1275
  return { command: config.command, args: config.args(testFile, cwd) };
1246
1276
  }
@@ -11,6 +11,41 @@
11
11
  *
12
12
  * The SDK function is a one-line discriminant check, so we inline it and keep
13
13
  * every `@earendil-works/pi-coding-agent` import type-only (types compile away).
14
+ * `tests/host-sdk-type-only.test.ts` pins that invariant.
15
+ *
16
+ * ## S6 audit: the per-tool `is*ToolResult` discriminators (#1334)
17
+ *
18
+ * The SDK also exports seven `tool_result` discriminators — `isBashToolResult`,
19
+ * `isReadToolResult`, `isEditToolResult`, `isWriteToolResult`,
20
+ * `isGrepToolResult`, `isFindToolResult`, `isLsToolResult`. pi-lens does NOT
21
+ * consolidate onto them, and the reasons are worth recording so the question
22
+ * isn't relitigated:
23
+ *
24
+ * 1. **They are runtime values, not types.** Same `--omit=dev` constraint as
25
+ * above — importing them would break on a clean user install. Inlining them
26
+ * is the only option, and each one's entire body is verbatim
27
+ * `e.toolName === "<name>"` (checked against the pinned SDK's `types.js`).
28
+ * 2. **`isToolCallEventType` already subsumes all seven.** It is the SDK's own
29
+ * generic form of the same check, and it is already inlined below and used
30
+ * at pi-lens's `tool_call` sites. Adding seven fixed-name aliases of a
31
+ * generic we already have would be indirection, not consolidation.
32
+ * 3. **The seven cover strictly fewer tools than pi-lens intercepts.** They
33
+ * enumerate the built-ins only; pi-lens's `tool_call`/`tool_result` paths
34
+ * also key off `lsp_navigation` and pi-lens's own registered tools, which no
35
+ * host discriminator names.
36
+ * 4. **Narrowing to the host union would LOSE fields pi-lens reads.** The host
37
+ * `ToolResultEvent` declares `toolCallId`/`input`/`content`/`isError`/
38
+ * `details`/`usage`; pi-lens's local `ToolResultEvent`
39
+ * (`clients/runtime-tool-result.ts`) additionally carries
40
+ * `id`/`callId`/`requestId`/`provider`/`model`/`sessionId`/`session`, which
41
+ * the telemetry-identity path reads. A guard that narrowed to
42
+ * `EditToolResultEvent` would drop them.
43
+ *
44
+ * What IS consolidated is the part that costs nothing: the host's `details`
45
+ * SHAPES are type-only exports, so `EditToolDetails` & co. are imported as
46
+ * types rather than re-declared ad hoc. Genuinely pi-lens-specific `details`
47
+ * payloads (`searchReads`, `piLensPartialApply`) stay hand-declared — no host
48
+ * type describes them.
14
49
  */
15
50
  export function isToolCallEventType(toolName, event) {
16
51
  return (!!event &&