@dylanpiercey/work 0.2.19 → 0.2.21

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 (493) hide show
  1. package/README.md +3 -1
  2. package/bin/cli/session.mjs +256 -31
  3. package/bin/cli/topic.mjs +73 -40
  4. package/dist/_ChI2bucF.js +182 -0
  5. package/dist/_CwRrg_5F.js +2 -0
  6. package/dist/{_CsokArOR.js → _D2c8RJYx.js} +244 -58
  7. package/dist/_D4MBRSvk.js +730 -0
  8. package/dist/_D_EchrLM.js +2 -0
  9. package/dist/index.mjs +3319 -2288
  10. package/dist/public/assets/_0_tMiE7f.js +1 -0
  11. package/dist/public/assets/{_bHL-NcWS.js → _5Ph1wNdv.js} +1 -1
  12. package/dist/public/assets/_5Ph1wNdv.js.br +0 -0
  13. package/dist/public/assets/{_CCoTlnvb.js → _73_5-rCS.js} +1 -1
  14. package/dist/public/assets/_73_5-rCS.js.br +0 -0
  15. package/dist/public/assets/{_Ctjz3BD9.js → _7GQ1l7sx.js} +1 -1
  16. package/dist/public/assets/_7GQ1l7sx.js.br +0 -0
  17. package/dist/public/assets/_7k6uqsTc.js +1 -0
  18. package/dist/public/assets/_A-HJRoUO.js +1 -0
  19. package/dist/public/assets/{_DbT6uo7W.js → _AG2JmsQz.js} +1 -1
  20. package/dist/public/assets/_AG2JmsQz.js.br +0 -0
  21. package/dist/public/assets/_B-imOnRL.js +1 -0
  22. package/dist/public/assets/_B0RaDdiN.js +1 -0
  23. package/dist/public/assets/_B2I37jlY.js +1 -0
  24. package/dist/public/assets/_B2W_RvT4.js +1 -0
  25. package/dist/public/assets/_B3CzJbQp.js +1 -0
  26. package/dist/public/assets/_B8r95K43.js +1 -0
  27. package/dist/public/assets/{_CPaMvBMG.js → _BA03_q-y.js} +1 -1
  28. package/dist/public/assets/_BA03_q-y.js.br +0 -0
  29. package/dist/public/assets/{_MHZgY1AQ.js → _BBa2z28B.js} +1 -1
  30. package/dist/public/assets/_BBa2z28B.js.br +0 -0
  31. package/dist/public/assets/_BByqToGp.js +1 -0
  32. package/dist/public/assets/_BDeHik-b.js +1 -0
  33. package/dist/public/assets/_BDeHik-b.js.br +0 -0
  34. package/dist/public/assets/{_DTNiWZFr.js → _BFRiYaJJ.js} +1 -1
  35. package/dist/public/assets/_BFRiYaJJ.js.br +0 -0
  36. package/dist/public/assets/{_CHmEM8Sm.js → _BFwKmI_N.js} +1 -1
  37. package/dist/public/assets/_BFwKmI_N.js.br +0 -0
  38. package/dist/public/assets/{_DDcVFyaQ.js → _BHNeaYnj.js} +1 -1
  39. package/dist/public/assets/_BHNeaYnj.js.br +0 -0
  40. package/dist/public/assets/{_BprZx4vg.js → _BICa3xdD.js} +2 -2
  41. package/dist/public/assets/_BICa3xdD.js.br +0 -0
  42. package/dist/public/assets/{_DuyCZnNC.js → _BIFenNek.js} +1 -1
  43. package/dist/public/assets/_BIFenNek.js.br +0 -0
  44. package/dist/public/assets/{_BH9BIky6.js → _BIZTsyRb.js} +1 -1
  45. package/dist/public/assets/_BIZTsyRb.js.br +0 -0
  46. package/dist/public/assets/_BIa9L_Jp.js +1 -0
  47. package/dist/public/assets/_BMzbHEFm.js +1 -0
  48. package/dist/public/assets/_BN97aa7P.js +1 -0
  49. package/dist/public/assets/_BN97aa7P.js.br +0 -0
  50. package/dist/public/assets/_BNwDgGuR.js +1 -0
  51. package/dist/public/assets/_BOUZTVjf.js +1 -0
  52. package/dist/public/assets/_BPz4j7rE.js +1 -0
  53. package/dist/public/assets/_BTIm72sB.js +1 -0
  54. package/dist/public/assets/{_J1v2clxU.js → _BUYhsvxh.js} +1 -1
  55. package/dist/public/assets/_BUYhsvxh.js.br +0 -0
  56. package/dist/public/assets/_BXJTxGED.js +1 -0
  57. package/dist/public/assets/_BY0If-li.js +1 -0
  58. package/dist/public/assets/{_D__ojGam.js → _BYAIloss.js} +1 -1
  59. package/dist/public/assets/_BYAIloss.js.br +0 -0
  60. package/dist/public/assets/{_B9qGqvit.js → _BYRLA-dW.js} +1 -1
  61. package/dist/public/assets/{_YoXk_8Bl.js → _Bce4ghWU.js} +1 -1
  62. package/dist/public/assets/_Bce4ghWU.js.br +0 -0
  63. package/dist/public/assets/{_J3wdy6bJ.js → _BcsCv88i.js} +1 -1
  64. package/dist/public/assets/_BcsCv88i.js.br +0 -0
  65. package/dist/public/assets/{_-7Amnss4.js → _Bdmof7vZ.js} +1 -1
  66. package/dist/public/assets/_Bdmof7vZ.js.br +0 -0
  67. package/dist/public/assets/_BfZCi5tl.js +1 -0
  68. package/dist/public/assets/{_DYhs8iJg.js → _Bg6bkAHS.js} +12 -12
  69. package/dist/public/assets/_Bg6bkAHS.js.br +0 -0
  70. package/dist/public/assets/{_Cmtl59QM.js → _BgvqVgPM.js} +1 -1
  71. package/dist/public/assets/_BgvqVgPM.js.br +0 -0
  72. package/dist/public/assets/{_Dtx52FYB.js → _BizVDqf8.js} +1 -1
  73. package/dist/public/assets/{_Bt03HU8S.js → _Bk8Ggq5-.js} +1 -1
  74. package/dist/public/assets/{_BBCzcNZY.js → _BkfWuvuV.js} +1 -1
  75. package/dist/public/assets/_BkfWuvuV.js.br +0 -0
  76. package/dist/public/assets/{_CBEKHwUV.js → _BkzIkssa.js} +1 -1
  77. package/dist/public/assets/_BkzIkssa.js.br +0 -0
  78. package/dist/public/assets/{_BClUYs-k.js → _BlDj9LAX.js} +1 -1
  79. package/dist/public/assets/_BlDj9LAX.js.br +0 -0
  80. package/dist/public/assets/_BlMnx5Na.js +1 -0
  81. package/dist/public/assets/{_C1RigMYD.js → _Bmbd0VHt.js} +1 -1
  82. package/dist/public/assets/_Bmbd0VHt.js.br +0 -0
  83. package/dist/public/assets/_BmrjESDR.js +1 -0
  84. package/dist/public/assets/_Bo-ZmKi7.js +1 -0
  85. package/dist/public/assets/_BoQkVIQr.js +1 -0
  86. package/dist/public/assets/_BoRKAxyI.js +1 -0
  87. package/dist/public/assets/_BqIUSM2Y.js +1 -0
  88. package/dist/public/assets/_BrEXuoKx.js +1 -0
  89. package/dist/public/assets/{_D7qWWxdI.js → _Bsq9keoe.js} +1 -1
  90. package/dist/public/assets/_Bsq9keoe.js.br +0 -0
  91. package/dist/public/assets/{_UZAFx6D8.js → _Bvx-j57v.js} +1 -1
  92. package/dist/public/assets/_Bvx-j57v.js.br +0 -0
  93. package/dist/public/assets/_BzqqrLsh.js +1 -0
  94. package/dist/public/assets/{_G8KNSVdM.js → _BzuJUSrq.js} +1 -1
  95. package/dist/public/assets/_BzuJUSrq.js.br +0 -0
  96. package/dist/public/assets/{_uCKs5N6Q.js → _C08Yvl87.js} +1 -1
  97. package/dist/public/assets/_C08Yvl87.js.br +0 -0
  98. package/dist/public/assets/_C1JmLCpr.js +1 -0
  99. package/dist/public/assets/_C1JmLCpr.js.br +0 -0
  100. package/dist/public/assets/{_BPDSQUbl.js → _C58IJd_X.js} +1 -1
  101. package/dist/public/assets/_C58IJd_X.js.br +0 -0
  102. package/dist/public/assets/{_DCrPsldZ.js → _C5zDywEl.js} +1 -1
  103. package/dist/public/assets/_C5zDywEl.js.br +0 -0
  104. package/dist/public/assets/{_CG383oZY.js → _C640tDQf.js} +1 -1
  105. package/dist/public/assets/_C640tDQf.js.br +0 -0
  106. package/dist/public/assets/{_DsehEuMD.js → _C9iToy9b.js} +1 -1
  107. package/dist/public/assets/_C9iToy9b.js.br +0 -0
  108. package/dist/public/assets/{_CuglAToi.js → _CDjIrVlP.js} +1 -1
  109. package/dist/public/assets/_CDjIrVlP.js.br +0 -0
  110. package/dist/public/assets/{_qAsGEOt5.js → _CDxca_Y6.js} +1 -1
  111. package/dist/public/assets/_CDxca_Y6.js.br +0 -0
  112. package/dist/public/assets/_CEW7bDu1.js +1 -0
  113. package/dist/public/assets/{_CEC5O89D.js → _CH9bw9am.js} +1 -1
  114. package/dist/public/assets/_CH9bw9am.js.br +0 -0
  115. package/dist/public/assets/_CHHsqkCg.js +1 -0
  116. package/dist/public/assets/_CI27TAPs.js +1 -0
  117. package/dist/public/assets/_CK6szfVl.js +1 -0
  118. package/dist/public/assets/_CL0Zklna.js +1 -0
  119. package/dist/public/assets/{_C7Y4xApK.js → _CLf29XSp.js} +1 -1
  120. package/dist/public/assets/_CLf29XSp.js.br +0 -0
  121. package/dist/public/assets/_CQ5mzxP3.js +1 -0
  122. package/dist/public/assets/{_CspPbDoP.js → _CSJjeQ2T.js} +1 -1
  123. package/dist/public/assets/_CSJjeQ2T.js.br +0 -0
  124. package/dist/public/assets/{_BhecGD7y.js → _CVZMUsZa.js} +1 -1
  125. package/dist/public/assets/_CVZMUsZa.js.br +0 -0
  126. package/dist/public/assets/_CXTzKJ7b.js +1 -0
  127. package/dist/public/assets/{_Cl7LTITm.js → _CXb8mRib.js} +1 -1
  128. package/dist/public/assets/_CXb8mRib.js.br +0 -0
  129. package/dist/public/assets/_CXg0iofG.js +1 -0
  130. package/dist/public/assets/_CYfTE2mK.js +1 -0
  131. package/dist/public/assets/_CYjOt5W9.js +1 -0
  132. package/dist/public/assets/_CZuGGG4i.js +1 -0
  133. package/dist/public/assets/{_T5HFHZgl.js → _C_iT3nzY.js} +1 -1
  134. package/dist/public/assets/_C_iT3nzY.js.br +0 -0
  135. package/dist/public/assets/{_C-BYkx5h.js → _CaNdac_8.js} +1 -1
  136. package/dist/public/assets/_CaNdac_8.js.br +0 -0
  137. package/dist/public/assets/_CaiQP-gC.js +1 -0
  138. package/dist/public/assets/_Cdn3JBI2.js +1 -0
  139. package/dist/public/assets/_CdnnYSkh.js +1 -0
  140. package/dist/public/assets/{_CdpmkkzR.js → _CerICoJl.js} +1 -1
  141. package/dist/public/assets/_CerICoJl.js.br +0 -0
  142. package/dist/public/assets/_CfnM74sI.js +1 -0
  143. package/dist/public/assets/{_DWb03VKf.js → _Cfupsedr.js} +1 -1
  144. package/dist/public/assets/_Cfupsedr.js.br +0 -0
  145. package/dist/public/assets/_ChTIOm8i.js +1 -0
  146. package/dist/public/assets/_ChqCBy1f.js +1 -0
  147. package/dist/public/assets/_CiorUJIA.js +1 -0
  148. package/dist/public/assets/_Cjbj13jO.js +1 -0
  149. package/dist/public/assets/_Cjbj13jO.js.br +0 -0
  150. package/dist/public/assets/_Ck1wrcUI.js +1 -0
  151. package/dist/public/assets/{_BAWjkhA8.js → _Ck7pAEbn.js} +1 -1
  152. package/dist/public/assets/_Ck7pAEbn.js.br +0 -0
  153. package/dist/public/assets/{_CBgzBB_k.js → _CkFtsZjQ.js} +1 -1
  154. package/dist/public/assets/_CkFtsZjQ.js.br +0 -0
  155. package/dist/public/assets/{_bDI-pCZR.js → _Cl4-TcfE.js} +1 -1
  156. package/dist/public/assets/_Cl4-TcfE.js.br +0 -0
  157. package/dist/public/assets/_CoqRYp5v.js +1 -0
  158. package/dist/public/assets/_CqpW3h-I.js +1 -0
  159. package/dist/public/assets/{_C6Yt6h_R.js → _CsGNOykB.js} +1 -1
  160. package/dist/public/assets/_CsGNOykB.js.br +0 -0
  161. package/dist/public/assets/_Ctnz7WWJ.js +1 -0
  162. package/dist/public/assets/{_B9xuaMHt.js → _CxVvYDtS.js} +1 -1
  163. package/dist/public/assets/_CxVvYDtS.js.br +0 -0
  164. package/dist/public/assets/_CxyIt6f7.js +1 -0
  165. package/dist/public/assets/{_0sTkxfPx.js → _CyL-kdgT.js} +1 -1
  166. package/dist/public/assets/_CyL-kdgT.js.br +0 -0
  167. package/dist/public/assets/_CzJ9InTW.js +1 -0
  168. package/dist/public/assets/{_Bcc0Xs64.js → _D1eeoDTu.js} +1 -1
  169. package/dist/public/assets/_D1eeoDTu.js.br +0 -0
  170. package/dist/public/assets/_D4CDV27H.js +1 -0
  171. package/dist/public/assets/{_zN8SypHW.js → _D4_n-0mW.js} +1 -1
  172. package/dist/public/assets/_D4_n-0mW.js.br +0 -0
  173. package/dist/public/assets/_D4cLcNV3.js +1 -0
  174. package/dist/public/assets/_DAyjzJQh.js +1 -0
  175. package/dist/public/assets/{_XsB9KmcW.js → _DDzF_HKK.js} +1 -1
  176. package/dist/public/assets/_DDzF_HKK.js.br +0 -0
  177. package/dist/public/assets/{_CfP0f0PU.js → _DErtgeIr.js} +1 -1
  178. package/dist/public/assets/_DErtgeIr.js.br +0 -0
  179. package/dist/public/assets/_DFfExL2u.js +1 -0
  180. package/dist/public/assets/_DFrz22tm.js +1 -0
  181. package/dist/public/assets/_DHa_6Ojs.js +1 -0
  182. package/dist/public/assets/_DJOP49xX.js +1 -0
  183. package/dist/public/assets/_DK8uOd3E.js +1 -0
  184. package/dist/public/assets/{_BtedGrGs.js → _DOdGN8S4.js} +1 -1
  185. package/dist/public/assets/_DOdGN8S4.js.br +0 -0
  186. package/dist/public/assets/{_BDdZkZRc.js → _DRLwtZUR.js} +1 -1
  187. package/dist/public/assets/_DRLwtZUR.js.br +0 -0
  188. package/dist/public/assets/{_B9I2AEux.js → _DRTmj9TH.js} +1 -1
  189. package/dist/public/assets/_DRTmj9TH.js.br +0 -0
  190. package/dist/public/assets/_DSzLnpML.js +1 -0
  191. package/dist/public/assets/_DUKPsBJp.js +1 -0
  192. package/dist/public/assets/_DVYTGzTu.js +2 -0
  193. package/dist/public/assets/_DVYTGzTu.js.br +0 -0
  194. package/dist/public/assets/_DVmN6ae4.js +1 -0
  195. package/dist/public/assets/_DWA6owFW.js +1 -0
  196. package/dist/public/assets/{_D36PnqCD.js → _DdYu7WPn.js} +1 -1
  197. package/dist/public/assets/_DdYu7WPn.js.br +0 -0
  198. package/dist/public/assets/_Df7MvCAw.js +1 -0
  199. package/dist/public/assets/_DgOj7Cbi.js +1 -0
  200. package/dist/public/assets/{_qxffRpjc.js → _DhVfuzvb.js} +1 -1
  201. package/dist/public/assets/{_dVHSDgPC.js → _DiprQjpN.js} +1 -1
  202. package/dist/public/assets/_DiprQjpN.js.br +0 -0
  203. package/dist/public/assets/_DnlLdQgB.js +1 -0
  204. package/dist/public/assets/_DsnvOSuz.js +1 -0
  205. package/dist/public/assets/_Dt3XHRda.js +1 -0
  206. package/dist/public/assets/{_CDyWgQ0v.js → _DtP6T0Qs.js} +4 -4
  207. package/dist/public/assets/_DtP6T0Qs.js.br +0 -0
  208. package/dist/public/assets/_DtTvqD6P.js +86 -0
  209. package/dist/public/assets/_DtTvqD6P.js.br +0 -0
  210. package/dist/public/assets/{_BmpOmFbo.js → _DuaHQLSY.js} +1 -1
  211. package/dist/public/assets/_DuaHQLSY.js.br +0 -0
  212. package/dist/public/assets/_DvUlBhvt.js +1 -0
  213. package/dist/public/assets/{_DJBR8Qwq.js → _DwGQe611.js} +1 -1
  214. package/dist/public/assets/_DwGQe611.js.br +0 -0
  215. package/dist/public/assets/{_C_D5TPb7.js → _DwywWG3y.js} +1 -1
  216. package/dist/public/assets/_DwywWG3y.js.br +0 -0
  217. package/dist/public/assets/_IVFMD_0n.js +1 -0
  218. package/dist/public/assets/{_DYUFCi44.js → _Ij8bPUyH.js} +1 -1
  219. package/dist/public/assets/_Ij8bPUyH.js.br +0 -0
  220. package/dist/public/assets/_J6lHekiE.js +1 -0
  221. package/dist/public/assets/{_CB52LkYt.js → _NdzBn2sR.js} +1 -1
  222. package/dist/public/assets/_NdzBn2sR.js.br +0 -0
  223. package/dist/public/assets/_O_eRw3B2.js +1 -0
  224. package/dist/public/assets/{_CIfCdAzS.js → _P3IdziH9.js} +1 -1
  225. package/dist/public/assets/{_DSeQngGR.js → _P_Cq2but.js} +1 -1
  226. package/dist/public/assets/_P_Cq2but.js.br +0 -0
  227. package/dist/public/assets/_Qz67tpvL.js +1 -0
  228. package/dist/public/assets/{_D3IviZbJ.js → _R03vQ_v0.js} +1 -1
  229. package/dist/public/assets/_R03vQ_v0.js.br +0 -0
  230. package/dist/public/assets/{_C-DhXiEm.js → _RFw6Nx5T.js} +1 -1
  231. package/dist/public/assets/_RFw6Nx5T.js.br +0 -0
  232. package/dist/public/assets/{_D8ac72_O.js → _STdNaT6y.js} +1 -1
  233. package/dist/public/assets/_STdNaT6y.js.br +0 -0
  234. package/dist/public/assets/{_CL8DzBla.js → _UA84gjfG.js} +1 -1
  235. package/dist/public/assets/_UA84gjfG.js.br +0 -0
  236. package/dist/public/assets/_WkGa-CtY.js +1 -0
  237. package/dist/public/assets/{_briyaWgK.js → _YUh2tPBd.js} +1 -1
  238. package/dist/public/assets/_YUh2tPBd.js.br +0 -0
  239. package/dist/public/assets/_ZyOQxLKv.js +1 -0
  240. package/dist/public/assets/_ZyOQxLKv.js.br +0 -0
  241. package/dist/public/assets/{_G1BLeMns.js → _c-qsSFlV.js} +1 -1
  242. package/dist/public/assets/_c-qsSFlV.js.br +0 -0
  243. package/dist/public/assets/_dokDnQxT.js +1 -0
  244. package/dist/public/assets/_evDhQu9i.js +1 -0
  245. package/dist/public/assets/_gJS63N3S.js +1 -0
  246. package/dist/public/assets/{_DmoI4cIl.js → _gNcK1gjL.js} +1 -1
  247. package/dist/public/assets/_gNcK1gjL.js.br +0 -0
  248. package/dist/public/assets/_iRrqodg_.js +1 -0
  249. package/dist/public/assets/{_1M3oZPSf.js → _kVP48xNg.js} +1 -1
  250. package/dist/public/assets/_kVP48xNg.js.br +0 -0
  251. package/dist/public/assets/_kzqXqxfV.js +1 -0
  252. package/dist/public/assets/{_DN7pTn2g.js → _lkg74XVz.js} +1 -1
  253. package/dist/public/assets/_lkg74XVz.js.br +0 -0
  254. package/dist/public/assets/{_CdtjIoUd.js → _mSdir26q.js} +1 -1
  255. package/dist/public/assets/_mSdir26q.js.br +0 -0
  256. package/dist/public/assets/{_BjZqS7za.js → _maOaIkt7.js} +1 -1
  257. package/dist/public/assets/_maOaIkt7.js.br +0 -0
  258. package/dist/public/assets/{_BdSsUhCi.js → _oz27bk8p.js} +1 -1
  259. package/dist/public/assets/_oz27bk8p.js.br +0 -0
  260. package/dist/public/assets/{_BlshXH2Y.js → _pWJ2zOe1.js} +9 -9
  261. package/dist/public/assets/_pWJ2zOe1.js.br +0 -0
  262. package/dist/public/assets/{_BQW1kIop.js → _puLINbut.js} +1 -1
  263. package/dist/public/assets/_puLINbut.js.br +0 -0
  264. package/dist/public/assets/_u10cI9v9.js +1 -0
  265. package/dist/public/assets/_u10cI9v9.js.br +0 -0
  266. package/dist/public/assets/{_EcMqP1xI.js → _uifx05bO.js} +1 -1
  267. package/dist/public/assets/_uifx05bO.js.br +0 -0
  268. package/dist/public/assets/{_CPj_VL66.js → _vK3Svg3Y.js} +1 -1
  269. package/dist/public/assets/_vK3Svg3Y.js.br +0 -0
  270. package/dist/public/assets/_vatAiflQ.js +1 -0
  271. package/dist/public/assets/{_DSCqWPO0.js → _vkQNoNgo.js} +1 -1
  272. package/dist/public/assets/_vkQNoNgo.js.br +0 -0
  273. package/dist/public/assets/{_DzNFlI0M.js → _vrEdqivA.js} +1 -1
  274. package/dist/public/assets/_vrEdqivA.js.br +0 -0
  275. package/dist/public/assets/{_DpbHp8yR.js → _waOVbKBy.js} +1 -1
  276. package/dist/public/assets/_waOVbKBy.js.br +0 -0
  277. package/dist/public/assets/{_Dw1P6xZJ.js → _xClsbTiz.js} +1 -1
  278. package/dist/public/assets/_xClsbTiz.js.br +0 -0
  279. package/dist/public/assets/{_CToqok6Q.js → _yEwkwRQh.js} +1 -1
  280. package/dist/public/assets/_yEwkwRQh.js.br +0 -0
  281. package/dist/public/assets/{_C3fslTAD.js → _zjCzqshZ.js} +1 -1
  282. package/dist/public/assets/_zjCzqshZ.js.br +0 -0
  283. package/dist/public/assets/files-view-LgAHHBkN.js +2 -0
  284. package/dist/public/assets/manage-workspace-GIrOdQfT.js +2 -0
  285. package/dist/public/assets/new-BnJGtHxA.js +1 -0
  286. package/dist/public/assets/new-workspace-D0_Bjnwr.js +2 -0
  287. package/dist/public/assets/review-view-EK5wo6mn.js +2 -0
  288. package/dist/public/assets/settings-BnJGtHxA.js +1 -0
  289. package/dist/public/assets/settings-page-fQ5vUGWY.js +2 -0
  290. package/dist/public/assets/styles-DJePZwKA.css +1 -0
  291. package/dist/public/assets/styles-DJePZwKA.css.br +0 -0
  292. package/dist/public/assets/w-BnJGtHxA.js +1 -0
  293. package/dist/public/assets/w._-6UqjOxF-.js +1 -0
  294. package/dist/public/assets/w._-B3lMtxDs.js +1 -0
  295. package/dist/public/assets/w._-BnJGtHxA.js +1 -0
  296. package/package.json +1 -1
  297. package/dist/_L2HNAA_8.js +0 -2
  298. package/dist/__TCdgPY5.js +0 -173
  299. package/dist/public/assets/_-7Amnss4.js.br +0 -0
  300. package/dist/public/assets/_0XXNUttq.js +0 -1
  301. package/dist/public/assets/_0sTkxfPx.js.br +0 -0
  302. package/dist/public/assets/_0zzYbK0A.js +0 -1
  303. package/dist/public/assets/_1M3oZPSf.js.br +0 -0
  304. package/dist/public/assets/_2O5HnHht.js +0 -1
  305. package/dist/public/assets/_7WlUaJPH.js +0 -1
  306. package/dist/public/assets/_8Tr7ByPg.js +0 -1
  307. package/dist/public/assets/_9AXMmQSO.js +0 -1
  308. package/dist/public/assets/_B1VqbV-X.js +0 -1
  309. package/dist/public/assets/_B9I2AEux.js.br +0 -0
  310. package/dist/public/assets/_B9xuaMHt.js.br +0 -0
  311. package/dist/public/assets/_BAWjkhA8.js.br +0 -0
  312. package/dist/public/assets/_BBCzcNZY.js.br +0 -0
  313. package/dist/public/assets/_BBW2szHh.js +0 -1
  314. package/dist/public/assets/_BCP2Njnu.js +0 -1
  315. package/dist/public/assets/_BClUYs-k.js.br +0 -0
  316. package/dist/public/assets/_BDdZkZRc.js.br +0 -0
  317. package/dist/public/assets/_BEDmGSgS.js +0 -1
  318. package/dist/public/assets/_BEDmGSgS.js.br +0 -0
  319. package/dist/public/assets/_BH9BIky6.js.br +0 -0
  320. package/dist/public/assets/_BLdi8Ee5.js +0 -1
  321. package/dist/public/assets/_BPDSQUbl.js.br +0 -0
  322. package/dist/public/assets/_BQW1kIop.js.br +0 -0
  323. package/dist/public/assets/_BQeoUfFw.js +0 -1
  324. package/dist/public/assets/_BRzroLbh.js +0 -1
  325. package/dist/public/assets/_BSXsTYSe.js +0 -1
  326. package/dist/public/assets/_BTXDT3Na.js +0 -1
  327. package/dist/public/assets/_BXm4xeFI.js +0 -1
  328. package/dist/public/assets/_BY8UeogK.js +0 -1
  329. package/dist/public/assets/_BYpyhp64.js +0 -1
  330. package/dist/public/assets/_BYpyhp64.js.br +0 -0
  331. package/dist/public/assets/_B_Kz7LnY.js +0 -1
  332. package/dist/public/assets/_Bcc0Xs64.js.br +0 -0
  333. package/dist/public/assets/_BdSsUhCi.js.br +0 -0
  334. package/dist/public/assets/_BdaWssEH.js +0 -1
  335. package/dist/public/assets/_BhecGD7y.js.br +0 -0
  336. package/dist/public/assets/_Bj9dpPhN.js +0 -1
  337. package/dist/public/assets/_BjZqS7za.js.br +0 -0
  338. package/dist/public/assets/_BkSUiyHK.js +0 -1
  339. package/dist/public/assets/_BlshXH2Y.js.br +0 -0
  340. package/dist/public/assets/_BmX-VP7w.js +0 -1
  341. package/dist/public/assets/_BmpOmFbo.js.br +0 -0
  342. package/dist/public/assets/_Bo6YntUl.js +0 -1
  343. package/dist/public/assets/_BprZx4vg.js.br +0 -0
  344. package/dist/public/assets/_Bqm7OnIV.js +0 -1
  345. package/dist/public/assets/_BquBGUNK.js +0 -1
  346. package/dist/public/assets/_BquBGUNK.js.br +0 -0
  347. package/dist/public/assets/_BrB66aRZ.js +0 -1
  348. package/dist/public/assets/_BtedGrGs.js.br +0 -0
  349. package/dist/public/assets/_C-BYkx5h.js.br +0 -0
  350. package/dist/public/assets/_C-DhXiEm.js.br +0 -0
  351. package/dist/public/assets/_C-NBFnST.js +0 -1
  352. package/dist/public/assets/_C1RigMYD.js.br +0 -0
  353. package/dist/public/assets/_C2vRS-ES.js +0 -1
  354. package/dist/public/assets/_C3fslTAD.js.br +0 -0
  355. package/dist/public/assets/_C4EYjWGn.js +0 -1
  356. package/dist/public/assets/_C4EYjWGn.js.br +0 -0
  357. package/dist/public/assets/_C6Yt6h_R.js.br +0 -0
  358. package/dist/public/assets/_C7Y4xApK.js.br +0 -0
  359. package/dist/public/assets/_CB52LkYt.js.br +0 -0
  360. package/dist/public/assets/_CBEKHwUV.js.br +0 -0
  361. package/dist/public/assets/_CBSLBYQF.js +0 -1
  362. package/dist/public/assets/_CBgzBB_k.js.br +0 -0
  363. package/dist/public/assets/_CCoTlnvb.js.br +0 -0
  364. package/dist/public/assets/_CD26To-f.js +0 -1
  365. package/dist/public/assets/_CDyWgQ0v.js.br +0 -0
  366. package/dist/public/assets/_CEC5O89D.js.br +0 -0
  367. package/dist/public/assets/_CF2kEAU7.js +0 -1
  368. package/dist/public/assets/_CFURqbmO.js +0 -1
  369. package/dist/public/assets/_CG383oZY.js.br +0 -0
  370. package/dist/public/assets/_CHNJosg3.js +0 -1
  371. package/dist/public/assets/_CHmEM8Sm.js.br +0 -0
  372. package/dist/public/assets/_CKyzH0fl.js +0 -1
  373. package/dist/public/assets/_CL8DzBla.js.br +0 -0
  374. package/dist/public/assets/_CNYS94C5.js +0 -1
  375. package/dist/public/assets/_CNhypHJN.js +0 -1
  376. package/dist/public/assets/_CO-FkxlA.js +0 -1
  377. package/dist/public/assets/_COiGBSpO.js +0 -1
  378. package/dist/public/assets/_COvolvRQ.js +0 -1
  379. package/dist/public/assets/_CPaMvBMG.js.br +0 -0
  380. package/dist/public/assets/_CPj_VL66.js.br +0 -0
  381. package/dist/public/assets/_CQJC8Vx4.js +0 -1
  382. package/dist/public/assets/_CRHNlzBC.js +0 -1
  383. package/dist/public/assets/_CToqok6Q.js.br +0 -0
  384. package/dist/public/assets/_CUFKkl0B.js +0 -1
  385. package/dist/public/assets/_CZsOUa-q.js +0 -1
  386. package/dist/public/assets/_C_D5TPb7.js.br +0 -0
  387. package/dist/public/assets/_CdHI48v6.js +0 -1
  388. package/dist/public/assets/_CdpmkkzR.js.br +0 -0
  389. package/dist/public/assets/_CdtjIoUd.js.br +0 -0
  390. package/dist/public/assets/_Ce9Tv01m.js +0 -1
  391. package/dist/public/assets/_CeC7Lv10.js +0 -1
  392. package/dist/public/assets/_CfP0f0PU.js.br +0 -0
  393. package/dist/public/assets/_Cg7DH3xk.js +0 -1
  394. package/dist/public/assets/_Cg7DH3xk.js.br +0 -0
  395. package/dist/public/assets/_CikNq0z8.js +0 -1
  396. package/dist/public/assets/_Cl7LTITm.js.br +0 -0
  397. package/dist/public/assets/_Cmtl59QM.js.br +0 -0
  398. package/dist/public/assets/_CshYq_Dp.js +0 -1
  399. package/dist/public/assets/_CspPbDoP.js.br +0 -0
  400. package/dist/public/assets/_Ctjz3BD9.js.br +0 -0
  401. package/dist/public/assets/_CuglAToi.js.br +0 -0
  402. package/dist/public/assets/_CwSoAVRN.js +0 -1
  403. package/dist/public/assets/_D0XQV-Hm.js +0 -1
  404. package/dist/public/assets/_D36PnqCD.js.br +0 -0
  405. package/dist/public/assets/_D3IviZbJ.js.br +0 -0
  406. package/dist/public/assets/_D6rgUB9O.js +0 -1
  407. package/dist/public/assets/_D7qWWxdI.js.br +0 -0
  408. package/dist/public/assets/_D8ac72_O.js.br +0 -0
  409. package/dist/public/assets/_D9WWxrQR.js +0 -1
  410. package/dist/public/assets/_D9hI5dSA.js +0 -1
  411. package/dist/public/assets/_DCrPsldZ.js.br +0 -0
  412. package/dist/public/assets/_DDcVFyaQ.js.br +0 -0
  413. package/dist/public/assets/_DDhkKo8Q.js +0 -1
  414. package/dist/public/assets/_DJBR8Qwq.js.br +0 -0
  415. package/dist/public/assets/_DLpa6VYT.js +0 -1
  416. package/dist/public/assets/_DMqe6rR-.js +0 -1
  417. package/dist/public/assets/_DN7pTn2g.js.br +0 -0
  418. package/dist/public/assets/_DP8UuFuJ.js +0 -1
  419. package/dist/public/assets/_DQedUaqM.js +0 -1
  420. package/dist/public/assets/_DSCqWPO0.js.br +0 -0
  421. package/dist/public/assets/_DSeQngGR.js.br +0 -0
  422. package/dist/public/assets/_DTNiWZFr.js.br +0 -0
  423. package/dist/public/assets/_DThlusXY.js +0 -1
  424. package/dist/public/assets/_DUK16H19.js +0 -1
  425. package/dist/public/assets/_DUZ13t3U.js +0 -1
  426. package/dist/public/assets/_DWb03VKf.js.br +0 -0
  427. package/dist/public/assets/_DWsyhfgn.js +0 -1
  428. package/dist/public/assets/_DXuzYhW6.js +0 -1
  429. package/dist/public/assets/_DXyOzA2b.js +0 -1
  430. package/dist/public/assets/_DYUFCi44.js.br +0 -0
  431. package/dist/public/assets/_DYhs8iJg.js.br +0 -0
  432. package/dist/public/assets/_D__ojGam.js.br +0 -0
  433. package/dist/public/assets/_DaFI_W5D.js +0 -1
  434. package/dist/public/assets/_DbT6uo7W.js.br +0 -0
  435. package/dist/public/assets/_DhnT0cCE.js +0 -1
  436. package/dist/public/assets/_Dm9OGn2q.js +0 -1
  437. package/dist/public/assets/_DmkeGFoM.js +0 -1
  438. package/dist/public/assets/_DmoI4cIl.js.br +0 -0
  439. package/dist/public/assets/_DpbHp8yR.js.br +0 -0
  440. package/dist/public/assets/_Dqz_HBE1.js +0 -1
  441. package/dist/public/assets/_DsehEuMD.js.br +0 -0
  442. package/dist/public/assets/_DuEyirL6.js +0 -1
  443. package/dist/public/assets/_DuuloSIi.js +0 -1
  444. package/dist/public/assets/_DuyCZnNC.js.br +0 -0
  445. package/dist/public/assets/_Dw1P6xZJ.js.br +0 -0
  446. package/dist/public/assets/_DzNFlI0M.js.br +0 -0
  447. package/dist/public/assets/_EcMqP1xI.js.br +0 -0
  448. package/dist/public/assets/_G1BLeMns.js.br +0 -0
  449. package/dist/public/assets/_G8KNSVdM.js.br +0 -0
  450. package/dist/public/assets/_J1v2clxU.js.br +0 -0
  451. package/dist/public/assets/_J3wdy6bJ.js.br +0 -0
  452. package/dist/public/assets/_MHZgY1AQ.js.br +0 -0
  453. package/dist/public/assets/_NHTZitq1.js +0 -2
  454. package/dist/public/assets/_NHTZitq1.js.br +0 -0
  455. package/dist/public/assets/_PsuNqRL9.js +0 -86
  456. package/dist/public/assets/_PsuNqRL9.js.br +0 -0
  457. package/dist/public/assets/_T5HFHZgl.js.br +0 -0
  458. package/dist/public/assets/_UZAFx6D8.js.br +0 -0
  459. package/dist/public/assets/_XA8_RQXF.js +0 -1
  460. package/dist/public/assets/_XsB9KmcW.js.br +0 -0
  461. package/dist/public/assets/_YoXk_8Bl.js.br +0 -0
  462. package/dist/public/assets/_YubCdy3Z.js +0 -1
  463. package/dist/public/assets/_bDI-pCZR.js.br +0 -0
  464. package/dist/public/assets/_bHL-NcWS.js.br +0 -0
  465. package/dist/public/assets/_bqRzDYc8.js +0 -1
  466. package/dist/public/assets/_briyaWgK.js.br +0 -0
  467. package/dist/public/assets/_dVHSDgPC.js.br +0 -0
  468. package/dist/public/assets/_gkZjZ9I4.js +0 -1
  469. package/dist/public/assets/_plyCYAnN.js +0 -1
  470. package/dist/public/assets/_q0Z44mWJ.js +0 -1
  471. package/dist/public/assets/_q0Z44mWJ.js.br +0 -0
  472. package/dist/public/assets/_qAsGEOt5.js.br +0 -0
  473. package/dist/public/assets/_uCKs5N6Q.js.br +0 -0
  474. package/dist/public/assets/_utWnC80Q.js +0 -1
  475. package/dist/public/assets/_utvzcBHT.js +0 -1
  476. package/dist/public/assets/_v8WbCPI8.js +0 -1
  477. package/dist/public/assets/_yK4b_Bl5.js +0 -1
  478. package/dist/public/assets/_yoQW4BY5.js +0 -1
  479. package/dist/public/assets/_zB6USXHX.js +0 -1
  480. package/dist/public/assets/_zN8SypHW.js.br +0 -0
  481. package/dist/public/assets/files-view-Fl0rU3Ns.js +0 -2
  482. package/dist/public/assets/manage-workspace-DggRcsXf.js +0 -2
  483. package/dist/public/assets/new-C7NxTJAT.js +0 -1
  484. package/dist/public/assets/new-workspace-C0pw5Iz1.js +0 -2
  485. package/dist/public/assets/review-view-C4YQ0J-X.js +0 -2
  486. package/dist/public/assets/settings-C7NxTJAT.js +0 -1
  487. package/dist/public/assets/settings-page-Cl_1tWCv.js +0 -2
  488. package/dist/public/assets/styles-Vcsj4CA7.css +0 -1
  489. package/dist/public/assets/styles-Vcsj4CA7.css.br +0 -0
  490. package/dist/public/assets/w-C7NxTJAT.js +0 -1
  491. package/dist/public/assets/w._-BbFH2lR-.js +0 -1
  492. package/dist/public/assets/w._-C7NxTJAT.js +0 -1
  493. package/dist/public/assets/w._-YIzLOiyZ.js +0 -1
