@herbertgao/pi-extensions 2026.8.6 → 2026.8.8

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 (385) hide show
  1. package/README.md +8 -6
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +320 -22
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -17
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
  15. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  16. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  17. package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
  18. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
  19. package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
  21. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
  22. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
  23. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
  25. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
  26. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
  27. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
  28. package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
  29. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
  30. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
  31. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
  32. package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
  33. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
  36. package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
  37. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
  38. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +5 -1
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -2
  43. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
  44. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
  46. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +140 -97
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
  49. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
  50. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  51. package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
  52. package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
  53. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
  54. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
  55. package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
  56. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
  57. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
  58. package/node_modules/@narumitw/pi-btw/README.md +120 -111
  59. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  60. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  61. package/node_modules/@narumitw/pi-btw/package.json +10 -6
  62. package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
  63. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  64. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  65. package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
  66. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  67. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
  68. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
  69. package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
  70. package/node_modules/pi-lens/CHANGELOG.md +999 -0
  71. package/node_modules/pi-lens/README.md +117 -3
  72. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  73. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  74. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
  75. package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
  76. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  77. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  78. package/node_modules/pi-lens/dist/clients/bash-file-access.js +381 -13
  79. package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
  80. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  81. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -0
  82. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  83. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  84. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +206 -0
  85. package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
  86. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  87. package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
  88. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  89. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  90. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  91. package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
  92. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  93. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  94. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +84 -14
  95. package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
  96. package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
  97. package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
  98. package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
  99. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
  100. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  101. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
  102. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
  103. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  104. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
  122. package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
  123. package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
  124. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  125. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  126. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  127. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +17 -8
  128. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
  129. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
  130. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
  131. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
  132. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
  133. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  134. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
  135. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
  136. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  137. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
  138. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  139. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +188 -0
  140. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
  141. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
  142. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
  143. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  144. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  145. package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
  146. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  147. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
  148. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  149. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  150. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  151. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  152. package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
  153. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  154. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
  155. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  156. package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
  157. package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
  158. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  159. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  160. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  161. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  162. package/node_modules/pi-lens/dist/clients/jscpd-client.js +87 -8
  163. package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
  164. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  165. package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
  166. package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
  167. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  168. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  169. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  170. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
  171. package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
  172. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
  173. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  174. package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
  175. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  176. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  177. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  178. package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
  179. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  180. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  181. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
  182. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
  183. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  184. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  185. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  186. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  187. package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
  188. package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
  189. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
  190. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  191. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  192. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  193. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  194. package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
  195. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  196. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  197. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  198. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
  199. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  200. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  201. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
  202. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  203. package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
  204. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  205. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  206. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  207. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +8 -3
  208. package/node_modules/pi-lens/dist/clients/read-guard.js +253 -10
  209. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  210. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  211. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
  212. package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
  213. package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
  214. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
  215. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
  216. package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
  217. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
  218. package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
  219. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  220. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
  221. package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
  222. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  223. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  224. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  225. package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
  226. package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
  227. package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
  228. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  229. package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
  230. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  231. package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
  232. package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
  233. package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
  234. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  235. package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  237. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  238. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
  239. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  240. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  241. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  242. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  243. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  244. package/node_modules/pi-lens/dist/index.js +61407 -48577
  245. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
  246. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
  247. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  248. package/node_modules/pi-lens/docs/agent-guide.md +6 -1
  249. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
  250. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  251. package/node_modules/pi-lens/docs/features.md +19 -5
  252. package/node_modules/pi-lens/docs/globalconfig.md +3 -0
  253. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  254. package/node_modules/pi-lens/docs/mcp.md +2 -2
  255. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  256. package/node_modules/pi-lens/docs/settings.md +19 -1
  257. package/node_modules/pi-lens/docs/usage.md +1 -0
  258. package/node_modules/pi-lens/package.json +27 -10
  259. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
  260. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
  261. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
  262. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
  263. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
  264. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
  265. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
  300. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
  301. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
  302. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
  303. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  304. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  305. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  306. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  307. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  308. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  309. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
  310. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  311. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  312. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  313. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  314. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  315. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  316. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  317. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  318. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  319. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
  320. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  321. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  322. package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
  323. package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
  324. package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
  325. package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
  326. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
  327. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
  328. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
  329. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  330. package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
  331. package/node_modules/pi-mcp-adapter/README.md +47 -5
  332. package/node_modules/pi-mcp-adapter/cli.js +163 -1
  333. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  334. package/node_modules/pi-mcp-adapter/config.ts +25 -7
  335. package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
  336. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  337. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  338. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  339. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  340. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  341. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  342. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  343. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  344. package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
  345. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  346. package/node_modules/pi-mcp-adapter/package.json +3 -1
  347. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  348. package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
  349. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  350. package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
  351. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  352. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  353. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  354. package/node_modules/pi-mcp-adapter/types.ts +2 -0
  355. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  356. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  357. package/node_modules/pi-web-access/CHANGELOG.md +37 -0
  358. package/node_modules/pi-web-access/README.md +32 -13
  359. package/node_modules/pi-web-access/anysearch.ts +4 -2
  360. package/node_modules/pi-web-access/brave.ts +16 -4
  361. package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
  362. package/node_modules/pi-web-access/curator-page.ts +6 -3
  363. package/node_modules/pi-web-access/curator-server.ts +4 -1
  364. package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
  365. package/node_modules/pi-web-access/exa.ts +18 -7
  366. package/node_modules/pi-web-access/extract.ts +40 -5
  367. package/node_modules/pi-web-access/firecrawl.ts +18 -2
  368. package/node_modules/pi-web-access/gemini-search.ts +16 -4
  369. package/node_modules/pi-web-access/github-extract.ts +65 -36
  370. package/node_modules/pi-web-access/index.ts +60 -61
  371. package/node_modules/pi-web-access/openai-search.ts +17 -6
  372. package/node_modules/pi-web-access/package.json +1 -1
  373. package/node_modules/pi-web-access/page-query.ts +4 -2
  374. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  375. package/node_modules/pi-web-access/parallel.ts +2 -2
  376. package/node_modules/pi-web-access/pdf-extract.ts +18 -5
  377. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  378. package/node_modules/pi-web-access/serper.ts +211 -0
  379. package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
  380. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  381. package/node_modules/pi-web-access/summary-review.ts +44 -22
  382. package/node_modules/pi-web-access/tavily.ts +16 -4
  383. package/node_modules/pi-web-access/utils.ts +87 -0
  384. package/node_modules/pi-web-access/valyu.ts +199 -0
  385. package/package.json +14 -14
