@deepseek-insight/dsi 0.8.0 → 0.8.2

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 (176) hide show
  1. package/build/client/_app/immutable/assets/0.DBVVEjy9.css +2 -0
  2. package/build/client/_app/immutable/assets/2.BPprd30B.css +1 -0
  3. package/build/client/_app/immutable/chunks/{Dk9aRp2m.js → 4B6J_kM2.js} +1 -1
  4. package/build/client/_app/immutable/chunks/{ANnPTMPF.js → 4cwyag_I.js} +1 -1
  5. package/build/client/_app/immutable/chunks/{D7-uGicP.js → 7FnrqGK9.js} +1 -1
  6. package/build/client/_app/immutable/chunks/{CIH5Juz4.js → AcmOeh2U.js} +1 -1
  7. package/build/client/_app/immutable/chunks/{BqX9BB0G.js → B2jrDnt8.js} +1 -1
  8. package/build/client/_app/immutable/chunks/{A5Iiq81h.js → B4F5liKq.js} +1 -1
  9. package/build/client/_app/immutable/chunks/{D3rUyYDm.js → B6bTO8_7.js} +1 -1
  10. package/build/client/_app/immutable/chunks/{2XtVrxH4.js → BBd0nTHG.js} +1 -1
  11. package/build/client/_app/immutable/chunks/BHDqH9nE.js +1 -0
  12. package/build/client/_app/immutable/chunks/BHodvdRc.js +1 -0
  13. package/build/client/_app/immutable/chunks/{-izoh3h0.js → BO99LSSA.js} +1 -1
  14. package/build/client/_app/immutable/chunks/{BjafRUyA.js → BQC6O_RV.js} +1 -1
  15. package/build/client/_app/immutable/chunks/{BJsp4NMH.js → BWRXzjmQ.js} +1 -1
  16. package/build/client/_app/immutable/chunks/{crRp5OG4.js → BXKc4uuX.js} +1 -1
  17. package/build/client/_app/immutable/chunks/{j2lJ25s0.js → BenkQ_4r.js} +1 -1
  18. package/build/client/_app/immutable/chunks/{Dso_gKeU.js → BkYT72a1.js} +1 -1
  19. package/build/client/_app/immutable/chunks/{CCWXLdgd.js → BlwWx85l.js} +1 -1
  20. package/build/client/_app/immutable/chunks/{DCmONIPx.js → BmDADyfH.js} +1 -1
  21. package/build/client/_app/immutable/chunks/{DYfx-RRD.js → Bpd0I3U7.js} +1 -1
  22. package/build/client/_app/immutable/chunks/{B-V7Vlsz.js → Bqwvv7Vf.js} +4 -4
  23. package/build/client/_app/immutable/chunks/{CQTGR8fW.js → BsBBq-Qk.js} +1 -1
  24. package/build/client/_app/immutable/chunks/{IBXFCASw.js → Byu_teLA.js} +1 -1
  25. package/build/client/_app/immutable/chunks/{Cx8YXmgi.js → C4gs6zoI.js} +1 -1
  26. package/build/client/_app/immutable/chunks/CAneZX4t.js +8 -0
  27. package/build/client/_app/immutable/chunks/{CvvYpRG9.js → CAoCg_fG.js} +1 -1
  28. package/build/client/_app/immutable/chunks/{olUfRNXS.js → CB55Rp7-.js} +1 -1
  29. package/build/client/_app/immutable/chunks/{C1dC47iq.js → CH_bR_0j.js} +1 -1
  30. package/build/client/_app/immutable/chunks/{DfIqw6WM.js → CK5vhXvt.js} +1 -1
  31. package/build/client/_app/immutable/chunks/{0HT0ILkA.js → CRFuOqJI.js} +1 -1
  32. package/build/client/_app/immutable/chunks/{gXyYVhfn.js → CZoElI5B.js} +1 -1
  33. package/build/client/_app/immutable/chunks/{dcghWWmq.js → CajOZJDl.js} +1 -1
  34. package/build/client/_app/immutable/chunks/{BImoJlJo.js → CdaJvl_A.js} +1 -1
  35. package/build/client/_app/immutable/chunks/{CNJYmM8n.js → CeLBjOd9.js} +1 -1
  36. package/build/client/_app/immutable/chunks/{IoX9lmZK.js → CevKuuic.js} +1 -1
  37. package/build/client/_app/immutable/chunks/{B_Gknb5_.js → Cf0aMC4n.js} +1 -1
  38. package/build/client/_app/immutable/chunks/{C_MwBDNt.js → CnxoqrkQ.js} +1 -1
  39. package/build/client/_app/immutable/chunks/{ChC4viXw.js → Cr2ck_ss.js} +1 -1
  40. package/build/client/_app/immutable/chunks/{fJBuRi-A.js → Czc4_W7v.js} +1 -1
  41. package/build/client/_app/immutable/chunks/{CHYEvS-6.js → Czey8tDK.js} +1 -1
  42. package/build/client/_app/immutable/chunks/D-jXFTzB.js +1 -0
  43. package/build/client/_app/immutable/chunks/{bpkmZ_Dv.js → D0ChUnpi.js} +1 -1
  44. package/build/client/_app/immutable/chunks/{B5S0Wke9.js → D0uxHECr.js} +1 -1
  45. package/build/client/_app/immutable/chunks/{2M1KS72j.js → D6KenyiF.js} +1 -1
  46. package/build/client/_app/immutable/chunks/{DT1b6JaK.js → DBKMIEwD.js} +1 -1
  47. package/build/client/_app/immutable/chunks/{Bq4mG8qS.js → DEVxi5CK.js} +1 -1
  48. package/build/client/_app/immutable/chunks/{Bh_Z0-Fh.js → DFBKiA2Z.js} +1 -1
  49. package/build/client/_app/immutable/chunks/{DSqRqQNp.js → DIxy2USu.js} +1 -1
  50. package/build/client/_app/immutable/chunks/{D4I0Dqwh.js → DJQr4efH.js} +1 -1
  51. package/build/client/_app/immutable/chunks/DQXo7qdJ.js +1 -0
  52. package/build/client/_app/immutable/chunks/{3E8jbhSl.js → DU8C5thd.js} +1 -1
  53. package/build/client/_app/immutable/chunks/{D7eKc9ur.js → DUCaFYlx.js} +1 -1
  54. package/build/client/_app/immutable/chunks/{CbtU_GW3.js → DdI16loP.js} +1 -1
  55. package/build/client/_app/immutable/chunks/{DykTZ90H.js → DdJNsJBH.js} +1 -1
  56. package/build/client/_app/immutable/chunks/{C6zqVyWx.js → DfUgh5E_.js} +1 -1
  57. package/build/client/_app/immutable/chunks/{Ch7rc-L7.js → DmRY6FWm.js} +4 -4
  58. package/build/client/_app/immutable/chunks/{D7XrPGMK.js → DuRZnRVw.js} +1 -1
  59. package/build/client/_app/immutable/chunks/{Do0VAo0_.js → DuiFyTVb.js} +1 -1
  60. package/build/client/_app/immutable/chunks/{Ck2086Sr.js → DwcY-69G.js} +1 -1
  61. package/build/client/_app/immutable/chunks/K3xyLTzZ.js +1 -0
  62. package/build/client/_app/immutable/chunks/{GMyoOYdi.js → NcOjFWr3.js} +1 -1
  63. package/build/client/_app/immutable/chunks/{BZ6uvzU8.js → O6xxeEm8.js} +1 -1
  64. package/build/client/_app/immutable/chunks/{DrVddB75.js → OW5Q7tGb.js} +1 -1
  65. package/build/client/_app/immutable/chunks/{CW2uYEvb.js → SN3Efo-Q.js} +1 -1
  66. package/build/client/_app/immutable/chunks/{DpSjzsDs.js → TTdBFs3C.js} +2 -2
  67. package/build/client/_app/immutable/chunks/{Bf1I5ROF.js → ap4GAVq-.js} +1 -1
  68. package/build/client/_app/immutable/chunks/{DWYSL4om.js → at6PQqQ4.js} +1 -1
  69. package/build/client/_app/immutable/chunks/cHj8EuyS.js +3 -0
  70. package/build/client/_app/immutable/chunks/{l3etNtOh.js → eFcFJ9Ld.js} +1 -1
  71. package/build/client/_app/immutable/chunks/{Bx68-tOf.js → kzciT-3i.js} +1 -1
  72. package/build/client/_app/immutable/chunks/{DNf96C-O.js → lF8CNVOA.js} +1 -1
  73. package/build/client/_app/immutable/chunks/o7DVZODA.js +1 -0
  74. package/build/client/_app/immutable/chunks/pdYhlwhf.js +1 -0
  75. package/build/client/_app/immutable/chunks/{q1Yj7q99.js → q5PRaRZk.js} +1 -1
  76. package/build/client/_app/immutable/chunks/{BKU5-8Td.js → zypfUZYM.js} +1 -1
  77. package/build/client/_app/immutable/entry/app.DIq2Q3OX.js +2 -0
  78. package/build/client/_app/immutable/entry/start.E6P3Z7tx.js +1 -0
  79. package/build/client/_app/immutable/nodes/0.Dm_ry-Pr.js +1 -0
  80. package/build/client/_app/immutable/nodes/1.DKIIO5Pq.js +1 -0
  81. package/build/client/_app/immutable/nodes/2.CpOJSq6u.js +340 -0
  82. package/build/client/_app/version.json +1 -1
  83. package/build/handler.js +6 -6
  84. package/build/index.js +6 -6
  85. package/build/server/chunks/chunks/{db.js-B8BUpxGM.js → db.js-DQm6CZ_r.js} +2 -2
  86. package/build/server/chunks/chunks/{db2.js-CNe3I_g2.js → db2.js-DUhFxA3a.js} +2 -2
  87. package/build/server/chunks/chunks/{dsh-connection.js-xltcocWy.js → dsh-connection.js-BgeraFA2.js} +2 -2
  88. package/build/server/chunks/chunks/{git-probe.js-CUsTmhmV.js → git-probe.js-Cn_ugqcH.js} +2 -2
  89. package/build/server/chunks/chunks/{index-server.js-CV2lq-ha.js → index-server.js-DmIEbDVz.js} +2 -2
  90. package/build/server/chunks/chunks/{insight-config.js-CaHHJpFK.js → insight-config.js-Dp_2gB5J.js} +5 -3
  91. package/build/server/chunks/chunks/{internal2.js-BtL7AFjQ.js → internal2.js-DFG0wDsP.js} +3 -3
  92. package/build/server/chunks/chunks/{registry.js-BTiJ1Kaj.js → registry.js-BC-TNdmn.js} +47 -8
  93. package/build/server/chunks/chunks/{server.js-DqHGsQU2.js → server.js-B1bDXhHu.js} +47 -2
  94. package/build/server/chunks/chunks/{state.js-D3ob-Gqa.js → state.js-Dki_Bq11.js} +4 -4
  95. package/build/server/chunks/chunks/{watcher.js-DcT3cS4v.js → watcher.js-f54CFvdI.js} +4 -4
  96. package/build/server/chunks/entries/endpoints/api/a2a/_id_/{_server.ts.js-19pFOjH8.js → _server.ts.js-BjzdVwdY.js} +3 -3
  97. package/build/server/chunks/entries/endpoints/api/a2a/{_server.ts.js-BcUn6axe.js → _server.ts.js-DN0zl7cz.js} +5 -5
  98. package/build/server/chunks/entries/endpoints/api/a2a/register/{_server.ts.js-oMpzLZoy.js → _server.ts.js-C3byr74D.js} +5 -5
  99. package/build/server/chunks/entries/endpoints/api/browser/_id_/close/{_server.ts.js-DC3qPMQS.js → _server.ts.js-BKChU9D7.js} +3 -3
  100. package/build/server/chunks/entries/endpoints/api/browser/_id_/input/{_server.ts.js-CHNcK7BH.js → _server.ts.js-CUFYX5kg.js} +3 -3
  101. package/build/server/chunks/entries/endpoints/api/browser/_id_/mcp/{_server.ts.js-CYkOJL2O.js → _server.ts.js-fg2eb_ZY.js} +3 -3
  102. package/build/server/chunks/entries/endpoints/api/browser/_id_/navigate/{_server.ts.js-DHTDi8KR.js → _server.ts.js-Dt1n31IP.js} +3 -3
  103. package/build/server/chunks/entries/endpoints/api/browser/_id_/page/{_server.ts.js-Y5khEC2l.js → _server.ts.js-DIF8juwJ.js} +3 -3
  104. package/build/server/chunks/entries/endpoints/api/browser/_id_/stream/{_server.ts.js-BmjgfZD2.js → _server.ts.js-BFdXJdhd.js} +3 -3
  105. package/build/server/chunks/entries/endpoints/api/browser/_id_/viewport/{_server.ts.js-IxS-goi1.js → _server.ts.js-BIF_7OHe.js} +3 -3
  106. package/build/server/chunks/entries/endpoints/api/browser/{_server.ts.js-6STmJ7FD.js → _server.ts.js-B7yjEF1N.js} +3 -3
  107. package/build/server/chunks/entries/endpoints/api/config/{_server.ts.js-BVyx8gPc.js → _server.ts.js-C8XDnDwe.js} +3 -3
  108. package/build/server/chunks/entries/endpoints/api/dsh/directory/{_server.ts.js-CNJbv6CC.js → _server.ts.js-BFmWshpv.js} +3 -3
  109. package/build/server/chunks/entries/endpoints/api/dsh/jobs/{_server.ts.js-CDWmXDJX.js → _server.ts.js-DATWy5mQ.js} +3 -3
  110. package/build/server/chunks/entries/endpoints/api/dsh/jobs/follow/{_server.ts.js-BDXQcQSL.js → _server.ts.js-CugOD1Zd.js} +3 -3
  111. package/build/server/chunks/entries/endpoints/api/dsh/pick-directory/{_server.ts.js-CgedtzOg.js → _server.ts.js-DCupM4da.js} +3 -3
  112. package/build/server/chunks/entries/endpoints/api/dsh/presets/{_server.ts.js-ut2pK15B.js → _server.ts.js-Bh1btvr9.js} +3 -3
  113. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/{_server.ts.js-Ct2W7g4c.js → _server.ts.js-Cb8SBWVw.js} +3 -3
  114. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/cancel/{_server.ts.js-Rke3V_qh.js → _server.ts.js-WI9yH2iG.js} +3 -3
  115. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/catalog/{_server.ts.js-BYHm5WBA.js → _server.ts.js-bN9adUqz.js} +3 -3
  116. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/changes/{_server.ts.js-B_bEUKkt.js → _server.ts.js-Bxlm966G.js} +3 -3
  117. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/command/{_server.ts.js-D78fGUQk.js → _server.ts.js-CM-raN_Q.js} +3 -3
  118. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/events/{_server.ts.js-CgB_c7zG.js → _server.ts.js-lBsxHSo6.js} +3 -3
  119. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/fork/{_server.ts.js-dVaW22_K.js → _server.ts.js-DvNkrTaY.js} +3 -3
  120. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/goal/{_server.ts.js-Dl8SBXdH.js → _server.ts.js-DXbCrefw.js} +3 -3
  121. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/history/{_server.ts.js-BKDiwMIE.js → _server.ts.js-BrEgFdCF.js} +3 -3
  122. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/models/{_server.ts.js-D3FY2Wxt.js → _server.ts.js-C_AEaLLJ.js} +3 -3
  123. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/path/{_server.ts.js-BWuIEdjl.js → _server.ts.js-Dj-pF5ik.js} +2 -2
  124. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/permission/{_server.ts.js-CeiQFOGP.js → _server.ts.js-BX9FWJ6g.js} +3 -3
  125. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/prompt/{_server.ts.js-lMofZOns.js → _server.ts.js-CQ2Bmtu4.js} +3 -3
  126. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/rename/{_server.ts.js-CNalVHrK.js → _server.ts.js-Ha7xjnKW.js} +3 -3
  127. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/respond/{_server.ts.js-I2s8qvcV.js → _server.ts.js-BOg6llHk.js} +3 -3
  128. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/select-model/{_server.ts.js-DTKELD7v.js → _server.ts.js-DBqGALzZ.js} +3 -3
  129. package/build/server/chunks/entries/endpoints/api/dsh/sessions/{_server.ts.js-BXSD__Gg.js → _server.ts.js-CvA8WDDb.js} +3 -3
  130. package/build/server/chunks/entries/endpoints/api/dsh/workspace-file/{_server.ts.js-C9IZl2Qh.js → _server.ts.js-BfjNH40j.js} +3 -3
  131. package/build/server/chunks/entries/endpoints/api/dsh/workspace-tree/{_server.ts.js-BRXu3UtL.js → _server.ts.js-De_qumyr.js} +3 -3
  132. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/{_server.ts.js-DmnpiaD2.js → _server.ts.js-tFpJJHCb.js} +3 -3
  133. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/delete/{_server.ts.js-C5qCdsdm.js → _server.ts.js-DVx5GGA_.js} +3 -3
  134. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/rename/{_server.ts.js-BVUn49yf.js → _server.ts.js-DuKT-aZp.js} +3 -3
  135. package/build/server/chunks/entries/endpoints/api/prompts/_id_/{_server.ts.js-DuCOsoF0.js → _server.ts.js-DsWFidFY.js} +3 -3
  136. package/build/server/chunks/entries/endpoints/api/prompts/{_server.ts.js-2mcRY7IP.js → _server.ts.js-C6j0adQs.js} +3 -3
  137. package/build/server/chunks/entries/endpoints/api/prompts/use/{_server.ts.js-DZjaHZxU.js → _server.ts.js-BChAg4hm.js} +3 -3
  138. package/build/server/chunks/entries/endpoints/api/settings/{_server.ts.js-DTVmsohJ.js → _server.ts.js-BPSHqbZN.js} +2 -2
  139. package/build/server/chunks/entries/endpoints/api/terminal/{_server.ts.js-DZXTArj7.js → _server.ts.js-D5CbUe5k.js} +2 -2
  140. package/build/server/chunks/entries/endpoints/api/workspace/file-write/{_server.ts.js-LSc5EKH7.js → _server.ts.js-BRhlbYEe.js} +4 -4
  141. package/build/server/chunks/entries/endpoints/api/workspace/git-events/{_server.ts.js-DNjiScBe.js → _server.ts.js-B9YI66ZL.js} +4 -4
  142. package/build/server/chunks/entries/endpoints/api/workspace/git-file-head/{_server.ts.js-CHMbLoSn.js → _server.ts.js-DSvXRZQL.js} +4 -4
  143. package/build/server/chunks/entries/endpoints/api/workspace/git-map/{_server.ts.js-BgM4JEAm.js → _server.ts.js-8A0skdlM.js} +4 -4
  144. package/build/server/chunks/entries/endpoints/api/workspace/git-status/{_server.ts.js-BH0cLS8o.js → _server.ts.js-Bc6J3t3m.js} +4 -4
  145. package/build/server/chunks/entries/endpoints/api/workspace/write-gate/{_server.ts.js-BzlV3cVT.js → _server.ts.js-CfL8Por5.js} +4 -4
  146. package/build/server/chunks/entries/pages/{_error.svelte.js-9cKDDMkE.js → _error.svelte.js-EnDLC3Jj.js} +5 -5
  147. package/build/server/chunks/entries/pages/{_page.server.ts.js-DttLUwdf.js → _page.server.ts.js-ar1DbW1v.js} +2 -2
  148. package/build/server/chunks/entries/pages/{_page.svelte.js-hjZYZCe1.js → _page.svelte.js-CQUo8VGL.js} +1028 -541
  149. package/build/server/chunks/{handler-B_azsHTz.js → handler-BBp0LoYK.js} +3 -3
  150. package/build/server/chunks/{index.js-3VY3QWe-.js → index.js-S4257Wcs.js} +4 -4
  151. package/build/server/chunks/{manifest.js-hHcXduh_.js → manifest.js-DajiWH1H.js} +55 -55
  152. package/build/server/chunks/nodes/{0.js-B_LVBEe8.js → 0.js-DtkNHIFx.js} +3 -3
  153. package/build/server/chunks/nodes/1.js-OAvYMTzU.js +9 -0
  154. package/build/server/chunks/nodes/{2.js-bVRsbAhW.js → 2.js-BORDEffk.js} +7 -7
  155. package/package.json +1 -1
  156. package/skills/dsi-kb-scenario/SKILL.md +67 -0
  157. package/template/.dsi/prompts.sqlite-shm +0 -0
  158. package/template/.dsi/prompts.sqlite-wal +0 -0
  159. package/template/.dsi/settings.yaml +8 -1
  160. package/build/client/_app/immutable/assets/0.c2dRYi3B.css +0 -2
  161. package/build/client/_app/immutable/assets/2.DBblYO_a.css +0 -1
  162. package/build/client/_app/immutable/chunks/BBDOLPkB.js +0 -1
  163. package/build/client/_app/immutable/chunks/BMgyB-Sy.js +0 -1
  164. package/build/client/_app/immutable/chunks/BYHxHjHc.js +0 -1
  165. package/build/client/_app/immutable/chunks/BwNsQhd8.js +0 -1
  166. package/build/client/_app/immutable/chunks/C0CuJuob.js +0 -1
  167. package/build/client/_app/immutable/chunks/CMByLjfJ.js +0 -1
  168. package/build/client/_app/immutable/chunks/DmLHHlla.js +0 -3
  169. package/build/client/_app/immutable/chunks/J_8-FdbR.js +0 -1
  170. package/build/client/_app/immutable/chunks/da2fibLv.js +0 -8
  171. package/build/client/_app/immutable/entry/app.GsYnI6xk.js +0 -2
  172. package/build/client/_app/immutable/entry/start.keNjq0dA.js +0 -1
  173. package/build/client/_app/immutable/nodes/0.BJVfjaPJ.js +0 -1
  174. package/build/client/_app/immutable/nodes/1.rhLd5ssJ.js +0 -1
  175. package/build/client/_app/immutable/nodes/2.DdzHBwFT.js +0 -340
  176. package/build/server/chunks/nodes/1.js-BRybp38b.js +0 -9
