@deepseek-insight/dsi 0.8.5 → 0.9.0

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 (210) hide show
  1. package/.agents/skills/{dsi-gb-verifier → glass-dsi}/SKILL.md +57 -5
  2. package/.agents/skills/glass-dsi/references/cdp-verification.md +132 -0
  3. package/.agents/skills/glass-dsi/scripts/_connect.mjs +81 -0
  4. package/.agents/skills/glass-dsi/scripts/glass-url.mjs +48 -0
  5. package/.agents/skills/glass-dsi/scripts/glass.mjs +84 -0
  6. package/.agents/skills/glass-url/SKILL.md +117 -0
  7. package/.agents/skills/glass-url/scripts/_args.mjs +49 -0
  8. package/.agents/skills/glass-url/scripts/_connect.mjs +99 -0
  9. package/.agents/skills/glass-url/scripts/glass-url.mjs +114 -0
  10. package/bin/dsi.mjs +23 -74
  11. package/bin/lib/zai-patch.mjs +115 -0
  12. package/build/client/_app/immutable/assets/0.Ch5VtsKp.css +2 -0
  13. package/build/client/_app/immutable/assets/2.D0QOh44D.css +1 -0
  14. package/build/client/_app/immutable/chunks/{DwcY-69G.js → 02Wfo2G3.js} +1 -1
  15. package/build/client/_app/immutable/chunks/0Tfhif1V.js +3 -0
  16. package/build/client/_app/immutable/chunks/0ruuBBbh.js +2 -0
  17. package/build/client/_app/immutable/chunks/{DUCaFYlx.js → 4bHE1npv.js} +1 -1
  18. package/build/client/_app/immutable/chunks/{4cwyag_I.js → B4hDUAJl.js} +1 -1
  19. package/build/client/_app/immutable/chunks/{Cr2ck_ss.js → BIPXB-2I.js} +1 -1
  20. package/build/client/_app/immutable/chunks/{CeLBjOd9.js → BIgv-kQR.js} +1 -1
  21. package/build/client/_app/immutable/chunks/BK6k1nBs.js +1 -0
  22. package/build/client/_app/immutable/chunks/{SN3Efo-Q.js → BKwmKcDY.js} +1 -1
  23. package/build/client/_app/immutable/chunks/{CRFuOqJI.js → BORjuqef.js} +1 -1
  24. package/build/client/_app/immutable/chunks/{CH_bR_0j.js → BPmZB0-N.js} +1 -1
  25. package/build/client/_app/immutable/chunks/BROtno1Y.js +1 -0
  26. package/build/client/_app/immutable/chunks/{DEVxi5CK.js → BT5Iel00.js} +1 -1
  27. package/build/client/_app/immutable/chunks/{DdI16loP.js → BX3y_1Hh.js} +1 -1
  28. package/build/client/_app/immutable/chunks/{DuiFyTVb.js → Bea1gxLq.js} +1 -1
  29. package/build/client/_app/immutable/chunks/{D0uxHECr.js → BpkpgvVw.js} +1 -1
  30. package/build/client/_app/immutable/chunks/{CB55Rp7-.js → BreZS7EW.js} +1 -1
  31. package/build/client/_app/immutable/chunks/{BmDADyfH.js → BsS_byzk.js} +1 -1
  32. package/build/client/_app/immutable/chunks/{BWRXzjmQ.js → Bslg-dr5.js} +1 -1
  33. package/build/client/_app/immutable/chunks/{BkYT72a1.js → C-YczRN1.js} +1 -1
  34. package/build/client/_app/immutable/chunks/{DBKMIEwD.js → C2aW4lzo.js} +1 -1
  35. package/build/client/_app/immutable/chunks/{C4gs6zoI.js → C2qFXaz5.js} +1 -1
  36. package/build/client/_app/immutable/chunks/{BBd0nTHG.js → C5RyRpOh.js} +1 -1
  37. package/build/client/_app/immutable/chunks/{DJQr4efH.js → C5iHDVU_.js} +1 -1
  38. package/build/client/_app/immutable/chunks/{B4F5liKq.js → C7opVlLF.js} +1 -1
  39. package/build/client/_app/immutable/chunks/{DIxy2USu.js → CAuEkmZ4.js} +1 -1
  40. package/build/client/_app/immutable/chunks/{BO99LSSA.js → CIkiqgtA.js} +1 -1
  41. package/build/client/_app/immutable/chunks/{Bpd0I3U7.js → CJesWaZn.js} +1 -1
  42. package/build/client/_app/immutable/chunks/{at6PQqQ4.js → CRsoS5Y9.js} +1 -1
  43. package/build/client/_app/immutable/chunks/CTWtsoJD.js +6 -0
  44. package/build/client/_app/immutable/chunks/CWk5gmU2.js +1 -0
  45. package/build/client/_app/immutable/chunks/{lF8CNVOA.js → CXkrluSK.js} +1 -1
  46. package/build/client/_app/immutable/chunks/{DmRY6FWm.js → C_8kFZ_X.js} +4 -4
  47. package/build/client/_app/immutable/chunks/{D6KenyiF.js → Ch7hUoAH.js} +1 -1
  48. package/build/client/_app/immutable/chunks/{b4-Ro8NH.js → ChmmHPdM.js} +1 -1
  49. package/build/client/_app/immutable/chunks/{DfUgh5E_.js → CjajmcJs.js} +1 -1
  50. package/build/client/_app/immutable/chunks/{q5PRaRZk.js → Ck6GS6Vb.js} +1 -1
  51. package/build/client/_app/immutable/chunks/{eFcFJ9Ld.js → ClGoDr_f.js} +1 -1
  52. package/build/client/_app/immutable/chunks/{BQC6O_RV.js → ClqGHlec.js} +1 -1
  53. package/build/client/_app/immutable/chunks/{zypfUZYM.js → CnW6hje6.js} +1 -1
  54. package/build/client/_app/immutable/chunks/{OW5Q7tGb.js → CpI6VYCH.js} +1 -1
  55. package/build/client/_app/immutable/chunks/{BXKc4uuX.js → CygwwaiE.js} +1 -1
  56. package/build/client/_app/immutable/chunks/{Bqwvv7Vf.js → CyhZtsZO.js} +35 -35
  57. package/build/client/_app/immutable/chunks/{BenkQ_4r.js → D-E2Noqq.js} +1 -1
  58. package/build/client/_app/immutable/chunks/{DuRZnRVw.js → D4Btzp_A.js} +1 -1
  59. package/build/client/_app/immutable/chunks/{CdaJvl_A.js → D4C3Jijv.js} +1 -1
  60. package/build/client/_app/immutable/chunks/D9jhmf3I.js +1 -0
  61. package/build/client/_app/immutable/chunks/{Cf0aMC4n.js → DCw0gAtv.js} +1 -1
  62. package/build/client/_app/immutable/chunks/{B6bTO8_7.js → DEW3KpiC.js} +1 -1
  63. package/build/client/_app/immutable/chunks/{O6xxeEm8.js → DYLFbKJe.js} +1 -1
  64. package/build/client/_app/immutable/chunks/{BsBBq-Qk.js → DYu7kgVa.js} +1 -1
  65. package/build/client/_app/immutable/chunks/Dfexc5qV.js +1 -0
  66. package/build/client/_app/immutable/chunks/{kzciT-3i.js → DhmUE8Ri.js} +1 -1
  67. package/build/client/_app/immutable/chunks/{DdJNsJBH.js → DjwX3rAC.js} +1 -1
  68. package/build/client/_app/immutable/chunks/{CajOZJDl.js → DlOfy8Sx.js} +1 -1
  69. package/build/client/_app/immutable/chunks/{CK5vhXvt.js → Do7Y1_MQ.js} +1 -1
  70. package/build/client/_app/immutable/chunks/{ap4GAVq-.js → Dq2XIb1m.js} +1 -1
  71. package/build/client/_app/immutable/chunks/{Czey8tDK.js → DuT_Qr5k.js} +1 -1
  72. package/build/client/_app/immutable/chunks/{4B6J_kM2.js → DyGggFea.js} +1 -1
  73. package/build/client/_app/immutable/chunks/{D0ChUnpi.js → Dym4i64U.js} +1 -1
  74. package/build/client/_app/immutable/chunks/FPsIAiN_.js +1 -0
  75. package/build/client/_app/immutable/chunks/{CevKuuic.js → GIczpP_D.js} +1 -1
  76. package/build/client/_app/immutable/chunks/{B2jrDnt8.js → LjOLSmU7.js} +1 -1
  77. package/build/client/_app/immutable/chunks/VtK73aN-.js +8 -0
  78. package/build/client/_app/immutable/chunks/{AcmOeh2U.js → ZqoQH_jm.js} +1 -1
  79. package/build/client/_app/immutable/chunks/{BlwWx85l.js → aXn6rE_7.js} +1 -1
  80. package/build/client/_app/immutable/chunks/{Czc4_W7v.js → dUOeoGwg.js} +1 -1
  81. package/build/client/_app/immutable/chunks/f50lp1rr.js +1 -0
  82. package/build/client/_app/immutable/chunks/{7FnrqGK9.js → lvLrv1cG.js} +1 -1
  83. package/build/client/_app/immutable/chunks/{CZoElI5B.js → pt3_jHwh.js} +1 -1
  84. package/build/client/_app/immutable/chunks/{Byu_teLA.js → q8irUX-p.js} +1 -1
  85. package/build/client/_app/immutable/chunks/{CnxoqrkQ.js → qmOgUo3c.js} +1 -1
  86. package/build/client/_app/immutable/chunks/vpNeypNM.js +1 -0
  87. package/build/client/_app/immutable/chunks/{DU8C5thd.js → xvTPLhcB.js} +1 -1
  88. package/build/client/_app/immutable/chunks/{DFBKiA2Z.js → zp7hrpsC.js} +1 -1
  89. package/build/client/_app/immutable/entry/app.D4oc_iez.js +2 -0
  90. package/build/client/_app/immutable/entry/start.Xkr2MCWg.js +1 -0
  91. package/build/client/_app/immutable/nodes/0.fsrqKU9i.js +1 -0
  92. package/build/client/_app/immutable/nodes/1.3F37GwcO.js +1 -0
  93. package/build/client/_app/immutable/nodes/2.DsWNNw0K.js +340 -0
  94. package/build/client/_app/version.json +1 -1
  95. package/build/handler.js +6 -6
  96. package/build/index.js +6 -6
  97. package/build/server/chunks/chunks/{app-config.svelte.js-DCc9d7A4.js → app-config.svelte.js-BXjvTmJu.js} +4 -3
  98. package/build/server/chunks/chunks/{config.js-s6iKwHD7.js → config.js-r_jw_bQQ.js} +53 -2
  99. package/build/server/chunks/chunks/{db.js-CxxWK5sn.js → db.js-f2PmBjyD.js} +2 -2
  100. package/build/server/chunks/chunks/{db2.js-DwJ9lySe.js → db2.js-DkwY64WO.js} +2 -2
  101. package/build/server/chunks/chunks/{dsh-connection.js-Chtudg1p.js → dsh-connection.js-BW07Aicl.js} +18 -10
  102. package/build/server/chunks/chunks/{dsh-events.js-BUdvZQmd.js → dsh-events.js-BHf0lLZ5.js} +11 -1
  103. package/build/server/chunks/chunks/{git-probe.js-BX9FPnet.js → git-probe.js-CQqTV7XX.js} +3 -3
  104. package/build/server/chunks/chunks/{index-server.js-DmIEbDVz.js → index-server.js-CPkVoRxB.js} +2 -2
  105. package/build/server/chunks/chunks/{insight-config.js-Db5fe5Df.js → insight-config.js-C5-Rhh5A.js} +13 -4
  106. package/build/server/chunks/chunks/{internal2.js-CaZaz-a9.js → internal2.js-DbC8VGqD.js} +4 -4
  107. package/build/server/chunks/chunks/{registry.js-syaTZ_-A.js → registry.js-CWnRQ4vx.js} +430 -52
  108. package/build/server/chunks/chunks/{registry2.js-D3Pr1Rv9.js → registry2.js-CFzpvj9c.js} +17 -1
  109. package/build/server/chunks/chunks/{server.js-B1bDXhHu.js → server.js-Dijo7DtV.js} +2 -2
  110. package/build/server/chunks/chunks/{settings-document.js-BHESJ7im.js → settings-document.js-DxKURfc_.js} +2 -2
  111. package/build/server/chunks/chunks/{state.js-oYjf745s.js → state.js-DR4xiIVw.js} +5 -5
  112. package/build/server/chunks/chunks/{watcher.js-Ci9jsM5l.js → watcher.js-DvlNn8X0.js} +5 -5
  113. package/build/server/chunks/entries/endpoints/api/a2a/_id_/{_server.ts.js-CHaYhzjy.js → _server.ts.js-DItDXV23.js} +5 -5
  114. package/build/server/chunks/entries/endpoints/api/a2a/{_server.ts.js-CdyqA85c.js → _server.ts.js-Hor8QZb1.js} +8 -8
  115. package/build/server/chunks/entries/endpoints/api/a2a/register/{_server.ts.js-DO_FS5b4.js → _server.ts.js-CEvvsa8B.js} +8 -8
  116. package/build/server/chunks/entries/endpoints/api/browser/_id_/activate/{_server.ts.js-D7Be4JUf.js → _server.ts.js-sXqf-okw.js} +5 -5
  117. package/build/server/chunks/entries/endpoints/api/browser/_id_/close/{_server.ts.js-CGkm2H-U.js → _server.ts.js-Byj9ApJh.js} +5 -5
  118. package/build/server/chunks/entries/endpoints/api/browser/_id_/closetab/{_server.ts.js-D7SLUfOo.js → _server.ts.js-DOIsrzvg.js} +16 -9
  119. package/build/server/chunks/entries/endpoints/api/browser/_id_/element/{_server.ts.js-C3d_JV-q.js → _server.ts.js-Cq3gmRfE.js} +5 -5
  120. package/build/server/chunks/entries/endpoints/api/browser/_id_/history/_server.ts.js-BGSLIV0t.js +61 -0
  121. package/build/server/chunks/entries/endpoints/api/browser/_id_/input/{_server.ts.js-DW0hyVML.js → _server.ts.js-8slca75-.js} +5 -5
  122. package/build/server/chunks/entries/endpoints/api/browser/_id_/mcp/{_server.ts.js-Ev-hdBlf.js → _server.ts.js-CpbdTYds.js} +5 -5
  123. package/build/server/chunks/entries/endpoints/api/browser/_id_/navigate/{_server.ts.js-DZ8-wocV.js → _server.ts.js-Bls9LtLY.js} +5 -5
  124. package/build/server/chunks/entries/endpoints/api/browser/_id_/opentab/{_server.ts.js-aapPrIQK.js → _server.ts.js-DqNi_iW_.js} +5 -5
  125. package/build/server/chunks/entries/endpoints/api/browser/_id_/page/{_server.ts.js-DANA_hMd.js → _server.ts.js-DuXWwo7i.js} +5 -5
  126. package/build/server/chunks/entries/endpoints/api/browser/_id_/stream/{_server.ts.js-BqfseXFy.js → _server.ts.js-DXfqBDEw.js} +17 -5
  127. package/build/server/chunks/entries/endpoints/api/browser/_id_/tabs/{_server.ts.js-DFFF9qe-.js → _server.ts.js-Bgnl8lYs.js} +5 -5
  128. package/build/server/chunks/entries/endpoints/api/browser/_id_/viewport/{_server.ts.js-ek6-D4Zm.js → _server.ts.js-FHmQVbrv.js} +5 -5
  129. package/build/server/chunks/entries/endpoints/api/browser/_id_/zoom/_server.ts.js-BV4cBtSA.js +62 -0
  130. package/build/server/chunks/entries/endpoints/api/browser/{_server.ts.js-CPjKy3ma.js → _server.ts.js-4vgkwh7v.js} +9 -6
  131. package/build/server/chunks/entries/endpoints/api/config/{_server.ts.js-CWE9NP6g.js → _server.ts.js-C_9kwANR.js} +9 -6
  132. package/build/server/chunks/entries/endpoints/api/dsh/directory/{_server.ts.js-D-raYQon.js → _server.ts.js-h1OTHcL4.js} +5 -5
  133. package/build/server/chunks/entries/endpoints/api/dsh/jobs/{_server.ts.js-CI4dEHFY.js → _server.ts.js-B6nih9Sd.js} +5 -5
  134. package/build/server/chunks/entries/endpoints/api/dsh/jobs/follow/{_server.ts.js-cnjoSLtY.js → _server.ts.js-Cf17SVmD.js} +5 -5
  135. package/build/server/chunks/entries/endpoints/api/dsh/pick-directory/{_server.ts.js-0UUtapX5.js → _server.ts.js-DjNwMbdS.js} +5 -5
  136. package/build/server/chunks/entries/endpoints/api/dsh/presets/{_server.ts.js-MK5ezU8u.js → _server.ts.js-Cz5aaEhC.js} +5 -5
  137. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/_server.ts.js-BFBy5O9Y.js +78 -0
  138. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/cancel/{_server.ts.js-wGEl1fuF.js → _server.ts.js-CgEdCo3T.js} +5 -5
  139. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/catalog/{_server.ts.js-Bz7u2BlD.js → _server.ts.js-Bo_aEnHh.js} +5 -5
  140. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/changes/{_server.ts.js-yue5aEjr.js → _server.ts.js-Bd2G_GaH.js} +5 -5
  141. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/command/{_server.ts.js-BFSs5T2m.js → _server.ts.js-DL64FyRw.js} +5 -5
  142. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/events/{_server.ts.js-C2i85wQy.js → _server.ts.js-MhOGB66D.js} +6 -6
  143. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/fork/{_server.ts.js-_toO4f4W.js → _server.ts.js-MjPgXgGO.js} +5 -5
  144. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/goal/{_server.ts.js-BGJnDV85.js → _server.ts.js-BUjDae5H.js} +5 -5
  145. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/history/{_server.ts.js-CQCJg8U8.js → _server.ts.js-dTKd7Hsv.js} +6 -6
  146. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/models/{_server.ts.js-0ADvdE79.js → _server.ts.js-B82rvKoI.js} +5 -5
  147. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/path/{_server.ts.js-DyO4T1Ro.js → _server.ts.js-Cqijsi-c.js} +4 -4
  148. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/permission/{_server.ts.js-CIY7oimw.js → _server.ts.js-CL_vVv2p.js} +29 -6
  149. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/prompt/{_server.ts.js-B-9faNHX.js → _server.ts.js-WS4W9Ly4.js} +5 -5
  150. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/rename/{_server.ts.js-E7-0zfiH.js → _server.ts.js-B72KGRGh.js} +5 -5
  151. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/respond/{_server.ts.js-CODtLQ3Q.js → _server.ts.js-DK5xb2b5.js} +5 -5
  152. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/select-model/{_server.ts.js-BiSxsU-j.js → _server.ts.js-lhT87EQu.js} +5 -5
  153. package/build/server/chunks/entries/endpoints/api/dsh/sessions/{_server.ts.js-C0WJnv2b.js → _server.ts.js-CMhfhbkN.js} +5 -5
  154. package/build/server/chunks/entries/endpoints/api/dsh/subagents/{_server.ts.js-D5bc4xg4.js → _server.ts.js-BLvcFsg6.js} +5 -5
  155. package/build/server/chunks/entries/endpoints/api/dsh/workspace-file/{_server.ts.js-23ycAyUg.js → _server.ts.js-D_rw2Uq6.js} +5 -5
  156. package/build/server/chunks/entries/endpoints/api/dsh/workspace-tree/{_server.ts.js-B4w5Jh7f.js → _server.ts.js-DfXpMMpw.js} +5 -5
  157. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/{_server.ts.js-VQLxDbFE.js → _server.ts.js-2mJCJVxk.js} +5 -5
  158. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/delete/{_server.ts.js-vs5N5Cya.js → _server.ts.js-BCx0Lzjf.js} +5 -5
  159. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/rename/{_server.ts.js-BOWhoBHV.js → _server.ts.js-DECaSjwp.js} +5 -5
  160. package/build/server/chunks/entries/endpoints/api/prompts/_id_/{_server.ts.js-aDEAGfJe.js → _server.ts.js-i_ciJzlb.js} +5 -5
  161. package/build/server/chunks/entries/endpoints/api/prompts/{_server.ts.js-BZ-nRrTp.js → _server.ts.js-BO1pScn7.js} +5 -5
  162. package/build/server/chunks/entries/endpoints/api/prompts/use/{_server.ts.js-CkDY1PQ7.js → _server.ts.js-Buhpf7WE.js} +5 -5
  163. package/build/server/chunks/entries/endpoints/api/settings/{_server.ts.js-CHvgF47Y.js → _server.ts.js-DngUQzcT.js} +4 -4
  164. package/build/server/chunks/entries/endpoints/api/terminal/_id_/output/{_server.ts.js-BNBxebgG.js → _server.ts.js-DLETP4yQ.js} +2 -2
  165. package/build/server/chunks/entries/endpoints/api/terminal/_id_/reattach/{_server.ts.js-DDRJBGIr.js → _server.ts.js-uWl6oxPS.js} +2 -2
  166. package/build/server/chunks/entries/endpoints/api/terminal/_id_/send/{_server.ts.js-CA0vc_Cm.js → _server.ts.js-DYNmXaAd.js} +9 -2
  167. package/build/server/chunks/entries/endpoints/api/terminal/_id_/stream/{_server.ts.js-D6L8Gd_f.js → _server.ts.js-C5m3Ktho.js} +2 -2
  168. package/build/server/chunks/entries/endpoints/api/terminal/{_server.ts.js-CbRT4vBo.js → _server.ts.js-DoTNvcOa.js} +5 -5
  169. package/build/server/chunks/entries/endpoints/api/workspace/file-write/{_server.ts.js-BwD0KaXy.js → _server.ts.js-BzYOJSkI.js} +7 -7
  170. package/build/server/chunks/entries/endpoints/api/workspace/git-events/{_server.ts.js-DgbMRh3d.js → _server.ts.js-xcNesei9.js} +7 -7
  171. package/build/server/chunks/entries/endpoints/api/workspace/git-file-head/{_server.ts.js-DRqZawic.js → _server.ts.js-DsJWYdxt.js} +7 -7
  172. package/build/server/chunks/entries/endpoints/api/workspace/git-map/{_server.ts.js-CTXwwwB1.js → _server.ts.js-CNCku9BR.js} +7 -7
  173. package/build/server/chunks/entries/endpoints/api/workspace/git-status/{_server.ts.js-B4aJBY2w.js → _server.ts.js-nLsNjOxj.js} +7 -7
  174. package/build/server/chunks/entries/endpoints/api/workspace/write-gate/{_server.ts.js-CDJJA18L.js → _server.ts.js-urQk2-ds.js} +7 -7
  175. package/build/server/chunks/entries/{hooks.server.js-Iel6oE7w.js → hooks.server.js-CU2RE5vs.js} +3 -3
  176. package/build/server/chunks/entries/pages/{_error.svelte.js-B-wdFjVG.js → _error.svelte.js-e018KpwE.js} +6 -6
  177. package/build/server/chunks/entries/pages/{_page.server.ts.js-CaoeQzem.js → _page.server.ts.js-BK3Y6eff.js} +3 -3
  178. package/build/server/chunks/entries/pages/{_page.svelte.js-CY7zcWr4.js → _page.svelte.js-DQWBiRk1.js} +2681 -648
  179. package/build/server/chunks/{handler-DYk4NJto.js → handler-DsD7I1_u.js} +3 -3
  180. package/build/server/chunks/{index.js-kL9MZ99b.js → index.js-C_WAkwJs.js} +4 -4
  181. package/build/server/chunks/{manifest.js-BrMLQqec.js → manifest.js-DUy52VaP.js} +79 -65
  182. package/build/server/chunks/nodes/{0.js-BembYTTr.js → 0.js-CuV3dXVD.js} +3 -3
  183. package/build/server/chunks/nodes/1.js-Dc5QC-NJ.js +9 -0
  184. package/build/server/chunks/nodes/{2.js-BezA2RPm.js → 2.js-PwcF4_kT.js} +10 -10
  185. package/package.json +2 -2
  186. package/template/.dsi/prompts.sqlite +0 -0
  187. package/template/.dsi/prompts.sqlite-shm +0 -0
  188. package/template/.dsi/prompts.sqlite-wal +0 -0
  189. package/template/.dsi/settings.yaml +7 -2
  190. package/build/client/_app/immutable/assets/0.C6AGVUc8.css +0 -2
  191. package/build/client/_app/immutable/assets/2.gXzZuuwh.css +0 -1
  192. package/build/client/_app/immutable/chunks/BFOY8uwF.js +0 -1
  193. package/build/client/_app/immutable/chunks/BHDqH9nE.js +0 -1
  194. package/build/client/_app/immutable/chunks/CAneZX4t.js +0 -8
  195. package/build/client/_app/immutable/chunks/CrTRqozz.js +0 -1
  196. package/build/client/_app/immutable/chunks/DQXo7qdJ.js +0 -1
  197. package/build/client/_app/immutable/chunks/DxGYLnDH.js +0 -1
  198. package/build/client/_app/immutable/chunks/HD-mJtOS.js +0 -6
  199. package/build/client/_app/immutable/chunks/K3xyLTzZ.js +0 -1
  200. package/build/client/_app/immutable/chunks/cHj8EuyS.js +0 -3
  201. package/build/client/_app/immutable/chunks/hC0DBYN6.js +0 -2
  202. package/build/client/_app/immutable/chunks/o7DVZODA.js +0 -1
  203. package/build/client/_app/immutable/chunks/pdYhlwhf.js +0 -1
  204. package/build/client/_app/immutable/entry/app.DHewwbUQ.js +0 -2
  205. package/build/client/_app/immutable/entry/start.C0PcwkeZ.js +0 -1
  206. package/build/client/_app/immutable/nodes/0.CP10wY64.js +0 -1
  207. package/build/client/_app/immutable/nodes/1.qWvE0DiU.js +0 -1
  208. package/build/client/_app/immutable/nodes/2.Nw7iFtoh.js +0 -341
  209. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/_server.ts.js-CEiMgzjC.js +0 -46
  210. package/build/server/chunks/nodes/1.js-CKJjyWGZ.js +0 -9
@@ -1,15 +1,15 @@
1
- import { a as __exportAll, o as onDestroy } from '../../chunks/index-server.js-DmIEbDVz.js';
1
+ import { a as __exportAll, o as onDestroy } from '../../chunks/index-server.js-CPkVoRxB.js';
2
2
  import '../../chunks/exports.js-DH_tjtdv.js';
3
- import { M as derived, V as head, T as writable, W as escape_html, X as attr, Y as bind_props, a as setContext, Z as attr_class, _ as attr_style, $ as store_get, a0 as spread_props, a1 as stringify, a2 as attributes, a3 as clsx, a4 as ensure_array_like, a5 as element, g as getContext, a6 as unsubscribe_stores, a7 as html, r as run, a8 as props_id } from '../../chunks/server.js-B1bDXhHu.js';
4
- import { U as UI_LOCALES } from '../../chunks/config.js-s6iKwHD7.js';
3
+ import { M as derived, V as head, T as writable, X as attr, W as escape_html, Y as ensure_array_like, Z as attr_class, _ as attr_style, $ as stringify, a0 as bind_props, a as setContext, a1 as store_get, a2 as spread_props, a3 as attributes, a4 as clsx, a5 as element, g as getContext, a6 as unsubscribe_stores, a7 as html, r as run, a8 as props_id } from '../../chunks/server.js-Dijo7DtV.js';
4
+ import { U as UI_LOCALES } from '../../chunks/config.js-r_jw_bQQ.js';
5
5
  import { m as mergeEntries, c as collapseSystemPromptEntries, t as truncate } from '../../chunks/merge.js-yMwW440S.js';
6
6
  import { p as parseA2aSignature, m as mintA2aId, b as buildDeliveredText } from '../../chunks/a2a-protocol.js-C77mVg2Q.js';
7
7
  import { b as applyKnobEvent, E as EMPTY_KNOBS, r as resolvePermission, l as localPermission, c as presetLabel, d as presetDescription, C as CUSTOM_PRESET, F as FULL_ACCESS_PRESET } from '../../chunks/permission-state.js-B7UpAHBv.js';
8
8
  import { D as DEFAULT_IMAGE_LIMITS } from '../../chunks/image-limits.js-CUdJ0f7r.js';
9
9
  import { s as sanitizeWorkspaceProfile, d as dsiKey, t as themePrefs } from '../../chunks/theme-prefs.svelte.js-8CaWz46g.js';
10
- import { a as appConfig, p as previewSegments, b as parseTagWords, i as isValidTagWord, s as shouldRecordPrompt, g as getTrigger, t as triggerMode, c as searchKey, d as textPreviewOf } from '../../chunks/app-config.svelte.js-DCc9d7A4.js';
10
+ import { a as appConfig, p as previewSegments, b as parseTagWords, i as isValidTagWord, s as shouldRecordPrompt, g as getTrigger, t as triggerMode, c as searchKey, d as textPreviewOf } from '../../chunks/app-config.svelte.js-BXjvTmJu.js';
11
11
  import { c as getLocale } from '../../chunks/runtime.js-CCJi3XaY.js';
12
- import { p as page, a as afterNavigate, t, c as currentLocale, e as replaceState, u as unexpectederror1, s as sessionnotfound2, r as reapednote1, d as dshunreachable1, b as backtoworkspace2 } from '../../chunks/state.js-oYjf745s.js';
12
+ import { p as page, a as afterNavigate, t, c as currentLocale, e as replaceState, u as unexpectederror1, s as sessionnotfound2, r as reapednote1, d as dshunreachable1, b as backtoworkspace2 } from '../../chunks/state.js-DR4xiIVw.js';
13
13
  import 'yaml';
14
14
  import 'html-to-image';
15
15
  import hljs from 'highlight.js/lib/core';
@@ -21,7 +21,7 @@ import xml from 'highlight.js/lib/languages/xml';
21
21
  import css from 'highlight.js/lib/languages/css';
22
22
  import '../../chunks/uneval.js-BJ9Qq2SF.js';
23
23
  import '../../chunks/shared.js-HQ0rfhm4.js';
24
- import '../../chunks/internal2.js-CaZaz-a9.js';
24
+ import '../../chunks/internal2.js-DbC8VGqD.js';
25
25
  import '../../chunks/utils.js-CAdNO8Tu.js';
26
26
 
27
27
  //#region src/lib/paraglide/messages/abort.js
@@ -1336,6 +1336,38 @@ var browserreload1 = ((inputs = {}, options = {}) => {
1336
1336
  return en_browserreload1();
1337
1337
  });
1338
1338
  //#endregion
1339
+ //#region src/lib/paraglide/messages/browsersessiondead2.js
1340
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1341
+ /** @typedef {{}} Browsersessiondead2Inputs */
1342
+ var en_browsersessiondead2 = () => {
1343
+ return `glass session closed — the browser behind this panel is gone`;
1344
+ };
1345
+ var zh_browsersessiondead2 = () => {
1346
+ return `glass 会话已关闭 — 该面板背后的浏览器已不存在`;
1347
+ };
1348
+ var id_browsersessiondead2 = () => {
1349
+ return `sesi glass ditutup — peramban di balik panel ini sudah tiada`;
1350
+ };
1351
+ var es_browsersessiondead2 = () => {
1352
+ return `sesión de glass cerrada — el navegador detrás de este panel ya no existe`;
1353
+ };
1354
+ /**
1355
+ * | output |
1356
+ * | --- |
1357
+ * | "glass session closed — the browser behind this panel is gone" |
1358
+ *
1359
+ * @param {Browsersessiondead2Inputs} inputs
1360
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1361
+ * @returns {LocalizedString}
1362
+ */
1363
+ var browsersessiondead2 = ((inputs = {}, options = {}) => {
1364
+ const locale = options.locale ?? getLocale();
1365
+ if (locale === "zh") return zh_browsersessiondead2();
1366
+ if (locale === "id") return id_browsersessiondead2();
1367
+ if (locale === "es") return es_browsersessiondead2();
1368
+ return en_browsersessiondead2();
1369
+ });
1370
+ //#endregion
1339
1371
  //#region src/lib/paraglide/messages/browsersessionfailed2.js
1340
1372
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1341
1373
  /** @typedef {{ reason: NonNullable<unknown> }} Browsersessionfailed2Inputs */
@@ -1464,6 +1496,38 @@ var browserwaitingframes2 = ((inputs = {}, options = {}) => {
1464
1496
  return en_browserwaitingframes2();
1465
1497
  });
1466
1498
  //#endregion
1499
+ //#region src/lib/paraglide/messages/browserzoom1.js
1500
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1501
+ /** @typedef {{}} Browserzoom1Inputs */
1502
+ var en_browserzoom1 = () => {
1503
+ return `Content zoom`;
1504
+ };
1505
+ var zh_browserzoom1 = () => {
1506
+ return `内容缩放`;
1507
+ };
1508
+ var id_browserzoom1 = () => {
1509
+ return `Zoom konten`;
1510
+ };
1511
+ var es_browserzoom1 = () => {
1512
+ return `Zoom de contenido`;
1513
+ };
1514
+ /**
1515
+ * | output |
1516
+ * | --- |
1517
+ * | "Content zoom" |
1518
+ *
1519
+ * @param {Browserzoom1Inputs} inputs
1520
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1521
+ * @returns {LocalizedString}
1522
+ */
1523
+ var browserzoom1 = ((inputs = {}, options = {}) => {
1524
+ const locale = options.locale ?? getLocale();
1525
+ if (locale === "zh") return zh_browserzoom1();
1526
+ if (locale === "id") return id_browserzoom1();
1527
+ if (locale === "es") return es_browserzoom1();
1528
+ return en_browserzoom1();
1529
+ });
1530
+ //#endregion
1467
1531
  //#region src/lib/paraglide/messages/cachehit1.js
1468
1532
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1469
1533
  /** @typedef {{}} Cachehit1Inputs */
@@ -1688,6 +1752,70 @@ var choosefolder1 = ((inputs = {}, options = {}) => {
1688
1752
  return en_choosefolder1();
1689
1753
  });
1690
1754
  //#endregion
1755
+ //#region src/lib/paraglide/messages/chordarmedlabel2.js
1756
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1757
+ /** @typedef {{}} Chordarmedlabel2Inputs */
1758
+ var en_chordarmedlabel2 = () => {
1759
+ return `Alt+S chord armed — next key`;
1760
+ };
1761
+ var zh_chordarmedlabel2 = () => {
1762
+ return `Alt+S 组合键已就绪 — 下一个按键`;
1763
+ };
1764
+ var id_chordarmedlabel2 = () => {
1765
+ return `Kord Alt+S armed — tombol berikutnya`;
1766
+ };
1767
+ var es_chordarmedlabel2 = () => {
1768
+ return `Acordo Alt+S armado — siguiente tecla`;
1769
+ };
1770
+ /**
1771
+ * | output |
1772
+ * | --- |
1773
+ * | "Alt+S chord armed — next key" |
1774
+ *
1775
+ * @param {Chordarmedlabel2Inputs} inputs
1776
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1777
+ * @returns {LocalizedString}
1778
+ */
1779
+ var chordarmedlabel2 = ((inputs = {}, options = {}) => {
1780
+ const locale = options.locale ?? getLocale();
1781
+ if (locale === "zh") return zh_chordarmedlabel2();
1782
+ if (locale === "id") return id_chordarmedlabel2();
1783
+ if (locale === "es") return es_chordarmedlabel2();
1784
+ return en_chordarmedlabel2();
1785
+ });
1786
+ //#endregion
1787
+ //#region src/lib/paraglide/messages/chordarmedtitle2.js
1788
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1789
+ /** @typedef {{}} Chordarmedtitle2Inputs */
1790
+ var en_chordarmedtitle2 = () => {
1791
+ return `Alt+S armed`;
1792
+ };
1793
+ var zh_chordarmedtitle2 = () => {
1794
+ return `Alt+S 已就绪`;
1795
+ };
1796
+ var id_chordarmedtitle2 = () => {
1797
+ return `Alt+S diarmed`;
1798
+ };
1799
+ var es_chordarmedtitle2 = () => {
1800
+ return `Alt+S armado`;
1801
+ };
1802
+ /**
1803
+ * | output |
1804
+ * | --- |
1805
+ * | "Alt+S armed" |
1806
+ *
1807
+ * @param {Chordarmedtitle2Inputs} inputs
1808
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1809
+ * @returns {LocalizedString}
1810
+ */
1811
+ var chordarmedtitle2 = ((inputs = {}, options = {}) => {
1812
+ const locale = options.locale ?? getLocale();
1813
+ if (locale === "zh") return zh_chordarmedtitle2();
1814
+ if (locale === "id") return id_chordarmedtitle2();
1815
+ if (locale === "es") return es_chordarmedtitle2();
1816
+ return en_chordarmedtitle2();
1817
+ });
1818
+ //#endregion
1691
1819
  //#region src/lib/paraglide/messages/clearbtn1.js