@@ -16,7 +16,8 @@
16
16
  import * as fs from "node:fs";
17
17
  import * as os from "node:os";
18
18
  import * as path from "node:path";
19
- import { isCommandAvailableAsync, safeSpawnAsync } from "./safe-spawn.js";
19
+ import { classifyProbeFailure, createAvailabilityLatch, isTransientDecision, logAvailabilityDecision, startHostStallSampler, } from "./dispatch/runners/utils/availability-policy.js";
20
+ import { safeSpawnAsync } from "./safe-spawn.js";
20
21
  /**
21
22
  * Fallback preference when nothing is declared (or the declared manager is
22
23
  * missing). npm first for maximum compatibility; bun last. A project lockfile
@@ -72,18 +73,142 @@ function readPackageManagerField(targetPath) {
72
73
  // ============================================================================
73
74
  // AVAILABILITY (cached per process; reset in tests)
74
75
  // ============================================================================
75
- const availabilityCache = new Map();
76
- function isAvailable(pm) {
77
- let cached = availabilityCache.get(pm);
78
- if (!cached) {
79
- cached = isCommandAvailableAsync(pm);
80
- availabilityCache.set(pm, cached);
76
+ /**
77
+ * Budget for the `where`/`which <pm>` probe. Matches the previous
78
+ * `isCommandAvailableAsync` default so the observable timing is unchanged.
79
+ */
80
+ const PROBE_TIMEOUT_MS = 5_000;
81
+ /**
82
+ * A timed-out probe used to be memoized as a permanent `false` — the process
83
+ * would silently downgrade a declared pnpm/yarn manager to npm for its whole
84
+ * life. The blast radius was internal: this resolver only serves installs
85
+ * into pi-lens's own managed tools directory and `pilens_rebuild` on a
86
+ * pi-lens source checkout, never a user project's lockfile (#1496). Each
87
+ * manager now sits behind the shared transient-aware latch (#1467/#1476):
88
+ * only a genuine absence (`where`/`which` exits non-zero, or ENOENT) latches;
89
+ * a timeout, abort or host stall expires on a cooldown and is re-probed.
90
+ */
91
+ const availabilityLatches = new Map();
92
+ const inFlightProbes = new Map();
93
+ function getLatch(pm) {
94
+ let latch = availabilityLatches.get(pm);
95
+ if (!latch) {
96
+ latch = createAvailabilityLatch();
97
+ availabilityLatches.set(pm, latch);
98
+ }
99
+ return latch;
100
+ }
101
+ async function probeAvailability(pm) {
102
+ const latch = getLatch(pm);
103
+ const startedAt = Date.now();
104
+ const finder = onWindows() ? "where" : "which";
105
+ const sampler = startHostStallSampler();
106
+ let result;
107
+ let hostStallMs;
108
+ try {
109
+ result = await safeSpawnAsync(finder, [pm], { timeout: PROBE_TIMEOUT_MS });
81
110
  }
82
- return cached;
111
+ finally {
112
+ hostStallMs = sampler.stop();
113
+ }
114
+ const elapsedMs = Date.now() - startedAt;
115
+ if (result.status === 0 && !result.error) {
116
+ latch.noteAvailable();
117
+ logAvailabilityDecision({
118
+ tool: pm,
119
+ verdict: "available",
120
+ outcome: "success",
121
+ cause: "ok",
122
+ elapsedMs,
123
+ latched: true,
124
+ hostStallMs,
125
+ budgetMs: PROBE_TIMEOUT_MS,
126
+ });
127
+ return true;
128
+ }
129
+ const { outcome, cause, evidence } = classifyProbeFailure(result, {
130
+ hostStallMs,
131
+ // Preserve pre-#1496 meaning for anything the classifier can't place: a
132
+ // present manager that rejects its probe is durable, same as before.
133
+ unclassifiedFailureOutcome: "missing",
134
+ });
135
+ const retryAfterMs = latch.noteUnavailable(outcome, cause);
136
+ logAvailabilityDecision({
137
+ tool: pm,
138
+ verdict: "unavailable",
139
+ outcome,
140
+ cause,
141
+ elapsedMs,
142
+ latched: outcome !== "transient",
143
+ hostStallMs,
144
+ ...(retryAfterMs > 0 && { retryAfterMs }),
145
+ budgetMs: PROBE_TIMEOUT_MS,
146
+ classifiedBy: "probe",
147
+ evidence,
148
+ });
149
+ return false;
150
+ }
151
+ /**
152
+ * Resolve whether `pm` is available. `onTransient`, when given, fires
153
+ * whenever the resolved `false` came from a probe that never got a fair
154
+ * hearing (a stall, an abort, a host-level failure classified `transient` by
155
+ * `classifyProbeFailure`) rather than a genuine absence — including when that
156
+ * verdict is served from the latch's own cooldown-bounded memo, not just on a
157
+ * fresh probe (#1585).
158
+ *
159
+ * Before this, the return type was a bare boolean: a caller like
160
+ * `allAvailableGlobalBinDirs` could not tell "pnpm isn't installed" from
161
+ * "the `where pnpm` probe stalled", so a transient miss silently dropped
162
+ * pnpm's global bin dir with no way to flag the result as provisional —
163
+ * exactly the boolean-collapse `getToolPath`'s `onTransient` plumbing (#1569)
164
+ * was built to avoid, one layer up.
165
+ */
166
+ function isAvailable(pm, onTransient) {
167
+ const latch = getLatch(pm);
168
+ const reportIfTransient = (result) => {
169
+ if (!result && isTransientDecision({ outcome: latch.getOutcome() })) {
170
+ onTransient?.();
171
+ }
172
+ return result;
173
+ };
174
+ const memo = latch.read();
175
+ if (memo !== null)
176
+ return Promise.resolve(reportIfTransient(memo));
177
+ // A verdict can now expire, so concurrent callers arriving just after a
178
+ // cooldown must share ONE probe rather than each spawning their own.
179
+ const inFlight = inFlightProbes.get(pm);
180
+ if (inFlight)
181
+ return inFlight.then(reportIfTransient);
182
+ // #1653 review F1: a probe started before a session reset can settle AFTER
183
+ // a later session's own probe for the same manager is already in flight.
184
+ // An unconditional delete-by-key would evict that NEWER entry out from
185
+ // under it, so a third caller in the gap finds nothing in-flight and
186
+ // spawns a duplicate. Only remove the entry if it is still THIS call's
187
+ // promise — the same identity guard `resolveMadge` uses in
188
+ // dependency-checker.ts for the equivalent race.
189
+ const probe = probeAvailability(pm).finally(() => {
190
+ if (inFlightProbes.get(pm) === probe)
191
+ inFlightProbes.delete(pm);
192
+ });
193
+ inFlightProbes.set(pm, probe);
194
+ return probe.then(reportIfTransient);
83
195
  }
