@saluzi/saluzi-edu 0.2.61 → 0.2.63
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/dist/cli.js +204 -116
- package/dist/parade/web/menu.html +71 -23
- package/dist/rcs-web/assets/{AdminPanel-Xlza8Stt.js → AdminPanel-CqP_94xa.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/Claim-BMWwu213.js → dist/rcs-web/assets/Claim-BvfARQ6Q.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/Dashboard-D5awDzM3.js → dist/rcs-web/assets/Dashboard-BDGi4XpN.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/Join-ok37ggfZ.js → dist/rcs-web/assets/Join-PPDYBhsJ.js} +1 -1
- package/dist/rcs-web/assets/{Login-5qo97rq-.js → Login-JprQIEpr.js} +1 -1
- package/dist/rcs-web/assets/{Register-D_UOG8ar.js → Register-cuGuAE83.js} +1 -1
- package/dist/rcs-web/assets/{SessionDetail-BbHrR4Qu.js → SessionDetail-D-xhkyLo.js} +5 -5
- package/dist/rcs-web/assets/{SessionVisibilityBadge-Dy4FwTzo.js → SessionVisibilityBadge-91WyR9K6.js} +1 -1
- package/dist/rcs-web/assets/{Setup-GnPeNyH9.js → Setup-Buwa9Y3M.js} +1 -1
- package/dist/rcs-web/assets/{ShareLanding-CUjQydLL.js → ShareLanding-DhwgJb6V.js} +1 -1
- package/dist/rcs-web/assets/{TeamCreate-Ck2fEoUW.js → TeamCreate-CaoinTSG.js} +1 -1
- package/dist/rcs-web/assets/{TeamDetail-De6EPND0.js → TeamDetail-D5ahen24.js} +1 -1
- package/dist/rcs-web/assets/{TeamList-C-0LJRxd.js → TeamList-qCuKKSH3.js} +1 -1
- package/dist/rcs-web/assets/{TeamSettings-BszOrXVW.js → TeamSettings-BaIwImrp.js} +1 -1
- package/dist/rcs-web/assets/{UserSearchInput-CyQWtLL-.js → UserSearchInput-BxcYR_HU.js} +1 -1
- package/dist/rcs-web/assets/{UserSettings-DgyYp-1y.js → UserSettings-zfGfcuWs.js} +1 -1
- package/dist/rcs-web/assets/{arc-BaOPt7k-.js → arc-DwAbF6eM.js} +1 -1
- package/dist/rcs-web/assets/{architectureDiagram-3BPJPVTR-SvIakXbT.js → architectureDiagram-3BPJPVTR-uMOwOwiN.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/blockDiagram-GPEHLZMM-CiDp9J7i.js → dist/rcs-web/assets/blockDiagram-GPEHLZMM-B5BqFTkP.js} +1 -1
- package/dist/rcs-web/assets/{c4Diagram-AAUBKEIU-D9wzA9ur.js → c4Diagram-AAUBKEIU-D6eienz2.js} +1 -1
- package/dist/rcs-web/assets/channel-CCfqpGSl.js +1 -0
- package/dist/rcs-web/assets/{chunk-2J33WTMH-qfYueRAP.js → chunk-2J33WTMH-DqVxv8yW.js} +1 -1
- package/dist/rcs-web/assets/{chunk-4BX2VUAB-D1V_UCiK.js → chunk-4BX2VUAB-X5o4x8om.js} +1 -1
- package/dist/rcs-web/assets/{chunk-55IACEB6-C67QiGmo.js → chunk-55IACEB6-D7G25_Y5.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/chunk-727SXJPM-D2Wln4TT.js → dist/rcs-web/assets/chunk-727SXJPM-CoXI1FIy.js} +1 -1
- package/dist/rcs-web/assets/{chunk-AQP2D5EJ-03h8hZhw.js → chunk-AQP2D5EJ-C73Crhqe.js} +1 -1
- package/dist/rcs-web/assets/{chunk-FMBD7UC4-7zas8pDp.js → chunk-FMBD7UC4-DVzxIsSE.js} +1 -1
- package/dist/rcs-web/assets/{chunk-ND2GUHAM-PUXucyY6.js → chunk-ND2GUHAM-C6_oEhLf.js} +1 -1
- package/dist/rcs-web/assets/{chunk-QZHKN3VN-M3U5l4yW.js → chunk-QZHKN3VN-COvH7k5r.js} +1 -1
- package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-DzNdVs3v.js +1 -0
- package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-DzNdVs3v.js +1 -0
- package/dist/rcs-web/assets/{code-block-IT6T5CEO-BgUazuuS.js → code-block-IT6T5CEO-CE-2f_-K.js} +1 -1
- package/dist/rcs-web/assets/{copy-DjaSB1Rw.js → copy-9pzb1Po6.js} +1 -1
- package/dist/rcs-web/assets/{cose-bilkent-S5V4N54A-zPupX74N.js → cose-bilkent-S5V4N54A-B9sMDFRe.js} +1 -1
- package/dist/rcs-web/assets/{dagre-BM42HDAG-B_EJ050J.js → dagre-BM42HDAG-DB1jXylM.js} +1 -1
- package/dist/rcs-web/assets/{diagram-2AECGRRQ-dnnxPH7w.js → diagram-2AECGRRQ-MNuqSRmg.js} +1 -1
- package/dist/rcs-web/assets/{diagram-5GNKFQAL-CLEOqCLZ.js → diagram-5GNKFQAL-BZwhvaEY.js} +1 -1
- package/dist/rcs-web/assets/{diagram-KO2AKTUF-DKBGpiRW.js → diagram-KO2AKTUF-3Wp2PnI2.js} +1 -1
- package/dist/rcs-web/assets/{diagram-LMA3HP47-BAilhXiA.js → diagram-LMA3HP47-CTcV1SBj.js} +1 -1
- package/dist/rcs-web/assets/{diagram-OG6HWLK6-C3CdmOxC.js → diagram-OG6HWLK6-DzXhSQDC.js} +1 -1
- package/dist/rcs-web/assets/{erDiagram-TEJ5UH35-D1yv-3Jv.js → erDiagram-TEJ5UH35-CwSihkB8.js} +1 -1
- package/dist/rcs-web/assets/{flowDiagram-I6XJVG4X-DpW11XWj.js → flowDiagram-I6XJVG4X-BSuXctT4.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/ganttDiagram-6RSMTGT7-CWr8suZm.js → dist/rcs-web/assets/ganttDiagram-6RSMTGT7-B87oxjmY.js} +1 -1
- package/dist/rcs-web/assets/{gitGraphDiagram-PVQCEYII-BspxLSNV.js → gitGraphDiagram-PVQCEYII-BRrwOi3C.js} +1 -1
- package/dist/rcs-web/assets/{infoDiagram-5YYISTIA-Bow20s-Q.js → infoDiagram-5YYISTIA-B-8QXS0n.js} +1 -1
- package/dist/rcs-web/assets/{ishikawaDiagram-YF4QCWOH-BESvGYGI.js → ishikawaDiagram-YF4QCWOH-Bau9MU6C.js} +1 -1
- package/dist/rcs-web/assets/{journeyDiagram-JHISSGLW-DZ6gzC7H.js → journeyDiagram-JHISSGLW-D_tAp--R.js} +1 -1
- package/dist/rcs-web/assets/{kanban-definition-UN3LZRKU-DIQo2GiM.js → kanban-definition-UN3LZRKU---UIvjMZ.js} +1 -1
- package/dist/rcs-web/assets/{linear-CdXALiZ8.js → linear-CIDLjd5h.js} +1 -1
- package/dist/rcs-web/assets/{main-CwLwGVDc.js → main-N3GYCdLF.js} +3 -3
- package/dist/rcs-web/assets/{mermaid-VLURNSYL-C0ZKM74W.js → mermaid-VLURNSYL-Cu5A5sMk.js} +4 -4
- package/dist/rcs-web/assets/{mermaid.core-eEtoQhrQ.js → mermaid.core-CEJOtCGw.js} +5 -5
- package/dist/rcs-web/assets/{mindmap-definition-RKZ34NQL-CcW3H_cH.js → mindmap-definition-RKZ34NQL-ldyccyCP.js} +1 -1
- package/dist/rcs-web/assets/{pieDiagram-4H26LBE5-DpXUpJMl.js → pieDiagram-4H26LBE5-CmghofeF.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/quadrantDiagram-W4KKPZXB-DOwMRzzP.js → dist/rcs-web/assets/quadrantDiagram-W4KKPZXB-B-2N2UHr.js} +1 -1
- package/dist/rcs-web/assets/{requirementDiagram-4Y6WPE33-CBi_6NcW.js → requirementDiagram-4Y6WPE33-39jlO9Y8.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-CKbAoTHm.js → dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-DdY7KNFB.js} +1 -1
- package/dist/rcs-web/assets/{sequenceDiagram-3UESZ5HK-a3rYCe-w.js → sequenceDiagram-3UESZ5HK-D2k5rX6x.js} +1 -1
- package/dist/rcs-web/assets/{stateDiagram-AJRCARHV-B6R_Dt84.js → stateDiagram-AJRCARHV-CP9N457o.js} +1 -1
- package/dist/rcs-web/assets/{stateDiagram-v2-BHNVJYJU-Cq935fvz.js → stateDiagram-v2-BHNVJYJU-CPhZYlL0.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-8DXPKq1k.js → dist/rcs-web/assets/timeline-definition-PNZ67QCA-DSEPBO8O.js} +1 -1
- package/dist/rcs-web/assets/{vennDiagram-CIIHVFJN-BfDEkku5.js → vennDiagram-CIIHVFJN-CkNMwCJ3.js} +1 -1
- package/dist/rcs-web/assets/{wardleyDiagram-YWT4CUSO-Dvp2XZVf.js → wardleyDiagram-YWT4CUSO-Cxd-F60s.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/xychartDiagram-2RQKCTM6-DiPjQLUx.js → dist/rcs-web/assets/xychartDiagram-2RQKCTM6-BLL105NN.js} +1 -1
- package/dist/rcs-web/index.html +1 -1
- package/package.json +1 -1
- package/packages/remote-control-server/src/__tests__/models-state-snapshot.test.ts +216 -0
- package/packages/remote-control-server/src/__tests__/turn-end-status.test.ts +217 -1
- package/packages/remote-control-server/src/routes/v2/worker-events.ts +12 -1
- package/packages/remote-control-server/src/routes/web/control.ts +11 -2
- package/packages/remote-control-server/src/routes/web/sessions.ts +33 -0
- package/packages/remote-control-server/src/services/transport.ts +12 -0
- package/packages/remote-control-server/src/transport/event-bus.ts +25 -0
- package/packages/remote-control-server/src/transport/ws-handler.ts +14 -1
- package/packages/remote-control-server/web/dist/assets/{AdminPanel-Xlza8Stt.js → AdminPanel-CqP_94xa.js} +1 -1
- package/{dist/rcs-web/assets/Claim-BMWwu213.js → packages/remote-control-server/web/dist/assets/Claim-BvfARQ6Q.js} +1 -1
- package/{dist/rcs-web/assets/Dashboard-D5awDzM3.js → packages/remote-control-server/web/dist/assets/Dashboard-BDGi4XpN.js} +1 -1
- package/{dist/rcs-web/assets/Join-ok37ggfZ.js → packages/remote-control-server/web/dist/assets/Join-PPDYBhsJ.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{Login-5qo97rq-.js → Login-JprQIEpr.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{Register-D_UOG8ar.js → Register-cuGuAE83.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{SessionDetail-BbHrR4Qu.js → SessionDetail-D-xhkyLo.js} +5 -5
- package/packages/remote-control-server/web/dist/assets/{SessionVisibilityBadge-Dy4FwTzo.js → SessionVisibilityBadge-91WyR9K6.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{Setup-GnPeNyH9.js → Setup-Buwa9Y3M.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{ShareLanding-CUjQydLL.js → ShareLanding-DhwgJb6V.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{TeamCreate-Ck2fEoUW.js → TeamCreate-CaoinTSG.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{TeamDetail-De6EPND0.js → TeamDetail-D5ahen24.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{TeamList-C-0LJRxd.js → TeamList-qCuKKSH3.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{TeamSettings-BszOrXVW.js → TeamSettings-BaIwImrp.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{UserSearchInput-CyQWtLL-.js → UserSearchInput-BxcYR_HU.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{UserSettings-DgyYp-1y.js → UserSettings-zfGfcuWs.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{arc-BaOPt7k-.js → arc-DwAbF6eM.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{architectureDiagram-3BPJPVTR-SvIakXbT.js → architectureDiagram-3BPJPVTR-uMOwOwiN.js} +1 -1
- package/{dist/rcs-web/assets/blockDiagram-GPEHLZMM-CiDp9J7i.js → packages/remote-control-server/web/dist/assets/blockDiagram-GPEHLZMM-B5BqFTkP.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{c4Diagram-AAUBKEIU-D9wzA9ur.js → c4Diagram-AAUBKEIU-D6eienz2.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/channel-CCfqpGSl.js +1 -0
- package/packages/remote-control-server/web/dist/assets/{chunk-2J33WTMH-qfYueRAP.js → chunk-2J33WTMH-DqVxv8yW.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-4BX2VUAB-D1V_UCiK.js → chunk-4BX2VUAB-X5o4x8om.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-55IACEB6-C67QiGmo.js → chunk-55IACEB6-D7G25_Y5.js} +1 -1
- package/{dist/rcs-web/assets/chunk-727SXJPM-D2Wln4TT.js → packages/remote-control-server/web/dist/assets/chunk-727SXJPM-CoXI1FIy.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-AQP2D5EJ-03h8hZhw.js → chunk-AQP2D5EJ-C73Crhqe.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-FMBD7UC4-7zas8pDp.js → chunk-FMBD7UC4-DVzxIsSE.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-ND2GUHAM-PUXucyY6.js → chunk-ND2GUHAM-C6_oEhLf.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-QZHKN3VN-M3U5l4yW.js → chunk-QZHKN3VN-COvH7k5r.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-DzNdVs3v.js +1 -0
- package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-DzNdVs3v.js +1 -0
- package/packages/remote-control-server/web/dist/assets/{code-block-IT6T5CEO-BgUazuuS.js → code-block-IT6T5CEO-CE-2f_-K.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{copy-DjaSB1Rw.js → copy-9pzb1Po6.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{cose-bilkent-S5V4N54A-zPupX74N.js → cose-bilkent-S5V4N54A-B9sMDFRe.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{dagre-BM42HDAG-B_EJ050J.js → dagre-BM42HDAG-DB1jXylM.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{diagram-2AECGRRQ-dnnxPH7w.js → diagram-2AECGRRQ-MNuqSRmg.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{diagram-5GNKFQAL-CLEOqCLZ.js → diagram-5GNKFQAL-BZwhvaEY.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{diagram-KO2AKTUF-DKBGpiRW.js → diagram-KO2AKTUF-3Wp2PnI2.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{diagram-LMA3HP47-BAilhXiA.js → diagram-LMA3HP47-CTcV1SBj.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{diagram-OG6HWLK6-C3CdmOxC.js → diagram-OG6HWLK6-DzXhSQDC.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{erDiagram-TEJ5UH35-D1yv-3Jv.js → erDiagram-TEJ5UH35-CwSihkB8.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{flowDiagram-I6XJVG4X-DpW11XWj.js → flowDiagram-I6XJVG4X-BSuXctT4.js} +1 -1
- package/{dist/rcs-web/assets/ganttDiagram-6RSMTGT7-CWr8suZm.js → packages/remote-control-server/web/dist/assets/ganttDiagram-6RSMTGT7-B87oxjmY.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{gitGraphDiagram-PVQCEYII-BspxLSNV.js → gitGraphDiagram-PVQCEYII-BRrwOi3C.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{infoDiagram-5YYISTIA-Bow20s-Q.js → infoDiagram-5YYISTIA-B-8QXS0n.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{ishikawaDiagram-YF4QCWOH-BESvGYGI.js → ishikawaDiagram-YF4QCWOH-Bau9MU6C.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{journeyDiagram-JHISSGLW-DZ6gzC7H.js → journeyDiagram-JHISSGLW-D_tAp--R.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{kanban-definition-UN3LZRKU-DIQo2GiM.js → kanban-definition-UN3LZRKU---UIvjMZ.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{linear-CdXALiZ8.js → linear-CIDLjd5h.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{main-CwLwGVDc.js → main-N3GYCdLF.js} +3 -3
- package/packages/remote-control-server/web/dist/assets/{mermaid-VLURNSYL-C0ZKM74W.js → mermaid-VLURNSYL-Cu5A5sMk.js} +4 -4
- package/packages/remote-control-server/web/dist/assets/{mermaid.core-eEtoQhrQ.js → mermaid.core-CEJOtCGw.js} +5 -5
- package/packages/remote-control-server/web/dist/assets/{mindmap-definition-RKZ34NQL-CcW3H_cH.js → mindmap-definition-RKZ34NQL-ldyccyCP.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{pieDiagram-4H26LBE5-DpXUpJMl.js → pieDiagram-4H26LBE5-CmghofeF.js} +1 -1
- package/{dist/rcs-web/assets/quadrantDiagram-W4KKPZXB-DOwMRzzP.js → packages/remote-control-server/web/dist/assets/quadrantDiagram-W4KKPZXB-B-2N2UHr.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{requirementDiagram-4Y6WPE33-CBi_6NcW.js → requirementDiagram-4Y6WPE33-39jlO9Y8.js} +1 -1
- package/{dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-CKbAoTHm.js → packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-DdY7KNFB.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{sequenceDiagram-3UESZ5HK-a3rYCe-w.js → sequenceDiagram-3UESZ5HK-D2k5rX6x.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{stateDiagram-AJRCARHV-B6R_Dt84.js → stateDiagram-AJRCARHV-CP9N457o.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{stateDiagram-v2-BHNVJYJU-Cq935fvz.js → stateDiagram-v2-BHNVJYJU-CPhZYlL0.js} +1 -1
- package/{dist/rcs-web/assets/timeline-definition-PNZ67QCA-8DXPKq1k.js → packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-DSEPBO8O.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{vennDiagram-CIIHVFJN-BfDEkku5.js → vennDiagram-CIIHVFJN-CkNMwCJ3.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{wardleyDiagram-YWT4CUSO-Dvp2XZVf.js → wardleyDiagram-YWT4CUSO-Cxd-F60s.js} +1 -1
- package/{dist/rcs-web/assets/xychartDiagram-2RQKCTM6-DiPjQLUx.js → packages/remote-control-server/web/dist/assets/xychartDiagram-2RQKCTM6-BLL105NN.js} +1 -1
- package/packages/remote-control-server/web/dist/index.html +1 -1
- package/dist/rcs-web/assets/channel-CirgRB_G.js +0 -1
- package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-Cq12UEz9.js +0 -1
- package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-Cq12UEz9.js +0 -1
- package/packages/remote-control-server/web/dist/assets/channel-CirgRB_G.js +0 -1
- package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-Cq12UEz9.js +0 -1
- package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-Cq12UEz9.js +0 -1
|
@@ -7,6 +7,12 @@
|
|
|
7
7
|
* - v1 session-ingress (HybridTransport POST → ingestBridgeMessage)
|
|
8
8
|
* - v2 CCR worker events (POST /v1/code/sessions/:id/worker/events)
|
|
9
9
|
* Both must end the turn with a derived session_status event, status=idle.
|
|
10
|
+
*
|
|
11
|
+
* Also covers the inversion variant: the worker's bridge write paths are not
|
|
12
|
+
* strictly ordered, so the turn-end result can arrive BEFORE the final
|
|
13
|
+
* mirrored assistant message. A late assistant must NOT flip the session
|
|
14
|
+
* back to running (turn-signal guard, EventBus.turnActive) — that re-engaged
|
|
15
|
+
* the web UI input and left every subsequent message stuck in the queue.
|
|
10
16
|
*/
|
|
11
17
|
import { describe, test, expect, beforeEach, mock } from 'bun:test'
|
|
12
18
|
import { mockConfigModule } from './helpers/mock-config'
|
|
@@ -131,7 +137,23 @@ describe('turn end emits session_status idle (stuck-running regression)', () =>
|
|
|
131
137
|
expect(getSession(sessionId)?.status).toBe('idle')
|
|
132
138
|
})
|
|
133
139
|
|
|
134
|
-
test('v2 worker events: assistant → result derives running → idle', async () => {
|
|
140
|
+
test('v2 worker events: user → assistant → result derives running → idle', async () => {
|
|
141
|
+
// User message from the web UI starts the turn (turn-signal)
|
|
142
|
+
const res0 = await app.request(`/web/sessions/${sessionId}/events`, {
|
|
143
|
+
method: 'POST',
|
|
144
|
+
headers: {
|
|
145
|
+
Authorization: auth('user-1'),
|
|
146
|
+
'Content-Type': 'application/json',
|
|
147
|
+
},
|
|
148
|
+
body: JSON.stringify({
|
|
149
|
+
type: 'user',
|
|
150
|
+
uuid: 'v2-web-user-1',
|
|
151
|
+
content: 'hello',
|
|
152
|
+
message: { content: 'hello' },
|
|
153
|
+
}),
|
|
154
|
+
})
|
|
155
|
+
expect(res0.status).toBe(200)
|
|
156
|
+
|
|
135
157
|
// Assistant event marks the turn running
|
|
136
158
|
const res1 = await app.request(
|
|
137
159
|
`/v1/code/sessions/${sessionId}/worker/events`,
|
|
@@ -179,6 +201,200 @@ describe('turn end emits session_status idle (stuck-running regression)', () =>
|
|
|
179
201
|
expect(statuses[statuses.length - 1]).toBe('idle')
|
|
180
202
|
})
|
|
181
203
|
|
|
204
|
+
test('v1 session-ingress: REPL-initiated turn (mirrored user) derives running', async () => {
|
|
205
|
+
// A turn typed in the terminal REPL reaches the server via the
|
|
206
|
+
// transcript mirror: [user, assistant] in one writeBatch POST. The
|
|
207
|
+
// mirrored user message must arm the turn signal so the assistant
|
|
208
|
+
// event derives running.
|
|
209
|
+
const res = await app.request(
|
|
210
|
+
`/v2/session_ingress/session/${sessionId}/events`,
|
|
211
|
+
{
|
|
212
|
+
method: 'POST',
|
|
213
|
+
headers: { ...AUTH_HEADERS, 'Content-Type': 'application/json' },
|
|
214
|
+
body: JSON.stringify({
|
|
215
|
+
events: [
|
|
216
|
+
{
|
|
217
|
+
type: 'user',
|
|
218
|
+
uuid: 'repl-user-1',
|
|
219
|
+
message: { role: 'user', content: 'typed in terminal' },
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
type: 'assistant',
|
|
223
|
+
uuid: 'repl-asst-1',
|
|
224
|
+
message: {
|
|
225
|
+
role: 'assistant',
|
|
226
|
+
content: [{ type: 'text', text: 'terminal reply' }],
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
}),
|
|
231
|
+
},
|
|
232
|
+
)
|
|
233
|
+
expect(res.status).toBe(200)
|
|
234
|
+
expect(getSession(sessionId)?.status).toBe('running')
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
test('v1 session-ingress: late assistant after result does not resurrect running', async () => {
|
|
238
|
+
// Inversion regression: the REPL bridge POSTs the synthetic turn-end
|
|
239
|
+
// result BEFORE the final mirrored assistant message (transcript-mirror
|
|
240
|
+
// render race). The late assistant must not flip the session back to
|
|
241
|
+
// running — that left the web UI input engaged and queued every new
|
|
242
|
+
// message indefinitely.
|
|
243
|
+
await app.request(`/web/sessions/${sessionId}/events`, {
|
|
244
|
+
method: 'POST',
|
|
245
|
+
headers: {
|
|
246
|
+
Authorization: auth('user-1'),
|
|
247
|
+
'Content-Type': 'application/json',
|
|
248
|
+
},
|
|
249
|
+
body: JSON.stringify({
|
|
250
|
+
type: 'user',
|
|
251
|
+
uuid: 'inv-user-1',
|
|
252
|
+
content: 'hi',
|
|
253
|
+
message: { content: 'hi' },
|
|
254
|
+
}),
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
// Worker delivers result first, then the final assistant message
|
|
258
|
+
const res = await app.request(
|
|
259
|
+
`/v2/session_ingress/session/${sessionId}/events`,
|
|
260
|
+
{
|
|
261
|
+
method: 'POST',
|
|
262
|
+
headers: { ...AUTH_HEADERS, 'Content-Type': 'application/json' },
|
|
263
|
+
body: JSON.stringify({
|
|
264
|
+
events: [
|
|
265
|
+
{
|
|
266
|
+
type: 'result_success',
|
|
267
|
+
subtype: 'success',
|
|
268
|
+
uuid: 'inv-result-1',
|
|
269
|
+
result: '',
|
|
270
|
+
total_cost_usd: 0,
|
|
271
|
+
usage: {},
|
|
272
|
+
},
|
|
273
|
+
],
|
|
274
|
+
}),
|
|
275
|
+
},
|
|
276
|
+
)
|
|
277
|
+
expect(res.status).toBe(200)
|
|
278
|
+
expect(getSession(sessionId)?.status).toBe('idle')
|
|
279
|
+
|
|
280
|
+
const lateRes = await app.request(
|
|
281
|
+
`/v2/session_ingress/session/${sessionId}/events`,
|
|
282
|
+
{
|
|
283
|
+
method: 'POST',
|
|
284
|
+
headers: { ...AUTH_HEADERS, 'Content-Type': 'application/json' },
|
|
285
|
+
body: JSON.stringify({
|
|
286
|
+
events: [
|
|
287
|
+
{
|
|
288
|
+
type: 'assistant',
|
|
289
|
+
uuid: 'inv-asst-1',
|
|
290
|
+
message: {
|
|
291
|
+
role: 'assistant',
|
|
292
|
+
content: [{ type: 'text', text: 'Hello again!' }],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
],
|
|
296
|
+
}),
|
|
297
|
+
},
|
|
298
|
+
)
|
|
299
|
+
expect(lateRes.status).toBe(200)
|
|
300
|
+
expect(getSession(sessionId)?.status).toBe('idle')
|
|
301
|
+
|
|
302
|
+
const statuses = statusEvents(getEventBus(sessionId).getEventsSince(0))
|
|
303
|
+
expect(statuses[statuses.length - 1]).toBe('idle')
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
test('v2 worker events: late assistant after result does not resurrect running', async () => {
|
|
307
|
+
await app.request(`/web/sessions/${sessionId}/events`, {
|
|
308
|
+
method: 'POST',
|
|
309
|
+
headers: {
|
|
310
|
+
Authorization: auth('user-1'),
|
|
311
|
+
'Content-Type': 'application/json',
|
|
312
|
+
},
|
|
313
|
+
body: JSON.stringify({
|
|
314
|
+
type: 'user',
|
|
315
|
+
uuid: 'inv2-user-1',
|
|
316
|
+
content: 'hi',
|
|
317
|
+
message: { content: 'hi' },
|
|
318
|
+
}),
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
await app.request(`/v1/code/sessions/${sessionId}/worker/events`, {
|
|
322
|
+
method: 'POST',
|
|
323
|
+
headers: { ...AUTH_HEADERS, 'Content-Type': 'application/json' },
|
|
324
|
+
body: JSON.stringify([
|
|
325
|
+
{
|
|
326
|
+
type: 'result_success',
|
|
327
|
+
subtype: 'success',
|
|
328
|
+
uuid: 'inv2-result-1',
|
|
329
|
+
result: '',
|
|
330
|
+
},
|
|
331
|
+
]),
|
|
332
|
+
})
|
|
333
|
+
expect(getSession(sessionId)?.status).toBe('idle')
|
|
334
|
+
|
|
335
|
+
await app.request(`/v1/code/sessions/${sessionId}/worker/events`, {
|
|
336
|
+
method: 'POST',
|
|
337
|
+
headers: { ...AUTH_HEADERS, 'Content-Type': 'application/json' },
|
|
338
|
+
body: JSON.stringify([
|
|
339
|
+
{
|
|
340
|
+
type: 'assistant',
|
|
341
|
+
uuid: 'inv2-asst-1',
|
|
342
|
+
message: {
|
|
343
|
+
role: 'assistant',
|
|
344
|
+
content: [{ type: 'text', text: 'late mirror' }],
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
]),
|
|
348
|
+
})
|
|
349
|
+
expect(getSession(sessionId)?.status).toBe('idle')
|
|
350
|
+
|
|
351
|
+
const statuses = statusEvents(getEventBus(sessionId).getEventsSince(0))
|
|
352
|
+
expect(statuses[statuses.length - 1]).toBe('idle')
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
test('interrupt ends the turn: late assistant does not resurrect running', async () => {
|
|
356
|
+
await app.request(`/web/sessions/${sessionId}/events`, {
|
|
357
|
+
method: 'POST',
|
|
358
|
+
headers: {
|
|
359
|
+
Authorization: auth('user-1'),
|
|
360
|
+
'Content-Type': 'application/json',
|
|
361
|
+
},
|
|
362
|
+
body: JSON.stringify({
|
|
363
|
+
type: 'user',
|
|
364
|
+
uuid: 'intr-user-1',
|
|
365
|
+
content: 'work',
|
|
366
|
+
message: { content: 'work' },
|
|
367
|
+
}),
|
|
368
|
+
})
|
|
369
|
+
expect(getSession(sessionId)?.status).toBe('running')
|
|
370
|
+
|
|
371
|
+
await app.request(`/web/sessions/${sessionId}/interrupt`, {
|
|
372
|
+
method: 'POST',
|
|
373
|
+
headers: { Authorization: auth('user-1') },
|
|
374
|
+
})
|
|
375
|
+
expect(getSession(sessionId)?.status).toBe('idle')
|
|
376
|
+
|
|
377
|
+
// A mirrored assistant message that was still in flight when the user
|
|
378
|
+
// hit Stop arrives after the interrupt — must not re-engage running.
|
|
379
|
+
await app.request(`/v2/session_ingress/session/${sessionId}/events`, {
|
|
380
|
+
method: 'POST',
|
|
381
|
+
headers: { ...AUTH_HEADERS, 'Content-Type': 'application/json' },
|
|
382
|
+
body: JSON.stringify({
|
|
383
|
+
events: [
|
|
384
|
+
{
|
|
385
|
+
type: 'assistant',
|
|
386
|
+
uuid: 'intr-asst-1',
|
|
387
|
+
message: {
|
|
388
|
+
role: 'assistant',
|
|
389
|
+
content: [{ type: 'text', text: 'partial reply' }],
|
|
390
|
+
},
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
}),
|
|
394
|
+
})
|
|
395
|
+
expect(getSession(sessionId)?.status).toBe('idle')
|
|
396
|
+
})
|
|
397
|
+
|
|
182
398
|
test('v2 worker events: control_request derives requires_action', async () => {
|
|
183
399
|
const res = await app.request(
|
|
184
400
|
`/v1/code/sessions/${sessionId}/worker/events`,
|
|
@@ -77,12 +77,23 @@ app.post(
|
|
|
77
77
|
// state uploads leaves the session stuck on 'running', so the web UI
|
|
78
78
|
// input never leaves the running state and every new message lands
|
|
79
79
|
// in the queue instead of being sent.
|
|
80
|
+
//
|
|
81
|
+
// Turn-signal accounting (EventBus.turnActive): the worker's write
|
|
82
|
+
// paths are not strictly ordered — the turn-end result can reach the
|
|
83
|
+
// server BEFORE the final assistant message. A late assistant must
|
|
84
|
+
// not flip the session back to running after the turn ended.
|
|
85
|
+
const bus = getEventBus(sessionId)
|
|
86
|
+
if (eventType === 'user') {
|
|
87
|
+
bus.turnActive = true
|
|
88
|
+
} else if (eventType === 'result' || eventType === 'result_success') {
|
|
89
|
+
bus.turnActive = false
|
|
90
|
+
}
|
|
80
91
|
const targetStatus =
|
|
81
92
|
eventType === 'result' || eventType === 'result_success'
|
|
82
93
|
? 'idle'
|
|
83
94
|
: eventType === 'control_request'
|
|
84
95
|
? 'requires_action'
|
|
85
|
-
: eventType === 'assistant'
|
|
96
|
+
: eventType === 'assistant' && bus.turnActive
|
|
86
97
|
? 'running'
|
|
87
98
|
: null
|
|
88
99
|
if (targetStatus) {
|
|
@@ -75,8 +75,14 @@ app.post('/sessions/:id/events', sessionAuth, async c => {
|
|
|
75
75
|
// (ws-handler.ts ingestBridgeMessage) marks it idle again. Skip when the
|
|
76
76
|
// session is already running so repeated user messages don't spam
|
|
77
77
|
// session_status events.
|
|
78
|
-
if (eventType === 'user'
|
|
79
|
-
|
|
78
|
+
if (eventType === 'user') {
|
|
79
|
+
// Turn-signal (EventBus.turnActive): a user message starts a turn —
|
|
80
|
+
// later assistant events of this turn may derive `running` (see
|
|
81
|
+
// ws-handler.ts).
|
|
82
|
+
getEventBus(sessionId).turnActive = true
|
|
83
|
+
if (getSession(sessionId)?.status !== 'running') {
|
|
84
|
+
updateSessionStatus(sessionId, 'running')
|
|
85
|
+
}
|
|
80
86
|
}
|
|
81
87
|
log(
|
|
82
88
|
`[RC-DEBUG] web -> server: published outbound event id=${event.id} type=${event.type} direction=${event.direction} subscribers=${getEventBus(sessionId).subscriberCount()}`,
|
|
@@ -134,6 +140,9 @@ app.post('/sessions/:id/interrupt', sessionAuth, async c => {
|
|
|
134
140
|
{ action: 'interrupt' },
|
|
135
141
|
'outbound',
|
|
136
142
|
)
|
|
143
|
+
// Interrupt ends the turn — a late mirrored assistant message must not
|
|
144
|
+
// flip the session back to running (EventBus.turnActive, see ws-handler.ts).
|
|
145
|
+
getEventBus(sessionId).turnActive = false
|
|
137
146
|
updateSessionStatus(sessionId, 'idle')
|
|
138
147
|
return c.json({ status: 'ok' }, 200)
|
|
139
148
|
})
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
import { createWorkItem, stopWork } from '../../services/work-dispatch'
|
|
35
35
|
import { createSSEStream } from '../../transport/sse-writer'
|
|
36
36
|
import { getEventBus } from '../../transport/event-bus'
|
|
37
|
+
import { publishSessionEvent } from '../../services/transport'
|
|
37
38
|
|
|
38
39
|
const app = new Hono()
|
|
39
40
|
|
|
@@ -286,6 +287,26 @@ app.get('/sessions/:id/history', sessionAuth, async c => {
|
|
|
286
287
|
const events = [...byId.values()].sort(
|
|
287
288
|
(a, b) => a.createdAt - b.createdAt || a.seqNum - b.seqNum,
|
|
288
289
|
)
|
|
290
|
+
// models_state fallback: the worker reports the model list once per bridge
|
|
291
|
+
// connect, so the event log can legitimately lack it (/clear before the
|
|
292
|
+
// re-seed existed, event-window eviction, pre-persistence servers). The
|
|
293
|
+
// bus keeps the latest snapshot out-of-band — merge it here so the web UI
|
|
294
|
+
// can restore the model selector on every re-entry.
|
|
295
|
+
if (!events.some(e => e.type === 'models_state')) {
|
|
296
|
+
const snapshot = getEventBus(sessionId).modelsStateSnapshot
|
|
297
|
+
if (snapshot) {
|
|
298
|
+
const lastCreated = events[events.length - 1]?.createdAt ?? Date.now()
|
|
299
|
+
events.push({
|
|
300
|
+
id: `models_state_snapshot_${sessionId}`,
|
|
301
|
+
sessionId,
|
|
302
|
+
seqNum: 0,
|
|
303
|
+
type: 'models_state',
|
|
304
|
+
payload: { models_state: snapshot },
|
|
305
|
+
direction: 'inbound',
|
|
306
|
+
createdAt: lastCreated + 1,
|
|
307
|
+
})
|
|
308
|
+
}
|
|
309
|
+
}
|
|
289
310
|
return c.json({ events }, 200)
|
|
290
311
|
})
|
|
291
312
|
|
|
@@ -344,6 +365,18 @@ app.post('/sessions/:id/clear', sessionAuth, async c => {
|
|
|
344
365
|
},
|
|
345
366
|
{ transient: true },
|
|
346
367
|
)
|
|
368
|
+
// Re-seed models_state from the bus snapshot. The worker only reports
|
|
369
|
+
// models_state once per bridge connect, so a plain history wipe would make
|
|
370
|
+
// the model selector permanently gray after re-entering the session (and
|
|
371
|
+
// /model would report "未提供模型选择能力") until the worker reconnects.
|
|
372
|
+
if (bus.modelsStateSnapshot) {
|
|
373
|
+
publishSessionEvent(
|
|
374
|
+
sessionId,
|
|
375
|
+
'models_state',
|
|
376
|
+
{ type: 'models_state', models_state: bus.modelsStateSnapshot },
|
|
377
|
+
'inbound',
|
|
378
|
+
)
|
|
379
|
+
}
|
|
347
380
|
log(`[RCS] Cleared conversation history for session ${sessionId}`)
|
|
348
381
|
return c.json({ status: 'ok' }, 200)
|
|
349
382
|
})
|
|
@@ -169,6 +169,18 @@ export function publishSessionEvent(
|
|
|
169
169
|
const bus = getEventBus(sessionId)
|
|
170
170
|
const eventId = randomUUID()
|
|
171
171
|
|
|
172
|
+
// models_state is a one-shot snapshot from the worker (sent on bridge
|
|
173
|
+
// connect, never re-sent during the worker's lifetime). Keep the latest
|
|
174
|
+
// payload on the bus so /clear re-seeding and /history fallback can
|
|
175
|
+
// restore the web UI's model selector even after the event log lost the
|
|
176
|
+
// original entry.
|
|
177
|
+
if (type === 'models_state' && payload && typeof payload === 'object') {
|
|
178
|
+
const state = (payload as Record<string, unknown>).models_state
|
|
179
|
+
if (state && typeof state === 'object') {
|
|
180
|
+
bus.modelsStateSnapshot = state as Record<string, unknown>
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
172
184
|
const normalized = normalizePayload(type, payload)
|
|
173
185
|
const transient = TRANSIENT_EVENT_TYPES.has(type)
|
|
174
186
|
|
|
@@ -30,6 +30,31 @@ export class EventBus {
|
|
|
30
30
|
MAX_SEEN_UUIDS_PER_BUS,
|
|
31
31
|
)
|
|
32
32
|
private seenUuidWriteIdx = 0
|
|
33
|
+
/**
|
|
34
|
+
* Latest models_state payload for the session, kept OUT of the retained
|
|
35
|
+
* event window. The worker reports models_state only once per bridge
|
|
36
|
+
* connect, while the event log is mutable (/clear wipes it, the bounded
|
|
37
|
+
* window evicts old entries) — without this snapshot any log loss makes
|
|
38
|
+
* the web UI's model selector permanently gray until the worker
|
|
39
|
+
* reconnects. Lives on the bus so it is dropped when the session is
|
|
40
|
+
* deleted (removeEventBus) and survives clearHistory().
|
|
41
|
+
*/
|
|
42
|
+
modelsStateSnapshot: Record<string, unknown> | null = null
|
|
43
|
+
/**
|
|
44
|
+
* Turn-signal for status derivation (ws-handler.ts / worker-events.ts /
|
|
45
|
+
* control.ts): `true` while a turn is in progress (set by user events),
|
|
46
|
+
* `false` once it ends (result / result_success / interrupt).
|
|
47
|
+
*
|
|
48
|
+
* The REPL bridge's write paths are not strictly ordered — the synthetic
|
|
49
|
+
* turn-end result can be POSTed BEFORE the final mirrored assistant
|
|
50
|
+
* message (transcript-mirror render race, flush-gate bypass). Deriving
|
|
51
|
+
* `running` from such a late assistant flips the session back to running
|
|
52
|
+
* AFTER the turn ended, so the web UI input stays engaged and every new
|
|
53
|
+
* message lands in the queue instead of being sent. `false` by default:
|
|
54
|
+
* an assistant arriving with no user signal in flight belongs to an
|
|
55
|
+
* already-ended turn.
|
|
56
|
+
*/
|
|
57
|
+
turnActive = false
|
|
33
58
|
|
|
34
59
|
subscribe(callback: Subscriber): () => void {
|
|
35
60
|
this.subscribers.add(callback)
|
|
@@ -342,13 +342,26 @@ export function ingestBridgeMessage(
|
|
|
342
342
|
// assistant → running (LLM streaming). Skip when the session isn't in the
|
|
343
343
|
// store (test fixtures) or status is already the target so streaming
|
|
344
344
|
// assistant chunks don't spam session_status events.
|
|
345
|
+
//
|
|
346
|
+
// Turn-signal accounting (EventBus.turnActive): the REPL bridge can POST
|
|
347
|
+
// the synthetic turn-end result BEFORE the final mirrored assistant
|
|
348
|
+
// message (transcript-mirror render race in useReplBridge / flush-gate
|
|
349
|
+
// bypass in replBridge.writeMessages). A late assistant must not flip
|
|
350
|
+
// the session back to running after the turn ended — the web UI input
|
|
351
|
+
// would re-engage and every new message would land in the queue.
|
|
352
|
+
const bus = getEventBus(sessionId)
|
|
353
|
+
if (eventType === 'user') {
|
|
354
|
+
bus.turnActive = true
|
|
355
|
+
} else if (eventType === 'result' || eventType === 'result_success') {
|
|
356
|
+
bus.turnActive = false
|
|
357
|
+
}
|
|
345
358
|
const session = getSession(sessionId)
|
|
346
359
|
const targetStatus =
|
|
347
360
|
eventType === 'result' || eventType === 'result_success'
|
|
348
361
|
? 'idle'
|
|
349
362
|
: eventType === 'control_request'
|
|
350
363
|
? 'requires_action'
|
|
351
|
-
: eventType === 'assistant'
|
|
364
|
+
: eventType === 'assistant' && bus.turnActive
|
|
352
365
|
? 'running'
|
|
353
366
|
: null
|
|
354
367
|
if (session && targetStatus && session.status !== targetStatus) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{e as d,j as e}from"./vendor-DE_-CLIE.js";import{ak as c,al as o,J as m,af as s,a8 as l,x as u}from"./main-
|
|
1
|
+
import{e as d,j as e}from"./vendor-DE_-CLIE.js";import{ak as c,al as o,J as m,af as s,a8 as l,x as u}from"./main-N3GYCdLF.js";import"./shiki-mEP5vQQu.js";import"./motion-BILbV7YQ.js";function j(){c();const[a,i]=d.useState([]),{myTeams:r,isLoading:x}=o(),n=d.useCallback(async()=>{try{const t=await m();i(t||[])}catch(t){console.error("Admin: failed to load sessions",t)}},[]);return d.useEffect(()=>{n()},[n]),e.jsx("div",{className:"flex-1 overflow-y-auto",children:e.jsxs("div",{className:"mx-auto max-w-5xl px-4 py-8",children:[e.jsx("h1",{className:"mb-6 font-display text-2xl font-semibold text-text-primary",children:s("admin.title")}),e.jsxs("section",{className:"mb-10",children:[e.jsxs("h2",{className:"mb-4 font-display text-lg font-semibold text-text-primary",children:[s("admin.teams")," (",r.length,")"]}),x?e.jsx("div",{className:"rounded-xl border border-border bg-surface-1 p-4 text-center text-text-muted",children:s("common.loading")}):r.length===0?e.jsx("div",{className:"rounded-xl border border-border bg-surface-1 p-4 text-center text-text-muted",children:s("admin.noTeams")}):e.jsx("div",{className:"space-y-2",children:r.map(t=>e.jsxs("a",{href:`/teams/${t.slug}`,className:"flex items-center justify-between rounded-xl border border-border bg-surface-1 px-4 py-3 no-underline transition-colors hover:border-border-light hover:bg-surface-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("span",{className:"font-medium text-text-primary",children:t.name}),e.jsx("span",{className:"ml-2 text-xs text-text-muted",children:t.slug})]}),e.jsx("span",{className:"text-xs text-text-muted",children:l(new Date(t.created_at).getTime()/1e3)})]},t.id))})]}),e.jsxs("section",{children:[e.jsxs("h2",{className:"mb-4 font-display text-lg font-semibold text-text-primary",children:[s("admin.sessions")," (",a.length,")"]}),a.length===0?e.jsx("div",{className:"rounded-xl border border-border bg-surface-1 p-4 text-center text-text-muted",children:s("admin.noSessions")}):e.jsx("div",{className:"space-y-2",children:a.map(t=>e.jsxs("a",{href:`/code/${t.id}`,className:"flex items-center justify-between rounded-xl border border-border bg-surface-1 px-4 py-3 no-underline transition-colors hover:border-border-light hover:bg-surface-2",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"truncate font-medium text-text-primary",children:t.title||t.id}),e.jsx("span",{className:"rounded-full bg-surface-2 px-2 py-0.5 text-xs text-text-muted",children:t.source||"unknown"})]}),e.jsx("div",{className:"truncate text-xs text-text-muted",children:t.id})]}),e.jsxs("div",{className:"ml-4 flex items-center gap-3",children:[e.jsx(u,{status:t.status}),e.jsx("span",{className:"text-xs text-text-muted",children:l(t.updated_at||t.created_at)})]})]},t.id))})]})]})})}export{j as AdminPanel};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{e as r,j as e}from"./vendor-DE_-CLIE.js";import{E as u,J as f}from"./main-
|
|
1
|
+
import{e as r,j as e}from"./vendor-DE_-CLIE.js";import{E as u,J as f}from"./main-N3GYCdLF.js";import"./shiki-mEP5vQQu.js";import"./motion-BILbV7YQ.js";const v=2e3,N=3e4;function E(){const c=window.location.pathname.split("/"),i=c[c.length-1]||"",[s,n]=r.useState("idle"),[m,l]=r.useState(null),[a,d]=r.useState(null);return r.useEffect(()=>{if(!i||!i.startsWith("clm_")){l("Invalid claim token"),n("error");return}n("claiming"),u(i).then(t=>{d(t.environment_id),n("waiting")}).catch(t=>{l(t instanceof Error?t.message:"Claim failed"),n("error")})},[i]),r.useEffect(()=>{if(s!=="waiting"||!a)return;let t=!1;const x=Date.now(),o=setInterval(()=>{if(Date.now()-x>N){clearInterval(o),t||n("timeout");return}f().then(h=>{t||(h||[]).some(p=>p.environment_id===a)&&(clearInterval(o),window.location.href="/code/")}).catch(()=>{})},v);return()=>{t=!0,clearInterval(o)}},[s,a]),s==="claiming"?e.jsx("div",{className:"px-6 py-16 sm:px-10 sm:py-20",children:e.jsx("p",{className:"text-sm text-text-muted",children:"Claiming environment..."})}):s==="error"?e.jsxs("div",{className:"px-6 py-16 sm:px-10 sm:py-20",children:[e.jsx("p",{className:"text-sm text-destructive",children:m}),e.jsx("a",{href:"/code",className:"mt-4 inline-block text-accent hover:underline",children:"Back to dashboard"})]}):s==="waiting"||s==="timeout"?e.jsxs("div",{className:"px-6 py-16 sm:px-10 sm:py-20",children:[e.jsxs("header",{className:"mb-10",children:[e.jsx("h1",{className:"font-display text-2xl font-semibold tracking-tight text-text-primary",children:"Environment claimed"}),e.jsx("p",{className:"mt-2 text-sm text-text-muted",children:"You are now the owner of this environment."})]}),e.jsxs("div",{className:"space-y-4",children:[a&&e.jsx("p",{className:"font-mono text-xs text-text-muted",children:a}),s==="waiting"?e.jsxs("p",{className:"text-sm text-text-muted",children:["Waiting for the worker to create a session",e.jsx("span",{className:"animate-pulse",children:"…"})]}):e.jsx("p",{className:"text-sm text-text-muted",children:"The worker has not created a session yet — it may be offline or stopped. The session will appear on the dashboard once the worker connects."}),e.jsx("a",{href:"/code",className:"inline-block rounded-md bg-accent px-4 py-2 text-sm font-medium text-white hover:bg-accent/90 transition-colors",children:"Go to dashboard"})]})]}):e.jsx("div",{className:"px-6 py-16 sm:px-10 sm:py-20",children:e.jsx("p",{className:"text-sm text-text-muted",children:"Claiming environment..."})})}export{E as Claim};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{j as e,e as o}from"./vendor-DE_-CLIE.js";import{a5 as O,a4 as _,al as E,aj as T,x as F,ak as L,af as a,a8 as A,q as $,s as W,e as H,r as V,d as P,ab as q,G,J,K,I as R}from"./main-
|
|
1
|
+
import{j as e,e as o}from"./vendor-DE_-CLIE.js";import{a5 as O,a4 as _,al as E,aj as T,x as F,ak as L,af as a,a8 as A,q as $,s as W,e as H,r as V,d as P,ab as q,G,J,K,I as R}from"./main-N3GYCdLF.js";import{g as D}from"./workerType-Bd-zteMi.js";import{S as U,D as Z,a as z,c as Q,d as X,b as Y}from"./SessionVisibilityBadge-91WyR9K6.js";import"./shiki-mEP5vQQu.js";import"./motion-BILbV7YQ.js";/**
|
|
2
2
|
* @license lucide-react v0.555.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{e as r,j as e}from"./vendor-DE_-CLIE.js";import{aj as v,af as t}from"./main-
|
|
1
|
+
import{e as r,j as e}from"./vendor-DE_-CLIE.js";import{aj as v,af as t}from"./main-N3GYCdLF.js";import"./shiki-mEP5vQQu.js";import"./motion-BILbV7YQ.js";function E({onSuccess:b,onInvalidInvite:l}){const{join:f}=v(),[u,h]=r.useState(""),[d,j]=r.useState(""),[o,w]=r.useState(""),[c,g]=r.useState(""),[m,n]=r.useState(""),[x,p]=r.useState(!1);r.useEffect(()=>{const a=new URLSearchParams(window.location.search).get("invite");a?h(a):l()},[l]);const y=async s=>{if(s.preventDefault(),n(""),o.length<8){n(t("auth.setup.passwordTooShort"));return}if(o!==c){n(t("auth.setup.passwordMismatch"));return}p(!0);try{await f(u,d,o),b()}catch(a){const i=a instanceof Error?a.message:"Join failed";if(i.includes("Invalid invitation")||i.includes("expired")||i.includes("already used")){l();return}n(i)}finally{p(!1)}};return e.jsx("div",{className:"flex min-h-screen items-center justify-center bg-surface-0 px-4",children:e.jsxs("div",{className:"w-full max-w-sm space-y-6",children:[e.jsxs("div",{className:"text-center",children:[e.jsx("h1",{className:"font-display text-2xl font-semibold text-text-primary",children:t("auth.join.title")}),e.jsx("p",{className:"mt-2 text-sm text-text-muted",children:t("auth.join.welcome")}),e.jsx("p",{className:"mt-1 text-sm text-text-muted",children:t("auth.join.description")})]}),e.jsxs("form",{onSubmit:y,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-sm font-medium text-text-secondary",children:t("auth.join.username")}),e.jsx("input",{type:"text",value:d,onChange:s=>j(s.target.value),required:!0,autoComplete:"username",autoFocus:!0,className:"w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:border-brand focus:outline-none"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-sm font-medium text-text-secondary",children:t("auth.join.password")}),e.jsx("input",{type:"password",value:o,onChange:s=>w(s.target.value),required:!0,autoComplete:"new-password",className:"w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:border-brand focus:outline-none"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-sm font-medium text-text-secondary",children:t("auth.join.confirmPassword")}),e.jsx("input",{type:"password",value:c,onChange:s=>g(s.target.value),required:!0,autoComplete:"new-password",className:"w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:border-brand focus:outline-none"})]}),m&&e.jsx("p",{className:"text-sm text-status-error",children:m}),e.jsx("button",{type:"submit",disabled:x||!u,className:"w-full rounded-lg bg-brand px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-brand-light disabled:cursor-not-allowed disabled:opacity-50",children:x?t("common.loading"):t("auth.join.submit")})]})]})})}export{E as Join};
|
package/packages/remote-control-server/web/dist/assets/{Login-5qo97rq-.js → Login-JprQIEpr.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{e as r,j as e}from"./vendor-DE_-CLIE.js";import{aj as f,af as t}from"./main-
|
|
1
|
+
import{e as r,j as e}from"./vendor-DE_-CLIE.js";import{aj as f,af as t}from"./main-N3GYCdLF.js";import"./shiki-mEP5vQQu.js";import"./motion-BILbV7YQ.js";function N({onSuccess:d,onNavigateRegister:c}){const{login:m,registrationAllowed:x}=f(),[a,p]=r.useState(""),[o,b]=r.useState(""),[l,n]=r.useState(""),[i,u]=r.useState(!1),h=async s=>{s.preventDefault(),n(""),u(!0);try{await m(a,o),d()}catch{n(t("auth.login.failed"))}finally{u(!1)}};return e.jsx("div",{className:"flex min-h-screen items-center justify-center bg-surface-0 px-4",children:e.jsxs("div",{className:"w-full max-w-sm space-y-6",children:[e.jsxs("div",{className:"text-center",children:[e.jsx("h1",{className:"font-display text-2xl font-semibold text-text-primary",children:t("auth.login.title")}),e.jsx("p",{className:"mt-2 text-sm text-text-muted",children:t("auth.login.description")})]}),e.jsxs("form",{onSubmit:h,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-sm font-medium text-text-secondary",children:t("auth.login.username")}),e.jsx("input",{type:"text",value:a,onChange:s=>p(s.target.value),required:!0,autoComplete:"username",autoFocus:!0,className:"w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:border-brand focus:outline-none"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-sm font-medium text-text-secondary",children:t("auth.login.password")}),e.jsx("input",{type:"password",value:o,onChange:s=>b(s.target.value),required:!0,autoComplete:"current-password",className:"w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:border-brand focus:outline-none"})]}),l&&e.jsx("p",{className:"text-sm text-status-error",children:l}),e.jsx("button",{type:"submit",disabled:i,className:"w-full rounded-lg bg-brand px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-brand-light disabled:cursor-not-allowed disabled:opacity-50",children:i?t("common.loading"):t("auth.login.submit")})]}),x&&e.jsx("button",{type:"button",onClick:c,className:"w-full text-center text-sm text-text-muted hover:text-text-primary transition-colors",children:t("auth.login.register")})]})})}export{N as Login};
|
package/packages/remote-control-server/web/dist/assets/{Register-D_UOG8ar.js → Register-cuGuAE83.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{e as r,j as e}from"./vendor-DE_-CLIE.js";import{aj as y,af as t}from"./main-
|
|
1
|
+
import{e as r,j as e}from"./vendor-DE_-CLIE.js";import{aj as y,af as t}from"./main-N3GYCdLF.js";import"./shiki-mEP5vQQu.js";import"./motion-BILbV7YQ.js";function S({onSuccess:m,onBack:x}){const{register:p}=y(),[n,b]=r.useState(""),[a,h]=r.useState(""),[l,f]=r.useState(""),[i,o]=r.useState(""),[u,d]=r.useState(!1),g=async s=>{if(s.preventDefault(),o(""),a.length<8){o(t("auth.setup.passwordTooShort"));return}if(a!==l){o(t("auth.setup.passwordMismatch"));return}d(!0);try{await p(n,a),m()}catch(c){o(c instanceof Error?c.message:t("auth.register.failed"))}finally{d(!1)}};return e.jsx("div",{className:"flex min-h-screen items-center justify-center bg-surface-0 px-4",children:e.jsxs("div",{className:"w-full max-w-sm space-y-6",children:[e.jsxs("div",{className:"text-center",children:[e.jsx("h1",{className:"font-display text-2xl font-semibold text-text-primary",children:t("auth.register.title")}),e.jsx("p",{className:"mt-2 text-sm text-text-muted",children:t("auth.register.description")})]}),e.jsxs("form",{onSubmit:g,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-sm font-medium text-text-secondary",children:t("auth.login.username")}),e.jsx("input",{type:"text",value:n,onChange:s=>b(s.target.value),required:!0,autoComplete:"username",autoFocus:!0,className:"w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:border-brand focus:outline-none"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-sm font-medium text-text-secondary",children:t("auth.login.password")}),e.jsx("input",{type:"password",value:a,onChange:s=>h(s.target.value),required:!0,autoComplete:"new-password",className:"w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:border-brand focus:outline-none"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-sm font-medium text-text-secondary",children:t("auth.join.confirmPassword")}),e.jsx("input",{type:"password",value:l,onChange:s=>f(s.target.value),required:!0,autoComplete:"new-password",className:"w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus:border-brand focus:outline-none"})]}),i&&e.jsx("p",{className:"text-sm text-status-error",children:i}),e.jsx("button",{type:"submit",disabled:u,className:"w-full rounded-lg bg-brand px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-brand-light disabled:cursor-not-allowed disabled:opacity-50",children:u?t("common.loading"):t("auth.register.submit")})]}),e.jsx("button",{type:"button",onClick:x,className:"w-full text-center text-sm text-text-muted hover:text-text-primary transition-colors",children:t("auth.register.backToLogin")})]})})}export{S as Register};
|