aicodeman 1.41.0 → 1.42.0

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 (339) hide show
  1. package/README.md +101 -21
  2. package/dist/attachment-registry.d.ts +2 -0
  3. package/dist/attachment-registry.d.ts.map +1 -1
  4. package/dist/attachment-registry.js +14 -3
  5. package/dist/attachment-registry.js.map +1 -1
  6. package/dist/cli-agent.d.ts +2 -0
  7. package/dist/cli-agent.d.ts.map +1 -1
  8. package/dist/cli-agent.js +13 -9
  9. package/dist/cli-agent.js.map +1 -1
  10. package/dist/cli.d.ts +25 -1
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +97 -11
  13. package/dist/cli.js.map +1 -1
  14. package/dist/config/buffer-limits.d.ts +9 -0
  15. package/dist/config/buffer-limits.d.ts.map +1 -1
  16. package/dist/config/buffer-limits.js +9 -0
  17. package/dist/config/buffer-limits.js.map +1 -1
  18. package/dist/config/cli-registry/schema.d.ts +10 -0
  19. package/dist/config/cli-registry/schema.d.ts.map +1 -1
  20. package/dist/config/cli-registry/schema.js +26 -0
  21. package/dist/config/cli-registry/schema.js.map +1 -1
  22. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  23. package/dist/config/cli-registry/stock.js +89 -6
  24. package/dist/config/cli-registry/stock.js.map +1 -1
  25. package/dist/config/cli-registry/types.d.ts +61 -0
  26. package/dist/config/cli-registry/types.d.ts.map +1 -1
  27. package/dist/folder-listing.d.ts +94 -0
  28. package/dist/folder-listing.d.ts.map +1 -0
  29. package/dist/folder-listing.js +241 -0
  30. package/dist/folder-listing.js.map +1 -0
  31. package/dist/git-worktrees.d.ts +292 -0
  32. package/dist/git-worktrees.d.ts.map +1 -0
  33. package/dist/git-worktrees.js +791 -0
  34. package/dist/git-worktrees.js.map +1 -0
  35. package/dist/hooks-config.d.ts +36 -16
  36. package/dist/hooks-config.d.ts.map +1 -1
  37. package/dist/hooks-config.js +45 -20
  38. package/dist/hooks-config.js.map +1 -1
  39. package/dist/html-view-capabilities.d.ts +54 -0
  40. package/dist/html-view-capabilities.d.ts.map +1 -0
  41. package/dist/html-view-capabilities.js +103 -0
  42. package/dist/html-view-capabilities.js.map +1 -0
  43. package/dist/mcp-server.d.ts +114 -0
  44. package/dist/mcp-server.d.ts.map +1 -0
  45. package/dist/mcp-server.js +918 -0
  46. package/dist/mcp-server.js.map +1 -0
  47. package/dist/mcp-sync.d.ts +5 -0
  48. package/dist/mcp-sync.d.ts.map +1 -1
  49. package/dist/mcp-sync.js +51 -5
  50. package/dist/mcp-sync.js.map +1 -1
  51. package/dist/mux-interface.d.ts +36 -1
  52. package/dist/mux-interface.d.ts.map +1 -1
  53. package/dist/remote-files.d.ts +37 -0
  54. package/dist/remote-files.d.ts.map +1 -1
  55. package/dist/remote-files.js +103 -0
  56. package/dist/remote-files.js.map +1 -1
  57. package/dist/remote-pane-history.d.ts +103 -0
  58. package/dist/remote-pane-history.d.ts.map +1 -0
  59. package/dist/remote-pane-history.js +258 -0
  60. package/dist/remote-pane-history.js.map +1 -0
  61. package/dist/remote-ssh-limiter.d.ts +16 -3
  62. package/dist/remote-ssh-limiter.d.ts.map +1 -1
  63. package/dist/remote-ssh-limiter.js +37 -6
  64. package/dist/remote-ssh-limiter.js.map +1 -1
  65. package/dist/services/unified-session-service.d.ts +8 -0
  66. package/dist/services/unified-session-service.d.ts.map +1 -1
  67. package/dist/services/unified-session-service.js +21 -0
  68. package/dist/services/unified-session-service.js.map +1 -1
  69. package/dist/session-activity.d.ts +51 -0
  70. package/dist/session-activity.d.ts.map +1 -1
  71. package/dist/session-activity.js +62 -0
  72. package/dist/session-activity.js.map +1 -1
  73. package/dist/session-submit-verifier.js +1 -1
  74. package/dist/session.d.ts +90 -2
  75. package/dist/session.d.ts.map +1 -1
  76. package/dist/session.js +247 -9
  77. package/dist/session.js.map +1 -1
  78. package/dist/tab-layout-legacy-order.d.ts.map +1 -1
  79. package/dist/tab-layout-legacy-order.js +72 -13
  80. package/dist/tab-layout-legacy-order.js.map +1 -1
  81. package/dist/tab-layout-service.d.ts +33 -2
  82. package/dist/tab-layout-service.d.ts.map +1 -1
  83. package/dist/tab-layout-service.js +102 -7
  84. package/dist/tab-layout-service.js.map +1 -1
  85. package/dist/tab-layout.d.ts +9 -0
  86. package/dist/tab-layout.d.ts.map +1 -1
  87. package/dist/tab-layout.js +15 -2
  88. package/dist/tab-layout.js.map +1 -1
  89. package/dist/tmux-manager.d.ts +130 -7
  90. package/dist/tmux-manager.d.ts.map +1 -1
  91. package/dist/tmux-manager.js +263 -36
  92. package/dist/tmux-manager.js.map +1 -1
  93. package/dist/types/session.d.ts +53 -0
  94. package/dist/types/session.d.ts.map +1 -1
  95. package/dist/types/session.js.map +1 -1
  96. package/dist/usage-telemetry.d.ts +44 -7
  97. package/dist/usage-telemetry.d.ts.map +1 -1
  98. package/dist/usage-telemetry.js +72 -7
  99. package/dist/usage-telemetry.js.map +1 -1
  100. package/dist/utils/deepseek-cli-resolver.d.ts.map +1 -1
  101. package/dist/utils/deepseek-cli-resolver.js +1 -1
  102. package/dist/utils/deepseek-cli-resolver.js.map +1 -1
  103. package/dist/web/approval-inbox.d.ts +24 -2
  104. package/dist/web/approval-inbox.d.ts.map +1 -1
  105. package/dist/web/approval-inbox.js +8 -2
  106. package/dist/web/approval-inbox.js.map +1 -1
  107. package/dist/web/middleware/auth.d.ts.map +1 -1
  108. package/dist/web/middleware/auth.js +33 -0
  109. package/dist/web/middleware/auth.js.map +1 -1
  110. package/dist/web/ports/session-port.d.ts +8 -1
  111. package/dist/web/ports/session-port.d.ts.map +1 -1
  112. package/dist/web/public/admin-ui.js.gz +0 -0
  113. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  114. package/dist/web/public/app.f04bb2a5.js +43 -0
  115. package/dist/web/public/app.f04bb2a5.js.br +0 -0
  116. package/dist/web/public/app.f04bb2a5.js.gz +0 -0
  117. package/dist/web/public/approvals-ui.js +4 -0
  118. package/dist/web/public/approvals-ui.js.br +0 -0
  119. package/dist/web/public/approvals-ui.js.gz +0 -0
  120. package/dist/web/public/{constants.bc9c1f63.js → constants.12b0c247.js} +395 -7
  121. package/dist/web/public/constants.12b0c247.js.br +0 -0
  122. package/dist/web/public/constants.12b0c247.js.gz +0 -0
  123. package/dist/web/public/cron-ui.js.gz +0 -0
  124. package/dist/web/public/entrance-animations.js.gz +0 -0
  125. package/dist/web/public/gesture/gesture-codeman.js +112 -6
  126. package/dist/web/public/git-status-ui.js.gz +0 -0
  127. package/dist/web/public/home-sessions.js.gz +0 -0
  128. package/dist/web/public/host-wake-ui.js.gz +0 -0
  129. package/dist/web/public/i18n.06659676.js +2 -0
  130. package/dist/web/public/i18n.06659676.js.br +0 -0
  131. package/dist/web/public/i18n.06659676.js.gz +0 -0
  132. package/dist/web/public/image-input.fcdcb46c.js +462 -0
  133. package/dist/web/public/image-input.fcdcb46c.js.br +0 -0
  134. package/dist/web/public/image-input.fcdcb46c.js.gz +0 -0
  135. package/dist/web/public/index.html +169 -24
  136. package/dist/web/public/index.html.br +0 -0
  137. package/dist/web/public/index.html.gz +0 -0
  138. package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
  139. package/dist/web/public/{keyboard-accessory.c1e7c7b7.js → keyboard-accessory.b42f539b.js} +124 -44
  140. package/dist/web/public/keyboard-accessory.b42f539b.js.br +0 -0
  141. package/dist/web/public/keyboard-accessory.b42f539b.js.gz +0 -0
  142. package/dist/web/public/mobile-handlers.0ef9c311.js.gz +0 -0
  143. package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
  144. package/dist/web/public/mobile-overview.js +11 -2
  145. package/dist/web/public/mobile-overview.js.br +0 -0
  146. package/dist/web/public/mobile-overview.js.gz +0 -0
  147. package/dist/web/public/mobile.2dff1580.css +1 -0
  148. package/dist/web/public/mobile.2dff1580.css.br +0 -0
  149. package/dist/web/public/mobile.2dff1580.css.gz +0 -0
  150. package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
  151. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  152. package/dist/web/public/{panels-ui.71846fcb.js → panels-ui.73ec0137.js} +87 -87
  153. package/dist/web/public/panels-ui.73ec0137.js.br +0 -0
  154. package/dist/web/public/panels-ui.73ec0137.js.gz +0 -0
  155. package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
  156. package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
  157. package/dist/web/public/readmymind-ui.js.gz +0 -0
  158. package/dist/web/public/reboot-restore-ui.js.gz +0 -0
  159. package/dist/web/public/{respawn-ui.ff0dae4c.js → respawn-ui.d7adcf6a.js} +1 -1
  160. package/dist/web/public/respawn-ui.d7adcf6a.js.br +0 -0
  161. package/dist/web/public/respawn-ui.d7adcf6a.js.gz +0 -0
  162. package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
  163. package/dist/web/public/session-lineage.js.gz +0 -0
  164. package/dist/web/public/session-ui.d52ff6aa.js +100 -0
  165. package/dist/web/public/session-ui.d52ff6aa.js.br +0 -0
  166. package/dist/web/public/session-ui.d52ff6aa.js.gz +0 -0
  167. package/dist/web/public/settings-ui.3a22bd2a.js +97 -0
  168. package/dist/web/public/settings-ui.3a22bd2a.js.br +0 -0
  169. package/dist/web/public/settings-ui.3a22bd2a.js.gz +0 -0
  170. package/dist/web/public/spreadsheet-preview-worker.js +11 -0
  171. package/dist/web/public/spreadsheet-preview-worker.js.br +0 -0
  172. package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
  173. package/dist/web/public/{spreadsheet-preview.af82fa2f.js → spreadsheet-preview.75c751de.js} +1 -1
  174. package/dist/web/public/spreadsheet-preview.75c751de.js.br +0 -0
  175. package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
  176. package/dist/web/public/spreadsheet-xlsx-core.js +110 -0
  177. package/dist/web/public/spreadsheet-xlsx-core.js.br +0 -0
  178. package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
  179. package/dist/web/public/styles.ba6a9b84.css +1 -0
  180. package/dist/web/public/styles.ba6a9b84.css.br +0 -0
  181. package/dist/web/public/styles.ba6a9b84.css.gz +0 -0
  182. package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
  183. package/dist/web/public/sw.js +6 -2
  184. package/dist/web/public/sw.js.br +0 -0
  185. package/dist/web/public/sw.js.gz +0 -0
  186. package/dist/web/public/tab-layout-browser.2d6189f7.js +1 -0
  187. package/dist/web/public/tab-layout-browser.2d6189f7.js.br +0 -0
  188. package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
  189. package/dist/web/public/{tab-rail-resize.a5867793.js → tab-rail-resize.7157e0bd.js} +1 -1
  190. package/dist/web/public/tab-rail-resize.7157e0bd.js.br +0 -0
  191. package/dist/web/public/tab-rail-resize.7157e0bd.js.gz +0 -0
  192. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
  193. package/dist/web/public/terminal-split.js.gz +0 -0
  194. package/dist/web/public/terminal-tile.js +45 -24
  195. package/dist/web/public/terminal-tile.js.br +0 -0
  196. package/dist/web/public/terminal-tile.js.gz +0 -0
  197. package/dist/web/public/terminal-ui.0a7ccc29.js +2 -0
  198. package/dist/web/public/terminal-ui.0a7ccc29.js.br +0 -0
  199. package/dist/web/public/terminal-ui.0a7ccc29.js.gz +0 -0
  200. package/dist/web/public/tile-grid.js +439 -18
  201. package/dist/web/public/tile-grid.js.br +0 -0
  202. package/dist/web/public/tile-grid.js.gz +0 -0
  203. package/dist/web/public/ultracode-panel.js.gz +0 -0
  204. package/dist/web/public/ultracode-windows.js.gz +0 -0
  205. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  206. package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
  207. package/dist/web/public/vendor/fflate.min.js.gz +0 -0
  208. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  209. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  210. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  211. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  212. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  213. package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.gz +0 -0
  214. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.gz +0 -0
  215. package/dist/web/public/vendor/xterm.css.gz +0 -0
  216. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  217. package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
  218. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  219. package/dist/web/public/webview-tabs.js +12 -0
  220. package/dist/web/public/webview-tabs.js.br +0 -0
  221. package/dist/web/public/webview-tabs.js.gz +0 -0
  222. package/dist/web/public/whats-new.json +13 -0
  223. package/dist/web/route-helpers.d.ts +8 -0
  224. package/dist/web/route-helpers.d.ts.map +1 -1
  225. package/dist/web/route-helpers.js +8 -0
  226. package/dist/web/route-helpers.js.map +1 -1
  227. package/dist/web/routes/admin-routes.d.ts.map +1 -1
  228. package/dist/web/routes/admin-routes.js +4 -1
  229. package/dist/web/routes/admin-routes.js.map +1 -1
  230. package/dist/web/routes/approval-routes.d.ts.map +1 -1
  231. package/dist/web/routes/approval-routes.js +12 -10
  232. package/dist/web/routes/approval-routes.js.map +1 -1
  233. package/dist/web/routes/case-routes.d.ts.map +1 -1
  234. package/dist/web/routes/case-routes.js +10 -3
  235. package/dist/web/routes/case-routes.js.map +1 -1
  236. package/dist/web/routes/file-routes.d.ts +46 -1
  237. package/dist/web/routes/file-routes.d.ts.map +1 -1
  238. package/dist/web/routes/file-routes.js +214 -27
  239. package/dist/web/routes/file-routes.js.map +1 -1
  240. package/dist/web/routes/hook-event-routes.d.ts.map +1 -1
  241. package/dist/web/routes/hook-event-routes.js +8 -1
  242. package/dist/web/routes/hook-event-routes.js.map +1 -1
  243. package/dist/web/routes/html-view-routes.d.ts +60 -0
  244. package/dist/web/routes/html-view-routes.d.ts.map +1 -0
  245. package/dist/web/routes/html-view-routes.js +288 -0
  246. package/dist/web/routes/html-view-routes.js.map +1 -0
  247. package/dist/web/routes/index.d.ts +2 -0
  248. package/dist/web/routes/index.d.ts.map +1 -1
  249. package/dist/web/routes/index.js +2 -0
  250. package/dist/web/routes/index.js.map +1 -1
  251. package/dist/web/routes/ralph-routes.d.ts.map +1 -1
  252. package/dist/web/routes/ralph-routes.js +19 -14
  253. package/dist/web/routes/ralph-routes.js.map +1 -1
  254. package/dist/web/routes/reboot-restore-routes.js +2 -2
  255. package/dist/web/routes/reboot-restore-routes.js.map +1 -1
  256. package/dist/web/routes/session-routes.d.ts +8 -5
  257. package/dist/web/routes/session-routes.d.ts.map +1 -1
  258. package/dist/web/routes/session-routes.js +462 -109
  259. package/dist/web/routes/session-routes.js.map +1 -1
  260. package/dist/web/routes/status-telemetry-routes.d.ts.map +1 -1
  261. package/dist/web/routes/status-telemetry-routes.js +24 -6
  262. package/dist/web/routes/status-telemetry-routes.js.map +1 -1
  263. package/dist/web/routes/system-routes.d.ts +9 -0
  264. package/dist/web/routes/system-routes.d.ts.map +1 -1
  265. package/dist/web/routes/system-routes.js +91 -12
  266. package/dist/web/routes/system-routes.js.map +1 -1
  267. package/dist/web/routes/worktree-routes.d.ts +52 -0
  268. package/dist/web/routes/worktree-routes.d.ts.map +1 -0
  269. package/dist/web/routes/worktree-routes.js +220 -0
  270. package/dist/web/routes/worktree-routes.js.map +1 -0
  271. package/dist/web/schemas.d.ts +45 -0
  272. package/dist/web/schemas.d.ts.map +1 -1
  273. package/dist/web/schemas.js +105 -0
  274. package/dist/web/schemas.js.map +1 -1
  275. package/dist/web/screen-blocked.d.ts +80 -0
  276. package/dist/web/screen-blocked.d.ts.map +1 -0
  277. package/dist/web/screen-blocked.js +106 -0
  278. package/dist/web/screen-blocked.js.map +1 -0
  279. package/dist/web/server.d.ts +6 -1
  280. package/dist/web/server.d.ts.map +1 -1
  281. package/dist/web/server.js +73 -14
  282. package/dist/web/server.js.map +1 -1
  283. package/dist/web/session-listener-wiring.d.ts +1 -0
  284. package/dist/web/session-listener-wiring.d.ts.map +1 -1
  285. package/dist/web/session-listener-wiring.js +20 -0
  286. package/dist/web/session-listener-wiring.js.map +1 -1
  287. package/dist/web/session-wait-registry.d.ts +27 -9
  288. package/dist/web/session-wait-registry.d.ts.map +1 -1
  289. package/dist/web/session-wait-registry.js +36 -13
  290. package/dist/web/session-wait-registry.js.map +1 -1
  291. package/dist/web/sse-events.d.ts +12 -4
  292. package/dist/web/sse-events.d.ts.map +1 -1
  293. package/dist/web/sse-events.js +12 -4
  294. package/dist/web/sse-events.js.map +1 -1
  295. package/package.json +3 -2
  296. package/skills/codeman/SKILL.md +47 -27
  297. package/skills/codeman/preamble.sh +14 -11
  298. package/skills/codeman/reference/endpoints.md +1 -1
  299. package/skills/codeman/reference/recipes.md +12 -9
  300. package/skills/codeman/reference/verbs.md +3 -1
  301. package/dist/web/public/app.6f8552e1.js +0 -43
  302. package/dist/web/public/app.6f8552e1.js.br +0 -0
  303. package/dist/web/public/app.6f8552e1.js.gz +0 -0
  304. package/dist/web/public/constants.bc9c1f63.js.br +0 -0
  305. package/dist/web/public/constants.bc9c1f63.js.gz +0 -0
  306. package/dist/web/public/i18n.a9840ea2.js +0 -2
  307. package/dist/web/public/i18n.a9840ea2.js.br +0 -0
  308. package/dist/web/public/i18n.a9840ea2.js.gz +0 -0
  309. package/dist/web/public/image-input.e00471c6.js +0 -283
  310. package/dist/web/public/image-input.e00471c6.js.br +0 -0
  311. package/dist/web/public/image-input.e00471c6.js.gz +0 -0
  312. package/dist/web/public/keyboard-accessory.c1e7c7b7.js.br +0 -0
  313. package/dist/web/public/keyboard-accessory.c1e7c7b7.js.gz +0 -0
  314. package/dist/web/public/mobile.111b187d.css +0 -1
  315. package/dist/web/public/mobile.111b187d.css.br +0 -0
  316. package/dist/web/public/mobile.111b187d.css.gz +0 -0
  317. package/dist/web/public/panels-ui.71846fcb.js.br +0 -0
  318. package/dist/web/public/panels-ui.71846fcb.js.gz +0 -0
  319. package/dist/web/public/respawn-ui.ff0dae4c.js.br +0 -0
  320. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  321. package/dist/web/public/session-ui.f731602c.js +0 -100
  322. package/dist/web/public/session-ui.f731602c.js.br +0 -0
  323. package/dist/web/public/session-ui.f731602c.js.gz +0 -0
  324. package/dist/web/public/settings-ui.4e33390f.js +0 -97
  325. package/dist/web/public/settings-ui.4e33390f.js.br +0 -0
  326. package/dist/web/public/settings-ui.4e33390f.js.gz +0 -0
  327. package/dist/web/public/spreadsheet-preview.af82fa2f.js.br +0 -0
  328. package/dist/web/public/spreadsheet-preview.af82fa2f.js.gz +0 -0
  329. package/dist/web/public/styles.81a72906.css +0 -1
  330. package/dist/web/public/styles.81a72906.css.br +0 -0
  331. package/dist/web/public/styles.81a72906.css.gz +0 -0
  332. package/dist/web/public/tab-layout-browser.065fcba4.js +0 -1
  333. package/dist/web/public/tab-layout-browser.065fcba4.js.br +0 -0
  334. package/dist/web/public/tab-layout-browser.065fcba4.js.gz +0 -0
  335. package/dist/web/public/tab-rail-resize.a5867793.js.br +0 -0
  336. package/dist/web/public/tab-rail-resize.a5867793.js.gz +0 -0
  337. package/dist/web/public/terminal-ui.b7267005.js +0 -2
  338. package/dist/web/public/terminal-ui.b7267005.js.br +0 -0
  339. package/dist/web/public/terminal-ui.b7267005.js.gz +0 -0