84
- /** Clear the process-wide availability cache. Intended for tests. */
196
+ /**
197
+ * Clear the process-wide availability cache: pnpm/yarn/bun/npm each sit
198
+ * behind their own module-local `AvailabilityLatch` in `availabilityLatches`,
199
+ * so `resetDispatchAvailabilityState`'s generation counter (the mechanism
200
+ * most dispatch runners inherit) never reaches them — the same shape as
201
+ * psscriptanalyzer's (#1490) and zizmor's (#1535) module-local latches.
202
+ * Without this wired into `session_start`, a genuine "pnpm is missing"
203
+ * verdict from one session stayed latched into the next: install pnpm mid
204
+ * day, start a fresh session, pi-lens still reports it missing until a
205
+ * process restart (#1653). Called from `handleSessionStart`'s per-session
206
+ * reset block beside `resetZizmorTokenAvailability()` /
207
+ * `resetPsScriptAnalyzerAvailability()`; also used directly by tests.
208
+ */
85
209
  export function _resetPackageManagerCache() {
86
- availabilityCache.clear();
210
+ availabilityLatches.clear();
211
+ inFlightProbes.clear();
87
212
  }
88
213
  // ============================================================================
89
214
  // RESOLUTION
@@ -134,6 +259,24 @@ export function installArgs(pm, pkg, options = {}) {
134
259
  args.push(pkg);
135
260
  return args;
136
261
  }
