@dylanpiercey/work 0.2.16 → 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 +16 -2
- 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 +405 -82
- package/dist/_BAJGOEa1.js +168 -0
- package/dist/{_cZI5p-2V.js → _BlLEM8du.js} +80 -48
- package/dist/_t9VsALwo.js +2 -0
- package/dist/index.mjs +3548 -2613
- package/dist/public/assets/{_BwIqXHWp.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/{_BtCVvK2k.js → _4Sj6a8Ya.js} +1 -1
- package/dist/public/assets/_4Sj6a8Ya.js.br +0 -0
- package/dist/public/assets/{_Hu1xz4Lu.js → _5tN48iuJ.js} +1 -1
- package/dist/public/assets/_5tN48iuJ.js.br +0 -0
- package/dist/public/assets/{_gIdf7Xw5.js → _8_DzkMgB.js} +1 -1
- package/dist/public/assets/_8_DzkMgB.js.br +0 -0
- package/dist/public/assets/{_DSw-4lX2.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/{_BAZwH6Ve.js → _B-H6ABVZ.js} +1 -1
- package/dist/public/assets/_B-H6ABVZ.js.br +0 -0
- package/dist/public/assets/{_CNramc89.js → _B-iOtMg6.js} +1 -1
- package/dist/public/assets/_B-iOtMg6.js.br +0 -0
- package/dist/public/assets/{_DYH0eCbn.js → _B0FhzjB2.js} +1 -1
- package/dist/public/assets/_B0FhzjB2.js.br +0 -0
- package/dist/public/assets/{_BdIL1kV4.js → _B26gPL08.js} +1 -1
- package/dist/public/assets/_B26gPL08.js.br +0 -0
- package/dist/public/assets/{_BMrsOtya.js → _B2DHvTZR.js} +1 -1
- package/dist/public/assets/{_BCuTz32B.js → _B3Z1kRpD.js} +1 -1
- package/dist/public/assets/_B3Z1kRpD.js.br +0 -0
- package/dist/public/assets/{_G9Zy20B_.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/{_HlShuyJR.js → _B4hn3NNW.js} +1 -1
- package/dist/public/assets/_B4hn3NNW.js.br +0 -0
- package/dist/public/assets/{_o-w-GRlW.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/{_C1gXJmH-.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/{_B4jkmqvY.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/{_DDDY02_q.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/{_CkOLwn-O.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/{_qiP5PaTJ.js → _BIUaA4Nl.js} +1 -1
- package/dist/public/assets/_BIUaA4Nl.js.br +0 -0
- package/dist/public/assets/{_D4JoXfrO.js → _BJpBnuvv.js} +1 -1
- package/dist/public/assets/_BJpBnuvv.js.br +0 -0
- package/dist/public/assets/{_D5-Xbg1R.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/{_DYUAPXDQ.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/{_C7n1c5sG.js → _BXHggM8M.js} +1 -1
- package/dist/public/assets/_BXHggM8M.js.br +0 -0
- package/dist/public/assets/{_DSUWiRRK.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/{_Bfa3k3Hb.js → _BkGAUdMd.js} +1 -1
- package/dist/public/assets/_BkGAUdMd.js.br +0 -0
- package/dist/public/assets/{_5fKzV_xm.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/{_C4lapxL9.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/{_BA4Iu42n.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/{_B015R9rm.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/{_DRfZHwBJ.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/{_BBbmRU3k.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/{_DVOLp04e.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/{_Bl5WXdoB.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/{_CQIzzFRZ.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/{_CLaHO3fE.js → _CIDjLk1A.js} +1 -1
- package/dist/public/assets/_CIDjLk1A.js.br +0 -0
- package/dist/public/assets/{_CBcx1kOh.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/{_D9_2hMWP.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/{_CVxQyHtq.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/{_Dy3vjhI9.js → _CX5VOdNU.js} +1 -1
- package/dist/public/assets/_CX5VOdNU.js.br +0 -0
- package/dist/public/assets/{_CfM615kO.js → _CYcgwayF.js} +1 -1
- package/dist/public/assets/_CYcgwayF.js.br +0 -0
- package/dist/public/assets/{_hvh7Kn8G.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/{_x9gsUMHG.js → _CcINcTUt.js} +1 -1
- package/dist/public/assets/_CcINcTUt.js.br +0 -0
- package/dist/public/assets/{_Bfh0n3cD.js → _CcflXOTj.js} +1 -1
- package/dist/public/assets/_CcflXOTj.js.br +0 -0
- package/dist/public/assets/{_BjiY-VzO.js → _Cfts4mFJ.js} +1 -1
- package/dist/public/assets/_Cfts4mFJ.js.br +0 -0
- package/dist/public/assets/{_YRsH_Jn5.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/{_Cxhfb-mP.js → _CpVeIwQ4.js} +1 -1
- package/dist/public/assets/_CpVeIwQ4.js.br +0 -0
- package/dist/public/assets/{_BO_dGrB_.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/{_aY3LCTY6.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/{_CPakGo19.js → _DB7_Yora.js} +1 -1
- package/dist/public/assets/_DB7_Yora.js.br +0 -0
- package/dist/public/assets/{_CHWlI8eM.js → _DDWIDZyP.js} +1 -1
- package/dist/public/assets/_DDWIDZyP.js.br +0 -0
- package/dist/public/assets/{_C634i9Iw.js → _DG3L8-RO.js} +1 -1
- package/dist/public/assets/_DG3L8-RO.js.br +0 -0
- package/dist/public/assets/{_D5woWAW8.js → _DGRgLaG-.js} +1 -1
- package/dist/public/assets/_DGRgLaG-.js.br +0 -0
- package/dist/public/assets/{_DW7N6KAK.js → _DG_QOtsx.js} +1 -1
- package/dist/public/assets/_DG_QOtsx.js.br +0 -0
- package/dist/public/assets/{_B5aDrGbO.js → _DHYIZWev.js} +11 -11
- package/dist/public/assets/_DHYIZWev.js.br +0 -0
- package/dist/public/assets/{_8n8ba3Xr.js → _DJwY_zBh.js} +1 -1
- package/dist/public/assets/_DJwY_zBh.js.br +0 -0
- package/dist/public/assets/{_DLbIAQvl.js → _DKlB-yMq.js} +1 -1
- package/dist/public/assets/_DKlB-yMq.js.br +0 -0
- package/dist/public/assets/{_CrJYhl4C.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/{_CvHnOFNG.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/{_Brgs9TFt.js → _DRpsUHP5.js} +1 -1
- package/dist/public/assets/_DRpsUHP5.js.br +0 -0
- package/dist/public/assets/{_CJDXsoZG.js → _DUH5o_iN.js} +1 -1
- package/dist/public/assets/_DUH5o_iN.js.br +0 -0
- package/dist/public/assets/{_B-Kvhca4.js → _DUmYv8Kf.js} +1 -1
- package/dist/public/assets/_DUmYv8Kf.js.br +0 -0
- package/dist/public/assets/{_vGfofQqO.js → _DXvsvUmJ.js} +1 -1
- package/dist/public/assets/_DXvsvUmJ.js.br +0 -0
- package/dist/public/assets/{_Cbsfq4Xq.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/{_BzlH6kTq.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/{_DO4kss9P.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/{_C94vR51w.js → _Dh9434oc.js} +1 -1
- package/dist/public/assets/{_9nMouJiN.js → _DjYscMjF.js} +1 -1
- package/dist/public/assets/_DjYscMjF.js.br +0 -0
- package/dist/public/assets/{_De1k3VnO.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/{_P2VZNfpY.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/{_oGfeAy8g.js → _GK8r-gEu.js} +1 -1
- package/dist/public/assets/_GK8r-gEu.js.br +0 -0
- package/dist/public/assets/{_Dt7EUvlj.js → _HpxvfbM2.js} +1 -1
- package/dist/public/assets/_HpxvfbM2.js.br +0 -0
- package/dist/public/assets/{_DGB38_-Q.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/{_BpLGw_gQ.js → _WOU8TCkO.js} +1 -1
- package/dist/public/assets/_WOU8TCkO.js.br +0 -0
- package/dist/public/assets/{_qf-8mlHT.js → _XWw1j8vS.js} +1 -1
- package/dist/public/assets/_XWw1j8vS.js.br +0 -0
- package/dist/public/assets/{_DVeUDVeu.js → _YDyNvOET.js} +1 -1
- package/dist/public/assets/_YDyNvOET.js.br +0 -0
- package/dist/public/assets/{_CQzhv_mX.js → _f8D86HXZ.js} +1 -1
- package/dist/public/assets/_f8D86HXZ.js.br +0 -0
- package/dist/public/assets/{_IIk2IzWK.js → _hbXd8Ogo.js} +1 -1
- package/dist/public/assets/_hbXd8Ogo.js.br +0 -0
- package/dist/public/assets/{_rkCbTrLW.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/{_Gjew_pmJ.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/{_DVevGBhv.js → _o8mJsMHw.js} +1 -1
- package/dist/public/assets/_o8mJsMHw.js.br +0 -0
- package/dist/public/assets/{_DoIAcib0.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/{_Df1iTAvl.js → _rv9KtZHz.js} +1 -1
- package/dist/public/assets/_rv9KtZHz.js.br +0 -0
- package/dist/public/assets/{_CzuoYQDG.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/{_DuaMWtx-.js → _vG7bXn-C.js} +1 -1
- package/dist/public/assets/_vG7bXn-C.js.br +0 -0
- package/dist/public/assets/{_DkvRY2VF.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/{_BcWxCrBn.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/lib/setup/firewall.d.mts +5 -1
- package/lib/setup/firewall.mjs +23 -4
- package/package.json +1 -1
- package/dist/_Bhsm2MDa.js +0 -2
- package/dist/_Bktr58J-.js +0 -167
- package/dist/public/assets/_-LGAXy6L.js +0 -1
- package/dist/public/assets/_1fMDVNSL.js +0 -1
- package/dist/public/assets/_4MxLuDH4.js +0 -1
- package/dist/public/assets/_5fKzV_xm.js.br +0 -0
- package/dist/public/assets/_6uAQn-KZ.js +0 -1
- package/dist/public/assets/_6yZQC8Sj.js +0 -1
- package/dist/public/assets/_8JhYgpHe.js +0 -1
- package/dist/public/assets/_8n8ba3Xr.js.br +0 -0
- package/dist/public/assets/_9nMouJiN.js.br +0 -0
- package/dist/public/assets/_B-Kvhca4.js.br +0 -0
- package/dist/public/assets/_B4jkmqvY.js.br +0 -0
- package/dist/public/assets/_B5aDrGbO.js.br +0 -0
- package/dist/public/assets/_B71hDPcu.js +0 -1
- package/dist/public/assets/_B7XpTOeJ.js +0 -1
- package/dist/public/assets/_BA4Iu42n.js.br +0 -0
- package/dist/public/assets/_BAZwH6Ve.js.br +0 -0
- package/dist/public/assets/_BBZdAtMC.js +0 -1
- package/dist/public/assets/_BBbmRU3k.js.br +0 -0
- package/dist/public/assets/_BCuTz32B.js.br +0 -0
- package/dist/public/assets/_BFZ4oi5n.js +0 -1
- package/dist/public/assets/_BGd-I5rD.js +0 -1
- package/dist/public/assets/_BHp0OMqQ.js +0 -1
- package/dist/public/assets/_BO_dGrB_.js.br +0 -0
- package/dist/public/assets/_BOloI1-O.js +0 -1
- package/dist/public/assets/_BPD5OqbS.js +0 -1
- package/dist/public/assets/_BXZtuyZh.js +0 -1
- package/dist/public/assets/_B_aWrUZM.js +0 -1
- package/dist/public/assets/_B_wTYBYf.js +0 -1
- package/dist/public/assets/_Bbqj4oLG.js +0 -1
- package/dist/public/assets/_BdIL1kV4.js.br +0 -0
- package/dist/public/assets/_Bfa3k3Hb.js.br +0 -0
- package/dist/public/assets/_Bfh0n3cD.js.br +0 -0
- package/dist/public/assets/_BjiY-VzO.js.br +0 -0
- package/dist/public/assets/_Bl5WXdoB.js.br +0 -0
- package/dist/public/assets/_BnsBjEIT.js +0 -1
- package/dist/public/assets/_BnsBjEIT.js.br +0 -0
- package/dist/public/assets/_BpL0bstc.js +0 -2
- package/dist/public/assets/_BpL0bstc.js.br +0 -0
- package/dist/public/assets/_BpLGw_gQ.js.br +0 -0
- package/dist/public/assets/_BqiRi4qy.js +0 -1
- package/dist/public/assets/_Brgs9TFt.js.br +0 -0
- package/dist/public/assets/_BtCVvK2k.js.br +0 -0
- package/dist/public/assets/_BtEgXsuK.js +0 -1
- package/dist/public/assets/_BtEgXsuK.js.br +0 -0
- package/dist/public/assets/_BtN42R2m.js +0 -1
- package/dist/public/assets/_Bv9d1C-N.js +0 -1
- package/dist/public/assets/_BwIqXHWp.js.br +0 -0
- package/dist/public/assets/_BwvpgNRf.js +0 -1
- package/dist/public/assets/_Bx9nWm8r.js +0 -1
- package/dist/public/assets/_Bx9nWm8r.js.br +0 -0
- package/dist/public/assets/_BybJoj1B.js +0 -1
- package/dist/public/assets/_Bync_PH8.js +0 -1
- package/dist/public/assets/_Bync_PH8.js.br +0 -0
- package/dist/public/assets/_BzlH6kTq.js.br +0 -0
- package/dist/public/assets/_C1gXJmH-.js.br +0 -0
- package/dist/public/assets/_C24Yukj9.js +0 -1
- package/dist/public/assets/_C4lapxL9.js.br +0 -0
- package/dist/public/assets/_C634i9Iw.js.br +0 -0
- package/dist/public/assets/_C7n1c5sG.js.br +0 -0
- package/dist/public/assets/_CBMRDyF5.js +0 -1
- package/dist/public/assets/_CBcx1kOh.js.br +0 -0
- package/dist/public/assets/_CDLK6m8H.js +0 -1
- package/dist/public/assets/_CGmPVd6x.js +0 -1
- package/dist/public/assets/_CHWlI8eM.js.br +0 -0
- package/dist/public/assets/_CIiNyABw.js +0 -1
- package/dist/public/assets/_CJDXsoZG.js.br +0 -0
- package/dist/public/assets/_CKpKOqv6.js +0 -1
- package/dist/public/assets/_CLaHO3fE.js.br +0 -0
- package/dist/public/assets/_CMbRT0RN.js +0 -1
- package/dist/public/assets/_CNiymwwH.js +0 -1
- package/dist/public/assets/_CNramc89.js.br +0 -0
- package/dist/public/assets/_COjSvk7K.js +0 -1
- package/dist/public/assets/_CPakGo19.js.br +0 -0
- package/dist/public/assets/_CQIzzFRZ.js.br +0 -0
- package/dist/public/assets/_CQzhv_mX.js.br +0 -0
- package/dist/public/assets/_CRfRDlj2.js +0 -1
- package/dist/public/assets/_CSp3_AhQ.js +0 -1
- package/dist/public/assets/_CU-yRMtu.js +0 -6
- package/dist/public/assets/_CU-yRMtu.js.br +0 -0
- package/dist/public/assets/_CUPj7ARi.js +0 -1
- package/dist/public/assets/_CVBq_iEC.js +0 -1
- package/dist/public/assets/_CVxQyHtq.js.br +0 -0
- package/dist/public/assets/_CYEdfiVK.js +0 -1
- package/dist/public/assets/_CYNWm9iq.js +0 -1
- package/dist/public/assets/_Ca-c93LZ.js +0 -1
- package/dist/public/assets/_Ca4BTBEZ.js +0 -1
- package/dist/public/assets/_Ca4BTBEZ.js.br +0 -0
- package/dist/public/assets/_CbWILCnD.js +0 -1
- package/dist/public/assets/_Cbjd3Q9T.js +0 -2
- package/dist/public/assets/_Cbjd3Q9T.js.br +0 -0
- package/dist/public/assets/_Cbsfq4Xq.js.br +0 -0
- package/dist/public/assets/_CfM615kO.js.br +0 -0
- package/dist/public/assets/_Cfge4b__.js +0 -1
- package/dist/public/assets/_Cg7H9vg0.js +0 -1
- package/dist/public/assets/_CkOLwn-O.js.br +0 -0
- package/dist/public/assets/_ClJiup1H.js +0 -1
- package/dist/public/assets/_CpU9EtMF.js +0 -1
- package/dist/public/assets/_CpU9EtMF.js.br +0 -0
- package/dist/public/assets/_Cq8bC13s.js +0 -1
- package/dist/public/assets/_CrJYhl4C.js.br +0 -0
- package/dist/public/assets/_CvHnOFNG.js.br +0 -0
- package/dist/public/assets/_Cxhfb-mP.js.br +0 -0
- package/dist/public/assets/_CzSlKec6.js +0 -1
- package/dist/public/assets/_CzuoYQDG.js.br +0 -0
- package/dist/public/assets/_D4JoXfrO.js.br +0 -0
- package/dist/public/assets/_D5-Xbg1R.js.br +0 -0
- package/dist/public/assets/_D5woWAW8.js.br +0 -0
- package/dist/public/assets/_D99Wlj0O.js +0 -1
- package/dist/public/assets/_D9_2hMWP.js.br +0 -0
- package/dist/public/assets/_DC_EInc4.js +0 -1
- package/dist/public/assets/_DCgPMOAm.js +0 -1
- package/dist/public/assets/_DDDY02_q.js.br +0 -0
- package/dist/public/assets/_DDuN0b6I.js +0 -1
- package/dist/public/assets/_DEm5vgv_.js +0 -1
- package/dist/public/assets/_DFBqmRUc.js +0 -1
- package/dist/public/assets/_DGB38_-Q.js.br +0 -0
- package/dist/public/assets/_DHwe--xJ.js +0 -1
- package/dist/public/assets/_DK_ROILU.js +0 -1
- package/dist/public/assets/_DLUV6ZQ4.js +0 -1
- package/dist/public/assets/_DLbIAQvl.js.br +0 -0
- package/dist/public/assets/_DMWoxRSc.js +0 -16
- package/dist/public/assets/_DMWoxRSc.js.br +0 -0
- package/dist/public/assets/_DNekcg31.js +0 -1
- package/dist/public/assets/_DO4kss9P.js.br +0 -0
- package/dist/public/assets/_DOpQqgoi.js +0 -1
- package/dist/public/assets/_DRDoh9gX.js +0 -1
- package/dist/public/assets/_DRfZHwBJ.js.br +0 -0
- package/dist/public/assets/_DSUWiRRK.js.br +0 -0
- package/dist/public/assets/_DSw-4lX2.js.br +0 -0
- package/dist/public/assets/_DUQz9QdQ.js +0 -1
- package/dist/public/assets/_DUb2rGXm.js +0 -1
- package/dist/public/assets/_DUb2rGXm.js.br +0 -0
- package/dist/public/assets/_DVOLp04e.js.br +0 -0
- package/dist/public/assets/_DVeUDVeu.js.br +0 -0
- package/dist/public/assets/_DVevGBhv.js.br +0 -0
- package/dist/public/assets/_DW7N6KAK.js.br +0 -0
- package/dist/public/assets/_DXn7VNFu.js +0 -1
- package/dist/public/assets/_DYH0eCbn.js.br +0 -0
- package/dist/public/assets/_DYUAPXDQ.js.br +0 -0
- package/dist/public/assets/_DbODstMe.js +0 -1
- package/dist/public/assets/_Dc7kGfRQ.js +0 -1
- package/dist/public/assets/_De1k3VnO.js.br +0 -0
- package/dist/public/assets/_Df1iTAvl.js.br +0 -0
- package/dist/public/assets/_DgYlRNTv.js +0 -1
- package/dist/public/assets/_DjQSx1cs.js +0 -1
- package/dist/public/assets/_DkvRY2VF.js.br +0 -0
- package/dist/public/assets/_DoIAcib0.js.br +0 -0
- package/dist/public/assets/_Dt7EUvlj.js.br +0 -0
- package/dist/public/assets/_DuaMWtx-.js.br +0 -0
- package/dist/public/assets/_Dy3vjhI9.js.br +0 -0
- package/dist/public/assets/_G9Zy20B_.js.br +0 -0
- package/dist/public/assets/_Gjew_pmJ.js.br +0 -0
- package/dist/public/assets/_HCEgTdm1.js +0 -1
- package/dist/public/assets/_Hak9GZSq.js +0 -1
- package/dist/public/assets/_HlShuyJR.js.br +0 -0
- package/dist/public/assets/_Hu1xz4Lu.js.br +0 -0
- package/dist/public/assets/_IIk2IzWK.js.br +0 -0
- package/dist/public/assets/_JCQQIgqJ.js +0 -1
- package/dist/public/assets/_LzgGPkGH.js +0 -1
- package/dist/public/assets/_N96Oqzt6.js +0 -1
- package/dist/public/assets/_OSMLzC7w.js +0 -1
- package/dist/public/assets/_P2VZNfpY.js.br +0 -0
- package/dist/public/assets/_Tj4gwE2h.js +0 -1
- package/dist/public/assets/_UgBaqmVR.js +0 -1
- package/dist/public/assets/_VV8USAwR.js +0 -1
- package/dist/public/assets/_XWoqVB1l.js +0 -1
- package/dist/public/assets/_YRsH_Jn5.js.br +0 -0
- package/dist/public/assets/_aY3LCTY6.js.br +0 -0
- package/dist/public/assets/_b3iaRNRr.js +0 -1
- package/dist/public/assets/_cKcWLQPj.js +0 -1
- package/dist/public/assets/_cVTJMvgA.js +0 -1
- package/dist/public/assets/_fTrEfQgl.js +0 -1
- package/dist/public/assets/_gIdf7Xw5.js.br +0 -0
- package/dist/public/assets/_hlPeODrN.js +0 -1
- package/dist/public/assets/_hvh7Kn8G.js.br +0 -0
- package/dist/public/assets/_joWx_YVF.js +0 -1
- package/dist/public/assets/_k1dlXWES.js +0 -1
- package/dist/public/assets/_kPqXo7z9.js +0 -86
- package/dist/public/assets/_kPqXo7z9.js.br +0 -0
- package/dist/public/assets/_o-w-GRlW.js.br +0 -0
- package/dist/public/assets/_oGfeAy8g.js.br +0 -0
- package/dist/public/assets/_qf-8mlHT.js.br +0 -0
- package/dist/public/assets/_qiP5PaTJ.js.br +0 -0
- package/dist/public/assets/_rkCbTrLW.js.br +0 -0
- package/dist/public/assets/_vGfofQqO.js.br +0 -0
- package/dist/public/assets/_x9gsUMHG.js.br +0 -0
- package/dist/public/assets/_xh9Gonv9.js +0 -1
- package/dist/public/assets/files-view-BAyLKvRK.js +0 -2
- package/dist/public/assets/manage-workspace-B2x5MV3x.js +0 -2
- package/dist/public/assets/new-BYYj4BqJ.js +0 -1
- package/dist/public/assets/new-workspace-Der44YSz.js +0 -2
- package/dist/public/assets/review-view-DKfw2IXZ.js +0 -2
- package/dist/public/assets/settings-BYYj4BqJ.js +0 -1
- package/dist/public/assets/settings-page-C2QJm3t_.js +0 -2
- package/dist/public/assets/styles-Dh_Zl9g6.css +0 -1
- package/dist/public/assets/styles-Dh_Zl9g6.css.br +0 -0
- package/dist/public/assets/w-BYYj4BqJ.js +0 -1
- package/dist/public/assets/w._-BYYj4BqJ.js +0 -1
- package/dist/public/assets/w._-DiowwH3T.js +0 -1
- package/dist/public/assets/w._-jtiTmGZc.js +0 -1
package/bin/work.mjs
CHANGED
|
@@ -5,18 +5,27 @@
|
|
|
5
5
|
// (--tailscale serves work on the tailnet with `tailscale serve`, which
|
|
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
|
-
// firewall that
|
|
9
|
-
// which it otherwise offers; --no-firewall skips that
|
|
8
|
+
// firewall that may drop it, or on macOS lets the service's node in,
|
|
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";
|
|
@@ -45,6 +60,7 @@ import {
|
|
|
45
60
|
import { allowHost, stateText } from "../lib/setup/tailscale.mjs";
|
|
46
61
|
import {
|
|
47
62
|
applyPlan,
|
|
63
|
+
dropText,
|
|
48
64
|
firewallProbe,
|
|
49
65
|
serviceNode,
|
|
50
66
|
} from "../lib/setup/firewall.mjs";
|
|
@@ -54,6 +70,7 @@ import { dialHost, listenStream } from "../lib/setup/listen.mjs";
|
|
|
54
70
|
import { commentMarkdown } from "../lib/review/markdown.mjs";
|
|
55
71
|
import { formatInvite, parseInvite } from "../lib/share/manifest.mjs";
|
|
56
72
|
import { duration, pctText } from "../lib/usage/format.mjs";
|
|
73
|
+
import { locOf, portBlockedAt, portUrlAt } from "../lib/ports/url.mjs";
|
|
57
74
|
|
|
58
75
|
const pkgRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
59
76
|
const pkg = JSON.parse(
|
|
@@ -62,7 +79,10 @@ const pkg = JSON.parse(
|
|
|
62
79
|
const distEntry = path.join(pkgRoot, "dist", "index.mjs");
|
|
63
80
|
const appPort = process.env.WORK_APP_PORT || "7171";
|
|
64
81
|
|
|
65
|
-
|
|
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);
|
|
66
86
|
const warn = (msg) => console.warn(`warning: ${msg}`);
|
|
67
87
|
const die = (msg) => {
|
|
68
88
|
console.error(`error: ${msg}`);
|
|
@@ -78,6 +98,12 @@ const sh = (cmd, args, opts = {}) =>
|
|
|
78
98
|
const [, , command = "help", ...args] = process.argv;
|
|
79
99
|
const yes = args.includes("--yes") || args.includes("-y");
|
|
80
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;
|
|
81
107
|
/** `--name <value>` style flags take the next arg; keep it out of the
|
|
82
108
|
* positionals so `work join --name x` still reads stdin. */
|
|
83
109
|
const VALUED = new Set(["--name", "--allow"]);
|
|
@@ -100,7 +126,20 @@ const flagValues = (flag) =>
|
|
|
100
126
|
return [args[i + 1]];
|
|
101
127
|
});
|
|
102
128
|
|
|
103
|
-
|
|
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;
|
|
104
143
|
case "start":
|
|
105
144
|
await start();
|
|
106
145
|
break;
|
|
@@ -168,9 +207,10 @@ switch (command) {
|
|
|
168
207
|
console.log(pkg.version);
|
|
169
208
|
break;
|
|
170
209
|
default:
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
);
|
|
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;
|
|
174
214
|
}
|
|
175
215
|
|
|
176
216
|
async function start() {
|
|
@@ -231,18 +271,38 @@ function serverUrl() {
|
|
|
231
271
|
return `http://${dialHost(env.WORK_LISTEN)}:${env.PORT}`;
|
|
232
272
|
}
|
|
233
273
|
|
|
234
|
-
|
|
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) {
|
|
235
277
|
const port = serviceEnv().PORT;
|
|
278
|
+
let res;
|
|
236
279
|
try {
|
|
237
|
-
|
|
238
|
-
|
|
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),
|
|
239
286
|
});
|
|
240
|
-
|
|
241
|
-
return await res.json();
|
|
242
|
-
} catch (err) {
|
|
243
|
-
if (err?.message?.startsWith("server answered")) throw err;
|
|
287
|
+
} catch {
|
|
244
288
|
die(`no work server on port ${port}. Start one with: work start`);
|
|
245
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);
|
|
246
306
|
}
|
|
247
307
|
|
|
248
308
|
/**
|
|
@@ -254,7 +314,7 @@ async function apiGet(path) {
|
|
|
254
314
|
async function resolveWorkspace(arg) {
|
|
255
315
|
const [list, status] = await Promise.all([
|
|
256
316
|
apiGet("/api/workspaces"),
|
|
257
|
-
apiGet(
|
|
317
|
+
apiGet(statusPath()),
|
|
258
318
|
]);
|
|
259
319
|
let ws;
|
|
260
320
|
if (arg) {
|
|
@@ -293,10 +353,17 @@ function pad(s, n) {
|
|
|
293
353
|
return String(s ?? "").padEnd(n);
|
|
294
354
|
}
|
|
295
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
|
+
|
|
296
363
|
async function workspacesCmd() {
|
|
297
364
|
const [list, status] = await Promise.all([
|
|
298
365
|
apiGet("/api/workspaces"),
|
|
299
|
-
apiGet(
|
|
366
|
+
apiGet(statusPath()),
|
|
300
367
|
]);
|
|
301
368
|
const rows = list.map((w) => ({ ...w, ...(status[w.id] || {}) }));
|
|
302
369
|
if (jsonOut) return console.log(JSON.stringify(rows, null, 2));
|
|
@@ -322,21 +389,26 @@ function prLine(pr) {
|
|
|
322
389
|
: pr.isDraft
|
|
323
390
|
? "draft"
|
|
324
391
|
: "open";
|
|
325
|
-
return `#${pr.number} ${state} ${pr.title} ${pr.url}`;
|
|
392
|
+
return `#${pr.number} ${state} ${pr.title}${pr.headRefName ? ` (${pr.headRefName})` : ""} ${pr.url}`;
|
|
326
393
|
}
|
|
327
394
|
|
|
328
395
|
async function workspaceCmd() {
|
|
329
396
|
const { ws, status } = await resolveWorkspace(positional[0]);
|
|
330
397
|
const procs = await apiGet(`/api/workspaces/${ws.id}/procs`).catch(() => []);
|
|
331
|
-
const [sessions] = await Promise.all([
|
|
398
|
+
const [sessions, linkPort] = await Promise.all([
|
|
332
399
|
apiGet(`/api/workspaces/${ws.id}/sessions`).catch(() => []),
|
|
400
|
+
portLinker(),
|
|
333
401
|
]);
|
|
402
|
+
const me = process.env.WORK_SESSION_ID;
|
|
334
403
|
const out = {
|
|
335
404
|
...ws,
|
|
336
|
-
ports: status.ports
|
|
405
|
+
ports: (status.ports || []).map((p) => ({
|
|
406
|
+
...p,
|
|
407
|
+
...linkPort(p.port, p.local),
|
|
408
|
+
})),
|
|
337
409
|
repos: mergeRepos(ws, status),
|
|
338
|
-
sessions,
|
|
339
|
-
procs,
|
|
410
|
+
sessions: sessions.map((s) => (s.id === me ? { ...s, self: true } : s)),
|
|
411
|
+
procs: procs.map((p) => withUrls(p, linkPort)),
|
|
340
412
|
};
|
|
341
413
|
if (jsonOut) return console.log(JSON.stringify(out, null, 2));
|
|
342
414
|
console.log(`${ws.name} (${ws.status})`);
|
|
@@ -351,16 +423,58 @@ async function workspaceCmd() {
|
|
|
351
423
|
console.log(` sessions:`);
|
|
352
424
|
for (const s of sessions) {
|
|
353
425
|
const phase = s.state?.phase || (s.state?.alive ? "idle" : "off");
|
|
354
|
-
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
|
+
);
|
|
355
429
|
}
|
|
356
430
|
}
|
|
357
431
|
if (procs.length) {
|
|
358
432
|
console.log(` running:`);
|
|
359
|
-
for (const p of procs)
|
|
360
|
-
console.log(
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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(" ")}`;
|
|
364
478
|
}
|
|
365
479
|
|
|
366
480
|
/** Workspace repos joined with the status snapshot's PRs per repo. */
|
|
@@ -386,13 +500,15 @@ async function reposCmd() {
|
|
|
386
500
|
|
|
387
501
|
async function procsCmd() {
|
|
388
502
|
const { ws } = await resolveWorkspace(positional[0]);
|
|
389
|
-
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));
|
|
390
508
|
if (jsonOut) return console.log(JSON.stringify(procs, null, 2));
|
|
391
509
|
if (!procs.length) return console.log("nothing running");
|
|
392
510
|
for (const p of procs)
|
|
393
|
-
console.log(
|
|
394
|
-
`${pad(p.pid, 7)} ${p.cmd}${p.ports?.length ? " " + p.ports.map((x) => `:${x}`).join(" ") : ""}`,
|
|
395
|
-
);
|
|
511
|
+
console.log(`${pad(p.pid, 7)} ${p.cmd}${portsText(p)}`);
|
|
396
512
|
}
|
|
397
513
|
|
|
398
514
|
/** Comments left on the review page but not yet sent: an agent can pull
|
|
@@ -401,9 +517,23 @@ async function procsCmd() {
|
|
|
401
517
|
async function reviewCmd() {
|
|
402
518
|
const { ws } = await resolveWorkspace(positional[0]);
|
|
403
519
|
const { comments = [] } = await apiGet(`/api/workspaces/${ws.id}/review`);
|
|
404
|
-
if (jsonOut)
|
|
405
|
-
if (!comments.length)
|
|
406
|
-
|
|
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
|
+
}
|
|
407
537
|
}
|
|
408
538
|
|
|
409
539
|
/** The diff's sections, which say which lane or PR a comment's lines are
|
|
@@ -412,41 +542,25 @@ async function reviewCmd() {
|
|
|
412
542
|
* comments then read as the checkout's rather than failing the command. */
|
|
413
543
|
async function reviewSections(wsId, comments) {
|
|
414
544
|
if (!comments.some((c) => c.head)) return null;
|
|
415
|
-
const port = serviceEnv().PORT;
|
|
416
545
|
try {
|
|
417
|
-
const res = await fetch(
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
);
|
|
546
|
+
const res = await fetch(`${serverUrl()}/api/workspaces/${wsId}/diff`, {
|
|
547
|
+
signal: AbortSignal.timeout(60_000),
|
|
548
|
+
});
|
|
421
549
|
return res.ok ? ((await res.json()).sections ?? null) : null;
|
|
422
550
|
} catch {
|
|
423
551
|
return null;
|
|
424
552
|
}
|
|
425
553
|
}
|
|
426
554
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
try {
|
|
431
|
-
res = await fetch(`${serverUrl()}${path}`, {
|
|
432
|
-
method: "POST",
|
|
433
|
-
headers: { "content-type": "application/json" },
|
|
434
|
-
body: body === undefined ? undefined : JSON.stringify(body),
|
|
435
|
-
signal: AbortSignal.timeout(15 * 60_000),
|
|
436
|
-
});
|
|
437
|
-
} catch {
|
|
438
|
-
die(`no work server on port ${port}. Start one with: work start`);
|
|
439
|
-
}
|
|
440
|
-
const data = await res.json().catch(() => ({}));
|
|
441
|
-
if (!res.ok || data.error)
|
|
442
|
-
die(data.error || `server answered ${res.status} for ${path}`);
|
|
443
|
-
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);
|
|
444
558
|
}
|
|
445
559
|
|
|
446
560
|
/** One line per workspace/repo of what the file will not carry. */
|
|
447
561
|
function printPreflight(found) {
|
|
448
562
|
for (const w of found.workspaces) {
|
|
449
|
-
|
|
563
|
+
say(w.name);
|
|
450
564
|
for (const r of w.repos) {
|
|
451
565
|
const parts = [];
|
|
452
566
|
for (const b of r.unpushed)
|
|
@@ -455,10 +569,10 @@ function printPreflight(found) {
|
|
|
455
569
|
if (r.untracked.length) parts.push(`${r.untracked.length} untracked`);
|
|
456
570
|
if (r.ignored.length) parts.push(`${r.ignored.length} ignored`);
|
|
457
571
|
if (r.more) parts.push(`+${r.more} more`);
|
|
458
|
-
|
|
459
|
-
for (const f of r.modified)
|
|
460
|
-
for (const f of r.untracked)
|
|
461
|
-
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}`);
|
|
462
576
|
}
|
|
463
577
|
}
|
|
464
578
|
}
|
|
@@ -476,7 +590,7 @@ async function exportCmd() {
|
|
|
476
590
|
);
|
|
477
591
|
}
|
|
478
592
|
if (found.workspaces.length) {
|
|
479
|
-
|
|
593
|
+
say("not in the backup:");
|
|
480
594
|
printPreflight(found);
|
|
481
595
|
if (!yes) {
|
|
482
596
|
console.log("");
|
|
@@ -497,6 +611,18 @@ async function exportCmd() {
|
|
|
497
611
|
"work-backup.json";
|
|
498
612
|
fs.writeFileSync(name, await res.text());
|
|
499
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
|
+
);
|
|
500
626
|
}
|
|
501
627
|
|
|
502
628
|
function readManifest(file) {
|
|
@@ -657,6 +783,8 @@ function until(iso) {
|
|
|
657
783
|
}
|
|
658
784
|
|
|
659
785
|
async function setup() {
|
|
786
|
+
// First: a bad name fails before anything is touched.
|
|
787
|
+
editAllowedHosts();
|
|
660
788
|
await bridge();
|
|
661
789
|
const d = await doctor(doctorOpts());
|
|
662
790
|
await fix(d);
|
|
@@ -669,13 +797,30 @@ async function setup() {
|
|
|
669
797
|
const port = serviceEnv().PORT;
|
|
670
798
|
if (!tailnet) maybeTunnel(port);
|
|
671
799
|
if (running) {
|
|
672
|
-
|
|
673
|
-
|
|
800
|
+
const answered = await waitForServer();
|
|
801
|
+
if (answered) log(`done — http://localhost:${port}`);
|
|
802
|
+
else {
|
|
674
803
|
warn(
|
|
675
804
|
`service started but nothing answered on port ${port} within 30s — check the logs`,
|
|
676
805
|
);
|
|
806
|
+
// A setup that left no server is a failed one, to whatever ran it.
|
|
807
|
+
process.exitCode = 1;
|
|
808
|
+
}
|
|
677
809
|
if (tailnet)
|
|
678
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
|
+
);
|
|
679
824
|
} else {
|
|
680
825
|
// A fresh install's shell may not have mise on PATH yet — name the shim.
|
|
681
826
|
const shim = path.join(
|
|
@@ -693,6 +838,34 @@ async function setup() {
|
|
|
693
838
|
}
|
|
694
839
|
}
|
|
695
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
|
+
|
|
696
869
|
/** Bring a database from before 0.1 to the baseline this release starts
|
|
697
870
|
* from (lib/setup/bridge.mjs), before anything touches the service: the
|
|
698
871
|
* server it would restart refuses such a database. Run with the settings
|
|
@@ -744,22 +917,35 @@ async function update() {
|
|
|
744
917
|
// `--prefer-online`: npm serves `latest` from a cached packument for a
|
|
745
918
|
// few minutes after a publish, so an update right behind a release
|
|
746
919
|
// reinstalled the version already running.
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
"
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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
|
+
);
|
|
754
933
|
// Re-exec the (possibly new) CLI to finish with fresh code.
|
|
755
934
|
sh("work", [
|
|
756
935
|
"setup",
|
|
757
936
|
...(yes ? ["--yes"] : []),
|
|
758
937
|
...args.filter((a) =>
|
|
759
|
-
[
|
|
760
|
-
|
|
761
|
-
|
|
938
|
+
[
|
|
939
|
+
"--tailscale",
|
|
940
|
+
"--no-tailscale",
|
|
941
|
+
"--firewall",
|
|
942
|
+
"--no-firewall",
|
|
943
|
+
"--json",
|
|
944
|
+
"--non-interactive",
|
|
945
|
+
].includes(a),
|
|
762
946
|
),
|
|
947
|
+
...flagValues("--allow-host").flatMap((h) => ["--allow-host", h]),
|
|
948
|
+
...flagValues("--disallow-host").flatMap((h) => ["--disallow-host", h]),
|
|
763
949
|
]);
|
|
764
950
|
}
|
|
765
951
|
|
|
@@ -975,7 +1161,7 @@ async function fix(d) {
|
|
|
975
1161
|
}
|
|
976
1162
|
log(`installing ${tool.label} via ${tool.mise ? "mise" : "gh"}`);
|
|
977
1163
|
try {
|
|
978
|
-
await installTool(tool.id, { log: (l) =>
|
|
1164
|
+
await installTool(tool.id, { log: (l) => say(` ${l}`) });
|
|
979
1165
|
} catch (err) {
|
|
980
1166
|
if (tool.required) die(`${tool.label} install failed: ${err.message}`);
|
|
981
1167
|
warn(`${tool.label} install failed (non-fatal)`);
|
|
@@ -1641,7 +1827,7 @@ async function firewall() {
|
|
|
1641
1827
|
if (asked) log(`${f.what} already admits UDP ${f.port}`);
|
|
1642
1828
|
return;
|
|
1643
1829
|
}
|
|
1644
|
-
const drops = `${
|
|
1830
|
+
const drops = `${dropText(f)}, which direct connections from your other devices use`;
|
|
1645
1831
|
if (!f.plan.length) {
|
|
1646
1832
|
if (asked || !yes) warn(`${drops}: ${f.fix}`);
|
|
1647
1833
|
return;
|
|
@@ -1740,6 +1926,7 @@ function allowTailnet(serve) {
|
|
|
1740
1926
|
* controlling terminal, since the curl installer pipes its script into the
|
|
1741
1927
|
* shell this runs under. Null with no terminal at all. */
|
|
1742
1928
|
function terminal() {
|
|
1929
|
+
if (!interactive) return null;
|
|
1743
1930
|
if (process.stdin.isTTY) return process.stdin;
|
|
1744
1931
|
try {
|
|
1745
1932
|
return new tty.ReadStream(fs.openSync("/dev/tty", "r"));
|
|
@@ -1762,3 +1949,139 @@ async function confirm(input, question) {
|
|
|
1762
1949
|
rl.close();
|
|
1763
1950
|
}
|
|
1764
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
|
+
}
|