@herbertgao/pi-extensions 2026.8.1 → 2026.8.3

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 (403) hide show
  1. package/README.md +13 -3
  2. package/node_modules/@czottmann/pi-automode/README.md +16 -2
  3. package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +35 -0
  4. package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +18 -9
  5. package/node_modules/@czottmann/pi-automode/docs/defaults.md +6 -2
  6. package/node_modules/@czottmann/pi-automode/examples/automode.local.json +6 -0
  7. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +11 -7
  8. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +100 -0
  9. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +32 -0
  10. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +78 -3
  11. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +16 -4
  12. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/paths.ts +23 -1
  13. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/permissions.ts +22 -1
  14. package/node_modules/@czottmann/pi-automode/extensions/auto-mode/types.ts +18 -2
  15. package/node_modules/@czottmann/pi-automode/package.json +4 -4
  16. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-audit.md +5 -0
  17. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-debt.md +5 -0
  18. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-gain.md +5 -0
  19. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-help.md +5 -0
  20. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail-review.md +5 -0
  21. package/node_modules/@dietrichgebert/ponytail/.opencode/command/ponytail.md +5 -0
  22. package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail-frontmatter.cjs +23 -0
  23. package/node_modules/@dietrichgebert/ponytail/.opencode/plugins/ponytail.mjs +99 -0
  24. package/node_modules/@dietrichgebert/ponytail/.qoder/rules/ponytail.md +30 -0
  25. package/node_modules/@dietrichgebert/ponytail/.qoder-plugin/plugin.json +16 -0
  26. package/node_modules/@dietrichgebert/ponytail/AGENTS.md +32 -0
  27. package/node_modules/@dietrichgebert/ponytail/LICENSE +21 -0
  28. package/node_modules/@dietrichgebert/ponytail/README.es.md +298 -0
  29. package/node_modules/@dietrichgebert/ponytail/README.ko.md +315 -0
  30. package/node_modules/@dietrichgebert/ponytail/README.md +351 -0
  31. package/node_modules/@dietrichgebert/ponytail/assets/benchmark-3model.svg +21 -0
  32. package/node_modules/@dietrichgebert/ponytail/assets/benchmark-agentic.svg +62 -0
  33. package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.png +0 -0
  34. package/node_modules/@dietrichgebert/ponytail/assets/logo-dark.svg +115 -0
  35. package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt-dark.svg +27 -0
  36. package/node_modules/@dietrichgebert/ponytail/assets/logo-greenpt.svg +27 -0
  37. package/node_modules/@dietrichgebert/ponytail/assets/logo.png +0 -0
  38. package/node_modules/@dietrichgebert/ponytail/assets/social-preview.png +0 -0
  39. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-es.png +0 -0
  40. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner-ko.png +0 -0
  41. package/node_modules/@dietrichgebert/ponytail/assets/waitlist-banner.png +0 -0
  42. package/node_modules/@dietrichgebert/ponytail/hooks/claude-codex-hooks.json +44 -0
  43. package/node_modules/@dietrichgebert/ponytail/hooks/copilot-hooks.json +21 -0
  44. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-activate.js +96 -0
  45. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-config.js +169 -0
  46. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-instructions.js +98 -0
  47. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-mode-tracker.js +130 -0
  48. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-runtime.js +85 -0
  49. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-statusline.ps1 +24 -0
  50. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-statusline.sh +18 -0
  51. package/node_modules/@dietrichgebert/ponytail/hooks/ponytail-subagent.js +77 -0
  52. package/node_modules/@dietrichgebert/ponytail/hooks/qoder-hooks.json +26 -0
  53. package/node_modules/@dietrichgebert/ponytail/package.json +47 -0
  54. package/node_modules/@dietrichgebert/ponytail/pi-extension/index.js +211 -0
  55. package/node_modules/@dietrichgebert/ponytail/pi-extension/package.json +8 -0
  56. package/node_modules/@dietrichgebert/ponytail/scripts/uninstall.js +60 -0
  57. package/node_modules/@dietrichgebert/ponytail/skills/ponytail/SKILL.md +120 -0
  58. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-audit/SKILL.md +41 -0
  59. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-debt/SKILL.md +44 -0
  60. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-gain/SKILL.md +50 -0
  61. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-help/SKILL.md +71 -0
  62. package/node_modules/@dietrichgebert/ponytail/skills/ponytail-review/SKILL.md +57 -0
  63. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +6 -10
  64. package/node_modules/@herbertgao/pi-cc-extensions/README.md +5 -9
  65. package/node_modules/@herbertgao/pi-cc-extensions/assets/readme/hero.en.svg +101 -0
  66. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +1 -17
  67. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +15 -9
  68. package/node_modules/@herbertgao/pi-cc-extensions/extensions/{utils/agent-summary.ts → feature/agent-summary/core.ts} +37 -35
  69. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{agent-summary.ts → agent-summary/index.ts} +3 -3
  70. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +24 -83
  71. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +1 -1
  72. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{session-reference.ts → reference/index.ts} +1 -1
  73. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{agent-autocomplete.ts → reference/subagent.ts} +19 -9
  74. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{pi-startup-header.ts → shell/startup-header.ts} +1 -1
  75. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{working-message.ts → shell/working-message.ts} +5 -2
  76. package/node_modules/@herbertgao/pi-cc-extensions/extensions/index.ts +32 -28
  77. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +452 -94
  78. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/default-mode.ts +727 -0
  79. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/index.ts +66 -776
  80. package/node_modules/@herbertgao/pi-cc-extensions/extensions/{feature → renderer}/markdown-enhance.ts +134 -11
  81. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +130 -0
  82. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{mouse-interaction.ts → mouse/interaction.ts} +90 -568
  83. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +144 -0
  84. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/packets.ts +143 -0
  85. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/scroll.ts +195 -0
  86. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/ansi-utils.ts +56 -1
  87. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/diff-renderer.ts +4 -4
  88. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/line-width-safety.ts +1 -1
  89. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/write-display-utils.ts +12 -0
  90. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/write-execution.ts +1 -2
  91. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-grouping.ts → tool/grouping.ts} +27 -10
  92. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-result.ts → tool/result.ts} +4 -13
  93. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/transcript-refresh.ts +91 -0
  94. package/node_modules/@herbertgao/pi-cc-extensions/extensions/utils/fullscreen-detect.ts +0 -27
  95. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  96. package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-dark.json +1 -0
  97. package/node_modules/@herbertgao/pi-cc-extensions/themes/cc-light.json +2 -2
  98. package/node_modules/@herbertgao/pi-stash/README.md +9 -9
  99. package/node_modules/@herbertgao/pi-stash/package.json +1 -1
  100. package/node_modules/@herbertgao/pi-stash/src/index.ts +2 -1
  101. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +20 -0
  102. package/node_modules/@herbertgao/pi-subagents/README.md +6 -2
  103. package/node_modules/@herbertgao/pi-subagents/package.json +3 -3
  104. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +1 -0
  105. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +3 -1
  106. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +85 -11
  107. package/node_modules/@herbertgao/pi-subagents/src/index.ts +61 -39
  108. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +26 -35
  109. package/node_modules/@herbertgao/pi-subagents/src/prompts.ts +15 -1
  110. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +12 -0
  111. package/node_modules/@herbertgao/pi-subagents/src/types.ts +2 -0
  112. package/node_modules/@narumitw/pi-btw/LICENSE +21 -0
  113. package/node_modules/@narumitw/pi-btw/README.md +210 -0
  114. package/node_modules/@narumitw/pi-btw/package.json +53 -0
  115. package/node_modules/@narumitw/pi-btw/src/bring-to-main.ts +632 -0
  116. package/node_modules/@narumitw/pi-btw/src/btw.ts +996 -0
  117. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +339 -0
  118. package/node_modules/@narumitw/pi-btw/src/index.ts +1 -0
  119. package/node_modules/@narumitw/pi-btw/src/menu.ts +296 -0
  120. package/node_modules/@narumitw/pi-btw/src/settings.ts +237 -0
  121. package/node_modules/@narumitw/pi-btw/src/side-thread.ts +238 -0
  122. package/node_modules/@narumitw/pi-btw/src/text.ts +10 -0
  123. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +620 -0
  124. package/node_modules/@pi-plugins/fast-mode/LICENSE +21 -0
  125. package/node_modules/@pi-plugins/fast-mode/README.md +92 -0
  126. package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts +6 -0
  127. package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -0
  128. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +2026 -0
  129. package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -0
  130. package/node_modules/@pi-plugins/fast-mode/package.json +73 -0
  131. package/node_modules/pi-mcp-adapter/CHANGELOG.md +78 -0
  132. package/node_modules/pi-mcp-adapter/README.md +80 -16
  133. package/node_modules/pi-mcp-adapter/agent-dir.ts +40 -0
  134. package/node_modules/pi-mcp-adapter/agent-plugin-loader.ts +377 -0
  135. package/node_modules/pi-mcp-adapter/commands.ts +21 -9
  136. package/node_modules/pi-mcp-adapter/config.ts +110 -49
  137. package/node_modules/pi-mcp-adapter/direct-tools.ts +40 -27
  138. package/node_modules/pi-mcp-adapter/elicitation-handler.ts +37 -36
  139. package/node_modules/pi-mcp-adapter/errors.ts +21 -17
  140. package/node_modules/pi-mcp-adapter/host-html-template.ts +13 -7
  141. package/node_modules/pi-mcp-adapter/index.ts +52 -17
  142. package/node_modules/pi-mcp-adapter/init.ts +9 -7
  143. package/node_modules/pi-mcp-adapter/json-schema-validator.ts +2 -2
  144. package/node_modules/pi-mcp-adapter/lifecycle.ts +8 -8
  145. package/node_modules/pi-mcp-adapter/logger.ts +1 -1
  146. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +122 -25
  147. package/node_modules/pi-mcp-adapter/mcp-auth.ts +120 -2
  148. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +138 -61
  149. package/node_modules/pi-mcp-adapter/mcp-code.ts +13 -11
  150. package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +62 -17
  151. package/node_modules/pi-mcp-adapter/mcp-output-guard.ts +15 -11
  152. package/node_modules/pi-mcp-adapter/mcp-panel.ts +34 -15
  153. package/node_modules/pi-mcp-adapter/mcp-probe.ts +131 -34
  154. package/node_modules/pi-mcp-adapter/mcp-script-worker.mjs +2 -2
  155. package/node_modules/pi-mcp-adapter/mcp-setup-panel.ts +7 -4
  156. package/node_modules/pi-mcp-adapter/mcp-trace.ts +59 -64
  157. package/node_modules/pi-mcp-adapter/metadata-cache.ts +34 -26
  158. package/node_modules/pi-mcp-adapter/npx-resolver.ts +6 -4
  159. package/node_modules/pi-mcp-adapter/oauth-handler.ts +1 -1
  160. package/node_modules/pi-mcp-adapter/oauth.ts +48 -0
  161. package/node_modules/pi-mcp-adapter/onboarding-state.ts +19 -11
  162. package/node_modules/pi-mcp-adapter/package.json +20 -9
  163. package/node_modules/pi-mcp-adapter/panel-keys.ts +20 -4
  164. package/node_modules/pi-mcp-adapter/prompts.ts +2 -2
  165. package/node_modules/pi-mcp-adapter/proxy-modes.ts +56 -21
  166. package/node_modules/pi-mcp-adapter/sampling-handler.ts +22 -15
  167. package/node_modules/pi-mcp-adapter/search-ranking.ts +2 -1
  168. package/node_modules/pi-mcp-adapter/server-manager.ts +165 -113
  169. package/node_modules/pi-mcp-adapter/session-recovery.ts +11 -12
  170. package/node_modules/pi-mcp-adapter/skills/mcp-scripting/SKILL.md +3 -3
  171. package/node_modules/pi-mcp-adapter/state.ts +3 -1
  172. package/node_modules/pi-mcp-adapter/tool-approval.ts +67 -4
  173. package/node_modules/pi-mcp-adapter/tool-metadata.ts +6 -5
  174. package/node_modules/pi-mcp-adapter/tool-registrar.ts +187 -3
  175. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +14 -2
  176. package/node_modules/pi-mcp-adapter/ts-shape.ts +9 -2
  177. package/node_modules/pi-mcp-adapter/types.ts +111 -22
  178. package/node_modules/pi-mcp-adapter/ui-app-bridge-helpers.ts +40 -0
  179. package/node_modules/pi-mcp-adapter/ui-resource-handler.ts +28 -19
  180. package/node_modules/pi-mcp-adapter/ui-server.ts +90 -58
  181. package/node_modules/pi-mcp-adapter/ui-session.ts +16 -14
  182. package/node_modules/pi-mcp-adapter/unix-socket-transport.ts +4 -4
  183. package/node_modules/pi-mcp-adapter/utils.ts +23 -9
  184. package/node_modules/pi-web-access/CHANGELOG.md +45 -0
  185. package/node_modules/pi-web-access/README.md +104 -29
  186. package/node_modules/pi-web-access/bocha.ts +221 -0
  187. package/node_modules/pi-web-access/curator-page.ts +113 -12
  188. package/node_modules/pi-web-access/curator-server.ts +56 -20
  189. package/node_modules/pi-web-access/datalab-pdf-extract.ts +568 -0
  190. package/node_modules/pi-web-access/duckduckgo.ts +123 -0
  191. package/node_modules/pi-web-access/extract.ts +288 -143
  192. package/node_modules/pi-web-access/feature-config.ts +29 -0
  193. package/node_modules/pi-web-access/gemini-api.ts +4 -0
  194. package/node_modules/pi-web-access/gemini-search.ts +45 -12
  195. package/node_modules/pi-web-access/gemini-web.ts +68 -3
  196. package/node_modules/pi-web-access/index.ts +160 -71
  197. package/node_modules/pi-web-access/jina-search.ts +284 -0
  198. package/node_modules/pi-web-access/kagi.ts +12 -12
  199. package/node_modules/pi-web-access/openai-search.ts +12 -2
  200. package/node_modules/pi-web-access/package.json +4 -3
  201. package/node_modules/pi-web-access/pdf-extract.ts +327 -228
  202. package/node_modules/pi-web-access/storage.ts +440 -2
  203. package/node_modules/pi-web-access/summary-model-scope.ts +1 -1
  204. package/node_modules/pi-web-access/summary-review.ts +4 -2
  205. package/node_modules/pi-web-access/video-extract.ts +10 -8
  206. package/node_modules/pi-web-access/xai-search.ts +12 -2
  207. package/node_modules/pi-web-access/youtube-extract.ts +2 -1
  208. package/node_modules/remote-pi/LICENSE +21 -0
  209. package/node_modules/remote-pi/README.md +675 -0
  210. package/node_modules/remote-pi/dist/actions/handlers.d.ts +122 -0
  211. package/node_modules/remote-pi/dist/actions/handlers.js +160 -0
  212. package/node_modules/remote-pi/dist/actions/handlers.js.map +1 -0
  213. package/node_modules/remote-pi/dist/actions/registry.d.ts +39 -0
  214. package/node_modules/remote-pi/dist/actions/registry.js +58 -0
  215. package/node_modules/remote-pi/dist/actions/registry.js.map +1 -0
  216. package/node_modules/remote-pi/dist/bin/supervisord.d.ts +2 -0
  217. package/node_modules/remote-pi/dist/bin/supervisord.js +86 -0
  218. package/node_modules/remote-pi/dist/bin/supervisord.js.map +1 -0
  219. package/node_modules/remote-pi/dist/commands/builtin_mirror.d.ts +58 -0
  220. package/node_modules/remote-pi/dist/commands/builtin_mirror.js +71 -0
  221. package/node_modules/remote-pi/dist/commands/builtin_mirror.js.map +1 -0
  222. package/node_modules/remote-pi/dist/commands/list_commands.d.ts +60 -0
  223. package/node_modules/remote-pi/dist/commands/list_commands.js +73 -0
  224. package/node_modules/remote-pi/dist/commands/list_commands.js.map +1 -0
  225. package/node_modules/remote-pi/dist/config.d.ts +62 -0
  226. package/node_modules/remote-pi/dist/config.js +115 -0
  227. package/node_modules/remote-pi/dist/config.js.map +1 -0
  228. package/node_modules/remote-pi/dist/daemon/client.d.ts +20 -0
  229. package/node_modules/remote-pi/dist/daemon/client.js +131 -0
  230. package/node_modules/remote-pi/dist/daemon/client.js.map +1 -0
  231. package/node_modules/remote-pi/dist/daemon/control_protocol.d.ts +176 -0
  232. package/node_modules/remote-pi/dist/daemon/control_protocol.js +63 -0
  233. package/node_modules/remote-pi/dist/daemon/control_protocol.js.map +1 -0
  234. package/node_modules/remote-pi/dist/daemon/cron_log.d.ts +45 -0
  235. package/node_modules/remote-pi/dist/daemon/cron_log.js +72 -0
  236. package/node_modules/remote-pi/dist/daemon/cron_log.js.map +1 -0
  237. package/node_modules/remote-pi/dist/daemon/cron_registry.d.ts +80 -0
  238. package/node_modules/remote-pi/dist/daemon/cron_registry.js +194 -0
  239. package/node_modules/remote-pi/dist/daemon/cron_registry.js.map +1 -0
  240. package/node_modules/remote-pi/dist/daemon/id.d.ts +24 -0
  241. package/node_modules/remote-pi/dist/daemon/id.js +36 -0
  242. package/node_modules/remote-pi/dist/daemon/id.js.map +1 -0
  243. package/node_modules/remote-pi/dist/daemon/install.d.ts +170 -0
  244. package/node_modules/remote-pi/dist/daemon/install.js +547 -0
  245. package/node_modules/remote-pi/dist/daemon/install.js.map +1 -0
  246. package/node_modules/remote-pi/dist/daemon/registry.d.ts +63 -0
  247. package/node_modules/remote-pi/dist/daemon/registry.js +153 -0
  248. package/node_modules/remote-pi/dist/daemon/registry.js.map +1 -0
  249. package/node_modules/remote-pi/dist/daemon/rpc_child.d.ts +194 -0
  250. package/node_modules/remote-pi/dist/daemon/rpc_child.js +389 -0
  251. package/node_modules/remote-pi/dist/daemon/rpc_child.js.map +1 -0
  252. package/node_modules/remote-pi/dist/daemon/supervisor.d.ts +93 -0
  253. package/node_modules/remote-pi/dist/daemon/supervisor.js +596 -0
  254. package/node_modules/remote-pi/dist/daemon/supervisor.js.map +1 -0
  255. package/node_modules/remote-pi/dist/extension_ui_bridge.d.ts +26 -0
  256. package/node_modules/remote-pi/dist/extension_ui_bridge.js +341 -0
  257. package/node_modules/remote-pi/dist/extension_ui_bridge.js.map +1 -0
  258. package/node_modules/remote-pi/dist/index.d.ts +213 -0
  259. package/node_modules/remote-pi/dist/index.js +4996 -0
  260. package/node_modules/remote-pi/dist/index.js.map +1 -0
  261. package/node_modules/remote-pi/dist/mcp/mesh_result.d.ts +10 -0
  262. package/node_modules/remote-pi/dist/mcp/mesh_result.js +42 -0
  263. package/node_modules/remote-pi/dist/mcp/mesh_result.js.map +1 -0
  264. package/node_modules/remote-pi/dist/mcp/mesh_server.d.ts +16 -0
  265. package/node_modules/remote-pi/dist/mcp/mesh_server.js +327 -0
  266. package/node_modules/remote-pi/dist/mcp/mesh_server.js.map +1 -0
  267. package/node_modules/remote-pi/dist/mesh/canonical.d.ts +30 -0
  268. package/node_modules/remote-pi/dist/mesh/canonical.js +61 -0
  269. package/node_modules/remote-pi/dist/mesh/canonical.js.map +1 -0
  270. package/node_modules/remote-pi/dist/mesh/client.d.ts +18 -0
  271. package/node_modules/remote-pi/dist/mesh/client.js +125 -0
  272. package/node_modules/remote-pi/dist/mesh/client.js.map +1 -0
  273. package/node_modules/remote-pi/dist/mesh/encoding.d.ts +38 -0
  274. package/node_modules/remote-pi/dist/mesh/encoding.js +216 -0
  275. package/node_modules/remote-pi/dist/mesh/encoding.js.map +1 -0
  276. package/node_modules/remote-pi/dist/mesh/self_revoke.d.ts +73 -0
  277. package/node_modules/remote-pi/dist/mesh/self_revoke.js +401 -0
  278. package/node_modules/remote-pi/dist/mesh/self_revoke.js.map +1 -0
  279. package/node_modules/remote-pi/dist/mesh/siblings.d.ts +49 -0
  280. package/node_modules/remote-pi/dist/mesh/siblings.js +159 -0
  281. package/node_modules/remote-pi/dist/mesh/siblings.js.map +1 -0
  282. package/node_modules/remote-pi/dist/mesh/types.d.ts +34 -0
  283. package/node_modules/remote-pi/dist/mesh/types.js +11 -0
  284. package/node_modules/remote-pi/dist/mesh/types.js.map +1 -0
  285. package/node_modules/remote-pi/dist/mesh/verify.d.ts +17 -0
  286. package/node_modules/remote-pi/dist/mesh/verify.js +86 -0
  287. package/node_modules/remote-pi/dist/mesh/verify.js.map +1 -0
  288. package/node_modules/remote-pi/dist/pairing/crypto.d.ts +8 -0
  289. package/node_modules/remote-pi/dist/pairing/crypto.js +22 -0
  290. package/node_modules/remote-pi/dist/pairing/crypto.js.map +1 -0
  291. package/node_modules/remote-pi/dist/pairing/handshake.d.ts +28 -0
  292. package/node_modules/remote-pi/dist/pairing/handshake.js +113 -0
  293. package/node_modules/remote-pi/dist/pairing/handshake.js.map +1 -0
  294. package/node_modules/remote-pi/dist/pairing/noise-sha256.d.ts +16 -0
  295. package/node_modules/remote-pi/dist/pairing/noise-sha256.js +103 -0
  296. package/node_modules/remote-pi/dist/pairing/noise-sha256.js.map +1 -0
  297. package/node_modules/remote-pi/dist/pairing/qr.d.ts +59 -0
  298. package/node_modules/remote-pi/dist/pairing/qr.js +125 -0
  299. package/node_modules/remote-pi/dist/pairing/qr.js.map +1 -0
  300. package/node_modules/remote-pi/dist/pairing/storage.d.ts +120 -0
  301. package/node_modules/remote-pi/dist/pairing/storage.js +604 -0
  302. package/node_modules/remote-pi/dist/pairing/storage.js.map +1 -0
  303. package/node_modules/remote-pi/dist/protocol/codec.d.ts +7 -0
  304. package/node_modules/remote-pi/dist/protocol/codec.js +49 -0
  305. package/node_modules/remote-pi/dist/protocol/codec.js.map +1 -0
  306. package/node_modules/remote-pi/dist/protocol/types.d.ts +393 -0
  307. package/node_modules/remote-pi/dist/protocol/types.js +2 -0
  308. package/node_modules/remote-pi/dist/protocol/types.js.map +1 -0
  309. package/node_modules/remote-pi/dist/rooms.d.ts +29 -0
  310. package/node_modules/remote-pi/dist/rooms.js +57 -0
  311. package/node_modules/remote-pi/dist/rooms.js.map +1 -0
  312. package/node_modules/remote-pi/dist/session/address.d.ts +49 -0
  313. package/node_modules/remote-pi/dist/session/address.js +58 -0
  314. package/node_modules/remote-pi/dist/session/address.js.map +1 -0
  315. package/node_modules/remote-pi/dist/session/agent_bridge.d.ts +55 -0
  316. package/node_modules/remote-pi/dist/session/agent_bridge.js +146 -0
  317. package/node_modules/remote-pi/dist/session/agent_bridge.js.map +1 -0
  318. package/node_modules/remote-pi/dist/session/bridge.d.ts +37 -0
  319. package/node_modules/remote-pi/dist/session/bridge.js +130 -0
  320. package/node_modules/remote-pi/dist/session/bridge.js.map +1 -0
  321. package/node_modules/remote-pi/dist/session/broker.d.ts +189 -0
  322. package/node_modules/remote-pi/dist/session/broker.js +507 -0
  323. package/node_modules/remote-pi/dist/session/broker.js.map +1 -0
  324. package/node_modules/remote-pi/dist/session/broker_remote.d.ts +74 -0
  325. package/node_modules/remote-pi/dist/session/broker_remote.js +583 -0
  326. package/node_modules/remote-pi/dist/session/broker_remote.js.map +1 -0
  327. package/node_modules/remote-pi/dist/session/cwd_lock.d.ts +33 -0
  328. package/node_modules/remote-pi/dist/session/cwd_lock.js +126 -0
  329. package/node_modules/remote-pi/dist/session/cwd_lock.js.map +1 -0
  330. package/node_modules/remote-pi/dist/session/envelope.d.ts +33 -0
  331. package/node_modules/remote-pi/dist/session/envelope.js +117 -0
  332. package/node_modules/remote-pi/dist/session/envelope.js.map +1 -0
  333. package/node_modules/remote-pi/dist/session/global_config.d.ts +33 -0
  334. package/node_modules/remote-pi/dist/session/global_config.js +73 -0
  335. package/node_modules/remote-pi/dist/session/global_config.js.map +1 -0
  336. package/node_modules/remote-pi/dist/session/ipc.d.ts +27 -0
  337. package/node_modules/remote-pi/dist/session/ipc.js +22 -0
  338. package/node_modules/remote-pi/dist/session/ipc.js.map +1 -0
  339. package/node_modules/remote-pi/dist/session/leader_election.d.ts +32 -0
  340. package/node_modules/remote-pi/dist/session/leader_election.js +106 -0
  341. package/node_modules/remote-pi/dist/session/leader_election.js.map +1 -0
  342. package/node_modules/remote-pi/dist/session/local_config.d.ts +55 -0
  343. package/node_modules/remote-pi/dist/session/local_config.js +157 -0
  344. package/node_modules/remote-pi/dist/session/local_config.js.map +1 -0
  345. package/node_modules/remote-pi/dist/session/mesh_message.d.ts +20 -0
  346. package/node_modules/remote-pi/dist/session/mesh_message.js +28 -0
  347. package/node_modules/remote-pi/dist/session/mesh_message.js.map +1 -0
  348. package/node_modules/remote-pi/dist/session/mesh_node.d.ts +116 -0
  349. package/node_modules/remote-pi/dist/session/mesh_node.js +573 -0
  350. package/node_modules/remote-pi/dist/session/mesh_node.js.map +1 -0
  351. package/node_modules/remote-pi/dist/session/peer.d.ts +139 -0
  352. package/node_modules/remote-pi/dist/session/peer.js +451 -0
  353. package/node_modules/remote-pi/dist/session/peer.js.map +1 -0
  354. package/node_modules/remote-pi/dist/session/peer_inventory.d.ts +13 -0
  355. package/node_modules/remote-pi/dist/session/peer_inventory.js +48 -0
  356. package/node_modules/remote-pi/dist/session/peer_inventory.js.map +1 -0
  357. package/node_modules/remote-pi/dist/session/peer_limits.d.ts +9 -0
  358. package/node_modules/remote-pi/dist/session/peer_limits.js +21 -0
  359. package/node_modules/remote-pi/dist/session/peer_limits.js.map +1 -0
  360. package/node_modules/remote-pi/dist/session/setup_wizard.d.ts +39 -0
  361. package/node_modules/remote-pi/dist/session/setup_wizard.js +63 -0
  362. package/node_modules/remote-pi/dist/session/setup_wizard.js.map +1 -0
  363. package/node_modules/remote-pi/dist/session/tool_gate.d.ts +5 -0
  364. package/node_modules/remote-pi/dist/session/tool_gate.js +11 -0
  365. package/node_modules/remote-pi/dist/session/tool_gate.js.map +1 -0
  366. package/node_modules/remote-pi/dist/session/tools.d.ts +24 -0
  367. package/node_modules/remote-pi/dist/session/tools.js +252 -0
  368. package/node_modules/remote-pi/dist/session/tools.js.map +1 -0
  369. package/node_modules/remote-pi/dist/session/wizard.d.ts +13 -0
  370. package/node_modules/remote-pi/dist/session/wizard.js +20 -0
  371. package/node_modules/remote-pi/dist/session/wizard.js.map +1 -0
  372. package/node_modules/remote-pi/dist/settings.d.ts +15 -0
  373. package/node_modules/remote-pi/dist/settings.js +52 -0
  374. package/node_modules/remote-pi/dist/settings.js.map +1 -0
  375. package/node_modules/remote-pi/dist/transport/peer_channel.d.ts +37 -0
  376. package/node_modules/remote-pi/dist/transport/peer_channel.js +98 -0
  377. package/node_modules/remote-pi/dist/transport/peer_channel.js.map +1 -0
  378. package/node_modules/remote-pi/dist/transport/pi_forward_client.d.ts +29 -0
  379. package/node_modules/remote-pi/dist/transport/pi_forward_client.js +62 -0
  380. package/node_modules/remote-pi/dist/transport/pi_forward_client.js.map +1 -0
  381. package/node_modules/remote-pi/dist/transport/relay_client.d.ts +91 -0
  382. package/node_modules/remote-pi/dist/transport/relay_client.js +206 -0
  383. package/node_modules/remote-pi/dist/transport/relay_client.js.map +1 -0
  384. package/node_modules/remote-pi/dist/ui/footer.d.ts +32 -0
  385. package/node_modules/remote-pi/dist/ui/footer.js +34 -0
  386. package/node_modules/remote-pi/dist/ui/footer.js.map +1 -0
  387. package/node_modules/remote-pi/docs/daemon.md +289 -0
  388. package/node_modules/remote-pi/package.json +88 -0
  389. package/node_modules/remote-pi/service-templates/launchd.plist.template +35 -0
  390. package/node_modules/remote-pi/service-templates/systemd.service.template +19 -0
  391. package/node_modules/remote-pi/service-templates/task-launcher.vbs.template +10 -0
  392. package/node_modules/remote-pi/service-templates/task-scheduler.xml.template +38 -0
  393. package/node_modules/remote-pi/skills/agent-network/SKILL.md +310 -0
  394. package/package.json +37 -12
  395. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool-diff/write-display-utils.ts +0 -29
  396. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{session-reference-core.ts → reference/session.ts} +0 -0
  397. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/{pi-aliases.ts → shell/aliases.ts} +0 -0
  398. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/ATTRIBUTION.md +0 -0
  399. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/diff-presentation.ts +0 -0
  400. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/index.ts +0 -0
  401. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/render-utils.ts +0 -0
  402. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/shiki-highlight.ts +0 -0
  403. /package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/{tool-diff → tool/diff}/types.ts +0 -0
