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,255 @@
1
+ import { Command } from "commander";
2
+ import { render } from "ink";
3
+ import React from "react";
4
+ import { execSync } from "child_process";
5
+ import { existsSync, writeFileSync, unlinkSync, readFileSync, mkdirSync } from "fs";
6
+ import { createInterface } from "readline";
7
+ import { join } from "path";
8
+ import { App } from "../app.js";
9
+ import { isInTmux, getTmuxSessionName } from "../tmux/detect.js";
10
+ import { CLAUDE_WATCH_DIR, SESSIONS_DIR, DEFAULT_SERVER_PORT } from "../utils/paths.js";
11
+ import { VERSION } from "../utils/version.js";
12
+ import { isPidAlive } from "../utils/pid.js";
13
+ import {
14
+ checkHooksStatus,
15
+ getInstalledHooksVersion,
16
+ installHooks,
17
+ saveClaudeSettings,
18
+ } from "../setup/hooks.js";
19
+
20
+ const WATCH_SESSION = "watch";
21
+
22
+ /**
23
+ * Prompt user for input and return their response.
24
+ */
25
+ function promptUser(question: string): Promise<string> {
26
+ const rl = createInterface({
27
+ input: process.stdin,
28
+ output: process.stdout,
29
+ });
30
+
31
+ return new Promise((resolve) => {
32
+ rl.question(question, (answer) => {
33
+ rl.close();
34
+ resolve(answer);
35
+ });
36
+ });
37
+ }
38
+
39
+ export interface TuiOptions {
40
+ serve?: boolean;
41
+ port: string;
42
+ host: string;
43
+ }
44
+
45
+ export async function runTui(options: TuiOptions): Promise<void> {
46
+ // Check if running in tmux
47
+ if (!isInTmux()) {
48
+ console.error("claude-mux requires tmux to run.");
49
+ console.error("");
50
+ console.error("Start tmux first, then run claude-mux from inside tmux.");
51
+ process.exit(1);
52
+ }
53
+
54
+ // Check if we're in the correct session
55
+ const currentSession = getTmuxSessionName();
56
+ if (currentSession !== WATCH_SESSION) {
57
+ console.log(`Switching to '${WATCH_SESSION}' session...`);
58
+
59
+ // Build command to re-invoke claude-mux the same way it was originally called
60
+ const cwd = process.cwd();
61
+ // Escape single quotes in args for shell safety
62
+ const escapeArg = (arg: string) => `'${arg.replace(/'/g, "'\\''")}'`;
63
+ const originalCmd = process.argv.map(escapeArg).join(" ");
64
+ const fullCmd = `cd ${escapeArg(cwd)} && ${originalCmd}`;
65
+
66
+ try {
67
+ // Kill any existing watch session that isn't running claude-mux,
68
+ // then (re)create it with the command passed directly to new-session.
69
+ //
70
+ // We avoid tmux send-keys entirely because it races with shell init
71
+ // on macOS: zsh's compinit prompt intercepts keystrokes before the
72
+ // shell is ready, mangling the command (e.g. "cd" becoming "åWcd").
73
+ // Passing the command to new-session bypasses interactive shell init.
74
+
75
+ let needsCreate = true;
76
+ try {
77
+ execSync(`tmux has-session -t ${WATCH_SESSION} 2>/dev/null`, { stdio: "ignore" });
78
+ // Session exists - check if claude-mux is already running
79
+ try {
80
+ const paneCmd = execSync(
81
+ `tmux list-panes -t ${WATCH_SESSION} -F "#{pane_current_command}"`,
82
+ { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
83
+ ).trim();
84
+ if (paneCmd.includes("node") || paneCmd.includes("claude-mux")) {
85
+ // Already running, just switch to it
86
+ needsCreate = false;
87
+ } else {
88
+ // Session exists but claude-mux isn't running — add a new window
89
+ execSync(`tmux new-window -t ${WATCH_SESSION} ${escapeArg(fullCmd)}`, { stdio: "ignore" });
90
+ needsCreate = false;
91
+ }
92
+ } catch {
93
+ // Can't list panes — add a new window in the existing session
94
+ execSync(`tmux new-window -t ${WATCH_SESSION} ${escapeArg(fullCmd)}`, { stdio: "ignore" });
95
+ needsCreate = false;
96
+ }
97
+ } catch {
98
+ // Session doesn't exist
99
+ }
100
+
101
+ if (needsCreate) {
102
+ execSync(`tmux new-session -d -s ${WATCH_SESSION} ${escapeArg(fullCmd)}`, { stdio: "ignore" });
103
+ }
104
+ execSync(`tmux switch-client -t ${WATCH_SESSION}`, { stdio: "inherit" });
105
+ } catch (error) {
106
+ console.error("Failed to switch to watch session:", error);
107
+ process.exit(1);
108
+ }
109
+
110
+ process.exit(0);
111
+ }
112
+
113
+ // We're in the watch session, run the TUI
114
+
115
+ // Auto-create data directories if needed
116
+ if (!existsSync(CLAUDE_WATCH_DIR)) {
117
+ mkdirSync(CLAUDE_WATCH_DIR, { recursive: true });
118
+ }
119
+ if (!existsSync(SESSIONS_DIR)) {
120
+ mkdirSync(SESSIONS_DIR, { recursive: true });
121
+ }
122
+
123
+ // Check hooks version and prompt if needed
124
+ const hooksStatus = checkHooksStatus();
125
+ if (hooksStatus !== "current") {
126
+ const installedVersion = getInstalledHooksVersion();
127
+ const action = hooksStatus === "install" ? "installed" : "updated";
128
+ const currentInfo = installedVersion ? `installed: ${installedVersion}` : "not installed";
129
+
130
+ console.log(`claude-mux hooks need to be ${action} (${currentInfo}, required: ${VERSION})`);
131
+ console.log("");
132
+
133
+ const answer = await promptUser(`${hooksStatus === "install" ? "Install" : "Update"} hooks now? [Y/n/q]: `);
134
+ const normalized = answer.toLowerCase().trim();
135
+
136
+ if (normalized === "q") {
137
+ console.log("Exiting.");
138
+ process.exit(0);
139
+ } else if (normalized === "n") {
140
+ console.log("Skipping hook installation. Some features may not work correctly.");
141
+ console.log("");
142
+ } else {
143
+ // Default to Yes
144
+ console.log("Installing hooks...");
145
+ const { newSettings } = installHooks();
146
+ saveClaudeSettings(newSettings);
147
+ console.log("Hooks installed successfully.");
148
+ console.log("");
149
+ }
150
+ }
151
+
152
+ // Check if another instance is already running
153
+ const lockFile = join(CLAUDE_WATCH_DIR, "claude-mux.lock");
154
+ if (existsSync(lockFile)) {
155
+ try {
156
+ const lock = JSON.parse(readFileSync(lockFile, "utf-8"));
157
+ if (lock.pid && isPidAlive(lock.pid)) {
158
+ if (lock.version === VERSION) {
159
+ console.log("claude-mux is already running.");
160
+ if (lock.tmux_target) {
161
+ try {
162
+ execSync(`tmux switch-client -t "${lock.tmux_target}"`, { stdio: "inherit" });
163
+ } catch {
164
+ // Ignore - may already be in the right pane
165
+ }
166
+ }
167
+ process.exit(0);
168
+ } else {
169
+ // Different version — kill old instance and restart
170
+ console.log(`Restarting claude-mux (${lock.version || "unknown"} → ${VERSION})...`);
171
+ process.kill(lock.pid, "SIGTERM");
172
+ execSync("sleep 0.5", { stdio: "ignore" });
173
+ }
174
+ }
175
+ } catch {
176
+ // Stale or corrupt lock file, proceed
177
+ }
178
+ }
179
+
180
+ // Move window and pane to base indices so claude-mux is always at the first position
181
+ try {
182
+ const baseIndex = execSync('tmux show-options -gv base-index', {
183
+ encoding: "utf-8",
184
+ stdio: ["pipe", "pipe", "pipe"],
185
+ }).trim();
186
+ execSync(`tmux move-window -t ${baseIndex}`, { stdio: "ignore" });
187
+ } catch {
188
+ // Ignore - already at base index or move not possible
189
+ }
190
+ try {
191
+ const paneBaseIndex = execSync('tmux show-options -gv pane-base-index', {
192
+ encoding: "utf-8",
193
+ stdio: ["pipe", "pipe", "pipe"],
194
+ }).trim();
195
+ execSync(`tmux swap-pane -t .${paneBaseIndex}`, { stdio: "ignore" });
196
+ } catch {
197
+ // Ignore - already at base pane index or swap not possible
198
+ }
199
+
200
+ // Write lock file
201
+ const tmuxTarget = `${WATCH_SESSION}:${(() => {
202
+ try {
203
+ return execSync('tmux display-message -p "#{window_index}.#{pane_index}"', {
204
+ encoding: "utf-8",
205
+ stdio: ["pipe", "pipe", "pipe"],
206
+ }).trim();
207
+ } catch {
208
+ return "1.1";
209
+ }
210
+ })()}`;
211
+ writeFileSync(lockFile, JSON.stringify({ pid: process.pid, tmux_target: tmuxTarget, version: VERSION }));
212
+
213
+ // Rename current window to "watch"
214
+ try {
215
+ execSync(`tmux rename-window watch`, { stdio: "ignore" });
216
+ } catch {
217
+ // Ignore errors
218
+ }
219
+
220
+ // Add tmux keybinding dynamically (prefix + W to switch to watch session pane)
221
+ try {
222
+ execSync(`tmux bind-key W switch-client -t "${tmuxTarget}"`, { stdio: "ignore" });
223
+ } catch {
224
+ // Ignore errors - binding might already exist
225
+ }
226
+
227
+ // Start HTTP server if --serve flag is provided
228
+ if (options.serve) {
229
+ const { runServe } = await import("./serve.js");
230
+ await runServe({ port: options.port, host: options.host });
231
+ }
232
+
233
+ // Enter alternate screen buffer (like vim, htop)
234
+ process.stdout.write("\x1b[?1049h");
235
+ process.stdout.write("\x1b[H"); // Move cursor to top-left
236
+
237
+ const { waitUntilExit } = render(React.createElement(App));
238
+
239
+ try {
240
+ await waitUntilExit();
241
+ } finally {
242
+ // Exit alternate screen buffer, restore previous content
243
+ process.stdout.write("\x1b[?1049l");
244
+ try { unlinkSync(lockFile); } catch { /* ignore */ }
245
+ }
246
+ }
247
+
248
+ export function createTuiCommand(): Command {
249
+ return new Command("tui")
250
+ .description("Run the TUI dashboard (requires tmux)")
251
+ .option("--serve", "Start HTTP server alongside TUI")
252
+ .option("--port <number>", "Server port", String(DEFAULT_SERVER_PORT))
253
+ .option("--host <address>", "Server host (use 0.0.0.0 for LAN)", "127.0.0.1")
254
+ .action(runTui);
255
+ }
@@ -0,0 +1,13 @@
1
+ import { Command } from "commander";
2
+ import { runCleanup } from "../setup/index.js";
3
+
4
+ export async function runUninstallCommand(): Promise<void> {
5
+ await runCleanup();
6
+ process.exit(0);
7
+ }
8
+
9
+ export function createUninstallCommand(): Command {
10
+ return new Command("uninstall")
11
+ .description("Remove claude-mux hooks and configuration")
12
+ .action(runUninstallCommand);
13
+ }
@@ -0,0 +1,32 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+
4
+ interface HeaderProps {
5
+ claudeCount: number;
6
+ tmuxCount: number;
7
+ }
8
+
9
+ export function Header({ claudeCount, tmuxCount }: HeaderProps) {
10
+ const parts: string[] = [];
11
+ if (claudeCount > 0) {
12
+ parts.push(`${claudeCount} claude`);
13
+ }
14
+ if (tmuxCount > 0) {
15
+ parts.push(`${tmuxCount} tmux`);
16
+ }
17
+ const countText = parts.length > 0 ? parts.join(", ") : "no sessions";
18
+
19
+ return (
20
+ <Box
21
+ borderStyle="single"
22
+ borderBottom={false}
23
+ paddingX={1}
24
+ justifyContent="space-between"
25
+ >
26
+ <Text bold color="cyan">
27
+ claude-mux
28
+ </Text>
29
+ <Text dimColor>{countText}</Text>
30
+ </Box>
31
+ );
32
+ }
@@ -0,0 +1,45 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+
4
+ interface HelpDialogProps {
5
+ width?: number;
6
+ }
7
+
8
+ const KEYS = [
9
+ { key: "Enter", desc: "Go to session" },
10
+ { key: "↑↓ / j k", desc: "Select session" },
11
+ { key: "h", desc: "Toggle help" },
12
+ { key: "q", desc: "Quit" },
13
+ { key: "prefix+W", desc: "Return here" },
14
+ ];
15
+
16
+ export function HelpDialog({ width }: HelpDialogProps) {
17
+ const boxWidth = Math.min(width || 40, 40);
18
+
19
+ return (
20
+ <Box flexDirection="column" alignItems="center" justifyContent="center" width={width}>
21
+ <Box
22
+ flexDirection="column"
23
+ borderStyle="round"
24
+ paddingX={2}
25
+ paddingY={1}
26
+ width={boxWidth}
27
+ >
28
+ <Box justifyContent="center" marginBottom={1}>
29
+ <Text bold>Keyboard Shortcuts</Text>
30
+ </Box>
31
+ {KEYS.map(({ key, desc }) => (
32
+ <Box key={key}>
33
+ <Box width={14}>
34
+ <Text color="cyan">{key}</Text>
35
+ </Box>
36
+ <Text dimColor>{desc}</Text>
37
+ </Box>
38
+ ))}
39
+ <Box justifyContent="center" marginTop={1}>
40
+ <Text dimColor>Press any key to close</Text>
41
+ </Box>
42
+ </Box>
43
+ </Box>
44
+ );
45
+ }
@@ -0,0 +1,202 @@
1
+ import React, { useState, useEffect } from "react";
2
+ import { Box, Text } from "ink";
3
+ import type { Session, SessionState } from "../db/index.js";
4
+ import type { TmuxSession } from "../tmux/detect.js";
5
+
6
+ const BLINK_INTERVAL = 500;
7
+
8
+ // Self-contained blinking bullet - only this component re-renders during blink
9
+ function BlinkingBullet({ color, shouldBlink }: { color: string; shouldBlink: boolean }) {
10
+ const [visible, setVisible] = useState(true);
11
+
12
+ useEffect(() => {
13
+ if (!shouldBlink) {
14
+ setVisible(true);
15
+ return;
16
+ }
17
+ const interval = setInterval(() => {
18
+ setVisible((prev) => !prev);
19
+ }, BLINK_INTERVAL);
20
+ return () => clearInterval(interval);
21
+ }, [shouldBlink]);
22
+
23
+ return <Text color={color}>{visible ? "●" : " "}</Text>;
24
+ }
25
+
26
+ // Unified display item - either a Claude session or a plain tmux session
27
+ export type DisplayItem =
28
+ | { type: "claude"; session: Session }
29
+ | { type: "tmux"; tmuxSession: TmuxSession };
30
+
31
+ interface SessionEntryProps {
32
+ item: DisplayItem;
33
+ isSelected: boolean;
34
+ width?: number;
35
+ }
36
+
37
+ function getStateColor(state: SessionState): string {
38
+ switch (state) {
39
+ case "waiting":
40
+ case "permission":
41
+ return "red";
42
+ case "idle":
43
+ return "yellow";
44
+ case "busy":
45
+ return "green";
46
+ default:
47
+ return "gray";
48
+ }
49
+ }
50
+
51
+ function getStateText(session: Session): string {
52
+ switch (session.state) {
53
+ case "permission":
54
+ return "Waiting: permission";
55
+ case "waiting":
56
+ return session.prompt_text ? `Waiting: ${truncate(session.prompt_text, 30)}` : "Waiting";
57
+ case "idle":
58
+ return "Idle";
59
+ case "busy":
60
+ return session.current_action || "Working...";
61
+ default:
62
+ return session.state;
63
+ }
64
+ }
65
+
66
+ function truncate(str: string, maxLen: number): string {
67
+ if (str.length <= maxLen) return str;
68
+ return str.slice(0, maxLen - 1) + "…";
69
+ }
70
+
71
+ function truncatePath(path: string, maxLen: number): string {
72
+ if (path.length <= maxLen) return path;
73
+
74
+ // Try to show ~ for home directory
75
+ const home = process.env.HOME || process.env.USERPROFILE || "";
76
+ if (home && path.startsWith(home)) {
77
+ path = "~" + path.slice(home.length);
78
+ if (path.length <= maxLen) return path;
79
+ }
80
+
81
+ // Truncate from the beginning
82
+ return "…" + path.slice(-(maxLen - 1));
83
+ }
84
+
85
+ export function SessionEntry({ item, isSelected, width }: SessionEntryProps) {
86
+ if (item.type === "claude") {
87
+ return <ClaudeEntry session={item.session} isSelected={isSelected} width={width} />;
88
+ } else {
89
+ return <TmuxEntry tmuxSession={item.tmuxSession} isSelected={isSelected} width={width} />;
90
+ }
91
+ }
92
+
93
+ function ClaudeEntry({
94
+ session,
95
+ isSelected,
96
+ width,
97
+ }: {
98
+ session: Session;
99
+ isSelected: boolean;
100
+ width?: number;
101
+ }) {
102
+ const stateColor = getStateColor(session.state);
103
+ const shouldBlink = session.state === "busy";
104
+
105
+ const tmuxTarget = session.tmux_target || "—";
106
+
107
+ // Fixed widths for prefix and suffix columns
108
+ const prefixWidth = 4; // selector + bullet + space
109
+ const typeWidth = 8;
110
+ const totalWidth = width || 100;
111
+ const stateWidth = totalWidth <= 70 ? 10 : 22;
112
+
113
+ // Calculate flex column widths from remaining space
114
+ const remainingWidth = totalWidth - prefixWidth - typeWidth - stateWidth;
115
+ const targetWidth = Math.floor(remainingWidth * 0.3);
116
+ const pathWidth = remainingWidth - targetWidth;
117
+
118
+ return (
119
+ <Box width={width}>
120
+ {/* Selection indicator (▶ is wide, takes 2 cols) or 2 spaces */}
121
+ <Text color="cyan" bold>{isSelected ? "▶" : " "}</Text>
122
+ {/* Bullet in column 4 - self-contained blink logic */}
123
+ <BlinkingBullet color={stateColor} shouldBlink={shouldBlink} />
124
+ <Text>{" "}</Text>
125
+
126
+ {/* tmux target */}
127
+ <Box width={targetWidth} overflowX="hidden">
128
+ <Text dimColor wrap="truncate-end">{tmuxTarget}</Text>
129
+ </Box>
130
+
131
+ {/* Working directory */}
132
+ <Box width={pathWidth} overflowX="hidden">
133
+ <Text wrap="truncate-end">{truncatePath(session.cwd, pathWidth)}</Text>
134
+ </Box>
135
+
136
+ {/* Type column */}
137
+ <Box width={typeWidth}>
138
+ <Text dimColor>claude</Text>
139
+ </Box>
140
+
141
+ {/* State description */}
142
+ <Box width={stateWidth} overflowX="hidden">
143
+ <Text color={stateColor} wrap="truncate-end">{getStateText(session)}</Text>
144
+ </Box>
145
+ </Box>
146
+ );
147
+ }
148
+
149
+ function TmuxEntry({
150
+ tmuxSession,
151
+ isSelected,
152
+ width,
153
+ }: {
154
+ tmuxSession: TmuxSession;
155
+ isSelected: boolean;
156
+ width?: number;
157
+ }) {
158
+ const bullet = "●";
159
+
160
+ // Fixed widths for prefix and suffix columns
161
+ const prefixWidth = 4; // selector + bullet + space
162
+ const typeWidth = 8;
163
+ const totalWidth = width || 100;
164
+ const stateWidth = totalWidth <= 70 ? 10 : 22;
165
+
166
+ // Calculate flex column widths from remaining space
167
+ const remainingWidth = totalWidth - prefixWidth - typeWidth - stateWidth;
168
+ const targetWidth = Math.floor(remainingWidth * 0.3);
169
+ const pathWidth = remainingWidth - targetWidth;
170
+
171
+ const windowInfo = `${tmuxSession.windowCount} window${tmuxSession.windowCount !== 1 ? "s" : ""}${tmuxSession.attached ? " (attached)" : ""}`;
172
+
173
+ return (
174
+ <Box width={width}>
175
+ {/* Selection indicator (▶ is wide, takes 2 cols) or 2 spaces */}
176
+ <Text color="cyan" bold>{isSelected ? "▶" : " "}</Text>
177
+ {/* Bullet in column 4 */}
178
+ <Text dimColor>{bullet}</Text>
179
+ <Text>{" "}</Text>
180
+
181
+ {/* Session name as target */}
182
+ <Box width={targetWidth} overflowX="hidden">
183
+ <Text dimColor wrap="truncate-end">{tmuxSession.name}</Text>
184
+ </Box>
185
+
186
+ {/* Window count info */}
187
+ <Box width={pathWidth} overflowX="hidden">
188
+ <Text dimColor wrap="truncate-end">{windowInfo}</Text>
189
+ </Box>
190
+
191
+ {/* Type column */}
192
+ <Box width={typeWidth}>
193
+ <Text dimColor>tmux</Text>
194
+ </Box>
195
+
196
+ {/* Empty state column for alignment */}
197
+ <Box width={stateWidth}>
198
+ <Text dimColor>—</Text>
199
+ </Box>
200
+ </Box>
201
+ );
202
+ }
@@ -0,0 +1,98 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+ import type { Session } from "../db/index.js";
4
+ import type { TmuxSession } from "../tmux/detect.js";
5
+ import { SessionEntry, type DisplayItem } from "./SessionEntry.js";
6
+
7
+ interface SessionListProps {
8
+ sessions: Session[];
9
+ tmuxSessions: TmuxSession[];
10
+ selectedIndex: number;
11
+ width?: number;
12
+ }
13
+
14
+ export function SessionList({ sessions, tmuxSessions, selectedIndex, width }: SessionListProps) {
15
+ // Get tmux session names that have Claude instances
16
+ const claudeTmuxSessions = new Set<string>();
17
+ for (const session of sessions) {
18
+ if (session.tmux_target) {
19
+ // Extract session name from target (e.g., "cw:1.3" -> "cw")
20
+ const sessionName = session.tmux_target.split(":")[0];
21
+ claudeTmuxSessions.add(sessionName);
22
+ }
23
+ }
24
+
25
+ // Filter tmux sessions to only those without Claude instances
26
+ const nonClaudeTmuxSessions = tmuxSessions.filter(
27
+ (ts) => !claudeTmuxSessions.has(ts.name)
28
+ );
29
+
30
+ // Build unified display items: Claude sessions first, then non-Claude tmux sessions
31
+ const items: DisplayItem[] = [
32
+ ...sessions.map((session): DisplayItem => ({ type: "claude", session })),
33
+ ...nonClaudeTmuxSessions.map((tmuxSession): DisplayItem => ({ type: "tmux", tmuxSession })),
34
+ ];
35
+
36
+ if (items.length === 0) {
37
+ return (
38
+ <Box paddingY={1}>
39
+ <Text dimColor> No sessions</Text>
40
+ </Box>
41
+ );
42
+ }
43
+
44
+ return (
45
+ <Box flexDirection="column">
46
+ {items.map((item, index) => (
47
+ <SessionEntry
48
+ key={item.type === "claude" ? item.session.id : `tmux-${item.tmuxSession.name}`}
49
+ item={item}
50
+ isSelected={index === selectedIndex}
51
+ width={width}
52
+ />
53
+ ))}
54
+ </Box>
55
+ );
56
+ }
57
+
58
+ // Export the total count for navigation purposes
59
+ export function getTotalItemCount(sessions: Session[], tmuxSessions: TmuxSession[]): number {
60
+ const claudeTmuxSessions = new Set<string>();
61
+ for (const session of sessions) {
62
+ if (session.tmux_target) {
63
+ const sessionName = session.tmux_target.split(":")[0];
64
+ claudeTmuxSessions.add(sessionName);
65
+ }
66
+ }
67
+ const nonClaudeTmuxSessions = tmuxSessions.filter(
68
+ (ts) => !claudeTmuxSessions.has(ts.name)
69
+ );
70
+ return sessions.length + nonClaudeTmuxSessions.length;
71
+ }
72
+
73
+ // Get the display item at a specific index
74
+ export function getItemAtIndex(
75
+ sessions: Session[],
76
+ tmuxSessions: TmuxSession[],
77
+ index: number
78
+ ): DisplayItem | null {
79
+ const claudeTmuxSessions = new Set<string>();
80
+ for (const session of sessions) {
81
+ if (session.tmux_target) {
82
+ const sessionName = session.tmux_target.split(":")[0];
83
+ claudeTmuxSessions.add(sessionName);
84
+ }
85
+ }
86
+ const nonClaudeTmuxSessions = tmuxSessions.filter(
87
+ (ts) => !claudeTmuxSessions.has(ts.name)
88
+ );
89
+
90
+ if (index < sessions.length) {
91
+ return { type: "claude", session: sessions[index] };
92
+ }
93
+ const tmuxIndex = index - sessions.length;
94
+ if (tmuxIndex < nonClaudeTmuxSessions.length) {
95
+ return { type: "tmux", tmuxSession: nonClaudeTmuxSessions[tmuxIndex] };
96
+ }
97
+ return null;
98
+ }
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ import { Box, Text } from "ink";
3
+ import { VERSION } from "../utils/version.js";
4
+
5
+ interface StatusBarProps {
6
+ inTmux: boolean;
7
+ }
8
+
9
+ export function StatusBar({ inTmux }: StatusBarProps) {
10
+ return (
11
+ <Box borderStyle="single" borderTop={false} paddingX={1} justifyContent="space-between">
12
+ <Text>
13
+ <Text color="cyan">[h]</Text>
14
+ <Text dimColor> Help </Text>
15
+ <Text color="cyan">[q]</Text>
16
+ <Text dimColor> Quit </Text>
17
+ <Text color="cyan">[prefix+W]</Text>
18
+ <Text dimColor> Return here</Text>
19
+ {!inTmux && (
20
+ <Text color="yellow"> (not in tmux - navigation disabled)</Text>
21
+ )}
22
+ </Text>
23
+ <Text dimColor>v{VERSION}</Text>
24
+ </Box>
25
+ );
26
+ }
@@ -0,0 +1,5 @@
1
+ export { Header } from "./Header.js";
2
+ export { HelpDialog } from "./HelpDialog.js";
3
+ export { SessionEntry } from "./SessionEntry.js";
4
+ export { SessionList } from "./SessionList.js";
5
+ export { StatusBar } from "./StatusBar.js";