@dylanpiercey/work 0.2.69 → 0.2.71

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 (497) hide show
  1. package/bin/cli/session.mjs +36 -4
  2. package/bin/cli/topic.mjs +421 -23
  3. package/dist/{_Da7kjbAP.js → _B3z3x0nb.js} +100 -11
  4. package/dist/_BawMVLA9.js +2 -0
  5. package/dist/{_DDCmzS5h.js → _BcuBHot2.js} +113 -113
  6. package/dist/_D3ixWlKr.js +2 -0
  7. package/dist/{_CilTmd3l.js → _DHaRHB4s.js} +237 -36
  8. package/dist/index.mjs +1225 -1098
  9. package/dist/public/assets/{_DIEqAzJB.js → _-JtZtVz8.js} +1 -1
  10. package/dist/public/assets/_-JtZtVz8.js.br +0 -0
  11. package/dist/public/assets/{_DeGJuali.js → _0QJDM3NO.js} +1 -1
  12. package/dist/public/assets/_0QJDM3NO.js.br +0 -0
  13. package/dist/public/assets/{_BiIrl8ml.js → _0vqLbImj.js} +1 -1
  14. package/dist/public/assets/_0vqLbImj.js.br +0 -0
  15. package/dist/public/assets/_2W-pgjXX.js +1 -0
  16. package/dist/public/assets/{_ZlbOPzr7.js → _4ogr0vzb.js} +1 -1
  17. package/dist/public/assets/_4ogr0vzb.js.br +0 -0
  18. package/dist/public/assets/{_wC0cYIUL.js → _5lt7STSU.js} +10 -10
  19. package/dist/public/assets/_5lt7STSU.js.br +0 -0
  20. package/dist/public/assets/{_DPKcpw43.js → _6D14OK7z.js} +1 -1
  21. package/dist/public/assets/_6D14OK7z.js.br +0 -0
  22. package/dist/public/assets/{_BnDvb8rh.js → _9D7sZPkr.js} +1 -1
  23. package/dist/public/assets/_9D7sZPkr.js.br +0 -0
  24. package/dist/public/assets/{_w3JsvUod.js → _Alp3-sd6.js} +1 -1
  25. package/dist/public/assets/_B0CqgYFf.js +1 -0
  26. package/dist/public/assets/{_DLoAVrbv.js → _B0sUN2tx.js} +1 -1
  27. package/dist/public/assets/_B0sUN2tx.js.br +0 -0
  28. package/dist/public/assets/_B1KbLd5h.js +1 -0
  29. package/dist/public/assets/{_D4XHSL1o.js → _B5SjUyop.js} +1 -1
  30. package/dist/public/assets/_B5SjUyop.js.br +0 -0
  31. package/dist/public/assets/_B7FCBIYG.js +1 -0
  32. package/dist/public/assets/_B7FCBIYG.js.br +0 -0
  33. package/dist/public/assets/_B9G7-El7.js +1 -0
  34. package/dist/public/assets/_BDNW7Ugd.js +1 -0
  35. package/dist/public/assets/{_G0Ur49hc.js → _BGXJVx0k.js} +1 -1
  36. package/dist/public/assets/_BGXJVx0k.js.br +0 -0
  37. package/dist/public/assets/{_HnJD2Vzo.js → _BHypHLzv.js} +1 -1
  38. package/dist/public/assets/_BHypHLzv.js.br +0 -0
  39. package/dist/public/assets/{_YTVYw9XV.js → _BJ0RWeiG.js} +1 -1
  40. package/dist/public/assets/_BJ0RWeiG.js.br +0 -0
  41. package/dist/public/assets/{_D-pAxlQ-.js → _BLALkhiZ.js} +4 -4
  42. package/dist/public/assets/_BLALkhiZ.js.br +0 -0
  43. package/dist/public/assets/_BMNhhqEV.js +1 -0
  44. package/dist/public/assets/{_C3k75NG8.js → _BPHBcrYh.js} +1 -1
  45. package/dist/public/assets/_BPHBcrYh.js.br +0 -0
  46. package/dist/public/assets/{_KtT9ovgB.js → _BPoePslg.js} +1 -1
  47. package/dist/public/assets/_BPoePslg.js.br +0 -0
  48. package/dist/public/assets/{_B5QrsHwd.js → _BQuf46P2.js} +1 -1
  49. package/dist/public/assets/_BQuf46P2.js.br +0 -0
  50. package/dist/public/assets/_BTydwZJh.js +1 -0
  51. package/dist/public/assets/{_CLpJpkGL.js → _BUbGYrKa.js} +1 -1
  52. package/dist/public/assets/_BUbGYrKa.js.br +0 -0
  53. package/dist/public/assets/{_Dh_fGh7B.js → _BUh4HTF3.js} +1 -1
  54. package/dist/public/assets/_BUh4HTF3.js.br +0 -0
  55. package/dist/public/assets/{_DE5SUDS8.js → _BVXZCAXs.js} +1 -1
  56. package/dist/public/assets/_BVXZCAXs.js.br +0 -0
  57. package/dist/public/assets/_BWBW2sE5.js +1 -0
  58. package/dist/public/assets/_BXgfsaug.js +1 -0
  59. package/dist/public/assets/_BXgfsaug.js.br +0 -0
  60. package/dist/public/assets/_BZycN9ye.js +1 -0
  61. package/dist/public/assets/_BaQeAF-B.js +1 -0
  62. package/dist/public/assets/_BhA6H8WQ.js +1 -0
  63. package/dist/public/assets/_BikFQJva.js +1 -0
  64. package/dist/public/assets/_Bk0YJ7b1.js +1 -0
  65. package/dist/public/assets/{_DcCeapFB.js → _BlSH3TRK.js} +1 -1
  66. package/dist/public/assets/_BlSH3TRK.js.br +0 -0
  67. package/dist/public/assets/_BqSnw21E.js +1 -0
  68. package/dist/public/assets/{_DdWxi_D9.js → _BtWMgvvl.js} +2 -2
  69. package/dist/public/assets/_BtWMgvvl.js.br +0 -0
  70. package/dist/public/assets/{_5pKDjgHs.js → _BvskbvTW.js} +1 -1
  71. package/dist/public/assets/_BvskbvTW.js.br +0 -0
  72. package/dist/public/assets/{_rizgJsHK.js → _Bx8oVkmQ.js} +1 -1
  73. package/dist/public/assets/_Bx8oVkmQ.js.br +0 -0
  74. package/dist/public/assets/_BxPoJO_L.js +1 -0
  75. package/dist/public/assets/{_BH9u6x7L.js → _C09HUxcS.js} +1 -1
  76. package/dist/public/assets/_C09HUxcS.js.br +0 -0
  77. package/dist/public/assets/_C14PL76N.js +1 -0
  78. package/dist/public/assets/{_3jDFL-Cg.js → _C15TsQVx.js} +1 -1
  79. package/dist/public/assets/_C15TsQVx.js.br +0 -0
  80. package/dist/public/assets/_C1bNeWUD.js +1 -0
  81. package/dist/public/assets/{_B9OVFXEI.js → _C2IlBo8e.js} +1 -1
  82. package/dist/public/assets/_C2IlBo8e.js.br +0 -0
  83. package/dist/public/assets/{_lCk1CAYf.js → _C3F6fdUB.js} +1 -1
  84. package/dist/public/assets/_C5KZ0ozw.js +1 -0
  85. package/dist/public/assets/_C5KZ0ozw.js.br +0 -0
  86. package/dist/public/assets/_C94IJ4uX.js +1 -0
  87. package/dist/public/assets/_CCRiWfSo.js +1 -0
  88. package/dist/public/assets/{_CUPYyx5O.js → _CCl1txGr.js} +1 -1
  89. package/dist/public/assets/{_TOwFHHoM.js → _CDHWB_us.js} +1 -1
  90. package/dist/public/assets/_CDHWB_us.js.br +0 -0
  91. package/dist/public/assets/_CE-UlWde.js +1 -0
  92. package/dist/public/assets/{_BJcqxD6V.js → _CEgYI4gj.js} +1 -1
  93. package/dist/public/assets/_CEgYI4gj.js.br +0 -0
  94. package/dist/public/assets/_CI9y5SMD.js +1 -0
  95. package/dist/public/assets/_CLrYkY55.js +1 -0
  96. package/dist/public/assets/{_C4Hln-a1.js → _CPTaxuJG.js} +1 -1
  97. package/dist/public/assets/_CPTaxuJG.js.br +0 -0
  98. package/dist/public/assets/_CQKcBCsl.js +1 -0
  99. package/dist/public/assets/{_9PIiwVmz.js → _CQuARfyY.js} +1 -1
  100. package/dist/public/assets/_CQuARfyY.js.br +0 -0
  101. package/dist/public/assets/_CRdqojLF.js +1 -0
  102. package/dist/public/assets/{_B0tb8Vgp.js → _CRew7lgJ.js} +1 -1
  103. package/dist/public/assets/_CRew7lgJ.js.br +0 -0
  104. package/dist/public/assets/_CS11TygF.js +1 -0
  105. package/dist/public/assets/{_kHV7j6Zv.js → _CS9qmTkt.js} +1 -1
  106. package/dist/public/assets/_CS9qmTkt.js.br +0 -0
  107. package/dist/public/assets/_CSSixb56.js +1 -0
  108. package/dist/public/assets/_CSa_w7tA.js +86 -0
  109. package/dist/public/assets/_CSa_w7tA.js.br +0 -0
  110. package/dist/public/assets/_CTbIErzd.js +1 -0
  111. package/dist/public/assets/_CTbIErzd.js.br +0 -0
  112. package/dist/public/assets/_CXf2VxeD.js +1 -0
  113. package/dist/public/assets/{_BciKbAaO.js → _CYHURCb7.js} +1 -1
  114. package/dist/public/assets/_CYHURCb7.js.br +0 -0
  115. package/dist/public/assets/_C_vPuVhA.js +1 -0
  116. package/dist/public/assets/_Cajx7i0I.js +1 -0
  117. package/dist/public/assets/{_B1rg6S37.js → _Cb-D3ERI.js} +1 -1
  118. package/dist/public/assets/_Cb-D3ERI.js.br +0 -0
  119. package/dist/public/assets/_Cc8Hhqep.js +1 -0
  120. package/dist/public/assets/{_CbAa5uAw.js → _Ce6hwXny.js} +1 -1
  121. package/dist/public/assets/_Ce6hwXny.js.br +0 -0
  122. package/dist/public/assets/_CeSD_6xP.js +1 -0
  123. package/dist/public/assets/_CfFIePkk.js +1 -0
  124. package/dist/public/assets/_CfUhSwyu.js +1 -0
  125. package/dist/public/assets/_CfziTCiN.js +1 -0
  126. package/dist/public/assets/_Ci7l0V_h.js +1 -0
  127. package/dist/public/assets/{_ByZbJftZ.js → _Cif8YVIW.js} +1 -1
  128. package/dist/public/assets/_Cif8YVIW.js.br +0 -0
  129. package/dist/public/assets/_CjI_b19m.js +1 -0
  130. package/dist/public/assets/{_DUEm1sqD.js → _CjT2-NNY.js} +1 -1
  131. package/dist/public/assets/_CjT2-NNY.js.br +0 -0
  132. package/dist/public/assets/_Cjromvor.js +1 -0
  133. package/dist/public/assets/{_l9Ig5EJO.js → _CmcVar5g.js} +1 -1
  134. package/dist/public/assets/_CmcVar5g.js.br +0 -0
  135. package/dist/public/assets/_Cof8T6gT.js +1 -0
  136. package/dist/public/assets/{_BICdCzpd.js → _CreV-6z6.js} +1 -1
  137. package/dist/public/assets/_CreV-6z6.js.br +0 -0
  138. package/dist/public/assets/_CsKkccjn.js +1 -0
  139. package/dist/public/assets/{_CXhoovwf.js → _CsnlIPmX.js} +1 -1
  140. package/dist/public/assets/_CsnlIPmX.js.br +0 -0
  141. package/dist/public/assets/_CsxBH5UX.js +1 -0
  142. package/dist/public/assets/{_CtYn_7Ld.js → _CvrDFzmP.js} +1 -1
  143. package/dist/public/assets/_CvrDFzmP.js.br +0 -0
  144. package/dist/public/assets/{_CRAhvbwb.js → _CwAvlnWz.js} +1 -1
  145. package/dist/public/assets/_CwAvlnWz.js.br +0 -0
  146. package/dist/public/assets/{_DJVQZQI-.js → _CwBNy_7k.js} +1 -1
  147. package/dist/public/assets/_CwBNy_7k.js.br +0 -0
  148. package/dist/public/assets/{_BMXY56L9.js → _Cx0sSSLJ.js} +1 -1
  149. package/dist/public/assets/_Cx0sSSLJ.js.br +0 -0
  150. package/dist/public/assets/_CxyaZiJz.js +1 -0
  151. package/dist/public/assets/{_BSyW2RLw.js → _D-4UJozU.js} +1 -1
  152. package/dist/public/assets/_D-4UJozU.js.br +0 -0
  153. package/dist/public/assets/{_Coj9l4W_.js → _D0PrCOmg.js} +1 -1
  154. package/dist/public/assets/_D0PrCOmg.js.br +0 -0
  155. package/dist/public/assets/{_LsFmgSj_.js → _D0n_5okc.js} +1 -1
  156. package/dist/public/assets/_D0n_5okc.js.br +0 -0
  157. package/dist/public/assets/{_aVJfol8S.js → _D1ZTqBtg.js} +1 -1
  158. package/dist/public/assets/_D1ZTqBtg.js.br +0 -0
  159. package/dist/public/assets/_D2m31-DG.js +1 -0
  160. package/dist/public/assets/_D2vTqjKk.js +1 -0
  161. package/dist/public/assets/{_DxgeJa1G.js → _D2zuXOi5.js} +1 -1
  162. package/dist/public/assets/_D2zuXOi5.js.br +0 -0
  163. package/dist/public/assets/{_BoRNFqwj.js → _D3mGPwaD.js} +1 -1
  164. package/dist/public/assets/{_DmBJQY0z.js → _D4SspWzi.js} +1 -1
  165. package/dist/public/assets/_D4SspWzi.js.br +0 -0
  166. package/dist/public/assets/_D8BYyk4L.js +1 -0
  167. package/dist/public/assets/_D8c2vqae.js +1 -0
  168. package/dist/public/assets/{_SkNT3g1t.js → _D93e76eJ.js} +1 -1
  169. package/dist/public/assets/_D93e76eJ.js.br +0 -0
  170. package/dist/public/assets/{_a3BQDAxj.js → _DB0x3S_V.js} +1 -1
  171. package/dist/public/assets/_DB0x3S_V.js.br +0 -0
  172. package/dist/public/assets/{_CiYp9PxT.js → _DBqiCvB3.js} +1 -1
  173. package/dist/public/assets/_DBqiCvB3.js.br +0 -0
  174. package/dist/public/assets/_DDPfcBYW.js +1 -0
  175. package/dist/public/assets/_DE7f6G-4.js +1 -0
  176. package/dist/public/assets/_DFc8nVyA.js +1 -0
  177. package/dist/public/assets/_DGNNG6hE.js +1 -0
  178. package/dist/public/assets/{_BiIQdsrx.js → _DI_3CxxT.js} +1 -1
  179. package/dist/public/assets/_DKaZoJEU.js +1 -0
  180. package/dist/public/assets/_DPCcVPqS.js +1 -0
  181. package/dist/public/assets/{_BUPTpTYH.js → _DPO20UhE.js} +1 -1
  182. package/dist/public/assets/_DPO20UhE.js.br +0 -0
  183. package/dist/public/assets/_DQ9KMZkg.js +1 -0
  184. package/dist/public/assets/_DQfR4nGA.js +1 -0
  185. package/dist/public/assets/_DRl7_NsH.js +1 -0
  186. package/dist/public/assets/_DSjKT54G.js +1 -0
  187. package/dist/public/assets/{_B-cgAjqV.js → _DUQ4-DAq.js} +1 -1
  188. package/dist/public/assets/_DUQ4-DAq.js.br +0 -0
  189. package/dist/public/assets/{_ulL_yezz.js → _DVUACl-0.js} +1 -1
  190. package/dist/public/assets/_DVUACl-0.js.br +0 -0
  191. package/dist/public/assets/_DVaVJl4U.js +1 -0
  192. package/dist/public/assets/{_C1EEKbbh.js → _DWJFJSQt.js} +1 -1
  193. package/dist/public/assets/_DWJFJSQt.js.br +0 -0
  194. package/dist/public/assets/{_zGawNqPU.js → _DW_3eCmy.js} +1 -1
  195. package/dist/public/assets/_DW_3eCmy.js.br +0 -0
  196. package/dist/public/assets/_DWcr4WT2.js +1 -0
  197. package/dist/public/assets/_D_uqbH0s.js +1 -0
  198. package/dist/public/assets/_Db3LFxDp.js +1 -0
  199. package/dist/public/assets/{_D9-mnhpM.js → _DcKVJllO.js} +1 -1
  200. package/dist/public/assets/_DcKVJllO.js.br +0 -0
  201. package/dist/public/assets/_De55CP4F.js +1 -0
  202. package/dist/public/assets/{_CEzgbnFo.js → _DglTnOtH.js} +1 -1
  203. package/dist/public/assets/_DglTnOtH.js.br +0 -0
  204. package/dist/public/assets/_DhyrSLt_.js +1 -0
  205. package/dist/public/assets/_DishjoMc.js +1 -0
  206. package/dist/public/assets/_DlHs_b1x.js +1 -0
  207. package/dist/public/assets/{_C23aBO0p.js → _DmlL12SP.js} +1 -1
  208. package/dist/public/assets/_DmlL12SP.js.br +0 -0
  209. package/dist/public/assets/{_B40fHLkj.js → _Dnj7y5O6.js} +1 -1
  210. package/dist/public/assets/_Dnj7y5O6.js.br +0 -0
  211. package/dist/public/assets/_DqB9AEIR.js +1 -0
  212. package/dist/public/assets/_DqmZjpyA.js +1 -0
  213. package/dist/public/assets/_DrC0PHwd.js +1 -0
  214. package/dist/public/assets/_DrtDlCCB.js +1 -0
  215. package/dist/public/assets/{_Dv298HDL.js → _DsxZHqAt.js} +1 -1
  216. package/dist/public/assets/_DsxZHqAt.js.br +0 -0
  217. package/dist/public/assets/{_B_zlRrUP.js → _DucELdm1.js} +1 -1
  218. package/dist/public/assets/_DucELdm1.js.br +0 -0
  219. package/dist/public/assets/{_CKvOm2QG.js → _Dw2w_cI1.js} +1 -1
  220. package/dist/public/assets/_Dw2w_cI1.js.br +0 -0
  221. package/dist/public/assets/{_C0W4EC0Z.js → _Dx2nYKAs.js} +1 -1
  222. package/dist/public/assets/_Dx2nYKAs.js.br +0 -0
  223. package/dist/public/assets/{_gy0a9Cmp.js → _DxZFU6SY.js} +1 -1
  224. package/dist/public/assets/_DxZFU6SY.js.br +0 -0
  225. package/dist/public/assets/_DyztCqYX.js +1 -0
  226. package/dist/public/assets/_Dz42MOZj.js +1 -0
  227. package/dist/public/assets/{_CsNZdkZU.js → _DzSNrU-9.js} +1 -1
  228. package/dist/public/assets/_DzSNrU-9.js.br +0 -0
  229. package/dist/public/assets/{_BORTVznS.js → _HnLpRxna.js} +2 -2
  230. package/dist/public/assets/_HnLpRxna.js.br +0 -0
  231. package/dist/public/assets/{_0H09AGax.js → _Im1dFxR8.js} +1 -1
  232. package/dist/public/assets/_Im1dFxR8.js.br +0 -0
  233. package/dist/public/assets/_ImlHzwYY.js +1 -0
  234. package/dist/public/assets/_J-P8YHmV.js +1 -0
  235. package/dist/public/assets/_KsdD4dsM.js +1 -0
  236. package/dist/public/assets/_KsdD4dsM.js.br +0 -0
  237. package/dist/public/assets/_LRjlRqrU.js +7 -0
  238. package/dist/public/assets/_LRjlRqrU.js.br +0 -0
  239. package/dist/public/assets/_LTl-SYyD.js +1 -0
  240. package/dist/public/assets/{_Cw9GxBkQ.js → _LniUny_a.js} +1 -1
  241. package/dist/public/assets/_LniUny_a.js.br +0 -0
  242. package/dist/public/assets/_Oup4mCuX.js +1 -0
  243. package/dist/public/assets/{_DuKrnKV2.js → _R3Kvmve2.js} +1 -1
  244. package/dist/public/assets/_R3Kvmve2.js.br +0 -0
  245. package/dist/public/assets/{_Cw3MnPjo.js → _R7YbF1yw.js} +1 -1
  246. package/dist/public/assets/_R7YbF1yw.js.br +0 -0
  247. package/dist/public/assets/{_CDG0zRut.js → _S9Qy4Cmi.js} +1 -1
  248. package/dist/public/assets/_S9Qy4Cmi.js.br +0 -0
  249. package/dist/public/assets/{_BF2_gMS8.js → _ShiWFlWr.js} +1 -1
  250. package/dist/public/assets/_ShiWFlWr.js.br +0 -0
  251. package/dist/public/assets/{_CDPOV9zA.js → _TLB-Nq6Z.js} +1 -1
  252. package/dist/public/assets/_TLB-Nq6Z.js.br +0 -0
  253. package/dist/public/assets/_YcOZiOZ4.js +2 -0
  254. package/dist/public/assets/_YcOZiOZ4.js.br +0 -0
  255. package/dist/public/assets/_YjSW_ahw.js +1 -0
  256. package/dist/public/assets/_c9iXcb5V.js +1 -0
  257. package/dist/public/assets/{_T32b15Ve.js → _dSWMMogH.js} +1 -1
  258. package/dist/public/assets/_dSWMMogH.js.br +0 -0
  259. package/dist/public/assets/_dp0lBRTw.js +1 -0
  260. package/dist/public/assets/_etOTb_Um.js +1 -0
  261. package/dist/public/assets/{_DmISa8wc.js → _fZ9Nn0aY.js} +1 -1
  262. package/dist/public/assets/_fZ9Nn0aY.js.br +0 -0
  263. package/dist/public/assets/_h3o298tf.js +1 -0
  264. package/dist/public/assets/_iTnQEpuR.js +1 -0
  265. package/dist/public/assets/{_BWwfOfMX.js → _ii--A0F-.js} +1 -1
  266. package/dist/public/assets/_ii--A0F-.js.br +0 -0
  267. package/dist/public/assets/{_BZhRz8TB.js → _ixsF2ttz.js} +1 -1
  268. package/dist/public/assets/_ixsF2ttz.js.br +0 -0
  269. package/dist/public/assets/_kQ2OAVME.js +1 -0
  270. package/dist/public/assets/{_fBJXUlyl.js → _l71VhzhS.js} +1 -1
  271. package/dist/public/assets/_l71VhzhS.js.br +0 -0
  272. package/dist/public/assets/{_CY7Wr_6h.js → _ptpihSzL.js} +1 -1
  273. package/dist/public/assets/_ptpihSzL.js.br +0 -0
  274. package/dist/public/assets/{_B6Zw_zoM.js → _suQAT3jW.js} +1 -1
  275. package/dist/public/assets/_suQAT3jW.js.br +0 -0
  276. package/dist/public/assets/{_Bdq41ArX.js → _t5-hsdI5.js} +1 -1
  277. package/dist/public/assets/_t5-hsdI5.js.br +0 -0
  278. package/dist/public/assets/{_CAN3Gwlo.js → _tEBqbfOJ.js} +1 -1
  279. package/dist/public/assets/_tEBqbfOJ.js.br +0 -0
  280. package/dist/public/assets/{_C3La6EyV.js → _vy4Y1hd_.js} +1 -1
  281. package/dist/public/assets/_vy4Y1hd_.js.br +0 -0
  282. package/dist/public/assets/{_CKNilRtP.js → _x7Lebeio.js} +1 -1
  283. package/dist/public/assets/_x7Lebeio.js.br +0 -0
  284. package/dist/public/assets/_z3J861v3.js +1 -0
  285. package/dist/public/assets/files-view-DyuIyBwJ.js +2 -0
  286. package/dist/public/assets/manage-workspace-CtSdSPLU.js +2 -0
  287. package/dist/public/assets/new-ClUAGfpX.js +1 -0
  288. package/dist/public/assets/new-workspace-BLb55_cv.js +2 -0
  289. package/dist/public/assets/review-view-BhRXZEwU.js +2 -0
  290. package/dist/public/assets/settings-ClUAGfpX.js +1 -0
  291. package/dist/public/assets/settings-page-CTit2PgC.js +2 -0
  292. package/dist/public/assets/styles-C4hTgteh.css +1 -0
  293. package/dist/public/assets/styles-C4hTgteh.css.br +0 -0
  294. package/dist/public/assets/w-ClUAGfpX.js +1 -0
  295. package/dist/public/assets/w._-ClUAGfpX.js +1 -0
  296. package/dist/public/assets/w._-CtbjyBu3.js +1 -0
  297. package/dist/public/assets/w._-D5ZiKvyZ.js +1 -0
  298. package/package.json +1 -1
  299. package/dist/_BkRvQO5r.js +0 -2
  300. package/dist/_C29NgtBI.js +0 -2
  301. package/dist/public/assets/_-EmIcUKk.js +0 -1
  302. package/dist/public/assets/_-Zp0T_lO.js +0 -1
  303. package/dist/public/assets/_0H09AGax.js.br +0 -0
  304. package/dist/public/assets/_3jDFL-Cg.js.br +0 -0
  305. package/dist/public/assets/_42tHqFp1.js +0 -1
  306. package/dist/public/assets/_43jDY_uH.js +0 -1
  307. package/dist/public/assets/_5pKDjgHs.js.br +0 -0
  308. package/dist/public/assets/_73JN1my-.js +0 -1
  309. package/dist/public/assets/_7X0H8kL8.js +0 -1
  310. package/dist/public/assets/_9PIiwVmz.js.br +0 -0
  311. package/dist/public/assets/_Ag37ZLrV.js +0 -1
  312. package/dist/public/assets/_B-cgAjqV.js.br +0 -0
  313. package/dist/public/assets/_B0YQ-oFW.js +0 -1
  314. package/dist/public/assets/_B0tb8Vgp.js.br +0 -0
  315. package/dist/public/assets/_B1fJukJK.js +0 -1
  316. package/dist/public/assets/_B1rg6S37.js.br +0 -0
  317. package/dist/public/assets/_B40fHLkj.js.br +0 -0
  318. package/dist/public/assets/_B4a1Ga-C.js +0 -1
  319. package/dist/public/assets/_B5QrsHwd.js.br +0 -0
  320. package/dist/public/assets/_B6Gi_-aO.js +0 -1
  321. package/dist/public/assets/_B6Zw_zoM.js.br +0 -0
  322. package/dist/public/assets/_B7FUbkdd.js +0 -1
  323. package/dist/public/assets/_B9OVFXEI.js.br +0 -0
  324. package/dist/public/assets/_BAxxcUnT.js +0 -1
  325. package/dist/public/assets/_BBVcNRD6.js +0 -1
  326. package/dist/public/assets/_BCO2lKSr.js +0 -1
  327. package/dist/public/assets/_BF2_gMS8.js.br +0 -0
  328. package/dist/public/assets/_BH9u6x7L.js.br +0 -0
  329. package/dist/public/assets/_BHyPBbeA.js +0 -1
  330. package/dist/public/assets/_BICdCzpd.js.br +0 -0
  331. package/dist/public/assets/_BJcqxD6V.js.br +0 -0
  332. package/dist/public/assets/_BKsJcK3w.js +0 -1
  333. package/dist/public/assets/_BMXY56L9.js.br +0 -0
  334. package/dist/public/assets/_BORTVznS.js.br +0 -0
  335. package/dist/public/assets/_BOr_i2db.js +0 -1
  336. package/dist/public/assets/_BSCc1FVi.js +0 -1
  337. package/dist/public/assets/_BSEhhZ07.js +0 -1
  338. package/dist/public/assets/_BSyW2RLw.js.br +0 -0
  339. package/dist/public/assets/_BUPTpTYH.js.br +0 -0
  340. package/dist/public/assets/_BUqHNT5-.js +0 -1
  341. package/dist/public/assets/_BWwfOfMX.js.br +0 -0
  342. package/dist/public/assets/_BZXQzilG.js +0 -1
  343. package/dist/public/assets/_BZhRz8TB.js.br +0 -0
  344. package/dist/public/assets/_B_1_7y_i.js +0 -1
  345. package/dist/public/assets/_B_zlRrUP.js.br +0 -0
  346. package/dist/public/assets/_BciKbAaO.js.br +0 -0
  347. package/dist/public/assets/_BdNI84NG.js +0 -1
  348. package/dist/public/assets/_Bdq41ArX.js.br +0 -0
  349. package/dist/public/assets/_BfT9QWYM.js +0 -1
  350. package/dist/public/assets/_BflxkINP.js +0 -1
  351. package/dist/public/assets/_BiIrl8ml.js.br +0 -0
  352. package/dist/public/assets/_Bmgmfh64.js +0 -1
  353. package/dist/public/assets/_BnDvb8rh.js.br +0 -0
  354. package/dist/public/assets/_BstVSsFN.js +0 -1
  355. package/dist/public/assets/_Bu1DxZly.js +0 -1
  356. package/dist/public/assets/_By3jAAQI.js +0 -1
  357. package/dist/public/assets/_By3jAAQI.js.br +0 -0
  358. package/dist/public/assets/_ByZbJftZ.js.br +0 -0
  359. package/dist/public/assets/_BzU0dRn3.js +0 -1
  360. package/dist/public/assets/_C-IpRzUC.js +0 -1
  361. package/dist/public/assets/_C0W4EC0Z.js.br +0 -0
  362. package/dist/public/assets/_C1EEKbbh.js.br +0 -0
  363. package/dist/public/assets/_C1I4axdk.js +0 -1
  364. package/dist/public/assets/_C23aBO0p.js.br +0 -0
  365. package/dist/public/assets/_C3La6EyV.js.br +0 -0
  366. package/dist/public/assets/_C3k75NG8.js.br +0 -0
  367. package/dist/public/assets/_C4Hln-a1.js.br +0 -0
  368. package/dist/public/assets/_C7nRA4nl.js +0 -1
  369. package/dist/public/assets/_CAN3Gwlo.js.br +0 -0
  370. package/dist/public/assets/_CB6bJYj7.js +0 -1
  371. package/dist/public/assets/_CDG0zRut.js.br +0 -0
  372. package/dist/public/assets/_CDPOV9zA.js.br +0 -0
  373. package/dist/public/assets/_CEzgbnFo.js.br +0 -0
  374. package/dist/public/assets/_CH7j19or.js +0 -1
  375. package/dist/public/assets/_CH7j19or.js.br +0 -0
  376. package/dist/public/assets/_CKNilRtP.js.br +0 -0
  377. package/dist/public/assets/_CKvOm2QG.js.br +0 -0
  378. package/dist/public/assets/_CLpJpkGL.js.br +0 -0
  379. package/dist/public/assets/_CN4xiFtS.js +0 -1
  380. package/dist/public/assets/_CRAhvbwb.js.br +0 -0
  381. package/dist/public/assets/_CRkxKTgw.js +0 -1
  382. package/dist/public/assets/_CS08pKi4.js +0 -1
  383. package/dist/public/assets/_CSE16QHd.js +0 -1
  384. package/dist/public/assets/_CT4ei2Jg.js +0 -1
  385. package/dist/public/assets/_CW5ES2vr.js +0 -1
  386. package/dist/public/assets/_CWhF-4OC.js +0 -1
  387. package/dist/public/assets/_CXhoovwf.js.br +0 -0
  388. package/dist/public/assets/_CY7Wr_6h.js.br +0 -0
  389. package/dist/public/assets/_C_-mBehU.js +0 -1
  390. package/dist/public/assets/_CazYpkki.js +0 -1
  391. package/dist/public/assets/_CbAa5uAw.js.br +0 -0
  392. package/dist/public/assets/_CcbwLXni.js +0 -1
  393. package/dist/public/assets/_CiYp9PxT.js.br +0 -0
  394. package/dist/public/assets/_CmLGUmi9.js +0 -1
  395. package/dist/public/assets/_CmLGUmi9.js.br +0 -0
  396. package/dist/public/assets/_Coj9l4W_.js.br +0 -0
  397. package/dist/public/assets/_Cp1MBi_q.js +0 -1
  398. package/dist/public/assets/_CpXvQ4wL.js +0 -1
  399. package/dist/public/assets/_CsNZdkZU.js.br +0 -0
  400. package/dist/public/assets/_Ct8a3v8n.js +0 -1
  401. package/dist/public/assets/_CtYn_7Ld.js.br +0 -0
  402. package/dist/public/assets/_CthHHBjW.js +0 -2
  403. package/dist/public/assets/_CthHHBjW.js.br +0 -0
  404. package/dist/public/assets/_CtliFzZo.js +0 -1
  405. package/dist/public/assets/_Cw3MnPjo.js.br +0 -0
  406. package/dist/public/assets/_Cw9GxBkQ.js.br +0 -0
  407. package/dist/public/assets/_CwLlOfhS.js +0 -1
  408. package/dist/public/assets/_Cz606f5R.js +0 -7
  409. package/dist/public/assets/_Cz606f5R.js.br +0 -0
  410. package/dist/public/assets/_D-pAxlQ-.js.br +0 -0
  411. package/dist/public/assets/_D24Cf_aJ.js +0 -1
  412. package/dist/public/assets/_D2Bfy3Mq.js +0 -1
  413. package/dist/public/assets/_D3_-HE_e.js +0 -1
  414. package/dist/public/assets/_D4XHSL1o.js.br +0 -0
  415. package/dist/public/assets/_D8WYrmFe.js +0 -1
  416. package/dist/public/assets/_D8WYrmFe.js.br +0 -0
  417. package/dist/public/assets/_D9-mnhpM.js.br +0 -0
  418. package/dist/public/assets/_DBjp4Oaj.js +0 -1
  419. package/dist/public/assets/_DBzqRlRQ.js +0 -1
  420. package/dist/public/assets/_DC6M2qH2.js +0 -1
  421. package/dist/public/assets/_DE5SUDS8.js.br +0 -0
  422. package/dist/public/assets/_DEGMhwoO.js +0 -1
  423. package/dist/public/assets/_DIEqAzJB.js.br +0 -0
  424. package/dist/public/assets/_DJVQZQI-.js.br +0 -0
  425. package/dist/public/assets/_DL8YLICC.js +0 -1
  426. package/dist/public/assets/_DLoAVrbv.js.br +0 -0
  427. package/dist/public/assets/_DLpha-BN.js +0 -1
  428. package/dist/public/assets/_DPKcpw43.js.br +0 -0
  429. package/dist/public/assets/_DUEm1sqD.js.br +0 -0
  430. package/dist/public/assets/_DX8wVfyk.js +0 -1
  431. package/dist/public/assets/_DXEbBRHY.js +0 -1
  432. package/dist/public/assets/_DX_AAVan.js +0 -1
  433. package/dist/public/assets/_DXhgTM12.js +0 -1
  434. package/dist/public/assets/_DcCeapFB.js.br +0 -0
  435. package/dist/public/assets/_DdWxi_D9.js.br +0 -0
  436. package/dist/public/assets/_DeGJuali.js.br +0 -0
  437. package/dist/public/assets/_Dge-T7VA.js +0 -1
  438. package/dist/public/assets/_Dh_fGh7B.js.br +0 -0
  439. package/dist/public/assets/_DlKCZs5m.js +0 -1
  440. package/dist/public/assets/_DmAY0SHM.js +0 -1
  441. package/dist/public/assets/_DmBJQY0z.js.br +0 -0
  442. package/dist/public/assets/_DmISa8wc.js.br +0 -0
  443. package/dist/public/assets/_DpUeYTvU.js +0 -1
  444. package/dist/public/assets/_DqcTAqJs.js +0 -1
  445. package/dist/public/assets/_DrntETw8.js +0 -1
  446. package/dist/public/assets/_Dsb-mJGm.js +0 -1
  447. package/dist/public/assets/_DuKrnKV2.js.br +0 -0
  448. package/dist/public/assets/_Dv298HDL.js.br +0 -0
  449. package/dist/public/assets/_DxgeJa1G.js.br +0 -0
  450. package/dist/public/assets/_DxpwwPqc.js +0 -1
  451. package/dist/public/assets/_G0Ur49hc.js.br +0 -0
  452. package/dist/public/assets/_GRlZXT_k.js +0 -1
  453. package/dist/public/assets/_HnJD2Vzo.js.br +0 -0
  454. package/dist/public/assets/_KtT9ovgB.js.br +0 -0
  455. package/dist/public/assets/_LsFmgSj_.js.br +0 -0
  456. package/dist/public/assets/_M2eABJML.js +0 -1
  457. package/dist/public/assets/_N7_4E3sa.js +0 -1
  458. package/dist/public/assets/_SCQ7gzWP.js +0 -1
  459. package/dist/public/assets/_SkNT3g1t.js.br +0 -0
  460. package/dist/public/assets/_T32b15Ve.js.br +0 -0
  461. package/dist/public/assets/_TOwFHHoM.js.br +0 -0
  462. package/dist/public/assets/_UUd1gazT.js +0 -1
  463. package/dist/public/assets/_YTVYw9XV.js.br +0 -0
  464. package/dist/public/assets/_ZlbOPzr7.js.br +0 -0
  465. package/dist/public/assets/_a3BQDAxj.js.br +0 -0
  466. package/dist/public/assets/_aVJfol8S.js.br +0 -0
  467. package/dist/public/assets/_ee3nMJZE.js +0 -86
  468. package/dist/public/assets/_ee3nMJZE.js.br +0 -0
  469. package/dist/public/assets/_fBJXUlyl.js.br +0 -0
  470. package/dist/public/assets/_gy0a9Cmp.js.br +0 -0
  471. package/dist/public/assets/_iTbVHO4b.js +0 -1
  472. package/dist/public/assets/_k79dEMkm.js +0 -1
  473. package/dist/public/assets/_kHV7j6Zv.js.br +0 -0
  474. package/dist/public/assets/_l9Ig5EJO.js.br +0 -0
  475. package/dist/public/assets/_lYxkU02J.js +0 -1
  476. package/dist/public/assets/_rizgJsHK.js.br +0 -0
  477. package/dist/public/assets/_rmo2BlTL.js +0 -1
  478. package/dist/public/assets/_sEygC0rY.js +0 -1
  479. package/dist/public/assets/_sEygC0rY.js.br +0 -0
  480. package/dist/public/assets/_ulL_yezz.js.br +0 -0
  481. package/dist/public/assets/_vWNf9U23.js +0 -1
  482. package/dist/public/assets/_vd2rHjSk.js +0 -1
  483. package/dist/public/assets/_wC0cYIUL.js.br +0 -0
  484. package/dist/public/assets/_zGawNqPU.js.br +0 -0
  485. package/dist/public/assets/files-view-D9y_w_28.js +0 -2
  486. package/dist/public/assets/manage-workspace-BCRACsUn.js +0 -2
  487. package/dist/public/assets/new-BdLH98ro.js +0 -1
  488. package/dist/public/assets/new-workspace-TMTnjdBC.js +0 -2
  489. package/dist/public/assets/review-view-CvIicWqZ.js +0 -2
  490. package/dist/public/assets/settings-BdLH98ro.js +0 -1
  491. package/dist/public/assets/settings-page-I3W3CL5p.js +0 -2
  492. package/dist/public/assets/styles-D39vLjzP.css +0 -1
  493. package/dist/public/assets/styles-D39vLjzP.css.br +0 -0
  494. package/dist/public/assets/w-BdLH98ro.js +0 -1
  495. package/dist/public/assets/w._-BD4s-fU6.js +0 -1
  496. package/dist/public/assets/w._-BdLH98ro.js +0 -1
  497. package/dist/public/assets/w._-DnOj6Zzs.js +0 -1