262
+ /**
263
+ * Args to re-resolve an already-declared dependency to the newest version its
264
+ * recorded range still permits. npm/pnpm/bun spell this `update`; yarn classic
265
+ * spells it `upgrade`.
266
+ *
267
+ * This is the command that repairs a dependency frozen by its own lockfile.
268
+ * `installArgs` re-runs the install, and a lockfile entry that already
269
+ * satisfies the range makes that a no-op: pi-lens's managed tools tree stayed
270
+ * on the version written at first install for the life of the machine even
271
+ * though the declared caret range permitted 28 newer minors (#1730).
272
+ */
273
+ export function updateArgs(pm, pkg, options = {}) {
274
+ const args = [pm === "yarn" ? "upgrade" : "update"];
275
+ if (options.ignoreScripts)
276
+ args.push("--ignore-scripts");
277
+ args.push(pkg);
278
+ return args;
279
+ }
137
280
  /**
138
281
  * Args to install a single package **globally** (`-g`). npm/pnpm/bun spell this
139
282
  * `install -g` / `add -g`; yarn uses `global add` (yarn classic — Berry removed
@@ -204,12 +347,18 @@ async function globalBinDirsFor(pm) {
204
347
  * Global bin directories for every installed manager, deduped. Used to locate a
205
348
  * globally-installed tool binary when PATH is stale (e.g. right after an
206
349
  * `install -g`) or when the tool was installed via a non-npm manager.
350
+ *
351
+ * `onTransient`, when given, fires once per manager whose `isAvailable` probe
352
+ * was transient (stalled/unspawnable, not a genuine absence) — the boolean
353
+ * `allAvailableGlobalBinDirs` returns can't itself distinguish "not
354
+ * installed" from "couldn't tell", so a caller that persists this result
355
+ * needs the callback to know the answer may be incomplete (#1585).
207
356
  */
