@herbertgao/pi-extensions 2026.8.4 → 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 (288) hide show
  1. package/README.md +4 -4
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +10 -2
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +10 -2
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +5 -8
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  13. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  14. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +8 -0
  15. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  16. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +15 -2
  20. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  21. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  22. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  25. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  26. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  27. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  30. package/node_modules/@narumitw/pi-btw/README.md +8 -7
  31. package/node_modules/@narumitw/pi-btw/package.json +2 -2
  32. package/node_modules/@narumitw/pi-btw/src/menu.ts +1 -0
  33. package/node_modules/pi-lens/CHANGELOG.md +2440 -954
  34. package/node_modules/pi-lens/README.md +13 -0
  35. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  36. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  37. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  38. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  39. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  40. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  41. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  42. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  43. package/node_modules/pi-lens/dist/clients/biome-client.js +29 -25
  44. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  45. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  46. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  47. package/node_modules/pi-lens/dist/clients/bus-publish.js +10 -3
  48. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  49. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  50. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  51. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  52. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  53. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  54. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  55. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  56. package/node_modules/pi-lens/dist/clients/console-guard-install.js +14 -0
  57. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  58. package/node_modules/pi-lens/dist/clients/dead-code-client.js +2 -1
  59. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  60. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  61. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  62. package/node_modules/pi-lens/dist/clients/dependency-checker.js +347 -75
  63. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +61 -11
  64. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
  65. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +63 -20
  66. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  67. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  68. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  69. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  70. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  71. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1085 -681
  72. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  73. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  74. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  75. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  76. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  77. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  78. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  79. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  80. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  81. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  82. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  83. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +14 -6
  84. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  85. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  86. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  87. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +277 -26
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  99. package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
  100. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  101. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  102. package/node_modules/pi-lens/dist/clients/extension-log.js +139 -0
  103. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  104. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  105. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  106. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  107. package/node_modules/pi-lens/dist/clients/format-events-publish.js +16 -3
  108. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  109. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  110. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  111. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  112. package/node_modules/pi-lens/dist/clients/git-guard.js +681 -11
  113. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  114. package/node_modules/pi-lens/dist/clients/go-client.js +2 -1
  115. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +8 -0
  116. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  117. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  118. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  119. package/node_modules/pi-lens/dist/clients/installer/index.js +390 -99
  120. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  121. package/node_modules/pi-lens/dist/clients/jscpd-client.js +31 -54
  122. package/node_modules/pi-lens/dist/clients/knip-client.js +15 -36
  123. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  124. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  125. package/node_modules/pi-lens/dist/clients/latency-logger.js +23 -1
  126. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  127. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  128. package/node_modules/pi-lens/dist/clients/lens-events.js +27 -4
  129. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  130. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  131. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +30 -0
  132. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  133. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +1 -1
  134. package/node_modules/pi-lens/dist/clients/lsp/client.js +493 -48
  135. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  136. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +86 -0
  137. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  138. package/node_modules/pi-lens/dist/clients/lsp/index.js +1807 -780
  139. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  140. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  141. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  142. package/node_modules/pi-lens/dist/clients/lsp/server.js +196 -32
  143. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  144. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  145. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  146. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +123 -32
  147. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  148. package/node_modules/pi-lens/dist/clients/mcp/session.js +216 -8
  149. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  150. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  151. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  152. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  153. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  154. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  155. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  156. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  157. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  158. package/node_modules/pi-lens/dist/clients/pipeline.js +47 -13
  159. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  160. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  161. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  162. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  163. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  164. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  165. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  166. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  167. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  168. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  169. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  170. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  171. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  172. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  173. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  174. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  175. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  176. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  177. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  178. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  179. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  180. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  181. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  182. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +107 -73
  183. package/node_modules/pi-lens/dist/clients/runtime-context.js +36 -12
  184. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +74 -6
  185. package/node_modules/pi-lens/dist/clients/runtime-session.js +405 -117
  186. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  187. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +218 -23
  188. package/node_modules/pi-lens/dist/clients/runtime-turn.js +237 -64
  189. package/node_modules/pi-lens/dist/clients/rust-client.js +2 -1
  190. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  191. package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -1
  192. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  193. package/node_modules/pi-lens/dist/clients/sg-runner.js +284 -174
  194. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  195. package/node_modules/pi-lens/dist/clients/smells-rollup.js +224 -0
  196. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  197. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  198. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  199. package/node_modules/pi-lens/dist/clients/startup-timing.js +1 -1
  200. package/node_modules/pi-lens/dist/clients/test-runner-client.js +38 -8
  201. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  202. package/node_modules/pi-lens/dist/clients/tool-policy.js +388 -39
  203. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  204. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  205. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  206. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  207. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  208. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  209. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  210. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  211. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  212. package/node_modules/pi-lens/dist/clients/warm-attach.js +33 -13
  213. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  214. package/node_modules/pi-lens/dist/clients/word-index.js +391 -64
  215. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  216. package/node_modules/pi-lens/dist/index.js +49361 -36888
  217. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  218. package/node_modules/pi-lens/dist/mcp/server.js +211 -44
  219. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  220. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +200 -36
  221. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +153 -40
  222. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  223. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  224. package/node_modules/pi-lens/docs/agent-guide.md +2 -2
  225. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  226. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  227. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  228. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +5 -2
  229. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  230. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  231. package/node_modules/pi-lens/docs/fable.md +27 -0
  232. package/node_modules/pi-lens/docs/features.md +31 -2
  233. package/node_modules/pi-lens/docs/globalconfig.md +45 -1
  234. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  235. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  236. package/node_modules/pi-lens/docs/mcp.md +37 -4
  237. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  238. package/node_modules/pi-lens/docs/settings.md +12 -1
  239. package/node_modules/pi-lens/docs/tools.md +4 -1
  240. package/node_modules/pi-lens/docs/usage.md +18 -0
  241. package/node_modules/pi-lens/package.json +10 -10
  242. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  243. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  244. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  245. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  246. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  247. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  248. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  249. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  250. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  251. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  252. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  253. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  254. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +55 -2
  255. package/node_modules/pi-mcp-adapter/CHANGELOG.md +25 -0
  256. package/node_modules/pi-mcp-adapter/README.md +34 -3
  257. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  258. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  259. package/node_modules/pi-mcp-adapter/direct-tools.ts +54 -7
  260. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  261. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  262. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  263. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  264. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  265. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  266. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  267. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  268. package/node_modules/pi-mcp-adapter/metadata-cache.ts +27 -4
  269. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  270. package/node_modules/pi-mcp-adapter/package.json +3 -3
  271. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  272. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  273. package/node_modules/pi-mcp-adapter/server-manager.ts +36 -7
  274. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  275. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  276. package/node_modules/pi-mcp-adapter/tool-metadata.ts +42 -4
  277. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  278. package/node_modules/pi-mcp-adapter/types.ts +93 -27
  279. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  280. package/package.json +11 -12
  281. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  282. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  283. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  284. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  285. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  286. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  287. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  288. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -1,6 +1,6 @@
