@symerian/symi 3.4.30 → 3.4.32

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 (422) hide show
  1. package/dist/{agent-O3PihJOY.js → agent-BaSGoKPq.js} +17 -17
  2. package/dist/{agent-tdS4G7e8.js → agent-C8IIjDyn.js} +21 -21
  3. package/dist/{agent-scope-Ck_TLGsV.js → agent-scope-B6p555mP.js} +1 -1
  4. package/dist/{agent-scope-DJI5ijOw.js → agent-scope-DIjW66iO.js} +3 -3
  5. package/dist/{agents-C2MpIr16.js → agents-D6Ygz9ED.js} +12 -12
  6. package/dist/{agents.config-PPeqGzAc.js → agents.config-D1nFwU81.js} +1 -1
  7. package/dist/{agents.config-LRW5SZoE.js → agents.config-D7cHU-OU.js} +1 -1
  8. package/dist/{audit-TmPjr_wD.js → audit-BI8Rbs5q.js} +19 -19
  9. package/dist/{audit-yf3H4Y1h.js → audit-nqP-JeOr.js} +17 -17
  10. package/dist/{auth-BSmNj-Lv.js → auth-BbwD4lRX.js} +1 -1
  11. package/dist/{auth-choice-Bw2Kd6RM.js → auth-choice-BBrEzoy2.js} +8 -8
  12. package/dist/{auth-choice-CyBcsQ9T.js → auth-choice-Bx4Duu6u.js} +8 -8
  13. package/dist/{auth-profiles-C1lvfaCM.js → auth-profiles-BFSVvFKy.js} +6 -6
  14. package/dist/{auth-profiles-BG_wMJz6.js → auth-profiles-Bs5D0GUv.js} +4 -4
  15. package/dist/{auth-token-C0-TDuag.js → auth-token-Brb1Askz.js} +2 -2
  16. package/dist/{auth-token-BwQ5Nv4O.js → auth-token-SebYuqfR.js} +2 -2
  17. package/dist/{banner-D7__HlM-.js → banner-l9GjW5Rm.js} +2 -2
  18. package/dist/{bindings-D5s2VRjL.js → bindings-9LSA3Jr1.js} +1 -1
  19. package/dist/{bonjour-discovery-YoubCASb.js → bonjour-discovery-BTpm6P8H.js} +1 -1
  20. package/dist/{bonjour-discovery-CPzedvdf.js → bonjour-discovery-CU1mz7AC.js} +2 -2
  21. package/dist/{browser-cli-R6JagRCf.js → browser-cli-BAxOL41p.js} +22 -22
  22. package/dist/{browser-cli-B_6WWHm_.js → browser-cli-Bk8DxxeA.js} +13 -13
  23. package/dist/build-info.json +3 -3
  24. package/dist/bundled/boot-md/handler.js +4 -4
  25. package/dist/bundled/session-memory/handler.js +4 -4
  26. package/dist/{call-IfleM0ap.js → call-5IE9ycvm.js} +3 -4
  27. package/dist/{call-sikajorp.js → call-BPJn2_th.js} +5 -6
  28. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  29. package/dist/{catalog-DgsRZ5Yu.js → catalog-CJzUbDcX.js} +2 -2
  30. package/dist/{catalog-Bc0hKvgn.js → catalog-CSgSg5Gp.js} +2 -2
  31. package/dist/{channel-options-DrHwfPTb.js → channel-options-COanIUoQ.js} +5 -5
  32. package/dist/{channel-options-B5974x-7.js → channel-options-DGUqfnbP.js} +2 -2
  33. package/dist/{channel-selection-Cc4Pvn6b.js → channel-selection-BvIcXQLj.js} +2 -2
  34. package/dist/{channels-cli-D50PQAPc.js → channels-cli-B1zmnm5a.js} +83 -83
  35. package/dist/{channels-cli-C6Nv9mzy.js → channels-cli-CZ3M3yE1.js} +62 -62
  36. package/dist/{channels-status-issues-VZcSU4qT.js → channels-status-issues-DC8vgOMo.js} +1 -1
  37. package/dist/{chrome-DJCkCRLf.js → chrome-B0wRtBRB.js} +3 -3
  38. package/dist/{chrome-DT1fIVG1.js → chrome-B4P7ycw5.js} +7 -7
  39. package/dist/{chrome-CPSDqbK6.js → chrome-CQn8fDIy.js} +7 -7
  40. package/dist/{chrome-BM8HZu2p.js → chrome-VbDUdW0_.js} +4 -4
  41. package/dist/{chunk-D2_aCcvs.js → chunk-DQGU0F8t.js} +1 -1
  42. package/dist/{clack-prompter-BwhCW0Jc.js → clack-prompter-CWQQn_CK.js} +5 -5
  43. package/dist/cli-C7I5uEFC.js +128 -0
  44. package/dist/{cli-DZoms4qg.js → cli-CC5GrdTI.js} +52 -52
  45. package/dist/{client-Bcz3rG5V.js → client-Dp8LUTmF.js} +3 -5
  46. package/dist/{client-BzacpVvW.js → client-qjXXRKCO.js} +5 -7
  47. package/dist/{clipboard-Dz-Ob0yt.js → clipboard-McRwF3r0.js} +1 -1
  48. package/dist/{command-format-6B5tP-i9.js → command-format-Xm6vX3qJ.js} +1 -1
  49. package/dist/{command-registry--D98SJ6k.js → command-registry-D8fj6th4.js} +12 -12
  50. package/dist/{commands-DgyiLrAe.js → commands-B3UrgxIz.js} +2 -2
  51. package/dist/{commands-BN08daX-.js → commands-CHkx0oTl.js} +1 -1
  52. package/dist/{commands-registry-Bbs_ugoi.js → commands-registry-BNCcZy2y.js} +5 -5
  53. package/dist/{commands-registry-QB7xD3bc.js → commands-registry-Bccp0eH5.js} +3 -3
  54. package/dist/{completion-cli-CHYvpIPw.js → completion-cli-BxspmuYm.js} +3 -3
  55. package/dist/{completion-cli-QxWULepB.js → completion-cli-C-85b5b8.js} +4 -4
  56. package/dist/{config-vtCLkS2w.js → config-DqMsGcSQ.js} +7 -21
  57. package/dist/{config-cli-CcZo2229.js → config-cli-BqzjDmIH.js} +13 -13
  58. package/dist/{config-cli-DstpcB33.js → config-cli-DSDGwckX.js} +12 -12
  59. package/dist/{config-guard-CC-lFWDU.js → config-guard-CJcSKMuP.js} +21 -21
  60. package/dist/{config-guard-CCJrDmON.js → config-guard-Cu-dwAgi.js} +4 -4
  61. package/dist/{config-BTSBEAnk.js → config-igdtSRrZ.js} +10 -24
  62. package/dist/{config-validation-DSnQNdDO.js → config-validation-Bp2wJ610.js} +1 -1
  63. package/dist/{config-validation-YCrMlM9Z.js → config-validation-Bs1Gp2oG.js} +2 -2
  64. package/dist/{configure-B-UvSZZ7.js → configure-BazJdwKU.js} +14 -14
  65. package/dist/{configure-C4Qjzxdq.js → configure-Dl1f1Den.js} +25 -25
  66. package/dist/{consolidate-CPVaVTv0.js → consolidate-7Usm-b2g.js} +4 -4
  67. package/dist/{control-service-CwRG4M_O.js → control-service-DO8FjrS6.js} +4 -4
  68. package/dist/{control-service--TrXUUt_.js → control-service-Fn3d9AlH.js} +5 -5
  69. package/dist/{control-ui-assets-DI1jLkM6.js → control-ui-assets-DUhvOLUL.js} +2 -2
  70. package/dist/{cron-cli-DUETe3Of.js → cron-cli-DXgI5Lid.js} +10 -10
  71. package/dist/{cron-cli-BfUM5_Kw.js → cron-cli-DZyH2BfZ.js} +19 -19
  72. package/dist/{daemon-cli-DRDkDw_M.js → daemon-cli-C6FSROt1.js} +18 -18
  73. package/dist/{daemon-cli-Dy5eY4M7.js → daemon-cli-DmMYx5Uf.js} +10 -10
  74. package/dist/daemon-cli.js +0 -3
  75. package/dist/{daemon-runtime-ChztAKDA.js → daemon-runtime-2Y9RfgcP.js} +2 -2
  76. package/dist/{daemon-runtime-CqMnoGym.js → daemon-runtime-BpfA4d6Q.js} +2 -2
  77. package/dist/{deliver-59sRVaYQ.js → deliver-BkCYBlzi.js} +4 -4
  78. package/dist/{deliver-Mqq3tgqB.js → deliver-DvW5xHHr.js} +4 -4
  79. package/dist/{deliver-fvcQPsBc.js → deliver-RwovDEDy.js} +8 -8
  80. package/dist/{deliver-BHmK4isn.js → deliver-izdrXPr4.js} +5 -5
  81. package/dist/{delivery-queue-Du1ukE9B.js → delivery-queue-DDs84baU.js} +1 -1
  82. package/dist/{delivery-queue-Bqja5xKq.js → delivery-queue-nheCYaMd.js} +1 -1
  83. package/dist/{deps-CeHgkkO6.js → deps-bCHNuszw.js} +1 -1
  84. package/dist/{devices-cli-DV8wT4cj.js → devices-cli-D6xXc9Ym.js} +17 -17
  85. package/dist/{devices-cli-BCZ2HHjT.js → devices-cli-IMv-0zor.js} +9 -9
  86. package/dist/{diagnostic-Db9MI5bh.js → diagnostic-CwF3MnBL.js} +1 -1
  87. package/dist/{diagnostics-B9e2Kvx8.js → diagnostics-DxdqTfpW.js} +1 -1
  88. package/dist/{directory-cli-BVGd0l0T.js → directory-cli-3wlYB9In.js} +7 -7
  89. package/dist/{directory-cli-B6Ja7314.js → directory-cli-ClbYhd6z.js} +17 -17
  90. package/dist/{dm-policy-shared-Bjdk2L7B.js → dm-policy-shared-5HLej1br.js} +2 -2
  91. package/dist/{dm-policy-shared-BBTioONS.js → dm-policy-shared-CSF4Tw_F.js} +1 -1
  92. package/dist/{dns-cli-MEjZBWpL.js → dns-cli-CY2voLuR.js} +14 -14
  93. package/dist/{dns-cli-DH-ksmiI.js → dns-cli-CoVIqRWx.js} +8 -8
  94. package/dist/{dock-CSF4Y7tm.js → dock-CnGWTXL4.js} +2 -2
  95. package/dist/{docs-cli-BuX8FDdh.js → docs-cli-CFklWCND.js} +5 -5
  96. package/dist/{docs-cli-Cc3Rhfkx.js → docs-cli-DjQ3SvBq.js} +8 -8
  97. package/dist/{doctor-completion-rBc-f29C.js → doctor-completion-BwHbIZjF.js} +2 -2
  98. package/dist/{doctor-completion-C4Sf8CFV.js → doctor-completion-CX7LjkOD.js} +2 -2
  99. package/dist/{doctor-config-flow-CrnteetS.js → doctor-config-flow-CYDx1U0Z.js} +7 -7
  100. package/dist/{doctor-config-flow-BhmF6EAq.js → doctor-config-flow-wvoEFNeZ.js} +8 -8
  101. package/dist/entry.js +4 -7
  102. package/dist/{env-DoZWjLUy.js → env-B97Ms861.js} +1 -1
  103. package/dist/{exec-BcMHopF9.js → exec-DKyLtSjm.js} +2 -2
  104. package/dist/{exec-approvals-BndOYKTM.js → exec-approvals-B8n8es8o.js} +1 -1
  105. package/dist/{exec-approvals-BZBjOrJL.js → exec-approvals-CZOc8M5w.js} +1 -1
  106. package/dist/{exec-approvals-cli-Bqh3x_d1.js → exec-approvals-cli-B_P-1zVp.js} +24 -24
  107. package/dist/{exec-approvals-cli-CyXTXgft.js → exec-approvals-cli-Dy1jvh2M.js} +16 -16
  108. package/dist/extensionAPI.js +4 -4
  109. package/dist/{fetch-guard-BuQQKfW1.js → fetch-guard-DG6T0ZdL.js} +1 -1
  110. package/dist/{frontmatter-BH3ExkUY.js → frontmatter-B4levtVg.js} +2 -2
  111. package/dist/{gateway-cli-BrcMZGyF.js → gateway-cli-CTcK1Az2.js} +113 -114
  112. package/dist/{gateway-cli-fT43bqlv.js → gateway-cli-CW-Z71cE.js} +88 -89
  113. package/dist/{gateway-rpc-BEqCo2JK.js → gateway-rpc-C1xjWlxu.js} +1 -1
  114. package/dist/{gateway-rpc-cpgRv0Yq.js → gateway-rpc-DD_aXogj.js} +3 -3
  115. package/dist/{github-copilot-token-DIIEouRg.js → github-copilot-token-BTNK6Tcd.js} +1 -1
  116. package/dist/{github-copilot-token-CrM1aEWo.js → github-copilot-token-a6a53zx_.js} +1 -1
  117. package/dist/{glass-ui-ws-dERcmtve.js → glass-ui-ws-BNJkhJrL.js} +96 -96
  118. package/dist/{glass-ui-ws-BfMKuf9v.js → glass-ui-ws-BZvH4MBO.js} +68 -68
  119. package/dist/{gmail-setup-utils-Cz9Tb30q.js → gmail-setup-utils-B1BYpISg.js} +2 -2
  120. package/dist/{gmail-setup-utils-5bVmaBiu.js → gmail-setup-utils-fA1VaWLv.js} +3 -3
  121. package/dist/{health-Bpjd5_Oq.js → health-D8cKia4i.js} +10 -10
  122. package/dist/{health-DDxrkioj.js → health-DdzNc1yA.js} +5 -5
  123. package/dist/{health-format-BQcmGV4C.js → health-format-39e76m9p.js} +1 -1
  124. package/dist/{help-format-Bm9CoBSa.js → help-format-BI_G2p1e.js} +1 -1
  125. package/dist/{hooks-cli-Bkp-j7h6.js → hooks-cli-DkP3Y4ou.js} +76 -76
  126. package/dist/{hooks-cli-Btgk__9z.js → hooks-cli-qO421UdO.js} +59 -59
  127. package/dist/{hooks-status-BjjfBQnp.js → hooks-status-COU9Cw9_.js} +2 -2
  128. package/dist/{hooks-status-BaV4_YaJ.js → hooks-status-uaFS2SUa.js} +3 -3
  129. package/dist/{image-ops-CiGlXf65.js → image-ops-C-gIIp7Q.js} +1 -1
  130. package/dist/index.js +81 -81
  131. package/dist/{inspect-B_hklr0u.js → inspect-BDzd6yBs.js} +1 -1
  132. package/dist/{installs-DjzewzNC.js → installs-DhSLZRT7.js} +2 -2
  133. package/dist/{installs-B7y-N4mr.js → installs-cPraL4Dg.js} +2 -2
  134. package/dist/{lifecycle-core-CHB-QdED.js → lifecycle-core-BEmljRfh.js} +7 -7
  135. package/dist/{lifecycle-core-B0tG8ERp.js → lifecycle-core-uN2bsrZs.js} +3 -3
  136. package/dist/{links-Bmkpld9F.js → links-CSaUKNKm.js} +1 -1
  137. package/dist/{links-D4w-tJYZ.js → links-Db3Rw0Tg.js} +1 -1
  138. package/dist/llm-slug-generator.js +4 -4
  139. package/dist/{local-roots-DSeNuIW-.js → local-roots-Bk3321gv.js} +2 -2
  140. package/dist/{local-roots-lknhM9c3.js → local-roots-BnDnugq3.js} +3 -3
  141. package/dist/{logging-miJdTAeb.js → logging-B96FQvnn.js} +2 -2
  142. package/dist/{logging-DrqPd0Fg.js → logging-BeA4q4J_.js} +1 -1
  143. package/dist/{logs-cli-CUhZrDw7.js → logs-cli-BB0Mq8D1.js} +11 -11
  144. package/dist/{logs-cli-CGcdfvBo.js → logs-cli-Dbmzz8m_.js} +18 -18
  145. package/dist/{manager-BeNnzSJv.js → manager-BD_cpL9b.js} +1 -1
  146. package/dist/{manager-Di9qtuZF.js → manager-BQaZlWzK.js} +6 -6
  147. package/dist/{manager-uBAL1G42.js → manager-D0NIHMuQ.js} +1 -1
  148. package/dist/{manager-DqMx0qDw.js → manager-DOiW-Koo.js} +9 -9
  149. package/dist/{manifest-registry-0FO1WTmC.js → manifest-registry-DJcKcUQ9.js} +1 -1
  150. package/dist/{manifest-registry-DYQQ9Cci.js → manifest-registry-D_LsBSyt.js} +1 -1
  151. package/dist/{markdown-tables-Ca1j7TYS.js → markdown-tables-GTLvbzuR.js} +1 -1
  152. package/dist/{memory-BDeydRz3.js → memory-Cl4I_45k.js} +6 -6
  153. package/dist/{memory-cli-D4hZiGr5.js → memory-cli-CszP57Ee.js} +8 -8
  154. package/dist/{memory-cli-BXclq7qt.js → memory-cli-DkD_OD70.js} +13 -13
  155. package/dist/{memory-BXoRMmVn.js → memory-kIYeV9aO.js} +7 -7
  156. package/dist/{message-channel-BqrA0uMO.js → message-channel-C_V8IAYx.js} +1 -1
  157. package/dist/{model-DibfNW71.js → model-BRcKPW49.js} +1 -1
  158. package/dist/{model-Czbmn47-.js → model-DgN15006.js} +1 -1
  159. package/dist/{model-catalog-DPnCNs5N.js → model-catalog-C2rNhRI4.js} +4 -4
  160. package/dist/{model-catalog-Ds0dg_ob.js → model-catalog-CaGfL-2g.js} +4 -4
  161. package/dist/{model-picker-DuPommMc.js → model-picker-4NUXHy8M.js} +3 -3
  162. package/dist/{model-picker-BbaEgNir.js → model-picker-CV56GE8A.js} +3 -3
  163. package/dist/{models-B0wNKA18.js → models-BYi0Fo1a.js} +21 -21
  164. package/dist/{models-cli-CZY5Me88.js → models-cli-Bn9M1TgO.js} +83 -83
  165. package/dist/{models-cli-CL5K06Wu.js → models-cli-EdjvkvFO.js} +59 -59
  166. package/dist/{models-config-Box19p27.js → models-config-Unnduxgs.js} +3 -3
  167. package/dist/{models-config-CPlvO1b0.js → models-config-yKxNCn4V.js} +3 -3
  168. package/dist/{node-cli-BFBfD3vK.js → node-cli-39H0MZ8q.js} +36 -36
  169. package/dist/{node-cli-CWWMajKF.js → node-cli-C8FYMIjN.js} +21 -21
  170. package/dist/{node-service-CkP4-uRI.js → node-service-tPO_yUk7.js} +1 -1
  171. package/dist/{nodes-cli-BY4Ppctn.js → nodes-cli-C-03nIJ0.js} +22 -22
  172. package/dist/{nodes-cli-YmE7S-JB.js → nodes-cli-CqxQexTU.js} +14 -14
  173. package/dist/{nodes-screen-BfQScwqX.js → nodes-screen-Bkq2kswx.js} +2 -2
  174. package/dist/{nodes-screen-BMUoHTPZ.js → nodes-screen-JELuBMBi.js} +1 -1
  175. package/dist/{note-C4Pc_hIl.js → note-CHrtEumO.js} +2 -2
  176. package/dist/{npm-registry-spec-C8W7KCAB.js → npm-registry-spec-BXw_6vF6.js} +2 -2
  177. package/dist/{npm-registry-spec-s-9OX2Kw.js → npm-registry-spec-NLo2PCol.js} +1 -1
  178. package/dist/{onboard-DjlI4mIw.js → onboard-C8IQnigm.js} +19 -19
  179. package/dist/{onboard-HqUZVKyD.js → onboard-CAIujkV7.js} +13 -13
  180. package/dist/{onboard-channels-BbF5-N3g.js → onboard-channels-B2l6OoMg.js} +7 -7
  181. package/dist/{onboard-channels-C5EUFcLq.js → onboard-channels-D_uUQbem.js} +9 -9
  182. package/dist/{onboard-custom-C-6Cooq5.js → onboard-custom-B2fJvyxt.js} +3 -3
  183. package/dist/{onboard-custom-63SI3jrk.js → onboard-custom-DcZ2SEUv.js} +3 -3
  184. package/dist/{onboard-helpers-Cb3WFLl9.js → onboard-helpers-Bm-oyLWy.js} +5 -5
  185. package/dist/{onboard-helpers-Bpa6_3vl.js → onboard-helpers-CHfdRdZR.js} +9 -9
  186. package/dist/{onboard-hooks-ggR6fsQs.js → onboard-hooks-DBYkemjF.js} +8 -8
  187. package/dist/{onboard-hooks-DXXg3YH9.js → onboard-hooks-DgRzMz0E.js} +5 -5
  188. package/dist/{onboard-remote-Cnxe89N8.js → onboard-remote-ecyetiyL.js} +3 -3
  189. package/dist/{onboard-remote-CqtCrqtm.js → onboard-remote-z8XLK4M0.js} +3 -3
  190. package/dist/{onboard-skills-D5Ww8pwO.js → onboard-skills-BLvL0KPR.js} +4 -4
  191. package/dist/{onboard-skills-CS3l5fhH.js → onboard-skills-C53RGq_5.js} +5 -5
  192. package/dist/{onboarding-BPmsmDud.js → onboarding-4v9LJueP.js} +18 -18
  193. package/dist/{onboarding-Be_HJIFA.js → onboarding-BIq5BxG0.js} +16 -16
  194. package/dist/{onboarding.finalize-QwO5yuPm.js → onboarding.finalize-Bkcwe5RS.js} +51 -51
  195. package/dist/{onboarding.finalize-dsCUTKCQ.js → onboarding.finalize-CXAQzVXM.js} +32 -32
  196. package/dist/{onboarding.gateway-config-BZDShYzP.js → onboarding.gateway-config-3JMN1xRf.js} +22 -22
  197. package/dist/{onboarding.gateway-config-Ctd1_QW4.js → onboarding.gateway-config-Ft3f6Jba.js} +11 -11
  198. package/dist/{openai-model-default-Dxlm7Pvs.js → openai-model-default-BVPmAuXK.js} +3 -3
  199. package/dist/{openai-model-default-DT9-42Xb.js → openai-model-default-CDDFpxUr.js} +3 -3
  200. package/dist/{outbound-send-deps-DPsU_Xdy.js → outbound-send-deps-Dmc3B-LK.js} +1 -1
  201. package/dist/{pairing-cli-PtlNv7Gr.js → pairing-cli-B_icqS8Y.js} +9 -9
  202. package/dist/{pairing-cli-C1TeY-2m.js → pairing-cli-CJGA4j6G.js} +15 -15
  203. package/dist/{pairing-store-5oyzSW2X.js → pairing-store-BGf29nPx.js} +4 -4
  204. package/dist/{pairing-store-B9MEud_Y.js → pairing-store-CtBnCGHZ.js} +2 -2
  205. package/dist/{pairing-token-Cup-49D-.js → pairing-token-Bnr7QjVF.js} +1 -1
  206. package/dist/{pairing-token-BaZLnDjo.js → pairing-token-CURbSHdi.js} +1 -1
  207. package/dist/{path-env-C8hRAfiL.js → path-env-DuQralyy.js} +1 -1
  208. package/dist/{paths-By0XjHBk.js → paths-BSzKwaxE.js} +1 -4
  209. package/dist/{paths-BldkKgCk.js → paths-CJcw9nbZ.js} +1 -1
  210. package/dist/{paths-gcw23t43.js → paths-CNexk5_o.js} +1 -1
  211. package/dist/{paths-7zaGPdLp.js → paths-CsQkeUQ3.js} +1 -1
  212. package/dist/{paths-DeDKrl27.js → paths-Dc6A9_vI.js} +1 -1
  213. package/dist/{pi-auth-json-BOXWkXms.js → pi-auth-json-CUZ7IgY7.js} +1 -1
  214. package/dist/{pi-auth-json-DVUJqaKg.js → pi-auth-json-SHGGQzOL.js} +1 -1
  215. package/dist/{pi-embedded-Cp7d6jtB.js → pi-embedded-CGebiST2.js} +10 -13
  216. package/dist/{pi-embedded-helpers-CVKIHnFv.js → pi-embedded-helpers-BwBjqJM5.js} +2 -2
  217. package/dist/{pi-embedded-helpers-DMVyRPBT.js → pi-embedded-helpers-CAdI9wJ5.js} +4 -4
  218. package/dist/{pi-tools.policy-8_wTu7v2.js → pi-tools.policy-BaRznBvu.js} +3 -3
  219. package/dist/{pi-tools.policy-C5aC-K5q.js → pi-tools.policy-Dyx3nBmp.js} +5 -5
  220. package/dist/{plugin-auto-enable-CYoZQPJO.js → plugin-auto-enable-D2TNEv3x.js} +4 -4
  221. package/dist/{plugin-auto-enable-BWd5lJQf.js → plugin-auto-enable-DSliW8o4.js} +3 -3
  222. package/dist/{plugin-registry-BG51uZOA.js → plugin-registry-D7ACpV2Y.js} +3 -3
  223. package/dist/{plugin-registry-BouuQy-X.js → plugin-registry-d4hMhLLZ.js} +5 -5
  224. package/dist/plugin-sdk/gateway/protocol/index.d.ts +2 -5
  225. package/dist/plugin-sdk/gateway/protocol/schema/logs-chat.d.ts +0 -1
  226. package/dist/{plugins-CypN_04v.js → plugins-DuuHorqi.js} +1 -1
  227. package/dist/{plugins-cli-Bk7Al8u3.js → plugins-cli-CPf1hMaZ.js} +76 -76
  228. package/dist/{plugins-cli-B-zVOiQN.js → plugins-cli-D1gd8p9T.js} +58 -58
  229. package/dist/{ports-BgvsHTN5.js → ports-BAzQoIw0.js} +2 -2
  230. package/dist/{ports-YkSuli-C.js → ports-Cv4kt1bT.js} +1 -1
  231. package/dist/{ports-BxtK6PMH.js → ports-DRHSHvqY.js} +2 -2
  232. package/dist/{ports-CduvYJlk.js → ports-DqxP-bXz.js} +3 -3
  233. package/dist/{program-BOh0XGsA.js → program-C19G7o-Q.js} +63 -63
  234. package/dist/{program-context-D73fzUUe.js → program-context-BSUkEz3n.js} +39 -39
  235. package/dist/{progress-B3rWk9lR.js → progress-CyPyGCDn.js} +2 -2
  236. package/dist/{prompt-select-styled-Bz1VV3Qu.js → prompt-select-styled-B5wlPYN5.js} +40 -40
  237. package/dist/{prompt-select-styled-Bj-hrPCx.js → prompt-select-styled-CnYM7W0j.js} +24 -24
  238. package/dist/{prompt-style-LtRrtcTi.js → prompt-style-Cad0BDRS.js} +1 -1
  239. package/dist/{provider-auth-helpers-BK6NFk2Q.js → provider-auth-helpers-BUC4xGK9.js} +5 -5
  240. package/dist/{provider-auth-helpers-D3hXI6HN.js → provider-auth-helpers-DpRoNr_8.js} +7 -7
  241. package/dist/{push-apns-C1guJr4R.js → push-apns-Bm39oOO9.js} +5 -5
  242. package/dist/{push-apns-CMxk3Hxf.js → push-apns-DqmFEcqh.js} +3 -3
  243. package/dist/{pw-ai-CE2TBGif.js → pw-ai-B0-pgbYu.js} +9 -9
  244. package/dist/{pw-ai-EtT_bBJY.js → pw-ai-B2NuWIL7.js} +13 -13
  245. package/dist/{pw-ai-w6Qalz1W.js → pw-ai-BB1pJj9_.js} +1 -1
  246. package/dist/{pw-ai-C5MJKzUM.js → pw-ai-BsEf8C15.js} +1 -1
  247. package/dist/{qmd-manager--xIse9H_.js → qmd-manager--kGuC39q.js} +4 -4
  248. package/dist/{qmd-manager-DgCmfS8D.js → qmd-manager-358OTDns.js} +8 -8
  249. package/dist/{qr-cli-BeHlC33g.js → qr-cli-Cx7DYTSk.js} +5 -5
  250. package/dist/{qr-cli-zto9YWnY.js → qr-cli-hPIeUYAT.js} +11 -11
  251. package/dist/{redact-identifier-B1VHIbnd.js → redact-identifier-Cm1VfV7E.js} +4 -4
  252. package/dist/{register.agent-CNhg2KUt.js → register.agent-CCKcgAXs.js} +91 -91
  253. package/dist/{register.agent-COv5OPLQ.js → register.agent-DZuxoC0a.js} +71 -71
  254. package/dist/register.configure-CJErdFO_.js +129 -0
  255. package/dist/register.configure-JT8T7HO5.js +125 -0
  256. package/dist/{register.maintenance-BAK-DiQY.js → register.maintenance-CKsv0lok.js} +70 -70
  257. package/dist/{register.maintenance-B_slxJa6.js → register.maintenance-DDzKUGYJ.js} +98 -98
  258. package/dist/{register.message-Bbtej3vy.js → register.message-CpOXi1rz.js} +74 -74
  259. package/dist/{register.message-CCBmn5ja.js → register.message-_bfhetTg.js} +55 -55
  260. package/dist/{register.onboard-Cu2KnArg.js → register.onboard-BHtTh0b_.js} +42 -42
  261. package/dist/{register.onboard-B3jO_Goy.js → register.onboard-CkIM3hU7.js} +24 -24
  262. package/dist/{register.setup-Ca6zdWpf.js → register.setup-CLhdFQHW.js} +42 -42
  263. package/dist/{register.setup-CYSISTDO.js → register.setup-CYtYDKMU.js} +27 -27
  264. package/dist/{register.status-health-sessions-D9p0ClqJ.js → register.status-health-sessions-DZnebsxZ.js} +60 -60
  265. package/dist/{register.status-health-sessions-CGbg9k6d.js → register.status-health-sessions-DmX0DLAt.js} +39 -39
  266. package/dist/{register.subclis-loifbhVx.js → register.subclis-CnDo2jzv.js} +29 -29
  267. package/dist/{registry-Sbac4a4z.js → registry-DKJLAPDB.js} +2 -2
  268. package/dist/{replies-PetyGT0p.js → replies-B2O2eRh6.js} +3 -3
  269. package/dist/{replies-Dj640LxQ.js → replies-DIHkSwoW.js} +2 -2
  270. package/dist/{reply-prefix-CXsO5E1Z.js → reply-prefix-B7pYEiW_.js} +1 -1
  271. package/dist/{reply-prefix-DKeEUCUp.js → reply-prefix-BOdARKaY.js} +1 -1
  272. package/dist/{resolve-route-8JoEBwi6.js → resolve-route-CRWE36h5.js} +4 -4
  273. package/dist/{resolve-route-BcYnh5es.js → resolve-route-DNKcB7Q9.js} +1 -1
  274. package/dist/{routes-CJ4en0jL.js → routes-BMShi_eY.js} +7 -7
  275. package/dist/{routes-B5y-oAKp.js → routes-Cio8is5Y.js} +5 -5
  276. package/dist/{rpc-qWm1bRo5.js → rpc-CEhoSTGo.js} +1 -1
  277. package/dist/{rpc-ElDiKzq4.js → rpc-D0Ldc6Hv.js} +3 -3
  278. package/dist/{run-main-B7Ria3zD.js → run-main-BIRbWKyA.js} +73 -73
  279. package/dist/{runtime-guard-oeRbIq84.js → runtime-guard-BZ3_1QqS.js} +1 -1
  280. package/dist/{sandbox-BJgHc4Vu.js → sandbox-B4RfQ7k1.js} +9 -9
  281. package/dist/{sandbox-C8Gh5iJW.js → sandbox-C-UeHmuJ.js} +11 -11
  282. package/dist/{sandbox-cli-CSudrHYL.js → sandbox-cli-B43FqqPT.js} +17 -17
  283. package/dist/{sandbox-cli-DkMmnojU.js → sandbox-cli-CNAPNXJ4.js} +29 -29
  284. package/dist/{security-cli-pLoqKkfb.js → security-cli-BSd8_Gsq.js} +38 -38
  285. package/dist/{security-cli-B2lCR2xX.js → security-cli-DDM0Z6IW.js} +27 -27
  286. package/dist/{send-DuYvWRLE.js → send-DSK6O8SC.js} +9 -9
  287. package/dist/{send-CY9na-Jw.js → send-EluKytgO.js} +3 -3
  288. package/dist/{server-context-DdWWaDf6.js → server-context-CDTuNR-O.js} +5 -5
  289. package/dist/{server-context-CJFU_WfI.js → server-context-DFO6o83F.js} +8 -8
  290. package/dist/{server-methods-Dk_EnINI.js → server-methods-Dz6NGEg3.js} +35 -59
  291. package/dist/{server-methods-RhVqtIqB.js → server-methods-vp5zi6v5.js} +41 -65
  292. package/dist/{server-node-events-BHegSgG9.js → server-node-events-4ufB_olv.js} +55 -55
  293. package/dist/{server-node-events-UQx561GA.js → server-node-events-B7UtUhkC.js} +74 -74
  294. package/dist/{service-BCu0FBzN.js → service-AP9pR9R5.js} +1 -1
  295. package/dist/{session-cost-usage-5VmVPhKy.js → session-cost-usage-Cj3vd7lZ.js} +1 -1
  296. package/dist/{session-cost-usage-XhPrxXSs.js → session-cost-usage-DYcv40ss.js} +1 -1
  297. package/dist/{session-utils-DFJztVrF.js → session-utils-CgGDr4eh.js} +12 -12
  298. package/dist/{session-utils-CAVPV2Hh.js → session-utils-D1VcHni_.js} +7 -7
  299. package/dist/{sessions-CqLQkkWg.js → sessions-BNEDanZO.js} +4 -4
  300. package/dist/{sessions-BsGGoTdl.js → sessions-Dh88Kqd6.js} +9 -9
  301. package/dist/{sessions-BDM9kNY0.js → sessions-iLfSd6VD.js} +5 -5
  302. package/dist/{shared-CpwtQRJB.js → shared-CIeW3aWF.js} +4 -4
  303. package/dist/{shared-D7tsGdxc.js → shared-DP6YX7_w.js} +1 -1
  304. package/dist/{shared-B7nP44vU.js → shared-DmYHvtn2.js} +2 -2
  305. package/dist/{shared-CbUpEKXt.js → shared-_wwqvx84.js} +3 -3
  306. package/dist/{skill-commands-B45w-suH.js → skill-commands-5QB5E8bv.js} +4 -4
  307. package/dist/{skill-commands-CRQniaHy.js → skill-commands-CcCCVblU.js} +4 -4
  308. package/dist/{skills-CTcjFd_F.js → skills-BP6p7GnN.js} +3 -3
  309. package/dist/{skills-haW9gU7e.js → skills-Bmjf5nFv.js} +3 -3
  310. package/dist/{skills-cli-9Mlb7VRg.js → skills-cli-BJDvUT_e.js} +13 -13
  311. package/dist/{skills-cli-CV_42wby.js → skills-cli-Byp9MfZh.js} +17 -17
  312. package/dist/{skills-install-B4JPO_Np.js → skills-install-BB27sD4d.js} +4 -4
  313. package/dist/{skills-install-D5ikt72d.js → skills-install-BzqoHn0x.js} +3 -3
  314. package/dist/{skills-remote-BW2GvG2l.js → skills-remote-CqwR3Zvp.js} +5 -5
  315. package/dist/{skills-remote-BASG1Doo.js → skills-remote-DHfuS68n.js} +4 -4
  316. package/dist/{skills-status-1iVfuVIG.js → skills-status-01KNlWUS.js} +3 -3
  317. package/dist/{skills-status-C9lLJu0B.js → skills-status-BNDqwHkP.js} +3 -3
  318. package/dist/{sqlite-DL_ZWVN-.js → sqlite-DBEvS-Ne.js} +2 -2
  319. package/dist/{sqlite-67BqaVPd.js → sqlite-l3CZYU6t.js} +1 -1
  320. package/dist/{status-CrddsMfu.js → status-B0HecH1s.js} +4 -4
  321. package/dist/{status-D5RhVO0A.js → status-BD8gFYKH.js} +18 -18
  322. package/dist/{status-DPu7qNXE.js → status-DEXnB1sw.js} +27 -27
  323. package/dist/{status-Bci6O3aA.js → status-MMLxoRgQ.js} +3 -3
  324. package/dist/{status.update-D5CachQ_.js → status.update-Be8PuHCh.js} +2 -2
  325. package/dist/{status.update-Dfd0eZOH.js → status.update-CB9e3eWW.js} +2 -2
  326. package/dist/{subagent-registry-CsXaK_sy.js → subagent-registry-C57PFGHU.js} +61 -61
  327. package/dist/{subsystem-CHbO_DkH.js → subsystem-CtH6J8AV.js} +1 -1
  328. package/dist/{synthesis-BwcfS9jt.js → synthesis-CQdzrLFL.js} +4 -4
  329. package/dist/{synthesis-CU_MR7nV.js → synthesis-CjsIBd8X.js} +71 -71
  330. package/dist/{synthesis-dplLmFIP.js → synthesis-DSdF0vsi.js} +4 -4
  331. package/dist/{synthesis-BoZf8BeO.js → synthesis-j_kjlFo1.js} +52 -52
  332. package/dist/{system-cli-CCn-08Zm.js → system-cli-BM8KbtUc.js} +18 -18
  333. package/dist/{system-cli-D5FffFX5.js → system-cli-CQFH_HwX.js} +10 -10
  334. package/dist/{systemd-bkj5giUQ.js → systemd-9LEEqibe.js} +2 -2
  335. package/dist/{systemd-hints-UeG2BDXq.js → systemd-hints-A1W3AdVo.js} +3 -3
  336. package/dist/{systemd-hints-CufcSfMk.js → systemd-hints-BejQ6J2Y.js} +2 -2
  337. package/dist/{systemd-linger-DVkUgWAi.js → systemd-linger-PqG8iGCt.js} +2 -2
  338. package/dist/{table-Sfrx6RZ-.js → table-CSEp22Mk.js} +1 -1
  339. package/dist/{table-B4DunWtf.js → table-DkAQzCOR.js} +2 -2
  340. package/dist/{tailscale-G_tEEN9T.js → tailscale-D7dC-5EX.js} +3 -3
  341. package/dist/{tokens-BdVB8KXo.js → tokens-BKbemuIk.js} +1 -1
  342. package/dist/{tokens-h4i8ww8n.js → tokens-K3kGchJA.js} +1 -1
  343. package/dist/{tool-display-BngPYwnR.js → tool-display-Dr6VaTg5.js} +1 -1
  344. package/dist/{tool-display-DccYrlOh.js → tool-display-wSdT0Ynz.js} +1 -1
  345. package/dist/{tool-loop-detection-ckNnHN4a.js → tool-loop-detection-CLDr_JBu.js} +1 -1
  346. package/dist/{tool-loop-detection-DldKffR8.js → tool-loop-detection-CSSq5kkt.js} +4 -4
  347. package/dist/{trash-S6FbJcDo.js → trash-BjVrPcAx.js} +1 -1
  348. package/dist/{tui-DZ8gksSZ.js → tui-D0j61PXx.js} +8 -8
  349. package/dist/{tui-DroW8IOb.js → tui-DFuScHlA.js} +10 -10
  350. package/dist/{tui-cli-CyBJYh9u.js → tui-cli-25xTveHh.js} +24 -24
  351. package/dist/{tui-cli-1SpmbQMM.js → tui-cli-C3dXNtPo.js} +36 -36
  352. package/dist/{unified-runner-BFLLzEHE.js → unified-runner-BNt7TQKM.js} +10 -13
  353. package/dist/{unified-runner-CSPkKZHX.js → unified-runner-DCiPB--z.js} +73 -73
  354. package/dist/{update-BITFZPr2.js → update-C1rkPV1C.js} +3 -3
  355. package/dist/{update-OkPZ3jjl.js → update-CjZgU686.js} +3 -3
  356. package/dist/{update-check-CMbKkelk.js → update-check-CZxZhEXr.js} +2 -2
  357. package/dist/{update-cli-Dh5dvdv-.js → update-cli-CWufRpkr.js} +104 -104
  358. package/dist/{update-cli-yW6Xl6fs.js → update-cli-Dl_QbjXc.js} +77 -77
  359. package/dist/{update-runner-BI8ZSR1b.js → update-runner-Dq5UYQbo.js} +5 -5
  360. package/dist/{update-runner-CIgLduhH.js → update-runner-ENJw0Mco.js} +2 -2
  361. package/dist/{utils-CTPsqyE_.js → utils-BU8jVQFM.js} +1 -1
  362. package/dist/{webhooks-cli-Cwhu9vyD.js → webhooks-cli-Clx8DGfA.js} +14 -14
  363. package/dist/{webhooks-cli-4bmyKzwb.js → webhooks-cli-UfO_WffC.js} +11 -11
  364. package/dist/{widearea-dns-BZ7fV_kq.js → widearea-dns-C5NqCQ3L.js} +1 -1
  365. package/dist/{widearea-dns-D9KXb2gb.js → widearea-dns-drOINmDM.js} +1 -1
  366. package/dist/{with-timeout-D_FOTx48.js → with-timeout-BE7lxhxW.js} +2 -2
  367. package/dist/{with-timeout-bWr6yBeX.js → with-timeout-BcL6qAbd.js} +2 -2
  368. package/dist/{workspace-DxscDsm6.js → workspace-B3sO7QlN.js} +2 -2
  369. package/dist/{workspace-BHDa_VCi.js → workspace-Bb1HX2I0.js} +1 -1
  370. package/dist/{workspace-dirs-2xcWGse3.js → workspace-dirs-23IYtZj2.js} +1 -1
  371. package/dist/{workspace-dirs-aYEM1rQE.js → workspace-dirs-D5OnUmvw.js} +1 -1
  372. package/extensions/memory-core/node_modules/.bin/symi +0 -0
  373. package/extensions/msteams/node_modules/.bin/symi +0 -0
  374. package/extensions/outlook/node_modules/.bin/symi +0 -0
  375. package/extensions/slack/node_modules/.bin/symi +0 -0
  376. package/package.json +108 -79
  377. package/dist/cli-CK62Eh_9.js +0 -128
  378. package/dist/control-ui/css/revert-red-theme.md +0 -141
  379. package/dist/control-ui/css/style.css +0 -5843
  380. package/dist/control-ui/css/style.css.backup-2026-03-03-162525 +0 -3546
  381. package/dist/control-ui/css/style.css.backup-before-red-2026-03-03-162525 +0 -3546
  382. package/dist/control-ui/css/style.css.backup-before-red-theme-2026-03-03-162530 +0 -3546
  383. package/dist/control-ui/css/style.css.pre-2row +0 -2165
  384. package/dist/control-ui/css/style.css.pre-brand +0 -1776
  385. package/dist/control-ui/css/style.css.pre-history +0 -1974
  386. package/dist/control-ui/css/style.css.pre-nav +0 -2264
  387. package/dist/control-ui/css/style.css.pre-newsession +0 -1898
  388. package/dist/control-ui/css/style.css.pre-queue +0 -2195
  389. package/dist/control-ui/css/style.css.pre-red-prompt +0 -2524
  390. package/dist/control-ui/css/style.css.pre-stop +0 -2239
  391. package/dist/control-ui/css/style.css.pre-textarea +0 -2184
  392. package/dist/control-ui/css/style.css.pre-watchdog +0 -1848
  393. package/dist/control-ui/css/style.css.red-theme +0 -2999
  394. package/dist/control-ui/index.html +0 -1042
  395. package/dist/control-ui/js/app.js +0 -1304
  396. package/dist/control-ui/js/app.js.pre-2row +0 -463
  397. package/dist/control-ui/js/app.js.pre-heartbeat-filter +0 -595
  398. package/dist/control-ui/js/app.js.pre-newsession +0 -408
  399. package/dist/control-ui/js/app.js.pre-queue +0 -476
  400. package/dist/control-ui/js/app.js.pre-stop +0 -564
  401. package/dist/control-ui/js/app.js.pre-textarea +0 -467
  402. package/dist/control-ui/js/app.js.pre-watchdog +0 -293
  403. package/dist/control-ui/js/connections.js +0 -438
  404. package/dist/control-ui/js/gateway.js +0 -233
  405. package/dist/control-ui/js/gateway.js.pre-stop +0 -110
  406. package/dist/control-ui/js/history.js +0 -732
  407. package/dist/control-ui/js/logs.js +0 -238
  408. package/dist/control-ui/js/menu.js +0 -230
  409. package/dist/control-ui/js/menu.js.pre-nav +0 -66
  410. package/dist/control-ui/js/metrics.js +0 -53
  411. package/dist/control-ui/js/models.js +0 -138
  412. package/dist/control-ui/js/render.js +0 -882
  413. package/dist/control-ui/js/render.test.js +0 -112
  414. package/dist/control-ui/js/scheduling.js +0 -461
  415. package/dist/control-ui/js/settings.js +0 -909
  416. package/dist/control-ui/js/slash-autocomplete.js +0 -168
  417. package/dist/control-ui/js/subagents.js +0 -560
  418. package/dist/control-ui/js/utils.js +0 -29
  419. package/dist/control-ui/vendor/highlight.min.js +0 -2518
  420. package/dist/control-ui/vendor/marked.min.js +0 -69
  421. package/dist/register.configure-RhKVlfWH.js +0 -125
  422. package/dist/register.configure-q33027ym.js +0 -129
