@juspay/shooter 1.17.0 → 1.19.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/build/client/_app/immutable/assets/{0.B0O0vCnX.css → 0.BwNtE8TX.css} +1 -1
- package/build/client/_app/immutable/assets/0.BwNtE8TX.css.br +0 -0
- package/build/client/_app/immutable/assets/{0.B0O0vCnX.css.gz → 0.BwNtE8TX.css.gz} +0 -0
- package/build/client/_app/immutable/assets/8.BYgAX7hR.css +1 -0
- package/build/client/_app/immutable/assets/8.BYgAX7hR.css.br +0 -0
- package/build/client/_app/immutable/assets/8.BYgAX7hR.css.gz +0 -0
- package/build/client/_app/immutable/assets/9.DV6pZunn.css +1 -0
- package/build/client/_app/immutable/assets/9.DV6pZunn.css.br +0 -0
- package/build/client/_app/immutable/assets/9.DV6pZunn.css.gz +0 -0
- package/build/client/_app/immutable/chunks/{DZQMsHM5.js → 2rBV5OkJ.js} +1 -1
- package/build/client/_app/immutable/chunks/2rBV5OkJ.js.br +0 -0
- package/build/client/_app/immutable/chunks/2rBV5OkJ.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BB2l8o4X.js +1 -0
- package/build/client/_app/immutable/chunks/BB2l8o4X.js.br +0 -0
- package/build/client/_app/immutable/chunks/BB2l8o4X.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{Cg3dlX05.js → BPDiEZo0.js} +2 -2
- package/build/client/_app/immutable/chunks/BPDiEZo0.js.br +0 -0
- package/build/client/_app/immutable/chunks/BPDiEZo0.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{C_9BZILB.js → BcpydfqI.js} +1 -1
- package/build/client/_app/immutable/chunks/BcpydfqI.js.br +0 -0
- package/build/client/_app/immutable/chunks/BcpydfqI.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BcqA7eKM.js +3 -0
- package/build/client/_app/immutable/chunks/BcqA7eKM.js.br +0 -0
- package/build/client/_app/immutable/chunks/BcqA7eKM.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BdtLzPpO.js +1 -0
- package/build/client/_app/immutable/chunks/BdtLzPpO.js.br +0 -0
- package/build/client/_app/immutable/chunks/BdtLzPpO.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BRqaaL5D.js → BvmdJful.js} +1 -1
- package/build/client/_app/immutable/chunks/BvmdJful.js.br +0 -0
- package/build/client/_app/immutable/chunks/BvmdJful.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{C5VOyQCG.js → ClIPTXf3.js} +1 -1
- package/build/client/_app/immutable/chunks/ClIPTXf3.js.br +0 -0
- package/build/client/_app/immutable/chunks/ClIPTXf3.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BctvtE4d.js → DA4Zt9Me.js} +1 -1
- package/build/client/_app/immutable/chunks/DA4Zt9Me.js.br +0 -0
- package/build/client/_app/immutable/chunks/{BctvtE4d.js.gz → DA4Zt9Me.js.gz} +0 -0
- package/build/client/_app/immutable/chunks/{CjfxuHdN.js → DCDL_9ys.js} +1 -1
- package/build/client/_app/immutable/chunks/DCDL_9ys.js.br +0 -0
- package/build/client/_app/immutable/chunks/DCDL_9ys.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{DYuMZGL5.js → DWmC0QM7.js} +1 -1
- package/build/client/_app/immutable/chunks/DWmC0QM7.js.br +0 -0
- package/build/client/_app/immutable/chunks/DWmC0QM7.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{DZvnhU_8.js → ZS5XYDx_.js} +2 -2
- package/build/client/_app/immutable/chunks/ZS5XYDx_.js.br +0 -0
- package/build/client/_app/immutable/chunks/ZS5XYDx_.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.D4TXlu7A.js +2 -0
- package/build/client/_app/immutable/entry/app.D4TXlu7A.js.br +0 -0
- package/build/client/_app/immutable/entry/app.D4TXlu7A.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BBQhtURO.js +1 -0
- package/build/client/_app/immutable/entry/start.BBQhtURO.js.br +0 -0
- package/build/client/_app/immutable/entry/start.BBQhtURO.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.1zylwAPT.js +10 -0
- package/build/client/_app/immutable/nodes/0.1zylwAPT.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.1zylwAPT.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{1.Fqso94b3.js → 1.BVnLUSs-.js} +1 -1
- package/build/client/_app/immutable/nodes/1.BVnLUSs-.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.BVnLUSs-.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{8.BjKgvSie.js → 10.D1wl2wPX.js} +2 -2
- package/build/client/_app/immutable/nodes/10.D1wl2wPX.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.D1wl2wPX.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{9.BRT6HOXB.js → 11.C18nMGmp.js} +1 -1
- package/build/client/_app/immutable/nodes/11.C18nMGmp.js.br +0 -0
- package/build/client/_app/immutable/nodes/11.C18nMGmp.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{2.BusCVJWk.js → 2.D1Mm0DUX.js} +2 -2
- package/build/client/_app/immutable/nodes/2.D1Mm0DUX.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.D1Mm0DUX.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{3.DUlpocIc.js → 3.Wfz3TcJd.js} +3 -3
- package/build/client/_app/immutable/nodes/3.Wfz3TcJd.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.Wfz3TcJd.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{4.BSVqdrrD.js → 4.CBX9A3ka.js} +2 -2
- package/build/client/_app/immutable/nodes/4.CBX9A3ka.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.CBX9A3ka.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{5.Cfj35gpY.js → 5.DIVKuZc9.js} +1 -1
- package/build/client/_app/immutable/nodes/5.DIVKuZc9.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.DIVKuZc9.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{6.CG4eKRH0.js → 6.DtZAEPXb.js} +1 -1
- package/build/client/_app/immutable/nodes/6.DtZAEPXb.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.DtZAEPXb.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{7.DHilxD1o.js → 7.MfBRh32I.js} +1 -1
- package/build/client/_app/immutable/nodes/7.MfBRh32I.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.MfBRh32I.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.DVE6LnOC.js +1 -0
- package/build/client/_app/immutable/nodes/8.DVE6LnOC.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.DVE6LnOC.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.BCel5OqI.js +2 -0
- package/build/client/_app/immutable/nodes/9.BCel5OqI.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.BCel5OqI.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/server/chunks/{0-BWFSL107.js → 0-DJqyZZTr.js} +4 -4
- package/build/server/chunks/{0-BWFSL107.js.map → 0-DJqyZZTr.js.map} +1 -1
- package/build/server/chunks/1-2YUVen1F.js +9 -0
- package/build/server/chunks/{1-Bw5KlAjL.js.map → 1-2YUVen1F.js.map} +1 -1
- package/build/server/chunks/10-D1X7LB3v.js +9 -0
- package/build/server/chunks/10-D1X7LB3v.js.map +1 -0
- package/build/server/chunks/11-qXSPdF5j.js +9 -0
- package/build/server/chunks/11-qXSPdF5j.js.map +1 -0
- package/build/server/chunks/{2-CQ3yYSVK.js → 2-BD7kj1mt.js} +3 -3
- package/build/server/chunks/{2-CQ3yYSVK.js.map → 2-BD7kj1mt.js.map} +1 -1
- package/build/server/chunks/{3-DZ4H9hPs.js → 3-oNjv-BhZ.js} +3 -3
- package/build/server/chunks/{3-DZ4H9hPs.js.map → 3-oNjv-BhZ.js.map} +1 -1
- package/build/server/chunks/{4-BtYdKCVW.js → 4-Bb5VFhsO.js} +3 -3
- package/build/server/chunks/{4-BtYdKCVW.js.map → 4-Bb5VFhsO.js.map} +1 -1
- package/build/server/chunks/{5-CvJK3PiH.js → 5-oNoWuIsn.js} +3 -3
- package/build/server/chunks/{5-CvJK3PiH.js.map → 5-oNoWuIsn.js.map} +1 -1
- package/build/server/chunks/6-DRJGUqHG.js +9 -0
- package/build/server/chunks/{6-BZ0enR6b.js.map → 6-DRJGUqHG.js.map} +1 -1
- package/build/server/chunks/7-_giJiu0L.js +9 -0
- package/build/server/chunks/{7-Lg8imTZn.js.map → 7-_giJiu0L.js.map} +1 -1
- package/build/server/chunks/8-zvWAVNT5.js +9 -0
- package/build/server/chunks/8-zvWAVNT5.js.map +1 -0
- package/build/server/chunks/9-DVyDL445.js +9 -0
- package/build/server/chunks/9-DVyDL445.js.map +1 -0
- package/build/server/chunks/Banner-BgaAs1rs.js +90 -0
- package/build/server/chunks/Banner-BgaAs1rs.js.map +1 -0
- package/build/server/chunks/{Button-B5dU-ntz.js → Button-D0hZ7JYt.js} +2 -2
- package/build/server/chunks/Button-D0hZ7JYt.js.map +1 -0
- package/build/server/chunks/{Icon-C7Ml3GX6.js → Icon-D0GBnDcs.js} +3 -3
- package/build/server/chunks/Icon-D0GBnDcs.js.map +1 -0
- package/build/server/chunks/{Input-CPGO0sbS.js → Input-OmIiydSx.js} +2 -2
- package/build/server/chunks/Input-OmIiydSx.js.map +1 -0
- package/build/server/chunks/{Pill-CcrtCejm.js → Pill-4xJ-VhAA.js} +3 -3
- package/build/server/chunks/Pill-4xJ-VhAA.js.map +1 -0
- package/build/server/chunks/{Shimmer-C5jkvGr1.js → Shimmer-Dw2uvTC1.js} +2 -2
- package/build/server/chunks/Shimmer-Dw2uvTC1.js.map +1 -0
- package/build/server/chunks/{_error.svelte-CSIxs-ab.js → _error.svelte-CZnkxeLr.js} +8 -8
- package/build/server/chunks/{_error.svelte-CSIxs-ab.js.map → _error.svelte-CZnkxeLr.js.map} +1 -1
- package/build/server/chunks/{_layout.svelte-noB4j-v2.js → _layout.svelte-DfgNGGiM.js} +16 -11
- package/build/server/chunks/_layout.svelte-DfgNGGiM.js.map +1 -0
- package/build/server/chunks/{_page.svelte-DnTpPnPR.js → _page.svelte-BLo2v_8E.js} +7 -88
- package/build/server/chunks/_page.svelte-BLo2v_8E.js.map +1 -0
- package/build/server/chunks/_page.svelte-BTlfUsBp.js +43 -0
- package/build/server/chunks/_page.svelte-BTlfUsBp.js.map +1 -0
- package/build/server/chunks/{_page.svelte-C60lAagP.js → _page.svelte-BUBLUSGo.js} +8 -8
- package/build/server/chunks/_page.svelte-BUBLUSGo.js.map +1 -0
- package/build/server/chunks/{_page.svelte-BV0XyYJZ.js → _page.svelte-BX2FMgSg.js} +4 -4
- package/build/server/chunks/{_page.svelte-BV0XyYJZ.js.map → _page.svelte-BX2FMgSg.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-BUkm2304.js → _page.svelte-C7B0qdrC.js} +5 -5
- package/build/server/chunks/{_page.svelte-BUkm2304.js.map → _page.svelte-C7B0qdrC.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-Dmg-RFCg.js → _page.svelte-CE7COWnF.js} +7 -7
- package/build/server/chunks/{_page.svelte-Dmg-RFCg.js.map → _page.svelte-CE7COWnF.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-BfB8maoc.js → _page.svelte-CWsjjd4l.js} +9 -9
- package/build/server/chunks/{_page.svelte-BfB8maoc.js.map → _page.svelte-CWsjjd4l.js.map} +1 -1
- package/build/server/chunks/_page.svelte-D5S2hkBk.js +104 -0
- package/build/server/chunks/_page.svelte-D5S2hkBk.js.map +1 -0
- package/build/server/chunks/{_page.svelte-B6qyh-K-.js → _page.svelte-D_Ey8QRG.js} +11 -11
- package/build/server/chunks/{_page.svelte-B6qyh-K-.js.map → _page.svelte-D_Ey8QRG.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-DuzZr5dA.js → _page.svelte-tBuIq8Pg.js} +11 -11
- package/build/server/chunks/{_page.svelte-DuzZr5dA.js.map → _page.svelte-tBuIq8Pg.js.map} +1 -1
- package/build/server/chunks/_server.ts-BaaY7Z9D.js +77 -0
- package/build/server/chunks/_server.ts-BaaY7Z9D.js.map +1 -0
- package/build/server/chunks/{_server.ts-5wx4ZppI.js → _server.ts-Bi0Oe4PF.js} +7 -4
- package/build/server/chunks/_server.ts-Bi0Oe4PF.js.map +1 -0
- package/build/server/chunks/_server.ts-C0317RBD.js +57 -0
- package/build/server/chunks/_server.ts-C0317RBD.js.map +1 -0
- package/build/server/chunks/{_server.ts-CKXVBbwb.js → _server.ts-CRVNEOd2.js} +10 -8
- package/build/server/chunks/_server.ts-CRVNEOd2.js.map +1 -0
- package/build/server/chunks/_server.ts-CVPZOpiv.js +23 -0
- package/build/server/chunks/_server.ts-CVPZOpiv.js.map +1 -0
- package/build/server/chunks/{_server.ts-CyjDrcZN.js → _server.ts-C_OOUqsd.js} +9 -1
- package/build/server/chunks/_server.ts-C_OOUqsd.js.map +1 -0
- package/build/server/chunks/{_server.ts-BMMTS86y.js → _server.ts-D9ir7u24.js} +3 -4
- package/build/server/chunks/{_server.ts-BMMTS86y.js.map → _server.ts-D9ir7u24.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DZ5naqSL.js → _server.ts-DMm0hBP4.js} +5 -1
- package/build/server/chunks/_server.ts-DMm0hBP4.js.map +1 -0
- package/build/server/chunks/{_server.ts-CgHc1Zpx.js → _server.ts-DhJx0DLr.js} +7 -4
- package/build/server/chunks/_server.ts-DhJx0DLr.js.map +1 -0
- package/build/server/chunks/_server.ts-DkZX_O9a.js +39 -0
- package/build/server/chunks/_server.ts-DkZX_O9a.js.map +1 -0
- package/build/server/chunks/{_server.ts-B1z0q6qZ.js → _server.ts-DxT9IlZF.js} +6 -5
- package/build/server/chunks/_server.ts-DxT9IlZF.js.map +1 -0
- package/build/server/chunks/{_server.ts-Bt7EAfjo.js → _server.ts-MbnroWEF.js} +25 -48
- package/build/server/chunks/_server.ts-MbnroWEF.js.map +1 -0
- package/build/server/chunks/_server.ts-Mttr0-Sl.js +48 -0
- package/build/server/chunks/_server.ts-Mttr0-Sl.js.map +1 -0
- package/build/server/chunks/_server.ts-jtqWDWcf.js +45 -0
- package/build/server/chunks/_server.ts-jtqWDWcf.js.map +1 -0
- package/build/server/chunks/{cache-Me3zUAaD.js → cache-BlMaDsHi.js} +2 -2
- package/build/server/chunks/{cache-Me3zUAaD.js.map → cache-BlMaDsHi.js.map} +1 -1
- package/build/server/chunks/{client-CfNnl32g.js → client-Ds1brw-8.js} +4 -4
- package/build/server/chunks/{client-CfNnl32g.js.map → client-Ds1brw-8.js.map} +1 -1
- package/build/server/chunks/client2-DngLdcUc.js +7 -0
- package/build/server/chunks/{client2-DDP30_vY.js.map → client2-DngLdcUc.js.map} +1 -1
- package/build/server/chunks/coordinator-DMU_ADXf.js +530 -0
- package/build/server/chunks/coordinator-DMU_ADXf.js.map +1 -0
- package/build/server/chunks/{index-CJrGuxuM.js → index-CoYB03g7.js} +2 -2
- package/build/server/chunks/{index-CJrGuxuM.js.map → index-CoYB03g7.js.map} +1 -1
- package/build/server/chunks/{index-server--49oHtA0.js → index-server-Bq3cnK69.js} +2 -2
- package/build/server/chunks/{index-server--49oHtA0.js.map → index-server-Bq3cnK69.js.map} +1 -1
- package/build/server/chunks/{index2-MY7PXeAc.js → index2-dSGQ9Eaa.js} +2 -2
- package/build/server/chunks/{index2-MY7PXeAc.js.map → index2-dSGQ9Eaa.js.map} +1 -1
- package/build/server/chunks/{pty-manager-RmhVe2Ez.js → pty-manager-41h3IK8K.js} +100 -2
- package/build/server/chunks/pty-manager-41h3IK8K.js.map +1 -0
- package/build/server/chunks/qwen-reader-DGfUbKaJ.js +2112 -0
- package/build/server/chunks/qwen-reader-DGfUbKaJ.js.map +1 -0
- package/build/server/chunks/{registry-DzJj2E6I.js → registry-D4J_CuzW.js} +56 -24
- package/build/server/chunks/registry-D4J_CuzW.js.map +1 -0
- package/build/server/chunks/{root-xvQIR1Bt.js → root-D4IoFC8F.js} +2 -2
- package/build/server/chunks/root-D4IoFC8F.js.map +1 -0
- package/build/server/chunks/{state.svelte-RCtlkrNH.js → state.svelte-CmHqngc_.js} +3 -3
- package/build/server/chunks/{state.svelte-RCtlkrNH.js.map → state.svelte-CmHqngc_.js.map} +1 -1
- package/build/server/chunks/{stores-C-LqoonT.js → stores-CRYxfF0o.js} +4 -4
- package/build/server/chunks/stores-CRYxfF0o.js.map +1 -0
- package/build/server/chunks/super-session-handler-DPyxFgmz.js +22 -0
- package/build/server/chunks/super-session-handler-DPyxFgmz.js.map +1 -0
- package/build/server/index.js +4 -4
- package/build/server/index.js.map +1 -1
- package/build/server/manifest.js +79 -21
- package/build/server/manifest.js.map +1 -1
- package/package.json +2 -2
- package/scripts/e2e-all-features.sh +204 -0
- package/scripts/e2e-cross-terminal.sh +168 -0
- package/server.ts +37 -0
- package/src/lib/modules/client/common/provider.ts +0 -2
- package/src/lib/modules/client/terminal/ChatView.svelte +9 -2
- package/src/lib/modules/client/terminal/LaunchSheet.svelte +3 -0
- package/src/lib/modules/server/sessions/amp-reader.ts +439 -0
- package/src/lib/modules/server/sessions/copilot-reader.ts +542 -0
- package/src/lib/modules/server/sessions/cursor-reader.ts +634 -0
- package/src/lib/modules/server/sessions/gemini-reader.ts +48 -25
- package/src/lib/modules/server/sessions/opencode-reader.ts +13 -12
- package/src/lib/modules/server/sessions/process-detector.ts +37 -60
- package/src/lib/modules/server/sessions/provider-paths.ts +173 -0
- package/src/lib/modules/server/sessions/qwen-reader.ts +41 -15
- package/src/lib/modules/server/sessions/registry.ts +55 -14
- package/src/lib/modules/server/sos/coordinator.ts +492 -0
- package/src/lib/modules/server/sos/policy-gate.ts +56 -0
- package/src/lib/modules/server/sos/relay-store.ts +159 -0
- package/src/lib/modules/server/terminal/generic-session-watcher.ts +163 -0
- package/src/lib/modules/server/terminal/pty-input.ts +37 -0
- package/src/lib/modules/server/terminal/pty-manager.ts +51 -0
- package/src/lib/modules/server/ws/server.ts +6 -1
- package/src/lib/modules/server/ws/session-handler.ts +17 -2
- package/src/lib/modules/server/ws/super-session-handler.ts +200 -0
- package/src/lib/theme.css +1 -2
- package/src/lib/types/generated/Sessions.ts +1 -4
- package/src/lib/types/index.ts +2 -1
- package/src/lib/types/server.ts +23 -6
- package/src/lib/types/sessions.ts +1 -10
- package/src/lib/types/sos.ts +134 -0
- package/src/routes/+layout.svelte +9 -2
- package/src/routes/api/sessions/connect/+server.ts +7 -3
- package/src/routes/api/sos/+server.ts +36 -0
- package/src/routes/api/sos/[id]/+server.ts +55 -0
- package/src/routes/api/sos/[id]/inject/+server.ts +44 -0
- package/src/routes/api/sos/[id]/members/+server.ts +47 -0
- package/src/routes/api/sos/[id]/members/[mid]/+server.ts +17 -0
- package/src/routes/api/sos/[id]/rules/+server.ts +85 -0
- package/src/routes/sos/+page.svelte +195 -0
- package/src/routes/sos/[id]/+page.svelte +677 -0
- package/build/client/_app/immutable/assets/0.B0O0vCnX.css.br +0 -0
- package/build/client/_app/immutable/chunks/BRqaaL5D.js.br +0 -0
- package/build/client/_app/immutable/chunks/BRqaaL5D.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BctvtE4d.js.br +0 -0
- package/build/client/_app/immutable/chunks/BxFShcQO.js +0 -1
- package/build/client/_app/immutable/chunks/BxFShcQO.js.br +0 -0
- package/build/client/_app/immutable/chunks/BxFShcQO.js.gz +0 -0
- package/build/client/_app/immutable/chunks/ByzqAuXw.js +0 -3
- package/build/client/_app/immutable/chunks/ByzqAuXw.js.br +0 -0
- package/build/client/_app/immutable/chunks/ByzqAuXw.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C5VOyQCG.js.br +0 -0
- package/build/client/_app/immutable/chunks/C5VOyQCG.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C_9BZILB.js.br +0 -0
- package/build/client/_app/immutable/chunks/C_9BZILB.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cg3dlX05.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cg3dlX05.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CjfxuHdN.js.br +0 -0
- package/build/client/_app/immutable/chunks/CjfxuHdN.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DYuMZGL5.js.br +0 -0
- package/build/client/_app/immutable/chunks/DYuMZGL5.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DZQMsHM5.js.br +0 -0
- package/build/client/_app/immutable/chunks/DZQMsHM5.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DZvnhU_8.js.br +0 -0
- package/build/client/_app/immutable/chunks/DZvnhU_8.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Pw0jDB7M.js +0 -1
- package/build/client/_app/immutable/chunks/Pw0jDB7M.js.br +0 -0
- package/build/client/_app/immutable/chunks/Pw0jDB7M.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.CNaTe-zm.js +0 -2
- package/build/client/_app/immutable/entry/app.CNaTe-zm.js.br +0 -0
- package/build/client/_app/immutable/entry/app.CNaTe-zm.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.hxYnjcDu.js +0 -1
- package/build/client/_app/immutable/entry/start.hxYnjcDu.js.br +0 -0
- package/build/client/_app/immutable/entry/start.hxYnjcDu.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.C3ELOf4c.js +0 -7
- package/build/client/_app/immutable/nodes/0.C3ELOf4c.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.C3ELOf4c.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.Fqso94b3.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.Fqso94b3.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.BusCVJWk.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.BusCVJWk.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.DUlpocIc.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.DUlpocIc.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.BSVqdrrD.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.BSVqdrrD.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.Cfj35gpY.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.Cfj35gpY.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.CG4eKRH0.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.CG4eKRH0.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.DHilxD1o.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.DHilxD1o.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.BjKgvSie.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.BjKgvSie.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.BRT6HOXB.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.BRT6HOXB.js.gz +0 -0
- package/build/server/chunks/1-Bw5KlAjL.js +0 -9
- package/build/server/chunks/6-BZ0enR6b.js +0 -9
- package/build/server/chunks/7-Lg8imTZn.js +0 -9
- package/build/server/chunks/8-DKs4yOL7.js +0 -9
- package/build/server/chunks/8-DKs4yOL7.js.map +0 -1
- package/build/server/chunks/9-UNmpUWDY.js +0 -9
- package/build/server/chunks/9-UNmpUWDY.js.map +0 -1
- package/build/server/chunks/Button-B5dU-ntz.js.map +0 -1
- package/build/server/chunks/Icon-C7Ml3GX6.js.map +0 -1
- package/build/server/chunks/Input-CPGO0sbS.js.map +0 -1
- package/build/server/chunks/Pill-CcrtCejm.js.map +0 -1
- package/build/server/chunks/Shimmer-C5jkvGr1.js.map +0 -1
- package/build/server/chunks/_layout.svelte-noB4j-v2.js.map +0 -1
- package/build/server/chunks/_page.svelte-C60lAagP.js.map +0 -1
- package/build/server/chunks/_page.svelte-DnTpPnPR.js.map +0 -1
- package/build/server/chunks/_server.ts-5wx4ZppI.js.map +0 -1
- package/build/server/chunks/_server.ts-B1z0q6qZ.js.map +0 -1
- package/build/server/chunks/_server.ts-Bt7EAfjo.js.map +0 -1
- package/build/server/chunks/_server.ts-CKXVBbwb.js.map +0 -1
- package/build/server/chunks/_server.ts-CgHc1Zpx.js.map +0 -1
- package/build/server/chunks/_server.ts-CyjDrcZN.js.map +0 -1
- package/build/server/chunks/_server.ts-DZ5naqSL.js.map +0 -1
- package/build/server/chunks/client2-DDP30_vY.js +0 -7
- package/build/server/chunks/opencode-db-path-BwaPufWf.js +0 -411
- package/build/server/chunks/opencode-db-path-BwaPufWf.js.map +0 -1
- package/build/server/chunks/pty-manager-RmhVe2Ez.js.map +0 -1
- package/build/server/chunks/qwen-reader-2fTFuC_D.js +0 -622
- package/build/server/chunks/qwen-reader-2fTFuC_D.js.map +0 -1
- package/build/server/chunks/registry-DzJj2E6I.js.map +0 -1
- package/build/server/chunks/root-xvQIR1Bt.js.map +0 -1
- package/build/server/chunks/stores-C-LqoonT.js.map +0 -1
- /package/build/client/_app/immutable/assets/{8.BhoBXADL.css → 10.BhoBXADL.css} +0 -0
- /package/build/client/_app/immutable/assets/{8.BhoBXADL.css.br → 10.BhoBXADL.css.br} +0 -0
- /package/build/client/_app/immutable/assets/{8.BhoBXADL.css.gz → 10.BhoBXADL.css.gz} +0 -0
- /package/build/client/_app/immutable/assets/{9.v5KA95xm.css → 11.v5KA95xm.css} +0 -0
- /package/build/client/_app/immutable/assets/{9.v5KA95xm.css.br → 11.v5KA95xm.css.br} +0 -0
- /package/build/client/_app/immutable/assets/{9.v5KA95xm.css.gz → 11.v5KA95xm.css.gz} +0 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GenericSessionWatcher — live tailing for the five read-only providers
|
|
3
|
+
* (cursor, copilot, qwen, gemini, amp).
|
|
4
|
+
*
|
|
5
|
+
* The byte-offset watchers (claude/codex) and the SQLite poller (opencode)
|
|
6
|
+
* each understand one wire format. These five providers store sessions in
|
|
7
|
+
* heterogeneous shapes — per-turn JSONL for some, a single rewritten JSON
|
|
8
|
+
* document for others — so a byte-incremental reader would need five bespoke
|
|
9
|
+
* parsers. Instead this watcher re-parses the whole file on each change via
|
|
10
|
+
* the shared `parseReadOnlyProviderFile` dispatch and emits only messages
|
|
11
|
+
* whose ID it has not delivered before. That makes it correct for both
|
|
12
|
+
* append-only and whole-document-rewrite formats with one code path.
|
|
13
|
+
*
|
|
14
|
+
* The public surface (getHistory + ref-counted subscribe) matches
|
|
15
|
+
* SessionWatcherLike, so the server's session-watcher adapter can route to it
|
|
16
|
+
* by path without any handler changes.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { ConversationMessage, GenericWatchedFile, OnNewEntries } from '$lib/types';
|
|
20
|
+
|
|
21
|
+
import { watch as chokidarWatch } from 'chokidar';
|
|
22
|
+
|
|
23
|
+
import { parseReadOnlyProviderFile } from '../sessions/provider-paths';
|
|
24
|
+
|
|
25
|
+
class GenericSessionWatcher {
|
|
26
|
+
private watched = new Map<string, GenericWatchedFile>();
|
|
27
|
+
|
|
28
|
+
/** Re-read the whole file and return the full parsed conversation. */
|
|
29
|
+
getHistory(filePath: string): ConversationMessage[] {
|
|
30
|
+
return parseReadOnlyProviderFile(filePath);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Stop watching a single file and release its chokidar handle. */
|
|
34
|
+
stop(filePath: string): void {
|
|
35
|
+
const watched = this.watched.get(filePath);
|
|
36
|
+
if (!watched) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
void watched.watcher.close();
|
|
40
|
+
this.watched.delete(filePath);
|
|
41
|
+
console.log(`[generic-watcher] Stopped watching: ${filePath}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Stop watching every file. */
|
|
45
|
+
stopAll(): void {
|
|
46
|
+
for (const [filePath] of this.watched) {
|
|
47
|
+
this.stop(filePath);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Subscribe to new messages for a file. Adds the callback to an existing
|
|
53
|
+
* watcher when one is present (ref-counted), otherwise starts a chokidar
|
|
54
|
+
* watch. Returns an unsubscribe function that tears the watcher down once
|
|
55
|
+
* the last subscriber leaves — identical lifecycle to SessionWatcher.
|
|
56
|
+
*/
|
|
57
|
+
subscribe(filePath: string, onNewEntries: OnNewEntries): () => void {
|
|
58
|
+
const existing = this.watched.get(filePath);
|
|
59
|
+
if (existing) {
|
|
60
|
+
existing.callbacks.add(onNewEntries);
|
|
61
|
+
return () => {
|
|
62
|
+
this.removeCallback(filePath, onNewEntries);
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Seed the emitted set with everything already in the file so the first
|
|
67
|
+
// change only surfaces genuinely new messages — history is sent separately
|
|
68
|
+
// via getHistory, mirroring the byte watchers' initial-offset behaviour.
|
|
69
|
+
const emittedMessageIds = new Set<string>();
|
|
70
|
+
try {
|
|
71
|
+
for (const msg of parseReadOnlyProviderFile(filePath)) {
|
|
72
|
+
emittedMessageIds.add(msg.id);
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
// Degrade gracefully: an unreadable/racy file at subscribe time must not
|
|
76
|
+
// prevent watching — the first change will just re-surface what's there.
|
|
77
|
+
console.error(`[generic-watcher] Failed to seed ${filePath}:`, error);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const watcher = chokidarWatch(filePath, {
|
|
81
|
+
awaitWriteFinish: { pollInterval: 100, stabilityThreshold: 200 },
|
|
82
|
+
ignoreInitial: true,
|
|
83
|
+
usePolling: false,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const watched: GenericWatchedFile = {
|
|
87
|
+
callbacks: new Set([onNewEntries]),
|
|
88
|
+
emittedMessageIds,
|
|
89
|
+
filePath,
|
|
90
|
+
watcher,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const onChange = (): void => {
|
|
94
|
+
this.readNew(watched);
|
|
95
|
+
};
|
|
96
|
+
watcher.on('add', onChange);
|
|
97
|
+
watcher.on('change', onChange);
|
|
98
|
+
watcher.on('error', (error) => {
|
|
99
|
+
console.error(`[generic-watcher] Error watching ${filePath}:`, error);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
this.watched.set(filePath, watched);
|
|
103
|
+
console.log(`[generic-watcher] Watching: ${filePath} (seeded ${emittedMessageIds.size} msgs)`);
|
|
104
|
+
|
|
105
|
+
return () => {
|
|
106
|
+
this.removeCallback(filePath, onNewEntries);
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Legacy fire-and-forget API matching SessionWatcher.watch(). */
|
|
111
|
+
watch(filePath: string, onNewEntries: OnNewEntries): void {
|
|
112
|
+
this.subscribe(filePath, onNewEntries);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Re-parse the file and deliver any messages whose ID has not been emitted.
|
|
117
|
+
* If a rewrite drops the count below what we have seen (truncation/reset),
|
|
118
|
+
* the new IDs simply won't match, so nothing spurious is sent.
|
|
119
|
+
*/
|
|
120
|
+
private readNew(watched: GenericWatchedFile): void {
|
|
121
|
+
let messages: ConversationMessage[];
|
|
122
|
+
try {
|
|
123
|
+
messages = parseReadOnlyProviderFile(watched.filePath);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.error(`[generic-watcher] Failed to re-read ${watched.filePath}:`, error);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const fresh = messages.filter((msg) => !watched.emittedMessageIds.has(msg.id));
|
|
130
|
+
if (fresh.length === 0) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
for (const msg of fresh) {
|
|
134
|
+
watched.emittedMessageIds.add(msg.id);
|
|
135
|
+
}
|
|
136
|
+
for (const cb of watched.callbacks) {
|
|
137
|
+
try {
|
|
138
|
+
cb(fresh);
|
|
139
|
+
} catch (cbError) {
|
|
140
|
+
console.error('[generic-watcher] Callback error:', cbError);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Remove one callback; stop watching when none remain. */
|
|
146
|
+
private removeCallback(filePath: string, onNewEntries: OnNewEntries): void {
|
|
147
|
+
const watched = this.watched.get(filePath);
|
|
148
|
+
if (!watched) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
watched.callbacks.delete(onNewEntries);
|
|
152
|
+
if (watched.callbacks.size === 0) {
|
|
153
|
+
this.stop(filePath);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Single shared instance across module loaders (matches sessionWatcher).
|
|
159
|
+
const GW_GLOBAL_KEY = '__shooter_generic_session_watcher';
|
|
160
|
+
export const genericSessionWatcher: GenericSessionWatcher =
|
|
161
|
+
((globalThis as Record<string, unknown>)[GW_GLOBAL_KEY] as GenericSessionWatcher) ||
|
|
162
|
+
new GenericSessionWatcher();
|
|
163
|
+
(globalThis as Record<string, unknown>)[GW_GLOBAL_KEY] = genericSessionWatcher;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTY input helpers.
|
|
3
|
+
*
|
|
4
|
+
* Submitting text to an interactive agent TUI (codex, claude, gemini, qwen, …)
|
|
5
|
+
* is not as simple as appending a newline. These TUIs read the PTY in raw mode:
|
|
6
|
+
*
|
|
7
|
+
* - A bare LF (`\n`) is NOT the Enter key — it types a literal newline into
|
|
8
|
+
* the prompt and never submits. (Verified: LF leaves codex sitting on its
|
|
9
|
+
* prompt; the message just accumulates.)
|
|
10
|
+
* - Even `"<text>\r"` written as a SINGLE chunk is treated as a bracketed
|
|
11
|
+
* paste by the TUI, so the trailing CR is absorbed into the pasted body
|
|
12
|
+
* instead of submitting. (Verified: codex types the text but does not run.)
|
|
13
|
+
*
|
|
14
|
+
* The reliable approach — the same bytes a real terminal emulator sends when a
|
|
15
|
+
* human pastes and presses Enter — is to wrap the body in an explicit bracketed
|
|
16
|
+
* paste (`ESC[200~` … `ESC[201~`) and then send a CR. The paste-end marker
|
|
17
|
+
* closes the paste unambiguously, so the following CR is a real Enter. This
|
|
18
|
+
* also preserves embedded newlines in multi-line messages (the whole point of
|
|
19
|
+
* bracketed paste) and submits correctly in modern interactive shells, where
|
|
20
|
+
* bracketed paste is enabled by default.
|
|
21
|
+
*
|
|
22
|
+
* Verified empirically against codex 0.136 and claude 2.1 — both receive the
|
|
23
|
+
* message and complete a turn.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const PASTE_START = '\x1b[200~';
|
|
27
|
+
const PASTE_END = '\x1b[201~';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Build the PTY byte sequence that delivers `text` to an interactive terminal
|
|
31
|
+
* and submits it (presses Enter). Any trailing newline the caller added is
|
|
32
|
+
* stripped — the CR after the paste-end marker is what submits.
|
|
33
|
+
*/
|
|
34
|
+
export function ptySubmitSequence(text: string): string {
|
|
35
|
+
const body = text.replace(/[\r\n]+$/, '');
|
|
36
|
+
return `${PASTE_START}${body}${PASTE_END}\r`;
|
|
37
|
+
}
|
|
@@ -13,6 +13,10 @@ import path from 'path';
|
|
|
13
13
|
import { fileURLToPath } from 'url';
|
|
14
14
|
|
|
15
15
|
import { findCodexRolloutForCwd } from '../sessions/codex-reader';
|
|
16
|
+
import {
|
|
17
|
+
discoverReadOnlyProviderSessionFile,
|
|
18
|
+
readOnlySourceForCommand,
|
|
19
|
+
} from '../sessions/provider-paths';
|
|
16
20
|
import { broadcastEvent } from '../ws/server.js';
|
|
17
21
|
import { HolderClient } from './holder-client';
|
|
18
22
|
import { openCodeWatcher } from './opencode-watcher';
|
|
@@ -1005,6 +1009,53 @@ class PtyManager {
|
|
|
1005
1009
|
5 * 60 * 1000
|
|
1006
1010
|
);
|
|
1007
1011
|
}
|
|
1012
|
+
|
|
1013
|
+
// For the read-only providers (cursor/copilot/qwen/gemini/amp): poll their
|
|
1014
|
+
// store for a session started after launch and matching this cwd, then set
|
|
1015
|
+
// sessionFile to that path. The WS adapter routes it to the generic watcher
|
|
1016
|
+
// by its provider-root path, giving the same live-tail the JSONL watchers
|
|
1017
|
+
// provide for Claude/Codex.
|
|
1018
|
+
const readOnlySource = readOnlySourceForCommand(command);
|
|
1019
|
+
if (readOnlySource) {
|
|
1020
|
+
const launchTime = terminal.createdAt.getTime();
|
|
1021
|
+
terminal.pollTimer = setInterval(() => {
|
|
1022
|
+
if (terminal.status === 'exited' || terminal.sessionFile) {
|
|
1023
|
+
if (terminal.pollTimer) {
|
|
1024
|
+
clearInterval(terminal.pollTimer);
|
|
1025
|
+
terminal.pollTimer = null;
|
|
1026
|
+
}
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
try {
|
|
1030
|
+
const file = discoverReadOnlyProviderSessionFile(
|
|
1031
|
+
readOnlySource,
|
|
1032
|
+
cwd,
|
|
1033
|
+
launchTime,
|
|
1034
|
+
Date.now()
|
|
1035
|
+
);
|
|
1036
|
+
if (file) {
|
|
1037
|
+
terminal.sessionFile = file;
|
|
1038
|
+
if (terminal.pollTimer) {
|
|
1039
|
+
clearInterval(terminal.pollTimer);
|
|
1040
|
+
terminal.pollTimer = null;
|
|
1041
|
+
}
|
|
1042
|
+
terminalStore.update(id, { sessionFile: file });
|
|
1043
|
+
}
|
|
1044
|
+
} catch {
|
|
1045
|
+
// ignore filesystem errors
|
|
1046
|
+
}
|
|
1047
|
+
}, 2000);
|
|
1048
|
+
|
|
1049
|
+
setTimeout(
|
|
1050
|
+
() => {
|
|
1051
|
+
if (terminal.pollTimer) {
|
|
1052
|
+
clearInterval(terminal.pollTimer);
|
|
1053
|
+
terminal.pollTimer = null;
|
|
1054
|
+
}
|
|
1055
|
+
},
|
|
1056
|
+
5 * 60 * 1000
|
|
1057
|
+
);
|
|
1058
|
+
}
|
|
1008
1059
|
}
|
|
1009
1060
|
|
|
1010
1061
|
/** Wire up all HolderClient callbacks (activity, CWD, output, exit, disconnect). */
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
handleEventsConnection,
|
|
16
16
|
} from './events-handler.js';
|
|
17
17
|
import { handleSessionConnection } from './session-handler.js';
|
|
18
|
+
import { handleSuperSessionConnection } from './super-session-handler.js';
|
|
18
19
|
import { handleTerminalConnection } from './terminal-handler.js';
|
|
19
20
|
export type { WireShooterEvent as ShooterEvent } from '$lib/types';
|
|
20
21
|
|
|
@@ -61,10 +62,11 @@ export function setupWebSocketHandlers(
|
|
|
61
62
|
|
|
62
63
|
// Route matching
|
|
63
64
|
const terminalMatch = /^\/ws\/terminal\/(.+)$/.exec(pathname);
|
|
65
|
+
const superSessionMatch = /^\/ws\/super-session\/(.+)$/.exec(pathname);
|
|
64
66
|
const sessionMatch = /^\/ws\/session\/(.+)$/.exec(pathname);
|
|
65
67
|
const isEvents = pathname === '/ws/events';
|
|
66
68
|
|
|
67
|
-
if (!terminalMatch && !sessionMatch && !isEvents) {
|
|
69
|
+
if (!terminalMatch && !superSessionMatch && !sessionMatch && !isEvents) {
|
|
68
70
|
socket.destroy();
|
|
69
71
|
return;
|
|
70
72
|
}
|
|
@@ -83,6 +85,9 @@ export function setupWebSocketHandlers(
|
|
|
83
85
|
if (terminalMatch) {
|
|
84
86
|
const terminalId = terminalMatch[1];
|
|
85
87
|
handleTerminalConnection(ws, terminalId);
|
|
88
|
+
} else if (superSessionMatch) {
|
|
89
|
+
const superSessionId = superSessionMatch[1];
|
|
90
|
+
handleSuperSessionConnection(ws, superSessionId);
|
|
86
91
|
} else if (sessionMatch) {
|
|
87
92
|
const sessionId = sessionMatch[1];
|
|
88
93
|
handleSessionConnection(ws, sessionId);
|
|
@@ -23,6 +23,7 @@ import * as fs from 'fs';
|
|
|
23
23
|
import * as path from 'path';
|
|
24
24
|
|
|
25
25
|
import { findCodexRolloutById } from '../sessions/codex-reader';
|
|
26
|
+
import { ptySubmitSequence } from '../terminal/pty-input';
|
|
26
27
|
|
|
27
28
|
// ── Module-level references ──────────────────────────────────────────
|
|
28
29
|
|
|
@@ -222,7 +223,17 @@ function findTerminalBySessionUuid(uuid: string): ManagedTerminal | undefined {
|
|
|
222
223
|
// module-level _ptyManagerFull reference if available.
|
|
223
224
|
if (_ptyManagerFull) {
|
|
224
225
|
for (const t of _ptyManagerFull.list()) {
|
|
225
|
-
|
|
226
|
+
// Match across every provider's file naming so a running non-Claude
|
|
227
|
+
// agent can be reached (and replied to) by its session UUID:
|
|
228
|
+
// claude/cursor/qwen: <uuid>.jsonl ; codex: -<uuid>.jsonl ;
|
|
229
|
+
// copilot: <uuid>.jsonl OR <uuid>/events.jsonl ; amp: T-<uuid>.json ;
|
|
230
|
+
// opencode: bare session id.
|
|
231
|
+
if (
|
|
232
|
+
t.sessionFile?.includes(`${uuid}.jsonl`) ||
|
|
233
|
+
t.sessionFile?.endsWith(`/${uuid}/events.jsonl`) ||
|
|
234
|
+
t.sessionFile?.endsWith(`/T-${uuid}.json`) ||
|
|
235
|
+
t.openCodeSessionId === uuid
|
|
236
|
+
) {
|
|
226
237
|
return _ptyManager.getTerminal(t.id);
|
|
227
238
|
}
|
|
228
239
|
}
|
|
@@ -537,7 +548,11 @@ function wireClientMessages(ws: WebSocket, state: ConnectionState): void {
|
|
|
537
548
|
safeSend(ws, { message: 'Terminal has exited', type: 'error' });
|
|
538
549
|
return;
|
|
539
550
|
}
|
|
540
|
-
|
|
551
|
+
// Deliver + submit via a bracketed paste (see pty-input.ts): a bare
|
|
552
|
+
// LF never submits to an agent TUI and a trailing CR in the same
|
|
553
|
+
// write is absorbed as paste content. Bracketed paste closes the
|
|
554
|
+
// paste explicitly so the following CR is a real Enter.
|
|
555
|
+
currentTerminal.pty.write(ptySubmitSequence(msg.text));
|
|
541
556
|
break;
|
|
542
557
|
}
|
|
543
558
|
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
// WebSocket handler for /ws/super-session/:id — the merged Session-Over-Sessions
|
|
2
|
+
// stream. On connect it replays the merged transcript (sos-history) and then
|
|
3
|
+
// streams live tagged messages from every member. Accepts human-driven control
|
|
4
|
+
// messages: relay-forward (inject into a member's terminal), member-add,
|
|
5
|
+
// member-remove. Mirrors session-handler.ts in shape.
|
|
6
|
+
|
|
7
|
+
import type { SessionSource, SosClientMessage, SosServerMessage } from '$lib/types';
|
|
8
|
+
import type { WebSocket } from 'ws';
|
|
9
|
+
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
|
|
12
|
+
import { PROVIDERS } from '../sessions/registry';
|
|
13
|
+
import { sosCoordinator } from '../sos/coordinator';
|
|
14
|
+
|
|
15
|
+
const MAX_RELAY_TEXT = 10240; // 10 KB, same cap as /ws/session send-input
|
|
16
|
+
// Stop streaming to a client whose outbound buffer exceeds this — bounds memory
|
|
17
|
+
// growth when a slow consumer can't drain sos-history replay or a live burst.
|
|
18
|
+
const MAX_WS_BUFFERED_BYTES = 1_000_000;
|
|
19
|
+
const VALID_SOURCES = new Set<string>(PROVIDERS.map((p) => p.source));
|
|
20
|
+
|
|
21
|
+
export function handleSuperSessionConnection(ws: WebSocket, id: string): void {
|
|
22
|
+
const session = sosCoordinator.getSuperSession(id);
|
|
23
|
+
if (!session) {
|
|
24
|
+
safeSend(ws, { message: `Super-session not found: ${id}`, type: 'sos-error' });
|
|
25
|
+
ws.close(1008, 'Super-session not found');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// subscribe() replays the current transcript as an sos-history message, then
|
|
30
|
+
// streams live sos-message / sos-member-* events. If a send fails (socket
|
|
31
|
+
// closed or buffer over cap), stop feeding this client to bound memory.
|
|
32
|
+
let unsubscribe: (() => void) | null = null;
|
|
33
|
+
unsubscribe = sosCoordinator.subscribe(id, (msg) => {
|
|
34
|
+
if (!safeSend(ws, msg)) {
|
|
35
|
+
unsubscribe?.();
|
|
36
|
+
unsubscribe = null;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
ws.on('message', (raw: Buffer | string) => {
|
|
41
|
+
const data = typeof raw === 'string' ? raw : raw.toString('utf-8');
|
|
42
|
+
const msg = parseClientMessage(data);
|
|
43
|
+
if (!msg) {
|
|
44
|
+
// Surface schema drift instead of silently dropping the frame — a dead
|
|
45
|
+
// control in the UI is much harder to debug than an explicit error.
|
|
46
|
+
safeSend(ws, { message: 'Invalid super-session control message', type: 'sos-error' });
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
handleClientMessage(ws, id, msg);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
ws.on('close', () => {
|
|
53
|
+
unsubscribe?.();
|
|
54
|
+
});
|
|
55
|
+
ws.on('error', () => {
|
|
56
|
+
// cleanup happens in 'close'
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** True when the string is a known provider source. */
|
|
61
|
+
export function isValidProvider(value: string): value is SessionSource {
|
|
62
|
+
return VALID_SOURCES.has(value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** True for a bare session id (OpenCode) or an absolute path under HOME. */
|
|
66
|
+
export function isValidSessionKey(key: string): boolean {
|
|
67
|
+
if (/^[A-Za-z0-9_-]+$/.test(key)) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
const home = process.env.HOME || '';
|
|
71
|
+
if (home === '' || !path.isAbsolute(key)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
// Resolve before comparing so `..` segments cannot escape the HOME sandbox
|
|
75
|
+
// (e.g. /home/user/../etc/passwd passes a raw prefix check but not this).
|
|
76
|
+
const relative = path.relative(path.resolve(home), path.resolve(key));
|
|
77
|
+
return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function handleClientMessage(ws: WebSocket, superSessionId: string, msg: SosClientMessage): void {
|
|
81
|
+
switch (msg.type) {
|
|
82
|
+
case 'member-add': {
|
|
83
|
+
const member = sosCoordinator.addMember(superSessionId, {
|
|
84
|
+
capability: msg.capability,
|
|
85
|
+
provider: msg.provider,
|
|
86
|
+
sessionKey: msg.sessionKey,
|
|
87
|
+
terminalId: msg.terminalId ?? null,
|
|
88
|
+
});
|
|
89
|
+
if (!member) {
|
|
90
|
+
safeSend(ws, { message: 'Failed to add member', type: 'sos-error' });
|
|
91
|
+
}
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
case 'member-remove': {
|
|
95
|
+
const ok = sosCoordinator.removeMember(superSessionId, msg.memberId);
|
|
96
|
+
if (!ok) {
|
|
97
|
+
safeSend(ws, { message: 'Member not found', type: 'sos-error' });
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case 'relay-approve': {
|
|
102
|
+
if (!sosCoordinator.approveRelay(superSessionId, msg.relayId)) {
|
|
103
|
+
safeSend(ws, { message: 'Pending relay not found', type: 'sos-error' });
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
case 'relay-deny': {
|
|
108
|
+
if (!sosCoordinator.denyRelay(superSessionId, msg.relayId)) {
|
|
109
|
+
safeSend(ws, { message: 'Pending relay not found', type: 'sos-error' });
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case 'relay-forward': {
|
|
114
|
+
const error = sosCoordinator.relayForward(superSessionId, msg.toMemberId, msg.text);
|
|
115
|
+
if (error) {
|
|
116
|
+
safeSend(ws, { message: error, type: 'sos-error' });
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function parseClientMessage(raw: string): null | SosClientMessage {
|
|
124
|
+
let parsed: unknown;
|
|
125
|
+
try {
|
|
126
|
+
parsed = JSON.parse(raw);
|
|
127
|
+
} catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const msg = parsed as Record<string, unknown>;
|
|
134
|
+
|
|
135
|
+
switch (msg.type) {
|
|
136
|
+
case 'member-add': {
|
|
137
|
+
if (
|
|
138
|
+
typeof msg.sessionKey !== 'string' ||
|
|
139
|
+
!isValidSessionKey(msg.sessionKey) ||
|
|
140
|
+
typeof msg.provider !== 'string' ||
|
|
141
|
+
!isValidProvider(msg.provider)
|
|
142
|
+
) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
capability: typeof msg.capability === 'string' ? msg.capability : undefined,
|
|
147
|
+
provider: msg.provider,
|
|
148
|
+
sessionKey: msg.sessionKey,
|
|
149
|
+
terminalId: typeof msg.terminalId === 'string' ? msg.terminalId : undefined,
|
|
150
|
+
type: 'member-add',
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
case 'member-remove': {
|
|
154
|
+
if (typeof msg.memberId !== 'string' || msg.memberId.length === 0) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
return { memberId: msg.memberId, type: 'member-remove' };
|
|
158
|
+
}
|
|
159
|
+
case 'relay-approve': {
|
|
160
|
+
if (typeof msg.relayId !== 'string' || msg.relayId.length === 0) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
return { relayId: msg.relayId, type: 'relay-approve' };
|
|
164
|
+
}
|
|
165
|
+
case 'relay-deny': {
|
|
166
|
+
if (typeof msg.relayId !== 'string' || msg.relayId.length === 0) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
return { relayId: msg.relayId, type: 'relay-deny' };
|
|
170
|
+
}
|
|
171
|
+
case 'relay-forward': {
|
|
172
|
+
if (
|
|
173
|
+
typeof msg.toMemberId !== 'string' ||
|
|
174
|
+
typeof msg.text !== 'string' ||
|
|
175
|
+
msg.text.length === 0 ||
|
|
176
|
+
msg.text.length > MAX_RELAY_TEXT
|
|
177
|
+
) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
return { text: msg.text, toMemberId: msg.toMemberId, type: 'relay-forward' };
|
|
181
|
+
}
|
|
182
|
+
default:
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function safeSend(ws: WebSocket, msg: SosServerMessage): boolean {
|
|
188
|
+
try {
|
|
189
|
+
if (ws.readyState !== 1 /* OPEN */) {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
if (ws.bufferedAmount > MAX_WS_BUFFERED_BYTES) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
ws.send(JSON.stringify(msg));
|
|
196
|
+
return true;
|
|
197
|
+
} catch {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
package/src/lib/theme.css
CHANGED
|
@@ -527,8 +527,7 @@
|
|
|
527
527
|
}
|
|
528
528
|
|
|
529
529
|
/* Additional providers reuse the existing colour families (cosmetic only). */
|
|
530
|
-
.pill-source-qwen
|
|
531
|
-
.pill-source-iflow {
|
|
530
|
+
.pill-source-qwen {
|
|
532
531
|
--pill-background: var(--ds-red-100);
|
|
533
532
|
--pill-color: var(--ds-red-900);
|
|
534
533
|
--pill-font-size: 10px;
|
|
@@ -22,8 +22,7 @@ export type SessionSource =
|
|
|
22
22
|
| 'qwen'
|
|
23
23
|
| 'cursor'
|
|
24
24
|
| 'copilot'
|
|
25
|
-
| 'amp'
|
|
26
|
-
| 'iflow';
|
|
25
|
+
| 'amp';
|
|
27
26
|
|
|
28
27
|
export function decodeSessionSource(rawInput: unknown): SessionSource | null {
|
|
29
28
|
switch (rawInput) {
|
|
@@ -35,7 +34,6 @@ export function decodeSessionSource(rawInput: unknown): SessionSource | null {
|
|
|
35
34
|
case 'cursor':
|
|
36
35
|
case 'copilot':
|
|
37
36
|
case 'amp':
|
|
38
|
-
case 'iflow':
|
|
39
37
|
return rawInput;
|
|
40
38
|
}
|
|
41
39
|
return null;
|
|
@@ -51,7 +49,6 @@ export function _decodeSessionSource(rawInput: unknown): SessionSource | undefin
|
|
|
51
49
|
case 'cursor':
|
|
52
50
|
case 'copilot':
|
|
53
51
|
case 'amp':
|
|
54
|
-
case 'iflow':
|
|
55
52
|
return rawInput;
|
|
56
53
|
}
|
|
57
54
|
return;
|
package/src/lib/types/index.ts
CHANGED
|
@@ -12,8 +12,8 @@ export type * from './gemini';
|
|
|
12
12
|
export * from './generated';
|
|
13
13
|
export type * from './neurolink';
|
|
14
14
|
export type * from './server';
|
|
15
|
-
|
|
16
15
|
export type * from './sessions';
|
|
16
|
+
|
|
17
17
|
// Explicit re-exports to resolve conflicts between generated types and the
|
|
18
18
|
// hand-written sessions.ts versions. The generated Sessions module exports
|
|
19
19
|
// wrapper-class variants (CMessagePartTextPart, etc.) with `type: string`
|
|
@@ -27,5 +27,6 @@ export type {
|
|
|
27
27
|
ToolResultPart,
|
|
28
28
|
ToolUsePart,
|
|
29
29
|
} from './sessions';
|
|
30
|
+
export type * from './sos';
|
|
30
31
|
export type * from './terminal-client';
|
|
31
32
|
export type * from './ws';
|
package/src/lib/types/server.ts
CHANGED
|
@@ -24,6 +24,23 @@ export interface CodexWatchState {
|
|
|
24
24
|
watcher: FSWatcher;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Watch state for the generic re-read-on-change watcher used by the
|
|
29
|
+
* read-only providers (cursor, copilot, qwen, gemini, amp). Unlike the
|
|
30
|
+
* byte-offset watchers, it re-parses the whole file on each change and
|
|
31
|
+
* dedupes by message ID — robust for both append-only JSONL and
|
|
32
|
+
* whole-document JSON formats.
|
|
33
|
+
*/
|
|
34
|
+
export interface GenericWatchedFile {
|
|
35
|
+
callbacks: Set<OnNewEntries>;
|
|
36
|
+
/** Message IDs already delivered, so re-reads only emit genuinely new messages. */
|
|
37
|
+
emittedMessageIds: Set<string>;
|
|
38
|
+
filePath: string;
|
|
39
|
+
watcher: FSWatcher;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ── pty-manager types ───────────────────────────────────────────────
|
|
43
|
+
|
|
27
44
|
/** Messages received from the holder process (local ndjson protocol). */
|
|
28
45
|
export type HolderIncomingMessage =
|
|
29
46
|
| { active: boolean; type: 'activity' }
|
|
@@ -33,21 +50,19 @@ export type HolderIncomingMessage =
|
|
|
33
50
|
| { exitCode: null | number; exited: boolean; pid: number; type: 'info' }
|
|
34
51
|
| { path: string; type: 'cwd' };
|
|
35
52
|
|
|
36
|
-
// ── pty-manager types ───────────────────────────────────────────────
|
|
37
|
-
|
|
38
53
|
/** Messages sent to the holder process (local ndjson protocol). */
|
|
39
54
|
export type HolderOutgoingMessage =
|
|
40
55
|
| { cols: number; rows: number; type: 'resize' }
|
|
41
56
|
| { data: string; type: 'input' }
|
|
42
57
|
| { signal?: string; type: 'kill' };
|
|
43
58
|
|
|
59
|
+
// ── session-watcher types ───────────────────────────────────────────
|
|
60
|
+
|
|
44
61
|
/**
|
|
45
62
|
* Callback invoked when new JSONL entries are parsed from a watched file.
|
|
46
63
|
*/
|
|
47
64
|
export type OnNewEntries = (entries: ConversationMessage[]) => void;
|
|
48
65
|
|
|
49
|
-
// ── session-watcher types ───────────────────────────────────────────
|
|
50
|
-
|
|
51
66
|
export interface OpenCodeWatchState {
|
|
52
67
|
callbacks: Set<(messages: ConversationMessage[]) => void>;
|
|
53
68
|
/** Set of message IDs we have already emitted, to avoid duplicates. */
|
|
@@ -62,6 +77,8 @@ export interface OpenCodeWatchState {
|
|
|
62
77
|
sessionId: string;
|
|
63
78
|
}
|
|
64
79
|
|
|
80
|
+
// ── opencode-watcher types ──────────────────────────────────────────
|
|
81
|
+
|
|
65
82
|
export interface PtyManagedTerminal {
|
|
66
83
|
args: string[];
|
|
67
84
|
clients: Set<WebSocket>;
|
|
@@ -89,14 +106,14 @@ export interface PtyManagedTerminal {
|
|
|
89
106
|
watcherOffset: number;
|
|
90
107
|
}
|
|
91
108
|
|
|
92
|
-
// ──
|
|
109
|
+
// ── codex-watcher types ─────────────────────────────────────────────
|
|
93
110
|
|
|
94
111
|
export interface PtyOutputBuffer {
|
|
95
112
|
data: string[];
|
|
96
113
|
size: number;
|
|
97
114
|
}
|
|
98
115
|
|
|
99
|
-
// ──
|
|
116
|
+
// ── generic-session-watcher types ───────────────────────────────────
|
|
100
117
|
|
|
101
118
|
export interface SessionWatchedFile {
|
|
102
119
|
callbacks: Set<OnNewEntries>;
|
|
@@ -23,16 +23,7 @@ export interface ConversationMessage {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export interface DetectedProcess {
|
|
26
|
-
command:
|
|
27
|
-
| 'amp'
|
|
28
|
-
| 'claude'
|
|
29
|
-
| 'codex'
|
|
30
|
-
| 'copilot'
|
|
31
|
-
| 'cursor-agent'
|
|
32
|
-
| 'gemini'
|
|
33
|
-
| 'iflow'
|
|
34
|
-
| 'opencode'
|
|
35
|
-
| 'qwen';
|
|
26
|
+
command: 'amp' | 'claude' | 'codex' | 'copilot' | 'cursor-agent' | 'gemini' | 'opencode' | 'qwen';
|
|
36
27
|
cwd: string;
|
|
37
28
|
kind: string;
|
|
38
29
|
pid: number;
|