package/README.md CHANGED
@@ -62,7 +62,9 @@ Inside a workspace, `work branches`, `work session`, `work topic`,
62
62
  `work review`, `work notify` and `work open`; agents start and message each
63
63
  other with `work session new|send|wait` — any vendor's, each in a tab of its
64
64
  own the user watches, its last message as a turn ends coming back to the
65
- one that asked as a prompt; to change things,
65
+ one that asked as a prompt — and run groups of them with
66
+ `work session fanout`, which the session list shows as a
67
+ lead's team; to change things,
66
68
  `work workspace create`, `work repo add`, `work config get|set` (checked
67
69
  against what each setting takes; `work config schema` lists them),
68
70
  `work agent|skill|lsp|host` and `work gh login`; `work status` sums the
@@ -1,10 +1,13 @@
1
1
  // `work session`: which session this is (an agent's own pane, by
2
2
  // WORK_SESSION_ID), its name in the session list, and the workspace's
3
- // other sessions — starting one, messaging it and waiting on its reply,
4
- // closing it (server/messages.ts).
3
+ // other sessions — starting one or a fan-out of them, messaging one and
4
+ // waiting on replies, closing them (server/messages.ts, server/team.ts).
5
+ import path from "node:path";
6
+ import { makeTopics, topicRepos } from "./topic.mjs";
5
7
 