@@ -382,7 +382,7 @@ work session send <id> "<text>"|- [--no-reply] [--now|--interrupt]
382
382
  work session unsend <id>
383
383
  Take back what this session queued for <id> that is not typed in yet:
384
384
  a message that went in stays in its turn (send a correction instead).
385
- work session reopen <id> [--agent <id>] [--now]
385
+ work session reopen <id> [--agent <id>] [--now] [--team]
386
386
  Start a session again on its own conversation, where its CLI can resume
387
387
  one (Claude, Codex): one closed — by its lead's close, the user's, or
388
388
  for being done — back under the session that started it, or under this
@@ -392,8 +392,17 @@ work session reopen <id> [--agent <id>] [--now]
392
392
  where the two share their conversations. What is queued for it and what
393
393
  it owes you stay: send it a message to carry it on. A restart ends the
394
394
  turn under way and what its pane runs (a background job, a dev server),
395
- so a running one mid-turn or with jobs is refused, saying what it is
396
- on, unless --now.
395
+ so a running one mid-turn or with jobs moves once it is idle, saying
396
+ what it waits out, unless --now restarts it at once. On this session
397
+ itself (\`reopen $WORK_SESSION_ID --agent claude2\`, a lead moving to
398
+ another account) it always waits for this turn's end, --now or not:
399
+ finish the turn and it moves, its conversation, team and queue kept.
400
+ --team, for a closed lead, brings back with it the sessions closed in
401
+ the same close, each under its own parent again and on its own
402
+ conversation (as --agent too, where that is another instance of its
403
+ CLI), naming any that cannot be reopened; those under one come back
404
+ under the nearest above them that did. It needs no --force: it brings
405
+ back what ran, not more.
397
406
  work session wait [<id>|<group>...] [--any] [--timeout <seconds>]
398
407
  Wait for the replies owed to this session (by those sessions or groups,
399
408
  else by any), printing each as it comes; a reply printed here is not
@@ -777,16 +786,39 @@ work session kill --done
777
786
  case "reopen": {
778
787
  const [id] = rest;
779
788
  if (!id)
780
- ctx.die("usage: work session reopen <id> [--agent <id>] [--now]");
789
+ ctx.die(
790
+ "usage: work session reopen <id> [--agent <id>] [--now] [--team]",
791
+ );
781
792
  const agent = ctx.flag("--agent");
782
793
  const r = await ctx.api.post(`/api/sessions/${id}/reopen${by()}`, {
783
794
  ...(agent ? { agent } : {}),
784
795
  ...(ctx.has("--now") ? { now: true } : {}),
796
+ ...(ctx.has("--team") ? { team: true } : {}),
785
797
  });
786
798
  return ctx.out(r, (r) => {
799
+ if (r.scheduled) {
800
+ const self = r.id === process.env.WORK_SESSION_ID;
801
+ console.log(
802
+ `${r.id} moves to ${r.scheduled} once ${self ? "this turn ends" : `it is idle (it waits out ${r.waits.join(", and ")})`}, on its own conversation, its team and queue kept.`,
803
+ );
804
+ if (self)
805
+ console.log(
806
+ "Finish this turn: say what you were on, then stop. The move starts this conversation again as the new instance.",
807
+ );
808
+ return;
809
+ }
787
810
  console.log(
788
811
  `${r.restarted ? "restarted" : "reopened"} ${r.id} on its conversation as ${r.agent}${r.parent ? `, under ${r.parent}` : ""}`,
789
812
  );
813
+ if (r.team) {
814
+ console.log(
815
+ r.team.reopened.length
816
+ ? `with its team: ${r.team.reopened.join(", ")}`
817
+ : "nothing was closed with it to bring back",
818
+ );
819
+ for (const s of r.team.skipped)
820
+ console.log(` not reopened ${s.id}: ${s.why}`);
821
+ }
790
822
  console.log(
791
823
  `It is at its prompt: \`work session send ${r.id} "…"\` carries it on.`,
792
824
  );
