aicodeman 1.40.0 → 1.41.1

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 (351) hide show
  1. package/README.md +81 -13
  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 +227 -0
  7. package/dist/cli-agent.d.ts.map +1 -0
  8. package/dist/cli-agent.js +771 -0
  9. package/dist/cli-agent.js.map +1 -0
  10. package/dist/cli.d.ts +25 -1
  11. package/dist/cli.d.ts.map +1 -1
  12. package/dist/cli.js +103 -41
  13. package/dist/cli.js.map +1 -1
  14. package/dist/codeman-credentials.d.ts +27 -0
  15. package/dist/codeman-credentials.d.ts.map +1 -0
  16. package/dist/codeman-credentials.js +66 -0
  17. package/dist/codeman-credentials.js.map +1 -0
  18. package/dist/config/buffer-limits.d.ts +9 -0
  19. package/dist/config/buffer-limits.d.ts.map +1 -1
  20. package/dist/config/buffer-limits.js +9 -0
  21. package/dist/config/buffer-limits.js.map +1 -1
  22. package/dist/config/cli-registry/schema.d.ts +10 -0
  23. package/dist/config/cli-registry/schema.d.ts.map +1 -1
  24. package/dist/config/cli-registry/schema.js +15 -0
  25. package/dist/config/cli-registry/schema.js.map +1 -1
  26. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  27. package/dist/config/cli-registry/stock.js +47 -0
  28. package/dist/config/cli-registry/stock.js.map +1 -1
  29. package/dist/config/cli-registry/types.d.ts +47 -1
  30. package/dist/config/cli-registry/types.d.ts.map +1 -1
  31. package/dist/folder-listing.d.ts +94 -0
  32. package/dist/folder-listing.d.ts.map +1 -0
  33. package/dist/folder-listing.js +241 -0
  34. package/dist/folder-listing.js.map +1 -0
  35. package/dist/git-clone.d.ts.map +1 -1
  36. package/dist/git-clone.js +4 -0
  37. package/dist/git-clone.js.map +1 -1
  38. package/dist/hooks-config.d.ts +36 -16
  39. package/dist/hooks-config.d.ts.map +1 -1
  40. package/dist/hooks-config.js +45 -20
  41. package/dist/hooks-config.js.map +1 -1
  42. package/dist/html-view-capabilities.d.ts +54 -0
  43. package/dist/html-view-capabilities.d.ts.map +1 -0
  44. package/dist/html-view-capabilities.js +103 -0
  45. package/dist/html-view-capabilities.js.map +1 -0
  46. package/dist/image-watcher.d.ts.map +1 -1
  47. package/dist/image-watcher.js +6 -2
  48. package/dist/image-watcher.js.map +1 -1
  49. package/dist/mcp-server.d.ts +114 -0
  50. package/dist/mcp-server.d.ts.map +1 -0
  51. package/dist/mcp-server.js +917 -0
  52. package/dist/mcp-server.js.map +1 -0
  53. package/dist/mcp-sync-targets.d.ts +34 -0
  54. package/dist/mcp-sync-targets.d.ts.map +1 -0
  55. package/dist/mcp-sync-targets.js +55 -0
  56. package/dist/mcp-sync-targets.js.map +1 -0
  57. package/dist/mcp-sync.d.ts +7 -1
  58. package/dist/mcp-sync.d.ts.map +1 -1
  59. package/dist/mcp-sync.js +113 -6
  60. package/dist/mcp-sync.js.map +1 -1
  61. package/dist/mux-interface.d.ts +36 -1
  62. package/dist/mux-interface.d.ts.map +1 -1
  63. package/dist/remote-files.d.ts +37 -0
  64. package/dist/remote-files.d.ts.map +1 -1
  65. package/dist/remote-files.js +103 -0
  66. package/dist/remote-files.js.map +1 -1
  67. package/dist/remote-pane-history.d.ts +103 -0
  68. package/dist/remote-pane-history.d.ts.map +1 -0
  69. package/dist/remote-pane-history.js +258 -0
  70. package/dist/remote-pane-history.js.map +1 -0
  71. package/dist/remote-ssh-limiter.d.ts +16 -3
  72. package/dist/remote-ssh-limiter.d.ts.map +1 -1
  73. package/dist/remote-ssh-limiter.js +37 -6
  74. package/dist/remote-ssh-limiter.js.map +1 -1
  75. package/dist/session.d.ts +29 -1
  76. package/dist/session.d.ts.map +1 -1
  77. package/dist/session.js +63 -4
  78. package/dist/session.js.map +1 -1
  79. package/dist/subagent-watcher.d.ts.map +1 -1
  80. package/dist/subagent-watcher.js +29 -6
  81. package/dist/subagent-watcher.js.map +1 -1
  82. package/dist/tab-layout-legacy-order.d.ts.map +1 -1
  83. package/dist/tab-layout-legacy-order.js +72 -13
  84. package/dist/tab-layout-legacy-order.js.map +1 -1
  85. package/dist/tab-layout-service.d.ts +33 -2
  86. package/dist/tab-layout-service.d.ts.map +1 -1
  87. package/dist/tab-layout-service.js +102 -7
  88. package/dist/tab-layout-service.js.map +1 -1
  89. package/dist/tab-layout.d.ts +9 -0
  90. package/dist/tab-layout.d.ts.map +1 -1
  91. package/dist/tab-layout.js +15 -2
  92. package/dist/tab-layout.js.map +1 -1
  93. package/dist/templates/case-template.md +2 -0
  94. package/dist/tmux-manager.d.ts +76 -2
  95. package/dist/tmux-manager.d.ts.map +1 -1
  96. package/dist/tmux-manager.js +216 -40
  97. package/dist/tmux-manager.js.map +1 -1
  98. package/dist/tui/tui-client.d.ts +3 -17
  99. package/dist/tui/tui-client.d.ts.map +1 -1
  100. package/dist/tui/tui-client.js +3 -44
  101. package/dist/tui/tui-client.js.map +1 -1
  102. package/dist/types/session.d.ts +53 -0
  103. package/dist/types/session.d.ts.map +1 -1
  104. package/dist/types/session.js.map +1 -1
  105. package/dist/usage-telemetry.d.ts +44 -7
  106. package/dist/usage-telemetry.d.ts.map +1 -1
  107. package/dist/usage-telemetry.js +72 -7
  108. package/dist/usage-telemetry.js.map +1 -1
  109. package/dist/utils/index.d.ts +1 -0
  110. package/dist/utils/index.d.ts.map +1 -1
  111. package/dist/utils/index.js +1 -0
  112. package/dist/utils/index.js.map +1 -1
  113. package/dist/utils/process-exit-wait.d.ts +40 -0
  114. package/dist/utils/process-exit-wait.d.ts.map +1 -0
  115. package/dist/utils/process-exit-wait.js +68 -0
  116. package/dist/utils/process-exit-wait.js.map +1 -0
  117. package/dist/web/approval-inbox.d.ts +12 -0
  118. package/dist/web/approval-inbox.d.ts.map +1 -1
  119. package/dist/web/approval-inbox.js +1 -0
  120. package/dist/web/approval-inbox.js.map +1 -1
  121. package/dist/web/middleware/auth.d.ts.map +1 -1
  122. package/dist/web/middleware/auth.js +33 -0
  123. package/dist/web/middleware/auth.js.map +1 -1
  124. package/dist/web/paste-image-gc.d.ts +46 -6
  125. package/dist/web/paste-image-gc.d.ts.map +1 -1
  126. package/dist/web/paste-image-gc.js +106 -32
  127. package/dist/web/paste-image-gc.js.map +1 -1
  128. package/dist/web/ports/session-port.d.ts +8 -1
  129. package/dist/web/ports/session-port.d.ts.map +1 -1
  130. package/dist/web/public/admin-ui.js.gz +0 -0
  131. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  132. package/dist/web/public/app.24689381.js +43 -0
  133. package/dist/web/public/app.24689381.js.br +0 -0
  134. package/dist/web/public/app.24689381.js.gz +0 -0
  135. package/dist/web/public/approvals-ui.js +4 -0
  136. package/dist/web/public/approvals-ui.js.br +0 -0
  137. package/dist/web/public/approvals-ui.js.gz +0 -0
  138. package/dist/web/public/{constants.c0f8f9de.js → constants.17d77b65.js} +690 -35
  139. package/dist/web/public/constants.17d77b65.js.br +0 -0
  140. package/dist/web/public/constants.17d77b65.js.gz +0 -0
  141. package/dist/web/public/cron-ui.js.gz +0 -0
  142. package/dist/web/public/entrance-animations.js +490 -43
  143. package/dist/web/public/entrance-animations.js.br +0 -0
  144. package/dist/web/public/entrance-animations.js.gz +0 -0
  145. package/dist/web/public/gesture/gesture-codeman.js +112 -6
  146. package/dist/web/public/git-status-ui.js.gz +0 -0
  147. package/dist/web/public/home-sessions.js +2 -1
  148. package/dist/web/public/home-sessions.js.br +0 -0
  149. package/dist/web/public/home-sessions.js.gz +0 -0
  150. package/dist/web/public/host-wake-ui.js.gz +0 -0
  151. package/dist/web/public/i18n.9afd8e4d.js +2 -0
  152. package/dist/web/public/i18n.9afd8e4d.js.br +0 -0
  153. package/dist/web/public/i18n.9afd8e4d.js.gz +0 -0
  154. package/dist/web/public/image-input.9ed1d0d2.js +453 -0
  155. package/dist/web/public/image-input.9ed1d0d2.js.br +0 -0
  156. package/dist/web/public/image-input.9ed1d0d2.js.gz +0 -0
  157. package/dist/web/public/index.html +223 -46
  158. package/dist/web/public/index.html.br +0 -0
  159. package/dist/web/public/index.html.gz +0 -0
  160. package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
  161. package/dist/web/public/{keyboard-accessory.c1e7c7b7.js → keyboard-accessory.c458eea8.js} +115 -35
  162. package/dist/web/public/keyboard-accessory.c458eea8.js.br +0 -0
  163. package/dist/web/public/keyboard-accessory.c458eea8.js.gz +0 -0
  164. package/dist/web/public/mobile-handlers.0ef9c311.js.gz +0 -0
  165. package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
  166. package/dist/web/public/mobile-overview.js +11 -2
  167. package/dist/web/public/mobile-overview.js.br +0 -0
  168. package/dist/web/public/mobile-overview.js.gz +0 -0
  169. package/dist/web/public/mobile.2dff1580.css +1 -0
  170. package/dist/web/public/mobile.2dff1580.css.br +0 -0
  171. package/dist/web/public/mobile.2dff1580.css.gz +0 -0
  172. package/dist/web/public/{notification-manager.50bb87d8.js → notification-manager.feb82c04.js} +19 -2
  173. package/dist/web/public/notification-manager.feb82c04.js.br +0 -0
  174. package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
  175. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  176. package/dist/web/public/{panels-ui.4735dfc2.js → panels-ui.73ec0137.js} +87 -87
  177. package/dist/web/public/panels-ui.73ec0137.js.br +0 -0
  178. package/dist/web/public/panels-ui.73ec0137.js.gz +0 -0
  179. package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
  180. package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
  181. package/dist/web/public/readmymind-ui.js.gz +0 -0
  182. package/dist/web/public/reboot-restore-ui.js.gz +0 -0
  183. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  184. package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
  185. package/dist/web/public/session-lineage.js.gz +0 -0
  186. package/dist/web/public/{session-ui.f731602c.js → session-ui.dbc6819b.js} +33 -33
  187. package/dist/web/public/session-ui.dbc6819b.js.br +0 -0
  188. package/dist/web/public/session-ui.dbc6819b.js.gz +0 -0
  189. package/dist/web/public/settings-ui.81ac264e.js +97 -0
  190. package/dist/web/public/settings-ui.81ac264e.js.br +0 -0
  191. package/dist/web/public/settings-ui.81ac264e.js.gz +0 -0
  192. package/dist/web/public/spreadsheet-preview-worker.js +11 -0
  193. package/dist/web/public/spreadsheet-preview-worker.js.br +0 -0
  194. package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
  195. package/dist/web/public/{spreadsheet-preview.af82fa2f.js → spreadsheet-preview.75c751de.js} +1 -1
  196. package/dist/web/public/spreadsheet-preview.75c751de.js.br +0 -0
  197. package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
  198. package/dist/web/public/spreadsheet-xlsx-core.js +110 -0
  199. package/dist/web/public/spreadsheet-xlsx-core.js.br +0 -0
  200. package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
  201. package/dist/web/public/styles.900a28e4.css +1 -0
  202. package/dist/web/public/styles.900a28e4.css.br +0 -0
  203. package/dist/web/public/styles.900a28e4.css.gz +0 -0
  204. package/dist/web/public/{subagent-windows.e6ca799f.js → subagent-windows.07277a58.js} +7 -5
  205. package/dist/web/public/subagent-windows.07277a58.js.br +0 -0
  206. package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
  207. package/dist/web/public/sw.js +6 -2
  208. package/dist/web/public/sw.js.br +0 -0
  209. package/dist/web/public/sw.js.gz +0 -0
  210. package/dist/web/public/tab-layout-browser.2d6189f7.js +1 -0
  211. package/dist/web/public/tab-layout-browser.2d6189f7.js.br +0 -0
  212. package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
  213. package/dist/web/public/{tab-rail-resize.a5867793.js → tab-rail-resize.7157e0bd.js} +1 -1
  214. package/dist/web/public/tab-rail-resize.7157e0bd.js.br +0 -0
  215. package/dist/web/public/tab-rail-resize.7157e0bd.js.gz +0 -0
  216. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
  217. package/dist/web/public/terminal-split.js.gz +0 -0
  218. package/dist/web/public/terminal-tile.js +135 -38
  219. package/dist/web/public/terminal-tile.js.br +0 -0
  220. package/dist/web/public/terminal-tile.js.gz +0 -0
  221. package/dist/web/public/terminal-ui.858f5da5.js +2 -0
  222. package/dist/web/public/terminal-ui.858f5da5.js.br +0 -0
  223. package/dist/web/public/terminal-ui.858f5da5.js.gz +0 -0
  224. package/dist/web/public/tile-grid.js +769 -137
  225. package/dist/web/public/tile-grid.js.br +0 -0
  226. package/dist/web/public/tile-grid.js.gz +0 -0
  227. package/dist/web/public/ultracode-panel.js.gz +0 -0
  228. package/dist/web/public/ultracode-windows.js +9 -6
  229. package/dist/web/public/ultracode-windows.js.br +0 -0
  230. package/dist/web/public/ultracode-windows.js.gz +0 -0
  231. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  232. package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
  233. package/dist/web/public/vendor/fflate.min.js.gz +0 -0
  234. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  235. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  236. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  237. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  238. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  239. package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.gz +0 -0
  240. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js +4 -0
  241. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.br +0 -0
  242. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.gz +0 -0
  243. package/dist/web/public/vendor/xterm.css.gz +0 -0
  244. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  245. package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
  246. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  247. package/dist/web/public/webview-tabs.js +12 -0
  248. package/dist/web/public/webview-tabs.js.br +0 -0
  249. package/dist/web/public/webview-tabs.js.gz +0 -0
  250. package/dist/web/route-helpers.d.ts +8 -0
  251. package/dist/web/route-helpers.d.ts.map +1 -1
  252. package/dist/web/route-helpers.js +8 -0
  253. package/dist/web/route-helpers.js.map +1 -1
  254. package/dist/web/routes/admin-routes.d.ts.map +1 -1
  255. package/dist/web/routes/admin-routes.js +4 -1
  256. package/dist/web/routes/admin-routes.js.map +1 -1
  257. package/dist/web/routes/approval-routes.d.ts.map +1 -1
  258. package/dist/web/routes/approval-routes.js +6 -8
  259. package/dist/web/routes/approval-routes.js.map +1 -1
  260. package/dist/web/routes/case-routes.js +1 -1
  261. package/dist/web/routes/case-routes.js.map +1 -1
  262. package/dist/web/routes/cli-registry-routes.d.ts +23 -4
  263. package/dist/web/routes/cli-registry-routes.d.ts.map +1 -1
  264. package/dist/web/routes/cli-registry-routes.js +92 -7
  265. package/dist/web/routes/cli-registry-routes.js.map +1 -1
  266. package/dist/web/routes/file-routes.d.ts +46 -1
  267. package/dist/web/routes/file-routes.d.ts.map +1 -1
  268. package/dist/web/routes/file-routes.js +214 -27
  269. package/dist/web/routes/file-routes.js.map +1 -1
  270. package/dist/web/routes/hook-event-routes.d.ts.map +1 -1
  271. package/dist/web/routes/hook-event-routes.js +8 -1
  272. package/dist/web/routes/hook-event-routes.js.map +1 -1
  273. package/dist/web/routes/html-view-routes.d.ts +60 -0
  274. package/dist/web/routes/html-view-routes.d.ts.map +1 -0
  275. package/dist/web/routes/html-view-routes.js +288 -0
  276. package/dist/web/routes/html-view-routes.js.map +1 -0
  277. package/dist/web/routes/index.d.ts +1 -0
  278. package/dist/web/routes/index.d.ts.map +1 -1
  279. package/dist/web/routes/index.js +1 -0
  280. package/dist/web/routes/index.js.map +1 -1
  281. package/dist/web/routes/mcp-sync-routes.d.ts +7 -2
  282. package/dist/web/routes/mcp-sync-routes.d.ts.map +1 -1
  283. package/dist/web/routes/mcp-sync-routes.js +10 -3
  284. package/dist/web/routes/mcp-sync-routes.js.map +1 -1
  285. package/dist/web/routes/reboot-restore-routes.js +3 -3
  286. package/dist/web/routes/reboot-restore-routes.js.map +1 -1
  287. package/dist/web/routes/session-routes.d.ts +1 -0
  288. package/dist/web/routes/session-routes.d.ts.map +1 -1
  289. package/dist/web/routes/session-routes.js +345 -90
  290. package/dist/web/routes/session-routes.js.map +1 -1
  291. package/dist/web/routes/status-telemetry-routes.d.ts.map +1 -1
  292. package/dist/web/routes/status-telemetry-routes.js +16 -2
  293. package/dist/web/routes/status-telemetry-routes.js.map +1 -1
  294. package/dist/web/schemas.d.ts +32 -0
  295. package/dist/web/schemas.d.ts.map +1 -1
  296. package/dist/web/schemas.js +74 -0
  297. package/dist/web/schemas.js.map +1 -1
  298. package/dist/web/server.d.ts +7 -2
  299. package/dist/web/server.d.ts.map +1 -1
  300. package/dist/web/server.js +77 -24
  301. package/dist/web/server.js.map +1 -1
  302. package/dist/web/sse-events.d.ts +5 -2
  303. package/dist/web/sse-events.d.ts.map +1 -1
  304. package/dist/web/sse-events.js +5 -2
  305. package/dist/web/sse-events.js.map +1 -1
  306. package/package.json +5 -4
  307. package/skills/codeman/SKILL.md +30 -7
  308. package/README.zh-CN.md +0 -1147
  309. package/dist/web/public/app.abadc970.js +0 -43
  310. package/dist/web/public/app.abadc970.js.br +0 -0
  311. package/dist/web/public/app.abadc970.js.gz +0 -0
  312. package/dist/web/public/constants.c0f8f9de.js.br +0 -0
  313. package/dist/web/public/constants.c0f8f9de.js.gz +0 -0
  314. package/dist/web/public/i18n.a31747a9.js +0 -2
  315. package/dist/web/public/i18n.a31747a9.js.br +0 -0
  316. package/dist/web/public/i18n.a31747a9.js.gz +0 -0
  317. package/dist/web/public/image-input.898a538b.js +0 -281
  318. package/dist/web/public/image-input.898a538b.js.br +0 -0
  319. package/dist/web/public/image-input.898a538b.js.gz +0 -0
  320. package/dist/web/public/keyboard-accessory.c1e7c7b7.js.br +0 -0
  321. package/dist/web/public/keyboard-accessory.c1e7c7b7.js.gz +0 -0
  322. package/dist/web/public/mobile.111b187d.css +0 -1
  323. package/dist/web/public/mobile.111b187d.css.br +0 -0
  324. package/dist/web/public/mobile.111b187d.css.gz +0 -0
  325. package/dist/web/public/notification-manager.50bb87d8.js.br +0 -0
  326. package/dist/web/public/notification-manager.50bb87d8.js.gz +0 -0
  327. package/dist/web/public/panels-ui.4735dfc2.js.br +0 -0
  328. package/dist/web/public/panels-ui.4735dfc2.js.gz +0 -0
  329. package/dist/web/public/session-ui.f731602c.js.br +0 -0
  330. package/dist/web/public/session-ui.f731602c.js.gz +0 -0
  331. package/dist/web/public/settings-ui.a97ab16f.js +0 -97
  332. package/dist/web/public/settings-ui.a97ab16f.js.br +0 -0
  333. package/dist/web/public/settings-ui.a97ab16f.js.gz +0 -0
  334. package/dist/web/public/spreadsheet-preview.af82fa2f.js.br +0 -0
  335. package/dist/web/public/spreadsheet-preview.af82fa2f.js.gz +0 -0
  336. package/dist/web/public/styles.8ee12666.css +0 -1
  337. package/dist/web/public/styles.8ee12666.css.br +0 -0
  338. package/dist/web/public/styles.8ee12666.css.gz +0 -0
  339. package/dist/web/public/subagent-windows.e6ca799f.js.br +0 -0
  340. package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
  341. package/dist/web/public/tab-layout-browser.065fcba4.js +0 -1
  342. package/dist/web/public/tab-layout-browser.065fcba4.js.br +0 -0
  343. package/dist/web/public/tab-layout-browser.065fcba4.js.gz +0 -0
  344. package/dist/web/public/tab-rail-resize.a5867793.js.br +0 -0
  345. package/dist/web/public/tab-rail-resize.a5867793.js.gz +0 -0
  346. package/dist/web/public/terminal-ui.5059b30e.js +0 -2
  347. package/dist/web/public/terminal-ui.5059b30e.js.br +0 -0
  348. package/dist/web/public/terminal-ui.5059b30e.js.gz +0 -0
  349. package/dist/web/public/vendor/xterm-zerolag-input.bbb5f84c.js +0 -4
  350. package/dist/web/public/vendor/xterm-zerolag-input.bbb5f84c.js.br +0 -0
  351. package/dist/web/public/vendor/xterm-zerolag-input.bbb5f84c.js.gz +0 -0
