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.
Files changed (252) hide show
  1. package/client/dist/assets/ActivityFeedPage-BgLjSsDn.js +1 -0
  2. package/client/dist/assets/AgentBrowserCapture-R87DoreG.js +1 -0
  3. package/client/dist/assets/AgentModeCodePane-CO8F0ttc.js +2 -0
  4. package/client/dist/assets/AgentModeJobsPane-BecN3lwS.js +1 -0
  5. package/client/dist/assets/AgentsPage-_-Q9plMs.js +86 -0
  6. package/client/dist/assets/AnalyticsPage-Cqh5IGaF.js +1 -0
  7. package/client/dist/assets/{BarChart-HPiao--v.js → BarChart-DZlxRF5i.js} +1 -1
  8. package/client/dist/assets/CodePage-4eiDoOBX.js +2 -0
  9. package/client/dist/assets/{DesktopAnalyticsPage-B2RBxIvj.js → DesktopAnalyticsPage-DyiCeq0h.js} +1 -1
  10. package/client/dist/assets/{DocsDialog-BJDvUEGj.js → DocsDialog-CDZv0FMK.js} +2 -2
  11. package/client/dist/assets/DocsPage-BmwaXyUf.js +11 -0
  12. package/client/dist/assets/{ExportDropdown-CYMcbLTD.js → ExportDropdown-CWafyruY.js} +1 -1
  13. package/client/dist/assets/IntegrationsPage-CY2jfpeW.js +3 -0
  14. package/client/dist/assets/JobDetailPage-p0lsbXRg.js +1 -0
  15. package/client/dist/assets/JobsPage-GeKC3ckC.js +1 -0
  16. package/client/dist/assets/LogViewer-Cz7jzyU2.js +16 -0
  17. package/client/dist/assets/LoopBuilderPage-C_vv7AW2.js +7 -0
  18. package/client/dist/assets/LoopsPage-CettzySP.js +1 -0
  19. package/client/dist/assets/ProjectSettingsDialog-Xw30FTul.js +1 -0
  20. package/client/dist/assets/agent-B7GdHP3Z.js +1 -0
  21. package/client/dist/assets/agent-BHmcgoJf.js +1 -0
  22. package/client/dist/assets/agent-BdY_fii4.js +1 -0
  23. package/client/dist/assets/agent-C32FOi9v.js +1 -0
  24. package/client/dist/assets/agent-CiFQxoaZ2.js +1 -0
  25. package/client/dist/assets/agent-CtAag7V6.js +1 -0
  26. package/client/dist/assets/agent-DE4Mp1fY2.js +1 -0
  27. package/client/dist/assets/agent-DK8qovyG2.js +1 -0
  28. package/client/dist/assets/{dist-js-ClEfL6Bo.js → dist-js-DoZ1SVEs.js} +1 -1
  29. package/client/dist/assets/{dist-js-b2_z7zAi.js → dist-js-zlcAXgob.js} +1 -1
  30. package/client/dist/assets/index-5mbwBNQ-.css +2 -0
  31. package/client/dist/assets/index-CG4z4_Mq.js +152 -0
  32. package/client/dist/assets/{lib-CfphudAm.js → lib-zJbG81CY.js} +2 -2
  33. package/client/dist/assets/nav-BAsYcqdw2.js +1 -0
  34. package/client/dist/assets/nav-BRrNlZkr.js +1 -0
  35. package/client/dist/assets/nav-Bqhyfbcj2.js +1 -0
  36. package/client/dist/assets/nav-CQb9y1km.js +1 -0
  37. package/client/dist/assets/nav-Cibp2KWF.js +1 -0
  38. package/client/dist/assets/nav-CzKzuwH8.js +1 -0
  39. package/client/dist/assets/nav-Danf5sRf2.js +1 -0
  40. package/client/dist/assets/nav-DtTnF9xd.js +1 -0
  41. package/client/dist/assets/{settings-DmyDpuzu.js → settings-BPq9nCJm.js} +1 -1
  42. package/client/dist/assets/{settings-DaXhxNug2.js → settings-BWHGtmU12.js} +1 -1
  43. package/client/dist/assets/{settings-MjYVJvDE.js → settings-C-m3yEZ2.js} +1 -1
  44. package/client/dist/assets/settings-CY8udi0e.js +1 -0
  45. package/client/dist/assets/{settings-CfOWHPzc2.js → settings-DZj7Uqy32.js} +1 -1
  46. package/client/dist/assets/{settings-CX29QcQW.js → settings-VgCsjaYf.js} +1 -1
  47. package/client/dist/assets/{settings-DwPRLcxr2.js → settings-r8Qq2Gzp2.js} +1 -1
  48. package/client/dist/assets/{settings-BOZBX-Vq.js → settings-zZr7NzuB.js} +1 -1
  49. package/client/dist/assets/{upload-Ox9jUq1X.js → upload-Cm4KWhcE.js} +1 -1
  50. package/client/dist/assets/{value-BeQVX5gN.js → value-m3Q84dDF.js} +1 -1
  51. package/client/dist/index.html +5 -5
  52. package/package.json +1 -1
  53. package/server/dist/agent-chat-manager.js +117 -13
  54. package/server/dist/agent-chat-router.js +7 -2
  55. package/server/dist/agent-operator-prompt.js +4 -2
  56. package/server/dist/file-provenance.js +9 -6
  57. package/server/dist/project-git.js +147 -0
  58. package/server/dist/project-router-git.js +43 -0
  59. package/server/dist/project-router.js +2 -0
  60. package/client/dist/assets/ActivityFeedPage-C0_k6n5T.js +0 -1
  61. package/client/dist/assets/AgentBrowserCapture-NHUCEnTh.js +0 -1
  62. package/client/dist/assets/AgentModeCodePane-jddXrhPY.js +0 -2
  63. package/client/dist/assets/AgentsPage-BPjf6bId.js +0 -86
  64. package/client/dist/assets/AnalyticsPage-BaJjj5mO.js +0 -1
  65. package/client/dist/assets/CodePage-CAD4KfkC.js +0 -2
  66. package/client/dist/assets/DocsPage-B6H-DBs8.js +0 -11
  67. package/client/dist/assets/IntegrationsPage-Dx_UpQVk.js +0 -3
  68. package/client/dist/assets/JobDetailPage-BlTnsRAN.js +0 -16
  69. package/client/dist/assets/JobsPage-EB0PbXOk.js +0 -1
  70. package/client/dist/assets/LoopBuilderPage-DfWfhhJY.js +0 -7
  71. package/client/dist/assets/LoopsPage-DCVATTv5.js +0 -1
  72. package/client/dist/assets/agent-B5Ycau5M.js +0 -1
  73. package/client/dist/assets/agent-BEz08l4_2.js +0 -1
  74. package/client/dist/assets/agent-BIX51CEA.js +0 -1
  75. package/client/dist/assets/agent-Bc9Kwf65.js +0 -1
  76. package/client/dist/assets/agent-BiM7puyn.js +0 -1
  77. package/client/dist/assets/agent-C0kYSv3m2.js +0 -1
  78. package/client/dist/assets/agent-CCzWlfqs.js +0 -1
  79. package/client/dist/assets/agent-DiCSo31C.js +0 -1
  80. package/client/dist/assets/index-9yNUBwEi.css +0 -2
  81. package/client/dist/assets/index-BeujshsU.js +0 -152
  82. package/client/dist/assets/nav--1ErXZrS.js +0 -1
  83. package/client/dist/assets/nav-18nqSJ8h.js +0 -1
  84. package/client/dist/assets/nav-BuonHb17.js +0 -1
  85. package/client/dist/assets/nav-C-sCoOLY2.js +0 -1
  86. package/client/dist/assets/nav-ClXz_3Ic2.js +0 -1
  87. package/client/dist/assets/nav-CtqgSQeE2.js +0 -1
  88. package/client/dist/assets/nav-S3YvCaVv.js +0 -1
  89. package/client/dist/assets/nav-czg8NkN-.js +0 -1
  90. package/client/dist/assets/settings-zJFdTzKE.js +0 -1
  91. /package/client/dist/assets/{activity-C5SeKbom.js → activity-B_71BWg3.js} +0 -0
  92. /package/client/dist/assets/{activity-DLdwUYv7.js → activity-BpTTj_PH.js} +0 -0
  93. /package/client/dist/assets/{activity-BlvN5rhP.js → activity-Ch-wbr0C2.js} +0 -0
  94. /package/client/dist/assets/{activity-DVuiy8TI2.js → activity-D0rfjQzT2.js} +0 -0
  95. /package/client/dist/assets/{activity-DIJexk6v2.js → activity-D2e62vbV2.js} +0 -0
  96. /package/client/dist/assets/{activity-Dsf3J7iW.js → activity-DHv2V5Oi.js} +0 -0
  97. /package/client/dist/assets/{activity-DOKV_Wyf.js → activity-DemHQS7l.js} +0 -0
  98. /package/client/dist/assets/{addspec-CXfEOrD42.js → addspec-B6Ns8KU02.js} +0 -0
  99. /package/client/dist/assets/{addspec-D28kw9ow2.js → addspec-CrEm6Fzr2.js} +0 -0
  100. /package/client/dist/assets/{addspec-BXV6sx5l.js → addspec-D6L4ZteP.js} +0 -0
  101. /package/client/dist/assets/{addspec-DC1tgsFG.js → addspec-Dio-H5z0.js} +0 -0
  102. /package/client/dist/assets/{addspec-DcHALPEp.js → addspec-l_zU5gla.js} +0 -0
  103. /package/client/dist/assets/{addspec-CS895X6A.js → addspec-qGyH7MHy2.js} +0 -0
  104. /package/client/dist/assets/{addspec-D39EEg02.js → addspec-xwRX_Pnf.js} +0 -0
  105. /package/client/dist/assets/{agents-CsDEv4Fj.js → agents-CHgCudUV.js} +0 -0
  106. /package/client/dist/assets/{agents-z0kA-y0Q.js → agents-CnaPeSyw.js} +0 -0
  107. /package/client/dist/assets/{agents-BXDCFJQa.js → agents-DuhLEaQ_.js} +0 -0
  108. /package/client/dist/assets/{agents-BFrHy5d-2.js → agents-Dumx4JiM2.js} +0 -0
  109. /package/client/dist/assets/{agents-BFy2Kq_k2.js → agents-OzxCLVW1.js} +0 -0
  110. /package/client/dist/assets/{agents-CTdwacTO.js → agents-Xh-zYHUx2.js} +0 -0
  111. /package/client/dist/assets/{agents-BySH0Gvw.js → agents-hv3sqmPm2.js} +0 -0
  112. /package/client/dist/assets/{agentstudio-CSZo7p8K.js → agentstudio-BIxikDf_.js} +0 -0
  113. /package/client/dist/assets/{agentstudio-B8H2H4Db2.js → agentstudio-Bo91kfUd2.js} +0 -0
  114. /package/client/dist/assets/{agentstudio-B9zthaTJ.js → agentstudio-Bz8cP8_c.js} +0 -0
  115. /package/client/dist/assets/{agentstudio-BDMpU01s.js → agentstudio-CCthUdzR.js} +0 -0
  116. /package/client/dist/assets/{agentstudio-CdD6J23W.js → agentstudio-CcH8Ckql2.js} +0 -0
  117. /package/client/dist/assets/{agentstudio-D80fZu_M2.js → agentstudio-DARgYg5Z2.js} +0 -0
  118. /package/client/dist/assets/{agentstudio-EuKglkaF2.js → agentstudio-VJOa_NVO.js} +0 -0
  119. /package/client/dist/assets/{aiedit-B_VOTUo42.js → aiedit-5ZXN4cep2.js} +0 -0
  120. /package/client/dist/assets/{aiedit-DX3BBpXF.js → aiedit-7B2dvCv-.js} +0 -0
  121. /package/client/dist/assets/{aiedit-TON-4N9S.js → aiedit-B7gAJZVC.js} +0 -0
  122. /package/client/dist/assets/{aiedit-ybQmdsST.js → aiedit-D92V-kUW.js} +0 -0
  123. /package/client/dist/assets/{aiedit-D59sPapq2.js → aiedit-D9ualLVJ.js} +0 -0
  124. /package/client/dist/assets/{aiedit-Cxoe_0wv.js → aiedit-h48tJU0V2.js} +0 -0
  125. /package/client/dist/assets/{aiedit-GYOYWCHJ2.js → aiedit-xkA_mR2a2.js} +0 -0
  126. /package/client/dist/assets/{analytics-DGOoMkaZ.js → analytics-BBAfeB1o.js} +0 -0
  127. /package/client/dist/assets/{analytics-B2jjXLCP2.js → analytics-BM1R5CEp2.js} +0 -0
  128. /package/client/dist/assets/{analytics-BotqRU_R.js → analytics-BjLruoYS.js} +0 -0
  129. /package/client/dist/assets/{analytics-CqMJQb7N.js → analytics-CKwh2zUr.js} +0 -0
  130. /package/client/dist/assets/{analytics-DL7uwNAI2.js → analytics-CpcjUkV72.js} +0 -0
  131. /package/client/dist/assets/{analytics-Ck3vl2Qo2.js → analytics-DbXHdSlk2.js} +0 -0
  132. /package/client/dist/assets/{analytics-BTkXLTfa.js → analytics-Djzr1xUQ.js} +0 -0
  133. /package/client/dist/assets/{attachments-7w-BR2V2.js → attachments-Bnbyj2PN.js} +0 -0
  134. /package/client/dist/assets/{attachments-D0fGlFve.js → attachments-C-gyrCOb.js} +0 -0
  135. /package/client/dist/assets/{attachments-Cbh4AwjP.js → attachments-C11tOKZ_.js} +0 -0
  136. /package/client/dist/assets/{attachments-BcE7kZG-2.js → attachments-CIeLa8l12.js} +0 -0
  137. /package/client/dist/assets/{attachments-B5QX1Xfa2.js → attachments-Cxrs0pyL2.js} +0 -0
  138. /package/client/dist/assets/{attachments-BsJJXFzT.js → attachments-DslHfa-L.js} +0 -0
  139. /package/client/dist/assets/{attachments-D3DJpd3e2.js → attachments-TTPsc0a52.js} +0 -0
  140. /package/client/dist/assets/{browser-CmWGMRGf2.js → browser-BKP6hqQC2.js} +0 -0
  141. /package/client/dist/assets/{browser-CaV3BJNY2.js → browser-BTivfZKE2.js} +0 -0
  142. /package/client/dist/assets/{browser-BOxg0p3n.js → browser-DEEO-OSi.js} +0 -0
  143. /package/client/dist/assets/{browser-D6wbpBOL2.js → browser-DlKLfT612.js} +0 -0
  144. /package/client/dist/assets/{browser-dsgDU1HB.js → browser-DlSXtfu5.js} +0 -0
  145. /package/client/dist/assets/{browser-BSh8xUWV.js → browser-INCUyduh.js} +0 -0
  146. /package/client/dist/assets/{browser-9GR11iTi.js → browser-bpO3onlS.js} +0 -0
  147. /package/client/dist/assets/{chat-CYHUUW0p2.js → chat-5mdg_YIc2.js} +0 -0
  148. /package/client/dist/assets/{chat-CAo0jCnj2.js → chat-BGax2nV62.js} +0 -0
  149. /package/client/dist/assets/{chat-DhpcWjOf.js → chat-BpYxnkr4.js} +0 -0
  150. /package/client/dist/assets/{chat-cFG-UfRA2.js → chat-BvHrebKC2.js} +0 -0
  151. /package/client/dist/assets/{chat-B90iLDI4.js → chat-CZyiLJvQ.js} +0 -0
  152. /package/client/dist/assets/{chat-CW54IP3u.js → chat-DKYP7NnC.js} +0 -0
  153. /package/client/dist/assets/{chat-D1PXX_p2.js → chat-wkTIy9rX.js} +0 -0
  154. /package/client/dist/assets/{code-B5UrmjaE2.js → code-BFxE1Yt62.js} +0 -0
  155. /package/client/dist/assets/{code-B1aOMCVV.js → code-BefYOm5Q.js} +0 -0
  156. /package/client/dist/assets/{code-DZKjfzBN.js → code-BkXpJt99.js} +0 -0
  157. /package/client/dist/assets/{code-CjBHU0nw.js → code-C6Sq7_t8.js} +0 -0
  158. /package/client/dist/assets/{code--qUk_yn-.js → code-CGj3w-2N.js} +0 -0
  159. /package/client/dist/assets/{code-D7GLAjrz2.js → code-Dfsxc9o82.js} +0 -0
  160. /package/client/dist/assets/{code-Cjv4_HkK2.js → code-Y5urks5s2.js} +0 -0
  161. /package/client/dist/assets/{commands-oB9q2vy_2.js → commands-Bb7MnPqn2.js} +0 -0
  162. /package/client/dist/assets/{commands-MqNuGGO4.js → commands-CQkdthjF.js} +0 -0
  163. /package/client/dist/assets/{commands-BCx1uDIE.js → commands-C_7zZwJf.js} +0 -0
  164. /package/client/dist/assets/{commands-Bhw9Hqsa2.js → commands-DBc5llLi2.js} +0 -0
  165. /package/client/dist/assets/{commands-B9XaopQC.js → commands-D_6B8lfU.js} +0 -0
  166. /package/client/dist/assets/{commands-DuaQT-it.js → commands-DhZNhSbl.js} +0 -0
  167. /package/client/dist/assets/{commands-D0RnooQF2.js → commands-uz_uKT242.js} +0 -0
  168. /package/client/dist/assets/{common-wEB9RBdf.js → common-Bb64s3Bm.js} +0 -0
  169. /package/client/dist/assets/{common-BXzqeuiC2.js → common-C8ZD5upH2.js} +0 -0
  170. /package/client/dist/assets/{common-C-jaOdxz2.js → common-CeQUwuHt2.js} +0 -0
  171. /package/client/dist/assets/{common-BaJ6MF7T.js → common-DPxotRK9.js} +0 -0
  172. /package/client/dist/assets/{common-DPGR3Tfo.js → common-KbQuTSGg.js} +0 -0
  173. /package/client/dist/assets/{common-CRd-Ge5u2.js → common-QjVnq9XP2.js} +0 -0
  174. /package/client/dist/assets/{common-CKjy-R8-.js → common-k5MTOHpn.js} +0 -0
  175. /package/client/dist/assets/{dashboard-CcEpALV_.js → dashboard-B8032psZ.js} +0 -0
  176. /package/client/dist/assets/{dashboard-DxEPkALo2.js → dashboard-BHGKtxty2.js} +0 -0
  177. /package/client/dist/assets/{dashboard-MgDVmaYS2.js → dashboard-CXnoUgN22.js} +0 -0
  178. /package/client/dist/assets/{dashboard-CfltY66K.js → dashboard-Ccyxqy7d.js} +0 -0
  179. /package/client/dist/assets/{dashboard-DLeC5ziO.js → dashboard-Dc5ZAgMN.js} +0 -0
  180. /package/client/dist/assets/{dashboard-Bl2_Yjs6.js → dashboard-JMY8ueD3.js} +0 -0
  181. /package/client/dist/assets/{dashboard-C_vS9RaM2.js → dashboard-tkWr1aHD2.js} +0 -0
  182. /package/client/dist/assets/{explore-OZhWV0Eb2.js → explore-BHEhNekP2.js} +0 -0
  183. /package/client/dist/assets/{explore-D-htKul_.js → explore-CWlAXx0f2.js} +0 -0
  184. /package/client/dist/assets/{explore-Dvp-5qOw2.js → explore-DAsroA482.js} +0 -0
  185. /package/client/dist/assets/{explore-IS8VyaSZ.js → explore-DG1CtYqT.js} +0 -0
  186. /package/client/dist/assets/{explore-FaKfWCr72.js → explore-DMSGAnhK.js} +0 -0
  187. /package/client/dist/assets/{explore-B_79NLR5.js → explore-DaXiW9-6.js} +0 -0
  188. /package/client/dist/assets/{explore-D5b2jgvR.js → explore-UwHHj2ux.js} +0 -0
  189. /package/client/dist/assets/{format-command-CHImQv6W.js → format-command-BHymDa4r.js} +0 -0
  190. /package/client/dist/assets/{integrations-B97cGWfo2.js → integrations-B-JVE1_D.js} +0 -0
  191. /package/client/dist/assets/{integrations-C3Ma3GdM.js → integrations-BAujIDoE.js} +0 -0
  192. /package/client/dist/assets/{integrations-Bp3leAh3.js → integrations-CAF21FbQ.js} +0 -0
  193. /package/client/dist/assets/{integrations-Du_0rDfi2.js → integrations-CHCgning2.js} +0 -0
  194. /package/client/dist/assets/{integrations-C5MUA-0-.js → integrations-CtsOpq2D2.js} +0 -0
  195. /package/client/dist/assets/{integrations-CiQbCn_W.js → integrations-DS5FFMes.js} +0 -0
  196. /package/client/dist/assets/{integrations-t4X5UVcx2.js → integrations-axZN4--n2.js} +0 -0
  197. /package/client/dist/assets/{jira-D6IDTIsc2.js → jira-BcZzX9122.js} +0 -0
  198. /package/client/dist/assets/{jira-DdEKW9Pu.js → jira-CTYs7LA12.js} +0 -0
  199. /package/client/dist/assets/{jira-BzFvFn7t2.js → jira-D2nN39e92.js} +0 -0
  200. /package/client/dist/assets/{jira-BCHx9zUF.js → jira-DJxmIkyr.js} +0 -0
  201. /package/client/dist/assets/{jira-DSZ5xFRl.js → jira-IhC1ROIc.js} +0 -0
  202. /package/client/dist/assets/{jira-BqXyykbt2.js → jira-Iw575fN8.js} +0 -0
  203. /package/client/dist/assets/{jira-B1XaR6fj.js → jira-kbWZY7jH.js} +0 -0
  204. /package/client/dist/assets/{jobs-CeOcGHd_2.js → jobs-Bvh_HiRo2.js} +0 -0
  205. /package/client/dist/assets/{jobs-BgHEgCWk2.js → jobs-BzYX5VLd.js} +0 -0
  206. /package/client/dist/assets/{jobs-CU-khJTt.js → jobs-DTfaTfzQ2.js} +0 -0
  207. /package/client/dist/assets/{jobs-Ct5v2p6T.js → jobs-DrPyq5J2.js} +0 -0
  208. /package/client/dist/assets/{jobs-m7L0K9uC2.js → jobs-Dty7cCdI2.js} +0 -0
  209. /package/client/dist/assets/{jobs-Ce0SE81t.js → jobs-Dv8MP-eE.js} +0 -0
  210. /package/client/dist/assets/{jobs-BX9dP3Qn.js → jobs-DvkAoA8D.js} +0 -0
  211. /package/client/dist/assets/{loops-BlrQiK122.js → loops-BR4FmOv12.js} +0 -0
  212. /package/client/dist/assets/{loops-DuuWQWTI.js → loops-BgX_uudn.js} +0 -0
  213. /package/client/dist/assets/{loops-KOTryzk5.js → loops-Bpl2j2LP.js} +0 -0
  214. /package/client/dist/assets/{loops-Bs0ectZ32.js → loops-DW8hSMdS2.js} +0 -0
  215. /package/client/dist/assets/{loops-CLZV8HHY2.js → loops-Q2muu8hW2.js} +0 -0
  216. /package/client/dist/assets/{loops-t1mUZtf0.js → loops-Y3FQsUCh.js} +0 -0
  217. /package/client/dist/assets/{loops-BEUiCzEI.js → loops-q7CNDvfK.js} +0 -0
  218. /package/client/dist/assets/{mcp-CXy61khH.js → mcp-B8omp_Cd.js} +0 -0
  219. /package/client/dist/assets/{mcp-_DUUXTHB2.js → mcp-B_nWlxZa2.js} +0 -0
  220. /package/client/dist/assets/{mcp-dlOyUQQy2.js → mcp-Cb2jtHP72.js} +0 -0
  221. /package/client/dist/assets/{mcp-4QbfLPa4.js → mcp-DPqm2C8-.js} +0 -0
  222. /package/client/dist/assets/{mcp-NlLc9T8u2.js → mcp-DTCCrYHz2.js} +0 -0
  223. /package/client/dist/assets/{mcp-zqSVP7nA.js → mcp-D_oPS6Zc.js} +0 -0
  224. /package/client/dist/assets/{mcp-CmOBPDjE.js → mcp-DytBbASZ.js} +0 -0
  225. /package/client/dist/assets/{setup-BxVydxbl2.js → setup-CNMdCHHt2.js} +0 -0
  226. /package/client/dist/assets/{setup-BmXfxlzA2.js → setup-Cag4XrbL2.js} +0 -0
  227. /package/client/dist/assets/{setup-DIRZ1Lf-.js → setup-D9IHGoWU.js} +0 -0
  228. /package/client/dist/assets/{setup-Dx13pESZ.js → setup-Dg6Ba3JT.js} +0 -0
  229. /package/client/dist/assets/{setup-Z01j3st4.js → setup-DyK36RIW.js} +0 -0
  230. /package/client/dist/assets/{setup-SLAi4xxQ2.js → setup-aTlGxuwi2.js} +0 -0
  231. /package/client/dist/assets/{setup-DwbKSnKQ.js → setup-kWsoAeHQ.js} +0 -0
  232. /package/client/dist/assets/{specs-BYSOlQRw2.js → specs-BFSUPa122.js} +0 -0
  233. /package/client/dist/assets/{specs-BWQ-0EXt2.js → specs-BMzip1WY2.js} +0 -0
  234. /package/client/dist/assets/{specs-d-zU7_3Q.js → specs-C-mtLcXw.js} +0 -0
  235. /package/client/dist/assets/{specs-CkP0B28v2.js → specs-CAzpvADd2.js} +0 -0
  236. /package/client/dist/assets/{specs-57pue7UQ.js → specs-CyRIw_IR.js} +0 -0
  237. /package/client/dist/assets/{specs-nM5Cpcqe.js → specs-DMm7gB_l.js} +0 -0
  238. /package/client/dist/assets/{specs-RSYuLgF4.js → specs-DuottM0Z.js} +0 -0
  239. /package/client/dist/assets/{terminal-D3RTuBwy.js → terminal-58ReNaya.js} +0 -0
  240. /package/client/dist/assets/{terminal-Adi3W-GZ2.js → terminal-CDiOAmBd2.js} +0 -0
  241. /package/client/dist/assets/{terminal-DOuNm2BI.js → terminal-CJN-mQMc.js} +0 -0
  242. /package/client/dist/assets/{terminal-C8KlD61D.js → terminal-CYB4TiAd.js} +0 -0
  243. /package/client/dist/assets/{terminal-BA6FCZna2.js → terminal-DTQ_dPqi2.js} +0 -0
  244. /package/client/dist/assets/{terminal-BCIUSkrg.js → terminal-DawP8xNL.js} +0 -0
  245. /package/client/dist/assets/{terminal-DCkOEjSj2.js → terminal-DsaDTq5N2.js} +0 -0
  246. /package/client/dist/assets/{tickets-Bsyv_znj.js → tickets-CNvIilmP.js} +0 -0
  247. /package/client/dist/assets/{tickets-C_UPra_1.js → tickets-CujsZvkf.js} +0 -0
  248. /package/client/dist/assets/{tickets-B2q36GlQ2.js → tickets-DBfFePwk2.js} +0 -0
  249. /package/client/dist/assets/{tickets-DiUA3rXq.js → tickets-Da15iaRw.js} +0 -0
  250. /package/client/dist/assets/{tickets-DDjU7UfE2.js → tickets-Df6pee-O2.js} +0 -0
  251. /package/client/dist/assets/{tickets-DR4ZrPMf.js → tickets-DoRTUYRT.js} +0 -0
  252. /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._active.has(conversationId) || this._reserved.has(conversationId)) {
44
- this._emitError(conversationId, 'The agent is busy. Try again in a moment.');
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._runTurn(conversation, userText, options);
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
- this._broadcast({ type: 'agent_stream', conversationId, delta: ev.text, timestamp: timestamp() });
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._broadcast({ type: 'agent_tool', conversationId, tool: ev.name, timestamp: timestamp() });
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
- (0, agent_store_1.updateAgentConversation)(this._db, conversationId, {
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
- (0, agent_store_1.updateAgentConversation)(this._db, conversationId, { session_id: null, provider: conversation.provider, model, tier_level: tierLevel });
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
- void manager.sendMessage(conversation.id, text, { tierLevel, model, attachmentIds }).catch((e) => console.error('[agent-chat] send failed:', e));
303
- res.status(202).json({ accepted: true });
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. Never emit this block when you are not asking the
78
- user to choose.
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
- const GIT_EXEC_ENV = (() => {
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};