@dylanpiercey/work 0.0.120 → 0.0.121
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 +35 -8
- package/bin/work.mjs +380 -41
- package/dist/_B1lVb01g.js +2 -0
- package/dist/_Bjh5JEm7.js +2 -0
- package/dist/_CfwTkTbL.js +352 -0
- package/dist/{_DEBFGwto.js → _CivNK9fo.js} +22 -20
- package/dist/{_DE2RUdbF.js → _Cr71Xd0d.js} +8 -3
- package/dist/_DJyHc1w-.js +1739 -0
- package/dist/{_BZhGz-eY.js → _DnaZVHJ7.js} +97 -96
- package/dist/_Dpa8WFuv.js +2 -0
- package/dist/index.mjs +4183 -4191
- package/dist/public/assets/{_BrTLGsp82.js → _-zdUyUYM2.js} +1 -1
- package/dist/public/assets/_-zdUyUYM2.js.br +0 -0
- package/dist/public/assets/{_Cvly93xo2.js → _0L2K8sFq2.js} +1 -1
- package/dist/public/assets/_0L2K8sFq2.js.br +0 -0
- package/dist/public/assets/{_CQ-tqbUq.js → _42jdam49.js} +1 -1
- package/dist/public/assets/_42jdam49.js.br +0 -0
- package/dist/public/assets/{_BEOZghNJ2.js → _9dJ8BnyZ2.js} +1 -1
- package/dist/public/assets/_9dJ8BnyZ2.js.br +0 -0
- package/dist/public/assets/{_zJkCtRhb.js → _B03G1Nvs.js} +1 -1
- package/dist/public/assets/_B03G1Nvs.js.br +0 -0
- package/dist/public/assets/{_BLgtdDQm.js → _B0dZ7_qK.js} +1 -1
- package/dist/public/assets/_B0dZ7_qK.js.br +0 -0
- package/dist/public/assets/{_DdnCyOPs.js → _B1VuWiKK.js} +1 -1
- package/dist/public/assets/_B1VuWiKK.js.br +0 -0
- package/dist/public/assets/{_CwtAB8Ju2.js → _B5nrQZIq2.js} +1 -1
- package/dist/public/assets/_B5nrQZIq2.js.br +0 -0
- package/dist/public/assets/{_B_MP9UES.js → _B8ZQ8inF.js} +1 -1
- package/dist/public/assets/_B8ZQ8inF.js.br +0 -0
- package/dist/public/assets/{_DhLWIgCs.js → _B9e51G1K.js} +1 -1
- package/dist/public/assets/_B9e51G1K.js.br +0 -0
- package/dist/public/assets/{_h6HS-Zb_2.js → _BH015W2i2.js} +1 -1
- package/dist/public/assets/_BH015W2i2.js.br +0 -0
- package/dist/public/assets/{_Brws7C1N.js → _BHjcfVXB.js} +6 -6
- package/dist/public/assets/_BHjcfVXB.js.br +0 -0
- package/dist/public/assets/{_BfZMmKaW.js → _BNIilCsC.js} +1 -1
- package/dist/public/assets/_BNIilCsC.js.br +0 -0
- package/dist/public/assets/{_CihMY3_B2.js → _BPgL37mi2.js} +1 -1
- package/dist/public/assets/_BPgL37mi2.js.br +0 -0
- package/dist/public/assets/{_BDRc66NB2.js → _BR3D4nzj2.js} +1 -1
- package/dist/public/assets/_BR3D4nzj2.js.br +0 -0
- package/dist/public/assets/{_BoXfCUcF.js → _BRSJwfZ3.js} +1 -1
- package/dist/public/assets/{_BbE6iGBd.js → _BSFENb4l.js} +1 -1
- package/dist/public/assets/_BSFENb4l.js.br +0 -0
- package/dist/public/assets/{_DBXfsrRd.js → _BSWpz0dK.js} +1 -1
- package/dist/public/assets/_BSWpz0dK.js.br +0 -0
- package/dist/public/assets/{_DZgx_rAt.js → _BUOWar32.js} +1 -1
- package/dist/public/assets/_BUOWar32.js.br +0 -0
- package/dist/public/assets/{_Ces5jihM.js → _BZWlvMSJ.js} +1 -1
- package/dist/public/assets/_BZWlvMSJ.js.br +0 -0
- package/dist/public/assets/{_F8phZWNM2.js → _B_dMglA92.js} +1 -1
- package/dist/public/assets/_B_dMglA92.js.br +0 -0
- package/dist/public/assets/{_N0Ea8Q_R.js → _Beb6Lb1w.js} +1 -1
- package/dist/public/assets/_Beb6Lb1w.js.br +0 -0
- package/dist/public/assets/{_BUmLRB7c2.js → _BjIMoOV-2.js} +1 -1
- package/dist/public/assets/_BjIMoOV-2.js.br +0 -0
- package/dist/public/assets/{_Cv-4N4xQ.js → _BlLuOKRT.js} +1 -1
- package/dist/public/assets/_BlLuOKRT.js.br +0 -0
- package/dist/public/assets/{_BilqQTfw.js → _BlXwius8.js} +1 -1
- package/dist/public/assets/_BlXwius8.js.br +0 -0
- package/dist/public/assets/{_DdYfAoJz.js → _Bmt76eWT.js} +1 -1
- package/dist/public/assets/_Bmt76eWT.js.br +0 -0
- package/dist/public/assets/{_BaiP7ogH.js → _BoS5LU5l.js} +1 -1
- package/dist/public/assets/_BoS5LU5l.js.br +0 -0
- package/dist/public/assets/{_uJTU0UZd2.js → _BsNKabYu2.js} +1 -1
- package/dist/public/assets/_BsNKabYu2.js.br +0 -0
- package/dist/public/assets/{_D2be5yUI.js → _C0OXw3Vy.js} +1 -1
- package/dist/public/assets/_C0OXw3Vy.js.br +0 -0
- package/dist/public/assets/{_CrPK-ZOH2.js → _CBUJNdeq2.js} +1 -1
- package/dist/public/assets/_CBUJNdeq2.js.br +0 -0
- package/dist/public/assets/{_DfpMH3So2.js → _CCNhM32c2.js} +1 -1
- package/dist/public/assets/_CCNhM32c2.js.br +0 -0
- package/dist/public/assets/{_D11ZFURg.js → _CFBaZNUT.js} +1 -1
- package/dist/public/assets/_CFBaZNUT.js.br +0 -0
- package/dist/public/assets/{_BGHYY00K2.js → _CJHqzl--2.js} +1 -1
- package/dist/public/assets/_CJHqzl--2.js.br +0 -0
- package/dist/public/assets/{_BHgE7f-_2.js → _CMGgQ-4H2.js} +1 -1
- package/dist/public/assets/_CMGgQ-4H2.js.br +0 -0
- package/dist/public/assets/{_BzULaZGs.js → _CPX0D-my.js} +1 -1
- package/dist/public/assets/_CPX0D-my.js.br +0 -0
- package/dist/public/assets/{_CeECfdVo2.js → _CRuHDn_O2.js} +1 -1
- package/dist/public/assets/_CRuHDn_O2.js.br +0 -0
- package/dist/public/assets/{_p1VLQxPw.js → _CUOao_Hj.js} +1 -1
- package/dist/public/assets/_CUOao_Hj.js.br +0 -0
- package/dist/public/assets/{_CIio55Q2.js → _CUVw5V4z.js} +1 -1
- package/dist/public/assets/_CUVw5V4z.js.br +0 -0
- package/dist/public/assets/{_CYLlpjQc.js → _CYMGOhCb.js} +1 -1
- package/dist/public/assets/_CYMGOhCb.js.br +0 -0
- package/dist/public/assets/{_BtmFYBHk.js → _CZfap_Dj.js} +1 -1
- package/dist/public/assets/_CZfap_Dj.js.br +0 -0
- package/dist/public/assets/{_DRKLaQtq.js → _CbNmSe5k.js} +1 -1
- package/dist/public/assets/_CbNmSe5k.js.br +0 -0
- package/dist/public/assets/{_8hF31A2G.js → _CdtuhZSc.js} +1 -1
- package/dist/public/assets/_CdtuhZSc.js.br +0 -0
- package/dist/public/assets/{_BPcKgx9L.js → _ClhApln3.js} +1 -1
- package/dist/public/assets/_ClhApln3.js.br +0 -0
- package/dist/public/assets/{_QuFTKxMO2.js → _CvA5IOAW2.js} +1 -1
- package/dist/public/assets/_CvA5IOAW2.js.br +0 -0
- package/dist/public/assets/{_z3QzE4ht2.js → _CwZYmUdt2.js} +1 -1
- package/dist/public/assets/{_CG2uZvAG.js → _CxrcWZPE.js} +1 -1
- package/dist/public/assets/_CxrcWZPE.js.br +0 -0
- package/dist/public/assets/{_Du-i6H8r.js → _D-KjGTSW.js} +24 -21
- package/dist/public/assets/_D-KjGTSW.js.br +0 -0
- package/dist/public/assets/{_Ca811EeR.js → _D4u4SpiK.js} +1 -1
- package/dist/public/assets/_D4u4SpiK.js.br +0 -0
- package/dist/public/assets/{_DiaYv9e1.js → _D6CjH3JN.js} +1 -1
- package/dist/public/assets/_D6CjH3JN.js.br +0 -0
- package/dist/public/assets/{_BCKhXQct2.js → _D7cQLLGK2.js} +1 -1
- package/dist/public/assets/_D7cQLLGK2.js.br +0 -0
- package/dist/public/assets/{_DDag_nXJ.js → _DBoABI85.js} +1 -1
- package/dist/public/assets/_DBoABI85.js.br +0 -0
- package/dist/public/assets/{_CzMjLSTK.js → _DNcd1xtp.js} +1 -1
- package/dist/public/assets/_DNcd1xtp.js.br +0 -0
- package/dist/public/assets/{_BEPt7EWk.js → _DQGTProt.js} +1 -1
- package/dist/public/assets/_DQGTProt.js.br +0 -0
- package/dist/public/assets/{_D8lg2J6H.js → _DSIH6_Li.js} +1 -1
- package/dist/public/assets/_DSIH6_Li.js.br +0 -0
- package/dist/public/assets/{_cS3NYZ_K2.js → _DXHf4WHs2.js} +1 -1
- package/dist/public/assets/_DXHf4WHs2.js.br +0 -0
- package/dist/public/assets/{_0_ngOEbL.js → _D_qDhyn2.js} +1 -1
- package/dist/public/assets/_D_qDhyn2.js.br +0 -0
- package/dist/public/assets/{_BFgJoTOo.js → _DcMfCkmd.js} +1 -1
- package/dist/public/assets/_DcMfCkmd.js.br +0 -0
- package/dist/public/assets/{_CkBv_F0f.js → _DgDEdxEu.js} +1 -1
- package/dist/public/assets/_DgDEdxEu.js.br +0 -0
- package/dist/public/assets/{_dBVoJwVC.js → _DlhDim1D.js} +1 -1
- package/dist/public/assets/_DlhDim1D.js.br +0 -0
- package/dist/public/assets/{_-3OmHyNU.js → _DqLib98x.js} +1 -1
- package/dist/public/assets/_DqLib98x.js.br +0 -0
- package/dist/public/assets/{_fR2ilomn.js → _Ds0Qa0YX.js} +1 -1
- package/dist/public/assets/_Ds0Qa0YX.js.br +0 -0
- package/dist/public/assets/{_CwZCc-fE2.js → _DyUvL09k2.js} +1 -1
- package/dist/public/assets/_DyUvL09k2.js.br +0 -0
- package/dist/public/assets/{_D2xWjoK-2.js → _J6xlcydH2.js} +1 -1
- package/dist/public/assets/_J6xlcydH2.js.br +0 -0
- package/dist/public/assets/{_DkYHMy0q2.js → _MInulccf2.js} +1 -1
- package/dist/public/assets/{_GdcmEEuJ.js → _QMVFINxi.js} +1 -1
- package/dist/public/assets/_QMVFINxi.js.br +0 -0
- package/dist/public/assets/{_BqNoqWIY.js → _S9QQtt68.js} +1 -1
- package/dist/public/assets/_S9QQtt68.js.br +0 -0
- package/dist/public/assets/{_BuF6uiIm.js → _XCJLLGxV.js} +1 -1
- package/dist/public/assets/_XCJLLGxV.js.br +0 -0
- package/dist/public/assets/{_DWctbEWg.js → _Y-bTh0dW.js} +1 -1
- package/dist/public/assets/_Y-bTh0dW.js.br +0 -0
- package/dist/public/assets/{_CJ_9Hl5d.js → _Y8TOk1pR.js} +1 -1
- package/dist/public/assets/_Y8TOk1pR.js.br +0 -0
- package/dist/public/assets/{_cdbANa0O.js → _YetFhXkM.js} +1 -1
- package/dist/public/assets/_YetFhXkM.js.br +0 -0
- package/dist/public/assets/{_CeVHIZWy2.js → _YmJopjX92.js} +1 -1
- package/dist/public/assets/_YmJopjX92.js.br +0 -0
- package/dist/public/assets/{_wc-pkVQS.js → _mbzaOqik.js} +1 -1
- package/dist/public/assets/_mbzaOqik.js.br +0 -0
- package/dist/public/assets/{_FEbRnVo7.js → _rMcfapaa.js} +1 -1
- package/dist/public/assets/_rMcfapaa.js.br +0 -0
- package/dist/public/assets/{_BIsQjQ872.js → _rRtbbfKJ2.js} +1 -1
- package/dist/public/assets/_rRtbbfKJ2.js.br +0 -0
- package/dist/public/assets/{_D4V7vTBe.js → _sSWgnHeU.js} +1 -1
- package/dist/public/assets/_sSWgnHeU.js.br +0 -0
- package/dist/public/assets/{_B6bSumz1.js → _xOeYy_3v.js} +1 -1
- package/dist/public/assets/_xOeYy_3v.js.br +0 -0
- package/dist/public/assets/app-page-BWf0w6W9.css +1 -0
- package/dist/public/assets/app-page-BWf0w6W9.css.br +0 -0
- package/dist/public/assets/diff-view-BZaYYEDK.css +1 -0
- package/dist/public/assets/diff-view-BZaYYEDK.css.br +0 -0
- package/dist/public/assets/new-K-7z0qE8.js +1 -0
- package/dist/public/assets/settings-K-7z0qE8.js +1 -0
- package/dist/public/assets/w-K-7z0qE8.js +1 -0
- package/dist/public/assets/w._-D5d4klUv.js +1 -0
- package/dist/public/assets/w._-K-7z0qE8.js +1 -0
- package/lib/review/markdown.mjs +6 -2
- package/lib/setup/catalog.d.mts +3 -1
- package/lib/setup/catalog.mjs +11 -2
- package/lib/setup/doctor.mjs +96 -20
- package/lib/setup/install.d.mts +9 -3
- package/lib/setup/install.mjs +68 -39
- package/lib/share/manifest.d.mts +27 -0
- package/lib/share/manifest.mjs +144 -0
- package/package.json +6 -2
- package/scripts/migrate.mjs +101 -30
- package/dist/_BIDn_RW1.js +0 -2
- package/dist/public/assets/_-3OmHyNU.js.br +0 -0
- package/dist/public/assets/_0_ngOEbL.js.br +0 -0
- package/dist/public/assets/_8hF31A2G.js.br +0 -0
- package/dist/public/assets/_B6bSumz1.js.br +0 -0
- package/dist/public/assets/_BCKhXQct2.js.br +0 -0
- package/dist/public/assets/_BDRc66NB2.js.br +0 -0
- package/dist/public/assets/_BEOZghNJ2.js.br +0 -0
- package/dist/public/assets/_BEPt7EWk.js.br +0 -0
- package/dist/public/assets/_BFgJoTOo.js.br +0 -0
- package/dist/public/assets/_BGHYY00K2.js.br +0 -0
- package/dist/public/assets/_BHgE7f-_2.js.br +0 -0
- package/dist/public/assets/_BIsQjQ872.js.br +0 -0
- package/dist/public/assets/_BLgtdDQm.js.br +0 -0
- package/dist/public/assets/_BPcKgx9L.js.br +0 -0
- package/dist/public/assets/_BUmLRB7c2.js.br +0 -0
- package/dist/public/assets/_B_MP9UES.js.br +0 -0
- package/dist/public/assets/_BaiP7ogH.js.br +0 -0
- package/dist/public/assets/_BbE6iGBd.js.br +0 -0
- package/dist/public/assets/_BfZMmKaW.js.br +0 -0
- package/dist/public/assets/_BilqQTfw.js.br +0 -0
- package/dist/public/assets/_BqNoqWIY.js.br +0 -0
- package/dist/public/assets/_BrTLGsp82.js.br +0 -0
- package/dist/public/assets/_Brws7C1N.js.br +0 -0
- package/dist/public/assets/_BtmFYBHk.js.br +0 -0
- package/dist/public/assets/_BuF6uiIm.js.br +0 -0
- package/dist/public/assets/_BzULaZGs.js.br +0 -0
- package/dist/public/assets/_CG2uZvAG.js.br +0 -0
- package/dist/public/assets/_CIio55Q2.js.br +0 -0
- package/dist/public/assets/_CJ_9Hl5d.js.br +0 -0
- package/dist/public/assets/_CQ-tqbUq.js.br +0 -0
- package/dist/public/assets/_CYLlpjQc.js.br +0 -0
- package/dist/public/assets/_Ca811EeR.js.br +0 -0
- package/dist/public/assets/_CeECfdVo2.js.br +0 -0
- package/dist/public/assets/_CeVHIZWy2.js.br +0 -0
- package/dist/public/assets/_Ces5jihM.js.br +0 -7
- package/dist/public/assets/_CihMY3_B2.js.br +0 -0
- package/dist/public/assets/_CkBv_F0f.js.br +0 -0
- package/dist/public/assets/_CrPK-ZOH2.js.br +0 -0
- package/dist/public/assets/_Cv-4N4xQ.js.br +0 -0
- package/dist/public/assets/_Cvly93xo2.js.br +0 -0
- package/dist/public/assets/_CwZCc-fE2.js.br +0 -0
- package/dist/public/assets/_CwtAB8Ju2.js.br +0 -0
- package/dist/public/assets/_CzMjLSTK.js.br +0 -0
- package/dist/public/assets/_D11ZFURg.js.br +0 -0
- package/dist/public/assets/_D2be5yUI.js.br +0 -0
- package/dist/public/assets/_D2xWjoK-2.js.br +0 -0
- package/dist/public/assets/_D4V7vTBe.js.br +0 -0
- package/dist/public/assets/_D8lg2J6H.js.br +0 -0
- package/dist/public/assets/_DBXfsrRd.js.br +0 -0
- package/dist/public/assets/_DDag_nXJ.js.br +0 -0
- package/dist/public/assets/_DRKLaQtq.js.br +0 -0
- package/dist/public/assets/_DWctbEWg.js.br +0 -3
- package/dist/public/assets/_DZgx_rAt.js.br +0 -0
- package/dist/public/assets/_DdYfAoJz.js.br +0 -0
- package/dist/public/assets/_DdnCyOPs.js.br +0 -0
- package/dist/public/assets/_DfpMH3So2.js.br +0 -0
- package/dist/public/assets/_DhLWIgCs.js.br +0 -0
- package/dist/public/assets/_DiaYv9e1.js.br +0 -0
- package/dist/public/assets/_Du-i6H8r.js.br +0 -0
- package/dist/public/assets/_F8phZWNM2.js.br +0 -0
- package/dist/public/assets/_FEbRnVo7.js.br +0 -0
- package/dist/public/assets/_GdcmEEuJ.js.br +0 -0
- package/dist/public/assets/_N0Ea8Q_R.js.br +0 -0
- package/dist/public/assets/_QuFTKxMO2.js.br +0 -0
- package/dist/public/assets/_cS3NYZ_K2.js.br +0 -0
- package/dist/public/assets/_cdbANa0O.js.br +0 -0
- package/dist/public/assets/_dBVoJwVC.js.br +0 -0
- package/dist/public/assets/_fR2ilomn.js.br +0 -0
- package/dist/public/assets/_h6HS-Zb_2.js.br +0 -0
- package/dist/public/assets/_p1VLQxPw.js.br +0 -0
- package/dist/public/assets/_uJTU0UZd2.js.br +0 -0
- package/dist/public/assets/_wc-pkVQS.js.br +0 -0
- package/dist/public/assets/_zJkCtRhb.js.br +0 -0
- package/dist/public/assets/app-page-DgsAA8Om.css +0 -1
- package/dist/public/assets/app-page-DgsAA8Om.css.br +0 -0
- package/dist/public/assets/diff-view-BqwTpf5k.css +0 -1
- package/dist/public/assets/diff-view-BqwTpf5k.css.br +0 -0
- package/dist/public/assets/new-cBa61wMi.js +0 -1
- package/dist/public/assets/settings-cBa61wMi.js +0 -1
- package/dist/public/assets/w-cBa61wMi.js +0 -1
- package/dist/public/assets/w._-B9llVTHr.js +0 -1
- package/dist/public/assets/w._-cBa61wMi.js +0 -1
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { U as subscriberCount, V as publish, W as subscriberJoins, dt as all, ft as db, g as sessionStates, l as listSessions } from "./_Cr71Xd0d.js";
|
|
2
|
+
import { A as portsByWorkspace, J as hostToken, K as forgetToken, M as headOid, Q as ownsBranch, R as repoParent, V as DEFAULT_HOST, Y as joinRepo, Z as splitRepo, h as listWorkspaces, o as pushFailureFor, q as graphqlUrl, z as swr } from "./_DJyHc1w-.js";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
//#region src/server/github-api.ts
|
|
5
|
+
/** Run a GraphQL query against one host.
|
|
6
|
+
*
|
|
7
|
+
* Partial failures come back as a populated `errors` alongside usable `data`
|
|
8
|
+
* — one repo deleted, renamed, or outside this token's scope. Callers want
|
|
9
|
+
* the repos that did resolve, so `data` wins whenever it is present; this
|
|
10
|
+
* matches how the `gh` path treated a non-zero exit with usable stdout. */
|
|
11
|
+
async function graphql(query, host = DEFAULT_HOST) {
|
|
12
|
+
const res = await fetch(graphqlUrl(host), {
|
|
13
|
+
method: "POST",
|
|
14
|
+
headers: {
|
|
15
|
+
authorization: `Bearer ${await hostToken(host)}`,
|
|
16
|
+
"content-type": "application/json",
|
|
17
|
+
accept: "application/vnd.github+json",
|
|
18
|
+
"user-agent": "work"
|
|
19
|
+
},
|
|
20
|
+
body: JSON.stringify({ query })
|
|
21
|
+
});
|
|
22
|
+
if (!res.ok && res.status !== 200) {
|
|
23
|
+
if (res.status === 401 || res.status === 403) forgetToken(host);
|
|
24
|
+
throw new Error(`github graphql ${res.status}`);
|
|
25
|
+
}
|
|
26
|
+
const body = await res.json();
|
|
27
|
+
if (!body?.data) throw new Error(body?.errors?.[0]?.message || "graphql response without data");
|
|
28
|
+
return body.data;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/server/prs.ts
|
|
32
|
+
var TTL_MS$1 = 12e4;
|
|
33
|
+
/** PRs whose head is the workspace branch or one of its `-topic` lanes.
|
|
34
|
+
* `exclude` lists other workspaces' branches — slugs are user-chosen, so
|
|
35
|
+
* another workspace's branch can extend this prefix and its PRs must not
|
|
36
|
+
* be attributed here. */
|
|
37
|
+
function prsForBranchPrefix(prs, prefix, exclude = []) {
|
|
38
|
+
return prs.filter((pr) => ownsBranch(pr.headRefName, prefix) && !exclude.some((x) => ownsBranch(pr.headRefName, x)));
|
|
39
|
+
}
|
|
40
|
+
/** `[host/]owner/name#branch` — the host prefix travels with the name. */
|
|
41
|
+
var branchKey = (fullName, branch) => `${fullName}#${branch}`;
|
|
42
|
+
/** One workspace's PRs in one repo — its branch and every `-topic` lane, in
|
|
43
|
+
* every state. Asking for the workspace's own branches is what keeps this
|
|
44
|
+
* proportional to the workspace rather than to the repo: the alternative,
|
|
45
|
+
* a recency window over all of a repo's PRs, fetched roughly twice what it
|
|
46
|
+
* kept here and still aged a quiet workspace out on a busy repo.
|
|
47
|
+
* Key: `fullName#branch`. */
|
|
48
|
+
var branchPrs = swr(TTL_MS$1, async (key, refresh) => {
|
|
49
|
+
const sep = key.indexOf("#");
|
|
50
|
+
const fullName = key.slice(0, sep);
|
|
51
|
+
const { host, name } = splitRepo(fullName);
|
|
52
|
+
const upstream = await repoParent(fullName);
|
|
53
|
+
return (await searchPrs(host, upstream ? [name, splitRepo(upstream).name] : [name], [key.slice(sep + 1)], refresh)).filter((n) => ownsNode(n, fullName, upstream));
|
|
54
|
+
});
|
|
55
|
+
/** A workspace repo's PRs, minus any belonging to a workspace whose branch
|
|
56
|
+
* extends this one's. `since` is an imported workspace's arrival: a
|
|
57
|
+
* restored or joined workspace keeps its branch name, so the branch's whole
|
|
58
|
+
* history on GitHub matches — finished PRs from before it arrived here are
|
|
59
|
+
* its previous life's, not chips to dismiss again. Open PRs always show;
|
|
60
|
+
* hiding live work would be the worse mistake. */
|
|
61
|
+
async function workspacePrs(fullName, branch, foreign, refresh = false, since) {
|
|
62
|
+
return prsForBranchPrefix(await branchPrs(branchKey(fullName, branch), refresh).catch(() => []), branch, foreign).filter((pr) => !since || pr.state === "OPEN" || !pr.updatedAt || pr.updatedAt >= since);
|
|
63
|
+
}
|
|
64
|
+
/** Refresh many repos' PRs with one GraphQL request (vs one `gh pr list`
|
|
65
|
+
* process per repo) — called from the status watcher for active
|
|
66
|
+
* workspaces so open/merge/close flips surface in ~watch-tick time
|
|
67
|
+
* instead of waiting out the per-repo TTL. Throttled internally. */
|
|
68
|
+
var BATCH_MIN_MS = 15e3;
|
|
69
|
+
/** After a detected local push, poll fast for a bit — the PR appears
|
|
70
|
+
* and merges/closes in the minutes right after. */
|
|
71
|
+
var HOT_MIN_MS = 3e3;
|
|
72
|
+
var HOT_WINDOW_MS = 18e4;
|
|
73
|
+
var lastBatch = 0;
|
|
74
|
+
var hotUntil = 0;
|
|
75
|
+
function notePushActivity() {
|
|
76
|
+
hotUntil = Date.now() + HOT_WINDOW_MS;
|
|
77
|
+
}
|
|
78
|
+
/** Inside the post-push window where PR state is actively flipping. */
|
|
79
|
+
function inHotWindow() {
|
|
80
|
+
return Date.now() < hotUntil;
|
|
81
|
+
}
|
|
82
|
+
/** `headRefOid` is the PR's own head commit, which is what the UI compares
|
|
83
|
+
* against. Reaching through `headRef` gets the branch's *current* tip
|
|
84
|
+
* instead — a different commit entirely once a workspace branch is reused,
|
|
85
|
+
* and `headRef { oid }` is not even a field, so GitHub answers 200 with an
|
|
86
|
+
* `errors` array and no `data`. */
|
|
87
|
+
var GQL_PR_FIELDS = "number title url headRefName baseRefName isDraft state headRefOid updatedAt";
|
|
88
|
+
/** Does this search hit belong to `fullName`'s workspace repo? Directly when
|
|
89
|
+
* the PR lives in that repo *with its head branch there too*; via the fork
|
|
90
|
+
* case when it lives in `upstream` with its head on the fork. The head check
|
|
91
|
+
* on both arms keeps one PR from being claimed twice when a workspace holds
|
|
92
|
+
* a fork and its upstream, and keeps a same-named branch pushed by someone
|
|
93
|
+
* else's fork from being claimed at all. A null headRepository (head repo
|
|
94
|
+
* deleted) stays with the PR's own repo. */
|
|
95
|
+
function ownsNode(n, fullName, upstream) {
|
|
96
|
+
const head = n.headRepository?.nameWithOwner;
|
|
97
|
+
return n.repository.nameWithOwner === fullName && (!head || head === fullName) || !!upstream && n.repository.nameWithOwner === upstream && head === fullName;
|
|
98
|
+
}
|
|
99
|
+
/** Dedup key: PR numbers restart per repo, and a fork target's list spans
|
|
100
|
+
* the fork and its upstream. */
|
|
101
|
+
var nodeKey = (p) => `${p.repository.nameWithOwner}#${p.number}`;
|
|
102
|
+
/** Search's `head:` matches a branch *and* its `-topic` lanes, so one term
|
|
103
|
+
* covers a whole workspace, and repeated terms are OR'd within a qualifier
|
|
104
|
+
* while different qualifiers are AND'd — `repo:a repo:b head:x head:y`
|
|
105
|
+
* reads as (a|b) and (x|y). That is what lets every workspace share one
|
|
106
|
+
* request instead of needing an alias per repo and per branch. */
|
|
107
|
+
function searchTerms(repos, branches) {
|
|
108
|
+
return [...repos.map((r) => `repo:${r}`), ...branches.map((b) => `head:${b}`)].join(" ");
|
|
109
|
+
}
|
|
110
|
+
/** Finished PRs are asked for by recency, open ones are not: a merged PR
|
|
111
|
+
* only has to outlive its dismissal, while an open PR must stay visible
|
|
112
|
+
* however long it has sat idle — which is exactly what a recency window
|
|
113
|
+
* over the whole repo got wrong. */
|
|
114
|
+
var CLOSED_FIRST = 60;
|
|
115
|
+
var OPEN_FIRST = 100;
|
|
116
|
+
/** Search pages at 100. Open PRs are the page that can genuinely overflow
|
|
117
|
+
* (every workspace's, in one request), so it is followed — bounded, because
|
|
118
|
+
* an unbounded follow is a way to hang the status tick on a bad query. */
|
|
119
|
+
var MAX_OPEN_PAGES = 4;
|
|
120
|
+
var searchField = (alias, query, first, after) => `${alias}: search(query: ${JSON.stringify(query)}, type: ISSUE, first: ${first}${after ? `, after: ${JSON.stringify(after)}` : ""}) { pageInfo { hasNextPage endCursor } nodes { ... on PullRequest { ${GQL_PR_FIELDS} repository { nameWithOwner } headRepository { nameWithOwner } } } }`;
|
|
121
|
+
/** Every PR on the given branches (and their lanes) across the given repos
|
|
122
|
+
* of one host (`repos` are bare `owner/name`). `refresh` is accepted for the
|
|
123
|
+
* swr signature; freshness here is GitHub's, not ours. Nodes come back with
|
|
124
|
+
* the host folded into `repository.nameWithOwner` so callers compare full
|
|
125
|
+
* names. */
|
|
126
|
+
async function searchPrs(host, repos, branches, _refresh) {
|
|
127
|
+
const terms = searchTerms(repos, branches);
|
|
128
|
+
const out = [];
|
|
129
|
+
let cursor;
|
|
130
|
+
for (let page = 0; page < MAX_OPEN_PAGES; page++) {
|
|
131
|
+
const data = await graphql("query {" + searchField("open", `is:pr is:open ${terms}`, OPEN_FIRST, cursor) + (page === 0 ? " " + searchField("done", `is:pr is:closed sort:updated-desc ${terms}`, CLOSED_FIRST) : "") + "}", host);
|
|
132
|
+
const open = data.open;
|
|
133
|
+
const done = data.done;
|
|
134
|
+
for (const node of [...open?.nodes ?? [], ...done?.nodes ?? []]) if (node?.number) out.push({
|
|
135
|
+
...node,
|
|
136
|
+
repository: { nameWithOwner: joinRepo(host, node.repository.nameWithOwner) },
|
|
137
|
+
headRepository: node.headRepository ? { nameWithOwner: joinRepo(host, node.headRepository.nameWithOwner) } : null
|
|
138
|
+
});
|
|
139
|
+
if (!open?.pageInfo.hasNextPage || !open.pageInfo.endCursor) break;
|
|
140
|
+
cursor = open.pageInfo.endCursor;
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
async function refreshPrsBatch(targets, force = false) {
|
|
145
|
+
const wanted = [...new Map(targets.filter((t) => t.fullName.includes("/") && t.branch).map((t) => [branchKey(t.fullName, t.branch), t])).values()];
|
|
146
|
+
const minMs = force ? 2e3 : Date.now() < hotUntil ? HOT_MIN_MS : BATCH_MIN_MS;
|
|
147
|
+
if (!wanted.length || Date.now() - lastBatch < minMs) return false;
|
|
148
|
+
const prevBatch = lastBatch;
|
|
149
|
+
lastBatch = Date.now();
|
|
150
|
+
try {
|
|
151
|
+
const upstreams = new Map(await Promise.all(wanted.map(async (t) => [t.fullName, await repoParent(t.fullName)])));
|
|
152
|
+
const byHost = /* @__PURE__ */ new Map();
|
|
153
|
+
for (const t of wanted) {
|
|
154
|
+
const { host, name } = splitRepo(t.fullName);
|
|
155
|
+
const names = (byHost.get(host) || /* @__PURE__ */ new Set()).add(name);
|
|
156
|
+
const upstream = upstreams.get(t.fullName);
|
|
157
|
+
if (upstream) names.add(splitRepo(upstream).name);
|
|
158
|
+
byHost.set(host, names);
|
|
159
|
+
}
|
|
160
|
+
const branches = [...new Set(wanted.map((t) => t.branch))];
|
|
161
|
+
const results = await Promise.all([...byHost].map(([host, names]) => searchPrs(host, [...names], branches).catch((err) => {
|
|
162
|
+
if (byHost.size === 1) throw err;
|
|
163
|
+
return null;
|
|
164
|
+
})));
|
|
165
|
+
const nodes = results.flatMap((r) => r ?? []);
|
|
166
|
+
const failedHosts = new Set([...byHost.keys()].filter((_, i) => results[i] === null));
|
|
167
|
+
for (const target of wanted) {
|
|
168
|
+
if (failedHosts.has(splitRepo(target.fullName).host)) continue;
|
|
169
|
+
const foreign = branches.filter((b) => b !== target.branch);
|
|
170
|
+
const key = branchKey(target.fullName, target.branch);
|
|
171
|
+
const incoming = prsForBranchPrefix(nodes.filter((n) => ownsNode(n, target.fullName, upstreams.get(target.fullName) ?? null)), target.branch, foreign);
|
|
172
|
+
const open = incoming.filter((p) => p.state === "OPEN");
|
|
173
|
+
const openKeys = new Set(open.map(nodeKey));
|
|
174
|
+
const done = /* @__PURE__ */ new Map();
|
|
175
|
+
for (const p of branchPrs.get(key) ?? []) if (p.state !== "OPEN" && !openKeys.has(nodeKey(p))) done.set(nodeKey(p), p);
|
|
176
|
+
for (const p of incoming) if (p.state !== "OPEN" && !openKeys.has(nodeKey(p))) done.set(nodeKey(p), p);
|
|
177
|
+
branchPrs.set(key, [...open, ...done.values()]);
|
|
178
|
+
}
|
|
179
|
+
return true;
|
|
180
|
+
} catch (err) {
|
|
181
|
+
lastBatch = prevBatch;
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Confirm a finished (merged/closed) PR so it leaves the manage list. */
|
|
186
|
+
function dismissPr(workspaceId, fullName, number) {
|
|
187
|
+
db.prepare("INSERT OR IGNORE INTO dismissed_prs (workspace_id, full_name, number) VALUES (?, ?, ?)").run(workspaceId, fullName, number);
|
|
188
|
+
}
|
|
189
|
+
/** Drop dismissed PRs from a repo's list — unless one reopened. Keyed by
|
|
190
|
+
* each PR's own repo + number: a fork target's list spans the fork and its
|
|
191
|
+
* upstream (same numbers restart per repo), so a workspace-repo-wide key
|
|
192
|
+
* would let dismissing upstream #N hide the fork's own #N too. Rows written
|
|
193
|
+
* before PRs carried their repo are keyed by the workspace repo alone and
|
|
194
|
+
* still match via that fallback. */
|
|
195
|
+
function withoutDismissed(workspaceId, fullName, list) {
|
|
196
|
+
const dismissed = new Set(all("SELECT full_name, number FROM dismissed_prs WHERE workspace_id = ?", workspaceId).map((row) => `${row.full_name}#${row.number}`));
|
|
197
|
+
return list.filter((pr) => pr.state === "OPEN" || !dismissed.has(`${pr.repository?.nameWithOwner ?? fullName}#${pr.number}`));
|
|
198
|
+
}
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region src/server/status.ts
|
|
201
|
+
var TTL_MS = 2e3;
|
|
202
|
+
var snapshot = null;
|
|
203
|
+
var inflight = null;
|
|
204
|
+
var snapshotGen = 0;
|
|
205
|
+
/** Drop the cached snapshot AND detach any in-flight compute — callers
|
|
206
|
+
* after an invalidation get a computation that starts from fresh state. */
|
|
207
|
+
function invalidateSnapshot() {
|
|
208
|
+
snapshot = null;
|
|
209
|
+
snapshotGen++;
|
|
210
|
+
inflight = null;
|
|
211
|
+
}
|
|
212
|
+
function statusForAll() {
|
|
213
|
+
if (snapshot && Date.now() - snapshot.at < TTL_MS) return Promise.resolve(snapshot.value);
|
|
214
|
+
if (!inflight) {
|
|
215
|
+
const gen = snapshotGen;
|
|
216
|
+
const run = computeStatus().then((value) => {
|
|
217
|
+
if (gen === snapshotGen) snapshot = {
|
|
218
|
+
at: Date.now(),
|
|
219
|
+
value
|
|
220
|
+
};
|
|
221
|
+
return value;
|
|
222
|
+
}).finally(() => {
|
|
223
|
+
if (inflight === run) inflight = null;
|
|
224
|
+
});
|
|
225
|
+
inflight = run;
|
|
226
|
+
}
|
|
227
|
+
return inflight;
|
|
228
|
+
}
|
|
229
|
+
/** Push-based freshness: while any events-bus client is connected,
|
|
230
|
+
* recompute the (shared, deduped) snapshot on a slow tick and publish it
|
|
231
|
+
* only when it actually changed — ports appearing, PR open/merge/close flips reach
|
|
232
|
+
* every client in ~15s instead of waiting out a slow poll, and idle
|
|
233
|
+
* systems push nothing at all. */
|
|
234
|
+
var WATCH_MS = 1e4;
|
|
235
|
+
/** Right after a local push, PR+check state flips within seconds — tick
|
|
236
|
+
* fast so the badge lands while it still feels immediate. */
|
|
237
|
+
var WATCH_HOT_MS = 4e3;
|
|
238
|
+
var watching = false;
|
|
239
|
+
/** Last published state per workspace, so a tick can publish the ones that
|
|
240
|
+
* actually moved. Comparing the whole snapshot instead meant one agent's
|
|
241
|
+
* commit — or any session, port or PR flip in a workspace nobody is
|
|
242
|
+
* looking at — pushed every workspace to every client, which each then
|
|
243
|
+
* re-rendered and re-fingerprinted to conclude nothing of theirs had
|
|
244
|
+
* changed. That amplification grows with the number of workspaces. */
|
|
245
|
+
var lastPushed = /* @__PURE__ */ new Map();
|
|
246
|
+
var lastJoins = -1;
|
|
247
|
+
async function watchTick() {
|
|
248
|
+
if (!subscriberCount()) return;
|
|
249
|
+
try {
|
|
250
|
+
if (await refreshPrsBatch(activeRepoTargets()).catch(() => false)) invalidateSnapshot();
|
|
251
|
+
const value = await statusForAll();
|
|
252
|
+
const joins = subscriberJoins();
|
|
253
|
+
const everything = joins !== lastJoins;
|
|
254
|
+
lastJoins = joins;
|
|
255
|
+
const changed = {};
|
|
256
|
+
for (const [id, ws] of Object.entries(value)) {
|
|
257
|
+
const json = JSON.stringify(ws);
|
|
258
|
+
if (everything || lastPushed.get(id) !== json) changed[id] = ws;
|
|
259
|
+
lastPushed.set(id, json);
|
|
260
|
+
}
|
|
261
|
+
for (const id of lastPushed.keys()) if (!(id in value)) lastPushed.delete(id);
|
|
262
|
+
if (Object.keys(changed).length) publish("status.changed", changed);
|
|
263
|
+
} catch {}
|
|
264
|
+
}
|
|
265
|
+
var watchTimer;
|
|
266
|
+
function scheduleTick(ms) {
|
|
267
|
+
clearTimeout(watchTimer);
|
|
268
|
+
watchTimer = setTimeout(tick, ms);
|
|
269
|
+
watchTimer.unref?.();
|
|
270
|
+
}
|
|
271
|
+
async function tick() {
|
|
272
|
+
await watchTick();
|
|
273
|
+
scheduleTick(inHotWindow() ? WATCH_HOT_MS : WATCH_MS);
|
|
274
|
+
}
|
|
275
|
+
/** Recompute and push right now (e.g. a local push was detected) instead
|
|
276
|
+
* of waiting out the watch tick — and drop the loop into its fast cadence
|
|
277
|
+
* (the push opened the hot window, but the pending timeout was scheduled
|
|
278
|
+
* for the slow one). */
|
|
279
|
+
function pokeStatusWatch() {
|
|
280
|
+
invalidateSnapshot();
|
|
281
|
+
watchTick().then(() => {
|
|
282
|
+
if (watching) scheduleTick(inHotWindow() ? WATCH_HOT_MS : WATCH_MS);
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
function startStatusWatch() {
|
|
286
|
+
if (watching) return;
|
|
287
|
+
watching = true;
|
|
288
|
+
scheduleTick(WATCH_MS);
|
|
289
|
+
}
|
|
290
|
+
/** Every active workspace's repos, paired with the branch that workspace
|
|
291
|
+
* works on — the batch refreshes both the recency window and the exact-head
|
|
292
|
+
* lookup for each, in one request. */
|
|
293
|
+
function activeRepoTargets() {
|
|
294
|
+
return listWorkspaces().filter((ws) => ws.status === "active").flatMap((ws) => ws.repos.map((r) => ({
|
|
295
|
+
fullName: r.full_name,
|
|
296
|
+
branch: ws.branch
|
|
297
|
+
})));
|
|
298
|
+
}
|
|
299
|
+
/** Status with PRs refetched first (throttled): a client returning to the
|
|
300
|
+
* foreground wants current PR state — merges/closes happen on GitHub and
|
|
301
|
+
* send no local signal, so without this they wait out the slow poll. */
|
|
302
|
+
async function statusForAllFresh() {
|
|
303
|
+
if (await refreshPrsBatch(activeRepoTargets(), true).catch(() => false)) invalidateSnapshot();
|
|
304
|
+
return statusForAll();
|
|
305
|
+
}
|
|
306
|
+
/** RSS here is the Node + Marko baseline (~80 MB empty, ~115 MB loaded),
|
|
307
|
+
* not a leak and not worth chasing — young-gen flags do not move it. */
|
|
308
|
+
async function computeStatus() {
|
|
309
|
+
const everyWorkspace = listWorkspaces();
|
|
310
|
+
const workspaces = everyWorkspace.filter((ws) => ws.status === "active");
|
|
311
|
+
const paths = new Map(workspaces.map((ws) => [ws.id, ws.path]));
|
|
312
|
+
const [ports, states] = await Promise.all([portsByWorkspace(paths), sessionStates()]);
|
|
313
|
+
const entries = await Promise.all(workspaces.map(async (ws) => {
|
|
314
|
+
const foreign = everyWorkspace.filter((w) => w.id !== ws.id).map((w) => w.branch);
|
|
315
|
+
const statuses = await Promise.all(ws.repos.map((repo) => repoStatus(ws, repo, foreign)));
|
|
316
|
+
return [ws.id, {
|
|
317
|
+
ports: ports.get(ws.id) || [],
|
|
318
|
+
repos: statuses,
|
|
319
|
+
...sessionCounts(ws.id, states)
|
|
320
|
+
}];
|
|
321
|
+
}));
|
|
322
|
+
return Object.fromEntries(entries);
|
|
323
|
+
}
|
|
324
|
+
async function repoStatus(ws, repo, foreign) {
|
|
325
|
+
const dir = path.join(ws.path, repo.worktree);
|
|
326
|
+
const [repoPrs, localHead] = await Promise.all([workspacePrs(repo.full_name, ws.branch, foreign, false, ws.imported_at).then((list) => withoutDismissed(ws.id, repo.full_name, list)), headOid(dir).then((h) => h.oid)]);
|
|
327
|
+
const unpushed = pushFailureFor(repo.full_name, ws.branch, foreign);
|
|
328
|
+
return {
|
|
329
|
+
full_name: repo.full_name,
|
|
330
|
+
worktree: repo.worktree,
|
|
331
|
+
...localHead && { localHead },
|
|
332
|
+
...unpushed && { unpushed },
|
|
333
|
+
prs: repoPrs
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
function sessionCounts(workspaceId, states) {
|
|
337
|
+
const sessions = listSessions(workspaceId).map((s) => ({
|
|
338
|
+
id: s.id,
|
|
339
|
+
agent: s.agent,
|
|
340
|
+
title: s.title,
|
|
341
|
+
state: states[s.id] || { alive: false }
|
|
342
|
+
}));
|
|
343
|
+
const live = sessions.map((s) => s.state).filter((state) => !!state.alive);
|
|
344
|
+
return {
|
|
345
|
+
sessions,
|
|
346
|
+
agents: live.length,
|
|
347
|
+
working: live.filter((state) => state.phase === "working").length,
|
|
348
|
+
waiting: live.filter((state) => state.phase === "waiting").length
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
//#endregion
|
|
352
|
+
export { statusForAllFresh as a, refreshPrsBatch as c, statusForAll as i, workspacePrs as l, pokeStatusWatch as n, dismissPr as o, startStatusWatch as r, notePushActivity as s, activeRepoTargets as t };
|
|
@@ -1594,6 +1594,9 @@ function _attr_details_or_dialog_open(scopeId, nodeAccessor, open, openChange, s
|
|
|
1594
1594
|
let normalizedOpen = isNotVoid(open);
|
|
1595
1595
|
return openChange && writeControlledScope(4, scopeId, nodeAccessor, normalizedOpen || void 0, openChange, serializeType), normalizedOpen ? " open" : "";
|
|
1596
1596
|
}
|
|
1597
|
+
function _attr_nonce() {
|
|
1598
|
+
return getChunk().boundary.state.nonceAttr;
|
|
1599
|
+
}
|
|
1597
1600
|
function _attr(name, value) {
|
|
1598
1601
|
return isVoid(value) ? "" : nonVoidAttr(name, value);
|
|
1599
1602
|
}
|
|
@@ -1975,7 +1978,7 @@ var toastTitle = {
|
|
|
1975
1978
|
};
|
|
1976
1979
|
//#endregion
|
|
1977
1980
|
//#region src/tags/icons/icon-base.marko
|
|
1978
|
-
var icon_base_default = _template("
|
|
1981
|
+
var icon_base_default = _template("N", (input) => {
|
|
1979
1982
|
const $scope0_reason = _scope_reason();
|
|
1980
1983
|
const $scope0_id = _scope_id();
|
|
1981
1984
|
const size = input.size ?? 15;
|
|
@@ -1984,7 +1987,7 @@ var icon_base_default = _template("M", (input) => {
|
|
|
1984
1987
|
});
|
|
1985
1988
|
//#endregion
|
|
1986
1989
|
//#region src/tags/icons/icon-xmark.marko
|
|
1987
|
-
var icon_xmark_default = _template("
|
|
1990
|
+
var icon_xmark_default = _template("nb", (input) => {
|
|
1988
1991
|
const $scope0_reason = _scope_reason(), $sg__input_size__OR__input_class = _serialize_guard($scope0_reason, 0);
|
|
1989
1992
|
const $scope0_id = _scope_id();
|
|
1990
1993
|
_set_serialize_reason({
|
|
@@ -2001,7 +2004,7 @@ var icon_xmark_default = _template("lb", (input) => {
|
|
|
2001
2004
|
});
|
|
2002
2005
|
//#endregion
|
|
2003
2006
|
//#region src/tags/toast.marko
|
|
2004
|
-
var toast_default = _template("
|
|
2007
|
+
var toast_default = _template("D", (input) => {
|
|
2005
2008
|
const $scope0_reason = _scope_reason(), $sg__input_title = _serialize_guard($scope0_reason, 7), $sg__input_title__OR__input_content__OR__input_action__OR__input_onDismiss = _serialize_guard($scope0_reason, 5), $sg__input_content = _serialize_guard($scope0_reason, 8), $sg__input_action = _serialize_guard($scope0_reason, 9), $sg__input_action__OR__input_onDismiss = _serialize_guard($scope0_reason, 3), $sg__input_onDismiss = _serialize_guard($scope0_reason, 11), $si__input_content = _serialize_if($scope0_reason, 8), $si__input_action__OR__input_onDismiss = _serialize_if($scope0_reason, 3), $si__input_action_content = _serialize_if($scope0_reason, 10);
|
|
2006
2009
|
const $scope0_id = _scope_id();
|
|
2007
2010
|
const $input_action_content__closures = /* @__PURE__ */ new Set();
|
|
@@ -2058,7 +2061,7 @@ var toast_default = _template("C", (input) => {
|
|
|
2058
2061
|
_html(`<button${_attr_class([iconBtnRow, "_bm"])} type=button title=Dismiss aria-label=Dismiss>`);
|
|
2059
2062
|
icon_xmark_default({ size: 14 });
|
|
2060
2063
|
_html(`</button>${_el_resume($scope5_id, "a")}`);
|
|
2061
|
-
_script($scope5_id, "
|
|
2064
|
+
_script($scope5_id, "D0");
|
|
2062
2065
|
writeScope($scope5_id, { _: _scope_with_id($scope3_id) });
|
|
2063
2066
|
return 0;
|
|
2064
2067
|
}
|
|
@@ -2069,8 +2072,8 @@ var toast_default = _template("C", (input) => {
|
|
|
2069
2072
|
}
|
|
2070
2073
|
}, $scope0_id, "e", $sg__input_action__OR__input_onDismiss, $sg__input_action__OR__input_onDismiss, $sg__input_title__OR__input_content__OR__input_action__OR__input_onDismiss, 0, 1);
|
|
2071
2074
|
_html(`</div>${_el_resume($scope0_id, "a")}`);
|
|
2072
|
-
_script($scope0_id, "
|
|
2073
|
-
_script($scope0_id, "
|
|
2075
|
+
_script($scope0_id, "D1");
|
|
2076
|
+
_script($scope0_id, "D2");
|
|
2074
2077
|
writeScope($scope0_id, {
|
|
2075
2078
|
j: _serialize_if($scope0_reason, 7) && title,
|
|
2076
2079
|
k: _serialize_if($scope0_reason, 0) && inputClass,
|
|
@@ -2128,8 +2131,7 @@ function diffTreeOpen() {
|
|
|
2128
2131
|
}
|
|
2129
2132
|
function diffScope() {
|
|
2130
2133
|
const v = get("diff-scope");
|
|
2131
|
-
|
|
2132
|
-
return get("diff-uncommitted") === "1" ? "working" : "committed";
|
|
2134
|
+
return v === "working" || v === "dirty" ? v : "committed";
|
|
2133
2135
|
}
|
|
2134
2136
|
function setDiffScope(scope) {
|
|
2135
2137
|
set("diff-scope", scope);
|
|
@@ -2171,12 +2173,12 @@ function theme() {
|
|
|
2171
2173
|
function setTheme(mode) {
|
|
2172
2174
|
set("theme", mode === "system" ? null : mode);
|
|
2173
2175
|
}
|
|
2174
|
-
var sectionCount = "
|
|
2175
|
-
var row = "
|
|
2176
|
+
var sectionCount = "_bq _H _I";
|
|
2177
|
+
var row = "_bB _bt";
|
|
2176
2178
|
var iconBtn = "_Z _j";
|
|
2177
2179
|
//#endregion
|
|
2178
2180
|
//#region src/tags/icons/icon-refresh.marko
|
|
2179
|
-
var icon_refresh_default = _template("
|
|
2181
|
+
var icon_refresh_default = _template("fb", (input) => {
|
|
2180
2182
|
const $scope0_reason = _scope_reason(), $sg__input_size__OR__input_class = _serialize_guard($scope0_reason, 0);
|
|
2181
2183
|
const $scope0_id = _scope_id();
|
|
2182
2184
|
_set_serialize_reason({
|
|
@@ -2193,7 +2195,7 @@ var icon_refresh_default = _template("db", (input) => {
|
|
|
2193
2195
|
});
|
|
2194
2196
|
//#endregion
|
|
2195
2197
|
//#region src/tags/icons/icon-back.marko
|
|
2196
|
-
var icon_back_default = _template("
|
|
2198
|
+
var icon_back_default = _template("M", (input) => {
|
|
2197
2199
|
const $scope0_reason = _scope_reason(), $sg__input_size__OR__input_class = _serialize_guard($scope0_reason, 0);
|
|
2198
2200
|
const $scope0_id = _scope_id();
|
|
2199
2201
|
_set_serialize_reason({
|
|
@@ -2210,7 +2212,7 @@ var icon_back_default = _template("L", (input) => {
|
|
|
2210
2212
|
});
|
|
2211
2213
|
//#endregion
|
|
2212
2214
|
//#region src/tags/icons/icon-chevron-right.marko
|
|
2213
|
-
var icon_chevron_right_default = _template("
|
|
2215
|
+
var icon_chevron_right_default = _template("S", (input) => {
|
|
2214
2216
|
const $scope0_reason = _scope_reason(), $sg__input_size__OR__input_class = _serialize_guard($scope0_reason, 0);
|
|
2215
2217
|
const $scope0_id = _scope_id();
|
|
2216
2218
|
_set_serialize_reason({
|
|
@@ -2227,7 +2229,7 @@ var icon_chevron_right_default = _template("R", (input) => {
|
|
|
2227
2229
|
});
|
|
2228
2230
|
//#endregion
|
|
2229
2231
|
//#region src/tags/icons/icon-arrow-up.marko
|
|
2230
|
-
var icon_arrow_up_default = _template("
|
|
2232
|
+
var icon_arrow_up_default = _template("L", (input) => {
|
|
2231
2233
|
const $scope0_reason = _scope_reason(), $sg__input_size__OR__input_class = _serialize_guard($scope0_reason, 0);
|
|
2232
2234
|
const $scope0_id = _scope_id();
|
|
2233
2235
|
_set_serialize_reason({
|
|
@@ -2244,7 +2246,7 @@ var icon_arrow_up_default = _template("K", (input) => {
|
|
|
2244
2246
|
});
|
|
2245
2247
|
//#endregion
|
|
2246
2248
|
//#region src/tags/icons/icon-search.marko
|
|
2247
|
-
var icon_search_default = _template("
|
|
2249
|
+
var icon_search_default = _template("gb", (input) => {
|
|
2248
2250
|
const $scope0_reason = _scope_reason(), $sg__input_size__OR__input_class = _serialize_guard($scope0_reason, 0);
|
|
2249
2251
|
const $scope0_id = _scope_id();
|
|
2250
2252
|
_set_serialize_reason({
|
|
@@ -2303,7 +2305,7 @@ function fuzzy(query, text) {
|
|
|
2303
2305
|
}
|
|
2304
2306
|
//#endregion
|
|
2305
2307
|
//#region src/tags/icons/icon-sidebar.marko
|
|
2306
|
-
var icon_sidebar_default = _template("
|
|
2308
|
+
var icon_sidebar_default = _template("jb", (input) => {
|
|
2307
2309
|
const $scope0_reason = _scope_reason(), $sg__input_size__OR__input_class = _serialize_guard($scope0_reason, 0);
|
|
2308
2310
|
const $scope0_id = _scope_id();
|
|
2309
2311
|
_set_serialize_reason({
|
|
@@ -2318,11 +2320,11 @@ var icon_sidebar_default = _template("hb", (input) => {
|
|
|
2318
2320
|
});
|
|
2319
2321
|
_serialize_if($scope0_reason, 0) && writeScope($scope0_id, { a: _existing_scope($childScope) });
|
|
2320
2322
|
});
|
|
2321
|
-
var findInput = "
|
|
2322
|
-
var findIconBtn = "
|
|
2323
|
+
var findInput = "_f9 _l";
|
|
2324
|
+
var findIconBtn = "_gb _j";
|
|
2323
2325
|
//#endregion
|
|
2324
2326
|
//#region src/tags/icons/icon-arrow-down.marko
|
|
2325
|
-
var icon_arrow_down_default = _template("
|
|
2327
|
+
var icon_arrow_down_default = _template("I", (input) => {
|
|
2326
2328
|
const $scope0_reason = _scope_reason(), $sg__input_size__OR__input_class = _serialize_guard($scope0_reason, 0);
|
|
2327
2329
|
const $scope0_id = _scope_id();
|
|
2328
2330
|
_set_serialize_reason({
|
|
@@ -2338,4 +2340,4 @@ var icon_arrow_down_default = _template("H", (input) => {
|
|
|
2338
2340
|
_serialize_if($scope0_reason, 0) && writeScope($scope0_id, { a: _existing_scope($childScope) });
|
|
2339
2341
|
});
|
|
2340
2342
|
//#endregion
|
|
2341
|
-
export {
|
|
2343
|
+
export { _attr_style as $, parseRepoUrl as A, _subscribe as At, metaTrunc as B, setWorkspaceTab as C, _scope_reason as Ct, toast_default as D, _serialize_guard as Dt, workspaceTab as E, _sep as Et, btnSm as F, attrTag as Ft, _attr_class as G, tone as H, iconBtnLg as I, forOf as It, _attr_input_value as J, _attr_details_or_dialog_open as K, iconBtnRow as L, withPageAssets as Lt, repoWebUrl as M, _to_text as Mt, setPrimaryHost as N, _trailers as Nt, icon_xmark_default as O, _serialize_if as Ot, btnLg as P, _var as Pt, _attr_select_value as Q, iconBtnXs as R, writeScope as Rt, setTheme as S, _scope_id as St, theme as T, _script as Tt, $global as U, phase as V, _attr as W, _attr_option_value as X, _attr_nonce as Y, _attr_or as Z, diffScope as _, _id as _t, fuzzy as a, _dynamic_tag as at, setDiffPos as b, _resume as bt, icon_arrow_up_default as c, _el_resume as ct, icon_refresh_default as d, _existing_scope as dt, _attr_textarea_value as et, iconBtn as f, _flush_head as ft, diffPos as g, _html as gt, diffFilter as h, _hoist_read_error as ht, icon_sidebar_default as i, _content_resume as it, repoLabel as j, _template as jt, icon_base_default as k, _set_serialize_reason as kt, icon_chevron_right_default as l, _escape as lt, sectionCount as m, _hoist as mt, findIconBtn as n, _attrs_partial as nt, rankRepos as o, _el as ot, row as p, _for_of as pt, _attr_input_checked as q, findInput as r, _content as rt, icon_search_default as s, _el_read_error as st, icon_arrow_down_default as t, _attrs as tt, icon_back_default as u, _escape_script as ut, diffTreeOpen as v, _if as vt, sideNavOpen as w, _scope_with_id as wt, setDiffScope as x, _resume_branch as xt, ignoredSsoOrgs as y, _peek_scope_id as yt, inputLg as z };
|
|
@@ -9,7 +9,8 @@ import { promisify } from "node:util";
|
|
|
9
9
|
import { DatabaseSync } from "node:sqlite";
|
|
10
10
|
import { createHash } from "node:crypto";
|
|
11
11
|
//#region src/server/config.ts
|
|
12
|
-
var
|
|
12
|
+
var rawHome = os.homedir();
|
|
13
|
+
var home$1 = rawHome && rawHome !== "undefined" && rawHome !== "null" ? rawHome : "";
|
|
13
14
|
var config = {
|
|
14
15
|
/** Root directory containing all workspaces. */
|
|
15
16
|
workRoot: process.env.WORK_ROOT || path.join(home$1, "work"),
|
|
@@ -81,6 +82,7 @@ function utf8Locale(env) {
|
|
|
81
82
|
}
|
|
82
83
|
//#endregion
|
|
83
84
|
//#region src/server/db.ts
|
|
85
|
+
if (!path.isAbsolute(config.dataDir)) throw new Error(`data dir must be absolute, got "${config.dataDir}" — check WORK_DATA_DIR and $HOME`);
|
|
84
86
|
var db = new DatabaseSync(path.join(config.dataDir, "work.db"));
|
|
85
87
|
db.exec("PRAGMA busy_timeout = 5000");
|
|
86
88
|
function all(sql, ...params) {
|
|
@@ -165,6 +167,9 @@ function ensureColumn(table, column, decl) {
|
|
|
165
167
|
}
|
|
166
168
|
ensureColumn("review_comments", "head", "TEXT");
|
|
167
169
|
ensureColumn("review_comments", "snippet", "TEXT");
|
|
170
|
+
ensureColumn("workspaces", "materialized", "INTEGER NOT NULL DEFAULT 1");
|
|
171
|
+
ensureColumn("workspaces", "origin_branch", "TEXT");
|
|
172
|
+
ensureColumn("workspaces", "imported_at", "TEXT");
|
|
168
173
|
//#endregion
|
|
169
174
|
//#region lib/setup/agents.json
|
|
170
175
|
var agents_default = [
|
|
@@ -6551,7 +6556,7 @@ function publishChange(sessionId) {
|
|
|
6551
6556
|
const row = get("SELECT workspace_id FROM sessions WHERE id = ?", sessionId);
|
|
6552
6557
|
if (row?.workspace_id) {
|
|
6553
6558
|
const workspaceId = row.workspace_id;
|
|
6554
|
-
import("./
|
|
6559
|
+
import("./_B1lVb01g.js").then((m) => m.notifySessionsChanged(workspaceId));
|
|
6555
6560
|
return;
|
|
6556
6561
|
}
|
|
6557
6562
|
publish("sessions.changed");
|
|
@@ -8213,4 +8218,4 @@ function sleep(ms) {
|
|
|
8213
8218
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8214
8219
|
}
|
|
8215
8220
|
//#endregion
|
|
8216
|
-
export { setSetting as $, setScrapedPhase as A, saveSubscription as B, agentBadge as C, agentMeta as D, agentLabel as E, manifest as F, agentChoices as G, subscribe as H, normalizeAccent as I, enabledAgents as J, allPrefs as K, setInstance as L, ACCENT_RE as M, getInstance as N, clearAgentPhase as O, iconSvg as P, setPref as Q, deleteSubscription as R, blankRow as S, agentFromCommand as T, subscriberCount as U, publish as V, subscriberJoins as W, preferredAgent as X, getSetting as Y, setDisabledAgents as Z, tmuxName as _,
|
|
8221
|
+
export { setSetting as $, setScrapedPhase as A, saveSubscription as B, agentBadge as C, agentMeta as D, agentLabel as E, manifest as F, agentChoices as G, subscribe as H, normalizeAccent as I, enabledAgents as J, allPrefs as K, setInstance as L, ACCENT_RE as M, getInstance as N, clearAgentPhase as O, iconSvg as P, setPref as Q, deleteSubscription as R, blankRow as S, agentFromCommand as T, subscriberCount as U, publish as V, subscriberJoins as W, preferredAgent as X, getSetting as Y, setDisabledAgents as Z, tmuxName as _, git as _t, ensureTmuxServer as a, which as at, readHookPayload as b, config as bt, killWorkspaceSessions as c, agentById as ct, newSessionArgs as d, all as dt, discoverAgents as et, notifySessionsChanged as f, db as ft, sessionStates as g, gh as gt, sendToSession as h, TMUX_SOCKET as ht, disposeSessions as i, setupPath as it, setSessionViewers as j, setAgentPhase as k, listSessions as l, agentLabel$1 as lt, renameSession as m, workspacePath as mt, clearTmuxStarted as n, ghKnownHosts as nt, getSession as o, DEFAULT_GITHUB_HOST as ot, panePids as p, get as pt, disabledAgents as q, createSession as r, miseVersions as rt, killSession as s, TOOLS as st, cleanEnv as t, doctor as tt, markTmuxStarted as u, toolById as ut, tmuxWasStarted as v, run$1 as vt, agentFamily as w, reportsWorking as x, AGENTS as y, tmux as yt, pushPublicKey as z };
|