@dylanpiercey/work 0.2.17 → 0.2.18
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.
- package/README.md +13 -0
- package/bin/cli/README.md +34 -0
- package/bin/cli/_progress.mjs +68 -0
- package/bin/cli/_repo.mjs +32 -0
- package/bin/cli/_target.mjs +49 -0
- package/bin/cli/agent.mjs +153 -0
- package/bin/cli/branches.mjs +79 -0
- package/bin/cli/config.mjs +175 -0
- package/bin/cli/host.mjs +142 -0
- package/bin/cli/lsp.mjs +117 -0
- package/bin/cli/notify.mjs +53 -0
- package/bin/cli/open.mjs +37 -0
- package/bin/cli/repo.mjs +98 -0
- package/bin/cli/session.mjs +167 -0
- package/bin/cli/skill.mjs +99 -0
- package/bin/cli/stack.mjs +51 -0
- package/bin/cli/status.mjs +86 -0
- package/bin/cli/topic.mjs +585 -0
- package/bin/cli/workspace.mjs +184 -0
- package/bin/work.mjs +402 -80
- package/dist/_BAJGOEa1.js +168 -0
- package/dist/{_Bj-WwfnW.js → _BlLEM8du.js} +76 -46
- package/dist/_t9VsALwo.js +2 -0
- package/dist/index.mjs +3550 -2616
- package/dist/public/assets/{_CXVkXsw1.js → _10dZ1R0m.js} +1 -1
- package/dist/public/assets/_10dZ1R0m.js.br +0 -0
- package/dist/public/assets/_1EPD0XJG.js +1 -0
- package/dist/public/assets/_1jA3fFvQ.js +1 -0
- package/dist/public/assets/{_DZanHI_X.js → _4Sj6a8Ya.js} +1 -1
- package/dist/public/assets/_4Sj6a8Ya.js.br +0 -0
- package/dist/public/assets/{_Quh6tl1u.js → _5tN48iuJ.js} +1 -1
- package/dist/public/assets/_5tN48iuJ.js.br +0 -0
- package/dist/public/assets/{_CYQ4srZb.js → _8_DzkMgB.js} +1 -1
- package/dist/public/assets/_8_DzkMgB.js.br +0 -0
- package/dist/public/assets/{_CxgPm_xy.js → _9JG-F3GR.js} +1 -1
- package/dist/public/assets/_9JG-F3GR.js.br +0 -0
- package/dist/public/assets/_9KUM3Nch.js +2 -0
- package/dist/public/assets/_9KUM3Nch.js.br +0 -0
- package/dist/public/assets/{_BoEcMQmX.js → _B-H6ABVZ.js} +1 -1
- package/dist/public/assets/_B-H6ABVZ.js.br +0 -0
- package/dist/public/assets/{_D-0pUYXq.js → _B-iOtMg6.js} +1 -1
- package/dist/public/assets/_B-iOtMg6.js.br +0 -0
- package/dist/public/assets/{_CJgqLdsx.js → _B0FhzjB2.js} +1 -1
- package/dist/public/assets/_B0FhzjB2.js.br +0 -0
- package/dist/public/assets/{_C1-Nli75.js → _B26gPL08.js} +1 -1
- package/dist/public/assets/_B26gPL08.js.br +0 -0
- package/dist/public/assets/{_BA-MNdjL.js → _B2DHvTZR.js} +1 -1
- package/dist/public/assets/{_vX9d6g5Y.js → _B3Z1kRpD.js} +1 -1
- package/dist/public/assets/_B3Z1kRpD.js.br +0 -0
- package/dist/public/assets/{_BfQeZPXW.js → _B3sH8Usv.js} +1 -1
- package/dist/public/assets/_B3sH8Usv.js.br +0 -0
- package/dist/public/assets/_B42hLH2K.js +1 -0
- package/dist/public/assets/{_CY_Z-kV5.js → _B4hn3NNW.js} +1 -1
- package/dist/public/assets/_B4hn3NNW.js.br +0 -0
- package/dist/public/assets/{_DK-MOyi_.js → _B5NleRC6.js} +1 -1
- package/dist/public/assets/_B5NleRC6.js.br +0 -0
- package/dist/public/assets/_B5fRGxPQ.js +1 -0
- package/dist/public/assets/_B5fRGxPQ.js.br +0 -0
- package/dist/public/assets/_B65yR5Ej.js +1 -0
- package/dist/public/assets/_B6Sh9WEH.js +1 -0
- package/dist/public/assets/{_C7bHTlG1.js → _B6VtVybz.js} +1 -1
- package/dist/public/assets/_B6VtVybz.js.br +0 -0
- package/dist/public/assets/_B7rJ4n9b.js +1 -0
- package/dist/public/assets/_B8M-AD29.js +1 -0
- package/dist/public/assets/{_BQEpu56f.js → _B8joFpf1.js} +1 -1
- package/dist/public/assets/_B8joFpf1.js.br +0 -0
- package/dist/public/assets/_B9nA-Uh1.js +1 -0
- package/dist/public/assets/_B9nA-Uh1.js.br +0 -0
- package/dist/public/assets/_BA6X_Aj6.js +1 -0
- package/dist/public/assets/_BBFJV2Bx.js +1 -0
- package/dist/public/assets/_BCW5GFMW.js +1 -0
- package/dist/public/assets/{_TynjiShF.js → _BD1SQU0V.js} +1 -1
- package/dist/public/assets/_BD1SQU0V.js.br +0 -0
- package/dist/public/assets/_BEpd9Y1R.js +1 -0
- package/dist/public/assets/_BEy7R4W_.js +1 -0
- package/dist/public/assets/_BFGJOHQb.js +1 -0
- package/dist/public/assets/{_BiY8chB-.js → _BI45WgW9.js} +1 -1
- package/dist/public/assets/_BI45WgW9.js.br +0 -0
- package/dist/public/assets/_BIKvQKWe.js +1 -0
- package/dist/public/assets/_BIPnL2aI.js +1 -0
- package/dist/public/assets/{_Dj5RDA5P.js → _BIUaA4Nl.js} +1 -1
- package/dist/public/assets/_BIUaA4Nl.js.br +0 -0
- package/dist/public/assets/{_Ch-UiovX.js → _BJpBnuvv.js} +1 -1
- package/dist/public/assets/_BJpBnuvv.js.br +0 -0
- package/dist/public/assets/{_0KruTMn9.js → _BLeLpnYL.js} +1 -1
- package/dist/public/assets/_BLeLpnYL.js.br +0 -0
- package/dist/public/assets/_BMb5ANTv.js +1 -0
- package/dist/public/assets/{_ChPy2IX4.js → _BSRsPQTe.js} +1 -1
- package/dist/public/assets/_BSRsPQTe.js.br +0 -0
- package/dist/public/assets/_BVuerXin.js +6 -0
- package/dist/public/assets/_BVuerXin.js.br +0 -0
- package/dist/public/assets/_BWV8aSlZ.js +1 -0
- package/dist/public/assets/{_Q5s6o5H4.js → _BXHggM8M.js} +1 -1
- package/dist/public/assets/_BXHggM8M.js.br +0 -0
- package/dist/public/assets/{_D8uBvHXU.js → _BXPUZfKX.js} +1 -1
- package/dist/public/assets/_BXPUZfKX.js.br +0 -0
- package/dist/public/assets/_BYebhygn.js +1 -0
- package/dist/public/assets/_BZgCxd-U.js +1 -0
- package/dist/public/assets/_BZgCxd-U.js.br +0 -0
- package/dist/public/assets/_B_W51WxU.js +1 -0
- package/dist/public/assets/_B_jFFNyT.js +1 -0
- package/dist/public/assets/_Ba9OQzPV.js +1 -0
- package/dist/public/assets/_Ba9OQzPV.js.br +0 -0
- package/dist/public/assets/_BayiY7GU.js +1 -0
- package/dist/public/assets/_BcDMeS82.js +1 -0
- package/dist/public/assets/_BdD1sZp_.js +1 -0
- package/dist/public/assets/_Bg_WwlL2.js +1 -0
- package/dist/public/assets/_BhHzv4g0.js +1 -0
- package/dist/public/assets/_BjEinMEe.js +1 -0
- package/dist/public/assets/_BjEinMEe.js.br +0 -0
- package/dist/public/assets/{_DPiemRX1.js → _BkGAUdMd.js} +1 -1
- package/dist/public/assets/_BkGAUdMd.js.br +0 -0
- package/dist/public/assets/{_FwFz43m8.js → _BkHLXMjq.js} +1 -1
- package/dist/public/assets/_BkHLXMjq.js.br +0 -0
- package/dist/public/assets/_BmSWsZvV.js +1 -0
- package/dist/public/assets/{_D_GeNCls.js → _Bn6y2_ex.js} +1 -1
- package/dist/public/assets/_Bn6y2_ex.js.br +0 -0
- package/dist/public/assets/_Bp2gqUaf.js +1 -0
- package/dist/public/assets/_Bs6oYKkD.js +1 -0
- package/dist/public/assets/{_CYhJ6ae-.js → _Bs_MPTBZ.js} +1 -1
- package/dist/public/assets/_Bs_MPTBZ.js.br +0 -0
- package/dist/public/assets/_Bt13j1ev.js +1 -0
- package/dist/public/assets/{_D-pUpBL1.js → _Bt4cxzaP.js} +1 -1
- package/dist/public/assets/_BwlnYt-t.js +1 -0
- package/dist/public/assets/_Bx9aUXTG.js +1 -0
- package/dist/public/assets/{_DUdEYxV0.js → _BxKDE6Ct.js} +1 -1
- package/dist/public/assets/_BxKDE6Ct.js.br +0 -0
- package/dist/public/assets/_BymFDqKj.js +1 -0
- package/dist/public/assets/{_i4iteLF8.js → _C-z8Ntse.js} +1 -1
- package/dist/public/assets/_C-z8Ntse.js.br +0 -0
- package/dist/public/assets/_C0XUbqWe.js +1 -0
- package/dist/public/assets/_C1upDwBv.js +1 -0
- package/dist/public/assets/_C3f4huqn.js +1 -0
- package/dist/public/assets/{_BHyWcuOR.js → _C46o3wQ8.js} +1 -1
- package/dist/public/assets/_C46o3wQ8.js.br +0 -0
- package/dist/public/assets/_C4_3qKLX.js +1 -0
- package/dist/public/assets/_C7tG4xwv.js +1 -0
- package/dist/public/assets/_C8LciIOa.js +1 -0
- package/dist/public/assets/{_zcAaK79d.js → _C9k00otG.js} +1 -1
- package/dist/public/assets/_C9k00otG.js.br +0 -0
- package/dist/public/assets/_CBG92pZO.js +1 -0
- package/dist/public/assets/_CBfI2lSr.js +1 -0
- package/dist/public/assets/{_BPNSknLT.js → _CFKwHn62.js} +1 -1
- package/dist/public/assets/_CFKwHn62.js.br +0 -0
- package/dist/public/assets/_CHDvRNgn.js +1 -0
- package/dist/public/assets/{_DVLNzEkW.js → _CIDjLk1A.js} +1 -1
- package/dist/public/assets/_CIDjLk1A.js.br +0 -0
- package/dist/public/assets/{_3fvr5bU1.js → _CLV83hY7.js} +1 -1
- package/dist/public/assets/_CLV83hY7.js.br +0 -0
- package/dist/public/assets/_CO8ZosDU.js +1 -0
- package/dist/public/assets/{_D4CkNo0r.js → _CPqT91JX.js} +1 -1
- package/dist/public/assets/_CPqT91JX.js.br +0 -0
- package/dist/public/assets/_CRZ03hrO.js +1 -0
- package/dist/public/assets/_CUKvJRmi.js +1 -0
- package/dist/public/assets/_CU_FKEsy.js +1 -0
- package/dist/public/assets/{_Do6b-nfX.js → _CUxBk_RE.js} +1 -1
- package/dist/public/assets/_CUxBk_RE.js.br +0 -0
- package/dist/public/assets/_CW_vyZfo.js +1 -0
- package/dist/public/assets/{_BOBYB-cj.js → _CX5VOdNU.js} +1 -1
- package/dist/public/assets/_CX5VOdNU.js.br +0 -0
- package/dist/public/assets/{_C5c3o9N3.js → _CYcgwayF.js} +1 -1
- package/dist/public/assets/_CYcgwayF.js.br +0 -0
- package/dist/public/assets/{_BXcMBVCY.js → _CZsqsL_m.js} +1 -1
- package/dist/public/assets/_CZsqsL_m.js.br +0 -0
- package/dist/public/assets/_C_a8QggH.js +1 -0
- package/dist/public/assets/_C_ymFHNL.js +1 -0
- package/dist/public/assets/_CaU4irFc.js +1 -0
- package/dist/public/assets/_Cb3fSi2R.js +1 -0
- package/dist/public/assets/{_DOKecL0e.js → _CcINcTUt.js} +1 -1
- package/dist/public/assets/_CcINcTUt.js.br +0 -0
- package/dist/public/assets/{_BTh4v5Tr.js → _CcflXOTj.js} +1 -1
- package/dist/public/assets/_CcflXOTj.js.br +0 -0
- package/dist/public/assets/{_DbLQjG4R.js → _Cfts4mFJ.js} +1 -1
- package/dist/public/assets/_Cfts4mFJ.js.br +0 -0
- package/dist/public/assets/{_v3HPnNBs.js → _ClHeQc6g.js} +1 -1
- package/dist/public/assets/_ClHeQc6g.js.br +0 -0
- package/dist/public/assets/_CnSlVcEh.js +1 -0
- package/dist/public/assets/_Co71-HWR.js +1 -0
- package/dist/public/assets/_CpEeHKyF.js +1 -0
- package/dist/public/assets/{_CNUs2Gqk.js → _CpVeIwQ4.js} +1 -1
- package/dist/public/assets/_CpVeIwQ4.js.br +0 -0
- package/dist/public/assets/{_Cc_GUPR4.js → _Cq4DpL3R.js} +1 -1
- package/dist/public/assets/_Cq4DpL3R.js.br +0 -0
- package/dist/public/assets/_CvxsvMFa.js +1 -0
- package/dist/public/assets/{_DorQTaAa.js → _Cwdn40Q2.js} +1 -1
- package/dist/public/assets/_Cwdn40Q2.js.br +0 -0
- package/dist/public/assets/_CzN0wC_5.js +16 -0
- package/dist/public/assets/_CzN0wC_5.js.br +0 -0
- package/dist/public/assets/_D3ieGLoq.js +1 -0
- package/dist/public/assets/_D4wF26fk.js +1 -0
- package/dist/public/assets/_D9a9nY1Q.js +1 -0
- package/dist/public/assets/{_CIWiehYG.js → _DB7_Yora.js} +1 -1
- package/dist/public/assets/_DB7_Yora.js.br +0 -0
- package/dist/public/assets/{_6klEiBhY.js → _DDWIDZyP.js} +1 -1
- package/dist/public/assets/_DDWIDZyP.js.br +0 -0
- package/dist/public/assets/{_Cwtn28hL.js → _DG3L8-RO.js} +1 -1
- package/dist/public/assets/_DG3L8-RO.js.br +0 -0
- package/dist/public/assets/{_BxS3xvmE.js → _DGRgLaG-.js} +1 -1
- package/dist/public/assets/_DGRgLaG-.js.br +0 -0
- package/dist/public/assets/{_pEUCjhqm.js → _DG_QOtsx.js} +1 -1
- package/dist/public/assets/_DG_QOtsx.js.br +0 -0
- package/dist/public/assets/{_BwSXxzqy.js → _DHYIZWev.js} +11 -11
- package/dist/public/assets/_DHYIZWev.js.br +0 -0
- package/dist/public/assets/{_BoTzWlXR.js → _DJwY_zBh.js} +1 -1
- package/dist/public/assets/_DJwY_zBh.js.br +0 -0
- package/dist/public/assets/{_C9jR1P3s.js → _DKlB-yMq.js} +1 -1
- package/dist/public/assets/_DKlB-yMq.js.br +0 -0
- package/dist/public/assets/{_DYqx8g78.js → _DMCVOg7x.js} +1 -1
- package/dist/public/assets/_DMCVOg7x.js.br +0 -0
- package/dist/public/assets/_DMXnrdYy.js +1 -0
- package/dist/public/assets/_DMXnrdYy.js.br +0 -0
- package/dist/public/assets/{_Di78jTI-.js → _DNrRZhO7.js} +1 -1
- package/dist/public/assets/_DNrRZhO7.js.br +0 -0
- package/dist/public/assets/_DPdb5l-Z.js +1 -0
- package/dist/public/assets/{_Depr5Jps.js → _DRpsUHP5.js} +1 -1
- package/dist/public/assets/_DRpsUHP5.js.br +0 -0
- package/dist/public/assets/{_BHgwN0LC.js → _DUH5o_iN.js} +1 -1
- package/dist/public/assets/_DUH5o_iN.js.br +0 -0
- package/dist/public/assets/{_-ycNE92Z.js → _DUmYv8Kf.js} +1 -1
- package/dist/public/assets/_DUmYv8Kf.js.br +0 -0
- package/dist/public/assets/{_CPbClwhX.js → _DXvsvUmJ.js} +1 -1
- package/dist/public/assets/_DXvsvUmJ.js.br +0 -0
- package/dist/public/assets/{_DqGOYRpi.js → _DYxQeog7.js} +1 -1
- package/dist/public/assets/_DYxQeog7.js.br +0 -0
- package/dist/public/assets/_DZIDdpeW.js +1 -0
- package/dist/public/assets/{_CCONYsJT.js → _DZqoQxTm.js} +1 -1
- package/dist/public/assets/_DZqoQxTm.js.br +0 -0
- package/dist/public/assets/_D_4RJnk0.js +2 -0
- package/dist/public/assets/_D_4RJnk0.js.br +0 -0
- package/dist/public/assets/_DclJXqwW.js +1 -0
- package/dist/public/assets/_Debmjz1c.js +1 -0
- package/dist/public/assets/_DeiCZCO_.js +1 -0
- package/dist/public/assets/{_yp48NYOW.js → _Df-N1G_n.js} +1 -1
- package/dist/public/assets/_Df-N1G_n.js.br +0 -0
- package/dist/public/assets/_Df_3rEok.js +86 -0
- package/dist/public/assets/_Df_3rEok.js.br +0 -0
- package/dist/public/assets/{_DO_4_u2Q.js → _Dh9434oc.js} +1 -1
- package/dist/public/assets/{_Dhn3A3KJ.js → _DjYscMjF.js} +1 -1
- package/dist/public/assets/_DjYscMjF.js.br +0 -0
- package/dist/public/assets/{_cyorvuL1.js → _Dku55Ypt.js} +1 -1
- package/dist/public/assets/_Dku55Ypt.js.br +0 -0
- package/dist/public/assets/_Dm8TVkBX.js +1 -0
- package/dist/public/assets/_DnUBW0Qq.js +1 -0
- package/dist/public/assets/_DoOPrRIy.js +1 -0
- package/dist/public/assets/_DqJvxlYV.js +1 -0
- package/dist/public/assets/_Drle66GA.js +1 -0
- package/dist/public/assets/_DtrvrAfl.js +1 -0
- package/dist/public/assets/{_B5JxE4Sx.js → _DwTaEsY5.js} +1 -1
- package/dist/public/assets/_DwTaEsY5.js.br +0 -0
- package/dist/public/assets/_Dypj9l-z.js +1 -0
- package/dist/public/assets/_DyvwMfCp.js +1 -0
- package/dist/public/assets/{_OpbuiQ7h.js → _GK8r-gEu.js} +1 -1
- package/dist/public/assets/_GK8r-gEu.js.br +0 -0
- package/dist/public/assets/{_BqWlTTxo.js → _HpxvfbM2.js} +1 -1
- package/dist/public/assets/_HpxvfbM2.js.br +0 -0
- package/dist/public/assets/{_CIrZGxEf.js → _RudCGuBM.js} +1 -1
- package/dist/public/assets/_RudCGuBM.js.br +0 -0
- package/dist/public/assets/_UbfI3k4y.js +1 -0
- package/dist/public/assets/{_A-jpjc8j.js → _WOU8TCkO.js} +1 -1
- package/dist/public/assets/_WOU8TCkO.js.br +0 -0
- package/dist/public/assets/{_C-lB_p3U.js → _XWw1j8vS.js} +1 -1
- package/dist/public/assets/_XWw1j8vS.js.br +0 -0
- package/dist/public/assets/{_BCB8LQS3.js → _YDyNvOET.js} +1 -1
- package/dist/public/assets/_YDyNvOET.js.br +0 -0
- package/dist/public/assets/{_DzlXwaiG.js → _f8D86HXZ.js} +1 -1
- package/dist/public/assets/_f8D86HXZ.js.br +0 -0
- package/dist/public/assets/{_BUW_V5kN.js → _hbXd8Ogo.js} +1 -1
- package/dist/public/assets/_hbXd8Ogo.js.br +0 -0
- package/dist/public/assets/{_CrlNjDih.js → _i6YkSowH.js} +1 -1
- package/dist/public/assets/_i6YkSowH.js.br +0 -0
- package/dist/public/assets/_k1ciacDf.js +1 -0
- package/dist/public/assets/_k6nXIP-i.js +1 -0
- package/dist/public/assets/_keX09TNx.js +1 -0
- package/dist/public/assets/{_Dwe1TUjY.js → _l9xpLTP_.js} +1 -1
- package/dist/public/assets/_l9xpLTP_.js.br +0 -0
- package/dist/public/assets/_n9Rb26YX.js +1 -0
- package/dist/public/assets/{_4_sKOYsy.js → _o8mJsMHw.js} +1 -1
- package/dist/public/assets/_o8mJsMHw.js.br +0 -0
- package/dist/public/assets/{_Ca2DTddL.js → _oVsjszGq.js} +1 -1
- package/dist/public/assets/_oVsjszGq.js.br +0 -0
- package/dist/public/assets/_pM8W420Q.js +1 -0
- package/dist/public/assets/{_C449plW0.js → _rv9KtZHz.js} +1 -1
- package/dist/public/assets/_rv9KtZHz.js.br +0 -0
- package/dist/public/assets/{_B19mS3yM.js → _sSKEak2x.js} +1 -1
- package/dist/public/assets/_sSKEak2x.js.br +0 -0
- package/dist/public/assets/_tJgkkxOD.js +1 -0
- package/dist/public/assets/_tJgkkxOD.js.br +0 -0
- package/dist/public/assets/_uP3LGOtV.js +1 -0
- package/dist/public/assets/{_BT7DMail.js → _vG7bXn-C.js} +1 -1
- package/dist/public/assets/_vG7bXn-C.js.br +0 -0
- package/dist/public/assets/{_BTWfPOi-.js → _vHqiFYsh.js} +1 -1
- package/dist/public/assets/_vHqiFYsh.js.br +0 -0
- package/dist/public/assets/_vXJ7nP0d.js +1 -0
- package/dist/public/assets/{_Dks8YY2K.js → _w-MAJku6.js} +1 -1
- package/dist/public/assets/_wvhU__5f.js +1 -0
- package/dist/public/assets/_xFMpRp_e.js +1 -0
- package/dist/public/assets/_yXimF5vw.js +1 -0
- package/dist/public/assets/files-view-BennlUmP.js +2 -0
- package/dist/public/assets/manage-workspace-CaESLJdc.js +2 -0
- package/dist/public/assets/new-BNH4m99d.js +1 -0
- package/dist/public/assets/new-workspace-CwiZjHNn.js +2 -0
- package/dist/public/assets/review-view-BdbMyVt7.js +2 -0
- package/dist/public/assets/settings-BNH4m99d.js +1 -0
- package/dist/public/assets/settings-page-CU3aC70Q.js +2 -0
- package/dist/public/assets/styles-ctr-Sxsj.css +1 -0
- package/dist/public/assets/styles-ctr-Sxsj.css.br +0 -0
- package/dist/public/assets/w-BNH4m99d.js +1 -0
- package/dist/public/assets/w._-BNH4m99d.js +1 -0
- package/dist/public/assets/w._-CLYxMMR4.js +1 -0
- package/dist/public/assets/w._-_w8eUYMy.js +1 -0
- package/dist/public/sw.js +11 -4
- package/dist/public/sw.js.br +0 -0
- package/lib/ports/url.d.mts +20 -0
- package/lib/ports/url.mjs +80 -0
- package/package.json +1 -1
- package/dist/_CLoLdV87.js +0 -2
- package/dist/_DPpY3UqO.js +0 -167
- package/dist/public/assets/_-ycNE92Z.js.br +0 -0
- package/dist/public/assets/_0KruTMn9.js.br +0 -0
- package/dist/public/assets/_0NH5yJMx.js +0 -1
- package/dist/public/assets/_1CAp-NbR.js +0 -1
- package/dist/public/assets/_3fvr5bU1.js.br +0 -0
- package/dist/public/assets/_4Dkmi0BI.js +0 -1
- package/dist/public/assets/_4_sKOYsy.js.br +0 -0
- package/dist/public/assets/_6klEiBhY.js.br +0 -0
- package/dist/public/assets/_7_64OpLh.js +0 -1
- package/dist/public/assets/_7p-zxUs0.js +0 -1
- package/dist/public/assets/_8RAv3gFP.js +0 -1
- package/dist/public/assets/_9PDxaMA9.js +0 -1
- package/dist/public/assets/_9PDxaMA9.js.br +0 -0
- package/dist/public/assets/_9mbDrbe7.js +0 -1
- package/dist/public/assets/_A-jpjc8j.js.br +0 -0
- package/dist/public/assets/_B0JwTeu6.js +0 -1
- package/dist/public/assets/_B19mS3yM.js.br +0 -0
- package/dist/public/assets/_B1Sfrnda.js +0 -1
- package/dist/public/assets/_B3i0wS_I.js +0 -1
- package/dist/public/assets/_B5JxE4Sx.js.br +0 -0
- package/dist/public/assets/_B9RLcC8I.js +0 -1
- package/dist/public/assets/_BCB8LQS3.js.br +0 -0
- package/dist/public/assets/_BE7UYyYb.js +0 -1
- package/dist/public/assets/_BHgwN0LC.js.br +0 -0
- package/dist/public/assets/_BHyWcuOR.js.br +0 -0
- package/dist/public/assets/_BIpUDgQH.js +0 -16
- package/dist/public/assets/_BIpUDgQH.js.br +0 -0
- package/dist/public/assets/_BMlgaRlM.js +0 -1
- package/dist/public/assets/_BOBYB-cj.js.br +0 -0
- package/dist/public/assets/_BPNSknLT.js.br +0 -0
- package/dist/public/assets/_BQEpu56f.js.br +0 -0
- package/dist/public/assets/_BT7DMail.js.br +0 -0
- package/dist/public/assets/_BTJHQNIz.js +0 -1
- package/dist/public/assets/_BTWfPOi-.js.br +0 -0
- package/dist/public/assets/_BTh4v5Tr.js.br +0 -0
- package/dist/public/assets/_BUW_V5kN.js.br +0 -0
- package/dist/public/assets/_BXcMBVCY.js.br +0 -0
- package/dist/public/assets/_B_MtJKnj.js +0 -1
- package/dist/public/assets/_Bay3D1io.js +0 -1
- package/dist/public/assets/_BfQeZPXW.js.br +0 -0
- package/dist/public/assets/_BgKjJWz_.js +0 -1
- package/dist/public/assets/_BiY8chB-.js.br +0 -0
- package/dist/public/assets/_Bk5THQZb.js +0 -1
- package/dist/public/assets/_BmeQRnXS.js +0 -1
- package/dist/public/assets/_BoEcMQmX.js.br +0 -0
- package/dist/public/assets/_BoTzWlXR.js.br +0 -0
- package/dist/public/assets/_BqWlTTxo.js.br +0 -0
- package/dist/public/assets/_BuMTHEPk.js +0 -1
- package/dist/public/assets/_BuMTHEPk.js.br +0 -0
- package/dist/public/assets/_BubhcEjq.js +0 -1
- package/dist/public/assets/_BwSXxzqy.js.br +0 -0
- package/dist/public/assets/_BxS3xvmE.js.br +0 -0
- package/dist/public/assets/_ByvA6zJz.js +0 -1
- package/dist/public/assets/_Bz2Sejcy.js +0 -1
- package/dist/public/assets/_C-lB_p3U.js.br +0 -0
- package/dist/public/assets/_C1-Nli75.js.br +0 -0
- package/dist/public/assets/_C3mw4T_r.js +0 -1
- package/dist/public/assets/_C449plW0.js.br +0 -0
- package/dist/public/assets/_C5c3o9N3.js.br +0 -0
- package/dist/public/assets/_C7bHTlG1.js.br +0 -0
- package/dist/public/assets/_C8mt6nRC.js +0 -1
- package/dist/public/assets/_C9jR1P3s.js.br +0 -0
- package/dist/public/assets/_CCONYsJT.js.br +0 -0
- package/dist/public/assets/_CCZAROAW.js +0 -1
- package/dist/public/assets/_CCZAROAW.js.br +0 -0
- package/dist/public/assets/_CG3s9pE5.js +0 -1
- package/dist/public/assets/_CIWiehYG.js.br +0 -0
- package/dist/public/assets/_CIrZGxEf.js.br +0 -0
- package/dist/public/assets/_CIurl9jC.js +0 -1
- package/dist/public/assets/_CJgqLdsx.js.br +0 -0
- package/dist/public/assets/_CMbVHIgP.js +0 -1
- package/dist/public/assets/_CNUs2Gqk.js.br +0 -0
- package/dist/public/assets/_CPbClwhX.js.br +0 -0
- package/dist/public/assets/_CQUlxerJ.js +0 -1
- package/dist/public/assets/_CTDYlYHi.js +0 -1
- package/dist/public/assets/_CXVkXsw1.js.br +0 -0
- package/dist/public/assets/_CY5EBxZ6.js +0 -1
- package/dist/public/assets/_CYQ4srZb.js.br +0 -0
- package/dist/public/assets/_CY_Z-kV5.js.br +0 -0
- package/dist/public/assets/_CYhJ6ae-.js.br +0 -0
- package/dist/public/assets/_CZbVK94d.js +0 -1
- package/dist/public/assets/_C_A97h_2.js +0 -1
- package/dist/public/assets/_C_A97h_2.js.br +0 -0
- package/dist/public/assets/_C_Y5Dwzy.js +0 -1
- package/dist/public/assets/_Ca2DTddL.js.br +0 -0
- package/dist/public/assets/_Cc2nu3_5.js +0 -1
- package/dist/public/assets/_Cc_GUPR4.js.br +0 -0
- package/dist/public/assets/_CgFUs0bE.js +0 -1
- package/dist/public/assets/_Ch-UiovX.js.br +0 -0
- package/dist/public/assets/_ChDp0-FJ.js +0 -1
- package/dist/public/assets/_ChPy2IX4.js.br +0 -0
- package/dist/public/assets/_Chsgo2e1.js +0 -1
- package/dist/public/assets/_CjECwrWB.js +0 -1
- package/dist/public/assets/_CmW74dH7.js +0 -1
- package/dist/public/assets/_CmhAUlqu.js +0 -1
- package/dist/public/assets/_CrlNjDih.js.br +0 -0
- package/dist/public/assets/_CvzTEaQq.js +0 -1
- package/dist/public/assets/_Cw-dmwPJ.js +0 -86
- package/dist/public/assets/_Cw-dmwPJ.js.br +0 -0
- package/dist/public/assets/_Cwtn28hL.js.br +0 -0
- package/dist/public/assets/_CxHuLHdz.js +0 -1
- package/dist/public/assets/_CxgPm_xy.js.br +0 -0
- package/dist/public/assets/_D-0pUYXq.js.br +0 -0
- package/dist/public/assets/_D-rV-z_T.js +0 -1
- package/dist/public/assets/_D4CkNo0r.js.br +0 -0
- package/dist/public/assets/_D4fP_viq.js +0 -1
- package/dist/public/assets/_D570Sd6p.js +0 -1
- package/dist/public/assets/_D6Gudpw8.js +0 -1
- package/dist/public/assets/_D8ZTP1ck.js +0 -1
- package/dist/public/assets/_D8uBvHXU.js.br +0 -0
- package/dist/public/assets/_D8xGEGlm.js +0 -1
- package/dist/public/assets/_D9GZHKow.js +0 -1
- package/dist/public/assets/_DE0eZjad.js +0 -1
- package/dist/public/assets/_DElIEG9n.js +0 -1
- package/dist/public/assets/_DF0n9xzn.js +0 -2
- package/dist/public/assets/_DF0n9xzn.js.br +0 -0
- package/dist/public/assets/_DFX_tXcw.js +0 -1
- package/dist/public/assets/_DJ2gfhU_.js +0 -1
- package/dist/public/assets/_DK-MOyi_.js.br +0 -0
- package/dist/public/assets/_DOKecL0e.js.br +0 -0
- package/dist/public/assets/_DPXXIOLX.js +0 -1
- package/dist/public/assets/_DPb3t58B.js +0 -1
- package/dist/public/assets/_DPiemRX1.js.br +0 -0
- package/dist/public/assets/_DPpbgqBC.js +0 -1
- package/dist/public/assets/_DRVSLjxA.js +0 -1
- package/dist/public/assets/_DTHWnu6M.js +0 -1
- package/dist/public/assets/_DUdEYxV0.js.br +0 -0
- package/dist/public/assets/_DVLNzEkW.js.br +0 -0
- package/dist/public/assets/_DWpx2Uof.js +0 -1
- package/dist/public/assets/_DXYEUAmC.js +0 -1
- package/dist/public/assets/_DYTVambU.js +0 -1
- package/dist/public/assets/_DYqx8g78.js.br +0 -0
- package/dist/public/assets/_DZanHI_X.js.br +0 -0
- package/dist/public/assets/_D_GeNCls.js.br +0 -0
- package/dist/public/assets/_DbLQjG4R.js.br +0 -0
- package/dist/public/assets/_DbmusecK.js +0 -1
- package/dist/public/assets/_DbmusecK.js.br +0 -0
- package/dist/public/assets/_DemN-D5U.js +0 -1
- package/dist/public/assets/_Depr5Jps.js.br +0 -0
- package/dist/public/assets/_DhJfHI4f.js +0 -1
- package/dist/public/assets/_Dhn3A3KJ.js.br +0 -0
- package/dist/public/assets/_Di78jTI-.js.br +0 -0
- package/dist/public/assets/_DiBTtPlu.js +0 -1
- package/dist/public/assets/_Dj5RDA5P.js.br +0 -0
- package/dist/public/assets/_DkjKARSS.js +0 -1
- package/dist/public/assets/_Do6b-nfX.js.br +0 -0
- package/dist/public/assets/_DorQTaAa.js.br +0 -0
- package/dist/public/assets/_DpxVmwni.js +0 -1
- package/dist/public/assets/_DqGOYRpi.js.br +0 -0
- package/dist/public/assets/_DsbxQ1i8.js +0 -1
- package/dist/public/assets/_Dt_P7K1V.js +0 -6
- package/dist/public/assets/_Dt_P7K1V.js.br +0 -0
- package/dist/public/assets/_Dwe1TUjY.js.br +0 -0
- package/dist/public/assets/_DyROQKS8.js +0 -1
- package/dist/public/assets/_DzEUPsq0.js +0 -1
- package/dist/public/assets/_DzlXwaiG.js.br +0 -0
- package/dist/public/assets/_FwFz43m8.js.br +0 -0
- package/dist/public/assets/_OpbuiQ7h.js.br +0 -0
- package/dist/public/assets/_Q5s6o5H4.js.br +0 -0
- package/dist/public/assets/_Quh6tl1u.js.br +0 -0
- package/dist/public/assets/_Rh99sjDe.js +0 -1
- package/dist/public/assets/_SEE1XtID.js +0 -1
- package/dist/public/assets/_SZjr1kid.js +0 -1
- package/dist/public/assets/_T7rMqM5P.js +0 -1
- package/dist/public/assets/_TynjiShF.js.br +0 -0
- package/dist/public/assets/_UENAEFcY.js +0 -1
- package/dist/public/assets/_UwTOb1gP.js +0 -1
- package/dist/public/assets/_WrxtT1Ok.js +0 -1
- package/dist/public/assets/_WrxtT1Ok.js.br +0 -0
- package/dist/public/assets/_bcvRRCkB.js +0 -1
- package/dist/public/assets/_cyorvuL1.js.br +0 -0
- package/dist/public/assets/_gi--JOq8.js +0 -1
- package/dist/public/assets/_i4iteLF8.js.br +0 -0
- package/dist/public/assets/_i7vMugBN.js +0 -1
- package/dist/public/assets/_j7jPRUEQ.js +0 -2
- package/dist/public/assets/_j7jPRUEQ.js.br +0 -0
- package/dist/public/assets/_pEUCjhqm.js.br +0 -0
- package/dist/public/assets/_qkJuNTl-.js +0 -1
- package/dist/public/assets/_uuZJDLIV.js +0 -1
- package/dist/public/assets/_v3HPnNBs.js.br +0 -0
- package/dist/public/assets/_vX9d6g5Y.js.br +0 -0
- package/dist/public/assets/_vhysM7gk.js +0 -1
- package/dist/public/assets/_vjwPQHk_.js +0 -1
- package/dist/public/assets/_yp48NYOW.js.br +0 -0
- package/dist/public/assets/_zcAaK79d.js.br +0 -0
- package/dist/public/assets/_zwPrEKxN.js +0 -1
- package/dist/public/assets/_zwPrEKxN.js.br +0 -0
- package/dist/public/assets/files-view-CzRAql9-.js +0 -2
- package/dist/public/assets/manage-workspace-C-c1R4pP.js +0 -2
- package/dist/public/assets/new-DWfNwssk.js +0 -1
- package/dist/public/assets/new-workspace-B8XAfkIH.js +0 -2
- package/dist/public/assets/review-view-DivHZNBf.js +0 -2
- package/dist/public/assets/settings-DWfNwssk.js +0 -1
- package/dist/public/assets/settings-page-BN9Hj1ui.js +0 -2
- package/dist/public/assets/styles-NmwxQh5L.css +0 -1
- package/dist/public/assets/styles-NmwxQh5L.css.br +0 -0
- package/dist/public/assets/w-DWfNwssk.js +0 -1
- package/dist/public/assets/w._-C9dj1aZ0.js +0 -1
- package/dist/public/assets/w._-D7_D4HlM.js +0 -1
- package/dist/public/assets/w._-DWfNwssk.js +0 -1
package/bin/work.mjs
CHANGED
|
@@ -6,17 +6,26 @@
|
|
|
6
6
|
// it otherwise offers when Tailscale is logged in; --no-tailscale skips that;
|
|
7
7
|
// --firewall adds a `work` rule for direct connections' UDP port to a host
|
|
8
8
|
// firewall that may drop it, or on macOS lets the service's node in,
|
|
9
|
-
// which it otherwise offers; --no-firewall skips that
|
|
9
|
+
// which it otherwise offers; --no-firewall skips that;
|
|
10
|
+
// --allow-host <name> / --disallow-host <name>, repeated, put one name
|
|
11
|
+
// in or out of WORK_ALLOWED_HOSTS and keep the rest; --json prints
|
|
12
|
+
// what it did as JSON on stdout, its progress on stderr)
|
|
10
13
|
// work doctor report machine readiness (--json, --fix to install what's missing)
|
|
11
14
|
// work start run the server in the foreground
|
|
12
|
-
// work update upgrade the npm package and refresh the service
|
|
15
|
+
// work update upgrade the npm package and refresh the service (--yes, --json as setup's)
|
|
13
16
|
// work usage print agent plan/quota usage
|
|
14
17
|
// work workspaces list workspaces (name, branch, sessions, ports)
|
|
15
|
-
// work workspace [id|name] one workspace: repos, PRs, sessions, procs (default: the current one
|
|
18
|
+
// work workspace [id|name] one workspace: repos, PRs, sessions, procs (default: the current one;
|
|
19
|
+
// --fresh asks GitHub again rather than the PR cache, ~2 min old)
|
|
16
20
|
// work repos [id|name] a workspace's repos with base branch and open PRs
|
|
17
|
-
// work procs [id|name] a workspace's running processes and ports
|
|
18
|
-
//
|
|
19
|
-
//
|
|
21
|
+
// work procs [id|name] a workspace's running processes and ports, each port with
|
|
22
|
+
// the link that opens it from the user's browser (through the
|
|
23
|
+
// address it last reached work by)
|
|
24
|
+
// work review [id|name] pending review comments as markdown (--json for rows;
|
|
25
|
+
// --take also clears exactly those from the review, as its
|
|
26
|
+
// Send does, once acted on, so a later Send cannot repeat them)
|
|
27
|
+
// work export [file] write a backup manifest (workspaces, settings, skills, tool pins;
|
|
28
|
+
// --json says what it wrote)
|
|
20
29
|
// work restore <file> bring a manifest's workspaces and machine setup back (--yes to run;
|
|
21
30
|
// --allow <spec|host>, repeated, for each tool outside work's catalog
|
|
22
31
|
// or new GitHub host it names — skipped otherwise)
|
|
@@ -26,7 +35,13 @@
|
|
|
26
35
|
//
|
|
27
36
|
// The read commands ask the running server (same data as the UI) and take
|
|
28
37
|
// --json for machine-readable output — agents inside a workspace should
|
|
29
|
-
// use them instead of poking at the filesystem or GitHub.
|
|
38
|
+
// use them instead of poking at the filesystem or GitHub. Nothing prompts
|
|
39
|
+
// under --json, --non-interactive or WORK_NONINTERACTIVE=1: a question is
|
|
40
|
+
// answered no, as --yes answers setup's optional ones.
|
|
41
|
+
//
|
|
42
|
+
// Commands beyond these live one file each under bin/cli/ (a file there
|
|
43
|
+
// exports `commands`; see bin/cli/README.md), found at run time, and
|
|
44
|
+
// `work help` lists them all: this header's own lines, then theirs.
|
|
30
45
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
31
46
|
import fs from "node:fs";
|
|
32
47
|
import os from "node:os";
|
|
@@ -55,6 +70,7 @@ import { dialHost, listenStream } from "../lib/setup/listen.mjs";
|
|
|
55
70
|
import { commentMarkdown } from "../lib/review/markdown.mjs";
|
|
56
71
|
import { formatInvite, parseInvite } from "../lib/share/manifest.mjs";
|
|
57
72
|
import { duration, pctText } from "../lib/usage/format.mjs";
|
|
73
|
+
import { locOf, portBlockedAt, portUrlAt } from "../lib/ports/url.mjs";
|
|
58
74
|
|
|
59
75
|
const pkgRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
60
76
|
const pkg = JSON.parse(
|
|
@@ -63,7 +79,10 @@ const pkg = JSON.parse(
|
|
|
63
79
|
const distEntry = path.join(pkgRoot, "dist", "index.mjs");
|
|
64
80
|
const appPort = process.env.WORK_APP_PORT || "7171";
|
|
65
81
|
|
|
66
|
-
|
|
82
|
+
// Under --json, stdout is the JSON alone: what a command says along the
|
|
83
|
+
// way goes to stderr.
|
|
84
|
+
const log = (msg) => (jsonOut ? console.error : console.log)(`==> ${msg}`);
|
|
85
|
+
const say = (msg) => (jsonOut ? console.error : console.log)(msg);
|
|
67
86
|
const warn = (msg) => console.warn(`warning: ${msg}`);
|
|
68
87
|
const die = (msg) => {
|
|
69
88
|
console.error(`error: ${msg}`);
|
|
@@ -79,6 +98,12 @@ const sh = (cmd, args, opts = {}) =>
|
|
|
79
98
|
const [, , command = "help", ...args] = process.argv;
|
|
80
99
|
const yes = args.includes("--yes") || args.includes("-y");
|
|
81
100
|
const jsonOut = args.includes("--json");
|
|
101
|
+
/** Whether a question may be asked at all: an agent's shell often has a
|
|
102
|
+
* controlling terminal it cannot answer on, and a prompt there hangs it. */
|
|
103
|
+
const interactive =
|
|
104
|
+
!jsonOut &&
|
|
105
|
+
!args.includes("--non-interactive") &&
|
|
106
|
+
!process.env.WORK_NONINTERACTIVE;
|
|
82
107
|
/** `--name <value>` style flags take the next arg; keep it out of the
|
|
83
108
|
* positionals so `work join --name x` still reads stdin. */
|
|
84
109
|
const VALUED = new Set(["--name", "--allow"]);
|
|
@@ -101,7 +126,20 @@ const flagValues = (flag) =>
|
|
|
101
126
|
return [args[i + 1]];
|
|
102
127
|
});
|
|
103
128
|
|
|
104
|
-
|
|
129
|
+
// A command of bin/cli/ (`workspace create`: a word of the core's, then
|
|
130
|
+
// its own) is looked for first, so one can extend a core command with
|
|
131
|
+
// verbs of its own without a case here.
|
|
132
|
+
const cli = await cliCommand(command, positional[0]);
|
|
133
|
+
|
|
134
|
+
switch (cli ? "" : command) {
|
|
135
|
+
case "":
|
|
136
|
+
await cli.cmd.run(cliContext(cli.words));
|
|
137
|
+
break;
|
|
138
|
+
case "help":
|
|
139
|
+
case "--help":
|
|
140
|
+
case "-h":
|
|
141
|
+
await helpCmd(positional[0]);
|
|
142
|
+
break;
|
|
105
143
|
case "start":
|
|
106
144
|
await start();
|
|
107
145
|
break;
|
|
@@ -169,9 +207,10 @@ switch (command) {
|
|
|
169
207
|
console.log(pkg.version);
|
|
170
208
|
break;
|
|
171
209
|
default:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
);
|
|
210
|
+
// A typo must fail: an agent reads the exit code, and usage on stdout
|
|
211
|
+
// with 0 read as the command having run.
|
|
212
|
+
console.error(`error: no command \`${command}\` (see: work help)`);
|
|
213
|
+
process.exitCode = 2;
|
|
175
214
|
}
|
|
176
215
|
|
|
177
216
|
async function start() {
|
|
@@ -232,18 +271,38 @@ function serverUrl() {
|
|
|
232
271
|
return `http://${dialHost(env.WORK_LISTEN)}:${env.PORT}`;
|
|
233
272
|
}
|
|
234
273
|
|
|
235
|
-
|
|
274
|
+
/** One request to the running server: its JSON, or the command dies with
|
|
275
|
+
* the server's own reason (`{error}`), never only its status. */
|
|
276
|
+
async function apiCall(method, path, body, timeoutMs = 30_000) {
|
|
236
277
|
const port = serviceEnv().PORT;
|
|
278
|
+
let res;
|
|
237
279
|
try {
|
|
238
|
-
|
|
239
|
-
|
|
280
|
+
res = await fetch(`${serverUrl()}${path}`, {
|
|
281
|
+
method,
|
|
282
|
+
headers:
|
|
283
|
+
body === undefined ? undefined : { "content-type": "application/json" },
|
|
284
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
285
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
240
286
|
});
|
|
241
|
-
|
|
242
|
-
return await res.json();
|
|
243
|
-
} catch (err) {
|
|
244
|
-
if (err?.message?.startsWith("server answered")) throw err;
|
|
287
|
+
} catch {
|
|
245
288
|
die(`no work server on port ${port}. Start one with: work start`);
|
|
246
289
|
}
|
|
290
|
+
const text = await res.text();
|
|
291
|
+
let data = null;
|
|
292
|
+
try {
|
|
293
|
+
data = text ? JSON.parse(text) : null;
|
|
294
|
+
} catch {}
|
|
295
|
+
if (!res.ok || (data && typeof data === "object" && data.error)) {
|
|
296
|
+
die(
|
|
297
|
+
(data && data.error) ||
|
|
298
|
+
`server answered ${res.status} for ${method} ${path}`,
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
return data;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function apiGet(path) {
|
|
305
|
+
return apiCall("GET", path);
|
|
247
306
|
}
|
|
248
307
|
|
|
249
308
|
/**
|
|
@@ -255,7 +314,7 @@ async function apiGet(path) {
|
|
|
255
314
|
async function resolveWorkspace(arg) {
|
|
256
315
|
const [list, status] = await Promise.all([
|
|
257
316
|
apiGet("/api/workspaces"),
|
|
258
|
-
apiGet(
|
|
317
|
+
apiGet(statusPath()),
|
|
259
318
|
]);
|
|
260
319
|
let ws;
|
|
261
320
|
if (arg) {
|
|
@@ -294,10 +353,17 @@ function pad(s, n) {
|
|
|
294
353
|
return String(s ?? "").padEnd(n);
|
|
295
354
|
}
|
|
296
355
|
|
|
356
|
+
/** The status snapshot, or with --fresh one that asks GitHub again: a PR
|
|
357
|
+
* made a moment ago (`gh pr create`) is otherwise missing for as long as
|
|
358
|
+
* the PR cache keeps its last answer. */
|
|
359
|
+
function statusPath() {
|
|
360
|
+
return args.includes("--fresh") ? "/api/status?fresh" : "/api/status";
|
|
361
|
+
}
|
|
362
|
+
|
|
297
363
|
async function workspacesCmd() {
|
|
298
364
|
const [list, status] = await Promise.all([
|
|
299
365
|
apiGet("/api/workspaces"),
|
|
300
|
-
apiGet(
|
|
366
|
+
apiGet(statusPath()),
|
|
301
367
|
]);
|
|
302
368
|
const rows = list.map((w) => ({ ...w, ...(status[w.id] || {}) }));
|
|
303
369
|
if (jsonOut) return console.log(JSON.stringify(rows, null, 2));
|
|
@@ -323,21 +389,26 @@ function prLine(pr) {
|
|
|
323
389
|
: pr.isDraft
|
|
324
390
|
? "draft"
|
|
325
391
|
: "open";
|
|
326
|
-
return `#${pr.number} ${state} ${pr.title} ${pr.url}`;
|
|
392
|
+
return `#${pr.number} ${state} ${pr.title}${pr.headRefName ? ` (${pr.headRefName})` : ""} ${pr.url}`;
|
|
327
393
|
}
|
|
328
394
|
|
|
329
395
|
async function workspaceCmd() {
|
|
330
396
|
const { ws, status } = await resolveWorkspace(positional[0]);
|
|
331
397
|
const procs = await apiGet(`/api/workspaces/${ws.id}/procs`).catch(() => []);
|
|
332
|
-
const [sessions] = await Promise.all([
|
|
398
|
+
const [sessions, linkPort] = await Promise.all([
|
|
333
399
|
apiGet(`/api/workspaces/${ws.id}/sessions`).catch(() => []),
|
|
400
|
+
portLinker(),
|
|
334
401
|
]);
|
|
402
|
+
const me = process.env.WORK_SESSION_ID;
|
|
335
403
|
const out = {
|
|
336
404
|
...ws,
|
|
337
|
-
ports: status.ports
|
|
405
|
+
ports: (status.ports || []).map((p) => ({
|
|
406
|
+
...p,
|
|
407
|
+
...linkPort(p.port, p.local),
|
|
408
|
+
})),
|
|
338
409
|
repos: mergeRepos(ws, status),
|
|
339
|
-
sessions,
|
|
340
|
-
procs,
|
|
410
|
+
sessions: sessions.map((s) => (s.id === me ? { ...s, self: true } : s)),
|
|
411
|
+
procs: procs.map((p) => withUrls(p, linkPort)),
|
|
341
412
|
};
|
|
342
413
|
if (jsonOut) return console.log(JSON.stringify(out, null, 2));
|
|
343
414
|
console.log(`${ws.name} (${ws.status})`);
|
|
@@ -352,16 +423,58 @@ async function workspaceCmd() {
|
|
|
352
423
|
console.log(` sessions:`);
|
|
353
424
|
for (const s of sessions) {
|
|
354
425
|
const phase = s.state?.phase || (s.state?.alive ? "idle" : "off");
|
|
355
|
-
console.log(
|
|
426
|
+
console.log(
|
|
427
|
+
` ${pad(s.id, 9)} ${pad(s.agent, 10)} ${pad(phase, 8)} ${s.title || ""}${s.id === me ? " (this session)" : ""}`,
|
|
428
|
+
);
|
|
356
429
|
}
|
|
357
430
|
}
|
|
358
431
|
if (procs.length) {
|
|
359
432
|
console.log(` running:`);
|
|
360
|
-
for (const p of procs)
|
|
361
|
-
console.log(
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
433
|
+
for (const p of out.procs)
|
|
434
|
+
console.log(` ${pad(p.pid, 7)} ${p.cmd}${portsText(p)}`);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/** How a port opens for the user: through the address their browser last
|
|
439
|
+
* reached work by (`/api/boot`'s `origin`) as the page's port chip would
|
|
440
|
+
* (lib/ports/url), or this machine's own when no browser has yet. `blocked`
|
|
441
|
+
* says why that link cannot work (a port bound to loopback, a page on a
|
|
442
|
+
* direct address). */
|
|
443
|
+
async function portLinker() {
|
|
444
|
+
const boot = await apiGet("/api/boot");
|
|
445
|
+
const loc = boot.origin ? locOf(boot.origin) : null;
|
|
446
|
+
return (port, local) => {
|
|
447
|
+
if (!loc) return { url: `http://localhost:${port}` };
|
|
448
|
+
const blocked = portBlockedAt(port, local, loc);
|
|
449
|
+
return {
|
|
450
|
+
url: portUrlAt(port, loc, boot.portHosts),
|
|
451
|
+
...(blocked && { blocked }),
|
|
452
|
+
};
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/** A process with each of its ports' links (`urls`, by port). */
|
|
457
|
+
function withUrls(p, linkPort) {
|
|
458
|
+
if (!p.ports?.length) return p;
|
|
459
|
+
const local = new Set(p.local || []);
|
|
460
|
+
return {
|
|
461
|
+
...p,
|
|
462
|
+
urls: Object.fromEntries(
|
|
463
|
+
p.ports.map((port) => [port, linkPort(port, local.has(port))]),
|
|
464
|
+
),
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/** A process's ports for a line of text, each with where it opens. */
|
|
469
|
+
function portsText(p) {
|
|
470
|
+
if (!p.ports?.length) return "";
|
|
471
|
+
return ` ${p.ports
|
|
472
|
+
.map((port) => {
|
|
473
|
+
const link = p.urls?.[port];
|
|
474
|
+
if (!link) return `:${port}`;
|
|
475
|
+
return `:${port} ${link.url}${link.blocked ? ` (${link.blocked})` : ""}`;
|
|
476
|
+
})
|
|
477
|
+
.join(" ")}`;
|
|
365
478
|
}
|
|
366
479
|
|
|
367
480
|
/** Workspace repos joined with the status snapshot's PRs per repo. */
|
|
@@ -387,13 +500,15 @@ async function reposCmd() {
|
|
|
387
500
|
|
|
388
501
|
async function procsCmd() {
|
|
389
502
|
const { ws } = await resolveWorkspace(positional[0]);
|
|
390
|
-
const
|
|
503
|
+
const [raw, linkPort] = await Promise.all([
|
|
504
|
+
apiGet(`/api/workspaces/${ws.id}/procs`),
|
|
505
|
+
portLinker(),
|
|
506
|
+
]);
|
|
507
|
+
const procs = raw.map((p) => withUrls(p, linkPort));
|
|
391
508
|
if (jsonOut) return console.log(JSON.stringify(procs, null, 2));
|
|
392
509
|
if (!procs.length) return console.log("nothing running");
|
|
393
510
|
for (const p of procs)
|
|
394
|
-
console.log(
|
|
395
|
-
`${pad(p.pid, 7)} ${p.cmd}${p.ports?.length ? " " + p.ports.map((x) => `:${x}`).join(" ") : ""}`,
|
|
396
|
-
);
|
|
511
|
+
console.log(`${pad(p.pid, 7)} ${p.cmd}${portsText(p)}`);
|
|
397
512
|
}
|
|
398
513
|
|
|
399
514
|
/** Comments left on the review page but not yet sent: an agent can pull
|
|
@@ -402,9 +517,23 @@ async function procsCmd() {
|
|
|
402
517
|
async function reviewCmd() {
|
|
403
518
|
const { ws } = await resolveWorkspace(positional[0]);
|
|
404
519
|
const { comments = [] } = await apiGet(`/api/workspaces/${ws.id}/review`);
|
|
405
|
-
if (jsonOut)
|
|
406
|
-
if (!comments.length)
|
|
407
|
-
|
|
520
|
+
if (jsonOut) console.log(JSON.stringify(comments, null, 2));
|
|
521
|
+
else if (!comments.length) console.log("no pending review comments");
|
|
522
|
+
else
|
|
523
|
+
console.log(
|
|
524
|
+
commentMarkdown(comments, await reviewSections(ws.id, comments)),
|
|
525
|
+
);
|
|
526
|
+
// Taken, the comments leave the review as a Send takes them: exactly the
|
|
527
|
+
// ones printed, so one written meanwhile stays for the next look.
|
|
528
|
+
if (args.includes("--take") && comments.length) {
|
|
529
|
+
await apiPost(`/api/workspaces/${ws.id}/review`, {
|
|
530
|
+
action: "clear",
|
|
531
|
+
ids: comments.map((c) => c.id),
|
|
532
|
+
});
|
|
533
|
+
console.error(
|
|
534
|
+
`took ${comments.length} comment${comments.length === 1 ? "" : "s"} off the review`,
|
|
535
|
+
);
|
|
536
|
+
}
|
|
408
537
|
}
|
|
409
538
|
|
|
410
539
|
/** The diff's sections, which say which lane or PR a comment's lines are
|
|
@@ -413,41 +542,25 @@ async function reviewCmd() {
|
|
|
413
542
|
* comments then read as the checkout's rather than failing the command. */
|
|
414
543
|
async function reviewSections(wsId, comments) {
|
|
415
544
|
if (!comments.some((c) => c.head)) return null;
|
|
416
|
-
const port = serviceEnv().PORT;
|
|
417
545
|
try {
|
|
418
|
-
const res = await fetch(
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
);
|
|
546
|
+
const res = await fetch(`${serverUrl()}/api/workspaces/${wsId}/diff`, {
|
|
547
|
+
signal: AbortSignal.timeout(60_000),
|
|
548
|
+
});
|
|
422
549
|
return res.ok ? ((await res.json()).sections ?? null) : null;
|
|
423
550
|
} catch {
|
|
424
551
|
return null;
|
|
425
552
|
}
|
|
426
553
|
}
|
|
427
554
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
try {
|
|
432
|
-
res = await fetch(`${serverUrl()}${path}`, {
|
|
433
|
-
method: "POST",
|
|
434
|
-
headers: { "content-type": "application/json" },
|
|
435
|
-
body: body === undefined ? undefined : JSON.stringify(body),
|
|
436
|
-
signal: AbortSignal.timeout(15 * 60_000),
|
|
437
|
-
});
|
|
438
|
-
} catch {
|
|
439
|
-
die(`no work server on port ${port}. Start one with: work start`);
|
|
440
|
-
}
|
|
441
|
-
const data = await res.json().catch(() => ({}));
|
|
442
|
-
if (!res.ok || data.error)
|
|
443
|
-
die(data.error || `server answered ${res.status} for ${path}`);
|
|
444
|
-
return data;
|
|
555
|
+
/** A write: as long as a clone can take (a create, a restore). */
|
|
556
|
+
function apiPost(path, body) {
|
|
557
|
+
return apiCall("POST", path, body ?? {}, 15 * 60_000);
|
|
445
558
|
}
|
|
446
559
|
|
|
447
560
|
/** One line per workspace/repo of what the file will not carry. */
|
|
448
561
|
function printPreflight(found) {
|
|
449
562
|
for (const w of found.workspaces) {
|
|
450
|
-
|
|
563
|
+
say(w.name);
|
|
451
564
|
for (const r of w.repos) {
|
|
452
565
|
const parts = [];
|
|
453
566
|
for (const b of r.unpushed)
|
|
@@ -456,10 +569,10 @@ function printPreflight(found) {
|
|
|
456
569
|
if (r.untracked.length) parts.push(`${r.untracked.length} untracked`);
|
|
457
570
|
if (r.ignored.length) parts.push(`${r.ignored.length} ignored`);
|
|
458
571
|
if (r.more) parts.push(`+${r.more} more`);
|
|
459
|
-
|
|
460
|
-
for (const f of r.modified)
|
|
461
|
-
for (const f of r.untracked)
|
|
462
|
-
for (const f of r.ignored)
|
|
572
|
+
say(` ${r.worktree}/ ${parts.join(", ")}`);
|
|
573
|
+
for (const f of r.modified) say(` M ${f}`);
|
|
574
|
+
for (const f of r.untracked) say(` ? ${f}`);
|
|
575
|
+
for (const f of r.ignored) say(` ! ${f}`);
|
|
463
576
|
}
|
|
464
577
|
}
|
|
465
578
|
}
|
|
@@ -477,7 +590,7 @@ async function exportCmd() {
|
|
|
477
590
|
);
|
|
478
591
|
}
|
|
479
592
|
if (found.workspaces.length) {
|
|
480
|
-
|
|
593
|
+
say("not in the backup:");
|
|
481
594
|
printPreflight(found);
|
|
482
595
|
if (!yes) {
|
|
483
596
|
console.log("");
|
|
@@ -498,6 +611,18 @@ async function exportCmd() {
|
|
|
498
611
|
"work-backup.json";
|
|
499
612
|
fs.writeFileSync(name, await res.text());
|
|
500
613
|
log(`wrote ${name}`);
|
|
614
|
+
if (jsonOut)
|
|
615
|
+
console.log(
|
|
616
|
+
JSON.stringify(
|
|
617
|
+
{
|
|
618
|
+
file: path.resolve(name),
|
|
619
|
+
contents: c ?? null,
|
|
620
|
+
left_out: found.workspaces,
|
|
621
|
+
},
|
|
622
|
+
null,
|
|
623
|
+
2,
|
|
624
|
+
),
|
|
625
|
+
);
|
|
501
626
|
}
|
|
502
627
|
|
|
503
628
|
function readManifest(file) {
|
|
@@ -658,6 +783,8 @@ function until(iso) {
|
|
|
658
783
|
}
|
|
659
784
|
|
|
660
785
|
async function setup() {
|
|
786
|
+
// First: a bad name fails before anything is touched.
|
|
787
|
+
editAllowedHosts();
|
|
661
788
|
await bridge();
|
|
662
789
|
const d = await doctor(doctorOpts());
|
|
663
790
|
await fix(d);
|
|
@@ -670,13 +797,30 @@ async function setup() {
|
|
|
670
797
|
const port = serviceEnv().PORT;
|
|
671
798
|
if (!tailnet) maybeTunnel(port);
|
|
672
799
|
if (running) {
|
|
673
|
-
|
|
674
|
-
|
|
800
|
+
const answered = await waitForServer();
|
|
801
|
+
if (answered) log(`done — http://localhost:${port}`);
|
|
802
|
+
else {
|
|
675
803
|
warn(
|
|
676
804
|
`service started but nothing answered on port ${port} within 30s — check the logs`,
|
|
677
805
|
);
|
|
806
|
+
// A setup that left no server is a failed one, to whatever ran it.
|
|
807
|
+
process.exitCode = 1;
|
|
808
|
+
}
|
|
678
809
|
if (tailnet)
|
|
679
810
|
log(`on your phone and other devices on the tailnet: ${tailnet}`);
|
|
811
|
+
if (jsonOut)
|
|
812
|
+
console.log(
|
|
813
|
+
JSON.stringify(
|
|
814
|
+
{
|
|
815
|
+
ok: answered,
|
|
816
|
+
version: pkg.version,
|
|
817
|
+
url: `http://localhost:${port}`,
|
|
818
|
+
tailnet: tailnet || null,
|
|
819
|
+
},
|
|
820
|
+
null,
|
|
821
|
+
2,
|
|
822
|
+
),
|
|
823
|
+
);
|
|
680
824
|
} else {
|
|
681
825
|
// A fresh install's shell may not have mise on PATH yet — name the shim.
|
|
682
826
|
const shim = path.join(
|
|
@@ -694,6 +838,34 @@ async function setup() {
|
|
|
694
838
|
}
|
|
695
839
|
}
|
|
696
840
|
|
|
841
|
+
/** `--allow-host <name>` / `--disallow-host <name>`, each repeatable: one
|
|
842
|
+
* name in or out of the service's WORK_ALLOWED_HOSTS, the rest kept —
|
|
843
|
+
* `WORK_ALLOWED_HOSTS=… work setup` replaces the whole list, which an
|
|
844
|
+
* agent adding one proxy's name would otherwise have to read back first.
|
|
845
|
+
* Applied before anything writes the service, which carries what this
|
|
846
|
+
* leaves in the environment (`serviceEnv`). */
|
|
847
|
+
function editAllowedHosts() {
|
|
848
|
+
const allow = flagValues("--allow-host");
|
|
849
|
+
const disallow = flagValues("--disallow-host");
|
|
850
|
+
if (!allow.length && !disallow.length) return;
|
|
851
|
+
for (const name of [...allow, ...disallow]) {
|
|
852
|
+
if (!/^[A-Za-z0-9.-]+$/.test(name))
|
|
853
|
+
die(
|
|
854
|
+
`not a host name: ${name} (one name per flag, e.g. work.example.com)`,
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
const before = serviceEnv().WORK_ALLOWED_HOSTS || "";
|
|
858
|
+
let next = before;
|
|
859
|
+
for (const name of allow) next = allowHost(next, name, true);
|
|
860
|
+
for (const name of disallow) next = allowHost(next, name, false);
|
|
861
|
+
process.env.WORK_ALLOWED_HOSTS = next;
|
|
862
|
+
log(
|
|
863
|
+
next === before
|
|
864
|
+
? `WORK_ALLOWED_HOSTS unchanged: ${next || "(none)"}`
|
|
865
|
+
: `WORK_ALLOWED_HOSTS=${next || "(none)"}`,
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
|
|
697
869
|
/** Bring a database from before 0.1 to the baseline this release starts
|
|
698
870
|
* from (lib/setup/bridge.mjs), before anything touches the service: the
|
|
699
871
|
* server it would restart refuses such a database. Run with the settings
|
|
@@ -745,22 +917,35 @@ async function update() {
|
|
|
745
917
|
// `--prefer-online`: npm serves `latest` from a cached packument for a
|
|
746
918
|
// few minutes after a publish, so an update right behind a release
|
|
747
919
|
// reinstalled the version already running.
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
"
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
920
|
+
// Under --json, npm's own output goes to stderr: stdout is setup's JSON.
|
|
921
|
+
const stdio = jsonOut ? ["inherit", 2, 2] : "inherit";
|
|
922
|
+
sh(
|
|
923
|
+
"npm",
|
|
924
|
+
[
|
|
925
|
+
"install",
|
|
926
|
+
"-g",
|
|
927
|
+
"--prefer-online",
|
|
928
|
+
...allowScriptsArgs(),
|
|
929
|
+
"@dylanpiercey/work@latest",
|
|
930
|
+
],
|
|
931
|
+
{ stdio },
|
|
932
|
+
);
|
|
755
933
|
// Re-exec the (possibly new) CLI to finish with fresh code.
|
|
756
934
|
sh("work", [
|
|
757
935
|
"setup",
|
|
758
936
|
...(yes ? ["--yes"] : []),
|
|
759
937
|
...args.filter((a) =>
|
|
760
|
-
[
|
|
761
|
-
|
|
762
|
-
|
|
938
|
+
[
|
|
939
|
+
"--tailscale",
|
|
940
|
+
"--no-tailscale",
|
|
941
|
+
"--firewall",
|
|
942
|
+
"--no-firewall",
|
|
943
|
+
"--json",
|
|
944
|
+
"--non-interactive",
|
|
945
|
+
].includes(a),
|
|
763
946
|
),
|
|
947
|
+
...flagValues("--allow-host").flatMap((h) => ["--allow-host", h]),
|
|
948
|
+
...flagValues("--disallow-host").flatMap((h) => ["--disallow-host", h]),
|
|
764
949
|
]);
|
|
765
950
|
}
|
|
766
951
|
|
|
@@ -976,7 +1161,7 @@ async function fix(d) {
|
|
|
976
1161
|
}
|
|
977
1162
|
log(`installing ${tool.label} via ${tool.mise ? "mise" : "gh"}`);
|
|
978
1163
|
try {
|
|
979
|
-
await installTool(tool.id, { log: (l) =>
|
|
1164
|
+
await installTool(tool.id, { log: (l) => say(` ${l}`) });
|
|
980
1165
|
} catch (err) {
|
|
981
1166
|
if (tool.required) die(`${tool.label} install failed: ${err.message}`);
|
|
982
1167
|
warn(`${tool.label} install failed (non-fatal)`);
|
|
@@ -1741,6 +1926,7 @@ function allowTailnet(serve) {
|
|
|
1741
1926
|
* controlling terminal, since the curl installer pipes its script into the
|
|
1742
1927
|
* shell this runs under. Null with no terminal at all. */
|
|
1743
1928
|
function terminal() {
|
|
1929
|
+
if (!interactive) return null;
|
|
1744
1930
|
if (process.stdin.isTTY) return process.stdin;
|
|
1745
1931
|
try {
|
|
1746
1932
|
return new tty.ReadStream(fs.openSync("/dev/tty", "r"));
|
|
@@ -1763,3 +1949,139 @@ async function confirm(input, question) {
|
|
|
1763
1949
|
rl.close();
|
|
1764
1950
|
}
|
|
1765
1951
|
}
|
|
1952
|
+
|
|
1953
|
+
// -- commands of bin/cli/ and help ------------------------------------------
|
|
1954
|
+
|
|
1955
|
+
/** Every command a file of bin/cli/ exports (`_`-prefixed files are its
|
|
1956
|
+
* helpers), loaded once. (Kept on the function: the dispatch above runs
|
|
1957
|
+
* before a top-level `let` here would be initialised.) */
|
|
1958
|
+
async function cliCommands() {
|
|
1959
|
+
if (cliCommands.cache) return cliCommands.cache;
|
|
1960
|
+
const dir = path.join(pkgRoot, "bin", "cli");
|
|
1961
|
+
const files = fs.existsSync(dir)
|
|
1962
|
+
? fs
|
|
1963
|
+
.readdirSync(dir)
|
|
1964
|
+
.filter((f) => f.endsWith(".mjs") && !f.startsWith("_"))
|
|
1965
|
+
.sort()
|
|
1966
|
+
: [];
|
|
1967
|
+
const all = [];
|
|
1968
|
+
for (const f of files) {
|
|
1969
|
+
const mod = await import(path.join(dir, f));
|
|
1970
|
+
for (const c of mod.commands || []) all.push(c);
|
|
1971
|
+
}
|
|
1972
|
+
cliCommands.cache = all;
|
|
1973
|
+
return all;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
/** A core command's other name, which a bin/cli/ command's first word may
|
|
1977
|
+
* be spelled with (`work ws create` is `workspace create`). */
|
|
1978
|
+
function canonical(word) {
|
|
1979
|
+
return word === "ws" ? "workspace" : word;
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
/** The bin/cli/ command `argv` names: two words (`workspace create`)
|
|
1983
|
+
* before one, so a verb of its own wins over the word alone. */
|
|
1984
|
+
async function cliCommand(first, second) {
|
|
1985
|
+
const all = await cliCommands();
|
|
1986
|
+
const head = canonical(first);
|
|
1987
|
+
const names = (c) => [c.name, ...(c.aliases || [])];
|
|
1988
|
+
if (second) {
|
|
1989
|
+
const two = `${head} ${second}`;
|
|
1990
|
+
const cmd = all.find((c) => names(c).includes(two));
|
|
1991
|
+
if (cmd) return { cmd, words: 2 };
|
|
1992
|
+
}
|
|
1993
|
+
const cmd = all.find((c) => names(c).includes(head));
|
|
1994
|
+
return cmd ? { cmd, words: 1 } : null;
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
/** What a bin/cli/ command is handed: its own argv, the CLI's flags, and
|
|
1998
|
+
* the helpers every command shares — the running server (`api`), which
|
|
1999
|
+
* workspace is meant, and how to say something or fail. */
|
|
2000
|
+
function cliContext(words) {
|
|
2001
|
+
const own = args.slice(0);
|
|
2002
|
+
// The words that named it are not its positionals.
|
|
2003
|
+
const pos = positional.slice(words - 1);
|
|
2004
|
+
return {
|
|
2005
|
+
pkg,
|
|
2006
|
+
args: own,
|
|
2007
|
+
positional: pos,
|
|
2008
|
+
json: jsonOut,
|
|
2009
|
+
yes,
|
|
2010
|
+
has: (flag) => args.includes(flag),
|
|
2011
|
+
flag: flagValue,
|
|
2012
|
+
flags: flagValues,
|
|
2013
|
+
/** Positionals with `valued` flags' values left out (`--agent x`). */
|
|
2014
|
+
parse(valued = []) {
|
|
2015
|
+
const set = new Set([...VALUED, ...valued]);
|
|
2016
|
+
return args
|
|
2017
|
+
.filter(
|
|
2018
|
+
(a, i) => a === "-" || (!a.startsWith("-") && !set.has(args[i - 1])),
|
|
2019
|
+
)
|
|
2020
|
+
.slice(words - 1);
|
|
2021
|
+
},
|
|
2022
|
+
api: {
|
|
2023
|
+
get: (p) => apiCall("GET", p),
|
|
2024
|
+
post: (p, body) => apiPost(p, body),
|
|
2025
|
+
put: (p, body) => apiCall("PUT", p, body ?? {}),
|
|
2026
|
+
patch: (p, body) => apiCall("PATCH", p, body ?? {}),
|
|
2027
|
+
del: (p, body) => apiCall("DELETE", p, body),
|
|
2028
|
+
},
|
|
2029
|
+
serverUrl,
|
|
2030
|
+
resolveWorkspace,
|
|
2031
|
+
/** `data` as JSON under --json, else what `text` prints. */
|
|
2032
|
+
out(data, text) {
|
|
2033
|
+
if (jsonOut) console.log(JSON.stringify(data, null, 2));
|
|
2034
|
+
else text?.(data);
|
|
2035
|
+
},
|
|
2036
|
+
pad,
|
|
2037
|
+
log,
|
|
2038
|
+
warn,
|
|
2039
|
+
die,
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
/** The header's own lines for the core commands: `work <name>` and what
|
|
2044
|
+
* continues it, as written at the top of this file. */
|
|
2045
|
+
function coreHelp() {
|
|
2046
|
+
const src = fs.readFileSync(fileURLToPath(import.meta.url), "utf8");
|
|
2047
|
+
const lines = [];
|
|
2048
|
+
for (const line of src.split("\n").slice(1)) {
|
|
2049
|
+
if (!line.startsWith("//")) break;
|
|
2050
|
+
const text = line.replace(/^\/\/ ?/, "");
|
|
2051
|
+
// The list starts at its first `work …` line and ends at a blank one.
|
|
2052
|
+
if (!lines.length && !/^ {2}work /.test(text)) continue;
|
|
2053
|
+
if (!text.trim()) break;
|
|
2054
|
+
lines.push(text.replace(/^ {2}/, ""));
|
|
2055
|
+
}
|
|
2056
|
+
return lines;
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
/** `work help`: every command, the core's then bin/cli/'s; `work help
|
|
2060
|
+
* <cmd>` that one's whole text. */
|
|
2061
|
+
async function helpCmd(topic) {
|
|
2062
|
+
const all = await cliCommands();
|
|
2063
|
+
const core = coreHelp();
|
|
2064
|
+
if (topic) {
|
|
2065
|
+
const head = canonical(topic);
|
|
2066
|
+
const own = all.filter(
|
|
2067
|
+
(c) => c.name === head || c.name.startsWith(`${head} `),
|
|
2068
|
+
);
|
|
2069
|
+
const start = core.findIndex((l) => new RegExp(`^work ${head}\\b`).test(l));
|
|
2070
|
+
if (start < 0 && !own.length)
|
|
2071
|
+
die(`no command \`${topic}\` (see: work help)`);
|
|
2072
|
+
if (start >= 0) {
|
|
2073
|
+
let end = start + 1;
|
|
2074
|
+
while (end < core.length && !core[end].startsWith("work ")) end++;
|
|
2075
|
+
console.log(core.slice(start, end).join("\n"));
|
|
2076
|
+
}
|
|
2077
|
+
for (const c of own) console.log(`\n${c.help || c.summary}`);
|
|
2078
|
+
return;
|
|
2079
|
+
}
|
|
2080
|
+
console.log(`work ${pkg.version}\n`);
|
|
2081
|
+
console.log(core.join("\n"));
|
|
2082
|
+
for (const c of all) console.log(`work ${c.name.padEnd(22)} ${c.summary}`);
|
|
2083
|
+
console.log(
|
|
2084
|
+
"\nwork help <command> for one command's whole text. Most take --json;",
|
|
2085
|
+
);
|
|
2086
|
+
console.log("under it stdout is JSON alone and progress goes to stderr.");
|
|
2087
|
+
}
|