@@ -1,1304 +0,0 @@
1
- // ── Symi UI — Live Gateway App ────────────────────────────────────────
2
-
3
- const responseArea = document.getElementById("response-area");
4
- const promptInput = document.getElementById("prompt-input");
5
- const sendBtn = document.getElementById("send-btn");
6
- const newSessionBtn = document.getElementById("new-session-btn");
7
- const stopBtn = document.getElementById("stop-btn");
8
-
9
- let isStreaming = false;
10
- let workingActive = false;
11
- let activeSubagentCount = 0;
12
- let currentRunId = null;
13
- let streamBubble = null;
14
- let streamContent = null;
15
- let streamStart = 0;
16
-
17
- // ── Feed cache (localStorage fallback) ──────────────────────────
18
- const FEED_CACHE_KEY = "symi:feed-cache";
19
- const FEED_CACHE_MAX = 200; // max messages to cache
20
-
21
- const feedCache = {
22
- save(messages) {
23
- try {
24
- const trimmed = Array.isArray(messages) ? messages.slice(-FEED_CACHE_MAX) : [];
25
- localStorage.setItem(FEED_CACHE_KEY, JSON.stringify(trimmed));
26
- } catch {
27
- // localStorage full or unavailable — ignore
28
- }
29
- },
30
- load() {
31
- try {
32
- const raw = localStorage.getItem(FEED_CACHE_KEY);
33
- return raw ? JSON.parse(raw) : [];
34
- } catch {
35
- return [];
36
- }
37
- },
38
- append(message) {
39
- try {
40
- const cached = this.load();
41
- cached.push(message);
42
- this.save(cached);
43
- } catch {
44
- // ignore
45
- }
46
- },
47
- clear() {
48
- try {
49
- localStorage.removeItem(FEED_CACHE_KEY);
50
- } catch {
51
- // ignore
52
- }
53
- },
54
- };
55
-
56
- // ── Lazy-loading pagination state ────────────────────────────────
57
- let historyStartIndex = 0; // index of first loaded message in full transcript
58
- let historyHasMore = false; // server says there are older messages
59
- let isLoadingMore = false; // guard against concurrent fetches
60
-
61
- // ── Prompt queue ──────────────────────────────────────────────────
62
- let chatQueue = []; // [{id, text}]
63
-
64
- // ── Watchdog + elapsed timer state ────────────────────────────────
65
- let watchdogTimer = null; // fires if no activity for WATCHDOG_MS
66
- let elapsedTimer = null; // ticks every second to show run duration
67
- let activityStart = 0; // timestamp of when current run began
68
- let elapsedBaseText = ""; // base sub-text for the elapsed display
69
- let WATCHDOG_MS = 300000; // 300 seconds of silence → failure (profile-overridable)
70
- // Track time of last upstream agent/chat event so the elapsed-timer tick can
71
- // surface a "still reasoning" hint when reasoning runs silently for >5s
72
- // (some models batch reasoning without streaming deltas; the orb timer alone
73
- // looks frozen even though work is happening).
74
- let lastEventTs = 0;
75
- const EXTENDED_SILENCE_MS = 5000;
76
-
77
- // ── Model profile state (updated via "profile" gateway event) ────
78
- let activeProfile = null;
79
- // NOTE: Client-side dedup removed — server-side per-client seq tracking in
80
- // glass-ui-ws.ts prevents duplicate broadcasts. See Phase 5 of v3 plan.
81
-
82
- // ── Utility ───────────────────────────────────────────────────────
83
- const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
84
- function escapeHtml(t) {
85
- return t.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
86
- }
87
- // Alias used by panel scripts (subagents.js, connections.js, scheduling.js)
88
- window.escHtml = escapeHtml;
89
-
90
- // ── Status indicator (top-right of response area) ─────────────────
91
- const statusEl = document.createElement("div");
92
- statusEl.className = "conn-status";
93
- statusEl.innerHTML =
94
- '<span class="conn-dot dot-yellow pulse"></span><span class="conn-label">connecting…</span>';
95
- responseArea.before(statusEl);
96
-
97
- function setStatus(state) {
98
- // 'connecting' | 'online' | 'offline'
99
- const dot = statusEl.querySelector(".conn-dot");
100
- const label = statusEl.querySelector(".conn-label");
101
- dot.className = `conn-dot ${state === "online" ? "dot-green pulse" : state === "offline" ? "dot-red" : "dot-yellow pulse"}`;
102
- label.textContent =
103
- state === "online" ? "live" : state === "offline" ? "disconnected" : "connecting…";
104
- }
105
-
106
- // ── Render helpers ─────────────────────────────────────────────────
107
- function addUserMessage(text) {
108
- const msg = document.createElement("div");
109
- msg.className = "message user-msg";
110
- msg.innerHTML = `<div class="bubble">${escapeHtml(text)}</div><div class="message-clearfix"></div>`;
111
- responseArea.appendChild(msg);
112
- msg.scrollIntoView({ behavior: "smooth", block: "end" });
113
- }
114
-
115
- // ── Thinking bubble ────────────────────────────────────────────────
116
- function createThinkingBubble() {
117
- const msg = document.createElement("div");
118
- msg.className = "message symi-msg thinking-msg";
119
- msg.innerHTML = `
120
- <div class="bubble thinking-bubble">
121
- <div class="think-header">
122
- <span class="think-badge">◈ PROCESSING</span>
123
- <span class="think-dots"><span>.</span><span>.</span><span>.</span></span>
124
- </div>
125
- <div class="think-bar-wrap"><div class="think-bar"></div></div>
126
- </div>
127
- <div class="message-clearfix"></div>
128
- `;
129
- responseArea.appendChild(msg);
130
- msg.scrollIntoView({ behavior: "smooth", block: "end" });
131
- return msg;
132
- }
133
-
134
- // ── Live thinking → Reasoning panel ───────────────────────────────
135
- // Buffers thinking deltas per run and flushes to the Reasoning panel as
136
- // a single entry on thinking_end. Keeps the main response bubble clean
137
- // (it only receives real text deltas) while surfacing the reasoning in
138
- // the dedicated panel.
139
- const thinkingBuffers = new Map();
140
-
141
- function handleThinkingAgentEvent(evt) {
142
- if (!evt || !evt.data) {
143
- return;
144
- }
145
- const runId = evt.runId ?? "live";
146
- const phase = evt.data.phase;
147
- const delta = typeof evt.data.delta === "string" ? evt.data.delta : "";
148
- const content = typeof evt.data.content === "string" ? evt.data.content : "";
149
-
150
- if (phase === "thinking_start") {
151
- thinkingBuffers.set(runId, "");
152
- return;
153
- }
154
- if (phase === "thinking_delta") {
155
- // Prefer appending deltas; fall back to the full content field if the
156
- // provider only sends cumulative content.
157
- const prev = thinkingBuffers.get(runId) ?? "";
158
- thinkingBuffers.set(runId, delta ? prev + delta : content || prev);
159
- return;
160
- }
161
- if (phase === "thinking_end") {
162
- const buffered = (thinkingBuffers.get(runId) ?? "").trim();
163
- thinkingBuffers.delete(runId);
164
- if (buffered && typeof window.appendToReasoningPanel === "function") {
165
- window.appendToReasoningPanel({ type: "thinking", thinking: buffered });
166
- }
167
- }
168
- }
169
-
170
- // ── Stream bubble lifecycle ────────────────────────────────────────
171
- function openStreamBubble() {
172
- streamStart = Date.now();
173
- const msg = document.createElement("div");
174
- msg.className = "message symi-msg stream-msg";
175
- msg.innerHTML = `<div class="bubble stream-bubble streaming"><div class="bubble-content"></div></div><div class="message-clearfix"></div>`;
176
- responseArea.appendChild(msg);
177
- streamBubble = msg.querySelector(".stream-bubble");
178
- streamContent = msg.querySelector(".bubble-content");
179
- msg.scrollIntoView({ behavior: "smooth", block: "end" });
180
- return msg;
181
- }
182
-
183
- function updateStream(text) {
184
- if (!streamContent) {
185
- return;
186
- }
187
- streamContent.textContent += text;
188
- responseArea.scrollTop = responseArea.scrollHeight;
189
- }
190
-
191
- function closeStreamBubble(model) {
192
- if (!streamBubble) {
193
- return;
194
- }
195
- streamBubble.classList.remove("streaming");
196
- streamBubble.classList.add("done");
197
-
198
- // Apply full markdown rendering to the final text. Build the replacement
199
- // BEFORE wiping the existing content so a failing/empty render can't leave
200
- // the bubble visibly blank ("response appeared then disappeared").
201
- const rawText = streamContent?.textContent ?? "";
202
- if (streamContent && rawText) {
203
- let textBlock = null;
204
- try {
205
- textBlock = renderBlock({ type: "text", text: rawText });
206
- } catch (err) {
207
- console.warn("[app] renderBlock failed during closeStreamBubble:", err);
208
- }
209
- if (textBlock && textBlock.textContent.trim()) {
210
- streamContent.innerHTML = "";
211
- streamContent.appendChild(textBlock);
212
- window.applyHighlighting(streamContent);
213
- }
214
- // else: preserve original textContent — the plain stream is better than
215
- // an empty bubble.
216
- }
217
-
218
- const elapsed = Date.now() - streamStart;
219
- const chars = Math.round(rawText.length / 4);
220
-
221
- // Add copy button
222
- const copyBtn = document.createElement("button");
223
- copyBtn.className = "msg-copy-btn msg-copy-visible";
224
- copyBtn.title = "Copy";
225
- copyBtn.addEventListener("click", function () {
226
- window.copyMessage(this);
227
- });
228
- copyBtn.innerHTML = `<svg width="12" height="12" viewBox="0 0 24 24" fill="none">
229
- <rect x="9" y="9" width="13" height="13" rx="2" stroke="currentColor" stroke-width="2"/>
230
- <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" stroke="currentColor" stroke-width="2"/>
231
- </svg>`;
232
- streamBubble.appendChild(copyBtn);
233
-
234
- const footer = document.createElement("div");
235
- footer.className = "telemetry";
236
- footer.innerHTML = `
237
- <span class="tele-item">✦ ${model.includes("/") ? model.split("/").slice(1).join("/") : model}</span>
238
- <span class="tele-sep">·</span>
239
- <span class="tele-item">${chars} tokens</span>
240
- <span class="tele-sep">·</span>
241
- <span class="tele-item">${elapsed}ms</span>
242
- `;
243
- streamBubble.appendChild(footer);
244
- requestAnimationFrame(() => {
245
- footer.classList.add("tele-visible");
246
- // Scroll to bottom immediately after markdown + footer are in the DOM
247
- responseArea.scrollTop = responseArea.scrollHeight;
248
- });
249
-
250
- // Second scroll after the fit-content width transition finishes (0.3s)
251
- setTimeout(() => {
252
- responseArea.scrollTop = responseArea.scrollHeight;
253
- }, 350);
254
-
255
- streamBubble = null;
256
- streamContent = null;
257
- }
258
-
259
- // ── Elapsed timer ─────────────────────────────────────────────────
260
- function startElapsedTimer(baseText) {
261
- stopElapsedTimer();
262
- activityStart = Date.now();
263
- elapsedBaseText = baseText;
264
- lastEventTs = activityStart;
265
- elapsedTimer = setInterval(() => {
266
- const secs = Math.floor((Date.now() - activityStart) / 1000);
267
- const m = Math.floor(secs / 60);
268
- const s = String(secs % 60).padStart(2, "0");
269
- const silentMs = Date.now() - lastEventTs;
270
- const showHint = elapsedBaseText.startsWith("Reasoning") && silentMs > EXTENDED_SILENCE_MS;
271
- const hint = showHint ? " (still reasoning)" : "";
272
- if (asoSub) {
273
- asoSub.textContent = `${elapsedBaseText}${hint} ${m}:${s}`;
274
- }
275
- }, 1000);
276
- }
277
-
278
- function stopElapsedTimer() {
279
- if (elapsedTimer) {
280
- clearInterval(elapsedTimer);
281
- elapsedTimer = null;
282
- }
283
- lastEventTs = 0;
284
- }
285
-
286
- // ── Watchdog ───────────────────────────────────────────────────────
287
- function armWatchdog() {
288
- clearWatchdog();
289
- watchdogTimer = setTimeout(() => handleRunFailure("timeout"), WATCHDOG_MS);
290
- }
291
-
292
- function clearWatchdog() {
293
- if (watchdogTimer) {
294
- clearTimeout(watchdogTimer);
295
- watchdogTimer = null;
296
- }
297
- }
298
-
299
- // ── Unified run failure handler ────────────────────────────────────
300
- // Called when: watchdog fires, gateway disconnects mid-run, or server
301
- // sends an explicit error event. Cleans up all state and shows the user
302
- // a clear error message + ERROR orb state.
303
- function handleRunFailure(reason) {
304
- // Stop timers immediately
305
- stopElapsedTimer();
306
- clearWatchdog();
307
- if (typeof window.closeLiveThinking === "function") {
308
- window.closeLiveThinking();
309
- }
310
-
311
- // Clean up any in-flight UI elements
312
- if (thinkingEl) {
313
- thinkingEl.remove();
314
- thinkingEl = null;
315
- }
316
- if (streamBubble) {
317
- // Don't render markdown on a partial/failed response — just mark it failed
318
- streamBubble.classList.remove("streaming");
319
- streamBubble.classList.add("done", "stream-failed");
320
- streamBubble = null;
321
- streamContent = null;
322
- }
323
-
324
- // Human-readable reason labels
325
- const labels = {
326
- timeout: `No response received after ${WATCHDOG_MS / 1000}s — the agent may still be running in the background`,
327
- disconnected: "Connection lost mid-run — gateway disconnected",
328
- };
329
- const label = labels[reason] || reason;
330
-
331
- // Inject error bubble into the feed
332
- const errEl = document.createElement("div");
333
- errEl.className = "message symi-msg";
334
- errEl.innerHTML = `
335
- <div class="bubble stream-bubble done run-error-bubble">
336
- <div class="run-error-icon">⚠</div>
337
- <div class="bubble-content run-error-text">${escapeHtml(label)}</div>
338
- </div>
339
- <div class="message-clearfix"></div>
340
- `;
341
- responseArea.appendChild(errEl);
342
- requestAnimationFrame(() => {
343
- responseArea.scrollTop = responseArea.scrollHeight;
344
- });
345
-
346
- // Show ERROR state on orb, then reset input
347
- setAgentStatus("error");
348
- hideWorkingIndicator();
349
- isStreaming = false;
350
- currentRunId = null;
351
- stopBtn.style.opacity = "";
352
- stopBtn.disabled = false;
353
- enableInput();
354
- updateQueueBtn(); // keep queue button visible if items remain
355
- }
356
-
357
- // ── Render history (on first connect) ─────────────────────────────
358
- function renderHistory(messages) {
359
- const isEmpty = !messages || messages.length === 0;
360
- const hasExistingContent = responseArea.querySelectorAll(".message").length > 0;
361
-
362
- // Guard: if server sends empty history but the DOM already has messages,
363
- // keep the existing feed — prevents blank screen on transient failures.
364
- if (isEmpty && hasExistingContent) {
365
- return;
366
- }
367
-
368
- // Fallback: server is empty and DOM is empty — try localStorage cache
369
- if (isEmpty) {
370
- const cached = feedCache.load();
371
- if (cached.length > 0) {
372
- messages = cached;
373
- } else {
374
- return; // nothing to render anywhere
375
- }
376
- } else {
377
- // Server sent real history — cache it for future fallback
378
- feedCache.save(messages);
379
- }
380
-
381
- // Clear reasoning panel in sync with the feed — prevents double-entries on reconnect
382
- if (typeof window.clearReasoningPanel === "function") {
383
- window.clearReasoningPanel();
384
- }
385
- responseArea.innerHTML = "";
386
- responseArea.prepend(loadMoreSentinel);
387
- for (const m of messages) {
388
- if (!m || !m.role) {
389
- continue;
390
- }
391
-
392
- // Route toolResult messages to the Reasoning Panel — they're tool output, not user-facing
393
- if (m.role === "toolResult" || m.role === "tool") {
394
- const content = Array.isArray(m.content) ? m.content : [];
395
- const text = content
396
- .map((b) => b.text ?? "")
397
- .join("\n")
398
- .trim();
399
- if (text && typeof window.appendToReasoningPanel === "function") {
400
- window.appendToReasoningPanel({
401
- type: "tool_result",
402
- content: m.content,
403
- is_error: m.isError === true,
404
- });
405
- }
406
- continue;
407
- }
408
-
409
- // Skip system/compaction messages entirely
410
- if (m.role === "system") {
411
- continue;
412
- }
413
-
414
- // Route plugin context user messages to Reasoning Panel
415
- if (m.role === "user") {
416
- const txt = Array.isArray(m.content)
417
- ? m.content
418
- .filter((b) => b.type === "text")
419
- .map((b) => b.text ?? "")
420
- .join("")
421
- .trim()
422
- : extractText(m.content).trim();
423
- if (/^\[.+\]\s+(Not connected|Connected as)\b/i.test(txt)) {
424
- if (typeof window.appendToReasoningPanel === "function") {
425
- window.appendToReasoningPanel({ type: "text", text: "[Plugin context]" });
426
- }
427
- continue;
428
- }
429
- if (/^Review your response against the original user request/i.test(txt)) {
430
- if (typeof window.appendToReasoningPanel === "function") {
431
- window.appendToReasoningPanel({ type: "text", text: "[Post-generation verification]" });
432
- }
433
- continue;
434
- }
435
- }
436
-
437
- const hasContent = Array.isArray(m.content)
438
- ? m.content.some((b) => b.type === "text" && (b.text ?? "").trim())
439
- : extractText(m.content).trim();
440
- if (!hasContent) {
441
- continue;
442
- }
443
-
444
- const el = window.renderMessage(m);
445
- if (!el) {
446
- continue;
447
- }
448
- responseArea.appendChild(el);
449
- window.applyHighlighting(el);
450
- }
451
-
452
- // Update sentinel visibility
453
- updateLoadMoreSentinel();
454
-
455
- // Scroll to very bottom after history renders
456
- requestAnimationFrame(() => {
457
- responseArea.scrollTop = responseArea.scrollHeight;
458
- });
459
- }
460
-
461
- // ── Lazy-loading: sentinel + IntersectionObserver ─────────────────
462
- const loadMoreSentinel = document.createElement("div");
463
- loadMoreSentinel.className = "load-more-sentinel";
464
- loadMoreSentinel.id = "load-more-sentinel";
465
- loadMoreSentinel.textContent = "Loading older messages…";
466
- loadMoreSentinel.style.display = "none";
467
- responseArea.prepend(loadMoreSentinel);
468
-
469
- function updateLoadMoreSentinel() {
470
- loadMoreSentinel.style.display = historyHasMore ? "" : "none";
471
- }
472
-
473
- const loadMoreObserver = new IntersectionObserver(
474
- (entries) => {
475
- if (entries[0]?.isIntersecting && historyHasMore && !isLoadingMore) {
476
- void loadMoreHistory();
477
- }
478
- },
479
- { root: responseArea, threshold: 0.1 },
480
- );
481
- loadMoreObserver.observe(loadMoreSentinel);
482
-
483
- async function loadMoreHistory() {
484
- if (isLoadingMore || !historyHasMore || historyStartIndex <= 0) {
485
- return;
486
- }
487
- isLoadingMore = true;
488
- loadMoreSentinel.textContent = "Loading older messages…";
489
-
490
- try {
491
- const result = await gateway.rpc("chat.history", {
492
- sessionKey: window.SESSION_KEY,
493
- limit: 100,
494
- before: historyStartIndex,
495
- });
496
-
497
- const msgs = result.messages ?? [];
498
- historyStartIndex = result.startIndex ?? 0;
499
- historyHasMore = result.hasMore ?? false;
500
-
501
- if (msgs.length === 0) {
502
- historyHasMore = false;
503
- updateLoadMoreSentinel();
504
- return;
505
- }
506
-
507
- // Remember scroll position so we can restore it after prepending
508
- const prevScrollHeight = responseArea.scrollHeight;
509
- const prevScrollTop = responseArea.scrollTop;
510
-
511
- // Build fragment of older messages (reuse same filtering as renderHistory)
512
- const frag = document.createDocumentFragment();
513
- for (const m of msgs) {
514
- if (!m || !m.role) {
515
- continue;
516
- }
517
- if (m.role === "toolResult" || m.role === "tool") {
518
- const content = Array.isArray(m.content) ? m.content : [];
519
- const text = content
520
- .map((b) => b.text ?? "")
521
- .join("\n")
522
- .trim();
523
- if (text && typeof window.appendToReasoningPanel === "function") {
524
- window.appendToReasoningPanel({
525
- type: "tool_result",
526
- content: m.content,
527
- is_error: m.isError === true,
528
- });
529
- }
530
- continue;
531
- }
532
- if (m.role === "system") {
533
- continue;
534
- }
535
-
536
- // Route plugin context & verification user messages to Reasoning Panel
537
- if (m.role === "user") {
538
- const txt = Array.isArray(m.content)
539
- ? m.content
540
- .filter((b) => b.type === "text")
541
- .map((b) => b.text ?? "")
542
- .join("")
543
- .trim()
544
- : extractText(m.content).trim();
545
- if (/^Review your response against the original user request/i.test(txt)) {
546
- if (typeof window.appendToReasoningPanel === "function") {
547
- window.appendToReasoningPanel({ type: "text", text: "[Post-generation verification]" });
548
- }
549
- continue;
550
- }
551
- }
552
-
553
- const hasContent = Array.isArray(m.content)
554
- ? m.content.some((b) => b.type === "text" && (b.text ?? "").trim())
555
- : extractText(m.content).trim();
556
- if (!hasContent) {
557
- continue;
558
- }
559
- const el = window.renderMessage(m);
560
- if (!el) {
561
- continue;
562
- }
563
- frag.appendChild(el);
564
- window.applyHighlighting(el);
565
- }
566
-
567
- // Insert after sentinel (which stays at top)
568
- loadMoreSentinel.after(frag);
569
-
570
- // Restore scroll position so the view doesn't jump
571
- requestAnimationFrame(() => {
572
- const newScrollHeight = responseArea.scrollHeight;
573
- responseArea.scrollTop = prevScrollTop + (newScrollHeight - prevScrollHeight);
574
- });
575
-
576
- updateLoadMoreSentinel();
577
- } catch (err) {
578
- console.warn("[lazy-load] Failed to load older history:", err);
579
- loadMoreSentinel.textContent = "Failed to load — scroll up to retry";
580
- } finally {
581
- isLoadingMore = false;
582
- }
583
- }
584
-
585
- // ── Gateway event handler ──────────────────────────────────────────
586
- let thinkingEl = null;
587
-
588
- function handleGatewayEvent(event) {
589
- // Handle sub-agent lifecycle events (independent of isStreaming)
590
- if (event.event === "subagent") {
591
- const s = event.payload;
592
- if (s && s.phase === "started") {
593
- activeSubagentCount++;
594
- showWorkingIndicator();
595
- } else if (s && s.phase === "completed") {
596
- activeSubagentCount = Math.max(0, activeSubagentCount - 1);
597
- if (activeSubagentCount === 0 && !isStreaming) {
598
- hideWorkingIndicator();
599
- }
600
- }
601
- return;
602
- }
603
-
604
- // Handle agent lifecycle/tool events — these prove the agent is alive.
605
- // No isStreaming guard: agent events must be processed even before the
606
- // first text delta arrives (critical for Gemma/vLLM tool-use phases).
607
- if (event.event === "agent") {
608
- const a = event.payload;
609
- if (a) {
610
- // Cross-session filter: agent events for OTHER sessions (cron-fired
611
- // channel runs, slack/msteams inbound, scheduled jobs) must not arm the
612
- // user's watchdog. Without this guard, every background run resets the
613
- // watchdog and produces phantom "Run timed out" warnings when no
614
- // follow-up event arrives within WATCHDOG_MS.
615
- if (a.sessionKey && a.sessionKey !== window.SESSION_KEY) {
616
- return;
617
- }
618
- // Cross-run filter: late agent events from a finished run (e.g.
619
- // lifecycle:end fires after chat:final cleared currentRunId) must not
620
- // re-arm a fresh watchdog timer.
621
- if (a.runId && currentRunId && a.runId !== currentRunId) {
622
- return;
623
- }
624
- // Any agent event resets the watchdog — the agent is working
625
- armWatchdog();
626
- showWorkingIndicator();
627
- lastEventTs = Date.now();
628
-
629
- // Update the sub-label with what the agent is actually doing
630
- if (a.stream === "tool" && a.data) {
631
- if (a.data.phase === "start" && a.data.name) {
632
- elapsedBaseText = `Running tool: ${a.data.name}`;
633
- } else if (a.data.phase === "result") {
634
- elapsedBaseText = "Reasoning through request";
635
- }
636
- } else if (a.stream === "compaction" && a.data) {
637
- if (a.data.phase === "start") {
638
- elapsedBaseText = "Compacting context";
639
- } else if (a.data.phase === "end") {
640
- elapsedBaseText = "Reasoning through request";
641
- }
642
- } else if (a.stream === "thinking") {
643
- elapsedBaseText = "Reasoning";
644
- // Stream the thinking content into the Reasoning panel (bottom-left).
645
- // Deltas are buffered per run; flushed as a single entry on
646
- // thinking_end so the panel gets one entry per thinking block, not
647
- // one per token.
648
- handleThinkingAgentEvent(a);
649
- } else if (a.stream === "lifecycle" && a.data) {
650
- if (a.data.phase === "start") {
651
- elapsedBaseText = "Reasoning through request";
652
- }
653
- }
654
- }
655
- return;
656
- }
657
-
658
- if (event.event !== "chat") {
659
- return;
660
- }
661
- const p = event.payload;
662
- if (!p || p.sessionKey !== window.SESSION_KEY) {
663
- return;
664
- }
665
-
666
- if (p.runId && currentRunId && p.runId !== currentRunId) {
667
- // Cross-run chat event (e.g. cron-fired channel run, chat.injectMessage,
668
- // late event from a finished run). Not relevant to the user's active turn.
669
- return;
670
- }
671
- if (isStreaming) {
672
- // Any chat event for our session and our run proves the agent is alive —
673
- // reset watchdog.
674
- armWatchdog();
675
- lastEventTs = Date.now();
676
- }
677
-
678
- // Handle "thinking" state broadcast from gateway (agent started processing)
679
- if (p.state === "thinking") {
680
- if (p.runId && currentRunId && p.runId !== currentRunId) {
681
- return; // Cross-run thinking event
682
- }
683
- if (!isStreaming) {
684
- return; // Ignore stale thinking events
685
- }
686
- setAgentStatus("thinking");
687
- showWorkingIndicator();
688
- armWatchdog();
689
- return;
690
- }
691
-
692
- if (p.state === "delta") {
693
- // Capture runId on first delta so abort can target the exact run
694
- if (p.runId && !currentRunId) {
695
- currentRunId = p.runId;
696
- }
697
-
698
- // First delta — remove thinking bubble, open stream bubble
699
- if (thinkingEl) {
700
- thinkingEl.remove();
701
- thinkingEl = null;
702
- }
703
- if (!streamBubble) {
704
- openStreamBubble();
705
- setAgentStatus("streaming");
706
- }
707
-
708
- const text = extractText(p.message);
709
- if (text) {
710
- updateStream(text);
711
- }
712
- // Stream thinking deltas live to the Reasoning Panel
713
- const thinkingText =
714
- typeof window.extractThinkingText === "function" ? window.extractThinkingText(p.message) : "";
715
- if (thinkingText && typeof window.updateLiveThinking === "function") {
716
- window.updateLiveThinking(thinkingText);
717
- }
718
- } else if (p.state === "final") {
719
- stopElapsedTimer();
720
- clearWatchdog();
721
- if (typeof window.closeLiveThinking === "function") {
722
- window.closeLiveThinking();
723
- }
724
- // If final arrives with message content but no prior deltas (burst response),
725
- // render the full message directly instead of closing an empty stream bubble.
726
- if (!streamBubble && p.message) {
727
- const finalText = extractText(p.message?.content ?? p.message);
728
- if (finalText && finalText.trim()) {
729
- if (thinkingEl) {
730
- thinkingEl.remove();
731
- thinkingEl = null;
732
- }
733
- const rendered = window.renderMessage({
734
- role: "assistant",
735
- content: p.message.content ?? [{ type: "text", text: finalText }],
736
- timestamp: p.message.timestamp ?? Date.now(),
737
- });
738
- if (rendered) {
739
- responseArea.appendChild(rendered);
740
- window.applyHighlighting(rendered);
741
- responseArea.scrollTop = responseArea.scrollHeight;
742
- }
743
- }
744
- } else {
745
- closeStreamBubble(window.activeModelId || "unknown model");
746
- }
747
- // Cache the completed assistant message for feed persistence
748
- if (p.message) {
749
- const finalText = extractText(p.message?.content ?? p.message);
750
- if (finalText && finalText.trim()) {
751
- feedCache.append({
752
- role: "assistant",
753
- content: p.message.content ?? [{ type: "text", text: finalText }],
754
- timestamp: p.message.timestamp ?? Date.now(),
755
- });
756
- }
757
- }
758
- setAgentStatus("done");
759
- // Sync sub-agent count from server and conditionally hide working indicator
760
- if (typeof p.activeSubagentCount === "number") {
761
- activeSubagentCount = p.activeSubagentCount;
762
- }
763
- if (activeSubagentCount <= 0) {
764
- hideWorkingIndicator();
765
- }
766
- isStreaming = false;
767
- currentRunId = null;
768
- stopBtn.style.opacity = ""; // reset stop button visual state
769
- stopBtn.disabled = false;
770
- enableInput();
771
- drainQueue();
772
- } else if (p.state === "aborted") {
773
- // Clean abort (user-initiated or model decided to stop) — not an error
774
- stopElapsedTimer();
775
- clearWatchdog();
776
- if (typeof window.closeLiveThinking === "function") {
777
- window.closeLiveThinking();
778
- }
779
- if (streamBubble) {
780
- closeStreamBubble(window.activeModelId || "unknown model");
781
- }
782
- if (thinkingEl) {
783
- thinkingEl.remove();
784
- thinkingEl = null;
785
- }
786
- setAgentStatus("idle");
787
- hideWorkingIndicator();
788
- isStreaming = false;
789
- currentRunId = null;
790
- stopBtn.style.opacity = ""; // reset stop button visual state
791
- stopBtn.disabled = false;
792
- enableInput();
793
- drainQueue();
794
- } else if (p.state === "error") {
795
- // Server-reported error — route through unified failure handler.
796
- // The gateway emits the diagnostic at top-level `errorMessage`
797
- // (camelCase); fall back to nested `error.message` for forward-compat
798
- // and the legacy default if neither shape is present.
799
- const message = p.errorMessage || p.error?.message || "Server reported an error";
800
- handleRunFailure(message);
801
- }
802
- }
803
-
804
- // ── Agent Status Orb ───────────────────────────────────────────────
805
- const asoPanel = document.getElementById("agent-status-panel");
806
- const asoLabel = document.getElementById("aso-label");
807
- const asoSub = document.getElementById("aso-sub");
808
- const asoWorking = document.getElementById("aso-working");
809
- let asoDoneTimer = null;
810
-
811
- const ASO_STATES = {
812
- idle: { state: "idle", label: "STANDBY", sub: "Awaiting your prompt" },
813
- waiting: { state: "waiting", label: "WAITING", sub: "Sending to Landman\u2026" },
814
- thinking: { state: "thinking", label: "PROCESSING", sub: "Reasoning through request" },
815
- streaming: { state: "streaming", label: "RESPONDING", sub: "Generating response" },
816
- done: { state: "done", label: "COMPLETE", sub: "Response ready" },
817
- error: { state: "error", label: "FAILED", sub: "Run ended unexpectedly" },
818
- };
819
-
820
- function setAgentStatus(key) {
821
- if (!asoPanel) {
822
- return;
823
- }
824
-
825
- // Clear any pending auto-transition timers
826
- if (asoDoneTimer) {
827
- clearTimeout(asoDoneTimer);
828
- asoDoneTimer = null;
829
- }
830
-
831
- const s = ASO_STATES[key] || ASO_STATES.idle;
832
- asoPanel.dataset.state = s.state;
833
- if (asoLabel) {
834
- asoLabel.textContent = s.label;
835
- }
836
- if (asoSub) {
837
- asoSub.textContent = s.sub;
838
- }
839
-
840
- // Pulse the reasoning live-dot while agent is actively thinking/streaming
841
- const reasoningDot = document.getElementById("reasoning-live-dot");
842
- if (reasoningDot) {
843
- const active = key === "thinking" || key === "streaming" || key === "waiting";
844
- reasoningDot.classList.toggle("active", active);
845
- }
846
-
847
- // ── Elapsed timer management ──────────────────────────────────
848
- if (key === "waiting") {
849
- // For burst-style models (Gemma/vLLM), arm watchdog immediately on send
850
- // so the user gets feedback if the model never responds.
851
- if (activeProfile?.ui?.armWatchdogOnSend !== false) {
852
- armWatchdog();
853
- }
854
- startElapsedTimer("Sending to agent");
855
- } else if (key === "thinking") {
856
- // Start elapsed timer and watchdog when processing begins
857
- armWatchdog();
858
- elapsedBaseText = "Reasoning through request";
859
- } else if (key === "streaming") {
860
- // Transition from thinking → streaming: keep watchdog running (will be
861
- // reset on each delta), switch elapsed timer base text
862
- elapsedBaseText = "Generating response";
863
- } else {
864
- // Any terminal/non-active state: stop elapsed timer and watchdog
865
- stopElapsedTimer();
866
- clearWatchdog();
867
- }
868
-
869
- // ── Auto-revert timers ────────────────────────────────────────
870
- if (key === "done") {
871
- asoDoneTimer = setTimeout(() => setAgentStatus("idle"), 3000);
872
- }
873
- if (key === "error") {
874
- asoDoneTimer = setTimeout(() => setAgentStatus("idle"), 4000);
875
- }
876
- }
877
-
878
- // ── Working indicator helpers ─────────────────────────────────────
879
- function showWorkingIndicator() {
880
- if (!workingActive) {
881
- workingActive = true;
882
- if (asoWorking) {
883
- asoWorking.classList.add("active");
884
- }
885
- }
886
- }
887
- function hideWorkingIndicator() {
888
- if (workingActive) {
889
- workingActive = false;
890
- if (asoWorking) {
891
- asoWorking.classList.remove("active");
892
- }
893
- }
894
- }
895
-
896
- // ── Input state ────────────────────────────────────────────────────
897
- function disableInput() {
898
- // Keep textarea enabled so user can type their next queued message while AI responds
899
- sendBtn.disabled = true;
900
- newSessionBtn.disabled = true;
901
- sendBtn.classList.add("btn-loading");
902
- }
903
-
904
- function enableInput() {
905
- sendBtn.disabled = false;
906
- newSessionBtn.disabled = false;
907
- sendBtn.classList.remove("btn-loading");
908
- promptInput.focus();
909
- }
910
-
911
- // ── Queue helpers ──────────────────────────────────────────────────
912
- const queueBtn = document.getElementById("queue-btn");
913
- const queueCancelX = document.getElementById("queue-cancel-x");
914
-
915
- function updateQueueBtn() {
916
- const streaming = isStreaming;
917
- const count = chatQueue.length;
918
-
919
- if (streaming || count > 0) {
920
- // Show stop + queue buttons, hide New Session
921
- stopBtn.classList.add("visible");
922
- queueBtn.classList.add("visible");
923
- newSessionBtn.style.display = "none";
924
-
925
- if (count > 0) {
926
- queueBtn.classList.add("has-queue");
927
- queueBtn.querySelector(".queue-btn-label").textContent = `Queued (${count})`;
928
- } else {
929
- queueBtn.classList.remove("has-queue");
930
- queueBtn.querySelector(".queue-btn-label").textContent = "Queue ↵";
931
- }
932
- } else {
933
- // Hide stop + queue, restore New Session
934
- stopBtn.classList.remove("visible");
935
- queueBtn.classList.remove("visible", "has-queue");
936
- newSessionBtn.style.display = "";
937
- }
938
- }
939
-
940
- function queueMessage(text) {
941
- if (!text.trim()) {
942
- return;
943
- }
944
- chatQueue = [...chatQueue, { id: Date.now(), text: text.trim() }];
945
- updateQueueBtn();
946
- }
947
-
948
- function clearQueue() {
949
- chatQueue = [];
950
- updateQueueBtn();
951
- }
952
-
953
- function drainQueue() {
954
- if (chatQueue.length === 0) {
955
- updateQueueBtn();
956
- return;
957
- }
958
- const [next, ...rest] = chatQueue;
959
- chatQueue = rest;
960
- updateQueueBtn();
961
- // Small delay so the UI settles before starting the next send
962
- setTimeout(() => sendText(next.text), 120);
963
- }
964
-
965
- // ── Core send (no input reading — accepts text directly) ───────────
966
- async function sendText(text) {
967
- if (!gateway.connected) {
968
- return;
969
- }
970
- isStreaming = true;
971
- showWorkingIndicator();
972
- disableInput();
973
- updateQueueBtn();
974
-
975
- addUserMessage(text);
976
- feedCache.append({
977
- role: "user",
978
- content: [{ type: "text", text }],
979
- timestamp: Date.now(),
980
- });
981
- await sleep(200);
982
-
983
- // Mark the start of this run in the Reasoning Panel
984
- if (typeof window.injectReasoningRunSeparator === "function") {
985
- window.injectReasoningRunSeparator();
986
- }
987
-
988
- setAgentStatus("waiting");
989
- thinkingEl = createThinkingBubble();
990
- setAgentStatus("thinking");
991
-
992
- try {
993
- await gateway.send(text);
994
- } catch (err) {
995
- handleRunFailure(err.message || "Failed to send message");
996
- }
997
- }
998
-
999
- // ── Send handler (reads input, queues if busy) ─────────────────────
1000
- async function handleSend() {
1001
- const text = promptInput.value.trim();
1002
- if (!text) {
1003
- return;
1004
- }
1005
-
1006
- // Clear the input immediately regardless of streaming state
1007
- promptInput.value = "";
1008
- promptInput.style.height = "auto";
1009
-
1010
- if (isStreaming) {
1011
- // AI is busy — queue it
1012
- queueMessage(text);
1013
- return;
1014
- }
1015
-
1016
- if (!gateway.connected) {
1017
- return;
1018
- }
1019
- await sendText(text);
1020
- }
1021
-
1022
- // ── New Session handler ────────────────────────────────────────────
1023
- async function handleNewSession() {
1024
- if (isStreaming || !gateway.connected) {
1025
- return;
1026
- }
1027
-
1028
- promptInput.disabled = true; // lock textarea during reset
1029
- disableInput();
1030
- setAgentStatus("waiting");
1031
-
1032
- try {
1033
- // Send the /new slash command — gateway resets the session
1034
- await gateway.send("/new");
1035
-
1036
- // Fade out existing messages, then show cleared state
1037
- responseArea.style.transition = "opacity 0.25s ease";
1038
- responseArea.style.opacity = "0";
1039
-
1040
- await sleep(260);
1041
-
1042
- responseArea.innerHTML = "";
1043
- responseArea.prepend(loadMoreSentinel);
1044
- responseArea.style.opacity = "1";
1045
- historyStartIndex = 0;
1046
- historyHasMore = false;
1047
- feedCache.clear(); // clear cached feed — new session starts fresh
1048
- updateLoadMoreSentinel();
1049
- if (typeof window.clearReasoningPanel === "function") {
1050
- window.clearReasoningPanel();
1051
- }
1052
- if (typeof window.clearSymipulsePanel === "function") {
1053
- window.clearSymipulsePanel();
1054
- }
1055
-
1056
- // Show empty-state indicator
1057
- const cleared = document.createElement("div");
1058
- cleared.className = "session-cleared";
1059
- cleared.innerHTML = `
1060
- <div class="session-cleared-icon">◈</div>
1061
- <div class="session-cleared-text">NEW SESSION STARTED</div>
1062
- `;
1063
- responseArea.appendChild(cleared);
1064
-
1065
- setAgentStatus("idle");
1066
- activeSubagentCount = 0;
1067
- hideWorkingIndicator();
1068
- clearQueue(); // discard any queued prompts — new session = clean slate
1069
-
1070
- // Show archive toast — lets user jump directly to history if they regret it
1071
- if (typeof window.showArchiveToast === "function") {
1072
- window.showArchiveToast();
1073
- }
1074
-
1075
- // After a short pause, remove the cleared indicator and let history load
1076
- await sleep(1800);
1077
- cleared.style.transition = "opacity 0.4s ease";
1078
- cleared.style.opacity = "0";
1079
- await sleep(420);
1080
- cleared.remove();
1081
- } catch (err) {
1082
- handleRunFailure(err.message || "Failed to start new session");
1083
- return;
1084
- }
1085
-
1086
- promptInput.disabled = false; // re-enable textarea after reset
1087
- enableInput();
1088
- }
1089
-
1090
- // ── Stop handler ───────────────────────────────────────────────────
1091
- async function handleStop() {
1092
- if (!isStreaming || !gateway.connected) {
1093
- return;
1094
- }
1095
- try {
1096
- await gateway.abort(currentRunId);
1097
- // The gateway will send an 'aborted' event which cleans up state.
1098
- // Visually dim the stop button while we wait for confirmation.
1099
- stopBtn.style.opacity = "0.45";
1100
- stopBtn.disabled = true;
1101
- } catch (err) {
1102
- console.warn("[stop] abort failed:", err.message);
1103
- }
1104
- }
1105
-
1106
- sendBtn.addEventListener("click", handleSend);
1107
- newSessionBtn.addEventListener("click", handleNewSession);
1108
- stopBtn.addEventListener("click", handleStop);
1109
-
1110
- // Queue button — queue current input (if idle text present) or show queued count
1111
- queueBtn.addEventListener("click", (e) => {
1112
- // Cancel X — clears the queue
1113
- if (e.target === queueCancelX || queueCancelX.contains(e.target)) {
1114
- clearQueue();
1115
- return;
1116
- }
1117
- // Main button click — queue the current input if no item queued yet
1118
- if (chatQueue.length === 0) {
1119
- const text = promptInput.value.trim();
1120
- if (text) {
1121
- promptInput.value = "";
1122
- promptInput.style.height = "auto";
1123
- queueMessage(text);
1124
- }
1125
- }
1126
- });
1127
- promptInput.addEventListener("keydown", (e) => {
1128
- if (e.key === "Enter" && !e.shiftKey) {
1129
- e.preventDefault();
1130
- void handleSend();
1131
- }
1132
- });
1133
-
1134
- // ── Textarea auto-resize (up to 3 lines) ──────────────────────────
1135
- function autoResizePrompt() {
1136
- promptInput.style.height = "auto";
1137
- promptInput.style.height = promptInput.scrollHeight + "px";
1138
- }
1139
-
1140
- promptInput.addEventListener("input", autoResizePrompt);
1141
-
1142
- // Clicking anywhere on the prompt bar (padding, icon, gaps) focuses the input
1143
- // Click anywhere on the main input row (not buttons) focuses the input
1144
- document.getElementById("prompt-bar").addEventListener("click", (e) => {
1145
- const inSend = sendBtn.contains(e.target) || e.target === sendBtn;
1146
- const inNewSession = newSessionBtn.contains(e.target) || e.target === newSessionBtn;
1147
- const inHistory = document.getElementById("history-btn").contains(e.target);
1148
- const inQueue = queueBtn.contains(e.target);
1149
- const inStop = stopBtn.contains(e.target);
1150
- // Only focus if clicking in the main row area (not the actions row)
1151
- const inActionsRow = e.target.closest(".prompt-row-actions");
1152
- if (!inSend && !inNewSession && !inHistory && !inQueue && !inStop && !inActionsRow) {
1153
- promptInput.focus();
1154
- }
1155
- });
1156
-
1157
- // ── Model profile listener ────────────────────────────────────────
1158
- window.addEventListener("symi:profile-changed", (e) => {
1159
- activeProfile = e.detail;
1160
- WATCHDOG_MS = activeProfile?.ui?.watchdogMs ?? 300000;
1161
-
1162
- // Update model label in header if present
1163
- const modelLabel = document.getElementById("active-model-label");
1164
- if (modelLabel) {
1165
- modelLabel.textContent = activeProfile?.label ?? "";
1166
- }
1167
- const modelBadge = document.getElementById("model-badge");
1168
- if (modelBadge) {
1169
- modelBadge.textContent = activeProfile?.ui?.badge ?? "";
1170
- }
1171
-
1172
- console.log(
1173
- "[app] profile updated:",
1174
- activeProfile?.label,
1175
- "watchdog:",
1176
- WATCHDOG_MS,
1177
- "armOnSend:",
1178
- activeProfile?.ui?.armWatchdogOnSend,
1179
- );
1180
- });
1181
-
1182
- // ── Gateway setup ──────────────────────────────────────────────────
1183
- // ── Session reload (called after session restore from history drawer) ──
1184
- window.reloadSession = async function () {
1185
- feedCache.clear();
1186
- responseArea.innerHTML = "";
1187
- responseArea.prepend(loadMoreSentinel);
1188
- historyStartIndex = 0;
1189
- historyHasMore = false;
1190
- updateLoadMoreSentinel();
1191
- if (typeof window.clearReasoningPanel === "function") {
1192
- window.clearReasoningPanel();
1193
- }
1194
- if (typeof window.clearSymipulsePanel === "function") {
1195
- window.clearSymipulsePanel();
1196
- }
1197
- setAgentStatus("idle");
1198
- activeSubagentCount = 0;
1199
- hideWorkingIndicator();
1200
-
1201
- // Show restored indicator
1202
- const restored = document.createElement("div");
1203
- restored.className = "session-cleared";
1204
- restored.innerHTML = `
1205
- <div class="session-cleared-icon">◈</div>
1206
- <div class="session-cleared-text">SESSION RESTORED</div>
1207
- `;
1208
- responseArea.appendChild(restored);
1209
-
1210
- // Load history from the restored session
1211
- try {
1212
- const result = await gateway.rpc("chat.history", { sessionKey: window.SESSION_KEY });
1213
- if (result?.messages) {
1214
- renderHistory(result.messages);
1215
- }
1216
- } catch (err) {
1217
- console.error("[app] Failed to load restored session history:", err);
1218
- }
1219
-
1220
- // Remove indicator after a pause
1221
- setTimeout(() => {
1222
- restored.style.transition = "opacity 0.4s ease";
1223
- restored.style.opacity = "0";
1224
- setTimeout(() => restored.remove(), 420);
1225
- }, 1500);
1226
- };
1227
-
1228
- const gateway = new SymiGateway();
1229
- window.gateway = gateway;
1230
-
1231
- gateway.addEventListener("connect", () => {
1232
- setStatus("online");
1233
- enableInput();
1234
- // History arrives via separate 'history' event pushed by the server
1235
- // Bridge to window events for panel scripts
1236
- window.dispatchEvent(new Event("gateway:connected"));
1237
- });
1238
-
1239
- gateway.addEventListener("history", (e) => {
1240
- const msgs = Array.isArray(e.detail?.messages) ? e.detail.messages : [];
1241
- historyStartIndex = e.detail?.startIndex ?? 0;
1242
- historyHasMore = e.detail?.hasMore ?? false;
1243
- renderHistory(msgs);
1244
- // Server-side retries were exhausted — keep the cached feed visible but
1245
- // show a small banner so the user knows they're on stale data and can
1246
- // take action (reload, check gateway logs, /new, etc.).
1247
- if (e.detail?.error === "history.unavailable") {
1248
- showHistoryUnavailableBanner();
1249
- } else {
1250
- clearHistoryUnavailableBanner();
1251
- }
1252
- });
1253
-
1254
- function showHistoryUnavailableBanner() {
1255
- let banner = document.getElementById("history-unavailable-banner");
1256
- if (!banner) {
1257
- banner = document.createElement("div");
1258
- banner.id = "history-unavailable-banner";
1259
- banner.className = "history-unavailable-banner";
1260
- banner.textContent =
1261
- "History unavailable — showing cached view. Gateway retry failed; try reloading.";
1262
- const dismiss = document.createElement("button");
1263
- dismiss.type = "button";
1264
- dismiss.className = "history-unavailable-dismiss";
1265
- dismiss.textContent = "×";
1266
- dismiss.addEventListener("click", clearHistoryUnavailableBanner);
1267
- banner.appendChild(dismiss);
1268
- // Insert at the top of the response area so it's the first thing seen.
1269
- if (responseArea?.parentElement) {
1270
- responseArea.parentElement.insertBefore(banner, responseArea);
1271
- } else {
1272
- document.body.prepend(banner);
1273
- }
1274
- }
1275
- banner.style.display = "";
1276
- }
1277
-
1278
- function clearHistoryUnavailableBanner() {
1279
- const banner = document.getElementById("history-unavailable-banner");
1280
- if (banner) {
1281
- banner.remove();
1282
- }
1283
- }
1284
-
1285
- gateway.addEventListener("disconnect", () => {
1286
- setStatus("offline");
1287
- // If the gateway drops while a run is in progress, surface the failure
1288
- // immediately rather than leaving the UI in a permanently locked state.
1289
- if (isStreaming) {
1290
- handleRunFailure("disconnected");
1291
- }
1292
- });
1293
-
1294
- gateway.addEventListener("event", (e) => {
1295
- handleGatewayEvent(e.detail);
1296
- // Forward to native debug panel if open
1297
- if (window.__debugPanelCapture) {
1298
- window.__debugPanelCapture(e.detail?.event ?? "unknown", e.detail?.payload);
1299
- }
1300
- });
1301
-
1302
- // Start connecting
1303
- disableInput();
1304
- gateway.start();