@@ -1,5 +1,6 @@
1
- import { a as __exportAll, o as onDestroy } from '../../chunks/index-server.js-CV2lq-ha.js';
2
- import { M as derived, V as head, X as bind_props, W as escape_html, Y as attr, Z as attr_style, _ as attr_class, a as setContext, $ as spread_props, a0 as attributes, a1 as clsx, a2 as ensure_array_like, a3 as element, g as getContext, a4 as stringify, a5 as html, r as run, a6 as props_id } from '../../chunks/server.js-DqHGsQU2.js';
1
+ import { a as __exportAll, o as onDestroy } from '../../chunks/index-server.js-DmIEbDVz.js';
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';
3
4
  import { U as UI_LOCALES } from '../../chunks/config.js-vThvQeMn.js';
4
5
  import { m as mergeEntries, c as collapseSystemPromptEntries, t as truncate } from '../../chunks/merge.js-yMwW440S.js';
5
6
  import { p as parseA2aSignature, m as mintA2aId, b as buildDeliveredText } from '../../chunks/a2a-protocol.js-C77mVg2Q.js';
@@ -8,7 +9,7 @@ import { D as DEFAULT_IMAGE_LIMITS } from '../../chunks/image-limits.js-CUdJ0f7r
8
9
  import { s as sanitizeWorkspaceProfile, d as dsiKey, t as themePrefs } from '../../chunks/theme-prefs.svelte.js-8CaWz46g.js';
9
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-BM4WbMFB.js';
10
11
  import { c as getLocale } from '../../chunks/runtime.js-CCJi3XaY.js';
11
- 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-D3ob-Gqa.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-Dki_Bq11.js';
12
13
  import 'yaml';
13
14
  import 'html-to-image';
14
15
  import hljs from 'highlight.js/lib/core';
@@ -20,8 +21,7 @@ import xml from 'highlight.js/lib/languages/xml';
20
21
  import css from 'highlight.js/lib/languages/css';
21
22
  import '../../chunks/uneval.js-BJ9Qq2SF.js';
22
23
  import '../../chunks/shared.js-HQ0rfhm4.js';
23
- import '../../chunks/internal2.js-BtL7AFjQ.js';
24
- import '../../chunks/exports.js-DH_tjtdv.js';
24
+ import '../../chunks/internal2.js-DFG0wDsP.js';
25
25
  import '../../chunks/utils.js-CAdNO8Tu.js';
26
26
 
27
27
  //#region src/lib/paraglide/messages/abort.js
@@ -952,6 +952,38 @@ var browserchiplabel2 = ((inputs = {}, options = {}) => {
952
952
  return en_browserchiplabel2();
953
953
  });
954
954
  //#endregion
955
+ //#region src/lib/paraglide/messages/browserclosedelete2.js
956
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
957
+ /** @typedef {{}} Browserclosedelete2Inputs */
958
+ var en_browserclosedelete2 = () => {
959
+ return `Delete the glass browser — kills the session and removes the panel`;
960
+ };
961
+ var zh_browserclosedelete2 = () => {
962
+ return `删除玻璃浏览器 — 终止会话并移除面板`;
963
+ };
964
+ var id_browserclosedelete2 = () => {
965
+ return `Hapus browser kaca — matikan sesi dan hapus panel`;
966
+ };
967
+ var es_browserclosedelete2 = () => {
968
+ return `Eliminar el navegador de vidrio — mata la sesión y quita el panel`;
969
+ };
970
+ /**
971
+ * | output |
972
+ * | --- |
973
+ * | "Delete the glass browser — kills the session and removes the panel" |
974
+ *
975
+ * @param {Browserclosedelete2Inputs} inputs
976
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
977
+ * @returns {LocalizedString}
978
+ */
979
+ var browserclosedelete2 = ((inputs = {}, options = {}) => {
980
+ const locale = options.locale ?? getLocale();
981
+ if (locale === "zh") return zh_browserclosedelete2();
982
+ if (locale === "id") return id_browserclosedelete2();
983
+ if (locale === "es") return es_browserclosedelete2();
984
+ return en_browserclosedelete2();
985
+ });
986
+ //#endregion
955
987
  //#region src/lib/paraglide/messages/browserforward1.js
956
988
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
957
989
  /** @typedef {{}} Browserforward1Inputs */
