specrails-desktop 2.19.0 → 2.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client/dist/assets/ActivityFeedPage-BgLjSsDn.js +1 -0
- package/client/dist/assets/AgentBrowserCapture-R87DoreG.js +1 -0
- package/client/dist/assets/AgentModeCodePane-CO8F0ttc.js +2 -0
- package/client/dist/assets/AgentModeJobsPane-BecN3lwS.js +1 -0
- package/client/dist/assets/AgentsPage-_-Q9plMs.js +86 -0
- package/client/dist/assets/AnalyticsPage-Cqh5IGaF.js +1 -0
- package/client/dist/assets/{BarChart-HPiao--v.js → BarChart-DZlxRF5i.js} +1 -1
- package/client/dist/assets/CodePage-4eiDoOBX.js +2 -0
- package/client/dist/assets/{DesktopAnalyticsPage-B2RBxIvj.js → DesktopAnalyticsPage-DyiCeq0h.js} +1 -1
- package/client/dist/assets/{DocsDialog-BJDvUEGj.js → DocsDialog-CDZv0FMK.js} +2 -2
- package/client/dist/assets/DocsPage-BmwaXyUf.js +11 -0
- package/client/dist/assets/{ExportDropdown-CYMcbLTD.js → ExportDropdown-CWafyruY.js} +1 -1
- package/client/dist/assets/IntegrationsPage-CY2jfpeW.js +3 -0
- package/client/dist/assets/JobDetailPage-p0lsbXRg.js +1 -0
- package/client/dist/assets/JobsPage-GeKC3ckC.js +1 -0
- package/client/dist/assets/LogViewer-Cz7jzyU2.js +16 -0
- package/client/dist/assets/LoopBuilderPage-C_vv7AW2.js +7 -0
- package/client/dist/assets/LoopsPage-CettzySP.js +1 -0
- package/client/dist/assets/ProjectSettingsDialog-Xw30FTul.js +1 -0
- package/client/dist/assets/agent-B7GdHP3Z.js +1 -0
- package/client/dist/assets/agent-BHmcgoJf.js +1 -0
- package/client/dist/assets/agent-BdY_fii4.js +1 -0
- package/client/dist/assets/agent-C32FOi9v.js +1 -0
- package/client/dist/assets/agent-CiFQxoaZ2.js +1 -0
- package/client/dist/assets/agent-CtAag7V6.js +1 -0
- package/client/dist/assets/agent-DE4Mp1fY2.js +1 -0
- package/client/dist/assets/agent-DK8qovyG2.js +1 -0
- package/client/dist/assets/{dist-js-ClEfL6Bo.js → dist-js-DoZ1SVEs.js} +1 -1
- package/client/dist/assets/{dist-js-b2_z7zAi.js → dist-js-zlcAXgob.js} +1 -1
- package/client/dist/assets/index-5mbwBNQ-.css +2 -0
- package/client/dist/assets/index-CG4z4_Mq.js +152 -0
- package/client/dist/assets/{lib-CfphudAm.js → lib-zJbG81CY.js} +2 -2
- package/client/dist/assets/nav-BAsYcqdw2.js +1 -0
- package/client/dist/assets/nav-BRrNlZkr.js +1 -0
- package/client/dist/assets/nav-Bqhyfbcj2.js +1 -0
- package/client/dist/assets/nav-CQb9y1km.js +1 -0
- package/client/dist/assets/nav-Cibp2KWF.js +1 -0
- package/client/dist/assets/nav-CzKzuwH8.js +1 -0
- package/client/dist/assets/nav-Danf5sRf2.js +1 -0
- package/client/dist/assets/nav-DtTnF9xd.js +1 -0
- package/client/dist/assets/{settings-DmyDpuzu.js → settings-BPq9nCJm.js} +1 -1
- package/client/dist/assets/{settings-DaXhxNug2.js → settings-BWHGtmU12.js} +1 -1
- package/client/dist/assets/{settings-MjYVJvDE.js → settings-C-m3yEZ2.js} +1 -1
- package/client/dist/assets/settings-CY8udi0e.js +1 -0
- package/client/dist/assets/{settings-CfOWHPzc2.js → settings-DZj7Uqy32.js} +1 -1
- package/client/dist/assets/{settings-CX29QcQW.js → settings-VgCsjaYf.js} +1 -1
- package/client/dist/assets/{settings-DwPRLcxr2.js → settings-r8Qq2Gzp2.js} +1 -1
- package/client/dist/assets/{settings-BOZBX-Vq.js → settings-zZr7NzuB.js} +1 -1
- package/client/dist/assets/{upload-Ox9jUq1X.js → upload-Cm4KWhcE.js} +1 -1
- package/client/dist/assets/{value-BeQVX5gN.js → value-m3Q84dDF.js} +1 -1
- package/client/dist/index.html +5 -5
- package/package.json +1 -1
- package/server/dist/agent-chat-manager.js +117 -13
- package/server/dist/agent-chat-router.js +7 -2
- package/server/dist/agent-operator-prompt.js +4 -2
- package/server/dist/file-provenance.js +9 -6
- package/server/dist/project-git.js +147 -0
- package/server/dist/project-router-git.js +43 -0
- package/server/dist/project-router.js +2 -0
- package/client/dist/assets/ActivityFeedPage-C0_k6n5T.js +0 -1
- package/client/dist/assets/AgentBrowserCapture-NHUCEnTh.js +0 -1
- package/client/dist/assets/AgentModeCodePane-jddXrhPY.js +0 -2
- package/client/dist/assets/AgentsPage-BPjf6bId.js +0 -86
- package/client/dist/assets/AnalyticsPage-BaJjj5mO.js +0 -1
- package/client/dist/assets/CodePage-CAD4KfkC.js +0 -2
- package/client/dist/assets/DocsPage-B6H-DBs8.js +0 -11
- package/client/dist/assets/IntegrationsPage-Dx_UpQVk.js +0 -3
- package/client/dist/assets/JobDetailPage-BlTnsRAN.js +0 -16
- package/client/dist/assets/JobsPage-EB0PbXOk.js +0 -1
- package/client/dist/assets/LoopBuilderPage-DfWfhhJY.js +0 -7
- package/client/dist/assets/LoopsPage-DCVATTv5.js +0 -1
- package/client/dist/assets/agent-B5Ycau5M.js +0 -1
- package/client/dist/assets/agent-BEz08l4_2.js +0 -1
- package/client/dist/assets/agent-BIX51CEA.js +0 -1
- package/client/dist/assets/agent-Bc9Kwf65.js +0 -1
- package/client/dist/assets/agent-BiM7puyn.js +0 -1
- package/client/dist/assets/agent-C0kYSv3m2.js +0 -1
- package/client/dist/assets/agent-CCzWlfqs.js +0 -1
- package/client/dist/assets/agent-DiCSo31C.js +0 -1
- package/client/dist/assets/index-9yNUBwEi.css +0 -2
- package/client/dist/assets/index-BeujshsU.js +0 -152
- package/client/dist/assets/nav--1ErXZrS.js +0 -1
- package/client/dist/assets/nav-18nqSJ8h.js +0 -1
- package/client/dist/assets/nav-BuonHb17.js +0 -1
- package/client/dist/assets/nav-C-sCoOLY2.js +0 -1
- package/client/dist/assets/nav-ClXz_3Ic2.js +0 -1
- package/client/dist/assets/nav-CtqgSQeE2.js +0 -1
- package/client/dist/assets/nav-S3YvCaVv.js +0 -1
- package/client/dist/assets/nav-czg8NkN-.js +0 -1
- package/client/dist/assets/settings-zJFdTzKE.js +0 -1
- /package/client/dist/assets/{activity-C5SeKbom.js → activity-B_71BWg3.js} +0 -0
- /package/client/dist/assets/{activity-DLdwUYv7.js → activity-BpTTj_PH.js} +0 -0
- /package/client/dist/assets/{activity-BlvN5rhP.js → activity-Ch-wbr0C2.js} +0 -0
- /package/client/dist/assets/{activity-DVuiy8TI2.js → activity-D0rfjQzT2.js} +0 -0
- /package/client/dist/assets/{activity-DIJexk6v2.js → activity-D2e62vbV2.js} +0 -0
- /package/client/dist/assets/{activity-Dsf3J7iW.js → activity-DHv2V5Oi.js} +0 -0
- /package/client/dist/assets/{activity-DOKV_Wyf.js → activity-DemHQS7l.js} +0 -0
- /package/client/dist/assets/{addspec-CXfEOrD42.js → addspec-B6Ns8KU02.js} +0 -0
- /package/client/dist/assets/{addspec-D28kw9ow2.js → addspec-CrEm6Fzr2.js} +0 -0
- /package/client/dist/assets/{addspec-BXV6sx5l.js → addspec-D6L4ZteP.js} +0 -0
- /package/client/dist/assets/{addspec-DC1tgsFG.js → addspec-Dio-H5z0.js} +0 -0
- /package/client/dist/assets/{addspec-DcHALPEp.js → addspec-l_zU5gla.js} +0 -0
- /package/client/dist/assets/{addspec-CS895X6A.js → addspec-qGyH7MHy2.js} +0 -0
- /package/client/dist/assets/{addspec-D39EEg02.js → addspec-xwRX_Pnf.js} +0 -0
- /package/client/dist/assets/{agents-CsDEv4Fj.js → agents-CHgCudUV.js} +0 -0
- /package/client/dist/assets/{agents-z0kA-y0Q.js → agents-CnaPeSyw.js} +0 -0
- /package/client/dist/assets/{agents-BXDCFJQa.js → agents-DuhLEaQ_.js} +0 -0
- /package/client/dist/assets/{agents-BFrHy5d-2.js → agents-Dumx4JiM2.js} +0 -0
- /package/client/dist/assets/{agents-BFy2Kq_k2.js → agents-OzxCLVW1.js} +0 -0
- /package/client/dist/assets/{agents-CTdwacTO.js → agents-Xh-zYHUx2.js} +0 -0
- /package/client/dist/assets/{agents-BySH0Gvw.js → agents-hv3sqmPm2.js} +0 -0
- /package/client/dist/assets/{agentstudio-CSZo7p8K.js → agentstudio-BIxikDf_.js} +0 -0
- /package/client/dist/assets/{agentstudio-B8H2H4Db2.js → agentstudio-Bo91kfUd2.js} +0 -0
- /package/client/dist/assets/{agentstudio-B9zthaTJ.js → agentstudio-Bz8cP8_c.js} +0 -0
- /package/client/dist/assets/{agentstudio-BDMpU01s.js → agentstudio-CCthUdzR.js} +0 -0
- /package/client/dist/assets/{agentstudio-CdD6J23W.js → agentstudio-CcH8Ckql2.js} +0 -0
- /package/client/dist/assets/{agentstudio-D80fZu_M2.js → agentstudio-DARgYg5Z2.js} +0 -0
- /package/client/dist/assets/{agentstudio-EuKglkaF2.js → agentstudio-VJOa_NVO.js} +0 -0
- /package/client/dist/assets/{aiedit-B_VOTUo42.js → aiedit-5ZXN4cep2.js} +0 -0
- /package/client/dist/assets/{aiedit-DX3BBpXF.js → aiedit-7B2dvCv-.js} +0 -0
- /package/client/dist/assets/{aiedit-TON-4N9S.js → aiedit-B7gAJZVC.js} +0 -0
- /package/client/dist/assets/{aiedit-ybQmdsST.js → aiedit-D92V-kUW.js} +0 -0
- /package/client/dist/assets/{aiedit-D59sPapq2.js → aiedit-D9ualLVJ.js} +0 -0
- /package/client/dist/assets/{aiedit-Cxoe_0wv.js → aiedit-h48tJU0V2.js} +0 -0
- /package/client/dist/assets/{aiedit-GYOYWCHJ2.js → aiedit-xkA_mR2a2.js} +0 -0
- /package/client/dist/assets/{analytics-DGOoMkaZ.js → analytics-BBAfeB1o.js} +0 -0
- /package/client/dist/assets/{analytics-B2jjXLCP2.js → analytics-BM1R5CEp2.js} +0 -0
- /package/client/dist/assets/{analytics-BotqRU_R.js → analytics-BjLruoYS.js} +0 -0
- /package/client/dist/assets/{analytics-CqMJQb7N.js → analytics-CKwh2zUr.js} +0 -0
- /package/client/dist/assets/{analytics-DL7uwNAI2.js → analytics-CpcjUkV72.js} +0 -0
- /package/client/dist/assets/{analytics-Ck3vl2Qo2.js → analytics-DbXHdSlk2.js} +0 -0
- /package/client/dist/assets/{analytics-BTkXLTfa.js → analytics-Djzr1xUQ.js} +0 -0
- /package/client/dist/assets/{attachments-7w-BR2V2.js → attachments-Bnbyj2PN.js} +0 -0
- /package/client/dist/assets/{attachments-D0fGlFve.js → attachments-C-gyrCOb.js} +0 -0
- /package/client/dist/assets/{attachments-Cbh4AwjP.js → attachments-C11tOKZ_.js} +0 -0
- /package/client/dist/assets/{attachments-BcE7kZG-2.js → attachments-CIeLa8l12.js} +0 -0
- /package/client/dist/assets/{attachments-B5QX1Xfa2.js → attachments-Cxrs0pyL2.js} +0 -0
- /package/client/dist/assets/{attachments-BsJJXFzT.js → attachments-DslHfa-L.js} +0 -0
- /package/client/dist/assets/{attachments-D3DJpd3e2.js → attachments-TTPsc0a52.js} +0 -0
- /package/client/dist/assets/{browser-CmWGMRGf2.js → browser-BKP6hqQC2.js} +0 -0
- /package/client/dist/assets/{browser-CaV3BJNY2.js → browser-BTivfZKE2.js} +0 -0
- /package/client/dist/assets/{browser-BOxg0p3n.js → browser-DEEO-OSi.js} +0 -0
- /package/client/dist/assets/{browser-D6wbpBOL2.js → browser-DlKLfT612.js} +0 -0
- /package/client/dist/assets/{browser-dsgDU1HB.js → browser-DlSXtfu5.js} +0 -0
- /package/client/dist/assets/{browser-BSh8xUWV.js → browser-INCUyduh.js} +0 -0
- /package/client/dist/assets/{browser-9GR11iTi.js → browser-bpO3onlS.js} +0 -0
- /package/client/dist/assets/{chat-CYHUUW0p2.js → chat-5mdg_YIc2.js} +0 -0
- /package/client/dist/assets/{chat-CAo0jCnj2.js → chat-BGax2nV62.js} +0 -0
- /package/client/dist/assets/{chat-DhpcWjOf.js → chat-BpYxnkr4.js} +0 -0
- /package/client/dist/assets/{chat-cFG-UfRA2.js → chat-BvHrebKC2.js} +0 -0
- /package/client/dist/assets/{chat-B90iLDI4.js → chat-CZyiLJvQ.js} +0 -0
- /package/client/dist/assets/{chat-CW54IP3u.js → chat-DKYP7NnC.js} +0 -0
- /package/client/dist/assets/{chat-D1PXX_p2.js → chat-wkTIy9rX.js} +0 -0
- /package/client/dist/assets/{code-B5UrmjaE2.js → code-BFxE1Yt62.js} +0 -0
- /package/client/dist/assets/{code-B1aOMCVV.js → code-BefYOm5Q.js} +0 -0
- /package/client/dist/assets/{code-DZKjfzBN.js → code-BkXpJt99.js} +0 -0
- /package/client/dist/assets/{code-CjBHU0nw.js → code-C6Sq7_t8.js} +0 -0
- /package/client/dist/assets/{code--qUk_yn-.js → code-CGj3w-2N.js} +0 -0
- /package/client/dist/assets/{code-D7GLAjrz2.js → code-Dfsxc9o82.js} +0 -0
- /package/client/dist/assets/{code-Cjv4_HkK2.js → code-Y5urks5s2.js} +0 -0
- /package/client/dist/assets/{commands-oB9q2vy_2.js → commands-Bb7MnPqn2.js} +0 -0
- /package/client/dist/assets/{commands-MqNuGGO4.js → commands-CQkdthjF.js} +0 -0
- /package/client/dist/assets/{commands-BCx1uDIE.js → commands-C_7zZwJf.js} +0 -0
- /package/client/dist/assets/{commands-Bhw9Hqsa2.js → commands-DBc5llLi2.js} +0 -0
- /package/client/dist/assets/{commands-B9XaopQC.js → commands-D_6B8lfU.js} +0 -0
- /package/client/dist/assets/{commands-DuaQT-it.js → commands-DhZNhSbl.js} +0 -0
- /package/client/dist/assets/{commands-D0RnooQF2.js → commands-uz_uKT242.js} +0 -0
- /package/client/dist/assets/{common-wEB9RBdf.js → common-Bb64s3Bm.js} +0 -0
- /package/client/dist/assets/{common-BXzqeuiC2.js → common-C8ZD5upH2.js} +0 -0
- /package/client/dist/assets/{common-C-jaOdxz2.js → common-CeQUwuHt2.js} +0 -0
- /package/client/dist/assets/{common-BaJ6MF7T.js → common-DPxotRK9.js} +0 -0
- /package/client/dist/assets/{common-DPGR3Tfo.js → common-KbQuTSGg.js} +0 -0
- /package/client/dist/assets/{common-CRd-Ge5u2.js → common-QjVnq9XP2.js} +0 -0
- /package/client/dist/assets/{common-CKjy-R8-.js → common-k5MTOHpn.js} +0 -0
- /package/client/dist/assets/{dashboard-CcEpALV_.js → dashboard-B8032psZ.js} +0 -0
- /package/client/dist/assets/{dashboard-DxEPkALo2.js → dashboard-BHGKtxty2.js} +0 -0
- /package/client/dist/assets/{dashboard-MgDVmaYS2.js → dashboard-CXnoUgN22.js} +0 -0
- /package/client/dist/assets/{dashboard-CfltY66K.js → dashboard-Ccyxqy7d.js} +0 -0
- /package/client/dist/assets/{dashboard-DLeC5ziO.js → dashboard-Dc5ZAgMN.js} +0 -0
- /package/client/dist/assets/{dashboard-Bl2_Yjs6.js → dashboard-JMY8ueD3.js} +0 -0
- /package/client/dist/assets/{dashboard-C_vS9RaM2.js → dashboard-tkWr1aHD2.js} +0 -0
- /package/client/dist/assets/{explore-OZhWV0Eb2.js → explore-BHEhNekP2.js} +0 -0
- /package/client/dist/assets/{explore-D-htKul_.js → explore-CWlAXx0f2.js} +0 -0
- /package/client/dist/assets/{explore-Dvp-5qOw2.js → explore-DAsroA482.js} +0 -0
- /package/client/dist/assets/{explore-IS8VyaSZ.js → explore-DG1CtYqT.js} +0 -0
- /package/client/dist/assets/{explore-FaKfWCr72.js → explore-DMSGAnhK.js} +0 -0
- /package/client/dist/assets/{explore-B_79NLR5.js → explore-DaXiW9-6.js} +0 -0
- /package/client/dist/assets/{explore-D5b2jgvR.js → explore-UwHHj2ux.js} +0 -0
- /package/client/dist/assets/{format-command-CHImQv6W.js → format-command-BHymDa4r.js} +0 -0
- /package/client/dist/assets/{integrations-B97cGWfo2.js → integrations-B-JVE1_D.js} +0 -0
- /package/client/dist/assets/{integrations-C3Ma3GdM.js → integrations-BAujIDoE.js} +0 -0
- /package/client/dist/assets/{integrations-Bp3leAh3.js → integrations-CAF21FbQ.js} +0 -0
- /package/client/dist/assets/{integrations-Du_0rDfi2.js → integrations-CHCgning2.js} +0 -0
- /package/client/dist/assets/{integrations-C5MUA-0-.js → integrations-CtsOpq2D2.js} +0 -0
- /package/client/dist/assets/{integrations-CiQbCn_W.js → integrations-DS5FFMes.js} +0 -0
- /package/client/dist/assets/{integrations-t4X5UVcx2.js → integrations-axZN4--n2.js} +0 -0
- /package/client/dist/assets/{jira-D6IDTIsc2.js → jira-BcZzX9122.js} +0 -0
- /package/client/dist/assets/{jira-DdEKW9Pu.js → jira-CTYs7LA12.js} +0 -0
- /package/client/dist/assets/{jira-BzFvFn7t2.js → jira-D2nN39e92.js} +0 -0
- /package/client/dist/assets/{jira-BCHx9zUF.js → jira-DJxmIkyr.js} +0 -0
- /package/client/dist/assets/{jira-DSZ5xFRl.js → jira-IhC1ROIc.js} +0 -0
- /package/client/dist/assets/{jira-BqXyykbt2.js → jira-Iw575fN8.js} +0 -0
- /package/client/dist/assets/{jira-B1XaR6fj.js → jira-kbWZY7jH.js} +0 -0
- /package/client/dist/assets/{jobs-CeOcGHd_2.js → jobs-Bvh_HiRo2.js} +0 -0
- /package/client/dist/assets/{jobs-BgHEgCWk2.js → jobs-BzYX5VLd.js} +0 -0
- /package/client/dist/assets/{jobs-CU-khJTt.js → jobs-DTfaTfzQ2.js} +0 -0
- /package/client/dist/assets/{jobs-Ct5v2p6T.js → jobs-DrPyq5J2.js} +0 -0
- /package/client/dist/assets/{jobs-m7L0K9uC2.js → jobs-Dty7cCdI2.js} +0 -0
- /package/client/dist/assets/{jobs-Ce0SE81t.js → jobs-Dv8MP-eE.js} +0 -0
- /package/client/dist/assets/{jobs-BX9dP3Qn.js → jobs-DvkAoA8D.js} +0 -0
- /package/client/dist/assets/{loops-BlrQiK122.js → loops-BR4FmOv12.js} +0 -0
- /package/client/dist/assets/{loops-DuuWQWTI.js → loops-BgX_uudn.js} +0 -0
- /package/client/dist/assets/{loops-KOTryzk5.js → loops-Bpl2j2LP.js} +0 -0
- /package/client/dist/assets/{loops-Bs0ectZ32.js → loops-DW8hSMdS2.js} +0 -0
- /package/client/dist/assets/{loops-CLZV8HHY2.js → loops-Q2muu8hW2.js} +0 -0
- /package/client/dist/assets/{loops-t1mUZtf0.js → loops-Y3FQsUCh.js} +0 -0
- /package/client/dist/assets/{loops-BEUiCzEI.js → loops-q7CNDvfK.js} +0 -0
- /package/client/dist/assets/{mcp-CXy61khH.js → mcp-B8omp_Cd.js} +0 -0
- /package/client/dist/assets/{mcp-_DUUXTHB2.js → mcp-B_nWlxZa2.js} +0 -0
- /package/client/dist/assets/{mcp-dlOyUQQy2.js → mcp-Cb2jtHP72.js} +0 -0
- /package/client/dist/assets/{mcp-4QbfLPa4.js → mcp-DPqm2C8-.js} +0 -0
- /package/client/dist/assets/{mcp-NlLc9T8u2.js → mcp-DTCCrYHz2.js} +0 -0
- /package/client/dist/assets/{mcp-zqSVP7nA.js → mcp-D_oPS6Zc.js} +0 -0
- /package/client/dist/assets/{mcp-CmOBPDjE.js → mcp-DytBbASZ.js} +0 -0
- /package/client/dist/assets/{setup-BxVydxbl2.js → setup-CNMdCHHt2.js} +0 -0
- /package/client/dist/assets/{setup-BmXfxlzA2.js → setup-Cag4XrbL2.js} +0 -0
- /package/client/dist/assets/{setup-DIRZ1Lf-.js → setup-D9IHGoWU.js} +0 -0
- /package/client/dist/assets/{setup-Dx13pESZ.js → setup-Dg6Ba3JT.js} +0 -0
- /package/client/dist/assets/{setup-Z01j3st4.js → setup-DyK36RIW.js} +0 -0
- /package/client/dist/assets/{setup-SLAi4xxQ2.js → setup-aTlGxuwi2.js} +0 -0
- /package/client/dist/assets/{setup-DwbKSnKQ.js → setup-kWsoAeHQ.js} +0 -0
- /package/client/dist/assets/{specs-BYSOlQRw2.js → specs-BFSUPa122.js} +0 -0
- /package/client/dist/assets/{specs-BWQ-0EXt2.js → specs-BMzip1WY2.js} +0 -0
- /package/client/dist/assets/{specs-d-zU7_3Q.js → specs-C-mtLcXw.js} +0 -0
- /package/client/dist/assets/{specs-CkP0B28v2.js → specs-CAzpvADd2.js} +0 -0
- /package/client/dist/assets/{specs-57pue7UQ.js → specs-CyRIw_IR.js} +0 -0
- /package/client/dist/assets/{specs-nM5Cpcqe.js → specs-DMm7gB_l.js} +0 -0
- /package/client/dist/assets/{specs-RSYuLgF4.js → specs-DuottM0Z.js} +0 -0
- /package/client/dist/assets/{terminal-D3RTuBwy.js → terminal-58ReNaya.js} +0 -0
- /package/client/dist/assets/{terminal-Adi3W-GZ2.js → terminal-CDiOAmBd2.js} +0 -0
- /package/client/dist/assets/{terminal-DOuNm2BI.js → terminal-CJN-mQMc.js} +0 -0
- /package/client/dist/assets/{terminal-C8KlD61D.js → terminal-CYB4TiAd.js} +0 -0
- /package/client/dist/assets/{terminal-BA6FCZna2.js → terminal-DTQ_dPqi2.js} +0 -0
- /package/client/dist/assets/{terminal-BCIUSkrg.js → terminal-DawP8xNL.js} +0 -0
- /package/client/dist/assets/{terminal-DCkOEjSj2.js → terminal-DsaDTq5N2.js} +0 -0
- /package/client/dist/assets/{tickets-Bsyv_znj.js → tickets-CNvIilmP.js} +0 -0
- /package/client/dist/assets/{tickets-C_UPra_1.js → tickets-CujsZvkf.js} +0 -0
- /package/client/dist/assets/{tickets-B2q36GlQ2.js → tickets-DBfFePwk2.js} +0 -0
- /package/client/dist/assets/{tickets-DiUA3rXq.js → tickets-Da15iaRw.js} +0 -0
- /package/client/dist/assets/{tickets-DDjU7UfE2.js → tickets-Df6pee-O2.js} +0 -0
- /package/client/dist/assets/{tickets-DR4ZrPMf.js → tickets-DoRTUYRT.js} +0 -0
- /package/client/dist/assets/{tickets-D72LbUtU2.js → tickets-DvohTziT2.js} +0 -0
|
@@ -20,6 +20,12 @@ class AgentChatManager {
|
|
|
20
20
|
* window the attachment-extraction await opens between the busy guard and
|
|
21
21
|
* `_active.set` in onSpawn (mirrors ChatManager's reservation pattern). */
|
|
22
22
|
_reserved = new Set();
|
|
23
|
+
/** Messages sent while a turn was in flight — drained FIFO after it settles. */
|
|
24
|
+
_queue = new Map();
|
|
25
|
+
/** Conversations whose in-flight turn the user deliberately stopped. Consulted
|
|
26
|
+
* at settle so an abort is never mistaken for a stale session (auto-heal
|
|
27
|
+
* would resurrect the aborted prompt) nor surfaced as an error. */
|
|
28
|
+
_abortedTurns = new Set();
|
|
23
29
|
constructor(broadcast, db, port) {
|
|
24
30
|
this._broadcast = broadcast;
|
|
25
31
|
this._db = db;
|
|
@@ -29,10 +35,19 @@ class AgentChatManager {
|
|
|
29
35
|
isStreaming(conversationId) {
|
|
30
36
|
return this._active.has(conversationId);
|
|
31
37
|
}
|
|
38
|
+
/** True while a turn is in flight (spawned or reserved) — a send now queues. */
|
|
39
|
+
isBusy(conversationId) {
|
|
40
|
+
return this._active.has(conversationId) || this._reserved.has(conversationId);
|
|
41
|
+
}
|
|
32
42
|
/**
|
|
33
43
|
* Runs one agent turn: persists the user message, spawns the AI CLI pointed at
|
|
34
44
|
* the Specrails MCP, streams deltas + tool-use as `agent_*` events, then
|
|
35
45
|
* persists the assistant reply and the session id. Settles once.
|
|
46
|
+
*
|
|
47
|
+
* A send while a turn is in flight is QUEUED (never rejected): the busy check
|
|
48
|
+
* and the enqueue are synchronous (before any await), so the router's isBusy
|
|
49
|
+
* read in the same event-loop frame is consistent with what happens here.
|
|
50
|
+
* Queued turns drain FIFO after the current turn settles; abort discards them.
|
|
36
51
|
*/
|
|
37
52
|
async sendMessage(conversationId, userText, options = {}) {
|
|
38
53
|
const conversation = (0, agent_store_1.getAgentConversation)(this._db, conversationId);
|
|
@@ -40,16 +55,60 @@ class AgentChatManager {
|
|
|
40
55
|
this._emitError(conversationId, 'Unknown conversation');
|
|
41
56
|
return;
|
|
42
57
|
}
|
|
43
|
-
if (this.
|
|
44
|
-
this.
|
|
58
|
+
if (this.isBusy(conversationId)) {
|
|
59
|
+
const pending = this._queue.get(conversationId) ?? [];
|
|
60
|
+
const queueId = options.queueId ?? null;
|
|
61
|
+
pending.push({ queueId, text: userText, options });
|
|
62
|
+
this._queue.set(conversationId, pending);
|
|
63
|
+
this._broadcast({
|
|
64
|
+
type: 'agent_queued',
|
|
65
|
+
conversationId,
|
|
66
|
+
queueId,
|
|
67
|
+
text: userText,
|
|
68
|
+
position: pending.length,
|
|
69
|
+
timestamp: new Date().toISOString(),
|
|
70
|
+
});
|
|
45
71
|
return;
|
|
46
72
|
}
|
|
47
73
|
this._reserved.add(conversationId);
|
|
48
74
|
try {
|
|
49
|
-
await this.
|
|
75
|
+
await this._runTurnSafely(conversation, userText, options);
|
|
76
|
+
// Drain messages queued while we were running. Each drained turn re-reads
|
|
77
|
+
// the conversation row so a mid-flight tier/provider/model change applies.
|
|
78
|
+
for (;;) {
|
|
79
|
+
const pending = this._queue.get(conversationId);
|
|
80
|
+
const next = pending?.shift();
|
|
81
|
+
if (!next)
|
|
82
|
+
break;
|
|
83
|
+
if (pending && pending.length === 0)
|
|
84
|
+
this._queue.delete(conversationId);
|
|
85
|
+
const conv = (0, agent_store_1.getAgentConversation)(this._db, conversationId);
|
|
86
|
+
if (!conv)
|
|
87
|
+
break; // deleted mid-drain (abort() already cleared the queue)
|
|
88
|
+
this._broadcast({
|
|
89
|
+
type: 'agent_dequeued',
|
|
90
|
+
conversationId,
|
|
91
|
+
queueId: next.queueId,
|
|
92
|
+
text: next.text,
|
|
93
|
+
timestamp: new Date().toISOString(),
|
|
94
|
+
});
|
|
95
|
+
await this._runTurnSafely(conv, next.text, next.options);
|
|
96
|
+
}
|
|
50
97
|
}
|
|
51
98
|
finally {
|
|
52
99
|
this._reserved.delete(conversationId);
|
|
100
|
+
this._abortedTurns.delete(conversationId);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** One turn that can never break the drain loop (or leave the client hung
|
|
104
|
+
* streaming): an unexpected throw surfaces as agent_error instead. */
|
|
105
|
+
async _runTurnSafely(conversation, userText, options) {
|
|
106
|
+
try {
|
|
107
|
+
await this._runTurn(conversation, userText, options);
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
console.error(`[agent-chat] turn failed (${conversation.id}):`, err);
|
|
111
|
+
this._emitError(conversation.id, err instanceof Error ? err.message : 'The agent turn failed.');
|
|
53
112
|
}
|
|
54
113
|
}
|
|
55
114
|
async _runTurn(conversation, userText, options) {
|
|
@@ -167,10 +226,17 @@ class AgentChatManager {
|
|
|
167
226
|
switch (ev.kind) {
|
|
168
227
|
case 'text-delta':
|
|
169
228
|
streamed += ev.text;
|
|
170
|
-
|
|
229
|
+
// A killed child (abort / conversation DELETE) keeps flushing its
|
|
230
|
+
// buffered stdout — suppress the broadcasts once it left _active
|
|
231
|
+
// so stragglers can't resurrect client-side streaming state.
|
|
232
|
+
if (this._active.has(conversationId)) {
|
|
233
|
+
this._broadcast({ type: 'agent_stream', conversationId, delta: ev.text, timestamp: timestamp() });
|
|
234
|
+
}
|
|
171
235
|
break;
|
|
172
236
|
case 'tool-use':
|
|
173
|
-
this.
|
|
237
|
+
if (this._active.has(conversationId)) {
|
|
238
|
+
this._broadcast({ type: 'agent_tool', conversationId, tool: ev.name, timestamp: timestamp() });
|
|
239
|
+
}
|
|
174
240
|
break;
|
|
175
241
|
case 'session-started':
|
|
176
242
|
if (ev.sessionId)
|
|
@@ -199,12 +265,37 @@ class AgentChatManager {
|
|
|
199
265
|
}
|
|
200
266
|
return { text, sessionId: capturedSessionId, error: capturedError, code: result.code, spawnFailed: result.spawnFailed, stderrTail: result.stderrTail };
|
|
201
267
|
};
|
|
268
|
+
// Conversation CONFIG (provider/model/tier) is owned by the PATCH route —
|
|
269
|
+
// never write turn-START snapshots back at settle, or a mid-turn provider
|
|
270
|
+
// switch would be silently reverted and a queued turn drained onto the old
|
|
271
|
+
// provider. Only the session id persists, and only while the row's provider
|
|
272
|
+
// is still the one this turn actually ran on (a foreign session id must not
|
|
273
|
+
// pollute the new provider's freshly-reset state).
|
|
274
|
+
const persistSession = (sessionId) => {
|
|
275
|
+
const fresh = (0, agent_store_1.getAgentConversation)(this._db, conversationId);
|
|
276
|
+
if (fresh && fresh.provider === conversation.provider) {
|
|
277
|
+
(0, agent_store_1.updateAgentConversation)(this._db, conversationId, { session_id: sessionId });
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
const settleAborted = (r) => {
|
|
281
|
+
// Deliberate user Stop: keep any partial text (it was already streamed to
|
|
282
|
+
// the client), never auto-heal, never surface an error.
|
|
283
|
+
if (r.text && (0, agent_store_1.getAgentConversation)(this._db, conversationId)) {
|
|
284
|
+
(0, agent_store_1.addAgentMessage)(this._db, { conversationId, role: 'assistant', content: r.text });
|
|
285
|
+
persistSession(r.sessionId);
|
|
286
|
+
this._broadcast({ type: 'agent_done', conversationId, fullText: r.text, timestamp: timestamp() });
|
|
287
|
+
}
|
|
288
|
+
};
|
|
202
289
|
const canResume = !!conversation.session_id && adapter.capabilities.nativeResume;
|
|
203
290
|
let r = await invoke(canResume);
|
|
204
291
|
// Deleted mid-turn (DELETE aborts the child and drops the row): stop here —
|
|
205
292
|
// no auto-heal respawn, no FK-violating assistant INSERT.
|
|
206
293
|
if (!(0, agent_store_1.getAgentConversation)(this._db, conversationId))
|
|
207
294
|
return;
|
|
295
|
+
if (this._abortedTurns.delete(conversationId)) {
|
|
296
|
+
settleAborted(r);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
208
299
|
// Auto-heal a stale/foreign session: a resume that produced no text (e.g. a
|
|
209
300
|
// provider switch leaving another provider's session id, or codex
|
|
210
301
|
// "no rollout found for thread id") retries once as a fresh turn.
|
|
@@ -214,6 +305,10 @@ class AgentChatManager {
|
|
|
214
305
|
r = await invoke(false);
|
|
215
306
|
if (!(0, agent_store_1.getAgentConversation)(this._db, conversationId))
|
|
216
307
|
return;
|
|
308
|
+
if (this._abortedTurns.delete(conversationId)) {
|
|
309
|
+
settleAborted(r);
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
217
312
|
}
|
|
218
313
|
if (r.spawnFailed) {
|
|
219
314
|
this._emitError(conversationId, `Failed to launch ${adapter.binary}. Is it installed and on PATH?`);
|
|
@@ -221,18 +316,13 @@ class AgentChatManager {
|
|
|
221
316
|
}
|
|
222
317
|
if (r.text) {
|
|
223
318
|
(0, agent_store_1.addAgentMessage)(this._db, { conversationId, role: 'assistant', content: r.text });
|
|
224
|
-
(
|
|
225
|
-
session_id: r.sessionId,
|
|
226
|
-
provider: conversation.provider,
|
|
227
|
-
model,
|
|
228
|
-
tier_level: tierLevel,
|
|
229
|
-
});
|
|
319
|
+
persistSession(r.sessionId);
|
|
230
320
|
this._broadcast({ type: 'agent_done', conversationId, fullText: r.text, timestamp: timestamp() });
|
|
231
321
|
return;
|
|
232
322
|
}
|
|
233
323
|
// Failure: reset the session so the NEXT turn starts fresh, and surface the
|
|
234
324
|
// real reason instead of silently doing nothing.
|
|
235
|
-
(
|
|
325
|
+
persistSession(null);
|
|
236
326
|
const reason = r.error ||
|
|
237
327
|
(r.stderrTail ? r.stderrTail.split('\n').filter(Boolean).slice(-3).join(' ').slice(0, 300) : '') ||
|
|
238
328
|
(r.code !== 0 ? `${adapter.binary} exited with code ${r.code}` : 'The agent returned no output.');
|
|
@@ -265,8 +355,14 @@ class AgentChatManager {
|
|
|
265
355
|
console.error(`[agent-chat] auto-title failed (${conversationId}):`, err);
|
|
266
356
|
}
|
|
267
357
|
}
|
|
268
|
-
/** Aborts the active turn for a conversation, if any.
|
|
358
|
+
/** Aborts the active turn for a conversation, if any. Stop means stop: any
|
|
359
|
+
* queued messages are discarded too (broadcast so the client drops chips),
|
|
360
|
+
* and the settling turn is marked aborted so the stale-session auto-heal
|
|
361
|
+
* can never resurrect the stopped prompt as a fresh spawn. */
|
|
269
362
|
abort(conversationId) {
|
|
363
|
+
this._clearQueue(conversationId);
|
|
364
|
+
if (this.isBusy(conversationId))
|
|
365
|
+
this._abortedTurns.add(conversationId);
|
|
270
366
|
const child = this._active.get(conversationId);
|
|
271
367
|
if (!child)
|
|
272
368
|
return false;
|
|
@@ -279,8 +375,16 @@ class AgentChatManager {
|
|
|
279
375
|
this._active.delete(conversationId);
|
|
280
376
|
return true;
|
|
281
377
|
}
|
|
378
|
+
_clearQueue(conversationId) {
|
|
379
|
+
const pending = this._queue.get(conversationId);
|
|
380
|
+
if (!pending || pending.length === 0)
|
|
381
|
+
return;
|
|
382
|
+
this._queue.delete(conversationId);
|
|
383
|
+
this._broadcast({ type: 'agent_queue_cleared', conversationId, timestamp: new Date().toISOString() });
|
|
384
|
+
}
|
|
282
385
|
/** Kills all active turns (graceful shutdown). */
|
|
283
386
|
async shutdown() {
|
|
387
|
+
this._queue.clear();
|
|
284
388
|
for (const [, child] of this._active) {
|
|
285
389
|
try {
|
|
286
390
|
child.kill('SIGTERM');
|
|
@@ -295,12 +295,17 @@ function createAgentChatRouter(deps) {
|
|
|
295
295
|
if (rawAtt && typeof rawAtt === 'object' && Array.isArray(rawAtt.ids)) {
|
|
296
296
|
attachmentIds = (rawAtt.ids).filter((x) => typeof x === 'string');
|
|
297
297
|
}
|
|
298
|
+
const queueId = typeof body.queueId === 'string' ? body.queueId : null;
|
|
298
299
|
// Fire-and-forget: the turn streams over WS. Persist the chosen tier first so
|
|
299
300
|
// a refresh mid-turn restores the right level.
|
|
300
301
|
if (tierLevel !== undefined)
|
|
301
302
|
(0, agent_store_1.updateAgentConversation)(desktopDb, conversation.id, { tier_level: tierLevel });
|
|
302
|
-
|
|
303
|
-
|
|
303
|
+
// isBusy here and sendMessage's own busy/enqueue branch run in the same
|
|
304
|
+
// synchronous frame (the enqueue happens before sendMessage's first await),
|
|
305
|
+
// so the flag the client gets always matches what actually happened.
|
|
306
|
+
const queued = manager.isBusy(conversation.id);
|
|
307
|
+
void manager.sendMessage(conversation.id, text, { tierLevel, model, attachmentIds, queueId }).catch((e) => console.error('[agent-chat] send failed:', e));
|
|
308
|
+
res.status(202).json({ accepted: true, queued });
|
|
304
309
|
});
|
|
305
310
|
router.post('/conversations/:id/abort', (req, res) => {
|
|
306
311
|
const aborted = manager.abort(String(req.params.id));
|
|
@@ -74,8 +74,10 @@ coding pipelines over them.
|
|
|
74
74
|
block with language \`options\` at the very END of the reply, containing only a
|
|
75
75
|
JSON array of the choice labels (2-6 short strings, e.g.
|
|
76
76
|
\`["Option A", "Option B"]\`) — the app renders them as clickable chips the
|
|
77
|
-
user can tap to answer.
|
|
78
|
-
|
|
77
|
+
user can tap to answer. The opening \`\`\`options fence MUST start on its own
|
|
78
|
+
line (a blank line after your prose), the array on the next line, and the
|
|
79
|
+
block MUST close with \`\`\`. Never emit this block when you are not asking
|
|
80
|
+
the user to choose.
|
|
79
81
|
|
|
80
82
|
## Permission ladder & confirmation rules
|
|
81
83
|
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.GIT_EXEC_ENV = void 0;
|
|
6
7
|
exports.resolveHeadSha = resolveHeadSha;
|
|
7
8
|
exports.listUntracked = listUntracked;
|
|
8
9
|
exports.snapshotWorkingTree = snapshotWorkingTree;
|
|
@@ -30,7 +31,9 @@ const GIT_MAX_BUFFER = 16 * 1024 * 1024;
|
|
|
30
31
|
// the on-demand diff patches beyond this cap are skipped (the UI shows "diff
|
|
31
32
|
// unavailable" for them). Mirrors the existing large-job warn threshold (50).
|
|
32
33
|
const MAX_PATCH_FILES = 50;
|
|
33
|
-
|
|
34
|
+
// Exported: project-git.ts (the Agent-Mode git bar) runs the same cwd-scoped
|
|
35
|
+
// git calls and needs the identical hostile-repo hardening.
|
|
36
|
+
exports.GIT_EXEC_ENV = (() => {
|
|
34
37
|
// Inherit the parent env but STRIP git-location vars. If the app process (or a
|
|
35
38
|
// parent) ever exports GIT_DIR / GIT_WORK_TREE / GIT_INDEX_FILE, every cwd-scoped
|
|
36
39
|
// git call below would silently operate on that repo instead of the project —
|
|
@@ -66,7 +69,7 @@ function resolveHeadSha(cwd) {
|
|
|
66
69
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
67
70
|
timeout: GIT_TIMEOUT_MS,
|
|
68
71
|
maxBuffer: GIT_MAX_BUFFER,
|
|
69
|
-
env: GIT_EXEC_ENV,
|
|
72
|
+
env: exports.GIT_EXEC_ENV,
|
|
70
73
|
});
|
|
71
74
|
return out.trim();
|
|
72
75
|
}
|
|
@@ -84,7 +87,7 @@ function listUntracked(cwd) {
|
|
|
84
87
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
85
88
|
timeout: GIT_TIMEOUT_MS,
|
|
86
89
|
maxBuffer: GIT_MAX_BUFFER,
|
|
87
|
-
env: GIT_EXEC_ENV,
|
|
90
|
+
env: exports.GIT_EXEC_ENV,
|
|
88
91
|
});
|
|
89
92
|
return out.split('\0').filter((p) => p.length > 0);
|
|
90
93
|
}
|
|
@@ -101,7 +104,7 @@ function snapshotWorkingTree(cwd) {
|
|
|
101
104
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
102
105
|
timeout: GIT_TIMEOUT_MS,
|
|
103
106
|
maxBuffer: GIT_MAX_BUFFER,
|
|
104
|
-
env: GIT_EXEC_ENV,
|
|
107
|
+
env: exports.GIT_EXEC_ENV,
|
|
105
108
|
});
|
|
106
109
|
ref = out.trim();
|
|
107
110
|
}
|
|
@@ -135,7 +138,7 @@ function diffAgainstSnapshot(cwd, snapshotRef, untrackedBefore, baseSha) {
|
|
|
135
138
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
136
139
|
timeout: GIT_TIMEOUT_MS,
|
|
137
140
|
maxBuffer: GIT_MAX_BUFFER,
|
|
138
|
-
env: GIT_EXEC_ENV,
|
|
141
|
+
env: exports.GIT_EXEC_ENV,
|
|
139
142
|
});
|
|
140
143
|
}
|
|
141
144
|
catch {
|
|
@@ -272,7 +275,7 @@ function collectDiffPatches(cwd, snapshotRef, diff, baseSha) {
|
|
|
272
275
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
273
276
|
maxBuffer: MAX_PATCH_BYTES + 64 * 1024,
|
|
274
277
|
timeout: GIT_TIMEOUT_MS,
|
|
275
|
-
env: GIT_EXEC_ENV,
|
|
278
|
+
env: exports.GIT_EXEC_ENV,
|
|
276
279
|
});
|
|
277
280
|
}
|
|
278
281
|
catch (err) {
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseWorktreePorcelain = parseWorktreePorcelain;
|
|
4
|
+
exports.getProjectGitInfo = getProjectGitInfo;
|
|
5
|
+
exports.compactCheckoutError = compactCheckoutError;
|
|
6
|
+
exports.checkoutProjectBranch = checkoutProjectBranch;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const file_provenance_1 = require("./file-provenance");
|
|
9
|
+
// ─── Project git info + branch switch (Agent-Mode git bar) ────────────────────
|
|
10
|
+
//
|
|
11
|
+
// Read the repo's current branch / last commit / local branches, and check out
|
|
12
|
+
// another LOCAL branch on user request. Always spawns the `git` CLI with the
|
|
13
|
+
// hardened env from file-provenance (hostile-repo config stripped, prompts
|
|
14
|
+
// disabled) and argv arrays (no shell). The checkout target is validated
|
|
15
|
+
// against `git branch` output, so no user string can smuggle flags or refs.
|
|
16
|
+
const GIT_TIMEOUT_MS = 10_000;
|
|
17
|
+
const GIT_MAX_BUFFER = 4 * 1024 * 1024;
|
|
18
|
+
function git(repoDir, args) {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
(0, child_process_1.execFile)('git', args, { cwd: repoDir, env: file_provenance_1.GIT_EXEC_ENV, timeout: GIT_TIMEOUT_MS, maxBuffer: GIT_MAX_BUFFER, windowsHide: true }, (err, stdout, stderr) => {
|
|
21
|
+
if (err) {
|
|
22
|
+
const detail = String(stderr || err.message).trim();
|
|
23
|
+
reject(new Error(detail));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
resolve(String(stdout).trim());
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const NOT_A_REPO = { git: false, branch: null, detached: false, dirty: false, branches: [], lastCommit: null, worktrees: [] };
|
|
31
|
+
/** Parse `git worktree list --porcelain` blocks (blank-line separated). */
|
|
32
|
+
function parseWorktreePorcelain(out) {
|
|
33
|
+
const worktrees = [];
|
|
34
|
+
for (const block of out.split(/\n\n+/)) {
|
|
35
|
+
const lines = block.split('\n').map((l) => l.trim()).filter(Boolean);
|
|
36
|
+
if (lines.length === 0)
|
|
37
|
+
continue;
|
|
38
|
+
let wtPath = null;
|
|
39
|
+
let head = '';
|
|
40
|
+
let branch = null;
|
|
41
|
+
for (const line of lines) {
|
|
42
|
+
if (line.startsWith('worktree '))
|
|
43
|
+
wtPath = line.slice('worktree '.length);
|
|
44
|
+
else if (line.startsWith('HEAD '))
|
|
45
|
+
head = line.slice('HEAD '.length);
|
|
46
|
+
else if (line.startsWith('branch refs/heads/'))
|
|
47
|
+
branch = line.slice('branch refs/heads/'.length);
|
|
48
|
+
}
|
|
49
|
+
if (wtPath)
|
|
50
|
+
worktrees.push({ path: wtPath, branch, head, isMain: worktrees.length === 0 });
|
|
51
|
+
}
|
|
52
|
+
return worktrees;
|
|
53
|
+
}
|
|
54
|
+
async function listLocalBranches(repoDir) {
|
|
55
|
+
const out = await git(repoDir, ['branch', '--format=%(refname:short)']);
|
|
56
|
+
return out.split('\n').map((b) => b.trim()).filter(Boolean);
|
|
57
|
+
}
|
|
58
|
+
async function getProjectGitInfo(repoDir) {
|
|
59
|
+
try {
|
|
60
|
+
await git(repoDir, ['rev-parse', '--is-inside-work-tree']);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return NOT_A_REPO;
|
|
64
|
+
}
|
|
65
|
+
// symbolic-ref works on an unborn branch too (fresh `git init`); it fails
|
|
66
|
+
// when HEAD is detached.
|
|
67
|
+
let branch = null;
|
|
68
|
+
let detached = false;
|
|
69
|
+
try {
|
|
70
|
+
branch = await git(repoDir, ['symbolic-ref', '--short', 'HEAD']);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
detached = true;
|
|
74
|
+
}
|
|
75
|
+
let lastCommit = null;
|
|
76
|
+
try {
|
|
77
|
+
const raw = await git(repoDir, ['log', '-1', '--format=%h%s%cI']);
|
|
78
|
+
const [hash, subject, at] = raw.split('');
|
|
79
|
+
if (hash)
|
|
80
|
+
lastCommit = { hash, subject: subject ?? '', at: at ?? '' };
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
/* empty repo — no commits yet */
|
|
84
|
+
}
|
|
85
|
+
let branches = [];
|
|
86
|
+
try {
|
|
87
|
+
branches = await listLocalBranches(repoDir);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
/* keep [] */
|
|
91
|
+
}
|
|
92
|
+
let dirty = false;
|
|
93
|
+
try {
|
|
94
|
+
dirty = (await git(repoDir, ['status', '--porcelain'])) !== '';
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
/* keep false */
|
|
98
|
+
}
|
|
99
|
+
let worktrees = [];
|
|
100
|
+
try {
|
|
101
|
+
worktrees = parseWorktreePorcelain(await git(repoDir, ['worktree', 'list', '--porcelain']));
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
/* keep [] */
|
|
105
|
+
}
|
|
106
|
+
return { git: true, branch, detached, dirty, branches, lastCommit, worktrees };
|
|
107
|
+
}
|
|
108
|
+
/** Compact git's overwrite refusal: the raw message lists EVERY dirty file
|
|
109
|
+
* (dozens on a busy tree) — unreadable in a toast. Keep the count + a taste. */
|
|
110
|
+
function compactCheckoutError(msg) {
|
|
111
|
+
const lines = msg.split('\n').map((l) => l.trim()).filter(Boolean);
|
|
112
|
+
const idx = lines.findIndex((l) => l.includes('Your local changes to the following files would be overwritten'));
|
|
113
|
+
if (idx === -1)
|
|
114
|
+
return msg.slice(0, 400);
|
|
115
|
+
const files = lines
|
|
116
|
+
.slice(idx + 1)
|
|
117
|
+
.filter((l) => !l.startsWith('Please ') && !l.startsWith('Aborting') && !l.startsWith('error:') && !l.startsWith('hint:'));
|
|
118
|
+
if (files.length === 0)
|
|
119
|
+
return msg.slice(0, 400);
|
|
120
|
+
const shown = files.slice(0, 3).join(', ');
|
|
121
|
+
const more = files.length - Math.min(files.length, 3);
|
|
122
|
+
return (`Your local changes to ${files.length} file${files.length === 1 ? '' : 's'} would be overwritten by checkout` +
|
|
123
|
+
` (${shown}${more > 0 ? ` … +${more} more` : ''}). Commit or stash them first.`);
|
|
124
|
+
}
|
|
125
|
+
/** Check out an existing LOCAL branch. The name must match one reported by
|
|
126
|
+
* `git branch`, so arbitrary flags/refs can never reach the argv. */
|
|
127
|
+
async function checkoutProjectBranch(repoDir, branch) {
|
|
128
|
+
let branches;
|
|
129
|
+
try {
|
|
130
|
+
branches = await listLocalBranches(repoDir);
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
return { ok: false, error: err instanceof Error ? err.message : 'git failed' };
|
|
134
|
+
}
|
|
135
|
+
if (!branches.includes(branch)) {
|
|
136
|
+
return { ok: false, error: `Unknown local branch: ${branch}` };
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
await git(repoDir, ['checkout', branch]);
|
|
140
|
+
return { ok: true };
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
// Typical: uncommitted changes that would be overwritten — surface git's own
|
|
144
|
+
// reason (compacted: the raw refusal lists every dirty file).
|
|
145
|
+
return { ok: false, error: compactCheckoutError(err instanceof Error ? err.message : 'git checkout failed') };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerGitRoutes = registerGitRoutes;
|
|
4
|
+
const project_git_1 = require("./project-git");
|
|
5
|
+
// ─── Git domain routes (/api/projects/:projectId/git) ─────────────────────────
|
|
6
|
+
//
|
|
7
|
+
// Backs the Agent-Mode git bar: current branch + last commit + local branches,
|
|
8
|
+
// and a user-initiated branch switch. Git always runs against project.path (the
|
|
9
|
+
// REAL repo — under artifact relocation the workspace never holds the code).
|
|
10
|
+
function registerGitRoutes(deps) {
|
|
11
|
+
const { router, ctx } = deps;
|
|
12
|
+
router.get('/:projectId/git', async (req, res) => {
|
|
13
|
+
try {
|
|
14
|
+
res.json(await (0, project_git_1.getProjectGitInfo)(ctx(req).project.path));
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
console.error('[project-git] info failed:', err);
|
|
18
|
+
res.status(500).json({ error: 'Failed to read git info' });
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
router.post('/:projectId/git/checkout', async (req, res) => {
|
|
22
|
+
const body = (req.body ?? {});
|
|
23
|
+
const branch = typeof body.branch === 'string' ? body.branch.trim() : '';
|
|
24
|
+
if (!branch) {
|
|
25
|
+
res.status(400).json({ error: 'branch is required' });
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const repoDir = ctx(req).project.path;
|
|
29
|
+
try {
|
|
30
|
+
const result = await (0, project_git_1.checkoutProjectBranch)(repoDir, branch);
|
|
31
|
+
if (!result.ok) {
|
|
32
|
+
// 409: the working tree state (or an unknown branch) refused the switch.
|
|
33
|
+
res.status(409).json({ error: result.error });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
res.json(await (0, project_git_1.getProjectGitInfo)(repoDir));
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.error('[project-git] checkout failed:', err);
|
|
40
|
+
res.status(500).json({ error: 'Checkout failed' });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -19,6 +19,7 @@ const project_router_tickets_1 = require("./project-router-tickets");
|
|
|
19
19
|
const project_router_terminals_1 = require("./project-router-terminals");
|
|
20
20
|
const project_router_settings_1 = require("./project-router-settings");
|
|
21
21
|
const project_router_loop_runs_1 = require("./project-router-loop-runs");
|
|
22
|
+
const project_router_git_1 = require("./project-router-git");
|
|
22
23
|
// Re-export the spec helpers from their new home so existing importers
|
|
23
24
|
// (`import { ... } from './project-router'`) keep working unchanged.
|
|
24
25
|
var project_router_helpers_1 = require("./project-router-helpers");
|
|
@@ -117,5 +118,6 @@ function createProjectRouter(registry) {
|
|
|
117
118
|
(0, project_router_terminals_1.registerTerminalsRoutes)(deps);
|
|
118
119
|
(0, project_router_settings_1.registerSettingsRoutes)(deps);
|
|
119
120
|
(0, project_router_loop_runs_1.registerLoopRunRoutes)(deps);
|
|
121
|
+
(0, project_router_git_1.registerGitRoutes)(deps);
|
|
120
122
|
return router;
|
|
121
123
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./chunk-BNv3lrIs.js";import{Bt as t,In as n,On as r,Qt as i,Y as a,Zt as o,en as s,fn as c,mn as l,pn as u,rn as d,yt as f,zt as p}from"./index-BeujshsU.js";var m=i(`ban`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M4.929 4.929 19.07 19.071`,key:`196cmz`}]]),h=e(n(),1);function g(e){let t=new Set;return e.filter(e=>{let n=`${e.type}:${e.jobId}`;return t.has(n)?!1:(t.add(n),!0)})}function _({activeProjectId:e,limit:t=50}){let[n,r]=(0,h.useState)([]),[i,a]=(0,h.useState)(!1),[o,s]=(0,h.useState)(!0),u=(0,h.useRef)(e);(0,h.useEffect)(()=>{u.current=e},[e]);let{registerHandler:f,unregisterHandler:p}=c();(0,h.useEffect)(()=>{if(!e){r([]),s(!0);return}let n=!1;a(!0),r([]),s(!0);async function i(){let e=l();try{let i=await fetch(`${e}/activity?limit=${t}`);if(!i.ok||n)return;let a=await i.json();if(n)return;r(a),s(a.length===t)}catch{}finally{n||a(!1)}}return i(),()=>{n=!0}},[e,t]);let m=(0,h.useCallback)(async()=>{if(i||!o)return;a(!0);let e=l(),n=u.current;try{r(i=>{let o=i[i.length-1];if(!o)return i;let c=encodeURIComponent(o.timestamp);return fetch(`${e}/activity?limit=${t}&before=${c}`).then(e=>e.json()).then(e=>{if(u.current!==n){a(!1);return}r(t=>g([...t,...e])),s(e.length===t),a(!1)}).catch(()=>a(!1)),i})}catch{a(!1)}},[i,o,t]),_=(0,h.useCallback)(e=>{let t=e,n=u.current;if(!(!t||typeof t.type!=`string`)&&!(t.projectId&&t.projectId!==n)){if(t.type===`queue`&&Array.isArray(t.jobs)){let e=[];for(let n of t.jobs){let t=n.status===`completed`?`job_completed`:n.status===`failed`?`job_failed`:n.status===`canceled`?`job_canceled`:`job_started`;e.push({id:`${t}:${n.id}`,type:t,jobId:n.id,jobCommand:n.command??``,timestamp:n.startedAt??new Date().toISOString(),summary:`${t.replace(`_`,` `)}: ${n.command??``}`,costUsd:null})}e.length>0&&r(t=>g([...e,...t]))}if(t.type===`phase`&&t.phase&&t.state&&t.timestamp){let e={id:`phase:${t.phase}:${t.state}:${t.timestamp}`,type:`job_started`,jobId:`phase-${t.phase}`,jobCommand:d.t(`activity:feed.phaseCommand`,{phase:t.phase,state:t.state}),timestamp:t.timestamp,summary:`Phase ${t.phase} is ${t.state}`,costUsd:null};r(t=>g([e,...t]))}}},[]);return(0,h.useLayoutEffect)(()=>(f(`activity`,_),()=>p(`activity`)),[_,f,p]),{items:n,loading:i,hasMore:o,loadMore:m}}var v=u();function y(e,t){let n=Date.now()-new Date(e).getTime(),r=Math.floor(n/1e3);if(r<60)return t(`feed.relativeTime.seconds`,{value:r});let i=Math.floor(r/60);if(i<60)return t(`feed.relativeTime.minutes`,{value:i});let a=Math.floor(i/60);return a<24?t(`feed.relativeTime.hours`,{value:a}):t(`feed.relativeTime.days`,{value:Math.floor(a/24)})}function b({type:e}){switch(e){case`job_completed`:return(0,v.jsx)(t,{className:`w-4 h-4 text-green-500 aurora-light:text-accent-success flex-shrink-0`});case`job_failed`:return(0,v.jsx)(p,{className:`w-4 h-4 text-red-500 aurora-light:text-destructive flex-shrink-0`});case`job_canceled`:return(0,v.jsx)(m,{className:`w-4 h-4 text-muted-foreground flex-shrink-0`});default:return(0,v.jsx)(a,{className:`w-4 h-4 text-blue-500 aurora-light:text-accent-info flex-shrink-0`})}}function x(e,t){switch(e){case`job_completed`:return t(`common:status.completed`);case`job_failed`:return t(`common:status.failed`);case`job_canceled`:return t(`common:status.canceled`);default:return t(`feed.typeStarted`)}}function S(e){switch(e){case`job_completed`:return`text-green-500 aurora-light:text-accent-success`;case`job_failed`:return`text-red-500 aurora-light:text-destructive`;case`job_canceled`:return`text-muted-foreground`;default:return`text-blue-500 aurora-light:text-accent-info`}}function C(){let{t:e}=r(`activity`),{activeProjectId:t}=s(),{items:n,loading:i,hasMore:a,loadMore:c}=_({activeProjectId:t}),l=(0,h.useRef)(null);return(0,h.useEffect)(()=>{let e=l.current;if(!e)return;let t=new IntersectionObserver(e=>{e[0].isIntersecting&&a&&!i&&c()},{threshold:.1});return t.observe(e),()=>t.disconnect()},[a,i,c]),(0,v.jsxs)(`div`,{className:`flex flex-col h-full overflow-hidden`,children:[(0,v.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-3 border-b border-border bg-background/50`,children:[(0,v.jsx)(o,{className:`w-4 h-4 text-muted-foreground`}),(0,v.jsx)(`h1`,{className:`text-sm font-medium`,children:e(`feed.title`)})]}),(0,v.jsxs)(`div`,{className:`flex-1 overflow-y-auto`,children:[i&&n.length===0?(0,v.jsx)(`div`,{className:`flex items-center justify-center h-32`,children:(0,v.jsx)(f,{className:`w-4 h-4 animate-spin text-muted-foreground`})}):n.length===0?(0,v.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-48 gap-2 text-muted-foreground`,children:[(0,v.jsx)(o,{className:`w-8 h-8 opacity-40`}),(0,v.jsx)(`p`,{className:`text-sm`,children:e(`feed.emptyTitle`)}),(0,v.jsx)(`p`,{className:`text-xs opacity-70`,children:e(`feed.emptyHint`)})]}):(0,v.jsx)(`ul`,{className:`divide-y divide-border/50`,children:n.map(t=>(0,v.jsxs)(`li`,{className:`flex items-center gap-3 px-4 py-2.5 hover:bg-accent/30 transition-colors`,children:[(0,v.jsx)(b,{type:t.type}),(0,v.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,v.jsx)(`p`,{className:`text-xs text-foreground truncate`,title:t.jobCommand,children:t.jobCommand}),(0,v.jsxs)(`div`,{className:`flex items-center gap-2 mt-0.5`,children:[(0,v.jsx)(`span`,{className:`text-xs font-medium ${S(t.type)}`,children:x(t.type,e)}),t.costUsd!=null&&(0,v.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[`$`,t.costUsd.toFixed(4)]})]})]}),(0,v.jsx)(`span`,{className:`text-xs text-muted-foreground flex-shrink-0 tabular-nums`,children:y(t.timestamp,e)})]},`${t.type}:${t.jobId}`))}),(0,v.jsx)(`div`,{ref:l,className:`h-1`}),i&&n.length>0&&(0,v.jsx)(`div`,{className:`flex justify-center py-3`,children:(0,v.jsx)(f,{className:`w-4 h-4 animate-spin text-muted-foreground`})}),!a&&n.length>0&&(0,v.jsx)(`p`,{className:`text-center text-xs text-muted-foreground py-3`,children:e(`feed.allLoaded`)})]})]})}export{C as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./chunk-BNv3lrIs.js";import{D as t,Dn as n,In as r,On as i,n as a,pn as o,r as s}from"./index-BeujshsU.js";var c=e(r(),1),l=o();function u({projectId:e,conversationId:r}){let{t:o}=i(`agent`),{closeBrowser:u,queueCapture:d}=a(),f=(0,c.useMemo)(()=>`agent-${r??`home`}-${Math.round(performance.now())}`,[r]),p=async e=>{try{if(!r)throw Error(o(`workspace.requiresConversation`));let t=await(await fetch(e.screenshotDataUrl)).blob();d(await s(r,new File([t],`capture-${Date.now()}.png`,{type:`image/png`}))),n.success(o(`workspace.browserCaptured`)),u()}catch(e){n.error(e instanceof Error?e.message:o(`workspace.uploadFailed`))}};return(0,l.jsx)(t,{open:!0,onClose:u,projectId:e,pendingSpecId:f,confirmLabel:o(`workspace.browserConfirm`),onCaptured:e=>{p(e)}})}export{u as AgentBrowserCapture};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/CodePage-CAD4KfkC.js","assets/chunk-BNv3lrIs.js","assets/index-BeujshsU.js","assets/preload-helper-DSXbuxSR.js","assets/clsx-1dnHRn8W.js","assets/auth-Cvsb7-Ek.js","assets/activity-D8vQJrpW.js","assets/addspec-DxW6oPsk.js","assets/agent-CCzWlfqs.js","assets/agents-Cev2oFfX.js","assets/agentstudio-CZm2rOzt.js","assets/aiedit-DYtnZU9H.js","assets/analytics-B4FJ_pry.js","assets/attachments-Ci6_42Kh.js","assets/browser-ZB1afzjZ.js","assets/chat-VMflhzxn.js","assets/code-wtcs0ivb.js","assets/commands-CckaBWdV.js","assets/common-BPQQkgJZ.js","assets/dashboard-CoED_41r.js","assets/explore-BKVV5JSu.js","assets/integrations-CuWnMR5L.js","assets/jira-DXMoAKWD.js","assets/jobs---dwa4Nf.js","assets/loops-CQuuMlyZ.js","assets/mcp-CIH0pH1K.js","assets/nav-18nqSJ8h.js","assets/settings-zJFdTzKE.js","assets/setup-G4ZvDKxX.js","assets/specs-BYeAbIEy.js","assets/terminal-DFPNRLKp.js","assets/tickets-CkfbISuK.js","assets/index-9yNUBwEi.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{a as e}from"./chunk-BNv3lrIs.js";import{t}from"./preload-helper-DSXbuxSR.js";import{In as n,On as r,X as i,_t as a,n as o,pn as s,vt as c}from"./index-BeujshsU.js";var l=e(n(),1),u=s(),d=(0,l.lazy)(()=>t(()=>import(`./CodePage-CAD4KfkC.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]))),f=new Map,p=420,m=560;function h({projectId:e,conversationId:t}){let{t:n}=r(`agent`),{closeCodePane:s}=o(),[h,g]=(0,l.useState)(m),[_,v]=(0,l.useState)(!1),y=(0,l.useRef)(null),b=`${e}:${t}`,x=(0,l.useCallback)(e=>{f.set(b,e)},[b]),S=(0,l.useCallback)(e=>{let t=e.clientX,n=h,r=window.innerWidth-p;try{e.currentTarget.setPointerCapture(e.pointerId)}catch{}let i=e=>{g(Math.min(Math.max(n+(t-e.clientX),p),r))},a=()=>{window.removeEventListener(`pointermove`,i),window.removeEventListener(`pointerup`,a),window.removeEventListener(`pointercancel`,a)};window.addEventListener(`pointermove`,i),window.addEventListener(`pointerup`,a),window.addEventListener(`pointercancel`,a)},[h]);return(0,u.jsxs)(`div`,{ref:y,className:`flex h-full flex-col overflow-hidden border-l border-border bg-background`,style:_?{flex:1}:{width:h,flexShrink:0},children:[(0,u.jsx)(`div`,{className:`relative flex items-center`,children:!_&&(0,u.jsx)(`div`,{role:`separator`,"aria-orientation":`vertical`,onPointerDown:S,className:`absolute left-0 top-0 h-full w-1.5 -translate-x-full cursor-col-resize select-none touch-none hover:bg-accent-primary/20`,title:n(`workspace.resizeCode`)})}),(0,u.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-border/60 bg-surface/40 px-3 py-1.5`,children:[(0,u.jsx)(`span`,{className:`text-xs font-medium text-foreground/70`,children:n(`workspace.files`)}),(0,u.jsxs)(`div`,{className:`ml-auto flex items-center gap-1`,children:[(0,u.jsx)(`button`,{type:`button`,onClick:()=>v(e=>!e),"aria-label":n(_?`restore`:`maximize`),title:n(_?`restore`:`maximize`),className:`rounded-md p-1 text-foreground/60 hover:bg-surface hover:text-foreground`,children:_?(0,u.jsx)(a,{className:`h-4 w-4`}):(0,u.jsx)(c,{className:`h-4 w-4`})}),(0,u.jsx)(`button`,{type:`button`,onClick:s,"aria-label":n(`workspace.closeFiles`),title:n(`workspace.closeFiles`),className:`rounded-md p-1 text-foreground/60 hover:bg-surface hover:text-foreground`,children:(0,u.jsx)(i,{className:`h-4 w-4`})})]})]}),(0,u.jsx)(`div`,{className:`min-h-0 flex-1 overflow-hidden`,children:(0,u.jsx)(l.Suspense,{fallback:(0,u.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`…`}),children:(0,u.jsx)(d,{embedded:!0,initialPath:f.get(b)??null,onSelectedPathChange:x})})})]},b)}export{h as AgentModeCodePane};
|