@dylanpiercey/work 0.2.17 → 0.2.19
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 -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 +296 -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 +411 -80
- package/dist/{_Bj-WwfnW.js → _CsokArOR.js} +183 -59
- package/dist/_L2HNAA_8.js +2 -0
- package/dist/__TCdgPY5.js +173 -0
- package/dist/index.mjs +3917 -2606
- package/dist/public/assets/{_C9jR1P3s.js → _-7Amnss4.js} +1 -1
- package/dist/public/assets/_-7Amnss4.js.br +0 -0
- package/dist/public/assets/_0XXNUttq.js +1 -0
- package/dist/public/assets/{_CIrZGxEf.js → _0sTkxfPx.js} +1 -1
- package/dist/public/assets/_0sTkxfPx.js.br +0 -0
- package/dist/public/assets/_0zzYbK0A.js +1 -0
- package/dist/public/assets/{_CJgqLdsx.js → _1M3oZPSf.js} +1 -1
- package/dist/public/assets/_1M3oZPSf.js.br +0 -0
- package/dist/public/assets/_2O5HnHht.js +1 -0
- package/dist/public/assets/_7WlUaJPH.js +1 -0
- package/dist/public/assets/_8Tr7ByPg.js +1 -0
- package/dist/public/assets/_9AXMmQSO.js +1 -0
- package/dist/public/assets/_B1VqbV-X.js +1 -0
- package/dist/public/assets/{_BxS3xvmE.js → _B9I2AEux.js} +1 -1
- package/dist/public/assets/_B9I2AEux.js.br +0 -0
- package/dist/public/assets/{_DO_4_u2Q.js → _B9qGqvit.js} +1 -1
- package/dist/public/assets/{_CIWiehYG.js → _B9xuaMHt.js} +1 -1
- package/dist/public/assets/_B9xuaMHt.js.br +0 -0
- package/dist/public/assets/{_BqWlTTxo.js → _BAWjkhA8.js} +1 -1
- package/dist/public/assets/_BAWjkhA8.js.br +0 -0
- package/dist/public/assets/{_CNUs2Gqk.js → _BBCzcNZY.js} +1 -1
- package/dist/public/assets/_BBCzcNZY.js.br +0 -0
- package/dist/public/assets/_BBW2szHh.js +1 -0
- package/dist/public/assets/_BCP2Njnu.js +1 -0
- package/dist/public/assets/{_A-jpjc8j.js → _BClUYs-k.js} +1 -1
- package/dist/public/assets/_BClUYs-k.js.br +0 -0
- package/dist/public/assets/{_B5JxE4Sx.js → _BDdZkZRc.js} +1 -1
- package/dist/public/assets/_BDdZkZRc.js.br +0 -0
- package/dist/public/assets/_BEDmGSgS.js +1 -0
- package/dist/public/assets/_BEDmGSgS.js.br +0 -0
- package/dist/public/assets/_BH9BIky6.js +1 -0
- package/dist/public/assets/_BH9BIky6.js.br +0 -0
- package/dist/public/assets/_BLdi8Ee5.js +1 -0
- package/dist/public/assets/{_C449plW0.js → _BPDSQUbl.js} +1 -1
- package/dist/public/assets/_BPDSQUbl.js.br +0 -0
- package/dist/public/assets/{_B19mS3yM.js → _BQW1kIop.js} +1 -1
- package/dist/public/assets/_BQW1kIop.js.br +0 -0
- package/dist/public/assets/_BQeoUfFw.js +1 -0
- package/dist/public/assets/_BRzroLbh.js +1 -0
- package/dist/public/assets/_BSXsTYSe.js +1 -0
- package/dist/public/assets/_BTXDT3Na.js +1 -0
- package/dist/public/assets/_BXm4xeFI.js +1 -0
- package/dist/public/assets/_BY8UeogK.js +1 -0
- package/dist/public/assets/_BYpyhp64.js +1 -0
- package/dist/public/assets/_BYpyhp64.js.br +0 -0
- package/dist/public/assets/_B_Kz7LnY.js +1 -0
- package/dist/public/assets/{_DqGOYRpi.js → _Bcc0Xs64.js} +1 -1
- package/dist/public/assets/_Bcc0Xs64.js.br +0 -0
- package/dist/public/assets/{_Do6b-nfX.js → _BdSsUhCi.js} +1 -1
- package/dist/public/assets/_BdSsUhCi.js.br +0 -0
- package/dist/public/assets/_BdaWssEH.js +1 -0
- package/dist/public/assets/{_BHyWcuOR.js → _BhecGD7y.js} +1 -1
- package/dist/public/assets/_BhecGD7y.js.br +0 -0
- package/dist/public/assets/_Bj9dpPhN.js +1 -0
- package/dist/public/assets/{_DorQTaAa.js → _BjZqS7za.js} +1 -1
- package/dist/public/assets/_BjZqS7za.js.br +0 -0
- package/dist/public/assets/_BkSUiyHK.js +1 -0
- package/dist/public/assets/_BlshXH2Y.js +16 -0
- package/dist/public/assets/_BlshXH2Y.js.br +0 -0
- package/dist/public/assets/_BmX-VP7w.js +1 -0
- package/dist/public/assets/{_v3HPnNBs.js → _BmpOmFbo.js} +1 -1
- package/dist/public/assets/_BmpOmFbo.js.br +0 -0
- package/dist/public/assets/_Bo6YntUl.js +1 -0
- package/dist/public/assets/_BprZx4vg.js +2 -0
- package/dist/public/assets/_BprZx4vg.js.br +0 -0
- package/dist/public/assets/_Bqm7OnIV.js +1 -0
- package/dist/public/assets/_BquBGUNK.js +1 -0
- package/dist/public/assets/_BquBGUNK.js.br +0 -0
- package/dist/public/assets/_BrB66aRZ.js +1 -0
- package/dist/public/assets/{_BA-MNdjL.js → _Bt03HU8S.js} +1 -1
- package/dist/public/assets/{_BTWfPOi-.js → _BtedGrGs.js} +1 -1
- package/dist/public/assets/_BtedGrGs.js.br +0 -0
- package/dist/public/assets/{_DUdEYxV0.js → _C-BYkx5h.js} +1 -1
- package/dist/public/assets/_C-BYkx5h.js.br +0 -0
- package/dist/public/assets/{_BUW_V5kN.js → _C-DhXiEm.js} +1 -1
- package/dist/public/assets/_C-DhXiEm.js.br +0 -0
- package/dist/public/assets/_C-NBFnST.js +1 -0
- package/dist/public/assets/{_BoTzWlXR.js → _C1RigMYD.js} +1 -1
- package/dist/public/assets/_C1RigMYD.js.br +0 -0
- package/dist/public/assets/_C2vRS-ES.js +1 -0
- package/dist/public/assets/{_CrlNjDih.js → _C3fslTAD.js} +1 -1
- package/dist/public/assets/_C3fslTAD.js.br +0 -0
- package/dist/public/assets/{_BuMTHEPk.js → _C4EYjWGn.js} +1 -1
- package/dist/public/assets/_C4EYjWGn.js.br +0 -0
- package/dist/public/assets/{_yp48NYOW.js → _C6Yt6h_R.js} +1 -1
- package/dist/public/assets/_C6Yt6h_R.js.br +0 -0
- package/dist/public/assets/{_cyorvuL1.js → _C7Y4xApK.js} +1 -1
- package/dist/public/assets/_C7Y4xApK.js.br +0 -0
- package/dist/public/assets/{_D4CkNo0r.js → _CB52LkYt.js} +1 -1
- package/dist/public/assets/_CB52LkYt.js.br +0 -0
- package/dist/public/assets/{_CxgPm_xy.js → _CBEKHwUV.js} +1 -1
- package/dist/public/assets/_CBEKHwUV.js.br +0 -0
- package/dist/public/assets/_CBSLBYQF.js +1 -0
- package/dist/public/assets/_CBgzBB_k.js +1 -0
- package/dist/public/assets/_CBgzBB_k.js.br +0 -0
- package/dist/public/assets/{_CCONYsJT.js → _CCoTlnvb.js} +1 -1
- package/dist/public/assets/_CCoTlnvb.js.br +0 -0
- package/dist/public/assets/_CD26To-f.js +1 -0
- package/dist/public/assets/_CDyWgQ0v.js +6 -0
- package/dist/public/assets/_CDyWgQ0v.js.br +0 -0
- package/dist/public/assets/{_vX9d6g5Y.js → _CEC5O89D.js} +1 -1
- package/dist/public/assets/_CEC5O89D.js.br +0 -0
- package/dist/public/assets/_CF2kEAU7.js +1 -0
- package/dist/public/assets/_CFURqbmO.js +1 -0
- package/dist/public/assets/{_Cwtn28hL.js → _CG383oZY.js} +1 -1
- package/dist/public/assets/_CG383oZY.js.br +0 -0
- package/dist/public/assets/_CHNJosg3.js +1 -0
- package/dist/public/assets/{_Cc_GUPR4.js → _CHmEM8Sm.js} +1 -1
- package/dist/public/assets/_CHmEM8Sm.js.br +0 -0
- package/dist/public/assets/_CIfCdAzS.js +1 -0
- package/dist/public/assets/_CKyzH0fl.js +1 -0
- package/dist/public/assets/{_BCB8LQS3.js → _CL8DzBla.js} +1 -1
- package/dist/public/assets/_CL8DzBla.js.br +0 -0
- package/dist/public/assets/_CNYS94C5.js +1 -0
- package/dist/public/assets/_CNhypHJN.js +1 -0
- package/dist/public/assets/_CO-FkxlA.js +1 -0
- package/dist/public/assets/_COiGBSpO.js +1 -0
- package/dist/public/assets/_COvolvRQ.js +1 -0
- package/dist/public/assets/{_Di78jTI-.js → _CPaMvBMG.js} +1 -1
- package/dist/public/assets/_CPaMvBMG.js.br +0 -0
- package/dist/public/assets/{_C7bHTlG1.js → _CPj_VL66.js} +1 -1
- package/dist/public/assets/_CPj_VL66.js.br +0 -0
- package/dist/public/assets/_CQJC8Vx4.js +1 -0
- package/dist/public/assets/_CRHNlzBC.js +1 -0
- package/dist/public/assets/{_C1-Nli75.js → _CToqok6Q.js} +1 -1
- package/dist/public/assets/_CToqok6Q.js.br +0 -0
- package/dist/public/assets/_CUFKkl0B.js +1 -0
- package/dist/public/assets/_CZsOUa-q.js +1 -0
- package/dist/public/assets/{_D8uBvHXU.js → _C_D5TPb7.js} +1 -1
- package/dist/public/assets/_C_D5TPb7.js.br +0 -0
- package/dist/public/assets/_CdHI48v6.js +1 -0
- package/dist/public/assets/{_BfQeZPXW.js → _CdpmkkzR.js} +1 -1
- package/dist/public/assets/_CdpmkkzR.js.br +0 -0
- package/dist/public/assets/{_6klEiBhY.js → _CdtjIoUd.js} +1 -1
- package/dist/public/assets/_CdtjIoUd.js.br +0 -0
- package/dist/public/assets/_Ce9Tv01m.js +1 -0
- package/dist/public/assets/_CeC7Lv10.js +1 -0
- package/dist/public/assets/{_CYhJ6ae-.js → _CfP0f0PU.js} +1 -1
- package/dist/public/assets/_CfP0f0PU.js.br +0 -0
- package/dist/public/assets/_Cg7DH3xk.js +1 -0
- package/dist/public/assets/_Cg7DH3xk.js.br +0 -0
- package/dist/public/assets/_CikNq0z8.js +1 -0
- package/dist/public/assets/{_DK-MOyi_.js → _Cl7LTITm.js} +1 -1
- package/dist/public/assets/_Cl7LTITm.js.br +0 -0
- package/dist/public/assets/{_BT7DMail.js → _Cmtl59QM.js} +1 -1
- package/dist/public/assets/_Cmtl59QM.js.br +0 -0
- package/dist/public/assets/_CshYq_Dp.js +1 -0
- package/dist/public/assets/{_Dj5RDA5P.js → _CspPbDoP.js} +1 -1
- package/dist/public/assets/_CspPbDoP.js.br +0 -0
- package/dist/public/assets/{_Ca2DTddL.js → _Ctjz3BD9.js} +1 -1
- package/dist/public/assets/_Ctjz3BD9.js.br +0 -0
- package/dist/public/assets/{_C5c3o9N3.js → _CuglAToi.js} +1 -1
- package/dist/public/assets/_CuglAToi.js.br +0 -0
- package/dist/public/assets/_CwSoAVRN.js +1 -0
- package/dist/public/assets/_D0XQV-Hm.js +1 -0
- package/dist/public/assets/{_D_GeNCls.js → _D36PnqCD.js} +1 -1
- package/dist/public/assets/_D36PnqCD.js.br +0 -0
- package/dist/public/assets/{_DYqx8g78.js → _D3IviZbJ.js} +1 -1
- package/dist/public/assets/_D3IviZbJ.js.br +0 -0
- package/dist/public/assets/_D6rgUB9O.js +1 -0
- package/dist/public/assets/{_Dwe1TUjY.js → _D7qWWxdI.js} +1 -1
- package/dist/public/assets/_D7qWWxdI.js.br +0 -0
- package/dist/public/assets/{_CPbClwhX.js → _D8ac72_O.js} +1 -1
- package/dist/public/assets/_D8ac72_O.js.br +0 -0
- package/dist/public/assets/_D9WWxrQR.js +1 -0
- package/dist/public/assets/_D9hI5dSA.js +1 -0
- package/dist/public/assets/{_DzlXwaiG.js → _DCrPsldZ.js} +1 -1
- package/dist/public/assets/_DCrPsldZ.js.br +0 -0
- package/dist/public/assets/{_ChPy2IX4.js → _DDcVFyaQ.js} +1 -1
- package/dist/public/assets/_DDcVFyaQ.js.br +0 -0
- package/dist/public/assets/_DDhkKo8Q.js +1 -0
- package/dist/public/assets/{_CY_Z-kV5.js → _DJBR8Qwq.js} +1 -1
- package/dist/public/assets/_DJBR8Qwq.js.br +0 -0
- package/dist/public/assets/{_CxHuLHdz.js → _DLpa6VYT.js} +1 -1
- package/dist/public/assets/_DMqe6rR-.js +1 -0
- package/dist/public/assets/{_DbLQjG4R.js → _DN7pTn2g.js} +1 -1
- package/dist/public/assets/_DN7pTn2g.js.br +0 -0
- package/dist/public/assets/_DP8UuFuJ.js +1 -0
- package/dist/public/assets/_DQedUaqM.js +1 -0
- package/dist/public/assets/{_DPiemRX1.js → _DSCqWPO0.js} +1 -1
- package/dist/public/assets/_DSCqWPO0.js.br +0 -0
- package/dist/public/assets/{_BoEcMQmX.js → _DSeQngGR.js} +1 -1
- package/dist/public/assets/_DSeQngGR.js.br +0 -0
- package/dist/public/assets/{_D-0pUYXq.js → _DTNiWZFr.js} +1 -1
- package/dist/public/assets/_DTNiWZFr.js.br +0 -0
- package/dist/public/assets/_DThlusXY.js +1 -0
- package/dist/public/assets/_DUK16H19.js +1 -0
- package/dist/public/assets/_DUZ13t3U.js +1 -0
- package/dist/public/assets/{_BHgwN0LC.js → _DWb03VKf.js} +1 -1
- package/dist/public/assets/_DWb03VKf.js.br +0 -0
- package/dist/public/assets/_DWsyhfgn.js +1 -0
- package/dist/public/assets/_DXuzYhW6.js +1 -0
- package/dist/public/assets/_DXyOzA2b.js +1 -0
- package/dist/public/assets/{_BXcMBVCY.js → _DYUFCi44.js} +1 -1
- package/dist/public/assets/_DYUFCi44.js.br +0 -0
- package/dist/public/assets/{_BwSXxzqy.js → _DYhs8iJg.js} +12 -12
- package/dist/public/assets/_DYhs8iJg.js.br +0 -0
- package/dist/public/assets/{_Dhn3A3KJ.js → _D__ojGam.js} +1 -1
- package/dist/public/assets/_D__ojGam.js.br +0 -0
- package/dist/public/assets/_DaFI_W5D.js +1 -0
- package/dist/public/assets/{_BiY8chB-.js → _DbT6uo7W.js} +1 -1
- package/dist/public/assets/_DbT6uo7W.js.br +0 -0
- package/dist/public/assets/_DhnT0cCE.js +1 -0
- package/dist/public/assets/_Dm9OGn2q.js +1 -0
- package/dist/public/assets/_DmkeGFoM.js +1 -0
- package/dist/public/assets/{_DVLNzEkW.js → _DmoI4cIl.js} +1 -1
- package/dist/public/assets/_DmoI4cIl.js.br +0 -0
- package/dist/public/assets/{_zcAaK79d.js → _DpbHp8yR.js} +1 -1
- package/dist/public/assets/_DpbHp8yR.js.br +0 -0
- package/dist/public/assets/_Dqz_HBE1.js +1 -0
- package/dist/public/assets/{_DOKecL0e.js → _DsehEuMD.js} +1 -1
- package/dist/public/assets/_DsehEuMD.js.br +0 -0
- package/dist/public/assets/{_D-pUpBL1.js → _Dtx52FYB.js} +1 -1
- package/dist/public/assets/_DuEyirL6.js +1 -0
- package/dist/public/assets/_DuuloSIi.js +1 -0
- package/dist/public/assets/{_Ch-UiovX.js → _DuyCZnNC.js} +1 -1
- package/dist/public/assets/_DuyCZnNC.js.br +0 -0
- package/dist/public/assets/{_BQEpu56f.js → _Dw1P6xZJ.js} +1 -1
- package/dist/public/assets/_Dw1P6xZJ.js.br +0 -0
- package/dist/public/assets/{_C-lB_p3U.js → _DzNFlI0M.js} +1 -1
- package/dist/public/assets/_DzNFlI0M.js.br +0 -0
- package/dist/public/assets/{_CYQ4srZb.js → _EcMqP1xI.js} +1 -1
- package/dist/public/assets/_EcMqP1xI.js.br +0 -0
- package/dist/public/assets/{_0KruTMn9.js → _G1BLeMns.js} +1 -1
- package/dist/public/assets/_G1BLeMns.js.br +0 -0
- package/dist/public/assets/{_FwFz43m8.js → _G8KNSVdM.js} +1 -1
- package/dist/public/assets/_G8KNSVdM.js.br +0 -0
- package/dist/public/assets/{_3fvr5bU1.js → _J1v2clxU.js} +1 -1
- package/dist/public/assets/_J1v2clxU.js.br +0 -0
- package/dist/public/assets/{_Depr5Jps.js → _J3wdy6bJ.js} +1 -1
- package/dist/public/assets/_J3wdy6bJ.js.br +0 -0
- package/dist/public/assets/{_-ycNE92Z.js → _MHZgY1AQ.js} +1 -1
- package/dist/public/assets/_MHZgY1AQ.js.br +0 -0
- package/dist/public/assets/_NHTZitq1.js +2 -0
- package/dist/public/assets/_NHTZitq1.js.br +0 -0
- package/dist/public/assets/{_Cw-dmwPJ.js → _PsuNqRL9.js} +20 -20
- package/dist/public/assets/_PsuNqRL9.js.br +0 -0
- package/dist/public/assets/{_CXVkXsw1.js → _T5HFHZgl.js} +1 -1
- package/dist/public/assets/_T5HFHZgl.js.br +0 -0
- package/dist/public/assets/{_4_sKOYsy.js → _UZAFx6D8.js} +1 -1
- package/dist/public/assets/_UZAFx6D8.js.br +0 -0
- package/dist/public/assets/_XA8_RQXF.js +1 -0
- package/dist/public/assets/{_BTh4v5Tr.js → _XsB9KmcW.js} +1 -1
- package/dist/public/assets/_XsB9KmcW.js.br +0 -0
- package/dist/public/assets/{_i4iteLF8.js → _YoXk_8Bl.js} +1 -1
- package/dist/public/assets/_YoXk_8Bl.js.br +0 -0
- package/dist/public/assets/_YubCdy3Z.js +1 -0
- package/dist/public/assets/{_Q5s6o5H4.js → _bDI-pCZR.js} +1 -1
- package/dist/public/assets/_bDI-pCZR.js.br +0 -0
- package/dist/public/assets/{_TynjiShF.js → _bHL-NcWS.js} +1 -1
- package/dist/public/assets/_bHL-NcWS.js.br +0 -0
- package/dist/public/assets/_bqRzDYc8.js +1 -0
- package/dist/public/assets/{_OpbuiQ7h.js → _briyaWgK.js} +1 -1
- package/dist/public/assets/_briyaWgK.js.br +0 -0
- package/dist/public/assets/{_pEUCjhqm.js → _dVHSDgPC.js} +1 -1
- package/dist/public/assets/_dVHSDgPC.js.br +0 -0
- package/dist/public/assets/_gkZjZ9I4.js +1 -0
- package/dist/public/assets/_plyCYAnN.js +1 -0
- package/dist/public/assets/_q0Z44mWJ.js +1 -0
- package/dist/public/assets/_q0Z44mWJ.js.br +0 -0
- package/dist/public/assets/{_BPNSknLT.js → _qAsGEOt5.js} +1 -1
- package/dist/public/assets/_qAsGEOt5.js.br +0 -0
- package/dist/public/assets/{_Dks8YY2K.js → _qxffRpjc.js} +1 -1
- package/dist/public/assets/{_BOBYB-cj.js → _uCKs5N6Q.js} +1 -1
- package/dist/public/assets/_uCKs5N6Q.js.br +0 -0
- package/dist/public/assets/_utWnC80Q.js +1 -0
- package/dist/public/assets/_utvzcBHT.js +1 -0
- package/dist/public/assets/_v8WbCPI8.js +1 -0
- package/dist/public/assets/_yK4b_Bl5.js +1 -0
- package/dist/public/assets/_yoQW4BY5.js +1 -0
- package/dist/public/assets/_zB6USXHX.js +1 -0
- package/dist/public/assets/{_Quh6tl1u.js → _zN8SypHW.js} +1 -1
- package/dist/public/assets/_zN8SypHW.js.br +0 -0
- package/dist/public/assets/files-view-Fl0rU3Ns.js +2 -0
- package/dist/public/assets/manage-workspace-DggRcsXf.js +2 -0
- package/dist/public/assets/new-C7NxTJAT.js +1 -0
- package/dist/public/assets/new-workspace-C0pw5Iz1.js +2 -0
- package/dist/public/assets/review-view-C4YQ0J-X.js +2 -0
- package/dist/public/assets/settings-C7NxTJAT.js +1 -0
- package/dist/public/assets/settings-page-Cl_1tWCv.js +2 -0
- package/dist/public/assets/styles-Vcsj4CA7.css +1 -0
- package/dist/public/assets/styles-Vcsj4CA7.css.br +0 -0
- package/dist/public/assets/w-C7NxTJAT.js +1 -0
- package/dist/public/assets/w._-BbFH2lR-.js +1 -0
- package/dist/public/assets/w._-C7NxTJAT.js +1 -0
- package/dist/public/assets/w._-YIzLOiyZ.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/preview/media.d.mts +1 -1
- package/lib/preview/media.mjs +15 -2
- 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.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.br +0 -0
- package/dist/public/assets/_Cwtn28hL.js.br +0 -0
- 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 +0 -1
- 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,22 @@ 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
|
+
// `work session --help` is what an agent tries before `work help`.
|
|
137
|
+
if (args.includes("--help") || args.includes("-h")) await helpCmd(command);
|
|
138
|
+
else await cli.cmd.run(cliContext(cli.words));
|
|
139
|
+
break;
|
|
140
|
+
case "help":
|
|
141
|
+
case "--help":
|
|
142
|
+
case "-h":
|
|
143
|
+
await helpCmd(positional[0]);
|
|
144
|
+
break;
|
|
105
145
|
case "start":
|
|
106
146
|
await start();
|
|
107
147
|
break;
|
|
@@ -169,9 +209,10 @@ switch (command) {
|
|
|
169
209
|
console.log(pkg.version);
|
|
170
210
|
break;
|
|
171
211
|
default:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
);
|
|
212
|
+
// A typo must fail: an agent reads the exit code, and usage on stdout
|
|
213
|
+
// with 0 read as the command having run.
|
|
214
|
+
console.error(`error: no command \`${command}\` (see: work help)`);
|
|
215
|
+
process.exitCode = 2;
|
|
175
216
|
}
|
|
176
217
|
|
|
177
218
|
async function start() {
|
|
@@ -232,18 +273,45 @@ function serverUrl() {
|
|
|
232
273
|
return `http://${dialHost(env.WORK_LISTEN)}:${env.PORT}`;
|
|
233
274
|
}
|
|
234
275
|
|
|
235
|
-
|
|
276
|
+
/** One request to the running server: its JSON, or the command dies with
|
|
277
|
+
* the server's own reason (`{error}`), never only its status. */
|
|
278
|
+
async function apiCall(method, path, body, timeoutMs = 30_000) {
|
|
236
279
|
const port = serviceEnv().PORT;
|
|
280
|
+
let res;
|
|
237
281
|
try {
|
|
238
|
-
|
|
239
|
-
|
|
282
|
+
res = await fetch(`${serverUrl()}${path}`, {
|
|
283
|
+
method,
|
|
284
|
+
headers:
|
|
285
|
+
body === undefined ? undefined : { "content-type": "application/json" },
|
|
286
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
287
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
240
288
|
});
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
289
|
+
} catch {
|
|
290
|
+
// Codex runs commands in a sandbox with no network, a local socket
|
|
291
|
+
// included: the server is up, the command has to run outside it,
|
|
292
|
+
// which the agent asks the user for.
|
|
293
|
+
if (process.env.CODEX_SANDBOX_NETWORK_DISABLED)
|
|
294
|
+
die(
|
|
295
|
+
"work cannot reach its server from inside Codex's sandbox (no network there): run this command outside the sandbox, with escalated permissions",
|
|
296
|
+
);
|
|
245
297
|
die(`no work server on port ${port}. Start one with: work start`);
|
|
246
298
|
}
|
|
299
|
+
const text = await res.text();
|
|
300
|
+
let data = null;
|
|
301
|
+
try {
|
|
302
|
+
data = text ? JSON.parse(text) : null;
|
|
303
|
+
} catch {}
|
|
304
|
+
if (!res.ok || (data && typeof data === "object" && data.error)) {
|
|
305
|
+
die(
|
|
306
|
+
(data && data.error) ||
|
|
307
|
+
`server answered ${res.status} for ${method} ${path}`,
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
return data;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function apiGet(path) {
|
|
314
|
+
return apiCall("GET", path);
|
|
247
315
|
}
|
|
248
316
|
|
|
249
317
|
/**
|
|
@@ -255,7 +323,7 @@ async function apiGet(path) {
|
|
|
255
323
|
async function resolveWorkspace(arg) {
|
|
256
324
|
const [list, status] = await Promise.all([
|
|
257
325
|
apiGet("/api/workspaces"),
|
|
258
|
-
apiGet(
|
|
326
|
+
apiGet(statusPath()),
|
|
259
327
|
]);
|
|
260
328
|
let ws;
|
|
261
329
|
if (arg) {
|
|
@@ -294,10 +362,17 @@ function pad(s, n) {
|
|
|
294
362
|
return String(s ?? "").padEnd(n);
|
|
295
363
|
}
|
|
296
364
|
|
|
365
|
+
/** The status snapshot, or with --fresh one that asks GitHub again: a PR
|
|
366
|
+
* made a moment ago (`gh pr create`) is otherwise missing for as long as
|
|
367
|
+
* the PR cache keeps its last answer. */
|
|
368
|
+
function statusPath() {
|
|
369
|
+
return args.includes("--fresh") ? "/api/status?fresh" : "/api/status";
|
|
370
|
+
}
|
|
371
|
+
|
|
297
372
|
async function workspacesCmd() {
|
|
298
373
|
const [list, status] = await Promise.all([
|
|
299
374
|
apiGet("/api/workspaces"),
|
|
300
|
-
apiGet(
|
|
375
|
+
apiGet(statusPath()),
|
|
301
376
|
]);
|
|
302
377
|
const rows = list.map((w) => ({ ...w, ...(status[w.id] || {}) }));
|
|
303
378
|
if (jsonOut) return console.log(JSON.stringify(rows, null, 2));
|
|
@@ -323,21 +398,26 @@ function prLine(pr) {
|
|
|
323
398
|
: pr.isDraft
|
|
324
399
|
? "draft"
|
|
325
400
|
: "open";
|
|
326
|
-
return `#${pr.number} ${state} ${pr.title} ${pr.url}`;
|
|
401
|
+
return `#${pr.number} ${state} ${pr.title}${pr.headRefName ? ` (${pr.headRefName})` : ""} ${pr.url}`;
|
|
327
402
|
}
|
|
328
403
|
|
|
329
404
|
async function workspaceCmd() {
|
|
330
405
|
const { ws, status } = await resolveWorkspace(positional[0]);
|
|
331
406
|
const procs = await apiGet(`/api/workspaces/${ws.id}/procs`).catch(() => []);
|
|
332
|
-
const [sessions] = await Promise.all([
|
|
407
|
+
const [sessions, linkPort] = await Promise.all([
|
|
333
408
|
apiGet(`/api/workspaces/${ws.id}/sessions`).catch(() => []),
|
|
409
|
+
portLinker(),
|
|
334
410
|
]);
|
|
411
|
+
const me = process.env.WORK_SESSION_ID;
|
|
335
412
|
const out = {
|
|
336
413
|
...ws,
|
|
337
|
-
ports: status.ports
|
|
414
|
+
ports: (status.ports || []).map((p) => ({
|
|
415
|
+
...p,
|
|
416
|
+
...linkPort(p.port, p.local),
|
|
417
|
+
})),
|
|
338
418
|
repos: mergeRepos(ws, status),
|
|
339
|
-
sessions,
|
|
340
|
-
procs,
|
|
419
|
+
sessions: sessions.map((s) => (s.id === me ? { ...s, self: true } : s)),
|
|
420
|
+
procs: procs.map((p) => withUrls(p, linkPort)),
|
|
341
421
|
};
|
|
342
422
|
if (jsonOut) return console.log(JSON.stringify(out, null, 2));
|
|
343
423
|
console.log(`${ws.name} (${ws.status})`);
|
|
@@ -352,16 +432,58 @@ async function workspaceCmd() {
|
|
|
352
432
|
console.log(` sessions:`);
|
|
353
433
|
for (const s of sessions) {
|
|
354
434
|
const phase = s.state?.phase || (s.state?.alive ? "idle" : "off");
|
|
355
|
-
console.log(
|
|
435
|
+
console.log(
|
|
436
|
+
` ${pad(s.id, 9)} ${pad(s.agent, 10)} ${pad(phase, 8)} ${s.title || ""}${s.id === me ? " (this session)" : ""}`,
|
|
437
|
+
);
|
|
356
438
|
}
|
|
357
439
|
}
|
|
358
440
|
if (procs.length) {
|
|
359
441
|
console.log(` running:`);
|
|
360
|
-
for (const p of procs)
|
|
361
|
-
console.log(
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
442
|
+
for (const p of out.procs)
|
|
443
|
+
console.log(` ${pad(p.pid, 7)} ${p.cmd}${portsText(p)}`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** How a port opens for the user: through the address their browser last
|
|
448
|
+
* reached work by (`/api/boot`'s `origin`) as the page's port chip would
|
|
449
|
+
* (lib/ports/url), or this machine's own when no browser has yet. `blocked`
|
|
450
|
+
* says why that link cannot work (a port bound to loopback, a page on a
|
|
451
|
+
* direct address). */
|
|
452
|
+
async function portLinker() {
|
|
453
|
+
const boot = await apiGet("/api/boot");
|
|
454
|
+
const loc = boot.origin ? locOf(boot.origin) : null;
|
|
455
|
+
return (port, local) => {
|
|
456
|
+
if (!loc) return { url: `http://localhost:${port}` };
|
|
457
|
+
const blocked = portBlockedAt(port, local, loc);
|
|
458
|
+
return {
|
|
459
|
+
url: portUrlAt(port, loc, boot.portHosts),
|
|
460
|
+
...(blocked && { blocked }),
|
|
461
|
+
};
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** A process with each of its ports' links (`urls`, by port). */
|
|
466
|
+
function withUrls(p, linkPort) {
|
|
467
|
+
if (!p.ports?.length) return p;
|
|
468
|
+
const local = new Set(p.local || []);
|
|
469
|
+
return {
|
|
470
|
+
...p,
|
|
471
|
+
urls: Object.fromEntries(
|
|
472
|
+
p.ports.map((port) => [port, linkPort(port, local.has(port))]),
|
|
473
|
+
),
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/** A process's ports for a line of text, each with where it opens. */
|
|
478
|
+
function portsText(p) {
|
|
479
|
+
if (!p.ports?.length) return "";
|
|
480
|
+
return ` ${p.ports
|
|
481
|
+
.map((port) => {
|
|
482
|
+
const link = p.urls?.[port];
|
|
483
|
+
if (!link) return `:${port}`;
|
|
484
|
+
return `:${port} ${link.url}${link.blocked ? ` (${link.blocked})` : ""}`;
|
|
485
|
+
})
|
|
486
|
+
.join(" ")}`;
|
|
365
487
|
}
|
|
366
488
|
|
|
367
489
|
/** Workspace repos joined with the status snapshot's PRs per repo. */
|
|
@@ -387,13 +509,15 @@ async function reposCmd() {
|
|
|
387
509
|
|
|
388
510
|
async function procsCmd() {
|
|
389
511
|
const { ws } = await resolveWorkspace(positional[0]);
|
|
390
|
-
const
|
|
512
|
+
const [raw, linkPort] = await Promise.all([
|
|
513
|
+
apiGet(`/api/workspaces/${ws.id}/procs`),
|
|
514
|
+
portLinker(),
|
|
515
|
+
]);
|
|
516
|
+
const procs = raw.map((p) => withUrls(p, linkPort));
|
|
391
517
|
if (jsonOut) return console.log(JSON.stringify(procs, null, 2));
|
|
392
518
|
if (!procs.length) return console.log("nothing running");
|
|
393
519
|
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
|
-
);
|
|
520
|
+
console.log(`${pad(p.pid, 7)} ${p.cmd}${portsText(p)}`);
|
|
397
521
|
}
|
|
398
522
|
|
|
399
523
|
/** Comments left on the review page but not yet sent: an agent can pull
|
|
@@ -402,9 +526,23 @@ async function procsCmd() {
|
|
|
402
526
|
async function reviewCmd() {
|
|
403
527
|
const { ws } = await resolveWorkspace(positional[0]);
|
|
404
528
|
const { comments = [] } = await apiGet(`/api/workspaces/${ws.id}/review`);
|
|
405
|
-
if (jsonOut)
|
|
406
|
-
if (!comments.length)
|
|
407
|
-
|
|
529
|
+
if (jsonOut) console.log(JSON.stringify(comments, null, 2));
|
|
530
|
+
else if (!comments.length) console.log("no pending review comments");
|
|
531
|
+
else
|
|
532
|
+
console.log(
|
|
533
|
+
commentMarkdown(comments, await reviewSections(ws.id, comments)),
|
|
534
|
+
);
|
|
535
|
+
// Taken, the comments leave the review as a Send takes them: exactly the
|
|
536
|
+
// ones printed, so one written meanwhile stays for the next look.
|
|
537
|
+
if (args.includes("--take") && comments.length) {
|
|
538
|
+
await apiPost(`/api/workspaces/${ws.id}/review`, {
|
|
539
|
+
action: "clear",
|
|
540
|
+
ids: comments.map((c) => c.id),
|
|
541
|
+
});
|
|
542
|
+
console.error(
|
|
543
|
+
`took ${comments.length} comment${comments.length === 1 ? "" : "s"} off the review`,
|
|
544
|
+
);
|
|
545
|
+
}
|
|
408
546
|
}
|
|
409
547
|
|
|
410
548
|
/** The diff's sections, which say which lane or PR a comment's lines are
|
|
@@ -413,41 +551,25 @@ async function reviewCmd() {
|
|
|
413
551
|
* comments then read as the checkout's rather than failing the command. */
|
|
414
552
|
async function reviewSections(wsId, comments) {
|
|
415
553
|
if (!comments.some((c) => c.head)) return null;
|
|
416
|
-
const port = serviceEnv().PORT;
|
|
417
554
|
try {
|
|
418
|
-
const res = await fetch(
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
);
|
|
555
|
+
const res = await fetch(`${serverUrl()}/api/workspaces/${wsId}/diff`, {
|
|
556
|
+
signal: AbortSignal.timeout(60_000),
|
|
557
|
+
});
|
|
422
558
|
return res.ok ? ((await res.json()).sections ?? null) : null;
|
|
423
559
|
} catch {
|
|
424
560
|
return null;
|
|
425
561
|
}
|
|
426
562
|
}
|
|
427
563
|
|
|
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;
|
|
564
|
+
/** A write: as long as a clone can take (a create, a restore). */
|
|
565
|
+
function apiPost(path, body) {
|
|
566
|
+
return apiCall("POST", path, body ?? {}, 15 * 60_000);
|
|
445
567
|
}
|
|
446
568
|
|
|
447
569
|
/** One line per workspace/repo of what the file will not carry. */
|
|
448
570
|
function printPreflight(found) {
|
|
449
571
|
for (const w of found.workspaces) {
|
|
450
|
-
|
|
572
|
+
say(w.name);
|
|
451
573
|
for (const r of w.repos) {
|
|
452
574
|
const parts = [];
|
|
453
575
|
for (const b of r.unpushed)
|
|
@@ -456,10 +578,10 @@ function printPreflight(found) {
|
|
|
456
578
|
if (r.untracked.length) parts.push(`${r.untracked.length} untracked`);
|
|
457
579
|
if (r.ignored.length) parts.push(`${r.ignored.length} ignored`);
|
|
458
580
|
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)
|
|
581
|
+
say(` ${r.worktree}/ ${parts.join(", ")}`);
|
|
582
|
+
for (const f of r.modified) say(` M ${f}`);
|
|
583
|
+
for (const f of r.untracked) say(` ? ${f}`);
|
|
584
|
+
for (const f of r.ignored) say(` ! ${f}`);
|
|
463
585
|
}
|
|
464
586
|
}
|
|
465
587
|
}
|
|
@@ -477,7 +599,7 @@ async function exportCmd() {
|
|
|
477
599
|
);
|
|
478
600
|
}
|
|
479
601
|
if (found.workspaces.length) {
|
|
480
|
-
|
|
602
|
+
say("not in the backup:");
|
|
481
603
|
printPreflight(found);
|
|
482
604
|
if (!yes) {
|
|
483
605
|
console.log("");
|
|
@@ -498,6 +620,18 @@ async function exportCmd() {
|
|
|
498
620
|
"work-backup.json";
|
|
499
621
|
fs.writeFileSync(name, await res.text());
|
|
500
622
|
log(`wrote ${name}`);
|
|
623
|
+
if (jsonOut)
|
|
624
|
+
console.log(
|
|
625
|
+
JSON.stringify(
|
|
626
|
+
{
|
|
627
|
+
file: path.resolve(name),
|
|
628
|
+
contents: c ?? null,
|
|
629
|
+
left_out: found.workspaces,
|
|
630
|
+
},
|
|
631
|
+
null,
|
|
632
|
+
2,
|
|
633
|
+
),
|
|
634
|
+
);
|
|
501
635
|
}
|
|
502
636
|
|
|
503
637
|
function readManifest(file) {
|
|
@@ -658,6 +792,8 @@ function until(iso) {
|
|
|
658
792
|
}
|
|
659
793
|
|
|
660
794
|
async function setup() {
|
|
795
|
+
// First: a bad name fails before anything is touched.
|
|
796
|
+
editAllowedHosts();
|
|
661
797
|
await bridge();
|
|
662
798
|
const d = await doctor(doctorOpts());
|
|
663
799
|
await fix(d);
|
|
@@ -670,13 +806,30 @@ async function setup() {
|
|
|
670
806
|
const port = serviceEnv().PORT;
|
|
671
807
|
if (!tailnet) maybeTunnel(port);
|
|
672
808
|
if (running) {
|
|
673
|
-
|
|
674
|
-
|
|
809
|
+
const answered = await waitForServer();
|
|
810
|
+
if (answered) log(`done — http://localhost:${port}`);
|
|
811
|
+
else {
|
|
675
812
|
warn(
|
|
676
813
|
`service started but nothing answered on port ${port} within 30s — check the logs`,
|
|
677
814
|
);
|
|
815
|
+
// A setup that left no server is a failed one, to whatever ran it.
|
|
816
|
+
process.exitCode = 1;
|
|
817
|
+
}
|
|
678
818
|
if (tailnet)
|
|
679
819
|
log(`on your phone and other devices on the tailnet: ${tailnet}`);
|
|
820
|
+
if (jsonOut)
|
|
821
|
+
console.log(
|
|
822
|
+
JSON.stringify(
|
|
823
|
+
{
|
|
824
|
+
ok: answered,
|
|
825
|
+
version: pkg.version,
|
|
826
|
+
url: `http://localhost:${port}`,
|
|
827
|
+
tailnet: tailnet || null,
|
|
828
|
+
},
|
|
829
|
+
null,
|
|
830
|
+
2,
|
|
831
|
+
),
|
|
832
|
+
);
|
|
680
833
|
} else {
|
|
681
834
|
// A fresh install's shell may not have mise on PATH yet — name the shim.
|
|
682
835
|
const shim = path.join(
|
|
@@ -694,6 +847,34 @@ async function setup() {
|
|
|
694
847
|
}
|
|
695
848
|
}
|
|
696
849
|
|
|
850
|
+
/** `--allow-host <name>` / `--disallow-host <name>`, each repeatable: one
|
|
851
|
+
* name in or out of the service's WORK_ALLOWED_HOSTS, the rest kept —
|
|
852
|
+
* `WORK_ALLOWED_HOSTS=… work setup` replaces the whole list, which an
|
|
853
|
+
* agent adding one proxy's name would otherwise have to read back first.
|
|
854
|
+
* Applied before anything writes the service, which carries what this
|
|
855
|
+
* leaves in the environment (`serviceEnv`). */
|
|
856
|
+
function editAllowedHosts() {
|
|
857
|
+
const allow = flagValues("--allow-host");
|
|
858
|
+
const disallow = flagValues("--disallow-host");
|
|
859
|
+
if (!allow.length && !disallow.length) return;
|
|
860
|
+
for (const name of [...allow, ...disallow]) {
|
|
861
|
+
if (!/^[A-Za-z0-9.-]+$/.test(name))
|
|
862
|
+
die(
|
|
863
|
+
`not a host name: ${name} (one name per flag, e.g. work.example.com)`,
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
const before = serviceEnv().WORK_ALLOWED_HOSTS || "";
|
|
867
|
+
let next = before;
|
|
868
|
+
for (const name of allow) next = allowHost(next, name, true);
|
|
869
|
+
for (const name of disallow) next = allowHost(next, name, false);
|
|
870
|
+
process.env.WORK_ALLOWED_HOSTS = next;
|
|
871
|
+
log(
|
|
872
|
+
next === before
|
|
873
|
+
? `WORK_ALLOWED_HOSTS unchanged: ${next || "(none)"}`
|
|
874
|
+
: `WORK_ALLOWED_HOSTS=${next || "(none)"}`,
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
|
|
697
878
|
/** Bring a database from before 0.1 to the baseline this release starts
|
|
698
879
|
* from (lib/setup/bridge.mjs), before anything touches the service: the
|
|
699
880
|
* server it would restart refuses such a database. Run with the settings
|
|
@@ -745,22 +926,35 @@ async function update() {
|
|
|
745
926
|
// `--prefer-online`: npm serves `latest` from a cached packument for a
|
|
746
927
|
// few minutes after a publish, so an update right behind a release
|
|
747
928
|
// reinstalled the version already running.
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
"
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
929
|
+
// Under --json, npm's own output goes to stderr: stdout is setup's JSON.
|
|
930
|
+
const stdio = jsonOut ? ["inherit", 2, 2] : "inherit";
|
|
931
|
+
sh(
|
|
932
|
+
"npm",
|
|
933
|
+
[
|
|
934
|
+
"install",
|
|
935
|
+
"-g",
|
|
936
|
+
"--prefer-online",
|
|
937
|
+
...allowScriptsArgs(),
|
|
938
|
+
"@dylanpiercey/work@latest",
|
|
939
|
+
],
|
|
940
|
+
{ stdio },
|
|
941
|
+
);
|
|
755
942
|
// Re-exec the (possibly new) CLI to finish with fresh code.
|
|
756
943
|
sh("work", [
|
|
757
944
|
"setup",
|
|
758
945
|
...(yes ? ["--yes"] : []),
|
|
759
946
|
...args.filter((a) =>
|
|
760
|
-
[
|
|
761
|
-
|
|
762
|
-
|
|
947
|
+
[
|
|
948
|
+
"--tailscale",
|
|
949
|
+
"--no-tailscale",
|
|
950
|
+
"--firewall",
|
|
951
|
+
"--no-firewall",
|
|
952
|
+
"--json",
|
|
953
|
+
"--non-interactive",
|
|
954
|
+
].includes(a),
|
|
763
955
|
),
|
|
956
|
+
...flagValues("--allow-host").flatMap((h) => ["--allow-host", h]),
|
|
957
|
+
...flagValues("--disallow-host").flatMap((h) => ["--disallow-host", h]),
|
|
764
958
|
]);
|
|
765
959
|
}
|
|
766
960
|
|
|
@@ -976,7 +1170,7 @@ async function fix(d) {
|
|
|
976
1170
|
}
|
|
977
1171
|
log(`installing ${tool.label} via ${tool.mise ? "mise" : "gh"}`);
|
|
978
1172
|
try {
|
|
979
|
-
await installTool(tool.id, { log: (l) =>
|
|
1173
|
+
await installTool(tool.id, { log: (l) => say(` ${l}`) });
|
|
980
1174
|
} catch (err) {
|
|
981
1175
|
if (tool.required) die(`${tool.label} install failed: ${err.message}`);
|
|
982
1176
|
warn(`${tool.label} install failed (non-fatal)`);
|
|
@@ -1741,6 +1935,7 @@ function allowTailnet(serve) {
|
|
|
1741
1935
|
* controlling terminal, since the curl installer pipes its script into the
|
|
1742
1936
|
* shell this runs under. Null with no terminal at all. */
|
|
1743
1937
|
function terminal() {
|
|
1938
|
+
if (!interactive) return null;
|
|
1744
1939
|
if (process.stdin.isTTY) return process.stdin;
|
|
1745
1940
|
try {
|
|
1746
1941
|
return new tty.ReadStream(fs.openSync("/dev/tty", "r"));
|
|
@@ -1763,3 +1958,139 @@ async function confirm(input, question) {
|
|
|
1763
1958
|
rl.close();
|
|
1764
1959
|
}
|
|
1765
1960
|
}
|
|
1961
|
+
|
|
1962
|
+
// -- commands of bin/cli/ and help ------------------------------------------
|
|
1963
|
+
|
|
1964
|
+
/** Every command a file of bin/cli/ exports (`_`-prefixed files are its
|
|
1965
|
+
* helpers), loaded once. (Kept on the function: the dispatch above runs
|
|
1966
|
+
* before a top-level `let` here would be initialised.) */
|
|
1967
|
+
async function cliCommands() {
|
|
1968
|
+
if (cliCommands.cache) return cliCommands.cache;
|
|
1969
|
+
const dir = path.join(pkgRoot, "bin", "cli");
|
|
1970
|
+
const files = fs.existsSync(dir)
|
|
1971
|
+
? fs
|
|
1972
|
+
.readdirSync(dir)
|
|
1973
|
+
.filter((f) => f.endsWith(".mjs") && !f.startsWith("_"))
|
|
1974
|
+
.sort()
|
|
1975
|
+
: [];
|
|
1976
|
+
const all = [];
|
|
1977
|
+
for (const f of files) {
|
|
1978
|
+
const mod = await import(path.join(dir, f));
|
|
1979
|
+
for (const c of mod.commands || []) all.push(c);
|
|
1980
|
+
}
|
|
1981
|
+
cliCommands.cache = all;
|
|
1982
|
+
return all;
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
/** A core command's other name, which a bin/cli/ command's first word may
|
|
1986
|
+
* be spelled with (`work ws create` is `workspace create`). */
|
|
1987
|
+
function canonical(word) {
|
|
1988
|
+
return word === "ws" ? "workspace" : word;
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
/** The bin/cli/ command `argv` names: two words (`workspace create`)
|
|
1992
|
+
* before one, so a verb of its own wins over the word alone. */
|
|
1993
|
+
async function cliCommand(first, second) {
|
|
1994
|
+
const all = await cliCommands();
|
|
1995
|
+
const head = canonical(first);
|
|
1996
|
+
const names = (c) => [c.name, ...(c.aliases || [])];
|
|
1997
|
+
if (second) {
|
|
1998
|
+
const two = `${head} ${second}`;
|
|
1999
|
+
const cmd = all.find((c) => names(c).includes(two));
|
|
2000
|
+
if (cmd) return { cmd, words: 2 };
|
|
2001
|
+
}
|
|
2002
|
+
const cmd = all.find((c) => names(c).includes(head));
|
|
2003
|
+
return cmd ? { cmd, words: 1 } : null;
|
|
2004
|
+
}
|
|
2005
|
+
|
|
2006
|
+
/** What a bin/cli/ command is handed: its own argv, the CLI's flags, and
|
|
2007
|
+
* the helpers every command shares — the running server (`api`), which
|
|
2008
|
+
* workspace is meant, and how to say something or fail. */
|
|
2009
|
+
function cliContext(words) {
|
|
2010
|
+
const own = args.slice(0);
|
|
2011
|
+
// The words that named it are not its positionals.
|
|
2012
|
+
const pos = positional.slice(words - 1);
|
|
2013
|
+
return {
|
|
2014
|
+
pkg,
|
|
2015
|
+
args: own,
|
|
2016
|
+
positional: pos,
|
|
2017
|
+
json: jsonOut,
|
|
2018
|
+
yes,
|
|
2019
|
+
has: (flag) => args.includes(flag),
|
|
2020
|
+
flag: flagValue,
|
|
2021
|
+
flags: flagValues,
|
|
2022
|
+
/** Positionals with `valued` flags' values left out (`--agent x`). */
|
|
2023
|
+
parse(valued = []) {
|
|
2024
|
+
const set = new Set([...VALUED, ...valued]);
|
|
2025
|
+
return args
|
|
2026
|
+
.filter(
|
|
2027
|
+
(a, i) => a === "-" || (!a.startsWith("-") && !set.has(args[i - 1])),
|
|
2028
|
+
)
|
|
2029
|
+
.slice(words - 1);
|
|
2030
|
+
},
|
|
2031
|
+
api: {
|
|
2032
|
+
get: (p) => apiCall("GET", p),
|
|
2033
|
+
post: (p, body) => apiPost(p, body),
|
|
2034
|
+
put: (p, body) => apiCall("PUT", p, body ?? {}),
|
|
2035
|
+
patch: (p, body) => apiCall("PATCH", p, body ?? {}),
|
|
2036
|
+
del: (p, body) => apiCall("DELETE", p, body),
|
|
2037
|
+
},
|
|
2038
|
+
serverUrl,
|
|
2039
|
+
resolveWorkspace,
|
|
2040
|
+
/** `data` as JSON under --json, else what `text` prints. */
|
|
2041
|
+
out(data, text) {
|
|
2042
|
+
if (jsonOut) console.log(JSON.stringify(data, null, 2));
|
|
2043
|
+
else text?.(data);
|
|
2044
|
+
},
|
|
2045
|
+
pad,
|
|
2046
|
+
log,
|
|
2047
|
+
warn,
|
|
2048
|
+
die,
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
/** The header's own lines for the core commands: `work <name>` and what
|
|
2053
|
+
* continues it, as written at the top of this file. */
|
|
2054
|
+
function coreHelp() {
|
|
2055
|
+
const src = fs.readFileSync(fileURLToPath(import.meta.url), "utf8");
|
|
2056
|
+
const lines = [];
|
|
2057
|
+
for (const line of src.split("\n").slice(1)) {
|
|
2058
|
+
if (!line.startsWith("//")) break;
|
|
2059
|
+
const text = line.replace(/^\/\/ ?/, "");
|
|
2060
|
+
// The list starts at its first `work …` line and ends at a blank one.
|
|
2061
|
+
if (!lines.length && !/^ {2}work /.test(text)) continue;
|
|
2062
|
+
if (!text.trim()) break;
|
|
2063
|
+
lines.push(text.replace(/^ {2}/, ""));
|
|
2064
|
+
}
|
|
2065
|
+
return lines;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
/** `work help`: every command, the core's then bin/cli/'s; `work help
|
|
2069
|
+
* <cmd>` that one's whole text. */
|
|
2070
|
+
async function helpCmd(topic) {
|
|
2071
|
+
const all = await cliCommands();
|
|
2072
|
+
const core = coreHelp();
|
|
2073
|
+
if (topic) {
|
|
2074
|
+
const head = canonical(topic);
|
|
2075
|
+
const own = all.filter(
|
|
2076
|
+
(c) => c.name === head || c.name.startsWith(`${head} `),
|
|
2077
|
+
);
|
|
2078
|
+
const start = core.findIndex((l) => new RegExp(`^work ${head}\\b`).test(l));
|
|
2079
|
+
if (start < 0 && !own.length)
|
|
2080
|
+
die(`no command \`${topic}\` (see: work help)`);
|
|
2081
|
+
if (start >= 0) {
|
|
2082
|
+
let end = start + 1;
|
|
2083
|
+
while (end < core.length && !core[end].startsWith("work ")) end++;
|
|
2084
|
+
console.log(core.slice(start, end).join("\n"));
|
|
2085
|
+
}
|
|
2086
|
+
for (const c of own) console.log(`\n${c.help || c.summary}`);
|
|
2087
|
+
return;
|
|
2088
|
+
}
|
|
2089
|
+
console.log(`work ${pkg.version}\n`);
|
|
2090
|
+
console.log(core.join("\n"));
|
|
2091
|
+
for (const c of all) console.log(`work ${c.name.padEnd(22)} ${c.summary}`);
|
|
2092
|
+
console.log(
|
|
2093
|
+
"\nwork help <command> for one command's whole text. Most take --json;",
|
|
2094
|
+
);
|
|
2095
|
+
console.log("under it stdout is JSON alone and progress goes to stderr.");
|
|
2096
|
+
}
|