package/bin/cli/topic.mjs CHANGED
@@ -6,6 +6,7 @@
6
6
  // plus the server's workspace rows (bases) and status (PRs).
7
7
  import { spawnSync } from "node:child_process";
8
8
  import fs from "node:fs";
9
+ import os from "node:os";
9
10
  import path from "node:path";
10
11
 
11
12
  /** A topic's name: a word, or `<group>.<topic>` (folded into one review
@@ -24,11 +25,12 @@ const INSTALLERS = [
24
25
  ["Gemfile.lock", "bundle install"],
25
26
  ];
26
27
 
27
- function git(cwd, args, { allowFail = false } = {}) {
28
+ function git(cwd, args, { allowFail = false, env = {}, input } = {}) {
28
29
  const r = spawnSync("git", args, {
29
30
  cwd,
30
31
  encoding: "utf8",
31
- env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
32
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0", ...env },
33
+ input,
32
34
  });
33
35
  if (r.status !== 0 && !allowFail) {
34
36
  const why = (r.stderr || r.stdout || "").trim() || `exit ${r.status}`;
@@ -106,6 +108,27 @@ function aheadBehind(dir, base, tip) {
106
108
  return { ahead, behind };
107
109
  }
108
110
 
111
+ /** Its changes are all in `base` already though its commits are not —
112
+ * squashed into another PR, cherry-picked, folded in by hand: merging it
113
+ * there would change nothing, or every one of its commits' patches is
114
+ * there. Either way nothing is lost by putting it away, where ancestry
115
+ * alone called it unmerged for good. */
116
+ function landedIn(dir, base, tip) {
117
+ const merged = git(dir, ["merge-tree", "--write-tree", base, tip], {
118
+ allowFail: true,
119
+ });
120
+ // A clean merge prints its tree alone; one with conflicts exits 1.
121
+ if (merged.ok && merged.out === oid(dir, `${base}^{tree}`)) return true;
122
+ // Each commit's patch already there (`-`), even where the base has moved
123
+ // the same lines on since and the merge would conflict.
124
+ const cherry = git(dir, ["cherry", base, tip], { allowFail: true });
125
+ return (
126
+ cherry.ok &&
127
+ cherry.out !== "" &&
128
+ cherry.out.split("\n").every((l) => l.startsWith("- "))
129
+ );
130
+ }
131
+
109
132
  /** Where the workspace and its repos are, the other workspaces' branches
110
133
  * (whose topics are not this one's), and each repo's PRs — dismissed ones
111
134
  * too: a merged chip the user dismissed is still the merge that lets
@@ -125,9 +148,56 @@ async function context(ctx, fresh) {
125
148
  dir: path.join(ws.path, r.worktree),
126
149
  prs: prsOf.get(r.full_name) || [],
127
150
  }));
151
+ await withOlderPrs(ctx, ws, repos, foreign);
128
152
  return { ws, repos, foreign };
129
153
  }
130
154
 
155
+ /** The PRs the workspace's search no longer holds, for the topics that
156
+ * point at one. That search keeps only its latest finished PRs, so a topic
157
+ * squash-merged long ago read as unmerged work for good. Its tell: pushed
158
+ * once (an upstream recorded) and its copy on origin gone, which is how a
159
+ * merged PR's branch ends when GitHub deletes it, while a topic never
160
+ * pushed (most of a team's) asks nothing. Those few are asked for by name,
161
+ * in one request, and added to the repo's list. */
162
+ async function withOlderPrs(ctx, ws, repos, foreign) {
163
+ const heads = new Set();
164
+ for (const repo of repos) {
165
+ if (!fs.existsSync(repo.dir)) continue;
166
+ const pushed = git(
167
+ repo.dir,
168
+ [
169
+ "config",
170
+ "--get-regexp",
171
+ `^branch\\.${ws.branch.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}-.*\\.remote$`,
172
+ ],
173
+ { allowFail: true },
174
+ ).out;
175
+ for (const line of pushed.split("\n")) {
176
+ const branch = line.match(/^branch\.(.+)\.remote /)?.[1];
177
+ if (
178
+ branch &&
179
+ owns(branch, ws.branch, foreign) &&
180
+ !prFor(repo, branch) &&
181
+ oid(repo.dir, `refs/heads/${branch}`) &&
182
+ !oid(repo.dir, `refs/remotes/origin/${branch}`)
183
+ )
184
+ heads.add(branch);
185
+ }
186
+ }
187
+ if (!heads.size) return;
188
+ const found = await ctx.api
189
+ .get(
190
+ `/api/workspaces/${ws.id}/prs?heads=${encodeURIComponent([...heads].join(","))}`,
191
+ )
192
+ .catch(() => null);
193
+ for (const r of found?.repos || []) {
194
+ const repo = repos.find((x) => x.full_name === r.full_name);
195
+ if (!repo) continue;
196
+ const have = new Set(repo.prs.map((p) => p.number));
197
+ repo.prs.push(...(r.prs || []).filter((p) => !have.has(p.number)));
198
+ }
199
+ }
200
+
131
201
  const topicDir = (ws, name, repo) =>
