claude-mux 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (636) hide show
  1. package/.beads/README.md +81 -0
  2. package/.beads/config.yaml +62 -0
  3. package/.beads/interactions.jsonl +0 -0
  4. package/.beads/issues.jsonl +5 -0
  5. package/.beads/metadata.json +4 -0
  6. package/.eslintrc.json +25 -0
  7. package/.gitattributes +3 -0
  8. package/.prettierrc +7 -0
  9. package/CLAUDE.md +123 -0
  10. package/LICENSE +21 -0
  11. package/PLAN-beads-integration.md +250 -0
  12. package/README.md +366 -0
  13. package/dist/app.d.ts +2 -0
  14. package/dist/app.d.ts.map +1 -0
  15. package/dist/app.js +147 -0
  16. package/dist/app.js.map +1 -0
  17. package/dist/cli.d.ts +3 -0
  18. package/dist/cli.d.ts.map +1 -0
  19. package/dist/cli.js +65 -0
  20. package/dist/cli.js.map +1 -0
  21. package/dist/commands/index.d.ts +5 -0
  22. package/dist/commands/index.d.ts.map +1 -0
  23. package/dist/commands/index.js +5 -0
  24. package/dist/commands/index.js.map +1 -0
  25. package/dist/commands/serve.d.ts +8 -0
  26. package/dist/commands/serve.d.ts.map +1 -0
  27. package/dist/commands/serve.js +59 -0
  28. package/dist/commands/serve.js.map +1 -0
  29. package/dist/commands/setup.d.ts +4 -0
  30. package/dist/commands/setup.d.ts.map +1 -0
  31. package/dist/commands/setup.js +12 -0
  32. package/dist/commands/setup.js.map +1 -0
  33. package/dist/commands/tui.d.ts +9 -0
  34. package/dist/commands/tui.d.ts.map +1 -0
  35. package/dist/commands/tui.js +234 -0
  36. package/dist/commands/tui.js.map +1 -0
  37. package/dist/commands/uninstall.d.ts +4 -0
  38. package/dist/commands/uninstall.d.ts.map +1 -0
  39. package/dist/commands/uninstall.js +12 -0
  40. package/dist/commands/uninstall.js.map +1 -0
  41. package/dist/components/Header.d.ts +7 -0
  42. package/dist/components/Header.d.ts.map +1 -0
  43. package/dist/components/Header.js +14 -0
  44. package/dist/components/Header.js.map +1 -0
  45. package/dist/components/HelpDialog.d.ts +6 -0
  46. package/dist/components/HelpDialog.d.ts.map +1 -0
  47. package/dist/components/HelpDialog.js +14 -0
  48. package/dist/components/HelpDialog.js.map +1 -0
  49. package/dist/components/SessionEntry.d.ts +17 -0
  50. package/dist/components/SessionEntry.d.ts.map +1 -0
  51. package/dist/components/SessionEntry.js +102 -0
  52. package/dist/components/SessionEntry.js.map +1 -0
  53. package/dist/components/SessionList.d.ts +14 -0
  54. package/dist/components/SessionList.d.ts.map +1 -0
  55. package/dist/components/SessionList.js +57 -0
  56. package/dist/components/SessionList.js.map +1 -0
  57. package/dist/components/StatusBar.d.ts +6 -0
  58. package/dist/components/StatusBar.d.ts.map +1 -0
  59. package/dist/components/StatusBar.js +7 -0
  60. package/dist/components/StatusBar.js.map +1 -0
  61. package/dist/components/index.d.ts +6 -0
  62. package/dist/components/index.d.ts.map +1 -0
  63. package/dist/components/index.js +6 -0
  64. package/dist/components/index.js.map +1 -0
  65. package/dist/db/index.d.ts +2 -0
  66. package/dist/db/index.d.ts.map +1 -0
  67. package/dist/db/index.js +3 -0
  68. package/dist/db/index.js.map +1 -0
  69. package/dist/db/schema.d.ts +4 -0
  70. package/dist/db/schema.d.ts.map +1 -0
  71. package/dist/db/schema.js +23 -0
  72. package/dist/db/schema.js.map +1 -0
  73. package/dist/db/sessions-json.d.ts +85 -0
  74. package/dist/db/sessions-json.d.ts.map +1 -0
  75. package/dist/db/sessions-json.js +242 -0
  76. package/dist/db/sessions-json.js.map +1 -0
  77. package/dist/db/sessions.d.ts +38 -0
  78. package/dist/db/sessions.d.ts.map +1 -0
  79. package/dist/db/sessions.js +87 -0
  80. package/dist/db/sessions.js.map +1 -0
  81. package/dist/hooks/claude-mux-hook.d.ts +15 -0
  82. package/dist/hooks/claude-mux-hook.d.ts.map +1 -0
  83. package/dist/hooks/claude-mux-hook.js +396 -0
  84. package/dist/hooks/claude-mux-hook.js.map +1 -0
  85. package/dist/hooks/claude-watch-hook.d.ts +15 -0
  86. package/dist/hooks/claude-watch-hook.d.ts.map +1 -0
  87. package/dist/hooks/claude-watch-hook.js +396 -0
  88. package/dist/hooks/claude-watch-hook.js.map +1 -0
  89. package/dist/server/custom-server.d.ts +13 -0
  90. package/dist/server/custom-server.d.ts.map +1 -0
  91. package/dist/server/custom-server.js +63 -0
  92. package/dist/server/custom-server.js.map +1 -0
  93. package/dist/server/index.d.ts +9 -0
  94. package/dist/server/index.d.ts.map +1 -0
  95. package/dist/server/index.js +1143 -0
  96. package/dist/server/index.js.map +1 -0
  97. package/dist/server/middleware/cors.d.ts +2 -0
  98. package/dist/server/middleware/cors.d.ts.map +1 -0
  99. package/dist/server/middleware/cors.js +11 -0
  100. package/dist/server/middleware/cors.js.map +1 -0
  101. package/dist/server/routes/sessions.d.ts +3 -0
  102. package/dist/server/routes/sessions.d.ts.map +1 -0
  103. package/dist/server/routes/sessions.js +78 -0
  104. package/dist/server/routes/sessions.js.map +1 -0
  105. package/dist/server/routes/stream.d.ts +3 -0
  106. package/dist/server/routes/stream.d.ts.map +1 -0
  107. package/dist/server/routes/stream.js +45 -0
  108. package/dist/server/routes/stream.js.map +1 -0
  109. package/dist/server/types.d.ts +28 -0
  110. package/dist/server/types.d.ts.map +1 -0
  111. package/dist/server/types.js +2 -0
  112. package/dist/server/types.js.map +1 -0
  113. package/dist/server/watcher.d.ts +22 -0
  114. package/dist/server/watcher.d.ts.map +1 -0
  115. package/dist/server/watcher.js +119 -0
  116. package/dist/server/watcher.js.map +1 -0
  117. package/dist/server/websocket.d.ts +51 -0
  118. package/dist/server/websocket.d.ts.map +1 -0
  119. package/dist/server/websocket.js +156 -0
  120. package/dist/server/websocket.js.map +1 -0
  121. package/dist/server/ws-handlers.d.ts +174 -0
  122. package/dist/server/ws-handlers.d.ts.map +1 -0
  123. package/dist/server/ws-handlers.js +695 -0
  124. package/dist/server/ws-handlers.js.map +1 -0
  125. package/dist/setup/hooks.d.ts +44 -0
  126. package/dist/setup/hooks.d.ts.map +1 -0
  127. package/dist/setup/hooks.js +267 -0
  128. package/dist/setup/hooks.js.map +1 -0
  129. package/dist/setup/index.d.ts +3 -0
  130. package/dist/setup/index.d.ts.map +1 -0
  131. package/dist/setup/index.js +3 -0
  132. package/dist/setup/index.js.map +1 -0
  133. package/dist/setup/wizard.d.ts +4 -0
  134. package/dist/setup/wizard.d.ts.map +1 -0
  135. package/dist/setup/wizard.js +72 -0
  136. package/dist/setup/wizard.js.map +1 -0
  137. package/dist/tmux/detect.d.ts +25 -0
  138. package/dist/tmux/detect.d.ts.map +1 -0
  139. package/dist/tmux/detect.js +71 -0
  140. package/dist/tmux/detect.js.map +1 -0
  141. package/dist/tmux/navigate.d.ts +13 -0
  142. package/dist/tmux/navigate.d.ts.map +1 -0
  143. package/dist/tmux/navigate.js +41 -0
  144. package/dist/tmux/navigate.js.map +1 -0
  145. package/dist/tmux/pane.d.ts +57 -0
  146. package/dist/tmux/pane.d.ts.map +1 -0
  147. package/dist/tmux/pane.js +156 -0
  148. package/dist/tmux/pane.js.map +1 -0
  149. package/dist/tmux/resize.d.ts +10 -0
  150. package/dist/tmux/resize.d.ts.map +1 -0
  151. package/dist/tmux/resize.js +25 -0
  152. package/dist/tmux/resize.js.map +1 -0
  153. package/dist/utils/paths.d.ts +7 -0
  154. package/dist/utils/paths.d.ts.map +1 -0
  155. package/dist/utils/paths.js +9 -0
  156. package/dist/utils/paths.js.map +1 -0
  157. package/dist/utils/pid.d.ts +5 -0
  158. package/dist/utils/pid.d.ts.map +1 -0
  159. package/dist/utils/pid.js +14 -0
  160. package/dist/utils/pid.js.map +1 -0
  161. package/dist/utils/version.d.ts +6 -0
  162. package/dist/utils/version.d.ts.map +1 -0
  163. package/dist/utils/version.js +6 -0
  164. package/dist/utils/version.js.map +1 -0
  165. package/dist/web/client/_app/immutable/assets/0.WptSHSUl.css +1 -0
  166. package/dist/web/client/_app/immutable/assets/2.s6Kx4oz1.css +1 -0
  167. package/dist/web/client/_app/immutable/assets/4.DoNWy7tW.css +1 -0
  168. package/dist/web/client/_app/immutable/assets/AllSessionsPanel.CGHY3HLy.css +1 -0
  169. package/dist/web/client/_app/immutable/chunks/-3mUPuLP.js +1 -0
  170. package/dist/web/client/_app/immutable/chunks/B5U4_V3d.js +1 -0
  171. package/dist/web/client/_app/immutable/chunks/BHwiZXRv.js +1 -0
  172. package/dist/web/client/_app/immutable/chunks/C9P-coqM.js +1 -0
  173. package/dist/web/client/_app/immutable/chunks/Cegv0r8x.js +1 -0
  174. package/dist/web/client/_app/immutable/chunks/DU91Ml7U.js +3 -0
  175. package/dist/web/client/_app/immutable/chunks/DmdO6ygw.js +1 -0
  176. package/dist/web/client/_app/immutable/chunks/HKNo9LID.js +5 -0
  177. package/dist/web/client/_app/immutable/chunks/U4ip-C0d.js +2 -0
  178. package/dist/web/client/_app/immutable/chunks/cgUjKIhX.js +2 -0
  179. package/dist/web/client/_app/immutable/entry/app.CGIBnoln.js +2 -0
  180. package/dist/web/client/_app/immutable/entry/start.CJk8zB1j.js +1 -0
  181. package/dist/web/client/_app/immutable/nodes/0.CqlJ9a31.js +1 -0
  182. package/dist/web/client/_app/immutable/nodes/1.BQUZh2-w.js +1 -0
  183. package/dist/web/client/_app/immutable/nodes/2.CCV1YdgF.js +1 -0
  184. package/dist/web/client/_app/immutable/nodes/3.D9tDCdq8.js +1 -0
  185. package/dist/web/client/_app/immutable/nodes/4.BqPyNkFA.js +6 -0
  186. package/dist/web/client/_app/version.json +1 -0
  187. package/dist/web/client/robots.txt +3 -0
  188. package/dist/web/env.js +32 -0
  189. package/dist/web/handler.js +744 -0
  190. package/dist/web/index.js +49 -0
  191. package/dist/web/server/chunks/0-BHWsmCJv.js +23 -0
  192. package/dist/web/server/chunks/0-BHWsmCJv.js.map +1 -0
  193. package/dist/web/server/chunks/1-YRx6A8Tm.js +17 -0
  194. package/dist/web/server/chunks/1-YRx6A8Tm.js.map +1 -0
  195. package/dist/web/server/chunks/2-eC6JuGAo.js +22 -0
  196. package/dist/web/server/chunks/2-eC6JuGAo.js.map +1 -0
  197. package/dist/web/server/chunks/3-Bk-wV20p.js +32 -0
  198. package/dist/web/server/chunks/3-Bk-wV20p.js.map +1 -0
  199. package/dist/web/server/chunks/4-nteBgDrW.js +21 -0
  200. package/dist/web/server/chunks/4-nteBgDrW.js.map +1 -0
  201. package/dist/web/server/chunks/AllSessionsPanel.svelte_svelte_type_style_lang-Bt4B0-oi.js +35 -0
  202. package/dist/web/server/chunks/AllSessionsPanel.svelte_svelte_type_style_lang-Bt4B0-oi.js.map +1 -0
  203. package/dist/web/server/chunks/_layout.svelte-BIF9eZCY.js +453 -0
  204. package/dist/web/server/chunks/_layout.svelte-BIF9eZCY.js.map +1 -0
  205. package/dist/web/server/chunks/_page.svelte-Be6iabRn.js +34 -0
  206. package/dist/web/server/chunks/_page.svelte-Be6iabRn.js.map +1 -0
  207. package/dist/web/server/chunks/_page.svelte-C_fGJVSE.js +576 -0
  208. package/dist/web/server/chunks/_page.svelte-C_fGJVSE.js.map +1 -0
  209. package/dist/web/server/chunks/_page.svelte-CnfJk6cu.js +2722 -0
  210. package/dist/web/server/chunks/_page.svelte-CnfJk6cu.js.map +1 -0
  211. package/dist/web/server/chunks/_server.ts-3WAmKvn2.js +34 -0
  212. package/dist/web/server/chunks/_server.ts-3WAmKvn2.js.map +1 -0
  213. package/dist/web/server/chunks/_server.ts-BAWJCSFb.js +29 -0
  214. package/dist/web/server/chunks/_server.ts-BAWJCSFb.js.map +1 -0
  215. package/dist/web/server/chunks/_server.ts-BPpMOZCm.js +24 -0
  216. package/dist/web/server/chunks/_server.ts-BPpMOZCm.js.map +1 -0
  217. package/dist/web/server/chunks/_server.ts-BUKgRb6U.js +13 -0
  218. package/dist/web/server/chunks/_server.ts-BUKgRb6U.js.map +1 -0
  219. package/dist/web/server/chunks/_server.ts-BVHUS8fm.js +41 -0
  220. package/dist/web/server/chunks/_server.ts-BVHUS8fm.js.map +1 -0
  221. package/dist/web/server/chunks/_server.ts-BrF3od0O.js +45 -0
  222. package/dist/web/server/chunks/_server.ts-BrF3od0O.js.map +1 -0
  223. package/dist/web/server/chunks/_server.ts-C4oPmOJR.js +38 -0
  224. package/dist/web/server/chunks/_server.ts-C4oPmOJR.js.map +1 -0
  225. package/dist/web/server/chunks/_server.ts-CDAUUmG_.js +21 -0
  226. package/dist/web/server/chunks/_server.ts-CDAUUmG_.js.map +1 -0
  227. package/dist/web/server/chunks/_server.ts-CR0uWvpz.js +24 -0
  228. package/dist/web/server/chunks/_server.ts-CR0uWvpz.js.map +1 -0
  229. package/dist/web/server/chunks/_server.ts-CSqdCNGi.js +21 -0
  230. package/dist/web/server/chunks/_server.ts-CSqdCNGi.js.map +1 -0
  231. package/dist/web/server/chunks/_server.ts-DI9fzUo9.js +52 -0
  232. package/dist/web/server/chunks/_server.ts-DI9fzUo9.js.map +1 -0
  233. package/dist/web/server/chunks/_server.ts-DNjJTClI.js +46 -0
  234. package/dist/web/server/chunks/_server.ts-DNjJTClI.js.map +1 -0
  235. package/dist/web/server/chunks/_server.ts-DdbOAkOj.js +22 -0
  236. package/dist/web/server/chunks/_server.ts-DdbOAkOj.js.map +1 -0
  237. package/dist/web/server/chunks/_server.ts-Df2isGQc.js +41 -0
  238. package/dist/web/server/chunks/_server.ts-Df2isGQc.js.map +1 -0
  239. package/dist/web/server/chunks/_server.ts-Vpw25_-3.js +12 -0
  240. package/dist/web/server/chunks/_server.ts-Vpw25_-3.js.map +1 -0
  241. package/dist/web/server/chunks/_server.ts-WldRpSRi.js +26 -0
  242. package/dist/web/server/chunks/_server.ts-WldRpSRi.js.map +1 -0
  243. package/dist/web/server/chunks/alert-dialog-description-DDA6u-nS.js +2890 -0
  244. package/dist/web/server/chunks/alert-dialog-description-DDA6u-nS.js.map +1 -0
  245. package/dist/web/server/chunks/auth-DrUf-v4J.js +51 -0
  246. package/dist/web/server/chunks/auth-DrUf-v4J.js.map +1 -0
  247. package/dist/web/server/chunks/button-D6xS9rHt.js +2335 -0
  248. package/dist/web/server/chunks/button-D6xS9rHt.js.map +1 -0
  249. package/dist/web/server/chunks/chunk-EKzHsMy_.js +42 -0
  250. package/dist/web/server/chunks/chunks-DmdqVYC7.js +58 -0
  251. package/dist/web/server/chunks/chunks-DmdqVYC7.js.map +1 -0
  252. package/dist/web/server/chunks/client-CUrSQijh.js +18 -0
  253. package/dist/web/server/chunks/client-CUrSQijh.js.map +1 -0
  254. package/dist/web/server/chunks/clsx-FzI4_gi0.js +332 -0
  255. package/dist/web/server/chunks/clsx-FzI4_gi0.js.map +1 -0
  256. package/dist/web/server/chunks/error.svelte-D-c-9pTE.js +27 -0
  257. package/dist/web/server/chunks/error.svelte-D-c-9pTE.js.map +1 -0
  258. package/dist/web/server/chunks/events-BDBlYddw.js +89 -0
  259. package/dist/web/server/chunks/events-BDBlYddw.js.map +1 -0
  260. package/dist/web/server/chunks/exports-CCurQ-Tl.js +131 -0
  261. package/dist/web/server/chunks/exports-CCurQ-Tl.js.map +1 -0
  262. package/dist/web/server/chunks/hooks.server-BK1bopsh.js +86 -0
  263. package/dist/web/server/chunks/hooks.server-BK1bopsh.js.map +1 -0
  264. package/dist/web/server/chunks/index2-BQnysSj-.js +2588 -0
  265. package/dist/web/server/chunks/index2-BQnysSj-.js.map +1 -0
  266. package/dist/web/server/chunks/internal-DLENj6YI.js +61 -0
  267. package/dist/web/server/chunks/internal-DLENj6YI.js.map +1 -0
  268. package/dist/web/server/chunks/pane-Dg3pKvsm.js +94 -0
  269. package/dist/web/server/chunks/pane-Dg3pKvsm.js.map +1 -0
  270. package/dist/web/server/chunks/sessions-json-DgfkCLO7.js +107 -0
  271. package/dist/web/server/chunks/sessions-json-DgfkCLO7.js.map +1 -0
  272. package/dist/web/server/chunks/sessions.svelte-Ds82MvkB.js +178 -0
  273. package/dist/web/server/chunks/sessions.svelte-Ds82MvkB.js.map +1 -0
  274. package/dist/web/server/chunks/state.svelte-xeAZvWZ6.js +7 -0
  275. package/dist/web/server/chunks/state.svelte-xeAZvWZ6.js.map +1 -0
  276. package/dist/web/server/chunks/ws-handlers-B4r5eSP2.js +733 -0
  277. package/dist/web/server/chunks/ws-handlers-B4r5eSP2.js.map +1 -0
  278. package/dist/web/server/index.js +4907 -0
  279. package/dist/web/server/index.js.map +1 -0
  280. package/dist/web/server/manifest.js +233 -0
  281. package/dist/web/server/manifest.js.map +1 -0
  282. package/docs/images/desktop-dashboard.png +0 -0
  283. package/docs/images/desktop-session.png +0 -0
  284. package/docs/images/mobile-dashboard.png +0 -0
  285. package/docs/images/mobile-session.png +0 -0
  286. package/docs/release-checklist.md +228 -0
  287. package/docs/removing-hooks.md +135 -0
  288. package/docs/state-transitions.md +109 -0
  289. package/package.json +71 -0
  290. package/src/app.tsx +188 -0
  291. package/src/cli.ts +83 -0
  292. package/src/commands/index.ts +4 -0
  293. package/src/commands/serve.ts +75 -0
  294. package/src/commands/setup.ts +13 -0
  295. package/src/commands/tui.ts +255 -0
  296. package/src/commands/uninstall.ts +13 -0
  297. package/src/components/Header.tsx +32 -0
  298. package/src/components/HelpDialog.tsx +45 -0
  299. package/src/components/SessionEntry.tsx +202 -0
  300. package/src/components/SessionList.tsx +98 -0
  301. package/src/components/StatusBar.tsx +26 -0
  302. package/src/components/index.ts +5 -0
  303. package/src/db/index.ts +20 -0
  304. package/src/db/sessions-json.ts +314 -0
  305. package/src/hooks/claude-mux-hook.ts +498 -0
  306. package/src/server/watcher.ts +128 -0
  307. package/src/server/ws-handlers.ts +922 -0
  308. package/src/setup/hooks.ts +333 -0
  309. package/src/setup/index.ts +2 -0
  310. package/src/setup/wizard.ts +81 -0
  311. package/src/tmux/detect.ts +87 -0
  312. package/src/tmux/navigate.ts +42 -0
  313. package/src/tmux/pane.ts +167 -0
  314. package/src/tmux/resize.ts +28 -0
  315. package/src/utils/paths.ts +11 -0
  316. package/src/utils/pid.ts +12 -0
  317. package/src/utils/version.ts +5 -0
  318. package/tests/components/Header.test.tsx +42 -0
  319. package/tests/components/SessionEntry-extended.test.tsx +165 -0
  320. package/tests/components/SessionEntry.test.tsx +138 -0
  321. package/tests/components/SessionList.test.tsx +110 -0
  322. package/tests/components/StatusBar.test.tsx +31 -0
  323. package/tests/db/index.test.ts +78 -0
  324. package/tests/db/sessions.test.ts +230 -0
  325. package/tests/server/integration.test.ts +319 -0
  326. package/tests/server/sessions.test.ts +114 -0
  327. package/tests/setup/hooks-integration.test.ts +148 -0
  328. package/tests/setup/hooks.test.ts +123 -0
  329. package/tests/tmux/detect.test.ts +54 -0
  330. package/tests/tmux/navigate.test.ts +30 -0
  331. package/tests/utils/pid.test.ts +17 -0
  332. package/tsconfig.cli.json +9 -0
  333. package/tsconfig.json +22 -0
  334. package/vitest.config.ts +29 -0
  335. package/web/.svelte-kit/adapter-bun/.vite/manifest.json +408 -0
  336. package/web/.svelte-kit/adapter-bun/_app/immutable/assets/AllSessionsPanel.BKhqOrbV.css +1 -0
  337. package/web/.svelte-kit/adapter-bun/_app/immutable/assets/_layout.WptSHSUl.css +1 -0
  338. package/web/.svelte-kit/adapter-bun/_app/immutable/assets/_page.DldLgTc-.css +1 -0
  339. package/web/.svelte-kit/adapter-bun/_app/immutable/assets/_page.DoNWy7tW.css +1 -0
  340. package/web/.svelte-kit/adapter-bun/chunks/AllSessionsPanel.svelte_svelte_type_style_lang.js +49 -0
  341. package/web/.svelte-kit/adapter-bun/chunks/alert-dialog-description.js +2670 -0
  342. package/web/.svelte-kit/adapter-bun/chunks/auth.js +59 -0
  343. package/web/.svelte-kit/adapter-bun/chunks/button.js +82 -0
  344. package/web/.svelte-kit/adapter-bun/chunks/client.js +29 -0
  345. package/web/.svelte-kit/adapter-bun/chunks/context.js +133 -0
  346. package/web/.svelte-kit/adapter-bun/chunks/environment.js +34 -0
  347. package/web/.svelte-kit/adapter-bun/chunks/events.js +121 -0
  348. package/web/.svelte-kit/adapter-bun/chunks/exports.js +174 -0
  349. package/web/.svelte-kit/adapter-bun/chunks/false.js +4 -0
  350. package/web/.svelte-kit/adapter-bun/chunks/index.js +59 -0
  351. package/web/.svelte-kit/adapter-bun/chunks/index2.js +2828 -0
  352. package/web/.svelte-kit/adapter-bun/chunks/internal.js +920 -0
  353. package/web/.svelte-kit/adapter-bun/chunks/pane.js +82 -0
  354. package/web/.svelte-kit/adapter-bun/chunks/sessions-json.js +124 -0
  355. package/web/.svelte-kit/adapter-bun/chunks/sessions.svelte.js +229 -0
  356. package/web/.svelte-kit/adapter-bun/chunks/shared.js +542 -0
  357. package/web/.svelte-kit/adapter-bun/chunks/state.svelte.js +16 -0
  358. package/web/.svelte-kit/adapter-bun/chunks/utils.js +43 -0
  359. package/web/.svelte-kit/adapter-bun/chunks/ws-handlers.js +782 -0
  360. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/auth/login/_server.ts.js +22 -0
  361. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/auth/logout/_server.ts.js +9 -0
  362. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/beads/_server.ts.js +22 -0
  363. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/browse/_server.ts.js +50 -0
  364. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/chrome/_server.ts.js +30 -0
  365. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/files/image/_server.ts.js +53 -0
  366. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/health/_server.ts.js +7 -0
  367. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/projects/new-session/_server.ts.js +44 -0
  368. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_id_/_server.ts.js +20 -0
  369. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_id_/kill/_server.ts.js +36 -0
  370. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_id_/restart/_server.ts.js +40 -0
  371. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_id_/screenshots/_server.ts.js +28 -0
  372. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_id_/send/_server.ts.js +29 -0
  373. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_server.ts.js +49 -0
  374. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_target_/output/_server.ts.js +14 -0
  375. package/web/.svelte-kit/adapter-bun/entries/endpoints/api/tmux/panes/_server.ts.js +21 -0
  376. package/web/.svelte-kit/adapter-bun/entries/fallbacks/error.svelte.js +27 -0
  377. package/web/.svelte-kit/adapter-bun/entries/hooks.server.js +105 -0
  378. package/web/.svelte-kit/adapter-bun/entries/pages/_layout.svelte.js +499 -0
  379. package/web/.svelte-kit/adapter-bun/entries/pages/_page.svelte.js +3057 -0
  380. package/web/.svelte-kit/adapter-bun/entries/pages/login/_page.server.ts.js +15 -0
  381. package/web/.svelte-kit/adapter-bun/entries/pages/login/_page.svelte.js +37 -0
  382. package/web/.svelte-kit/adapter-bun/entries/pages/session/_target_/_page.svelte.js +653 -0
  383. package/web/.svelte-kit/adapter-bun/index.js +3864 -0
  384. package/web/.svelte-kit/adapter-bun/internal.js +13 -0
  385. package/web/.svelte-kit/adapter-bun/manifest-full.js +167 -0
  386. package/web/.svelte-kit/adapter-bun/manifest.js +171 -0
  387. package/web/.svelte-kit/adapter-bun/nodes/0.js +8 -0
  388. package/web/.svelte-kit/adapter-bun/nodes/1.js +8 -0
  389. package/web/.svelte-kit/adapter-bun/nodes/2.js +8 -0
  390. package/web/.svelte-kit/adapter-bun/nodes/3.js +10 -0
  391. package/web/.svelte-kit/adapter-bun/nodes/4.js +8 -0
  392. package/web/.svelte-kit/adapter-bun/remote-entry.js +541 -0
  393. package/web/.svelte-kit/adapter-node/.vite/manifest.json +223 -0
  394. package/web/.svelte-kit/adapter-node/_app/immutable/assets/_layout.4NiX29PU.css +1 -0
  395. package/web/.svelte-kit/adapter-node/_app/immutable/assets/_page.BEMzYUGV.css +1 -0
  396. package/web/.svelte-kit/adapter-node/_app/immutable/assets/_page.DOJn7TG7.css +1 -0
  397. package/web/.svelte-kit/adapter-node/chunks/context.js +121 -0
  398. package/web/.svelte-kit/adapter-node/chunks/environment.js +34 -0
  399. package/web/.svelte-kit/adapter-node/chunks/exports.js +174 -0
  400. package/web/.svelte-kit/adapter-node/chunks/false.js +4 -0
  401. package/web/.svelte-kit/adapter-node/chunks/index.js +59 -0
  402. package/web/.svelte-kit/adapter-node/chunks/index2.js +2710 -0
  403. package/web/.svelte-kit/adapter-node/chunks/internal.js +1005 -0
  404. package/web/.svelte-kit/adapter-node/chunks/sessions-json.js +109 -0
  405. package/web/.svelte-kit/adapter-node/chunks/sessions.svelte.js +67 -0
  406. package/web/.svelte-kit/adapter-node/chunks/shared.js +542 -0
  407. package/web/.svelte-kit/adapter-node/chunks/state.svelte.js +16 -0
  408. package/web/.svelte-kit/adapter-node/chunks/utils.js +43 -0
  409. package/web/.svelte-kit/adapter-node/entries/endpoints/api/browse/_server.ts.js +50 -0
  410. package/web/.svelte-kit/adapter-node/entries/endpoints/api/health/_server.ts.js +7 -0
  411. package/web/.svelte-kit/adapter-node/entries/endpoints/api/projects/new-session/_server.ts.js +44 -0
  412. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_id_/_server.ts.js +20 -0
  413. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_id_/kill/_server.ts.js +30 -0
  414. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_id_/send/_server.ts.js +22 -0
  415. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_server.ts.js +126 -0
  416. package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_target_/output/_server.ts.js +14 -0
  417. package/web/.svelte-kit/adapter-node/entries/fallbacks/error.svelte.js +44 -0
  418. package/web/.svelte-kit/adapter-node/entries/pages/_layout.svelte.js +12 -0
  419. package/web/.svelte-kit/adapter-node/entries/pages/_page.svelte.js +87 -0
  420. package/web/.svelte-kit/adapter-node/entries/pages/session/_target_/_page.svelte.js +76 -0
  421. package/web/.svelte-kit/adapter-node/index.js +3864 -0
  422. package/web/.svelte-kit/adapter-node/internal.js +13 -0
  423. package/web/.svelte-kit/adapter-node/manifest-full.js +103 -0
  424. package/web/.svelte-kit/adapter-node/manifest.js +107 -0
  425. package/web/.svelte-kit/adapter-node/nodes/0.js +8 -0
  426. package/web/.svelte-kit/adapter-node/nodes/1.js +8 -0
  427. package/web/.svelte-kit/adapter-node/nodes/2.js +8 -0
  428. package/web/.svelte-kit/adapter-node/nodes/3.js +8 -0
  429. package/web/.svelte-kit/adapter-node/remote-entry.js +541 -0
  430. package/web/.svelte-kit/ambient.d.ts +187 -0
  431. package/web/.svelte-kit/generated/client/app.js +33 -0
  432. package/web/.svelte-kit/generated/client/matchers.js +1 -0
  433. package/web/.svelte-kit/generated/client/nodes/0.js +1 -0
  434. package/web/.svelte-kit/generated/client/nodes/1.js +1 -0
  435. package/web/.svelte-kit/generated/client/nodes/2.js +1 -0
  436. package/web/.svelte-kit/generated/client/nodes/3.js +1 -0
  437. package/web/.svelte-kit/generated/client/nodes/4.js +1 -0
  438. package/web/.svelte-kit/generated/client-optimized/app.js +33 -0
  439. package/web/.svelte-kit/generated/client-optimized/matchers.js +1 -0
  440. package/web/.svelte-kit/generated/client-optimized/nodes/0.js +1 -0
  441. package/web/.svelte-kit/generated/client-optimized/nodes/1.js +1 -0
  442. package/web/.svelte-kit/generated/client-optimized/nodes/2.js +1 -0
  443. package/web/.svelte-kit/generated/client-optimized/nodes/3.js +1 -0
  444. package/web/.svelte-kit/generated/client-optimized/nodes/4.js +1 -0
  445. package/web/.svelte-kit/generated/root.js +3 -0
  446. package/web/.svelte-kit/generated/root.svelte +68 -0
  447. package/web/.svelte-kit/generated/server/internal.js +53 -0
  448. package/web/.svelte-kit/non-ambient.d.ts +73 -0
  449. package/web/.svelte-kit/output/client/.vite/manifest.json +203 -0
  450. package/web/.svelte-kit/output/client/_app/immutable/assets/0.WptSHSUl.css +1 -0
  451. package/web/.svelte-kit/output/client/_app/immutable/assets/2.s6Kx4oz1.css +1 -0
  452. package/web/.svelte-kit/output/client/_app/immutable/assets/4.DoNWy7tW.css +1 -0
  453. package/web/.svelte-kit/output/client/_app/immutable/assets/AllSessionsPanel.CGHY3HLy.css +1 -0
  454. package/web/.svelte-kit/output/client/_app/immutable/chunks/-3mUPuLP.js +1 -0
  455. package/web/.svelte-kit/output/client/_app/immutable/chunks/B5U4_V3d.js +1 -0
  456. package/web/.svelte-kit/output/client/_app/immutable/chunks/BHwiZXRv.js +1 -0
  457. package/web/.svelte-kit/output/client/_app/immutable/chunks/C9P-coqM.js +1 -0
  458. package/web/.svelte-kit/output/client/_app/immutable/chunks/Cegv0r8x.js +1 -0
  459. package/web/.svelte-kit/output/client/_app/immutable/chunks/DU91Ml7U.js +3 -0
  460. package/web/.svelte-kit/output/client/_app/immutable/chunks/DmdO6ygw.js +1 -0
  461. package/web/.svelte-kit/output/client/_app/immutable/chunks/HKNo9LID.js +5 -0
  462. package/web/.svelte-kit/output/client/_app/immutable/chunks/U4ip-C0d.js +2 -0
  463. package/web/.svelte-kit/output/client/_app/immutable/chunks/cgUjKIhX.js +2 -0
  464. package/web/.svelte-kit/output/client/_app/immutable/entry/app.CGIBnoln.js +2 -0
  465. package/web/.svelte-kit/output/client/_app/immutable/entry/start.CJk8zB1j.js +1 -0
  466. package/web/.svelte-kit/output/client/_app/immutable/nodes/0.CqlJ9a31.js +1 -0
  467. package/web/.svelte-kit/output/client/_app/immutable/nodes/1.BQUZh2-w.js +1 -0
  468. package/web/.svelte-kit/output/client/_app/immutable/nodes/2.CCV1YdgF.js +1 -0
  469. package/web/.svelte-kit/output/client/_app/immutable/nodes/3.D9tDCdq8.js +1 -0
  470. package/web/.svelte-kit/output/client/_app/immutable/nodes/4.BqPyNkFA.js +6 -0
  471. package/web/.svelte-kit/output/client/_app/version.json +1 -0
  472. package/web/.svelte-kit/output/client/robots.txt +3 -0
  473. package/web/.svelte-kit/output/server/.vite/manifest.json +408 -0
  474. package/web/.svelte-kit/output/server/_app/immutable/assets/AllSessionsPanel.BKhqOrbV.css +1 -0
  475. package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.WptSHSUl.css +1 -0
  476. package/web/.svelte-kit/output/server/_app/immutable/assets/_page.DldLgTc-.css +1 -0
  477. package/web/.svelte-kit/output/server/_app/immutable/assets/_page.DoNWy7tW.css +1 -0
  478. package/web/.svelte-kit/output/server/chunks/AllSessionsPanel.svelte_svelte_type_style_lang.js +49 -0
  479. package/web/.svelte-kit/output/server/chunks/alert-dialog-description.js +2670 -0
  480. package/web/.svelte-kit/output/server/chunks/auth.js +59 -0
  481. package/web/.svelte-kit/output/server/chunks/button.js +82 -0
  482. package/web/.svelte-kit/output/server/chunks/client.js +29 -0
  483. package/web/.svelte-kit/output/server/chunks/context.js +133 -0
  484. package/web/.svelte-kit/output/server/chunks/environment.js +34 -0
  485. package/web/.svelte-kit/output/server/chunks/events.js +121 -0
  486. package/web/.svelte-kit/output/server/chunks/exports.js +174 -0
  487. package/web/.svelte-kit/output/server/chunks/false.js +4 -0
  488. package/web/.svelte-kit/output/server/chunks/index.js +59 -0
  489. package/web/.svelte-kit/output/server/chunks/index2.js +2828 -0
  490. package/web/.svelte-kit/output/server/chunks/internal.js +920 -0
  491. package/web/.svelte-kit/output/server/chunks/pane.js +82 -0
  492. package/web/.svelte-kit/output/server/chunks/sessions-json.js +124 -0
  493. package/web/.svelte-kit/output/server/chunks/sessions.svelte.js +229 -0
  494. package/web/.svelte-kit/output/server/chunks/shared.js +542 -0
  495. package/web/.svelte-kit/output/server/chunks/state.svelte.js +16 -0
  496. package/web/.svelte-kit/output/server/chunks/utils.js +43 -0
  497. package/web/.svelte-kit/output/server/chunks/ws-handlers.js +782 -0
  498. package/web/.svelte-kit/output/server/entries/endpoints/api/auth/login/_server.ts.js +22 -0
  499. package/web/.svelte-kit/output/server/entries/endpoints/api/auth/logout/_server.ts.js +9 -0
  500. package/web/.svelte-kit/output/server/entries/endpoints/api/beads/_server.ts.js +22 -0
  501. package/web/.svelte-kit/output/server/entries/endpoints/api/browse/_server.ts.js +50 -0
  502. package/web/.svelte-kit/output/server/entries/endpoints/api/chrome/_server.ts.js +30 -0
  503. package/web/.svelte-kit/output/server/entries/endpoints/api/files/image/_server.ts.js +53 -0
  504. package/web/.svelte-kit/output/server/entries/endpoints/api/health/_server.ts.js +7 -0
  505. package/web/.svelte-kit/output/server/entries/endpoints/api/projects/new-session/_server.ts.js +44 -0
  506. package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_id_/_server.ts.js +20 -0
  507. package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_id_/kill/_server.ts.js +36 -0
  508. package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_id_/restart/_server.ts.js +40 -0
  509. package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_id_/screenshots/_server.ts.js +28 -0
  510. package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_id_/send/_server.ts.js +29 -0
  511. package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_server.ts.js +49 -0
  512. package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_target_/output/_server.ts.js +14 -0
  513. package/web/.svelte-kit/output/server/entries/endpoints/api/tmux/panes/_server.ts.js +21 -0
  514. package/web/.svelte-kit/output/server/entries/fallbacks/error.svelte.js +27 -0
  515. package/web/.svelte-kit/output/server/entries/hooks.server.js +105 -0
  516. package/web/.svelte-kit/output/server/entries/pages/_layout.svelte.js +499 -0
  517. package/web/.svelte-kit/output/server/entries/pages/_page.svelte.js +3057 -0
  518. package/web/.svelte-kit/output/server/entries/pages/login/_page.server.ts.js +15 -0
  519. package/web/.svelte-kit/output/server/entries/pages/login/_page.svelte.js +37 -0
  520. package/web/.svelte-kit/output/server/entries/pages/session/_target_/_page.svelte.js +653 -0
  521. package/web/.svelte-kit/output/server/index.js +3864 -0
  522. package/web/.svelte-kit/output/server/internal.js +13 -0
  523. package/web/.svelte-kit/output/server/manifest-full.js +167 -0
  524. package/web/.svelte-kit/output/server/manifest.js +167 -0
  525. package/web/.svelte-kit/output/server/nodes/0.js +8 -0
  526. package/web/.svelte-kit/output/server/nodes/1.js +8 -0
  527. package/web/.svelte-kit/output/server/nodes/2.js +8 -0
  528. package/web/.svelte-kit/output/server/nodes/3.js +10 -0
  529. package/web/.svelte-kit/output/server/nodes/4.js +8 -0
  530. package/web/.svelte-kit/output/server/remote-entry.js +541 -0
  531. package/web/.svelte-kit/tsconfig.json +58 -0
  532. package/web/.svelte-kit/types/route_meta_data.json +55 -0
  533. package/web/.svelte-kit/types/src/routes/$types.d.ts +24 -0
  534. package/web/.svelte-kit/types/src/routes/api/auth/login/$types.d.ts +10 -0
  535. package/web/.svelte-kit/types/src/routes/api/auth/logout/$types.d.ts +10 -0
  536. package/web/.svelte-kit/types/src/routes/api/beads/$types.d.ts +10 -0
  537. package/web/.svelte-kit/types/src/routes/api/browse/$types.d.ts +10 -0
  538. package/web/.svelte-kit/types/src/routes/api/chrome/$types.d.ts +10 -0
  539. package/web/.svelte-kit/types/src/routes/api/files/image/$types.d.ts +10 -0
  540. package/web/.svelte-kit/types/src/routes/api/health/$types.d.ts +10 -0
  541. package/web/.svelte-kit/types/src/routes/api/projects/new-session/$types.d.ts +10 -0
  542. package/web/.svelte-kit/types/src/routes/api/sessions/$types.d.ts +10 -0
  543. package/web/.svelte-kit/types/src/routes/api/sessions/[id]/$types.d.ts +11 -0
  544. package/web/.svelte-kit/types/src/routes/api/sessions/[id]/kill/$types.d.ts +11 -0
  545. package/web/.svelte-kit/types/src/routes/api/sessions/[id]/restart/$types.d.ts +11 -0
  546. package/web/.svelte-kit/types/src/routes/api/sessions/[id]/screenshots/$types.d.ts +11 -0
  547. package/web/.svelte-kit/types/src/routes/api/sessions/[id]/send/$types.d.ts +11 -0
  548. package/web/.svelte-kit/types/src/routes/api/sessions/[target]/output/$types.d.ts +11 -0
  549. package/web/.svelte-kit/types/src/routes/api/tmux/panes/$types.d.ts +10 -0
  550. package/web/.svelte-kit/types/src/routes/login/$types.d.ts +25 -0
  551. package/web/.svelte-kit/types/src/routes/login/proxy+page.server.ts +19 -0
  552. package/web/.svelte-kit/types/src/routes/session/[target]/$types.d.ts +19 -0
  553. package/web/README.md +42 -0
  554. package/web/components.json +16 -0
  555. package/web/package.json +35 -0
  556. package/web/src/app.css +128 -0
  557. package/web/src/app.d.ts +13 -0
  558. package/web/src/app.html +11 -0
  559. package/web/src/hooks.server.ts +156 -0
  560. package/web/src/lib/assets/favicon.svg +1 -0
  561. package/web/src/lib/components/AllSessionsPanel.svelte +789 -0
  562. package/web/src/lib/components/BeadsPanel.svelte +146 -0
  563. package/web/src/lib/components/IssueItem.svelte +287 -0
  564. package/web/src/lib/components/ScreenshotsPanel.svelte +336 -0
  565. package/web/src/lib/components/SessionsSidebar.svelte +312 -0
  566. package/web/src/lib/components/TerminalRenderer.svelte +189 -0
  567. package/web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte +18 -0
  568. package/web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte +18 -0
  569. package/web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte +29 -0
  570. package/web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte +17 -0
  571. package/web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte +20 -0
  572. package/web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte +20 -0
  573. package/web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte +20 -0
  574. package/web/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte +7 -0
  575. package/web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte +17 -0
  576. package/web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte +7 -0
  577. package/web/src/lib/components/ui/alert-dialog/alert-dialog.svelte +7 -0
  578. package/web/src/lib/components/ui/alert-dialog/index.ts +37 -0
  579. package/web/src/lib/components/ui/badge/badge.svelte +50 -0
  580. package/web/src/lib/components/ui/badge/index.ts +2 -0
  581. package/web/src/lib/components/ui/button/button.svelte +86 -0
  582. package/web/src/lib/components/ui/button/index.ts +17 -0
  583. package/web/src/lib/components/ui/checkbox/checkbox.svelte +36 -0
  584. package/web/src/lib/components/ui/checkbox/index.ts +6 -0
  585. package/web/src/lib/components/ui/dialog/dialog-close.svelte +7 -0
  586. package/web/src/lib/components/ui/dialog/dialog-content.svelte +45 -0
  587. package/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
  588. package/web/src/lib/components/ui/dialog/dialog-footer.svelte +20 -0
  589. package/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  590. package/web/src/lib/components/ui/dialog/dialog-overlay.svelte +20 -0
  591. package/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
  592. package/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
  593. package/web/src/lib/components/ui/dialog/dialog-trigger.svelte +7 -0
  594. package/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
  595. package/web/src/lib/components/ui/dialog/index.ts +34 -0
  596. package/web/src/lib/components/ui/scroll-area/index.ts +10 -0
  597. package/web/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte +31 -0
  598. package/web/src/lib/components/ui/scroll-area/scroll-area.svelte +43 -0
  599. package/web/src/lib/components/ui/textarea/index.ts +7 -0
  600. package/web/src/lib/components/ui/textarea/textarea.svelte +23 -0
  601. package/web/src/lib/index.ts +1 -0
  602. package/web/src/lib/server/auth.ts +90 -0
  603. package/web/src/lib/stores/beads.svelte.ts +163 -0
  604. package/web/src/lib/stores/input-injection.svelte.ts +39 -0
  605. package/web/src/lib/stores/preferences.svelte.ts +55 -0
  606. package/web/src/lib/stores/sessions.svelte.ts +108 -0
  607. package/web/src/lib/stores/terminal.svelte.ts +96 -0
  608. package/web/src/lib/stores/websocket-base.svelte.ts +209 -0
  609. package/web/src/lib/types/terminal.ts +31 -0
  610. package/web/src/lib/utils/terminal-parser.ts +239 -0
  611. package/web/src/lib/utils.ts +13 -0
  612. package/web/src/routes/+layout.svelte +450 -0
  613. package/web/src/routes/+page.svelte +19 -0
  614. package/web/src/routes/api/auth/login/+server.ts +34 -0
  615. package/web/src/routes/api/auth/logout/+server.ts +10 -0
  616. package/web/src/routes/api/beads/+server.ts +28 -0
  617. package/web/src/routes/api/browse/+server.ts +59 -0
  618. package/web/src/routes/api/chrome/+server.ts +35 -0
  619. package/web/src/routes/api/files/image/+server.ts +64 -0
  620. package/web/src/routes/api/health/+server.ts +6 -0
  621. package/web/src/routes/api/projects/new-session/+server.ts +50 -0
  622. package/web/src/routes/api/sessions/+server.ts +62 -0
  623. package/web/src/routes/api/sessions/[id]/+server.ts +19 -0
  624. package/web/src/routes/api/sessions/[id]/kill/+server.ts +46 -0
  625. package/web/src/routes/api/sessions/[id]/restart/+server.ts +59 -0
  626. package/web/src/routes/api/sessions/[id]/screenshots/+server.ts +32 -0
  627. package/web/src/routes/api/sessions/[id]/send/+server.ts +31 -0
  628. package/web/src/routes/api/sessions/[target]/output/+server.ts +13 -0
  629. package/web/src/routes/api/tmux/panes/+server.ts +32 -0
  630. package/web/src/routes/login/+page.server.ts +18 -0
  631. package/web/src/routes/login/+page.svelte +69 -0
  632. package/web/src/routes/session/[target]/+page.svelte +450 -0
  633. package/web/static/robots.txt +3 -0
  634. package/web/svelte.config.js +20 -0
  635. package/web/tsconfig.json +20 -0
  636. package/web/vite.config.ts +154 -0