1
1
  import * as nodeFs from "node:fs";
2
- import { hostWouldApplyOldText, normalizeForGuardMatch, } from "./host-edit-normalize.js";
3
- import { logReadGuardEvent } from "./read-guard-logger.js";
2
+ import { hostWouldApplyOldText, normalizeForGuardMatch, normalizeToLF, stripBom, } from "./host-edit-normalize.js";
3
+ import { boundedIndexesForCount, createReadGuardEditBatchSummary, logReadGuardEvent, } from "./read-guard-logger.js";
4
4
  import { isToolCallEventType } from "./tool-event.js";
5
5
  // Track repeated oldtext_not_found failures per (filePath, preview) to escalate messages.
6
6
  const recentOldTextFailures = new Map();
@@ -51,6 +51,15 @@ function tokenSimilarity(a, b) {
51
51
  * its edit from verbatim text in one turn instead of re-reading blind. Scans a
52
52
  * ±window around `nearLine` when known (the first-line locator), else the whole
53
53
  * file. Returns the top matches above `minScore`, with their real line numbers.
54
+ *
55
+ * Scores in normalized space but returns only `{ line, score }` — the caller
56
+ * renders the text from a structurally-aligned RAW view so a suggestion can
57
+ * never quote the normalized projection (#1050). NFKC folds CJK full-width
58
+ * punctuation (`:`→`:`, `,`→`,`, `;`→`;`) and HOST_UNICODE_DASHES folds
59
+ * `—`→`-`, so a suggestion rendered from normalized content told the agent to
60
+ * copy bytes the file does not contain; the host's edit tool then fuzzy-matched
61
+ * it and wrote the folded form onto the touched line. Normalization here is
62
+ * comparison-only, exactly as everywhere else in this file.
54
63
  */
55
64
  function findSimilarLines(content, target, options = {}) {
56
65
  const { nearLine, window = 60, max = 3, minScore = 0.5 } = options;
@@ -67,14 +76,26 @@ function findSimilarLines(content, target, options = {}) {
67
76
  continue;
68
77
  const score = tokenSimilarity(needle, text);
69
78
  if (score >= minScore)
70
- scored.push({ line: i + 1, text, score });
79
+ scored.push({ line: i + 1, score });
71
80
  }
72
81
  scored.sort((a, b) => b.score - a.score);
73
82
  return scored.slice(0, max);
74
83
  }
75
- function formatSimilarLines(suggestions) {
84
+ /**
85
+ * Render did-you-mean rows from the file's real characters rather than the
86
+ * normalized match space the line numbers were scored in. Taking only
87
+ * `{ line }` from the scan makes quoting normalized text structurally
88
+ * impossible (#1050).
89
+ *
90
+ * `rawLineAligned` must be `normalizeToLF(stripBom(raw).text)`: the same
91
+ * STRUCTURAL normalization `normalizeForGuardMatch` applies (so line indices
92
+ * cross-index 1:1 even for lone-CR or BOM files) but none of its CHARACTER
93
+ * folding, so full-width punctuation, smart quotes, and NBSP survive.
94
+ */
95
+ function formatSimilarLines(suggestions, rawLineAligned) {
96
+ const rawLines = rawLineAligned.split("\n");
76
97
  const pad = (n) => String(n).padStart(4, " ");
77
- const rows = suggestions.map(({ line, text }) => ` ${pad(line)} │ ${text.trimEnd()}`);
98
+ const rows = suggestions.map(({ line }) => ` ${pad(line)} │ ${(rawLines[line - 1] ?? "").trimEnd()}`);
78
99
  return `\n\nDid you mean one of these current lines?\n${rows.join("\n")}`;
79
100
  }
80
101
  export function countFileLines(filePath) {
@@ -135,7 +156,7 @@ function getHashlineOperations(input) {
135
156
  return [input];
136
157
  return [];
137
158
  }
138
- function resolveHashlineEditInput(input, filePath, sessionId) {
159
+ function resolveHashlineEditInput(input, filePath, sessionId, correlationId) {
139
160
  const operations = getHashlineOperations(input);
140
161
  if (operations.length === 0)
141
162
  return undefined;
@@ -175,9 +196,21 @@ function resolveHashlineEditInput(input, filePath, sessionId) {
175
196
  errors.push(`operation[${index}] is not a recognized hashline edit`);
176
197
  }
177
198
  if (errors.length > 0) {
199
+ const editBatchSummary = createReadGuardEditBatchSummary({
200
+ requestedIndexes: boundedIndexesForCount(operations.length),
201
+ requestedTotal: operations.length,
202
+ rejectedReasons: boundedIndexesForCount(operations.length).map((index) => ({
203
+ index,
204
+ code: "preflight_blocked",
205
+ })),
206
+ rejectedTotal: operations.length,
207
+ durationMs: 0,
208
+ terminalStatus: "blocked",
209
+ });
178
210
  if (filePath) {
179
211
  logReadGuardEvent({
180
212
  event: "edit_preflight_blocked",
213
+ correlationId,
181
214
  sessionId,
182
215
  filePath,
183
216
  metadata: {
@@ -189,6 +222,12 @@ function resolveHashlineEditInput(input, filePath, sessionId) {
189
222
  errors: errors.slice(0, 10),
190
223
  },
191
224
  });
225
+ logReadGuardEvent({
226
+ event: "edit_batch_summary",
227
+ correlationId,
228
+ filePath,
229
+ metadata: { tool: "edit", editBatchSummary },
230
+ });
192
231
  }
193
232
  // Every blocking verdict ends with a single concrete next-action line so
194
233
  // the agent recovers in one turn (#328 — uniform recovery-hint discipline).
@@ -197,6 +236,7 @@ function resolveHashlineEditInput(input, filePath, sessionId) {
197
236
  return {
198
237
  touchedLines: undefined,
199
238
  preflightError: `🔴 BLOCKED — Unsupported hashline edit target\n\n${errors.join("\n")}\n\n${retryHint}`,
239
+ editBatchSummary,
200
240
  };
201
241
  }
202
242
  if (ranges.length === 0)
@@ -205,6 +245,7 @@ function resolveHashlineEditInput(input, filePath, sessionId) {
205
245
  if (filePath) {
206
246
  logReadGuardEvent({
207
247
  event: "touched_lines_detected",
248
+ correlationId,
208
249
  sessionId,
209
250
  filePath,
210
251
  metadata: {
@@ -287,13 +328,23 @@ function exactOldTextForApply(rawContentLf, oldText, candidate) {
287
328
  }
288
329
  return undefined;
289
330
  }
290
- function resolveOldTextEdits(edits, filePath, sessionId) {
331
+ function resolveOldTextEdits(edits, filePath, sessionId, correlationId) {
332
+ const startedAt = Date.now();
333
+ const requestedIndexes = [];
334
+ const logBatchEvent = (entry) => logReadGuardEvent({ ...entry, correlationId });
291
335
  let rawContent;
292
336
  try {
293
337
  rawContent = nodeFs.readFileSync(filePath, "utf-8");
294
338
  }
295
339
  catch {
296
- logReadGuardEvent({
340
+ const editBatchSummary = createReadGuardEditBatchSummary({
341
+ requestedIndexes: edits.map((edit, index) => edit.originalIndex ?? index),
342
+ rejectedReasons: edits.map((edit, index) => ({
343
+ index: edit.originalIndex ?? index,
344
+ code: "preflight_blocked",
345
+ })),
346
+ });
347
+ logBatchEvent({
297
348
  event: "touched_lines_missing",
298
349
  sessionId,
299
350
  filePath,
@@ -303,7 +354,12 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
303
354
  editCount: edits.length,
304
355
  },
305
356
  });
306
- return { touchedLines: undefined };
357
+ logBatchEvent({
358
+ event: "edit_batch_summary",
359
+ filePath,
360
+ metadata: { tool: "edit", editBatchSummary },
361
+ });
362
+ return { touchedLines: undefined, editBatchSummary };
307
363
  }
308
364
  const rawContentLf = rawContent.replace(/\r\n/g, "\n");
309
365
  const content = normalizeContent(rawContent);
@@ -311,12 +367,16 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
311
367
  const failureKinds = [];
312
368
  const failedEditIndexes = [];
313
369
  const failedOldTextPreviews = [];
370
+ const rejectedReasons = [];
371
+ const resolvedIndexes = [];
314
372
  const resolvedRanges = [];
315
373
  const passedEdits = [];
316
374
  let maxFailCount = 0;
317
375
  for (let i = 0; i < edits.length; i++) {
318
376
  const oldText = edits[i].oldText;
319
377
  const editIndex = edits[i].originalIndex ?? i;
378
+ if (requestedIndexes.length < 100)
379
+ requestedIndexes.push(editIndex);
320
380
  if (!oldText)
321
381
  continue;
322
382
  let needle = normalizeContent(oldText);
@@ -327,7 +387,7 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
327
387
  needle = normalizeContent(corrected);
328
388
  occurrenceLines = findOccurrenceLines(content, needle);
329
389
  if (occurrenceLines.length > 0) {
330
- logReadGuardEvent({
390
+ logBatchEvent({
331
391
  event: "oldtext_indent_corrected",
332
392
  sessionId,
333
393
  filePath,
@@ -343,8 +403,13 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
343
403
  if (occurrenceLines.length === 0) {
344
404
  const preview = oldText.trimStart().substring(0, 60).replace(/\n/g, "↵");
345
405
  failureKinds.push("oldtext_not_found");
346
- failedEditIndexes.push(editIndex);
347
- failedOldTextPreviews.push(preview);
406
+ if (failedEditIndexes.length < 100) {
407
+ failedEditIndexes.push(editIndex);
408
+ failedOldTextPreviews.push(preview);
409
+ }
410
+ if (rejectedReasons.length < 100) {
411
+ rejectedReasons.push({ index: editIndex, code: "oldtext_not_found" });
412
+ }
348
413
  const failCount = trackOldTextFailure(filePath, preview);
349
414
  if (failCount > maxFailCount)
350
415
  maxFailCount = failCount;
@@ -401,11 +466,14 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
401
466
  // similarity) so the model can rebuild oldText verbatim in one turn
402
467
  // instead of re-reading blind. Skipped on the quote-style path, which
403
468
  // already names the precise fix. Anchored near the first-line locator
404
- // when known, else scans the whole file.
469
+ // when known, else scans the whole file. Scored against `content`
470
+ // (normalized) but RENDERED from a structurally-aligned raw view —
471
+ // quoting the normalized projection told the agent to copy bytes the
472
+ // file does not contain (#1050).
405
473
  if (!errorMsg.includes("quote style")) {
406
474
  const similarLines = findSimilarLines(content, oldText.replace(/\r\n/g, "\n").split("\n")[0], { nearLine: findFirstLineOfOldText(content, oldText) });
407
475
  if (similarLines.length > 0) {
408
- errorMsg += formatSimilarLines(similarLines);
476
+ errorMsg += formatSimilarLines(similarLines, normalizeToLF(stripBom(rawContent).text));
409
477
  }
410
478
  }
411
479
  errors.push(errorMsg);
@@ -414,7 +482,7 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
414
482
  // friction the host wouldn't have); false => a genuine miss. This is the
415
483
  // measurement that tells us whether the guard earns its keep (#257).
416
484
  const hostMatch = hostWouldApplyOldText(rawContent, oldText);
417
- logReadGuardEvent({
485
+ logBatchEvent({
418
486
  event: "oldtext_not_found",
419
487
  sessionId,
420
488
  filePath,
@@ -434,6 +502,8 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
434
502
  const startLine = occurrenceLines[0];
435
503
  const endLine = startLine + needle.split("\n").length - 1;
436
504
  resolvedRanges.push([startLine, endLine]);
505
+ if (resolvedIndexes.length < 100)
506
+ resolvedIndexes.push(editIndex);
437
507
  const applyOldText = exactOldTextForApply(rawContentLf, oldText, needle);
438
508
  if (applyOldText !== undefined) {
439
509
  passedEdits.push({
@@ -442,7 +512,7 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
442
512
  originalIndex: editIndex,
443
513
  });
444
514
  }
445
- logReadGuardEvent({
515
+ logBatchEvent({
446
516
  event: "oldtext_resolved",
447
517
  sessionId,
448
518
  filePath,
@@ -457,12 +527,17 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
457
527
  else {
458
528
  const preview = oldText.trimStart().substring(0, 60).replace(/\n/g, "↵");
459
529
  failureKinds.push("oldtext_duplicate");
460
- failedEditIndexes.push(editIndex);
461
- failedOldTextPreviews.push(preview);
530
+ if (failedEditIndexes.length < 100) {
531
+ failedEditIndexes.push(editIndex);
532
+ failedOldTextPreviews.push(preview);
533
+ }
534
+ if (rejectedReasons.length < 100) {
535
+ rejectedReasons.push({ index: editIndex, code: "oldtext_duplicate" });
536
+ }
462
537
  const matchSpanLines = needle.split("\n").length;
463
538
  const contextBlock = formatOccurrenceContext(content, occurrenceLines, matchSpanLines);
464
539
  errors.push(`edits[${editIndex}].oldText ("${preview}") appears ${occurrenceLines.length} times:\n${contextBlock}\nPick the location you want and extend your oldText with the unique line above or below it (shown as context).`);
465
- logReadGuardEvent({
540
+ logBatchEvent({
466
541
  event: "oldtext_duplicate",
467
542
  sessionId,
468
543
  filePath,
@@ -470,8 +545,8 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
470
545
  tool: "edit",
471
546
  source: "edits_without_ranges",
472
547
  editIndex,
548
+ occurrenceLines: occurrenceLines.slice(0, 100),
473
549
  occurrenceCount: occurrenceLines.length,
474
- occurrenceLines,
475
550
  oldTextPreview: preview,
476
551
  },
477
552
  });
@@ -485,8 +560,19 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
485
560
  "One or more edit targets could not be resolved to exact lines. Re-read the relevant section and retry with the exact content as it appears in the file.",
486
561
  ];
487
562
  const uniqueFailureKinds = [...new Set(failureKinds)];
488
- logReadGuardEvent({
563
+ const editBatchSummary = createReadGuardEditBatchSummary({
564
+ requestedIndexes,
565
+ requestedTotal: edits.length,
566
+ resolvedIndexes,
567
+ resolvedTotal: resolvedRanges.length,
568
+ rejectedReasons,
569
+ rejectedTotal: Math.max(0, oldTextEditCount - resolvedRanges.length),
570
+ durationMs: Date.now() - startedAt,
571
+ terminalStatus: "blocked",
572
+ });
573
+ logBatchEvent({
489
574
  event: "edit_preflight_blocked",
575
+ correlationId,
490
576
  sessionId,
491
577
  filePath,
492
578
  metadata: {
@@ -511,14 +597,27 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
511
597
  const header = maxFailCount >= 2
512
598
  ? `🛑 RE-READ REQUIRED — You have submitted this oldText before and it still does not match.\n\nDo NOT retry from memory. Re-read \`${filePath}\` to get the current content, then rebuild your edit from the verbatim file text.`
513
599
  : `🔄 RETRYABLE — Edit target not found`;
600
+ logBatchEvent({
601
+ event: "edit_batch_summary",
602
+ correlationId,
603
+ filePath,
604
+ metadata: { tool: "edit", editBatchSummary },
605
+ });
514
606
  return {
515
607
  touchedLines: undefined,
516
608
  preflightError: `${header}\n\n${failureDetails.join("\n\n")}${appliedNote}`,
517
609
  partiallyApplicable: passedEdits.length > 0 ? passedEdits : undefined,
610
+ editBatchSummary,
518
611
  };
519
612
  }
520
613
  if (resolvedRanges.length === 0) {
521
- logReadGuardEvent({
614
+ const editBatchSummary = createReadGuardEditBatchSummary({
615
+ requestedIndexes,
616
+ requestedTotal: edits.length,
617
+ rejectedTotal: oldTextEditCount,
618
+ terminalStatus: "blocked",
619
+ });
620
+ logBatchEvent({
522
621
  event: "touched_lines_missing",
523
622
  sessionId,
524
623
  filePath,
@@ -528,7 +627,12 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
528
627
  editCount: edits.length,
529
628
  },
530
629
  });
531
- return { touchedLines: undefined };
630
+ logBatchEvent({
631
+ event: "edit_batch_summary",
632
+ filePath,
633
+ metadata: { tool: "edit", editBatchSummary },
634
+ });
635
+ return { touchedLines: undefined, editBatchSummary };
532
636
  }
533
637
  const starts = resolvedRanges.map(([s]) => s);
534
638
  const ends = resolvedRanges.map(([, e]) => e);
@@ -537,7 +641,7 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
537
641
  Math.max(...ends),
538
642
  ];
539
643
  const editRanges = resolvedRanges.length > 1 ? resolvedRanges : undefined;
540
- logReadGuardEvent({
644
+ logBatchEvent({
541
645
  event: "touched_lines_detected",
542
646
  sessionId,
543
647
  filePath,
@@ -549,7 +653,20 @@ function resolveOldTextEdits(edits, filePath, sessionId) {
549
653
  totalEditCount: edits.length,
550
654
  },
551
655
  });
552
- return { touchedLines, editRanges, contentMatchValidated: true };
656
+ const editBatchSummary = createReadGuardEditBatchSummary({
657
+ requestedIndexes,
658
+ requestedTotal: edits.length,
659
+ resolvedIndexes,
660
+ resolvedTotal: resolvedRanges.length,
661
+ durationMs: Date.now() - startedAt,
662
+ terminalStatus: "success",
663
+ });
664
+ return {
665
+ touchedLines,
666
+ editRanges,
667
+ contentMatchValidated: true,
668
+ editBatchSummary,
669
+ };
553
670
  }
554
671
  /**
555
672
  * Normalises an oldText string for whitespace-only differences that editors routinely
@@ -888,7 +1005,7 @@ export function relocateEditRange(input, from, to) {
888
1005
  }
889
1006
  return applied;
890
1007
  }
891
- export function getTouchedLinesForGuard(event, filePath, sessionId) {
1008
+ export function getTouchedLinesForGuard(event, filePath, sessionId, correlationId) {
892
1009
  if (isToolCallEventType("edit", event)) {
893
1010
  // The host standard-edit fields (path, edits[].oldText/newText) are pinned
894
1011
  // to the SDK's EditToolInput, so a host edit-schema change is a compile
@@ -897,7 +1014,7 @@ export function getTouchedLinesForGuard(event, filePath, sessionId) {
897
1014
  // edit tools; oldText/newText are probed as optional because range-only
898
1015
  // edits omit them (refs #3).
899
1016
  const editInput = event.input;
900
- const hashlineResult = resolveHashlineEditInput(editInput, filePath, sessionId);
1017
+ const hashlineResult = resolveHashlineEditInput(editInput, filePath, sessionId, correlationId);
901
1018
  if (hashlineResult)
902
1019
  return hashlineResult;
903
1020
  if (editInput.oldRange) {
@@ -908,6 +1025,7 @@ export function getTouchedLinesForGuard(event, filePath, sessionId) {
908
1025
  if (filePath) {
909
1026
  logReadGuardEvent({
910
1027
  event: "touched_lines_detected",
1028
+ correlationId,
911
1029
  sessionId,
912
1030
  filePath,
913
1031
  metadata: {
@@ -935,14 +1053,14 @@ export function getTouchedLinesForGuard(event, filePath, sessionId) {
935
1053
  .filter((edit) => typeof edit.range?.start?.line !== "number" && !!edit.oldText);
936
1054
  if (rangedEdits.length === 0) {
937
1055
  if (filePath) {
938
- return resolveOldTextEdits(editInput.edits, filePath, sessionId);
1056
+ return resolveOldTextEdits(editInput.edits, filePath, sessionId, correlationId);
939
1057
  }
940
1058
  return { touchedLines: undefined };
941
1059
  }
942
1060
  let oldTextTouchedLines;
943
1061
  let oldTextEditRanges;
944
1062
  if (unresolvedOldTextEdits.length > 0 && filePath) {
945
- const resolved = resolveOldTextEdits(unresolvedOldTextEdits, filePath, sessionId);
1063
+ const resolved = resolveOldTextEdits(unresolvedOldTextEdits, filePath, sessionId, correlationId);
946
1064
  if (resolved.preflightError) {
947
1065
  return resolved;
948
1066
  }
@@ -970,6 +1088,7 @@ export function getTouchedLinesForGuard(event, filePath, sessionId) {
970
1088
  if (filePath) {
971
1089
  logReadGuardEvent({
972
1090
  event: "touched_lines_detected",
1091
+ correlationId,
973
1092
  sessionId,
974
1093
  filePath,
975
1094
  metadata: {
@@ -990,6 +1109,7 @@ export function getTouchedLinesForGuard(event, filePath, sessionId) {
990
1109
  const topLevelKeys = Object.keys(editInput);
991
1110
  logReadGuardEvent({
992
1111
  event: "touched_lines_missing",
1112
+ correlationId,
993
1113
  sessionId,
994
1114
  filePath,
995
1115
  metadata: {
@@ -1014,6 +1134,7 @@ export function getTouchedLinesForGuard(event, filePath, sessionId) {
1014
1134
  if (filePath) {
1015
1135
  logReadGuardEvent({
1016
1136
  event: "touched_lines_detected",
1137
+ correlationId,
1017
1138
  sessionId,
1018
1139
  filePath,
1019
1140
  metadata: {