1692
1820
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1693
1821
  /** @typedef {{}} Clearbtn1Inputs */
@@ -3288,6 +3416,38 @@ var ctxchipcontext2 = ((inputs = {}, options = {}) => {
3288
3416
  return en_ctxchipcontext2();
3289
3417
  });
3290
3418
  //#endregion
3419
+ //#region src/lib/paraglide/messages/ctxchipgoal2.js
3420
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
3421
+ /** @typedef {{}} Ctxchipgoal2Inputs */
3422
+ var en_ctxchipgoal2 = () => {
3423
+ return `goal`;
3424
+ };
3425
+ var zh_ctxchipgoal2 = () => {
3426
+ return `目标`;
3427
+ };
3428
+ var id_ctxchipgoal2 = () => {
3429
+ return `tujuan`;
3430
+ };
3431
+ var es_ctxchipgoal2 = () => {
3432
+ return `meta`;
3433
+ };
3434
+ /**
3435
+ * | output |
3436
+ * | --- |
3437
+ * | "goal" |
3438
+ *
3439
+ * @param {Ctxchipgoal2Inputs} inputs
3440
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
3441
+ * @returns {LocalizedString}
3442
+ */
3443
+ var ctxchipgoal2 = ((inputs = {}, options = {}) => {
3444
+ const locale = options.locale ?? getLocale();
3445
+ if (locale === "zh") return zh_ctxchipgoal2();
3446
+ if (locale === "id") return id_ctxchipgoal2();
3447
+ if (locale === "es") return es_ctxchipgoal2();
3448
+ return en_ctxchipgoal2();
3449
+ });
3450
+ //#endregion
3291
3451
  //#region src/lib/paraglide/messages/ctxchipinjected2.js
3292
3452
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
3293
3453
  /** @typedef {{}} Ctxchipinjected2Inputs */
@@ -3480,6 +3640,70 @@ var ctxchipskills2 = ((inputs = {}, options = {}) => {
3480
3640
  return en_ctxchipskills2();
3481
3641
  });
3482
3642
  //#endregion
3643
+ //#region src/lib/paraglide/messages/ctxchiptimecontext3.js
3644
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
3645
+ /** @typedef {{}} Ctxchiptimecontext3Inputs */
3646
+ var en_ctxchiptimecontext3 = () => {
3647
+ return `time context`;
3648
+ };
3649
+ var zh_ctxchiptimecontext3 = () => {
3650
+ return `时间上下文`;
3651
+ };
3652
+ var id_ctxchiptimecontext3 = () => {
3653
+ return `konteks waktu`;
3654
+ };
3655
+ var es_ctxchiptimecontext3 = () => {
3656
+ return `contexto temporal`;
3657
+ };
3658
+ /**
3659
+ * | output |
3660
+ * | --- |
3661
+ * | "time context" |
3662
+ *
3663
+ * @param {Ctxchiptimecontext3Inputs} inputs
3664
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
3665
+ * @returns {LocalizedString}
3666
+ */
3667
+ var ctxchiptimecontext3 = ((inputs = {}, options = {}) => {
3668
+ const locale = options.locale ?? getLocale();
3669
+ if (locale === "zh") return zh_ctxchiptimecontext3();
3670
+ if (locale === "id") return id_ctxchiptimecontext3();
3671
+ if (locale === "es") return es_ctxchiptimecontext3();
3672
+ return en_ctxchiptimecontext3();
3673
+ });
3674
+ //#endregion
3675
+ //#region src/lib/paraglide/messages/ctxchiptoolgoal3.js
3676
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
3677
+ /** @typedef {{}} Ctxchiptoolgoal3Inputs */
3678
+ var en_ctxchiptoolgoal3 = () => {
3679
+ return `tool goal`;
3680
+ };
3681
+ var zh_ctxchiptoolgoal3 = () => {
3682
+ return `工具目标`;
3683
+ };
3684
+ var id_ctxchiptoolgoal3 = () => {
3685
+ return `tujuan alat`;
3686
+ };
3687
+ var es_ctxchiptoolgoal3 = () => {
3688
+ return `meta de herramienta`;
3689
+ };
3690
+ /**
3691
+ * | output |
3692
+ * | --- |
3693
+ * | "tool goal" |
3694
+ *
3695
+ * @param {Ctxchiptoolgoal3Inputs} inputs
3696
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
3697
+ * @returns {LocalizedString}
3698
+ */
3699
+ var ctxchiptoolgoal3 = ((inputs = {}, options = {}) => {
3700
+ const locale = options.locale ?? getLocale();
3701
+ if (locale === "zh") return zh_ctxchiptoolgoal3();
3702
+ if (locale === "id") return id_ctxchiptoolgoal3();
3703
+ if (locale === "es") return es_ctxchiptoolgoal3();
3704
+ return en_ctxchiptoolgoal3();
3705
+ });
3706
+ //#endregion
3483
3707
  //#region src/lib/paraglide/messages/ctxchipuserapproval3.js
3484
3708
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
3485
3709
  /** @typedef {{}} Ctxchipuserapproval3Inputs */
@@ -4952,38 +5176,6 @@ var fileeyediff2 = ((inputs = {}, options = {}) => {
4952
5176
  return en_fileeyediff2();
4953
5177
  });
4954
5178
  //#endregion
4955
- //#region src/lib/paraglide/messages/fileeyeedit2.js
4956
- /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
4957
- /** @typedef {{}} Fileeyeedit2Inputs */
4958
- var en_fileeyeedit2 = () => {
4959
- return `Edit`;
4960
- };
4961
- var zh_fileeyeedit2 = () => {
4962
- return `编辑`;
4963
- };
4964
- var id_fileeyeedit2 = () => {
4965
- return `Edit`;
4966
- };
4967
- var es_fileeyeedit2 = () => {
4968
- return `Editar`;
4969
- };
4970
- /**
4971
- * | output |
4972
- * | --- |
4973
- * | "Edit" |
4974
- *
4975
- * @param {Fileeyeedit2Inputs} inputs
4976
- * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
4977
- * @returns {LocalizedString}
4978
- */
4979
- var fileeyeedit2 = ((inputs = {}, options = {}) => {
4980
- const locale = options.locale ?? getLocale();
4981
- if (locale === "zh") return zh_fileeyeedit2();
4982
- if (locale === "id") return id_fileeyeedit2();
4983
- if (locale === "es") return es_fileeyeedit2();
4984
- return en_fileeyeedit2();
4985
- });
4986
- //#endregion
4987
5179
  //#region src/lib/paraglide/messages/fileeyeexternalchange3.js
4988
5180
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
4989
5181
  /** @typedef {{}} Fileeyeexternalchange3Inputs */
@@ -5048,6 +5240,38 @@ var fileeyenewfile3 = ((inputs = {}, options = {}) => {
5048
5240
  return en_fileeyenewfile3();
5049
5241
  });
5050
5242
  //#endregion
5243
+ //#region src/lib/paraglide/messages/fileeyepreview2.js
5244
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
5245
+ /** @typedef {{}} Fileeyepreview2Inputs */
5246
+ var en_fileeyepreview2 = () => {
5247
+ return `Preview`;
5248
+ };
5249
+ var zh_fileeyepreview2 = () => {
5250
+ return `预览`;
5251
+ };
5252
+ var id_fileeyepreview2 = () => {
5253
+ return `Pratinjau`;
5254
+ };
5255
+ var es_fileeyepreview2 = () => {
5256
+ return `Vista previa`;
5257
+ };
5258
+ /**
5259
+ * | output |
5260
+ * | --- |
5261
+ * | "Preview" |
5262
+ *
5263
+ * @param {Fileeyepreview2Inputs} inputs
5264
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
5265
+ * @returns {LocalizedString}
5266
+ */
5267
+ var fileeyepreview2 = ((inputs = {}, options = {}) => {
5268
+ const locale = options.locale ?? getLocale();
5269
+ if (locale === "zh") return zh_fileeyepreview2();
5270
+ if (locale === "id") return id_fileeyepreview2();
5271
+ if (locale === "es") return es_fileeyepreview2();
5272
+ return en_fileeyepreview2();
5273
+ });
5274
+ //#endregion
5051
5275
  //#region src/lib/paraglide/messages/fileeyereadonly3.js
5052
5276
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
5053
5277
  /** @typedef {{}} Fileeyereadonly3Inputs */
@@ -6264,6 +6488,38 @@ var injectedtitle1 = ((inputs = {}, options = {}) => {
6264
6488
  return en_injectedtitle1();
6265
6489
  });
6266
6490
  //#endregion
6491
+ //#region src/lib/paraglide/messages/jobtailempty2.js
6492
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
6493
+ /** @typedef {{}} Jobtailempty2Inputs */
6494
+ var en_jobtailempty2 = () => {
6495
+ return `no output — the command wrote nothing to the job's log`;
6496
+ };
6497
+ var zh_jobtailempty2 = () => {
6498
+ return `无输出 — 命令未向作业日志写入任何内容`;
6499
+ };
6500
+ var id_jobtailempty2 = () => {
6501
+ return `tidak ada output — perintah tidak menulis apa pun ke log pekerjaan`;
6502
+ };
6503
+ var es_jobtailempty2 = () => {
6504
+ return `sin salida — el comando no escribió nada en el registro del trabajo`;
6505
+ };
6506
+ /**
6507
+ * | output |
6508
+ * | --- |
6509
+ * | "no output — the command wrote nothing to the job's log" |
6510
+ *
6511
+ * @param {Jobtailempty2Inputs} inputs
6512
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
6513
+ * @returns {LocalizedString}
6514
+ */
6515
+ var jobtailempty2 = ((inputs = {}, options = {}) => {
6516
+ const locale = options.locale ?? getLocale();
6517
+ if (locale === "zh") return zh_jobtailempty2();
6518
+ if (locale === "id") return id_jobtailempty2();
6519
+ if (locale === "es") return es_jobtailempty2();
6520
+ return en_jobtailempty2();
6521
+ });
6522
+ //#endregion
6267
6523
  //#region src/lib/paraglide/messages/jobtailwaiting2.js
6268
6524
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
6269
6525
  /** @typedef {{}} Jobtailwaiting2Inputs */
@@ -8632,6 +8888,38 @@ var planmode1 = ((inputs = {}, options = {}) => {
8632
8888
  return en_planmode1();
8633
8889
  });
8634
8890
  //#endregion
8891
+ //#region src/lib/paraglide/messages/pluginrackapplynote3.js
8892
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
8893
+ /** @typedef {{}} Pluginrackapplynote3Inputs */
8894
+ var en_pluginrackapplynote3 = () => {
8895
+ return `The apply finished while the floor was down — the list below is already refreshed.`;
8896
+ };
8897
+ var zh_pluginrackapplynote3 = () => {
8898
+ return `应用已在页面下线期间完成 — 下面的列表已是最新。`;
8899
+ };
8900
+ var id_pluginrackapplynote3 = () => {
8901
+ return `Penerapan selesai saat lantai mati — daftar di bawah sudah diperbarui.`;
8902
+ };
8903
+ var es_pluginrackapplynote3 = () => {
8904
+ return `La aplicación terminó mientras el piso estaba caído — la lista de abajo ya está actualizada.`;
8905
+ };
8906
+ /**
8907
+ * | output |
8908
+ * | --- |
8909
+ * | "The apply finished while the floor was down — the list below is already refreshed." |
8910
+ *
8911
+ * @param {Pluginrackapplynote3Inputs} inputs
8912
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
8913
+ * @returns {LocalizedString}
8914
+ */
8915
+ var pluginrackapplynote3 = ((inputs = {}, options = {}) => {
8916
+ const locale = options.locale ?? getLocale();
8917
+ if (locale === "zh") return zh_pluginrackapplynote3();
8918
+ if (locale === "id") return id_pluginrackapplynote3();
8919
+ if (locale === "es") return es_pluginrackapplynote3();
8920
+ return en_pluginrackapplynote3();
8921
+ });
8922
+ //#endregion
8635
8923
  //#region src/lib/paraglide/messages/pluginrackapplying2.js
8636
8924
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
8637
8925
  /** @typedef {{}} Pluginrackapplying2Inputs */
@@ -13176,6 +13464,134 @@ var terminaltabclose2 = ((inputs = {}, options = {}) => {
13176
13464
  return en_terminaltabclose2();
13177
13465
  });
13178
13466
  //#endregion
13467
+ //#region src/lib/paraglide/messages/terminaltabsclear2.js
13468
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
13469
+ /** @typedef {{}} Terminaltabsclear2Inputs */
13470
+ var en_terminaltabsclear2 = () => {
13471
+ return `Clear tabs`;
13472
+ };
13473
+ var zh_terminaltabsclear2 = () => {
13474
+ return `清除标签`;
13475
+ };
13476
+ var id_terminaltabsclear2 = () => {
13477
+ return `Bersihkan tab`;
13478
+ };
13479
+ var es_terminaltabsclear2 = () => {
13480
+ return `Limpiar pestañas`;
13481
+ };
13482
+ /**
13483
+ * | output |
13484
+ * | --- |
13485
+ * | "Clear tabs" |
13486
+ *
13487
+ * @param {Terminaltabsclear2Inputs} inputs
13488
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
13489
+ * @returns {LocalizedString}
13490
+ */
13491
+ var terminaltabsclear2 = ((inputs = {}, options = {}) => {
13492
+ const locale = options.locale ?? getLocale();
13493
+ if (locale === "zh") return zh_terminaltabsclear2();
13494
+ if (locale === "id") return id_terminaltabsclear2();
13495
+ if (locale === "es") return es_terminaltabsclear2();
13496
+ return en_terminaltabsclear2();
13497
+ });
13498
+ //#endregion
13499
+ //#region src/lib/paraglide/messages/terminaltabsclearall3.js
13500
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
13501
+ /** @typedef {{}} Terminaltabsclearall3Inputs */
13502
+ var en_terminaltabsclearall3 = () => {
13503
+ return `Clear all`;
13504
+ };
13505
+ var zh_terminaltabsclearall3 = () => {
13506
+ return `全部清除`;
13507
+ };
13508
+ var id_terminaltabsclearall3 = () => {
13509
+ return `Bersihkan semua`;
13510
+ };
13511
+ var es_terminaltabsclearall3 = () => {
13512
+ return `Limpiar todo`;
13513
+ };
13514
+ /**
13515
+ * | output |
13516
+ * | --- |
13517
+ * | "Clear all" |
13518
+ *
13519
+ * @param {Terminaltabsclearall3Inputs} inputs
13520
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
13521
+ * @returns {LocalizedString}
13522
+ */
13523
+ var terminaltabsclearall3 = ((inputs = {}, options = {}) => {
13524
+ const locale = options.locale ?? getLocale();
13525
+ if (locale === "zh") return zh_terminaltabsclearall3();
13526
+ if (locale === "id") return id_terminaltabsclearall3();
13527
+ if (locale === "es") return es_terminaltabsclearall3();
13528
+ return en_terminaltabsclearall3();
13529
+ });
13530
+ //#endregion
13531
+ //#region src/lib/paraglide/messages/terminaltabsclearjobs3.js
13532
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
13533
+ /** @typedef {{}} Terminaltabsclearjobs3Inputs */
13534
+ var en_terminaltabsclearjobs3 = () => {
13535
+ return `Clear jobs`;
13536
+ };
13537
+ var zh_terminaltabsclearjobs3 = () => {
13538
+ return `清除任务`;
13539
+ };
13540
+ var id_terminaltabsclearjobs3 = () => {
13541
+ return `Bersihkan job`;
13542
+ };
13543
+ var es_terminaltabsclearjobs3 = () => {
13544
+ return `Limpiar jobs`;
13545
+ };
13546
+ /**
13547
+ * | output |
13548
+ * | --- |
13549
+ * | "Clear jobs" |
13550
+ *
13551
+ * @param {Terminaltabsclearjobs3Inputs} inputs
13552
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
13553
+ * @returns {LocalizedString}
13554
+ */
13555
+ var terminaltabsclearjobs3 = ((inputs = {}, options = {}) => {
13556
+ const locale = options.locale ?? getLocale();
13557
+ if (locale === "zh") return zh_terminaltabsclearjobs3();
13558
+ if (locale === "id") return id_terminaltabsclearjobs3();
13559
+ if (locale === "es") return es_terminaltabsclearjobs3();
13560
+ return en_terminaltabsclearjobs3();
13561
+ });
13562
+ //#endregion
13563
+ //#region src/lib/paraglide/messages/terminaltabsclearterminals3.js
13564
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
13565
+ /** @typedef {{}} Terminaltabsclearterminals3Inputs */
13566
+ var en_terminaltabsclearterminals3 = () => {
13567
+ return `Clear terminals`;
13568
+ };
13569
+ var zh_terminaltabsclearterminals3 = () => {
13570
+ return `清除终端`;
13571
+ };
13572
+ var id_terminaltabsclearterminals3 = () => {
13573
+ return `Bersihkan terminal`;
13574
+ };
13575
+ var es_terminaltabsclearterminals3 = () => {
13576
+ return `Limpiar terminales`;
13577
+ };
13578
+ /**
13579
+ * | output |
13580
+ * | --- |
13581
+ * | "Clear terminals" |
13582
+ *
13583
+ * @param {Terminaltabsclearterminals3Inputs} inputs
13584
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
13585
+ * @returns {LocalizedString}
13586
+ */
13587
+ var terminaltabsclearterminals3 = ((inputs = {}, options = {}) => {
13588
+ const locale = options.locale ?? getLocale();
13589
+ if (locale === "zh") return zh_terminaltabsclearterminals3();
13590
+ if (locale === "id") return id_terminaltabsclearterminals3();
13591
+ if (locale === "es") return es_terminaltabsclearterminals3();
13592
+ return en_terminaltabsclearterminals3();
13593
+ });
13594
+ //#endregion
13179
13595
  //#region src/lib/paraglide/messages/text.js
13180
13596
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
13181
13597
  /** @typedef {{}} TextInputs */
@@ -14584,6 +15000,38 @@ var workspaceexplorerempty2 = ((inputs = {}, options = {}) => {
14584
15000
  return en_workspaceexplorerempty2();
14585
15001
  });
14586
15002
  //#endregion
15003
+ //#region src/lib/paraglide/messages/workspaceexplorerhide2.js
15004
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
15005
+ /** @typedef {{}} Workspaceexplorerhide2Inputs */
15006
+ var en_workspaceexplorerhide2 = () => {
15007
+ return `Hide explorer`;
15008
+ };
15009
+ var zh_workspaceexplorerhide2 = () => {
15010
+ return `隐藏资源管理器`;
15011
+ };
15012
+ var id_workspaceexplorerhide2 = () => {
15013
+ return `Sembunyikan explorer`;
15014
+ };
15015
+ var es_workspaceexplorerhide2 = () => {
15016
+ return `Ocultar explorador`;
15017
+ };
15018
+ /**
15019
+ * | output |
15020
+ * | --- |
15021
+ * | "Hide explorer" |
15022
+ *
15023
+ * @param {Workspaceexplorerhide2Inputs} inputs
15024
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
15025
+ * @returns {LocalizedString}
15026
+ */
15027
+ var workspaceexplorerhide2 = ((inputs = {}, options = {}) => {
15028
+ const locale = options.locale ?? getLocale();
15029
+ if (locale === "zh") return zh_workspaceexplorerhide2();
15030
+ if (locale === "id") return id_workspaceexplorerhide2();
15031
+ if (locale === "es") return es_workspaceexplorerhide2();
15032
+ return en_workspaceexplorerhide2();
15033
+ });
15034
+ //#endregion
14587
15035
  //#region src/lib/paraglide/messages/workspaceexplorerloadfailed3.js
14588
15036
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
14589
15037
  /** @typedef {{}} Workspaceexplorerloadfailed3Inputs */
@@ -14648,6 +15096,38 @@ var workspaceexplorerloading2 = ((inputs = {}, options = {}) => {
14648
15096
  return en_workspaceexplorerloading2();
14649
15097
  });
14650
15098
  //#endregion
15099
+ //#region src/lib/paraglide/messages/workspaceexplorershow2.js
15100
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
15101
+ /** @typedef {{}} Workspaceexplorershow2Inputs */
15102
+ var en_workspaceexplorershow2 = () => {
15103
+ return `Show explorer`;
15104
+ };
15105
+ var zh_workspaceexplorershow2 = () => {
15106
+ return `显示资源管理器`;
15107
+ };
15108
+ var id_workspaceexplorershow2 = () => {
15109
+ return `Tampilkan explorer`;
15110
+ };
15111
+ var es_workspaceexplorershow2 = () => {
15112
+ return `Mostrar explorador`;
15113
+ };
15114
+ /**
15115
+ * | output |
15116
+ * | --- |
15117
+ * | "Show explorer" |
15118
+ *
15119
+ * @param {Workspaceexplorershow2Inputs} inputs
15120
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
15121
+ * @returns {LocalizedString}
15122
+ */
15123
+ var workspaceexplorershow2 = ((inputs = {}, options = {}) => {
15124
+ const locale = options.locale ?? getLocale();
15125
+ if (locale === "zh") return zh_workspaceexplorershow2();
15126
+ if (locale === "id") return id_workspaceexplorershow2();
15127
+ if (locale === "es") return es_workspaceexplorershow2();
15128
+ return en_workspaceexplorershow2();
15129
+ });
15130
+ //#endregion
14651
15131
  //#region src/lib/paraglide/messages/workspaceexplorertitle2.js
14652
15132
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
14653
15133
  /** @typedef {{}} Workspaceexplorertitle2Inputs */
@@ -14712,6 +15192,38 @@ var workspaceexplorertruncated2 = ((inputs = {}, options = {}) => {
14712
15192
  return en_workspaceexplorertruncated2();
14713
15193
  });
14714
15194
  //#endregion
15195
+ //#region src/lib/paraglide/messages/workspacefilecancel2.js
15196
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
15197
+ /** @typedef {{}} Workspacefilecancel2Inputs */
15198
+ var en_workspacefilecancel2 = () => {
15199
+ return `Cancel`;
15200
+ };
15201
+ var zh_workspacefilecancel2 = () => {
15202
+ return `取消`;
15203
+ };
15204
+ var id_workspacefilecancel2 = () => {
15205
+ return `Batal`;
15206
+ };
15207
+ var es_workspacefilecancel2 = () => {
15208
+ return `Cancelar`;
15209
+ };
15210
+ /**
15211
+ * | output |
15212
+ * | --- |
15213
+ * | "Cancel" |
15214
+ *
15215
+ * @param {Workspacefilecancel2Inputs} inputs
15216
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
15217
+ * @returns {LocalizedString}
15218
+ */
15219
+ var workspacefilecancel2 = ((inputs = {}, options = {}) => {
15220
+ const locale = options.locale ?? getLocale();
15221
+ if (locale === "zh") return zh_workspacefilecancel2();
15222
+ if (locale === "id") return id_workspacefilecancel2();
15223
+ if (locale === "es") return es_workspacefilecancel2();
15224
+ return en_workspacefilecancel2();
15225
+ });
15226
+ //#endregion
14715
15227
  //#region src/lib/paraglide/messages/workspacefilecopyfilename3.js
14716
15228
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
14717
15229
  /** @typedef {{}} Workspacefilecopyfilename3Inputs */
@@ -14968,6 +15480,38 @@ var workspacefilesaving2 = ((inputs = {}, options = {}) => {
14968
15480
  return en_workspacefilesaving2();
14969
15481
  });
14970
15482
  //#endregion
15483
+ //#region src/lib/paraglide/messages/workspacefilesource2.js
15484
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
15485
+ /** @typedef {{}} Workspacefilesource2Inputs */
15486
+ var en_workspacefilesource2 = () => {
15487
+ return `Source`;
15488
+ };
15489
+ var zh_workspacefilesource2 = () => {
15490
+ return `源码`;
15491
+ };
15492
+ var id_workspacefilesource2 = () => {
15493
+ return `Kode`;
15494
+ };
15495
+ var es_workspacefilesource2 = () => {
15496
+ return `Código`;
15497
+ };
15498
+ /**
15499
+ * | output |
15500
+ * | --- |
15501
+ * | "Source" |
15502
+ *
15503
+ * @param {Workspacefilesource2Inputs} inputs
15504
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
15505
+ * @returns {LocalizedString}
15506
+ */
15507
+ var workspacefilesource2 = ((inputs = {}, options = {}) => {
15508
+ const locale = options.locale ?? getLocale();
15509
+ if (locale === "zh") return zh_workspacefilesource2();
15510
+ if (locale === "id") return id_workspacefilesource2();
15511
+ if (locale === "es") return es_workspacefilesource2();
15512
+ return en_workspacefilesource2();
15513
+ });
15514
+ //#endregion
14971
15515
  //#region src/lib/paraglide/messages/workspacefilestale2.js
14972
15516
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
14973
15517
  /** @typedef {{}} Workspacefilestale2Inputs */
@@ -15000,6 +15544,102 @@ var workspacefilestale2 = ((inputs = {}, options = {}) => {
15000
15544
  return en_workspacefilestale2();
15001
15545
  });
15002
15546
  //#endregion
15547
+ //#region src/lib/paraglide/messages/workspacefiletabsclear3.js
15548
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
15549
+ /** @typedef {{}} Workspacefiletabsclear3Inputs */
15550
+ var en_workspacefiletabsclear3 = () => {
15551
+ return `Clear tabs`;
15552
+ };
15553
+ var zh_workspacefiletabsclear3 = () => {
15554
+ return `清除标签`;
15555
+ };
15556
+ var id_workspacefiletabsclear3 = () => {
15557
+ return `Bersihkan tab`;
15558
+ };
15559
+ var es_workspacefiletabsclear3 = () => {
15560
+ return `Limpiar pestañas`;
15561
+ };
15562
+ /**
15563
+ * | output |
15564
+ * | --- |
15565
+ * | "Clear tabs" |
15566
+ *
15567
+ * @param {Workspacefiletabsclear3Inputs} inputs
15568
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
15569
+ * @returns {LocalizedString}
15570
+ */
15571
+ var workspacefiletabsclear3 = ((inputs = {}, options = {}) => {
15572
+ const locale = options.locale ?? getLocale();
15573
+ if (locale === "zh") return zh_workspacefiletabsclear3();
15574
+ if (locale === "id") return id_workspacefiletabsclear3();
15575
+ if (locale === "es") return es_workspacefiletabsclear3();
15576
+ return en_workspacefiletabsclear3();
15577
+ });
15578
+ //#endregion
15579
+ //#region src/lib/paraglide/messages/workspacefiletabsclearall4.js
15580
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
15581
+ /** @typedef {{}} Workspacefiletabsclearall4Inputs */
15582
+ var en_workspacefiletabsclearall4 = () => {
15583
+ return `Clear all`;
15584
+ };
15585
+ var zh_workspacefiletabsclearall4 = () => {
15586
+ return `全部清除`;
15587
+ };
15588
+ var id_workspacefiletabsclearall4 = () => {
15589
+ return `Bersihkan semua`;
15590
+ };
15591
+ var es_workspacefiletabsclearall4 = () => {
15592
+ return `Limpiar todo`;
15593
+ };
15594
+ /**
15595
+ * | output |
15596
+ * | --- |
15597
+ * | "Clear all" |
15598
+ *
15599
+ * @param {Workspacefiletabsclearall4Inputs} inputs
15600
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
15601
+ * @returns {LocalizedString}
15602
+ */
15603
+ var workspacefiletabsclearall4 = ((inputs = {}, options = {}) => {
15604
+ const locale = options.locale ?? getLocale();
15605
+ if (locale === "zh") return zh_workspacefiletabsclearall4();
15606
+ if (locale === "id") return id_workspacefiletabsclearall4();
15607
+ if (locale === "es") return es_workspacefiletabsclearall4();
15608
+ return en_workspacefiletabsclearall4();
15609
+ });
15610
+ //#endregion
15611
+ //#region src/lib/paraglide/messages/workspacefiletabsclearnondirty5.js
15612
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
15613
+ /** @typedef {{}} Workspacefiletabsclearnondirty5Inputs */
15614
+ var en_workspacefiletabsclearnondirty5 = () => {
15615
+ return `Clear non-dirty`;
15616
+ };
15617
+ var zh_workspacefiletabsclearnondirty5 = () => {
15618
+ return `清除未修改`;
15619
+ };
15620
+ var id_workspacefiletabsclearnondirty5 = () => {
15621
+ return `Bersihkan yang tidak berubah`;
15622
+ };
15623
+ var es_workspacefiletabsclearnondirty5 = () => {
15624
+ return `Limpiar sin cambios`;
15625
+ };
15626
+ /**
15627
+ * | output |
15628
+ * | --- |
15629
+ * | "Clear non-dirty" |
15630
+ *
15631
+ * @param {Workspacefiletabsclearnondirty5Inputs} inputs
15632
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
15633
+ * @returns {LocalizedString}
15634
+ */
15635
+ var workspacefiletabsclearnondirty5 = ((inputs = {}, options = {}) => {
15636
+ const locale = options.locale ?? getLocale();
15637
+ if (locale === "zh") return zh_workspacefiletabsclearnondirty5();
15638
+ if (locale === "id") return id_workspacefiletabsclearnondirty5();
15639
+ if (locale === "es") return es_workspacefiletabsclearnondirty5();
15640
+ return en_workspacefiletabsclearnondirty5();
15641
+ });
15642
+ //#endregion
15003
15643
  //#region src/lib/paraglide/messages/workspacefiletruncated2.js
15004
15644
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
15005
15645
  /** @typedef {{}} Workspacefiletruncated2Inputs */
@@ -15204,10 +15844,12 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15204
15844
  browserOpenTitle: () => browseropentitle2,
15205
15845
  browserPanelTitle: () => browserpaneltitle2,
15206
15846
  browserReload: () => browserreload1,
15847
+ browserSessionDead: () => browsersessiondead2,
15207
15848
  browserSessionFailed: () => browsersessionfailed2,
15208
15849
  browserTabCloseTitle: () => browsertabclosetitle3,
15209
15850
  browserUrlPlaceholder: () => browserurlplaceholder2,
15210
15851
  browserWaitingFrames: () => browserwaitingframes2,
15852
+ browserZoom: () => browserzoom1,
15211
15853
  cacheHit: () => cachehit1,
15212
15854
  cachedInput: () => cachedinput1,
15213
15855
  cancel: () => cancel,
@@ -15215,6 +15857,8 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15215
15857
  catalogUnavailable: () => catalogunavailable1,
15216
15858
  chatButtonMode: () => chatbuttonmode2,
15217
15859
  chooseFolder: () => choosefolder1,
15860
+ chordArmedLabel: () => chordarmedlabel2,
15861
+ chordArmedTitle: () => chordarmedtitle2,
15218
15862
  clearBtn: () => clearbtn1,
15219
15863
  clearDateFilter: () => cleardatefilter2,
15220
15864
  clearFilter: () => clearfilter1,
@@ -15265,12 +15909,15 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15265
15909
  creating: () => creating,
15266
15910
  ctxChipCompact: () => ctxchipcompact2,
15267
15911
  ctxChipContext: () => ctxchipcontext2,
15912
+ ctxChipGoal: () => ctxchipgoal2,
15268
15913
  ctxChipInjected: () => ctxchipinjected2,
15269
15914
  ctxChipInstructions: () => ctxchipinstructions2,
15270
15915
  ctxChipPlugin: () => ctxchipplugin2,
15271
15916
  ctxChipRecall: () => ctxchiprecall2,
15272
15917
  ctxChipSkill: () => ctxchipskill2,
15273
15918
  ctxChipSkills: () => ctxchipskills2,
15919
+ ctxChipTimeContext: () => ctxchiptimecontext3,
15920
+ ctxChipToolGoal: () => ctxchiptoolgoal3,
15274
15921
  ctxChipUserApproval: () => ctxchipuserapproval3,
15275
15922
  ctxSnapshotSupersedes: () => ctxsnapshotsupersedes2,
15276
15923
  ctxWindowTitle: () => ctxwindowtitle2,
@@ -15318,9 +15965,9 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15318
15965
  failedToLoad: () => failedtoload2,
15319
15966
  feedNext: () => feednext1,
15320
15967
  fileEyeDiff: () => fileeyediff2,
15321
- fileEyeEdit: () => fileeyeedit2,
15322
15968
  fileEyeExternalChange: () => fileeyeexternalchange3,
15323
15969
  fileEyeNewFile: () => fileeyenewfile3,
15970
+ fileEyePreview: () => fileeyepreview2,
15324
15971
  fileEyeReadOnly: () => fileeyereadonly3,
15325
15972
  fileEyeToggleLabel: () => fileeyetogglelabel3,
15326
15973
  filterBy: () => filterby1,
@@ -15359,6 +16006,7 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15359
16006
  impliedNote: () => impliednote1,
15360
16007
  injectedFiles: () => injectedfiles1,
15361
16008
  injectedTitle: () => injectedtitle1,
16009
+ jobTailEmpty: () => jobtailempty2,
15362
16010
  jobTailWaiting: () => jobtailwaiting2,
15363
16011
  jobs: () => jobs,
15364
16012
  jobsLiveTitle_one: () => jobslivetitle_one2,
@@ -15433,6 +16081,7 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15433
16081
  pendingAttachments: () => pendingattachments1,
15434
16082
  pickSession: () => picksession1,
15435
16083
  planMode: () => planmode1,
16084
+ pluginRackApplyNote: () => pluginrackapplynote3,
15436
16085
  pluginRackApplying: () => pluginrackapplying2,
15437
16086
  pluginRackBy: () => pluginrackby2,
15438
16087
  pluginRackCollapseAll: () => pluginrackcollapseall3,
@@ -15577,6 +16226,10 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15577
16226
  terminalSettleStdinRead: () => terminalsettlestdinread3,
15578
16227
  terminalSettleTimeout: () => terminalsettletimeout2,
15579
16228
  terminalTabClose: () => terminaltabclose2,
16229
+ terminalTabsClear: () => terminaltabsclear2,
16230
+ terminalTabsClearAll: () => terminaltabsclearall3,
16231
+ terminalTabsClearJobs: () => terminaltabsclearjobs3,
16232
+ terminalTabsClearTerminals: () => terminaltabsclearterminals3,
15580
16233
  text: () => text,
15581
16234
  themeChoice_dark: () => themechoice_dark1,
15582
16235
  themeChoice_light: () => themechoice_light1,
@@ -15622,10 +16275,13 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15622
16275
  workspaceDeleteCost: () => workspacedeletecost2,
15623
16276
  workspaceExplorerCopyWorkspace: () => workspaceexplorercopyworkspace3,
15624
16277
  workspaceExplorerEmpty: () => workspaceexplorerempty2,
16278
+ workspaceExplorerHide: () => workspaceexplorerhide2,
15625
16279
  workspaceExplorerLoadFailed: () => workspaceexplorerloadfailed3,
15626
16280
  workspaceExplorerLoading: () => workspaceexplorerloading2,
16281
+ workspaceExplorerShow: () => workspaceexplorershow2,
15627
16282
  workspaceExplorerTitle: () => workspaceexplorertitle2,
15628
16283
  workspaceExplorerTruncated: () => workspaceexplorertruncated2,
16284
+ workspaceFileCancel: () => workspacefilecancel2,
15629
16285
  workspaceFileCopyFilename: () => workspacefilecopyfilename3,
