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
@@ -0,0 +1,453 @@
1
+ /**
2
+ * Image Input Mixin - Clipboard paste and drag-and-drop image support
3
+ *
4
+ * For paste: intercepts Ctrl+V at the xterm keyboard level, creates a temporary
5
+ * hidden contenteditable div ("paste trap"), lets the browser's native paste fill
6
+ * it, then checks for image data. This works on HTTP (no secure context needed).
7
+ *
8
+ * For drag-and-drop: listens on the terminal container for file drops.
9
+ *
10
+ * @dependency app.js (uses global `app` for sendInput, activeSessionId, showToast)
11
+ * @dependency panels-ui.js (provides showToast)
12
+ */
13
+
14
+ Object.assign(CodemanApp.prototype, {
15
+
16
+ initImageInput() {
17
+ // Phone toolbar Attach (index.html): the tap lands on the file INPUT, which
18
+ // sits invisibly over the button, and the browser opens the picker itself.
19
+ //
20
+ // Nothing here may open the picker from script. While the keyboard is up,
21
+ // app.js's keyboard tap shim cancels every touch on a toolbar BUTTON and
22
+ // re-dispatches it as a scripted click, and iOS will not open a file picker
23
+ // from an untrusted click: measured on iOS 17, `isTrusted: false` two
24
+ // milliseconds after pointerdown, no picker, no error, and no real click after
25
+ // it either because the gesture was cancelled. A native tap on the input is not
26
+ // a button tap, so the shim leaves it alone and the click stays trusted. It also
27
+ // anchors the picker popover to the input's own frame (a `hidden` input has
28
+ // none, which is why the composer's picker floated loose).
29
+ //
30
+ // Cancelling mousedown's default keeps focus on the terminal's hidden textarea,
31
+ // so the fixed toolbar never reflows out from under the finger mid-tap.
32
+ //
33
+ // It does NOT keep the keyboard up, and nothing here can: iOS resigns first
34
+ // responder to present the picker, and on DEVICE it does not hand the keyboard
35
+ // back when the picker closes, even though focus never left the textarea.
36
+ // (An iOS 27 simulator does hand it back, which is a simulator artifact, so do
37
+ // not take a keyboard measurement from one.) A blur-then-focus on the close
38
+ // of the picker, cancel and change alike, restores DOM focus and still leaves
39
+ // the keyboard down, because iOS only raises it inside a user gesture. So the
40
+ // user taps the prompt when ready to type, which is the keyboard policy
41
+ // everywhere else in the app.
42
+ //
43
+ // Do not try to hide the keyboard's exit by freezing the page's keyboard
44
+ // state across the picker. That was tried (holdKeyboardState, reverted) to
45
+ // avoid the reflow and the two PTY resizes the hide/show pair costs: with the
46
+ // keyboard gone and the layout still keyboard-sized, the toolbar and accessory
47
+ // bar strand in the MIDDLE of the screen over a dead black band, which is far
48
+ // worse than the reflow. The page must follow the keyboard out.
49
+ const attachBtn = document.getElementById('attachBtnMobile');
50
+ const attachInput = document.getElementById('attachFileInput');
51
+ if (attachBtn && attachInput) {
52
+ attachInput.addEventListener('mousedown', (event) => event.preventDefault());
53
+ // The button is the ACCESSIBLE control (the input is aria-hidden and not
54
+ // tabbable), so a keyboard or VoiceOver activation arrives here instead of on
55
+ // the input. That click is trusted, so opening the picker from it is allowed.
56
+ attachBtn.addEventListener('click', () => attachInput.click());
57
+ attachInput.addEventListener('click', (event) => {
58
+ if (!this.activeSessionId) {
59
+ event.preventDefault(); // refuse before the picker opens, not after a pick
60
+ this.showToast('Open a session to attach a file', 'error');
61
+ return;
62
+ }
63
+ // Captured before the picker opens: the session can be deleted while it is
64
+ // up, and the pick must not land on whatever replaced it.
65
+ this._attachSessionId = this.activeSessionId;
66
+ });
67
+ attachInput.addEventListener('change', () => {
68
+ const files = Array.from(attachInput.files || []);
69
+ // Reset so picking the same file again still fires change.
70
+ attachInput.value = '';
71
+ // Captured when the picker opened (see the click handler above).
72
+ const sessionId = this._attachSessionId;
73
+ this._attachSessionId = null;
74
+ if (files.length > 0) {
75
+ void this._attachFromToolbar(files, sessionId).catch((err) => console.warn('Attach failed:', err));
76
+ }
77
+ });
78
+ }
79
+
80
+ // Drag-and-drop handlers on terminal container
81
+ const container = document.getElementById('terminalContainer');
82
+ if (!container) return;
83
+
84
+ container.addEventListener('dragover', (e) => {
85
+ e.preventDefault();
86
+ if (e.dataTransfer && e.dataTransfer.types.includes('Files')) {
87
+ container.classList.add('drag-active');
88
+ }
89
+ });
90
+
91
+ container.addEventListener('dragleave', (e) => {
92
+ if (!container.contains(e.relatedTarget)) {
93
+ container.classList.remove('drag-active');
94
+ }
95
+ });
96
+
97
+ container.addEventListener('drop', (e) => {
98
+ e.preventDefault();
99
+ container.classList.remove('drag-active');
100
+
101
+ if (!this.activeSessionId) return;
102
+ if (!e.dataTransfer || !e.dataTransfer.files.length) return;
103
+
104
+ const mediaFiles = Array.from(e.dataTransfer.files).filter((f) => this._promptAttachKind(f));
105
+ if (mediaFiles.length === 0) {
106
+ this.showToast('Only image or video files are supported', 'error');
107
+ return;
108
+ }
109
+ this._uploadAndInsertImages(mediaFiles);
110
+ });
111
+ },
112
+
113
+ /** Upload the toolbar Attach selection and put the paths on the prompt. The
114
+ * Compose dialog is deliberately not involved (see initImageInput).
115
+ *
116
+ * With local echo on (every phone by default) the paths go into the OVERLAY as
117
+ * pending text rather than to the PTY. That is what makes them part of "what the
118
+ * user typed": they paint at the prompt, anything typed after them appends in
119
+ * order, Enter flushes the whole line, and opening Compose adopts path and prose
120
+ * together (_takePendingLocalEcho reads exactly this buffer). Writing to the PTY
121
+ * instead would strand the path on the terminal while Compose took only the prose.
122
+ * Without the overlay (local echo off) there is nothing to buffer into, so the
123
+ * text goes straight out. The trailing space keeps the next word off the path. */
124
+ async _attachFromToolbar(files, sessionId) {
125
+ const media = files.filter((f) => this._promptAttachKind(f));
126
+ if (media.length === 0) {
127
+ this.showToast('Only image or video files are supported', 'error');
128
+ return;
129
+ }
130
+ if (!sessionId) return; // no captured session: refuse rather than guess at one
131
+ const paths = await this._uploadAndInsertImages(media, { insert: false, sessionId });
132
+ if (paths.length === 0) return;
133
+ // Deleted while the upload ran: a write would go to a dead session, and the
134
+ // flushed maps below would gain an entry whose cleanup has already run.
135
+ if (this.sessions && !this.sessions.has(sessionId)) return;
136
+ const text = paths.join(' ');
137
+
138
+ // The prompt composer, if it opened for this session while the upload ran, is
139
+ // where the prompt now lives: it took the terminal's pending text with it, so
140
+ // appending behind it would strand the path outside the text being composed.
141
+ // _insertComposerText adds its own separator and fires the draft save.
142
+ const openComposer = KeyboardAccessoryBar._composerOverlay;
143
+ const composerTextarea =
144
+ openComposer?.isConnected && openComposer.dataset.sessionId === sessionId
145
+ ? openComposer.querySelector('.prompt-composer-textarea')
146
+ : null;
147
+ if (composerTextarea) {
148
+ KeyboardAccessoryBar._insertComposerText(composerTextarea, text);
149
+ return;
150
+ }
151
+
152
+ const stillActive = this.activeSessionId === sessionId;
153
+ // The overlay holds the prompt only while local echo actually owns it. A
154
+ // session handed back to plain PTY echo by a composer nav key (echo
155
+ // passthrough) skips the whole overlay branch in onData, Enter included, so
156
+ // text buffered there would sit on screen and never be submitted. Nor while
157
+ // the tile grid owns the terminal area: the main terminal is parked and
158
+ // hidden then, and a tile's Enter never reaches its overlay, so the path
159
+ // goes to the PTY like any other background write.
160
+ const overlayOwnsPrompt =
161
+ stillActive &&
162
+ !this._tilesOwnTerminal?.() &&
163
+ this._localEchoEnabled &&
164
+ this._localEchoOverlay &&
165
+ !this._echoPassthroughSessions?.has(sessionId);
166
+ if (overlayOwnsPrompt) {
167
+ // Prompt text the overlay has not adopted yet (a tab completion, a restored
168
+ // tab) only lands in its flushed half once detection runs, and appendText
169
+ // runs it AFTER we would have measured. Detect first, or the separator is
170
+ // computed against an empty string and the path fuses onto a real word.
171
+ if (!this._localEchoOverlay.pendingText && !this._localEchoOverlay.getFlushed().count) {
172
+ this._localEchoOverlay.detectBufferText();
173
+ }
174
+ const flushed = this._localEchoOverlay.getFlushed().text || '';
175
+ const prompt = flushed + (this._localEchoOverlay.pendingText || '');
176
+ const gap = prompt && !/\s$/.test(prompt) ? ' ' : '';
177
+ this._localEchoOverlay.appendText(gap + text + ' ');
178
+ } else {
179
+ // No buffer to measure, so lead with a separator unconditionally rather than
180
+ // risk fusing onto whatever the CLI's own composer already holds.
181
+ const out = ` ${text} `;
182
+ this._sendInputAsync(sessionId, out);
183
+ // A background session's prompt is tracked in the flushed maps, which is what
184
+ // a later composer open adopts and erases. An untracked write leaves that
185
+ // count short, so the erase would eat the tail of this path instead. Not for
186
+ // a passthrough session: its cursor can sit mid-text, nothing tracks its
187
+ // composer, and Enter there never clears the maps, so a record would offset
188
+ // the overlay for the next prompt instead.
189
+ if (!stillActive && !this._echoPassthroughSessions?.has(sessionId)) {
190
+ if (!this._flushedOffsets) this._flushedOffsets = new Map();
191
+ if (!this._flushedTexts) this._flushedTexts = new Map();
192
+ this._flushedTexts.set(sessionId, (this._flushedTexts.get(sessionId) || '') + out);
193
+ this._flushedOffsets.set(sessionId, (this._flushedOffsets.get(sessionId) || 0) + out.length);
194
+ }
195
+ }
196
+ },
197
+
198
+ // Called from customKeyEventHandler in terminal-ui.js on Ctrl+V keydown.
199
+ // Creates a hidden paste trap, lets the browser paste into it, then inspects
200
+ // the result for images. Works on plain HTTP (no Clipboard API needed).
201
+ // `target` names the terminal the Ctrl+V came from and its session; both
202
+ // default to the primary pane. A second terminal (the split pane) passes its
203
+ // own, so text pastes into THAT xterm and images upload to THAT session.
204
+ _handleImagePaste(target = {}) {
205
+ const self = this;
206
+ const terminal = target.terminal || this.terminal;
207
+ const sessionId = target.sessionId || this.activeSessionId;
208
+
209
+ // Create a hidden contenteditable div to receive the paste
210
+ const trap = document.createElement('div');
211
+ trap.contentEditable = 'true';
212
+ trap.style.cssText = 'position:fixed;left:-9999px;top:0;width:1px;height:1px;opacity:0;overflow:hidden';
213
+ document.body.appendChild(trap);
214
+ trap.focus();
215
+
216
+ // One Ctrl+V can deliver TWO paste events to this trap. The
217
+ // execCommand('paste') below fires one wherever the browser honours that
218
+ // command, and the key's own default action fires another, because xterm's
219
+ // custom key handler returns false without cancelling the keydown. Handling
220
+ // both sends the clipboard text to the PTY twice, which is the "Ctrl+V
221
+ // pastes twice, right-click Paste does not" report: the context-menu paste
222
+ // has no keydown, so it only ever produces one event. The trap therefore
223
+ // accepts the first paste and drops every later one.
224
+ var pasteConsumed = false;
225
+
226
+ // Listen for the paste event on our trap
227
+ trap.addEventListener('paste', function(e) {
228
+ e.stopPropagation();
229
+ e.preventDefault();
230
+ if (pasteConsumed) return;
231
+ pasteConsumed = true;
232
+
233
+ // Check for images or videos in clipboard items
234
+ var imageFiles = [];
235
+ var items = e.clipboardData && e.clipboardData.items;
236
+ if (items) {
237
+ for (var i = 0; i < items.length; i++) {
238
+ var blob = items[i].getAsFile();
239
+ if (blob && self._promptAttachKind(blob)) imageFiles.push(blob);
240
+ }
241
+ }
242
+
243
+ // Clean up the trap
244
+ setTimeout(function() {
245
+ if (trap.parentNode) trap.parentNode.removeChild(trap);
246
+ // Refocus the terminal
247
+ if (terminal) terminal.focus();
248
+ }, 0);
249
+
250
+ if (imageFiles.length > 0) {
251
+ self._uploadAndInsertImages(imageFiles, { sessionId: sessionId });
252
+ } else {
253
+ // No image -- route text through xterm's paste() so bracketed-paste
254
+ // markers (CSI 200~ ... CSI 201~) survive when the inner application
255
+ // has enabled bracketed-paste mode (Claude Code does). Sending text
256
+ // via raw sendInput() strips those markers and makes pasted input
257
+ // indistinguishable from typed input, weakening the CLI's
258
+ // prompt-injection defenses.
259
+ var text = e.clipboardData ? e.clipboardData.getData('text/plain') : '';
260
+ if (text && terminal) terminal.paste(text);
261
+ }
262
+ });
263
+
264
+ // Trigger the browser's native paste via execCommand
265
+ // (this fires the paste event on our focused trap element)
266
+ document.execCommand('paste');
267
+ },
268
+
269
+ /** What a pick or a paste may upload: 'image', or 'video' for the camera
270
+ * roll's clips (the server streams those to disk under their own cap), else
271
+ * null. The one filter behind Attach, drop, the Compose and paste-dialog
272
+ * pickers and the clipboard handlers. The MIME type decides; some Android
273
+ * file managers hand over a File with none, so the name's extension is the
274
+ * fallback, mirroring the server's own allowlists. */
275
+ _promptAttachKind(file) {
276
+ if (file.type.startsWith('image/')) return 'image';
277
+ if (file.type.startsWith('video/')) return 'video';
278
+ const ext = (file.name || '').toLowerCase().match(/\.([a-z0-9]+)$/)?.[1] || '';
279
+ if (['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'heic', 'heif'].includes(ext)) return 'image';
280
+ if (['mp4', 'webm', 'mov', 'm4v', 'ogv'].includes(ext)) return 'video';
281
+ return null;
282
+ },
283
+
284
+ // Max images accepted in one batch (paste / drop / mobile picker). Each is
285
+ // uploaded as its own request, so 20 stays under the server's 30 uploads/min
286
+ // rate limit while covering "select a bunch of photos at once".
287
+ _maxBatchImages: 20,
288
+ // How many uploads to run concurrently. Small enough that decoding several
289
+ // large images through <canvas> at once won't OOM a phone, large enough that
290
+ // 20 photos don't crawl through serially.
291
+ _uploadConcurrency: 3,
292
+
293
+ /** Upload a batch and normally insert its paths into the active terminal.
294
+ * The prompt composer passes `{ insert: false }` so it can put those paths
295
+ * into its textarea instead. `options.sessionId` names the session to upload
296
+ * to (default: the active one). Returns successful paths in selection order. */
297
+ async _uploadAndInsertImages(fileList, options = {}) {
298
+ const sessionId = options.sessionId || this.activeSessionId;
299
+ if (!sessionId) return [];
300
+ if (options.sessionId && this.sessions && !this.sessions.has(sessionId)) return [];
301
+
302
+ let files = Array.from(fileList || []);
303
+ if (files.length === 0) return [];
304
+
305
+ // Cap the batch and tell the user what got dropped (no silent truncation).
306
+ let capped = false;
307
+ if (files.length > this._maxBatchImages) {
308
+ files = files.slice(0, this._maxBatchImages);
309
+ capped = true;
310
+ }
311
+
312
+ const total = files.length;
313
+ let done = 0;
314
+ let failed = 0;
315
+ let failReason = ''; // first server reason, shown in the toast so a failure is not just a count
316
+ const results = new Array(total); // preserve selection order for insertion
317
+ const progress = () =>
318
+ this.showToast(`Uploading ${Math.min(done + 1, total)}/${total} file${total > 1 ? 's' : ''}…`, 'info');
319
+ progress();
320
+
321
+ // Bounded-concurrency worker pool over the file list.
322
+ let next = 0;
323
+ const worker = async () => {
324
+ for (;;) {
325
+ const i = next++;
326
+ if (i >= total) return;
327
+ try {
328
+ // Re-encode to a standard JPEG/PNG (and downscale very large images)
329
+ // before upload. Galleries on some phones (notably Android/MIUI) hand
330
+ // back a WebP/HEIF whose filename and MIME claim "image/jpeg", which
331
+ // passes the server's extension allowlist but fails its magic-byte
332
+ // check. Decoding through the browser and re-encoding guarantees the
333
+ // bytes match the extension we send — and shrinks huge photos so they
334
+ // fit the upload limit and iOS's <canvas> area cap.
335
+ const normalized = await this._normalizeImageForUpload(files[i]);
336
+ results[i] = await this._uploadPasteImage(sessionId, normalized);
337
+ } catch (err) {
338
+ failed++;
339
+ if (!failReason && err && err.message) failReason = err.message;
340
+ console.warn('Image upload failed:', err);
341
+ results[i] = null;
342
+ } finally {
343
+ done++;
344
+ if (done < total) progress();
345
+ }
346
+ }
347
+ };
348
+ await Promise.all(Array.from({ length: Math.min(this._uploadConcurrency, total) }, () => worker()));
349
+
350
+ const paths = results.filter(Boolean);
351
+ if (paths.length > 0 && options.insert !== false) {
352
+ // Insert all paths in one shot, space-separated, in selection order, into
353
+ // the session the batch was uploaded TO. Not sendInput(): it re-reads
354
+ // activeSessionId, and after the awaits above that is whatever tab the
355
+ // user switched to mid-upload, so the paths landed in the wrong session.
356
+ // Same delivery sendInput() uses (durable queue, useMux for the POST path).
357
+ this._sendInputAsync(sessionId, paths.join(' '), { useMux: true });
358
+ }
359
+
360
+ // Final status: successes, plus any failures / cap so nothing is silent.
361
+ const parts = [];
362
+ if (paths.length > 0) parts.push(`${paths.length} file${paths.length > 1 ? 's' : ''} ready`);
363
+ if (failed > 0) parts.push(failReason ? `${failed} failed: ${failReason}` : `${failed} failed`);
364
+ if (capped) parts.push(`max ${this._maxBatchImages} per batch`);
365
+ const tone = paths.length > 0 ? (failed > 0 || capped ? 'info' : 'success') : 'error';
366
+ this.showToast(parts.join(' · ') || 'No files uploaded', tone);
367
+ return paths;
368
+ },
369
+
370
+ async _uploadPasteImage(sessionId, file) {
371
+ const form = new FormData();
372
+ form.append('image', file);
373
+
374
+ // A video takes the server's disk-streamed path and its larger cap; the flag
375
+ // has to ride the URL because the size budget is fixed before the part is read.
376
+ const kind = this._promptAttachKind(file) === 'video' ? '?kind=video' : '';
377
+ const resp = await fetch('/api/sessions/' + sessionId + '/paste-image' + kind, {
378
+ method: 'POST',
379
+ body: form,
380
+ });
381
+
382
+ if (!resp.ok) {
383
+ const data = await resp.json().catch(() => ({}));
384
+ throw new Error(data.error || 'HTTP ' + resp.status);
385
+ }
386
+
387
+ const data = await resp.json();
388
+ return data.data.path;
389
+ },
390
+
391
+ // Decode an image File through the browser and re-encode it to a format the
392
+ // server accepts, so the uploaded bytes always match their declared
393
+ // extension. PNG is re-encoded as PNG (preserves transparency); everything
394
+ // else (JPEG, WebP, HEIF, unknown) becomes JPEG. Animated GIFs are passed
395
+ // through untouched since a canvas would flatten them to one frame. On any
396
+ // decode/encode failure the original file is returned unchanged so the server
397
+ // still gets a chance (and logs a precise diagnostic).
398
+ async _normalizeImageForUpload(file) {
399
+ // Only an image goes through the canvas; a video is uploaded as picked. With no
400
+ // MIME (some Android file managers) the name's extension stands in, as it does in
401
+ // _promptAttachKind, so a .gif keeps its frames and a .png its transparency.
402
+ const name = (file.name || '').toLowerCase();
403
+ const isGif = file.type === 'image/gif' || (!file.type && name.endsWith('.gif'));
404
+ if (this._promptAttachKind(file) !== 'image' || isGif) return file;
405
+
406
+ const toPng = file.type === 'image/png' || (!file.type && name.endsWith('.png'));
407
+ const url = URL.createObjectURL(file);
408
+ try {
409
+ const img = new Image();
410
+ await new Promise((resolve, reject) => {
411
+ img.onload = () => resolve();
412
+ img.onerror = () => reject(new Error('decode failed'));
413
+ img.src = url;
414
+ });
415
+
416
+ const width = img.naturalWidth;
417
+ const height = img.naturalHeight;
418
+ if (!width || !height) return file;
419
+
420
+ // Downscale very large images. Two reasons: (1) iOS Safari refuses to
421
+ // render a <canvas> larger than ~16.7M px (it returns a blank/null
422
+ // blob), so a 48MP photo would otherwise fail to re-encode and fall back
423
+ // to the original — which then trips the server's magic-byte check for
424
+ // HEIF mislabeled as JPEG. (2) It keeps multi-photo uploads fast and well
425
+ // under the size limit. Cap the longest edge so area stays safely below
426
+ // the canvas limit while still uploading a large, high-quality image.
427
+ const MAX_EDGE = 4096;
428
+ const scale = Math.min(1, MAX_EDGE / Math.max(width, height));
429
+ const w = Math.max(1, Math.round(width * scale));
430
+ const h = Math.max(1, Math.round(height * scale));
431
+
432
+ const canvas = document.createElement('canvas');
433
+ canvas.width = w;
434
+ canvas.height = h;
435
+ const ctx = canvas.getContext('2d');
436
+ if (!ctx) return file;
437
+ ctx.drawImage(img, 0, 0, w, h);
438
+
439
+ const mime = toPng ? 'image/png' : 'image/jpeg';
440
+ const blob = await new Promise((resolve) => canvas.toBlob(resolve, mime, 0.92));
441
+ if (!blob) return file;
442
+
443
+ const baseName = (file.name || 'image').replace(/\.[^.]+$/, '') || 'image';
444
+ return new File([blob], baseName + (toPng ? '.png' : '.jpg'), { type: mime });
445
+ } catch (err) {
446
+ console.warn('Image re-encode failed, uploading original:', err);
447
+ return file;
448
+ } finally {
449
+ URL.revokeObjectURL(url);
450
+ }
451
+ },
452
+
453
+ });