@saluzi/saluzi-edu 0.2.59 → 0.2.61
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 +362 -120
- package/dist/guide/guide-data.json +5 -1
- package/dist/parade/web/cube.js +403 -81
- package/dist/parade/web/index.html +172 -41
- package/dist/parade/web/menu.html +195 -0
- package/dist/rcs-web/assets/{AdminPanel-CbcZ7Vnr.js → AdminPanel-Xlza8Stt.js} +1 -1
- package/dist/rcs-web/assets/Claim-BMWwu213.js +1 -0
- package/{packages/remote-control-server/web/dist/assets/Dashboard-BZGcSCFY.js → dist/rcs-web/assets/Dashboard-D5awDzM3.js} +2 -2
- package/{packages/remote-control-server/web/dist/assets/Join-B_e3BKa3.js → dist/rcs-web/assets/Join-ok37ggfZ.js} +1 -1
- package/dist/rcs-web/assets/{Login-u6CGGkoD.js → Login-5qo97rq-.js} +1 -1
- package/dist/rcs-web/assets/{Register-C4Fk0ibc.js → Register-D_UOG8ar.js} +1 -1
- package/dist/rcs-web/assets/SessionDetail-BbHrR4Qu.js +65 -0
- package/dist/rcs-web/assets/{SessionVisibilityBadge-BHKxlh8U.js → SessionVisibilityBadge-Dy4FwTzo.js} +1 -1
- package/dist/rcs-web/assets/{Setup-DReCE0zx.js → Setup-GnPeNyH9.js} +1 -1
- package/dist/rcs-web/assets/{ShareLanding-qE1U0WKZ.js → ShareLanding-CUjQydLL.js} +1 -1
- package/dist/rcs-web/assets/{TeamCreate-BgwgZP4a.js → TeamCreate-Ck2fEoUW.js} +1 -1
- package/dist/rcs-web/assets/{TeamDetail-BHCvnI2t.js → TeamDetail-De6EPND0.js} +2 -2
- package/dist/rcs-web/assets/{TeamList-B7uC8lDV.js → TeamList-C-0LJRxd.js} +1 -1
- package/dist/rcs-web/assets/{TeamSettings-DtgvrKEE.js → TeamSettings-BszOrXVW.js} +1 -1
- package/dist/rcs-web/assets/{UserSearchInput-dgxhGWfJ.js → UserSearchInput-CyQWtLL-.js} +1 -1
- package/dist/rcs-web/assets/{UserSettings-Zyjam23-.js → UserSettings-DgyYp-1y.js} +1 -1
- package/dist/rcs-web/assets/{arc-DgC_wPAg.js → arc-BaOPt7k-.js} +1 -1
- package/dist/rcs-web/assets/{architectureDiagram-3BPJPVTR-BnnCRJZs.js → architectureDiagram-3BPJPVTR-SvIakXbT.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/blockDiagram-GPEHLZMM-CvpYdvcP.js → dist/rcs-web/assets/blockDiagram-GPEHLZMM-CiDp9J7i.js} +1 -1
- package/dist/rcs-web/assets/{c4Diagram-AAUBKEIU-DNK__-3d.js → c4Diagram-AAUBKEIU-D9wzA9ur.js} +1 -1
- package/dist/rcs-web/assets/channel-CirgRB_G.js +1 -0
- package/dist/rcs-web/assets/{chunk-2J33WTMH-5JQBz2na.js → chunk-2J33WTMH-qfYueRAP.js} +1 -1
- package/dist/rcs-web/assets/{chunk-4BX2VUAB-YJh8d73x.js → chunk-4BX2VUAB-D1V_UCiK.js} +1 -1
- package/dist/rcs-web/assets/{chunk-55IACEB6-U5c5GQZN.js → chunk-55IACEB6-C67QiGmo.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/chunk-727SXJPM-ifGCid_3.js → dist/rcs-web/assets/chunk-727SXJPM-D2Wln4TT.js} +1 -1
- package/dist/rcs-web/assets/{chunk-AQP2D5EJ-DxqPH2_Q.js → chunk-AQP2D5EJ-03h8hZhw.js} +1 -1
- package/dist/rcs-web/assets/{chunk-FMBD7UC4-dDtjQRPo.js → chunk-FMBD7UC4-7zas8pDp.js} +1 -1
- package/dist/rcs-web/assets/{chunk-ND2GUHAM-0UF6vhhE.js → chunk-ND2GUHAM-PUXucyY6.js} +1 -1
- package/dist/rcs-web/assets/{chunk-QZHKN3VN-CfZ4xcBz.js → chunk-QZHKN3VN-M3U5l4yW.js} +1 -1
- package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-Cq12UEz9.js +1 -0
- package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-Cq12UEz9.js +1 -0
- package/dist/rcs-web/assets/{code-block-IT6T5CEO-B4B0UrXo.js → code-block-IT6T5CEO-BgUazuuS.js} +1 -1
- package/dist/rcs-web/assets/{copy-_OW0eGyp.js → copy-DjaSB1Rw.js} +1 -1
- package/dist/rcs-web/assets/{cose-bilkent-S5V4N54A-B19xQvnh.js → cose-bilkent-S5V4N54A-zPupX74N.js} +1 -1
- package/dist/rcs-web/assets/{dagre-BM42HDAG-5JJnjI1B.js → dagre-BM42HDAG-B_EJ050J.js} +1 -1
- package/dist/rcs-web/assets/{diagram-2AECGRRQ-BY2NR7vr.js → diagram-2AECGRRQ-dnnxPH7w.js} +1 -1
- package/dist/rcs-web/assets/{diagram-5GNKFQAL-3zC3GraP.js → diagram-5GNKFQAL-CLEOqCLZ.js} +1 -1
- package/dist/rcs-web/assets/{diagram-KO2AKTUF-T1Jt5zH3.js → diagram-KO2AKTUF-DKBGpiRW.js} +1 -1
- package/dist/rcs-web/assets/{diagram-LMA3HP47-ehrkQG1e.js → diagram-LMA3HP47-BAilhXiA.js} +1 -1
- package/dist/rcs-web/assets/{diagram-OG6HWLK6-D8ZJlGs0.js → diagram-OG6HWLK6-C3CdmOxC.js} +1 -1
- package/dist/rcs-web/assets/{erDiagram-TEJ5UH35-Ckn1pY7G.js → erDiagram-TEJ5UH35-D1yv-3Jv.js} +1 -1
- package/dist/rcs-web/assets/{flowDiagram-I6XJVG4X-C1xnAOfH.js → flowDiagram-I6XJVG4X-DpW11XWj.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/ganttDiagram-6RSMTGT7-Dw8qOfCT.js → dist/rcs-web/assets/ganttDiagram-6RSMTGT7-CWr8suZm.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/gitGraphDiagram-PVQCEYII-Cg3La45a.js → dist/rcs-web/assets/gitGraphDiagram-PVQCEYII-BspxLSNV.js} +1 -1
- package/dist/rcs-web/assets/{infoDiagram-5YYISTIA-CGH2aXpd.js → infoDiagram-5YYISTIA-Bow20s-Q.js} +1 -1
- package/dist/rcs-web/assets/{ishikawaDiagram-YF4QCWOH-x89F9Igr.js → ishikawaDiagram-YF4QCWOH-BESvGYGI.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/journeyDiagram-JHISSGLW-Ckd_pKi0.js → dist/rcs-web/assets/journeyDiagram-JHISSGLW-DZ6gzC7H.js} +1 -1
- package/dist/rcs-web/assets/{kanban-definition-UN3LZRKU-D2dEXdru.js → kanban-definition-UN3LZRKU-DIQo2GiM.js} +1 -1
- package/dist/rcs-web/assets/{linear-CexxJrg8.js → linear-CdXALiZ8.js} +1 -1
- package/dist/rcs-web/assets/{main-L9iyf39T.js → main-CwLwGVDc.js} +7 -7
- package/dist/rcs-web/assets/{mermaid-VLURNSYL-BomP37Br.js → mermaid-VLURNSYL-C0ZKM74W.js} +4 -4
- package/dist/rcs-web/assets/{mermaid.core-BxkfDFm_.js → mermaid.core-eEtoQhrQ.js} +5 -5
- package/dist/rcs-web/assets/{mindmap-definition-RKZ34NQL-HVsZx8Je.js → mindmap-definition-RKZ34NQL-CcW3H_cH.js} +1 -1
- package/dist/rcs-web/assets/{pieDiagram-4H26LBE5-D0U9q74D.js → pieDiagram-4H26LBE5-DpXUpJMl.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/quadrantDiagram-W4KKPZXB-CWPBZMPj.js → dist/rcs-web/assets/quadrantDiagram-W4KKPZXB-DOwMRzzP.js} +1 -1
- package/dist/rcs-web/assets/{requirementDiagram-4Y6WPE33-CiQbIN_P.js → requirementDiagram-4Y6WPE33-CBi_6NcW.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-Bw66fXM0.js → dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-CKbAoTHm.js} +1 -1
- package/dist/rcs-web/assets/{sequenceDiagram-3UESZ5HK-lv5WhGb6.js → sequenceDiagram-3UESZ5HK-a3rYCe-w.js} +1 -1
- package/dist/rcs-web/assets/{stateDiagram-AJRCARHV-BLRRpX3g.js → stateDiagram-AJRCARHV-B6R_Dt84.js} +1 -1
- package/dist/rcs-web/assets/{stateDiagram-v2-BHNVJYJU-B-5gzDu6.js → stateDiagram-v2-BHNVJYJU-Cq935fvz.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-DO8oVMVA.js → dist/rcs-web/assets/timeline-definition-PNZ67QCA-8DXPKq1k.js} +1 -1
- package/dist/rcs-web/assets/{vennDiagram-CIIHVFJN-D2RbeAHj.js → vennDiagram-CIIHVFJN-BfDEkku5.js} +1 -1
- package/dist/rcs-web/assets/{wardleyDiagram-YWT4CUSO-D8D1cIXp.js → wardleyDiagram-YWT4CUSO-Dvp2XZVf.js} +1 -1
- package/{packages/remote-control-server/web/dist/assets/xychartDiagram-2RQKCTM6-Bzk5AxMb.js → dist/rcs-web/assets/xychartDiagram-2RQKCTM6-DiPjQLUx.js} +1 -1
- package/dist/rcs-web/index.html +1 -1
- package/package.json +1 -1
- package/packages/remote-control-server/src/__tests__/event-bus.test.ts +50 -0
- package/packages/remote-control-server/src/__tests__/routes.test.ts +115 -5
- package/packages/remote-control-server/src/__tests__/turn-end-status.test.ts +205 -0
- package/packages/remote-control-server/src/routes/v2/worker-events.ts +22 -0
- package/packages/remote-control-server/src/routes/web/sessions.ts +64 -1
- package/packages/remote-control-server/src/transport/event-bus.ts +9 -0
- package/packages/remote-control-server/web/dist/assets/{AdminPanel-CbcZ7Vnr.js → AdminPanel-Xlza8Stt.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/Claim-BMWwu213.js +1 -0
- package/{dist/rcs-web/assets/Dashboard-BZGcSCFY.js → packages/remote-control-server/web/dist/assets/Dashboard-D5awDzM3.js} +2 -2
- package/{dist/rcs-web/assets/Join-B_e3BKa3.js → packages/remote-control-server/web/dist/assets/Join-ok37ggfZ.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{Login-u6CGGkoD.js → Login-5qo97rq-.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{Register-C4Fk0ibc.js → Register-D_UOG8ar.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/SessionDetail-BbHrR4Qu.js +65 -0
- package/packages/remote-control-server/web/dist/assets/{SessionVisibilityBadge-BHKxlh8U.js → SessionVisibilityBadge-Dy4FwTzo.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{Setup-DReCE0zx.js → Setup-GnPeNyH9.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{ShareLanding-qE1U0WKZ.js → ShareLanding-CUjQydLL.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{TeamCreate-BgwgZP4a.js → TeamCreate-Ck2fEoUW.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{TeamDetail-BHCvnI2t.js → TeamDetail-De6EPND0.js} +2 -2
- package/packages/remote-control-server/web/dist/assets/{TeamList-B7uC8lDV.js → TeamList-C-0LJRxd.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{TeamSettings-DtgvrKEE.js → TeamSettings-BszOrXVW.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{UserSearchInput-dgxhGWfJ.js → UserSearchInput-CyQWtLL-.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{UserSettings-Zyjam23-.js → UserSettings-DgyYp-1y.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{arc-DgC_wPAg.js → arc-BaOPt7k-.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{architectureDiagram-3BPJPVTR-BnnCRJZs.js → architectureDiagram-3BPJPVTR-SvIakXbT.js} +1 -1
- package/{dist/rcs-web/assets/blockDiagram-GPEHLZMM-CvpYdvcP.js → packages/remote-control-server/web/dist/assets/blockDiagram-GPEHLZMM-CiDp9J7i.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{c4Diagram-AAUBKEIU-DNK__-3d.js → c4Diagram-AAUBKEIU-D9wzA9ur.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/channel-CirgRB_G.js +1 -0
- package/packages/remote-control-server/web/dist/assets/{chunk-2J33WTMH-5JQBz2na.js → chunk-2J33WTMH-qfYueRAP.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-4BX2VUAB-YJh8d73x.js → chunk-4BX2VUAB-D1V_UCiK.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-55IACEB6-U5c5GQZN.js → chunk-55IACEB6-C67QiGmo.js} +1 -1
- package/{dist/rcs-web/assets/chunk-727SXJPM-ifGCid_3.js → packages/remote-control-server/web/dist/assets/chunk-727SXJPM-D2Wln4TT.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-AQP2D5EJ-DxqPH2_Q.js → chunk-AQP2D5EJ-03h8hZhw.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-FMBD7UC4-dDtjQRPo.js → chunk-FMBD7UC4-7zas8pDp.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-ND2GUHAM-0UF6vhhE.js → chunk-ND2GUHAM-PUXucyY6.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{chunk-QZHKN3VN-CfZ4xcBz.js → chunk-QZHKN3VN-M3U5l4yW.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-Cq12UEz9.js +1 -0
- package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-Cq12UEz9.js +1 -0
- package/packages/remote-control-server/web/dist/assets/{code-block-IT6T5CEO-B4B0UrXo.js → code-block-IT6T5CEO-BgUazuuS.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{copy-_OW0eGyp.js → copy-DjaSB1Rw.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{cose-bilkent-S5V4N54A-B19xQvnh.js → cose-bilkent-S5V4N54A-zPupX74N.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{dagre-BM42HDAG-5JJnjI1B.js → dagre-BM42HDAG-B_EJ050J.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{diagram-2AECGRRQ-BY2NR7vr.js → diagram-2AECGRRQ-dnnxPH7w.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{diagram-5GNKFQAL-3zC3GraP.js → diagram-5GNKFQAL-CLEOqCLZ.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{diagram-KO2AKTUF-T1Jt5zH3.js → diagram-KO2AKTUF-DKBGpiRW.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{diagram-LMA3HP47-ehrkQG1e.js → diagram-LMA3HP47-BAilhXiA.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{diagram-OG6HWLK6-D8ZJlGs0.js → diagram-OG6HWLK6-C3CdmOxC.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{erDiagram-TEJ5UH35-Ckn1pY7G.js → erDiagram-TEJ5UH35-D1yv-3Jv.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{flowDiagram-I6XJVG4X-C1xnAOfH.js → flowDiagram-I6XJVG4X-DpW11XWj.js} +1 -1
- package/{dist/rcs-web/assets/ganttDiagram-6RSMTGT7-Dw8qOfCT.js → packages/remote-control-server/web/dist/assets/ganttDiagram-6RSMTGT7-CWr8suZm.js} +1 -1
- package/{dist/rcs-web/assets/gitGraphDiagram-PVQCEYII-Cg3La45a.js → packages/remote-control-server/web/dist/assets/gitGraphDiagram-PVQCEYII-BspxLSNV.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{infoDiagram-5YYISTIA-CGH2aXpd.js → infoDiagram-5YYISTIA-Bow20s-Q.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{ishikawaDiagram-YF4QCWOH-x89F9Igr.js → ishikawaDiagram-YF4QCWOH-BESvGYGI.js} +1 -1
- package/{dist/rcs-web/assets/journeyDiagram-JHISSGLW-Ckd_pKi0.js → packages/remote-control-server/web/dist/assets/journeyDiagram-JHISSGLW-DZ6gzC7H.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{kanban-definition-UN3LZRKU-D2dEXdru.js → kanban-definition-UN3LZRKU-DIQo2GiM.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{linear-CexxJrg8.js → linear-CdXALiZ8.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{main-L9iyf39T.js → main-CwLwGVDc.js} +7 -7
- package/packages/remote-control-server/web/dist/assets/{mermaid-VLURNSYL-BomP37Br.js → mermaid-VLURNSYL-C0ZKM74W.js} +4 -4
- package/packages/remote-control-server/web/dist/assets/{mermaid.core-BxkfDFm_.js → mermaid.core-eEtoQhrQ.js} +5 -5
- package/packages/remote-control-server/web/dist/assets/{mindmap-definition-RKZ34NQL-HVsZx8Je.js → mindmap-definition-RKZ34NQL-CcW3H_cH.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{pieDiagram-4H26LBE5-D0U9q74D.js → pieDiagram-4H26LBE5-DpXUpJMl.js} +1 -1
- package/{dist/rcs-web/assets/quadrantDiagram-W4KKPZXB-CWPBZMPj.js → packages/remote-control-server/web/dist/assets/quadrantDiagram-W4KKPZXB-DOwMRzzP.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{requirementDiagram-4Y6WPE33-CiQbIN_P.js → requirementDiagram-4Y6WPE33-CBi_6NcW.js} +1 -1
- package/{dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-Bw66fXM0.js → packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-CKbAoTHm.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{sequenceDiagram-3UESZ5HK-lv5WhGb6.js → sequenceDiagram-3UESZ5HK-a3rYCe-w.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{stateDiagram-AJRCARHV-BLRRpX3g.js → stateDiagram-AJRCARHV-B6R_Dt84.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{stateDiagram-v2-BHNVJYJU-B-5gzDu6.js → stateDiagram-v2-BHNVJYJU-Cq935fvz.js} +1 -1
- package/{dist/rcs-web/assets/timeline-definition-PNZ67QCA-DO8oVMVA.js → packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-8DXPKq1k.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{vennDiagram-CIIHVFJN-D2RbeAHj.js → vennDiagram-CIIHVFJN-BfDEkku5.js} +1 -1
- package/packages/remote-control-server/web/dist/assets/{wardleyDiagram-YWT4CUSO-D8D1cIXp.js → wardleyDiagram-YWT4CUSO-Dvp2XZVf.js} +1 -1
- package/{dist/rcs-web/assets/xychartDiagram-2RQKCTM6-Bzk5AxMb.js → packages/remote-control-server/web/dist/assets/xychartDiagram-2RQKCTM6-DiPjQLUx.js} +1 -1
- package/packages/remote-control-server/web/dist/index.html +1 -1
- package/dist/rcs-web/assets/Claim-CN3D3Ku6.js +0 -1
- package/dist/rcs-web/assets/SessionDetail-Bd1YgozL.js +0 -65
- package/dist/rcs-web/assets/channel-DB6b62-p.js +0 -1
- package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-DkXLqlKv.js +0 -1
- package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-DkXLqlKv.js +0 -1
- package/packages/remote-control-server/web/dist/assets/Claim-CN3D3Ku6.js +0 -1
- package/packages/remote-control-server/web/dist/assets/SessionDetail-Bd1YgozL.js +0 -65
- package/packages/remote-control-server/web/dist/assets/channel-DB6b62-p.js +0 -1
- package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-DkXLqlKv.js +0 -1
- package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-DkXLqlKv.js +0 -1
|
@@ -6066,6 +6066,10 @@
|
|
|
6066
6066
|
"category": "bridge",
|
|
6067
6067
|
"description": "worker 连接的 RCS 地址"
|
|
6068
6068
|
},
|
|
6069
|
+
{
|
|
6070
|
+
"name": "SALUZI_BRIDGE_CLAIM_TIMEOUT_MS",
|
|
6071
|
+
"category": "other"
|
|
6072
|
+
},
|
|
6069
6073
|
{
|
|
6070
6074
|
"name": "SALUZI_BRIDGE_MAX_SESSIONS",
|
|
6071
6075
|
"category": "other"
|
|
@@ -7144,7 +7148,7 @@
|
|
|
7144
7148
|
"可视化"
|
|
7145
7149
|
]
|
|
7146
7150
|
},
|
|
7147
|
-
"content": "\n## 什么是 /parade\n\nParade 是 Saluzi 的桌面悬浮提示功能。它在桌面显示一个小型悬浮窗口(基于 Electron),实时反映:\n\n- **运行中会话数**:当前正在执行工具调用的会话\n- **等待中会话数**:等待用户输入或权限确认的会话\n- **连接状态**:WebSocket 连接状态指示灯\n\n外观示意(运行中 2 / 等待 1):\n\n::parade-preview::\n\n## 启用 Parade\n\n```\n> /parade\n```\n\n首次启用会自动检测并安装 Electron
|
|
7151
|
+
"content": "\n## 什么是 /parade\n\nParade 是 Saluzi 的桌面悬浮提示功能。它在桌面显示一个小型悬浮窗口(基于 Electron),实时反映:\n\n- **运行中会话数**:当前正在执行工具调用的会话\n- **等待中会话数**:等待用户输入或权限确认的会话\n- **连接状态**:WebSocket 连接状态指示灯\n\n外观示意(运行中 2 / 等待 1):\n\n::parade-preview::\n\n## 启用 Parade\n\n```\n> /parade\n```\n\n首次启用会自动检测并安装 Electron(若未安装),然后启动悬浮窗。悬浮窗默认定位在**主显示器右下角**(避开任务栏),220×130 像素,无边框始终置顶。\n\n## 关闭 Parade\n\n```\n> /parade off\n```\n\n## 多会话并行\n\n多个终端各自运行 Saluzi 会话时,所有 CLI 实例共享同一个 Parade 窗口(通过 PID 锁文件确保单例)。悬浮窗显示所有已连接会话的运行/等待计数。\n\nParade 服务器以**脱离模式**运行——即使启动它的 CLI 关闭,悬浮窗仍然存活,直到用 `/parade off` 显式关闭。\n\n## 显示模式\n\n右键悬浮窗(或在左侧立方体区域滚动滚轮)可在 4 种显示模式间切换,按信息完整度排序:\n\n| 模式 | 显示内容 | 默认窗口尺寸 |\n|------|----------|--------------|\n| Cube only | 仅左侧立方体图案 | 130×130 |\n| Cube + counts | 立方体 + 运行/等待计数 | 176×130 |\n| Standard(默认) | 立方体 + 计数 + 会话列表 | 220×130 |\n| Detail | 大窗口详情:全部会话、状态徽章(RUN/BLOCK/IDLE)、更完整的 prompt,整行可点击跳转 | 460×340 |\n\n- 当前模式在右键菜单中以实心圆点标记,切换后持久化,重启悬浮窗后仍生效\n- 窗口尺寸随模式自动调整;手动拖拽调整过的尺寸按模式记忆(下次进入同一模式时恢复)\n- 放大窗口时,立方体图案与字体大小按比例缩放\n- 菜单底部的 **Rotation: Dynamic/Static** 控制旋转时机:运行时旋转(默认)或空闲时旋转\n\n## 跳转终端\n\n会话列表每行左侧的指示点(悬停变为 ▸)可跳转到该会话所在的终端窗口;Detail 模式下点击整行即可。\n\n跨边界场景(WSL 内的 CLI 向 Windows 侧悬浮窗上报)中,WSL 进程在 Windows 侧没有对应进程 ID,Parade 会退而激活检测到的终端窗口(Windows Terminal 等)。存在多个终端窗口时聚焦第一个匹配窗口,不保证定位到具体标签页。\n\n## 平台支持\n\n| 平台 | 状态 | 说明 |\n|------|------|------|\n| macOS | 完全支持 | 原生 Electron |\n| Linux | 支持 | 需 X11 或 Wayland |\n| Windows | 支持 | Electron |\n| WSL | 支持 | 通过 /etc/resolv.conf 解析主机 IP |\n\n## 故障排查\n\n- **悬浮窗不显示**:检查 Electron 是否安装(`/parade` 会自动安装,支持 `ELECTRON_MIRROR` 环境变量配置镜像)\n- **Electron 安装路径**:`~/.saluzi/parade/`\n- **多显示器**:悬浮窗默认在主显示器顶部居中\n"
|
|
7148
7152
|
},
|
|
7149
7153
|
"docs/guide/keyboard-shortcuts": {
|
|
7150
7154
|
"frontmatter": {
|
package/dist/parade/web/cube.js
CHANGED
|
@@ -3,38 +3,224 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Responsibilities:
|
|
5
5
|
* 1. Render a purple 3D cube via CSS 3D transforms in the left stage area.
|
|
6
|
-
* 2. Animate the cube with
|
|
6
|
+
* 2. Animate the cube with a fast glow-pulse rotation when runningCount > 0.
|
|
7
7
|
* 3. Update the info bar (right side) with running/waiting counts and
|
|
8
8
|
* per-session prompt text from WebSocket pushes.
|
|
9
|
+
* 4. Manage the 4-level display mode (logo / mini / standard / detail) with
|
|
10
|
+
* window-size sync, persistence, and right-click menu switching.
|
|
9
11
|
*
|
|
10
12
|
* WebSocket protocol: receives JSON array of SessionEntry objects:
|
|
11
13
|
* [{ pid, sessionId, state, prompt, lastHeartbeat }, ...]
|
|
14
|
+
*
|
|
15
|
+
* Unit contract (must match the electron main script in paradeWindow.ts):
|
|
16
|
+
* - design px: the base coordinate system. All CSS dimensions are
|
|
17
|
+
* calc(Npx * var(--ui-scale)); --ui-scale is derived from the window
|
|
18
|
+
* size relative to the current mode's base size.
|
|
19
|
+
* - IPC bounds (parade-set-bounds / parade-bounds-changed): design px.
|
|
20
|
+
* The main process multiplies/divides by its unitScale (dpiScale).
|
|
21
|
+
* - localStorage sizes: design px (portable across DPI settings).
|
|
12
22
|
*/
|
|
13
23
|
|
|
14
24
|
// ---------------------------------------------------------------------------
|
|
15
25
|
// Configuration
|
|
16
26
|
// ---------------------------------------------------------------------------
|
|
17
27
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
28
|
+
var WS_RECONNECT_MS = 2000
|
|
29
|
+
|
|
30
|
+
// Per-mode config. win = natural window size (design px, applied on mode
|
|
31
|
+
// switch when no user-customized size is saved). base = scale reference
|
|
32
|
+
// (design px at --ui-scale 1) — detail uses a smaller base so fonts render
|
|
33
|
+
// large enough to read at its natural window size. maxPrompt/maxRows control
|
|
34
|
+
// the session list density.
|
|
35
|
+
var MODES = {
|
|
36
|
+
logo: { win: [130, 130], base: [130, 130], maxPrompt: 30, maxRows: 5 },
|
|
37
|
+
mini: { win: [176, 130], base: [176, 130], maxPrompt: 30, maxRows: 5 },
|
|
38
|
+
standard: { win: [220, 130], base: [220, 130], maxPrompt: 30, maxRows: 5 },
|
|
39
|
+
detail: { win: [460, 340], base: [300, 220], maxPrompt: 80, maxRows: 20 },
|
|
40
|
+
}
|
|
41
|
+
var MODE_ORDER = ['logo', 'mini', 'standard', 'detail']
|
|
42
|
+
var SCALE_MIN = 1
|
|
43
|
+
var SCALE_MAX = 3
|
|
44
|
+
// Window bounds clamps in design px — must match the parade-set-bounds
|
|
45
|
+
// clamps in the electron main script (which multiplies by unitScale).
|
|
46
|
+
var BOUNDS_MIN = [100, 80]
|
|
47
|
+
var BOUNDS_MAX = [900, 700]
|
|
48
|
+
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Zoom / port (needed before everything — applyScale divides by zoomFactor)
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
// Derive port from the current page's URL so the WebSocket targets the same
|
|
54
|
+
// server that served this page. Falls back to query string (?port=) for the
|
|
55
|
+
// file:// case (native Webview windows launched with a file URL), then to
|
|
56
|
+
// the default 17841.
|
|
57
|
+
var urlParams = new URLSearchParams(window.location.search)
|
|
58
|
+
var port = window.location.port || urlParams.get('port') || '17841'
|
|
59
|
+
|
|
60
|
+
// On native Win11, Electron is launched with --force-device-scale-factor=1
|
|
61
|
+
// to eliminate DPI conversion mismatches in getBounds/setBounds. This makes
|
|
62
|
+
// 1 CSS pixel = 1 physical pixel, so content renders at 1x scale (smaller
|
|
63
|
+
// on high-DPI displays). The main process passes the OS DPI factor as ?zoom=
|
|
64
|
+
// so we can CSS-zoom the content to match the intended physical size.
|
|
65
|
+
//
|
|
66
|
+
// --ui-scale must be computed against DESIGN px, not the zoomed CSS px:
|
|
67
|
+
// window.innerWidth counts physical px here (root zoom doesn't change the
|
|
68
|
+
// viewport CSS px count), so divide by zoomFactor to avoid double-scaling.
|
|
69
|
+
var zoomParam = parseFloat(urlParams.get('zoom')) || 0
|
|
70
|
+
if (zoomParam > 1) {
|
|
71
|
+
document.documentElement.style.zoom = String(zoomParam)
|
|
72
|
+
}
|
|
73
|
+
var zoomFactor = zoomParam > 1 ? zoomParam : 1
|
|
74
|
+
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Display mode state (applied as early as possible to avoid resize flash)
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
var displayMode = 'standard'
|
|
80
|
+
try {
|
|
81
|
+
let storedMode = localStorage.getItem('parade-display-mode')
|
|
82
|
+
if (storedMode && MODES[storedMode]) displayMode = storedMode
|
|
83
|
+
} catch (_) {
|
|
84
|
+
/* localStorage may be unavailable */
|
|
85
|
+
}
|
|
86
|
+
document.body.dataset.mode = displayMode
|
|
87
|
+
|
|
88
|
+
// Per-mode user-customized window size (design px). Saved on manual resize,
|
|
89
|
+
// preferred over the mode's natural size on mode entry / boot.
|
|
90
|
+
function clampSize(w, h) {
|
|
91
|
+
return [
|
|
92
|
+
Math.max(BOUNDS_MIN[0], Math.min(BOUNDS_MAX[0], Math.round(w))),
|
|
93
|
+
Math.max(BOUNDS_MIN[1], Math.min(BOUNDS_MAX[1], Math.round(h))),
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function savedSize(mode) {
|
|
98
|
+
try {
|
|
99
|
+
const raw = localStorage.getItem('parade-size-' + mode)
|
|
100
|
+
if (!raw) return null
|
|
101
|
+
const parts = JSON.parse(raw)
|
|
102
|
+
if (
|
|
103
|
+
Array.isArray(parts) &&
|
|
104
|
+
parts.length === 2 &&
|
|
105
|
+
Number.isFinite(parts[0]) &&
|
|
106
|
+
Number.isFinite(parts[1])
|
|
107
|
+
) {
|
|
108
|
+
return clampSize(parts[0], parts[1])
|
|
109
|
+
}
|
|
110
|
+
} catch (_) {
|
|
111
|
+
/* ignore */
|
|
112
|
+
}
|
|
113
|
+
return null
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function saveSize(mode, w, h) {
|
|
117
|
+
try {
|
|
118
|
+
localStorage.setItem('parade-size-' + mode, JSON.stringify(clampSize(w, h)))
|
|
119
|
+
} catch (_) {
|
|
120
|
+
/* ignore */
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Bounds echo suppression: after WE request bounds, the main process echoes
|
|
125
|
+
// parade-bounds-changed back — without the flag we'd persist our own mode
|
|
126
|
+
// size as a "user customization" (feedback loop).
|
|
127
|
+
var suppressBoundsSave = false
|
|
128
|
+
|
|
129
|
+
function requestWindowBounds(w, h) {
|
|
130
|
+
if (!window.parade || typeof window.parade.setBounds !== 'function') return
|
|
131
|
+
var s = clampSize(w, h)
|
|
132
|
+
suppressBoundsSave = true
|
|
133
|
+
window.parade.setBounds(s[0], s[1])
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (window.parade && typeof window.parade.onBoundsChanged === 'function') {
|
|
137
|
+
window.parade.onBoundsChanged(function (w, h) {
|
|
138
|
+
if (suppressBoundsSave) {
|
|
139
|
+
suppressBoundsSave = false
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
if (typeof w === 'number' && typeof h === 'number' && w > 0 && h > 0) {
|
|
143
|
+
saveSize(displayMode, w, h)
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
}
|
|
21
147
|
|
|
22
148
|
// ---------------------------------------------------------------------------
|
|
23
149
|
// DOM references
|
|
24
150
|
// ---------------------------------------------------------------------------
|
|
25
151
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
152
|
+
var cubeEl = document.getElementById('cube')
|
|
153
|
+
var cubeStageEl = document.getElementById('cube-stage')
|
|
154
|
+
var runningCountEl = document.getElementById('running-count')
|
|
155
|
+
var waitingCountEl = document.getElementById('waiting-count')
|
|
156
|
+
var waitingPillEl = document.getElementById('waiting-pill')
|
|
157
|
+
var sessionsEl = document.getElementById('sessions-inner')
|
|
158
|
+
var sessionsContainer = document.getElementById('sessions')
|
|
159
|
+
var scrollbarTrack = document.getElementById('scrollbar-track')
|
|
160
|
+
var scrollbarThumb = document.getElementById('scrollbar-thumb')
|
|
161
|
+
var moreLineEl = document.getElementById('more-line')
|
|
162
|
+
var ctxMenu = document.getElementById('ctx-menu')
|
|
163
|
+
var ctxMode = document.getElementById('ctx-mode')
|
|
164
|
+
var closeBtn = document.getElementById('close-btn')
|
|
165
|
+
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// Session state
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
/** @type {Array<{pid:number, sessionId:string, state:string, prompt:string, lastHeartbeat:number}>} */
|
|
171
|
+
var sessions = []
|
|
172
|
+
var runningCount = 0
|
|
173
|
+
var waitingCount = 0
|
|
174
|
+
var ws = null
|
|
175
|
+
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// UI scale — grows the cube and fonts with the window
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
|
|
180
|
+
function applyScale() {
|
|
181
|
+
var mode = MODES[displayMode]
|
|
182
|
+
var w = window.innerWidth / zoomFactor
|
|
183
|
+
var h = window.innerHeight / zoomFactor
|
|
184
|
+
var s = Math.min(w / mode.base[0], h / mode.base[1])
|
|
185
|
+
s = Math.max(SCALE_MIN, Math.min(SCALE_MAX, s))
|
|
186
|
+
document.documentElement.style.setProperty('--ui-scale', s.toFixed(4))
|
|
187
|
+
// Window resizes change the session viewport — re-measure the scrollbar.
|
|
188
|
+
requestAnimationFrame(updateScrollbar)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Re-measure on every window resize (restored — the WebGL→CSS refactor in
|
|
192
|
+
// 982be36 accidentally dropped this listener).
|
|
193
|
+
window.addEventListener('resize', applyScale)
|
|
194
|
+
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
// Display mode switching
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
|
|
199
|
+
function setMode(mode) {
|
|
200
|
+
if (!MODES[mode]) return
|
|
201
|
+
var changed = mode !== displayMode
|
|
202
|
+
displayMode = mode
|
|
203
|
+
try {
|
|
204
|
+
localStorage.setItem('parade-display-mode', mode)
|
|
205
|
+
} catch (_) {
|
|
206
|
+
/* ignore */
|
|
207
|
+
}
|
|
208
|
+
document.body.dataset.mode = mode
|
|
209
|
+
if (changed) {
|
|
210
|
+
// Replay the mode-swap fade animation (needs a reflow to restart).
|
|
211
|
+
document.body.classList.remove('mode-swap')
|
|
212
|
+
void document.body.offsetWidth
|
|
213
|
+
document.body.classList.add('mode-swap')
|
|
214
|
+
// Truncation/badges/row cap changed — force a row rebuild.
|
|
215
|
+
lastRowSig = null
|
|
216
|
+
}
|
|
217
|
+
updateViewMenu()
|
|
218
|
+
applyScale()
|
|
219
|
+
updateSessionRows()
|
|
220
|
+
// Resize the window to this mode's saved (or natural) size.
|
|
221
|
+
var size = savedSize(mode) || MODES[mode].win
|
|
222
|
+
requestWindowBounds(size[0], size[1])
|
|
223
|
+
}
|
|
38
224
|
|
|
39
225
|
// ---------------------------------------------------------------------------
|
|
40
226
|
// Custom scrollbar — invisible by default, fades in on hover/scroll.
|
|
@@ -161,29 +347,6 @@ if (scrollbarThumb && scrollbarTrack) {
|
|
|
161
347
|
// WebSocket connection
|
|
162
348
|
// ---------------------------------------------------------------------------
|
|
163
349
|
|
|
164
|
-
// Derive port from the current page's URL so the WebSocket targets the same
|
|
165
|
-
// server that served this page. Falls back to query string (?port=) for the
|
|
166
|
-
// file:// case (native Webview windows launched with a file URL), then to
|
|
167
|
-
// the default 17841.
|
|
168
|
-
var urlParams = new URLSearchParams(window.location.search)
|
|
169
|
-
var port = window.location.port || urlParams.get('port') || '17841'
|
|
170
|
-
|
|
171
|
-
// On native Win11, Electron is launched with --force-device-scale-factor=1
|
|
172
|
-
// to eliminate DPI conversion mismatches in getBounds/setBounds. This makes
|
|
173
|
-
// 1 CSS pixel = 1 physical pixel, so content renders at 1x scale (smaller
|
|
174
|
-
// on high-DPI displays). The main process passes the OS DPI factor as ?zoom=
|
|
175
|
-
// so we can CSS-zoom the content to match the intended physical size.
|
|
176
|
-
var zoomParam = parseFloat(urlParams.get('zoom')) || 0
|
|
177
|
-
if (zoomParam > 1) {
|
|
178
|
-
document.documentElement.style.zoom = String(zoomParam)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/** @type {Array<{pid:number, sessionId:string, state:string, prompt:string, lastHeartbeat:number}>} */
|
|
182
|
-
let sessions = []
|
|
183
|
-
let runningCount = 0
|
|
184
|
-
let waitingCount = 0
|
|
185
|
-
let ws = null
|
|
186
|
-
|
|
187
350
|
function connectWebSocket() {
|
|
188
351
|
try {
|
|
189
352
|
ws = new WebSocket('ws://localhost:' + port + '/ws')
|
|
@@ -269,7 +432,33 @@ function updateCounts() {
|
|
|
269
432
|
updateCubeRotation()
|
|
270
433
|
}
|
|
271
434
|
|
|
435
|
+
// ---------------------------------------------------------------------------
|
|
436
|
+
// Session rows
|
|
437
|
+
// ---------------------------------------------------------------------------
|
|
438
|
+
// Rows are rebuilt ONLY when the displayed data actually changes. The CLI
|
|
439
|
+
// heartbeats every 1s and each POST broadcasts the full session list —
|
|
440
|
+
// rebuilding on every message would replace row elements between a user's
|
|
441
|
+
// mousedown and mouseup, swallowing clicks (the original jump-button bug).
|
|
442
|
+
|
|
443
|
+
var lastRowSig = null
|
|
444
|
+
|
|
445
|
+
function sessionSignature() {
|
|
446
|
+
return sessions
|
|
447
|
+
.map(function (s) {
|
|
448
|
+
return s.pid + '|' + s.state + '|' + (s.prompt || '')
|
|
449
|
+
})
|
|
450
|
+
.join('¦')
|
|
451
|
+
}
|
|
452
|
+
|
|
272
453
|
function updateSessionRows() {
|
|
454
|
+
var mode = MODES[displayMode]
|
|
455
|
+
var sig = sessionSignature()
|
|
456
|
+
if (sig === lastRowSig) {
|
|
457
|
+
requestAnimationFrame(updateScrollbar)
|
|
458
|
+
return
|
|
459
|
+
}
|
|
460
|
+
lastRowSig = sig
|
|
461
|
+
|
|
273
462
|
var runningSessions = sessions.filter(function (s) {
|
|
274
463
|
return s.state === 'running'
|
|
275
464
|
})
|
|
@@ -291,21 +480,23 @@ function updateSessionRows() {
|
|
|
291
480
|
return
|
|
292
481
|
}
|
|
293
482
|
|
|
483
|
+
var cap = mode.maxRows
|
|
294
484
|
// Running sessions first (primary focus, purple dot)
|
|
295
|
-
var displayedRunning = runningSessions.slice(0,
|
|
485
|
+
var displayedRunning = runningSessions.slice(0, cap)
|
|
296
486
|
displayedRunning.forEach(function (s) {
|
|
297
487
|
sessionsEl.appendChild(buildSessionRow(s, 'running'))
|
|
298
488
|
})
|
|
299
489
|
|
|
300
|
-
// Blocked sessions next (amber dot, needs user action)
|
|
301
|
-
|
|
490
|
+
// Blocked sessions next (amber dot, needs user action). Standard modes
|
|
491
|
+
// keep at most 2 visible so running rows dominate; detail shows all.
|
|
492
|
+
var blockedCap = displayMode === 'detail' ? cap : 2
|
|
493
|
+
var displayedBlocked = blockedSessions.slice(0, blockedCap)
|
|
302
494
|
displayedBlocked.forEach(function (s) {
|
|
303
495
|
sessionsEl.appendChild(buildSessionRow(s, 'blocked'))
|
|
304
496
|
})
|
|
305
497
|
|
|
306
498
|
// Idle sessions last (dim, just "connected")
|
|
307
|
-
var slotsLeft =
|
|
308
|
-
MAX_DISPLAYED_SESSIONS - displayedRunning.length - displayedBlocked.length
|
|
499
|
+
var slotsLeft = cap - displayedRunning.length - displayedBlocked.length
|
|
309
500
|
var displayedIdle = idleSessions.slice(0, Math.max(0, slotsLeft))
|
|
310
501
|
displayedIdle.forEach(function (s) {
|
|
311
502
|
sessionsEl.appendChild(buildSessionRow(s, 'idle'))
|
|
@@ -325,11 +516,13 @@ function updateSessionRows() {
|
|
|
325
516
|
}
|
|
326
517
|
|
|
327
518
|
function buildSessionRow(s, kind) {
|
|
519
|
+
var mode = MODES[displayMode]
|
|
328
520
|
var row = document.createElement('div')
|
|
329
521
|
row.className = 'session-row ' + kind
|
|
522
|
+
row.setAttribute('data-pid', String(s.pid))
|
|
330
523
|
var promptText = s.prompt || ''
|
|
331
|
-
if (promptText.length >
|
|
332
|
-
promptText = promptText.substring(0,
|
|
524
|
+
if (promptText.length > mode.maxPrompt) {
|
|
525
|
+
promptText = promptText.substring(0, mode.maxPrompt) + '...'
|
|
333
526
|
}
|
|
334
527
|
var text = document.createElement('span')
|
|
335
528
|
text.className = 'session-text'
|
|
@@ -340,13 +533,53 @@ function buildSessionRow(s, kind) {
|
|
|
340
533
|
} else {
|
|
341
534
|
text.textContent = promptText || '(running)'
|
|
342
535
|
}
|
|
343
|
-
//
|
|
536
|
+
// State badge — visible in detail mode only (CSS)
|
|
537
|
+
var badge = document.createElement('span')
|
|
538
|
+
badge.className =
|
|
539
|
+
'session-badge ' +
|
|
540
|
+
(kind === 'running' ? 'run' : kind === 'blocked' ? 'block' : 'idle')
|
|
541
|
+
badge.textContent =
|
|
542
|
+
kind === 'running' ? 'RUN' : kind === 'blocked' ? 'BLOCK' : 'IDLE'
|
|
543
|
+
// Jump-to-terminal dot — placed at left indicator, morphs into ▸ on hover.
|
|
544
|
+
// Click handling is delegated (see mousedown/mouseup pairing below) so a
|
|
545
|
+
// rebuild between press and release can't swallow the jump.
|
|
344
546
|
var jump = document.createElement('span')
|
|
345
547
|
jump.className = 'session-jump'
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
548
|
+
row.appendChild(text)
|
|
549
|
+
row.appendChild(badge)
|
|
550
|
+
row.insertBefore(jump, row.firstChild)
|
|
551
|
+
|
|
552
|
+
return row
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Jump dispatch: mousedown records the pressed row; mouseup on the SAME row
|
|
556
|
+
// fires the focus request. Immune to element replacement between events.
|
|
557
|
+
// In detail mode the whole row is the hit target; other modes require the
|
|
558
|
+
// jump dot.
|
|
559
|
+
var pressedPid = null
|
|
560
|
+
|
|
561
|
+
sessionsEl.addEventListener('mousedown', function (e) {
|
|
562
|
+
if (e.button !== 0) return
|
|
563
|
+
var row = e.target.closest('.session-row')
|
|
564
|
+
pressedPid = row ? row.getAttribute('data-pid') : null
|
|
565
|
+
})
|
|
566
|
+
|
|
567
|
+
sessionsEl.addEventListener('mouseup', function (e) {
|
|
568
|
+
if (e.button !== 0 || pressedPid === null) return
|
|
569
|
+
var pressed = pressedPid
|
|
570
|
+
pressedPid = null
|
|
571
|
+
var row = e.target.closest('.session-row')
|
|
572
|
+
var pid = row ? row.getAttribute('data-pid') : null
|
|
573
|
+
var isJumpClick = !!e.target.closest('.session-jump')
|
|
574
|
+
if (!row || pid === null || pid !== pressed) return
|
|
575
|
+
if (displayMode !== 'detail' && !isJumpClick) return
|
|
576
|
+
sendFocus(Number(pid), row)
|
|
577
|
+
})
|
|
578
|
+
|
|
579
|
+
function sendFocus(pid, row) {
|
|
580
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
581
|
+
ws.send(JSON.stringify({ type: 'focus', pid: pid }))
|
|
582
|
+
if (row) {
|
|
350
583
|
// Pulse the row to confirm jump was sent
|
|
351
584
|
row.classList.remove('jumping')
|
|
352
585
|
void row.offsetWidth // force reflow to restart animation
|
|
@@ -354,25 +587,21 @@ function buildSessionRow(s, kind) {
|
|
|
354
587
|
setTimeout(function () {
|
|
355
588
|
row.classList.remove('jumping')
|
|
356
589
|
}, 1300)
|
|
357
|
-
if (window.parade && typeof window.parade.debugLog === 'function') {
|
|
358
|
-
window.parade.debugLog('[jump] click pid=' + s.pid + ' ws=OPEN sent')
|
|
359
|
-
}
|
|
360
|
-
} else {
|
|
361
|
-
if (window.parade && typeof window.parade.debugLog === 'function') {
|
|
362
|
-
window.parade.debugLog(
|
|
363
|
-
'[jump] click pid=' +
|
|
364
|
-
s.pid +
|
|
365
|
-
' ws=' +
|
|
366
|
-
(ws ? ws.readyState : 'null') +
|
|
367
|
-
' NOT sent',
|
|
368
|
-
)
|
|
369
|
-
}
|
|
370
590
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
591
|
+
if (window.parade && typeof window.parade.debugLog === 'function') {
|
|
592
|
+
window.parade.debugLog('[jump] click pid=' + pid + ' ws=OPEN sent')
|
|
593
|
+
}
|
|
594
|
+
} else {
|
|
595
|
+
if (window.parade && typeof window.parade.debugLog === 'function') {
|
|
596
|
+
window.parade.debugLog(
|
|
597
|
+
'[jump] click pid=' +
|
|
598
|
+
pid +
|
|
599
|
+
' ws=' +
|
|
600
|
+
(ws ? ws.readyState : 'null') +
|
|
601
|
+
' NOT sent',
|
|
602
|
+
)
|
|
603
|
+
}
|
|
604
|
+
}
|
|
376
605
|
}
|
|
377
606
|
|
|
378
607
|
// ---------------------------------------------------------------------------
|
|
@@ -381,12 +610,46 @@ function buildSessionRow(s, kind) {
|
|
|
381
610
|
|
|
382
611
|
document.addEventListener('contextmenu', function (e) {
|
|
383
612
|
e.preventDefault()
|
|
613
|
+
// Electron bridge: the menu opens as its own cursor-anchored popup window
|
|
614
|
+
// (see paradeWindow.ts 'parade-open-menu'), so it can extend beyond this
|
|
615
|
+
// window's bounds — the in-page fallback below is clipped by them, which
|
|
616
|
+
// truncated the menu on the small logo/mini modes.
|
|
617
|
+
if (window.parade && typeof window.parade.openMenu === 'function') {
|
|
618
|
+
window.parade.openMenu({ mode: displayMode, rot: cubeMode })
|
|
619
|
+
return
|
|
620
|
+
}
|
|
621
|
+
// Fallback (bridge missing — e.g. debugging the UI in a regular browser
|
|
622
|
+
// tab): show the in-page menu with flip/clamp positioning, accepting that
|
|
623
|
+
// it cannot leave the window.
|
|
384
624
|
updateModeLabel()
|
|
625
|
+
updateViewMenu()
|
|
385
626
|
ctxMenu.style.display = 'block'
|
|
386
|
-
|
|
387
|
-
|
|
627
|
+
// Flip/clamp positioning: the menu is taller than the logo/mini windows.
|
|
628
|
+
var mw = ctxMenu.offsetWidth
|
|
629
|
+
var mh = ctxMenu.offsetHeight
|
|
630
|
+
var x = Math.min(e.clientX, window.innerWidth - mw - 4)
|
|
631
|
+
var y = e.clientY
|
|
632
|
+
if (y + mh > window.innerHeight - 4) {
|
|
633
|
+
y = Math.max(4, e.clientY - mh)
|
|
634
|
+
}
|
|
635
|
+
ctxMenu.style.left = Math.max(4, x) + 'px'
|
|
636
|
+
ctxMenu.style.top = y + 'px'
|
|
388
637
|
})
|
|
389
638
|
|
|
639
|
+
// Actions arriving from the popup menu window (relayed via the main process).
|
|
640
|
+
// The parade window stays the source of truth — the popup only reports what
|
|
641
|
+
// was clicked, this side applies and persists it.
|
|
642
|
+
if (window.parade && typeof window.parade.onMenuAction === 'function') {
|
|
643
|
+
window.parade.onMenuAction(function (action) {
|
|
644
|
+
if (!action || typeof action !== 'object') return
|
|
645
|
+
if (action.type === 'view' && MODES[action.value]) {
|
|
646
|
+
setMode(action.value)
|
|
647
|
+
} else if (action.type === 'rotation') {
|
|
648
|
+
toggleRotationMode()
|
|
649
|
+
}
|
|
650
|
+
})
|
|
651
|
+
}
|
|
652
|
+
|
|
390
653
|
// Frameless window drag + corner resize via IPC (Electron). Left-click on
|
|
391
654
|
// the body starts a move-drag; left-click on a .corner-handle starts a
|
|
392
655
|
// proportional resize. The main process polls the cursor and moves/resizes
|
|
@@ -425,6 +688,25 @@ document.addEventListener('click', function () {
|
|
|
425
688
|
ctxMenu.style.display = 'none'
|
|
426
689
|
})
|
|
427
690
|
|
|
691
|
+
// View-mode radio items
|
|
692
|
+
var viewItems = ctxMenu.querySelectorAll('.ctx-view')
|
|
693
|
+
for (let vi = 0; vi < viewItems.length; vi++) {
|
|
694
|
+
viewItems[vi].addEventListener('click', function (e) {
|
|
695
|
+
e.stopPropagation()
|
|
696
|
+
ctxMenu.style.display = 'none'
|
|
697
|
+
setMode(this.getAttribute('data-view'))
|
|
698
|
+
})
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function updateViewMenu() {
|
|
702
|
+
for (let i = 0; i < viewItems.length; i++) {
|
|
703
|
+
viewItems[i].classList.toggle(
|
|
704
|
+
'active',
|
|
705
|
+
viewItems[i].getAttribute('data-view') === displayMode,
|
|
706
|
+
)
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
428
710
|
// ---------------------------------------------------------------------------
|
|
429
711
|
// Close button (top-right corner)
|
|
430
712
|
// ---------------------------------------------------------------------------
|
|
@@ -451,7 +733,7 @@ closeBtn.addEventListener('click', function () {
|
|
|
451
733
|
// ---------------------------------------------------------------------------
|
|
452
734
|
// Dynamic (default): cube rotates when sessions are running, static when idle.
|
|
453
735
|
// Static (inverse): cube static when running, rotates when idle.
|
|
454
|
-
// The context menu shows the
|
|
736
|
+
// The context menu shows the CURRENT mode.
|
|
455
737
|
|
|
456
738
|
var cubeMode = 'dynamic'
|
|
457
739
|
try {
|
|
@@ -461,11 +743,12 @@ try {
|
|
|
461
743
|
}
|
|
462
744
|
|
|
463
745
|
function updateModeLabel() {
|
|
464
|
-
ctxMode.textContent =
|
|
746
|
+
ctxMode.textContent =
|
|
747
|
+
'Rotation: ' + (cubeMode === 'dynamic' ? 'Dynamic' : 'Static')
|
|
465
748
|
}
|
|
466
749
|
|
|
467
|
-
|
|
468
|
-
|
|
750
|
+
// Shared by the in-page menu (fallback) and the popup menu action relay.
|
|
751
|
+
function toggleRotationMode() {
|
|
469
752
|
cubeMode = cubeMode === 'dynamic' ? 'static' : 'dynamic'
|
|
470
753
|
try {
|
|
471
754
|
localStorage.setItem('parade-cube-mode', cubeMode)
|
|
@@ -474,16 +757,54 @@ ctxMode.addEventListener('click', function () {
|
|
|
474
757
|
}
|
|
475
758
|
updateModeLabel()
|
|
476
759
|
updateCubeRotation()
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
ctxMode.addEventListener('click', function (e) {
|
|
763
|
+
e.stopPropagation()
|
|
764
|
+
ctxMenu.style.display = 'none'
|
|
765
|
+
toggleRotationMode()
|
|
477
766
|
})
|
|
478
767
|
|
|
479
768
|
updateModeLabel()
|
|
480
769
|
|
|
770
|
+
// ---------------------------------------------------------------------------
|
|
771
|
+
// Wheel-to-cycle display modes (on the cube stage)
|
|
772
|
+
// ---------------------------------------------------------------------------
|
|
773
|
+
// Accumulates wheel deltas with a threshold + cooldown so a single notch
|
|
774
|
+
// (or trackpad flood — the logo mode stage spans the whole window) flips
|
|
775
|
+
// exactly one mode.
|
|
776
|
+
|
|
777
|
+
var wheelAccum = 0
|
|
778
|
+
var wheelLockUntil = 0
|
|
779
|
+
|
|
780
|
+
cubeStageEl.addEventListener(
|
|
781
|
+
'wheel',
|
|
782
|
+
function (e) {
|
|
783
|
+
if (!e.deltaY) return
|
|
784
|
+
e.preventDefault()
|
|
785
|
+
var now = Date.now()
|
|
786
|
+
if (now < wheelLockUntil) return
|
|
787
|
+
wheelAccum += e.deltaY
|
|
788
|
+
if (Math.abs(wheelAccum) >= 120) {
|
|
789
|
+
const dir = wheelAccum > 0 ? 1 : -1
|
|
790
|
+
wheelAccum = 0
|
|
791
|
+
wheelLockUntil = now + 500
|
|
792
|
+
const idx = MODE_ORDER.indexOf(displayMode)
|
|
793
|
+
const next = Math.min(MODE_ORDER.length - 1, Math.max(0, idx + dir))
|
|
794
|
+
if (next !== idx) setMode(MODE_ORDER[next])
|
|
795
|
+
}
|
|
796
|
+
},
|
|
797
|
+
{ passive: false },
|
|
798
|
+
)
|
|
799
|
+
|
|
481
800
|
// ---------------------------------------------------------------------------
|
|
482
801
|
// CSS 3D Cube rotation control
|
|
483
802
|
// ---------------------------------------------------------------------------
|
|
484
803
|
// The cube is a CSS 3D transform element (see index.html <style>). Rotation
|
|
485
804
|
// is driven by applying/removing the .rotating class, which toggles the
|
|
486
|
-
// cube-spin @keyframes animation
|
|
805
|
+
// cube-spin @keyframes animation plus the stage-level glow/halo pulses
|
|
806
|
+
// (never on .cube itself — filter/opacity would flatten preserve-3d).
|
|
807
|
+
// Logic mirrors the previous WebGL loop:
|
|
487
808
|
// Dynamic: rotate when runningCount > 0
|
|
488
809
|
// Static: rotate when runningCount === 0 (inverse)
|
|
489
810
|
|
|
@@ -491,16 +812,17 @@ function updateCubeRotation() {
|
|
|
491
812
|
if (!cubeEl) return
|
|
492
813
|
var shouldRotate =
|
|
493
814
|
cubeMode === 'dynamic' ? runningCount > 0 : runningCount === 0
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
} else {
|
|
497
|
-
cubeEl.classList.remove('rotating')
|
|
498
|
-
}
|
|
815
|
+
cubeEl.classList.toggle('rotating', shouldRotate)
|
|
816
|
+
if (cubeStageEl) cubeStageEl.classList.toggle('rotating', shouldRotate)
|
|
499
817
|
}
|
|
500
818
|
|
|
501
819
|
// Apply initial state — re-evaluated on each WS message via updateCounts
|
|
502
820
|
updateCubeRotation()
|
|
503
821
|
|
|
822
|
+
// Apply the persisted mode/scale/window bounds as early as possible so a
|
|
823
|
+
// detail-mode boot doesn't flash at the default 220x130 size.
|
|
824
|
+
setMode(displayMode)
|
|
825
|
+
|
|
504
826
|
// Start the WebSocket connection
|
|
505
827
|
setWsStatus('connecting')
|
|
506
828
|
connectWebSocket()
|