@symerian/symi 3.5.19 → 3.5.21

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 (261) hide show
  1. package/dist/{agent-D0Z4r5fr.js → agent-DgVWcnlD.js} +1 -1
  2. package/dist/{agent-DCDT-MPE.js → agent-NT0EKnK_.js} +18 -18
  3. package/dist/{agent-scope-DOrZjOnW.js → agent-scope-Bnsyyeci.js} +18 -18
  4. package/dist/{agents-CdkBeP0d.js → agents-Dlcpc1K3.js} +3 -3
  5. package/dist/{agents.config-B7sNDvhz.js → agents.config-DA0ISLi7.js} +1 -1
  6. package/dist/{audit-B7deV4Lp.js → audit-CPloCzEZ.js} +2 -2
  7. package/dist/{audit-BCStg-Hv.js → audit-CXIXYDRx.js} +20 -20
  8. package/dist/{auth-choice-BIGcxSzP.js → auth-choice--DymOp5O.js} +2 -2
  9. package/dist/{auth-choice-B3DU-aBr.js → auth-choice-BtXIQPTU.js} +11 -11
  10. package/dist/{auth-profiles-Ce7R_25e.js → auth-profiles-D5nYBj_Z.js} +2 -2
  11. package/dist/{auth-token-Cr28IDKY.js → auth-token-fgnCQEHT.js} +3 -3
  12. package/dist/{banner-ChNdzPjD.js → banner-CY_9VW7E.js} +1 -1
  13. package/dist/{browser-cli-C9xaKW8l.js → browser-cli-C5VVk6C9.js} +3 -3
  14. package/dist/{browser-cli-BTg8SVs-.js → browser-cli-DOTM7UBC.js} +9 -9
  15. package/dist/build-info.json +3 -3
  16. package/dist/bundled/boot-md/handler.js +4 -4
  17. package/dist/bundled/session-memory/handler.js +4 -4
  18. package/dist/{call-BccaLPi8.js → call-Bpjj5p7I.js} +9 -9
  19. package/dist/{call-DZg43vv8.js → call-C2urR5Fj.js} +1 -1
  20. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  21. package/dist/{channel-options-CUptVX8c.js → channel-options-XRJiHUm5.js} +1 -1
  22. package/dist/{channel-options-LLmAnD_L.js → channel-options-rFgJaKzJ.js} +1 -1
  23. package/dist/{channels-cli-xoromnio.js → channels-cli-CQ4M05oy.js} +57 -57
  24. package/dist/{channels-cli-B0OQvVUL.js → channels-cli-QMHCRAb5.js} +9 -9
  25. package/dist/{chrome-DJChpTwP.js → chrome-38OnGyuN.js} +2 -2
  26. package/dist/{chrome-CmQwGAuL.js → chrome-3jl2ulOE.js} +4 -4
  27. package/dist/{chrome-DNssqQJs.js → chrome-OTJg3QKn.js} +4 -4
  28. package/dist/{cli-C7v-sID8.js → cli-B-uoiYP2.js} +45 -45
  29. package/dist/{cli-CMNR7ULk.js → cli-BafqEuaj.js} +6 -6
  30. package/dist/{client-k0MT6NBw.js → client-CTrfpKT3.js} +7 -2
  31. package/dist/{client-DCxeV1bw.js → client-yVTJ5jx5.js} +6 -1
  32. package/dist/{command-registry-CXcvXjUR.js → command-registry-CLm8TAH3.js} +11 -11
  33. package/dist/{commands-registry-Ca5hh7nh.js → commands-registry-CwXsDVuO.js} +1 -1
  34. package/dist/{completion-cli-DJ1YCeSg.js → completion-cli-Cn_81QBb.js} +12 -12
  35. package/dist/{completion-cli-B1Fg6Lmg.js → completion-cli-DOBXkVwG.js} +2 -2
  36. package/dist/{config-B4jkreCN.js → config-BngIfn5l.js} +2 -2
  37. package/dist/{config-cli-D5DlWt6T.js → config-cli-B1cPkJ4p.js} +4 -4
  38. package/dist/{config-cli-CQ1FAvY_.js → config-cli-BgHYqFH1.js} +1 -1
  39. package/dist/{config-guard-BRm3RiOi.js → config-guard-DStz4_V2.js} +6 -6
  40. package/dist/{config-validation-Cdyg1BZB.js → config-validation-Dxj9LRzr.js} +1 -1
  41. package/dist/{configure-bhJB2Dti.js → configure-C7zmSgvC.js} +14 -14
  42. package/dist/{configure-DG1lf0Ld.js → configure-DmzM0S7L.js} +6 -6
  43. package/dist/{consolidate-DymnvvYm.js → consolidate-CO32_TEx.js} +6 -6
  44. package/dist/{control-service-D8kKOts5.js → control-service-CUreKVeY.js} +4 -4
  45. package/dist/control-ui/css/style.css +478 -80
  46. package/dist/control-ui/index.html +54 -127
  47. package/dist/control-ui/js/render.js +11 -227
  48. package/dist/control-ui/js/scheduling.js +85 -224
  49. package/dist/control-ui/js/subagents.js +78 -394
  50. package/dist/control-ui/js/symframe-awaiting.js +301 -0
  51. package/dist/control-ui/js/symframe-pin-store.js +104 -0
  52. package/dist/control-ui/js/symframe-substrate.js +395 -0
  53. package/dist/control-ui/js/symframe.js +244 -6
  54. package/dist/{control-ui-assets-CJQ97d4u.js → control-ui-assets-B8B9z_Ll.js} +1 -1
  55. package/dist/{cost-cli-DWiVCOCx.js → cost-cli-D-ssjcRF.js} +3 -3
  56. package/dist/{cron-cli-8RaBr1CM.js → cron-cli-BNBs3zue.js} +3 -3
  57. package/dist/{cron-cli-fW3wtftG.js → cron-cli-otPeKxmi.js} +7 -7
  58. package/dist/{daemon-cli-Y6clFgva.js → daemon-cli-DDqeG2nd.js} +2 -2
  59. package/dist/{daemon-cli-0EiZTQ2A.js → daemon-cli-qDdMg615.js} +11 -11
  60. package/dist/daemon-cli.js +6 -1
  61. package/dist/{daemon-runtime-DlQla_dA.js → daemon-runtime-CKn0wmCk.js} +10 -10
  62. package/dist/{deliver-B04yNX82.js → deliver-BiWlR84Y.js} +4 -4
  63. package/dist/{deliver-lTZLIQqf.js → deliver-CWMFmMCv.js} +2 -2
  64. package/dist/{deliver-q23ar_Pm.js → deliver-f3cIWxXT.js} +4 -4
  65. package/dist/{deps-Bf9dt2UO.js → deps-CdibsPMx.js} +1 -1
  66. package/dist/{devices-cli-C2gQTsB0.js → devices-cli-BJ3rVWOw.js} +2 -2
  67. package/dist/{devices-cli-DfiSkZ7k.js → devices-cli-DDPwF2Nx.js} +6 -6
  68. package/dist/{diagnostics-DlZODdRf.js → diagnostics-CYkqD5lP.js} +5 -5
  69. package/dist/{directory-cli-Bm5QYEo-.js → directory-cli-giqTe8Yg.js} +3 -3
  70. package/dist/{dm-policy-shared-CeFt0nch.js → dm-policy-shared-B61_yf6G.js} +1 -1
  71. package/dist/{dns-cli-CubLq4j9.js → dns-cli-Dssz4RqF.js} +3 -3
  72. package/dist/{docs-cli-PS8m1er7.js → docs-cli-Ct1STieY.js} +1 -1
  73. package/dist/{doctor-completion-CfF0J8fs.js → doctor-completion-CL7MyXlo.js} +2 -2
  74. package/dist/{doctor-completion-ScxFfN93.js → doctor-completion-k0HiL05o.js} +1 -1
  75. package/dist/{doctor-config-flow-C52W1uUK.js → doctor-config-flow-ljVnQJjo.js} +9 -9
  76. package/dist/entry.js +1 -1
  77. package/dist/{exec-approvals-cli-Cl-vWA1q.js → exec-approvals-cli-Cau1vPQI.js} +4 -4
  78. package/dist/{exec-approvals-cli-BaKWIf56.js → exec-approvals-cli-DsBoQu5H.js} +13 -13
  79. package/dist/extensionAPI.js +4 -4
  80. package/dist/{file-lock-BVUYnlQv.js → file-lock-2AecMjCa.js} +8 -8
  81. package/dist/{fs-safe-BdejYjW8.js → fs-safe-B0Is-oLk.js} +6 -6
  82. package/dist/{gateway-cli-kq5EWlnF.js → gateway-cli-DG_2YZ8B.js} +98 -98
  83. package/dist/{gateway-cli-CK-5nguV.js → gateway-cli-DgmGygc6.js} +16 -16
  84. package/dist/{gateway-rpc-Bzg_TTKP.js → gateway-rpc-Kv0-8W2E.js} +1 -1
  85. package/dist/{gateway-rpc-D12UaJS5.js → gateway-rpc-gaoD882s.js} +1 -1
  86. package/dist/{glass-ui-ws-B6p0iPsO.js → glass-ui-ws-Bof7krDJ.js} +67 -67
  87. package/dist/{glass-ui-ws-CVr0_1gT.js → glass-ui-ws-Dl45d7eU.js} +13 -13
  88. package/dist/{health-CPU9rQGj.js → health-CMbUI4aN.js} +4 -4
  89. package/dist/{health-CJb2CYtg.js → health-znS85U-F.js} +1 -1
  90. package/dist/{hooks-cli-DbgVZaP4.js → hooks-cli-Cb9BzCOY.js} +7 -7
  91. package/dist/{hooks-cli-13HCu5Xs.js → hooks-cli-Cgjor7F-.js} +59 -59
  92. package/dist/{image-ops-L70xVnpG.js → image-ops-BzCBIakN.js} +10 -10
  93. package/dist/index.js +52 -52
  94. package/dist/{inspect-CGKsaVZ4.js → inspect-DzYUb_Dl.js} +4 -4
  95. package/dist/{install-safe-path-B2JrFspY.js → install-safe-path-BrpA09f2.js} +11 -11
  96. package/dist/{installs-D890uIIW.js → installs-bnDlOSq2.js} +10 -10
  97. package/dist/{internal-DVCddhhN.js → internal-csqU78gW.js} +9 -9
  98. package/dist/{lifecycle-core-wFwnK_mD.js → lifecycle-core-cSR_xiIO.js} +5 -5
  99. package/dist/llm-slug-generator.js +4 -4
  100. package/dist/{local-roots-CgDCgCuM.js → local-roots-2Jb79HZ8.js} +1 -1
  101. package/dist/{logs-cli-R16VTptK.js → logs-cli-Kr145PO_.js} +7 -7
  102. package/dist/{logs-cli-CQeK5fn7.js → logs-cli-LiAjkog2.js} +3 -3
  103. package/dist/{manager-CxFs8Z_F.js → manager-CceVgXHV.js} +1 -1
  104. package/dist/{manager-B2SWSuad.js → manager-Cv4xI8sP.js} +1 -1
  105. package/dist/{manager-CHLdCC6u.js → manager-DG6PODgu.js} +15 -15
  106. package/dist/{manager-BhEbaYDa.js → manager-V4UCf0Av.js} +1 -1
  107. package/dist/{memory-DFpqcIst.js → memory-A2D5e8dL.js} +2 -2
  108. package/dist/{memory-DavRjdTi.js → memory-BFnx3v3_.js} +5 -5
  109. package/dist/{memory-cli-DZnq3S6s.js → memory-cli-1zjVJITN.js} +2 -2
  110. package/dist/{memory-cli-B-Cp1Sb1.js → memory-cli-CHNghdrm.js} +12 -12
  111. package/dist/{model-MUMSB_7d.js → model-Cwbcw-km.js} +1 -1
  112. package/dist/{model-auth-1EAQvYRv.js → model-auth-_C07_3Yr.js} +2 -2
  113. package/dist/{model-catalog-IWi6-nY9.js → model-catalog-BWurV7gl.js} +3 -3
  114. package/dist/{model-picker-Cf6UgQEh.js → model-picker-Dpkr5xBW.js} +5 -5
  115. package/dist/{model-selection-7wdmO-Iw.js → model-selection-CCTzD29o.js} +1 -1
  116. package/dist/{models-Cht7Mzvs.js → models-BYev6YAG.js} +3 -3
  117. package/dist/{models-cli-B_motPDX.js → models-cli-BbK8HMKa.js} +55 -55
  118. package/dist/{models-cli-DXswzgUR.js → models-cli-Fa5r1QYP.js} +9 -9
  119. package/dist/{models-config-B5Xxy-c-.js → models-config-DlXge3Sd.js} +8 -8
  120. package/dist/{node-cli-D-gsjRXY.js → node-cli-BPnBosC4.js} +27 -27
  121. package/dist/{node-cli-VmKhIXuP.js → node-cli-Cv7x1gGu.js} +1 -1
  122. package/dist/{node-service-BH08wY5j.js → node-service-Cc18m-uk.js} +1 -1
  123. package/dist/{nodes-cli-BMvxQGCp.js → nodes-cli-CN_m6PO5.js} +10 -10
  124. package/dist/{nodes-cli-D199d74o.js → nodes-cli-DaHOBbd4.js} +3 -3
  125. package/dist/{nodes-screen-De9ma6e1.js → nodes-screen-Cp5QP3ET.js} +4 -4
  126. package/dist/{npm-registry-spec-DTqn-NXZ.js → npm-registry-spec-C-muP97-.js} +9 -9
  127. package/dist/{onboard-DFJcbABp.js → onboard-B2IcTMv-.js} +15 -15
  128. package/dist/{onboard-CdRA8BRG.js → onboard-D-m6WTZl.js} +3 -3
  129. package/dist/{onboard-channels-fadyQGBK.js → onboard-channels-Z-Jkrk5-.js} +1 -1
  130. package/dist/{onboard-channels-Ca7ZFQ2Y.js → onboard-channels-wfGO5Zlh.js} +4 -4
  131. package/dist/{onboard-custom-BcRYreNG.js → onboard-custom-DnDrvxSg.js} +3 -3
  132. package/dist/{onboard-helpers-CQBpac8h.js → onboard-helpers-BKejzolA.js} +8 -8
  133. package/dist/{onboard-helpers-BcLPSb5N.js → onboard-helpers-Dhr98nj8.js} +1 -1
  134. package/dist/{onboard-hooks-2SCajRKc.js → onboard-hooks-D9jHwImb.js} +1 -1
  135. package/dist/{onboard-remote-Bo3tpC9N.js → onboard-remote-DZdMxd1Q.js} +1 -1
  136. package/dist/{onboard-remote-BWK5Ths4.js → onboard-remote-y3ZmP90U.js} +1 -1
  137. package/dist/{onboard-skills-BLl8HPJO.js → onboard-skills-2SUv-W7i.js} +1 -1
  138. package/dist/{onboard-skills-DvacccqZ.js → onboard-skills-BFhHfrt9.js} +3 -3
  139. package/dist/{onboarding-ojb2rFkA.js → onboarding-BckHLQMV.js} +7 -7
  140. package/dist/{onboarding-BywueA1d.js → onboarding-DqlPV372.js} +12 -12
  141. package/dist/{onboarding.finalize-DdxBQpUU.js → onboarding.finalize-Bwjv3jew.js} +31 -31
  142. package/dist/{onboarding.finalize-DHvlZi9G.js → onboarding.finalize-CbH_ShIW.js} +9 -9
  143. package/dist/{onboarding.gateway-config-DPBNWNV6.js → onboarding.gateway-config-CiRo9EMt.js} +8 -8
  144. package/dist/{onboarding.gateway-config-ZK9517uR.js → onboarding.gateway-config-sNSeEykB.js} +3 -3
  145. package/dist/{openai-model-default-BkuuK-Di.js → openai-model-default-De-UAjwg.js} +2 -2
  146. package/dist/{pairing-cli-Rsae0KnN.js → pairing-cli-CBMMCNnx.js} +5 -5
  147. package/dist/{pairing-store-BNhJOnWn.js → pairing-store-Be-ZQK87.js} +1 -1
  148. package/dist/{pairing-token-Dcy37-4s.js → pairing-token-B703A1U3.js} +7 -7
  149. package/dist/{paths-DObzwe08.js → paths-BWqg8NZT.js} +1 -1
  150. package/dist/{pi-auth-json-Db8XJVGL.js → pi-auth-json-D-vdh-nY.js} +6 -6
  151. package/dist/{pi-embedded-DJE9TMwq.js → pi-embedded-B9rtlNMc.js} +32 -16
  152. package/dist/{pi-embedded-helpers-D-OFjhdI.js → pi-embedded-helpers-j1JrlsI0.js} +6 -6
  153. package/dist/{pi-tools.policy-H2t-Xkfc.js → pi-tools.policy-CvAqjEH9.js} +3 -3
  154. package/dist/{plugin-auto-enable-DJBhDIMq.js → plugin-auto-enable-BXSJTxI7.js} +1 -1
  155. package/dist/{plugin-registry-tG7NXc3Y.js → plugin-registry-B43UosQh.js} +3 -3
  156. package/dist/{plugin-registry-Tlmjr-LX.js → plugin-registry-CS4WgHbu.js} +1 -1
  157. package/dist/plugin-sdk/gateway/protocol/schema/logs-chat.d.ts +1 -1
  158. package/dist/plugin-sdk/infra/symframe-broadcast.d.ts +18 -6
  159. package/dist/{plugins-cli-CRKD8aho.js → plugins-cli-BV2wbjfI.js} +54 -54
  160. package/dist/{plugins-cli-Cm0G_-Y5.js → plugins-cli-BY42hyHP.js} +7 -7
  161. package/dist/{ports-r7LBic2V.js → ports-Bi3V_3n9.js} +1 -1
  162. package/dist/{ports-gxLM5ahL.js → ports-CB_Iu83U.js} +2 -2
  163. package/dist/{program-DEmAlwmD.js → program-P9F1DxBa.js} +12 -12
  164. package/dist/{program-context-DRCRbDpu.js → program-context-BmXxHUKe.js} +40 -40
  165. package/dist/{prompt-select-styled-pomsR-zf.js → prompt-select-styled-B2ah467m.js} +7 -7
  166. package/dist/{prompt-select-styled-B41Tx9aC.js → prompt-select-styled-BlQZX6pK.js} +38 -38
  167. package/dist/{provider-auth-helpers-rKWs_r7a.js → provider-auth-helpers-Bgb_Bfp9.js} +1 -1
  168. package/dist/{provider-auth-helpers-CdQwOam7.js → provider-auth-helpers-WLwb6tL4.js} +6 -6
  169. package/dist/{push-apns-eCM0qmrY.js → push-apns-CBGvXev_.js} +4 -4
  170. package/dist/{push-apns-CZPUHftn.js → push-apns-DnSCjFu7.js} +1 -1
  171. package/dist/{pw-ai-BiBvIJzd.js → pw-ai-CP5pn3eU.js} +7 -7
  172. package/dist/{pw-ai-v__CyAlM.js → pw-ai-DOAsQ5NX.js} +1 -1
  173. package/dist/{pw-ai-DLsdzdgc.js → pw-ai-DY_6l11g.js} +1 -1
  174. package/dist/{qmd-manager-C8-M4Pru.js → qmd-manager-Dxyue7B1.js} +19 -19
  175. package/dist/{qr-cli-1sCVaPcF.js → qr-cli-DHw6muwK.js} +3 -3
  176. package/dist/{register.agent-BQPvYYdn.js → register.agent-BuEcmVg0.js} +12 -12
  177. package/dist/{register.agent-N1hoqMFR.js → register.agent-CXdTiqyP.js} +67 -67
  178. package/dist/{register.configure-BHHZ44xB.js → register.configure-DVcn-gCO.js} +70 -70
  179. package/dist/{register.configure-BAc3P4Z-.js → register.configure-YDKJ-KQg.js} +14 -14
  180. package/dist/{register.maintenance-lX0a3Hzl.js → register.maintenance-BiGvpEj-.js} +13 -13
  181. package/dist/{register.maintenance-DDgy5Iyy.js → register.maintenance-cpspl8D6.js} +67 -67
  182. package/dist/{register.message-Br-IH_0z.js → register.message-BIuLbESM.js} +7 -7
  183. package/dist/{register.message-B4lDhHpE.js → register.message-BjcYy5UG.js} +47 -47
  184. package/dist/{register.onboard-B-GoYJIc.js → register.onboard-C4vIASed.js} +6 -6
  185. package/dist/{register.onboard-Bv0s2_KV.js → register.onboard-D4RN92s2.js} +25 -25
  186. package/dist/{register.setup-DQ6KLkAI.js → register.setup-BvoXF0xl.js} +28 -28
  187. package/dist/{register.setup-4lNdC98i.js → register.setup-D-Jt2e1d.js} +6 -6
  188. package/dist/{register.status-health-sessions-Cg7bK5K2.js → register.status-health-sessions-BY9hMD1s.js} +8 -8
  189. package/dist/{register.status-health-sessions-ByGn71_M.js → register.status-health-sessions-DjDvCXBn.js} +41 -41
  190. package/dist/{register.subclis-FMlcLBX0.js → register.subclis-Cibmeapc.js} +20 -20
  191. package/dist/{replies-CbXXjn9X.js → replies-B_3j7R_Q.js} +1 -1
  192. package/dist/{reply-prefix-BFNeXT65.js → reply-prefix-CtZtkTJK.js} +1 -1
  193. package/dist/{resolve-route-C1IIA6kH.js → resolve-route-Du0VftVs.js} +1 -1
  194. package/dist/{routes-ivqbutvM.js → routes-BwTUoI5h.js} +10 -10
  195. package/dist/{rpc-Dk1Az_d8.js → rpc-BnAKPQDB.js} +1 -1
  196. package/dist/{rpc-JAmDaTYt.js → rpc-CwxSZZOx.js} +1 -1
  197. package/dist/{run-main-DSyeVDsT.js → run-main-BhEQjKtM.js} +20 -20
  198. package/dist/{sandbox-BkznAPKO.js → sandbox-CZGTCone.js} +18 -18
  199. package/dist/{sandbox-cli-Bb9cBtBH.js → sandbox-cli-DEtGT_4y.js} +13 -13
  200. package/dist/{security-cli-DmgGLP83.js → security-cli-CS-ZT1LE.js} +3 -3
  201. package/dist/{security-cli-D47LQbpf.js → security-cli-DJd7Fcdy.js} +29 -29
  202. package/dist/{send-B0jHSNMF.js → send-CxjvucMO.js} +7 -7
  203. package/dist/{server-context-ChcbJgNo.js → server-context-DXdk410X.js} +5 -5
  204. package/dist/{server-methods-DGBBt49x.js → server-methods-CWxr5b-w.js} +19 -13
  205. package/dist/{server-methods-BkHB2MOW.js → server-methods-DfVfzYqq.js} +68 -62
  206. package/dist/{server-node-events-C186LRm0.js → server-node-events-B0yC6hi1.js} +48 -48
  207. package/dist/{server-node-events-D-Akk3uq.js → server-node-events-ClDEcUTJ.js} +8 -8
  208. package/dist/{service-e6MzlLCd.js → service-CRZoXO_n.js} +15 -15
  209. package/dist/{session-dirs-C9E2G0yZ.js → session-dirs-a00Ad2SO.js} +2 -2
  210. package/dist/{session-utils-Cs1jlD-q.js → session-utils-CJhcRx3E.js} +14 -14
  211. package/dist/{sessions-Dxf5Kjig.js → sessions-BCc3THTm.js} +10 -10
  212. package/dist/{shared-1xPo9ygd.js → shared-C39SiDDJ.js} +1 -1
  213. package/dist/{shared-COtpr3Ad.js → shared-Dh-O8nRd.js} +3 -3
  214. package/dist/{skill-commands-DDGGlq68.js → skill-commands-DWvXs3lz.js} +4 -4
  215. package/dist/{skill-scanner-BCgVcIwi.js → skill-scanner-CIlHPszT.js} +5 -5
  216. package/dist/{skills-BwDmcZdt.js → skills-CYcBtLGH.js} +4 -4
  217. package/dist/{skills-cli-B-7TY-vS.js → skills-cli-CD9s3cgm.js} +7 -7
  218. package/dist/{skills-install-Dwzsjoc8.js → skills-install-BTa9IuQ6.js} +3 -3
  219. package/dist/{skills-remote-bz71Bstn.js → skills-remote-BcRQTDsZ.js} +3 -3
  220. package/dist/{skills-status-BKX1PjCc.js → skills-status-DLnCHUZ2.js} +1 -1
  221. package/dist/{sqlite-Cod7C5ba.js → sqlite-BpogPlQW.js} +5 -5
  222. package/dist/{status-CFgCSaDq.js → status-BWxLtb3D.js} +23 -23
  223. package/dist/{status-poPDyC8O.js → status-Doq8T1zj.js} +3 -3
  224. package/dist/{status-Bahhq7OQ.js → status-K1k4g3Ai.js} +1 -1
  225. package/dist/{status-D9LC5P_Y.js → status-ojZB_Lrf.js} +5 -5
  226. package/dist/{status.update-DGJi0OLl.js → status.update-CKfyV6zw.js} +3 -3
  227. package/dist/{subagent-registry-V2o45tIn.js → subagent-registry-BOt7g9hn.js} +21 -10
  228. package/dist/{symframe-cli-bxdpivve.js → symframe-cli-CrUtJw_7.js} +31 -7
  229. package/dist/{symframe-cli-ppdMo15M.js → symframe-cli-D1CtN3pf.js} +37 -13
  230. package/dist/{symi-root-BQ0IpoW2.js → symi-root-DeCVdZB4.js} +2 -2
  231. package/dist/{synthesis-B2EyHFXy.js → synthesis-BIQLrbys.js} +6 -6
  232. package/dist/{synthesis-BlJyO1E_.js → synthesis-Bc2QkGvt.js} +4 -4
  233. package/dist/{synthesis-CPSq83PP.js → synthesis-VZNnlUTf.js} +45 -45
  234. package/dist/{synthesis-C2WbvLOI.js → synthesis-yl24Ovw4.js} +4 -4
  235. package/dist/{system-cli-nPyjUPBH.js → system-cli-CvN-Wq9U.js} +3 -3
  236. package/dist/{system-cli-BroqLjZ6.js → system-cli-r7WJj0Xh.js} +7 -7
  237. package/dist/{systemd-CUIM0n5P.js → systemd-CsoVnIbM.js} +5 -5
  238. package/dist/{systemd-hints-CsrzMCTD.js → systemd-hints-QISwLlFU.js} +6 -6
  239. package/dist/{systemd-linger-BzYk7A6M.js → systemd-linger-BnhuRdbt.js} +1 -1
  240. package/dist/{tui-Bp9k5skv.js → tui-BxgdImL_.js} +2 -2
  241. package/dist/{tui-DzROrE20.js → tui-J7Jxp-FF.js} +7 -7
  242. package/dist/{tui-cli-BHBF8O-3.js → tui-cli-DR48dU_C.js} +19 -19
  243. package/dist/{tui-cli-Dv4hBFdc.js → tui-cli-DqvgN5ng.js} +3 -3
  244. package/dist/{unified-runner-CIQIkbvi.js → unified-runner-BV5TdNFv.js} +32 -16
  245. package/dist/{unified-runner-CduaBH_0.js → unified-runner-DXjH-prv.js} +117 -106
  246. package/dist/{update-yYduAjKd.js → update-Cb0Fmxic.js} +3 -3
  247. package/dist/{update-check-BCL_K7kx.js → update-check-u6Jgr1cz.js} +5 -5
  248. package/dist/{update-cli-WcLxjBiY.js → update-cli-CKpjWtlv.js} +77 -77
  249. package/dist/{update-cli-BKnHBe8a.js → update-cli-Dn6QQZLd.js} +14 -14
  250. package/dist/{update-runner-BLV8SI96.js → update-runner-G2YgEATs.js} +15 -15
  251. package/dist/{webhooks-cli-D5k-Y2A8.js → webhooks-cli-DjUITimx.js} +4 -4
  252. package/dist/{with-timeout-DPR4A2dx.js → with-timeout-CLrF-Yr_.js} +1 -1
  253. package/dist/{workspace-dirs-jKFQf7of.js → workspace-dirs-DCICLTHx.js} +1 -1
  254. package/dist/{wsl-CglTdtlb.js → wsl-DTi7eX-V.js} +2 -2
  255. package/extensions/memory-core/package.json +1 -1
  256. package/extensions/msteams/CHANGELOG.md +12 -0
  257. package/extensions/msteams/package.json +1 -1
  258. package/extensions/open-prose/package.json +1 -1
  259. package/extensions/outlook/package.json +1 -1
  260. package/extensions/slack/package.json +1 -1
  261. package/package.json +1 -1