@@ -0,0 +1,108 @@
1
+ import { browser } from '$app/environment';
2
+ import { ReliableWebSocket } from './websocket-base.svelte';
3
+
4
+ export interface Screenshot {
5
+ path: string;
6
+ timestamp: number;
7
+ }
8
+
9
+ export interface Session {
10
+ v: number;
11
+ id: string;
12
+ pid: number;
13
+ cwd: string;
14
+ git_root: string | null;
15
+ beads_enabled: boolean;
16
+ tmux_target: string | null;
17
+ state: 'busy' | 'idle' | 'waiting' | 'permission';
18
+ current_action: string | null;
19
+ prompt_text: string | null;
20
+ last_update: number;
21
+ pane_title?: string | null;
22
+ screenshots?: Screenshot[];
23
+ chrome_active?: boolean;
24
+ }
25
+
26
+ class SessionStore extends ReliableWebSocket {
27
+ sessions = $state<Session[]>([]);
28
+ paused = $state(false);
29
+
30
+ // Saved projects from localStorage
31
+ savedProjects = $state<string[]>([]);
32
+
33
+ protected getWsUrl(): string {
34
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
35
+ return `${protocol}//${window.location.host}/api/sessions/stream`;
36
+ }
37
+
38
+ protected getLogPrefix(): string {
39
+ return '[sessions]';
40
+ }
41
+
42
+ protected handleMessage(event: MessageEvent): void {
43
+ if (this.paused) return;
44
+ const data = JSON.parse(event.data);
45
+ if (data.sessions) {
46
+ this.sessions = data.sessions;
47
+ }
48
+ }
49
+
50
+ connect(): void {
51
+ this.doConnect();
52
+ }
53
+
54
+ disconnect(): void {
55
+ this.doDisconnect();
56
+ }
57
+
58
+ togglePause(): void {
59
+ this.paused = !this.paused;
60
+ }
61
+
62
+ loadSavedProjects(): void {
63
+ if (!browser) return;
64
+ try {
65
+ this.savedProjects = JSON.parse(localStorage.getItem('claude-mux-projects') || '[]');
66
+ } catch {
67
+ this.savedProjects = [];
68
+ }
69
+ }
70
+
71
+ saveProject(cwd: string): void {
72
+ if (!browser || this.savedProjects.includes(cwd)) return;
73
+ this.savedProjects = [...this.savedProjects, cwd];
74
+ localStorage.setItem('claude-mux-projects', JSON.stringify(this.savedProjects));
75
+ }
76
+
77
+ removeProject(cwd: string): void {
78
+ this.savedProjects = this.savedProjects.filter((p) => p !== cwd);
79
+ localStorage.setItem('claude-mux-projects', JSON.stringify(this.savedProjects));
80
+ }
81
+ }
82
+
83
+ export const sessionStore = new SessionStore();
84
+
85
+ // Helper functions
86
+ export function stateColor(state: string): string {
87
+ switch (state) {
88
+ case 'permission':
89
+ case 'waiting':
90
+ return '#e74c3c';
91
+ case 'idle':
92
+ return '#f39c12';
93
+ case 'busy':
94
+ return '#27ae60';
95
+ default:
96
+ return '#666';
97
+ }
98
+ }
99
+
100
+ export function getProjectColor(cwd: string): string {
101
+ // Generate a consistent color based on path hash
102
+ let hash = 0;
103
+ for (let i = 0; i < cwd.length; i++) {
104
+ hash = cwd.charCodeAt(i) + ((hash << 5) - hash);
105
+ }
106
+ const hue = Math.abs(hash) % 360;
107
+ return `hsl(${hue}, 60%, 40%)`;
108
+ }
@@ -0,0 +1,96 @@
1
+ import { browser } from '$app/environment';
2
+ import { ReliableWebSocket } from './websocket-base.svelte';
3
+ import { parseTerminalOutput, getBlockStats } from '$lib/utils/terminal-parser';
4
+ import type { ParsedBlock } from '$lib/types/terminal';
5
+
6
+ class TerminalStore extends ReliableWebSocket {
7
+ output = $state('');
8
+
9
+ // Derived parsed blocks - automatically recomputed when output changes
10
+ parsedBlocks: ParsedBlock[] = $derived(parseTerminalOutput(this.output));
11
+
12
+ // Derived stats for UI indicators
13
+ stats = $derived(getBlockStats(this.parsedBlocks));
14
+
15
+ private target: string | null = null;
16
+ private resizeTimer: ReturnType<typeof setTimeout> | null = null;
17
+ private lastSentSize: { cols: number; rows: number } | null = null;
18
+
19
+ protected getWsUrl(): string {
20
+ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
21
+ const encodedTarget = encodeURIComponent(this.target!);
22
+ return `${protocol}//${window.location.host}/api/sessions/${encodedTarget}/stream`;
23
+ }
24
+
25
+ protected getLogPrefix(): string {
26
+ return '[terminal]';
27
+ }
28
+
29
+ protected shouldReconnect(): boolean {
30
+ return this.target !== null;
31
+ }
32
+
33
+ protected handleMessage(event: MessageEvent): void {
34
+ const data = JSON.parse(event.data);
35
+ if (data.output !== undefined) {
36
+ this.output = data.output;
37
+ }
38
+ }
39
+
40
+ connect(target: string | null | undefined): void {
41
+ if (!browser || !target) return;
42
+
43
+ // If already connected to the same target, do nothing
44
+ if (this.ws && this.target === target) return;
45
+
46
+ // If connected to a different target, close old connection first
47
+ if (this.ws) {
48
+ // Disconnect without allowing reconnect (target will be null temporarily)
49
+ const oldTarget = this.target;
50
+ this.target = null; // Prevent reconnect in doDisconnect
51
+ this.doDisconnect();
52
+ this.target = oldTarget;
53
+ }
54
+
55
+ // Clear output when switching to a different target
56
+ if (this.target !== target) {
57
+ this.output = '';
58
+ }
59
+
60
+ this.target = target;
61
+ this.doConnect();
62
+ }
63
+
64
+ disconnect(): void {
65
+ // Cancel resize timer
66
+ if (this.resizeTimer) {
67
+ clearTimeout(this.resizeTimer);
68
+ this.resizeTimer = null;
69
+ }
70
+ this.lastSentSize = null;
71
+
72
+ // Clear target before disconnecting to prevent reconnect
73
+ this.target = null;
74
+ this.doDisconnect();
75
+ }
76
+
77
+ sendResize(cols: number, rows: number): void {
78
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
79
+
80
+ // Skip if same as last sent
81
+ if (this.lastSentSize?.cols === cols && this.lastSentSize?.rows === rows) return;
82
+
83
+ // Debounce
84
+ if (this.resizeTimer) clearTimeout(this.resizeTimer);
85
+
86
+ this.resizeTimer = setTimeout(() => {
87
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
88
+ this.ws.send(JSON.stringify({ type: 'resize', cols, rows }));
89
+ this.lastSentSize = { cols, rows };
90
+ }
91
+ this.resizeTimer = null;
92
+ }, 150);
93
+ }
94
+ }
95
+
96
+ export const terminalStore = new TerminalStore();
@@ -0,0 +1,209 @@
1
+ import { browser } from '$app/environment';
2
+
3
+ /**
4
+ * Configuration for reliable WebSocket connections.
5
+ * Tuned for mobile networks where connections drop frequently.
6
+ */
7
+ export interface WebSocketConfig {
8
+ /** Keep-alive ping interval in ms (default: 30s) */
9
+ pingInterval?: number;
10
+ /** Max time to wait for pong before considering connection dead (default: 10s) */
11
+ pongTimeout?: number;
12
+ /** Initial reconnect delay in ms (default: 1s) */
13
+ baseReconnectDelay?: number;
14
+ /** Maximum reconnect delay in ms (default: 30s) */
15
+ maxReconnectDelay?: number;
16
+ }
17
+
18
+ const DEFAULT_CONFIG: Required<WebSocketConfig> = {
19
+ pingInterval: 30000,
20
+ pongTimeout: 10000,
21
+ baseReconnectDelay: 1000,
22
+ maxReconnectDelay: 30000
23
+ };
24
+
25
+ /**
26
+ * Base class for reliable WebSocket connections with:
27
+ * - Ping/pong keep-alive for detecting stale connections
28
+ * - Exponential backoff with jitter for reconnection
29
+ * - Visibility change handling for mobile background/foreground transitions
30
+ */
31
+ export abstract class ReliableWebSocket {
32
+ connected = $state(false);
33
+
34
+ protected ws: WebSocket | null = null;
35
+ private pingTimer: ReturnType<typeof setInterval> | null = null;
36
+ private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
37
+ private lastPong: number = 0;
38
+ private reconnectAttempts: number = 0;
39
+ private visibilityHandler: (() => void) | null = null;
40
+ private config: Required<WebSocketConfig>;
41
+
42
+ constructor(config?: WebSocketConfig) {
43
+ this.config = { ...DEFAULT_CONFIG, ...config };
44
+ }
45
+
46
+ /** Subclass must provide the WebSocket URL */
47
+ protected abstract getWsUrl(): string;
48
+
49
+ /** Subclass must handle incoming messages (after pong filtering) */
50
+ protected abstract handleMessage(event: MessageEvent): void;
51
+
52
+ /** Subclass can override to control reconnection (e.g., only reconnect if target is set) */
53
+ protected shouldReconnect(): boolean {
54
+ return true;
55
+ }
56
+
57
+ /** Subclass can override to run code on successful connection */
58
+ protected onConnected(): void {}
59
+
60
+ /** Subclass can override to run code on disconnection */
61
+ protected onDisconnected(): void {}
62
+
63
+ /** Get the log prefix for debug messages */
64
+ protected abstract getLogPrefix(): string;
65
+
66
+ protected doConnect(): void {
67
+ if (!browser || this.ws) return;
68
+
69
+ const url = this.getWsUrl();
70
+ this.ws = new WebSocket(url);
71
+
72
+ this.ws.onopen = () => {
73
+ this.connected = true;
74
+ this.reconnectAttempts = 0;
75
+ this.lastPong = Date.now();
76
+ if (this.reconnectTimer) {
77
+ clearTimeout(this.reconnectTimer);
78
+ this.reconnectTimer = null;
79
+ }
80
+ this.startPingTimer();
81
+ this.setupVisibilityHandler();
82
+ this.onConnected();
83
+ };
84
+
85
+ this.ws.onmessage = (event) => {
86
+ // Handle pong response
87
+ if (event.data === 'pong') {
88
+ this.lastPong = Date.now();
89
+ return;
90
+ }
91
+ this.handleMessage(event);
92
+ };
93
+
94
+ this.ws.onclose = () => {
95
+ this.connected = false;
96
+ this.ws = null;
97
+ this.stopPingTimer();
98
+ this.onDisconnected();
99
+ if (this.shouldReconnect()) {
100
+ this.scheduleReconnect();
101
+ }
102
+ };
103
+
104
+ this.ws.onerror = () => {
105
+ this.ws?.close();
106
+ };
107
+ }
108
+
109
+ protected doDisconnect(): void {
110
+ if (this.reconnectTimer) {
111
+ clearTimeout(this.reconnectTimer);
112
+ this.reconnectTimer = null;
113
+ }
114
+
115
+ this.stopPingTimer();
116
+ this.removeVisibilityHandler();
117
+ this.connected = false;
118
+ this.reconnectAttempts = 0;
119
+
120
+ if (this.ws) {
121
+ this.ws.onopen = null;
122
+ this.ws.onclose = null;
123
+ this.ws.onerror = null;
124
+ this.ws.onmessage = null;
125
+ if (this.ws.readyState !== WebSocket.CLOSED) {
126
+ this.ws.close();
127
+ }
128
+ this.ws = null;
129
+ }
130
+ }
131
+
132
+ /** Force reconnection (resets backoff) */
133
+ protected forceReconnect(): void {
134
+ this.reconnectAttempts = 0;
135
+ if (this.ws) {
136
+ this.ws.onclose = null; // Prevent normal onclose from scheduling reconnect
137
+ this.ws.close();
138
+ this.ws = null;
139
+ }
140
+ this.stopPingTimer();
141
+ this.connected = false;
142
+ this.doConnect();
143
+ }
144
+
145
+ private startPingTimer(): void {
146
+ this.stopPingTimer();
147
+ this.pingTimer = setInterval(() => {
148
+ if (this.ws?.readyState === WebSocket.OPEN) {
149
+ // Check if connection is stale (no pong received recently)
150
+ if (Date.now() - this.lastPong > this.config.pingInterval + this.config.pongTimeout) {
151
+ if (import.meta.env.DEV) console.debug(`${this.getLogPrefix()} Connection stale, forcing reconnect`);
152
+ this.ws?.close();
153
+ return;
154
+ }
155
+ this.ws.send('ping');
156
+ }
157
+ }, this.config.pingInterval);
158
+ }
159
+
160
+ private stopPingTimer(): void {
161
+ if (this.pingTimer) {
162
+ clearInterval(this.pingTimer);
163
+ this.pingTimer = null;
164
+ }
165
+ }
166
+
167
+ private scheduleReconnect(): void {
168
+ if (this.reconnectTimer) return;
169
+
170
+ // Exponential backoff with jitter
171
+ const delay = Math.min(
172
+ this.config.baseReconnectDelay * Math.pow(2, this.reconnectAttempts) + Math.random() * 1000,
173
+ this.config.maxReconnectDelay
174
+ );
175
+ this.reconnectAttempts++;
176
+
177
+ if (import.meta.env.DEV) console.debug(`${this.getLogPrefix()} Reconnecting in ${Math.round(delay)}ms (attempt ${this.reconnectAttempts})`);
178
+ this.reconnectTimer = setTimeout(() => {
179
+ this.reconnectTimer = null;
180
+ this.doConnect();
181
+ }, delay);
182
+ }
183
+
184
+ private setupVisibilityHandler(): void {
185
+ if (this.visibilityHandler) return;
186
+
187
+ this.visibilityHandler = () => {
188
+ if (document.visibilityState === 'visible' && this.shouldReconnect()) {
189
+ if (import.meta.env.DEV) console.debug(`${this.getLogPrefix()} Page visible, checking connection`);
190
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
191
+ if (import.meta.env.DEV) console.debug(`${this.getLogPrefix()} Connection lost while hidden, reconnecting`);
192
+ this.forceReconnect();
193
+ } else {
194
+ // Send a ping to verify connection is alive
195
+ this.ws.send('ping');
196
+ }
197
+ }
198
+ };
199
+
200
+ document.addEventListener('visibilitychange', this.visibilityHandler);
201
+ }
202
+
203
+ private removeVisibilityHandler(): void {
204
+ if (this.visibilityHandler) {
205
+ document.removeEventListener('visibilitychange', this.visibilityHandler);
206
+ this.visibilityHandler = null;
207
+ }
208
+ }
209
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Terminal output block types for visual differentiation
3
+ */
4
+ export type BlockType =
5
+ | 'user-prompt' // Lines starting with ❯
6
+ | 'claude-response' // Lines starting with ●
7
+ | 'tool-call' // Tool invocations like "● Bash(ls)"
8
+ | 'tool-result' // Lines starting with ⎿
9
+ | 'separator' // Lines starting with ─────
10
+ | 'status' // Status bar content (Esc to interrupt, etc.)
11
+ | 'spinner' // Active spinner animation
12
+ | 'plain'; // Unclassified content
13
+
14
+ /**
15
+ * A parsed block of terminal output with type classification
16
+ */
17
+ export interface ParsedBlock {
18
+ /** Unique identifier for Svelte keyed each */
19
+ id: number;
20
+ /** The type of content this block represents */
21
+ type: BlockType;
22
+ /** The raw text content of this block */
23
+ content: string;
24
+ /** Optional metadata extracted from the content */
25
+ metadata?: {
26
+ /** Tool name for tool-call blocks */
27
+ toolName?: string;
28
+ /** Whether this block appears complete */
29
+ isComplete?: boolean;
30
+ };
31
+ }
@@ -0,0 +1,239 @@
1
+ import type { BlockType, ParsedBlock } from '$lib/types/terminal';
2
+
3
+ /**
4
+ * Regex patterns for Claude Code visual elements
5
+ */
6
+ const PATTERNS = {
7
+ // User prompt starts with ❯ (Unicode chevron only - ASCII > is used for selection indicators)
8
+ userPrompt: /^❯\s/,
9
+ // Claude response starts with ● (filled circle) followed by actual text
10
+ claudeResponse: /^●\s+\S/,
11
+ // Working indicator: just ● alone or with whitespace (no content after)
12
+ workingIndicator: /^●\s*$/,
13
+ // Tool result starts with ⎿ (with optional leading whitespace)
14
+ toolResult: /^(\s*)⎿/,
15
+ // Indented content (2+ spaces at start) - continues tool results
16
+ indentedContent: /^(\s{2,}|\t)/,
17
+ // Separator is 5+ dashes
18
+ separator: /^─{5,}/,
19
+ // Tool call: ● ToolName(...) or ● tool-name (...)
20
+ toolCall: /^●\s+([\w-]+)\s*\(/,
21
+ // MCP tool call: ● mcp-server - tool_name (MCP)
22
+ mcpToolCall: /^●\s+([\w-]+)\s+-\s+([\w_]+)\s+\(MCP\)/,
23
+ // Braille spinner characters
24
+ spinner: /[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏⠐⠂⠄]/,
25
+ // Status hints
26
+ statusHint: /(Esc to interrupt|ctrl\+c to interrupt|Esc to cancel|to cycle\))/i,
27
+ // Progress bar or status line at bottom
28
+ progressBar: /^\s*[\w-]+\s+\[.*\]\s+\w+@/
29
+ };
30
+
31
+ /**
32
+ * Classify a single line of terminal output
33
+ */
34
+ function classifyLine(line: string, previousType: BlockType | null): BlockType {
35
+ // Check for separator first (most specific)
36
+ if (PATTERNS.separator.test(line)) return 'separator';
37
+
38
+ // Check for MCP tool call
39
+ if (PATTERNS.mcpToolCall.test(line)) return 'tool-call';
40
+
41
+ // Check for regular tool call
42
+ if (PATTERNS.toolCall.test(line)) return 'tool-call';
43
+
44
+ // Check for working indicator (just ● with no content) - treat as spinner
45
+ if (PATTERNS.workingIndicator.test(line)) return 'spinner';
46
+
47
+ // Check for user prompt
48
+ if (PATTERNS.userPrompt.test(line)) return 'user-prompt';
49
+
50
+ // Check for Claude response (but not tool call)
51
+ if (PATTERNS.claudeResponse.test(line)) return 'claude-response';
52
+
53
+ // Check for tool result
54
+ if (PATTERNS.toolResult.test(line)) return 'tool-result';
55
+
56
+ // Indented content continues tool calls (multi-line arguments)
57
+ if (previousType === 'tool-call' && PATTERNS.indentedContent.test(line)) {
58
+ return 'tool-call';
59
+ }
60
+
61
+ // Indented content continues tool results
62
+ if (previousType === 'tool-result' && PATTERNS.indentedContent.test(line)) {
63
+ return 'tool-result';
64
+ }
65
+
66
+ // Check for status/progress indicators
67
+ if (PATTERNS.statusHint.test(line) || PATTERNS.progressBar.test(line)) return 'status';
68
+
69
+ // Check for active spinner
70
+ if (PATTERNS.spinner.test(line) && line.length < 100) return 'spinner';
71
+
72
+ return 'plain';
73
+ }
74
+
75
+ /**
76
+ * Extract tool name from a tool call line
77
+ */
78
+ function extractToolName(line: string): string | undefined {
79
+ // Try MCP tool format first
80
+ const mcpMatch = line.match(PATTERNS.mcpToolCall);
81
+ if (mcpMatch) {
82
+ return `${mcpMatch[1]}:${mcpMatch[2]}`;
83
+ }
84
+
85
+ // Try regular tool format
86
+ const match = line.match(PATTERNS.toolCall);
87
+ if (match) {
88
+ return match[1];
89
+ }
90
+
91
+ return undefined;
92
+ }
93
+
94
+ /**
95
+ * Check if a line is a genuine new tool call (not just continuation)
96
+ */
97
+ function isNewToolCall(line: string): boolean {
98
+ return PATTERNS.toolCall.test(line) || PATTERNS.mcpToolCall.test(line);
99
+ }
100
+
101
+ /**
102
+ * Transition table: defines when to CONTINUE (false) vs BREAK (true) blocks.
103
+ * true = start new block, false = continue current block, undefined = use default (break on type change)
104
+ *
105
+ * Format: TRANSITIONS[currentType][newType] = shouldBreak
106
+ */
107
+ const TRANSITIONS: Record<BlockType, Partial<Record<BlockType, boolean>>> = {
108
+ 'user-prompt': {
109
+ 'plain': false, // Multi-line user input continues
110
+ 'spinner': false, // Spinners during input don't break
111
+ },
112
+ 'claude-response': {
113
+ 'plain': false, // Response text continues
114
+ 'spinner': false, // Spinners during response don't break
115
+ },
116
+ 'tool-call': {
117
+ 'tool-call': false, // Continuation lines (handled specially for new tool calls)
118
+ 'tool-result': false, // Results follow tool calls
119
+ 'spinner': false, // Spinners during execution don't break
120
+ },
121
+ 'tool-result': {
122
+ 'tool-result': false, // Multiple result lines continue
123
+ 'spinner': false, // Spinners during results don't break
124
+ },
125
+ 'separator': {
126
+ // Separators always break - no continues
127
+ },
128
+ 'status': {
129
+ 'status': false, // Status lines group together
130
+ },
131
+ 'spinner': {
132
+ 'spinner': false, // Multiple spinner frames group together
133
+ },
134
+ 'plain': {
135
+ 'plain': false, // Plain content groups together
136
+ },
137
+ };
138
+
139
+ /**
140
+ * Determine if we should start a new block based on current and new type.
141
+ * Uses explicit transition table for clarity and maintainability.
142
+ */
143
+ function shouldStartNewBlock(current: ParsedBlock | null, newType: BlockType, line: string): boolean {
144
+ if (!current) return true;
145
+
146
+ // Separators and user prompts always start new blocks
147
+ if (newType === 'separator' || newType === 'user-prompt') {
148
+ return true;
149
+ }
150
+
151
+ // Special case: new tool calls always start new blocks, but continuations don't
152
+ if (newType === 'tool-call' && isNewToolCall(line)) {
153
+ return true;
154
+ }
155
+
156
+ // Look up transition in table
157
+ const transition = TRANSITIONS[current.type]?.[newType];
158
+
159
+ // If explicitly defined, use that
160
+ if (transition !== undefined) {
161
+ return transition;
162
+ }
163
+
164
+ // Default: break on type change
165
+ return current.type !== newType;
166
+ }
167
+
168
+ /**
169
+ * Parse terminal output into typed blocks
170
+ */
171
+ export function parseTerminalOutput(output: string): ParsedBlock[] {
172
+ if (!output || output.trim() === '') {
173
+ return [];
174
+ }
175
+
176
+ const lines = output.split('\n');
177
+ const blocks: ParsedBlock[] = [];
178
+ let currentBlock: ParsedBlock | null = null;
179
+ let blockIdCounter = 0;
180
+
181
+ for (const line of lines) {
182
+ // Skip empty lines - they just add vertical space
183
+ if (line.trim() === '') {
184
+ continue;
185
+ }
186
+
187
+ const previousType = currentBlock?.type ?? null;
188
+ const blockType = classifyLine(line, previousType);
189
+
190
+ if (shouldStartNewBlock(currentBlock, blockType, line)) {
191
+ // Save current block if exists
192
+ if (currentBlock && currentBlock.content.trim()) {
193
+ blocks.push(currentBlock);
194
+ }
195
+
196
+ // Create new block
197
+ currentBlock = {
198
+ id: ++blockIdCounter,
199
+ type: blockType,
200
+ content: line
201
+ };
202
+
203
+ // Extract metadata for tool calls
204
+ if (blockType === 'tool-call') {
205
+ const toolName = extractToolName(line);
206
+ if (toolName) {
207
+ currentBlock.metadata = { toolName };
208
+ }
209
+ }
210
+ } else if (currentBlock) {
211
+ // Append to current block
212
+ currentBlock.content += '\n' + line;
213
+ }
214
+ }
215
+
216
+ // Don't forget the last block
217
+ if (currentBlock && currentBlock.content.trim()) {
218
+ blocks.push(currentBlock);
219
+ }
220
+
221
+ return blocks;
222
+ }
223
+
224
+ /**
225
+ * Get statistics about parsed blocks
226
+ */
227
+ export function getBlockStats(blocks: ParsedBlock[]): {
228
+ userPrompts: number;
229
+ claudeResponses: number;
230
+ toolCalls: number;
231
+ hasActiveSpinner: boolean;
232
+ } {
233
+ return {
234
+ userPrompts: blocks.filter((b) => b.type === 'user-prompt').length,
235
+ claudeResponses: blocks.filter((b) => b.type === 'claude-response').length,
236
+ toolCalls: blocks.filter((b) => b.type === 'tool-call').length,
237
+ hasActiveSpinner: blocks.some((b) => b.type === 'spinner')
238
+ };
239
+ }
@@ -0,0 +1,13 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
7
+
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T;
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+ export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T;
12
+ export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
13
+ export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };