@symerian/symi 3.5.20 → 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 (257) 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-OTJg3QKn.js} +7 -7
  27. package/dist/{cli-C7v-sID8.js → cli-B-uoiYP2.js} +45 -45
  28. package/dist/{cli-CMNR7ULk.js → cli-BafqEuaj.js} +6 -6
  29. package/dist/{client-k0MT6NBw.js → client-CTrfpKT3.js} +7 -2
  30. package/dist/{client-DCxeV1bw.js → client-yVTJ5jx5.js} +6 -1
  31. package/dist/{command-registry-CXcvXjUR.js → command-registry-CLm8TAH3.js} +11 -11
  32. package/dist/{commands-registry-Ca5hh7nh.js → commands-registry-CwXsDVuO.js} +1 -1
  33. package/dist/{completion-cli-DJ1YCeSg.js → completion-cli-Cn_81QBb.js} +12 -12
  34. package/dist/{completion-cli-B1Fg6Lmg.js → completion-cli-DOBXkVwG.js} +2 -2
  35. package/dist/{config-B4jkreCN.js → config-BngIfn5l.js} +2 -2
  36. package/dist/{config-cli-D5DlWt6T.js → config-cli-B1cPkJ4p.js} +4 -4
  37. package/dist/{config-cli-CQ1FAvY_.js → config-cli-BgHYqFH1.js} +1 -1
  38. package/dist/{config-guard-BRm3RiOi.js → config-guard-DStz4_V2.js} +6 -6
  39. package/dist/{config-validation-Cdyg1BZB.js → config-validation-Dxj9LRzr.js} +1 -1
  40. package/dist/{configure-bhJB2Dti.js → configure-C7zmSgvC.js} +14 -14
  41. package/dist/{configure-DG1lf0Ld.js → configure-DmzM0S7L.js} +6 -6
  42. package/dist/{consolidate-DymnvvYm.js → consolidate-CO32_TEx.js} +6 -6
  43. package/dist/{control-service-D8kKOts5.js → control-service-CUreKVeY.js} +4 -4
  44. package/dist/control-ui/css/style.css +270 -0
  45. package/dist/control-ui/index.html +44 -114
  46. package/dist/control-ui/js/scheduling.js +85 -224
  47. package/dist/control-ui/js/subagents.js +78 -394
  48. package/dist/control-ui/js/symframe-awaiting.js +301 -0
  49. package/dist/control-ui/js/symframe-pin-store.js +104 -0
  50. package/dist/control-ui/js/symframe.js +238 -2
  51. package/dist/{control-ui-assets-CJQ97d4u.js → control-ui-assets-B8B9z_Ll.js} +1 -1
  52. package/dist/{cost-cli-DWiVCOCx.js → cost-cli-D-ssjcRF.js} +3 -3
  53. package/dist/{cron-cli-8RaBr1CM.js → cron-cli-BNBs3zue.js} +3 -3
  54. package/dist/{cron-cli-fW3wtftG.js → cron-cli-otPeKxmi.js} +7 -7
  55. package/dist/{daemon-cli-Y6clFgva.js → daemon-cli-DDqeG2nd.js} +2 -2
  56. package/dist/{daemon-cli-0EiZTQ2A.js → daemon-cli-qDdMg615.js} +11 -11
  57. package/dist/daemon-cli.js +6 -1
  58. package/dist/{daemon-runtime-DlQla_dA.js → daemon-runtime-CKn0wmCk.js} +10 -10
  59. package/dist/{deliver-B04yNX82.js → deliver-BiWlR84Y.js} +4 -4
  60. package/dist/{deliver-lTZLIQqf.js → deliver-CWMFmMCv.js} +2 -2
  61. package/dist/{deps-Bf9dt2UO.js → deps-CdibsPMx.js} +1 -1
  62. package/dist/{devices-cli-C2gQTsB0.js → devices-cli-BJ3rVWOw.js} +2 -2
  63. package/dist/{devices-cli-DfiSkZ7k.js → devices-cli-DDPwF2Nx.js} +6 -6
  64. package/dist/{diagnostics-DlZODdRf.js → diagnostics-CYkqD5lP.js} +5 -5
  65. package/dist/{directory-cli-Bm5QYEo-.js → directory-cli-giqTe8Yg.js} +3 -3
  66. package/dist/{dm-policy-shared-CeFt0nch.js → dm-policy-shared-B61_yf6G.js} +1 -1
  67. package/dist/{dns-cli-CubLq4j9.js → dns-cli-Dssz4RqF.js} +3 -3
  68. package/dist/{docs-cli-PS8m1er7.js → docs-cli-Ct1STieY.js} +1 -1
  69. package/dist/{doctor-completion-CfF0J8fs.js → doctor-completion-CL7MyXlo.js} +2 -2
  70. package/dist/{doctor-completion-ScxFfN93.js → doctor-completion-k0HiL05o.js} +1 -1
  71. package/dist/{doctor-config-flow-C52W1uUK.js → doctor-config-flow-ljVnQJjo.js} +9 -9
  72. package/dist/entry.js +1 -1
  73. package/dist/{exec-approvals-cli-Cl-vWA1q.js → exec-approvals-cli-Cau1vPQI.js} +4 -4
  74. package/dist/{exec-approvals-cli-BaKWIf56.js → exec-approvals-cli-DsBoQu5H.js} +13 -13
  75. package/dist/extensionAPI.js +2 -2
  76. package/dist/{file-lock-BVUYnlQv.js → file-lock-2AecMjCa.js} +8 -8
  77. package/dist/{fs-safe-BdejYjW8.js → fs-safe-B0Is-oLk.js} +6 -6
  78. package/dist/{gateway-cli-kq5EWlnF.js → gateway-cli-DG_2YZ8B.js} +98 -98
  79. package/dist/{gateway-cli-CK-5nguV.js → gateway-cli-DgmGygc6.js} +16 -16
  80. package/dist/{gateway-rpc-Bzg_TTKP.js → gateway-rpc-Kv0-8W2E.js} +1 -1
  81. package/dist/{gateway-rpc-D12UaJS5.js → gateway-rpc-gaoD882s.js} +1 -1
  82. package/dist/{glass-ui-ws-B6p0iPsO.js → glass-ui-ws-Bof7krDJ.js} +67 -67
  83. package/dist/{glass-ui-ws-CVr0_1gT.js → glass-ui-ws-Dl45d7eU.js} +13 -13
  84. package/dist/{health-CPU9rQGj.js → health-CMbUI4aN.js} +4 -4
  85. package/dist/{health-CJb2CYtg.js → health-znS85U-F.js} +1 -1
  86. package/dist/{hooks-cli-DbgVZaP4.js → hooks-cli-Cb9BzCOY.js} +7 -7
  87. package/dist/{hooks-cli-13HCu5Xs.js → hooks-cli-Cgjor7F-.js} +59 -59
  88. package/dist/{image-ops-L70xVnpG.js → image-ops-BzCBIakN.js} +10 -10
  89. package/dist/index.js +52 -52
  90. package/dist/{inspect-CGKsaVZ4.js → inspect-DzYUb_Dl.js} +4 -4
  91. package/dist/{install-safe-path-B2JrFspY.js → install-safe-path-BrpA09f2.js} +11 -11
  92. package/dist/{installs-D890uIIW.js → installs-bnDlOSq2.js} +10 -10
  93. package/dist/{internal-DVCddhhN.js → internal-csqU78gW.js} +9 -9
  94. package/dist/{lifecycle-core-wFwnK_mD.js → lifecycle-core-cSR_xiIO.js} +5 -5
  95. package/dist/llm-slug-generator.js +4 -4
  96. package/dist/{local-roots-CgDCgCuM.js → local-roots-2Jb79HZ8.js} +1 -1
  97. package/dist/{logs-cli-R16VTptK.js → logs-cli-Kr145PO_.js} +7 -7
  98. package/dist/{logs-cli-CQeK5fn7.js → logs-cli-LiAjkog2.js} +3 -3
  99. package/dist/{manager-CxFs8Z_F.js → manager-CceVgXHV.js} +1 -1
  100. package/dist/{manager-B2SWSuad.js → manager-Cv4xI8sP.js} +1 -1
  101. package/dist/{manager-CHLdCC6u.js → manager-DG6PODgu.js} +15 -15
  102. package/dist/{manager-LPPGAsqn.js → manager-V4UCf0Av.js} +1 -1
  103. package/dist/{memory-DFpqcIst.js → memory-A2D5e8dL.js} +2 -2
  104. package/dist/{memory-DavRjdTi.js → memory-BFnx3v3_.js} +5 -5
  105. package/dist/{memory-cli-DZnq3S6s.js → memory-cli-1zjVJITN.js} +2 -2
  106. package/dist/{memory-cli-B-Cp1Sb1.js → memory-cli-CHNghdrm.js} +12 -12
  107. package/dist/{model-MUMSB_7d.js → model-Cwbcw-km.js} +1 -1
  108. package/dist/{model-auth-1EAQvYRv.js → model-auth-_C07_3Yr.js} +2 -2
  109. package/dist/{model-catalog-IWi6-nY9.js → model-catalog-BWurV7gl.js} +3 -3
  110. package/dist/{model-picker-Cf6UgQEh.js → model-picker-Dpkr5xBW.js} +5 -5
  111. package/dist/{model-selection-7wdmO-Iw.js → model-selection-CCTzD29o.js} +1 -1
  112. package/dist/{models-Cht7Mzvs.js → models-BYev6YAG.js} +3 -3
  113. package/dist/{models-cli-B_motPDX.js → models-cli-BbK8HMKa.js} +55 -55
  114. package/dist/{models-cli-DXswzgUR.js → models-cli-Fa5r1QYP.js} +9 -9
  115. package/dist/{models-config-B5Xxy-c-.js → models-config-DlXge3Sd.js} +8 -8
  116. package/dist/{node-cli-D-gsjRXY.js → node-cli-BPnBosC4.js} +27 -27
  117. package/dist/{node-cli-VmKhIXuP.js → node-cli-Cv7x1gGu.js} +1 -1
  118. package/dist/{node-service-BH08wY5j.js → node-service-Cc18m-uk.js} +1 -1
  119. package/dist/{nodes-cli-BMvxQGCp.js → nodes-cli-CN_m6PO5.js} +10 -10
  120. package/dist/{nodes-cli-D199d74o.js → nodes-cli-DaHOBbd4.js} +3 -3
  121. package/dist/{nodes-screen-De9ma6e1.js → nodes-screen-Cp5QP3ET.js} +4 -4
  122. package/dist/{npm-registry-spec-DTqn-NXZ.js → npm-registry-spec-C-muP97-.js} +9 -9
  123. package/dist/{onboard-DFJcbABp.js → onboard-B2IcTMv-.js} +15 -15
  124. package/dist/{onboard-CdRA8BRG.js → onboard-D-m6WTZl.js} +3 -3
  125. package/dist/{onboard-channels-fadyQGBK.js → onboard-channels-Z-Jkrk5-.js} +1 -1
  126. package/dist/{onboard-channels-Ca7ZFQ2Y.js → onboard-channels-wfGO5Zlh.js} +4 -4
  127. package/dist/{onboard-custom-BcRYreNG.js → onboard-custom-DnDrvxSg.js} +3 -3
  128. package/dist/{onboard-helpers-CQBpac8h.js → onboard-helpers-BKejzolA.js} +8 -8
  129. package/dist/{onboard-helpers-BcLPSb5N.js → onboard-helpers-Dhr98nj8.js} +1 -1
  130. package/dist/{onboard-hooks-2SCajRKc.js → onboard-hooks-D9jHwImb.js} +1 -1
  131. package/dist/{onboard-remote-Bo3tpC9N.js → onboard-remote-DZdMxd1Q.js} +1 -1
  132. package/dist/{onboard-remote-BWK5Ths4.js → onboard-remote-y3ZmP90U.js} +1 -1
  133. package/dist/{onboard-skills-BLl8HPJO.js → onboard-skills-2SUv-W7i.js} +1 -1
  134. package/dist/{onboard-skills-DvacccqZ.js → onboard-skills-BFhHfrt9.js} +3 -3
  135. package/dist/{onboarding-ojb2rFkA.js → onboarding-BckHLQMV.js} +7 -7
  136. package/dist/{onboarding-BywueA1d.js → onboarding-DqlPV372.js} +12 -12
  137. package/dist/{onboarding.finalize-DdxBQpUU.js → onboarding.finalize-Bwjv3jew.js} +31 -31
  138. package/dist/{onboarding.finalize-DHvlZi9G.js → onboarding.finalize-CbH_ShIW.js} +9 -9
  139. package/dist/{onboarding.gateway-config-DPBNWNV6.js → onboarding.gateway-config-CiRo9EMt.js} +8 -8
  140. package/dist/{onboarding.gateway-config-ZK9517uR.js → onboarding.gateway-config-sNSeEykB.js} +3 -3
  141. package/dist/{openai-model-default-BkuuK-Di.js → openai-model-default-De-UAjwg.js} +2 -2
  142. package/dist/{pairing-cli-Rsae0KnN.js → pairing-cli-CBMMCNnx.js} +5 -5
  143. package/dist/{pairing-store-BNhJOnWn.js → pairing-store-Be-ZQK87.js} +1 -1
  144. package/dist/{pairing-token-Dcy37-4s.js → pairing-token-B703A1U3.js} +7 -7
  145. package/dist/{paths-DObzwe08.js → paths-BWqg8NZT.js} +1 -1
  146. package/dist/{pi-auth-json-Db8XJVGL.js → pi-auth-json-D-vdh-nY.js} +6 -6
  147. package/dist/{pi-embedded-Da0QRlM0.js → pi-embedded-B9rtlNMc.js} +25 -9
  148. package/dist/{pi-embedded-helpers-D-OFjhdI.js → pi-embedded-helpers-j1JrlsI0.js} +6 -6
  149. package/dist/{pi-tools.policy-H2t-Xkfc.js → pi-tools.policy-CvAqjEH9.js} +3 -3
  150. package/dist/{plugin-auto-enable-DJBhDIMq.js → plugin-auto-enable-BXSJTxI7.js} +1 -1
  151. package/dist/{plugin-registry-tG7NXc3Y.js → plugin-registry-B43UosQh.js} +3 -3
  152. package/dist/{plugin-registry-Tlmjr-LX.js → plugin-registry-CS4WgHbu.js} +1 -1
  153. package/dist/plugin-sdk/gateway/protocol/schema/logs-chat.d.ts +1 -1
  154. package/dist/plugin-sdk/index.js +6 -6
  155. package/dist/plugin-sdk/infra/symframe-broadcast.d.ts +18 -6
  156. package/dist/{plugins-cli-CRKD8aho.js → plugins-cli-BV2wbjfI.js} +54 -54
  157. package/dist/{plugins-cli-Cm0G_-Y5.js → plugins-cli-BY42hyHP.js} +7 -7
  158. package/dist/{ports-r7LBic2V.js → ports-Bi3V_3n9.js} +1 -1
  159. package/dist/{ports-gxLM5ahL.js → ports-CB_Iu83U.js} +2 -2
  160. package/dist/{program-DEmAlwmD.js → program-P9F1DxBa.js} +12 -12
  161. package/dist/{program-context-DRCRbDpu.js → program-context-BmXxHUKe.js} +40 -40
  162. package/dist/{prompt-select-styled-pomsR-zf.js → prompt-select-styled-B2ah467m.js} +7 -7
  163. package/dist/{prompt-select-styled-B41Tx9aC.js → prompt-select-styled-BlQZX6pK.js} +38 -38
  164. package/dist/{provider-auth-helpers-rKWs_r7a.js → provider-auth-helpers-Bgb_Bfp9.js} +1 -1
  165. package/dist/{provider-auth-helpers-CdQwOam7.js → provider-auth-helpers-WLwb6tL4.js} +6 -6
  166. package/dist/{push-apns-eCM0qmrY.js → push-apns-CBGvXev_.js} +4 -4
  167. package/dist/{push-apns-CZPUHftn.js → push-apns-DnSCjFu7.js} +1 -1
  168. package/dist/{pw-ai-BiBvIJzd.js → pw-ai-CP5pn3eU.js} +7 -7
  169. package/dist/{pw-ai-DLsdzdgc.js → pw-ai-DY_6l11g.js} +1 -1
  170. package/dist/{qmd-manager-C8-M4Pru.js → qmd-manager-Dxyue7B1.js} +19 -19
  171. package/dist/{qr-cli-1sCVaPcF.js → qr-cli-DHw6muwK.js} +3 -3
  172. package/dist/{register.agent-BQPvYYdn.js → register.agent-BuEcmVg0.js} +12 -12
  173. package/dist/{register.agent-N1hoqMFR.js → register.agent-CXdTiqyP.js} +67 -67
  174. package/dist/{register.configure-BHHZ44xB.js → register.configure-DVcn-gCO.js} +70 -70
  175. package/dist/{register.configure-BAc3P4Z-.js → register.configure-YDKJ-KQg.js} +14 -14
  176. package/dist/{register.maintenance-lX0a3Hzl.js → register.maintenance-BiGvpEj-.js} +13 -13
  177. package/dist/{register.maintenance-DDgy5Iyy.js → register.maintenance-cpspl8D6.js} +67 -67
  178. package/dist/{register.message-Br-IH_0z.js → register.message-BIuLbESM.js} +7 -7
  179. package/dist/{register.message-B4lDhHpE.js → register.message-BjcYy5UG.js} +47 -47
  180. package/dist/{register.onboard-B-GoYJIc.js → register.onboard-C4vIASed.js} +6 -6
  181. package/dist/{register.onboard-Bv0s2_KV.js → register.onboard-D4RN92s2.js} +25 -25
  182. package/dist/{register.setup-DQ6KLkAI.js → register.setup-BvoXF0xl.js} +28 -28
  183. package/dist/{register.setup-4lNdC98i.js → register.setup-D-Jt2e1d.js} +6 -6
  184. package/dist/{register.status-health-sessions-Cg7bK5K2.js → register.status-health-sessions-BY9hMD1s.js} +8 -8
  185. package/dist/{register.status-health-sessions-ByGn71_M.js → register.status-health-sessions-DjDvCXBn.js} +41 -41
  186. package/dist/{register.subclis-FMlcLBX0.js → register.subclis-Cibmeapc.js} +20 -20
  187. package/dist/{replies-CbXXjn9X.js → replies-B_3j7R_Q.js} +1 -1
  188. package/dist/{reply-prefix-BFNeXT65.js → reply-prefix-CtZtkTJK.js} +1 -1
  189. package/dist/{resolve-route-C1IIA6kH.js → resolve-route-Du0VftVs.js} +1 -1
  190. package/dist/{routes-ivqbutvM.js → routes-BwTUoI5h.js} +10 -10
  191. package/dist/{rpc-Dk1Az_d8.js → rpc-BnAKPQDB.js} +1 -1
  192. package/dist/{rpc-JAmDaTYt.js → rpc-CwxSZZOx.js} +1 -1
  193. package/dist/{run-main-DSyeVDsT.js → run-main-BhEQjKtM.js} +20 -20
  194. package/dist/{sandbox-BkznAPKO.js → sandbox-CZGTCone.js} +18 -18
  195. package/dist/{sandbox-cli-Bb9cBtBH.js → sandbox-cli-DEtGT_4y.js} +13 -13
  196. package/dist/{security-cli-DmgGLP83.js → security-cli-CS-ZT1LE.js} +3 -3
  197. package/dist/{security-cli-D47LQbpf.js → security-cli-DJd7Fcdy.js} +29 -29
  198. package/dist/{send-B0jHSNMF.js → send-CxjvucMO.js} +7 -7
  199. package/dist/{server-context-ChcbJgNo.js → server-context-DXdk410X.js} +5 -5
  200. package/dist/{server-methods-DGBBt49x.js → server-methods-CWxr5b-w.js} +19 -13
  201. package/dist/{server-methods-BkHB2MOW.js → server-methods-DfVfzYqq.js} +68 -62
  202. package/dist/{server-node-events-C186LRm0.js → server-node-events-B0yC6hi1.js} +48 -48
  203. package/dist/{server-node-events-D-Akk3uq.js → server-node-events-ClDEcUTJ.js} +8 -8
  204. package/dist/{service-e6MzlLCd.js → service-CRZoXO_n.js} +15 -15
  205. package/dist/{session-dirs-C9E2G0yZ.js → session-dirs-a00Ad2SO.js} +2 -2
  206. package/dist/{session-utils-Cs1jlD-q.js → session-utils-CJhcRx3E.js} +14 -14
  207. package/dist/{sessions-Dxf5Kjig.js → sessions-BCc3THTm.js} +10 -10
  208. package/dist/{shared-1xPo9ygd.js → shared-C39SiDDJ.js} +1 -1
  209. package/dist/{shared-COtpr3Ad.js → shared-Dh-O8nRd.js} +3 -3
  210. package/dist/{skill-commands-DDGGlq68.js → skill-commands-DWvXs3lz.js} +4 -4
  211. package/dist/{skill-scanner-BCgVcIwi.js → skill-scanner-CIlHPszT.js} +5 -5
  212. package/dist/{skills-BwDmcZdt.js → skills-CYcBtLGH.js} +4 -4
  213. package/dist/{skills-cli-B-7TY-vS.js → skills-cli-CD9s3cgm.js} +7 -7
  214. package/dist/{skills-install-Dwzsjoc8.js → skills-install-BTa9IuQ6.js} +3 -3
  215. package/dist/{skills-remote-bz71Bstn.js → skills-remote-BcRQTDsZ.js} +3 -3
  216. package/dist/{skills-status-BKX1PjCc.js → skills-status-DLnCHUZ2.js} +1 -1
  217. package/dist/{sqlite-Cod7C5ba.js → sqlite-BpogPlQW.js} +5 -5
  218. package/dist/{status-CFgCSaDq.js → status-BWxLtb3D.js} +23 -23
  219. package/dist/{status-poPDyC8O.js → status-Doq8T1zj.js} +3 -3
  220. package/dist/{status-Bahhq7OQ.js → status-K1k4g3Ai.js} +1 -1
  221. package/dist/{status-D9LC5P_Y.js → status-ojZB_Lrf.js} +5 -5
  222. package/dist/{status.update-DGJi0OLl.js → status.update-CKfyV6zw.js} +3 -3
  223. package/dist/{subagent-registry-V2o45tIn.js → subagent-registry-BOt7g9hn.js} +21 -10
  224. package/dist/{symframe-cli-bxdpivve.js → symframe-cli-CrUtJw_7.js} +31 -7
  225. package/dist/{symframe-cli-ppdMo15M.js → symframe-cli-D1CtN3pf.js} +37 -13
  226. package/dist/{symi-root-BQ0IpoW2.js → symi-root-DeCVdZB4.js} +2 -2
  227. package/dist/{synthesis-B2EyHFXy.js → synthesis-BIQLrbys.js} +6 -6
  228. package/dist/{synthesis-DGau1ONT.js → synthesis-Bc2QkGvt.js} +2 -2
  229. package/dist/{synthesis-CPSq83PP.js → synthesis-VZNnlUTf.js} +45 -45
  230. package/dist/{synthesis-C2WbvLOI.js → synthesis-yl24Ovw4.js} +4 -4
  231. package/dist/{system-cli-nPyjUPBH.js → system-cli-CvN-Wq9U.js} +3 -3
  232. package/dist/{system-cli-BroqLjZ6.js → system-cli-r7WJj0Xh.js} +7 -7
  233. package/dist/{systemd-CUIM0n5P.js → systemd-CsoVnIbM.js} +5 -5
  234. package/dist/{systemd-hints-CsrzMCTD.js → systemd-hints-QISwLlFU.js} +6 -6
  235. package/dist/{systemd-linger-BzYk7A6M.js → systemd-linger-BnhuRdbt.js} +1 -1
  236. package/dist/{tui-Bp9k5skv.js → tui-BxgdImL_.js} +2 -2
  237. package/dist/{tui-DzROrE20.js → tui-J7Jxp-FF.js} +7 -7
  238. package/dist/{tui-cli-BHBF8O-3.js → tui-cli-DR48dU_C.js} +19 -19
  239. package/dist/{tui-cli-Dv4hBFdc.js → tui-cli-DqvgN5ng.js} +3 -3
  240. package/dist/{unified-runner-CIQIkbvi.js → unified-runner-BV5TdNFv.js} +32 -16
  241. package/dist/{unified-runner-CduaBH_0.js → unified-runner-DXjH-prv.js} +117 -106
  242. package/dist/{update-yYduAjKd.js → update-Cb0Fmxic.js} +3 -3
  243. package/dist/{update-check-BCL_K7kx.js → update-check-u6Jgr1cz.js} +5 -5
  244. package/dist/{update-cli-WcLxjBiY.js → update-cli-CKpjWtlv.js} +77 -77
  245. package/dist/{update-cli-BKnHBe8a.js → update-cli-Dn6QQZLd.js} +14 -14
  246. package/dist/{update-runner-BLV8SI96.js → update-runner-G2YgEATs.js} +15 -15
  247. package/dist/{webhooks-cli-D5k-Y2A8.js → webhooks-cli-DjUITimx.js} +4 -4
  248. package/dist/{with-timeout-DPR4A2dx.js → with-timeout-CLrF-Yr_.js} +1 -1
  249. package/dist/{workspace-dirs-jKFQf7of.js → workspace-dirs-DCICLTHx.js} +1 -1
  250. package/dist/{wsl-CglTdtlb.js → wsl-DTi7eX-V.js} +2 -2
  251. package/extensions/memory-core/package.json +1 -1
  252. package/extensions/msteams/CHANGELOG.md +6 -0
  253. package/extensions/msteams/package.json +1 -1
  254. package/extensions/open-prose/package.json +1 -1
  255. package/extensions/outlook/package.json +1 -1
  256. package/extensions/slack/package.json +1 -1
  257. package/package.json +1 -1
@@ -0,0 +1,301 @@
1
+ // ── Symframe AWAITING surface ───────────────────────────────────────────────
2
+ // Stage C of the Dynamic Glass Panel arc — see ~/Documents/dynamic-glass-panel.md.
3
+ //
4
+ // The AWAITING surface is a footer inside the symframe that merges
5
+ // in-flight sub-agents and scheduled cron jobs into a single list —
6
+ // one mental concept: "things that aren't done yet."
7
+ //
8
+ // Sort order:
9
+ // 1. In-flight sub-agents first, sorted by start time (descending —
10
+ // most-recently-started visible at the top)
11
+ // 2. Then scheduled jobs sorted by next ETA (soonest first)
12
+ //
13
+ // Data flow:
14
+ // subagents.js + scheduling.js dispatch CustomEvents after each
15
+ // successful poll fetch. The AWAITING surface listens to both events
16
+ // and re-renders the merged list. No duplicate polling — single
17
+ // source of truth per data type.
18
+ //
19
+ // Click handlers:
20
+ // - Sub-agent row → no-op for now (subagents.list returns enough
21
+ // info to display, but there's no per-subagent detail modal yet;
22
+ // future enhancement: open a side view with the subagent transcript)
23
+ // - Schedule row → opens the existing schedule edit modal via
24
+ // window.schedulingPanel.openForEdit(job)
25
+ // - Schedule toggle → window.schedulingPanel.toggle(jobId)
26
+ // - [+ Add] → small menu: "Spawn subagent" / "Add scheduled task"
27
+ // → opens the corresponding existing modal.
28
+ // ─────────────────────────────────────────────────────────────────────────────
29
+
30
+ "use strict";
31
+
32
+ (function () {
33
+ const root = document.getElementById("symframe-awaiting");
34
+ if (!root) {
35
+ return;
36
+ }
37
+ const list = document.getElementById("awaiting-list");
38
+ const countEl = document.getElementById("awaiting-count");
39
+ const addBtn = document.getElementById("awaiting-add-btn");
40
+ const addMenu = document.getElementById("awaiting-add-menu");
41
+
42
+ // ── State ──
43
+ let subagents = [];
44
+ let schedules = [];
45
+
46
+ // ── DOM helpers ──
47
+ function escHtml(s) {
48
+ return String(s ?? "")
49
+ .replace(/&/g, "&")
50
+ .replace(/</g, "&lt;")
51
+ .replace(/>/g, "&gt;")
52
+ .replace(/"/g, "&quot;")
53
+ .replace(/'/g, "&#39;");
54
+ }
55
+
56
+ // ── Formatters ──
57
+ function formatRuntime(sub) {
58
+ const start = sub.startedAt;
59
+ const end = sub.endedAt || Date.now();
60
+ if (!start) {
61
+ return "--";
62
+ }
63
+ const seconds = Math.floor((end - start) / 1000);
64
+ if (seconds < 60) {
65
+ return `${seconds}s`;
66
+ }
67
+ const minutes = Math.floor(seconds / 60);
68
+ const secs = seconds % 60;
69
+ if (minutes < 60) {
70
+ return `${minutes}m${secs > 0 ? secs + "s" : ""}`;
71
+ }
72
+ const hours = Math.floor(minutes / 60);
73
+ const mins = minutes % 60;
74
+ return `${hours}h${mins}m`;
75
+ }
76
+
77
+ function formatEta(nextRunAtMs) {
78
+ if (!nextRunAtMs) {
79
+ return "—";
80
+ }
81
+ const ms = nextRunAtMs - Date.now();
82
+ if (ms <= 0) {
83
+ return "now";
84
+ }
85
+ const minutes = Math.floor(ms / 60_000);
86
+ if (minutes < 1) {
87
+ return "<1m";
88
+ }
89
+ if (minutes < 60) {
90
+ return `in ${minutes}m`;
91
+ }
92
+ const hours = Math.floor(minutes / 60);
93
+ const mins = minutes % 60;
94
+ if (hours < 24) {
95
+ return mins > 0 ? `in ${hours}h ${mins}m` : `in ${hours}h`;
96
+ }
97
+ const days = Math.floor(hours / 24);
98
+ const hrs = hours % 24;
99
+ return hrs > 0 ? `in ${days}d ${hrs}h` : `in ${days}d`;
100
+ }
101
+
102
+ // ── Item builders ──
103
+ function buildSubagentRow(sub) {
104
+ const item = document.createElement("div");
105
+ item.className = "awaiting-item awaiting-item-subagent";
106
+ item.dataset.runId = sub.runId || "";
107
+ const label = sub.label || "Subagent";
108
+ const status = sub.status === "active" || !sub.endedAt ? "running" : sub.status;
109
+ const right = status === "running" ? formatRuntime(sub) : status;
110
+ item.innerHTML = `
111
+ <span class="awaiting-glyph awaiting-glyph-subagent">◆</span>
112
+ <span class="awaiting-label">${escHtml(label)}</span>
113
+ <span class="awaiting-meta">${escHtml(right)}</span>
114
+ `;
115
+ return item;
116
+ }
117
+
118
+ function buildScheduleRow(job) {
119
+ const item = document.createElement("div");
120
+ item.className = "awaiting-item awaiting-item-schedule";
121
+ if (!job.enabled) {
122
+ item.classList.add("awaiting-item-disabled");
123
+ }
124
+ item.dataset.scheduleId = job.id || "";
125
+ item.tabIndex = 0;
126
+ item.setAttribute("role", "button");
127
+ const name = job.name || "Unnamed";
128
+ const eta = job.enabled ? formatEta(job.state?.nextRunAtMs) : "off";
129
+ item.innerHTML = `
130
+ <span class="awaiting-glyph awaiting-glyph-schedule" data-action="toggle" title="${job.enabled ? "Disable" : "Enable"}">⏱</span>
131
+ <span class="awaiting-label">${escHtml(name)}</span>
132
+ <span class="awaiting-meta">${escHtml(eta)}</span>
133
+ `;
134
+ // Toggle on the glyph; edit modal on the row.
135
+ item.addEventListener("click", (e) => {
136
+ if (e.target instanceof Element && e.target.dataset.action === "toggle") {
137
+ e.stopPropagation();
138
+ if (typeof window.schedulingPanel?.toggle === "function") {
139
+ void window.schedulingPanel.toggle(job.id);
140
+ }
141
+ return;
142
+ }
143
+ if (typeof window.schedulingPanel?.openForEdit === "function") {
144
+ window.schedulingPanel.openForEdit(job);
145
+ }
146
+ });
147
+ item.addEventListener("keydown", (e) => {
148
+ if (e.key === "Enter" || e.key === " ") {
149
+ e.preventDefault();
150
+ if (typeof window.schedulingPanel?.openForEdit === "function") {
151
+ window.schedulingPanel.openForEdit(job);
152
+ }
153
+ }
154
+ });
155
+ return item;
156
+ }
157
+
158
+ // ── Render ──
159
+ function render() {
160
+ const activeSubagents = subagents
161
+ .filter((s) => s.status === "active" || !s.endedAt)
162
+ .toSorted((a, b) => (b.startedAt || 0) - (a.startedAt || 0));
163
+
164
+ const sortedSchedules = schedules.toSorted((a, b) => {
165
+ // Enabled first; then by next ETA ascending; disabled tail
166
+ if (a.enabled !== b.enabled) {
167
+ return b.enabled ? 1 : -1;
168
+ }
169
+ return (a.state?.nextRunAtMs || Infinity) - (b.state?.nextRunAtMs || Infinity);
170
+ });
171
+
172
+ const totalActive = activeSubagents.length + sortedSchedules.filter((s) => s.enabled).length;
173
+
174
+ // Hide entire footer when nothing's pending and no schedules exist —
175
+ // a quiet panel is part of the design. Show whenever there's any
176
+ // activity or any scheduled job (even disabled — so user can re-enable).
177
+ const hasAny = activeSubagents.length > 0 || sortedSchedules.length > 0;
178
+ root.hidden = !hasAny && !addMenuOpen;
179
+
180
+ // Count badge: "N active" (in-flight subagents + enabled schedules)
181
+ if (countEl) {
182
+ if (totalActive === 0) {
183
+ countEl.textContent = "";
184
+ } else {
185
+ const subPart =
186
+ activeSubagents.length > 0
187
+ ? `${activeSubagents.length} sub${activeSubagents.length !== 1 ? "s" : ""}`
188
+ : null;
189
+ const schedPart =
190
+ sortedSchedules.filter((s) => s.enabled).length > 0
191
+ ? `${sortedSchedules.filter((s) => s.enabled).length} job${sortedSchedules.filter((s) => s.enabled).length !== 1 ? "s" : ""}`
192
+ : null;
193
+ countEl.textContent = [subPart, schedPart].filter(Boolean).join(" · ");
194
+ }
195
+ }
196
+
197
+ if (!list) {
198
+ return;
199
+ }
200
+ list.innerHTML = "";
201
+ for (const sub of activeSubagents) {
202
+ list.appendChild(buildSubagentRow(sub));
203
+ }
204
+ for (const job of sortedSchedules) {
205
+ list.appendChild(buildScheduleRow(job));
206
+ }
207
+ }
208
+
209
+ // ── Add menu ──
210
+ let addMenuOpen = false;
211
+
212
+ function openAddMenu() {
213
+ if (!addMenu || !addBtn) {
214
+ return;
215
+ }
216
+ addMenuOpen = true;
217
+ addMenu.hidden = false;
218
+ addBtn.setAttribute("aria-expanded", "true");
219
+ // Ensure footer is visible while menu is open
220
+ root.hidden = false;
221
+ document.addEventListener("click", onOutsideClickAddMenu, true);
222
+ document.addEventListener("keydown", onAddMenuKey);
223
+ }
224
+
225
+ function closeAddMenu() {
226
+ if (!addMenu || !addBtn) {
227
+ return;
228
+ }
229
+ addMenuOpen = false;
230
+ addMenu.hidden = true;
231
+ addBtn.setAttribute("aria-expanded", "false");
232
+ document.removeEventListener("click", onOutsideClickAddMenu, true);
233
+ document.removeEventListener("keydown", onAddMenuKey);
234
+ render(); // re-evaluate hidden state
235
+ }
236
+
237
+ function onOutsideClickAddMenu(e) {
238
+ if (!addMenu || !addBtn) {
239
+ return;
240
+ }
241
+ if (e.target instanceof Node) {
242
+ if (addMenu.contains(e.target) || addBtn.contains(e.target)) {
243
+ return;
244
+ }
245
+ }
246
+ closeAddMenu();
247
+ }
248
+
249
+ function onAddMenuKey(e) {
250
+ if (e.key === "Escape") {
251
+ closeAddMenu();
252
+ }
253
+ }
254
+
255
+ // ── Init ──
256
+ function init() {
257
+ window.addEventListener("symi:subagents-updated", (e) => {
258
+ subagents = e.detail?.subagents || [];
259
+ render();
260
+ });
261
+ window.addEventListener("symi:schedules-updated", (e) => {
262
+ schedules = e.detail?.schedules || [];
263
+ render();
264
+ });
265
+
266
+ if (addBtn) {
267
+ addBtn.addEventListener("click", (e) => {
268
+ e.stopPropagation();
269
+ if (addMenuOpen) {
270
+ closeAddMenu();
271
+ } else {
272
+ openAddMenu();
273
+ }
274
+ });
275
+ }
276
+ if (addMenu) {
277
+ addMenu.addEventListener("click", (e) => {
278
+ const target = e.target instanceof Element ? e.target.closest("[data-add]") : null;
279
+ if (!target) {
280
+ return;
281
+ }
282
+ const which = target.getAttribute("data-add");
283
+ closeAddMenu();
284
+ if (which === "subagent" && typeof window.subagentsPanel?.open === "function") {
285
+ window.subagentsPanel.open();
286
+ } else if (which === "schedule" && typeof window.schedulingPanel?.open === "function") {
287
+ window.schedulingPanel.open();
288
+ }
289
+ });
290
+ }
291
+
292
+ // First paint
293
+ render();
294
+ }
295
+
296
+ if (document.readyState === "loading") {
297
+ document.addEventListener("DOMContentLoaded", init);
298
+ } else {
299
+ init();
300
+ }
301
+ })();
@@ -0,0 +1,104 @@
1
+ // ── Symframe Pin Store ──────────────────────────────────────────────────────
2
+ // Stage C of the Dynamic Glass Panel arc — see ~/Documents/dynamic-glass-panel.md §9.3.
3
+ //
4
+ // Per-browser pin persistence via localStorage. Pinned cards survive
5
+ // page reload, /new, and gateway reconnect — they are user-curated
6
+ // state, not agent-pushed state.
7
+ //
8
+ // Storage shape:
9
+ // localStorage["symi:symframe:pins"] = JSON.stringify({
10
+ // version: 1,
11
+ // pins: [
12
+ // { id, card: {...}, pinnedAt: <ms> },
13
+ // ...
14
+ // ]
15
+ // })
16
+ //
17
+ // `card` is a snapshot of the card at pin time — frozen content. A
18
+ // dynamic card whose content changes after pinning will keep the
19
+ // pinned-time snapshot in the registry on next reload (intentional;
20
+ // the user pinned what they saw).
21
+ //
22
+ // Public API (window.symframePinStore):
23
+ // list() — snapshot of all pinned card records
24
+ // pin(card) — write a card to localStorage (idempotent on id)
25
+ // unpin(id) — remove a card from localStorage by id
26
+ // isPinned(id) — boolean check
27
+ // ─────────────────────────────────────────────────────────────────────────────
28
+
29
+ "use strict";
30
+
31
+ (function () {
32
+ const KEY = "symi:symframe:pins";
33
+ const VERSION = 1;
34
+
35
+ function readStore() {
36
+ try {
37
+ const raw = localStorage.getItem(KEY);
38
+ if (!raw) {
39
+ return { version: VERSION, pins: [] };
40
+ }
41
+ const parsed = JSON.parse(raw);
42
+ if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.pins)) {
43
+ return { version: VERSION, pins: [] };
44
+ }
45
+ return parsed;
46
+ } catch (err) {
47
+ console.warn("[symframe-pin-store] read failed; resetting:", err);
48
+ return { version: VERSION, pins: [] };
49
+ }
50
+ }
51
+
52
+ function writeStore(store) {
53
+ try {
54
+ localStorage.setItem(KEY, JSON.stringify(store));
55
+ } catch (err) {
56
+ console.warn("[symframe-pin-store] write failed:", err);
57
+ }
58
+ }
59
+
60
+ function list() {
61
+ return readStore().pins;
62
+ }
63
+
64
+ function pin(card) {
65
+ if (!card || typeof card !== "object" || !card.id) {
66
+ console.warn("[symframe-pin-store] pin: card missing id");
67
+ return false;
68
+ }
69
+ const store = readStore();
70
+ const existing = store.pins.findIndex((p) => p.id === card.id);
71
+ const record = {
72
+ id: card.id,
73
+ card: { ...card, pinned: true },
74
+ pinnedAt: Date.now(),
75
+ };
76
+ if (existing >= 0) {
77
+ store.pins[existing] = record;
78
+ } else {
79
+ store.pins.push(record);
80
+ }
81
+ writeStore(store);
82
+ return true;
83
+ }
84
+
85
+ function unpin(id) {
86
+ if (!id) {
87
+ return false;
88
+ }
89
+ const store = readStore();
90
+ const before = store.pins.length;
91
+ store.pins = store.pins.filter((p) => p.id !== id);
92
+ if (store.pins.length === before) {
93
+ return false;
94
+ }
95
+ writeStore(store);
96
+ return true;
97
+ }
98
+
99
+ function isPinned(id) {
100
+ return readStore().pins.some((p) => p.id === id);
101
+ }
102
+
103
+ window.symframePinStore = { list, pin, unpin, isPinned };
104
+ })();
@@ -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,6 +573,180 @@
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());
@@ -586,7 +780,20 @@
586
780
  }
587
781
  }
588
782
 
589
- 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
+ };
590
797
 
591
798
  // Phase 3: server-pushed cards. The gateway's `symframe` broadcast is
592
799
  // re-emitted as a window-level CustomEvent by gateway.js — subscribe
@@ -594,6 +801,8 @@
594
801
  // chat.symframe.push RPC: { action, id?, card?, force? }.
595
802
  // Stage A: `force` flows through to update/remove so the agent (via
596
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.
597
806
  window.addEventListener("symi:symframe", (e) => {
598
807
  const payload = e.detail;
599
808
  if (!payload || typeof payload !== "object") {
@@ -606,6 +815,33 @@
606
815
  update(payload.id, payload.card, force);
607
816
  } else if (payload.action === "remove" && payload.id) {
608
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);
609
828
  }
610
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
+ }
611
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";