@herbertgao/pi-extensions 2026.8.4 → 2026.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +11 -3
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +11 -3
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +24 -0
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +91 -1
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +7 -3
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +7 -6
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +21 -12
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +4 -5
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +53 -14
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +22 -12
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/result.ts +2 -4
  14. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  15. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +18 -0
  16. package/node_modules/@herbertgao/pi-subagents/package.json +8 -4
  17. package/node_modules/@herbertgao/pi-subagents/src/agent-color.ts +72 -67
  18. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +255 -0
  19. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +191 -3
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +20 -4
  21. package/node_modules/@herbertgao/pi-subagents/src/index.ts +289 -113
  22. package/node_modules/@herbertgao/pi-subagents/src/output-file.ts +24 -1
  23. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +24 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +15 -6
  25. package/node_modules/@herbertgao/pi-subagents/src/ui/schedule-menu.ts +9 -8
  26. package/node_modules/@herbertgao/pi-subagents/src/ui/select-item.ts +48 -0
  27. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +9 -5
  28. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +2 -0
  29. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +20 -0
  30. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +6 -0
  31. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +7 -0
  32. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
  33. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +7 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +16 -5
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +4 -2
  36. package/node_modules/@narumitw/pi-btw/README.md +32 -24
  37. package/node_modules/@narumitw/pi-btw/package.json +6 -6
  38. package/node_modules/@narumitw/pi-btw/src/btw.ts +4 -2
  39. package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -13
  40. package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
  41. package/node_modules/pi-lens/CHANGELOG.md +2535 -954
  42. package/node_modules/pi-lens/README.md +13 -0
  43. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +73 -18
  44. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +314 -0
  45. package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +21 -4
  46. package/node_modules/pi-lens/dist/clients/agent-nudge.js +14 -7
  47. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +68 -16
  48. package/node_modules/pi-lens/dist/clients/ast-grep-types.js +0 -1
  49. package/node_modules/pi-lens/dist/clients/ast-grep-yaml-synth.js +37 -10
  50. package/node_modules/pi-lens/dist/clients/atomic-write-staging.js +63 -0
  51. package/node_modules/pi-lens/dist/clients/atomic-write.js +114 -14
  52. package/node_modules/pi-lens/dist/clients/bash-file-access.js +193 -23
  53. package/node_modules/pi-lens/dist/clients/biome-client.js +136 -24
  54. package/node_modules/pi-lens/dist/clients/bootstrap.js +11 -2
  55. package/node_modules/pi-lens/dist/clients/bounded-cache.js +34 -0
  56. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +192 -0
  57. package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
  58. package/node_modules/pi-lens/dist/clients/bus-publish.js +19 -4
  59. package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +47 -5
  60. package/node_modules/pi-lens/dist/clients/cache-manager.js +97 -9
  61. package/node_modules/pi-lens/dist/clients/cache-observability.js +301 -14
  62. package/node_modules/pi-lens/dist/clients/call-graph.js +449 -117
  63. package/node_modules/pi-lens/dist/clients/cascade-format.js +57 -2
  64. package/node_modules/pi-lens/dist/clients/child-unref.js +85 -0
  65. package/node_modules/pi-lens/dist/clients/codebase-model.js +52 -23
  66. package/node_modules/pi-lens/dist/clients/collateral-test-role.js +40 -0
  67. package/node_modules/pi-lens/dist/clients/complexity-client.js +2 -1
  68. package/node_modules/pi-lens/dist/clients/console-guard-install.js +26 -0
  69. package/node_modules/pi-lens/dist/clients/cooperative-budget.js +42 -0
  70. package/node_modules/pi-lens/dist/clients/dead-code-client.js +137 -31
  71. package/node_modules/pi-lens/dist/clients/debug-handles.js +206 -0
  72. package/node_modules/pi-lens/dist/clients/debug-heap.js +167 -0
  73. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +153 -0
  74. package/node_modules/pi-lens/dist/clients/dependency-checker.js +361 -77
  75. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +65 -13
  76. package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +18 -4
  77. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +176 -29
  78. package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +23 -7
  79. package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +8 -18
  80. package/node_modules/pi-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +8 -5
  81. package/node_modules/pi-lens/dist/clients/dispatch/indent-detect.js +35 -0
  82. package/node_modules/pi-lens/dist/clients/dispatch/inline-suppressions.js +17 -8
  83. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +1172 -683
  84. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +14 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +11 -1
  86. package/node_modules/pi-lens/dist/clients/dispatch/rule-id-normalize.js +50 -0
  87. package/node_modules/pi-lens/dist/clients/dispatch/rule-policy.js +135 -0
  88. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +23 -5
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +5 -9
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +3 -2
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +154 -0
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +3 -2
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +5 -1
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +47 -6
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -9
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +9 -5
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +4 -8
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +2 -3
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -3
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +163 -0
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +37 -5
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +3 -1
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +13 -7
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +226 -0
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +69 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +3 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +473 -42
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +22 -0
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +97 -0
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +5 -4
  114. package/node_modules/pi-lens/dist/clients/disposition-publish.js +18 -4
  115. package/node_modules/pi-lens/dist/clients/durable-store.js +97 -0
  116. package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
  117. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +94 -3
  118. package/node_modules/pi-lens/dist/clients/extension-log.js +432 -0
  119. package/node_modules/pi-lens/dist/clients/extension-mode.js +73 -0
  120. package/node_modules/pi-lens/dist/clients/file-kinds.js +57 -0
  121. package/node_modules/pi-lens/dist/clients/file-role.js +18 -3
  122. package/node_modules/pi-lens/dist/clients/file-utils.js +56 -34
  123. package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
  124. package/node_modules/pi-lens/dist/clients/format-events-publish.js +51 -7
  125. package/node_modules/pi-lens/dist/clients/format-service.js +24 -8
  126. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +8 -0
  127. package/node_modules/pi-lens/dist/clients/formatters.js +358 -61
  128. package/node_modules/pi-lens/dist/clients/generated-artifacts.js +148 -15
  129. package/node_modules/pi-lens/dist/clients/git-guard.js +678 -11
  130. package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +4 -0
  131. package/node_modules/pi-lens/dist/clients/go-client.js +23 -40
  132. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +124 -7
  133. package/node_modules/pi-lens/dist/clients/grammar-source.js +12 -4
  134. package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +21 -3
  135. package/node_modules/pi-lens/dist/clients/host-ports.js +31 -0
  136. package/node_modules/pi-lens/dist/clients/installer/index.js +395 -100
  137. package/node_modules/pi-lens/dist/clients/instance-reaper.js +142 -172
  138. package/node_modules/pi-lens/dist/clients/jscpd-client.js +27 -55
  139. package/node_modules/pi-lens/dist/clients/knip-client.js +58 -42
  140. package/node_modules/pi-lens/dist/clients/language-policy.js +14 -2
  141. package/node_modules/pi-lens/dist/clients/language-profile.js +13 -7
  142. package/node_modules/pi-lens/dist/clients/latency-logger.js +72 -1
  143. package/node_modules/pi-lens/dist/clients/lens-config.js +12 -1
  144. package/node_modules/pi-lens/dist/clients/lens-engine.js +86 -17
  145. package/node_modules/pi-lens/dist/clients/lens-events.js +63 -9
  146. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
  147. package/node_modules/pi-lens/dist/clients/lens-map.js +94 -19
  148. package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +73 -0
  149. package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -1
  150. package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
  151. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +59 -14
  152. package/node_modules/pi-lens/dist/clients/lsp/client.js +662 -56
  153. package/node_modules/pi-lens/dist/clients/lsp/config.js +13 -2
  154. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +115 -0
  155. package/node_modules/pi-lens/dist/clients/lsp/edits.js +1012 -121
  156. package/node_modules/pi-lens/dist/clients/lsp/index.js +2025 -800
  157. package/node_modules/pi-lens/dist/clients/lsp/launch.js +32 -26
  158. package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
  159. package/node_modules/pi-lens/dist/clients/lsp/ruby-drive-dirs.js +83 -0
  160. package/node_modules/pi-lens/dist/clients/lsp/server.js +437 -86
  161. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +96 -0
  162. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
  163. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +18 -3
  164. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +28 -4
  165. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +8 -0
  166. package/node_modules/pi-lens/dist/clients/lsp-mutation.js +248 -0
  167. package/node_modules/pi-lens/dist/clients/mcp/analyze.js +127 -32
  168. package/node_modules/pi-lens/dist/clients/mcp/ipc.js +157 -24
  169. package/node_modules/pi-lens/dist/clients/mcp/session.js +235 -14
  170. package/node_modules/pi-lens/dist/clients/memory-sampler.js +115 -0
  171. package/node_modules/pi-lens/dist/clients/metrics-client.js +2 -1
  172. package/node_modules/pi-lens/dist/clients/metrics-history.js +2 -1
  173. package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
  174. package/node_modules/pi-lens/dist/clients/module-report-lsp.js +5 -0
  175. package/node_modules/pi-lens/dist/clients/module-report.js +168 -3
  176. package/node_modules/pi-lens/dist/clients/ndjson-logger.js +319 -118
  177. package/node_modules/pi-lens/dist/clients/opengrep-client.js +1 -1
  178. package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +120 -5
  179. package/node_modules/pi-lens/dist/clients/path-utils.js +110 -9
  180. package/node_modules/pi-lens/dist/clients/pipeline.js +76 -15
  181. package/node_modules/pi-lens/dist/clients/print-mode.js +21 -0
  182. package/node_modules/pi-lens/dist/clients/project-changes.js +40 -0
  183. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +3 -2
  184. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +1 -1
  185. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +8 -0
  186. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +23 -2
  187. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +21 -1
  188. package/node_modules/pi-lens/dist/clients/project-lens-config.js +86 -9
  189. package/node_modules/pi-lens/dist/clients/project-report.js +27 -13
  190. package/node_modules/pi-lens/dist/clients/project-snapshot.js +175 -20
  191. package/node_modules/pi-lens/dist/clients/project-trust.js +181 -0
  192. package/node_modules/pi-lens/dist/clients/quiet-window.js +18 -4
  193. package/node_modules/pi-lens/dist/clients/read-bridge.js +147 -0
  194. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +159 -1
  195. package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +150 -29
  196. package/node_modules/pi-lens/dist/clients/read-guard.js +185 -4
  197. package/node_modules/pi-lens/dist/clients/resource-sampler.js +70 -84
  198. package/node_modules/pi-lens/dist/clients/review-graph/builder.js +1122 -221
  199. package/node_modules/pi-lens/dist/clients/review-graph/git-identity.js +2 -1
  200. package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +21 -10
  201. package/node_modules/pi-lens/dist/clients/review-graph/query.js +24 -0
  202. package/node_modules/pi-lens/dist/clients/review-graph/symbol-id.js +46 -0
  203. package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +57 -6
  204. package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +51 -3
  205. package/node_modules/pi-lens/dist/clients/review-graph-logger.js +30 -1
  206. package/node_modules/pi-lens/dist/clients/ruff-client.js +27 -44
  207. package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
  208. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +257 -77
  209. package/node_modules/pi-lens/dist/clients/runtime-context.js +129 -12
  210. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +242 -26
  211. package/node_modules/pi-lens/dist/clients/runtime-session.js +428 -117
  212. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +71 -48
  213. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +342 -33
  214. package/node_modules/pi-lens/dist/clients/runtime-turn.js +619 -93
  215. package/node_modules/pi-lens/dist/clients/rust-client.js +23 -38
  216. package/node_modules/pi-lens/dist/clients/safe-spawn.js +777 -62
  217. package/node_modules/pi-lens/dist/clients/security-scan-client.js +90 -6
  218. package/node_modules/pi-lens/dist/clients/session-state-store.js +3 -2
  219. package/node_modules/pi-lens/dist/clients/sg-runner.js +424 -196
  220. package/node_modules/pi-lens/dist/clients/slow-fs.js +2 -1
  221. package/node_modules/pi-lens/dist/clients/smells-rollup.js +231 -0
  222. package/node_modules/pi-lens/dist/clients/source-filter.js +184 -20
  223. package/node_modules/pi-lens/dist/clients/source-walker.js +66 -10
  224. package/node_modules/pi-lens/dist/clients/startup-scan.js +15 -16
  225. package/node_modules/pi-lens/dist/clients/startup-timing.js +7 -1
  226. package/node_modules/pi-lens/dist/clients/test-runner-client.js +469 -32
  227. package/node_modules/pi-lens/dist/clients/tool-event.js +35 -0
  228. package/node_modules/pi-lens/dist/clients/tool-policy.js +390 -39
  229. package/node_modules/pi-lens/dist/clients/tool-render.js +155 -0
  230. package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
  231. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +6 -1
  232. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +419 -50
  233. package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +21 -0
  234. package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +7 -1
  235. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +7 -2
  236. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +44 -7
  237. package/node_modules/pi-lens/dist/clients/user-notify.js +51 -0
  238. package/node_modules/pi-lens/dist/clients/vanished-instance-marker.js +57 -0
  239. package/node_modules/pi-lens/dist/clients/warm-attach.js +50 -13
  240. package/node_modules/pi-lens/dist/clients/widget-state.js +300 -43
  241. package/node_modules/pi-lens/dist/clients/word-index.js +680 -81
  242. package/node_modules/pi-lens/dist/clients/workspace-topology.js +89 -6
  243. package/node_modules/pi-lens/dist/index.js +51785 -36118
  244. package/node_modules/pi-lens/dist/mcp/analyze-cli.js +182 -29
  245. package/node_modules/pi-lens/dist/mcp/server.js +219 -46
  246. package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
  247. package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
  248. package/node_modules/pi-lens/dist/tools/ast-grep-search.js +93 -27
  249. package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
  250. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +203 -38
  251. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +210 -42
  252. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -3
  253. package/node_modules/pi-lens/dist/tools/module-report.js +9 -0
  254. package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
  255. package/node_modules/pi-lens/docs/agent-guide.md +40 -15
  256. package/node_modules/pi-lens/docs/agent-tools.md +21 -10
  257. package/node_modules/pi-lens/docs/analysisall.md +192 -0
  258. package/node_modules/pi-lens/docs/api-ports-inventory.md +165 -0
  259. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +14 -3
  260. package/node_modules/pi-lens/docs/durable-store-audit-1202.md +32 -0
  261. package/node_modules/pi-lens/docs/environment-variables.md +44 -0
  262. package/node_modules/pi-lens/docs/fable.md +27 -0
  263. package/node_modules/pi-lens/docs/features.md +45 -3
  264. package/node_modules/pi-lens/docs/globalconfig.md +56 -1
  265. package/node_modules/pi-lens/docs/language-coverage.md +4 -3
  266. package/node_modules/pi-lens/docs/lsp-capability-matrix.md +2 -2
  267. package/node_modules/pi-lens/docs/mcp.md +37 -4
  268. package/node_modules/pi-lens/docs/servercapabilities.md +3 -3
  269. package/node_modules/pi-lens/docs/settings.md +18 -1
  270. package/node_modules/pi-lens/docs/tools.md +4 -1
  271. package/node_modules/pi-lens/docs/usage.md +41 -5
  272. package/node_modules/pi-lens/docs/word-index.md +35 -0
  273. package/node_modules/pi-lens/package.json +10 -10
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-except-test.yml +49 -0
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-host-path-in-win32-branch-test.yml +87 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +8 -0
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-js-test.yml +9 -0
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-nested-links-test.yml +11 -1
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-json-store-write-test.yml +17 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +7 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +7 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +8 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +8 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-laundering-test.yml +11 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-win32-isabsolute-for-qualification-test.yml +16 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-except.yml +3 -15
  288. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +25 -0
  289. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +21 -0
  290. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread-js.yml +21 -0
  291. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
  292. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-nested-links.yml +7 -0
  293. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +30 -0
  294. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +9 -0
  295. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +9 -0
  296. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +13 -0
  297. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +16 -0
  298. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +27 -0
  299. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +23 -0
  300. package/node_modules/pi-lens/rules/tree-sitter-queries/tsx/no-nested-links.yml +4 -6
  301. package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +2 -2
  302. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +134 -2
  303. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +10 -11
  304. package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
  305. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +8 -114
  306. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +129 -0
  307. package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
  308. package/node_modules/pi-mcp-adapter/CHANGELOG.md +38 -0
  309. package/node_modules/pi-mcp-adapter/README.md +38 -4
  310. package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
  311. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +1 -1
  312. package/node_modules/pi-mcp-adapter/cli.js +25 -4
  313. package/node_modules/pi-mcp-adapter/commands.ts +15 -7
  314. package/node_modules/pi-mcp-adapter/config.ts +4 -4
  315. package/node_modules/pi-mcp-adapter/direct-tools.ts +58 -8
  316. package/node_modules/pi-mcp-adapter/host-html-template.ts +0 -8
  317. package/node_modules/pi-mcp-adapter/index.ts +8 -3
  318. package/node_modules/pi-mcp-adapter/init.ts +29 -5
  319. package/node_modules/pi-mcp-adapter/lifecycle.ts +0 -4
  320. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
  321. package/node_modules/pi-mcp-adapter/mcp-auth.ts +60 -2
  322. package/node_modules/pi-mcp-adapter/mcp-panel.ts +45 -9
  323. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +22 -20
  324. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +2 -1
  325. package/node_modules/pi-mcp-adapter/metadata-cache.ts +37 -4
  326. package/node_modules/pi-mcp-adapter/npx-resolver.ts +81 -26
  327. package/node_modules/pi-mcp-adapter/package.json +4 -3
  328. package/node_modules/pi-mcp-adapter/proxy-modes.ts +108 -26
  329. package/node_modules/pi-mcp-adapter/request-headers-command.ts +336 -0
  330. package/node_modules/pi-mcp-adapter/search-ranking.ts +86 -7
  331. package/node_modules/pi-mcp-adapter/server-manager.ts +41 -7
  332. package/node_modules/pi-mcp-adapter/session-recovery.ts +8 -2
  333. package/node_modules/pi-mcp-adapter/tool-approval.ts +48 -7
  334. package/node_modules/pi-mcp-adapter/tool-metadata.ts +62 -4
  335. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +138 -12
  336. package/node_modules/pi-mcp-adapter/types.ts +176 -27
  337. package/node_modules/pi-mcp-adapter/ui-server.ts +20 -1
  338. package/node_modules/pi-web-access/CHANGELOG.md +14 -0
  339. package/node_modules/pi-web-access/README.md +18 -12
  340. package/node_modules/pi-web-access/auth-fetch.ts +148 -0
  341. package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
  342. package/node_modules/pi-web-access/curator-page.ts +5 -3
  343. package/node_modules/pi-web-access/curator-server.ts +2 -1
  344. package/node_modules/pi-web-access/extract.ts +106 -34
  345. package/node_modules/pi-web-access/fetch-params.ts +17 -3
  346. package/node_modules/pi-web-access/firecrawl.ts +172 -12
  347. package/node_modules/pi-web-access/gemini-search.ts +18 -4
  348. package/node_modules/pi-web-access/index.ts +120 -48
  349. package/node_modules/pi-web-access/package.json +2 -2
  350. package/node_modules/pi-web-access/summary-review.ts +11 -5
  351. package/node_modules/pi-web-access/youtube-extract.ts +2 -2
  352. package/package.json +12 -13
  353. package/node_modules/pi-lens/dist/clients/ast-grep-parser.js +0 -86
  354. package/node_modules/pi-lens/dist/clients/lsp/interactive-install.js +0 -367
  355. package/node_modules/pi-lens/dist/clients/lsp/lsp-index.js +0 -10
  356. package/node_modules/pi-lens/dist/clients/lsp/server-strategies.js +0 -5
  357. package/node_modules/pi-lens/dist/clients/project-metadata.js +0 -690
  358. package/node_modules/pi-lens/dist/clients/source-groups.js +0 -96
  359. package/node_modules/pi-lens/dist/clients/startup-marker.js +0 -6
  360. package/node_modules/pi-lens/dist/clients/types.js +0 -11
