@dylanpiercey/work 0.2.19 → 0.2.20

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 (506) hide show
  1. package/README.md +3 -1
  2. package/bin/cli/plan.mjs +85 -0
  3. package/bin/cli/session.mjs +267 -31
  4. package/bin/cli/topic.mjs +63 -40
  5. package/dist/_BHlbSSAl.js +182 -0
  6. package/dist/_C9c_BxRk.js +787 -0
  7. package/dist/_DrEeyoLF.js +2 -0
  8. package/dist/_E0fWorAK.js +2 -0
  9. package/dist/{_CsokArOR.js → _Hb3LeA5Q.js} +218 -58
  10. package/dist/index.mjs +3456 -2299
  11. package/dist/public/assets/_-TUXzZ5j.js +1 -0
  12. package/dist/public/assets/_-TUXzZ5j.js.br +0 -0
  13. package/dist/public/assets/_0BO-2AH8.js +1 -0
  14. package/dist/public/assets/_1MkpPhCv.js +1 -0
  15. package/dist/public/assets/_2Czzn44S.js +2 -0
  16. package/dist/public/assets/_2Czzn44S.js.br +0 -0
  17. package/dist/public/assets/{_B9qGqvit.js → _2M3NjHcy.js} +1 -1
  18. package/dist/public/assets/_3J3NCTfA.js +1 -0
  19. package/dist/public/assets/_3yfaou9w.js +1 -0
  20. package/dist/public/assets/{_DSeQngGR.js → _6fcPfRKt.js} +1 -1
  21. package/dist/public/assets/_6fcPfRKt.js.br +0 -0
  22. package/dist/public/assets/_9kzNcuvf.js +1 -0
  23. package/dist/public/assets/_AbxeWvtk.js +1 -0
  24. package/dist/public/assets/{_D__ojGam.js → _B1AH7m_8.js} +1 -1
  25. package/dist/public/assets/_B1AH7m_8.js.br +0 -0
  26. package/dist/public/assets/{_BAWjkhA8.js → _B2zs9J9f.js} +1 -1
  27. package/dist/public/assets/_B2zs9J9f.js.br +0 -0
  28. package/dist/public/assets/_B4Tl4g-I.js +1 -0
  29. package/dist/public/assets/_B6GPBTnX.js +1 -0
  30. package/dist/public/assets/{_qxffRpjc.js → _B7u83Fqc.js} +1 -1
  31. package/dist/public/assets/_B89z0EK7.js +1 -0
  32. package/dist/public/assets/{_C6Yt6h_R.js → _BCYHTWZd.js} +1 -1
  33. package/dist/public/assets/_BCYHTWZd.js.br +0 -0
  34. package/dist/public/assets/_BD01_px3.js +1 -0
  35. package/dist/public/assets/_BDt0PKxz.js +1 -0
  36. package/dist/public/assets/{_0sTkxfPx.js → _BFD3zDfn.js} +1 -1
  37. package/dist/public/assets/_BFD3zDfn.js.br +0 -0
  38. package/dist/public/assets/{_CBEKHwUV.js → _BH5TfgM7.js} +1 -1
  39. package/dist/public/assets/_BH5TfgM7.js.br +0 -0
  40. package/dist/public/assets/_BHEzkZBl.js +1 -0
  41. package/dist/public/assets/{_CB52LkYt.js → _BHxaJLxf.js} +1 -1
  42. package/dist/public/assets/_BHxaJLxf.js.br +0 -0
  43. package/dist/public/assets/{_D8ac72_O.js → _BJc28pt5.js} +1 -1
  44. package/dist/public/assets/_BJc28pt5.js.br +0 -0
  45. package/dist/public/assets/{_BBCzcNZY.js → _BJpqJK9r.js} +1 -1
  46. package/dist/public/assets/_BJpqJK9r.js.br +0 -0
  47. package/dist/public/assets/_BKSNShOz.js +1 -0
  48. package/dist/public/assets/{_DTNiWZFr.js → _BKcc-iTi.js} +1 -1
  49. package/dist/public/assets/_BKcc-iTi.js.br +0 -0
  50. package/dist/public/assets/{_CG383oZY.js → _BMXIDoUj.js} +1 -1
  51. package/dist/public/assets/_BMXIDoUj.js.br +0 -0
  52. package/dist/public/assets/{_CEC5O89D.js → _BQMwlV-0.js} +1 -1
  53. package/dist/public/assets/_BQMwlV-0.js.br +0 -0
  54. package/dist/public/assets/_BUjgl28E.js +1 -0
  55. package/dist/public/assets/_BYUg95ML.js +1 -0
  56. package/dist/public/assets/{_CspPbDoP.js → _B_LxZatx.js} +1 -1
  57. package/dist/public/assets/_B_LxZatx.js.br +0 -0
  58. package/dist/public/assets/{_CfP0f0PU.js → _BeQUut65.js} +1 -1
  59. package/dist/public/assets/_BeQUut65.js.br +0 -0
  60. package/dist/public/assets/{_DJBR8Qwq.js → _Bf7EsJwj.js} +1 -1
  61. package/dist/public/assets/_Bf7EsJwj.js.br +0 -0
  62. package/dist/public/assets/_BfVmvTXe.js +1 -0
  63. package/dist/public/assets/_BfqDnPV7.js +1 -0
  64. package/dist/public/assets/{_BdSsUhCi.js → _Bfuu6mAX.js} +1 -1
  65. package/dist/public/assets/_Bfuu6mAX.js.br +0 -0
  66. package/dist/public/assets/{_CPaMvBMG.js → _BgBUZElB.js} +1 -1
  67. package/dist/public/assets/_BgBUZElB.js.br +0 -0
  68. package/dist/public/assets/{_CToqok6Q.js → _Bgbj7Vl5.js} +1 -1
  69. package/dist/public/assets/_Bgbj7Vl5.js.br +0 -0
  70. package/dist/public/assets/{_J3wdy6bJ.js → _BhrCWDl2.js} +1 -1
  71. package/dist/public/assets/_BhrCWDl2.js.br +0 -0
  72. package/dist/public/assets/_Bjsevhjr.js +1 -0
  73. package/dist/public/assets/_BjzBYn47.js +1 -0
  74. package/dist/public/assets/_BmyB1F-C.js +1 -0
  75. package/dist/public/assets/{_bDI-pCZR.js → _BpGvpggY.js} +1 -1
  76. package/dist/public/assets/_BpGvpggY.js.br +0 -0
  77. package/dist/public/assets/_BpjknrsF.js +1 -0
  78. package/dist/public/assets/{_BClUYs-k.js → _BpunB-I_.js} +1 -1
  79. package/dist/public/assets/_BpunB-I_.js.br +0 -0
  80. package/dist/public/assets/{_DsehEuMD.js → _Bqgtb-fc.js} +1 -1
  81. package/dist/public/assets/_Bqgtb-fc.js.br +0 -0
  82. package/dist/public/assets/_BtkDWVh9.js +1 -0
  83. package/dist/public/assets/{_zN8SypHW.js → _BvEJgNLp.js} +1 -1
  84. package/dist/public/assets/_BvEJgNLp.js.br +0 -0
  85. package/dist/public/assets/_BvYgAZl3.js +1 -0
  86. package/dist/public/assets/_C0Bfz_Is.js +1 -0
  87. package/dist/public/assets/_C1Aa6bJ9.js +1 -0
  88. package/dist/public/assets/_C3i3LRNx.js +1 -0
  89. package/dist/public/assets/_C4RHKQLq.js +1 -0
  90. package/dist/public/assets/{_DN7pTn2g.js → _C5Wk6L8u.js} +1 -1
  91. package/dist/public/assets/_C5Wk6L8u.js.br +0 -0
  92. package/dist/public/assets/_C7N1s7w_.js +1 -0
  93. package/dist/public/assets/_C7N1s7w_.js.br +0 -0
  94. package/dist/public/assets/_C96lrIeU.js +1 -0
  95. package/dist/public/assets/{_CPj_VL66.js → _CAhkFk0k.js} +1 -1
  96. package/dist/public/assets/_CAhkFk0k.js.br +0 -0
  97. package/dist/public/assets/{_bHL-NcWS.js → _CCmHKlXX.js} +1 -1
  98. package/dist/public/assets/_CCmHKlXX.js.br +0 -0
  99. package/dist/public/assets/{_DpbHp8yR.js → _CEY_n10t.js} +1 -1
  100. package/dist/public/assets/_CEY_n10t.js.br +0 -0
  101. package/dist/public/assets/_CEejNMib.js +1 -0
  102. package/dist/public/assets/_CFo4GZR9.js +1 -0
  103. package/dist/public/assets/{_Cmtl59QM.js → _CGH2Busx.js} +1 -1
  104. package/dist/public/assets/_CGH2Busx.js.br +0 -0
  105. package/dist/public/assets/{_DuyCZnNC.js → _CHwp4prQ.js} +1 -1
  106. package/dist/public/assets/_CHwp4prQ.js.br +0 -0
  107. package/dist/public/assets/{_C_D5TPb7.js → _CN7Wz2eA.js} +1 -1
  108. package/dist/public/assets/_CN7Wz2eA.js.br +0 -0
  109. package/dist/public/assets/_CP58TjsV.js +1 -0
  110. package/dist/public/assets/_CP58TjsV.js.br +0 -0
  111. package/dist/public/assets/_CPruMiA4.js +1 -0
  112. package/dist/public/assets/_CQEZuOE_.js +1 -0
  113. package/dist/public/assets/_CSMoDPwM.js +16 -0
  114. package/dist/public/assets/_CSMoDPwM.js.br +0 -0
  115. package/dist/public/assets/{_briyaWgK.js → _CVEabnQh.js} +1 -1
  116. package/dist/public/assets/_CVEabnQh.js.br +0 -0
  117. package/dist/public/assets/{_J1v2clxU.js → _CWTelCGM.js} +1 -1
  118. package/dist/public/assets/_CWTelCGM.js.br +0 -0
  119. package/dist/public/assets/_CXpplsaj.js +1 -0
  120. package/dist/public/assets/{_BhecGD7y.js → _CY0xLX0Y.js} +1 -1
  121. package/dist/public/assets/_CY0xLX0Y.js.br +0 -0
  122. package/dist/public/assets/{_dVHSDgPC.js → _CZNztOn6.js} +1 -1
  123. package/dist/public/assets/_CZNztOn6.js.br +0 -0
  124. package/dist/public/assets/{_Dtx52FYB.js → _Cabq459u.js} +1 -1
  125. package/dist/public/assets/_Cb593OOX.js +1 -0
  126. package/dist/public/assets/_Cbis2WSl.js +1 -0
  127. package/dist/public/assets/{_T5HFHZgl.js → _CeZa36O-.js} +1 -1
  128. package/dist/public/assets/_CeZa36O-.js.br +0 -0
  129. package/dist/public/assets/{_CCoTlnvb.js → _ChTMXnIu.js} +1 -1
  130. package/dist/public/assets/_ChTMXnIu.js.br +0 -0
  131. package/dist/public/assets/_Cig63HLr.js +1 -0
  132. package/dist/public/assets/_CjkPh72t.js +1 -0
  133. package/dist/public/assets/_Cm6nigjK.js +1 -0
  134. package/dist/public/assets/_CnAEQUMb.js +1 -0
  135. package/dist/public/assets/{_uCKs5N6Q.js → _Coroy2lI.js} +1 -1
  136. package/dist/public/assets/_Coroy2lI.js.br +0 -0
  137. package/dist/public/assets/_CpAeLnqO.js +1 -0
  138. package/dist/public/assets/_CpAeLnqO.js.br +0 -0
  139. package/dist/public/assets/_Cpkby1iI.js +1 -0
  140. package/dist/public/assets/_Cs0Q8LaN.js +1 -0
  141. package/dist/public/assets/_Ct2pbvTU.js +1 -0
  142. package/dist/public/assets/{_DWb03VKf.js → _CtC83UyG.js} +1 -1
  143. package/dist/public/assets/_CtC83UyG.js.br +0 -0
  144. package/dist/public/assets/_CtVSUTWd.js +1 -0
  145. package/dist/public/assets/_Ctf0pL3c.js +1 -0
  146. package/dist/public/assets/_CtvMc-Fn.js +1 -0
  147. package/dist/public/assets/_Cv7TctYK.js +1 -0
  148. package/dist/public/assets/_Cv7TctYK.js.br +0 -0
  149. package/dist/public/assets/{_DmoI4cIl.js → _CvKDzuxc.js} +1 -1
  150. package/dist/public/assets/_CvKDzuxc.js.br +0 -0
  151. package/dist/public/assets/_CvxhsaLv.js +1 -0
  152. package/dist/public/assets/_CwxTh04m.js +1 -0
  153. package/dist/public/assets/_CyMRBJfa.js +1 -0
  154. package/dist/public/assets/{_CdtjIoUd.js → _D-wwbDX7.js} +1 -1
  155. package/dist/public/assets/_D-wwbDX7.js.br +0 -0
  156. package/dist/public/assets/_D02jmNge.js +1 -0
  157. package/dist/public/assets/{_C1RigMYD.js → _D0gWUr-E.js} +1 -1
  158. package/dist/public/assets/_D0gWUr-E.js.br +0 -0
  159. package/dist/public/assets/_D2wtQpHN.js +1 -0
  160. package/dist/public/assets/_D2wtQpHN.js.br +0 -0
  161. package/dist/public/assets/_D3uCXh8z.js +2 -0
  162. package/dist/public/assets/_D3uCXh8z.js.br +0 -0
  163. package/dist/public/assets/_D5GW0gg0.js +1 -0
  164. package/dist/public/assets/_D5GW0gg0.js.br +0 -0
  165. package/dist/public/assets/{_BmpOmFbo.js → _D6YVA8vA.js} +1 -1
  166. package/dist/public/assets/_D6YVA8vA.js.br +0 -0
  167. package/dist/public/assets/_D85prZ-z.js +1 -0
  168. package/dist/public/assets/_D8QlsPTv.js +1 -0
  169. package/dist/public/assets/_D8QlsPTv.js.br +0 -0
  170. package/dist/public/assets/_D8rDqOqJ.js +1 -0
  171. package/dist/public/assets/{_1M3oZPSf.js → _DAcmaIgY.js} +1 -1
  172. package/dist/public/assets/_DAcmaIgY.js.br +0 -0
  173. package/dist/public/assets/_DBlahxfT.js +1 -0
  174. package/dist/public/assets/_DCPGqAo6.js +1 -0
  175. package/dist/public/assets/{_MHZgY1AQ.js → _DDBuDrkA.js} +1 -1
  176. package/dist/public/assets/_DDBuDrkA.js.br +0 -0
  177. package/dist/public/assets/_DDfwtidv.js +1 -0
  178. package/dist/public/assets/_DDfwtidv.js.br +0 -0
  179. package/dist/public/assets/_DEqzNO7a.js +1 -0
  180. package/dist/public/assets/_DEyhBnnd.js +1 -0
  181. package/dist/public/assets/{_DYUFCi44.js → _DG1LpTGX.js} +1 -1
  182. package/dist/public/assets/_DG1LpTGX.js.br +0 -0
  183. package/dist/public/assets/_DJK-MioE.js +1 -0
  184. package/dist/public/assets/{_DDcVFyaQ.js → _DLCgfhNS.js} +1 -1
  185. package/dist/public/assets/_DLCgfhNS.js.br +0 -0
  186. package/dist/public/assets/_DLYvRpNz.js +6 -0
  187. package/dist/public/assets/_DLYvRpNz.js.br +0 -0
  188. package/dist/public/assets/_DPzjUc1B.js +1 -0
  189. package/dist/public/assets/_DRDW7RgT.js +1 -0
  190. package/dist/public/assets/{_CHmEM8Sm.js → _DSoJ6ck3.js} +1 -1
  191. package/dist/public/assets/_DSoJ6ck3.js.br +0 -0
  192. package/dist/public/assets/{_C3fslTAD.js → _DW92UwGh.js} +1 -1
  193. package/dist/public/assets/_DW92UwGh.js.br +0 -0
  194. package/dist/public/assets/{_Bcc0Xs64.js → _DYIjiPYY.js} +1 -1
  195. package/dist/public/assets/_DYIjiPYY.js.br +0 -0
  196. package/dist/public/assets/_DZeeRtLs.js +1 -0
  197. package/dist/public/assets/{_XsB9KmcW.js → _DZzucnmx.js} +1 -1
  198. package/dist/public/assets/_DZzucnmx.js.br +0 -0
  199. package/dist/public/assets/{_EcMqP1xI.js → _D_AjKzkm.js} +1 -1
  200. package/dist/public/assets/_D_AjKzkm.js.br +0 -0
  201. package/dist/public/assets/{_DYhs8iJg.js → _DdVG8Rbg.js} +116 -116
  202. package/dist/public/assets/_DdVG8Rbg.js.br +0 -0
  203. package/dist/public/assets/{_BH9BIky6.js → _DdcPtDZz.js} +1 -1
  204. package/dist/public/assets/_DdcPtDZz.js.br +0 -0
  205. package/dist/public/assets/{_-7Amnss4.js → _De_msLFQ.js} +1 -1
  206. package/dist/public/assets/_De_msLFQ.js.br +0 -0
  207. package/dist/public/assets/_DeiCZJcm.js +1 -0
  208. package/dist/public/assets/_DeiCZJcm.js.br +0 -0
  209. package/dist/public/assets/{_CL8DzBla.js → _DfNM5GDo.js} +1 -1
  210. package/dist/public/assets/_DfNM5GDo.js.br +0 -0
  211. package/dist/public/assets/{_C7Y4xApK.js → _Dg6OsRrR.js} +1 -1
  212. package/dist/public/assets/_Dg6OsRrR.js.br +0 -0
  213. package/dist/public/assets/_DgrmX7cI.js +1 -0
  214. package/dist/public/assets/_DiPK_ps-.js +1 -0
  215. package/dist/public/assets/{_DbT6uo7W.js → _Dow17jzJ.js} +1 -1
  216. package/dist/public/assets/_Dow17jzJ.js.br +0 -0
  217. package/dist/public/assets/{_BtedGrGs.js → _DpSZYTyI.js} +1 -1
  218. package/dist/public/assets/_DpSZYTyI.js.br +0 -0
  219. package/dist/public/assets/_DpXO9fPK.js +1 -0
  220. package/dist/public/assets/_DpXO9fPK.js.br +0 -0
  221. package/dist/public/assets/{_DzNFlI0M.js → _DqiBcDpF.js} +1 -1
  222. package/dist/public/assets/_DqiBcDpF.js.br +0 -0
  223. package/dist/public/assets/_DqkJjiCU.js +1 -0
  224. package/dist/public/assets/{_ahCaQNeo.js → _Draa__tn.js} +1 -1
  225. package/dist/public/assets/_Draa__tn.js.br +0 -0
  226. package/dist/public/assets/_Drs3T7dh.js +1 -0
  227. package/dist/public/assets/_Drs3T7dh.js.br +0 -0
  228. package/dist/public/assets/_DtBGe4AJ.js +1 -0
  229. package/dist/public/assets/{_Dw1P6xZJ.js → _DxSnjCPi.js} +1 -1
  230. package/dist/public/assets/_DxSnjCPi.js.br +0 -0
  231. package/dist/public/assets/{_B9I2AEux.js → _DyEhTpVE.js} +1 -1
  232. package/dist/public/assets/_DyEhTpVE.js.br +0 -0
  233. package/dist/public/assets/{_D3IviZbJ.js → _DyFcXAXE.js} +1 -1
  234. package/dist/public/assets/_DyFcXAXE.js.br +0 -0
  235. package/dist/public/assets/_FPItrlZz.js +1 -0
  236. package/dist/public/assets/{_UZAFx6D8.js → _HGP7qpI4.js} +1 -1
  237. package/dist/public/assets/_HGP7qpI4.js.br +0 -0
  238. package/dist/public/assets/{_DCrPsldZ.js → _L-b7Vsug.js} +1 -1
  239. package/dist/public/assets/_L-b7Vsug.js.br +0 -0
  240. package/dist/public/assets/{_Cl7LTITm.js → _LWpc-K1g.js} +1 -1
  241. package/dist/public/assets/_LWpc-K1g.js.br +0 -0
  242. package/dist/public/assets/{_C-DhXiEm.js → _MwkLbzHQ.js} +1 -1
  243. package/dist/public/assets/_MwkLbzHQ.js.br +0 -0
  244. package/dist/public/assets/_O4DIriLZ.js +1 -0
  245. package/dist/public/assets/{_YoXk_8Bl.js → _T0Ktx7Km.js} +1 -1
  246. package/dist/public/assets/_T0Ktx7Km.js.br +0 -0
  247. package/dist/public/assets/_T6O8KX0b.js +1 -0
  248. package/dist/public/assets/_TWZgGi12.js +1 -0
  249. package/dist/public/assets/{_C-BYkx5h.js → _UBgRR4E9.js} +1 -1
  250. package/dist/public/assets/_UBgRR4E9.js.br +0 -0
  251. package/dist/public/assets/_X3T0JcUM.js +87 -0
  252. package/dist/public/assets/_X3T0JcUM.js.br +0 -0
  253. package/dist/public/assets/_YtP2gTmD.js +1 -0
  254. package/dist/public/assets/{_BQW1kIop.js → __1UtPhZb.js} +1 -1
  255. package/dist/public/assets/__1UtPhZb.js.br +0 -0
  256. package/dist/public/assets/__WDcLOp3.js +1 -0
  257. package/dist/public/assets/{_CIfCdAzS.js → __cyNMcUU.js} +1 -1
  258. package/dist/public/assets/{_BPDSQUbl.js → _csFWQzWs.js} +1 -1
  259. package/dist/public/assets/_csFWQzWs.js.br +0 -0
  260. package/dist/public/assets/_eURsGF_D.js +1 -0
  261. package/dist/public/assets/_fEPizk9T.js +1 -0
  262. package/dist/public/assets/{_B9xuaMHt.js → _hC5RUmrf.js} +1 -1
  263. package/dist/public/assets/_hC5RUmrf.js.br +0 -0
  264. package/dist/public/assets/_hfgYVPfe.js +1 -0
  265. package/dist/public/assets/_i51v5tw8.js +1 -0
  266. package/dist/public/assets/{_CuglAToi.js → _k1uZxEJ-.js} +1 -1
  267. package/dist/public/assets/_k1uZxEJ-.js.br +0 -0
  268. package/dist/public/assets/_l4nNKr9o.js +1 -0
  269. package/dist/public/assets/{_D7qWWxdI.js → _lA6BOkV1.js} +1 -1
  270. package/dist/public/assets/_lA6BOkV1.js.br +0 -0
  271. package/dist/public/assets/_qyrPXpIj.js +1 -0
  272. package/dist/public/assets/{_Bt03HU8S.js → _sLUOjXIk.js} +1 -1
  273. package/dist/public/assets/{_G1BLeMns.js → _sjeWoc5X.js} +1 -1
  274. package/dist/public/assets/_sjeWoc5X.js.br +0 -0
  275. package/dist/public/assets/_tByKwKUc.js +1 -0
  276. package/dist/public/assets/{_G8KNSVdM.js → _tFVcmmKI.js} +1 -1
  277. package/dist/public/assets/_tFVcmmKI.js.br +0 -0
  278. package/dist/public/assets/{_Ctjz3BD9.js → _txvO7pXr.js} +1 -1
  279. package/dist/public/assets/_txvO7pXr.js.br +0 -0
  280. package/dist/public/assets/_um7Vy7NX.js +1 -0
  281. package/dist/public/assets/_veNUvOqP.js +1 -0
  282. package/dist/public/assets/{_DSCqWPO0.js → _w8hTnp0H.js} +1 -1
  283. package/dist/public/assets/_w8hTnp0H.js.br +0 -0
  284. package/dist/public/assets/_wGWNa6Sp.js +1 -0
  285. package/dist/public/assets/_wxbEv1JK.js +1 -0
  286. package/dist/public/assets/files-view-BOE5HTrF.js +2 -0
  287. package/dist/public/assets/manage-workspace-ClwsrQ4a.js +2 -0
  288. package/dist/public/assets/new-CJ6ZElay.js +1 -0
  289. package/dist/public/assets/new-workspace-DWSBO4Vx.js +2 -0
  290. package/dist/public/assets/review-view-DffAZHOz.js +2 -0
  291. package/dist/public/assets/settings-CJ6ZElay.js +1 -0
  292. package/dist/public/assets/settings-page-CYL_T3Vf.js +2 -0
  293. package/dist/public/assets/styles-taHUfRpm.css +1 -0
  294. package/dist/public/assets/styles-taHUfRpm.css.br +0 -0
  295. package/dist/public/assets/w-CJ6ZElay.js +1 -0
  296. package/dist/public/assets/w._-CJ6ZElay.js +1 -0
  297. package/dist/public/assets/w._-ChCIRlhY.js +1 -0
  298. package/dist/public/assets/w._-WsR2-skZ.js +1 -0
  299. package/package.json +1 -1
  300. package/dist/_L2HNAA_8.js +0 -2
  301. package/dist/__TCdgPY5.js +0 -173
  302. package/dist/public/assets/_-7Amnss4.js.br +0 -0
  303. package/dist/public/assets/_0XXNUttq.js +0 -1
  304. package/dist/public/assets/_0sTkxfPx.js.br +0 -0
  305. package/dist/public/assets/_0zzYbK0A.js +0 -1
  306. package/dist/public/assets/_1M3oZPSf.js.br +0 -0
  307. package/dist/public/assets/_2O5HnHht.js +0 -1
  308. package/dist/public/assets/_7WlUaJPH.js +0 -1
  309. package/dist/public/assets/_8Tr7ByPg.js +0 -1
  310. package/dist/public/assets/_9AXMmQSO.js +0 -1
  311. package/dist/public/assets/_B1VqbV-X.js +0 -1
  312. package/dist/public/assets/_B9I2AEux.js.br +0 -0
  313. package/dist/public/assets/_B9xuaMHt.js.br +0 -0
  314. package/dist/public/assets/_BAWjkhA8.js.br +0 -0
  315. package/dist/public/assets/_BBCzcNZY.js.br +0 -0
  316. package/dist/public/assets/_BBW2szHh.js +0 -1
  317. package/dist/public/assets/_BCP2Njnu.js +0 -1
  318. package/dist/public/assets/_BClUYs-k.js.br +0 -0
  319. package/dist/public/assets/_BDdZkZRc.js +0 -1
  320. package/dist/public/assets/_BDdZkZRc.js.br +0 -0
  321. package/dist/public/assets/_BEDmGSgS.js +0 -1
  322. package/dist/public/assets/_BEDmGSgS.js.br +0 -0
  323. package/dist/public/assets/_BH9BIky6.js.br +0 -0
  324. package/dist/public/assets/_BLdi8Ee5.js +0 -1
  325. package/dist/public/assets/_BPDSQUbl.js.br +0 -0
  326. package/dist/public/assets/_BQW1kIop.js.br +0 -0
  327. package/dist/public/assets/_BQeoUfFw.js +0 -1
  328. package/dist/public/assets/_BRzroLbh.js +0 -1
  329. package/dist/public/assets/_BSXsTYSe.js +0 -1
  330. package/dist/public/assets/_BTXDT3Na.js +0 -1
  331. package/dist/public/assets/_BXm4xeFI.js +0 -1
  332. package/dist/public/assets/_BY8UeogK.js +0 -1
  333. package/dist/public/assets/_BYpyhp64.js +0 -1
  334. package/dist/public/assets/_BYpyhp64.js.br +0 -0
  335. package/dist/public/assets/_B_Kz7LnY.js +0 -1
  336. package/dist/public/assets/_Bcc0Xs64.js.br +0 -0
  337. package/dist/public/assets/_BdSsUhCi.js.br +0 -0
  338. package/dist/public/assets/_BdaWssEH.js +0 -1
  339. package/dist/public/assets/_BhecGD7y.js.br +0 -0
  340. package/dist/public/assets/_Bj9dpPhN.js +0 -1
  341. package/dist/public/assets/_BjZqS7za.js +0 -1
  342. package/dist/public/assets/_BjZqS7za.js.br +0 -0
  343. package/dist/public/assets/_BkSUiyHK.js +0 -1
  344. package/dist/public/assets/_BlshXH2Y.js +0 -16
  345. package/dist/public/assets/_BlshXH2Y.js.br +0 -0
  346. package/dist/public/assets/_BmX-VP7w.js +0 -1
  347. package/dist/public/assets/_BmpOmFbo.js.br +0 -0
  348. package/dist/public/assets/_Bo6YntUl.js +0 -1
  349. package/dist/public/assets/_BprZx4vg.js +0 -2
  350. package/dist/public/assets/_BprZx4vg.js.br +0 -0
  351. package/dist/public/assets/_Bqm7OnIV.js +0 -1
  352. package/dist/public/assets/_BquBGUNK.js +0 -1
  353. package/dist/public/assets/_BquBGUNK.js.br +0 -0
  354. package/dist/public/assets/_BrB66aRZ.js +0 -1
  355. package/dist/public/assets/_BtedGrGs.js.br +0 -0
  356. package/dist/public/assets/_C-BYkx5h.js.br +0 -0
  357. package/dist/public/assets/_C-DhXiEm.js.br +0 -0
  358. package/dist/public/assets/_C-NBFnST.js +0 -1
  359. package/dist/public/assets/_C1RigMYD.js.br +0 -0
  360. package/dist/public/assets/_C2vRS-ES.js +0 -1
  361. package/dist/public/assets/_C3fslTAD.js.br +0 -0
  362. package/dist/public/assets/_C4EYjWGn.js +0 -1
  363. package/dist/public/assets/_C4EYjWGn.js.br +0 -0
  364. package/dist/public/assets/_C6Yt6h_R.js.br +0 -0
  365. package/dist/public/assets/_C7Y4xApK.js.br +0 -0
  366. package/dist/public/assets/_CB52LkYt.js.br +0 -0
  367. package/dist/public/assets/_CBEKHwUV.js.br +0 -0
  368. package/dist/public/assets/_CBSLBYQF.js +0 -1
  369. package/dist/public/assets/_CBgzBB_k.js +0 -1
  370. package/dist/public/assets/_CBgzBB_k.js.br +0 -0
  371. package/dist/public/assets/_CCoTlnvb.js.br +0 -0
  372. package/dist/public/assets/_CD26To-f.js +0 -1
  373. package/dist/public/assets/_CDyWgQ0v.js +0 -6
  374. package/dist/public/assets/_CDyWgQ0v.js.br +0 -0
  375. package/dist/public/assets/_CEC5O89D.js.br +0 -0
  376. package/dist/public/assets/_CF2kEAU7.js +0 -1
  377. package/dist/public/assets/_CFURqbmO.js +0 -1
  378. package/dist/public/assets/_CG383oZY.js.br +0 -0
  379. package/dist/public/assets/_CHNJosg3.js +0 -1
  380. package/dist/public/assets/_CHmEM8Sm.js.br +0 -0
  381. package/dist/public/assets/_CKyzH0fl.js +0 -1
  382. package/dist/public/assets/_CL8DzBla.js.br +0 -0
  383. package/dist/public/assets/_CNYS94C5.js +0 -1
  384. package/dist/public/assets/_CNhypHJN.js +0 -1
  385. package/dist/public/assets/_CO-FkxlA.js +0 -1
  386. package/dist/public/assets/_COiGBSpO.js +0 -1
  387. package/dist/public/assets/_COvolvRQ.js +0 -1
  388. package/dist/public/assets/_CPaMvBMG.js.br +0 -0
  389. package/dist/public/assets/_CPj_VL66.js.br +0 -0
  390. package/dist/public/assets/_CQJC8Vx4.js +0 -1
  391. package/dist/public/assets/_CRHNlzBC.js +0 -1
  392. package/dist/public/assets/_CToqok6Q.js.br +0 -0
  393. package/dist/public/assets/_CUFKkl0B.js +0 -1
  394. package/dist/public/assets/_CZsOUa-q.js +0 -1
  395. package/dist/public/assets/_C_D5TPb7.js.br +0 -0
  396. package/dist/public/assets/_CdHI48v6.js +0 -1
  397. package/dist/public/assets/_CdpmkkzR.js +0 -1
  398. package/dist/public/assets/_CdpmkkzR.js.br +0 -0
  399. package/dist/public/assets/_CdtjIoUd.js.br +0 -0
  400. package/dist/public/assets/_Ce9Tv01m.js +0 -1
  401. package/dist/public/assets/_CeC7Lv10.js +0 -1
  402. package/dist/public/assets/_CfP0f0PU.js.br +0 -0
  403. package/dist/public/assets/_Cg7DH3xk.js +0 -1
  404. package/dist/public/assets/_Cg7DH3xk.js.br +0 -0
  405. package/dist/public/assets/_CikNq0z8.js +0 -1
  406. package/dist/public/assets/_Cl7LTITm.js.br +0 -0
  407. package/dist/public/assets/_Cmtl59QM.js.br +0 -0
  408. package/dist/public/assets/_CshYq_Dp.js +0 -1
  409. package/dist/public/assets/_CspPbDoP.js.br +0 -0
  410. package/dist/public/assets/_Ctjz3BD9.js.br +0 -0
  411. package/dist/public/assets/_CuglAToi.js.br +0 -0
  412. package/dist/public/assets/_CwSoAVRN.js +0 -1
  413. package/dist/public/assets/_D0XQV-Hm.js +0 -1
  414. package/dist/public/assets/_D36PnqCD.js +0 -1
  415. package/dist/public/assets/_D36PnqCD.js.br +0 -0
  416. package/dist/public/assets/_D3IviZbJ.js.br +0 -0
  417. package/dist/public/assets/_D6rgUB9O.js +0 -1
  418. package/dist/public/assets/_D7qWWxdI.js.br +0 -0
  419. package/dist/public/assets/_D8ac72_O.js.br +0 -0
  420. package/dist/public/assets/_D9WWxrQR.js +0 -1
  421. package/dist/public/assets/_D9hI5dSA.js +0 -1
  422. package/dist/public/assets/_DCrPsldZ.js.br +0 -0
  423. package/dist/public/assets/_DDcVFyaQ.js.br +0 -0
  424. package/dist/public/assets/_DDhkKo8Q.js +0 -1
  425. package/dist/public/assets/_DJBR8Qwq.js.br +0 -0
  426. package/dist/public/assets/_DLpa6VYT.js +0 -1
  427. package/dist/public/assets/_DMqe6rR-.js +0 -1
  428. package/dist/public/assets/_DN7pTn2g.js.br +0 -0
  429. package/dist/public/assets/_DP8UuFuJ.js +0 -1
  430. package/dist/public/assets/_DQedUaqM.js +0 -1
  431. package/dist/public/assets/_DSCqWPO0.js.br +0 -0
  432. package/dist/public/assets/_DSeQngGR.js.br +0 -0
  433. package/dist/public/assets/_DTNiWZFr.js.br +0 -0
  434. package/dist/public/assets/_DThlusXY.js +0 -1
  435. package/dist/public/assets/_DUK16H19.js +0 -1
  436. package/dist/public/assets/_DUZ13t3U.js +0 -1
  437. package/dist/public/assets/_DWb03VKf.js.br +0 -0
  438. package/dist/public/assets/_DWsyhfgn.js +0 -1
  439. package/dist/public/assets/_DXuzYhW6.js +0 -1
  440. package/dist/public/assets/_DXyOzA2b.js +0 -1
  441. package/dist/public/assets/_DYUFCi44.js.br +0 -0
  442. package/dist/public/assets/_DYhs8iJg.js.br +0 -0
  443. package/dist/public/assets/_D__ojGam.js.br +0 -0
  444. package/dist/public/assets/_DaFI_W5D.js +0 -1
  445. package/dist/public/assets/_DbT6uo7W.js.br +0 -0
  446. package/dist/public/assets/_DhnT0cCE.js +0 -1
  447. package/dist/public/assets/_Dm9OGn2q.js +0 -1
  448. package/dist/public/assets/_DmkeGFoM.js +0 -1
  449. package/dist/public/assets/_DmoI4cIl.js.br +0 -0
  450. package/dist/public/assets/_DpbHp8yR.js.br +0 -0
  451. package/dist/public/assets/_Dqz_HBE1.js +0 -1
  452. package/dist/public/assets/_DsehEuMD.js.br +0 -0
  453. package/dist/public/assets/_DuEyirL6.js +0 -1
  454. package/dist/public/assets/_DuuloSIi.js +0 -1
  455. package/dist/public/assets/_DuyCZnNC.js.br +0 -0
  456. package/dist/public/assets/_Dw1P6xZJ.js.br +0 -0
  457. package/dist/public/assets/_DzNFlI0M.js.br +0 -0
  458. package/dist/public/assets/_EcMqP1xI.js.br +0 -0
  459. package/dist/public/assets/_G1BLeMns.js.br +0 -0
  460. package/dist/public/assets/_G8KNSVdM.js.br +0 -0
  461. package/dist/public/assets/_J1v2clxU.js.br +0 -0
  462. package/dist/public/assets/_J3wdy6bJ.js.br +0 -0
  463. package/dist/public/assets/_MHZgY1AQ.js.br +0 -0
  464. package/dist/public/assets/_NHTZitq1.js +0 -2
  465. package/dist/public/assets/_NHTZitq1.js.br +0 -0
  466. package/dist/public/assets/_PsuNqRL9.js +0 -86
  467. package/dist/public/assets/_PsuNqRL9.js.br +0 -0
  468. package/dist/public/assets/_T5HFHZgl.js.br +0 -0
  469. package/dist/public/assets/_UZAFx6D8.js.br +0 -0
  470. package/dist/public/assets/_XA8_RQXF.js +0 -1
  471. package/dist/public/assets/_XsB9KmcW.js.br +0 -0
  472. package/dist/public/assets/_YoXk_8Bl.js.br +0 -0
  473. package/dist/public/assets/_YubCdy3Z.js +0 -1
  474. package/dist/public/assets/_ahCaQNeo.js.br +0 -0
  475. package/dist/public/assets/_bDI-pCZR.js.br +0 -0
  476. package/dist/public/assets/_bHL-NcWS.js.br +0 -0
  477. package/dist/public/assets/_bqRzDYc8.js +0 -1
  478. package/dist/public/assets/_briyaWgK.js.br +0 -0
  479. package/dist/public/assets/_dVHSDgPC.js.br +0 -0
  480. package/dist/public/assets/_gkZjZ9I4.js +0 -1
  481. package/dist/public/assets/_plyCYAnN.js +0 -1
  482. package/dist/public/assets/_q0Z44mWJ.js +0 -1
  483. package/dist/public/assets/_q0Z44mWJ.js.br +0 -0
  484. package/dist/public/assets/_qAsGEOt5.js +0 -1
  485. package/dist/public/assets/_qAsGEOt5.js.br +0 -0
  486. package/dist/public/assets/_uCKs5N6Q.js.br +0 -0
  487. package/dist/public/assets/_utWnC80Q.js +0 -1
  488. package/dist/public/assets/_utvzcBHT.js +0 -1
  489. package/dist/public/assets/_v8WbCPI8.js +0 -1
  490. package/dist/public/assets/_yK4b_Bl5.js +0 -1
  491. package/dist/public/assets/_yoQW4BY5.js +0 -1
  492. package/dist/public/assets/_zB6USXHX.js +0 -1
  493. package/dist/public/assets/_zN8SypHW.js.br +0 -0
  494. package/dist/public/assets/files-view-Fl0rU3Ns.js +0 -2
  495. package/dist/public/assets/manage-workspace-DggRcsXf.js +0 -2
  496. package/dist/public/assets/new-C7NxTJAT.js +0 -1
  497. package/dist/public/assets/new-workspace-C0pw5Iz1.js +0 -2
  498. package/dist/public/assets/review-view-C4YQ0J-X.js +0 -2
  499. package/dist/public/assets/settings-C7NxTJAT.js +0 -1
  500. package/dist/public/assets/settings-page-Cl_1tWCv.js +0 -2
  501. package/dist/public/assets/styles-Vcsj4CA7.css +0 -1
  502. package/dist/public/assets/styles-Vcsj4CA7.css.br +0 -0
  503. package/dist/public/assets/w-C7NxTJAT.js +0 -1
  504. package/dist/public/assets/w._-BbFH2lR-.js +0 -1
  505. package/dist/public/assets/w._-C7NxTJAT.js +0 -1
  506. 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` and `work plan`, 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
@@ -0,0 +1,85 @@
1
+ // `work plan`: the phases a lead agent's fan-outs fall under, and a line
2
+ // of what it is doing as it goes (server/team.ts). It is what the team
3
+ // view draws over the groups — the job as the lead sees it — and nothing
4
+ // runs from it: the lead starts each phase's groups itself, with
5
+ // `work session fanout --phase`.
6
+
7
+ /** The session a command means: --session's, else this pane's own. */
8
+ function sessionId(ctx) {
9
+ const id = ctx.flag("--session") || process.env.WORK_SESSION_ID;
10
+ if (!id)
11
+ ctx.die(
12
+ "a plan is a session's: run this in one (WORK_SESSION_ID is unset) or pass --session <id>",
13
+ );
14
+ return id;
15
+ }
16
+
17
+ /** `--phase "Title"` or `--phase "Title: what it does"`. */
18
+ function phaseOf(text) {
19
+ const at = text.indexOf(":");
20
+ return at > 0
21
+ ? { title: text.slice(0, at).trim(), detail: text.slice(at + 1).trim() }
22
+ : { title: text.trim() };
23
+ }
24
+
25
+ export const commands = [
26
+ {
27
+ name: "plan",
28
+ summary: "a lead's phases and progress log, over its fan-outs",
29
+ help: `work plan [--json]
30
+ This session's plan: its phases, and the last lines it logged.
31
+ work plan new "<name>" --phase "<title>[: what it does]" [--phase …]
32
+ Start a plan (ending this session's last): the phases its fan-outs fall
33
+ under, in order. \`work session fanout --phase <title>\` files a group
34
+ under one; the user sees each phase's members and how far they are.
35
+ work plan log "<line>"
36
+ Say what you are doing, over the phases ("3 of 6 fixes pass;
37
+ reviewing them") — a narrator line, not a message to anyone.
38
+ work plan done
39
+ End the plan.`,
40
+ async run(ctx) {
41
+ const [verb, ...rest] = ctx.parse(["--phase", "--session"]);
42
+ const me = sessionId(ctx);
43
+ switch (verb) {
44
+ case undefined: {
45
+ const plan = await ctx.api.get(`/api/sessions/${me}/plan`);
46
+ return ctx.out(plan, (p) => {
47
+ if (!p) return console.log('no plan: `work plan new "<name>"`');
48
+ console.log(`${p.name}${p.done ? " (done)" : ""}`);
49
+ for (const ph of p.phases)
50
+ console.log(` ${ph.title}${ph.detail ? ` — ${ph.detail}` : ""}`);
51
+ for (const l of p.log) console.log(` · ${l.text}`);
52
+ });
53
+ }
54
+ case "new": {
55
+ const name = rest.join(" ").trim();
56
+ if (!name)
57
+ ctx.die('usage: work plan new "<name>" --phase "<title>" […]');
58
+ const plan = await ctx.api.post(`/api/sessions/${me}/plan`, {
59
+ name,
60
+ phases: ctx.flags("--phase").map(phaseOf),
61
+ });
62
+ return ctx.out(plan, (p) =>
63
+ console.log(
64
+ `plan "${p.name}": ${p.phases.map((x) => x.title).join(" → ") || "no phases"}`,
65
+ ),
66
+ );
67
+ }
68
+ case "log": {
69
+ const line = rest.join(" ").trim();
70
+ if (!line) ctx.die('usage: work plan log "<line>"');
71
+ await ctx.api.patch(`/api/sessions/${me}/plan`, { log: line });
72
+ return ctx.out({ logged: line }, () =>
73
+ console.log(`logged: ${line}`),
74
+ );
75
+ }
76
+ case "done": {
77
+ await ctx.api.patch(`/api/sessions/${me}/plan`, { done: true });
78
+ return ctx.out({ done: true }, () => console.log("plan done"));
79
+ }
80
+ default:
81
+ ctx.die(`no \`work plan ${verb}\` (see: work help plan)`);
82
+ }
83
+ },
84
+ },
85
+ ];
@@ -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.phase ? `[${g.phase}] ` : ""}${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,40 @@ 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>"] [--phase "<phase>"] [--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; --phase files the group under that phase of your
193
+ plan (\`work plan\`). For a quick sweep inside your own CLI, its own
194
+ subagents are cheaper: this is for other vendors, long work, or work the
195
+ user may want to watch.
196
+ work session team [--json]
197
+ This session's plan and groups: each member (its id, then its
198
+ session's), its state and its last line (what it is doing, or its
199
+ result).
200
+ work session retry <member>
201
+ Rerun a closed member in a fresh session: its group waits for it again.
202
+ work session skip <member>
203
+ Stop a member: a queued one never starts, a running one's session
204
+ closes; either way its group no longer waits on it.
117
205
  work session send <id> "<text>"|- [--no-reply]
118
206
  Message an agent session: typed in, headed with who it is from, once
119
207
  it is at its prompt — never into a turn under way, a question it asks,
@@ -121,13 +209,19 @@ work session send <id> "<text>"|- [--no-reply]
121
209
  unless --no-reply: the recipient's last message as that turn ends,
122
210
  typed into this session as a prompt of its own. End your turn to wait
123
211
  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).`,
212
+ work session wait [<id>|<group>...] [--any] [--timeout <seconds>]
213
+ Wait for the replies owed to this session (by those sessions or groups,
214
+ else by any), printing each as it comes; a reply printed here is not
215
+ typed in too. A group's come once all its members have answered, unless
216
+ --any: then whatever is in, as soon as anything is. Exits 124 if some
217
+ are still working after --timeout (${WAIT_S} s).
218
+ work session kill <id> [--keep-children] --yes
219
+ Close a session and the process in it, and the sessions it started
220
+ with theirs, unless --keep-children (they then stand on their own).
221
+ Whoever waits on a reply from one is told.
222
+ work session kill --done
223
+ Close now the sessions this one started that are done with (answered,
224
+ idle, not the user's): fan-out results stay in \`work session team\`.`,
131
225
  async run(ctx) {
132
226
  const [verb, ...rest] = ctx.parse([
133
227
  "--agent",
@@ -136,6 +230,11 @@ work session kill <id> --yes
136
230
  "--workspace",
137
231
  "--session",
138
232
  "--timeout",
233
+ "--topic",
234
+ "--repo",
235
+ "--count",
236
+ "--parallel",
237
+ "--phase",
139
238
  ]);
140
239
  switch (verb) {
141
240
  case undefined: {
@@ -182,17 +281,26 @@ work session kill <id> --yes
182
281
  }
183
282
  case "new": {
184
283
  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"))
284
+ const running = (await sessionsOf(ctx, ws.id)).filter(
285
+ (s) => s.phase !== "off",
286
+ );
287
+ if (running.length >= SESSION_CAP && !ctx.has("--force"))
187
288
  ctx.die(
188
- `${ws.name} already has ${existing.length} sessions: pass --force to start another`,
289
+ `${ws.name} already has ${running.length} sessions running: pass --force to start another (a group of them is \`work session fanout\`, which queues)`,
189
290
  );
190
291
  const agent = ctx.flag("--agent");
191
292
  const me = process.env.WORK_SESSION_ID;
192
293
  const prompt = await textOf(valueOf(ctx, "--prompt"));
294
+ const topic = ctx.flag("--topic");
295
+ const at = topic ? await topicDirs(ctx, topic, 1) : null;
193
296
  const created = await ctx.api.post(
194
297
  `/api/workspaces/${ws.id}/sessions`,
195
- { ...(agent ? { agent } : {}), ...(me ? { parent: me } : {}) },
298
+ {
299
+ ...(agent ? { agent } : {}),
300
+ ...(me ? { parent: me } : {}),
301
+ ...(at ? { dir: at.dirs[0] } : {}),
302
+ ...(ctx.has("--keep") ? { keep: true } : {}),
303
+ },
196
304
  );
197
305
  const title = ctx.flag("--title");
198
306
  if (title)
@@ -212,6 +320,7 @@ work session kill <id> --yes
212
320
  title: title || null,
213
321
  workspace: ws.id,
214
322
  parent: created.parent_id ?? null,
323
+ topic: topic ?? null,
215
324
  prompted: !!sent?.delivered,
216
325
  queued: sent?.queued ?? null,
217
326
  wantsReply: !!sent?.wantsReply,
@@ -219,7 +328,7 @@ work session kill <id> --yes
219
328
  };
220
329
  return ctx.out(out, (s) => {
221
330
  console.log(
222
- `started ${s.id} (${s.agent})${s.prompted ? " with its prompt" : ""}: [${s.title || s.agent}](${s.href})`,
331
+ `started ${s.id} (${s.agent})${s.prompted ? " with its prompt" : ""}${s.topic ? ` on topic ${s.topic}` : ""}: [${s.title || s.agent}](${s.href})`,
223
332
  );
224
333
  if (s.queued)
225
334
  console.log(`its prompt waits to be typed in: ${s.queued}`);
@@ -229,6 +338,94 @@ work session kill <id> --yes
229
338
  );
230
339
  });
231
340
  }
341
+ case "fanout": {
342
+ const me = sessionId(ctx);
343
+ const agents = ctx.flags("--agent");
344
+ if (!agents.length)
345
+ ctx.die(
346
+ 'usage: work session fanout --agent <id> [--agent <id>…] --prompt "<text>"|- [<item>…] (see: work help session)',
347
+ );
348
+ const prompt = await textOf(valueOf(ctx, "--prompt"));
349
+ if (!prompt) ctx.die("a fan-out needs a --prompt");
350
+ // A "-" is --prompt's stdin, not an item.
351
+ const items = rest.filter((i) => i !== "-");
352
+ const count = ctx.has("--count") ? Number(ctx.flag("--count")) : 1;
353
+ if (!Number.isInteger(count) || count < 1)
354
+ ctx.die("--count is a whole number of members per agent");
355
+ if (items.length && ctx.has("--count"))
356
+ ctx.die("--count or items, not both: items already say how many");
357
+ const parallel = ctx.has("--parallel")
358
+ ? Number(ctx.flag("--parallel"))
359
+ : undefined;
360
+ if (
361
+ parallel !== undefined &&
362
+ (!Number.isInteger(parallel) || parallel < 1)
363
+ )
364
+ ctx.die("--parallel is a whole number of members at once");
365
+ // Members in the server's order: by agent, then by item or number.
366
+ const total = new Set(agents).size * (items.length || count);
367
+ const topic = ctx.flag("--topic");
368
+ const at = topic ? await topicDirs(ctx, topic, total) : null;
369
+ const g = await ctx.api.post(`/api/sessions/${me}/groups`, {
370
+ title: ctx.flag("--title") ?? "",
371
+ prompt,
372
+ agents,
373
+ ...(items.length ? { items } : { count }),
374
+ ...(parallel ? { parallel } : {}),
375
+ ...(ctx.has("--phase") ? { phase: ctx.flag("--phase") } : {}),
376
+ fanIn: !ctx.has("--stream"),
377
+ closeDone: ctx.has("--close-done"),
378
+ keep: ctx.has("--keep"),
379
+ ...(at ? { dirs: at.dirs } : {}),
380
+ });
381
+ return ctx.out({ ...g, topics: at?.names ?? null }, (g) => {
382
+ console.log(
383
+ `fanned out ${g.id} "${g.title}": ${g.members.length} ${g.members.length === 1 ? "member" : "members"}, ${g.parallel} at a time`,
384
+ );
385
+ for (const m of g.members)
386
+ console.log(
387
+ ` ${ctx.pad(m.id, 10)} ${ctx.pad(m.agent, 8)} ${m.title}`,
388
+ );
389
+ if (at) for (const l of at.links) console.log(` review: ${l}`);
390
+ console.log(
391
+ g.fanIn
392
+ ? `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.`
393
+ : `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\`.`,
394
+ );
395
+ });
396
+ }
397
+ case "team": {
398
+ const me = sessionId(ctx);
399
+ const t = await ctx.api.get(`/api/sessions/${me}/team`);
400
+ return ctx.out(t, (t) => {
401
+ if (!t.plan && !t.groups.length)
402
+ return console.log(
403
+ "no plan or groups: `work session fanout` starts one",
404
+ );
405
+ if (t.plan) {
406
+ console.log(
407
+ `plan "${t.plan.name}"${t.plan.done ? " (done)" : ""}: ${t.plan.phases.map((p) => p.title).join(" → ") || "no phases"}`,
408
+ );
409
+ for (const l of t.plan.log) console.log(` · ${l.text}`);
410
+ }
411
+ for (const g of t.groups) printGroup(ctx, g);
412
+ });
413
+ }
414
+ case "retry":
415
+ case "skip": {
416
+ const [member] = rest;
417
+ if (!member) ctx.die(`usage: work session ${verb} <member>`);
418
+ await ctx.api.post(`/api/members/${member}/${verb}`);
419
+ return ctx.out(
420
+ { member, [verb === "retry" ? "retried" : "skipped"]: true },
421
+ () =>
422
+ console.log(
423
+ verb === "retry"
424
+ ? `queued ${member} again`
425
+ : `skipped ${member}`,
426
+ ),
427
+ );
428
+ }
232
429
  case "send": {
233
430
  const [id, ...words] = rest;
234
431
  const text = await textOf(words.join(" "));
@@ -248,8 +445,9 @@ work session kill <id> --yes
248
445
  const seconds = raw === undefined ? WAIT_S : Number(raw);
249
446
  if (!Number.isFinite(seconds) || seconds < 0)
250
447
  ctx.die("--timeout is a number of seconds");
448
+ const any = ctx.has("--any");
251
449
  const until = Date.now() + seconds * 1000;
252
- const body = rest.length ? { from: rest } : {};
450
+ const body = { ...(rest.length ? { from: rest } : {}), any };
253
451
  const replies = [];
254
452
  let owing = [];
255
453
  for (;;) {
@@ -258,6 +456,7 @@ work session kill <id> --yes
258
456
  if (!ctx.json) r.replies.forEach(printReply);
259
457
  owing = r.owing;
260
458
  if (!owing.length || Date.now() >= until) break;
459
+ if (any && replies.length) break;
261
460
  await new Promise((res) => setTimeout(res, POLL_MS));
262
461
  }
263
462
  if (ctx.json)
@@ -268,24 +467,61 @@ work session kill <id> --yes
268
467
  ? `nothing owed by ${rest.join(", ")}: a reply already typed in is in your prompt`
269
468
  : "no session owes this one a reply",
270
469
  );
271
- if (owing.length) {
470
+ if (owing.length && !(any && replies.length)) {
272
471
  ctx.warn(
273
472
  `still working: ${owing.map((o) => o.label).join(", ")} (wait again, or end your turn: the reply comes as a prompt)`,
274
473
  );
275
474
  process.exitCode = 124;
276
- }
475
+ } else if (owing.length && !ctx.json)
476
+ console.log(
477
+ `still working: ${owing.map((o) => o.label).join(", ")}`,
478
+ );
277
479
  return;
278
480
  }
279
481
  case "kill": {
482
+ if (ctx.has("--done")) {
483
+ const me = sessionId(ctx);
484
+ const { closed } = await ctx.api.post(
485
+ `/api/sessions/${me}/close-done`,
486
+ );
487
+ return ctx.out({ closed }, () =>
488
+ console.log(
489
+ closed
490
+ ? `closed ${closed} finished ${closed === 1 ? "session" : "sessions"}`
491
+ : "none of the sessions this one started is done with",
492
+ ),
493
+ );
494
+ }
280
495
  const [id] = rest;
281
- if (!id) ctx.die("usage: work session kill <id> --yes");
282
- if (!ctx.yes)
496
+ if (!id)
283
497
  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`,
498
+ "usage: work session kill <id> [--keep-children] --yes, or --done",
285
499
  );
286
- await ctx.api.del(`/api/sessions/${id}`);
287
- return ctx.out({ id, killed: true }, () =>
288
- console.log(`closed ${id}`),
500
+ const keep = ctx.has("--keep-children");
501
+ if (!ctx.yes) {
502
+ // Said before it happens: what else goes with it.
503
+ const { ws } = await ctx.resolveWorkspace(ctx.flag("--workspace"));
504
+ const list = await sessionsOf(ctx, ws.id);
505
+ const family = [id];
506
+ for (let i = 0; i < family.length; i++)
507
+ for (const s of list)
508
+ if (s.parent === family[i] && !family.includes(s.id))
509
+ family.push(s.id);
510
+ const others = keep ? 0 : family.length - 1;
511
+ ctx.die(
512
+ `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`,
513
+ );
514
+ }
515
+ const r = await ctx.api.del(
516
+ `/api/sessions/${id}${keep ? "?children=keep" : ""}`,
517
+ );
518
+ const closed = r?.closed ?? [id];
519
+ return ctx.out({ id, killed: true, closed }, () =>
520
+ console.log(
521
+ closed.length > 1
522
+ ? `closed ${id} and the sessions it started: ${closed.slice(1).join(", ")}`
523
+ : `closed ${id}`,
524
+ ),
289
525
  );
290
526
  }
291
527
  default:
package/bin/cli/topic.mjs CHANGED
@@ -170,65 +170,69 @@ 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;
220
223
  made.push({
224
+ topic: name,
221
225
  repo: repo.worktree,
222
226
  branch,
223
227
  path: dest,
224
228
  base: repo.base_branch,
225
229
  from: start,
226
230
  stacked,
227
- install,
231
+ install: installFor(dest),
228
232
  link: link(ws, repo, name),
229
233
  });
230
234
  }
231
- if (ctx.has("--install")) {
235
+ if (install) {
232
236
  for (const m of made) {
233
237
  if (!m.install) continue;
234
238
  ctx.log(`${m.repo}: ${m.install}`);
@@ -242,6 +246,25 @@ async function topicNew(ctx) {
242
246
  if (!m.installed) ctx.warn(`${m.repo}: \`${m.install}\` failed`);
243
247
  }
244
248
  }
249
+ return made;
250
+ }
251
+
252
+ /** The workspace, its repos, and the ones a command names (`--repo`, else
253
+ * the one the cwd is in): what `makeTopics` takes. */
254
+ export async function topicRepos(ctx) {
255
+ const { ws, repos } = await context(ctx, false);
256
+ return { ws, picked: pickRepos(ctx, ws, repos) };
257
+ }
258
+
259
+ async function topicNew(ctx) {
260
+ const [name] = ctx.parse(["--repo", "--from"]);
261
+ if (!name)
262
+ ctx.die("usage: work topic new <name> [--repo <repo>…] [--from <ref>]");
263
+ const { ws, picked } = await topicRepos(ctx);
264
+ const made = makeTopics(ctx, ws, picked, [name], {
265
+ from: ctx.has("--from") ? ctx.flag("--from") : null,
266
+ install: ctx.has("--install"),
267
+ }).map(({ topic: _, ...m }) => m);
245
268
  ctx.out(made, (rows) => {
246
269
  for (const m of rows) {
247
270
  console.log(`${m.repo}/ on ${m.branch}`);