6
- /** More sessions than this in one workspace is an agent starting them in
7
- * a loop, not a plan: past it, `new` wants --force. */
8
+ /** More sessions than this running in one workspace is an agent starting
9
+ * them in a loop, not a plan: past it, `new` wants --force. A fan-out's
10
+ * members go through its pool instead. */
8
11
  const SESSION_CAP = 8;
9
12
 
10
13
  /** The session a command means: --session's, else this pane's own. */
@@ -97,10 +100,67 @@ function printReply(r) {
97
100
  if (r.kind === "reply") console.log(`${r.text}\n`);
98
101
  }
99
102
 
103
+ /** Start folders for `count` sessions, a topic each (`<topic>`, or
104
+ * `<topic>-1`… for several) in the repos `--repo` names (else the cwd's):
105
+ * a member's worktree is its own, so their edits never meet. Relative
106
+ * to the workspace: a repo's worktree for one repo, the topic's folder
107
+ * for several. */
108
+ async function topicDirs(ctx, topic, count) {
109
+ const { ws, picked } = await topicRepos(ctx);
110
+ const names =
111
+ count === 1
112
+ ? [topic]
113
+ : Array.from({ length: count }, (_, i) => `${topic}-${i + 1}`);
114
+ const made = makeTopics(ctx, ws, picked, names, {
115
+ install: ctx.has("--install"),
116
+ });
117
+ return {
118
+ names,
119
+ dirs: names.map((name) => {
120
+ const rows = made.filter((m) => m.topic === name);
121
+ const dir = rows.length === 1 ? rows[0].path : path.dirname(rows[0].path);
122
+ return path.relative(ws.path, dir);
123
+ }),
124
+ links: made.map((m) => m.link),
125
+ };
126
+ }
127
+
128
+ const STATUS_MARK = {
129
+ queued: "◌",
130
+ starting: "◔",
131
+ working: "⟳",
132
+ waiting: "⚠",
133
+ idle: "·",
134
+ done: "✓",
135
+ closed: "✕",
136
+ };
137
+
138
+ /** One group of `work session team`: its head, then a line a member. */
139
+ function printGroup(ctx, g) {
140
+ const c = g.counts;
141
+ const left = c.queued + c.starting + c.working + c.waiting + c.idle;
142
+ const parts = [
143
+ `${c.done}/${g.members.length} done`,
144
+ c.working && `${c.working} working`,
145
+ c.waiting && `${c.waiting} waiting on the user`,
146
+ c.starting && `${c.starting} starting`,
147
+ c.queued && `${c.queued} queued`,
148
+ c.closed && `${c.closed} closed`,
149
+ ].filter(Boolean);
150
+ console.log(
151
+ `${g.id} "${g.title}" ${parts.join(" · ")} (${g.parallel} at a time, ${g.fanIn ? (left ? "replies held until all answer" : "replies sent as one") : "replies as each comes"})`,
152
+ );
153
+ for (const m of g.members)
154
+ console.log(
155
+ ` ${STATUS_MARK[m.status] ?? "?"} ${ctx.pad(m.status, 8)} ${ctx.pad(m.id, 9)} ${ctx.pad(m.session ?? "-", 9)} ${ctx.pad(m.agent, 8)} ${m.title}${m.line ? ` — ${m.line}` : ""}`,
156
+ );
157
+ }
158
+
100
159
  export const commands = [
101
160
  {
102
161
  name: "session",
103
- summary: "this session and the workspace's others: title, new, send, kill",
162
+ summary:
163
+ "this session and the workspace's others: new, fanout, send, wait, team, kill",
104
164
  help: `work session [--json]
105
165
  This session (WORK_SESSION_ID): its id, agent, name, state, and the
106
166
  workspace it is in (id, name, path) — what a link names (/w/<id>/…).
@@ -108,12 +168,39 @@ work session list [id|name] [--json]
108
168
  The workspace's sessions, this one marked.
109
169
  work session title "<name>" [--session <id>]
110
170
  Name a session in the session list (empty clears it).
111
- work session new [--agent <id>] [--title "<name>"] [--prompt "<text>"|-] [--no-reply] [--workspace <id|name>] [--force]
171
+ work session new [--agent <id>] [--title "<name>"] [--prompt "<text>"|-] [--no-reply] [--keep] [--topic <name> [--repo <repo>…] [--install]] [--workspace <id|name>] [--force]
112
172
  Start a session (the default agent unless --agent, any vendor's; "shell"
113
- for a terminal) in a tab of its own, where the user watches it, name it,
114
- and hand it a first prompt ("-": read it from stdin). Started from
115
- another session it is listed under that one, and the prompt is a
116
- message from it (below). Past ${SESSION_CAP} sessions in the workspace it wants --force.
173
+ for a terminal) in a tab of its own, where the user can watch it, name
174
+ it, and hand it a first prompt ("-": read it from stdin). Started from
175
+ another session it is listed under that one, runs in its permission
176
+ mode (it is an agent's to drive: nobody waits on it to answer a prompt),
177
+ and the prompt is a message from it (below). --topic starts it in a
178
+ topic branch of its own (\`work topic new\`). It closes once it has
179
+ answered and is done with — when your job finishes, or after ten idle
180
+ minutes — unless --keep, it is on the user's screen, or they have typed
181
+ into it. Past ${SESSION_CAP} running sessions in the workspace it wants --force.
182
+ work session fanout --agent <id> [--agent <id>…] [--count <n>] --prompt "<text>"|- [<item>…] [--title "<name>"] [--parallel <n>] [--stream] [--close-done|--keep] [--topic <name> [--repo <repo>…] [--install]]
183
+ Start a group of sessions from this one: each --agent once (or --count
184
+ times), or once for each <item> with {} in the prompt replaced by it
185
+ ({i} is the member's number). They queue and start --parallel at a time
186
+ (4), however many there are. Their replies come back to you as one
187
+ prompt once every member has answered (--stream: each as it comes); end
188
+ your turn to wait, or \`work session wait <group>\`. A member's session
189
+ closes once done with, as \`new\`'s does (its result is kept);
190
+ --close-done closes it as soon as it answers, --keep never;
191
+ --topic gives each member a topic branch of its own (<name>-1, -2, …),
192
+ side by side in Review. For a quick sweep inside your own CLI, its own
193
+ subagents are cheaper: this is for other vendors, long work, or work the
194
+ user may want to watch.
195
+ work session team [--json]
196
+ This session's groups: each member (its id, then its
197
+ session's), its state and its last line (what it is doing, or its
198
+ result).
199
+ work session retry <member>
200
+ Rerun a closed member in a fresh session: its group waits for it again.
201
+ work session skip <member>
202
+ Stop a member: a queued one never starts, a running one's session
203
+ closes; either way its group no longer waits on it.
117
204
  work session send <id> "<text>"|- [--no-reply]
118
205
  Message an agent session: typed in, headed with who it is from, once
119
206
  it is at its prompt — never into a turn under way, a question it asks,
@@ -121,13 +208,19 @@ work session send <id> "<text>"|- [--no-reply]
121
208
  unless --no-reply: the recipient's last message as that turn ends,
122
209
  typed into this session as a prompt of its own. End your turn to wait
123
210
  for it. A file's path says more than its text pasted in.
124
- work session wait [<id>...] [--timeout <seconds>]
125
- Wait for the replies owed to this session (by those sessions, else by
126
- any), printing each as it comes; a reply printed here is not typed in
127
- too. Exits 124 if some are still working after --timeout (${WAIT_S} s).
128
- work session kill <id> --yes
129
- Close a session and the process in it (whoever waits on its reply is
130
- told).`,
211
+ work session wait [<id>|<group>...] [--any] [--timeout <seconds>]
212
+ Wait for the replies owed to this session (by those sessions or groups,
213
+ else by any), printing each as it comes; a reply printed here is not
214
+ typed in too. A group's come once all its members have answered, unless
215
+ --any: then whatever is in, as soon as anything is. Exits 124 if some
216
+ are still working after --timeout (${WAIT_S} s).
217
+ work session kill <id> [--keep-children] --yes
218
+ Close a session and the process in it, and the sessions it started
219
+ with theirs, unless --keep-children (they then stand on their own).
220
+ Whoever waits on a reply from one is told.
221
+ work session kill --done
222
+ Close now the sessions this one started that are done with (answered,
223
+ idle, not the user's): fan-out results stay in \`work session team\`.`,
131
224
  async run(ctx) {
132
225
  const [verb, ...rest] = ctx.parse([
133
226
  "--agent",
@@ -136,6 +229,10 @@ work session kill <id> --yes
136
229
  "--workspace",
137
230
  "--session",
138
231
  "--timeout",
232
+ "--topic",
233
+ "--repo",
234
+ "--count",
235
+ "--parallel",
139
236
  ]);
140
237
  switch (verb) {
141
238
  case undefined: {
@@ -182,17 +279,26 @@ work session kill <id> --yes
182
279
  }
183
280
  case "new": {
184
281
  const { ws } = await ctx.resolveWorkspace(ctx.flag("--workspace"));
185
- const existing = await sessionsOf(ctx, ws.id);
186
- if (existing.length >= SESSION_CAP && !ctx.has("--force"))
282
+ const running = (await sessionsOf(ctx, ws.id)).filter(
283
+ (s) => s.phase !== "off",
284
+ );
285
+ if (running.length >= SESSION_CAP && !ctx.has("--force"))
187
286
  ctx.die(
188
- `${ws.name} already has ${existing.length} sessions: pass --force to start another`,
287
+ `${ws.name} already has ${running.length} sessions running: pass --force to start another (a group of them is \`work session fanout\`, which queues)`,
189
288
  );
190
289
  const agent = ctx.flag("--agent");
191
290
  const me = process.env.WORK_SESSION_ID;
192
291
  const prompt = await textOf(valueOf(ctx, "--prompt"));
292
+ const topic = ctx.flag("--topic");
293
+ const at = topic ? await topicDirs(ctx, topic, 1) : null;
193
294
  const created = await ctx.api.post(
194
295
  `/api/workspaces/${ws.id}/sessions`,
195
- { ...(agent ? { agent } : {}), ...(me ? { parent: me } : {}) },
296
+ {
297
+ ...(agent ? { agent } : {}),
298
+ ...(me ? { parent: me } : {}),
299
+ ...(at ? { dir: at.dirs[0] } : {}),
300
+ ...(ctx.has("--keep") ? { keep: true } : {}),
301
+ },
196
302
  );
197
303
  const title = ctx.flag("--title");
198
304
  if (title)
@@ -212,6 +318,7 @@ work session kill <id> --yes
212
318
  title: title || null,
213
319
  workspace: ws.id,
214
320
  parent: created.parent_id ?? null,
321
+ topic: topic ?? null,
215
322
  prompted: !!sent?.delivered,
216
323
  queued: sent?.queued ?? null,
217
324
  wantsReply: !!sent?.wantsReply,
@@ -219,7 +326,7 @@ work session kill <id> --yes
219
326
  };
220
327
  return ctx.out(out, (s) => {
221
328
  console.log(
222
- `started ${s.id} (${s.agent})${s.prompted ? " with its prompt" : ""}: [${s.title || s.agent}](${s.href})`,
329
+ `started ${s.id} (${s.agent})${s.prompted ? " with its prompt" : ""}${s.topic ? ` on topic ${s.topic}` : ""}: [${s.title || s.agent}](${s.href})`,
223
330
  );
224
331
  if (s.queued)
225
332
  console.log(`its prompt waits to be typed in: ${s.queued}`);
@@ -229,6 +336,85 @@ work session kill <id> --yes
229
336
  );
230
337
  });
231
338
  }
339
+ case "fanout": {
340
+ const me = sessionId(ctx);
341
+ const agents = ctx.flags("--agent");
342
+ if (!agents.length)
343
+ ctx.die(
344
+ 'usage: work session fanout --agent <id> [--agent <id>…] --prompt "<text>"|- [<item>…] (see: work help session)',
345
+ );
346
+ const prompt = await textOf(valueOf(ctx, "--prompt"));
347
+ if (!prompt) ctx.die("a fan-out needs a --prompt");
348
+ // A "-" is --prompt's stdin, not an item.
349
+ const items = rest.filter((i) => i !== "-");
350
+ const count = ctx.has("--count") ? Number(ctx.flag("--count")) : 1;
351
+ if (!Number.isInteger(count) || count < 1)
352
+ ctx.die("--count is a whole number of members per agent");
353
+ if (items.length && ctx.has("--count"))
354
+ ctx.die("--count or items, not both: items already say how many");
355
+ const parallel = ctx.has("--parallel")
356
+ ? Number(ctx.flag("--parallel"))
357
+ : undefined;
358
+ if (
359
+ parallel !== undefined &&
360
+ (!Number.isInteger(parallel) || parallel < 1)
361
+ )
362
+ ctx.die("--parallel is a whole number of members at once");
363
+ // Members in the server's order: by agent, then by item or number.
364
+ const total = new Set(agents).size * (items.length || count);
365
+ const topic = ctx.flag("--topic");
366
+ const at = topic ? await topicDirs(ctx, topic, total) : null;
367
+ const g = await ctx.api.post(`/api/sessions/${me}/groups`, {
368
+ title: ctx.flag("--title") ?? "",
369
+ prompt,
370
+ agents,
371
+ ...(items.length ? { items } : { count }),
372
+ ...(parallel ? { parallel } : {}),
373
+ fanIn: !ctx.has("--stream"),
374
+ closeDone: ctx.has("--close-done"),
375
+ keep: ctx.has("--keep"),
376
+ ...(at ? { dirs: at.dirs } : {}),
377
+ });
378
+ return ctx.out({ ...g, topics: at?.names ?? null }, (g) => {
379
+ console.log(
380
+ `fanned out ${g.id} "${g.title}": ${g.members.length} ${g.members.length === 1 ? "member" : "members"}, ${g.parallel} at a time`,
381
+ );
382
+ for (const m of g.members)
383
+ console.log(
384
+ ` ${ctx.pad(m.id, 10)} ${ctx.pad(m.agent, 8)} ${m.title}`,
385
+ );
386
+ if (at) for (const l of at.links) console.log(` review: ${l}`);
387
+ console.log(
388
+ g.fanIn
389
+ ? `Their replies come back to you as one prompt once every member has answered: end your turn to wait, or run \`work session wait ${g.id}\`. \`work session team\` shows how far they are.`
390
+ : `Each reply comes back to you as a prompt as it comes: end your turn to wait, or run \`work session wait ${g.id} --any\`.`,
391
+ );
392
+ });
393
+ }
394
+ case "team": {
395
+ const me = sessionId(ctx);
396
+ const t = await ctx.api.get(`/api/sessions/${me}/team`);
397
+ return ctx.out(t, (t) => {
398
+ if (!t.groups.length)
399
+ return console.log("no groups: `work session fanout` starts one");
400
+ for (const g of t.groups) printGroup(ctx, g);
401
+ });
402
+ }
403
+ case "retry":
404
+ case "skip": {
405
+ const [member] = rest;
406
+ if (!member) ctx.die(`usage: work session ${verb} <member>`);
407
+ await ctx.api.post(`/api/members/${member}/${verb}`);
408
+ return ctx.out(
409
+ { member, [verb === "retry" ? "retried" : "skipped"]: true },
410
+ () =>
411
+ console.log(
412
+ verb === "retry"
413
+ ? `queued ${member} again`
414
+ : `skipped ${member}`,
415
+ ),
416
+ );
417
+ }
232
418
  case "send": {
233
419
  const [id, ...words] = rest;
234
420
  const text = await textOf(words.join(" "));
@@ -248,8 +434,9 @@ work session kill <id> --yes
248
434
  const seconds = raw === undefined ? WAIT_S : Number(raw);
249
435
  if (!Number.isFinite(seconds) || seconds < 0)
250
436
  ctx.die("--timeout is a number of seconds");
437
+ const any = ctx.has("--any");
251
438
  const until = Date.now() + seconds * 1000;
252
- const body = rest.length ? { from: rest } : {};
439
+ const body = { ...(rest.length ? { from: rest } : {}), any };
253
440
  const replies = [];
254
441
  let owing = [];
255
442
  for (;;) {
@@ -258,6 +445,7 @@ work session kill <id> --yes
258
445
  if (!ctx.json) r.replies.forEach(printReply);
259
446
  owing = r.owing;
260
447
  if (!owing.length || Date.now() >= until) break;
448
+ if (any && replies.length) break;
261
449
  await new Promise((res) => setTimeout(res, POLL_MS));
262
450
  }
263
451
  if (ctx.json)
@@ -268,24 +456,61 @@ work session kill <id> --yes
268
456
  ? `nothing owed by ${rest.join(", ")}: a reply already typed in is in your prompt`
269
457
  : "no session owes this one a reply",
270
458
  );
271
- if (owing.length) {
459
+ if (owing.length && !(any && replies.length)) {
272
460
  ctx.warn(
273
461
  `still working: ${owing.map((o) => o.label).join(", ")} (wait again, or end your turn: the reply comes as a prompt)`,
274
462
  );
275
463
  process.exitCode = 124;
276
- }
464
+ } else if (owing.length && !ctx.json)
465
+ console.log(
466
+ `still working: ${owing.map((o) => o.label).join(", ")}`,
467
+ );
277
468
  return;
278
469
  }
279
470
  case "kill": {
471
+ if (ctx.has("--done")) {
472
+ const me = sessionId(ctx);
473
+ const { closed } = await ctx.api.post(
474
+ `/api/sessions/${me}/close-done`,
475
+ );
476
+ return ctx.out({ closed }, () =>
477
+ console.log(
478
+ closed
479
+ ? `closed ${closed} finished ${closed === 1 ? "session" : "sessions"}`
480
+ : "none of the sessions this one started is done with",
481
+ ),
482
+ );
483
+ }
280
484
  const [id] = rest;
281
- if (!id) ctx.die("usage: work session kill <id> --yes");
282
- if (!ctx.yes)
485
+ if (!id)
486
+ ctx.die(
487
+ "usage: work session kill <id> [--keep-children] --yes, or --done",
488
+ );
489
+ const keep = ctx.has("--keep-children");
490
+ if (!ctx.yes) {
491
+ // Said before it happens: what else goes with it.
492
+ const { ws } = await ctx.resolveWorkspace(ctx.flag("--workspace"));
493
+ const list = await sessionsOf(ctx, ws.id);
494
+ const family = [id];
495
+ for (let i = 0; i < family.length; i++)
496
+ for (const s of list)
497
+ if (s.parent === family[i] && !family.includes(s.id))
498
+ family.push(s.id);
499
+ const others = keep ? 0 : family.length - 1;
283
500
  ctx.die(
284
- `closing ${id} ends the process in it${id === process.env.WORK_SESSION_ID ? " — this session, the one running this command" : ""}: pass --yes`,
501
+ `closing ${id} ends the process in it${others ? ` and in the ${others} ${others === 1 ? "session" : "sessions"} it started (${family.slice(1).join(", ")}; --keep-children keeps them)` : ""}${(keep ? [id] : family).includes(process.env.WORK_SESSION_ID) ? " — this session, the one running this command, among them" : ""}: pass --yes`,
285
502
  );
286
- await ctx.api.del(`/api/sessions/${id}`);
287
- return ctx.out({ id, killed: true }, () =>
288
- console.log(`closed ${id}`),
503
+ }
504
+ const r = await ctx.api.del(
505
+ `/api/sessions/${id}${keep ? "?children=keep" : ""}`,
506
+ );
507
+ const closed = r?.closed ?? [id];
508
+ return ctx.out({ id, killed: true, closed }, () =>
509
+ console.log(
510
+ closed.length > 1
511
+ ? `closed ${id} and the sessions it started: ${closed.slice(1).join(", ")}`
512
+ : `closed ${id}`,
513
+ ),
289
514
  );
290
515
  }
291
516
  default:
package/bin/cli/topic.mjs CHANGED
@@ -170,65 +170,79 @@ function fetch(ctx, repo) {
170
170
 
171
171
  // -- new ---------------------------------------------------------------------
172
172
 
173
- async function topicNew(ctx) {
174
- const [name] = ctx.parse(["--repo", "--from"]);
175
- if (!name)
176
- ctx.die("usage: work topic new <name> [--repo <repo>…] [--from <ref>]");
177
- if (!NAME.test(name) || name.includes(".."))
178
- ctx.die(
179
- `"${name}" is not a topic name: letters, digits, \`-\`, \`_\`, and \`.\` for a group (\`<group>.<topic>\`)`,
180
- );
181
- const { ws, repos } = await context(ctx, false);
182
- const branch = `${ws.branch}-${name}`;
183
- const from = ctx.has("--from") ? ctx.flag("--from") : null;
184
- const picked = pickRepos(ctx, ws, repos);
185
- for (const repo of picked) {
186
- if (
187
- !git(repo.dir, ["check-ref-format", "--branch", branch], {
188
- allowFail: true,
189
- }).ok
190
- )
191
- ctx.die(`${branch} is not a branch name git takes`);
192
- }
193
- // Every refusal before anything is made: half a topic is worse than none.
194
- const plans = [];
195
- for (const repo of picked) {
196
- fetch(ctx, repo);
197
- const dest = topicDir(ws, name, repo);
198
- if (has(repo.dir, `refs/heads/${branch}`))
173
+ /** Make the topics `names`, each a branch off its base and a worktree in
174
+ * every repo `picked`, and run each's install with `install`. Every
175
+ * refusal comes before anything is made: half a topic is worse than
176
+ * none, and half a fan-out's worse still. Returns a row per worktree. */
177
+ export function makeTopics(
178
+ ctx,
179
+ ws,
180
+ picked,
181
+ names,
182
+ { from = null, install = false } = {},
183
+ ) {
184
+ for (const name of names)
185
+ if (!NAME.test(name) || name.includes(".."))
199
186
  ctx.die(
200
- `${repo.worktree}: ${branch} already exists${worktreesOf(repo.dir).get(branch) ? ` (at ${worktreesOf(repo.dir).get(branch)})` : ""} — pick another name, or work in it`,
187
+ `"${name}" is not a topic name: letters, digits, \`-\`, \`_\`, and \`.\` for a group (\`<group>.<topic>\`)`,
201
188
  );
202
- if (has(repo.dir, `refs/remotes/origin/${branch}`))
203
- ctx.die(
204
- `${repo.worktree}: ${branch} is already on origin — check it out there (git -C ${repo.dir} worktree add ${dest} ${branch}) rather than starting it again`,
205
- );
206
- if (fs.existsSync(dest)) ctx.die(`${dest} already exists`);
207
- const start = from ?? `origin/${repo.base_branch}`;
208
- if (!has(repo.dir, `${start}^{commit}`))
209
- ctx.die(`${repo.worktree}: no ${start} to start from`);
210
- plans.push({ repo, dest, start });
189
+ for (const repo of picked) fetch(ctx, repo);
190
+ const plans = [];
191
+ for (const name of names) {
192
+ const branch = `${ws.branch}-${name}`;
193
+ for (const repo of picked) {
194
+ if (
195
+ !git(repo.dir, ["check-ref-format", "--branch", branch], {
196
+ allowFail: true,
197
+ }).ok
198
+ )
199
+ ctx.die(`${branch} is not a branch name git takes`);
200
+ const dest = topicDir(ws, name, repo);
201
+ if (has(repo.dir, `refs/heads/${branch}`))
202
+ ctx.die(
203
+ `${repo.worktree}: ${branch} already exists${worktreesOf(repo.dir).get(branch) ? ` (at ${worktreesOf(repo.dir).get(branch)})` : ""} — pick another name, or work in it`,
204
+ );
205
+ if (has(repo.dir, `refs/remotes/origin/${branch}`))
206
+ ctx.die(
207
+ `${repo.worktree}: ${branch} is already on origin — check it out there (git -C ${repo.dir} worktree add ${dest} ${branch}) rather than starting it again`,
208
+ );
209
+ if (fs.existsSync(dest)) ctx.die(`${dest} already exists`);
210
+ const start = from ?? `origin/${repo.base_branch}`;
211
+ if (!has(repo.dir, `${start}^{commit}`))
212
+ ctx.die(`${repo.worktree}: no ${start} to start from`);
213
+ plans.push({ name, branch, repo, dest, start });
214
+ }
211
215
  }
212
216
  const made = [];
213
- for (const { repo, dest, start } of plans) {
217
+ for (const { name, branch, repo, dest, start } of plans) {
214
218
  fs.mkdirSync(path.dirname(dest), { recursive: true });
215
219
  // --no-track: its upstream is set by the first push, to its own name on
216
220
  // origin, never to the base it was cut from.
217
221
  git(repo.dir, ["worktree", "add", "--no-track", "-b", branch, dest, start]);
218
- const install = installFor(dest);
219
222
  const stacked = from && from !== `origin/${repo.base_branch}` ? from : null;
223
+ // Its PR's base, said as gh reads it (branch.<b>.gh-merge-base): the
224
+ // branch it stacks on, else the base it was cut from.
225
+ const prBase = (stacked ?? repo.base_branch).replace(/^origin\//, "");
226
+ if (
227
+ has(repo.dir, `refs/heads/${prBase}`) ||
228
+ has(repo.dir, `refs/remotes/origin/${prBase}`)
229
+ )
230
+ git(repo.dir, ["config", `branch.${branch}.gh-merge-base`, prBase], {
231
+ allowFail: true,
232
+ });
220
233
  made.push({
234
+ topic: name,
221
235
  repo: repo.worktree,
222
236
  branch,
223
237
  path: dest,
224
238
  base: repo.base_branch,
225
239
  from: start,
226
240
  stacked,
227
- install,
241
+ install: installFor(dest),
228
242
  link: link(ws, repo, name),
229
243
  });
230
244
  }
231
- if (ctx.has("--install")) {
245
+ if (install) {
232
246
  for (const m of made) {
233
247
  if (!m.install) continue;
234
248
  ctx.log(`${m.repo}: ${m.install}`);
@@ -242,6 +256,25 @@ async function topicNew(ctx) {
242
256
  if (!m.installed) ctx.warn(`${m.repo}: \`${m.install}\` failed`);
243
257
  }
244
258
  }
259
+ return made;
260
+ }
261
+
262
+ /** The workspace, its repos, and the ones a command names (`--repo`, else
263
+ * the one the cwd is in): what `makeTopics` takes. */
264
+ export async function topicRepos(ctx) {
265
+ const { ws, repos } = await context(ctx, false);
266
+ return { ws, picked: pickRepos(ctx, ws, repos) };
267
+ }
268
+
269
+ async function topicNew(ctx) {
270
+ const [name] = ctx.parse(["--repo", "--from"]);
271
+ if (!name)
272
+ ctx.die("usage: work topic new <name> [--repo <repo>…] [--from <ref>]");
273
+ const { ws, picked } = await topicRepos(ctx);
274
+ const made = makeTopics(ctx, ws, picked, [name], {
275
+ from: ctx.has("--from") ? ctx.flag("--from") : null,
276
+ install: ctx.has("--install"),
277
+ }).map(({ topic: _, ...m }) => m);
245
278
  ctx.out(made, (rows) => {
246
279
  for (const m of rows) {
247
280
  console.log(`${m.repo}/ on ${m.branch}`);