@recombine-ai/bosun 0.16.2 → 0.17.1

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 (524) hide show
  1. package/README.md +24 -0
  2. package/bin/bosun.js +153 -20
  3. package/bin/git-mode.js +1139 -0
  4. package/build/client/_app/immutable/assets/0.D9HpHezk.css +1 -0
  5. package/build/client/_app/immutable/assets/0.D9HpHezk.css.br +0 -0
  6. package/build/client/_app/immutable/assets/0.D9HpHezk.css.gz +0 -0
  7. package/build/client/_app/immutable/assets/{2.DtxQDOXx.css → 2.Bc0Sf3YD.css} +1 -1
  8. package/build/client/_app/immutable/assets/2.Bc0Sf3YD.css.br +0 -0
  9. package/build/client/_app/immutable/assets/2.Bc0Sf3YD.css.gz +0 -0
  10. package/build/client/_app/immutable/chunks/{DneQQ7D5.js → -3ZOIHDA.js} +1 -1
  11. package/build/client/_app/immutable/chunks/-3ZOIHDA.js.br +0 -0
  12. package/build/client/_app/immutable/chunks/-3ZOIHDA.js.gz +0 -0
  13. package/build/client/_app/immutable/chunks/7hV1SZxK.js +1 -0
  14. package/build/client/_app/immutable/chunks/7hV1SZxK.js.br +2 -0
  15. package/build/client/_app/immutable/chunks/7hV1SZxK.js.gz +0 -0
  16. package/build/client/_app/immutable/chunks/B-dTD_wm.js +1 -0
  17. package/build/client/_app/immutable/chunks/B-dTD_wm.js.br +0 -0
  18. package/build/client/_app/immutable/chunks/B-dTD_wm.js.gz +0 -0
  19. package/build/client/_app/immutable/chunks/{UqjCSZmA.js → B-iasAJv.js} +1 -1
  20. package/build/client/_app/immutable/chunks/B-iasAJv.js.br +0 -0
  21. package/build/client/_app/immutable/chunks/B-iasAJv.js.gz +0 -0
  22. package/build/client/_app/immutable/chunks/BDijIo6D.js +33 -0
  23. package/build/client/_app/immutable/chunks/BDijIo6D.js.br +0 -0
  24. package/build/client/_app/immutable/chunks/BDijIo6D.js.gz +0 -0
  25. package/build/client/_app/immutable/chunks/BHB0Pj1h.js +2 -0
  26. package/build/client/_app/immutable/chunks/BHB0Pj1h.js.br +0 -0
  27. package/build/client/_app/immutable/chunks/BHB0Pj1h.js.gz +0 -0
  28. package/build/client/_app/immutable/chunks/{Bog028VR.js → BKfmN1Rj.js} +1 -1
  29. package/build/client/_app/immutable/chunks/BKfmN1Rj.js.br +0 -0
  30. package/build/client/_app/immutable/chunks/BKfmN1Rj.js.gz +0 -0
  31. package/build/client/_app/immutable/chunks/{pPpIn6tB.js → BlFOg-Sd.js} +1 -1
  32. package/build/client/_app/immutable/chunks/BlFOg-Sd.js.br +0 -0
  33. package/build/client/_app/immutable/chunks/BlFOg-Sd.js.gz +0 -0
  34. package/build/client/_app/immutable/chunks/{CJcZ2GVC.js → Byg3jr1u.js} +1 -1
  35. package/build/client/_app/immutable/chunks/Byg3jr1u.js.br +0 -0
  36. package/build/client/_app/immutable/chunks/Byg3jr1u.js.gz +0 -0
  37. package/build/client/_app/immutable/chunks/{Bmd5zhWC.js → BzxxLgHi.js} +1 -1
  38. package/build/client/_app/immutable/chunks/BzxxLgHi.js.br +0 -0
  39. package/build/client/_app/immutable/chunks/BzxxLgHi.js.gz +0 -0
  40. package/build/client/_app/immutable/chunks/{CEHsomMo.js → C4UC6AgE.js} +1 -1
  41. package/build/client/_app/immutable/chunks/C4UC6AgE.js.br +0 -0
  42. package/build/client/_app/immutable/chunks/{CEHsomMo.js.gz → C4UC6AgE.js.gz} +0 -0
  43. package/build/client/_app/immutable/chunks/C60AG6QQ.js +1 -0
  44. package/build/client/_app/immutable/chunks/C60AG6QQ.js.br +0 -0
  45. package/build/client/_app/immutable/chunks/C60AG6QQ.js.gz +0 -0
  46. package/build/client/_app/immutable/chunks/CAIfVN23.js +1 -0
  47. package/build/client/_app/immutable/chunks/CAIfVN23.js.br +0 -0
  48. package/build/client/_app/immutable/chunks/CAIfVN23.js.gz +0 -0
  49. package/build/client/_app/immutable/chunks/{JcG4w2gF.js → CB9iDxwI.js} +1 -1
  50. package/build/client/_app/immutable/chunks/CB9iDxwI.js.br +0 -0
  51. package/build/client/_app/immutable/chunks/CB9iDxwI.js.gz +0 -0
  52. package/build/client/_app/immutable/chunks/{DoD3q5w5.js → CD_KdWs9.js} +1 -1
  53. package/build/client/_app/immutable/chunks/CD_KdWs9.js.br +0 -0
  54. package/build/client/_app/immutable/chunks/CD_KdWs9.js.gz +0 -0
  55. package/build/client/_app/immutable/chunks/CDy1LBR5.js +1 -0
  56. package/build/client/_app/immutable/chunks/CDy1LBR5.js.br +0 -0
  57. package/build/client/_app/immutable/chunks/CDy1LBR5.js.gz +0 -0
  58. package/build/client/_app/immutable/chunks/{DCXjBDmY.js → CMFNmSvo.js} +1 -1
  59. package/build/client/_app/immutable/chunks/CMFNmSvo.js.br +0 -0
  60. package/build/client/_app/immutable/chunks/CMFNmSvo.js.gz +0 -0
  61. package/build/client/_app/immutable/chunks/{Bv1mNXs0.js → CNIn4L55.js} +1 -1
  62. package/build/client/_app/immutable/chunks/CNIn4L55.js.br +0 -0
  63. package/build/client/_app/immutable/chunks/CNIn4L55.js.gz +0 -0
  64. package/build/client/_app/immutable/chunks/CUKoVL36.js +1 -0
  65. package/build/client/_app/immutable/chunks/CUKoVL36.js.br +0 -0
  66. package/build/client/_app/immutable/chunks/CUKoVL36.js.gz +0 -0
  67. package/build/client/_app/immutable/chunks/CYGbCr1i.js +3 -0
  68. package/build/client/_app/immutable/chunks/CYGbCr1i.js.br +0 -0
  69. package/build/client/_app/immutable/chunks/CYGbCr1i.js.gz +0 -0
  70. package/build/client/_app/immutable/chunks/CYr0FGgn.js +1 -0
  71. package/build/client/_app/immutable/chunks/CYr0FGgn.js.br +0 -0
  72. package/build/client/_app/immutable/chunks/CYr0FGgn.js.gz +0 -0
  73. package/build/client/_app/immutable/chunks/{DtXXy94i.js → Ce6a22qU.js} +1 -1
  74. package/build/client/_app/immutable/chunks/Ce6a22qU.js.br +0 -0
  75. package/build/client/_app/immutable/chunks/Ce6a22qU.js.gz +0 -0
  76. package/build/client/_app/immutable/chunks/{DfcDjAv-.js → CeoQ-OhK.js} +1 -1
  77. package/build/client/_app/immutable/chunks/CeoQ-OhK.js.br +0 -0
  78. package/build/client/_app/immutable/chunks/CeoQ-OhK.js.gz +0 -0
  79. package/build/client/_app/immutable/chunks/{D8mA-uZ4.js → CupXtwVS.js} +1 -1
  80. package/build/client/_app/immutable/chunks/CupXtwVS.js.br +0 -0
  81. package/build/client/_app/immutable/chunks/CupXtwVS.js.gz +0 -0
  82. package/build/client/_app/immutable/chunks/{B5zf3x62.js → Cy2Uze-c.js} +1 -1
  83. package/build/client/_app/immutable/chunks/Cy2Uze-c.js.br +0 -0
  84. package/build/client/_app/immutable/chunks/Cy2Uze-c.js.gz +0 -0
  85. package/build/client/_app/immutable/chunks/{Dg0A8wPA.js → D8Lmn3S5.js} +1 -1
  86. package/build/client/_app/immutable/chunks/D8Lmn3S5.js.br +0 -0
  87. package/build/client/_app/immutable/chunks/D8Lmn3S5.js.gz +0 -0
  88. package/build/client/_app/immutable/chunks/D8doM1Y6.js +1 -0
  89. package/build/client/_app/immutable/chunks/D8doM1Y6.js.br +2 -0
  90. package/build/client/_app/immutable/chunks/D8doM1Y6.js.gz +0 -0
  91. package/build/client/_app/immutable/chunks/{BHHfrjbV.js → D9BWOD7V.js} +1 -1
  92. package/build/client/_app/immutable/chunks/D9BWOD7V.js.br +3 -0
  93. package/build/client/_app/immutable/chunks/D9BWOD7V.js.gz +0 -0
  94. package/build/client/_app/immutable/chunks/{Cp_st-64.js → DBB88ZB7.js} +1 -1
  95. package/build/client/_app/immutable/chunks/DBB88ZB7.js.br +2 -0
  96. package/build/client/_app/immutable/chunks/DBB88ZB7.js.gz +0 -0
  97. package/build/client/_app/immutable/chunks/{Dm49pcMm.js → DC7lPrn4.js} +1 -1
  98. package/build/client/_app/immutable/chunks/DC7lPrn4.js.br +0 -0
  99. package/build/client/_app/immutable/chunks/DC7lPrn4.js.gz +0 -0
  100. package/build/client/_app/immutable/chunks/DCwWNTpf.js +9 -0
  101. package/build/client/_app/immutable/chunks/DCwWNTpf.js.br +0 -0
  102. package/build/client/_app/immutable/chunks/DCwWNTpf.js.gz +0 -0
  103. package/build/client/_app/immutable/chunks/{wcTQUnZO.js → DEnUeQNt.js} +1 -1
  104. package/build/client/_app/immutable/chunks/DEnUeQNt.js.br +0 -0
  105. package/build/client/_app/immutable/chunks/DEnUeQNt.js.gz +0 -0
  106. package/build/client/_app/immutable/chunks/D_laxq3h.js +1 -0
  107. package/build/client/_app/immutable/chunks/D_laxq3h.js.br +0 -0
  108. package/build/client/_app/immutable/chunks/D_laxq3h.js.gz +0 -0
  109. package/build/client/_app/immutable/chunks/{Ddv5LgEc.js → DfkYlKBk.js} +1 -1
  110. package/build/client/_app/immutable/chunks/DfkYlKBk.js.br +0 -0
  111. package/build/client/_app/immutable/chunks/DfkYlKBk.js.gz +0 -0
  112. package/build/client/_app/immutable/chunks/DnMS2X6M.js +2 -0
  113. package/build/client/_app/immutable/chunks/DnMS2X6M.js.br +0 -0
  114. package/build/client/_app/immutable/chunks/DnMS2X6M.js.gz +0 -0
  115. package/build/client/_app/immutable/chunks/{B1HdnQRQ.js → DrE1ro9S.js} +1 -1
  116. package/build/client/_app/immutable/chunks/DrE1ro9S.js.br +0 -0
  117. package/build/client/_app/immutable/chunks/DrE1ro9S.js.gz +0 -0
  118. package/build/client/_app/immutable/chunks/DzY_RPb9.js +1 -0
  119. package/build/client/_app/immutable/chunks/DzY_RPb9.js.br +0 -0
  120. package/build/client/_app/immutable/chunks/DzY_RPb9.js.gz +0 -0
  121. package/build/client/_app/immutable/chunks/PrCSpCPg.js +1 -0
  122. package/build/client/_app/immutable/chunks/PrCSpCPg.js.br +0 -0
  123. package/build/client/_app/immutable/chunks/PrCSpCPg.js.gz +0 -0
  124. package/build/client/_app/immutable/chunks/{CN555stc.js → eMofpOrR.js} +1 -1
  125. package/build/client/_app/immutable/chunks/eMofpOrR.js.br +0 -0
  126. package/build/client/_app/immutable/chunks/eMofpOrR.js.gz +0 -0
  127. package/build/client/_app/immutable/entry/app.BQUuHkSR.js +2 -0
  128. package/build/client/_app/immutable/entry/app.BQUuHkSR.js.br +0 -0
  129. package/build/client/_app/immutable/entry/app.BQUuHkSR.js.gz +0 -0
  130. package/build/client/_app/immutable/entry/start.DoeTycdu.js +1 -0
  131. package/build/client/_app/immutable/entry/start.DoeTycdu.js.br +2 -0
  132. package/build/client/_app/immutable/entry/start.DoeTycdu.js.gz +0 -0
  133. package/build/client/_app/immutable/nodes/0.DBnFpwRM.js +4 -0
  134. package/build/client/_app/immutable/nodes/0.DBnFpwRM.js.br +0 -0
  135. package/build/client/_app/immutable/nodes/0.DBnFpwRM.js.gz +0 -0
  136. package/build/client/_app/immutable/nodes/1.D-kI-fLd.js +1 -0
  137. package/build/client/_app/immutable/nodes/1.D-kI-fLd.js.br +0 -0
  138. package/build/client/_app/immutable/nodes/1.D-kI-fLd.js.gz +0 -0
  139. package/build/client/_app/immutable/nodes/10.DWb5H7vX.js +28 -0
  140. package/build/client/_app/immutable/nodes/10.DWb5H7vX.js.br +0 -0
  141. package/build/client/_app/immutable/nodes/10.DWb5H7vX.js.gz +0 -0
  142. package/build/client/_app/immutable/nodes/{15.D2I0y3ys.js → 15.CGc3_07c.js} +1 -1
  143. package/build/client/_app/immutable/nodes/15.CGc3_07c.js.br +3 -0
  144. package/build/client/_app/immutable/nodes/15.CGc3_07c.js.gz +0 -0
  145. package/build/client/_app/immutable/nodes/17.BIba62hW.js +3 -0
  146. package/build/client/_app/immutable/nodes/17.BIba62hW.js.br +0 -0
  147. package/build/client/_app/immutable/nodes/17.BIba62hW.js.gz +0 -0
  148. package/build/client/_app/immutable/nodes/18.Clxr6FwI.js +11 -0
  149. package/build/client/_app/immutable/nodes/18.Clxr6FwI.js.br +0 -0
  150. package/build/client/_app/immutable/nodes/18.Clxr6FwI.js.gz +0 -0
  151. package/build/client/_app/immutable/nodes/2.cbpnR8be.js +35 -0
  152. package/build/client/_app/immutable/nodes/2.cbpnR8be.js.br +0 -0
  153. package/build/client/_app/immutable/nodes/2.cbpnR8be.js.gz +0 -0
  154. package/build/client/_app/immutable/nodes/3.DsP759xk.js +1 -0
  155. package/build/client/_app/immutable/nodes/3.DsP759xk.js.br +0 -0
  156. package/build/client/_app/immutable/nodes/3.DsP759xk.js.gz +0 -0
  157. package/build/client/_app/immutable/nodes/{4.C8VxVbVn.js → 4.BIGLAIDe.js} +1 -1
  158. package/build/client/_app/immutable/nodes/4.BIGLAIDe.js.br +0 -0
  159. package/build/client/_app/immutable/nodes/4.BIGLAIDe.js.gz +0 -0
  160. package/build/client/_app/immutable/nodes/{5.BjrnKYaA.js → 5.zMHOyhDv.js} +1 -1
  161. package/build/client/_app/immutable/nodes/5.zMHOyhDv.js.br +0 -0
  162. package/build/client/_app/immutable/nodes/5.zMHOyhDv.js.gz +0 -0
  163. package/build/client/_app/immutable/nodes/6.DFQ1IZsQ.js +1 -0
  164. package/build/client/_app/immutable/nodes/6.DFQ1IZsQ.js.br +0 -0
  165. package/build/client/_app/immutable/nodes/6.DFQ1IZsQ.js.gz +0 -0
  166. package/build/client/_app/immutable/nodes/8.CTgEdr7L.js +2 -0
  167. package/build/client/_app/immutable/nodes/8.CTgEdr7L.js.br +0 -0
  168. package/build/client/_app/immutable/nodes/8.CTgEdr7L.js.gz +0 -0
  169. package/build/client/_app/immutable/nodes/9.BidF5Uvq.js +2 -0
  170. package/build/client/_app/immutable/nodes/9.BidF5Uvq.js.br +0 -0
  171. package/build/client/_app/immutable/nodes/9.BidF5Uvq.js.gz +0 -0
  172. package/build/client/_app/version.json +1 -1
  173. package/build/client/_app/version.json.br +0 -0
  174. package/build/client/_app/version.json.gz +0 -0
  175. package/build/server/chunks/0-BZOFUIfF.js +9 -0
  176. package/build/server/chunks/0-BZOFUIfF.js.map +1 -0
  177. package/build/server/chunks/1-XwGU5VVN.js +9 -0
  178. package/build/server/chunks/{1-C0HdTvXW.js.map → 1-XwGU5VVN.js.map} +1 -1
  179. package/build/server/chunks/10-BgFSx4ib.js +9 -0
  180. package/build/server/chunks/10-BgFSx4ib.js.map +1 -0
  181. package/build/server/chunks/15-BjTTC1jf.js +9 -0
  182. package/build/server/chunks/{15-BQcb9C_y.js.map → 15-BjTTC1jf.js.map} +1 -1
  183. package/build/server/chunks/17-BEkWCfzc.js +9 -0
  184. package/build/server/chunks/17-BEkWCfzc.js.map +1 -0
  185. package/build/server/chunks/18-C-S0wKdp.js +9 -0
  186. package/build/server/chunks/18-C-S0wKdp.js.map +1 -0
  187. package/build/server/chunks/2-o-cIkIjs.js +9 -0
  188. package/build/server/chunks/2-o-cIkIjs.js.map +1 -0
  189. package/build/server/chunks/3-B-ABlyFO.js +9 -0
  190. package/build/server/chunks/3-B-ABlyFO.js.map +1 -0
  191. package/build/server/chunks/4-joAFA_Y8.js +9 -0
  192. package/build/server/chunks/4-joAFA_Y8.js.map +1 -0
  193. package/build/server/chunks/5-DIhC9k4l.js +9 -0
  194. package/build/server/chunks/5-DIhC9k4l.js.map +1 -0
  195. package/build/server/chunks/6-CMuAQIcW.js +9 -0
  196. package/build/server/chunks/6-CMuAQIcW.js.map +1 -0
  197. package/build/server/chunks/8-CbETTVRG.js +9 -0
  198. package/build/server/chunks/8-CbETTVRG.js.map +1 -0
  199. package/build/server/chunks/9-nMV90uVU.js +9 -0
  200. package/build/server/chunks/9-nMV90uVU.js.map +1 -0
  201. package/build/server/chunks/{AgentSidebar-BWBnqHnV.js → AgentSidebar-BEbSdZdN.js} +4 -4
  202. package/build/server/chunks/{AgentSidebar-BWBnqHnV.js.map → AgentSidebar-BEbSdZdN.js.map} +1 -1
  203. package/build/server/chunks/{Button-DH7gdU0s.js → Button-Dc9CR4Wh.js} +2 -2
  204. package/build/server/chunks/{Button-DH7gdU0s.js.map → Button-Dc9CR4Wh.js.map} +1 -1
  205. package/build/server/chunks/{ChatStepTrace-BivoNYOY.js → ChatStepTrace-OM96X4g8.js} +18 -7
  206. package/build/server/chunks/ChatStepTrace-OM96X4g8.js.map +1 -0
  207. package/build/server/chunks/{Dropdown-DnARl86Q.js → Dropdown-Cgd7pG-k.js} +2 -2
  208. package/build/server/chunks/{Dropdown-DnARl86Q.js.map → Dropdown-Cgd7pG-k.js.map} +1 -1
  209. package/build/server/chunks/GitControlsButton-BLcNzrDt.js +81 -0
  210. package/build/server/chunks/GitControlsButton-BLcNzrDt.js.map +1 -0
  211. package/build/server/chunks/{Icon-DP1YKCRV.js → Icon-Bogvl2n9.js} +2 -2
  212. package/build/server/chunks/{Icon-DP1YKCRV.js.map → Icon-Bogvl2n9.js.map} +1 -1
  213. package/build/server/chunks/{Input-CUJ9Cg7b.js → Input-7hpw1WLW.js} +2 -2
  214. package/build/server/chunks/{Input-CUJ9Cg7b.js.map → Input-7hpw1WLW.js.map} +1 -1
  215. package/build/server/chunks/{Modal-CGJuNpZ0.js → Modal-7IIIfFEG.js} +5 -5
  216. package/build/server/chunks/{Modal-CGJuNpZ0.js.map → Modal-7IIIfFEG.js.map} +1 -1
  217. package/build/server/chunks/{Panel-zvjxe036.js → Panel-Cj1mXx9-.js} +2 -2
  218. package/build/server/chunks/{Panel-zvjxe036.js.map → Panel-Cj1mXx9-.js.map} +1 -1
  219. package/build/server/chunks/{Tab-CUkyLqbN.js → Tab-bf4ZDs5y.js} +4 -4
  220. package/build/server/chunks/{Tab-CUkyLqbN.js.map → Tab-bf4ZDs5y.js.map} +1 -1
  221. package/build/server/chunks/{_layout.svelte-BnrWYuLv.js → _layout.svelte-C71luIwv.js} +10 -10
  222. package/build/server/chunks/{_layout.svelte-BnrWYuLv.js.map → _layout.svelte-C71luIwv.js.map} +1 -1
  223. package/build/server/chunks/{_layout.svelte-wi6o5Ecu.js → _layout.svelte-CFhHgXI_.js} +24 -18
  224. package/build/server/chunks/_layout.svelte-CFhHgXI_.js.map +1 -0
  225. package/build/server/chunks/_layout.svelte-CJd_pmkx.js +431 -0
  226. package/build/server/chunks/_layout.svelte-CJd_pmkx.js.map +1 -0
  227. package/build/server/chunks/{_layout.svelte-B88WMyk0.js → _layout.svelte-D6rhwm98.js} +445 -70
  228. package/build/server/chunks/_layout.svelte-D6rhwm98.js.map +1 -0
  229. package/build/server/chunks/{_page.svelte-CeS_21Ho.js → _page.svelte-BBvDMiTV.js} +25 -21
  230. package/build/server/chunks/_page.svelte-BBvDMiTV.js.map +1 -0
  231. package/build/server/chunks/{_page.svelte-h_J4lNT9.js → _page.svelte-BQs9dEuq.js} +8 -7
  232. package/build/server/chunks/{_page.svelte-h_J4lNT9.js.map → _page.svelte-BQs9dEuq.js.map} +1 -1
  233. package/build/server/chunks/{_page.svelte-DhFNFMnl.js → _page.svelte-BoO2LWVX.js} +34 -14
  234. package/build/server/chunks/_page.svelte-BoO2LWVX.js.map +1 -0
  235. package/build/server/chunks/{_page.svelte-CHgQjBQj.js → _page.svelte-DUCTSdv-.js} +2 -2
  236. package/build/server/chunks/{_page.svelte-CHgQjBQj.js.map → _page.svelte-DUCTSdv-.js.map} +1 -1
  237. package/build/server/chunks/_page.svelte-FXYLKyMw.js +110 -0
  238. package/build/server/chunks/_page.svelte-FXYLKyMw.js.map +1 -0
  239. package/build/server/chunks/{_page.svelte-57pyhszV.js → _page.svelte-KA1hqKj2.js} +20 -107
  240. package/build/server/chunks/_page.svelte-KA1hqKj2.js.map +1 -0
  241. package/build/server/chunks/{_page.svelte-BSVJ2d2G.js → _page.svelte-y8CZFL8a.js} +210 -106
  242. package/build/server/chunks/_page.svelte-y8CZFL8a.js.map +1 -0
  243. package/build/server/chunks/{_page.svelte-DHSYVLoj.js → _page.svelte-yIHSIEW6.js} +21 -15
  244. package/build/server/chunks/_page.svelte-yIHSIEW6.js.map +1 -0
  245. package/build/server/chunks/_server.ts-Cp9DgLcE.js +336 -0
  246. package/build/server/chunks/_server.ts-Cp9DgLcE.js.map +1 -0
  247. package/build/server/chunks/{agents-context-CbFsZmi5.js → agents-context-owgusUPR.js} +2 -2
  248. package/build/server/chunks/{agents-context-CbFsZmi5.js.map → agents-context-owgusUPR.js.map} +1 -1
  249. package/build/server/chunks/{client-DO-hqMbT.js → client-P-7bDULt.js} +4 -4
  250. package/build/server/chunks/{client-DO-hqMbT.js.map → client-P-7bDULt.js.map} +1 -1
  251. package/build/server/chunks/{conversation-view-memory-CtbUZd_L.js → conversation-view-memory-SdpdqTR7.js} +2 -2
  252. package/build/server/chunks/{conversation-view-memory-CtbUZd_L.js.map → conversation-view-memory-SdpdqTR7.js.map} +1 -1
  253. package/build/server/chunks/{edit-workspace-context-tyHBPujC.js → edit-workspace-context-hanFnXR3.js} +2 -2
  254. package/build/server/chunks/{edit-workspace-context-tyHBPujC.js.map → edit-workspace-context-hanFnXR3.js.map} +1 -1
  255. package/build/server/chunks/error.svelte-yI9RS6H4.js +15 -0
  256. package/build/server/chunks/{error.svelte-DmKKN1RU.js.map → error.svelte-yI9RS6H4.js.map} +1 -1
  257. package/build/server/chunks/git-mode-context-BpNsAUGF.js +18 -0
  258. package/build/server/chunks/git-mode-context-BpNsAUGF.js.map +1 -0
  259. package/build/server/chunks/{index-LMsd1ih2.js → index-DGtbUu8Y.js} +2 -2
  260. package/build/server/chunks/{index-LMsd1ih2.js.map → index-DGtbUu8Y.js.map} +1 -1
  261. package/build/server/chunks/{index-server-BRr5mZEq.js → index-server-l8-WsVn4.js} +2 -2
  262. package/build/server/chunks/{index-server-BRr5mZEq.js.map → index-server-l8-WsVn4.js.map} +1 -1
  263. package/build/server/chunks/{index2-ClgfzZ89.js → index2-CtgLiJVO.js} +3 -3
  264. package/build/server/chunks/{index2-ClgfzZ89.js.map → index2-CtgLiJVO.js.map} +1 -1
  265. package/build/server/chunks/{index3-BdRUAffj.js → index3-4hbbCqW0.js} +2 -2
  266. package/build/server/chunks/{index3-BdRUAffj.js.map → index3-4hbbCqW0.js.map} +1 -1
  267. package/build/server/chunks/{root-4q2Pr7ck.js → root-sWPnlpi3.js} +2 -2
  268. package/build/server/chunks/{root-4q2Pr7ck.js.map → root-sWPnlpi3.js.map} +1 -1
  269. package/build/server/chunks/{source-selection-CcN1cgXc.js → source-selection-DSkaPGfZ.js} +7 -2
  270. package/build/server/chunks/source-selection-DSkaPGfZ.js.map +1 -0
  271. package/build/server/chunks/{state.svelte-Bd1i-u49.js → state.svelte-BkvaElc6.js} +3 -3
  272. package/build/server/chunks/{state.svelte-Bd1i-u49.js.map → state.svelte-BkvaElc6.js.map} +1 -1
  273. package/build/server/chunks/trpc-client-Cr8RJ4UO.js +260 -0
  274. package/build/server/chunks/trpc-client-Cr8RJ4UO.js.map +1 -0
  275. package/build/server/index.js +4 -4
  276. package/build/server/index.js.map +1 -1
  277. package/build/server/manifest.js +15 -15
  278. package/build/server/manifest.js.map +1 -1
  279. package/package.json +1 -1
  280. package/src/backend/git-mode/command.spec.ts +172 -0
  281. package/src/backend/git-mode/command.ts +405 -0
  282. package/src/backend/git-mode/config.spec.ts +45 -0
  283. package/src/backend/git-mode/config.ts +90 -0
  284. package/src/backend/git-mode/index.ts +20 -0
  285. package/src/backend/git-mode/repository-write-gate.spec.ts +116 -0
  286. package/src/backend/git-mode/repository-write-gate.ts +260 -0
  287. package/src/backend/git-mode/router.ts +59 -0
  288. package/src/backend/git-mode/service.spec.ts +1653 -0
  289. package/src/backend/git-mode/service.ts +2183 -0
  290. package/src/backend/git-mode/types.ts +82 -0
  291. package/src/backend/git-mode/write-tracker.spec.ts +46 -0
  292. package/src/backend/git-mode/write-tracker.ts +39 -0
  293. package/src/backend/lib/backend-restart.spec.ts +27 -0
  294. package/src/backend/lib/backend-restart.ts +16 -2
  295. package/src/backend/lib/middleware/cors.spec.ts +67 -0
  296. package/src/backend/lib/middleware/cors.ts +40 -12
  297. package/src/backend/roleplay/agent-loader.ts +49 -0
  298. package/src/backend/roleplay/old-server.ts +106 -56
  299. package/src/backend/roleplay/prompt-edit-proposals.ts +38 -4
  300. package/src/backend/roleplay/prompt-file.ts +59 -0
  301. package/src/backend/roleplay/router.spec.ts +75 -0
  302. package/src/backend/roleplay/router.ts +123 -69
  303. package/src/backend/roleplay/suggest-file-edit.ts +160 -0
  304. package/src/backend/roleplay/suggest-prompt-edit.ts +9 -138
  305. package/src/backend/roleplay/suggest-test-fix.spec.ts +50 -0
  306. package/src/backend/roleplay/suggest-test-fix.ts +65 -0
  307. package/src/backend/roleplay/test-fix-proposal-acceptance.spec.ts +253 -0
  308. package/src/backend/server.ts +116 -13
  309. package/src/backend/tests/academy.ts +17 -3
  310. package/src/backend/tests/data.spec.ts +81 -2
  311. package/src/backend/tests/data.ts +74 -4
  312. package/src/backend/tests/router.ts +101 -36
  313. package/src/backend/tests/suggest-test-history-edit.spec.ts +20 -0
  314. package/src/backend/tests/suggest-test-history-edit.ts +52 -0
  315. package/src/backend/tests/test-edit-source.spec.ts +61 -0
  316. package/src/backend/tests/test-edit-source.ts +34 -0
  317. package/src/backend/tests/test-history-edit-proposals.ts +69 -0
  318. package/src/backend/tests/test-history-overrides.spec.ts +24 -0
  319. package/src/backend/tests/test-selection.ts +27 -0
  320. package/src/lib/api-telescope/source-selection.spec.ts +44 -0
  321. package/src/lib/api-telescope/source-selection.ts +28 -0
  322. package/src/lib/components/Modal.svelte +1 -1
  323. package/src/lib/edit/edit-workspace-context.ts +33 -3
  324. package/src/lib/edit/test-ai-edit.spec.ts +31 -0
  325. package/src/lib/edit/test-ai-edit.ts +52 -0
  326. package/src/lib/git-mode/BlockingGitDialog.svelte +118 -0
  327. package/src/lib/git-mode/GitControlsButton.svelte +96 -0
  328. package/src/lib/git-mode/client-admission.spec.ts +304 -0
  329. package/src/lib/git-mode/client-admission.ts +343 -0
  330. package/src/lib/git-mode/errors.ts +2 -0
  331. package/src/lib/git-mode/git-mode-context.ts +70 -0
  332. package/src/lib/git-mode/refresh-policy.spec.ts +95 -0
  333. package/src/lib/git-mode/refresh-policy.ts +39 -0
  334. package/src/lib/git-mode/status-recovery.spec.ts +86 -0
  335. package/src/lib/git-mode/status-recovery.ts +33 -0
  336. package/src/lib/monaco/bosun-theme.ts +6 -83
  337. package/src/lib/monaco/editor-appearance.spec.ts +84 -0
  338. package/src/lib/monaco/editor-appearance.ts +154 -0
  339. package/src/lib/monaco/editor-decorations.spec.ts +91 -0
  340. package/src/lib/monaco/editor-decorations.ts +133 -0
  341. package/src/lib/tests/assertion-types.ts +74 -0
  342. package/src/lib/trpc-client.ts +15 -1
  343. package/src/lib/ws-client.spec.ts +208 -0
  344. package/src/lib/ws-client.ts +196 -14
  345. package/src/lib/ws-message.ts +24 -0
  346. package/build/client/_app/immutable/assets/0.Rrc0O--C.css +0 -1
  347. package/build/client/_app/immutable/assets/0.Rrc0O--C.css.br +0 -0
  348. package/build/client/_app/immutable/assets/0.Rrc0O--C.css.gz +0 -0
  349. package/build/client/_app/immutable/assets/2.DtxQDOXx.css.br +0 -0
  350. package/build/client/_app/immutable/assets/2.DtxQDOXx.css.gz +0 -0
  351. package/build/client/_app/immutable/chunks/B1HdnQRQ.js.br +0 -0
  352. package/build/client/_app/immutable/chunks/B1HdnQRQ.js.gz +0 -0
  353. package/build/client/_app/immutable/chunks/B5zf3x62.js.br +0 -0
  354. package/build/client/_app/immutable/chunks/B5zf3x62.js.gz +0 -0
  355. package/build/client/_app/immutable/chunks/BHHfrjbV.js.br +0 -2
  356. package/build/client/_app/immutable/chunks/BHHfrjbV.js.gz +0 -0
  357. package/build/client/_app/immutable/chunks/BU7aeYn4.js +0 -1
  358. package/build/client/_app/immutable/chunks/BU7aeYn4.js.br +0 -0
  359. package/build/client/_app/immutable/chunks/BU7aeYn4.js.gz +0 -0
  360. package/build/client/_app/immutable/chunks/BbGYcfPY.js +0 -3
  361. package/build/client/_app/immutable/chunks/BbGYcfPY.js.br +0 -0
  362. package/build/client/_app/immutable/chunks/BbGYcfPY.js.gz +0 -0
  363. package/build/client/_app/immutable/chunks/Bmd5zhWC.js.br +0 -0
  364. package/build/client/_app/immutable/chunks/Bmd5zhWC.js.gz +0 -0
  365. package/build/client/_app/immutable/chunks/BnqH7p3U.js +0 -33
  366. package/build/client/_app/immutable/chunks/BnqH7p3U.js.br +0 -0
  367. package/build/client/_app/immutable/chunks/BnqH7p3U.js.gz +0 -0
  368. package/build/client/_app/immutable/chunks/Bog028VR.js.br +0 -0
  369. package/build/client/_app/immutable/chunks/Bog028VR.js.gz +0 -0
  370. package/build/client/_app/immutable/chunks/Bv1mNXs0.js.br +0 -0
  371. package/build/client/_app/immutable/chunks/Bv1mNXs0.js.gz +0 -0
  372. package/build/client/_app/immutable/chunks/BvjXTrOz.js +0 -1
  373. package/build/client/_app/immutable/chunks/BvjXTrOz.js.br +0 -0
  374. package/build/client/_app/immutable/chunks/BvjXTrOz.js.gz +0 -0
  375. package/build/client/_app/immutable/chunks/C1R-s4aD.js +0 -1
  376. package/build/client/_app/immutable/chunks/C1R-s4aD.js.br +0 -0
  377. package/build/client/_app/immutable/chunks/C1R-s4aD.js.gz +0 -0
  378. package/build/client/_app/immutable/chunks/CC1OcqhR.js +0 -1
  379. package/build/client/_app/immutable/chunks/CC1OcqhR.js.br +0 -0
  380. package/build/client/_app/immutable/chunks/CC1OcqhR.js.gz +0 -0
  381. package/build/client/_app/immutable/chunks/CEHsomMo.js.br +0 -0
  382. package/build/client/_app/immutable/chunks/CJcZ2GVC.js.br +0 -0
  383. package/build/client/_app/immutable/chunks/CJcZ2GVC.js.gz +0 -0
  384. package/build/client/_app/immutable/chunks/CN555stc.js.br +0 -0
  385. package/build/client/_app/immutable/chunks/CN555stc.js.gz +0 -0
  386. package/build/client/_app/immutable/chunks/CQg2Mme0.js +0 -9
  387. package/build/client/_app/immutable/chunks/CQg2Mme0.js.br +0 -0
  388. package/build/client/_app/immutable/chunks/CQg2Mme0.js.gz +0 -0
  389. package/build/client/_app/immutable/chunks/Cp_st-64.js.br +0 -0
  390. package/build/client/_app/immutable/chunks/Cp_st-64.js.gz +0 -0
  391. package/build/client/_app/immutable/chunks/D8mA-uZ4.js.br +0 -0
  392. package/build/client/_app/immutable/chunks/D8mA-uZ4.js.gz +0 -0
  393. package/build/client/_app/immutable/chunks/DCXjBDmY.js.br +0 -0
  394. package/build/client/_app/immutable/chunks/DCXjBDmY.js.gz +0 -0
  395. package/build/client/_app/immutable/chunks/DSLyVE1P.js +0 -1
  396. package/build/client/_app/immutable/chunks/DSLyVE1P.js.br +0 -0
  397. package/build/client/_app/immutable/chunks/DSLyVE1P.js.gz +0 -0
  398. package/build/client/_app/immutable/chunks/Ddv5LgEc.js.br +0 -0
  399. package/build/client/_app/immutable/chunks/Ddv5LgEc.js.gz +0 -0
  400. package/build/client/_app/immutable/chunks/DfcDjAv-.js.br +0 -0
  401. package/build/client/_app/immutable/chunks/DfcDjAv-.js.gz +0 -0
  402. package/build/client/_app/immutable/chunks/Dg0A8wPA.js.br +0 -0
  403. package/build/client/_app/immutable/chunks/Dg0A8wPA.js.gz +0 -0
  404. package/build/client/_app/immutable/chunks/Dm49pcMm.js.br +0 -0
  405. package/build/client/_app/immutable/chunks/Dm49pcMm.js.gz +0 -0
  406. package/build/client/_app/immutable/chunks/DneQQ7D5.js.br +0 -0
  407. package/build/client/_app/immutable/chunks/DneQQ7D5.js.gz +0 -0
  408. package/build/client/_app/immutable/chunks/DoD3q5w5.js.br +0 -0
  409. package/build/client/_app/immutable/chunks/DoD3q5w5.js.gz +0 -0
  410. package/build/client/_app/immutable/chunks/DtXXy94i.js.br +0 -0
  411. package/build/client/_app/immutable/chunks/DtXXy94i.js.gz +0 -0
  412. package/build/client/_app/immutable/chunks/Dy2CFyD6.js +0 -2
  413. package/build/client/_app/immutable/chunks/Dy2CFyD6.js.br +0 -0
  414. package/build/client/_app/immutable/chunks/Dy2CFyD6.js.gz +0 -0
  415. package/build/client/_app/immutable/chunks/DyBwTDJp.js +0 -2
  416. package/build/client/_app/immutable/chunks/DyBwTDJp.js.br +0 -0
  417. package/build/client/_app/immutable/chunks/DyBwTDJp.js.gz +0 -0
  418. package/build/client/_app/immutable/chunks/ILTCveYH.js +0 -1
  419. package/build/client/_app/immutable/chunks/ILTCveYH.js.br +0 -0
  420. package/build/client/_app/immutable/chunks/ILTCveYH.js.gz +0 -0
  421. package/build/client/_app/immutable/chunks/JcG4w2gF.js.br +0 -0
  422. package/build/client/_app/immutable/chunks/JcG4w2gF.js.gz +0 -0
  423. package/build/client/_app/immutable/chunks/UqjCSZmA.js.br +0 -0
  424. package/build/client/_app/immutable/chunks/UqjCSZmA.js.gz +0 -0
  425. package/build/client/_app/immutable/chunks/_YcrHZ6P.js +0 -1
  426. package/build/client/_app/immutable/chunks/_YcrHZ6P.js.br +0 -2
  427. package/build/client/_app/immutable/chunks/_YcrHZ6P.js.gz +0 -0
  428. package/build/client/_app/immutable/chunks/i6ygh6h8.js +0 -1
  429. package/build/client/_app/immutable/chunks/i6ygh6h8.js.br +0 -2
  430. package/build/client/_app/immutable/chunks/i6ygh6h8.js.gz +0 -0
  431. package/build/client/_app/immutable/chunks/oRi68ch3.js +0 -1
  432. package/build/client/_app/immutable/chunks/oRi68ch3.js.br +0 -0
  433. package/build/client/_app/immutable/chunks/oRi68ch3.js.gz +0 -0
  434. package/build/client/_app/immutable/chunks/pPpIn6tB.js.br +0 -0
  435. package/build/client/_app/immutable/chunks/pPpIn6tB.js.gz +0 -0
  436. package/build/client/_app/immutable/chunks/r0sHOWrM.js +0 -1
  437. package/build/client/_app/immutable/chunks/r0sHOWrM.js.br +0 -0
  438. package/build/client/_app/immutable/chunks/r0sHOWrM.js.gz +0 -0
  439. package/build/client/_app/immutable/chunks/wcTQUnZO.js.br +0 -0
  440. package/build/client/_app/immutable/chunks/wcTQUnZO.js.gz +0 -0
  441. package/build/client/_app/immutable/entry/app.DdO0gkPg.js +0 -2
  442. package/build/client/_app/immutable/entry/app.DdO0gkPg.js.br +0 -0
  443. package/build/client/_app/immutable/entry/app.DdO0gkPg.js.gz +0 -0
  444. package/build/client/_app/immutable/entry/start.eAjDq0c9.js +0 -1
  445. package/build/client/_app/immutable/entry/start.eAjDq0c9.js.br +0 -2
  446. package/build/client/_app/immutable/entry/start.eAjDq0c9.js.gz +0 -0
  447. package/build/client/_app/immutable/nodes/0.nG3DdvIX.js +0 -3
  448. package/build/client/_app/immutable/nodes/0.nG3DdvIX.js.br +0 -0
  449. package/build/client/_app/immutable/nodes/0.nG3DdvIX.js.gz +0 -0
  450. package/build/client/_app/immutable/nodes/1.Ceu0XS6v.js +0 -1
  451. package/build/client/_app/immutable/nodes/1.Ceu0XS6v.js.br +0 -0
  452. package/build/client/_app/immutable/nodes/1.Ceu0XS6v.js.gz +0 -0
  453. package/build/client/_app/immutable/nodes/10.dm2dgy31.js +0 -13
  454. package/build/client/_app/immutable/nodes/10.dm2dgy31.js.br +0 -0
  455. package/build/client/_app/immutable/nodes/10.dm2dgy31.js.gz +0 -0
  456. package/build/client/_app/immutable/nodes/15.D2I0y3ys.js.br +0 -0
  457. package/build/client/_app/immutable/nodes/15.D2I0y3ys.js.gz +0 -0
  458. package/build/client/_app/immutable/nodes/17.CKxGp0E7.js +0 -3
  459. package/build/client/_app/immutable/nodes/17.CKxGp0E7.js.br +0 -0
  460. package/build/client/_app/immutable/nodes/17.CKxGp0E7.js.gz +0 -0
  461. package/build/client/_app/immutable/nodes/18.DHJxyQpw.js +0 -11
  462. package/build/client/_app/immutable/nodes/18.DHJxyQpw.js.br +0 -0
  463. package/build/client/_app/immutable/nodes/18.DHJxyQpw.js.gz +0 -0
  464. package/build/client/_app/immutable/nodes/2.DesR2keg.js +0 -35
  465. package/build/client/_app/immutable/nodes/2.DesR2keg.js.br +0 -0
  466. package/build/client/_app/immutable/nodes/2.DesR2keg.js.gz +0 -0
  467. package/build/client/_app/immutable/nodes/3.BUKrXGR_.js +0 -1
  468. package/build/client/_app/immutable/nodes/3.BUKrXGR_.js.br +0 -0
  469. package/build/client/_app/immutable/nodes/3.BUKrXGR_.js.gz +0 -0
  470. package/build/client/_app/immutable/nodes/4.C8VxVbVn.js.br +0 -0
  471. package/build/client/_app/immutable/nodes/4.C8VxVbVn.js.gz +0 -0
  472. package/build/client/_app/immutable/nodes/5.BjrnKYaA.js.br +0 -0
  473. package/build/client/_app/immutable/nodes/5.BjrnKYaA.js.gz +0 -0
  474. package/build/client/_app/immutable/nodes/6.C_hEzPrU.js +0 -1
  475. package/build/client/_app/immutable/nodes/6.C_hEzPrU.js.br +0 -0
  476. package/build/client/_app/immutable/nodes/6.C_hEzPrU.js.gz +0 -0
  477. package/build/client/_app/immutable/nodes/8.BTYaOiDC.js +0 -2
  478. package/build/client/_app/immutable/nodes/8.BTYaOiDC.js.br +0 -0
  479. package/build/client/_app/immutable/nodes/8.BTYaOiDC.js.gz +0 -0
  480. package/build/client/_app/immutable/nodes/9.DVspuDYY.js +0 -2
  481. package/build/client/_app/immutable/nodes/9.DVspuDYY.js.br +0 -0
  482. package/build/client/_app/immutable/nodes/9.DVspuDYY.js.gz +0 -0
  483. package/build/server/chunks/0-D_duQDWy.js +0 -9
  484. package/build/server/chunks/0-D_duQDWy.js.map +0 -1
  485. package/build/server/chunks/1-C0HdTvXW.js +0 -9
  486. package/build/server/chunks/10-DcfhCR4R.js +0 -9
  487. package/build/server/chunks/10-DcfhCR4R.js.map +0 -1
  488. package/build/server/chunks/15-BQcb9C_y.js +0 -9
  489. package/build/server/chunks/17-DuVCTioj.js +0 -9
  490. package/build/server/chunks/17-DuVCTioj.js.map +0 -1
  491. package/build/server/chunks/18-CT0VFW_p.js +0 -9
  492. package/build/server/chunks/18-CT0VFW_p.js.map +0 -1
  493. package/build/server/chunks/2-DgTzKQAP.js +0 -9
  494. package/build/server/chunks/2-DgTzKQAP.js.map +0 -1
  495. package/build/server/chunks/3-eQMSMzXP.js +0 -9
  496. package/build/server/chunks/3-eQMSMzXP.js.map +0 -1
  497. package/build/server/chunks/4-OaAJtDqP.js +0 -9
  498. package/build/server/chunks/4-OaAJtDqP.js.map +0 -1
  499. package/build/server/chunks/5-CBdMutbv.js +0 -9
  500. package/build/server/chunks/5-CBdMutbv.js.map +0 -1
  501. package/build/server/chunks/6-FoEi7ggm.js +0 -9
  502. package/build/server/chunks/6-FoEi7ggm.js.map +0 -1
  503. package/build/server/chunks/8-B44yRkfX.js +0 -9
  504. package/build/server/chunks/8-B44yRkfX.js.map +0 -1
  505. package/build/server/chunks/9-eUjFpHzI.js +0 -9
  506. package/build/server/chunks/9-eUjFpHzI.js.map +0 -1
  507. package/build/server/chunks/ChatStepTrace-BivoNYOY.js.map +0 -1
  508. package/build/server/chunks/_layout.svelte-B-0DHjLB.js +0 -45
  509. package/build/server/chunks/_layout.svelte-B-0DHjLB.js.map +0 -1
  510. package/build/server/chunks/_layout.svelte-B88WMyk0.js.map +0 -1
  511. package/build/server/chunks/_layout.svelte-wi6o5Ecu.js.map +0 -1
  512. package/build/server/chunks/_page.svelte-57pyhszV.js.map +0 -1
  513. package/build/server/chunks/_page.svelte-BSVJ2d2G.js.map +0 -1
  514. package/build/server/chunks/_page.svelte-BoHt2cpr.js +0 -61
  515. package/build/server/chunks/_page.svelte-BoHt2cpr.js.map +0 -1
  516. package/build/server/chunks/_page.svelte-CeS_21Ho.js.map +0 -1
  517. package/build/server/chunks/_page.svelte-DHSYVLoj.js.map +0 -1
  518. package/build/server/chunks/_page.svelte-DhFNFMnl.js.map +0 -1
  519. package/build/server/chunks/_server.ts-D_eo_OAK.js +0 -139
  520. package/build/server/chunks/_server.ts-D_eo_OAK.js.map +0 -1
  521. package/build/server/chunks/error.svelte-DmKKN1RU.js +0 -15
  522. package/build/server/chunks/source-selection-CcN1cgXc.js.map +0 -1
  523. package/build/server/chunks/trpc-client-D8L6vWf4.js +0 -14
  524. package/build/server/chunks/trpc-client-D8L6vWf4.js.map +0 -1
