@dylanpiercey/work 0.0.44 → 0.0.45
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/dist/{_B6irorCp.js → _BlvusYIA.js} +2 -2
- package/dist/{_Tcoxq_nF.js → _DncwyiYL.js} +17 -17
- package/dist/{_Cja4R2gP.js → _P9IsUQm2.js} +58 -59
- package/dist/_kABYZA6_.js +2 -0
- package/dist/index.mjs +398 -867
- package/dist/public/assets/{_D0en76Ej.js → _0jDMZ5Nf.js} +1 -1
- package/dist/public/assets/_0jDMZ5Nf.js.br +0 -0
- package/dist/public/assets/{_dAPOyRJr.js → _2JIp-AkL.js} +1 -1
- package/dist/public/assets/_2JIp-AkL.js.br +0 -0
- package/dist/public/assets/{_DAVDeGoR.js → _6t6kjpdU.js} +1 -1
- package/dist/public/assets/_6t6kjpdU.js.br +0 -0
- package/dist/public/assets/{_D_EzfDaC.js → _7WXyLEhK.js} +1 -1
- package/dist/public/assets/_7WXyLEhK.js.br +0 -0
- package/dist/public/assets/{_CIVAj2XC.js → _B-HE1A0L.js} +1 -1
- package/dist/public/assets/_B-HE1A0L.js.br +0 -0
- package/dist/public/assets/{_D5BjTqU42.js → _B-tmCiTe2.js} +1 -1
- package/dist/public/assets/_B-tmCiTe2.js.br +0 -0
- package/dist/public/assets/{_CcjW-l5T.js → _B1lH2KuX.js} +1 -1
- package/dist/public/assets/_B1lH2KuX.js.br +0 -0
- package/dist/public/assets/{_DJAJCWgm.js → _B2jdNsMP.js} +5 -5
- package/dist/public/assets/_B2jdNsMP.js.br +0 -0
- package/dist/public/assets/{_Bd7b48iJ.js → _B6bkX_xw.js} +1 -1
- package/dist/public/assets/_B6bkX_xw.js.br +0 -0
- package/dist/public/assets/{_FT8jstIj.js → _B7_IQvxy.js} +1 -1
- package/dist/public/assets/_B7_IQvxy.js.br +0 -0
- package/dist/public/assets/{_ePAxCx7r.js → _BBnPf4LB.js} +1 -1
- package/dist/public/assets/_BBnPf4LB.js.br +0 -0
- package/dist/public/assets/{_BPvgcQ_P.js → _BEn7bsbI.js} +1 -1
- package/dist/public/assets/_BEn7bsbI.js.br +0 -0
- package/dist/public/assets/{_Bnp1UtCp2.js → _BKPFmzRa2.js} +1 -1
- package/dist/public/assets/_BKPFmzRa2.js.br +0 -0
- package/dist/public/assets/{_CJ4aiC36.js → _BKSy9tfl.js} +1 -1
- package/dist/public/assets/_BKSy9tfl.js.br +0 -0
- package/dist/public/assets/{_Z_Oh39Jb.js → _BPhrpOAd.js} +1 -1
- package/dist/public/assets/_BPhrpOAd.js.br +0 -0
- package/dist/public/assets/{_DZtm6WF2.js → _BQKEgF_-.js} +1 -1
- package/dist/public/assets/_BQKEgF_-.js.br +0 -0
- package/dist/public/assets/{_DA_t7MOs2.js → _BVVf3KNx2.js} +1 -1
- package/dist/public/assets/_BVVf3KNx2.js.br +0 -0
- package/dist/public/assets/{_D0ljGGvp2.js → _BdE0YzeT2.js} +1 -1
- package/dist/public/assets/_BdE0YzeT2.js.br +0 -0
- package/dist/public/assets/{_BCTR0wV0.js → _BeS7I1tE.js} +1 -1
- package/dist/public/assets/_BeS7I1tE.js.br +0 -0
- package/dist/public/assets/{_DtMzVsHW2.js → _Bj8eqKyf2.js} +1 -1
- package/dist/public/assets/_Bj8eqKyf2.js.br +0 -0
- package/dist/public/assets/{_DvsUo16D2.js → _BmpuJc0U2.js} +1 -1
- package/dist/public/assets/_BmpuJc0U2.js.br +0 -0
- package/dist/public/assets/{_C2OfA6BZ.js → _BrNJO7NC.js} +1 -1
- package/dist/public/assets/_BrNJO7NC.js.br +0 -0
- package/dist/public/assets/{_BA7PhURg.js → _BsDGIBWi.js} +1 -1
- package/dist/public/assets/_BsDGIBWi.js.br +0 -0
- package/dist/public/assets/{_BBXJK7fW.js → _BszYFXns.js} +1 -1
- package/dist/public/assets/_BszYFXns.js.br +0 -0
- package/dist/public/assets/{_DbJRI9_H.js → _C-3_S2jT.js} +1 -1
- package/dist/public/assets/_C-3_S2jT.js.br +0 -0
- package/dist/public/assets/{_DucRMQLL2.js → _C2a60ukk2.js} +1 -1
- package/dist/public/assets/_C2a60ukk2.js.br +0 -0
- package/dist/public/assets/{_CasdikBZ2.js → _C5qWivO82.js} +1 -1
- package/dist/public/assets/_C5qWivO82.js.br +0 -0
- package/dist/public/assets/{_CL84pok8.js → _C7E2sftJ.js} +1 -1
- package/dist/public/assets/_C7E2sftJ.js.br +0 -0
- package/dist/public/assets/{_Tou5xDB12.js → _C9jJ-zAu2.js} +1 -1
- package/dist/public/assets/_C9jJ-zAu2.js.br +0 -0
- package/dist/public/assets/{_DbnzsP9f.js → _CBWyaxNg.js} +1 -1
- package/dist/public/assets/_CBWyaxNg.js.br +0 -0
- package/dist/public/assets/{_CjrYQPNO.js → _CCxiHsg1.js} +1 -1
- package/dist/public/assets/_CCxiHsg1.js.br +0 -0
- package/dist/public/assets/{_BnN7B1Mb.js → _CMXeuTU3.js} +1 -1
- package/dist/public/assets/_CMXeuTU3.js.br +0 -0
- package/dist/public/assets/{_DoaHBjpa.js → _COItZVVh.js} +1 -1
- package/dist/public/assets/_COItZVVh.js.br +0 -0
- package/dist/public/assets/{_DaTkOx5R.js → _CQjfWgLv.js} +1 -1
- package/dist/public/assets/_CQjfWgLv.js.br +0 -0
- package/dist/public/assets/{_2By3R--W2.js → _CUudFj1k2.js} +1 -1
- package/dist/public/assets/_CUudFj1k2.js.br +0 -0
- package/dist/public/assets/{__UTjMwX3.js → _CVRoyRZW.js} +1 -1
- package/dist/public/assets/_CVRoyRZW.js.br +0 -0
- package/dist/public/assets/{_CQRG1j1X.js → _CVpg0dqw.js} +1 -1
- package/dist/public/assets/_CVpg0dqw.js.br +0 -0
- package/dist/public/assets/{__OpDUxvR.js → _CWcbEhLf.js} +1 -1
- package/dist/public/assets/_CWcbEhLf.js.br +0 -0
- package/dist/public/assets/{_jDukN6_E2.js → _ChdHZg3q2.js} +1 -1
- package/dist/public/assets/_ChdHZg3q2.js.br +0 -0
- package/dist/public/assets/{_e1lYvQAo2.js → _Csumg8kE2.js} +1 -1
- package/dist/public/assets/_Csumg8kE2.js.br +0 -0
- package/dist/public/assets/{_BRP9V2vY.js → _Cu2zWIrA.js} +1 -1
- package/dist/public/assets/_Cu2zWIrA.js.br +0 -0
- package/dist/public/assets/{_C1uG69PI.js → _CvB8TafR.js} +1 -1
- package/dist/public/assets/_CvB8TafR.js.br +0 -0
- package/dist/public/assets/{_ZLwlH_XK.js → _CxfUzQkI.js} +1 -1
- package/dist/public/assets/_CxfUzQkI.js.br +0 -0
- package/dist/public/assets/{_DIezl6EI.js → _D5wyt0NZ.js} +1 -1
- package/dist/public/assets/_D5wyt0NZ.js.br +0 -0
- package/dist/public/assets/{_BqdeosKn.js → _DAES5BQ6.js} +1 -1
- package/dist/public/assets/_DAES5BQ6.js.br +0 -0
- package/dist/public/assets/{_jmw7zbFI2.js → _DAp7RKbE2.js} +1 -1
- package/dist/public/assets/_DAp7RKbE2.js.br +0 -0
- package/dist/public/assets/{_BNDbFEJj.js → _DJIoEU4l.js} +1 -1
- package/dist/public/assets/_DJIoEU4l.js.br +0 -0
- package/dist/public/assets/{_CQ3pD5r12.js → _DQZT5aYv2.js} +1 -1
- package/dist/public/assets/_DQZT5aYv2.js.br +0 -0
- package/dist/public/assets/{_Dkmb-8CU.js → _DSfzkPVh.js} +1 -1
- package/dist/public/assets/_DSfzkPVh.js.br +0 -0
- package/dist/public/assets/{_D861FlLr2.js → _DSl3gnKp2.js} +1 -1
- package/dist/public/assets/{_BBdsdafe2.js → _DUwDVnyb2.js} +1 -1
- package/dist/public/assets/_DUwDVnyb2.js.br +0 -0
- package/dist/public/assets/{_DCD2JMxh2.js → _DYgx29Kq2.js} +1 -1
- package/dist/public/assets/{_DS7FwF-J.js → _DbeeD9R1.js} +1 -1
- package/dist/public/assets/_DbeeD9R1.js.br +0 -0
- package/dist/public/assets/{_CqmPWoAp2.js → _DdvD3pSx2.js} +1 -1
- package/dist/public/assets/_DdvD3pSx2.js.br +0 -0
- package/dist/public/assets/{_D0PcbpPB.js → _DlEZP4B2.js} +1 -1
- package/dist/public/assets/_DlEZP4B2.js.br +0 -0
- package/dist/public/assets/{_C9UHqcOT2.js → _DmkxrcNE2.js} +1 -1
- package/dist/public/assets/_DmkxrcNE2.js.br +0 -0
- package/dist/public/assets/{_DY4GR3La.js → _Dp6GcCez.js} +1 -1
- package/dist/public/assets/_Dp6GcCez.js.br +0 -0
- package/dist/public/assets/{_E5DvansN.js → _Drob8ol2.js} +1 -1
- package/dist/public/assets/_Drob8ol2.js.br +0 -0
- package/dist/public/assets/{_4aAs0pvU.js → _Fd6qP3go.js} +1 -1
- package/dist/public/assets/_Fd6qP3go.js.br +0 -0
- package/dist/public/assets/{_U0PVI62V.js → _GX4ApnkB.js} +1 -1
- package/dist/public/assets/_GX4ApnkB.js.br +0 -0
- package/dist/public/assets/{_BAQFHOGb.js → _HmwD_O7C.js} +1 -1
- package/dist/public/assets/_HmwD_O7C.js.br +0 -0
- package/dist/public/assets/{_BdiO50aC2.js → _IiVyZhFQ2.js} +1 -1
- package/dist/public/assets/_IiVyZhFQ2.js.br +0 -0
- package/dist/public/assets/{_BaIOx6992.js → _M4_M1GCx2.js} +1 -1
- package/dist/public/assets/_M4_M1GCx2.js.br +0 -0
- package/dist/public/assets/{_D2sFNldb.js → _MbiYJ36s.js} +1 -1
- package/dist/public/assets/_MbiYJ36s.js.br +0 -0
- package/dist/public/assets/{_BBEMecyM2.js → _NSw61-q82.js} +1 -1
- package/dist/public/assets/_NSw61-q82.js.br +0 -0
- package/dist/public/assets/{_BRV26aAF.js → _QBVNsQ8h.js} +1 -1
- package/dist/public/assets/_QBVNsQ8h.js.br +0 -0
- package/dist/public/assets/{_Dyejz2MQ.js → _RcdEaPTX.js} +1 -1
- package/dist/public/assets/_RcdEaPTX.js.br +0 -0
- package/dist/public/assets/{_BPzHoTu3.js → _Ty6Zi_p6.js} +1 -1
- package/dist/public/assets/_Ty6Zi_p6.js.br +0 -0
- package/dist/public/assets/{_BculF-XV.js → _WSiIjl8k.js} +1 -1
- package/dist/public/assets/{_DbbVTGR82.js → _c4j42n9F2.js} +1 -1
- package/dist/public/assets/_c4j42n9F2.js.br +0 -0
- package/dist/public/assets/{_CAP_5S-t.js → _cRSAYsIy.js} +1 -1
- package/dist/public/assets/_cRSAYsIy.js.br +0 -0
- package/dist/public/assets/{_BkeFq1dG2.js → _gqKnRhHm2.js} +1 -1
- package/dist/public/assets/_gqKnRhHm2.js.br +0 -0
- package/dist/public/assets/{_Bt3B1aEu2.js → _i3m2va9y2.js} +1 -1
- package/dist/public/assets/_i3m2va9y2.js.br +0 -0
- package/dist/public/assets/{_CMmwGR_Q.js → _rShrll8V.js} +1 -1
- package/dist/public/assets/_rShrll8V.js.br +0 -0
- package/dist/public/assets/{_BYRkkQxk.js → _wsALS6ya.js} +1 -1
- package/dist/public/assets/_wsALS6ya.js.br +0 -0
- package/dist/public/assets/{_B7T2AE8L.js → _wx4NAfvC.js} +1 -1
- package/dist/public/assets/_wx4NAfvC.js.br +0 -0
- package/dist/public/assets/{diff-view-sXFdzozK.css → diff-view-l7q43Ong.css} +1 -1
- package/dist/public/assets/diff-view-l7q43Ong.css.br +0 -0
- package/dist/public/assets/{index-DKRkgwLo.js → index-BXWsr0DP.js} +4 -4
- package/dist/public/assets/index-BXWsr0DP.js.br +0 -0
- package/dist/public/assets/index-Du7Hgz2d.css +1 -0
- package/dist/public/assets/index-Du7Hgz2d.css.br +0 -0
- package/dist/public/assets/{preload-helper-Cioq5Qre.css → preload-helper-Di0vWBYv.css} +1 -1
- package/dist/public/assets/preload-helper-Di0vWBYv.css.br +0 -0
- package/package.json +1 -1
- package/scripts/migrate.mjs +93 -0
- package/dist/_L15vvgS1.js +0 -2
- package/dist/public/assets/_2By3R--W2.js.br +0 -0
- package/dist/public/assets/_4aAs0pvU.js.br +0 -0
- package/dist/public/assets/_B7T2AE8L.js.br +0 -0
- package/dist/public/assets/_BA7PhURg.js.br +0 -0
- package/dist/public/assets/_BAQFHOGb.js.br +0 -0
- package/dist/public/assets/_BBEMecyM2.js.br +0 -0
- package/dist/public/assets/_BBXJK7fW.js.br +0 -0
- package/dist/public/assets/_BBdsdafe2.js.br +0 -0
- package/dist/public/assets/_BCTR0wV0.js.br +0 -0
- package/dist/public/assets/_BNDbFEJj.js.br +0 -0
- package/dist/public/assets/_BPvgcQ_P.js.br +0 -0
- package/dist/public/assets/_BPzHoTu3.js.br +0 -0
- package/dist/public/assets/_BRP9V2vY.js.br +0 -0
- package/dist/public/assets/_BRV26aAF.js.br +0 -0
- package/dist/public/assets/_BYRkkQxk.js.br +0 -0
- package/dist/public/assets/_BaIOx6992.js.br +0 -0
- package/dist/public/assets/_Bd7b48iJ.js.br +0 -0
- package/dist/public/assets/_BdiO50aC2.js.br +0 -0
- package/dist/public/assets/_BkeFq1dG2.js.br +0 -0
- package/dist/public/assets/_BnN7B1Mb.js.br +0 -0
- package/dist/public/assets/_Bnp1UtCp2.js.br +0 -0
- package/dist/public/assets/_BqdeosKn.js.br +0 -0
- package/dist/public/assets/_Bt3B1aEu2.js.br +0 -0
- package/dist/public/assets/_C1uG69PI.js.br +0 -0
- package/dist/public/assets/_C2OfA6BZ.js.br +0 -0
- package/dist/public/assets/_C9UHqcOT2.js.br +0 -0
- package/dist/public/assets/_CAP_5S-t.js.br +0 -0
- package/dist/public/assets/_CIVAj2XC.js.br +0 -0
- package/dist/public/assets/_CJ4aiC36.js.br +0 -0
- package/dist/public/assets/_CL84pok8.js.br +0 -0
- package/dist/public/assets/_CMmwGR_Q.js.br +0 -0
- package/dist/public/assets/_CQ3pD5r12.js.br +0 -0
- package/dist/public/assets/_CQRG1j1X.js.br +0 -0
- package/dist/public/assets/_CasdikBZ2.js.br +0 -0
- package/dist/public/assets/_CcjW-l5T.js.br +0 -0
- package/dist/public/assets/_CjrYQPNO.js.br +0 -0
- package/dist/public/assets/_CqmPWoAp2.js.br +0 -0
- package/dist/public/assets/_D0PcbpPB.js.br +0 -0
- package/dist/public/assets/_D0en76Ej.js.br +0 -0
- package/dist/public/assets/_D0ljGGvp2.js.br +0 -0
- package/dist/public/assets/_D2sFNldb.js.br +0 -0
- package/dist/public/assets/_D5BjTqU42.js.br +0 -0
- package/dist/public/assets/_DAVDeGoR.js.br +0 -0
- package/dist/public/assets/_DA_t7MOs2.js.br +0 -0
- package/dist/public/assets/_DIezl6EI.js.br +0 -0
- package/dist/public/assets/_DJAJCWgm.js.br +0 -0
- package/dist/public/assets/_DS7FwF-J.js.br +0 -0
- package/dist/public/assets/_DY4GR3La.js.br +0 -0
- package/dist/public/assets/_DZtm6WF2.js.br +0 -0
- package/dist/public/assets/_D_EzfDaC.js.br +0 -0
- package/dist/public/assets/_DaTkOx5R.js.br +0 -0
- package/dist/public/assets/_DbJRI9_H.js.br +0 -0
- package/dist/public/assets/_DbbVTGR82.js.br +0 -0
- package/dist/public/assets/_DbnzsP9f.js.br +0 -0
- package/dist/public/assets/_Dkmb-8CU.js.br +0 -0
- package/dist/public/assets/_DoaHBjpa.js.br +0 -0
- package/dist/public/assets/_DtMzVsHW2.js.br +0 -0
- package/dist/public/assets/_DucRMQLL2.js.br +0 -0
- package/dist/public/assets/_DvsUo16D2.js.br +0 -0
- package/dist/public/assets/_Dyejz2MQ.js.br +0 -0
- package/dist/public/assets/_E5DvansN.js.br +0 -0
- package/dist/public/assets/_FT8jstIj.js.br +0 -0
- package/dist/public/assets/_Tou5xDB12.js.br +0 -0
- package/dist/public/assets/_U0PVI62V.js.br +0 -0
- package/dist/public/assets/_ZLwlH_XK.js.br +0 -0
- package/dist/public/assets/_Z_Oh39Jb.js.br +0 -0
- package/dist/public/assets/__OpDUxvR.js.br +0 -0
- package/dist/public/assets/__UTjMwX3.js.br +0 -0
- package/dist/public/assets/_dAPOyRJr.js.br +0 -0
- package/dist/public/assets/_e1lYvQAo2.js.br +0 -0
- package/dist/public/assets/_ePAxCx7r.js.br +0 -0
- package/dist/public/assets/_jDukN6_E2.js.br +0 -0
- package/dist/public/assets/_jmw7zbFI2.js.br +0 -0
- package/dist/public/assets/diff-view-sXFdzozK.css.br +0 -0
- package/dist/public/assets/index-DKRkgwLo.js.br +0 -0
- package/dist/public/assets/index-c70b3ZMB.css +0 -1
- package/dist/public/assets/index-c70b3ZMB.css.br +0 -0
- package/dist/public/assets/preload-helper-Cioq5Qre.css.br +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./_BMI-E3GI.js";
|
|
2
|
-
import { A as
|
|
3
|
-
import { $ as _subscribe, A as _el_resume, B as _peek_scope_id, C as _attr_style, D as _dynamic_tag, E as _content_resume, F as _hoist, G as _scope_with_id, H as _resume_branch, I as _hoist_read_error, J as _serialize_guard, K as _script, L as _html, M as _existing_scope, N as _flush_head, P as _for_of, Q as _show_start, R as _id, S as _attr_select_value, T as _content, U as _scope_id, V as _resume, W as _scope_reason, X as _set_serialize_reason, Y as _serialize_if, Z as _show_end, _ as _attr, at as attrTag, b as _attr_input_value, c as sideNavOpen, d as icon_base_default, et as _template, f as fuzzy, g as $global, h as phase, i as icon_sidebar_default, it as _var, j as _escape, k as _el_read_error, l as workspaceTab, m as toast_default, n as findIconBtn, nt as _trailers, ot as withPageAssets, p as rankRepos, q as _sep, r as findInput, rt as _try, s as setWorkspaceTab, st as writeScope, tt as _to_text, u as icon_refresh_default, v as _attr_class, w as _await, x as _attr_option_value, z as _if } from "./
|
|
2
|
+
import { A as TMUX_SOCKET, B as db, C as pushPublicKey, D as preferredAgent, E as allPrefs, F as publish, H as workspacePath, I as subscribe, L as subscriberCount, M as git, N as run, O as setPref, P as tmux, R as subscriberJoins, S as deleteSubscription, T as AGENTS, U as config, V as get, _ as reasonFromHookPayload, a as killSession, b as setSessionViewers, c as newSessionArgs, d as renameSession, f as sendToSession, g as clearAgentPhase, h as reportsWorking, i as getSession, j as gh, k as setSetting, m as tmuxName, n as createSession, o as killWorkspaceSessions, p as sessionStates, r as ensureTmuxServer, s as listSessions, t as cleanEnv, u as panePids, v as setAgentPhase, w as saveSubscription, x as summaryFromHookPayload, y as setScrapedPhase, z as all } from "./_P9IsUQm2.js";
|
|
3
|
+
import { $ as _subscribe, A as _el_resume, B as _peek_scope_id, C as _attr_style, D as _dynamic_tag, E as _content_resume, F as _hoist, G as _scope_with_id, H as _resume_branch, I as _hoist_read_error, J as _serialize_guard, K as _script, L as _html, M as _existing_scope, N as _flush_head, P as _for_of, Q as _show_start, R as _id, S as _attr_select_value, T as _content, U as _scope_id, V as _resume, W as _scope_reason, X as _set_serialize_reason, Y as _serialize_if, Z as _show_end, _ as _attr, at as attrTag, b as _attr_input_value, c as sideNavOpen, d as icon_base_default, et as _template, f as fuzzy, g as $global, h as phase, i as icon_sidebar_default, it as _var, j as _escape, k as _el_read_error, l as workspaceTab, m as toast_default, n as findIconBtn, nt as _trailers, ot as withPageAssets, p as rankRepos, q as _sep, r as findInput, rt as _try, s as setWorkspaceTab, st as writeScope, tt as _to_text, u as icon_refresh_default, v as _attr_class, w as _await, x as _attr_option_value, z as _if } from "./_BlvusYIA.js";
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import { createServer } from "node:http";
|
|
6
6
|
import path from "node:path";
|
|
@@ -1958,6 +1958,46 @@ async function workspaceBranches(bare, branch, exclude) {
|
|
|
1958
1958
|
"refs/heads/"
|
|
1959
1959
|
], bare).catch(() => "")).split("\n").filter((b) => ownsBranch(b, branch) && !exclude.some((x) => ownsBranch(b, x)));
|
|
1960
1960
|
}
|
|
1961
|
+
/** Delete a finished lane's local branch from the shared bare cache.
|
|
1962
|
+
*
|
|
1963
|
+
* Only a `-topic` lane, never the workspace branch itself: that one is
|
|
1964
|
+
* reused for the next change, so it outlives every PR opened from it.
|
|
1965
|
+
*
|
|
1966
|
+
* `headOid` is the finished PR's own head commit, and the local tip has to
|
|
1967
|
+
* still be sitting on it. That is what separates "this branch is the PR you
|
|
1968
|
+
* just finished with" from "this branch has commits you never pushed" — the
|
|
1969
|
+
* former stays reachable through the PR on GitHub (`refs/pull/N/head`
|
|
1970
|
+
* outlives both the merge and the branch, so a closed-unmerged lane is as
|
|
1971
|
+
* recoverable as a merged one), the latter would be gone for good. The
|
|
1972
|
+
* remote ref is not the test: GitHub prunes it on merge exactly when
|
|
1973
|
+
* pruning is safest.
|
|
1974
|
+
*
|
|
1975
|
+
* `-D` rather than `-d` because a squash-merged lane is not an ancestor of
|
|
1976
|
+
* its base, so git cannot see the merge that GitHub reports. It is also
|
|
1977
|
+
* what refuses when the lane is still checked out in a worktree — that
|
|
1978
|
+
* returns false rather than raising, a lane you are standing on being a
|
|
1979
|
+
* reason to keep it, not an error. */
|
|
1980
|
+
async function pruneLaneBranch(workspaceId, fullName, lane, headOid) {
|
|
1981
|
+
const ws = getWorkspace(workspaceId);
|
|
1982
|
+
if (!ws || !headOid || lane === ws.branch) return false;
|
|
1983
|
+
if (!ownsBranch(lane, ws.branch)) return false;
|
|
1984
|
+
if (otherWorkspaceBranches(workspaceId).some((b) => ownsBranch(lane, b))) return false;
|
|
1985
|
+
if (!ws.repos.some((r) => r.full_name === fullName)) return false;
|
|
1986
|
+
return withRepoLock(fullName, async () => {
|
|
1987
|
+
const bare = barePath(fullName);
|
|
1988
|
+
const local = await git([
|
|
1989
|
+
"rev-parse",
|
|
1990
|
+
"--verify",
|
|
1991
|
+
`refs/heads/${lane}`
|
|
1992
|
+
], bare).catch(() => "");
|
|
1993
|
+
if (!local || local !== headOid) return false;
|
|
1994
|
+
return git([
|
|
1995
|
+
"branch",
|
|
1996
|
+
"-D",
|
|
1997
|
+
lane
|
|
1998
|
+
], bare).then(() => true, () => false);
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
1961
2001
|
/** Directory/branch-safe prefix for a workspace name. Decomposing first keeps
|
|
1962
2002
|
* accented Latin readable (é → e); a name with nothing ASCII left (another
|
|
1963
2003
|
* script, emoji) falls back to a generic prefix — the random id is what makes
|
|
@@ -2118,10 +2158,7 @@ function swr(ttlMs, load, seed) {
|
|
|
2118
2158
|
}
|
|
2119
2159
|
//#endregion
|
|
2120
2160
|
//#region src/server/prs.ts
|
|
2121
|
-
var PR_JSON = "number,title,url,headRefName,baseRefName,headRefOid,isDraft,state";
|
|
2122
2161
|
var TTL_MS$3 = 12e4;
|
|
2123
|
-
/** PRs in every state for a repo, stale-while-revalidate cached. */
|
|
2124
|
-
var prs = swr(TTL_MS$3, fetchPrs);
|
|
2125
2162
|
/** PRs whose head is the workspace branch or one of its `-topic` lanes.
|
|
2126
2163
|
* `exclude` lists other workspaces' branches — slugs are user-chosen, so
|
|
2127
2164
|
* another workspace's branch can extend this prefix and its PRs must not
|
|
@@ -2130,51 +2167,21 @@ function prsForBranchPrefix(prs, prefix, exclude = []) {
|
|
|
2130
2167
|
const owns = (ref, b) => ref === b || ref.startsWith(`${b}-`);
|
|
2131
2168
|
return prs.filter((pr) => owns(pr.headRefName, prefix) && !exclude.some((x) => owns(pr.headRefName, x)));
|
|
2132
2169
|
}
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
*
|
|
2136
|
-
*
|
|
2137
|
-
*
|
|
2138
|
-
|
|
2170
|
+
var branchKey = (fullName, branch) => `${fullName}#${branch}`;
|
|
2171
|
+
/** One workspace's PRs in one repo — its branch and every `-topic` lane, in
|
|
2172
|
+
* every state. Asking for the workspace's own branches is what keeps this
|
|
2173
|
+
* proportional to the workspace rather than to the repo: the alternative,
|
|
2174
|
+
* a recency window over all of a repo's PRs, fetched roughly twice what it
|
|
2175
|
+
* kept here and still aged a quiet workspace out on a busy repo.
|
|
2176
|
+
* Key: `fullName#branch`. */
|
|
2177
|
+
var branchPrs = swr(TTL_MS$3, (key, refresh) => {
|
|
2139
2178
|
const sep = key.indexOf("#");
|
|
2140
|
-
|
|
2141
|
-
const branch = key.slice(sep + 1);
|
|
2142
|
-
return repoPrs(fullName, 20, [
|
|
2143
|
-
"pr",
|
|
2144
|
-
"list",
|
|
2145
|
-
"--repo",
|
|
2146
|
-
fullName,
|
|
2147
|
-
"--head",
|
|
2148
|
-
branch,
|
|
2149
|
-
"--state",
|
|
2150
|
-
"all",
|
|
2151
|
-
"--limit",
|
|
2152
|
-
"20",
|
|
2153
|
-
"--json",
|
|
2154
|
-
PR_JSON
|
|
2155
|
-
], branch);
|
|
2179
|
+
return searchPrs([key.slice(0, sep)], [key.slice(sep + 1)], refresh);
|
|
2156
2180
|
});
|
|
2157
|
-
/** A workspace repo's PRs
|
|
2158
|
-
*
|
|
2181
|
+
/** A workspace repo's PRs, minus any belonging to a workspace whose branch
|
|
2182
|
+
* extends this one's. */
|
|
2159
2183
|
async function workspacePrs(fullName, branch, foreign, refresh = false) {
|
|
2160
|
-
|
|
2161
|
-
const list = prsForBranchPrefix(windowed, branch, foreign);
|
|
2162
|
-
for (const pr of prsForBranchPrefix(exact, branch, foreign)) if (!list.some((p) => p.number === pr.number)) list.push(pr);
|
|
2163
|
-
return list;
|
|
2164
|
-
}
|
|
2165
|
-
async function fetchPrs(fullName) {
|
|
2166
|
-
return repoPrs(fullName, 100, [
|
|
2167
|
-
"pr",
|
|
2168
|
-
"list",
|
|
2169
|
-
"--repo",
|
|
2170
|
-
fullName,
|
|
2171
|
-
"--state",
|
|
2172
|
-
"all",
|
|
2173
|
-
"--limit",
|
|
2174
|
-
"100",
|
|
2175
|
-
"--json",
|
|
2176
|
-
PR_JSON
|
|
2177
|
-
]);
|
|
2184
|
+
return prsForBranchPrefix(await branchPrs(branchKey(fullName, branch), refresh).catch(() => []), branch, foreign);
|
|
2178
2185
|
}
|
|
2179
2186
|
/** Refresh many repos' PRs with one GraphQL request (vs one `gh pr list`
|
|
2180
2187
|
* process per repo) — called from the status watcher for active
|
|
@@ -2194,59 +2201,61 @@ function notePushActivity() {
|
|
|
2194
2201
|
function inHotWindow() {
|
|
2195
2202
|
return Date.now() < hotUntil;
|
|
2196
2203
|
}
|
|
2197
|
-
/** `headRefOid` is the PR's own head commit, which is what
|
|
2198
|
-
*
|
|
2199
|
-
*
|
|
2200
|
-
*
|
|
2201
|
-
*
|
|
2204
|
+
/** `headRefOid` is the PR's own head commit, which is what the UI compares
|
|
2205
|
+
* against. Reaching through `headRef` gets the branch's *current* tip
|
|
2206
|
+
* instead — a different commit entirely once a workspace branch is reused,
|
|
2207
|
+
* and `headRef { oid }` is not even a field, so GitHub answers 200 with an
|
|
2208
|
+
* `errors` array and no `data`. */
|
|
2202
2209
|
var GQL_PR_FIELDS = "number title url headRefName baseRefName isDraft state headRefOid";
|
|
2203
|
-
/**
|
|
2204
|
-
*
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
}
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2210
|
+
/** Search's `head:` matches a branch *and* its `-topic` lanes, so one term
|
|
2211
|
+
* covers a whole workspace, and repeated terms are OR'd within a qualifier
|
|
2212
|
+
* while different qualifiers are AND'd — `repo:a repo:b head:x head:y`
|
|
2213
|
+
* reads as (a|b) and (x|y). That is what lets every workspace share one
|
|
2214
|
+
* request instead of needing an alias per repo and per branch. */
|
|
2215
|
+
function searchTerms(repos, branches) {
|
|
2216
|
+
return [...repos.map((r) => `repo:${r}`), ...branches.map((b) => `head:${b}`)].join(" ");
|
|
2217
|
+
}
|
|
2218
|
+
/** Finished PRs are asked for by recency, open ones are not: a merged PR
|
|
2219
|
+
* only has to outlive its dismissal, while an open PR must stay visible
|
|
2220
|
+
* however long it has sat idle — which is exactly what a recency window
|
|
2221
|
+
* over the whole repo got wrong. */
|
|
2222
|
+
var CLOSED_FIRST = 60;
|
|
2223
|
+
var OPEN_FIRST = 100;
|
|
2224
|
+
/** Search pages at 100. Open PRs are the page that can genuinely overflow
|
|
2225
|
+
* (every workspace's, in one request), so it is followed — bounded, because
|
|
2226
|
+
* an unbounded follow is a way to hang the status tick on a bad query. */
|
|
2227
|
+
var MAX_OPEN_PAGES = 4;
|
|
2228
|
+
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 } } } }`;
|
|
2229
|
+
/** Every PR on the given branches (and their lanes) across the given repos.
|
|
2230
|
+
* `refresh` is accepted for the swr signature; freshness here is GitHub's,
|
|
2231
|
+
* not ours. */
|
|
2232
|
+
async function searchPrs(repos, branches, _refresh) {
|
|
2233
|
+
const terms = searchTerms(repos, branches);
|
|
2234
|
+
const out = [];
|
|
2235
|
+
let cursor;
|
|
2236
|
+
for (let page = 0; page < MAX_OPEN_PAGES; page++) {
|
|
2237
|
+
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) : "") + "}");
|
|
2238
|
+
const open = data.open;
|
|
2239
|
+
const done = data.done;
|
|
2240
|
+
for (const node of [...open?.nodes ?? [], ...done?.nodes ?? []]) if (node?.number) out.push(node);
|
|
2241
|
+
if (!open?.pageInfo.hasNextPage || !open.pageInfo.endCursor) break;
|
|
2242
|
+
cursor = open.pageInfo.endCursor;
|
|
2218
2243
|
}
|
|
2244
|
+
return out;
|
|
2219
2245
|
}
|
|
2220
|
-
async function refreshPrsBatch(
|
|
2221
|
-
const
|
|
2246
|
+
async function refreshPrsBatch(targets, force = false) {
|
|
2247
|
+
const wanted = [...new Map(targets.filter((t) => t.fullName.includes("/") && t.branch).map((t) => [branchKey(t.fullName, t.branch), t])).values()];
|
|
2222
2248
|
const minMs = force ? 2e3 : Date.now() < hotUntil ? HOT_MIN_MS : BATCH_MIN_MS;
|
|
2223
|
-
if (!
|
|
2249
|
+
if (!wanted.length || Date.now() - lastBatch < minMs) return false;
|
|
2224
2250
|
const prevBatch = lastBatch;
|
|
2225
2251
|
lastBatch = Date.now();
|
|
2226
2252
|
try {
|
|
2227
|
-
const
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
"api",
|
|
2234
|
-
"graphql",
|
|
2235
|
-
"-f",
|
|
2236
|
-
`query=${query}`
|
|
2237
|
-
]).catch((e) => {
|
|
2238
|
-
if (!e.stdout) throw err;
|
|
2239
|
-
return e.stdout;
|
|
2240
|
-
});
|
|
2241
|
-
const parsed = JSON.parse(out).data;
|
|
2242
|
-
if (!parsed) throw err;
|
|
2243
|
-
return parsed;
|
|
2244
|
-
});
|
|
2245
|
-
names.forEach((fullName, i) => {
|
|
2246
|
-
const repo = data[`r${i}`];
|
|
2247
|
-
if (!repo) return;
|
|
2248
|
-
prs.set(fullName, repo.pullRequests.nodes);
|
|
2249
|
-
});
|
|
2253
|
+
const nodes = await searchPrs([...new Set(wanted.map((t) => t.fullName))], [...new Set(wanted.map((t) => t.branch))]);
|
|
2254
|
+
const branches = [...new Set(wanted.map((t) => t.branch))];
|
|
2255
|
+
for (const target of wanted) {
|
|
2256
|
+
const foreign = branches.filter((b) => b !== target.branch);
|
|
2257
|
+
branchPrs.set(branchKey(target.fullName, target.branch), prsForBranchPrefix(nodes.filter((n) => n.repository.nameWithOwner === target.fullName), target.branch, foreign));
|
|
2258
|
+
}
|
|
2250
2259
|
return true;
|
|
2251
2260
|
} catch (err) {
|
|
2252
2261
|
lastBatch = prevBatch;
|
|
@@ -2263,6 +2272,62 @@ function withoutDismissed(workspaceId, fullName, list) {
|
|
|
2263
2272
|
return list.filter((pr) => pr.state === "OPEN" || !dismissed.has(pr.number));
|
|
2264
2273
|
}
|
|
2265
2274
|
//#endregion
|
|
2275
|
+
//#region src/server/git-refs.ts
|
|
2276
|
+
/** The checked-out commit of a worktree, read off disk instead of spawned.
|
|
2277
|
+
*
|
|
2278
|
+
* Every status tick needs this for every repo of every active workspace —
|
|
2279
|
+
* it is what tells an open review that an agent committed, since a local
|
|
2280
|
+
* commit reaches GitHub through nothing the app can be told about. As a
|
|
2281
|
+
* process per repo per tick that was the bulk of the git the server ran;
|
|
2282
|
+
* the same answer is three small file reads.
|
|
2283
|
+
*
|
|
2284
|
+
* `git` stays the authority for anything this cannot read confidently: a
|
|
2285
|
+
* ref backend it does not understand, a chain that does not end in an oid,
|
|
2286
|
+
* a layout it has never seen. Being slower is better than being wrong,
|
|
2287
|
+
* because the drift banner reads a stale oid as "your checkout differs
|
|
2288
|
+
* from the review". */
|
|
2289
|
+
async function headOid(dir) {
|
|
2290
|
+
return await readHead(dir).catch(() => "") || spawnHead(dir);
|
|
2291
|
+
}
|
|
2292
|
+
var spawnHead = (dir) => git(["rev-parse", "HEAD"], dir).catch(() => "");
|
|
2293
|
+
/** Both hash algorithms, since a repo may be SHA-256. */
|
|
2294
|
+
var OID = /^[0-9a-f]{40}(?:[0-9a-f]{24})?$/;
|
|
2295
|
+
/** A symref chain that runs this long is a loop, not a layout. */
|
|
2296
|
+
var MAX_HOPS = 5;
|
|
2297
|
+
async function readHead(dir) {
|
|
2298
|
+
const { gitDir, common } = await gitDirs(dir);
|
|
2299
|
+
if (await exists(path.join(common, "reftable"))) return "";
|
|
2300
|
+
let ref = (await fsp.readFile(path.join(gitDir, "HEAD"), "utf8")).trim();
|
|
2301
|
+
for (let hop = 0; ref.startsWith("ref: ") && hop < MAX_HOPS; hop++) {
|
|
2302
|
+
const name = ref.slice(5).trim();
|
|
2303
|
+
const loose = await read(path.join(gitDir, name)) ?? await read(path.join(common, name));
|
|
2304
|
+
if (loose !== void 0) {
|
|
2305
|
+
ref = loose.trim();
|
|
2306
|
+
continue;
|
|
2307
|
+
}
|
|
2308
|
+
const packed = await read(path.join(common, "packed-refs"));
|
|
2309
|
+
if (packed === void 0) return "";
|
|
2310
|
+
const line = packed.split("\n").find((l) => !l.startsWith("^") && l.endsWith(` ${name}`));
|
|
2311
|
+
if (!line) return "";
|
|
2312
|
+
ref = line.slice(0, line.indexOf(" "));
|
|
2313
|
+
}
|
|
2314
|
+
return OID.test(ref) ? ref : "";
|
|
2315
|
+
}
|
|
2316
|
+
/** A worktree's `.git` is a file pointing at its admin directory inside the
|
|
2317
|
+
* shared bare cache, which in turn points back at the common ref store. */
|
|
2318
|
+
async function gitDirs(dir) {
|
|
2319
|
+
const dotGit = path.join(dir, ".git");
|
|
2320
|
+
const gitDir = await isDir(dotGit) ? dotGit : path.resolve(dir, (await fsp.readFile(dotGit, "utf8")).replace(/^gitdir:/, "").trim());
|
|
2321
|
+
const commonRef = await read(path.join(gitDir, "commondir"));
|
|
2322
|
+
return {
|
|
2323
|
+
gitDir,
|
|
2324
|
+
common: commonRef ? path.resolve(gitDir, commonRef.trim()) : gitDir
|
|
2325
|
+
};
|
|
2326
|
+
}
|
|
2327
|
+
var read = (file) => fsp.readFile(file, "utf8").catch(() => void 0);
|
|
2328
|
+
var exists = (file) => fsp.stat(file).then(() => true, () => false);
|
|
2329
|
+
var isDir = (file) => fsp.stat(file).then((s) => s.isDirectory(), () => false);
|
|
2330
|
+
//#endregion
|
|
2266
2331
|
//#region src/server/status.ts
|
|
2267
2332
|
var TTL_MS$2 = 2e3;
|
|
2268
2333
|
var snapshot = null;
|
|
@@ -2302,17 +2367,30 @@ var WATCH_MS = 1e4;
|
|
|
2302
2367
|
* fast so the badge lands while it still feels immediate. */
|
|
2303
2368
|
var WATCH_HOT_MS = 4e3;
|
|
2304
2369
|
var watching = false;
|
|
2305
|
-
|
|
2370
|
+
/** Last published state per workspace, so a tick can publish the ones that
|
|
2371
|
+
* actually moved. Comparing the whole snapshot instead meant one agent's
|
|
2372
|
+
* commit — or any session, port or PR flip in a workspace nobody is
|
|
2373
|
+
* looking at — pushed every workspace to every client, which each then
|
|
2374
|
+
* re-rendered and re-fingerprinted to conclude nothing of theirs had
|
|
2375
|
+
* changed. That amplification grows with the number of workspaces. */
|
|
2376
|
+
var lastPushed = /* @__PURE__ */ new Map();
|
|
2377
|
+
var lastJoins = -1;
|
|
2306
2378
|
async function watchTick() {
|
|
2307
2379
|
if (!subscriberCount()) return;
|
|
2308
2380
|
try {
|
|
2309
|
-
if (await refreshPrsBatch(
|
|
2381
|
+
if (await refreshPrsBatch(activeRepoTargets()).catch(() => false)) invalidateSnapshot();
|
|
2310
2382
|
const value = await statusForAll();
|
|
2311
|
-
const
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2383
|
+
const joins = subscriberJoins();
|
|
2384
|
+
const everything = joins !== lastJoins;
|
|
2385
|
+
lastJoins = joins;
|
|
2386
|
+
const changed = {};
|
|
2387
|
+
for (const [id, ws] of Object.entries(value)) {
|
|
2388
|
+
const json = JSON.stringify(ws);
|
|
2389
|
+
if (everything || lastPushed.get(id) !== json) changed[id] = ws;
|
|
2390
|
+
lastPushed.set(id, json);
|
|
2391
|
+
}
|
|
2392
|
+
for (const id of lastPushed.keys()) if (!(id in value)) lastPushed.delete(id);
|
|
2393
|
+
if (Object.keys(changed).length) publish("status.changed", changed);
|
|
2316
2394
|
} catch {}
|
|
2317
2395
|
}
|
|
2318
2396
|
var watchTimer;
|
|
@@ -2340,14 +2418,20 @@ function startStatusWatch() {
|
|
|
2340
2418
|
watching = true;
|
|
2341
2419
|
scheduleTick(WATCH_MS);
|
|
2342
2420
|
}
|
|
2343
|
-
|
|
2344
|
-
|
|
2421
|
+
/** Every active workspace's repos, paired with the branch that workspace
|
|
2422
|
+
* works on — the batch refreshes both the recency window and the exact-head
|
|
2423
|
+
* lookup for each, in one request. */
|
|
2424
|
+
function activeRepoTargets() {
|
|
2425
|
+
return listWorkspaces().filter((ws) => ws.status === "active").flatMap((ws) => ws.repos.map((r) => ({
|
|
2426
|
+
fullName: r.full_name,
|
|
2427
|
+
branch: ws.branch
|
|
2428
|
+
})));
|
|
2345
2429
|
}
|
|
2346
2430
|
/** Status with PRs refetched first (throttled): a client returning to the
|
|
2347
2431
|
* foreground wants current PR state — merges/closes happen on GitHub and
|
|
2348
2432
|
* send no local signal, so without this they wait out the slow poll. */
|
|
2349
2433
|
async function statusForAllFresh() {
|
|
2350
|
-
if (await refreshPrsBatch(
|
|
2434
|
+
if (await refreshPrsBatch(activeRepoTargets(), true).catch(() => false)) invalidateSnapshot();
|
|
2351
2435
|
return statusForAll();
|
|
2352
2436
|
}
|
|
2353
2437
|
/** RSS here is the Node + Marko baseline (~80 MB empty, ~115 MB loaded),
|
|
@@ -2373,7 +2457,7 @@ async function computeStatus() {
|
|
|
2373
2457
|
}
|
|
2374
2458
|
async function repoStatus(ws, repo, foreign) {
|
|
2375
2459
|
const dir = path.join(ws.path, repo.worktree);
|
|
2376
|
-
const [repoPrs, localHead] = await Promise.all([workspacePrs(repo.full_name, ws.branch, foreign).then((list) => withoutDismissed(ws.id, repo.full_name, list)),
|
|
2460
|
+
const [repoPrs, localHead] = await Promise.all([workspacePrs(repo.full_name, ws.branch, foreign).then((list) => withoutDismissed(ws.id, repo.full_name, list)), headOid(dir)]);
|
|
2377
2461
|
return {
|
|
2378
2462
|
full_name: repo.full_name,
|
|
2379
2463
|
worktree: repo.worktree,
|
|
@@ -2679,17 +2763,17 @@ var palette_default = _template("o", (input) => {
|
|
|
2679
2763
|
_if(() => {
|
|
2680
2764
|
if (!input.inline) {
|
|
2681
2765
|
const $scope5_id = _scope_id();
|
|
2682
|
-
_html(`<div${_attr_class("
|
|
2766
|
+
_html(`<div${_attr_class("_bo")}></div>${_el_resume($scope5_id, "a")}`);
|
|
2683
2767
|
_script($scope5_id, "o4");
|
|
2684
2768
|
writeScope($scope5_id, {});
|
|
2685
2769
|
return 0;
|
|
2686
2770
|
}
|
|
2687
2771
|
}, $scope0_id, "a", $sg__input_inline, $sg__input_inline, 1, 0, 1);
|
|
2688
|
-
_html(`<div${_attr_class(["
|
|
2772
|
+
_html(`<div${_attr_class(["_bq", { ["_bp"]: input.inline }])} data-palette${input.inline ? " data-inline" : ""} role=dialog aria-label=Workspaces>`);
|
|
2689
2773
|
_if(() => {
|
|
2690
2774
|
if (input.inline && !input.workspaces.length) {
|
|
2691
2775
|
const $scope8_id = _scope_id();
|
|
2692
|
-
_html(`<div${_attr_class("
|
|
2776
|
+
_html(`<div${_attr_class("_by")}><p${_attr_class("_bK")}>A <strong>workspace</strong> checks out one or more repos as git worktrees on a shared branch and gives each agent session its own terminal. Create one to get started.</p><p${_attr_class("_bK")}>Pick your preferred agent below — new sessions and the quick-create button use it. GitHub access uses your <code>gh</code> login.</p></div>`);
|
|
2693
2777
|
_serialize_if($scope0_reason, 0) && writeScope($scope8_id, {});
|
|
2694
2778
|
return 0;
|
|
2695
2779
|
}
|
|
@@ -2697,33 +2781,33 @@ var palette_default = _template("o", (input) => {
|
|
|
2697
2781
|
_html(`<input${_attr_input_value($scope0_id, "d", query || "", _resume(function(v) {
|
|
2698
2782
|
query = v;
|
|
2699
2783
|
hiRaw = 0;
|
|
2700
|
-
}, "o0", $scope0_id))}${_attr_class("
|
|
2784
|
+
}, "o0", $scope0_id))}${_attr_class("_bI")} autofocus placeholder="Jump to workspace…" aria-label="Filter workspaces">${_el_resume($scope0_id, "d")}<ul${_attr_class(["_br", !input.inline && "_bJ"])}>`);
|
|
2701
2785
|
_for_of(rows$1, (row$1, i) => {
|
|
2702
2786
|
const $scope1_id = _scope_id();
|
|
2703
|
-
_html(`<li><div${_attr_class("
|
|
2704
|
-
["
|
|
2705
|
-
["
|
|
2787
|
+
_html(`<li><div${_attr_class("_bs")}><button${_attr_class(["_bv", {
|
|
2788
|
+
["_bu"]: i === hi,
|
|
2789
|
+
["_bt"]: row$1.kind === "ws" && row$1.archived
|
|
2706
2790
|
}])}>`);
|
|
2707
2791
|
_if(() => {
|
|
2708
2792
|
if (row$1.kind === "new") {
|
|
2709
2793
|
const $scope10_id = _scope_id();
|
|
2710
|
-
_html(`<span${_attr_class("
|
|
2794
|
+
_html(`<span${_attr_class("_bz")}>+ New workspace</span>`);
|
|
2711
2795
|
writeScope($scope10_id, {});
|
|
2712
2796
|
return 0;
|
|
2713
2797
|
} else if (row$1.kind === "cmd") {
|
|
2714
2798
|
const $scope9_id = _scope_id();
|
|
2715
|
-
_html(`<span${_attr_class(["
|
|
2799
|
+
_html(`<span${_attr_class(["_bz", "_bx"])}>▸ <!>${_escape(row$1.label)}${_el_resume($scope9_id, "b")}</span>`);
|
|
2716
2800
|
writeScope($scope9_id, {});
|
|
2717
2801
|
return 1;
|
|
2718
2802
|
} else {
|
|
2719
2803
|
const $scope2_id = _scope_id();
|
|
2720
2804
|
const st = input.status[row$1.ws.id];
|
|
2721
2805
|
const rowPrs = (st?.repos || []).flatMap((r) => r.prs || []);
|
|
2722
|
-
_html(`<span${_attr_class("
|
|
2806
|
+
_html(`<span${_attr_class("_bz")}><span${_attr_class(["_q", phase[phaseOf(st)]])}></span>${_el_resume($scope2_id, "b")}<span${_attr_class("_bA")}>${_escape(row$1.ws.name)}${_el_resume($scope2_id, "d")}</span>`);
|
|
2723
2807
|
_if(() => {
|
|
2724
2808
|
if (row$1.ws.id === input.selectedId) {
|
|
2725
2809
|
const $scope14_id = _scope_id();
|
|
2726
|
-
_html(`<span${_attr_class(["_j", "
|
|
2810
|
+
_html(`<span${_attr_class(["_j", "_bC"])}>open</span>`);
|
|
2727
2811
|
writeScope($scope14_id, {});
|
|
2728
2812
|
return 0;
|
|
2729
2813
|
}
|
|
@@ -2736,11 +2820,11 @@ var palette_default = _template("o", (input) => {
|
|
|
2736
2820
|
return 0;
|
|
2737
2821
|
}
|
|
2738
2822
|
}, $scope2_id, "f", 1, 1, 1, 0, 1);
|
|
2739
|
-
_html(`<span${_attr_class("
|
|
2823
|
+
_html(`<span${_attr_class("_bB")}>`);
|
|
2740
2824
|
_if(() => {
|
|
2741
2825
|
if (st?.agents) {
|
|
2742
2826
|
const $scope11_id = _scope_id();
|
|
2743
|
-
_html(`<span${_attr_class(["_j", "
|
|
2827
|
+
_html(`<span${_attr_class(["_j", "_bD"])}${_attr("title", `${st.agents} running session${st.agents === 1 ? "" : "s"}${st.working ? ` — ${st.working} working` : ""}${st.waiting ? ` — ${st.waiting} waiting on you` : ""}`)}>${_escape(st.agents)}${_el_resume($scope11_id, "b")}</span>${_el_resume($scope11_id, "a")}`);
|
|
2744
2828
|
writeScope($scope11_id, {});
|
|
2745
2829
|
return 0;
|
|
2746
2830
|
}
|
|
@@ -2748,7 +2832,7 @@ var palette_default = _template("o", (input) => {
|
|
|
2748
2832
|
_if(() => {
|
|
2749
2833
|
if (rowPrs.length) {
|
|
2750
2834
|
const $scope13_id = _scope_id();
|
|
2751
|
-
_html(`<span${_attr_class(["_j", "
|
|
2835
|
+
_html(`<span${_attr_class(["_j", "_bD"])}${_attr("title", `${rowPrs.length} open PR${rowPrs.length === 1 ? "" : "s"}`)}>${_escape(rowPrs.length)}${_el_resume($scope13_id, "b")} PR<!>${rowPrs.length === 1 ? "" : "s"}${_el_resume($scope13_id, "c")}</span>${_el_resume($scope13_id, "a")}`);
|
|
2752
2836
|
writeScope($scope13_id, {});
|
|
2753
2837
|
return 0;
|
|
2754
2838
|
}
|
|
@@ -2756,12 +2840,12 @@ var palette_default = _template("o", (input) => {
|
|
|
2756
2840
|
_if(() => {
|
|
2757
2841
|
if ((st?.ports || []).length) {
|
|
2758
2842
|
const $scope12_id = _scope_id();
|
|
2759
|
-
_html(`<span${_attr_class(["_j", "
|
|
2843
|
+
_html(`<span${_attr_class(["_j", "_bD"])}${_attr("title", st.ports.map((p) => `:${p.port} ${p.cmd}`).join("\n"))}>:<!>${_escape(st.ports.length)}${_el_resume($scope12_id, "b")}</span>${_el_resume($scope12_id, "a")}`);
|
|
2760
2844
|
writeScope($scope12_id, {});
|
|
2761
2845
|
return 0;
|
|
2762
2846
|
}
|
|
2763
2847
|
}, $scope2_id, "j", 1, 1, 1, 0, 1);
|
|
2764
|
-
_html(`</span></span><span${_attr_class("
|
|
2848
|
+
_html(`</span></span><span${_attr_class("_bE")}>`);
|
|
2765
2849
|
_for_of(st?.repos || row$1.ws.repos, (repo) => {
|
|
2766
2850
|
const $scope16_id = _scope_id();
|
|
2767
2851
|
_html(`<span${_attr_class("_o")}>${_escape(repo.worktree)}${_el_resume($scope16_id, "b")}</span>`);
|
|
@@ -2781,13 +2865,13 @@ var palette_default = _template("o", (input) => {
|
|
|
2781
2865
|
_if(() => {
|
|
2782
2866
|
if (row$1.kind === "ws") {
|
|
2783
2867
|
const $scope3_id = _scope_id();
|
|
2784
|
-
_html(`<button${_attr_class("
|
|
2868
|
+
_html(`<button${_attr_class("_bw")} title="Review changes">`);
|
|
2785
2869
|
icon_diff_default({ size: 13 });
|
|
2786
|
-
_html(`</button>${_el_resume($scope3_id, "a")}<button${_attr_class("
|
|
2870
|
+
_html(`</button>${_el_resume($scope3_id, "a")}<button${_attr_class("_bw")} title="Manage workspace">`);
|
|
2787
2871
|
icon_manage_default({ size: 13 });
|
|
2788
2872
|
const newPopId = _id();
|
|
2789
2873
|
let pickerReady = false;
|
|
2790
|
-
_html(`</button>${_el_resume($scope3_id, "c")}<button${_attr_class("
|
|
2874
|
+
_html(`</button>${_el_resume($scope3_id, "c")}<button${_attr_class("_bw")} title="New session"${_attr("popovertarget", newPopId)}>`);
|
|
2791
2875
|
icon_plus_default({ size: 13 });
|
|
2792
2876
|
_html(`</button>${_el_resume($scope3_id, "e")}<div${_attr("id", newPopId)} popover=auto${_attr_class("_bM")}>`);
|
|
2793
2877
|
_for_of([], (agent) => {
|
|
@@ -2828,13 +2912,13 @@ var palette_default = _template("o", (input) => {
|
|
|
2828
2912
|
_if(() => {
|
|
2829
2913
|
if (archived.length && !query) {
|
|
2830
2914
|
const $scope7_id = _scope_id();
|
|
2831
|
-
_html(`<button${_attr_class("
|
|
2915
|
+
_html(`<button${_attr_class("_bH")}>${`archived (${_escape(`${archived.length}`)})`}${_el_resume($scope7_id, "b")}</button>${_el_resume($scope7_id, "a")}`);
|
|
2832
2916
|
_script($scope7_id, "o8");
|
|
2833
2917
|
writeScope($scope7_id, {});
|
|
2834
2918
|
return 0;
|
|
2835
2919
|
}
|
|
2836
2920
|
}, $scope0_id, "f", 1, 1, 1, 0, 1);
|
|
2837
|
-
_html(`<div${_attr_class("
|
|
2921
|
+
_html(`<div${_attr_class("_bF")}><span></span><span${_attr_class("_bG")}>↑↓ navigate · ↵ open · ⌘1–9 switch · esc close</span>`);
|
|
2838
2922
|
_if(() => {
|
|
2839
2923
|
if (settings) {
|
|
2840
2924
|
const $scope6_id = _scope_id();
|
|
@@ -2850,7 +2934,7 @@ var palette_default = _template("o", (input) => {
|
|
|
2850
2934
|
body: JSON.stringify({ preferredAgent: v })
|
|
2851
2935
|
}).catch(() => {});
|
|
2852
2936
|
}, "o1", $scope6_id), () => {
|
|
2853
|
-
_html(`<select${_attr_class("
|
|
2937
|
+
_html(`<select${_attr_class("_bL")} aria-label="Preferred agent">`);
|
|
2854
2938
|
_for_of(settings.agents, (agent) => {
|
|
2855
2939
|
const $scope17_id = _scope_id();
|
|
2856
2940
|
_html(`<option${_attr_option_value(agent)}>${_escape(agent)}${_el_resume($scope17_id, "b")}</option>${_el_resume($scope17_id, "a")}`);
|
|
@@ -2911,8 +2995,8 @@ var palette_default = _template("o", (input) => {
|
|
|
2911
2995
|
});
|
|
2912
2996
|
//#endregion
|
|
2913
2997
|
//#region src/tags/new-workspace.css.ts
|
|
2914
|
-
var content$2 = "
|
|
2915
|
-
var iconBtn$3 = "
|
|
2998
|
+
var content$2 = "_V _O";
|
|
2999
|
+
var iconBtn$3 = "_Y _y";
|
|
2916
3000
|
//#endregion
|
|
2917
3001
|
//#region src/tags/repo-picker.marko
|
|
2918
3002
|
var api$6;
|
|
@@ -2962,14 +3046,14 @@ var repo_picker_default = _template("q", (input) => {
|
|
|
2962
3046
|
input.onError?.(String(err.message || err));
|
|
2963
3047
|
}
|
|
2964
3048
|
}, "q5", $scope0_id);
|
|
2965
|
-
_html(`<div${_attr_class("
|
|
3049
|
+
_html(`<div${_attr_class("_bX")}><input${_attr_input_value($scope0_id, "b", filter, _resume(function(v) {
|
|
2966
3050
|
filter = v;
|
|
2967
3051
|
highlight = 0;
|
|
2968
|
-
}, "q0", $scope0_id))}${_attr_class("
|
|
3052
|
+
}, "q0", $scope0_id))}${_attr_class("_b9")} placeholder="Add a repo…" aria-label="Add a repo"${_attr("disabled", input.disabled)}>${_el_resume($scope0_id, "b")}`);
|
|
2969
3053
|
_if(() => {
|
|
2970
3054
|
if (filter && !catalog) {
|
|
2971
3055
|
const $scope8_id = _scope_id();
|
|
2972
|
-
_html(`<p${_attr_class("
|
|
3056
|
+
_html(`<p${_attr_class("_b8")}>Loading repos…</p>`);
|
|
2973
3057
|
writeScope($scope8_id, {});
|
|
2974
3058
|
return 0;
|
|
2975
3059
|
}
|
|
@@ -2977,23 +3061,23 @@ var repo_picker_default = _template("q", (input) => {
|
|
|
2977
3061
|
_if(() => {
|
|
2978
3062
|
if (results.length) {
|
|
2979
3063
|
const $scope2_id = _scope_id();
|
|
2980
|
-
_html(`<ul${_attr_class("
|
|
3064
|
+
_html(`<ul${_attr_class("_bY")}>`);
|
|
2981
3065
|
_for_of(results, (repo, i) => {
|
|
2982
3066
|
const $scope3_id = _scope_id();
|
|
2983
|
-
_html(`<li><div${_attr_class(["
|
|
3067
|
+
_html(`<li><div${_attr_class(["_b0", { ["_bZ"]: i === highlight }])}><button${_attr_class("_b1")}>`);
|
|
2984
3068
|
icon_plus_default({
|
|
2985
3069
|
size: 12,
|
|
2986
|
-
class: "
|
|
3070
|
+
class: "_b6"
|
|
2987
3071
|
});
|
|
2988
|
-
_html(`<span${_attr_class("
|
|
3072
|
+
_html(`<span${_attr_class("_b7")}>${_escape(repo.nameWithOwner)}${_el_resume($scope3_id, "e")}</span></button>${_el_resume($scope3_id, "b")}<button${_attr_class(["_b3", { ["_b2"]: branchesFor === repo.nameWithOwner }])}${_attr("title", `Pick a base branch for ${repo.nameWithOwner}`)}${_attr("aria-label", `Pick a base branch for ${repo.nameWithOwner}`)}>⎇</button>${_el_resume($scope3_id, "f")}</div>${_el_resume($scope3_id, "a")}`);
|
|
2989
3073
|
_if(() => {
|
|
2990
3074
|
if (branchesFor === repo.nameWithOwner) {
|
|
2991
3075
|
const $scope4_id = _scope_id();
|
|
2992
|
-
_html(`<div${_attr_class("
|
|
3076
|
+
_html(`<div${_attr_class("_b4")}>`);
|
|
2993
3077
|
_if(() => {
|
|
2994
3078
|
if (!branches) {
|
|
2995
3079
|
const $scope9_id = _scope_id();
|
|
2996
|
-
_html(`<p${_attr_class("
|
|
3080
|
+
_html(`<p${_attr_class("_b8")}><span${_attr_class("_w")}></span> Loading branches…</p>`);
|
|
2997
3081
|
writeScope($scope9_id, {});
|
|
2998
3082
|
return 0;
|
|
2999
3083
|
} else {
|
|
@@ -3003,24 +3087,24 @@ var repo_picker_default = _template("q", (input) => {
|
|
|
3003
3087
|
const $scope6_id = _scope_id();
|
|
3004
3088
|
_html(`<input${_attr_input_value($scope6_id, "a", branchFilter, _resume((_new_branchFilter) => {
|
|
3005
3089
|
branchFilter = _new_branchFilter;
|
|
3006
|
-
}, "q1", $scope6_id))}${_attr_class("
|
|
3090
|
+
}, "q1", $scope6_id))}${_attr_class("_b_")} placeholder="Filter branches…" aria-label="Filter branches" autofocus>${_el_resume($scope6_id, "a")}`);
|
|
3007
3091
|
_script($scope6_id, "q6");
|
|
3008
3092
|
_subscribe($branchFilter__closures, writeScope($scope6_id, { Ca9: 1 }));
|
|
3009
3093
|
return 0;
|
|
3010
3094
|
}
|
|
3011
3095
|
}, $scope5_id, "a", 1, 1, 1, 0, 1);
|
|
3012
3096
|
const shown = (branchFilter ? branches.filter((b) => b.toLowerCase().includes(branchFilter.toLowerCase())) : branches).slice(0, 12);
|
|
3013
|
-
_html(`<ul${_attr_class("
|
|
3097
|
+
_html(`<ul${_attr_class("_b5")}>`);
|
|
3014
3098
|
_for_of(shown, (branch) => {
|
|
3015
3099
|
const $scope7_id = _scope_id();
|
|
3016
|
-
_html(`<li><button${_attr_class(["
|
|
3100
|
+
_html(`<li><button${_attr_class(["_b1", "_ca"])}><span${_attr_class(["_b7", "_o"])}>${_escape(branch)}${_el_resume($scope7_id, "c")}</span></button>${_el_resume($scope7_id, "a")}</li>`);
|
|
3017
3101
|
_script($scope7_id, "q7");
|
|
3018
3102
|
writeScope($scope7_id, { e: branch });
|
|
3019
3103
|
}, (b) => b, $scope5_id, "c", 1, 1, 1, 0, 1);
|
|
3020
3104
|
_if(() => {
|
|
3021
3105
|
if (!shown.length) {
|
|
3022
3106
|
const $scope10_id = _scope_id();
|
|
3023
|
-
_html(`<li><p${_attr_class("
|
|
3107
|
+
_html(`<li><p${_attr_class("_b8")}>No branches match.</p></li>`);
|
|
3024
3108
|
writeScope($scope10_id, {});
|
|
3025
3109
|
return 0;
|
|
3026
3110
|
}
|
|
@@ -3045,7 +3129,7 @@ var repo_picker_default = _template("q", (input) => {
|
|
|
3045
3129
|
return 0;
|
|
3046
3130
|
} else if (filter && catalog) {
|
|
3047
3131
|
const $scope1_id = _scope_id();
|
|
3048
|
-
_html(`<p${_attr_class("
|
|
3132
|
+
_html(`<p${_attr_class("_b8")}>No repos match "<!>${_escape(filter)}${_el_resume($scope1_id, "b")}".</p>`);
|
|
3049
3133
|
writeScope($scope1_id, {});
|
|
3050
3134
|
return 1;
|
|
3051
3135
|
}
|
|
@@ -3196,28 +3280,28 @@ var new_workspace_default = _template("m", (input) => {
|
|
|
3196
3280
|
return 0;
|
|
3197
3281
|
}
|
|
3198
3282
|
}, $scope0_id, "h", 1, 1, 1, 0, 1);
|
|
3199
|
-
_html(`<label${_attr_class("
|
|
3283
|
+
_html(`<label${_attr_class("_Z")}><span${_attr_class("_bj")}>Name</span><input${_attr_input_value($scope0_id, "k", name, _resume((_new_name) => {
|
|
3200
3284
|
name = _new_name;
|
|
3201
|
-
}, "m0", $scope0_id))}${_attr_class("
|
|
3285
|
+
}, "m0", $scope0_id))}${_attr_class("_bk")} placeholder=my-feature${_attr("disabled", busy)} autofocus>${_el_resume($scope0_id, "k")}</label><section${_attr_class("_0")}><div${_attr_class("_1")}><h2${_attr_class("_bl")}>Repos</h2><button${_attr_class(iconBtn$3)} title="Refresh repo list" aria-label="Refresh repo list"${_attr("disabled", catalogRefreshing)}>`);
|
|
3202
3286
|
_set_serialize_reason(1);
|
|
3203
3287
|
const $childScope = _peek_scope_id();
|
|
3204
3288
|
icon_refresh_default({
|
|
3205
3289
|
size: 14,
|
|
3206
3290
|
class: catalogRefreshing && "_v"
|
|
3207
3291
|
});
|
|
3208
|
-
_html(`</button>${_el_resume($scope0_id, "o")}</div><ul${_attr_class("
|
|
3292
|
+
_html(`</button>${_el_resume($scope0_id, "o")}</div><ul${_attr_class("_2")}>`);
|
|
3209
3293
|
_for_of(selected, (repo) => {
|
|
3210
3294
|
const $scope1_id = _scope_id();
|
|
3211
|
-
_html(`<li${_attr_class("
|
|
3295
|
+
_html(`<li${_attr_class("_3")}><span${_attr_class("_4")}>${_escape(repo.fullName)}${_el_resume($scope1_id, "c")}</span>`);
|
|
3212
3296
|
_if(() => {
|
|
3213
3297
|
if (repo.baseBranch) {
|
|
3214
3298
|
const $scope8_id = _scope_id();
|
|
3215
|
-
_html(`<span${_attr_class(["
|
|
3299
|
+
_html(`<span${_attr_class(["_5", "_o"])} title="Base branch">⎇ <!>${_escape(repo.baseBranch)}${_el_resume($scope8_id, "b")}</span>`);
|
|
3216
3300
|
writeScope($scope8_id, {});
|
|
3217
3301
|
return 0;
|
|
3218
3302
|
}
|
|
3219
3303
|
}, $scope1_id, "d", 1, 1, 1, 0, 1);
|
|
3220
|
-
_html(`<button${_attr_class("
|
|
3304
|
+
_html(`<button${_attr_class("_6")}${_attr("title", `Remove ${repo.fullName}`)}${_attr("disabled", busy)}>×</button>${_el_resume($scope1_id, "e")}</li>`);
|
|
3221
3305
|
_script($scope1_id, "m11");
|
|
3222
3306
|
writeScope($scope1_id, {
|
|
3223
3307
|
h: repo?.fullName,
|
|
@@ -3227,7 +3311,7 @@ var new_workspace_default = _template("m", (input) => {
|
|
|
3227
3311
|
_if(() => {
|
|
3228
3312
|
if (!selected.length) {
|
|
3229
3313
|
const $scope9_id = _scope_id();
|
|
3230
|
-
_html(`<li${_attr_class("
|
|
3314
|
+
_html(`<li${_attr_class("_7")}>No repos yet — search below to add one (or create empty).</li>`);
|
|
3231
3315
|
writeScope($scope9_id, {});
|
|
3232
3316
|
return 0;
|
|
3233
3317
|
}
|
|
@@ -3252,10 +3336,10 @@ var new_workspace_default = _template("m", (input) => {
|
|
|
3252
3336
|
_if(() => {
|
|
3253
3337
|
if (busy && steps$1.length) {
|
|
3254
3338
|
const $scope6_id = _scope_id();
|
|
3255
|
-
_html(`<ul${_attr_class("
|
|
3339
|
+
_html(`<ul${_attr_class("_8")}>`);
|
|
3256
3340
|
_for_of(steps$1, (step$1, i) => {
|
|
3257
3341
|
const $scope7_id = _scope_id();
|
|
3258
|
-
_html(`<li${_attr_class(["
|
|
3342
|
+
_html(`<li${_attr_class(["_bm", { ["_9"]: i === steps$1.length - 1 }])}>`);
|
|
3259
3343
|
_if(() => {
|
|
3260
3344
|
if (i === steps$1.length - 1) {
|
|
3261
3345
|
const $scope10_id = _scope_id();
|
|
@@ -3264,7 +3348,7 @@ var new_workspace_default = _template("m", (input) => {
|
|
|
3264
3348
|
return 0;
|
|
3265
3349
|
} else {
|
|
3266
3350
|
const $scope11_id = _scope_id();
|
|
3267
|
-
_html(`<span${_attr_class("
|
|
3351
|
+
_html(`<span${_attr_class("__")}>✓</span>`);
|
|
3268
3352
|
writeScope($scope11_id, {});
|
|
3269
3353
|
return 1;
|
|
3270
3354
|
}
|
|
@@ -3276,19 +3360,19 @@ var new_workspace_default = _template("m", (input) => {
|
|
|
3276
3360
|
return 0;
|
|
3277
3361
|
}
|
|
3278
3362
|
}, $scope0_id, "v", 1, 1, 1, 0, 1);
|
|
3279
|
-
_html(`<div${_attr_class("
|
|
3363
|
+
_html(`<div${_attr_class("_W")}><button type=button${_attr_class(["_f", "_bn"])}${_attr("disabled", busy || !!restoring)}>Cancel</button>${_el_resume($scope0_id, "x")}<button type=button${_attr_class([
|
|
3280
3364
|
"_f",
|
|
3281
3365
|
"_g",
|
|
3282
|
-
"
|
|
3283
|
-
"
|
|
3366
|
+
"_X",
|
|
3367
|
+
"_bn"
|
|
3284
3368
|
])}${_attr("disabled", busy || !!restoring || !name.trim())}>${busy ? "Creating…" : "Create workspace"}${_el_resume($scope0_id, "z")}</button>${_el_resume($scope0_id, "y")}</div>`);
|
|
3285
3369
|
_if(() => {
|
|
3286
3370
|
if (archived$2.length) {
|
|
3287
3371
|
const $scope2_id = _scope_id();
|
|
3288
|
-
_html(`<section${_attr_class("
|
|
3372
|
+
_html(`<section${_attr_class("_ba")}><div${_attr_class("_1")}><h2${_attr_class("_bl")}>Archived</h2><span${_attr_class("_bb")}>${_escape(archived$2.length)}${_el_resume($scope2_id, "e", $sg__input_workspaces)}</span></div><p${_attr_class("_bc")}>Restore a parked space instead of creating a new one.</p><ul${_attr_class("_bd")}>`);
|
|
3289
3373
|
_for_of(archived$2, (ws) => {
|
|
3290
3374
|
const $scope3_id = _scope_id();
|
|
3291
|
-
_html(`<li${_attr_class("
|
|
3375
|
+
_html(`<li${_attr_class("_be")}><div${_attr_class("_bf")}><span${_attr_class("_bg")}>${_escape(ws.name)}${_el_resume($scope3_id, "d", $sg__input_workspaces)}</span><span${_attr_class(["_bh", "_o"])}${_attr("title", ws.display_path || ws.path)}>${_escape(ws.display_path || ws.path)}${_el_resume($scope3_id, "f", $sg__input_workspaces)}</span>${_el_resume($scope3_id, "e", $sg__input_workspaces)}</div><button type=button${_attr_class(["_f", "_bi"])}${_attr("disabled", busy || !!restoring)}>`);
|
|
3292
3376
|
_if(() => {
|
|
3293
3377
|
if (restoring === ws.id) {
|
|
3294
3378
|
const $scope12_id = _scope_id();
|
|
@@ -3410,8 +3494,8 @@ function vapidKey(base64) {
|
|
|
3410
3494
|
const raw = atob(padded.replace(/-/g, "+").replace(/_/g, "/"));
|
|
3411
3495
|
return Uint8Array.from(raw, (c) => c.charCodeAt(0));
|
|
3412
3496
|
}
|
|
3413
|
-
var iconBtn$2 = "
|
|
3414
|
-
var navToggle = "
|
|
3497
|
+
var iconBtn$2 = "_cD _y";
|
|
3498
|
+
var navToggle = "_cH _y";
|
|
3415
3499
|
_template("C", (input) => {
|
|
3416
3500
|
const $scope0_reason = _scope_reason(), $sg__input_size__OR__input_class = _serialize_guard($scope0_reason, 0);
|
|
3417
3501
|
const $scope0_id = _scope_id();
|
|
@@ -4017,19 +4101,19 @@ var side_nav_default = _template("t", (input) => {
|
|
|
4017
4101
|
const wsSelected = view !== "usage" && view !== "new";
|
|
4018
4102
|
const otherIds = itemIds.filter((id) => id !== ws.id);
|
|
4019
4103
|
const listIds = isPage ? [ws.id, ...otherIds] : itemIds;
|
|
4020
|
-
_html(`<aside${_attr_class(["
|
|
4021
|
-
["
|
|
4022
|
-
["
|
|
4104
|
+
_html(`<aside${_attr_class(["_cG", {
|
|
4105
|
+
["_cE"]: !navOpen,
|
|
4106
|
+
["_cF"]: isPage
|
|
4023
4107
|
}])}${_attr("hidden", view === "diff")}>`);
|
|
4024
4108
|
_if(() => {
|
|
4025
4109
|
if (isPage) {
|
|
4026
4110
|
const $scope1_id = _scope_id();
|
|
4027
|
-
_html(`<header${_attr_class("
|
|
4111
|
+
_html(`<header${_attr_class("_cJ")}><h1${_attr_class("_cK")}>Workspaces</h1><div${_attr_class("_cL")}>`);
|
|
4028
4112
|
_if(() => {}, $scope1_id, "d", 1, 1, 1, 0, 1);
|
|
4029
4113
|
_html(`<button${_attr_class([
|
|
4030
4114
|
iconBtn$2,
|
|
4031
|
-
"
|
|
4032
|
-
{ ["
|
|
4115
|
+
"_cM",
|
|
4116
|
+
{ ["_cC"]: view === "usage" }
|
|
4033
4117
|
])} title=Usage aria-pressed=${view === "usage" ? "true" : "false"}>`);
|
|
4034
4118
|
icon_gauge_default({ size: 16 });
|
|
4035
4119
|
_html(`</button>${_el_resume($scope1_id, "e")}</div></header>`);
|
|
@@ -4038,13 +4122,13 @@ var side_nav_default = _template("t", (input) => {
|
|
|
4038
4122
|
return 0;
|
|
4039
4123
|
}
|
|
4040
4124
|
}, $scope0_id, "b", 1, 1, 1, 0, 1);
|
|
4041
|
-
_html(`<div${_attr_class("
|
|
4125
|
+
_html(`<div${_attr_class("_cP")}>`);
|
|
4042
4126
|
_for_of(listIds, (wsId) => {
|
|
4043
4127
|
const $scope2_id = _scope_id();
|
|
4044
4128
|
_if(() => {
|
|
4045
4129
|
if (isPage && wsId === ws.id) {
|
|
4046
4130
|
const $scope10_id = _scope_id();
|
|
4047
|
-
_html(`<h2${_attr_class("
|
|
4131
|
+
_html(`<h2${_attr_class("_cN")}>Current</h2>`);
|
|
4048
4132
|
writeScope($scope10_id, {});
|
|
4049
4133
|
return 0;
|
|
4050
4134
|
}
|
|
@@ -4052,7 +4136,7 @@ var side_nav_default = _template("t", (input) => {
|
|
|
4052
4136
|
_if(() => {
|
|
4053
4137
|
if (isPage && wsId !== ws.id && wsId === otherIds[0]) {
|
|
4054
4138
|
const $scope11_id = _scope_id();
|
|
4055
|
-
_html(`<h2${_attr_class("
|
|
4139
|
+
_html(`<h2${_attr_class("_cN")}>Other spaces</h2>`);
|
|
4056
4140
|
writeScope($scope11_id, {});
|
|
4057
4141
|
return 0;
|
|
4058
4142
|
}
|
|
@@ -4150,7 +4234,7 @@ var side_nav_default = _template("t", (input) => {
|
|
|
4150
4234
|
railHover = null;
|
|
4151
4235
|
}, 150);
|
|
4152
4236
|
}, "t9", $scope3_id);
|
|
4153
|
-
_html(`<div${_attr_class("
|
|
4237
|
+
_html(`<div${_attr_class("_cQ")}>`);
|
|
4154
4238
|
_for_of(itemIds, (wsId, i) => {
|
|
4155
4239
|
const $scope4_id = _scope_id();
|
|
4156
4240
|
_html("<span>");
|
|
@@ -4197,7 +4281,7 @@ var side_nav_default = _template("t", (input) => {
|
|
|
4197
4281
|
if (railHover) {
|
|
4198
4282
|
const $scope5_id = _scope_id();
|
|
4199
4283
|
const hoverId = railHover.id;
|
|
4200
|
-
_html(`<div${_attr_class("
|
|
4284
|
+
_html(`<div${_attr_class("_cT")}${_attr_style(`top:${railHover.top}px;left:${railHover.left}px`)}>`);
|
|
4201
4285
|
_set_serialize_reason({
|
|
4202
4286
|
0: 1,
|
|
4203
4287
|
1: 1,
|
|
@@ -4300,11 +4384,11 @@ var side_nav_default = _template("t", (input) => {
|
|
|
4300
4384
|
return 0;
|
|
4301
4385
|
}
|
|
4302
4386
|
}, $scope0_id, "d");
|
|
4303
|
-
_html(`<div${_attr_class("
|
|
4387
|
+
_html(`<div${_attr_class("_cR")}>`);
|
|
4304
4388
|
_if(() => {
|
|
4305
4389
|
if (isPage) {
|
|
4306
4390
|
const $scope6_id = _scope_id();
|
|
4307
|
-
_html(`<button${_attr_class(["
|
|
4391
|
+
_html(`<button${_attr_class(["_cO", { ["_cC"]: view === "new" }])} title="New workspace" aria-pressed=${view === "new" ? "true" : "false"}>`);
|
|
4308
4392
|
icon_folder_plus_default({ size: 16 });
|
|
4309
4393
|
_html(` New workspace</button>${_el_resume($scope6_id, "a")}`);
|
|
4310
4394
|
_script($scope6_id, "t21");
|
|
@@ -4326,11 +4410,11 @@ var side_nav_default = _template("t", (input) => {
|
|
|
4326
4410
|
return 1;
|
|
4327
4411
|
}
|
|
4328
4412
|
}, $scope7_id, "a", 1, 1, 1, "</button>", 1);
|
|
4329
|
-
_html(`<div${_attr_class(["_p", "
|
|
4413
|
+
_html(`<div${_attr_class(["_p", "_cS"])}></div>`);
|
|
4330
4414
|
_if(() => {}, $scope7_id, "c", 1, 1, 1, 0, 1);
|
|
4331
|
-
_html(`<button${_attr_class([iconBtn$2, { ["
|
|
4415
|
+
_html(`<button${_attr_class([iconBtn$2, { ["_cC"]: view === "usage" }])} title=Usage aria-pressed=${view === "usage" ? "true" : "false"}>`);
|
|
4332
4416
|
icon_gauge_default({ size: 15 });
|
|
4333
|
-
_html(`</button>${_el_resume($scope7_id, "d")}<button${_attr_class([iconBtn$2, { ["
|
|
4417
|
+
_html(`</button>${_el_resume($scope7_id, "d")}<button${_attr_class([iconBtn$2, { ["_cC"]: view === "new" }])} title="New workspace" aria-pressed=${view === "new" ? "true" : "false"}>`);
|
|
4334
4418
|
icon_folder_plus_default({ size: 16 });
|
|
4335
4419
|
_html(`</button>${_el_resume($scope7_id, "f")}`);
|
|
4336
4420
|
_script($scope7_id, "t23");
|
|
@@ -4397,9 +4481,9 @@ var side_nav_default = _template("t", (input) => {
|
|
|
4397
4481
|
});
|
|
4398
4482
|
//#endregion
|
|
4399
4483
|
//#region src/tags/manage-workspace.css.ts
|
|
4400
|
-
var content$1 = "
|
|
4401
|
-
var pageMeta = "
|
|
4402
|
-
var iconBtn$1 = "
|
|
4484
|
+
var content$1 = "_cU _O";
|
|
4485
|
+
var pageMeta = "_cV _T";
|
|
4486
|
+
var iconBtn$1 = "_dm _y";
|
|
4403
4487
|
//#endregion
|
|
4404
4488
|
//#region src/tags/manage-workspace.marko
|
|
4405
4489
|
var api$3;
|
|
@@ -4493,16 +4577,16 @@ var manage_workspace_default = _template("k", (input) => {
|
|
|
4493
4577
|
setTimeout(() => loadProcs(void 0), 500);
|
|
4494
4578
|
}, "k5", $scope0_id);
|
|
4495
4579
|
const titleId = _id();
|
|
4496
|
-
_html(`<div${_attr_class("_M")} role=region${_attr("aria-labelledby", titleId)}><div${_attr_class("_N")}><div${_attr_class(content$1)}><header${_attr_class("_Q")}><div${_attr_class("_S")}><h1${_attr("id", titleId)}${_attr_class("_R")}>Manage</h1><p${_attr_class(pageMeta)}${_attr("title", ws.display_path || ws.path)}><span${_attr_class("
|
|
4580
|
+
_html(`<div${_attr_class("_M")} role=region${_attr("aria-labelledby", titleId)}><div${_attr_class("_N")}><div${_attr_class(content$1)}><header${_attr_class("_Q")}><div${_attr_class("_S")}><h1${_attr("id", titleId)}${_attr_class("_R")}>Manage</h1><p${_attr_class(pageMeta)}${_attr("title", ws.display_path || ws.path)}><span${_attr_class("_cW")}>${_escape(ws.name)}${_el_resume($scope0_id, "i")}</span>`);
|
|
4497
4581
|
_if(() => {
|
|
4498
4582
|
if (ws.status !== "active") {
|
|
4499
4583
|
const $scope10_id = _scope_id();
|
|
4500
|
-
_html(`<span${_attr_class(["
|
|
4584
|
+
_html(`<span${_attr_class(["_cZ", "_c0"])}>Archived</span>`);
|
|
4501
4585
|
writeScope($scope10_id, {});
|
|
4502
4586
|
return 0;
|
|
4503
4587
|
}
|
|
4504
4588
|
}, $scope0_id, "j", 1, 1, 1, 0, 1);
|
|
4505
|
-
_html(`<span${_attr_class("
|
|
4589
|
+
_html(`<span${_attr_class("_cX")} aria-hidden=true>·</span><span${_attr_class(["_cY", "_o"])}>${_escape(ws.display_path || ws.path)}${_el_resume($scope0_id, "m")}</span></p>${_el_resume($scope0_id, "g")}</div></header>`);
|
|
4506
4590
|
_if(() => {
|
|
4507
4591
|
if (error) {
|
|
4508
4592
|
const $scope2_id = _scope_id();
|
|
@@ -4526,26 +4610,26 @@ var manage_workspace_default = _template("k", (input) => {
|
|
|
4526
4610
|
_if(() => {
|
|
4527
4611
|
if (pendingAction && actionStep) {
|
|
4528
4612
|
const $scope7_id = _scope_id();
|
|
4529
|
-
_html(`<p${_attr_class("
|
|
4613
|
+
_html(`<p${_attr_class("_c1")}><span${_attr_class("_w")}></span><!>${_escape(actionStep)}${_el_resume($scope7_id, "c")}</p>`);
|
|
4530
4614
|
writeScope($scope7_id, {});
|
|
4531
4615
|
return 0;
|
|
4532
4616
|
}
|
|
4533
4617
|
}, $scope0_id, "o", 1, 1, 1, 0, 1);
|
|
4534
|
-
_html(`<section${_attr_class("
|
|
4618
|
+
_html(`<section${_attr_class("_c2")}><div${_attr_class("_c3")}><h2${_attr_class("_dn")}>Repos</h2><span${_attr_class("_c4")}>${_escape(ws.repos.length)}${_el_resume($scope0_id, "t")}</span><div${_attr_class("_p")}></div><button${_attr_class(iconBtn$1)} title="Refresh repo list" aria-label="Refresh repo list"${_attr("disabled", catalogRefreshing)}>`);
|
|
4535
4619
|
_set_serialize_reason(1);
|
|
4536
4620
|
const $childScope = _peek_scope_id();
|
|
4537
4621
|
icon_refresh_default({
|
|
4538
4622
|
size: 14,
|
|
4539
4623
|
class: catalogRefreshing && "_v"
|
|
4540
4624
|
});
|
|
4541
|
-
_html(`</button>${_el_resume($scope0_id, "v")}</div><ul${_attr_class("
|
|
4625
|
+
_html(`</button>${_el_resume($scope0_id, "v")}</div><ul${_attr_class("_c6")}>`);
|
|
4542
4626
|
_for_of(ws.repos, (row) => {
|
|
4543
4627
|
const $scope1_id = _scope_id();
|
|
4544
|
-
_html(`<li${_attr_class("
|
|
4628
|
+
_html(`<li${_attr_class("_c8")}><div${_attr_class("_c9")}><span${_attr_class(["_c_", "_o"])}>${_escape(row.worktree)}${_el_resume($scope1_id, "d")}/</span><span${_attr_class("_da")}><span${_attr_class("_db")}>${_escape(row.full_name)}${_el_resume($scope1_id, "g")}</span>`);
|
|
4545
4629
|
_if(() => {
|
|
4546
4630
|
if (row.base_branch !== row.default_branch) {
|
|
4547
4631
|
const $scope11_id = _scope_id();
|
|
4548
|
-
_html(`<span${_attr_class(["
|
|
4632
|
+
_html(`<span${_attr_class(["_dc", "_o"])} title="Base branch">⎇ <!>${_escape(row.base_branch)}${_el_resume($scope11_id, "b")}</span>`);
|
|
4549
4633
|
writeScope($scope11_id, {});
|
|
4550
4634
|
return 0;
|
|
4551
4635
|
}
|
|
@@ -4560,9 +4644,9 @@ var manage_workspace_default = _template("k", (input) => {
|
|
|
4560
4644
|
} else {
|
|
4561
4645
|
const $scope6_id = _scope_id();
|
|
4562
4646
|
_html(`<button${_attr_class([
|
|
4563
|
-
"
|
|
4564
|
-
"
|
|
4565
|
-
{ ["
|
|
4647
|
+
"_dd",
|
|
4648
|
+
"_df",
|
|
4649
|
+
{ ["_de"]: confirmingRemove === row.full_name }
|
|
4566
4650
|
])}${confirmingRemove === row.full_name ? _attr("title", `Really remove ${row.worktree}/? Uncommitted changes are lost.`) : _attr("title", `Remove ${row.worktree}/`)}>${confirmingRemove === row.full_name ? "Remove?" : "×"}${_el_resume($scope6_id, "b")}</button>${_el_resume($scope6_id, "a")}`);
|
|
4567
4651
|
_script($scope6_id, "k11");
|
|
4568
4652
|
_subscribe($confirmingRemove__closures, writeScope($scope6_id, {}));
|
|
@@ -4579,19 +4663,19 @@ var manage_workspace_default = _template("k", (input) => {
|
|
|
4579
4663
|
}, "full_name", $scope0_id, "y", 1, 1, 1, 0, 1);
|
|
4580
4664
|
_for_of([...busy].filter((n) => !inWorkspace.has(n)), (name) => {
|
|
4581
4665
|
const $scope13_id = _scope_id();
|
|
4582
|
-
_html(`<li${_attr_class(["
|
|
4666
|
+
_html(`<li${_attr_class(["_c8", "_c7"])}><span${_attr_class("_w")}></span><div${_attr_class("_c9")}><span${_attr_class("_db")}>Adding <!>${_escape(name)}${_el_resume($scope13_id, "e")}…</span></div></li>`);
|
|
4583
4667
|
writeScope($scope13_id, {});
|
|
4584
4668
|
}, (n) => n, $scope0_id, "z", 1, 1, 1, 0, 1);
|
|
4585
4669
|
_html("</ul>");
|
|
4586
4670
|
_if(() => {
|
|
4587
4671
|
if (!ws.repos.length && !busy.size) {
|
|
4588
4672
|
const $scope14_id = _scope_id();
|
|
4589
|
-
_html(`<p${_attr_class("
|
|
4673
|
+
_html(`<p${_attr_class("_dh")}>No repos yet — search below to add one.</p>`);
|
|
4590
4674
|
writeScope($scope14_id, {});
|
|
4591
4675
|
return 0;
|
|
4592
4676
|
}
|
|
4593
4677
|
}, $scope0_id, "a0", 1, 1, 1, 0, 1);
|
|
4594
|
-
_html(`<div${_attr_class("
|
|
4678
|
+
_html(`<div${_attr_class("_c5")}>`);
|
|
4595
4679
|
const $childScope2 = _peek_scope_id();
|
|
4596
4680
|
let refreshCatalog = repo_picker_default({
|
|
4597
4681
|
exclude: inWorkspace,
|
|
@@ -4611,17 +4695,17 @@ var manage_workspace_default = _template("k", (input) => {
|
|
|
4611
4695
|
_if(() => {
|
|
4612
4696
|
if (running.length) {
|
|
4613
4697
|
const $scope8_id = _scope_id();
|
|
4614
|
-
_html(`<section${_attr_class("
|
|
4698
|
+
_html(`<section${_attr_class("_c2")}><div${_attr_class("_c3")}><h2${_attr_class("_dn")}>Running</h2><span${_attr_class("_c4")}>${_escape(running.length)}${_el_resume($scope8_id, "e")}</span></div><ul${_attr_class("_c6")}>`);
|
|
4615
4699
|
_for_of(running, (p) => {
|
|
4616
4700
|
const $scope9_id = _scope_id();
|
|
4617
|
-
_html(`<li${_attr_class("
|
|
4701
|
+
_html(`<li${_attr_class("_c8")}><div${_attr_class("_c9")}${_attr("title", p.args)}><span${_attr_class(["_c_", "_o"])}>${_escape(p.cmd)}${_el_resume($scope9_id, "d")}</span>`);
|
|
4618
4702
|
_if(() => {
|
|
4619
4703
|
if (p.ports.length) {
|
|
4620
4704
|
const $scope15_id = _scope_id();
|
|
4621
|
-
_html(`<span${_attr_class("
|
|
4705
|
+
_html(`<span${_attr_class("_da")}>`);
|
|
4622
4706
|
_for_of(p.ports, (port) => {
|
|
4623
4707
|
const $scope16_id = _scope_id();
|
|
4624
|
-
_html(`<button${_attr_class(["_j", "
|
|
4708
|
+
_html(`<button${_attr_class(["_j", "_dg"])}${_attr("title", `Open http://${typeof location === "undefined" ? "localhost" : location.hostname}:${port}`)}>:<!>${_escape(port)}${_el_resume($scope16_id, "b")}</button>${_el_resume($scope16_id, "a")}`);
|
|
4625
4709
|
_script($scope16_id, "k13");
|
|
4626
4710
|
writeScope($scope16_id, { d: port });
|
|
4627
4711
|
}, (x) => String(x), $scope15_id, "a", 1, 1, 1, "</span>", 1);
|
|
@@ -4629,7 +4713,7 @@ var manage_workspace_default = _template("k", (input) => {
|
|
|
4629
4713
|
return 0;
|
|
4630
4714
|
}
|
|
4631
4715
|
}, $scope9_id, "e", 1, 1, 1, 0, 1);
|
|
4632
|
-
_html(`</div>${_el_resume($scope9_id, "b")}<button${_attr_class(["
|
|
4716
|
+
_html(`</div>${_el_resume($scope9_id, "b")}<button${_attr_class(["_dd", "_df"])} type=button${_attr("title", `Kill ${p.pid}`)}${_attr("aria-label", `Kill process ${p.pid}`)}>×</button>${_el_resume($scope9_id, "f")}</li>`);
|
|
4633
4717
|
_script($scope9_id, "k14");
|
|
4634
4718
|
writeScope($scope9_id, {
|
|
4635
4719
|
k: p?.ports,
|
|
@@ -4641,17 +4725,17 @@ var manage_workspace_default = _template("k", (input) => {
|
|
|
4641
4725
|
return 0;
|
|
4642
4726
|
}
|
|
4643
4727
|
}, $scope0_id, "a4", 1, 1, 1, 0, 1);
|
|
4644
|
-
_html(`<section${_attr_class(["
|
|
4728
|
+
_html(`<section${_attr_class(["_c2", "_di"])}><div${_attr_class("_c3")}><h2${_attr_class("_dn")}>Workspace</h2></div><div${_attr_class("_dj")}>`);
|
|
4645
4729
|
_if(() => {
|
|
4646
4730
|
if (ws.status === "active") {
|
|
4647
4731
|
const $scope4_id = _scope_id();
|
|
4648
|
-
_html(`<button type=button${_attr_class(["_f", "
|
|
4732
|
+
_html(`<button type=button${_attr_class(["_f", "_dk"])}${_attr("disabled", !!pendingAction)}>${pendingAction === "archive" ? "Archiving…" : "Archive"}${_el_resume($scope4_id, "b")}</button>${_el_resume($scope4_id, "a")}`);
|
|
4649
4733
|
_script($scope4_id, "k15");
|
|
4650
4734
|
writeScope($scope4_id, {});
|
|
4651
4735
|
return 0;
|
|
4652
4736
|
} else {
|
|
4653
4737
|
const $scope5_id = _scope_id();
|
|
4654
|
-
_html(`<button type=button${_attr_class(["_f", "
|
|
4738
|
+
_html(`<button type=button${_attr_class(["_f", "_dk"])}${_attr("disabled", !!pendingAction)}>Restore</button>${_el_resume($scope5_id, "a")}`);
|
|
4655
4739
|
_script($scope5_id, "k16");
|
|
4656
4740
|
writeScope($scope5_id, {});
|
|
4657
4741
|
return 1;
|
|
@@ -4660,9 +4744,9 @@ var manage_workspace_default = _template("k", (input) => {
|
|
|
4660
4744
|
_html(`<button type=button${_attr_class([
|
|
4661
4745
|
"_f",
|
|
4662
4746
|
"_i",
|
|
4663
|
-
"
|
|
4747
|
+
"_dk",
|
|
4664
4748
|
{ ["_h"]: confirmingDelete }
|
|
4665
|
-
])}${_attr("disabled", !!pendingAction)}>${pendingAction === "delete" ? "Deleting…" : "Delete"}${_el_resume($scope0_id, "ab")}</button>${_el_resume($scope0_id, "aa")}</div><p${_attr_class("
|
|
4749
|
+
])}${_attr("disabled", !!pendingAction)}>${pendingAction === "delete" ? "Deleting…" : "Delete"}${_el_resume($scope0_id, "ab")}</button>${_el_resume($scope0_id, "aa")}</div><p${_attr_class("_dl")}>Archive hides the space from the list. Delete removes it and its worktrees.</p></section></div></div></div>`);
|
|
4666
4750
|
_script($scope0_id, "k17");
|
|
4667
4751
|
_script($scope0_id, "k18");
|
|
4668
4752
|
writeScope($scope0_id, {
|
|
@@ -4699,8 +4783,8 @@ var manage_workspace_default = _template("k", (input) => {
|
|
|
4699
4783
|
});
|
|
4700
4784
|
//#endregion
|
|
4701
4785
|
//#region src/tags/usage-stats.css.ts
|
|
4702
|
-
var content = "
|
|
4703
|
-
var iconBtn = "
|
|
4786
|
+
var content = "_cb _O _P";
|
|
4787
|
+
var iconBtn = "_cc _y";
|
|
4704
4788
|
//#endregion
|
|
4705
4789
|
//#region src/tags/usage-stats.marko
|
|
4706
4790
|
var api$2;
|
|
@@ -4735,7 +4819,7 @@ var usage_stats_default = _template("x", (input) => {
|
|
|
4735
4819
|
refreshing = false;
|
|
4736
4820
|
}, "x1", $scope0_id);
|
|
4737
4821
|
const titleId = _id();
|
|
4738
|
-
_html(`<div${_attr_class("_M")} role=region${_attr("aria-labelledby", titleId)}><div${_attr_class("_N")}><div${_attr_class(content)}><header${_attr_class("_Q")}><div${_attr_class("_S")}><h1${_attr("id", titleId)}${_attr_class("_R")}>Usage</h1><p${_attr_class("_T")}>Provider plan windows across your agents.</p></div><div${_attr_class("_U")}><button${_attr_class([iconBtn, "
|
|
4822
|
+
_html(`<div${_attr_class("_M")} role=region${_attr("aria-labelledby", titleId)}><div${_attr_class("_N")}><div${_attr_class(content)}><header${_attr_class("_Q")}><div${_attr_class("_S")}><h1${_attr("id", titleId)}${_attr_class("_R")}>Usage</h1><p${_attr_class("_T")}>Provider plan windows across your agents.</p></div><div${_attr_class("_U")}><button${_attr_class([iconBtn, "_cd"])} title="Refresh usage" aria-label="Refresh usage"${_attr("disabled", refreshing)}>`);
|
|
4739
4823
|
_set_serialize_reason(1);
|
|
4740
4824
|
const $childScope = _peek_scope_id();
|
|
4741
4825
|
icon_refresh_default({
|
|
@@ -4746,24 +4830,24 @@ var usage_stats_default = _template("x", (input) => {
|
|
|
4746
4830
|
_if(() => {
|
|
4747
4831
|
if (!usage) {
|
|
4748
4832
|
const $scope3_id = _scope_id();
|
|
4749
|
-
_html(`<p${_attr_class(["_n", "
|
|
4833
|
+
_html(`<p${_attr_class(["_n", "_ce"])}><span${_attr_class("_w")}></span> Loading usage…</p>`);
|
|
4750
4834
|
writeScope($scope3_id, {});
|
|
4751
4835
|
return 0;
|
|
4752
4836
|
} else if (usage.error) {
|
|
4753
4837
|
const $scope1_id = _scope_id();
|
|
4754
|
-
_html(`<p${_attr_class(["_n", "
|
|
4838
|
+
_html(`<p${_attr_class(["_n", "_ce"])}>${_escape(usage.error)}${_el_resume($scope1_id, "b")}</p>`);
|
|
4755
4839
|
writeScope($scope1_id, {});
|
|
4756
4840
|
return 1;
|
|
4757
4841
|
} else {
|
|
4758
4842
|
const $scope2_id = _scope_id();
|
|
4759
|
-
_html(`<div${_attr_class("
|
|
4843
|
+
_html(`<div${_attr_class("_cf")}>`);
|
|
4760
4844
|
_for_of(usage.agents || [], (agent) => {
|
|
4761
4845
|
const $scope4_id = _scope_id();
|
|
4762
|
-
_html(`<div${_attr_class("
|
|
4846
|
+
_html(`<div${_attr_class("_cg")}><div${_attr_class("_ch")}><strong${_attr_class("_cA")}>${_escape(agent.agent)}${_el_resume($scope4_id, "d")}</strong>`);
|
|
4763
4847
|
_if(() => {
|
|
4764
4848
|
if (agent.plan) {
|
|
4765
4849
|
const $scope5_id = _scope_id();
|
|
4766
|
-
_html(`<span${_attr_class("
|
|
4850
|
+
_html(`<span${_attr_class("_ci")}>${_escape(agent.plan.replace(/^default_/, "").replaceAll("_", " "))}${_el_resume($scope5_id, "b")}</span>`);
|
|
4767
4851
|
writeScope($scope5_id, {});
|
|
4768
4852
|
return 0;
|
|
4769
4853
|
}
|
|
@@ -4771,25 +4855,25 @@ var usage_stats_default = _template("x", (input) => {
|
|
|
4771
4855
|
_if(() => {
|
|
4772
4856
|
if (agent.stale_seconds != null) {
|
|
4773
4857
|
const $scope6_id = _scope_id();
|
|
4774
|
-
_html(`<span${_attr_class("
|
|
4858
|
+
_html(`<span${_attr_class("_cj")}${_attr("title", `${agent.note || "couldn't reach this provider"} — these are the last cached numbers, ${duration(agent.stale_seconds * 1e3)} old`)}>⚠ <!>${_escape(duration(agent.stale_seconds * 1e3))}${_el_resume($scope6_id, "b")} old</span>${_el_resume($scope6_id, "a")}`);
|
|
4775
4859
|
writeScope($scope6_id, {});
|
|
4776
4860
|
return 0;
|
|
4777
4861
|
}
|
|
4778
4862
|
}, $scope4_id, "f", 1, 1, 1, 0, 1);
|
|
4779
|
-
_html(`</div><div${_attr_class(["
|
|
4863
|
+
_html(`</div><div${_attr_class(["_ck", { ["_cB"]: agent.stale_seconds != null }])}>`);
|
|
4780
4864
|
_for_of(agent.windows || [], (win) => {
|
|
4781
4865
|
const $scope7_id = _scope_id();
|
|
4782
4866
|
const pct = Math.round(win.used_percent);
|
|
4783
4867
|
const label = resetLabel(win.resets_at, agent.stale_seconds != null);
|
|
4784
|
-
const fillClass = win.used_percent >= 90 ? "
|
|
4785
|
-
const pctClass = win.used_percent >= 90 ? "
|
|
4786
|
-
_html(`<div${_attr_class("
|
|
4868
|
+
const fillClass = win.used_percent >= 90 ? "_ct" : win.used_percent >= 70 ? "_cs" : win.used_percent >= 40 ? "_cr" : "_cq";
|
|
4869
|
+
const pctClass = win.used_percent >= 90 ? "_cy" : win.used_percent >= 70 ? "_cx" : win.used_percent >= 40 ? "_cw" : "_cv";
|
|
4870
|
+
_html(`<div${_attr_class("_cm")}${_attr("title", `${win.window}: ${pct}% used${win.resets_at ? ` — resets ${new Date(win.resets_at).toLocaleString()}` : ""}`)}><span${_attr_class("_cn")}>${_escape(win.window)}${_el_resume($scope7_id, "c")}</span><span${_attr_class("_co")}><span${_attr_class(["_cp", fillClass])}${_attr_style(`width:${Math.min(100, Math.max(2, win.used_percent))}%`)}></span>${_el_resume($scope7_id, "e")}</span><span${_attr_class(["_cu", pctClass])}>${_escape(pct)}${_el_resume($scope7_id, "g")}%</span>${_el_resume($scope7_id, "f")}<span${_attr_class("_cz")}>${label ? `↻ ${_escape(`${_to_text(label)}`)}` : ""}${_el_resume($scope7_id, "i")}</span></div>${_el_resume($scope7_id, "a")}`);
|
|
4787
4871
|
writeScope($scope7_id, {});
|
|
4788
4872
|
}, "window", $scope4_id, "h", 1, 1, 1, 0, 1);
|
|
4789
4873
|
_if(() => {
|
|
4790
4874
|
if (agent.note) {
|
|
4791
4875
|
const $scope8_id = _scope_id();
|
|
4792
|
-
_html(`<p${_attr_class("
|
|
4876
|
+
_html(`<p${_attr_class("_cl")}>${_escape(agent.note)}${_el_resume($scope8_id, "b")}</p>`);
|
|
4793
4877
|
writeScope($scope8_id, {});
|
|
4794
4878
|
return 0;
|
|
4795
4879
|
}
|
|
@@ -4853,15 +4937,15 @@ var term_find_default = _template("u", (input) => {
|
|
|
4853
4937
|
const canStep = hasQuery && open;
|
|
4854
4938
|
const keybar = input.placement === "keybar";
|
|
4855
4939
|
_html(`<div${_attr_class([
|
|
4856
|
-
"
|
|
4857
|
-
keybar ? "
|
|
4858
|
-
!open && "
|
|
4859
|
-
])} aria-hidden=${open ? "false" : "true"}><div${_attr_class(["
|
|
4940
|
+
"_fb",
|
|
4941
|
+
keybar ? "_fd" : "_fc",
|
|
4942
|
+
!open && "_ff"
|
|
4943
|
+
])} aria-hidden=${open ? "false" : "true"}><div${_attr_class(["_e7", keybar ? "_fe" : "_e9"])}><input${_attr_input_value($scope0_id, "c", query, _resume(function(v) {
|
|
4860
4944
|
if (!open) return;
|
|
4861
4945
|
query = v;
|
|
4862
4946
|
live.query = v;
|
|
4863
4947
|
run(0);
|
|
4864
|
-
}, "u0", $scope0_id))}${_attr_class([findInput, keybar && "
|
|
4948
|
+
}, "u0", $scope0_id))}${_attr_class([findInput, keybar && "_fg"])} type=search enterkeyhint=search autocomplete=off tabindex=${open ? "0" : "-1"} placeholder="Find in terminal" aria-label="Find in terminal">${_el_resume($scope0_id, "c")}<button type=button${_attr_class([findIconBtn, keybar && "_fh"])} title="Previous match"${_attr("disabled", !canStep)} tabindex=${open ? "0" : "-1"}>↑</button>${_el_resume($scope0_id, "d")}<button type=button${_attr_class([findIconBtn, keybar && "_fh"])} title="Next match"${_attr("disabled", !canStep)} tabindex=${open ? "0" : "-1"}>↓</button>${_el_resume($scope0_id, "e")}<button type=button${_attr_class([findIconBtn, keybar && "_fh"])} title="Close find" tabindex=${open ? "0" : "-1"}>×</button>${_el_resume($scope0_id, "f")}</div>${_el_resume($scope0_id, "b", _serialize_guard($scope0_reason, 2))}</div>${_el_resume($scope0_id, "a")}`);
|
|
4865
4949
|
_script($scope0_id, "u4");
|
|
4866
4950
|
_script($scope0_id, "u5");
|
|
4867
4951
|
_script($scope0_id, "u6");
|
|
@@ -5279,7 +5363,7 @@ var work_view_default = _template("y", (input) => {
|
|
|
5279
5363
|
let DiffView = null;
|
|
5280
5364
|
const loadDiffView = _resume(() => {
|
|
5281
5365
|
if (DiffView) return;
|
|
5282
|
-
import("./
|
|
5366
|
+
import("./_DncwyiYL.js").then((m) => {
|
|
5283
5367
|
DiffView = m.default;
|
|
5284
5368
|
});
|
|
5285
5369
|
}, "y4", $scope0_id);
|
|
@@ -6818,7 +6902,7 @@ var postHandler$11 = normalizeHandler(Run.POST({ search: (value) => parse(Query$
|
|
|
6818
6902
|
if (q.session && q.state) {
|
|
6819
6903
|
const payload = await ctx.request.json().catch(() => void 0);
|
|
6820
6904
|
if (q.state === "idle") clearAgentPhase(q.session);
|
|
6821
|
-
else setAgentPhase(q.session, q.state, q.reason, summaryFromHookPayload(payload));
|
|
6905
|
+
else setAgentPhase(q.session, q.state, reasonFromHookPayload(payload, q.reason), summaryFromHookPayload(payload));
|
|
6822
6906
|
return Response.json({ ok: true });
|
|
6823
6907
|
}
|
|
6824
6908
|
const body = parse(AgentState, await ctx.request.json());
|
|
@@ -6832,668 +6916,90 @@ function post2(context) {
|
|
|
6832
6916
|
return call(mware4, __postHandler, context);
|
|
6833
6917
|
}
|
|
6834
6918
|
//#endregion
|
|
6835
|
-
//#region src/server/scrape/engine.ts
|
|
6836
|
-
function detect(manifest, input) {
|
|
6837
|
-
let winner;
|
|
6838
|
-
let winnerText = "";
|
|
6839
|
-
for (const rule of manifest.rules) {
|
|
6840
|
-
if (winner && rule.priority <= winner.priority) continue;
|
|
6841
|
-
const text = region(input, rule.region);
|
|
6842
|
-
if (gateMatches(rule, text, text.toLowerCase())) {
|
|
6843
|
-
winner = rule;
|
|
6844
|
-
winnerText = text;
|
|
6845
|
-
}
|
|
6846
|
-
}
|
|
6847
|
-
if (!winner) return {};
|
|
6848
|
-
if (winner.skip_state_update) return { skip: true };
|
|
6849
|
-
return {
|
|
6850
|
-
state: winner.state === "unknown" ? void 0 : winner.state,
|
|
6851
|
-
blockerText: winner.visible_blocker && winner.region !== "osc_title" ? winnerText : void 0
|
|
6852
|
-
};
|
|
6853
|
-
}
|
|
6854
|
-
function gateMatches(gate, text, lower) {
|
|
6855
|
-
if (gate.contains?.some((n) => !lower.includes(n.toLowerCase()))) return false;
|
|
6856
|
-
if (gate.regex?.some((p) => !compile(p).test(text))) return false;
|
|
6857
|
-
if (gate.line_regex?.some((p) => {
|
|
6858
|
-
const re = compile(p);
|
|
6859
|
-
return !text.split("\n").some((line) => re.test(line));
|
|
6860
|
-
})) return false;
|
|
6861
|
-
if (gate.all?.some((g) => !gateMatches(g, text, lower))) return false;
|
|
6862
|
-
if (gate.any?.length && !gate.any.some((g) => gateMatches(g, text, lower))) return false;
|
|
6863
|
-
if (gate.not?.some((g) => gateMatches(g, text, lower))) return false;
|
|
6864
|
-
return true;
|
|
6865
|
-
}
|
|
6866
|
-
/** Rust-regex → JS: translate \x{..} escapes and leading inline flags.
|
|
6867
|
-
* Compiled patterns are memoized (manifests are static data). */
|
|
6868
|
-
var compiled = /* @__PURE__ */ new Map();
|
|
6869
|
-
function compile(pattern) {
|
|
6870
|
-
let re = compiled.get(pattern);
|
|
6871
|
-
if (!re) {
|
|
6872
|
-
let source = pattern;
|
|
6873
|
-
let flags = "u";
|
|
6874
|
-
const inline = source.match(/^\(\?([ims]+)\)/);
|
|
6875
|
-
if (inline) {
|
|
6876
|
-
flags += inline[1];
|
|
6877
|
-
source = source.slice(inline[0].length);
|
|
6878
|
-
}
|
|
6879
|
-
source = source.replaceAll(/\\x\{([0-9a-fA-F]+)\}/g, "\\u{$1}").replaceAll("\\A", "^");
|
|
6880
|
-
try {
|
|
6881
|
-
re = new RegExp(source, flags);
|
|
6882
|
-
} catch {
|
|
6883
|
-
re = new RegExp(source, flags.replace("u", ""));
|
|
6884
|
-
}
|
|
6885
|
-
compiled.set(pattern, re);
|
|
6886
|
-
}
|
|
6887
|
-
return re;
|
|
6888
|
-
}
|
|
6889
|
-
function region(input, spec) {
|
|
6890
|
-
const trimmed = spec.trim();
|
|
6891
|
-
if (trimmed === "osc_title") return input.oscTitle;
|
|
6892
|
-
if (trimmed === "osc_progress") return "";
|
|
6893
|
-
const content = input.screen;
|
|
6894
|
-
switch (trimmed) {
|
|
6895
|
-
case "whole_recent": return content;
|
|
6896
|
-
case "after_last_prompt_marker": return afterLastPromptMarker(content);
|
|
6897
|
-
case "prompt_box_body": return promptBoxBody(content);
|
|
6898
|
-
case "above_prompt_box": return abovePromptBox(content);
|
|
6899
|
-
case "last_non_empty_above_prompt_box": return lastNonEmptyLine(abovePromptBox(content));
|
|
6900
|
-
case "after_last_horizontal_rule": return afterLastHorizontalRule(content);
|
|
6901
|
-
}
|
|
6902
|
-
const bottom = regionCount(trimmed, "bottom_non_empty_lines");
|
|
6903
|
-
if (bottom !== void 0) return bottomNonEmptyLines(content, bottom);
|
|
6904
|
-
const bottomAll = regionCount(trimmed, "bottom_lines");
|
|
6905
|
-
if (bottomAll !== void 0) return content.split("\n").slice(-bottomAll).join("\n");
|
|
6906
|
-
const top = regionCount(trimmed, "top_non_empty_lines");
|
|
6907
|
-
if (top !== void 0) return topNonEmptyLines(content, top);
|
|
6908
|
-
return "";
|
|
6909
|
-
}
|
|
6910
|
-
function regionCount(spec, name) {
|
|
6911
|
-
const match = spec.match(new RegExp(`^${name}\\((\\d+)\\)$`));
|
|
6912
|
-
return match ? Number(match[1]) : void 0;
|
|
6913
|
-
}
|
|
6914
|
-
function bottomNonEmptyLines(content, count) {
|
|
6915
|
-
const lines = content.split("\n");
|
|
6916
|
-
let seen = 0;
|
|
6917
|
-
for (let i = lines.length - 1; i >= 0; i--) if (lines[i].trim()) {
|
|
6918
|
-
seen++;
|
|
6919
|
-
if (seen === count) return lines.slice(i).join("\n");
|
|
6920
|
-
}
|
|
6921
|
-
return seen ? lines.join("\n") : "";
|
|
6922
|
-
}
|
|
6923
|
-
function topNonEmptyLines(content, count) {
|
|
6924
|
-
const lines = content.split("\n");
|
|
6925
|
-
let seen = 0;
|
|
6926
|
-
for (let i = 0; i < lines.length; i++) if (lines[i].trim()) {
|
|
6927
|
-
seen++;
|
|
6928
|
-
if (seen === count) return lines.slice(0, i + 1).join("\n");
|
|
6929
|
-
}
|
|
6930
|
-
return seen ? lines.join("\n") : "";
|
|
6931
|
-
}
|
|
6932
|
-
/** Codex draws its prompt as a "›" line; content after the last one is the
|
|
6933
|
-
* live tail of the turn. */
|
|
6934
|
-
function afterLastPromptMarker(content) {
|
|
6935
|
-
const lines = content.split("\n");
|
|
6936
|
-
for (let i = lines.length - 1; i >= 0; i--) if (lines[i] === "›" || lines[i].startsWith("› ")) return lines.slice(i + 1).join("\n");
|
|
6937
|
-
return content;
|
|
6938
|
-
}
|
|
6939
|
-
function isHorizontalRule(line) {
|
|
6940
|
-
const trimmed = line.trim();
|
|
6941
|
-
if (!trimmed) return false;
|
|
6942
|
-
let rule = 0;
|
|
6943
|
-
for (const ch of trimmed) if (ch === "─") rule++;
|
|
6944
|
-
else break;
|
|
6945
|
-
if (!rule) return false;
|
|
6946
|
-
return !trimmed.slice(rule).trimStart() || rule >= 3;
|
|
6947
|
-
}
|
|
6948
|
-
function afterLastHorizontalRule(content) {
|
|
6949
|
-
const lines = content.split("\n");
|
|
6950
|
-
for (let i = lines.length - 1; i >= 0; i--) if (isHorizontalRule(lines[i])) return lines.slice(i + 1).join("\n");
|
|
6951
|
-
return content;
|
|
6952
|
-
}
|
|
6953
|
-
/** The prompt box's inner text: between the last two horizontal rules
|
|
6954
|
-
* (its borders), scanning bottom-up. */
|
|
6955
|
-
function promptBoxTopBorderIndex(lines) {
|
|
6956
|
-
let borders = 0;
|
|
6957
|
-
for (let i = lines.length - 1; i >= 0; i--) if (isHorizontalRule(lines[i])) {
|
|
6958
|
-
borders++;
|
|
6959
|
-
if (borders === 2) return i;
|
|
6960
|
-
}
|
|
6961
|
-
}
|
|
6962
|
-
function promptBoxBody(content) {
|
|
6963
|
-
const lines = content.split("\n");
|
|
6964
|
-
const top = promptBoxTopBorderIndex(lines);
|
|
6965
|
-
if (top === void 0) return "";
|
|
6966
|
-
let end = lines.length;
|
|
6967
|
-
for (let i = top + 1; i < lines.length; i++) if (isHorizontalRule(lines[i])) {
|
|
6968
|
-
end = i;
|
|
6969
|
-
break;
|
|
6970
|
-
}
|
|
6971
|
-
return lines.slice(top + 1, end).join("\n");
|
|
6972
|
-
}
|
|
6973
|
-
function abovePromptBox(content) {
|
|
6974
|
-
const lines = content.split("\n");
|
|
6975
|
-
const top = promptBoxTopBorderIndex(lines);
|
|
6976
|
-
return top === void 0 ? content : lines.slice(0, top).join("\n");
|
|
6977
|
-
}
|
|
6978
|
-
function lastNonEmptyLine(content) {
|
|
6979
|
-
const lines = content.split("\n");
|
|
6980
|
-
for (let i = lines.length - 1; i >= 0; i--) if (lines[i].trim()) return lines[i];
|
|
6981
|
-
return "";
|
|
6982
|
-
}
|
|
6983
|
-
/** Session agent kind → manifest ("shell" has none). */
|
|
6984
|
-
var MANIFESTS = {
|
|
6985
|
-
claude: {
|
|
6986
|
-
id: "claude",
|
|
6987
|
-
rules: [
|
|
6988
|
-
{
|
|
6989
|
-
id: "osc_title_working",
|
|
6990
|
-
state: "working",
|
|
6991
|
-
priority: 1100,
|
|
6992
|
-
region: "osc_title",
|
|
6993
|
-
regex: ["^[\\x{2800}-\\x{28FF}] "]
|
|
6994
|
-
},
|
|
6995
|
-
{
|
|
6996
|
-
id: "btw_overlay_working",
|
|
6997
|
-
state: "working",
|
|
6998
|
-
priority: 975,
|
|
6999
|
-
region: "bottom_non_empty_lines(5)",
|
|
7000
|
-
line_regex: ["^\\s*/btw(?:\\s|$)", "(?i)esc to close\\s*$"]
|
|
7001
|
-
},
|
|
7002
|
-
{
|
|
7003
|
-
id: "transcript_viewer",
|
|
7004
|
-
state: "unknown",
|
|
7005
|
-
priority: 1e3,
|
|
7006
|
-
region: "bottom_non_empty_lines(3)",
|
|
7007
|
-
skip_state_update: true,
|
|
7008
|
-
contains: ["showing detailed transcript"],
|
|
7009
|
-
any: [
|
|
7010
|
-
{ contains: ["ctrl+o", "to toggle"] },
|
|
7011
|
-
{ contains: ["ctrl+e", "show all"] },
|
|
7012
|
-
{ contains: ["ctrl+e", "collapse"] },
|
|
7013
|
-
{ contains: ["↑↓ scroll"] },
|
|
7014
|
-
{ contains: ["? for shortcuts"] }
|
|
7015
|
-
]
|
|
7016
|
-
},
|
|
7017
|
-
{
|
|
7018
|
-
id: "live_blocked_form",
|
|
7019
|
-
state: "blocked",
|
|
7020
|
-
priority: 980,
|
|
7021
|
-
region: "after_last_horizontal_rule",
|
|
7022
|
-
visible_blocker: true,
|
|
7023
|
-
contains: ["esc to cancel"],
|
|
7024
|
-
any: [{ contains: ["enter to confirm"] }, {
|
|
7025
|
-
contains: ["enter to select"],
|
|
7026
|
-
any: [
|
|
7027
|
-
{ contains: ["tab/arrow keys to navigate"] },
|
|
7028
|
-
{ contains: ["arrow keys to navigate"] },
|
|
7029
|
-
{ contains: ["arrows to navigate"] },
|
|
7030
|
-
{ contains: ["↑/↓ to navigate"] },
|
|
7031
|
-
{ contains: ["↑↓ to navigate"] }
|
|
7032
|
-
]
|
|
7033
|
-
}]
|
|
7034
|
-
},
|
|
7035
|
-
{
|
|
7036
|
-
id: "dynamic_workflow_prompt",
|
|
7037
|
-
state: "blocked",
|
|
7038
|
-
priority: 980,
|
|
7039
|
-
region: "whole_recent",
|
|
7040
|
-
visible_blocker: true,
|
|
7041
|
-
contains: ["run a dynamic workflow?", "esc to cancel"]
|
|
7042
|
-
},
|
|
7043
|
-
{
|
|
7044
|
-
id: "live_prompt_box",
|
|
7045
|
-
state: "idle",
|
|
7046
|
-
priority: 950,
|
|
7047
|
-
region: "prompt_box_body",
|
|
7048
|
-
line_regex: ["^\\s*❯"],
|
|
7049
|
-
not: [
|
|
7050
|
-
{ contains: ["enter to select"] },
|
|
7051
|
-
{ contains: ["esc to cancel"] },
|
|
7052
|
-
{ contains: ["tab/arrow keys"] },
|
|
7053
|
-
{ contains: ["arrow keys to navigate"] },
|
|
7054
|
-
{ contains: ["↑/↓ to navigate"] }
|
|
7055
|
-
]
|
|
7056
|
-
},
|
|
7057
|
-
{
|
|
7058
|
-
id: "model_picker_menu",
|
|
7059
|
-
state: "unknown",
|
|
7060
|
-
priority: 900,
|
|
7061
|
-
region: "whole_recent",
|
|
7062
|
-
skip_state_update: true,
|
|
7063
|
-
contains: [
|
|
7064
|
-
"select model",
|
|
7065
|
-
"enter to set as default",
|
|
7066
|
-
"esc to cancel"
|
|
7067
|
-
],
|
|
7068
|
-
not: [{ contains: ["do you want to proceed?"] }, { contains: ["enter to select"] }]
|
|
7069
|
-
},
|
|
7070
|
-
{
|
|
7071
|
-
id: "bash_permission_prompt",
|
|
7072
|
-
state: "blocked",
|
|
7073
|
-
priority: 850,
|
|
7074
|
-
region: "whole_recent",
|
|
7075
|
-
visible_blocker: true,
|
|
7076
|
-
contains: ["do you want to proceed?"],
|
|
7077
|
-
any: [
|
|
7078
|
-
{ contains: ["bash command"] },
|
|
7079
|
-
{ contains: ["bash("] },
|
|
7080
|
-
{ contains: ["contains expansion"] },
|
|
7081
|
-
{ contains: ["tab to amend"] },
|
|
7082
|
-
{ contains: ["ctrl+e to explain"] }
|
|
7083
|
-
],
|
|
7084
|
-
all: [{ any: [
|
|
7085
|
-
{ line_regex: ["(?i)^\\s*❯?\\s*yes\\b"] },
|
|
7086
|
-
{ line_regex: ["(?i)^\\s*1\\.\\s*yes\\b"] },
|
|
7087
|
-
{ line_regex: ["(?i)^\\s*2\\.\\s*no\\b"] }
|
|
7088
|
-
] }]
|
|
7089
|
-
},
|
|
7090
|
-
{
|
|
7091
|
-
id: "generic_permission_prompt",
|
|
7092
|
-
state: "blocked",
|
|
7093
|
-
priority: 840,
|
|
7094
|
-
region: "after_last_horizontal_rule",
|
|
7095
|
-
visible_blocker: true,
|
|
7096
|
-
contains: ["do you want to proceed?", "esc to cancel"],
|
|
7097
|
-
all: [{ any: [
|
|
7098
|
-
{ line_regex: ["(?i)^\\s*❯?\\s*1\\.\\s*yes\\b"] },
|
|
7099
|
-
{ line_regex: ["(?i)^\\s*2\\.\\s*yes\\b"] },
|
|
7100
|
-
{ line_regex: ["(?i)^\\s*2\\.\\s*no\\b"] },
|
|
7101
|
-
{ line_regex: ["(?i)^\\s*3\\.\\s*no\\b"] }
|
|
7102
|
-
] }]
|
|
7103
|
-
},
|
|
7104
|
-
{
|
|
7105
|
-
id: "legacy_no_prompt_blocker",
|
|
7106
|
-
state: "blocked",
|
|
7107
|
-
priority: 300,
|
|
7108
|
-
region: "whole_recent",
|
|
7109
|
-
any: [
|
|
7110
|
-
{
|
|
7111
|
-
contains: ["do you want to"],
|
|
7112
|
-
any: [{ contains: ["yes"] }, { contains: ["❯"] }]
|
|
7113
|
-
},
|
|
7114
|
-
{
|
|
7115
|
-
contains: ["would you like to"],
|
|
7116
|
-
any: [{ contains: ["yes"] }, { contains: ["❯"] }]
|
|
7117
|
-
},
|
|
7118
|
-
{ contains: ["waiting for permission"] },
|
|
7119
|
-
{ contains: ["do you want to allow this connection?"] },
|
|
7120
|
-
{ contains: ["tab to amend"] },
|
|
7121
|
-
{ contains: ["ctrl+e to explain"] },
|
|
7122
|
-
{ contains: ["do you want to proceed?", "esc to cancel"] },
|
|
7123
|
-
{ contains: ["review your answers"] },
|
|
7124
|
-
{ contains: ["skip interview and plan immediately"] }
|
|
7125
|
-
],
|
|
7126
|
-
not: [{ regex: ["(?m)^\\s*❯\\s*$"] }]
|
|
7127
|
-
},
|
|
7128
|
-
{
|
|
7129
|
-
id: "osc_title_idle",
|
|
7130
|
-
state: "idle",
|
|
7131
|
-
priority: 250,
|
|
7132
|
-
region: "osc_title",
|
|
7133
|
-
regex: ["^\\x{2733} "]
|
|
7134
|
-
},
|
|
7135
|
-
{
|
|
7136
|
-
id: "osc_progress_idle",
|
|
7137
|
-
state: "idle",
|
|
7138
|
-
priority: 250,
|
|
7139
|
-
region: "osc_progress",
|
|
7140
|
-
regex: ["^4;0"]
|
|
7141
|
-
}
|
|
7142
|
-
]
|
|
7143
|
-
},
|
|
7144
|
-
codex: {
|
|
7145
|
-
id: "codex",
|
|
7146
|
-
rules: [
|
|
7147
|
-
{
|
|
7148
|
-
id: "osc_title_blocked",
|
|
7149
|
-
state: "blocked",
|
|
7150
|
-
priority: 1100,
|
|
7151
|
-
region: "osc_title",
|
|
7152
|
-
visible_blocker: true,
|
|
7153
|
-
contains: ["Action Required"]
|
|
7154
|
-
},
|
|
7155
|
-
{
|
|
7156
|
-
id: "osc_title_working",
|
|
7157
|
-
state: "working",
|
|
7158
|
-
priority: 1050,
|
|
7159
|
-
region: "osc_title",
|
|
7160
|
-
regex: ["(?:^| )[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏](?: |$)"]
|
|
7161
|
-
},
|
|
7162
|
-
{
|
|
7163
|
-
id: "transcript_viewer",
|
|
7164
|
-
state: "unknown",
|
|
7165
|
-
priority: 1e3,
|
|
7166
|
-
region: "after_last_prompt_marker",
|
|
7167
|
-
skip_state_update: true,
|
|
7168
|
-
contains: [
|
|
7169
|
-
"↑/↓ to scroll",
|
|
7170
|
-
"pgup/pgdn to",
|
|
7171
|
-
"home/end to jump",
|
|
7172
|
-
"q to quit"
|
|
7173
|
-
],
|
|
7174
|
-
any: [{ contains: ["esc to edit prev"] }, { contains: ["esc/← to edit prev"] }]
|
|
7175
|
-
},
|
|
7176
|
-
{
|
|
7177
|
-
id: "trust_directory",
|
|
7178
|
-
state: "blocked",
|
|
7179
|
-
priority: 950,
|
|
7180
|
-
region: "top_non_empty_lines(20)",
|
|
7181
|
-
visible_blocker: true,
|
|
7182
|
-
all: [{ regex: ["^> You are in [^\\r\\n]+(?:\\r?\\n|$)"] }, { regex: ["(?s)Do\\s+you\\s+trust\\s+the\\s+contents\\s+of\\s+this\\s+directory\\?"] }]
|
|
7183
|
-
},
|
|
7184
|
-
{
|
|
7185
|
-
id: "live_strong_blocker",
|
|
7186
|
-
state: "blocked",
|
|
7187
|
-
priority: 900,
|
|
7188
|
-
region: "after_last_prompt_marker",
|
|
7189
|
-
visible_blocker: true,
|
|
7190
|
-
any: [
|
|
7191
|
-
{ contains: ["press enter to confirm or esc to cancel"] },
|
|
7192
|
-
{ contains: ["enter to submit answer"] },
|
|
7193
|
-
{ contains: ["enter to submit all"] },
|
|
7194
|
-
{ contains: ["allow command?"] }
|
|
7195
|
-
]
|
|
7196
|
-
},
|
|
7197
|
-
{
|
|
7198
|
-
id: "weak_blocker",
|
|
7199
|
-
state: "blocked",
|
|
7200
|
-
priority: 600,
|
|
7201
|
-
region: "whole_recent",
|
|
7202
|
-
any: [
|
|
7203
|
-
{ contains: ["[y/n]"] },
|
|
7204
|
-
{ contains: ["yes (y)"] },
|
|
7205
|
-
{
|
|
7206
|
-
contains: ["do you want to"],
|
|
7207
|
-
any: [{ contains: ["yes"] }, { contains: ["❯"] }]
|
|
7208
|
-
},
|
|
7209
|
-
{
|
|
7210
|
-
contains: ["would you like to"],
|
|
7211
|
-
any: [{ contains: ["yes"] }, { contains: ["❯"] }]
|
|
7212
|
-
}
|
|
7213
|
-
]
|
|
7214
|
-
},
|
|
7215
|
-
{
|
|
7216
|
-
id: "screen_working_fallback",
|
|
7217
|
-
state: "working",
|
|
7218
|
-
priority: 500,
|
|
7219
|
-
region: "bottom_non_empty_lines(3)",
|
|
7220
|
-
line_regex: ["^[•◦]\\s+Working \\([^)]*esc to interrupt\\)(?: · .*)?$"],
|
|
7221
|
-
not: [{ contains: ["■ Conversation interrupted"] }]
|
|
7222
|
-
},
|
|
7223
|
-
{
|
|
7224
|
-
id: "osc_title_idle",
|
|
7225
|
-
state: "idle",
|
|
7226
|
-
priority: 100,
|
|
7227
|
-
region: "osc_title",
|
|
7228
|
-
regex: ["\\S"],
|
|
7229
|
-
not: [{ regex: ["(?:^| )[⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏](?: |$)"] }, { contains: ["Action Required"] }]
|
|
7230
|
-
}
|
|
7231
|
-
]
|
|
7232
|
-
},
|
|
7233
|
-
cursor: {
|
|
7234
|
-
id: "cursor",
|
|
7235
|
-
rules: [
|
|
7236
|
-
{
|
|
7237
|
-
id: "write_file_approval",
|
|
7238
|
-
state: "blocked",
|
|
7239
|
-
priority: 320,
|
|
7240
|
-
region: "bottom_non_empty_lines(8)",
|
|
7241
|
-
visible_blocker: true,
|
|
7242
|
-
contains: ["write to this file?", "proceed (y)"],
|
|
7243
|
-
any: [
|
|
7244
|
-
{ contains: ["reject & propose changes"] },
|
|
7245
|
-
{ contains: ["esc or n or p"] },
|
|
7246
|
-
{ contains: ["add write("] }
|
|
7247
|
-
]
|
|
7248
|
-
},
|
|
7249
|
-
{
|
|
7250
|
-
id: "approval_prompt",
|
|
7251
|
-
state: "blocked",
|
|
7252
|
-
priority: 300,
|
|
7253
|
-
region: "whole_recent",
|
|
7254
|
-
visible_blocker: true,
|
|
7255
|
-
any: [
|
|
7256
|
-
{
|
|
7257
|
-
contains: ["waiting for approval", "run this command?"],
|
|
7258
|
-
any: [{ contains: ["run (once) (y)"] }, { contains: ["skip (esc or n)"] }]
|
|
7259
|
-
},
|
|
7260
|
-
{ contains: ["(y) (enter)"] },
|
|
7261
|
-
{ line_regex: ["(?i)^\\s*allow .*\\(y\\)"] },
|
|
7262
|
-
{ contains: ["keep (n)"] },
|
|
7263
|
-
{ contains: ["skip (esc or n)"] },
|
|
7264
|
-
{ line_regex: ["(?i)^\\s*(?:→\\s*)?run .*\\(y\\)"] }
|
|
7265
|
-
]
|
|
7266
|
-
},
|
|
7267
|
-
{
|
|
7268
|
-
id: "stop_hint_working",
|
|
7269
|
-
state: "working",
|
|
7270
|
-
priority: 100,
|
|
7271
|
-
region: "bottom_non_empty_lines(6)",
|
|
7272
|
-
contains: ["ctrl+c to stop"]
|
|
7273
|
-
},
|
|
7274
|
-
{
|
|
7275
|
-
id: "background_task_status_working",
|
|
7276
|
-
state: "working",
|
|
7277
|
-
priority: 95,
|
|
7278
|
-
region: "bottom_non_empty_lines(5)",
|
|
7279
|
-
line_regex: ["(?i)\\b[1-9][0-9]*\\s+background\\s+tasks?\\b"]
|
|
7280
|
-
},
|
|
7281
|
-
{
|
|
7282
|
-
id: "spinner_working",
|
|
7283
|
-
state: "working",
|
|
7284
|
-
priority: 90,
|
|
7285
|
-
region: "bottom_non_empty_lines(8)",
|
|
7286
|
-
line_regex: ["^\\s*(⬡|⬢|[\\x{2800}-\\x{28FF}]+)\\s+\\p{Alphabetic}+\\w*ing\\b"]
|
|
7287
|
-
}
|
|
7288
|
-
]
|
|
7289
|
-
},
|
|
7290
|
-
grok: {
|
|
7291
|
-
id: "grok",
|
|
7292
|
-
rules: [
|
|
7293
|
-
{
|
|
7294
|
-
id: "osc_title_blocked",
|
|
7295
|
-
state: "blocked",
|
|
7296
|
-
priority: 1300,
|
|
7297
|
-
region: "osc_title",
|
|
7298
|
-
visible_blocker: true,
|
|
7299
|
-
contains: ["Action Required"]
|
|
7300
|
-
},
|
|
7301
|
-
{
|
|
7302
|
-
id: "option_dialog_blocked",
|
|
7303
|
-
state: "blocked",
|
|
7304
|
-
priority: 1200,
|
|
7305
|
-
region: "whole_recent",
|
|
7306
|
-
visible_blocker: true,
|
|
7307
|
-
line_regex: ["^\\s*┃\\s+[0-9a-z]+\\s+\\([●○]\\)\\s"]
|
|
7308
|
-
},
|
|
7309
|
-
{
|
|
7310
|
-
id: "permission_hints_blocked",
|
|
7311
|
-
state: "blocked",
|
|
7312
|
-
priority: 1190,
|
|
7313
|
-
region: "bottom_non_empty_lines(2)",
|
|
7314
|
-
visible_blocker: true,
|
|
7315
|
-
contains: [
|
|
7316
|
-
":select",
|
|
7317
|
-
"ctrl+o:yolo",
|
|
7318
|
-
"ctrl+c:cancel"
|
|
7319
|
-
]
|
|
7320
|
-
},
|
|
7321
|
-
{
|
|
7322
|
-
id: "question_dialog_hints_blocked",
|
|
7323
|
-
state: "blocked",
|
|
7324
|
-
priority: 1185,
|
|
7325
|
-
region: "bottom_non_empty_lines(2)",
|
|
7326
|
-
visible_blocker: true,
|
|
7327
|
-
contains: ["tab:scrollback", "shift+x:dismiss"]
|
|
7328
|
-
},
|
|
7329
|
-
{
|
|
7330
|
-
id: "permission_scope_selector",
|
|
7331
|
-
state: "blocked",
|
|
7332
|
-
priority: 1180,
|
|
7333
|
-
region: "whole_recent",
|
|
7334
|
-
visible_blocker: true,
|
|
7335
|
-
contains: ["yes, proceed", "no, reject"],
|
|
7336
|
-
any: [{ contains: ["use ← → to choose permission whitelist scope"] }, { contains: ["←/→:scope"] }]
|
|
7337
|
-
},
|
|
7338
|
-
{
|
|
7339
|
-
id: "background_work_chip_working",
|
|
7340
|
-
state: "working",
|
|
7341
|
-
priority: 1170,
|
|
7342
|
-
region: "top_non_empty_lines(1)",
|
|
7343
|
-
line_regex: ["[⋅:⸬⁙.·]\\s+[1-9][0-9]*\\s+│"]
|
|
7344
|
-
},
|
|
7345
|
-
{
|
|
7346
|
-
id: "osc_progress_working",
|
|
7347
|
-
state: "working",
|
|
7348
|
-
priority: 1150,
|
|
7349
|
-
region: "osc_progress",
|
|
7350
|
-
regex: ["^4;1;-1$"]
|
|
7351
|
-
},
|
|
7352
|
-
{
|
|
7353
|
-
id: "osc_title_idle",
|
|
7354
|
-
state: "idle",
|
|
7355
|
-
priority: 1100,
|
|
7356
|
-
region: "osc_title",
|
|
7357
|
-
regex: ["(?:^| - )grok$"],
|
|
7358
|
-
not: [{ regex: ["[\\x{2800}-\\x{28FF}]"] }]
|
|
7359
|
-
},
|
|
7360
|
-
{
|
|
7361
|
-
id: "osc_title_working",
|
|
7362
|
-
state: "working",
|
|
7363
|
-
priority: 1e3,
|
|
7364
|
-
region: "osc_title",
|
|
7365
|
-
regex: ["\\S"]
|
|
7366
|
-
},
|
|
7367
|
-
{
|
|
7368
|
-
id: "osc_progress_idle",
|
|
7369
|
-
state: "idle",
|
|
7370
|
-
priority: 950,
|
|
7371
|
-
region: "osc_progress",
|
|
7372
|
-
regex: ["^4;0;0$"]
|
|
7373
|
-
},
|
|
7374
|
-
{
|
|
7375
|
-
id: "spinner_status_working",
|
|
7376
|
-
state: "working",
|
|
7377
|
-
priority: 200,
|
|
7378
|
-
region: "whole_recent",
|
|
7379
|
-
line_regex: ["^\\s*[\\x{2801}-\\x{28FF}]\\s.*\\[stop\\]\\s*$"]
|
|
7380
|
-
},
|
|
7381
|
-
{
|
|
7382
|
-
id: "esc_cancel_hints_working",
|
|
7383
|
-
state: "working",
|
|
7384
|
-
priority: 190,
|
|
7385
|
-
region: "bottom_non_empty_lines(2)",
|
|
7386
|
-
contains: ["esc:cancel", "ctrl+.:shortcuts"]
|
|
7387
|
-
},
|
|
7388
|
-
{
|
|
7389
|
-
id: "waiting_tool_working",
|
|
7390
|
-
state: "working",
|
|
7391
|
-
priority: 120,
|
|
7392
|
-
region: "whole_recent",
|
|
7393
|
-
any: [{ all: [{ contains: ["ctrl+c:cancel", "ctrl+enter:interject"] }, { contains: ["waiting"] }] }, { line_regex: ["^\\s*[\\x{2801}-\\x{28FF}]\\s+(Run|Read|Search|List)\\b"] }]
|
|
7394
|
-
},
|
|
7395
|
-
{
|
|
7396
|
-
id: "prompt_hints_idle",
|
|
7397
|
-
state: "idle",
|
|
7398
|
-
priority: 100,
|
|
7399
|
-
region: "bottom_non_empty_lines(2)",
|
|
7400
|
-
contains: ["ctrl+.:shortcuts"],
|
|
7401
|
-
not: [{ contains: ["esc:cancel"] }, { contains: ["ctrl+c:cancel"] }]
|
|
7402
|
-
}
|
|
7403
|
-
]
|
|
7404
|
-
},
|
|
7405
|
-
copilot: {
|
|
7406
|
-
id: "copilot",
|
|
7407
|
-
rules: [{
|
|
7408
|
-
id: "selection_blocker",
|
|
7409
|
-
state: "blocked",
|
|
7410
|
-
priority: 300,
|
|
7411
|
-
region: "whole_recent",
|
|
7412
|
-
visible_blocker: true,
|
|
7413
|
-
all: [{ any: [{ contains: ["esc to cancel"] }, { contains: ["esc cancel"] }] }, { any: [
|
|
7414
|
-
{ contains: ["enter to select"] },
|
|
7415
|
-
{ contains: ["enter to confirm"] },
|
|
7416
|
-
{ contains: ["enter to submit"] },
|
|
7417
|
-
{ contains: ["enter accept"] }
|
|
7418
|
-
] }]
|
|
7419
|
-
}, {
|
|
7420
|
-
id: "working_cancel_hint",
|
|
7421
|
-
state: "working",
|
|
7422
|
-
priority: 100,
|
|
7423
|
-
region: "whole_recent",
|
|
7424
|
-
any: [
|
|
7425
|
-
{ contains: ["esc to cancel"] },
|
|
7426
|
-
{ contains: ["esc cancel"] },
|
|
7427
|
-
{ contains: ["esc again to cancel"] },
|
|
7428
|
-
{ contains: ["esc interrupt"] }
|
|
7429
|
-
]
|
|
7430
|
-
}]
|
|
7431
|
-
}
|
|
7432
|
-
};
|
|
7433
|
-
//#endregion
|
|
7434
6919
|
//#region src/server/scraper.ts
|
|
7435
|
-
/**
|
|
7436
|
-
*
|
|
7437
|
-
*
|
|
7438
|
-
* the
|
|
7439
|
-
*
|
|
7440
|
-
*
|
|
6920
|
+
/** Whether an agent session is doing anything, from tmux alone.
|
|
6921
|
+
*
|
|
6922
|
+
* tmux stamps every pane with the time it last produced output, and that
|
|
6923
|
+
* is the whole signal here: a pane that is writing is a turn in progress,
|
|
6924
|
+
* one that has gone quiet is a turn that ended. Nothing reads what is on
|
|
6925
|
+
* the screen.
|
|
6926
|
+
*
|
|
6927
|
+
* Only agents that cannot say it themselves are watched. An agent whose
|
|
6928
|
+
* hooks report both starting and stopping is left alone entirely — asking
|
|
6929
|
+
* two sources about one fact means arbitrating them when they disagree,
|
|
6930
|
+
* and the screen always disagrees last, because it is still painting the
|
|
6931
|
+
* reply after the hook has said the turn is over.
|
|
6932
|
+
*
|
|
6933
|
+
* What is given up: a CLI with no hooks looks the same stopped on a
|
|
6934
|
+
* question as it does finished, since a pane waiting for an answer is
|
|
6935
|
+
* silent either way. What is gained: one `list-panes` a tick whatever the
|
|
6936
|
+
* session count, and no rules to keep matching five CLIs that redecorate
|
|
6937
|
+
* whenever they like. */
|
|
7441
6938
|
var POLL_MS = 2e3;
|
|
7442
|
-
/**
|
|
7443
|
-
* tick instead of waking every 2s forever. */
|
|
6939
|
+
/** Nothing to watch — idle at a slow tick instead of waking every 2s. */
|
|
7444
6940
|
var IDLE_POLL_MS = 15e3;
|
|
6941
|
+
/** Quiet for this long is a stopped turn. Comfortably above one poll, so a
|
|
6942
|
+
* pane that writes in bursts is not called idle between them, and above
|
|
6943
|
+
* tmux's one-second stamp resolution. */
|
|
6944
|
+
var IDLE_AFTER_MS = 4e3;
|
|
6945
|
+
/** Opening a session sizes the tmux window to the browser, and an agent
|
|
6946
|
+
* TUI repaints itself on the resize. That repaint moves the stamp exactly
|
|
6947
|
+
* as output would, so a session reads busy the moment you look at it.
|
|
6948
|
+
*
|
|
6949
|
+
* What separates them is *when*: the repaint carries the second the attach
|
|
6950
|
+
* happened, while anything the agent goes on to write carries a later one.
|
|
6951
|
+
* So the attach is recorded, and for a short while after it a stamp from
|
|
6952
|
+
* that same second is not treated as output — but a later one still is, so
|
|
6953
|
+
* a session you open and immediately give work to still lights up. */
|
|
6954
|
+
var ATTACH_SETTLE_MS = 8e3;
|
|
6955
|
+
/** tmux stamps whole seconds, so the repaint can land in the second after
|
|
6956
|
+
* the attach as easily as the one it happened in. */
|
|
6957
|
+
var ATTACH_GRACE_MS = 1500;
|
|
6958
|
+
var attachedAt = /* @__PURE__ */ new Map();
|
|
6959
|
+
function noteViewerAttached(sessionId) {
|
|
6960
|
+
attachedAt.set(sessionId, Date.now());
|
|
6961
|
+
}
|
|
7445
6962
|
function startScraper() {
|
|
7446
6963
|
if (started) return;
|
|
7447
6964
|
started = true;
|
|
7448
6965
|
const tick = async () => {
|
|
7449
|
-
const
|
|
7450
|
-
setTimeout(tick,
|
|
6966
|
+
const watching = await scan().catch(() => false);
|
|
6967
|
+
setTimeout(tick, watching ? POLL_MS : IDLE_POLL_MS).unref?.();
|
|
7451
6968
|
};
|
|
7452
6969
|
tick();
|
|
7453
6970
|
}
|
|
7454
6971
|
var started = false;
|
|
7455
|
-
/** Returns whether there was anything to
|
|
6972
|
+
/** Returns whether there was anything to watch (drives the poll cadence). */
|
|
7456
6973
|
async function scan() {
|
|
7457
|
-
const sessions = all("SELECT id, agent FROM sessions").filter((session) => session.agent
|
|
6974
|
+
const sessions = all("SELECT id, agent FROM sessions").filter((session) => session.agent !== "shell" && !reportsWorking(session.agent));
|
|
7458
6975
|
if (!sessions.length) return false;
|
|
7459
|
-
const panes = /* @__PURE__ */ new Map();
|
|
7460
6976
|
const out = await tmux([
|
|
7461
6977
|
"list-panes",
|
|
7462
6978
|
"-a",
|
|
7463
6979
|
"-F",
|
|
7464
|
-
"#{session_name} #{
|
|
6980
|
+
"#{session_name} #{window_activity}"
|
|
7465
6981
|
]).catch(() => null);
|
|
7466
6982
|
if (out === null) return false;
|
|
6983
|
+
const wroteAt = /* @__PURE__ */ new Map();
|
|
7467
6984
|
for (const line of out.split("\n")) {
|
|
7468
|
-
const [name,
|
|
7469
|
-
if (name?.startsWith("wk-"))
|
|
6985
|
+
const [name, stamp] = line.split(" ");
|
|
6986
|
+
if (name?.startsWith("wk-")) wroteAt.set(name.slice(3), Number(stamp) * 1e3);
|
|
7470
6987
|
}
|
|
6988
|
+
const now = Date.now();
|
|
6989
|
+
let live = 0;
|
|
7471
6990
|
for (const session of sessions) {
|
|
7472
|
-
|
|
7473
|
-
|
|
6991
|
+
const wrote = wroteAt.get(session.id);
|
|
6992
|
+
if (wrote === void 0) {
|
|
6993
|
+
clearAgentPhase(session.id);
|
|
6994
|
+
attachedAt.delete(session.id);
|
|
6995
|
+
continue;
|
|
6996
|
+
}
|
|
6997
|
+
live++;
|
|
6998
|
+
const attached = attachedAt.get(session.id);
|
|
6999
|
+
const busy = !(attached !== void 0 && now - attached < ATTACH_SETTLE_MS && wrote <= attached + ATTACH_GRACE_MS) && Number.isFinite(wrote) && now - wrote < IDLE_AFTER_MS;
|
|
7000
|
+
setScrapedPhase(session.id, busy ? "working" : void 0);
|
|
7474
7001
|
}
|
|
7475
|
-
|
|
7476
|
-
await Promise.all(live.map(async (session) => {
|
|
7477
|
-
const screen = await tmux([
|
|
7478
|
-
"capture-pane",
|
|
7479
|
-
"-p",
|
|
7480
|
-
"-J",
|
|
7481
|
-
"-t",
|
|
7482
|
-
`wk-${session.id}`
|
|
7483
|
-
]).catch(() => "");
|
|
7484
|
-
const result = detect(MANIFESTS[session.agent], {
|
|
7485
|
-
screen,
|
|
7486
|
-
oscTitle: panes.get(session.id)
|
|
7487
|
-
});
|
|
7488
|
-
if (result.skip) return;
|
|
7489
|
-
setScrapedPhase(session.id, result.state === "working" ? "working" : result.state === "blocked" ? "waiting" : void 0, result.blockerText && blockerSummary(result.blockerText));
|
|
7490
|
-
}));
|
|
7491
|
-
return live.length > 0;
|
|
7492
|
-
}
|
|
7493
|
-
/** Human-readable line(s) from a blocker region: the question the agent is
|
|
7494
|
-
* asking, with box borders, option lists, and hint bars stripped. */
|
|
7495
|
-
function blockerSummary(region) {
|
|
7496
|
-
return region.split("\n").map((line) => line.replace(/^[│┃⎿└├]\s*/, "").replace(/\s*[│┃]$/, "").trim()).filter((line) => line && !/^[╭╰│─━┃❯>✳·. ]+$/.test(line) && !/^❯?\s*\d+\.\s/.test(line) && !/^[0-9a-z]+\s+\([●○]\)\s/.test(line) && !/(ctrl\+|esc to|esc or|esc:|:select|shift\+|\(y\)|\(n\)|y\/n|arrow keys|↑|↓|tab to|enter to)/i.test(line)).slice(0, 2).join(" — ").slice(0, 180) || void 0;
|
|
7002
|
+
return live > 0;
|
|
7497
7003
|
}
|
|
7498
7004
|
//#endregion
|
|
7499
7005
|
//#region src/server/boot.ts
|
|
@@ -7640,7 +7146,11 @@ var Query = /* @__PURE__ */ object({
|
|
|
7640
7146
|
var postHandler$8 = normalizeHandler(Run.POST({ search: (value) => parse(Query, value) }, async (ctx) => {
|
|
7641
7147
|
if (ctx.search.token !== hookToken()) return Response.json({ error: "bad token" }, { status: 403 });
|
|
7642
7148
|
notePushActivity();
|
|
7643
|
-
|
|
7149
|
+
const targets = activeRepoTargets().filter((t) => t.fullName === ctx.search.repo);
|
|
7150
|
+
await refreshPrsBatch(targets.length ? targets : [{
|
|
7151
|
+
fullName: ctx.search.repo,
|
|
7152
|
+
branch: ""
|
|
7153
|
+
}], true).catch(() => {});
|
|
7644
7154
|
pokeStatusWatch();
|
|
7645
7155
|
return Response.json({ ok: true });
|
|
7646
7156
|
}), "POST");
|
|
@@ -8827,7 +8337,7 @@ async function workspaceDiff(ws, opts = {}) {
|
|
|
8827
8337
|
"--abbrev-ref",
|
|
8828
8338
|
"HEAD"
|
|
8829
8339
|
], dir).catch(() => "HEAD");
|
|
8830
|
-
const localHead = await
|
|
8340
|
+
const localHead = await headOid(dir);
|
|
8831
8341
|
const open = (await workspacePrs(repo.full_name, ws.branch, foreign, refresh)).filter((p) => p.state === "OPEN" && p.baseRefName && p.headRefName && (!focus || focus === `${repo.worktree}/${p.number}`));
|
|
8832
8342
|
if (open.length) return Promise.all(open.map((p) => prDiff(dir, repo, p, {
|
|
8833
8343
|
uncommitted: uncommitted && branch === p.headRefName,
|
|
@@ -9158,11 +8668,31 @@ var Dismiss = /* @__PURE__ */ object({
|
|
|
9158
8668
|
number: /* @__PURE__ */ pipe(/* @__PURE__ */ number(), /* @__PURE__ */ integer())
|
|
9159
8669
|
});
|
|
9160
8670
|
var POST$3 = Run.POST({ json: Dismiss }, async (ctx) => {
|
|
8671
|
+
const ws = ctx.data.workspace;
|
|
9161
8672
|
const body = await readBody(ctx);
|
|
9162
|
-
dismissPr(
|
|
8673
|
+
dismissPr(ws.id, body.fullName, body.number);
|
|
8674
|
+
await pruneDismissedLane(ws, body.fullName, body.number);
|
|
9163
8675
|
pokeStatusWatch();
|
|
9164
|
-
return Response.json(await listPrs(
|
|
8676
|
+
return Response.json(await listPrs(ws, false));
|
|
9165
8677
|
});
|
|
8678
|
+
/** Dismissing a finished lane's chip is the point at which the user says
|
|
8679
|
+
* they are done with it, so take the local branch with it — otherwise a
|
|
8680
|
+
* lane's ref lives in the shared bare cache until the whole workspace is
|
|
8681
|
+
* deleted, and they accumulate for as long as the workspace does.
|
|
8682
|
+
*
|
|
8683
|
+
* The workspace's open PRs are fetched without a recency bound, so this
|
|
8684
|
+
* list settles whether anything else still needs the branch without asking
|
|
8685
|
+
* GitHub again. Best-effort throughout: a lane that cannot be pruned is
|
|
8686
|
+
* left alone rather than failing the dismissal the user asked for. */
|
|
8687
|
+
async function pruneDismissedLane(ws, fullName, number) {
|
|
8688
|
+
try {
|
|
8689
|
+
const list = await workspacePrs(fullName, ws.branch, otherWorkspaceBranches(ws.id));
|
|
8690
|
+
const pr = list.find((p) => p.number === number);
|
|
8691
|
+
if (!pr || pr.state === "OPEN" || !pr.headRefOid) return;
|
|
8692
|
+
if (list.some((p) => p.headRefName === pr.headRefName && p.state === "OPEN")) return;
|
|
8693
|
+
await pruneLaneBranch(ws.id, fullName, pr.headRefName, pr.headRefOid);
|
|
8694
|
+
} catch {}
|
|
8695
|
+
}
|
|
9166
8696
|
async function listPrs(ws, refresh) {
|
|
9167
8697
|
const foreign = otherWorkspaceBranches(ws.id);
|
|
9168
8698
|
return Promise.all(ws.repos.map(async (repo) => ({
|
|
@@ -13538,6 +13068,7 @@ var lastForced = /* @__PURE__ */ new Map();
|
|
|
13538
13068
|
* notifications skip sessions someone is actively watching. */
|
|
13539
13069
|
var viewerCounts = /* @__PURE__ */ new Map();
|
|
13540
13070
|
function trackViewer(sessionId, delta) {
|
|
13071
|
+
if (delta > 0) noteViewerAttached(sessionId);
|
|
13541
13072
|
const count = Math.max(0, (viewerCounts.get(sessionId) ?? 0) + delta);
|
|
13542
13073
|
if (count > 0) viewerCounts.set(sessionId, count);
|
|
13543
13074
|
else viewerCounts.delete(sessionId);
|
|
@@ -13811,4 +13342,4 @@ server.listen(port, () => {
|
|
|
13811
13342
|
//#endregion
|
|
13812
13343
|
export {};
|
|
13813
13344
|
|
|
13814
|
-
;var __MARKO_MANIFEST__={"esfPH6H":{"block":[2,"stylesheet#/assets/preload-helper-
|
|
13345
|
+
;var __MARKO_MANIFEST__={"esfPH6H":{"block":[2,"stylesheet#/assets/preload-helper-Di0vWBYv.css",6,"<link",0," rel=\"stylesheet\" crossorigin href=\"",1,"assets/preload-helper-Di0vWBYv.css\"",">",2,"stylesheet#/assets/index-Du7Hgz2d.css",6,"<link",0," rel=\"stylesheet\" crossorigin href=\"",1,"assets/index-Du7Hgz2d.css\"",">"],"defer":[2,"/assets/index-BXWsr0DP.js",6,"<script",0," async type=\"module\" crossorigin src=\"",1,"assets/index-BXWsr0DP.js\"","></script>",2,"modulepreload#/assets/_B-HE1A0L.js",6,"<link",0," rel=\"modulepreload\" crossorigin href=\"",1,"assets/_B-HE1A0L.js\"",">"]}};
|