@@ -0,0 +1,395 @@
1
+ // ── Symframe Substrate ─────────────────────────────────────────────────
2
+ // Stage B of the Dynamic Glass Panel arc — see ~/Documents/dynamic-glass-panel.md.
3
+ //
4
+ // The substrate is the ambient reasoning layer that lives BEHIND the
5
+ // foreground cards in the symframe. It's the single move that converts
6
+ // the panel from "card list with a tagline" into a felt "window into
7
+ // the agent's mind" — there is always something alive in the negative
8
+ // space, even when no specific card is being pushed.
9
+ //
10
+ // What this module owns:
11
+ // - The substrate container (#symframe-substrate)
12
+ // - The live trace (the in-flight thinking entry, pinned at top with a
13
+ // pulsing dot — full opacity, no blur)
14
+ // - Recent reasoning entries (every block routed through the old
15
+ // reasoning-feed window globals — `appendToReasoningPanel`,
16
+ // `injectReasoningRunSeparator`, `openLiveThinking`,
17
+ // `updateLiveThinking`, `closeLiveThinking`, `clearReasoningPanel`)
18
+ // - Per-entry decay tick: opacity / blur / scale / height collapse as
19
+ // a function of (now - entry.createdAt). See DECAY_TIERS below.
20
+ // - Quiet-mind empty state when the substrate has no entries
21
+ //
22
+ // Backward-compatible surface:
23
+ // This module DEFINES the same six window globals that render.js used
24
+ // to expose for the reasoning panel. Script load order in index.html
25
+ // loads render.js first then this file, so our definitions override.
26
+ // app.js (~12 call sites) is unchanged.
27
+ //
28
+ // Layout:
29
+ // The substrate is one of two children of .symframe-stack (the other
30
+ // is .symframe-cards). Both share a single CSS grid cell via
31
+ // grid-area: overlay, with the substrate at z-index 0 and cards at
32
+ // z-index 1. Cards have backdrop-filter so the substrate is visible
33
+ // THROUGH them — the agent's mind breathes behind whatever artifacts
34
+ // are foregrounded.
35
+
36
+ "use strict";
37
+
38
+ (function () {
39
+ const substrate = document.getElementById("symframe-substrate");
40
+ if (!substrate) {
41
+ // Substrate not in DOM — nothing to do. The 6 window globals stay
42
+ // bound to render.js's no-op-on-missing-DOM implementations.
43
+ return;
44
+ }
45
+
46
+ // ── Decay tiers ─────────────────────────────────────────────────────
47
+ // Each entry carries dataset.createdAt; the tick reads its age and
48
+ // looks up the matching tier. Tiers are evaluated in order; first
49
+ // match (age < maxAge) wins. Constants tuned per the plan §5.2; expect
50
+ // to revisit live.
51
+ const DECAY_TIERS = [
52
+ { maxAge: 10_000, opacity: 1.0, blur: 0, scale: 1.0, texture: false },
53
+ { maxAge: 30_000, opacity: 0.85, blur: 1, scale: 1.0, texture: false },
54
+ { maxAge: 120_000, opacity: 0.55, blur: 2, scale: 1.0, texture: false },
55
+ { maxAge: 600_000, opacity: 0.25, blur: 4, scale: 0.97, texture: false },
56
+ { maxAge: Infinity, opacity: 0.08, blur: 6, scale: 0.94, texture: true },
57
+ ];
58
+
59
+ const DECAY_TICK_MS = 1000;
60
+
61
+ // ── Live trace state ────────────────────────────────────────────────
62
+ // The "live" entry is the in-flight thinking stream. It's pinned at
63
+ // the top of the substrate, exempt from decay, and has a pulsing dot.
64
+ // When closeLiveThinking fires, the live class is dropped and the
65
+ // entry starts decaying like any other.
66
+ let liveEntry = null;
67
+ let liveBody = null;
68
+ let liveBuffer = "";
69
+
70
+ // Decay tick handle. Pauses when page is hidden (Page Visibility API)
71
+ // so a backgrounded tab doesn't burn CPU on substrate-only animation.
72
+ let decayHandle = null;
73
+
74
+ // ── DOM helpers ─────────────────────────────────────────────────────
75
+ function escHtml(s) {
76
+ return String(s ?? "")
77
+ .replace(/&/g, "&amp;")
78
+ .replace(/</g, "&lt;")
79
+ .replace(/>/g, "&gt;")
80
+ .replace(/"/g, "&quot;")
81
+ .replace(/'/g, "&#39;");
82
+ }
83
+
84
+ function ensureEmptyRemoved() {
85
+ const empty = substrate.querySelector(".substrate-empty");
86
+ if (empty) {
87
+ empty.remove();
88
+ }
89
+ }
90
+
91
+ function renderQuietMind() {
92
+ if (substrate.querySelector(".substrate-empty")) {
93
+ return;
94
+ }
95
+ const empty = document.createElement("div");
96
+ empty.className = "substrate-empty";
97
+ empty.innerHTML = `
98
+ <span class="substrate-quiet-dot" aria-hidden="true"></span>
99
+ <span class="substrate-quiet-label">quiet mind</span>
100
+ `;
101
+ substrate.appendChild(empty);
102
+ }
103
+
104
+ function insertAtTopRespectingLive(entry) {
105
+ // Live entry stays at index 0; everything else prepends after it.
106
+ if (liveEntry && substrate.firstChild === liveEntry) {
107
+ liveEntry.after(entry);
108
+ } else {
109
+ substrate.prepend(entry);
110
+ }
111
+ }
112
+
113
+ // ── Decay ────────────────────────────────────────────────────────────
114
+ function applyDecay(el, age) {
115
+ let tier = DECAY_TIERS[DECAY_TIERS.length - 1];
116
+ for (const t of DECAY_TIERS) {
117
+ if (age < t.maxAge) {
118
+ tier = t;
119
+ break;
120
+ }
121
+ }
122
+ el.style.setProperty("--substrate-opacity", String(tier.opacity));
123
+ el.style.setProperty("--substrate-blur", `${tier.blur}px`);
124
+ el.style.setProperty("--substrate-scale", String(tier.scale));
125
+ el.classList.toggle("substrate-texture", tier.texture);
126
+ }
127
+
128
+ function tickDecay() {
129
+ const now = Date.now();
130
+ const entries = substrate.querySelectorAll(".substrate-entry:not(.substrate-live)");
131
+ for (const e of entries) {
132
+ const createdAt = Number(e.dataset.createdAt) || now;
133
+ applyDecay(e, now - createdAt);
134
+ }
135
+ }
136
+
137
+ function startDecayTick() {
138
+ if (decayHandle) {
139
+ return;
140
+ }
141
+ decayHandle = setInterval(tickDecay, DECAY_TICK_MS);
142
+ }
143
+
144
+ function stopDecayTick() {
145
+ if (decayHandle) {
146
+ clearInterval(decayHandle);
147
+ decayHandle = null;
148
+ }
149
+ }
150
+
151
+ document.addEventListener("visibilitychange", () => {
152
+ if (document.hidden) {
153
+ stopDecayTick();
154
+ } else if (substrate.querySelector(".substrate-entry:not(.substrate-live)")) {
155
+ startDecayTick();
156
+ tickDecay(); // immediate catch-up after a long pause
157
+ }
158
+ });
159
+
160
+ // ── Entry builders ──────────────────────────────────────────────────
161
+ // Returns an HTMLElement or null (null = skip, e.g. empty block).
162
+ // Class names mirror the existing reasoning-* set so the badge/body
163
+ // styles from style.css continue to apply unchanged.
164
+ function buildEntryForBlock(block) {
165
+ const entry = document.createElement("div");
166
+ entry.className = "substrate-entry reasoning-entry";
167
+ entry.dataset.createdAt = String(Date.now());
168
+
169
+ switch (block.type) {
170
+ case "text": {
171
+ const text = (block.text ?? "").trim();
172
+ if (!text) {
173
+ return null;
174
+ }
175
+ entry.innerHTML = `
176
+ <div class="reasoning-entry-header">
177
+ <span class="reasoning-entry-badge badge-narration">✦ NOTE</span>
178
+ <span class="reasoning-entry-name">${escHtml(text.split("\n")[0].slice(0, 60))}${text.length > 60 ? "…" : ""}</span>
179
+ </div>
180
+ `;
181
+ return entry;
182
+ }
183
+ case "thinking": {
184
+ const text = (block.thinking ?? "").trim();
185
+ if (!text) {
186
+ return null;
187
+ }
188
+ entry.innerHTML = `
189
+ <div class="reasoning-entry-header">
190
+ <span class="reasoning-entry-badge badge-think">◈ THINK</span>
191
+ <span class="reasoning-entry-name">${escHtml(text.split("\n")[0].slice(0, 60))}${text.length > 60 ? "…" : ""}</span>
192
+ </div>
193
+ <div class="reasoning-think-body">${escHtml(text)}</div>
194
+ `;
195
+ return entry;
196
+ }
197
+ case "tool_use":
198
+ case "toolCall": {
199
+ const name = block.name ?? "tool";
200
+ const inputData = block.input ?? block.arguments ?? {};
201
+ const inputJson = inputData ? JSON.stringify(inputData, null, 2) : "{}";
202
+ let preview = "";
203
+ try {
204
+ const obj = typeof inputData === "string" ? JSON.parse(inputData) : inputData;
205
+ const keys = Object.keys(obj ?? {});
206
+ if (keys.length) {
207
+ const val = String(obj[keys[0]]).slice(0, 50);
208
+ preview = `${keys[0]}: ${val}${val.length >= 50 ? "…" : ""}`;
209
+ }
210
+ } catch {
211
+ /* ignore */
212
+ }
213
+ entry.innerHTML = `
214
+ <div class="reasoning-entry-header">
215
+ <span class="reasoning-entry-badge badge-tool">⚙ TOOL</span>
216
+ <span class="reasoning-entry-name">${escHtml(name)}</span>
217
+ </div>
218
+ ${preview ? `<div class="reasoning-tool-preview">${escHtml(preview)}</div>` : ""}
219
+ <div class="reasoning-tool-detail">${escHtml(inputJson)}</div>
220
+ `;
221
+ entry.style.cursor = "pointer";
222
+ entry.addEventListener("click", () => entry.classList.toggle("expanded"));
223
+ return entry;
224
+ }
225
+ case "tool_result": {
226
+ const content = Array.isArray(block.content)
227
+ ? block.content.map((b) => b.text ?? "").join("\n")
228
+ : String(block.content ?? "");
229
+ const chars = content.length;
230
+ const isError = block.is_error === true;
231
+ entry.innerHTML = `
232
+ <div class="reasoning-entry-header">
233
+ <span class="reasoning-entry-badge badge-result">${isError ? "⚠ ERROR" : "↩ RESULT"}</span>
234
+ <span class="reasoning-entry-name">${chars} chars</span>
235
+ </div>
236
+ <div class="reasoning-result-meta">${escHtml(content.slice(0, 80))}${chars > 80 ? "…" : ""}</div>
237
+ `;
238
+ return entry;
239
+ }
240
+ default:
241
+ return null;
242
+ }
243
+ }
244
+
245
+ // ── Window globals (preserve render.js signatures) ──────────────────
246
+
247
+ /**
248
+ * Append a finished block to the substrate. Block shapes match what
249
+ * app.js produces from agent events: { type:"text"|"thinking"|
250
+ * "tool_use"|"toolCall"|"tool_result", ... }.
251
+ */
252
+ window.appendToReasoningPanel = function (block) {
253
+ ensureEmptyRemoved();
254
+ const entry = buildEntryForBlock(block);
255
+ if (!entry) {
256
+ return;
257
+ }
258
+ insertAtTopRespectingLive(entry);
259
+ startDecayTick();
260
+ };
261
+
262
+ /**
263
+ * Inject a horizontal-rule + timestamp separator marking a new agent
264
+ * run. Called from app.js on lifecycle:start.
265
+ */
266
+ window.injectReasoningRunSeparator = function () {
267
+ ensureEmptyRemoved();
268
+ const sep = document.createElement("div");
269
+ sep.className = "substrate-entry substrate-run-sep reasoning-run-sep";
270
+ sep.dataset.createdAt = String(Date.now());
271
+ const now = new Date();
272
+ const hhmm = now.toLocaleTimeString("en-US", {
273
+ hour: "2-digit",
274
+ minute: "2-digit",
275
+ hour12: false,
276
+ });
277
+ sep.innerHTML = `<span class="reasoning-run-sep-label">RUN · ${hhmm}</span>`;
278
+ insertAtTopRespectingLive(sep);
279
+ startDecayTick();
280
+ };
281
+
282
+ /**
283
+ * Clear all substrate entries and restore the quiet-mind empty state.
284
+ * Called from app.js on session reset.
285
+ */
286
+ window.clearReasoningPanel = function () {
287
+ substrate.innerHTML = "";
288
+ liveEntry = null;
289
+ liveBody = null;
290
+ liveBuffer = "";
291
+ stopDecayTick();
292
+ renderQuietMind();
293
+ };
294
+
295
+ /**
296
+ * Open the live thinking entry — pinned at top, exempt from decay,
297
+ * with a pulsing dot. Called when streaming starts.
298
+ */
299
+ window.openLiveThinking = function () {
300
+ if (liveEntry) {
301
+ return; // already open
302
+ }
303
+ ensureEmptyRemoved();
304
+ liveBuffer = "";
305
+ const entry = document.createElement("div");
306
+ entry.className = "substrate-entry substrate-live reasoning-entry";
307
+ entry.id = "substrate-live-entry";
308
+ entry.innerHTML = `
309
+ <div class="reasoning-entry-header">
310
+ <span class="substrate-live-dot" aria-hidden="true"></span>
311
+ <span class="reasoning-entry-badge badge-think">◈ THINKING</span>
312
+ <span class="reasoning-entry-name" id="substrate-live-name">…</span>
313
+ </div>
314
+ <div class="reasoning-think-body" id="substrate-live-body"></div>
315
+ `;
316
+ substrate.prepend(entry);
317
+ liveEntry = entry;
318
+ liveBody = entry.querySelector("#substrate-live-body");
319
+ };
320
+
321
+ /**
322
+ * Append text to the live thinking entry's body. Idempotent on open —
323
+ * calls openLiveThinking if no live entry exists yet.
324
+ */
325
+ window.updateLiveThinking = function (text) {
326
+ if (!liveEntry) {
327
+ window.openLiveThinking();
328
+ }
329
+ if (typeof text !== "string" || !text) {
330
+ return;
331
+ }
332
+ liveBuffer += text;
333
+ if (liveBody) {
334
+ liveBody.textContent = liveBuffer;
335
+ }
336
+ // Update name preview to the first line
337
+ const nameEl = liveEntry?.querySelector("#substrate-live-name");
338
+ if (nameEl) {
339
+ const firstLine = liveBuffer.split("\n")[0].slice(0, 60);
340
+ nameEl.textContent = firstLine + (liveBuffer.length > 60 ? "…" : "");
341
+ }
342
+ };
343
+
344
+ /**
345
+ * Close the live thinking entry: drop the live class so it starts
346
+ * decaying like any other entry, and stamp its createdAt to "now" so
347
+ * the decay timer starts from when it finished, not when it opened.
348
+ */
349
+ window.closeLiveThinking = function () {
350
+ if (!liveEntry) {
351
+ return;
352
+ }
353
+ liveEntry.classList.remove("substrate-live");
354
+ liveEntry.removeAttribute("id");
355
+ liveEntry.dataset.createdAt = String(Date.now());
356
+ const nameEl = liveEntry.querySelector("#substrate-live-name");
357
+ if (nameEl) {
358
+ nameEl.removeAttribute("id");
359
+ }
360
+ const bodyEl = liveEntry.querySelector("#substrate-live-body");
361
+ if (bodyEl) {
362
+ bodyEl.removeAttribute("id");
363
+ }
364
+ liveEntry = null;
365
+ liveBody = null;
366
+ liveBuffer = "";
367
+ startDecayTick();
368
+ };
369
+
370
+ // Extract thinking text from a content array — used by streaming code
371
+ // in app.js to extract just the thinking portion from a content
372
+ // array (Anthropic-style multi-block messages). Recursive on
373
+ // content.content to handle wrapper-shape messages.
374
+ window.extractThinkingText = function (content) {
375
+ if (!content) {
376
+ return "";
377
+ }
378
+ if (typeof content === "string") {
379
+ return "";
380
+ }
381
+ if (Array.isArray(content)) {
382
+ return content
383
+ .filter((b) => b?.type === "thinking")
384
+ .map((b) => b.thinking ?? "")
385
+ .join("");
386
+ }
387
+ if (content?.content) {
388
+ return window.extractThinkingText(content.content);
389
+ }
390
+ return "";
391
+ };
392
+
393
+ // ── Initial state ───────────────────────────────────────────────────
394
+ renderQuietMind();
395
+ })();
@@ -358,7 +358,21 @@
358
358
  const titleSpan = document.createElement("span");
359
359
  titleSpan.textContent = card.title || "";
360
360
  header.appendChild(titleSpan);
361
- if (card.dismissable && !card.sticky) {
361
+ // Stage C: pin glyph for pinned cards. Click toggles unpin.
362
+ if (card.pinned) {
363
+ const pinGlyph = document.createElement("button");
364
+ pinGlyph.className = "symframe-card-pin";
365
+ pinGlyph.type = "button";
366
+ pinGlyph.setAttribute("aria-label", "Unpin");
367
+ pinGlyph.title = "Pinned — click to unpin";
368
+ pinGlyph.textContent = "📌";
369
+ pinGlyph.addEventListener("click", (e) => {
370
+ e.preventDefault();
371
+ e.stopPropagation();
372
+ unpin(card.id);
373
+ });
374
+ header.appendChild(pinGlyph);
375
+ } else if (card.dismissable && !card.sticky) {
362
376
  const dismiss = document.createElement("button");
363
377
  dismiss.className = "symframe-card-dismiss";
364
378
  dismiss.type = "button";
@@ -535,6 +549,12 @@
535
549
  * Remove a card from the registry + DOM. Sticky cards refuse removal
536
550
  * unless force=true is passed (defensive — the system panels really
537
551
  * shouldn't disappear via stray API calls).
552
+ *
553
+ * Stage C: pinned cards behave like sticky for the user-side dismiss
554
+ * button (× hidden in the header) but `remove` still drops them when
555
+ * called — the pin survives in localStorage and the card re-appears
556
+ * on the next reload. To actually drop a pinned card permanently,
557
+ * the agent / user must unpin first.
538
558
  */
539
559
  function remove(id, force = false) {
540
560
  const entry = cards.get(id);
@@ -553,17 +573,193 @@
553
573
  return true;
554
574
  }
555
575
 
576
+ // ── Stage C: dwell / release / recall / pin / unpin ────────────────
577
+ // The CRUD vocabulary (add/update/remove) treats the panel as a
578
+ // notification list. These verbs treat it as a mind-window: cards
579
+ // can be foregrounded ("dwell"), softly let go of ("release"),
580
+ // brought back ("recall"), or persisted across sessions ("pin").
581
+
582
+ const RECENTLY_RELEASED_MAX = 10;
583
+ /** @type {Array<{id:string, card:object, releasedAt:number}>} */
584
+ const recentlyReleased = [];
585
+
586
+ /**
587
+ * Pull a card to the top of the stack with a brief cyan border pulse.
588
+ * Implementation: prepend the element (newest-first stack order
589
+ * normally has it there if it was just added, but for older cards
590
+ * this lifts them up), then add a `dwelling` class for a 600ms
591
+ * CSS pulse animation. Sticky cards aren't reordered (they live at
592
+ * the anchored end of the stack by design).
593
+ */
594
+ function dwell(id) {
595
+ const entry = cards.get(id);
596
+ if (!entry) {
597
+ console.warn(`[symframe] dwell: unknown id ${id}`);
598
+ return false;
599
+ }
600
+ if (!entry.element) {
601
+ console.warn(`[symframe] dwell: card ${id} has no element`);
602
+ return false;
603
+ }
604
+ if (!entry.sticky) {
605
+ // Re-prepend to bring to top of ephemeral stack.
606
+ container.prepend(entry.element);
607
+ }
608
+ entry.element.classList.remove("symframe-dwelling");
609
+ // Re-flow so the animation restarts even on repeated dwell calls.
610
+ void entry.element.offsetWidth;
611
+ entry.element.classList.add("symframe-dwelling");
612
+ setTimeout(() => entry.element?.classList.remove("symframe-dwelling"), 700);
613
+ return true;
614
+ }
615
+
616
+ /**
617
+ * Soft-dismiss a card. Animated fade + scale; on animation end the
618
+ * element is removed from the registry and DOM. Unlike `remove`,
619
+ * `release` records the card in a session ring buffer so `recall(id)`
620
+ * can bring it back. Sticky cards refuse release without force=true.
621
+ */
622
+ function release(id, force = false) {
623
+ const entry = cards.get(id);
624
+ if (!entry) {
625
+ return false;
626
+ }
627
+ if (entry.sticky && !force) {
628
+ console.warn(`[symframe] release: refusing sticky card '${id}' without force=true`);
629
+ return false;
630
+ }
631
+ // Snapshot for recall (strip the live DOM element)
632
+ const snapshot = { ...entry };
633
+ delete snapshot.element;
634
+ recentlyReleased.unshift({
635
+ id,
636
+ card: snapshot,
637
+ releasedAt: Date.now(),
638
+ });
639
+ if (recentlyReleased.length > RECENTLY_RELEASED_MAX) {
640
+ recentlyReleased.length = RECENTLY_RELEASED_MAX;
641
+ }
642
+ // Animate then drop
643
+ const el = entry.element;
644
+ if (el) {
645
+ el.classList.add("symframe-releasing");
646
+ const cleanup = () => {
647
+ cards.delete(id);
648
+ if (el.parentElement === container) {
649
+ el.remove();
650
+ }
651
+ updateCount();
652
+ };
653
+ // Fail-safe: drop after the CSS transition window even if the
654
+ // transitionend event doesn't fire (browser bug, reduced motion).
655
+ const handle = setTimeout(cleanup, 900);
656
+ el.addEventListener(
657
+ "transitionend",
658
+ () => {
659
+ clearTimeout(handle);
660
+ cleanup();
661
+ },
662
+ { once: true },
663
+ );
664
+ } else {
665
+ cards.delete(id);
666
+ updateCount();
667
+ }
668
+ return true;
669
+ }
670
+
671
+ /**
672
+ * Re-summon a recently-released card from the session ring buffer.
673
+ * Calling `recall(id)` without an id recalls the most-recent release.
674
+ * If the id isn't in the buffer or the card already exists, no-op.
675
+ */
676
+ function recall(id) {
677
+ const recordIdx = id
678
+ ? recentlyReleased.findIndex((r) => r.id === id)
679
+ : recentlyReleased.length > 0
680
+ ? 0
681
+ : -1;
682
+ if (recordIdx < 0) {
683
+ console.warn(`[symframe] recall: nothing to recall${id ? ` for id ${id}` : ""}`);
684
+ return false;
685
+ }
686
+ const [record] = recentlyReleased.splice(recordIdx, 1);
687
+ if (cards.has(record.id)) {
688
+ // Already restored elsewhere — no-op.
689
+ return false;
690
+ }
691
+ add(record.card);
692
+ return true;
693
+ }
694
+
695
+ /** Snapshot of recently-released cards (most-recent first). */
696
+ function listRecentlyReleased() {
697
+ return recentlyReleased.slice();
698
+ }
699
+
700
+ /**
701
+ * Pin a card to localStorage so it survives reload + /new. Idempotent
702
+ * on id. The card is marked `pinned: true` so the dismiss button is
703
+ * hidden. Calling pin on an unknown id is a no-op.
704
+ */
705
+ function pin(id) {
706
+ const entry = cards.get(id);
707
+ if (!entry) {
708
+ console.warn(`[symframe] pin: unknown id ${id}`);
709
+ return false;
710
+ }
711
+ if (typeof window.symframePinStore?.pin !== "function") {
712
+ console.warn("[symframe] pin: pin-store unavailable");
713
+ return false;
714
+ }
715
+ const snapshot = { ...entry };
716
+ delete snapshot.element;
717
+ snapshot.pinned = true;
718
+ snapshot.dismissable = false;
719
+ window.symframePinStore.pin(snapshot);
720
+ // Update live entry so the chrome reflects the pin (no dismiss btn,
721
+ // pin glyph in header).
722
+ entry.pinned = true;
723
+ entry.dismissable = false;
724
+ if (entry.element) {
725
+ const newEl = renderCardElement(entry);
726
+ entry.element.replaceWith(newEl);
727
+ entry.element = newEl;
728
+ }
729
+ return true;
730
+ }
731
+
732
+ /** Inverse of pin. Removes from localStorage; does NOT drop the card. */
733
+ function unpin(id) {
734
+ const entry = cards.get(id);
735
+ if (typeof window.symframePinStore?.unpin === "function") {
736
+ window.symframePinStore.unpin(id);
737
+ }
738
+ if (entry) {
739
+ entry.pinned = false;
740
+ entry.dismissable = true;
741
+ if (entry.element) {
742
+ const newEl = renderCardElement(entry);
743
+ entry.element.replaceWith(newEl);
744
+ entry.element = newEl;
745
+ }
746
+ }
747
+ return true;
748
+ }
749
+
556
750
  /** Snapshot of all registered cards. */
557
751
  function list() {
558
752
  return Array.from(cards.values());
559
753
  }
560
754
 
561
- // Auto-register the 3 sticky panels that already live in the DOM. The
562
- // existing JS for each panel (subagents.js, scheduling.js, reasoning
563
- // render code) keeps targeting them by id and is unaffected.
755
+ // Auto-register the sticky panels that already live in the DOM. The
756
+ // existing JS for each panel (subagents.js, scheduling.js) keeps
757
+ // targeting them by id and is unaffected.
758
+ // Stage B (3.5.20): reasoning was removed from this list — its DOM
759
+ // block is gone; reasoning content now flows to #symframe-substrate
760
+ // (see glass-ui/js/symframe-substrate.js).
564
761
  const KNOWN_STICKY = [
565
762
  { id: "subagents", elementId: "subagents-panel", title: "SUBAGENTS", type: "panel-subagents" },
566
- { id: "reasoning", elementId: "reasoning-panel", title: "REASONING", type: "panel-reasoning" },
567
763
  {
568
764
  id: "scheduling",
569
765
  elementId: "scheduling-panel",
@@ -584,7 +780,20 @@
584
780
  }
585
781
  }
586
782
 
587
- window.symframe = { add, update, remove, list, register };
783
+ window.symframe = {
784
+ add,
785
+ update,
786
+ remove,
787
+ list,
788
+ register,
789
+ // Stage C — attention verbs
790
+ dwell,
791
+ release,
792
+ recall,
793
+ pin,
794
+ unpin,
795
+ listRecentlyReleased,
796
+ };
588
797
 
589
798
  // Phase 3: server-pushed cards. The gateway's `symframe` broadcast is
590
799
  // re-emitted as a window-level CustomEvent by gateway.js — subscribe
@@ -592,6 +801,8 @@
592
801
  // chat.symframe.push RPC: { action, id?, card?, force? }.
593
802
  // Stage A: `force` flows through to update/remove so the agent (via
594
803
  // display_artifact) and the CLI can override the sticky-card guard.
804
+ // Stage C: new verbs (dwell / release / recall / pin / unpin) route
805
+ // alongside the existing CRUD trio.
595
806
  window.addEventListener("symi:symframe", (e) => {
596
807
  const payload = e.detail;
597
808
  if (!payload || typeof payload !== "object") {
@@ -604,6 +815,33 @@
604
815
  update(payload.id, payload.card, force);
605
816
  } else if (payload.action === "remove" && payload.id) {
606
817
  remove(payload.id, force);
818
+ } else if (payload.action === "dwell" && payload.id) {
819
+ dwell(payload.id);
820
+ } else if (payload.action === "release" && payload.id) {
821
+ release(payload.id, force);
822
+ } else if (payload.action === "recall") {
823
+ recall(payload.id);
824
+ } else if (payload.action === "pin" && payload.id) {
825
+ pin(payload.id);
826
+ } else if (payload.action === "unpin" && payload.id) {
827
+ unpin(payload.id);
607
828
  }
608
829
  });
830
+
831
+ // Stage C: restore pinned cards from localStorage on boot. Pinned
832
+ // cards are user-curated state and survive reload, /new, and gateway
833
+ // reconnect. Each pin is a snapshot; the registry re-adds it as a
834
+ // dynamic card with pinned=true (no dismiss button).
835
+ if (typeof window.symframePinStore?.list === "function") {
836
+ try {
837
+ const pinned = window.symframePinStore.list();
838
+ for (const record of pinned) {
839
+ if (record?.card && !cards.has(record.id)) {
840
+ add({ ...record.card, pinned: true, dismissable: false });
841
+ }
842
+ }
843
+ } catch (err) {
844
+ console.warn("[symframe] failed to restore pinned cards:", err);
845
+ }
846
+ }
609
847
  })();
@@ -1,5 +1,5 @@
1
1
  import { f as defaultRuntime } from "./subsystem-CHbO_DkH.js";
2
- import { n as resolveSymiPackageRootSync, t as resolveSymiPackageRoot } from "./symi-root-BQ0IpoW2.js";
2
+ import { n as resolveSymiPackageRootSync, t as resolveSymiPackageRoot } from "./symi-root-DeCVdZB4.js";
3
3
  import { t as runCommandWithTimeout } from "./exec-DuYbft0z.js";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import path from "node:path";