208
- export async function allAvailableGlobalBinDirs() {
357
+ export async function allAvailableGlobalBinDirs(onTransient) {
209
358
  const dirs = [];
210
359
  const seen = new Set();
211
360
  for (const pm of PREFERENCE) {
212
- if (!(await isAvailable(pm)))
361
+ if (!(await isAvailable(pm, onTransient)))
213
362
  continue;
214
363
  for (const dir of await globalBinDirsFor(pm)) {
215
364
  const normalized = path.resolve(dir);
@@ -251,8 +400,15 @@ export async function findGlobalBinary(command, windowsExt = ".cmd") {
251
400
  }
252
401
  return undefined;
253
402
  }
254
- /** Local `node_modules/.bin/<tool>` walking up from `startDir` to the fs root. */
255
- function findLocalBinUpwards(tool, startDir, windowsExt) {
403
+ /**
404
+ * Local `node_modules/.bin/<tool>` walking up from `startDir` to the fs root.
405
+ *
406
+ * Exported so callers that must NOT pay for global-bin discovery can reuse this
407
+ * walk instead of copying it. `findNodeToolBinary` below adds `findGlobalBinary`,
408
+ * which spawns a probe per package manager; a caller resolving a command on
409
+ * every run (knip, #1721) needs the filesystem half only.
410
+ */
411
+ export function findLocalBinUpwards(tool, startDir, windowsExt = ".cmd") {
256
412
  const names = onWindows() ? [`${tool}${windowsExt}`, tool] : [tool];
257
413
  let dir = path.resolve(startDir);
258
414
  const root = path.parse(dir).root;
@@ -0,0 +1,27 @@
1
+ import { logLatency } from "./latency-logger.js";
2
+ // Verified guesses are expected host behavior, not degradations. Keep their
3
+ // exact session count in memory and publish one bounded row at session end.
4
+ // This tally is intentionally memory-only: a process crash loses its count.
5
+ // The rollup is best-effort session telemetry, not durable accounting.
6
+ let verifiedGuessCount = 0;
7
+ export function recordVerifiedPathAttributionGuess() {
8
+ verifiedGuessCount += 1;
9
+ }
10
+ export function getVerifiedPathAttributionGuessCount() {
11
+ return verifiedGuessCount;
12
+ }
13
+ export function emitVerifiedPathAttributionRollup(filePath) {
14
+ if (verifiedGuessCount === 0)
15
+ return;
16
+ logLatency({
17
+ type: "phase",
18
+ phase: "path_attribution_verified_rollup",
19
+ filePath,
20
+ durationMs: 0,
21
+ metadata: { count: verifiedGuessCount },
22
+ });
23
+ verifiedGuessCount = 0;
24
+ }
25
+ export function resetVerifiedPathAttributionGuessCount() {
26
+ verifiedGuessCount = 0;
27
+ }
@@ -452,3 +452,163 @@ export function direntsHaveMarkerGlobMatch(entries, pattern) {
452
452
  return entries.some((entry) => (entry.isFile() || entry.isSymbolicLink()) &&
453
453
  nameMatchesMarkerGlob(entry.name, pattern));
454
454
  }
455
+ /**
456
+ * Narrow no-break space, U+202F. macOS writes it before AM/PM in screenshot
457
+ * file names; users type an ordinary space.
458
+ */
459
+ const NARROW_NO_BREAK_SPACE = "\u202F";
460
+ /** Right single quotation mark, U+2019. macOS writes it; users type U+0027. */
461
+ const RIGHT_SINGLE_QUOTE = "\u2019";
462
+ /**
463
+ * The unicode space class pi folds to U+0020, copied character-for-character
464
+ * from `@earendil-works/pi-coding-agent/dist/utils/paths.js:6`
465
+ * (`UNICODE_SPACES`, source `src/utils/paths.ts`). Widening or narrowing this
466
+ * set makes pi-lens resolve a different file than pi does.
467
+ */
468
+ const HOST_UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
469
+ /**
470
+ * Mirror pi's `normalizeWindowsShellPath`
471
+ * (`@earendil-works/pi-coding-agent/dist/utils/paths.js:47-56`): convert Git
472
+ * Bash, MSYS, Cygwin, and WSL drive paths to a form native Windows APIs
473
+ * accept.
474
+ */
475
+ function hostNormalizeWindowsShellPath(filePath) {
476
+ if (!filePath.startsWith("/") ||
477
+ filePath.startsWith("//") ||
478
+ filePath.includes("\\")) {
479
+ return filePath;
480
+ }
481
+ const match = filePath.match(/^\/(?:mnt\/|cygdrive\/)?([a-z])(?:\/(.*))?$/i);
482
+ if (!match)
483
+ return filePath;
484
+ const suffix = match[2]?.replaceAll("/", "\\");
485
+ return `${match[1].toUpperCase()}:\\${suffix ?? ""}`;
486
+ }
487
+ /**
488
+ * Mirror pi's `normalizePath`
489
+ * (`@earendil-works/pi-coding-agent/dist/utils/paths.js:57-79`, source
490
+ * `src/utils/paths.ts`), in pi's order, which is load-bearing: the unicode
491
+ * fold runs BEFORE the `@` strip, and the tilde expansion before the
492
+ * `file://` conversion.
493
+ *
494
+ * The `win32` step is gated on `process.platform`, exactly as pi gates it.
495
+ * This is a deliberate exception to the usual probe-the-filesystem rule
496
+ * (AGENTS.md shape 2): pi-lens runs in pi's own process, so mirroring the
497
+ * host's own platform branch is what keeps the two resolvers in agreement.
498
+ * Shape-based parsing here would DIVERGE from the host, not protect against
499
+ * it.
500
+ */
501
+ export function normalizeHostToolPath(input, options = {}) {
502
+ let normalized = input;
503
+ if (options.normalizeUnicodeSpaces) {
504
+ normalized = normalized.replace(HOST_UNICODE_SPACES, " ");
505
+ }
506
+ if (options.stripAtPrefix && normalized.startsWith("@")) {
507
+ normalized = normalized.slice(1);
508
+ }
509
+ if (process.platform === "win32") {
510
+ normalized = hostNormalizeWindowsShellPath(normalized);
511
+ }
512
+ // `homedir()` is resolved inside the branch, as pi does. This runs on every
513
+ // tool_call and a `~` path is the rare case.
514
+ if (normalized === "~")
515
+ return os.homedir();
516
+ if (normalized.startsWith("~/") ||
517
+ (process.platform === "win32" && normalized.startsWith("~\\"))) {
518
+ return path.join(os.homedir(), normalized.slice(2));
519
+ }
520
+ if (/^file:\/\//.test(normalized)) {
521
+ try {
522
+ return fileURLToPath(normalized);
523
+ }
524
+ catch {
525
+ // pi lets a malformed file: URL throw out of normalizePath, but pi-lens
526
+ // is advisory instrumentation on the same event: a URL pi rejects must
527
+ // degrade to "no path" here, never take down the tool_call handler.
528
+ return normalized;
529
+ }
530
+ }
531
+ return normalized;
532
+ }
533
+ /**
534
+ * Mirror pi's `resolveToCwd`
535
+ * (`@earendil-works/pi-coding-agent/dist/core/tools/path-utils.js:42-44`,
536
+ * source `src/core/tools/path-utils.ts:~44-46`) \u2014 the BASE resolution every
537
+ * read/edit/write path goes through before the variant ladder below ever
538
+ * runs.
539
+ *
540
+ * Two details are pi's, not ours, and both matter:
541
+ * - the input is normalized with `normalizeUnicodeSpaces` + `stripAtPrefix`;
542
+ * the BASE DIR is normalized with neither (`resolvePath`,
543
+ * `dist/utils/paths.js:80-84`).
544
+ * - an already-absolute input is re-resolved on its own, ignoring the cwd.
545
+ */
546
+ export function resolveHostToolPath(input, baseDir) {
547
+ const normalized = normalizeHostToolPath(input, {
548
+ normalizeUnicodeSpaces: true,
549
+ stripAtPrefix: true,
550
+ });
551
+ const normalizedBaseDir = normalizeHostToolPath(baseDir);
552
+ return path.isAbsolute(normalized)
553
+ ? path.resolve(normalized)
554
+ : path.resolve(normalizedBaseDir, normalized);
555
+ }
556
+ /**
557
+ * Mirror pi's read-path fallback ladder (#1655 item 5).
558
+ *
559
+ * pi does NOT open `resolve(cwd, input.path)`. `resolveReadPath`
560
+ * (`@earendil-works/pi-coding-agent/dist/core/tools/path-utils.js:45-70`,
561
+ * source `src/core/tools/path-utils.ts:52-83`) resolves, and when that path
562
+ * does not exist it silently retries four unicode/spacing variants in this
563
+ * exact order:
564
+ *
565
+ * 1. narrow no-break space before `AM.`/`PM.` (`tryMacOSScreenshotPath`)
566
+ * 2. NFD normalization (`tryNFDVariant`) — macOS stores names decomposed
567
+ * 3. U+0027 → U+2019 (`tryCurlyQuoteVariant`)
568
+ * 4. NFD + curly quote combined
569
+ *
570
+ * Each candidate is used only when it DIFFERS from the resolved path and the
571
+ * file exists; otherwise pi falls back to the resolved path. So the file pi
572
+ * actually read can differ from what a naive `path.resolve` produces, and
573
+ * pi-lens keyed its read guard, LSP touch, and dispatch off the naive form —
574
+ * silently doing nothing for exactly those files.
575
+ *
576
+ * Order matters: it is pi's, so pi-lens picks the same file pi did when more
577
+ * than one variant happens to exist.
578
+ *
579
+ * @param resolvedPath an already-resolved absolute path (the naive form)
580
+ * @param fileExists injectable existence probe; defaults to `existsSync`
581
+ */
582
+ export function resolveHostPathVariants(resolvedPath, fileExists = existsSync) {
583
+ if (fileExists(resolvedPath)) {
584
+ return { path: resolvedPath, unresolved: false, triedVariants: [] };
585
+ }
586
+ const nfd = resolvedPath.normalize("NFD");
587
+ const candidates = [
588
+ {
589
+ variant: "narrow-nbsp",
590
+ candidate: resolvedPath.replace(/ (AM|PM)\./gi, `${NARROW_NO_BREAK_SPACE}$1.`),
591
+ },
592
+ { variant: "nfd", candidate: nfd },
593
+ {
594
+ variant: "curly-quote",
595
+ candidate: resolvedPath.replaceAll("'", RIGHT_SINGLE_QUOTE),
596
+ },
597
+ {
598
+ variant: "nfd-curly-quote",
599
+ candidate: nfd.replaceAll("'", RIGHT_SINGLE_QUOTE),
600
+ },
601
+ ];
602
+ const triedVariants = [];
603
+ for (const { variant, candidate } of candidates) {
604
+ // pi skips a candidate identical to the resolved path, so pi-lens does
605
+ // too — otherwise a no-op "variant" would be reported as a match.
606
+ if (candidate === resolvedPath)
607
+ continue;
608
+ triedVariants.push(variant);
609
+ if (fileExists(candidate)) {
610
+ return { path: candidate, variant, unresolved: false, triedVariants };
611
+ }
612
+ }
613
+ return { path: resolvedPath, unresolved: true, triedVariants };
614
+ }