@@ -19,7 +19,7 @@ import {
19
19
  truncateToWidth,
20
20
  visibleWidth,
21
21
  } from "@earendil-works/pi-tui"
22
- import { renderAgentName } from "../agent-color.js"
22
+ import { hasAgentBadge, renderAgentName } from "../agent-color.js"
23
23
  import type { AgentManager } from "../agent-manager.js"
24
24
  import type { AgentRecord } from "../types.js"
25
25
  import { getLifetimeTotal } from "../usage.js"
@@ -476,15 +476,24 @@ export class FleetList {
476
476
  width: number,
477
477
  theme: Theme,
478
478
  ): string {
479
- const left = ` ${this.bullet(rosterIndex, sel, theme)} ${renderAgentName(record.type, theme, { fallbackColor: "muted" })} ${record.description}`
479
+ const selected = rosterIndex === sel
480
+ const name = renderAgentName(
481
+ record.type,
482
+ theme,
483
+ selected
484
+ ? { fallbackColor: "text", bold: hasAgentBadge(record.type) }
485
+ : { fallbackColor: "muted" },
486
+ )
487
+ const description = selected
488
+ ? theme.fg("text", record.description)
489
+ : record.description
490
+ const left = ` ${this.bullet(rosterIndex, sel, theme)} ${name} ${description}`
480
491
  const tokens = getLifetimeTotal(
481
492
  this.agentActivity.get(record.id)?.lifetimeUsage ?? record.lifetimeUsage,
482
493
  )
483
494
  const elapsedMs = (record.completedAt ?? Date.now()) - record.startedAt // freezes once finished
484
- const right = theme.fg(
485
- "dim",
486
- `${formatFleetElapsed(elapsedMs)} · ${formatFleetTokens(tokens)}`,
487
- )
495
+ const stats = `${formatFleetElapsed(elapsedMs)} · ${formatFleetTokens(tokens)}`
496
+ const right = selected ? theme.fg("text", stats) : theme.fg("dim", stats)
488
497
  return rightAlign(left, right, width)
489
498
  }
