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.
- package/.beads/README.md +81 -0
- package/.beads/config.yaml +62 -0
- package/.beads/interactions.jsonl +0 -0
- package/.beads/issues.jsonl +5 -0
- package/.beads/metadata.json +4 -0
- package/.eslintrc.json +25 -0
- package/.gitattributes +3 -0
- package/.prettierrc +7 -0
- package/CLAUDE.md +123 -0
- package/LICENSE +21 -0
- package/PLAN-beads-integration.md +250 -0
- package/README.md +366 -0
- package/dist/app.d.ts +2 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +147 -0
- package/dist/app.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +65 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/index.d.ts +5 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +5 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/serve.d.ts +8 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +59 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/setup.d.ts +4 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +12 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/tui.d.ts +9 -0
- package/dist/commands/tui.d.ts.map +1 -0
- package/dist/commands/tui.js +234 -0
- package/dist/commands/tui.js.map +1 -0
- package/dist/commands/uninstall.d.ts +4 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +12 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/components/Header.d.ts +7 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Header.js +14 -0
- package/dist/components/Header.js.map +1 -0
- package/dist/components/HelpDialog.d.ts +6 -0
- package/dist/components/HelpDialog.d.ts.map +1 -0
- package/dist/components/HelpDialog.js +14 -0
- package/dist/components/HelpDialog.js.map +1 -0
- package/dist/components/SessionEntry.d.ts +17 -0
- package/dist/components/SessionEntry.d.ts.map +1 -0
- package/dist/components/SessionEntry.js +102 -0
- package/dist/components/SessionEntry.js.map +1 -0
- package/dist/components/SessionList.d.ts +14 -0
- package/dist/components/SessionList.d.ts.map +1 -0
- package/dist/components/SessionList.js +57 -0
- package/dist/components/SessionList.js.map +1 -0
- package/dist/components/StatusBar.d.ts +6 -0
- package/dist/components/StatusBar.d.ts.map +1 -0
- package/dist/components/StatusBar.js +7 -0
- package/dist/components/StatusBar.js.map +1 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +6 -0
- package/dist/components/index.js.map +1 -0
- package/dist/db/index.d.ts +2 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +3 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +4 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +23 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/db/sessions-json.d.ts +85 -0
- package/dist/db/sessions-json.d.ts.map +1 -0
- package/dist/db/sessions-json.js +242 -0
- package/dist/db/sessions-json.js.map +1 -0
- package/dist/db/sessions.d.ts +38 -0
- package/dist/db/sessions.d.ts.map +1 -0
- package/dist/db/sessions.js +87 -0
- package/dist/db/sessions.js.map +1 -0
- package/dist/hooks/claude-mux-hook.d.ts +15 -0
- package/dist/hooks/claude-mux-hook.d.ts.map +1 -0
- package/dist/hooks/claude-mux-hook.js +396 -0
- package/dist/hooks/claude-mux-hook.js.map +1 -0
- package/dist/hooks/claude-watch-hook.d.ts +15 -0
- package/dist/hooks/claude-watch-hook.d.ts.map +1 -0
- package/dist/hooks/claude-watch-hook.js +396 -0
- package/dist/hooks/claude-watch-hook.js.map +1 -0
- package/dist/server/custom-server.d.ts +13 -0
- package/dist/server/custom-server.d.ts.map +1 -0
- package/dist/server/custom-server.js +63 -0
- package/dist/server/custom-server.js.map +1 -0
- package/dist/server/index.d.ts +9 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +1143 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware/cors.d.ts +2 -0
- package/dist/server/middleware/cors.d.ts.map +1 -0
- package/dist/server/middleware/cors.js +11 -0
- package/dist/server/middleware/cors.js.map +1 -0
- package/dist/server/routes/sessions.d.ts +3 -0
- package/dist/server/routes/sessions.d.ts.map +1 -0
- package/dist/server/routes/sessions.js +78 -0
- package/dist/server/routes/sessions.js.map +1 -0
- package/dist/server/routes/stream.d.ts +3 -0
- package/dist/server/routes/stream.d.ts.map +1 -0
- package/dist/server/routes/stream.js +45 -0
- package/dist/server/routes/stream.js.map +1 -0
- package/dist/server/types.d.ts +28 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/watcher.d.ts +22 -0
- package/dist/server/watcher.d.ts.map +1 -0
- package/dist/server/watcher.js +119 -0
- package/dist/server/watcher.js.map +1 -0
- package/dist/server/websocket.d.ts +51 -0
- package/dist/server/websocket.d.ts.map +1 -0
- package/dist/server/websocket.js +156 -0
- package/dist/server/websocket.js.map +1 -0
- package/dist/server/ws-handlers.d.ts +174 -0
- package/dist/server/ws-handlers.d.ts.map +1 -0
- package/dist/server/ws-handlers.js +695 -0
- package/dist/server/ws-handlers.js.map +1 -0
- package/dist/setup/hooks.d.ts +44 -0
- package/dist/setup/hooks.d.ts.map +1 -0
- package/dist/setup/hooks.js +267 -0
- package/dist/setup/hooks.js.map +1 -0
- package/dist/setup/index.d.ts +3 -0
- package/dist/setup/index.d.ts.map +1 -0
- package/dist/setup/index.js +3 -0
- package/dist/setup/index.js.map +1 -0
- package/dist/setup/wizard.d.ts +4 -0
- package/dist/setup/wizard.d.ts.map +1 -0
- package/dist/setup/wizard.js +72 -0
- package/dist/setup/wizard.js.map +1 -0
- package/dist/tmux/detect.d.ts +25 -0
- package/dist/tmux/detect.d.ts.map +1 -0
- package/dist/tmux/detect.js +71 -0
- package/dist/tmux/detect.js.map +1 -0
- package/dist/tmux/navigate.d.ts +13 -0
- package/dist/tmux/navigate.d.ts.map +1 -0
- package/dist/tmux/navigate.js +41 -0
- package/dist/tmux/navigate.js.map +1 -0
- package/dist/tmux/pane.d.ts +57 -0
- package/dist/tmux/pane.d.ts.map +1 -0
- package/dist/tmux/pane.js +156 -0
- package/dist/tmux/pane.js.map +1 -0
- package/dist/tmux/resize.d.ts +10 -0
- package/dist/tmux/resize.d.ts.map +1 -0
- package/dist/tmux/resize.js +25 -0
- package/dist/tmux/resize.js.map +1 -0
- package/dist/utils/paths.d.ts +7 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +9 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/pid.d.ts +5 -0
- package/dist/utils/pid.d.ts.map +1 -0
- package/dist/utils/pid.js +14 -0
- package/dist/utils/pid.js.map +1 -0
- package/dist/utils/version.d.ts +6 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +6 -0
- package/dist/utils/version.js.map +1 -0
- package/dist/web/client/_app/immutable/assets/0.WptSHSUl.css +1 -0
- package/dist/web/client/_app/immutable/assets/2.s6Kx4oz1.css +1 -0
- package/dist/web/client/_app/immutable/assets/4.DoNWy7tW.css +1 -0
- package/dist/web/client/_app/immutable/assets/AllSessionsPanel.CGHY3HLy.css +1 -0
- package/dist/web/client/_app/immutable/chunks/-3mUPuLP.js +1 -0
- package/dist/web/client/_app/immutable/chunks/B5U4_V3d.js +1 -0
- package/dist/web/client/_app/immutable/chunks/BHwiZXRv.js +1 -0
- package/dist/web/client/_app/immutable/chunks/C9P-coqM.js +1 -0
- package/dist/web/client/_app/immutable/chunks/Cegv0r8x.js +1 -0
- package/dist/web/client/_app/immutable/chunks/DU91Ml7U.js +3 -0
- package/dist/web/client/_app/immutable/chunks/DmdO6ygw.js +1 -0
- package/dist/web/client/_app/immutable/chunks/HKNo9LID.js +5 -0
- package/dist/web/client/_app/immutable/chunks/U4ip-C0d.js +2 -0
- package/dist/web/client/_app/immutable/chunks/cgUjKIhX.js +2 -0
- package/dist/web/client/_app/immutable/entry/app.CGIBnoln.js +2 -0
- package/dist/web/client/_app/immutable/entry/start.CJk8zB1j.js +1 -0
- package/dist/web/client/_app/immutable/nodes/0.CqlJ9a31.js +1 -0
- package/dist/web/client/_app/immutable/nodes/1.BQUZh2-w.js +1 -0
- package/dist/web/client/_app/immutable/nodes/2.CCV1YdgF.js +1 -0
- package/dist/web/client/_app/immutable/nodes/3.D9tDCdq8.js +1 -0
- package/dist/web/client/_app/immutable/nodes/4.BqPyNkFA.js +6 -0
- package/dist/web/client/_app/version.json +1 -0
- package/dist/web/client/robots.txt +3 -0
- package/dist/web/env.js +32 -0
- package/dist/web/handler.js +744 -0
- package/dist/web/index.js +49 -0
- package/dist/web/server/chunks/0-BHWsmCJv.js +23 -0
- package/dist/web/server/chunks/0-BHWsmCJv.js.map +1 -0
- package/dist/web/server/chunks/1-YRx6A8Tm.js +17 -0
- package/dist/web/server/chunks/1-YRx6A8Tm.js.map +1 -0
- package/dist/web/server/chunks/2-eC6JuGAo.js +22 -0
- package/dist/web/server/chunks/2-eC6JuGAo.js.map +1 -0
- package/dist/web/server/chunks/3-Bk-wV20p.js +32 -0
- package/dist/web/server/chunks/3-Bk-wV20p.js.map +1 -0
- package/dist/web/server/chunks/4-nteBgDrW.js +21 -0
- package/dist/web/server/chunks/4-nteBgDrW.js.map +1 -0
- package/dist/web/server/chunks/AllSessionsPanel.svelte_svelte_type_style_lang-Bt4B0-oi.js +35 -0
- package/dist/web/server/chunks/AllSessionsPanel.svelte_svelte_type_style_lang-Bt4B0-oi.js.map +1 -0
- package/dist/web/server/chunks/_layout.svelte-BIF9eZCY.js +453 -0
- package/dist/web/server/chunks/_layout.svelte-BIF9eZCY.js.map +1 -0
- package/dist/web/server/chunks/_page.svelte-Be6iabRn.js +34 -0
- package/dist/web/server/chunks/_page.svelte-Be6iabRn.js.map +1 -0
- package/dist/web/server/chunks/_page.svelte-C_fGJVSE.js +576 -0
- package/dist/web/server/chunks/_page.svelte-C_fGJVSE.js.map +1 -0
- package/dist/web/server/chunks/_page.svelte-CnfJk6cu.js +2722 -0
- package/dist/web/server/chunks/_page.svelte-CnfJk6cu.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-3WAmKvn2.js +34 -0
- package/dist/web/server/chunks/_server.ts-3WAmKvn2.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-BAWJCSFb.js +29 -0
- package/dist/web/server/chunks/_server.ts-BAWJCSFb.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-BPpMOZCm.js +24 -0
- package/dist/web/server/chunks/_server.ts-BPpMOZCm.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-BUKgRb6U.js +13 -0
- package/dist/web/server/chunks/_server.ts-BUKgRb6U.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-BVHUS8fm.js +41 -0
- package/dist/web/server/chunks/_server.ts-BVHUS8fm.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-BrF3od0O.js +45 -0
- package/dist/web/server/chunks/_server.ts-BrF3od0O.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-C4oPmOJR.js +38 -0
- package/dist/web/server/chunks/_server.ts-C4oPmOJR.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-CDAUUmG_.js +21 -0
- package/dist/web/server/chunks/_server.ts-CDAUUmG_.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-CR0uWvpz.js +24 -0
- package/dist/web/server/chunks/_server.ts-CR0uWvpz.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-CSqdCNGi.js +21 -0
- package/dist/web/server/chunks/_server.ts-CSqdCNGi.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-DI9fzUo9.js +52 -0
- package/dist/web/server/chunks/_server.ts-DI9fzUo9.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-DNjJTClI.js +46 -0
- package/dist/web/server/chunks/_server.ts-DNjJTClI.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-DdbOAkOj.js +22 -0
- package/dist/web/server/chunks/_server.ts-DdbOAkOj.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-Df2isGQc.js +41 -0
- package/dist/web/server/chunks/_server.ts-Df2isGQc.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-Vpw25_-3.js +12 -0
- package/dist/web/server/chunks/_server.ts-Vpw25_-3.js.map +1 -0
- package/dist/web/server/chunks/_server.ts-WldRpSRi.js +26 -0
- package/dist/web/server/chunks/_server.ts-WldRpSRi.js.map +1 -0
- package/dist/web/server/chunks/alert-dialog-description-DDA6u-nS.js +2890 -0
- package/dist/web/server/chunks/alert-dialog-description-DDA6u-nS.js.map +1 -0
- package/dist/web/server/chunks/auth-DrUf-v4J.js +51 -0
- package/dist/web/server/chunks/auth-DrUf-v4J.js.map +1 -0
- package/dist/web/server/chunks/button-D6xS9rHt.js +2335 -0
- package/dist/web/server/chunks/button-D6xS9rHt.js.map +1 -0
- package/dist/web/server/chunks/chunk-EKzHsMy_.js +42 -0
- package/dist/web/server/chunks/chunks-DmdqVYC7.js +58 -0
- package/dist/web/server/chunks/chunks-DmdqVYC7.js.map +1 -0
- package/dist/web/server/chunks/client-CUrSQijh.js +18 -0
- package/dist/web/server/chunks/client-CUrSQijh.js.map +1 -0
- package/dist/web/server/chunks/clsx-FzI4_gi0.js +332 -0
- package/dist/web/server/chunks/clsx-FzI4_gi0.js.map +1 -0
- package/dist/web/server/chunks/error.svelte-D-c-9pTE.js +27 -0
- package/dist/web/server/chunks/error.svelte-D-c-9pTE.js.map +1 -0
- package/dist/web/server/chunks/events-BDBlYddw.js +89 -0
- package/dist/web/server/chunks/events-BDBlYddw.js.map +1 -0
- package/dist/web/server/chunks/exports-CCurQ-Tl.js +131 -0
- package/dist/web/server/chunks/exports-CCurQ-Tl.js.map +1 -0
- package/dist/web/server/chunks/hooks.server-BK1bopsh.js +86 -0
- package/dist/web/server/chunks/hooks.server-BK1bopsh.js.map +1 -0
- package/dist/web/server/chunks/index2-BQnysSj-.js +2588 -0
- package/dist/web/server/chunks/index2-BQnysSj-.js.map +1 -0
- package/dist/web/server/chunks/internal-DLENj6YI.js +61 -0
- package/dist/web/server/chunks/internal-DLENj6YI.js.map +1 -0
- package/dist/web/server/chunks/pane-Dg3pKvsm.js +94 -0
- package/dist/web/server/chunks/pane-Dg3pKvsm.js.map +1 -0
- package/dist/web/server/chunks/sessions-json-DgfkCLO7.js +107 -0
- package/dist/web/server/chunks/sessions-json-DgfkCLO7.js.map +1 -0
- package/dist/web/server/chunks/sessions.svelte-Ds82MvkB.js +178 -0
- package/dist/web/server/chunks/sessions.svelte-Ds82MvkB.js.map +1 -0
- package/dist/web/server/chunks/state.svelte-xeAZvWZ6.js +7 -0
- package/dist/web/server/chunks/state.svelte-xeAZvWZ6.js.map +1 -0
- package/dist/web/server/chunks/ws-handlers-B4r5eSP2.js +733 -0
- package/dist/web/server/chunks/ws-handlers-B4r5eSP2.js.map +1 -0
- package/dist/web/server/index.js +4907 -0
- package/dist/web/server/index.js.map +1 -0
- package/dist/web/server/manifest.js +233 -0
- package/dist/web/server/manifest.js.map +1 -0
- package/docs/images/desktop-dashboard.png +0 -0
- package/docs/images/desktop-session.png +0 -0
- package/docs/images/mobile-dashboard.png +0 -0
- package/docs/images/mobile-session.png +0 -0
- package/docs/release-checklist.md +228 -0
- package/docs/removing-hooks.md +135 -0
- package/docs/state-transitions.md +109 -0
- package/package.json +71 -0
- package/src/app.tsx +188 -0
- package/src/cli.ts +83 -0
- package/src/commands/index.ts +4 -0
- package/src/commands/serve.ts +75 -0
- package/src/commands/setup.ts +13 -0
- package/src/commands/tui.ts +255 -0
- package/src/commands/uninstall.ts +13 -0
- package/src/components/Header.tsx +32 -0
- package/src/components/HelpDialog.tsx +45 -0
- package/src/components/SessionEntry.tsx +202 -0
- package/src/components/SessionList.tsx +98 -0
- package/src/components/StatusBar.tsx +26 -0
- package/src/components/index.ts +5 -0
- package/src/db/index.ts +20 -0
- package/src/db/sessions-json.ts +314 -0
- package/src/hooks/claude-mux-hook.ts +498 -0
- package/src/server/watcher.ts +128 -0
- package/src/server/ws-handlers.ts +922 -0
- package/src/setup/hooks.ts +333 -0
- package/src/setup/index.ts +2 -0
- package/src/setup/wizard.ts +81 -0
- package/src/tmux/detect.ts +87 -0
- package/src/tmux/navigate.ts +42 -0
- package/src/tmux/pane.ts +167 -0
- package/src/tmux/resize.ts +28 -0
- package/src/utils/paths.ts +11 -0
- package/src/utils/pid.ts +12 -0
- package/src/utils/version.ts +5 -0
- package/tests/components/Header.test.tsx +42 -0
- package/tests/components/SessionEntry-extended.test.tsx +165 -0
- package/tests/components/SessionEntry.test.tsx +138 -0
- package/tests/components/SessionList.test.tsx +110 -0
- package/tests/components/StatusBar.test.tsx +31 -0
- package/tests/db/index.test.ts +78 -0
- package/tests/db/sessions.test.ts +230 -0
- package/tests/server/integration.test.ts +319 -0
- package/tests/server/sessions.test.ts +114 -0
- package/tests/setup/hooks-integration.test.ts +148 -0
- package/tests/setup/hooks.test.ts +123 -0
- package/tests/tmux/detect.test.ts +54 -0
- package/tests/tmux/navigate.test.ts +30 -0
- package/tests/utils/pid.test.ts +17 -0
- package/tsconfig.cli.json +9 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +29 -0
- package/web/.svelte-kit/adapter-bun/.vite/manifest.json +408 -0
- package/web/.svelte-kit/adapter-bun/_app/immutable/assets/AllSessionsPanel.BKhqOrbV.css +1 -0
- package/web/.svelte-kit/adapter-bun/_app/immutable/assets/_layout.WptSHSUl.css +1 -0
- package/web/.svelte-kit/adapter-bun/_app/immutable/assets/_page.DldLgTc-.css +1 -0
- package/web/.svelte-kit/adapter-bun/_app/immutable/assets/_page.DoNWy7tW.css +1 -0
- package/web/.svelte-kit/adapter-bun/chunks/AllSessionsPanel.svelte_svelte_type_style_lang.js +49 -0
- package/web/.svelte-kit/adapter-bun/chunks/alert-dialog-description.js +2670 -0
- package/web/.svelte-kit/adapter-bun/chunks/auth.js +59 -0
- package/web/.svelte-kit/adapter-bun/chunks/button.js +82 -0
- package/web/.svelte-kit/adapter-bun/chunks/client.js +29 -0
- package/web/.svelte-kit/adapter-bun/chunks/context.js +133 -0
- package/web/.svelte-kit/adapter-bun/chunks/environment.js +34 -0
- package/web/.svelte-kit/adapter-bun/chunks/events.js +121 -0
- package/web/.svelte-kit/adapter-bun/chunks/exports.js +174 -0
- package/web/.svelte-kit/adapter-bun/chunks/false.js +4 -0
- package/web/.svelte-kit/adapter-bun/chunks/index.js +59 -0
- package/web/.svelte-kit/adapter-bun/chunks/index2.js +2828 -0
- package/web/.svelte-kit/adapter-bun/chunks/internal.js +920 -0
- package/web/.svelte-kit/adapter-bun/chunks/pane.js +82 -0
- package/web/.svelte-kit/adapter-bun/chunks/sessions-json.js +124 -0
- package/web/.svelte-kit/adapter-bun/chunks/sessions.svelte.js +229 -0
- package/web/.svelte-kit/adapter-bun/chunks/shared.js +542 -0
- package/web/.svelte-kit/adapter-bun/chunks/state.svelte.js +16 -0
- package/web/.svelte-kit/adapter-bun/chunks/utils.js +43 -0
- package/web/.svelte-kit/adapter-bun/chunks/ws-handlers.js +782 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/auth/login/_server.ts.js +22 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/auth/logout/_server.ts.js +9 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/beads/_server.ts.js +22 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/browse/_server.ts.js +50 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/chrome/_server.ts.js +30 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/files/image/_server.ts.js +53 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/health/_server.ts.js +7 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/projects/new-session/_server.ts.js +44 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_id_/_server.ts.js +20 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_id_/kill/_server.ts.js +36 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_id_/restart/_server.ts.js +40 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_id_/screenshots/_server.ts.js +28 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_id_/send/_server.ts.js +29 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_server.ts.js +49 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/sessions/_target_/output/_server.ts.js +14 -0
- package/web/.svelte-kit/adapter-bun/entries/endpoints/api/tmux/panes/_server.ts.js +21 -0
- package/web/.svelte-kit/adapter-bun/entries/fallbacks/error.svelte.js +27 -0
- package/web/.svelte-kit/adapter-bun/entries/hooks.server.js +105 -0
- package/web/.svelte-kit/adapter-bun/entries/pages/_layout.svelte.js +499 -0
- package/web/.svelte-kit/adapter-bun/entries/pages/_page.svelte.js +3057 -0
- package/web/.svelte-kit/adapter-bun/entries/pages/login/_page.server.ts.js +15 -0
- package/web/.svelte-kit/adapter-bun/entries/pages/login/_page.svelte.js +37 -0
- package/web/.svelte-kit/adapter-bun/entries/pages/session/_target_/_page.svelte.js +653 -0
- package/web/.svelte-kit/adapter-bun/index.js +3864 -0
- package/web/.svelte-kit/adapter-bun/internal.js +13 -0
- package/web/.svelte-kit/adapter-bun/manifest-full.js +167 -0
- package/web/.svelte-kit/adapter-bun/manifest.js +171 -0
- package/web/.svelte-kit/adapter-bun/nodes/0.js +8 -0
- package/web/.svelte-kit/adapter-bun/nodes/1.js +8 -0
- package/web/.svelte-kit/adapter-bun/nodes/2.js +8 -0
- package/web/.svelte-kit/adapter-bun/nodes/3.js +10 -0
- package/web/.svelte-kit/adapter-bun/nodes/4.js +8 -0
- package/web/.svelte-kit/adapter-bun/remote-entry.js +541 -0
- package/web/.svelte-kit/adapter-node/.vite/manifest.json +223 -0
- package/web/.svelte-kit/adapter-node/_app/immutable/assets/_layout.4NiX29PU.css +1 -0
- package/web/.svelte-kit/adapter-node/_app/immutable/assets/_page.BEMzYUGV.css +1 -0
- package/web/.svelte-kit/adapter-node/_app/immutable/assets/_page.DOJn7TG7.css +1 -0
- package/web/.svelte-kit/adapter-node/chunks/context.js +121 -0
- package/web/.svelte-kit/adapter-node/chunks/environment.js +34 -0
- package/web/.svelte-kit/adapter-node/chunks/exports.js +174 -0
- package/web/.svelte-kit/adapter-node/chunks/false.js +4 -0
- package/web/.svelte-kit/adapter-node/chunks/index.js +59 -0
- package/web/.svelte-kit/adapter-node/chunks/index2.js +2710 -0
- package/web/.svelte-kit/adapter-node/chunks/internal.js +1005 -0
- package/web/.svelte-kit/adapter-node/chunks/sessions-json.js +109 -0
- package/web/.svelte-kit/adapter-node/chunks/sessions.svelte.js +67 -0
- package/web/.svelte-kit/adapter-node/chunks/shared.js +542 -0
- package/web/.svelte-kit/adapter-node/chunks/state.svelte.js +16 -0
- package/web/.svelte-kit/adapter-node/chunks/utils.js +43 -0
- package/web/.svelte-kit/adapter-node/entries/endpoints/api/browse/_server.ts.js +50 -0
- package/web/.svelte-kit/adapter-node/entries/endpoints/api/health/_server.ts.js +7 -0
- package/web/.svelte-kit/adapter-node/entries/endpoints/api/projects/new-session/_server.ts.js +44 -0
- package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_id_/_server.ts.js +20 -0
- package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_id_/kill/_server.ts.js +30 -0
- package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_id_/send/_server.ts.js +22 -0
- package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_server.ts.js +126 -0
- package/web/.svelte-kit/adapter-node/entries/endpoints/api/sessions/_target_/output/_server.ts.js +14 -0
- package/web/.svelte-kit/adapter-node/entries/fallbacks/error.svelte.js +44 -0
- package/web/.svelte-kit/adapter-node/entries/pages/_layout.svelte.js +12 -0
- package/web/.svelte-kit/adapter-node/entries/pages/_page.svelte.js +87 -0
- package/web/.svelte-kit/adapter-node/entries/pages/session/_target_/_page.svelte.js +76 -0
- package/web/.svelte-kit/adapter-node/index.js +3864 -0
- package/web/.svelte-kit/adapter-node/internal.js +13 -0
- package/web/.svelte-kit/adapter-node/manifest-full.js +103 -0
- package/web/.svelte-kit/adapter-node/manifest.js +107 -0
- package/web/.svelte-kit/adapter-node/nodes/0.js +8 -0
- package/web/.svelte-kit/adapter-node/nodes/1.js +8 -0
- package/web/.svelte-kit/adapter-node/nodes/2.js +8 -0
- package/web/.svelte-kit/adapter-node/nodes/3.js +8 -0
- package/web/.svelte-kit/adapter-node/remote-entry.js +541 -0
- package/web/.svelte-kit/ambient.d.ts +187 -0
- package/web/.svelte-kit/generated/client/app.js +33 -0
- package/web/.svelte-kit/generated/client/matchers.js +1 -0
- package/web/.svelte-kit/generated/client/nodes/0.js +1 -0
- package/web/.svelte-kit/generated/client/nodes/1.js +1 -0
- package/web/.svelte-kit/generated/client/nodes/2.js +1 -0
- package/web/.svelte-kit/generated/client/nodes/3.js +1 -0
- package/web/.svelte-kit/generated/client/nodes/4.js +1 -0
- package/web/.svelte-kit/generated/client-optimized/app.js +33 -0
- package/web/.svelte-kit/generated/client-optimized/matchers.js +1 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/0.js +1 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/1.js +1 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/2.js +1 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/3.js +1 -0
- package/web/.svelte-kit/generated/client-optimized/nodes/4.js +1 -0
- package/web/.svelte-kit/generated/root.js +3 -0
- package/web/.svelte-kit/generated/root.svelte +68 -0
- package/web/.svelte-kit/generated/server/internal.js +53 -0
- package/web/.svelte-kit/non-ambient.d.ts +73 -0
- package/web/.svelte-kit/output/client/.vite/manifest.json +203 -0
- package/web/.svelte-kit/output/client/_app/immutable/assets/0.WptSHSUl.css +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/assets/2.s6Kx4oz1.css +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/assets/4.DoNWy7tW.css +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/assets/AllSessionsPanel.CGHY3HLy.css +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/-3mUPuLP.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/B5U4_V3d.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/BHwiZXRv.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/C9P-coqM.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/Cegv0r8x.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DU91Ml7U.js +3 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/DmdO6ygw.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/HKNo9LID.js +5 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/U4ip-C0d.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/chunks/cgUjKIhX.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/entry/app.CGIBnoln.js +2 -0
- package/web/.svelte-kit/output/client/_app/immutable/entry/start.CJk8zB1j.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/0.CqlJ9a31.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/1.BQUZh2-w.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/2.CCV1YdgF.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/3.D9tDCdq8.js +1 -0
- package/web/.svelte-kit/output/client/_app/immutable/nodes/4.BqPyNkFA.js +6 -0
- package/web/.svelte-kit/output/client/_app/version.json +1 -0
- package/web/.svelte-kit/output/client/robots.txt +3 -0
- package/web/.svelte-kit/output/server/.vite/manifest.json +408 -0
- package/web/.svelte-kit/output/server/_app/immutable/assets/AllSessionsPanel.BKhqOrbV.css +1 -0
- package/web/.svelte-kit/output/server/_app/immutable/assets/_layout.WptSHSUl.css +1 -0
- package/web/.svelte-kit/output/server/_app/immutable/assets/_page.DldLgTc-.css +1 -0
- package/web/.svelte-kit/output/server/_app/immutable/assets/_page.DoNWy7tW.css +1 -0
- package/web/.svelte-kit/output/server/chunks/AllSessionsPanel.svelte_svelte_type_style_lang.js +49 -0
- package/web/.svelte-kit/output/server/chunks/alert-dialog-description.js +2670 -0
- package/web/.svelte-kit/output/server/chunks/auth.js +59 -0
- package/web/.svelte-kit/output/server/chunks/button.js +82 -0
- package/web/.svelte-kit/output/server/chunks/client.js +29 -0
- package/web/.svelte-kit/output/server/chunks/context.js +133 -0
- package/web/.svelte-kit/output/server/chunks/environment.js +34 -0
- package/web/.svelte-kit/output/server/chunks/events.js +121 -0
- package/web/.svelte-kit/output/server/chunks/exports.js +174 -0
- package/web/.svelte-kit/output/server/chunks/false.js +4 -0
- package/web/.svelte-kit/output/server/chunks/index.js +59 -0
- package/web/.svelte-kit/output/server/chunks/index2.js +2828 -0
- package/web/.svelte-kit/output/server/chunks/internal.js +920 -0
- package/web/.svelte-kit/output/server/chunks/pane.js +82 -0
- package/web/.svelte-kit/output/server/chunks/sessions-json.js +124 -0
- package/web/.svelte-kit/output/server/chunks/sessions.svelte.js +229 -0
- package/web/.svelte-kit/output/server/chunks/shared.js +542 -0
- package/web/.svelte-kit/output/server/chunks/state.svelte.js +16 -0
- package/web/.svelte-kit/output/server/chunks/utils.js +43 -0
- package/web/.svelte-kit/output/server/chunks/ws-handlers.js +782 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/auth/login/_server.ts.js +22 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/auth/logout/_server.ts.js +9 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/beads/_server.ts.js +22 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/browse/_server.ts.js +50 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/chrome/_server.ts.js +30 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/files/image/_server.ts.js +53 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/health/_server.ts.js +7 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/projects/new-session/_server.ts.js +44 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_id_/_server.ts.js +20 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_id_/kill/_server.ts.js +36 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_id_/restart/_server.ts.js +40 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_id_/screenshots/_server.ts.js +28 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_id_/send/_server.ts.js +29 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_server.ts.js +49 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/sessions/_target_/output/_server.ts.js +14 -0
- package/web/.svelte-kit/output/server/entries/endpoints/api/tmux/panes/_server.ts.js +21 -0
- package/web/.svelte-kit/output/server/entries/fallbacks/error.svelte.js +27 -0
- package/web/.svelte-kit/output/server/entries/hooks.server.js +105 -0
- package/web/.svelte-kit/output/server/entries/pages/_layout.svelte.js +499 -0
- package/web/.svelte-kit/output/server/entries/pages/_page.svelte.js +3057 -0
- package/web/.svelte-kit/output/server/entries/pages/login/_page.server.ts.js +15 -0
- package/web/.svelte-kit/output/server/entries/pages/login/_page.svelte.js +37 -0
- package/web/.svelte-kit/output/server/entries/pages/session/_target_/_page.svelte.js +653 -0
- package/web/.svelte-kit/output/server/index.js +3864 -0
- package/web/.svelte-kit/output/server/internal.js +13 -0
- package/web/.svelte-kit/output/server/manifest-full.js +167 -0
- package/web/.svelte-kit/output/server/manifest.js +167 -0
- package/web/.svelte-kit/output/server/nodes/0.js +8 -0
- package/web/.svelte-kit/output/server/nodes/1.js +8 -0
- package/web/.svelte-kit/output/server/nodes/2.js +8 -0
- package/web/.svelte-kit/output/server/nodes/3.js +10 -0
- package/web/.svelte-kit/output/server/nodes/4.js +8 -0
- package/web/.svelte-kit/output/server/remote-entry.js +541 -0
- package/web/.svelte-kit/tsconfig.json +58 -0
- package/web/.svelte-kit/types/route_meta_data.json +55 -0
- package/web/.svelte-kit/types/src/routes/$types.d.ts +24 -0
- package/web/.svelte-kit/types/src/routes/api/auth/login/$types.d.ts +10 -0
- package/web/.svelte-kit/types/src/routes/api/auth/logout/$types.d.ts +10 -0
- package/web/.svelte-kit/types/src/routes/api/beads/$types.d.ts +10 -0
- package/web/.svelte-kit/types/src/routes/api/browse/$types.d.ts +10 -0
- package/web/.svelte-kit/types/src/routes/api/chrome/$types.d.ts +10 -0
- package/web/.svelte-kit/types/src/routes/api/files/image/$types.d.ts +10 -0
- package/web/.svelte-kit/types/src/routes/api/health/$types.d.ts +10 -0
- package/web/.svelte-kit/types/src/routes/api/projects/new-session/$types.d.ts +10 -0
- package/web/.svelte-kit/types/src/routes/api/sessions/$types.d.ts +10 -0
- package/web/.svelte-kit/types/src/routes/api/sessions/[id]/$types.d.ts +11 -0
- package/web/.svelte-kit/types/src/routes/api/sessions/[id]/kill/$types.d.ts +11 -0
- package/web/.svelte-kit/types/src/routes/api/sessions/[id]/restart/$types.d.ts +11 -0
- package/web/.svelte-kit/types/src/routes/api/sessions/[id]/screenshots/$types.d.ts +11 -0
- package/web/.svelte-kit/types/src/routes/api/sessions/[id]/send/$types.d.ts +11 -0
- package/web/.svelte-kit/types/src/routes/api/sessions/[target]/output/$types.d.ts +11 -0
- package/web/.svelte-kit/types/src/routes/api/tmux/panes/$types.d.ts +10 -0
- package/web/.svelte-kit/types/src/routes/login/$types.d.ts +25 -0
- package/web/.svelte-kit/types/src/routes/login/proxy+page.server.ts +19 -0
- package/web/.svelte-kit/types/src/routes/session/[target]/$types.d.ts +19 -0
- package/web/README.md +42 -0
- package/web/components.json +16 -0
- package/web/package.json +35 -0
- package/web/src/app.css +128 -0
- package/web/src/app.d.ts +13 -0
- package/web/src/app.html +11 -0
- package/web/src/hooks.server.ts +156 -0
- package/web/src/lib/assets/favicon.svg +1 -0
- package/web/src/lib/components/AllSessionsPanel.svelte +789 -0
- package/web/src/lib/components/BeadsPanel.svelte +146 -0
- package/web/src/lib/components/IssueItem.svelte +287 -0
- package/web/src/lib/components/ScreenshotsPanel.svelte +336 -0
- package/web/src/lib/components/SessionsSidebar.svelte +312 -0
- package/web/src/lib/components/TerminalRenderer.svelte +189 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte +18 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte +18 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte +29 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte +17 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte +20 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte +20 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte +20 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog-portal.svelte +7 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte +17 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog-trigger.svelte +7 -0
- package/web/src/lib/components/ui/alert-dialog/alert-dialog.svelte +7 -0
- package/web/src/lib/components/ui/alert-dialog/index.ts +37 -0
- package/web/src/lib/components/ui/badge/badge.svelte +50 -0
- package/web/src/lib/components/ui/badge/index.ts +2 -0
- package/web/src/lib/components/ui/button/button.svelte +86 -0
- package/web/src/lib/components/ui/button/index.ts +17 -0
- package/web/src/lib/components/ui/checkbox/checkbox.svelte +36 -0
- package/web/src/lib/components/ui/checkbox/index.ts +6 -0
- package/web/src/lib/components/ui/dialog/dialog-close.svelte +7 -0
- package/web/src/lib/components/ui/dialog/dialog-content.svelte +45 -0
- package/web/src/lib/components/ui/dialog/dialog-description.svelte +17 -0
- package/web/src/lib/components/ui/dialog/dialog-footer.svelte +20 -0
- package/web/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
- package/web/src/lib/components/ui/dialog/dialog-overlay.svelte +20 -0
- package/web/src/lib/components/ui/dialog/dialog-portal.svelte +7 -0
- package/web/src/lib/components/ui/dialog/dialog-title.svelte +17 -0
- package/web/src/lib/components/ui/dialog/dialog-trigger.svelte +7 -0
- package/web/src/lib/components/ui/dialog/dialog.svelte +7 -0
- package/web/src/lib/components/ui/dialog/index.ts +34 -0
- package/web/src/lib/components/ui/scroll-area/index.ts +10 -0
- package/web/src/lib/components/ui/scroll-area/scroll-area-scrollbar.svelte +31 -0
- package/web/src/lib/components/ui/scroll-area/scroll-area.svelte +43 -0
- package/web/src/lib/components/ui/textarea/index.ts +7 -0
- package/web/src/lib/components/ui/textarea/textarea.svelte +23 -0
- package/web/src/lib/index.ts +1 -0
- package/web/src/lib/server/auth.ts +90 -0
- package/web/src/lib/stores/beads.svelte.ts +163 -0
- package/web/src/lib/stores/input-injection.svelte.ts +39 -0
- package/web/src/lib/stores/preferences.svelte.ts +55 -0
- package/web/src/lib/stores/sessions.svelte.ts +108 -0
- package/web/src/lib/stores/terminal.svelte.ts +96 -0
- package/web/src/lib/stores/websocket-base.svelte.ts +209 -0
- package/web/src/lib/types/terminal.ts +31 -0
- package/web/src/lib/utils/terminal-parser.ts +239 -0
- package/web/src/lib/utils.ts +13 -0
- package/web/src/routes/+layout.svelte +450 -0
- package/web/src/routes/+page.svelte +19 -0
- package/web/src/routes/api/auth/login/+server.ts +34 -0
- package/web/src/routes/api/auth/logout/+server.ts +10 -0
- package/web/src/routes/api/beads/+server.ts +28 -0
- package/web/src/routes/api/browse/+server.ts +59 -0
- package/web/src/routes/api/chrome/+server.ts +35 -0
- package/web/src/routes/api/files/image/+server.ts +64 -0
- package/web/src/routes/api/health/+server.ts +6 -0
- package/web/src/routes/api/projects/new-session/+server.ts +50 -0
- package/web/src/routes/api/sessions/+server.ts +62 -0
- package/web/src/routes/api/sessions/[id]/+server.ts +19 -0
- package/web/src/routes/api/sessions/[id]/kill/+server.ts +46 -0
- package/web/src/routes/api/sessions/[id]/restart/+server.ts +59 -0
- package/web/src/routes/api/sessions/[id]/screenshots/+server.ts +32 -0
- package/web/src/routes/api/sessions/[id]/send/+server.ts +31 -0
- package/web/src/routes/api/sessions/[target]/output/+server.ts +13 -0
- package/web/src/routes/api/tmux/panes/+server.ts +32 -0
- package/web/src/routes/login/+page.server.ts +18 -0
- package/web/src/routes/login/+page.svelte +69 -0
- package/web/src/routes/session/[target]/+page.svelte +450 -0
- package/web/static/robots.txt +3 -0
- package/web/svelte.config.js +20 -0
- package/web/tsconfig.json +20 -0
- 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 };
|