15630
16286
  workspaceFileDirty: () => workspacefiledirty2,
15631
16287
  workspaceFileEdit: () => workspacefileedit2,
@@ -15634,7 +16290,11 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15634
16290
  workspaceFileSave: () => workspacefilesave2,
15635
16291
  workspaceFileSaveFailed: () => workspacefilesavefailed3,
15636
16292
  workspaceFileSaving: () => workspacefilesaving2,
16293
+ workspaceFileSource: () => workspacefilesource2,
15637
16294
  workspaceFileStale: () => workspacefilestale2,
16295
+ workspaceFileTabsClear: () => workspacefiletabsclear3,
16296
+ workspaceFileTabsClearAll: () => workspacefiletabsclearall4,
16297
+ workspaceFileTabsClearNonDirty: () => workspacefiletabsclearnondirty5,
15638
16298
  workspaceFileTruncated: () => workspacefiletruncated2,
15639
16299
  workspacePanelCommonCopyColumn: () => workspacepanelcommoncopycolumn4,
15640
16300
  workspacePlusAgent: () => workspaceplusagent2,
@@ -15686,10 +16346,12 @@ var messages_exports = /* @__PURE__ */ __exportAll({
15686
16346
  browserOpenTitle: () => browseropentitle2,
15687
16347
  browserPanelTitle: () => browserpaneltitle2,
15688
16348
  browserReload: () => browserreload1,
16349
+ browserSessionDead: () => browsersessiondead2,
15689
16350
  browserSessionFailed: () => browsersessionfailed2,
15690
16351
  browserTabCloseTitle: () => browsertabclosetitle3,
15691
16352
  browserUrlPlaceholder: () => browserurlplaceholder2,
15692
16353
  browserWaitingFrames: () => browserwaitingframes2,
16354
+ browserZoom: () => browserzoom1,
15693
16355
  cacheHit: () => cachehit1,
15694
16356
  cachedInput: () => cachedinput1,
15695
16357
  cancel: () => cancel,
@@ -15697,6 +16359,8 @@ var messages_exports = /* @__PURE__ */ __exportAll({
15697
16359
  catalogUnavailable: () => catalogunavailable1,
15698
16360
  chatButtonMode: () => chatbuttonmode2,
15699
16361
  chooseFolder: () => choosefolder1,
16362
+ chordArmedLabel: () => chordarmedlabel2,
16363
+ chordArmedTitle: () => chordarmedtitle2,
15700
16364
  clearBtn: () => clearbtn1,
15701
16365
  clearDateFilter: () => cleardatefilter2,
15702
16366
  clearFilter: () => clearfilter1,
@@ -15747,12 +16411,15 @@ var messages_exports = /* @__PURE__ */ __exportAll({
15747
16411
  creating: () => creating,
15748
16412
  ctxChipCompact: () => ctxchipcompact2,
15749
16413
  ctxChipContext: () => ctxchipcontext2,
16414
+ ctxChipGoal: () => ctxchipgoal2,
15750
16415
  ctxChipInjected: () => ctxchipinjected2,
15751
16416
  ctxChipInstructions: () => ctxchipinstructions2,
15752
16417
  ctxChipPlugin: () => ctxchipplugin2,
15753
16418
  ctxChipRecall: () => ctxchiprecall2,
15754
16419
  ctxChipSkill: () => ctxchipskill2,
15755
16420
  ctxChipSkills: () => ctxchipskills2,
16421
+ ctxChipTimeContext: () => ctxchiptimecontext3,
16422
+ ctxChipToolGoal: () => ctxchiptoolgoal3,
15756
16423
  ctxChipUserApproval: () => ctxchipuserapproval3,
15757
16424
  ctxSnapshotSupersedes: () => ctxsnapshotsupersedes2,
15758
16425
  ctxWindowTitle: () => ctxwindowtitle2,
@@ -15800,9 +16467,9 @@ var messages_exports = /* @__PURE__ */ __exportAll({
15800
16467
  failedToLoad: () => failedtoload2,
15801
16468
  feedNext: () => feednext1,
15802
16469
  fileEyeDiff: () => fileeyediff2,
15803
- fileEyeEdit: () => fileeyeedit2,
15804
16470
  fileEyeExternalChange: () => fileeyeexternalchange3,
15805
16471
  fileEyeNewFile: () => fileeyenewfile3,
16472
+ fileEyePreview: () => fileeyepreview2,
15806
16473
  fileEyeReadOnly: () => fileeyereadonly3,
15807
16474
  fileEyeToggleLabel: () => fileeyetogglelabel3,
15808
16475
  filterBy: () => filterby1,
@@ -15841,6 +16508,7 @@ var messages_exports = /* @__PURE__ */ __exportAll({
15841
16508
  impliedNote: () => impliednote1,
15842
16509
  injectedFiles: () => injectedfiles1,
15843
16510
  injectedTitle: () => injectedtitle1,
16511
+ jobTailEmpty: () => jobtailempty2,
15844
16512
  jobTailWaiting: () => jobtailwaiting2,
15845
16513
  jobs: () => jobs,
15846
16514
  jobsLiveTitle_one: () => jobslivetitle_one2,
@@ -15916,6 +16584,7 @@ var messages_exports = /* @__PURE__ */ __exportAll({
15916
16584
  pendingAttachments: () => pendingattachments1,
15917
16585
  pickSession: () => picksession1,
15918
16586
  planMode: () => planmode1,
16587
+ pluginRackApplyNote: () => pluginrackapplynote3,
15919
16588
  pluginRackApplying: () => pluginrackapplying2,
15920
16589
  pluginRackBy: () => pluginrackby2,
15921
16590
  pluginRackCollapseAll: () => pluginrackcollapseall3,
@@ -16060,6 +16729,10 @@ var messages_exports = /* @__PURE__ */ __exportAll({
16060
16729
  terminalSettleStdinRead: () => terminalsettlestdinread3,
16061
16730
  terminalSettleTimeout: () => terminalsettletimeout2,
16062
16731
  terminalTabClose: () => terminaltabclose2,
16732
+ terminalTabsClear: () => terminaltabsclear2,
16733
+ terminalTabsClearAll: () => terminaltabsclearall3,
16734
+ terminalTabsClearJobs: () => terminaltabsclearjobs3,
16735
+ terminalTabsClearTerminals: () => terminaltabsclearterminals3,
16063
16736
  text: () => text,
16064
16737
  themeChoice_dark: () => themechoice_dark1,
16065
16738
  themeChoice_light: () => themechoice_light1,
@@ -16105,10 +16778,13 @@ var messages_exports = /* @__PURE__ */ __exportAll({
16105
16778
  workspaceDeleteCost: () => workspacedeletecost2,
16106
16779
  workspaceExplorerCopyWorkspace: () => workspaceexplorercopyworkspace3,
16107
16780
  workspaceExplorerEmpty: () => workspaceexplorerempty2,
16781
+ workspaceExplorerHide: () => workspaceexplorerhide2,
16108
16782
  workspaceExplorerLoadFailed: () => workspaceexplorerloadfailed3,
16109
16783
  workspaceExplorerLoading: () => workspaceexplorerloading2,
16784
+ workspaceExplorerShow: () => workspaceexplorershow2,
16110
16785
  workspaceExplorerTitle: () => workspaceexplorertitle2,
16111
16786
  workspaceExplorerTruncated: () => workspaceexplorertruncated2,
16787
+ workspaceFileCancel: () => workspacefilecancel2,
16112
16788
  workspaceFileCopyFilename: () => workspacefilecopyfilename3,
16113
16789
  workspaceFileDirty: () => workspacefiledirty2,
16114
16790
  workspaceFileEdit: () => workspacefileedit2,
@@ -16117,7 +16793,11 @@ var messages_exports = /* @__PURE__ */ __exportAll({
16117
16793
  workspaceFileSave: () => workspacefilesave2,
16118
16794
  workspaceFileSaveFailed: () => workspacefilesavefailed3,
16119
16795
  workspaceFileSaving: () => workspacefilesaving2,
16796
+ workspaceFileSource: () => workspacefilesource2,
16120
16797
  workspaceFileStale: () => workspacefilestale2,
16798
+ workspaceFileTabsClear: () => workspacefiletabsclear3,
16799
+ workspaceFileTabsClearAll: () => workspacefiletabsclearall4,
16800
+ workspaceFileTabsClearNonDirty: () => workspacefiletabsclearnondirty5,
16121
16801
  workspaceFileTruncated: () => workspacefiletruncated2,
16122
16802
  workspacePanelCommonCopyColumn: () => workspacepanelcommoncopycolumn4,
16123
16803
  workspacePlusAgent: () => workspaceplusagent2,
@@ -16435,6 +17115,24 @@ function Circle_dashed($$renderer, $$props) {
16435
17115
  ]));
16436
17116
  }
16437
17117
  //#endregion
17118
+ //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/circle-plus.svelte
17119
+ function Circle_plus($$renderer, $$props) {
17120
+ let { $$slots, $$events, ...props } = $$props;
17121
+ Icon($$renderer, spread_props([
17122
+ { name: "circle-plus" },
17123
+ props,
17124
+ { iconNode: [
17125
+ ["circle", {
17126
+ "cx": "12",
17127
+ "cy": "12",
17128
+ "r": "10"
17129
+ }],
17130
+ ["path", { "d": "M8 12h8" }],
17131
+ ["path", { "d": "M12 8v8" }]
17132
+ ] }
17133
+ ]));
17134
+ }
17135
+ //#endregion
16438
17136
  //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/circle-x.svelte
16439
17137
  function Circle_x($$renderer, $$props) {
16440
17138
  let { $$slots, $$events, ...props } = $$props;
@@ -16727,6 +17425,26 @@ function Panel_left_close($$renderer, $$props) {
16727
17425
  ]));
16728
17426
  }
16729
17427
  //#endregion
17428
+ //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/panel-left-open.svelte
17429
+ function Panel_left_open($$renderer, $$props) {
17430
+ let { $$slots, $$events, ...props } = $$props;
17431
+ Icon($$renderer, spread_props([
17432
+ { name: "panel-left-open" },
17433
+ props,
17434
+ { iconNode: [
17435
+ ["rect", {
17436
+ "width": "18",
17437
+ "height": "18",
17438
+ "x": "3",
17439
+ "y": "3",
17440
+ "rx": "2"
17441
+ }],
17442
+ ["path", { "d": "M9 3v18" }],
17443
+ ["path", { "d": "m14 9 3 3-3 3" }]
17444
+ ] }
17445
+ ]));
17446
+ }
17447
+ //#endregion
16730
17448
  //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/paperclip.svelte
16731
17449
  function Paperclip($$renderer, $$props) {
16732
17450
  let { $$slots, $$events, ...props } = $$props;
@@ -16737,6 +17455,16 @@ function Paperclip($$renderer, $$props) {
16737
17455
  ]));
16738
17456
  }
16739
17457
  //#endregion
17458
+ //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/pencil.svelte
17459
+ function Pencil($$renderer, $$props) {
17460
+ let { $$slots, $$events, ...props } = $$props;
17461
+ Icon($$renderer, spread_props([
17462
+ { name: "pencil" },
17463
+ props,
17464
+ { iconNode: [["path", { "d": "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" }], ["path", { "d": "m15 5 4 4" }]] }
17465
+ ]));
17466
+ }
17467
+ //#endregion
16740
17468
  //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/plus.svelte
16741
17469
  function Plus($$renderer, $$props) {
16742
17470
  let { $$slots, $$events, ...props } = $$props;
@@ -16747,17 +17475,16 @@ function Plus($$renderer, $$props) {
16747
17475
  ]));
16748
17476
  }
16749
17477
  //#endregion
16750
- //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/refresh-cw.svelte
16751
- function Refresh_cw($$renderer, $$props) {
17478
+ //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/presentation.svelte
17479
+ function Presentation($$renderer, $$props) {
16752
17480
  let { $$slots, $$events, ...props } = $$props;
16753
17481
  Icon($$renderer, spread_props([
16754
- { name: "refresh-cw" },
17482
+ { name: "presentation" },
16755
17483
  props,
16756
17484
  { iconNode: [
16757
- ["path", { "d": "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" }],
16758
- ["path", { "d": "M21 3v5h-5" }],
16759
- ["path", { "d": "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" }],
16760
- ["path", { "d": "M8 16H3v5" }]
17485
+ ["path", { "d": "M2 3h20" }],
17486
+ ["path", { "d": "M21 3v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V3" }],
17487
+ ["path", { "d": "m7 21 5-5 5 5" }]
16761
17488
  ] }
16762
17489
  ]));
16763
17490
  }
@@ -16796,6 +17523,20 @@ function Rotate_cw($$renderer, $$props) {
16796
17523
  ]));
16797
17524
  }
16798
17525
  //#endregion
17526
+ //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/save.svelte
17527
+ function Save($$renderer, $$props) {
17528
+ let { $$slots, $$events, ...props } = $$props;
17529
+ Icon($$renderer, spread_props([
17530
+ { name: "save" },
17531
+ props,
17532
+ { iconNode: [
17533
+ ["path", { "d": "M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z" }],
17534
+ ["path", { "d": "M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7" }],
17535
+ ["path", { "d": "M7 3v4a1 1 0 0 0 1 1h7" }]
17536
+ ] }
17537
+ ]));
17538
+ }
17539
+ //#endregion
16799
17540
  //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/settings.svelte
16800
17541
  function Settings($$renderer, $$props) {
16801
17542
  let { $$slots, $$events, ...props } = $$props;
@@ -16908,6 +17649,24 @@ function Trash_2($$renderer, $$props) {
16908
17649
  ]));
16909
17650
  }
16910
17651
  //#endregion
17652
+ //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/undo-dot.svelte
17653
+ function Undo_dot($$renderer, $$props) {
17654
+ let { $$slots, $$events, ...props } = $$props;
17655
+ Icon($$renderer, spread_props([
17656
+ { name: "undo-dot" },
17657
+ props,
17658
+ { iconNode: [
17659
+ ["path", { "d": "M21 17a9 9 0 0 0-15-6.7L3 13" }],
17660
+ ["path", { "d": "M3 7v6h6" }],
17661
+ ["circle", {
17662
+ "cx": "12",
17663
+ "cy": "17",
17664
+ "r": "1"
17665
+ }]
17666
+ ] }
17667
+ ]));
17668
+ }
17669
+ //#endregion
16911
17670
  //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/wrench.svelte
16912
17671
  function Wrench($$renderer, $$props) {
16913
17672
  let { $$slots, $$events, ...props } = $$props;
@@ -17975,8 +18734,8 @@ function ThemeToggle($$renderer, $$props) {
17975
18734
  }
17976
18735
  //#endregion
17977
18736
  //#region package.json
17978
- var version = "0.8.5";
17979
- var dsh = { "webVersion": "0.2.1-rc.3" };
18737
+ var version = "0.9.0";
18738
+ var dsh = { "webVersion": "0.2.2-alpha.2" };
17980
18739
  //#endregion
17981
18740
  //#region src/lib/version.ts
17982
18741
  /**
@@ -18115,13 +18874,34 @@ function voicedSkillRow(row) {
18115
18874
  };
18116
18875
  }
18117
18876
  //#endregion
18118
- //#region src/lib/components/composer/menu/SlashMenu.svelte
18877
+ //#region src/lib/components/composer/menu/slash-menu-shared.ts
18878
+ /**
18879
+ * SlashMenu's exported pure helpers, in a plain .ts module so BOTH
18880
+ * svelte-check (svelte2tsx) AND raw tsc see the named exports — the
18881
+ * wildcard `declare module '*.svelte'` ambient has no named members,
18882
+ * so module-script exports of a .svelte file are invisible to tsc.
18883
+ * SlashMenu.svelte re-exports these from its <script module> (ONE
18884
+ * source of truth; existing importers keep their import paths).
18885
+ */
18886
+ /**
18887
+ * slashMenuMatches — the menu's And-filter, exported so the HOST
18888
+ * counts matched rows for its keyboard guard with the SAME matcher
18889
+ * (ONE source of truth; the menu and the ladder-guard never drift).
18890
+ *
18891
+ * Strip parity: split the query on `;` and whitespace, lowercase,
18892
+ * drop empties; EVERY term must hit the row's display text
18893
+ * (`name + description`), case-insensitive. A bare `/` (query with
18894
+ * no terms) matches everything — the open menu lists the whole
18895
+ * vocabulary before the operator narrows it.
18896
+ */
18119
18897
  function slashMenuMatches(row, query) {
18120
18898
  const terms = query.slice(1).toLowerCase().split(/[;\s]+/).filter(Boolean);
18121
18899
  if (terms.length === 0) return true;
18122
18900
  const hay = `${row.name} ${row.display ?? ""} ${row.description}`.toLowerCase();
18123
18901
  return terms.every((t) => hay.includes(t));
18124
18902
  }
18903
+ //#endregion
18904
+ //#region src/lib/components/composer/menu/SlashMenu.svelte
18125
18905
  function SlashMenu($$renderer, $$props) {
18126
18906
  $$renderer.component(($$renderer) => {
18127
18907
  /**
@@ -18304,335 +19084,10 @@ function saveTagFilter(base, words, profile) {
18304
19084
  } catch {}
18305
19085
  }
18306
19086
  //#endregion
18307
- //#region src/lib/utils/markdown.ts
18308
- /**
18309
- * markdown — render markdown to sanitized HTML (Wave 2, task 2.1;
18310
- * PRD §3.3 shared layer; BC-12).
18311
- *
18312
- * Pure function, no I/O, no Svelte, no DOM: runs server-side (SSR cold load)
18313
- * and client-side alike. Two-stage pipeline with an allow-list escape hatch —
18314
- * raw HTML never reaches the output:
18315
- *
18316
- * 1. ESCAPE every <, >, &, ", ' in the source text. Any markup-like
18317
- * construct in the transcript is now inert character data; the markdown
18318
- * tokenizer can no longer emit an HTML node from user/wire content.
18319
- * 2. Convert the escaped text with a small CommonMark-subset tokenizer
18320
- * whose emitter can ONLY produce the allow-listed tags below (p, strong,
18321
- * em, del, code, pre, h1-h4, ul/ol/li, blockquote, hr, a, table/
18322
- * thead/tbody/tr/th/td) — plus ONE structured exception: a ```mermaid
18323
- * fence emits a bare placeholder <div class="mermaid-diagram"> whose
18324
- * only attribute is the base64 diagram source; the SVG itself is
18325
- * produced client-side by the mermaid runtime, never by this emitter.
18326
- * Inline
18327
- * code and code fences re-inject their (already-escaped) bodies verbatim
18328
- * — code renders as characters, never markup (tool-payload rule).
18329
- * Paragraph soft line breaks stay as raw \n (the bubble renders with
18330
- * whitespace-pre-wrap — no <br> node needed).
18331
- * 3. Links: only http(s) schemes survive; every other scheme (javascript:,
18332
- * data:, vbscript:, file:, mailto:…) is reduced to plain text. Emitted
18333
- * <a> tags carry rel="noopener noreferrer" target="_blank".
18334
- *
18335
- * Why not a dependency: the project has zero render deps today; the subset
18336
- * below is what the harness transcripts actually use (bold, inline code,
18337
- * fenced blocks, lists, headings) — pinned by markdown.test.ts. The escape-
18338
- * first order makes sanitization structural rather than a block-list chase.
18339
- */
18340
- /** Escape HTML-significant characters — stage 1 of the pipeline. */
18341
- function escapeHtml(text) {
18342
- return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&#39;");
18343
- }
18344
- /**
18345
- * GFM table row: two or more pipe-delimited cells. Cells may ALL be empty —
18346
- * a header-less table (`| | | |\n|---|---|---|\n…`, GitHub renders these)
18347
- * must still start a table; requiring content here swallowed the header,
18348
- * the delimiter row, and every body row into one raw pipe paragraph
18349
- * (2026-08-26 fix, found via a header-less lineage table rendering as text).
18350
- * Over-triggering is structurally impossible: a row only becomes a table
18351
- * when the NEXT line is a strict delimiter row; and `| just a pipe line`
18352
- * stays one cell.
18353
- */
18354
- function isTableRow(line) {
18355
- if (!line.includes("|")) return false;
18356
- return splitRow(line).length >= 2;
18357
- }
18358
- /** GFM delimiter row: cells of only -, :, optional spaces (e.g. |---|:--:|). */
18359
- function isDelimiterRow(line) {
18360
- if (!line.includes("|") && !/^[-:\s]+$/.test(line)) return false;
18361
- const stripped = line.replace(/\|/g, "").trim();
18362
- if (stripped === "" || !/^[-:\s]+$/.test(stripped)) return false;
18363
- return splitRow(line).length >= 2 && splitRow(line).every((c) => /^:?-+:?$/.test(c.trim()));
18364
- }
18365
- /** Split one pipe row into cells: trim outer pipes, split on inner ones. */
18366
- function splitRow(line) {
18367
- let s = line.trim();
18368
- if (s.startsWith("|")) s = s.slice(1);
18369
- if (s.endsWith("|")) s = s.slice(0, -1);
18370
- const literals = [];
18371
- s = s.replace(/\\\|/g, () => {
18372
- literals.push("|");
18373
- return `\u0001${literals.length - 1}\u0001`;
18374
- });
18375
- return s.split("|").map((c) => c.replace(/\u0001(\d+)\u0001/g, (_m, idx) => literals[Number(idx)] ?? "").trim());
18376
- }
18377
- /** List item line: indent, bullet (- * +) or ordered (N. / N)) marker, body. */
18378
- var LIST_ITEM_RE = /^(\s*)([-*+]|\d+[.)])\s+(.*)$/;
18379
- /** Indent width in spaces — a tab advances to the next multiple of 4. */
18380
- function indentWidth(s) {
18381
- let w = 0;
18382
- for (const ch of s) if (ch === " ") w += 4 - w % 4;
18383
- else w += 1;
18384
- return w;
18385
- }
18386
- /**
18387
- * Parse one list run from lines[start] (a list item): consecutive item
18388
- * lines at ANY indent plus lazy plain-text continuations.
18389
- *
18390
- * deeper indent than the innermost open item → nests INSIDE it;
18391
- * same indent → sibling;
18392
- * kind change (bullet ⇄ ordered) at an EXISTING depth → ends the run
18393
- * (the outer scan then emits the next list as its own block — the
18394
- * pre-nesting behavior of two sibling lists is kept);
18395
- * blank line / fence / heading / quote → run over.
18396
- *
18397
- * Mixed kinds still nest when the indent is deeper — a numbered plan
18398
- * under a bullet is legal CommonMark and common in transcripts.
18399
- */
18400
- function parseListRun(lines, start) {
18401
- const items = [];
18402
- const stack = [];
18403
- let i = start;
18404
- while (i < lines.length) {
18405
- const l = lines[i];
18406
- const m = LIST_ITEM_RE.exec(l);
18407
- if (m) {
18408
- const indent = indentWidth(m[1]);
18409
- const ordered = /^\d/.test(m[2]);
18410
- while (stack.length > 0 && stack[stack.length - 1].indent > indent) stack.pop();
18411
- if (stack.length === 0) {
18412
- if (items.length > 0 && ordered !== items[0].ordered) break;
18413
- const it = {
18414
- indent,
18415
- ordered,
18416
- text: m[3],
18417
- children: []
18418
- };
18419
- items.push(it);
18420
- stack.push(it);
18421
- } else {
18422
- const top = stack[stack.length - 1];
18423
- if (indent === top.indent && ordered !== top.ordered) break;
18424
- const it = {
18425
- indent,
18426
- ordered,
18427
- text: m[3],
18428
- children: []
18429
- };
18430
- if (indent > top.indent) top.children.push(it);
18431
- else {
18432
- const parent = stack.length >= 2 ? stack[stack.length - 2] : null;
18433
- if (parent) parent.children.push(it);
18434
- else items.push(it);
18435
- stack.pop();
18436
- }
18437
- stack.push(it);
18438
- }
18439
- i += 1;
18440
- continue;
18441
- }
18442
- if (stack.length > 0 && l.trim() !== "" && !/^(#{1,6})\s|^```|^&gt;/.test(l)) {
18443
- stack[stack.length - 1].text += ` ${l.trim()}`;
18444
- i += 1;
18445
- continue;
18446
- }
18447
- break;
18448
- }
18449
- return {
18450
- items,
18451
- next: i
18452
- };
18453
- }
18454
- /** Emit an item tree — one inline pass per item, children inside the <li>. */
18455
- function emitList(items) {
18456
- const tag = items[0].ordered ? "ol" : "ul";
18457
- return `<${tag}>${items.map((it) => `<li>${renderInline(it.text)}${it.children.length > 0 ? emitList(it.children) : ""}</li>`).join("")}</${tag}>`;
18458
- }
18459
- /** Reverse stage-1 escaping — mermaid parses the ORIGINAL syntax, not entities. */
18460
- function unescapeEntities(text) {
18461
- return text.replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&quot;", "\"").replaceAll("&#39;", "'").replaceAll("&amp;", "&");
18462
- }
18463
- /** Base64 that survives non-ASCII (diagram labels are arbitrary text). */
18464
- function btoaUnicode(text) {
18465
- return btoa(String.fromCharCode(...new TextEncoder().encode(text)));
18466
- }
18467
- var ESCAPED_CODE_FENCE = /^```/;
18468
- /**
18469
- * Render markdown to sanitized HTML (single entry point, BC-12).
18470
- * Output uses ONLY the allow-listed tags; empty input renders ''.
18471
- */
18472
- function renderMarkdown(text) {
18473
- if (text === "") return "";
18474
- const escaped = escapeHtml(text);
18475
- const out = [];
18476
- const lines = escaped.split("\n");
18477
- let i = 0;
18478
- while (i < lines.length) {
18479
- const line = lines[i];
18480
- if (ESCAPED_CODE_FENCE.test(line.trimStart())) {
18481
- const opener = line.trimStart().slice(3).trim().toLowerCase();
18482
- const body = [];
18483
- i += 1;
18484
- while (i < lines.length && !ESCAPED_CODE_FENCE.test(lines[i].trimStart())) {
18485
- body.push(lines[i]);
18486
- i += 1;
18487
- }
18488
- i += 1;
18489
- if (opener === "mermaid") {
18490
- const encoded = btoaUnicode(unescapeEntities(body.join("\n")));
18491
- out.push(`<div class="mermaid-diagram" data-source="${encoded}" data-processed="false"></div>`);
18492
- continue;
18493
- }
18494
- out.push(`<pre><code>${body.join("\n")}</code></pre>`);
18495
- continue;
18496
- }
18497
- if (line.trim() === "") {
18498
- i += 1;
18499
- continue;
18500
- }
18501
- const heading = /^(#{1,6})\s+(.*)$/.exec(line);
18502
- if (heading) {
18503
- const level = Math.min(4, heading[1].length);
18504
- out.push(`<h${level}>${renderInline(heading[2])}</h${level}>`);
18505
- i += 1;
18506
- continue;
18507
- }
18508
- if (/^([-*_])(\s*\1){2,}\s*$/.test(line)) {
18509
- out.push("<hr />");
18510
- i += 1;
18511
- continue;
18512
- }
18513
- if (isTableRow(line) && i + 1 < lines.length && isDelimiterRow(lines[i + 1])) {
18514
- const header = splitRow(line);
18515
- i += 2;
18516
- const body = [];
18517
- while (i < lines.length && isTableRow(lines[i]) && !isDelimiterRow(lines[i])) {
18518
- body.push(splitRow(lines[i]));
18519
- i += 1;
18520
- }
18521
- const thead = `<thead><tr>${header.map((c) => `<th>${renderInline(c)}</th>`).join("")}</tr></thead>`;
18522
- const tbody = `<tbody>${body.map((row) => `<tr>${row.map((c) => `<td>${renderInline(c)}</td>`).join("")}</tr>`).join("")}</tbody>`;
18523
- out.push(`<table>${thead}${tbody}</table>`);
18524
- continue;
18525
- }
18526
- if (/^&gt;\s?/.test(line)) {
18527
- const body = [];
18528
- while (i < lines.length && /^&gt;\s?/.test(lines[i])) {
18529
- body.push(lines[i].replace(/^&gt;\s?/, ""));
18530
- i += 1;
18531
- }
18532
- out.push(`<blockquote><p>${renderInline(body.join(" "))}</p></blockquote>`);
18533
- continue;
18534
- }
18535
- if (LIST_ITEM_RE.test(line)) {
18536
- const run = parseListRun(lines, i);
18537
- out.push(emitList(run.items));
18538
- i = run.next;
18539
- continue;
18540
- }
18541
- const para = [];
18542
- while (i < lines.length && lines[i].trim() !== "" && !ESCAPED_CODE_FENCE.test(lines[i].trimStart()) && !/^#{1,6}\s/.test(lines[i]) && !/^&gt;\s?/.test(lines[i]) && !/^(\s*)([-*+]|\d+[.)])\s+/.test(lines[i]) && !/^([-*_])(\s*\1){2,}\s*$/.test(lines[i]) && !(isTableRow(lines[i]) && i + 1 < lines.length && isDelimiterRow(lines[i + 1]))) {
18543
- para.push(lines[i]);
18544
- i += 1;
18545
- }
18546
- if (para.length > 0) out.push(`<p>${renderInline(para.join("\n"))}</p>`);
18547
- }
18548
- return out.join("\n");
18549
- }
18550
- /**
18551
- * Inline pass: code spans first (their bodies stay verbatim), then emphasis,
18552
- * then links. Escaped text in, allow-listed tags out.
18553
- */
18554
- function renderInline(text) {
18555
- const codeSpans = [];
18556
- let rest = text.replace(/`([^`\n]+)`/g, (_m, body) => {
18557
- const raw = unescapeEntities(body);
18558
- if (/^https?:\/\/\S+$/i.test(raw)) codeSpans.push(externalAnchor(raw));
18559
- else codeSpans.push(`<code>${body}</code>`);
18560
- return `\u0000${codeSpans.length - 1}\u0000`;
18561
- });
18562
- rest = emphasis(rest);
18563
- rest = links(rest);
18564
- rest = autolinkBareUrls(rest);
18565
- return rest.replace(/\u0000(\d+)\u0000/g, (_m, idx) => codeSpans[Number(idx)] ?? "");
18566
- }
18567
- /** One hardened external anchor from a RAW url — display is origin+path
18568
- * (query/fragment stripped), href keeps everything (BC-12 attributes). */
18569
- function externalAnchor(rawUrl) {
18570
- let cut = rawUrl.length;
18571
- for (const c of ["?", "#"]) {
18572
- const i = rawUrl.indexOf(c);
18573
- if (i !== -1 && i < cut) cut = i;
18574
- }
18575
- return `<a href="${rawUrl.replaceAll("\"", "&quot;")}" rel="noopener noreferrer" target="_blank">${rawUrl.slice(0, cut)}</a>`;
18576
- }
18577
- /**
18578
- * Bare-URL autolink (2026-09-27): an http(s) URL in plain text becomes an
18579
- * anchor whose DISPLAY TEXT is the origin+path with the query/hash stripped
18580
- * (transcript URLs like …new?merge_request[source_branch]=… render short)
18581
- * while the HREF keeps the FULL URL. Runs after [label](href) parsing and
18582
- * skips text inside existing anchors/code placeholders (\u0000N\u0000 markers).
18583
- * Trailing punctuation ),.,;:!?'"] and matching surrounding parens stay
18584
- * outside the link (CommonMark's autolink tail rule).
18585
- */
18586
- function autolinkBareUrls(text) {
18587
- return text.replace(/https?:\/\/[^\s<>"'\u0000]+/gi, (whole, offset, full) => {
18588
- const before = full.slice(Math.max(0, offset - 2e3), offset);
18589
- if (/<a\s[^>]*$/i.test(before) || /<code>[^<]*$/i.test(before)) return whole;
18590
- let url = whole;
18591
- while (url.endsWith(")") && (url.match(/\(/g)?.length ?? 0) < (url.match(/\)/g)?.length ?? 0)) url = url.slice(0, -1);
18592
- url = url.replace(/[.,;:!?]+$/, "");
18593
- const tail = whole.slice(url.length);
18594
- return `${externalAnchor(url)}${tail}`;
18595
- });
18596
- }
18597
- /** ***bold-italic***, **bold**, *italic*, _italic_, ~~strike~~. */
18598
- function emphasis(text) {
18599
- return text.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>").replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\*(.+?)\*/g, "<em>$1</em>").replace(/(?<![\w])_(.+?)_(?![\w])/g, "<em>$1</em>").replace(/~~(.+?)~~/g, "<del>$1</del>");
18600
- }
18601
- /**
18602
- * [label](href) — http(s) hrefs become hardened external anchors; SCHEME-FREE
18603
- * relative hrefs (assistant file links like [card](src/lib/…)) become same-
18604
- * origin anchors; anything carrying a scheme (javascript:, data:, mailto:,
18605
- * //evil.com protocol-relative, …) stays inert text (BC-12).
18606
- */
18607
- function links(text) {
18608
- return text.replace(/\[([^\]]+)\]\((?:&lt;([^>]*?)&gt;|([^)\s]+))\)/g, (whole, labelA, angleHref, bareHref) => {
18609
- const label = labelA;
18610
- const bare = (angleHref !== void 0 ? angleHref : bareHref).replaceAll("&amp;", "&").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&quot;", "\"").replaceAll("&#39;", "'").replace(/^<(.+)>$/, "$1");
18611
- if (/^https?:\/\//i.test(bare)) return `<a href="${bare.replaceAll("\"", "&quot;")}" rel="noopener noreferrer" target="_blank">${label}</a>`;
18612
- if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(bare) || bare.startsWith("//")) return whole;
18613
- return `<a href="${bare.replaceAll("\"", "&quot;")}">${label}</a>`;
18614
- });
18615
- }
18616
- //#endregion
18617
19087
  //#region src/lib/components/composer/menu/suggest-strip/StripTip.svelte
18618
19088
  function StripTip($$renderer, $$props) {
18619
19089
  $$renderer.component(($$renderer) => {
18620
- /**
18621
- * StripTip — the multiline full-text preview tooltip of one suggestion
18622
- * row (OCI's StripMultiline lineage, its own component again).
18623
- *
18624
- * Presentational: chip anchor + live flags + raw text in, one portaled
18625
- * tooltip out. Visible only while its chip is the active (keyboard-
18626
- * highlighted) row, the row text is multiline, and no ⋯ menu is open
18627
- * anywhere on the strip (the host threads menuOpen/anyMenuOpen).
18628
- */
18629
- let { active = false, menuOpen = false, anyMenuOpen = false, text } = $$props;
18630
- /** Tooltip box; null = hidden. Mirrors the STRIP's horizontal geometry
18631
- * — same left edge, same width — regardless of which chip is active;
18632
- * y anchors above the whole strip. Hides whenever any ⋯ menu is open. */
18633
- let tipPos = null;
18634
- if (active && text.includes("\n") && !menuOpen && !anyMenuOpen && tipPos);
18635
- else $$renderer.push("<!--[-1-->");
19090
+ $$renderer.push("<!--[-1-->");
18636
19091
  $$renderer.push(`<!--]-->`);
18637
19092
  });
18638
19093
  }
@@ -18656,7 +19111,7 @@ function StripChip($$renderer, $$props) {
18656
19111
  * tooltip renders through StripTip (same body-portal escape); this
18657
19112
  * chip only hands it the anchor and the live flags.
18658
19113
  */
18659
- let { row, active = false, query = "", mode = "find", menuOpen = false, anyMenuOpen = false, onstep = void 0, onrename = void 0, ondelete = void 0} = $$props;
19114
+ let { row, active = false, query = "", mode = "find", menuOpen = false, onstep = void 0, onrename = void 0, ondelete = void 0} = $$props;
18660
19115
  /** The ⋯ menu exists only when both of its handlers do. */
18661
19116
  const hasMenu = derived(() => onrename !== void 0 && ondelete !== void 0);
18662
19117
  /** Segments for the current query — recomputed per render (pure service). */
@@ -18698,9 +19153,6 @@ function StripChip($$renderer, $$props) {
18698
19153
  } else $$renderer.push("<!--[-1-->");
18699
19154
  $$renderer.push(`<!--]--> `);
18700
19155
  StripTip($$renderer, {
18701
- active,
18702
- menuOpen,
18703
- anyMenuOpen,
18704
19156
  text: row.text});
18705
19157
  $$renderer.push(`<!----> `);
18706
19158
  if (menuOpen && onrename !== void 0 && ondelete !== void 0) {
@@ -18824,7 +19276,6 @@ function SuggestStrip($$renderer, $$props) {
18824
19276
  row,
18825
19277
  active: index === activeIndex,
18826
19278
  menuOpen: menuForId === row.id,
18827
- anyMenuOpen: menuForId !== null,
18828
19279
  query,
18829
19280
  mode,
18830
19281
  onstep: onstep === void 0 ? void 0 : () => onstep(index),
@@ -19759,7 +20210,8 @@ function defaultPanelPrefs() {
19759
20210
  selectedPanelId: null,
19760
20211
  panelWidth: defaultPanelWidth(),
19761
20212
  zoom: 1,
19762
- treePct: 30
20213
+ treePct: 30,
20214
+ explorerHidden: false
19763
20215
  };
19764
20216
  }
19765
20217
  /**
@@ -19930,12 +20382,14 @@ function loadPanelPrefs(profile) {
19930
20382
  const panelWidth = typeof parsed.panelWidth === "number" && Number.isFinite(parsed.panelWidth) ? clampPanelWidth(parsed.panelWidth) : defaultPanelWidth();
19931
20383
  const zoom = typeof parsed.zoom === "number" && Number.isFinite(parsed.zoom) ? clampPanelZoom(parsed.zoom) : 1;
19932
20384
  const treePct = typeof parsed.treePct === "number" && Number.isFinite(parsed.treePct) ? clampTreePct(parsed.treePct) : 30;
20385
+ const explorerHidden = parsed.explorerHidden === true;
19933
20386
  return {
19934
20387
  panels,
19935
20388
  selectedPanelId: typeof parsed.selectedPanelId === "string" && panels.some((panel) => panel.id === parsed.selectedPanelId) ? parsed.selectedPanelId : panels[0]?.id ?? null,
19936
20389
  panelWidth,
19937
20390
  zoom,
19938
- treePct
20391
+ treePct,
20392
+ explorerHidden
19939
20393
  };
19940
20394
  } catch {
19941
20395
  return defaultPanelPrefs();
@@ -20165,6 +20619,148 @@ function AppSidebarHeader($$renderer, $$props) {
20165
20619
  });
20166
20620
  }
20167
20621
  //#endregion
20622
+ //#region src/lib/components/common/WidthBadge.svelte
20623
+ function WidthBadge($$renderer, $$props) {
20624
+ /**
20625
+ * WidthBadge — the resize chip (Movable Rail ADR, amendment 2026-10-30
20626
+ * D1): one home for the live px readout that used to live inline in
20627
+ * PanelColumn (2026-08-28). Presentational ONLY — the owner's drag
20628
+ * machine writes the phase; this renders it and intercepts no pointer
20629
+ * (the drag owns the pointer; the afterglow must not block clicks).
20630
+ * The floor badge (PanelColumn) and the sidebar rail badge
20631
+ * (AppSidebar standalone) share this grammar; the embedded rail gets
20632
+ * no badge at all (zoom-scaled px would misreport — ADR D3).
20633
+ */
20634
+ let { phase, width, testid = "panel-width-badge" } = $$props;
20635
+ $$renderer.push(`<span data-svelte="WidthBadge"${attr_class("width-badge svelte-1mjaqxx", void 0, { "fading": phase === "fading" })}${attr("data-testid", testid)}${attr("data-badge-phase", phase)} aria-hidden="true">${escape_html(Math.round(width))}px</span>`);
20636
+ }
20637
+ //#endregion
20638
+ //#region src/lib/utils/sidebar-prefs.ts
20639
+ /**
20640
+ * Sidebar preferences — persisted layout state for the conversation page's
20641
+ * app sidebar (OCI ControlRail pattern, 2026-08-23).
20642
+ *
20643
+ * Pure localStorage round-trip: SSR-safe (no localStorage → defaults), junk
20644
+ * payloads and out-of-range widths fall back instead of throwing into the
20645
+ * page, and writes are best-effort (a full or blocked store must not break
20646
+ * the layout — it only loses persistence for that session).
20647
+ *
20648
+ * Workspace profiles (storage-profile.ts): `?profile=widi` moves the key
20649
+ * to `dsi-sidebar_widi` — each desk remembers its own rail layout.
20650
+ */
20651
+ /** localStorage base key — one JSON blob `{ collapsed, width }`. */
20652
+ var STORAGE_KEY = "dsi-sidebar";
20653
+ /** The single width bound site — load-side sanitizing and drag clamping
20654
+ * both route through here so the bounds exist in exactly one place.
20655
+ * Bounds read the config store (layout load has landed them before any
20656
+ * mount; constants are the fallback defaults). */
20657
+ function clampSidebarWidth(width) {
20658
+ const { minWidth, maxWidth } = appConfig().sidebar;
20659
+ return Math.max(minWidth, Math.min(maxWidth, width));
20660
+ }
20661
+ /** Config-driven default width (clamped through the single bound site). */
20662
+ function defaultSidebarWidth() {
20663
+ return clampSidebarWidth(appConfig().sidebar.defaultWidth);
20664
+ }
20665
+ /** Persisted defaults when nothing (usable) is stored. */
20666
+ function defaultSidebarPrefs() {
20667
+ return {
20668
+ collapsed: false,
20669
+ width: defaultSidebarWidth()
20670
+ };
20671
+ }
20672
+ /**
20673
+ * Read prefs from localStorage.
20674
+ * @param profile sanitized workspace profile (null/omitted = default desk).
20675
+ * @returns stored prefs when parseable, defaults when absent, junk, or SSR.
20676
+ */
20677
+ function loadSidebarPrefs(profile) {
20678
+ if (typeof localStorage === "undefined") return defaultSidebarPrefs();
20679
+ try {
20680
+ const raw = localStorage.getItem(dsiKey(STORAGE_KEY, profile));
20681
+ if (!raw) return defaultSidebarPrefs();
20682
+ const parsed = JSON.parse(raw);
20683
+ if (parsed === null || typeof parsed !== "object") return defaultSidebarPrefs();
20684
+ return {
20685
+ collapsed: parsed.collapsed === true,
20686
+ width: clampSidebarWidth(typeof parsed.width === "number" && Number.isFinite(parsed.width) ? parsed.width : defaultSidebarWidth())
20687
+ };
20688
+ } catch {
20689
+ return defaultSidebarPrefs();
20690
+ }
20691
+ }
20692
+ //#endregion
20693
+ //#region src/lib/services/workspace/page-prefs.svelte.ts
20694
+ var PagePrefs = class {
20695
+ /** Width preset for the next conversation panel (clamped). */
20696
+ panelWidth = 0;
20697
+ /** Floor zoom (clamped). */
20698
+ zoom = 1;
20699
+ /** Explorer Layout split (clamped). */
20700
+ treePct = 0;
20701
+ /** Explorer hide/show (2026-10-31 toggle RCA): $state is REQUIRED —
20702
+ * a plain field swallowed the toggle click silently (no re-render). */
20703
+ explorerHidden = false;
20704
+ /** Sidebar rail state (OCI ControlRail port). */
20705
+ sidebarCollapsed = false;
20706
+ sidebarWidth = 0;
20707
+ /** Sidebar width-badge phase (Movable Rail ADR amendment 2026-10-30):
20708
+ * 'live' while the gutter drag moves, 'fading' through the 10s
20709
+ * afterglow, null otherwise. GESTURE state, never persisted — the
20710
+ * save whitelist below carries only collapsed + width. */
20711
+ sidebarBadge = null;
20712
+ #profile = null;
20713
+ #initialised = false;
20714
+ /** Non-reactive: the afterglow timer id (drag.svelte.ts dragRefs
20715
+ * pattern — timers never belong in reactive state). */
20716
+ #afterglowTimer = null;
20717
+ /** Seed every field from the persisted blobs — exactly once, BEFORE
20718
+ * the route reads any field (makePanel reads panelWidth during the
20719
+ * seed reset). Intentional initial capture per the route's old
20720
+ * "svelte-ignore state_referenced_locally" comments: prefs seed the
20721
+ * layout once; later writes go through the save effects. */
20722
+ init(profile) {
20723
+ this.#initialised = true;
20724
+ this.#profile = profile;
20725
+ const floor = loadPanelPrefs(profile);
20726
+ this.panelWidth = clampPanelWidth(floor.panelWidth);
20727
+ this.zoom = clampPanelZoom(floor.zoom);
20728
+ this.treePct = clampTreePct(floor.treePct);
20729
+ this.explorerHidden = floor.explorerHidden === true;
20730
+ const sidebar = loadSidebarPrefs(profile);
20731
+ this.sidebarCollapsed = sidebar.collapsed;
20732
+ this.sidebarWidth = sidebar.width;
20733
+ }
20734
+ get profile() {
20735
+ return this.#profile;
20736
+ }
20737
+ /** Sidebar persistence (the route's old sidebar save effect). Call
20738
+ * during component initialisation — $effect needs an owner. */
20739
+ installSidebarAutoSave() {}
20740
+ /** The badge afterglow (10s linear fade, mirroring the floor's
20741
+ * drag.svelte.ts:118-128): called at gutter mouseup — freezes the
20742
+ * phase into 'fading', then null. A drag that starts before the
20743
+ * timer fires cancels it (the chip goes back to live instantly,
20744
+ * never a 10s fade-in). */
20745
+ armSidebarAfterglow() {
20746
+ this.sidebarBadge = "fading";
20747
+ if (this.#afterglowTimer !== null) clearTimeout(this.#afterglowTimer);
20748
+ this.#afterglowTimer = setTimeout(() => {
20749
+ this.sidebarBadge = null;
20750
+ this.#afterglowTimer = null;
20751
+ }, 1e4);
20752
+ }
20753
+ /** A new gutter drag cancels any armed afterglow. */
20754
+ cancelSidebarAfterglow() {
20755
+ if (this.#afterglowTimer !== null) {
20756
+ clearTimeout(this.#afterglowTimer);
20757
+ this.#afterglowTimer = null;
20758
+ }
20759
+ this.sidebarBadge = "live";
20760
+ }
20761
+ };
20762
+ var pagePrefs = new PagePrefs();
20763
+ //#endregion
20168
20764
  //#region src/lib/components/common/layout/AppSidebar.svelte
20169
20765
  function AppSidebar($$renderer, $$props) {
20170
20766
  $$renderer.component(($$renderer) => {
@@ -20267,7 +20863,16 @@ function AppSidebar($$renderer, $$props) {
20267
20863
  $$renderer.push(`<!----></aside>`);
20268
20864
  } else {
20269
20865
  $$renderer.push("<!--[-1-->");
20270
- $$renderer.push(`<div data-svelte="AppSidebar" class="rail-wrap svelte-113gpvg" data-testid="app-sidebar"${attr_style(`width: ${stringify(width)}px`)}><aside class="rail svelte-113gpvg">`);
20866
+ $$renderer.push(`<div data-svelte="AppSidebar" class="rail-wrap svelte-113gpvg" data-testid="app-sidebar"${attr_style(`width: ${stringify(width)}px`)}>`);
20867
+ if (pagePrefs.sidebarBadge !== null) {
20868
+ $$renderer.push("<!--[0-->");
20869
+ WidthBadge($$renderer, {
20870
+ phase: pagePrefs.sidebarBadge,
20871
+ width,
20872
+ testid: "sidebar-width-badge"
20873
+ });
20874
+ } else $$renderer.push("<!--[-1-->");
20875
+ $$renderer.push(`<!--]--> <aside class="rail svelte-113gpvg">`);
20271
20876
  AppSidebarHeader($$renderer, {
20272
20877
  captureContainer,
20273
20878
  trayContainer,
@@ -21193,15 +21798,25 @@ function parseCommand(text) {
21193
21798
  let rest = args === "" ? [] : args.split(/\s+/);
21194
21799
  let agentId;
21195
21800
  let ws;
21801
+ let title;
21196
21802
  let addPanel = false;
21197
- if (rest.length > 0 && rest[0].startsWith("@") && rest[0].length > 1) {
21198
- agentId = rest[0].slice(1);
21199
- rest = rest.slice(1);
21200
- }
21201
21803
  if (rest.length > 0 && rest[rest.length - 1] === "--add") {
21202
21804
  addPanel = true;
21203
21805
  rest = rest.slice(0, -1);
21204
21806
  }
21807
+ const titleIdx = rest.indexOf("--title");
21808
+ if (titleIdx !== -1) {
21809
+ if (titleIdx === rest.length - 1) return {
21810
+ type: "new",
21811
+ args
21812
+ };
21813
+ title = rest.slice(titleIdx + 1).join(" ");
21814
+ rest = rest.slice(0, titleIdx);
21815
+ }
21816
+ if (rest.length > 0 && rest[0].startsWith("@") && rest[0].length > 1) {
21817
+ agentId = rest[0].slice(1);
21818
+ rest = rest.slice(1);
21819
+ }
21205
21820
  if (rest.length === 1 && !rest[0].startsWith("@") && !rest[0].startsWith("--") && rest[0] !== "?") {
21206
21821
  ws = rest[0];
21207
21822
  rest = [];
@@ -21215,6 +21830,7 @@ function parseCommand(text) {
21215
21830
  args: "",
21216
21831
  ...agentId !== void 0 ? { agentId } : {},
21217
21832
  ...ws !== void 0 ? { ws } : {},
21833
+ ...title !== void 0 ? { title } : {},
21218
21834
  ...addPanel ? { addPanel: true } : {}
21219
21835
  };
21220
21836
  }
@@ -21358,7 +21974,7 @@ function commandHelpTopic(text) {
21358
21974
  * PRESET_TABLE (permission-state); ids/examples mirror command-parser. */
21359
21975
  var COMMAND_HELP = {
21360
21976
  new: {
21361
- usage: "/new [@agent] [workspace] [--add]",
21977
+ usage: "/new [@agent] [workspace] [--title <title>] [--add]",
21362
21978
  summary: "Creates a fresh session — it inherits this session's workspace and agent. Name a registered workspace to land THERE instead of inheriting (unique title, or the full path). Default: it replaces this panel. With --add: it opens in a NEW panel to the right, and focus stays here.",
21363
21979
  params: [
21364
21980
  {
@@ -21369,6 +21985,10 @@ var COMMAND_HELP = {
21369
21985
  name: "workspace",
21370
21986
  description: "Optional registered workspace — a unique title (recipe-ws) or the full path (/home/u/recipe-ws). The new session runs there instead of inheriting; an ambiguous name lists the candidates instead of guessing."
21371
21987
  },
21988
+ {
21989
+ name: "--title <title>",
21990
+ description: "Optional title for the new session — everything after --title is the title, verbatim. Applied after the session is created; a failed rename keeps the default title."
21991
+ },
21372
21992
  {
21373
21993
  name: "--add",
21374
21994
  description: "Open the new session in a NEW panel placed to the RIGHT of the current panel; the current panel keeps the selection and the caret (the default panel swap never runs)."
@@ -21388,8 +22008,8 @@ var COMMAND_HELP = {
21388
22008
  description: "New session inside the registered recipe-ws workspace."
21389
22009
  },
21390
22010
  {
21391
- line: "/new @app-dev --add",
21392
- description: "New app-dev session in a panel to the right — this panel keeps focus."
22011
+ line: "/new @app-dev --title Refactor Auth --add",
22012
+ description: "New app-dev session titled Refactor Auth in a panel to the right — this panel keeps focus."
21393
22013
  }
21394
22014
  ]
21395
22015
  },
@@ -21917,14 +22537,17 @@ function ContextConsumption($$renderer, $$props) {
21917
22537
  * ContextConsumption — context window usage indicator (OCI port,
21918
22538
  * 2026-08-23; percentage wired 2026-08-24). Two display modes:
21919
22539
  *
21920
- * both values → OCI's exact bar: colored progress (green <60%,
21921
- * amber <85%, red ≥85%) + percentage label
22540
+ * both values, → OCI's exact bar: colored progress (green <60%,
22541
+ * used > 0 amber <85%, red ≥85%) + percentage label
21922
22542
  * used only → DSI fallback: "≈12.3k ctx" text label. The DSH
21923
22543
  * wire reports per-step usage but no model context
21924
22544
  * window, so when the model is unknown to the
21925
22545
  * local catalog (context-window.ts) the bar has
21926
22546
  * no denominator — the label keeps the slot
21927
22547
  * honest instead of dead.
22548
+ * used = 0 → the fallback label too ("≈0 ctx"): a zero-usage
22549
+ * turn would otherwise paint a 0%-wide bar — a dead
22550
+ * slot (SC#1, 2026-11-01).
21928
22551
  * neither → renders nothing (OCI contract).
21929
22552
  *
21930
22553
  * `used` = what the LAST model request consumed: input + cache-read +
@@ -21934,7 +22557,7 @@ function ContextConsumption($$renderer, $$props) {
21934
22557
  * overrides), never wire truth — the bar's tooltip says so.
21935
22558
  */
21936
22559
  let { used = void 0, limit = void 0 } = $$props;
21937
- const percent = derived(() => used !== void 0 && limit !== void 0 && limit > 0 ? Math.round(used / limit * 100) : void 0);
22560
+ const percent = derived(() => used !== void 0 && used > 0 && limit !== void 0 && limit > 0 ? Math.round(used / limit * 100) : void 0);
21938
22561
  function formatK(n) {
21939
22562
  return n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
21940
22563
  }
@@ -23596,7 +24219,7 @@ function workspaceFileTitle(path) {
23596
24219
  */
23597
24220
  function panelHeaderLabel(panel) {
23598
24221
  if (panel.kind === "terminal") return "Terminal";
23599
- if (panel.kind === "browser") return "Browser";
24222
+ if (panel.kind === "browser") return "Glass Browser";
23600
24223
  if (panel.kind === "prompt-manager") return MANAGER_ROW_TITLE;
23601
24224
  if (panel.kind === "skill-shelf") return "Skill Shelf";
23602
24225
  if (panel.kind === "plugin-rack") return "Plugin Rack";
@@ -23630,7 +24253,7 @@ function panelRowsFor(input) {
23630
24253
  const openerDepth = p.openedBy !== void 0 ? lineageFacts.depthById.get(p.openedBy) ?? 0 : 0;
23631
24254
  return {
23632
24255
  panel: p,
23633
- title: "Browser",
24256
+ title: "Glass Browser",
23634
24257
  workspace: null,
23635
24258
  dead: false,
23636
24259
  running: false,
@@ -24749,7 +25372,8 @@ function EditingTitle($$renderer, $$props) {
24749
25372
  * from SessionIdAndName: BOTH title states inside one component —
24750
25373
  *
24751
25374
  * display — the rename trigger button (title="Rename this session")
24752
- * editing — the inline form (input + Save + Cancel + error line)
25375
+ * editing — the inline form (input + ✓/✕ icon verbs + error line;
25376
+ * ADR-0044: the verbs are icon-only, words on tooltips)
24753
25377
  *
24754
25378
  * Rename is fully owned here: draft, in-flight lock, the POST
24755
25379
  * (session.rename via the page’s /api/dsh route), the error surface,
@@ -25070,10 +25694,10 @@ function ToolsAndStatusHeader($$renderer, $$props) {
25070
25694
  });
25071
25695
  }
25072
25696
  //#endregion
25073
- //#region src/lib/components/conversation/header/OpenBrowserButton.svelte
25074
- function OpenBrowserButton($$renderer, $$props) {
25697
+ //#region src/lib/components/conversation/header/BrowserButton.svelte
25698
+ function BrowserButton($$renderer, $$props) {
25075
25699
  $$renderer.component(($$renderer) => {
25076
- $$renderer.push(`<button data-svelte="OpenBrowserButton" type="button" class="rounded border border-surface-border px-1.5 py-0.5 text-xs hover:bg-surface-active" data-testid="open-browser"${attr("title", browseropentitle2())}>${escape_html(browserchiplabel2())}</button>`);
25700
+ $$renderer.push(`<button data-svelte="BrowserButton" type="button" class="rounded border border-surface-border px-1.5 py-0.5 text-xs hover:bg-surface-active" data-testid="open-browser"${attr("title", browseropentitle2())}>${escape_html(browserchiplabel2())}</button>`);
25077
25701
  });
25078
25702
  }
25079
25703
  //#endregion
@@ -25103,7 +25727,7 @@ function ConversationHeader($$renderer, $$props) {
25103
25727
  $$renderer.push(`<!----> `);
25104
25728
  if (onOpenBrowser) {
25105
25729
  $$renderer.push("<!--[0-->");
25106
- OpenBrowserButton($$renderer);
25730
+ BrowserButton($$renderer);
25107
25731
  } else $$renderer.push("<!--[-1-->");
25108
25732
  $$renderer.push(`<!--]--> `);
25109
25733
  ToolsAndStatusHeader($$renderer, {
@@ -25556,7 +26180,7 @@ async function resolveWorkspaceToken(token) {
25556
26180
  /** The /new verb (moved verbatim from the executeCommand body). */
25557
26181
  async function runNewLine(command, ctx, onNote) {
25558
26182
  if (command.args !== "") {
25559
- const usage = "usage: /new [@agent] [workspace] [--add]";
26183
+ const usage = "usage: /new [@agent] [workspace] [--title <title>] [--add]";
25560
26184
  onNote?.(false, usage);
25561
26185
  return {
25562
26186
  ok: false,
@@ -25603,6 +26227,13 @@ async function runNewLine(command, ctx, onNote) {
25603
26227
  note
25604
26228
  };
25605
26229
  }
26230
+ if (command.title !== void 0 && command.title !== "") try {
26231
+ await fetch(`/api/dsh/session/${encodeURIComponent(body.sessionId)}/rename`, {
26232
+ method: "POST",
26233
+ headers: { "content-type": "application/json" },
26234
+ body: JSON.stringify({ title: command.title })
26235
+ });
26236
+ } catch {}
25606
26237
  if (command.addPanel === true) {
25607
26238
  if (!addPanelFromSidebar({
25608
26239
  sessionId: body.sessionId,
@@ -26765,7 +27396,7 @@ function groupTurns(entries) {
26765
27396
  continue;
26766
27397
  }
26767
27398
  if (entry.kind === "user-message") {
26768
- if (entry.meta) {
27399
+ if (entry.meta && entry.imageRefs === void 0) {
26769
27400
  const last = groups[groups.length - 1];
26770
27401
  if (last?.kind === "prompt") {
26771
27402
  last.context.push(entry);
@@ -27034,6 +27665,346 @@ function LoadOlderSentinel($$renderer, $$props) {
27034
27665
  });
27035
27666
  }
27036
27667
  //#endregion
27668
+ //#region src/lib/utils/markdown.ts
27669
+ /**
27670
+ * markdown — render markdown to sanitized HTML (Wave 2, task 2.1;
27671
+ * PRD §3.3 shared layer; BC-12).
27672
+ *
27673
+ * Pure function, no I/O, no Svelte, no DOM: runs server-side (SSR cold load)
27674
+ * and client-side alike. Two-stage pipeline with an allow-list escape hatch —
27675
+ * raw HTML never reaches the output:
27676
+ *
27677
+ * 1. ESCAPE every <, >, &, ", ' in the source text. Any markup-like
27678
+ * construct in the transcript is now inert character data; the markdown
27679
+ * tokenizer can no longer emit an HTML node from user/wire content.
27680
+ * 2. Convert the escaped text with a small CommonMark-subset tokenizer
27681
+ * whose emitter can ONLY produce the allow-listed tags below (p, strong,
27682
+ * em, del, code, pre, h1-h4, ul/ol/li, blockquote, hr, a, table/
27683
+ * thead/tbody/tr/th/td) — plus ONE structured exception: a ```mermaid
27684
+ * fence emits a bare placeholder <div class="mermaid-diagram"> whose
27685
+ * only attribute is the base64 diagram source; the SVG itself is
27686
+ * produced client-side by the mermaid runtime, never by this emitter.
27687
+ * Inline
27688
+ * code and code fences re-inject their (already-escaped) bodies verbatim
27689
+ * — code renders as characters, never markup (tool-payload rule).
27690
+ * Paragraph soft line breaks stay as raw \n (the bubble renders with
27691
+ * whitespace-pre-wrap — no <br> node needed).
27692
+ * 3. Links: only http(s) schemes survive; every other scheme (javascript:,
27693
+ * data:, vbscript:, file:, mailto:…) is reduced to plain text. Emitted
27694
+ * <a> tags carry rel="noopener noreferrer" target="_blank".
27695
+ *
27696
+ * Why not a dependency: the project has zero render deps today; the subset
27697
+ * below is what the harness transcripts actually use (bold, inline code,
27698
+ * fenced blocks, lists, headings) — pinned by markdown.test.ts. The escape-
27699
+ * first order makes sanitization structural rather than a block-list chase.
27700
+ */
27701
+ /** Escape HTML-significant characters — stage 1 of the pipeline. */
27702
+ function escapeHtml(text) {
27703
+ return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&#39;");
27704
+ }
27705
+ /**
27706
+ * GFM table row: two or more pipe-delimited cells. Cells may ALL be empty —
27707
+ * a header-less table (`| | | |\n|---|---|---|\n…`, GitHub renders these)
27708
+ * must still start a table; requiring content here swallowed the header,
27709
+ * the delimiter row, and every body row into one raw pipe paragraph
27710
+ * (2026-08-26 fix, found via a header-less lineage table rendering as text).
27711
+ * Over-triggering is structurally impossible: a row only becomes a table
27712
+ * when the NEXT line is a strict delimiter row; and `| just a pipe line`
27713
+ * stays one cell.
27714
+ */
27715
+ function isTableRow(line) {
27716
+ if (!line.includes("|")) return false;
27717
+ return splitRow(line).length >= 2;
27718
+ }
27719
+ /** GFM delimiter row: cells of only -, :, optional spaces (e.g. |---|:--:|). */
27720
+ function isDelimiterRow(line) {
27721
+ if (!line.includes("|") && !/^[-:\s]+$/.test(line)) return false;
27722
+ const stripped = line.replace(/\|/g, "").trim();
27723
+ if (stripped === "" || !/^[-:\s]+$/.test(stripped)) return false;
27724
+ return splitRow(line).length >= 2 && splitRow(line).every((c) => /^:?-+:?$/.test(c.trim()));
27725
+ }
27726
+ /** Split one pipe row into cells: trim outer pipes, split on inner ones. */
27727
+ function splitRow(line) {
27728
+ let s = line.trim();
27729
+ if (s.startsWith("|")) s = s.slice(1);
27730
+ if (s.endsWith("|")) s = s.slice(0, -1);
27731
+ const literals = [];
27732
+ s = s.replace(/\\\|/g, () => {
27733
+ literals.push("|");
27734
+ return `\u0001${literals.length - 1}\u0001`;
27735
+ });
27736
+ return s.split("|").map((c) => c.replace(/\u0001(\d+)\u0001/g, (_m, idx) => literals[Number(idx)] ?? "").trim());
27737
+ }
27738
+ /** List item line: indent, bullet (- * +) or ordered (N. / N)) marker, body. */
27739
+ var LIST_ITEM_RE = /^(\s*)([-*+]|\d+[.)])\s+(.*)$/;
27740
+ /** Indent width in spaces — a tab advances to the next multiple of 4. */
27741
+ function indentWidth(s) {
27742
+ let w = 0;
27743
+ for (const ch of s) if (ch === " ") w += 4 - w % 4;
27744
+ else w += 1;
27745
+ return w;
27746
+ }
27747
+ /**
27748
+ * Parse one list run from lines[start] (a list item): consecutive item
27749
+ * lines at ANY indent plus lazy plain-text continuations.
27750
+ *
27751
+ * deeper indent than the innermost open item → nests INSIDE it;
27752
+ * same indent → sibling;
27753
+ * kind change (bullet ⇄ ordered) at an EXISTING depth → ends the run
27754
+ * (the outer scan then emits the next list as its own block — the
27755
+ * pre-nesting behavior of two sibling lists is kept);
27756
+ * blank line / fence / heading / quote → run over.
27757
+ *
27758
+ * Mixed kinds still nest when the indent is deeper — a numbered plan
27759
+ * under a bullet is legal CommonMark and common in transcripts.
27760
+ */
27761
+ function parseListRun(lines, start) {
27762
+ const items = [];
27763
+ const stack = [];
27764
+ let i = start;
27765
+ while (i < lines.length) {
27766
+ const l = lines[i];
27767
+ const m = LIST_ITEM_RE.exec(l);
27768
+ if (m) {
27769
+ const indent = indentWidth(m[1]);
27770
+ const ordered = /^\d/.test(m[2]);
27771
+ while (stack.length > 0 && stack[stack.length - 1].indent > indent) stack.pop();
27772
+ if (stack.length === 0) {
27773
+ if (items.length > 0 && ordered !== items[0].ordered) break;
27774
+ const it = {
27775
+ indent,
27776
+ ordered,
27777
+ text: m[3],
27778
+ children: []
27779
+ };
27780
+ items.push(it);
27781
+ stack.push(it);
27782
+ } else {
27783
+ const top = stack[stack.length - 1];
27784
+ if (indent === top.indent && ordered !== top.ordered) break;
27785
+ const it = {
27786
+ indent,
27787
+ ordered,
27788
+ text: m[3],
27789
+ children: []
27790
+ };
27791
+ if (indent > top.indent) top.children.push(it);
27792
+ else {
27793
+ const parent = stack.length >= 2 ? stack[stack.length - 2] : null;
27794
+ if (parent) parent.children.push(it);
27795
+ else items.push(it);
27796
+ stack.pop();
27797
+ }
27798
+ stack.push(it);
27799
+ }
27800
+ i += 1;
27801
+ continue;
27802
+ }
27803
+ if (stack.length > 0 && l.trim() !== "" && !/^(#{1,6})\s|^```|^&gt;/.test(l)) {
27804
+ stack[stack.length - 1].text += ` ${l.trim()}`;
27805
+ i += 1;
27806
+ continue;
27807
+ }
27808
+ break;
27809
+ }
27810
+ return {
27811
+ items,
27812
+ next: i
27813
+ };
27814
+ }
27815
+ /** Emit an item tree — one inline pass per item, children inside the <li>. */
27816
+ function emitList(items) {
27817
+ const tag = items[0].ordered ? "ol" : "ul";
27818
+ return `<${tag}>${items.map((it) => `<li>${renderInline(it.text)}${it.children.length > 0 ? emitList(it.children) : ""}</li>`).join("")}</${tag}>`;
27819
+ }
27820
+ /** Reverse stage-1 escaping — mermaid parses the ORIGINAL syntax, not entities. */
27821
+ function unescapeEntities(text) {
27822
+ return text.replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&quot;", "\"").replaceAll("&#39;", "'").replaceAll("&amp;", "&");
27823
+ }
27824
+ /** Base64 that survives non-ASCII (diagram labels are arbitrary text). */
27825
+ function btoaUnicode(text) {
27826
+ return btoa(String.fromCharCode(...new TextEncoder().encode(text)));
27827
+ }
27828
+ var ESCAPED_CODE_FENCE = /^```/;
27829
+ /**
27830
+ * Stage 0 — the harness wraps tool-result file paths in <path>…</path>
27831
+ * blocks (every attached image rides one). Escaped by stage 1, they
27832
+ * rendered as dead literal text. This pass rewrites each block to a
27833
+ * [basename](full path) markdown link BEFORE escaping, so the existing
27834
+ * machinery takes over: links() emits the scheme-free anchor (its refusal
27835
+ * rules still guard the href) and MarkdownContent's File Link Intent
27836
+ * (ADR 2026-09-25 D2) opens the file on click.
27837
+ *
27838
+ * Fenced code runs are carved out FIRST and passed through verbatim —
27839
+ * the tool-payload rule: a <path> quoted inside a transcript paste is
27840
+ * data, never a link.
27841
+ */
27842
+ function pathBlocksToLinks(text) {
27843
+ const parts = [];
27844
+ const fence = /```[\s\S]*?(```|$)/g;
27845
+ let last = 0;
27846
+ for (const m of text.matchAll(fence)) {
27847
+ parts.push(transformPaths(text.slice(last, m.index)));
27848
+ parts.push(m[0]);
27849
+ last = (m.index ?? 0) + m[0].length;
27850
+ }
27851
+ parts.push(transformPaths(text.slice(last)));
27852
+ return parts.join("");
27853
+ }
27854
+ function transformPaths(text) {
27855
+ return text.replace(/<path>\s*([^\n<]+?)\s*<\/path>/g, (_m, p) => {
27856
+ return `[${p.split("/").pop() || p}](<${p}>)`;
27857
+ });
27858
+ }
27859
+ /**
27860
+ * Render markdown to sanitized HTML (single entry point, BC-12).
27861
+ * Output uses ONLY the allow-listed tags; empty input renders ''.
27862
+ */
27863
+ function renderMarkdown(text) {
27864
+ if (text === "") return "";
27865
+ const escaped = escapeHtml(pathBlocksToLinks(text));
27866
+ const out = [];
27867
+ const lines = escaped.split("\n");
27868
+ let i = 0;
27869
+ while (i < lines.length) {
27870
+ const line = lines[i];
27871
+ if (ESCAPED_CODE_FENCE.test(line.trimStart())) {
27872
+ const opener = line.trimStart().slice(3).trim().toLowerCase();
27873
+ const body = [];
27874
+ i += 1;
27875
+ while (i < lines.length && !ESCAPED_CODE_FENCE.test(lines[i].trimStart())) {
27876
+ body.push(lines[i]);
27877
+ i += 1;
27878
+ }
27879
+ i += 1;
27880
+ if (opener === "mermaid") {
27881
+ const encoded = btoaUnicode(unescapeEntities(body.join("\n")));
27882
+ out.push(`<div class="mermaid-diagram" data-source="${encoded}" data-processed="false"></div>`);
27883
+ continue;
27884
+ }
27885
+ out.push(`<pre><code>${body.join("\n")}</code></pre>`);
27886
+ continue;
27887
+ }
27888
+ if (line.trim() === "") {
27889
+ i += 1;
27890
+ continue;
27891
+ }
27892
+ const heading = /^(#{1,6})\s+(.*)$/.exec(line);
27893
+ if (heading) {
27894
+ const level = Math.min(4, heading[1].length);
27895
+ out.push(`<h${level}>${renderInline(heading[2])}</h${level}>`);
27896
+ i += 1;
27897
+ continue;
27898
+ }
27899
+ if (/^([-*_])(\s*\1){2,}\s*$/.test(line)) {
27900
+ out.push("<hr />");
27901
+ i += 1;
27902
+ continue;
27903
+ }
27904
+ if (isTableRow(line) && i + 1 < lines.length && isDelimiterRow(lines[i + 1])) {
27905
+ const header = splitRow(line);
27906
+ i += 2;
27907
+ const body = [];
27908
+ while (i < lines.length && isTableRow(lines[i]) && !isDelimiterRow(lines[i])) {
27909
+ body.push(splitRow(lines[i]));
27910
+ i += 1;
27911
+ }
27912
+ const thead = `<thead><tr>${header.map((c) => `<th>${renderInline(c)}</th>`).join("")}</tr></thead>`;
27913
+ const tbody = `<tbody>${body.map((row) => `<tr>${row.map((c) => `<td>${renderInline(c)}</td>`).join("")}</tr>`).join("")}</tbody>`;
27914
+ out.push(`<table>${thead}${tbody}</table>`);
27915
+ continue;
27916
+ }
27917
+ if (/^&gt;\s?/.test(line)) {
27918
+ const body = [];
27919
+ while (i < lines.length && /^&gt;\s?/.test(lines[i])) {
27920
+ body.push(lines[i].replace(/^&gt;\s?/, ""));
27921
+ i += 1;
27922
+ }
27923
+ out.push(`<blockquote><p>${renderInline(body.join(" "))}</p></blockquote>`);
27924
+ continue;
27925
+ }
27926
+ if (LIST_ITEM_RE.test(line)) {
27927
+ const run = parseListRun(lines, i);
27928
+ out.push(emitList(run.items));
27929
+ i = run.next;
27930
+ continue;
27931
+ }
27932
+ const para = [];
27933
+ while (i < lines.length && lines[i].trim() !== "" && !ESCAPED_CODE_FENCE.test(lines[i].trimStart()) && !/^#{1,6}\s/.test(lines[i]) && !/^&gt;\s?/.test(lines[i]) && !/^(\s*)([-*+]|\d+[.)])\s+/.test(lines[i]) && !/^([-*_])(\s*\1){2,}\s*$/.test(lines[i]) && !(isTableRow(lines[i]) && i + 1 < lines.length && isDelimiterRow(lines[i + 1]))) {
27934
+ para.push(lines[i]);
27935
+ i += 1;
27936
+ }
27937
+ if (para.length > 0) out.push(`<p>${renderInline(para.join("\n"))}</p>`);
27938
+ }
27939
+ return out.join("\n");
27940
+ }
27941
+ /**
27942
+ * Inline pass: code spans first (their bodies stay verbatim), then emphasis,
27943
+ * then links. Escaped text in, allow-listed tags out.
27944
+ */
27945
+ function renderInline(text) {
27946
+ const codeSpans = [];
27947
+ let rest = text.replace(/`([^`\n]+)`/g, (_m, body) => {
27948
+ const raw = unescapeEntities(body);
27949
+ if (/^https?:\/\/\S+$/i.test(raw)) codeSpans.push(externalAnchor(raw));
27950
+ else codeSpans.push(`<code>${body}</code>`);
27951
+ return `\u0000${codeSpans.length - 1}\u0000`;
27952
+ });
27953
+ rest = emphasis(rest);
27954
+ rest = links(rest);
27955
+ rest = autolinkBareUrls(rest);
27956
+ return rest.replace(/\u0000(\d+)\u0000/g, (_m, idx) => codeSpans[Number(idx)] ?? "");
27957
+ }
27958
+ /** One hardened external anchor from a RAW url — display is origin+path
27959
+ * (query/fragment stripped), href keeps everything (BC-12 attributes). */
27960
+ function externalAnchor(rawUrl) {
27961
+ let cut = rawUrl.length;
27962
+ for (const c of ["?", "#"]) {
27963
+ const i = rawUrl.indexOf(c);
27964
+ if (i !== -1 && i < cut) cut = i;
27965
+ }
27966
+ return `<a href="${rawUrl.replaceAll("\"", "&quot;")}" rel="noopener noreferrer" target="_blank">${rawUrl.slice(0, cut)}</a>`;
27967
+ }
27968
+ /**
27969
+ * Bare-URL autolink (2026-09-27): an http(s) URL in plain text becomes an
27970
+ * anchor whose DISPLAY TEXT is the origin+path with the query/hash stripped
27971
+ * (transcript URLs like …new?merge_request[source_branch]=… render short)
27972
+ * while the HREF keeps the FULL URL. Runs after [label](href) parsing and
27973
+ * skips text inside existing anchors/code placeholders (\u0000N\u0000 markers).
27974
+ * Trailing punctuation ),.,;:!?'"] and matching surrounding parens stay
27975
+ * outside the link (CommonMark's autolink tail rule).
27976
+ */
27977
+ function autolinkBareUrls(text) {
27978
+ return text.replace(/https?:\/\/[^\s<>"'\u0000]+/gi, (whole, offset, full) => {
27979
+ const before = full.slice(Math.max(0, offset - 2e3), offset);
27980
+ if (/<a\s[^>]*$/i.test(before) || /<code>[^<]*$/i.test(before)) return whole;
27981
+ let url = whole;
27982
+ while (url.endsWith(")") && (url.match(/\(/g)?.length ?? 0) < (url.match(/\)/g)?.length ?? 0)) url = url.slice(0, -1);
27983
+ url = url.replace(/[.,;:!?]+$/, "");
27984
+ const tail = whole.slice(url.length);
27985
+ return `${externalAnchor(url)}${tail}`;
27986
+ });
27987
+ }
27988
+ /** ***bold-italic***, **bold**, *italic*, _italic_, ~~strike~~. */
27989
+ function emphasis(text) {
27990
+ return text.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>").replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\*(.+?)\*/g, "<em>$1</em>").replace(/(?<![\w])_(.+?)_(?![\w])/g, "<em>$1</em>").replace(/~~(.+?)~~/g, "<del>$1</del>");
27991
+ }
27992
+ /**
27993
+ * [label](href) — http(s) hrefs become hardened external anchors; SCHEME-FREE
27994
+ * relative hrefs (assistant file links like [card](src/lib/…)) become same-
27995
+ * origin anchors; anything carrying a scheme (javascript:, data:, mailto:,
27996
+ * //evil.com protocol-relative, …) stays inert text (BC-12).
27997
+ */
27998
+ function links(text) {
27999
+ return text.replace(/\[([^\]]+)\]\((?:&lt;([^>]*?)&gt;|([^)\s]+))\)/g, (whole, labelA, angleHref, bareHref) => {
28000
+ const label = labelA;
28001
+ const bare = (angleHref !== void 0 ? angleHref : bareHref).replaceAll("&amp;", "&").replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&quot;", "\"").replaceAll("&#39;", "'").replace(/^<(.+)>$/, "$1");
28002
+ if (/^https?:\/\//i.test(bare)) return `<a href="${bare.replaceAll("\"", "&quot;")}" rel="noopener noreferrer" target="_blank">${label}</a>`;
28003
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(bare) || bare.startsWith("//")) return whole;
28004
+ return `<a href="${bare.replaceAll("\"", "&quot;")}">${label}</a>`;
28005
+ });
28006
+ }
28007
+ //#endregion
27037
28008
  //#region src/lib/utils/file-link.ts
27038
28009
  /**
27039
28010
  * file-link — pure predicates for transcript file links (File Link Intent
@@ -27949,7 +28920,7 @@ function MessageBubble($$renderer, $$props) {
27949
28920
  * stamp mount at the content edge (hover-reveal family, OCI
27950
28921
  * placement); children-only mounts (context chips) get neither.
27951
28922
  */
27952
- let { role, skin, text, time, showSave = true, children, onFileLink } = $$props;
28923
+ let { role, skin, text, time, showSave = true, children, onFileLink, hideMarkdown = false } = $$props;
27953
28924
  /** Raw ⇄ rendered flip state — owned here, wired to ToolsMessage. */
27954
28925
  let showRaw = false;
27955
28926
  /** Bubble element ref — capture target for the canvas copy button. */
@@ -27959,7 +28930,7 @@ function MessageBubble($$renderer, $$props) {
27959
28930
  let $$inner_renderer;
27960
28931
  function $$render_inner($$renderer) {
27961
28932
  $$renderer.push(`<div data-svelte="MessageBubble"${attr_class(`group/bubble relative max-w-[80%] rounded-2xl ${tail()} border px-4 pt-2 pb-3 text-sm leading-relaxed text-text-primary ${stringify(skin)}`)} data-testid="message-bubble"${attr("data-role", role)}>`);
27962
- if (text !== void 0) {
28933
+ if (text !== void 0 && !hideMarkdown) {
27963
28934
  $$renderer.push("<!--[0-->");
27964
28935
  if (showRaw) {
27965
28936
  $$renderer.push("<!--[0-->");
@@ -28032,10 +29003,19 @@ function MessageImages($$renderer, $$props) {
28032
29003
  let { refs = []} = $$props;
28033
29004
  /** Per-slot render state, keyed by attachmentId. */
28034
29005
  let slots = {};
28035
- if (refs.length > 0) {
29006
+ /** The crash guard (each_key_duplicate, operator report 2026-10-31): the
29007
+ * attachment id IS the content hash, so one prompt's ledger can carry
29008
+ * the same image twice — and a keyed each may not. Two refs with one
29009
+ * id are ONE image: keep the first occurrence, render the distinct
29010
+ * set. The boundary is robust against already-written ledgers. */
29011
+ const uniqueRefs = derived(() => {
29012
+ const seen = /* @__PURE__ */ new Set();
29013
+ return refs.filter((r) => seen.has(r.attachmentId) ? false : (seen.add(r.attachmentId), true));
29014
+ });
29015
+ if (uniqueRefs().length > 0) {
28036
29016
  $$renderer.push("<!--[0-->");
28037
29017
  $$renderer.push(`<div data-svelte="MessageImages" class="flex flex-wrap justify-end gap-1.5" data-testid="message-images" role="list"${attr("aria-label", t(attachedimages1))}><!--[-->`);
28038
- const each_array = ensure_array_like(refs);
29018
+ const each_array = ensure_array_like(uniqueRefs());
28039
29019
  for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
28040
29020
  let ref = each_array[$$index];
28041
29021
  if (slots[ref.attachmentId]?.url) {
@@ -28056,6 +29036,33 @@ function MessageImages($$renderer, $$props) {
28056
29036
  });
28057
29037
  }
28058
29038
  //#endregion
29039
+ //#region src/lib/utils/injected-path-table.ts
29040
+ /** The whole trimmed text must be EXACTLY this trio — nothing before or
29041
+ * after, so prose that merely quotes the tags stays inert (the same
29042
+ * rule as markdown.ts's fence carve-out). */
29043
+ var TRIO = /^<path>\s*([^\n<]+?)\s*<\/path>\s*<type>\s*([^\n<]+?)\s*<\/type>\s*<content>\s*([\s\S]+?)\s*<\/content>\s*$/;
29044
+ function parseInjectedPathTable(text) {
29045
+ const m = TRIO.exec(text.trim());
29046
+ if (!m) return null;
29047
+ const path = m[1].trim();
29048
+ if (path === "") return null;
29049
+ return [
29050
+ {
29051
+ key: "path",
29052
+ value: path,
29053
+ href: path
29054
+ },
29055
+ {
29056
+ key: "type",
29057
+ value: m[2].trim()
29058
+ },
29059
+ {
29060
+ key: "content",
29061
+ value: m[3].trim().replaceAll("\n", " ")
29062
+ }
29063
+ ];
29064
+ }
29065
+ //#endregion
28059
29066
  //#region src/lib/components/message/prompt/PromptBubble.svelte
28060
29067
  function PromptBubble($$renderer, $$props) {
28061
29068
  $$renderer.component(($$renderer) => {
@@ -28095,8 +29102,13 @@ function PromptBubble($$renderer, $$props) {
28095
29102
  * the row, OCI placement). Assistant responses live in AssistantTurn —
28096
29103
  * this bubble is user-side only.
28097
29104
  */
28098
- let { text, time, tone = "prompt", imageRefs = [], sessionId, children, onFileLink } = $$props;
29105
+ let { text, time, tone = "prompt", imageRefs = [], sessionId, children, onFileLink, meta } = $$props;
28099
29106
  const skin = derived(() => tone === "context" ? "bg-accent-blue/10 border-accent-blue/20" : "bg-accent-blue/15 border-accent-blue/20");
29107
+ /** 2026-10-29: an INJECTED message whose text is exactly the harness's
29108
+ * <path>/<type>/<content> trio renders as a key/value table (path value
29109
+ * is a file link) instead of dead escaped tags. Human prompts and
29110
+ * quoting prose never match (the parser is whole-block strict). */
29111
+ const injectedRows = derived(() => meta === "injected" && text !== void 0 ? parseInjectedPathTable(text) : null);
28100
29112
  $$renderer.push(`<div data-svelte="PromptBubble" class="flex w-full min-w-0 flex-col items-end gap-1.5">`);
28101
29113
  if (imageRefs.length > 0 && sessionId !== void 0) {
28102
29114
  $$renderer.push("<!--[0-->");
@@ -28112,7 +29124,29 @@ function PromptBubble($$renderer, $$props) {
28112
29124
  text,
28113
29125
  time,
28114
29126
  onFileLink,
29127
+ hideMarkdown: injectedRows() !== null,
29128
+ showSave: injectedRows() === null,
28115
29129
  children: ($$renderer) => {
29130
+ if (injectedRows()) {
29131
+ $$renderer.push("<!--[0-->");
29132
+ $$renderer.push(`<table class="injected-data-table w-full border-collapse text-xs" data-testid="injected-data-table"><tbody><!--[-->`);
29133
+ const each_array = ensure_array_like(injectedRows());
29134
+ for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
29135
+ let row = each_array[$$index];
29136
+ $$renderer.push(`<tr class="border-b border-surface-border/40"><td class="k w-20 shrink-0 py-1 pr-2 align-top font-medium opacity-60">${escape_html(row.key)}</td><td class="v py-1 break-all">`);
29137
+ if (row.href && onFileLink) {
29138
+ $$renderer.push("<!--[0-->");
29139
+ row.href;
29140
+ $$renderer.push(`<button type="button" class="cursor-pointer text-left underline underline-offset-2 hover:opacity-80">${escape_html(row.value.split("/").pop())}</button>`);
29141
+ } else {
29142
+ $$renderer.push("<!--[-1-->");
29143
+ $$renderer.push(`${escape_html(row.value)}`);
29144
+ }
29145
+ $$renderer.push(`<!--]--></td></tr>`);
29146
+ }
29147
+ $$renderer.push(`<!--]--></tbody></table>`);
29148
+ } else $$renderer.push("<!--[-1-->");
29149
+ $$renderer.push(`<!--]--> `);
28116
29150
  if (children) {
28117
29151
  $$renderer.push("<!--[0-->");
28118
29152
  children($$renderer);
@@ -28155,6 +29189,9 @@ function ContextInjectionChip($$renderer, $$props) {
28155
29189
  "skill-catalog": () => ctxchipskills2(),
28156
29190
  "skill-invocation": () => ctxchipskill2(),
28157
29191
  "user-approval": () => ctxchipuserapproval3(),
29192
+ goal: () => ctxchipgoal2(),
29193
+ "tool-goal": () => ctxchiptoolgoal3(),
29194
+ "time-context": () => ctxchiptimecontext3(),
28158
29195
  compaction: () => ctxchipcompact2(),
28159
29196
  plugin: () => ctxchipplugin2(),
28160
29197
  recall: () => ctxchiprecall2(),
@@ -28172,7 +29209,14 @@ function ContextInjectionChip($$renderer, $$props) {
28172
29209
  if (producer === "plugin" || producer === "injected") return name;
28173
29210
  return label;
28174
29211
  });
28175
- $$renderer.push(`<div data-svelte="ContextInjectionChip" class="text-xs" data-testid="context-injection-chip"${attr("data-producer", producer)}${attr("data-open", open)}><span class="inline-flex items-center"><button type="button"${attr("aria-expanded", open)} data-testid="context-injection-toggle"${attr("aria-label", title())}${attr_class(`chip-button inline-flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-mono font-medium max-w-full mx-0.5 my-0.5 align-middle shrink-0 transition-colors select-none cursor-pointer ${open ? "bg-accent-purple/20 text-accent-purple border border-accent-purple/30" : "bg-surface0/10 text-text-secondary border border-text-muted/20 hover:bg-surface0/20 hover:text-text-primary"}`, "svelte-hhkfw6")}>`);
29212
+ const WIRE_NAMED = [
29213
+ "goal",
29214
+ "tool-goal",
29215
+ "time-context"
29216
+ ];
29217
+ const wireName = derived(() => name !== void 0 && name !== "" && WIRE_NAMED.includes(producer) ? name : void 0);
29218
+ const aria = derived(() => wireName() === void 0 ? title() : `${title()} (${wireName()})`);
29219
+ $$renderer.push(`<div data-svelte="ContextInjectionChip" class="text-xs" data-testid="context-injection-chip"${attr("data-producer", producer)}${attr("data-open", open)}><span class="inline-flex items-center"><button type="button"${attr("aria-expanded", open)} data-testid="context-injection-toggle"${attr("aria-label", aria())}${attr("title", wireName())}${attr_class(`chip-button inline-flex items-center gap-1 px-1.5 py-0.5 rounded-md text-xs font-mono font-medium max-w-full mx-0.5 my-0.5 align-middle shrink-0 transition-colors select-none cursor-pointer ${open ? "bg-accent-purple/20 text-accent-purple border border-accent-purple/30" : "bg-surface0/10 text-text-secondary border border-text-muted/20 hover:bg-surface0/20 hover:text-text-primary"}`, "svelte-hhkfw6")}>`);
28176
29220
  if (open) {
28177
29221
  $$renderer.push("<!--[0-->");
28178
29222
  Chevron_down($$renderer, { size: 10 });
@@ -28207,7 +29251,11 @@ function chipNameOf(meta, metaSource) {
28207
29251
  return str(refs[0]?.label);
28208
29252
  }
28209
29253
  case "plugin": return str(metaSource?.plugin);
29254
+ case "goal":
29255
+ case "tool-goal":
29256
+ case "time-context": return str(metaSource?.plugin) ?? str(metaSource?.kind);
28210
29257
  case "injected": return str(metaSource?.kind);
29258
+ case "user-approval": return str(metaSource?.plugin) ?? str(metaSource?.kind);
28211
29259
  default: return;
28212
29260
  }
28213
29261
  }
@@ -30842,6 +31890,7 @@ function ConversationScrollArea($$renderer, $$props) {
30842
31890
  time: group.kind === "prompt" ? group.entry.time : group.entries[0]?.time,
30843
31891
  tone: group.kind === "prompt" ? "prompt" : "context",
30844
31892
  imageRefs: group.kind === "prompt" ? group.entry.imageRefs : void 0,
31893
+ meta: group.kind === "prompt" ? group.entry.meta : void 0,
30845
31894
  sessionId,
30846
31895
  onFileLink,
30847
31896
  children: ($$renderer) => {
@@ -31955,6 +33004,17 @@ function focusedInsertionSlot(panels, selectedIndex, parentOf) {
31955
33004
  * re-export hub, never by importing another sibling directly.
31956
33005
  */
31957
33006
  var d$4 = floorSeam;
33007
+ /** The rack's tab intent (The Plugin Rack ADR, 2026-09-27): same
33008
+ * persisted-entry write as the shelf's - panel-prefs saves the blob,
33009
+ * a hard reload restores the active tab. */
33010
+ function setRackTab(panelId, tab) {
33011
+ const idx = st.panels.findIndex((p) => p.id === panelId);
33012
+ if (idx < 0 || st.panels[idx].kind !== "plugin-rack") return;
33013
+ st.panels = st.panels.with(idx, {
33014
+ ...st.panels[idx],
33015
+ tab
33016
+ });
33017
+ }
31958
33018
  /** Chip click action: ONE explorer per WORKSPACE root across ALL
31959
33019
  * sessions — a click on any session sharing the root FOCUSES the open
31960
33020
  * explorer (dedupe key = root, D1); a fresh root lands at the focused
@@ -32071,6 +33131,11 @@ function activateExplorerTab(panelId, path) {
32071
33131
  function setExplorerTreePct(_panelId, pct) {
32072
33132
  d$4().setTreePct(clampTreePct(pct));
32073
33133
  }
33134
+ /** Explorer hide/show (2026-10-31): one DESK fact like the tree percent —
33135
+ * the toggle flips it through the configured setter (pagePrefs persist). */
33136
+ function setExplorerHidden(_panelId, hidden) {
33137
+ d$4().setExplorerHidden?.(hidden);
33138
+ }
32074
33139
  /** Git Eye repo-collapse intent (2026-09-13): the collapsed repo set is
32075
33140
  * PERSISTED on the entry. Default is EXPANDED. */
32076
33141
  function toggleExplorerRepo(panelId, repoRel) {
@@ -33216,12 +34281,17 @@ function ConversationPanel($$renderer, $$props) {
33216
34281
  /** Context consumption (2026-08-23): the LAST assistant usage record
33217
34282
  * across the ledger — what the most recent model request consumed
33218
34283
  * (uncached input + cache-read + cache-write = the full prompt seen).
33219
- * Wire truth via DsiTokenUsage; undefined until a turn finalizes. */
34284
+ * Wire truth via DsiTokenUsage; 0 once the session has ledger entries
34285
+ * but no usage yet (aborted turn / pre-first-finalize — SC#1
34286
+ * 2026-11-01: an aborted turn leaves no usage record, and the honest
34287
+ * display is "≈0 ctx", not a dead slot). Undefined only on an empty
34288
+ * session (no entries at all). */
33220
34289
  const contextTokens = derived(() => {
33221
34290
  for (let i = store.entries.length - 1; i >= 0; i--) {
33222
34291
  const e = store.entries[i];
33223
34292
  if (e.kind === "assistant-message" && e.usage !== void 0) return e.usage.inputTokens + (e.usage.cacheReadTokens ?? 0) + (e.usage.cacheWriteTokens ?? 0);
33224
34293
  }
34294
+ return store.entries.length > 0 ? 0 : void 0;
33225
34295
  });
33226
34296
  const totalContextLimit = derived(() => contextWindowOf());
33227
34297
  /** Session baseline (ADR 2026-09-08 "The Stats Bar", D2): this
@@ -33471,6 +34541,132 @@ function ConversationPanel($$renderer, $$props) {
33471
34541
  });
33472
34542
  }
33473
34543
  //#endregion
34544
+ //#region src/lib/utils/key-chords.ts
34545
+ /**
34546
+ * key-chords.ts — the Alt+S width-preset chord machine (ADR-0006a).
34547
+ *
34548
+ * A PURE reducer: every transition is (state, event, facts) -> { state,
34549
+ * action }. No DOM, no stores, no timers — the caller owns the clock
34550
+ * (now) and the wiring (which element heard the key). This is what makes
34551
+ * the chord unit-testable to every branch, and keeps the route keydown
34552
+ * listener a three-line adapter.
34553
+ *
34554
+ * Grammar: press-and-release Alt+S arms a CHORD_WINDOW_MS window; a
34555
+ * following digit 1..9 fires { apply, n }; any other key or the window
34556
+ * expiring disarms. Alt+S never arms when the floor has no presets (D4:
34557
+ * silent absence — the feature gates itself).
34558
+ */
34559
+ var CHORD_WINDOW_MS = 2e3;
34560
+ var IDLE_CHORD = {
34561
+ armed: false};
34562
+ /** Verb → label (the palette renders these; D16). */
34563
+ var CHORD_VERB_LABELS = {
34564
+ a: "Close agent extras (terminals + sub-agents + explorers)",
34565
+ b: "Close all glass browsers",
34566
+ g: "Toggle plugin manager",
34567
+ k: "Toggle skill manager",
34568
+ c: "Close config explorers",
34569
+ n: "New session, same agent + workspace",
34570
+ p: "Toggle prompt manager",
34571
+ s: "Toggle sidebar",
34572
+ t: "Toggle terminal",
34573
+ w: "Close workspace explorers"
34574
+ };
34575
+ /** The live palette rows (D16): derived PURELY from what exists right now.
34576
+ * presets gate the digit lanes (D4), panelKinds (+ subagentCount) gate the
34577
+ * verbs; the p/t toggles are always live — their add path creates the
34578
+ * target. No registry import: the wiring feeds the facts in. */
34579
+ function chordOptions(facts) {
34580
+ const rows = [];
34581
+ const slots = /* @__PURE__ */ new Set([
34582
+ ...Object.keys(facts.presets.agent).map(Number),
34583
+ ...Object.keys(facts.presets.glass).map(Number),
34584
+ ...Object.keys(facts.presets.sidebar).map(Number),
34585
+ ...Object.keys(facts.presets.zoom ?? {}).map(Number)
34586
+ ]);
34587
+ for (const n of [...slots].sort((x, y) => x - y)) rows.push({
34588
+ key: String(n),
34589
+ label: `Width preset ${n}`
34590
+ });
34591
+ const kinds = new Set(facts.panelKinds);
34592
+ if (kinds.has("terminal") || kinds.has("workspace-explorer") || kinds.has("plugin-rack") || kinds.has("skill-shelf") || facts.subagentCount > 0) rows.push({
34593
+ key: "a",
34594
+ label: CHORD_VERB_LABELS.a
34595
+ });
34596
+ if (kinds.has("browser")) rows.push({
34597
+ key: "b",
34598
+ label: CHORD_VERB_LABELS.b
34599
+ });
34600
+ if (kinds.has("settings-home") || kinds.has("skill-shelf") || kinds.has("plugin-rack")) rows.push({
34601
+ key: "c",
34602
+ label: CHORD_VERB_LABELS.c
34603
+ });
34604
+ rows.push({
34605
+ key: "p",
34606
+ label: CHORD_VERB_LABELS.p
34607
+ });
34608
+ rows.push({
34609
+ key: "g",
34610
+ label: CHORD_VERB_LABELS.g
34611
+ });
34612
+ rows.push({
34613
+ key: "k",
34614
+ label: CHORD_VERB_LABELS.k
34615
+ });
34616
+ rows.push({
34617
+ key: "t",
34618
+ label: CHORD_VERB_LABELS.t
34619
+ });
34620
+ if (facts.focusedConversation) rows.push({
34621
+ key: "n",
34622
+ label: CHORD_VERB_LABELS.n
34623
+ });
34624
+ rows.push({
34625
+ key: "s",
34626
+ label: CHORD_VERB_LABELS.s
34627
+ });
34628
+ if (kinds.has("workspace-explorer")) rows.push({
34629
+ key: "w",
34630
+ label: CHORD_VERB_LABELS.w
34631
+ });
34632
+ return rows.sort((x, y) => x.key.localeCompare(y.key));
34633
+ }
34634
+ //#endregion
34635
+ //#region src/lib/components/panels/ChordPalette.svelte
34636
+ function ChordPalette($$renderer, $$props) {
34637
+ $$renderer.component(($$renderer) => {
34638
+ /**
34639
+ * ChordPalette — the armed Alt+S chord's face (ADR-0006a amendment
34640
+ * D16/D18, 2026-10-31). Centered on the viewport; while armed it fills
34641
+ * a footer progress bar 0→100% across IDLE_CLOSE_MS — pastel-green
34642
+ * while the chord's 2s action window (CHORD_WINDOW_MS) is open,
34643
+ * pastel-yellow after — and at 100% fires `onexpire` (the route resets
34644
+ * the chord to idle). The clock is THIS component's visibility
34645
+ * lifecycle (D18: view-lifecycle, not reducer state); every other rule
34646
+ * of the pure view stands: no stores, no key handlers.
34647
+ */
34648
+ /** The 10s idle window before the palette closes itself (D18). */
34649
+ const IDLE_CLOSE_MS = 1e4;
34650
+ let { open, rows} = $$props;
34651
+ let now = Date.now();
34652
+ const elapsed = derived(() => open ? Math.max(0, Math.min(now - (Date.now()), IDLE_CLOSE_MS)) : 0);
34653
+ const pct = derived(() => Math.round(elapsed() / IDLE_CLOSE_MS * 100));
34654
+ const inActionWindow = derived(() => elapsed() < CHORD_WINDOW_MS);
34655
+ const barColor = derived(() => inActionWindow() ? "bg-green-300" : "bg-yellow-200");
34656
+ if (open) {
34657
+ $$renderer.push("<!--[0-->");
34658
+ $$renderer.push(`<div data-svelte="ChordPalette" class="fixed top-1/2 left-1/2 z-50 w-72 -translate-x-1/2 -translate-y-1/2 rounded-lg border border-black/10 bg-white/95 px-3 py-2 shadow-lg backdrop-blur dark:border-white/15 dark:bg-neutral-900/95" data-testid="chord-palette"${attr("data-chord-elapsed", elapsed())} aria-live="polite"${attr("aria-label", t(() => chordarmedlabel2()))}><div class="mb-1 text-[10px] font-semibold tracking-wide text-neutral-400 uppercase">${escape_html(t(() => chordarmedtitle2()))}</div> <ul class="m-0 list-none space-y-0.5 p-0"><!--[-->`);
34659
+ const each_array = ensure_array_like(rows);
34660
+ for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
34661
+ let row = each_array[$$index];
34662
+ $$renderer.push(`<li class="flex items-center gap-2 text-xs" data-testid="chord-palette-row"${attr("data-chord-key", row.key)}><kbd class="min-w-5 rounded border border-black/15 bg-neutral-100 px-1 text-center font-mono text-[11px] dark:border-white/20 dark:bg-neutral-800">${escape_html(row.key)}</kbd> <span class="text-neutral-700 dark:text-neutral-200">${escape_html(row.label)}</span></li>`);
34663
+ }
34664
+ $$renderer.push(`<!--]--></ul> <div class="mt-2 h-1 w-full overflow-hidden rounded bg-neutral-200 dark:bg-neutral-700" data-testid="chord-palette-decay"><div${attr_class(`h-full ${barColor()} transition-[width] duration-100 ease-linear`)}${attr_style(`width: ${stringify(pct())}%`)} data-testid="chord-palette-progress"${attr("data-chord-phase", inActionWindow() ? "action" : "idle")}></div></div></div>`);
34665
+ } else $$renderer.push("<!--[-1-->");
34666
+ $$renderer.push(`<!--]-->`);
34667
+ });
34668
+ }
34669
+ //#endregion
33474
34670
  //#region src/lib/components/terminal/frame-state.ts
33475
34671
  var initialTerminalPanelState = {
33476
34672
  lastSettle: null,
@@ -33520,24 +34716,71 @@ function TerminalPanel($$renderer, $$props) {
33520
34716
  //#endregion
33521
34717
  //#region src/lib/components/terminal/TerminalTabHeader.svelte
33522
34718
  function TerminalTabHeader($$renderer, $$props) {
33523
- let { children, actions } = $$props;
33524
- $$renderer.push(`<div data-svelte="TerminalTabHeader" role="tablist" class="flex items-center gap-1 border-b border-slate-800 px-1 py-0.5" data-testid="terminal-tab-header">`);
33525
- children($$renderer);
33526
- $$renderer.push(`<!----> `);
33527
- if (actions) {
33528
- $$renderer.push("<!--[0-->");
33529
- $$renderer.push(`<div class="ml-auto flex items-center" data-testid="terminal-tab-header-actions">`);
33530
- actions($$renderer);
33531
- $$renderer.push(`<!----></div>`);
33532
- } else $$renderer.push("<!--[-1-->");
33533
- $$renderer.push(`<!--]--></div>`);
34719
+ $$renderer.component(($$renderer) => {
34720
+ /**
34721
+ * TerminalTabHeader — the desk's tablist strip (Terminal Desk ADR D1,
34722
+ * Wave 2; amended 2026-11-03 D5a/D5b): presentation only; the desk owns
34723
+ * selection state. The strip SCROLLS when crowded (overflow-x) and the
34724
+ * sticky clear control sits in a fixed slot at the right edge, OUTSIDE
34725
+ * the scroller. The popover's three scope verbs (Clear all / Clear jobs /
34726
+ * Clear terminals) emit ONE onClear intent — the desk resolves scope.
34727
+ * No Cancel verb: outside click or Esc cancels.
34728
+ */
34729
+ let { children, actions, onClear } = $$props;
34730
+ let clearOpen = false;
34731
+ $$renderer.push(`<div data-svelte="TerminalTabHeader" class="flex min-w-0 items-center gap-1 border-b border-slate-800 px-1 py-0.5" data-testid="terminal-tab-header"><div class="strip flex min-w-0 flex-1 items-center gap-1 overflow-x-auto" role="tablist" data-testid="terminal-tabstrip">`);
34732
+ children($$renderer);
34733
+ $$renderer.push(`<!----></div> `);
34734
+ if (onClear) {
34735
+ $$renderer.push("<!--[0-->");
34736
+ $$renderer.push(`<div class="clear-slot relative flex flex-none items-center" data-testid="terminal-tabstrip-clear-slot"><button type="button" class="clear-btn flex h-5 w-5 items-center justify-center rounded border border-slate-600 text-[0.8rem] leading-none text-slate-400 hover:bg-slate-700 hover:text-slate-200" data-testid="terminal-tabstrip-clear"${attr("aria-label", t(terminaltabsclear2))}${attr("title", t(terminaltabsclear2))}${attr("aria-expanded", clearOpen)}>×</button> `);
34737
+ $$renderer.push("<!--[-1-->");
34738
+ $$renderer.push(`<!--]--></div>`);
34739
+ } else $$renderer.push("<!--[-1-->");
34740
+ $$renderer.push(`<!--]--> `);
34741
+ if (actions) {
34742
+ $$renderer.push("<!--[0-->");
34743
+ $$renderer.push(`<div class="ml-auto flex flex-none items-center" data-testid="terminal-tab-header-actions">`);
34744
+ actions($$renderer);
34745
+ $$renderer.push(`<!----></div>`);
34746
+ } else $$renderer.push("<!--[-1-->");
34747
+ $$renderer.push(`<!--]--></div>`);
34748
+ });
34749
+ }
34750
+ //#endregion
34751
+ //#region src/lib/components/common/buttons/CloseButton.svelte
34752
+ function CloseButton($$renderer, $$props) {
34753
+ $$renderer.component(($$renderer) => {
34754
+ /**
34755
+ * CloseButton — the tab-strip ✕ as a reusable button (extracted from
34756
+ * BrowserTab 2026-11-02; TerminalTabButton's inline ✕ span migrated same
34757
+ * day). Presentational (house button pattern, see ReloadButton): the
34758
+ * CALLER owns what closing means and ALL the chrome — pass Tailwind
34759
+ * classes via `class`; the button renders the glyph and reports the click.
34760
+ *
34761
+ * Contract: the click NEVER bubbles (both tab callers stopPropagation'd —
34762
+ * the strip's select must not fire when the ✕ is hit) and the button is
34763
+ * focusable only when the caller says so (`tabindex` — the terminal tab
34764
+ * passes -1 so keyboard focus lands on the tab, not the close).
34765
+ */
34766
+ let { onclick, label, testid, tabindex = void 0, class: className = "" } = $$props;
34767
+ $$renderer.push(`<button data-svelte="CloseButton" type="button"${attr_class(clsx(className))}${attr("data-testid", testid)}${attr("title", label)}${attr("aria-label", label)}${attr("tabindex", tabindex)}>✕</button>`);
34768
+ });
33534
34769
  }
33535
34770
  //#endregion
33536
34771
  //#region src/lib/components/terminal/TerminalTabButton.svelte
33537
34772
  function TerminalTabButton($$renderer, $$props) {
33538
34773
  $$renderer.component(($$renderer) => {
33539
34774
  let { index, selected, label, title, onSelect, onClose } = $$props;
33540
- $$renderer.push(`<div data-svelte="TerminalTabButton" role="tab"${attr("title", title ?? label)}${attr("aria-selected", selected)} tabindex="0"${attr_class(`flex cursor-pointer items-center gap-1 rounded px-2 py-0.5 text-[10px] ${selected ? "bg-slate-700 text-slate-100" : "text-slate-400 hover:bg-slate-800"}`)}${attr("data-testid", `terminal-tab-button-${stringify(index)}`)}${attr("data-selected", selected ? "true" : "false")}><span>${escape_html(label)}</span> <span class="ml-1 rounded px-1 text-slate-500 hover:bg-slate-600 hover:text-slate-200" role="button" tabindex="-1"${attr("aria-label", t(terminaltabclose2) + " " + label)}${attr("data-testid", `terminal-tab-close-${stringify(index)}`)}>×</span></div>`);
34775
+ $$renderer.push(`<div data-svelte="TerminalTabButton" role="tab"${attr("title", title ?? label)}${attr("aria-selected", selected)} tabindex="0"${attr_class(`flex cursor-pointer items-center gap-1 rounded px-2 py-0.5 text-[10px] ${selected ? "bg-slate-700 text-slate-100" : "text-slate-400 hover:bg-slate-800"}`)}${attr("data-testid", `terminal-tab-button-${stringify(index)}`)}${attr("data-selected", selected ? "true" : "false")}><span>${escape_html(label)}</span> `);
34776
+ CloseButton($$renderer, {
34777
+ class: "ml-1 rounded px-1 text-slate-500 hover:bg-slate-600 hover:text-slate-200",
34778
+ label: t(terminaltabclose2) + " " + label,
34779
+ testid: `terminal-tab-close-${stringify(index)}`,
34780
+ tabindex: -1,
34781
+ onclick: () => onClose()
34782
+ });
34783
+ $$renderer.push(`<!----></div>`);
33541
34784
  });
33542
34785
  }
33543
34786
  //#endregion
@@ -33713,7 +34956,14 @@ function JobTail($$renderer, $$props) {
33713
34956
  $$renderer.push(`<!--]--> `);
33714
34957
  if (tail().lines.length === 0) {
33715
34958
  $$renderer.push("<!--[0-->");
33716
- $$renderer.push(`<div class="text-slate-500" data-testid="job-tail-empty">${escape_html(jobtailwaiting2())}</div>`);
34959
+ if (tail().settled) {
34960
+ $$renderer.push("<!--[0-->");
34961
+ $$renderer.push(`<div class="text-slate-500" data-testid="job-tail-empty">${escape_html(jobtailempty2())}</div>`);
34962
+ } else {
34963
+ $$renderer.push("<!--[-1-->");
34964
+ $$renderer.push(`<div class="text-slate-500" data-testid="job-tail-empty">${escape_html(jobtailwaiting2())}</div>`);
34965
+ }
34966
+ $$renderer.push(`<!--]-->`);
33717
34967
  } else $$renderer.push("<!--[-1-->");
33718
34968
  $$renderer.push(`<!--]--> <!--[-->`);
33719
34969
  const each_array = ensure_array_like(tail().lines);
@@ -33867,6 +35117,42 @@ function TerminalDesk($$renderer, $$props) {
33867
35117
  }
33868
35118
  selectedTab = Math.min(tabIndex, tabs.length - 1);
33869
35119
  }
35120
+ /** Ladder-close ONE row's session without touching the tab arrays —
35121
+ * the clear verb's per-session half (ADR D5c amendment 2026-11-03). */
35122
+ function killRow(row) {
35123
+ if (!row.assigned) return;
35124
+ fetch("/api/terminal/" + row.assigned.sessionId + "/send", {
35125
+ method: "POST",
35126
+ headers: { "content-type": "application/json" },
35127
+ body: JSON.stringify({
35128
+ token: row.assigned.token,
35129
+ action: "close"
35130
+ }),
35131
+ keepalive: true
35132
+ }).catch(() => void 0);
35133
+ }
35134
+ /** The clear verb's scope resolution (ADR D5b/D5c amendment 2026-11-03):
35135
+ * jobs ⇒ close every job-follower tab (roster unwatch, PTYs untouched);
35136
+ * terminals ⇒ ladder-close every shell session, then mint ONE fresh T1
35137
+ * and select it — the fresh-T1 rule: the desk slot is NEVER removed by
35138
+ * a clear verb, so D5's last-shell onShellExit cascade does not run
35139
+ * here. all ⇒ both, ending in fresh T1. */
35140
+ function clearScope(scope) {
35141
+ if (scope === "jobs" || scope === "all") for (const job of [...jobTabs]) closeJobTab(job);
35142
+ if (scope === "terminals" || scope === "all") {
35143
+ for (const tab of tabs) for (const row of tab.rows) killRow(row);
35144
+ tabs.splice(0, tabs.length);
35145
+ (async () => {
35146
+ const row = await mintSession();
35147
+ if (!row) return;
35148
+ tabs.push({
35149
+ key: mkKey(),
35150
+ rows: [row]
35151
+ });
35152
+ selectedTab = 0;
35153
+ })();
35154
+ }
35155
+ }
33870
35156
  /** Shell exit in a row (D5): the session is already dead — shrink the
33871
35157
  * tab; an empty tab closes (selection rules as closeTab); the desk's
33872
35158
  * last shell dying removes the slot (if only one terminal overall, it
@@ -33890,6 +35176,7 @@ function TerminalDesk($$renderer, $$props) {
33890
35176
  } else {
33891
35177
  $$renderer.push("<!--[-1-->");
33892
35178
  TerminalTabHeader($$renderer, {
35179
+ onClear: clearScope,
33893
35180
  children: ($$renderer) => {
33894
35181
  $$renderer.push(`<!--[-->`);
33895
35182
  const each_array = ensure_array_like(tabs);
@@ -33902,20 +35189,19 @@ function TerminalDesk($$renderer, $$props) {
33902
35189
  onSelect: () => selectedTab = i,
33903
35190
  onClose: () => closeTab(i)
33904
35191
  });
33905
- $$renderer.push(`<!----> <!--[-->`);
33906
- const each_array_1 = ensure_array_like(jobTabs);
33907
- for (let ji = 0, $$length = each_array_1.length; ji < $$length; ji++) {
33908
- let job = each_array_1[ji];
33909
- TerminalTabButton($$renderer, {
33910
- index: tabs.length + ji,
33911
- label: "T" + (tabs.length + ji + 1) + "-J",
33912
- title: job.label || job.jobId,
33913
- selected: tabs.length + ji === selectedTab,
33914
- onSelect: () => selectedTab = tabs.length + ji,
33915
- onClose: () => closeJobTab(job)
33916
- });
33917
- }
33918
- $$renderer.push(`<!--]-->`);
35192
+ }
35193
+ $$renderer.push(`<!--]--> <!--[-->`);
35194
+ const each_array_1 = ensure_array_like(jobTabs);
35195
+ for (let ji = 0, $$length = each_array_1.length; ji < $$length; ji++) {
35196
+ let job = each_array_1[ji];
35197
+ TerminalTabButton($$renderer, {
35198
+ index: tabs.length + ji,
35199
+ label: "T" + (tabs.length + ji + 1) + "-J",
35200
+ title: job.label || job.jobId,
35201
+ selected: tabs.length + ji === selectedTab,
35202
+ onSelect: () => selectedTab = tabs.length + ji,
35203
+ onClose: () => closeJobTab(job)
35204
+ });
33919
35205
  }
33920
35206
  $$renderer.push(`<!--]-->`);
33921
35207
  }});
@@ -34045,19 +35331,170 @@ function removeBrowserSlot(sessionId, storage = defaultStorage()) {
34045
35331
  function primeBrowserSlotStore(storage = defaultStorage()) {
34046
35332
  browserSlotStore.set(readBrowserSlots(storage));
34047
35333
  }
35334
+ var SS_KEY = "dsi.harness.sessionKey.v2";
35335
+ var capturedKey = null;
35336
+ function tabStorage() {
35337
+ try {
35338
+ return typeof sessionStorage !== "undefined" ? sessionStorage : null;
35339
+ } catch {
35340
+ return null;
35341
+ }
35342
+ }
35343
+ /** Called once at page init, BEFORE the URL cleanup, with the still-present
35344
+ * sessionKey query param. A real key WINS over any tab memory (the tab was
35345
+ * (re)seeded with a concrete conversation) and is remembered for reloads;
35346
+ * null means "bare load" — fall back to the tab memory, never clear it. */
35347
+ function captureHarnessSessionKey(key) {
35348
+ const ss = tabStorage();
35349
+ if (key !== null && key.length > 0) {
35350
+ capturedKey = key;
35351
+ try {
35352
+ ss?.setItem(SS_KEY, key);
35353
+ } catch {}
35354
+ return;
35355
+ }
35356
+ if (!capturedKey) try {
35357
+ capturedKey = ss?.getItem(SS_KEY) ?? null;
35358
+ } catch {
35359
+ capturedKey = null;
35360
+ }
35361
+ }
35362
+ /** The harness conversation session key — the client-side source of the D7
35363
+ * ownership fact. Order: load-time capture → tab memory → live URL.
35364
+ * Null when all three are absent (degraded: legacy behavior). */
35365
+ function harnessSessionKey() {
35366
+ if (capturedKey) return capturedKey;
35367
+ try {
35368
+ const stored = tabStorage()?.getItem(SS_KEY) ?? null;
35369
+ if (stored) {
35370
+ capturedKey = stored;
35371
+ return stored;
35372
+ }
35373
+ } catch {}
35374
+ try {
35375
+ if (typeof location === "undefined") return null;
35376
+ const k = new URLSearchParams(location.search).get("sessionKey");
35377
+ return k !== null && k.length > 0 ? k : null;
35378
+ } catch {
35379
+ return null;
35380
+ }
35381
+ }
34048
35382
  //#endregion
34049
- //#region src/lib/components/browser/BrowserClosed.svelte
35383
+ //#region src/lib/components/common/buttons/ReloadButton.svelte
35384
+ function ReloadButton($$renderer, $$props) {
35385
+ /**
35386
+ * ReloadButton — the refresh icon with the CanvasCopyButton feedback
35387
+ * machine (extracted from WorkspaceFileToolbar 2026-10-28): idle
35388
+ * RotateCw → busy Loader2 spin → done Check → idle. Presentational
35389
+ * (house button pattern): the CALLER owns the state machine and what
35390
+ * a reload means — the button renders the state and reports the click.
35391
+ *
35392
+ * Styling: no chrome of its own — pass Tailwind classes via `class`
35393
+ * (the CanvasCopyButton pattern); each surface keeps its own chip
35394
+ * grammar and `data-testid`.
35395
+ */
35396
+ let { state = "idle", onclick, label, testid, disabled = false, size = 14, class: className = "" } = $$props;
35397
+ $$renderer.push(`<button data-svelte="ReloadButton" type="button"${attr_class(clsx(className))}${attr("data-testid", testid)}${attr("data-state", state)}${attr("title", label)}${attr("aria-label", label)}${attr("disabled", disabled, true)}>`);
35398
+ if (state === "done") {
35399
+ $$renderer.push("<!--[0-->");
35400
+ Check($$renderer, {
35401
+ size,
35402
+ class: "text-status-pass"
35403
+ });
35404
+ } else if (state === "busy") {
35405
+ $$renderer.push("<!--[1-->");
35406
+ Loader_circle($$renderer, {
35407
+ size,
35408
+ class: "animate-spin"
35409
+ });
35410
+ } else {
35411
+ $$renderer.push("<!--[-1-->");
35412
+ Rotate_cw($$renderer, { size });
35413
+ }
35414
+ $$renderer.push(`<!--]--></button>`);
35415
+ }
35416
+ //#endregion
35417
+ //#region src/lib/components/browser/buttons/BrowserClosed.svelte
34050
35418
  function BrowserClosed($$renderer, $$props) {
34051
35419
  $$renderer.component(($$renderer) => {
34052
35420
  let { closing = false} = $$props;
34053
- $$renderer.push(`<button data-svelte="BrowserClosed" class="rounded hover:bg-surface-active svelte-18cg1lj" data-testid="browse-close"${attr("aria-label", browserclosedelete2())}${attr("title", browserclosedelete2())}${attr("disabled", closing, true)}><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="red" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18"></path><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"></path><path d="M10 11v6"></path><path d="M14 11v6"></path></svg></button>`);
35421
+ $$renderer.push(`<button data-svelte="BrowserClosed" class="rounded hover:bg-surface-active svelte-1kvjut5" data-testid="browse-close"${attr("aria-label", browserclosedelete2())}${attr("title", browserclosedelete2())}${attr("disabled", closing, true)}><svg class="browser-icon-trash" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18"></path><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"></path><path d="M10 11v6"></path><path d="M14 11v6"></path></svg></button>`);
35422
+ });
35423
+ }
35424
+ //#endregion
35425
+ //#region src/lib/components/browser/buttons/BackButton.svelte
35426
+ function BackButton($$renderer, $$props) {
35427
+ /**
35428
+ * BackButton — the nav ← glyph (extracted from BrowserHeader 2026-11-02).
35429
+ * Contract (ADR long-press history): press-and-HOLD arms the history
35430
+ * menu via the caller's hold machine; a quick CLICK navigates one step.
35431
+ * Presentational (house pattern): the caller owns canBack/busy and the
35432
+ * hold/menu state — this button renders the glyph and reports hold
35433
+ * down/up plus the click.
35434
+ */
35435
+ let { label, testid, disabled = false, class: className = "" } = $$props;
35436
+ $$renderer.push(`<button data-svelte="BackButton" type="button"${attr_class(clsx(className))}${attr("data-testid", testid)}${attr("aria-label", label)}${attr("title", label)}${attr("disabled", disabled, true)}>←</button>`);
35437
+ }
35438
+ //#endregion
35439
+ //#region src/lib/components/browser/buttons/ForwardButton.svelte
35440
+ function ForwardButton($$renderer, $$props) {
35441
+ /**
35442
+ * ForwardButton — the nav → glyph (extracted from BrowserHeader
35443
+ * 2026-11-02), BackButton's twin: press-and-HOLD arms the history menu
35444
+ * via the caller's hold machine; a quick CLICK navigates one step.
35445
+ * Presentational (house pattern): the caller owns canForward/busy and
35446
+ * the hold/menu state — this button renders the glyph and reports hold
35447
+ * down/up plus the click.
35448
+ */
35449
+ let { label, testid, disabled = false, class: className = "" } = $$props;
35450
+ $$renderer.push(`<button data-svelte="ForwardButton" type="button"${attr_class(clsx(className))}${attr("data-testid", testid)}${attr("aria-label", label)}${attr("title", label)}${attr("disabled", disabled, true)}>→</button>`);
35451
+ }
35452
+ //#endregion
35453
+ //#region src/lib/components/browser/buttons/UrlCopy.svelte
35454
+ function UrlCopy($$renderer, $$props) {
35455
+ /**
35456
+ * UrlCopy — the prefix copy-URL chip (extracted from BrowserHeader
35457
+ * 2026-11-02; the focus-polish correction that put the icon on the
35458
+ * LEADING edge of the input, prefix-icon style). Copies the FOCUSED
35459
+ * tab's URL; the copied state flips the icon to a check. Presentational
35460
+ * (house pattern): the caller owns what copying means and when the
35461
+ * check reverts — this chip renders the state and reports the intent.
35462
+ */
35463
+ let { copied = false, disabled = false, label, copiedLabel, testid, class: className = "" } = $$props;
35464
+ $$renderer.push(`<button data-svelte="UrlCopy" type="button"${attr_class(clsx(className))}${attr("data-testid", testid)}${attr("aria-label", copied ? copiedLabel ?? label : label)}${attr("title", copied ? copiedLabel ?? label : label)}${attr("disabled", disabled, true)}>`);
35465
+ if (copied) {
35466
+ $$renderer.push("<!--[0-->");
35467
+ Check($$renderer, { size: 12 });
35468
+ } else {
35469
+ $$renderer.push("<!--[-1-->");
35470
+ Copy($$renderer, { size: 12 });
35471
+ }
35472
+ $$renderer.push(`<!--]--></button>`);
35473
+ }
35474
+ //#endregion
35475
+ //#region src/lib/components/browser/buttons/UrlInput.svelte
35476
+ function UrlInput($$renderer, $$props) {
35477
+ $$renderer.component(($$renderer) => {
35478
+ /**
35479
+ * UrlInput — the search-style URL box (extracted from BrowserHeader
35480
+ * 2026-11-02; glass-tab-ids Task 4 grammar): Escape restores the
35481
+ * placeholder (clears the draft), Enter submits; the panel's answer —
35482
+ * never Enter — is what settles the value. IME safety: Enter during
35483
+ * composition confirms the candidate string, never the omnibox command.
35484
+ * Presentational (house pattern): the caller owns what a submit means.
35485
+ */
35486
+ let { value = "", placeholder = "", disabled = false, onsubmit, testid, class: className = "" } = $$props;
35487
+ $$renderer.push(`<input data-svelte="UrlInput"${attr_class(clsx(className))} type="text"${attr("data-testid", testid)}${attr("placeholder", placeholder)}${attr("disabled", disabled, true)}${attr("value", value)}/>`);
35488
+ bind_props($$props, { value });
34054
35489
  });
34055
35490
  }
34056
35491
  //#endregion
34057
35492
  //#region src/lib/components/browser/BrowserHeader.svelte
34058
35493
  function BrowserHeader($$renderer, $$props) {
34059
35494
  $$renderer.component(($$renderer) => {
34060
- let { status, reBound = false, sessionId = null, closing = false, busy = false, canBack = false, canForward = false, onclose, onnavigate, onreload, onhistory } = $$props;
35495
+ let { status, reBound = false, sessionId = null, closing = false, busy = false, canBack = false, canForward = false, onclose, onnavigate, onreload, onhistory, focusTargetId = null, onhistoryto, placeholder = void 0, copyUrl = null } = $$props;
35496
+ /** Copy feedback: the icon swaps to a check for ~1.5s — no toast. */
35497
+ let copied = false;
34061
35498
  /** Ephemeral intent, never state (D2): the panel clears it on the
34062
35499
  * route ANSWER via clearInput() — success or refusal both answer. */
34063
35500
  let urlText = "";
@@ -34065,16 +35502,85 @@ function BrowserHeader($$renderer, $$props) {
34065
35502
  function clearInput() {
34066
35503
  urlText = "";
34067
35504
  }
34068
- $$renderer.push(`<div data-svelte="BrowserHeader" class="flex items-center gap-2 border-b border-surface-border px-2 py-1 text-xs"><span class="flex min-w-0 flex-1 items-center gap-2"><button class="rounded px-1 hover:bg-surface-active disabled:opacity-40" data-testid="browser-back"${attr("aria-label", browserback1())}${attr("disabled", busy || !canBack, true)}>←</button> <button class="rounded px-1 hover:bg-surface-active disabled:opacity-40" data-testid="browser-forward"${attr("aria-label", browserforward1())}${attr("disabled", busy || !canForward, true)}>→</button> <button class="rounded px-1 hover:bg-surface-active disabled:opacity-40" data-testid="browser-reload"${attr("aria-label", browserreload1())}${attr("disabled", status !== "live" || busy, true)}>⟳</button> <input class="min-w-0 flex-1 rounded border border-surface-border bg-surface px-2 py-0.5" type="text" data-testid="browser-url-input"${attr("placeholder", browserurlplaceholder2())}${attr("disabled", status !== "live" || busy, true)}${attr("value", urlText)}/></span> <span class="flex items-center gap-2" data-testid="browser-status"${attr("data-status", status)}${attr("data-rebound", reBound)}><span${attr_class(`inline-block h-2 w-2 rounded-full ${status === "live" ? "bg-emerald-500" : status === "failed" || status === "closed" ? "bg-red-500" : "bg-amber-400"}`)}></span> `);
34069
- if (sessionId) {
34070
- $$renderer.push("<!--[0-->");
34071
- $$renderer.push(`<span class="rounded-t-md border border-b-0 border-surface-border bg-surface-elevated px-2 py-0.5 font-mono text-[10px] opacity-80" data-testid="browser-session-tab">${escape_html(sessionId.slice(0, 8))}</span>`);
34072
- } else $$renderer.push("<!--[-1-->");
34073
- $$renderer.push(`<!--]--> `);
34074
- BrowserClosed($$renderer, {
34075
- closing});
34076
- $$renderer.push(`<!----></span></div>`);
34077
- bind_props($$props, { clearInput });
35505
+ /** glass-tab-ids Task 4: query-active echoes the active tab's address
35506
+ * ("tab:N <url>") into the box — readable and re-editable. */
35507
+ function setOmniboxValue(v) {
35508
+ urlText = v;
35509
+ }
35510
+ function submit() {
35511
+ const t = urlText.trim();
35512
+ if (!t) return;
35513
+ onnavigate?.(t);
35514
+ }
35515
+ let $$settled = true;
35516
+ let $$inner_renderer;
35517
+ function $$render_inner($$renderer) {
35518
+ $$renderer.push(`<div data-svelte="BrowserHeader" class="flex items-center gap-1 border-b border-surface-border px-2 py-1 text-xs"><span class="flex min-w-0 flex-1 items-center gap-2"><span class="relative flex items-center gap-1">`);
35519
+ BackButton($$renderer, {
35520
+ class: "browser-glyph flex h-6 w-6 items-center justify-center rounded border border-surface-border bg-surface text-[18px] leading-none hover:bg-surface-active disabled:opacity-40",
35521
+ label: browserback1(),
35522
+ testid: "browser-back",
35523
+ disabled: busy || !canBack});
35524
+ $$renderer.push(`<!----> `);
35525
+ ForwardButton($$renderer, {
35526
+ class: "browser-glyph flex h-6 w-6 items-center justify-center rounded border border-surface-border bg-surface text-[18px] leading-none hover:bg-surface-active disabled:opacity-40",
35527
+ label: browserforward1(),
35528
+ testid: "browser-forward",
35529
+ disabled: busy || !canForward});
35530
+ $$renderer.push(`<!----> `);
35531
+ $$renderer.push("<!--[-1-->");
35532
+ $$renderer.push(`<!--]--></span> `);
35533
+ ReloadButton($$renderer, {
35534
+ onclick: () => onreload?.(),
35535
+ label: browserreload1(),
35536
+ testid: "browser-reload",
35537
+ disabled: status !== "live" || busy,
35538
+ size: 12,
35539
+ class: "browser-glyph flex h-6 w-6 items-center justify-center rounded border border-surface-border bg-surface text-[18px] leading-none hover:bg-surface-active disabled:opacity-40"
35540
+ });
35541
+ $$renderer.push(`<!----> `);
35542
+ UrlCopy($$renderer, {
35543
+ class: "flex h-6 w-6 shrink-0 items-center justify-center rounded border border-surface-border bg-surface text-surface-muted hover:bg-surface-active disabled:opacity-40",
35544
+ copied,
35545
+ copiedLabel: "Copied",
35546
+ label: "Copy focused tab URL",
35547
+ testid: "browser-copy-url",
35548
+ disabled: !copyUrl});
35549
+ $$renderer.push(`<!----> `);
35550
+ UrlInput($$renderer, {
35551
+ class: "min-w-0 flex-1 rounded border border-surface-border bg-surface px-2 py-0.5",
35552
+ placeholder: placeholder ?? browserurlplaceholder2(),
35553
+ disabled: status !== "live" || busy,
35554
+ testid: "browser-url-input",
35555
+ onsubmit: submit,
35556
+ get value() {
35557
+ return urlText;
35558
+ },
35559
+ set value($$value) {
35560
+ urlText = $$value;
35561
+ $$settled = false;
35562
+ }
35563
+ });
35564
+ $$renderer.push(`<!----></span> <span class="flex items-center gap-2" data-testid="browser-status"${attr("data-status", status)}${attr("data-rebound", reBound)}><span${attr_class(`inline-block h-2 w-2 rounded-full ${status === "live" ? "bg-emerald-500" : status === "failed" || status === "closed" ? "bg-red-500" : "bg-amber-400"}`)}></span> `);
35565
+ if (sessionId) {
35566
+ $$renderer.push("<!--[0-->");
35567
+ $$renderer.push(`<span class="rounded-t-md border border-b-0 border-surface-border bg-surface-elevated px-2 py-0.5 font-mono text-[10px] opacity-80" data-testid="browser-session-tab">${escape_html(sessionId.slice(0, 8))}</span>`);
35568
+ } else $$renderer.push("<!--[-1-->");
35569
+ $$renderer.push(`<!--]--> `);
35570
+ BrowserClosed($$renderer, {
35571
+ closing});
35572
+ $$renderer.push(`<!----></span></div>`);
35573
+ }
35574
+ do {
35575
+ $$settled = true;
35576
+ $$inner_renderer = $$renderer.copy();
35577
+ $$render_inner($$inner_renderer);
35578
+ } while (!$$settled);
35579
+ $$renderer.subsume($$inner_renderer);
35580
+ bind_props($$props, {
35581
+ clearInput,
35582
+ setOmniboxValue
35583
+ });
34078
35584
  });
34079
35585
  }
34080
35586
  //#endregion
@@ -34103,8 +35609,11 @@ function BrowserContent($$renderer, $$props) {
34103
35609
  $$renderer.push(`<!--]--> <button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">${escape_html(browserreload1())}</button> <div class="my-1 border-t border-zinc-300"></div> <button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">${escape_html(browserctxsendrightclick4())}</button></div>`);
34104
35610
  } else $$renderer.push("<!--[-1-->");
34105
35611
  $$renderer.push(`<!--]--> `);
34106
- if (status !== "live") {
35612
+ if (status === "closed") {
34107
35613
  $$renderer.push("<!--[0-->");
35614
+ $$renderer.push(`<div class="absolute inset-0 grid place-items-center text-xs opacity-80" data-testid="browser-closed">${escape_html(browsersessiondead2())}</div>`);
35615
+ } else if (status !== "live") {
35616
+ $$renderer.push("<!--[1-->");
34108
35617
  $$renderer.push(`<div class="absolute inset-0 grid place-items-center text-xs opacity-60" data-testid="browser-placeholder">${escape_html(status === "opening" ? browserlaunching1() : browserwaitingframes2())}</div>`);
34109
35618
  } else $$renderer.push("<!--[-1-->");
34110
35619
  $$renderer.push(`<!--]--></div>`);
@@ -34120,14 +35629,92 @@ function BrowserContent($$renderer, $$props) {
34120
35629
  //#region src/lib/components/browser/BrowserTab.svelte
34121
35630
  function BrowserTab($$renderer, $$props) {
34122
35631
  $$renderer.component(($$renderer) => {
34123
- let { tab, disabled = false} = $$props;
34124
- $$renderer.push(`<div data-svelte="BrowserTab" class="relative shrink-0"><button type="button"${attr_class("w-32 truncate rounded px-1.5 py-0.5 pr-4 text-left whitespace-nowrap", void 0, {
34125
- "bg-blue-200": tab.active,
34126
- "text-blue-900": tab.active,
34127
- "text-zinc-600": !tab.active,
34128
- "hover:bg-zinc-100": !tab.active,
34129
- "font-medium": tab.active
34130
- })}${attr("disabled", disabled || tab.active, true)} data-testid="browser-tab"${attr("data-active", tab.active)}${attr("title", tab.url)}>${escape_html(tab.title || tab.url || "tab")}</button> <button type="button" class="absolute right-0.5 top-1/2 -translate-y-1/2 rounded text-[10px] leading-none text-red-500 hover:bg-red-500 hover:text-white"${attr("title", browsertabclosetitle3())} data-testid="browser-tab-close">✕</button></div>`);
35632
+ let { tab, position = void 0, disabled = false, onclose } = $$props;
35633
+ /** Focus polish 2026-10-28: the badge reads the strip position — the same
35634
+ * number Alt+N dispatches on — while PROMPT GRAMMAR stays tab:{id}
35635
+ * (the registry is untouched; this is display-only). */
35636
+ /** Real-favicon upgrade (fix round 2): the same cheap s2 path the menu
35637
+ * uses; non-http(s) tabs keep the colored dot (the img never renders). */
35638
+ function faviconUrl(u) {
35639
+ try {
35640
+ const p = new URL(u);
35641
+ return p.protocol === "http:" || p.protocol === "https:" ? "https://www.google.com/s2/favicons?domain=" + p.hostname + "&sz=32" : "";
35642
+ } catch {
35643
+ return "";
35644
+ }
35645
+ }
35646
+ const ordinalLabel = derived(() => position !== void 0 ? "t" + position + ":" + tab.tabId : "tab:" + tab.tabId);
35647
+ $$renderer.push(`<div data-svelte="BrowserTab" class="group/tab relative flex shrink-0 items-stretch"><button type="button"${attr_class(`flex h-6 w-36 items-center gap-1 truncate rounded-t-md border border-b-0 px-1.5 text-left whitespace-nowrap ${tab.active ? "border-transparent bg-blue-100 text-blue-900 font-medium shadow-sm" : "border-transparent text-zinc-600 hover:bg-zinc-100 hover:border-surface-border"}`)}${attr("disabled", disabled || tab.active, true)} data-testid="browser-tab"${attr("data-active", tab.active)}${attr("title", tab.url)}><span class="relative flex h-3.5 w-3.5 shrink-0 items-center justify-center" data-testid="browser-tab-favicon"><span${attr_class(`absolute h-1.5 w-1.5 rounded-full ${tab.active ? "bg-emerald-500" : "bg-zinc-400"}`)}></span> `);
35648
+ if (faviconUrl(tab.url)) {
35649
+ $$renderer.push("<!--[0-->");
35650
+ $$renderer.push(`<img${attr("src", faviconUrl(tab.url))} alt="" class="relative h-3.5 w-3.5 rounded-sm" onerror="this.__e=event"/>`);
35651
+ } else $$renderer.push("<!--[-1-->");
35652
+ $$renderer.push(`<!--]--></span> `);
35653
+ if (tab.tabId !== void 0) {
35654
+ $$renderer.push("<!--[0-->");
35655
+ $$renderer.push(`<span class="shrink-0 rounded-sm bg-black/5 px-0.5 font-mono text-[9px] leading-tight opacity-80" data-testid="browser-tab-ordinal">${escape_html(ordinalLabel())}</span>`);
35656
+ } else $$renderer.push("<!--[-1-->");
35657
+ $$renderer.push(`<!--]--> <span class="min-w-0 flex-1 truncate">${escape_html(tab.title || tab.url || "tab")}</span></button> `);
35658
+ CloseButton($$renderer, {
35659
+ class: "browser-glyph browser-glyph-destructive absolute right-0 top-1/2 flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded font-semibold opacity-0 leading-none transition-opacity group-hover/tab:opacity-100 hover:bg-red-500 focus-visible:opacity-100",
35660
+ label: browsertabclosetitle3(),
35661
+ testid: "browser-tab-close",
35662
+ onclick: () => onclose?.(tab.targetId)
35663
+ });
35664
+ $$renderer.push(`<!----></div>`);
35665
+ });
35666
+ }
35667
+ //#endregion
35668
+ //#region src/lib/components/browser/buttons/BrowserNew.svelte
35669
+ function BrowserNew($$renderer, $$props) {
35670
+ /**
35671
+ * BrowserNew — the tab-strip + chip as a reusable button (extracted from
35672
+ * BrowserPanel 2026-11-02, CloseButton day): ADR-0042 D3's tab CREATE —
35673
+ * an absent-URL opentab; the CALLER owns what creating means and the
35674
+ * chrome (pass Tailwind classes via `class`).
35675
+ *
35676
+ * Icon: lucide Plus at rest, CirclePlus on hover — the hover swap is the
35677
+ * component's own contract (named group `new` on the button itself, so
35678
+ * the swap works wherever the chip mounts, no parent group needed).
35679
+ * CirclePlus is the canonical name — PlusCircle is the deprecated alias.
35680
+ */
35681
+ let { label, testid, disabled = false, size = 12, class: className = "" } = $$props;
35682
+ $$renderer.push(`<button data-svelte="BrowserNew" type="button"${attr_class(`group/new ${stringify(className)}`)}${attr("data-testid", testid)}${attr("title", label)}${attr("aria-label", label)}${attr("disabled", disabled, true)}>`);
35683
+ Plus($$renderer, {
35684
+ size,
35685
+ class: "group-hover/new:hidden"
35686
+ });
35687
+ $$renderer.push(`<!----> `);
35688
+ Circle_plus($$renderer, {
35689
+ size,
35690
+ class: "hidden group-hover/new:block"
35691
+ });
35692
+ $$renderer.push(`<!----></button>`);
35693
+ }
35694
+ //#endregion
35695
+ //#region src/lib/components/browser/BrowserProvenance.svelte
35696
+ function BrowserProvenance($$renderer, $$props) {
35697
+ $$renderer.component(($$renderer) => {
35698
+ /**
35699
+ * BrowserProvenance — the lineage chip row (ADR-0036 D3): who asked for
35700
+ * this glass. The title rides the spine merge the route resolved; a
35701
+ * pruned opener degrades to the raw session id. Depth tint like the
35702
+ * transcript. Owns the live zoom slider when the knob is enabled.
35703
+ */
35704
+ let { openedBy, parentTitle, focusedTitle, depth} = $$props;
35705
+ $$renderer.push(`<div data-svelte="BrowserProvenance"${attr_class("browser-provenance flex items-center gap-1 border-b border-surface-border px-2 py-0.5 text-[10px] text-surface-muted svelte-ifad3s", void 0, { "depth-tinted": depth > 0 })} data-testid="browser-provenance"${attr("title", openedBy)}><span class="opacity-70">⌥</span> <span class="flex min-w-0 items-center gap-1 truncate text-[12px] font-bold"><span class="text-[color:var(--color-accent-purple)]">${escape_html(parentTitle ?? openedBy)}</span>`);
35706
+ if (focusedTitle) {
35707
+ $$renderer.push("<!--[0-->");
35708
+ $$renderer.push(`<span class="text-text-muted">|</span><span class="text-[color:var(--color-accent-blue)]">${escape_html(focusedTitle)}</span>`);
35709
+ } else $$renderer.push("<!--[-1-->");
35710
+ $$renderer.push(`<!--]--></span> `);
35711
+ if (depth > 0) {
35712
+ $$renderer.push("<!--[0-->");
35713
+ $$renderer.push(`<span class="opacity-60">·d${escape_html(depth)}</span>`);
35714
+ } else $$renderer.push("<!--[-1-->");
35715
+ $$renderer.push(`<!--]--> `);
35716
+ $$renderer.push("<!--[-1-->");
35717
+ $$renderer.push(`<!--]--></div>`);
34131
35718
  });
34132
35719
  }
34133
35720
  //#endregion
@@ -34174,98 +35761,97 @@ function createMoveCoalescer(raf, fire) {
34174
35761
  } };
34175
35762
  }
34176
35763
  //#endregion
34177
- //#region src/lib/utils/sidebar-prefs.ts
34178
- /**
34179
- * Sidebar preferences — persisted layout state for the conversation page's
34180
- * app sidebar (OCI ControlRail pattern, 2026-08-23).
34181
- *
34182
- * Pure localStorage round-trip: SSR-safe (no localStorage → defaults), junk
34183
- * payloads and out-of-range widths fall back instead of throwing into the
34184
- * page, and writes are best-effort (a full or blocked store must not break
34185
- * the layout — it only loses persistence for that session).
34186
- *
34187
- * Workspace profiles (storage-profile.ts): `?profile=widi` moves the key
34188
- * to `dsi-sidebar_widi` — each desk remembers its own rail layout.
34189
- */
34190
- /** localStorage base key — one JSON blob `{ collapsed, width }`. */
34191
- var STORAGE_KEY = "dsi-sidebar";
34192
- /** The single width bound site — load-side sanitizing and drag clamping
34193
- * both route through here so the bounds exist in exactly one place.
34194
- * Bounds read the config store (layout load has landed them before any
34195
- * mount; constants are the fallback defaults). */
34196
- function clampSidebarWidth(width) {
34197
- const { minWidth, maxWidth } = appConfig().sidebar;
34198
- return Math.max(minWidth, Math.min(maxWidth, width));
34199
- }
34200
- /** Config-driven default width (clamped through the single bound site). */
34201
- function defaultSidebarWidth() {
34202
- return clampSidebarWidth(appConfig().sidebar.defaultWidth);
34203
- }
34204
- /** Persisted defaults when nothing (usable) is stored. */
34205
- function defaultSidebarPrefs() {
34206
- return {
34207
- collapsed: false,
34208
- width: defaultSidebarWidth()
35764
+ //#region src/lib/browser/tab-grammar.ts
35765
+ /** URL-shaped: has a scheme (foo://…) or a dotted host (example.com). */
35766
+ function isUrlShaped(s) {
35767
+ return /^[a-z][a-z0-9+.-]*:\/\//i.test(s) || /^[^\s/]+\.[^\s/]{2,}$/.test(s);
35768
+ }
35769
+ /** "tab:N" with N a positive integer, else null. */
35770
+ function matchTabRef(s) {
35771
+ const m = /^tab:(\d+)$/i.exec(s);
35772
+ if (!m) return null;
35773
+ const n = Number(m[1]);
35774
+ return n >= 1 ? n : null;
35775
+ }
35776
+ function parseTabCommand(input) {
35777
+ const text = input.trim();
35778
+ const lower = text.toLowerCase();
35779
+ if (lower === "active") return { kind: "query-active" };
35780
+ if (lower === "close active") return {
35781
+ kind: "close",
35782
+ tabId: "active"
34209
35783
  };
34210
- }
34211
- /**
34212
- * Read prefs from localStorage.
34213
- * @param profile sanitized workspace profile (null/omitted = default desk).
34214
- * @returns stored prefs when parseable, defaults when absent, junk, or SSR.
34215
- */
34216
- function loadSidebarPrefs(profile) {
34217
- if (typeof localStorage === "undefined") return defaultSidebarPrefs();
34218
- try {
34219
- const raw = localStorage.getItem(dsiKey(STORAGE_KEY, profile));
34220
- if (!raw) return defaultSidebarPrefs();
34221
- const parsed = JSON.parse(raw);
34222
- if (parsed === null || typeof parsed !== "object") return defaultSidebarPrefs();
35784
+ if (/^close\s+tab:\S+$/i.test(lower)) {
35785
+ const ref = text.slice(text.indexOf(":") + 1);
35786
+ const n = Number(ref);
35787
+ if (Number.isInteger(n) && n >= 1) return {
35788
+ kind: "close",
35789
+ tabId: n
35790
+ };
34223
35791
  return {
34224
- collapsed: parsed.collapsed === true,
34225
- width: clampSidebarWidth(typeof parsed.width === "number" && Number.isFinite(parsed.width) ? parsed.width : defaultSidebarWidth())
35792
+ kind: "error",
35793
+ error: `invalid tab reference: tab:${ref}`
34226
35794
  };
34227
- } catch {
34228
- return defaultSidebarPrefs();
34229
35795
  }
34230
- }
34231
- //#endregion
34232
- //#region src/lib/services/workspace/page-prefs.svelte.ts
34233
- var PagePrefs = class {
34234
- /** Width preset for the next conversation panel (clamped). */
34235
- panelWidth = 0;
34236
- /** Floor zoom (clamped). */
34237
- zoom = 1;
34238
- /** Explorer Layout split (clamped). */
34239
- treePct = 0;
34240
- /** Sidebar rail state (OCI ControlRail port). */
34241
- sidebarCollapsed = false;
34242
- sidebarWidth = 0;
34243
- #profile = null;
34244
- #initialised = false;
34245
- /** Seed every field from the persisted blobs — exactly once, BEFORE
34246
- * the route reads any field (makePanel reads panelWidth during the
34247
- * seed reset). Intentional initial capture per the route's old
34248
- * "svelte-ignore state_referenced_locally" comments: prefs seed the
34249
- * layout once; later writes go through the save effects. */
34250
- init(profile) {
34251
- this.#initialised = true;
34252
- this.#profile = profile;
34253
- const floor = loadPanelPrefs(profile);
34254
- this.panelWidth = clampPanelWidth(floor.panelWidth);
34255
- this.zoom = clampPanelZoom(floor.zoom);
34256
- this.treePct = clampTreePct(floor.treePct);
34257
- const sidebar = loadSidebarPrefs(profile);
34258
- this.sidebarCollapsed = sidebar.collapsed;
34259
- this.sidebarWidth = sidebar.width;
35796
+ const reuse = /^reuse\s+(\S+)(?:\s+(\S+))?$/i.exec(text);
35797
+ if (reuse) {
35798
+ const n = matchTabRef(reuse[1]);
35799
+ if (n !== null) {
35800
+ const url = reuse[2];
35801
+ return url ? {
35802
+ kind: "focus",
35803
+ tabId: n,
35804
+ url
35805
+ } : {
35806
+ kind: "focus",
35807
+ tabId: n
35808
+ };
35809
+ }
35810
+ return {
35811
+ kind: "error",
35812
+ error: `invalid tab reference: ${reuse[1]}`
35813
+ };
34260
35814
  }
34261
- get profile() {
34262
- return this.#profile;
35815
+ const change = /^change(?:\s+to)?\s+(\S+)$/i.exec(text);
35816
+ if (change) {
35817
+ const n = matchTabRef(change[1]);
35818
+ if (n !== null) return {
35819
+ kind: "focus",
35820
+ tabId: n
35821
+ };
35822
+ return {
35823
+ kind: "error",
35824
+ error: `invalid tab reference: ${change[1]}`
35825
+ };
34263
35826
  }
34264
- /** Sidebar persistence (the route's old sidebar save effect). Call
34265
- * during component initialisation — `$effect` needs an owner. */
34266
- installSidebarAutoSave() {}
34267
- };
34268
- var pagePrefs = new PagePrefs();
35827
+ if (/^tab:/i.test(text)) {
35828
+ const n = matchTabRef(text);
35829
+ if (n !== null) return {
35830
+ kind: "focus",
35831
+ tabId: n
35832
+ };
35833
+ return {
35834
+ kind: "error",
35835
+ error: `invalid tab reference: ${text}`
35836
+ };
35837
+ }
35838
+ if (lower === "glass") return { kind: "open" };
35839
+ if (/^glass\s+/i.test(text)) {
35840
+ const rest = text.replace(/^glass\s+/i, "");
35841
+ if (isUrlShaped(rest)) return {
35842
+ kind: "open",
35843
+ url: rest
35844
+ };
35845
+ return {
35846
+ kind: "open",
35847
+ text: rest
35848
+ };
35849
+ }
35850
+ return {
35851
+ kind: "url-or-search",
35852
+ text: input
35853
+ };
35854
+ }
34269
35855
  //#endregion
34270
35856
  //#region src/lib/components/browser/BrowserPanel.svelte
34271
35857
  function BrowserPanel($$renderer, $$props) {
@@ -34286,10 +35872,39 @@ function BrowserPanel($$renderer, $$props) {
34286
35872
  let proxyBusy = false;
34287
35873
  let canBack = false;
34288
35874
  let canForward = false;
35875
+ const SEARCH_URL = "https://www.google.com/search?q=";
35876
+ /** glass-tab-ids Task 4: the focused tab's URL IS the omnibox hint, but
35877
+ * a 2000-char SPA URL would eat the strip — truncate the hint at 64. */
35878
+ const OMNIBOX_PLACEHOLDER_MAX = 64;
35879
+ /** The omnibox placeholder: the ACTIVE tab's URL (64-char truncated) when
35880
+ * one is active; the localized "Search or type a URL" when none is.
35881
+ * Empty OR about:blank (any case, optional fragment suffix like
35882
+ * 'about:blank#blocked') is NO URL — a fresh tab must show the
35883
+ * original placeholder, not the blank URL. */
35884
+ function isNoUrl(u) {
35885
+ const s = u.toLowerCase();
35886
+ return !s || s === "about:blank" || s.startsWith("about:blank#") || s.startsWith("data:");
35887
+ }
35888
+ const omniboxPlaceholder = derived(() => {
35889
+ const url = tabs.find((tb) => tb.active)?.url ?? "";
35890
+ if (isNoUrl(url)) return t(browserurlplaceholder2);
35891
+ return url.length > OMNIBOX_PLACEHOLDER_MAX ? url.slice(0, OMNIBOX_PLACEHOLDER_MAX) : url;
35892
+ });
34289
35893
  /** ADR-0040 D5: the tab strip — the registry's tab list mirrored here;
34290
35894
  * the SERVER stays the authority (activeTargetId), this is a view. */
34291
35895
  let tabs = [];
34292
35896
  let switching = false;
35897
+ /** Focus polish 2026-10-28: the FOCUSED tab's facts for the header's
35898
+ * prefix copy-URL icon (null = no real URL — the isNoUrl guard, so an
35899
+ * empty/about:blank tab disables the copy) and the info line's
35900
+ * '{sessionTitle} | {tab title}' suffix (FULL text; CSS truncates). */
35901
+ const focusedTab = derived(() => tabs.find((tb) => tb.active) ?? null);
35902
+ const focusedTitle = derived(() => focusedTab()?.title ?? "");
35903
+ const focusedUrl = derived(() => focusedTab() && !isNoUrl(focusedTab().url) ? focusedTab().url : null);
35904
+ /** ADR-0040 D4: activate paints the BOUNDARY frame from the response —
35905
+ * the panel never waits on a blank paint — then re-attaches the SSE at
35906
+ * the carried seq so the stream resumes on the new relay's ring. */
35907
+ async function activateTab(targetId) {}
34293
35908
  const moves = createMoveCoalescer((cb) => requestAnimationFrame(cb), (x, y) => void post());
34294
35909
  async function post(input) {}
34295
35910
  function toViewportCx(e) {
@@ -34362,6 +35977,9 @@ function BrowserPanel($$renderer, $$props) {
34362
35977
  * the blank signal, never a literal about:blank. Callers own their own
34363
35978
  * ctxClose(). */
34364
35979
  async function openTab(url) {}
35980
+ async function ctxCloseTab(targetId) {
35981
+ ctxClose();
35982
+ }
34365
35983
  function ctxAct(action) {
34366
35984
  const m = ctxMenu;
34367
35985
  ctxClose();
@@ -34399,16 +36017,65 @@ function BrowserPanel($$renderer, $$props) {
34399
36017
  text: e.type === "keydown" && e.key.length === 1 ? e.key : void 0
34400
36018
  });
34401
36019
  }
36020
+ /** A URL/search phrase is a URL when the route would take it verbatim;
36021
+ * anything else rides the search engine (ADR-0031 D2). glass-tab-ids
36022
+ * Task 4 adds the dotted-host arm: "example.com" navigates, it does not
36023
+ * search (the same shape the tab-grammar parser accepts after "glass"). */
36024
+ function toTarget(text) {
36025
+ return /^[a-z][a-z0-9+.-]*:\/\/|^data:text\/html/.test(text) || /^([^\s/]+\.[^\s/]{2,})$/.test(text) ? text : SEARCH_URL + encodeURIComponent(text);
36026
+ }
36027
+ /** glass-tab-ids Task 4: the omnibox speaks tab grammar. A parsed command
36028
+ * acts (open/focus/close/query-active); anything the parser passes over
36029
+ * falls through to the classic URL-or-search split in the ACTIVE tab.
36030
+ * tabId→targetId resolution is PANEL-LOCAL — read off the tabs payload
36031
+ * the strip poll already holds; no server round-trip resolves it. */
36032
+ async function handleOmniboxSubmit(text) {
36033
+ const cmd = parseTabCommand(text);
36034
+ if (cmd.kind === "open") {
36035
+ await openTab(cmd.url ?? SEARCH_URL + encodeURIComponent(cmd.text ?? ""));
36036
+ return;
36037
+ }
36038
+ if (cmd.kind === "focus") {
36039
+ const target = tabs.find((tb) => tb.tabId === cmd.tabId)?.targetId;
36040
+ if (!target) {
36041
+ console.warn("[browser-panel] omnibox: no tab tab:" + cmd.tabId);
36042
+ return;
36043
+ }
36044
+ await activateTab();
36045
+ if (cmd.url) await proxy({ url: toTarget(cmd.url) });
36046
+ return;
36047
+ }
36048
+ if (cmd.kind === "close") {
36049
+ const target = cmd.tabId === "active" ? tabs.find((tb) => tb.active)?.targetId : tabs.find((tb) => tb.tabId === cmd.tabId)?.targetId;
36050
+ if (!target) {
36051
+ console.warn("[browser-panel] omnibox: close resolved to no tab", cmd.tabId);
36052
+ return;
36053
+ }
36054
+ await ctxCloseTab();
36055
+ return;
36056
+ }
36057
+ if (cmd.kind === "query-active") {
36058
+ if (tabs.find((tb) => tb.active));
36059
+ return;
36060
+ }
36061
+ if (cmd.kind === "error") {
36062
+ console.warn("[browser-panel] omnibox:", cmd.error);
36063
+ return;
36064
+ }
36065
+ proxy();
36066
+ }
34402
36067
  /** One POST for every proxy verb; the ANSWER (success or refusal)
34403
36068
  * clears the input and refreshes the history bounds. A dead session
34404
36069
  * surfaces as the closed status, never a crash (404/409). */
34405
36070
  async function proxy(body) {}
34406
- function submitUrl(text) {
34407
- proxy();
34408
- }
34409
36071
  function goHistory(dir) {
34410
36072
  proxy();
34411
36073
  }
36074
+ /** Long-press history dropdown (operator-approved 2026-10-28): the
36075
+ * header reports the picked list index; the panel performs the TRUE
36076
+ * travel POST (Page.navigateToHistoryEntry — no new history entry)
36077
+ * and the answer refreshes the bounds exactly like a proxy verb. */
36078
+ async function goHistoryTo(index) {}
34412
36079
  /** The FOLD (ADR-0037 D1): the header close button only reports
34413
36080
  * upward - the route's onclose is removePanel, the panel leaves the
34414
36081
  * floor, and the SERVER SESSION STAYS ALIVE (the reaper is the
@@ -34419,11 +36086,12 @@ function BrowserPanel($$renderer, $$props) {
34419
36086
  function fold() {
34420
36087
  onclose?.();
34421
36088
  }
34422
- onDestroy(() => {});
36089
+ onDestroy(() => {
36090
+ });
34423
36091
  let $$settled = true;
34424
36092
  let $$inner_renderer;
34425
36093
  function $$render_inner($$renderer) {
34426
- $$renderer.push(`<div data-svelte="BrowserPanel" class="relative flex h-full flex-col bg-surface-elevated" data-testid="panel-browser">`);
36094
+ $$renderer.push(`<div data-svelte="BrowserPanel" class="glass-browser-icons relative flex h-full flex-col bg-surface-elevated svelte-283365" data-testid="panel-browser">`);
34427
36095
  BrowserHeader($$renderer, {
34428
36096
  status,
34429
36097
  reBound,
@@ -34433,32 +36101,45 @@ function BrowserPanel($$renderer, $$props) {
34433
36101
  canBack,
34434
36102
  canForward,
34435
36103
  onclose: () => fold(),
34436
- onnavigate: submitUrl,
36104
+ onnavigate: handleOmniboxSubmit,
36105
+ placeholder: omniboxPlaceholder(),
34437
36106
  onreload: () => void proxy(),
34438
- onhistory: goHistory
36107
+ onhistory: goHistory,
36108
+ focusTargetId: focusedTab()?.targetId ?? null,
36109
+ onhistoryto: (i) => void goHistoryTo(),
36110
+ copyUrl: focusedUrl()
34439
36111
  });
34440
36112
  $$renderer.push(`<!----> `);
34441
36113
  if (openedBy) {
34442
36114
  $$renderer.push("<!--[0-->");
34443
- $$renderer.push(`<div${attr_class("browser-provenance flex items-center gap-1 border-b border-surface-border px-2 py-0.5 text-[10px] text-surface-muted svelte-283365", void 0, { "depth-tinted": depth > 0 })} data-testid="browser-provenance"${attr("title", openedBy)}><span class="opacity-70">⌥</span> <span class="truncate">${escape_html(parentTitle ?? openedBy)}</span> `);
34444
- if (depth > 0) {
34445
- $$renderer.push("<!--[0-->");
34446
- $$renderer.push(`<span class="opacity-60">·d${escape_html(depth)}</span>`);
34447
- } else $$renderer.push("<!--[-1-->");
34448
- $$renderer.push(`<!--]--></div>`);
36115
+ BrowserProvenance($$renderer, {
36116
+ openedBy,
36117
+ parentTitle,
36118
+ focusedTitle: focusedTitle(),
36119
+ depth,
36120
+ zoomLabel: t(browserzoom1)});
34449
36121
  } else $$renderer.push("<!--[-1-->");
34450
36122
  $$renderer.push(`<!--]--> `);
34451
36123
  if (tabs.length >= 1) {
34452
36124
  $$renderer.push("<!--[0-->");
34453
36125
  $$renderer.push(`<div class="flex items-center gap-1 overflow-x-auto border-b border-surface-border px-1 py-0.5 text-[11px]" data-testid="browser-tab-strip"><!--[-->`);
34454
36126
  const each_array = ensure_array_like(tabs);
34455
- for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
34456
- let t = each_array[$$index];
36127
+ for (let i = 0, $$length = each_array.length; i < $$length; i++) {
36128
+ let t = each_array[i];
34457
36129
  BrowserTab($$renderer, {
34458
36130
  tab: t,
34459
- disabled: switching});
36131
+ position: i + 1,
36132
+ disabled: switching,
36133
+ onclose: (id) => void ctxCloseTab()
36134
+ });
34460
36135
  }
34461
- $$renderer.push(`<!--]--> <button type="button" class="shrink-0 rounded px-1.5 leading-none text-zinc-500 hover:bg-zinc-100 disabled:opacity-40"${attr("title", t(browsernewtab2))}${attr("aria-label", t(browsernewtab2))} data-testid="browser-tab-new"${attr("disabled", true, true)}>+</button></div>`);
36136
+ $$renderer.push(`<!--]--> `);
36137
+ BrowserNew($$renderer, {
36138
+ class: "flex h-5 w-5 shrink-0 items-center justify-center rounded border border-accent-blue/20 bg-accent-blue/10 text-text-secondary hover:bg-accent-blue/20 disabled:opacity-40",
36139
+ label: t(browsernewtab2),
36140
+ testid: "browser-tab-new",
36141
+ disabled: true});
36142
+ $$renderer.push(`<!----></div>`);
34462
36143
  } else $$renderer.push("<!--[-1-->");
34463
36144
  $$renderer.push(`<!--]--> `);
34464
36145
  BrowserContent($$renderer, {
@@ -34529,19 +36210,62 @@ function SettingsSkillsToolbar($$renderer, $$props) {
34529
36210
  });
34530
36211
  }
34531
36212
  //#endregion
36213
+ //#region src/lib/components/common/tabs/SegmentedTabs.svelte
36214
+ function SegmentedTabs($$renderer, $$props) {
36215
+ $$renderer.component(($$renderer) => {
36216
+ /**
36217
+ * SegmentedTabs — THE one joined-pill tab grammar (The Plugin Rack
36218
+ * ADR, amendment IV 2026-10-31): the scoped-CSS pill lived
36219
+ * copy-pasted in PluginManagerHeaderTabs, SettingsSkillsHeaderTabs
36220
+ * and WorkspaceFileTabGroup; this Tailwind component replaces all
36221
+ * three (zero gap, outer curves only, active = accent blue).
36222
+ * Presentational: no state lives here — the owner owns `active`
36223
+ * and speaks its own tab vocabulary through `tabs`/`onchange`.
36224
+ * The on/off states are MUTUALLY EXCLUSIVE class sets (v4 lesson:
36225
+ * bg-transparent + bg-accent-blue in one list fight by stylesheet
36226
+ * order, and transparent won — the white-on-white pill).
36227
+ */
36228
+ /** The owner's tab id — echoed back through onchange. */
36229
+ /** The visible (already localized) label. */
36230
+ /** Renders the segment disabled (e.g. a locked Diff). */
36231
+ /** The owner's test hook (data-testid). */
36232
+ let { tabs, active, ariaLabel, groupTestid, onchange } = $$props;
36233
+ $$renderer.push(`<div data-svelte="SegmentedTabs" class="inline-flex shrink-0" role="group"${attr("aria-label", ariaLabel)}${attr("data-testid", groupTestid)}><!--[-->`);
36234
+ const each_array = ensure_array_like(tabs);
36235
+ for (let i = 0, $$length = each_array.length; i < $$length; i++) {
36236
+ let seg = each_array[i];
36237
+ $$renderer.push(`<button type="button"${attr_class(`cursor-pointer border px-2 py-[0.1rem] text-[0.6875rem] leading-normal transition-colors ${i === 0 ? "rounded-l-sm" : "rounded-r-sm border-l-0"} ${active === seg.id ? "border-accent-blue bg-accent-blue text-white" : "border-border bg-transparent"} disabled:cursor-not-allowed disabled:opacity-50`)}${attr("aria-pressed", active === seg.id)}${attr("disabled", seg.disabled === true, true)}${attr("data-testid", seg.testid)}>${escape_html(seg.label)}</button>`);
36238
+ }
36239
+ $$renderer.push(`<!--]--></div>`);
36240
+ });
36241
+ }
36242
+ //#endregion
34532
36243
  //#region src/lib/components/settings-skills/SettingsSkillsHeaderTabs.svelte
34533
36244
  function SettingsSkillsHeaderTabs($$renderer, $$props) {
34534
36245
  $$renderer.component(($$renderer) => {
34535
36246
  /**
34536
- * SettingsSkillsHeaderTabs — the shelf's own tab pill (The Shelf
34537
- * Chrome, D3): the joined-pill segmented grammar (class:on,
34538
- * aria-pressed) speaking the shelf's native tab names directly —
34539
- * install / uninstall, plain labels, no counts. Install is the
34540
- * default tab. Presentational: the panel owns the tab state; this
34541
- * renders the two segments and reports picks.
36247
+ * SettingsSkillsHeaderTabs — the shelf's tab pill (The Shelf
36248
+ * Chrome, D3; Plugin Rack amendment IV 2026-10-31): the joined-pill
36249
+ * grammar now lives ONCE in the shared SegmentedTabs (Tailwind) —
36250
+ * this is a thin adapter speaking the shelf's native tab names.
36251
+ * Presentational: the panel owns the tab state.
34542
36252
  */
34543
- let { tab = "install"} = $$props;
34544
- $$renderer.push(`<div data-svelte="SettingsSkillsHeaderTabs" class="seg-group svelte-34npwv" role="group"${attr("aria-label", t(skillsshelftitle2))} data-testid="shelf-tab-group"><button type="button"${attr_class("seg left svelte-34npwv", void 0, { "on": tab === "install" })}${attr("aria-pressed", tab === "install")} data-testid="shelf-tab-install">${escape_html(t(skillsshelftabinstall3))}</button> <button type="button"${attr_class("seg right svelte-34npwv", void 0, { "on": tab === "uninstall" })}${attr("aria-pressed", tab === "uninstall")} data-testid="shelf-tab-uninstall">${escape_html(t(skillsshelftabuninstall3))}</button></div>`);
36253
+ let { tab = "install", ontabchange } = $$props;
36254
+ SegmentedTabs($$renderer, {
36255
+ active: tab,
36256
+ groupTestid: "shelf-tab-group",
36257
+ ariaLabel: t(skillsshelftitle2),
36258
+ onchange: (id) => ontabchange?.(id === "uninstall" ? "uninstall" : "install"),
36259
+ tabs: [{
36260
+ id: "install",
36261
+ label: t(skillsshelftabinstall3),
36262
+ testid: "shelf-tab-install"
36263
+ }, {
36264
+ id: "uninstall",
36265
+ label: t(skillsshelftabuninstall3),
36266
+ testid: "shelf-tab-uninstall"
36267
+ }]
36268
+ });
34545
36269
  });
34546
36270
  }
34547
36271
  //#endregion
@@ -34626,10 +36350,12 @@ function SettingsSkillsHeader($$renderer, $$props) {
34626
36350
  * lineage-fold pill (cross-tab by contract, ADR D2). Presentational:
34627
36351
  * every verb and all state are owned by SettingsSkillsPanel.
34628
36352
  */
34629
- let { tab, reloadState, busy} = $$props;
36353
+ let { tab, ontabchange, reloadState, busy} = $$props;
34630
36354
  $$renderer.push(`<div data-svelte="SettingsSkillsHeader" class="shelf-header svelte-17gmpcz" data-testid="shelf-header">`);
34631
36355
  SettingsSkillsHeaderTabs($$renderer, {
34632
- tab});
36356
+ tab,
36357
+ ontabchange
36358
+ });
34633
36359
  $$renderer.push(`<!----> `);
34634
36360
  SettingsSkillsHeaderActions($$renderer, {
34635
36361
  tab,
@@ -34678,6 +36404,7 @@ function SettingsSkillsPanel($$renderer, $$props) {
34678
36404
  $$renderer.push(`<!----> `);
34679
36405
  SettingsSkillsHeader($$renderer, {
34680
36406
  tab,
36407
+ ontabchange: (v) => tab = v,
34681
36408
  reloadState: reloadState(),
34682
36409
  busy});
34683
36410
  $$renderer.push(`<!----> `);
@@ -34701,13 +36428,28 @@ function PluginManagerHeaderTabs($$renderer, $$props) {
34701
36428
  $$renderer.component(($$renderer) => {
34702
36429
  /**
34703
36430
  * PluginManagerHeaderTabs - the rack's install/uninstall tab pill
34704
- * (The Plugin Rack ADR, 2026-09-27, D1), the shelf HeaderTabs'
34705
- * joined-pill segmented grammar (SettingsSkillsHeaderTabs, D3):
34706
- * presentational - tab state lives in PluginManagerPanel, this only
34707
- * renders the two segments and reports picks.
36431
+ * (The Plugin Rack ADR, 2026-09-27, D1; amendment IV 2026-10-31):
36432
+ * the joined-pill grammar now lives ONCE in the shared
36433
+ * SegmentedTabs (Tailwind) — this is a thin adapter speaking the
36434
+ * rack's native tab vocabulary and keeping the rack testids.
36435
+ * Presentational - tab state lives in PluginManagerPanel.
34708
36436
  */
34709
- let { tab} = $$props;
34710
- $$renderer.push(`<div data-svelte="PluginManagerHeaderTabs" class="seg-group svelte-srf628" role="group"${attr("aria-label", t(pluginracktitle2))} data-testid="rack-tabs"><button type="button"${attr_class("seg left svelte-srf628", void 0, { "on": tab === "install" })}${attr("aria-pressed", tab === "install")} data-testid="rack-tab-install">${escape_html(t(pluginrackinstall2))}</button> <button type="button"${attr_class("seg right svelte-srf628", void 0, { "on": tab === "uninstall" })}${attr("aria-pressed", tab === "uninstall")} data-testid="rack-tab-uninstall">${escape_html(t(pluginrackuninstall2))}</button></div>`);
36437
+ let { tab, ontabchange } = $$props;
36438
+ SegmentedTabs($$renderer, {
36439
+ active: tab,
36440
+ groupTestid: "rack-tabs",
36441
+ ariaLabel: t(pluginracktitle2),
36442
+ onchange: (id) => ontabchange(id === "uninstall" ? "uninstall" : "install"),
36443
+ tabs: [{
36444
+ id: "install",
36445
+ label: t(pluginrackinstall2),
36446
+ testid: "rack-tab-install"
36447
+ }, {
36448
+ id: "uninstall",
36449
+ label: t(pluginrackuninstall2),
36450
+ testid: "rack-tab-uninstall"
36451
+ }]
36452
+ });
34711
36453
  });
34712
36454
  }
34713
36455
  //#endregion
@@ -34764,10 +36506,12 @@ function PluginManagerHeader($$renderer, $$props) {
34764
36506
  * Presentational: every verb and all state are owned by
34765
36507
  * PluginManagerPanel.
34766
36508
  */
34767
- let { tab, loading, floorBounce} = $$props;
36509
+ let { tab, ontabchange, loading, floorBounce} = $$props;
34768
36510
  $$renderer.push(`<div data-svelte="PluginManagerHeader" class="rack-head svelte-1lc924" data-testid="rack-header">`);
34769
36511
  PluginManagerHeaderTabs($$renderer, {
34770
- tab});
36512
+ tab,
36513
+ ontabchange
36514
+ });
34771
36515
  $$renderer.push(`<!----> `);
34772
36516
  PluginManagerHeaderActions($$renderer, {
34773
36517
  loading,
@@ -34809,10 +36553,14 @@ function PluginManagerPanel($$renderer, $$props) {
34809
36553
  /** Persisted chrome (the explorer-tab pattern): the active pill tab.
34810
36554
  * Junk sanitizes to 'install'. */
34811
36555
  /** Reports the active tab up to the panel entry (hard-reload survival). */
34812
- let { initialTab = "install"} = $$props;
36556
+ let { initialTab = "install", ontabchange } = $$props;
34813
36557
  let loading = true;
34814
36558
  let floorBounce = false;
34815
36559
  let tab = initialTab === "uninstall" ? "uninstall" : "install";
36560
+ function setTab(next) {
36561
+ tab = next;
36562
+ ontabchange?.(next);
36563
+ }
34816
36564
  let searchQ = "";
34817
36565
  let $$settled = true;
34818
36566
  let $$inner_renderer;
@@ -34832,7 +36580,8 @@ function PluginManagerPanel($$renderer, $$props) {
34832
36580
  PluginManagerHeader($$renderer, {
34833
36581
  tab,
34834
36582
  loading,
34835
- floorBounce});
36583
+ floorBounce,
36584
+ ontabchange: setTab});
34836
36585
  $$renderer.push(`<!----> `);
34837
36586
  {
34838
36587
  $$renderer.push("<!--[1-->");
@@ -35034,12 +36783,23 @@ function InjectedDocPanel($$renderer, $$props) {
35034
36783
  //#region src/lib/components/workspace-explorer/WorkspaceExplorerButtons.svelte
35035
36784
  function WorkspaceExplorerButtons($$renderer, $$props) {
35036
36785
  $$renderer.component(($$renderer) => {
35037
- $$renderer.push(`<div data-svelte="WorkspaceExplorerButtons" class="actions svelte-57vdun"><button class="head-btn svelte-57vdun" data-testid="explorer-refresh"${attr("aria-label", t(refresh))}${attr("title", t(refresh))}>`);
35038
- Refresh_cw($$renderer, {
36786
+ /**
36787
+ * WorkspaceExplorerButtons — the toolbar's action cluster, extracted
36788
+ * from WorkspaceExplorerToolbar (2026-09-13): Refresh and
36789
+ * Collapse-all. INTENT ONLY (Module
36790
+ * Communication Map): the buttons emit onRefresh / onCollapseAll —
36791
+ * the panel owns the state the intents act on.
36792
+ */
36793
+ let { onRefresh} = $$props;
36794
+ $$renderer.push(`<div data-svelte="WorkspaceExplorerButtons" class="actions svelte-57vdun">`);
36795
+ ReloadButton($$renderer, {
36796
+ onclick: onRefresh,
36797
+ label: t(refresh),
36798
+ testid: "explorer-refresh",
35039
36799
  size: 12,
35040
- "aria-hidden": "true"
36800
+ class: "head-btn"
35041
36801
  });
35042
- $$renderer.push(`<!----></button> <button class="head-btn svelte-57vdun" data-testid="explorer-collapse-all"${attr("aria-label", t(collapseall1))}${attr("title", t(collapseall1))}>`);
36802
+ $$renderer.push(`<!----> <button class="head-btn" data-testid="explorer-collapse-all"${attr("aria-label", t(collapseall1))}${attr("title", t(collapseall1))}>`);
35043
36803
  Chevrons_down_up($$renderer, {
35044
36804
  size: 12,
35045
36805
  "aria-hidden": "true"
@@ -35051,9 +36811,10 @@ function WorkspaceExplorerButtons($$renderer, $$props) {
35051
36811
  //#region src/lib/components/workspace-explorer/WorkspaceExplorerToolbar.svelte
35052
36812
  function WorkspaceExplorerToolbar($$renderer, $$props) {
35053
36813
  $$renderer.component(($$renderer) => {
35054
- let { activeTab = "explorer"} = $$props;
36814
+ let { onRefresh, activeTab = "explorer"} = $$props;
35055
36815
  $$renderer.push(`<div data-svelte="WorkspaceExplorerToolbar" class="explorer-toolbar svelte-wowz6p" data-testid="explorer-toolbar"><div class="tabs svelte-wowz6p" role="tablist" data-testid="explorer-tabs"><button role="tab"${attr_class("tab svelte-wowz6p", void 0, { "active": activeTab === "explorer" })}${attr("aria-selected", activeTab === "explorer")} data-testid="git-tab-explorer">${escape_html(t(giteyetabexplorer3))}</button> <button role="tab"${attr_class("tab svelte-wowz6p", void 0, { "active": activeTab === "changes" })}${attr("aria-selected", activeTab === "changes")} data-testid="git-tab-changes">${escape_html(t(giteyetabchanges3))}</button></div> `);
35056
- WorkspaceExplorerButtons($$renderer);
36816
+ WorkspaceExplorerButtons($$renderer, {
36817
+ onRefresh});
35057
36818
  $$renderer.push(`<!----></div>`);
35058
36819
  });
35059
36820
  }
@@ -35072,8 +36833,6 @@ function WorkspaceExplorerTree($$renderer, $$props) {
35072
36833
  * the levels cache, the fetches, and the git state — this component
35073
36834
  * reads them as props and emits toggle / open-file intents back.
35074
36835
  */
35075
- /** One listing row (workspaceFiles/list WorkspaceDirectoryEntry). */
35076
- /** Viewing state for one fetched level (owner-held, never persisted). */
35077
36836
  let { root, levels, expanded, repoMaps, changedPaths, changedDirs, activeFile = null } = $$props;
35078
36837
  /** The row's child rel path (the listing's names are basenames). */
35079
36838
  function childRel(rel, name) {
@@ -35294,9 +37053,10 @@ function WorkspaceExplorer($$renderer, $$props) {
35294
37053
  * never scroll itself; the scroll lives on .tree-scroll so the toolbar
35295
37054
  * stays pinned (the toolbar-scrolls-away bug).
35296
37055
  */
35297
- let { root, activeTab, levels, expanded, repoMaps, changedPaths, changedDirs, activeFile = null, changesRepos, changesStatuses, collapsedRepos} = $$props;
37056
+ let { root, activeTab, onRefresh, levels, expanded, repoMaps, changedPaths, changedDirs, activeFile = null, changesRepos, changesStatuses, collapsedRepos} = $$props;
35298
37057
  $$renderer.push(`<div data-svelte="WorkspaceExplorer" class="explorer svelte-td8lru">`);
35299
37058
  WorkspaceExplorerToolbar($$renderer, {
37059
+ onRefresh,
35300
37060
  activeTab});
35301
37061
  $$renderer.push(`<!----> `);
35302
37062
  if (activeTab === "changes") {
@@ -35330,14 +37090,137 @@ function WorkspaceExplorer($$renderer, $$props) {
35330
37090
  function WorkspaceFileTabGroup($$renderer, $$props) {
35331
37091
  $$renderer.component(($$renderer) => {
35332
37092
  /**
35333
- * WorkspaceFileTabGroup — the File Eye toggle (ADR D6), extracted
35334
- * from WorkspaceFileToolbar's .seg-group: the chat-mode-toggle
35335
- * segmented grammar — joined pill, class:on, aria-pressed. Edit is
35336
- * default. Presentational: the parent owns the view state and the
35337
- * change intent; this renders the two segments and reports picks.
37093
+ * WorkspaceFileTabGroup — the File Eye toggle (ADR D6; Plugin Rack
37094
+ * amendment IV 2026-10-31): the joined-pill grammar now lives ONCE
37095
+ * in the shared SegmentedTabs (Tailwind) — a thin adapter speaking
37096
+ * the File Eye's edit/diff vocabulary and keeping the dirty-buffer
37097
+ * lock on the Diff segment (ADR D3). Presentational: the parent
37098
+ * owns the view state and the change intent.
37099
+ */
37100
+ let { view = "edit", onviewchange } = $$props;
37101
+ SegmentedTabs($$renderer, {
37102
+ active: view,
37103
+ groupTestid: "file-view-toggle",
37104
+ ariaLabel: t(fileeyetogglelabel3),
37105
+ onchange: (id) => onviewchange?.(id === "diff" ? "diff" : "edit"),
37106
+ tabs: [{
37107
+ id: "edit",
37108
+ label: t(fileeyepreview2),
37109
+ testid: "file-view-edit"
37110
+ }, {
37111
+ id: "diff",
37112
+ label: t(fileeyediff2),
37113
+ testid: "file-view-diff"
37114
+ }]
37115
+ });
37116
+ });
37117
+ }
37118
+ //#endregion
37119
+ //#region src/lib/components/workspace-file/toolbar/PreviewTab.svelte
37120
+ function PreviewTab($$renderer, $$props) {
37121
+ $$renderer.component(($$renderer) => {
37122
+ /**
37123
+ * PreviewTab — the preview segment of the file toolbar's tab pair:
37124
+ * icon-only (Presentation glyph), the paraglide label rides
37125
+ * aria-label + title so the accessible name survives.
37126
+ */
37127
+ let { active} = $$props;
37128
+ $$renderer.push(`<button data-svelte="PreviewTab" role="tab"${attr("aria-selected", active)} data-testid="tab-preview"${attr("aria-label", t(workspacefilepreview2))}${attr("title", t(workspacefilepreview2))}${attr_class("svelte-1f747f8", void 0, { "active": active })}>`);
37129
+ Presentation($$renderer, {
37130
+ size: 12,
37131
+ "aria-hidden": "true"
37132
+ });
37133
+ $$renderer.push(`<!----></button>`);
37134
+ });
37135
+ }
37136
+ //#endregion
37137
+ //#region src/lib/components/workspace-file/toolbar/EditTab.svelte
37138
+ function EditTab($$renderer, $$props) {
37139
+ $$renderer.component(($$renderer) => {
37140
+ /**
37141
+ * EditTab — the source segment of the file toolbar's tab pair:
37142
+ * icon-only (CodeXml glyph), the paraglide label rides
37143
+ * aria-label + title so the accessible name survives.
35338
37144
  */
35339
- let { view = "edit", diffDisabled = false} = $$props;
35340
- $$renderer.push(`<div data-svelte="WorkspaceFileTabGroup" class="seg-group svelte-15pktjs" role="group"${attr("aria-label", t(fileeyetogglelabel3))} data-testid="file-view-toggle"><button type="button"${attr_class("seg left svelte-15pktjs", void 0, { "on": view === "edit" })}${attr("aria-pressed", view === "edit")} data-testid="file-view-edit">${escape_html(t(fileeyeedit2))}</button> <button type="button"${attr_class("seg right svelte-15pktjs", void 0, { "on": view === "diff" })}${attr("disabled", diffDisabled, true)}${attr("aria-pressed", view === "diff")} data-testid="file-view-diff">${escape_html(t(fileeyediff2))}</button></div>`);
37145
+ let { active} = $$props;
37146
+ $$renderer.push(`<button data-svelte="EditTab" role="tab"${attr("aria-selected", active)} data-testid="tab-edit"${attr("aria-label", t(workspacefilesource2))}${attr("title", t(workspacefilesource2))}${attr_class("svelte-z03alu", void 0, { "active": active })}>`);
37147
+ Code_xml($$renderer, {
37148
+ size: 12,
37149
+ "aria-hidden": "true"
37150
+ });
37151
+ $$renderer.push(`<!----></button>`);
37152
+ });
37153
+ }
37154
+ //#endregion
37155
+ //#region src/lib/components/workspace-file/toolbar/FileEdit.svelte
37156
+ function FileEdit($$renderer, $$props) {
37157
+ $$renderer.component(($$renderer) => {
37158
+ /**
37159
+ * FileEdit — The Single Edit (ADR D2/D6): the mode verb. Icon-only
37160
+ * (Pencil when idle, X while editing); the label rides aria-label +
37161
+ * title and flips Edit -> Cancel with the mode.
37162
+ */
37163
+ let { editing = false} = $$props;
37164
+ $$renderer.push(`<button data-svelte="FileEdit" type="button" class="head-chip svelte-1nxrcih" data-testid="file-edit"${attr("aria-label", editing ? t(workspacefilecancel2) : t(workspacefileedit2))}${attr("title", editing ? t(workspacefilecancel2) : t(workspacefileedit2))}>`);
37165
+ if (editing) {
37166
+ $$renderer.push("<!--[0-->");
37167
+ Undo_dot($$renderer, {
37168
+ size: 12,
37169
+ "aria-hidden": "true"
37170
+ });
37171
+ } else {
37172
+ $$renderer.push("<!--[-1-->");
37173
+ Pencil($$renderer, {
37174
+ size: 12,
37175
+ "aria-hidden": "true"
37176
+ });
37177
+ }
37178
+ $$renderer.push(`<!--]--></button>`);
37179
+ });
37180
+ }
37181
+ //#endregion
37182
+ //#region src/lib/components/workspace-file/toolbar/FileSave.svelte
37183
+ function FileSave($$renderer, $$props) {
37184
+ $$renderer.component(($$renderer) => {
37185
+ /**
37186
+ * FileSave — The Single Edit (ADR D3): Save renders ONLY while a draft
37187
+ * exists (the owner gates the mount). Icon-only (Save glyph); disabled
37188
+ * while the delegated save is in flight.
37189
+ */
37190
+ let { saving = false} = $$props;
37191
+ $$renderer.push(`<button data-svelte="FileSave" type="button" class="head-chip save-btn svelte-k5ua2k" data-testid="file-save"${attr("aria-label", saving ? t(workspacefilesaving2) : t(workspacefilesave2))}${attr("title", saving ? t(workspacefilesaving2) : t(workspacefilesave2))}${attr("disabled", saving, true)}>`);
37192
+ Save($$renderer, {
37193
+ size: 12,
37194
+ "aria-hidden": "true"
37195
+ });
37196
+ $$renderer.push(`<!----></button>`);
37197
+ });
37198
+ }
37199
+ //#endregion
37200
+ //#region src/lib/components/workspace-file/toolbar/HeadChip.svelte
37201
+ function HeadChip($$renderer, $$props) {
37202
+ $$renderer.component(($$renderer) => {
37203
+ /**
37204
+ * HeadChip — the workspace-explorer hide/show toggle (2026-10-31):
37205
+ * icon-only bordered chip; the glyph reflects the lane's visibility
37206
+ * and the paraglide label rides aria-label + title.
37207
+ */
37208
+ let { hidden = false} = $$props;
37209
+ $$renderer.push(`<button data-svelte="HeadChip" type="button" class="head-chip svelte-1u072cb" data-testid="explorer-toggle"${attr("aria-label", hidden ? t(workspaceexplorershow2) : t(workspaceexplorerhide2))}${attr("title", hidden ? t(workspaceexplorershow2) : t(workspaceexplorerhide2))}>`);
37210
+ if (hidden) {
37211
+ $$renderer.push("<!--[0-->");
37212
+ Panel_left_open($$renderer, {
37213
+ size: 12,
37214
+ "aria-hidden": "true"
37215
+ });
37216
+ } else {
37217
+ $$renderer.push("<!--[-1-->");
37218
+ Panel_left_close($$renderer, {
37219
+ size: 12,
37220
+ "aria-hidden": "true"
37221
+ });
37222
+ }
37223
+ $$renderer.push(`<!--]--></button>`);
35341
37224
  });
35342
37225
  }
35343
37226
  //#endregion
@@ -35348,19 +37231,49 @@ function WorkspaceFileToolbar($$renderer, $$props) {
35348
37231
  * (idle → busy spinner → done check → idle), mirrored per the 2026-10-27
35349
37232
  * UX-parity operator request: a click that shows nothing happening "sucks". */
35350
37233
  let reloadState = "idle";
37234
+ async function handleReload() {
37235
+ if (reloadState === "busy" || !onreload) return;
37236
+ reloadState = "busy";
37237
+ try {
37238
+ await onreload();
37239
+ reloadState = "done";
37240
+ setTimeout(() => reloadState = "idle", 2e3);
37241
+ } catch {
37242
+ reloadState = "idle";
37243
+ }
37244
+ }
35351
37245
  let columnEl = null;
35352
- let { dirty, saveState = "idle", stale = false, staleNote = "", hasTabs = false, tab = "preview", view = "edit", showToggle = false, diffDisabled = false, readonly = false, onviewchange, onsave, onreload, path } = $$props;
37246
+ let { dirty, saveState = "idle", stale = false, staleNote = "", hasTabs = false, tab = "preview", view = "edit", showToggle = false, editing = false, ontoggledit, readonly = false, onviewchange, onsave, onreload, ontoggleexplorer, explorerHidden = false, path } = $$props;
35353
37247
  $$renderer.push(`<div data-svelte="WorkspaceFileToolbar" class="file-toolbar svelte-1vsjf39" data-testid="file-toolbar"><span class="path svelte-1vsjf39"${attr("title", path)}>${escape_html(path)}</span> `);
35354
37248
  if (showToggle) {
35355
37249
  $$renderer.push("<!--[0-->");
35356
37250
  WorkspaceFileTabGroup($$renderer, {
35357
37251
  view,
35358
- diffDisabled});
37252
+ onviewchange
37253
+ });
37254
+ } else $$renderer.push("<!--[-1-->");
37255
+ $$renderer.push(`<!--]--> `);
37256
+ if (hasTabs) {
37257
+ $$renderer.push("<!--[0-->");
37258
+ $$renderer.push(`<div class="tabs svelte-1vsjf39" role="tablist">`);
37259
+ PreviewTab($$renderer, {
37260
+ active: tab === "preview"});
37261
+ $$renderer.push(`<!----> `);
37262
+ EditTab($$renderer, {
37263
+ active: tab === "edit"});
37264
+ $$renderer.push(`<!----></div>`);
35359
37265
  } else $$renderer.push("<!--[-1-->");
35360
37266
  $$renderer.push(`<!--]--> `);
35361
37267
  if (!readonly) {
35362
37268
  $$renderer.push("<!--[0-->");
35363
- $$renderer.push(`<button type="button" class="save-btn svelte-1vsjf39" data-testid="file-save"${attr("disabled", !dirty || saveState === "saving" || view === "diff", true)}>${escape_html(saveState === "saving" ? t(workspacefilesaving2) : t(workspacefilesave2))}</button>`);
37269
+ FileEdit($$renderer, {
37270
+ editing});
37271
+ } else $$renderer.push("<!--[-1-->");
37272
+ $$renderer.push(`<!--]--> `);
37273
+ if (!readonly && editing && dirty) {
37274
+ $$renderer.push("<!--[0-->");
37275
+ FileSave($$renderer, {
37276
+ saving: saveState === "saving"});
35364
37277
  } else $$renderer.push("<!--[-1-->");
35365
37278
  $$renderer.push(`<!--]--> `);
35366
37279
  if (dirty) {
@@ -35378,17 +37291,21 @@ function WorkspaceFileToolbar($$renderer, $$props) {
35378
37291
  $$renderer.push(`<span class="stale svelte-1vsjf39" data-testid="file-stale-external">${escape_html(staleNote)}</span>`);
35379
37292
  } else $$renderer.push("<!--[-1-->");
35380
37293
  $$renderer.push(`<!--]--> `);
35381
- if (hasTabs) {
37294
+ if (onreload) {
35382
37295
  $$renderer.push("<!--[0-->");
35383
- $$renderer.push(`<div class="tabs svelte-1vsjf39" role="tablist"><button role="tab"${attr("aria-selected", tab === "preview")} data-testid="tab-preview"${attr_class("svelte-1vsjf39", void 0, { "active": tab === "preview" })}>${escape_html(t(workspacefilepreview2))}</button> <button role="tab"${attr("aria-selected", tab === "edit")} data-testid="tab-edit"${attr_class("svelte-1vsjf39", void 0, { "active": tab === "edit" })}>${escape_html(t(workspacefileedit2))}</button></div>`);
37296
+ ReloadButton($$renderer, {
37297
+ state: reloadState,
37298
+ onclick: handleReload,
37299
+ label: t(refresh),
37300
+ testid: "file-reload",
37301
+ class: "reload-btn"
37302
+ });
35384
37303
  } else $$renderer.push("<!--[-1-->");
35385
37304
  $$renderer.push(`<!--]--> `);
35386
- if (onreload) {
37305
+ if (ontoggleexplorer) {
35387
37306
  $$renderer.push("<!--[0-->");
35388
- $$renderer.push(`<button type="button" class="reload-btn svelte-1vsjf39" data-testid="file-reload"${attr("data-state", reloadState)}${attr("title", t(refresh))}${attr("aria-label", t(refresh))}>`);
35389
- $$renderer.push("<!--[-1-->");
35390
- Rotate_cw($$renderer, { size: 14 });
35391
- $$renderer.push(`<!--]--></button>`);
37307
+ HeadChip($$renderer, {
37308
+ hidden: explorerHidden});
35392
37309
  } else $$renderer.push("<!--[-1-->");
35393
37310
  $$renderer.push(`<!--]--> <span class="copy-slot svelte-1vsjf39">`);
35394
37311
  CanvasCopyButton($$renderer, {
@@ -35421,7 +37338,7 @@ function WorkspaceFile($$renderer, $$props) {
35421
37338
  * old overflow:auto container made the hosts content-sized and the
35422
37339
  * page-level scrollbar stole the height.
35423
37340
  */
35424
- let { tab = void 0, dirty, fullPath, saveState, fileStale, staleNote, hasTabs, activeView, showToggle, diffDisabled, readonly, onViewChange, onSave, onReload, saveError, saveFailedNote, loadingNote, loadFailedNote, truncatedNote, newFileNote, phase, errorCode, title, isImage, bytesSrc, isHtml, text, isMarkdown, noHead, eof, editorHost = null, diffHost = null } = $$props;
37341
+ let { tab = void 0, dirty, fullPath, saveState, fileStale, staleNote, hasTabs, activeView, showToggle, editing, onToggleEdit, readonly, onViewChange, onSave, onReload, onToggleExplorer, explorerHidden = false, saveError, saveFailedNote, loadingNote, loadFailedNote, truncatedNote, newFileNote, phase, errorCode, title, isImage, bytesSrc, isHtml, text, isMarkdown, noHead, eof, editorHost = null, diffHost = null } = $$props;
35425
37342
  let $$settled = true;
35426
37343
  let $$inner_renderer;
35427
37344
  function $$render_inner($$renderer) {
@@ -35435,11 +37352,14 @@ function WorkspaceFile($$renderer, $$props) {
35435
37352
  hasTabs,
35436
37353
  view: activeView,
35437
37354
  showToggle,
35438
- diffDisabled,
37355
+ editing,
37356
+ ontoggledit: onToggleEdit,
35439
37357
  readonly,
35440
37358
  onviewchange: onViewChange,
35441
37359
  onsave: onSave,
35442
37360
  onreload: onReload,
37361
+ ontoggleexplorer: onToggleExplorer,
37362
+ explorerHidden,
35443
37363
  get tab() {
35444
37364
  return tab;
35445
37365
  },
@@ -35528,7 +37448,7 @@ function WorkspaceFilePanel($$renderer, $$props) {
35528
37448
  * outside-workspace, too-large, not-text, not-regular-file.
35529
37449
  */
35530
37450
  /** The read receipt (api/dsh/workspace-file body, DshWorkspaceFileText). */
35531
- let { sessionId, path, root, view = "edit", onviewchange, onclose, highlightLines = null, onhighlightdone } = $$props;
37451
+ let { sessionId, path, root, view = "edit", onviewchange, onclose, highlightLines = null, onhighlightdone, ontoggleexplorer, explorerHidden = false, ondirtychange } = $$props;
35532
37452
  let viewOverride = null;
35533
37453
  const activeView = derived(() => viewOverride ?? view);
35534
37454
  let tab = "preview";
@@ -35538,6 +37458,22 @@ function WorkspaceFilePanel($$renderer, $$props) {
35538
37458
  let eof = true;
35539
37459
  /** Dirty = the edit buffer differs from the baseline. */
35540
37460
  let dirty = false;
37461
+ /** Clear-scope surfacing (ADR D5c amendment 2026-11-03): the explorer
37462
+ * panel keeps a per-path dirty map so its tab strip can tint dirty
37463
+ * tabs and resolve Clear non-dirty. Optional — standalone file
37464
+ * panels pass no listener and lose nothing. */
37465
+ /** The Single Edit (ADR D2): the operator-facing edit mode — the raw
37466
+ * editor mounts writable only while this is true. Cancel reverts the
37467
+ * buffer to the baseline. */
37468
+ let editing = false;
37469
+ /** Edit-mode intent: entering carries the live buffer; Cancel (D2)
37470
+ * reverts to baseline and clears dirty. */
37471
+ function setEditing(next) {
37472
+ if (next === editing) return;
37473
+ if (!next) dirty = false;
37474
+ editing = next;
37475
+ if (next && isMarkdown() && tab !== "edit") tab = "edit";
37476
+ }
35541
37477
  /** The delegated save's progress (ADR D4): idle → saving → saved /
35542
37478
  * failed; a further edit re-arms the button from any state. */
35543
37479
  let saveState = "idle";
@@ -35615,11 +37551,14 @@ function WorkspaceFilePanel($$renderer, $$props) {
35615
37551
  hasTabs: hasTabs(),
35616
37552
  activeView: activeView(),
35617
37553
  showToggle: false,
35618
- diffDisabled: dirty,
37554
+ editing,
37555
+ onToggleEdit: setEditing,
35619
37556
  readonly: false,
35620
37557
  onViewChange: setView,
35621
37558
  onSave: save,
35622
37559
  onReload: refreshFile,
37560
+ onToggleExplorer: ontoggleexplorer,
37561
+ explorerHidden,
35623
37562
  saveError,
35624
37563
  saveFailedNote: t(workspacefilesavefailed3),
35625
37564
  loadingNote: t(workspaceexplorerloading2),
@@ -35745,30 +37684,44 @@ function WorkspaceFileTabs($$renderer, $$props) {
35745
37684
  * PRESENTATION ONLY (Module Communication Map): the open-tab list, the
35746
37685
  * active path, and every fetch arrive as PROPS from the owning
35747
37686
  * WorkspaceExplorerPanel; the only things leaving are INTENT callbacks
35748
- * — onActivate (focus an open tab), onClose (the per-tab [x]). The
35749
- * content region is the parent's children snippet, so the panel hosts
35750
- * WorkspaceFile itself and this component never fetches.
37687
+ * — onActivate (focus an open tab), onClose (the per-tab [x]), and
37688
+ * onClearAll (the sticky clear's blanket confirm, ADR D5c amendment
37689
+ * 2026-11-03). The content region is the parent's children snippet, so
37690
+ * the panel hosts WorkspaceFile itself and this component never fetches.
35751
37691
  *
35752
37692
  * A closed panel drops the tabs with it (D5) — nothing here persists.
35753
37693
  */
35754
37694
  /** One open file tab — the panel's component state, deduped by path. */
35755
37695
  /** Root-relative path — identity within the panel's tab list. */
35756
- let { tabs, activePath, children } = $$props;
37696
+ /** Unsaved edit-buffer flag — the panel computes it from its
37697
+ * baseline (ADR D5d amendment 2026-11-03); drives the tint. */
37698
+ let { tabs, activePath, onClearAll, children } = $$props;
35757
37699
  /** Tab label — the leaf name; the full root-relative path rides the
35758
37700
  * title attribute (ADR D5). */
35759
37701
  function leaf(path) {
35760
37702
  const idx = path.lastIndexOf("/");
35761
37703
  return idx === -1 ? path : path.slice(idx + 1);
35762
37704
  }
37705
+ let clearOpen = false;
35763
37706
  $$renderer.push(`<div data-svelte="WorkspaceFileTabs" class="file-tabs svelte-1xheh2q" data-testid="workspace-file-tabs">`);
35764
37707
  if (tabs.length > 0) {
35765
37708
  $$renderer.push("<!--[0-->");
35766
- $$renderer.push(`<div class="strip svelte-1xheh2q" role="tablist" data-testid="workspace-file-tabstrip"><!--[-->`);
37709
+ $$renderer.push(`<div class="strip-row svelte-1xheh2q"><div class="strip svelte-1xheh2q" role="tablist" data-testid="workspace-file-tabstrip"><!--[-->`);
35767
37710
  const each_array = ensure_array_like(tabs);
35768
37711
  for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
35769
37712
  let tab = each_array[$$index];
35770
- $$renderer.push(`<button type="button" role="tab"${attr_class("tab svelte-1xheh2q", void 0, { "active": tab.path === activePath })}${attr("data-testid", `workspace-file-tab-${stringify(tab.path)}`)}${attr("title", tab.path)}${attr("aria-selected", tab.path === activePath)}><span class="label svelte-1xheh2q">${escape_html(leaf(tab.path))}</span> <span role="button" tabindex="-1" class="close svelte-1xheh2q"${attr("data-testid", `workspace-file-tabclose-${stringify(tab.path)}`)}${attr("aria-label", t(close))}${attr("title", t(close))}>×</span></button>`);
37713
+ $$renderer.push(`<button type="button" role="tab"${attr_class("tab svelte-1xheh2q", void 0, {
37714
+ "active": tab.path === activePath,
37715
+ "dirty": tab.dirty === true
37716
+ })}${attr("data-testid", `workspace-file-tab-${stringify(tab.path)}`)}${attr("title", tab.path)}${attr("aria-selected", tab.path === activePath)}><span class="label svelte-1xheh2q">${escape_html(leaf(tab.path))}</span> <span role="button" tabindex="-1" class="close svelte-1xheh2q"${attr("data-testid", `workspace-file-tabclose-${stringify(tab.path)}`)}${attr("aria-label", t(close))}${attr("title", t(close))}>×</span></button>`);
35771
37717
  }
37718
+ $$renderer.push(`<!--]--></div> `);
37719
+ if (onClearAll) {
37720
+ $$renderer.push("<!--[0-->");
37721
+ $$renderer.push(`<div class="clear-slot svelte-1xheh2q" data-testid="workspace-file-tabstrip-clear-slot"><button type="button" class="clear-btn svelte-1xheh2q" data-testid="workspace-file-tabstrip-clear"${attr("aria-label", t(workspacefiletabsclear3))}${attr("title", t(workspacefiletabsclear3))}${attr("aria-expanded", clearOpen)}>×</button> `);
37722
+ $$renderer.push("<!--[-1-->");
37723
+ $$renderer.push(`<!--]--></div>`);
37724
+ } else $$renderer.push("<!--[-1-->");
35772
37725
  $$renderer.push(`<!--]--></div> <div class="body svelte-1xheh2q">`);
35773
37726
  children($$renderer);
35774
37727
  $$renderer.push(`<!----></div>`);
@@ -35811,7 +37764,7 @@ function ResizeGutter($$renderer, $$props) {
35811
37764
  //#region src/lib/components/workspace-explorer/WorkspaceExplorerPanel.svelte
35812
37765
  function WorkspaceExplorerPanel($$renderer, $$props) {
35813
37766
  $$renderer.component(($$renderer) => {
35814
- let { sessionId, root, home, expanded, onToggle, onOpenFile, onCollapseAll, tab = "explorer", onTabChange, collapsedRepos, onToggleRepo, onCollapseAllRepos, treePct = 30, onTreePctChange, pendingOpenFile = null, onPendingOpenConsumed, openTabs = [], activeFile = null, onOpenTab, onCloseTab, onActivateTab } = $$props;
37767
+ let { sessionId, root, home, expanded, onToggle, onOpenFile, onCollapseAll, tab = "explorer", onTabChange, collapsedRepos, onToggleRepo, onCollapseAllRepos, treePct = 30, onTreePctChange, pendingOpenFile = null, onPendingOpenConsumed, openTabs = [], activeFile = null, onOpenTab, onCloseTab, onActivateTab, ontoggleexplorer, explorerHidden = false } = $$props;
35815
37768
  /** Rel path → level state. Key '' is the root level. */
35816
37769
  let levels = {};
35817
37770
  let repoMaps = {};
@@ -35853,6 +37806,19 @@ function WorkspaceExplorerPanel($$renderer, $$props) {
35853
37806
  }
35854
37807
  return out;
35855
37808
  });
37809
+ /** Refresh intent: drop the whole levels cache — the effect re-fetches
37810
+ * the root level and every still-expanded path once each. */
37811
+ function refresh() {
37812
+ levels = {};
37813
+ invalidateGit();
37814
+ }
37815
+ /** The git caches ONLY (Index Pulse W3): the tree structure did not
37816
+ * change, so the levels cache survives — the probes and status fetches
37817
+ * re-run through the same guarded effects as a full Refresh. */
37818
+ function invalidateGit() {
37819
+ repoMaps = {};
37820
+ changesStatuses = {};
37821
+ }
35856
37822
  let pulseSource = null;
35857
37823
  function closePulse() {
35858
37824
  pulseSource?.close();
@@ -35866,28 +37832,47 @@ function WorkspaceExplorerPanel($$renderer, $$props) {
35866
37832
  /** The rendered tree lane: the settled px, or the narrow-lane default
35867
37833
  * before the first measurement. Percent lives only in treePct. */
35868
37834
  const treeBasis = derived(() => 280);
35869
- $$renderer.push(`<div data-svelte="WorkspaceExplorerPanel" data-testid="workspace-explorer" class="split svelte-ldghfc"${attr_style(`--tree-basis: ${stringify(treeBasis())}px`)}>`);
35870
- WorkspaceExplorer($$renderer, {
35871
- activeFile,
35872
- root,
35873
- activeTab: activeTab(),
35874
- levels,
35875
- expanded,
35876
- repoMaps,
35877
- changedPaths: changedPaths(),
35878
- changedDirs: changedDirs(),
35879
- changesRepos: changesRepos(),
35880
- changesStatuses,
35881
- collapsedRepos});
35882
- $$renderer.push(`<!----> `);
35883
- ResizeGutter($$renderer, {
35884
- index: 0,
35885
- onDragStart: startSplitDrag
35886
- });
35887
- $$renderer.push(`<!----> `);
37835
+ /** Hide/show (2026-10-31): a hidden lane collapses the basis to zero —
37836
+ * the tree and the gutter unmount, the file region takes the width. */
37837
+ const laneBasis = derived(() => explorerHidden ? 0 : treeBasis());
37838
+ let dirtyMap = {};
37839
+ $$renderer.push(`<div data-svelte="WorkspaceExplorerPanel" data-testid="workspace-explorer" class="split svelte-ldghfc"${attr_style(`--tree-basis: ${stringify(laneBasis())}px`)}>`);
37840
+ if (!explorerHidden) {
37841
+ $$renderer.push("<!--[0-->");
37842
+ WorkspaceExplorer($$renderer, {
37843
+ activeFile,
37844
+ root,
37845
+ activeTab: activeTab(),
37846
+ onRefresh: refresh,
37847
+ levels,
37848
+ expanded,
37849
+ repoMaps,
37850
+ changedPaths: changedPaths(),
37851
+ changedDirs: changedDirs(),
37852
+ changesRepos: changesRepos(),
37853
+ changesStatuses,
37854
+ collapsedRepos});
37855
+ $$renderer.push(`<!----> `);
37856
+ ResizeGutter($$renderer, {
37857
+ index: 0,
37858
+ onDragStart: startSplitDrag
37859
+ });
37860
+ $$renderer.push(`<!---->`);
37861
+ } else $$renderer.push("<!--[-1-->");
37862
+ $$renderer.push(`<!--]--> `);
35888
37863
  WorkspaceFileTabs($$renderer, {
35889
- tabs: openTabs.map((p) => ({ path: p })),
37864
+ tabs: openTabs.map((p) => ({
37865
+ path: p,
37866
+ dirty: dirtyMap[p] === true
37867
+ })),
35890
37868
  activePath: activeFile,
37869
+ onClearAll: (scope) => {
37870
+ const doomed = scope === "all" ? [...openTabs] : openTabs.filter((p) => dirtyMap[p] !== true);
37871
+ for (const path of doomed) {
37872
+ onCloseTab?.(path);
37873
+ delete dirtyMap[path];
37874
+ }
37875
+ },
35891
37876
  children: ($$renderer) => {
35892
37877
  if (activeFile !== null) {
35893
37878
  $$renderer.push("<!--[0-->");
@@ -35905,7 +37890,12 @@ function WorkspaceExplorerPanel($$renderer, $$props) {
35905
37890
  root,
35906
37891
  highlightLines: lineTarget,
35907
37892
  onhighlightdone: () => lineTarget = null,
35908
- onclose: () => {}
37893
+ onclose: () => {},
37894
+ ontoggleexplorer,
37895
+ explorerHidden,
37896
+ ondirtychange: (d) => {
37897
+ dirtyMap[activeFile] = d;
37898
+ }
35909
37899
  });
35910
37900
  } else $$renderer.push("<!--[-1-->");
35911
37901
  $$renderer.push(`<!--]-->`);
@@ -36065,7 +38055,10 @@ function PanelColumn($$renderer, $$props) {
36065
38055
  $$renderer.push(`<!----> `);
36066
38056
  if (widthBadge !== null) {
36067
38057
  $$renderer.push("<!--[0-->");
36068
- $$renderer.push(`<span${attr_class("width-badge svelte-1cuodug", void 0, { "fading": widthBadge === "fading" })} data-testid="panel-width-badge"${attr("data-badge-phase", widthBadge)} aria-hidden="true">${escape_html(Math.round(panel.width))}px</span>`);
38058
+ WidthBadge($$renderer, {
38059
+ phase: widthBadge,
38060
+ width: panel.width
38061
+ });
36069
38062
  } else $$renderer.push("<!--[-1-->");
36070
38063
  $$renderer.push(`<!--]--> <div class="body svelte-1cuodug">`);
36071
38064
  children($$renderer);
@@ -36379,6 +38372,7 @@ function _page($$renderer, $$props) {
36379
38372
  const fromQuery = page.url.searchParams.get("sessionKey");
36380
38373
  return fromQuery !== null && fromQuery.length > 0 ? fromQuery : null;
36381
38374
  }
38375
+ captureHarnessSessionKey(seedSessionId());
36382
38376
  const seededInitially = seedSessionId() !== null;
36383
38377
  const seedCold = seedColdOf(page.data);
36384
38378
  pagePrefs.init(activeProfile);
@@ -36394,6 +38388,7 @@ function _page($$renderer, $$props) {
36394
38388
  getPanelWidth: () => pagePrefs.panelWidth,
36395
38389
  setPanelWidthPreset: (w) => pagePrefs.panelWidth = w,
36396
38390
  setTreePct: (pct) => pagePrefs.treePct = pct,
38391
+ setExplorerHidden: (hidden) => pagePrefs.explorerHidden = hidden,
36397
38392
  getSettingsHomes: () => appConfig().settingsHomes,
36398
38393
  applyTerminalDeskAction: (a) => void 0,
36399
38394
  releaseGlasses: (ids) => void releaseGlasses(ids)
@@ -36401,22 +38396,35 @@ function _page($$renderer, $$props) {
36401
38396
  initFloor(seededInitially ? [makePanel(seedSessionId(), seedCold?.agentPreset ?? null)] : initialPrefs.panels, seededInitially ? null : initialPrefs.selectedPanelId);
36402
38397
  if (seededInitially) selectPanel(floor.panels[0]?.id ?? null);
36403
38398
  if (seededInitially && seedCold !== void 0) pageFeeds.primeSeed(seedSessionId(), seedCold);
38399
+ let restoringGlasses = false;
36404
38400
  async function restoreBrowserGlasses() {
38401
+ if (restoringGlasses) return;
38402
+ restoringGlasses = true;
36405
38403
  try {
36406
38404
  if (floor.panels.some((panel) => panel.kind === "browser")) return;
36407
38405
  const res = await fetch("/api/browser");
36408
38406
  if (!res.ok) return;
36409
38407
  const body = await res.json();
38408
+ const ownSessions = new Set(floor.panels.filter((p) => p.kind === "conversation").map((p) => p.sessionId));
38409
+ const pageKey = harnessSessionKey();
38410
+ if (pageKey) ownSessions.add(pageKey);
36410
38411
  const live = new Set((body.sessions ?? []).map((s) => s.id));
38412
+ const ownerOf = new Map((body.sessions ?? []).map((s) => [s.id, s.ownerSessionId ?? null]));
38413
+ const mine = (id) => {
38414
+ const owner = ownerOf.get(id);
38415
+ return owner == null || ownSessions.has(owner);
38416
+ };
36411
38417
  const slots = readBrowserSlots();
36412
- const dead = slots.filter((s) => s.sessionId && !live.has(s.sessionId));
38418
+ const dead = slots.filter((s) => s.sessionId && (!live.has(s.sessionId) || !mine(s.sessionId)));
36413
38419
  if (dead.length > 0) persistBrowserSlots(slots.filter((s) => !dead.includes(s)));
36414
38420
  for (const slot of slots) {
36415
38421
  if (slot.folded) continue;
36416
- if (!slot.sessionId || !live.has(slot.sessionId)) continue;
38422
+ if (!slot.sessionId || !live.has(slot.sessionId) || !mine(slot.sessionId)) continue;
36417
38423
  summonGlass(slot);
36418
38424
  }
36419
- } catch {}
38425
+ } catch {} finally {
38426
+ restoringGlasses = false;
38427
+ }
36420
38428
  }
36421
38429
  /** Bring ONE folded glass back (the summon; the replace verb is the
36422
38430
  * same re-bind — the glass owns its slot identity, D4). keepSelection:
@@ -36467,6 +38475,22 @@ function _page($$renderer, $$props) {
36467
38475
  function startSidebarResize(e) {
36468
38476
  e.preventDefault();
36469
38477
  e.clientX, pagePrefs.sidebarWidth;
38478
+ pagePrefs.cancelSidebarAfterglow();
38479
+ }
38480
+ let chord = IDLE_CHORD;
38481
+ function subagentConversationCount() {
38482
+ const subagents = floorSeam().getLineageFacts().subagentIds;
38483
+ return floor.panels.filter((p) => p.kind === "conversation" && subagents.has(p.sessionId)).length;
38484
+ }
38485
+ function chordPaletteRows() {
38486
+ const kinds = [...new Set(floor.panels.map((p) => p.kind))];
38487
+ const selected = floor.panels.find((p) => p.id === floor.selectedPanelId);
38488
+ return chordOptions({
38489
+ presets: appConfig().panel.presets,
38490
+ panelKinds: kinds,
38491
+ subagentCount: subagentConversationCount(),
38492
+ focusedConversation: selected?.kind === "conversation"
38493
+ });
36470
38494
  }
36471
38495
  function sidebarRail($$renderer) {
36472
38496
  AppSidebar($$renderer, {
@@ -36504,7 +38528,9 @@ function _page($$renderer, $$props) {
36504
38528
  $$renderer.push(`<div class="panel-manager-body svelte-1uha8ag" data-testid="panel-terminal">`);
36505
38529
  TerminalDesk($$renderer, {
36506
38530
  restored: panel.desk ?? null,
36507
- onMirror: (m) => terminalDeskMirrors[panel.id] = m,
38531
+ onMirror: (m) => {
38532
+ terminalDeskMirrors[panel.id] = m;
38533
+ },
36508
38534
  onShellExit: () => removePanel(panel.id)
36509
38535
  });
36510
38536
  $$renderer.push(`<!----></div>`);
@@ -36541,7 +38567,9 @@ function _page($$renderer, $$props) {
36541
38567
  $$renderer.push(`<div class="panel-manager-body svelte-1uha8ag" data-testid="panel-plugins">`);
36542
38568
  PluginManagerPanel($$renderer, {
36543
38569
  refreshToken: panel.refresh ?? 0,
36544
- initialTab: panel.tab ?? "install"});
38570
+ initialTab: panel.tab ?? "install",
38571
+ ontabchange: (v) => setRackTab(panel.id, v)
38572
+ });
36545
38573
  $$renderer.push(`<!----></div>`);
36546
38574
  } else if (panel.kind === "skill-shelf") {
36547
38575
  $$renderer.push("<!--[5-->");
@@ -36582,6 +38610,8 @@ function _page($$renderer, $$props) {
36582
38610
  onCollapseAllRepos: (repos) => collapseExplorerRepos(panel.id, repos),
36583
38611
  treePct: pagePrefs.treePct,
36584
38612
  onTreePctChange: (pct) => setExplorerTreePct(panel.id, pct),
38613
+ explorerHidden: pagePrefs.explorerHidden,
38614
+ ontoggleexplorer: () => setExplorerHidden(panel.id, !pagePrefs.explorerHidden),
36585
38615
  pendingOpenFile: pendingFileIntents()[panel.id] ?? null,
36586
38616
  onPendingOpenConsumed: (nonce) => consumeFileIntent(panel.id, nonce),
36587
38617
  openTabs: panel.openTabs ?? [],
@@ -36684,7 +38714,10 @@ function _page($$renderer, $$props) {
36684
38714
  $$renderer.push(`<title>Workspace — deepseek-insight</title>`);
36685
38715
  });
36686
38716
  });
36687
- $$renderer.push(`<div data-svelte="ConversationPage" class="flex h-dvh conversation-page svelte-1uha8ag">`);
38717
+ ChordPalette($$renderer, {
38718
+ open: chord.armed,
38719
+ rows: chordPaletteRows()});
38720
+ $$renderer.push(`<!----> <div data-svelte="ConversationPage" class="flex h-dvh conversation-page svelte-1uha8ag">`);
36688
38721
  if (!sidebarInZoom()) {
36689
38722
  $$renderer.push("<!--[0-->");
36690
38723
  sidebarRail($$renderer);
@@ -36753,4 +38786,4 @@ function _page($$renderer, $$props) {
36753
38786
  }
36754
38787
 
36755
38788
  export { _page as default };
36756
- //# sourceMappingURL=_page.svelte.js-CY7zcWr4.js.map
38789
+ //# sourceMappingURL=_page.svelte.js-DQWBiRk1.js.map