490
499
  }
@@ -11,6 +11,7 @@
11
11
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent"
12
12
  import type { SubagentScheduler } from "../schedule.js"
13
13
  import type { ScheduledSubagent } from "../types.js"
14
+ import { selectItem } from "./select-item.js"
14
15
 
15
16
  /** Format an ISO timestamp as relative time ("in 4h", "2d ago", "—"). */
16
17
  function relTime(iso: string | undefined, now = Date.now()): string {
@@ -88,16 +89,16 @@ export async function showSchedulesMenu(
88
89
  return
89
90
  }
90
91
 
91
- const labels = jobs.map((j) => formatJob(j, scheduler))
92
- const choice = await ctx.ui.select(
92
+ // Numbered + item-paired: two jobs whose names agree in the first 18
93
+ // characters format identically, and matching the returned string back
94
+ // against a parallel label array cancelled whichever came first.
95
+ const job = await selectItem(
96
+ ctx.ui,
93
97
  `Scheduled jobs (${jobs.length}) — select to cancel`,
94
- labels,
98
+ jobs,
99
+ (j) => formatJob(j, scheduler),
95
100
  )
96
- if (!choice) return
97
-
98
- const idx = labels.indexOf(choice)
99
- if (idx < 0) return
100
- const job = jobs[idx]
101
+ if (!job) return
101
102
 
102
103
  const ok = await ctx.ui.confirm(
103
104
  `Cancel "${job.name}"?`,
@@ -0,0 +1,48 @@
1
+ /**
2
+ * select-item.ts — pick an item from a list via `ctx.ui.select`, safely.
3
+ *
4
+ * Pi's dialog API is `select(title, options: string[]) => Promise<string | undefined>`:
5
+ * strings in, string out, with no index or value form. Callers therefore have to
6
+ * map the returned string back to the item it came from, and the obvious way —
7
+ * `labels.indexOf(choice)` over a parallel array — silently resolves to the
8
+ * FIRST match whenever two rows format identically. Row formatters here truncate
9
+ * (job names to 18 chars, agent descriptions to whatever fits), and the text they
10
+ * truncate is LLM-authored, so collisions are ordinary rather than exotic.
11
+ *
12
+ * This numbers every row, which makes the labels unique by construction — no
13
+ * data-dependent branch that only executes in the case nobody exercises — and
14
+ * keeps each label paired with its item so a later edit that sorts or filters
15
+ * between building and resolving cannot desync them.
16
+ */
17
+
18
+ /** Minimal shape of the `ctx.ui` surface this needs. */
19
+ export interface SelectUI {
20
+ select(title: string, options: string[]): Promise<string | undefined>
21
+ }
22
+
23
+ /**
24
+ * Show a numbered picker and return the chosen item (not its label).
25
+ *
26
+ * Returns undefined when the user escapes, or when the returned string is not
27
+ * one we offered.
28
+ */
29
+ export async function selectItem<T>(
30
+ ui: SelectUI,
31
+ title: string,
32
+ items: readonly T[],
33
+ format: (item: T, index: number) => string,
34
+ ): Promise<T | undefined> {
35
+ // Pad the number so a 10+ item list keeps its columns aligned.
36
+ const width = String(items.length).length
37
+ const rows = items.map((item, i) => ({
38
+ item,
39
+ label: `${String(i + 1).padStart(width)}. ${format(item, i)}`,
40
+ }))
41
+
42
+ const choice = await ui.select(
43
+ title,
44
+ rows.map((r) => r.label),
45
+ )
46
+ if (!choice) return undefined
47
+ return rows.find((r) => r.label === choice)?.item
48
+ }
@@ -134,11 +134,15 @@ export function cleanupWorktree(
134
134
  // Truncate description for commit message (no shell sanitization needed — execFileSync uses argv)
135
135
  const safeDesc = agentDescription.slice(0, 200)
136
136
  const commitMsg = `pi-agent: ${safeDesc}`
137
- execFileSync("git", ["commit", "--no-verify", "-m", commitMsg], {
138
- cwd: worktree.path,
139
- stdio: "pipe",
140
- timeout: 10000,
141
- })
137
+ execFileSync(
138
+ "git",
139
+ ["commit", "--no-verify", "--no-gpg-sign", "-m", commitMsg],
140
+ {
141
+ cwd: worktree.path,
142
+ stdio: "pipe",
143
+ timeout: 10000,
144
+ },
145
+ )
142
146
  } else {
143
147
  const currentSha = execFileSync("git", ["rev-parse", "HEAD"], {
144
148
  cwd: worktree.path,
@@ -27,6 +27,8 @@ Nothing to set up — the tool is live as soon as Pi restarts. Hand the model a
27
27
 
28
28
  Rather than picking a strategy on your behalf, the model calls `ask_user_question` and a dialog takes over the bottom of your terminal. Move with `↑`/`↓`, choose with `Enter`, press `n` to attach a note, or land on the `Type something.` row to answer in your own words. While typing, `Shift+Enter` adds a line, `Ctrl+G` opens Pi's configured external editor, and `Ctrl+U` clears the draft; browsing another option and returning keeps what you wrote. `Esc` abandons the questionnaire entirely.
29
29
 
30
+ When the questionnaire begins waiting in an interactive TTY, it emits one standard terminal BEL (`\x07`). Your terminal configuration determines whether that appears as an audible alert, a visual alert, or nothing; redirected and non-TTY output is untouched.
31
+
30
32
  ![Single question in the dialog: the tab strip reads Feature Type, Design Tab, Testing, Release, Submit; the question Which real development task are we planning right now? sits above four numbered options — Bug fix (Recommended), New feature, Refactor, Perf tuning — each with a one-line description, followed by the appended Type something. row](https://raw.githubusercontent.com/juicesharp/rpiv-mono/main/packages/rpiv-ask-user-question/docs/single-question.jpg)
31
33
 
32
34
  When the model asks several things at once, `Tab` moves between them and a Submit tab reviews everything before it goes back:
@@ -61,6 +61,24 @@ const ERROR_SESSION_LOAD_FAILED =
61
61
  const ERROR_STALE_MODULE_CACHE =
62
62
  "Error: the questionnaire UI cannot load — the host's module cache went stale after an earlier failed load (typically dependencies replaced on disk mid-session). This is unrecoverable within the current Pi process. The user never saw the questions — do NOT treat this as a decline. Ask the questions as plain chat text instead, and tell the user to restart Pi to restore this tool.";
63
63
 
64
+ /** Standard terminal bell — same byte rpiv-warp exports as OSC_TERMINATOR. */
65
+ export const BEL = "\x07";
66
+
67
+ /**
68
+ * Emit one portable terminal attention signal without touching redirected output.
69
+ * Writes to stdout rather than rpiv-warp's `/dev/tty` transport: the `isTTY` gate
70
+ * both proves an interactive terminal owns the coming wait and keeps the byte out
71
+ * of piped RPC transports (VS Code pendant, Zed) — a `/dev/tty` write would ring
72
+ * even when the questionnaire renders in a remote host's own UI.
73
+ */
74
+ function emitTerminalAttention(): void {
75
+ try {
76
+ if (process.stdout.isTTY) process.stdout.write(BEL);
77
+ } catch {
78
+ // Terminal attention is best effort; the questionnaire must still proceed.
79
+ }
80
+ }
81
+
64
82
  /** Delay before the background session-graph pre-warm; mirrors rpiv-workflow's /wf prewarm. */
65
83
  export const PREWARM_DELAY_MS = 2000;
66
84
 
@@ -173,6 +191,7 @@ Preview content is rendered as markdown in a monospace box. Multi-line text with
173
191
  if ((ctx as { mode?: string }).mode === "rpc" && hasDialogUI(ctx.ui)) {
174
192
  emitAskUserBlockedEvent(pi, true);
175
193
  try {
194
+ emitTerminalAttention();
176
195
  return buildQuestionnaireResponse(await runRpcQuestionnaire(ctx.ui, typed), typed);
177
196
  } finally {
178
197
  emitAskUserBlockedEvent(pi, false);
@@ -232,6 +251,7 @@ Preview content is rendered as markdown in a monospace box. Multi-line text with
232
251
 
233
252
  emitAskUserBlockedEvent(pi, true);
234
253
  try {
254
+ emitTerminalAttention();
235
255
  const result = await ctx.ui.custom<QuestionnaireResult>(
236
256
  (tui, theme, keybindings, done) => {
237
257
  const session = new QuestionnaireSession({
@@ -11,6 +11,12 @@ render at all.
11
11
  | RPC / ACP host (VS Code pendant, Zed, Paseo) | `ask_user_question` in its tool list | A sequence of the host's own native select and input dialogs |
12
12
  | Non-interactive run (no UI) | Nothing — the tool is removed | Nothing |
13
13
 
14
+ ### Terminal attention
15
+
16
+ After UI availability and questionnaire validation succeed, the package emits exactly one standard terminal BEL (`\x07`) immediately before the interactive wait begins. The signal is sent to `stdout` only when `process.stdout.isTTY` is true, so redirected output and non-TTY RPC streams stay untouched. A TTY-backed RPC dialog walker receives the same signal as the TUI path.
17
+
18
+ The BEL is best effort: if the synchronous terminal write fails, the questionnaire continues and its existing prompt/blocked lifecycle and result envelope are unchanged. The terminal configuration decides whether the BEL is audible, visual, or ignored. No BEL is emitted for missing UI, invalid questionnaires, or a failed TUI session load.
19
+
14
20
  ### Non-interactive runs
15
21
 
16
22
  A `before_agent_start` hook reconciles the active tool set against `ctx.hasUI` before every
@@ -18,6 +18,13 @@ adapts to the size of your terminal.
18
18
  | `Ctrl+U` | Clear the current custom-answer draft. | `Type something.` input |
19
19
  | `Ctrl+]` | Collapse or expand the dialog. Configurable via `collapseKey`. | Everywhere, including while collapsed |
20
20
 
21
+ The table names the default keys; the dialog actually follows your Pi keybindings.
22
+ Confirm listens to both `tui.select.confirm` and `tui.input.submit`, and a key bound to
23
+ `tui.input.newLine` always inserts a newline even if it also matches confirm. So a
24
+ Slack-style configuration — `enter` folded into `tui.input.newLine`, submit moved to
25
+ `ctrl+enter` — keeps working: `enter` breaks lines, and your submit key confirms
26
+ everywhere `Enter` does.
27
+
21
28
  In a multi-select question, `Enter` on a regular row toggles its checkbox exactly like
22
29
  `Space` — it does not submit. Committing the question means focusing the `Next` row and
23
30
  pressing `Enter`. That is deliberate: it makes `Enter` a zero-cost way to flip boxes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juicesharp/rpiv-ask-user-question",
3
- "version": "2.4.0",
3
+ "version": "2.6.0",
4
4
  "description": "Pi extension. A structured questionnaire the model can put to you when it would otherwise guess, with typed options instead of free-form replies.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -93,7 +93,7 @@
93
93
  }
94
94
  },
95
95
  "dependencies": {
96
- "@juicesharp/rpiv-config": "^2.4.0",
96
+ "@juicesharp/rpiv-config": "^2.6.0",
97
97
  "typebox": "^1.1.24"
98
98
  }
99
99
  }
@@ -130,6 +130,13 @@ class QuestionnaireBuilder {
130
130
  const textEditorTheme = editorTheme(this.theme);
131
131
  this.notesInput = new Editor(this.tui, textEditorTheme);
132
132
  this.inlineInput = new Editor(this.tui, textEditorTheme);
133
+ // The key router owns confirm/submit semantics; keys reaching these headless
134
+ // editors are text-editing only. Without this, a `tui.input.submit` match inside
135
+ // Editor.handleInput would run submitValue(), which resets the buffer and
136
+ // silently destroys the draft — no onSubmit is wired here, so the text is
137
+ // unrecoverable (#156).
138
+ this.notesInput.disableSubmit = true;
139
+ this.inlineInput.disableSubmit = true;
133
140
  }
134
141
 
135
142
  build(): QuestionnaireBuilt {
@@ -6,6 +6,7 @@ import type { QuestionnaireRuntime, QuestionnaireState } from "./state.js";
6
6
  const KEYBIND_UP = "tui.select.up";
7
7
  const KEYBIND_DOWN = "tui.select.down";
8
8
  const KEYBIND_CONFIRM = "tui.select.confirm";
9
+ const KEYBIND_SUBMIT = "tui.input.submit";
9
10
  const KEYBIND_CANCEL = "tui.select.cancel";
10
11
  const KEYBIND_NEW_LINE = "tui.input.newLine";
11
12
  const KEYBIND_EDITOR_UP = "tui.editor.cursorUp";
@@ -39,6 +40,16 @@ export interface QuestionnaireKeybindings {
39
40
  matches(data: string, name: string): boolean;
40
41
  }
41
42
 
43
+ // Confirm has two semantic sources: `tui.select.confirm` (the select-list default)
44
+ // and `tui.input.submit` (the user's "send" key). A Slack-style configuration folds
45
+ // `enter` into `tui.input.newLine` and moves submit elsewhere (e.g. `ctrl+enter`);
46
+ // the newline checks below stay first, so without the submit source every confirm
47
+ // branch would be shadowed by the collision and no key could confirm (#156). With
48
+ // pi defaults both names resolve to `enter`, so matching either is equivalent.
49
+ function isConfirm(kb: QuestionnaireKeybindings, data: string): boolean {
50
+ return kb.matches(data, KEYBIND_CONFIRM) || kb.matches(data, KEYBIND_SUBMIT);
51
+ }
52
+
42
53
  export function wrapTab(index: number, total: number): number {
43
54
  if (total <= 0) return 0;
44
55
  return ((index % total) + total) % total;
@@ -183,7 +194,7 @@ export function routeKey(data: string, state: QuestionnaireState, runtime: Quest
183
194
  if (state.notesVisible) {
184
195
  if (kb.matches(data, KEYBIND_CANCEL)) return { kind: "notes_exit" };
185
196
  if (kb.matches(data, KEYBIND_NEW_LINE)) return { kind: "notes_forward", data };
186
- if (kb.matches(data, KEYBIND_CONFIRM)) return { kind: "notes_exit" };
197
+ if (isConfirm(kb, data)) return { kind: "notes_exit" };
187
198
  return { kind: "notes_forward", data };
188
199
  }
189
200
 
@@ -191,7 +202,7 @@ export function routeKey(data: string, state: QuestionnaireState, runtime: Quest
191
202
  // Newline takes precedence over confirmation if a user configuration binds
192
203
  // the same physical key to both semantic actions.
193
204
  if (kb.matches(data, KEYBIND_NEW_LINE)) return { kind: "ignore" };
194
- if (kb.matches(data, KEYBIND_CONFIRM)) {
205
+ if (isConfirm(kb, data)) {
195
206
  const answer = buildSingleSelectAnswer(state, runtime);
196
207
  if (!answer) return { kind: "ignore" };
197
208
  return { kind: "confirm", answer, autoAdvanceTab: computeAutoAdvanceTab(state, runtime) };
@@ -219,7 +230,7 @@ export function routeKey(data: string, state: QuestionnaireState, runtime: Quest
219
230
  const next = wrapTab(state.submitChoiceIndex + delta, 2);
220
231
  return { kind: "submit_nav", nextIndex: (next === 1 ? 1 : 0) as 0 | 1 };
221
232
  }
222
- if (kb.matches(data, KEYBIND_CONFIRM)) {
233
+ if (isConfirm(kb, data)) {
223
234
  // D1 (revised): Submit always submits; Cancel always cancels. The warning header
224
235
  // is informational only — `allAnswered(state)` no longer gates submission. Partial
225
236
  // answers flow through `orderedAnswers()` in the host.
@@ -265,7 +276,7 @@ export function routeKey(data: string, state: QuestionnaireState, runtime: Quest
265
276
  if (focusedMeta?.activatesInputMode) return { kind: "ignore" };
266
277
  return { kind: "toggle", index: state.optionIndex };
267
278
  }
268
- if (kb.matches(data, KEYBIND_CONFIRM)) {
279
+ if (isConfirm(kb, data)) {
269
280
  // Enter on the "Type something." row is handled by the inputMode block above
270
281
  // (→ confirm kind:"custom"). Defensive: never enter the toggle/multi_confirm
271
282
  // path for an inputMode-activating row.
@@ -289,7 +300,7 @@ export function routeKey(data: string, state: QuestionnaireState, runtime: Quest
289
300
  return { kind: "ignore" };
290
301
  }
291
302
 
292
- if (kb.matches(data, KEYBIND_CONFIRM)) {
303
+ if (isConfirm(kb, data)) {
293
304
  const answer = buildSingleSelectAnswer(state, runtime);
294
305
  if (!answer) return { kind: "ignore" };
295
306
  return { kind: "confirm", answer, autoAdvanceTab: computeAutoAdvanceTab(state, runtime) };
@@ -139,7 +139,9 @@ export class QuestionnaireSession {
139
139
  }
140
140
 
141
141
  private mirrorNotesDraft(s: QuestionnaireState): QuestionnaireState {
142
- const draft = this.notesInput.getText();
142
+ // Drafts restore through Editor.setText, which clears the backing paste map —
143
+ // read expanded so stored drafts never orphan a paste marker.
144
+ const draft = this.notesInput.getExpandedText?.() ?? this.notesInput.getText();
143
145
  return s.notesDraft === draft ? s : { ...s, notesDraft: draft };
144
146
  }
145
147
 
@@ -202,7 +204,7 @@ export class QuestionnaireSession {
202
204
  const lastLine = this.inlineInput.getLines().length - 1;
203
205
  return {
204
206
  keybindings: this.keybindings,
205
- inputBuffer: this.inlineInput.getText(),
207
+ inputBuffer: this.inlineInput.getExpandedText?.() ?? this.inlineInput.getText(),
206
208
  canMoveInputUp: cursor.line > 0,
207
209
  canMoveInputDown: cursor.line < lastLine,
208
210
  questions: this.questions,
@@ -18,7 +18,7 @@ Use it when you want to ask a temporary question, inspect context, or get a shor
18
18
  - Optionally brings the latest answer, a question-to-end suffix, an exact line range, or the entire side thread into the main editor.
19
19
  - Uses the current session branch as context.
20
20
  - Uses Pi's current model or an independent model selected in `pi-btw.json`.
21
- - Uses a pi-btw thinking level that can be changed with Pi's configured thinking shortcut and remembered for next time.
21
+ - Uses a pi-btw thinking level that can either start from the main thread or use a fixed remembered value.
22
22
  - Does not append the side question or answer to the main conversation.
23
23
  - Works as an independently installable npm Pi extension package.
24
24
 
@@ -58,14 +58,15 @@ Examples:
58
58
  /btw is this API name idiomatic?
59
59
  ```
60
60
 
61
- Running `/btw` alone opens a menu with **Start side thread** selected first. When the current Pi
62
- session has non-empty side threads in memory, **Resume side thread** opens a bounded choice list;
63
- **Settings** changes the starting thinking level and whether shortcut changes are remembered.
64
- Each Resume row keeps the first question as its fixed title, shows its question count, and the list
65
- is ordered by the newest recorded answer or visible error. Opening and closing a thread without a
66
- new result does not reorder it. `/btw <question>` bypasses this menu and always starts a fresh side
67
- thread. Its answer opens above the side-thread editor. The side thread uses a dedicated full-screen
68
- terminal view.
61
+ Running `/btw` alone opens a menu with **Start side thread** selected first.
62
+ When the current Pi session has non-empty side threads in memory, **Resume side thread** opens a bounded searchable choice list.
63
+ Search matches the displayed first question and question count while returning the thread's raw in-memory ID.
64
+ **Settings** changes the starting thinking level and whether shortcut changes for fixed levels are remembered.
65
+ Each Resume row keeps the first question as its fixed title, shows its question count, and the list is ordered by the newest recorded answer or visible error.
66
+ Opening and closing a thread without a new result does not reorder it.
67
+ `/btw <question>` bypasses this menu and always starts a fresh side thread.
68
+ Its answer opens above the side-thread editor.
69
+ The side thread uses a dedicated full-screen terminal view.
69
70
  The main agent continues running in the background, but its screen rendering stays suspended until
70
71
  `/btw` closes, so new main-thread output cannot move a mouse selection inside the side thread.
71
72
  Drag the primary mouse button across side-thread text to select and copy it through Pi's terminal
@@ -78,9 +79,11 @@ Previous side questions and answers remain available to the model and visible fo
78
79
  invocation. The side-thread header shows its current thinking level. Press Pi's configured
79
80
  `app.thinking.cycle` shortcut (`Shift+Tab` by default) in the composer to cycle the levels
80
81
  supported by the side-thread model; every later question uses the displayed level until it is
81
- changed again. By default, each shortcut change is also written to `pi-btw.json` for the next
82
- invocation. Turn **Remember thinking level changes** off in Settings to keep changes local to the
83
- current side thread. Neither path changes the main session's thinking level.
82
+ changed again. When a fixed thinking level is selected, each shortcut change is also written to
83
+ `pi-btw.json` for the next invocation by default. Turn **Remember thinking level changes** off in
84
+ Settings to keep fixed-level changes local to the current side thread. When **Same as main thread** is
85
+ selected, shortcut changes are always local to the current side thread. Neither path changes the main
86
+ session's thinking level.
84
87
  While a response is running, the transcript and composer remain visible above an `Answering…`
85
88
  status.
86
89
  Type another question and press `Enter` to queue it as `Steering`; queued questions are shown in
@@ -147,18 +150,23 @@ cannot be found or authenticated, pi-btw warns and falls back to the current ses
147
150
  If neither model is available, `/btw` reports an error and stops. This selection affects only
148
151
  `/btw`; it does not change the main session model.
149
152
 
150
- Pi calls its reasoning setting the **thinking level**. `thinkingLevel` sets pi-btw's starting
151
- level; accepted values are `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. When the
152
- field is absent for backward compatibility, the next invocation starts from the current session
153
- level. The initial value and shortcut cycle are clamped to the selected side model's capabilities
154
- using Pi's model rules. Pi-btw does not read, write, or change the main session's
155
- `defaultThinkingLevel`.
156
-
157
- `rememberThinkingLevelChanges` controls only persistence and defaults to `true` when omitted. A
158
- side-thread shortcut always changes that side thread immediately. When remembering is on, the
159
- concrete level is written for the next invocation; when off, `pi-btw.json` stays unchanged. If a
160
- shortcut write fails, the local change remains active and pi-btw warns that it was not remembered.
161
- A failed Settings-screen save instead restores the previous displayed value.
153
+ Pi calls its reasoning setting the **thinking level**. In Settings, choose **Same as main thread**
154
+ to start each new side thread from the main thread's current thinking level. This is stored by
155
+ omitting `thinkingLevel` from `pi-btw.json`.
156
+
157
+ Set `thinkingLevel` only when you want a fixed pi-btw starting level. Accepted fixed values are
158
+ `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. The initial value and shortcut cycle
159
+ are clamped to the selected side model's capabilities using Pi's model rules. Resumed side threads
160
+ keep their own local thinking level instead of re-syncing with the main thread. Pi-btw does not read,
161
+ write, or change the main session's `defaultThinkingLevel`.
162
+
163
+ `rememberThinkingLevelChanges` controls only persistence for fixed thinking levels and defaults to
164
+ `true` when omitted. A side-thread shortcut always changes that side thread immediately. When a fixed
165
+ thinking level is selected and remembering is on, the concrete level is written for the next
166
+ invocation; when off, `pi-btw.json` stays unchanged. When **Same as main thread** is selected,
167
+ shortcut changes stay local even when remembering is on. If a shortcut write fails, the local change
168
+ remains active and pi-btw warns that it was not remembered. A failed Settings-screen save instead
169
+ restores the previous displayed value.
162
170
 
163
171
  A missing settings file is a side-effect-free read: pi-btw creates it only after a Settings change
164
172
  or a remembered shortcut change. Saves are ordered within the Pi process and published atomically
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@narumitw/pi-btw",
3
- "version": "0.50.0",
3
+ "version": "0.52.0",
4
4
  "description": "Pi extension that adds a /btw side-question command.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -31,10 +31,10 @@
31
31
  "typecheck": "tsc --noEmit"
32
32
  },
33
33
  "devDependencies": {
34
- "@biomejs/biome": "2.5.7",
35
- "@earendil-works/pi-ai": "0.84.1",
36
- "@earendil-works/pi-coding-agent": "0.84.1",
37
- "@earendil-works/pi-tui": "0.84.1",
34
+ "@biomejs/biome": "2.5.8",
35
+ "@earendil-works/pi-ai": "0.84.2",
36
+ "@earendil-works/pi-coding-agent": "0.84.2",
37
+ "@earendil-works/pi-tui": "0.84.2",
38
38
  "typescript": "7.0.2"
39
39
  },
40
40
  "repository": {
@@ -43,7 +43,7 @@
43
43
  "directory": "packages/pi-btw"
44
44
  },
45
45
  "dependencies": {
46
- "@narumitw/pi-tui-kit": "^0.49.1"
46
+ "@narumitw/pi-tui-kit": "^0.54.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@earendil-works/pi-ai": "*",
@@ -194,7 +194,7 @@ export async function loadBtwThinkingLevel(
194
194
 
195
195
  options.warn?.(
196
196
  sanitizeSingleLine(
197
- `pi-btw settings ignored: ${settings.reason}; expected optional model "provider/model-id", thinkingLevel "${BTW_THINKING_LEVELS.join('" | "')}", and boolean rememberThinkingLevelChanges. Using current Pi thinking level.`,
197
+ `pi-btw settings ignored: ${settings.reason}; expected optional model "provider/model-id", omitted thinkingLevel for Same as main thread or thinkingLevel "${BTW_THINKING_LEVELS.join('" | "')}", and boolean rememberThinkingLevelChanges. Using current Pi thinking level.`,
198
198
  ),
199
199
  );
200
200
  return currentThinkingLevel;
@@ -265,6 +265,7 @@ export default function btw(pi: ExtensionAPI, dependencies: BtwExtensionDependen
265
265
  }
266
266
 
267
267
  const settings = await loadSettings(ctx);
268
+ const sameAsMainThinkingLevel = settings.thinkingLevel === undefined;
268
269
  const resolution = await resolveModel(settings, ctx);
269
270
  if (resolution.kind === "cancelled") {
270
271
  notifySafely(ctx, "Cancelled", "info");
@@ -302,7 +303,8 @@ export default function btw(pi: ExtensionAPI, dependencies: BtwExtensionDependen
302
303
  initialQuestion: question || undefined,
303
304
  selected: resolution.selected,
304
305
  thinkingLevel: state.thinkingLevel,
305
- rememberThinkingLevelChanges: effectiveRememberThinkingLevelChanges(settings),
306
+ rememberThinkingLevelChanges:
307
+ !sameAsMainThinkingLevel && effectiveRememberThinkingLevelChanges(settings),
306
308
  state,
307
309
  ctx: fullscreenCtx,
308
310
  });
@@ -7,6 +7,7 @@ import type { Component, TUI } from "@earendil-works/pi-tui";
7
7
  import type { MenuContext, RunMenuResult } from "@narumitw/pi-tui-kit";
8
8
  import {
9
9
  type BtwSettings,
10
+ type BtwSettingsPatch,
10
11
  btwSettingsPath,
11
12
  effectiveRememberThinkingLevelChanges,
12
13
  readBtwSettings,
@@ -35,7 +36,7 @@ export interface ShowBtwCommandMenuOptions {
35
36
  settingsPath?: string;
36
37
  readSettings?: typeof readBtwSettings;
37
38
  updateSettings?: (
38
- patch: Partial<Pick<BtwSettings, "thinkingLevel" | "rememberThinkingLevelChanges">>,
39
+ patch: BtwSettingsPatch,
39
40
  options: UpdateBtwSettingsOptions,
40
41
  ) => Promise<BtwSettings>;
41
42
  }
@@ -44,6 +45,7 @@ export type BtwCommandMenuResult = "start" | "closed" | { kind: "resume"; thread
44
45
 
45
46
  type BtwMenuScreen = "main" | "resume" | "settings" | "invalid";
46
47
  type BtwMenuAction = "start" | "resume" | "set-thinking" | "set-remember";
48
+ const SAME_AS_MAIN_THREAD = "Same as main thread";
47
49
  type BtwCustomOptions = Parameters<ExtensionCommandContext["ui"]["custom"]>[1];
48
50
 
49
51
  type BtwCustomFactory<T> = (
@@ -79,8 +81,22 @@ export async function showBtwCommandMenu(
79
81
  }
80
82
  return { kind: "valid", settings: loaded.kind === "loaded" ? loaded.settings : {} };
81
83
  };
82
- const displayThinkingLevel = (settings: BtwSettings): BtwThinkingLevel =>
83
- clampToAvailableThinkingLevel(settings.thinkingLevel ?? options.currentThinkingLevel, levels);
84
+ const currentMainThinkingLevel = clampToAvailableThinkingLevel(
85
+ options.currentThinkingLevel,
86
+ levels,
87
+ );
88
+ const displayThinkingLevel = (settings: BtwSettings): string =>
89
+ settings.thinkingLevel === undefined
90
+ ? SAME_AS_MAIN_THREAD
91
+ : clampToAvailableThinkingLevel(settings.thinkingLevel, levels);
92
+ const displayThinkingSummary = (settings: BtwSettings): string =>
93
+ settings.thinkingLevel === undefined
94
+ ? `${SAME_AS_MAIN_THREAD} (currently ${currentMainThinkingLevel})`
95
+ : displayThinkingLevel(settings);
96
+ const displayRememberSummary = (settings: BtwSettings): string => {
97
+ const value = effectiveRememberThinkingLevelChanges(settings) ? "On" : "Off";
98
+ return settings.thinkingLevel === undefined ? `${value} (fixed levels only)` : value;
99
+ };
84
100
 
85
101
  const menu = defineMenu<BtwMenuState, BtwMenuScreen, BtwMenuAction, MenuContext>({
86
102
  start: "main",
@@ -89,7 +105,7 @@ export async function showBtwCommandMenu(
89
105
  kind: "actions",
90
106
  title: "Pi BTW",
91
107
  lines: [
92
- `Thinking: ${displayThinkingLevel(state.settings)} · Remember changes: ${effectiveRememberThinkingLevelChanges(state.settings) ? "On" : "Off"}`,
108
+ `Thinking: ${displayThinkingSummary(state.settings)} · Remember changes: ${displayRememberSummary(state.settings)}`,
93
109
  ],
94
110
  items: [
95
111
  {
@@ -111,7 +127,7 @@ export async function showBtwCommandMenu(
111
127
  {
112
128
  id: "settings",
113
129
  label: "Settings",
114
- description: "Choose pi-btw thinking and whether shortcut changes are remembered",
130
+ description: "Choose pi-btw thinking level and fixed-level shortcut memory",
115
131
  to: state.kind === "invalid" ? "invalid" : "settings",
116
132
  },
117
133
  ],
@@ -120,6 +136,7 @@ export async function showBtwCommandMenu(
120
136
  resume: () => ({
121
137
  kind: "choice",
122
138
  title: "Resume BTW side thread",
139
+ enableSearch: true,
123
140
  items: resumeThreads.map((thread) => ({
124
141
  id: thread.id,
125
142
  label: thread.title,
@@ -137,15 +154,15 @@ export async function showBtwCommandMenu(
137
154
  {
138
155
  id: "thinkingLevel",
139
156
  label: "Thinking level",
140
- description: "Set the starting level for future pi-btw side threads.",
157
+ description: `Set the starting level for future pi-btw side threads. Currently ${currentMainThinkingLevel}.`,
141
158
  currentValue: displayThinkingLevel(state.settings),
142
- values: levels,
159
+ values: [SAME_AS_MAIN_THREAD, ...levels],
143
160
  action: "set-thinking",
144
161
  },
145
162
  {
146
163
  id: "rememberThinkingLevelChanges",
147
164
  label: "Remember thinking level changes",
148
- description: "Save side-thread shortcut changes to pi-btw.json for next time.",
165
+ description: "Save shortcut changes for fixed thinking levels to pi-btw.json.",
149
166
  currentValue: effectiveRememberThinkingLevelChanges(state.settings) ? "On" : "Off",
150
167
  values: ["On", "Off"],
151
168
  action: "set-remember",
@@ -175,12 +192,16 @@ export async function showBtwCommandMenu(
175
192
  return { kind: "close" } as const;
176
193
  },
177
194
  "set-thinking": async ({ value, signal }) => {
178
- if (!value || !levels.includes(value as BtwThinkingLevel)) return { kind: "rejected" };
195
+ if (!value) return { kind: "rejected" };
196
+ const patch =
197
+ value === SAME_AS_MAIN_THREAD
198
+ ? ({ thinkingLevel: undefined } satisfies BtwSettingsPatch)
199
+ : levels.includes(value as BtwThinkingLevel)
200
+ ? ({ thinkingLevel: value as BtwThinkingLevel } satisfies BtwSettingsPatch)
201
+ : undefined;
202
+ if (!patch) return { kind: "rejected" };
179
203
  try {
180
- await updateSettings(
181
- { thinkingLevel: value as BtwThinkingLevel },
182
- { settingsPath, signal },
183
- );
204
+ await updateSettings(patch, { settingsPath, signal });
184
205
  if (signal.aborted) return { kind: "rejected" };
185
206
  notifySafely(ctx, `Pi BTW thinking level: ${value}.`, "info");
186
207
  return { kind: "stay" };