@deepseek-insight/dsi 0.8.3 → 0.8.5

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 (110) hide show
  1. package/.agents/skills/dsi-gb-verifier/SKILL.md +143 -0
  2. package/build/client/_app/immutable/assets/0.C6AGVUc8.css +2 -0
  3. package/build/client/_app/immutable/assets/{2.BPprd30B.css → 2.gXzZuuwh.css} +1 -1
  4. package/build/client/_app/immutable/chunks/BFOY8uwF.js +1 -0
  5. package/build/client/_app/immutable/chunks/CrTRqozz.js +1 -0
  6. package/build/client/_app/immutable/chunks/DxGYLnDH.js +1 -0
  7. package/build/client/_app/immutable/chunks/HD-mJtOS.js +6 -0
  8. package/build/client/_app/immutable/chunks/{BoHeiMOU.js → b4-Ro8NH.js} +1 -1
  9. package/build/client/_app/immutable/chunks/hC0DBYN6.js +2 -0
  10. package/build/client/_app/immutable/entry/{app.S_mxIoOg.js → app.DHewwbUQ.js} +2 -2
  11. package/build/client/_app/immutable/entry/start.C0PcwkeZ.js +1 -0
  12. package/build/client/_app/immutable/nodes/{0.6dTmg1Xv.js → 0.CP10wY64.js} +1 -1
  13. package/build/client/_app/immutable/nodes/{1.D20V6eTe.js → 1.qWvE0DiU.js} +1 -1
  14. package/build/client/_app/immutable/nodes/{2.BHcBdFqH.js → 2.Nw7iFtoh.js} +224 -223
  15. package/build/client/_app/version.json +1 -1
  16. package/build/handler.js +4 -4
  17. package/build/index.js +4 -4
  18. package/build/server/chunks/chunks/{app-config.svelte.js-BM4WbMFB.js → app-config.svelte.js-DCc9d7A4.js} +6 -2
  19. package/build/server/chunks/chunks/{config.js-vThvQeMn.js → config.js-s6iKwHD7.js} +3 -2
  20. package/build/server/chunks/chunks/{db.js-DQm6CZ_r.js → db.js-CxxWK5sn.js} +2 -2
  21. package/build/server/chunks/chunks/{db2.js-DUhFxA3a.js → db2.js-DwJ9lySe.js} +2 -2
  22. package/build/server/chunks/chunks/{dsh-connection.js-BgeraFA2.js → dsh-connection.js-Chtudg1p.js} +3 -3
  23. package/build/server/chunks/chunks/{dsh-events.js-BUkLR6ZV.js → dsh-events.js-BUdvZQmd.js} +6 -3
  24. package/build/server/chunks/chunks/{git-probe.js-CLF37SRh.js → git-probe.js-BX9FPnet.js} +3 -3
  25. package/build/server/chunks/chunks/{insight-config.js-Dp_2gB5J.js → insight-config.js-Db5fe5Df.js} +9 -5
  26. package/build/server/chunks/chunks/{internal2.js-Ba5p8uFM.js → internal2.js-CaZaz-a9.js} +3 -3
  27. package/build/server/chunks/chunks/ledger-stats.js-BWACyDPg.js +72 -0
  28. package/build/server/chunks/chunks/{registry.js-C2MdrfNv.js → registry.js-syaTZ_-A.js} +403 -34
  29. package/build/server/chunks/chunks/{settings-document.js-Gw1puaik.js → settings-document.js-BHESJ7im.js} +2 -2
  30. package/build/server/chunks/chunks/{state.js-BSiAgink.js → state.js-oYjf745s.js} +3 -3
  31. package/build/server/chunks/chunks/{watcher.js-BVKnoQUw.js → watcher.js-Ci9jsM5l.js} +5 -5
  32. package/build/server/chunks/entries/endpoints/api/a2a/_id_/{_server.ts.js-BjzdVwdY.js → _server.ts.js-CHaYhzjy.js} +5 -5
  33. package/build/server/chunks/entries/endpoints/api/a2a/{_server.ts.js-3kQCQuHT.js → _server.ts.js-CdyqA85c.js} +8 -8
  34. package/build/server/chunks/entries/endpoints/api/a2a/register/{_server.ts.js-BUBTCLFn.js → _server.ts.js-DO_FS5b4.js} +8 -8
  35. package/build/server/chunks/entries/endpoints/api/browser/_id_/activate/{_server.ts.js-CogDOHKu.js → _server.ts.js-D7Be4JUf.js} +5 -5
  36. package/build/server/chunks/entries/endpoints/api/browser/_id_/close/{_server.ts.js-xOt7LnS1.js → _server.ts.js-CGkm2H-U.js} +5 -5
  37. package/build/server/chunks/entries/endpoints/api/browser/_id_/closetab/{_server.ts.js-CSmVPvSM.js → _server.ts.js-D7SLUfOo.js} +5 -5
  38. package/build/server/chunks/entries/endpoints/api/browser/_id_/element/{_server.ts.js-BA40oCDW.js → _server.ts.js-C3d_JV-q.js} +5 -5
  39. package/build/server/chunks/entries/endpoints/api/browser/_id_/input/{_server.ts.js-EX7eVzjp.js → _server.ts.js-DW0hyVML.js} +5 -5
  40. package/build/server/chunks/entries/endpoints/api/browser/_id_/mcp/{_server.ts.js-B_EcmyFt.js → _server.ts.js-Ev-hdBlf.js} +5 -5
  41. package/build/server/chunks/entries/endpoints/api/browser/_id_/navigate/{_server.ts.js-C3dYbyS3.js → _server.ts.js-DZ8-wocV.js} +5 -5
  42. package/build/server/chunks/entries/endpoints/api/browser/_id_/opentab/{_server.ts.js-CMhJJO25.js → _server.ts.js-aapPrIQK.js} +11 -9
  43. package/build/server/chunks/entries/endpoints/api/browser/_id_/page/{_server.ts.js-DIW4uI2S.js → _server.ts.js-DANA_hMd.js} +5 -5
  44. package/build/server/chunks/entries/endpoints/api/browser/_id_/stream/{_server.ts.js-CIPIlq5X.js → _server.ts.js-BqfseXFy.js} +26 -9
  45. package/build/server/chunks/entries/endpoints/api/browser/_id_/tabs/{_server.ts.js-CoEdOiml.js → _server.ts.js-DFFF9qe-.js} +5 -5
  46. package/build/server/chunks/entries/endpoints/api/browser/_id_/viewport/{_server.ts.js-CdELUoGT.js → _server.ts.js-ek6-D4Zm.js} +5 -5
  47. package/build/server/chunks/entries/endpoints/api/browser/{_server.ts.js-ea6HpNGh.js → _server.ts.js-CPjKy3ma.js} +5 -5
  48. package/build/server/chunks/entries/endpoints/api/config/{_server.ts.js-C8XDnDwe.js → _server.ts.js-CWE9NP6g.js} +12 -5
  49. package/build/server/chunks/entries/endpoints/api/dsh/directory/{_server.ts.js-BFmWshpv.js → _server.ts.js-D-raYQon.js} +5 -5
  50. package/build/server/chunks/entries/endpoints/api/dsh/jobs/{_server.ts.js-DATWy5mQ.js → _server.ts.js-CI4dEHFY.js} +5 -5
  51. package/build/server/chunks/entries/endpoints/api/dsh/jobs/follow/{_server.ts.js-CugOD1Zd.js → _server.ts.js-cnjoSLtY.js} +5 -5
  52. package/build/server/chunks/entries/endpoints/api/dsh/pick-directory/{_server.ts.js-DCupM4da.js → _server.ts.js-0UUtapX5.js} +5 -5
  53. package/build/server/chunks/entries/endpoints/api/dsh/presets/{_server.ts.js-Bh1btvr9.js → _server.ts.js-MK5ezU8u.js} +5 -5
  54. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/{_server.ts.js-Cb8SBWVw.js → _server.ts.js-CEiMgzjC.js} +5 -5
  55. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/cancel/{_server.ts.js-WI9yH2iG.js → _server.ts.js-wGEl1fuF.js} +5 -5
  56. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/catalog/{_server.ts.js-bN9adUqz.js → _server.ts.js-Bz7u2BlD.js} +5 -5
  57. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/changes/{_server.ts.js-Bxlm966G.js → _server.ts.js-yue5aEjr.js} +5 -5
  58. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/command/{_server.ts.js-CM-raN_Q.js → _server.ts.js-BFSs5T2m.js} +5 -5
  59. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/events/{_server.ts.js-BzP30TXW.js → _server.ts.js-C2i85wQy.js} +7 -70
  60. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/fork/{_server.ts.js-DvNkrTaY.js → _server.ts.js-_toO4f4W.js} +5 -5
  61. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/goal/{_server.ts.js-DXbCrefw.js → _server.ts.js-BGJnDV85.js} +5 -5
  62. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/history/{_server.ts.js-B7YRQhuJ.js → _server.ts.js-CQCJg8U8.js} +6 -6
  63. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/models/{_server.ts.js-C_AEaLLJ.js → _server.ts.js-0ADvdE79.js} +5 -5
  64. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/path/{_server.ts.js-Dj-pF5ik.js → _server.ts.js-DyO4T1Ro.js} +4 -4
  65. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/permission/{_server.ts.js-BX9FWJ6g.js → _server.ts.js-CIY7oimw.js} +5 -5
  66. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/prompt/{_server.ts.js-CQ2Bmtu4.js → _server.ts.js-B-9faNHX.js} +5 -5
  67. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/rename/{_server.ts.js-Ha7xjnKW.js → _server.ts.js-E7-0zfiH.js} +5 -5
  68. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/respond/{_server.ts.js-BOg6llHk.js → _server.ts.js-CODtLQ3Q.js} +5 -5
  69. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/select-model/{_server.ts.js-DBqGALzZ.js → _server.ts.js-BiSxsU-j.js} +5 -5
  70. package/build/server/chunks/entries/endpoints/api/dsh/sessions/{_server.ts.js-CvA8WDDb.js → _server.ts.js-C0WJnv2b.js} +5 -5
  71. package/build/server/chunks/entries/endpoints/api/dsh/subagents/_server.ts.js-D5bc4xg4.js +72 -0
  72. package/build/server/chunks/entries/endpoints/api/dsh/workspace-file/{_server.ts.js-BfjNH40j.js → _server.ts.js-23ycAyUg.js} +5 -5
  73. package/build/server/chunks/entries/endpoints/api/dsh/workspace-tree/{_server.ts.js-De_qumyr.js → _server.ts.js-B4w5Jh7f.js} +5 -5
  74. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/{_server.ts.js-tFpJJHCb.js → _server.ts.js-VQLxDbFE.js} +5 -5
  75. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/delete/{_server.ts.js-DVx5GGA_.js → _server.ts.js-vs5N5Cya.js} +5 -5
  76. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/rename/{_server.ts.js-DuKT-aZp.js → _server.ts.js-BOWhoBHV.js} +5 -5
  77. package/build/server/chunks/entries/endpoints/api/prompts/_id_/{_server.ts.js-DsWFidFY.js → _server.ts.js-aDEAGfJe.js} +5 -5
  78. package/build/server/chunks/entries/endpoints/api/prompts/{_server.ts.js-C6j0adQs.js → _server.ts.js-BZ-nRrTp.js} +5 -5
  79. package/build/server/chunks/entries/endpoints/api/prompts/use/{_server.ts.js-BChAg4hm.js → _server.ts.js-CkDY1PQ7.js} +5 -5
  80. package/build/server/chunks/entries/endpoints/api/settings/{_server.ts.js-BPSHqbZN.js → _server.ts.js-CHvgF47Y.js} +4 -4
  81. package/build/server/chunks/entries/endpoints/api/terminal/{_server.ts.js-D5CbUe5k.js → _server.ts.js-CbRT4vBo.js} +4 -4
  82. package/build/server/chunks/entries/endpoints/api/workspace/file-write/{_server.ts.js-B-5YihUA.js → _server.ts.js-BwD0KaXy.js} +7 -7
  83. package/build/server/chunks/entries/endpoints/api/workspace/git-events/{_server.ts.js-DT5jRZFE.js → _server.ts.js-DgbMRh3d.js} +7 -7
  84. package/build/server/chunks/entries/endpoints/api/workspace/git-file-head/{_server.ts.js-DtW-utrd.js → _server.ts.js-DRqZawic.js} +7 -7
  85. package/build/server/chunks/entries/endpoints/api/workspace/git-map/{_server.ts.js-8AIAo9jX.js → _server.ts.js-CTXwwwB1.js} +7 -7
  86. package/build/server/chunks/entries/endpoints/api/workspace/git-status/{_server.ts.js-CMw96vjY.js → _server.ts.js-B4aJBY2w.js} +7 -7
  87. package/build/server/chunks/entries/endpoints/api/workspace/write-gate/{_server.ts.js-DKufa14_.js → _server.ts.js-CDJJA18L.js} +7 -7
  88. package/build/server/chunks/entries/{hooks.server.js-B-e4_ekh.js → hooks.server.js-Iel6oE7w.js} +3 -3
  89. package/build/server/chunks/entries/pages/{_error.svelte.js-D8-G0evO.js → _error.svelte.js-B-wdFjVG.js} +4 -4
  90. package/build/server/chunks/entries/pages/{_page.server.ts.js-7x6ZfGoB.js → _page.server.ts.js-CaoeQzem.js} +3 -3
  91. package/build/server/chunks/entries/pages/{_page.svelte.js-7xWLRsiZ.js → _page.svelte.js-CY7zcWr4.js} +1713 -1077
  92. package/build/server/chunks/{handler-BedQ0jP-.js → handler-DYk4NJto.js} +3 -3
  93. package/build/server/chunks/{index.js-BF6tPPQs.js → index.js-kL9MZ99b.js} +2 -2
  94. package/build/server/chunks/{manifest.js-3c0p7QAl.js → manifest.js-BrMLQqec.js} +67 -60
  95. package/build/server/chunks/nodes/{0.js-B3i7sGR_.js → 0.js-BembYTTr.js} +3 -3
  96. package/build/server/chunks/nodes/1.js-CKJjyWGZ.js +9 -0
  97. package/build/server/chunks/nodes/{2.js-CgnRGwm6.js → 2.js-BezA2RPm.js} +10 -10
  98. package/package.json +1 -1
  99. package/skills/{dsi-kb-scenario → dsi-fc-scenario}/SKILL.md +11 -6
  100. package/template/.dsi/prompts.sqlite-shm +0 -0
  101. package/template/.dsi/prompts.sqlite-wal +0 -0
  102. package/template/.dsi/settings.yaml +2 -2
  103. package/build/client/_app/immutable/assets/0.DyOAkKS-.css +0 -2
  104. package/build/client/_app/immutable/chunks/C9QAOGL1.js +0 -2
  105. package/build/client/_app/immutable/chunks/D-Rolhzs.js +0 -1
  106. package/build/client/_app/immutable/chunks/NcOjFWr3.js +0 -6
  107. package/build/client/_app/immutable/chunks/QJuSx3RG.js +0 -1
  108. package/build/client/_app/immutable/chunks/sC_8Ss7w.js +0 -1
  109. package/build/client/_app/immutable/entry/start.BPQAB3iV.js +0 -1
  110. package/build/server/chunks/nodes/1.js-eUf50uxI.js +0 -9
@@ -1,15 +1,15 @@
1
1
  import { a as __exportAll, o as onDestroy } from '../../chunks/index-server.js-DmIEbDVz.js';
2
2
  import '../../chunks/exports.js-DH_tjtdv.js';
3
3
  import { M as derived, V as head, T as writable, W as escape_html, X as attr, Y as bind_props, a as setContext, Z as attr_class, _ as attr_style, $ as store_get, a0 as spread_props, a1 as stringify, a2 as attributes, a3 as clsx, a4 as ensure_array_like, a5 as element, g as getContext, a6 as unsubscribe_stores, a7 as html, r as run, a8 as props_id } from '../../chunks/server.js-B1bDXhHu.js';
4
- import { U as UI_LOCALES } from '../../chunks/config.js-vThvQeMn.js';
4
+ import { U as UI_LOCALES } from '../../chunks/config.js-s6iKwHD7.js';
5
5
  import { m as mergeEntries, c as collapseSystemPromptEntries, t as truncate } from '../../chunks/merge.js-yMwW440S.js';
6
6
  import { p as parseA2aSignature, m as mintA2aId, b as buildDeliveredText } from '../../chunks/a2a-protocol.js-C77mVg2Q.js';
7
7
  import { b as applyKnobEvent, E as EMPTY_KNOBS, r as resolvePermission, l as localPermission, c as presetLabel, d as presetDescription, C as CUSTOM_PRESET, F as FULL_ACCESS_PRESET } from '../../chunks/permission-state.js-B7UpAHBv.js';
8
8
  import { D as DEFAULT_IMAGE_LIMITS } from '../../chunks/image-limits.js-CUdJ0f7r.js';
9
9
  import { s as sanitizeWorkspaceProfile, d as dsiKey, t as themePrefs } from '../../chunks/theme-prefs.svelte.js-8CaWz46g.js';
10
- import { a as appConfig, p as previewSegments, b as parseTagWords, i as isValidTagWord, s as shouldRecordPrompt, g as getTrigger, t as triggerMode, c as searchKey, d as textPreviewOf } from '../../chunks/app-config.svelte.js-BM4WbMFB.js';
10
+ import { a as appConfig, p as previewSegments, b as parseTagWords, i as isValidTagWord, s as shouldRecordPrompt, g as getTrigger, t as triggerMode, c as searchKey, d as textPreviewOf } from '../../chunks/app-config.svelte.js-DCc9d7A4.js';
11
11
  import { c as getLocale } from '../../chunks/runtime.js-CCJi3XaY.js';
12
- import { p as page, a as afterNavigate, t, c as currentLocale, e as replaceState, u as unexpectederror1, s as sessionnotfound2, r as reapednote1, d as dshunreachable1, b as backtoworkspace2 } from '../../chunks/state.js-BSiAgink.js';
12
+ import { p as page, a as afterNavigate, t, c as currentLocale, e as replaceState, u as unexpectederror1, s as sessionnotfound2, r as reapednote1, d as dshunreachable1, b as backtoworkspace2 } from '../../chunks/state.js-oYjf745s.js';
13
13
  import 'yaml';
14
14
  import 'html-to-image';
15
15
  import hljs from 'highlight.js/lib/core';
@@ -21,7 +21,7 @@ import xml from 'highlight.js/lib/languages/xml';
21
21
  import css from 'highlight.js/lib/languages/css';
22
22
  import '../../chunks/uneval.js-BJ9Qq2SF.js';
23
23
  import '../../chunks/shared.js-HQ0rfhm4.js';
24
- import '../../chunks/internal2.js-Ba5p8uFM.js';
24
+ import '../../chunks/internal2.js-CaZaz-a9.js';
25
25
  import '../../chunks/utils.js-CAdNO8Tu.js';
26
26
 
27
27
  //#region src/lib/paraglide/messages/abort.js
@@ -984,6 +984,166 @@ var browserclosedelete2 = ((inputs = {}, options = {}) => {
984
984
  return en_browserclosedelete2();
985
985
  });
986
986
  //#endregion
987
+ //#region src/lib/paraglide/messages/browserctxcopyimage3.js
988
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
989
+ /** @typedef {{}} Browserctxcopyimage3Inputs */
990
+ var en_browserctxcopyimage3 = () => {
991
+ return `Copy image address`;
992
+ };
993
+ var zh_browserctxcopyimage3 = () => {
994
+ return `复制图片地址`;
995
+ };
996
+ var id_browserctxcopyimage3 = () => {
997
+ return `Salin alamat gambar`;
998
+ };
999
+ var es_browserctxcopyimage3 = () => {
1000
+ return `Copiar la dirección de la imagen`;
1001
+ };
1002
+ /**
1003
+ * | output |
1004
+ * | --- |
1005
+ * | "Copy image address" |
1006
+ *
1007
+ * @param {Browserctxcopyimage3Inputs} inputs
1008
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1009
+ * @returns {LocalizedString}
1010
+ */
1011
+ var browserctxcopyimage3 = ((inputs = {}, options = {}) => {
1012
+ const locale = options.locale ?? getLocale();
1013
+ if (locale === "zh") return zh_browserctxcopyimage3();
1014
+ if (locale === "id") return id_browserctxcopyimage3();
1015
+ if (locale === "es") return es_browserctxcopyimage3();
1016
+ return en_browserctxcopyimage3();
1017
+ });
1018
+ //#endregion
1019
+ //#region src/lib/paraglide/messages/browserctxcopylink3.js
1020
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1021
+ /** @typedef {{}} Browserctxcopylink3Inputs */
1022
+ var en_browserctxcopylink3 = () => {
1023
+ return `Copy link address`;
1024
+ };
1025
+ var zh_browserctxcopylink3 = () => {
1026
+ return `复制链接地址`;
1027
+ };
1028
+ var id_browserctxcopylink3 = () => {
1029
+ return `Salin alamat tautan`;
1030
+ };
1031
+ var es_browserctxcopylink3 = () => {
1032
+ return `Copiar la dirección del enlace`;
1033
+ };
1034
+ /**
1035
+ * | output |
1036
+ * | --- |
1037
+ * | "Copy link address" |
1038
+ *
1039
+ * @param {Browserctxcopylink3Inputs} inputs
1040
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1041
+ * @returns {LocalizedString}
1042
+ */
1043
+ var browserctxcopylink3 = ((inputs = {}, options = {}) => {
1044
+ const locale = options.locale ?? getLocale();
1045
+ if (locale === "zh") return zh_browserctxcopylink3();
1046
+ if (locale === "id") return id_browserctxcopylink3();
1047
+ if (locale === "es") return es_browserctxcopylink3();
1048
+ return en_browserctxcopylink3();
1049
+ });
1050
+ //#endregion
1051
+ //#region src/lib/paraglide/messages/browserctxopenimage3.js
1052
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1053
+ /** @typedef {{}} Browserctxopenimage3Inputs */
1054
+ var en_browserctxopenimage3 = () => {
1055
+ return `Open image in new tab`;
1056
+ };
1057
+ var zh_browserctxopenimage3 = () => {
1058
+ return `在新标签页中打开图片`;
1059
+ };
1060
+ var id_browserctxopenimage3 = () => {
1061
+ return `Buka gambar di tab baru`;
1062
+ };
1063
+ var es_browserctxopenimage3 = () => {
1064
+ return `Abrir imagen en una pestaña nueva`;
1065
+ };
1066
+ /**
1067
+ * | output |
1068
+ * | --- |
1069
+ * | "Open image in new tab" |
1070
+ *
1071
+ * @param {Browserctxopenimage3Inputs} inputs
1072
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1073
+ * @returns {LocalizedString}
1074
+ */
1075
+ var browserctxopenimage3 = ((inputs = {}, options = {}) => {
1076
+ const locale = options.locale ?? getLocale();
1077
+ if (locale === "zh") return zh_browserctxopenimage3();
1078
+ if (locale === "id") return id_browserctxopenimage3();
1079
+ if (locale === "es") return es_browserctxopenimage3();
1080
+ return en_browserctxopenimage3();
1081
+ });
1082
+ //#endregion
1083
+ //#region src/lib/paraglide/messages/browserctxopenlink3.js
1084
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1085
+ /** @typedef {{}} Browserctxopenlink3Inputs */
1086
+ var en_browserctxopenlink3 = () => {
1087
+ return `Open link in new tab`;
1088
+ };
1089
+ var zh_browserctxopenlink3 = () => {
1090
+ return `在新标签页中打开链接`;
1091
+ };
1092
+ var id_browserctxopenlink3 = () => {
1093
+ return `Buka tautan di tab baru`;
1094
+ };
1095
+ var es_browserctxopenlink3 = () => {
1096
+ return `Abrir enlace en una pestaña nueva`;
1097
+ };
1098
+ /**
1099
+ * | output |
1100
+ * | --- |
1101
+ * | "Open link in new tab" |
1102
+ *
1103
+ * @param {Browserctxopenlink3Inputs} inputs
1104
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1105
+ * @returns {LocalizedString}
1106
+ */
1107
+ var browserctxopenlink3 = ((inputs = {}, options = {}) => {
1108
+ const locale = options.locale ?? getLocale();
1109
+ if (locale === "zh") return zh_browserctxopenlink3();
1110
+ if (locale === "id") return id_browserctxopenlink3();
1111
+ if (locale === "es") return es_browserctxopenlink3();
1112
+ return en_browserctxopenlink3();
1113
+ });
1114
+ //#endregion
1115
+ //#region src/lib/paraglide/messages/browserctxsendrightclick4.js
1116
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1117
+ /** @typedef {{}} Browserctxsendrightclick4Inputs */
1118
+ var en_browserctxsendrightclick4 = () => {
1119
+ return `Send right-click to the page`;
1120
+ };
1121
+ var zh_browserctxsendrightclick4 = () => {
1122
+ return `向页面发送右键点击`;
1123
+ };
1124
+ var id_browserctxsendrightclick4 = () => {
1125
+ return `Kirim klik kanan ke halaman`;
1126
+ };
1127
+ var es_browserctxsendrightclick4 = () => {
1128
+ return `Enviar clic derecho a la página`;
1129
+ };
1130
+ /**
1131
+ * | output |
1132
+ * | --- |
1133
+ * | "Send right-click to the page" |
1134
+ *
1135
+ * @param {Browserctxsendrightclick4Inputs} inputs
1136
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1137
+ * @returns {LocalizedString}
1138
+ */
1139
+ var browserctxsendrightclick4 = ((inputs = {}, options = {}) => {
1140
+ const locale = options.locale ?? getLocale();
1141
+ if (locale === "zh") return zh_browserctxsendrightclick4();
1142
+ if (locale === "id") return id_browserctxsendrightclick4();
1143
+ if (locale === "es") return es_browserctxsendrightclick4();
1144
+ return en_browserctxsendrightclick4();
1145
+ });
1146
+ //#endregion
987
1147
  //#region src/lib/paraglide/messages/browserforward1.js
