@juspay/shooter 1.1.0 → 1.3.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/bin/shooter.cjs +182 -31
- package/build/client/_app/immutable/assets/{0.DC5pAwP3.css → 0.BhZOCxO4.css} +1 -1
- package/build/client/_app/immutable/assets/0.BhZOCxO4.css.br +0 -0
- package/build/client/_app/immutable/assets/0.BhZOCxO4.css.gz +0 -0
- package/build/client/_app/immutable/assets/1.BYutk3aU.css +1 -0
- package/build/client/_app/immutable/assets/1.BYutk3aU.css.br +0 -0
- package/build/client/_app/immutable/assets/1.BYutk3aU.css.gz +0 -0
- package/build/client/_app/immutable/assets/{3.BoXp0JoS.css → 3.DGDHCVnW.css} +1 -1
- package/build/client/_app/immutable/assets/3.DGDHCVnW.css.br +0 -0
- package/build/client/_app/immutable/assets/3.DGDHCVnW.css.gz +0 -0
- package/build/client/_app/immutable/assets/4.BFUut--w.css +1 -0
- package/build/client/_app/immutable/assets/4.BFUut--w.css.br +0 -0
- package/build/client/_app/immutable/assets/4.BFUut--w.css.gz +0 -0
- package/build/client/_app/immutable/assets/5.BTOx7yt7.css +1 -0
- package/build/client/_app/immutable/assets/5.BTOx7yt7.css.br +0 -0
- package/build/client/_app/immutable/assets/5.BTOx7yt7.css.gz +0 -0
- package/build/client/_app/immutable/assets/{7.PyEFVv_s.css → 7.DwS5ZHBh.css} +1 -1
- package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.br +0 -0
- package/build/client/_app/immutable/assets/7.DwS5ZHBh.css.gz +0 -0
- package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css +1 -0
- package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.br +0 -0
- package/build/client/_app/immutable/assets/ChatView.CwWbzIL-.css.gz +0 -0
- package/build/client/_app/immutable/chunks/B5NAKyil.js +20 -0
- package/build/client/_app/immutable/chunks/B5NAKyil.js.br +0 -0
- package/build/client/_app/immutable/chunks/B5NAKyil.js.gz +0 -0
- package/build/client/_app/immutable/chunks/B8XegpSE.js +1 -0
- package/build/client/_app/immutable/chunks/B8XegpSE.js.br +0 -0
- package/build/client/_app/immutable/chunks/B8XegpSE.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{50RPd5u3.js → B8zoBsv3.js} +1 -1
- package/build/client/_app/immutable/chunks/B8zoBsv3.js.br +0 -0
- package/build/client/_app/immutable/chunks/B8zoBsv3.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BLszSzTT.js +1 -0
- package/build/client/_app/immutable/chunks/BLszSzTT.js.br +0 -0
- package/build/client/_app/immutable/chunks/BLszSzTT.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BOYo8yTr.js +1 -0
- package/build/client/_app/immutable/chunks/BOYo8yTr.js.br +0 -0
- package/build/client/_app/immutable/chunks/BOYo8yTr.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bu1aqm5j.js +1 -0
- package/build/client/_app/immutable/chunks/Bu1aqm5j.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bu1aqm5j.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{CdL99jkG.js → CNmDAqoQ.js} +1 -1
- package/build/client/_app/immutable/chunks/CNmDAqoQ.js.br +0 -0
- package/build/client/_app/immutable/chunks/CNmDAqoQ.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{ClK4wZbC.js → CQjSATpv.js} +16 -16
- package/build/client/_app/immutable/chunks/CQjSATpv.js.br +0 -0
- package/build/client/_app/immutable/chunks/CQjSATpv.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{CojFyTPp.js → CSoRdFvv.js} +1 -1
- package/build/client/_app/immutable/chunks/CSoRdFvv.js.br +0 -0
- package/build/client/_app/immutable/chunks/CSoRdFvv.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{tjbnEgXP.js → CZHsSL_X.js} +1 -1
- package/build/client/_app/immutable/chunks/CZHsSL_X.js.br +0 -0
- package/build/client/_app/immutable/chunks/CZHsSL_X.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CrVuYlkB.js +1 -0
- package/build/client/_app/immutable/chunks/CrVuYlkB.js.br +0 -0
- package/build/client/_app/immutable/chunks/CrVuYlkB.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D3Vl-Qqr.js +1 -0
- package/build/client/_app/immutable/chunks/D3Vl-Qqr.js.br +0 -0
- package/build/client/_app/immutable/chunks/D3Vl-Qqr.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DVkn4r72.js +1 -0
- package/build/client/_app/immutable/chunks/DVkn4r72.js.br +0 -0
- package/build/client/_app/immutable/chunks/DVkn4r72.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DjsDGxCa.js +41 -0
- package/build/client/_app/immutable/chunks/DjsDGxCa.js.br +0 -0
- package/build/client/_app/immutable/chunks/DjsDGxCa.js.gz +0 -0
- package/build/client/_app/immutable/chunks/UJOiqIYE.js +1 -0
- package/build/client/_app/immutable/chunks/UJOiqIYE.js.br +0 -0
- package/build/client/_app/immutable/chunks/UJOiqIYE.js.gz +0 -0
- package/build/client/_app/immutable/chunks/r0JawsZc.js +2 -0
- package/build/client/_app/immutable/chunks/r0JawsZc.js.br +0 -0
- package/build/client/_app/immutable/chunks/r0JawsZc.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.CWzZbNpA.js +2 -0
- package/build/client/_app/immutable/entry/app.CWzZbNpA.js.br +0 -0
- package/build/client/_app/immutable/entry/app.CWzZbNpA.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.t0E4BXrO.js +1 -0
- package/build/client/_app/immutable/entry/start.t0E4BXrO.js.br +2 -0
- package/build/client/_app/immutable/entry/start.t0E4BXrO.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.5I21KR7K.js +1 -0
- package/build/client/_app/immutable/nodes/0.5I21KR7K.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.5I21KR7K.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.BDCm0X_6.js +1 -0
- package/build/client/_app/immutable/nodes/1.BDCm0X_6.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.BDCm0X_6.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.CKjSEOom.js +1 -0
- package/build/client/_app/immutable/nodes/2.CKjSEOom.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.CKjSEOom.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.3yohCM25.js +3 -0
- package/build/client/_app/immutable/nodes/3.3yohCM25.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.3yohCM25.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.pRflZhvu.js +1 -0
- package/build/client/_app/immutable/nodes/4.pRflZhvu.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.pRflZhvu.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.Co1ngwGh.js +4 -0
- package/build/client/_app/immutable/nodes/5.Co1ngwGh.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.Co1ngwGh.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.CUnGGKik.js +2 -0
- package/build/client/_app/immutable/nodes/6.CUnGGKik.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.CUnGGKik.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.CgvPBG9m.js +2 -0
- package/build/client/_app/immutable/nodes/7.CgvPBG9m.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.CgvPBG9m.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/client/manifest.json +13 -0
- package/build/client/manifest.json.br +0 -0
- package/build/client/manifest.json.gz +0 -0
- package/build/server/chunks/0-CYsoSMA0.js +9 -0
- package/build/server/chunks/0-CYsoSMA0.js.map +1 -0
- package/build/server/chunks/1-BSsLbzC1.js +9 -0
- package/build/server/chunks/1-BSsLbzC1.js.map +1 -0
- package/build/server/chunks/2-De1V922H.js +9 -0
- package/build/server/chunks/2-De1V922H.js.map +1 -0
- package/build/server/chunks/3-Ck7ewhOX.js +9 -0
- package/build/server/chunks/3-Ck7ewhOX.js.map +1 -0
- package/build/server/chunks/4-Dl1IrE-x.js +9 -0
- package/build/server/chunks/4-Dl1IrE-x.js.map +1 -0
- package/build/server/chunks/5-CkT7yrsJ.js +9 -0
- package/build/server/chunks/{5-D0wB7nfE.js.map → 5-CkT7yrsJ.js.map} +1 -1
- package/build/server/chunks/6-DMkV5QEZ.js +9 -0
- package/build/server/chunks/6-DMkV5QEZ.js.map +1 -0
- package/build/server/chunks/7-b4mtbSZL.js +9 -0
- package/build/server/chunks/7-b4mtbSZL.js.map +1 -0
- package/build/server/chunks/{Button-C7D5W6wV.js → Button-Cs1aE6ka.js} +2 -2
- package/build/server/chunks/{Button-C7D5W6wV.js.map → Button-Cs1aE6ka.js.map} +1 -1
- package/build/server/chunks/{EmptyState-Ci4pSpmY.js → EmptyState-DDFH1K8g.js} +10 -4
- package/build/server/chunks/EmptyState-DDFH1K8g.js.map +1 -0
- package/build/server/chunks/{Icon-DyrkHVnV.js → Icon-CEUrotA6.js} +3 -3
- package/build/server/chunks/{Icon-DyrkHVnV.js.map → Icon-CEUrotA6.js.map} +1 -1
- package/build/server/chunks/{Shimmer-BITK6wrm.js → Shimmer-DB8W1zt6.js} +2 -2
- package/build/server/chunks/{Shimmer-BITK6wrm.js.map → Shimmer-DB8W1zt6.js.map} +1 -1
- package/build/server/chunks/_error.svelte-uCOJNxvr.js +39 -0
- package/build/server/chunks/_error.svelte-uCOJNxvr.js.map +1 -0
- package/build/server/chunks/{_layout.svelte-CO4f8UD7.js → _layout.svelte-CtWmEJwe.js} +5 -25
- package/build/server/chunks/_layout.svelte-CtWmEJwe.js.map +1 -0
- package/build/server/chunks/{_page.svelte-C6bns9aQ.js → _page.svelte-BcZaKdX9.js} +13 -9
- package/build/server/chunks/_page.svelte-BcZaKdX9.js.map +1 -0
- package/build/server/chunks/{_page.svelte-3Cc3NMAP.js → _page.svelte-BdYynOck.js} +18 -14
- package/build/server/chunks/_page.svelte-BdYynOck.js.map +1 -0
- package/build/server/chunks/{_page.svelte-CFCONiDK.js → _page.svelte-BgevQjq1.js} +16 -12
- package/build/server/chunks/_page.svelte-BgevQjq1.js.map +1 -0
- package/build/server/chunks/{_page.svelte-DskND_G9.js → _page.svelte-CVq6tRb3.js} +8 -8
- package/build/server/chunks/_page.svelte-CVq6tRb3.js.map +1 -0
- package/build/server/chunks/{_page.svelte-rTrWmhOp.js → _page.svelte-CxWcQ0Am.js} +8 -8
- package/build/server/chunks/_page.svelte-CxWcQ0Am.js.map +1 -0
- package/build/server/chunks/{_page.svelte-C0p3HsIW.js → _page.svelte-DO4oa_LY.js} +11 -13
- package/build/server/chunks/_page.svelte-DO4oa_LY.js.map +1 -0
- package/build/server/chunks/{_server.ts-CS5H5klP.js → _server.ts-CAxsWKvS.js} +14 -10
- package/build/server/chunks/_server.ts-CAxsWKvS.js.map +1 -0
- package/build/server/chunks/{_server.ts-C8slOHB0.js → _server.ts-CTpcLUH8.js} +3 -2
- package/build/server/chunks/_server.ts-CTpcLUH8.js.map +1 -0
- package/build/server/chunks/_server.ts-CtH0dhUp.js +71 -0
- package/build/server/chunks/_server.ts-CtH0dhUp.js.map +1 -0
- package/build/server/chunks/{_server.ts-DhTrdlWH.js → _server.ts-DB_Kg97c.js} +14 -3
- package/build/server/chunks/_server.ts-DB_Kg97c.js.map +1 -0
- package/build/server/chunks/_server.ts-DYpJImqd.js +99 -0
- package/build/server/chunks/_server.ts-DYpJImqd.js.map +1 -0
- package/build/server/chunks/{_server.ts-DpEVfp8W.js → _server.ts-Deok2y88.js} +58 -40
- package/build/server/chunks/_server.ts-Deok2y88.js.map +1 -0
- package/build/server/chunks/{_server.ts-uHUi-4cd.js → _server.ts-vekTmWAx.js} +3 -2
- package/build/server/chunks/_server.ts-vekTmWAx.js.map +1 -0
- package/build/server/chunks/{client2-BjxIYuno.js → client-BdGHe_hY.js} +4 -4
- package/build/server/chunks/client-BdGHe_hY.js.map +1 -0
- package/build/server/chunks/client2-CCBGA-2V.js +7 -0
- package/build/server/chunks/client2-CCBGA-2V.js.map +1 -0
- package/build/server/chunks/{index-Cnl871UW.js → index-DwaY1cAm.js} +2 -2
- package/build/server/chunks/{index-Cnl871UW.js.map → index-DwaY1cAm.js.map} +1 -1
- package/build/server/chunks/{index-server-CUC9Jt7r.js → index-server-CrDaL06Y.js} +2 -2
- package/build/server/chunks/{index-server-CUC9Jt7r.js.map → index-server-CrDaL06Y.js.map} +1 -1
- package/build/server/chunks/{index2-HA3VTH7y.js → index2-CgclKpUj.js} +2 -2
- package/build/server/chunks/{index2-HA3VTH7y.js.map → index2-CgclKpUj.js.map} +1 -1
- package/build/server/chunks/opencode-db-path-DcfhJtJy.js +15 -0
- package/build/server/chunks/opencode-db-path-DcfhJtJy.js.map +1 -0
- package/build/server/chunks/{pty-manager-DR0Wt2Ac.js → pty-manager-BQVB7IVj.js} +17 -15
- package/build/server/chunks/pty-manager-BQVB7IVj.js.map +1 -0
- package/build/server/chunks/{root-DhswcH6o.js → root-DDSnEAZv.js} +2 -2
- package/build/server/chunks/{root-DhswcH6o.js.map → root-DDSnEAZv.js.map} +1 -1
- package/build/server/chunks/{state.svelte-2Lellg7t.js → state.svelte-hBbXlUak.js} +3 -3
- package/build/server/chunks/{state.svelte-2Lellg7t.js.map → state.svelte-hBbXlUak.js.map} +1 -1
- package/build/server/chunks/stores-DHNzYNpX.js +28 -0
- package/build/server/chunks/stores-DHNzYNpX.js.map +1 -0
- package/build/server/index.js +5 -5
- package/build/server/index.js.map +1 -1
- package/build/server/manifest.js +30 -16
- package/build/server/manifest.js.map +1 -1
- package/package.json +1 -1
- package/scripts/setup.cjs +87 -13
- package/server.ts +3 -0
- package/src/app.html +3 -0
- package/src/lib/modules/client/common/cache.ts +10 -2
- package/src/lib/modules/client/common/index.ts +1 -1
- package/src/lib/modules/client/common/markdown.ts +22 -1
- package/src/lib/modules/client/common/time.ts +13 -11
- package/src/lib/modules/client/terminal/ChatView.svelte +324 -67
- package/src/lib/modules/client/terminal/ConnectionStatus.svelte +1 -0
- package/src/lib/modules/client/terminal/xterm-wrapper.ts +4 -1
- package/src/lib/modules/server/sessions/jsonl-reader.ts +43 -28
- package/src/lib/modules/server/sessions/opencode-db-path.ts +26 -0
- package/src/lib/modules/server/sessions/opencode-reader.ts +13 -15
- package/src/lib/modules/server/sessions/process-detector.ts +103 -0
- package/src/lib/modules/server/terminal/opencode-watcher.ts +3 -14
- package/src/lib/modules/server/terminal/pty-manager.ts +20 -8
- package/src/lib/modules/server/ws/session-handler.ts +282 -104
- package/src/lib/theme.css +30 -0
- package/src/routes/+error.svelte +94 -0
- package/src/routes/+page.svelte +18 -8
- package/src/routes/api/health/+server.ts +14 -2
- package/src/routes/api/sessions/+server.ts +12 -4
- package/src/routes/api/sessions/connect/+server.ts +125 -0
- package/src/routes/api/sessions/detect/+server.ts +27 -0
- package/src/routes/api/terminals/+server.ts +12 -9
- package/src/routes/config/+page.svelte +22 -1
- package/src/routes/project/+page.svelte +159 -8
- package/src/routes/session/[id]/+page.svelte +477 -299
- package/src/routes/terminals/+page.svelte +14 -3
- package/src/routes/terminals/[id]/+page.svelte +25 -0
- package/svelte.config.js +1 -1
- package/build/client/_app/immutable/assets/0.DC5pAwP3.css.br +0 -0
- package/build/client/_app/immutable/assets/0.DC5pAwP3.css.gz +0 -0
- package/build/client/_app/immutable/assets/3.BoXp0JoS.css.br +0 -0
- package/build/client/_app/immutable/assets/3.BoXp0JoS.css.gz +0 -0
- package/build/client/_app/immutable/assets/4.cJuCkJKZ.css +0 -1
- package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.br +0 -0
- package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.gz +0 -0
- package/build/client/_app/immutable/assets/5.DRjApZQW.css +0 -1
- package/build/client/_app/immutable/assets/5.DRjApZQW.css.br +0 -0
- package/build/client/_app/immutable/assets/5.DRjApZQW.css.gz +0 -0
- package/build/client/_app/immutable/assets/7.PyEFVv_s.css.br +0 -0
- package/build/client/_app/immutable/assets/7.PyEFVv_s.css.gz +0 -0
- package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css +0 -1
- package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.br +0 -0
- package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.gz +0 -0
- package/build/client/_app/immutable/chunks/50RPd5u3.js.br +0 -0
- package/build/client/_app/immutable/chunks/50RPd5u3.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BDC7XD4o.js +0 -1
- package/build/client/_app/immutable/chunks/BDC7XD4o.js.br +0 -0
- package/build/client/_app/immutable/chunks/BDC7XD4o.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BeONA6_G.js +0 -2
- package/build/client/_app/immutable/chunks/BeONA6_G.js.br +0 -0
- package/build/client/_app/immutable/chunks/BeONA6_G.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BygiiMA0.js +0 -1
- package/build/client/_app/immutable/chunks/BygiiMA0.js.br +0 -0
- package/build/client/_app/immutable/chunks/BygiiMA0.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CGLrx-H5.js +0 -1
- package/build/client/_app/immutable/chunks/CGLrx-H5.js.br +0 -0
- package/build/client/_app/immutable/chunks/CGLrx-H5.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CHvUpVYv.js +0 -1
- package/build/client/_app/immutable/chunks/CHvUpVYv.js.br +0 -0
- package/build/client/_app/immutable/chunks/CHvUpVYv.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CbqC9BW7.js +0 -1
- package/build/client/_app/immutable/chunks/CbqC9BW7.js.br +0 -2
- package/build/client/_app/immutable/chunks/CbqC9BW7.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CdL99jkG.js.br +0 -0
- package/build/client/_app/immutable/chunks/CdL99jkG.js.gz +0 -0
- package/build/client/_app/immutable/chunks/ClK4wZbC.js.br +0 -0
- package/build/client/_app/immutable/chunks/ClK4wZbC.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CojFyTPp.js.br +0 -0
- package/build/client/_app/immutable/chunks/CojFyTPp.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DREFAyhX.js +0 -60
- package/build/client/_app/immutable/chunks/DREFAyhX.js.br +0 -0
- package/build/client/_app/immutable/chunks/DREFAyhX.js.gz +0 -0
- package/build/client/_app/immutable/chunks/K_aHH2KN.js +0 -1
- package/build/client/_app/immutable/chunks/K_aHH2KN.js.br +0 -0
- package/build/client/_app/immutable/chunks/K_aHH2KN.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Ona8oofC.js +0 -1
- package/build/client/_app/immutable/chunks/Ona8oofC.js.br +0 -0
- package/build/client/_app/immutable/chunks/Ona8oofC.js.gz +0 -0
- package/build/client/_app/immutable/chunks/tjbnEgXP.js.br +0 -0
- package/build/client/_app/immutable/chunks/tjbnEgXP.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.anqwe7ZL.js +0 -2
- package/build/client/_app/immutable/entry/app.anqwe7ZL.js.br +0 -0
- package/build/client/_app/immutable/entry/app.anqwe7ZL.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BV2VRv6h.js +0 -1
- package/build/client/_app/immutable/entry/start.BV2VRv6h.js.br +0 -2
- package/build/client/_app/immutable/entry/start.BV2VRv6h.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.D0i5MqcI.js +0 -1
- package/build/client/_app/immutable/nodes/0.D0i5MqcI.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.D0i5MqcI.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.DN5n5c6F.js +0 -1
- package/build/client/_app/immutable/nodes/1.DN5n5c6F.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.DN5n5c6F.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.BTjkNKZJ.js +0 -1
- package/build/client/_app/immutable/nodes/2.BTjkNKZJ.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.BTjkNKZJ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.CEkigHDv.js +0 -3
- package/build/client/_app/immutable/nodes/3.CEkigHDv.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.CEkigHDv.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.B-8Zsc9k.js +0 -1
- package/build/client/_app/immutable/nodes/4.B-8Zsc9k.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.B-8Zsc9k.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.shitbtHc.js +0 -1
- package/build/client/_app/immutable/nodes/5.shitbtHc.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.shitbtHc.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.CB8Q6eH8.js +0 -2
- package/build/client/_app/immutable/nodes/6.CB8Q6eH8.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.CB8Q6eH8.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.D0CrR6pl.js +0 -2
- package/build/client/_app/immutable/nodes/7.D0CrR6pl.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.D0CrR6pl.js.gz +0 -0
- package/build/server/chunks/0-Cs1dzfRz.js +0 -9
- package/build/server/chunks/0-Cs1dzfRz.js.map +0 -1
- package/build/server/chunks/1-BCSX7oED.js +0 -9
- package/build/server/chunks/1-BCSX7oED.js.map +0 -1
- package/build/server/chunks/2-6gkeO8b4.js +0 -9
- package/build/server/chunks/2-6gkeO8b4.js.map +0 -1
- package/build/server/chunks/3-DH9J9Vsc.js +0 -9
- package/build/server/chunks/3-DH9J9Vsc.js.map +0 -1
- package/build/server/chunks/4-Rzy5TYjl.js +0 -9
- package/build/server/chunks/4-Rzy5TYjl.js.map +0 -1
- package/build/server/chunks/5-D0wB7nfE.js +0 -9
- package/build/server/chunks/6-DR2ABDPq.js +0 -9
- package/build/server/chunks/6-DR2ABDPq.js.map +0 -1
- package/build/server/chunks/7-D-oQJsia.js +0 -9
- package/build/server/chunks/7-D-oQJsia.js.map +0 -1
- package/build/server/chunks/EmptyState-Ci4pSpmY.js.map +0 -1
- package/build/server/chunks/_layout.svelte-CO4f8UD7.js.map +0 -1
- package/build/server/chunks/_page.svelte-3Cc3NMAP.js.map +0 -1
- package/build/server/chunks/_page.svelte-C0p3HsIW.js.map +0 -1
- package/build/server/chunks/_page.svelte-C6bns9aQ.js.map +0 -1
- package/build/server/chunks/_page.svelte-CFCONiDK.js.map +0 -1
- package/build/server/chunks/_page.svelte-DskND_G9.js.map +0 -1
- package/build/server/chunks/_page.svelte-rTrWmhOp.js.map +0 -1
- package/build/server/chunks/_server.ts-C8slOHB0.js.map +0 -1
- package/build/server/chunks/_server.ts-CS5H5klP.js.map +0 -1
- package/build/server/chunks/_server.ts-DhTrdlWH.js.map +0 -1
- package/build/server/chunks/_server.ts-DpEVfp8W.js.map +0 -1
- package/build/server/chunks/_server.ts-uHUi-4cd.js.map +0 -1
- package/build/server/chunks/client-BYT9c0ig.js +0 -7
- package/build/server/chunks/client-BYT9c0ig.js.map +0 -1
- package/build/server/chunks/client2-BjxIYuno.js.map +0 -1
- package/build/server/chunks/error.svelte-BG_yE-Wt.js +0 -27
- package/build/server/chunks/error.svelte-BG_yE-Wt.js.map +0 -1
- package/build/server/chunks/pty-manager-DR0Wt2Ac.js.map +0 -1
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
import type { MessageRole, TextContentBlock } from '$generated/types';
|
|
7
7
|
import type { WebSocket } from 'ws';
|
|
8
8
|
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
|
|
9
12
|
import type { ConversationMessage, MessagePart } from '../sessions/types';
|
|
10
13
|
|
|
11
14
|
// ── Types ────────────────────────────────────────────────────────────
|
|
@@ -42,6 +45,11 @@ interface ManagedTerminal {
|
|
|
42
45
|
status: 'exited' | 'running';
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
/** Extended PTY manager interface with list() for UUID-based terminal search. */
|
|
49
|
+
interface PtyManagerFullLike extends PtyManagerLike {
|
|
50
|
+
list: () => ManagedTerminal[];
|
|
51
|
+
}
|
|
52
|
+
|
|
45
53
|
interface PtyManagerLike {
|
|
46
54
|
getTerminal: (id: string) => ManagedTerminal | undefined;
|
|
47
55
|
}
|
|
@@ -75,10 +83,13 @@ interface SessionWatcherLike {
|
|
|
75
83
|
// ── Module-level references ──────────────────────────────────────────
|
|
76
84
|
|
|
77
85
|
let _ptyManager: null | PtyManagerLike = null;
|
|
86
|
+
let _ptyManagerFull: null | PtyManagerFullLike = null;
|
|
78
87
|
let _sessionWatcher: null | SessionWatcherLike = null;
|
|
79
88
|
|
|
80
89
|
/** Per-connection state tracked for cleanup. */
|
|
81
90
|
interface ConnectionState {
|
|
91
|
+
/** True when the session is file-only (no terminal backing it). */
|
|
92
|
+
isExternalSession: boolean;
|
|
82
93
|
retryInterval: null | ReturnType<typeof setInterval>;
|
|
83
94
|
terminalId: string;
|
|
84
95
|
unsubscribe: (() => void) | null;
|
|
@@ -86,120 +97,69 @@ interface ConnectionState {
|
|
|
86
97
|
|
|
87
98
|
/**
|
|
88
99
|
* Handle a new WebSocket connection on the `/ws/session/:id` channel.
|
|
89
|
-
*
|
|
90
|
-
*
|
|
100
|
+
* Accepts BOTH Shooter terminal IDs and external Claude Code session UUIDs.
|
|
101
|
+
*
|
|
102
|
+
* Resolution order:
|
|
103
|
+
* 1. Try `_ptyManager.getTerminal(id)` — works for Shooter terminal IDs.
|
|
104
|
+
* 2. Search all terminals for one whose `sessionFile` contains the UUID.
|
|
105
|
+
* 3. If still no terminal, treat as an external session — find the JSONL
|
|
106
|
+
* file directly and stream it via the session watcher.
|
|
91
107
|
*/
|
|
92
|
-
export function handleSessionConnection(ws: WebSocket,
|
|
93
|
-
const state: ConnectionState = {
|
|
108
|
+
export function handleSessionConnection(ws: WebSocket, id: string): void {
|
|
109
|
+
const state: ConnectionState = {
|
|
110
|
+
isExternalSession: false,
|
|
111
|
+
retryInterval: null,
|
|
112
|
+
terminalId: id,
|
|
113
|
+
unsubscribe: null,
|
|
114
|
+
};
|
|
94
115
|
|
|
95
|
-
// ── 1.
|
|
96
|
-
|
|
97
|
-
safeSend(ws, { message: 'PTY manager not initialised', type: 'error' });
|
|
98
|
-
ws.close(1011, 'PTY manager not initialised');
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
116
|
+
// ── 1. Try to resolve to a terminal ──────────────────────────────
|
|
117
|
+
let terminal: ManagedTerminal | undefined;
|
|
101
118
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
ws.close(1008, 'Terminal not found');
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ── 2. Subscribe to session file ─────────────────────────────────
|
|
110
|
-
subscribeToSession(ws, state, terminal);
|
|
119
|
+
if (_ptyManager) {
|
|
120
|
+
// 1a. Direct terminal ID lookup
|
|
121
|
+
terminal = _ptyManager.getTerminal(id);
|
|
111
122
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const msg = parseClientMessage(data);
|
|
116
|
-
if (!msg) {
|
|
117
|
-
return;
|
|
123
|
+
// 1b. Search by session UUID in sessionFile paths
|
|
124
|
+
if (!terminal) {
|
|
125
|
+
terminal = findTerminalBySessionUuid(id);
|
|
118
126
|
}
|
|
127
|
+
}
|
|
119
128
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
currentTerminal.pty.write('\x03');
|
|
130
|
-
break;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
case 'send-input': {
|
|
134
|
-
// Write text + newline to PTY stdin (the Chat view sends complete
|
|
135
|
-
// messages, not raw keystrokes).
|
|
136
|
-
const currentTerminal = _ptyManager?.getTerminal(state.terminalId);
|
|
137
|
-
if (!currentTerminal || currentTerminal.status === 'exited') {
|
|
138
|
-
safeSend(ws, { message: 'Terminal has exited', type: 'error' });
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
currentTerminal.pty.write(`${msg.text}\n`);
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
case 'subscribe': {
|
|
146
|
-
// (Re)subscribe to a different session. Clean up the old subscription
|
|
147
|
-
// and attach to the new terminal.
|
|
148
|
-
const newTerminal = _ptyManager?.getTerminal(msg.sessionId);
|
|
149
|
-
if (!newTerminal) {
|
|
150
|
-
safeSend(ws, {
|
|
151
|
-
message: `Terminal not found: ${msg.sessionId}`,
|
|
152
|
-
type: 'error',
|
|
153
|
-
});
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Tear down old subscription and retry interval.
|
|
158
|
-
if (state.retryInterval) {
|
|
159
|
-
clearInterval(state.retryInterval);
|
|
160
|
-
state.retryInterval = null;
|
|
161
|
-
}
|
|
162
|
-
if (state.unsubscribe) {
|
|
163
|
-
state.unsubscribe();
|
|
164
|
-
state.unsubscribe = null;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
state.terminalId = msg.sessionId;
|
|
168
|
-
subscribeToSession(ws, state, newTerminal);
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
} catch (err) {
|
|
173
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
174
|
-
console.error(`[ws/session] Error handling ${msg.type} for ${state.terminalId}:`, errMsg);
|
|
175
|
-
safeSend(ws, { message: `Failed to handle ${msg.type}: ${errMsg}`, type: 'error' });
|
|
176
|
-
}
|
|
177
|
-
});
|
|
129
|
+
// ── 2. If we found a terminal, use the normal flow ───────────────
|
|
130
|
+
if (terminal) {
|
|
131
|
+
state.terminalId = terminal.id;
|
|
132
|
+
subscribeToSession(ws, state, terminal);
|
|
133
|
+
wireClientMessages(ws, state);
|
|
134
|
+
wireCleanup(ws, state);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
178
137
|
|
|
179
|
-
// ──
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
});
|
|
138
|
+
// ── 3. External session — find JSONL file directly ───────────────
|
|
139
|
+
const jsonlPath = findJsonlFileForSession(id);
|
|
140
|
+
if (jsonlPath) {
|
|
141
|
+
state.isExternalSession = true;
|
|
142
|
+
subscribeToExternalSession(ws, state, jsonlPath);
|
|
143
|
+
wireClientMessages(ws, state);
|
|
144
|
+
wireCleanup(ws, state);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
190
147
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
148
|
+
// Nothing found at all
|
|
149
|
+
safeSend(ws, { message: `Session not found: ${id}`, type: 'error' });
|
|
150
|
+
ws.close(1008, 'Session not found');
|
|
194
151
|
}
|
|
195
152
|
|
|
196
|
-
// ── Helpers ──────────────────────────────────────────────────────────
|
|
197
|
-
|
|
198
153
|
/**
|
|
199
154
|
* Register the PTY manager instance. Called once during server bootstrap.
|
|
155
|
+
* If the manager also exposes a `list()` method, it is stored as the full
|
|
156
|
+
* reference for UUID-based terminal search.
|
|
200
157
|
*/
|
|
201
158
|
export function setPtyManager(manager: PtyManagerLike): void {
|
|
202
159
|
_ptyManager = manager;
|
|
160
|
+
if ('list' in manager && typeof (manager as PtyManagerFullLike).list === 'function') {
|
|
161
|
+
_ptyManagerFull = manager as PtyManagerFullLike;
|
|
162
|
+
}
|
|
203
163
|
}
|
|
204
164
|
|
|
205
165
|
/**
|
|
@@ -209,8 +169,6 @@ export function setSessionWatcher(watcher: SessionWatcherLike): void {
|
|
|
209
169
|
_sessionWatcher = watcher;
|
|
210
170
|
}
|
|
211
171
|
|
|
212
|
-
// ── Conversion: ConversationMessage → wire format ────────────────────
|
|
213
|
-
|
|
214
172
|
/**
|
|
215
173
|
* Convert ConversationMessage[] into HistoryMessage[] for the initial
|
|
216
174
|
* `history` payload sent when a client connects.
|
|
@@ -275,6 +233,66 @@ function conversationToLive(msg: ConversationMessage): ServerMessage[] {
|
|
|
275
233
|
return messages;
|
|
276
234
|
}
|
|
277
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Scan ~/.claude/projects/ for a JSONL file matching the given session UUID.
|
|
238
|
+
* Returns the absolute path if found, or null.
|
|
239
|
+
*/
|
|
240
|
+
function findJsonlFileForSession(sessionId: string): null | string {
|
|
241
|
+
const claudeProjectsDir = path.join(process.env.HOME || '', '.claude', 'projects');
|
|
242
|
+
|
|
243
|
+
if (!fs.existsSync(claudeProjectsDir)) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
const projectDirs = fs.readdirSync(claudeProjectsDir);
|
|
249
|
+
for (const dir of projectDirs) {
|
|
250
|
+
const fullDir = path.join(claudeProjectsDir, dir);
|
|
251
|
+
try {
|
|
252
|
+
if (!fs.statSync(fullDir).isDirectory()) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
} catch {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const jsonlPath = path.join(fullDir, `${sessionId}.jsonl`);
|
|
260
|
+
if (fs.existsSync(jsonlPath)) {
|
|
261
|
+
return jsonlPath;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
} catch {
|
|
265
|
+
// Ignore filesystem errors
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Search all managed terminals for one whose sessionFile contains the
|
|
275
|
+
* given session UUID. Returns the first match or undefined.
|
|
276
|
+
*/
|
|
277
|
+
function findTerminalBySessionUuid(uuid: string): ManagedTerminal | undefined {
|
|
278
|
+
if (!_ptyManager) {
|
|
279
|
+
return undefined;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// getTerminal only takes an ID — we need to probe. The PtyManager
|
|
283
|
+
// exposes a list() method via its adapter, but the handler only has
|
|
284
|
+
// the PtyManagerLike interface with getTerminal(). We'll use the
|
|
285
|
+
// module-level _ptyManagerFull reference if available.
|
|
286
|
+
if (_ptyManagerFull) {
|
|
287
|
+
for (const t of _ptyManagerFull.list()) {
|
|
288
|
+
if (t.sessionFile && t.sessionFile.includes(`${uuid}.jsonl`)) {
|
|
289
|
+
return _ptyManager.getTerminal(t.id);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
|
|
278
296
|
/** Parse and validate an inbound client message. */
|
|
279
297
|
function parseClientMessage(raw: string): ClientMessage | null {
|
|
280
298
|
try {
|
|
@@ -308,7 +326,7 @@ function parseClientMessage(raw: string): ClientMessage | null {
|
|
|
308
326
|
}
|
|
309
327
|
}
|
|
310
328
|
|
|
311
|
-
// ──
|
|
329
|
+
// ── Conversion: ConversationMessage → wire format ────────────────────
|
|
312
330
|
|
|
313
331
|
/**
|
|
314
332
|
* Map a single MessagePart to the HistoryPart wire format.
|
|
@@ -331,8 +349,6 @@ function partToHistoryPart(part: MessagePart): HistoryPart {
|
|
|
331
349
|
}
|
|
332
350
|
}
|
|
333
351
|
|
|
334
|
-
// ── Main handler ─────────────────────────────────────────────────────
|
|
335
|
-
|
|
336
352
|
/** Safely send a JSON message over a WebSocket. */
|
|
337
353
|
function safeSend(ws: WebSocket, msg: ServerMessage): boolean {
|
|
338
354
|
try {
|
|
@@ -346,6 +362,54 @@ function safeSend(ws: WebSocket, msg: ServerMessage): boolean {
|
|
|
346
362
|
}
|
|
347
363
|
}
|
|
348
364
|
|
|
365
|
+
/**
|
|
366
|
+
* Subscribe to an external session (one with no Shooter terminal).
|
|
367
|
+
* Reads history from the JSONL file and streams live updates via
|
|
368
|
+
* the session watcher.
|
|
369
|
+
*/
|
|
370
|
+
function subscribeToExternalSession(
|
|
371
|
+
ws: WebSocket,
|
|
372
|
+
state: ConnectionState,
|
|
373
|
+
jsonlPath: string
|
|
374
|
+
): void {
|
|
375
|
+
if (!_sessionWatcher) {
|
|
376
|
+
safeSend(ws, { message: 'Session watcher not initialised', type: 'error' });
|
|
377
|
+
safeSend(ws, { messages: [], type: 'history' });
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Send full history
|
|
382
|
+
try {
|
|
383
|
+
const allMessages = _sessionWatcher.getHistory(jsonlPath);
|
|
384
|
+
const historyMessages = conversationToHistory(allMessages);
|
|
385
|
+
safeSend(ws, { messages: historyMessages, type: 'history' });
|
|
386
|
+
} catch (err) {
|
|
387
|
+
console.error(`[ws/session] Failed to read external history for ${state.terminalId}:`, err);
|
|
388
|
+
safeSend(ws, { messages: [], type: 'history' });
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Stream live updates
|
|
392
|
+
try {
|
|
393
|
+
const unsubscribe = _sessionWatcher.subscribe(jsonlPath, (messages: ConversationMessage[]) => {
|
|
394
|
+
if (ws.readyState !== 1 /* OPEN */) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
for (const msg of messages) {
|
|
398
|
+
const liveMessages = conversationToLive(msg);
|
|
399
|
+
for (const liveMsg of liveMessages) {
|
|
400
|
+
safeSend(ws, liveMsg);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
state.unsubscribe = unsubscribe;
|
|
405
|
+
} catch (err) {
|
|
406
|
+
console.error(`[ws/session] Failed to subscribe to external session ${state.terminalId}:`, err);
|
|
407
|
+
safeSend(ws, { message: 'Failed to subscribe to session updates', type: 'error' });
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// ── Connection state ─────────────────────────────────────────────────
|
|
412
|
+
|
|
349
413
|
/**
|
|
350
414
|
* Subscribe to a terminal's session file. Sends the full history as a
|
|
351
415
|
* `history` message, then streams new entries as they appear.
|
|
@@ -413,6 +477,8 @@ function subscribeToSession(
|
|
|
413
477
|
subscribeWithSessionKey(ws, state, terminal, sessionKey);
|
|
414
478
|
}
|
|
415
479
|
|
|
480
|
+
// ── Main handler ─────────────────────────────────────────────────────
|
|
481
|
+
|
|
416
482
|
/**
|
|
417
483
|
* Subscribe to a session using an already-known session key. Sends history
|
|
418
484
|
* and starts streaming new entries. Extracted so both the normal path and
|
|
@@ -467,3 +533,115 @@ function subscribeWithSessionKey(
|
|
|
467
533
|
safeSend(ws, { type: 'session-end' });
|
|
468
534
|
}
|
|
469
535
|
}
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Wire up cleanup handlers for WebSocket close and error events.
|
|
539
|
+
*/
|
|
540
|
+
function wireCleanup(ws: WebSocket, state: ConnectionState): void {
|
|
541
|
+
ws.on('close', () => {
|
|
542
|
+
if (state.retryInterval) {
|
|
543
|
+
clearInterval(state.retryInterval);
|
|
544
|
+
state.retryInterval = null;
|
|
545
|
+
}
|
|
546
|
+
if (state.unsubscribe) {
|
|
547
|
+
state.unsubscribe();
|
|
548
|
+
state.unsubscribe = null;
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
ws.on('error', () => {
|
|
553
|
+
// Errors are followed by 'close', which handles cleanup.
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Wire up client message handling (send-input, cancel, subscribe).
|
|
559
|
+
* Extracted so both terminal-backed and external sessions share the same
|
|
560
|
+
* message loop.
|
|
561
|
+
*/
|
|
562
|
+
function wireClientMessages(ws: WebSocket, state: ConnectionState): void {
|
|
563
|
+
ws.on('message', (raw: Buffer | string) => {
|
|
564
|
+
const data = typeof raw === 'string' ? raw : raw.toString('utf-8');
|
|
565
|
+
const msg = parseClientMessage(data);
|
|
566
|
+
if (!msg) {
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
try {
|
|
571
|
+
switch (msg.type) {
|
|
572
|
+
case 'cancel': {
|
|
573
|
+
if (state.isExternalSession) {
|
|
574
|
+
safeSend(ws, {
|
|
575
|
+
message: 'Cannot cancel — this is a read-only session. Connect to a terminal first.',
|
|
576
|
+
type: 'error',
|
|
577
|
+
});
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
const currentTerminal = _ptyManager?.getTerminal(state.terminalId);
|
|
581
|
+
if (!currentTerminal || currentTerminal.status === 'exited') {
|
|
582
|
+
safeSend(ws, { message: 'Terminal has exited', type: 'error' });
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
currentTerminal.pty.write('\x03');
|
|
586
|
+
break;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
case 'send-input': {
|
|
590
|
+
if (state.isExternalSession) {
|
|
591
|
+
safeSend(ws, {
|
|
592
|
+
message: 'Cannot send input — this is a read-only session. Connect to a terminal first.',
|
|
593
|
+
type: 'error',
|
|
594
|
+
});
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
const currentTerminal = _ptyManager?.getTerminal(state.terminalId);
|
|
598
|
+
if (!currentTerminal || currentTerminal.status === 'exited') {
|
|
599
|
+
safeSend(ws, { message: 'Terminal has exited', type: 'error' });
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
currentTerminal.pty.write(`${msg.text}\n`);
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
case 'subscribe': {
|
|
607
|
+
// (Re)subscribe to a different session. Clean up the old subscription.
|
|
608
|
+
if (state.retryInterval) {
|
|
609
|
+
clearInterval(state.retryInterval);
|
|
610
|
+
state.retryInterval = null;
|
|
611
|
+
}
|
|
612
|
+
if (state.unsubscribe) {
|
|
613
|
+
state.unsubscribe();
|
|
614
|
+
state.unsubscribe = null;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Try terminal first, then external
|
|
618
|
+
const newTerminal = _ptyManager?.getTerminal(msg.sessionId)
|
|
619
|
+
?? findTerminalBySessionUuid(msg.sessionId);
|
|
620
|
+
|
|
621
|
+
if (newTerminal) {
|
|
622
|
+
state.terminalId = newTerminal.id;
|
|
623
|
+
state.isExternalSession = false;
|
|
624
|
+
subscribeToSession(ws, state, newTerminal);
|
|
625
|
+
} else {
|
|
626
|
+
const jsonlPath = findJsonlFileForSession(msg.sessionId);
|
|
627
|
+
if (jsonlPath) {
|
|
628
|
+
state.terminalId = msg.sessionId;
|
|
629
|
+
state.isExternalSession = true;
|
|
630
|
+
subscribeToExternalSession(ws, state, jsonlPath);
|
|
631
|
+
} else {
|
|
632
|
+
safeSend(ws, {
|
|
633
|
+
message: `Session not found: ${msg.sessionId}`,
|
|
634
|
+
type: 'error',
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
} catch (err) {
|
|
642
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
643
|
+
console.error(`[ws/session] Error handling ${msg.type} for ${state.terminalId}:`, errMsg);
|
|
644
|
+
safeSend(ws, { message: `Failed to handle ${msg.type}: ${errMsg}`, type: 'error' });
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
}
|
package/src/lib/theme.css
CHANGED
|
@@ -276,12 +276,37 @@
|
|
|
276
276
|
--button-hover-text-color: var(--ds-background-100);
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
.btn-connect {
|
|
280
|
+
--button-color: #0d9488;
|
|
281
|
+
--button-text-color: #fff;
|
|
282
|
+
--button-hover-color: #14b8a6;
|
|
283
|
+
--button-hover-text-color: #fff;
|
|
284
|
+
--button-border: 1px solid #0d9488;
|
|
285
|
+
--button-hover-border: 1px solid #14b8a6;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.btn-resume {
|
|
289
|
+
--button-color: transparent;
|
|
290
|
+
--button-text-color: var(--ds-gray-900);
|
|
291
|
+
--button-border: 1px solid var(--ds-gray-400);
|
|
292
|
+
--button-hover-color: var(--ds-gray-100);
|
|
293
|
+
--button-hover-text-color: var(--ds-gray-1000);
|
|
294
|
+
--button-hover-border: 1px solid var(--ds-gray-600);
|
|
295
|
+
}
|
|
296
|
+
|
|
279
297
|
.btn-sm {
|
|
280
298
|
--button-height: 32px;
|
|
281
299
|
--button-padding: 0 10px;
|
|
282
300
|
--button-font-size: var(--text-base);
|
|
283
301
|
}
|
|
284
302
|
|
|
303
|
+
.btn-xs {
|
|
304
|
+
--button-height: 28px;
|
|
305
|
+
--button-padding: 0 8px;
|
|
306
|
+
--button-font-size: var(--text-xs);
|
|
307
|
+
--button-border-radius: var(--radius-sm);
|
|
308
|
+
}
|
|
309
|
+
|
|
285
310
|
.btn-lg {
|
|
286
311
|
--button-height: 48px;
|
|
287
312
|
--button-padding: 0 20px;
|
|
@@ -526,4 +551,9 @@
|
|
|
526
551
|
.shimmer-card {
|
|
527
552
|
--shimmer-height: 90px;
|
|
528
553
|
}
|
|
554
|
+
|
|
555
|
+
.btn-xs {
|
|
556
|
+
min-height: 36px;
|
|
557
|
+
padding: 6px 12px;
|
|
558
|
+
}
|
|
529
559
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { goto } from '$app/navigation';
|
|
3
|
+
import { page } from '$app/stores';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<svelte:head>
|
|
7
|
+
<title>Error - Shooter</title>
|
|
8
|
+
</svelte:head>
|
|
9
|
+
|
|
10
|
+
<main class="error-page">
|
|
11
|
+
<div class="error-content">
|
|
12
|
+
<div class="error-code">{$page.status}</div>
|
|
13
|
+
<h1 class="error-title">
|
|
14
|
+
{#if $page.status === 404}
|
|
15
|
+
Page not found
|
|
16
|
+
{:else}
|
|
17
|
+
Something went wrong
|
|
18
|
+
{/if}
|
|
19
|
+
</h1>
|
|
20
|
+
<p class="error-message">
|
|
21
|
+
{#if $page.error?.message}
|
|
22
|
+
{$page.error.message}
|
|
23
|
+
{:else if $page.status === 404}
|
|
24
|
+
The page you're looking for doesn't exist or has been moved.
|
|
25
|
+
{:else}
|
|
26
|
+
An unexpected error occurred. Try refreshing or going back.
|
|
27
|
+
{/if}
|
|
28
|
+
</p>
|
|
29
|
+
<div class="error-actions">
|
|
30
|
+
<button class="error-btn" onclick={() => goto('/')}>Go Home</button>
|
|
31
|
+
<button class="error-btn error-btn-secondary" onclick={() => { history.back(); }}>Go Back</button>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</main>
|
|
35
|
+
|
|
36
|
+
<style>
|
|
37
|
+
.error-page {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
min-height: 60vh;
|
|
42
|
+
padding: var(--space-6);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.error-content {
|
|
46
|
+
text-align: center;
|
|
47
|
+
max-width: 400px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.error-code {
|
|
51
|
+
font-size: 4rem;
|
|
52
|
+
font-weight: 700;
|
|
53
|
+
color: var(--color-text-tertiary, #555);
|
|
54
|
+
line-height: 1;
|
|
55
|
+
margin-bottom: var(--space-2);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.error-title {
|
|
59
|
+
font-size: 1.25rem;
|
|
60
|
+
font-weight: 600;
|
|
61
|
+
margin-bottom: var(--space-3);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.error-message {
|
|
65
|
+
color: var(--color-text-secondary, #888);
|
|
66
|
+
font-size: 0.875rem;
|
|
67
|
+
line-height: 1.5;
|
|
68
|
+
margin-bottom: var(--space-5);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.error-actions {
|
|
72
|
+
display: flex;
|
|
73
|
+
gap: var(--space-3);
|
|
74
|
+
justify-content: center;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.error-btn {
|
|
78
|
+
padding: 10px 20px;
|
|
79
|
+
border-radius: 8px;
|
|
80
|
+
font-size: 0.875rem;
|
|
81
|
+
font-weight: 500;
|
|
82
|
+
cursor: pointer;
|
|
83
|
+
border: none;
|
|
84
|
+
background: var(--color-accent, #0d9488);
|
|
85
|
+
color: white;
|
|
86
|
+
min-height: 44px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.error-btn-secondary {
|
|
90
|
+
background: transparent;
|
|
91
|
+
border: 1px solid var(--border, #333);
|
|
92
|
+
color: var(--color-text-secondary, #888);
|
|
93
|
+
}
|
|
94
|
+
</style>
|