package/dist/session.js CHANGED
@@ -42,7 +42,7 @@ import { TaskTracker } from './task-tracker.js';
42
42
  import { RalphTracker } from './ralph-tracker.js';
43
43
  import { BashToolParser } from './bash-tool-parser.js';
44
44
  import { isTrustDialogScreen, trustDialogNextKey, TRUST_KEY_CONFIRM, TRUST_DIALOG_WINDOW_MS, TRUST_DIALOG_RETRY_MS, TRUST_DIALOG_MAX_ATTEMPTS, TRUST_DIALOG_SCAN_BYTES, } from './session-trust-dialog.js';
45
- import { trackActivityStreak, isSustainedActivity, isPaneQuiet, watchingLabel, isAwaitingWorkers, WATCHING_TAIL_LINES, IDLE_RECHECK_MS, PANE_PROBE_MIN_INTERVAL_MS, PANE_PROBE_RECHECK_MS, } from './session-activity.js';
45
+ import { trackActivityStreak, isSustainedActivity, isPaneQuiet, watchingLabel, isAwaitingWorkers, isBlockedScreen, WATCHING_TAIL_LINES, BLOCKED_TAIL_LINES, BLOCKED_RECHECK_MS, BLOCKED_QUIET_RECHECK_MS, BLOCKED_CLEAR_READS, IDLE_RECHECK_MS, PANE_PROBE_MIN_INTERVAL_MS, PANE_PROBE_RECHECK_MS, } from './session-activity.js';
46
46
  import { BufferAccumulator, ANSI_ESCAPE_PATTERN_FULL, TOKEN_PATTERN, SPINNER_PATTERN, CLAUDE_WORKING_LINE_PATTERN, MAX_SESSION_TOKENS, execPattern, getClaudeCliVersion, getClaudeBinaryPath, spawnPtyWithHelperRepair, resolveLocalShell, waitForProcessesExit, } from './utils/index.js';