@@ -0,0 +1,343 @@
1
+ import { TRPCClientError, type TRPCLink } from '@trpc/client'
2
+ import type { AnyTRPCRouter } from '@trpc/server'
3
+ import { observable } from '@trpc/server/observable'
4
+
5
+ import { GIT_MODE_USAGE_BLOCKED_MESSAGE } from './errors'
6
+
7
+ export const GIT_FLUSH_OPERATION_CONTEXT_KEY = 'bosunGitFlushOperationId'
8
+
9
+ export type RepositoryClientAdmissionMode = 'unknown' | 'open' | 'quiescing' | 'locked'
10
+
11
+ export interface RepositoryClientAdmissionState {
12
+ mode: RepositoryClientAdmissionMode
13
+ flushOperationId: string | null
14
+ }
15
+
16
+ export interface GitFlushTransportOptions {
17
+ gitFlushOperationId: string
18
+ }
19
+
20
+ type StateListener = (state: RepositoryClientAdmissionState) => void
21
+ type BlockedMutationListener = (path: string) => void
22
+ type ServerBlockedListener = () => void
23
+
24
+ interface StateWaiter {
25
+ predicate: (state: RepositoryClientAdmissionState) => boolean
26
+ resolve: () => void
27
+ reject: (error: Error) => void
28
+ onAbort: (() => void) | null
29
+ }
30
+
31
+ function abortReason(signal: AbortSignal): Error {
32
+ return signal.reason instanceof Error
33
+ ? signal.reason
34
+ : new Error(signal.reason === undefined ? 'Request aborted.' : String(signal.reason))
35
+ }
36
+
37
+ const MUTATION_BLOCKED_MESSAGE =
38
+ 'Bosun is refreshing the project. This change was not applied; wait for the refresh to finish.'
39
+
40
+ export class GitModeMutationBlockedError extends Error {
41
+ readonly path: string
42
+
43
+ constructor(path: string) {
44
+ super(MUTATION_BLOCKED_MESSAGE)
45
+ this.name = 'GitModeMutationBlockedError'
46
+ this.path = path
47
+ }
48
+ }
49
+
50
+ function errorChainIncludes(error: unknown, predicate: (candidate: unknown) => boolean): boolean {
51
+ const seen = new Set<unknown>()
52
+ let candidate = error
53
+ while (candidate && !seen.has(candidate)) {
54
+ if (predicate(candidate)) return true
55
+ seen.add(candidate)
56
+ candidate =
57
+ typeof candidate === 'object' && candidate !== null && 'cause' in candidate
58
+ ? (candidate as { cause?: unknown }).cause
59
+ : null
60
+ }
61
+ return false
62
+ }
63
+
64
+ function isFetchTransportError(error: unknown): boolean {
65
+ return errorChainIncludes(error, (candidate) => {
66
+ if (typeof candidate !== 'object' || candidate === null) return false
67
+ const namedError = candidate as { name?: unknown; message?: unknown }
68
+ if (namedError.name !== 'TypeError' || typeof namedError.message !== 'string') return false
69
+ return /^(failed to fetch|load failed|networkerror when attempting to fetch resource\.?)$/i.test(
70
+ namedError.message.trim()
71
+ )
72
+ })
73
+ }
74
+
75
+ export function isGitModeMutationBlockedError(error: unknown): boolean {
76
+ return errorChainIncludes(
77
+ error,
78
+ (candidate) =>
79
+ candidate instanceof GitModeMutationBlockedError ||
80
+ (typeof candidate === 'object' &&
81
+ candidate !== null &&
82
+ 'name' in candidate &&
83
+ (candidate as { name?: unknown }).name === 'GitModeMutationBlockedError')
84
+ )
85
+ }
86
+
87
+ export function isGitModeUsageBlockedError(error: unknown): boolean {
88
+ return errorChainIncludes(
89
+ error,
90
+ (candidate) =>
91
+ typeof candidate === 'object' &&
92
+ candidate !== null &&
93
+ 'message' in candidate &&
94
+ (candidate as { message?: unknown }).message === GIT_MODE_USAGE_BLOCKED_MESSAGE
95
+ )
96
+ }
97
+
98
+ export function gitFlushRequestOptions(operationId: string) {
99
+ return {
100
+ context: {
101
+ [GIT_FLUSH_OPERATION_CONTEXT_KEY]: operationId
102
+ }
103
+ }
104
+ }
105
+
106
+ export class RepositoryClientAdmission {
107
+ private state: RepositoryClientAdmissionState = {
108
+ mode: 'unknown',
109
+ flushOperationId: null
110
+ }
111
+ private readonly stateListeners = new Set<StateListener>()
112
+ private readonly blockedMutationListeners = new Set<BlockedMutationListener>()
113
+ private readonly serverBlockedListeners = new Set<ServerBlockedListener>()
114
+ private readonly waiters = new Set<StateWaiter>()
115
+ private tainted = false
116
+ private lastBlockedMutationPath: string | null = null
117
+
118
+ getState(): RepositoryClientAdmissionState {
119
+ return this.state
120
+ }
121
+
122
+ isTainted(): boolean {
123
+ return this.tainted
124
+ }
125
+
126
+ isOpen(): boolean {
127
+ return this.state.mode === 'open'
128
+ }
129
+
130
+ isFlushAuthorized(operationId: string | null | undefined): boolean {
131
+ return (
132
+ this.state.mode === 'quiescing' &&
133
+ Boolean(operationId) &&
134
+ operationId === this.state.flushOperationId
135
+ )
136
+ }
137
+
138
+ setState(next: RepositoryClientAdmissionState): void {
139
+ this.state = {
140
+ mode: next.mode,
141
+ flushOperationId: next.mode === 'quiescing' ? next.flushOperationId : null
142
+ }
143
+ for (const listener of this.stateListeners) listener(this.state)
144
+ this.resolveWaiters()
145
+ }
146
+
147
+ forceServerBlocked(): void {
148
+ this.setState({ mode: 'locked', flushOperationId: null })
149
+ for (const listener of this.serverBlockedListeners) listener()
150
+ }
151
+
152
+ blockMutation(path: string): GitModeMutationBlockedError {
153
+ this.tainted = true
154
+ this.lastBlockedMutationPath = path
155
+ for (const listener of this.blockedMutationListeners) listener(path)
156
+ return new GitModeMutationBlockedError(path)
157
+ }
158
+
159
+ onStateChange(listener: StateListener): () => void {
160
+ this.stateListeners.add(listener)
161
+ return () => this.stateListeners.delete(listener)
162
+ }
163
+
164
+ onBlockedMutation(listener: BlockedMutationListener): () => void {
165
+ this.blockedMutationListeners.add(listener)
166
+ if (this.tainted) listener(this.lastBlockedMutationPath ?? 'repository')
167
+ return () => this.blockedMutationListeners.delete(listener)
168
+ }
169
+
170
+ onServerBlocked(listener: ServerBlockedListener): () => void {
171
+ this.serverBlockedListeners.add(listener)
172
+ return () => this.serverBlockedListeners.delete(listener)
173
+ }
174
+
175
+ waitUntilOpen(signal?: AbortSignal | null): Promise<void> {
176
+ return this.waitFor((state) => state.mode === 'open', signal)
177
+ }
178
+
179
+ waitUntilKnown(signal?: AbortSignal | null): Promise<void> {
180
+ return this.waitFor((state) => state.mode !== 'unknown', signal)
181
+ }
182
+
183
+ dispose(): void {
184
+ const error = new Error('Repository client admission was disposed.')
185
+ for (const waiter of this.waiters) {
186
+ waiter.onAbort?.()
187
+ waiter.reject(error)
188
+ }
189
+ this.waiters.clear()
190
+ this.stateListeners.clear()
191
+ this.blockedMutationListeners.clear()
192
+ this.serverBlockedListeners.clear()
193
+ }
194
+
195
+ private waitFor(
196
+ predicate: (state: RepositoryClientAdmissionState) => boolean,
197
+ signal?: AbortSignal | null
198
+ ): Promise<void> {
199
+ if (predicate(this.state)) return Promise.resolve()
200
+ if (signal?.aborted) return Promise.reject(abortReason(signal))
201
+
202
+ return new Promise((resolve, reject) => {
203
+ const waiter: StateWaiter = {
204
+ predicate,
205
+ resolve,
206
+ reject,
207
+ onAbort: null
208
+ }
209
+ if (signal) {
210
+ const onAbort = () => {
211
+ this.waiters.delete(waiter)
212
+ reject(abortReason(signal))
213
+ }
214
+ waiter.onAbort = () => signal.removeEventListener('abort', onAbort)
215
+ signal.addEventListener('abort', onAbort, { once: true })
216
+ }
217
+ this.waiters.add(waiter)
218
+ })
219
+ }
220
+
221
+ private resolveWaiters(): void {
222
+ for (const waiter of [...this.waiters]) {
223
+ if (!waiter.predicate(this.state)) continue
224
+ this.waiters.delete(waiter)
225
+ waiter.onAbort?.()
226
+ waiter.resolve()
227
+ }
228
+ }
229
+ }
230
+
231
+ function isGitControlPath(path: string): boolean {
232
+ return path === 'gitMode' || path.startsWith('gitMode.')
233
+ }
234
+
235
+ function flushOperationId(context: Record<string, unknown>): string | null {
236
+ const value = context[GIT_FLUSH_OPERATION_CONTEXT_KEY]
237
+ return typeof value === 'string' ? value : null
238
+ }
239
+
240
+ export function repositoryAdmissionLink<TRouter extends AnyTRPCRouter>(
241
+ admission: RepositoryClientAdmission
242
+ ): TRPCLink<TRouter> {
243
+ return () =>
244
+ ({ op, next }) =>
245
+ observable((observer) => {
246
+ let cancelled = false
247
+ let downstream: { unsubscribe: () => void } | null = null
248
+ const waitAbort = new AbortController()
249
+ const abortWait = () => waitAbort.abort(op.signal?.reason)
250
+ if (op.signal?.aborted) abortWait()
251
+ else op.signal?.addEventListener('abort', abortWait, { once: true })
252
+
253
+ const reportError = (error: unknown) => {
254
+ if (cancelled) return
255
+ observer.error(
256
+ TRPCClientError.from(error instanceof Error ? error : new Error(String(error)))
257
+ )
258
+ }
259
+
260
+ const waitForOpenAndSubscribe = async () => {
261
+ while (!cancelled) {
262
+ await admission.waitUntilOpen(waitAbort.signal)
263
+ if (cancelled) return
264
+ // Resolving a waiter schedules this continuation in a microtask. Admission may
265
+ // have closed again before it runs, so only dispatch from a still-open state.
266
+ if (!admission.isOpen()) continue
267
+ subscribeDownstream()
268
+ return
269
+ }
270
+ }
271
+
272
+ const subscribeDownstream = () => {
273
+ if (cancelled) return
274
+ downstream = next(op).subscribe({
275
+ next: (value) => observer.next(value),
276
+ complete: () => observer.complete(),
277
+ error: (error) => {
278
+ if (cancelled) return
279
+ const serverBlocked = isGitModeUsageBlockedError(error)
280
+ if (op.type === 'mutation') {
281
+ if (serverBlocked && !admission.isFlushAuthorized(flushOperationId(op.context))) {
282
+ admission.forceServerBlocked()
283
+ reportError(admission.blockMutation(op.path))
284
+ return
285
+ }
286
+ reportError(error)
287
+ return
288
+ }
289
+
290
+ if (
291
+ op.type === 'query' &&
292
+ (serverBlocked || (!admission.isOpen() && isFetchTransportError(error)))
293
+ ) {
294
+ if (serverBlocked) admission.forceServerBlocked()
295
+ downstream = null
296
+ void waitForOpenAndSubscribe().catch(reportError)
297
+ return
298
+ }
299
+
300
+ reportError(error)
301
+ }
302
+ })
303
+ }
304
+
305
+ const start = async () => {
306
+ if (isGitControlPath(op.path)) {
307
+ subscribeDownstream()
308
+ return
309
+ }
310
+
311
+ if (op.type === 'query' || op.type === 'subscription') {
312
+ await waitForOpenAndSubscribe()
313
+ return
314
+ }
315
+
316
+ if (admission.getState().mode === 'unknown')
317
+ await admission.waitUntilKnown(waitAbort.signal)
318
+ const state = admission.getState()
319
+ if (state.mode === 'open') {
320
+ subscribeDownstream()
321
+ return
322
+ }
323
+
324
+ const operationId = flushOperationId(op.context)
325
+ if (admission.isFlushAuthorized(operationId)) {
326
+ subscribeDownstream()
327
+ return
328
+ }
329
+
330
+ reportError(admission.blockMutation(op.path))
331
+ }
332
+
333
+ void start().catch(reportError)
334
+ return () => {
335
+ cancelled = true
336
+ op.signal?.removeEventListener('abort', abortWait)
337
+ waitAbort.abort()
338
+ downstream?.unsubscribe()
339
+ }
340
+ })
341
+ }
342
+
343
+ export const repositoryClientAdmission = new RepositoryClientAdmission()
@@ -0,0 +1,2 @@
1
+ export const GIT_MODE_USAGE_BLOCKED_MESSAGE =
2
+ 'Bosun is refreshing or blocked by Git mode. Use the open Git dialog to continue.'
@@ -0,0 +1,70 @@
1
+ import { createContext } from 'svelte'
2
+
3
+ export type GitModePhase =
4
+ | 'idle'
5
+ | 'preparing'
6
+ | 'flushing'
7
+ | 'refreshing'
8
+ | 'awaiting-changes'
9
+ | 'processing'
10
+ | 'restarting'
11
+ | 'fatal'
12
+
13
+ export interface GitModeFatal {
14
+ title: string
15
+ message: string
16
+ prUrl?: string | null
17
+ }
18
+
19
+ export interface GitModeStatus {
20
+ enabled: boolean
21
+ phase: GitModePhase
22
+ operationId: string | null
23
+ tabNeedsFlush?: boolean
24
+ hasChanges: boolean
25
+ canPrepareRelease: boolean
26
+ fatal: GitModeFatal | null
27
+ reloadToken: string | null
28
+ deferredReason: string | null
29
+ preparationStage: GitModePreparationStage | null
30
+ }
31
+
32
+ export type GitModeManualAction = 'save' | 'discard' | 'prepare-release'
33
+ export type GitModePreparationStage = 'preflight' | 'browser-writes'
34
+ export interface GitModeFlushContext {
35
+ operationId: string
36
+ }
37
+ export type GitModeFlusher = (context: GitModeFlushContext) => void | Promise<void>
38
+ export type GitModeBlocker = () => string | null
39
+
40
+ export interface GitModeController {
41
+ state: GitModeStatus
42
+ openSaveDialog: () => void
43
+ openDiscardDialog: () => void
44
+ prepareRelease: () => void
45
+ manualAction: () => GitModeManualAction | null
46
+ registerFlusher: (
47
+ name: string,
48
+ flusher: GitModeFlusher,
49
+ options?: { final?: boolean }
50
+ ) => () => void
51
+ registerBlocker: (name: string, blocker: GitModeBlocker) => () => void
52
+ isWritePaused: () => boolean
53
+ isActivationStarting: () => boolean
54
+ requestBlockedOperationNotice: () => void
55
+ }
56
+
57
+ export const [getGitModeContext, setGitModeContext] = createContext<GitModeController>()
58
+
59
+ export const disabledGitModeStatus = (): GitModeStatus => ({
60
+ enabled: false,
61
+ phase: 'idle',
62
+ operationId: null,
63
+ tabNeedsFlush: false,
64
+ hasChanges: false,
65
+ canPrepareRelease: false,
66
+ fatal: null,
67
+ reloadToken: null,
68
+ deferredReason: null,
69
+ preparationStage: null
70
+ })
@@ -0,0 +1,95 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { disabledGitModeStatus, type GitModeStatus } from './git-mode-context'
4
+ import {
5
+ gitClientAdmissionState,
6
+ gitStatusPausesWrites,
7
+ isBackgroundGitRefresh,
8
+ shouldPauseWritesForGitTabResume
9
+ } from './refresh-policy'
10
+
11
+ function status(overrides: Partial<GitModeStatus>): GitModeStatus {
12
+ return { ...disabledGitModeStatus(), enabled: true, ...overrides }
13
+ }
14
+
15
+ describe('isBackgroundGitRefresh', () => {
16
+ it('keeps preflight non-blocking until browser writes are being flushed', () => {
17
+ expect(
18
+ isBackgroundGitRefresh(status({ phase: 'preparing', preparationStage: 'preflight' }))
19
+ ).toBe(false)
20
+ expect(
21
+ isBackgroundGitRefresh(status({ phase: 'preparing', preparationStage: 'browser-writes' }))
22
+ ).toBe(true)
23
+ })
24
+
25
+ it.each(['flushing', 'refreshing', 'processing', 'restarting'] as const)(
26
+ 'treats %s as a background refresh',
27
+ (phase) => {
28
+ expect(isBackgroundGitRefresh(status({ phase }))).toBe(true)
29
+ }
30
+ )
31
+
32
+ it('does not classify action-required states as background refreshes', () => {
33
+ expect(isBackgroundGitRefresh(status({ phase: 'awaiting-changes' }))).toBe(false)
34
+ expect(isBackgroundGitRefresh(status({ phase: 'fatal' }))).toBe(false)
35
+ })
36
+ })
37
+
38
+ describe('gitStatusPausesWrites', () => {
39
+ it('pauses writes for background and action-required states', () => {
40
+ expect(gitStatusPausesWrites(status({ phase: 'refreshing' }))).toBe(true)
41
+ expect(gitStatusPausesWrites(status({ phase: 'awaiting-changes' }))).toBe(true)
42
+ expect(gitStatusPausesWrites(status({ phase: 'fatal' }))).toBe(true)
43
+ })
44
+
45
+ it('leaves idle and preflight writes available', () => {
46
+ expect(gitStatusPausesWrites(status({ phase: 'idle' }))).toBe(false)
47
+ expect(
48
+ gitStatusPausesWrites(status({ phase: 'preparing', preparationStage: 'preflight' }))
49
+ ).toBe(false)
50
+ })
51
+ })
52
+
53
+ describe('shouldPauseWritesForGitTabResume', () => {
54
+ it('does not pause an already-active tab for an ordinary window focus event', () => {
55
+ expect(shouldPauseWritesForGitTabResume(true)).toBe(false)
56
+ })
57
+
58
+ it('keeps a suspended tab paused until its resume status refresh succeeds', () => {
59
+ expect(shouldPauseWritesForGitTabResume(false)).toBe(true)
60
+ })
61
+ })
62
+
63
+ describe('gitClientAdmissionState', () => {
64
+ it('keeps ordinary requests pending until the first authoritative status', () => {
65
+ expect(gitClientAdmissionState(status({ phase: 'idle' }), false, true)).toEqual({
66
+ mode: 'unknown',
67
+ flushOperationId: null
68
+ })
69
+ })
70
+
71
+ it('opens after a disabled or enabled idle status', () => {
72
+ expect(gitClientAdmissionState(disabledGitModeStatus(), true, false).mode).toBe('open')
73
+ expect(gitClientAdmissionState(disabledGitModeStatus(), true, true).mode).toBe('open')
74
+ expect(gitClientAdmissionState(status({ phase: 'idle' }), true, false).mode).toBe('open')
75
+ })
76
+
77
+ it('quiesces browser writes with only the active operation authorized', () => {
78
+ expect(
79
+ gitClientAdmissionState(
80
+ status({
81
+ phase: 'preparing',
82
+ preparationStage: 'browser-writes',
83
+ operationId: 'operation-1'
84
+ }),
85
+ true,
86
+ true
87
+ )
88
+ ).toEqual({ mode: 'quiescing', flushOperationId: 'operation-1' })
89
+ })
90
+
91
+ it('locks requests for backend phases and local suspension', () => {
92
+ expect(gitClientAdmissionState(status({ phase: 'refreshing' }), true, true).mode).toBe('locked')
93
+ expect(gitClientAdmissionState(status({ phase: 'idle' }), true, true).mode).toBe('locked')
94
+ })
95
+ })
@@ -0,0 +1,39 @@
1
+ import type { GitModeStatus } from './git-mode-context'
2
+ import type { RepositoryClientAdmissionState } from './client-admission'
3
+
4
+ export function isBackgroundGitRefresh(status: GitModeStatus): boolean {
5
+ if (!status.enabled) return false
6
+ if (status.phase === 'preparing') return status.preparationStage === 'browser-writes'
7
+ return ['flushing', 'refreshing', 'processing', 'restarting'].includes(status.phase)
8
+ }
9
+
10
+ export function gitStatusPausesWrites(status: GitModeStatus): boolean {
11
+ return (
12
+ isBackgroundGitRefresh(status) ||
13
+ (status.enabled && ['awaiting-changes', 'fatal'].includes(status.phase))
14
+ )
15
+ }
16
+
17
+ export function shouldPauseWritesForGitTabResume(tabWasActive: boolean): boolean {
18
+ return !tabWasActive
19
+ }
20
+
21
+ export function gitClientAdmissionState(
22
+ status: GitModeStatus,
23
+ statusSeen: boolean,
24
+ locallyPaused: boolean
25
+ ): RepositoryClientAdmissionState {
26
+ if (!statusSeen) return { mode: 'unknown', flushOperationId: null }
27
+ if (!status.enabled) return { mode: 'open', flushOperationId: null }
28
+ if (
29
+ status.phase === 'preparing' &&
30
+ status.preparationStage === 'browser-writes' &&
31
+ status.operationId
32
+ ) {
33
+ return { mode: 'quiescing', flushOperationId: status.operationId }
34
+ }
35
+ if (locallyPaused || gitStatusPausesWrites(status)) {
36
+ return { mode: 'locked', flushOperationId: null }
37
+ }
38
+ return { mode: 'open', flushOperationId: null }
39
+ }
@@ -0,0 +1,86 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { recoverRequiredGitStatus } from './status-recovery'
4
+
5
+ function deferred() {
6
+ let resolve!: () => void
7
+ const promise = new Promise<void>((next) => {
8
+ resolve = next
9
+ })
10
+ return { promise, resolve }
11
+ }
12
+
13
+ describe('recoverRequiredGitStatus', () => {
14
+ it('requests another status when invalidated during the recovery request', async () => {
15
+ let requiredSequence: number | null = 1
16
+ let successfulSequence = 0
17
+ let inFlight: Promise<void> | null = null
18
+ let requestCount = 0
19
+ const requests = [deferred(), deferred()]
20
+
21
+ const recovery = recoverRequiredGitStatus({
22
+ getRequiredSequence: () => requiredSequence,
23
+ getSuccessfulSequence: () => successfulSequence,
24
+ getInFlightRequest: () => inFlight,
25
+ requestStatus: () => {
26
+ const sequence = ++requestCount
27
+ const request = requests[sequence - 1]
28
+ inFlight = request.promise.then(() => {
29
+ successfulSequence = sequence
30
+ if (successfulSequence >= (requiredSequence ?? Infinity)) requiredSequence = null
31
+ inFlight = null
32
+ })
33
+ return inFlight
34
+ }
35
+ })
36
+
37
+ await Promise.resolve()
38
+ expect(requestCount).toBe(1)
39
+
40
+ requiredSequence = 2
41
+ requests[0].resolve()
42
+ await requests[0].promise
43
+ await Promise.resolve()
44
+ expect(requestCount).toBe(2)
45
+
46
+ requests[1].resolve()
47
+ await expect(recovery).resolves.toEqual({ status: 'satisfied' })
48
+ expect(successfulSequence).toBe(2)
49
+ expect(requiredSequence).toBeNull()
50
+ })
51
+
52
+ it('stops immediate recovery when a fresh request does not complete successfully', async () => {
53
+ let requestCount = 0
54
+
55
+ await expect(
56
+ recoverRequiredGitStatus({
57
+ getRequiredSequence: () => 1,
58
+ getSuccessfulSequence: () => 0,
59
+ getInFlightRequest: () => null,
60
+ requestStatus: async () => {
61
+ requestCount += 1
62
+ }
63
+ })
64
+ ).resolves.toEqual({ status: 'request-failed', requiredSequence: 1 })
65
+ expect(requestCount).toBe(1)
66
+ })
67
+
68
+ it('reports which requirement failed when a newer invalidation arrives in flight', async () => {
69
+ let requiredSequence = 1
70
+ const request = deferred()
71
+ const recovery = recoverRequiredGitStatus({
72
+ getRequiredSequence: () => requiredSequence,
73
+ getSuccessfulSequence: () => 0,
74
+ getInFlightRequest: () => null,
75
+ requestStatus: () => request.promise
76
+ })
77
+
78
+ requiredSequence = 2
79
+ request.resolve()
80
+
81
+ await expect(recovery).resolves.toEqual({
82
+ status: 'request-failed',
83
+ requiredSequence: 1
84
+ })
85
+ })
86
+ })
@@ -0,0 +1,33 @@
1
+ export interface GitStatusRecoverySource {
2
+ getRequiredSequence: () => number | null
3
+ getSuccessfulSequence: () => number
4
+ getInFlightRequest: () => Promise<void> | null
5
+ requestStatus: () => Promise<void>
6
+ }
7
+
8
+ export type GitStatusRecoveryResult =
9
+ | { status: 'satisfied' }
10
+ | { status: 'request-failed'; requiredSequence: number }
11
+
12
+ export async function recoverRequiredGitStatus(
13
+ source: GitStatusRecoverySource
14
+ ): Promise<GitStatusRecoveryResult> {
15
+ while (true) {
16
+ const required = source.getRequiredSequence()
17
+ if (required === null || source.getSuccessfulSequence() >= required) {
18
+ return { status: 'satisfied' }
19
+ }
20
+
21
+ const inFlight = source.getInFlightRequest()
22
+ if (inFlight) {
23
+ await inFlight
24
+ continue
25
+ }
26
+
27
+ const successBeforeRequest = source.getSuccessfulSequence()
28
+ await source.requestStatus()
29
+ if (source.getSuccessfulSequence() === successBeforeRequest) {
30
+ return { status: 'request-failed', requiredSequence: required }
31
+ }
32
+ }
33
+ }