@dylanpiercey/work 0.2.17 → 0.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/bin/cli/README.md +34 -0
- package/bin/cli/_progress.mjs +68 -0
- package/bin/cli/_repo.mjs +32 -0
- package/bin/cli/_target.mjs +49 -0
- package/bin/cli/agent.mjs +153 -0
- package/bin/cli/branches.mjs +79 -0
- package/bin/cli/config.mjs +175 -0
- package/bin/cli/host.mjs +142 -0
- package/bin/cli/lsp.mjs +117 -0
- package/bin/cli/notify.mjs +53 -0
- package/bin/cli/open.mjs +37 -0
- package/bin/cli/repo.mjs +98 -0
- package/bin/cli/session.mjs +167 -0
- package/bin/cli/skill.mjs +99 -0
- package/bin/cli/stack.mjs +51 -0
- package/bin/cli/status.mjs +86 -0
- package/bin/cli/topic.mjs +585 -0
- package/bin/cli/workspace.mjs +184 -0
- package/bin/work.mjs +402 -80
- package/dist/_BAJGOEa1.js +168 -0
- package/dist/{_Bj-WwfnW.js → _BlLEM8du.js} +76 -46
- package/dist/_t9VsALwo.js +2 -0
- package/dist/index.mjs +3550 -2616
- package/dist/public/assets/{_CXVkXsw1.js → _10dZ1R0m.js} +1 -1
- package/dist/public/assets/_10dZ1R0m.js.br +0 -0
- package/dist/public/assets/_1EPD0XJG.js +1 -0
- package/dist/public/assets/_1jA3fFvQ.js +1 -0
- package/dist/public/assets/{_DZanHI_X.js → _4Sj6a8Ya.js} +1 -1
- package/dist/public/assets/_4Sj6a8Ya.js.br +0 -0
- package/dist/public/assets/{_Quh6tl1u.js → _5tN48iuJ.js} +1 -1
- package/dist/public/assets/_5tN48iuJ.js.br +0 -0
- package/dist/public/assets/{_CYQ4srZb.js → _8_DzkMgB.js} +1 -1
- package/dist/public/assets/_8_DzkMgB.js.br +0 -0
- package/dist/public/assets/{_CxgPm_xy.js → _9JG-F3GR.js} +1 -1
- package/dist/public/assets/_9JG-F3GR.js.br +0 -0
- package/dist/public/assets/_9KUM3Nch.js +2 -0
- package/dist/public/assets/_9KUM3Nch.js.br +0 -0
- package/dist/public/assets/{_BoEcMQmX.js → _B-H6ABVZ.js} +1 -1
- package/dist/public/assets/_B-H6ABVZ.js.br +0 -0
- package/dist/public/assets/{_D-0pUYXq.js → _B-iOtMg6.js} +1 -1
- package/dist/public/assets/_B-iOtMg6.js.br +0 -0
- package/dist/public/assets/{_CJgqLdsx.js → _B0FhzjB2.js} +1 -1
- package/dist/public/assets/_B0FhzjB2.js.br +0 -0
- package/dist/public/assets/{_C1-Nli75.js → _B26gPL08.js} +1 -1
- package/dist/public/assets/_B26gPL08.js.br +0 -0
- package/dist/public/assets/{_BA-MNdjL.js → _B2DHvTZR.js} +1 -1
- package/dist/public/assets/{_vX9d6g5Y.js → _B3Z1kRpD.js} +1 -1
- package/dist/public/assets/_B3Z1kRpD.js.br +0 -0
- package/dist/public/assets/{_BfQeZPXW.js → _B3sH8Usv.js} +1 -1
- package/dist/public/assets/_B3sH8Usv.js.br +0 -0
- package/dist/public/assets/_B42hLH2K.js +1 -0
- package/dist/public/assets/{_CY_Z-kV5.js → _B4hn3NNW.js} +1 -1
- package/dist/public/assets/_B4hn3NNW.js.br +0 -0
- package/dist/public/assets/{_DK-MOyi_.js → _B5NleRC6.js} +1 -1
- package/dist/public/assets/_B5NleRC6.js.br +0 -0
- package/dist/public/assets/_B5fRGxPQ.js +1 -0
- package/dist/public/assets/_B5fRGxPQ.js.br +0 -0
- package/dist/public/assets/_B65yR5Ej.js +1 -0
- package/dist/public/assets/_B6Sh9WEH.js +1 -0
- package/dist/public/assets/{_C7bHTlG1.js → _B6VtVybz.js} +1 -1
- package/dist/public/assets/_B6VtVybz.js.br +0 -0
- package/dist/public/assets/_B7rJ4n9b.js +1 -0
- package/dist/public/assets/_B8M-AD29.js +1 -0
- package/dist/public/assets/{_BQEpu56f.js → _B8joFpf1.js} +1 -1
- package/dist/public/assets/_B8joFpf1.js.br +0 -0
- package/dist/public/assets/_B9nA-Uh1.js +1 -0
- package/dist/public/assets/_B9nA-Uh1.js.br +0 -0
- package/dist/public/assets/_BA6X_Aj6.js +1 -0
- package/dist/public/assets/_BBFJV2Bx.js +1 -0
- package/dist/public/assets/_BCW5GFMW.js +1 -0
- package/dist/public/assets/{_TynjiShF.js → _BD1SQU0V.js} +1 -1
- package/dist/public/assets/_BD1SQU0V.js.br +0 -0
- package/dist/public/assets/_BEpd9Y1R.js +1 -0
- package/dist/public/assets/_BEy7R4W_.js +1 -0
- package/dist/public/assets/_BFGJOHQb.js +1 -0
- package/dist/public/assets/{_BiY8chB-.js → _BI45WgW9.js} +1 -1
- package/dist/public/assets/_BI45WgW9.js.br +0 -0
- package/dist/public/assets/_BIKvQKWe.js +1 -0
- package/dist/public/assets/_BIPnL2aI.js +1 -0
- package/dist/public/assets/{_Dj5RDA5P.js → _BIUaA4Nl.js} +1 -1
- package/dist/public/assets/_BIUaA4Nl.js.br +0 -0
- package/dist/public/assets/{_Ch-UiovX.js → _BJpBnuvv.js} +1 -1
- package/dist/public/assets/_BJpBnuvv.js.br +0 -0
- package/dist/public/assets/{_0KruTMn9.js → _BLeLpnYL.js} +1 -1
- package/dist/public/assets/_BLeLpnYL.js.br +0 -0
- package/dist/public/assets/_BMb5ANTv.js +1 -0
- package/dist/public/assets/{_ChPy2IX4.js → _BSRsPQTe.js} +1 -1
- package/dist/public/assets/_BSRsPQTe.js.br +0 -0
- package/dist/public/assets/_BVuerXin.js +6 -0
- package/dist/public/assets/_BVuerXin.js.br +0 -0
- package/dist/public/assets/_BWV8aSlZ.js +1 -0
- package/dist/public/assets/{_Q5s6o5H4.js → _BXHggM8M.js} +1 -1
- package/dist/public/assets/_BXHggM8M.js.br +0 -0
- package/dist/public/assets/{_D8uBvHXU.js → _BXPUZfKX.js} +1 -1
- package/dist/public/assets/_BXPUZfKX.js.br +0 -0
- package/dist/public/assets/_BYebhygn.js +1 -0
- package/dist/public/assets/_BZgCxd-U.js +1 -0
- package/dist/public/assets/_BZgCxd-U.js.br +0 -0
- package/dist/public/assets/_B_W51WxU.js +1 -0
- package/dist/public/assets/_B_jFFNyT.js +1 -0
- package/dist/public/assets/_Ba9OQzPV.js +1 -0
- package/dist/public/assets/_Ba9OQzPV.js.br +0 -0
- package/dist/public/assets/_BayiY7GU.js +1 -0
- package/dist/public/assets/_BcDMeS82.js +1 -0
- package/dist/public/assets/_BdD1sZp_.js +1 -0
- package/dist/public/assets/_Bg_WwlL2.js +1 -0
- package/dist/public/assets/_BhHzv4g0.js +1 -0
- package/dist/public/assets/_BjEinMEe.js +1 -0
- package/dist/public/assets/_BjEinMEe.js.br +0 -0
- package/dist/public/assets/{_DPiemRX1.js → _BkGAUdMd.js} +1 -1
- package/dist/public/assets/_BkGAUdMd.js.br +0 -0
- package/dist/public/assets/{_FwFz43m8.js → _BkHLXMjq.js} +1 -1
- package/dist/public/assets/_BkHLXMjq.js.br +0 -0
- package/dist/public/assets/_BmSWsZvV.js +1 -0
- package/dist/public/assets/{_D_GeNCls.js → _Bn6y2_ex.js} +1 -1
- package/dist/public/assets/_Bn6y2_ex.js.br +0 -0
- package/dist/public/assets/_Bp2gqUaf.js +1 -0
- package/dist/public/assets/_Bs6oYKkD.js +1 -0
- package/dist/public/assets/{_CYhJ6ae-.js → _Bs_MPTBZ.js} +1 -1
- package/dist/public/assets/_Bs_MPTBZ.js.br +0 -0
- package/dist/public/assets/_Bt13j1ev.js +1 -0
- package/dist/public/assets/{_D-pUpBL1.js → _Bt4cxzaP.js} +1 -1
- package/dist/public/assets/_BwlnYt-t.js +1 -0
- package/dist/public/assets/_Bx9aUXTG.js +1 -0
- package/dist/public/assets/{_DUdEYxV0.js → _BxKDE6Ct.js} +1 -1
- package/dist/public/assets/_BxKDE6Ct.js.br +0 -0
- package/dist/public/assets/_BymFDqKj.js +1 -0
- package/dist/public/assets/{_i4iteLF8.js → _C-z8Ntse.js} +1 -1
- package/dist/public/assets/_C-z8Ntse.js.br +0 -0
- package/dist/public/assets/_C0XUbqWe.js +1 -0
- package/dist/public/assets/_C1upDwBv.js +1 -0
- package/dist/public/assets/_C3f4huqn.js +1 -0
- package/dist/public/assets/{_BHyWcuOR.js → _C46o3wQ8.js} +1 -1
- package/dist/public/assets/_C46o3wQ8.js.br +0 -0
- package/dist/public/assets/_C4_3qKLX.js +1 -0
- package/dist/public/assets/_C7tG4xwv.js +1 -0
- package/dist/public/assets/_C8LciIOa.js +1 -0
- package/dist/public/assets/{_zcAaK79d.js → _C9k00otG.js} +1 -1
- package/dist/public/assets/_C9k00otG.js.br +0 -0
- package/dist/public/assets/_CBG92pZO.js +1 -0
- package/dist/public/assets/_CBfI2lSr.js +1 -0
- package/dist/public/assets/{_BPNSknLT.js → _CFKwHn62.js} +1 -1
- package/dist/public/assets/_CFKwHn62.js.br +0 -0
- package/dist/public/assets/_CHDvRNgn.js +1 -0
- package/dist/public/assets/{_DVLNzEkW.js → _CIDjLk1A.js} +1 -1
- package/dist/public/assets/_CIDjLk1A.js.br +0 -0
- package/dist/public/assets/{_3fvr5bU1.js → _CLV83hY7.js} +1 -1
- package/dist/public/assets/_CLV83hY7.js.br +0 -0
- package/dist/public/assets/_CO8ZosDU.js +1 -0
- package/dist/public/assets/{_D4CkNo0r.js → _CPqT91JX.js} +1 -1
- package/dist/public/assets/_CPqT91JX.js.br +0 -0
- package/dist/public/assets/_CRZ03hrO.js +1 -0
- package/dist/public/assets/_CUKvJRmi.js +1 -0
- package/dist/public/assets/_CU_FKEsy.js +1 -0
- package/dist/public/assets/{_Do6b-nfX.js → _CUxBk_RE.js} +1 -1
- package/dist/public/assets/_CUxBk_RE.js.br +0 -0
- package/dist/public/assets/_CW_vyZfo.js +1 -0
- package/dist/public/assets/{_BOBYB-cj.js → _CX5VOdNU.js} +1 -1
- package/dist/public/assets/_CX5VOdNU.js.br +0 -0
- package/dist/public/assets/{_C5c3o9N3.js → _CYcgwayF.js} +1 -1
- package/dist/public/assets/_CYcgwayF.js.br +0 -0
- package/dist/public/assets/{_BXcMBVCY.js → _CZsqsL_m.js} +1 -1
- package/dist/public/assets/_CZsqsL_m.js.br +0 -0
- package/dist/public/assets/_C_a8QggH.js +1 -0
- package/dist/public/assets/_C_ymFHNL.js +1 -0
- package/dist/public/assets/_CaU4irFc.js +1 -0
- package/dist/public/assets/_Cb3fSi2R.js +1 -0
- package/dist/public/assets/{_DOKecL0e.js → _CcINcTUt.js} +1 -1
- package/dist/public/assets/_CcINcTUt.js.br +0 -0
- package/dist/public/assets/{_BTh4v5Tr.js → _CcflXOTj.js} +1 -1
- package/dist/public/assets/_CcflXOTj.js.br +0 -0
- package/dist/public/assets/{_DbLQjG4R.js → _Cfts4mFJ.js} +1 -1
- package/dist/public/assets/_Cfts4mFJ.js.br +0 -0
- package/dist/public/assets/{_v3HPnNBs.js → _ClHeQc6g.js} +1 -1
- package/dist/public/assets/_ClHeQc6g.js.br +0 -0
- package/dist/public/assets/_CnSlVcEh.js +1 -0
- package/dist/public/assets/_Co71-HWR.js +1 -0
- package/dist/public/assets/_CpEeHKyF.js +1 -0
- package/dist/public/assets/{_CNUs2Gqk.js → _CpVeIwQ4.js} +1 -1
- package/dist/public/assets/_CpVeIwQ4.js.br +0 -0
- package/dist/public/assets/{_Cc_GUPR4.js → _Cq4DpL3R.js} +1 -1
- package/dist/public/assets/_Cq4DpL3R.js.br +0 -0
- package/dist/public/assets/_CvxsvMFa.js +1 -0
- package/dist/public/assets/{_DorQTaAa.js → _Cwdn40Q2.js} +1 -1
- package/dist/public/assets/_Cwdn40Q2.js.br +0 -0
- package/dist/public/assets/_CzN0wC_5.js +16 -0
- package/dist/public/assets/_CzN0wC_5.js.br +0 -0
- package/dist/public/assets/_D3ieGLoq.js +1 -0
- package/dist/public/assets/_D4wF26fk.js +1 -0
- package/dist/public/assets/_D9a9nY1Q.js +1 -0
- package/dist/public/assets/{_CIWiehYG.js → _DB7_Yora.js} +1 -1
- package/dist/public/assets/_DB7_Yora.js.br +0 -0
- package/dist/public/assets/{_6klEiBhY.js → _DDWIDZyP.js} +1 -1
- package/dist/public/assets/_DDWIDZyP.js.br +0 -0
- package/dist/public/assets/{_Cwtn28hL.js → _DG3L8-RO.js} +1 -1
- package/dist/public/assets/_DG3L8-RO.js.br +0 -0
- package/dist/public/assets/{_BxS3xvmE.js → _DGRgLaG-.js} +1 -1
- package/dist/public/assets/_DGRgLaG-.js.br +0 -0
- package/dist/public/assets/{_pEUCjhqm.js → _DG_QOtsx.js} +1 -1
- package/dist/public/assets/_DG_QOtsx.js.br +0 -0
- package/dist/public/assets/{_BwSXxzqy.js → _DHYIZWev.js} +11 -11
- package/dist/public/assets/_DHYIZWev.js.br +0 -0
- package/dist/public/assets/{_BoTzWlXR.js → _DJwY_zBh.js} +1 -1
- package/dist/public/assets/_DJwY_zBh.js.br +0 -0
- package/dist/public/assets/{_C9jR1P3s.js → _DKlB-yMq.js} +1 -1
- package/dist/public/assets/_DKlB-yMq.js.br +0 -0
- package/dist/public/assets/{_DYqx8g78.js → _DMCVOg7x.js} +1 -1
- package/dist/public/assets/_DMCVOg7x.js.br +0 -0
- package/dist/public/assets/_DMXnrdYy.js +1 -0
- package/dist/public/assets/_DMXnrdYy.js.br +0 -0
- package/dist/public/assets/{_Di78jTI-.js → _DNrRZhO7.js} +1 -1
- package/dist/public/assets/_DNrRZhO7.js.br +0 -0
- package/dist/public/assets/_DPdb5l-Z.js +1 -0
- package/dist/public/assets/{_Depr5Jps.js → _DRpsUHP5.js} +1 -1
- package/dist/public/assets/_DRpsUHP5.js.br +0 -0
- package/dist/public/assets/{_BHgwN0LC.js → _DUH5o_iN.js} +1 -1
- package/dist/public/assets/_DUH5o_iN.js.br +0 -0
- package/dist/public/assets/{_-ycNE92Z.js → _DUmYv8Kf.js} +1 -1
- package/dist/public/assets/_DUmYv8Kf.js.br +0 -0
- package/dist/public/assets/{_CPbClwhX.js → _DXvsvUmJ.js} +1 -1
- package/dist/public/assets/_DXvsvUmJ.js.br +0 -0
- package/dist/public/assets/{_DqGOYRpi.js → _DYxQeog7.js} +1 -1
- package/dist/public/assets/_DYxQeog7.js.br +0 -0
- package/dist/public/assets/_DZIDdpeW.js +1 -0
- package/dist/public/assets/{_CCONYsJT.js → _DZqoQxTm.js} +1 -1
- package/dist/public/assets/_DZqoQxTm.js.br +0 -0
- package/dist/public/assets/_D_4RJnk0.js +2 -0
- package/dist/public/assets/_D_4RJnk0.js.br +0 -0
- package/dist/public/assets/_DclJXqwW.js +1 -0
- package/dist/public/assets/_Debmjz1c.js +1 -0
- package/dist/public/assets/_DeiCZCO_.js +1 -0
- package/dist/public/assets/{_yp48NYOW.js → _Df-N1G_n.js} +1 -1
- package/dist/public/assets/_Df-N1G_n.js.br +0 -0
- package/dist/public/assets/_Df_3rEok.js +86 -0
- package/dist/public/assets/_Df_3rEok.js.br +0 -0
- package/dist/public/assets/{_DO_4_u2Q.js → _Dh9434oc.js} +1 -1
- package/dist/public/assets/{_Dhn3A3KJ.js → _DjYscMjF.js} +1 -1
- package/dist/public/assets/_DjYscMjF.js.br +0 -0
- package/dist/public/assets/{_cyorvuL1.js → _Dku55Ypt.js} +1 -1
- package/dist/public/assets/_Dku55Ypt.js.br +0 -0
- package/dist/public/assets/_Dm8TVkBX.js +1 -0
- package/dist/public/assets/_DnUBW0Qq.js +1 -0
- package/dist/public/assets/_DoOPrRIy.js +1 -0
- package/dist/public/assets/_DqJvxlYV.js +1 -0
- package/dist/public/assets/_Drle66GA.js +1 -0
- package/dist/public/assets/_DtrvrAfl.js +1 -0
- package/dist/public/assets/{_B5JxE4Sx.js → _DwTaEsY5.js} +1 -1
- package/dist/public/assets/_DwTaEsY5.js.br +0 -0
- package/dist/public/assets/_Dypj9l-z.js +1 -0
- package/dist/public/assets/_DyvwMfCp.js +1 -0
- package/dist/public/assets/{_OpbuiQ7h.js → _GK8r-gEu.js} +1 -1
- package/dist/public/assets/_GK8r-gEu.js.br +0 -0
- package/dist/public/assets/{_BqWlTTxo.js → _HpxvfbM2.js} +1 -1
- package/dist/public/assets/_HpxvfbM2.js.br +0 -0
- package/dist/public/assets/{_CIrZGxEf.js → _RudCGuBM.js} +1 -1
- package/dist/public/assets/_RudCGuBM.js.br +0 -0
- package/dist/public/assets/_UbfI3k4y.js +1 -0
- package/dist/public/assets/{_A-jpjc8j.js → _WOU8TCkO.js} +1 -1
- package/dist/public/assets/_WOU8TCkO.js.br +0 -0
- package/dist/public/assets/{_C-lB_p3U.js → _XWw1j8vS.js} +1 -1
- package/dist/public/assets/_XWw1j8vS.js.br +0 -0
- package/dist/public/assets/{_BCB8LQS3.js → _YDyNvOET.js} +1 -1
- package/dist/public/assets/_YDyNvOET.js.br +0 -0
- package/dist/public/assets/{_DzlXwaiG.js → _f8D86HXZ.js} +1 -1
- package/dist/public/assets/_f8D86HXZ.js.br +0 -0
- package/dist/public/assets/{_BUW_V5kN.js → _hbXd8Ogo.js} +1 -1
- package/dist/public/assets/_hbXd8Ogo.js.br +0 -0
- package/dist/public/assets/{_CrlNjDih.js → _i6YkSowH.js} +1 -1
- package/dist/public/assets/_i6YkSowH.js.br +0 -0
- package/dist/public/assets/_k1ciacDf.js +1 -0
- package/dist/public/assets/_k6nXIP-i.js +1 -0
- package/dist/public/assets/_keX09TNx.js +1 -0
- package/dist/public/assets/{_Dwe1TUjY.js → _l9xpLTP_.js} +1 -1
- package/dist/public/assets/_l9xpLTP_.js.br +0 -0
- package/dist/public/assets/_n9Rb26YX.js +1 -0
- package/dist/public/assets/{_4_sKOYsy.js → _o8mJsMHw.js} +1 -1
- package/dist/public/assets/_o8mJsMHw.js.br +0 -0
- package/dist/public/assets/{_Ca2DTddL.js → _oVsjszGq.js} +1 -1
- package/dist/public/assets/_oVsjszGq.js.br +0 -0
- package/dist/public/assets/_pM8W420Q.js +1 -0
- package/dist/public/assets/{_C449plW0.js → _rv9KtZHz.js} +1 -1
- package/dist/public/assets/_rv9KtZHz.js.br +0 -0
- package/dist/public/assets/{_B19mS3yM.js → _sSKEak2x.js} +1 -1
- package/dist/public/assets/_sSKEak2x.js.br +0 -0
- package/dist/public/assets/_tJgkkxOD.js +1 -0
- package/dist/public/assets/_tJgkkxOD.js.br +0 -0
- package/dist/public/assets/_uP3LGOtV.js +1 -0
- package/dist/public/assets/{_BT7DMail.js → _vG7bXn-C.js} +1 -1
- package/dist/public/assets/_vG7bXn-C.js.br +0 -0
- package/dist/public/assets/{_BTWfPOi-.js → _vHqiFYsh.js} +1 -1
- package/dist/public/assets/_vHqiFYsh.js.br +0 -0
- package/dist/public/assets/_vXJ7nP0d.js +1 -0
- package/dist/public/assets/{_Dks8YY2K.js → _w-MAJku6.js} +1 -1
- package/dist/public/assets/_wvhU__5f.js +1 -0
- package/dist/public/assets/_xFMpRp_e.js +1 -0
- package/dist/public/assets/_yXimF5vw.js +1 -0
- package/dist/public/assets/files-view-BennlUmP.js +2 -0
- package/dist/public/assets/manage-workspace-CaESLJdc.js +2 -0
- package/dist/public/assets/new-BNH4m99d.js +1 -0
- package/dist/public/assets/new-workspace-CwiZjHNn.js +2 -0
- package/dist/public/assets/review-view-BdbMyVt7.js +2 -0
- package/dist/public/assets/settings-BNH4m99d.js +1 -0
- package/dist/public/assets/settings-page-CU3aC70Q.js +2 -0
- package/dist/public/assets/styles-ctr-Sxsj.css +1 -0
- package/dist/public/assets/styles-ctr-Sxsj.css.br +0 -0
- package/dist/public/assets/w-BNH4m99d.js +1 -0
- package/dist/public/assets/w._-BNH4m99d.js +1 -0
- package/dist/public/assets/w._-CLYxMMR4.js +1 -0
- package/dist/public/assets/w._-_w8eUYMy.js +1 -0
- package/dist/public/sw.js +11 -4
- package/dist/public/sw.js.br +0 -0
- package/lib/ports/url.d.mts +20 -0
- package/lib/ports/url.mjs +80 -0
- package/package.json +1 -1
- package/dist/_CLoLdV87.js +0 -2
- package/dist/_DPpY3UqO.js +0 -167
- package/dist/public/assets/_-ycNE92Z.js.br +0 -0
- package/dist/public/assets/_0KruTMn9.js.br +0 -0
- package/dist/public/assets/_0NH5yJMx.js +0 -1
- package/dist/public/assets/_1CAp-NbR.js +0 -1
- package/dist/public/assets/_3fvr5bU1.js.br +0 -0
- package/dist/public/assets/_4Dkmi0BI.js +0 -1
- package/dist/public/assets/_4_sKOYsy.js.br +0 -0
- package/dist/public/assets/_6klEiBhY.js.br +0 -0
- package/dist/public/assets/_7_64OpLh.js +0 -1
- package/dist/public/assets/_7p-zxUs0.js +0 -1
- package/dist/public/assets/_8RAv3gFP.js +0 -1
- package/dist/public/assets/_9PDxaMA9.js +0 -1
- package/dist/public/assets/_9PDxaMA9.js.br +0 -0
- package/dist/public/assets/_9mbDrbe7.js +0 -1
- package/dist/public/assets/_A-jpjc8j.js.br +0 -0
- package/dist/public/assets/_B0JwTeu6.js +0 -1
- package/dist/public/assets/_B19mS3yM.js.br +0 -0
- package/dist/public/assets/_B1Sfrnda.js +0 -1
- package/dist/public/assets/_B3i0wS_I.js +0 -1
- package/dist/public/assets/_B5JxE4Sx.js.br +0 -0
- package/dist/public/assets/_B9RLcC8I.js +0 -1
- package/dist/public/assets/_BCB8LQS3.js.br +0 -0
- package/dist/public/assets/_BE7UYyYb.js +0 -1
- package/dist/public/assets/_BHgwN0LC.js.br +0 -0
- package/dist/public/assets/_BHyWcuOR.js.br +0 -0
- package/dist/public/assets/_BIpUDgQH.js +0 -16
- package/dist/public/assets/_BIpUDgQH.js.br +0 -0
- package/dist/public/assets/_BMlgaRlM.js +0 -1
- package/dist/public/assets/_BOBYB-cj.js.br +0 -0
- package/dist/public/assets/_BPNSknLT.js.br +0 -0
- package/dist/public/assets/_BQEpu56f.js.br +0 -0
- package/dist/public/assets/_BT7DMail.js.br +0 -0
- package/dist/public/assets/_BTJHQNIz.js +0 -1
- package/dist/public/assets/_BTWfPOi-.js.br +0 -0
- package/dist/public/assets/_BTh4v5Tr.js.br +0 -0
- package/dist/public/assets/_BUW_V5kN.js.br +0 -0
- package/dist/public/assets/_BXcMBVCY.js.br +0 -0
- package/dist/public/assets/_B_MtJKnj.js +0 -1
- package/dist/public/assets/_Bay3D1io.js +0 -1
- package/dist/public/assets/_BfQeZPXW.js.br +0 -0
- package/dist/public/assets/_BgKjJWz_.js +0 -1
- package/dist/public/assets/_BiY8chB-.js.br +0 -0
- package/dist/public/assets/_Bk5THQZb.js +0 -1
- package/dist/public/assets/_BmeQRnXS.js +0 -1
- package/dist/public/assets/_BoEcMQmX.js.br +0 -0
- package/dist/public/assets/_BoTzWlXR.js.br +0 -0
- package/dist/public/assets/_BqWlTTxo.js.br +0 -0
- package/dist/public/assets/_BuMTHEPk.js +0 -1
- package/dist/public/assets/_BuMTHEPk.js.br +0 -0
- package/dist/public/assets/_BubhcEjq.js +0 -1
- package/dist/public/assets/_BwSXxzqy.js.br +0 -0
- package/dist/public/assets/_BxS3xvmE.js.br +0 -0
- package/dist/public/assets/_ByvA6zJz.js +0 -1
- package/dist/public/assets/_Bz2Sejcy.js +0 -1
- package/dist/public/assets/_C-lB_p3U.js.br +0 -0
- package/dist/public/assets/_C1-Nli75.js.br +0 -0
- package/dist/public/assets/_C3mw4T_r.js +0 -1
- package/dist/public/assets/_C449plW0.js.br +0 -0
- package/dist/public/assets/_C5c3o9N3.js.br +0 -0
- package/dist/public/assets/_C7bHTlG1.js.br +0 -0
- package/dist/public/assets/_C8mt6nRC.js +0 -1
- package/dist/public/assets/_C9jR1P3s.js.br +0 -0
- package/dist/public/assets/_CCONYsJT.js.br +0 -0
- package/dist/public/assets/_CCZAROAW.js +0 -1
- package/dist/public/assets/_CCZAROAW.js.br +0 -0
- package/dist/public/assets/_CG3s9pE5.js +0 -1
- package/dist/public/assets/_CIWiehYG.js.br +0 -0
- package/dist/public/assets/_CIrZGxEf.js.br +0 -0
- package/dist/public/assets/_CIurl9jC.js +0 -1
- package/dist/public/assets/_CJgqLdsx.js.br +0 -0
- package/dist/public/assets/_CMbVHIgP.js +0 -1
- package/dist/public/assets/_CNUs2Gqk.js.br +0 -0
- package/dist/public/assets/_CPbClwhX.js.br +0 -0
- package/dist/public/assets/_CQUlxerJ.js +0 -1
- package/dist/public/assets/_CTDYlYHi.js +0 -1
- package/dist/public/assets/_CXVkXsw1.js.br +0 -0
- package/dist/public/assets/_CY5EBxZ6.js +0 -1
- package/dist/public/assets/_CYQ4srZb.js.br +0 -0
- package/dist/public/assets/_CY_Z-kV5.js.br +0 -0
- package/dist/public/assets/_CYhJ6ae-.js.br +0 -0
- package/dist/public/assets/_CZbVK94d.js +0 -1
- package/dist/public/assets/_C_A97h_2.js +0 -1
- package/dist/public/assets/_C_A97h_2.js.br +0 -0
- package/dist/public/assets/_C_Y5Dwzy.js +0 -1
- package/dist/public/assets/_Ca2DTddL.js.br +0 -0
- package/dist/public/assets/_Cc2nu3_5.js +0 -1
- package/dist/public/assets/_Cc_GUPR4.js.br +0 -0
- package/dist/public/assets/_CgFUs0bE.js +0 -1
- package/dist/public/assets/_Ch-UiovX.js.br +0 -0
- package/dist/public/assets/_ChDp0-FJ.js +0 -1
- package/dist/public/assets/_ChPy2IX4.js.br +0 -0
- package/dist/public/assets/_Chsgo2e1.js +0 -1
- package/dist/public/assets/_CjECwrWB.js +0 -1
- package/dist/public/assets/_CmW74dH7.js +0 -1
- package/dist/public/assets/_CmhAUlqu.js +0 -1
- package/dist/public/assets/_CrlNjDih.js.br +0 -0
- package/dist/public/assets/_CvzTEaQq.js +0 -1
- package/dist/public/assets/_Cw-dmwPJ.js +0 -86
- package/dist/public/assets/_Cw-dmwPJ.js.br +0 -0
- package/dist/public/assets/_Cwtn28hL.js.br +0 -0
- package/dist/public/assets/_CxHuLHdz.js +0 -1
- package/dist/public/assets/_CxgPm_xy.js.br +0 -0
- package/dist/public/assets/_D-0pUYXq.js.br +0 -0
- package/dist/public/assets/_D-rV-z_T.js +0 -1
- package/dist/public/assets/_D4CkNo0r.js.br +0 -0
- package/dist/public/assets/_D4fP_viq.js +0 -1
- package/dist/public/assets/_D570Sd6p.js +0 -1
- package/dist/public/assets/_D6Gudpw8.js +0 -1
- package/dist/public/assets/_D8ZTP1ck.js +0 -1
- package/dist/public/assets/_D8uBvHXU.js.br +0 -0
- package/dist/public/assets/_D8xGEGlm.js +0 -1
- package/dist/public/assets/_D9GZHKow.js +0 -1
- package/dist/public/assets/_DE0eZjad.js +0 -1
- package/dist/public/assets/_DElIEG9n.js +0 -1
- package/dist/public/assets/_DF0n9xzn.js +0 -2
- package/dist/public/assets/_DF0n9xzn.js.br +0 -0
- package/dist/public/assets/_DFX_tXcw.js +0 -1
- package/dist/public/assets/_DJ2gfhU_.js +0 -1
- package/dist/public/assets/_DK-MOyi_.js.br +0 -0
- package/dist/public/assets/_DOKecL0e.js.br +0 -0
- package/dist/public/assets/_DPXXIOLX.js +0 -1
- package/dist/public/assets/_DPb3t58B.js +0 -1
- package/dist/public/assets/_DPiemRX1.js.br +0 -0
- package/dist/public/assets/_DPpbgqBC.js +0 -1
- package/dist/public/assets/_DRVSLjxA.js +0 -1
- package/dist/public/assets/_DTHWnu6M.js +0 -1
- package/dist/public/assets/_DUdEYxV0.js.br +0 -0
- package/dist/public/assets/_DVLNzEkW.js.br +0 -0
- package/dist/public/assets/_DWpx2Uof.js +0 -1
- package/dist/public/assets/_DXYEUAmC.js +0 -1
- package/dist/public/assets/_DYTVambU.js +0 -1
- package/dist/public/assets/_DYqx8g78.js.br +0 -0
- package/dist/public/assets/_DZanHI_X.js.br +0 -0
- package/dist/public/assets/_D_GeNCls.js.br +0 -0
- package/dist/public/assets/_DbLQjG4R.js.br +0 -0
- package/dist/public/assets/_DbmusecK.js +0 -1
- package/dist/public/assets/_DbmusecK.js.br +0 -0
- package/dist/public/assets/_DemN-D5U.js +0 -1
- package/dist/public/assets/_Depr5Jps.js.br +0 -0
- package/dist/public/assets/_DhJfHI4f.js +0 -1
- package/dist/public/assets/_Dhn3A3KJ.js.br +0 -0
- package/dist/public/assets/_Di78jTI-.js.br +0 -0
- package/dist/public/assets/_DiBTtPlu.js +0 -1
- package/dist/public/assets/_Dj5RDA5P.js.br +0 -0
- package/dist/public/assets/_DkjKARSS.js +0 -1
- package/dist/public/assets/_Do6b-nfX.js.br +0 -0
- package/dist/public/assets/_DorQTaAa.js.br +0 -0
- package/dist/public/assets/_DpxVmwni.js +0 -1
- package/dist/public/assets/_DqGOYRpi.js.br +0 -0
- package/dist/public/assets/_DsbxQ1i8.js +0 -1
- package/dist/public/assets/_Dt_P7K1V.js +0 -6
- package/dist/public/assets/_Dt_P7K1V.js.br +0 -0
- package/dist/public/assets/_Dwe1TUjY.js.br +0 -0
- package/dist/public/assets/_DyROQKS8.js +0 -1
- package/dist/public/assets/_DzEUPsq0.js +0 -1
- package/dist/public/assets/_DzlXwaiG.js.br +0 -0
- package/dist/public/assets/_FwFz43m8.js.br +0 -0
- package/dist/public/assets/_OpbuiQ7h.js.br +0 -0
- package/dist/public/assets/_Q5s6o5H4.js.br +0 -0
- package/dist/public/assets/_Quh6tl1u.js.br +0 -0
- package/dist/public/assets/_Rh99sjDe.js +0 -1
- package/dist/public/assets/_SEE1XtID.js +0 -1
- package/dist/public/assets/_SZjr1kid.js +0 -1
- package/dist/public/assets/_T7rMqM5P.js +0 -1
- package/dist/public/assets/_TynjiShF.js.br +0 -0
- package/dist/public/assets/_UENAEFcY.js +0 -1
- package/dist/public/assets/_UwTOb1gP.js +0 -1
- package/dist/public/assets/_WrxtT1Ok.js +0 -1
- package/dist/public/assets/_WrxtT1Ok.js.br +0 -0
- package/dist/public/assets/_bcvRRCkB.js +0 -1
- package/dist/public/assets/_cyorvuL1.js.br +0 -0
- package/dist/public/assets/_gi--JOq8.js +0 -1
- package/dist/public/assets/_i4iteLF8.js.br +0 -0
- package/dist/public/assets/_i7vMugBN.js +0 -1
- package/dist/public/assets/_j7jPRUEQ.js +0 -2
- package/dist/public/assets/_j7jPRUEQ.js.br +0 -0
- package/dist/public/assets/_pEUCjhqm.js.br +0 -0
- package/dist/public/assets/_qkJuNTl-.js +0 -1
- package/dist/public/assets/_uuZJDLIV.js +0 -1
- package/dist/public/assets/_v3HPnNBs.js.br +0 -0
- package/dist/public/assets/_vX9d6g5Y.js.br +0 -0
- package/dist/public/assets/_vhysM7gk.js +0 -1
- package/dist/public/assets/_vjwPQHk_.js +0 -1
- package/dist/public/assets/_yp48NYOW.js.br +0 -0
- package/dist/public/assets/_zcAaK79d.js.br +0 -0
- package/dist/public/assets/_zwPrEKxN.js +0 -1
- package/dist/public/assets/_zwPrEKxN.js.br +0 -0
- package/dist/public/assets/files-view-CzRAql9-.js +0 -2
- package/dist/public/assets/manage-workspace-C-c1R4pP.js +0 -2
- package/dist/public/assets/new-DWfNwssk.js +0 -1
- package/dist/public/assets/new-workspace-B8XAfkIH.js +0 -2
- package/dist/public/assets/review-view-DivHZNBf.js +0 -2
- package/dist/public/assets/settings-DWfNwssk.js +0 -1
- package/dist/public/assets/settings-page-BN9Hj1ui.js +0 -2
- package/dist/public/assets/styles-NmwxQh5L.css +0 -1
- package/dist/public/assets/styles-NmwxQh5L.css.br +0 -0
- package/dist/public/assets/w-DWfNwssk.js +0 -1
- package/dist/public/assets/w._-C9dj1aZ0.js +0 -1
- package/dist/public/assets/w._-D7_D4HlM.js +0 -1
- package/dist/public/assets/w._-DWfNwssk.js +0 -1
package/README.md
CHANGED
|
@@ -54,6 +54,19 @@ work-source prod # global @dylanpiercey/work again
|
|
|
54
54
|
work-source # status
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
### From the command line (and agents)
|
|
58
|
+
|
|
59
|
+
Everything the app's pages do has a `work` command too, so an agent — or a
|
|
60
|
+
script — can use and set up work from a terminal: `work help` lists them.
|
|
61
|
+
Inside a workspace, `work branches`, `work session`, `work topic`,
|
|
62
|
+
`work review`, `work notify` and `work open`; to change things,
|
|
63
|
+
`work workspace create`, `work repo add`, `work config get|set` (checked
|
|
64
|
+
against what each setting takes; `work config schema` lists them),
|
|
65
|
+
`work agent|skill|lsp|host` and `work gh login`; `work status` sums the
|
|
66
|
+
machine up, and `work procs` prints each workspace port's link as the
|
|
67
|
+
user's browser would open it. Every command takes `--json` (JSON alone on
|
|
68
|
+
stdout) and never prompts under it or `--non-interactive`.
|
|
69
|
+
|
|
57
70
|
### Access
|
|
58
71
|
|
|
59
72
|
work has no login of its own — it runs agents and terminals as you, so it
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# bin/cli
|
|
2
|
+
|
|
3
|
+
`work` commands beyond the core ones in `bin/work.mjs`, one file each. A
|
|
4
|
+
file here (not starting with `_`) exports `commands`, and `work` finds it at
|
|
5
|
+
run time; `work help` lists it.
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
/** @type {import("./_types").Command[]} */
|
|
9
|
+
export const commands = [
|
|
10
|
+
{
|
|
11
|
+
// One word (`branches`), or a core command's word and a verb of its own
|
|
12
|
+
// (`workspace create`, which `work ws create` also reaches).
|
|
13
|
+
name: "branches",
|
|
14
|
+
aliases: [],
|
|
15
|
+
summary: "one line for `work help`",
|
|
16
|
+
help: "the whole text for `work help branches`",
|
|
17
|
+
async run(ctx) {
|
|
18
|
+
// ctx.positional — the words after the command's own name
|
|
19
|
+
// ctx.parse(["--agent"]) — positionals with those flags' values left out
|
|
20
|
+
// ctx.has("--fresh"), ctx.flag("--agent"), ctx.flags("--repo")
|
|
21
|
+
// ctx.json — --json was passed: print JSON alone (ctx.out does)
|
|
22
|
+
// ctx.api.get/post/put/patch/del(path, body) — the running server;
|
|
23
|
+
// a non-2xx answer or `{error}` dies with the server's reason
|
|
24
|
+
// ctx.resolveWorkspace(arg) — { ws, status }: the named one, else the
|
|
25
|
+
// session's (WORK_SESSION_ID), else the one holding the cwd
|
|
26
|
+
// ctx.out(data, (data) => print text), ctx.log, ctx.warn, ctx.die
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Plain node, no dependencies: it ships in the npm package as it is. Under
|
|
33
|
+
`--json` stdout is the JSON alone (`ctx.log` and `ctx.warn` go to stderr);
|
|
34
|
+
a failure exits non-zero with its reason (`ctx.die`).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Following a long request's progress lines from the terminal, as the
|
|
2
|
+
// app's own views follow them (src/client/progress.ts).
|
|
3
|
+
|
|
4
|
+
/** How often a lane's line said again further on (a clone's percentage)
|
|
5
|
+
* is printed: it moves every few hundred ms, and each is a line here. */
|
|
6
|
+
const REPLACE_EVERY_MS = 3000;
|
|
7
|
+
|
|
8
|
+
/** Run `request` (a long POST) while printing on stderr the progress lines
|
|
9
|
+
* the server tags with `op`, read from a cursor taken first so none is
|
|
10
|
+
* missed or replayed. `onLine` sees each line too (a sign-in's code).
|
|
11
|
+
* Polled rather than taken off the events socket: plain node has no
|
|
12
|
+
* WebSocket client to spare, and the app polls the same route itself
|
|
13
|
+
* where a proxy holds the socket back. */
|
|
14
|
+
export async function follow(ctx, op, request, onLine) {
|
|
15
|
+
const base = ctx.serverUrl();
|
|
16
|
+
const get = async (q) => {
|
|
17
|
+
try {
|
|
18
|
+
const res = await fetch(`${base}/api/progress${q}`, {
|
|
19
|
+
signal: AbortSignal.timeout(10_000),
|
|
20
|
+
});
|
|
21
|
+
return res.ok ? await res.json() : null;
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
let last = (await get(""))?.seq ?? 0;
|
|
27
|
+
/** Each lane's last printed line and when: a line said again is printed
|
|
28
|
+
* only when it says something new, and not more often than the above. */
|
|
29
|
+
const said = new Map();
|
|
30
|
+
const take = async () => {
|
|
31
|
+
const r = await get(`?since=${last}&op=${encodeURIComponent(op)}`);
|
|
32
|
+
for (const e of r?.messages ?? []) {
|
|
33
|
+
if (e.seq <= last) continue;
|
|
34
|
+
last = e.seq;
|
|
35
|
+
if (e.done || !e.message) continue;
|
|
36
|
+
const lane = e.lane ?? "";
|
|
37
|
+
const prev = said.get(lane);
|
|
38
|
+
if (e.replace) {
|
|
39
|
+
// The line back as it began (a fetch done) says nothing new.
|
|
40
|
+
if (prev?.text === e.message) continue;
|
|
41
|
+
if (prev && Date.now() - prev.at < REPLACE_EVERY_MS) continue;
|
|
42
|
+
}
|
|
43
|
+
said.set(lane, { text: e.message, at: Date.now() });
|
|
44
|
+
process.stderr.write(` ${e.message}\n`);
|
|
45
|
+
onLine?.(e.message);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
let settled = false;
|
|
49
|
+
const result = request().finally(() => {
|
|
50
|
+
settled = true;
|
|
51
|
+
});
|
|
52
|
+
const poll = (async () => {
|
|
53
|
+
while (!settled) {
|
|
54
|
+
await new Promise((r) => setTimeout(r, 800));
|
|
55
|
+
if (!settled) await take();
|
|
56
|
+
}
|
|
57
|
+
})();
|
|
58
|
+
const value = await result;
|
|
59
|
+
await poll;
|
|
60
|
+
// Lines that came between the last poll and the answer.
|
|
61
|
+
await take();
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** An id for one operation's progress lines (the server takes ≤ 40). */
|
|
66
|
+
export function opId() {
|
|
67
|
+
return `cli-${Math.random().toString(36).slice(2, 10)}`;
|
|
68
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// A repo as a command line names it, the way the app's repo picker reads
|
|
2
|
+
// a pasted one (src/client/github.ts parseRepoUrl, mirrored here: plain
|
|
3
|
+
// node, no imports from src/).
|
|
4
|
+
|
|
5
|
+
const FULL_NAME = /^(?:[\w.-]+\/)?[\w.-]+\/[\w.-]+$/;
|
|
6
|
+
|
|
7
|
+
/** `owner/name`, `host/owner/name` or a clone URL (`https://host/o/n(.git)`,
|
|
8
|
+
* `ssh://git@host/o/n`, `git@host:o/n.git`) → `[host/]owner/name`, the
|
|
9
|
+
* host left out for github.com; null when it is none of those. */
|
|
10
|
+
export function repoName(text) {
|
|
11
|
+
const t = String(text || "").trim();
|
|
12
|
+
const m =
|
|
13
|
+
/^(?:https?|ssh):\/\/(?:[^@/\s]+@)?([a-z0-9.-]+)(?::\d+)?\/([\w.-]+)\/([\w.-]*?)(?:\.git)?\/?$/i.exec(
|
|
14
|
+
t,
|
|
15
|
+
) || /^[\w.-]+@([a-z0-9.-]+):([\w.-]+)\/([\w.-]*?)(?:\.git)?$/i.exec(t);
|
|
16
|
+
if (m) {
|
|
17
|
+
const host = m[1].toLowerCase();
|
|
18
|
+
if (!host.includes(".") || !m[3]) return null;
|
|
19
|
+
const name = `${m[2]}/${m[3]}`;
|
|
20
|
+
return host === "github.com" ? name : `${host}/${name}`;
|
|
21
|
+
}
|
|
22
|
+
const bare = t.replace(/\.git$/, "").replace(/^github\.com\//i, "");
|
|
23
|
+
return FULL_NAME.test(bare) ? bare : null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Whether `key` (as `--base <key>=…` names a repo) means `fullName`: the
|
|
27
|
+
* whole name, `owner/name`, or the name alone. */
|
|
28
|
+
export function namesRepo(key, fullName) {
|
|
29
|
+
const k = key.toLowerCase();
|
|
30
|
+
const f = fullName.toLowerCase();
|
|
31
|
+
return f === k || f.endsWith(`/${k}`);
|
|
32
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// What `work open` and `work notify --link` name, as the link the user's
|
|
2
|
+
// page opens: an app page as it is, a web page as it is, or a path in the
|
|
3
|
+
// workspace as its Files page — resolved by the server as a terminal's
|
|
4
|
+
// printed path is (`/term-paths`: the session's directory, its checkout,
|
|
5
|
+
// the workspace, each repo; files and folders inside its checkouts and
|
|
6
|
+
// .share/ only).
|
|
7
|
+
import os from "node:os";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {any} ctx a bin/cli context
|
|
12
|
+
* @param {{ id: string }} ws
|
|
13
|
+
* @param {string} raw `/w/…`, `http(s)://…`, or a path (`src/a.ts:12`,
|
|
14
|
+
* `.share/shots/`, an absolute one)
|
|
15
|
+
* @returns {Promise<{ link: string, label: string } | null>}
|
|
16
|
+
*/
|
|
17
|
+
export async function resolveTarget(ctx, ws, raw) {
|
|
18
|
+
if (/^\/w\//.test(raw)) return { link: raw, label: raw };
|
|
19
|
+
if (/^https?:\/\//i.test(raw)) return { link: raw, label: raw };
|
|
20
|
+
// `name:42` is a line in it, as editors and the terminal's links take it.
|
|
21
|
+
const m = /^(.*?):(\d+)(?::\d+)?$/.exec(raw);
|
|
22
|
+
const target = m ? m[1] : raw;
|
|
23
|
+
const line = m ? Number(m[2]) : null;
|
|
24
|
+
const home = target.startsWith("~/")
|
|
25
|
+
? path.join(os.homedir(), target.slice(2))
|
|
26
|
+
: target;
|
|
27
|
+
// This shell's own directory first; then as typed, which the server
|
|
28
|
+
// tries against the session's, the workspace and each repo.
|
|
29
|
+
const abs = path.resolve(process.cwd(), home);
|
|
30
|
+
const answers = await ctx.api.post(`/api/workspaces/${ws.id}/term-paths`, {
|
|
31
|
+
...(process.env.WORK_SESSION_ID && {
|
|
32
|
+
session: process.env.WORK_SESSION_ID,
|
|
33
|
+
}),
|
|
34
|
+
paths: [abs, home],
|
|
35
|
+
});
|
|
36
|
+
const hit = answers?.[0] ?? answers?.[1];
|
|
37
|
+
if (!hit) return null;
|
|
38
|
+
const q = new URLSearchParams({ file: hit.key });
|
|
39
|
+
if (line && !hit.key.endsWith("/")) q.set("line", String(line));
|
|
40
|
+
return {
|
|
41
|
+
link: `/w/${ws.id}/files?${q}`,
|
|
42
|
+
label: `${hit.key}${line && !hit.key.endsWith("/") ? `:${line}` : ""}`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Why a target named nothing, said once for both commands. */
|
|
47
|
+
export function unresolved(raw) {
|
|
48
|
+
return `nothing at ${raw} in this workspace: a file or folder in its checkouts or its .share/, an app page (/w/…), or a URL`;
|
|
49
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// `work agent`: the agent CLIs this machine has, as Settings → Agents
|
|
2
|
+
// lists and switches them.
|
|
3
|
+
import { follow } from "./_progress.mjs";
|
|
4
|
+
|
|
5
|
+
/** What both lists are read from: the machine's agents (installed or
|
|
6
|
+
* not, each binary on PATH an instance) and the app's choices among them
|
|
7
|
+
* (the default, the ones switched off). */
|
|
8
|
+
async function snapshot(ctx) {
|
|
9
|
+
const [setup, settings] = await Promise.all([
|
|
10
|
+
ctx.api.get("/api/setup"),
|
|
11
|
+
ctx.api.get("/api/settings"),
|
|
12
|
+
]);
|
|
13
|
+
const off = new Set(settings.disabledAgents || []);
|
|
14
|
+
return {
|
|
15
|
+
default: settings.preferredAgent ?? null,
|
|
16
|
+
agents: (setup.agents || []).map((a) => ({
|
|
17
|
+
id: a.id,
|
|
18
|
+
label: a.label,
|
|
19
|
+
installed: a.installed,
|
|
20
|
+
installable: a.installable,
|
|
21
|
+
instances: (a.instances || []).map((i) => ({
|
|
22
|
+
id: i.id,
|
|
23
|
+
command: i.command,
|
|
24
|
+
path: i.path,
|
|
25
|
+
enabled: !off.has(i.id),
|
|
26
|
+
})),
|
|
27
|
+
})),
|
|
28
|
+
catalog: settings.catalog || [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function printList(s) {
|
|
33
|
+
console.log(`default: ${s.default ?? "(none)"}`);
|
|
34
|
+
const w = Math.max(5, ...s.agents.map((a) => a.id.length));
|
|
35
|
+
for (const a of s.agents) {
|
|
36
|
+
if (!a.instances.length) {
|
|
37
|
+
console.log(
|
|
38
|
+
`${a.id.padEnd(w)} ${a.label} — not installed${a.installable ? " (work agent install " + a.id + ")" : ""}`,
|
|
39
|
+
);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const each = a.instances
|
|
43
|
+
.map((i) => `${i.id}${i.enabled ? "" : " (off)"}`)
|
|
44
|
+
.join(", ");
|
|
45
|
+
console.log(`${a.id.padEnd(w)} ${a.label} — ${each}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** An instance id the machine has (`claude`, `claude2`), or the command
|
|
50
|
+
* dies naming the ones it does. */
|
|
51
|
+
function instance(ctx, s, id) {
|
|
52
|
+
if (!id) ctx.die("name the agent: an instance id from work agent list");
|
|
53
|
+
const hit = s.catalog.find((c) => c.id === id && c.id !== "shell");
|
|
54
|
+
if (!hit) {
|
|
55
|
+
const have = s.catalog
|
|
56
|
+
.filter((c) => c.id !== "shell")
|
|
57
|
+
.map((c) => c.id)
|
|
58
|
+
.join(", ");
|
|
59
|
+
ctx.die(`no installed agent ${id} (installed: ${have || "none"})`);
|
|
60
|
+
}
|
|
61
|
+
return hit;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** @type {Array<{name: string, summary: string, help: string, run: (ctx: any) => Promise<void>}>} */
|
|
65
|
+
export const commands = [
|
|
66
|
+
{
|
|
67
|
+
name: "agent",
|
|
68
|
+
summary: "agent CLIs: list | install | enable | disable | default",
|
|
69
|
+
help: `work agent [list]
|
|
70
|
+
The agent CLIs this machine knows: each family, whether it is installed,
|
|
71
|
+
its instances (one per binary on PATH: claude, claude2) and which are
|
|
72
|
+
switched off, and the default new sessions start with.
|
|
73
|
+
work agent install <family>
|
|
74
|
+
Install an agent CLI the machine lacks (claude, codex, …), as Settings
|
|
75
|
+
does; its installer's output goes to stderr.
|
|
76
|
+
work agent enable|disable <instance>
|
|
77
|
+
Show or hide an installed instance in the app's pickers (it stays
|
|
78
|
+
installed).
|
|
79
|
+
work agent default <instance>
|
|
80
|
+
The agent new sessions start with: an installed instance that is
|
|
81
|
+
switched on (with none, new sessions are a plain shell).`,
|
|
82
|
+
async run(ctx) {
|
|
83
|
+
const [verb = "list", id] = ctx.parse();
|
|
84
|
+
if (verb === "list") {
|
|
85
|
+
const s = await snapshot(ctx);
|
|
86
|
+
const { catalog, ...shown } = s;
|
|
87
|
+
return ctx.out(shown, printList);
|
|
88
|
+
}
|
|
89
|
+
if (verb === "install") {
|
|
90
|
+
const s = await snapshot(ctx);
|
|
91
|
+
const fam = s.agents.find((a) => a.id === id);
|
|
92
|
+
if (!fam)
|
|
93
|
+
ctx.die(
|
|
94
|
+
`no agent family ${id ?? ""} (known: ${s.agents.map((a) => a.id).join(", ")})`,
|
|
95
|
+
);
|
|
96
|
+
if (fam.installed) {
|
|
97
|
+
ctx.out({ id: fam.id, installed: true }, () =>
|
|
98
|
+
console.log(`${fam.label} is already installed`),
|
|
99
|
+
);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!fam.installable)
|
|
103
|
+
ctx.die(`${fam.label} has no installer work can run here`);
|
|
104
|
+
const setup = await follow(ctx, `setup:${fam.id}`, () =>
|
|
105
|
+
ctx.api.post(`/api/setup/${encodeURIComponent(fam.id)}`, {
|
|
106
|
+
action: "install",
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
109
|
+
const now = (setup.agents || []).find((a) => a.id === fam.id);
|
|
110
|
+
ctx.out({ id: fam.id, installed: !!now?.installed }, () =>
|
|
111
|
+
console.log(
|
|
112
|
+
now?.installed
|
|
113
|
+
? `installed ${fam.label}`
|
|
114
|
+
: `${fam.label} still is not on PATH (see the output above)`,
|
|
115
|
+
),
|
|
116
|
+
);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (verb === "enable" || verb === "disable") {
|
|
120
|
+
const s = await snapshot(ctx);
|
|
121
|
+
const inst = instance(ctx, s, id);
|
|
122
|
+
await ctx.api.put("/api/settings", {
|
|
123
|
+
agent: { id: inst.id, enabled: verb === "enable" },
|
|
124
|
+
});
|
|
125
|
+
ctx.out({ id: inst.id, enabled: verb === "enable" }, () =>
|
|
126
|
+
console.log(
|
|
127
|
+
`${inst.id} ${verb === "enable" ? "shows in" : "is hidden from"} the app's pickers`,
|
|
128
|
+
),
|
|
129
|
+
);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (verb === "default") {
|
|
133
|
+
if (!id) ctx.die("name the agent: work agent default <instance>");
|
|
134
|
+
const s = await snapshot(ctx);
|
|
135
|
+
const inst = instance(ctx, s, id);
|
|
136
|
+
// The server keeps a default only while it is switched on; one that
|
|
137
|
+
// is off would be stored and then read back as another.
|
|
138
|
+
if (!inst.enabled)
|
|
139
|
+
ctx.die(`${id} is switched off: work agent enable ${id} first`);
|
|
140
|
+
const after = await ctx.api.put("/api/settings", {
|
|
141
|
+
preferredAgent: id,
|
|
142
|
+
});
|
|
143
|
+
ctx.out({ default: after.preferredAgent }, () =>
|
|
144
|
+
console.log(`new sessions start with ${after.preferredAgent}`),
|
|
145
|
+
);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
ctx.die(
|
|
149
|
+
`no agent verb ${verb} (list, install, enable, disable, default)`,
|
|
150
|
+
);
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
];
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// `work branches`: the workspace's sections as the review lists them —
|
|
2
|
+
// each repo's checkout, its topic branches (lanes), their PRs — with the
|
|
3
|
+
// id a review link names and the link itself, so an agent links and
|
|
4
|
+
// rebases what is there rather than guessing names from a convention.
|
|
5
|
+
|
|
6
|
+
/** What a section is up to, in a few words. */
|
|
7
|
+
function stateOf(s) {
|
|
8
|
+
const parts = [];
|
|
9
|
+
if (s.pr)
|
|
10
|
+
parts.push(
|
|
11
|
+
`PR #${s.pr.number}${s.pr.isDraft ? " draft" : ""}: ${s.pr.title}`,
|
|
12
|
+
);
|
|
13
|
+
else if (s.unborn) parts.push("no commits yet");
|
|
14
|
+
else if (s.contained) parts.push("nothing of its own (merged, or not begun)");
|
|
15
|
+
else if (s.unpushed) parts.push(`${s.unpushed} unpushed`);
|
|
16
|
+
else if (s.ready) parts.push("pushed, no PR");
|
|
17
|
+
if (s.edits) parts.push(`${s.edits} uncommitted`);
|
|
18
|
+
if (s.stack) parts.push(`layer ${s.stack.index + 1} of ${s.stack.size}`);
|
|
19
|
+
return parts.join(" · ") || "—";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Whether a checkout's own section says anything: one with nothing of
|
|
23
|
+
* its own and no edits is every idle repo of a large workspace. */
|
|
24
|
+
function worthListing(s, all) {
|
|
25
|
+
if (s.id.includes("@") || s.id.includes("#")) return true;
|
|
26
|
+
return all || !s.contained || !!s.edits || !!s.pr;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const commands = [
|
|
30
|
+
{
|
|
31
|
+
name: "branches",
|
|
32
|
+
summary: "the workspace's branches and PRs, with each one's review link",
|
|
33
|
+
help: `work branches [id|name] [--all] [--fresh] [--json]
|
|
34
|
+
The workspace's sections as the review lists them: each repo's checkout
|
|
35
|
+
(only one with something of its own, unless --all), its topic branches
|
|
36
|
+
(\`repo@topic\`) and open PRs (\`repo#123\`), each with its state (PR,
|
|
37
|
+
unpushed commits, uncommitted edits, merged) and the Markdown link that
|
|
38
|
+
opens it in the review: [topic](/w/<id>/review?section=repo@topic).
|
|
39
|
+
--fresh asks GitHub again rather than the PR cache (~2 min old).`,
|
|
40
|
+
async run(ctx) {
|
|
41
|
+
const [arg] = ctx.positional;
|
|
42
|
+
const { ws } = await ctx.resolveWorkspace(arg);
|
|
43
|
+
const sections = await ctx.api.get(`/api/workspaces/${ws.id}/sections`);
|
|
44
|
+
const all = ctx.has("--all");
|
|
45
|
+
const rows = sections
|
|
46
|
+
.filter((s) => worthListing(s, all))
|
|
47
|
+
.map((s) => {
|
|
48
|
+
const label = s.id.includes("@")
|
|
49
|
+
? s.id.slice(s.id.indexOf("@") + 1)
|
|
50
|
+
: s.id;
|
|
51
|
+
// `@` as itself, as the links agents are told to write spell it;
|
|
52
|
+
// a PR section's `#` must be escaped.
|
|
53
|
+
const href = `/w/${ws.id}/review?section=${encodeURIComponent(s.id).replace(/%40/g, "@")}`;
|
|
54
|
+
return {
|
|
55
|
+
id: s.id,
|
|
56
|
+
repo: s.worktree,
|
|
57
|
+
branch: s.headRef || s.pr?.headRefName || s.branch,
|
|
58
|
+
base: s.base,
|
|
59
|
+
state: stateOf(s),
|
|
60
|
+
pr: s.pr ? { number: s.pr.number, url: s.pr.url } : null,
|
|
61
|
+
unpushed: s.unpushed || 0,
|
|
62
|
+
edits: s.edits || 0,
|
|
63
|
+
merged: !!s.contained && !s.pr,
|
|
64
|
+
link: `[${label}](${href})`,
|
|
65
|
+
href,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
ctx.out(rows, (list) => {
|
|
69
|
+
if (!list.length)
|
|
70
|
+
return console.log("nothing of its own on any branch");
|
|
71
|
+
const w = Math.max(...list.map((r) => r.id.length));
|
|
72
|
+
for (const r of list)
|
|
73
|
+
console.log(
|
|
74
|
+
`${ctx.pad(r.id, w)} ${r.branch} ${r.state}\n${" ".repeat(w + 2)}${r.link}`,
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
];
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// `work config`: every setting the app's Settings pages change, read and
|
|
2
|
+
// written through the running server's one registry of them
|
|
3
|
+
// (src/server/settings-registry.ts), which checks each value — so an agent
|
|
4
|
+
// can turn on language servers or pick the default agent without a browser,
|
|
5
|
+
// and a wrong value is refused with what the setting takes.
|
|
6
|
+
|
|
7
|
+
/** A value as a person reads it. */
|
|
8
|
+
export function shown(value) {
|
|
9
|
+
if (value === null || value === undefined) return "(unset)";
|
|
10
|
+
if (typeof value === "boolean") return value ? "on" : "off";
|
|
11
|
+
if (Array.isArray(value)) return value.length ? value.join(",") : "(none)";
|
|
12
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
13
|
+
if (value === "") return "(empty)";
|
|
14
|
+
return String(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const SCOPES = [
|
|
18
|
+
["machine", "machine (every device)"],
|
|
19
|
+
["device", "one kind of device"],
|
|
20
|
+
["ui-state", "page state"],
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
/** `key = value` and, when changed, what it would otherwise be; the
|
|
24
|
+
* description under it. */
|
|
25
|
+
function printEntries(entries) {
|
|
26
|
+
for (const [scope, title] of SCOPES) {
|
|
27
|
+
const rows = entries.filter((e) => e.scope === scope);
|
|
28
|
+
if (!rows.length) continue;
|
|
29
|
+
console.log(`\n${title}`);
|
|
30
|
+
for (const e of rows) {
|
|
31
|
+
const was = e.isDefault
|
|
32
|
+
? ""
|
|
33
|
+
: ` (default ${e.defaultText ?? shown(e.default)})`;
|
|
34
|
+
const managed = e.managed ? ` [set with ${e.managed}]` : "";
|
|
35
|
+
console.log(` ${e.key} = ${shown(e.value)}${was}${managed}`);
|
|
36
|
+
console.log(` ${e.description}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** What a setting takes, in a few words. */
|
|
42
|
+
function takes(d) {
|
|
43
|
+
switch (d.type) {
|
|
44
|
+
case "bool":
|
|
45
|
+
return "on|off";
|
|
46
|
+
case "enum":
|
|
47
|
+
return d.values.join("|");
|
|
48
|
+
case "int":
|
|
49
|
+
return `${d.min}–${d.max}`;
|
|
50
|
+
case "list":
|
|
51
|
+
return d.values?.length ? `list of ${d.values.join("|")}` : "list";
|
|
52
|
+
case "json":
|
|
53
|
+
return "JSON object";
|
|
54
|
+
default:
|
|
55
|
+
return d.maxLength ? `text ≤${d.maxLength}` : "text";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const KEY = (ctx, verb) => {
|
|
60
|
+
const key = ctx.positional[0];
|
|
61
|
+
if (!key) ctx.die(`usage: work config ${verb} <key> (see: work config list)`);
|
|
62
|
+
return key;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const list = {
|
|
66
|
+
summary: "every setting with its value (--all adds page state)",
|
|
67
|
+
async run(ctx) {
|
|
68
|
+
const entries = await ctx.api.get(
|
|
69
|
+
`/api/settings/values${ctx.has("--all") ? "?all" : ""}`,
|
|
70
|
+
);
|
|
71
|
+
ctx.out(entries, printEntries);
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const commands = [
|
|
76
|
+
{
|
|
77
|
+
name: "config",
|
|
78
|
+
...list,
|
|
79
|
+
async run(ctx) {
|
|
80
|
+
// `work config theme` is a typo for get or set, not a list.
|
|
81
|
+
if (ctx.positional[0])
|
|
82
|
+
ctx.die(
|
|
83
|
+
`no \`work config ${ctx.positional[0]}\`: list, get, set, unset or schema (see: work help config)`,
|
|
84
|
+
);
|
|
85
|
+
return list.run(ctx);
|
|
86
|
+
},
|
|
87
|
+
help: `work config [list] [--all] [--json]
|
|
88
|
+
every setting the app's Settings change: its value, its default when
|
|
89
|
+
changed from it, and what it does (--all adds each page's own state)
|
|
90
|
+
work config get <key> one setting's value (--json: the whole entry)
|
|
91
|
+
work config set <key> <value> change one: on|off, a number, one of its
|
|
92
|
+
values, a list as a,b (or the items as
|
|
93
|
+
separate args), a JSON object; refused with
|
|
94
|
+
what it takes when the value does not fit
|
|
95
|
+
work config unset <key> put one back to its default
|
|
96
|
+
work config schema [--json] every setting: its type, what it takes, its
|
|
97
|
+
default, whose it is and what it does`,
|
|
98
|
+
},
|
|
99
|
+
{ name: "config list", ...list, help: "work config list [--all] [--json]" },
|
|
100
|
+
{
|
|
101
|
+
name: "config get",
|
|
102
|
+
summary: "one setting's value",
|
|
103
|
+
help: "work config get <key> [--json]",
|
|
104
|
+
async run(ctx) {
|
|
105
|
+
const key = KEY(ctx, "get");
|
|
106
|
+
const e = await ctx.api.get(
|
|
107
|
+
`/api/settings/values?key=${encodeURIComponent(key)}`,
|
|
108
|
+
);
|
|
109
|
+
ctx.out(e, () => console.log(shown(e.value)));
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: "config set",
|
|
114
|
+
summary: "change one setting (checked against what it takes)",
|
|
115
|
+
help: `work config set <key> <value…> [--json]
|
|
116
|
+
work config set lsp on
|
|
117
|
+
work config set theme dark
|
|
118
|
+
work config set lsp-off typescript,marko
|
|
119
|
+
work config set command.claude "claude --verbose"
|
|
120
|
+
work config set keys '{"palette": "Mod+K"}'`,
|
|
121
|
+
async run(ctx) {
|
|
122
|
+
const key = KEY(ctx, "set");
|
|
123
|
+
const words = ctx.positional.slice(1);
|
|
124
|
+
if (!words.length)
|
|
125
|
+
ctx.die(
|
|
126
|
+
`usage: work config set ${key} <value> (work config unset ${key} for its default)`,
|
|
127
|
+
);
|
|
128
|
+
const e = await ctx.api.post("/api/settings/values", {
|
|
129
|
+
key,
|
|
130
|
+
value: words.length > 1 ? words : words[0],
|
|
131
|
+
});
|
|
132
|
+
ctx.out(e, () => console.log(`${e.key} = ${shown(e.value)}`));
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: "config unset",
|
|
137
|
+
summary: "put one setting back to its default",
|
|
138
|
+
help: "work config unset <key> [--json]",
|
|
139
|
+
async run(ctx) {
|
|
140
|
+
const key = KEY(ctx, "unset");
|
|
141
|
+
const e = await ctx.api.post("/api/settings/values", {
|
|
142
|
+
key,
|
|
143
|
+
value: null,
|
|
144
|
+
});
|
|
145
|
+
ctx.out(e, () => console.log(`${e.key} = ${shown(e.value)}`));
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: "config schema",
|
|
150
|
+
summary: "every setting's type, values, default and scope",
|
|
151
|
+
help: "work config schema [--json]",
|
|
152
|
+
async run(ctx) {
|
|
153
|
+
const schema = await ctx.api.get("/api/settings/schema");
|
|
154
|
+
ctx.out(schema, () => {
|
|
155
|
+
for (const [scope, title] of SCOPES) {
|
|
156
|
+
const rows = schema.filter((d) => d.scope === scope);
|
|
157
|
+
if (!rows.length) continue;
|
|
158
|
+
console.log(`\n${title}`);
|
|
159
|
+
for (const d of rows) {
|
|
160
|
+
const dflt = d.defaultText ?? shown(d.default);
|
|
161
|
+
const extra = [
|
|
162
|
+
`default ${dflt}`,
|
|
163
|
+
d.backup && "in backups",
|
|
164
|
+
d.managed && `set with ${d.managed}`,
|
|
165
|
+
]
|
|
166
|
+
.filter(Boolean)
|
|
167
|
+
.join(", ");
|
|
168
|
+
console.log(` ${d.key} ${takes(d)} (${extra})`);
|
|
169
|
+
console.log(` ${d.description}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
];
|