@@ -0,0 +1,632 @@
1
+ import type { KeybindingsManager, Theme } from "@earendil-works/pi-coding-agent";
2
+ import {
3
+ type Component,
4
+ Key,
5
+ matchesKey,
6
+ type TUI,
7
+ truncateToWidth,
8
+ visibleWidth,
9
+ } from "@earendil-works/pi-tui";
10
+ import type { SideThreadTurn } from "./side-thread.js";
11
+
12
+ const RESERVED_APP_ROWS = 3;
13
+ const GRAPHEME_SEGMENTER = new Intl.Segmenter(undefined, { granularity: "grapheme" });
14
+
15
+ export interface BtwBringToMainSegment {
16
+ role: "user" | "assistant";
17
+ text: string;
18
+ }
19
+
20
+ export interface BtwBringToMainSummary {
21
+ lines: number;
22
+ messages: number;
23
+ tokens: number;
24
+ }
25
+
26
+ export interface BtwSelectionLine {
27
+ role: BtwBringToMainSegment["role"];
28
+ text: string;
29
+ }
30
+
31
+ export interface BtwTextPosition {
32
+ line: number;
33
+ column: number;
34
+ }
35
+
36
+ export interface BtwTextRangeSelectorState {
37
+ cursor: BtwTextPosition;
38
+ anchor?: BtwTextPosition;
39
+ lineAnchor?: number;
40
+ preferredColumn: number;
41
+ scrollOffset: number;
42
+ horizontalOffset: number;
43
+ }
44
+
45
+ export type BtwQuickBringToMainScope =
46
+ | { kind: "latest" }
47
+ | { kind: "from"; answeredTurnIndex: number }
48
+ | { kind: "entire" };
49
+
50
+ export type BtwTextRangeSelectorAction =
51
+ | { kind: "confirm"; segments: BtwBringToMainSegment[] }
52
+ | { kind: "back" }
53
+ | { kind: "close" };
54
+
55
+ export function getAnsweredTurns(
56
+ turns: readonly SideThreadTurn[],
57
+ ): Array<Extract<SideThreadTurn, { kind: "answered" }>> {
58
+ return turns.filter(
59
+ (turn): turn is Extract<SideThreadTurn, { kind: "answered" }> => turn.kind === "answered",
60
+ );
61
+ }
62
+
63
+ export function buildQuickBringToMainSegments(
64
+ turns: readonly SideThreadTurn[],
65
+ scope: BtwQuickBringToMainScope,
66
+ ): BtwBringToMainSegment[] {
67
+ const answered = getAnsweredTurns(turns);
68
+ const selected =
69
+ scope.kind === "latest"
70
+ ? answered.slice(-1)
71
+ : scope.kind === "from"
72
+ ? answered.slice(Math.max(0, scope.answeredTurnIndex))
73
+ : answered;
74
+ return selected.flatMap((turn) => [
75
+ { role: "user" as const, text: turn.question },
76
+ { role: "assistant" as const, text: turn.answer },
77
+ ]);
78
+ }
79
+
80
+ export function buildBtwSelectionLines(turns: readonly SideThreadTurn[]): BtwSelectionLine[] {
81
+ return buildQuickBringToMainSegments(turns, { kind: "entire" }).flatMap((segment) =>
82
+ segment.text.split("\n").map((text) => ({ role: segment.role, text })),
83
+ );
84
+ }
85
+
86
+ export function segmentsFromLineRange(
87
+ lines: readonly BtwSelectionLine[],
88
+ anchor: number,
89
+ cursor: number,
90
+ ): BtwBringToMainSegment[] {
91
+ if (lines.length === 0) return [];
92
+ const start = Math.max(0, Math.min(anchor, cursor, lines.length - 1));
93
+ const end = Math.max(0, Math.min(Math.max(anchor, cursor), lines.length - 1));
94
+ const segments: BtwBringToMainSegment[] = [];
95
+ for (const line of lines.slice(start, end + 1)) {
96
+ const previous = segments.at(-1);
97
+ if (previous?.role === line.role) {
98
+ previous.text += `\n${line.text}`;
99
+ } else {
100
+ segments.push({ role: line.role, text: line.text });
101
+ }
102
+ }
103
+ return segments;
104
+ }
105
+
106
+ export function segmentsFromTextRange(
107
+ lines: readonly BtwSelectionLine[],
108
+ anchor: BtwTextPosition,
109
+ cursor: BtwTextPosition,
110
+ ): BtwBringToMainSegment[] {
111
+ if (lines.length === 0) return [];
112
+ const first = clampTextPosition(lines, anchor);
113
+ const second = clampTextPosition(lines, cursor);
114
+ const [start, end] = compareTextPositions(first, second) <= 0 ? [first, second] : [second, first];
115
+ if (compareTextPositions(start, end) === 0) return [];
116
+
117
+ const segments: BtwBringToMainSegment[] = [];
118
+ for (let lineIndex = start.line; lineIndex <= end.line; lineIndex += 1) {
119
+ const line = lines[lineIndex];
120
+ if (!line) continue;
121
+ const characters = splitGraphemes(line.text);
122
+ const from = lineIndex === start.line ? start.column : 0;
123
+ const to = lineIndex === end.line ? end.column : characters.length;
124
+ const text = characters.slice(from, to).join("");
125
+ if (text) {
126
+ const previous = segments.at(-1);
127
+ if (previous?.role === line.role) previous.text += text;
128
+ else segments.push({ role: line.role, text });
129
+ }
130
+ const crossesSameRoleLine = lineIndex < end.line && lines[lineIndex + 1]?.role === line.role;
131
+ if (crossesSameRoleLine) {
132
+ const current = segments.at(-1);
133
+ if (current?.role === line.role) current.text += "\n";
134
+ else segments.push({ role: line.role, text: "\n" });
135
+ }
136
+ }
137
+ return segments;
138
+ }
139
+
140
+ export function estimateBringToMainTokens(segments: readonly BtwBringToMainSegment[]): number {
141
+ return Math.ceil(
142
+ Buffer.byteLength(segments.map((segment) => segment.text).join("\n"), "utf8") / 4,
143
+ );
144
+ }
145
+
146
+ export function summarizeBringToMain(
147
+ segments: readonly BtwBringToMainSegment[],
148
+ ): BtwBringToMainSummary {
149
+ return {
150
+ lines: segments.reduce((count, segment) => count + segment.text.split("\n").length, 0),
151
+ messages: segments.length,
152
+ tokens: estimateBringToMainTokens(segments),
153
+ };
154
+ }
155
+
156
+ export function formatBtwBringToMain(segments: readonly BtwBringToMainSegment[]): string {
157
+ const body = segments
158
+ .map(
159
+ (segment) =>
160
+ `${segment.role === "user" ? "User" : "Assistant"}:\n${escapeBringToMainText(segment.text)}`,
161
+ )
162
+ .join("\n\n");
163
+ return [
164
+ "The following context was brought back from a /btw side discussion.",
165
+ "Treat it as discussion context, not as work already completed.",
166
+ "",
167
+ "<btw_context>",
168
+ body,
169
+ "</btw_context>",
170
+ ].join("\n");
171
+ }
172
+
173
+ export class BtwTextRangeSelector implements Component {
174
+ private readonly lines: BtwSelectionLine[];
175
+ private cursor: BtwTextPosition = { line: 0, column: 0 };
176
+ private anchor: BtwTextPosition | undefined;
177
+ private lineAnchor: number | undefined;
178
+ private preferredColumn = 0;
179
+ private scrollOffset = 0;
180
+ private horizontalOffset = 0;
181
+ private warning: string | undefined;
182
+ private finished = false;
183
+
184
+ constructor(
185
+ private readonly tui: TUI,
186
+ private readonly theme: Theme,
187
+ private readonly keybindings: KeybindingsManager,
188
+ turns: readonly SideThreadTurn[],
189
+ private readonly onAction: (action: BtwTextRangeSelectorAction) => void,
190
+ initialState?: BtwTextRangeSelectorState,
191
+ ) {
192
+ this.lines = buildBtwSelectionLines(turns);
193
+ if (initialState) {
194
+ this.cursor = clampTextPosition(this.lines, initialState.cursor);
195
+ this.anchor = initialState.anchor
196
+ ? clampTextPosition(this.lines, initialState.anchor)
197
+ : undefined;
198
+ this.lineAnchor =
199
+ initialState.lineAnchor === undefined
200
+ ? undefined
201
+ : Math.max(0, Math.min(this.lines.length - 1, initialState.lineAnchor));
202
+ this.preferredColumn = Math.max(0, initialState.preferredColumn);
203
+ this.scrollOffset = Math.max(0, initialState.scrollOffset);
204
+ this.horizontalOffset = Math.max(0, initialState.horizontalOffset);
205
+ }
206
+ }
207
+
208
+ getState(): BtwTextRangeSelectorState {
209
+ return {
210
+ cursor: { ...this.cursor },
211
+ anchor: this.anchor ? { ...this.anchor } : undefined,
212
+ lineAnchor: this.lineAnchor,
213
+ preferredColumn: this.preferredColumn,
214
+ scrollOffset: this.scrollOffset,
215
+ horizontalOffset: this.horizontalOffset,
216
+ };
217
+ }
218
+
219
+ render(width: number): string[] {
220
+ const safeWidth = Math.max(1, width);
221
+ const availableRows = Math.max(1, this.tui.terminal.rows - RESERVED_APP_ROWS);
222
+ const showStatus = availableRows >= 4;
223
+ const showFooter = availableRows >= 3;
224
+ const viewportHeight = Math.max(
225
+ 1,
226
+ availableRows - 1 - (showStatus ? 1 : 0) - (showFooter ? 1 : 0),
227
+ );
228
+ this.keepCursorVisible(viewportHeight);
229
+ const textWidth = Math.max(1, safeWidth - visibleWidth("●> Assistant │ "));
230
+ this.keepCursorHorizontallyVisible(textWidth);
231
+ const range = this.getSelectionRange();
232
+ const lineRange = this.getLineSelectionRange();
233
+ const visible = this.lines.slice(this.scrollOffset, this.scrollOffset + viewportHeight);
234
+ const rows = visible.map((line, visibleIndex) => {
235
+ const lineIndex = this.scrollOffset + visibleIndex;
236
+ const role = line.role === "user" ? "User" : "Assistant";
237
+ const lineSelected = lineRange
238
+ ? lineIndex >= lineRange.start && lineIndex <= lineRange.end
239
+ : false;
240
+ const prefix = `${lineSelected ? "●" : " "}${lineIndex === this.cursor.line ? ">" : " "} ${role.padEnd(9)} │ `;
241
+ const text = this.renderTextLine(line, lineIndex, range, lineSelected);
242
+ return truncateToWidth(
243
+ lineIndex === this.cursor.line ? this.theme.fg("accent", prefix) + text : prefix + text,
244
+ safeWidth,
245
+ "",
246
+ );
247
+ });
248
+ const selected = this.getSelectedSegments();
249
+ const summary = summarizeBringToMain(selected);
250
+ const status =
251
+ selected.length === 0
252
+ ? "Selected: none"
253
+ : `Selected: ${summary.lines} ${summary.lines === 1 ? "line" : "lines"} · ${summary.messages} ${summary.messages === 1 ? "message" : "messages"} · ~${summary.tokens} ${summary.tokens === 1 ? "token" : "tokens"}`;
254
+ const confirm = confirmKeyLabel(this.keybindings);
255
+ const back = keybindingLabel(this.keybindings, "tui.select.cancel", ["ctrl+c"]);
256
+ const vertical = `${keybindingLabel(this.keybindings, "tui.select.up")}/${keybindingLabel(this.keybindings, "tui.select.down")}`;
257
+ const confirmUsesSpace = this.keybindings.matches(" ", "tui.select.confirm");
258
+ const detailedFooter = this.warning
259
+ ? `${this.warning} • ${confirmUsesSpace ? "Shift+Arrows select" : "Space lines • Shift+Arrows text"} • ${back} back • Ctrl+C close`
260
+ : this.lineAnchor !== undefined
261
+ ? `${confirmUsesSpace ? `${vertical} extend lines` : `Space clear • ${vertical} extend lines`} • Shift+Arrows text • ${confirm} bring • ${back} back • Ctrl+C close`
262
+ : `Shift+Arrows select • Arrows move${confirmUsesSpace ? "" : " • Space lines"} • ${confirm} bring • ${back} back • Ctrl+C close`;
263
+ const criticalFooter = `${confirm} bring • ${back} back • Ctrl+C close`;
264
+ const footer = visibleWidth(detailedFooter) <= safeWidth ? detailedFooter : criticalFooter;
265
+ return fitRows(
266
+ [
267
+ truncateToWidth(
268
+ this.theme.fg("accent", this.theme.bold("Select text to bring to main")),
269
+ safeWidth,
270
+ "",
271
+ ),
272
+ ...(showStatus ? [truncateToWidth(this.theme.fg("muted", status), safeWidth, "")] : []),
273
+ ...rows,
274
+ ...(showFooter
275
+ ? [
276
+ truncateToWidth(
277
+ this.theme.fg(this.warning ? "warning" : "muted", footer),
278
+ safeWidth,
279
+ "",
280
+ ),
281
+ ]
282
+ : []),
283
+ ],
284
+ availableRows,
285
+ );
286
+ }
287
+
288
+ handleInput(data: string): void {
289
+ if (this.finished) return;
290
+ if (matchesKey(data, Key.ctrl("c"))) {
291
+ this.finish({ kind: "close" });
292
+ return;
293
+ }
294
+ if (this.keybindings.matches(data, "tui.select.cancel")) {
295
+ this.finish({ kind: "back" });
296
+ return;
297
+ }
298
+ if (matchesConfirm(data, this.keybindings)) {
299
+ if (this.lines.length > 0) {
300
+ const segments = this.getSelectedSegments();
301
+ if (segments.length === 0) {
302
+ this.warning = "Select text first";
303
+ this.tui.requestRender();
304
+ } else {
305
+ this.finish({ kind: "confirm", segments });
306
+ }
307
+ }
308
+ return;
309
+ }
310
+ if (matchesKey(data, Key.space)) {
311
+ this.anchor = undefined;
312
+ this.lineAnchor = this.lineAnchor === undefined ? this.cursor.line : undefined;
313
+ this.afterMove();
314
+ return;
315
+ }
316
+ if (matchesKey(data, Key.shift("left"))) {
317
+ this.moveHorizontal(-1, true);
318
+ return;
319
+ }
320
+ if (matchesKey(data, Key.shift("right"))) {
321
+ this.moveHorizontal(1, true);
322
+ return;
323
+ }
324
+ if (matchesKey(data, Key.shift("up"))) {
325
+ this.moveVertical(-1, true);
326
+ return;
327
+ }
328
+ if (matchesKey(data, Key.shift("down"))) {
329
+ this.moveVertical(1, true);
330
+ return;
331
+ }
332
+ if (matchesKey(data, Key.left)) {
333
+ this.moveHorizontal(-1, false);
334
+ return;
335
+ }
336
+ if (matchesKey(data, Key.right)) {
337
+ this.moveHorizontal(1, false);
338
+ return;
339
+ }
340
+ if (this.keybindings.matches(data, "tui.select.up")) {
341
+ this.moveVertical(-1, false);
342
+ return;
343
+ }
344
+ if (this.keybindings.matches(data, "tui.select.down")) {
345
+ this.moveVertical(1, false);
346
+ return;
347
+ }
348
+ if (this.keybindings.matches(data, "tui.select.pageUp")) {
349
+ this.moveVertical(-10, false);
350
+ return;
351
+ }
352
+ if (this.keybindings.matches(data, "tui.select.pageDown")) {
353
+ this.moveVertical(10, false);
354
+ return;
355
+ }
356
+ }
357
+
358
+ invalidate(): void {}
359
+
360
+ private renderTextLine(
361
+ line: BtwSelectionLine,
362
+ lineIndex: number,
363
+ range: { start: BtwTextPosition; end: BtwTextPosition } | undefined,
364
+ lineSelected: boolean,
365
+ ): string {
366
+ const characters = splitGraphemes(line.text);
367
+ let rendered = this.horizontalOffset > 0 ? this.theme.fg("muted", "…") : "";
368
+ let buffer = "";
369
+ let bufferSelected = false;
370
+ const flush = () => {
371
+ if (!buffer) return;
372
+ rendered += bufferSelected
373
+ ? this.theme.bg("selectedBg", this.theme.fg("text", buffer))
374
+ : buffer;
375
+ buffer = "";
376
+ };
377
+ for (let column = this.horizontalOffset; column <= characters.length; column += 1) {
378
+ if (range && lineIndex === range.start.line && column === range.start.column) {
379
+ flush();
380
+ rendered += this.theme.fg("accent", "[");
381
+ }
382
+ if (lineIndex === this.cursor.line && column === this.cursor.column) {
383
+ flush();
384
+ rendered += this.theme.fg("accent", "│");
385
+ }
386
+ if (range && lineIndex === range.end.line && column === range.end.column) {
387
+ flush();
388
+ rendered += this.theme.fg("accent", "]");
389
+ }
390
+ const character = characters[column];
391
+ if (character === undefined) continue;
392
+ const selected =
393
+ lineSelected || (range ? positionFallsInside(lineIndex, column, range) : false);
394
+ if (buffer && selected !== bufferSelected) flush();
395
+ bufferSelected = selected;
396
+ buffer += escapeTerminalControls(character);
397
+ }
398
+ flush();
399
+ return rendered;
400
+ }
401
+
402
+ private getSelectionRange(): { start: BtwTextPosition; end: BtwTextPosition } | undefined {
403
+ if (!this.anchor || compareTextPositions(this.anchor, this.cursor) === 0) return undefined;
404
+ return compareTextPositions(this.anchor, this.cursor) < 0
405
+ ? { start: this.anchor, end: this.cursor }
406
+ : { start: this.cursor, end: this.anchor };
407
+ }
408
+
409
+ private getLineSelectionRange(): { start: number; end: number } | undefined {
410
+ return this.lineAnchor === undefined
411
+ ? undefined
412
+ : {
413
+ start: Math.min(this.lineAnchor, this.cursor.line),
414
+ end: Math.max(this.lineAnchor, this.cursor.line),
415
+ };
416
+ }
417
+
418
+ private getSelectedSegments(): BtwBringToMainSegment[] {
419
+ if (this.lineAnchor !== undefined) {
420
+ return segmentsFromLineRange(this.lines, this.lineAnchor, this.cursor.line);
421
+ }
422
+ return this.anchor ? segmentsFromTextRange(this.lines, this.anchor, this.cursor) : [];
423
+ }
424
+
425
+ private moveHorizontal(delta: -1 | 1, extend: boolean): void {
426
+ if (this.lines.length === 0) return;
427
+ if (!extend) this.lineAnchor = undefined;
428
+ if (!extend && this.anchor) {
429
+ const range = this.getSelectionRange();
430
+ if (range) this.cursor = delta < 0 ? range.start : range.end;
431
+ this.anchor = undefined;
432
+ this.preferredColumn = this.cursor.column;
433
+ this.afterMove();
434
+ return;
435
+ }
436
+ this.beginOrClearSelection(extend);
437
+ const line = this.lines[this.cursor.line];
438
+ const length = line ? splitGraphemes(line.text).length : 0;
439
+ if (delta < 0) {
440
+ if (this.cursor.column > 0) this.cursor = { ...this.cursor, column: this.cursor.column - 1 };
441
+ else if (this.cursor.line > 0) {
442
+ const previousLine = this.lines[this.cursor.line - 1];
443
+ this.cursor = {
444
+ line: this.cursor.line - 1,
445
+ column: previousLine ? splitGraphemes(previousLine.text).length : 0,
446
+ };
447
+ }
448
+ } else if (this.cursor.column < length) {
449
+ this.cursor = { ...this.cursor, column: this.cursor.column + 1 };
450
+ } else if (this.cursor.line < this.lines.length - 1) {
451
+ this.cursor = { line: this.cursor.line + 1, column: 0 };
452
+ }
453
+ this.preferredColumn = this.cursor.column;
454
+ this.afterMove();
455
+ }
456
+
457
+ private moveVertical(delta: number, extend: boolean): void {
458
+ if (this.lines.length === 0) return;
459
+ if (extend || this.lineAnchor === undefined) this.beginOrClearSelection(extend);
460
+ const line = Math.max(0, Math.min(this.lines.length - 1, this.cursor.line + delta));
461
+ const target = this.lines[line];
462
+ this.cursor = {
463
+ line,
464
+ column: Math.min(this.preferredColumn, target ? splitGraphemes(target.text).length : 0),
465
+ };
466
+ this.afterMove();
467
+ }
468
+
469
+ private beginOrClearSelection(extend: boolean): void {
470
+ if (extend) this.lineAnchor = undefined;
471
+ if (extend && !this.anchor) this.anchor = { ...this.cursor };
472
+ if (!extend) this.anchor = undefined;
473
+ }
474
+
475
+ private afterMove(): void {
476
+ this.warning = undefined;
477
+ this.tui.requestRender();
478
+ }
479
+
480
+ private keepCursorVisible(height: number): void {
481
+ if (height <= 0) return;
482
+ if (this.cursor.line < this.scrollOffset) this.scrollOffset = this.cursor.line;
483
+ if (this.cursor.line >= this.scrollOffset + height) {
484
+ this.scrollOffset = this.cursor.line - height + 1;
485
+ }
486
+ }
487
+
488
+ private keepCursorHorizontallyVisible(width: number): void {
489
+ const characters = splitGraphemes(this.lines[this.cursor.line]?.text ?? "");
490
+ const displayWidths = characters.map((character) =>
491
+ visibleWidth(escapeTerminalControls(character)),
492
+ );
493
+ const currentWidth = displayWidths[this.cursor.column] ?? 0;
494
+ let usedWidth = 1 + Math.min(currentWidth, Math.max(0, width - 1));
495
+ let offset = this.cursor.column;
496
+ for (let index = this.cursor.column - 1; index >= 0; index -= 1) {
497
+ const nextWidth = usedWidth + (displayWidths[index] ?? 0) + (index > 0 ? 1 : 0);
498
+ if (nextWidth > width) break;
499
+ usedWidth += displayWidths[index] ?? 0;
500
+ offset = index;
501
+ }
502
+ this.horizontalOffset = offset;
503
+ }
504
+
505
+ private finish(action: BtwTextRangeSelectorAction): void {
506
+ if (this.finished) return;
507
+ this.finished = true;
508
+ this.onAction(action);
509
+ }
510
+ }
511
+
512
+ function clampTextPosition(
513
+ lines: readonly BtwSelectionLine[],
514
+ position: BtwTextPosition,
515
+ ): BtwTextPosition {
516
+ const line = Math.max(0, Math.min(lines.length - 1, position.line));
517
+ const text = lines[line]?.text ?? "";
518
+ return {
519
+ line,
520
+ column: Math.max(0, Math.min(splitGraphemes(text).length, position.column)),
521
+ };
522
+ }
523
+
524
+ function confirmKeyLabel(keybindings: KeybindingsManager): string {
525
+ return keybindingLabel(keybindings, "tui.select.confirm", ["ctrl+c"], "enter");
526
+ }
527
+
528
+ function matchesConfirm(data: string, keybindings: KeybindingsManager): boolean {
529
+ if (matchesKey(data, Key.ctrl("c"))) return false;
530
+ const hasUsableBinding = keybindings
531
+ .getKeys("tui.select.confirm")
532
+ .map(String)
533
+ .some((key) => key.toLowerCase() !== "ctrl+c");
534
+ return (
535
+ keybindings.matches(data, "tui.select.confirm") ||
536
+ (!hasUsableBinding && matchesKey(data, Key.enter))
537
+ );
538
+ }
539
+
540
+ function keybindingLabel(
541
+ keybindings: KeybindingsManager,
542
+ keybinding:
543
+ | "tui.select.confirm"
544
+ | "tui.select.cancel"
545
+ | "tui.select.up"
546
+ | "tui.select.down"
547
+ | "tui.select.pageUp"
548
+ | "tui.select.pageDown",
549
+ excluded: readonly string[] = [],
550
+ fallback?: string,
551
+ ): string {
552
+ const key = keybindings
553
+ .getKeys(keybinding)
554
+ .map(String)
555
+ .find((candidate) => !excluded.includes(candidate.toLowerCase()));
556
+ return formatKeyLabel(key ?? fallback ?? keybinding);
557
+ }
558
+
559
+ function formatKeyLabel(key: string): string {
560
+ return key
561
+ .split("+")
562
+ .map((part) => {
563
+ const lower = part.toLowerCase();
564
+ if (lower === "ctrl") return "Ctrl";
565
+ if (lower === "alt") return "Alt";
566
+ if (lower === "shift") return "Shift";
567
+ if (lower === "escape" || lower === "esc") return "Esc";
568
+ if (lower === "enter" || lower === "return") return "Enter";
569
+ if (lower === "pageup") return "PgUp";
570
+ if (lower === "pagedown") return "PgDn";
571
+ return part.length === 1
572
+ ? part.toUpperCase()
573
+ : `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`;
574
+ })
575
+ .join("+");
576
+ }
577
+
578
+ function splitGraphemes(text: string): string[] {
579
+ return [...GRAPHEME_SEGMENTER.segment(text)].map(({ segment }) => segment);
580
+ }
581
+
582
+ function compareTextPositions(first: BtwTextPosition, second: BtwTextPosition): number {
583
+ return first.line === second.line ? first.column - second.column : first.line - second.line;
584
+ }
585
+
586
+ function positionFallsInside(
587
+ line: number,
588
+ column: number,
589
+ range: { start: BtwTextPosition; end: BtwTextPosition },
590
+ ): boolean {
591
+ const position = { line, column };
592
+ return (
593
+ compareTextPositions(position, range.start) >= 0 &&
594
+ compareTextPositions(position, range.end) < 0
595
+ );
596
+ }
597
+
598
+ function fitRows(rows: string[], availableRows: number): string[] {
599
+ if (rows.length <= availableRows) return rows;
600
+ if (availableRows <= 1) return rows.slice(0, 1);
601
+ return [rows[0] ?? "", ...rows.slice(rows.length - availableRows + 1)];
602
+ }
603
+
604
+ function escapeBringToMainText(text: string): string {
605
+ return [...text]
606
+ .map((character) => {
607
+ if (character === "\n") return character;
608
+ if (character === "\t") return " ";
609
+ const code = character.charCodeAt(0);
610
+ if (code <= 31 || (code >= 127 && code <= 159)) {
611
+ return `\\x${code.toString(16).padStart(2, "0")}`;
612
+ }
613
+ return character;
614
+ })
615
+ .join("")
616
+ .replace(/<btw_context(?=[ \t\r\n>])/g, "&lt;btw_context")
617
+ .replace(/<\/btw_context[ \t\r\n]*>/g, (terminator) =>
618
+ terminator.replaceAll("<", "&lt;").replaceAll(">", "&gt;"),
619
+ );
620
+ }
621
+
622
+ function escapeTerminalControls(text: string): string {
623
+ return [...text]
624
+ .map((character) => {
625
+ const code = character.charCodeAt(0);
626
+ if (code <= 31 || (code >= 127 && code <= 159)) {
627
+ return `\\x${code.toString(16).padStart(2, "0")}`;
628
+ }
629
+ return character;
630
+ })
631
+ .join("");
632
+ }