@zythum02/fello-server 0.1.52 → 0.1.54
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/out/renderer/assets/{_baseUniq-C0L-SxO8.js → _baseUniq-DYINnBRJ.js} +1 -1
- package/out/renderer/assets/_baseUniq-DYINnBRJ.js.br +0 -0
- package/out/renderer/assets/_baseUniq-DYINnBRJ.js.gz +0 -0
- package/out/renderer/assets/{arc-bnlMIyYF.js → arc-BSUyw88k.js} +1 -1
- package/out/renderer/assets/arc-BSUyw88k.js.br +0 -0
- package/out/renderer/assets/arc-BSUyw88k.js.gz +0 -0
- package/out/renderer/assets/{architectureDiagram-Q4EWVU46-Cr0249Lu.js → architectureDiagram-Q4EWVU46-Cxb8DhYZ.js} +6 -6
- package/out/renderer/assets/architectureDiagram-Q4EWVU46-Cxb8DhYZ.js.br +0 -0
- package/out/renderer/assets/architectureDiagram-Q4EWVU46-Cxb8DhYZ.js.gz +0 -0
- package/out/renderer/assets/{arrow-left-D589pHHA.js → arrow-left-CQqe9rrj.js} +1 -1
- package/out/renderer/assets/arrow-up-1eI4tva4.js +21 -0
- package/out/renderer/assets/{automation-CvjrkE9z.js → automation-CQAOpWYp.js} +7 -8
- package/out/renderer/assets/automation-CQAOpWYp.js.br +0 -0
- package/out/renderer/assets/automation-CQAOpWYp.js.gz +0 -0
- package/out/renderer/assets/{blockDiagram-DXYQGD6D-Cw6vh5dx.js → blockDiagram-DXYQGD6D-CFozis-v.js} +7 -7
- package/out/renderer/assets/blockDiagram-DXYQGD6D-CFozis-v.js.br +0 -0
- package/out/renderer/assets/blockDiagram-DXYQGD6D-CFozis-v.js.gz +0 -0
- package/out/renderer/assets/{c4Diagram-AHTNJAMY-BUrvcyv2.js → c4Diagram-AHTNJAMY-CcDDkZUp.js} +3 -3
- package/out/renderer/assets/c4Diagram-AHTNJAMY-CcDDkZUp.js.br +0 -0
- package/out/renderer/assets/c4Diagram-AHTNJAMY-CcDDkZUp.js.gz +0 -0
- package/out/renderer/assets/{channel-DQr36qW5.js → channel-B-VC_ZcK.js} +1 -1
- package/out/renderer/assets/{chunk-4BX2VUAB-DOsXCDD7.js → chunk-4BX2VUAB-ClHmnOTC.js} +1 -1
- package/out/renderer/assets/{chunk-4TB4RGXK-D_fBnf0p.js → chunk-4TB4RGXK-mwOvn19G.js} +5 -5
- package/out/renderer/assets/chunk-4TB4RGXK-mwOvn19G.js.br +0 -0
- package/out/renderer/assets/chunk-4TB4RGXK-mwOvn19G.js.gz +0 -0
- package/out/renderer/assets/{chunk-55IACEB6-3ETNuedT.js → chunk-55IACEB6-CE8f6iip.js} +1 -1
- package/out/renderer/assets/{chunk-EDXVE4YY-BJLqHaER.js → chunk-EDXVE4YY-CU7aY96h.js} +1 -1
- package/out/renderer/assets/chunk-EDXVE4YY-CU7aY96h.js.br +0 -0
- package/out/renderer/assets/chunk-EDXVE4YY-CU7aY96h.js.gz +0 -0
- package/out/renderer/assets/{chunk-FMBD7UC4-DP-WGTNG.js → chunk-FMBD7UC4-B38kFkjv.js} +1 -1
- package/out/renderer/assets/{chunk-OYMX7WX6-CrS7loi7.js → chunk-OYMX7WX6-BriTCtaz.js} +3 -3
- package/out/renderer/assets/chunk-OYMX7WX6-BriTCtaz.js.br +0 -0
- package/out/renderer/assets/{chunk-OYMX7WX6-CrS7loi7.js.gz → chunk-OYMX7WX6-BriTCtaz.js.gz} +0 -0
- package/out/renderer/assets/{chunk-QZHKN3VN-C53USs5W.js → chunk-QZHKN3VN-BwJ37p5G.js} +1 -1
- package/out/renderer/assets/{chunk-YZCP3GAM-CMgdytZR.js → chunk-YZCP3GAM-BlHAYoQe.js} +1 -1
- package/out/renderer/assets/chunk-YZCP3GAM-BlHAYoQe.js.br +0 -0
- package/out/renderer/assets/chunk-YZCP3GAM-BlHAYoQe.js.gz +0 -0
- package/out/renderer/assets/{circle-x-OvXymUrf.js → circle-x-D_gJIgxf.js} +1 -1
- package/out/renderer/assets/{classDiagram-v2-HSJHXN6E-DIYtEiO5.js → classDiagram-6PBFFD2Q-D01ZMeaj.js} +7 -7
- package/out/renderer/assets/{classDiagram-6PBFFD2Q-DIYtEiO5.js → classDiagram-v2-HSJHXN6E-D01ZMeaj.js} +7 -7
- package/out/renderer/assets/{clone-D45P7Iqc.js → clone-qctAbdCx.js} +1 -1
- package/out/renderer/assets/{code-editor-SuOcN-5B.js → code-editor-tm0AYOLz.js} +2 -2
- package/out/renderer/assets/code-editor-tm0AYOLz.js.br +0 -0
- package/out/renderer/assets/code-editor-tm0AYOLz.js.gz +0 -0
- package/out/renderer/assets/{collapsible-Bd85ZCyx.js → collapsible-DD6NlDid.js} +1 -1
- package/out/renderer/assets/collapsible-DD6NlDid.js.br +0 -0
- package/out/renderer/assets/collapsible-DD6NlDid.js.gz +0 -0
- package/out/renderer/assets/command-BF4jOeoL.js +11 -0
- package/out/renderer/assets/{cose-bilkent-S5V4N54A-Dq8VllNT.js → cose-bilkent-S5V4N54A-CF4brbsf.js} +2 -2
- package/out/renderer/assets/cose-bilkent-S5V4N54A-CF4brbsf.js.br +0 -0
- package/out/renderer/assets/cose-bilkent-S5V4N54A-CF4brbsf.js.gz +0 -0
- package/out/renderer/assets/{dagre-KV5264BT-Dec8q4UT.js → dagre-KV5264BT-C6I5VgRp.js} +7 -7
- package/out/renderer/assets/dagre-KV5264BT-C6I5VgRp.js.br +0 -0
- package/out/renderer/assets/dagre-KV5264BT-C6I5VgRp.js.gz +0 -0
- package/out/renderer/assets/{diagram-5BDNPKRD-CzA2u_EN.js → diagram-5BDNPKRD-BAO72D5R.js} +7 -7
- package/out/renderer/assets/diagram-5BDNPKRD-BAO72D5R.js.br +0 -0
- package/out/renderer/assets/diagram-5BDNPKRD-BAO72D5R.js.gz +0 -0
- package/out/renderer/assets/{diagram-G4DWMVQ6-C8h3R7jD.js → diagram-G4DWMVQ6-BmpkrtJs.js} +7 -7
- package/out/renderer/assets/diagram-G4DWMVQ6-BmpkrtJs.js.br +0 -0
- package/out/renderer/assets/diagram-G4DWMVQ6-BmpkrtJs.js.gz +0 -0
- package/out/renderer/assets/{diagram-MMDJMWI5-9tiXSF90.js → diagram-MMDJMWI5-8keZZjgB.js} +6 -6
- package/out/renderer/assets/diagram-MMDJMWI5-8keZZjgB.js.br +0 -0
- package/out/renderer/assets/diagram-MMDJMWI5-8keZZjgB.js.gz +0 -0
- package/out/renderer/assets/{diagram-TYMM5635-BrarGJNf.js → diagram-TYMM5635-Be4uDvHI.js} +6 -6
- package/out/renderer/assets/diagram-TYMM5635-Be4uDvHI.js.br +0 -0
- package/out/renderer/assets/diagram-TYMM5635-Be4uDvHI.js.gz +0 -0
- package/out/renderer/assets/{ellipsis-BafkhboM.js → ellipsis-92s4sSUO.js} +1 -1
- package/out/renderer/assets/{erDiagram-SMLLAGMA-1Q9StK7L.js → erDiagram-SMLLAGMA-C6IgAbhi.js} +5 -5
- package/out/renderer/assets/erDiagram-SMLLAGMA-C6IgAbhi.js.br +0 -0
- package/out/renderer/assets/erDiagram-SMLLAGMA-C6IgAbhi.js.gz +0 -0
- package/out/renderer/assets/{field-ohYLdnJa.js → field-BPsDfe4e.js} +1 -1
- package/out/renderer/assets/field-BPsDfe4e.js.br +0 -0
- package/out/renderer/assets/field-BPsDfe4e.js.gz +0 -0
- package/out/renderer/assets/{file-text-CshHuHgW.js → file-text-ITbWr8iW.js} +1 -1
- package/out/renderer/assets/{flowDiagram-DWJPFMVM-CpcXVOmj.js → flowDiagram-DWJPFMVM-vbYKBn4t.js} +7 -7
- package/out/renderer/assets/flowDiagram-DWJPFMVM-vbYKBn4t.js.br +0 -0
- package/out/renderer/assets/flowDiagram-DWJPFMVM-vbYKBn4t.js.gz +0 -0
- package/out/renderer/assets/{ganttDiagram-T4ZO3ILL-C7Da4JBG.js → ganttDiagram-T4ZO3ILL-AxXIe9I4.js} +3 -3
- package/out/renderer/assets/ganttDiagram-T4ZO3ILL-AxXIe9I4.js.br +0 -0
- package/out/renderer/assets/ganttDiagram-T4ZO3ILL-AxXIe9I4.js.gz +0 -0
- package/out/renderer/assets/{gitGraphDiagram-UUTBAWPF-COBL52q_.js → gitGraphDiagram-UUTBAWPF-DSipARMB.js} +7 -7
- package/out/renderer/assets/gitGraphDiagram-UUTBAWPF-DSipARMB.js.br +0 -0
- package/out/renderer/assets/gitGraphDiagram-UUTBAWPF-DSipARMB.js.gz +0 -0
- package/out/renderer/assets/{graph-vKaAs6sc.js → graph-mNaHfg3r.js} +2 -2
- package/out/renderer/assets/graph-mNaHfg3r.js.br +0 -0
- package/out/renderer/assets/graph-mNaHfg3r.js.gz +0 -0
- package/out/renderer/assets/{highlighted-body-OFNGDK62-BGNnB1Ll.js → highlighted-body-OFNGDK62-8846XFj-.js} +2 -2
- package/out/renderer/assets/{index-BJPggXxf.js → index-BUwXrbHW.js} +1979 -663
- package/out/renderer/assets/index-BUwXrbHW.js.br +0 -0
- package/out/renderer/assets/index-BUwXrbHW.js.gz +0 -0
- package/out/renderer/assets/index-DOIzYXAl.css +382 -0
- package/out/renderer/assets/index-DOIzYXAl.css.br +0 -0
- package/out/renderer/assets/index-DOIzYXAl.css.gz +0 -0
- package/out/renderer/assets/{infoDiagram-42DDH7IO-z37e1cYq.js → infoDiagram-42DDH7IO-ThYxaM6U.js} +5 -5
- package/out/renderer/assets/infoDiagram-42DDH7IO-ThYxaM6U.js.br +0 -0
- package/out/renderer/assets/infoDiagram-42DDH7IO-ThYxaM6U.js.gz +0 -0
- package/out/renderer/assets/{ishikawaDiagram-UXIWVN3A-D0QTo3NZ.js → ishikawaDiagram-UXIWVN3A-EcWEDDQ3.js} +2 -2
- package/out/renderer/assets/ishikawaDiagram-UXIWVN3A-EcWEDDQ3.js.br +0 -0
- package/out/renderer/assets/ishikawaDiagram-UXIWVN3A-EcWEDDQ3.js.gz +0 -0
- package/out/renderer/assets/{item-Cv-tnX8b.js → item-Dph2aCdz.js} +20 -2
- package/out/renderer/assets/item-Dph2aCdz.js.br +0 -0
- package/out/renderer/assets/item-Dph2aCdz.js.gz +0 -0
- package/out/renderer/assets/{journeyDiagram-VCZTEJTY-CQV0gdjM.js → journeyDiagram-VCZTEJTY-Ct6VLkXK.js} +5 -5
- package/out/renderer/assets/journeyDiagram-VCZTEJTY-Ct6VLkXK.js.br +0 -0
- package/out/renderer/assets/journeyDiagram-VCZTEJTY-Ct6VLkXK.js.gz +0 -0
- package/out/renderer/assets/{kanban-definition-6JOO6SKY-DouRT6vc.js → kanban-definition-6JOO6SKY-DHWulQen.js} +3 -3
- package/out/renderer/assets/kanban-definition-6JOO6SKY-DHWulQen.js.br +0 -0
- package/out/renderer/assets/kanban-definition-6JOO6SKY-DHWulQen.js.gz +0 -0
- package/out/renderer/assets/{layout-BhbUjpvY.js → layout-pfquJ3N_.js} +4 -4
- package/out/renderer/assets/layout-pfquJ3N_.js.br +0 -0
- package/out/renderer/assets/layout-pfquJ3N_.js.gz +0 -0
- package/out/renderer/assets/{linear-D1WO10JK.js → linear-CdfVBcAB.js} +1 -1
- package/out/renderer/assets/linear-CdfVBcAB.js.br +0 -0
- package/out/renderer/assets/linear-CdfVBcAB.js.gz +0 -0
- package/out/renderer/assets/{link-2-C5KPDK2L.js → link-2-DpdZfD3m.js} +1 -1
- package/out/renderer/assets/{mermaid-GHXKKRXX-KwA2c0l5.js → mermaid-GHXKKRXX-CqMNodCp.js} +54 -54
- package/out/renderer/assets/mermaid-GHXKKRXX-CqMNodCp.js.br +0 -0
- package/out/renderer/assets/mermaid-GHXKKRXX-CqMNodCp.js.gz +0 -0
- package/out/renderer/assets/mic-CT1bYBEV.js +22 -0
- package/out/renderer/assets/{min-BP2C7bzG.js → min-CiK16GFr.js} +2 -2
- package/out/renderer/assets/min-CiK16GFr.js.br +0 -0
- package/out/renderer/assets/min-CiK16GFr.js.gz +0 -0
- package/out/renderer/assets/{mindmap-definition-QFDTVHPH-CxLYrjVp.js → mindmap-definition-QFDTVHPH-BvmM-Xdx.js} +4 -4
- package/out/renderer/assets/mindmap-definition-QFDTVHPH-BvmM-Xdx.js.br +0 -0
- package/out/renderer/assets/mindmap-definition-QFDTVHPH-BvmM-Xdx.js.gz +0 -0
- package/out/renderer/assets/{open-guide-UhaRhiI6.js → open-guide-BqiUQfrM.js} +1 -1
- package/out/renderer/assets/{package-search-DpyeQ5Lx.js → package-search-BxIuIl9F.js} +1 -1
- package/out/renderer/assets/{pieDiagram-DEJITSTG-D1LBRn_k.js → pieDiagram-DEJITSTG-CQY4NZ_4.js} +7 -7
- package/out/renderer/assets/pieDiagram-DEJITSTG-CQY4NZ_4.js.br +0 -0
- package/out/renderer/assets/pieDiagram-DEJITSTG-CQY4NZ_4.js.gz +0 -0
- package/out/renderer/assets/{plus-CsV_3veW.js → plus-C5XdFVFm.js} +1 -1
- package/out/renderer/assets/{quadrantDiagram-34T5L4WZ-89cdKeKP.js → quadrantDiagram-34T5L4WZ-BiDWKNht.js} +3 -3
- package/out/renderer/assets/quadrantDiagram-34T5L4WZ-BiDWKNht.js.br +0 -0
- package/out/renderer/assets/quadrantDiagram-34T5L4WZ-BiDWKNht.js.gz +0 -0
- package/out/renderer/assets/{requirementDiagram-MS252O5E-BPmX5cbr.js → requirementDiagram-MS252O5E-D-KxL9Tf.js} +4 -4
- package/out/renderer/assets/requirementDiagram-MS252O5E-D-KxL9Tf.js.br +0 -0
- package/out/renderer/assets/requirementDiagram-MS252O5E-D-KxL9Tf.js.gz +0 -0
- package/out/renderer/assets/{resizable-C_plViAK.js → resizable-ObbINbIB.js} +1 -1
- package/out/renderer/assets/resizable-ObbINbIB.js.br +0 -0
- package/out/renderer/assets/resizable-ObbINbIB.js.gz +0 -0
- package/out/renderer/assets/{sankeyDiagram-XADWPNL6-Cy6CP9QU.js → sankeyDiagram-XADWPNL6-BIFbqkzs.js} +2 -2
- package/out/renderer/assets/sankeyDiagram-XADWPNL6-BIFbqkzs.js.br +0 -0
- package/out/renderer/assets/sankeyDiagram-XADWPNL6-BIFbqkzs.js.gz +0 -0
- package/out/renderer/assets/{schedule-BRGzJU8Q.js → schedule-BtuArq_x.js} +9 -10
- package/out/renderer/assets/schedule-BtuArq_x.js.br +0 -0
- package/out/renderer/assets/schedule-BtuArq_x.js.gz +0 -0
- package/out/renderer/assets/{search-BHyqy--Q.js → search-TCnuQyCi.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-FGHM5R23-B3c7Za1w.js → sequenceDiagram-FGHM5R23-DQX-_zuj.js} +4 -4
- package/out/renderer/assets/sequenceDiagram-FGHM5R23-DQX-_zuj.js.br +0 -0
- package/out/renderer/assets/sequenceDiagram-FGHM5R23-DQX-_zuj.js.gz +0 -0
- package/out/renderer/assets/{session-DAyi31xW.js → session-C_1BpGhU.js} +1511 -263
- package/out/renderer/assets/session-C_1BpGhU.js.br +0 -0
- package/out/renderer/assets/session-C_1BpGhU.js.gz +0 -0
- package/out/renderer/assets/{setting-dialog-B9QpnCSy.js → setting-dialog-D1_-4H95.js} +3 -3
- package/out/renderer/assets/setting-dialog-D1_-4H95.js.br +0 -0
- package/out/renderer/assets/setting-dialog-D1_-4H95.js.gz +0 -0
- package/out/renderer/assets/{settings-2-DTnwbGMG.js → settings-2-BwfZrIw6.js} +1 -1
- package/out/renderer/assets/{settings-agents-BrAPSjkm.js → settings-agents-BtuYXQ1V.js} +26 -15
- package/out/renderer/assets/settings-agents-BtuYXQ1V.js.br +0 -0
- package/out/renderer/assets/settings-agents-BtuYXQ1V.js.gz +0 -0
- package/out/renderer/assets/{settings-general-Ck2OiZjy.js → settings-general-cHqsKFFa.js} +36 -3
- package/out/renderer/assets/settings-general-cHqsKFFa.js.br +0 -0
- package/out/renderer/assets/settings-general-cHqsKFFa.js.gz +0 -0
- package/out/renderer/assets/{settings-ilink-D0Br74W_.js → settings-ilink-BR1Vd9t9.js} +3 -3
- package/out/renderer/assets/settings-ilink-BR1Vd9t9.js.br +0 -0
- package/out/renderer/assets/settings-ilink-BR1Vd9t9.js.gz +0 -0
- package/out/renderer/assets/{settings-image-generation-BdyKoUUZ.js → settings-image-generation-MUHYnpbm.js} +6 -7
- package/out/renderer/assets/settings-image-generation-MUHYnpbm.js.br +0 -0
- package/out/renderer/assets/settings-image-generation-MUHYnpbm.js.gz +0 -0
- package/out/renderer/assets/{settings-layout-B7d1oQnz.js → settings-layout-SBihzFfb.js} +16 -3
- package/out/renderer/assets/settings-layout-SBihzFfb.js.br +0 -0
- package/out/renderer/assets/settings-layout-SBihzFfb.js.gz +0 -0
- package/out/renderer/assets/{settings-mcp-DtnVGpCh.js → settings-mcp-Co88s-0y.js} +8 -9
- package/out/renderer/assets/settings-mcp-Co88s-0y.js.br +0 -0
- package/out/renderer/assets/settings-mcp-Co88s-0y.js.gz +0 -0
- package/out/renderer/assets/{settings-memory-Bff_D3Id.js → settings-memory-CNH9gHYC.js} +2 -3
- package/out/renderer/assets/settings-memory-CNH9gHYC.js.br +0 -0
- package/out/renderer/assets/settings-memory-CNH9gHYC.js.gz +0 -0
- package/out/renderer/assets/settings-shortcuts-C1s7YIMj.js +267 -0
- package/out/renderer/assets/settings-shortcuts-C1s7YIMj.js.br +0 -0
- package/out/renderer/assets/settings-shortcuts-C1s7YIMj.js.gz +0 -0
- package/out/renderer/assets/{settings-snippets-CuwNZ684.js → settings-snippets-DGgI6mxm.js} +7 -8
- package/out/renderer/assets/settings-snippets-DGgI6mxm.js.br +0 -0
- package/out/renderer/assets/settings-snippets-DGgI6mxm.js.gz +0 -0
- package/out/renderer/assets/settings-speech-to-text-CV0xM7yz.js +1054 -0
- package/out/renderer/assets/settings-speech-to-text-CV0xM7yz.js.br +0 -0
- package/out/renderer/assets/settings-speech-to-text-CV0xM7yz.js.gz +0 -0
- package/out/renderer/assets/{settings-webui-CcjZQw6G.js → settings-webui-Bj9dJDcm.js} +2 -2
- package/out/renderer/assets/settings-webui-Bj9dJDcm.js.br +0 -0
- package/out/renderer/assets/settings-webui-Bj9dJDcm.js.gz +0 -0
- package/out/renderer/assets/{skills-installed-BR3EmTKD.js → skills-installed-Bhd5a33I.js} +4 -4
- package/out/renderer/assets/skills-installed-Bhd5a33I.js.br +0 -0
- package/out/renderer/assets/skills-installed-Bhd5a33I.js.gz +0 -0
- package/out/renderer/assets/{skills-layout-Cgy95TdD.js → skills-layout-DZFDa1cw.js} +2 -2
- package/out/renderer/assets/skills-layout-DZFDa1cw.js.br +0 -0
- package/out/renderer/assets/skills-layout-DZFDa1cw.js.gz +0 -0
- package/out/renderer/assets/{skills-skills-sh-7eO0Llg2.js → skills-skills-sh-DF59nekm.js} +4 -4
- package/out/renderer/assets/skills-skills-sh-DF59nekm.js.br +0 -0
- package/out/renderer/assets/skills-skills-sh-DF59nekm.js.gz +0 -0
- package/out/renderer/assets/{sortable.esm-BTWJnVbf.js → sortable.esm-BlhN8Kkg.js} +1 -1
- package/out/renderer/assets/sortable.esm-BlhN8Kkg.js.br +0 -0
- package/out/renderer/assets/sortable.esm-BlhN8Kkg.js.gz +0 -0
- package/out/renderer/assets/{standard-schema-Dk273X__.js → standard-schema-CGAs4bGi.js} +1 -1
- package/out/renderer/assets/standard-schema-CGAs4bGi.js.br +0 -0
- package/out/renderer/assets/standard-schema-CGAs4bGi.js.gz +0 -0
- package/out/renderer/assets/{stateDiagram-FHFEXIEX-C-7WuE0a.js → stateDiagram-FHFEXIEX-DappRrGm.js} +9 -9
- package/out/renderer/assets/stateDiagram-FHFEXIEX-DappRrGm.js.br +0 -0
- package/out/renderer/assets/stateDiagram-FHFEXIEX-DappRrGm.js.gz +0 -0
- package/out/renderer/assets/{stateDiagram-v2-QKLJ7IA2-IZRTgRo8.js → stateDiagram-v2-QKLJ7IA2-mbgJN2Ya.js} +5 -5
- package/out/renderer/assets/{task-Bd1x6VfK.js → task-C7tCZ6e3.js} +11 -12
- package/out/renderer/assets/task-C7tCZ6e3.js.br +0 -0
- package/out/renderer/assets/task-C7tCZ6e3.js.gz +0 -0
- package/out/renderer/assets/{textarea-CcqU8Ki7.js → textarea-DNSPhqFr.js} +2 -2
- package/out/renderer/assets/{timeline-definition-GMOUNBTQ-DVUMAatS.js → timeline-definition-GMOUNBTQ-o8XIUDyn.js} +3 -3
- package/out/renderer/assets/timeline-definition-GMOUNBTQ-o8XIUDyn.js.br +0 -0
- package/out/renderer/assets/timeline-definition-GMOUNBTQ-o8XIUDyn.js.gz +0 -0
- package/out/renderer/assets/{vennDiagram-DHZGUBPP-BtKdpgmE.js → vennDiagram-DHZGUBPP-mnc6bpmR.js} +2 -2
- package/out/renderer/assets/vennDiagram-DHZGUBPP-mnc6bpmR.js.br +0 -0
- package/out/renderer/assets/vennDiagram-DHZGUBPP-mnc6bpmR.js.gz +0 -0
- package/out/renderer/assets/{wardley-RL74JXVD-DRlpukah.js → wardley-RL74JXVD-wdJYeEiD.js} +4 -4
- package/out/renderer/assets/wardley-RL74JXVD-wdJYeEiD.js.br +0 -0
- package/out/renderer/assets/wardley-RL74JXVD-wdJYeEiD.js.gz +0 -0
- package/out/renderer/assets/{wardleyDiagram-NUSXRM2D-c_iDOO-3.js → wardleyDiagram-NUSXRM2D-Ddx6k7tJ.js} +6 -6
- package/out/renderer/assets/wardleyDiagram-NUSXRM2D-Ddx6k7tJ.js.br +0 -0
- package/out/renderer/assets/wardleyDiagram-NUSXRM2D-Ddx6k7tJ.js.gz +0 -0
- package/out/renderer/assets/{wrench-C-pOIUrz.js → wrench-BsjH8RPm.js} +1 -1
- package/out/renderer/assets/wrench-BsjH8RPm.js.br +0 -0
- package/out/renderer/assets/wrench-BsjH8RPm.js.gz +0 -0
- package/out/renderer/assets/{xlsx-view-Ca3bToM7.js → xlsx-view-CQd4jbk-.js} +21 -13
- package/out/renderer/assets/xlsx-view-CQd4jbk-.js.br +0 -0
- package/out/renderer/assets/xlsx-view-CQd4jbk-.js.gz +0 -0
- package/out/renderer/assets/{xychartDiagram-5P7HB3ND-D65drBbj.js → xychartDiagram-5P7HB3ND-VIQ9wuz0.js} +3 -3
- package/out/renderer/assets/xychartDiagram-5P7HB3ND-VIQ9wuz0.js.br +0 -0
- package/out/renderer/assets/xychartDiagram-5P7HB3ND-VIQ9wuz0.js.gz +0 -0
- package/out/renderer/index.html +2 -2
- package/out/renderer/index.html.br +0 -0
- package/out/renderer/index.html.gz +0 -0
- package/out/scripts/mcp-skills/server.mjs +1 -1
- package/out/server/main.js +290 -11
- package/package.json +2 -1
- package/resources/tree-sitter-wasm/tree-sitter-dart.wasm +0 -0
- package/out/renderer/assets/_baseUniq-C0L-SxO8.js.br +0 -0
- package/out/renderer/assets/_baseUniq-C0L-SxO8.js.gz +0 -0
- package/out/renderer/assets/arc-bnlMIyYF.js.br +0 -0
- package/out/renderer/assets/arc-bnlMIyYF.js.gz +0 -0
- package/out/renderer/assets/architectureDiagram-Q4EWVU46-Cr0249Lu.js.br +0 -0
- package/out/renderer/assets/architectureDiagram-Q4EWVU46-Cr0249Lu.js.gz +0 -0
- package/out/renderer/assets/automation-CvjrkE9z.js.br +0 -0
- package/out/renderer/assets/automation-CvjrkE9z.js.gz +0 -0
- package/out/renderer/assets/blockDiagram-DXYQGD6D-Cw6vh5dx.js.br +0 -0
- package/out/renderer/assets/blockDiagram-DXYQGD6D-Cw6vh5dx.js.gz +0 -0
- package/out/renderer/assets/c4Diagram-AHTNJAMY-BUrvcyv2.js.br +0 -0
- package/out/renderer/assets/c4Diagram-AHTNJAMY-BUrvcyv2.js.gz +0 -0
- package/out/renderer/assets/chunk-4TB4RGXK-D_fBnf0p.js.br +0 -0
- package/out/renderer/assets/chunk-4TB4RGXK-D_fBnf0p.js.gz +0 -0
- package/out/renderer/assets/chunk-EDXVE4YY-BJLqHaER.js.br +0 -0
- package/out/renderer/assets/chunk-EDXVE4YY-BJLqHaER.js.gz +0 -0
- package/out/renderer/assets/chunk-OYMX7WX6-CrS7loi7.js.br +0 -0
- package/out/renderer/assets/chunk-YZCP3GAM-CMgdytZR.js.br +0 -0
- package/out/renderer/assets/chunk-YZCP3GAM-CMgdytZR.js.gz +0 -0
- package/out/renderer/assets/clipboard-xI9lExaB.js +0 -15
- package/out/renderer/assets/code-editor-SuOcN-5B.js.br +0 -0
- package/out/renderer/assets/code-editor-SuOcN-5B.js.gz +0 -0
- package/out/renderer/assets/collapsible-Bd85ZCyx.js.br +0 -0
- package/out/renderer/assets/collapsible-Bd85ZCyx.js.gz +0 -0
- package/out/renderer/assets/context-menu-BO9-4FYd.js +0 -282
- package/out/renderer/assets/context-menu-BO9-4FYd.js.br +0 -0
- package/out/renderer/assets/context-menu-BO9-4FYd.js.gz +0 -0
- package/out/renderer/assets/cose-bilkent-S5V4N54A-Dq8VllNT.js.br +0 -0
- package/out/renderer/assets/cose-bilkent-S5V4N54A-Dq8VllNT.js.gz +0 -0
- package/out/renderer/assets/dagre-KV5264BT-Dec8q4UT.js.br +0 -0
- package/out/renderer/assets/dagre-KV5264BT-Dec8q4UT.js.gz +0 -0
- package/out/renderer/assets/diagram-5BDNPKRD-CzA2u_EN.js.br +0 -0
- package/out/renderer/assets/diagram-5BDNPKRD-CzA2u_EN.js.gz +0 -0
- package/out/renderer/assets/diagram-G4DWMVQ6-C8h3R7jD.js.br +0 -0
- package/out/renderer/assets/diagram-G4DWMVQ6-C8h3R7jD.js.gz +0 -0
- package/out/renderer/assets/diagram-MMDJMWI5-9tiXSF90.js.br +0 -0
- package/out/renderer/assets/diagram-MMDJMWI5-9tiXSF90.js.gz +0 -0
- package/out/renderer/assets/diagram-TYMM5635-BrarGJNf.js.br +0 -0
- package/out/renderer/assets/diagram-TYMM5635-BrarGJNf.js.gz +0 -0
- package/out/renderer/assets/erDiagram-SMLLAGMA-1Q9StK7L.js.br +0 -0
- package/out/renderer/assets/erDiagram-SMLLAGMA-1Q9StK7L.js.gz +0 -0
- package/out/renderer/assets/field-ohYLdnJa.js.br +0 -0
- package/out/renderer/assets/field-ohYLdnJa.js.gz +0 -0
- package/out/renderer/assets/flowDiagram-DWJPFMVM-CpcXVOmj.js.br +0 -0
- package/out/renderer/assets/flowDiagram-DWJPFMVM-CpcXVOmj.js.gz +0 -0
- package/out/renderer/assets/ganttDiagram-T4ZO3ILL-C7Da4JBG.js.br +0 -0
- package/out/renderer/assets/ganttDiagram-T4ZO3ILL-C7Da4JBG.js.gz +0 -0
- package/out/renderer/assets/gitGraphDiagram-UUTBAWPF-COBL52q_.js.br +0 -0
- package/out/renderer/assets/gitGraphDiagram-UUTBAWPF-COBL52q_.js.gz +0 -0
- package/out/renderer/assets/graph-vKaAs6sc.js.br +0 -0
- package/out/renderer/assets/graph-vKaAs6sc.js.gz +0 -0
- package/out/renderer/assets/index-BJPggXxf.js.br +0 -0
- package/out/renderer/assets/index-BJPggXxf.js.gz +0 -0
- package/out/renderer/assets/index-DGML4zYf.css +0 -382
- package/out/renderer/assets/index-DGML4zYf.css.br +0 -0
- package/out/renderer/assets/index-DGML4zYf.css.gz +0 -0
- package/out/renderer/assets/infoDiagram-42DDH7IO-z37e1cYq.js.br +0 -0
- package/out/renderer/assets/infoDiagram-42DDH7IO-z37e1cYq.js.gz +0 -0
- package/out/renderer/assets/ishikawaDiagram-UXIWVN3A-D0QTo3NZ.js.br +0 -0
- package/out/renderer/assets/ishikawaDiagram-UXIWVN3A-D0QTo3NZ.js.gz +0 -0
- package/out/renderer/assets/item-Cv-tnX8b.js.br +0 -0
- package/out/renderer/assets/item-Cv-tnX8b.js.gz +0 -0
- package/out/renderer/assets/journeyDiagram-VCZTEJTY-CQV0gdjM.js.br +0 -0
- package/out/renderer/assets/journeyDiagram-VCZTEJTY-CQV0gdjM.js.gz +0 -0
- package/out/renderer/assets/kanban-definition-6JOO6SKY-DouRT6vc.js.br +0 -0
- package/out/renderer/assets/kanban-definition-6JOO6SKY-DouRT6vc.js.gz +0 -0
- package/out/renderer/assets/layout-BhbUjpvY.js.br +0 -0
- package/out/renderer/assets/layout-BhbUjpvY.js.gz +0 -0
- package/out/renderer/assets/linear-D1WO10JK.js.br +0 -0
- package/out/renderer/assets/linear-D1WO10JK.js.gz +0 -0
- package/out/renderer/assets/mermaid-GHXKKRXX-KwA2c0l5.js.br +0 -0
- package/out/renderer/assets/mermaid-GHXKKRXX-KwA2c0l5.js.gz +0 -0
- package/out/renderer/assets/min-BP2C7bzG.js.br +0 -0
- package/out/renderer/assets/min-BP2C7bzG.js.gz +0 -0
- package/out/renderer/assets/mindmap-definition-QFDTVHPH-CxLYrjVp.js.br +0 -0
- package/out/renderer/assets/mindmap-definition-QFDTVHPH-CxLYrjVp.js.gz +0 -0
- package/out/renderer/assets/pieDiagram-DEJITSTG-D1LBRn_k.js.br +0 -0
- package/out/renderer/assets/pieDiagram-DEJITSTG-D1LBRn_k.js.gz +0 -0
- package/out/renderer/assets/quadrantDiagram-34T5L4WZ-89cdKeKP.js.br +0 -0
- package/out/renderer/assets/quadrantDiagram-34T5L4WZ-89cdKeKP.js.gz +0 -0
- package/out/renderer/assets/refresh-cw-CYW3HR-E.js +0 -11
- package/out/renderer/assets/requirementDiagram-MS252O5E-BPmX5cbr.js.br +0 -0
- package/out/renderer/assets/requirementDiagram-MS252O5E-BPmX5cbr.js.gz +0 -0
- package/out/renderer/assets/resizable-C_plViAK.js.br +0 -0
- package/out/renderer/assets/resizable-C_plViAK.js.gz +0 -0
- package/out/renderer/assets/sankeyDiagram-XADWPNL6-Cy6CP9QU.js.br +0 -0
- package/out/renderer/assets/sankeyDiagram-XADWPNL6-Cy6CP9QU.js.gz +0 -0
- package/out/renderer/assets/schedule-BRGzJU8Q.js.br +0 -0
- package/out/renderer/assets/schedule-BRGzJU8Q.js.gz +0 -0
- package/out/renderer/assets/sequenceDiagram-FGHM5R23-B3c7Za1w.js.br +0 -0
- package/out/renderer/assets/sequenceDiagram-FGHM5R23-B3c7Za1w.js.gz +0 -0
- package/out/renderer/assets/session-DAyi31xW.js.br +0 -0
- package/out/renderer/assets/session-DAyi31xW.js.gz +0 -0
- package/out/renderer/assets/setting-dialog-B9QpnCSy.js.br +0 -0
- package/out/renderer/assets/setting-dialog-B9QpnCSy.js.gz +0 -0
- package/out/renderer/assets/settings-agents-BrAPSjkm.js.br +0 -0
- package/out/renderer/assets/settings-agents-BrAPSjkm.js.gz +0 -0
- package/out/renderer/assets/settings-general-Ck2OiZjy.js.br +0 -0
- package/out/renderer/assets/settings-general-Ck2OiZjy.js.gz +0 -0
- package/out/renderer/assets/settings-ilink-D0Br74W_.js.br +0 -0
- package/out/renderer/assets/settings-ilink-D0Br74W_.js.gz +0 -0
- package/out/renderer/assets/settings-image-generation-BdyKoUUZ.js.br +0 -0
- package/out/renderer/assets/settings-image-generation-BdyKoUUZ.js.gz +0 -0
- package/out/renderer/assets/settings-layout-B7d1oQnz.js.br +0 -0
- package/out/renderer/assets/settings-layout-B7d1oQnz.js.gz +0 -0
- package/out/renderer/assets/settings-mcp-DtnVGpCh.js.br +0 -0
- package/out/renderer/assets/settings-mcp-DtnVGpCh.js.gz +0 -0
- package/out/renderer/assets/settings-memory-Bff_D3Id.js.br +0 -0
- package/out/renderer/assets/settings-memory-Bff_D3Id.js.gz +0 -0
- package/out/renderer/assets/settings-snippets-CuwNZ684.js.br +0 -0
- package/out/renderer/assets/settings-snippets-CuwNZ684.js.gz +0 -0
- package/out/renderer/assets/settings-webui-CcjZQw6G.js.br +0 -0
- package/out/renderer/assets/settings-webui-CcjZQw6G.js.gz +0 -0
- package/out/renderer/assets/skills-installed-BR3EmTKD.js.br +0 -0
- package/out/renderer/assets/skills-installed-BR3EmTKD.js.gz +0 -0
- package/out/renderer/assets/skills-layout-Cgy95TdD.js.br +0 -0
- package/out/renderer/assets/skills-layout-Cgy95TdD.js.gz +0 -0
- package/out/renderer/assets/skills-skills-sh-7eO0Llg2.js.br +0 -0
- package/out/renderer/assets/skills-skills-sh-7eO0Llg2.js.gz +0 -0
- package/out/renderer/assets/sortable.esm-BTWJnVbf.js.br +0 -0
- package/out/renderer/assets/sortable.esm-BTWJnVbf.js.gz +0 -0
- package/out/renderer/assets/standard-schema-Dk273X__.js.br +0 -0
- package/out/renderer/assets/standard-schema-Dk273X__.js.gz +0 -0
- package/out/renderer/assets/stateDiagram-FHFEXIEX-C-7WuE0a.js.br +0 -0
- package/out/renderer/assets/stateDiagram-FHFEXIEX-C-7WuE0a.js.gz +0 -0
- package/out/renderer/assets/task-Bd1x6VfK.js.br +0 -0
- package/out/renderer/assets/task-Bd1x6VfK.js.gz +0 -0
- package/out/renderer/assets/timeline-definition-GMOUNBTQ-DVUMAatS.js.br +0 -0
- package/out/renderer/assets/timeline-definition-GMOUNBTQ-DVUMAatS.js.gz +0 -0
- package/out/renderer/assets/vennDiagram-DHZGUBPP-BtKdpgmE.js.br +0 -0
- package/out/renderer/assets/vennDiagram-DHZGUBPP-BtKdpgmE.js.gz +0 -0
- package/out/renderer/assets/wardley-RL74JXVD-DRlpukah.js.br +0 -0
- package/out/renderer/assets/wardley-RL74JXVD-DRlpukah.js.gz +0 -0
- package/out/renderer/assets/wardleyDiagram-NUSXRM2D-c_iDOO-3.js.br +0 -0
- package/out/renderer/assets/wardleyDiagram-NUSXRM2D-c_iDOO-3.js.gz +0 -0
- package/out/renderer/assets/wrench-C-pOIUrz.js.br +0 -0
- package/out/renderer/assets/wrench-C-pOIUrz.js.gz +0 -0
- package/out/renderer/assets/xlsx-view-Ca3bToM7.js.br +0 -0
- package/out/renderer/assets/xlsx-view-Ca3bToM7.js.gz +0 -0
- package/out/renderer/assets/xychartDiagram-5P7HB3ND-D65drBbj.js.br +0 -0
- package/out/renderer/assets/xychartDiagram-5P7HB3ND-D65drBbj.js.gz +0 -0
|
@@ -1,37 +1,21 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./code-editor-
|
|
2
|
-
import { c as createLucideIcon, r as reactExports,
|
|
3
|
-
import { S as Settings2 } from "./settings-2-
|
|
4
|
-
import { i as isValidMessageToDisplay, M as MessageBubble, A as ArrowUpToLine, S as Square, j as jsonToPrettyYamlExports, p as parseFileReference, c as CodeCompareView, r as resolveFileUrl, I as ImageView, P as PdfView, D as DocxView, a as PptxView, X as XlsxView, R as RotateCcw, F as Folders } from "./xlsx-view-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { S as Search } from "./search-
|
|
12
|
-
import { E as ExternalLink } from "./link-2-
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
16
|
-
import "./
|
|
17
|
-
import "./item-Cv-tnX8b.js";
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./code-editor-tm0AYOLz.js","./index-BUwXrbHW.js","./index-DOIzYXAl.css","./mermaid-GHXKKRXX-CqMNodCp.js","./code-editor-BwxubRqT.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import { c as createLucideIcon, r as reactExports, av as formatErrorMessage, bz as ReactStore, bA as popupStoreSelectors, bB as triggerHover, au as triggerPress, bC as escapeKey, bD as attachPreventUnmountOnClose, bE as closePress, bF as PATIENT_CLICK_THRESHOLD, an as reactDomExports, bG as focusOut, bH as setPopupOpenState, bI as createInitialPopupStoreState, bJ as createPopupFloatingRootContext, bK as Timeout, bL as PopupTriggerMap, j as jsxRuntimeExports, bM as FloatingTree, bN as usePopupRootSync, bO as useImplicitActiveTrigger, bP as useOpenStateTransitions, at as createChangeEventDetails, bQ as imperativeAction, bR as PopupHandleAttachment, bS as usePopupRootStore, bT as useDismiss, bU as usePopupInteractionProps, bV as usePopupHandleStore, ar as useBaseUiId, bW as useTriggerDataForwarding, bX as useHoverReferenceInteraction, bY as safePolygon, bZ as useClick, b_ as useOpenMethodTriggerProps, az as useButton, b$ as useTriggerFocusGuards, ay as useRenderElement, c0 as CLICK_TRIGGER_IDENTIFIER, c1 as FocusGuard, c2 as pressableTriggerOpenStateMapping, c3 as triggerOpenStateMapping, c4 as FloatingPortal, c5 as POPUP_COLLISION_AVOIDANCE, c6 as useFloatingNodeId, aC as useAnimationsFinished, c7 as useAnchorPositioning, aD as useIsoLayoutEffect, c8 as useAnchoredPopupScrollLock, c9 as usePositioner, ca as InternalBackdrop, cb as inertValue, cc as FloatingNode, as as useStableCallback, cd as useToolbarRootContext, aE as useOpenChangeComplete, ce as useHoverFloatingInteraction, cf as createDefaultInitialFocus, cg as FOCUSABLE_POPUP_PROPS, bj as COMPOSITE_KEYS, ch as getDisabledMountTransitionStyles, ci as FloatingFocusManager, cj as isHTMLElement, ck as popupTransitionStateMapping, u as useTranslation, b as useMessage, X as useNavigate, a as useAppStore, f as request, g as extractErrorMessage, _ as Badge, cl as formatUpdatedTime, V as electron, aK as Tabs, aL as TabsList, aM as TabsTrigger, af as ALL_FEATURES, ag as FEATURE_I18N_KEYS, M as cn$1, d as Switch, B as Button, R as LoaderCircle, cm as buttonVariants, C as Check, e as Copy, i as isWebUI, U as FolderOpen, cn as restartSession, co as SessionLifecycleBusyError, cp as closeSession, h as copyText, cq as RestartSessionError, am as React, cr as Tooltip, cs as TooltipTrigger, ct as TooltipContent, cu as useFocusTarget, S as ScrollArea, a1 as Bot, cv as formatDuration, ao as getDefaultExportFromCjs, cw as ReactDOM, Y as subscribe, cx as clientId, A as DropdownMenu, E as DropdownMenuTrigger, cy as ChevronDown, F as DropdownMenuContent, G as DropdownMenuItem, cz as v$2, J as generateUUID, aP as reduceFlushStreaming, cA as HoverCard, cB as HoverCardTrigger, cC as HoverCardContent, cD as X$1, aR as Folder, L as Library, cE as DropdownMenuSub, cF as DropdownMenuSubTrigger, cG as DropdownMenuSubContent, cH as CircleQuestionMark, cI as ChevronUp, aQ as Clock, cJ as z$1, a0 as CircleCheck, cK as __vitePreload, I as Input, m as ContextMenuContent, n as ContextMenuItem, o as ContextMenuSeparator, cL as Code, bt as EDITOR_LABELS, k as ContextMenu, l as ContextMenuTrigger, aN as webUIBaseUrl, a6 as RefreshCw, a7 as ChevronRight, cM as MessageSquare, cN as FolderPlus, cO as Eye, P as Pencil, T as Trash2, cP as useProjectState, cQ as useFocusTargetRegistry, cR as TabsContent, cS as loadSession } from "./index-BUwXrbHW.js";
|
|
3
|
+
import { S as Settings2 } from "./settings-2-BwfZrIw6.js";
|
|
4
|
+
import { i as isValidMessageToDisplay, M as MessageBubble, A as ArrowUpToLine, S as Square, j as jsonToPrettyYamlExports, p as parseFileReference, c as CodeCompareView, r as resolveFileUrl, I as ImageView, P as PdfView, D as DocxView, a as PptxView, X as XlsxView, R as RotateCcw, F as Folders } from "./xlsx-view-CQd4jbk-.js";
|
|
5
|
+
import { a as ArrowDown, A as ArrowUp, b as ArrowRight } from "./arrow-up-1eI4tva4.js";
|
|
6
|
+
import { M as Mic, C as Clipboard } from "./mic-CT1bYBEV.js";
|
|
7
|
+
import { I as Image, W as Wrench } from "./wrench-BsjH8RPm.js";
|
|
8
|
+
import { F as FileText } from "./file-text-ITbWr8iW.js";
|
|
9
|
+
import { A as ArrowLeft } from "./arrow-left-CQqe9rrj.js";
|
|
10
|
+
import { aQ as CodeView, S as StreamMarkdown, aR as FileIcon } from "./mermaid-GHXKKRXX-CqMNodCp.js";
|
|
11
|
+
import { S as Search } from "./search-TCnuQyCi.js";
|
|
12
|
+
import { E as ExternalLink } from "./link-2-DpdZfD3m.js";
|
|
13
|
+
import { P as Plus } from "./plus-C5XdFVFm.js";
|
|
14
|
+
import { R as ResizablePanelGroup, a as ResizablePanel, b as ResizableHandle } from "./resizable-ObbINbIB.js";
|
|
15
|
+
import "./collapsible-DD6NlDid.js";
|
|
16
|
+
import "./item-Dph2aCdz.js";
|
|
18
17
|
import "./schemas-c0X-G5_P.js";
|
|
19
|
-
import "./ellipsis-
|
|
20
|
-
const __iconNode$k = [
|
|
21
|
-
["path", { d: "M12 5v14", key: "s699le" }],
|
|
22
|
-
["path", { d: "m19 12-7 7-7-7", key: "1idqje" }]
|
|
23
|
-
];
|
|
24
|
-
const ArrowDown = createLucideIcon("arrow-down", __iconNode$k);
|
|
25
|
-
const __iconNode$j = [
|
|
26
|
-
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
27
|
-
["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
|
|
28
|
-
];
|
|
29
|
-
const ArrowRight = createLucideIcon("arrow-right", __iconNode$j);
|
|
30
|
-
const __iconNode$i = [
|
|
31
|
-
["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
|
|
32
|
-
["path", { d: "M12 19V5", key: "x0mq9r" }]
|
|
33
|
-
];
|
|
34
|
-
const ArrowUp = createLucideIcon("arrow-up", __iconNode$i);
|
|
18
|
+
import "./ellipsis-92s4sSUO.js";
|
|
35
19
|
const __iconNode$h = [
|
|
36
20
|
[
|
|
37
21
|
"path",
|
|
@@ -816,76 +800,71 @@ function ChatHeader({ session }) {
|
|
|
816
800
|
const currentProjectInfo = projects.find((project) => project.id === currentProjectId);
|
|
817
801
|
const [localMcpServers, setLocalMcpServers] = reactExports.useState([]);
|
|
818
802
|
const [localFeatures, setLocalFeatures] = reactExports.useState([]);
|
|
803
|
+
const [isRestarting, setIsRestarting] = reactExports.useState(false);
|
|
819
804
|
const [isClosing, setIsClosing] = reactExports.useState(false);
|
|
820
805
|
const handleToggle = reactExports.useCallback((mcpId) => {
|
|
821
806
|
setLocalMcpServers(
|
|
822
807
|
(prev) => prev.includes(mcpId) ? prev.filter((id) => id !== mcpId) : [...prev, mcpId]
|
|
823
808
|
);
|
|
824
809
|
}, []);
|
|
810
|
+
const handlePermissionChange = reactExports.useCallback(
|
|
811
|
+
async (permissionMode) => {
|
|
812
|
+
try {
|
|
813
|
+
await request.updateSession({ sessionId: session.id, permissionMode });
|
|
814
|
+
} catch (err) {
|
|
815
|
+
console.error("Failed to update session permission:", err);
|
|
816
|
+
toast.error(
|
|
817
|
+
extractErrorMessage(err) || t("chatHeader.failedToUpdatePermission", "Failed to update permission.")
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
[session.id, t, toast]
|
|
822
|
+
);
|
|
825
823
|
const handleSyncAndRefresh = async () => {
|
|
826
|
-
if (!session) return;
|
|
824
|
+
if (!session || isClosing || isRestarting) return;
|
|
825
|
+
setIsRestarting(true);
|
|
827
826
|
try {
|
|
828
|
-
await
|
|
829
|
-
|
|
827
|
+
await restartSession({
|
|
828
|
+
session,
|
|
830
829
|
mcpServers: localMcpServers,
|
|
831
830
|
features: localFeatures
|
|
832
831
|
});
|
|
833
832
|
} catch (err) {
|
|
834
|
-
console.error("Failed to
|
|
835
|
-
|
|
836
|
-
extractErrorMessage(err) || t("chat.failedToUpdateMcpServers", "Failed to update MCP servers")
|
|
837
|
-
);
|
|
838
|
-
return;
|
|
839
|
-
}
|
|
840
|
-
const { resetSessionState, updateSessionState, updateSession } = useAppStore.getState();
|
|
841
|
-
try {
|
|
842
|
-
updateSession({ ...session, isStreaming: false });
|
|
843
|
-
updateSessionState(session.id, (prev) => reduceFlushStreaming(prev));
|
|
844
|
-
resetSessionState(session.id);
|
|
845
|
-
updateSessionState(session.id, () => ({ isLoading: true }));
|
|
846
|
-
const result = await request.getSessionHistory({ sessionId: session.id });
|
|
847
|
-
if (!result) return;
|
|
848
|
-
let state = useAppStore.getState().getSessionState(session.id);
|
|
849
|
-
state = { ...state, messages: [], activeToolCalls: /* @__PURE__ */ new Map(), activeSubagents: /* @__PURE__ */ new Map() };
|
|
850
|
-
for (const notification of result.messages) {
|
|
851
|
-
state = reduceSessionNotification(session.id, state, notification);
|
|
852
|
-
}
|
|
853
|
-
const displayIds = new Set(
|
|
854
|
-
result.messages.map((m) => m?.update?._meta?.fello?.displayId).filter(Boolean)
|
|
855
|
-
);
|
|
856
|
-
for (const notification of state.pendingNotifications) {
|
|
857
|
-
const did = notification.update._meta?.fello?.displayId;
|
|
858
|
-
if (did && displayIds.has(did)) continue;
|
|
859
|
-
state = reduceSessionNotification(session.id, state, notification);
|
|
860
|
-
}
|
|
861
|
-
state = {
|
|
862
|
-
...state,
|
|
863
|
-
pendingNotifications: [],
|
|
864
|
-
isLoading: false
|
|
865
|
-
};
|
|
866
|
-
updateSessionState(session.id, () => state);
|
|
867
|
-
request.loadSession({ sessionId: session.id, force: true }).catch((err) => {
|
|
868
|
-
console.error("Failed to load session:", err);
|
|
833
|
+
console.error("Failed to restart session:", err);
|
|
834
|
+
if (err instanceof SessionLifecycleBusyError) {
|
|
869
835
|
toast.error(
|
|
870
|
-
|
|
836
|
+
t(
|
|
837
|
+
"chatHeader.sessionOperationInProgress",
|
|
838
|
+
"Another session operation is already in progress."
|
|
839
|
+
)
|
|
871
840
|
);
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
const
|
|
876
|
-
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
const lifecycleError = err instanceof RestartSessionError ? err : null;
|
|
844
|
+
const cause = lifecycleError?.cause ?? err;
|
|
845
|
+
const fallback = lifecycleError?.stage === "update" ? t("chat.failedToUpdateMcpServers", "Failed to update MCP servers") : t("chat.failedToLoadSession", "Failed to load session.");
|
|
846
|
+
toast.error(extractErrorMessage(cause) || fallback);
|
|
877
847
|
} finally {
|
|
878
|
-
|
|
848
|
+
setIsRestarting(false);
|
|
879
849
|
}
|
|
880
850
|
};
|
|
881
851
|
const handleCloseSession = async () => {
|
|
882
|
-
if (isClosing) return;
|
|
852
|
+
if (isClosing || isRestarting) return;
|
|
883
853
|
setIsClosing(true);
|
|
884
854
|
try {
|
|
885
|
-
await
|
|
855
|
+
await closeSession(session.id);
|
|
886
856
|
navigate("/");
|
|
887
857
|
} catch (err) {
|
|
888
858
|
console.error("Failed to close session:", err);
|
|
859
|
+
if (err instanceof SessionLifecycleBusyError) {
|
|
860
|
+
toast.error(
|
|
861
|
+
t(
|
|
862
|
+
"chatHeader.sessionOperationInProgress",
|
|
863
|
+
"Another session operation is already in progress."
|
|
864
|
+
)
|
|
865
|
+
);
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
889
868
|
toast.error(
|
|
890
869
|
extractErrorMessage(err) || t("chatHeader.failedToCloseSession", "Failed to close session.")
|
|
891
870
|
);
|
|
@@ -904,7 +883,7 @@ function ChatHeader({ session }) {
|
|
|
904
883
|
children: [
|
|
905
884
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "px-1 text-[10px] uppercase select-none", children: session.agentId }),
|
|
906
885
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 min-w-0 items-baseline gap-2", children: [
|
|
907
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate text-[13px] font-normal text-sidebar-foreground/85", children: session.title || t("sidebar.
|
|
886
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate text-[13px] font-normal text-sidebar-foreground/85", children: session.title || t("sidebar.newSession", "New Session") }),
|
|
908
887
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 text-[10px] text-muted-foreground truncate", children: currentProjectInfo?.cwd }),
|
|
909
888
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-xs text-sidebar-foreground/70 whitespace-nowrap", children: formatUpdatedTime(session.updatedAt) })
|
|
910
889
|
] }),
|
|
@@ -921,21 +900,53 @@ function ChatHeader({ session }) {
|
|
|
921
900
|
},
|
|
922
901
|
children: [
|
|
923
902
|
/* @__PURE__ */ jsxRuntimeExports.jsx(PopoverTrigger, { className: "flex size-7 items-center justify-center rounded-md text-sidebar-foreground/45 hover:bg-sidebar-accent/30 hover:text-sidebar-foreground/70 outline-none transition-colors data-pressed:bg-sidebar-accent/40", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Settings2, { className: "size-4" }) }),
|
|
924
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(PopoverPortal, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(PopoverPositioner, { side: "bottom", align: "end", sideOffset: 4, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(PopoverPopup, { className: "z-10
|
|
925
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
903
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(PopoverPortal, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(PopoverPositioner, { side: "bottom", align: "end", sideOffset: 4, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(PopoverPopup, { className: "z-10 w-110 rounded-lg border border-border bg-popover text-popover-foreground shadow-lg outline-none p-1.5 origin-(--transform-origin) data-ending-style:scale-90 data-starting-style:scale-90 data-ending-style:opacity-0 data-starting-style:opacity-0 transition-[transform,opacity] duration-100", children: [
|
|
904
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-px py-1", children: [
|
|
905
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
906
|
+
CopyableRow,
|
|
907
|
+
{
|
|
908
|
+
label: t("chatHeader.sessionId", "Session"),
|
|
909
|
+
value: session.id,
|
|
910
|
+
openFolderTitle: t("chatHeader.openSessionFolder", "Open Session Folder"),
|
|
911
|
+
onOpenFolder: async () => {
|
|
912
|
+
const dirPath = await request.getSessionDataSystemPath({
|
|
913
|
+
sessionId: session.id
|
|
914
|
+
});
|
|
915
|
+
if (dirPath) electron.revealInFinder(dirPath);
|
|
916
|
+
}
|
|
936
917
|
}
|
|
918
|
+
) }),
|
|
919
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
920
|
+
CopyableRow,
|
|
921
|
+
{
|
|
922
|
+
label: t("chatHeader.projectId", "Project"),
|
|
923
|
+
value: currentProjectInfo?.cwd ?? session.projectTitle,
|
|
924
|
+
openFolderTitle: t("chatHeader.openProjectFolder", "Open Project Folder"),
|
|
925
|
+
onOpenFolder: async () => {
|
|
926
|
+
const dirPath = currentProjectInfo?.cwd;
|
|
927
|
+
if (dirPath) electron.revealInFinder(dirPath);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
) })
|
|
931
|
+
] }),
|
|
932
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t border-border/50 my-1" }),
|
|
933
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2 py-1 text-xs font-semibold text-foreground/80", children: t("sidebar.newSessionDialog.permission", "Permission") }),
|
|
934
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
935
|
+
Tabs,
|
|
936
|
+
{
|
|
937
|
+
value: session.permissionMode,
|
|
938
|
+
onValueChange: (value) => {
|
|
939
|
+
if (value === "ask" || value === "allow-all") {
|
|
940
|
+
void handlePermissionChange(value);
|
|
941
|
+
}
|
|
942
|
+
},
|
|
943
|
+
className: "w-full px-2 my-2",
|
|
944
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(TabsList, { className: "w-full", children: [
|
|
945
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "ask", className: "text-xs", children: t("sidebar.newSessionDialog.permissionAsk", "Ask") }),
|
|
946
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsTrigger, { value: "allow-all", className: "text-xs", children: t("sidebar.newSessionDialog.permissionAllowAll", "Allow all") })
|
|
947
|
+
] })
|
|
937
948
|
}
|
|
938
|
-
)
|
|
949
|
+
),
|
|
939
950
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border-t border-border/50 my-1" }),
|
|
940
951
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2 py-1 text-xs font-semibold text-foreground/80", children: t("constant.feature.title", "Features") }),
|
|
941
952
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: ALL_FEATURES.length >= 2 ? "grid grid-cols-2 gap-0.5" : "", children: ALL_FEATURES.map((feature) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
@@ -1011,14 +1022,17 @@ function ChatHeader({ session }) {
|
|
|
1011
1022
|
)
|
|
1012
1023
|
] }),
|
|
1013
1024
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex gap-1", children: [
|
|
1014
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
1025
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
1015
1026
|
Button,
|
|
1016
1027
|
{
|
|
1017
1028
|
size: "xs",
|
|
1018
1029
|
className: "flex flex-3 items-center gap-2 h-7 text-xs font-normal",
|
|
1019
1030
|
onClick: handleSyncAndRefresh,
|
|
1020
|
-
disabled: isClosing,
|
|
1021
|
-
children:
|
|
1031
|
+
disabled: isClosing || isRestarting,
|
|
1032
|
+
children: [
|
|
1033
|
+
isRestarting && /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3 animate-spin" }),
|
|
1034
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("chatHeader.refresh", "Restart Session") })
|
|
1035
|
+
]
|
|
1022
1036
|
}
|
|
1023
1037
|
),
|
|
1024
1038
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
@@ -1028,7 +1042,7 @@ function ChatHeader({ session }) {
|
|
|
1028
1042
|
variant: "destructive",
|
|
1029
1043
|
className: "flex flex-1 items-center gap-1.5 h-7 text-xs font-normal",
|
|
1030
1044
|
onClick: handleCloseSession,
|
|
1031
|
-
disabled: isClosing,
|
|
1045
|
+
disabled: isClosing || isRestarting,
|
|
1032
1046
|
children: [
|
|
1033
1047
|
isClosing && /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3 animate-spin" }),
|
|
1034
1048
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: isClosing ? t("chatHeader.closingSession", "Closing…") : t("chatHeader.closeSession", "Close Session") })
|
|
@@ -1162,23 +1176,23 @@ function CopyableRow({
|
|
|
1162
1176
|
":"
|
|
1163
1177
|
] }),
|
|
1164
1178
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 min-w-0 truncate font-mono text-muted-foreground/70 select-all", children: value }),
|
|
1165
|
-
|
|
1179
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1166
1180
|
"button",
|
|
1167
1181
|
{
|
|
1168
1182
|
type: "button",
|
|
1169
1183
|
className: "shrink-0 flex items-center justify-center size-5 rounded hover:bg-accent/50 text-muted-foreground/50 hover:text-muted-foreground transition-colors -mr-1",
|
|
1170
|
-
onClick:
|
|
1171
|
-
|
|
1172
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx(FolderOpen, { className: "size-3" })
|
|
1184
|
+
onClick: handleCopy,
|
|
1185
|
+
children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { className: "size-3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Copy, { className: "size-3" })
|
|
1173
1186
|
}
|
|
1174
1187
|
),
|
|
1175
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1188
|
+
!isWebUI && onOpenFolder && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1176
1189
|
"button",
|
|
1177
1190
|
{
|
|
1178
1191
|
type: "button",
|
|
1179
1192
|
className: "shrink-0 flex items-center justify-center size-5 rounded hover:bg-accent/50 text-muted-foreground/50 hover:text-muted-foreground transition-colors -mr-1",
|
|
1180
|
-
onClick:
|
|
1181
|
-
|
|
1193
|
+
onClick: onOpenFolder,
|
|
1194
|
+
title: openFolderTitle,
|
|
1195
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(FolderOpen, { className: "size-3" })
|
|
1182
1196
|
}
|
|
1183
1197
|
)
|
|
1184
1198
|
] });
|
|
@@ -1359,14 +1373,14 @@ function ChatTimeline({ items, activeDisplayId, onSelect: onSelect2 }) {
|
|
|
1359
1373
|
{
|
|
1360
1374
|
type: "button",
|
|
1361
1375
|
onClick: () => handleSelect(item.displayId),
|
|
1362
|
-
className: "p-1 group pointer-events-auto",
|
|
1376
|
+
className: "p-1 group/timeline pointer-events-auto outline-0",
|
|
1363
1377
|
"aria-label": ariaLabel,
|
|
1364
1378
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1365
1379
|
"div",
|
|
1366
1380
|
{
|
|
1367
1381
|
className: cn$1(
|
|
1368
|
-
"size-2 rounded-full transition-colors outline-none focus-visible:ring-
|
|
1369
|
-
isActive ? "bg-foreground/40" : "bg-muted-foreground/15 group-hover:bg-muted-foreground/40"
|
|
1382
|
+
"size-2 rounded-full transition-colors outline-none group-focus-visible/timeline:ring-1 group-focus-visible/timeline:ring-ring",
|
|
1383
|
+
isActive ? "bg-foreground/40" : "bg-muted-foreground/15 group-hover/timeline:bg-muted-foreground/40"
|
|
1370
1384
|
)
|
|
1371
1385
|
}
|
|
1372
1386
|
)
|
|
@@ -1425,6 +1439,12 @@ function ChatArea({ session }) {
|
|
|
1425
1439
|
const getViewport = reactExports.useCallback(() => {
|
|
1426
1440
|
return scrollAreaRef.current?.querySelector('[data-slot="scroll-area-viewport"]');
|
|
1427
1441
|
}, []);
|
|
1442
|
+
const focusChatArea = reactExports.useCallback(() => {
|
|
1443
|
+
const viewport = getViewport();
|
|
1444
|
+
if (!viewport) return;
|
|
1445
|
+
viewport.focus({ preventScroll: true });
|
|
1446
|
+
}, [getViewport]);
|
|
1447
|
+
useFocusTarget("chat-area", focusChatArea);
|
|
1428
1448
|
const scrollToBottom = reactExports.useCallback((behavior) => {
|
|
1429
1449
|
if (scrollTimeoutRef.current) {
|
|
1430
1450
|
clearTimeout(scrollTimeoutRef.current);
|
|
@@ -1695,7 +1715,7 @@ function ChatArea({ session }) {
|
|
|
1695
1715
|
const copyText$1 = reactExports.useCallback(async (text) => {
|
|
1696
1716
|
return copyText(text);
|
|
1697
1717
|
}, []);
|
|
1698
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full relative min-h-0 flex flex-1
|
|
1718
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full relative min-h-0 flex flex-1 group/chat-area", children: [
|
|
1699
1719
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 w-6 -mr-6 relative z-1 pointer-events-none", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
1700
1720
|
ChatTimeline,
|
|
1701
1721
|
{
|
|
@@ -1709,7 +1729,7 @@ function ChatArea({ session }) {
|
|
|
1709
1729
|
{
|
|
1710
1730
|
ref: scrollAreaRef,
|
|
1711
1731
|
className: "flex-1 w-full transform-gpu",
|
|
1712
|
-
viewportClassName: "animate-in fade-in",
|
|
1732
|
+
viewportClassName: "animate-in fade-in chat-area",
|
|
1713
1733
|
children: [
|
|
1714
1734
|
hasMore && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-10 py-3 max-w-5xl mx-auto", children: [
|
|
1715
1735
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 border-b border-dashed border-muted-foreground/30" }),
|
|
@@ -1879,7 +1899,8 @@ function ChatArea({ session }) {
|
|
|
1879
1899
|
"aria-label": t("chatArea.scrollToBottom", "Scroll to bottom"),
|
|
1880
1900
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowDown, { className: "size-4" })
|
|
1881
1901
|
}
|
|
1882
|
-
)
|
|
1902
|
+
),
|
|
1903
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pointer-events-none absolute -top-px left-0 right-0 h-px bg-linear-to-r from-ring/30 from-10% via-ring/80 via-30% to-ring/30 animate-out fill-mode-both fade-out ease-out duration-1500 hidden group-has-[.chat-area:focus-visible]/chat-area:block" })
|
|
1883
1904
|
] });
|
|
1884
1905
|
}
|
|
1885
1906
|
function _arrayWithoutHoles$1(arr) {
|
|
@@ -4314,6 +4335,669 @@ function nodesToMentionText(nodes) {
|
|
|
4314
4335
|
return `@[${prefix}${n.name}](${n.id})`;
|
|
4315
4336
|
}).join(" ");
|
|
4316
4337
|
}
|
|
4338
|
+
const TARGET_SAMPLE_RATE = 16e3;
|
|
4339
|
+
const FRAME_SAMPLES = 320;
|
|
4340
|
+
const workletSource = `
|
|
4341
|
+
class FelloPcmProcessor extends AudioWorkletProcessor {
|
|
4342
|
+
constructor() {
|
|
4343
|
+
super();
|
|
4344
|
+
this.buffer = [];
|
|
4345
|
+
this.position = 0;
|
|
4346
|
+
this.output = [];
|
|
4347
|
+
this.ratio = sampleRate / ${TARGET_SAMPLE_RATE};
|
|
4348
|
+
}
|
|
4349
|
+
process(inputs, outputs) {
|
|
4350
|
+
const input = inputs[0] && inputs[0][0];
|
|
4351
|
+
if (input) {
|
|
4352
|
+
for (let i = 0; i < input.length; i++) this.buffer.push(input[i]);
|
|
4353
|
+
while (this.position + 1 < this.buffer.length) {
|
|
4354
|
+
const index = Math.floor(this.position);
|
|
4355
|
+
const fraction = this.position - index;
|
|
4356
|
+
const sample = this.buffer[index] * (1 - fraction) + this.buffer[index + 1] * fraction;
|
|
4357
|
+
const clamped = Math.max(-1, Math.min(1, sample));
|
|
4358
|
+
this.output.push(clamped < 0 ? clamped * 32768 : clamped * 32767);
|
|
4359
|
+
this.position += this.ratio;
|
|
4360
|
+
if (this.output.length >= ${FRAME_SAMPLES}) {
|
|
4361
|
+
const pcm = new Int16Array(${FRAME_SAMPLES});
|
|
4362
|
+
for (let i = 0; i < ${FRAME_SAMPLES}; i++) pcm[i] = this.output[i];
|
|
4363
|
+
this.output = this.output.slice(${FRAME_SAMPLES});
|
|
4364
|
+
this.port.postMessage(pcm.buffer, [pcm.buffer]);
|
|
4365
|
+
}
|
|
4366
|
+
}
|
|
4367
|
+
const remove = Math.max(0, Math.floor(this.position));
|
|
4368
|
+
if (remove > 0) {
|
|
4369
|
+
this.buffer = this.buffer.slice(remove);
|
|
4370
|
+
this.position -= remove;
|
|
4371
|
+
}
|
|
4372
|
+
}
|
|
4373
|
+
const output = outputs[0] && outputs[0][0];
|
|
4374
|
+
if (output) output.fill(0);
|
|
4375
|
+
return true;
|
|
4376
|
+
}
|
|
4377
|
+
}
|
|
4378
|
+
registerProcessor("fello-pcm-processor", FelloPcmProcessor);
|
|
4379
|
+
`;
|
|
4380
|
+
function arrayBufferToBase64(buffer) {
|
|
4381
|
+
const bytes = new Uint8Array(buffer);
|
|
4382
|
+
let binary = "";
|
|
4383
|
+
const chunkSize = 32768;
|
|
4384
|
+
for (let offset = 0; offset < bytes.length; offset += chunkSize) {
|
|
4385
|
+
binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));
|
|
4386
|
+
}
|
|
4387
|
+
return btoa(binary);
|
|
4388
|
+
}
|
|
4389
|
+
function errorMessage(error) {
|
|
4390
|
+
return error instanceof Error ? error.message : String(error);
|
|
4391
|
+
}
|
|
4392
|
+
function useRealtimeAsr(options) {
|
|
4393
|
+
const { onTranscript, onError, onRecordingChange } = options;
|
|
4394
|
+
const configured = useAppStore((state) => state.speechToText.some((provider) => provider.active));
|
|
4395
|
+
const [recording, setRecording] = reactExports.useState(false);
|
|
4396
|
+
const [audioLevel, setAudioLevel] = reactExports.useState(0);
|
|
4397
|
+
const [inputDevices, setInputDevices] = reactExports.useState([]);
|
|
4398
|
+
const asrSessionIdRef = reactExports.useRef(null);
|
|
4399
|
+
const streamRef = reactExports.useRef(null);
|
|
4400
|
+
const audioContextRef = reactExports.useRef(null);
|
|
4401
|
+
const sourceRef = reactExports.useRef(null);
|
|
4402
|
+
const nodeRef = reactExports.useRef(null);
|
|
4403
|
+
const stoppedRef = reactExports.useRef(false);
|
|
4404
|
+
const stoppingRef = reactExports.useRef(false);
|
|
4405
|
+
const recordingRef = reactExports.useRef(false);
|
|
4406
|
+
const audioLevelValueRef = reactExports.useRef(0);
|
|
4407
|
+
const audioLevelFrameRef = reactExports.useRef(null);
|
|
4408
|
+
const stopRef = reactExports.useRef(async () => {
|
|
4409
|
+
});
|
|
4410
|
+
const callbacksRef = reactExports.useRef({ onTranscript, onError, onRecordingChange });
|
|
4411
|
+
callbacksRef.current = { onTranscript, onError, onRecordingChange };
|
|
4412
|
+
const setRecordingState = reactExports.useCallback((value) => {
|
|
4413
|
+
recordingRef.current = value;
|
|
4414
|
+
setRecording(value);
|
|
4415
|
+
callbacksRef.current.onRecordingChange?.(value);
|
|
4416
|
+
}, []);
|
|
4417
|
+
reactExports.useEffect(() => {
|
|
4418
|
+
const handleTranscript = (event) => {
|
|
4419
|
+
if (event.clientId !== clientId || event.asrSessionId !== asrSessionIdRef.current) return;
|
|
4420
|
+
callbacksRef.current.onTranscript?.({
|
|
4421
|
+
text: event.text,
|
|
4422
|
+
isFinal: event.isFinal,
|
|
4423
|
+
id: event.id,
|
|
4424
|
+
index: event.index
|
|
4425
|
+
});
|
|
4426
|
+
};
|
|
4427
|
+
const handleError = (event) => {
|
|
4428
|
+
if (event.clientId !== clientId || event.asrSessionId !== asrSessionIdRef.current) return;
|
|
4429
|
+
callbacksRef.current.onError?.(event.message);
|
|
4430
|
+
};
|
|
4431
|
+
const handleClosed = (event) => {
|
|
4432
|
+
if (event.clientId !== clientId || event.asrSessionId !== asrSessionIdRef.current) return;
|
|
4433
|
+
if (recordingRef.current && !stoppingRef.current) {
|
|
4434
|
+
callbacksRef.current.onError?.("实时语音识别连接已关闭。");
|
|
4435
|
+
void stopRef.current();
|
|
4436
|
+
}
|
|
4437
|
+
};
|
|
4438
|
+
subscribe.on("asr-transcript", handleTranscript);
|
|
4439
|
+
subscribe.on("asr-error", handleError);
|
|
4440
|
+
subscribe.on("asr-closed", handleClosed);
|
|
4441
|
+
return () => {
|
|
4442
|
+
subscribe.off("asr-transcript", handleTranscript);
|
|
4443
|
+
subscribe.off("asr-error", handleError);
|
|
4444
|
+
subscribe.off("asr-closed", handleClosed);
|
|
4445
|
+
};
|
|
4446
|
+
}, [setRecordingState]);
|
|
4447
|
+
const updateAudioLevel = reactExports.useCallback((buffer) => {
|
|
4448
|
+
const samples = new Int16Array(buffer);
|
|
4449
|
+
if (samples.length === 0) return;
|
|
4450
|
+
let sumSquares = 0;
|
|
4451
|
+
for (const sample of samples) {
|
|
4452
|
+
const normalized = sample / 32768;
|
|
4453
|
+
sumSquares += normalized * normalized;
|
|
4454
|
+
}
|
|
4455
|
+
const rms = Math.sqrt(sumSquares / samples.length);
|
|
4456
|
+
audioLevelValueRef.current = Math.min(1, rms * 4);
|
|
4457
|
+
if (audioLevelFrameRef.current !== null) return;
|
|
4458
|
+
audioLevelFrameRef.current = requestAnimationFrame(() => {
|
|
4459
|
+
audioLevelFrameRef.current = null;
|
|
4460
|
+
setAudioLevel(audioLevelValueRef.current);
|
|
4461
|
+
});
|
|
4462
|
+
}, []);
|
|
4463
|
+
const cleanupAudio = reactExports.useCallback(async () => {
|
|
4464
|
+
if (audioLevelFrameRef.current !== null) {
|
|
4465
|
+
cancelAnimationFrame(audioLevelFrameRef.current);
|
|
4466
|
+
audioLevelFrameRef.current = null;
|
|
4467
|
+
}
|
|
4468
|
+
audioLevelValueRef.current = 0;
|
|
4469
|
+
setAudioLevel(0);
|
|
4470
|
+
nodeRef.current?.disconnect();
|
|
4471
|
+
sourceRef.current?.disconnect();
|
|
4472
|
+
streamRef.current?.getTracks().forEach((track) => track.stop());
|
|
4473
|
+
streamRef.current = null;
|
|
4474
|
+
nodeRef.current = null;
|
|
4475
|
+
sourceRef.current = null;
|
|
4476
|
+
const context = audioContextRef.current;
|
|
4477
|
+
audioContextRef.current = null;
|
|
4478
|
+
await context?.close().catch(() => void 0);
|
|
4479
|
+
}, []);
|
|
4480
|
+
const refreshInputDevices = reactExports.useCallback(async () => {
|
|
4481
|
+
if (!navigator.mediaDevices?.enumerateDevices) return [];
|
|
4482
|
+
try {
|
|
4483
|
+
let devices = await navigator.mediaDevices.enumerateDevices();
|
|
4484
|
+
if (devices.length > 0 && devices.every((device) => !device.label)) {
|
|
4485
|
+
try {
|
|
4486
|
+
const permissionStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
4487
|
+
permissionStream.getTracks().forEach((track) => track.stop());
|
|
4488
|
+
devices = await navigator.mediaDevices.enumerateDevices();
|
|
4489
|
+
} catch {
|
|
4490
|
+
}
|
|
4491
|
+
}
|
|
4492
|
+
const audioInputs = devices.filter((device) => device.kind === "audioinput").map((device, index) => ({
|
|
4493
|
+
deviceId: device.deviceId,
|
|
4494
|
+
label: device.label || `Microphone ${index + 1}`
|
|
4495
|
+
}));
|
|
4496
|
+
setInputDevices(audioInputs);
|
|
4497
|
+
return audioInputs;
|
|
4498
|
+
} catch (error) {
|
|
4499
|
+
callbacksRef.current.onError?.(errorMessage(error));
|
|
4500
|
+
return [];
|
|
4501
|
+
}
|
|
4502
|
+
}, []);
|
|
4503
|
+
const start = reactExports.useCallback(
|
|
4504
|
+
async (deviceId = "default") => {
|
|
4505
|
+
if (recordingRef.current || !configured) return;
|
|
4506
|
+
const asrSessionId = `asr_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
4507
|
+
asrSessionIdRef.current = asrSessionId;
|
|
4508
|
+
stoppedRef.current = false;
|
|
4509
|
+
stoppingRef.current = false;
|
|
4510
|
+
try {
|
|
4511
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
4512
|
+
audio: {
|
|
4513
|
+
channelCount: 1,
|
|
4514
|
+
echoCancellation: true,
|
|
4515
|
+
noiseSuppression: true,
|
|
4516
|
+
...deviceId !== "default" ? { deviceId: { exact: deviceId } } : {}
|
|
4517
|
+
}
|
|
4518
|
+
});
|
|
4519
|
+
streamRef.current = stream;
|
|
4520
|
+
const audioContext = new AudioContext();
|
|
4521
|
+
audioContextRef.current = audioContext;
|
|
4522
|
+
await audioContext.resume();
|
|
4523
|
+
const workletUrl = URL.createObjectURL(
|
|
4524
|
+
new Blob([workletSource], { type: "application/javascript" })
|
|
4525
|
+
);
|
|
4526
|
+
try {
|
|
4527
|
+
await audioContext.audioWorklet.addModule(workletUrl);
|
|
4528
|
+
} finally {
|
|
4529
|
+
URL.revokeObjectURL(workletUrl);
|
|
4530
|
+
}
|
|
4531
|
+
const source = audioContext.createMediaStreamSource(stream);
|
|
4532
|
+
const node = new AudioWorkletNode(audioContext, "fello-pcm-processor");
|
|
4533
|
+
const silentGain = audioContext.createGain();
|
|
4534
|
+
silentGain.gain.value = 0;
|
|
4535
|
+
node.port.onmessage = (message) => {
|
|
4536
|
+
if (stoppedRef.current || asrSessionIdRef.current !== asrSessionId) return;
|
|
4537
|
+
updateAudioLevel(message.data);
|
|
4538
|
+
void request.sendRealtimeAsrFrame({
|
|
4539
|
+
clientId,
|
|
4540
|
+
asrSessionId,
|
|
4541
|
+
audioB64: arrayBufferToBase64(message.data)
|
|
4542
|
+
}).catch((error) => callbacksRef.current.onError?.(errorMessage(error)));
|
|
4543
|
+
};
|
|
4544
|
+
sourceRef.current = source;
|
|
4545
|
+
nodeRef.current = node;
|
|
4546
|
+
await request.startRealtimeAsr({ clientId, asrSessionId });
|
|
4547
|
+
source.connect(node);
|
|
4548
|
+
node.connect(silentGain);
|
|
4549
|
+
silentGain.connect(audioContext.destination);
|
|
4550
|
+
setRecordingState(true);
|
|
4551
|
+
} catch (error) {
|
|
4552
|
+
await cleanupAudio();
|
|
4553
|
+
await request.stopRealtimeAsr({ clientId, asrSessionId }).catch(() => void 0);
|
|
4554
|
+
asrSessionIdRef.current = null;
|
|
4555
|
+
callbacksRef.current.onError?.(errorMessage(error));
|
|
4556
|
+
setRecordingState(false);
|
|
4557
|
+
}
|
|
4558
|
+
},
|
|
4559
|
+
[cleanupAudio, configured, setRecordingState, updateAudioLevel]
|
|
4560
|
+
);
|
|
4561
|
+
const stop = reactExports.useCallback(async () => {
|
|
4562
|
+
const asrSessionId = asrSessionIdRef.current;
|
|
4563
|
+
if (!asrSessionId) return;
|
|
4564
|
+
stoppedRef.current = true;
|
|
4565
|
+
stoppingRef.current = true;
|
|
4566
|
+
await cleanupAudio();
|
|
4567
|
+
await request.stopRealtimeAsr({ clientId, asrSessionId }).catch((error) => {
|
|
4568
|
+
callbacksRef.current.onError?.(errorMessage(error));
|
|
4569
|
+
});
|
|
4570
|
+
asrSessionIdRef.current = null;
|
|
4571
|
+
stoppingRef.current = false;
|
|
4572
|
+
setRecordingState(false);
|
|
4573
|
+
}, [cleanupAudio, setRecordingState]);
|
|
4574
|
+
stopRef.current = stop;
|
|
4575
|
+
reactExports.useEffect(() => {
|
|
4576
|
+
return () => {
|
|
4577
|
+
stoppedRef.current = true;
|
|
4578
|
+
void stopRef.current();
|
|
4579
|
+
};
|
|
4580
|
+
}, []);
|
|
4581
|
+
const toggle = reactExports.useCallback(() => {
|
|
4582
|
+
void (recordingRef.current ? stop() : start());
|
|
4583
|
+
}, [start, stop]);
|
|
4584
|
+
return {
|
|
4585
|
+
recording,
|
|
4586
|
+
audioLevel,
|
|
4587
|
+
configured,
|
|
4588
|
+
inputDevices,
|
|
4589
|
+
refreshInputDevices,
|
|
4590
|
+
start,
|
|
4591
|
+
stop,
|
|
4592
|
+
toggle
|
|
4593
|
+
};
|
|
4594
|
+
}
|
|
4595
|
+
const ASR_WAVEFORM_BARS = [0.35, 0.65, 0.95, 0.55, 0.8, 0.45, 0.9, 0.6, 0.38];
|
|
4596
|
+
const DEFAULT_MAX_DURATION = 5 * 60 * 1e3;
|
|
4597
|
+
const ALT_DOUBLE_PRESS_WINDOW = 350;
|
|
4598
|
+
const VOICE_INPUT_DEVICE_STORAGE_KEY = "fello.voice-input.device-id";
|
|
4599
|
+
let activeVoiceRecording = null;
|
|
4600
|
+
let voiceRecordingStartChain = Promise.resolve();
|
|
4601
|
+
function getInputCursor(input) {
|
|
4602
|
+
return input.selectionStart ?? input.value.length;
|
|
4603
|
+
}
|
|
4604
|
+
function VoiceInputButton({
|
|
4605
|
+
inputRef,
|
|
4606
|
+
disabled = false,
|
|
4607
|
+
className,
|
|
4608
|
+
maxDuration = DEFAULT_MAX_DURATION,
|
|
4609
|
+
ref
|
|
4610
|
+
}) {
|
|
4611
|
+
const { t } = useTranslation();
|
|
4612
|
+
const { toast } = useMessage();
|
|
4613
|
+
const altDoublePressEnabled = useAppStore((state) => state.voiceInput.altDoublePress);
|
|
4614
|
+
const [instanceId] = reactExports.useState(() => /* @__PURE__ */ Symbol("VoiceInputButton"));
|
|
4615
|
+
const stopAsrRef = reactExports.useRef(() => Promise.resolve());
|
|
4616
|
+
const asrApplyingRef = reactExports.useRef(false);
|
|
4617
|
+
const asrSegmentsRef = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
4618
|
+
const asrTailRef = reactExports.useRef(0);
|
|
4619
|
+
const asrCurrentKeyRef = reactExports.useRef(null);
|
|
4620
|
+
const asrSequenceRef = reactExports.useRef(0);
|
|
4621
|
+
const lastAltTapAtRef = reactExports.useRef(null);
|
|
4622
|
+
const suppressAltUntilRef = reactExports.useRef(0);
|
|
4623
|
+
const freezeAsrSegments = reactExports.useCallback(() => {
|
|
4624
|
+
asrSegmentsRef.current.clear();
|
|
4625
|
+
asrCurrentKeyRef.current = null;
|
|
4626
|
+
const textarea = inputRef.current;
|
|
4627
|
+
if (textarea) asrTailRef.current = getInputCursor(textarea);
|
|
4628
|
+
}, [inputRef]);
|
|
4629
|
+
const applyAsrTranscript = reactExports.useCallback(
|
|
4630
|
+
(transcript) => {
|
|
4631
|
+
const textarea = inputRef.current;
|
|
4632
|
+
if (!textarea) return;
|
|
4633
|
+
const key = transcript.id ? `id:${transcript.id}` : transcript.index !== void 0 ? `index:${transcript.index}` : asrCurrentKeyRef.current ?? `stream:${asrSequenceRef.current++}`;
|
|
4634
|
+
let segment = asrSegmentsRef.current.get(key);
|
|
4635
|
+
if (!segment) {
|
|
4636
|
+
segment = { start: asrTailRef.current, length: 0 };
|
|
4637
|
+
asrSegmentsRef.current.set(key, segment);
|
|
4638
|
+
asrCurrentKeyRef.current = key;
|
|
4639
|
+
}
|
|
4640
|
+
textarea.focus();
|
|
4641
|
+
textarea.setSelectionRange(segment.start, segment.start + segment.length);
|
|
4642
|
+
asrApplyingRef.current = true;
|
|
4643
|
+
try {
|
|
4644
|
+
document.execCommand("insertText", false, transcript.text);
|
|
4645
|
+
} finally {
|
|
4646
|
+
asrApplyingRef.current = false;
|
|
4647
|
+
}
|
|
4648
|
+
textarea.ownerDocument.dispatchEvent(new Event("selectionchange"));
|
|
4649
|
+
segment.length = transcript.text.length;
|
|
4650
|
+
asrTailRef.current = segment.start + segment.length;
|
|
4651
|
+
if (transcript.isFinal) {
|
|
4652
|
+
asrSegmentsRef.current.delete(key);
|
|
4653
|
+
asrCurrentKeyRef.current = null;
|
|
4654
|
+
}
|
|
4655
|
+
},
|
|
4656
|
+
[inputRef]
|
|
4657
|
+
);
|
|
4658
|
+
const handleRecordingChange = reactExports.useCallback(
|
|
4659
|
+
(recording) => {
|
|
4660
|
+
if (recording) {
|
|
4661
|
+
activeVoiceRecording = {
|
|
4662
|
+
owner: instanceId,
|
|
4663
|
+
stop: () => stopAsrRef.current()
|
|
4664
|
+
};
|
|
4665
|
+
} else {
|
|
4666
|
+
freezeAsrSegments();
|
|
4667
|
+
if (activeVoiceRecording?.owner === instanceId) {
|
|
4668
|
+
activeVoiceRecording = null;
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
},
|
|
4672
|
+
[freezeAsrSegments, instanceId]
|
|
4673
|
+
);
|
|
4674
|
+
const asr = useRealtimeAsr({
|
|
4675
|
+
onTranscript: applyAsrTranscript,
|
|
4676
|
+
onError: (message) => toast.error(message),
|
|
4677
|
+
onRecordingChange: handleRecordingChange
|
|
4678
|
+
});
|
|
4679
|
+
const { start: startAsr, stop: stopAsr, refreshInputDevices } = asr;
|
|
4680
|
+
const handleStop = reactExports.useCallback(async () => {
|
|
4681
|
+
await stopAsr();
|
|
4682
|
+
}, [stopAsr]);
|
|
4683
|
+
stopAsrRef.current = handleStop;
|
|
4684
|
+
reactExports.useImperativeHandle(
|
|
4685
|
+
ref,
|
|
4686
|
+
() => ({
|
|
4687
|
+
stop: handleStop
|
|
4688
|
+
}),
|
|
4689
|
+
[handleStop]
|
|
4690
|
+
);
|
|
4691
|
+
const handleStart = reactExports.useCallback(
|
|
4692
|
+
async (deviceId) => {
|
|
4693
|
+
const startOperation = voiceRecordingStartChain.then(async () => {
|
|
4694
|
+
await activeVoiceRecording?.stop();
|
|
4695
|
+
const textarea = inputRef.current;
|
|
4696
|
+
if (!textarea) return;
|
|
4697
|
+
textarea.focus();
|
|
4698
|
+
const cursorPosition = getInputCursor(textarea);
|
|
4699
|
+
const before = textarea.value.slice(0, cursorPosition);
|
|
4700
|
+
if (before.length > 0 && !/\s$/.test(before)) {
|
|
4701
|
+
asrApplyingRef.current = true;
|
|
4702
|
+
try {
|
|
4703
|
+
document.execCommand("insertText", false, " ");
|
|
4704
|
+
} finally {
|
|
4705
|
+
asrApplyingRef.current = false;
|
|
4706
|
+
}
|
|
4707
|
+
}
|
|
4708
|
+
asrSegmentsRef.current.clear();
|
|
4709
|
+
asrCurrentKeyRef.current = null;
|
|
4710
|
+
asrTailRef.current = getInputCursor(textarea);
|
|
4711
|
+
await startAsr(deviceId);
|
|
4712
|
+
});
|
|
4713
|
+
voiceRecordingStartChain = startOperation.catch(() => void 0);
|
|
4714
|
+
await startOperation;
|
|
4715
|
+
},
|
|
4716
|
+
[startAsr, inputRef]
|
|
4717
|
+
);
|
|
4718
|
+
const [savedDeviceId, setSavedDeviceId] = reactExports.useState(() => {
|
|
4719
|
+
try {
|
|
4720
|
+
return localStorage.getItem(VOICE_INPUT_DEVICE_STORAGE_KEY);
|
|
4721
|
+
} catch {
|
|
4722
|
+
return null;
|
|
4723
|
+
}
|
|
4724
|
+
});
|
|
4725
|
+
const [deviceMenuOpen, setDeviceMenuOpen] = reactExports.useState(false);
|
|
4726
|
+
const [starting, setStarting] = reactExports.useState(false);
|
|
4727
|
+
const rememberDevice = reactExports.useCallback((deviceId) => {
|
|
4728
|
+
setSavedDeviceId(deviceId);
|
|
4729
|
+
try {
|
|
4730
|
+
localStorage.setItem(VOICE_INPUT_DEVICE_STORAGE_KEY, deviceId);
|
|
4731
|
+
} catch {
|
|
4732
|
+
}
|
|
4733
|
+
}, []);
|
|
4734
|
+
const handleSelectDevice = reactExports.useCallback(
|
|
4735
|
+
(deviceId) => {
|
|
4736
|
+
rememberDevice(deviceId);
|
|
4737
|
+
setDeviceMenuOpen(false);
|
|
4738
|
+
},
|
|
4739
|
+
[rememberDevice]
|
|
4740
|
+
);
|
|
4741
|
+
const handleMicClick = reactExports.useCallback(async () => {
|
|
4742
|
+
if (disabled || !asr.configured || starting) return;
|
|
4743
|
+
setStarting(true);
|
|
4744
|
+
try {
|
|
4745
|
+
const devices = await refreshInputDevices();
|
|
4746
|
+
const hasSavedDevice = savedDeviceId != null && devices.some((device) => device.deviceId === savedDeviceId);
|
|
4747
|
+
if (hasSavedDevice) {
|
|
4748
|
+
await handleStart(savedDeviceId);
|
|
4749
|
+
} else {
|
|
4750
|
+
setDeviceMenuOpen(true);
|
|
4751
|
+
}
|
|
4752
|
+
} finally {
|
|
4753
|
+
setStarting(false);
|
|
4754
|
+
}
|
|
4755
|
+
}, [asr.configured, disabled, handleStart, refreshInputDevices, savedDeviceId, starting]);
|
|
4756
|
+
const handleShortcutToggle = reactExports.useCallback(async () => {
|
|
4757
|
+
if (disabled || !asr.configured || starting) return;
|
|
4758
|
+
if (asr.recording) {
|
|
4759
|
+
await handleStop();
|
|
4760
|
+
return;
|
|
4761
|
+
}
|
|
4762
|
+
setStarting(true);
|
|
4763
|
+
try {
|
|
4764
|
+
const devices = await refreshInputDevices();
|
|
4765
|
+
const hasSavedDevice = savedDeviceId != null && devices.some((device) => device.deviceId === savedDeviceId);
|
|
4766
|
+
await handleStart(hasSavedDevice ? savedDeviceId : void 0);
|
|
4767
|
+
} finally {
|
|
4768
|
+
setStarting(false);
|
|
4769
|
+
}
|
|
4770
|
+
}, [
|
|
4771
|
+
asr.configured,
|
|
4772
|
+
asr.recording,
|
|
4773
|
+
disabled,
|
|
4774
|
+
handleStart,
|
|
4775
|
+
handleStop,
|
|
4776
|
+
refreshInputDevices,
|
|
4777
|
+
savedDeviceId,
|
|
4778
|
+
starting
|
|
4779
|
+
]);
|
|
4780
|
+
const handleDeviceMenuChange = reactExports.useCallback(
|
|
4781
|
+
(open) => {
|
|
4782
|
+
setDeviceMenuOpen(open);
|
|
4783
|
+
if (open) void refreshInputDevices();
|
|
4784
|
+
},
|
|
4785
|
+
[refreshInputDevices]
|
|
4786
|
+
);
|
|
4787
|
+
reactExports.useEffect(() => {
|
|
4788
|
+
lastAltTapAtRef.current = null;
|
|
4789
|
+
const handleKeyDown = (event) => {
|
|
4790
|
+
const input = inputRef.current;
|
|
4791
|
+
if (!input || document.activeElement !== input) {
|
|
4792
|
+
lastAltTapAtRef.current = null;
|
|
4793
|
+
return;
|
|
4794
|
+
}
|
|
4795
|
+
if (event.key === "Escape") {
|
|
4796
|
+
lastAltTapAtRef.current = null;
|
|
4797
|
+
suppressAltUntilRef.current = 0;
|
|
4798
|
+
if (!event.repeat && !event.ctrlKey && !event.metaKey && !event.shiftKey && asr.recording) {
|
|
4799
|
+
event.preventDefault();
|
|
4800
|
+
void handleStop();
|
|
4801
|
+
}
|
|
4802
|
+
return;
|
|
4803
|
+
}
|
|
4804
|
+
if (event.key !== "Alt") {
|
|
4805
|
+
lastAltTapAtRef.current = null;
|
|
4806
|
+
return;
|
|
4807
|
+
}
|
|
4808
|
+
if (!altDoublePressEnabled || event.repeat || event.ctrlKey || event.metaKey || event.shiftKey) {
|
|
4809
|
+
lastAltTapAtRef.current = null;
|
|
4810
|
+
return;
|
|
4811
|
+
}
|
|
4812
|
+
const now = Date.now();
|
|
4813
|
+
if (now < suppressAltUntilRef.current) {
|
|
4814
|
+
lastAltTapAtRef.current = null;
|
|
4815
|
+
return;
|
|
4816
|
+
}
|
|
4817
|
+
if (asr.recording) {
|
|
4818
|
+
lastAltTapAtRef.current = null;
|
|
4819
|
+
suppressAltUntilRef.current = now + ALT_DOUBLE_PRESS_WINDOW;
|
|
4820
|
+
event.preventDefault();
|
|
4821
|
+
void handleStop();
|
|
4822
|
+
return;
|
|
4823
|
+
}
|
|
4824
|
+
const lastTapAt = lastAltTapAtRef.current;
|
|
4825
|
+
if (lastTapAt !== null && now - lastTapAt <= ALT_DOUBLE_PRESS_WINDOW) {
|
|
4826
|
+
lastAltTapAtRef.current = null;
|
|
4827
|
+
event.preventDefault();
|
|
4828
|
+
void handleShortcutToggle();
|
|
4829
|
+
}
|
|
4830
|
+
};
|
|
4831
|
+
const handleKeyUp = (event) => {
|
|
4832
|
+
if (event.key !== "Alt") return;
|
|
4833
|
+
const input = inputRef.current;
|
|
4834
|
+
if (!input || document.activeElement !== input) {
|
|
4835
|
+
lastAltTapAtRef.current = null;
|
|
4836
|
+
return;
|
|
4837
|
+
}
|
|
4838
|
+
if (Date.now() < suppressAltUntilRef.current) {
|
|
4839
|
+
lastAltTapAtRef.current = null;
|
|
4840
|
+
return;
|
|
4841
|
+
}
|
|
4842
|
+
lastAltTapAtRef.current = Date.now();
|
|
4843
|
+
};
|
|
4844
|
+
const resetAltTap = () => {
|
|
4845
|
+
lastAltTapAtRef.current = null;
|
|
4846
|
+
suppressAltUntilRef.current = 0;
|
|
4847
|
+
};
|
|
4848
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
4849
|
+
window.addEventListener("keyup", handleKeyUp);
|
|
4850
|
+
window.addEventListener("blur", resetAltTap);
|
|
4851
|
+
return () => {
|
|
4852
|
+
window.removeEventListener("keydown", handleKeyDown);
|
|
4853
|
+
window.removeEventListener("keyup", handleKeyUp);
|
|
4854
|
+
window.removeEventListener("blur", resetAltTap);
|
|
4855
|
+
};
|
|
4856
|
+
}, [altDoublePressEnabled, asr.recording, handleShortcutToggle, handleStop, inputRef]);
|
|
4857
|
+
reactExports.useEffect(() => {
|
|
4858
|
+
const textarea = inputRef.current;
|
|
4859
|
+
if (!textarea) return;
|
|
4860
|
+
const handleInput = () => {
|
|
4861
|
+
if (!asrApplyingRef.current && asr.recording) freezeAsrSegments();
|
|
4862
|
+
};
|
|
4863
|
+
textarea.addEventListener("input", handleInput);
|
|
4864
|
+
return () => textarea.removeEventListener("input", handleInput);
|
|
4865
|
+
}, [asr.recording, freezeAsrSegments, inputRef]);
|
|
4866
|
+
reactExports.useEffect(() => {
|
|
4867
|
+
if (disabled && asr.recording) void handleStop();
|
|
4868
|
+
}, [asr.recording, disabled, handleStop]);
|
|
4869
|
+
reactExports.useEffect(() => {
|
|
4870
|
+
if (!asr.recording || maxDuration <= 0 || !Number.isFinite(maxDuration)) return;
|
|
4871
|
+
const timer = setTimeout(() => void handleStop(), maxDuration);
|
|
4872
|
+
return () => clearTimeout(timer);
|
|
4873
|
+
}, [asr.recording, handleStop, maxDuration]);
|
|
4874
|
+
if (!asr.configured) return null;
|
|
4875
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
4876
|
+
"div",
|
|
4877
|
+
{
|
|
4878
|
+
className: cn$1(
|
|
4879
|
+
"relative inline-flex h-7 transition-[width] duration-300 ease-out flex-none",
|
|
4880
|
+
asr.recording ? "w-18" : "w-12.5",
|
|
4881
|
+
className
|
|
4882
|
+
),
|
|
4883
|
+
children: [
|
|
4884
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4885
|
+
"div",
|
|
4886
|
+
{
|
|
4887
|
+
className: cn$1(
|
|
4888
|
+
"absolute inset-0 transition-[opacity,transform,visibility] duration-300 ease-out",
|
|
4889
|
+
asr.recording ? "visible scale-100 opacity-100" : "pointer-events-none invisible scale-90 opacity-0"
|
|
4890
|
+
),
|
|
4891
|
+
"aria-hidden": !asr.recording,
|
|
4892
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
4893
|
+
Button,
|
|
4894
|
+
{
|
|
4895
|
+
variant: "default",
|
|
4896
|
+
size: "sm",
|
|
4897
|
+
className: "h-full w-full rounded-lg bg-muted hover:bg-input border border-input text-amber-300/50 hover:text-amber-200",
|
|
4898
|
+
onClick: () => void handleStop(),
|
|
4899
|
+
"aria-label": t("chatInput.stopVoiceInput", "Stop voice input"),
|
|
4900
|
+
"aria-pressed": "true",
|
|
4901
|
+
title: t("chatInput.stopVoiceInput", "Stop voice input"),
|
|
4902
|
+
children: [
|
|
4903
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Mic, { className: "size-3.5 shrink-0 animate-pulse" }),
|
|
4904
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4905
|
+
"span",
|
|
4906
|
+
{
|
|
4907
|
+
className: "flex h-4 flex-1 items-center justify-center gap-0.5 overflow-hidden",
|
|
4908
|
+
"aria-hidden": "true",
|
|
4909
|
+
children: ASR_WAVEFORM_BARS.map((scale, index) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4910
|
+
"span",
|
|
4911
|
+
{
|
|
4912
|
+
className: "border-l rounded-full bg-amber-300 transition-[height] duration-75",
|
|
4913
|
+
style: {
|
|
4914
|
+
height: `${Math.max(2, Math.round(2 + asr.audioLevel * 16 * scale))}px`
|
|
4915
|
+
}
|
|
4916
|
+
},
|
|
4917
|
+
index
|
|
4918
|
+
))
|
|
4919
|
+
}
|
|
4920
|
+
)
|
|
4921
|
+
]
|
|
4922
|
+
}
|
|
4923
|
+
)
|
|
4924
|
+
}
|
|
4925
|
+
),
|
|
4926
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4927
|
+
"div",
|
|
4928
|
+
{
|
|
4929
|
+
className: cn$1(
|
|
4930
|
+
"absolute inset-0 transition-[opacity,transform,visibility] duration-300 ease-out",
|
|
4931
|
+
asr.recording ? "pointer-events-none invisible scale-90 opacity-0" : "visible scale-100 opacity-100"
|
|
4932
|
+
),
|
|
4933
|
+
"aria-hidden": asr.recording,
|
|
4934
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenu, { open: deviceMenuOpen, onOpenChange: handleDeviceMenuChange, children: [
|
|
4935
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-full items-stretch", children: [
|
|
4936
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4937
|
+
Button,
|
|
4938
|
+
{
|
|
4939
|
+
size: "sm",
|
|
4940
|
+
className: "h-full w-8 rounded-r-none border-r-0 bg-muted hover:bg-input border border-input text-amber-300/50 hover:text-amber-200",
|
|
4941
|
+
onClick: () => void handleMicClick(),
|
|
4942
|
+
disabled: disabled || !asr.configured || starting,
|
|
4943
|
+
"aria-busy": starting,
|
|
4944
|
+
"aria-label": starting ? t("chatInput.startingVoiceInput", "Starting voice input") : t("chatInput.voiceInput", "Voice input"),
|
|
4945
|
+
title: starting ? t("chatInput.startingVoiceInput", "Starting voice input") : asr.configured ? t("chatInput.voiceInput", "Voice input") : t("chatInput.voiceInputNotConfigured", "Configure voice input in Settings"),
|
|
4946
|
+
children: starting ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3.5 animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Mic, { className: "size-3.5" })
|
|
4947
|
+
}
|
|
4948
|
+
),
|
|
4949
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4950
|
+
DropdownMenuTrigger,
|
|
4951
|
+
{
|
|
4952
|
+
render: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4953
|
+
Button,
|
|
4954
|
+
{
|
|
4955
|
+
size: "icon",
|
|
4956
|
+
className: "h-full w-4.5 rounded-l-none bg-muted hover:bg-input border border-input border-l-0 px-0 text-amber-300/50 hover:text-amber-200",
|
|
4957
|
+
disabled: disabled || !asr.configured || starting,
|
|
4958
|
+
"aria-label": t("chatInput.selectVoiceInputDevice", "Select microphone"),
|
|
4959
|
+
title: t("chatInput.selectVoiceInputDevice", "Select microphone")
|
|
4960
|
+
}
|
|
4961
|
+
),
|
|
4962
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-3" })
|
|
4963
|
+
}
|
|
4964
|
+
)
|
|
4965
|
+
] }),
|
|
4966
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4967
|
+
DropdownMenuContent,
|
|
4968
|
+
{
|
|
4969
|
+
side: "top",
|
|
4970
|
+
align: "center",
|
|
4971
|
+
className: "w-auto! max-w-72 min-w-(--anchor-width)",
|
|
4972
|
+
children: asr.inputDevices.length > 0 ? asr.inputDevices.map((device) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
4973
|
+
DropdownMenuItem,
|
|
4974
|
+
{
|
|
4975
|
+
onClick: () => handleSelectDevice(device.deviceId),
|
|
4976
|
+
className: "gap-2",
|
|
4977
|
+
children: [
|
|
4978
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4979
|
+
Check,
|
|
4980
|
+
{
|
|
4981
|
+
className: cn$1(
|
|
4982
|
+
"size-3 shrink-0",
|
|
4983
|
+
device.deviceId === savedDeviceId ? "opacity-100" : "opacity-0"
|
|
4984
|
+
)
|
|
4985
|
+
}
|
|
4986
|
+
),
|
|
4987
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-w-0 flex-col gap-0.5 pr-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: device.label }) })
|
|
4988
|
+
]
|
|
4989
|
+
},
|
|
4990
|
+
device.deviceId
|
|
4991
|
+
)) : /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownMenuItem, { disabled: true, children: t("chatInput.noAudioInputDevices", "No audio input devices found") })
|
|
4992
|
+
}
|
|
4993
|
+
)
|
|
4994
|
+
] })
|
|
4995
|
+
}
|
|
4996
|
+
)
|
|
4997
|
+
]
|
|
4998
|
+
}
|
|
4999
|
+
);
|
|
5000
|
+
}
|
|
4317
5001
|
function readFileAsBase64(file) {
|
|
4318
5002
|
return new Promise((resolve, reject) => {
|
|
4319
5003
|
const reader = new FileReader();
|
|
@@ -4447,10 +5131,16 @@ function ChatInput({ session }) {
|
|
|
4447
5131
|
const promptCapabilities = initializeInfo?.agentCapabilities?.promptCapabilities;
|
|
4448
5132
|
const supportsImage = promptCapabilities?.image ?? false;
|
|
4449
5133
|
const supportsEmbedded = promptCapabilities?.embeddedContext ?? false;
|
|
4450
|
-
const
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
)
|
|
5134
|
+
const textareaRef = reactExports.useRef(null);
|
|
5135
|
+
const voiceInputRef = reactExports.useRef(null);
|
|
5136
|
+
const getTextarea = reactExports.useCallback(() => textareaRef.current, []);
|
|
5137
|
+
const focusInput = reactExports.useCallback(() => {
|
|
5138
|
+
const textarea = getTextarea();
|
|
5139
|
+
if (!textarea || textarea.disabled) return false;
|
|
5140
|
+
textarea.focus({ preventScroll: true });
|
|
5141
|
+
return document.activeElement === textarea;
|
|
5142
|
+
}, [getTextarea]);
|
|
5143
|
+
useFocusTarget("chat-input", focusInput);
|
|
4454
5144
|
const insertTriggerChar = reactExports.useCallback(
|
|
4455
5145
|
(char) => {
|
|
4456
5146
|
const textarea = getTextarea();
|
|
@@ -4617,6 +5307,7 @@ function ChatInput({ session }) {
|
|
|
4617
5307
|
[localInput, availableCommands]
|
|
4618
5308
|
);
|
|
4619
5309
|
const handleSubmit = reactExports.useCallback(async () => {
|
|
5310
|
+
await voiceInputRef.current?.stop();
|
|
4620
5311
|
v$2();
|
|
4621
5312
|
const state = useAppStore.getState().getSessionState(session.id);
|
|
4622
5313
|
const currentAttachments = state.draftAttachments;
|
|
@@ -4911,7 +5602,10 @@ function ChatInput({ session }) {
|
|
|
4911
5602
|
MentionsInput$1,
|
|
4912
5603
|
{
|
|
4913
5604
|
value: localInput,
|
|
4914
|
-
|
|
5605
|
+
inputRef: textareaRef,
|
|
5606
|
+
onChange: (_e3, newValue) => {
|
|
5607
|
+
setLocalInput(newValue);
|
|
5608
|
+
},
|
|
4915
5609
|
onBlur: handleBlur,
|
|
4916
5610
|
onKeyDown: handleKeyDown,
|
|
4917
5611
|
placeholder: disabled ? t("chatInput.placeholderDisabled") : t("chatInput.placeholderActive"),
|
|
@@ -5005,14 +5699,14 @@ function ChatInput({ session }) {
|
|
|
5005
5699
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
5006
5700
|
"div",
|
|
5007
5701
|
{
|
|
5008
|
-
className: "flex cursor-text items-center justify-between gap-2
|
|
5702
|
+
className: "flex cursor-text items-center justify-between gap-2 -mt-3 overflow-hidden",
|
|
5009
5703
|
onClick: (e) => {
|
|
5010
5704
|
const target = e.target;
|
|
5011
5705
|
if (target.closest("button, select, [role='combobox']")) return;
|
|
5012
5706
|
getTextarea()?.focus();
|
|
5013
5707
|
},
|
|
5014
5708
|
children: [
|
|
5015
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 overflow-hidden", children: [
|
|
5709
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 p-2 overflow-hidden -mr-4", children: [
|
|
5016
5710
|
availableModes.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenu, { children: [
|
|
5017
5711
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
5018
5712
|
DropdownMenuTrigger,
|
|
@@ -5022,7 +5716,7 @@ function ChatInput({ session }) {
|
|
|
5022
5716
|
{
|
|
5023
5717
|
variant: "outline",
|
|
5024
5718
|
size: "sm",
|
|
5025
|
-
className: "h-7 text-xs text-muted-foreground hover:text-foreground gap-2 max-w-48 shrink overflow-hidden"
|
|
5719
|
+
className: "h-7 min-w-16 text-xs text-muted-foreground hover:text-foreground gap-2 max-w-48 shrink overflow-hidden"
|
|
5026
5720
|
}
|
|
5027
5721
|
),
|
|
5028
5722
|
children: [
|
|
@@ -5144,7 +5838,7 @@ function ChatInput({ session }) {
|
|
|
5144
5838
|
] })
|
|
5145
5839
|
] })
|
|
5146
5840
|
] }),
|
|
5147
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 overflow-hidden", children: [
|
|
5841
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 p-2 overflow-hidden", children: [
|
|
5148
5842
|
availableModels.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs(DropdownMenu, { children: [
|
|
5149
5843
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
5150
5844
|
DropdownMenuTrigger,
|
|
@@ -5154,7 +5848,7 @@ function ChatInput({ session }) {
|
|
|
5154
5848
|
{
|
|
5155
5849
|
variant: "outline",
|
|
5156
5850
|
size: "sm",
|
|
5157
|
-
className: "h-7 text-xs text-muted-foreground hover:text-foreground gap-2 max-w-48 shrink overflow-hidden"
|
|
5851
|
+
className: "h-7 min-w-16 text-xs text-muted-foreground hover:text-foreground gap-2 max-w-48 shrink overflow-hidden"
|
|
5158
5852
|
}
|
|
5159
5853
|
),
|
|
5160
5854
|
children: [
|
|
@@ -5290,6 +5984,7 @@ function ChatInput({ session }) {
|
|
|
5290
5984
|
}
|
|
5291
5985
|
)
|
|
5292
5986
|
] }),
|
|
5987
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(VoiceInputButton, { ref: voiceInputRef, inputRef: textareaRef, disabled }),
|
|
5293
5988
|
isStreaming ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5294
5989
|
Button,
|
|
5295
5990
|
{
|
|
@@ -5333,14 +6028,14 @@ const mentionsInputStyle = {
|
|
|
5333
6028
|
highlighter: {
|
|
5334
6029
|
padding: "12px 16px 8px",
|
|
5335
6030
|
border: "none",
|
|
5336
|
-
maxHeight:
|
|
6031
|
+
maxHeight: "80vh"
|
|
5337
6032
|
},
|
|
5338
6033
|
input: {
|
|
5339
6034
|
padding: "12px 16px 8px",
|
|
5340
6035
|
border: "none",
|
|
5341
6036
|
outline: "none",
|
|
5342
6037
|
overflow: "auto",
|
|
5343
|
-
maxHeight:
|
|
6038
|
+
maxHeight: "80vh",
|
|
5344
6039
|
color: "var(--foreground)",
|
|
5345
6040
|
fontSize: 13,
|
|
5346
6041
|
lineHeight: "1.5",
|
|
@@ -5433,12 +6128,15 @@ function AskUserDialog({ sessionId }) {
|
|
|
5433
6128
|
"div",
|
|
5434
6129
|
{
|
|
5435
6130
|
ref: cardRef,
|
|
6131
|
+
role: "dialog",
|
|
6132
|
+
"aria-labelledby": "ask-user-dialog-title",
|
|
6133
|
+
"aria-describedby": currentRequest.description ? "ask-user-dialog-description" : void 0,
|
|
5436
6134
|
onClick: () => setCollapsed(false),
|
|
5437
6135
|
className: "grid grid-rows-[auto_1fr_auto] rounded-xl border border-border bg-card p-4 shadow-lg shadow-primary/5 max-h-[90vh]",
|
|
5438
6136
|
children: [
|
|
5439
6137
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mb-3 min-h-0", children: [
|
|
5440
6138
|
/* @__PURE__ */ jsxRuntimeExports.jsx(CircleQuestionMark, { className: "size-4.5 shrink-0 text-sky-500" }),
|
|
5441
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-medium leading-snug truncate", children: currentRequest.title || t("askUser.title", "Request") }),
|
|
6139
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { id: "ask-user-dialog-title", className: "text-sm font-medium leading-snug truncate", children: currentRequest.title || t("askUser.title", "Request") }),
|
|
5442
6140
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center ml-auto gap-1", children: [
|
|
5443
6141
|
currentRequest.timeoutAt != null && /* @__PURE__ */ jsxRuntimeExports.jsx(AskUserCountdown, { timeoutAt: currentRequest.timeoutAt }),
|
|
5444
6142
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -5452,13 +6150,14 @@ function AskUserDialog({ sessionId }) {
|
|
|
5452
6150
|
setCollapsed((c) => !c);
|
|
5453
6151
|
},
|
|
5454
6152
|
"aria-label": collapsed ? t("askUser.expand", "Expand") : t("askUser.collapse", "Collapse"),
|
|
6153
|
+
"aria-expanded": !collapsed,
|
|
5455
6154
|
title: collapsed ? t("askUser.expand", "Expand") : t("askUser.collapse", "Collapse"),
|
|
5456
6155
|
children: collapsed ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { className: "size-4" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { className: "size-4" })
|
|
5457
6156
|
}
|
|
5458
6157
|
)
|
|
5459
6158
|
] })
|
|
5460
6159
|
] }),
|
|
5461
|
-
currentRequest.description && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "h-full rounded-md bg-muted/40", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "py-3 px-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs text-muted-foreground leading-relaxed whitespace-pre-wrap", children: /* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: formatDescription(currentRequest.description) }) }) }) }) }),
|
|
6160
|
+
currentRequest.description && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { id: "ask-user-dialog-description", className: "min-h-0 overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "h-full rounded-md bg-muted/40", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "py-3 px-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs text-muted-foreground leading-relaxed whitespace-pre-wrap", children: /* @__PURE__ */ jsxRuntimeExports.jsx("code", { children: formatDescription(currentRequest.description) }) }) }) }) }),
|
|
5462
6161
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cn$1("pt-3 min-h-0", collapsed ? "pointer-events-none" : ""), children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5463
6162
|
AskUserOptions,
|
|
5464
6163
|
{
|
|
@@ -5522,13 +6221,21 @@ function AskUserOptions({
|
|
|
5522
6221
|
const [highlightedIndex, setHighlightedIndex] = reactExports.useState(null);
|
|
5523
6222
|
const [isDragOver, setIsDragOver] = reactExports.useState(false);
|
|
5524
6223
|
const inputContainerRef = reactExports.useRef(null);
|
|
6224
|
+
const optionRefs = reactExports.useRef([]);
|
|
6225
|
+
const otherButtonRef = reactExports.useRef(null);
|
|
6226
|
+
const textareaRef = reactExports.useRef(null);
|
|
6227
|
+
const voiceInputRef = reactExports.useRef(null);
|
|
5525
6228
|
const navigate = useNavigate();
|
|
5526
6229
|
const snippets = useAppStore((s15) => s15.snippets);
|
|
5527
6230
|
const fileInputRef = reactExports.useRef(null);
|
|
5528
|
-
const getTextarea = reactExports.useCallback(
|
|
5529
|
-
|
|
5530
|
-
[]
|
|
5531
|
-
|
|
6231
|
+
const getTextarea = reactExports.useCallback(() => textareaRef.current, []);
|
|
6232
|
+
const focusAskUser = reactExports.useCallback(() => {
|
|
6233
|
+
const target = mode === "input" ? textareaRef.current : optionRefs.current[0];
|
|
6234
|
+
if (!target || target.disabled) return false;
|
|
6235
|
+
target.focus({ preventScroll: true });
|
|
6236
|
+
return document.activeElement === target;
|
|
6237
|
+
}, [mode]);
|
|
6238
|
+
useFocusTarget("ask-user-dialog", focusAskUser);
|
|
5532
6239
|
const insertTriggerChar = reactExports.useCallback(
|
|
5533
6240
|
(char) => {
|
|
5534
6241
|
const textarea = getTextarea();
|
|
@@ -5593,7 +6300,7 @@ function AskUserOptions({
|
|
|
5593
6300
|
}
|
|
5594
6301
|
if (paths.length === 0) return;
|
|
5595
6302
|
void (async () => {
|
|
5596
|
-
const textarea =
|
|
6303
|
+
const textarea = textareaRef.current;
|
|
5597
6304
|
if (!textarea) return;
|
|
5598
6305
|
textarea.focus();
|
|
5599
6306
|
const tags = await Promise.all(
|
|
@@ -5679,7 +6386,8 @@ function AskUserOptions({
|
|
|
5679
6386
|
window.addEventListener("keydown", handler);
|
|
5680
6387
|
return () => window.removeEventListener("keydown", handler);
|
|
5681
6388
|
}, [mode, hasOptions, request$1.options, handleSelectOption]);
|
|
5682
|
-
const handleSubmitInput = () => {
|
|
6389
|
+
const handleSubmitInput = async () => {
|
|
6390
|
+
await voiceInputRef.current?.stop();
|
|
5683
6391
|
const trimmed = resolveMentions(inputValue).trim();
|
|
5684
6392
|
request.respondAskUser({
|
|
5685
6393
|
sessionId: request$1.sessionId,
|
|
@@ -5693,35 +6401,57 @@ function AskUserOptions({
|
|
|
5693
6401
|
if (e.nativeEvent.isComposing) return;
|
|
5694
6402
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
5695
6403
|
e.preventDefault();
|
|
5696
|
-
handleSubmitInput();
|
|
6404
|
+
void handleSubmitInput();
|
|
5697
6405
|
}
|
|
5698
6406
|
};
|
|
5699
6407
|
reactExports.useEffect(() => {
|
|
5700
|
-
if (mode
|
|
5701
|
-
|
|
5702
|
-
}
|
|
6408
|
+
if (mode !== "input") return;
|
|
6409
|
+
textareaRef.current?.focus();
|
|
5703
6410
|
}, [mode]);
|
|
6411
|
+
reactExports.useEffect(() => {
|
|
6412
|
+
if (mode !== "options" || !hasOptions) return;
|
|
6413
|
+
const frame = window.requestAnimationFrame(() => optionRefs.current[0]?.focus());
|
|
6414
|
+
return () => window.cancelAnimationFrame(frame);
|
|
6415
|
+
}, [hasOptions, mode]);
|
|
6416
|
+
const handleOptionKeyDown = (event, index) => {
|
|
6417
|
+
const { key } = event;
|
|
6418
|
+
if (key === "ArrowDown" || key === "ArrowUp" || key === "Home" || key === "End") {
|
|
6419
|
+
event.preventDefault();
|
|
6420
|
+
event.stopPropagation();
|
|
6421
|
+
if (key === "Home") {
|
|
6422
|
+
optionRefs.current[0]?.focus();
|
|
6423
|
+
} else if (key === "End") {
|
|
6424
|
+
if (showOther) otherButtonRef.current?.focus();
|
|
6425
|
+
else optionRefs.current[request$1.options.length - 1]?.focus();
|
|
6426
|
+
} else if (key === "ArrowDown") {
|
|
6427
|
+
if (index < request$1.options.length - 1) {
|
|
6428
|
+
optionRefs.current[index + 1]?.focus();
|
|
6429
|
+
} else if (showOther) {
|
|
6430
|
+
otherButtonRef.current?.focus();
|
|
6431
|
+
}
|
|
6432
|
+
} else if (index > 0) {
|
|
6433
|
+
optionRefs.current[index - 1]?.focus();
|
|
6434
|
+
}
|
|
6435
|
+
}
|
|
6436
|
+
};
|
|
5704
6437
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
5705
6438
|
mode === "options" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
5706
6439
|
request$1.options.map((option, index) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
5707
|
-
"
|
|
6440
|
+
"button",
|
|
5708
6441
|
{
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
className: `relative flex w-full min-h-8 py-2 px-2 text-xs text-left rounded-lg border transition-all select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:translate-y-px ${highlightedIndex === index ? "ring-1 ring-sky-500 bg-sky-500/10 border-sky-500/30" : option.danger ? "bg-destructive/10 text-destructive hover:bg-destructive/20 border-destructive/20" : "bg-secondary/50 hover:bg-secondary hover:text-foreground"}`,
|
|
5712
|
-
onClick: () => handleSelectOption(option.value),
|
|
5713
|
-
onKeyDown: (e) => {
|
|
5714
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
5715
|
-
e.preventDefault();
|
|
5716
|
-
handleSelectOption(option.value);
|
|
5717
|
-
}
|
|
6442
|
+
ref: (element) => {
|
|
6443
|
+
optionRefs.current[index] = element;
|
|
5718
6444
|
},
|
|
6445
|
+
type: "button",
|
|
6446
|
+
className: `relative flex w-full min-h-8 py-2 px-2 text-xs text-left rounded-lg border transition-all select-none focus-visible:border-ring focus-visible:ring-1 focus-visible:ring-ring/50 active:translate-y-px ${highlightedIndex === index ? "ring-1 ring-sky-500 bg-sky-500/10 border-sky-500/30" : option.danger ? "bg-destructive/10 text-destructive hover:bg-destructive/20 border-destructive/20" : "bg-secondary/50 hover:bg-secondary hover:text-foreground"}`,
|
|
6447
|
+
onClick: () => handleSelectOption(option.value),
|
|
6448
|
+
onKeyDown: (event) => handleOptionKeyDown(event, index),
|
|
5719
6449
|
children: [
|
|
5720
6450
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-start gap-1.5 w-full", children: [
|
|
5721
6451
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-flex size-5 items-center justify-center rounded bg-muted-foreground/10 text-[10px] font-mono shrink-0 self-start mt-0.5", children: index + 1 }),
|
|
5722
6452
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1 whitespace-normal self-start py-1", children: option.label })
|
|
5723
6453
|
] }),
|
|
5724
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("
|
|
6454
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute top-0.5 right-1 text-[9px] leading-none text-muted-foreground/30 shrink-0 self-start font-mono", children: option.priority })
|
|
5725
6455
|
]
|
|
5726
6456
|
},
|
|
5727
6457
|
option.value
|
|
@@ -5729,10 +6459,22 @@ function AskUserOptions({
|
|
|
5729
6459
|
showOther && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
5730
6460
|
Button,
|
|
5731
6461
|
{
|
|
6462
|
+
ref: otherButtonRef,
|
|
5732
6463
|
variant: "ghost",
|
|
5733
6464
|
size: "sm",
|
|
5734
6465
|
className: "justify-start h-8 px-2 text-xs text-muted-foreground",
|
|
5735
6466
|
onClick: () => setMode("input"),
|
|
6467
|
+
onKeyDown: (event) => {
|
|
6468
|
+
if (event.key === "ArrowUp") {
|
|
6469
|
+
event.preventDefault();
|
|
6470
|
+
event.stopPropagation();
|
|
6471
|
+
optionRefs.current[request$1.options.length - 1]?.focus();
|
|
6472
|
+
} else if (event.key === "Home") {
|
|
6473
|
+
event.preventDefault();
|
|
6474
|
+
event.stopPropagation();
|
|
6475
|
+
optionRefs.current[0]?.focus();
|
|
6476
|
+
}
|
|
6477
|
+
},
|
|
5736
6478
|
children: [
|
|
5737
6479
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("askUser.other", "Custom reply") }),
|
|
5738
6480
|
/* @__PURE__ */ jsxRuntimeExports.jsx(ArrowRight, { className: "size-3" })
|
|
@@ -5767,6 +6509,7 @@ function AskUserOptions({
|
|
|
5767
6509
|
MentionsInput$1,
|
|
5768
6510
|
{
|
|
5769
6511
|
value: inputValue,
|
|
6512
|
+
inputRef: textareaRef,
|
|
5770
6513
|
onChange: (_e3, newValue) => setInputValue(newValue),
|
|
5771
6514
|
onKeyDown: handleKeyDown,
|
|
5772
6515
|
placeholder: t("askUser.inputPlaceholder", "Type your response... (Enter to send)"),
|
|
@@ -5907,16 +6650,19 @@ function AskUserOptions({
|
|
|
5907
6650
|
)) : /* @__PURE__ */ jsxRuntimeExports.jsx(DropdownMenuItem, { onClick: () => navigate("/settings/snippets"), children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-muted-foreground", children: t("chatInput.snippetsEmpty", "No snippets. Click to add in Settings.") }) }) })
|
|
5908
6651
|
] })
|
|
5909
6652
|
] }),
|
|
5910
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
6653
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
6654
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(VoiceInputButton, { ref: voiceInputRef, inputRef: textareaRef }),
|
|
6655
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
6656
|
+
Button,
|
|
6657
|
+
{
|
|
6658
|
+
size: "icon",
|
|
6659
|
+
className: "size-7 rounded-lg",
|
|
6660
|
+
onClick: handleSubmitInput,
|
|
6661
|
+
"aria-label": t("askUser.submit", "Submit"),
|
|
6662
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowUp, { className: "size-3.5" })
|
|
6663
|
+
}
|
|
6664
|
+
)
|
|
6665
|
+
] })
|
|
5920
6666
|
] })
|
|
5921
6667
|
]
|
|
5922
6668
|
}
|
|
@@ -6128,7 +6874,7 @@ function useFile(projectId, file, options = {}) {
|
|
|
6128
6874
|
};
|
|
6129
6875
|
}
|
|
6130
6876
|
const CodeEditor = reactExports.lazy(
|
|
6131
|
-
() => __vitePreload(() => import("./code-editor-
|
|
6877
|
+
() => __vitePreload(() => import("./code-editor-tm0AYOLz.js"), true ? __vite__mapDeps([0,1,2,3,4]) : void 0, import.meta.url).then((m) => ({ default: m.CodeEditor }))
|
|
6132
6878
|
);
|
|
6133
6879
|
const MAX_EDIT_SIZE = 1024 * 1024;
|
|
6134
6880
|
const EditPanel = reactExports.forwardRef(function EditPanel2({ projectId, filePath, content, loading = false, onCancel, onSaved }, ref) {
|
|
@@ -16699,6 +17445,9 @@ const GIT_SUMMARY_BADGES = [
|
|
|
16699
17445
|
{ key: "C", color: "text-yellow-500" },
|
|
16700
17446
|
{ key: "D", color: "text-red-500" }
|
|
16701
17447
|
];
|
|
17448
|
+
function fileNavigationItemKey(item) {
|
|
17449
|
+
return item.type === "action" ? `action:${item.action}` : `tree:${item.id}`;
|
|
17450
|
+
}
|
|
16702
17451
|
function TreeItem({
|
|
16703
17452
|
node,
|
|
16704
17453
|
depth,
|
|
@@ -16712,7 +17461,10 @@ function TreeItem({
|
|
|
16712
17461
|
onEditChange,
|
|
16713
17462
|
onEditSubmit,
|
|
16714
17463
|
onEditCancel,
|
|
16715
|
-
actions
|
|
17464
|
+
actions,
|
|
17465
|
+
onKeyDown: onKeyDown2,
|
|
17466
|
+
registerRef,
|
|
17467
|
+
onFocus
|
|
16716
17468
|
}) {
|
|
16717
17469
|
const { t } = useTranslation();
|
|
16718
17470
|
const isOpen = openFolders.has(node.id);
|
|
@@ -16723,6 +17475,15 @@ function TreeItem({
|
|
|
16723
17475
|
reactExports.useEffect(() => {
|
|
16724
17476
|
if (isEditing) setTimeout(() => inputRef.current?.focus(), 0);
|
|
16725
17477
|
}, [isEditing]);
|
|
17478
|
+
const handleView = (e) => {
|
|
17479
|
+
if (node.isFolder) {
|
|
17480
|
+
actions.toggle(node);
|
|
17481
|
+
actions.select(node.id, e);
|
|
17482
|
+
} else {
|
|
17483
|
+
actions.previewFile(node.id);
|
|
17484
|
+
actions.select(node.id, e);
|
|
17485
|
+
}
|
|
17486
|
+
};
|
|
16726
17487
|
const childProps = {
|
|
16727
17488
|
selectedIds,
|
|
16728
17489
|
openFolders,
|
|
@@ -16733,7 +17494,10 @@ function TreeItem({
|
|
|
16733
17494
|
onEditChange,
|
|
16734
17495
|
onEditSubmit,
|
|
16735
17496
|
onEditCancel,
|
|
16736
|
-
actions
|
|
17497
|
+
actions,
|
|
17498
|
+
onKeyDown: onKeyDown2,
|
|
17499
|
+
registerRef,
|
|
17500
|
+
onFocus
|
|
16737
17501
|
};
|
|
16738
17502
|
const status = gitStatusMap.get(node.id);
|
|
16739
17503
|
let statusText = "";
|
|
@@ -16770,7 +17534,22 @@ function TreeItem({
|
|
|
16770
17534
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
16771
17535
|
ContextMenuTrigger,
|
|
16772
17536
|
{
|
|
16773
|
-
render: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
17537
|
+
render: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
17538
|
+
"div",
|
|
17539
|
+
{
|
|
17540
|
+
ref: (element) => registerRef(node.id, element),
|
|
17541
|
+
tabIndex: -1,
|
|
17542
|
+
role: "treeitem",
|
|
17543
|
+
"aria-level": depth + 1,
|
|
17544
|
+
"aria-expanded": node.isFolder ? isOpen : void 0,
|
|
17545
|
+
"aria-selected": isSelected,
|
|
17546
|
+
className: "outline-0 focus-visible:inset-ring-1 focus-visible:inset-ring-ring/80 rounded-md",
|
|
17547
|
+
onKeyDown: (e) => {
|
|
17548
|
+
if (e.target === e.currentTarget) onKeyDown2(e, node);
|
|
17549
|
+
},
|
|
17550
|
+
onFocus: () => onFocus(node.id)
|
|
17551
|
+
}
|
|
17552
|
+
),
|
|
16774
17553
|
draggable: !isEditing,
|
|
16775
17554
|
onDragStart: (e) => {
|
|
16776
17555
|
e.stopPropagation();
|
|
@@ -16788,7 +17567,6 @@ function TreeItem({
|
|
|
16788
17567
|
},
|
|
16789
17568
|
className: cn$1(
|
|
16790
17569
|
"flex h-6 cursor-default select-none items-center gap-1.5 px-1.5 text-sx leading-none text-foreground/60",
|
|
16791
|
-
node.ignored && "opacity-50",
|
|
16792
17570
|
node.id === previewId ? "bg-primary/8 hover:bg-primary/10" : "hover:bg-primary/5 hover:text-foreground",
|
|
16793
17571
|
isSelected ? "text-foreground bg-primary/6" : "",
|
|
16794
17572
|
isDragOver && "relative ring-1 ring-primary bg-primary/5"
|
|
@@ -16800,13 +17578,7 @@ function TreeItem({
|
|
|
16800
17578
|
actions.select(node.id, e);
|
|
16801
17579
|
return;
|
|
16802
17580
|
}
|
|
16803
|
-
|
|
16804
|
-
actions.toggle(node);
|
|
16805
|
-
actions.select(node.id, e);
|
|
16806
|
-
} else {
|
|
16807
|
-
actions.previewFile(node.id);
|
|
16808
|
-
actions.select(node.id, e);
|
|
16809
|
-
}
|
|
17581
|
+
handleView(e);
|
|
16810
17582
|
},
|
|
16811
17583
|
children: [
|
|
16812
17584
|
node.isFolder ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -16814,10 +17586,11 @@ function TreeItem({
|
|
|
16814
17586
|
{
|
|
16815
17587
|
className: cn$1(
|
|
16816
17588
|
"size-3.5 shrink-0 text-muted-foreground scale-110 transition-transform",
|
|
16817
|
-
isOpen && "rotate-90"
|
|
17589
|
+
isOpen && "rotate-90",
|
|
17590
|
+
node.ignored && "opacity-50"
|
|
16818
17591
|
)
|
|
16819
17592
|
}
|
|
16820
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx(FileIcon, { name: node.name, className: "size-3.5 shrink-0 text-muted-foreground/90" }),
|
|
17593
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(FileIcon, { name: node.name, className: cn$1("size-3.5 shrink-0 text-muted-foreground/90", node.ignored && "opacity-50") }),
|
|
16821
17594
|
isEditing ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
16822
17595
|
"input",
|
|
16823
17596
|
{
|
|
@@ -16838,7 +17611,8 @@ function TreeItem({
|
|
|
16838
17611
|
{
|
|
16839
17612
|
className: cn$1(
|
|
16840
17613
|
"flex-1 truncate leading-normal",
|
|
16841
|
-
statusText && !node.isFolder && statusColor
|
|
17614
|
+
statusText && !node.isFolder && statusColor,
|
|
17615
|
+
node.ignored && "opacity-50"
|
|
16842
17616
|
),
|
|
16843
17617
|
children: node.name
|
|
16844
17618
|
}
|
|
@@ -16858,6 +17632,11 @@ function TreeItem({
|
|
|
16858
17632
|
}
|
|
16859
17633
|
),
|
|
16860
17634
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(ContextMenuContent, { children: [
|
|
17635
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(ContextMenuItem, { onClick: handleView, children: [
|
|
17636
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Eye, {}),
|
|
17637
|
+
t("filePanel.view")
|
|
17638
|
+
] }),
|
|
17639
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ContextMenuSeparator, {}),
|
|
16861
17640
|
node.isFolder ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
16862
17641
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(ContextMenuItem, { onClick: () => actions.createIn(node.id, false), children: [
|
|
16863
17642
|
/* @__PURE__ */ jsxRuntimeExports.jsx(FilePlus, {}),
|
|
@@ -16997,7 +17776,13 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
16997
17776
|
onPreviewFile
|
|
16998
17777
|
}) {
|
|
16999
17778
|
const { t } = useTranslation();
|
|
17000
|
-
const
|
|
17779
|
+
const treeRef = reactExports.useRef(null);
|
|
17780
|
+
const treeItemRefs = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
17781
|
+
const navigationActionRefs = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
17782
|
+
const lastFocusedActionRef = reactExports.useRef(null);
|
|
17783
|
+
const focusedTreeItemIdRef = reactExports.useRef(null);
|
|
17784
|
+
const pendingFocusIdRef = reactExports.useRef(null);
|
|
17785
|
+
const pendingFocusRestoreRef = reactExports.useRef(false);
|
|
17001
17786
|
const [data, setData] = reactExports.useState([]);
|
|
17002
17787
|
const [loading, setLoading] = reactExports.useState(false);
|
|
17003
17788
|
const [showLoading, setShowLoading] = reactExports.useState(false);
|
|
@@ -17208,6 +17993,144 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17208
17993
|
},
|
|
17209
17994
|
[openFolders]
|
|
17210
17995
|
);
|
|
17996
|
+
const registerTreeItemRef = reactExports.useCallback((id, element) => {
|
|
17997
|
+
if (element) {
|
|
17998
|
+
treeItemRefs.current.set(id, element);
|
|
17999
|
+
} else {
|
|
18000
|
+
treeItemRefs.current.delete(id);
|
|
18001
|
+
}
|
|
18002
|
+
}, []);
|
|
18003
|
+
const registerNavigationActionRef = reactExports.useCallback(
|
|
18004
|
+
(action, element) => {
|
|
18005
|
+
if (element) {
|
|
18006
|
+
navigationActionRefs.current.set(action, element);
|
|
18007
|
+
} else {
|
|
18008
|
+
navigationActionRefs.current.delete(action);
|
|
18009
|
+
}
|
|
18010
|
+
},
|
|
18011
|
+
[]
|
|
18012
|
+
);
|
|
18013
|
+
const handleTreeItemFocus = reactExports.useCallback((id) => {
|
|
18014
|
+
focusedTreeItemIdRef.current = id;
|
|
18015
|
+
}, []);
|
|
18016
|
+
const focusTreeItem = reactExports.useCallback(
|
|
18017
|
+
(id) => {
|
|
18018
|
+
let element = treeItemRefs.current.get(id);
|
|
18019
|
+
if (!element) {
|
|
18020
|
+
const visibleIds = flattenTree(data);
|
|
18021
|
+
const itemIndex = visibleIds.indexOf(id);
|
|
18022
|
+
if (itemIndex !== -1) {
|
|
18023
|
+
element = treeRef.current?.querySelectorAll('[role="treeitem"]')[itemIndex];
|
|
18024
|
+
}
|
|
18025
|
+
}
|
|
18026
|
+
if (!element) return;
|
|
18027
|
+
element.focus({ preventScroll: true });
|
|
18028
|
+
element.scrollIntoView({ block: "nearest" });
|
|
18029
|
+
},
|
|
18030
|
+
[data, flattenTree]
|
|
18031
|
+
);
|
|
18032
|
+
const fileNavigationItems = reactExports.useMemo(() => {
|
|
18033
|
+
const items = [];
|
|
18034
|
+
if (!isWebUI && cwd) {
|
|
18035
|
+
items.push({ type: "action", action: "reveal" });
|
|
18036
|
+
items.push({ type: "action", action: "editor" });
|
|
18037
|
+
}
|
|
18038
|
+
if (!loading) {
|
|
18039
|
+
items.push(
|
|
18040
|
+
{ type: "action", action: "new-file" },
|
|
18041
|
+
{ type: "action", action: "new-folder" },
|
|
18042
|
+
{ type: "action", action: "refresh" },
|
|
18043
|
+
{ type: "action", action: "collapse" }
|
|
18044
|
+
);
|
|
18045
|
+
}
|
|
18046
|
+
items.push(...flattenTree(data).map((id) => ({ type: "tree", id })));
|
|
18047
|
+
return items;
|
|
18048
|
+
}, [cwd, data, flattenTree, loading]);
|
|
18049
|
+
const fileActionItems = reactExports.useMemo(
|
|
18050
|
+
() => fileNavigationItems.filter(
|
|
18051
|
+
(item) => item.type === "action"
|
|
18052
|
+
),
|
|
18053
|
+
[fileNavigationItems]
|
|
18054
|
+
);
|
|
18055
|
+
const treeNavigationItems = reactExports.useMemo(
|
|
18056
|
+
() => fileNavigationItems.filter(
|
|
18057
|
+
(item) => item.type === "tree"
|
|
18058
|
+
),
|
|
18059
|
+
[fileNavigationItems]
|
|
18060
|
+
);
|
|
18061
|
+
const focusFileNavigationItem = reactExports.useCallback(
|
|
18062
|
+
(item) => {
|
|
18063
|
+
if (item.type === "action") {
|
|
18064
|
+
const element = navigationActionRefs.current.get(item.action);
|
|
18065
|
+
if (!element) return;
|
|
18066
|
+
element.focus({ preventScroll: true });
|
|
18067
|
+
return;
|
|
18068
|
+
}
|
|
18069
|
+
focusTreeItem(item.id);
|
|
18070
|
+
},
|
|
18071
|
+
[focusTreeItem]
|
|
18072
|
+
);
|
|
18073
|
+
const handleFileNavigationKeyDown = reactExports.useCallback(
|
|
18074
|
+
(event, items, item) => {
|
|
18075
|
+
event.preventDefault();
|
|
18076
|
+
event.stopPropagation();
|
|
18077
|
+
if (items.length === 0) return;
|
|
18078
|
+
const currentIndex = items.findIndex(
|
|
18079
|
+
(navigationItem) => fileNavigationItemKey(navigationItem) === fileNavigationItemKey(item)
|
|
18080
|
+
);
|
|
18081
|
+
const nextIndex = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : Math.max(
|
|
18082
|
+
0,
|
|
18083
|
+
Math.min(
|
|
18084
|
+
items.length - 1,
|
|
18085
|
+
currentIndex + (event.key === "ArrowRight" || event.key === "ArrowDown" ? 1 : -1)
|
|
18086
|
+
)
|
|
18087
|
+
);
|
|
18088
|
+
const nextItem = items[nextIndex];
|
|
18089
|
+
if (nextItem) focusFileNavigationItem(nextItem);
|
|
18090
|
+
},
|
|
18091
|
+
[focusFileNavigationItem]
|
|
18092
|
+
);
|
|
18093
|
+
const focusFileTree = reactExports.useCallback(() => {
|
|
18094
|
+
const visibleIds = flattenTree(data);
|
|
18095
|
+
const targetId = lastSelectedId && visibleIds.includes(lastSelectedId) && lastSelectedId || visibleIds.find((id) => selectedIds.has(id)) || visibleIds[0];
|
|
18096
|
+
if (targetId) {
|
|
18097
|
+
focusTreeItem(targetId);
|
|
18098
|
+
} else if (fileActionItems[0]) {
|
|
18099
|
+
focusFileNavigationItem(fileActionItems[0]);
|
|
18100
|
+
}
|
|
18101
|
+
}, [
|
|
18102
|
+
data,
|
|
18103
|
+
fileActionItems,
|
|
18104
|
+
flattenTree,
|
|
18105
|
+
focusFileNavigationItem,
|
|
18106
|
+
focusTreeItem,
|
|
18107
|
+
lastSelectedId,
|
|
18108
|
+
selectedIds
|
|
18109
|
+
]);
|
|
18110
|
+
useFocusTarget("file-tree-content", focusFileTree);
|
|
18111
|
+
reactExports.useEffect(() => {
|
|
18112
|
+
if (!pendingFocusRestoreRef.current || loading) return;
|
|
18113
|
+
const visibleIds = flattenTree(data);
|
|
18114
|
+
const pendingId = pendingFocusIdRef.current;
|
|
18115
|
+
const targetId = pendingId && visibleIds.includes(pendingId) ? pendingId : visibleIds[0];
|
|
18116
|
+
const fallbackAction = fileActionItems[0];
|
|
18117
|
+
pendingFocusRestoreRef.current = false;
|
|
18118
|
+
pendingFocusIdRef.current = null;
|
|
18119
|
+
window.requestAnimationFrame(() => {
|
|
18120
|
+
if (targetId) {
|
|
18121
|
+
focusTreeItem(targetId);
|
|
18122
|
+
} else if (fallbackAction) {
|
|
18123
|
+
focusFileNavigationItem(fallbackAction);
|
|
18124
|
+
}
|
|
18125
|
+
});
|
|
18126
|
+
}, [
|
|
18127
|
+
data,
|
|
18128
|
+
fileActionItems,
|
|
18129
|
+
flattenTree,
|
|
18130
|
+
focusFileNavigationItem,
|
|
18131
|
+
focusTreeItem,
|
|
18132
|
+
loading
|
|
18133
|
+
]);
|
|
17211
18134
|
reactExports.useEffect(() => {
|
|
17212
18135
|
useAppStore.getState().updateProjectState(projectId, () => ({
|
|
17213
18136
|
openFolders: Array.from(openFolders)
|
|
@@ -17259,6 +18182,86 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17259
18182
|
},
|
|
17260
18183
|
[activeProjectId]
|
|
17261
18184
|
);
|
|
18185
|
+
const handleTreeKeyDown = reactExports.useCallback(
|
|
18186
|
+
(event, node) => {
|
|
18187
|
+
const { key } = event;
|
|
18188
|
+
const isVerticalNavigationKey = key === "ArrowUp" || key === "ArrowDown" || key === "Home" || key === "End";
|
|
18189
|
+
if (isVerticalNavigationKey) {
|
|
18190
|
+
const treeItem = { type: "tree", id: node.id };
|
|
18191
|
+
const currentIndex = treeNavigationItems.findIndex((item) => item.id === node.id);
|
|
18192
|
+
if (key === "ArrowUp" && currentIndex === 0) {
|
|
18193
|
+
const actionItem = fileActionItems.find((item) => item.action === lastFocusedActionRef.current) ?? fileActionItems[0];
|
|
18194
|
+
if (actionItem) {
|
|
18195
|
+
event.preventDefault();
|
|
18196
|
+
event.stopPropagation();
|
|
18197
|
+
focusFileNavigationItem(actionItem);
|
|
18198
|
+
return;
|
|
18199
|
+
}
|
|
18200
|
+
}
|
|
18201
|
+
handleFileNavigationKeyDown(event, treeNavigationItems, treeItem);
|
|
18202
|
+
return;
|
|
18203
|
+
}
|
|
18204
|
+
if (key === "/") {
|
|
18205
|
+
event.preventDefault();
|
|
18206
|
+
event.stopPropagation();
|
|
18207
|
+
const target = event.currentTarget;
|
|
18208
|
+
const rect = target.getBoundingClientRect();
|
|
18209
|
+
target.dispatchEvent(
|
|
18210
|
+
new MouseEvent("contextmenu", {
|
|
18211
|
+
bubbles: true,
|
|
18212
|
+
cancelable: true,
|
|
18213
|
+
view: window,
|
|
18214
|
+
button: 2,
|
|
18215
|
+
buttons: 2,
|
|
18216
|
+
clientX: rect.left + rect.width / 2,
|
|
18217
|
+
clientY: rect.top + rect.height / 2
|
|
18218
|
+
})
|
|
18219
|
+
);
|
|
18220
|
+
return;
|
|
18221
|
+
}
|
|
18222
|
+
if (key === "ArrowLeft" || key === "ArrowRight") {
|
|
18223
|
+
event.preventDefault();
|
|
18224
|
+
event.stopPropagation();
|
|
18225
|
+
if (key === "ArrowRight" && node.isFolder) {
|
|
18226
|
+
if (!openFolders.has(node.id)) {
|
|
18227
|
+
toggle(node);
|
|
18228
|
+
} else {
|
|
18229
|
+
const firstChild = node.children?.[0];
|
|
18230
|
+
if (firstChild) focusTreeItem(firstChild.id);
|
|
18231
|
+
}
|
|
18232
|
+
} else if (key === "ArrowLeft") {
|
|
18233
|
+
if (node.isFolder && openFolders.has(node.id)) {
|
|
18234
|
+
toggle(node);
|
|
18235
|
+
} else {
|
|
18236
|
+
const parentId = node.id.slice(0, node.id.lastIndexOf("/"));
|
|
18237
|
+
if (parentId) focusTreeItem(parentId);
|
|
18238
|
+
}
|
|
18239
|
+
}
|
|
18240
|
+
return;
|
|
18241
|
+
}
|
|
18242
|
+
if (key === "Enter" || key === " " || key === "Spacebar") {
|
|
18243
|
+
event.preventDefault();
|
|
18244
|
+
event.stopPropagation();
|
|
18245
|
+
setSelectedIds(/* @__PURE__ */ new Set([node.id]));
|
|
18246
|
+
setLastSelectedId(node.id);
|
|
18247
|
+
if (node.isFolder) {
|
|
18248
|
+
toggle(node);
|
|
18249
|
+
} else {
|
|
18250
|
+
onPreviewFile(node.id);
|
|
18251
|
+
}
|
|
18252
|
+
}
|
|
18253
|
+
},
|
|
18254
|
+
[
|
|
18255
|
+
fileActionItems,
|
|
18256
|
+
focusFileNavigationItem,
|
|
18257
|
+
focusTreeItem,
|
|
18258
|
+
handleFileNavigationKeyDown,
|
|
18259
|
+
onPreviewFile,
|
|
18260
|
+
openFolders,
|
|
18261
|
+
toggle,
|
|
18262
|
+
treeNavigationItems
|
|
18263
|
+
]
|
|
18264
|
+
);
|
|
17262
18265
|
const collapseAll = reactExports.useCallback(() => {
|
|
17263
18266
|
setOpenFolders(/* @__PURE__ */ new Set());
|
|
17264
18267
|
openFoldersRef.current = /* @__PURE__ */ new Set();
|
|
@@ -17397,6 +18400,16 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17397
18400
|
request.getPlatform().then((p) => setOsPlatform(p));
|
|
17398
18401
|
}, []);
|
|
17399
18402
|
const trashLabel = osPlatform === "darwin" ? t("filePanel.moveToTrash") : osPlatform === "win32" ? t("filePanel.moveToRecycleBin") : t("filePanel.moveToTrash");
|
|
18403
|
+
const prepareFocusAfterDelete = (ids) => {
|
|
18404
|
+
const isDeletedId = (id) => ids.some((deletedId) => id === deletedId || id.startsWith(`${deletedId}/`));
|
|
18405
|
+
const referenceId = (focusedTreeItemIdRef.current && isDeletedId(focusedTreeItemIdRef.current) ? focusedTreeItemIdRef.current : null) ?? (lastSelectedId && isDeletedId(lastSelectedId) ? lastSelectedId : null) ?? ids.find(isDeletedId);
|
|
18406
|
+
if (!referenceId) return;
|
|
18407
|
+
const visibleIds = flattenTree(data);
|
|
18408
|
+
const referenceIndex = visibleIds.indexOf(referenceId);
|
|
18409
|
+
const targetId = (referenceIndex !== -1 ? visibleIds.slice(referenceIndex + 1).find((id) => !isDeletedId(id)) : void 0) ?? (referenceIndex !== -1 ? [...visibleIds.slice(0, referenceIndex)].reverse().find((id) => !isDeletedId(id)) : void 0) ?? visibleIds.find((id) => !isDeletedId(id));
|
|
18410
|
+
pendingFocusIdRef.current = targetId ?? null;
|
|
18411
|
+
pendingFocusRestoreRef.current = true;
|
|
18412
|
+
};
|
|
17400
18413
|
const deleteNode = async (ids) => {
|
|
17401
18414
|
if (ids.length === 0 || !activeProjectId) return;
|
|
17402
18415
|
await confirm2({
|
|
@@ -17425,7 +18438,9 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17425
18438
|
} catch (err) {
|
|
17426
18439
|
console.error("Delete failed:", extractErrorMessage(err));
|
|
17427
18440
|
}
|
|
18441
|
+
prepareFocusAfterDelete(ids);
|
|
17428
18442
|
setSelectedIds(/* @__PURE__ */ new Set());
|
|
18443
|
+
setLastSelectedId(null);
|
|
17429
18444
|
refresh();
|
|
17430
18445
|
return "trashed";
|
|
17431
18446
|
}
|
|
@@ -17443,7 +18458,9 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17443
18458
|
} catch (err) {
|
|
17444
18459
|
console.error("Delete failed:", extractErrorMessage(err));
|
|
17445
18460
|
}
|
|
18461
|
+
prepareFocusAfterDelete(ids);
|
|
17446
18462
|
setSelectedIds(/* @__PURE__ */ new Set());
|
|
18463
|
+
setLastSelectedId(null);
|
|
17447
18464
|
refresh();
|
|
17448
18465
|
return "deleted";
|
|
17449
18466
|
}
|
|
@@ -17884,6 +18901,47 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17884
18901
|
}
|
|
17885
18902
|
return null;
|
|
17886
18903
|
};
|
|
18904
|
+
const handleFileActionKeyDown = (event, action) => {
|
|
18905
|
+
if (event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "Home" || event.key === "End") {
|
|
18906
|
+
handleFileNavigationKeyDown(event, fileActionItems, { type: "action", action });
|
|
18907
|
+
return;
|
|
18908
|
+
}
|
|
18909
|
+
if (event.key === "ArrowDown") {
|
|
18910
|
+
event.preventDefault();
|
|
18911
|
+
event.stopPropagation();
|
|
18912
|
+
const firstTreeItem = treeNavigationItems[0];
|
|
18913
|
+
if (firstTreeItem) focusFileNavigationItem(firstTreeItem);
|
|
18914
|
+
return;
|
|
18915
|
+
}
|
|
18916
|
+
if (event.key !== "Enter" && event.key !== " " && event.key !== "Spacebar") return;
|
|
18917
|
+
event.preventDefault();
|
|
18918
|
+
event.stopPropagation();
|
|
18919
|
+
switch (action) {
|
|
18920
|
+
case "reveal":
|
|
18921
|
+
if (cwd) void revealInFinder(cwd);
|
|
18922
|
+
break;
|
|
18923
|
+
case "editor":
|
|
18924
|
+
if (cwd) {
|
|
18925
|
+
const editorName = useAppStore.getState().editor.name;
|
|
18926
|
+
void electron.openInEditor(cwd, editorName).catch((err) => {
|
|
18927
|
+
console.error("openInEditor failed:", extractErrorMessage(err));
|
|
18928
|
+
});
|
|
18929
|
+
}
|
|
18930
|
+
break;
|
|
18931
|
+
case "new-file":
|
|
18932
|
+
createIn(getSelectedFolder(), false);
|
|
18933
|
+
break;
|
|
18934
|
+
case "new-folder":
|
|
18935
|
+
createIn(getSelectedFolder(), true);
|
|
18936
|
+
break;
|
|
18937
|
+
case "refresh":
|
|
18938
|
+
refresh();
|
|
18939
|
+
break;
|
|
18940
|
+
case "collapse":
|
|
18941
|
+
collapseAll();
|
|
18942
|
+
break;
|
|
18943
|
+
}
|
|
18944
|
+
};
|
|
17887
18945
|
if (!projectId) {
|
|
17888
18946
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full items-center justify-center text-xs text-muted-foreground", children: t("filePanel.noProject", "No project selected") });
|
|
17889
18947
|
}
|
|
@@ -17903,9 +18961,12 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17903
18961
|
onEditChange: setEditingValue,
|
|
17904
18962
|
onEditSubmit: submitEdit,
|
|
17905
18963
|
onEditCancel: () => setEditingId(null),
|
|
17906
|
-
actions
|
|
18964
|
+
actions,
|
|
18965
|
+
onKeyDown: handleTreeKeyDown,
|
|
18966
|
+
registerRef: registerTreeItemRef,
|
|
18967
|
+
onFocus: handleTreeItemFocus
|
|
17907
18968
|
};
|
|
17908
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", {
|
|
18969
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-full min-h-0 flex-col text-xs w-full", children: [
|
|
17909
18970
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-10 items-center gap-0.5 border-b border-border", children: [
|
|
17910
18971
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex text-muted-foreground items-center gap-1 px-3", children: [
|
|
17911
18972
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Folders, { className: "size-3.5" }),
|
|
@@ -17916,10 +18977,16 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17916
18977
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
17917
18978
|
Button,
|
|
17918
18979
|
{
|
|
18980
|
+
ref: (element) => registerNavigationActionRef("reveal", element),
|
|
17919
18981
|
variant: "ghost",
|
|
17920
18982
|
size: "icon",
|
|
18983
|
+
tabIndex: -1,
|
|
17921
18984
|
className: "size-6 text-muted-foreground hover:text-foreground",
|
|
17922
18985
|
disabled: !cwd,
|
|
18986
|
+
onKeyDown: (event) => handleFileActionKeyDown(event, "reveal"),
|
|
18987
|
+
onFocus: () => {
|
|
18988
|
+
lastFocusedActionRef.current = "reveal";
|
|
18989
|
+
},
|
|
17923
18990
|
onClick: () => revealInFinder(cwd),
|
|
17924
18991
|
title: t("filePanel.revealInFinder"),
|
|
17925
18992
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(FolderOpen, { className: "size-3.5" })
|
|
@@ -17928,10 +18995,16 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17928
18995
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
17929
18996
|
Button,
|
|
17930
18997
|
{
|
|
18998
|
+
ref: (element) => registerNavigationActionRef("editor", element),
|
|
17931
18999
|
variant: "ghost",
|
|
17932
19000
|
size: "icon",
|
|
19001
|
+
tabIndex: -1,
|
|
17933
19002
|
className: "size-6 text-muted-foreground hover:text-foreground",
|
|
17934
19003
|
disabled: !cwd,
|
|
19004
|
+
onKeyDown: (event) => handleFileActionKeyDown(event, "editor"),
|
|
19005
|
+
onFocus: () => {
|
|
19006
|
+
lastFocusedActionRef.current = "editor";
|
|
19007
|
+
},
|
|
17935
19008
|
onClick: () => {
|
|
17936
19009
|
if (!cwd) return;
|
|
17937
19010
|
const editorName = useAppStore.getState().editor.name;
|
|
@@ -17949,10 +19022,16 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17949
19022
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
17950
19023
|
Button,
|
|
17951
19024
|
{
|
|
19025
|
+
ref: (element) => registerNavigationActionRef("new-file", element),
|
|
17952
19026
|
variant: "ghost",
|
|
17953
19027
|
size: "icon",
|
|
19028
|
+
tabIndex: -1,
|
|
17954
19029
|
className: "size-6 text-muted-foreground hover:text-foreground",
|
|
17955
19030
|
disabled: loading,
|
|
19031
|
+
onKeyDown: (event) => handleFileActionKeyDown(event, "new-file"),
|
|
19032
|
+
onFocus: () => {
|
|
19033
|
+
lastFocusedActionRef.current = "new-file";
|
|
19034
|
+
},
|
|
17956
19035
|
onClick: () => createIn(getSelectedFolder(), false),
|
|
17957
19036
|
title: t("filePanel.newFile"),
|
|
17958
19037
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(FilePlus, { className: "size-3.5" })
|
|
@@ -17961,10 +19040,16 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17961
19040
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
17962
19041
|
Button,
|
|
17963
19042
|
{
|
|
19043
|
+
ref: (element) => registerNavigationActionRef("new-folder", element),
|
|
17964
19044
|
variant: "ghost",
|
|
17965
19045
|
size: "icon",
|
|
19046
|
+
tabIndex: -1,
|
|
17966
19047
|
className: "size-6 text-muted-foreground hover:text-foreground",
|
|
17967
19048
|
disabled: loading,
|
|
19049
|
+
onKeyDown: (event) => handleFileActionKeyDown(event, "new-folder"),
|
|
19050
|
+
onFocus: () => {
|
|
19051
|
+
lastFocusedActionRef.current = "new-folder";
|
|
19052
|
+
},
|
|
17968
19053
|
onClick: () => createIn(getSelectedFolder(), true),
|
|
17969
19054
|
title: t("filePanel.newFolder"),
|
|
17970
19055
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(FolderPlus, { className: "size-3.5" })
|
|
@@ -17973,10 +19058,16 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17973
19058
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
17974
19059
|
Button,
|
|
17975
19060
|
{
|
|
19061
|
+
ref: (element) => registerNavigationActionRef("refresh", element),
|
|
17976
19062
|
variant: "ghost",
|
|
17977
19063
|
size: "icon",
|
|
19064
|
+
tabIndex: -1,
|
|
17978
19065
|
className: "size-6 text-muted-foreground hover:text-foreground",
|
|
17979
19066
|
disabled: loading,
|
|
19067
|
+
onKeyDown: (event) => handleFileActionKeyDown(event, "refresh"),
|
|
19068
|
+
onFocus: () => {
|
|
19069
|
+
lastFocusedActionRef.current = "refresh";
|
|
19070
|
+
},
|
|
17980
19071
|
onClick: refresh,
|
|
17981
19072
|
title: t("filePanel.refresh", "Refresh"),
|
|
17982
19073
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { className: "size-3.5" })
|
|
@@ -17985,10 +19076,16 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
17985
19076
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
17986
19077
|
Button,
|
|
17987
19078
|
{
|
|
19079
|
+
ref: (element) => registerNavigationActionRef("collapse", element),
|
|
17988
19080
|
variant: "ghost",
|
|
17989
19081
|
size: "icon",
|
|
19082
|
+
tabIndex: -1,
|
|
17990
19083
|
className: "size-6 text-muted-foreground hover:text-foreground",
|
|
17991
19084
|
disabled: loading,
|
|
19085
|
+
onKeyDown: (event) => handleFileActionKeyDown(event, "collapse"),
|
|
19086
|
+
onFocus: () => {
|
|
19087
|
+
lastFocusedActionRef.current = "collapse";
|
|
19088
|
+
},
|
|
17992
19089
|
onClick: collapseAll,
|
|
17993
19090
|
title: t("filePanel.collapseFolders"),
|
|
17994
19091
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(ListChevronsDownUp, { className: "size-3.5" })
|
|
@@ -18010,11 +19107,18 @@ const FilePanel = reactExports.memo(function FilePanel2({
|
|
|
18010
19107
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground/70", children: t("filePanel.emptyDirectory") })
|
|
18011
19108
|
]
|
|
18012
19109
|
}
|
|
18013
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "min-h-0 flex-1
|
|
19110
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "min-h-0 flex-1 px-1", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(ContextMenu, { children: [
|
|
18014
19111
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18015
19112
|
ContextMenuTrigger,
|
|
18016
19113
|
{
|
|
18017
|
-
render: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19114
|
+
render: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19115
|
+
"div",
|
|
19116
|
+
{
|
|
19117
|
+
ref: treeRef,
|
|
19118
|
+
role: "tree",
|
|
19119
|
+
"aria-label": t("filePanel.title", "Files")
|
|
19120
|
+
}
|
|
19121
|
+
),
|
|
18018
19122
|
className: "min-h-full py-1",
|
|
18019
19123
|
onClick: (e) => {
|
|
18020
19124
|
if (e.target === e.currentTarget) clearSelection();
|
|
@@ -18142,6 +19246,10 @@ function findNode(node, id) {
|
|
|
18142
19246
|
}
|
|
18143
19247
|
return null;
|
|
18144
19248
|
}
|
|
19249
|
+
const ADD_TERMINAL_NAVIGATION_ID = "__add_terminal__";
|
|
19250
|
+
function terminalNavigationItemKey(item) {
|
|
19251
|
+
return item.type === "add" ? ADD_TERMINAL_NAVIGATION_ID : item.id;
|
|
19252
|
+
}
|
|
18145
19253
|
function TerminalPanel({
|
|
18146
19254
|
projectId,
|
|
18147
19255
|
activeTerminalId,
|
|
@@ -18151,7 +19259,51 @@ function TerminalPanel({
|
|
|
18151
19259
|
const projectState = useProjectState(projectId);
|
|
18152
19260
|
const terminals = projectState.terminals;
|
|
18153
19261
|
const updateProjectState = useAppStore((s15) => s15.updateProjectState);
|
|
18154
|
-
|
|
19262
|
+
const navigationItemRefs = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
19263
|
+
const focusedNavigationItemIdRef = reactExports.useRef(null);
|
|
19264
|
+
const navigationItems = reactExports.useMemo(() => {
|
|
19265
|
+
const items = [{ type: "add" }];
|
|
19266
|
+
items.push(
|
|
19267
|
+
...terminals.map(
|
|
19268
|
+
(terminal) => ({ type: "terminal", id: terminal.id })
|
|
19269
|
+
)
|
|
19270
|
+
);
|
|
19271
|
+
return items;
|
|
19272
|
+
}, [terminals]);
|
|
19273
|
+
const terminalItems = reactExports.useMemo(
|
|
19274
|
+
() => navigationItems.filter(
|
|
19275
|
+
(item) => item.type === "terminal"
|
|
19276
|
+
),
|
|
19277
|
+
[navigationItems]
|
|
19278
|
+
);
|
|
19279
|
+
const registerNavigationItemRef = reactExports.useCallback((id, element) => {
|
|
19280
|
+
if (element) {
|
|
19281
|
+
navigationItemRefs.current.set(id, element);
|
|
19282
|
+
} else {
|
|
19283
|
+
navigationItemRefs.current.delete(id);
|
|
19284
|
+
}
|
|
19285
|
+
}, []);
|
|
19286
|
+
const focusNavigationItem = reactExports.useCallback((item) => {
|
|
19287
|
+
const element = navigationItemRefs.current.get(terminalNavigationItemKey(item));
|
|
19288
|
+
if (!element) return;
|
|
19289
|
+
element.focus({ preventScroll: true });
|
|
19290
|
+
element.scrollIntoView({ block: "nearest" });
|
|
19291
|
+
}, []);
|
|
19292
|
+
const focusTerminalList = reactExports.useCallback(() => {
|
|
19293
|
+
const activeItem = activeTerminalId ? navigationItems.find(
|
|
19294
|
+
(item) => item.type === "terminal" && item.id === activeTerminalId
|
|
19295
|
+
) : void 0;
|
|
19296
|
+
focusNavigationItem(activeItem ?? navigationItems[0]);
|
|
19297
|
+
}, [activeTerminalId, focusNavigationItem, navigationItems]);
|
|
19298
|
+
useFocusTarget("terminal-list-content", focusTerminalList);
|
|
19299
|
+
const selectTerminal = reactExports.useCallback(
|
|
19300
|
+
(terminalId) => {
|
|
19301
|
+
updateProjectState(projectId, () => ({ activeTerminalId: terminalId }));
|
|
19302
|
+
onSelectTerminal(terminalId);
|
|
19303
|
+
},
|
|
19304
|
+
[onSelectTerminal, projectId, updateProjectState]
|
|
19305
|
+
);
|
|
19306
|
+
const createTerminal = reactExports.useCallback(async () => {
|
|
18155
19307
|
if (!projectId) return;
|
|
18156
19308
|
const { terminalId } = await request.createTerminal({ projectId, cwd: "", clientId });
|
|
18157
19309
|
updateProjectState(projectId, (prev) => ({
|
|
@@ -18159,9 +19311,14 @@ function TerminalPanel({
|
|
|
18159
19311
|
activeTerminalId: terminalId
|
|
18160
19312
|
}));
|
|
18161
19313
|
onSelectTerminal(terminalId);
|
|
18162
|
-
}
|
|
19314
|
+
}, [onSelectTerminal, projectId, updateProjectState]);
|
|
18163
19315
|
async function deleteTerminal(terminalId, e) {
|
|
18164
|
-
e
|
|
19316
|
+
e?.stopPropagation();
|
|
19317
|
+
const shouldRestoreFocus = focusedNavigationItemIdRef.current === terminalId;
|
|
19318
|
+
const deletedIndex = navigationItems.findIndex(
|
|
19319
|
+
(item) => item.type === "terminal" && item.id === terminalId
|
|
19320
|
+
);
|
|
19321
|
+
const focusTarget = deletedIndex === -1 ? void 0 : navigationItems[deletedIndex + 1] ?? navigationItems[deletedIndex - 1] ?? navigationItems[0];
|
|
18165
19322
|
destroyTerminalInstance(terminalId);
|
|
18166
19323
|
await request.killTerminal({ terminalId });
|
|
18167
19324
|
updateProjectState(projectId, (prev) => {
|
|
@@ -18171,7 +19328,81 @@ function TerminalPanel({
|
|
|
18171
19328
|
activeTerminalId: prev.activeTerminalId === terminalId ? nextList[nextList.length - 1]?.id ?? null : prev.activeTerminalId
|
|
18172
19329
|
};
|
|
18173
19330
|
});
|
|
19331
|
+
if (shouldRestoreFocus && focusTarget) {
|
|
19332
|
+
window.requestAnimationFrame(() => focusNavigationItem(focusTarget));
|
|
19333
|
+
}
|
|
18174
19334
|
}
|
|
19335
|
+
const handleNavigationKeyDown = reactExports.useCallback(
|
|
19336
|
+
(event, item) => {
|
|
19337
|
+
const { key } = event;
|
|
19338
|
+
if (item.type === "add") {
|
|
19339
|
+
if (key === "ArrowLeft" || key === "ArrowRight" || key === "Home" || key === "End") {
|
|
19340
|
+
event.preventDefault();
|
|
19341
|
+
event.stopPropagation();
|
|
19342
|
+
focusNavigationItem(item);
|
|
19343
|
+
return;
|
|
19344
|
+
}
|
|
19345
|
+
if (key === "ArrowDown") {
|
|
19346
|
+
event.preventDefault();
|
|
19347
|
+
event.stopPropagation();
|
|
19348
|
+
const firstTerminal = terminalItems[0];
|
|
19349
|
+
if (firstTerminal) focusNavigationItem(firstTerminal);
|
|
19350
|
+
return;
|
|
19351
|
+
}
|
|
19352
|
+
if (key === "Enter" || key === " " || key === "Spacebar") {
|
|
19353
|
+
event.preventDefault();
|
|
19354
|
+
event.stopPropagation();
|
|
19355
|
+
void createTerminal();
|
|
19356
|
+
}
|
|
19357
|
+
return;
|
|
19358
|
+
}
|
|
19359
|
+
const isVerticalNavigationKey = key === "ArrowUp" || key === "ArrowDown" || key === "Home" || key === "End";
|
|
19360
|
+
if (isVerticalNavigationKey) {
|
|
19361
|
+
event.preventDefault();
|
|
19362
|
+
event.stopPropagation();
|
|
19363
|
+
const currentIndex = terminalItems.findIndex((terminal) => terminal.id === item.id);
|
|
19364
|
+
if (key === "ArrowUp" && currentIndex === 0) {
|
|
19365
|
+
focusNavigationItem({ type: "add" });
|
|
19366
|
+
return;
|
|
19367
|
+
}
|
|
19368
|
+
if (terminalItems.length === 0) return;
|
|
19369
|
+
const nextIndex = key === "Home" ? 0 : key === "End" ? terminalItems.length - 1 : Math.max(
|
|
19370
|
+
0,
|
|
19371
|
+
Math.min(
|
|
19372
|
+
terminalItems.length - 1,
|
|
19373
|
+
currentIndex + (key === "ArrowDown" ? 1 : -1)
|
|
19374
|
+
)
|
|
19375
|
+
);
|
|
19376
|
+
const nextTerminal = terminalItems[nextIndex];
|
|
19377
|
+
if (nextTerminal) focusNavigationItem(nextTerminal);
|
|
19378
|
+
return;
|
|
19379
|
+
}
|
|
19380
|
+
if (key === "/") {
|
|
19381
|
+
event.preventDefault();
|
|
19382
|
+
event.stopPropagation();
|
|
19383
|
+
const target = event.currentTarget;
|
|
19384
|
+
const rect = target.getBoundingClientRect();
|
|
19385
|
+
target.dispatchEvent(
|
|
19386
|
+
new MouseEvent("contextmenu", {
|
|
19387
|
+
bubbles: true,
|
|
19388
|
+
cancelable: true,
|
|
19389
|
+
view: window,
|
|
19390
|
+
button: 2,
|
|
19391
|
+
buttons: 2,
|
|
19392
|
+
clientX: rect.left + rect.width / 2,
|
|
19393
|
+
clientY: rect.top + rect.height / 2
|
|
19394
|
+
})
|
|
19395
|
+
);
|
|
19396
|
+
return;
|
|
19397
|
+
}
|
|
19398
|
+
if (key === "Enter" || key === " " || key === "Spacebar") {
|
|
19399
|
+
event.preventDefault();
|
|
19400
|
+
event.stopPropagation();
|
|
19401
|
+
selectTerminal(item.id);
|
|
19402
|
+
}
|
|
19403
|
+
},
|
|
19404
|
+
[createTerminal, focusNavigationItem, selectTerminal, terminalItems]
|
|
19405
|
+
);
|
|
18175
19406
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-full flex-col", children: [
|
|
18176
19407
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-10 items-center gap-0.5 border-b border-border", children: [
|
|
18177
19408
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex text-muted-foreground items-center gap-1 px-3", children: [
|
|
@@ -18181,10 +19412,16 @@ function TerminalPanel({
|
|
|
18181
19412
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ml-auto mr-2 flex items-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18182
19413
|
Button,
|
|
18183
19414
|
{
|
|
19415
|
+
ref: (element) => registerNavigationItemRef(ADD_TERMINAL_NAVIGATION_ID, element),
|
|
18184
19416
|
variant: "ghost",
|
|
18185
19417
|
size: "icon",
|
|
19418
|
+
tabIndex: -1,
|
|
18186
19419
|
className: "size-6 text-muted-foreground hover:text-foreground",
|
|
18187
19420
|
onClick: () => void createTerminal(),
|
|
19421
|
+
onKeyDown: (event) => handleNavigationKeyDown(event, { type: "add" }),
|
|
19422
|
+
onFocus: () => {
|
|
19423
|
+
focusedNavigationItemIdRef.current = ADD_TERMINAL_NAVIGATION_ID;
|
|
19424
|
+
},
|
|
18188
19425
|
"aria-label": t("terminalPanel.addTerminal", "Add terminal"),
|
|
18189
19426
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "size-3.5" })
|
|
18190
19427
|
}
|
|
@@ -18193,41 +19430,70 @@ function TerminalPanel({
|
|
|
18193
19430
|
terminals.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center text-muted-foreground", children: [
|
|
18194
19431
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "size-10 rounded-full bg-muted flex items-center justify-center mb-3 -mt-10", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SquareTerminal, { className: "size-5 text-muted-foreground/60" }) }),
|
|
18195
19432
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground/70", children: t("terminalPanel.noTerminalSelected", "No terminals") })
|
|
18196
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-0.5 py-1 px-1", children: terminals.map((terminal) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
18197
|
-
|
|
18198
|
-
|
|
18199
|
-
|
|
18200
|
-
|
|
18201
|
-
|
|
18202
|
-
onSelectTerminal(terminal.id);
|
|
18203
|
-
},
|
|
18204
|
-
className: cn$1(
|
|
18205
|
-
"flex h-8 items-center gap-2 rounded-md pl-2 pr-1.5 text-xs w-full transition-colors",
|
|
18206
|
-
terminal.id === activeTerminalId ? "bg-accent text-accent-foreground" : "text-foreground/70 hover:bg-accent/50 hover:text-foreground"
|
|
18207
|
-
),
|
|
18208
|
-
children: [
|
|
18209
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18210
|
-
Circle,
|
|
19433
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ScrollArea, { className: "min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-0.5 py-1 px-1", children: terminals.map((terminal) => /* @__PURE__ */ jsxRuntimeExports.jsxs(ContextMenu, { children: [
|
|
19434
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
19435
|
+
ContextMenuTrigger,
|
|
19436
|
+
{
|
|
19437
|
+
render: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19438
|
+
"button",
|
|
18211
19439
|
{
|
|
18212
|
-
|
|
18213
|
-
|
|
18214
|
-
|
|
18215
|
-
|
|
19440
|
+
ref: (element) => registerNavigationItemRef(terminal.id, element),
|
|
19441
|
+
type: "button",
|
|
19442
|
+
tabIndex: -1,
|
|
19443
|
+
className: "outline-0 focus-visible:inset-ring-1 focus-visible:inset-ring-ring/80 rounded-md",
|
|
19444
|
+
"aria-current": terminal.id === activeTerminalId ? "true" : void 0,
|
|
19445
|
+
onKeyDown: (event) => handleNavigationKeyDown(event, { type: "terminal", id: terminal.id }),
|
|
19446
|
+
onFocus: () => {
|
|
19447
|
+
focusedNavigationItemIdRef.current = terminal.id;
|
|
19448
|
+
}
|
|
18216
19449
|
}
|
|
18217
19450
|
),
|
|
18218
|
-
|
|
18219
|
-
|
|
18220
|
-
"
|
|
18221
|
-
|
|
18222
|
-
|
|
18223
|
-
|
|
18224
|
-
|
|
18225
|
-
|
|
18226
|
-
|
|
18227
|
-
|
|
18228
|
-
|
|
18229
|
-
|
|
18230
|
-
|
|
19451
|
+
onClick: () => selectTerminal(terminal.id),
|
|
19452
|
+
className: cn$1(
|
|
19453
|
+
"flex h-8 items-center gap-2 rounded-md pl-2 pr-1.5 text-xs w-full transition-colors",
|
|
19454
|
+
terminal.id === activeTerminalId ? "bg-accent text-accent-foreground" : "text-foreground/70 hover:bg-accent/50 hover:text-foreground"
|
|
19455
|
+
),
|
|
19456
|
+
children: [
|
|
19457
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19458
|
+
Circle,
|
|
19459
|
+
{
|
|
19460
|
+
className: cn$1(
|
|
19461
|
+
"size-2 shrink-0",
|
|
19462
|
+
terminal.running ? "fill-emerald-400 text-emerald-400" : "text-muted-foreground"
|
|
19463
|
+
)
|
|
19464
|
+
}
|
|
19465
|
+
),
|
|
19466
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-left", children: terminal.id.slice(0, 8) }),
|
|
19467
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19468
|
+
"span",
|
|
19469
|
+
{
|
|
19470
|
+
className: "flex size-5 shrink-0 items-center justify-center rounded hover:bg-background/70",
|
|
19471
|
+
onClick: (e) => void deleteTerminal(terminal.id, e),
|
|
19472
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(X$1, { className: "size-3 text-muted-foreground" })
|
|
19473
|
+
}
|
|
19474
|
+
)
|
|
19475
|
+
]
|
|
19476
|
+
}
|
|
19477
|
+
),
|
|
19478
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(ContextMenuContent, { children: [
|
|
19479
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(ContextMenuItem, { onClick: () => selectTerminal(terminal.id), children: [
|
|
19480
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Eye, {}),
|
|
19481
|
+
t("terminalPanel.view", "View")
|
|
19482
|
+
] }),
|
|
19483
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(ContextMenuSeparator, {}),
|
|
19484
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
19485
|
+
ContextMenuItem,
|
|
19486
|
+
{
|
|
19487
|
+
variant: "destructive",
|
|
19488
|
+
onClick: () => void deleteTerminal(terminal.id),
|
|
19489
|
+
children: [
|
|
19490
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, {}),
|
|
19491
|
+
t("terminalPanel.delete", "Delete")
|
|
19492
|
+
]
|
|
19493
|
+
}
|
|
19494
|
+
)
|
|
19495
|
+
] })
|
|
19496
|
+
] }, terminal.id)) }) })
|
|
18231
19497
|
] });
|
|
18232
19498
|
}
|
|
18233
19499
|
function Panel({
|
|
@@ -18240,6 +19506,27 @@ function Panel({
|
|
|
18240
19506
|
onSelectTerminal
|
|
18241
19507
|
}) {
|
|
18242
19508
|
const { t } = useTranslation();
|
|
19509
|
+
const { focus } = useFocusTargetRegistry();
|
|
19510
|
+
const focusFileTree = reactExports.useCallback(() => {
|
|
19511
|
+
const focusFileTreeContent = () => focus("file-tree-content");
|
|
19512
|
+
if (tab === "files") {
|
|
19513
|
+
focusFileTreeContent();
|
|
19514
|
+
return;
|
|
19515
|
+
}
|
|
19516
|
+
onTabChange("files");
|
|
19517
|
+
window.requestAnimationFrame(focusFileTreeContent);
|
|
19518
|
+
}, [focus, onTabChange, tab]);
|
|
19519
|
+
useFocusTarget("file-tree", focusFileTree, Boolean(projectId));
|
|
19520
|
+
const focusTerminalList = reactExports.useCallback(() => {
|
|
19521
|
+
const focusTerminalListContent = () => focus("terminal-list-content");
|
|
19522
|
+
if (tab === "terminal") {
|
|
19523
|
+
focusTerminalListContent();
|
|
19524
|
+
return;
|
|
19525
|
+
}
|
|
19526
|
+
onTabChange("terminal");
|
|
19527
|
+
window.requestAnimationFrame(focusTerminalListContent);
|
|
19528
|
+
}, [focus, onTabChange, tab]);
|
|
19529
|
+
useFocusTarget("terminal-list", focusTerminalList, Boolean(projectId));
|
|
18243
19530
|
if (!projectId) {
|
|
18244
19531
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-full items-center justify-center text-xs text-muted-foreground border-l border-border bg-background", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("panel.noProjectSelected", "No project selected") }) });
|
|
18245
19532
|
}
|
|
@@ -18260,7 +19547,7 @@ function Panel({
|
|
|
18260
19547
|
t("panel.terminal", "Terminal")
|
|
18261
19548
|
] })
|
|
18262
19549
|
] }) }),
|
|
18263
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "files", className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19550
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "files", keepMounted: true, className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18264
19551
|
FilePanel,
|
|
18265
19552
|
{
|
|
18266
19553
|
projectId,
|
|
@@ -18268,7 +19555,7 @@ function Panel({
|
|
|
18268
19555
|
onPreviewFile
|
|
18269
19556
|
}
|
|
18270
19557
|
) }),
|
|
18271
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "terminal", className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19558
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(TabsContent, { value: "terminal", keepMounted: true, className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18272
19559
|
TerminalPanel,
|
|
18273
19560
|
{
|
|
18274
19561
|
projectId,
|
|
@@ -18350,61 +19637,21 @@ function Session({ session }) {
|
|
|
18350
19637
|
const [connectionError, setConnectionError] = reactExports.useState(false);
|
|
18351
19638
|
reactExports.useEffect(() => {
|
|
18352
19639
|
setConnectionError(false);
|
|
18353
|
-
|
|
19640
|
+
const sessionState = useAppStore.getState().getSessionState(sessionId);
|
|
19641
|
+
const shouldLoadHistory = sessionState.messages.length === 0 && !isCreatingSession && sessionState.loadedAt === null;
|
|
19642
|
+
if (shouldLoadHistory && fetchingRef.current === sessionId) return;
|
|
19643
|
+
if (shouldLoadHistory) fetchingRef.current = sessionId;
|
|
19644
|
+
void loadSession(sessionId, { loadHistory: shouldLoadHistory }).catch((err) => {
|
|
19645
|
+
if (err instanceof SessionLifecycleBusyError) return;
|
|
18354
19646
|
setConnectionError(true);
|
|
18355
19647
|
toast.error(err instanceof Error ? err.message : String(err));
|
|
19648
|
+
}).finally(() => {
|
|
19649
|
+
if (fetchingRef.current === sessionId) fetchingRef.current = null;
|
|
18356
19650
|
});
|
|
18357
|
-
const sessionState = useAppStore.getState().getSessionState(sessionId);
|
|
18358
|
-
if (sessionState.messages.length > 0 || isCreatingSession || sessionState.loadedAt !== null) {
|
|
18359
|
-
return;
|
|
18360
|
-
}
|
|
18361
|
-
if (fetchingRef.current === sessionId) return;
|
|
18362
|
-
fetchingRef.current = sessionId;
|
|
18363
|
-
async function fetchHistory() {
|
|
18364
|
-
useAppStore.getState().updateSessionState(sessionId, (prev) => ({
|
|
18365
|
-
...reduceFlushStreaming(prev),
|
|
18366
|
-
isLoading: true
|
|
18367
|
-
}));
|
|
18368
|
-
try {
|
|
18369
|
-
const result = await request.getSessionHistory({ sessionId });
|
|
18370
|
-
let state = useAppStore.getState().getSessionState(sessionId);
|
|
18371
|
-
state = { ...state, messages: [], activeToolCalls: /* @__PURE__ */ new Map(), activeSubagents: /* @__PURE__ */ new Map() };
|
|
18372
|
-
const displayIds = /* @__PURE__ */ new Set();
|
|
18373
|
-
for (const notification of result.messages) {
|
|
18374
|
-
const displayId = notification?.update?._meta?.fello?.displayId;
|
|
18375
|
-
if (displayId) {
|
|
18376
|
-
displayIds.add(displayId);
|
|
18377
|
-
}
|
|
18378
|
-
if (!notification?.update) continue;
|
|
18379
|
-
state = reduceSessionNotification(sessionId, state, notification);
|
|
18380
|
-
}
|
|
18381
|
-
for (const notification of state.pendingNotifications) {
|
|
18382
|
-
const did = notification.update._meta?.fello?.displayId;
|
|
18383
|
-
if (did && displayIds.has(did)) {
|
|
18384
|
-
continue;
|
|
18385
|
-
}
|
|
18386
|
-
state = reduceSessionNotification(sessionId, state, notification);
|
|
18387
|
-
}
|
|
18388
|
-
state = reduceFlushStreaming(state);
|
|
18389
|
-
state = {
|
|
18390
|
-
...state,
|
|
18391
|
-
isLoading: false,
|
|
18392
|
-
pendingNotifications: [],
|
|
18393
|
-
loadedAt: Date.now()
|
|
18394
|
-
};
|
|
18395
|
-
useAppStore.getState().updateSessionState(sessionId, () => state);
|
|
18396
|
-
} catch (err) {
|
|
18397
|
-
console.error("Failed to fetch session history", err);
|
|
18398
|
-
useAppStore.getState().updateSessionState(sessionId, (prev) => ({ ...prev, isLoading: false }));
|
|
18399
|
-
} finally {
|
|
18400
|
-
fetchingRef.current = null;
|
|
18401
|
-
}
|
|
18402
|
-
}
|
|
18403
|
-
void fetchHistory();
|
|
18404
19651
|
}, [sessionId, isCreatingSession, toast]);
|
|
18405
19652
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("main", { ref: setMainEl, className: "flex min-w-0 flex-1 flex-col relative overflow-hidden", children: isLoading || sessionConnected !== "connected" || isCreatingSession ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-4 relative", children: [
|
|
18406
19653
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute left-0 top-0 right-0 h-12", style: { WebkitAppRegion: "drag" } }),
|
|
18407
|
-
connectionError &&
|
|
19654
|
+
connectionError && !isCreatingSession ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
18408
19655
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm font-normal text-muted-foreground", children: t("session.connectionFailed") }),
|
|
18409
19656
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
18410
19657
|
Button,
|
|
@@ -18413,7 +19660,8 @@ function Session({ session }) {
|
|
|
18413
19660
|
size: "sm",
|
|
18414
19661
|
onClick: () => {
|
|
18415
19662
|
setConnectionError(false);
|
|
18416
|
-
|
|
19663
|
+
void loadSession(sessionId, { force: true, loadHistory: true }).catch((err) => {
|
|
19664
|
+
if (err instanceof SessionLifecycleBusyError) return;
|
|
18417
19665
|
setConnectionError(true);
|
|
18418
19666
|
toast.error(err instanceof Error ? err.message : String(err));
|
|
18419
19667
|
});
|