@openpalm/ui 0.13.0-beta.6 → 0.13.0-beta.7
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/.openpalm-ui-version +1 -1
- package/build/client/_app/immutable/assets/4.Cd3Y_8BZ.css +1 -0
- package/build/client/_app/immutable/assets/4.Cd3Y_8BZ.css.br +3 -0
- package/build/client/_app/immutable/assets/4.Cd3Y_8BZ.css.gz +0 -0
- package/build/client/_app/immutable/assets/6.BM7A1dW5.css +1 -0
- package/build/client/_app/immutable/assets/6.BM7A1dW5.css.br +0 -0
- package/build/client/_app/immutable/assets/6.BM7A1dW5.css.gz +0 -0
- package/build/client/_app/immutable/assets/{7.BTWb8aLW.css → 7.BsquVIMw.css} +1 -1
- package/build/client/_app/immutable/assets/7.BsquVIMw.css.br +0 -0
- package/build/client/_app/immutable/assets/7.BsquVIMw.css.gz +0 -0
- package/build/client/_app/immutable/assets/QuestionCard.CSfD3z_X.css +1 -0
- package/build/client/_app/immutable/assets/QuestionCard.CSfD3z_X.css.br +0 -0
- package/build/client/_app/immutable/assets/QuestionCard.CSfD3z_X.css.gz +0 -0
- package/build/client/_app/immutable/chunks/1F1QVf3N.js +1 -0
- package/build/client/_app/immutable/chunks/1F1QVf3N.js.br +0 -0
- package/build/client/_app/immutable/chunks/1F1QVf3N.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{DmFbAjwW.js → 92accNiq.js} +1 -1
- package/build/client/_app/immutable/chunks/92accNiq.js.br +0 -0
- package/build/client/_app/immutable/chunks/92accNiq.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{SXdvPq3_.js → BBXQKGHA.js} +1 -1
- package/build/client/_app/immutable/chunks/BBXQKGHA.js.br +1 -0
- package/build/client/_app/immutable/chunks/BBXQKGHA.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BE_4J5sS.js +3 -0
- package/build/client/_app/immutable/chunks/BE_4J5sS.js.br +0 -0
- package/build/client/_app/immutable/chunks/BE_4J5sS.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{CUa5ff3d.js → BGx9HO1u.js} +1 -1
- package/build/client/_app/immutable/chunks/BGx9HO1u.js.br +0 -0
- package/build/client/_app/immutable/chunks/BGx9HO1u.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BdIq5WIo.js +1 -0
- package/build/client/_app/immutable/chunks/BdIq5WIo.js.br +5 -0
- package/build/client/_app/immutable/chunks/BdIq5WIo.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BDK50g8a.js → ByiipSaR.js} +1 -1
- package/build/client/_app/immutable/chunks/ByiipSaR.js.br +3 -0
- package/build/client/_app/immutable/chunks/ByiipSaR.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{D5FtEngX.js → C4qTU5YY.js} +1 -1
- package/build/client/_app/immutable/chunks/C4qTU5YY.js.br +0 -0
- package/build/client/_app/immutable/chunks/C4qTU5YY.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C6rMFkms.js +14 -0
- package/build/client/_app/immutable/chunks/C6rMFkms.js.br +0 -0
- package/build/client/_app/immutable/chunks/C6rMFkms.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{mG6HnNbi.js → CJc9QEdG.js} +1 -1
- package/build/client/_app/immutable/chunks/CJc9QEdG.js.br +2 -0
- package/build/client/_app/immutable/chunks/CJc9QEdG.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Clt9pCG1.js +1 -0
- package/build/client/_app/immutable/chunks/Clt9pCG1.js.br +0 -0
- package/build/client/_app/immutable/chunks/Clt9pCG1.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CuKFR3Qo.js +3 -0
- package/build/client/_app/immutable/chunks/CuKFR3Qo.js.br +0 -0
- package/build/client/_app/immutable/chunks/CuKFR3Qo.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CzKYnjEX.js +1 -0
- package/build/client/_app/immutable/chunks/CzKYnjEX.js.br +0 -0
- package/build/client/_app/immutable/chunks/CzKYnjEX.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D1VTYdXF.js +1 -0
- package/build/client/_app/immutable/chunks/D1VTYdXF.js.br +0 -0
- package/build/client/_app/immutable/chunks/D1VTYdXF.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D3d8Mm8X.js +1 -0
- package/build/client/_app/immutable/chunks/D3d8Mm8X.js.br +1 -0
- package/build/client/_app/immutable/chunks/D3d8Mm8X.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DF5Aoa59.js +1 -0
- package/build/client/_app/immutable/chunks/DF5Aoa59.js.br +2 -0
- package/build/client/_app/immutable/chunks/DF5Aoa59.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{NR-JVJz-.js → DTAO9S6h.js} +1 -1
- package/build/client/_app/immutable/chunks/DTAO9S6h.js.br +0 -0
- package/build/client/_app/immutable/chunks/DTAO9S6h.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DTLQuSQp.js +3 -0
- package/build/client/_app/immutable/chunks/DTLQuSQp.js.br +0 -0
- package/build/client/_app/immutable/chunks/DTLQuSQp.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DaRQZQEK.js +5 -0
- package/build/client/_app/immutable/chunks/DaRQZQEK.js.br +0 -0
- package/build/client/_app/immutable/chunks/DaRQZQEK.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dz-hw4Sz.js +5 -0
- package/build/client/_app/immutable/chunks/Dz-hw4Sz.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dz-hw4Sz.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{hSjQday7.js → _zkFsY4j.js} +1 -1
- package/build/client/_app/immutable/chunks/_zkFsY4j.js.br +0 -0
- package/build/client/_app/immutable/chunks/_zkFsY4j.js.gz +0 -0
- package/build/client/_app/immutable/chunks/mNzUu332.js +1 -0
- package/build/client/_app/immutable/chunks/mNzUu332.js.br +0 -0
- package/build/client/_app/immutable/chunks/mNzUu332.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.DKG33-gU.js +2 -0
- package/build/client/_app/immutable/entry/app.DKG33-gU.js.br +0 -0
- package/build/client/_app/immutable/entry/app.DKG33-gU.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.vDtUfDrT.js +1 -0
- package/build/client/_app/immutable/entry/start.vDtUfDrT.js.br +1 -0
- package/build/client/_app/immutable/entry/start.vDtUfDrT.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.eA5H3idZ.js +1 -0
- package/build/client/_app/immutable/nodes/0.eA5H3idZ.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.eA5H3idZ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.CvKFymDh.js +1 -0
- package/build/client/_app/immutable/nodes/1.CvKFymDh.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.CvKFymDh.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.DFMf8WUQ.js +1 -0
- package/build/client/_app/immutable/nodes/10.DFMf8WUQ.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.DFMf8WUQ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{11.DViPDhJG.js → 11.BZQW5Y67.js} +6 -6
- package/build/client/_app/immutable/nodes/11.BZQW5Y67.js.br +0 -0
- package/build/client/_app/immutable/nodes/11.BZQW5Y67.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.tmtk1Bjc.js +1 -0
- package/build/client/_app/immutable/nodes/2.tmtk1Bjc.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.tmtk1Bjc.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.BEaeucAu.js +1 -0
- package/build/client/_app/immutable/nodes/3.BEaeucAu.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.BEaeucAu.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.B-36aGPk.js +1 -0
- package/build/client/_app/immutable/nodes/4.B-36aGPk.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.B-36aGPk.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{5.CIMkqYzP.js → 5.bgdUYUlr.js} +2 -2
- package/build/client/_app/immutable/nodes/5.bgdUYUlr.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.bgdUYUlr.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.D0P837Li.js +2 -0
- package/build/client/_app/immutable/nodes/6.D0P837Li.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.D0P837Li.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.C4seSCJq.js +14 -0
- package/build/client/_app/immutable/nodes/7.C4seSCJq.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.C4seSCJq.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.BANf4x1v.js +1 -0
- package/build/client/_app/immutable/nodes/8.BANf4x1v.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.BANf4x1v.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.DCgNAMuD.js +128 -0
- package/build/client/_app/immutable/nodes/9.DCgNAMuD.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.DCgNAMuD.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +1 -1
- package/build/client/_app/version.json.gz +0 -0
- package/build/server/chunks/{0-BtezztJz.js → 0-D9FIO-Bk.js} +6 -6
- package/build/server/chunks/{0-BtezztJz.js.map → 0-D9FIO-Bk.js.map} +1 -1
- package/build/server/chunks/1-ItPJxTHP.js +9 -0
- package/build/server/chunks/{1-CvGA_TOi.js.map → 1-ItPJxTHP.js.map} +1 -1
- package/build/server/chunks/{10-D_ipl62-.js → 10-B4fDiATl.js} +3 -3
- package/build/server/chunks/{10-D_ipl62-.js.map → 10-B4fDiATl.js.map} +1 -1
- package/build/server/chunks/11-CZj9K6K7.js +9 -0
- package/build/server/chunks/{11-Bp7zXIv8.js.map → 11-CZj9K6K7.js.map} +1 -1
- package/build/server/chunks/{2-CQSBaE_w.js → 2-KPMSLSlE.js} +2 -2
- package/build/server/chunks/{2-CQSBaE_w.js.map → 2-KPMSLSlE.js.map} +1 -1
- package/build/server/chunks/{3-CZdWulB3.js → 3-DpC38K23.js} +10 -11
- package/build/server/chunks/3-DpC38K23.js.map +1 -0
- package/build/server/chunks/4-DrJ64j1x.js +9 -0
- package/build/server/chunks/4-DrJ64j1x.js.map +1 -0
- package/build/server/chunks/{5-CeJvfCdk.js → 5-BxzwX0rY.js} +3 -3
- package/build/server/chunks/{5-CeJvfCdk.js.map → 5-BxzwX0rY.js.map} +1 -1
- package/build/server/chunks/6-DxXeT1e3.js +9 -0
- package/build/server/chunks/6-DxXeT1e3.js.map +1 -0
- package/build/server/chunks/7-CuHe_mFY.js +9 -0
- package/build/server/chunks/{7-mi0k2tJn.js.map → 7-CuHe_mFY.js.map} +1 -1
- package/build/server/chunks/{8-DiHmrGkL.js → 8-DFD8sNRI.js} +5 -7
- package/build/server/chunks/8-DFD8sNRI.js.map +1 -0
- package/build/server/chunks/9-CVIPxN5B.js +9 -0
- package/build/server/chunks/9-CVIPxN5B.js.map +1 -0
- package/build/server/chunks/{IconActivity-DrgUhxxi.js → ChatMessage-fWnwEF6b.js} +3 -57
- package/build/server/chunks/ChatMessage-fWnwEF6b.js.map +1 -0
- package/build/server/chunks/{ChatNavbar-FJW5r496.js → ChatNavbar-CJYo_Hbc.js} +8 -8
- package/build/server/chunks/{ChatNavbar-FJW5r496.js.map → ChatNavbar-CJYo_Hbc.js.map} +1 -1
- package/build/server/chunks/IconActivity-BU1QGLAZ.js +58 -0
- package/build/server/chunks/IconActivity-BU1QGLAZ.js.map +1 -0
- package/build/server/chunks/{IconServer-w-1K5jNR.js → IconServer-DkywyVFu.js} +5 -5
- package/build/server/chunks/{IconServer-w-1K5jNR.js.map → IconServer-DkywyVFu.js.map} +1 -1
- package/build/server/chunks/{IconSoundOn-DZGaQz_p.js → IconSoundOn-DoAiK-qp.js} +8 -11
- package/build/server/chunks/IconSoundOn-DoAiK-qp.js.map +1 -0
- package/build/server/chunks/IconStop-DKVpXPKq.js +1648 -0
- package/build/server/chunks/IconStop-DKVpXPKq.js.map +1 -0
- package/build/server/chunks/QuestionCard-BCfoxMiS.js +128 -0
- package/build/server/chunks/QuestionCard-BCfoxMiS.js.map +1 -0
- package/build/server/chunks/{_layout.svelte-B-_IlE2E.js → _layout.svelte-DArOWGd3.js} +3 -3
- package/build/server/chunks/{_layout.svelte-B-_IlE2E.js.map → _layout.svelte-DArOWGd3.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-DM96lwQ1.js → _page.svelte-B2cX_j9w.js} +3 -3
- package/build/server/chunks/{_page.svelte-DM96lwQ1.js.map → _page.svelte-B2cX_j9w.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-CB1qUSpk.js → _page.svelte-BcpGl-vl.js} +12 -16
- package/build/server/chunks/_page.svelte-BcpGl-vl.js.map +1 -0
- package/build/server/chunks/_page.svelte-CGEtuNmS.js +192 -0
- package/build/server/chunks/_page.svelte-CGEtuNmS.js.map +1 -0
- package/build/server/chunks/{_page.svelte-CPZBh4-z.js → _page.svelte-Dpf94Jor.js} +3 -3
- package/build/server/chunks/{_page.svelte-CPZBh4-z.js.map → _page.svelte-Dpf94Jor.js.map} +1 -1
- package/build/server/chunks/{_page.svelte-GcuuPiXq.js → _page.svelte-FOm-OMQe.js} +6 -6
- package/build/server/chunks/_page.svelte-FOm-OMQe.js.map +1 -0
- package/build/server/chunks/{_page.svelte-K6kU7jIW.js → _page.svelte-S90xJHRa.js} +43 -134
- package/build/server/chunks/_page.svelte-S90xJHRa.js.map +1 -0
- package/build/server/chunks/{_page.svelte-CPo3vFZf.js → _page.svelte-qxgG6hsh.js} +10 -9
- package/build/server/chunks/_page.svelte-qxgG6hsh.js.map +1 -0
- package/build/server/chunks/{_server.ts-BCrEvrVb.js → _server.ts--F22byeV.js} +8 -8
- package/build/server/chunks/{_server.ts-BCrEvrVb.js.map → _server.ts--F22byeV.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CT0jVfA6.js → _server.ts-08JCSzPu.js} +10 -10
- package/build/server/chunks/_server.ts-08JCSzPu.js.map +1 -0
- package/build/server/chunks/{_server.ts-s2Seq_VN.js → _server.ts-3bBG0DBN.js} +7 -7
- package/build/server/chunks/{_server.ts-s2Seq_VN.js.map → _server.ts-3bBG0DBN.js.map} +1 -1
- package/build/server/chunks/{_server.ts-ygmDTh5G.js → _server.ts-7pcCO8Pf.js} +8 -8
- package/build/server/chunks/{_server.ts-ygmDTh5G.js.map → _server.ts-7pcCO8Pf.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BJGOO9Nn.js → _server.ts-AC1zqetQ.js} +3 -3
- package/build/server/chunks/{_server.ts-BJGOO9Nn.js.map → _server.ts-AC1zqetQ.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DjIJCqkv.js → _server.ts-B-uAgtQC.js} +7 -7
- package/build/server/chunks/{_server.ts-DjIJCqkv.js.map → _server.ts-B-uAgtQC.js.map} +1 -1
- package/build/server/chunks/{_server.ts-w4ncTcy1.js → _server.ts-B0MK-ynu.js} +9 -9
- package/build/server/chunks/{_server.ts-w4ncTcy1.js.map → _server.ts-B0MK-ynu.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CMOAhXEC.js → _server.ts-B1vQkdVA.js} +9 -9
- package/build/server/chunks/{_server.ts-CMOAhXEC.js.map → _server.ts-B1vQkdVA.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CZMdC1Kd.js → _server.ts-B3iKXyUo.js} +7 -7
- package/build/server/chunks/{_server.ts-CZMdC1Kd.js.map → _server.ts-B3iKXyUo.js.map} +1 -1
- package/build/server/chunks/{_server.ts-D3G8ICxb.js → _server.ts-B7319d6O.js} +7 -7
- package/build/server/chunks/{_server.ts-D3G8ICxb.js.map → _server.ts-B7319d6O.js.map} +1 -1
- package/build/server/chunks/{_server.ts-V-MiUhz4.js → _server.ts-BCpQ8Qdr.js} +7 -7
- package/build/server/chunks/{_server.ts-V-MiUhz4.js.map → _server.ts-BCpQ8Qdr.js.map} +1 -1
- package/build/server/chunks/{_server.ts-6QSsgi7N.js → _server.ts-BF5JzSrs.js} +7 -7
- package/build/server/chunks/{_server.ts-6QSsgi7N.js.map → _server.ts-BF5JzSrs.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Df7bUUvM.js → _server.ts-BGTw6w-C.js} +8 -8
- package/build/server/chunks/{_server.ts-Df7bUUvM.js.map → _server.ts-BGTw6w-C.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CU4SIH7_.js → _server.ts-BH8Y1mmb.js} +5 -5
- package/build/server/chunks/{_server.ts-CU4SIH7_.js.map → _server.ts-BH8Y1mmb.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Dim_lnRX.js → _server.ts-BHaFrgm9.js} +8 -8
- package/build/server/chunks/{_server.ts-Dim_lnRX.js.map → _server.ts-BHaFrgm9.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Bwt_pOeg.js → _server.ts-BKnCIXe5.js} +7 -7
- package/build/server/chunks/{_server.ts-Bwt_pOeg.js.map → _server.ts-BKnCIXe5.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Blmg0cXL.js → _server.ts-BOn4TCRw.js} +8 -8
- package/build/server/chunks/{_server.ts-Blmg0cXL.js.map → _server.ts-BOn4TCRw.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BQZ6mdSh.js → _server.ts-BS4UTF4H.js} +7 -7
- package/build/server/chunks/{_server.ts-BQZ6mdSh.js.map → _server.ts-BS4UTF4H.js.map} +1 -1
- package/build/server/chunks/{_server.ts-ykET4T6s.js → _server.ts-BWMJRzwx.js} +9 -9
- package/build/server/chunks/_server.ts-BWMJRzwx.js.map +1 -0
- package/build/server/chunks/{_server.ts-WZl_x3WY.js → _server.ts-B_7lGoo_.js} +7 -7
- package/build/server/chunks/{_server.ts-WZl_x3WY.js.map → _server.ts-B_7lGoo_.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CtGn47WI.js → _server.ts-BaEUZaLH.js} +5 -5
- package/build/server/chunks/{_server.ts-CtGn47WI.js.map → _server.ts-BaEUZaLH.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BfL_49xD.js → _server.ts-BgL3_hTS.js} +8 -8
- package/build/server/chunks/{_server.ts-BfL_49xD.js.map → _server.ts-BgL3_hTS.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CoVlX74M.js → _server.ts-BgOS_sDK.js} +8 -8
- package/build/server/chunks/{_server.ts-CoVlX74M.js.map → _server.ts-BgOS_sDK.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CFrPK6QO.js → _server.ts-BhA9ywuA.js} +7 -7
- package/build/server/chunks/{_server.ts-CFrPK6QO.js.map → _server.ts-BhA9ywuA.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CzEoO4z1.js → _server.ts-BtZ9-ZYu.js} +3 -3
- package/build/server/chunks/{_server.ts-CzEoO4z1.js.map → _server.ts-BtZ9-ZYu.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CPiybiLB.js → _server.ts-C4tBc7fm.js} +10 -10
- package/build/server/chunks/{_server.ts-CPiybiLB.js.map → _server.ts-C4tBc7fm.js.map} +1 -1
- package/build/server/chunks/{_server.ts-513m4Yqs.js → _server.ts-C5T_Zuoy.js} +8 -8
- package/build/server/chunks/{_server.ts-513m4Yqs.js.map → _server.ts-C5T_Zuoy.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BcqSTHN5.js → _server.ts-CCTZbI7L.js} +8 -8
- package/build/server/chunks/{_server.ts-BcqSTHN5.js.map → _server.ts-CCTZbI7L.js.map} +1 -1
- package/build/server/chunks/{_server.ts-YcvtqJwd.js → _server.ts-CEUFtmpE.js} +8 -8
- package/build/server/chunks/{_server.ts-YcvtqJwd.js.map → _server.ts-CEUFtmpE.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BNOepqUw.js → _server.ts-CFKGqT4L.js} +7 -7
- package/build/server/chunks/{_server.ts-BNOepqUw.js.map → _server.ts-CFKGqT4L.js.map} +1 -1
- package/build/server/chunks/{_server.ts-JhxhiGGc.js → _server.ts-CLMsuxkK.js} +7 -7
- package/build/server/chunks/{_server.ts-JhxhiGGc.js.map → _server.ts-CLMsuxkK.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Dw7F066C.js → _server.ts-CMfz71Do.js} +7 -7
- package/build/server/chunks/{_server.ts-Dw7F066C.js.map → _server.ts-CMfz71Do.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CPNIDSmd.js → _server.ts-CQeqwCqj.js} +7 -7
- package/build/server/chunks/{_server.ts-CPNIDSmd.js.map → _server.ts-CQeqwCqj.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BXPj75Y1.js → _server.ts-CSBd_6yC.js} +8 -8
- package/build/server/chunks/{_server.ts-BXPj75Y1.js.map → _server.ts-CSBd_6yC.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BcO0Zf4D.js → _server.ts-CSYdjKAH.js} +8 -8
- package/build/server/chunks/{_server.ts-BcO0Zf4D.js.map → _server.ts-CSYdjKAH.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DVNN4NHW.js → _server.ts-CY-GNKZT.js} +7 -7
- package/build/server/chunks/{_server.ts-DVNN4NHW.js.map → _server.ts-CY-GNKZT.js.map} +1 -1
- package/build/server/chunks/{_server.ts-iFah_o1y.js → _server.ts-CYu5XSM8.js} +7 -7
- package/build/server/chunks/{_server.ts-iFah_o1y.js.map → _server.ts-CYu5XSM8.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Do0cbyyq.js → _server.ts-CjeMP5Vf.js} +8 -8
- package/build/server/chunks/_server.ts-CjeMP5Vf.js.map +1 -0
- package/build/server/chunks/{_server.ts-CVvUFmDd.js → _server.ts-Cjo35hc1.js} +7 -7
- package/build/server/chunks/{_server.ts-CVvUFmDd.js.map → _server.ts-Cjo35hc1.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DpnNS7XE.js → _server.ts-CkVeEW46.js} +7 -7
- package/build/server/chunks/{_server.ts-DpnNS7XE.js.map → _server.ts-CkVeEW46.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BaVwMXGu.js → _server.ts-Cph8nHvr.js} +7 -7
- package/build/server/chunks/{_server.ts-BaVwMXGu.js.map → _server.ts-Cph8nHvr.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BFRCkpIB.js → _server.ts-CpyfojV9.js} +8 -8
- package/build/server/chunks/{_server.ts-BFRCkpIB.js.map → _server.ts-CpyfojV9.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CqK78x99.js → _server.ts-CtkA_Ld0.js} +8 -8
- package/build/server/chunks/{_server.ts-CqK78x99.js.map → _server.ts-CtkA_Ld0.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DgtgUx0V.js → _server.ts-Cu48eVwM.js} +3 -3
- package/build/server/chunks/{_server.ts-DgtgUx0V.js.map → _server.ts-Cu48eVwM.js.map} +1 -1
- package/build/server/chunks/{_server.ts-C4Pel5kC.js → _server.ts-CvjVUcFR.js} +7 -7
- package/build/server/chunks/{_server.ts-C4Pel5kC.js.map → _server.ts-CvjVUcFR.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Dixj3o5E.js → _server.ts-CxH-7UEc.js} +7 -7
- package/build/server/chunks/{_server.ts-Dixj3o5E.js.map → _server.ts-CxH-7UEc.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Bnzq20kw.js → _server.ts-D0XsGdhx.js} +7 -7
- package/build/server/chunks/{_server.ts-Bnzq20kw.js.map → _server.ts-D0XsGdhx.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DMUseo0C.js → _server.ts-D6-C5ctd.js} +8 -8
- package/build/server/chunks/{_server.ts-DMUseo0C.js.map → _server.ts-D6-C5ctd.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BLXzfOzW.js → _server.ts-DQI9hYcE.js} +7 -7
- package/build/server/chunks/{_server.ts-BLXzfOzW.js.map → _server.ts-DQI9hYcE.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BvtdTKYv.js → _server.ts-DQTJ_bFp.js} +8 -8
- package/build/server/chunks/{_server.ts-BvtdTKYv.js.map → _server.ts-DQTJ_bFp.js.map} +1 -1
- package/build/server/chunks/{_server.ts-B_dmjFtu.js → _server.ts-DR0kmbl9.js} +8 -8
- package/build/server/chunks/_server.ts-DR0kmbl9.js.map +1 -0
- package/build/server/chunks/{_server.ts-Bvb9c_At.js → _server.ts-DR_9WXW4.js} +9 -9
- package/build/server/chunks/{_server.ts-Bvb9c_At.js.map → _server.ts-DR_9WXW4.js.map} +1 -1
- package/build/server/chunks/{_server.ts-HHMqD_RA.js → _server.ts-DXwG4w1_.js} +5 -6
- package/build/server/chunks/_server.ts-DXwG4w1_.js.map +1 -0
- package/build/server/chunks/{_server.ts-Cgdl0C1I.js → _server.ts-DYLc6Os9.js} +7 -7
- package/build/server/chunks/{_server.ts-Cgdl0C1I.js.map → _server.ts-DYLc6Os9.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DbvC6vbj.js → _server.ts-DYg52Wyj.js} +7 -7
- package/build/server/chunks/{_server.ts-DbvC6vbj.js.map → _server.ts-DYg52Wyj.js.map} +1 -1
- package/build/server/chunks/{_server.ts-D3FpBEaY.js → _server.ts-Dc1s3sLN.js} +9 -9
- package/build/server/chunks/_server.ts-Dc1s3sLN.js.map +1 -0
- package/build/server/chunks/{_server.ts-CZ3VVtAj.js → _server.ts-DcpOpD6s.js} +7 -7
- package/build/server/chunks/{_server.ts-CZ3VVtAj.js.map → _server.ts-DcpOpD6s.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BrQJNRtC.js → _server.ts-DeuURP8u.js} +7 -7
- package/build/server/chunks/{_server.ts-BrQJNRtC.js.map → _server.ts-DeuURP8u.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CjfZfEOL.js → _server.ts-DhcBS9KQ.js} +7 -7
- package/build/server/chunks/{_server.ts-CjfZfEOL.js.map → _server.ts-DhcBS9KQ.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CuLEqJd2.js → _server.ts-DlKT-RbM.js} +9 -9
- package/build/server/chunks/{_server.ts-CuLEqJd2.js.map → _server.ts-DlKT-RbM.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DZrKSBmK.js → _server.ts-DuO_GU5A.js} +7 -7
- package/build/server/chunks/{_server.ts-DZrKSBmK.js.map → _server.ts-DuO_GU5A.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CGTCLl7g.js → _server.ts-DvUVX3X0.js} +8 -8
- package/build/server/chunks/{_server.ts-CGTCLl7g.js.map → _server.ts-DvUVX3X0.js.map} +1 -1
- package/build/server/chunks/{_server.ts-BQdhHsGb.js → _server.ts-DvfnkNfI.js} +8 -8
- package/build/server/chunks/{_server.ts-BQdhHsGb.js.map → _server.ts-DvfnkNfI.js.map} +1 -1
- package/build/server/chunks/{_server.ts-MBgNxLF2.js → _server.ts-DzV6EO26.js} +7 -7
- package/build/server/chunks/{_server.ts-MBgNxLF2.js.map → _server.ts-DzV6EO26.js.map} +1 -1
- package/build/server/chunks/{_server.ts-rVmsBymo.js → _server.ts-IEM_8o6U.js} +8 -8
- package/build/server/chunks/{_server.ts-rVmsBymo.js.map → _server.ts-IEM_8o6U.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Cf_ZLxIl.js → _server.ts-N_mH0t0f.js} +12 -13
- package/build/server/chunks/_server.ts-N_mH0t0f.js.map +1 -0
- package/build/server/chunks/{_server.ts-DgoPOMEf.js → _server.ts-Y5pBzFz4.js} +7 -7
- package/build/server/chunks/{_server.ts-DgoPOMEf.js.map → _server.ts-Y5pBzFz4.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Cp8YnPjm.js → _server.ts-ZKEBn-qW.js} +9 -9
- package/build/server/chunks/{_server.ts-Cp8YnPjm.js.map → _server.ts-ZKEBn-qW.js.map} +1 -1
- package/build/server/chunks/{_server.ts-Dy7MOoFx.js → _server.ts-fenM6Iln.js} +8 -8
- package/build/server/chunks/{_server.ts-Dy7MOoFx.js.map → _server.ts-fenM6Iln.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DnonNBWq.js → _server.ts-i9TaUbWr.js} +9 -9
- package/build/server/chunks/{_server.ts-DnonNBWq.js.map → _server.ts-i9TaUbWr.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CsI99fk3.js → _server.ts-iXjPBf7J.js} +8 -8
- package/build/server/chunks/{_server.ts-CsI99fk3.js.map → _server.ts-iXjPBf7J.js.map} +1 -1
- package/build/server/chunks/{_server.ts-D3EHXo-L.js → _server.ts-jqktLs6L.js} +7 -7
- package/build/server/chunks/{_server.ts-D3EHXo-L.js.map → _server.ts-jqktLs6L.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DbWhKo2R.js → _server.ts-oSGbQw4A.js} +7 -7
- package/build/server/chunks/{_server.ts-DbWhKo2R.js.map → _server.ts-oSGbQw4A.js.map} +1 -1
- package/build/server/chunks/{_server.ts-m7rCPG1J.js → _server.ts-pf6WrGLo.js} +8 -8
- package/build/server/chunks/{_server.ts-m7rCPG1J.js.map → _server.ts-pf6WrGLo.js.map} +1 -1
- package/build/server/chunks/{_server.ts-B5wBYGeP.js → _server.ts-v3cF2xWi.js} +7 -7
- package/build/server/chunks/{_server.ts-B5wBYGeP.js.map → _server.ts-v3cF2xWi.js.map} +1 -1
- package/build/server/chunks/{_server.ts-DwGTXfsS.js → _server.ts-vJBq3idp.js} +3 -3
- package/build/server/chunks/{_server.ts-DwGTXfsS.js.map → _server.ts-vJBq3idp.js.map} +1 -1
- package/build/server/chunks/{_server.ts-WLMG4R7D.js → _server.ts-vlaPk3to.js} +7 -7
- package/build/server/chunks/{_server.ts-WLMG4R7D.js.map → _server.ts-vlaPk3to.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CfLVH8TI.js → _server.ts-xQhNjF_X.js} +7 -7
- package/build/server/chunks/{_server.ts-CfLVH8TI.js.map → _server.ts-xQhNjF_X.js.map} +1 -1
- package/build/server/chunks/{_server.ts-D3CUgai-.js → _server.ts-yZ8CGJNE.js} +8 -8
- package/build/server/chunks/{_server.ts-D3CUgai-.js.map → _server.ts-yZ8CGJNE.js.map} +1 -1
- package/build/server/chunks/{_server.ts-B2BUFCOJ.js → _server.ts-z5C3PAAB.js} +3 -3
- package/build/server/chunks/{_server.ts-B2BUFCOJ.js.map → _server.ts-z5C3PAAB.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CvkF5YMt.js → _server.ts-zt3yI2wU.js} +7 -7
- package/build/server/chunks/{_server.ts-CvkF5YMt.js.map → _server.ts-zt3yI2wU.js.map} +1 -1
- package/build/server/chunks/{addon-helpers-tZ_tAgFZ.js → addon-helpers-B7bkHg-K.js} +5 -5
- package/build/server/chunks/{addon-helpers-tZ_tAgFZ.js.map → addon-helpers-B7bkHg-K.js.map} +1 -1
- package/build/server/chunks/{admin-update-lock-ZHLAwYiV.js → admin-update-lock-B-z4UE8R.js} +3 -3
- package/build/server/chunks/{admin-update-lock-ZHLAwYiV.js.map → admin-update-lock-B-z4UE8R.js.map} +1 -1
- package/build/server/chunks/{akm-DU_4Aa4m.js → akm-C4NCZfJB.js} +3 -3
- package/build/server/chunks/{akm-DU_4Aa4m.js.map → akm-C4NCZfJB.js.map} +1 -1
- package/build/server/chunks/{catalog-B4QoA_I8.js → catalog-Czlhb_2V.js} +5 -5
- package/build/server/chunks/{catalog-B4QoA_I8.js.map → catalog-Czlhb_2V.js.map} +1 -1
- package/build/server/chunks/{client-Dn-H0hgG.js → client-HEAniq5u.js} +2 -2
- package/build/server/chunks/{client-Dn-H0hgG.js.map → client-HEAniq5u.js.map} +1 -1
- package/build/server/chunks/{compose-args2-BFOGDQne.js → compose-args2-B1cYvF5r.js} +3 -3
- package/build/server/chunks/compose-args2-B1cYvF5r.js.map +1 -0
- package/build/server/chunks/{config-DoYNsM1_.js → config-C15S-ENd.js} +2 -2
- package/build/server/chunks/{config-DoYNsM1_.js.map → config-C15S-ENd.js.map} +1 -1
- package/build/server/chunks/{constants-1vPYIIwP.js → constants-C8L-P-CF.js} +2 -2
- package/build/server/chunks/{constants-1vPYIIwP.js.map → constants-C8L-P-CF.js.map} +1 -1
- package/build/server/chunks/{docker2-BYFlumV1.js → docker2-CF7qyd1U.js} +3 -3
- package/build/server/chunks/docker2-CF7qyd1U.js.map +1 -0
- package/build/server/chunks/{docker3-CtXDh00O.js → docker3-BsPagEza.js} +2 -2
- package/build/server/chunks/{docker3-CtXDh00O.js.map → docker3-BsPagEza.js.map} +1 -1
- package/build/server/chunks/environment-BYp8JQYM.js.map +1 -1
- package/build/server/chunks/{error.svelte-DWK4R1_M.js → error.svelte-C-lukbaB.js} +4 -4
- package/build/server/chunks/{error.svelte-DWK4R1_M.js.map → error.svelte-C-lukbaB.js.map} +1 -1
- package/build/server/chunks/features-DltizIi4.js +79 -0
- package/build/server/chunks/features-DltizIi4.js.map +1 -0
- package/build/server/chunks/{helpers-DxodR6tq.js → helpers-DWpoPvHz.js} +17 -22
- package/build/server/chunks/helpers-DWpoPvHz.js.map +1 -0
- package/build/server/chunks/{hooks.server-Bzj8OieV.js → hooks.server-BcdEyWVU.js} +12 -12
- package/build/server/chunks/hooks.server-BcdEyWVU.js.map +1 -0
- package/build/server/chunks/{http-CfHMreaI.js → http-7E5W3vGt.js} +3 -3
- package/build/server/chunks/http-7E5W3vGt.js.map +1 -0
- package/build/server/chunks/{internal-BcbUGF7Z.js → internal-BNSUwl-r.js} +8 -4
- package/build/server/chunks/{internal-BcbUGF7Z.js.map → internal-BNSUwl-r.js.map} +1 -1
- package/build/server/chunks/{landing-DhaVkN2f.js → landing-DY53l_CN.js} +10 -12
- package/build/server/chunks/landing-DY53l_CN.js.map +1 -0
- package/build/server/chunks/{network-preset-CJ1RRnki.js → network-preset-BvVAoagy.js} +14 -13
- package/build/server/chunks/network-preset-BvVAoagy.js.map +1 -0
- package/build/server/chunks/opencode-target-DYD2zQ4l.js +203 -0
- package/build/server/chunks/opencode-target-DYD2zQ4l.js.map +1 -0
- package/build/server/chunks/{paths-Bgos728b.js → paths-BVdkvR9U.js} +2 -2
- package/build/server/chunks/{paths-Bgos728b.js.map → paths-BVdkvR9U.js.map} +1 -1
- package/build/server/chunks/{runtime-context.svelte-C5zNEC6u.js → runtime-context.svelte-CRT-b6Ae.js} +8 -11
- package/build/server/chunks/runtime-context.svelte-CRT-b6Ae.js.map +1 -0
- package/build/server/chunks/{session-cookie-C8DcD6bt.js → session-cookie-D2_H1UEW.js} +2 -2
- package/build/server/chunks/{session-cookie-C8DcD6bt.js.map → session-cookie-D2_H1UEW.js.map} +1 -1
- package/build/server/chunks/{setup-deploy-D9j0EGGd.js → setup-deploy-C1h733rH.js} +2 -2
- package/build/server/chunks/{setup-deploy-D9j0EGGd.js.map → setup-deploy-C1h733rH.js.map} +1 -1
- package/build/server/chunks/{src-DbArH65P.js → src-B2-r_9oB.js} +68 -78
- package/build/server/chunks/src-B2-r_9oB.js.map +1 -0
- package/build/server/chunks/{state-Bq8fep3F.js → state-Dkjz2T4C.js} +2 -2
- package/build/server/chunks/{state-Bq8fep3F.js.map → state-Dkjz2T4C.js.map} +1 -1
- package/build/server/chunks/{state2-Cna2OZrd.js → state2-CS9rhust.js} +2 -2
- package/build/server/chunks/{state2-Cna2OZrd.js.map → state2-CS9rhust.js.map} +1 -1
- package/build/server/chunks/{voice-state.svelte-2hAkP5Di.js → voice-state.svelte-CSmyLPRH.js} +25 -3
- package/build/server/chunks/voice-state.svelte-CSmyLPRH.js.map +1 -0
- package/build/server/index.js +1 -1
- package/build/server/manifest.js +94 -122
- package/build/server/manifest.js.map +1 -1
- package/package.json +3 -3
- package/build/client/_app/immutable/assets/4.B2m7mOkq.css +0 -1
- package/build/client/_app/immutable/assets/4.B2m7mOkq.css.br +0 -0
- package/build/client/_app/immutable/assets/4.B2m7mOkq.css.gz +0 -0
- package/build/client/_app/immutable/assets/6.CmRPKjbq.css +0 -1
- package/build/client/_app/immutable/assets/6.CmRPKjbq.css.br +0 -0
- package/build/client/_app/immutable/assets/6.CmRPKjbq.css.gz +0 -0
- package/build/client/_app/immutable/assets/7.BTWb8aLW.css.br +0 -0
- package/build/client/_app/immutable/assets/7.BTWb8aLW.css.gz +0 -0
- package/build/client/_app/immutable/chunks/BDK50g8a.js.br +0 -0
- package/build/client/_app/immutable/chunks/BDK50g8a.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BX_cLEyR.js +0 -1
- package/build/client/_app/immutable/chunks/BX_cLEyR.js.br +0 -0
- package/build/client/_app/immutable/chunks/BX_cLEyR.js.gz +0 -0
- package/build/client/_app/immutable/chunks/ByFgZDEl.js +0 -1
- package/build/client/_app/immutable/chunks/ByFgZDEl.js.br +0 -0
- package/build/client/_app/immutable/chunks/ByFgZDEl.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BzIvC31O.js +0 -3
- package/build/client/_app/immutable/chunks/BzIvC31O.js.br +0 -0
- package/build/client/_app/immutable/chunks/BzIvC31O.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C718MJXm.js +0 -5
- package/build/client/_app/immutable/chunks/C718MJXm.js.br +0 -0
- package/build/client/_app/immutable/chunks/C718MJXm.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CUa5ff3d.js.br +0 -0
- package/build/client/_app/immutable/chunks/CUa5ff3d.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cnz20Kyu.js +0 -3
- package/build/client/_app/immutable/chunks/Cnz20Kyu.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cnz20Kyu.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CoOosFtk.js +0 -3
- package/build/client/_app/immutable/chunks/CoOosFtk.js.br +0 -0
- package/build/client/_app/immutable/chunks/CoOosFtk.js.gz +0 -0
- package/build/client/_app/immutable/chunks/D5FtEngX.js.br +0 -0
- package/build/client/_app/immutable/chunks/D5FtEngX.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DBHgGGCD.js +0 -1
- package/build/client/_app/immutable/chunks/DBHgGGCD.js.br +0 -0
- package/build/client/_app/immutable/chunks/DBHgGGCD.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DBaSfL95.js +0 -1
- package/build/client/_app/immutable/chunks/DBaSfL95.js.br +0 -0
- package/build/client/_app/immutable/chunks/DBaSfL95.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DfZbBavE.js +0 -1
- package/build/client/_app/immutable/chunks/DfZbBavE.js.br +0 -1
- package/build/client/_app/immutable/chunks/DfZbBavE.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DmFbAjwW.js.br +0 -3
- package/build/client/_app/immutable/chunks/DmFbAjwW.js.gz +0 -0
- package/build/client/_app/immutable/chunks/NR-JVJz-.js.br +0 -0
- package/build/client/_app/immutable/chunks/NR-JVJz-.js.gz +0 -0
- package/build/client/_app/immutable/chunks/R6GPcDBF.js +0 -14
- package/build/client/_app/immutable/chunks/R6GPcDBF.js.br +0 -0
- package/build/client/_app/immutable/chunks/R6GPcDBF.js.gz +0 -0
- package/build/client/_app/immutable/chunks/SXdvPq3_.js.br +0 -0
- package/build/client/_app/immutable/chunks/SXdvPq3_.js.gz +0 -0
- package/build/client/_app/immutable/chunks/c0lkYAgh.js +0 -5
- package/build/client/_app/immutable/chunks/c0lkYAgh.js.br +0 -0
- package/build/client/_app/immutable/chunks/c0lkYAgh.js.gz +0 -0
- package/build/client/_app/immutable/chunks/hSjQday7.js.br +0 -0
- package/build/client/_app/immutable/chunks/hSjQday7.js.gz +0 -0
- package/build/client/_app/immutable/chunks/mG6HnNbi.js.br +0 -0
- package/build/client/_app/immutable/chunks/mG6HnNbi.js.gz +0 -0
- package/build/client/_app/immutable/chunks/ra5AJhOl.js +0 -1
- package/build/client/_app/immutable/chunks/ra5AJhOl.js.br +0 -2
- package/build/client/_app/immutable/chunks/ra5AJhOl.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.SHrJgM4c.js +0 -2
- package/build/client/_app/immutable/entry/app.SHrJgM4c.js.br +0 -0
- package/build/client/_app/immutable/entry/app.SHrJgM4c.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.CM0OuHkF.js +0 -1
- package/build/client/_app/immutable/entry/start.CM0OuHkF.js.br +0 -0
- package/build/client/_app/immutable/entry/start.CM0OuHkF.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.mcDF2Cfv.js +0 -1
- package/build/client/_app/immutable/nodes/0.mcDF2Cfv.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.mcDF2Cfv.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.BRotfm1G.js +0 -1
- package/build/client/_app/immutable/nodes/1.BRotfm1G.js.br +0 -2
- package/build/client/_app/immutable/nodes/1.BRotfm1G.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.CtHRQW64.js +0 -1
- package/build/client/_app/immutable/nodes/10.CtHRQW64.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.CtHRQW64.js.gz +0 -0
- package/build/client/_app/immutable/nodes/11.DViPDhJG.js.br +0 -0
- package/build/client/_app/immutable/nodes/11.DViPDhJG.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.C-PzaHZx.js +0 -1
- package/build/client/_app/immutable/nodes/2.C-PzaHZx.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.C-PzaHZx.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.26Z_fr6N.js +0 -1
- package/build/client/_app/immutable/nodes/3.26Z_fr6N.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.26Z_fr6N.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.B1PIKbh6.js +0 -6
- package/build/client/_app/immutable/nodes/4.B1PIKbh6.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.B1PIKbh6.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.CIMkqYzP.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.CIMkqYzP.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.U9QsdKdj.js +0 -2
- package/build/client/_app/immutable/nodes/6.U9QsdKdj.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.U9QsdKdj.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.Dvpg6Lol.js +0 -14
- package/build/client/_app/immutable/nodes/7.Dvpg6Lol.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.Dvpg6Lol.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.NHp_bSVx.js +0 -1
- package/build/client/_app/immutable/nodes/8.NHp_bSVx.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.NHp_bSVx.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.zlIImD-K.js +0 -128
- package/build/client/_app/immutable/nodes/9.zlIImD-K.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.zlIImD-K.js.gz +0 -0
- package/build/server/chunks/1-CvGA_TOi.js +0 -9
- package/build/server/chunks/11-Bp7zXIv8.js +0 -9
- package/build/server/chunks/3-CZdWulB3.js.map +0 -1
- package/build/server/chunks/4-4bobZFC9.js +0 -9
- package/build/server/chunks/4-4bobZFC9.js.map +0 -1
- package/build/server/chunks/6-sGxxEzTB.js +0 -9
- package/build/server/chunks/6-sGxxEzTB.js.map +0 -1
- package/build/server/chunks/7-mi0k2tJn.js +0 -9
- package/build/server/chunks/8-DiHmrGkL.js.map +0 -1
- package/build/server/chunks/9-DB22e_yA.js +0 -9
- package/build/server/chunks/9-DB22e_yA.js.map +0 -1
- package/build/server/chunks/IconActivity-DrgUhxxi.js.map +0 -1
- package/build/server/chunks/IconSoundOn-DZGaQz_p.js.map +0 -1
- package/build/server/chunks/IconStop-BPbovgch.js +0 -956
- package/build/server/chunks/IconStop-BPbovgch.js.map +0 -1
- package/build/server/chunks/_page.svelte-CB1qUSpk.js.map +0 -1
- package/build/server/chunks/_page.svelte-CPo3vFZf.js.map +0 -1
- package/build/server/chunks/_page.svelte-F3gki1Uz.js +0 -155
- package/build/server/chunks/_page.svelte-F3gki1Uz.js.map +0 -1
- package/build/server/chunks/_page.svelte-GcuuPiXq.js.map +0 -1
- package/build/server/chunks/_page.svelte-K6kU7jIW.js.map +0 -1
- package/build/server/chunks/_server.ts-B_dmjFtu.js.map +0 -1
- package/build/server/chunks/_server.ts-BmRwgrKB.js +0 -67
- package/build/server/chunks/_server.ts-BmRwgrKB.js.map +0 -1
- package/build/server/chunks/_server.ts-CT0jVfA6.js.map +0 -1
- package/build/server/chunks/_server.ts-Cf_ZLxIl.js.map +0 -1
- package/build/server/chunks/_server.ts-CixURe5F.js +0 -49
- package/build/server/chunks/_server.ts-CixURe5F.js.map +0 -1
- package/build/server/chunks/_server.ts-CyIO3STA.js +0 -73
- package/build/server/chunks/_server.ts-CyIO3STA.js.map +0 -1
- package/build/server/chunks/_server.ts-CzIZ-UYy.js +0 -113
- package/build/server/chunks/_server.ts-CzIZ-UYy.js.map +0 -1
- package/build/server/chunks/_server.ts-D3FpBEaY.js.map +0 -1
- package/build/server/chunks/_server.ts-Do0cbyyq.js.map +0 -1
- package/build/server/chunks/_server.ts-HHMqD_RA.js.map +0 -1
- package/build/server/chunks/_server.ts-ykET4T6s.js.map +0 -1
- package/build/server/chunks/compose-args2-BFOGDQne.js.map +0 -1
- package/build/server/chunks/connections-api-DlEoE3-k.js +0 -35
- package/build/server/chunks/connections-api-DlEoE3-k.js.map +0 -1
- package/build/server/chunks/docker2-BYFlumV1.js.map +0 -1
- package/build/server/chunks/endpoints-IFTldlrt.js +0 -473
- package/build/server/chunks/endpoints-IFTldlrt.js.map +0 -1
- package/build/server/chunks/features-BW-bVsl8.js +0 -118
- package/build/server/chunks/features-BW-bVsl8.js.map +0 -1
- package/build/server/chunks/helpers-DxodR6tq.js.map +0 -1
- package/build/server/chunks/hooks.server-Bzj8OieV.js.map +0 -1
- package/build/server/chunks/http-CfHMreaI.js.map +0 -1
- package/build/server/chunks/landing-DhaVkN2f.js.map +0 -1
- package/build/server/chunks/network-preset-CJ1RRnki.js.map +0 -1
- package/build/server/chunks/runtime-context.svelte-C5zNEC6u.js.map +0 -1
- package/build/server/chunks/src-DbArH65P.js.map +0 -1
- package/build/server/chunks/voice-state.svelte-2hAkP5Di.js.map +0 -1
- /package/build/client/_app/immutable/assets/{IconActivity.BdXOPwBm.css → ChatMessage.BdXOPwBm.css} +0 -0
- /package/build/client/_app/immutable/assets/{IconActivity.BdXOPwBm.css.br → ChatMessage.BdXOPwBm.css.br} +0 -0
- /package/build/client/_app/immutable/assets/{IconActivity.BdXOPwBm.css.gz → ChatMessage.BdXOPwBm.css.gz} +0 -0
|
@@ -0,0 +1,1648 @@
|
|
|
1
|
+
import { p as derived, d as attr, e as attr_class, a9 as stringify } from './dev-D85DamNs.js';
|
|
2
|
+
import { r as randomId } from './voice-state.svelte-CSmyLPRH.js';
|
|
3
|
+
|
|
4
|
+
//#region src/lib/chat/tool-strip.ts
|
|
5
|
+
function valueToText$1(value) {
|
|
6
|
+
if (typeof value === "string") return value;
|
|
7
|
+
if (value == null) return "";
|
|
8
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
9
|
+
try {
|
|
10
|
+
return JSON.stringify(value);
|
|
11
|
+
} catch {
|
|
12
|
+
return "";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function firstText$1(...values) {
|
|
16
|
+
for (const value of values) {
|
|
17
|
+
const text = valueToText$1(value);
|
|
18
|
+
if (text) return text;
|
|
19
|
+
}
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
function toolStripEntryFromSessionPart(part, fallbackId) {
|
|
23
|
+
if (part.type !== "tool" && !part.state) return null;
|
|
24
|
+
const status = part.state?.status ?? "running";
|
|
25
|
+
return {
|
|
26
|
+
id: part.callID ?? part.id ?? fallbackId,
|
|
27
|
+
kind: "tool",
|
|
28
|
+
tool: part.tool ?? "tool",
|
|
29
|
+
status,
|
|
30
|
+
title: part.state?.title ?? part.tool ?? "tool",
|
|
31
|
+
detail: firstText$1(part.state?.input, part.state?.metadata, part.state?.progress, part.state?.output),
|
|
32
|
+
output: valueToText$1(part.state?.output),
|
|
33
|
+
error: part.state?.error ?? "",
|
|
34
|
+
updatedAt: Date.now()
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function parseStructured(value) {
|
|
38
|
+
const trimmed = value.trim();
|
|
39
|
+
if (!trimmed) return null;
|
|
40
|
+
if (!(trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]"))) return null;
|
|
41
|
+
try {
|
|
42
|
+
return JSON.parse(trimmed);
|
|
43
|
+
} catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function formatDetail(value) {
|
|
48
|
+
const structured = parseStructured(value);
|
|
49
|
+
return structured === null ? value : JSON.stringify(structured, null, 2);
|
|
50
|
+
}
|
|
51
|
+
function prettyLabel(label) {
|
|
52
|
+
if (!label) return "";
|
|
53
|
+
return label.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_-]+/g, " ").replace(/\s+/g, " ").trim().replace(/^./, (char) => char.toUpperCase());
|
|
54
|
+
}
|
|
55
|
+
function toolIconType(tool, status) {
|
|
56
|
+
const name = tool.toLowerCase();
|
|
57
|
+
if (status === "error" || status === "failed") return "alert";
|
|
58
|
+
if (name === "step") return status === "completed" ? "done-circle" : "refresh";
|
|
59
|
+
if (name.includes("remember") || name.includes("memory")) return "edit";
|
|
60
|
+
if (name.includes("help") || name.includes("todo")) return status === "completed" ? "done" : "agent";
|
|
61
|
+
if (name.includes("bash") || name.includes("shell") || name.includes("command")) return "terminal";
|
|
62
|
+
if (name.includes("grep") || name.includes("search")) return "search";
|
|
63
|
+
if (name.includes("read") || name.includes("file")) return "file";
|
|
64
|
+
if (name.includes("edit") || name.includes("write") || name.includes("patch")) return "edit";
|
|
65
|
+
if (name.includes("web") || name.includes("http") || name.includes("fetch")) return "link";
|
|
66
|
+
if (name.includes("task") || name.includes("agent")) return "agent";
|
|
67
|
+
return status === "completed" ? "done" : "clock";
|
|
68
|
+
}
|
|
69
|
+
function timelineTitle(entry) {
|
|
70
|
+
return entry.kind === "step" ? entry.title : entry.title || entry.tool;
|
|
71
|
+
}
|
|
72
|
+
function toolKindLabel(entry) {
|
|
73
|
+
return entry.kind === "step" ? "Step" : "Tool";
|
|
74
|
+
}
|
|
75
|
+
function toolStatusLabel(status) {
|
|
76
|
+
switch (status) {
|
|
77
|
+
case "completed": return "completed";
|
|
78
|
+
case "error":
|
|
79
|
+
case "failed": return "failed";
|
|
80
|
+
case "pending": return "queued";
|
|
81
|
+
default: return "running";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function toolAriaLabel(entry) {
|
|
85
|
+
return `${toolKindLabel(entry)}: ${timelineTitle(entry)} (${toolStatusLabel(entry.status)})`;
|
|
86
|
+
}
|
|
87
|
+
function toolDetailRows(entry) {
|
|
88
|
+
const rows = [
|
|
89
|
+
{
|
|
90
|
+
label: "Type",
|
|
91
|
+
value: toolKindLabel(entry)
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
label: "Name",
|
|
95
|
+
value: timelineTitle(entry)
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
label: "Status",
|
|
99
|
+
value: prettyLabel(toolStatusLabel(entry.status))
|
|
100
|
+
}
|
|
101
|
+
];
|
|
102
|
+
if (entry.kind !== "step") rows.push({
|
|
103
|
+
label: "Tool ID",
|
|
104
|
+
value: entry.tool
|
|
105
|
+
});
|
|
106
|
+
if (entry.detail) rows.push({
|
|
107
|
+
label: entry.kind === "step" ? "Details" : "Input / Details",
|
|
108
|
+
value: formatDetail(entry.detail)
|
|
109
|
+
});
|
|
110
|
+
if (entry.output) rows.push({
|
|
111
|
+
label: "Output",
|
|
112
|
+
value: formatDetail(entry.output)
|
|
113
|
+
});
|
|
114
|
+
if (entry.error) rows.push({
|
|
115
|
+
label: "Error",
|
|
116
|
+
value: formatDetail(entry.error),
|
|
117
|
+
tone: "error"
|
|
118
|
+
});
|
|
119
|
+
return rows;
|
|
120
|
+
}
|
|
121
|
+
/** Patterns that indicate a command is carrying or referencing a secret. */
|
|
122
|
+
var SECRET_SIGNAL = /(token|secret|password|key\s*=|key=)/i;
|
|
123
|
+
/** Cleaned-first-segment prefix → friendly verb phrase. Order matters: more
|
|
124
|
+
* specific prefixes must be checked before their broader siblings. */
|
|
125
|
+
var COMMAND_PHRASES = [
|
|
126
|
+
{
|
|
127
|
+
prefix: "gh auth login",
|
|
128
|
+
phrase: "Signed in to GitHub"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
prefix: "gh auth status",
|
|
132
|
+
phrase: "Checked GitHub sign-in"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
prefix: "gh auth",
|
|
136
|
+
phrase: "Set up GitHub access"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
prefix: "gh repo",
|
|
140
|
+
phrase: "Looked up a GitHub repo"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
prefix: "gh ",
|
|
144
|
+
phrase: "Ran a GitHub command"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
prefix: "git config",
|
|
148
|
+
phrase: "Configured git"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
prefix: "git ",
|
|
152
|
+
phrase: "Ran a git command"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
prefix: "akm add",
|
|
156
|
+
phrase: "Added a knowledge source"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
prefix: "akm remove",
|
|
160
|
+
phrase: "Removed a knowledge source"
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
prefix: "akm ",
|
|
164
|
+
phrase: "Updated knowledge"
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
prefix: "cat ",
|
|
168
|
+
phrase: "Read a file"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
prefix: "ls ",
|
|
172
|
+
phrase: "Listed files"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
prefix: "grep",
|
|
176
|
+
phrase: "Searched files"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
prefix: "rg ",
|
|
180
|
+
phrase: "Searched files"
|
|
181
|
+
}
|
|
182
|
+
];
|
|
183
|
+
/** Strip leading `VAR=value ` env-var/token assignments repeatedly. */
|
|
184
|
+
function stripLeadingAssignments(input) {
|
|
185
|
+
let out = input;
|
|
186
|
+
while (/^[A-Z_][A-Z0-9_]*=\S+\s+/.test(out)) out = out.replace(/^[A-Z_][A-Z0-9_]*=\S+\s+/, "");
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
/** Keep only the first command segment (before chaining/pipe operators). */
|
|
190
|
+
function firstCommandSegment(input) {
|
|
191
|
+
let out = input;
|
|
192
|
+
for (const sep of [
|
|
193
|
+
" && ",
|
|
194
|
+
" || ",
|
|
195
|
+
" | ",
|
|
196
|
+
" ; "
|
|
197
|
+
]) {
|
|
198
|
+
const idx = out.indexOf(sep);
|
|
199
|
+
if (idx >= 0) out = out.slice(0, idx);
|
|
200
|
+
}
|
|
201
|
+
return out.trim();
|
|
202
|
+
}
|
|
203
|
+
/** Match a cleaned command against the friendly phrase table. */
|
|
204
|
+
function phraseForCommand(cleaned) {
|
|
205
|
+
const lower = cleaned.toLowerCase();
|
|
206
|
+
for (const { prefix, phrase } of COMMAND_PHRASES) if (lower.startsWith(prefix)) return phrase;
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Human-readable, de-credentialed summary for a row title. Audience is
|
|
211
|
+
* non-technical home users. Never throws and never returns an empty string.
|
|
212
|
+
* Strips leading env-var/token assignments and refuses to surface raw commands
|
|
213
|
+
* that contain secret material.
|
|
214
|
+
*/
|
|
215
|
+
function displayTitle(entry) {
|
|
216
|
+
try {
|
|
217
|
+
if (entry.kind === "step") return entry.title;
|
|
218
|
+
const raw = (entry.title || entry.tool || "").trim();
|
|
219
|
+
const name = (entry.tool || "").toLowerCase();
|
|
220
|
+
if (raw) {
|
|
221
|
+
const segment = firstCommandSegment(stripLeadingAssignments(raw));
|
|
222
|
+
if (segment) {
|
|
223
|
+
const matched = phraseForCommand(segment);
|
|
224
|
+
if (matched) return matched;
|
|
225
|
+
if (SECRET_SIGNAL.test(segment)) {
|
|
226
|
+
const verb = segment.split(/\s+/)[0] || "";
|
|
227
|
+
return verb ? `Ran a ${verb} command` : "Ran a command";
|
|
228
|
+
}
|
|
229
|
+
if (name.includes("read") || name.includes("file")) return "Read a file";
|
|
230
|
+
if (name.includes("edit") || name.includes("write") || name.includes("patch")) return "Edited a file";
|
|
231
|
+
if (name.includes("grep") || name.includes("search")) return "Searched";
|
|
232
|
+
if (name.includes("task") || name.includes("agent")) return entry.title;
|
|
233
|
+
return segment.replace(/^./, (char) => char.toUpperCase());
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (name.includes("read") || name.includes("file")) return "Read a file";
|
|
237
|
+
if (name.includes("edit") || name.includes("write") || name.includes("patch")) return "Edited a file";
|
|
238
|
+
if (name.includes("grep") || name.includes("search")) return "Searched";
|
|
239
|
+
if (name.includes("task") || name.includes("agent")) return entry.title || entry.tool || "Worked";
|
|
240
|
+
return raw || entry.tool || "Worked";
|
|
241
|
+
} catch {
|
|
242
|
+
return entry.title || entry.tool || "Worked";
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Relative time label: "just now" (<45s), "Nm ago" (<60m), "Nh ago" (<24h),
|
|
247
|
+
* "Nd ago" otherwise. Returns "" for falsy/zero timestamps and "just now" for
|
|
248
|
+
* future timestamps.
|
|
249
|
+
*/
|
|
250
|
+
function relativeTimeLabel(updatedAt, now = Date.now()) {
|
|
251
|
+
if (!updatedAt) return "";
|
|
252
|
+
const diff = now - updatedAt;
|
|
253
|
+
if (diff < 0) return "just now";
|
|
254
|
+
const seconds = Math.floor(diff / 1e3);
|
|
255
|
+
if (seconds < 45) return "just now";
|
|
256
|
+
const minutes = Math.floor(seconds / 60);
|
|
257
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
258
|
+
const hours = Math.floor(minutes / 60);
|
|
259
|
+
if (hours < 24) return `${hours}h ago`;
|
|
260
|
+
return `${Math.floor(hours / 24)}d ago`;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Whether a tool entry should appear in the user-facing activity log. Filters
|
|
264
|
+
* out internal todo-writer bookkeeping but never hides a failure.
|
|
265
|
+
*/
|
|
266
|
+
function isUserFacingTool(entry) {
|
|
267
|
+
const status = entry.status;
|
|
268
|
+
if (status === "error" || status === "failed") return true;
|
|
269
|
+
const name = (entry.tool || "").toLowerCase();
|
|
270
|
+
if (name === "todowrite" || name === "todoread") return false;
|
|
271
|
+
const label = entry.title || entry.tool || "";
|
|
272
|
+
if (/^\d+\s+todos?$/i.test(label)) return false;
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
//#endregion
|
|
276
|
+
//#region src/lib/chat/session-messages.ts
|
|
277
|
+
/**
|
|
278
|
+
* Flatten raw OpenCode session-message rows into UI `ChatEntry`s.
|
|
279
|
+
*
|
|
280
|
+
* Tool parts are grouped into the assistant turn that follows them (attached
|
|
281
|
+
* as `toolStates` on the `ChatMessage`). If tool parts appear with no
|
|
282
|
+
* following assistant text in the same OpenCode message they are emitted as a
|
|
283
|
+
* single `ChatToolGroup` entry — never as N separate entries.
|
|
284
|
+
*
|
|
285
|
+
* Skips non-text, non-tool parts (files, reasoning, etc.). Empty-text
|
|
286
|
+
* messages with no tool activity are dropped.
|
|
287
|
+
*
|
|
288
|
+
* Pure domain transformation (no transport) — kept next to `tool-strip.ts` so
|
|
289
|
+
* the chat api client can call it and it can be unit-tested in isolation.
|
|
290
|
+
*/
|
|
291
|
+
function flattenSessionMessages(rows) {
|
|
292
|
+
const messages = [];
|
|
293
|
+
for (const row of rows) {
|
|
294
|
+
const timestamp = row.info.time?.created ?? Date.now();
|
|
295
|
+
let textBuffer = "";
|
|
296
|
+
let textIndex = 0;
|
|
297
|
+
const pendingToolStates = [];
|
|
298
|
+
const flushText = () => {
|
|
299
|
+
const text = textBuffer.trim();
|
|
300
|
+
textBuffer = "";
|
|
301
|
+
if (!text && pendingToolStates.length === 0) return;
|
|
302
|
+
if (text) {
|
|
303
|
+
const entry = {
|
|
304
|
+
id: textIndex === 0 ? row.info.id : `${row.info.id}:text:${textIndex}`,
|
|
305
|
+
role: row.info.role,
|
|
306
|
+
text,
|
|
307
|
+
timestamp
|
|
308
|
+
};
|
|
309
|
+
if (pendingToolStates.length > 0) {
|
|
310
|
+
entry.toolStates = [...pendingToolStates];
|
|
311
|
+
pendingToolStates.length = 0;
|
|
312
|
+
}
|
|
313
|
+
messages.push(entry);
|
|
314
|
+
textIndex += 1;
|
|
315
|
+
} else if (pendingToolStates.length > 0) {
|
|
316
|
+
const group = {
|
|
317
|
+
id: `${row.info.id}:tools:${textIndex}`,
|
|
318
|
+
type: "tool-group",
|
|
319
|
+
toolStates: [...pendingToolStates],
|
|
320
|
+
timestamp
|
|
321
|
+
};
|
|
322
|
+
pendingToolStates.length = 0;
|
|
323
|
+
messages.push(group);
|
|
324
|
+
textIndex += 1;
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
row.parts.forEach((part, index) => {
|
|
328
|
+
if (part.type === "text" && part.text) {
|
|
329
|
+
textBuffer += part.text;
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (part.type === "tool" || part.state) {
|
|
333
|
+
const toolState = toolStripEntryFromSessionPart(part, `${row.info.id}:${index}`);
|
|
334
|
+
if (!toolState) return;
|
|
335
|
+
pendingToolStates.push(toolState);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
flushText();
|
|
339
|
+
}
|
|
340
|
+
return messages;
|
|
341
|
+
}
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/lib/connections/url-policy.ts
|
|
344
|
+
/**
|
|
345
|
+
* Browser-owned connection URL policy (Phase 3a — "One UI, delete the split").
|
|
346
|
+
*
|
|
347
|
+
* A leaf module with zero imports so both the direct transport
|
|
348
|
+
* (`probeHealth()` short-circuit) and the connections form can consult it
|
|
349
|
+
* without pulling in the IndexedDB store module. There is no guardian
|
|
350
|
+
* `/oc`-appending helper — Guardian is a transparent OpenCode proxy now, so
|
|
351
|
+
* the user provides the exact baseUrl and no path inference is performed.
|
|
352
|
+
*
|
|
353
|
+
* The ONLY refusal trigger: a plain-http, non-loopback connection URL is
|
|
354
|
+
* refused iff the app itself runs on an https: origin. This is exactly the
|
|
355
|
+
* platform mixed-content rule (an https origin cannot `fetch()` a plain-http
|
|
356
|
+
* cross-origin target — the request would never leave the browser), not a
|
|
357
|
+
* broader "https or non-loopback origin" check. Preserves:
|
|
358
|
+
* - loopback TARGETS from any origin (mixed-content loopback exemption —
|
|
359
|
+
* `http://127.0.0.1`/`localhost`/`::1` are "potentially trustworthy"),
|
|
360
|
+
* - plain-http LAN targets from a loopback-origin client (the zero-TLS
|
|
361
|
+
* desktop default — a `http://127.0.0.1` origin is a secure context),
|
|
362
|
+
* - plain-http LAN targets from a non-loopback http ORIGIN (the LAN-served
|
|
363
|
+
* tier: `rewriteLoopbackUrlForBrowserHost` in `./store.ts`).
|
|
364
|
+
*/
|
|
365
|
+
/** Canonical deep link to the TLS integration guide. Pinned by a test that
|
|
366
|
+
* the path segment names a real file, so a docs rename breaks CI instead of
|
|
367
|
+
* shipping a dead link. */
|
|
368
|
+
var TLS_GUIDE_URL = "https://github.com/itlackey/openpalm/blob/main/docs/remote-access-tls.md";
|
|
369
|
+
function isLoopbackHost(hostname) {
|
|
370
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
|
|
371
|
+
}
|
|
372
|
+
/** Remove legacy URL-embedded credentials before a URL reaches UI or storage. */
|
|
373
|
+
function redactUrlUserinfo(rawUrl) {
|
|
374
|
+
try {
|
|
375
|
+
const url = new URL(rawUrl);
|
|
376
|
+
url.username = "";
|
|
377
|
+
url.password = "";
|
|
378
|
+
return url.toString().replace(/\/$/, url.pathname === "/" && !rawUrl.endsWith("/") ? "" : "/");
|
|
379
|
+
} catch {
|
|
380
|
+
return rawUrl;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Refuse a plain-http non-loopback connection URL iff the app's own origin is
|
|
385
|
+
* https: (mixed content — the request could never succeed, so refuse up front
|
|
386
|
+
* with guidance instead of a generic fetch failure).
|
|
387
|
+
*
|
|
388
|
+
* `origin` defaults to `globalThis.location`; a null/undefined origin
|
|
389
|
+
* (non-browser context — tests, SSR) always allows, since there is no browser
|
|
390
|
+
* mixed-content policy to enforce there.
|
|
391
|
+
*/
|
|
392
|
+
function validateConnectionUrl(rawUrl, origin = globalThis.location ?? null) {
|
|
393
|
+
let url;
|
|
394
|
+
try {
|
|
395
|
+
url = new URL(rawUrl);
|
|
396
|
+
} catch {
|
|
397
|
+
return {
|
|
398
|
+
ok: false,
|
|
399
|
+
reason: "invalid-url",
|
|
400
|
+
message: "Enter a valid URL."
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") return {
|
|
404
|
+
ok: false,
|
|
405
|
+
reason: "invalid-url",
|
|
406
|
+
message: "The URL must use http:// or https://."
|
|
407
|
+
};
|
|
408
|
+
if (url.username || url.password) return {
|
|
409
|
+
ok: false,
|
|
410
|
+
reason: "userinfo-not-allowed",
|
|
411
|
+
message: "Do not put credentials in the URL. Use the Authentication fields instead."
|
|
412
|
+
};
|
|
413
|
+
if (url.protocol === "https:") return { ok: true };
|
|
414
|
+
if (isLoopbackHost(url.hostname)) return { ok: true };
|
|
415
|
+
if (origin?.protocol !== "https:") return { ok: true };
|
|
416
|
+
return {
|
|
417
|
+
ok: false,
|
|
418
|
+
reason: "insecure-remote",
|
|
419
|
+
message: "This app runs on a secure (https) origin, so browsers block plain-HTTP connections to remote servers. Use an https:// URL — see the TLS setup guide.",
|
|
420
|
+
guideUrl: TLS_GUIDE_URL
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/lib/connections/store.ts
|
|
425
|
+
/**
|
|
426
|
+
* Browser-owned connection store (Phase 3a — "One UI, delete the split").
|
|
427
|
+
*
|
|
428
|
+
* Connection records persist behind a storage abstraction so the same store
|
|
429
|
+
* logic runs over IndexedDB in the browser (offline-readable) and over an
|
|
430
|
+
* in-memory backend in tests. The store API is async throughout (IndexedDB is
|
|
431
|
+
* async) and keeps NO state in store-instance fields — a page reload
|
|
432
|
+
* constructs a new store over the same backend and must see identical state.
|
|
433
|
+
*
|
|
434
|
+
* Locked/default entries are seeded from a runtime-config.json fetched from
|
|
435
|
+
* the app's own origin at boot. Absent file = no default connection.
|
|
436
|
+
*
|
|
437
|
+
* The Connection shape is `{ id, label, baseUrl, auth }` with auth narrowed to
|
|
438
|
+
* none | basic (Guardian is a transparent OpenCode proxy — Basic is the only
|
|
439
|
+
* connection credential model).
|
|
440
|
+
*/
|
|
441
|
+
function rewriteLoopbackUrlForBrowserHost(rawUrl) {
|
|
442
|
+
const locationLike = globalThis.location;
|
|
443
|
+
const redactedUrl = redactUrlUserinfo(rawUrl);
|
|
444
|
+
if (!locationLike || isLoopbackHost(locationLike.hostname)) return redactedUrl;
|
|
445
|
+
try {
|
|
446
|
+
const url = new URL(redactedUrl);
|
|
447
|
+
if (!isLoopbackHost(url.hostname)) return redactedUrl;
|
|
448
|
+
url.hostname = locationLike.hostname;
|
|
449
|
+
return url.toString();
|
|
450
|
+
} catch {
|
|
451
|
+
return redactedUrl;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
function redactEntryUrl(entry) {
|
|
455
|
+
const baseUrl = redactUrlUserinfo(entry.baseUrl);
|
|
456
|
+
return baseUrl === entry.baseUrl ? entry : {
|
|
457
|
+
...entry,
|
|
458
|
+
baseUrl
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
function assertUrlHasNoUserinfo(rawUrl) {
|
|
462
|
+
let url;
|
|
463
|
+
try {
|
|
464
|
+
url = new URL(rawUrl);
|
|
465
|
+
} catch {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (url.username || url.password) throw new Error("Credentials must use the Authentication fields, not the connection URL.");
|
|
469
|
+
}
|
|
470
|
+
function adaptRuntimeConfigForBrowser(config) {
|
|
471
|
+
return { connections: config.connections.map((entry) => ({
|
|
472
|
+
...redactEntryUrl(entry),
|
|
473
|
+
baseUrl: entry.locked ? rewriteLoopbackUrlForBrowserHost(entry.baseUrl) : redactUrlUserinfo(entry.baseUrl)
|
|
474
|
+
})) };
|
|
475
|
+
}
|
|
476
|
+
var ACTIVE_ID_KEY = "activeId";
|
|
477
|
+
function clone(value) {
|
|
478
|
+
return structuredClone(value);
|
|
479
|
+
}
|
|
480
|
+
/** In-memory storage backend — same semantics as the IndexedDB one. */
|
|
481
|
+
function createMemoryStorage() {
|
|
482
|
+
const entries = /* @__PURE__ */ new Map();
|
|
483
|
+
const meta = /* @__PURE__ */ new Map();
|
|
484
|
+
let cryptoKey = null;
|
|
485
|
+
return {
|
|
486
|
+
async getAll() {
|
|
487
|
+
return [...entries.values()].map(clone);
|
|
488
|
+
},
|
|
489
|
+
async get(id) {
|
|
490
|
+
const entry = entries.get(id);
|
|
491
|
+
return entry ? clone(entry) : null;
|
|
492
|
+
},
|
|
493
|
+
async put(entry) {
|
|
494
|
+
entries.set(entry.id, clone(redactEntryUrl(entry)));
|
|
495
|
+
},
|
|
496
|
+
async delete(id) {
|
|
497
|
+
entries.delete(id);
|
|
498
|
+
},
|
|
499
|
+
async getMeta(key) {
|
|
500
|
+
return meta.get(key) ?? null;
|
|
501
|
+
},
|
|
502
|
+
async setMeta(key, value) {
|
|
503
|
+
if (value === null) meta.delete(key);
|
|
504
|
+
else meta.set(key, value);
|
|
505
|
+
},
|
|
506
|
+
async getCryptoKey() {
|
|
507
|
+
return cryptoKey;
|
|
508
|
+
},
|
|
509
|
+
async setCryptoKey(key) {
|
|
510
|
+
cryptoKey = key;
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
var IDB_NAME = "openpalm-ui-connections";
|
|
515
|
+
var IDB_VERSION = 1;
|
|
516
|
+
var STORE_CONNECTIONS = "connections";
|
|
517
|
+
var STORE_META = "meta";
|
|
518
|
+
var STORE_KEYS = "keys";
|
|
519
|
+
var CRYPTO_KEY_ID = "secret-store-aes-gcm-key";
|
|
520
|
+
function idbRequest(request) {
|
|
521
|
+
return new Promise((resolve, reject) => {
|
|
522
|
+
request.onsuccess = () => resolve(request.result);
|
|
523
|
+
request.onerror = () => reject(request.error ?? /* @__PURE__ */ new Error("IndexedDB request failed"));
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* F11 hardening: an IDB version bump with no `onblocked` handler and no
|
|
528
|
+
* `versionchange` listener can leave a boot hung forever with no error
|
|
529
|
+
* surfaced anywhere. `onblocked` rejects the open promise; `onVersionChange`
|
|
530
|
+
* is invoked once a successfully-opened connection later receives its OWN
|
|
531
|
+
* `versionchange` event (some other tab needs an upgrade): the connection
|
|
532
|
+
* closes itself immediately so it can't go on to block that upgrade in turn,
|
|
533
|
+
* and the caller uses the callback to drop its cached db promise so the NEXT
|
|
534
|
+
* storage operation reopens fresh.
|
|
535
|
+
*/
|
|
536
|
+
function openDatabase(onVersionChange) {
|
|
537
|
+
return new Promise((resolve, reject) => {
|
|
538
|
+
const request = indexedDB.open(IDB_NAME, IDB_VERSION);
|
|
539
|
+
request.onupgradeneeded = () => {
|
|
540
|
+
const db = request.result;
|
|
541
|
+
if (!db.objectStoreNames.contains(STORE_CONNECTIONS)) db.createObjectStore(STORE_CONNECTIONS, { keyPath: "id" });
|
|
542
|
+
if (!db.objectStoreNames.contains(STORE_META)) db.createObjectStore(STORE_META);
|
|
543
|
+
if (!db.objectStoreNames.contains(STORE_KEYS)) db.createObjectStore(STORE_KEYS);
|
|
544
|
+
};
|
|
545
|
+
request.onsuccess = () => {
|
|
546
|
+
const db = request.result;
|
|
547
|
+
db.onversionchange = () => {
|
|
548
|
+
db.close();
|
|
549
|
+
onVersionChange();
|
|
550
|
+
};
|
|
551
|
+
resolve(db);
|
|
552
|
+
};
|
|
553
|
+
request.onerror = () => reject(request.error ?? /* @__PURE__ */ new Error("IndexedDB open failed"));
|
|
554
|
+
request.onblocked = () => reject(/* @__PURE__ */ new Error("IndexedDB upgrade blocked by another open connection (close other tabs of this app and retry)"));
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* IndexedDB storage backend (raw IDB API, no deps). Lazily opens the database
|
|
559
|
+
* on first use; each operation runs in its own short transaction.
|
|
560
|
+
*/
|
|
561
|
+
function createIndexedDbStorage() {
|
|
562
|
+
let db = null;
|
|
563
|
+
const invalidate = () => {
|
|
564
|
+
db = null;
|
|
565
|
+
};
|
|
566
|
+
const database = () => {
|
|
567
|
+
db ??= openDatabase(invalidate);
|
|
568
|
+
return db;
|
|
569
|
+
};
|
|
570
|
+
const store = async (name, mode) => (await database()).transaction(name, mode).objectStore(name);
|
|
571
|
+
return {
|
|
572
|
+
async getAll() {
|
|
573
|
+
return idbRequest((await store(STORE_CONNECTIONS, "readonly")).getAll());
|
|
574
|
+
},
|
|
575
|
+
async get(id) {
|
|
576
|
+
return await idbRequest((await store(STORE_CONNECTIONS, "readonly")).get(id)) ?? null;
|
|
577
|
+
},
|
|
578
|
+
async put(entry) {
|
|
579
|
+
await idbRequest((await store(STORE_CONNECTIONS, "readwrite")).put(redactEntryUrl(entry)));
|
|
580
|
+
},
|
|
581
|
+
async delete(id) {
|
|
582
|
+
await idbRequest((await store(STORE_CONNECTIONS, "readwrite")).delete(id));
|
|
583
|
+
},
|
|
584
|
+
async getMeta(key) {
|
|
585
|
+
return await idbRequest((await store(STORE_META, "readonly")).get(key)) ?? null;
|
|
586
|
+
},
|
|
587
|
+
async setMeta(key, value) {
|
|
588
|
+
const metaStore = await store(STORE_META, "readwrite");
|
|
589
|
+
if (value === null) await idbRequest(metaStore.delete(key));
|
|
590
|
+
else await idbRequest(metaStore.put(value, key));
|
|
591
|
+
},
|
|
592
|
+
async getCryptoKey() {
|
|
593
|
+
return await idbRequest((await store(STORE_KEYS, "readonly")).get(CRYPTO_KEY_ID)) ?? null;
|
|
594
|
+
},
|
|
595
|
+
async setCryptoKey(key) {
|
|
596
|
+
await idbRequest((await store(STORE_KEYS, "readwrite")).put(key, CRYPTO_KEY_ID));
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
function createConnectionStore(options) {
|
|
601
|
+
const { storage } = options;
|
|
602
|
+
async function readEntry(id) {
|
|
603
|
+
const stored = await storage.get(id);
|
|
604
|
+
if (!stored) return null;
|
|
605
|
+
const entry = redactEntryUrl(stored);
|
|
606
|
+
if (entry.baseUrl !== stored.baseUrl) await storage.put(entry);
|
|
607
|
+
return entry;
|
|
608
|
+
}
|
|
609
|
+
async function requireEntry(id) {
|
|
610
|
+
const entry = await readEntry(id);
|
|
611
|
+
if (!entry) throw new Error(`Unknown connection: ${id}`);
|
|
612
|
+
return entry;
|
|
613
|
+
}
|
|
614
|
+
return {
|
|
615
|
+
async list() {
|
|
616
|
+
const stored = await storage.getAll();
|
|
617
|
+
const entries = stored.map(redactEntryUrl);
|
|
618
|
+
await Promise.all(entries.map((entry, index) => entry.baseUrl === stored[index]?.baseUrl ? Promise.resolve() : storage.put(entry)));
|
|
619
|
+
return entries;
|
|
620
|
+
},
|
|
621
|
+
get(id) {
|
|
622
|
+
return readEntry(id);
|
|
623
|
+
},
|
|
624
|
+
async add(input) {
|
|
625
|
+
assertUrlHasNoUserinfo(input.baseUrl);
|
|
626
|
+
const id = input.id ?? randomId();
|
|
627
|
+
if (await readEntry(id)) throw new Error(`Connection already exists: ${id}`);
|
|
628
|
+
const entry = {
|
|
629
|
+
...input,
|
|
630
|
+
id
|
|
631
|
+
};
|
|
632
|
+
await storage.put(entry);
|
|
633
|
+
return clone(entry);
|
|
634
|
+
},
|
|
635
|
+
async update(id, patch) {
|
|
636
|
+
if (patch.baseUrl !== void 0) assertUrlHasNoUserinfo(patch.baseUrl);
|
|
637
|
+
const entry = await requireEntry(id);
|
|
638
|
+
if (entry.locked) throw new Error(`Connection is locked (config-owned): ${id}`);
|
|
639
|
+
const updated = {
|
|
640
|
+
...entry,
|
|
641
|
+
...patch,
|
|
642
|
+
id
|
|
643
|
+
};
|
|
644
|
+
await storage.put(updated);
|
|
645
|
+
return clone(updated);
|
|
646
|
+
},
|
|
647
|
+
async remove(id) {
|
|
648
|
+
if ((await requireEntry(id)).locked) throw new Error(`Connection is locked (config-owned): ${id}`);
|
|
649
|
+
await storage.delete(id);
|
|
650
|
+
if (await storage.getMeta(ACTIVE_ID_KEY) === id) await storage.setMeta(ACTIVE_ID_KEY, null);
|
|
651
|
+
},
|
|
652
|
+
async setSecretRef(id, auth) {
|
|
653
|
+
const updated = {
|
|
654
|
+
...await requireEntry(id),
|
|
655
|
+
auth,
|
|
656
|
+
id
|
|
657
|
+
};
|
|
658
|
+
await storage.put(updated);
|
|
659
|
+
return clone(updated);
|
|
660
|
+
},
|
|
661
|
+
getActiveId() {
|
|
662
|
+
return storage.getMeta(ACTIVE_ID_KEY);
|
|
663
|
+
},
|
|
664
|
+
async getActive() {
|
|
665
|
+
const id = await storage.getMeta(ACTIVE_ID_KEY);
|
|
666
|
+
return id === null ? null : readEntry(id);
|
|
667
|
+
},
|
|
668
|
+
async setActive(id) {
|
|
669
|
+
await requireEntry(id);
|
|
670
|
+
await storage.setMeta(ACTIVE_ID_KEY, id);
|
|
671
|
+
},
|
|
672
|
+
async clearActive() {
|
|
673
|
+
await storage.setMeta(ACTIVE_ID_KEY, null);
|
|
674
|
+
},
|
|
675
|
+
async seedFromRuntimeConfig(config) {
|
|
676
|
+
if (!config) return;
|
|
677
|
+
const activeId = await storage.getMeta(ACTIVE_ID_KEY);
|
|
678
|
+
const configIds = new Set(config.connections.map((entry) => entry.id));
|
|
679
|
+
for (const existing of await storage.getAll()) {
|
|
680
|
+
if (!existing.locked || configIds.has(existing.id)) continue;
|
|
681
|
+
await storage.delete(existing.id);
|
|
682
|
+
if (activeId === existing.id) await storage.setMeta(ACTIVE_ID_KEY, null);
|
|
683
|
+
}
|
|
684
|
+
for (const entry of config.connections) {
|
|
685
|
+
const seededEntry = redactEntryUrl(entry);
|
|
686
|
+
const existing = await readEntry(entry.id);
|
|
687
|
+
if (!existing) await storage.put(clone(seededEntry));
|
|
688
|
+
else if (existing.locked) {
|
|
689
|
+
const seeded = clone(seededEntry);
|
|
690
|
+
const preserveAuth = existing.auth && existing.auth.mode !== "none";
|
|
691
|
+
await storage.put(preserveAuth ? {
|
|
692
|
+
...seeded,
|
|
693
|
+
auth: existing.auth
|
|
694
|
+
} : seeded);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
if (await storage.getMeta(ACTIVE_ID_KEY) !== null) return;
|
|
698
|
+
const fallback = config.connections.find((entry) => entry.isDefault);
|
|
699
|
+
if (fallback && await storage.get(fallback.id)) await storage.setMeta(ACTIVE_ID_KEY, fallback.id);
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Fetch '/runtime-config.json' from the app's OWN origin (relative URL — the
|
|
705
|
+
* static server ships the file beside the build; the app holds no other
|
|
706
|
+
* trusted origin at boot). Absent (404), unreachable (offline), or malformed
|
|
707
|
+
* -> null; never throws, so an offline PWA boot still reaches the stored
|
|
708
|
+
* connection list.
|
|
709
|
+
*/
|
|
710
|
+
async function loadRuntimeConfig(fetchImpl = globalThis.fetch) {
|
|
711
|
+
try {
|
|
712
|
+
const response = await fetchImpl("/runtime-config.json", {
|
|
713
|
+
method: "GET",
|
|
714
|
+
headers: { accept: "application/json" },
|
|
715
|
+
credentials: "omit"
|
|
716
|
+
});
|
|
717
|
+
if (!response.ok) return null;
|
|
718
|
+
const parsed = await response.json();
|
|
719
|
+
if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.connections)) return null;
|
|
720
|
+
return adaptRuntimeConfigForBrowser(parsed);
|
|
721
|
+
} catch {
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
//#endregion
|
|
726
|
+
//#region src/lib/connections/secrets.ts
|
|
727
|
+
var META_PREFIX = "secret:";
|
|
728
|
+
var ENCRYPTED_MARKER = 2;
|
|
729
|
+
var AES_GCM_LENGTH = 256;
|
|
730
|
+
var IV_BYTES = 12;
|
|
731
|
+
/**
|
|
732
|
+
* WebCrypto's `SubtleCrypto` is secure-context-only: on a plain-http LAN origin
|
|
733
|
+
* (the LAN-served tier) `crypto.subtle` is undefined, so encryption is simply
|
|
734
|
+
* not available there. Callers degrade to the legacy plaintext record shape —
|
|
735
|
+
* which `readMaterial` already reads — rather than throwing and blocking the
|
|
736
|
+
* user from saving a credential at all.
|
|
737
|
+
*/
|
|
738
|
+
function subtleAvailable() {
|
|
739
|
+
return typeof crypto !== "undefined" && !!crypto.subtle;
|
|
740
|
+
}
|
|
741
|
+
function isEncryptedRecord(value) {
|
|
742
|
+
return !!value && typeof value === "object" && value.v === ENCRYPTED_MARKER && typeof value.iv === "string" && typeof value.ciphertext === "string";
|
|
743
|
+
}
|
|
744
|
+
function bytesToBase64(bytes) {
|
|
745
|
+
let binary = "";
|
|
746
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
747
|
+
return btoa(binary);
|
|
748
|
+
}
|
|
749
|
+
function base64ToBytes(b64) {
|
|
750
|
+
const binary = atob(b64);
|
|
751
|
+
const bytes = new Uint8Array(binary.length);
|
|
752
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
753
|
+
return bytes;
|
|
754
|
+
}
|
|
755
|
+
var pendingKeys = /* @__PURE__ */ new WeakMap();
|
|
756
|
+
/** Generate-once, reuse-forever non-extractable AES-GCM key for this storage backend. */
|
|
757
|
+
async function getOrCreateKey(storage) {
|
|
758
|
+
const existing = await storage.getCryptoKey();
|
|
759
|
+
if (existing) return existing;
|
|
760
|
+
let pending = pendingKeys.get(storage);
|
|
761
|
+
if (!pending) {
|
|
762
|
+
pending = (async () => {
|
|
763
|
+
const key = await crypto.subtle.generateKey({
|
|
764
|
+
name: "AES-GCM",
|
|
765
|
+
length: AES_GCM_LENGTH
|
|
766
|
+
}, false, ["encrypt", "decrypt"]);
|
|
767
|
+
await storage.setCryptoKey(key);
|
|
768
|
+
return key;
|
|
769
|
+
})();
|
|
770
|
+
pendingKeys.set(storage, pending);
|
|
771
|
+
pending.catch(() => {
|
|
772
|
+
pendingKeys.delete(storage);
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
return pending;
|
|
776
|
+
}
|
|
777
|
+
async function encryptMaterial(key, material) {
|
|
778
|
+
const iv = crypto.getRandomValues(new Uint8Array(IV_BYTES));
|
|
779
|
+
const plaintext = new TextEncoder().encode(JSON.stringify(material));
|
|
780
|
+
const ciphertext = new Uint8Array(await crypto.subtle.encrypt({
|
|
781
|
+
name: "AES-GCM",
|
|
782
|
+
iv
|
|
783
|
+
}, key, plaintext));
|
|
784
|
+
return {
|
|
785
|
+
v: ENCRYPTED_MARKER,
|
|
786
|
+
iv: bytesToBase64(iv),
|
|
787
|
+
ciphertext: bytesToBase64(ciphertext)
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
async function decryptRecord(key, record) {
|
|
791
|
+
const iv = base64ToBytes(record.iv);
|
|
792
|
+
const ciphertext = base64ToBytes(record.ciphertext);
|
|
793
|
+
const plaintext = await crypto.subtle.decrypt({
|
|
794
|
+
name: "AES-GCM",
|
|
795
|
+
iv
|
|
796
|
+
}, key, ciphertext);
|
|
797
|
+
return JSON.parse(new TextDecoder().decode(plaintext));
|
|
798
|
+
}
|
|
799
|
+
async function writeMaterial(storage, ref, material) {
|
|
800
|
+
if (!subtleAvailable()) {
|
|
801
|
+
await storage.setMeta(META_PREFIX + ref, JSON.stringify(material));
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const record = await encryptMaterial(await getOrCreateKey(storage), material);
|
|
805
|
+
await storage.setMeta(META_PREFIX + ref, JSON.stringify(record));
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Read+decrypt a stored secret. Transparently migrates a legacy plaintext
|
|
809
|
+
* record by re-encrypting it in place before returning. Returns null for a
|
|
810
|
+
* missing ref or anything that can't be parsed/decrypted — the caller degrades
|
|
811
|
+
* gracefully rather than throwing.
|
|
812
|
+
*/
|
|
813
|
+
async function readMaterial(storage, ref) {
|
|
814
|
+
const raw = await storage.getMeta(META_PREFIX + ref);
|
|
815
|
+
if (raw === null) return null;
|
|
816
|
+
let parsed;
|
|
817
|
+
try {
|
|
818
|
+
parsed = JSON.parse(raw);
|
|
819
|
+
} catch {
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
if (isEncryptedRecord(parsed)) try {
|
|
823
|
+
return await decryptRecord(await getOrCreateKey(storage), parsed);
|
|
824
|
+
} catch {
|
|
825
|
+
return null;
|
|
826
|
+
}
|
|
827
|
+
const material = parsed;
|
|
828
|
+
if (subtleAvailable()) try {
|
|
829
|
+
await writeMaterial(storage, ref, material);
|
|
830
|
+
} catch {}
|
|
831
|
+
return material;
|
|
832
|
+
}
|
|
833
|
+
function createSecretStore(storage) {
|
|
834
|
+
return {
|
|
835
|
+
async set(ref, material) {
|
|
836
|
+
await writeMaterial(storage, ref, material);
|
|
837
|
+
},
|
|
838
|
+
async delete(ref) {
|
|
839
|
+
await storage.setMeta(META_PREFIX + ref, null);
|
|
840
|
+
},
|
|
841
|
+
async resolveAuth(entry) {
|
|
842
|
+
if (entry.auth.mode !== "basic" || !entry.auth.secretRef) return { mode: "none" };
|
|
843
|
+
const material = await readMaterial(storage, entry.auth.secretRef);
|
|
844
|
+
if (!material || typeof material.password !== "string") return { mode: "none" };
|
|
845
|
+
const username = entry.auth.username || material.username;
|
|
846
|
+
return username ? {
|
|
847
|
+
mode: "basic",
|
|
848
|
+
username,
|
|
849
|
+
password: material.password
|
|
850
|
+
} : {
|
|
851
|
+
mode: "basic",
|
|
852
|
+
password: material.password
|
|
853
|
+
};
|
|
854
|
+
},
|
|
855
|
+
async updateUsername(ref, username) {
|
|
856
|
+
const material = await readMaterial(storage, ref);
|
|
857
|
+
if (!material) return;
|
|
858
|
+
const updated = { ...material };
|
|
859
|
+
if (username === void 0) delete updated.username;
|
|
860
|
+
else updated.username = username;
|
|
861
|
+
await writeMaterial(storage, ref, updated);
|
|
862
|
+
}
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
//#endregion
|
|
866
|
+
//#region src/lib/chat/session-events.ts
|
|
867
|
+
/**
|
|
868
|
+
* SSE consumer for OpenCode's `/event` stream.
|
|
869
|
+
*
|
|
870
|
+
* Phase 3b ("One UI, delete the split"): the underlying stream is now opened by
|
|
871
|
+
* the browser-owned direct transport (`$lib/connections/boot.getTransport()`
|
|
872
|
+
* → `subscribeEvents(onFrame, signal)`), which talks to the active connection's
|
|
873
|
+
* OpenCode/Guardian base URL directly (no host proxy, no admin cookie) and
|
|
874
|
+
* REUSES this module's `parseFrame`. Reconnect/backoff, session-scoped dispatch,
|
|
875
|
+
* and abort semantics stay here — the chat layer's concern, not the transport's.
|
|
876
|
+
*
|
|
877
|
+
* Phase D of docs/technical/multi-endpoint-session-ux.md.
|
|
878
|
+
*/
|
|
879
|
+
var INITIAL_BACKOFF_MS = 1e3;
|
|
880
|
+
var MAX_BACKOFF_MS = 3e4;
|
|
881
|
+
/**
|
|
882
|
+
* Parse one `\n\n`-delimited SSE frame. Multi-line `data:` fields are
|
|
883
|
+
* concatenated with `\n` per the SSE spec. Reused by the direct transport.
|
|
884
|
+
*/
|
|
885
|
+
function parseFrame(chunk) {
|
|
886
|
+
const frame = {};
|
|
887
|
+
const dataLines = [];
|
|
888
|
+
for (const rawLine of chunk.split("\n")) {
|
|
889
|
+
if (!rawLine || rawLine.startsWith(":")) continue;
|
|
890
|
+
if (rawLine.startsWith("data:")) dataLines.push(rawLine.replace(/^data:\s?/, ""));
|
|
891
|
+
else if (rawLine.startsWith("event:")) frame.event = rawLine.replace(/^event:\s?/, "");
|
|
892
|
+
else if (rawLine.startsWith("id:")) frame.id = rawLine.replace(/^id:\s?/, "");
|
|
893
|
+
}
|
|
894
|
+
if (dataLines.length > 0) frame.data = dataLines.join("\n");
|
|
895
|
+
return frame;
|
|
896
|
+
}
|
|
897
|
+
function dispatch(handlers, payload) {
|
|
898
|
+
const info = payload.properties?.info;
|
|
899
|
+
const id = info?.id ?? payload.sessionID;
|
|
900
|
+
if (!id) return;
|
|
901
|
+
switch (payload.type) {
|
|
902
|
+
case "session.created":
|
|
903
|
+
handlers.onCreated(id);
|
|
904
|
+
return;
|
|
905
|
+
case "session.updated":
|
|
906
|
+
handlers.onUpdated(id, {
|
|
907
|
+
title: info?.title,
|
|
908
|
+
updatedAt: info?.time?.updated
|
|
909
|
+
});
|
|
910
|
+
return;
|
|
911
|
+
case "session.deleted":
|
|
912
|
+
handlers.onDeleted(id);
|
|
913
|
+
return;
|
|
914
|
+
default: return;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Open the active connection's `/event` SSE stream (via the direct transport)
|
|
919
|
+
* and dispatch session-scoped events. Returns an unsubscribe function that
|
|
920
|
+
* aborts the stream and prevents reconnection.
|
|
921
|
+
*
|
|
922
|
+
* `onConnect` fires on the first frame of each (re)connected stream — the point
|
|
923
|
+
* at which live updates are demonstrably flowing. The transport owns the fetch;
|
|
924
|
+
* this loop owns exponential-backoff reconnect and abort.
|
|
925
|
+
*/
|
|
926
|
+
function subscribeSessionEvents(handlers) {
|
|
927
|
+
let stopped = false;
|
|
928
|
+
let controller = new AbortController();
|
|
929
|
+
const sleep = (ms) => new Promise((resolve) => {
|
|
930
|
+
const timer = setTimeout(resolve, ms);
|
|
931
|
+
controller.signal.addEventListener("abort", () => {
|
|
932
|
+
clearTimeout(timer);
|
|
933
|
+
resolve();
|
|
934
|
+
}, { once: true });
|
|
935
|
+
});
|
|
936
|
+
async function readStream() {
|
|
937
|
+
let connected = false;
|
|
938
|
+
await getTransport().subscribeEvents((event) => {
|
|
939
|
+
if (!connected) {
|
|
940
|
+
connected = true;
|
|
941
|
+
handlers.onConnect?.();
|
|
942
|
+
}
|
|
943
|
+
const payload = event;
|
|
944
|
+
handlers.onEvent?.(payload);
|
|
945
|
+
dispatch(handlers, payload);
|
|
946
|
+
}, controller.signal);
|
|
947
|
+
}
|
|
948
|
+
(async () => {
|
|
949
|
+
let attempt = 0;
|
|
950
|
+
while (!stopped) try {
|
|
951
|
+
attempt++;
|
|
952
|
+
await readStream();
|
|
953
|
+
attempt = 0;
|
|
954
|
+
if (!stopped) await sleep(500);
|
|
955
|
+
} catch (err) {
|
|
956
|
+
if (stopped) return;
|
|
957
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
958
|
+
if (error.name !== "AbortError") {
|
|
959
|
+
console.warn("[session-events] SSE error, reconnecting", error);
|
|
960
|
+
handlers.onDisconnect?.(error);
|
|
961
|
+
}
|
|
962
|
+
await sleep(Math.min(INITIAL_BACKOFF_MS * 2 ** Math.max(0, attempt - 1), MAX_BACKOFF_MS));
|
|
963
|
+
if (controller.signal.aborted && !stopped) controller = new AbortController();
|
|
964
|
+
}
|
|
965
|
+
})();
|
|
966
|
+
return () => {
|
|
967
|
+
stopped = true;
|
|
968
|
+
try {
|
|
969
|
+
controller.abort();
|
|
970
|
+
} catch {}
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
//#endregion
|
|
974
|
+
//#region src/lib/transport/direct.ts
|
|
975
|
+
/**
|
|
976
|
+
* Minimal browser-owned direct transport (Phase 3a — "One UI, delete the
|
|
977
|
+
* split").
|
|
978
|
+
*
|
|
979
|
+
* Talks to a connection's OpenCode/Guardian base URL directly from the
|
|
980
|
+
* browser — no proxy, NO COOKIES (`credentials: 'omit'`). This is deliberately
|
|
981
|
+
* small: it exposes only the calls the ui chat layer needs and REUSES ui's
|
|
982
|
+
* existing SSE frame parser (`$lib/chat/session-events.ts` `parseFrame`) and
|
|
983
|
+
* event envelope type (`$lib/chat/oc-events.ts` `RawEvent`) rather than
|
|
984
|
+
* re-implementing them. Reconnect/backoff and session-scoped filtering are the
|
|
985
|
+
* chat layer's concern, not this transport's.
|
|
986
|
+
*/
|
|
987
|
+
var PROBE_TIMEOUT_MS = 5e3;
|
|
988
|
+
/**
|
|
989
|
+
* UTF-8-encode before base64ing: `btoa()` alone only accepts Latin-1 code
|
|
990
|
+
* points and throws a synchronous `InvalidCharacterError` for any password
|
|
991
|
+
* containing e.g. Cyrillic/CJK/emoji characters, before any network I/O.
|
|
992
|
+
*/
|
|
993
|
+
function base64Utf8(value) {
|
|
994
|
+
const bytes = new TextEncoder().encode(value);
|
|
995
|
+
let binary = "";
|
|
996
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
997
|
+
return btoa(binary);
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Build the `Authorization` header value for a resolved auth, or null for
|
|
1001
|
+
* `{ mode: 'none' }`. Basic username defaults to `'opencode'` (OpenCode's own
|
|
1002
|
+
* server default and what the host app sends).
|
|
1003
|
+
*/
|
|
1004
|
+
function authorizationHeader(auth) {
|
|
1005
|
+
if (auth.mode === "basic") return `Basic ${base64Utf8(`${auth.username ?? "opencode"}:${auth.password}`)}`;
|
|
1006
|
+
return null;
|
|
1007
|
+
}
|
|
1008
|
+
function createDirectTransport(getConnection, resolveAuth, fetchImpl = globalThis.fetch) {
|
|
1009
|
+
function requireConnection() {
|
|
1010
|
+
const connection = getConnection();
|
|
1011
|
+
if (!connection) throw new Error("No active connection");
|
|
1012
|
+
return connection;
|
|
1013
|
+
}
|
|
1014
|
+
/** Trailing-slash and path-prefix safe: reverse-proxied instances keep their prefix. */
|
|
1015
|
+
function baseFor(connection) {
|
|
1016
|
+
return connection.baseUrl.replace(/\/+$/, "");
|
|
1017
|
+
}
|
|
1018
|
+
async function authHeaders(connection) {
|
|
1019
|
+
const { authorization } = await resolveAuth(connection);
|
|
1020
|
+
return authorization ? { authorization } : {};
|
|
1021
|
+
}
|
|
1022
|
+
return {
|
|
1023
|
+
async request(method, path, body) {
|
|
1024
|
+
const connection = requireConnection();
|
|
1025
|
+
const init = {
|
|
1026
|
+
method,
|
|
1027
|
+
headers: {
|
|
1028
|
+
...body === void 0 ? {} : { "content-type": "application/json" },
|
|
1029
|
+
...await authHeaders(connection)
|
|
1030
|
+
},
|
|
1031
|
+
credentials: "omit"
|
|
1032
|
+
};
|
|
1033
|
+
if (body !== void 0) init.body = JSON.stringify(body);
|
|
1034
|
+
const response = await fetchImpl(`${baseFor(connection)}${path}`, init);
|
|
1035
|
+
if (!response.ok) throw Object.assign(/* @__PURE__ */ new Error(`HTTP ${response.status}`), { status: response.status });
|
|
1036
|
+
return response;
|
|
1037
|
+
},
|
|
1038
|
+
async subscribeEvents(onFrame, signal) {
|
|
1039
|
+
const connection = requireConnection();
|
|
1040
|
+
const response = await fetchImpl(`${baseFor(connection)}/event`, {
|
|
1041
|
+
method: "GET",
|
|
1042
|
+
headers: {
|
|
1043
|
+
accept: "text/event-stream",
|
|
1044
|
+
...await authHeaders(connection)
|
|
1045
|
+
},
|
|
1046
|
+
credentials: "omit",
|
|
1047
|
+
signal
|
|
1048
|
+
});
|
|
1049
|
+
if (!response.ok || !response.body) throw Object.assign(/* @__PURE__ */ new Error(`SSE stream failed: HTTP ${response.status}`), { status: response.status });
|
|
1050
|
+
const reader = response.body.getReader();
|
|
1051
|
+
const decoder = new TextDecoder();
|
|
1052
|
+
let buffer = "";
|
|
1053
|
+
try {
|
|
1054
|
+
while (true) {
|
|
1055
|
+
const { done, value } = await reader.read();
|
|
1056
|
+
if (done) break;
|
|
1057
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1058
|
+
const chunks = buffer.split("\n\n");
|
|
1059
|
+
buffer = chunks.pop() ?? "";
|
|
1060
|
+
for (const chunk of chunks) {
|
|
1061
|
+
if (!chunk) continue;
|
|
1062
|
+
const frame = parseFrame(chunk);
|
|
1063
|
+
if (!frame.data) continue;
|
|
1064
|
+
let event;
|
|
1065
|
+
try {
|
|
1066
|
+
event = JSON.parse(frame.data);
|
|
1067
|
+
} catch {
|
|
1068
|
+
continue;
|
|
1069
|
+
}
|
|
1070
|
+
onFrame(event);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
} finally {
|
|
1074
|
+
try {
|
|
1075
|
+
reader.releaseLock();
|
|
1076
|
+
} catch {}
|
|
1077
|
+
}
|
|
1078
|
+
},
|
|
1079
|
+
async probeHealth() {
|
|
1080
|
+
const connection = getConnection();
|
|
1081
|
+
if (!connection) return { status: "unreachable" };
|
|
1082
|
+
const base = baseFor(connection);
|
|
1083
|
+
const verdict = validateConnectionUrl(base);
|
|
1084
|
+
if (!verdict.ok && verdict.reason === "insecure-remote") return { status: "insecure" };
|
|
1085
|
+
try {
|
|
1086
|
+
const response = await fetchImpl(`${base}/`, {
|
|
1087
|
+
method: "GET",
|
|
1088
|
+
headers: await authHeaders(connection),
|
|
1089
|
+
credentials: "omit",
|
|
1090
|
+
cache: "no-store",
|
|
1091
|
+
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS)
|
|
1092
|
+
});
|
|
1093
|
+
if (response.status === 401 || response.status === 403) return { status: "unauthorized" };
|
|
1094
|
+
if (response.ok || response.status >= 300 && response.status < 400) return { status: "accessible" };
|
|
1095
|
+
return { status: "unreachable" };
|
|
1096
|
+
} catch {
|
|
1097
|
+
return { status: "unreachable" };
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
//#endregion
|
|
1103
|
+
//#region src/lib/connections/boot.ts
|
|
1104
|
+
/**
|
|
1105
|
+
* Browser connection boot (Phase 3b — "One UI, delete the split").
|
|
1106
|
+
*
|
|
1107
|
+
* One storage backend + one ConnectionStore + one SecretStore + one direct
|
|
1108
|
+
* transport per browsing session, created lazily on first access. The chat
|
|
1109
|
+
* layer (`$lib/api/chat.ts`, `$lib/chat/session-events.ts`) and the connection
|
|
1110
|
+
* switcher (`$lib/endpoints-state.svelte.ts`) all share these singletons so the
|
|
1111
|
+
* browser owns connections and talks to OpenCode/Guardian DIRECTLY — no host
|
|
1112
|
+
* proxy, no admin cookie.
|
|
1113
|
+
*
|
|
1114
|
+
* The transport reads the active connection SYNCHRONOUSLY from a snapshot the
|
|
1115
|
+
* connection store owner (`endpoints-state`) keeps in sync via
|
|
1116
|
+
* `setActiveConnection()`. The store's own `getActive()` is async (IndexedDB),
|
|
1117
|
+
* so it can't back the transport's synchronous `getConnection` directly.
|
|
1118
|
+
*
|
|
1119
|
+
* IndexedDB is the persistent backend; private-browsing modes that refuse it
|
|
1120
|
+
* degrade to an in-memory backend (session-only) rather than a blank page —
|
|
1121
|
+
* mirroring the client's `pickStorage`.
|
|
1122
|
+
*/
|
|
1123
|
+
var store = null;
|
|
1124
|
+
var secrets = null;
|
|
1125
|
+
var transport = null;
|
|
1126
|
+
/** Synchronous snapshot of the active connection for the transport. */
|
|
1127
|
+
var activeConnection = null;
|
|
1128
|
+
/**
|
|
1129
|
+
* Some private-browsing modes refuse IndexedDB entirely; degrade to a
|
|
1130
|
+
* session-only in-memory backend rather than a blank page (mirrors the
|
|
1131
|
+
* client's pickStorage).
|
|
1132
|
+
*/
|
|
1133
|
+
function pickStorage() {
|
|
1134
|
+
try {
|
|
1135
|
+
if (typeof indexedDB !== "undefined") return createIndexedDbStorage();
|
|
1136
|
+
} catch {}
|
|
1137
|
+
return createMemoryStorage();
|
|
1138
|
+
}
|
|
1139
|
+
function ensure() {
|
|
1140
|
+
if (store && secrets && transport) return;
|
|
1141
|
+
const storage = pickStorage();
|
|
1142
|
+
const connectionStore = createConnectionStore({ storage });
|
|
1143
|
+
const secretStore = createSecretStore(storage);
|
|
1144
|
+
const directTransport = createDirectTransport(() => activeConnection, async (connection) => {
|
|
1145
|
+
return { authorization: authorizationHeader(await secretStore.resolveAuth(connection)) ?? void 0 };
|
|
1146
|
+
});
|
|
1147
|
+
store = connectionStore;
|
|
1148
|
+
secrets = secretStore;
|
|
1149
|
+
transport = directTransport;
|
|
1150
|
+
}
|
|
1151
|
+
function getConnectionStore() {
|
|
1152
|
+
ensure();
|
|
1153
|
+
return store;
|
|
1154
|
+
}
|
|
1155
|
+
function getTransport() {
|
|
1156
|
+
ensure();
|
|
1157
|
+
return transport;
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Point the direct transport at `connection` (or clear it). Called by the
|
|
1161
|
+
* connection-store owner (`endpoints-state`) on load/activate — a plain
|
|
1162
|
+
* function, no `$effect`, so the transport's synchronous `getConnection`
|
|
1163
|
+
* always sees the current active connection.
|
|
1164
|
+
*/
|
|
1165
|
+
function setActiveConnection(connection) {
|
|
1166
|
+
activeConnection = connection;
|
|
1167
|
+
}
|
|
1168
|
+
//#endregion
|
|
1169
|
+
//#region src/lib/api/chat.ts
|
|
1170
|
+
/** Create a new session on the active connection's OpenCode instance. */
|
|
1171
|
+
async function createSession() {
|
|
1172
|
+
return await (await getTransport().request("POST", "/session", {})).json();
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* List sessions on the active connection.
|
|
1176
|
+
*
|
|
1177
|
+
* OpenCode returns `Array<Session>` with no ordering guarantee; we sort
|
|
1178
|
+
* desc by `time.updated` here so consumers can rely on it. See
|
|
1179
|
+
* docs/technical/multi-endpoint-session-ux.md §2.
|
|
1180
|
+
*/
|
|
1181
|
+
async function listSessions() {
|
|
1182
|
+
const summaries = (await (await getTransport().request("GET", "/session")).json()).map((s) => ({
|
|
1183
|
+
id: s.id,
|
|
1184
|
+
title: s.title ?? "",
|
|
1185
|
+
createdAt: s.time?.created ?? 0,
|
|
1186
|
+
updatedAt: s.time?.updated ?? s.time?.created ?? 0
|
|
1187
|
+
}));
|
|
1188
|
+
summaries.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
1189
|
+
return summaries;
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Fetch the messages for a session and map them to UI `ChatEntry`s.
|
|
1193
|
+
*
|
|
1194
|
+
* The part-flattening/grouping logic lives in `flattenSessionMessages`
|
|
1195
|
+
* (`$lib/chat/session-messages.ts`) — this client only handles transport.
|
|
1196
|
+
*/
|
|
1197
|
+
async function getSessionMessages(sessionId) {
|
|
1198
|
+
return flattenSessionMessages(await (await getTransport().request("GET", `/session/${encodeURIComponent(sessionId)}/message`)).json());
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1201
|
+
* Send a message to an existing session and await the full response (the
|
|
1202
|
+
* non-streaming fallback used when the SSE event stream isn't connected).
|
|
1203
|
+
*/
|
|
1204
|
+
async function sendChatMessage(sessionId, text) {
|
|
1205
|
+
return await (await getTransport().request("POST", `/session/${encodeURIComponent(sessionId)}/message`, { parts: [{
|
|
1206
|
+
type: "text",
|
|
1207
|
+
text
|
|
1208
|
+
}] })).json();
|
|
1209
|
+
}
|
|
1210
|
+
/** Start a turn without awaiting the reply — the SSE stream carries deltas. */
|
|
1211
|
+
async function startChatMessageTurn(sessionId, text) {
|
|
1212
|
+
await getTransport().request("POST", `/session/${encodeURIComponent(sessionId)}/message`, { parts: [{
|
|
1213
|
+
type: "text",
|
|
1214
|
+
text
|
|
1215
|
+
}] });
|
|
1216
|
+
}
|
|
1217
|
+
/**
|
|
1218
|
+
* Abort the in-flight turn on an existing session. Best-effort from the
|
|
1219
|
+
* caller's perspective — OpenCode exposes this as `POST /session/{id}/abort`.
|
|
1220
|
+
*/
|
|
1221
|
+
async function abortChatTurn(sessionId) {
|
|
1222
|
+
await (await getTransport().request("POST", `/session/${encodeURIComponent(sessionId)}/abort`, {})).text().catch(() => "");
|
|
1223
|
+
}
|
|
1224
|
+
async function replyChatPermission(requestId, reply) {
|
|
1225
|
+
await (await getTransport().request("POST", `/permission/${encodeURIComponent(requestId)}/reply`, { reply })).text().catch(() => "");
|
|
1226
|
+
}
|
|
1227
|
+
async function replyChatQuestion(requestId, answers) {
|
|
1228
|
+
await (await getTransport().request("POST", `/question/${encodeURIComponent(requestId)}/reply`, { answers })).text().catch(() => "");
|
|
1229
|
+
}
|
|
1230
|
+
async function rejectChatQuestion(requestId) {
|
|
1231
|
+
await (await getTransport().request("POST", `/question/${encodeURIComponent(requestId)}/reject`, {})).text().catch(() => "");
|
|
1232
|
+
}
|
|
1233
|
+
//#endregion
|
|
1234
|
+
//#region ../ui-kit/src/lib/components/icons/IconThemeSystem.svelte
|
|
1235
|
+
function IconThemeSystem($$renderer, $$props) {
|
|
1236
|
+
let { size = 20, class: className = "" } = $$props;
|
|
1237
|
+
$$renderer.push(`<svg xmlns="http://www.w3.org/2000/svg"${attr("width", size)}${attr("height", size)} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"${attr_class(`lucide lucide-sun-moon-icon lucide-sun-moon s-icon ${stringify(className)}`)}><path d="M12 2v2"></path><path d="M14.837 16.385a6 6 0 1 1-7.223-7.222c.624-.147.97.66.715 1.248a4 4 0 0 0 5.26 5.259c.589-.255 1.396.09 1.248.715"></path><path d="M16 12a4 4 0 0 0-4-4"></path><path d="m19 5-1.256 1.256"></path><path d="M20 12h2"></path></svg>`);
|
|
1238
|
+
}
|
|
1239
|
+
//#endregion
|
|
1240
|
+
//#region ../ui-kit/src/lib/components/icons/IconThemeLight.svelte
|
|
1241
|
+
function IconThemeLight($$renderer, $$props) {
|
|
1242
|
+
let { size = 20, class: className = "" } = $$props;
|
|
1243
|
+
$$renderer.push(`<svg aria-hidden="true"${attr("width", size)}${attr("height", size)} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"${attr_class(`s-icon ${stringify(className)}`)}><circle cx="12" cy="12" r="4"></circle><path d="M12 2.5v2.2M12 19.3v2.2M4.6 4.6l1.6 1.6M17.8 17.8l1.6 1.6M2.5 12h2.2M19.3 12h2.2M19.4 4.6l-1.6 1.6M6.2 17.8l-1.6 1.6"></path></svg>`);
|
|
1244
|
+
}
|
|
1245
|
+
//#endregion
|
|
1246
|
+
//#region ../ui-kit/src/lib/components/icons/IconThemeDark.svelte
|
|
1247
|
+
function IconThemeDark($$renderer, $$props) {
|
|
1248
|
+
let { size = 20, class: className = "" } = $$props;
|
|
1249
|
+
$$renderer.push(`<svg aria-hidden="true"${attr("width", size)}${attr("height", size)} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"${attr_class(`s-icon ${stringify(className)}`)}><path d="M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8z"></path></svg>`);
|
|
1250
|
+
}
|
|
1251
|
+
//#endregion
|
|
1252
|
+
//#region src/lib/chat/oc-events.ts
|
|
1253
|
+
function propStr(props, key) {
|
|
1254
|
+
const value = props?.[key];
|
|
1255
|
+
return typeof value === "string" ? value : void 0;
|
|
1256
|
+
}
|
|
1257
|
+
function partSnapshotType(event) {
|
|
1258
|
+
if (event.type !== "message.part.updated") return null;
|
|
1259
|
+
const part = event.properties?.part;
|
|
1260
|
+
if (typeof part?.id === "string" && typeof part.type === "string") return {
|
|
1261
|
+
partID: part.id,
|
|
1262
|
+
type: part.type
|
|
1263
|
+
};
|
|
1264
|
+
return null;
|
|
1265
|
+
}
|
|
1266
|
+
function extractTextDelta(event, sessionId, reasoningPartIds) {
|
|
1267
|
+
const props = event.properties ?? {};
|
|
1268
|
+
if (propStr(props, "sessionID") !== sessionId) return null;
|
|
1269
|
+
if (event.type === "session.next.text.delta") return propStr(props, "delta") ?? propStr(props, "text") ?? null;
|
|
1270
|
+
if (event.type === "message.part.delta") {
|
|
1271
|
+
const field = propStr(props, "field");
|
|
1272
|
+
if (field && field !== "text") return null;
|
|
1273
|
+
const partID = propStr(props, "partID");
|
|
1274
|
+
if (partID && reasoningPartIds?.has(partID)) return null;
|
|
1275
|
+
return propStr(props, "delta") ?? null;
|
|
1276
|
+
}
|
|
1277
|
+
return null;
|
|
1278
|
+
}
|
|
1279
|
+
function statusName(status) {
|
|
1280
|
+
if (typeof status === "string") return status;
|
|
1281
|
+
if (status && typeof status === "object" && typeof status.type === "string") return status.type;
|
|
1282
|
+
}
|
|
1283
|
+
function isTurnEnd(event, sessionId) {
|
|
1284
|
+
const props = event.properties ?? {};
|
|
1285
|
+
if (propStr(props, "sessionID") !== sessionId) return false;
|
|
1286
|
+
if (event.type === "session.idle") return true;
|
|
1287
|
+
if (event.type === "session.status") {
|
|
1288
|
+
const name = statusName(props.status);
|
|
1289
|
+
return name === "idle" || name === "completed" || name === "done";
|
|
1290
|
+
}
|
|
1291
|
+
return false;
|
|
1292
|
+
}
|
|
1293
|
+
function valueToText(value) {
|
|
1294
|
+
if (typeof value === "string") return value;
|
|
1295
|
+
if (value == null) return void 0;
|
|
1296
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1297
|
+
try {
|
|
1298
|
+
return JSON.stringify(value);
|
|
1299
|
+
} catch {
|
|
1300
|
+
return;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
function firstText(...values) {
|
|
1304
|
+
for (const value of values) {
|
|
1305
|
+
const text = valueToText(value);
|
|
1306
|
+
if (text) return text;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
function extractToolUpdate(event, sessionId) {
|
|
1310
|
+
const props = event.properties ?? {};
|
|
1311
|
+
if (propStr(props, "sessionID") !== sessionId) return null;
|
|
1312
|
+
const part = props.part ?? props.tool;
|
|
1313
|
+
if (event.type === "message.part.updated" && part && (part.type === "tool" || part.state)) {
|
|
1314
|
+
const state = part.state ?? {};
|
|
1315
|
+
return {
|
|
1316
|
+
callID: String(part.callID ?? part.id ?? ""),
|
|
1317
|
+
tool: String(part.tool ?? "tool"),
|
|
1318
|
+
status: String(state.status ?? "running"),
|
|
1319
|
+
title: typeof state.title === "string" ? state.title : void 0,
|
|
1320
|
+
detail: firstText(state.input, state.metadata, state.progress, state.output),
|
|
1321
|
+
output: valueToText(state.output),
|
|
1322
|
+
error: typeof state.error === "string" ? state.error : void 0
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
if (event.type.startsWith("session.next.tool.")) {
|
|
1326
|
+
const type = event.type.replace("session.next.tool.", "");
|
|
1327
|
+
return {
|
|
1328
|
+
callID: propStr(props, "callID") ?? "",
|
|
1329
|
+
tool: propStr(props, "tool") ?? "tool",
|
|
1330
|
+
status: type === "completed" ? "completed" : type === "failed" ? "error" : type === "called" ? "running" : propStr(props, "status") ?? "running",
|
|
1331
|
+
title: propStr(props, "title") ?? propStr(props, "tool"),
|
|
1332
|
+
detail: firstText(props.message, props.delta, props.progress, props.input, props.metadata),
|
|
1333
|
+
output: firstText(props.output, props.result),
|
|
1334
|
+
error: firstText(props.error)
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
return null;
|
|
1338
|
+
}
|
|
1339
|
+
function isSessionError(event, sessionId) {
|
|
1340
|
+
return event.type === "session.error" && propStr(event.properties, "sessionID") === sessionId;
|
|
1341
|
+
}
|
|
1342
|
+
function extractPermissionAsk(event, sessionId) {
|
|
1343
|
+
if (event.type !== "permission.asked") return null;
|
|
1344
|
+
if (propStr(event.properties, "sessionID") !== sessionId) return null;
|
|
1345
|
+
const id = propStr(event.properties, "id");
|
|
1346
|
+
if (!id) return null;
|
|
1347
|
+
const patterns = Array.isArray(event.properties?.patterns) ? event.properties.patterns.filter((item) => typeof item === "string") : [];
|
|
1348
|
+
const always = Array.isArray(event.properties?.always) ? event.properties.always.filter((item) => typeof item === "string") : [];
|
|
1349
|
+
const toolRecord = event.properties?.tool;
|
|
1350
|
+
return {
|
|
1351
|
+
requestID: id,
|
|
1352
|
+
permission: propStr(event.properties, "permission") ?? "tool",
|
|
1353
|
+
patterns,
|
|
1354
|
+
always,
|
|
1355
|
+
tool: propStr(toolRecord, "callID") ?? propStr(event.properties, "permission") ?? "tool",
|
|
1356
|
+
detail: firstText(event.properties?.metadata, event.properties?.message) ?? ""
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
function extractQuestionAsk(event, sessionId) {
|
|
1360
|
+
if (event.type !== "question.asked") return null;
|
|
1361
|
+
if (propStr(event.properties, "sessionID") !== sessionId) return null;
|
|
1362
|
+
const id = propStr(event.properties, "id");
|
|
1363
|
+
if (!id) return null;
|
|
1364
|
+
const rawQuestions = Array.isArray(event.properties?.questions) ? event.properties.questions : [];
|
|
1365
|
+
const questions = [];
|
|
1366
|
+
for (const raw of rawQuestions) {
|
|
1367
|
+
const item = raw;
|
|
1368
|
+
const options = Array.isArray(item.options) ? item.options.map((option) => option).filter((option) => typeof option.label === "string").map((option) => ({
|
|
1369
|
+
label: option.label,
|
|
1370
|
+
description: typeof option.description === "string" ? option.description : ""
|
|
1371
|
+
})) : [];
|
|
1372
|
+
questions.push({
|
|
1373
|
+
question: typeof item.question === "string" ? item.question : "",
|
|
1374
|
+
header: typeof item.header === "string" ? item.header : "",
|
|
1375
|
+
options
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
if (questions.length === 0) return null;
|
|
1379
|
+
return {
|
|
1380
|
+
requestID: id,
|
|
1381
|
+
questions
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
function extractStepUpdate(event, sessionId) {
|
|
1385
|
+
const props = event.properties ?? {};
|
|
1386
|
+
if (propStr(props, "sessionID") !== sessionId) return null;
|
|
1387
|
+
if (event.type !== "session.next.step.started" && event.type !== "session.next.step.ended") return null;
|
|
1388
|
+
return {
|
|
1389
|
+
id: propStr(props, "stepID") ?? propStr(props, "id") ?? event.type,
|
|
1390
|
+
title: propStr(props, "title") ?? propStr(props, "step") ?? (event.type === "session.next.step.started" ? "Working" : "Step complete"),
|
|
1391
|
+
status: event.type === "session.next.step.ended" ? "completed" : "running",
|
|
1392
|
+
detail: firstText(props.detail, props.message)
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
var SvelteSet = globalThis.Set;
|
|
1396
|
+
var SvelteMap = globalThis.Map;
|
|
1397
|
+
//#endregion
|
|
1398
|
+
//#region src/lib/desktop-notifications.ts
|
|
1399
|
+
var DESKTOP_NOTIFY_ENABLED_KEY = "openpalm.desktop.notify";
|
|
1400
|
+
var DESKTOP_NOTIFY_PREVIEW_KEY = "openpalm.desktop.notify.preview";
|
|
1401
|
+
function readFlag(key) {
|
|
1402
|
+
if (typeof window === "undefined") return false;
|
|
1403
|
+
try {
|
|
1404
|
+
return window.localStorage.getItem(key) === "1";
|
|
1405
|
+
} catch {
|
|
1406
|
+
return false;
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
function desktopNotifyEnabled() {
|
|
1410
|
+
return readFlag(DESKTOP_NOTIFY_ENABLED_KEY);
|
|
1411
|
+
}
|
|
1412
|
+
function desktopReplyPreviewEnabled() {
|
|
1413
|
+
return readFlag(DESKTOP_NOTIFY_PREVIEW_KEY);
|
|
1414
|
+
}
|
|
1415
|
+
function shouldNotifyDesktop() {
|
|
1416
|
+
if (typeof document === "undefined") return false;
|
|
1417
|
+
if (document.hasFocus()) return false;
|
|
1418
|
+
if (!desktopNotifyEnabled()) return false;
|
|
1419
|
+
return typeof window !== "undefined" && typeof window.openpalm?.notify === "function";
|
|
1420
|
+
}
|
|
1421
|
+
function notifyAssistantReply(replyText) {
|
|
1422
|
+
if (!shouldNotifyDesktop()) return;
|
|
1423
|
+
const body = desktopReplyPreviewEnabled() && replyText.trim() ? replyText.trim() : "Assistant replied";
|
|
1424
|
+
window.openpalm?.notify?.("OpenPalm", body);
|
|
1425
|
+
}
|
|
1426
|
+
function notifyAssistantError() {
|
|
1427
|
+
if (!shouldNotifyDesktop()) return;
|
|
1428
|
+
window.openpalm?.notify?.("OpenPalm", "Assistant error");
|
|
1429
|
+
}
|
|
1430
|
+
//#endregion
|
|
1431
|
+
//#region src/lib/connection-events.ts
|
|
1432
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
1433
|
+
var guards = /* @__PURE__ */ new Set();
|
|
1434
|
+
/** Subscribe to connection activation. Returns an unsubscribe function. */
|
|
1435
|
+
function onConnectionActivated(listener) {
|
|
1436
|
+
listeners.add(listener);
|
|
1437
|
+
return () => {
|
|
1438
|
+
listeners.delete(listener);
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Register a pre-switch veto. Return a user-facing reason string to block
|
|
1443
|
+
* the switch, or null to allow it. Returns an unregister function.
|
|
1444
|
+
*/
|
|
1445
|
+
function registerActivationGuard(guard) {
|
|
1446
|
+
guards.add(guard);
|
|
1447
|
+
return () => {
|
|
1448
|
+
guards.delete(guard);
|
|
1449
|
+
};
|
|
1450
|
+
}
|
|
1451
|
+
/** First non-null guard reason blocks the switch; null means proceed. */
|
|
1452
|
+
function activationBlockReason() {
|
|
1453
|
+
for (const guard of guards) {
|
|
1454
|
+
const reason = guard();
|
|
1455
|
+
if (reason) return reason;
|
|
1456
|
+
}
|
|
1457
|
+
return null;
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* Notify subscribers that `connectionId` is now active. Awaited by the
|
|
1461
|
+
* emitter: activation is not complete until every subscriber's handoff
|
|
1462
|
+
* (e.g. the chat store loading the connection's sessions) has settled.
|
|
1463
|
+
*/
|
|
1464
|
+
async function emitConnectionActivated(connectionId) {
|
|
1465
|
+
for (const listener of listeners) await listener(connectionId);
|
|
1466
|
+
}
|
|
1467
|
+
//#endregion
|
|
1468
|
+
//#region src/lib/endpoints-state.svelte.ts
|
|
1469
|
+
function toView(c) {
|
|
1470
|
+
return {
|
|
1471
|
+
...c,
|
|
1472
|
+
url: c.baseUrl,
|
|
1473
|
+
isDefault: Boolean(c.isDefault || c.locked),
|
|
1474
|
+
hasPassword: c.auth.mode === "basic"
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
var ConnectionsService = class {
|
|
1478
|
+
endpoints = [];
|
|
1479
|
+
activeId = "";
|
|
1480
|
+
loading = false;
|
|
1481
|
+
loaded = false;
|
|
1482
|
+
error = "";
|
|
1483
|
+
/** Runtime-config seed runs exactly once per browsing session. */
|
|
1484
|
+
seeded = false;
|
|
1485
|
+
#active = derived(() => this.endpoints.find((e) => e.id === this.activeId) ?? this.endpoints[0] ?? null);
|
|
1486
|
+
get active() {
|
|
1487
|
+
return this.#active();
|
|
1488
|
+
}
|
|
1489
|
+
set active($$value) {
|
|
1490
|
+
return this.#active($$value);
|
|
1491
|
+
}
|
|
1492
|
+
async load(force = false) {
|
|
1493
|
+
if (this.loading) return;
|
|
1494
|
+
if (this.loaded && !force) return;
|
|
1495
|
+
this.loading = true;
|
|
1496
|
+
this.error = "";
|
|
1497
|
+
try {
|
|
1498
|
+
const store = getConnectionStore();
|
|
1499
|
+
if (!this.seeded) {
|
|
1500
|
+
this.seeded = true;
|
|
1501
|
+
await store.seedFromRuntimeConfig(await loadRuntimeConfig());
|
|
1502
|
+
}
|
|
1503
|
+
const [connections, storedActiveId] = await Promise.all([store.list(), store.getActiveId()]);
|
|
1504
|
+
this.endpoints = connections.map(toView);
|
|
1505
|
+
this.activeId = storedActiveId ?? this.endpoints[0]?.id ?? "";
|
|
1506
|
+
setActiveConnection(connections.find((c) => c.id === this.activeId) ?? null);
|
|
1507
|
+
this.loaded = true;
|
|
1508
|
+
} catch (e) {
|
|
1509
|
+
const err = e;
|
|
1510
|
+
this.error = err.message ?? "Failed to load connections";
|
|
1511
|
+
} finally {
|
|
1512
|
+
this.loading = false;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
/** Monotonic activation counter: a failed activation may only roll state
|
|
1516
|
+
* back if no NEWER activation has started since (otherwise a slow failure
|
|
1517
|
+
* would clobber the selection a later, successful switch just persisted). */
|
|
1518
|
+
activationSeq = 0;
|
|
1519
|
+
async activate(id) {
|
|
1520
|
+
if (id === this.activeId) return;
|
|
1521
|
+
const blocked = activationBlockReason();
|
|
1522
|
+
if (blocked) {
|
|
1523
|
+
this.error = blocked;
|
|
1524
|
+
throw new Error(blocked);
|
|
1525
|
+
}
|
|
1526
|
+
const seq = ++this.activationSeq;
|
|
1527
|
+
const previous = this.activeId;
|
|
1528
|
+
const previousConnection = this.endpoints.find((e) => e.id === previous) ?? null;
|
|
1529
|
+
this.activeId = id;
|
|
1530
|
+
const store = getConnectionStore();
|
|
1531
|
+
try {
|
|
1532
|
+
await store.setActive(id);
|
|
1533
|
+
setActiveConnection(await store.get(id) ?? null);
|
|
1534
|
+
await emitConnectionActivated(id);
|
|
1535
|
+
} catch (e) {
|
|
1536
|
+
if (seq === this.activationSeq) {
|
|
1537
|
+
this.activeId = previous;
|
|
1538
|
+
if (previousConnection) {
|
|
1539
|
+
await store.setActive(previous).catch(() => {});
|
|
1540
|
+
setActiveConnection(previousConnection);
|
|
1541
|
+
} else {
|
|
1542
|
+
await store.clearActive().catch(() => {});
|
|
1543
|
+
setActiveConnection(null);
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
const err = e;
|
|
1547
|
+
this.error = err.message ?? "Failed to switch connection";
|
|
1548
|
+
throw e;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
};
|
|
1552
|
+
var endpointsService = new ConnectionsService();
|
|
1553
|
+
//#endregion
|
|
1554
|
+
//#region ../ui-kit/src/lib/components/icons/IconClose.svelte
|
|
1555
|
+
function IconClose($$renderer, $$props) {
|
|
1556
|
+
let { size = 20, class: className = "" } = $$props;
|
|
1557
|
+
$$renderer.push(`<svg aria-hidden="true"${attr("width", size)}${attr("height", size)} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"${attr_class(`s-icon ${stringify(className)}`)}><path d="M18 6 6 18"></path><path d="m6 6 12 12"></path></svg>`);
|
|
1558
|
+
}
|
|
1559
|
+
//#endregion
|
|
1560
|
+
//#region src/lib/format-date.ts
|
|
1561
|
+
var TIME_FMT = new Intl.DateTimeFormat(void 0, {
|
|
1562
|
+
hour: "numeric",
|
|
1563
|
+
minute: "2-digit"
|
|
1564
|
+
});
|
|
1565
|
+
var DATE_TIME_FMT = new Intl.DateTimeFormat(void 0, {
|
|
1566
|
+
year: "numeric",
|
|
1567
|
+
month: "short",
|
|
1568
|
+
day: "numeric",
|
|
1569
|
+
hour: "numeric",
|
|
1570
|
+
minute: "2-digit"
|
|
1571
|
+
});
|
|
1572
|
+
/** Time of day, e.g. "3:42 PM" (locale-aware). Empty string for a falsy input. */
|
|
1573
|
+
function formatTime(ts) {
|
|
1574
|
+
if (!ts) return "";
|
|
1575
|
+
return TIME_FMT.format(ts);
|
|
1576
|
+
}
|
|
1577
|
+
/**
|
|
1578
|
+
* Absolute date + time, e.g. "Jun 7, 2026, 3:42 PM". Use for tooltips / full
|
|
1579
|
+
* context where a relative label alone is ambiguous. Empty for a falsy input.
|
|
1580
|
+
*/
|
|
1581
|
+
function formatDateTime(ts) {
|
|
1582
|
+
if (!ts) return "";
|
|
1583
|
+
return DATE_TIME_FMT.format(ts);
|
|
1584
|
+
}
|
|
1585
|
+
/**
|
|
1586
|
+
* Absolute date + time from a date string (ISO-8601 or anything `Date` accepts),
|
|
1587
|
+
* rendered with the runtime locale via `toLocaleString()`. Unlike the epoch-ms
|
|
1588
|
+
* helpers above, this takes the string shape returned by admin/AKM endpoints.
|
|
1589
|
+
* Returns `fallback` (default em dash) for null/empty or unparseable input.
|
|
1590
|
+
*/
|
|
1591
|
+
function formatDate(value, fallback = "—") {
|
|
1592
|
+
if (!value) return fallback;
|
|
1593
|
+
const d = new Date(value);
|
|
1594
|
+
return Number.isNaN(d.getTime()) ? fallback : d.toLocaleString();
|
|
1595
|
+
}
|
|
1596
|
+
/**
|
|
1597
|
+
* Human-readable byte size, e.g. "512 B", "1.5 KB", "2.0 MB". Scales through
|
|
1598
|
+
* B/KB/MB/GB/TB (binary, 1024-based) with adaptive precision: whole numbers for
|
|
1599
|
+
* bytes and for values ≥ 10, one decimal otherwise. Em dash for non-finite input.
|
|
1600
|
+
*/
|
|
1601
|
+
function formatBytes(bytes) {
|
|
1602
|
+
if (!Number.isFinite(bytes)) return "—";
|
|
1603
|
+
const units = [
|
|
1604
|
+
"B",
|
|
1605
|
+
"KB",
|
|
1606
|
+
"MB",
|
|
1607
|
+
"GB",
|
|
1608
|
+
"TB"
|
|
1609
|
+
];
|
|
1610
|
+
let value = bytes;
|
|
1611
|
+
let i = 0;
|
|
1612
|
+
while (value >= 1024 && i < units.length - 1) {
|
|
1613
|
+
value /= 1024;
|
|
1614
|
+
i += 1;
|
|
1615
|
+
}
|
|
1616
|
+
return `${value.toFixed(value >= 10 || i === 0 ? 0 : 1)} ${units[i]}`;
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* Compact relative time, e.g. "just now", "5m ago", "yesterday", "3w ago".
|
|
1620
|
+
* Empty string for a falsy input. No date-fns dependency — that would be ~30 KB
|
|
1621
|
+
* for these few cases.
|
|
1622
|
+
*/
|
|
1623
|
+
function formatRelativeTime(ts) {
|
|
1624
|
+
if (!ts) return "";
|
|
1625
|
+
const diffSec = Math.max(0, (Date.now() - ts) / 1e3);
|
|
1626
|
+
if (diffSec < 60) return "just now";
|
|
1627
|
+
const min = Math.floor(diffSec / 60);
|
|
1628
|
+
if (min < 60) return `${min}m ago`;
|
|
1629
|
+
const hr = Math.floor(min / 60);
|
|
1630
|
+
if (hr < 24) return `${hr}h ago`;
|
|
1631
|
+
const day = Math.floor(hr / 24);
|
|
1632
|
+
if (day === 1) return "yesterday";
|
|
1633
|
+
if (day < 7) return `${day}d ago`;
|
|
1634
|
+
const wk = Math.floor(day / 7);
|
|
1635
|
+
if (wk < 5) return `${wk}w ago`;
|
|
1636
|
+
const mo = Math.floor(day / 30);
|
|
1637
|
+
if (mo < 12) return `${mo}mo ago`;
|
|
1638
|
+
return `${Math.floor(day / 365)}y ago`;
|
|
1639
|
+
}
|
|
1640
|
+
//#endregion
|
|
1641
|
+
//#region ../ui-kit/src/lib/components/icons/IconStop.svelte
|
|
1642
|
+
function IconStop($$renderer, $$props) {
|
|
1643
|
+
let { size = 20, class: className = "" } = $$props;
|
|
1644
|
+
$$renderer.push(`<svg aria-hidden="true"${attr("width", size)}${attr("height", size)} viewBox="0 0 24 24"${attr_class(`s-icon ${stringify(className)}`)}><rect fill="currentColor" stroke="none" x="7" y="7" width="10" height="10" rx="1.4"></rect></svg>`);
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
export { notifyAssistantError as A, notifyAssistantReply as B, onConnectionActivated as C, partSnapshotType as D, registerActivationGuard as E, rejectChatQuestion as F, relativeTimeLabel as G, replyChatPermission as H, IconClose as I, replyChatQuestion as J, sendChatMessage as K, startChatMessageTurn as L, subscribeSessionEvents as M, timelineTitle as N, toolAriaLabel as O, toolDetailRows as P, toolIconType as Q, toolStatusLabel as R, SvelteMap as S, IconStop as a, IconThemeDark as b, IconThemeLight as c, IconThemeSystem as d, SvelteSet as e, abortChatTurn as f, createSession as g, displayTitle as h, endpointsService as i, extractPermissionAsk as j, extractQuestionAsk as k, extractStepUpdate as l, extractTextDelta as m, extractToolUpdate as n, formatBytes as o, formatDate as p, formatDateTime as q, formatRelativeTime as r, formatTime as s, getSessionMessages as t, getTransport as u, isLoopbackHost as v, isSessionError as w, isTurnEnd as x, isUserFacingTool as y, listSessions as z };
|
|
1648
|
+
//# sourceMappingURL=IconStop-DKVpXPKq.js.map
|