@@ -283,12 +283,14 @@ Object.assign(CodemanApp.prototype, {
283
283
  wizardRect = wizardContent.getBoundingClientRect();
284
284
  }
285
285
 
286
- // Read tab rects for normal mode (only tabs that are actually needed)
286
+ // Read tab rects for normal mode (only tabs that are actually needed).
287
+ // Only a painted row is cached: a row a search or filter hid has no line
288
+ // (_paintedSessionTab), rather than one drawn from the viewport's corner.
287
289
  if (!wizardOpen) {
288
290
  for (const { agentId } of visibleSubagentWindows) {
289
291
  const parentSessionId = this.subagentParentMap.get(agentId);
290
292
  if (!parentSessionId || rects.has('tab:' + parentSessionId)) continue;
291
- const tab = document.querySelector(`.session-tab[data-id="${parentSessionId}"]`);
293
+ const tab = this._paintedSessionTab(parentSessionId);
292
294
  if (tab) rects.set('tab:' + parentSessionId, tab.getBoundingClientRect());
293
295
  }
294
296
  }
@@ -397,7 +399,7 @@ Object.assign(CodemanApp.prototype, {
397
399
 
398
400
  const tabRect = rects.get('tab:' + parentSessionId);
399
401
  if (!tabRect) {
400
- // Tab not in DOM (might be scrolled out or session closed)
402
+ // Tab not painted (session closed, collapsed group, or hidden by a search)
401
403
  continue;
402
404
  }
403
405
 
@@ -691,8 +693,8 @@ Object.assign(CodemanApp.prototype, {
691
693
  }
692
694
  }
693
695
 
694
- // Get parent TAB element for spawn animation
695
- const parentTab = parentSessionId ? document.querySelector(`.session-tab[data-id="${parentSessionId}"]`) : null;
696
+ // Get parent TAB element for spawn animation (a hidden row spawns normally)
697
+ const parentTab = this._paintedSessionTab(parentSessionId);
696
698
 
697
699
  // Create window element
698
700
  const win = document.createElement('div');
@@ -26,7 +26,7 @@
26
26
  // not the current one, so the old constant key meant that cleanup never deleted
27
27
  // anything — hashed assets from every release ever deployed accumulated in one
28
28
  // bucket until the origin hit its storage quota.
29
- const BUILD_ID = '56d036511286';
29
+ const BUILD_ID = '95cf4ad0cf5b';
30
30
  const CACHE_NAME = `codeman-${BUILD_ID}`;
31
31
 
32
32
  // Reverse-proxy base path: the worker is served at `<base>/sw.js`, so its own
@@ -48,7 +48,7 @@ const B = (p) => (p && p[0] === '/' ? SW_BASE + p : p);
48
48
  // handler caches every successful GET at runtime, but the precache warmed
49
49
  // nothing while looking like it did. Deriving it from the same manifest that
50
50
  // renames the files is the only thing that keeps the two from drifting again.
51
- const HASHED_ASSETS = ["styles.8ee12666.css", "mobile.111b187d.css", "constants.c0f8f9de.js", "i18n.a31747a9.js", "mobile-handlers.0ef9c311.js", "voice-input.2342c37b.js", "notification-manager.50bb87d8.js", "keyboard-accessory.c1e7c7b7.js", "input-cjk.8bc46081.js", "mobile-ime-preview.2dbaf262.js", "terminal-keycode229-recovery.af09f99a.js", "sanitize-html.e7147e76.js", "tab-layout-browser.065fcba4.js", "app.abadc970.js", "tab-rail-resize.a5867793.js", "terminal-ui.5059b30e.js", "respawn-ui.ff0dae4c.js", "ralph-panel.b350e2ef.js", "settings-ui.a97ab16f.js", "panels-ui.4735dfc2.js", "session-ui.f731602c.js", "ralph-wizard.b6c0dd19.js", "api-client.c9b1cddc.js", "subagent-windows.e6ca799f.js", "image-input.898a538b.js", "spreadsheet-preview.af82fa2f.js", "vendor/xterm-zerolag-input.bbb5f84c.js", "vendor/xterm-predictive-echo.ae5e3d5d.js"];
51
+ const HASHED_ASSETS = ["styles.900a28e4.css", "mobile.2dff1580.css", "constants.17d77b65.js", "i18n.9afd8e4d.js", "mobile-handlers.0ef9c311.js", "voice-input.2342c37b.js", "notification-manager.feb82c04.js", "keyboard-accessory.c458eea8.js", "input-cjk.8bc46081.js", "mobile-ime-preview.2dbaf262.js", "terminal-keycode229-recovery.af09f99a.js", "sanitize-html.e7147e76.js", "tab-layout-browser.2d6189f7.js", "app.24689381.js", "tab-rail-resize.7157e0bd.js", "terminal-ui.858f5da5.js", "respawn-ui.ff0dae4c.js", "ralph-panel.b350e2ef.js", "settings-ui.81ac264e.js", "panels-ui.73ec0137.js", "session-ui.dbc6819b.js", "ralph-wizard.b6c0dd19.js", "api-client.c9b1cddc.js", "subagent-windows.07277a58.js", "image-input.9ed1d0d2.js", "spreadsheet-preview.75c751de.js", "vendor/xterm-zerolag-input.0b69623c.js", "vendor/xterm-predictive-echo.ae5e3d5d.js"];
52
52
 
53
53
  // Core app shell -- cached on install for instant startup
54
54
  const APP_SHELL = [
@@ -101,6 +101,10 @@ self.addEventListener('fetch', (event) => {
101
101
  if (request.headers.get('upgrade') === 'websocket') return;
102
102
  if (request.headers.get('accept') === 'text/event-stream') return;
103
103
  if (request.url.includes('/api/')) return;
104
+ // A rendered HTML page is served `no-store` behind a capability that logout
105
+ // revokes; caching a popped-out page here would let the offline fallback
106
+ // serve it after the capability is gone.
107
+ if (request.url.includes('/html-view/')) return;
104
108
 
105
109
  event.respondWith(
106
110
  fetch(request)
Binary file
Binary file
@@ -0,0 +1 @@
1
+ "use strict";(function(Y){"use strict";const K="codeman:tab-groups-collapsed",H="codeman:tab-focus-collapsed",c=t=>`${t.kind}:${t.id}`,R=t=>!!t&&(t.kind==="session"||t.kind==="webview")&&typeof t.id=="string"&&t.id.length>0,_=t=>Array.isArray(t)?t.filter(n=>typeof n=="string"&&n):[],G=t=>[...new Set(_(t))],E=t=>{const n={kind:t.kind,id:t.id};return t.placement==="manual"&&(n.placement="manual"),t.focus===!0&&(n.focus=!0),n},X=t=>Array.isArray(t)?t.filter(R).map(E):[];function m(t){if(!t||typeof t!="object")throw new Error("Invalid tab layout");const n=Array.isArray(t.groups)?t.groups:[];return{version:Number.isSafeInteger(t.version)&&t.version>=0?t.version:0,updatedAt:typeof t.updatedAt=="string"?t.updatedAt:"",groups:n.filter(e=>e&&typeof e.id=="string"&&e.id.length>0).map(e=>({id:e.id,name:typeof e.name=="string"?e.name:"",refs:X(e.refs)})),ungrouped:X(t.ungrouped)}}function U(t){return!!t&&Array.isArray(t.groups)&&t.groups.length>0}function Q(t){if(t===null)return[];try{const n=JSON.parse(t);return Array.isArray(n)?G(n):null}catch{return null}}function Z(t,n){try{const e=Q(t.getItem(K)),r=e||[];if(n===void 0)return{ids:r,ok:!0};const o=new Set(G(n)),s=r.filter(a=>o.has(a));return(!e||s.length!==r.length)&&t.setItem(K,JSON.stringify(s)),{ids:s,ok:!0}}catch{return{ids:[],ok:!1}}}function ee(t){try{return{collapsed:t.getItem(H)==="true",ok:!0}}catch{return{collapsed:!1,ok:!1}}}function te(t,n){try{return t.setItem(H,n===!0?"true":"false"),{collapsed:n===!0,ok:!0}}catch{return{collapsed:!1,ok:!1}}}function B(t,n={}){if(!t)return[];const e=m(t),r=new Set(_(n.liveSessionIds)),o=new Set(_(n.openWebviewIds)),s=new Set,a=[];for(const i of[...e.groups.flatMap(u=>u.refs),...e.ungrouped]){if(i.focus!==!0||!(i.kind==="session"?r.has(i.id):o.has(i.id)))continue;const u=c(i);s.has(u)||(s.add(u),a.push({kind:i.kind,id:i.id}))}return a}function ne(t,n){const e=G(n);try{return t.setItem(K,JSON.stringify(e)),{ids:e,ok:!0}}catch{return{ids:[],ok:!1}}}function re(t,n={}){if(!t)return null;const e=m(t);if(!U(e))return null;const r=G(n.liveSessionIds),o=G(n.openWebviewIds),s=new Set(r),a=new Set(o),i=new Set(_(n.collapsedGroupIds)),u=n.activeWebviewId?`webview:${n.activeWebviewId}`:n.activeSessionId?`session:${n.activeSessionId}`:"",f=h=>h.kind==="session"?s.has(h.id):a.has(h.id),p=se(e,r,n.parents),d=new Set,y=[],b={},v={},l=[],g=(h,k,J)=>{const O=[],F=[];let V=0;for(const C of h){const M=c(C);if(d.has(M)||!f(C))continue;d.add(M),v[M]=k,V++;const W={kind:C.kind,id:C.id};if(J&&M!==u){b[M]=k,F.push(W);continue}O.push(W),y.push(W)}return{shown:O,hidden:F,count:V}};for(const h of e.groups){const k=i.has(h.id),{shown:J,hidden:O,count:F}=g(p(h.refs),h.id,k);l.push({id:h.id,name:h.name,refs:J,hidden:O,count:F,collapsed:k})}const S=[...r.map(h=>({kind:"session",id:h})),...o.map(h=>({kind:"webview",id:h}))],I=g([...p(e.ungrouped),...S],null,!1);return I.count>0&&l.push({id:null,name:"",refs:I.shown,hidden:[],count:I.count,collapsed:!1}),{sections:l,visibleRefs:y,hiddenTabGroupByRef:b,sectionByRef:v,focusRefs:B(e,n)}}const D={action:2,idle:1};function oe(t,n){const e={},r=t&&Array.isArray(t.sections)?t.sections:[];for(const o of r){if(o.id===null||!Array.isArray(o.hidden))continue;let s=null;for(const a of o.hidden){if(a.kind!=="session")continue;const i=n(a.id);D[i]&&(!s||D[i]>D[s])&&(s=i)}s&&(e[o.id]=s)}return e}function se(t,n,e){if(!e||typeof e!="object")return a=>a;const r=new Set(A(t).map(a=>c(a.ref))),o=new Set,s=new Map;for(let a=!0;a;){a=!1;for(const i of n){const u=`session:${i}`,f=e[i];if(r.has(u)||o.has(u)||typeof f!="string"||f===i)continue;const p=`session:${f}`;!r.has(p)&&!o.has(p)||(o.add(u),s.has(p)||s.set(p,[]),s.get(p).push({kind:"session",id:i}),a=!0)}}return s.size?a=>{const i=[...a];for(const[u,f]of s){const p=$(t,{kind:"session",id:u.slice(8)},e);let d=-1;i.forEach((y,b)=>{p.has(c(y))&&(d=b)}),d>=0&&i.splice(d+1,0,...f)}return i}:a=>a}function ae(t,n,e){return n?JSON.stringify({collapsed:G(e).sort(),sections:n.sections.map(r=>[r.id,r.name,r.count,r.refs.map(c),(r.hidden||[]).map(c)])}):null}function ie(t,n,e){return(t&&Array.isArray(t.sections)?t.sections:[]).map((o,s)=>{const a=o.refs.map(b=>n(b)).join("");if(o.id===null)return`<section class="tab-layout-group tab-layout-ungrouped" role="presentation" data-tab-group-id=""><div class="tab-layout-group-header tab-layout-ungrouped-header" aria-hidden="true"><span class="tab-layout-group-name">Ungrouped</span><span class="tab-layout-group-count">${o.count}</span></div><div class="tab-layout-group-refs" role="presentation">${a}</div></section>`;const i=e(o.id),u=`tab-layout-group-refs-${s}`,f=`tab-layout-group-name-${s}`,p=o.count===0,d=!o.collapsed&&!p,y=p?"":` aria-expanded="${d?"true":"false"}"`;return`<section class="tab-layout-group${o.collapsed?" tab-layout-group--collapsed":""}" role="presentation" data-tab-group-id="${i}"><div class="tab-layout-group-header tab-layout-group-toggle" role="treeitem" tabindex="-1" data-tab-group-header="${i}"${y}${d?` aria-owns="${u}"`:""} onclick="app.toggleTabGroupCollapsed(this.dataset.tabGroupHeader)" oncontextmenu="event.preventDefault(); app.openTabGroupMenu(event, this.dataset.tabGroupHeader)"><span class="tab-layout-group-chevron" aria-hidden="true"></span><span class="tab-layout-group-name" id="${f}" data-i18n-skip>${e(o.name)}</span><span class="tab-layout-group-count">${o.count}</span><span class="tab-layout-group-menu" aria-hidden="true" title="Group actions" onclick="event.stopPropagation(); app.openTabGroupMenu(event, this.closest('[data-tab-group-header]').dataset.tabGroupHeader)">&#x22EF;</span></div><div class="tab-layout-group-refs" id="${u}" ${d?`role="group" aria-labelledby="${f}"`:'role="presentation"'}>${a}</div></section>`}).join("")}function ue(t){const n=Number.isFinite(t.retryDelayMs)?t.retryDelayMs:5e3,e=Number.isFinite(t.maxRetryDelayMs)?t.maxRetryDelayMs:6e4,r=Number.isSafeInteger(t.maxRetries)?t.maxRetries:4;let o=0,s=!1,a=null,i=0;const u=()=>{a!==null&&t.cancelRetry&&t.cancelRetry(a),a=null},f=async()=>{if(s)return!1;const p=++o;u();try{const d=await t.fetchLayout();return s||p!==o?!1:(i=0,t.applyLayout(d),!0)}catch{if(s||p!==o)return!1;if(i++,t.applyFallback(),i<=r){const y=Math.min(e,n*2**(i-1));a=t.scheduleRetry(()=>f(),y)}return!1}};return{load:f,dispose(){s=!0,o++,u()}}}function w(t){throw new Error(`Tab layout edit failed: ${t}`)}const P=(t,n)=>Number.isInteger(t)?Math.max(0,Math.min(t,n)):n;function q(t){const n=typeof t=="string"?t.trim():"";return(!n||n.length>60)&&w("group name must be 1-60 characters"),n}function A(t){return[...t.groups.flatMap(n=>n.refs.map(e=>({groupId:n.id,ref:e}))),...t.ungrouped.map(n=>({groupId:null,ref:n}))]}function T(t,n){if(n===null)return t.ungrouped;const e=t.groups.find(r=>r.id===n);return e||w("unknown group"),e.refs}function $(t,n,e){const r=new Map(A(t).map(i=>[c(i.ref),i.ref])),o=new Map;for(const[i,u]of Object.entries(e||{})){const f=r.get(`session:${i}`);!f||f.placement==="manual"||!r.has(`session:${u}`)||(o.has(u)||o.set(u,[]),o.get(u).push(i))}const s=new Set,a=i=>{if(!s.has(i)&&(s.add(i),i.startsWith("session:")))for(const u of o.get(i.slice(8))||[])a(`session:${u}`)};return a(c(n)),s}function j(t,n,e){const r=m(t);if(!R(n)||n.kind!=="session")return null;const o=e?.[n.id];if(typeof o!="string"||!o||o===n.id)return null;const s=new Map(A(r).map(u=>[c(u.ref),u.ref])),a=s.get(c(n));if(!a)return null;if(!s.has(`session:${o}`))return{state:"dangling",parentId:o,canFollow:!1};const i=new Set([n.id]);for(let u=o;u&&s.has(`session:${u}`);u=e[u]){if(i.has(u))return{state:"cycle",parentId:o,canFollow:!1};i.add(u)}return a.placement==="manual"?{state:"manual",parentId:o,canFollow:!0}:{state:"inherited",parentId:o,canFollow:!1}}function z(t,n,e,r,o,s){const a=m(t),i=$(a,n,s),u=T(a,e).filter(p=>!i.has(c(p)));if(!r)return{groupId:e};const f=u.findIndex(p=>c(p)===c(r));return f<0?{groupId:e}:{groupId:e,index:o==="after"?f+1:f}}function le(t,n,e,r){const o=m(t);if(!n||!e)return null;if(n.type==="group"){const d=o.groups.findIndex(v=>v.id===n.groupId);if(d<0)return null;const y=e.type==="ungrouped"?null:e.groupId??null,b=y===null?o.groups.length-1:o.groups.findIndex(v=>v.id===y);return b<0||b===d?null:{type:"reorderGroup",groupId:n.groupId,index:b}}if(n.type!=="ref"||!R(n.ref))return null;const s=A(o).find(d=>c(d.ref)===c(n.ref));if(!s)return null;let a,i=null,u="before";if(e.type==="ref"&&R(e.ref)){if($(o,n.ref,r).has(c(e.ref)))return null;a=e.groupId??null,i=e.ref,u=e.placement==="after"?"after":"before"}else if(e.type==="group"){if(a=e.groupId??null,a===s.groupId)return null}else if(e.type==="ungrouped"){if(a=null,s.groupId===null)return null}else return null;if(a!==null&&!o.groups.some(d=>d.id===a))return null;const f=z(o,n.ref,a,i,u,r),p={type:"moveRef",ref:{kind:n.ref.kind,id:n.ref.id},groupId:f.groupId,...f.index===void 0?{}:{index:f.index},parents:r||{}};return x(L(o,p))===x(o)?null:p}function L(t,n){const e=m(t),r=n||{},o=e.groups.findIndex(s=>s.id===r.groupId);switch(r.type){case"createGroup":{(typeof r.id!="string"||!r.id)&&w("invalid group id");const s=q(r.name);return e.groups.some(a=>a.id===r.id)||(e.groups.length>=32&&w("group limit reached"),e.groups.splice(P(r.index,e.groups.length),0,{id:r.id,name:s,refs:[]})),e}case"renameGroup":return o<0&&w("unknown group"),e.groups[o].name=q(r.name),e;case"deleteGroup":{if(o<0)return e;const[s]=e.groups.splice(o,1);return e.ungrouped.push(...s.refs),e}case"reorderGroup":{o<0&&w("unknown group");const[s]=e.groups.splice(o,1);return e.groups.splice(P(r.index,e.groups.length),0,s),e}case"setFocus":{R(r.ref)||w("invalid row"),typeof r.focused!="boolean"&&w("invalid Focus state");const s=A(e).find(a=>c(a.ref)===c(r.ref));return s||w("unknown row"),r.focused?s.ref.focus=!0:delete s.ref.focus,e}case"moveRef":{R(r.ref)||w("invalid row");const s=c(r.ref);A(e).some(d=>c(d.ref)===s)||w("unknown row");const a=r.groupId??null;T(e,a);const i=$(e,r.ref,r.parents),u=A(e).filter(d=>i.has(c(d.ref))).map(d=>E(d.ref)),f=u.find(d=>c(d)===s);r.ref.kind==="session"&&r.parents?.[r.ref.id]&&(f.placement="manual"),u.sort((d,y)=>d===f?-1:y===f?1:0);for(const d of e.groups)d.refs=d.refs.filter(y=>!i.has(c(y)));e.ungrouped=e.ungrouped.filter(d=>!i.has(c(d)));const p=T(e,a);return p.splice(P(r.index,p.length),0,...u),e}case"followParent":{const s=j(e,r.ref,r.parents);if((!s||s.state==="dangling"||s.state==="cycle")&&w("no parent to follow"),s.state!=="manual")return e;const a=c(r.ref),i=l=>{if(c(l)!==a)return l;const g=E(l);return delete g.placement,g};for(const l of e.groups)l.refs=l.refs.map(i);e.ungrouped=e.ungrouped.map(i);const u=new Set;for(const l of $(e,r.ref,r.parents))u.add(l);const f=A(e).filter(l=>u.has(c(l.ref))).map(l=>E(l.ref));f.sort((l,g)=>c(l)===a?-1:c(g)===a?1:0);for(const l of e.groups)l.refs=l.refs.filter(g=>!u.has(c(g)));e.ungrouped=e.ungrouped.filter(l=>!u.has(c(l)));const p={kind:"session",id:s.parentId},d=A(e).find(l=>c(l.ref)===c(p)),y=T(e,d.groupId),b=$(e,p,r.parents);let v=-1;return y.forEach((l,g)=>{b.has(c(l))&&(v=g)}),y.splice(v+1,0,...f),e}default:return w(`unknown operation ${r.type}`)}}function x(t){const n=m(t);return JSON.stringify([n.groups,n.ungrouped])}function N(t,n){let e=m(t);const r=[];let o=0;for(const s of n)try{e=L(e,s),r.push(s)}catch{o++}return{layout:e,kept:r,dropped:o}}function de(t){let n=m(t.initialLayout),e=n,r=[],o=[],s=!1,a=null,i=!1;const u=t.schedule||(l=>setTimeout(l,0)),f=t.cancel||(l=>clearTimeout(l)),p=t.maxAttempts||3,d=l=>t.reportError?.(l),y=l=>t.applyLayout(m(e),l),b=()=>{a===null&&(a=u(v))};async function v(){if(a=null,i||s||r.length===0)return;s=!0,o=r,r=[];let l=!1,g=!1,S=!1;try{for(let I=0;I<p&&o.length;I++){const h=N(n,o);if(o=h.kept,h.dropped&&!g&&(g=!0,d("Tab groups changed elsewhere; part of your edit no longer applies.")),!o.length||x(h.layout)===x(n)){o=[];break}const k=await t.put({baseVersion:n.version,layout:h.layout});if(i)return;if(k?.ok&&k.layout)n=m(k.layout),o=[];else if(k?.status===409&&k.layout)n=m(k.layout);else if(k?.status===400&&t.fetchLayout&&!S){if(S=!0,n=m(await t.fetchLayout()),i)return}else throw new Error("Tab layout save failed")}o.length&&(l=!0,d("Tab groups kept changing elsewhere; your edit was not saved."))}catch{l=!0,d("Could not save tab groups.")}finally{if(o=[],s=!1,!i){const I=N(n,r);I.dropped&&!l&&!g&&d("Tab groups changed elsewhere; part of your edit no longer applies."),r=I.kept,e=I.layout,y({authoritative:!0}),l&&t.onFailure?.(),r.length?b():t.onSettled?.()}}}return{enqueue(l){return e=L(e,l),r.push(l),y({optimistic:!0}),b(),m(e)},restore(l){const g=N(e,Array.isArray(l)?l:[]);return!g.kept.length||x(g.layout)===x(e)?!1:(e=g.layout,r.push(...g.kept),y({optimistic:!0}),b(),!0)},adoptExternal(l){if(i||s)return!1;const g=m(l);if(g.version<n.version)return!1;n=g;const S=N(g,r);return S.dropped&&d("Tab groups changed elsewhere; part of your edit no longer applies."),r=S.kept,e=S.layout,y({authoritative:!0,external:!0}),!0},flush:v,isWriting:()=>s,hasPending:()=>s||r.length>0,pendingOperations:()=>JSON.parse(JSON.stringify([...o,...r])),baseVersion:()=>n.version,getLayout:()=>m(e),dispose(){i=!0,a!==null&&f(a),a=null,r=[]}}}Y.CodemanTabLayout={normalizeLayout:m,hasGroups:U,project:re,hiddenGroupAlerts:oe,structureKey:ae,renderProjection:ie,applyOperation:L,moveDestination:z,movingRefKeys:(t,n,e)=>[...$(m(t),n,e)],placementState:j,dropOperation:le,contentKey:x,createEditCoordinator:de,createLoadCoordinator:ue,loadCollapsedGroupIds:Z,saveCollapsedGroupIds:ne,focusRefs:B,loadFocusCollapsed:ee,saveFocusCollapsed:te,MAX_GROUPS:32}})(typeof window<"u"?window:globalThis);
@@ -1 +1 @@
1
- "use strict";Object.assign(CodemanApp.prototype,{_getTabRailMinimumTerminalWidth(){const t=this.terminal?._core?._renderService?.dimensions?.css?.cell?.width;return Number.isFinite(t)&&t>0?Math.ceil(t*40+24):420},_getTabRailBounds(){const t=document.querySelector(".main");return{viewportWidth:window.innerWidth,mainWidth:t?.clientWidth||window.innerWidth,minTerminalWidth:this._getTabRailMinimumTerminalWidth()}},_getCurrentTabRailWidth(){const t=Number.parseFloat(document.documentElement.style.getPropertyValue("--tab-rail-width"));if(Number.isFinite(t))return t;const e=document.getElementById("tabRail")?.getBoundingClientRect?.().width;return Number.isFinite(e)&&e>0?e:window.CodemanTabRail?.DEFAULT_WIDTH||256},readTabRailWidthSetting(){const t=document.getElementById("appSettingsTabRailWidth");return t?t.value==="custom"?Number(t.dataset.currentWidth)||this._getCurrentTabRailWidth():Number(t.value)||window.CodemanTabRail?.DEFAULT_WIDTH||256:this._getCurrentTabRailWidth()},syncTabRailWidthSetting(t){const e=document.getElementById("appSettingsTabRailWidth");if(!e)return;const i=Math.round(t);if(e.dataset.currentWidth=String(i),e.querySelector(`option[value="${i}"]`)){e.value=String(i);return}const n=e.querySelector('option[value="custom"]');n&&(n.textContent=`Custom (${i}px)`),e.value="custom"},_setTabRailWidth(t){const e=window.CodemanTabRail;if(!e)return 256;const i=e.resolveWidth({width:t}),a=this._getTabRailBounds(),n=e.resolveWidth({width:i,...a}),h=e.resolveWidth({width:e.MAX_WIDTH,...a}),r=document.documentElement;r.style.setProperty("--tab-rail-width",`${n}px`);const o=r.classList.contains("tab-rail-compact"),s=n<240;if(r.classList.toggle("tab-rail-compact",s),r.classList.toggle("tab-rail-tight",n<288),o!==s){const d=this._tallTabsEnabled;this.applyTabWrapSettings?.(),d!==void 0&&this._tallTabsEnabled!==d||this._fullRenderSessionTabs?.()}const l=document.getElementById("tabRailResizeHandle");return l&&(l.setAttribute("aria-valuemax",String(h)),l.setAttribute("aria-valuenow",String(n))),this.syncTabRailWidthSetting(i),n},_persistTabRailWidth(t){const e=this.loadAppSettingsFromStorage();e.tabRailWidth!==t&&(e.tabRailWidth=t,this.saveAppSettingsToStorage(e))},_claimTabRailResize(){this._tabRailResizeOwnsObserver=!0,clearTimeout(this._tabRailResizeWatchdog),clearTimeout(this._tabRailReleaseTimer),this._tabRailReleaseRaf&&cancelAnimationFrame(this._tabRailReleaseRaf),this._armTabRailResizeWatchdog(),this._resizeRaf&&cancelAnimationFrame(this._resizeRaf),this._resizeTimeout&&clearTimeout(this._resizeTimeout),this._resizeRaf=null,this._resizeTimeout=null},_armTabRailResizeWatchdog(){this._tabRailResizeWatchdog=setTimeout(()=>{if(this._tabRailResizeWatchdog=null,document.body.classList.contains("tab-rail-resizing")){this._armTabRailResizeWatchdog();return}this._tabRailResizeOwnsObserver=!1},1e3)},_releaseTabRailResize(){clearTimeout(this._tabRailResizeWatchdog),this._tabRailResizeWatchdog=null;const t=()=>{clearTimeout(this._tabRailReleaseTimer),this._tabRailReleaseTimer=null,this._tabRailReleaseRaf=null,this._tabRailResizeOwnsObserver=!1};typeof requestAnimationFrame=="function"?(this._tabRailReleaseRaf=requestAnimationFrame(()=>{this._tabRailReleaseRaf=requestAnimationFrame(t)}),this._tabRailReleaseTimer=setTimeout(t,250)):t()},_scheduleTabRailSettle(t,e=t){clearTimeout(this._tabRailSettleTimer),this._tabRailSettleTimer=setTimeout(async()=>{this._tabRailSettleTimer=null,this._persistTabRailWidth(e);try{this.activeSessionId&&this.sendResize?await this.sendResize(this.activeSessionId):this.syncTerminalGeometry?.(),this._updateConnectionLinesImmediate?.()}catch(i){console.warn("Failed to resize terminal after rail resize:",i)}finally{this._releaseTabRailResize()}},150)},_defaultTabRailWidth(){return document.documentElement.dataset.tabRailDetail!=="simple"?window.CodemanTabRail?.RICH_DEFAULT_WIDTH??320:window.CodemanTabRail?.DEFAULT_WIDTH??256},applyTabRailWidth(t={}){const i=this.loadAppSettingsFromStorage().tabRailWidth??this._defaultTabRailWidth(),a=window.CodemanTabRail?.resolveWidth({width:i})??256;t.settle&&this._claimTabRailResize();const n=this._setTabRailWidth(a);return t.persist!==!1&&i!==a&&this._persistTabRailWidth(a),t.settle&&this._scheduleTabRailSettle(n,a),n},_applyTabRailPointerWidth(t){const e=document.querySelector(".main");if(!e)return this._getCurrentTabRailWidth();const i=this._getCurrentTabRailWidth(),a=this._setTabRailWidth(t-e.getBoundingClientRect().left);let n=null;try{n=this.fitAddon?.proposeDimensions?.()}catch{}return n&&n.cols<40?this._setTabRailWidth(i):a},_queueTabRailPointerWidth(t){this._tabRailPendingClientX=t,!this._tabRailPointerRaf&&(this._tabRailPointerRaf=requestAnimationFrame(()=>{this._tabRailPointerRaf=null,this._tabRailDragWidth=this._applyTabRailPointerWidth(this._tabRailPendingClientX)}))},_finishTabRailDrag(t,e){if(!document.body.classList.contains("tab-rail-resizing"))return;this._tabRailPointerRaf&&(cancelAnimationFrame(this._tabRailPointerRaf),this._tabRailPointerRaf=null,this._tabRailDragWidth=this._applyTabRailPointerWidth(this._tabRailPendingClientX)),document.body.classList.remove("tab-rail-resizing");const i=document.getElementById("tabRailResizeShield");i&&(i.hidden=!0);try{t.hasPointerCapture?.(e)&&t.releasePointerCapture(e)}catch{}const a=window.CodemanTabRail?.resolveWidth({width:this._tabRailDragWidth})??this._tabRailDragWidth;this._scheduleTabRailSettle(this._tabRailDragWidth||this._getCurrentTabRailWidth(),a)},_onTabRailKeyDown(t){const e=window.CodemanTabRail?.resolveKeyboardWidth({key:t.key,shiftKey:t.shiftKey,currentWidth:this._getCurrentTabRailWidth(),defaultWidth:this._defaultTabRailWidth?.(),...this._getTabRailBounds()});if(e==null)return;t.preventDefault(),this._claimTabRailResize();const i=this._setTabRailWidth(e);this._scheduleTabRailSettle(i,window.CodemanTabRail.resolveWidth({width:e}))},initTabRailResize(){const t=document.getElementById("tabRailResizeHandle");if(!t||t.dataset.ready==="1")return;t.dataset.ready="1",this.applyTabRailWidth(),t.addEventListener("pointerdown",i=>{if(i.button!==0)return;i.preventDefault(),this.closeTabRailActionMenu(),this._claimTabRailResize(),this._tabRailDragWidth=this._getCurrentTabRailWidth(),this._tabRailPendingClientX=i.clientX,document.body.classList.add("tab-rail-resizing");const a=document.getElementById("tabRailResizeShield");a&&(a.hidden=!1);try{t.setPointerCapture(i.pointerId)}catch{document.body.classList.remove("tab-rail-resizing"),a&&(a.hidden=!0),this._releaseTabRailResize()}}),t.addEventListener("pointermove",i=>{t.hasPointerCapture?.(i.pointerId)&&this._queueTabRailPointerWidth(i.clientX)}),t.addEventListener("pointerup",i=>this._finishTabRailDrag(t,i.pointerId)),t.addEventListener("pointercancel",i=>this._finishTabRailDrag(t,i.pointerId)),t.addEventListener("lostpointercapture",i=>this._finishTabRailDrag(t,i.pointerId)),t.addEventListener("keydown",i=>this._onTabRailKeyDown(i)),t.addEventListener("dblclick",i=>{i.preventDefault(),this._claimTabRailResize();const a=this._defaultTabRailWidth?.()??(window.CodemanTabRail?.DEFAULT_WIDTH||256),n=this._setTabRailWidth(a);this._scheduleTabRailSettle(n,a)});let e=null;window.addEventListener("resize",()=>{clearTimeout(e),e=setTimeout(()=>{this.applyTabOrientation?.(),this.applyTabRailWidth({persist:!1})},100)})},closeTabRailActionMenu(t={}){const e=document.querySelector(".tab-rail-action-menu:not(.tab-layout-group-action-menu)"),i=this._tabRailActionMenuTrigger;e?.remove(),this._tabRailActionMenuOutside&&(document.removeEventListener("pointerdown",this._tabRailActionMenuOutside,!0),this._tabRailActionMenuOutside=null),this._tabRailActionMenuViewport&&(window.removeEventListener("resize",this._tabRailActionMenuViewport),this._tabRailActionMenuViewport=null),this._tabRailActionMenuTrigger=null,t.restoreFocus&&i?.focus?.()},openTabRailActionMenu(t,e){t.preventDefault(),t.stopPropagation(),this.closeTabRailActionMenu();const i=t.currentTarget,a=document.createElement("div");a.className="tab-rail-action-menu",a.setAttribute("role","menu"),a.setAttribute("aria-label","Session actions");const n=this.loadAppSettingsFromStorage(),h=[{label:"Session options",run:()=>this.openSessionOptions(e)},...this._tabRefMoveActions?.({kind:"session",id:e})||[],...(this.tabDetachButtonEnabled?.(n)??n.showTabDetachButton)||this.detachedSessions?.has(e)?[{label:"Open in a new window",run:()=>this.detachSession(e)}]:[],{label:"Close session",className:"danger",run:()=>this.requestCloseSession(e)}];for(const s of h){const l=document.createElement("button");l.type="button",l.setAttribute("role","menuitem"),l.textContent=s.label,s.className&&(l.className=s.className),l.addEventListener("click",()=>{this.closeTabRailActionMenu(),s.run()}),a.appendChild(l)}document.body.appendChild(a);const r=i.getBoundingClientRect(),o=a.getBoundingClientRect();a.style.left=`${Math.max(8,Math.min(r.right-o.width,window.innerWidth-o.width-8))}px`,a.style.top=`${Math.max(8,Math.min(r.bottom+4,window.innerHeight-o.height-8))}px`,this._tabRailActionMenuTrigger=i,this._tabRailActionMenuOutside=s=>{!a.contains(s.target)&&s.target!==i&&this.closeTabRailActionMenu()},document.addEventListener("pointerdown",this._tabRailActionMenuOutside,!0),this._tabRailActionMenuViewport=()=>this.closeTabRailActionMenu(),window.addEventListener("resize",this._tabRailActionMenuViewport,{once:!0}),a.addEventListener("keydown",s=>{const l=[...a.querySelectorAll("button")],d=l.indexOf(document.activeElement);if(s.key==="Escape")s.preventDefault(),this.closeTabRailActionMenu({restoreFocus:!0});else if(s.key==="ArrowDown"||s.key==="ArrowUp"){s.preventDefault();const c=s.key==="ArrowDown"?1:-1;l[(d+c+l.length)%l.length]?.focus()}}),a.querySelector("button")?.focus()}});
1
+ "use strict";Object.assign(CodemanApp.prototype,{_getTabRailMinimumTerminalWidth(){const t=this.terminal?._core?._renderService?.dimensions?.css?.cell?.width;return Number.isFinite(t)&&t>0?Math.ceil(t*40+24):420},_getTabRailBounds(){const t=document.querySelector(".main");return{viewportWidth:window.innerWidth,mainWidth:t?.clientWidth||window.innerWidth,minTerminalWidth:this._getTabRailMinimumTerminalWidth()}},_getCurrentTabRailWidth(){const t=Number.parseFloat(document.documentElement.style.getPropertyValue("--tab-rail-width"));if(Number.isFinite(t))return t;const e=document.getElementById("tabRail")?.getBoundingClientRect?.().width;return Number.isFinite(e)&&e>0?e:window.CodemanTabRail?.DEFAULT_WIDTH||256},readTabRailWidthSetting(){const t=document.getElementById("appSettingsTabRailWidth");return t?t.value==="custom"?Number(t.dataset.currentWidth)||this._getCurrentTabRailWidth():Number(t.value)||window.CodemanTabRail?.DEFAULT_WIDTH||256:this._getCurrentTabRailWidth()},syncTabRailWidthSetting(t){const e=document.getElementById("appSettingsTabRailWidth");if(!e)return;const i=Math.round(t);if(e.dataset.currentWidth=String(i),e.querySelector(`option[value="${i}"]`)){e.value=String(i);return}const n=e.querySelector('option[value="custom"]');n&&(n.textContent=`Custom (${i}px)`),e.value="custom"},_setTabRailWidth(t){const e=window.CodemanTabRail;if(!e)return 256;const i=e.resolveWidth({width:t}),a=this._getTabRailBounds(),n=e.resolveWidth({width:i,...a}),h=e.resolveWidth({width:e.MAX_WIDTH,...a}),o=document.documentElement;o.style.setProperty("--tab-rail-width",`${n}px`);const d=o.classList.contains("tab-rail-compact"),s=n<240;if(o.classList.toggle("tab-rail-compact",s),o.classList.toggle("tab-rail-tight",n<288),d!==s){const r=this._tallTabsEnabled;this.applyTabWrapSettings?.(),r!==void 0&&this._tallTabsEnabled!==r||this._fullRenderSessionTabs?.()}const l=document.getElementById("tabRailResizeHandle");return l&&(l.setAttribute("aria-valuemax",String(h)),l.setAttribute("aria-valuenow",String(n))),this.syncTabRailWidthSetting(i),n},_persistTabRailWidth(t){const e=this.loadAppSettingsFromStorage();e.tabRailWidth!==t&&(e.tabRailWidth=t,this.saveAppSettingsToStorage(e))},_claimTabRailResize(){this._tabRailResizeOwnsObserver=!0,clearTimeout(this._tabRailResizeWatchdog),clearTimeout(this._tabRailReleaseTimer),this._tabRailReleaseRaf&&cancelAnimationFrame(this._tabRailReleaseRaf),this._armTabRailResizeWatchdog(),this._resizeRaf&&cancelAnimationFrame(this._resizeRaf),this._resizeTimeout&&clearTimeout(this._resizeTimeout),this._resizeRaf=null,this._resizeTimeout=null},_armTabRailResizeWatchdog(){this._tabRailResizeWatchdog=setTimeout(()=>{if(this._tabRailResizeWatchdog=null,document.body.classList.contains("tab-rail-resizing")){this._armTabRailResizeWatchdog();return}this._tabRailResizeOwnsObserver=!1},1e3)},_releaseTabRailResize(){clearTimeout(this._tabRailResizeWatchdog),this._tabRailResizeWatchdog=null;const t=()=>{clearTimeout(this._tabRailReleaseTimer),this._tabRailReleaseTimer=null,this._tabRailReleaseRaf=null,this._tabRailResizeOwnsObserver=!1};typeof requestAnimationFrame=="function"?(this._tabRailReleaseRaf=requestAnimationFrame(()=>{this._tabRailReleaseRaf=requestAnimationFrame(t)}),this._tabRailReleaseTimer=setTimeout(t,250)):t()},_scheduleTabRailSettle(t,e=t){clearTimeout(this._tabRailSettleTimer),this._tabRailSettleTimer=setTimeout(async()=>{this._tabRailSettleTimer=null,this._persistTabRailWidth(e);try{this.activeSessionId&&this.sendResize?await this.sendResize(this.activeSessionId):this.syncTerminalGeometry?.(),this._updateConnectionLinesImmediate?.()}catch(i){console.warn("Failed to resize terminal after rail resize:",i)}finally{this._releaseTabRailResize()}},150)},_defaultTabRailWidth(){return document.documentElement.dataset.tabRailDetail!=="simple"?window.CodemanTabRail?.RICH_DEFAULT_WIDTH??320:window.CodemanTabRail?.DEFAULT_WIDTH??256},applyTabRailWidth(t={}){const i=this.loadAppSettingsFromStorage().tabRailWidth??this._defaultTabRailWidth(),a=window.CodemanTabRail?.resolveWidth({width:i})??256;t.settle&&this._claimTabRailResize();const n=this._setTabRailWidth(a);return t.persist!==!1&&i!==a&&this._persistTabRailWidth(a),t.settle&&this._scheduleTabRailSettle(n,a),n},_applyTabRailPointerWidth(t){const e=document.querySelector(".main");if(!e)return this._getCurrentTabRailWidth();const i=this._getCurrentTabRailWidth(),a=this._setTabRailWidth(t-e.getBoundingClientRect().left);let n=null;try{n=this.fitAddon?.proposeDimensions?.()}catch{}return n&&n.cols<40?this._setTabRailWidth(i):a},_queueTabRailPointerWidth(t){this._tabRailPendingClientX=t,!this._tabRailPointerRaf&&(this._tabRailPointerRaf=requestAnimationFrame(()=>{this._tabRailPointerRaf=null,this._tabRailDragWidth=this._applyTabRailPointerWidth(this._tabRailPendingClientX)}))},_finishTabRailDrag(t,e){if(!document.body.classList.contains("tab-rail-resizing"))return;this._tabRailPointerRaf&&(cancelAnimationFrame(this._tabRailPointerRaf),this._tabRailPointerRaf=null,this._tabRailDragWidth=this._applyTabRailPointerWidth(this._tabRailPendingClientX)),document.body.classList.remove("tab-rail-resizing");const i=document.getElementById("tabRailResizeShield");i&&(i.hidden=!0);try{t.hasPointerCapture?.(e)&&t.releasePointerCapture(e)}catch{}const a=window.CodemanTabRail?.resolveWidth({width:this._tabRailDragWidth})??this._tabRailDragWidth;this._scheduleTabRailSettle(this._tabRailDragWidth||this._getCurrentTabRailWidth(),a)},_onTabRailKeyDown(t){const e=window.CodemanTabRail?.resolveKeyboardWidth({key:t.key,shiftKey:t.shiftKey,currentWidth:this._getCurrentTabRailWidth(),defaultWidth:this._defaultTabRailWidth?.(),...this._getTabRailBounds()});if(e==null)return;t.preventDefault(),this._claimTabRailResize();const i=this._setTabRailWidth(e);this._scheduleTabRailSettle(i,window.CodemanTabRail.resolveWidth({width:e}))},initTabRailResize(){const t=document.getElementById("tabRailResizeHandle");if(!t||t.dataset.ready==="1")return;t.dataset.ready="1",this.applyTabRailWidth(),t.addEventListener("pointerdown",i=>{if(i.button!==0)return;i.preventDefault(),this.closeTabRailActionMenu(),this._claimTabRailResize(),this._tabRailDragWidth=this._getCurrentTabRailWidth(),this._tabRailPendingClientX=i.clientX,document.body.classList.add("tab-rail-resizing");const a=document.getElementById("tabRailResizeShield");a&&(a.hidden=!1);try{t.setPointerCapture(i.pointerId)}catch{document.body.classList.remove("tab-rail-resizing"),a&&(a.hidden=!0),this._releaseTabRailResize()}}),t.addEventListener("pointermove",i=>{t.hasPointerCapture?.(i.pointerId)&&this._queueTabRailPointerWidth(i.clientX)}),t.addEventListener("pointerup",i=>this._finishTabRailDrag(t,i.pointerId)),t.addEventListener("pointercancel",i=>this._finishTabRailDrag(t,i.pointerId)),t.addEventListener("lostpointercapture",i=>this._finishTabRailDrag(t,i.pointerId)),t.addEventListener("keydown",i=>this._onTabRailKeyDown(i)),t.addEventListener("dblclick",i=>{i.preventDefault(),this._claimTabRailResize();const a=this._defaultTabRailWidth?.()??(window.CodemanTabRail?.DEFAULT_WIDTH||256),n=this._setTabRailWidth(a);this._scheduleTabRailSettle(n,a)});let e=null;window.addEventListener("resize",()=>{clearTimeout(e),e=setTimeout(()=>{this.applyTabOrientation?.(),this.applyTabRailWidth({persist:!1})},100)})},closeTabRailActionMenu(t={}){const e=document.querySelector(".tab-rail-action-menu:not(.tab-layout-group-action-menu)"),i=this._tabRailActionMenuTrigger;e?.remove(),this._tabRailActionMenuOutside&&(document.removeEventListener("pointerdown",this._tabRailActionMenuOutside,!0),this._tabRailActionMenuOutside=null),this._tabRailActionMenuViewport&&(window.removeEventListener("resize",this._tabRailActionMenuViewport),this._tabRailActionMenuViewport=null),this._tabRailActionMenuTrigger=null,t.restoreFocus&&i?.focus?.()},openTabRailActionMenu(t,e){t.preventDefault(),t.stopPropagation(),this.closeTabRailActionMenu();const i=t.currentTarget,a=document.createElement("div");a.className="tab-rail-action-menu",a.setAttribute("role","menu"),a.setAttribute("aria-label","Session actions");const n=this.loadAppSettingsFromStorage(),h=[{label:"Session options",run:()=>this.openSessionOptions(e)},...this._tabRefFocusActions?.({kind:"session",id:e})||[],...this._tabRefMoveActions?.({kind:"session",id:e})||[],...this._tileGrid?.has?.(e)&&this._tileDetachAllowed?.()?[{label:"Open in a new window",run:()=>this.detachTile(e)}]:(this.tabDetachButtonEnabled?.(n)??n.showTabDetachButton)||this.detachedSessions?.has(e)?[{label:"Open in a new window",run:()=>this.detachSession(e)}]:[],{label:"Close session",className:"danger",run:()=>this.requestCloseSession(e)}];for(const s of h){if(s.note){const r=document.createElement("div");r.className="tab-rail-action-menu-note",r.setAttribute("role","none"),r.id="tabRailActionMenuNote",r.textContent=s.label,a.setAttribute("aria-describedby",r.id),a.appendChild(r);continue}const l=document.createElement("button");l.type="button",l.setAttribute("role","menuitem"),l.textContent=s.label,s.className&&(l.className=s.className),l.addEventListener("click",()=>{this.closeTabRailActionMenu(),s.run()}),a.appendChild(l)}document.body.appendChild(a);const o=i.getBoundingClientRect(),d=a.getBoundingClientRect();a.style.left=`${Math.max(8,Math.min(o.right-d.width,window.innerWidth-d.width-8))}px`,a.style.top=`${Math.max(8,Math.min(o.bottom+4,window.innerHeight-d.height-8))}px`,this._tabRailActionMenuTrigger=i,this._tabRailActionMenuOutside=s=>{!a.contains(s.target)&&s.target!==i&&this.closeTabRailActionMenu()},document.addEventListener("pointerdown",this._tabRailActionMenuOutside,!0),this._tabRailActionMenuViewport=()=>this.closeTabRailActionMenu(),window.addEventListener("resize",this._tabRailActionMenuViewport,{once:!0}),a.addEventListener("keydown",s=>{const l=[...a.querySelectorAll("button")],r=l.indexOf(document.activeElement);if(s.key==="Escape")s.preventDefault(),this.closeTabRailActionMenu({restoreFocus:!0});else if(s.key==="ArrowDown"||s.key==="ArrowUp"){s.preventDefault();const c=s.key==="ArrowDown"?1:-1;l[(r+c+l.length)%l.length]?.focus()}}),a.querySelector("button")?.focus()}});
@@ -11,21 +11,29 @@
11
11
  *
12
12
  * Deliberately plainer than the primary pane (this.terminal/this._ws in
13
13
  * terminal-ui.js): no local-echo overlay, no CJK IME textarea, no touch/mobile
14
- * handlers (a swipe on a touch screen pages nothing), no keyboard accessory
15
- * bar, and no SGR wheel forwarding to Claude's fullscreen renderer
16
- * (docs/tile-grid-plan.md follow-up 4). Built for wide screens; see
17
- * docs/split-pane-sessions-plan.md and docs/tile-grid-plan.md.
14
+ * handlers (a swipe on a touch screen pages nothing), and no keyboard
15
+ * accessory bar. Built for wide screens; see docs/split-pane-sessions-plan.md
16
+ * and docs/tile-grid-plan.md.
18
17
  *
19
18
  * What it does carry over from the primary pane, through the primary pane's
20
19
  * own code aimed at THIS pane (its terminal, its session, never the active
21
20
  * one):
22
- * - Hollow-buffer paging (#555): a CLI that draws in place (opencode on the
23
- * alternate screen, Claude's repaint mode) leaves the xterm no scrollback,
24
- * so the wheel pages the CLI's own transcript with PageUp/PageDown
25
- * (_maybePageCliTranscript) through the primary pane's gates, plus an
26
- * overflow-row discount for this pane's capture-before-resize load
27
- * (_localRows), and only while the viewport is on the live screen (a
28
- * wheel-down from those overflow rows is xterm's, and brings it home).
21
+ * - SGR wheel forwarding (_maybeForwardWheelToCli): Claude's fullscreen
22
+ * renderer scrolls its own transcript on SGR wheel reports, while this
23
+ * xterm holds only replayed repaint frames, so the wheel goes to the CLI
24
+ * as reports at the pointer's cell in this pane, through the primary
25
+ * pane's forwarding gate and its encoding (sgrWheelReports). Shift+wheel
26
+ * scrolls the local scrollback itself (_maybeScrollLocalOnShift), as the
27
+ * primary pane does, since xterm turns it into a horizontal no-op.
28
+ * - Hollow-buffer paging (#555): a CLI that draws in place (opencode and codex
29
+ * on the alternate screen, Claude's repaint mode) leaves the xterm no
30
+ * scrollback, so the wheel pages the CLI's own transcript with
31
+ * PageUp/PageDown (_maybePageCliTranscript) through the primary pane's gates
32
+ * and its pure gesture rules (CodemanTerminalInput.pageKeysForGesture), plus
33
+ * an overflow-row discount for this pane's capture-before-resize load
34
+ * (_localRows), only while the viewport is on the live screen (a wheel-down
35
+ * from those overflow rows is xterm's, and brings it home), and never while
36
+ * THIS pane's session has a dialog open.
29
37
  * - The desktop click report: a plain left-click hand-encoded as SGR while
30
38
  * the session's CLI has mouse tracking on (cliMouseTracking), for the modes
31
39
  * whose mouse DECSETs the server strips (_installClickListener), sent
@@ -42,8 +50,8 @@
42
50
  * Android tablet, or a large foldable unfolded in landscape, reaches.
43
51
  *
44
52
  * @dependency vendor/xterm.js, vendor/xterm-addon-fit.js
45
- * @dependency constants.js (window.CodemanTerminalFont, window.CodemanFetchDeadline, DEFAULT_SCROLLBACK, TERMINAL_TAIL_SIZE, TERMINAL_CHUNK_SIZE)
46
- * @dependency terminal-ui.js (codemanCurrentXtermTheme, codemanCurrentSkinIsLight, CodemanTerminalInput.shouldSuppressTerminalQueryResponse/isTerminalFocusOrMouseReport/wheelDeltaLines/pageKeysForTravel, app._shouldForwardWheelToApp/_localScrollbackIsHollow/_terminalViewportAtBottom/_handleDesktopTerminalClick)
53
+ * @dependency constants.js (window.CodemanTerminalFont, window.CodemanFetchDeadline, DEFAULT_SCROLLBACK, TERMINAL_TAIL_SIZE, SHELL_LOAD_BASE_QUERY, SHELL_LOAD_QUERY, TERMINAL_CHUNK_SIZE)
54
+ * @dependency terminal-ui.js (codemanCurrentXtermTheme, codemanCurrentSkinIsLight, CodemanTerminalInput.shouldSuppressTerminalQueryResponse/isTerminalFocusOrMouseReport/wheelDeltaLines/wheelDeltaWholeLines/sgrWheelReports/pageKeysForGesture, app._shouldForwardWheelToApp/_localScrollbackIsHollow/_terminalViewportAtBottom/_clientPointToCell/_handleDesktopTerminalClick, app.tabAlerts)
47
55
  * @dependency terminal-keycode229-recovery.js (window.CodemanKeyCode229Recovery, optional: absent, xterm's own textarea handling stands)
48
56
  * @loadorder 7.4 of 16, loaded after terminal-ui.js and before terminal-split.js
49
57
  */
@@ -198,9 +206,13 @@
198
206
  // flag, app._linkHovered, belongs to its terminal alone).
199
207
  this._linkHovered = false;
200
208
  this._onFocusIn = null;
201
- // Hollow-buffer paging (_maybePageCliTranscript): wheel travel short of a
202
- // whole page, carried to the next wheel event.
203
- this._pageKeyPending = 0;
209
+ // Hollow-buffer paging (_maybePageCliTranscript): the gesture in progress
210
+ // (travel short of a whole page, its direction and last event time), the
211
+ // state CodemanTerminalInput.pageKeysForGesture hands back.
212
+ this._pageKeyGesture = null;
213
+ // Shift+wheel travel short of a whole line, carried to the next wheel
214
+ // event (_maybeScrollLocalOnShift).
215
+ this._shiftScrollPending = 0;
204
216
  // Page keys waiting for the 40 ms flush, and its timer (_queueScrollBytes).
205
217
  this._scrollBytes = '';
206
218
  this._scrollFlushTimer = null;
@@ -234,6 +246,9 @@
234
246
 
235
247
  this.fitAddon = new FitAddon.FitAddon();
236
248
  this.terminal.loadAddon(this.fitAddon);
249
+ // OSC 52 clipboard writes from this pane's PTY, gated on THIS pane's
250
+ // buffer load so a replay never re-copies (terminal-ui.js).
251
+ global.app?._installOsc52Clipboard?.(this.terminal, () => this._bufferLoading);
237
252
  this.terminal.open(this.mountEl);
238
253
  this.fitAddon.fit();
239
254
 
@@ -761,8 +776,15 @@
761
776
  try {
762
777
  if (this._destroyed) return;
763
778
  const shell = this.sessionMode === 'shell';
764
- let query = shell ? `tail=${TERMINAL_TAIL_SIZE}` : 'full=1';
765
- if (this.boundedLoad && !shell) query = `full=1&tail=${TERMINAL_TAIL_SIZE}${this._historyLinesQuery()}`;
779
+ // A shell loads tmux's rendered history, bounded (SHELL_LOAD_QUERY,
780
+ // constants.js), never the raw byte recording; a grid tile bounds it
781
+ // by its own scrollback instead.
782
+ let query = shell ? SHELL_LOAD_QUERY : 'full=1';
783
+ if (this.boundedLoad) {
784
+ query = shell
785
+ ? `${SHELL_LOAD_BASE_QUERY}${this._historyLinesQuery()}`
786
+ : `full=1&tail=${TERMINAL_TAIL_SIZE}${this._historyLinesQuery()}`;
787
+ }
766
788
  this._loadAbort = controller;
767
789
  armDeadline(global.CodemanFetchDeadline?.terminalFetchDeadlineMs?.({ full: !shell }) ?? 45000);
768
790
  let payload;
@@ -1027,16 +1049,18 @@
1027
1049
 
1028
1050
  // Capture phase, because xterm's own wheel handler stopPropagation()s every
1029
1051
  // event it consumes, so a bubbling listener here would never see the wheel
1030
- // while the pane still has scrollback to scroll. Not passive: the one route
1031
- // this pane takes over, paging a hollow buffer's CLI transcript
1032
- // (_maybePageCliTranscript), is consumed right here (preventDefault plus
1052
+ // while the pane still has scrollback to scroll. Not passive: the three
1053
+ // routes this pane takes over, forwarding the wheel to Claude's fullscreen
1054
+ // renderer (_maybeForwardWheelToCli), paging a hollow buffer's CLI
1055
+ // transcript (_maybePageCliTranscript) and Shift+wheel's local scrollback
1056
+ // (_maybeScrollLocalOnShift), are consumed right here (preventDefault plus
1033
1057
  // stopPropagation in the capture phase, the primary pane's technique), so
1034
- // xterm's viewport, a descendant, never sees it. Every other wheel is left
1058
+ // xterm's viewport, a descendant, never sees them. Every other wheel is left
1035
1059
  // to xterm, which keeps doing the scrolling, and only observed for the
1036
1060
  // shell history pull.
1037
1061
  _installWheelListener() {
1038
1062
  this._onWheel = (ev) => {
1039
- if (this._maybePageCliTranscript(ev)) {
1063
+ if (this._maybeForwardWheelToCli(ev) || this._maybePageCliTranscript(ev) || this._maybeScrollLocalOnShift(ev)) {
1040
1064
  ev.preventDefault();
1041
1065
  ev.stopPropagation();
1042
1066
  return;
@@ -1046,6 +1070,71 @@
1046
1070
  this.mountEl.addEventListener('wheel', this._onWheel, { capture: true, passive: false });
1047
1071
  }
1048
1072
 
1073
+ // SGR wheel forwarding, the twin of the primary pane's capture-phase wheel
1074
+ // handler and _forwardScrollToApp (terminal-ui.js; keep them in step).
1075
+ // Claude's fullscreen renderer (claude 2.1.187+ while its mouse tracking is
1076
+ // on, cliMouseTracking) scrolls its own transcript on SGR wheel reports,
1077
+ // while this xterm holds only Codeman's replayed repaint frames (tmux keeps
1078
+ // no history for such a pane). Left to xterm, the wheel dragged those stale
1079
+ // frames, Claude's pinned input box with them, up the tile, or scrolled
1080
+ // nothing at all. The gate is the primary pane's own, asked for THIS pane
1081
+ // (its terminal, its session, never the active one), so the CLI rules stay
1082
+ // in terminal-ui.js and this file names no CLI; the reports go to this
1083
+ // pane's session through its own coalescer. Returns true when the wheel
1084
+ // belongs to the CLI: a gesture with no whole line or no measurable cell is
1085
+ // consumed too, as in the primary pane, so xterm never scrolls the stale
1086
+ // frames under a forwarding session. Shift fails the gate, so Shift+wheel
1087
+ // still scrolls the local scrollback (_maybeScrollLocalOnShift).
1088
+ _maybeForwardWheelToCli(ev) {
1089
+ if (this._destroyed || !this.terminal || !ev) return false;
1090
+ const app = global.app;
1091
+ const input = global.CodemanTerminalInput;
1092
+ if (!app?._shouldForwardWheelToApp || !input?.sgrWheelReports || !input.wheelDeltaWholeLines) return false;
1093
+ // xterm's own encoder forwards the wheel while the CLI's tracking reaches
1094
+ // it, and its alt-scroll owns the alternate buffer, as in the primary pane.
1095
+ const tracking = this.terminal.modes?.mouseTrackingMode;
1096
+ if (tracking && tracking !== 'none') return false;
1097
+ if (this.terminal.buffer?.active?.type === 'alternate') return false;
1098
+ if (!app._shouldForwardWheelToApp(ev, { terminal: this.terminal, sessionId: this.sessionId })) return false;
1099
+ // SGR coordinates address the live screen, so a report from a scrolled-up
1100
+ // viewport would hit-test another row: snap home first (_forwardScrollToApp).
1101
+ if (!app._terminalViewportAtBottom?.(this.terminal)) this.terminal.scrollToBottom?.();
1102
+ const lines = input.wheelDeltaWholeLines(ev, this.terminal.rows);
1103
+ const pos = app._clientPointToCell?.(ev.clientX, ev.clientY, this.terminal);
1104
+ const bytes = input.sgrWheelReports(lines, pos);
1105
+ if (bytes) this._queueScrollBytes(bytes);
1106
+ return true;
1107
+ }
1108
+
1109
+ // Shift+wheel scrolls this xterm's local scrollback, the explicit "local
1110
+ // history" gesture, here as in the primary pane (whose capture-phase wheel
1111
+ // handler scrolls with terminal.scrollLines() for the same reason). Left to
1112
+ // xterm it was dead off macOS: Chrome on Windows sends Shift+wheel as a
1113
+ // HORIZONTAL wheel (deltaX), and xterm's own scroller turns a Shift+vertical
1114
+ // wheel into a horizontal one, so the viewport never moved. Reads the
1115
+ // dominant axis under Shift (wheelDeltaLines), keeps the sub-line remainder
1116
+ // for the next event (a trackpad's small deltas), and on the way up still
1117
+ // asks a shell pane for more history. Returns true when the wheel was
1118
+ // consumed here.
1119
+ _maybeScrollLocalOnShift(ev) {
1120
+ if (this._destroyed || !this.terminal || !ev?.shiftKey) return false;
1121
+ const input = global.CodemanTerminalInput;
1122
+ if (!input?.wheelDeltaLines) return false;
1123
+ // xterm's own encoder forwards the wheel while the CLI's tracking reaches
1124
+ // it, and its alt-scroll owns the alternate buffer, as in the primary pane.
1125
+ const tracking = this.terminal.modes?.mouseTrackingMode;
1126
+ if (tracking && tracking !== 'none') return false;
1127
+ if (this.terminal.buffer?.active?.type === 'alternate') return false;
1128
+ const total = this._shiftScrollPending + input.wheelDeltaLines(ev, this.terminal.rows);
1129
+ const lines = Math.trunc(total);
1130
+ this._shiftScrollPending = total - lines;
1131
+ if (lines) {
1132
+ this.terminal.scrollLines(lines);
1133
+ if (lines < 0) this._maybeLoadMoreHistory();
1134
+ }
1135
+ return true;
1136
+ }
1137
+
1049
1138
  // A plain left-click reported to the CLI, the primary pane's desktop click
1050
1139
  // (terminal-ui.js _handleDesktopTerminalClick) aimed at this pane. The
1051
1140
  // server strips the mouse DECSETs of some modes (opencode's since #555, so a
@@ -1071,25 +1160,28 @@
1071
1160
 
1072
1161
  // Hollow-buffer paging, the twin of the primary pane's
1073
1162
  // _maybePageCliTranscript (terminal-ui.js; keep the two in step). A CLI that
1074
- // draws in place (opencode, on the alternate screen; Claude's repaint mode)
1075
- // leaves this xterm no scrollback, so a wheel scrolled nothing; instead the
1076
- // travel pages the CLI's own transcript with PageUp/PageDown. Every gate is
1077
- // the primary pane's own, asked for THIS pane (its terminal, its session,
1078
- // never the active one), so the CLI rules stay in terminal-ui.js and this
1079
- // file names no CLI. Returns true when the wheel was consumed here.
1163
+ // draws in place (on the alternate screen, or Claude's repaint mode) leaves
1164
+ // this xterm no scrollback, so a wheel scrolled nothing; instead the travel
1165
+ // pages the CLI's own transcript with PageUp/PageDown. Every gate is the
1166
+ // primary pane's own, asked for THIS pane (its terminal, its session, never
1167
+ // the active one), so the CLI rules stay in terminal-ui.js and this file
1168
+ // names no CLI. The gesture rules (first-event page, notch accumulation,
1169
+ // pinch and sideways-swipe consume) are the shared pure
1170
+ // CodemanTerminalInput.pageKeysForGesture, run on this tile's own state.
1171
+ // Returns true when the wheel was consumed here.
1080
1172
  _maybePageCliTranscript(ev) {
1081
1173
  if (this._destroyed || !this.terminal || !ev || ev.shiftKey) return false;
1082
1174
  const app = global.app;
1083
1175
  const input = global.CodemanTerminalInput;
1084
- if (!app || !input?.pageKeysForTravel || !input.wheelDeltaLines) return false;
1176
+ if (!app || !input?.pageKeysForGesture || !input.wheelDeltaLines) return false;
1085
1177
  // xterm's own encoder forwards the wheel while the CLI's tracking reaches
1086
1178
  // it (a shell running htop), as in the primary pane.
1087
1179
  const tracking = this.terminal.modes?.mouseTrackingMode;
1088
1180
  if (tracking && tracking !== 'none') return false;
1089
1181
  const target = { terminal: this.terminal, sessionId: this.sessionId };
1090
- // The primary pane would forward this wheel to Claude's fullscreen
1091
- // renderer as SGR reports. Tiles do not do that yet (docs/tile-grid-plan.md
1092
- // follow-up 4), so the wheel stays with xterm, as before.
1182
+ // A wheel for Claude's fullscreen renderer was forwarded as SGR reports
1183
+ // before this ran (_maybeForwardWheelToCli); the gate is repeated so a
1184
+ // forwarding session is never paged.
1093
1185
  if (app._shouldForwardWheelToApp?.(ev, target)) return false;
1094
1186
  if (!app._localScrollbackIsHollow?.({ ...target, localRows: this._localRows() })) return false;
1095
1187
  // Only from the live screen. The one gate the primary pane never needs: a
@@ -1105,14 +1197,19 @@
1105
1197
  if (!app._terminalViewportAtBottom?.(this.terminal)) return false;
1106
1198
  const lines = input.wheelDeltaLines(ev, this.terminal.rows);
1107
1199
  if (!lines) return false;
1108
- const step = input.pageKeysForTravel(this._pageKeyPending, lines, this.terminal.rows);
1109
- this._pageKeyPending = step.pending;
1200
+ // An open dialog (a pending permission prompt or question) in THIS tile's
1201
+ // session, which is usually not the active one: a page key would move its
1202
+ // selector. Consumed, so xterm does not scroll the rows under it either.
1203
+ if (app.tabAlerts?.get(this.sessionId) === 'action') return true;
1204
+ const step = input.pageKeysForGesture(this._pageKeyGesture, ev, lines, this.terminal.rows, performance.now());
1205
+ this._pageKeyGesture = step.state;
1110
1206
  if (step.keys) this._queueScrollBytes(step.keys);
1111
1207
  return true;
1112
1208
  }
1113
1209
 
1114
- // Coalesces the page keys into one send per 40 ms, bounded at 512 bytes so a
1115
- // fling cannot build a backlog that keeps paging after it stops. A narrow
1210
+ // Coalesces the scroll bytes (SGR wheel reports and page keys alike) into
1211
+ // one send per 40 ms, bounded at 512 bytes so a fling cannot build a backlog
1212
+ // that keeps scrolling after it stops. A narrow
1116
1213
  // twin of the primary pane's _queueScrollBytes / _flushWheelSgrQueue
1117
1214
  // (terminal-ui.js; keep the two in step), which flushes to the active
1118
1215
  // session only. Sent ephemeral (no seq, never persisted) to THIS pane's
@@ -1459,7 +1556,7 @@
1459
1556
  clearTimeout(this._scrollFlushTimer);
1460
1557
  this._scrollFlushTimer = null;
1461
1558
  this._scrollBytes = '';
1462
- this._pageKeyPending = 0;
1559
+ this._pageKeyGesture = null;
1463
1560
  this._detachSocket();
1464
1561
  if (this._onFocusIn) {
1465
1562
  this.terminal?.textarea?.removeEventListener('focus', this._onFocusIn);
Binary file
Binary file