@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.
Files changed (243) hide show
  1. package/dist/{_B6irorCp.js → _BlvusYIA.js} +2 -2
  2. package/dist/{_Tcoxq_nF.js → _DncwyiYL.js} +17 -17
  3. package/dist/{_Cja4R2gP.js → _P9IsUQm2.js} +58 -59
  4. package/dist/_kABYZA6_.js +2 -0
  5. package/dist/index.mjs +398 -867
  6. package/dist/public/assets/{_D0en76Ej.js → _0jDMZ5Nf.js} +1 -1
  7. package/dist/public/assets/_0jDMZ5Nf.js.br +0 -0
  8. package/dist/public/assets/{_dAPOyRJr.js → _2JIp-AkL.js} +1 -1
  9. package/dist/public/assets/_2JIp-AkL.js.br +0 -0
  10. package/dist/public/assets/{_DAVDeGoR.js → _6t6kjpdU.js} +1 -1
  11. package/dist/public/assets/_6t6kjpdU.js.br +0 -0
  12. package/dist/public/assets/{_D_EzfDaC.js → _7WXyLEhK.js} +1 -1
  13. package/dist/public/assets/_7WXyLEhK.js.br +0 -0
  14. package/dist/public/assets/{_CIVAj2XC.js → _B-HE1A0L.js} +1 -1
  15. package/dist/public/assets/_B-HE1A0L.js.br +0 -0
  16. package/dist/public/assets/{_D5BjTqU42.js → _B-tmCiTe2.js} +1 -1
  17. package/dist/public/assets/_B-tmCiTe2.js.br +0 -0
  18. package/dist/public/assets/{_CcjW-l5T.js → _B1lH2KuX.js} +1 -1
  19. package/dist/public/assets/_B1lH2KuX.js.br +0 -0
  20. package/dist/public/assets/{_DJAJCWgm.js → _B2jdNsMP.js} +5 -5
  21. package/dist/public/assets/_B2jdNsMP.js.br +0 -0
  22. package/dist/public/assets/{_Bd7b48iJ.js → _B6bkX_xw.js} +1 -1
  23. package/dist/public/assets/_B6bkX_xw.js.br +0 -0
  24. package/dist/public/assets/{_FT8jstIj.js → _B7_IQvxy.js} +1 -1
  25. package/dist/public/assets/_B7_IQvxy.js.br +0 -0
  26. package/dist/public/assets/{_ePAxCx7r.js → _BBnPf4LB.js} +1 -1
  27. package/dist/public/assets/_BBnPf4LB.js.br +0 -0
  28. package/dist/public/assets/{_BPvgcQ_P.js → _BEn7bsbI.js} +1 -1
  29. package/dist/public/assets/_BEn7bsbI.js.br +0 -0
  30. package/dist/public/assets/{_Bnp1UtCp2.js → _BKPFmzRa2.js} +1 -1
  31. package/dist/public/assets/_BKPFmzRa2.js.br +0 -0
  32. package/dist/public/assets/{_CJ4aiC36.js → _BKSy9tfl.js} +1 -1
  33. package/dist/public/assets/_BKSy9tfl.js.br +0 -0
  34. package/dist/public/assets/{_Z_Oh39Jb.js → _BPhrpOAd.js} +1 -1
  35. package/dist/public/assets/_BPhrpOAd.js.br +0 -0
  36. package/dist/public/assets/{_DZtm6WF2.js → _BQKEgF_-.js} +1 -1
  37. package/dist/public/assets/_BQKEgF_-.js.br +0 -0
  38. package/dist/public/assets/{_DA_t7MOs2.js → _BVVf3KNx2.js} +1 -1
  39. package/dist/public/assets/_BVVf3KNx2.js.br +0 -0
  40. package/dist/public/assets/{_D0ljGGvp2.js → _BdE0YzeT2.js} +1 -1
  41. package/dist/public/assets/_BdE0YzeT2.js.br +0 -0
  42. package/dist/public/assets/{_BCTR0wV0.js → _BeS7I1tE.js} +1 -1
  43. package/dist/public/assets/_BeS7I1tE.js.br +0 -0
  44. package/dist/public/assets/{_DtMzVsHW2.js → _Bj8eqKyf2.js} +1 -1
  45. package/dist/public/assets/_Bj8eqKyf2.js.br +0 -0
  46. package/dist/public/assets/{_DvsUo16D2.js → _BmpuJc0U2.js} +1 -1
  47. package/dist/public/assets/_BmpuJc0U2.js.br +0 -0
  48. package/dist/public/assets/{_C2OfA6BZ.js → _BrNJO7NC.js} +1 -1
  49. package/dist/public/assets/_BrNJO7NC.js.br +0 -0
  50. package/dist/public/assets/{_BA7PhURg.js → _BsDGIBWi.js} +1 -1
  51. package/dist/public/assets/_BsDGIBWi.js.br +0 -0
  52. package/dist/public/assets/{_BBXJK7fW.js → _BszYFXns.js} +1 -1
  53. package/dist/public/assets/_BszYFXns.js.br +0 -0
  54. package/dist/public/assets/{_DbJRI9_H.js → _C-3_S2jT.js} +1 -1
  55. package/dist/public/assets/_C-3_S2jT.js.br +0 -0
  56. package/dist/public/assets/{_DucRMQLL2.js → _C2a60ukk2.js} +1 -1
  57. package/dist/public/assets/_C2a60ukk2.js.br +0 -0
  58. package/dist/public/assets/{_CasdikBZ2.js → _C5qWivO82.js} +1 -1
  59. package/dist/public/assets/_C5qWivO82.js.br +0 -0
  60. package/dist/public/assets/{_CL84pok8.js → _C7E2sftJ.js} +1 -1
  61. package/dist/public/assets/_C7E2sftJ.js.br +0 -0
  62. package/dist/public/assets/{_Tou5xDB12.js → _C9jJ-zAu2.js} +1 -1
  63. package/dist/public/assets/_C9jJ-zAu2.js.br +0 -0
  64. package/dist/public/assets/{_DbnzsP9f.js → _CBWyaxNg.js} +1 -1
  65. package/dist/public/assets/_CBWyaxNg.js.br +0 -0
  66. package/dist/public/assets/{_CjrYQPNO.js → _CCxiHsg1.js} +1 -1
  67. package/dist/public/assets/_CCxiHsg1.js.br +0 -0
  68. package/dist/public/assets/{_BnN7B1Mb.js → _CMXeuTU3.js} +1 -1
  69. package/dist/public/assets/_CMXeuTU3.js.br +0 -0
  70. package/dist/public/assets/{_DoaHBjpa.js → _COItZVVh.js} +1 -1
  71. package/dist/public/assets/_COItZVVh.js.br +0 -0
  72. package/dist/public/assets/{_DaTkOx5R.js → _CQjfWgLv.js} +1 -1
  73. package/dist/public/assets/_CQjfWgLv.js.br +0 -0
  74. package/dist/public/assets/{_2By3R--W2.js → _CUudFj1k2.js} +1 -1
  75. package/dist/public/assets/_CUudFj1k2.js.br +0 -0
  76. package/dist/public/assets/{__UTjMwX3.js → _CVRoyRZW.js} +1 -1
  77. package/dist/public/assets/_CVRoyRZW.js.br +0 -0
  78. package/dist/public/assets/{_CQRG1j1X.js → _CVpg0dqw.js} +1 -1
  79. package/dist/public/assets/_CVpg0dqw.js.br +0 -0
  80. package/dist/public/assets/{__OpDUxvR.js → _CWcbEhLf.js} +1 -1
  81. package/dist/public/assets/_CWcbEhLf.js.br +0 -0
  82. package/dist/public/assets/{_jDukN6_E2.js → _ChdHZg3q2.js} +1 -1
  83. package/dist/public/assets/_ChdHZg3q2.js.br +0 -0
  84. package/dist/public/assets/{_e1lYvQAo2.js → _Csumg8kE2.js} +1 -1
  85. package/dist/public/assets/_Csumg8kE2.js.br +0 -0
  86. package/dist/public/assets/{_BRP9V2vY.js → _Cu2zWIrA.js} +1 -1
  87. package/dist/public/assets/_Cu2zWIrA.js.br +0 -0
  88. package/dist/public/assets/{_C1uG69PI.js → _CvB8TafR.js} +1 -1
  89. package/dist/public/assets/_CvB8TafR.js.br +0 -0
  90. package/dist/public/assets/{_ZLwlH_XK.js → _CxfUzQkI.js} +1 -1
  91. package/dist/public/assets/_CxfUzQkI.js.br +0 -0
  92. package/dist/public/assets/{_DIezl6EI.js → _D5wyt0NZ.js} +1 -1
  93. package/dist/public/assets/_D5wyt0NZ.js.br +0 -0
  94. package/dist/public/assets/{_BqdeosKn.js → _DAES5BQ6.js} +1 -1
  95. package/dist/public/assets/_DAES5BQ6.js.br +0 -0
  96. package/dist/public/assets/{_jmw7zbFI2.js → _DAp7RKbE2.js} +1 -1
  97. package/dist/public/assets/_DAp7RKbE2.js.br +0 -0
  98. package/dist/public/assets/{_BNDbFEJj.js → _DJIoEU4l.js} +1 -1
  99. package/dist/public/assets/_DJIoEU4l.js.br +0 -0
  100. package/dist/public/assets/{_CQ3pD5r12.js → _DQZT5aYv2.js} +1 -1
  101. package/dist/public/assets/_DQZT5aYv2.js.br +0 -0
  102. package/dist/public/assets/{_Dkmb-8CU.js → _DSfzkPVh.js} +1 -1
  103. package/dist/public/assets/_DSfzkPVh.js.br +0 -0
  104. package/dist/public/assets/{_D861FlLr2.js → _DSl3gnKp2.js} +1 -1
  105. package/dist/public/assets/{_BBdsdafe2.js → _DUwDVnyb2.js} +1 -1
  106. package/dist/public/assets/_DUwDVnyb2.js.br +0 -0
  107. package/dist/public/assets/{_DCD2JMxh2.js → _DYgx29Kq2.js} +1 -1
  108. package/dist/public/assets/{_DS7FwF-J.js → _DbeeD9R1.js} +1 -1
  109. package/dist/public/assets/_DbeeD9R1.js.br +0 -0
  110. package/dist/public/assets/{_CqmPWoAp2.js → _DdvD3pSx2.js} +1 -1
  111. package/dist/public/assets/_DdvD3pSx2.js.br +0 -0
  112. package/dist/public/assets/{_D0PcbpPB.js → _DlEZP4B2.js} +1 -1
  113. package/dist/public/assets/_DlEZP4B2.js.br +0 -0
  114. package/dist/public/assets/{_C9UHqcOT2.js → _DmkxrcNE2.js} +1 -1
  115. package/dist/public/assets/_DmkxrcNE2.js.br +0 -0
  116. package/dist/public/assets/{_DY4GR3La.js → _Dp6GcCez.js} +1 -1
  117. package/dist/public/assets/_Dp6GcCez.js.br +0 -0
  118. package/dist/public/assets/{_E5DvansN.js → _Drob8ol2.js} +1 -1
  119. package/dist/public/assets/_Drob8ol2.js.br +0 -0
  120. package/dist/public/assets/{_4aAs0pvU.js → _Fd6qP3go.js} +1 -1
  121. package/dist/public/assets/_Fd6qP3go.js.br +0 -0
  122. package/dist/public/assets/{_U0PVI62V.js → _GX4ApnkB.js} +1 -1
  123. package/dist/public/assets/_GX4ApnkB.js.br +0 -0
  124. package/dist/public/assets/{_BAQFHOGb.js → _HmwD_O7C.js} +1 -1
  125. package/dist/public/assets/_HmwD_O7C.js.br +0 -0
  126. package/dist/public/assets/{_BdiO50aC2.js → _IiVyZhFQ2.js} +1 -1
  127. package/dist/public/assets/_IiVyZhFQ2.js.br +0 -0
  128. package/dist/public/assets/{_BaIOx6992.js → _M4_M1GCx2.js} +1 -1
  129. package/dist/public/assets/_M4_M1GCx2.js.br +0 -0
  130. package/dist/public/assets/{_D2sFNldb.js → _MbiYJ36s.js} +1 -1
  131. package/dist/public/assets/_MbiYJ36s.js.br +0 -0
  132. package/dist/public/assets/{_BBEMecyM2.js → _NSw61-q82.js} +1 -1
  133. package/dist/public/assets/_NSw61-q82.js.br +0 -0
  134. package/dist/public/assets/{_BRV26aAF.js → _QBVNsQ8h.js} +1 -1
  135. package/dist/public/assets/_QBVNsQ8h.js.br +0 -0
  136. package/dist/public/assets/{_Dyejz2MQ.js → _RcdEaPTX.js} +1 -1
  137. package/dist/public/assets/_RcdEaPTX.js.br +0 -0
  138. package/dist/public/assets/{_BPzHoTu3.js → _Ty6Zi_p6.js} +1 -1
  139. package/dist/public/assets/_Ty6Zi_p6.js.br +0 -0
  140. package/dist/public/assets/{_BculF-XV.js → _WSiIjl8k.js} +1 -1
  141. package/dist/public/assets/{_DbbVTGR82.js → _c4j42n9F2.js} +1 -1
  142. package/dist/public/assets/_c4j42n9F2.js.br +0 -0
  143. package/dist/public/assets/{_CAP_5S-t.js → _cRSAYsIy.js} +1 -1
  144. package/dist/public/assets/_cRSAYsIy.js.br +0 -0
  145. package/dist/public/assets/{_BkeFq1dG2.js → _gqKnRhHm2.js} +1 -1
  146. package/dist/public/assets/_gqKnRhHm2.js.br +0 -0
  147. package/dist/public/assets/{_Bt3B1aEu2.js → _i3m2va9y2.js} +1 -1
  148. package/dist/public/assets/_i3m2va9y2.js.br +0 -0
  149. package/dist/public/assets/{_CMmwGR_Q.js → _rShrll8V.js} +1 -1
  150. package/dist/public/assets/_rShrll8V.js.br +0 -0
  151. package/dist/public/assets/{_BYRkkQxk.js → _wsALS6ya.js} +1 -1
  152. package/dist/public/assets/_wsALS6ya.js.br +0 -0
  153. package/dist/public/assets/{_B7T2AE8L.js → _wx4NAfvC.js} +1 -1
  154. package/dist/public/assets/_wx4NAfvC.js.br +0 -0
  155. package/dist/public/assets/{diff-view-sXFdzozK.css → diff-view-l7q43Ong.css} +1 -1
  156. package/dist/public/assets/diff-view-l7q43Ong.css.br +0 -0
  157. package/dist/public/assets/{index-DKRkgwLo.js → index-BXWsr0DP.js} +4 -4
  158. package/dist/public/assets/index-BXWsr0DP.js.br +0 -0
  159. package/dist/public/assets/index-Du7Hgz2d.css +1 -0
  160. package/dist/public/assets/index-Du7Hgz2d.css.br +0 -0
  161. package/dist/public/assets/{preload-helper-Cioq5Qre.css → preload-helper-Di0vWBYv.css} +1 -1
  162. package/dist/public/assets/preload-helper-Di0vWBYv.css.br +0 -0
  163. package/package.json +1 -1
  164. package/scripts/migrate.mjs +93 -0
  165. package/dist/_L15vvgS1.js +0 -2
  166. package/dist/public/assets/_2By3R--W2.js.br +0 -0
  167. package/dist/public/assets/_4aAs0pvU.js.br +0 -0
  168. package/dist/public/assets/_B7T2AE8L.js.br +0 -0
  169. package/dist/public/assets/_BA7PhURg.js.br +0 -0
  170. package/dist/public/assets/_BAQFHOGb.js.br +0 -0
  171. package/dist/public/assets/_BBEMecyM2.js.br +0 -0
  172. package/dist/public/assets/_BBXJK7fW.js.br +0 -0
  173. package/dist/public/assets/_BBdsdafe2.js.br +0 -0
  174. package/dist/public/assets/_BCTR0wV0.js.br +0 -0
  175. package/dist/public/assets/_BNDbFEJj.js.br +0 -0
  176. package/dist/public/assets/_BPvgcQ_P.js.br +0 -0
  177. package/dist/public/assets/_BPzHoTu3.js.br +0 -0
  178. package/dist/public/assets/_BRP9V2vY.js.br +0 -0
  179. package/dist/public/assets/_BRV26aAF.js.br +0 -0
  180. package/dist/public/assets/_BYRkkQxk.js.br +0 -0
  181. package/dist/public/assets/_BaIOx6992.js.br +0 -0
  182. package/dist/public/assets/_Bd7b48iJ.js.br +0 -0
  183. package/dist/public/assets/_BdiO50aC2.js.br +0 -0
  184. package/dist/public/assets/_BkeFq1dG2.js.br +0 -0
  185. package/dist/public/assets/_BnN7B1Mb.js.br +0 -0
  186. package/dist/public/assets/_Bnp1UtCp2.js.br +0 -0
  187. package/dist/public/assets/_BqdeosKn.js.br +0 -0
  188. package/dist/public/assets/_Bt3B1aEu2.js.br +0 -0
  189. package/dist/public/assets/_C1uG69PI.js.br +0 -0
  190. package/dist/public/assets/_C2OfA6BZ.js.br +0 -0
  191. package/dist/public/assets/_C9UHqcOT2.js.br +0 -0
  192. package/dist/public/assets/_CAP_5S-t.js.br +0 -0
  193. package/dist/public/assets/_CIVAj2XC.js.br +0 -0
  194. package/dist/public/assets/_CJ4aiC36.js.br +0 -0
  195. package/dist/public/assets/_CL84pok8.js.br +0 -0
  196. package/dist/public/assets/_CMmwGR_Q.js.br +0 -0
  197. package/dist/public/assets/_CQ3pD5r12.js.br +0 -0
  198. package/dist/public/assets/_CQRG1j1X.js.br +0 -0
  199. package/dist/public/assets/_CasdikBZ2.js.br +0 -0
  200. package/dist/public/assets/_CcjW-l5T.js.br +0 -0
  201. package/dist/public/assets/_CjrYQPNO.js.br +0 -0
  202. package/dist/public/assets/_CqmPWoAp2.js.br +0 -0
  203. package/dist/public/assets/_D0PcbpPB.js.br +0 -0
  204. package/dist/public/assets/_D0en76Ej.js.br +0 -0
  205. package/dist/public/assets/_D0ljGGvp2.js.br +0 -0
  206. package/dist/public/assets/_D2sFNldb.js.br +0 -0
  207. package/dist/public/assets/_D5BjTqU42.js.br +0 -0
  208. package/dist/public/assets/_DAVDeGoR.js.br +0 -0
  209. package/dist/public/assets/_DA_t7MOs2.js.br +0 -0
  210. package/dist/public/assets/_DIezl6EI.js.br +0 -0
  211. package/dist/public/assets/_DJAJCWgm.js.br +0 -0
  212. package/dist/public/assets/_DS7FwF-J.js.br +0 -0
  213. package/dist/public/assets/_DY4GR3La.js.br +0 -0
  214. package/dist/public/assets/_DZtm6WF2.js.br +0 -0
  215. package/dist/public/assets/_D_EzfDaC.js.br +0 -0
  216. package/dist/public/assets/_DaTkOx5R.js.br +0 -0
  217. package/dist/public/assets/_DbJRI9_H.js.br +0 -0
  218. package/dist/public/assets/_DbbVTGR82.js.br +0 -0
  219. package/dist/public/assets/_DbnzsP9f.js.br +0 -0
  220. package/dist/public/assets/_Dkmb-8CU.js.br +0 -0
  221. package/dist/public/assets/_DoaHBjpa.js.br +0 -0
  222. package/dist/public/assets/_DtMzVsHW2.js.br +0 -0
  223. package/dist/public/assets/_DucRMQLL2.js.br +0 -0
  224. package/dist/public/assets/_DvsUo16D2.js.br +0 -0
  225. package/dist/public/assets/_Dyejz2MQ.js.br +0 -0
  226. package/dist/public/assets/_E5DvansN.js.br +0 -0
  227. package/dist/public/assets/_FT8jstIj.js.br +0 -0
  228. package/dist/public/assets/_Tou5xDB12.js.br +0 -0
  229. package/dist/public/assets/_U0PVI62V.js.br +0 -0
  230. package/dist/public/assets/_ZLwlH_XK.js.br +0 -0
  231. package/dist/public/assets/_Z_Oh39Jb.js.br +0 -0
  232. package/dist/public/assets/__OpDUxvR.js.br +0 -0
  233. package/dist/public/assets/__UTjMwX3.js.br +0 -0
  234. package/dist/public/assets/_dAPOyRJr.js.br +0 -0
  235. package/dist/public/assets/_e1lYvQAo2.js.br +0 -0
  236. package/dist/public/assets/_ePAxCx7r.js.br +0 -0
  237. package/dist/public/assets/_jDukN6_E2.js.br +0 -0
  238. package/dist/public/assets/_jmw7zbFI2.js.br +0 -0
  239. package/dist/public/assets/diff-view-sXFdzozK.css.br +0 -0
  240. package/dist/public/assets/index-DKRkgwLo.js.br +0 -0
  241. package/dist/public/assets/index-c70b3ZMB.css +0 -1
  242. package/dist/public/assets/index-c70b3ZMB.css.br +0 -0
  243. 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 git, B as config, C as AGENTS, D as setSetting, E as setPref, F as subscriberCount, I as all, L as db, M as tmux, N as publish, O as TMUX_SOCKET, P as subscribe, R as get, S as saveSubscription, T as preferredAgent, _ as setScrapedPhase, a as killSession, b as deleteSubscription, c as newSessionArgs, d as renameSession, f as sendToSession, g as setAgentPhase, h as clearAgentPhase, i as getSession, j as run, k as gh, 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 setSessionViewers, w as allPrefs, x as pushPublicKey, y as summaryFromHookPayload, z as workspacePath } from "./_Cja4R2gP.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 "./_B6irorCp.js";
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
- /** Exact head-branch lookup. The windowed lists below (100 most recently
2134
- * created / 50 most recently updated) lose an older workspace PR on a
2135
- * busy repo, so the workspace branch itself is always queried directly.
2136
- * Lane branches (`-topic`) are actively worked and stay inside the
2137
- * windows. Key: `fullName#branch`. */
2138
- var headPrs = swr(TTL_MS$3, async (key) => {
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
- const fullName = key.slice(0, sep);
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: the recency-windowed list filtered to the
2158
- * branch prefix, plus the exact-head lookup merged in. */
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
- const [windowed, exact] = await Promise.all([prs(fullName, refresh), headPrs(`${fullName}#${branch}`, refresh)]);
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 `gh pr list`
2198
- * reports and what the UI compares against. Reaching through `headRef` gets
2199
- * the branch's *current* tip instead — a different commit entirely once a
2200
- * workspace branch is reused, and `headRef { oid }` is not even a field, so
2201
- * GitHub answers 200 with an `errors` array and no `data`. */
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
- /** One repo's PRs, newest-created first the order `gh pr list` returns and
2204
- * that `prsForBranchPrefix`'s windowing assumes. */
2205
- function repoPrsQuery(fullName, first, headRefName) {
2206
- const [owner, name] = fullName.split("/");
2207
- const head = headRefName ? ` headRefName: ${JSON.stringify(headRefName)}` : "";
2208
- return `query { repository(owner: ${JSON.stringify(owner)}, name: ${JSON.stringify(name)}) { pullRequests(first: ${first}${head}, orderBy: {field: CREATED_AT, direction: DESC}) { nodes { ${GQL_PR_FIELDS} } } } }`;
2209
- }
2210
- /** GraphQL first, `gh` if that cannot be reached at all — a machine whose
2211
- * credential lives somewhere only `gh` knows about keeps working. */
2212
- async function repoPrs(fullName, first, ghArgs, headRefName) {
2213
- try {
2214
- return (await graphql(repoPrsQuery(fullName, first, headRefName))).repository?.pullRequests.nodes ?? [];
2215
- } catch {
2216
- const out = await gh(ghArgs).catch(() => "[]");
2217
- return JSON.parse(out);
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(fullNames, force = false) {
2221
- const names = [...new Set(fullNames)].filter((n) => n.includes("/"));
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 (!names.length || Date.now() - lastBatch < minMs) return false;
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 query = "query {" + names.map((fullName, i) => {
2228
- const [owner, name] = fullName.split("/");
2229
- return `r${i}: repository(owner: ${JSON.stringify(owner)}, name: ${JSON.stringify(name)}) { pullRequests(first: 50, orderBy: {field: UPDATED_AT, direction: DESC}) { nodes { ${GQL_PR_FIELDS} } } }`;
2230
- }).join(" ") + "}";
2231
- const data = await graphql(query).catch(async (err) => {
2232
- const out = await gh([
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
- var lastPushed = "";
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(activeRepoNames()).catch(() => false)) invalidateSnapshot();
2381
+ if (await refreshPrsBatch(activeRepoTargets()).catch(() => false)) invalidateSnapshot();
2310
2382
  const value = await statusForAll();
2311
- const json = JSON.stringify(value);
2312
- if (json !== lastPushed) {
2313
- lastPushed = json;
2314
- publish("status.changed", value);
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
- function activeRepoNames() {
2344
- return listWorkspaces().filter((ws) => ws.status === "active").flatMap((ws) => ws.repos.map((r) => r.full_name));
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(activeRepoNames(), true).catch(() => false)) invalidateSnapshot();
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)), git(["rev-parse", "HEAD"], dir).catch(() => "")]);
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("_V")}></div>${_el_resume($scope5_id, "a")}`);
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(["_X", { ["_W"]: input.inline }])} data-palette${input.inline ? " data-inline" : ""} role=dialog aria-label=Workspaces>`);
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("_5")}><p${_attr_class("_bg")}>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("_bg")}>Pick your preferred agent below — new sessions and the quick-create button use it. GitHub access uses your <code>gh</code> login.</p></div>`);
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("_be")} autofocus placeholder="Jump to workspace…" aria-label="Filter workspaces">${_el_resume($scope0_id, "d")}<ul${_attr_class(["_Y", !input.inline && "_bf"])}>`);
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("_Z")}><button${_attr_class(["_2", {
2704
- ["_1"]: i === hi,
2705
- ["_0"]: row$1.kind === "ws" && row$1.archived
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("_6")}>+ New workspace</span>`);
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(["_6", "_4"])}>▸ <!>${_escape(row$1.label)}${_el_resume($scope9_id, "b")}</span>`);
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("_6")}><span${_attr_class(["_q", phase[phaseOf(st)]])}></span>${_el_resume($scope2_id, "b")}<span${_attr_class("_7")}>${_escape(row$1.ws.name)}${_el_resume($scope2_id, "d")}</span>`);
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", "_9"])}>open</span>`);
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("_8")}>`);
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", "__"])}${_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")}`);
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", "__"])}${_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")}`);
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", "__"])}${_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")}`);
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("_ba")}>`);
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("_3")} title="Review changes">`);
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("_3")} title="Manage workspace">`);
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("_3")} title="New session"${_attr("popovertarget", newPopId)}>`);
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("_bd")}>${`archived (${_escape(`${archived.length}`)})`}${_el_resume($scope7_id, "b")}</button>${_el_resume($scope7_id, "a")}`);
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("_bb")}><span></span><span${_attr_class("_bc")}>↑↓ navigate · ↵ open · ⌘1–9 switch · esc close</span>`);
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("_bh")} aria-label="Preferred agent">`);
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 = "_bi _O";
2915
- var iconBtn$3 = "_bl _y";
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("_cr")}><input${_attr_input_value($scope0_id, "b", filter, _resume(function(v) {
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("_cD")} placeholder="Add a repo…" aria-label="Add a repo"${_attr("disabled", input.disabled)}>${_el_resume($scope0_id, "b")}`);
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("_cC")}>Loading repos…</p>`);
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("_cs")}>`);
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(["_cu", { ["_ct"]: i === highlight }])}><button${_attr_class("_cv")}>`);
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: "_cA"
3070
+ class: "_b6"
2987
3071
  });
2988
- _html(`<span${_attr_class("_cB")}>${_escape(repo.nameWithOwner)}${_el_resume($scope3_id, "e")}</span></button>${_el_resume($scope3_id, "b")}<button${_attr_class(["_cx", { ["_cw"]: 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")}`);
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("_cy")}>`);
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("_cC")}><span${_attr_class("_w")}></span> Loading branches…</p>`);
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("_cE")} placeholder="Filter branches…" aria-label="Filter branches" autofocus>${_el_resume($scope6_id, "a")}`);
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("_cz")}>`);
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(["_cv", "_cF"])}><span${_attr_class(["_cB", "_o"])}>${_escape(branch)}${_el_resume($scope7_id, "c")}</span></button>${_el_resume($scope7_id, "a")}</li>`);
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("_cC")}>No branches match.</p></li>`);
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("_cC")}>No repos match "<!>${_escape(filter)}${_el_resume($scope1_id, "b")}".</p>`);
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("_bm")}><span${_attr_class("_bH")}>Name</span><input${_attr_input_value($scope0_id, "k", name, _resume((_new_name) => {
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("_bI")} placeholder=my-feature${_attr("disabled", busy)} autofocus>${_el_resume($scope0_id, "k")}</label><section${_attr_class("_bn")}><div${_attr_class("_bo")}><h2${_attr_class("_bJ")}>Repos</h2><button${_attr_class(iconBtn$3)} title="Refresh repo list" aria-label="Refresh repo list"${_attr("disabled", catalogRefreshing)}>`);
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("_bp")}>`);
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("_bq")}><span${_attr_class("_br")}>${_escape(repo.fullName)}${_el_resume($scope1_id, "c")}</span>`);
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(["_bs", "_o"])} title="Base branch">⎇ <!>${_escape(repo.baseBranch)}${_el_resume($scope8_id, "b")}</span>`);
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("_bt")}${_attr("title", `Remove ${repo.fullName}`)}${_attr("disabled", busy)}>×</button>${_el_resume($scope1_id, "e")}</li>`);
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("_bu")}>No repos yet — search below to add one (or create empty).</li>`);
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("_bv")}>`);
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(["_bK", { ["_bw"]: i === steps$1.length - 1 }])}>`);
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("_bx")}>✓</span>`);
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("_bj")}><button type=button${_attr_class(["_f", "_bL"])}${_attr("disabled", busy || !!restoring)}>Cancel</button>${_el_resume($scope0_id, "x")}<button type=button${_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
- "_bk",
3283
- "_bL"
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("_by")}><div${_attr_class("_bo")}><h2${_attr_class("_bJ")}>Archived</h2><span${_attr_class("_bz")}>${_escape(archived$2.length)}${_el_resume($scope2_id, "e", $sg__input_workspaces)}</span></div><p${_attr_class("_bA")}>Restore a parked space instead of creating a new one.</p><ul${_attr_class("_bB")}>`);
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("_bC")}><div${_attr_class("_bD")}><span${_attr_class("_bE")}>${_escape(ws.name)}${_el_resume($scope3_id, "d", $sg__input_workspaces)}</span><span${_attr_class(["_bF", "_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", "_bG"])}${_attr("disabled", busy || !!restoring)}>`);
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 = "_c8 _y";
3414
- var navToggle = "_db _y";
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(["_da", {
4021
- ["_c9"]: !navOpen,
4022
- ["_c_"]: isPage
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("_dd")}><h1${_attr_class("_de")}>Workspaces</h1><div${_attr_class("_df")}>`);
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
- "_dg",
4032
- { ["_c7"]: view === "usage" }
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("_dj")}>`);
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("_dh")}>Current</h2>`);
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("_dh")}>Other spaces</h2>`);
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("_dk")}>`);
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("_dn")}${_attr_style(`top:${railHover.top}px;left:${railHover.left}px`)}>`);
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("_dl")}>`);
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(["_di", { ["_c7"]: view === "new" }])} title="New workspace" aria-pressed=${view === "new" ? "true" : "false"}>`);
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", "_dm"])}></div>`);
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, { ["_c7"]: view === "usage" }])} title=Usage aria-pressed=${view === "usage" ? "true" : "false"}>`);
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, { ["_c7"]: view === "new" }])} title="New workspace" aria-pressed=${view === "new" ? "true" : "false"}>`);
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 = "_bX _O";
4401
- var pageMeta = "_bY _T";
4402
- var iconBtn$1 = "_cp _y";
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("_bZ")}>${_escape(ws.name)}${_el_resume($scope0_id, "i")}</span>`);
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(["_b2", "_b3"])}>Archived</span>`);
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("_b0")} aria-hidden=true>·</span><span${_attr_class(["_b1", "_o"])}>${_escape(ws.display_path || ws.path)}${_el_resume($scope0_id, "m")}</span></p>${_el_resume($scope0_id, "g")}</div></header>`);
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("_b4")}><span${_attr_class("_w")}></span><!>${_escape(actionStep)}${_el_resume($scope7_id, "c")}</p>`);
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("_b5")}><div${_attr_class("_b6")}><h2${_attr_class("_cq")}>Repos</h2><span${_attr_class("_b7")}>${_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)}>`);
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("_b9")}>`);
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("_ca")}><div${_attr_class("_cb")}><span${_attr_class(["_cc", "_o"])}>${_escape(row.worktree)}${_el_resume($scope1_id, "d")}/</span><span${_attr_class("_cd")}><span${_attr_class("_ce")}>${_escape(row.full_name)}${_el_resume($scope1_id, "g")}</span>`);
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(["_cf", "_o"])} title="Base branch">⎇ <!>${_escape(row.base_branch)}${_el_resume($scope11_id, "b")}</span>`);
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
- "_cg",
4564
- "_ci",
4565
- { ["_ch"]: confirmingRemove === row.full_name }
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(["_ca", "_b_"])}><span${_attr_class("_w")}></span><div${_attr_class("_cb")}><span${_attr_class("_ce")}>Adding <!>${_escape(name)}${_el_resume($scope13_id, "e")}…</span></div></li>`);
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("_ck")}>No repos yet — search below to add one.</p>`);
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("_b8")}>`);
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("_b5")}><div${_attr_class("_b6")}><h2${_attr_class("_cq")}>Running</h2><span${_attr_class("_b7")}>${_escape(running.length)}${_el_resume($scope8_id, "e")}</span></div><ul${_attr_class("_b9")}>`);
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("_ca")}><div${_attr_class("_cb")}${_attr("title", p.args)}><span${_attr_class(["_cc", "_o"])}>${_escape(p.cmd)}${_el_resume($scope9_id, "d")}</span>`);
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("_cd")}>`);
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", "_cj"])}${_attr("title", `Open http://${typeof location === "undefined" ? "localhost" : location.hostname}:${port}`)}>:<!>${_escape(port)}${_el_resume($scope16_id, "b")}</button>${_el_resume($scope16_id, "a")}`);
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(["_cg", "_ci"])} type=button${_attr("title", `Kill ${p.pid}`)}${_attr("aria-label", `Kill process ${p.pid}`)}>×</button>${_el_resume($scope9_id, "f")}</li>`);
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(["_b5", "_cl"])}><div${_attr_class("_b6")}><h2${_attr_class("_cq")}>Workspace</h2></div><div${_attr_class("_cm")}>`);
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", "_cn"])}${_attr("disabled", !!pendingAction)}>${pendingAction === "archive" ? "Archiving…" : "Archive"}${_el_resume($scope4_id, "b")}</button>${_el_resume($scope4_id, "a")}`);
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", "_cn"])}${_attr("disabled", !!pendingAction)}>Restore</button>${_el_resume($scope5_id, "a")}`);
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
- "_cn",
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("_co")}>Archive hides the space from the list. Delete removes it and its worktrees.</p></section></div></div></div>`);
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 = "_cG _O _P";
4703
- var iconBtn = "_cH _y";
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, "_cI"])} title="Refresh usage" aria-label="Refresh usage"${_attr("disabled", refreshing)}>`);
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", "_cJ"])}><span${_attr_class("_w")}></span> Loading usage…</p>`);
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", "_cJ"])}>${_escape(usage.error)}${_el_resume($scope1_id, "b")}</p>`);
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("_cK")}>`);
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("_cL")}><div${_attr_class("_cM")}><strong${_attr_class("_c5")}>${_escape(agent.agent)}${_el_resume($scope4_id, "d")}</strong>`);
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("_cN")}>${_escape(agent.plan.replace(/^default_/, "").replaceAll("_", " "))}${_el_resume($scope5_id, "b")}</span>`);
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("_cO")}${_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")}`);
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(["_cP", { ["_c6"]: agent.stale_seconds != null }])}>`);
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 ? "_cY" : win.used_percent >= 70 ? "_cX" : win.used_percent >= 40 ? "_cW" : "_cV";
4785
- const pctClass = win.used_percent >= 90 ? "_c3" : win.used_percent >= 70 ? "_c2" : win.used_percent >= 40 ? "_c1" : "_c0";
4786
- _html(`<div${_attr_class("_cR")}${_attr("title", `${win.window}: ${pct}% used${win.resets_at ? ` — resets ${new Date(win.resets_at).toLocaleString()}` : ""}`)}><span${_attr_class("_cS")}>${_escape(win.window)}${_el_resume($scope7_id, "c")}</span><span${_attr_class("_cT")}><span${_attr_class(["_cU", fillClass])}${_attr_style(`width:${Math.min(100, Math.max(2, win.used_percent))}%`)}></span>${_el_resume($scope7_id, "e")}</span><span${_attr_class(["_cZ", pctClass])}>${_escape(pct)}${_el_resume($scope7_id, "g")}%</span>${_el_resume($scope7_id, "f")}<span${_attr_class("_c4")}>${label ? `↻ ${_escape(`${_to_text(label)}`)}` : ""}${_el_resume($scope7_id, "i")}</span></div>${_el_resume($scope7_id, "a")}`);
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("_cQ")}>${_escape(agent.note)}${_el_resume($scope8_id, "b")}</p>`);
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
- "_fp",
4857
- keybar ? "_fr" : "_fq",
4858
- !open && "_ft"
4859
- ])} aria-hidden=${open ? "false" : "true"}><div${_attr_class(["_fk", keybar ? "_fs" : "_fm"])}><input${_attr_input_value($scope0_id, "c", query, _resume(function(v) {
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 && "_fu"])} 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 && "_fv"])} title="Previous match"${_attr("disabled", !canStep)} tabindex=${open ? "0" : "-1"}>↑</button>${_el_resume($scope0_id, "d")}<button type=button${_attr_class([findIconBtn, keybar && "_fv"])} title="Next match"${_attr("disabled", !canStep)} tabindex=${open ? "0" : "-1"}>↓</button>${_el_resume($scope0_id, "e")}<button type=button${_attr_class([findIconBtn, keybar && "_fv"])} 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")}`);
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("./_Tcoxq_nF.js").then((m) => {
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
- /** Herdr-style terminal scraping: agent state read from each session's
7436
- * pane title (set by the CLI via OSC) and rendered screen, matched against
7437
- * herdr's per-agent detection manifests (see scrape/manifests.ts). This is
7438
- * the primary state source for every agent CLI; Claude and Codex
7439
- * additionally report through launch-flag hooks (agent-flags.ts), which
7440
- * carry clean notification text. */
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
- /** With no scrapeable sessions there's nothing to watch — idle at a slow
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 scanned = await scan().catch(() => false);
7450
- setTimeout(tick, scanned ? POLL_MS : IDLE_POLL_MS).unref?.();
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 scrape (drives the poll cadence). */
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 in MANIFESTS);
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} #{pane_title}"
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, ...title] = line.split(" ");
7469
- if (name?.startsWith("wk-")) panes.set(name.slice(3), title.join(" "));
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
- if (panes.has(session.id)) continue;
7473
- clearAgentPhase(session.id);
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
- const live = sessions.filter((session) => panes.has(session.id));
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
- await refreshPrsBatch([ctx.search.repo], true).catch(() => {});
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 git(["rev-parse", "HEAD"], dir).catch(() => "");
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(ctx.data.workspace.id, body.fullName, body.number);
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(ctx.data.workspace, false));
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-Cioq5Qre.css",6,"<link",0," rel=\"stylesheet\" crossorigin href=\"",1,"assets/preload-helper-Cioq5Qre.css\"",">",2,"stylesheet#/assets/index-c70b3ZMB.css",6,"<link",0," rel=\"stylesheet\" crossorigin href=\"",1,"assets/index-c70b3ZMB.css\"",">"],"defer":[2,"/assets/index-DKRkgwLo.js",6,"<script",0," async type=\"module\" crossorigin src=\"",1,"assets/index-DKRkgwLo.js\"","></script>",2,"modulepreload#/assets/_CIVAj2XC.js",6,"<link",0," rel=\"modulepreload\" crossorigin href=\"",1,"assets/_CIVAj2XC.js\"",">"]}};
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\"",">"]}};