47
47
  import { MAX_TERMINAL_BUFFER_SIZE, TRIM_TERMINAL_TO as TERMINAL_BUFFER_TRIM_SIZE, MAX_TEXT_OUTPUT_SIZE, TRIM_TEXT_TO as TEXT_OUTPUT_TRIM_SIZE, MAX_MESSAGES, MAX_LINE_BUFFER_SIZE, } from './config/buffer-limits.js';
48
48
  import { DEFAULT_TMUX_HISTORY_LIMIT } from './config/terminal-history.js';
@@ -408,6 +408,7 @@ export class Session extends EventEmitter {
408
408
  _activityStreak = null; // Unbroken run of PTY repaints (working detection)
409
409
  _lastPaneProbeAt = 0; // Throttle for the tmux screen probe
410
410
  _lastPaneProbeWorking = null; // Its last verdict (null = could not read)
411
+ _lastPaneProbeTrustDialog = false; // Same capture showed the workspace-trust dialog (see _confirmIdle)
411
412
  /**
412
413
  * Background work the pane's own footer reports, e.g. `1 monitor`; null for none.
413
414
  *
@@ -431,6 +432,8 @@ export class Session extends EventEmitter {
431
432
  * running. A session that comes back with no label has no chip on its screen.
432
433
  */
433
434
  _watching = null;
435
+ /** Last `prompt_cache` report from the statusline exporter; null until Claude sends one. */
436
+ _promptCache = null;
434
437
  /** Lazily compiled `capabilities.workDetect.workingLine`. See _workingLinePattern(). */
435
438
  _workingLineRe = undefined;
436
439
  /** Lazily compiled `capabilities.workDetect.watchingLine`. See _watchingLinePattern(). */
@@ -439,6 +442,23 @@ export class Session extends EventEmitter {
439
442
  _watchingWindow = WATCHING_TAIL_LINES;
440
443
  /** Lazily compiled `capabilities.workDetect.awaitingLine`. See _awaitingLinePattern(). */
441
444
  _awaitingLineRe = undefined;
445
+ /** Lazily compiled `capabilities.workDetect.blockedLine`. See _blockedLinePattern(). */
446
+ _blockedLineRe = undefined;
447
+ /** Resolved with the pattern above: how many rows at the foot of the screen it sees. */
448
+ _blockedWindow = BLOCKED_TAIL_LINES;
449
+ /**
450
+ * The pane is showing a dialog the CLI blocks on, read off the screen with
451
+ * `capabilities.workDetect.blockedLine` (codex: an approval, a question, the trust
452
+ * prompt). Live state, not persisted: a restarted server re-reads it from the attach
453
+ * repaint the same way the watching label comes back. See `_noteBlockedReading()`.
454
+ */
455
+ _screenBlocked = false;
456
+ /** Consecutive readable captures without the dialog (cleared at BLOCKED_CLEAR_READS). */
457
+ _blockedGoneReads = 0;
458
+ /** When the last reading that SAW the dialog was taken. See `_armBlockedRecheck()`. */
459
+ _blockedSeenAt = 0;
460
+ /** Re-reads the screen while a dialog is up, so the alert clears with it. */
461
+ _blockedRecheckTimer = null;
442
462
  /**
443
463
  * The newest model the running CLI reported for itself (its statusline, or its own
444
464
  * footer read off the probe's capture), or null when none has. Feeds `displayModel`
@@ -753,6 +773,11 @@ export class Session extends EventEmitter {
753
773
  // browser panel arms and disarms — see `startPaneExitWatcher`.
754
774
  this.setPaneExit(config.paneExit);
755
775
  this._reportedModel = restoredReportedModel(config.displayModel) ?? null;
776
+ // Last prompt-cache report, restored so the Session Options readout is not blank until
777
+ // the pane's next statusline render. The readout is time-aware, so a value whose expiry
778
+ // has passed renders as cold rather than stale-warm. Set directly, not via
779
+ // setPromptCache, so recovery does not re-stamp a compaction it did not just observe.
780
+ this._promptCache = config.promptCache ?? null;
756
781
  // Never self-parent: a session pointing at itself would draw a zero-length
757
782
  // lineage arc under its own tab. Only reachable via the recovery path, where
758
783
  // both the id and the saved parent come from disk.
@@ -934,6 +959,11 @@ export class Session extends EventEmitter {
934
959
  if (newId === this._claudeSessionId)
935
960
  return;
936
961
  this._claudeSessionId = newId;
962
+ // The conversation itself changed (a post-/clear switch), so the old prefix's cache
963
+ // report and its compaction baseline belong to a conversation that is gone. Drop them
964
+ // rather than show the previous conversation's "warm until" against the new one; the
965
+ // next statusline render repopulates. A same-id reattach returned above, untouched.
966
+ this._promptCache = null;
937
967
  }
938
968
  /**
939
969
  * Append to the conversation chain, oldest first. A repeat of the current tail
@@ -1092,6 +1122,54 @@ export class Session extends EventEmitter {
1092
1122
  get watching() {
1093
1123
  return this._watching;
1094
1124
  }
1125
+ /**
1126
+ * True while the pane shows a dialog its CLI is blocked on, as read off the screen
1127
+ * (`capabilities.workDetect.blockedLine`). Always false for a CLI that declares none,
1128
+ * Claude included: its dialogs arrive as hook events instead. The `blocked` wait reads
1129
+ * it so a caller that asks after the dialog appeared is answered at once.
1130
+ */
1131
+ get screenBlocked() {
1132
+ return this._screenBlocked;
1133
+ }
1134
+ /**
1135
+ * Prompt-cache state of the main conversation as Claude Code last reported it on the
1136
+ * statusline (v2.1.251+), fed by `POST /api/status-telemetry`. Null until the first
1137
+ * report. It rides `toState()` for the Session Options readout and is restored on a
1138
+ * Codeman restart (constructor `promptCache`) so the row is not blank until the pane's
1139
+ * next render; the readout is time-aware, so a value whose `expiresAt` has passed renders
1140
+ * as cold rather than as a stale warm.
1141
+ */
1142
+ get promptCache() {
1143
+ return this._promptCache;
1144
+ }
1145
+ /**
1146
+ * Replace the prompt-cache report; true when it differs from the previous one. Stamps
1147
+ * `compactedAt` when this report ENTERS the window in which Claude Code reads
1148
+ * `recacheTokensIfCold` as null: a compaction (`/compact` or its own idle compaction) or
1149
+ * a clearing of old tool results opened it, and the previous report still had a known
1150
+ * value. Claude Code closes the window on the next request (that request is the one that
1151
+ * counts as an expected rebuild), so `expectedRebuilds` never rises inside it and is not
1152
+ * read here. The stamp is carried while the window holds and dropped once it closes; a
1153
+ * first report already inside the window gets none. It is never an alert.
1154
+ */
1155
+ setPromptCache(status) {
1156
+ const prev = this._promptCache;
1157
+ const inWindow = status.warm && status.recacheTokensIfCold == null;
1158
+ let compactedAt;
1159
+ if (inWindow && prev?.recacheTokensIfCold != null) {
1160
+ compactedAt = Date.now();
1161
+ }
1162
+ else if (inWindow && prev?.compactedAt != null) {
1163
+ compactedAt = prev.compactedAt;
1164
+ }
1165
+ // A NEW object when a stamp applies, never a mutation of the caller's parsed report: the
1166
+ // route broadcasts the STORED object, so the stamp lives here and never leaks back into the
1167
+ // parser's output (which would make the route's "broadcast the stored object" choice vacuous).
1168
+ const next = compactedAt != null ? { ...status, compactedAt } : status;
1169
+ const changed = JSON.stringify(next) !== JSON.stringify(prev);
1170
+ this._promptCache = next;
1171
+ return changed;
1172
+ }
1095
1173
  /**
1096
1174
  * Check if the session's process tree has active child processes beyond Claude itself.
1097
1175
  * Detects running bash tools, test suites, builds, servers, etc. that Claude spawned.
@@ -1506,6 +1584,8 @@ export class Session extends EventEmitter {
1506
1584
  autoCompactPrompt: this._autoOps.autoCompactPrompt,
1507
1585
  autoResumeEnabled: this._autoOps.autoResumeEnabled,
1508
1586
  autoResumeAt: this._autoOps.autoResumeAt ?? undefined,
1587
+ promptCache: this._promptCache ?? undefined,
1588
+ statusLineExporter: this._muxSession?.statusLine,
1509
1589
  imageWatcherEnabled: this._imageWatcherEnabled,
1510
1590
  pinned: this._pinned || undefined,
1511
1591
  pinnedAt: this._pinned ? (this._pinnedAt ?? undefined) : undefined,
@@ -2245,6 +2325,7 @@ export class Session extends EventEmitter {
2245
2325
  this._interactiveStartedAt = Date.now();
2246
2326
  this._trustDialogAttempts = 0;
2247
2327
  this._lastTrustDialogScanAt = 0;
2328
+ this._lastPaneProbeTrustDialog = false; // the last pane's verdict, not this one's
2248
2329
  if (this._trustDialogTimer) {
2249
2330
  clearTimeout(this._trustDialogTimer);
2250
2331
  this._trustDialogTimer = null;
@@ -2591,6 +2672,10 @@ export class Session extends EventEmitter {
2591
2672
  this._expensiveProcessTimer = null;
2592
2673
  }
2593
2674
  this._pendingCleanData = '';
2675
+ // Nothing reads this pane any more, so a dialog on it can no longer be seen to
2676
+ // close: drop the state (and its timer) while the listeners are still attached.
2677
+ // A re-attach re-reads the screen and raises it again if the dialog is still up.
2678
+ this._clearScreenBlocked();
2594
2679
  // If using mux, mark the session as detached but don't kill it
2595
2680
  if (this._muxSession && this._mux) {
2596
2681
  this._mux.setAttached(this.id, false);
@@ -2648,15 +2733,26 @@ export class Session extends EventEmitter {
2648
2733
  * a two-marker match (isTrustDialogScreen), and an attempt cap.
2649
2734
  */
2650
2735
  _maybeAcceptTrustDialog() {
2651
- if (this._trustDialogAccepted)
2736
+ // Stopped: the kill itself produces PTY output, and the buffer tail still holds the
2737
+ // dialog, so without this a deleted session kept "answering" it for several seconds.
2738
+ if (this._trustDialogAccepted || this._isStopped)
2652
2739
  return;
2653
2740
  const now = Date.now();
2654
2741
  if (now - this._interactiveStartedAt > TRUST_DIALOG_WINDOW_MS) {
2655
2742
  this._trustDialogAccepted = true; // window closed; anything matching now is not the dialog
2656
2743
  return;
2657
2744
  }
2658
- if (now - this._lastTrustDialogScanAt < TRUST_DIALOG_RETRY_MS)
2745
+ const sinceScan = now - this._lastTrustDialogScanAt;
2746
+ if (sinceScan < TRUST_DIALOG_RETRY_MS) {
2747
+ // ⚠️ Defer a throttled read, never drop it. The dialog's own paint is usually the
2748
+ // last output a launching pane produces, and it tends to land inside the throttle
2749
+ // of the read the blank screen before it triggered: dropped, nothing re-read the
2750
+ // screen and the session sat on the dialog for good (2 of 12 fresh launches on
2751
+ // Claude Code 2.1.294). A read already scheduled covers this one.
2752
+ if (!this._trustDialogTimer)
2753
+ this._rescanTrustDialogIn(TRUST_DIALOG_RETRY_MS - sinceScan + 100);
2659
2754
  return;
2755
+ }
2660
2756
  this._lastTrustDialogScanAt = now;
2661
2757
  // Prefer the pane; fall back to the buffer tail on a direct-PTY session,
2662
2758
  // where there is no screen to read.
@@ -2686,15 +2782,17 @@ export class Session extends EventEmitter {
2686
2782
  // on a live 2.1.252 spawn: cursor moved at 6 s, then nothing). The timer is
2687
2783
  // one-shot and self-rearming through this same path, and every exit route
2688
2784
  // goes through _clearAllTimers().
2689
- // The +100ms puts the re-entry OUTSIDE the scan throttle above; firing at
2690
- // exactly the throttle boundary would let the scan return early and break
2691
- // the chain with the dialog still on screen.
2785
+ // The +100ms puts the re-entry OUTSIDE the scan throttle above.
2786
+ this._rescanTrustDialogIn(TRUST_DIALOG_RETRY_MS + 100);
2787
+ }
2788
+ /** Re-run the trust-dialog scan after `delayMs`, replacing any read already scheduled. */
2789
+ _rescanTrustDialogIn(delayMs) {
2692
2790
  if (this._trustDialogTimer)
2693
2791
  clearTimeout(this._trustDialogTimer);
2694
2792
  this._trustDialogTimer = setTimeout(() => {
2695
2793
  this._trustDialogTimer = null;
2696
2794
  this._maybeAcceptTrustDialog();
2697
- }, TRUST_DIALOG_RETRY_MS + 100);
2795
+ }, delayMs);
2698
2796
  }
2699
2797
  /**
2700
2798
  * Per-chunk working/idle detection for an interactive pane. Split out of the
@@ -2768,10 +2866,29 @@ export class Session extends EventEmitter {
2768
2866
  return this._lastPaneProbeWorking;
2769
2867
  this._lastPaneProbeAt = now;
2770
2868
  const text = this._mux.capturePaneText?.(this._muxSession.muxName) ?? null;
2869
+ // A dialog the CLI is blocked on is not work, whatever else is on screen: codex's
2870
+ // question dialog carries `esc to interrupt` in its own key hints, which is codex's
2871
+ // working line, so without this a session waiting on the user's answer read as busy.
2872
+ // Decided from THIS capture, never from `_screenBlocked`, which lags a vanished dialog
2873
+ // by design (see `_noteBlockedReading`) and would otherwise call a resumed turn idle.
2874
+ const blockedOnScreen = text === null ? null : this._paneShowsBlocked(text);
2875
+ this._noteBlockedReading(blockedOnScreen, text);
2771
2876
  // A turn that ended by handing off to workers the CLI waits for is work too: the
2772
2877
  // composer is up and the pane is quiet, but the next turn starts without the user.
2773
2878
  this._lastPaneProbeWorking =
2774
- text === null ? null : this._workingLinePattern().test(text) || this._paneAwaitsWorkers(text);
2879
+ text === null
2880
+ ? null
2881
+ : !blockedOnScreen && (this._workingLinePattern().test(text) || this._paneAwaitsWorkers(text));
2882
+ // A capture that failed proves nothing either way, so it keeps the last answer.
2883
+ if (text !== null) {
2884
+ const trustDialog = isTrustDialogScreen(text);
2885
+ if (trustDialog &&
2886
+ !this._lastPaneProbeTrustDialog &&
2887
+ now - this._interactiveStartedAt <= TRUST_DIALOG_WINDOW_MS) {
2888
+ console.log(`[Session] Holding idle while the workspace trust dialog is on screen: ${this.id}`);
2889
+ }
2890
+ this._lastPaneProbeTrustDialog = trustDialog;
2891
+ }
2775
2892
  this._readWatching(text);
2776
2893
  this._readScreenModel(text);
2777
2894
  return this._lastPaneProbeWorking;
@@ -2963,6 +3080,109 @@ export class Session extends EventEmitter {
2963
3080
  const glyph = getCli(this.mode)?.capabilities.workDetect?.promptGlyph ?? '❯';
2964
3081
  return isAwaitingWorkers(paneText, this._awaitingLineRe, glyph);
2965
3082
  }
3083
+ /**
3084
+ * The regex matching the dialog this CLI blocks on, or null for a CLI whose registry
3085
+ * entry declares none (every CLI but codex today, Claude included: its dialogs arrive
3086
+ * as hook events). Compiled once per session through `compileVersionRegex()`, the same
3087
+ * guard the schema applies, so a pattern it refuses yields null rather than a throw.
3088
+ */
3089
+ _blockedLinePattern() {
3090
+ if (this._blockedLineRe === undefined) {
3091
+ const detect = getCli(this.mode)?.capabilities.workDetect;
3092
+ this._blockedLineRe = detect?.blockedLine ? compileVersionRegex(detect.blockedLine) : null;
3093
+ this._blockedWindow = detect?.blockedLines ?? BLOCKED_TAIL_LINES;
3094
+ }
3095
+ return this._blockedLineRe;
3096
+ }
3097
+ /** Whether this capture shows a dialog the CLI is blocked on. See `isBlockedScreen()`. */
3098
+ _paneShowsBlocked(paneText) {
3099
+ const pattern = this._blockedLinePattern();
3100
+ return pattern ? isBlockedScreen(paneText, pattern, this._blockedWindow) : false;
3101
+ }
3102
+ /**
3103
+ * Fold one screen reading into the blocked state, announcing each transition with
3104
+ * `blockedChanged` (the web server turns it into the alert and the `blocked` signal).
3105
+ *
3106
+ * The two directions are deliberately unequal:
3107
+ * - RAISE on one reading. A match needs the dialog's own footer at the foot of the
3108
+ * screen, which is only there when the dialog is fully drawn.
3109
+ * - CLEAR on BLOCKED_CLEAR_READS readings in a row. A single capture can land inside a
3110
+ * full-frame repaint, and clearing on it would re-raise a moment later and send the
3111
+ * alert, push and webhook twice for one dialog.
3112
+ * A capture that could not be read (`null`) is no evidence either way and changes
3113
+ * nothing, so a tmux hiccup can neither raise nor drop an alert. That is the opposite
3114
+ * of `_readWatching`, and for the same reason: each degrades toward the alert.
3115
+ *
3116
+ * While blocked, `_blockedRecheckTimer` keeps reading, since answering resumes the turn
3117
+ * and a busy pane never reaches the settle path that raised it.
3118
+ *
3119
+ * @param frame the capture the reading came from; rides the raise as the alert's context
3120
+ */
3121
+ _noteBlockedReading(onScreen, frame) {
3122
+ if (onScreen === null || !this._blockedLinePattern())
3123
+ return;
3124
+ if (onScreen) {
3125
+ this._blockedGoneReads = 0;
3126
+ // Stamped after the capture returned: output processed later is newer than it.
3127
+ this._blockedSeenAt = Date.now();
3128
+ if (!this._screenBlocked) {
3129
+ this._screenBlocked = true;
3130
+ this.emit('blockedChanged', true, frame);
3131
+ }
3132
+ this._armBlockedRecheck();
3133
+ return;
3134
+ }
3135
+ if (!this._screenBlocked)
3136
+ return;
3137
+ if (++this._blockedGoneReads < BLOCKED_CLEAR_READS) {
3138
+ this._armBlockedRecheck();
3139
+ return;
3140
+ }
3141
+ this._clearScreenBlocked();
3142
+ }
3143
+ /** (Re)arm the while-blocked screen read. One-shot and self-rearming, like the trust scan. */
3144
+ _armBlockedRecheck() {
3145
+ if (this._blockedRecheckTimer)
3146
+ clearTimeout(this._blockedRecheckTimer);
3147
+ this._blockedRecheckTimer = setTimeout(() => {
3148
+ this._blockedRecheckTimer = null;
3149
+ // No pane left to read (detached): nothing can change until a re-attach, whose
3150
+ // `_resetBuffers()` clears the state and whose repaint reads the screen afresh.
3151
+ if (this._isStopped || !this._screenBlocked || !this._mux?.capturePaneText || !this._muxSession)
3152
+ return;
3153
+ // A dialog leaves the screen only through a repaint, and tmux sends every repaint
3154
+ // to this client as PTY output (`_markActivity`). So while the last reading saw
3155
+ // the dialog and nothing has been drawn since, it is still up: skip the capture
3156
+ // (synchronous, see BLOCKED_QUIET_RECHECK_MS) and look again next interval. Never
3157
+ // once a reading has missed it: the confirming read must happen on a quiet pane
3158
+ // too, or the clear would wait for output that may never come.
3159
+ if (this._blockedGoneReads === 0 &&
3160
+ this._lastActivityAt < this._blockedSeenAt &&
3161
+ Date.now() - this._blockedSeenAt < BLOCKED_QUIET_RECHECK_MS) {
3162
+ this._armBlockedRecheck();
3163
+ return;
3164
+ }
3165
+ const text = this._mux.capturePaneText(this._muxSession.muxName) ?? null;
3166
+ // Unreadable this time: keep the state, keep looking (_noteBlockedReading ignores a null).
3167
+ if (text === null) {
3168
+ this._armBlockedRecheck();
3169
+ return;
3170
+ }
3171
+ this._noteBlockedReading(this._paneShowsBlocked(text), text);
3172
+ }, BLOCKED_RECHECK_MS);
3173
+ }
3174
+ /** Drop the blocked state (and its timer), announcing it when it was set. */
3175
+ _clearScreenBlocked() {
3176
+ this._blockedGoneReads = 0;
3177
+ if (this._blockedRecheckTimer) {
3178
+ clearTimeout(this._blockedRecheckTimer);
3179
+ this._blockedRecheckTimer = null;
3180
+ }
3181
+ if (!this._screenBlocked)
3182
+ return;
3183
+ this._screenBlocked = false;
3184
+ this.emit('blockedChanged', false, null);
3185
+ }
2966
3186
  /**
2967
3187
  * The regex matching this CLI's "a turn is running" status line.
2968
3188
  *
@@ -3023,6 +3243,16 @@ export class Session extends EventEmitter {
3023
3243
  this.activityTimeout = setTimeout(() => this._confirmIdle(), PANE_PROBE_RECHECK_MS);
3024
3244
  return;
3025
3245
  }
3246
+ // ⚠️ The workspace-trust dialog is not a composer, although its `❯` (on "No, exit")
3247
+ // arms this check and the dialog sits quiet. Calling it idle let an agent that waited
3248
+ // for idle send its prompt into the dialog, and the prompt's Enter answered *exit*.
3249
+ // Not working either, so the status stays where it is until the dialog is gone.
3250
+ // Bounded by the auto-accept's own startup window: later on, a screen that merely
3251
+ // quotes the dialog (an agent reading session-trust-dialog.ts) must not hold idle off.
3252
+ if (this._lastPaneProbeTrustDialog && Date.now() - this._interactiveStartedAt <= TRUST_DIALOG_WINDOW_MS) {
3253
+ this.activityTimeout = setTimeout(() => this._confirmIdle(), PANE_PROBE_RECHECK_MS);
3254
+ return;
3255
+ }
3026
3256
  this._awaitingIdleConfirmation = false;
3027
3257
  this.activityTimeout = null;
3028
3258
  // Emit idle if either:
@@ -3462,6 +3692,9 @@ export class Session extends EventEmitter {
3462
3692
  // into a program that never enabled tracking.
3463
3693
  this._cliMouseModes.clear();
3464
3694
  this._syncCliMouseTracking();
3695
+ // Nor does it start inside a dialog. Announced, so a pending alert for the old
3696
+ // pane's dialog is resolved rather than left behind it.
3697
+ this._clearScreenBlocked();
3465
3698
  this._markActivity(true);
3466
3699
  }
3467
3700
  _clearAllTimers() {
@@ -3473,6 +3706,11 @@ export class Session extends EventEmitter {
3473
3706
  clearTimeout(this._trustDialogTimer);
3474
3707
  this._trustDialogTimer = null;
3475
3708
  }
3709
+ // Clear the while-blocked screen read (the state itself is left to its owner)
3710
+ if (this._blockedRecheckTimer) {
3711
+ clearTimeout(this._blockedRecheckTimer);
3712
+ this._blockedRecheckTimer = null;
3713
+ }
3476
3714
  // Clear activity timeout to prevent memory leak
3477
3715
  if (this.activityTimeout) {
3478
3716
  clearTimeout(this.activityTimeout);
@@ -3928,7 +4166,7 @@ export class Session extends EventEmitter {
3928
4166
  *
3929
4167
  * More reliable than direct PTY write for programmatic input, especially
3930
4168
  * with Claude CLI which uses Ink (React for terminals).
3931
- * Uses tmux `send-keys -l` to inject text + Enter.
4169
+ * Uses tmux to inject the text (one bracketed paste) + Enter.
3932
4170
  *
3933
4171
  * @param data - Input data with optional `\r` for Enter
3934
4172
  * @returns true if input was sent, false if no mux session or PTY