@@ -14840,6 +14872,7 @@ var _index_exports = /* @__PURE__ */ __exportAll({
14840
14872
  broadcastSyncedTo: () => broadcastsyncedto2,
14841
14873
  browserBack: () => browserback1,
14842
14874
  browserChipLabel: () => browserchiplabel2,
14875
+ browserCloseDelete: () => browserclosedelete2,
14843
14876
  browserForward: () => browserforward1,
14844
14877
  browserLaunching: () => browserlaunching1,
14845
14878
  browserOpenTitle: () => browseropentitle2,
@@ -15311,6 +15344,7 @@ var messages_exports = /* @__PURE__ */ __exportAll({
15311
15344
  broadcastSyncedTo: () => broadcastsyncedto2,
15312
15345
  browserBack: () => browserback1,
15313
15346
  browserChipLabel: () => browserchiplabel2,
15347
+ browserCloseDelete: () => browserclosedelete2,
15314
15348
  browserForward: () => browserforward1,
15315
15349
  browserLaunching: () => browserlaunching1,
15316
15350
  browserOpenTitle: () => browseropentitle2,
@@ -17155,19 +17189,23 @@ function SessionStatus($$renderer, $$props) {
17155
17189
  * plus the ×N badge), the replacement must be re-measured, never
17156
17190
  * assumed.
17157
17191
  */
17158
- let { running, delegated = false, count = 0 } = $$props;
17192
+ let { delegated = false, count = 0, browser = false } = $$props;
17159
17193
  /** Accessible name — four distinct states; the count rides along
17160
17194
  * (WCAG 1.4.1: never color alone). */
17161
- const label = derived(() => running ? delegated ? count > 0 ? `running and delegating, ${count} running` : "running and delegating" : "running" : delegated ? count > 0 ? `delegating, ${count} running` : "delegating" : "idle");
17195
+ const label = derived(() => browser ? "browser session, folded — click to open" : delegated ? count > 0 ? `running and delegating, ${count} running` : "running and delegating" : "running" );
17162
17196
  $$renderer.push(`<span data-svelte="SessionStatus"${attr_class("status svelte-x2ntn8", void 0, {
17163
- "run": running,
17164
- "idle": !running,
17197
+ "run": !browser,
17198
+ "idle": false,
17199
+ "browser": browser,
17165
17200
  "delegated": delegated
17166
17201
  })} role="img"${attr("aria-label", label())} data-testid="session-status">`);
17167
- if (running) {
17202
+ if (browser) {
17168
17203
  $$renderer.push("<!--[0-->");
17204
+ $$renderer.push(`<span class="frame svelte-x2ntn8" aria-hidden="true"></span>`);
17205
+ } else {
17206
+ $$renderer.push("<!--[1-->");
17169
17207
  $$renderer.push(`<span class="bar svelte-x2ntn8"></span><span class="bar svelte-x2ntn8"></span><span class="bar svelte-x2ntn8"></span>`);
17170
- } else $$renderer.push("<!--[-1-->");
17208
+ }
17171
17209
  $$renderer.push(`<!--]-->`);
17172
17210
  if (count > 0) {
17173
17211
  $$renderer.push("<!--[0-->");
@@ -17581,7 +17619,7 @@ function ThemeToggle($$renderer, $$props) {
17581
17619
  }
17582
17620
  //#endregion
17583
17621
  //#region package.json
17584
- var version = "0.8.0";
17622
+ var version = "0.8.2";
17585
17623
  var dsh = { "webVersion": "0.2.1-rc.2" };
17586
17624
  //#endregion
17587
17625
  //#region src/lib/version.ts
@@ -19029,12 +19067,34 @@ function SidebarSessions($$renderer, $$props) {
19029
19067
  * picker dialog). Blank never-prompted sessions hide by default
19030
19068
  * (toggle in the filter row).
19031
19069
  */
19032
- let { currentSessionId, filter, paneledSessionIds = [], onfilterchange } = $$props;
19070
+ let { currentSessionId, filter, paneledSessionIds = [], glassRows = [], onfilterchange } = $$props;
19033
19071
  /** The host workspace registry — the AUTHORITY for chips/pills here. */
19034
19072
  let workspaces = [];
19035
19073
  /** The full host preset catalog — the agent pills list it entirely. */
19036
19074
  let availablePresets = [];
19037
19075
  const ready = derived(() => []);
19076
+ /** Folded-glass synthetic rows (2026-10-22): shaped as session
19077
+ * summaries so the WHOLE spine pipeline (lineage, family nesting,
19078
+ * filters) treats them as the opener's children. origin 'browser'
19079
+ * marks the row for RowSessionItem's summon click; workspace and
19080
+ * title ride the opener so filters keep the family whole. */
19081
+ const glassSummaries = derived(() => {
19082
+ return glassRows.map((g) => {
19083
+ const opener = ready().find((s) => s.sessionId === g.openedBy);
19084
+ return {
19085
+ sessionId: g.sessionId,
19086
+ title: g.title || "Browser",
19087
+ agentPreset: null,
19088
+ running: true,
19089
+ blank: false,
19090
+ updatedAt: opener?.updatedAt ?? 0,
19091
+ workspace: opener?.workspace ?? null,
19092
+ turns: null,
19093
+ parentSessionId: g.openedBy,
19094
+ origin: "browser"
19095
+ };
19096
+ });
19097
+ });
19038
19098
  /** Current row — looked up from the RAW list (never filtered away). */
19039
19099
  const current = derived(() => ready().find((s) => s.sessionId === currentSessionId) ?? null);
19040
19100
  let spine = loadSpineGroupPrefs(null);
@@ -19044,8 +19104,8 @@ function SidebarSessions($$renderer, $$props) {
19044
19104
  * generalized from 1 to N). */
19045
19105
  const paneled = derived(() => new Set(paneledSessionIds));
19046
19106
  const others = derived(() => ready().filter((s) => s.sessionId !== currentSessionId && !paneled().has(s.sessionId)));
19047
- const lineage = derived(() => deriveLineage(ready(), []));
19048
- const unsuppressed = derived(() => suppressFromSpine(others(), lineage(), paneled()));
19107
+ const lineage = derived(() => deriveLineage([...ready(), ...glassSummaries()], []));
19108
+ const unsuppressed = derived(() => suppressFromSpine([...others(), ...glassSummaries()], lineage(), paneled()));
19049
19109
  const wsPills = derived(() => workspaceOptions(others(), workspaces));
19050
19110
  const presets = derived(() => presetOptions(availablePresets, others()));
19051
19111
  /** Self-healed filter — a persisted key no pill carries reads as All. */
@@ -19220,26 +19280,424 @@ function CanvasCopyButton($$renderer, $$props) {
19220
19280
  });
19221
19281
  }
19222
19282
  //#endregion
19283
+ //#region src/lib/utils/panel-prefs.ts
19284
+ /** localStorage base key — one JSON blob `{ panels, selectedPanelId, panelWidth, zoom }`.
19285
+ * A workspace profile (`?profile=…` on the URL) suffixes EVERY dsi-* key
19286
+ * (see storage-profile.ts): the default desk lives under `dsi-panels`,
19287
+ * profile `widi` under `dsi-panels_widi`. */
19288
+ var PANEL_PREFS_KEY = "dsi-panels";
19289
+ /**
19290
+ * The storage key for a workspace profile.
19291
+ * @param profile sanitized profile segment, or null/undefined for the
19292
+ * default desk (`dsi-panels`).
19293
+ */
19294
+ function panelPrefsKey(profile) {
19295
+ return dsiKey(PANEL_PREFS_KEY, profile);
19296
+ }
19297
+ var PANEL_WORKSPACE_FILE_MAX_WIDTH = 1436;
19298
+ /** The single treePct bound site — sanitize a stored or dragged value
19299
+ * into [TREE_PCT_MIN, TREE_PCT_MAX]; junk (non-finite) falls back to
19300
+ * TREE_PCT_DEFAULT. Mirrors clampPanelZoom's discipline. */
19301
+ function clampTreePct(pct) {
19302
+ if (typeof pct !== "number" || !Number.isFinite(pct)) return 30;
19303
+ return Math.max(15, Math.min(70, Math.round(pct)));
19304
+ }
19305
+ /**
19306
+ * The single panel-width bound site — load-side sanitizing, gutter drags,
19307
+ * and the width slider all route through here. Bounds read the config
19308
+ * store (layout load has landed them before any mount; defaults before).
19309
+ */
19310
+ function clampPanelWidth(width, kind) {
19311
+ const { minWidth, maxWidth } = appConfig().panel;
19312
+ if (kind === "workspace-explorer") return Math.max(520, Math.min(PANEL_WORKSPACE_FILE_MAX_WIDTH, width));
19313
+ if (kind === "workspace-file") return Math.max(520, Math.min(PANEL_WORKSPACE_FILE_MAX_WIDTH, width));
19314
+ return Math.max(minWidth, Math.min(maxWidth, width));
19315
+ }
19316
+ /** The single zoom bound site — load-side sanitizing and the zoom slider. */
19317
+ function clampPanelZoom(zoom) {
19318
+ const { minZoom, maxZoom } = appConfig().panel;
19319
+ return Math.max(minZoom, Math.min(maxZoom, zoom));
19320
+ }
19321
+ /** Config-driven default width (clamped through the single bound site). */
19322
+ function defaultPanelWidth() {
19323
+ return clampPanelWidth(appConfig().panel.defaultWidth);
19324
+ }
19325
+ /**
19326
+ * The skill shelf's born width (The Shelf Chrome ADR, D5): a name list,
19327
+ * not a five-column table — the shelf pins 480 (DEFAULT_PANEL_MIN_WIDTH)
19328
+ * instead of the 730 conversation default, clamped through the single
19329
+ * bound site.
19330
+ */
19331
+ function shelfPanelWidth() {
19332
+ return clampPanelWidth(480);
19333
+ }
19334
+ /**
19335
+ * Clamp a stored explorer `expanded` list to sane paths (Workspace
19336
+ * Explorer restore): non-string members drop and a repeated path keeps
19337
+ * its FIRST occurrence — the tree treats `expanded` as a set of
19338
+ * root-relative directories, and a duplicate would double-render a row.
19339
+ */
19340
+ function clampExpanded(value) {
19341
+ if (!Array.isArray(value)) return [];
19342
+ const seen = /* @__PURE__ */ new Set();
19343
+ const out = [];
19344
+ for (const member of value) {
19345
+ if (typeof member !== "string" || seen.has(member)) continue;
19346
+ seen.add(member);
19347
+ out.push(member);
19348
+ }
19349
+ return out;
19350
+ }
19351
+ /** The terminal desk's structure clamp (Terminal Desk ADR D3, Wave 3):
19352
+ * sanitize a stored desk mirror into { tabs, selectedTab } or undefined.
19353
+ * Junk drops FIELD-WISE — non-string sessionIds drop, empty/junk tabs
19354
+ * drop, selectedTab clamps into range — so a stale blob degrades to
19355
+ * "fewer rows remembered", never a phantom row. All tabs dropped (or
19356
+ * junk at the top) ⇒ undefined: the desk falls back to one fresh row. */
19357
+ function clampDeskMirror(value) {
19358
+ if (value === null || typeof value !== "object") return void 0;
19359
+ const raw = value;
19360
+ if (!Array.isArray(raw.tabs)) return void 0;
19361
+ const tabs = [];
19362
+ for (const tab of raw.tabs) {
19363
+ if (tab === null || typeof tab !== "object") continue;
19364
+ const ids = tab.sessionIds;
19365
+ if (!Array.isArray(ids)) continue;
19366
+ const sessionIds = ids.filter((id) => typeof id === "string" && id.length > 0);
19367
+ if (sessionIds.length === 0) continue;
19368
+ tabs.push({ sessionIds });
19369
+ }
19370
+ const jobs = [];
19371
+ if (Array.isArray(raw.jobs)) for (const j of raw.jobs) {
19372
+ if (j === null || typeof j !== "object") continue;
19373
+ const owner = j.owner;
19374
+ const jobId = j.jobId;
19375
+ if (typeof owner !== "string" || typeof jobId !== "string") continue;
19376
+ if (owner.length === 0 || jobId.length === 0) continue;
19377
+ jobs.push({
19378
+ owner,
19379
+ jobId
19380
+ });
19381
+ }
19382
+ if (tabs.length === 0 && jobs.length === 0) return void 0;
19383
+ const maxIndex = tabs.length + jobs.length;
19384
+ return {
19385
+ tabs,
19386
+ selectedTab: typeof raw.selectedTab === "number" && Number.isFinite(raw.selectedTab) ? Math.max(0, Math.min(maxIndex, Math.round(raw.selectedTab))) : 0,
19387
+ ...jobs.length > 0 ? { jobs } : {}
19388
+ };
19389
+ }
19390
+ /** Persisted defaults when nothing (usable) is stored. */
19391
+ function defaultPanelPrefs() {
19392
+ return {
19393
+ panels: [],
19394
+ selectedPanelId: null,
19395
+ panelWidth: defaultPanelWidth(),
19396
+ zoom: 1,
19397
+ treePct: 30
19398
+ };
19399
+ }
19400
+ /**
19401
+ * Hard shape check for a stored panel entry (the parse boundary).
19402
+ * KIND (2026-09-06, ADR D6): absent or 'conversation' is the legacy shape —
19403
+ * `sessionId` required; 'prompt-manager' carries no session fields;
19404
+ * 'injected-doc' (Loadinjected ADR D2) requires non-empty `sourceSessionId`
19405
+ * + `displayPath` — the dedupe key. Any other kind value is hard junk
19406
+ * (entry drops). `agentPreset` and `width`
19407
+ * may be absent (defaulted later); `agentPreset` when present must be
19408
+ * string|null, `width` when present must be a finite number. Unknown
19409
+ * extra keys are fine — they survive sanitizing.
19410
+ */
19411
+ function isPanelEntry(value) {
19412
+ if (value === null || typeof value !== "object") return false;
19413
+ const entry = value;
19414
+ if (typeof entry.id !== "string" || entry.id.length === 0) return false;
19415
+ if (entry.kind !== void 0 && entry.kind !== "conversation" && entry.kind !== "prompt-manager" && entry.kind !== "settings-editor" && entry.kind !== "injected-doc" && entry.kind !== "skill-shelf" && entry.kind !== "plugin-rack" && entry.kind !== "workspace-explorer" && entry.kind !== "workspace-file" && entry.kind !== "terminal") return false;
19416
+ if (entry.kind === "settings-editor" && entry.target !== "dsi" && entry.target !== "dsh") return false;
19417
+ if (entry.kind === "workspace-explorer") {
19418
+ if (entry.sessionId !== null && (typeof entry.sessionId !== "string" || entry.sessionId.length === 0)) return false;
19419
+ if (entry.sessionId === null && entry.home !== "dsi" && entry.home !== "dsh") return false;
19420
+ }
19421
+ if (entry.kind === "workspace-file") {
19422
+ if (typeof entry.sessionId !== "string" || entry.sessionId.length === 0) return false;
19423
+ }
19424
+ if (entry.kind === "workspace-explorer" && typeof entry.root !== "string") return false;
19425
+ if (entry.kind === "workspace-file") {
19426
+ if (typeof entry.path !== "string" || entry.path.length === 0) return false;
19427
+ }
19428
+ if (entry.kind === "injected-doc") {
19429
+ if (typeof entry.sourceSessionId !== "string" || entry.sourceSessionId.length === 0) return false;
19430
+ if (typeof entry.displayPath !== "string" || entry.displayPath.length === 0) return false;
19431
+ }
19432
+ if (entry.kind !== "prompt-manager" && entry.kind !== "settings-editor" && entry.kind !== "skill-shelf" && entry.kind !== "plugin-rack" && entry.kind !== "injected-doc" && entry.kind !== "workspace-explorer" && entry.kind !== "workspace-file" && entry.kind !== "terminal") {
19433
+ if (typeof entry.sessionId !== "string" || entry.sessionId.length === 0) return false;
19434
+ if (entry.agentPreset !== void 0 && typeof entry.agentPreset !== "string" && entry.agentPreset !== null) return false;
19435
+ }
19436
+ if (entry.width !== void 0 && (typeof entry.width !== "number" || !Number.isFinite(entry.width))) return false;
19437
+ return true;
19438
+ }
19439
+ /** Drop hard-junk entries; default missing keys; clamp widths. Unknown
19440
+ * keys on surviving entries pass through untouched.
19441
+ *
19442
+ * Duplicate ids (2026-08-24 crash fix): a corrupted blob carrying the
19443
+ * same panel-N twice would reach the keyed each in SidebarOpenPanels
19444
+ * and crash Svelte (each_key_duplicate) at render — the each's key is
19445
+ * the panel id. Duplicates drop to the FIRST occurrence (order is the
19446
+ * floor's left-to-right truth); a selectedPanelId left dangling by the
19447
+ * dedupe re-sanitizes to the first panel in loadPanelPrefs. */
19448
+ function sanitizePanels(raw) {
19449
+ if (!Array.isArray(raw)) return [];
19450
+ const seen = /* @__PURE__ */ new Set();
19451
+ return raw.filter((entry) => isPanelEntry(entry)).map((entry) => {
19452
+ const kindDefault = entry.kind === "skill-shelf" ? shelfPanelWidth() : entry.kind === "plugin-rack" ? shelfPanelWidth() : entry.kind === "workspace-explorer" ? 850 : entry.kind === "workspace-file" ? 850 : defaultPanelWidth();
19453
+ const width = clampPanelWidth(typeof entry.width === "number" && Number.isFinite(entry.width) ? entry.width : kindDefault, entry.kind);
19454
+ if (entry.kind === "prompt-manager") return {
19455
+ id: entry.id,
19456
+ kind: "prompt-manager",
19457
+ width
19458
+ };
19459
+ if (entry.kind === "terminal") {
19460
+ const desk = clampDeskMirror(entry.desk);
19461
+ return {
19462
+ id: entry.id,
19463
+ kind: "terminal",
19464
+ ...desk ? { desk } : {},
19465
+ width
19466
+ };
19467
+ }
19468
+ if (entry.kind === "settings-editor") return {
19469
+ id: entry.id,
19470
+ kind: "settings-editor",
19471
+ target: entry.target,
19472
+ width
19473
+ };
19474
+ if (entry.kind === "skill-shelf") {
19475
+ let reload = null;
19476
+ const r = entry.reload;
19477
+ if (r && r.phase === "loading" && typeof r.startedAt === "number") reload = {
19478
+ phase: "loading",
19479
+ startedAt: r.startedAt
19480
+ };
19481
+ else if (r && r.phase === "done" && typeof r.startedAt === "number" && typeof r.doneAt === "number" && r.doneAt > Date.now()) reload = {
19482
+ phase: "done",
19483
+ startedAt: r.startedAt,
19484
+ doneAt: r.doneAt
19485
+ };
19486
+ return {
19487
+ id: entry.id,
19488
+ kind: "skill-shelf",
19489
+ tab: entry.tab === "uninstall" ? "uninstall" : "install",
19490
+ collapsed: clampExpanded(entry.collapsed),
19491
+ searchQ: typeof entry.searchQ === "string" ? entry.searchQ : "",
19492
+ reload,
19493
+ width
19494
+ };
19495
+ }
19496
+ if (entry.kind === "plugin-rack") return {
19497
+ id: entry.id,
19498
+ kind: "plugin-rack",
19499
+ tab: entry.tab === "uninstall" ? "uninstall" : "install",
19500
+ width
19501
+ };
19502
+ if (entry.kind === "injected-doc") return {
19503
+ id: entry.id,
19504
+ kind: "injected-doc",
19505
+ sourceSessionId: entry.sourceSessionId,
19506
+ displayPath: entry.displayPath,
19507
+ width
19508
+ };
19509
+ if (entry.kind === "workspace-explorer") {
19510
+ const home = entry.home === "dsi" || entry.home === "dsh" ? entry.home : void 0;
19511
+ return {
19512
+ id: entry.id,
19513
+ kind: "workspace-explorer",
19514
+ sessionId: entry.sessionId ?? null,
19515
+ root: entry.root,
19516
+ ...typeof entry.title === "string" && entry.title.length > 0 ? { title: entry.title } : {},
19517
+ ...home !== void 0 ? { home } : {},
19518
+ expanded: clampExpanded(entry.expanded),
19519
+ tab: entry.tab === "changes" ? "changes" : "explorer",
19520
+ collapsedRepos: clampExpanded(entry.collapsedRepos),
19521
+ openTabs: clampExpanded(entry.openTabs),
19522
+ activeFile: typeof entry.activeFile === "string" ? entry.activeFile : null,
19523
+ width
19524
+ };
19525
+ }
19526
+ if (entry.kind === "workspace-file") return {
19527
+ id: entry.id,
19528
+ kind: "workspace-file",
19529
+ sessionId: entry.sessionId,
19530
+ path: entry.path,
19531
+ explorerPanelId: typeof entry.explorerPanelId === "string" && entry.explorerPanelId.length > 0 ? entry.explorerPanelId : null,
19532
+ view: entry.view === "diff" ? "diff" : "edit",
19533
+ width
19534
+ };
19535
+ return {
19536
+ ...entry,
19537
+ id: entry.id,
19538
+ kind: "conversation",
19539
+ sessionId: entry.sessionId,
19540
+ agentPreset: entry.agentPreset ?? null,
19541
+ width
19542
+ };
19543
+ }).filter((entry) => {
19544
+ if (seen.has(entry.id)) return false;
19545
+ seen.add(entry.id);
19546
+ return true;
19547
+ });
19548
+ }
19549
+ /**
19550
+ * Read the workspace state from localStorage.
19551
+ * @param profile sanitized workspace profile (null/omitted = default desk).
19552
+ * @returns stored state when parseable (sanitized), defaults when absent,
19553
+ * junk, or SSR. A `selectedPanelId` pointing at a missing panel
19554
+ * sanitizes to the first panel's id (null when no panels remain).
19555
+ */
19556
+ function loadPanelPrefs(profile) {
19557
+ if (typeof localStorage === "undefined") return defaultPanelPrefs();
19558
+ try {
19559
+ const raw = localStorage.getItem(panelPrefsKey(profile));
19560
+ if (!raw) return defaultPanelPrefs();
19561
+ const parsed = JSON.parse(raw);
19562
+ if (parsed === null || typeof parsed !== "object") return defaultPanelPrefs();
19563
+ if (!Array.isArray(parsed.panels)) return defaultPanelPrefs();
19564
+ const panels = sanitizePanels(parsed.panels);
19565
+ const panelWidth = typeof parsed.panelWidth === "number" && Number.isFinite(parsed.panelWidth) ? clampPanelWidth(parsed.panelWidth) : defaultPanelWidth();
19566
+ const zoom = typeof parsed.zoom === "number" && Number.isFinite(parsed.zoom) ? clampPanelZoom(parsed.zoom) : 1;
19567
+ const treePct = typeof parsed.treePct === "number" && Number.isFinite(parsed.treePct) ? clampTreePct(parsed.treePct) : 30;
19568
+ return {
19569
+ panels,
19570
+ selectedPanelId: typeof parsed.selectedPanelId === "string" && panels.some((panel) => panel.id === parsed.selectedPanelId) ? parsed.selectedPanelId : panels[0]?.id ?? null,
19571
+ panelWidth,
19572
+ zoom,
19573
+ treePct
19574
+ };
19575
+ } catch {
19576
+ return defaultPanelPrefs();
19577
+ }
19578
+ }
19579
+ //#endregion
19580
+ //#region src/lib/components/panels/control-bar/ControlBar.svelte
19581
+ function ControlBar($$renderer, $$props) {
19582
+ $$renderer.component(($$renderer) => {
19583
+ /**
19584
+ * ControlBar — the floor's hover tray (Panel Floor W5 task 5.1,
19585
+ * ADR-0006 R7; OCI ControlBar precedent, minus its orchestration
19586
+ * organs). Pinned top-right over the panels viewport; hovering the
19587
+ * gear trigger reveals the tray, leaving hides it after 250ms (the
19588
+ * timer clears on re-enter, so grazing the tray keeps it open).
19589
+ *
19590
+ * This file owns the trigger + the reveal/hide lifecycle; the tray
19591
+ * body — the floor controls + the action-button row — is
19592
+ * ControlBarTray:
19593
+ * - AddPanel — paste a sessionId → two verbs: Add appends a new
19594
+ * panel beside the focus, Rplc replaces the ACTIVE
19595
+ * panel in place (both registry actions)
19596
+ * - SliderWidth — uniform-width preset 480..860 (`onresizeall` sets
19597
+ * every panel + the preset LIVE per thumb move)
19598
+ * - SliderZoom — floor zoom 25%..125% step 5 ($bindable zoom)
19599
+ * - TrayButtons — the tray's button row (the floor canvas-capture:
19600
+ * `captureContainer` flows the page-owned floor
19601
+ * element down to its CanvasCopyButton)
19602
+ *
19603
+ * Deliberately ABSENT (ADR-0006 R7): RegisterFeature and a home link —
19604
+ * DSI has no orchestration backend for the former, and the sidebar
19605
+ * owns Home for the latter. The OCI tray ships both; this floor does not.
19606
+ *
19607
+ * Communication: AddPanel fires `addPanelFromSidebar` /
19608
+ * `replaceSelectedFromRegistry` through the panel registry — the
19609
+ * tray is a LEAF like a spine row, and the
19610
+ * registry is the only leaf→root action channel (commitment 2). Zoom
19611
+ * is a `$bindable` prop the route owns; every bound routes through
19612
+ * panel-prefs clamps (one clamp site, commitment 3). `onresizeall` is
19613
+ * a ControlBar-specific prop: the tray is a DIRECT child of the
19614
+ * workspace route (not a sidebar intermediate), so prop wiring here
19615
+ * breaks no commitment.
19616
+ */
19617
+ let { panelWidth = 730, zoom = 1, onresizeall, captureContainer = null } = $$props;
19618
+ let open = false;
19619
+ let $$settled = true;
19620
+ let $$inner_renderer;
19621
+ function $$render_inner($$renderer) {
19622
+ $$renderer.push(`<div data-svelte="ControlBar"${attr_class("controlbar svelte-vs008k", void 0, { "open": open })} role="toolbar"${attr("aria-label", t(floorcontrols1))} aria-orientation="vertical" tabindex="-1" data-testid="controlbar"${attr("data-open", open)}><button type="button" class="trigger svelte-vs008k" data-testid="controlbar-trigger"${attr("aria-label", t(floorcontrols1))}${attr("aria-expanded", open)}>`);
19623
+ Settings($$renderer, {
19624
+ size: 14,
19625
+ "aria-hidden": "true"
19626
+ });
19627
+ $$renderer.push(`<!----></button> `);
19628
+ $$renderer.push("<!--[-1-->");
19629
+ $$renderer.push(`<!--]--></div>`);
19630
+ }
19631
+ do {
19632
+ $$settled = true;
19633
+ $$inner_renderer = $$renderer.copy();
19634
+ $$render_inner($$inner_renderer);
19635
+ } while (!$$settled);
19636
+ $$renderer.subsume($$inner_renderer);
19637
+ bind_props($$props, {
19638
+ panelWidth,
19639
+ zoom
19640
+ });
19641
+ });
19642
+ }
19643
+ //#endregion
19223
19644
  //#region src/lib/components/common/layout/AppSidebarHeaderAction.svelte
19224
19645
  function AppSidebarHeaderAction($$renderer, $$props) {
19225
19646
  $$renderer.component(($$renderer) => {
19226
19647
  /**
19227
19648
  * AppSidebarHeaderAction — the expanded rail header's right-hand action
19228
19649
  * cluster (extracted from AppSidebar, 2026-09): add-workspace, locale
19229
- * switcher, canvas copy, and the collapse button.
19650
+ * switcher, canvas copy, and the collapse button. The floor ControlBar
19651
+ * (2026-10-22) rides the cluster's head — it self-positions fixed
19652
+ * top-right over the floor, so hosting it here is purely a mount-site
19653
+ * move; the page still owns panelWidth/zoom state and the resize-all
19654
+ * handler, threaded through the sidebar as $bindable props.
19230
19655
  */
19231
- let { captureContainer = null} = $$props;
19232
- $$renderer.push(`<div data-svelte="AppSidebarHeaderAction" class="rail-header-actions svelte-ijmtbh">`);
19233
- CanvasCopyButton($$renderer, {
19234
- container: captureContainer,
19235
- mode: "visible",
19236
- title: t(copypageimage2),
19237
- size: 14,
19238
- class: "inline-flex h-[22px] w-[22px] shrink-0 items-center justify-center rounded transition-colors hover:bg-surface-hover"
19656
+ let { captureContainer = null, trayContainer = null, panelWidth = 730, zoom = 1, onresizeall, onToggleCollapse } = $$props;
19657
+ let $$settled = true;
19658
+ let $$inner_renderer;
19659
+ function $$render_inner($$renderer) {
19660
+ $$renderer.push(`<div data-svelte="AppSidebarHeaderAction" class="rail-header-actions svelte-ijmtbh">`);
19661
+ CanvasCopyButton($$renderer, {
19662
+ container: captureContainer,
19663
+ mode: "visible",
19664
+ title: t(copypageimage2),
19665
+ size: 14,
19666
+ class: "inline-flex h-[22px] w-[22px] shrink-0 items-center justify-center rounded transition-colors hover:bg-surface-hover"
19667
+ });
19668
+ $$renderer.push(`<!----> <button type="button" class="icon-btn svelte-ijmtbh"${attr("aria-expanded", true)}${attr("aria-label", t(collapsesidebar1))}${attr("title", t(collapsesidebar1))}>`);
19669
+ Panel_left_close($$renderer, { size: 14 });
19670
+ $$renderer.push(`<!----></button> `);
19671
+ ControlBar($$renderer, {
19672
+ onresizeall: onresizeall ?? (() => {}),
19673
+ captureContainer: trayContainer,
19674
+ get panelWidth() {
19675
+ return panelWidth;
19676
+ },
19677
+ set panelWidth($$value) {
19678
+ panelWidth = $$value;
19679
+ $$settled = false;
19680
+ },
19681
+ get zoom() {
19682
+ return zoom;
19683
+ },
19684
+ set zoom($$value) {
19685
+ zoom = $$value;
19686
+ $$settled = false;
19687
+ }
19688
+ });
19689
+ $$renderer.push(`<!----></div>`);
19690
+ }
19691
+ do {
19692
+ $$settled = true;
19693
+ $$inner_renderer = $$renderer.copy();
19694
+ $$render_inner($$inner_renderer);
19695
+ } while (!$$settled);
19696
+ $$renderer.subsume($$inner_renderer);
19697
+ bind_props($$props, {
19698
+ panelWidth,
19699
+ zoom
19239
19700
  });
19240
- $$renderer.push(`<!----> <button type="button" class="icon-btn svelte-ijmtbh"${attr("aria-expanded", true)}${attr("aria-label", t(collapsesidebar1))}${attr("title", t(collapsesidebar1))}>`);
19241
- Panel_left_close($$renderer, { size: 14 });
19242
- $$renderer.push(`<!----></button></div>`);
19243
19701
  });
19244
19702
  }
19245
19703
  //#endregion
@@ -19283,29 +19741,63 @@ function RestartButton($$renderer, $$props) {
19283
19741
  //#endregion
19284
19742
  //#region src/lib/components/common/layout/AppSidebarHeader.svelte
19285
19743
  function AppSidebarHeader($$renderer, $$props) {
19286
- /**
19287
- * AppSidebarHeader — the expanded rail header (extracted from
19288
- * AppSidebar, 2026-09): the About prefix, the brand title, and the
19289
- * right-hand action cluster, composed from AboutButton,
19290
- * AppSidebarHeaderTitle, and AppSidebarHeaderAction. Owns the
19291
- * animated gradient surface for the expanded state (the collapsed
19292
- * stub keeps its copy in AppSidebar — Svelte styles are
19293
- * component-scoped, so the shared rule had to be split; keep the two
19294
- * gradients in sync).
19295
- *
19296
- * Presentational only — collapse flipping stays delegated upward.
19297
- */
19298
- let { captureContainer = null, onToggleCollapse } = $$props;
19299
- $$renderer.push(`<header data-svelte="AppSidebarHeader" class="rail-header svelte-184i93r">`);
19300
- RestartButton($$renderer, { class: "rail-collapsed-label" });
19301
- $$renderer.push(`<!----> `);
19302
- AboutButton($$renderer, {});
19303
- $$renderer.push(`<!----> `);
19304
- AppSidebarHeaderTitle($$renderer);
19305
- $$renderer.push(`<!----> `);
19306
- AppSidebarHeaderAction($$renderer, {
19307
- captureContainer});
19308
- $$renderer.push(`<!----></header>`);
19744
+ $$renderer.component(($$renderer) => {
19745
+ /**
19746
+ * AppSidebarHeader — the expanded rail header (extracted from
19747
+ * AppSidebar, 2026-09): the About prefix, the brand title, and the
19748
+ * right-hand action cluster, composed from AboutButton,
19749
+ * AppSidebarHeaderTitle, and AppSidebarHeaderAction. Owns the
19750
+ * animated gradient surface for the expanded state (the collapsed
19751
+ * stub keeps its copy in AppSidebar — Svelte styles are
19752
+ * component-scoped, so the shared rule had to be split; keep the two
19753
+ * gradients in sync).
19754
+ *
19755
+ * Presentational only — collapse flipping stays delegated upward.
19756
+ */
19757
+ let { captureContainer = null, trayContainer = null, panelWidth = 730, zoom = 1, onresizeall, onToggleCollapse } = $$props;
19758
+ let $$settled = true;
19759
+ let $$inner_renderer;
19760
+ function $$render_inner($$renderer) {
19761
+ $$renderer.push(`<header data-svelte="AppSidebarHeader" class="rail-header svelte-184i93r">`);
19762
+ RestartButton($$renderer, { class: "rail-collapsed-label" });
19763
+ $$renderer.push(`<!----> `);
19764
+ AboutButton($$renderer, {});
19765
+ $$renderer.push(`<!----> `);
19766
+ AppSidebarHeaderTitle($$renderer);
19767
+ $$renderer.push(`<!----> `);
19768
+ AppSidebarHeaderAction($$renderer, {
19769
+ captureContainer,
19770
+ trayContainer,
19771
+ onresizeall,
19772
+ onToggleCollapse,
19773
+ get panelWidth() {
19774
+ return panelWidth;
19775
+ },
19776
+ set panelWidth($$value) {
19777
+ panelWidth = $$value;
19778
+ $$settled = false;
19779
+ },
19780
+ get zoom() {
19781
+ return zoom;
19782
+ },
19783
+ set zoom($$value) {
19784
+ zoom = $$value;
19785
+ $$settled = false;
19786
+ }
19787
+ });
19788
+ $$renderer.push(`<!----></header>`);
19789
+ }
19790
+ do {
19791
+ $$settled = true;
19792
+ $$inner_renderer = $$renderer.copy();
19793
+ $$render_inner($$inner_renderer);
19794
+ } while (!$$settled);
19795
+ $$renderer.subsume($$inner_renderer);
19796
+ bind_props($$props, {
19797
+ panelWidth,
19798
+ zoom
19799
+ });
19800
+ });
19309
19801
  }
19310
19802
  //#endregion
19311
19803
  //#region src/lib/components/common/layout/AppSidebar.svelte
@@ -19341,52 +19833,118 @@ function AppSidebar($$renderer, $$props) {
19341
19833
  * page (OCI ownership split); the gutter just reports mousedown, and the
19342
19834
  * single width clamp lives in sidebar-prefs (clampSidebarWidth).
19343
19835
  */
19344
- let { profile = null, collapsed = false, width = 400, embedded = false, currentSessionId, paneledSessionIds = [], captureContainer = null, onToggleCollapse} = $$props;
19836
+ let { profile = null, collapsed = false, width = 400, embedded = false, currentSessionId, paneledSessionIds = [], captureContainer = null, trayContainer = null, glassRows = [], panelWidth = 730, zoom = 1, onresizeall, onToggleCollapse, onResizeStart } = $$props;
19345
19837
  let filter = loadSessionFilter(profile);
19346
- if (collapsed) {
19347
- $$renderer.push("<!--[0-->");
19348
- $$renderer.push(`<div data-svelte="AppSidebar" class="rail-collapsed svelte-113gpvg" data-testid="app-sidebar-collapsed">`);
19349
- RestartButton($$renderer, { class: "rail-collapsed-label" });
19350
- $$renderer.push(`<!----> `);
19351
- AboutButton($$renderer, { class: "rail-collapsed-label" });
19352
- $$renderer.push(`<!----> <button type="button" class="stub-expand svelte-113gpvg"${attr("aria-expanded", false)}${attr("aria-label", t(expandsidebar1))}${attr("title", t(expandsidebar1))}>`);
19353
- Panel_left_close($$renderer, {
19354
- size: 14,
19355
- class: "rotate-180"
19356
- });
19357
- $$renderer.push(`<!----> <span class="rail-collapsed-label svelte-113gpvg">Deepseek Insight</span></button></div>`);
19358
- } else if (embedded) {
19359
- $$renderer.push("<!--[1-->");
19360
- $$renderer.push(`<aside data-svelte="AppSidebar" class="rail rail-embedded svelte-113gpvg" data-testid="app-sidebar">`);
19361
- AppSidebarHeader($$renderer, {
19362
- captureContainer,
19363
- onToggleCollapse
19364
- });
19365
- $$renderer.push(`<!----> `);
19366
- SidebarSessions($$renderer, {
19367
- currentSessionId,
19368
- paneledSessionIds,
19369
- filter,
19370
- onfilterchange: (f) => filter = f
19371
- });
19372
- $$renderer.push(`<!----></aside>`);
19373
- } else {
19374
- $$renderer.push("<!--[-1-->");
19375
- $$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">`);
19376
- AppSidebarHeader($$renderer, {
19377
- captureContainer,
19378
- onToggleCollapse
19379
- });
19380
- $$renderer.push(`<!----> `);
19381
- SidebarSessions($$renderer, {
19382
- currentSessionId,
19383
- paneledSessionIds,
19384
- filter,
19385
- onfilterchange: (f) => filter = f
19386
- });
19387
- $$renderer.push(`<!----></aside> <div class="rail-gutter svelte-113gpvg" data-testid="sidebar-gutter" role="separator" aria-orientation="vertical"${attr("aria-label", t(resizesidebar1))}></div></div>`);
19838
+ let $$settled = true;
19839
+ let $$inner_renderer;
19840
+ function $$render_inner($$renderer) {
19841
+ if (collapsed) {
19842
+ $$renderer.push("<!--[0-->");
19843
+ $$renderer.push(`<div data-svelte="AppSidebar" class="rail-collapsed svelte-113gpvg" data-testid="app-sidebar-collapsed">`);
19844
+ ControlBar($$renderer, {
19845
+ onresizeall: onresizeall ?? (() => {}),
19846
+ captureContainer: trayContainer,
19847
+ get panelWidth() {
19848
+ return panelWidth;
19849
+ },
19850
+ set panelWidth($$value) {
19851
+ panelWidth = $$value;
19852
+ $$settled = false;
19853
+ },
19854
+ get zoom() {
19855
+ return zoom;
19856
+ },
19857
+ set zoom($$value) {
19858
+ zoom = $$value;
19859
+ $$settled = false;
19860
+ }
19861
+ });
19862
+ $$renderer.push(`<!----> `);
19863
+ RestartButton($$renderer, { class: "rail-collapsed-label" });
19864
+ $$renderer.push(`<!----> `);
19865
+ AboutButton($$renderer, { class: "rail-collapsed-label" });
19866
+ $$renderer.push(`<!----> <button type="button" class="stub-expand svelte-113gpvg"${attr("aria-expanded", false)}${attr("aria-label", t(expandsidebar1))}${attr("title", t(expandsidebar1))}>`);
19867
+ Panel_left_close($$renderer, {
19868
+ size: 14,
19869
+ class: "rotate-180"
19870
+ });
19871
+ $$renderer.push(`<!----> <span class="rail-collapsed-label svelte-113gpvg">Deepseek Insight</span></button></div>`);
19872
+ } else if (embedded) {
19873
+ $$renderer.push("<!--[1-->");
19874
+ $$renderer.push(`<aside data-svelte="AppSidebar" class="rail rail-embedded svelte-113gpvg" data-testid="app-sidebar">`);
19875
+ AppSidebarHeader($$renderer, {
19876
+ captureContainer,
19877
+ trayContainer,
19878
+ onresizeall,
19879
+ onToggleCollapse,
19880
+ get panelWidth() {
19881
+ return panelWidth;
19882
+ },
19883
+ set panelWidth($$value) {
19884
+ panelWidth = $$value;
19885
+ $$settled = false;
19886
+ },
19887
+ get zoom() {
19888
+ return zoom;
19889
+ },
19890
+ set zoom($$value) {
19891
+ zoom = $$value;
19892
+ $$settled = false;
19893
+ }
19894
+ });
19895
+ $$renderer.push(`<!----> `);
19896
+ SidebarSessions($$renderer, {
19897
+ currentSessionId,
19898
+ paneledSessionIds,
19899
+ filter,
19900
+ onfilterchange: (f) => filter = f
19901
+ });
19902
+ $$renderer.push(`<!----></aside>`);
19903
+ } else {
19904
+ $$renderer.push("<!--[-1-->");
19905
+ $$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">`);
19906
+ AppSidebarHeader($$renderer, {
19907
+ captureContainer,
19908
+ trayContainer,
19909
+ onresizeall,
19910
+ onToggleCollapse,
19911
+ get panelWidth() {
19912
+ return panelWidth;
19913
+ },
19914
+ set panelWidth($$value) {
19915
+ panelWidth = $$value;
19916
+ $$settled = false;
19917
+ },
19918
+ get zoom() {
19919
+ return zoom;
19920
+ },
19921
+ set zoom($$value) {
19922
+ zoom = $$value;
19923
+ $$settled = false;
19924
+ }
19925
+ });
19926
+ $$renderer.push(`<!----> `);
19927
+ SidebarSessions($$renderer, {
19928
+ currentSessionId,
19929
+ paneledSessionIds,
19930
+ filter,
19931
+ glassRows,
19932
+ onfilterchange: (f) => filter = f
19933
+ });
19934
+ $$renderer.push(`<!----></aside> <div class="rail-gutter svelte-113gpvg" data-testid="sidebar-gutter" role="separator" aria-orientation="vertical"${attr("aria-label", t(resizesidebar1))}></div></div>`);
19935
+ }
19936
+ $$renderer.push(`<!--]-->`);
19388
19937
  }
19389
- $$renderer.push(`<!--]-->`);
19938
+ do {
19939
+ $$settled = true;
19940
+ $$inner_renderer = $$renderer.copy();
19941
+ $$render_inner($$inner_renderer);
19942
+ } while (!$$settled);
19943
+ $$renderer.subsume($$inner_renderer);
19944
+ bind_props($$props, {
19945
+ panelWidth,
19946
+ zoom
19947
+ });
19390
19948
  });
19391
19949
  }
19392
19950
  //#endregion
@@ -22213,6 +22771,25 @@ function PromptManagerPanel($$renderer, $$props) {
22213
22771
  function sessionOf(p) {
22214
22772
  return p.kind === "conversation" ? p.sessionId : null;
22215
22773
  }
22774
+ /**
22775
+ * The end index of the contiguous injected-doc tail following the index
22776
+ * "end" whose documents belong to "sourceSessionId" (Loadinjected ADR
22777
+ * D3, consolidated 2026-09-07). DOCUMENTS ONLY — deliberately NOT the
22778
+ * workspace tail (2026-09-10 order fix): a session child pinned under
22779
+ * this parent lands directly below it (the Lineage Pin) and pushes the
22780
+ * explorer/file pair right, keeping the floor order identical to the
22781
+ * sidebar's familyRenderOrder. The workspace pair stays contiguous via
22782
+ * unitOf/explorerUnit — it does not displace pinned children.
22783
+ */
22784
+ function docTailEnd(panels, end, sourceSessionId) {
22785
+ let i = end;
22786
+ while (i + 1 < panels.length) {
22787
+ const p = panels[i + 1];
22788
+ if (p.kind !== "injected-doc" || p.sourceSessionId !== sourceSessionId) break;
22789
+ i++;
22790
+ }
22791
+ return i;
22792
+ }
22216
22793
  /** Does the file panel's edge name this explorer — directly, or through
22217
22794
  * the legacy null edge restored before the edge existed (then adjacency
22218
22795
  * plus the shared session IS the edge; the dedupe keeps one explorer per
@@ -22343,13 +22920,31 @@ function blockBounds(panels, idx, facts) {
22343
22920
  if (head !== void 0 && head.kind === "workspace-explorer" && fileBelongsTo(at, head)) return explorerUnit(panels, i - 1);
22344
22921
  return [idx, idx];
22345
22922
  }
22346
- if (at.kind !== "injected-doc") return [idx, idx];
22347
- let i = idx;
22348
- while (i > 0 && panels[i - 1].kind === "injected-doc") i--;
22349
- const head = panels[i - 1];
22350
- if (head === void 0 || head.kind !== "conversation") return [idx, idx];
22351
- if (head.sessionId !== at.sourceSessionId) return [idx, idx];
22352
- sessionId = head.sessionId;
22923
+ if (at.kind === "browser") {
22924
+ let i = idx;
22925
+ while (i > 0 && panels[i - 1].kind === "browser") i--;
22926
+ const head = panels[i - 1];
22927
+ const inFamily = (id, root) => {
22928
+ if (id === void 0) return false;
22929
+ let cur = id;
22930
+ for (let guard = 0; guard < panels.length + 1 && cur !== null; guard++) {
22931
+ if (cur === root) return true;
22932
+ cur = facts.parentOf.get(cur) ?? null;
22933
+ }
22934
+ return false;
22935
+ };
22936
+ if (head === void 0 || head.kind !== "conversation" || !inFamily(head.sessionId, at.openedBy)) return [idx, idx];
22937
+ sessionId = head.sessionId;
22938
+ }
22939
+ if (at.kind !== "injected-doc" && sessionId === null) return [idx, idx];
22940
+ if (at.kind === "injected-doc") {
22941
+ let i = idx;
22942
+ while (i > 0 && panels[i - 1].kind === "injected-doc") i--;
22943
+ const head = panels[i - 1];
22944
+ if (head === void 0 || head.kind !== "conversation") return [idx, idx];
22945
+ if (head.sessionId !== at.sourceSessionId) return [idx, idx];
22946
+ sessionId = head.sessionId;
22947
+ }
22353
22948
  }
22354
22949
  for (let guard = 0; guard < panels.length + 1; guard++) {
22355
22950
  const parent = facts.parentOf.get(sessionId) ?? null;
@@ -22392,6 +22987,10 @@ function unitOf(panels, sessionId, facts) {
22392
22987
  end = i;
22393
22988
  continue;
22394
22989
  }
22990
+ if (p.kind === "browser" && p.openedBy !== void 0 && familySessions.has(p.openedBy)) {
22991
+ end = i;
22992
+ continue;
22993
+ }
22395
22994
  break;
22396
22995
  }
22397
22996
  return [start, end];
@@ -22660,7 +23259,27 @@ function panelRowsFor(input) {
22660
23259
  const { panels, spineRows, coldCache, deadSessions, edgeCache, lineageFacts, moveFacts } = input;
22661
23260
  const openSessionIds = openSessionIdsOf(panels);
22662
23261
  return panels.map((p, index) => {
22663
- if (p.kind === "terminal" || p.kind === "browser" || p.kind === "prompt-manager" || p.kind === "settings-editor" || p.kind === "skill-shelf" || p.kind === "plugin-rack") return {
23262
+ if (p.kind === "browser") {
23263
+ const parentOpen = p.openedBy !== void 0 && openSessionIds.has(p.openedBy);
23264
+ const openerDepth = p.openedBy !== void 0 ? lineageFacts.depthById.get(p.openedBy) ?? 0 : 0;
23265
+ return {
23266
+ panel: p,
23267
+ title: "Browser",
23268
+ workspace: null,
23269
+ dead: false,
23270
+ running: false,
23271
+ depth: parentOpen ? openerDepth + 1 : 0,
23272
+ runningDescendants: 0,
23273
+ kind: "panel",
23274
+ parentSessionId: p.openedBy ?? null,
23275
+ fork: false,
23276
+ spawnerTitle: null,
23277
+ siblingIndex: -1,
23278
+ canMoveUp: false,
23279
+ canMoveDown: false
23280
+ };
23281
+ }
23282
+ if (p.kind === "terminal" || p.kind === "prompt-manager" || p.kind === "settings-editor" || p.kind === "skill-shelf" || p.kind === "plugin-rack") return {
22664
23283
  panel: p,
22665
23284
  title: p.kind === "terminal" ? "Terminal" : p.kind === "browser" ? "Browser" : p.kind === "prompt-manager" ? MANAGER_ROW_TITLE : p.kind === "skill-shelf" ? "Skill Shelf" : p.kind === "plugin-rack" ? "Plugin Rack" : p.kind === "settings-editor" ? SETTINGS_ROW_TITLE[p.target] : "",
22666
23285
  workspace: null,
@@ -22739,6 +23358,32 @@ function panelRowsFor(input) {
22739
23358
  function rowFactsByPanelId(rows) {
22740
23359
  return new Map(rows.map((r) => [r.panel.id, r]));
22741
23360
  }
23361
+ /**
23362
+ * The folded-glass ghost rows (ADR-0037 D4, extracted 2026-10-24 — the
23363
+ * Glass Close Ladder task 2.2): the ONE derivation the route renders.
23364
+ * Pure over the slot mirror — a removeBrowserSlot prune drops the ghost
23365
+ * (roster) and the spine nest in the same stroke (Ladder ADR D4).
23366
+ */
23367
+ function foldedGlassRowsFor(slots, depthOf, titleFor) {
23368
+ return slots.filter((s) => s.folded && s.sessionId && s.openedBy).map((s) => ({
23369
+ panel: {
23370
+ id: "glass-" + s.sessionId,
23371
+ kind: "conversation",
23372
+ sessionId: s.sessionId,
23373
+ agentPreset: null,
23374
+ width: 0
23375
+ },
23376
+ title: "Browser — " + (titleFor(s.openedBy) ?? s.openedBy),
23377
+ workspace: null,
23378
+ dead: false,
23379
+ running: true,
23380
+ depth: depthOf(s.openedBy) + 1,
23381
+ runningDescendants: 0,
23382
+ kind: "ghost",
23383
+ parentSessionId: s.openedBy,
23384
+ siblingIndex: -1
23385
+ }));
23386
+ }
22742
23387
  //#endregion
22743
23388
  //#region src/lib/components/prompt-manager/PromptsManagerDialogHeader.svelte
22744
23389
  function PromptsManagerDialogHeader($$renderer, $$props) {
@@ -26047,9 +26692,10 @@ function hasDotDotSegment(path) {
26047
26692
  function parseFileLinkHref(href) {
26048
26693
  const value = stripAngleWrapper(href.trim());
26049
26694
  const hash = value.indexOf("#");
26050
- const raw = hash === -1 ? value : value.slice(0, hash);
26695
+ const raw = hash === -1 ? splitColonAnchor(value).path : value.slice(0, hash);
26051
26696
  const anchor = hash === -1 ? "" : value.slice(hash + 1);
26052
26697
  let lines = null;
26698
+ if (hash === -1) lines = splitColonAnchor(value).lines;
26053
26699
  const single = anchor.match(/^L?(\d+)$/);
26054
26700
  const range = anchor.match(/^L?(\d+)-L?(\d+)$/);
26055
26701
  if (single) {
@@ -26074,6 +26720,48 @@ function parseFileLinkHref(href) {
26074
26720
  /** CommonMark angle-bracket destinations (<path> and their %3C/%3E
26075
26721
  * encodings) are destination syntax, never path bytes - renderers that
26076
26722
  * hand the wrapper through must not have it reach the host read. */
26723
+ /**
26724
+ * The colon anchor arm (ADR-0028 The Colon Anchor): IDE-style :line
26725
+ * suffixes — path/file.ts:334, :10-20 — are the SAME fact as #L anchors
26726
+ * in IDE clothes, so they split into the display hint the same way.
26727
+ * Digits-only tail after the LAST colon; a malformed tail (:0, :20-10)
26728
+ * degrades to no hint and KEEPS the colon in the path (never guesses,
26729
+ * hash-grammar posture); any other colon stays path bytes (a:b/c.ts).
26730
+ */
26731
+ function splitColonAnchor(value) {
26732
+ const colon = value.lastIndexOf(":");
26733
+ if (colon === -1) return {
26734
+ path: value,
26735
+ lines: null
26736
+ };
26737
+ const tail = value.slice(colon + 1);
26738
+ const single = tail.match(/^(\d+)$/);
26739
+ const range = tail.match(/^(\d+)-(\d+)$/);
26740
+ if (single) {
26741
+ const n = Number(single[1]);
26742
+ if (n >= 1) return {
26743
+ path: value.slice(0, colon),
26744
+ lines: {
26745
+ start: n,
26746
+ end: n
26747
+ }
26748
+ };
26749
+ } else if (range) {
26750
+ const s = Number(range[1]);
26751
+ const e = Number(range[2]);
26752
+ if (s >= 1 && e >= s) return {
26753
+ path: value.slice(0, colon),
26754
+ lines: {
26755
+ start: s,
26756
+ end: e
26757
+ }
26758
+ };
26759
+ }
26760
+ return {
26761
+ path: value,
26762
+ lines: null
26763
+ };
26764
+ }
26077
26765
  function stripAngleWrapper(value) {
26078
26766
  return value.replace(/^(?:%3C|<)/i, "").replace(/(?:%3E|>)$/i, "");
26079
26767
  }
@@ -26081,6 +26769,7 @@ function normalizeFileLinkPath(href) {
26081
26769
  let value = stripAngleWrapper(href.trim()).replace(/^\.\//, "").replace(/\/{2,}/g, "/");
26082
26770
  const hash = value.indexOf("#");
26083
26771
  if (hash !== -1) value = value.slice(0, hash);
26772
+ value = splitColonAnchor(value).path;
26084
26773
  if (value.startsWith("/")) value = value.slice(1);
26085
26774
  if (value === "" || hasDotDotSegment(value)) return null;
26086
26775
  return value;
@@ -27484,7 +28173,7 @@ function ReasoningSection($$renderer, $$props) {
27484
28173
  $$renderer.push(`<!--]--> <span class="text-[10px]">${escape_html(t(thinklabel1))}</span> `);
27485
28174
  if (streaming) {
27486
28175
  $$renderer.push("<!--[0-->");
27487
- SessionStatus($$renderer, { running: true });
28176
+ SessionStatus($$renderer, { });
27488
28177
  } else $$renderer.push("<!--[-1-->");
27489
28178
  $$renderer.push(`<!--]--></button></div>`);
27490
28179
  } else $$renderer.push("<!--[-1-->");
@@ -32155,18 +32844,6 @@ function TerminalDesk($$renderer, $$props) {
32155
32844
  bind_props($$props, { applyAction });
32156
32845
  });
32157
32846
  }
32158
- //#endregion
32159
- //#region src/lib/services/panels/browser-session-resolver.ts
32160
- /**
32161
- * browser-session-resolver — the ONE re-bind-or-open seam (The Sticky Glass
32162
- * spec Wave 2 task 2.1; ADR-0030 D1/D4). The chip, the floor placement, and
32163
- * the panel's remount all ask here; none of them POSTs /api/browser open
32164
- * directly. Policy: the persisted localStorage id wins if the registry still
32165
- * lists it live (RE-BIND — reload survival); a dead id falls through to a
32166
- * fresh open, never an error surface. The resolved id is persisted so the
32167
- * NEXT reload re-binds too.
32168
- */
32169
- var LS_KEY = "dsi.browser.sessionId";
32170
32847
  /** localStorage guarded — SSR and privacy modes have no window.localStorage. */
32171
32848
  function defaultStorage() {
32172
32849
  try {
@@ -32175,23 +32852,75 @@ function defaultStorage() {
32175
32852
  return null;
32176
32853
  }
32177
32854
  }
32178
- function readPersistedId(storage = defaultStorage()) {
32179
- try {
32180
- return storage?.getItem(LS_KEY) ?? null;
32181
- } catch {
32182
- return null;
32183
- }
32184
- }
32185
32855
  var IDX_KEY = "dsi.browser.panelIndex";
32186
- function readPersistedIndex(storage = defaultStorage()) {
32856
+ /** Read the persisted glass list; every legacy shape upgrades, junk
32857
+ * drops. Sorted by floor position (restore order = floor order). */
32858
+ function readBrowserSlots(storage = defaultStorage()) {
32187
32859
  try {
32188
32860
  const raw = storage?.getItem(IDX_KEY);
32189
- const n = raw === null || raw === void 0 ? NaN : Number(raw);
32190
- return Number.isInteger(n) && n >= 0 ? n : null;
32861
+ if (raw === null || raw === void 0) return [];
32862
+ const parsed = JSON.parse(raw);
32863
+ const list = Array.isArray(parsed) ? parsed : parsed !== null && typeof parsed === "object" && Array.isArray(parsed.slots) ? parsed.slots : [parsed];
32864
+ const out = [];
32865
+ for (const item of list) {
32866
+ if (typeof item === "number") {
32867
+ if (Number.isInteger(item) && item >= 0) out.push({ index: item });
32868
+ continue;
32869
+ }
32870
+ if (item === null || typeof item !== "object") continue;
32871
+ const o = item;
32872
+ if (!Number.isInteger(o.index) || o.index < 0) continue;
32873
+ const slot = { index: o.index };
32874
+ if (typeof o.width === "number" && Number.isFinite(o.width) && o.width > 0) slot.width = o.width;
32875
+ if (typeof o.openedBy === "string" && o.openedBy.length > 0) slot.openedBy = o.openedBy;
32876
+ if (typeof o.sessionId === "string" && o.sessionId.length > 0) slot.sessionId = o.sessionId;
32877
+ if (o.folded === true) slot.folded = true;
32878
+ out.push(slot);
32879
+ }
32880
+ return out.sort((a, b) => a.index - b.index);
32191
32881
  } catch {
32192
- return null;
32882
+ return [];
32193
32883
  }
32194
32884
  }
32885
+ /** Write the whole glass list; an empty list clears the key. Also
32886
+ * mirrors the written list into the reactive store — the sidebar's
32887
+ * folded-glass rows derive from it (ADR-0037 D4). */
32888
+ function persistBrowserSlots(slots, storage = defaultStorage()) {
32889
+ try {
32890
+ if (slots.length > 0) storage?.setItem(IDX_KEY, JSON.stringify(slots));
32891
+ else storage?.removeItem(IDX_KEY);
32892
+ } catch {}
32893
+ browserSlotStore.set([...slots]);
32894
+ }
32895
+ /** Reactive mirror of the persisted glass list (Svelte store — the
32896
+ * plain .ts module stays rune-free). Rows and the route derive the
32897
+ * folded set from it; persistBrowserSlots is the only writer. */
32898
+ var browserSlotStore = writable([]);
32899
+ /**
32900
+ * Drop the slot entry whose glass session died (The Glass Close Ladder
32901
+ * ADR 2026-10-24 D4): the live prune — a dead glass's entry is REMOVED,
32902
+ * never folded, so the roster ghost and the spine nest drop with it in
32903
+ * the same mirror stroke, no reload. Unknown id = quiet no-op (false).
32904
+ */
32905
+ function removeBrowserSlot(sessionId, storage = defaultStorage()) {
32906
+ const slots = readBrowserSlots(storage);
32907
+ const next = slots.filter((s) => s.sessionId !== sessionId);
32908
+ if (next.length === slots.length) return false;
32909
+ persistBrowserSlots(next, storage);
32910
+ return true;
32911
+ }
32912
+ /** Seed the mirror from storage (boot). */
32913
+ function primeBrowserSlotStore(storage = defaultStorage()) {
32914
+ browserSlotStore.set(readBrowserSlots(storage));
32915
+ }
32916
+ //#endregion
32917
+ //#region src/lib/components/browser/BrowserClosed.svelte
32918
+ function BrowserClosed($$renderer, $$props) {
32919
+ $$renderer.component(($$renderer) => {
32920
+ let { closing = false} = $$props;
32921
+ $$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>`);
32922
+ });
32923
+ }
32195
32924
  //#endregion
32196
32925
  //#region src/lib/components/browser/BrowserHeader.svelte
32197
32926
  function BrowserHeader($$renderer, $$props) {
@@ -32209,7 +32938,10 @@ function BrowserHeader($$renderer, $$props) {
32209
32938
  $$renderer.push("<!--[0-->");
32210
32939
  $$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>`);
32211
32940
  } else $$renderer.push("<!--[-1-->");
32212
- $$renderer.push(`<!--]--> <button class="rounded px-1 hover:bg-surface-active" data-testid="panel-close"${attr("disabled", closing, true)}>✕</button></span></div>`);
32941
+ $$renderer.push(`<!--]--> `);
32942
+ BrowserClosed($$renderer, {
32943
+ closing});
32944
+ $$renderer.push(`<!----></span></div>`);
32213
32945
  bind_props($$props, { clearInput });
32214
32946
  });
32215
32947
  }
@@ -32284,6 +33016,7 @@ function createMoveCoalescer(raf, fire) {
32284
33016
  //#region src/lib/components/browser/BrowserPanel.svelte
32285
33017
  function BrowserPanel($$renderer, $$props) {
32286
33018
  $$renderer.component(($$renderer) => {
33019
+ let { onclose, openedBy = void 0, parentTitle = null, depth = 0} = $$props;
32287
33020
  let sessionId = null;
32288
33021
  /** True when mount re-bound to a surviving session (ADR-0030 D1) —
32289
33022
  * surfaced in the status strip for the operator. */
@@ -32354,11 +33087,16 @@ function BrowserPanel($$renderer, $$props) {
32354
33087
  function goHistory(dir) {
32355
33088
  proxy();
32356
33089
  }
32357
- /** D8 owner-release: close the SERVER session first (kills the browser),
32358
- * then report upward so the floor removes the panel. Exactly once —
32359
- * the closing flag guards double-invocations (the single-close-post
32360
- * unit contract). */
32361
- async function closePanel() {}
33090
+ /** The FOLD (ADR-0037 D1): the header close button only reports
33091
+ * upward - the route's onclose is removePanel, the panel leaves the
33092
+ * floor, and the SERVER SESSION STAYS ALIVE (the reaper is the
33093
+ * bound; the slot entry keeps the re-bind facts). The old
33094
+ * owner-release kill (POST /close on this click, ADR-0029 D8) is
33095
+ * retired from this surface: kills belong to the reaper and
33096
+ * cascade close now. */
33097
+ function fold() {
33098
+ onclose?.();
33099
+ }
32362
33100
  onDestroy(() => {});
32363
33101
  let $$settled = true;
32364
33102
  let $$inner_renderer;
@@ -32372,12 +33110,22 @@ function BrowserPanel($$renderer, $$props) {
32372
33110
  busy: proxyBusy,
32373
33111
  canBack,
32374
33112
  canForward,
32375
- onclose: () => void closePanel(),
33113
+ onclose: () => fold(),
32376
33114
  onnavigate: submitUrl,
32377
33115
  onreload: () => void proxy(),
32378
33116
  onhistory: goHistory
32379
33117
  });
32380
33118
  $$renderer.push(`<!----> `);
33119
+ if (openedBy) {
33120
+ $$renderer.push("<!--[0-->");
33121
+ $$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> `);
33122
+ if (depth > 0) {
33123
+ $$renderer.push("<!--[0-->");
33124
+ $$renderer.push(`<span class="opacity-60">·d${escape_html(depth)}</span>`);
33125
+ } else $$renderer.push("<!--[-1-->");
33126
+ $$renderer.push(`<!--]--></div>`);
33127
+ } else $$renderer.push("<!--[-1-->");
33128
+ $$renderer.push(`<!--]--> `);
32381
33129
  BrowserContent($$renderer, {
32382
33130
  status,
32383
33131
  failReason,
@@ -32412,6 +33160,18 @@ function BrowserPanel($$renderer, $$props) {
32412
33160
  });
32413
33161
  }
32414
33162
  //#endregion
33163
+ //#region src/lib/components/browser/BrowserManager.svelte
33164
+ function BrowserManager($$renderer, $$props) {
33165
+ let { onclose, openedBy = void 0, parentTitle = null, depth = 0} = $$props;
33166
+ $$renderer.push(`<div data-svelte="BrowserManager" class="panel-manager-body svelte-1qpx9ce" data-testid="panel-browser-slot">`);
33167
+ BrowserPanel($$renderer, {
33168
+ onclose,
33169
+ openedBy,
33170
+ parentTitle,
33171
+ depth});
33172
+ $$renderer.push(`<!----></div>`);
33173
+ }
33174
+ //#endregion
32415
33175
  //#region src/lib/components/settings-skills/SettingsSkillsToolbar.svelte
32416
33176
  function SettingsSkillsToolbar($$renderer, $$props) {
32417
33177
  $$renderer.component(($$renderer) => {
@@ -32932,303 +33692,6 @@ function InjectedDocPanel($$renderer, $$props) {
32932
33692
  });
32933
33693
  }
32934
33694
  //#endregion
32935
- //#region src/lib/utils/panel-prefs.ts
32936
- /** localStorage base key — one JSON blob `{ panels, selectedPanelId, panelWidth, zoom }`.
32937
- * A workspace profile (`?profile=…` on the URL) suffixes EVERY dsi-* key
32938
- * (see storage-profile.ts): the default desk lives under `dsi-panels`,
32939
- * profile `widi` under `dsi-panels_widi`. */
32940
- var PANEL_PREFS_KEY = "dsi-panels";
32941
- /**
32942
- * The storage key for a workspace profile.
32943
- * @param profile sanitized profile segment, or null/undefined for the
32944
- * default desk (`dsi-panels`).
32945
- */
32946
- function panelPrefsKey(profile) {
32947
- return dsiKey(PANEL_PREFS_KEY, profile);
32948
- }
32949
- var PANEL_WORKSPACE_FILE_MAX_WIDTH = 1436;
32950
- /** The single treePct bound site — sanitize a stored or dragged value
32951
- * into [TREE_PCT_MIN, TREE_PCT_MAX]; junk (non-finite) falls back to
32952
- * TREE_PCT_DEFAULT. Mirrors clampPanelZoom's discipline. */
32953
- function clampTreePct(pct) {
32954
- if (typeof pct !== "number" || !Number.isFinite(pct)) return 30;
32955
- return Math.max(15, Math.min(70, Math.round(pct)));
32956
- }
32957
- /**
32958
- * The single panel-width bound site — load-side sanitizing, gutter drags,
32959
- * and the width slider all route through here. Bounds read the config
32960
- * store (layout load has landed them before any mount; defaults before).
32961
- */
32962
- function clampPanelWidth(width, kind) {
32963
- const { minWidth, maxWidth } = appConfig().panel;
32964
- if (kind === "workspace-explorer") return Math.max(520, Math.min(PANEL_WORKSPACE_FILE_MAX_WIDTH, width));
32965
- if (kind === "workspace-file") return Math.max(520, Math.min(PANEL_WORKSPACE_FILE_MAX_WIDTH, width));
32966
- return Math.max(minWidth, Math.min(maxWidth, width));
32967
- }
32968
- /** The single zoom bound site — load-side sanitizing and the zoom slider. */
32969
- function clampPanelZoom(zoom) {
32970
- const { minZoom, maxZoom } = appConfig().panel;
32971
- return Math.max(minZoom, Math.min(maxZoom, zoom));
32972
- }
32973
- /** Config-driven default width (clamped through the single bound site). */
32974
- function defaultPanelWidth() {
32975
- return clampPanelWidth(appConfig().panel.defaultWidth);
32976
- }
32977
- /**
32978
- * The skill shelf's born width (The Shelf Chrome ADR, D5): a name list,
32979
- * not a five-column table — the shelf pins 480 (DEFAULT_PANEL_MIN_WIDTH)
32980
- * instead of the 730 conversation default, clamped through the single
32981
- * bound site.
32982
- */
32983
- function shelfPanelWidth() {
32984
- return clampPanelWidth(480);
32985
- }
32986
- /**
32987
- * Clamp a stored explorer `expanded` list to sane paths (Workspace
32988
- * Explorer restore): non-string members drop and a repeated path keeps
32989
- * its FIRST occurrence — the tree treats `expanded` as a set of
32990
- * root-relative directories, and a duplicate would double-render a row.
32991
- */
32992
- function clampExpanded(value) {
32993
- if (!Array.isArray(value)) return [];
32994
- const seen = /* @__PURE__ */ new Set();
32995
- const out = [];
32996
- for (const member of value) {
32997
- if (typeof member !== "string" || seen.has(member)) continue;
32998
- seen.add(member);
32999
- out.push(member);
33000
- }
33001
- return out;
33002
- }
33003
- /** The terminal desk's structure clamp (Terminal Desk ADR D3, Wave 3):
33004
- * sanitize a stored desk mirror into { tabs, selectedTab } or undefined.
33005
- * Junk drops FIELD-WISE — non-string sessionIds drop, empty/junk tabs
33006
- * drop, selectedTab clamps into range — so a stale blob degrades to
33007
- * "fewer rows remembered", never a phantom row. All tabs dropped (or
33008
- * junk at the top) ⇒ undefined: the desk falls back to one fresh row. */
33009
- function clampDeskMirror(value) {
33010
- if (value === null || typeof value !== "object") return void 0;
33011
- const raw = value;
33012
- if (!Array.isArray(raw.tabs)) return void 0;
33013
- const tabs = [];
33014
- for (const tab of raw.tabs) {
33015
- if (tab === null || typeof tab !== "object") continue;
33016
- const ids = tab.sessionIds;
33017
- if (!Array.isArray(ids)) continue;
33018
- const sessionIds = ids.filter((id) => typeof id === "string" && id.length > 0);
33019
- if (sessionIds.length === 0) continue;
33020
- tabs.push({ sessionIds });
33021
- }
33022
- const jobs = [];
33023
- if (Array.isArray(raw.jobs)) for (const j of raw.jobs) {
33024
- if (j === null || typeof j !== "object") continue;
33025
- const owner = j.owner;
33026
- const jobId = j.jobId;
33027
- if (typeof owner !== "string" || typeof jobId !== "string") continue;
33028
- if (owner.length === 0 || jobId.length === 0) continue;
33029
- jobs.push({
33030
- owner,
33031
- jobId
33032
- });
33033
- }
33034
- if (tabs.length === 0 && jobs.length === 0) return void 0;
33035
- const maxIndex = tabs.length + jobs.length;
33036
- return {
33037
- tabs,
33038
- selectedTab: typeof raw.selectedTab === "number" && Number.isFinite(raw.selectedTab) ? Math.max(0, Math.min(maxIndex, Math.round(raw.selectedTab))) : 0,
33039
- ...jobs.length > 0 ? { jobs } : {}
33040
- };
33041
- }
33042
- /** Persisted defaults when nothing (usable) is stored. */
33043
- function defaultPanelPrefs() {
33044
- return {
33045
- panels: [],
33046
- selectedPanelId: null,
33047
- panelWidth: defaultPanelWidth(),
33048
- zoom: 1,
33049
- treePct: 30
33050
- };
33051
- }
33052
- /**
33053
- * Hard shape check for a stored panel entry (the parse boundary).
33054
- * KIND (2026-09-06, ADR D6): absent or 'conversation' is the legacy shape —
33055
- * `sessionId` required; 'prompt-manager' carries no session fields;
33056
- * 'injected-doc' (Loadinjected ADR D2) requires non-empty `sourceSessionId`
33057
- * + `displayPath` — the dedupe key. Any other kind value is hard junk
33058
- * (entry drops). `agentPreset` and `width`
33059
- * may be absent (defaulted later); `agentPreset` when present must be
33060
- * string|null, `width` when present must be a finite number. Unknown
33061
- * extra keys are fine — they survive sanitizing.
33062
- */
33063
- function isPanelEntry(value) {
33064
- if (value === null || typeof value !== "object") return false;
33065
- const entry = value;
33066
- if (typeof entry.id !== "string" || entry.id.length === 0) return false;
33067
- if (entry.kind !== void 0 && entry.kind !== "conversation" && entry.kind !== "prompt-manager" && entry.kind !== "settings-editor" && entry.kind !== "injected-doc" && entry.kind !== "skill-shelf" && entry.kind !== "plugin-rack" && entry.kind !== "workspace-explorer" && entry.kind !== "workspace-file" && entry.kind !== "terminal") return false;
33068
- if (entry.kind === "settings-editor" && entry.target !== "dsi" && entry.target !== "dsh") return false;
33069
- if (entry.kind === "workspace-explorer") {
33070
- if (entry.sessionId !== null && (typeof entry.sessionId !== "string" || entry.sessionId.length === 0)) return false;
33071
- if (entry.sessionId === null && entry.home !== "dsi" && entry.home !== "dsh") return false;
33072
- }
33073
- if (entry.kind === "workspace-file") {
33074
- if (typeof entry.sessionId !== "string" || entry.sessionId.length === 0) return false;
33075
- }
33076
- if (entry.kind === "workspace-explorer" && typeof entry.root !== "string") return false;
33077
- if (entry.kind === "workspace-file") {
33078
- if (typeof entry.path !== "string" || entry.path.length === 0) return false;
33079
- }
33080
- if (entry.kind === "injected-doc") {
33081
- if (typeof entry.sourceSessionId !== "string" || entry.sourceSessionId.length === 0) return false;
33082
- if (typeof entry.displayPath !== "string" || entry.displayPath.length === 0) return false;
33083
- }
33084
- if (entry.kind !== "prompt-manager" && entry.kind !== "settings-editor" && entry.kind !== "skill-shelf" && entry.kind !== "plugin-rack" && entry.kind !== "injected-doc" && entry.kind !== "workspace-explorer" && entry.kind !== "workspace-file" && entry.kind !== "terminal") {
33085
- if (typeof entry.sessionId !== "string" || entry.sessionId.length === 0) return false;
33086
- if (entry.agentPreset !== void 0 && typeof entry.agentPreset !== "string" && entry.agentPreset !== null) return false;
33087
- }
33088
- if (entry.width !== void 0 && (typeof entry.width !== "number" || !Number.isFinite(entry.width))) return false;
33089
- return true;
33090
- }
33091
- /** Drop hard-junk entries; default missing keys; clamp widths. Unknown
33092
- * keys on surviving entries pass through untouched.
33093
- *
33094
- * Duplicate ids (2026-08-24 crash fix): a corrupted blob carrying the
33095
- * same panel-N twice would reach the keyed each in SidebarOpenPanels
33096
- * and crash Svelte (each_key_duplicate) at render — the each's key is
33097
- * the panel id. Duplicates drop to the FIRST occurrence (order is the
33098
- * floor's left-to-right truth); a selectedPanelId left dangling by the
33099
- * dedupe re-sanitizes to the first panel in loadPanelPrefs. */
33100
- function sanitizePanels(raw) {
33101
- if (!Array.isArray(raw)) return [];
33102
- const seen = /* @__PURE__ */ new Set();
33103
- return raw.filter((entry) => isPanelEntry(entry)).map((entry) => {
33104
- const kindDefault = entry.kind === "skill-shelf" ? shelfPanelWidth() : entry.kind === "plugin-rack" ? shelfPanelWidth() : entry.kind === "workspace-explorer" ? 850 : entry.kind === "workspace-file" ? 850 : defaultPanelWidth();
33105
- const width = clampPanelWidth(typeof entry.width === "number" && Number.isFinite(entry.width) ? entry.width : kindDefault, entry.kind);
33106
- if (entry.kind === "prompt-manager") return {
33107
- id: entry.id,
33108
- kind: "prompt-manager",
33109
- width
33110
- };
33111
- if (entry.kind === "terminal") {
33112
- const desk = clampDeskMirror(entry.desk);
33113
- return {
33114
- id: entry.id,
33115
- kind: "terminal",
33116
- ...desk ? { desk } : {},
33117
- width
33118
- };
33119
- }
33120
- if (entry.kind === "settings-editor") return {
33121
- id: entry.id,
33122
- kind: "settings-editor",
33123
- target: entry.target,
33124
- width
33125
- };
33126
- if (entry.kind === "skill-shelf") {
33127
- let reload = null;
33128
- const r = entry.reload;
33129
- if (r && r.phase === "loading" && typeof r.startedAt === "number") reload = {
33130
- phase: "loading",
33131
- startedAt: r.startedAt
33132
- };
33133
- else if (r && r.phase === "done" && typeof r.startedAt === "number" && typeof r.doneAt === "number" && r.doneAt > Date.now()) reload = {
33134
- phase: "done",
33135
- startedAt: r.startedAt,
33136
- doneAt: r.doneAt
33137
- };
33138
- return {
33139
- id: entry.id,
33140
- kind: "skill-shelf",
33141
- tab: entry.tab === "uninstall" ? "uninstall" : "install",
33142
- collapsed: clampExpanded(entry.collapsed),
33143
- searchQ: typeof entry.searchQ === "string" ? entry.searchQ : "",
33144
- reload,
33145
- width
33146
- };
33147
- }
33148
- if (entry.kind === "plugin-rack") return {
33149
- id: entry.id,
33150
- kind: "plugin-rack",
33151
- tab: entry.tab === "uninstall" ? "uninstall" : "install",
33152
- width
33153
- };
33154
- if (entry.kind === "injected-doc") return {
33155
- id: entry.id,
33156
- kind: "injected-doc",
33157
- sourceSessionId: entry.sourceSessionId,
33158
- displayPath: entry.displayPath,
33159
- width
33160
- };
33161
- if (entry.kind === "workspace-explorer") {
33162
- const home = entry.home === "dsi" || entry.home === "dsh" ? entry.home : void 0;
33163
- return {
33164
- id: entry.id,
33165
- kind: "workspace-explorer",
33166
- sessionId: entry.sessionId ?? null,
33167
- root: entry.root,
33168
- ...typeof entry.title === "string" && entry.title.length > 0 ? { title: entry.title } : {},
33169
- ...home !== void 0 ? { home } : {},
33170
- expanded: clampExpanded(entry.expanded),
33171
- tab: entry.tab === "changes" ? "changes" : "explorer",
33172
- collapsedRepos: clampExpanded(entry.collapsedRepos),
33173
- openTabs: clampExpanded(entry.openTabs),
33174
- activeFile: typeof entry.activeFile === "string" ? entry.activeFile : null,
33175
- width
33176
- };
33177
- }
33178
- if (entry.kind === "workspace-file") return {
33179
- id: entry.id,
33180
- kind: "workspace-file",
33181
- sessionId: entry.sessionId,
33182
- path: entry.path,
33183
- explorerPanelId: typeof entry.explorerPanelId === "string" && entry.explorerPanelId.length > 0 ? entry.explorerPanelId : null,
33184
- view: entry.view === "diff" ? "diff" : "edit",
33185
- width
33186
- };
33187
- return {
33188
- ...entry,
33189
- id: entry.id,
33190
- kind: "conversation",
33191
- sessionId: entry.sessionId,
33192
- agentPreset: entry.agentPreset ?? null,
33193
- width
33194
- };
33195
- }).filter((entry) => {
33196
- if (seen.has(entry.id)) return false;
33197
- seen.add(entry.id);
33198
- return true;
33199
- });
33200
- }
33201
- /**
33202
- * Read the workspace state from localStorage.
33203
- * @param profile sanitized workspace profile (null/omitted = default desk).
33204
- * @returns stored state when parseable (sanitized), defaults when absent,
33205
- * junk, or SSR. A `selectedPanelId` pointing at a missing panel
33206
- * sanitizes to the first panel's id (null when no panels remain).
33207
- */
33208
- function loadPanelPrefs(profile) {
33209
- if (typeof localStorage === "undefined") return defaultPanelPrefs();
33210
- try {
33211
- const raw = localStorage.getItem(panelPrefsKey(profile));
33212
- if (!raw) return defaultPanelPrefs();
33213
- const parsed = JSON.parse(raw);
33214
- if (parsed === null || typeof parsed !== "object") return defaultPanelPrefs();
33215
- if (!Array.isArray(parsed.panels)) return defaultPanelPrefs();
33216
- const panels = sanitizePanels(parsed.panels);
33217
- const panelWidth = typeof parsed.panelWidth === "number" && Number.isFinite(parsed.panelWidth) ? clampPanelWidth(parsed.panelWidth) : defaultPanelWidth();
33218
- const zoom = typeof parsed.zoom === "number" && Number.isFinite(parsed.zoom) ? clampPanelZoom(parsed.zoom) : 1;
33219
- const treePct = typeof parsed.treePct === "number" && Number.isFinite(parsed.treePct) ? clampTreePct(parsed.treePct) : 30;
33220
- return {
33221
- panels,
33222
- selectedPanelId: typeof parsed.selectedPanelId === "string" && panels.some((panel) => panel.id === parsed.selectedPanelId) ? parsed.selectedPanelId : panels[0]?.id ?? null,
33223
- panelWidth,
33224
- zoom,
33225
- treePct
33226
- };
33227
- } catch {
33228
- return defaultPanelPrefs();
33229
- }
33230
- }
33231
- //#endregion
33232
33695
  //#region src/lib/components/workspace-explorer/WorkspaceExplorerButtons.svelte
33233
33696
  function WorkspaceExplorerButtons($$renderer, $$props) {
33234
33697
  $$renderer.component(($$renderer) => {
@@ -34134,6 +34597,19 @@ function PanelsZoom($$renderer, $$props) {
34134
34597
  });
34135
34598
  }
34136
34599
  //#endregion
34600
+ //#region src/lib/components/panels/PanelClose.svelte
34601
+ function PanelClose($$renderer, $$props) {
34602
+ $$renderer.component(($$renderer) => {
34603
+ let { sessionId, lens = false} = $$props;
34604
+ $$renderer.push(`<button data-svelte="PanelClose" type="button" class="hdr-btn"${attr("disabled", lens, true)} data-testid="panel-close"${attr("aria-label", t(() => closepanelnamed2({ id: sessionId })))}${attr("title", t(closepanelhint2))}>`);
34605
+ X($$renderer, {
34606
+ size: 12,
34607
+ "aria-hidden": "true"
34608
+ });
34609
+ $$renderer.push(`<!----></button>`);
34610
+ });
34611
+ }
34612
+ //#endregion
34137
34613
  //#region src/lib/components/panels/PanelHeader.svelte
34138
34614
  function PanelHeader($$renderer, $$props) {
34139
34615
  $$renderer.component(($$renderer) => {
@@ -34183,12 +34659,9 @@ function PanelHeader($$renderer, $$props) {
34183
34659
  $$renderer.push(`<!--]--> `);
34184
34660
  if (onremove || lens) {
34185
34661
  $$renderer.push("<!--[0-->");
34186
- $$renderer.push(`<button type="button" class="hdr-btn svelte-1xanvl9"${attr("disabled", lens, true)} data-testid="panel-close"${attr("aria-label", t(() => closepanelnamed2({ id: sessionId })))}${attr("title", t(closepanelhint2))}>`);
34187
- X($$renderer, {
34188
- size: 12,
34189
- "aria-hidden": "true"
34190
- });
34191
- $$renderer.push(`<!----></button>`);
34662
+ PanelClose($$renderer, {
34663
+ sessionId,
34664
+ lens});
34192
34665
  } else $$renderer.push("<!--[-1-->");
34193
34666
  $$renderer.push(`<!--]--></span></div>`);
34194
34667
  });
@@ -34329,70 +34802,6 @@ function EmptyFloor($$renderer, $$props) {
34329
34802
  });
34330
34803
  }
34331
34804
  //#endregion
34332
- //#region src/lib/components/panels/control-bar/ControlBar.svelte
34333
- function ControlBar($$renderer, $$props) {
34334
- $$renderer.component(($$renderer) => {
34335
- /**
34336
- * ControlBar — the floor's hover tray (Panel Floor W5 task 5.1,
34337
- * ADR-0006 R7; OCI ControlBar precedent, minus its orchestration
34338
- * organs). Pinned top-right over the panels viewport; hovering the
34339
- * gear trigger reveals the tray, leaving hides it after 250ms (the
34340
- * timer clears on re-enter, so grazing the tray keeps it open).
34341
- *
34342
- * This file owns the trigger + the reveal/hide lifecycle; the tray
34343
- * body — the floor controls + the action-button row — is
34344
- * ControlBarTray:
34345
- * - AddPanel — paste a sessionId → two verbs: Add appends a new
34346
- * panel beside the focus, Rplc replaces the ACTIVE
34347
- * panel in place (both registry actions)
34348
- * - SliderWidth — uniform-width preset 480..860 (`onresizeall` sets
34349
- * every panel + the preset LIVE per thumb move)
34350
- * - SliderZoom — floor zoom 25%..125% step 5 ($bindable zoom)
34351
- * - TrayButtons — the tray's button row (the floor canvas-capture:
34352
- * `captureContainer` flows the page-owned floor
34353
- * element down to its CanvasCopyButton)
34354
- *
34355
- * Deliberately ABSENT (ADR-0006 R7): RegisterFeature and a home link —
34356
- * DSI has no orchestration backend for the former, and the sidebar
34357
- * owns Home for the latter. The OCI tray ships both; this floor does not.
34358
- *
34359
- * Communication: AddPanel fires `addPanelFromSidebar` /
34360
- * `replaceSelectedFromRegistry` through the panel registry — the
34361
- * tray is a LEAF like a spine row, and the
34362
- * registry is the only leaf→root action channel (commitment 2). Zoom
34363
- * is a `$bindable` prop the route owns; every bound routes through
34364
- * panel-prefs clamps (one clamp site, commitment 3). `onresizeall` is
34365
- * a ControlBar-specific prop: the tray is a DIRECT child of the
34366
- * workspace route (not a sidebar intermediate), so prop wiring here
34367
- * breaks no commitment.
34368
- */
34369
- let { panelWidth = 730, zoom = 1, onresizeall, captureContainer = null } = $$props;
34370
- let open = false;
34371
- let $$settled = true;
34372
- let $$inner_renderer;
34373
- function $$render_inner($$renderer) {
34374
- $$renderer.push(`<div data-svelte="ControlBar"${attr_class("controlbar svelte-vs008k", void 0, { "open": open })} role="toolbar"${attr("aria-label", t(floorcontrols1))} aria-orientation="vertical" tabindex="-1" data-testid="controlbar"${attr("data-open", open)}><button type="button" class="trigger svelte-vs008k" data-testid="controlbar-trigger"${attr("aria-label", t(floorcontrols1))}${attr("aria-expanded", open)}>`);
34375
- Settings($$renderer, {
34376
- size: 14,
34377
- "aria-hidden": "true"
34378
- });
34379
- $$renderer.push(`<!----></button> `);
34380
- $$renderer.push("<!--[-1-->");
34381
- $$renderer.push(`<!--]--></div>`);
34382
- }
34383
- do {
34384
- $$settled = true;
34385
- $$inner_renderer = $$renderer.copy();
34386
- $$render_inner($$inner_renderer);
34387
- } while (!$$settled);
34388
- $$renderer.subsume($$inner_renderer);
34389
- bind_props($$props, {
34390
- panelWidth,
34391
- zoom
34392
- });
34393
- });
34394
- }
34395
- //#endregion
34396
34805
  //#region src/lib/utils/sidebar-prefs.ts
34397
34806
  /**
34398
34807
  * Sidebar preferences — persisted layout state for the conversation page's
@@ -34575,6 +34984,18 @@ function workspaceExplorerSlot(panels, selectedIndex, facts) {
34575
34984
  return focusedInsertionSlot(panels, selectedIndex, facts.parentOf);
34576
34985
  }
34577
34986
  /**
34987
+ * The glass FIRST slot under its opener (operator ruling 2026-10-24):
34988
+ * a summoned/spawned glass lands DIRECTLY below its opener - past the
34989
+ * opener document tail, BEFORE every adopted child - matching the
34990
+ * spine tree wire order -1 (the ghost always reads as the first
34991
+ * child). Supersedes the region-end placement for the glass only.
34992
+ */
34993
+ function glassFirstSlot(panels, openedBy) {
34994
+ const openerIdx = panels.findIndex((p) => p.kind === "conversation" && p.sessionId === openedBy);
34995
+ if (openerIdx === -1) return panels.length;
34996
+ return docTailEnd(panels, openerIdx, openedBy) + 1;
34997
+ }
34998
+ /**
34578
34999
  * Insert-before-focused slot (operator spec, 2026-08-31): a fresh panel
34579
35000
  * lands at the FOCUSED panel's index — immediately before it — and takes
34580
35001
  * focus (the route selects it). 0 when nothing is focused (empty floor,
@@ -34602,7 +35023,7 @@ function focusedInsertionSlot(panels, selectedIndex, parentOf) {
34602
35023
  const focus = Math.max(0, selectedIndex);
34603
35024
  const focused = panels[focus];
34604
35025
  if (focused === void 0) return 0;
34605
- if (focused.kind === "workspace-explorer" || focused.kind === "workspace-file") {
35026
+ if (focused.kind === "workspace-explorer" || focused.kind === "workspace-file" || focused.kind === "browser") {
34606
35027
  const block = blockBounds(panels, focus, { parentOf });
34607
35028
  return block === null ? focus : block[0];
34608
35029
  }
@@ -34650,14 +35071,15 @@ function openWorkspaceExplorer(sessionId, workspace) {
34650
35071
  * browser panel across the floor — the terminal singleton rule (Terminal
34651
35072
  * Desk ADR D2). A click on an open browser FOCUSES it; a miss inserts at
34652
35073
  * the focused slot. */
34653
- function openBrowserPanel(index, keepSelection = false) {
34654
- const open = st.panels.find((p) => p.kind === "browser");
35074
+ function openBrowserPanel(index, keepSelection = false, width, openedBy, sessionId) {
35075
+ const open = st.panels.find((p) => p.kind === "browser" && p.openedBy === openedBy);
34655
35076
  if (open) {
34656
35077
  st.selectedPanelId = open.id;
34657
35078
  return;
34658
35079
  }
34659
35080
  const prevSelected = st.selectedPanelId;
34660
- insertPanel(makeBrowserPanel(), index === void 0 ? insertionSlot() : Math.max(0, Math.min(index, st.panels.length)));
35081
+ const slot = index !== void 0 ? Math.max(0, Math.min(index, st.panels.length)) : openedBy !== void 0 ? glassFirstSlot(st.panels, openedBy) : insertionSlot();
35082
+ insertPanel(makeBrowserPanel(width, openedBy, sessionId), slot);
34661
35083
  if (keepSelection && prevSelected !== null && prevSelected !== void 0) {
34662
35084
  if (st.panels.some((p) => p.id === prevSelected)) st.selectedPanelId = prevSelected;
34663
35085
  }
@@ -34828,6 +35250,9 @@ function removePanel(panelId, opts = {}) {
34828
35250
  }
34829
35251
  }
34830
35252
  const doomedPanelIds = new SvelteSet();
35253
+ if (opts.family !== false && rootSessionId !== null) {
35254
+ for (const p of st.panels) if (p.kind === "browser" && p.openedBy !== void 0 && doomed.has(p.openedBy)) doomedPanelIds.add(p.id);
35255
+ }
34831
35256
  if (opts.family !== false && root.kind === "workspace-explorer") {
34832
35257
  for (const p of st.panels) if (p.kind === "workspace-file" && (p.explorerPanelId === root.id || p.explorerPanelId === null && p.sessionId === root.sessionId)) doomedPanelIds.add(p.id);
34833
35258
  }
@@ -34924,11 +35349,18 @@ function makePanel(sessionId, agentPreset) {
34924
35349
  width: clampPanelWidth(d$1().getPanelWidth())
34925
35350
  };
34926
35351
  }
34927
- function makeBrowserPanel() {
35352
+ /** width: the reload-restored panel re-mints at the width the operator
35353
+ * dragged before (browser-slot persistence, RCA 2026-10-22); absent for
35354
+ * chip clicks and legacy slots — the honest-slider preset.
35355
+ * openedBy: the opener session's provenance, recorded ONCE at spawn and
35356
+ * never rewritten (ADR-0036 D1/D2); undefined = no conversation context. */
35357
+ function makeBrowserPanel(width, openedBy, sessionId) {
34928
35358
  return {
34929
35359
  id: nextPanelId(),
34930
35360
  kind: "browser",
34931
- width: clampPanelWidth(d$1().getPanelWidth())
35361
+ width: clampPanelWidth(width ?? d$1().getPanelWidth()),
35362
+ ...openedBy !== void 0 ? { openedBy } : {},
35363
+ ...sessionId !== void 0 ? { browserSessionId: sessionId } : {}
34932
35364
  };
34933
35365
  }
34934
35366
  function makeWorkspaceExplorerPanel(sessionId, root) {
@@ -35052,6 +35484,27 @@ function selectedIndex_() {
35052
35484
  return st.panels.findIndex((p) => p.id === st.selectedPanelId);
35053
35485
  }
35054
35486
  //#endregion
35487
+ //#region src/lib/services/panels/glass-release.ts
35488
+ /**
35489
+ * glass-release — the Glass Close Ladder executor (ADR 2026-10-24 D1/D3):
35490
+ * the ONE wire-kill caller. The registry stays the only teardown authority;
35491
+ * this module merely knocks on its door — fire-and-forget POST close per
35492
+ * doomed glass id, an ok answer pruning the slot entry LIVE (D4). A network
35493
+ * failure swallows (the reaper stays the net); a refusal never prunes.
35494
+ * Pure seam shape: fetch and the prune are injectable for tests.
35495
+ */
35496
+ async function releaseGlasses(sessionIds, deps = {}) {
35497
+ if (sessionIds.length === 0) return;
35498
+ const doFetch = deps.fetchImpl ?? fetch;
35499
+ const apiBase = deps.apiBase ?? "";
35500
+ await Promise.all(sessionIds.map(async (id) => {
35501
+ try {
35502
+ if (!(await doFetch(apiBase + "/api/browser/" + id + "/close", { method: "POST" })).ok) return;
35503
+ (deps.prune ?? ((sid) => removeBrowserSlot(sid)))(id);
35504
+ } catch {}
35505
+ }));
35506
+ }
35507
+ //#endregion
35055
35508
  //#region src/lib/services/panels/floor-reads.svelte.ts
35056
35509
  var floorReads = {
35057
35510
  get spineRows() {
@@ -35166,6 +35619,7 @@ function seedColdOf(data) {
35166
35619
  //#region src/routes/+page.svelte
35167
35620
  function _page($$renderer, $$props) {
35168
35621
  $$renderer.component(($$renderer) => {
35622
+ var $$store_subs;
35169
35623
  /**
35170
35624
  * Workspace route — the floor SHELL (ADR-0019 W3): configure the
35171
35625
  * floor-registry dep seam once, seed/restore through initFloor,
@@ -35194,21 +35648,38 @@ function _page($$renderer, $$props) {
35194
35648
  setPanelWidthPreset: (w) => pagePrefs.panelWidth = w,
35195
35649
  setTreePct: (pct) => pagePrefs.treePct = pct,
35196
35650
  getSettingsHomes: () => appConfig().settingsHomes,
35197
- applyTerminalDeskAction: (a) => void 0
35651
+ applyTerminalDeskAction: (a) => void 0,
35652
+ releaseGlasses: (ids) => void releaseGlasses(ids)
35198
35653
  });
35199
35654
  initFloor(seededInitially ? [makePanel(seedSessionId(), seedCold?.agentPreset ?? null)] : initialPrefs.panels, seededInitially ? null : initialPrefs.selectedPanelId);
35200
35655
  if (seededInitially) selectPanel(floor.panels[0]?.id ?? null);
35201
35656
  if (seededInitially && seedCold !== void 0) pageFeeds.primeSeed(seedSessionId(), seedCold);
35202
- (async () => {
35657
+ async function restoreBrowserGlasses() {
35203
35658
  try {
35204
- const persisted = readPersistedId();
35205
- if (!persisted) return;
35206
35659
  if (floor.panels.some((panel) => panel.kind === "browser")) return;
35207
35660
  const res = await fetch("/api/browser");
35208
35661
  if (!res.ok) return;
35209
- if ((await res.json()).sessions?.some((s) => s.id === persisted)) openBrowserPanel(readPersistedIndex() ?? void 0, true);
35662
+ const body = await res.json();
35663
+ const live = new Set((body.sessions ?? []).map((s) => s.id));
35664
+ const slots = readBrowserSlots();
35665
+ const dead = slots.filter((s) => s.sessionId && !live.has(s.sessionId));
35666
+ if (dead.length > 0) persistBrowserSlots(slots.filter((s) => !dead.includes(s)));
35667
+ for (const slot of slots) {
35668
+ if (slot.folded) continue;
35669
+ if (!slot.sessionId || !live.has(slot.sessionId)) continue;
35670
+ summonGlass(slot);
35671
+ }
35210
35672
  } catch {}
35211
- })();
35673
+ }
35674
+ /** Bring ONE folded glass back (the summon; the replace verb is the
35675
+ * same re-bind — the glass owns its slot identity, D4). keepSelection:
35676
+ * boot restore keeps the operator's focus (true, the default); the
35677
+ * ghost-click summon focuses the GLASS (false, Ladder focus contract). */
35678
+ function summonGlass(glass, opts = {}) {
35679
+ openBrowserPanel(glass.index, opts.keepSelection ?? true, glass.width, glass.openedBy, glass.sessionId);
35680
+ }
35681
+ primeBrowserSlotStore();
35682
+ restoreBrowserGlasses();
35212
35683
  const panels = derived(() => floor.panels);
35213
35684
  const selectedPanelId = derived(() => floor.selectedPanelId);
35214
35685
  const selected = derived(() => floor.selected);
@@ -35221,6 +35692,12 @@ function _page($$renderer, $$props) {
35221
35692
  const spineWorkspaces = derived(() => floorReads.spineWorkspaces);
35222
35693
  const lineageFacts = derived(() => floorReads.lineageFacts);
35223
35694
  const conversationPanels = derived(() => floorReads.conversationPanels);
35695
+ const allFoldedGlassRows = derived(() => foldedGlassRowsFor(store_get($$store_subs ??= {}, "$browserSlotStore", browserSlotStore), (id) => lineageFacts().depthById.get(id) ?? 0, (id) => panelTitleFor(id)));
35696
+ const spineGlassRows = derived(() => allFoldedGlassRows().filter((g) => !conversationPanels().some((p) => p.sessionId === g.parentSessionId)).map((g) => ({
35697
+ sessionId: g.panel.sessionId,
35698
+ openedBy: g.parentSessionId,
35699
+ title: g.title ?? "Browser"
35700
+ })));
35224
35701
  const sidebarPlacement = derived(() => appConfig().sidebar.placement);
35225
35702
  const sidebarInZoom = derived(() => sidebarPlacement() === "panels-zoom" && !pagePrefs.sidebarCollapsed);
35226
35703
  pageFeeds.installFeeds(() => conversationPanels().map((p) => p.sessionId));
@@ -35240,6 +35717,10 @@ function _page($$renderer, $$props) {
35240
35717
  function toggleSidebar() {
35241
35718
  pagePrefs.sidebarCollapsed = !pagePrefs.sidebarCollapsed;
35242
35719
  }
35720
+ function startSidebarResize(e) {
35721
+ e.preventDefault();
35722
+ e.clientX, pagePrefs.sidebarWidth;
35723
+ }
35243
35724
  function sidebarRail($$renderer) {
35244
35725
  AppSidebar($$renderer, {
35245
35726
  profile: activeProfile,
@@ -35249,7 +35730,26 @@ function _page($$renderer, $$props) {
35249
35730
  currentSessionId: selected()?.kind === "conversation" ? selected().sessionId : "",
35250
35731
  paneledSessionIds: conversationPanels().map((p) => p.sessionId),
35251
35732
  captureContainer: pageRoot,
35252
- onToggleCollapse: toggleSidebar});
35733
+ trayContainer: floorEl,
35734
+ glassRows: spineGlassRows(),
35735
+ onresizeall: resizeAll,
35736
+ onToggleCollapse: toggleSidebar,
35737
+ onResizeStart: startSidebarResize,
35738
+ get panelWidth() {
35739
+ return pagePrefs.panelWidth;
35740
+ },
35741
+ set panelWidth($$value) {
35742
+ pagePrefs.panelWidth = $$value;
35743
+ $$settled = false;
35744
+ },
35745
+ get zoom() {
35746
+ return pagePrefs.zoom;
35747
+ },
35748
+ set zoom($$value) {
35749
+ pagePrefs.zoom = $$value;
35750
+ $$settled = false;
35751
+ }
35752
+ });
35253
35753
  }
35254
35754
  function panelBody($$renderer, panel, floorPanelId, hostClose) {
35255
35755
  if (panel.kind === "terminal") {
@@ -35263,10 +35763,15 @@ function _page($$renderer, $$props) {
35263
35763
  $$renderer.push(`<!----></div>`);
35264
35764
  } else if (panel.kind === "browser") {
35265
35765
  $$renderer.push("<!--[1-->");
35266
- $$renderer.push(`<div class="panel-manager-body svelte-1uha8ag" data-testid="panel-browser-slot">`);
35267
- BrowserPanel($$renderer, {
35268
- browserSessionId: "browserSessionId" in panel ? panel.browserSessionId : void 0});
35269
- $$renderer.push(`<!----></div>`);
35766
+ BrowserManager($$renderer, {
35767
+ browserSessionId: "browserSessionId" in panel ? panel.browserSessionId : void 0,
35768
+ onclose: () => {
35769
+ if ("browserSessionId" in panel && panel.browserSessionId) releaseGlasses([panel.browserSessionId]);
35770
+ removePanel(panel.id);
35771
+ },
35772
+ openedBy: panel.openedBy,
35773
+ parentTitle: panel.openedBy ? panelTitleFor(panel.openedBy) ?? panel.openedBy : null,
35774
+ depth: panel.openedBy ? lineageFacts().depthById.get(panel.openedBy) ?? 0 : 0});
35270
35775
  } else if (panel.kind === "injected-doc") {
35271
35776
  $$renderer.push("<!--[2-->");
35272
35777
  $$renderer.push(`<div class="panel-manager-body svelte-1uha8ag">`);
@@ -35384,7 +35889,7 @@ function _page($$renderer, $$props) {
35384
35889
  a2aRows: a2aRowsFor(p.sessionId),
35385
35890
  a2aTitles: spineTitles(),
35386
35891
  onOpenExplorer: openWorkspaceExplorer,
35387
- onOpenBrowser: lineageFacts().subagentIds.has(p.sessionId) ? void 0 : () => openBrowserPanel(),
35892
+ onOpenBrowser: lineageFacts().subagentIds.has(p.sessionId) ? void 0 : () => openBrowserPanel(void 0, false, void 0, p.sessionId),
35388
35893
  focusComposer: p.id === focusComposerId(),
35389
35894
  oncomposerfocus: () => clearFocusComposer(),
35390
35895
  focused: p.id === selectedPanelId()
@@ -35413,7 +35918,7 @@ function _page($$renderer, $$props) {
35413
35918
  a2aTitles: spineTitles(),
35414
35919
  onNeedCold: (sid) => void ensureCold(sid),
35415
35920
  onOpenExplorer: openWorkspaceExplorer,
35416
- onOpenBrowser: lineageFacts().subagentIds.has(p.sessionId) ? void 0 : () => openBrowserPanel(),
35921
+ onOpenBrowser: lineageFacts().subagentIds.has(p.sessionId) ? void 0 : () => openBrowserPanel(void 0, false, void 0, p.sessionId),
35417
35922
  focusComposer: p.id === focusComposerId(),
35418
35923
  oncomposerfocus: () => clearFocusComposer(),
35419
35924
  focused: p.id === selectedPanelId()
@@ -35437,26 +35942,7 @@ function _page($$renderer, $$props) {
35437
35942
  $$renderer.push("<!--[0-->");
35438
35943
  sidebarRail($$renderer);
35439
35944
  } else $$renderer.push("<!--[-1-->");
35440
- $$renderer.push(`<!--]--> `);
35441
- ControlBar($$renderer, {
35442
- onresizeall: resizeAll,
35443
- captureContainer: floorEl,
35444
- get panelWidth() {
35445
- return pagePrefs.panelWidth;
35446
- },
35447
- set panelWidth($$value) {
35448
- pagePrefs.panelWidth = $$value;
35449
- $$settled = false;
35450
- },
35451
- get zoom() {
35452
- return pagePrefs.zoom;
35453
- },
35454
- set zoom($$value) {
35455
- pagePrefs.zoom = $$value;
35456
- $$settled = false;
35457
- }
35458
- });
35459
- $$renderer.push(`<!----> <div class="floor svelte-1uha8ag">`);
35945
+ $$renderer.push(`<!--]--> <div class="floor svelte-1uha8ag">`);
35460
35946
  PanelsZoom($$renderer, {
35461
35947
  zoom: pagePrefs.zoom,
35462
35948
  panels: panels(),
@@ -35515,8 +36001,9 @@ function _page($$renderer, $$props) {
35515
36001
  $$render_inner($$inner_renderer);
35516
36002
  } while (!$$settled);
35517
36003
  $$renderer.subsume($$inner_renderer);
36004
+ if ($$store_subs) unsubscribe_stores($$store_subs);
35518
36005
  });
35519
36006
  }
35520
36007
 
35521
36008
  export { _page as default };
35522
- //# sourceMappingURL=_page.svelte.js-hjZYZCe1.js.map
36009
+ //# sourceMappingURL=_page.svelte.js-CQUo8VGL.js.map