132
202
  path.join(ws.path, ".worktrees", name, repo.worktree);
133
203
 
@@ -374,6 +444,7 @@ function topicsIn(ws, repo, foreign) {
374
444
  // What `topic new` recorded for gh: the branch it stacks on, else the
375
445
  // repo's base.
376
446
  const recorded = mergeBases(repo.dir);
447
+ const dropped = droppedBranches(repo.dir);
377
448
  const bases = new Map();
378
449
  return [...branches].sort().map((branch) => {
379
450
  const name = branch.slice(prefix.length);
@@ -389,6 +460,7 @@ function topicsIn(ws, repo, foreign) {
389
460
  : { ahead: null, behind: null };
390
461
  const worktree = trees.get(branch) || null;
391
462
  const pr = prFor(repo, branch);
463
+ const contained = !!base && ahead === 0;
392
464
  return {
393
465
  topic: name,
394
466
  repo: repo.worktree,
@@ -424,7 +496,12 @@ function topicsIn(ws, repo, foreign) {
424
496
  // Nothing of its own past the base: either merged as it was, or a
425
497
  // topic with no commits yet. Either way, nothing is lost by
426
498
  // putting its worktree away.
427
- contained: !!base && ahead === 0,
499
+ contained,
500
+ // Commits of its own, but none of its changes the base lacks.
501
+ landed: !!base && !contained && landedIn(repo.dir, base, tip),
502
+ // Dropped here (`topic drop`), its local branch gone: what is left is
503
+ // origin's copy, which drop leaves alone.
504
+ dropped: !local && dropped.has(branch),
428
505
  link: link(ws, repo, name),
429
506
  };
430
507
  });
@@ -433,9 +510,11 @@ function topicsIn(ws, repo, foreign) {
433
510
  async function topicList(ctx) {
434
511
  const { ws, repos, foreign } = await context(ctx, ctx.has("--fresh"));
435
512
  const all = repos.flatMap((repo) => topicsIn(ws, repo, foreign));
436
- // Put away: merged (or nothing past its base) with no worktree left —
437
- // its branch kept, as the after-merge chores leave it. Listed on asking.
438
- const away = (t) => !t.worktree && (t.merged || t.contained);
513
+ // Put away: merged (or nothing of it its base lacks) with no worktree
514
+ // left — its branch kept, as the after-merge chores leave it — or dropped
515
+ // here. Listed on asking.
516
+ const away = (t) =>
517
+ t.dropped || (!t.worktree && (t.merged || t.contained || t.landed));
439
518
  const rows = ctx.has("--all") ? all : all.filter((t) => !away(t));
440
519
  const hidden = all.length - rows.length;
441
520
  ctx.out(rows, (list) => {
@@ -450,7 +529,9 @@ async function topicList(ctx) {
450
529
  ? `no ${t.baseBranch} or origin/${t.baseBranch} here to count against`
451
530
  : t.contained
452
531
  ? `nothing past ${t.base}`
453
- : `${t.ahead} ahead, ${t.behind} behind ${t.base}`;
532
+ : t.landed
533
+ ? `landed in ${t.base} (by other commits: ${t.ahead} of its own, none of its changes missing there)`
534
+ : `${t.ahead} ahead, ${t.behind} behind ${t.base}`;
454
535
  const flags = [
455
536
  t.dirty ? `${t.dirty} uncommitted` : null,
456
537
  t.local && !t.onOrigin && t.ahead ? "not pushed" : null,
@@ -458,7 +539,8 @@ async function topicList(ctx) {
458
539
  t.local && t.onOrigin && !t.unpushed && !t.pushed
459
540
  ? "origin has newer"
460
541
  : null,
461
- !t.local ? "only on origin" : null,
542
+ t.dropped ? "dropped here, origin keeps it" : null,
543
+ !t.local && !t.dropped ? "only on origin" : null,
462
544
  ].filter(Boolean);
463
545
  const pr = t.pr
464
546
  ? ` #${t.pr.number} ${t.pr.state === "OPEN" ? (t.pr.draft ? "draft" : "open") : t.pr.state.toLowerCase()}`
@@ -471,7 +553,7 @@ async function topicList(ctx) {
471
553
  }
472
554
  if (hidden)
473
555
  console.log(
474
- `${hidden} put away (merged, worktree removed): --all lists them`,
556
+ `${hidden} put away (merged or landed with its worktree removed, or dropped): --all lists them`,
475
557
  );
476
558
  });
477
559
  }
@@ -483,7 +565,7 @@ async function topicList(ctx) {
483
565
  * PR's head, or past what origin has of it. */
484
566
  function leftover(repo, t, pr) {
485
567
  const local = oid(repo.dir, `refs/heads/${t.branch}`);
486
- if (!local || t.contained) return null;
568
+ if (!local || t.contained || t.landed) return null;
487
569
  let head = pr?.headRefOid || null;
488
570
  if (head && !has(repo.dir, `${head}^{commit}`)) {
489
571
  // A squash-merged PR's head lives on in GitHub's pull ref.
@@ -532,15 +614,18 @@ async function topicDone(ctx) {
532
614
  const t = topicsIn(ws, repo, foreign).find((x) => x.branch === branch);
533
615
  if (!t) continue;
534
616
  const pr = prFor(repo, branch);
535
- if (!t.merged && !t.contained) {
617
+ if (!t.merged && !t.contained && !t.landed) {
536
618
  const prState = t.pr
537
619
  ? ` (#${t.pr.number} is ${t.pr.state.toLowerCase()})`
538
620
  : "";
621
+ // An abandoned topic is never merged: say how it goes instead.
539
622
  result.refused.push({
540
623
  repo: repo.worktree,
541
- why: t.base
542
- ? `${branch} is not merged${prState} and has ${t.ahead} commit(s) ${t.base} does not`
543
- : `${branch} is not merged${prState}, and there is no ${t.baseBranch} or origin/${t.baseBranch} here to check it against`,
624
+ why: `${
625
+ t.base
626
+ ? `${branch} is not merged${prState} and has changes in ${t.ahead} commit(s) ${t.base} lacks`
627
+ : `${branch} is not merged${prState}, and there is no ${t.baseBranch} or origin/${t.baseBranch} here to check it against`
628
+ } (to abandon it: work topic drop ${name})`,
544
629
  });
545
630
  continue;
546
631
  }
@@ -603,7 +688,8 @@ async function topicDone(ctx) {
603
688
  }
604
689
  // Nothing of its own: left where it is, unless what it stacks on
605
690
  // moved out from under it.
606
- if (other.contained && !moved.has(other.baseBranch)) continue;
691
+ if ((other.contained || other.landed) && !moved.has(other.baseBranch))
692
+ continue;
607
693
  const base = restack ? t.base : other.base;
608
694
  if (!other.local || !base) continue;
609
695
  const { behind } = aheadBehind(repo.dir, base, other.branch);
@@ -684,6 +770,307 @@ async function topicDone(ctx) {
684
770
  process.exitCode = 1;
685
771
  }
686
772
 
773
+ // -- drop --------------------------------------------------------------------
774
+
775
+ /** Where a dropped topic's last tip is kept, a ref per drop
776
+ * (`<branch>/<UTC stamp>`): outside `refs/work/<workspace>/`, whose
777
+ * snapshots the server prunes, and in no push. */
778
+ const DROPPED = "refs/work-dropped/";
779
+ /** How long a dropped topic can be brought back. */
780
+ const KEEP_DROPPED_DAYS = 30;
781
+ const DAY = 86_400_000;
782
+
783
+ const stampOf = (d) =>
784
+ d
785
+ .toISOString()
786
+ .replace(/[-:]/g, "")
787
+ .replace(/\.\d+Z$/, "Z");
788
+
789
+ function stampTime(stamp) {
790
+ const m = /^(\d{4})(\d\d)(\d\d)T(\d\d)(\d\d)(\d\d)Z$/.exec(stamp);
791
+ return m ? Date.UTC(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], +m[6]) : null;
792
+ }
793
+
794
+ /** Each dropped ref: its branch, the time of its drop. */
795
+ function droppedRefs(dir) {
796
+ return git(dir, ["for-each-ref", "--format=%(refname)", DROPPED], {
797
+ allowFail: true,
798
+ })
799
+ .out.split("\n")
800
+ .filter(Boolean)
801
+ .map((ref) => {
802
+ const rest = ref.slice(DROPPED.length);
803
+ const cut = rest.lastIndexOf("/");
804
+ return {
805
+ ref,
806
+ branch: rest.slice(0, cut),
807
+ at: stampTime(rest.slice(cut + 1)),
808
+ };
809
+ })
810
+ .filter((r) => r.branch && r.at !== null);
811
+ }
812
+
813
+ /** The branches dropped here (within their keep). */
814
+ function droppedBranches(dir) {
815
+ return new Set(droppedRefs(dir).map((r) => r.branch));
816
+ }
817
+
818
+ /** Dropped refs past their keep, gone: every workspace's on this repo,
819
+ * since its cache is shared and a deleted workspace drops nothing again. */
820
+ function pruneDropped(dir, now = Date.now()) {
821
+ const gone = droppedRefs(dir).filter(
822
+ (r) => r.at < now - KEEP_DROPPED_DAYS * DAY,
823
+ );
824
+ if (gone.length)
825
+ git(dir, ["update-ref", "--stdin"], {
826
+ allowFail: true,
827
+ input: gone.map((r) => `delete ${r.ref}\n`).join(""),
828
+ });
829
+ return gone.length;
830
+ }
831
+
832
+ /** A worktree as it is — uncommitted and untracked files too — as a commit
833
+ * on its HEAD, made through an index of its own so the worktree and its
834
+ * index are untouched: a forced drop keeps what it discards. */
835
+ function snapshotOf(worktree, message) {
836
+ const index = path.join(
837
+ os.tmpdir(),
838
+ `work-topic-drop-${process.pid}-${Date.now()}.index`,
839
+ );
840
+ // An identity of its own (a machine with none set still drops) and no
841
+ // signing (a key's passphrase prompt would hang a script).
842
+ const env = {
843
+ GIT_INDEX_FILE: index,
844
+ GIT_AUTHOR_NAME: "work",
845
+ GIT_AUTHOR_EMAIL: "work@localhost",
846
+ GIT_COMMITTER_NAME: "work",
847
+ GIT_COMMITTER_EMAIL: "work@localhost",
848
+ };
849
+ try {
850
+ git(worktree, ["read-tree", "HEAD"], { env });
851
+ git(worktree, ["add", "-A"], { env });
852
+ const tree = git(worktree, ["write-tree"], { env }).out;
853
+ return git(
854
+ worktree,
855
+ ["commit-tree", "--no-gpg-sign", tree, "-p", "HEAD", "-m", message],
856
+ { env },
857
+ ).out;
858
+ } finally {
859
+ fs.rmSync(index, { force: true });
860
+ }
861
+ }
862
+
863
+ const real = (p) => {
864
+ try {
865
+ return fs.realpathSync(p);
866
+ } catch {
867
+ return path.resolve(p);
868
+ }
869
+ };
870
+ const within = (dir, root) => dir === root || dir.startsWith(root + path.sep);
871
+
872
+ /** Everything about dropping the topic in one repo, before any of it is
873
+ * done: what goes, what would be lost, and what stands in the way —
874
+ * `blocks` give way to --yes, `stops` never do. */
875
+ function planDrop(ctx, ws, repo, t, sessions, topics) {
876
+ const plan = { repo, t, lost: [], blocks: [], stops: [], dirty: [] };
877
+ plan.local = oid(repo.dir, `refs/heads/${t.branch}`);
878
+ if (!plan.local) return plan;
879
+ if (t.worktree && real(t.worktree) === real(repo.dir))
880
+ plan.stops.push(
881
+ `${t.branch} is checked out in the workspace's own checkout (${repo.dir}): switch that off it first`,
882
+ );
883
+ if (t.worktree) {
884
+ plan.dirty = dirtyIn(t.worktree);
885
+ if (plan.dirty.length)
886
+ plan.blocks.push(
887
+ `${t.worktree} has ${plan.dirty.length} uncommitted change(s):\n ${plan.dirty.slice(0, 10).join("\n ")}`,
888
+ );
889
+ const here = real(t.worktree);
890
+ for (const s of sessions)
891
+ if (
892
+ s.state?.alive &&
893
+ s.launch_dir &&
894
+ within(real(path.resolve(ws.path, s.launch_dir)), here)
895
+ )
896
+ plan.blocks.push(
897
+ `session ${s.id}${s.title ? ` ("${s.title}")` : ""} is working in ${t.worktree}`,
898
+ );
899
+ }
900
+ // What the drop discards: none of it when its base holds every change.
901
+ const merged = t.merged && !leftover(repo, t, prFor(repo, t.branch));
902
+ if (!t.contained && !t.landed && !merged) {
903
+ if (!t.base)
904
+ plan.blocks.push(
905
+ `there is no ${t.baseBranch} or origin/${t.baseBranch} here to tell what of ${t.branch} would be lost`,
906
+ );
907
+ else {
908
+ plan.lost = git(repo.dir, [
909
+ "log",
910
+ "--format=%h %s",
911
+ `${t.base}..${plan.local}`,
912
+ ]).out.split("\n");
913
+ plan.blocks.push(
914
+ `${t.branch} has ${plan.lost.length} commit(s) whose changes ${t.base} lacks${
915
+ t.unpushed
916
+ ? `, ${t.onOrigin ? t.unpushed : "all"} of them on no remote`
917
+ : ""
918
+ }:\n ${plan.lost.slice(0, 10).join("\n ")}`,
919
+ );
920
+ }
921
+ }
922
+ if (t.pr?.state === "OPEN")
923
+ plan.blocks.push(
924
+ `#${t.pr.number} is open (the drop leaves the PR and origin's copy as they are)`,
925
+ );
926
+ plan.stacked = topics.filter(
927
+ (o) => o.branch !== t.branch && o.local && o.baseBranch === t.branch,
928
+ );
929
+ for (const o of plan.stacked)
930
+ plan.blocks.push(
931
+ `${o.branch} stacks on it (with --yes it is counted against ${t.baseBranch} instead, still carrying ${t.branch}'s commits)`,
932
+ );
933
+ return plan;
934
+ }
935
+
936
+ async function topicDrop(ctx) {
937
+ const [name] = ctx.parse([]);
938
+ if (!name) ctx.die("usage: work topic drop <name> [--yes] [--json]");
939
+ const { ws, repos, foreign } = await context(ctx, false);
940
+ const branch = `${ws.branch}-${name}`;
941
+ const touched = repos.filter(
942
+ (r) =>
943
+ has(r.dir, `refs/heads/${branch}`) ||
944
+ has(r.dir, `refs/remotes/origin/${branch}`),
945
+ );
946
+ if (!touched.length)
947
+ ctx.die(`no topic ${name} in ${ws.name} (see: work topic list)`);
948
+ const sessions = await ctx.api
949
+ .get(`/api/workspaces/${ws.id}/sessions`)
950
+ .catch(() => []);
951
+ // Every repo is planned before any is touched: half a topic dropped is
952
+ // worse than none.
953
+ const plans = [];
954
+ for (const repo of touched) {
955
+ // A fetch that fails (offline) only leaves the base older, which can
956
+ // only find more to lose.
957
+ ctx.log(`fetching ${repo.full_name}…`);
958
+ if (
959
+ !git(repo.dir, ["fetch", "--prune", "--quiet", "origin"], {
960
+ allowFail: true,
961
+ }).ok
962
+ )
963
+ ctx.warn(
964
+ `${repo.worktree}: could not fetch origin; counting against what is here`,
965
+ );
966
+ const topics = topicsIn(ws, repo, foreign);
967
+ const t = topics.find((x) => x.branch === branch);
968
+ if (t) plans.push(planDrop(ctx, ws, repo, t, sessions, topics));
969
+ }
970
+ const result = {
971
+ topic: name,
972
+ dropped: [],
973
+ skipped: [],
974
+ refused: [],
975
+ restacked: [],
976
+ };
977
+ for (const p of plans) {
978
+ for (const why of p.stops)
979
+ result.refused.push({ repo: p.repo.worktree, why });
980
+ if (!ctx.yes)
981
+ for (const why of p.blocks)
982
+ result.refused.push({ repo: p.repo.worktree, why });
983
+ }
984
+ if (!result.refused.length) {
985
+ const at = new Date();
986
+ for (const p of plans) {
987
+ const { repo, t } = p;
988
+ if (!p.local) {
989
+ result.skipped.push({
990
+ repo: repo.worktree,
991
+ why: `${branch} is only on origin: nothing here to drop (git push origin --delete ${branch} removes it there)`,
992
+ });
993
+ continue;
994
+ }
995
+ pruneDropped(repo.dir, at.getTime());
996
+ const keep = p.dirty.length
997
+ ? snapshotOf(
998
+ t.worktree,
999
+ `work topic drop: ${branch} with its uncommitted changes`,
1000
+ )
1001
+ : p.local;
1002
+ const ref = `${DROPPED}${branch}/${stampOf(at)}`;
1003
+ git(repo.dir, ["update-ref", ref, keep]);
1004
+ if (t.worktree) {
1005
+ git(repo.dir, [
1006
+ "worktree",
1007
+ "remove",
1008
+ ...(p.dirty.length ? ["--force"] : []),
1009
+ t.worktree,
1010
+ ]);
1011
+ // The topic's own folder, once its last repo's worktree is gone.
1012
+ try {
1013
+ fs.rmdirSync(path.dirname(t.worktree));
1014
+ } catch {}
1015
+ }
1016
+ for (const o of p.stacked) {
1017
+ git(repo.dir, [
1018
+ "config",
1019
+ `branch.${o.branch}.gh-merge-base`,
1020
+ t.baseBranch,
1021
+ ]);
1022
+ result.restacked.push({
1023
+ repo: repo.worktree,
1024
+ branch: o.branch,
1025
+ base: t.baseBranch,
1026
+ });
1027
+ }
1028
+ // Its config (the recorded base) goes with it.
1029
+ git(repo.dir, ["branch", "-D", branch]);
1030
+ result.dropped.push({
1031
+ repo: repo.worktree,
1032
+ branch,
1033
+ worktree: t.worktree,
1034
+ commits: p.lost.filter(Boolean).length,
1035
+ unpushed: p.lost.length ? t.unpushed : 0,
1036
+ uncommitted: p.dirty.length,
1037
+ kept: ref,
1038
+ keptDays: KEEP_DROPPED_DAYS,
1039
+ restore: `git -C ${repo.dir} branch ${branch} ${ref}`,
1040
+ onOrigin: t.onOrigin,
1041
+ });
1042
+ }
1043
+ }
1044
+ ctx.out(result, (r) => {
1045
+ for (const x of r.dropped) {
1046
+ const lost = [
1047
+ x.commits ? `${x.commits} commit(s) its base lacks` : null,
1048
+ x.uncommitted ? `${x.uncommitted} uncommitted change(s)` : null,
1049
+ ].filter(Boolean);
1050
+ console.log(
1051
+ `${x.repo}: dropped ${x.branch}${lost.length ? ` (${lost.join(", ")})` : ""}`,
1052
+ );
1053
+ if (x.worktree) console.log(` removed ${x.worktree}`);
1054
+ console.log(
1055
+ ` kept as ${x.kept} for ${x.keptDays} days; to bring it back: ${x.restore}${x.uncommitted ? " (its top commit holds the uncommitted changes)" : ""}`,
1056
+ );
1057
+ if (x.onOrigin)
1058
+ console.log(
1059
+ ` origin/${x.branch} is still on origin (git push origin --delete ${x.branch} removes it)`,
1060
+ );
1061
+ }
1062
+ for (const x of r.skipped) console.log(`${x.repo}: ${x.why}`);
1063
+ for (const x of r.restacked)
1064
+ console.log(`${x.repo}: ${x.branch} now counts against ${x.base}`);
1065
+ for (const x of r.refused) console.log(`${x.repo}: ${x.why}`);
1066
+ if (r.refused.length)
1067
+ console.log(
1068
+ `nothing dropped${ctx.yes ? "" : `: pass --yes to drop it anyway (its tip and uncommitted changes are kept ${KEEP_DROPPED_DAYS} days)`}`,
1069
+ );
1070
+ });
1071
+ if (result.refused.length) process.exitCode = 1;
1072
+ }
1073
+
687
1074
  // -- command -----------------------------------------------------------------
688
1075
 
689
1076
  const HELP = `work topic new <name> [--repo <repo>]… [--from <ref>] [--install]
@@ -703,17 +1090,27 @@ work topic list [--all] [--fresh] [--json]
703
1090
  answer.
704
1091
  work topic done <name> [--rebase] [--json]
705
1092
  after its PR merged, or once its base holds all of it (merged there
706
- by hand, say): fetch --prune, remove its worktree (only if clean, and
707
- only if the merge took every commit), keep the branch, and list the
708
- other open topics to rebase, each onto its own base — one stacked on
709
- this topic onto this one's, which becomes its base. --rebase does it
710
- where the worktree is clean, aborting on conflict. Never touches the
711
- workspace's own checkout.`;
1093
+ by hand, say) or all of its changes by other commits (squashed into
1094
+ another PR, cherry-picked): fetch --prune, remove its worktree (only
1095
+ if clean, and only if the merge took every commit), keep the branch,
1096
+ and list the other open topics to rebase, each onto its own base — one
1097
+ stacked on this topic onto this one's, which becomes its base.
1098
+ --rebase does it where the worktree is clean, aborting on conflict.
1099
+ Never touches the workspace's own checkout.
1100
+ work topic drop <name> [--yes] [--json]
1101
+ abandon a topic: remove its worktree and delete its local branch,
1102
+ keeping its tip (with any uncommitted changes) as
1103
+ refs/work-dropped/<branch>/<when> for ${KEEP_DROPPED_DAYS} days; the output says how to
1104
+ bring it back. Refuses, unless --yes, whatever would discard work:
1105
+ commits whose changes its base lacks (and which of them no remote has),
1106
+ uncommitted changes, a session working in it, a topic stacked on it, an
1107
+ open PR. Origin's copy and any PR are left as they are. Never touches
1108
+ the workspace's own checkout.`;
712
1109
 
713
1110
  export const commands = [
714
1111
  {
715
1112
  name: "topic",
716
- summary: "start, list and put away topic branches (work help topic)",
1113
+ summary: "start, list, put away and drop topic branches (work help topic)",
717
1114
  help: HELP,
718
1115
  async run(ctx) {
719
1116
  const [verb] = ctx.positional;
@@ -725,11 +1122,12 @@ export const commands = [
725
1122
  if (verb === "list" || verb === "ls" || !verb)
726
1123
  return await topicList(sub);
727
1124
  if (verb === "done") return await topicDone(sub);
1125
+ if (verb === "drop") return await topicDrop(sub);
728
1126
  } catch (err) {
729
1127
  ctx.die(err instanceof Error ? err.message : String(err));
730
1128
  }
731
1129
  ctx.die(
732
- `no \`work topic ${verb}\`: new, list or done (see: work help topic)`,
1130
+ `no \`work topic ${verb}\`: new, list, done or drop (see: work help topic)`,
733
1131
  );
734
1132
  },
735
1133
  },