988
1148
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
989
1149
  /** @typedef {{}} Browserforward1Inputs */
@@ -1048,6 +1208,38 @@ var browserlaunching1 = ((inputs = {}, options = {}) => {
1048
1208
  return en_browserlaunching1();
1049
1209
  });
1050
1210
  //#endregion
1211
+ //#region src/lib/paraglide/messages/browsernewtab2.js
1212
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1213
+ /** @typedef {{}} Browsernewtab2Inputs */
1214
+ var en_browsernewtab2 = () => {
1215
+ return `New tab`;
1216
+ };
1217
+ var zh_browsernewtab2 = () => {
1218
+ return `新标签页`;
1219
+ };
1220
+ var id_browsernewtab2 = () => {
1221
+ return `Tab baru`;
1222
+ };
1223
+ var es_browsernewtab2 = () => {
1224
+ return `Nueva pestaña`;
1225
+ };
1226
+ /**
1227
+ * | output |
1228
+ * | --- |
1229
+ * | "New tab" |
1230
+ *
1231
+ * @param {Browsernewtab2Inputs} inputs
1232
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1233
+ * @returns {LocalizedString}
1234
+ */
1235
+ var browsernewtab2 = ((inputs = {}, options = {}) => {
1236
+ const locale = options.locale ?? getLocale();
1237
+ if (locale === "zh") return zh_browsernewtab2();
1238
+ if (locale === "id") return id_browsernewtab2();
1239
+ if (locale === "es") return es_browsernewtab2();
1240
+ return en_browsernewtab2();
1241
+ });
1242
+ //#endregion
1051
1243
  //#region src/lib/paraglide/messages/browseropentitle2.js
1052
1244
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1053
1245
  /** @typedef {{}} Browseropentitle2Inputs */
@@ -1176,6 +1368,38 @@ var browsersessionfailed2 = ((inputs, options = {}) => {
1176
1368
  return en_browsersessionfailed2(inputs);
1177
1369
  });
1178
1370
  //#endregion
1371
+ //#region src/lib/paraglide/messages/browsertabclosetitle3.js
1372
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1373
+ /** @typedef {{}} Browsertabclosetitle3Inputs */
1374
+ var en_browsertabclosetitle3 = () => {
1375
+ return `Close tab`;
1376
+ };
1377
+ var zh_browsertabclosetitle3 = () => {
1378
+ return `关闭标签页`;
1379
+ };
1380
+ var id_browsertabclosetitle3 = () => {
1381
+ return `Tutup tab`;
1382
+ };
1383
+ var es_browsertabclosetitle3 = () => {
1384
+ return `Cerrar pestaña`;
1385
+ };
1386
+ /**
1387
+ * | output |
1388
+ * | --- |
1389
+ * | "Close tab" |
1390
+ *
1391
+ * @param {Browsertabclosetitle3Inputs} inputs
1392
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
1393
+ * @returns {LocalizedString}
1394
+ */
1395
+ var browsertabclosetitle3 = ((inputs = {}, options = {}) => {
1396
+ const locale = options.locale ?? getLocale();
1397
+ if (locale === "zh") return zh_browsertabclosetitle3();
1398
+ if (locale === "id") return id_browsertabclosetitle3();
1399
+ if (locale === "es") return es_browsertabclosetitle3();
1400
+ return en_browsertabclosetitle3();
1401
+ });
1402
+ //#endregion
1179
1403
  //#region src/lib/paraglide/messages/browserurlplaceholder2.js
1180
1404
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1181
1405
  /** @typedef {{}} Browserurlplaceholder2Inputs */
@@ -12376,6 +12600,70 @@ var streaming = ((inputs = {}, options = {}) => {
12376
12600
  return en_streaming();
12377
12601
  });
12378
12602
  //#endregion
12603
+ //#region src/lib/paraglide/messages/subagentanchorlabel2.js
12604
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
12605
+ /** @typedef {{}} Subagentanchorlabel2Inputs */
12606
+ var en_subagentanchorlabel2 = () => {
12607
+ return `Subagents`;
12608
+ };
12609
+ var zh_subagentanchorlabel2 = () => {
12610
+ return `子代理`;
12611
+ };
12612
+ var id_subagentanchorlabel2 = () => {
12613
+ return `Subagen`;
12614
+ };
12615
+ var es_subagentanchorlabel2 = () => {
12616
+ return `Subagentes`;
12617
+ };
12618
+ /**
12619
+ * | output |
12620
+ * | --- |
12621
+ * | "Subagents" |
12622
+ *
12623
+ * @param {Subagentanchorlabel2Inputs} inputs
12624
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
12625
+ * @returns {LocalizedString}
12626
+ */
12627
+ var subagentanchorlabel2 = ((inputs = {}, options = {}) => {
12628
+ const locale = options.locale ?? getLocale();
12629
+ if (locale === "zh") return zh_subagentanchorlabel2();
12630
+ if (locale === "id") return id_subagentanchorlabel2();
12631
+ if (locale === "es") return es_subagentanchorlabel2();
12632
+ return en_subagentanchorlabel2();
12633
+ });
12634
+ //#endregion
12635
+ //#region src/lib/paraglide/messages/subagentcloseallpanels3.js
12636
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
12637
+ /** @typedef {{}} Subagentcloseallpanels3Inputs */
12638
+ var en_subagentcloseallpanels3 = () => {
12639
+ return `del panel(s)`;
12640
+ };
12641
+ var zh_subagentcloseallpanels3 = () => {
12642
+ return `删除面板`;
12643
+ };
12644
+ var id_subagentcloseallpanels3 = () => {
12645
+ return `hapus panel`;
12646
+ };
12647
+ var es_subagentcloseallpanels3 = () => {
12648
+ return `eliminar panel(es)`;
12649
+ };
12650
+ /**
12651
+ * | output |
12652
+ * | --- |
12653
+ * | "del panel(s)" |
12654
+ *
12655
+ * @param {Subagentcloseallpanels3Inputs} inputs
12656
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
12657
+ * @returns {LocalizedString}
12658
+ */
12659
+ var subagentcloseallpanels3 = ((inputs = {}, options = {}) => {
12660
+ const locale = options.locale ?? getLocale();
12661
+ if (locale === "zh") return zh_subagentcloseallpanels3();
12662
+ if (locale === "id") return id_subagentcloseallpanels3();
12663
+ if (locale === "es") return es_subagentcloseallpanels3();
12664
+ return en_subagentcloseallpanels3();
12665
+ });
12666
+ //#endregion
12379
12667
  //#region src/lib/paraglide/messages/subagentmany1.js
12380
12668
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
12381
12669
  /** @typedef {{ n: NonNullable<unknown> }} Subagentmany1Inputs */
@@ -13496,6 +13784,38 @@ var tooltitlewrite2 = ((inputs = {}, options = {}) => {
13496
13784
  return en_tooltitlewrite2();
13497
13785
  });
13498
13786
  //#endregion
13787
+ //#region src/lib/paraglide/messages/totaltokens1.js
13788
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
13789
+ /** @typedef {{}} Totaltokens1Inputs */
13790
+ var en_totaltokens1 = () => {
13791
+ return `Total tokens`;
13792
+ };
13793
+ var zh_totaltokens1 = () => {
13794
+ return `总 Token 数`;
13795
+ };
13796
+ var id_totaltokens1 = () => {
13797
+ return `Total token`;
13798
+ };
13799
+ var es_totaltokens1 = () => {
13800
+ return `Tokens totales`;
13801
+ };
13802
+ /**
13803
+ * | output |
13804
+ * | --- |
13805
+ * | "Total tokens" |
13806
+ *
13807
+ * @param {Totaltokens1Inputs} inputs
13808
+ * @param {{ locale?: "en" | "zh" | "id" | "es" }} options
13809
+ * @returns {LocalizedString}
13810
+ */
13811
+ var totaltokens1 = ((inputs = {}, options = {}) => {
13812
+ const locale = options.locale ?? getLocale();
13813
+ if (locale === "zh") return zh_totaltokens1();
13814
+ if (locale === "id") return id_totaltokens1();
13815
+ if (locale === "es") return es_totaltokens1();
13816
+ return en_totaltokens1();
13817
+ });
13818
+ //#endregion
13499
13819
  //#region src/lib/paraglide/messages/turnfailed1.js
13500
13820
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
13501
13821
  /** @typedef {{}} Turnfailed1Inputs */
@@ -14873,12 +15193,19 @@ var _index_exports = /* @__PURE__ */ __exportAll({
14873
15193
  browserBack: () => browserback1,
14874
15194
  browserChipLabel: () => browserchiplabel2,
14875
15195
  browserCloseDelete: () => browserclosedelete2,
15196
+ browserCtxCopyImage: () => browserctxcopyimage3,
15197
+ browserCtxCopyLink: () => browserctxcopylink3,
15198
+ browserCtxOpenImage: () => browserctxopenimage3,
15199
+ browserCtxOpenLink: () => browserctxopenlink3,
15200
+ browserCtxSendRightClick: () => browserctxsendrightclick4,
14876
15201
  browserForward: () => browserforward1,
14877
15202
  browserLaunching: () => browserlaunching1,
15203
+ browserNewTab: () => browsernewtab2,
14878
15204
  browserOpenTitle: () => browseropentitle2,
14879
15205
  browserPanelTitle: () => browserpaneltitle2,
14880
15206
  browserReload: () => browserreload1,
14881
15207
  browserSessionFailed: () => browsersessionfailed2,
15208
+ browserTabCloseTitle: () => browsertabclosetitle3,
14882
15209
  browserUrlPlaceholder: () => browserurlplaceholder2,
14883
15210
  browserWaitingFrames: () => browserwaitingframes2,
14884
15211
  cacheHit: () => cachehit1,
@@ -15232,6 +15559,8 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15232
15559
  stop: () => stop,
15233
15560
  stopStreaming: () => stopstreaming1,
15234
15561
  streaming: () => streaming,
15562
+ subagentAnchorLabel: () => subagentanchorlabel2,
15563
+ subagentCloseAllPanels: () => subagentcloseallpanels3,
15235
15564
  subagentMany: () => subagentmany1,
15236
15565
  subagentOne: () => subagentone1,
15237
15566
  subagentTitleOwns: () => subagenttitleowns2,
@@ -15267,6 +15596,7 @@ var _index_exports = /* @__PURE__ */ __exportAll({
15267
15596
  toolTitleSearch: () => tooltitlesearch2,
15268
15597
  toolTitleToolCall: () => tooltitletoolcall3,
15269
15598
  toolTitleWrite: () => tooltitlewrite2,
15599
+ totalTokens: () => totaltokens1,
15270
15600
  turnFailed: () => turnfailed1,
15271
15601
  turnInFlight: () => turninflight2,
15272
15602
  turnStopped: () => turnstopped1,
@@ -15345,12 +15675,19 @@ var messages_exports = /* @__PURE__ */ __exportAll({
15345
15675
  browserBack: () => browserback1,
15346
15676
  browserChipLabel: () => browserchiplabel2,
15347
15677
  browserCloseDelete: () => browserclosedelete2,
15678
+ browserCtxCopyImage: () => browserctxcopyimage3,
15679
+ browserCtxCopyLink: () => browserctxcopylink3,
15680
+ browserCtxOpenImage: () => browserctxopenimage3,
15681
+ browserCtxOpenLink: () => browserctxopenlink3,
15682
+ browserCtxSendRightClick: () => browserctxsendrightclick4,
15348
15683
  browserForward: () => browserforward1,
15349
15684
  browserLaunching: () => browserlaunching1,
15685
+ browserNewTab: () => browsernewtab2,
15350
15686
  browserOpenTitle: () => browseropentitle2,
15351
15687
  browserPanelTitle: () => browserpaneltitle2,
15352
15688
  browserReload: () => browserreload1,
15353
15689
  browserSessionFailed: () => browsersessionfailed2,
15690
+ browserTabCloseTitle: () => browsertabclosetitle3,
15354
15691
  browserUrlPlaceholder: () => browserurlplaceholder2,
15355
15692
  browserWaitingFrames: () => browserwaitingframes2,
15356
15693
  cacheHit: () => cachehit1,
@@ -15705,6 +16042,8 @@ var messages_exports = /* @__PURE__ */ __exportAll({
15705
16042
  stop: () => stop,
15706
16043
  stopStreaming: () => stopstreaming1,
15707
16044
  streaming: () => streaming,
16045
+ subagentAnchorLabel: () => subagentanchorlabel2,
16046
+ subagentCloseAllPanels: () => subagentcloseallpanels3,
15708
16047
  subagentMany: () => subagentmany1,
15709
16048
  subagentOne: () => subagentone1,
15710
16049
  subagentTitleOwns: () => subagenttitleowns2,
@@ -15740,6 +16079,7 @@ var messages_exports = /* @__PURE__ */ __exportAll({
15740
16079
  toolTitleSearch: () => tooltitlesearch2,
15741
16080
  toolTitleToolCall: () => tooltitletoolcall3,
15742
16081
  toolTitleWrite: () => tooltitlewrite2,
16082
+ totalTokens: () => totaltokens1,
15743
16083
  turnFailed: () => turnfailed1,
15744
16084
  turnInFlight: () => turninflight2,
15745
16085
  turnStopped: () => turnstopped1,
@@ -16552,6 +16892,22 @@ function Target($$renderer, $$props) {
16552
16892
  ]));
16553
16893
  }
16554
16894
  //#endregion
16895
+ //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/trash-2.svelte
16896
+ function Trash_2($$renderer, $$props) {
16897
+ let { $$slots, $$events, ...props } = $$props;
16898
+ Icon($$renderer, spread_props([
16899
+ { name: "trash-2" },
16900
+ props,
16901
+ { iconNode: [
16902
+ ["path", { "d": "M10 11v6" }],
16903
+ ["path", { "d": "M14 11v6" }],
16904
+ ["path", { "d": "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" }],
16905
+ ["path", { "d": "M3 6h18" }],
16906
+ ["path", { "d": "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }]
16907
+ ] }
16908
+ ]));
16909
+ }
16910
+ //#endregion
16555
16911
  //#region node_modules/.pnpm/@lucide+svelte@1.35.0_svelte@5.56.10/node_modules/@lucide/svelte/dist/icons/wrench.svelte
16556
16912
  function Wrench($$renderer, $$props) {
16557
16913
  let { $$slots, $$events, ...props } = $$props;
@@ -17619,7 +17975,7 @@ function ThemeToggle($$renderer, $$props) {
17619
17975
  }
17620
17976
  //#endregion
17621
17977
  //#region package.json
17622
- var version = "0.8.3";
17978
+ var version = "0.8.5";
17623
17979
  var dsh = { "webVersion": "0.2.1-rc.3" };
17624
17980
  //#endregion
17625
17981
  //#region src/lib/version.ts
@@ -19311,6 +19667,10 @@ function clampPanelWidth(width, kind) {
19311
19667
  const { minWidth, maxWidth } = appConfig().panel;
19312
19668
  if (kind === "workspace-explorer") return Math.max(520, Math.min(PANEL_WORKSPACE_FILE_MAX_WIDTH, width));
19313
19669
  if (kind === "workspace-file") return Math.max(520, Math.min(PANEL_WORKSPACE_FILE_MAX_WIDTH, width));
19670
+ if (kind === "browser") {
19671
+ const { maxWidth: browserMax } = appConfig().browserWidths;
19672
+ return Math.max(minWidth, Math.min(browserMax, width));
19673
+ }
19314
19674
  return Math.max(minWidth, Math.min(maxWidth, width));
19315
19675
  }
19316
19676
  /** The single zoom bound site — load-side sanitizing and the zoom slider. */
@@ -19322,6 +19682,11 @@ function clampPanelZoom(zoom) {
19322
19682
  function defaultPanelWidth() {
19323
19683
  return clampPanelWidth(appConfig().panel.defaultWidth);
19324
19684
  }
19685
+ /** The glass panel's config-driven default (browser.defaultWidth, clamped
19686
+ * through the browser band) — chip-spawned glasses mint at this width. */
19687
+ function browserPanelWidth() {
19688
+ return clampPanelWidth(appConfig().browserWidths.defaultWidth, "browser");
19689
+ }
19325
19690
  /**
19326
19691
  * The skill shelf's born width (The Shelf Chrome ADR, D5): a name list,
19327
19692
  * not a five-column table — the shelf pins 480 (DEFAULT_PANEL_MIN_WIDTH)
@@ -22925,7 +23290,7 @@ function blockBounds(panels, idx, facts) {
22925
23290
  while (i > 0 && panels[i - 1].kind === "browser") i--;
22926
23291
  const head = panels[i - 1];
22927
23292
  const inFamily = (id, root) => {
22928
- if (id === void 0) return false;
23293
+ if (id === void 0 || root === void 0) return false;
22929
23294
  let cur = id;
22930
23295
  for (let guard = 0; guard < panels.length + 1 && cur !== null; guard++) {
22931
23296
  if (cur === root) return true;
@@ -22946,6 +23311,7 @@ function blockBounds(panels, idx, facts) {
22946
23311
  sessionId = head.sessionId;
22947
23312
  }
22948
23313
  }
23314
+ if (sessionId === null) return [idx, idx];
22949
23315
  for (let guard = 0; guard < panels.length + 1; guard++) {
22950
23316
  const parent = facts.parentOf.get(sessionId) ?? null;
22951
23317
  if (parent === null) break;
@@ -23281,7 +23647,7 @@ function panelRowsFor(input) {
23281
23647
  }
23282
23648
  if (p.kind === "terminal" || p.kind === "prompt-manager" || p.kind === "settings-editor" || p.kind === "skill-shelf" || p.kind === "plugin-rack") return {
23283
23649
  panel: p,
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] : "",
23650
+ title: p.kind === "terminal" ? "Terminal" : 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] : "",
23285
23651
  workspace: null,
23286
23652
  dead: false,
23287
23653
  running: false,
@@ -24724,7 +25090,7 @@ function ConversationHeader($$renderer, $$props) {
24724
25090
  * upward.
24725
25091
  */
24726
25092
  let { sessionId, title, workspace = null, workspaces = [], access = null, agent, agentId = null, isStreaming, transcript = null, subagent = false, plan = null, parentSessionId = null, focused = false, onOpenExplorer = void 0, onOpenBrowser = void 0 } = $$props;
24727
- $$renderer.push(`<header data-svelte="ConversationHeader"${attr_class(`flex items-center gap-3 border-b border-surface-border px-2 py-1 ${focused ? "bg-header-wash" : "bg-surface-elevated"}`)} data-testid="conversation-header"${attr("data-focused", focused ? "true" : "false")}>`);
25093
+ $$renderer.push(`<header data-svelte="ConversationHeader"${attr_class(`flex items-center gap-1 border-b border-surface-border px-2 py-1 ${focused ? "bg-header-wash" : "bg-surface-elevated"}`)} data-testid="conversation-header"${attr("data-focused", focused ? "true" : "false")}>`);
24728
25094
  SessionIdAndName($$renderer, {
24729
25095
  sessionId,
24730
25096
  title,
@@ -30827,13 +31193,13 @@ function FloatingAnchorContainerPopup($$renderer, $$props) {
30827
31193
  * `titleTestId` exists because the header's data-testid is part of
30828
31194
  * each leaf's pinned surface (plan-popup-header, user-message-jumper-header).
30829
31195
  */
30830
- let { open = false, triggerEl = void 0, title = void 0, titleTestId = void 0, popupTestId = "floating-anchor-popup", fitWidth = false, children } = $$props;
31196
+ let { open = false, triggerEl = void 0, title = void 0, titleTestId = void 0, popupTestId = "floating-anchor-popup", fitWidth = false, placement = "left", children } = $$props;
30831
31197
  /** Focus the box — leaves call it through bind:this when an action
30832
31198
  * must hand focus back (the jumper's stay-open jump). */
30833
31199
  function focus() {}
30834
31200
  if (open) {
30835
31201
  $$renderer.push("<!--[0-->");
30836
- $$renderer.push(`<div data-svelte="FloatingAnchorContainerPopup" tabindex="-1"${attr_class(`pointer-events-auto absolute right-full top-1/2 z-50 mr-2 max-h-[60vh] max-w-[80vw] -translate-y-1/2 overflow-y-auto rounded-lg border border-surface-border bg-surface-elevated py-1 shadow-xl outline-none focus:outline-none ${fitWidth ? "w-fit" : "w-96"}`)}${attr("data-testid", popupTestId)}>`);
31202
+ $$renderer.push(`<div data-svelte="FloatingAnchorContainerPopup" tabindex="-1"${attr_class(`pointer-events-auto absolute ${placement === "right" ? "left-full ml-2" : placement === "below" ? "right-0 top-full mt-2" : "right-full mr-2"} ${placement === "below" ? "" : "top-1/2 -translate-y-1/2"} z-50 max-h-[60vh] max-w-[80vw] overflow-y-auto rounded-lg border border-surface-border bg-surface-elevated py-1 shadow-xl outline-none focus:outline-none ${fitWidth ? "w-fit" : "w-96"}`)}${attr("data-testid", popupTestId)}>`);
30837
31203
  if (title !== void 0) {
30838
31204
  $$renderer.push("<!--[0-->");
30839
31205
  $$renderer.push(`<div class="border-b border-surface-border px-2.5 py-1.5 text-[10px] font-medium uppercase tracking-wider text-text-muted"${attr("data-testid", titleTestId)}>${escape_html(title)}</div>`);
@@ -31449,341 +31815,1096 @@ function InjectedShelfButton($$renderer, $$props) {
31449
31815
  });
31450
31816
  }
31451
31817
  //#endregion
31452
- //#region src/lib/components/conversation/panel/ConversationFloatingAnchor.svelte
31453
- function ConversationFloatingAnchor($$renderer, $$props) {
31454
- /**
31455
- * ConversationFloatingAnchor — the conversation page's floating action
31456
- * stack (OCI Floating Host port, 2026-08-23; extracted from the page
31457
- * 2026-08-24): jump and scroll actions beside the transcript they act
31458
- * on — the User Messages button (self-contained with its popup jumper
31459
- * since 2026-08-26; renders only when prompt groups exist) and the
31460
- * far-edge jump. Purely presentational — the viewport and turn groups
31461
- * arrive as props.
31462
- */
31463
- let { groups, container, todos = null, deliverables = null, onfileopen = void 0, jobsessionid = "", shelfentries = void 0, shelfsessionid = "", shelfworkspace = null, shelfpanelid = null, onshelfnote } = $$props;
31464
- if (container !== void 0) {
31465
- $$renderer.push("<!--[0-->");
31466
- FloatingAnchor($$renderer, {
31467
- children: ($$renderer) => {
31468
- PlanButton($$renderer, { todos: todos ?? [] });
31469
- $$renderer.push(`<!----> `);
31470
- DeliverablesButton($$renderer, {
31471
- deliveries: deliverables,
31472
- onfileopen
31473
- });
31474
- $$renderer.push(`<!----> `);
31475
- JobsButton($$renderer, { sessionId: jobsessionid });
31476
- $$renderer.push(`<!----> `);
31477
- if (shelfentries !== void 0) {
31478
- $$renderer.push("<!--[0-->");
31479
- InjectedShelfButton($$renderer, {
31480
- entries: shelfentries,
31481
- sessionId: shelfsessionid,
31482
- workspace: shelfworkspace,
31483
- panelId: shelfpanelid,
31484
- onnote: onshelfnote
31485
- });
31486
- } else $$renderer.push("<!--[-1-->");
31487
- $$renderer.push(`<!--]--> `);
31488
- UserMessagesButton($$renderer, {
31489
- groups,
31490
- container
31491
- });
31492
- $$renderer.push(`<!----> `);
31493
- BackToTheEdgeButton($$renderer);
31494
- $$renderer.push(`<!---->`);
31495
- }});
31496
- } else $$renderer.push("<!--[-1-->");
31497
- $$renderer.push(`<!--]-->`);
31498
- }
31499
- //#endregion
31500
- //#region src/lib/components/conversation/panel/A2aChipStack.svelte
31501
- function A2aChipStack($$renderer, $$props) {
31502
- $$renderer.component(($$renderer) => {
31503
- /**
31504
- * A2aChipStack — the sender panel's read-only delegation-ledger join
31505
- * (W4 4.2): one floating chip per recent exchange THIS panel sent,
31506
- * rendered beside the transcript on the floating-anchor pattern
31507
- * (right-middle stack, per-panel via the embedded anchor host).
31508
- *
31509
- * Honesty contract (PRD risk "Attribution overclaim in UI" + spec-check
31510
- * GAP-5): chip text derives from the row's `state` VERBATIM, all six
31511
- * states distinguished — `replied_approx` renders "may have replied",
31512
- * NEVER the confident "replied" string. The ledger is the truth; this
31513
- * component claims nothing the row does not say.
31514
- *
31515
- * Read-only by construction (BC-2): rows arrive as a prop from the
31516
- * page's EXISTING spine-cadence poll of GET /api/a2a?from= — the chip
31517
- * owns NO fetch, NO timer. Click = the existing panel doorway
31518
- * (addPanelFromSidebar dedupe→select). Dismiss is LOCAL-ONLY visual:
31519
- * rows are durable; the next poll brings a dismissed chip back only
31520
- * when it is still in the page's fetched window.
31521
- */
31522
- let { rows, titles } = $$props;
31523
- /** Local-only visual dismissal — rows are durable; the ledger is truth. */
31524
- let dismissed = /* @__PURE__ */ new Set();
31525
- /** The cap: newest 3 visible + one overflow indicator (spec 4.2). */
31526
- const CHIP_CAP = 3;
31527
- const visible = derived(() => rows.filter((r) => !dismissed.has(r.id)));
31528
- const capped = derived(() => visible().slice(0, CHIP_CAP));
31529
- const overflow = derived(() => Math.max(visible().length - CHIP_CAP, 0));
31530
- /**
31531
- * Chip text derives from the state VERBATIM (spec-check GAP-5): every
31532
- * state distinguished, `replied_approx` hedged as "may have replied" —
31533
- * never a confident claim the row cannot support.
31534
- */
31535
- function labelFor(state) {
31536
- switch (state) {
31537
- case "waiting": return "waiting";
31538
- case "replied_exact": return "replied (exact)";
31539
- case "replied": return "replied";
31540
- case "replied_approx": return "may have replied";
31541
- case "timeout": return "no reply (timeout)";
31542
- case "gone": return "target gone";
31543
- }
31544
- }
31545
- /** The target's display title — the spine title, else the id prefix. */
31546
- function titleFor(toSession) {
31547
- return titles[toSession] ?? toSession.replace(/^session-/, "").slice(0, 8);
31548
- }
31549
- if (visible().length > 0) {
31550
- $$renderer.push("<!--[0-->");
31551
- FloatingAnchor($$renderer, {
31552
- children: ($$renderer) => {
31553
- $$renderer.push(`<!--[-->`);
31554
- const each_array = ensure_array_like(capped());
31555
- for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
31556
- let row = each_array[$$index];
31557
- $$renderer.push(`<div class="a2a-chip-wrap" data-testid="a2a-chip"${attr("data-a2a-state", row.state)}${attr("data-a2a-id", row.id)}><button type="button"${attr_class("a2a-chip", void 0, {
31558
- "tone-waiting": row.state === "waiting",
31559
- "tone-replied-exact": row.state === "replied_exact",
31560
- "tone-replied": row.state === "replied",
31561
- "tone-replied-approx": row.state === "replied_approx",
31562
- "tone-timeout": row.state === "timeout",
31563
- "tone-gone": row.state === "gone"
31564
- })} data-testid="a2a-chip-button"${attr("title", `${stringify(titleFor(row.toSession))} — ${stringify(labelFor(row.state))}`)}>`);
31565
- if (row.state === "waiting") {
31566
- $$renderer.push("<!--[0-->");
31567
- Hourglass($$renderer, { size: 13 });
31568
- } else if (row.state === "replied_exact" || row.state === "replied") {
31569
- $$renderer.push("<!--[1-->");
31570
- Check($$renderer, { size: 13 });
31571
- } else $$renderer.push("<!--[-1-->");
31572
- $$renderer.push(`<!--]--> <span class="a2a-chip-label">${escape_html(labelFor(row.state))}</span></button> <button type="button" class="a2a-dismiss" data-testid="a2a-chip-dismiss" title="hide this chip (the ledger row stays)">`);
31573
- X($$renderer, { size: 11 });
31574
- $$renderer.push(`<!----></button></div>`);
31575
- }
31576
- $$renderer.push(`<!--]--> `);
31577
- if (overflow() > 0) {
31578
- $$renderer.push("<!--[0-->");
31579
- $$renderer.push(`<div class="a2a-chip-overflow" data-testid="a2a-chip-overflow">+${escape_html(overflow())} more</div>`);
31580
- } else $$renderer.push("<!--[-1-->");
31581
- $$renderer.push(`<!--]-->`);
31582
- }});
31583
- } else $$renderer.push("<!--[-1-->");
31584
- $$renderer.push(`<!--]-->`);
31585
- });
31586
- }
31587
- //#endregion
31588
- //#region src/lib/components/conversation/panel/ConversationStatsBar.svelte
31589
- function ConversationStatsBar($$renderer, $$props) {
31590
- $$renderer.component(($$renderer) => {
31591
- /**
31592
- * ConversationStatsBar — the panel's session baseline (ADR 2026-09-08
31593
- * "The Stats Bar", D1/D3/D5): one fixed-height line under the transcript
31594
- * showing what the ledger already proves — turns, steps, tool time,
31595
- * token totals, cache hit. Pure presentation: the panel derives the
31596
- * stats and hands them down; segments whose inputs never reached DSI
31597
- * are omitted, never approximated. Renders nothing before the first
31598
- * assistant message (D5 gate lives in the derive's null return).
31599
- */
31600
- let { stats } = $$props;
31601
- /** 85000 -> "1m25s"; 2400000 -> "40m"; 5400000 -> "1h30m"; 250 -> "250ms". */
31602
- function formatDuration(ms) {
31603
- if (ms < 1e3) return `${ms}ms`;
31604
- const totalSec = Math.floor(ms / 1e3);
31605
- const h = Math.floor(totalSec / 3600);
31606
- const m = Math.floor(totalSec % 3600 / 60);
31607
- const s = totalSec % 60;
31608
- if (h > 0) return `${h}h${m}m`;
31609
- if (m > 0) return s > 0 ? `${m}m${s}s` : `${m}m`;
31610
- return `${s}s`;
31818
+ //#region src/lib/services/conversation/subagent-clock.svelte.ts
31819
+ var SubagentClock = class {
31820
+ /** sessionId → first-sight epoch ms (running rows only). */
31821
+ firstSeen = {};
31822
+ /** sessionId → frozen elapsed ms, set once at the settle observation. */
31823
+ frozen = {};
31824
+ /** The tick's reading — read by elapsedMs so a live tick re-renders. */
31825
+ now = Date.now();
31826
+ /** Feed one spine tick: register unseen running ids, freeze settled
31827
+ * ones, expire ids gone from the feed. Call on every fetch (the
31828
+ * button's poll cadence), not on a timer — this IS the sighting lane. */
31829
+ observe(rows) {
31830
+ const t = Date.now();
31831
+ const seen = /* @__PURE__ */ new Set();
31832
+ for (const row of rows) {
31833
+ seen.add(row.sessionId);
31834
+ if (row.running && this.firstSeen[row.sessionId] === void 0) this.firstSeen[row.sessionId] = t;
31835
+ if (!row.running && this.firstSeen[row.sessionId] !== void 0 && this.frozen[row.sessionId] === void 0) this.frozen[row.sessionId] = t - this.firstSeen[row.sessionId];
31611
31836
  }
31612
- /** 15800 -> "15.8K"; 56300 -> "56.3K"; 15800000 -> "15.8M"; 108000 -> "108K"; 999 -> "999". */
31613
- function formatTokens(n) {
31614
- if (n >= 1e6) return `${(n / 1e6).toFixed(1).replace(/\.0$/, "")}M`;
31615
- if (n >= 1e3) return `${(n / 1e3).toFixed(1).replace(/\.0$/, "")}K`;
31616
- return String(n);
31837
+ for (const id of Object.keys(this.firstSeen)) if (!seen.has(id)) {
31838
+ delete this.firstSeen[id];
31839
+ delete this.frozen[id];
31617
31840
  }
31618
- const segments = derived(() => {
31619
- if (stats === null) return [];
31620
- const parts = [`${stats.turns} turns · ${stats.steps} steps`];
31621
- const durations = [];
31622
- if (stats.llmMs !== void 0 && stats.llmMs > 0) durations.push(`LLM ${formatDuration(stats.llmMs)}`);
31623
- if (stats.toolMs > 0) durations.push(`Tool ${formatDuration(stats.toolMs)}`);
31624
- if (durations.length > 0) parts.push(durations.join(" · "));
31625
- const speeds = [];
31626
- if (stats.ttftSteps !== void 0 && stats.ttftSteps > 0 && stats.ttftMs !== void 0) speeds.push(`TTFT avg ${formatDuration(stats.ttftMs / stats.ttftSteps)}`);
31627
- if (stats.decodeMs !== void 0 && stats.decodeMs > 0 && stats.decodeTokens !== void 0) speeds.push(`${Math.max(1, Math.round(stats.decodeTokens / (stats.decodeMs / 1e3)))} tok/s`);
31628
- if (speeds.length > 0) parts.push(speeds.join(" · "));
31629
- const inputTotal = stats.billedInputTokens ?? stats.inputTokens;
31630
- if (inputTotal !== void 0) parts.push(`Input ${formatTokens(inputTotal)} tok · Output ${formatTokens(stats.outputTokens ?? 0)} tok`);
31631
- if (stats.cacheHitPercent !== void 0) parts.push(`Cache hit ${stats.cacheHitPercent}%`);
31632
- return parts;
31633
- });
31634
- if (stats !== null) {
31635
- $$renderer.push("<!--[0-->");
31636
- $$renderer.push(`<div data-svelte="ConversationStatsBar" class="stats-bar svelte-hnxn10" data-testid="conversation-stats-bar"${attr("title", segments().join(" | "))}><!--[-->`);
31637
- const each_array = ensure_array_like(segments());
31638
- for (let i = 0, $$length = each_array.length; i < $$length; i++) {
31639
- let segment = each_array[i];
31640
- if (i > 0) {
31641
- $$renderer.push("<!--[0-->");
31642
- $$renderer.push(`<span class="sep svelte-hnxn10" aria-hidden="true">|</span>`);
31643
- } else $$renderer.push("<!--[-1-->");
31644
- $$renderer.push(`<!--]--> <span class="segment svelte-hnxn10" data-testid="stats-segment">${escape_html(segment)}</span>`);
31645
- }
31646
- $$renderer.push(`<!--]--></div>`);
31647
- } else $$renderer.push("<!--[-1-->");
31648
- $$renderer.push(`<!--]-->`);
31649
- });
31650
- }
31651
- //#endregion
31652
- //#region src/lib/components/conversation/panel/submit-ladder.svelte.ts
31653
- var SubmitLadder = class {
31654
- deps;
31655
- /** True while the plain-send rung is in flight — the footer's sending flag. */
31656
- submitted = false;
31657
- /** Inline command feedback (role=status, auto-dismiss 5s) — the ONLY
31658
- * command UI surface; the input has already cleared by intercept time.
31659
- * The wire work lives in command-executor (Prompt Macro W1 1.2): the
31660
- * /new create+swap, /permission route, and mention delivery are the
31661
- * SAME bytes the typed path always sent — the panel now renders
31662
- * outcomes only (banner kind from result.ok). */
31663
- commandNote = null;
31664
- commandNoteTimer;
31665
- constructor(deps) {
31666
- this.deps = deps;
31667
- }
31668
- /** Inline command feedback — every rung banners through here. */
31669
- noteCommand(kind, text) {
31670
- this.commandNote = {
31671
- kind,
31672
- text
31673
- };
31674
- if (this.commandNoteTimer !== void 0) clearTimeout(this.commandNoteTimer);
31675
- this.commandNoteTimer = setTimeout(() => this.commandNote = null, 5e3);
31841
+ this.now = t;
31676
31842
  }
31677
- async onsubmit(text, images) {
31678
- if (isTypedRun(text)) {
31679
- this.deps.startMacro({
31680
- text,
31681
- id: -1
31682
- }, false);
31683
- return true;
31684
- }
31685
- const command = parseCommand(text);
31686
- if (command !== null) {
31687
- let bannered = false;
31688
- const result = await executeCommand(command, this.deps.ctx(), (ok, note) => {
31689
- bannered = true;
31690
- this.noteCommand(ok ? "ok" : "error", note);
31691
- });
31692
- if (!bannered && result.note !== void 0) this.noteCommand(result.ok ? "ok" : "error", result.note);
31693
- return true;
31694
- }
31695
- if (text.trim().length === 0 && images.length === 0) return false;
31696
- const slashCatalog = this.deps.slashCatalog;
31697
- if (slashCatalog?.state === "ready") {
31698
- if (resolveHostCommand(text, slashCatalog.commands) !== null) return (await executeHostCommand(text, this.deps.ctx(), (ok, note) => this.noteCommand(ok ? "ok" : "error", note))).ok;
31699
- }
31700
- this.submitted = true;
31701
- try {
31702
- return (await sendPrompt(text, this.deps.ctx(), (t) => this.deps.orchestrator.submit(t, images))).ok;
31703
- } finally {
31704
- this.submitted = false;
31705
- }
31843
+ /** Live tick — the open popup calls this on its 1s interval so a
31844
+ * running row's elapsed advances between polls. */
31845
+ tick() {
31846
+ this.now = Date.now();
31706
31847
  }
31707
- async oncancel() {
31708
- await this.deps.orchestrator.cancel();
31848
+ /** Elapsed ms for one id: the frozen settle delta, or now − firstSeen
31849
+ * for a running row, or null when there is NO honest sample (never
31850
+ * sighted running, or first seen already settled). */
31851
+ elapsedMs(id) {
31852
+ const frozen = this.frozen[id];
31853
+ if (frozen !== void 0) return frozen;
31854
+ const t0 = this.firstSeen[id];
31855
+ if (t0 === void 0) return null;
31856
+ return Math.max(0, this.now - t0);
31709
31857
  }
31710
- /** Menu command pick: the SAME rung the ladder uses (one execution
31711
- * surface, D2), banner notes through the shared note path; the
31712
- * boolean admits the composer's draft clearing (BC-A3). */
31713
- async onpickcommand(line) {
31714
- return (await executeHostCommand(line, this.deps.ctx(), (ok, note) => this.noteCommand(ok ? "ok" : "error", note))).ok;
31858
+ /** Does the id carry any sample at all (frozen or live)? */
31859
+ sighted(id) {
31860
+ return this.frozen[id] !== void 0 || this.firstSeen[id] !== void 0;
31715
31861
  }
31716
31862
  };
31717
- //#endregion
31718
- //#region src/lib/utils/auto-open-slots.ts
31719
- /** The newest reasoning entry's id (wire order), else null — the
31720
- * transient think target. Empty reasoning strings do not count (the
31721
- * chip renders nothing to open). */
31722
- function newestReasoningId(entries) {
31723
- for (let i = entries.length - 1; i >= 0; i--) {
31724
- const e = entries[i];
31725
- if (e.kind === "assistant-message" && e.reasoning !== void 0 && e.reasoning !== "") return e.id;
31726
- }
31727
- return null;
31863
+ /** The desk-lifetime singleton — one registry per page visit (ADR D3). */
31864
+ var subagentClock = new SubagentClock();
31865
+ /**
31866
+ * The open workspace explorer for a workspace ROOT — The Shared Tree ADR
31867
+ * (2026-09-17) D1's dedupe key: ONE explorer per ROOT across ALL sessions,
31868
+ * so a chip click on any session sharing the root FOCUSES instead of
31869
+ * adding (a duplicate is a bug, not a feature). The retired per-session
31870
+ * key ("two sessions sharing one workspace hold distinct explorers",
31871
+ * Workspace Explorer D4) produced N byte-identical trees for N sessions.
31872
+ */
31873
+ function findWorkspaceExplorerPanel(panels, root) {
31874
+ return panels.find((p) => p.kind === "workspace-explorer" && p.root === root);
31728
31875
  }
31729
- /** Suppression-aware view of a raw target: null while the user kept THIS
31730
- * id collapsed (a newer target id simply stops matching). */
31731
- function suppressed(targetId, suppressedId) {
31732
- return targetId !== null && suppressedId === targetId ? null : targetId;
31876
+ /**
31877
+ * The explorer's slot (The Shared Tree ADR 2026-09-17, D3): the FOCUSED
31878
+ * slot — the explorer is NOT a lineage child; a workspace tree has no
31879
+ * parent session, only an opener. The retired after-source rule
31880
+ * (Workspace Explorer D3, "Parent → explorer → file") interposed the
31881
+ * panel inside a conversation's family unit — the family clamp inside
31882
+ * focusedInsertionSlot still keeps any real family unsplit.
31883
+ */
31884
+ function workspaceExplorerSlot(panels, selectedIndex, facts) {
31885
+ return focusedInsertionSlot(panels, selectedIndex, facts.parentOf);
31733
31886
  }
31734
- //#endregion
31735
- //#region src/lib/components/conversation/panel/popups.svelte.ts
31736
- var Popups = class {
31737
- /** Chip popup state (2026-08-22, OCI pattern): ONE open chip at a time —
31738
- * the id of the expanded entry; detail renders AFTER the chip row.
31739
- * Per-panel by construction (moved here with the block). */
31740
- openChipId = null;
31741
- /** Peek popup state (ToolPeekButton port, 2026-08-22): the run key whose
31742
- * chip row has its list popup open — ONE at a time, and never while a
31743
- * chip detail popup is open (OCI mutual-exclusion contract). */
31744
- peekOpenRunKey = null;
31745
- thinkSuppressedId = null;
31746
- planSuppressedId = null;
31747
- /** The newest todo_write entry's id, STICKY: adopted only while
31748
- * streaming AND stuck (the detection window), then kept across newer
31749
- * thinks, turn end, and scroll-away — the plan stays on screen until
31750
- * a newer todo_write supersedes it or the user collapses it. */
31751
- autoPlanIdRaw = null;
31752
- deps;
31753
- stopPlanEffect;
31754
- constructor(deps) {
31755
- this.deps = deps;
31756
- this.stopPlanEffect = () => {};
31757
- }
31758
- destroy() {
31759
- this.stopPlanEffect();
31760
- }
31761
- /** The newest reasoning entry's id (wire order) while streaming AND
31762
- * stuck to the live end, else null — the transient think target. */
31763
- get autoThinkTargetId() {
31764
- if (!this.deps.store.isStreaming || !this.deps.stick) return null;
31765
- return newestReasoningId(this.deps.store.renderEntries);
31766
- }
31767
- /** Suppression-aware think target: null while the user kept THIS think
31768
- * collapsed (a newer think id simply stops matching). */
31769
- get autoThinkId() {
31770
- return suppressed(this.autoThinkTargetId, this.thinkSuppressedId);
31771
- }
31772
- /** Suppression-aware plan target (same id-tied rule as the think). */
31773
- get autoPlanId() {
31774
- return suppressed(this.autoPlanIdRaw, this.planSuppressedId);
31775
- }
31776
- toggleChip(id, autoOpen = false) {
31777
- if (autoOpen) {
31778
- if (id === this.autoPlanId) this.planSuppressedId = id;
31779
- else if (this.autoThinkId !== null && id === `r:${this.autoThinkId}`) this.thinkSuppressedId = this.autoThinkId;
31780
- return;
31781
- }
31782
- this.openChipId = this.openChipId === id ? null : id;
31783
- this.peekOpenRunKey = null;
31784
- }
31785
- togglePeek(runKey) {
31786
- this.peekOpenRunKey = this.peekOpenRunKey === runKey ? null : runKey;
31887
+ /**
31888
+ * The glass FIRST slot under its opener (operator ruling 2026-10-24):
31889
+ * a summoned/spawned glass lands DIRECTLY below its opener - past the
31890
+ * opener document tail, BEFORE every adopted child - matching the
31891
+ * spine tree wire order -1 (the ghost always reads as the first
31892
+ * child). Supersedes the region-end placement for the glass only.
31893
+ */
31894
+ function glassFirstSlot(panels, openedBy) {
31895
+ const openerIdx = panels.findIndex((p) => p.kind === "conversation" && p.sessionId === openedBy);
31896
+ if (openerIdx === -1) return panels.length;
31897
+ return docTailEnd(panels, openerIdx, openedBy) + 1;
31898
+ }
31899
+ /**
31900
+ * Insert-before-focused slot (operator spec, 2026-08-31): a fresh panel
31901
+ * lands at the FOCUSED panel's index — immediately before it — and takes
31902
+ * focus (the route selects it). 0 when nothing is focused (empty floor,
31903
+ * stale selection) — the old front-add stays the fallback. Math.max keeps
31904
+ * splice's negative-index semantics out of the no-selection case.
31905
+ *
31906
+ * Family clamp (lineage I2): a slot strictly inside a family would wedge
31907
+ * the newcomer between a spawner and its pinned child — unitOf/blockBounds,
31908
+ * the sidebar's familyRenderOrder, and the adoption slot walk all assume
31909
+ * families stay contiguous on the floor. When the focus is a family CHILD,
31910
+ * the slot climbs to the family head — the nearest non-splitting slot left
31911
+ * of the focus (parentOf only carries on-floor parents, so an orphan child
31912
+ * is a root here, its own unit). A lone panel or a family head keeps the
31913
+ * exact focus slot.
31914
+ *
31915
+ * Manager focus (ADR D6): no session, no family — the slot is the focus
31916
+ * itself.
31917
+ *
31918
+ * Workspace member focus (2026-09-10): the explorer/file pair is a family
31919
+ * unit in the SAME block math (blockBounds — the Loadinjected D3 walk-back
31920
+ * grammar), so the clamp is the SAME one: insert at the unit head — the
31921
+ * PARENT position, left of the block — never between explorer and file.
31922
+ */
31923
+ function focusedInsertionSlot(panels, selectedIndex, parentOf) {
31924
+ const focus = Math.max(0, selectedIndex);
31925
+ const focused = panels[focus];
31926
+ if (focused === void 0) return 0;
31927
+ if (focused.kind === "workspace-explorer" || focused.kind === "workspace-file" || focused.kind === "browser") {
31928
+ const block = blockBounds(panels, focus, { parentOf });
31929
+ return block === null ? focus : block[0];
31930
+ }
31931
+ if (focused.kind !== "conversation") return focus;
31932
+ let head = focused.sessionId;
31933
+ for (;;) {
31934
+ const parent = parentOf.get(head) ?? null;
31935
+ if (parent === null) break;
31936
+ head = parent;
31937
+ }
31938
+ if (head === focused.sessionId) return focus;
31939
+ const headIndex = panels.findIndex((p) => p.kind === "conversation" && p.sessionId === head);
31940
+ return headIndex >= 0 ? Math.min(headIndex, focus) : focus;
31941
+ }
31942
+ //#endregion
31943
+ //#region src/lib/services/panels/floor-registry/chrome.ts
31944
+ /**
31945
+ * floor-registry/chrome — panel chrome intents + explorer + file-intent
31946
+ * mailbox + removal (ADR-0022 W3).
31947
+ *
31948
+ * Moved WHOLE from the state home (floor-registry.svelte.ts): the
31949
+ * skill-shelf / plugin-rack chrome setters, the ONE-explorer-per-workspace
31950
+ * open grammar, the explorer tree/tab/git intents, the file-intent
31951
+ * publish/consume mailbox, and family-close removal. Plain module: every
31952
+ * write goes through the state home's reactive `st` hub and its
31953
+ * primitives (ADR-0019 D2: exactly ONE writer home for floor state).
31954
+ * Sibling rule: factories/slots are reached through the state home's
31955
+ * re-export hub, never by importing another sibling directly.
31956
+ */
31957
+ var d$4 = floorSeam;
31958
+ /** Chip click action: ONE explorer per WORKSPACE root across ALL
31959
+ * sessions — a click on any session sharing the root FOCUSES the open
31960
+ * explorer (dedupe key = root, D1); a fresh root lands at the focused
31961
+ * slot (D3, non-lineage — the explorer is not a lineage child).
31962
+ * sessionId rides the fresh panel as PROVENANCE (D4), never identity. */
31963
+ function openWorkspaceExplorer(sessionId, workspace) {
31964
+ const open = findWorkspaceExplorerPanel(st.panels, workspace);
31965
+ if (open) {
31966
+ st.selectedPanelId = open.id;
31967
+ return;
31968
+ }
31969
+ insertPanel(makeWorkspaceExplorerPanel(sessionId, workspace), workspaceExplorerSlot(st.panels, selectedIndex_(), d$4().getMoveFacts()));
31970
+ }
31971
+ /** Chip click action (The Glass Browser spec W2, ADR-0029 D4): ONE live
31972
+ * browser panel across the floor — the terminal singleton rule (Terminal
31973
+ * Desk ADR D2). A click on an open browser FOCUSES it; a miss inserts at
31974
+ * the focused slot. */
31975
+ function openBrowserPanel(index, keepSelection = false, width, openedBy, sessionId) {
31976
+ const open = st.panels.find((p) => p.kind === "browser" && p.openedBy === openedBy);
31977
+ if (open) {
31978
+ st.selectedPanelId = open.id;
31979
+ return;
31980
+ }
31981
+ const prevSelected = st.selectedPanelId;
31982
+ const slot = index !== void 0 ? Math.max(0, Math.min(index, st.panels.length)) : openedBy !== void 0 ? glassFirstSlot(st.panels, openedBy) : insertionSlot();
31983
+ insertPanel(makeBrowserPanel(width, openedBy, sessionId), slot);
31984
+ if (keepSelection && prevSelected !== null && prevSelected !== void 0) {
31985
+ if (st.panels.some((p) => p.id === prevSelected)) st.selectedPanelId = prevSelected;
31986
+ }
31987
+ }
31988
+ /** The open explorer for a session's workspace (The Shared Tree D1):
31989
+ * matched by ROOT across sessions — the panel's provenance sessionId
31990
+ * is not the key. */
31991
+ function sessionWorkspaceExplorer(sessionId) {
31992
+ const root = d$4().getWorkspaceFor(sessionId);
31993
+ return root === null ? void 0 : findWorkspaceExplorerPanel(st.panels, root);
31994
+ }
31995
+ /** Explorer tree intents: the panel emits toggle/open-file; the owner
31996
+ * mutates expanded (the persisted part) — the levels cache stays
31997
+ * component-local. */
31998
+ function toggleExplorerPath(panelId, path) {
31999
+ const idx = st.panels.findIndex((p) => p.id === panelId);
32000
+ if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
32001
+ const explorer = st.panels[idx];
32002
+ const next = explorer.expanded.includes(path) ? explorer.expanded.filter((p) => p !== path) : [...explorer.expanded, path];
32003
+ st.panels = st.panels.with(idx, {
32004
+ ...explorer,
32005
+ expanded: next
32006
+ });
32007
+ }
32008
+ /** Explorer collapse-all intent: the panel emits; the owner empties the
32009
+ * expanded list (the persisted part). */
32010
+ function collapseExplorerPaths(panelId) {
32011
+ const idx = st.panels.findIndex((p) => p.id === panelId);
32012
+ if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
32013
+ st.panels = st.panels.with(idx, {
32014
+ ...st.panels[idx],
32015
+ expanded: []
32016
+ });
32017
+ }
32018
+ /** Git Eye tab intent (2026-09-12): the active tab is PERSISTED on the
32019
+ * entry — a hard reload restores it. */
32020
+ function setExplorerTab(panelId, tab) {
32021
+ const idx = st.panels.findIndex((p) => p.id === panelId);
32022
+ if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
32023
+ st.panels = st.panels.with(idx, {
32024
+ ...st.panels[idx],
32025
+ tab
32026
+ });
32027
+ }
32028
+ /** Explorer Layout tabs (amendment 2026-09-16): the tab list and the
32029
+ * active tab are OWNER-PERSISTED entry facts. The file tabs die with
32030
+ * the panel (D5). */
32031
+ function openExplorerTab(panelId, path) {
32032
+ const idx = st.panels.findIndex((p) => p.id === panelId);
32033
+ if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
32034
+ const ex = st.panels[idx];
32035
+ const tabs = ex.openTabs ?? [];
32036
+ const openTabs = tabs.includes(path) ? tabs : [...tabs, path];
32037
+ st.panels = st.panels.with(idx, {
32038
+ ...ex,
32039
+ openTabs,
32040
+ activeFile: path
32041
+ });
32042
+ }
32043
+ function closeExplorerTab(panelId, path) {
32044
+ const idx = st.panels.findIndex((p) => p.id === panelId);
32045
+ if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
32046
+ const ex = st.panels[idx];
32047
+ const tabs = ex.openTabs ?? [];
32048
+ const closedAt = tabs.indexOf(path);
32049
+ if (closedAt === -1) return;
32050
+ const openTabs = tabs.filter((p) => p !== path);
32051
+ const activeFile = ex.activeFile === path ? openTabs.length === 0 ? null : openTabs[Math.max(0, closedAt - 1)] : ex.activeFile ?? null;
32052
+ st.panels = st.panels.with(idx, {
32053
+ ...ex,
32054
+ openTabs,
32055
+ activeFile
32056
+ });
32057
+ }
32058
+ function activateExplorerTab(panelId, path) {
32059
+ const idx = st.panels.findIndex((p) => p.id === panelId);
32060
+ if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
32061
+ const ex = st.panels[idx];
32062
+ if (!(ex.openTabs ?? []).includes(path)) return;
32063
+ st.panels = st.panels.with(idx, {
32064
+ ...ex,
32065
+ activeFile: path
32066
+ });
32067
+ }
32068
+ /** The Explorer Layout drag settle (ADR D4): one DESK fact — the split
32069
+ * is desk state, persisted with the floor blob, NOT per entry. The
32070
+ * panel already clamped; clamp again at the single bound site. */
32071
+ function setExplorerTreePct(_panelId, pct) {
32072
+ d$4().setTreePct(clampTreePct(pct));
32073
+ }
32074
+ /** Git Eye repo-collapse intent (2026-09-13): the collapsed repo set is
32075
+ * PERSISTED on the entry. Default is EXPANDED. */
32076
+ function toggleExplorerRepo(panelId, repoRel) {
32077
+ const idx = st.panels.findIndex((p) => p.id === panelId);
32078
+ if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
32079
+ const explorer = st.panels[idx];
32080
+ const prev = explorer.collapsedRepos ?? [];
32081
+ const next = prev.includes(repoRel) ? prev.filter((r) => r !== repoRel) : [...prev, repoRel];
32082
+ st.panels = st.panels.with(idx, {
32083
+ ...explorer,
32084
+ collapsedRepos: next
32085
+ });
32086
+ }
32087
+ /** Git Eye collapse-all-repos intent (2026-09-13): collapses EVERY known
32088
+ * repo — persisted like the single-repo toggle. */
32089
+ function collapseExplorerRepos(panelId, repos) {
32090
+ const idx = st.panels.findIndex((p) => p.id === panelId);
32091
+ if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
32092
+ const explorer = st.panels[idx];
32093
+ const prev = explorer.collapsedRepos ?? [];
32094
+ const next = [...prev, ...repos.filter((r) => !prev.includes(r))];
32095
+ st.panels = st.panels.with(idx, {
32096
+ ...explorer,
32097
+ collapsedRepos: next
32098
+ });
32099
+ }
32100
+ /** File Eye view intent (2026-09-13): diff vs edit is PERSISTED on the
32101
+ * entry. */
32102
+ function setFileView(panelId, view) {
32103
+ const idx = st.panels.findIndex((p) => p.id === panelId);
32104
+ if (idx < 0 || st.panels[idx].kind !== "workspace-file") return;
32105
+ st.panels = st.panels.with(idx, {
32106
+ ...st.panels[idx],
32107
+ view
32108
+ });
32109
+ }
32110
+ /** Tree file-click action (The Settings Tree ADR 2026-09-18 D1): the
32111
+ * intent publishes to the session's explorer, which opens/focuses a
32112
+ * tab. No open explorer ⇒ the intent drops. */
32113
+ function openWorkspaceFile(sessionId, path, lines) {
32114
+ const host = sessionWorkspaceExplorer(sessionId);
32115
+ if (host) publishFileIntent(host.id, path, lines);
32116
+ }
32117
+ /** Publish a file intent to an explorer panel and focus it. `lines` is
32118
+ * the optional #L anchor target — display metadata, not persisted. */
32119
+ function publishFileIntent(explorerId, path, lines) {
32120
+ st.pendingFileIntents[explorerId] = {
32121
+ path,
32122
+ nonce: ++st.fileIntentSeq,
32123
+ lines: lines ?? null
32124
+ };
32125
+ st.selectedPanelId = explorerId;
32126
+ }
32127
+ /** The panel consumed intent nonce N — clear exactly that publish. */
32128
+ function consumeFileIntent(explorerId, nonce) {
32129
+ if (st.pendingFileIntents[explorerId]?.nonce === nonce) st.pendingFileIntents[explorerId] = null;
32130
+ }
32131
+ /** Remove a panel; family close walks the wire lineage transitively
32132
+ * (every descendant sub-agent goes with it, nested included). The
32133
+ * Shift+Click amendment (2026-09-01): family === false opts OUT — only
32134
+ * THAT panel drops, the children re-root as orphan family heads.
32135
+ *
32136
+ * The session's workspace pair closes with it (2026-09-10); closing an
32137
+ * EXPLORER dooms its file children BY PANEL ID — the stored
32138
+ * explorerPanelId edge, with the legacy null-edge fallback. A
32139
+ * settings-home explorer (sessionId null) dies with the close. */
32140
+ function removePanel(panelId, opts = {}) {
32141
+ const idx = st.panels.findIndex((p) => p.id === panelId);
32142
+ if (idx < 0) return;
32143
+ const root = st.panels[idx];
32144
+ const rootSessionId = root.kind === "conversation" ? root.sessionId : null;
32145
+ const doomed = new SvelteSet(rootSessionId !== null ? [rootSessionId] : []);
32146
+ if (opts.family !== false && rootSessionId !== null) {
32147
+ const stack = [rootSessionId];
32148
+ while (stack.length > 0) for (const kid of d$4().getLineageFacts().childrenByParent.get(stack.pop()) ?? []) if (!doomed.has(kid.sessionId)) {
32149
+ doomed.add(kid.sessionId);
32150
+ stack.push(kid.sessionId);
32151
+ }
32152
+ }
32153
+ const doomedPanelIds = new SvelteSet();
32154
+ if (opts.family !== false && rootSessionId !== null) {
32155
+ for (const p of st.panels) if (p.kind === "browser" && p.openedBy !== void 0 && doomed.has(p.openedBy)) doomedPanelIds.add(p.id);
32156
+ }
32157
+ if (opts.family !== false && root.kind === "workspace-explorer") {
32158
+ 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);
32159
+ }
32160
+ st.panels = st.panels.filter((p) => p.id !== root.id && !doomedPanelIds.has(p.id) && (p.kind === "conversation" ? !doomed.has(p.sessionId) : !("sessionId" in p) || p.sessionId === null || opts.family !== false && !doomed.has(p.sessionId)));
32161
+ if (st.selectedPanelId !== null && !st.panels.some((p) => p.id === st.selectedPanelId)) st.selectedPanelId = st.panels[Math.min(idx, st.panels.length - 1)]?.id ?? null;
32162
+ clearLoupeIfGone();
32163
+ }
32164
+ //#endregion
32165
+ //#region src/lib/services/panels/floor-registry/drag.svelte.ts
32166
+ var d$2 = floorSeam;
32167
+ /** Honest-slider's "slider sets all panels" leg (REALTIME, 2026-08-27):
32168
+ * one width for every CONVERSATION column + the uniform preset.
32169
+ * 2026-09-13: the workspace kinds are FIXED lanes — the explorer and
32170
+ * file panels keep their own widths. */
32171
+ function resizeAll(width) {
32172
+ const w = clampPanelWidth(width);
32173
+ d$2().setPanelWidthPreset(w);
32174
+ st.panels = st.panels.map((p) => p.kind === "conversation" ? {
32175
+ ...p,
32176
+ width: w
32177
+ } : p);
32178
+ }
32179
+ /** A transcript file link publishes ONLY after the tree route proves
32180
+ * the file exists inside the session's workspace — the gate lives in
32181
+ * the shared util; anything else drops the click. No navigation ever
32182
+ * happens. No explorer yet ⇒ OPEN ONE (amendment 2026-09-25): the link
32183
+ * itself opens the panel; without a workspace root there is nothing to
32184
+ * open. W2 (T2.3): moved wholesale from the route — pure machine over
32185
+ * the deps seam + the shared utils. */
32186
+ async function openFileLinkFromMarkdown(sessionId, rawHref) {
32187
+ const { path, lines } = parseFileLinkHref(rawHref);
32188
+ if (path === "") return;
32189
+ const target = await resolveFileLinkTarget(sessionId, path, d$2().getWorkspaceFor(sessionId), void 0, workspaceRootDirs);
32190
+ if (target === null) return;
32191
+ if (!sessionWorkspaceExplorer(sessionId)) {
32192
+ const root = d$2().getWorkspaceFor(sessionId);
32193
+ if (!root) return;
32194
+ openWorkspaceExplorer(sessionId, root);
32195
+ }
32196
+ openWorkspaceFile(sessionId, target, lines);
32197
+ }
32198
+ /** /events?full=1 carries entries+lastSeq+running+pending/settled
32199
+ * answers (the ledger-tail resync surface); /history carries hasMore.
32200
+ * Its beforeSeq anchor needs the tail's lastSeq, so the events response
32201
+ * resolves first — the only serialization. W2 (T2.6): moved wholesale
32202
+ * from the route — a pure wire read over the global fetch. */
32203
+ async function fetchColdFromWire(sessionId) {
32204
+ const eventsRes = await fetch(`/api/dsh/session/${encodeURIComponent(sessionId)}/events?full=1`);
32205
+ if (!eventsRes.ok) return null;
32206
+ const events = await eventsRes.json();
32207
+ if (!events.ok) return null;
32208
+ const lastSeq = events.lastSeq ?? -1;
32209
+ let hasMore = false;
32210
+ const historyRes = await fetch(`/api/dsh/session/${encodeURIComponent(sessionId)}/history?beforeSeq=${lastSeq + 1}`);
32211
+ if (historyRes.ok) {
32212
+ const history = await historyRes.json();
32213
+ if (history.ok) hasMore = (history.entries?.length ?? 0) > 0 || history.hasMore === true;
32214
+ }
32215
+ return {
32216
+ title: null,
32217
+ workspace: null,
32218
+ agentPreset: null,
32219
+ entries: events.entries ?? [],
32220
+ lastSeq,
32221
+ running: events.running ?? false,
32222
+ hasMore,
32223
+ pendingAnswers: events.pendingAnswers ?? [],
32224
+ settledAnswers: events.settledAnswers ?? [],
32225
+ permission: events.permission ?? null,
32226
+ imageLimits: events.imageLimits ?? null,
32227
+ knobEvents: events.knobEvents ?? [],
32228
+ deliverables: events.deliverables ?? []
32229
+ };
32230
+ }
32231
+ //#endregion
32232
+ //#region src/lib/services/panels/floor-registry/factories.ts
32233
+ /**
32234
+ * floor-registry/factories — panel factories + placement slots (ADR-0022 W2).
32235
+ *
32236
+ * Moved WHOLE from the state home (floor-registry.svelte.ts): the eight
32237
+ * make* panel factories and the slot grammar (insertPanel, insertionSlot,
32238
+ * pinnedSlotIndex). Plain module: no runes here — every write goes through
32239
+ * the state home's reactive `st` hub and its primitives (ADR-0019 D2:
32240
+ * exactly ONE writer home for floor state). Sibling rule: this file never
32241
+ * imports another sibling; shared needs come from the state home.
32242
+ */
32243
+ var d$1 = floorSeam;
32244
+ function makePanel(sessionId, agentPreset) {
32245
+ return {
32246
+ id: nextPanelId(),
32247
+ kind: "conversation",
32248
+ sessionId,
32249
+ agentPreset,
32250
+ width: clampPanelWidth(d$1().getPanelWidth())
32251
+ };
32252
+ }
32253
+ /** width: the reload-restored panel re-mints at the width the operator
32254
+ * dragged before (browser-slot persistence, RCA 2026-10-22); absent for
32255
+ * chip clicks and legacy slots — the honest-slider preset.
32256
+ * openedBy: the opener session's provenance, recorded ONCE at spawn and
32257
+ * never rewritten (ADR-0036 D1/D2); undefined = no conversation context. */
32258
+ function makeBrowserPanel(width, openedBy, sessionId) {
32259
+ return {
32260
+ id: nextPanelId(),
32261
+ kind: "browser",
32262
+ width: clampPanelWidth(width ?? browserPanelWidth(), "browser"),
32263
+ ...openedBy !== void 0 ? { openedBy } : {},
32264
+ ...sessionId !== void 0 ? { browserSessionId: sessionId } : {}
32265
+ };
32266
+ }
32267
+ function makeWorkspaceExplorerPanel(sessionId, root) {
32268
+ return {
32269
+ id: nextPanelId(),
32270
+ kind: "workspace-explorer",
32271
+ sessionId,
32272
+ root,
32273
+ expanded: [],
32274
+ width: clampPanelWidth(850, "workspace-explorer")
32275
+ };
32276
+ }
32277
+ function insertPanel(entry, index) {
32278
+ const next = [...st.panels];
32279
+ next.splice(Math.min(index, next.length), 0, entry);
32280
+ st.panels = next;
32281
+ st.selectedPanelId = entry.id;
32282
+ }
32283
+ function insertionSlot() {
32284
+ return focusedInsertionSlot(st.panels, selectedIndex_(), d$1().getMoveFacts().parentOf);
32285
+ }
32286
+ //#endregion
32287
+ //#region src/lib/services/panels/floor-registry.svelte.ts
32288
+ var deps = null;
32289
+ function configureFloorRegistry(d0) {
32290
+ deps = d0;
32291
+ }
32292
+ function d() {
32293
+ if (deps === null) throw new Error("floor-registry: configureFloorRegistry() was never called");
32294
+ return deps;
32295
+ }
32296
+ /** Sibling-module access to the dep seam (ADR-0022 W2): the ONE outside-reads
32297
+ * channel; siblings never open their own config channel. */
32298
+ function floorSeam() {
32299
+ return d();
32300
+ }
32301
+ var st = {
32302
+ panels: [],
32303
+ selectedPanelId: null,
32304
+ loupePanelId: null,
32305
+ focusComposerId: null,
32306
+ panelIdSeq: 0,
32307
+ terminalDeskMirrors: {},
32308
+ pendingFileIntents: {},
32309
+ fileIntentSeq: 0,
32310
+ drag: null,
32311
+ widthBadgeFading: false
32312
+ };
32313
+ /** Non-reactive gesture refs (drag start index, fade timer, badge ids) —
32314
+ * written by floor-registry/drag.svelte.ts; the ids set is a live
32315
+ * SvelteSet so badge visibility stays reactive. */
32316
+ var dragRefs = {
32317
+ ids: new SvelteSet()
32318
+ };
32319
+ var floor = {
32320
+ get panels() {
32321
+ return st.panels;
32322
+ },
32323
+ get selectedPanelId() {
32324
+ return st.selectedPanelId;
32325
+ },
32326
+ get loupePanelId() {
32327
+ return st.loupePanelId;
32328
+ },
32329
+ get focusComposerId() {
32330
+ return st.focusComposerId;
32331
+ },
32332
+ get terminalDeskMirrors() {
32333
+ return st.terminalDeskMirrors;
32334
+ },
32335
+ get pendingFileIntents() {
32336
+ return st.pendingFileIntents;
32337
+ },
32338
+ get drag() {
32339
+ return st.drag;
32340
+ },
32341
+ get widthBadgeFading() {
32342
+ return st.widthBadgeFading;
32343
+ },
32344
+ get widthBadgeIds() {
32345
+ return dragRefs.ids;
32346
+ },
32347
+ get selected() {
32348
+ return st.panels.find((p) => p.id === st.selectedPanelId) ?? null;
32349
+ },
32350
+ get loupePanel() {
32351
+ return st.panels.find((p) => p.id === st.loupePanelId) ?? null;
32352
+ }
32353
+ };
32354
+ function nextPanelId() {
32355
+ st.panelIdSeq += 1;
32356
+ return "panel-" + st.panelIdSeq;
32357
+ }
32358
+ function syncPanelIdSeq(entries) {
32359
+ for (const p of entries) {
32360
+ const m = /^panel-(\d+)$/.exec(p.id);
32361
+ if (m) st.panelIdSeq = Math.max(st.panelIdSeq, Number(m[1]));
32362
+ }
32363
+ }
32364
+ function initFloor(entries, selectedId) {
32365
+ st.panels = entries;
32366
+ st.selectedPanelId = selectedId;
32367
+ syncPanelIdSeq(entries);
32368
+ }
32369
+ /** The fresh panel mounted and its composer took focus — clear the
32370
+ * swap-focus marker (a marker whose panel never mounts stays inert:
32371
+ * panel ids are unique and never remount). */
32372
+ function clearFocusComposer() {
32373
+ st.focusComposerId = null;
32374
+ }
32375
+ function selectPanel(panelId) {
32376
+ if (st.panels.some((p) => p.id === panelId)) st.selectedPanelId = panelId;
32377
+ }
32378
+ function closeLoupe() {
32379
+ st.loupePanelId = null;
32380
+ }
32381
+ function clearLoupeIfGone() {
32382
+ if (st.loupePanelId !== null && !st.panels.some((p) => p.id === st.loupePanelId)) st.loupePanelId = null;
32383
+ }
32384
+ function selectedIndex_() {
32385
+ return st.panels.findIndex((p) => p.id === st.selectedPanelId);
32386
+ }
32387
+ //#endregion
32388
+ //#region src/lib/utils/compact-number.ts
32389
+ /** Compact number formatting for narrow UI badges: 1829 -> '1.8K',
32390
+ * 4200000 -> '4.2M'. Locale-stable ('en') so rack rows keep their width. */
32391
+ var compact = new Intl.NumberFormat("en", {
32392
+ notation: "compact",
32393
+ maximumFractionDigits: 1
32394
+ });
32395
+ function formatCompact(n) {
32396
+ return compact.format(n);
32397
+ }
32398
+ //#endregion
32399
+ //#region src/lib/components/anchor/subagent-anchor/SubagentPopup.svelte
32400
+ function SubagentPopup($$renderer, $$props) {
32401
+ $$renderer.component(($$renderer) => {
32402
+ /**
32403
+ * SubagentPopup — the ledger half of the Subagent Anchor (Subagent
32404
+ * Anchor ADR D1/D5, amendment D6/D7): every spawned session as ONE flat
32405
+ * row — title · tokens · elapsed — inside the house popup shell (Esc /
32406
+ * outside close, right-full placement, width cap). The popup owns NO
32407
+ * state: rows arrive as props from the anchor button's poll; elapsed
32408
+ * lives only in the subagent-clock registry; lineage is re-derived
32409
+ * per fetch upstream, never written here.
32410
+ *
32411
+ * D6 header: shell title row + the count chip (N helpers, M running).
32412
+ * D5 sort: running first, then token spend descending (nulls last).
32413
+ * D7 footer: Σ over EXACTLY the header's rows; any null-degraded row
32414
+ * flips it to the honest Σ-incomplete marker — a partial sum must never
32415
+ * read as whole. Elapsed is NOT summed (concurrent wall-clocks add to
32416
+ * nothing). The footnote states the one-tick first-sight bias.
32417
+ */
32418
+ let { open = false, triggerEl = void 0, rows, onopenrow } = $$props;
32419
+ const spend = (row) => row.tokens === null ? -1 : row.tokens.input + row.tokens.output;
32420
+ /** D5: running first, then token spend desc (unknown spends last),
32421
+ * then session id for a stable tiebreak. */
32422
+ const sorted = derived(() => [...rows].sort((a, b) => Number(b.running) - Number(a.running) || spend(b) - spend(a) || a.sessionId.localeCompare(b.sessionId)));
32423
+ const runningCount = derived(() => rows.filter((r) => r.running).length);
32424
+ const anyUnknown = derived(() => rows.some((r) => r.tokens === null));
32425
+ const totalTokens = derived(() => rows.reduce((acc, r) => r.tokens === null ? acc : acc + r.tokens.input + r.tokens.output, 0));
32426
+ /** True when this helper's panel is already open on the floor — the
32427
+ * row tints so the operator sees which helpers live in the zoom. */
32428
+ function onFloor(sessionId) {
32429
+ return floorPanelId(sessionId) !== null;
32430
+ }
32431
+ /** The floor panel id hosting this helper, null when not open. */
32432
+ function floorPanelId(sessionId) {
32433
+ return floor.panels.find((panel) => "sessionId" in panel && panel.sessionId === sessionId)?.id ?? null;
32434
+ }
32435
+ /** Any helper live on the floor — the close-all X's visibility. */
32436
+ const anyOnFloor = derived(() => rows.some((r) => onFloor(r.sessionId)));
32437
+ /** Compact ledger form, DSH GUI parity — null renders the dash (never 0). */
32438
+ function tokensLabel(row) {
32439
+ if (row.tokens === null) return "—";
32440
+ return `${formatCompact(row.tokens.input + row.tokens.output)} tok`;
32441
+ }
32442
+ /** Elapsed label — the ledger's operate time (llmMs, the stats bar's
32443
+ * own 'LLM …' number, settled rows included). The first-sight clock is
32444
+ * the FALLBACK for rows the host cannot date; null renders the dash
32445
+ * (never a guess). */
32446
+ function elapsedLabel(row) {
32447
+ let ms;
32448
+ if (typeof row.operateMs === "number") ms = row.operateMs;
32449
+ else ms = subagentClock.elapsedMs(row.sessionId);
32450
+ if (ms === null) return "—";
32451
+ const s = Math.floor(ms / 1e3);
32452
+ if (s < 60) return `${s}s`;
32453
+ const m = Math.floor(s / 60);
32454
+ if (m < 60) return `${m}m ${s % 60}s`;
32455
+ return `${Math.floor(m / 60)}h ${m % 60}m`;
32456
+ }
32457
+ let $$settled = true;
32458
+ let $$inner_renderer;
32459
+ function $$render_inner($$renderer) {
32460
+ FloatingAnchorContainerPopup($$renderer, {
32461
+ triggerEl,
32462
+ popupTestId: "subagent-popup",
32463
+ get open() {
32464
+ return open;
32465
+ },
32466
+ set open($$value) {
32467
+ open = $$value;
32468
+ $$settled = false;
32469
+ },
32470
+ children: ($$renderer) => {
32471
+ $$renderer.push(`<div class="flex items-center border-b border-surface-border px-2.5 py-1 text-[10px] uppercase tracking-wider text-text-muted" data-testid="subagent-popup-chip"><span class="flex-1">${escape_html(rows.length)}
32472
+ ${escape_html(rows.length === 1 ? "subagent" : "subagents")} · ${escape_html(runningCount())} running</span> `);
32473
+ if (anyOnFloor()) {
32474
+ $$renderer.push("<!--[0-->");
32475
+ $$renderer.push(`<button type="button" class="shrink-0 transition-colors"${attr("title", t(subagentcloseallpanels3))}${attr("aria-label", t(subagentcloseallpanels3))} data-testid="subagent-popup-close-all">`);
32476
+ Trash_2($$renderer, {
32477
+ size: 14,
32478
+ "aria-hidden": "true",
32479
+ style: "stroke: red;"
32480
+ });
32481
+ $$renderer.push(`<!----></button>`);
32482
+ } else $$renderer.push("<!--[-1-->");
32483
+ $$renderer.push(`<!--]--></div> <!--[-->`);
32484
+ const each_array = ensure_array_like(sorted());
32485
+ for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
32486
+ let row = each_array[$$index];
32487
+ $$renderer.push(`<button type="button"${attr_class(`flex w-full items-center gap-2 px-2.5 py-1.5 text-left text-xs transition-colors hover:bg-surface-hover ${onFloor(row.sessionId) ? "row-on-floor" : ""}`, "svelte-1lupp7r")} data-testid="subagent-row"><span${attr_class(`flex shrink-0 items-center ${row.running ? "text-amber-500" : "text-text-muted"}`)} data-testid="subagent-row-glyph">`);
32488
+ if (row.running) {
32489
+ $$renderer.push("<!--[0-->");
32490
+ Loader_circle($$renderer, {
32491
+ size: 11,
32492
+ class: "animate-spin"
32493
+ });
32494
+ } else {
32495
+ $$renderer.push("<!--[-1-->");
32496
+ Circle_dashed($$renderer, { size: 11 });
32497
+ }
32498
+ $$renderer.push(`<!--]--></span> <span class="min-w-0 flex-1 truncate">${escape_html(row.title ?? "—")}</span> <span class="w-20 shrink-0 text-right font-variant-numeric tabular-nums" data-testid="subagent-row-tokens">${escape_html(tokensLabel(row))}</span> <span class="w-14 shrink-0 text-right text-text-muted tabular-nums" data-testid="subagent-row-elapsed">${escape_html(elapsedLabel(row))}</span></button>`);
32499
+ }
32500
+ $$renderer.push(`<!--]--> <div${attr_class(`sticky bottom-0 flex items-center border-t border-surface-border bg-surface-elevated px-2.5 py-1.5 text-[12px] font-medium tracking-wider ${anyUnknown() ? "text-text-muted" : "text-text-primary"}`)} data-testid="subagent-popup-footer" style="padding-right: 6em;"><span class="flex-1 text-right">${escape_html(t(() => totaltokens1()))}</span> <span class="w-20 shrink-0 text-right font-variant-numeric tabular-nums" data-testid="subagent-popup-footer-tokens">${escape_html(anyUnknown() ? "—" : `${formatCompact(totalTokens())} tok`)}</span></div>`);
32501
+ },
32502
+ $$slots: { default: true }
32503
+ });
32504
+ }
32505
+ do {
32506
+ $$settled = true;
32507
+ $$inner_renderer = $$renderer.copy();
32508
+ $$render_inner($$inner_renderer);
32509
+ } while (!$$settled);
32510
+ $$renderer.subsume($$inner_renderer);
32511
+ bind_props($$props, { open });
32512
+ });
32513
+ }
32514
+ //#endregion
32515
+ //#region src/lib/components/anchor/subagent-anchor/SubagentAnchorButton.svelte
32516
+ function SubagentAnchorButton($$renderer, $$props) {
32517
+ $$renderer.component(($$renderer) => {
32518
+ /**
32519
+ * SubagentAnchorButton — the ledger leaf of the conversation page's
32520
+ * FloatingAnchor stack (Subagent Anchor ADR D1, placement REVISED
32521
+ * 2026-10-26: the operator's 'anchor' means the right-edge icon
32522
+ * column beside the transcript — JobsButton's seat — NOT the sidebar
32523
+ * header). Lists THIS conversation's sub-agents only (the ?parent
32524
+ * scoping, DSH dropdown parity) — one click: title, tokens, elapsed.
32525
+ * Hidden at zero rows so the stack keeps its shape. Owns the poll:
32526
+ * one GET per few seconds while mounted, each answer fed to the
32527
+ * subagent-clock registry as its spine tick (ADR D3).
32528
+ */
32529
+ let { onopensession = void 0} = $$props;
32530
+ let rows = [];
32531
+ let open = false;
32532
+ /** The toggle's wrapper — the shell's close-contract exclusion. */
32533
+ let triggerEl = void 0;
32534
+ const runningCount = derived(() => rows.filter((r) => r.running).length);
32535
+ let $$settled = true;
32536
+ let $$inner_renderer;
32537
+ function $$render_inner($$renderer) {
32538
+ if (rows.length > 0) {
32539
+ $$renderer.push("<!--[0-->");
32540
+ $$renderer.push(`<div data-svelte="SubagentAnchorButton" class="relative" data-testid="subagent-anchor-button"><button type="button"${attr_class(`floating-anchor-btn ${runningCount() > 0 ? "tone-purple" : "tone-idle"}`, "svelte-1vxt4fg", { "active": open })}${attr("title", t(subagentanchorlabel2))}${attr("aria-label", t(subagentanchorlabel2))} data-testid="subagent-anchor-trigger">`);
32541
+ Bot($$renderer, {
32542
+ size: 13,
32543
+ "aria-hidden": "true"
32544
+ });
32545
+ $$renderer.push(`<!----> <span data-testid="subagent-anchor-badge">${escape_html(runningCount() > 0 ? runningCount() : rows.length)}</span></button> `);
32546
+ SubagentPopup($$renderer, {
32547
+ triggerEl,
32548
+ rows,
32549
+ onopenrow: onopensession,
32550
+ get open() {
32551
+ return open;
32552
+ },
32553
+ set open($$value) {
32554
+ open = $$value;
32555
+ $$settled = false;
32556
+ }
32557
+ });
32558
+ $$renderer.push(`<!----></div>`);
32559
+ } else $$renderer.push("<!--[-1-->");
32560
+ $$renderer.push(`<!--]-->`);
32561
+ }
32562
+ do {
32563
+ $$settled = true;
32564
+ $$inner_renderer = $$renderer.copy();
32565
+ $$render_inner($$inner_renderer);
32566
+ } while (!$$settled);
32567
+ $$renderer.subsume($$inner_renderer);
32568
+ });
32569
+ }
32570
+ //#endregion
32571
+ //#region src/lib/components/conversation/panel/ConversationFloatingAnchor.svelte
32572
+ function ConversationFloatingAnchor($$renderer, $$props) {
32573
+ /**
32574
+ * ConversationFloatingAnchor — the conversation page's floating action
32575
+ * stack (OCI Floating Host port, 2026-08-23; extracted from the page
32576
+ * 2026-08-24): jump and scroll actions beside the transcript they act
32577
+ * on — the User Messages button (self-contained with its popup jumper
32578
+ * since 2026-08-26; renders only when prompt groups exist) and the
32579
+ * far-edge jump. Purely presentational — the viewport and turn groups
32580
+ * arrive as props.
32581
+ */
32582
+ let { groups, container, todos = null, deliverables = null, onfileopen = void 0, jobsessionid = "", shelfentries = void 0, shelfsessionid = "", shelfworkspace = null, shelfpanelid = null, onshelfnote } = $$props;
32583
+ if (container !== void 0) {
32584
+ $$renderer.push("<!--[0-->");
32585
+ FloatingAnchor($$renderer, {
32586
+ children: ($$renderer) => {
32587
+ PlanButton($$renderer, { todos: todos ?? [] });
32588
+ $$renderer.push(`<!----> `);
32589
+ DeliverablesButton($$renderer, {
32590
+ deliveries: deliverables,
32591
+ onfileopen
32592
+ });
32593
+ $$renderer.push(`<!----> `);
32594
+ JobsButton($$renderer, { sessionId: jobsessionid });
32595
+ $$renderer.push(`<!----> `);
32596
+ SubagentAnchorButton($$renderer, { });
32597
+ $$renderer.push(`<!----> `);
32598
+ if (shelfentries !== void 0) {
32599
+ $$renderer.push("<!--[0-->");
32600
+ InjectedShelfButton($$renderer, {
32601
+ entries: shelfentries,
32602
+ sessionId: shelfsessionid,
32603
+ workspace: shelfworkspace,
32604
+ panelId: shelfpanelid,
32605
+ onnote: onshelfnote
32606
+ });
32607
+ } else $$renderer.push("<!--[-1-->");
32608
+ $$renderer.push(`<!--]--> `);
32609
+ UserMessagesButton($$renderer, {
32610
+ groups,
32611
+ container
32612
+ });
32613
+ $$renderer.push(`<!----> `);
32614
+ BackToTheEdgeButton($$renderer);
32615
+ $$renderer.push(`<!---->`);
32616
+ }});
32617
+ } else $$renderer.push("<!--[-1-->");
32618
+ $$renderer.push(`<!--]-->`);
32619
+ }
32620
+ //#endregion
32621
+ //#region src/lib/components/conversation/panel/A2aChipStack.svelte
32622
+ function A2aChipStack($$renderer, $$props) {
32623
+ $$renderer.component(($$renderer) => {
32624
+ /**
32625
+ * A2aChipStack — the sender panel's read-only delegation-ledger join
32626
+ * (W4 4.2): one floating chip per recent exchange THIS panel sent,
32627
+ * rendered beside the transcript on the floating-anchor pattern
32628
+ * (right-middle stack, per-panel via the embedded anchor host).
32629
+ *
32630
+ * Honesty contract (PRD risk "Attribution overclaim in UI" + spec-check
32631
+ * GAP-5): chip text derives from the row's `state` VERBATIM, all six
32632
+ * states distinguished — `replied_approx` renders "may have replied",
32633
+ * NEVER the confident "replied" string. The ledger is the truth; this
32634
+ * component claims nothing the row does not say.
32635
+ *
32636
+ * Read-only by construction (BC-2): rows arrive as a prop from the
32637
+ * page's EXISTING spine-cadence poll of GET /api/a2a?from= — the chip
32638
+ * owns NO fetch, NO timer. Click = the existing panel doorway
32639
+ * (addPanelFromSidebar dedupe→select). Dismiss is LOCAL-ONLY visual:
32640
+ * rows are durable; the next poll brings a dismissed chip back only
32641
+ * when it is still in the page's fetched window.
32642
+ */
32643
+ let { rows, titles } = $$props;
32644
+ /** Local-only visual dismissal — rows are durable; the ledger is truth. */
32645
+ let dismissed = /* @__PURE__ */ new Set();
32646
+ /** The cap: newest 3 visible + one overflow indicator (spec 4.2). */
32647
+ const CHIP_CAP = 3;
32648
+ const visible = derived(() => rows.filter((r) => !dismissed.has(r.id)));
32649
+ const capped = derived(() => visible().slice(0, CHIP_CAP));
32650
+ const overflow = derived(() => Math.max(visible().length - CHIP_CAP, 0));
32651
+ /**
32652
+ * Chip text derives from the state VERBATIM (spec-check GAP-5): every
32653
+ * state distinguished, `replied_approx` hedged as "may have replied" —
32654
+ * never a confident claim the row cannot support.
32655
+ */
32656
+ function labelFor(state) {
32657
+ switch (state) {
32658
+ case "waiting": return "waiting";
32659
+ case "replied_exact": return "replied (exact)";
32660
+ case "replied": return "replied";
32661
+ case "replied_approx": return "may have replied";
32662
+ case "timeout": return "no reply (timeout)";
32663
+ case "gone": return "target gone";
32664
+ }
32665
+ }
32666
+ /** The target's display title — the spine title, else the id prefix. */
32667
+ function titleFor(toSession) {
32668
+ return titles[toSession] ?? toSession.replace(/^session-/, "").slice(0, 8);
32669
+ }
32670
+ if (visible().length > 0) {
32671
+ $$renderer.push("<!--[0-->");
32672
+ FloatingAnchor($$renderer, {
32673
+ children: ($$renderer) => {
32674
+ $$renderer.push(`<!--[-->`);
32675
+ const each_array = ensure_array_like(capped());
32676
+ for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
32677
+ let row = each_array[$$index];
32678
+ $$renderer.push(`<div class="a2a-chip-wrap" data-testid="a2a-chip"${attr("data-a2a-state", row.state)}${attr("data-a2a-id", row.id)}><button type="button"${attr_class("a2a-chip", void 0, {
32679
+ "tone-waiting": row.state === "waiting",
32680
+ "tone-replied-exact": row.state === "replied_exact",
32681
+ "tone-replied": row.state === "replied",
32682
+ "tone-replied-approx": row.state === "replied_approx",
32683
+ "tone-timeout": row.state === "timeout",
32684
+ "tone-gone": row.state === "gone"
32685
+ })} data-testid="a2a-chip-button"${attr("title", `${stringify(titleFor(row.toSession))} — ${stringify(labelFor(row.state))}`)}>`);
32686
+ if (row.state === "waiting") {
32687
+ $$renderer.push("<!--[0-->");
32688
+ Hourglass($$renderer, { size: 13 });
32689
+ } else if (row.state === "replied_exact" || row.state === "replied") {
32690
+ $$renderer.push("<!--[1-->");
32691
+ Check($$renderer, { size: 13 });
32692
+ } else $$renderer.push("<!--[-1-->");
32693
+ $$renderer.push(`<!--]--> <span class="a2a-chip-label">${escape_html(labelFor(row.state))}</span></button> <button type="button" class="a2a-dismiss" data-testid="a2a-chip-dismiss" title="hide this chip (the ledger row stays)">`);
32694
+ X($$renderer, { size: 11 });
32695
+ $$renderer.push(`<!----></button></div>`);
32696
+ }
32697
+ $$renderer.push(`<!--]--> `);
32698
+ if (overflow() > 0) {
32699
+ $$renderer.push("<!--[0-->");
32700
+ $$renderer.push(`<div class="a2a-chip-overflow" data-testid="a2a-chip-overflow">+${escape_html(overflow())} more</div>`);
32701
+ } else $$renderer.push("<!--[-1-->");
32702
+ $$renderer.push(`<!--]-->`);
32703
+ }});
32704
+ } else $$renderer.push("<!--[-1-->");
32705
+ $$renderer.push(`<!--]-->`);
32706
+ });
32707
+ }
32708
+ //#endregion
32709
+ //#region src/lib/components/conversation/panel/ConversationStatsBar.svelte
32710
+ function ConversationStatsBar($$renderer, $$props) {
32711
+ $$renderer.component(($$renderer) => {
32712
+ /**
32713
+ * ConversationStatsBar — the panel's session baseline (ADR 2026-09-08
32714
+ * "The Stats Bar", D1/D3/D5): one fixed-height line under the transcript
32715
+ * showing what the ledger already proves — turns, steps, tool time,
32716
+ * token totals, cache hit. Pure presentation: the panel derives the
32717
+ * stats and hands them down; segments whose inputs never reached DSI
32718
+ * are omitted, never approximated. Renders nothing before the first
32719
+ * assistant message (D5 gate lives in the derive's null return).
32720
+ */
32721
+ let { stats } = $$props;
32722
+ /** 85000 -> "1m25s"; 2400000 -> "40m"; 5400000 -> "1h30m"; 250 -> "250ms". */
32723
+ function formatDuration(ms) {
32724
+ if (ms < 1e3) return `${ms}ms`;
32725
+ const totalSec = Math.floor(ms / 1e3);
32726
+ const h = Math.floor(totalSec / 3600);
32727
+ const m = Math.floor(totalSec % 3600 / 60);
32728
+ const s = totalSec % 60;
32729
+ if (h > 0) return `${h}h${m}m`;
32730
+ if (m > 0) return s > 0 ? `${m}m${s}s` : `${m}m`;
32731
+ return `${s}s`;
32732
+ }
32733
+ /** 15800 -> "15.8K"; 56300 -> "56.3K"; 15800000 -> "15.8M"; 108000 -> "108K"; 999 -> "999". */
32734
+ function formatTokens(n) {
32735
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1).replace(/\.0$/, "")}M`;
32736
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1).replace(/\.0$/, "")}K`;
32737
+ return String(n);
32738
+ }
32739
+ const segments = derived(() => {
32740
+ if (stats === null) return [];
32741
+ const parts = [`${stats.turns} turns · ${stats.steps} steps`];
32742
+ const durations = [];
32743
+ if (stats.llmMs !== void 0 && stats.llmMs > 0) durations.push(`LLM ${formatDuration(stats.llmMs)}`);
32744
+ if (stats.toolMs > 0) durations.push(`Tool ${formatDuration(stats.toolMs)}`);
32745
+ if (durations.length > 0) parts.push(durations.join(" · "));
32746
+ const speeds = [];
32747
+ if (stats.ttftSteps !== void 0 && stats.ttftSteps > 0 && stats.ttftMs !== void 0) speeds.push(`TTFT avg ${formatDuration(stats.ttftMs / stats.ttftSteps)}`);
32748
+ if (stats.decodeMs !== void 0 && stats.decodeMs > 0 && stats.decodeTokens !== void 0) speeds.push(`${Math.max(1, Math.round(stats.decodeTokens / (stats.decodeMs / 1e3)))} tok/s`);
32749
+ if (speeds.length > 0) parts.push(speeds.join(" · "));
32750
+ const inputTotal = stats.billedInputTokens ?? stats.inputTokens;
32751
+ if (inputTotal !== void 0) parts.push(`Input ${formatTokens(inputTotal)} tok · Output ${formatTokens(stats.outputTokens ?? 0)} tok`);
32752
+ if (stats.cacheHitPercent !== void 0) parts.push(`Cache hit ${stats.cacheHitPercent}%`);
32753
+ return parts;
32754
+ });
32755
+ if (stats !== null) {
32756
+ $$renderer.push("<!--[0-->");
32757
+ $$renderer.push(`<div data-svelte="ConversationStatsBar" class="stats-bar svelte-hnxn10" data-testid="conversation-stats-bar"${attr("title", segments().join(" | "))}><!--[-->`);
32758
+ const each_array = ensure_array_like(segments());
32759
+ for (let i = 0, $$length = each_array.length; i < $$length; i++) {
32760
+ let segment = each_array[i];
32761
+ if (i > 0) {
32762
+ $$renderer.push("<!--[0-->");
32763
+ $$renderer.push(`<span class="sep svelte-hnxn10" aria-hidden="true">|</span>`);
32764
+ } else $$renderer.push("<!--[-1-->");
32765
+ $$renderer.push(`<!--]--> <span class="segment svelte-hnxn10" data-testid="stats-segment">${escape_html(segment)}</span>`);
32766
+ }
32767
+ $$renderer.push(`<!--]--></div>`);
32768
+ } else $$renderer.push("<!--[-1-->");
32769
+ $$renderer.push(`<!--]-->`);
32770
+ });
32771
+ }
32772
+ //#endregion
32773
+ //#region src/lib/components/conversation/panel/submit-ladder.svelte.ts
32774
+ var SubmitLadder = class {
32775
+ deps;
32776
+ /** True while the plain-send rung is in flight — the footer's sending flag. */
32777
+ submitted = false;
32778
+ /** Inline command feedback (role=status, auto-dismiss 5s) — the ONLY
32779
+ * command UI surface; the input has already cleared by intercept time.
32780
+ * The wire work lives in command-executor (Prompt Macro W1 1.2): the
32781
+ * /new create+swap, /permission route, and mention delivery are the
32782
+ * SAME bytes the typed path always sent — the panel now renders
32783
+ * outcomes only (banner kind from result.ok). */
32784
+ commandNote = null;
32785
+ commandNoteTimer;
32786
+ constructor(deps) {
32787
+ this.deps = deps;
32788
+ }
32789
+ /** Inline command feedback — every rung banners through here. */
32790
+ noteCommand(kind, text) {
32791
+ this.commandNote = {
32792
+ kind,
32793
+ text
32794
+ };
32795
+ if (this.commandNoteTimer !== void 0) clearTimeout(this.commandNoteTimer);
32796
+ this.commandNoteTimer = setTimeout(() => this.commandNote = null, 5e3);
32797
+ }
32798
+ async onsubmit(text, images) {
32799
+ if (isTypedRun(text)) {
32800
+ this.deps.startMacro({
32801
+ text,
32802
+ id: -1
32803
+ }, false);
32804
+ return true;
32805
+ }
32806
+ const command = parseCommand(text);
32807
+ if (command !== null) {
32808
+ let bannered = false;
32809
+ const result = await executeCommand(command, this.deps.ctx(), (ok, note) => {
32810
+ bannered = true;
32811
+ this.noteCommand(ok ? "ok" : "error", note);
32812
+ });
32813
+ if (!bannered && result.note !== void 0) this.noteCommand(result.ok ? "ok" : "error", result.note);
32814
+ return true;
32815
+ }
32816
+ if (text.trim().length === 0 && images.length === 0) return false;
32817
+ const slashCatalog = this.deps.slashCatalog;
32818
+ if (slashCatalog?.state === "ready") {
32819
+ if (resolveHostCommand(text, slashCatalog.commands) !== null) return (await executeHostCommand(text, this.deps.ctx(), (ok, note) => this.noteCommand(ok ? "ok" : "error", note))).ok;
32820
+ }
32821
+ this.submitted = true;
32822
+ try {
32823
+ return (await sendPrompt(text, this.deps.ctx(), (t) => this.deps.orchestrator.submit(t, images))).ok;
32824
+ } finally {
32825
+ this.submitted = false;
32826
+ }
32827
+ }
32828
+ async oncancel() {
32829
+ await this.deps.orchestrator.cancel();
32830
+ }
32831
+ /** Menu command pick: the SAME rung the ladder uses (one execution
32832
+ * surface, D2), banner notes through the shared note path; the
32833
+ * boolean admits the composer's draft clearing (BC-A3). */
32834
+ async onpickcommand(line) {
32835
+ return (await executeHostCommand(line, this.deps.ctx(), (ok, note) => this.noteCommand(ok ? "ok" : "error", note))).ok;
32836
+ }
32837
+ };
32838
+ //#endregion
32839
+ //#region src/lib/utils/auto-open-slots.ts
32840
+ /** The newest reasoning entry's id (wire order), else null — the
32841
+ * transient think target. Empty reasoning strings do not count (the
32842
+ * chip renders nothing to open). */
32843
+ function newestReasoningId(entries) {
32844
+ for (let i = entries.length - 1; i >= 0; i--) {
32845
+ const e = entries[i];
32846
+ if (e.kind === "assistant-message" && e.reasoning !== void 0 && e.reasoning !== "") return e.id;
32847
+ }
32848
+ return null;
32849
+ }
32850
+ /** Suppression-aware view of a raw target: null while the user kept THIS
32851
+ * id collapsed (a newer target id simply stops matching). */
32852
+ function suppressed(targetId, suppressedId) {
32853
+ return targetId !== null && suppressedId === targetId ? null : targetId;
32854
+ }
32855
+ //#endregion
32856
+ //#region src/lib/components/conversation/panel/popups.svelte.ts
32857
+ var Popups = class {
32858
+ /** Chip popup state (2026-08-22, OCI pattern): ONE open chip at a time —
32859
+ * the id of the expanded entry; detail renders AFTER the chip row.
32860
+ * Per-panel by construction (moved here with the block). */
32861
+ openChipId = null;
32862
+ /** Peek popup state (ToolPeekButton port, 2026-08-22): the run key whose
32863
+ * chip row has its list popup open — ONE at a time, and never while a
32864
+ * chip detail popup is open (OCI mutual-exclusion contract). */
32865
+ peekOpenRunKey = null;
32866
+ thinkSuppressedId = null;
32867
+ planSuppressedId = null;
32868
+ /** The newest todo_write entry's id, STICKY: adopted only while
32869
+ * streaming AND stuck (the detection window), then kept across newer
32870
+ * thinks, turn end, and scroll-away — the plan stays on screen until
32871
+ * a newer todo_write supersedes it or the user collapses it. */
32872
+ autoPlanIdRaw = null;
32873
+ deps;
32874
+ stopPlanEffect;
32875
+ constructor(deps) {
32876
+ this.deps = deps;
32877
+ this.stopPlanEffect = () => {};
32878
+ }
32879
+ destroy() {
32880
+ this.stopPlanEffect();
32881
+ }
32882
+ /** The newest reasoning entry's id (wire order) while streaming AND
32883
+ * stuck to the live end, else null — the transient think target. */
32884
+ get autoThinkTargetId() {
32885
+ if (!this.deps.store.isStreaming || !this.deps.stick) return null;
32886
+ return newestReasoningId(this.deps.store.renderEntries);
32887
+ }
32888
+ /** Suppression-aware think target: null while the user kept THIS think
32889
+ * collapsed (a newer think id simply stops matching). */
32890
+ get autoThinkId() {
32891
+ return suppressed(this.autoThinkTargetId, this.thinkSuppressedId);
32892
+ }
32893
+ /** Suppression-aware plan target (same id-tied rule as the think). */
32894
+ get autoPlanId() {
32895
+ return suppressed(this.autoPlanIdRaw, this.planSuppressedId);
32896
+ }
32897
+ toggleChip(id, autoOpen = false) {
32898
+ if (autoOpen) {
32899
+ if (id === this.autoPlanId) this.planSuppressedId = id;
32900
+ else if (this.autoThinkId !== null && id === `r:${this.autoThinkId}`) this.thinkSuppressedId = this.autoThinkId;
32901
+ return;
32902
+ }
32903
+ this.openChipId = this.openChipId === id ? null : id;
32904
+ this.peekOpenRunKey = null;
32905
+ }
32906
+ togglePeek(runKey) {
32907
+ this.peekOpenRunKey = this.peekOpenRunKey === runKey ? null : runKey;
31787
32908
  if (this.peekOpenRunKey !== null) this.openChipId = null;
31788
32909
  }
31789
32910
  };
@@ -32972,14 +34093,14 @@ function BrowserContent($$renderer, $$props) {
32972
34093
  $$renderer.push(`<div class="absolute z-50 min-w-44 rounded-md border border-zinc-700 bg-white py-1 text-xs shadow-xl"${attr_style(`left:${stringify(ctxMenu.px)}px; top:${stringify(ctxMenu.py)}px`)} data-testid="browser-ctxmenu">`);
32973
34094
  if (ctxMenu.src) {
32974
34095
  $$renderer.push("<!--[0-->");
32975
- $$renderer.push(`<button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">Open image in new tab</button> <button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">Copy image address</button>`);
34096
+ $$renderer.push(`<button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">${escape_html(browserctxopenimage3())}</button> <button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">${escape_html(browserctxcopyimage3())}</button>`);
32976
34097
  } else $$renderer.push("<!--[-1-->");
32977
34098
  $$renderer.push(`<!--]--> `);
32978
34099
  if (ctxMenu.href) {
32979
34100
  $$renderer.push("<!--[0-->");
32980
- $$renderer.push(`<button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">Open link in new tab</button> <button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">Copy link address</button>`);
34101
+ $$renderer.push(`<button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">${escape_html(browserctxopenlink3())}</button> <button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">${escape_html(browserctxcopylink3())}</button>`);
32981
34102
  } else $$renderer.push("<!--[-1-->");
32982
- $$renderer.push(`<!--]--> <button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">Reload</button> <div class="my-1 border-t border-zinc-300"></div> <button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">Send right-click to the page</button></div>`);
34103
+ $$renderer.push(`<!--]--> <button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">${escape_html(browserreload1())}</button> <div class="my-1 border-t border-zinc-300"></div> <button type="button" class="block w-full px-3 py-1.5 text-left text-zinc-900 hover:bg-zinc-200" data-testid="browser-ctxmenu-item">${escape_html(browserctxsendrightclick4())}</button></div>`);
32983
34104
  } else $$renderer.push("<!--[-1-->");
32984
34105
  $$renderer.push(`<!--]--> `);
32985
34106
  if (status !== "live") {
@@ -32996,6 +34117,20 @@ function BrowserContent($$renderer, $$props) {
32996
34117
  });
32997
34118
  }
32998
34119
  //#endregion
34120
+ //#region src/lib/components/browser/BrowserTab.svelte
34121
+ function BrowserTab($$renderer, $$props) {
34122
+ $$renderer.component(($$renderer) => {
34123
+ let { tab, disabled = false} = $$props;
34124
+ $$renderer.push(`<div data-svelte="BrowserTab" class="relative shrink-0"><button type="button"${attr_class("w-32 truncate rounded px-1.5 py-0.5 pr-4 text-left whitespace-nowrap", void 0, {
34125
+ "bg-blue-200": tab.active,
34126
+ "text-blue-900": tab.active,
34127
+ "text-zinc-600": !tab.active,
34128
+ "hover:bg-zinc-100": !tab.active,
34129
+ "font-medium": tab.active
34130
+ })}${attr("disabled", disabled || tab.active, true)} data-testid="browser-tab"${attr("data-active", tab.active)}${attr("title", tab.url)}>${escape_html(tab.title || tab.url || "tab")}</button> <button type="button" class="absolute right-0.5 top-1/2 -translate-y-1/2 rounded text-[10px] leading-none text-red-500 hover:bg-red-500 hover:text-white"${attr("title", browsertabclosetitle3())} data-testid="browser-tab-close">✕</button></div>`);
34131
+ });
34132
+ }
34133
+ //#endregion
32999
34134
  //#region src/lib/components/browser/mirror-input.ts
33000
34135
  /** The on-screen rect of the PAGE image inside its wrapper. The frame is
33001
34136
  * drawn aspect-true (canvas object-contain): when the frame is wider or
@@ -33154,6 +34289,7 @@ function BrowserPanel($$renderer, $$props) {
33154
34289
  /** ADR-0040 D5: the tab strip — the registry's tab list mirrored here;
33155
34290
  * the SERVER stays the authority (activeTargetId), this is a view. */
33156
34291
  let tabs = [];
34292
+ let switching = false;
33157
34293
  const moves = createMoveCoalescer((cb) => requestAnimationFrame(cb), (x, y) => void post());
33158
34294
  async function post(input) {}
33159
34295
  function toViewportCx(e) {
@@ -33220,16 +34356,19 @@ function BrowserPanel($$renderer, $$props) {
33220
34356
  x: p.x,
33221
34357
  y: p.y});
33222
34358
  }
33223
- async function ctxOpenTab(url) {
33224
- ctxClose();
33225
- }
34359
+ /** ADR-0042 D3: ONE client choreography for tab creation — the context
34360
+ * menu's open-link/image (url present) and the strip's + chip (url
34361
+ * empty = BLANK, the birth state again). Empty body per D1: absence is
34362
+ * the blank signal, never a literal about:blank. Callers own their own
34363
+ * ctxClose(). */
34364
+ async function openTab(url) {}
33226
34365
  function ctxAct(action) {
33227
34366
  const m = ctxMenu;
33228
34367
  ctxClose();
33229
34368
  if (!m) return;
33230
- if (action === "open-image" && m.src) return void ctxOpenTab(m.src);
34369
+ if (action === "open-image" && m.src) return void openTab(m.src);
33231
34370
  if (action === "copy-image" && m.src) return void ctxCopy(m.src);
33232
- if (action === "open-link" && m.href) return void ctxOpenTab(m.href);
34371
+ if (action === "open-link" && m.href) return void openTab(m.href);
33233
34372
  if (action === "copy-link" && m.href) return void ctxCopy(m.href);
33234
34373
  if (action === "reload") return void proxy();
33235
34374
  if (action === "send-right-click") return ctxSendRightClick();
@@ -33315,15 +34454,11 @@ function BrowserPanel($$renderer, $$props) {
33315
34454
  const each_array = ensure_array_like(tabs);
33316
34455
  for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
33317
34456
  let t = each_array[$$index];
33318
- $$renderer.push(`<div class="relative shrink-0"><button type="button"${attr_class("w-32 truncate rounded px-1.5 py-0.5 pr-4 text-left whitespace-nowrap", void 0, {
33319
- "bg-blue-200": t.active,
33320
- "text-blue-900": t.active,
33321
- "text-zinc-600": !t.active,
33322
- "hover:bg-zinc-100": !t.active,
33323
- "font-medium": t.active
33324
- })}${attr("disabled", t.active, true)} data-testid="browser-tab"${attr("data-active", t.active)}${attr("title", t.url)}>${escape_html(t.title || t.url || "tab")}</button> <button type="button" class="absolute right-0.5 top-1/2 -translate-y-1/2 rounded text-[10px] leading-none text-red-500 hover:bg-red-500 hover:text-white" title="Close tab" data-testid="browser-tab-close">✕</button></div>`);
34457
+ BrowserTab($$renderer, {
34458
+ tab: t,
34459
+ disabled: switching});
33325
34460
  }
33326
- $$renderer.push(`<!--]--></div>`);
34461
+ $$renderer.push(`<!--]--> <button type="button" class="shrink-0 rounded px-1.5 leading-none text-zinc-500 hover:bg-zinc-100 disabled:opacity-40"${attr("title", t(browsernewtab2))}${attr("aria-label", t(browsernewtab2))} data-testid="browser-tab-new"${attr("disabled", true, true)}>+</button></div>`);
33327
34462
  } else $$renderer.push("<!--[-1-->");
33328
34463
  $$renderer.push(`<!--]--> `);
33329
34464
  BrowserContent($$renderer, {
@@ -34209,9 +35344,13 @@ function WorkspaceFileTabGroup($$renderer, $$props) {
34209
35344
  //#region src/lib/components/workspace-file/WorkspaceFileToolbar.svelte
34210
35345
  function WorkspaceFileToolbar($$renderer, $$props) {
34211
35346
  $$renderer.component(($$renderer) => {
35347
+ /** The reload icon's feedback state — the CanvasCopyButton machine
35348
+ * (idle → busy spinner → done check → idle), mirrored per the 2026-10-27
35349
+ * UX-parity operator request: a click that shows nothing happening "sucks". */
35350
+ let reloadState = "idle";
34212
35351
  let columnEl = null;
34213
- let { dirty, saveState = "idle", stale = false, staleNote = "", hasTabs = false, tab = "preview", view = "edit", showToggle = false, diffDisabled = false, readonly = false, onviewchange, onsave, path } = $$props;
34214
- $$renderer.push(`<div data-svelte="WorkspaceFileToolbar" class="file-toolbar svelte-1vsjf39"><span class="path svelte-1vsjf39"${attr("title", path)}>${escape_html(path)}</span> `);
35352
+ let { dirty, saveState = "idle", stale = false, staleNote = "", hasTabs = false, tab = "preview", view = "edit", showToggle = false, diffDisabled = false, readonly = false, onviewchange, onsave, onreload, path } = $$props;
35353
+ $$renderer.push(`<div data-svelte="WorkspaceFileToolbar" class="file-toolbar svelte-1vsjf39" data-testid="file-toolbar"><span class="path svelte-1vsjf39"${attr("title", path)}>${escape_html(path)}</span> `);
34215
35354
  if (showToggle) {
34216
35355
  $$renderer.push("<!--[0-->");
34217
35356
  WorkspaceFileTabGroup($$renderer, {
@@ -34243,6 +35382,14 @@ function WorkspaceFileToolbar($$renderer, $$props) {
34243
35382
  $$renderer.push("<!--[0-->");
34244
35383
  $$renderer.push(`<div class="tabs svelte-1vsjf39" role="tablist"><button role="tab"${attr("aria-selected", tab === "preview")} data-testid="tab-preview"${attr_class("svelte-1vsjf39", void 0, { "active": tab === "preview" })}>${escape_html(t(workspacefilepreview2))}</button> <button role="tab"${attr("aria-selected", tab === "edit")} data-testid="tab-edit"${attr_class("svelte-1vsjf39", void 0, { "active": tab === "edit" })}>${escape_html(t(workspacefileedit2))}</button></div>`);
34245
35384
  } else $$renderer.push("<!--[-1-->");
35385
+ $$renderer.push(`<!--]--> `);
35386
+ if (onreload) {
35387
+ $$renderer.push("<!--[0-->");
35388
+ $$renderer.push(`<button type="button" class="reload-btn svelte-1vsjf39" data-testid="file-reload"${attr("data-state", reloadState)}${attr("title", t(refresh))}${attr("aria-label", t(refresh))}>`);
35389
+ $$renderer.push("<!--[-1-->");
35390
+ Rotate_cw($$renderer, { size: 14 });
35391
+ $$renderer.push(`<!--]--></button>`);
35392
+ } else $$renderer.push("<!--[-1-->");
34246
35393
  $$renderer.push(`<!--]--> <span class="copy-slot svelte-1vsjf39">`);
34247
35394
  CanvasCopyButton($$renderer, {
34248
35395
  container: columnEl,
@@ -34274,7 +35421,7 @@ function WorkspaceFile($$renderer, $$props) {
34274
35421
  * old overflow:auto container made the hosts content-sized and the
34275
35422
  * page-level scrollbar stole the height.
34276
35423
  */
34277
- let { tab = void 0, dirty, fullPath, saveState, fileStale, staleNote, hasTabs, activeView, showToggle, diffDisabled, readonly, onViewChange, onSave, saveError, saveFailedNote, loadingNote, loadFailedNote, truncatedNote, newFileNote, phase, errorCode, title, isImage, bytesSrc, isHtml, text, isMarkdown, noHead, eof, editorHost = null, diffHost = null } = $$props;
35424
+ let { tab = void 0, dirty, fullPath, saveState, fileStale, staleNote, hasTabs, activeView, showToggle, diffDisabled, readonly, onViewChange, onSave, onReload, saveError, saveFailedNote, loadingNote, loadFailedNote, truncatedNote, newFileNote, phase, errorCode, title, isImage, bytesSrc, isHtml, text, isMarkdown, noHead, eof, editorHost = null, diffHost = null } = $$props;
34278
35425
  let $$settled = true;
34279
35426
  let $$inner_renderer;
34280
35427
  function $$render_inner($$renderer) {
@@ -34292,6 +35439,7 @@ function WorkspaceFile($$renderer, $$props) {
34292
35439
  readonly,
34293
35440
  onviewchange: onViewChange,
34294
35441
  onsave: onSave,
35442
+ onreload: onReload,
34295
35443
  get tab() {
34296
35444
  return tab;
34297
35445
  },
@@ -34443,6 +35591,13 @@ function WorkspaceFilePanel($$renderer, $$props) {
34443
35591
  const homeDir = marker > 0 ? dsi.slice(0, marker) : null;
34444
35592
  return homeDir !== null && full.startsWith(homeDir + "/") ? "~" + full.slice(homeDir.length) : full;
34445
35593
  });
35594
+ /** Silent external refetch (Index Pulse): when the buffer holds no
35595
+ * draft, the fetched text/baseline advance to the disk truth and the
35596
+ * editor follows; when a draft exists, the panel only raises the
35597
+ * visible stale note - a draft is never clobbered. */
35598
+ async function refreshFile() {
35599
+ if (isImage() || true) return;
35600
+ }
34446
35601
  /** The DIRECT save (The File Eye ADR D4): POST the buffer to the
34447
35602
  * gated write route; the written receipt advances the baseline so
34448
35603
  * dirty clears — bytes on disk, not an agent's promise. */
@@ -34464,6 +35619,7 @@ function WorkspaceFilePanel($$renderer, $$props) {
34464
35619
  readonly: false,
34465
35620
  onViewChange: setView,
34466
35621
  onSave: save,
35622
+ onReload: refreshFile,
34467
35623
  saveError,
34468
35624
  saveFailedNote: t(workspacefilesavefailed3),
34469
35625
  loadingNote: t(workspaceexplorerloading2),
@@ -34707,8 +35863,10 @@ function WorkspaceExplorerPanel($$renderer, $$props) {
34707
35863
  * the active file panel and cleared once it reports the highlight done. */
34708
35864
  let lineTarget = null;
34709
35865
  function startSplitDrag(event) {}
34710
- const splitPct = derived(() => clampTreePct(treePct));
34711
- $$renderer.push(`<div data-svelte="WorkspaceExplorerPanel" data-testid="workspace-explorer" class="split svelte-ldghfc"${attr_style(`--tree-basis: ${stringify(splitPct())}%; --file-basis: ${stringify(100 - splitPct())}%`)}>`);
35866
+ /** The rendered tree lane: the settled px, or the narrow-lane default
35867
+ * before the first measurement. Percent lives only in treePct. */
35868
+ const treeBasis = derived(() => 280);
35869
+ $$renderer.push(`<div data-svelte="WorkspaceExplorerPanel" data-testid="workspace-explorer" class="split svelte-ldghfc"${attr_style(`--tree-basis: ${stringify(treeBasis())}px`)}>`);
34712
35870
  WorkspaceExplorer($$renderer, {
34713
35871
  activeFile,
34714
35872
  root,
@@ -34860,740 +36018,218 @@ function PanelHeader($$renderer, $$props) {
34860
36018
  class: "inline-flex h-[22px] w-[22px] shrink-0 items-center justify-center rounded transition-colors hover:bg-surface-hover"
34861
36019
  });
34862
36020
  } else $$renderer.push("<!--[-1-->");
34863
- $$renderer.push(`<!--]--> `);
34864
- if (onremove || lens) {
34865
- $$renderer.push("<!--[0-->");
34866
- PanelClose($$renderer, {
34867
- sessionId,
34868
- lens});
34869
- } else $$renderer.push("<!--[-1-->");
34870
- $$renderer.push(`<!--]--></span></div>`);
34871
- });
34872
- }
34873
- //#endregion
34874
- //#region src/lib/components/panels/PanelColumn.svelte
34875
- function PanelColumn($$renderer, $$props) {
34876
- $$renderer.component(($$renderer) => {
34877
- /**
34878
- * PanelColumn — one panel's fixed-width column shell (Panel Floor W3
34879
- * task 3.2, ADR-0006): PanelHeader (floor chrome) + the conversation
34880
- * body (ConversationPanel, keyed by sessionId INSIDE the route's each
34881
- * — remount locality) + the 6px ResizeGutter after every panel.
34882
- *
34883
- * Presentational shell only: width and selection arrive as props
34884
- * (bound up to the route); the body arrives as a snippet so the ROUTE
34885
- * owns the {#key panel.sessionId} remount and the per-panel cold data.
34886
- *
34887
- * Width badge (2026-08-28): a `widthBadge` phase prop ('live' during
34888
- * a gutter drag that moves this panel's width, 'fading' through the
34889
- * 10s afterglow) floats the CURRENT width at the column's top right,
34890
- * below the header's controls, pointer-transparent — the route owns
34891
- * the membership rule (changed-from-snapshot) and the fade timer.
34892
- */
34893
- let { panel, index, selected, widthBadge = null, copyValue, canMoveLeft = false, canMoveRight = false, onremove, children } = $$props;
34894
- $$renderer.push(`<div data-svelte="PanelColumn"${attr_class("column svelte-1cuodug", void 0, { "selected": selected })} data-testid="panel-column"${attr("data-panel-id", panel.id)}${attr("data-session-id", panel.kind === "conversation" ? panel.sessionId : null)}${attr_style(`width: ${stringify(panel.width)}px; min-width: ${stringify(panel.width)}px; max-width: ${stringify(panel.width)}px;`)}>`);
34895
- PanelHeader($$renderer, {
34896
- panelId: panel.id,
34897
- sessionId: panel.kind === "conversation" ? panel.sessionId : "",
34898
- label: panelHeaderLabel(panel),
34899
- copyValue: panel.kind === "workspace-explorer" ? panel.root : panel.kind === "workspace-file" ? copyValue : void 0,
34900
- copyLabel: panel.kind === "workspace-explorer" ? t(workspaceexplorercopyworkspace3) : panel.kind === "workspace-file" ? t(workspacefilecopyfilename3) : void 0,
34901
- labelTestId: panel.kind === "workspace-explorer" ? "explorer-title" : panel.kind === "workspace-file" ? "file-title" : void 0,
34902
- selected,
34903
- canMoveLeft,
34904
- canMoveRight,
34905
- onremove
34906
- });
34907
- $$renderer.push(`<!----> `);
34908
- if (widthBadge !== null) {
34909
- $$renderer.push("<!--[0-->");
34910
- $$renderer.push(`<span${attr_class("width-badge svelte-1cuodug", void 0, { "fading": widthBadge === "fading" })} data-testid="panel-width-badge"${attr("data-badge-phase", widthBadge)} aria-hidden="true">${escape_html(Math.round(panel.width))}px</span>`);
34911
- } else $$renderer.push("<!--[-1-->");
34912
- $$renderer.push(`<!--]--> <div class="body svelte-1cuodug">`);
34913
- children($$renderer);
34914
- $$renderer.push(`<!----></div></div> `);
34915
- ResizeGutter($$renderer, { index });
34916
- $$renderer.push(`<!---->`);
34917
- });
34918
- }
34919
- //#endregion
34920
- //#region src/lib/components/panels/PanelLoupe.svelte
34921
- function PanelLoupe($$renderer, $$props) {
34922
- $$renderer.component(($$renderer) => {
34923
- /**
34924
- * PanelLoupe — the reading lens over one floor panel (The Panel Loupe
34925
- * ADR D2/D5, 2026-09-04): a body-portaled modal dialog that renders
34926
- * one panel's content at reading size while the floor keeps its
34927
- * zoom. ANY kind lenses (The Loupe for Every Panel, 2026-09-08): the
34928
- * route feeds the SAME body snippet the column renders (D7 — one
34929
- * ladder, two sites) and the header rides the panel's label variant;
34930
- * the loupe itself carries no conversation logic.
34931
- *
34932
- * Contract donor: ImageLightbox (2026-08-28) — the portal, the fixed
34933
- * inset-0 z-[1000] layer, role="dialog" aria-modal, the mask's
34934
- * mousedown close, Escape, the × control, focus to the × on open and
34935
- * back to the opener on close. The portal is load-bearing: the floor
34936
- * row carries transform: scale(), and a fixed backdrop inside a
34937
- * transformed ancestor is trapped in that ancestor's box instead of
34938
- * covering the viewport (ADR D2). The action is inlined here by
34939
- * decision — the donor is cited, not modified or refactored.
34940
- *
34941
- * Lens flag (D8): setLensMode(true) during init, BEFORE children
34942
- * render — every floor-verb control inside the body snippet reads the
34943
- * flag at its own init and renders visible-disabled. Context follows
34944
- * the component tree, so the flag reaches snippet content even after
34945
- * the portal moves the DOM under document.body (asserted by the loupe
34946
- * unit tests).
34947
- *
34948
- * The lens × and this header's copy-id are the loupe's live controls;
34949
- * the header's move/close render visible-disabled (the floor verbs).
34950
- * Openness is the route's session-local state — never persisted (D5).
34951
- */
34952
- let { panelId, sessionId, label = void 0, children } = $$props;
34953
- setLensMode(true);
34954
- $$renderer.push(`<div data-svelte="PanelLoupe" class="fixed inset-0 z-[1000] grid place-items-center p-10" role="dialog" aria-modal="true"${attr("aria-label", t(panelloupe1))} data-testid="panel-loupe"${attr("data-panel-id", panelId)}${attr("data-session-id", sessionId)}><div class="absolute inset-0 bg-black/60" aria-hidden="true" data-testid="panel-loupe-mask"></div> <div class="relative" style="width: min(100vw - 4rem, 850px); height: min(95vh, calc(100vh - 5rem));" data-testid="panel-loupe-sheet"><div class="flex h-full w-full flex-col overflow-hidden rounded-xl shadow-2xl" style="background: var(--color-surface-primary, var(--color-surface-elevated));">`);
34955
- PanelHeader($$renderer, {
34956
- panelId,
34957
- sessionId,
34958
- label,
34959
- lens: true
34960
- });
34961
- $$renderer.push(`<!----> <div class="flex min-h-0 flex-1 flex-col overflow-hidden">`);
34962
- children($$renderer);
34963
- $$renderer.push(`<!----></div></div> <button type="button"${attr("aria-label", t(closeloupe1))} data-testid="panel-loupe-close" class="absolute -top-3 -right-3 z-10 flex h-9 w-9 cursor-pointer items-center justify-center rounded-full border border-surface-border bg-surface-elevated text-lg leading-none text-text-primary shadow-md hover:bg-surface-hover">×</button></div></div>`);
34964
- });
34965
- }
34966
- //#endregion
34967
- //#region src/lib/components/panels/StickyColumnContainer.svelte
34968
- function StickyColumnContainer($$renderer, $$props) {
34969
- $$renderer.component(($$renderer) => {
34970
- /**
34971
- * StickyColumnContainer — a fixed-width LEADING column inside the zoom
34972
- * row (OCI StickyColumnContainer port, 2026-08-26; hosts the embedded
34973
- * AppSidebar the way OCI's hosts ControlRail).
34974
- *
34975
- * "Sticky" = the width is TRIPLE-LOCKED (width/min/max all the same
34976
- * px), unlike panel columns whose widths live in [MIN, MAX]: the rail
34977
- * never flexes when the row measures itself at max-content. The
34978
- * column's background paints the full column height — the rail inside
34979
- * fills it (align-items: stretch).
34980
- *
34981
- * The trailing ResizeGutter is included BY DEFAULT (OCI parity) but
34982
- * only when panel columns actually follow (showGutter) — a rail alone
34983
- * on the floor has nothing to resize against. The gutter is the
34984
- * column's flex SIBLING (the rail's overflow must never clip its hit
34985
- * area) and reports mousedown through onResizeStart — the page owns
34986
- * the drag math and the single clamp (AppSidebar ownership split;
34987
- * ControlBar.onresizeall precedent: layout chrome is a DIRECT child
34988
- * of the route, so prop wiring here breaks no commitment).
34989
- */
34990
- let { width, showGutter = true, children } = $$props;
34991
- $$renderer.push(`<div data-svelte="StickyColumnContainer" class="rail-column svelte-s09nms" data-testid="sidebar-column"${attr_style(`width: ${stringify(width)}px; min-width: ${stringify(width)}px; max-width: ${stringify(width)}px;`)}>`);
34992
- children($$renderer);
34993
- $$renderer.push(`<!----></div> `);
34994
- if (showGutter) {
34995
- $$renderer.push("<!--[0-->");
34996
- $$renderer.push(`<div data-svelte="StickyColumnContainer" class="rail-gutter svelte-s09nms" data-testid="sidebar-gutter" role="separator" aria-orientation="vertical"${attr("aria-label", t(resizesidebar1))}></div>`);
34997
- } else $$renderer.push("<!--[-1-->");
34998
- $$renderer.push(`<!--]-->`);
34999
- });
35000
- }
35001
- //#endregion
35002
- //#region src/lib/components/panels/EmptyFloor.svelte
35003
- function EmptyFloor($$renderer, $$props) {
35004
- $$renderer.component(($$renderer) => {
35005
- $$renderer.push(`<div data-svelte="EmptyFloor" class="empty-floor svelte-z8g5d9" data-testid="workspace-empty"><p>${escape_html(t(noconversations1))}</p> <p class="hint svelte-z8g5d9">${escape_html(t(picksession1))}</p></div>`);
35006
- });
35007
- }
35008
- //#endregion
35009
- //#region src/lib/services/conversation/spine-feed.svelte.ts
35010
- var spineFeed = {
35011
- rows: [],
35012
- presets: [],
35013
- a2aRows: [],
35014
- workspaces: []
35015
- };
35016
- //#endregion
35017
- //#region src/lib/services/workspace/page-feeds.svelte.ts
35018
- var PageFeeds = class {
35019
- coldCache = {};
35020
- coldInFlight = new SvelteSet();
35021
- deadSessions = {};
35022
- edgeCache = {};
35023
- /** Seed-arrival prime: the seed panel mounts with full cold props on
35024
- * paint one (SSR parity for the seed path). Load-time constant. */
35025
- primeSeed(sessionId, cold) {
35026
- this.coldCache = {
35027
- ...this.coldCache,
35028
- [sessionId]: cold
35029
- };
35030
- }
35031
- /** Record an ADD-time parent edge (the route's doAdd fork path). */
35032
- rememberEdge(childSessionId, parentSessionId) {
35033
- this.edgeCache = {
35034
- ...this.edgeCache,
35035
- [childSessionId]: parentSessionId
35036
- };
35037
- }
35038
- /** One dual fetch, registries kept honest (in-flight guard, dead
35039
- * session card, loader clear in `finally`). The fetcher is injected:
35040
- * the wire call stays the route's (`fetchCold` reads the host
35041
- * config); the bookkeeping lives here. */
35042
- async runCold(sessionId, fetchCold) {
35043
- if (this.coldCache[sessionId] !== void 0 || this.coldInFlight.has(sessionId)) return;
35044
- this.coldInFlight = new SvelteSet(this.coldInFlight).add(sessionId);
35045
- try {
35046
- const cold = await fetchCold(sessionId);
35047
- if (cold !== null) this.coldCache = {
35048
- ...this.coldCache,
35049
- [sessionId]: cold
35050
- };
35051
- else this.deadSessions = {
35052
- ...this.deadSessions,
35053
- [sessionId]: `Session ${sessionId} not found on the DSH host. It may have been reaped.`
35054
- };
35055
- } finally {
35056
- const next = new SvelteSet(this.coldInFlight);
35057
- next.delete(sessionId);
35058
- this.coldInFlight = next;
35059
- }
35060
- }
35061
- /** The floor's two lifecycle feeds (call during component init —
35062
- * `$effect` needs an owner):
35063
- * - Prompt Sync hygiene (ADR "The Prompt Sync" D1/D6): a session
35064
- * that left the floor holds no check and no snapshot; count 0
35065
- * clears the broadcast. Conversation sessions only (D6).
35066
- * - Spine feed lifecycle (W8): ref-counted single timer started on
35067
- * mount, stopped on destroy; the a2a window rides the floor's
35068
- * conversation senders (first sender per tick, never per panel).
35069
- * Returns the spine subscription's cleanup. */
35070
- installFeeds(getConversationSessionIds) {
35071
- return () => {};
35072
- }
35073
- };
35074
- var pageFeeds = new PageFeeds();
35075
- /**
35076
- * The open workspace explorer for a workspace ROOT — The Shared Tree ADR
35077
- * (2026-09-17) D1's dedupe key: ONE explorer per ROOT across ALL sessions,
35078
- * so a chip click on any session sharing the root FOCUSES instead of
35079
- * adding (a duplicate is a bug, not a feature). The retired per-session
35080
- * key ("two sessions sharing one workspace hold distinct explorers",
35081
- * Workspace Explorer D4) produced N byte-identical trees for N sessions.
35082
- */
35083
- function findWorkspaceExplorerPanel(panels, root) {
35084
- return panels.find((p) => p.kind === "workspace-explorer" && p.root === root);
35085
- }
35086
- /**
35087
- * The explorer's slot (The Shared Tree ADR 2026-09-17, D3): the FOCUSED
35088
- * slot — the explorer is NOT a lineage child; a workspace tree has no
35089
- * parent session, only an opener. The retired after-source rule
35090
- * (Workspace Explorer D3, "Parent → explorer → file") interposed the
35091
- * panel inside a conversation's family unit — the family clamp inside
35092
- * focusedInsertionSlot still keeps any real family unsplit.
35093
- */
35094
- function workspaceExplorerSlot(panels, selectedIndex, facts) {
35095
- return focusedInsertionSlot(panels, selectedIndex, facts.parentOf);
35096
- }
35097
- /**
35098
- * The glass FIRST slot under its opener (operator ruling 2026-10-24):
35099
- * a summoned/spawned glass lands DIRECTLY below its opener - past the
35100
- * opener document tail, BEFORE every adopted child - matching the
35101
- * spine tree wire order -1 (the ghost always reads as the first
35102
- * child). Supersedes the region-end placement for the glass only.
35103
- */
35104
- function glassFirstSlot(panels, openedBy) {
35105
- const openerIdx = panels.findIndex((p) => p.kind === "conversation" && p.sessionId === openedBy);
35106
- if (openerIdx === -1) return panels.length;
35107
- return docTailEnd(panels, openerIdx, openedBy) + 1;
35108
- }
35109
- /**
35110
- * Insert-before-focused slot (operator spec, 2026-08-31): a fresh panel
35111
- * lands at the FOCUSED panel's index — immediately before it — and takes
35112
- * focus (the route selects it). 0 when nothing is focused (empty floor,
35113
- * stale selection) — the old front-add stays the fallback. Math.max keeps
35114
- * splice's negative-index semantics out of the no-selection case.
35115
- *
35116
- * Family clamp (lineage I2): a slot strictly inside a family would wedge
35117
- * the newcomer between a spawner and its pinned child — unitOf/blockBounds,
35118
- * the sidebar's familyRenderOrder, and the adoption slot walk all assume
35119
- * families stay contiguous on the floor. When the focus is a family CHILD,
35120
- * the slot climbs to the family head — the nearest non-splitting slot left
35121
- * of the focus (parentOf only carries on-floor parents, so an orphan child
35122
- * is a root here, its own unit). A lone panel or a family head keeps the
35123
- * exact focus slot.
35124
- *
35125
- * Manager focus (ADR D6): no session, no family — the slot is the focus
35126
- * itself.
35127
- *
35128
- * Workspace member focus (2026-09-10): the explorer/file pair is a family
35129
- * unit in the SAME block math (blockBounds — the Loadinjected D3 walk-back
35130
- * grammar), so the clamp is the SAME one: insert at the unit head — the
35131
- * PARENT position, left of the block — never between explorer and file.
35132
- */
35133
- function focusedInsertionSlot(panels, selectedIndex, parentOf) {
35134
- const focus = Math.max(0, selectedIndex);
35135
- const focused = panels[focus];
35136
- if (focused === void 0) return 0;
35137
- if (focused.kind === "workspace-explorer" || focused.kind === "workspace-file" || focused.kind === "browser") {
35138
- const block = blockBounds(panels, focus, { parentOf });
35139
- return block === null ? focus : block[0];
35140
- }
35141
- if (focused.kind !== "conversation") return focus;
35142
- let head = focused.sessionId;
35143
- for (;;) {
35144
- const parent = parentOf.get(head) ?? null;
35145
- if (parent === null) break;
35146
- head = parent;
35147
- }
35148
- if (head === focused.sessionId) return focus;
35149
- const headIndex = panels.findIndex((p) => p.kind === "conversation" && p.sessionId === head);
35150
- return headIndex >= 0 ? Math.min(headIndex, focus) : focus;
35151
- }
35152
- //#endregion
35153
- //#region src/lib/services/panels/floor-registry/chrome.ts
35154
- /**
35155
- * floor-registry/chrome — panel chrome intents + explorer + file-intent
35156
- * mailbox + removal (ADR-0022 W3).
35157
- *
35158
- * Moved WHOLE from the state home (floor-registry.svelte.ts): the
35159
- * skill-shelf / plugin-rack chrome setters, the ONE-explorer-per-workspace
35160
- * open grammar, the explorer tree/tab/git intents, the file-intent
35161
- * publish/consume mailbox, and family-close removal. Plain module: every
35162
- * write goes through the state home's reactive `st` hub and its
35163
- * primitives (ADR-0019 D2: exactly ONE writer home for floor state).
35164
- * Sibling rule: factories/slots are reached through the state home's
35165
- * re-export hub, never by importing another sibling directly.
35166
- */
35167
- var d$4 = floorSeam;
35168
- /** Chip click action: ONE explorer per WORKSPACE root across ALL
35169
- * sessions — a click on any session sharing the root FOCUSES the open
35170
- * explorer (dedupe key = root, D1); a fresh root lands at the focused
35171
- * slot (D3, non-lineage — the explorer is not a lineage child).
35172
- * sessionId rides the fresh panel as PROVENANCE (D4), never identity. */
35173
- function openWorkspaceExplorer(sessionId, workspace) {
35174
- const open = findWorkspaceExplorerPanel(st.panels, workspace);
35175
- if (open) {
35176
- st.selectedPanelId = open.id;
35177
- return;
35178
- }
35179
- insertPanel(makeWorkspaceExplorerPanel(sessionId, workspace), workspaceExplorerSlot(st.panels, selectedIndex_(), d$4().getMoveFacts()));
35180
- }
35181
- /** Chip click action (The Glass Browser spec W2, ADR-0029 D4): ONE live
35182
- * browser panel across the floor — the terminal singleton rule (Terminal
35183
- * Desk ADR D2). A click on an open browser FOCUSES it; a miss inserts at
35184
- * the focused slot. */
35185
- function openBrowserPanel(index, keepSelection = false, width, openedBy, sessionId) {
35186
- const open = st.panels.find((p) => p.kind === "browser" && p.openedBy === openedBy);
35187
- if (open) {
35188
- st.selectedPanelId = open.id;
35189
- return;
35190
- }
35191
- const prevSelected = st.selectedPanelId;
35192
- const slot = index !== void 0 ? Math.max(0, Math.min(index, st.panels.length)) : openedBy !== void 0 ? glassFirstSlot(st.panels, openedBy) : insertionSlot();
35193
- insertPanel(makeBrowserPanel(width, openedBy, sessionId), slot);
35194
- if (keepSelection && prevSelected !== null && prevSelected !== void 0) {
35195
- if (st.panels.some((p) => p.id === prevSelected)) st.selectedPanelId = prevSelected;
35196
- }
35197
- }
35198
- /** The open explorer for a session's workspace (The Shared Tree D1):
35199
- * matched by ROOT across sessions — the panel's provenance sessionId
35200
- * is not the key. */
35201
- function sessionWorkspaceExplorer(sessionId) {
35202
- const root = d$4().getWorkspaceFor(sessionId);
35203
- return root === null ? void 0 : findWorkspaceExplorerPanel(st.panels, root);
35204
- }
35205
- /** Explorer tree intents: the panel emits toggle/open-file; the owner
35206
- * mutates expanded (the persisted part) — the levels cache stays
35207
- * component-local. */
35208
- function toggleExplorerPath(panelId, path) {
35209
- const idx = st.panels.findIndex((p) => p.id === panelId);
35210
- if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
35211
- const explorer = st.panels[idx];
35212
- const next = explorer.expanded.includes(path) ? explorer.expanded.filter((p) => p !== path) : [...explorer.expanded, path];
35213
- st.panels = st.panels.with(idx, {
35214
- ...explorer,
35215
- expanded: next
35216
- });
35217
- }
35218
- /** Explorer collapse-all intent: the panel emits; the owner empties the
35219
- * expanded list (the persisted part). */
35220
- function collapseExplorerPaths(panelId) {
35221
- const idx = st.panels.findIndex((p) => p.id === panelId);
35222
- if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
35223
- st.panels = st.panels.with(idx, {
35224
- ...st.panels[idx],
35225
- expanded: []
35226
- });
35227
- }
35228
- /** Git Eye tab intent (2026-09-12): the active tab is PERSISTED on the
35229
- * entry — a hard reload restores it. */
35230
- function setExplorerTab(panelId, tab) {
35231
- const idx = st.panels.findIndex((p) => p.id === panelId);
35232
- if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
35233
- st.panels = st.panels.with(idx, {
35234
- ...st.panels[idx],
35235
- tab
35236
- });
35237
- }
35238
- /** Explorer Layout tabs (amendment 2026-09-16): the tab list and the
35239
- * active tab are OWNER-PERSISTED entry facts. The file tabs die with
35240
- * the panel (D5). */
35241
- function openExplorerTab(panelId, path) {
35242
- const idx = st.panels.findIndex((p) => p.id === panelId);
35243
- if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
35244
- const ex = st.panels[idx];
35245
- const tabs = ex.openTabs ?? [];
35246
- const openTabs = tabs.includes(path) ? tabs : [...tabs, path];
35247
- st.panels = st.panels.with(idx, {
35248
- ...ex,
35249
- openTabs,
35250
- activeFile: path
35251
- });
35252
- }
35253
- function closeExplorerTab(panelId, path) {
35254
- const idx = st.panels.findIndex((p) => p.id === panelId);
35255
- if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
35256
- const ex = st.panels[idx];
35257
- const tabs = ex.openTabs ?? [];
35258
- const closedAt = tabs.indexOf(path);
35259
- if (closedAt === -1) return;
35260
- const openTabs = tabs.filter((p) => p !== path);
35261
- const activeFile = ex.activeFile === path ? openTabs.length === 0 ? null : openTabs[Math.max(0, closedAt - 1)] : ex.activeFile ?? null;
35262
- st.panels = st.panels.with(idx, {
35263
- ...ex,
35264
- openTabs,
35265
- activeFile
36021
+ $$renderer.push(`<!--]--> `);
36022
+ if (onremove || lens) {
36023
+ $$renderer.push("<!--[0-->");
36024
+ PanelClose($$renderer, {
36025
+ sessionId,
36026
+ lens});
36027
+ } else $$renderer.push("<!--[-1-->");
36028
+ $$renderer.push(`<!--]--></span></div>`);
35266
36029
  });
35267
36030
  }
35268
- function activateExplorerTab(panelId, path) {
35269
- const idx = st.panels.findIndex((p) => p.id === panelId);
35270
- if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
35271
- const ex = st.panels[idx];
35272
- if (!(ex.openTabs ?? []).includes(path)) return;
35273
- st.panels = st.panels.with(idx, {
35274
- ...ex,
35275
- activeFile: path
36031
+ //#endregion
36032
+ //#region src/lib/components/panels/PanelColumn.svelte
36033
+ function PanelColumn($$renderer, $$props) {
36034
+ $$renderer.component(($$renderer) => {
36035
+ /**
36036
+ * PanelColumn — one panel's fixed-width column shell (Panel Floor W3
36037
+ * task 3.2, ADR-0006): PanelHeader (floor chrome) + the conversation
36038
+ * body (ConversationPanel, keyed by sessionId INSIDE the route's each
36039
+ * — remount locality) + the 6px ResizeGutter after every panel.
36040
+ *
36041
+ * Presentational shell only: width and selection arrive as props
36042
+ * (bound up to the route); the body arrives as a snippet so the ROUTE
36043
+ * owns the {#key panel.sessionId} remount and the per-panel cold data.
36044
+ *
36045
+ * Width badge (2026-08-28): a `widthBadge` phase prop ('live' during
36046
+ * a gutter drag that moves this panel's width, 'fading' through the
36047
+ * 10s afterglow) floats the CURRENT width at the column's top right,
36048
+ * below the header's controls, pointer-transparent — the route owns
36049
+ * the membership rule (changed-from-snapshot) and the fade timer.
36050
+ */
36051
+ let { panel, index, selected, widthBadge = null, copyValue, canMoveLeft = false, canMoveRight = false, onremove, children } = $$props;
36052
+ $$renderer.push(`<div data-svelte="PanelColumn"${attr_class("column svelte-1cuodug", void 0, { "selected": selected })} data-testid="panel-column"${attr("data-panel-id", panel.id)}${attr("data-session-id", panel.kind === "conversation" ? panel.sessionId : null)}${attr_style(`width: ${stringify(panel.width)}px; min-width: ${stringify(panel.width)}px; max-width: ${stringify(panel.width)}px;`)}>`);
36053
+ PanelHeader($$renderer, {
36054
+ panelId: panel.id,
36055
+ sessionId: panel.kind === "conversation" ? panel.sessionId : "",
36056
+ label: panelHeaderLabel(panel),
36057
+ copyValue: panel.kind === "workspace-explorer" ? panel.root : panel.kind === "workspace-file" ? copyValue : void 0,
36058
+ copyLabel: panel.kind === "workspace-explorer" ? t(workspaceexplorercopyworkspace3) : panel.kind === "workspace-file" ? t(workspacefilecopyfilename3) : void 0,
36059
+ labelTestId: panel.kind === "workspace-explorer" ? "explorer-title" : panel.kind === "workspace-file" ? "file-title" : void 0,
36060
+ selected,
36061
+ canMoveLeft,
36062
+ canMoveRight,
36063
+ onremove
36064
+ });
36065
+ $$renderer.push(`<!----> `);
36066
+ if (widthBadge !== null) {
36067
+ $$renderer.push("<!--[0-->");
36068
+ $$renderer.push(`<span${attr_class("width-badge svelte-1cuodug", void 0, { "fading": widthBadge === "fading" })} data-testid="panel-width-badge"${attr("data-badge-phase", widthBadge)} aria-hidden="true">${escape_html(Math.round(panel.width))}px</span>`);
36069
+ } else $$renderer.push("<!--[-1-->");
36070
+ $$renderer.push(`<!--]--> <div class="body svelte-1cuodug">`);
36071
+ children($$renderer);
36072
+ $$renderer.push(`<!----></div></div> `);
36073
+ ResizeGutter($$renderer, { index });
36074
+ $$renderer.push(`<!---->`);
35276
36075
  });
35277
36076
  }
35278
- /** The Explorer Layout drag settle (ADR D4): one DESK fact — the split
35279
- * is desk state, persisted with the floor blob, NOT per entry. The
35280
- * panel already clamped; clamp again at the single bound site. */
35281
- function setExplorerTreePct(_panelId, pct) {
35282
- d$4().setTreePct(clampTreePct(pct));
35283
- }
35284
- /** Git Eye repo-collapse intent (2026-09-13): the collapsed repo set is
35285
- * PERSISTED on the entry. Default is EXPANDED. */
35286
- function toggleExplorerRepo(panelId, repoRel) {
35287
- const idx = st.panels.findIndex((p) => p.id === panelId);
35288
- if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
35289
- const explorer = st.panels[idx];
35290
- const prev = explorer.collapsedRepos ?? [];
35291
- const next = prev.includes(repoRel) ? prev.filter((r) => r !== repoRel) : [...prev, repoRel];
35292
- st.panels = st.panels.with(idx, {
35293
- ...explorer,
35294
- collapsedRepos: next
36077
+ //#endregion
36078
+ //#region src/lib/components/panels/PanelLoupe.svelte
36079
+ function PanelLoupe($$renderer, $$props) {
36080
+ $$renderer.component(($$renderer) => {
36081
+ /**
36082
+ * PanelLoupe — the reading lens over one floor panel (The Panel Loupe
36083
+ * ADR D2/D5, 2026-09-04): a body-portaled modal dialog that renders
36084
+ * one panel's content at reading size while the floor keeps its
36085
+ * zoom. ANY kind lenses (The Loupe for Every Panel, 2026-09-08): the
36086
+ * route feeds the SAME body snippet the column renders (D7 — one
36087
+ * ladder, two sites) and the header rides the panel's label variant;
36088
+ * the loupe itself carries no conversation logic.
36089
+ *
36090
+ * Contract donor: ImageLightbox (2026-08-28) — the portal, the fixed
36091
+ * inset-0 z-[1000] layer, role="dialog" aria-modal, the mask's
36092
+ * mousedown close, Escape, the × control, focus to the × on open and
36093
+ * back to the opener on close. The portal is load-bearing: the floor
36094
+ * row carries transform: scale(), and a fixed backdrop inside a
36095
+ * transformed ancestor is trapped in that ancestor's box instead of
36096
+ * covering the viewport (ADR D2). The action is inlined here by
36097
+ * decision — the donor is cited, not modified or refactored.
36098
+ *
36099
+ * Lens flag (D8): setLensMode(true) during init, BEFORE children
36100
+ * render — every floor-verb control inside the body snippet reads the
36101
+ * flag at its own init and renders visible-disabled. Context follows
36102
+ * the component tree, so the flag reaches snippet content even after
36103
+ * the portal moves the DOM under document.body (asserted by the loupe
36104
+ * unit tests).
36105
+ *
36106
+ * The lens × and this header's copy-id are the loupe's live controls;
36107
+ * the header's move/close render visible-disabled (the floor verbs).
36108
+ * Openness is the route's session-local state — never persisted (D5).
36109
+ */
36110
+ let { panelId, sessionId, label = void 0, children } = $$props;
36111
+ setLensMode(true);
36112
+ $$renderer.push(`<div data-svelte="PanelLoupe" class="fixed inset-0 z-[1000] grid place-items-center p-10" role="dialog" aria-modal="true"${attr("aria-label", t(panelloupe1))} data-testid="panel-loupe"${attr("data-panel-id", panelId)}${attr("data-session-id", sessionId)}><div class="absolute inset-0 bg-black/60" aria-hidden="true" data-testid="panel-loupe-mask"></div> <div class="relative" style="width: min(100vw - 4rem, 850px); height: min(95vh, calc(100vh - 5rem));" data-testid="panel-loupe-sheet"><div class="flex h-full w-full flex-col overflow-hidden rounded-xl shadow-2xl" style="background: var(--color-surface-primary, var(--color-surface-elevated));">`);
36113
+ PanelHeader($$renderer, {
36114
+ panelId,
36115
+ sessionId,
36116
+ label,
36117
+ lens: true
36118
+ });
36119
+ $$renderer.push(`<!----> <div class="flex min-h-0 flex-1 flex-col overflow-hidden">`);
36120
+ children($$renderer);
36121
+ $$renderer.push(`<!----></div></div> <button type="button"${attr("aria-label", t(closeloupe1))} data-testid="panel-loupe-close" class="absolute -top-3 -right-3 z-10 flex h-9 w-9 cursor-pointer items-center justify-center rounded-full border border-surface-border bg-surface-elevated text-lg leading-none text-text-primary shadow-md hover:bg-surface-hover">×</button></div></div>`);
35295
36122
  });
35296
36123
  }
35297
- /** Git Eye collapse-all-repos intent (2026-09-13): collapses EVERY known
35298
- * repo — persisted like the single-repo toggle. */
35299
- function collapseExplorerRepos(panelId, repos) {
35300
- const idx = st.panels.findIndex((p) => p.id === panelId);
35301
- if (idx < 0 || st.panels[idx].kind !== "workspace-explorer") return;
35302
- const explorer = st.panels[idx];
35303
- const prev = explorer.collapsedRepos ?? [];
35304
- const next = [...prev, ...repos.filter((r) => !prev.includes(r))];
35305
- st.panels = st.panels.with(idx, {
35306
- ...explorer,
35307
- collapsedRepos: next
36124
+ //#endregion
36125
+ //#region src/lib/components/panels/StickyColumnContainer.svelte
36126
+ function StickyColumnContainer($$renderer, $$props) {
36127
+ $$renderer.component(($$renderer) => {
36128
+ /**
36129
+ * StickyColumnContainer — a fixed-width LEADING column inside the zoom
36130
+ * row (OCI StickyColumnContainer port, 2026-08-26; hosts the embedded
36131
+ * AppSidebar the way OCI's hosts ControlRail).
36132
+ *
36133
+ * "Sticky" = the width is TRIPLE-LOCKED (width/min/max all the same
36134
+ * px), unlike panel columns whose widths live in [MIN, MAX]: the rail
36135
+ * never flexes when the row measures itself at max-content. The
36136
+ * column's background paints the full column height — the rail inside
36137
+ * fills it (align-items: stretch).
36138
+ *
36139
+ * The trailing ResizeGutter is included BY DEFAULT (OCI parity) but
36140
+ * only when panel columns actually follow (showGutter) — a rail alone
36141
+ * on the floor has nothing to resize against. The gutter is the
36142
+ * column's flex SIBLING (the rail's overflow must never clip its hit
36143
+ * area) and reports mousedown through onResizeStart — the page owns
36144
+ * the drag math and the single clamp (AppSidebar ownership split;
36145
+ * ControlBar.onresizeall precedent: layout chrome is a DIRECT child
36146
+ * of the route, so prop wiring here breaks no commitment).
36147
+ */
36148
+ let { width, showGutter = true, children } = $$props;
36149
+ $$renderer.push(`<div data-svelte="StickyColumnContainer" class="rail-column svelte-s09nms" data-testid="sidebar-column"${attr_style(`width: ${stringify(width)}px; min-width: ${stringify(width)}px; max-width: ${stringify(width)}px;`)}>`);
36150
+ children($$renderer);
36151
+ $$renderer.push(`<!----></div> `);
36152
+ if (showGutter) {
36153
+ $$renderer.push("<!--[0-->");
36154
+ $$renderer.push(`<div data-svelte="StickyColumnContainer" class="rail-gutter svelte-s09nms" data-testid="sidebar-gutter" role="separator" aria-orientation="vertical"${attr("aria-label", t(resizesidebar1))}></div>`);
36155
+ } else $$renderer.push("<!--[-1-->");
36156
+ $$renderer.push(`<!--]-->`);
35308
36157
  });
35309
36158
  }
35310
- /** File Eye view intent (2026-09-13): diff vs edit is PERSISTED on the
35311
- * entry. */
35312
- function setFileView(panelId, view) {
35313
- const idx = st.panels.findIndex((p) => p.id === panelId);
35314
- if (idx < 0 || st.panels[idx].kind !== "workspace-file") return;
35315
- st.panels = st.panels.with(idx, {
35316
- ...st.panels[idx],
35317
- view
36159
+ //#endregion
36160
+ //#region src/lib/components/panels/EmptyFloor.svelte
36161
+ function EmptyFloor($$renderer, $$props) {
36162
+ $$renderer.component(($$renderer) => {
36163
+ $$renderer.push(`<div data-svelte="EmptyFloor" class="empty-floor svelte-z8g5d9" data-testid="workspace-empty"><p>${escape_html(t(noconversations1))}</p> <p class="hint svelte-z8g5d9">${escape_html(t(picksession1))}</p></div>`);
35318
36164
  });
35319
36165
  }
35320
- /** Tree file-click action (The Settings Tree ADR 2026-09-18 D1): the
35321
- * intent publishes to the session's explorer, which opens/focuses a
35322
- * tab. No open explorer ⇒ the intent drops. */
35323
- function openWorkspaceFile(sessionId, path, lines) {
35324
- const host = sessionWorkspaceExplorer(sessionId);
35325
- if (host) publishFileIntent(host.id, path, lines);
35326
- }
35327
- /** Publish a file intent to an explorer panel and focus it. `lines` is
35328
- * the optional #L anchor target — display metadata, not persisted. */
35329
- function publishFileIntent(explorerId, path, lines) {
35330
- st.pendingFileIntents[explorerId] = {
35331
- path,
35332
- nonce: ++st.fileIntentSeq,
35333
- lines: lines ?? null
35334
- };
35335
- st.selectedPanelId = explorerId;
35336
- }
35337
- /** The panel consumed intent nonce N — clear exactly that publish. */
35338
- function consumeFileIntent(explorerId, nonce) {
35339
- if (st.pendingFileIntents[explorerId]?.nonce === nonce) st.pendingFileIntents[explorerId] = null;
35340
- }
35341
- /** Remove a panel; family close walks the wire lineage transitively
35342
- * (every descendant sub-agent goes with it, nested included). The
35343
- * Shift+Click amendment (2026-09-01): family === false opts OUT — only
35344
- * THAT panel drops, the children re-root as orphan family heads.
35345
- *
35346
- * The session's workspace pair closes with it (2026-09-10); closing an
35347
- * EXPLORER dooms its file children BY PANEL ID — the stored
35348
- * explorerPanelId edge, with the legacy null-edge fallback. A
35349
- * settings-home explorer (sessionId null) dies with the close. */
35350
- function removePanel(panelId, opts = {}) {
35351
- const idx = st.panels.findIndex((p) => p.id === panelId);
35352
- if (idx < 0) return;
35353
- const root = st.panels[idx];
35354
- const rootSessionId = root.kind === "conversation" ? root.sessionId : null;
35355
- const doomed = new SvelteSet(rootSessionId !== null ? [rootSessionId] : []);
35356
- if (opts.family !== false && rootSessionId !== null) {
35357
- const stack = [rootSessionId];
35358
- while (stack.length > 0) for (const kid of d$4().getLineageFacts().childrenByParent.get(stack.pop()) ?? []) if (!doomed.has(kid.sessionId)) {
35359
- doomed.add(kid.sessionId);
35360
- stack.push(kid.sessionId);
35361
- }
35362
- }
35363
- const doomedPanelIds = new SvelteSet();
35364
- if (opts.family !== false && rootSessionId !== null) {
35365
- for (const p of st.panels) if (p.kind === "browser" && p.openedBy !== void 0 && doomed.has(p.openedBy)) doomedPanelIds.add(p.id);
35366
- }
35367
- if (opts.family !== false && root.kind === "workspace-explorer") {
35368
- 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);
35369
- }
35370
- st.panels = st.panels.filter((p) => p.id !== root.id && !doomedPanelIds.has(p.id) && (p.kind === "conversation" ? !doomed.has(p.sessionId) : !("sessionId" in p) || p.sessionId === null || opts.family !== false && !doomed.has(p.sessionId)));
35371
- if (st.selectedPanelId !== null && !st.panels.some((p) => p.id === st.selectedPanelId)) st.selectedPanelId = st.panels[Math.min(idx, st.panels.length - 1)]?.id ?? null;
35372
- clearLoupeIfGone();
35373
- }
35374
36166
  //#endregion
35375
- //#region src/lib/services/panels/floor-registry/drag.svelte.ts
35376
- var d$2 = floorSeam;
35377
- /** Honest-slider's "slider sets all panels" leg (REALTIME, 2026-08-27):
35378
- * one width for every CONVERSATION column + the uniform preset.
35379
- * 2026-09-13: the workspace kinds are FIXED lanes — the explorer and
35380
- * file panels keep their own widths. */
35381
- function resizeAll(width) {
35382
- const w = clampPanelWidth(width);
35383
- d$2().setPanelWidthPreset(w);
35384
- st.panels = st.panels.map((p) => p.kind === "conversation" ? {
35385
- ...p,
35386
- width: w
35387
- } : p);
35388
- }
35389
- /** A transcript file link publishes ONLY after the tree route proves
35390
- * the file exists inside the session's workspace — the gate lives in
35391
- * the shared util; anything else drops the click. No navigation ever
35392
- * happens. No explorer yet ⇒ OPEN ONE (amendment 2026-09-25): the link
35393
- * itself opens the panel; without a workspace root there is nothing to
35394
- * open. W2 (T2.3): moved wholesale from the route — pure machine over
35395
- * the deps seam + the shared utils. */
35396
- async function openFileLinkFromMarkdown(sessionId, rawHref) {
35397
- const { path, lines } = parseFileLinkHref(rawHref);
35398
- if (path === "") return;
35399
- const target = await resolveFileLinkTarget(sessionId, path, d$2().getWorkspaceFor(sessionId), void 0, workspaceRootDirs);
35400
- if (target === null) return;
35401
- if (!sessionWorkspaceExplorer(sessionId)) {
35402
- const root = d$2().getWorkspaceFor(sessionId);
35403
- if (!root) return;
35404
- openWorkspaceExplorer(sessionId, root);
36167
+ //#region src/lib/services/conversation/spine-feed.svelte.ts
36168
+ var spineFeed = {
36169
+ rows: [],
36170
+ presets: [],
36171
+ a2aRows: [],
36172
+ workspaces: []
36173
+ };
36174
+ //#endregion
36175
+ //#region src/lib/services/workspace/page-feeds.svelte.ts
36176
+ var PageFeeds = class {
36177
+ coldCache = {};
36178
+ coldInFlight = new SvelteSet();
36179
+ deadSessions = {};
36180
+ edgeCache = {};
36181
+ /** Seed-arrival prime: the seed panel mounts with full cold props on
36182
+ * paint one (SSR parity for the seed path). Load-time constant. */
36183
+ primeSeed(sessionId, cold) {
36184
+ this.coldCache = {
36185
+ ...this.coldCache,
36186
+ [sessionId]: cold
36187
+ };
35405
36188
  }
35406
- openWorkspaceFile(sessionId, target, lines);
35407
- }
35408
- /** /events?full=1 carries entries+lastSeq+running+pending/settled
35409
- * answers (the ledger-tail resync surface); /history carries hasMore.
35410
- * Its beforeSeq anchor needs the tail's lastSeq, so the events response
35411
- * resolves first — the only serialization. W2 (T2.6): moved wholesale
35412
- * from the route — a pure wire read over the global fetch. */
35413
- async function fetchColdFromWire(sessionId) {
35414
- const eventsRes = await fetch(`/api/dsh/session/${encodeURIComponent(sessionId)}/events?full=1`);
35415
- if (!eventsRes.ok) return null;
35416
- const events = await eventsRes.json();
35417
- if (!events.ok) return null;
35418
- const lastSeq = events.lastSeq ?? -1;
35419
- let hasMore = false;
35420
- const historyRes = await fetch(`/api/dsh/session/${encodeURIComponent(sessionId)}/history?beforeSeq=${lastSeq + 1}`);
35421
- if (historyRes.ok) {
35422
- const history = await historyRes.json();
35423
- if (history.ok) hasMore = (history.entries?.length ?? 0) > 0 || history.hasMore === true;
36189
+ /** Record an ADD-time parent edge (the route's doAdd fork path). */
36190
+ rememberEdge(childSessionId, parentSessionId) {
36191
+ this.edgeCache = {
36192
+ ...this.edgeCache,
36193
+ [childSessionId]: parentSessionId
36194
+ };
35424
36195
  }
35425
- return {
35426
- title: null,
35427
- workspace: null,
35428
- agentPreset: null,
35429
- entries: events.entries ?? [],
35430
- lastSeq,
35431
- running: events.running ?? false,
35432
- hasMore,
35433
- pendingAnswers: events.pendingAnswers ?? [],
35434
- settledAnswers: events.settledAnswers ?? [],
35435
- permission: events.permission ?? null,
35436
- imageLimits: events.imageLimits ?? null,
35437
- knobEvents: events.knobEvents ?? [],
35438
- deliverables: events.deliverables ?? []
35439
- };
35440
- }
35441
- //#endregion
35442
- //#region src/lib/services/panels/floor-registry/factories.ts
35443
- /**
35444
- * floor-registry/factories — panel factories + placement slots (ADR-0022 W2).
35445
- *
35446
- * Moved WHOLE from the state home (floor-registry.svelte.ts): the eight
35447
- * make* panel factories and the slot grammar (insertPanel, insertionSlot,
35448
- * pinnedSlotIndex). Plain module: no runes here — every write goes through
35449
- * the state home's reactive `st` hub and its primitives (ADR-0019 D2:
35450
- * exactly ONE writer home for floor state). Sibling rule: this file never
35451
- * imports another sibling; shared needs come from the state home.
35452
- */
35453
- var d$1 = floorSeam;
35454
- function makePanel(sessionId, agentPreset) {
35455
- return {
35456
- id: nextPanelId(),
35457
- kind: "conversation",
35458
- sessionId,
35459
- agentPreset,
35460
- width: clampPanelWidth(d$1().getPanelWidth())
35461
- };
35462
- }
35463
- /** width: the reload-restored panel re-mints at the width the operator
35464
- * dragged before (browser-slot persistence, RCA 2026-10-22); absent for
35465
- * chip clicks and legacy slots — the honest-slider preset.
35466
- * openedBy: the opener session's provenance, recorded ONCE at spawn and
35467
- * never rewritten (ADR-0036 D1/D2); undefined = no conversation context. */
35468
- function makeBrowserPanel(width, openedBy, sessionId) {
35469
- return {
35470
- id: nextPanelId(),
35471
- kind: "browser",
35472
- width: clampPanelWidth(width ?? d$1().getPanelWidth()),
35473
- ...openedBy !== void 0 ? { openedBy } : {},
35474
- ...sessionId !== void 0 ? { browserSessionId: sessionId } : {}
35475
- };
35476
- }
35477
- function makeWorkspaceExplorerPanel(sessionId, root) {
35478
- return {
35479
- id: nextPanelId(),
35480
- kind: "workspace-explorer",
35481
- sessionId,
35482
- root,
35483
- expanded: [],
35484
- width: clampPanelWidth(850, "workspace-explorer")
35485
- };
35486
- }
35487
- function insertPanel(entry, index) {
35488
- const next = [...st.panels];
35489
- next.splice(Math.min(index, next.length), 0, entry);
35490
- st.panels = next;
35491
- st.selectedPanelId = entry.id;
35492
- }
35493
- function insertionSlot() {
35494
- return focusedInsertionSlot(st.panels, selectedIndex_(), d$1().getMoveFacts().parentOf);
35495
- }
35496
- //#endregion
35497
- //#region src/lib/services/panels/floor-registry.svelte.ts
35498
- var deps = null;
35499
- function configureFloorRegistry(d0) {
35500
- deps = d0;
35501
- }
35502
- function d() {
35503
- if (deps === null) throw new Error("floor-registry: configureFloorRegistry() was never called");
35504
- return deps;
35505
- }
35506
- /** Sibling-module access to the dep seam (ADR-0022 W2): the ONE outside-reads
35507
- * channel; siblings never open their own config channel. */
35508
- function floorSeam() {
35509
- return d();
35510
- }
35511
- var st = {
35512
- panels: [],
35513
- selectedPanelId: null,
35514
- loupePanelId: null,
35515
- focusComposerId: null,
35516
- panelIdSeq: 0,
35517
- terminalDeskMirrors: {},
35518
- pendingFileIntents: {},
35519
- fileIntentSeq: 0,
35520
- drag: null,
35521
- widthBadgeFading: false
35522
- };
35523
- /** Non-reactive gesture refs (drag start index, fade timer, badge ids) —
35524
- * written by floor-registry/drag.svelte.ts; the ids set is a live
35525
- * SvelteSet so badge visibility stays reactive. */
35526
- var dragRefs = {
35527
- ids: new SvelteSet()
35528
- };
35529
- var floor = {
35530
- get panels() {
35531
- return st.panels;
35532
- },
35533
- get selectedPanelId() {
35534
- return st.selectedPanelId;
35535
- },
35536
- get loupePanelId() {
35537
- return st.loupePanelId;
35538
- },
35539
- get focusComposerId() {
35540
- return st.focusComposerId;
35541
- },
35542
- get terminalDeskMirrors() {
35543
- return st.terminalDeskMirrors;
35544
- },
35545
- get pendingFileIntents() {
35546
- return st.pendingFileIntents;
35547
- },
35548
- get drag() {
35549
- return st.drag;
35550
- },
35551
- get widthBadgeFading() {
35552
- return st.widthBadgeFading;
35553
- },
35554
- get widthBadgeIds() {
35555
- return dragRefs.ids;
35556
- },
35557
- get selected() {
35558
- return st.panels.find((p) => p.id === st.selectedPanelId) ?? null;
35559
- },
35560
- get loupePanel() {
35561
- return st.panels.find((p) => p.id === st.loupePanelId) ?? null;
36196
+ /** One dual fetch, registries kept honest (in-flight guard, dead
36197
+ * session card, loader clear in `finally`). The fetcher is injected:
36198
+ * the wire call stays the route's (`fetchCold` reads the host
36199
+ * config); the bookkeeping lives here. */
36200
+ async runCold(sessionId, fetchCold) {
36201
+ if (this.coldCache[sessionId] !== void 0 || this.coldInFlight.has(sessionId)) return;
36202
+ this.coldInFlight = new SvelteSet(this.coldInFlight).add(sessionId);
36203
+ try {
36204
+ const cold = await fetchCold(sessionId);
36205
+ if (cold !== null) this.coldCache = {
36206
+ ...this.coldCache,
36207
+ [sessionId]: cold
36208
+ };
36209
+ else this.deadSessions = {
36210
+ ...this.deadSessions,
36211
+ [sessionId]: `Session ${sessionId} not found on the DSH host. It may have been reaped.`
36212
+ };
36213
+ } finally {
36214
+ const next = new SvelteSet(this.coldInFlight);
36215
+ next.delete(sessionId);
36216
+ this.coldInFlight = next;
36217
+ }
35562
36218
  }
35563
- };
35564
- function nextPanelId() {
35565
- st.panelIdSeq += 1;
35566
- return "panel-" + st.panelIdSeq;
35567
- }
35568
- function syncPanelIdSeq(entries) {
35569
- for (const p of entries) {
35570
- const m = /^panel-(\d+)$/.exec(p.id);
35571
- if (m) st.panelIdSeq = Math.max(st.panelIdSeq, Number(m[1]));
36219
+ /** The floor's two lifecycle feeds (call during component init —
36220
+ * `$effect` needs an owner):
36221
+ * - Prompt Sync hygiene (ADR "The Prompt Sync" D1/D6): a session
36222
+ * that left the floor holds no check and no snapshot; count 0
36223
+ * clears the broadcast. Conversation sessions only (D6).
36224
+ * - Spine feed lifecycle (W8): ref-counted single timer started on
36225
+ * mount, stopped on destroy; the a2a window rides the floor's
36226
+ * conversation senders (first sender per tick, never per panel).
36227
+ * Returns the spine subscription's cleanup. */
36228
+ installFeeds(getConversationSessionIds) {
36229
+ return () => {};
35572
36230
  }
35573
- }
35574
- function initFloor(entries, selectedId) {
35575
- st.panels = entries;
35576
- st.selectedPanelId = selectedId;
35577
- syncPanelIdSeq(entries);
35578
- }
35579
- /** The fresh panel mounted and its composer took focus — clear the
35580
- * swap-focus marker (a marker whose panel never mounts stays inert:
35581
- * panel ids are unique and never remount). */
35582
- function clearFocusComposer() {
35583
- st.focusComposerId = null;
35584
- }
35585
- function selectPanel(panelId) {
35586
- if (st.panels.some((p) => p.id === panelId)) st.selectedPanelId = panelId;
35587
- }
35588
- function closeLoupe() {
35589
- st.loupePanelId = null;
35590
- }
35591
- function clearLoupeIfGone() {
35592
- if (st.loupePanelId !== null && !st.panels.some((p) => p.id === st.loupePanelId)) st.loupePanelId = null;
35593
- }
35594
- function selectedIndex_() {
35595
- return st.panels.findIndex((p) => p.id === st.selectedPanelId);
35596
- }
36231
+ };
36232
+ var pageFeeds = new PageFeeds();
35597
36233
  //#endregion
35598
36234
  //#region src/lib/services/panels/glass-release.ts
35599
36235
  /**
@@ -36117,4 +36753,4 @@ function _page($$renderer, $$props) {
36117
36753
  }
36118
36754
 
36119
36755
  export { _page as default };
36120
- //# sourceMappingURL=_page.svelte.js-7xWLRsiZ.js.map
36756
+ //# sourceMappingURL=_page.svelte.js-CY7zcWr4.js.map