hermes-web-ui 0.6.40 → 0.6.41
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.
- package/dist/client/assets/js/{AppSidebar-CaSVcbCW.js → AppSidebar-CNkSiv3l.js} +1 -1
- package/dist/client/assets/js/{ChannelsView-hdAXa1hf.js → ChannelsView-6rEo6RBl.js} +1 -1
- package/dist/client/assets/js/{ChatPanel-C6sX6idm.js → ChatPanel-ANAZWluc.js} +3 -3
- package/dist/client/assets/js/{ChatView-B68k_-D9.js → ChatView-DFcPsmRF.js} +1 -1
- package/dist/client/assets/js/{CodingAgentsView-CsIjwbXR.js → CodingAgentsView-CpIY0SHT.js} +1 -1
- package/dist/client/assets/js/{DefaultCredentialPrompt-BRhb4DOa.js → DefaultCredentialPrompt-DmNeotSW.js} +1 -1
- package/dist/client/assets/js/{DesktopBrowserPanel-BlBfS64w.js → DesktopBrowserPanel-CWjTU-3y.js} +1 -1
- package/dist/client/assets/js/{DesktopBrowserView-JukL0QuS.js → DesktopBrowserView-D9Qb3fIV.js} +1 -1
- package/dist/client/assets/js/{DesktopPetView-DWq4EiRU.js → DesktopPetView-B7REtC57.js} +1 -1
- package/dist/client/assets/js/{DesktopTitleBar-DphP4oa6.js → DesktopTitleBar-Dej_16hB.js} +1 -1
- package/dist/client/assets/js/{DevicesView-BFtrfqJs.js → DevicesView--d4HCkch.js} +1 -1
- package/dist/client/assets/js/{DocxFilePreview-CmVJ9Jxx.js → DocxFilePreview-BQz6WC7r.js} +2 -2
- package/dist/client/assets/js/{FileEditor-CdkNYp7b.js → FileEditor-BBegs-5i.js} +2 -2
- package/dist/client/assets/js/{FilePreview-CJrVRPRs.js → FilePreview-B7WqYvZs.js} +2 -2
- package/dist/client/assets/js/{FileRenameModal-mghyEXU4.js → FileRenameModal-82RkAZkd.js} +1 -1
- package/dist/client/assets/js/{FilesPanel-B9cKB5lX.js → FilesPanel-BHcg6CpC.js} +2 -2
- package/dist/client/assets/js/{FilesView-iKZu70E9.js → FilesView-Dl15WTar.js} +2 -2
- package/dist/client/assets/js/{GlobalAgentView-JZsss0gx.js → GlobalAgentView-dxEX611f.js} +1 -1
- package/dist/client/assets/js/{GlobalPendingActions-BRQIt5vl.js → GlobalPendingActions-CeK96C3G.js} +1 -1
- package/dist/client/assets/js/{GroupChatLinkView-CNrV8lnT.js → GroupChatLinkView-CJhI9DVE.js} +1 -1
- package/dist/client/assets/js/{GroupChatPanel-WK4zBasl.js → GroupChatPanel-CLa3s08V.js} +3 -3
- package/dist/client/assets/js/{GroupChatView-BlMUD1MW.js → GroupChatView-CUwvu-6F.js} +1 -1
- package/dist/client/assets/js/{HistoryMessageList-D8zoQ1Zs.js → HistoryMessageList-BdD8GJYM.js} +1 -1
- package/dist/client/assets/js/{HistoryView-Bpr8N2lC.js → HistoryView-Ro92tP5R.js} +1 -1
- package/dist/client/assets/js/{HtmlFilePreview-Bj3_-hMo.js → HtmlFilePreview-xYn7YtmC.js} +1 -1
- package/dist/client/assets/js/{JobsView-CZK26gTw.js → JobsView-BaNA1Yaa.js} +2 -2
- package/dist/client/assets/js/{JourneyView-BPUsLj4o.js → JourneyView-Bw-05mCF.js} +1 -1
- package/dist/client/assets/js/{KanbanView-B7d-2_z9.js → KanbanView-BYC32l2Q.js} +1 -1
- package/dist/client/assets/js/{LoginView-BpYyv831.js → LoginView-KrpCkwOr.js} +1 -1
- package/dist/client/assets/js/{LogsView-CabFHk0v.js → LogsView-Dgm4v5sN.js} +1 -1
- package/dist/client/assets/js/{MarkdownRenderer-CVtmHZwc.js → MarkdownRenderer-BIPowjr-.js} +3 -3
- package/dist/client/assets/js/{McpManagerView-C-ou8vf3.js → McpManagerView-DTtkUIvq.js} +1 -1
- package/dist/client/assets/js/{MemoryView-QGFW4iZo.js → MemoryView-BnL7xzux.js} +2 -2
- package/dist/client/assets/js/{MessageList-DZR-TFjD.js → MessageList-5tytzhb0.js} +3 -3
- package/dist/client/assets/js/{ModelsView-DiWdSWOW.js → ModelsView-ComCz0Ce.js} +1 -1
- package/dist/client/assets/js/{OutlinePanel-Dlr5svMY.js → OutlinePanel-CF_XPCRn.js} +1 -1
- package/dist/client/assets/js/{PageSidebarFooter-Bic1fUmG.js → PageSidebarFooter-dvLzcTIm.js} +1 -1
- package/dist/client/assets/js/{PdfFilePreview-Dkpan1ay.js → PdfFilePreview-COOAoJ4V.js} +2 -2
- package/dist/client/assets/js/{PerformanceView-LrZaED_Z.js → PerformanceView-D6dKifJh.js} +1 -1
- package/dist/client/assets/js/{PetdexView-Bv8RioGL.js → PetdexView-CmvzDYwf.js} +1 -1
- package/dist/client/assets/js/{PluginsView-CbtdIGlq.js → PluginsView-zJV9FE9c.js} +1 -1
- package/dist/client/assets/js/{PptxFilePreview-5if_GbU6.js → PptxFilePreview-dC4JxV6j.js} +2 -2
- package/dist/client/assets/js/{ProfileAvatar-DI9ciJxS.js → ProfileAvatar-C8xoALCI.js} +1 -1
- package/dist/client/assets/js/{ProfilesView-C-FSiKMU.js → ProfilesView-CxVxJRN_.js} +1 -1
- package/dist/client/assets/js/{ProviderConfigurationPrompt-BUoWC41Y.js → ProviderConfigurationPrompt-zwk1UwoP.js} +1 -1
- package/dist/client/assets/js/{SessionSearchModal-CEKvSihp.js → SessionSearchModal-DhwGsV-i.js} +1 -1
- package/dist/client/assets/js/{SettingRow-CSfiJmxx.js → SettingRow-DHqhLX3M.js} +1 -1
- package/dist/client/assets/js/{SettingsCircuitBadge-DHIEFyTR.js → SettingsCircuitBadge-CnWSfQZd.js} +1 -1
- package/dist/client/assets/js/{SettingsView-DbNJroV3.js → SettingsView-Cbroga25.js} +1 -1
- package/dist/client/assets/js/{SharedGroupChatView-CTYjqWcO.js → SharedGroupChatView-DXfqtQ33.js} +1 -1
- package/dist/client/assets/js/{SkillsUsageView-BqZ3GtfT.js → SkillsUsageView-C34i3lOQ.js} +1 -1
- package/dist/client/assets/js/{SkillsView-Bhla7821.js → SkillsView-DRG_1esx.js} +2 -2
- package/dist/client/assets/js/{SpreadsheetFilePreview-CGK8HDAx.js → SpreadsheetFilePreview-DRw4kIx5.js} +1 -1
- package/dist/client/assets/js/{TerminalPanel-CtBTLOwq.js → TerminalPanel-Da1nL9P8.js} +1 -1
- package/dist/client/assets/js/{TerminalView-BID7fupB.js → TerminalView-B6z-VaGq.js} +1 -1
- package/dist/client/assets/js/{ThemeView-Cx3ucIus.js → ThemeView-CAaJ9MH-.js} +1 -1
- package/dist/client/assets/js/{UsageView-ByGCsw7o.js → UsageView-B_hLsp0k.js} +1 -1
- package/dist/client/assets/js/{VersionPreviewView-DiAK1ind.js → VersionPreviewView-DKXL6anl.js} +1 -1
- package/dist/client/assets/js/{WebPet-CdIqrnp1.js → WebPet-BUvrfjpq.js} +1 -1
- package/dist/client/assets/js/{WorkflowView-DmBOhSuq.js → WorkflowView-r46Ap9FY.js} +1 -1
- package/dist/client/assets/js/{WorkspaceDiffPreview-dHIGp-9F.js → WorkspaceDiffPreview-EwZAE18F.js} +2 -2
- package/dist/client/assets/js/{abap-Dj8IFKiF.js → abap-C7gkFu-A.js} +1 -1
- package/dist/client/assets/js/{aiden0z-pptx-renderer.es-6vi5-jAN.js → aiden0z-pptx-renderer.es-DOpVaH_k.js} +1 -1
- package/dist/client/assets/js/{apex-C3INPUEt.js → apex-DZOtRowu.js} +1 -1
- package/dist/client/assets/js/{ar-Gk9y3ZfO.js → ar-8iThLSJQ.js} +1 -1
- package/dist/client/assets/js/architecture-7EHR7CIX-BrfhYGuP.js +1 -0
- package/dist/client/assets/js/{architectureDiagram-3BPJPVTR-DLZYeivB.js → architectureDiagram-3BPJPVTR-DEsTTzKd.js} +1 -1
- package/dist/client/assets/js/{auth-D1ZFqv22.js → auth-B52zm2Ir.js} +1 -1
- package/dist/client/assets/js/{azcli-UBzLhJq5.js → azcli-KxuicZQh.js} +1 -1
- package/dist/client/assets/js/{bat-P3O4jldt.js → bat-DfFP4HF-.js} +1 -1
- package/dist/client/assets/js/{bicep-DdQR9RxE.js → bicep-Co4bntVh.js} +1 -1
- package/dist/client/assets/js/{blockDiagram-GPEHLZMM-UWFo8sm5.js → blockDiagram-GPEHLZMM-NsxYeUKd.js} +1 -1
- package/dist/client/assets/js/{c4Diagram-AAUBKEIU-jgyj0wOb.js → c4Diagram-AAUBKEIU-D68asSzm.js} +1 -1
- package/dist/client/assets/js/{cameligo-Bb4ubW_C.js → cameligo-Xi0l_9Wr.js} +1 -1
- package/dist/client/assets/js/{chat-DdHii4Qz.js → chat-fUZW3YFa.js} +1 -1
- package/dist/client/assets/js/{chat-input-height-CSPwB9it.js → chat-input-height-lvFawuv9.js} +1 -1
- package/dist/client/assets/js/{chat-timestamp-DGQ8fmtT.js → chat-timestamp-4wWFcZWv.js} +1 -1
- package/dist/client/assets/js/{chunk-2J33WTMH-Br9OWF5a.js → chunk-2J33WTMH-CEU5sLIh.js} +1 -1
- package/dist/client/assets/js/{chunk-3OPIFGDE-Cb40LuI4.js → chunk-3OPIFGDE-DEhbKkCl.js} +1 -1
- package/dist/client/assets/js/{chunk-4BX2VUAB-jYtdiafd.js → chunk-4BX2VUAB-OIZUstuy.js} +1 -1
- package/dist/client/assets/js/{chunk-55IACEB6-CBtymeHY.js → chunk-55IACEB6-DQHKZCBG.js} +1 -1
- package/dist/client/assets/js/{chunk-5ZQYHXKU-yj9xqmex.js → chunk-5ZQYHXKU-BU3pQVVl.js} +1 -1
- package/dist/client/assets/js/{chunk-727SXJPM-er_5tB5X.js → chunk-727SXJPM-jj97gdnP.js} +1 -1
- package/dist/client/assets/js/{chunk-AQP2D5EJ-C4mDD6xK.js → chunk-AQP2D5EJ-jv-oWlkb.js} +1 -1
- package/dist/client/assets/js/{chunk-BSJP7CBP-QZesZe57.js → chunk-BSJP7CBP-DkKsepNF.js} +1 -1
- package/dist/client/assets/js/{chunk-CSCIHK7Q-5LH118bT.js → chunk-CSCIHK7Q-CLgoBoCF.js} +3 -3
- package/dist/client/assets/js/{chunk-FMBD7UC4-CQho6QZ5.js → chunk-FMBD7UC4-Bx1bCKUR.js} +1 -1
- package/dist/client/assets/js/{chunk-KSCS5N6A-DONM1Omv.js → chunk-KSCS5N6A-CZHZ6pBd.js} +1 -1
- package/dist/client/assets/js/{chunk-L5ZTLDWV-FN_zFWkp.js → chunk-L5ZTLDWV-dz9D3kOb.js} +1 -1
- package/dist/client/assets/js/{chunk-LZXEDZCA-CEEUVvpS.js → chunk-LZXEDZCA-CQiSQehC.js} +2 -2
- package/dist/client/assets/js/{chunk-ND2GUHAM-DWckpxQD.js → chunk-ND2GUHAM-mWODKb8v.js} +1 -1
- package/dist/client/assets/js/{chunk-NZK2D7GU-0mKZmkuV.js → chunk-NZK2D7GU-ivCkjCOR.js} +1 -1
- package/dist/client/assets/js/{chunk-O5CBEL6O-DIDAOkT_.js → chunk-O5CBEL6O-BRUisK47.js} +1 -1
- package/dist/client/assets/js/{chunk-QZHKN3VN-D3c-TMz-.js → chunk-QZHKN3VN-BHjgTrzY.js} +1 -1
- package/dist/client/assets/js/{chunk-WU5MYG2G-BZvSpwm4.js → chunk-WU5MYG2G-CNW1rcpL.js} +1 -1
- package/dist/client/assets/js/{chunk-XPW4576I-xdyJtk-s.js → chunk-XPW4576I-DP3dJbOu.js} +1 -1
- package/dist/client/assets/js/classDiagram-4FO5ZUOK-BVBBe3DQ.js +1 -0
- package/dist/client/assets/js/classDiagram-v2-Q7XG4LA2-DJUe3i9Y.js +1 -0
- package/dist/client/assets/js/{clipboard-DQ_A8ns-.js → clipboard-DHZFaAvO.js} +1 -1
- package/dist/client/assets/js/{clipboard-files-bDrcGKPe.js → clipboard-files-CBDy-02Y.js} +1 -1
- package/dist/client/assets/js/{clojure-ku7aCU1_.js → clojure-DuyGwS8X.js} +1 -1
- package/dist/client/assets/js/{coding-agents-DfHyBvky.js → coding-agents-BNTHD6kd.js} +1 -1
- package/dist/client/assets/js/{codingAgentProviders-BM18FAW9.js → codingAgentProviders-DM_ouxbL.js} +1 -1
- package/dist/client/assets/js/{coffee-DnRIdJlY.js → coffee-C5p7vzpa.js} +1 -1
- package/dist/client/assets/js/{completion-notification-XxjbntI8.js → completion-notification-CzdnhuX3.js} +1 -1
- package/dist/client/assets/js/{cose-bilkent-S5V4N54A-w891sIF1.js → cose-bilkent-S5V4N54A-De_ZdqY0.js} +1 -1
- package/dist/client/assets/js/{cpp-CN8i6ISX.js → cpp-II5hDbTe.js} +1 -1
- package/dist/client/assets/js/{csharp-B-fxig7O.js → csharp-D0POzSpv.js} +1 -1
- package/dist/client/assets/js/{csp-Bar9LGt4.js → csp-CwtuRkR3.js} +1 -1
- package/dist/client/assets/js/{css-DFtC5xZN.js → css-Dc2fJIqQ.js} +1 -1
- package/dist/client/assets/js/{cssMode-DH5XKKL2.js → cssMode-CC6jRvHF.js} +1 -1
- package/dist/client/assets/js/{cypher-BkJexWsv.js → cypher-DBcQoWDH.js} +1 -1
- package/dist/client/assets/js/{cytoscape.esm-BDsvr8Aq.js → cytoscape.esm-C9FMRqxM.js} +1 -1
- package/dist/client/assets/js/{dagre-BM42HDAG-BuT885pa.js → dagre-BM42HDAG-CvJIC410.js} +1 -1
- package/dist/client/assets/js/{dagre-BVUDh8Sh.js → dagre-BtgEsAtK.js} +1 -1
- package/dist/client/assets/js/{dart-B7W8hAtN.js → dart-Jf_Hmp2o.js} +1 -1
- package/dist/client/assets/js/{de-LDpd8WHJ.js → de-7hLSwCEx.js} +1 -1
- package/dist/client/assets/js/{defineProperty-DdPu4ZVv.js → defineProperty-DHkErCmG.js} +1 -1
- package/dist/client/assets/js/{desktop-browser-xrRFPNUg.js → desktop-browser-C6AhY0uu.js} +1 -1
- package/dist/client/assets/js/{diagram-2AECGRRQ-B1sSf-09.js → diagram-2AECGRRQ-CvPeU5Lm.js} +1 -1
- package/dist/client/assets/js/{diagram-5GNKFQAL-BffX22pf.js → diagram-5GNKFQAL-CBniYlkH.js} +1 -1
- package/dist/client/assets/js/{diagram-KO2AKTUF-D8QvpUpn.js → diagram-KO2AKTUF-C_yFaVRj.js} +1 -1
- package/dist/client/assets/js/{diagram-LMA3HP47-DkG7p3lQ.js → diagram-LMA3HP47-BzM1IxNe.js} +1 -1
- package/dist/client/assets/js/{diagram-OG6HWLK6-RjvNNvXM.js → diagram-OG6HWLK6-yvmf_3ax.js} +1 -1
- package/dist/client/assets/js/{dist-Bk0VKtV3.js → dist-BHzBn3v7.js} +1 -1
- package/dist/client/assets/js/{dockerfile-C4m7j8sy.js → dockerfile-J3d6ZPDJ.js} +1 -1
- package/dist/client/assets/js/{docx-preview-BpTW-GN7.js → docx-preview-Rqt8wMjQ.js} +1 -1
- package/dist/client/assets/js/{download-CX8EG48r.js → download-xhRMWMda.js} +1 -1
- package/dist/client/assets/js/{ecl-EHV358Ls.js → ecl-XnlT0p97.js} +1 -1
- package/dist/client/assets/js/{editor.api2-CnHBqh_d.js → editor.api2-ChO5nUQb.js} +1 -1
- package/dist/client/assets/js/{elixir-DLfp2Dwn.js → elixir-BEJbxH-B.js} +1 -1
- package/dist/client/assets/js/{en-D6VVFwFU.js → en-D2WSXgkM.js} +1 -1
- package/dist/client/assets/js/{erDiagram-TEJ5UH35-CLlLC6xx.js → erDiagram-TEJ5UH35-DZysD9r9.js} +1 -1
- package/dist/client/assets/js/{es-BIMLuyVP.js → es-B7Mq1P0U.js} +1 -1
- package/dist/client/assets/js/{esm-C8D4M0Yn.js → esm-DnZPPtmx.js} +1 -1
- package/dist/client/assets/js/eventmodeling-FCH6USID-vlE3-g2j.js +1 -0
- package/dist/client/assets/js/{file-preview-BvgwVZXh.js → file-preview-C417aixJ.js} +1 -1
- package/dist/client/assets/js/{files-CJkCqsUx.js → files-DjI-npgn.js} +1 -1
- package/dist/client/assets/js/{flow9-CtBaUnAi.js → flow9-j5XT_8TQ.js} +1 -1
- package/dist/client/assets/js/{flowDiagram-I6XJVG4X-VTRTPnqD.js → flowDiagram-I6XJVG4X-Dt5ZtyHz.js} +1 -1
- package/dist/client/assets/js/{fr-C2lf0cY2.js → fr-DvClrDOw.js} +1 -1
- package/dist/client/assets/js/{freemarker2-XLeMvhl_.js → freemarker2-BzCf_0SN.js} +1 -1
- package/dist/client/assets/js/{fsharp-Db0uaBQv.js → fsharp-ClU_Sdjr.js} +1 -1
- package/dist/client/assets/js/{ganttDiagram-6RSMTGT7-CdKcIZ8_.js → ganttDiagram-6RSMTGT7-Bca3rPWi.js} +1 -1
- package/dist/client/assets/js/gitGraph-WXDBUCRP-Cyd4P6XH.js +1 -0
- package/dist/client/assets/js/{gitGraphDiagram-PVQCEYII-Bcuyw6fo.js → gitGraphDiagram-PVQCEYII-Co29qnTg.js} +1 -1
- package/dist/client/assets/js/{go-DwaTlB-B.js → go-D3iUyCM0.js} +1 -1
- package/dist/client/assets/js/{graphlib-vAI4Pw7R.js → graphlib-Bln6qd-Z.js} +1 -1
- package/dist/client/assets/js/{graphql-Cf2XhNJR.js → graphql-z8koqyyL.js} +1 -1
- package/dist/client/assets/js/{group-agent-avatar-CPehpiK0.js → group-agent-avatar-CwqtaKGw.js} +1 -1
- package/dist/client/assets/js/{group-chat-CY62vc77.js → group-chat-Buz8HP-N.js} +1 -1
- package/dist/client/assets/js/{group-chat-xkdjC2Jt.js → group-chat-CgFAwCtr.js} +1 -1
- package/dist/client/assets/js/{group-chat-agent-link-DdSNKasF.js → group-chat-agent-link-N5IFeN_j.js} +1 -1
- package/dist/client/assets/js/{handlebars-CNEKu_p8.js → handlebars-C_JvhUYs.js} +1 -1
- package/dist/client/assets/js/{hcl-6UZbq6h2.js → hcl-X7TzviIX.js} +1 -1
- package/dist/client/assets/js/{highlight-DwtBT6t1.js → highlight-C4yUBxwQ.js} +1 -1
- package/dist/client/assets/js/{html-DfSIHhKA.js → html-B-rCQB0N.js} +1 -1
- package/dist/client/assets/js/{htmlMode-iGw9-O-W.js → htmlMode-CAeEf_yf.js} +1 -1
- package/dist/client/assets/js/{index-DnjQJzX4.js → index-DN4SafrP.js} +5 -5
- package/dist/client/assets/js/info-J43DQDTF-B9tkQ2Sb.js +1 -0
- package/dist/client/assets/js/{infoDiagram-5YYISTIA-85450Zam.js → infoDiagram-5YYISTIA-BWQGayms.js} +1 -1
- package/dist/client/assets/js/{ini-8em8V_Af.js → ini-LTHHN4J-.js} +1 -1
- package/dist/client/assets/js/{ishikawaDiagram-YF4QCWOH-BZ4az7UA.js → ishikawaDiagram-YF4QCWOH-Dhuplz_z.js} +1 -1
- package/dist/client/assets/js/{ja-C1bBXgr_.js → ja-D7BeX2_D.js} +1 -1
- package/dist/client/assets/js/{java-CP1MdIkO.js → java-BRFX-ya0.js} +1 -1
- package/dist/client/assets/js/{javascript-Cr8_LHYa.js → javascript-ZXiVmjXn.js} +1 -1
- package/dist/client/assets/js/{journeyDiagram-JHISSGLW-DGMB8Tgc.js → journeyDiagram-JHISSGLW-CJeatAU9.js} +1 -1
- package/dist/client/assets/js/{jsonMode-HCZ-1lFH.js → jsonMode-C6FcMe0o.js} +1 -1
- package/dist/client/assets/js/{jszip.min-BkR6b8DY.js → jszip.min-skZCUzWf.js} +1 -1
- package/dist/client/assets/js/{julia-DMTMxa5q.js → julia-Bph8N3CL.js} +1 -1
- package/dist/client/assets/js/{kanban-definition-UN3LZRKU-F5cH_RpB.js → kanban-definition-UN3LZRKU-tvWuOdSr.js} +1 -1
- package/dist/client/assets/js/{katex-CYbEJAbZ.js → katex-hSGJNERm.js} +1 -1
- package/dist/client/assets/js/{ko-qgOeHd8L.js → ko-BsVa-If_.js} +1 -1
- package/dist/client/assets/js/{kotlin-Blzus47W.js → kotlin-_c4-tPQp.js} +1 -1
- package/dist/client/assets/js/{less-DWCHpDyf.js → less-5oVo4jfQ.js} +1 -1
- package/dist/client/assets/js/{lexon-YXdlYGbJ.js → lexon-DE4YtGwF.js} +1 -1
- package/dist/client/assets/js/{liquid-DSQgvRwe.js → liquid-BGfieGMG.js} +1 -1
- package/dist/client/assets/js/{lspLanguageFeatures-0Hx2Vnc-.js → lspLanguageFeatures-DU_1H2uW.js} +1 -1
- package/dist/client/assets/js/{lua-Cyv3mTkg.js → lua-7WJSZJqD.js} +1 -1
- package/dist/client/assets/js/{m3-CPY3Ym7_.js → m3-gZlfoR19.js} +1 -1
- package/dist/client/assets/js/{markdown-DaPQ1nuG.js → markdown-BYF71orA.js} +1 -1
- package/dist/client/assets/js/{mdx-BqA6Xr9V.js → mdx-CunEIV3g.js} +1 -1
- package/dist/client/assets/js/{mermaid-parser.core-D4HRUOce.js → mermaid-parser.core-DU_SX15F.js} +3 -3
- package/dist/client/assets/js/{mermaid.core-w6kHmgOG.js → mermaid.core-8vsbhG5J.js} +3 -3
- package/dist/client/assets/js/{message-scroll-position-C5yRCyBU.js → message-scroll-position-C9_YO3pX.js} +2 -2
- package/dist/client/assets/js/{mindmap-definition-RKZ34NQL-CnzhnJ7Z.js → mindmap-definition-RKZ34NQL-HPtlKqL1.js} +1 -1
- package/dist/client/assets/js/{mips-BfqBfLvN.js → mips-DXkvw9aZ.js} +1 -1
- package/dist/client/assets/js/{models-wrytxWnf.js → models-BILDy2sV.js} +1 -1
- package/dist/client/assets/js/{monaco.contribution-Bc-DesyO.js → monaco.contribution-DDqeHGl3.js} +2 -2
- package/dist/client/assets/js/{msdax-DgMip49g.js → msdax-BbHEBDvP.js} +1 -1
- package/dist/client/assets/js/{mysql-DPUvF1g2.js → mysql-7I1rlwh7.js} +1 -1
- package/dist/client/assets/js/{objective-c-BQ3llrPW.js → objective-c-Dk03REAv.js} +1 -1
- package/dist/client/assets/js/packet-YPE3B663-DlTFK3Wo.js +1 -0
- package/dist/client/assets/js/{pascal-bFWHV7MZ.js → pascal-BCfNkzYY.js} +1 -1
- package/dist/client/assets/js/{pascaligo-C8Qza2pK.js → pascaligo-D-DslS98.js} +1 -1
- package/dist/client/assets/js/{pdf-Cb7x495t.js → pdf-B_OYWxSy.js} +1 -1
- package/dist/client/assets/js/{pdf.worker.min-DDUKJ6cJ.js → pdf.worker.min--q2RLEHa.js} +1 -1
- package/dist/client/assets/js/{perl-x25gw0_p.js → perl-MUnuTclx.js} +1 -1
- package/dist/client/assets/js/{pets-BfRsvl7D.js → pets-D74G2jqA.js} +1 -1
- package/dist/client/assets/js/{pgsql-DAUcGeRq.js → pgsql-BxCBktNe.js} +1 -1
- package/dist/client/assets/js/{php-nri1eqb2.js → php-zp9UgH03.js} +1 -1
- package/dist/client/assets/js/pie-LRSECV5Y-BtnBGhFZ.js +1 -0
- package/dist/client/assets/js/{pieDiagram-4H26LBE5-4LODdtT_.js → pieDiagram-4H26LBE5-CG8_pcHr.js} +1 -1
- package/dist/client/assets/js/{pla-CHi5LWNL.js → pla-DGCtmYZC.js} +1 -1
- package/dist/client/assets/js/{postiats-Bk7jD0AA.js → postiats-DHSW8gnY.js} +1 -1
- package/dist/client/assets/js/{powerquery-UTqJ0Vs7.js → powerquery-BGsPEmJe.js} +1 -1
- package/dist/client/assets/js/{powershell-CuPY3Rqk.js → powershell-BItlb0hE.js} +1 -1
- package/dist/client/assets/js/{profiles-D-vlI-Ec.js → profiles-BK5JKD7h.js} +1 -1
- package/dist/client/assets/js/{protobuf-Be4AIz9j.js → protobuf-BIhm6JYx.js} +1 -1
- package/dist/client/assets/js/{pt-D7_udWb3.js → pt-BSORCDMm.js} +1 -1
- package/dist/client/assets/js/{pug-CZFx15Ey.js → pug-BtnM7KZj.js} +1 -1
- package/dist/client/assets/js/{python-BgRg6Ez6.js → python-DxzTx1Q_.js} +1 -1
- package/dist/client/assets/js/{qsharp-BiBiLhRS.js → qsharp-B_8MSfaB.js} +1 -1
- package/dist/client/assets/js/{quadrantDiagram-W4KKPZXB-g_q9-dXx.js → quadrantDiagram-W4KKPZXB-CsbkMYuV.js} +1 -1
- package/dist/client/assets/js/{r-DM7NVSbZ.js → r-kvKC59jk.js} +1 -1
- package/dist/client/assets/js/radar-GUYGQ44K-BTKMKX4G.js +1 -0
- package/dist/client/assets/js/{razor-CiWy0jCW.js → razor-BwZ0MkaL.js} +1 -1
- package/dist/client/assets/js/{redis-BR2LPmFL.js → redis-5j1U_i85.js} +1 -1
- package/dist/client/assets/js/{redshift-B0sdAV16.js → redshift-CX1dFLA1.js} +1 -1
- package/dist/client/assets/js/{requirementDiagram-4Y6WPE33-EedCclad.js → requirementDiagram-4Y6WPE33-CKC7CQCX.js} +1 -1
- package/dist/client/assets/js/{restructuredtext-kQOBLN1M.js → restructuredtext-MV0-Naya.js} +1 -1
- package/dist/client/assets/js/{rough.esm-Dyx_2DON.js → rough.esm-CV1rL6PC.js} +1 -1
- package/dist/client/assets/js/{ru-CVQQmreT.js → ru-JsH6TKyg.js} +1 -1
- package/dist/client/assets/js/{ruby-CbdJXy6J.js → ruby-Bhyejf9X.js} +1 -1
- package/dist/client/assets/js/{rust-DZanYksk.js → rust-CR8d_FC1.js} +1 -1
- package/dist/client/assets/js/{sankeyDiagram-5OEKKPKP-DFC0nzsd.js → sankeyDiagram-5OEKKPKP-CKlqlvAe.js} +1 -1
- package/dist/client/assets/js/{sb-C5-WiqDZ.js → sb-hLW2EM2L.js} +1 -1
- package/dist/client/assets/js/{scala-Bk7i9nV-.js → scala-DVUhALEZ.js} +1 -1
- package/dist/client/assets/js/{scheme-CaZSWmJ2.js → scheme-BS6yNanr.js} +1 -1
- package/dist/client/assets/js/{scss-ByOYuc7K.js → scss-BfoRsElt.js} +1 -1
- package/dist/client/assets/js/{sequenceDiagram-3UESZ5HK-hWjPfqXt.js → sequenceDiagram-3UESZ5HK-CTimhD6H.js} +1 -1
- package/dist/client/assets/js/{session-browser-prefs-Br8OYA4_.js → session-browser-prefs-BT1woDux.js} +1 -1
- package/dist/client/assets/js/{sessions-iGK9S6zk.js → sessions-IkLKgnN6.js} +1 -1
- package/dist/client/assets/js/{settings-pbanANH0.js → settings-roYY6G3W.js} +1 -1
- package/dist/client/assets/js/{shell-Di0TEySc.js → shell-BO_Lyczz.js} +1 -1
- package/dist/client/assets/js/{skills-DC-UPcXj.js → skills-a5LPwmiT.js} +1 -1
- package/dist/client/assets/js/{solidity-BNTjAuuA.js → solidity-D3T2Ki4l.js} +1 -1
- package/dist/client/assets/js/{sophia-LY__8Yob.js → sophia-iJmIEvi8.js} +1 -1
- package/dist/client/assets/js/{sparql-CWnLfgGS.js → sparql-C2HCEExr.js} +1 -1
- package/dist/client/assets/js/{sql-B0ypQ9lR.js → sql-DM6_3GBc.js} +1 -1
- package/dist/client/assets/js/{src-BihFroE7.js → src-DD_TpJde.js} +1 -1
- package/dist/client/assets/js/{st-CqVFKTbZ.js → st-DSb39Fm5.js} +1 -1
- package/dist/client/assets/js/{stateDiagram-AJRCARHV-B7wEnYVe.js → stateDiagram-AJRCARHV-DwBGmBj6.js} +1 -1
- package/dist/client/assets/js/stateDiagram-v2-BHNVJYJU-5bNcwBne.js +1 -0
- package/dist/client/assets/js/{style-DDAg_jVj.js → style-B5xXhBlp.js} +1 -1
- package/dist/client/assets/js/{swift-B4ZZmDxc.js → swift-DrZYSZK3.js} +1 -1
- package/dist/client/assets/js/{systemverilog-zLt-O1mT.js → systemverilog-BAWNCaf6.js} +1 -1
- package/dist/client/assets/js/{tcl-DCSZmA-l.js → tcl-DY15ex6v.js} +1 -1
- package/dist/client/assets/js/{timeline-definition-PNZ67QCA-BN_LfleE.js → timeline-definition-PNZ67QCA-B8xuIu6g.js} +1 -1
- package/dist/client/assets/js/treeView-BLDUP644-DvZPUnGM.js +1 -0
- package/dist/client/assets/js/treemap-LRROVOQU-Bis1djYh.js +1 -0
- package/dist/client/assets/js/{tsMode-BjUcuHrq.js → tsMode-BE8JCSCE.js} +1 -1
- package/dist/client/assets/js/{ttsHelpers-BLunFYsq.js → ttsHelpers-BLNiQExI.js} +1 -1
- package/dist/client/assets/js/{twig-CuJlVpUG.js → twig-BpHF_18K.js} +1 -1
- package/dist/client/assets/js/{typescript-De40YVFt.js → typescript-FQ3z9hVG.js} +1 -1
- package/dist/client/assets/js/{typespec-8QcsIc3c.js → typespec-BKvcn6aE.js} +1 -1
- package/dist/client/assets/js/{useSttSettings-B1-KXN44.js → useSttSettings-DHX06G8A.js} +1 -1
- package/dist/client/assets/js/{vb-DEGTdhxf.js → vb-B74ucE43.js} +1 -1
- package/dist/client/assets/js/{vennDiagram-CIIHVFJN-hL8ax7wF.js → vennDiagram-CIIHVFJN-DtEu04QR.js} +1 -1
- package/dist/client/assets/js/wardley-L42UT6IY-CD4dIN63.js +1 -0
- package/dist/client/assets/js/{wardleyDiagram-YWT4CUSO-BIR-RA6Y.js → wardleyDiagram-YWT4CUSO-DdNKCPsp.js} +1 -1
- package/dist/client/assets/js/{wgsl-CmbiucmY.js → wgsl-DEf5Vdqv.js} +1 -1
- package/dist/client/assets/js/{workers-BgWBq4qY.js → workers-BbaiLVxx.js} +1 -1
- package/dist/client/assets/js/{workflow-socket-DZ9Ceffc.js → workflow-socket-DH402vxO.js} +1 -1
- package/dist/client/assets/js/{xml-SZLdwDmk.js → xml-zjE51I7v.js} +1 -1
- package/dist/client/assets/js/{xterm-D6CotCNH.js → xterm-Djy4rCx0.js} +1 -1
- package/dist/client/assets/js/{xychartDiagram-2RQKCTM6-DHa486uP.js → xychartDiagram-2RQKCTM6-CKqN7g7r.js} +1 -1
- package/dist/client/assets/js/{yaml-CgQpCgM5.js → yaml-DabeGoTc.js} +1 -1
- package/dist/client/assets/js/{zh-BDlMioZr.js → zh-CI4-L3JY.js} +1 -1
- package/dist/client/assets/js/{zh-TW-DTbLWR1A.js → zh-TW-wYlj-uOZ.js} +1 -1
- package/dist/client/index.html +1 -1
- package/dist/server/index.js +3 -3
- package/dist/server/openapi.json +1 -1
- package/package.json +9 -1
- package/dist/client/assets/js/architecture-7EHR7CIX-Cl4Qi40R.js +0 -1
- package/dist/client/assets/js/classDiagram-4FO5ZUOK-DC0BcY8x.js +0 -1
- package/dist/client/assets/js/classDiagram-v2-Q7XG4LA2-BfDDH_fm.js +0 -1
- package/dist/client/assets/js/eventmodeling-FCH6USID-Bgzwnvkn.js +0 -1
- package/dist/client/assets/js/gitGraph-WXDBUCRP-CwFrpI3e.js +0 -1
- package/dist/client/assets/js/info-J43DQDTF-wMwkmIWM.js +0 -1
- package/dist/client/assets/js/packet-YPE3B663-DYmKXJOE.js +0 -1
- package/dist/client/assets/js/pie-LRSECV5Y-Dx0hbcjV.js +0 -1
- package/dist/client/assets/js/radar-GUYGQ44K-D-t-QJhi.js +0 -1
- package/dist/client/assets/js/stateDiagram-v2-BHNVJYJU-CoMhBVvo.js +0 -1
- package/dist/client/assets/js/treeView-BLDUP644-CMJGhbWk.js +0 -1
- package/dist/client/assets/js/treemap-LRROVOQU-_j4KoVDh.js +0 -1
- package/dist/client/assets/js/wardley-L42UT6IY-BeOvmJoM.js +0 -1
package/dist/server/index.js
CHANGED
|
@@ -1591,7 +1591,7 @@ process.on('unhandledRejection', (error) => {
|
|
|
1591
1591
|
`);return tG(e).replace(/^\s*[-*+]\s+/gm,"").replace(/[*_#>]+/g,"").replace(/\s+/g," ").trim()}function vne(I){return yne.test(I.trimEnd())}function Ene(I){let e=!1,l=!1,t=!1,n=!1,c=!1;for(let G=0;G<I.length;G+=1){let a=I.slice(G);if(a.startsWith("```")){e=!e,G+=2;continue}if(e)continue;let s=I[G];if(s==="`"){l=!l;continue}if(!l){if(n){s===")"&&(n=!1);continue}if(c)if(/\s/.test(s))c=!1;else continue;if(a.startsWith("http://")||a.startsWith("https://")||a.startsWith("www.")){c=!0,a.startsWith("https://")?G+=7:a.startsWith("http://")?G+=6:G+=3;continue}if(t){s==="]"&&I[G+1]==="("&&(t=!1,n=!0,G+=1);continue}if(s==="["){t=!0;continue}if(s===`
|
|
1592
1592
|
`||s==="\r"){let d=G+1;if(s==="\r"&&I[G+1]===`
|
|
1593
1593
|
`&&(d+=1,G+=1),vne(I.slice(0,d)))return d}}}return-1}function ZW(I={}){let e="";function l(t=!1){let n=[];for(;e.length>0;){let c=Ene(e);if(c<0&&t&&(c=e.length),c<0)break;let G=e.slice(0,c);e=e.slice(c);let a=Ti(G);a&&n.push(a)}return n}return{pushDelta(t){return t?(e+=t,l(!1)):[]},flush(){let t=l(!0);return t.length>0?t.join(" "):null},reset(){e=""}}}var tx=["This session is a real-time voice conversation through an MCU device.","Keep every user-facing response brief, natural, and easy to understand when spoken aloud. Answer in the user's language.","Use plain text only. Do not use Markdown, headings, bullet lists, tables, code fences, or decorative formatting.",'When a request requires tools or non-trivial work, maximize the use of delegate_task with mode="background" for work that can safely continue asynchronously. Split independent work into background subtasks when useful.',"Give the user a very short acknowledgement and return promptly instead of making them wait. Use foreground work only when its result is required immediately for a safe or meaningful answer.","When a background result becomes available, proactively provide the concise spoken result. Never claim unfinished work is complete."].join(`
|
|
1594
|
-
`);var nx="ekko";function bs(I){return typeof I=="string"&&I.trim().toLowerCase()==="hermes"?"hermes":nx}function dw(I){return I==="hermes"?{source:"global_agent",session_source:"global_agent",instructions:tx}:{source:"coding_agent",session_source:"global_agent",coding_agent_id:"ekko-agent",instructions:tx}}var Cne=3e4,Jne=12e4,cx=5*1024*1024,eoI=10*1024*1024,rw="/global-agent",Ane=new Set(["GET","POST","PUT","PATCH","DELETE","HEAD"]),kne=new Set(["accept","accept-language","authorization","content-type","x-hermes-profile","x-request-id"]),Lne=["application/json","application/problem+json","application/x-ndjson","application/javascript","application/xml","application/x-www-form-urlencoded","text/"],fne=new Set(["/chat-run"]),xne=new Set(["run","resume","abort","cancel_queued_run","approval.respond","clarify.respond"]),zne=["run.started","message.delta","message.interim","reasoning.delta","thinking.delta","reasoning.available","tool.started","tool.completed","tool.failed","workspace.diff.completed","run.completed","run.failed","compression.started","compression.completed","abort.started","abort.timeout","abort.completed","usage.updated","agent.event","subagent.event","session.command","session.title.updated","run.queued","approval.requested","approval.resolved","clarify.requested","clarify.resolved","peer.user.message","resumed"],Une=new Set(["message.delta","message.interim","reasoning.delta","thinking.delta","reasoning.available"]),loI=new Set(["connect","connect_error","disconnect","disconnecting","newListener","removeListener"]),One={mcuPlayback:!0,sampleRate:Ke},Bne=280;function Mne(I){let e=new URL(I),l=e.pathname.replace(/\/+$/,"");return l?l!==rw&&!l.endsWith(rw)&&(e.pathname=`${l}${rw}`):e.pathname=rw,e.toString()}function Sne(I){let e=Array.isArray(I.choices)?I.choices.map(t=>String(t)):[],l=e.length>0?e:["once","session","deny"];return l.includes("session")?"session":l.includes("once")?"once":l.includes("always")?"always":null}var sx=class{constructor(e){this.options=e}options;socket=null;localAgentSocket=null;stopped=!1;reconnectBlockedReason="";pendingVoice=null;pendingVoiceStream=null;localMcuForwardQueue=Promise.resolve();audioWaiters=new Map;activeRuns=new Map;sessionRuns=new Map;backgroundListeners=new Map;pendingBackgroundSpeech=new Map;backgroundSpeechRuns=new Set;interruptedInteractions=new Set;ttsAbortControllers=new Map;recentlyInterruptedSessions=new Map;pendingInterrupts=new Map;audioUploadToken="";audioUploadPath="/global-agent/audio";remoteMcuUserToken="";start(){this.socket||(this.stopped=!1,this.reconnectBlockedReason="",this.connect())}stop(){this.stopped=!0;for(let e of[...this.backgroundListeners.values()])e.close();this.backgroundListeners.clear(),this.pendingBackgroundSpeech.clear(),this.socket?.disconnect(),this.socket=null,this.localAgentSocket?.disconnect(),this.localAgentSocket=null,this.cancelPendingInterrupts(),this.rejectAudioWaiters(new Error("MCU Socket.IO relay stopped"))}isConnected(){return!!this.socket?.connected}waitForConnected(e=5e3){let l=this.socket;return l?l.connected?Promise.resolve(!0):new Promise(t=>{let n=()=>{clearTimeout(a),l.off("connect",c),l.off("connect_error",G)},c=()=>{n(),t(!0)},G=()=>{n(),t(!1)},a=setTimeout(()=>{n(),t(!1)},e);l.once("connect",c),l.once("connect_error",G)}):Promise.resolve(!1)}connect(){if(this.stopped)return;let e={token:this.options.relayToken||void 0,instanceId:this.options.instanceId||void 0,role:"hermes-studio",clientRole:"web",relayRole:"web",machine:this.options.machineInfo||void 0};this.options.deviceCode&&(e.deviceCode=this.options.deviceCode,e.device_code=this.options.deviceCode);let l=Mne(this.options.relayUrl),t=yl(l,{auth:e,transports:["websocket","polling"],reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:3e4,timeout:3e4});this.socket=t,t.on("connect",()=>{h.info({relayUrl:this.redactedRelayUrl()},"[outbound-relay:mcu-sio] connected"),this.connectLocalAgentSocket();for(let n of this.pendingBackgroundSpeech.keys())this.flushBackgroundSpeech(n)}),t.on("connect_error",n=>{h.warn({err:n,relayUrl:this.redactedRelayUrl()},"[outbound-relay:mcu-sio] connection error"),(n.message==="device_code_not_allowed"||n.message.includes("\u975E\u5B98\u65B9\u8BBE\u5907\u7801"))&&(this.stopped=!0,this.reconnectBlockedReason=n.message,t.io.opts.reconnection=!1)}),t.on("disconnect",n=>{this.localAgentSocket?.disconnect(),this.localAgentSocket=null,this.rejectAudioWaiters(new Error("MCU Socket.IO relay disconnected")),h.info({reason:n,reconnectBlockedReason:this.reconnectBlockedReason||void 0,relayUrl:this.redactedRelayUrl()},"[outbound-relay:mcu-sio] disconnected")}),t.on("http.request",(n,c)=>{this.handleHttpRequest(n).then(G=>this.respond(G,c)).catch(G=>this.respond(nG(n?.id,"relay_internal_error",G instanceof Error?G.message:String(G),500),c))}),t.onAny((n,c)=>{loI.has(n)||n!=="http.request"&&this.handleRemoteEvent(n,c)})}async handleHttpRequest(e){let l=noI(e.method);if(!l)return nG(e.id,"method_not_allowed","Relay request method is not allowed",405);let t=coI(e.path);if(!t)return nG(e.id,"path_not_allowed","Relay request path is not allowed",403);if(t!=="/api/auth/mcu-login")return nG(e.id,"path_not_allowed","MCU relay only allows the MCU login endpoint",403);let n=aoI(e.headers),c=soI(e,l,n);if(toI(c))return c;c.contentType&&n.set("content-type",c.contentType),t==="/api/auth/mcu-login"&&n.set("x-hermes-relay-forwarded","mcu-socket.io");let G=GoI(e.timeoutMs),a=new AbortController,s=setTimeout(()=>a.abort(),G);try{let d=await this.options.fetchImpl(`${this.options.localBaseUrl.replace(/\/$/,"")}${t}`,{method:l,headers:n,body:c.body,signal:a.signal}),r=await roI(d);return t==="/api/auth/mcu-login"&&d.ok&&typeof r.body=="string"&&this.rememberRemoteMcuLoginToken(r.body),{id:e.id,status:d.status,headers:doI(d),...r}}catch(d){let r=a.signal.aborted;return nG(e.id,r?"request_timeout":"local_request_failed",r?`Local relay request timed out after ${G}ms`:d instanceof Error?d.message:String(d),r?504:502)}finally{clearTimeout(s)}}respond(e,l){if(l){l(e);return}this.socket?.emit("http.response",e)}connectLocalAgentSocket(){let e=this.options.userToken||"";if(this.localAgentSocket||!e)return;let l=this.options.localBaseUrl.replace(/\/$/,""),t=yl(`${l}/global-agent`,{auth:{token:e,role:"hermes-studio",instanceId:this.options.instanceId||this.options.deviceCode||void 0},transports:["websocket","polling"],reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:3e4,timeout:3e4});this.localAgentSocket=t,t.on("connect",()=>{h.info({relayUrl:this.redactedRelayUrl(),localBaseUrl:l,instanceId:this.options.instanceId||this.options.deviceCode||void 0},"[outbound-relay:mcu-sio] local global-agent bridge connected")}),t.on("connect_error",n=>{h.warn({err:n,localBaseUrl:l},"[outbound-relay:mcu-sio] local global-agent bridge connection failed")}),t.on("disconnect",n=>{h.info({reason:n,localBaseUrl:l},"[outbound-relay:mcu-sio] local global-agent bridge disconnected"),this.localAgentSocket===t&&(this.localAgentSocket=null)}),t.onAny((n,c)=>{loI.has(n)||(this.localMcuForwardQueue=this.localMcuForwardQueue.then(()=>this.forwardLocalMcuEventToRelay(n,c)).catch(G=>{h.warn({err:G,relayUrl:this.redactedRelayUrl(),eventName:n},"[outbound-relay:mcu-sio] failed to forward local MCU event to relay")}))})}emitLocalMcuEvent(e,l){this.connectLocalAgentSocket(),this.localAgentSocket?.emit(e,this.payloadForLocalMcuSocket(l))}payloadForLocalMcuSocket(e){let l=this.options.userToken||"";if(!this.remoteMcuUserToken||!l)return e;let t={...e,apiToken:l};return delete t.api_token,delete t.authorization,t}rememberRemoteMcuLoginToken(e){let l="";try{let t=JSON.parse(e);l=typeof t.token=="string"?t.token.trim():""}catch{return}!l||l===this.remoteMcuUserToken||(this.remoteMcuUserToken=l)}async forwardLocalMcuEventToRelay(e,l){if(this.stopped)return;let t=Ki(l)?{...l,type:typeof l.type=="string"&&l.type?l.type:e}:{type:e,payload:l},n=await this.prepareMcuRelayPayload(t);this.sendJson(n)}async prepareMcuRelayPayload(e){if(e.type!=="audio.enqueue")return e;let l=typeof e.url=="string"?e.url.trim():"";if(!l)return e;let t=await this.uploadMcuAudioUrlToRelay(l).catch(n=>(h.warn({err:n,relayUrl:this.redactedRelayUrl(),url:l,interactionId:typeof e.interactionId=="string"?e.interactionId:void 0,segmentId:typeof e.segmentId=="string"?e.segmentId:void 0},"[outbound-relay:mcu-sio] failed to upload local MCU audio URL to relay"),""));return t?{...e,url:t}:e}sendJson(e){if(!this.socket?.connected||this.stopped)return;let l=typeof e.type=="string"&&e.type.trim()?e.type.trim():"mcu.event";this.socket.emit(l,e)}rejectAudioWaiters(e){for(let[l,t]of this.audioWaiters.entries())clearTimeout(t.timer),t.reject(e),this.audioWaiters.delete(l)}remoteMcuApiToken(e){let t=(typeof e.apiToken=="string"?e.apiToken:typeof e.api_token=="string"?e.api_token:typeof e.authorization=="string"?e.authorization:"").trim();return t.toLowerCase().startsWith("bearer ")?t.slice(7).trim():t}authorizeRemoteMcuEvent(e){let l=this.remoteMcuUserToken||this.options.userToken||"",t=this.remoteMcuApiToken(e);return!l||!t||t!==l?(h.warn({relayUrl:this.redactedRelayUrl(),type:typeof e.type=="string"?e.type:void 0,interactionId:typeof e.interactionId=="string"?e.interactionId:void 0},"[outbound-relay:mcu-sio] rejected remote MCU event with invalid API token"),this.sendTokenInvalidPrompt(e),!1):!0}async sendTokenInvalidPrompt(e){let l=lG("token-invalid");try{let t=await this.uploadMcuAudioUrlToRelay(l);t&&(l=t)}catch(t){h.warn({err:t,relayUrl:this.redactedRelayUrl()},"[outbound-relay:mcu-sio] failed to upload token invalid prompt")}this.sendJson({type:"auth.invalid",event:typeof e.type=="string"?e.type:void 0,interactionId:typeof e.interactionId=="string"?e.interactionId:void 0,text:rs("token-invalid"),url:l,mimeType:"audio/x-pcm",channels:1,sampleRate:Ke})}handleRemoteEvent(e,l){let t=Ki(l)?{...l,type:typeof l.type=="string"&&l.type?l.type:e}:{type:e,payload:l};if(h.info({relayUrl:this.redactedRelayUrl(),type:typeof t.type=="string"?t.type:void 0,status:typeof t.status=="string"?t.status:void 0,text:typeof t.text=="string"?t.text.slice(0,300):void 0,interactionId:typeof t.interactionId=="string"?t.interactionId:void 0},"[outbound-relay:mcu-sio] event"),t.type==="mcu.auth.ok"){let n=Ki(t.audioUpload)?t.audioUpload:null,c=typeof n?.token=="string"?n.token.trim():"";c&&(this.audioUploadToken=c,this.audioUploadPath=typeof n?.url=="string"&&n.url.trim()?n.url.trim():"/global-agent/audio");return}if(t.type==="relay.replaced"){this.reconnectBlockedReason="replaced",this.stopped=!0,h.warn({relayUrl:this.redactedRelayUrl(),deviceCode:typeof t.deviceCode=="string"?t.deviceCode:void 0,role:typeof t.role=="string"?t.role:void 0},"[outbound-relay:mcu-sio] remote relay connection replaced; relay left connected but inactive"),this.localAgentSocket?.disconnect(),this.localAgentSocket=null,this.cancelPendingInterrupts(),this.rejectAudioWaiters(new Error("remote relay connection replaced"));return}if(this.authorizeRemoteMcuEvent(t)){if(t.type==="voice.recorded"){this.pendingVoice={interactionId:typeof t.interactionId=="string"&&t.interactionId.trim()?t.interactionId.trim():`mcu-voice-${Date.now()}`,mimeType:typeof t.mimeType=="string"&&t.mimeType.trim()?t.mimeType.trim():"audio/wav",bytes:Number.isFinite(Number(t.bytes))?Number(t.bytes):0,profile:typeof t.profile=="string"&&t.profile.trim()?t.profile.trim():"default",agentRuntime:bs(t.agentRuntime)};return}if(t.type==="voice.stream.start"){this.pendingVoice=null,this.pendingVoiceStream={interactionId:typeof t.interactionId=="string"&&t.interactionId.trim()?t.interactionId.trim():`mcu-voice-${Date.now()}`,mimeType:typeof t.mimeType=="string"&&t.mimeType.trim()?t.mimeType.trim():"audio/pcm",bytes:0,profile:typeof t.profile=="string"&&t.profile.trim()?t.profile.trim():"default",agentRuntime:bs(t.agentRuntime),sampleRate:Number.isFinite(Number(t.sampleRate))?Number(t.sampleRate):Ke,channels:Number(t.channels)===1?1:2,bitsPerSample:(Number(t.bitsPerSample)===16,16),chunks:[]},this.emitLocalMcuEvent("voice.stream.start",t);return}if(t.type==="voice.stream.chunk"){let n=t.data,c;if(typeof n=="string")c=Buffer.from(n,"base64");else if(Buffer.isBuffer(n))c=Buffer.from(n);else if(n instanceof Uint8Array)c=Buffer.from(n.buffer,n.byteOffset,n.byteLength);else if(n instanceof ArrayBuffer)c=Buffer.from(n);else return;if(!c.length)return;if(this.pendingVoiceStream){let G=typeof t.interactionId=="string"?t.interactionId.trim():"";if(G&&G!==this.pendingVoiceStream.interactionId){h.warn({relayUrl:this.redactedRelayUrl(),streamInteractionId:this.pendingVoiceStream.interactionId,chunkInteractionId:G},"[outbound-relay:mcu-sio] ignoring stale voice stream chunk");return}let a=Number(t.offset),s=Number.isFinite(a)&&a>=0?Math.floor(a):this.pendingVoiceStream.bytes;this.pendingVoiceStream.chunks.push(c),this.pendingVoiceStream.bytes+=c.length,this.emitLocalMcuEvent("voice.stream.chunk",{...t,interactionId:this.pendingVoiceStream.interactionId,offset:s,bytes:c.length,seq:Number.isFinite(Number(t.seq))?Math.floor(Number(t.seq)):void 0,crc32:Number.isFinite(Number(t.crc32))?Math.floor(Number(t.crc32))>>>0:void 0,data:c});return}h.info({relayUrl:this.redactedRelayUrl(),bytes:c.length,interactionId:this.pendingVoice?.interactionId},"[outbound-relay:mcu-sio] voice chunk received without stream metadata"),this.handleVoiceAudio(c);return}if(t.type==="voice.stream.end"){let n=this.pendingVoiceStream;if(!n){this.sendJson({type:"interaction.status",status:"failed",text:"missing voice stream metadata"});return}let c=typeof t.interactionId=="string"?t.interactionId.trim():"";if(c&&c!==n.interactionId){h.warn({relayUrl:this.redactedRelayUrl(),streamInteractionId:n.interactionId,endInteractionId:c},"[outbound-relay:mcu-sio] ignoring stale voice stream end");return}this.pendingVoiceStream=null,h.info({relayUrl:this.redactedRelayUrl(),bytes:n.bytes,interactionId:n.interactionId},"[outbound-relay:mcu-sio] voice stream completed"),this.emitLocalMcuEvent("voice.stream.end",t);return}if(t.type==="voice.stream.abort"){this.pendingVoiceStream=null,this.emitLocalMcuEvent("voice.stream.abort",t);return}if(t.type==="audio.done"||t.type==="audio.interrupted"||t.type==="audio.dropped"){this.emitLocalMcuEvent(t.type,t),t.type==="audio.interrupted"&&typeof t.interactionId=="string"&&this.abortActiveRun(t.interactionId);let n=typeof t.segmentId=="string"?t.segmentId:"";if(!n)return;let c=this.audioWaiters.get(n);if(!c)return;clearTimeout(c.timer),this.audioWaiters.delete(n),t.type==="audio.done"?c.resolve():c.reject(new Error(t.type));return}if(t.type==="mcu.interrupt"){this.emitLocalMcuEvent("mcu.interrupt",t);return}if(t.type==="mcu.session.clear"){this.emitLocalMcuEvent("mcu.session.clear",t);return}typeof t.type=="string"&&t.type.trim()&&this.emitLocalMcuEvent(t.type.trim(),t)}}wrapPcmAsWav(e,l,t,n){let c=Buffer.alloc(44),G=l*t*n/8,a=t*n/8;return c.write("RIFF",0,"ascii"),c.writeUInt32LE(36+e.length,4),c.write("WAVE",8,"ascii"),c.write("fmt ",12,"ascii"),c.writeUInt32LE(16,16),c.writeUInt16LE(1,20),c.writeUInt16LE(t,22),c.writeUInt32LE(l,24),c.writeUInt32LE(G,28),c.writeUInt16LE(a,32),c.writeUInt16LE(n,34),c.write("data",36,"ascii"),c.writeUInt32LE(e.length,40),Buffer.concat([c,e],44+e.length)}async handleVoiceAudio(e,l){let t=l||this.pendingVoice;if(l||(this.pendingVoice=null),!t){this.sendJson({type:"interaction.status",status:"failed",text:"missing voice metadata"});return}if(!this.options.userToken){this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"failed",text:"missing Web UI auth token"});return}this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"transcribing"});try{let n=await this.options.fetchImpl(`${this.options.localBaseUrl.replace(/\/$/,"")}/api/hermes/mcu/voice-turn`,{method:"POST",headers:{Authorization:`Bearer ${this.options.userToken}`,"Content-Type":t.mimeType,"X-Hermes-Mcu-Interaction-Id":t.interactionId,"X-Hermes-Mcu-Agent-Runtime":t.agentRuntime,"X-Hermes-Profile":t.profile},body:new Uint8Array(e)}),c=await n.text(),G={};try{G=c?JSON.parse(c):{}}catch{G={error:c}}if(!n.ok||G.ok===!1){if(G.ok===!1&&await this.enqueuePromptAudioFromVoiceTurn(t.interactionId,G))return;this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"failed",text:typeof G.error=="string"?G.error:`voice turn failed: ${n.status}`});return}if(G.accepted===!0)return;let a=typeof G.transcript=="string"?G.transcript:"";if(!a.trim()){this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"completed",text:""});return}this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"thinking",text:a}),await this.runChatFromTranscript(t,a)}catch(n){this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"failed",text:n instanceof Error?n.message:String(n)})}}async runChatFromTranscript(e,l){await new Promise(t=>{let n=this.mcuSessionId(e.profile,e.agentRuntime),c=`mcu_${(0,iV.randomUUID)()}`;this.interruptedInteractions.delete(e.interactionId);let G=yl(`${this.options.localBaseUrl.replace(/\/$/,"")}/chat-run`,{auth:this.options.userToken?{token:this.options.userToken}:{},query:{profile:e.profile},transports:["websocket","polling"],reconnection:!1,timeout:3e4}),a="",s=0,d=Promise.resolve(),r=[],o=Promise.resolve(),b=!1,m=!1,i=!1,Z=!1,u=!1,p=!1,Y,W="",N=0,V=ZW(),R=()=>{let L=this.backgroundListeners.get(n);return Z||L?.socket===G},F=L=>{if(this.interruptedInteractions.has(e.interactionId))return;let q=Ti(L);if(!q)return;let S=`${e.interactionId}-tts-${++s}`;this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"speaking",text:q});let U=this.registerTtsAbortController(e.interactionId),aI=this.synthesizeMcuSpeech(q,e.profile,U.signal).then(lI=>({ok:!0,audio:lI})).catch(lI=>({ok:!1,err:lI,aborted:U.signal.aborted})).finally(()=>{this.releaseTtsAbortController(e.interactionId,U)});d=d.then(async()=>{await o;let lI=await this.enqueueMcuSpeechSegment(e.interactionId,S,q,aI);o=lI.playbackDone,r.push(lI.playbackDone)}).catch(lI=>{if(lI instanceof Error&&lI.message==="audio.interrupted"){this.interruptedInteractions.add(e.interactionId),h.info({interactionId:e.interactionId,segmentId:S},"[outbound-relay:ws] MCU speech interrupted by user");return}h.warn({err:lI,interactionId:e.interactionId,segmentId:S},"[outbound-relay:ws] failed to enqueue MCU speech"),this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"failed",text:lI instanceof Error?lI.message:String(lI)}),this.sendJson({type:"audio.enqueue",interactionId:e.interactionId,segmentId:`${S}-failed-prompt`,text:rs("tts-failed"),url:lG("tts-failed"),mimeType:"audio/x-pcm",format:"s16le",channels:1,sampleRate:Ke})})},X=()=>{let L=V.flush();L&&F(L)},v=()=>{i||(i=!0,t())},H=()=>{if(m)return;m=!0,this.activeRuns.delete(e.interactionId),this.sessionRuns.get(n)?.socket===G&&this.sessionRuns.delete(n),this.interruptedInteractions.delete(e.interactionId),clearTimeout(J),v(),this.flushBackgroundSpeech(n)},k=()=>{if(b)return;b=!0,H(),this.backgroundListeners.get(n)?.socket===G&&this.backgroundListeners.delete(n),G.removeAllListeners(),G.disconnect()},A=()=>{if(b)return;H();let L=this.backgroundListeners.get(n);L&&L.socket!==G&&L.close(),this.backgroundListeners.set(n,{socket:G,close:k}),h.info({interactionId:e.interactionId,sessionId:n,backgroundPending:N},"[outbound-relay:ws] keeping MCU session listener for background delivery")},Q=()=>{N>0?A():k()},E=L=>{this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"failed",text:L}),k()},J=setTimeout(()=>{E("chat-run timed out")},3e5);G.on("connect_error",L=>{E(L.message||"chat-run connection failed")}),G.on("disconnect",L=>{if(!b){if(m){h.warn({sessionId:n,reason:L},"[outbound-relay:ws] MCU background session listener disconnected"),k();return}E(`chat-run disconnected: ${L}`)}}),G.on("connect",()=>{h.info({interactionId:e.interactionId,sessionId:n,profile:e.profile,transcriptLength:l.length},"[outbound-relay:ws] starting chat-run"),this.activeRuns.set(e.interactionId,{socket:G,sessionId:n}),this.sessionRuns.set(n,{interactionId:e.interactionId,socket:G});let L={input:l,session_id:n,queue_id:c,profile:e.profile,...dw(e.agentRuntime)},q=this.recentlyInterruptedSessions.get(n)||0;if(Date.now()-q<1e4){G.emit("abort",{session_id:n}),setTimeout(()=>G.emit("run",L),800),this.recentlyInterruptedSessions.delete(n);return}G.emit("run",L)}),G.on("run.started",(L={})=>{let q=typeof L.queue_id=="string"?L.queue_id:void 0,S=L.autonomous===!0;u=!S&&q===c,p=S&&R(),Y=p&&typeof L.delegation_id=="string"&&L.delegation_id.trim()?L.delegation_id.trim():void 0,W="",u&&this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"thinking"})}),G.on("run.queued",(L={})=>{let q=Array.isArray(L.queued_messages)?L.queued_messages:[];(L.dequeued_queue_id===c||q.some(U=>typeof U=="object"&&U!==null&&U.id===c))&&(u=!1,this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"thinking"}))}),G.on("tool.started",(L={})=>{if(!u)return;X(),a="";let q=typeof L.tool=="string"?L.tool:typeof L.name=="string"?L.name:"tool";this.sendJson({type:"tool.started",interactionId:e.interactionId,tool:q})});let K=(L={},q=!1)=>{if(!u)return;let S=typeof L.tool=="string"?L.tool:typeof L.name=="string"?L.name:"tool",U=q?"tool.failed":void 0;this.sendJson({type:"tool.completed",interactionId:e.interactionId,tool:S,error:U})};G.on("tool.completed",(L={})=>K(L)),G.on("tool.failed",(L={})=>K(L,!0)),G.on("message.delta",(L={})=>{if(typeof L.delta=="string"){if(p){W+=L.delta;return}if(!u)return;a+=L.delta;for(let q of V.pushDelta(L.delta))F(q)}}),G.on("run.completed",(L={})=>{if(N=Math.max(0,Number(L.background_pending)||0),L.autonomous===!0||p){let aI=typeof L.output=="string"&&L.output.trim()?L.output:W;R()&&aI.trim()&&this.queueBackgroundSpeech(n,{profile:e.profile,delegationId:typeof L.delegation_id=="string"&&L.delegation_id.trim()?L.delegation_id.trim():Y,text:aI}),p=!1,u=!1,Y=void 0,W="",m&&N===0&&k();return}let S=typeof L.queue_id=="string"?L.queue_id:void 0;if(!(u||S===c)||Z){m&&N===0&&k();return}if(Z=!0,u=!1,typeof L.output=="string"&&L.output.trim())if(a){if(L.output.startsWith(a)&&L.output.length>a.length){let aI=L.output.slice(a.length);a=L.output;for(let lI of V.pushDelta(aI))F(lI)}}else{a=L.output;for(let aI of V.pushDelta(L.output))F(aI)}X(),d.then(async()=>{if(await Promise.all(r),this.interruptedInteractions.has(e.interactionId)){k();return}this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"completed"}),Q()}).catch(aI=>{if(this.interruptedInteractions.has(e.interactionId)||aI instanceof Error&&aI.message==="audio.interrupted"){k();return}E(aI instanceof Error?aI.message:String(aI))})}),G.on("run.failed",(L={})=>{N=Math.max(0,Number(L.background_pending)||0);let q=L.autonomous===!0||p,S=typeof L.queue_id=="string"?L.queue_id:void 0,U=u||S===c;if(p=!1,u=!1,Y=void 0,W="",q||!U||Z){m&&N===0&&k();return}Z=!0,this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"failed",text:typeof L.error=="string"?L.error:"chat-run failed"}),Q()}),G.on("delegation.updated",(L={})=>{L.background_pending!=null&&(N=Math.max(0,Number(L.background_pending)||0),m&&N===0&&k())}),G.on("approval.requested",(L={})=>{if(!u&&!p)return;let q=typeof L.approval_id=="string"?L.approval_id:"",S=Sne(L);if(!q||!S){E("approval required");return}h.info({interactionId:e.interactionId,sessionId:n,approvalId:q,choice:S},"[outbound-relay:ws] auto-approving MCU chat-run approval"),p||this.sendJson({type:"tool.started",interactionId:e.interactionId,tool:"approval"}),G.emit("approval.respond",{session_id:n,approval_id:q,choice:S})}),G.on("approval.resolved",(L={})=>{if(!u)return;let q=L.resolved!==!1;this.sendJson({type:"tool.completed",interactionId:e.interactionId,tool:"approval",error:q?void 0:"approval failed"})}),G.on("clarify.requested",()=>{u&&E("clarification required")})})}queueBackgroundSpeech(e,l){let t=l.text.trim();if(!t)return;let n=this.pendingBackgroundSpeech.get(e)||[];l.delegationId&&n.some(c=>c.delegationId===l.delegationId)||(n.push({...l,text:t}),this.pendingBackgroundSpeech.set(e,n),this.flushBackgroundSpeech(e))}async flushBackgroundSpeech(e){if(this.stopped||!this.socket?.connected||this.backgroundSpeechRuns.has(e)||this.sessionRuns.has(e))return;let l=this.pendingBackgroundSpeech.get(e);if(l?.length){this.backgroundSpeechRuns.add(e);try{for(;l.length>0&&!this.sessionRuns.has(e)&&this.socket?.connected;){let t=l.shift();if(!t)break;await this.playBackgroundSpeech(t)}}catch(t){t instanceof Error&&t.message==="audio.interrupted"||h.warn({err:t,sessionId:e},"[outbound-relay:ws] failed to deliver MCU background speech")}finally{this.backgroundSpeechRuns.delete(e),l.length===0&&this.pendingBackgroundSpeech.delete(e)}}}async playBackgroundSpeech(e){let t=`mcu-background-${(e.delegationId||(0,iV.randomUUID)()).toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,96)||(0,iV.randomUUID)()}`,n=ZW(),c=n.pushDelta(e.text),G=n.flush();G&&c.push(G);let a=0;try{for(let s of c){let d=Ti(s);if(!d)continue;let r=`${t}-tts-${++a}`,o=this.registerTtsAbortController(t),b=this.synthesizeMcuSpeech(d,e.profile,o.signal).then(i=>({ok:!0,audio:i})).catch(i=>({ok:!1,err:i,aborted:o.signal.aborted})).finally(()=>this.releaseTtsAbortController(t,o));if(await(await this.enqueueMcuSpeechSegment(t,r,d,b)).playbackDone,this.interruptedInteractions.has(t))throw new Error("audio.interrupted")}a>0&&this.sendJson({type:"interaction.status",interactionId:t,status:"completed"})}finally{this.interruptedInteractions.delete(t)}}async enqueuePromptAudioFromVoiceTurn(e,l){let t=Ki(l.audio)?l.audio:l,n=typeof t.url=="string"?t.url.trim():"";if(!n)return!1;let c=typeof t.text=="string"?t.text:"",G=typeof t.mimeType=="string"&&t.mimeType.trim()?t.mimeType.trim():"audio/x-pcm",a=Number(t.channels)===1?1:2,s=Number.isFinite(Number(t.sampleRate))&&Number(t.sampleRate)>0?Number(t.sampleRate):Ke,d=Number.isFinite(Number(t.durationMs))&&Number(t.durationMs)>0?Number(t.durationMs):Math.max(1200,Math.min(c.length*180,9e3)),r=`${e}-prompt`;this.sendJson({type:"interaction.status",interactionId:e,status:"speaking",text:c});let o=this.waitForMcuAudioDone(r,Math.max(3e4,d+2e4)).catch(b=>{h.warn({err:b,interactionId:e,segmentId:r},"[outbound-relay:ws] MCU prompt playback did not complete")});return this.sendJson({type:"audio.enqueue",interactionId:e,segmentId:r,text:c,url:n,mimeType:G,channels:a,sampleRate:s,durationMs:d}),await o,this.sendJson({type:"interaction.status",interactionId:e,status:"completed"}),!0}abortActiveRun(e){this.interruptedInteractions.add(e),this.abortTts(e);let l=this.activeRuns.get(e);l&&(h.info({interactionId:e,sessionId:l.sessionId},"[outbound-relay:ws] aborting chat-run after MCU audio interrupt"),l.socket.emit("abort",{session_id:l.sessionId}),this.activeRuns.delete(e),this.sessionRuns.delete(l.sessionId))}scheduleMcuInterrupt(e,l){let t=this.mcuSessionId(e);this.cancelPendingInterrupt(t);let n=setTimeout(()=>{this.pendingInterrupts.delete(t),this.interruptMcuSession(e,l)},Bne);this.pendingInterrupts.set(t,{profile:e,interactionId:l,timer:n})}cancelPendingInterrupt(e){let l=this.pendingInterrupts.get(e);l&&(clearTimeout(l.timer),this.pendingInterrupts.delete(e))}cancelPendingInterrupts(){for(let e of this.pendingInterrupts.values())clearTimeout(e.timer);this.pendingInterrupts.clear()}forgetMcuSessionRun(e,l){this.pendingBackgroundSpeech.delete(e),this.backgroundListeners.get(e)?.close();let t=this.sessionRuns.get(e);t&&(this.interruptedInteractions.add(t.interactionId),this.abortTts(t.interactionId),this.activeRuns.delete(t.interactionId),this.sessionRuns.delete(e)),l&&(this.interruptedInteractions.add(l),this.abortTts(l),this.activeRuns.get(l)?.sessionId===e&&(this.activeRuns.delete(l),this.sessionRuns.delete(e)))}interruptMcuSession(e,l){let t=this.mcuSessionId(e),n=this.sessionRuns.get(t),c=l?this.activeRuns.get(l):void 0,G=l?this.ttsAbortControllers.has(l):!1;if(l&&(n||c||G)&&(this.interruptedInteractions.add(l),this.abortTts(l)),n){this.recentlyInterruptedSessions.set(t,Date.now()),this.interruptedInteractions.add(n.interactionId),this.abortTts(n.interactionId),h.info({interactionId:n.interactionId,sessionId:t},"[outbound-relay:ws] aborting chat-run after MCU interrupt"),n.socket.emit("abort",{session_id:t}),this.activeRuns.delete(n.interactionId),this.sessionRuns.delete(t);return}l&&c?.sessionId===t&&(this.recentlyInterruptedSessions.set(t,Date.now()),this.abortActiveRun(l))}registerTtsAbortController(e){let l=new AbortController;if(this.interruptedInteractions.has(e))return l.abort(),l;let t=this.ttsAbortControllers.get(e)||new Set;return t.add(l),this.ttsAbortControllers.set(e,t),l}releaseTtsAbortController(e,l){let t=this.ttsAbortControllers.get(e);t&&(t.delete(l),t.size===0&&this.ttsAbortControllers.delete(e))}abortTts(e){let l=this.ttsAbortControllers.get(e);if(l){for(let t of l)t.signal.aborted||t.abort();this.ttsAbortControllers.delete(e)}}clearMcuSession(e,l){let t=this.mcuSessionId(e);this.cancelPendingInterrupt(t),this.forgetMcuSessionRun(t,l);let n=$c()?.clearSessionHistory(t),c=n?.deleted??$b(t),G=n?.hadMemoryState??!1;h.info({sessionId:t,deleted:c,memoryCleared:G},"[outbound-relay:ws] cleared MCU chat session"),this.sendJson({type:"mcu.session.cleared",interactionId:l||void 0,profile:e,sessionId:t,deleted:c,memoryCleared:G})}mcuSessionId(e,l=nx){let t=(this.options.instanceId||"device").toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"device",n=(e||"default").toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"default";return`mcu-${t}-${n}-${l}`}async enqueueMcuSpeechSegment(e,l,t,n){if(this.interruptedInteractions.has(e))return{playbackDone:Promise.resolve()};let c=await n;if(!c.ok)throw c.aborted?new Error("audio.interrupted"):c.err;if(this.interruptedInteractions.has(e))return{playbackDone:Promise.resolve()};let G=this.waitForMcuAudioDone(l,Math.max(9e4,Math.min(t.length*1200,3e5)));return G.catch(()=>{}),this.sendJson({type:"audio.enqueue",interactionId:e,segmentId:l,text:t,url:c.audio.url,mimeType:c.audio.mimeType,channels:1,sampleRate:Ke,durationMs:Math.max(1200,Math.min(t.length*180,12e3)),completionManagedByServer:!0}),{playbackDone:G}}waitForMcuAudioDone(e,l){return new Promise((t,n)=>{let c=setTimeout(()=>{this.audioWaiters.delete(e),n(new Error(`MCU audio playback timed out: ${e}`))},l);this.audioWaiters.set(e,{resolve:t,reject:n,timer:c})})}async synthesizeMcuSpeech(e,l,t){if(!this.options.userToken)throw new Error("missing Web UI auth token");let n=this.options.localBaseUrl.replace(/\/$/,""),c={Authorization:`Bearer ${this.options.userToken}`,"Content-Type":"application/json","X-Hermes-Profile":l||"default"},G=Z=>this.options.fetchImpl(`${n}/api/hermes/tts/synthesize`,{method:"POST",headers:c,signal:t,body:JSON.stringify({...Z?{provider:Z}:{},text:e,options:One})}),a=async(Z,u)=>{let p=Buffer.from(await Z.arrayBuffer());if(!p.length)throw new Error(`${u} returned empty audio`);let Y=String(Z.headers.get("content-type")||"").split(";")[0].trim().toLowerCase(),W=p.length;if(Y==="audio/x-pcm"||Y==="audio/pcm")return h.info({context:u,contentType:Y,sourceBytes:W,pcmBytes:p.length},"[outbound-relay-client] MCU TTS PCM audio ready"),p;let N=await Gw(p,Y||"application/octet-stream",{sampleRate:Ke});if(N.mimeType!=="audio/x-pcm")throw new Error(`${u} returned ${Y||"unknown content type"} and PCM conversion is unavailable`);if(p=N.audio,!p.length)throw new Error(`${u} PCM conversion returned empty audio`);return h.info({context:u,contentType:Y||"application/octet-stream",sourceBytes:W,pcmBytes:p.length,sampleRate:Ke},"[outbound-relay-client] MCU TTS decoded to PCM"),p},s=await G();if(!s.ok){let Z=await s.text().catch(()=>"");if(h.warn({status:s.status,detail:Z.slice(0,200)},"[outbound-relay-client] active MCU TTS failed, falling back to Edge TTS"),s=await G("edge"),!s.ok){let u=await s.text().catch(()=>"");throw new Error(`MCU TTS failed and Edge fallback failed: ${s.status}${u?` ${u.slice(0,200)}`:""}`)}}let d;try{d=await a(s,"MCU TTS")}catch(Z){h.warn({err:Z},"[outbound-relay-client] MCU TTS audio decode failed, falling back to Edge TTS");let u=await G("edge");if(!u.ok){let p=await u.text().catch(()=>"");throw new Error(`MCU TTS decode failed and Edge fallback failed: ${u.status}${p?` ${p.slice(0,200)}`:""}`)}d=await a(u,"MCU Edge TTS fallback")}let r=(0,ax.join)(B.appHome,"mcu-audio");await(0,ow.mkdir)(r,{recursive:!0});let o=`${(0,iV.randomUUID)()}.adpcm`,b=aw(d,Ke);await(0,ow.writeFile)((0,ax.join)(r,o),b),h.info({file:o,textChars:e.length,pcmBytes:d.length,adpcmBytes:b.length,ratio:d.length>0?Number((b.length/d.length).toFixed(3)):0},"[outbound-relay-client] MCU TTS encoded to ADPCM");let m=`${n}/api/hermes/mcu/audio/${o}`;return{url:await this.uploadMcuAudioToRelay(b,"audio/x-ima-adpcm",t).catch(Z=>(h.warn({err:Z,relayUrl:this.redactedRelayUrl(),bytes:b.length},"[outbound-relay:ws] failed to upload MCU audio to relay"),""))||m,mimeType:"audio/x-ima-adpcm"}}relayHttpBaseUrl(){let e=new URL(this.options.relayUrl);return e.protocol==="ws:"&&(e.protocol="http:"),e.protocol==="wss:"&&(e.protocol="https:"),e.pathname="",e.search="",e.hash="",e.toString().replace(/\/$/,"")}resolveRelayAudioUploadUrl(){let e=this.relayHttpBaseUrl();if(/^https?:\/\//i.test(this.audioUploadPath))return this.audioUploadPath;let l=this.audioUploadPath.startsWith("/")?this.audioUploadPath:`/${this.audioUploadPath}`;return`${e}${l}`}async uploadMcuAudioToRelay(e,l="audio/x-pcm",t){if(!this.audioUploadToken||!this.options.deviceCode)return"";let n=this.resolveRelayAudioUploadUrl(),c=await this.options.fetchImpl(n,{method:"POST",headers:{Authorization:`Bearer ${this.audioUploadToken}`,"Content-Type":l,"X-Device-Code":this.options.deviceCode,"X-Audio-Sample-Rate":String(Ke),"X-Audio-Channels":"1"},body:new Uint8Array(e),signal:t}),G=await c.text(),a={};try{a=G?JSON.parse(G):{}}catch{a={error:G}}if(!c.ok||a.ok===!1){let r=typeof a.error=="string"?a.error:`relay audio upload failed: ${c.status}`;throw new Error(r)}let s=typeof a.url=="string"?a.url.trim():"";if(s)return s;let d=typeof a.path=="string"?a.path.trim():"";if(!d)throw new Error("relay audio upload did not return a URL");return`${this.relayHttpBaseUrl()}${d.startsWith("/")?d:`/${d}`}`}resolveLocalAudioUrl(e){if(/^https?:\/\//i.test(e))return e;let l=e.startsWith("/")?e:`/${e}`;return`${this.options.localBaseUrl.replace(/\/$/,"")}${l}`}async uploadMcuAudioUrlToRelay(e){if(!this.audioUploadToken||!this.options.deviceCode)return"";let l=this.resolveLocalAudioUrl(e),t=await this.options.fetchImpl(l,{method:"GET",headers:this.options.userToken?{Authorization:`Bearer ${this.options.userToken}`}:void 0});if(!t.ok){let G=await t.text().catch(()=>"");throw new Error(`local MCU audio fetch failed: ${t.status}${G?` ${G.slice(0,120)}`:""}`)}let n=Buffer.from(await t.arrayBuffer());if(!n.length)throw new Error("local MCU audio fetch returned empty audio");let c=String(t.headers.get("content-type")||"").split(";")[0].trim().toLowerCase()||"audio/x-pcm";return await this.uploadMcuAudioToRelay(n,c,void 0)}redactedRelayUrl(){try{let e=new URL(this.options.relayUrl);return(e.username||e.password)&&(e.username=e.username?"[redacted]":"",e.password=e.password?"[redacted]":""),e.toString()}catch{return"[invalid relay url]"}}};function nG(I,e,l,t){return{id:I,...t?{status:t}:{},error:{code:e,message:l}}}function uW(I,e,l){return{id:I,ok:!1,error:{code:e,message:l}}}function toI(I){return"error"in I}function noI(I){let e=String(I||"GET").trim().toUpperCase();return Ane.has(e)?e:null}function coI(I){let e=String(I||"").trim();if(!e||!e.startsWith("/")||e.startsWith("//"))return null;let l=new URL(e,"http://hermes-relay.local"),t=`${l.pathname}${l.search}`;return l.pathname==="/v1"||l.pathname.startsWith("/v1/")?null:t}function Gx(I){let e=String(I||"").trim();return!e||e.length>128?null:e}function jne(I){let e=String(I||"").trim();return fne.has(e)?e:null}function Tne(I){let e={};for(let[l,t]of Object.entries(I||{}))t!=null&&(e[l]=String(t));return e}function Kne(I){let e={};for(let[l,t]of Object.entries(I||{}))t!=null&&(e[l]=t);return e}function Ki(I){return!!I&&typeof I=="object"&&!Array.isArray(I)}function Dne(I,e=!0){return typeof I=="boolean"?I:e}function GoI(I){let e=Number(I);return!Number.isFinite(e)||e<=0?Cne:Math.min(Math.floor(e),Jne)}function aoI(I){let e=new Headers;for(let[l,t]of Object.entries(I||{})){let n=l.toLowerCase();if(!kne.has(n)||t==null)continue;let c=Array.isArray(t)?t.find(Boolean):t;c&&e.set(n,String(c))}return e}function soI(I,e,l){if(e==="GET"||e==="HEAD")return{byteLength:0};if(typeof I.bodyBase64=="string"){let c=Buffer.from(I.bodyBase64,"base64");return c.byteLength>cx?nG(I.id,"request_body_too_large","Relay request body exceeds the local size limit",413):{body:c,byteLength:c.byteLength}}if(I.body==null)return{byteLength:0};if(typeof I.body=="string"){let c=Buffer.byteLength(I.body);return c>cx?nG(I.id,"request_body_too_large","Relay request body exceeds the local size limit",413):{body:I.body,byteLength:c}}let t=JSON.stringify(I.body),n=Buffer.byteLength(t);return n>cx?nG(I.id,"request_body_too_large","Relay request body exceeds the local size limit",413):l.has("content-type")?{body:t,byteLength:n}:{body:t,contentType:"application/json",byteLength:n}}function doI(I){let e={};return I.headers.forEach((l,t)=>{let n=t.toLowerCase();n==="connection"||n==="transfer-encoding"||(e[n]=l)}),e}function _ne(I){let e=I.toLowerCase();return Lne.some(l=>e.startsWith(l)||e.includes(l))}async function roI(I){let e=I.headers.get("content-type")||"";if(!I.body)return{};let l=I.body.getReader(),t=[],n=0,c=!1;for(;;){let{done:a,value:s}=await l.read();if(a)break;let d=Buffer.from(s);if(n+=d.byteLength,n>eoI){let r=Math.max(0,eoI-(n-d.byteLength));r>0&&t.push(d.subarray(0,r)),c=!0,await l.cancel();break}t.push(d)}let G=Buffer.concat(t);return _ne(e)?{body:G.toString("utf-8"),truncated:c}:{bodyBase64:G.toString("base64"),truncated:c}}var dx=class{socket=null;socketBridges=new Map;relayUrl;relayToken;instanceId;deviceCode;localBaseUrl;machineInfo;fetchImpl;constructor(e){this.relayUrl=e.relayUrl,this.relayToken=e.relayToken,this.instanceId=e.instanceId,this.deviceCode=e.deviceCode,this.localBaseUrl=e.localBaseUrl.replace(/\/$/,""),this.machineInfo=e.machineInfo,this.fetchImpl=e.fetchImpl}start(){if(this.socket)return;let e={role:"hermes-studio"};this.relayToken&&(e.token=this.relayToken),this.deviceCode&&(e.deviceCode=this.deviceCode,e.device_code=this.deviceCode),this.instanceId&&(e.instanceId=this.instanceId),this.machineInfo&&(e.machine=this.machineInfo),this.socket=yl(this.relayUrl,{auth:e,transports:["websocket","polling"],reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:3e4,timeout:3e4}),this.socket.on("connect",()=>{h.info({relayUrl:this.redactedRelayUrl()},"[outbound-relay] connected"),this.socket?.emit("relay.ready",{capabilities:["http.request","socket.chat-run"],instanceId:this.instanceId||void 0})}),this.socket.on("connect_error",l=>{h.warn({err:l,relayUrl:this.redactedRelayUrl()},"[outbound-relay] connection failed"),(l.message==="device_code_not_allowed"||l.message.includes("\u975E\u5B98\u65B9\u8BBE\u5907\u7801"))&&this.stop()}),this.socket.on("disconnect",l=>{h.info({reason:l,relayUrl:this.redactedRelayUrl()},"[outbound-relay] disconnected")}),this.socket.on("relay.replaced",l=>{h.warn({payload:l,relayUrl:this.redactedRelayUrl()},"[outbound-relay] remote relay connection replaced; reconnect disabled"),this.stop()}),this.socket.on("http.request",(l,t)=>{this.handleHttpRequest(l).then(n=>this.respond(n,t)).catch(n=>this.respond(nG(l?.id,"relay_internal_error",n instanceof Error?n.message:String(n),500),t))}),this.socket.on("socket.open",(l,t)=>{this.respondSocket(this.openLocalSocket(l),t)}),this.socket.on("socket.event",(l,t)=>{this.respondSocket(this.emitLocalSocketEvent(l),t)}),this.socket.on("socket.close",(l,t)=>{this.respondSocket(this.closeLocalSocket(l),t)})}stop(){for(let e of this.socketBridges.values())e.socket.disconnect();this.socketBridges.clear(),this.socket?.disconnect(),this.socket=null}isConnected(){return!!this.socket?.connected}waitForConnected(e=5e3){let l=this.socket;return l?l.connected?Promise.resolve(!0):new Promise(t=>{let n=()=>{clearTimeout(a),l.off("connect",c),l.off("connect_error",G)},c=()=>{n(),t(!0)},G=()=>{n(),t(!1)},a=setTimeout(()=>{n(),t(!1)},e);l.once("connect",c),l.once("connect_error",G)}):Promise.resolve(!1)}async handleHttpRequest(e){let l=noI(e.method);if(!l)return nG(e.id,"method_not_allowed","Relay request method is not allowed",405);let t=coI(e.path);if(!t)return nG(e.id,"path_not_allowed","Relay request path is not allowed",403);let n=aoI(e.headers),c=soI(e,l,n);if(toI(c))return c;c.contentType&&n.set("content-type",c.contentType);let G=GoI(e.timeoutMs),a=new AbortController,s=setTimeout(()=>a.abort(),G);try{let d=await this.fetchImpl(`${this.localBaseUrl}${t}`,{method:l,headers:n,body:c.body,signal:a.signal}),r=await roI(d);return{id:e.id,status:d.status,headers:doI(d),...r}}catch(d){let r=a.signal.aborted;return nG(e.id,r?"request_timeout":"local_request_failed",r?`Local relay request timed out after ${G}ms`:d instanceof Error?d.message:String(d),r?504:502)}finally{clearTimeout(s)}}respond(e,l){if(l){l(e);return}this.socket?.emit("http.response",e)}openLocalSocket(e){let l=Gx(e.id);if(!l)return uW(e.id,"invalid_socket_id","Relay socket id is required");let t=jne(e.namespace);if(!t)return uW(l,"namespace_not_allowed","Relay socket namespace is not allowed");this.closeLocalSocket({id:l});let n=yl(`${this.localBaseUrl}${t}`,{auth:Kne(e.auth),query:Tne(e.query),transports:["websocket","polling"],reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:3e4,timeout:3e4}),c={id:l,namespace:t,socket:n,stream:Dne(e.stream),output:"",reasoning:""};this.socketBridges.set(l,c),n.on("connect",()=>{this.emitSocketEvent({id:l,namespace:t,event:"connect",payload:{socketId:n.id}})}),n.on("connect_error",G=>{this.emitSocketEvent({id:l,namespace:t,event:"connect_error",payload:{message:G.message}})}),n.on("disconnect",G=>{this.emitSocketEvent({id:l,namespace:t,event:"disconnect",payload:{reason:G}})});for(let G of zne)n.on(G,a=>{this.handleLocalSocketEvent(c,G,a)});return{id:l,ok:!0,namespace:t,stream:c.stream}}emitLocalSocketEvent(e){let l=Gx(e.id);if(!l)return uW(e.id,"invalid_socket_id","Relay socket id is required");let t=String(e.event||"").trim();if(!xne.has(t))return uW(l,"event_not_allowed","Relay socket event is not allowed");let n=this.socketBridges.get(l);return n?(typeof e.stream=="boolean"&&(n.stream=e.stream),t==="run"&&(n.output="",n.reasoning=""),n.socket.emit(t,e.payload),{id:l,ok:!0,namespace:n.namespace,event:t,stream:n.stream}):uW(l,"socket_not_open","Relay socket is not open")}closeLocalSocket(e){let l=Gx(e.id);if(!l)return uW(e.id,"invalid_socket_id","Relay socket id is required");let t=this.socketBridges.get(l);return t?(t.socket.disconnect(),this.socketBridges.delete(l),{id:l,ok:!0,namespace:t.namespace}):{id:l,ok:!0}}emitSocketEvent(e){this.socket?.emit("socket.event",{id:e.id,namespace:e.namespace,event:e.event,payload:e.payload})}handleLocalSocketEvent(e,l,t){if(!e.stream){if(l==="message.delta"&&Ki(t)&&typeof t.delta=="string"){e.output+=t.delta;return}if((l==="reasoning.delta"||l==="thinking.delta")&&Ki(t)){let n=typeof t.delta=="string"?t.delta:typeof t.text=="string"?t.text:"";e.reasoning+=n;return}if(Une.has(l))return;if(l==="run.completed"){this.emitSocketEvent({id:e.id,namespace:e.namespace,event:l,payload:this.withNonStreamingOutput(t,e)});return}}this.emitSocketEvent({id:e.id,namespace:e.namespace,event:l,payload:t})}withNonStreamingOutput(e,l){return Ki(e)?{...e,output:typeof e.output=="string"&&e.output?e.output:l.output,...l.reasoning&&typeof e.reasoning!="string"?{reasoning:l.reasoning}:{}}:{output:l.output,...l.reasoning?{reasoning:l.reasoning}:{}}}respondSocket(e,l){if(l){l(e);return}this.socket?.emit("socket.response",e)}redactedRelayUrl(){try{let e=new URL(this.relayUrl);return e.username="",e.password="",e.toString()}catch{return"<invalid-url>"}}},io=new Map;function qne(I,e){return(I.connectionId||I.instanceId||e).trim()}function bw(I={}){let e=(I.relayUrl??"").trim();if(!e)return null;let l=qne(I,e),t=io.get(l);if(t)return t;let n={relayUrl:e,relayToken:I.relayToken??"",userToken:I.userToken??"",instanceId:I.instanceId??"",deviceCode:I.deviceCode??"",localBaseUrl:I.localBaseUrl??`http://127.0.0.1:${B.port}`,machineInfo:I.machineInfo,fetchImpl:I.fetchImpl??fetch},c=I.relayProtocol==="mcu-socket.io"?new sx(n):new dx(n);return c.start(),io.set(l,c),c}function ooI(I){return I?io.get(I)||null:io.values().next().value||null}function mo(I){if(I){io.get(I)?.stop(),io.delete(I);return}for(let e of io.values())e.stop();io.clear()}var ebI=require("crypto");wi();AI();dI();var ms=require("os"),Wo=require("crypto");var VW=require("fs/promises"),pw=require("path");AI();uo();var Vx=(0,pw.resolve)(B.appHome,"device-identity.json"),Rx=null;function Fx(){return"0.6.40"}function Fce(I){return I.split(`
|
|
1594
|
+
`);var nx="ekko";function bs(I){return typeof I=="string"&&I.trim().toLowerCase()==="hermes"?"hermes":nx}function dw(I){return I==="hermes"?{source:"global_agent",session_source:"global_agent",instructions:tx}:{source:"coding_agent",session_source:"global_agent",coding_agent_id:"ekko-agent",instructions:tx}}var Cne=3e4,Jne=12e4,cx=5*1024*1024,eoI=10*1024*1024,rw="/global-agent",Ane=new Set(["GET","POST","PUT","PATCH","DELETE","HEAD"]),kne=new Set(["accept","accept-language","authorization","content-type","x-hermes-profile","x-request-id"]),Lne=["application/json","application/problem+json","application/x-ndjson","application/javascript","application/xml","application/x-www-form-urlencoded","text/"],fne=new Set(["/chat-run"]),xne=new Set(["run","resume","abort","cancel_queued_run","approval.respond","clarify.respond"]),zne=["run.started","message.delta","message.interim","reasoning.delta","thinking.delta","reasoning.available","tool.started","tool.completed","tool.failed","workspace.diff.completed","run.completed","run.failed","compression.started","compression.completed","abort.started","abort.timeout","abort.completed","usage.updated","agent.event","subagent.event","session.command","session.title.updated","run.queued","approval.requested","approval.resolved","clarify.requested","clarify.resolved","peer.user.message","resumed"],Une=new Set(["message.delta","message.interim","reasoning.delta","thinking.delta","reasoning.available"]),loI=new Set(["connect","connect_error","disconnect","disconnecting","newListener","removeListener"]),One={mcuPlayback:!0,sampleRate:Ke},Bne=280;function Mne(I){let e=new URL(I),l=e.pathname.replace(/\/+$/,"");return l?l!==rw&&!l.endsWith(rw)&&(e.pathname=`${l}${rw}`):e.pathname=rw,e.toString()}function Sne(I){let e=Array.isArray(I.choices)?I.choices.map(t=>String(t)):[],l=e.length>0?e:["once","session","deny"];return l.includes("session")?"session":l.includes("once")?"once":l.includes("always")?"always":null}var sx=class{constructor(e){this.options=e}options;socket=null;localAgentSocket=null;stopped=!1;reconnectBlockedReason="";pendingVoice=null;pendingVoiceStream=null;localMcuForwardQueue=Promise.resolve();audioWaiters=new Map;activeRuns=new Map;sessionRuns=new Map;backgroundListeners=new Map;pendingBackgroundSpeech=new Map;backgroundSpeechRuns=new Set;interruptedInteractions=new Set;ttsAbortControllers=new Map;recentlyInterruptedSessions=new Map;pendingInterrupts=new Map;audioUploadToken="";audioUploadPath="/global-agent/audio";remoteMcuUserToken="";start(){this.socket||(this.stopped=!1,this.reconnectBlockedReason="",this.connect())}stop(){this.stopped=!0;for(let e of[...this.backgroundListeners.values()])e.close();this.backgroundListeners.clear(),this.pendingBackgroundSpeech.clear(),this.socket?.disconnect(),this.socket=null,this.localAgentSocket?.disconnect(),this.localAgentSocket=null,this.cancelPendingInterrupts(),this.rejectAudioWaiters(new Error("MCU Socket.IO relay stopped"))}isConnected(){return!!this.socket?.connected}waitForConnected(e=5e3){let l=this.socket;return l?l.connected?Promise.resolve(!0):new Promise(t=>{let n=()=>{clearTimeout(a),l.off("connect",c),l.off("connect_error",G)},c=()=>{n(),t(!0)},G=()=>{n(),t(!1)},a=setTimeout(()=>{n(),t(!1)},e);l.once("connect",c),l.once("connect_error",G)}):Promise.resolve(!1)}connect(){if(this.stopped)return;let e={token:this.options.relayToken||void 0,instanceId:this.options.instanceId||void 0,role:"hermes-studio",clientRole:"web",relayRole:"web",machine:this.options.machineInfo||void 0};this.options.deviceCode&&(e.deviceCode=this.options.deviceCode,e.device_code=this.options.deviceCode);let l=Mne(this.options.relayUrl),t=yl(l,{auth:e,transports:["websocket","polling"],reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:3e4,timeout:3e4});this.socket=t,t.on("connect",()=>{h.info({relayUrl:this.redactedRelayUrl()},"[outbound-relay:mcu-sio] connected"),this.connectLocalAgentSocket();for(let n of this.pendingBackgroundSpeech.keys())this.flushBackgroundSpeech(n)}),t.on("connect_error",n=>{h.warn({err:n,relayUrl:this.redactedRelayUrl()},"[outbound-relay:mcu-sio] connection error"),(n.message==="device_code_not_allowed"||n.message.includes("\u975E\u5B98\u65B9\u8BBE\u5907\u7801"))&&(this.stopped=!0,this.reconnectBlockedReason=n.message,t.io.opts.reconnection=!1)}),t.on("disconnect",n=>{this.localAgentSocket?.disconnect(),this.localAgentSocket=null,this.rejectAudioWaiters(new Error("MCU Socket.IO relay disconnected")),h.info({reason:n,reconnectBlockedReason:this.reconnectBlockedReason||void 0,relayUrl:this.redactedRelayUrl()},"[outbound-relay:mcu-sio] disconnected")}),t.on("http.request",(n,c)=>{this.handleHttpRequest(n).then(G=>this.respond(G,c)).catch(G=>this.respond(nG(n?.id,"relay_internal_error",G instanceof Error?G.message:String(G),500),c))}),t.onAny((n,c)=>{loI.has(n)||n!=="http.request"&&this.handleRemoteEvent(n,c)})}async handleHttpRequest(e){let l=noI(e.method);if(!l)return nG(e.id,"method_not_allowed","Relay request method is not allowed",405);let t=coI(e.path);if(!t)return nG(e.id,"path_not_allowed","Relay request path is not allowed",403);if(t!=="/api/auth/mcu-login")return nG(e.id,"path_not_allowed","MCU relay only allows the MCU login endpoint",403);let n=aoI(e.headers),c=soI(e,l,n);if(toI(c))return c;c.contentType&&n.set("content-type",c.contentType),t==="/api/auth/mcu-login"&&n.set("x-hermes-relay-forwarded","mcu-socket.io");let G=GoI(e.timeoutMs),a=new AbortController,s=setTimeout(()=>a.abort(),G);try{let d=await this.options.fetchImpl(`${this.options.localBaseUrl.replace(/\/$/,"")}${t}`,{method:l,headers:n,body:c.body,signal:a.signal}),r=await roI(d);return t==="/api/auth/mcu-login"&&d.ok&&typeof r.body=="string"&&this.rememberRemoteMcuLoginToken(r.body),{id:e.id,status:d.status,headers:doI(d),...r}}catch(d){let r=a.signal.aborted;return nG(e.id,r?"request_timeout":"local_request_failed",r?`Local relay request timed out after ${G}ms`:d instanceof Error?d.message:String(d),r?504:502)}finally{clearTimeout(s)}}respond(e,l){if(l){l(e);return}this.socket?.emit("http.response",e)}connectLocalAgentSocket(){let e=this.options.userToken||"";if(this.localAgentSocket||!e)return;let l=this.options.localBaseUrl.replace(/\/$/,""),t=yl(`${l}/global-agent`,{auth:{token:e,role:"hermes-studio",instanceId:this.options.instanceId||this.options.deviceCode||void 0},transports:["websocket","polling"],reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:3e4,timeout:3e4});this.localAgentSocket=t,t.on("connect",()=>{h.info({relayUrl:this.redactedRelayUrl(),localBaseUrl:l,instanceId:this.options.instanceId||this.options.deviceCode||void 0},"[outbound-relay:mcu-sio] local global-agent bridge connected")}),t.on("connect_error",n=>{h.warn({err:n,localBaseUrl:l},"[outbound-relay:mcu-sio] local global-agent bridge connection failed")}),t.on("disconnect",n=>{h.info({reason:n,localBaseUrl:l},"[outbound-relay:mcu-sio] local global-agent bridge disconnected"),this.localAgentSocket===t&&(this.localAgentSocket=null)}),t.onAny((n,c)=>{loI.has(n)||(this.localMcuForwardQueue=this.localMcuForwardQueue.then(()=>this.forwardLocalMcuEventToRelay(n,c)).catch(G=>{h.warn({err:G,relayUrl:this.redactedRelayUrl(),eventName:n},"[outbound-relay:mcu-sio] failed to forward local MCU event to relay")}))})}emitLocalMcuEvent(e,l){this.connectLocalAgentSocket(),this.localAgentSocket?.emit(e,this.payloadForLocalMcuSocket(l))}payloadForLocalMcuSocket(e){let l=this.options.userToken||"";if(!this.remoteMcuUserToken||!l)return e;let t={...e,apiToken:l};return delete t.api_token,delete t.authorization,t}rememberRemoteMcuLoginToken(e){let l="";try{let t=JSON.parse(e);l=typeof t.token=="string"?t.token.trim():""}catch{return}!l||l===this.remoteMcuUserToken||(this.remoteMcuUserToken=l)}async forwardLocalMcuEventToRelay(e,l){if(this.stopped)return;let t=Ki(l)?{...l,type:typeof l.type=="string"&&l.type?l.type:e}:{type:e,payload:l},n=await this.prepareMcuRelayPayload(t);this.sendJson(n)}async prepareMcuRelayPayload(e){if(e.type!=="audio.enqueue")return e;let l=typeof e.url=="string"?e.url.trim():"";if(!l)return e;let t=await this.uploadMcuAudioUrlToRelay(l).catch(n=>(h.warn({err:n,relayUrl:this.redactedRelayUrl(),url:l,interactionId:typeof e.interactionId=="string"?e.interactionId:void 0,segmentId:typeof e.segmentId=="string"?e.segmentId:void 0},"[outbound-relay:mcu-sio] failed to upload local MCU audio URL to relay"),""));return t?{...e,url:t}:e}sendJson(e){if(!this.socket?.connected||this.stopped)return;let l=typeof e.type=="string"&&e.type.trim()?e.type.trim():"mcu.event";this.socket.emit(l,e)}rejectAudioWaiters(e){for(let[l,t]of this.audioWaiters.entries())clearTimeout(t.timer),t.reject(e),this.audioWaiters.delete(l)}remoteMcuApiToken(e){let t=(typeof e.apiToken=="string"?e.apiToken:typeof e.api_token=="string"?e.api_token:typeof e.authorization=="string"?e.authorization:"").trim();return t.toLowerCase().startsWith("bearer ")?t.slice(7).trim():t}authorizeRemoteMcuEvent(e){let l=this.remoteMcuUserToken||this.options.userToken||"",t=this.remoteMcuApiToken(e);return!l||!t||t!==l?(h.warn({relayUrl:this.redactedRelayUrl(),type:typeof e.type=="string"?e.type:void 0,interactionId:typeof e.interactionId=="string"?e.interactionId:void 0},"[outbound-relay:mcu-sio] rejected remote MCU event with invalid API token"),this.sendTokenInvalidPrompt(e),!1):!0}async sendTokenInvalidPrompt(e){let l=lG("token-invalid");try{let t=await this.uploadMcuAudioUrlToRelay(l);t&&(l=t)}catch(t){h.warn({err:t,relayUrl:this.redactedRelayUrl()},"[outbound-relay:mcu-sio] failed to upload token invalid prompt")}this.sendJson({type:"auth.invalid",event:typeof e.type=="string"?e.type:void 0,interactionId:typeof e.interactionId=="string"?e.interactionId:void 0,text:rs("token-invalid"),url:l,mimeType:"audio/x-pcm",channels:1,sampleRate:Ke})}handleRemoteEvent(e,l){let t=Ki(l)?{...l,type:typeof l.type=="string"&&l.type?l.type:e}:{type:e,payload:l};if(h.info({relayUrl:this.redactedRelayUrl(),type:typeof t.type=="string"?t.type:void 0,status:typeof t.status=="string"?t.status:void 0,text:typeof t.text=="string"?t.text.slice(0,300):void 0,interactionId:typeof t.interactionId=="string"?t.interactionId:void 0},"[outbound-relay:mcu-sio] event"),t.type==="mcu.auth.ok"){let n=Ki(t.audioUpload)?t.audioUpload:null,c=typeof n?.token=="string"?n.token.trim():"";c&&(this.audioUploadToken=c,this.audioUploadPath=typeof n?.url=="string"&&n.url.trim()?n.url.trim():"/global-agent/audio");return}if(t.type==="relay.replaced"){this.reconnectBlockedReason="replaced",this.stopped=!0,h.warn({relayUrl:this.redactedRelayUrl(),deviceCode:typeof t.deviceCode=="string"?t.deviceCode:void 0,role:typeof t.role=="string"?t.role:void 0},"[outbound-relay:mcu-sio] remote relay connection replaced; relay left connected but inactive"),this.localAgentSocket?.disconnect(),this.localAgentSocket=null,this.cancelPendingInterrupts(),this.rejectAudioWaiters(new Error("remote relay connection replaced"));return}if(this.authorizeRemoteMcuEvent(t)){if(t.type==="voice.recorded"){this.pendingVoice={interactionId:typeof t.interactionId=="string"&&t.interactionId.trim()?t.interactionId.trim():`mcu-voice-${Date.now()}`,mimeType:typeof t.mimeType=="string"&&t.mimeType.trim()?t.mimeType.trim():"audio/wav",bytes:Number.isFinite(Number(t.bytes))?Number(t.bytes):0,profile:typeof t.profile=="string"&&t.profile.trim()?t.profile.trim():"default",agentRuntime:bs(t.agentRuntime)};return}if(t.type==="voice.stream.start"){this.pendingVoice=null,this.pendingVoiceStream={interactionId:typeof t.interactionId=="string"&&t.interactionId.trim()?t.interactionId.trim():`mcu-voice-${Date.now()}`,mimeType:typeof t.mimeType=="string"&&t.mimeType.trim()?t.mimeType.trim():"audio/pcm",bytes:0,profile:typeof t.profile=="string"&&t.profile.trim()?t.profile.trim():"default",agentRuntime:bs(t.agentRuntime),sampleRate:Number.isFinite(Number(t.sampleRate))?Number(t.sampleRate):Ke,channels:Number(t.channels)===1?1:2,bitsPerSample:(Number(t.bitsPerSample)===16,16),chunks:[]},this.emitLocalMcuEvent("voice.stream.start",t);return}if(t.type==="voice.stream.chunk"){let n=t.data,c;if(typeof n=="string")c=Buffer.from(n,"base64");else if(Buffer.isBuffer(n))c=Buffer.from(n);else if(n instanceof Uint8Array)c=Buffer.from(n.buffer,n.byteOffset,n.byteLength);else if(n instanceof ArrayBuffer)c=Buffer.from(n);else return;if(!c.length)return;if(this.pendingVoiceStream){let G=typeof t.interactionId=="string"?t.interactionId.trim():"";if(G&&G!==this.pendingVoiceStream.interactionId){h.warn({relayUrl:this.redactedRelayUrl(),streamInteractionId:this.pendingVoiceStream.interactionId,chunkInteractionId:G},"[outbound-relay:mcu-sio] ignoring stale voice stream chunk");return}let a=Number(t.offset),s=Number.isFinite(a)&&a>=0?Math.floor(a):this.pendingVoiceStream.bytes;this.pendingVoiceStream.chunks.push(c),this.pendingVoiceStream.bytes+=c.length,this.emitLocalMcuEvent("voice.stream.chunk",{...t,interactionId:this.pendingVoiceStream.interactionId,offset:s,bytes:c.length,seq:Number.isFinite(Number(t.seq))?Math.floor(Number(t.seq)):void 0,crc32:Number.isFinite(Number(t.crc32))?Math.floor(Number(t.crc32))>>>0:void 0,data:c});return}h.info({relayUrl:this.redactedRelayUrl(),bytes:c.length,interactionId:this.pendingVoice?.interactionId},"[outbound-relay:mcu-sio] voice chunk received without stream metadata"),this.handleVoiceAudio(c);return}if(t.type==="voice.stream.end"){let n=this.pendingVoiceStream;if(!n){this.sendJson({type:"interaction.status",status:"failed",text:"missing voice stream metadata"});return}let c=typeof t.interactionId=="string"?t.interactionId.trim():"";if(c&&c!==n.interactionId){h.warn({relayUrl:this.redactedRelayUrl(),streamInteractionId:n.interactionId,endInteractionId:c},"[outbound-relay:mcu-sio] ignoring stale voice stream end");return}this.pendingVoiceStream=null,h.info({relayUrl:this.redactedRelayUrl(),bytes:n.bytes,interactionId:n.interactionId},"[outbound-relay:mcu-sio] voice stream completed"),this.emitLocalMcuEvent("voice.stream.end",t);return}if(t.type==="voice.stream.abort"){this.pendingVoiceStream=null,this.emitLocalMcuEvent("voice.stream.abort",t);return}if(t.type==="audio.done"||t.type==="audio.interrupted"||t.type==="audio.dropped"){this.emitLocalMcuEvent(t.type,t),t.type==="audio.interrupted"&&typeof t.interactionId=="string"&&this.abortActiveRun(t.interactionId);let n=typeof t.segmentId=="string"?t.segmentId:"";if(!n)return;let c=this.audioWaiters.get(n);if(!c)return;clearTimeout(c.timer),this.audioWaiters.delete(n),t.type==="audio.done"?c.resolve():c.reject(new Error(t.type));return}if(t.type==="mcu.interrupt"){this.emitLocalMcuEvent("mcu.interrupt",t);return}if(t.type==="mcu.session.clear"){this.emitLocalMcuEvent("mcu.session.clear",t);return}typeof t.type=="string"&&t.type.trim()&&this.emitLocalMcuEvent(t.type.trim(),t)}}wrapPcmAsWav(e,l,t,n){let c=Buffer.alloc(44),G=l*t*n/8,a=t*n/8;return c.write("RIFF",0,"ascii"),c.writeUInt32LE(36+e.length,4),c.write("WAVE",8,"ascii"),c.write("fmt ",12,"ascii"),c.writeUInt32LE(16,16),c.writeUInt16LE(1,20),c.writeUInt16LE(t,22),c.writeUInt32LE(l,24),c.writeUInt32LE(G,28),c.writeUInt16LE(a,32),c.writeUInt16LE(n,34),c.write("data",36,"ascii"),c.writeUInt32LE(e.length,40),Buffer.concat([c,e],44+e.length)}async handleVoiceAudio(e,l){let t=l||this.pendingVoice;if(l||(this.pendingVoice=null),!t){this.sendJson({type:"interaction.status",status:"failed",text:"missing voice metadata"});return}if(!this.options.userToken){this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"failed",text:"missing Web UI auth token"});return}this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"transcribing"});try{let n=await this.options.fetchImpl(`${this.options.localBaseUrl.replace(/\/$/,"")}/api/hermes/mcu/voice-turn`,{method:"POST",headers:{Authorization:`Bearer ${this.options.userToken}`,"Content-Type":t.mimeType,"X-Hermes-Mcu-Interaction-Id":t.interactionId,"X-Hermes-Mcu-Agent-Runtime":t.agentRuntime,"X-Hermes-Profile":t.profile},body:new Uint8Array(e)}),c=await n.text(),G={};try{G=c?JSON.parse(c):{}}catch{G={error:c}}if(!n.ok||G.ok===!1){if(G.ok===!1&&await this.enqueuePromptAudioFromVoiceTurn(t.interactionId,G))return;this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"failed",text:typeof G.error=="string"?G.error:`voice turn failed: ${n.status}`});return}if(G.accepted===!0)return;let a=typeof G.transcript=="string"?G.transcript:"";if(!a.trim()){this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"completed",text:""});return}this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"thinking",text:a}),await this.runChatFromTranscript(t,a)}catch(n){this.sendJson({type:"interaction.status",interactionId:t.interactionId,status:"failed",text:n instanceof Error?n.message:String(n)})}}async runChatFromTranscript(e,l){await new Promise(t=>{let n=this.mcuSessionId(e.profile,e.agentRuntime),c=`mcu_${(0,iV.randomUUID)()}`;this.interruptedInteractions.delete(e.interactionId);let G=yl(`${this.options.localBaseUrl.replace(/\/$/,"")}/chat-run`,{auth:this.options.userToken?{token:this.options.userToken}:{},query:{profile:e.profile},transports:["websocket","polling"],reconnection:!1,timeout:3e4}),a="",s=0,d=Promise.resolve(),r=[],o=Promise.resolve(),b=!1,m=!1,i=!1,Z=!1,u=!1,p=!1,Y,W="",N=0,V=ZW(),R=()=>{let L=this.backgroundListeners.get(n);return Z||L?.socket===G},F=L=>{if(this.interruptedInteractions.has(e.interactionId))return;let q=Ti(L);if(!q)return;let S=`${e.interactionId}-tts-${++s}`;this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"speaking",text:q});let U=this.registerTtsAbortController(e.interactionId),aI=this.synthesizeMcuSpeech(q,e.profile,U.signal).then(lI=>({ok:!0,audio:lI})).catch(lI=>({ok:!1,err:lI,aborted:U.signal.aborted})).finally(()=>{this.releaseTtsAbortController(e.interactionId,U)});d=d.then(async()=>{await o;let lI=await this.enqueueMcuSpeechSegment(e.interactionId,S,q,aI);o=lI.playbackDone,r.push(lI.playbackDone)}).catch(lI=>{if(lI instanceof Error&&lI.message==="audio.interrupted"){this.interruptedInteractions.add(e.interactionId),h.info({interactionId:e.interactionId,segmentId:S},"[outbound-relay:ws] MCU speech interrupted by user");return}h.warn({err:lI,interactionId:e.interactionId,segmentId:S},"[outbound-relay:ws] failed to enqueue MCU speech"),this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"failed",text:lI instanceof Error?lI.message:String(lI)}),this.sendJson({type:"audio.enqueue",interactionId:e.interactionId,segmentId:`${S}-failed-prompt`,text:rs("tts-failed"),url:lG("tts-failed"),mimeType:"audio/x-pcm",format:"s16le",channels:1,sampleRate:Ke})})},X=()=>{let L=V.flush();L&&F(L)},v=()=>{i||(i=!0,t())},H=()=>{if(m)return;m=!0,this.activeRuns.delete(e.interactionId),this.sessionRuns.get(n)?.socket===G&&this.sessionRuns.delete(n),this.interruptedInteractions.delete(e.interactionId),clearTimeout(J),v(),this.flushBackgroundSpeech(n)},k=()=>{if(b)return;b=!0,H(),this.backgroundListeners.get(n)?.socket===G&&this.backgroundListeners.delete(n),G.removeAllListeners(),G.disconnect()},A=()=>{if(b)return;H();let L=this.backgroundListeners.get(n);L&&L.socket!==G&&L.close(),this.backgroundListeners.set(n,{socket:G,close:k}),h.info({interactionId:e.interactionId,sessionId:n,backgroundPending:N},"[outbound-relay:ws] keeping MCU session listener for background delivery")},Q=()=>{N>0?A():k()},E=L=>{this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"failed",text:L}),k()},J=setTimeout(()=>{E("chat-run timed out")},3e5);G.on("connect_error",L=>{E(L.message||"chat-run connection failed")}),G.on("disconnect",L=>{if(!b){if(m){h.warn({sessionId:n,reason:L},"[outbound-relay:ws] MCU background session listener disconnected"),k();return}E(`chat-run disconnected: ${L}`)}}),G.on("connect",()=>{h.info({interactionId:e.interactionId,sessionId:n,profile:e.profile,transcriptLength:l.length},"[outbound-relay:ws] starting chat-run"),this.activeRuns.set(e.interactionId,{socket:G,sessionId:n}),this.sessionRuns.set(n,{interactionId:e.interactionId,socket:G});let L={input:l,session_id:n,queue_id:c,profile:e.profile,...dw(e.agentRuntime)},q=this.recentlyInterruptedSessions.get(n)||0;if(Date.now()-q<1e4){G.emit("abort",{session_id:n}),setTimeout(()=>G.emit("run",L),800),this.recentlyInterruptedSessions.delete(n);return}G.emit("run",L)}),G.on("run.started",(L={})=>{let q=typeof L.queue_id=="string"?L.queue_id:void 0,S=L.autonomous===!0;u=!S&&q===c,p=S&&R(),Y=p&&typeof L.delegation_id=="string"&&L.delegation_id.trim()?L.delegation_id.trim():void 0,W="",u&&this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"thinking"})}),G.on("run.queued",(L={})=>{let q=Array.isArray(L.queued_messages)?L.queued_messages:[];(L.dequeued_queue_id===c||q.some(U=>typeof U=="object"&&U!==null&&U.id===c))&&(u=!1,this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"thinking"}))}),G.on("tool.started",(L={})=>{if(!u)return;X(),a="";let q=typeof L.tool=="string"?L.tool:typeof L.name=="string"?L.name:"tool";this.sendJson({type:"tool.started",interactionId:e.interactionId,tool:q})});let K=(L={},q=!1)=>{if(!u)return;let S=typeof L.tool=="string"?L.tool:typeof L.name=="string"?L.name:"tool",U=q?"tool.failed":void 0;this.sendJson({type:"tool.completed",interactionId:e.interactionId,tool:S,error:U})};G.on("tool.completed",(L={})=>K(L)),G.on("tool.failed",(L={})=>K(L,!0)),G.on("message.delta",(L={})=>{if(typeof L.delta=="string"){if(p){W+=L.delta;return}if(!u)return;a+=L.delta;for(let q of V.pushDelta(L.delta))F(q)}}),G.on("run.completed",(L={})=>{if(N=Math.max(0,Number(L.background_pending)||0),L.autonomous===!0||p){let aI=typeof L.output=="string"&&L.output.trim()?L.output:W;R()&&aI.trim()&&this.queueBackgroundSpeech(n,{profile:e.profile,delegationId:typeof L.delegation_id=="string"&&L.delegation_id.trim()?L.delegation_id.trim():Y,text:aI}),p=!1,u=!1,Y=void 0,W="",m&&N===0&&k();return}let S=typeof L.queue_id=="string"?L.queue_id:void 0;if(!(u||S===c)||Z){m&&N===0&&k();return}if(Z=!0,u=!1,typeof L.output=="string"&&L.output.trim())if(a){if(L.output.startsWith(a)&&L.output.length>a.length){let aI=L.output.slice(a.length);a=L.output;for(let lI of V.pushDelta(aI))F(lI)}}else{a=L.output;for(let aI of V.pushDelta(L.output))F(aI)}X(),d.then(async()=>{if(await Promise.all(r),this.interruptedInteractions.has(e.interactionId)){k();return}this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"completed"}),Q()}).catch(aI=>{if(this.interruptedInteractions.has(e.interactionId)||aI instanceof Error&&aI.message==="audio.interrupted"){k();return}E(aI instanceof Error?aI.message:String(aI))})}),G.on("run.failed",(L={})=>{N=Math.max(0,Number(L.background_pending)||0);let q=L.autonomous===!0||p,S=typeof L.queue_id=="string"?L.queue_id:void 0,U=u||S===c;if(p=!1,u=!1,Y=void 0,W="",q||!U||Z){m&&N===0&&k();return}Z=!0,this.sendJson({type:"interaction.status",interactionId:e.interactionId,status:"failed",text:typeof L.error=="string"?L.error:"chat-run failed"}),Q()}),G.on("delegation.updated",(L={})=>{L.background_pending!=null&&(N=Math.max(0,Number(L.background_pending)||0),m&&N===0&&k())}),G.on("approval.requested",(L={})=>{if(!u&&!p)return;let q=typeof L.approval_id=="string"?L.approval_id:"",S=Sne(L);if(!q||!S){E("approval required");return}h.info({interactionId:e.interactionId,sessionId:n,approvalId:q,choice:S},"[outbound-relay:ws] auto-approving MCU chat-run approval"),p||this.sendJson({type:"tool.started",interactionId:e.interactionId,tool:"approval"}),G.emit("approval.respond",{session_id:n,approval_id:q,choice:S})}),G.on("approval.resolved",(L={})=>{if(!u)return;let q=L.resolved!==!1;this.sendJson({type:"tool.completed",interactionId:e.interactionId,tool:"approval",error:q?void 0:"approval failed"})}),G.on("clarify.requested",()=>{u&&E("clarification required")})})}queueBackgroundSpeech(e,l){let t=l.text.trim();if(!t)return;let n=this.pendingBackgroundSpeech.get(e)||[];l.delegationId&&n.some(c=>c.delegationId===l.delegationId)||(n.push({...l,text:t}),this.pendingBackgroundSpeech.set(e,n),this.flushBackgroundSpeech(e))}async flushBackgroundSpeech(e){if(this.stopped||!this.socket?.connected||this.backgroundSpeechRuns.has(e)||this.sessionRuns.has(e))return;let l=this.pendingBackgroundSpeech.get(e);if(l?.length){this.backgroundSpeechRuns.add(e);try{for(;l.length>0&&!this.sessionRuns.has(e)&&this.socket?.connected;){let t=l.shift();if(!t)break;await this.playBackgroundSpeech(t)}}catch(t){t instanceof Error&&t.message==="audio.interrupted"||h.warn({err:t,sessionId:e},"[outbound-relay:ws] failed to deliver MCU background speech")}finally{this.backgroundSpeechRuns.delete(e),l.length===0&&this.pendingBackgroundSpeech.delete(e)}}}async playBackgroundSpeech(e){let t=`mcu-background-${(e.delegationId||(0,iV.randomUUID)()).toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,96)||(0,iV.randomUUID)()}`,n=ZW(),c=n.pushDelta(e.text),G=n.flush();G&&c.push(G);let a=0;try{for(let s of c){let d=Ti(s);if(!d)continue;let r=`${t}-tts-${++a}`,o=this.registerTtsAbortController(t),b=this.synthesizeMcuSpeech(d,e.profile,o.signal).then(i=>({ok:!0,audio:i})).catch(i=>({ok:!1,err:i,aborted:o.signal.aborted})).finally(()=>this.releaseTtsAbortController(t,o));if(await(await this.enqueueMcuSpeechSegment(t,r,d,b)).playbackDone,this.interruptedInteractions.has(t))throw new Error("audio.interrupted")}a>0&&this.sendJson({type:"interaction.status",interactionId:t,status:"completed"})}finally{this.interruptedInteractions.delete(t)}}async enqueuePromptAudioFromVoiceTurn(e,l){let t=Ki(l.audio)?l.audio:l,n=typeof t.url=="string"?t.url.trim():"";if(!n)return!1;let c=typeof t.text=="string"?t.text:"",G=typeof t.mimeType=="string"&&t.mimeType.trim()?t.mimeType.trim():"audio/x-pcm",a=Number(t.channels)===1?1:2,s=Number.isFinite(Number(t.sampleRate))&&Number(t.sampleRate)>0?Number(t.sampleRate):Ke,d=Number.isFinite(Number(t.durationMs))&&Number(t.durationMs)>0?Number(t.durationMs):Math.max(1200,Math.min(c.length*180,9e3)),r=`${e}-prompt`;this.sendJson({type:"interaction.status",interactionId:e,status:"speaking",text:c});let o=this.waitForMcuAudioDone(r,Math.max(3e4,d+2e4)).catch(b=>{h.warn({err:b,interactionId:e,segmentId:r},"[outbound-relay:ws] MCU prompt playback did not complete")});return this.sendJson({type:"audio.enqueue",interactionId:e,segmentId:r,text:c,url:n,mimeType:G,channels:a,sampleRate:s,durationMs:d}),await o,this.sendJson({type:"interaction.status",interactionId:e,status:"completed"}),!0}abortActiveRun(e){this.interruptedInteractions.add(e),this.abortTts(e);let l=this.activeRuns.get(e);l&&(h.info({interactionId:e,sessionId:l.sessionId},"[outbound-relay:ws] aborting chat-run after MCU audio interrupt"),l.socket.emit("abort",{session_id:l.sessionId}),this.activeRuns.delete(e),this.sessionRuns.delete(l.sessionId))}scheduleMcuInterrupt(e,l){let t=this.mcuSessionId(e);this.cancelPendingInterrupt(t);let n=setTimeout(()=>{this.pendingInterrupts.delete(t),this.interruptMcuSession(e,l)},Bne);this.pendingInterrupts.set(t,{profile:e,interactionId:l,timer:n})}cancelPendingInterrupt(e){let l=this.pendingInterrupts.get(e);l&&(clearTimeout(l.timer),this.pendingInterrupts.delete(e))}cancelPendingInterrupts(){for(let e of this.pendingInterrupts.values())clearTimeout(e.timer);this.pendingInterrupts.clear()}forgetMcuSessionRun(e,l){this.pendingBackgroundSpeech.delete(e),this.backgroundListeners.get(e)?.close();let t=this.sessionRuns.get(e);t&&(this.interruptedInteractions.add(t.interactionId),this.abortTts(t.interactionId),this.activeRuns.delete(t.interactionId),this.sessionRuns.delete(e)),l&&(this.interruptedInteractions.add(l),this.abortTts(l),this.activeRuns.get(l)?.sessionId===e&&(this.activeRuns.delete(l),this.sessionRuns.delete(e)))}interruptMcuSession(e,l){let t=this.mcuSessionId(e),n=this.sessionRuns.get(t),c=l?this.activeRuns.get(l):void 0,G=l?this.ttsAbortControllers.has(l):!1;if(l&&(n||c||G)&&(this.interruptedInteractions.add(l),this.abortTts(l)),n){this.recentlyInterruptedSessions.set(t,Date.now()),this.interruptedInteractions.add(n.interactionId),this.abortTts(n.interactionId),h.info({interactionId:n.interactionId,sessionId:t},"[outbound-relay:ws] aborting chat-run after MCU interrupt"),n.socket.emit("abort",{session_id:t}),this.activeRuns.delete(n.interactionId),this.sessionRuns.delete(t);return}l&&c?.sessionId===t&&(this.recentlyInterruptedSessions.set(t,Date.now()),this.abortActiveRun(l))}registerTtsAbortController(e){let l=new AbortController;if(this.interruptedInteractions.has(e))return l.abort(),l;let t=this.ttsAbortControllers.get(e)||new Set;return t.add(l),this.ttsAbortControllers.set(e,t),l}releaseTtsAbortController(e,l){let t=this.ttsAbortControllers.get(e);t&&(t.delete(l),t.size===0&&this.ttsAbortControllers.delete(e))}abortTts(e){let l=this.ttsAbortControllers.get(e);if(l){for(let t of l)t.signal.aborted||t.abort();this.ttsAbortControllers.delete(e)}}clearMcuSession(e,l){let t=this.mcuSessionId(e);this.cancelPendingInterrupt(t),this.forgetMcuSessionRun(t,l);let n=$c()?.clearSessionHistory(t),c=n?.deleted??$b(t),G=n?.hadMemoryState??!1;h.info({sessionId:t,deleted:c,memoryCleared:G},"[outbound-relay:ws] cleared MCU chat session"),this.sendJson({type:"mcu.session.cleared",interactionId:l||void 0,profile:e,sessionId:t,deleted:c,memoryCleared:G})}mcuSessionId(e,l=nx){let t=(this.options.instanceId||"device").toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"device",n=(e||"default").toLowerCase().replace(/[^a-z0-9_-]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"default";return`mcu-${t}-${n}-${l}`}async enqueueMcuSpeechSegment(e,l,t,n){if(this.interruptedInteractions.has(e))return{playbackDone:Promise.resolve()};let c=await n;if(!c.ok)throw c.aborted?new Error("audio.interrupted"):c.err;if(this.interruptedInteractions.has(e))return{playbackDone:Promise.resolve()};let G=this.waitForMcuAudioDone(l,Math.max(9e4,Math.min(t.length*1200,3e5)));return G.catch(()=>{}),this.sendJson({type:"audio.enqueue",interactionId:e,segmentId:l,text:t,url:c.audio.url,mimeType:c.audio.mimeType,channels:1,sampleRate:Ke,durationMs:Math.max(1200,Math.min(t.length*180,12e3)),completionManagedByServer:!0}),{playbackDone:G}}waitForMcuAudioDone(e,l){return new Promise((t,n)=>{let c=setTimeout(()=>{this.audioWaiters.delete(e),n(new Error(`MCU audio playback timed out: ${e}`))},l);this.audioWaiters.set(e,{resolve:t,reject:n,timer:c})})}async synthesizeMcuSpeech(e,l,t){if(!this.options.userToken)throw new Error("missing Web UI auth token");let n=this.options.localBaseUrl.replace(/\/$/,""),c={Authorization:`Bearer ${this.options.userToken}`,"Content-Type":"application/json","X-Hermes-Profile":l||"default"},G=Z=>this.options.fetchImpl(`${n}/api/hermes/tts/synthesize`,{method:"POST",headers:c,signal:t,body:JSON.stringify({...Z?{provider:Z}:{},text:e,options:One})}),a=async(Z,u)=>{let p=Buffer.from(await Z.arrayBuffer());if(!p.length)throw new Error(`${u} returned empty audio`);let Y=String(Z.headers.get("content-type")||"").split(";")[0].trim().toLowerCase(),W=p.length;if(Y==="audio/x-pcm"||Y==="audio/pcm")return h.info({context:u,contentType:Y,sourceBytes:W,pcmBytes:p.length},"[outbound-relay-client] MCU TTS PCM audio ready"),p;let N=await Gw(p,Y||"application/octet-stream",{sampleRate:Ke});if(N.mimeType!=="audio/x-pcm")throw new Error(`${u} returned ${Y||"unknown content type"} and PCM conversion is unavailable`);if(p=N.audio,!p.length)throw new Error(`${u} PCM conversion returned empty audio`);return h.info({context:u,contentType:Y||"application/octet-stream",sourceBytes:W,pcmBytes:p.length,sampleRate:Ke},"[outbound-relay-client] MCU TTS decoded to PCM"),p},s=await G();if(!s.ok){let Z=await s.text().catch(()=>"");if(h.warn({status:s.status,detail:Z.slice(0,200)},"[outbound-relay-client] active MCU TTS failed, falling back to Edge TTS"),s=await G("edge"),!s.ok){let u=await s.text().catch(()=>"");throw new Error(`MCU TTS failed and Edge fallback failed: ${s.status}${u?` ${u.slice(0,200)}`:""}`)}}let d;try{d=await a(s,"MCU TTS")}catch(Z){h.warn({err:Z},"[outbound-relay-client] MCU TTS audio decode failed, falling back to Edge TTS");let u=await G("edge");if(!u.ok){let p=await u.text().catch(()=>"");throw new Error(`MCU TTS decode failed and Edge fallback failed: ${u.status}${p?` ${p.slice(0,200)}`:""}`)}d=await a(u,"MCU Edge TTS fallback")}let r=(0,ax.join)(B.appHome,"mcu-audio");await(0,ow.mkdir)(r,{recursive:!0});let o=`${(0,iV.randomUUID)()}.adpcm`,b=aw(d,Ke);await(0,ow.writeFile)((0,ax.join)(r,o),b),h.info({file:o,textChars:e.length,pcmBytes:d.length,adpcmBytes:b.length,ratio:d.length>0?Number((b.length/d.length).toFixed(3)):0},"[outbound-relay-client] MCU TTS encoded to ADPCM");let m=`${n}/api/hermes/mcu/audio/${o}`;return{url:await this.uploadMcuAudioToRelay(b,"audio/x-ima-adpcm",t).catch(Z=>(h.warn({err:Z,relayUrl:this.redactedRelayUrl(),bytes:b.length},"[outbound-relay:ws] failed to upload MCU audio to relay"),""))||m,mimeType:"audio/x-ima-adpcm"}}relayHttpBaseUrl(){let e=new URL(this.options.relayUrl);return e.protocol==="ws:"&&(e.protocol="http:"),e.protocol==="wss:"&&(e.protocol="https:"),e.pathname="",e.search="",e.hash="",e.toString().replace(/\/$/,"")}resolveRelayAudioUploadUrl(){let e=this.relayHttpBaseUrl();if(/^https?:\/\//i.test(this.audioUploadPath))return this.audioUploadPath;let l=this.audioUploadPath.startsWith("/")?this.audioUploadPath:`/${this.audioUploadPath}`;return`${e}${l}`}async uploadMcuAudioToRelay(e,l="audio/x-pcm",t){if(!this.audioUploadToken||!this.options.deviceCode)return"";let n=this.resolveRelayAudioUploadUrl(),c=await this.options.fetchImpl(n,{method:"POST",headers:{Authorization:`Bearer ${this.audioUploadToken}`,"Content-Type":l,"X-Device-Code":this.options.deviceCode,"X-Audio-Sample-Rate":String(Ke),"X-Audio-Channels":"1"},body:new Uint8Array(e),signal:t}),G=await c.text(),a={};try{a=G?JSON.parse(G):{}}catch{a={error:G}}if(!c.ok||a.ok===!1){let r=typeof a.error=="string"?a.error:`relay audio upload failed: ${c.status}`;throw new Error(r)}let s=typeof a.url=="string"?a.url.trim():"";if(s)return s;let d=typeof a.path=="string"?a.path.trim():"";if(!d)throw new Error("relay audio upload did not return a URL");return`${this.relayHttpBaseUrl()}${d.startsWith("/")?d:`/${d}`}`}resolveLocalAudioUrl(e){if(/^https?:\/\//i.test(e))return e;let l=e.startsWith("/")?e:`/${e}`;return`${this.options.localBaseUrl.replace(/\/$/,"")}${l}`}async uploadMcuAudioUrlToRelay(e){if(!this.audioUploadToken||!this.options.deviceCode)return"";let l=this.resolveLocalAudioUrl(e),t=await this.options.fetchImpl(l,{method:"GET",headers:this.options.userToken?{Authorization:`Bearer ${this.options.userToken}`}:void 0});if(!t.ok){let G=await t.text().catch(()=>"");throw new Error(`local MCU audio fetch failed: ${t.status}${G?` ${G.slice(0,120)}`:""}`)}let n=Buffer.from(await t.arrayBuffer());if(!n.length)throw new Error("local MCU audio fetch returned empty audio");let c=String(t.headers.get("content-type")||"").split(";")[0].trim().toLowerCase()||"audio/x-pcm";return await this.uploadMcuAudioToRelay(n,c,void 0)}redactedRelayUrl(){try{let e=new URL(this.options.relayUrl);return(e.username||e.password)&&(e.username=e.username?"[redacted]":"",e.password=e.password?"[redacted]":""),e.toString()}catch{return"[invalid relay url]"}}};function nG(I,e,l,t){return{id:I,...t?{status:t}:{},error:{code:e,message:l}}}function uW(I,e,l){return{id:I,ok:!1,error:{code:e,message:l}}}function toI(I){return"error"in I}function noI(I){let e=String(I||"GET").trim().toUpperCase();return Ane.has(e)?e:null}function coI(I){let e=String(I||"").trim();if(!e||!e.startsWith("/")||e.startsWith("//"))return null;let l=new URL(e,"http://hermes-relay.local"),t=`${l.pathname}${l.search}`;return l.pathname==="/v1"||l.pathname.startsWith("/v1/")?null:t}function Gx(I){let e=String(I||"").trim();return!e||e.length>128?null:e}function jne(I){let e=String(I||"").trim();return fne.has(e)?e:null}function Tne(I){let e={};for(let[l,t]of Object.entries(I||{}))t!=null&&(e[l]=String(t));return e}function Kne(I){let e={};for(let[l,t]of Object.entries(I||{}))t!=null&&(e[l]=t);return e}function Ki(I){return!!I&&typeof I=="object"&&!Array.isArray(I)}function Dne(I,e=!0){return typeof I=="boolean"?I:e}function GoI(I){let e=Number(I);return!Number.isFinite(e)||e<=0?Cne:Math.min(Math.floor(e),Jne)}function aoI(I){let e=new Headers;for(let[l,t]of Object.entries(I||{})){let n=l.toLowerCase();if(!kne.has(n)||t==null)continue;let c=Array.isArray(t)?t.find(Boolean):t;c&&e.set(n,String(c))}return e}function soI(I,e,l){if(e==="GET"||e==="HEAD")return{byteLength:0};if(typeof I.bodyBase64=="string"){let c=Buffer.from(I.bodyBase64,"base64");return c.byteLength>cx?nG(I.id,"request_body_too_large","Relay request body exceeds the local size limit",413):{body:c,byteLength:c.byteLength}}if(I.body==null)return{byteLength:0};if(typeof I.body=="string"){let c=Buffer.byteLength(I.body);return c>cx?nG(I.id,"request_body_too_large","Relay request body exceeds the local size limit",413):{body:I.body,byteLength:c}}let t=JSON.stringify(I.body),n=Buffer.byteLength(t);return n>cx?nG(I.id,"request_body_too_large","Relay request body exceeds the local size limit",413):l.has("content-type")?{body:t,byteLength:n}:{body:t,contentType:"application/json",byteLength:n}}function doI(I){let e={};return I.headers.forEach((l,t)=>{let n=t.toLowerCase();n==="connection"||n==="transfer-encoding"||(e[n]=l)}),e}function _ne(I){let e=I.toLowerCase();return Lne.some(l=>e.startsWith(l)||e.includes(l))}async function roI(I){let e=I.headers.get("content-type")||"";if(!I.body)return{};let l=I.body.getReader(),t=[],n=0,c=!1;for(;;){let{done:a,value:s}=await l.read();if(a)break;let d=Buffer.from(s);if(n+=d.byteLength,n>eoI){let r=Math.max(0,eoI-(n-d.byteLength));r>0&&t.push(d.subarray(0,r)),c=!0,await l.cancel();break}t.push(d)}let G=Buffer.concat(t);return _ne(e)?{body:G.toString("utf-8"),truncated:c}:{bodyBase64:G.toString("base64"),truncated:c}}var dx=class{socket=null;socketBridges=new Map;relayUrl;relayToken;instanceId;deviceCode;localBaseUrl;machineInfo;fetchImpl;constructor(e){this.relayUrl=e.relayUrl,this.relayToken=e.relayToken,this.instanceId=e.instanceId,this.deviceCode=e.deviceCode,this.localBaseUrl=e.localBaseUrl.replace(/\/$/,""),this.machineInfo=e.machineInfo,this.fetchImpl=e.fetchImpl}start(){if(this.socket)return;let e={role:"hermes-studio"};this.relayToken&&(e.token=this.relayToken),this.deviceCode&&(e.deviceCode=this.deviceCode,e.device_code=this.deviceCode),this.instanceId&&(e.instanceId=this.instanceId),this.machineInfo&&(e.machine=this.machineInfo),this.socket=yl(this.relayUrl,{auth:e,transports:["websocket","polling"],reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:3e4,timeout:3e4}),this.socket.on("connect",()=>{h.info({relayUrl:this.redactedRelayUrl()},"[outbound-relay] connected"),this.socket?.emit("relay.ready",{capabilities:["http.request","socket.chat-run"],instanceId:this.instanceId||void 0})}),this.socket.on("connect_error",l=>{h.warn({err:l,relayUrl:this.redactedRelayUrl()},"[outbound-relay] connection failed"),(l.message==="device_code_not_allowed"||l.message.includes("\u975E\u5B98\u65B9\u8BBE\u5907\u7801"))&&this.stop()}),this.socket.on("disconnect",l=>{h.info({reason:l,relayUrl:this.redactedRelayUrl()},"[outbound-relay] disconnected")}),this.socket.on("relay.replaced",l=>{h.warn({payload:l,relayUrl:this.redactedRelayUrl()},"[outbound-relay] remote relay connection replaced; reconnect disabled"),this.stop()}),this.socket.on("http.request",(l,t)=>{this.handleHttpRequest(l).then(n=>this.respond(n,t)).catch(n=>this.respond(nG(l?.id,"relay_internal_error",n instanceof Error?n.message:String(n),500),t))}),this.socket.on("socket.open",(l,t)=>{this.respondSocket(this.openLocalSocket(l),t)}),this.socket.on("socket.event",(l,t)=>{this.respondSocket(this.emitLocalSocketEvent(l),t)}),this.socket.on("socket.close",(l,t)=>{this.respondSocket(this.closeLocalSocket(l),t)})}stop(){for(let e of this.socketBridges.values())e.socket.disconnect();this.socketBridges.clear(),this.socket?.disconnect(),this.socket=null}isConnected(){return!!this.socket?.connected}waitForConnected(e=5e3){let l=this.socket;return l?l.connected?Promise.resolve(!0):new Promise(t=>{let n=()=>{clearTimeout(a),l.off("connect",c),l.off("connect_error",G)},c=()=>{n(),t(!0)},G=()=>{n(),t(!1)},a=setTimeout(()=>{n(),t(!1)},e);l.once("connect",c),l.once("connect_error",G)}):Promise.resolve(!1)}async handleHttpRequest(e){let l=noI(e.method);if(!l)return nG(e.id,"method_not_allowed","Relay request method is not allowed",405);let t=coI(e.path);if(!t)return nG(e.id,"path_not_allowed","Relay request path is not allowed",403);let n=aoI(e.headers),c=soI(e,l,n);if(toI(c))return c;c.contentType&&n.set("content-type",c.contentType);let G=GoI(e.timeoutMs),a=new AbortController,s=setTimeout(()=>a.abort(),G);try{let d=await this.fetchImpl(`${this.localBaseUrl}${t}`,{method:l,headers:n,body:c.body,signal:a.signal}),r=await roI(d);return{id:e.id,status:d.status,headers:doI(d),...r}}catch(d){let r=a.signal.aborted;return nG(e.id,r?"request_timeout":"local_request_failed",r?`Local relay request timed out after ${G}ms`:d instanceof Error?d.message:String(d),r?504:502)}finally{clearTimeout(s)}}respond(e,l){if(l){l(e);return}this.socket?.emit("http.response",e)}openLocalSocket(e){let l=Gx(e.id);if(!l)return uW(e.id,"invalid_socket_id","Relay socket id is required");let t=jne(e.namespace);if(!t)return uW(l,"namespace_not_allowed","Relay socket namespace is not allowed");this.closeLocalSocket({id:l});let n=yl(`${this.localBaseUrl}${t}`,{auth:Kne(e.auth),query:Tne(e.query),transports:["websocket","polling"],reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:3e4,timeout:3e4}),c={id:l,namespace:t,socket:n,stream:Dne(e.stream),output:"",reasoning:""};this.socketBridges.set(l,c),n.on("connect",()=>{this.emitSocketEvent({id:l,namespace:t,event:"connect",payload:{socketId:n.id}})}),n.on("connect_error",G=>{this.emitSocketEvent({id:l,namespace:t,event:"connect_error",payload:{message:G.message}})}),n.on("disconnect",G=>{this.emitSocketEvent({id:l,namespace:t,event:"disconnect",payload:{reason:G}})});for(let G of zne)n.on(G,a=>{this.handleLocalSocketEvent(c,G,a)});return{id:l,ok:!0,namespace:t,stream:c.stream}}emitLocalSocketEvent(e){let l=Gx(e.id);if(!l)return uW(e.id,"invalid_socket_id","Relay socket id is required");let t=String(e.event||"").trim();if(!xne.has(t))return uW(l,"event_not_allowed","Relay socket event is not allowed");let n=this.socketBridges.get(l);return n?(typeof e.stream=="boolean"&&(n.stream=e.stream),t==="run"&&(n.output="",n.reasoning=""),n.socket.emit(t,e.payload),{id:l,ok:!0,namespace:n.namespace,event:t,stream:n.stream}):uW(l,"socket_not_open","Relay socket is not open")}closeLocalSocket(e){let l=Gx(e.id);if(!l)return uW(e.id,"invalid_socket_id","Relay socket id is required");let t=this.socketBridges.get(l);return t?(t.socket.disconnect(),this.socketBridges.delete(l),{id:l,ok:!0,namespace:t.namespace}):{id:l,ok:!0}}emitSocketEvent(e){this.socket?.emit("socket.event",{id:e.id,namespace:e.namespace,event:e.event,payload:e.payload})}handleLocalSocketEvent(e,l,t){if(!e.stream){if(l==="message.delta"&&Ki(t)&&typeof t.delta=="string"){e.output+=t.delta;return}if((l==="reasoning.delta"||l==="thinking.delta")&&Ki(t)){let n=typeof t.delta=="string"?t.delta:typeof t.text=="string"?t.text:"";e.reasoning+=n;return}if(Une.has(l))return;if(l==="run.completed"){this.emitSocketEvent({id:e.id,namespace:e.namespace,event:l,payload:this.withNonStreamingOutput(t,e)});return}}this.emitSocketEvent({id:e.id,namespace:e.namespace,event:l,payload:t})}withNonStreamingOutput(e,l){return Ki(e)?{...e,output:typeof e.output=="string"&&e.output?e.output:l.output,...l.reasoning&&typeof e.reasoning!="string"?{reasoning:l.reasoning}:{}}:{output:l.output,...l.reasoning?{reasoning:l.reasoning}:{}}}respondSocket(e,l){if(l){l(e);return}this.socket?.emit("socket.response",e)}redactedRelayUrl(){try{let e=new URL(this.relayUrl);return e.username="",e.password="",e.toString()}catch{return"<invalid-url>"}}},io=new Map;function qne(I,e){return(I.connectionId||I.instanceId||e).trim()}function bw(I={}){let e=(I.relayUrl??"").trim();if(!e)return null;let l=qne(I,e),t=io.get(l);if(t)return t;let n={relayUrl:e,relayToken:I.relayToken??"",userToken:I.userToken??"",instanceId:I.instanceId??"",deviceCode:I.deviceCode??"",localBaseUrl:I.localBaseUrl??`http://127.0.0.1:${B.port}`,machineInfo:I.machineInfo,fetchImpl:I.fetchImpl??fetch},c=I.relayProtocol==="mcu-socket.io"?new sx(n):new dx(n);return c.start(),io.set(l,c),c}function ooI(I){return I?io.get(I)||null:io.values().next().value||null}function mo(I){if(I){io.get(I)?.stop(),io.delete(I);return}for(let e of io.values())e.stop();io.clear()}var ebI=require("crypto");wi();AI();dI();var ms=require("os"),Wo=require("crypto");var VW=require("fs/promises"),pw=require("path");AI();uo();var Vx=(0,pw.resolve)(B.appHome,"device-identity.json"),Rx=null;function Fx(){return"0.6.41"}function Fce(I){return I.split(`
|
|
1595
1595
|
`)[0]?.replace(/^Hermes Agent\s+/,"").trim()||""}async function Xx(){return Fce(await uw())}function Xce(I){return typeof I?.device_id=="string"&&I.device_id.length>=16&&typeof I?.device_public_key=="string"&&I.device_public_key.includes("PUBLIC KEY")&&typeof I?.device_private_key=="string"&&I.device_private_key.includes("PRIVATE KEY")}function RW(I){return`hwui_${(0,Wo.createHash)("sha256").update(I).digest("base64url").slice(0,32)}`}async function gce(){try{let l=JSON.parse(await(0,VW.readFile)(Vx,"utf-8"));if(Xce(l))return l}catch{}let I=(0,Wo.generateKeyPairSync)("ed25519",{publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem"}}),e={device_id:RW(I.publicKey),device_public_key:I.publicKey,device_private_key:I.privateKey};return await(0,VW.mkdir)((0,pw.dirname)(Vx),{recursive:!0}),await(0,VW.writeFile)(Vx,JSON.stringify(e,null,2),{encoding:"utf-8",mode:384}),e}function FW(){return Rx||(Rx=gce()),Rx}function IbI(I){return`${I.device_id}.${I.nonce}.${I.timestamp}`}async function qi(I,e){let l=await FW();return(0,Wo.sign)(null,Buffer.from(IbI({device_id:l.device_id,nonce:I,timestamp:e})),l.device_private_key).toString("base64url")}function pV(I){if(RW(I.device_public_key)!==I.device_id)return!1;try{return(0,Wo.verify)(null,Buffer.from(IbI(I)),I.device_public_key,Buffer.from(I.signature,"base64url"))}catch{return!1}}async function Kn(){let I=await Xx(),e=await FW();return{device_id:e.device_id,device_public_key:e.device_public_key,computer_name:(0,ms.hostname)(),os:{type:(0,ms.type)(),platform:(0,ms.platform)(),release:(0,ms.release)(),arch:(0,ms.arch)()},hermes_agent_version:I,hermes_web_ui_version:Fx()}}var Nw="/app-relay",Hce=3e4,wce=12e4,Qce=20*1024*1024,yce=20*1024*1024,vce=new Set(["GET","POST","PUT","PATCH","DELETE","HEAD"]),Ece=new Set(["accept","accept-language","authorization","content-type","if-none-match","range","x-hermes-profile","x-request-id"]),Cce=new Set(["/chat-run"]),Jce=new Set(["run","resume","abort","cancel_queued_run","approval.respond","clarify.respond"]),Ace=["application/json","application/problem+json","application/x-ndjson","application/javascript","application/xml","application/x-www-form-urlencoded","text/"],kce=new Set(["message.delta","message.interim","reasoning.delta","thinking.delta","reasoning.available"]),wx=class{constructor(e){this.options=e;this.relayUrl=Lce(e.relayUrl),this.localBaseUrl=e.localBaseUrl.replace(/\/$/,""),this.fetchImpl=e.fetchImpl}options;socket=null;bridges=new Map;relayUrl;localBaseUrl;fetchImpl;pairingCode="";pairingExpiresAt=0;start(){this.socket||(this.socket=yl(this.relayUrl,{auth:async e=>{let l=(0,ebI.randomUUID)(),t=Date.now(),n=await qi(l,t);e({role:"host",machineId:this.options.machineId,instanceId:this.options.machineId,publicKey:this.options.publicKey,nonce:l,timestamp:t,signature:n,machine:this.options.machineInfo})},transports:["websocket","polling"],reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:3e4,timeout:3e4}),this.socket.on("connect",()=>{h.info({relayUrl:this.redactedRelayUrl(),machineId:this.options.machineId},"[app-relay] connected")}),this.socket.on("connect_error",e=>{h.warn({err:e,relayUrl:this.redactedRelayUrl()},"[app-relay] connection failed")}),this.socket.on("disconnect",e=>{this.closeLocalBridges(),h.info({reason:e,relayUrl:this.redactedRelayUrl()},"[app-relay] disconnected")}),this.socket.on("relay.replaced",()=>this.stop()),this.socket.on("relay.ready",(e={})=>{this.rememberPairing(e)}),this.socket.on("app.http.request",(e,l)=>{this.handleHttpRequest(e).then(t=>l?.(t)).catch(t=>l?.(NV(e?.id,"relay_internal_error",t instanceof Error?t.message:String(t),500)))}),this.socket.on("app.socket.open",(e,l)=>{l?.(this.openLocalSocket(e))}),this.socket.on("app.socket.event",(e,l)=>{l?.(this.emitLocalSocketEvent(e))}),this.socket.on("app.socket.close",(e,l)=>{l?.(this.closeLocalSocket(e))}))}stop(){this.closeLocalBridges(),this.socket?.disconnect(),this.socket=null}isConnected(){return!!this.socket?.connected}status(){return{connected:this.isConnected(),machineId:this.options.machineId,pairingCode:this.pairingExpiresAt>Math.floor(Date.now()/1e3)?this.pairingCode:"",pairingExpiresAt:this.pairingExpiresAt}}requestPairingCode(e=5e3){let l=this.socket;return l?.connected?new Promise((t,n)=>{l.timeout(e).emit("pairing.request",{},(c,G={})=>{if(c||G.ok===!1){n(c||new Error(String(G.error||"pairing_request_failed")));return}if(this.rememberPairing(G),!this.pairingCode){n(new Error("pairing_request_failed"));return}t({pairingCode:this.pairingCode,expiresAt:this.pairingExpiresAt})})}):Promise.reject(new Error("app_relay_not_connected"))}waitForConnected(e=5e3){let l=this.socket;return l?l.connected?Promise.resolve(!0):new Promise(t=>{let n=()=>{clearTimeout(a),l.off("connect",c),l.off("connect_error",G)},c=()=>{n(),t(!0)},G=()=>{n(),t(!1)},a=setTimeout(()=>{n(),t(!1)},e);l.once("connect",c),l.once("connect_error",G)}):Promise.resolve(!1)}async handleHttpRequest(e){let l=fce(e.method);if(!l)return NV(e.id,"method_not_allowed","Relay request method is not allowed",405);let t=xce(e.path);if(!t)return NV(e.id,"path_not_allowed","Relay request path is not allowed",403);let n=zce(e.headers),c=Uce(e,l,n);if(Oce(c))return c;c.contentType&&n.set("content-type",c.contentType);let G=Tce(e.timeoutMs),a=new AbortController,s=setTimeout(()=>a.abort(),G);try{let d=await this.fetchImpl(`${this.localBaseUrl}${t}`,{method:l,headers:n,body:c.body,signal:a.signal});return{id:e.id,status:d.status,headers:Bce(d),...await Mce(d)}}catch(d){let r=a.signal.aborted;return NV(e.id,r?"request_timeout":"local_request_failed",r?`Local request timed out after ${G}ms`:d instanceof Error?d.message:String(d),r?504:502)}finally{clearTimeout(s)}}openLocalSocket(e){let l=gx(e.id);if(!l)return XW(e.id,"invalid_socket_id","Relay socket id is required");let t=String(e.namespace||"").trim();if(!Cce.has(t))return XW(l,"namespace_not_allowed","Relay socket namespace is not allowed");this.closeLocalSocket({id:l});let n=yl(`${this.localBaseUrl}${t}`,{auth:Sce(e.auth),query:jce(e.query),transports:["websocket","polling"],reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:3e4,timeout:3e4}),c={id:l,namespace:t,socket:n,stream:typeof e.stream=="boolean"?e.stream:!0,output:"",reasoning:""};return this.bridges.set(l,c),n.on("connect",()=>this.emitSocketEvent(c,"connect",{socketId:n.id})),n.on("connect_error",G=>this.emitSocketEvent(c,"connect_error",{message:G.message})),n.on("disconnect",G=>this.emitSocketEvent(c,"disconnect",{reason:G})),n.onAny((G,...a)=>{this.handleLocalSocketEvent(c,G,a.length<=1?a[0]:a)}),{id:l,ok:!0,namespace:t,stream:c.stream}}emitLocalSocketEvent(e){let l=gx(e.id);if(!l)return XW(e.id,"invalid_socket_id","Relay socket id is required");let t=String(e.event||"").trim();if(!Jce.has(t))return XW(l,"event_not_allowed","Relay socket event is not allowed");let n=this.bridges.get(l);return n?(typeof e.stream=="boolean"&&(n.stream=e.stream),t==="run"&&(n.output="",n.reasoning=""),n.socket.emit(t,e.payload),{id:l,ok:!0,namespace:n.namespace,event:t,stream:n.stream}):XW(l,"socket_not_open","Relay socket is not open")}closeLocalSocket(e){let l=gx(e.id);if(!l)return XW(e.id,"invalid_socket_id","Relay socket id is required");let t=this.bridges.get(l);return t?(t.socket.disconnect(),this.bridges.delete(l),{id:l,ok:!0,namespace:t.namespace}):{id:l,ok:!0}}handleLocalSocketEvent(e,l,t){if(!e.stream){if(l==="message.delta"&&Hx(t)&&typeof t.delta=="string"){e.output+=t.delta;return}if((l==="reasoning.delta"||l==="thinking.delta")&&Hx(t)){e.reasoning+=typeof t.delta=="string"?t.delta:typeof t.text=="string"?t.text:"";return}if(kce.has(l))return;if(l==="run.completed"){let n=Hx(t)?t:{};this.emitSocketEvent(e,l,{...n,output:typeof n.output=="string"&&n.output?n.output:e.output,...e.reasoning&&typeof n.reasoning!="string"?{reasoning:e.reasoning}:{}});return}}this.emitSocketEvent(e,l,t)}emitSocketEvent(e,l,t){this.socket?.emit("app.socket.event",{id:e.id,namespace:e.namespace,event:l,payload:t})}redactedRelayUrl(){try{let e=new URL(this.relayUrl);return e.username="",e.password="",e.toString()}catch{return"<invalid-url>"}}rememberPairing(e){let l=typeof e.pairingCode=="string"?e.pairingCode.trim():"",t=Number(e.expiresAt);!l||!Number.isFinite(t)||(this.pairingCode=l,this.pairingExpiresAt=Math.floor(t))}closeLocalBridges(){for(let e of this.bridges.values())e.socket.disconnect();this.bridges.clear()}},Pi=new Map;function lbI(I){let e=String(I.relayUrl||"").trim(),l=String(I.machineId||"").trim(),t=String(I.publicKey||"");if(!e||!l||!t.trim())return null;let n=String(I.connectionId||l).trim(),c=Pi.get(n);if(c)return c;let G=new wx({relayUrl:e,machineId:l,publicKey:t,machineInfo:I.machineInfo,localBaseUrl:I.localBaseUrl||`http://127.0.0.1:${B.port}`,fetchImpl:I.fetchImpl||fetch});return G.start(),Pi.set(n,G),G}function hw(I){return Pi.get(I)||null}function hV(I){if(I){Pi.get(I)?.stop(),Pi.delete(I);return}for(let e of Pi.values())e.stop();Pi.clear()}function Lce(I){let e=new URL(I),l=e.pathname.replace(/\/+$/,"");return l?l!==Nw&&!l.endsWith(Nw)&&(e.pathname=`${l}${Nw}`):e.pathname=Nw,e.toString()}function fce(I){let e=String(I||"GET").trim().toUpperCase();return vce.has(e)?e:null}function xce(I){let e=String(I||"").trim();if(!e||!e.startsWith("/")||e.startsWith("//"))return null;let l=new URL(e,"http://app-relay.local");return l.pathname==="/api"||l.pathname.startsWith("/api/")||l.pathname==="/upload"||l.pathname==="/health"?`${l.pathname}${l.search}`:null}function zce(I){let e=new Headers;for(let[l,t]of Object.entries(I||{})){let n=l.toLowerCase();if(!Ece.has(n)||t==null)continue;let c=Array.isArray(t)?t.find(Boolean):t;c&&e.set(n,String(c))}return e}function Uce(I,e,l){if(e==="GET"||e==="HEAD")return{};let t;return typeof I.bodyBase64=="string"?t=Buffer.from(I.bodyBase64,"base64"):typeof I.body=="string"?t=I.body:I.body!=null&&(t=JSON.stringify(I.body),l.has("content-type")||l.set("content-type","application/json")),t!=null&&Buffer.byteLength(typeof t=="string"?t:Buffer.from(t))>Qce?NV(I.id,"request_body_too_large","Relay request body exceeds the local size limit",413):{body:t}}function Oce(I){return"error"in I&&!!I.error}function Bce(I){let e={};return I.headers.forEach((l,t)=>{t.toLowerCase()==="connection"||t.toLowerCase()==="transfer-encoding"||(e[t.toLowerCase()]=l)}),e}async function Mce(I){if(!I.body)return{};let e=I.body.getReader(),l=[],t=0,n=!1;for(;;){let{done:s,value:d}=await e.read();if(s)break;let r=Buffer.from(d),o=yce-t;if(r.byteLength>o){o>0&&l.push(r.subarray(0,o)),n=!0,await e.cancel();break}l.push(r),t+=r.byteLength}let c=Buffer.concat(l),G=I.headers.get("content-type")||"";return Ace.some(s=>G.toLowerCase().startsWith(s)||G.toLowerCase().includes(s))?{body:c.toString("utf8"),truncated:n}:{bodyBase64:c.toString("base64"),truncated:n}}function gx(I){let e=String(I||"").trim();return e&&e.length<=128?e:""}function Sce(I){return Object.fromEntries(Object.entries(I||{}).filter(([,e])=>e!=null))}function jce(I){return Object.fromEntries(Object.entries(I||{}).filter(([,e])=>e!=null).map(([e,l])=>[e,String(l)]))}function Tce(I){let e=Number(I);return!Number.isFinite(e)||e<=0?Hce:Math.min(Math.floor(e),wce)}function NV(I,e,l,t){return{id:I,...t?{status:t}:{},error:{code:e,message:l}}}function XW(I,e,l){return{id:I,ok:!1,error:{code:e,message:l}}}function Hx(I){return!!I&&typeof I=="object"&&!Array.isArray(I)}di();var RbI=require("crypto");var HW=require("crypto"),ubI=T(require("http")),WbI=T(require("https"));dI();var tbI=require("crypto");Be();gl();var Qx=["chat.message.created","chat.run.queued","chat.run.started","chat.tool.started","chat.tool.completed","chat.tool.failed","chat.approval.requested","chat.approval.resolved","chat.clarification.requested","chat.clarification.resolved","chat.run.completed","chat.run.failed"];function nbI(I){try{let e=typeof I=="string"?JSON.parse(I):I;return Array.isArray(e)?e.map(l=>String(l)).filter(Boolean):[]}catch{return[]}}function Kce(I){return nbI(I).filter(e=>Qx.includes(e))}function cbI(I){return{id:String(I.id||""),name:String(I.name||""),url:String(I.url||""),secret:String(I.secret||""),event_types:Kce(I.event_types_json),profiles:nbI(I.profiles_json),enabled:!!I.enabled,include_content:!!I.include_content,include_user_content:!!I.include_user_content,allow_private_network:!!I.allow_private_network,max_retries:Number(I.max_retries??3),created_at:Number(I.created_at||0),updated_at:Number(I.updated_at||0)}}function Yw(){let I=x();return I?I.prepare(`SELECT * FROM ${Db} ORDER BY created_at ASC`).all().map(cbI):[]}function gW(I){let e=x();if(!e)return null;let l=e.prepare(`SELECT * FROM ${Db} WHERE id = ?`).get(I);return l?cbI(l):null}function GbI(I){let e=x();if(!e)return null;let l=Date.now(),t=(0,tbI.randomUUID)();return e.prepare(`INSERT INTO ${Db}
|
|
1596
1596
|
(id, name, url, secret, event_types_json, profiles_json, enabled, include_content, include_user_content, allow_private_network, max_retries, created_at, updated_at)
|
|
1597
1597
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(t,I.name,I.url,I.secret||"",JSON.stringify(I.event_types||[]),JSON.stringify(I.profiles||[]),I.enabled===!1?0:1,I.include_content?1:0,I.include_user_content?1:0,I.allow_private_network?1:0,I.max_retries??3,l,l),gW(t)}function abI(I,e){let l=x(),t=gW(I);if(!l||!t)return null;let n=e.clear_secret?"":e.secret===void 0?t.secret:e.secret;return l.prepare(`UPDATE ${Db}
|
|
@@ -1615,7 +1615,7 @@ process.on('unhandledRejection', (error) => {
|
|
|
1615
1615
|
\r
|
|
1616
1616
|
`),c.destroy();return}n.kanbanProfile=r||void 0}try{n.kanbanBoard=tm(a.searchParams.get("board"))}catch{c.write(`HTTP/1.1 400 Bad Request\r
|
|
1617
1617
|
\r
|
|
1618
|
-
`),c.destroy();return}e.handleUpgrade(n,c,G,s=>{e.emit("connection",s,n)})}})}),e.on("connection",(t,n)=>{let c=n.kanbanBoard||"default",G=oiI({board:c,interval:.5}),a=!1;HV(t,{type:"connected",board:c});let s=()=>{a||(a=!0,G.killed||G.kill())};G.stdout?.on("data",HiI(d=>{d.toLowerCase().startsWith("watching kanban events")||HV(t,{type:"event",board:c})})),G.stderr?.on("data",HiI(d=>{HV(t,{type:"error",board:c,message:d})})),G.on("error",d=>{h.error(d,"Hermes CLI: kanban watch failed"),HV(t,{type:"error",board:c,message:d.message}),t.readyState===t.OPEN&&t.close()}),G.on("exit",(d,r)=>{HV(t,{type:"stopped",board:c,code:d,signal:r}),t.readyState===t.OPEN&&t.close()}),t.on("close",s),t.on("error",s)}),h.info("WebSocket ready at /api/hermes/kanban/events (kanban watch bridge)")}JI();var Jw=require("fs"),Ew=require("path");uo();ei();function wV(I,e,l="[redacted endpoint]"){if(!I)return I;let t=I,n=e?.trim(),c=new Set;if(n){if(c.add(n),n.startsWith("ipc://")){let G=n.slice(6);G&&c.add(G)}if(n.startsWith("tcp://"))try{let G=new URL(n);G.host&&c.add(G.host)}catch{}}for(let G of c)t=t.split(G).join(l);return t.replace(/ipc:\/\/[^\s),;]+/g,l).replace(/(?:[A-Za-z]:)?[^\s),;]*agent-bridge\.sock/g,l)}function nae(){let I=[(0,Ew.resolve)(__dirname,"../../../../package.json"),(0,Ew.resolve)(__dirname,"../../package.json"),(0,Ew.resolve)(process.cwd(),"package.json")];for(let e of I)if((0,Jw.existsSync)(e))try{let l=JSON.parse((0,Jw.readFileSync)(e,"utf-8"));if(l?.name&&l?.version)return{name:String(l.name),version:String(l.version)}}catch{}return null}var cae=nae(),AW="0.6.
|
|
1618
|
+
`),c.destroy();return}e.handleUpgrade(n,c,G,s=>{e.emit("connection",s,n)})}})}),e.on("connection",(t,n)=>{let c=n.kanbanBoard||"default",G=oiI({board:c,interval:.5}),a=!1;HV(t,{type:"connected",board:c});let s=()=>{a||(a=!0,G.killed||G.kill())};G.stdout?.on("data",HiI(d=>{d.toLowerCase().startsWith("watching kanban events")||HV(t,{type:"event",board:c})})),G.stderr?.on("data",HiI(d=>{HV(t,{type:"error",board:c,message:d})})),G.on("error",d=>{h.error(d,"Hermes CLI: kanban watch failed"),HV(t,{type:"error",board:c,message:d.message}),t.readyState===t.OPEN&&t.close()}),G.on("exit",(d,r)=>{HV(t,{type:"stopped",board:c,code:d,signal:r}),t.readyState===t.OPEN&&t.close()}),t.on("close",s),t.on("error",s)}),h.info("WebSocket ready at /api/hermes/kanban/events (kanban watch bridge)")}JI();var Jw=require("fs"),Ew=require("path");uo();ei();function wV(I,e,l="[redacted endpoint]"){if(!I)return I;let t=I,n=e?.trim(),c=new Set;if(n){if(c.add(n),n.startsWith("ipc://")){let G=n.slice(6);G&&c.add(G)}if(n.startsWith("tcp://"))try{let G=new URL(n);G.host&&c.add(G.host)}catch{}}for(let G of c)t=t.split(G).join(l);return t.replace(/ipc:\/\/[^\s),;]+/g,l).replace(/(?:[A-Za-z]:)?[^\s),;]*agent-bridge\.sock/g,l)}function nae(){let I=[(0,Ew.resolve)(__dirname,"../../../../package.json"),(0,Ew.resolve)(__dirname,"../../package.json"),(0,Ew.resolve)(process.cwd(),"package.json")];for(let e of I)if((0,Jw.existsSync)(e))try{let l=JSON.parse((0,Jw.readFileSync)(e,"utf-8"));if(l?.name&&l?.version)return{name:String(l.name),version:String(l.version)}}catch{}return null}var cae=nae(),AW="0.6.41",cm="",QiI=250,viI=75,nm=null,vw=null;function Cw(){let I=(process.env.HERMES_WEB_UI_DISABLE_UPDATE_CHECK||"").trim().toLowerCase();return I==="true"||I==="1"||I==="on"||I==="yes"}function Gae(I,e){let l=c=>c.trim().replace(/^v/i,"").split(/[.-]/),t=l(I),n=l(e);for(let c=0;c<Math.max(t.length,n.length);c+=1){let G=t[c]||"0",a=n[c]||"0",s=Number.parseInt(G,10),d=Number.parseInt(a,10),o=Number.isFinite(s)&&Number.isFinite(d)?s-d:G.localeCompare(a,void 0,{numeric:!0});if(o!==0)return o}return 0}function EiI(I,e){return Gae(I,e)>0}async function yiI(){if(!Cw())try{let I=cae?.name||"hermes-web-ui",e=encodeURIComponent(I),l=await fetch(`https://registry.npmjs.org/${e}/latest`,{signal:AbortSignal.timeout(1e4)});l.ok&&(cm=(await l.json()).version,AW&&cm&&EiI(cm,AW)&&console.log(`Update available: ${AW} \u2192 ${cm}`))}catch{}}function c9(){Cw()||(setTimeout(yiI,5e3),setInterval(yiI,1800*1e3))}async function aae(){let I=Date.now();return nm&&nm.expiresAt>I||(vw||(vw=sae().finally(()=>{vw=null})),nm)?nm.value:await Promise.race([vw,new Promise(l=>{setTimeout(()=>l({status:"unknown",reachable:!1}),viI)})])}async function sae(){let I;try{let e=An();I=typeof e.getRuntimeState=="function"?e.getRuntimeState().endpoint:void 0;let l=await e.checkReadiness({timeoutMs:viI,connectRetryMs:0}),t={status:l.status,reachable:l.reachable,ready:l.ready,running:l.running,attached:l.attached,starting:l.starting,stopping:l.stopping,restart_scheduled:l.restartScheduled,restart_attempts:l.restartAttempts,endpoint_kind:l.endpointKind,pid:l.pid,error:wV(l.error,l.endpoint)};return nm={value:t,expiresAt:Date.now()+QiI},t}catch(e){let l={status:"unknown",reachable:!1,error:wV(e instanceof Error?e.message:String(e),I)};return nm={value:l,expiresAt:Date.now()+QiI},l}}function CiI(I){I.body={status:"ok"}}async function JiI(I){let l=(await uw()).split(`
|
|
1619
1619
|
`)[0].replace("Hermes Agent ","")||"",t=await aae();I.body={status:"ok",platform:"hermes-agent",version:l,gateway:"running",webui_version:AW,webui_latest:Cw()?"":cm,webui_update_available:Cw()?!1:!!(AW&&cm&&EiI(cm,AW)),node_version:process.versions.node,agent_bridge:t,is_docker:UF()}}var Aw=new D;Aw.get("/livez",CiI);Aw.get("/health",JiI);JI();var LiI=require("crypto"),Lw=require("fs/promises"),fiI=require("path");wI();var kw=require("path");AI();fl();function rae(I){let e=(I||"default").trim()||"default";if(e.includes("/")||e.includes("\\")||e.includes(".."))throw Object.assign(new Error("Invalid profile name"),{code:"invalid_profile"});return e}function AiI(I){return(0,kw.resolve)((0,kw.join)(B.uploadDir,rae(I)))}var ta=class extends Error{};function Fo(I){let e=I.match(/(?:^|;)\s*boundary=(?:"([^"]+)"|([^;]+))/i),l=(e?.[1]||e?.[2]||"").trim();return l?Buffer.from(`--${l}`):null}function Xo(I,e){let l=[],t=0;for(;;){let n=I.indexOf(e,t);if(n===-1)break;t>0&&l.push(I.subarray(t+2,n)),t=n+e.length}return l}function go(I){let e=I.match(/Content-Disposition:\s*form-data;([^\r\n]*)/i)?.[1];if(!e)return null;let l=e.match(/(?:^|;)\s*filename\*\s*=\s*([^;\r\n]+)/i)?.[1];if(l){let n=l.trim().replace(/^"|"$/g,"").match(/^UTF-8''(.+)$/i);if(!n)return null;try{return decodeURIComponent(n[1])}catch{throw new ta("Malformed multipart filename")}}return e.match(/(?:^|;)\s*filename="([^"]*)"/i)?.[1]??null}var kiI=50*1024*1024;function oae(I){return I.state?.profile?.name||uI()||"default"}async function xiI(I){let e=I.get("content-type")||"";if(!e.startsWith("multipart/form-data")){I.status=400,I.body={error:"Expected multipart/form-data"};return}let l=Fo(e);if(!l){I.status=400,I.body={error:"Missing boundary"};return}let t=[],n=0;for await(let d of I.req){if(n+=d.length,n>kiI){I.status=413,I.body={error:`File too large (max ${kiI/1024/1024}MB)`};return}t.push(d)}let c=Buffer.concat(t),G=Xo(c,l),a=[],s=AiI(oae(I));await(0,Lw.mkdir)(s,{recursive:!0});for(let d of G){let r=d.indexOf(Buffer.from(`\r
|
|
1620
1620
|
\r
|
|
1621
1621
|
`));if(r===-1)continue;let b=d.subarray(0,r).toString("utf-8"),m=d.subarray(r+4,d.length-2),i;try{i=go(b)}catch(Y){if(Y instanceof ta){I.status=400,I.body={error:Y.message};return}throw Y}if(!i)continue;let Z=i.includes(".")?"."+i.split(".").pop():"",u=(0,LiI.randomBytes)(8).toString("hex")+Z,p=(0,fiI.join)(s,u);await(0,Lw.writeFile)(p,m),a.push({name:i,path:p})}I.body={files:a}}var G9=new D;G9.post("/upload",xiI);JI();var Md=new D;Md.post("/api/hermes/update",_$);Md.get("/api/hermes/update/preview",LI,q$);Md.get("/api/hermes/update/preview/tags",LI,P$);Md.post("/api/hermes/update/preview/prepare",LI,$$);Md.post("/api/hermes/update/preview/install",LI,III);Md.post("/api/hermes/update/preview/start",LI,eII);Md.post("/api/hermes/update/preview/stop",LI,lII);JI();un();var TiI=require("crypto"),Vc=require("fs/promises"),am=require("path");AI();Be();gl();var iae=14,ziI=12,UiI=20;function a9(){let I=x();if(!I)throw new Error("Theme storage unavailable");return I}function fw(I){let e=Number(I);if(!Number.isInteger(e)||e<=0)throw new Ho("Invalid user");return e}function mae(I){let e=Number(I);if(!Number.isInteger(e)||e<ziI||e>UiI)throw new Ho(`Font size must be between ${ziI} and ${UiI}`);return e}function OiI(I,e){if(I==null||I==="")return null;if(typeof I!="string"||!/^#[0-9a-fA-F]{6}$/.test(I.trim()))throw new Ho(`${e} must be a six-digit hex color`);return I.trim().toLowerCase()}function Zae(I){return{userId:I.user_id,fontSize:I.font_size,textColor:I.text_color,accentColor:I.accent_color,backgroundFilename:I.background_filename,backgroundOriginalName:I.background_original_name,backgroundMime:I.background_mime,createdAt:I.created_at,updatedAt:I.updated_at}}function BiI(I){return{userId:I,fontSize:iae,textColor:null,accentColor:null,backgroundFilename:null,backgroundOriginalName:null,backgroundMime:null,createdAt:0,updatedAt:0}}var Ho=class extends Error{};function Gm(I){return{fontSize:I.fontSize,textColor:I.textColor,accentColor:I.accentColor,background:I.backgroundFilename?{name:I.backgroundOriginalName||"background",mime:I.backgroundMime,updatedAt:I.updatedAt}:null,updatedAt:I.updatedAt}}function Wn(I){let e=fw(I),l=x();if(!l)return BiI(e);let t=l.prepare(`SELECT * FROM ${yr} WHERE user_id = ?`).get(e);return t?Zae(t):BiI(e)}function MiI(I,e){let l=fw(I);if(!e||typeof e!="object"||Array.isArray(e))throw new Ho("Invalid theme settings");let t=Wn(l),n=Object.prototype.hasOwnProperty.call(e,"fontSize")?mae(e.fontSize):t.fontSize,c=Object.prototype.hasOwnProperty.call(e,"textColor")?OiI(e.textColor,"Text color"):t.textColor,G=Object.prototype.hasOwnProperty.call(e,"accentColor")?OiI(e.accentColor,"Accent color"):t.accentColor,a=Date.now(),s=t.createdAt||a;return a9().prepare(`INSERT INTO ${yr}
|
|
@@ -2648,7 +2648,7 @@ ${i}`;let X=`cli_run_${Date.now().toString(36)}_${Math.random().toString(36).sli
|
|
|
2648
2648
|
`)}function hHe(I){let e=I.match(/\b(\d+)\s*\/\s*(\d+)\s+turns\b/i);if(!e)return null;let l=Number(e[1]),t=Number(e[2]);return!Number.isFinite(l)||!Number.isFinite(t)||t<=0?null:{used:l,max:t}}async function YHe(I,e){try{return await I.bridge.reloadSkills(I.profile)}catch(t){if(!(t instanceof Error?t.message:String(t)).includes("unknown action: skills_reload"))throw t}let l=await I.bridge.command(e,"reload-skills",I.profile);if(l.handled&&l.action==="reload-skills")return l;throw new Error("The running Agent Bridge does not support /reload-skills yet. Restart the bridge and try again.")}function VHe(I){let e=Array.isArray(I.added)?I.added:[],l=Array.isArray(I.removed)?I.removed:[],t=typeof I.total=="number"&&Number.isFinite(I.total)?I.total:null,n=["Skills reloaded successfully."];if(!e.length&&!l.length)return n.push(t===null?"No skill changes detected.":`No skill changes detected. Total skills: ${t}.`),n.join(`
|
|
2649
2649
|
`);if(e.length){n.push("Added skills:");for(let c of e)n.push(`- ${uCI(c)}`)}if(l.length){n.push("Removed skills:");for(let c of l)n.push(`- ${uCI(c)}`)}return t!==null&&n.push(`Total skills: ${t}.`),n.join(`
|
|
2650
2650
|
`)}function uCI(I){if(!I||typeof I!="object")return String(I||"");let e=I,l=typeof e.name=="string"?e.name:"",t=typeof e.description=="string"?e.description:"";return t?`${l}: ${t}`:l}function RHe(I,e,l){ZI(I)||Gn({id:I,profile:l.profile,source:"cli",model:l.model,title:FHe(e)})}function FHe(I){let e=`[${I.rawName}]`,l=I.args.replace(/\s+/g," ").trim();return l?`${e} ${l}`.slice(0,120):e}function WCI(I,e,l){let t=Math.floor(Date.now()/1e3),n=kl({session_id:I,role:"command",content:l,timestamp:t});e.messages.push({id:n||`command_${t}_${e.messages.length}`,session_id:I,role:"command",content:l,timestamp:t}),Ot(I)}function XHe(I,e,l){let t=ZI(I);if(!t||YCI(t))return null;let c=an(I)?.messages||[],G=QHe(c);if(!G)return null;let a=Math.floor(Date.now()/1e3),s=gHe(),d=HHe(e,t.title||t.preview||""),r=wHe(t.source),o=dA({id:s,profile:t.profile||l.profile||"default",source:r,agent:t.agent||(r==="cli"?"hermes":""),agent_mode:t.agent_mode||"",agent_session_id:t.agent_session_id||"",agent_native_session_id:t.agent_native_session_id||"",model:t.model||l.model||"",provider:t.provider||l.provider||"",api_mode:t.api_mode||"",title:d,parent_session_id:I,workspace:t.workspace||void 0,category_id:t.category_id??null,ended_at:a,last_active:a,messages:c.map(b=>({role:b.role,content:b.content,display_role:b.display_role,display_content:b.display_content,tool_call_id:b.tool_call_id,tool_calls:b.tool_calls,tool_name:b.tool_name,timestamp:b.timestamp,token_count:b.token_count,finish_reason:b.finish_reason,reasoning:b.reasoning,reasoning_details:b.reasoning_details,reasoning_content:b.reasoning_content}))});return o?{id:s,profile:t.profile||l.profile||"default",source:r,title:d,model:t.model||l.model||null,provider:t.provider||l.provider||null,parentSessionId:I,forkPointMessageId:o.fork_point_message_id||null,parentTitle:t.title||t.preview||null,parentLastMessage:G?.content||null,parentLastMessageRole:G?.role||null,createdAt:a*1e3,updatedAt:a*1e3,messageCount:c.length,workspace:t.workspace||null}:null}function YCI(I){return I?.source==="coding_agent"||I?.agent==="claude"||I?.agent==="codex"||I?.agent==="ekko-agent"}function gHe(){let I=new Date;return`${[I.getFullYear(),String(I.getMonth()+1).padStart(2,"0"),String(I.getDate()).padStart(2,"0"),"_",String(I.getHours()).padStart(2,"0"),String(I.getMinutes()).padStart(2,"0"),String(I.getSeconds()).padStart(2,"0")].join("")}_${Math.random().toString(16).slice(2,8)}`}function HHe(I,e){let l=I.replace(/\s+/g," ").trim();if(l)return l.slice(0,120);let t=e.replace(/\s+/g," ").trim()||"branch",n="branch: ";return`${n}${t.slice(0,Math.max(0,120-n.length))}`}function wHe(I){return I==="api_server"||I==="cli"||I==="global_agent"||I==="workflow"||I==="group_chat"?I:"cli"}function QHe(I){for(let e=I.length-1;e>=0;e-=1){let l=I[e];if(l.role!=="user"&&l.role!=="assistant")continue;let t=String(l.content||"").replace(/\s+/g," ").trim();if(t)return{role:l.role,content:t.length>280?`${t.slice(0,277)}...`:t}}return null}function Wr(I,e,l,t,n){let c={...n,session_id:l};I.to(`session:${l}`).emit(t,c),!I.adapter.rooms.get(`session:${l}`)?.size&&e.connected&&e.emit(t,c)}un();es();Yu();Dh();function yHe(I){return(typeof I.handshake.query?.profile=="string"?I.handshake.query.profile.trim():"")||uI()||"default"}function vHe(I,e,l,t){let n=e.backgroundDelegations?.[l];if(!n?.messageId)return;let c=n.dispatchPayload||{},G=Array.isArray(t.results)?t.results.filter(m=>m&&typeof m=="object"):[t],a=Object.values(e.backgroundTasks||{}).filter(m=>m.runtime!=="ekko"),s=Array.isArray(c.goals)?c.goals.map(m=>String(m||"").trim()):[],d=G.map((m,i)=>{let Z=Number.isFinite(Number(m.task_index))?Number(m.task_index):i,u=String(m.goal||s[Z]||t.goal||c.goal||"").trim(),p=a.find(W=>Number(W.task_index??0)===Z&&(!u||!String(W.goal||"").trim()||String(W.goal||"").trim()===u))||(G.length===1?a.find(W=>!u||String(W.goal||"").trim()===u):void 0),Y=String(m.summary||p?.summary||p?.preview||"").trim();return{runtime:"hermes",mode:"background",delegation_id:l,subagent_id:String(p?.subagent_id||m.subagent_id||`${l}:${Z}`),task_index:Z,task_count:G.length,goal:u,model:m.model||p?.model||t.model,status:String(m.status||p?.status||t.status||"completed"),summary:Y,output:Y,started_at:p?.started_at||t.dispatched_at,completed_at:p?.completed_at||t.completed_at,duration_seconds:m.duration_seconds||p?.duration_seconds||t.duration_seconds||t.total_duration_seconds,api_calls:m.api_calls||p?.api_calls||t.api_calls,input_tokens:m.input_tokens||p?.input_tokens,output_tokens:m.output_tokens||p?.output_tokens,cost_usd:m.cost_usd||p?.cost_usd}}),r=d.length===1?d[0]:{runtime:"hermes",mode:"background",delegation_id:l,status:String(t.status||"completed"),tasks:d},o=JSON.stringify(r);if(!ih(I,n.messageId,o))return;let b=e.messages.find(m=>String(m.id)===String(n.messageId)||n.toolCallId&&m.tool_call_id===n.toolCallId);b&&(b.display_content=o)}function Xj(I,e){let l=I.replace(/^Error:\s*/,"").trim()||"unknown error";return wV(l,e,"configured endpoint")||"unknown error"}function EHe(I){let e=I instanceof Error?I.message:String(I);return/^Agent bridge request timed out after \d+ms$/.test(e.trim())}function VCI(I){let e=I?.source||void 0;if(!e||e==="cli"||e==="api_server")return!0;if(e==="workflow"||e==="group_chat"){let t=String(I?.agent||"").trim();return t!=="claude"&&t!=="codex"&&t!=="ekko-agent"&&!I?.agent_session_id}if(e!=="global_agent")return!1;let l=String(I?.agent||"").trim();return l!=="claude"&&l!=="codex"&&l!=="ekko-agent"&&!I?.agent_session_id}function Rj(I){return I==="cli"||I==="global_agent"||I==="workflow"||I==="group_chat"}async function CHe(){try{let I=await An().ensureReady({timeoutMs:1e3,connectRetryMs:0,recover:!1});return I.reachable?{ok:!0}:{ok:!1,error:Xj(I.error||`Agent Bridge is ${I.status}`,I.endpoint)}}catch(I){return{ok:!1,error:Xj(I instanceof Error?I.message:String(I))}}}function Fj(I,e){return I==="coding_agent"||(I==="workflow"||I==="group_chat")&&!!(e?.coding_agent_id||e?.agent_id)}function JHe(I){let e=Number(I);return!Number.isSafeInteger(e)||e<=0?null:Ao(e)?e:null}function AHe(I){return I?.coding_agent_id==="ekko-agent"||I?.agent_id==="ekko-agent"}function Hb(I){let e=I?.coding_agent_id||I?.agent_id;return e==="ekko-agent"?"ekko":e==="codex"?"codex":e==="claude-code"?"claude-code":"bridge"}var F1=class{nsp;bridge=new ie;backgroundBridge=new ie({timeoutMs:1e3,connectRetryMs:0});sessionMap=new Map;bridgeResumePolls=new Set;runWaiters=new Map;backgroundPollTimer;backgroundPollInFlight=!1;backgroundRecoveryNeeded=!0;backgroundBrokerId;backgroundPollRetryAt=0;backgroundActivityGraceUntil=0;closing=!1;constructor(e){this.nsp=e.of("/chat-run")}init(){this.closing=!1,this.nsp.use(this.authMiddleware.bind(this)),this.nsp.on("connection",this.onConnection.bind(this)),this.backgroundPollTimer=setInterval(()=>{this.pollBackgroundWork()},500),this.backgroundPollTimer.unref?.(),this.pollBackgroundWork(),h.info("[chat-run-socket] Socket.IO ready at /chat-run")}async authMiddleware(e,l){let t=e.handshake.auth?.token;if(!await sG()){l();return}let n=await _n(t||"");if(!n)return l(new Error("Authentication failed"));let c=String(e.handshake.query?.profile||"").trim();if(c&&!this.canAccessProfile(n,c))return l(new Error("Profile access denied"));e.data.user=n,l()}onConnection(e){let l=e.data.user,t=e.handshake.query?.profile||"default",n=()=>t||uI()||"default";e.join(`pending-interactions:${n()}`);let c=s=>!s||s==="default"?!0:MI().includes(s),G=(s,d)=>{let r=typeof d=="string"?d.trim():"";if(r){if(!c(r))throw new Error(`Profile "${r}" does not exist`);if(l&&!this.canAccessProfile(l,r))throw new Error(`Profile "${r}" is not available for this user`);return r}if(!s){let m=n();if(l&&!this.canAccessProfile(l,m))throw new Error(`Profile "${m}" is not available for this user`);return m}let o=ZI(s)?.profile||"",b=o&&c(o)?o:n();if(l&&!this.canAccessProfile(l,b))throw new Error(`Profile "${b}" is not available for this user`);return b},a=s=>{let d=ZI(s);if(!d)throw new Error("Session not found");let r=String(d.profile||"default").trim()||"default",o=n();if(r!==o)throw new Error(`Profile "${r}" is not available on this connection`);if(!c(r))throw new Error(`Profile "${r}" does not exist`);if(l&&!this.canAccessProfile(l,r))throw new Error(`Profile "${r}" is not available for this user`);return r};e.on("run",async s=>{let d;try{d=G(s.session_id,s.profile)}catch(r){let o={event:"run.failed",session_id:s.session_id,queue_id:s.queue_id,error:r instanceof Error?r.message:String(r)};e.emit("run.failed",o);return}if(s.category_id!==void 0&&(s.category_id=JHe(s.category_id)),s.session_id){let r=vG(this.sessionMap,s.session_id),o=RN(s.source,s.session_id),b=Vj(s.input);if(b&&(Rj(o)||b.name==="branch")){try{if(await hCI(s.session_id,b,{nsp:this.nsp,socket:e,sessionMap:this.sessionMap,bridge:this.bridge,profile:d,model:s.model,provider:s.provider,model_groups:s.model_groups,instructions:s.instructions,queueId:s.queue_id,runQueuedItem:this.runQueuedItem.bind(this)})!==!1)return;s.allow_command_passthrough=!0}catch(m){this.emitToSession(e,s.session_id,"session.command",{event:"session.command",command:b.rawName,ok:!1,action:"error",message:m instanceof Error?m.message:String(m)})}return}if(r.isWorking){let m=s.queue_id||`queue_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,8)}`;r.queue.push({queue_id:m,input:s.input,displayInput:s.display_input,displayRole:s.display_role,storageMessage:s.storage_message,model:s.model,provider:s.provider,model_groups:s.model_groups,instructions:s.instructions,groupSystemPrompt:s.group_system_prompt,groupRoomId:s.group_room_id,groupAgentId:s.group_agent_id,workflowId:s.workflow_id,workflowNodeId:s.workflow_node_id,profile:d,workspace:s.workspace,source:o,sessionSource:s.session_source,codingAgentId:s.coding_agent_id,agentId:s.agent_id,mode:s.mode,baseUrl:s.baseUrl,base_url:s.base_url,apiKey:s.apiKey,api_key:s.api_key,apiMode:s.apiMode,api_mode:s.api_mode,mcpServers:s.mcpServers,mcp_servers:s.mcp_servers,commandPassthrough:s.allow_command_passthrough,reasoningEffort:s.reasoning_effort,originSocketId:e.id});let i={event:"run.queued",session_id:s.session_id,queue_id:m,queue_length:r.queue.length,queued_messages:this.serializeQueuedMessages(r.queue)};Yc({event:"run.queued",sessionId:s.session_id,profile:d,source:o,agent:Hb(s),payload:i,roomId:s.group_room_id,workflowId:s.workflow_id,workflowNodeId:s.workflow_node_id}),this.nsp.to(`session:${s.session_id}`).emit("run.queued",i),h.info("[chat-run-socket] queued run for session %s (queue: %d)",s.session_id,r.queue.length);return}r.events=[],r.isWorking=!Fj(o,s),r.profile=d,r.source=o}try{await this.handleRun(e,s,d)}catch(r){let o={event:"run.failed",session_id:s.session_id,queue_id:s.queue_id,error:r instanceof Error?r.message:String(r)};if(s.session_id&&Yc({event:"run.failed",sessionId:s.session_id,profile:d,source:RN(s.source,s.session_id),agent:Hb(s),payload:o,roomId:s.group_room_id,workflowId:s.workflow_id,workflowNodeId:s.workflow_node_id}),s.session_id){let b=this.sessionMap.get(s.session_id);b&&!b.runId&&!b.abortController&&!b.activeRunMarker&&(b.isWorking=!1,b.profile=void 0)}e.emit("run.failed",o)}}),e.on("cancel_queued_run",s=>{if(!s.session_id||!s.queue_id)return;try{a(s.session_id)}catch{return}let d=this.sessionMap.get(s.session_id);if(!d?.queue.length)return;let r=d.queue.length;d.queue=d.queue.filter(o=>o.queue_id!==s.queue_id),d.queue.length!==r&&(this.nsp.to(`session:${s.session_id}`).emit("run.queued",{event:"run.queued",session_id:s.session_id,queue_length:d.queue.length,queued_messages:this.serializeQueuedMessages(d.queue)}),h.info("[chat-run-socket] cancelled queued run %s for session %s (queue: %d)",s.queue_id,s.session_id,d.queue.length))}),e.on("resume",async s=>{if(!s.session_id)return;let d=s.session_id;try{a(d)}catch(r){e.emit("run.failed",{event:"run.failed",session_id:d,error:r instanceof Error?r.message:String(r)});return}e.join(`session:${d}`),await this.resumeSession(e,d)}),e.on("abort",s=>{if(s.session_id){try{a(s.session_id)}catch{return}d0(this.nsp,e,s.session_id,this.sessionMap,this.bridge,this.runQueuedItem.bind(this))}}),e.on("approval.respond",async s=>{if(!s.session_id||!s.approval_id)return;try{a(s.session_id)}catch(r){e.emit("approval.resolved",{event:"approval.resolved",session_id:s.session_id,approval_id:s.approval_id,choice:s.choice||"deny",resolved:!1,error:r instanceof Error?r.message:String(r)});return}let d=hu(s.session_id,s.approval_id,s.choice);if(d.handled){d.resolved||this.emitToSession(e,s.session_id,"approval.resolved",{event:"approval.resolved",approval_id:s.approval_id,choice:d.choice,resolved:!1,error:"Approval does not belong to this session."});return}try{let r=await this.bridge.approvalRespond(s.approval_id,s.choice||"deny");this.emitToSession(e,s.session_id,"approval.resolved",{event:"approval.resolved",approval_id:s.approval_id,choice:s.choice||"deny",resolved:!!r.resolved})}catch(r){this.emitToSession(e,s.session_id,"approval.resolved",{event:"approval.resolved",approval_id:s.approval_id,choice:s.choice||"deny",resolved:!1,error:r instanceof Error?r.message:String(r)})}}),e.on("clarify.respond",async s=>{if(!s.session_id||!s.clarify_id)return;try{a(s.session_id)}catch(r){e.emit("clarify.resolved",{event:"clarify.resolved",session_id:s.session_id,clarify_id:s.clarify_id,resolved:!1,error:r instanceof Error?r.message:String(r)});return}let d=Gg(s.session_id,s.clarify_id,s.response);if(d.handled){d.resolved?this.clearClarifyEventState(s.session_id,s.clarify_id):this.emitToSession(e,s.session_id,"clarify.resolved",{event:"clarify.resolved",clarify_id:s.clarify_id,resolved:!1,error:"Clarification does not belong to this session."});return}try{let r=await this.bridge.clarifyRespond(s.clarify_id,s.response||"");this.emitToSession(e,s.session_id,"clarify.resolved",{event:"clarify.resolved",clarify_id:s.clarify_id,resolved:!!r?.resolved}),r?.resolved&&this.clearClarifyEventState(s.session_id,s.clarify_id)}catch(r){this.emitToSession(e,s.session_id,"clarify.resolved",{event:"clarify.resolved",clarify_id:s.clarify_id,resolved:!1,error:r instanceof Error?r.message:String(r)})}})}async handleRun(e,l,t,n=!1){let c=RN(l.source,l.session_id);if(l.session_id){let a=vG(this.sessionMap,l.session_id);a.webhookAgent=Hb(l),a.webhookRoomId=l.group_room_id,a.webhookWorkflowId=l.workflow_id,a.webhookWorkflowNodeId=l.workflow_node_id}if(l.session_id&&Rj(c)&&NCI(l.input)&&l.allow_command_passthrough!==!0)return;if(!Fj(c,l)){let a=await CHe();if(!a.ok){let r=!1,o=0;if(l.session_id){let m=this.sessionMap.get(l.session_id);if(o=m?.queue?.length??0,m&&!m.runId&&!m.abortController&&!m.activeRunMarker)if(o>0){let Z=m.queue[0];m.isWorking=!0,m.profile=Z?.profile||t,m.source=Z?.source,r=!0}else m.isWorking=!1,m.profile=void 0}let b={event:"run.failed",session_id:l.session_id,queue_id:l.queue_id,error:`Agent Bridge is not reachable: ${a.error}`};l.session_id&&Yc({event:"run.failed",sessionId:l.session_id,profile:t,source:c,agent:Hb(l),payload:b,roomId:l.group_room_id,workflowId:l.workflow_id,workflowNodeId:l.workflow_node_id}),o>0&&(b.queue_remaining=o),e.emit("run.failed",b),l.session_id&&l.background_delegation_id&&l.background_claim_id&&this.bridge.releaseBackgroundNotification(l.session_id,t,l.background_delegation_id,l.background_claim_id).catch(m=>h.warn(m,"[chat-run-socket] failed to release undelivered background notification")),l.session_id&&r&&this.dequeueNextQueuedRun(e,l.session_id,t);return}let s=l.instructions?`${Xc(void 0,{source:c})}
|
|
2651
|
-
${l.instructions}`:Xc(void 0,{source:c}),d=(r,o)=>{Yc({event:r,sessionId:String(l.session_id||o?.session_id||""),profile:t,source:c,agent:"bridge",payload:o,roomId:l.group_room_id,workflowId:l.workflow_id,workflowNodeId:l.workflow_node_id}),l.onEvent?.(r,o),this.emitPendingInteraction(t,r,o)};await $1I(this.nsp,e,{...l,instructions:s,onEvent:d},t,this.sessionMap,this.bridge,n,R1,this.dequeueNextQueuedRun.bind(this));return}if(AHe(l)){let a=(s,d)=>{Yc({event:s,sessionId:String(l.session_id||d?.session_id||""),profile:t,source:c,agent:"ekko",payload:d,roomId:l.group_room_id,workflowId:l.workflow_id,workflowNodeId:l.workflow_node_id}),l.onEvent?.(s,d),this.emitPendingInteraction(t,s,d)};await iCI(this.nsp,e,{...l,onEvent:a},t,this.sessionMap,this.dequeueNextQueuedRun.bind(this),n);return}let G=await nCI(this.nsp,e,l,t,this.sessionMap);G&&l.session_id&&(Yc({event:"message.created",sessionId:l.session_id,profile:t,source:c,agent:Hb(l),payload:{event:"message.created",queue_id:l.queue_id,message_id:G.messageId,role:l.display_role==="command"?"command":"user",content:l.display_input===null?l.storage_message||Ft(l.input):Ft(l.display_input??l.input),timestamp:Math.floor(Date.now()/1e3)},roomId:l.group_room_id,workflowId:l.workflow_id,workflowNodeId:l.workflow_node_id}),Yc({event:"run.started",sessionId:l.session_id,profile:t,source:c,agent:Hb(l),payload:{event:"run.started",run_id:G.runId,queue_id:l.queue_id},roomId:l.group_room_id,workflowId:l.workflow_id,workflowNodeId:l.workflow_node_id}))}backgroundPendingCount(e){let l=Object.values(e.backgroundDelegations||{}).filter(t=>t.status==="running"||t.status==="delivering").length;return l>0?l:Object.values(e.backgroundTasks||{}).filter(t=>t.status==="running").length}async sessionStateForBackground(e){let l=this.sessionMap.get(e);if(l)return l;if(!ZI(e))return null;let t=await R1(e,this.sessionMap);return this.sessionMap.set(e,t),t}applyBackgroundSessionPoll(e,l){((e.events?.length||0)>0||e.running_count>0)&&(this.backgroundActivityGraceUntil=Date.now()+3e4),l.backgroundTasks=l.backgroundTasks||{};for(let t of e.tasks||[]){let n=String(t.subagent_id||"").trim();n&&(l.backgroundTasks[n]={...t})}for(let t of e.events||[]){let n=String(t.event||"");n.startsWith("subagent.")&&this.emitExternalEvent(e.session_id,n,{...t,event:n,profile:e.profile,background:!0})}}socketForBackgroundRun(e){let l=this.nsp.adapter.rooms.get(`session:${e}`);if(l)for(let t of l){let n=this.nsp.sockets.get(t);if(n)return n}return{id:`background-run-${e}`,connected:!1,data:{},join:()=>{},emit:(t,n)=>this.nsp.to(`session:${e}`).emit(t,n),to:t=>({emit:(n,c)=>this.nsp.to(t).emit(n,c)})}}async scheduleBackgroundNotification(e){let l=String(e.session_id||"").trim(),t=String(e.delegation_id||"").trim(),n=String(e.claim_id||"").trim();if(!l||!t||!n||!e.message)return;let c=()=>this.backgroundBridge.releaseBackgroundNotification(l,e.profile,t,n);if(this.closing){await c();return}let G=ZI(l);if(!G){h.warn("[chat-run-socket] acknowledging orphaned background delegation %s for missing session %s",t,l),await this.backgroundBridge.completeBackgroundNotification(l,e.profile,t,n);return}let a=await this.sessionStateForBackground(l);if(!a){await c();return}if(this.closing){await c();return}a.backgroundDelegations=a.backgroundDelegations||{},vHe(l,a,t,e.event||{});let s=a.backgroundDelegations[t];a.backgroundDelegations[t]={...s,delegationId:t,status:"delivering",profile:e.profile,updatedAt:Date.now()},this.emitExternalEvent(l,"delegation.updated",{event:"delegation.updated",profile:e.profile,delegation_id:t,status:e.status||"completed",delivery_status:"delivering",background_pending:this.backgroundPendingCount(a)});let d={queue_id:`delegation_${t}`,input:e.message,displayInput:null,storageMessage:e.message,model:G.model||void 0,provider:G.provider||void 0,profile:e.profile||G.profile||"default",workspace:G.workspace,source:RN(G.source||void 0,l),backgroundDelegationId:t,backgroundClaimId:n,autonomous:!0};if(a.isWorking){a.queue.push(d),h.info("[chat-run-socket] queued background delegation %s for busy session %s",t,l);return}a.isWorking=!0,a.profile=d.profile,a.source=d.source,this.runQueuedItem(this.socketForBackgroundRun(l),l,d,d.profile)}needsBackgroundPoll(){if(this.closing)return!1;if(this.backgroundRecoveryNeeded||Date.now()<this.backgroundActivityGraceUntil)return!0;for(let e of this.sessionMap.values())if(Object.values(e.backgroundDelegations||{}).some(l=>l.status==="running"||l.status==="delivering")||Object.values(e.backgroundTasks||{}).some(l=>l.status==="running"&&l.runtime!=="ekko"))return!0;return!1}backgroundRecoveryRoutes(){let e=Math.floor(Date.now()/1e3)-691200,l=new Map;for(let t of Gd(void 0,void 0,1e4)){if(t.last_active<e||!VCI(t))continue;let n=t.profile||"default",c=l.get(n)||[];c.push(t.id),l.set(n,c)}return[...l.entries()].map(([t,n])=>({profile:t,session_ids:n}))}async pollBackgroundWork(){if(!(this.closing||this.backgroundPollInFlight||Date.now()<this.backgroundPollRetryAt||!this.needsBackgroundPoll())){this.backgroundPollInFlight=!0;try{let e=this.backgroundRecoveryNeeded,l=e?this.backgroundRecoveryRoutes():void 0,t=await this.backgroundBridge.backgroundPoll(l,{timeoutMs:e?12e4:1e3});if(this.closing){await Promise.allSettled((t.notifications||[]).map(c=>this.backgroundBridge.releaseBackgroundNotification(c.session_id,c.profile,c.delegation_id,c.claim_id)));return}let n=!!(this.backgroundBrokerId&&t.broker_id&&t.broker_id!==this.backgroundBrokerId);t.broker_id&&(this.backgroundBrokerId=t.broker_id),this.backgroundRecoveryNeeded=n&&!e,this.backgroundPollRetryAt=0,(t.pending_count||0)>0&&(this.backgroundActivityGraceUntil=Date.now()+31e4);for(let c of t.sessions||[]){let G=String(c.session_id||"").trim();if(!G)continue;let a=await this.sessionStateForBackground(G);a&&this.applyBackgroundSessionPoll(c,a)}for(let c of t.notifications||[])await this.scheduleBackgroundNotification(c)}catch(e){this.backgroundPollRetryAt=Date.now()+5e3,h.debug(e,"[chat-run-socket] background bridge poll unavailable")}finally{this.backgroundPollInFlight=!1}}}async resumeSession(e,l){let t=this.sessionMap.get(l);t||(t=await R1(l,this.sessionMap),this.sessionMap.set(l,t)),await this.reattachBridgeRun(e,l,t);let n=t.isWorking?t.events:(t.events||[]).filter(G=>G?.event==="run.reattach_failed"),c=rA(l);e.emit("resumed",{session_id:l,messages:t.messages,messageTotal:t.messageTotal,messageLoadedCount:t.messageLoadedCount,messagePageLimit:t.messagePageLimit,hasMoreBefore:t.hasMoreBefore,parentSessionId:c?.parent_session_id||null,forkPointMessageId:c?.fork_point_message_id||null,parentTitle:c?.parent_title||null,parentLastMessage:c?.parent_last_message||null,parentLastMessageRole:c?.parent_last_message_role||null,workspace:c?.workspace||null,isWorking:t.isWorking,isAborting:t.isAborting||!1,events:n,inputTokens:t.inputTokens,outputTokens:t.outputTokens,contextTokens:t.contextTokens,queueLength:t.queue?.length||0,queueMessages:this.serializeQueuedMessages(t.queue||[]),backgroundTasks:Object.values(t.backgroundTasks||{}),backgroundPending:this.backgroundPendingCount(t)}),h.info("[chat-run-socket] socket %s resumed session %s (working: %s, messages: %d)",e.id,l,t.isWorking,t.messages.length)}async reattachBridgeRun(e,l,t){if(t.runId&&t.isWorking)return;let n=ZI(l),c=t.source||n?.source;if(!VCI({source:c,agent:n?.agent,agent_session_id:n?.agent_session_id}))return;let G=n?.profile||yHe(e),a;try{let s=await this.bridge.statusIfLoaded(l,G,{timeoutMs:1e3}),d=s.running===!0,r=typeof s.current_run_id=="string"?s.current_run_id:"";if(!d||!r||(a=`${l}:${r}`,this.bridgeResumePolls.has(a)))return;this.bridgeResumePolls.add(a),t.isWorking=!0,t.isAborting=t.isAborting===!0,t.runId=r,t.activeRunMarker=void 0,t.profile=G,t.source=c==="global_agent"?"global_agent":c==="group_chat"?"group_chat":c==="workflow"?"workflow":"cli",t.events=[];let o=this.resumeInstructionsForSession(l);ICI(this.nsp,e,{sessionId:l,runId:r,profile:G,instructions:o,model:n?.model,provider:n?.provider,workspace:n?.workspace,source:c,onEvent:(b,m)=>Yc({event:b,sessionId:l,profile:G,source:String(c||"cli"),agent:"bridge",payload:m})},this.sessionMap,this.bridge,this.dequeueNextQueuedRun.bind(this)).finally(()=>{a&&this.bridgeResumePolls.delete(a)}),h.info("[chat-run-socket] reattached running bridge run %s for session %s",r,l)}catch(s){if(a&&this.bridgeResumePolls.delete(a),EHe(s)){h.debug(s,"[chat-run-socket] bridge status lookup timed out while resuming session %s",l);return}h.warn(s,"[chat-run-socket] bridge status lookup failed while resuming session %s",l);let d=An().getRuntimeState?.().endpoint,r=Xj(s instanceof Error?s.message:String(s),d),o={event:"run.reattach_failed",session_id:l,error:r,message:`Unable to confirm Agent Bridge status while resuming: ${r}`,text:`Unable to confirm Agent Bridge status while resuming: ${r}`},b=[...t.events||[]],m=b[b.length-1];(m?.event!=="run.reattach_failed"||m?.data?.error!==r)&&(b.push({event:"run.reattach_failed",data:o}),t.events=b),this.emitToSession(e,l,"run.reattach_failed",o)}}resumeInstructionsForSession(e){let l=ZI(e);return Xc(void 0,{source:l?.source})}dequeueNextQueuedRun(e,l,t="default"){let n=this.sessionMap.get(l);if(!n?.queue.length)return!1;let c=n.queue.shift();return n.isWorking=!0,n.profile=c.profile||t,n.source=c.source,h.info("[chat-run-socket] dequeuing queued run for session %s (remaining: %d)",l,n.queue.length),this.nsp.to(`session:${l}`).emit("run.queued",{event:"run.queued",session_id:l,queue_length:n.queue.length,dequeued_queue_id:c.queue_id,queued_messages:this.serializeQueuedMessages(n.queue)}),this.runQueuedItem(e,l,c,t),!0}runQueuedItem(e,l,t,n="default"){let c=t.displayInput===null;this.handleRun(e,{input:t.input,display_input:t.displayInput,display_role:t.displayRole,storage_message:t.storageMessage,session_id:l,model:t.model,provider:t.provider,model_groups:t.model_groups,instructions:t.instructions,group_system_prompt:t.groupSystemPrompt,group_room_id:t.groupRoomId,group_agent_id:t.groupAgentId,workflow_id:t.workflowId,workflow_node_id:t.workflowNodeId,workspace:t.workspace,source:t.source,session_source:t.sessionSource,queue_id:t.queue_id,peerExcludeSocketId:t.originSocketId,coding_agent_id:t.codingAgentId,agent_id:t.agentId,mode:t.mode,baseUrl:t.baseUrl,base_url:t.base_url,apiKey:t.apiKey,api_key:t.api_key,apiMode:t.apiMode,api_mode:t.api_mode,mcpServers:t.mcpServers,mcp_servers:t.mcp_servers,one_shot_model:t.oneShotModel,allow_command_passthrough:t.commandPassthrough,reasoning_effort:t.reasoningEffort,background_delegation_id:t.backgroundDelegationId,background_claim_id:t.backgroundClaimId,autonomous:t.autonomous},t.profile||n,c)}async runAndWait(e,l={}){let t=String(e.session_id||"").trim();if(!t)throw new Error("session_id is required");let n=l.profile||e.profile||ZI(t)?.profile||uI()||"default",c=RN(e.source,t),G=vG(this.sessionMap,t);return G.events=[],G.isWorking=!Fj(c,e),G.profile=n,G.source=c,new Promise(a=>{let s=!1,d="",r="",o="",b=l.timeoutMs&&l.timeoutMs>0?l.timeoutMs:null,m=this.runWaiters.get(t)||new Set,i=W=>{s||(s=!0,p&&clearTimeout(p),m.delete(u),m.size===0&&this.runWaiters.delete(t),a({session_id:t,run_id:o||W.run_id,output:d||W.output,reasoning:r||W.reasoning,...W}))},Z=async(W={})=>{let N=l.approvalChoice;if(!N||s)return;let V=typeof W.approval_id=="string"?W.approval_id:"",R=Array.isArray(W.choices)?W.choices.map(X=>String(X)):[],F=R.length>0?R:["once","session","deny"];if(!V){i({ok:!1,event:"run.failed",output:d,reasoning:r,error:"approval required"});return}if(!F.includes(N)){i({ok:!1,event:"run.failed",output:d,reasoning:r,error:`approval choice "${N}" is not available`});return}try{let X=await this.bridge.approvalRespond(V,N),v={event:"approval.resolved",session_id:t,approval_id:V,choice:N,resolved:!!X?.resolved};Yc({event:"approval.resolved",sessionId:t,profile:n,source:c,agent:Hb(e),payload:v,roomId:e.group_room_id,workflowId:e.workflow_id,workflowNodeId:e.workflow_node_id}),this.nsp.to(`session:${t}`).emit("approval.resolved",v),u("approval.resolved",v)}catch(X){let v=X instanceof Error?X.message:String(X);this.nsp.to(`session:${t}`).emit("approval.resolved",{event:"approval.resolved",session_id:t,approval_id:V,choice:N,resolved:!1,error:v}),i({ok:!1,event:"run.failed",output:d,reasoning:r,error:v})}},u=(W,N={})=>{typeof N.run_id=="string"&&N.run_id&&(o=N.run_id),W==="message.delta"&&typeof N.delta=="string"&&(d+=N.delta),(W==="reasoning.delta"||W==="thinking.delta")&&typeof N.delta=="string"&&(r+=N.delta);try{l.onEvent?.(W,N)}catch(V){h.warn(V,"[chat-run-socket] runAndWait event observer failed for session %s",t)}W==="approval.requested"?Z(N):W==="run.completed"?i({ok:!0,event:"run.completed",run_id:N.run_id,output:typeof N.output=="string"&&N.output?N.output:d,reasoning:typeof N.reasoning=="string"&&N.reasoning?N.reasoning:r}):W==="run.failed"&&i({ok:!1,event:"run.failed",run_id:N.run_id,output:d,reasoning:r,error:N.error?String(N.error):"chat-run failed"})},p=b?setTimeout(()=>{let W=`chat-run timed out after ${b}ms`;i({ok:!1,event:"run.failed",error:W}),this.abortSession(t,W).catch(N=>{h.warn(N,"[chat-run-socket] failed to abort timed-out session %s",t)})},b):null;m.add(u),this.runWaiters.set(t,m);let Y={id:`workflow-run-${t}`,connected:!0,data:{user:l.user},join:()=>{},to:W=>({emit:(N,V)=>{this.nsp.to(W).emit(N,V),u(N,V)}}),emit:(W,N)=>u(W,N)};this.handleRun(Y,{...e,onEvent:u},n).catch(W=>{let N=W instanceof Error?W.message:String(W),V={event:"run.failed",session_id:t,error:N};Yc({event:"run.failed",sessionId:t,profile:n,source:c,agent:Hb(e),payload:V,roomId:e.group_room_id,workflowId:e.workflow_id,workflowNodeId:e.workflow_node_id}),i({ok:!1,event:"run.failed",error:N})})})}async abortSession(e,l="Run canceled"){let t=String(e||"").trim();if(!t)return;let n={id:`workflow-abort-${t}`,connected:!1,data:{},emit:()=>{},join:()=>{},to:c=>({emit:(G,a)=>this.nsp.to(c).emit(G,a)})};await d0(this.nsp,n,t,this.sessionMap,this.bridge,this.runQueuedItem.bind(this)),this.emitExternalEvent(t,"run.failed",{event:"run.failed",error:l})}async disposeSession(e){let l=String(e||"").trim();if(!l)return;Ae.stop(l,{reportClosed:!1}),this.sessionMap.get(l)?.abortController?.abort(),this.sessionMap.delete(l),this.runWaiters.delete(l),vr(l)}emitExternalEvent(e,l,t){let n={...t,session_id:e},c=this.resolvePetEventProfile(e,n),G=this.sessionMap.get(e),a=ZI(e),s=String(a?.agent||"");Yc({event:l,sessionId:e,profile:c,source:G?.source||a?.source||"coding_agent",agent:G?.webhookAgent||(s==="codex"?"codex":s==="ekko-agent"?"ekko":"claude-code"),payload:n,roomId:G?.webhookRoomId,workflowId:G?.webhookWorkflowId,workflowNodeId:G?.webhookWorkflowNodeId}),this.observePetEvent(c,l,n),G?.isWorking&&(G.events.push({event:l,data:n}),G.events.length>200&&G.events.splice(0,G.events.length-200)),this.nsp.to(`session:${e}`).emit(l,n);let d=this.runWaiters.get(e);if(d)for(let r of d)r(l,n)}markExternalRunCompleted(e,l){let t=this.sessionMap.get(e);if(t&&(t.isWorking=!1,t.abortController=void 0,t.runId=void 0,t.activeRunMarker=void 0,t.events=[],t.responseRun=void 0,t.profile=void 0,h.info("[chat-run-socket] external run completed for session %s (%s)",e,l),t.queue.length>0)){let n=this.socketForQueuedRun(e,t.queue[0]);n&&this.dequeueNextQueuedRun(n,e)}}clearSessionHistory(e){let l=$b(e),t=this.sessionMap.get(e),n=!!t,c=t?.messagePageLimit;if(t){if(t.abortController?.abort(),t.isWorking&&Rj(t.source)){let G=t.profile;this.bridge.interrupt(e,"Session cleared",G).catch(a=>h.warn(a,"[chat-run-socket] failed to interrupt bridge run while clearing session %s",e))}t.messages=[],t.messageTotal=0,t.messageLoadedCount=0,t.hasMoreBefore=!1,t.inputTokens=0,t.outputTokens=0,t.contextTokens=0,t.events=[],t.queue=[],t.bridgePendingAssistantContent=void 0,t.bridgePendingReasoningContent=void 0,t.bridgePendingToolCallMarkup=void 0,t.bridgeOutput=void 0,t.bridgePendingTools=void 0,t.bridgeCompressionResults=void 0,t.responseRun=void 0,t.activeRunMarker=void 0,t.runId=void 0,t.abortController=void 0,t.isAborting=!1,t.isWorking=!1,t.profile=void 0,this.sessionMap.delete(e)}return this.nsp.emit("session.command",{event:"session.command",session_id:e,command:"clear",ok:!0,action:"clear",clearHistory:!0,source:"mcu",deleted:l,memory_cleared:n}),this.nsp.emit("resumed",{session_id:e,messages:[],messageTotal:0,messageLoadedCount:0,messagePageLimit:c,hasMoreBefore:!1,isWorking:!1,isAborting:!1,events:[],inputTokens:0,outputTokens:0,contextTokens:0,queueLength:0,queueMessages:[]}),this.nsp.emit("run.queued",{event:"run.queued",session_id:e,queue_length:0,queued_messages:[]}),h.info({sessionId:e,deleted:l,hadMemoryState:n},"[chat-run-socket] cleared session history and memory state"),{deleted:l,hadMemoryState:n}}socketForQueuedRun(e,l){if(l?.originSocketId){let n=this.nsp.sockets.get(l.originSocketId);if(n)return n}let t=this.nsp.adapter.rooms.get(`session:${e}`);if(t)for(let n of t){let c=this.nsp.sockets.get(n);if(c)return c}return this.nsp.sockets.values().next().value||null}clearClarifyEventState(e,l){let t=this.sessionMap.get(e);if(!t?.events.length)return;let n=t.events.filter(({event:c,data:G})=>c!=="clarify.requested"&&c!=="clarify.resolved"?!0:G?.clarify_id!==l);n.length!==t.events.length&&(t.events=n)}emitToSession(e,l,t,n){let c={...n,session_id:l},G=this.resolvePetEventProfile(l,c),a=this.sessionMap.get(l),s=ZI(l),d=String(s?.agent||"");Yc({event:t,sessionId:l,profile:G,source:a?.source||s?.source||"chat",agent:a?.webhookAgent||(d==="codex"?"codex":d==="ekko-agent"?"ekko":"bridge"),payload:c,roomId:a?.webhookRoomId,workflowId:a?.webhookWorkflowId,workflowNodeId:a?.webhookWorkflowNodeId}),this.observePetEvent(G,t,c),this.emitPendingInteraction(G,t,c),this.nsp.to(`session:${l}`).emit(t,c),!this.nsp.adapter.rooms.get(`session:${l}`)?.size&&e.connected&&e.emit(t,c)}emitPendingInteraction(e,l,t){if(l!=="approval.requested"&&l!=="approval.resolved"&&l!=="clarify.requested"&&l!=="clarify.resolved")return;let n=typeof t?.session_id=="string"?t.session_id:"";(n?this.sessionMap.get(n)?.source||ZI(n)?.source:void 0)!=="group_chat"&&this.nsp.to(`pending-interactions:${e}`).emit(l,t)}serializeQueuedMessages(e){return e.filter(l=>l.displayInput!==null).map(l=>({id:l.queue_id,role:l.displayRole||(typeof l.displayInput=="string"&&l.displayInput.trim().startsWith("/")?"command":"user"),content:Ft(l.displayInput??l.input),timestamp:Math.floor(Date.now()/1e3),queued:!0}))}canAccessProfile(e,l){return e.role==="super_admin"||aG(e.id,l)}async close(){if(this.closing)return;this.closing=!0,this.backgroundPollTimer&&(clearInterval(this.backgroundPollTimer),this.backgroundPollTimer=void 0);let e=[];for(let[t,n]of this.sessionMap.entries()){if(n.abortController)try{n.abortController.abort()}catch(c){h.warn(c,"[chat-run-socket] failed to abort controller for session %s",t)}for(let c of n.queue)!c.backgroundDelegationId||!c.backgroundClaimId||e.push(this.backgroundBridge.releaseBackgroundNotification(t,c.profile,c.backgroundDelegationId,c.backgroundClaimId))}this.sessionMap.clear();let l=await Promise.allSettled(e);for(let t of l)t.status==="rejected"&&h.warn(t.reason,"[chat-run-socket] failed to release queued background notification on close");await Promise.allSettled([this.bridge.close(),this.backgroundBridge.close()]),h.info("[chat-run-socket] closed all connections and cleared state")}resolvePetEventProfile(e,l){let t=typeof l.profile=="string"?l.profile.trim():"";if(t)return t;let n=this.sessionMap.get(e)?.profile;return n||ZI(e)?.profile||"default"}observePetEvent(e,l,t){try{hN(e,l,t)}catch(n){h.debug(n,"[chat-run-socket] failed to update pet state")}}};xa();var Ss=require("node:fs"),FCI=require("node:os"),Gt=require("node:path");AI();Me();dI();fl();wI();var kHe="hermes-studio",r0=[{name:"hermes-studio-api",toolset:"api"},{name:"hermes-studio-browser",toolset:"browser"},{name:"hermes-studio-devices",toolset:"devices"},{name:"hermes-studio-use",toolset:"use"}],LHe=new Set(r0.map(I=>I.name)),fHe=1860,xHe=new Set([kHe,"hermes-web-ui-mcp","hermes-studio-mcp"]),X1="HERMES_WEB_UI_MANAGED_MCP",zHe=new Set(["hermes-lan-peer-mcp","hermes-devices-mcp","hermes-web-ui-mcp","hermes-studio-mcp"]);function XCI(I){return["1","true","yes","on"].includes(String(I||"").trim().toLowerCase())}function UHe(){return XCI(process.env.HERMES_WEB_UI_DISABLE_MCP_AUTOINJECT)}function OHe(){return XCI(process.env.HERMES_WEB_UI_ALLOW_TRANSIENT_MCP_AUTOINJECT)}function dZ(I){try{return(0,Ss.realpathSync)(I)}catch{return(0,Gt.resolve)(I)}}function RCI(I){let e=dZ(I);return[(0,FCI.tmpdir)(),"/tmp","/private/tmp"].filter(Boolean).some(l=>ce(e,dZ(l)))}function BHe(I){try{let e=(0,Ss.readFileSync)(I,"utf8").split(/\r?\n/,1)[0]?.trim()||"",l=/^gitdir:\s*(.+)$/i.exec(e);if(!l)return!1;let t=dZ((0,Gt.resolve)((0,Gt.dirname)(I),l[1].trim())),n=(0,Ss.readFileSync)((0,Gt.join)(t,"commondir"),"utf8").trim();if(!n)return!1;let c=dZ((0,Gt.resolve)(t,n));return dZ((0,Gt.dirname)(t))===dZ((0,Gt.join)(c,"worktrees"))}catch{return!1}}function MHe(I){let e=(0,Gt.dirname)(dZ(I));for(;;){let l=(0,Gt.join)(e,".git");if((0,Ss.existsSync)(l))try{let n=(0,Ss.statSync)(l);if(n.isFile())return BHe(l);if(n.isDirectory())return!1}catch{return!1}let t=(0,Gt.dirname)(e);if(t===e)return!1;e=t}}function SHe(I){return OHe()?!1:RCI(B.appHome)||I!==null&&(RCI(I)||MHe(I))}function jHe(){return String(process.env.HERMES_DESKTOP||"").trim().toLowerCase()==="true"}function gCI(){return[process.env.HERMES_WEB_UI_MCP_BIN,(0,Gt.join)(process.cwd(),"bin/hermes-studio-mcp.mjs"),(0,Gt.join)(__dirname,"../../bin/hermes-studio-mcp.mjs"),(0,Gt.join)(__dirname,"../../../../../bin/hermes-studio-mcp.mjs"),(0,Gt.join)(process.cwd(),"bin/hermes-web-ui-mcp.mjs"),(0,Gt.join)(__dirname,"../../bin/hermes-web-ui-mcp.mjs"),(0,Gt.join)(__dirname,"../../../../../bin/hermes-web-ui-mcp.mjs")].filter(I=>!!I)}function THe(){return gCI().find(I=>(0,Ss.existsSync)(I))||null}function KHe(){return process.env.HERMES_AGENT_NODE?.trim()||null}function DHe(I,e){return e?{command:KHe()||process.execPath,args:[e,I]}:jHe()?{command:"hermes-studio-mcp",args:[I]}:(h.warn({candidates:gCI()},"[mcp-autoinject] bundled MCP script not found; falling back to PATH command"),{command:"hermes-studio-mcp",args:[I]})}function HCI(I,e,l,t){let n={HERMES_WEB_UI_URL:`http://127.0.0.1:${B.port}`,HERMES_WEB_UI_HOME:B.appHome,HERMES_WEBUI_STATE_DIR:B.appHome,HERMES_WEB_UI_PROFILE:I,HERMES_MCP_SERVER_NAME:e,HERMES_MCP_TOOLSET:l,[X1]:"1"};return{...DHe(l,t),...l==="use"?{timeout:fHe}:{},env:n,enabled:!0}}function FN(I){return!!I&&typeof I=="object"&&!Array.isArray(I)}function gj(I){return FN(I)?FN(I.env)&&I.env[X1]==="1"?!0:typeof I.command=="string"&&zHe.has(I.command):!1}function _He(I,e){let l=Array.isArray(e.args)?e.args:void 0,t=Array.isArray(I.args)?I.args:void 0;return!l&&!t?!0:!l||!t?!1:l.length===t.length&&l.every((n,c)=>t[c]===n)}function qHe(I,e){let l=e.env;return I.command===e.command&&_He(I,e)&&(e.timeout===void 0||I.timeout===e.timeout)&&I.enabled!==!1&&FN(I.env)&&I.env.HERMES_WEB_UI_URL===l.HERMES_WEB_UI_URL&&I.env.HERMES_WEB_UI_HOME===l.HERMES_WEB_UI_HOME&&I.env.HERMES_WEBUI_STATE_DIR===l.HERMES_WEBUI_STATE_DIR&&I.env.HERMES_WEB_UI_PROFILE===l.HERMES_WEB_UI_PROFILE&&I.env.HERMES_MCP_SERVER_NAME===l.HERMES_MCP_SERVER_NAME&&I.env.HERMES_MCP_TOOLSET===l.HERMES_MCP_TOOLSET&&I.env.HERMES_WEB_UI_TOKEN===void 0&&I.env[X1]===l[X1]}async function PHe(I,e){return await zl(I,l=>{let t=FN(l)?l:{};FN(t.mcp_servers)||(t.mcp_servers={});let n=!1,c=!1,G=!1;for(let[a,s]of Object.entries(t.mcp_servers))if(!LHe.has(a)){if(xHe.has(a)&&!gj(s))return{data:t,write:!1,result:{profile:I,status:"skipped",reason:`existing ${a} MCP server is not managed by Hermes Web UI`}};gj(s)&&(delete t.mcp_servers[a],n=!0,G=!0)}for(let a of r0){let s=HCI(I,a.name,a.toolset,e),d=t.mcp_servers[a.name];if(!d){t.mcp_servers[a.name]=s,n=!0,c=!0;continue}if(G=!0,!gj(d))return{data:t,write:!1,result:{profile:I,status:"skipped",reason:`existing ${a.name} MCP server is not managed by Hermes Web UI`}};if(FN(d)&&d.enabled===!1)return{data:t,write:!1,result:{profile:I,status:"skipped",reason:`existing ${a.name} MCP server is disabled by user`}};qHe(d,s)||(t.mcp_servers[a.name]=s.timeout===void 0&&Object.hasOwn(d,"timeout")?{...s,timeout:d.timeout}:s,n=!0)}return n?{data:t,result:{profile:I,status:c&&!G?"injected":"updated"}}:{data:t,write:!1,result:{profile:I,status:"unchanged"}}})}async function wCI(){let I=THe(),e=HCI("default",r0[0].name,r0[0].toolset,I),l={serverNames:r0.map(c=>c.name),command:String(e.command),targets:[]};if(UHe())return h.info("[mcp-autoinject] disabled by HERMES_WEB_UI_DISABLE_MCP_AUTOINJECT"),l;if(SHe(I))return h.info({appHome:B.appHome,bundledScript:I},"[mcp-autoinject] skipped for transient Web UI home or MCP launcher"),l;for(let c of MI())l.targets.push(await PHe(c,I));let t=l.targets.filter(c=>c.status==="injected"||c.status==="updated");t.length>0&&h.info({serverNames:l.serverNames,command:e.command,targets:t},"[mcp-autoinject] synced bundled MCP server");let n=l.targets.filter(c=>c.status==="skipped");return n.length>0&&h.warn({serverNames:l.serverNames,targets:n},"[mcp-autoinject] skipped unmanaged MCP server entries"),l}hW();$y();di();un();v2();dI();tN();var $He="/workflow";function QCI(I){return(typeof I=="string"?I.trim():"")||null}function vCI(I){return!I||I.role==="super_admin"?null:new Set(tt(I.id).map(e=>e.profile_name))}function Hj(I,e){let l=vCI(I);return!l||l.has(e||"default")}function yCI(I,e){let l=vCI(I);return l?e.filter(t=>l.has(t.profile||"default")):e}function pr(I,e){typeof I=="function"&&I(e)}var g1=class{nsp;manager;removeStatusListener;constructor(e,l=be()){this.manager=l,this.nsp=e.of($He),this.removeStatusListener=this.manager.onRuntimeStatus(t=>this.emitRuntimeStatus(t))}init(){this.nsp.use(this.authMiddleware.bind(this)),this.nsp.on("connection",this.onConnection.bind(this)),h.info("[workflow-socket] Socket.IO ready at /workflow")}close(){this.removeStatusListener()}async authMiddleware(e,l){if(!await sG()){l();return}let t=e.handshake.auth?.token,n=await _n(t||"");if(!n){l(new Error("Authentication failed"));return}let c=QCI(e.handshake.query?.profile);if(c&&!Hj(n,c)){l(new Error("Profile access denied"));return}e.data.user=n,l()}onConnection(e){e.on("workflows.list",(l,t)=>{let n=typeof l=="function"?l:t,c=typeof l=="function"?{}:l||{};this.handleList(e,c,n)}),e.on("workflow.status.subscribe",(l,t)=>{let n=typeof l=="function"?l:t,c=typeof l=="function"?{}:l||{};this.handleStatusSubscribe(e,c,n)}),e.on("workflow.status.unsubscribe",(l,t)=>{this.handleStatusUnsubscribe(e,l||{},t)})}handleList(e,l,t){let n=e.data.user,c=QCI(l.profile);if(c&&!Hj(n,c)){pr(t,{ok:!1,error:`Profile "${c}" is not available for this user`});return}let G=yCI(n,this.manager.list(c));pr(t,{ok:!0,data:{workflows:G}})}handleStatusSubscribe(e,l,t){let n=typeof l.workflowId=="string"?l.workflowId.trim():"";if(n){let s=this.manager.get(n),d=e.data.user;if(!s){pr(t,{ok:!1,error:"workflow not found"});return}if(!Hj(d,s.profile)){pr(t,{ok:!1,error:`Profile "${s.profile}" is not available for this user`});return}try{let r=this.statusWithEvidence(this.manager.getRuntimeStatus(n));e.join(this.workflowRoom(n)),pr(t,{ok:!0,data:{statuses:[r]}})}catch(r){h.error(r,"[workflow-socket] failed to load persisted execution evidence for workflow %s",n),pr(t,{ok:!1,error:r?.message||"workflow evidence read failed"})}return}let c=e.data.user,G=yCI(c,this.manager.list()),a=new Set(G.map(s=>s.id));for(let s of a)e.join(this.workflowRoom(s));try{let s=this.manager.listRuntimeStatuses().filter(d=>a.has(d.workflowId)).map(d=>this.statusWithEvidence(d));pr(t,{ok:!0,data:{statuses:s}})}catch(s){h.error(s,"[workflow-socket] failed to load persisted execution evidence for workflow status subscription"),pr(t,{ok:!1,error:s?.message||"workflow evidence read failed"})}}handleStatusUnsubscribe(e,l,t){let n=typeof l.workflowId=="string"?l.workflowId.trim():"";if(n)e.leave(this.workflowRoom(n));else for(let c of e.rooms)c.startsWith("workflow:")&&c.endsWith(":status")&&e.leave(c);pr(t,{ok:!0,data:{ok:!0}})}statusWithEvidence(e){if(!e.runId)return{...e,run:null};let l=qp(e.runId);if(!l)throw new Error(`workflow run ${e.runId} is unavailable while loading persisted evidence`);return{...e,run:l}}emitRuntimeStatus(e){try{this.nsp.to(this.workflowRoom(e.workflowId)).emit("workflow.status.updated",this.statusWithEvidence(e))}catch(l){h.error(l,"[workflow-socket] failed to load persisted execution evidence for workflow %s",e.workflowId),this.nsp.to(this.workflowRoom(e.workflowId)).emit("workflow.status.error",{workflowId:e.workflowId,runId:e.runId,error:l?.message||"workflow evidence read failed"})}}workflowRoom(e){return`workflow:${e}:status`}};dI();var Ac=require("zlib"),Iwe=1024,CCI=256*1024,ewe=new Set(["application/ecmascript","application/javascript","application/json","application/ld+json","application/manifest+json","application/rss+xml","application/wasm","application/xhtml+xml","application/xml","application/x-javascript","image/svg+xml","text/javascript"]);function lwe(I){let e=I.split(";",1)[0]?.trim().toLowerCase()||"";return e?e.startsWith("text/")||ewe.has(e)||e.endsWith("+json")||e.endsWith("+xml"):!1}function ECI(I,e){let l=null,t=null;for(let n of I.split(",")){let[c,...G]=n.split(";"),a=c?.trim().toLowerCase();if(!a)continue;let s=1;for(let d of G){let[r,o]=d.split("=");if(r?.trim().toLowerCase()!=="q")continue;let b=Number(o?.trim());s=Number.isFinite(b)?Math.max(0,Math.min(b,1)):0}a===e&&(t=s),a==="*"&&(l=s)}return t??l??0}function twe(I,e={}){let l=ECI(I,"br"),t=ECI(I,"gzip"),n=e.bodyLength??null,c=e.maxBrotliBytes??CCI;return l<=0&&t<=0?null:l>=t?n!==null&&n>c?t>0?"gzip":null:"br":"gzip"}function JCI(I){return!!I&&typeof I.pipe=="function"}function ACI(I,e){if(Buffer.isBuffer(e))return e.byteLength;if(typeof e=="string")return Buffer.byteLength(e);let l=Number(I.response.get("Content-Length"));return Number.isFinite(l)&&l>=0?l:null}function nwe(I,e){if(I.method==="HEAD"||I.status<200||I.status>=300||I.status===204||I.get("Range")||I.response.get("Content-Encoding")||!lwe(I.response.get("Content-Type")||I.type||""))return!1;let l=I.body;if(!l||!(Buffer.isBuffer(l)||typeof l=="string"||JCI(l)))return!1;let t=ACI(I,l);return t===null||t>=e}function cwe(I,e){return e==="br"?(0,Ac.brotliCompressSync)(I,{params:{[Ac.constants.BROTLI_PARAM_QUALITY]:Ac.constants.BROTLI_DEFAULT_QUALITY}}):(0,Ac.gzipSync)(I)}function Gwe(I){return I==="br"?(0,Ac.createBrotliCompress)({params:{[Ac.constants.BROTLI_PARAM_QUALITY]:Ac.constants.BROTLI_DEFAULT_QUALITY}}):(0,Ac.createGzip)()}function kCI(I={}){let e=I.minBytes??Iwe,l=I.maxBrotliBytes??CCI;return async(t,n)=>{if(await n(),!nwe(t,e))return;let c=t.body,G=ACI(t,c);t.vary("Accept-Encoding");let a=twe(t.get("Accept-Encoding"),{bodyLength:G,maxBrotliBytes:l});if(a){if(t.set("Content-Encoding",a),Buffer.isBuffer(c)||typeof c=="string"){let s=Buffer.isBuffer(c)?c:Buffer.from(c),d=cwe(s,a);if(d.byteLength>=s.byteLength){t.remove("Content-Encoding");return}t.body=d,t.set("Content-Length",String(d.byteLength));return}JCI(c)&&(t.remove("Content-Length"),t.body=c.pipe(Gwe(a)))}}}var awe="public, max-age=31536000, immutable",wj="no-cache";function LCI(I){let e=I.replaceAll("\\","/").replace(/^\.\//,"");return e==="index.html"?wj:e.startsWith("assets/")?awe:null}var cAI=T(Q5I(),1),GAI=T(nAI(),1),aAI=T(MN(),1),dC=["json","form","text","xml"],sAI=class extends Error{constructor(I){super(),this.name="UnsupportedBodyTypeError",this.message=`Invalid enabled type '${I}'. make sure to pass an array contains supported types ([${dC}]).`}};function REe(I){for(let l of I)if(!dC.includes(l))throw new sAI(l);return dC.reduce((l,t)=>({...l,[t]:I.includes(t)}),{})}function FEe(I){for(let t of Object.keys(I)){let n=I[t];if(!dC.includes(t)||!Array.isArray(n))throw new sAI(t)}return(0,GAI.default)({json:["application/json","application/json-patch+json","application/vnd.api+json","application/csp-report","application/reports+json","application/scim+json"],form:["application/x-www-form-urlencoded"],text:["text/plain"],xml:["text/xml","application/xml"]},I)}function XEe(I,e){return typeof I=="string"&&(I=I.replace(/;$/,"")),aAI.default.is(I,e)}function dAI(I={}){let{patchNode:e=!1,parsedMethods:l=["POST","PUT","PATCH"],detectJSON:t,onError:n,enableTypes:c=["json","form"],extendTypes:G={},enableRawChecking:a=!1,...s}=I,d=REe(c),r=FEe(G);async function o(b){let m=u=>!!(d[u]&&XEe(b.request.get("content-type"),r[u])),i=t?.(b)||m("json")?"json":m("form")?"form":m("text")||m("xml")?"text":null;if(!i)return{};let Z={returnRawBody:!0,strict:i==="json"?s.jsonStrict:void 0,[`${i}Types`]:r[i],limit:s[`${m("xml")?"xml":i}Limit`],encoding:s.encoding||"utf-8"};return cAI.default[i](b,Z)}return async function(m,i){if(!l.includes(m.method.toUpperCase())||e&&m.req.body!==void 0||m.request.body!==void 0||m.disableBodyParser)return i();if(a&&m.req.body!==void 0)return m.request.body=m.req.body,i();if(m.req.closed){m.status=499,m.body="Request already closed";return}try{let Z=await o(m);e&&(m.req.body="parsed"in Z?Z.parsed:{},m.req.rawBody===void 0&&(m.req.rawBody=Z.raw)),m.request.body="parsed"in Z?Z.parsed:{},m.request.rawBody===void 0&&(m.request.rawBody=Z.raw)}catch(Z){if(!n)throw Z;n(Z,m)}return i()}}function rAI(){return dAI({encoding:"utf-8",enableTypes:["json","form","text"],jsonLimit:"20mb",formLimit:"20mb",textLimit:"20mb",parsedMethods:["POST","PUT","PATCH","DELETE"]})}var HEe="0.6.40";process.on("uncaughtException",I=>{console.error("FATAL: Uncaught exception"),console.error(I),h.fatal(I,"Uncaught exception"),process.exit(1)});process.on("unhandledRejection",I=>{console.error("Unhandled rejection"),console.error(I),h.error(I,"Unhandled rejection")});var iAI=null,Eb=[],Q0=null,mAI=null,ZAI=null,wEe=null,rC=null,zT=null;function QEe(I,e,l){return new Promise((t,n)=>{let c=I.listen(e,l);c.once("listening",()=>t(c)),c.once("error",n)})}async function yEe(I,e,l){let t=l||"0.0.0.0";console.log(`[bootstrap] listening on ${t}:${e}`);let n=await QEe(I,e,t);return{primary:n,servers:[n]}}function vEe(I){let e=I?.address?.();return`http://127.0.0.1:${typeof e=="object"&&e?.port?e.port:B.port}`}function EEe(){try{return NAI.default.networkInterfaces()}catch{return{}}}function UT(){return String(process.env.HERMES_DESKTOP||"").trim().toLowerCase()==="true"}function CEe(I){return I?I==="127.0.0.1"||I==="::1"||I==="::ffff:127.0.0.1"||I.startsWith("::ffff:127."):!1}function JEe(I){return I.get("authorization").match(/^Bearer\s+(.+)$/i)?.[1]?.trim()||""}function AEe(I){I.use(async(e,l)=>{if(e.method!=="POST"||e.path!=="/api/desktop/shutdown"){await l();return}if(!UT()){e.status=404,e.body={error:"not_found"};return}let t=e.req.socket.remoteAddress;if(!CEe(t)){e.status=403,e.body={error:"forbidden"};return}let n=String(process.env.AUTH_TOKEN||"").trim();if(!n||JEe(e)!==n){e.status=401,e.body={error:"unauthorized"};return}if(!zT){e.status=503,e.body={error:"shutdown_not_ready"};return}e.status=202,e.body={ok:!0},setTimeout(()=>{zT?.("desktop-api")},50).unref?.()})}function hAI(I){let e=String(process.env[I]||"").trim().toLowerCase();return["1","true","yes","on"].includes(e)}function YAI(){return hAI("HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART")}function kEe(){return hAI("HERMES_WEB_UI_DISABLE_SKILL_INJECTION")}async function LEe(){YAI()?console.log("[bootstrap] profile gateway check disabled by HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART"):Wx().then(()=>console.log("[bootstrap] profile gateways checked")).catch(I=>{h.warn(I,"[bootstrap] failed to ensure profile gateways"),console.warn("[bootstrap] failed to ensure profile gateways:",I instanceof Error?I.message:I)});try{rC=await xA(),console.log("[bootstrap] agent bridge started")}catch(I){h.warn(I,"[bootstrap] agent bridge failed to start"),console.warn("[bootstrap] agent bridge failed to start:",I instanceof Error?I.message:I)}}function fEe(){YAI()?console.log("[bootstrap] profile gateway check disabled by HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART"):(async()=>{try{await Wx(),console.log("[bootstrap] profile gateways checked")}catch(I){h.warn(I,"[bootstrap] failed to ensure profile gateways"),console.warn("[bootstrap] failed to ensure profile gateways:",I instanceof Error?I.message:I)}})(),(async()=>{try{rC=await xA(),console.log("[bootstrap] agent bridge started")}catch(I){h.warn(I,"[bootstrap] agent bridge failed to start"),console.warn("[bootstrap] agent bridge failed to start:",I instanceof Error?I.message:I);return}})()}function xEe(){let I=tmI({httpPort:B.port}),e=!1,l=()=>{e||(e=!0,Mw().catch(t=>h.warn(t,"[lan-discovery] initial scan failed")))};I?(I.once("listening",l),setTimeout(l,500).unref?.()):l()}async function VAI(){if(console.log(`hermes-web-ui v${HEe} starting...`),await(0,xT.mkdir)(B.uploadDir,{recursive:!0}),U6()&&await(0,xT.mkdir)(B.dataDir,{recursive:!0}),await s8(),kEe())console.log("[bootstrap] bundled skill injection disabled by HERMES_WEB_UI_DISABLE_SKILL_INJECTION");else try{let Z=await new vm().injectMissingSkills();Z.injected.length>0&&h.info({injected:[...new Set(Z.injected)],targetCount:Z.targets.length},"[bootstrap] bundled skills injected"),Z.updated.length>0&&h.info({updated:[...new Set(Z.updated)],targetCount:Z.targets.length},"[bootstrap] bundled skills updated")}catch(i){h.warn(i,"[bootstrap] failed to inject bundled skills"),console.warn("[bootstrap] failed to inject bundled skills:",i instanceof Error?i.message:i)}try{await wCI()}catch(i){h.warn(i,"[bootstrap] failed to inject bundled MCP server"),console.warn("[bootstrap] failed to inject bundled MCP server:",i instanceof Error?i.message:i)}HL(),console.log("[bootstrap] ekko-agent setup complete"),UT()||await LEe();let I=new LP,{initAllStores:e}=await Promise.resolve().then(()=>(bAI(),oAI));e(),NbI(),console.log("[bootstrap] all stores initialized"),I.use(liI()),I.use((0,uAI.default)({origin:IiI(B.corsOrigins)})),I.use(rAI()),console.log("[bootstrap] cors + bodyParser registered"),AEe(I),C1I(I,[PbI,$bI]),console.log("[bootstrap] routes registered");let l=(0,oC.resolve)(__dirname,"..","client");I.use(kCI()),I.use((0,WAI.default)(l,{setHeaders(i,Z){let u=LCI((0,oC.relative)(l,Z));u&&i.setHeader("Cache-Control",u)}})),I.use(async i=>{(i.method==="GET"||i.method==="HEAD")&&!i.path.startsWith("/api")&&i.path!=="/health"&&i.path!=="/upload"&&(i.set("Cache-Control",wj),await(0,pAI.default)(i,"index.html",{root:l}))}),console.log("[bootstrap] SPA fallback registered");let t=await yEe(I,B.port,B.host);iAI=t.primary,Eb=t.servers,console.log("[bootstrap] app.listen called"),ciI(Eb),wiI(Eb),Fc().setupServer(Eb),console.log("[bootstrap] terminal + kanban + LAN peer websocket setup");let n=new dy(Eb);VhI(n),wEe=new Wy(n.getIO(),n),Q0=new F1(n.getIO()),Cf(Q0),n.setChatRunService(Q0),Q0.init(),Vs(()=>n.getChatRunService()).restore();let{getWorkflowManager:c}=await Promise.resolve().then(()=>(tN(),qHI)),G=await c().recoverActiveRuns();G.runs>0&&h.warn("Recovered %d orphaned workflow runs and aborted %d sessions",G.runs,G.sessions);let{getWorkflowScheduleService:a}=await Promise.resolve().then(()=>($M(),hwI));a().start(),mAI=new g1(n.getIO()),mAI.init(),ZAI=new h1(n.getIO()),ZAI.init();let s=vEe(iAI);XZI(n.getIO(),{localBaseUrl:s}),console.log("[bootstrap] global agent server ready");let{SessionDeleter:d}=await Promise.resolve().then(()=>(TQ(),EpI)),r=d.getInstance(),o=process.env.PROFILE||"default";r.start(o),console.log("[bootstrap] session deleter started, profile=%s",o),Eb.forEach(i=>{i.on("upgrade",(Z,u)=>{let p=new URL(Z.url||"",`http://${Z.headers.host}`);p.pathname!=="/api/hermes/terminal"&&p.pathname!=="/api/hermes/kanban/events"&&p.pathname!==fmI()&&!p.pathname.startsWith("/socket.io/")&&u.destroy()})});let b=EEe(),m=Object.values(b).flat().find(i=>i?.family==="IPv4"&&!i?.internal)?.address||"localhost";console.log(`Server: http://localhost:${B.port} (LAN: http://${m}:${B.port})`),console.log(`Log: ${B.appHome}/logs/server.log`),h.info("Server: http://localhost:%d (LAN: http://%s:%d)",B.port,m,B.port),xEe(),QRI("bootstrap"),UT()&&(rC=An(),fEe()),n.restoreWhenReady(),Eb.forEach(i=>{i.on("error",Z=>{console.error("[bootstrap] server error:",Z.code||Z.message),h.error({err:Z},"Server error")})}),zT=FbI(Eb,n,Q0,rC),c9()}VAI().catch(I=>{console.error("FATAL: Failed to start Hermes Web UI"),console.error(I),h.fatal(I,"Fatal error during bootstrap"),process.exit(1)});0&&(module.exports={bootstrap});
|
|
2651
|
+
${l.instructions}`:Xc(void 0,{source:c}),d=(r,o)=>{Yc({event:r,sessionId:String(l.session_id||o?.session_id||""),profile:t,source:c,agent:"bridge",payload:o,roomId:l.group_room_id,workflowId:l.workflow_id,workflowNodeId:l.workflow_node_id}),l.onEvent?.(r,o),this.emitPendingInteraction(t,r,o)};await $1I(this.nsp,e,{...l,instructions:s,onEvent:d},t,this.sessionMap,this.bridge,n,R1,this.dequeueNextQueuedRun.bind(this));return}if(AHe(l)){let a=(s,d)=>{Yc({event:s,sessionId:String(l.session_id||d?.session_id||""),profile:t,source:c,agent:"ekko",payload:d,roomId:l.group_room_id,workflowId:l.workflow_id,workflowNodeId:l.workflow_node_id}),l.onEvent?.(s,d),this.emitPendingInteraction(t,s,d)};await iCI(this.nsp,e,{...l,onEvent:a},t,this.sessionMap,this.dequeueNextQueuedRun.bind(this),n);return}let G=await nCI(this.nsp,e,l,t,this.sessionMap);G&&l.session_id&&(Yc({event:"message.created",sessionId:l.session_id,profile:t,source:c,agent:Hb(l),payload:{event:"message.created",queue_id:l.queue_id,message_id:G.messageId,role:l.display_role==="command"?"command":"user",content:l.display_input===null?l.storage_message||Ft(l.input):Ft(l.display_input??l.input),timestamp:Math.floor(Date.now()/1e3)},roomId:l.group_room_id,workflowId:l.workflow_id,workflowNodeId:l.workflow_node_id}),Yc({event:"run.started",sessionId:l.session_id,profile:t,source:c,agent:Hb(l),payload:{event:"run.started",run_id:G.runId,queue_id:l.queue_id},roomId:l.group_room_id,workflowId:l.workflow_id,workflowNodeId:l.workflow_node_id}))}backgroundPendingCount(e){let l=Object.values(e.backgroundDelegations||{}).filter(t=>t.status==="running"||t.status==="delivering").length;return l>0?l:Object.values(e.backgroundTasks||{}).filter(t=>t.status==="running").length}async sessionStateForBackground(e){let l=this.sessionMap.get(e);if(l)return l;if(!ZI(e))return null;let t=await R1(e,this.sessionMap);return this.sessionMap.set(e,t),t}applyBackgroundSessionPoll(e,l){((e.events?.length||0)>0||e.running_count>0)&&(this.backgroundActivityGraceUntil=Date.now()+3e4),l.backgroundTasks=l.backgroundTasks||{};for(let t of e.tasks||[]){let n=String(t.subagent_id||"").trim();n&&(l.backgroundTasks[n]={...t})}for(let t of e.events||[]){let n=String(t.event||"");n.startsWith("subagent.")&&this.emitExternalEvent(e.session_id,n,{...t,event:n,profile:e.profile,background:!0})}}socketForBackgroundRun(e){let l=this.nsp.adapter.rooms.get(`session:${e}`);if(l)for(let t of l){let n=this.nsp.sockets.get(t);if(n)return n}return{id:`background-run-${e}`,connected:!1,data:{},join:()=>{},emit:(t,n)=>this.nsp.to(`session:${e}`).emit(t,n),to:t=>({emit:(n,c)=>this.nsp.to(t).emit(n,c)})}}async scheduleBackgroundNotification(e){let l=String(e.session_id||"").trim(),t=String(e.delegation_id||"").trim(),n=String(e.claim_id||"").trim();if(!l||!t||!n||!e.message)return;let c=()=>this.backgroundBridge.releaseBackgroundNotification(l,e.profile,t,n);if(this.closing){await c();return}let G=ZI(l);if(!G){h.warn("[chat-run-socket] acknowledging orphaned background delegation %s for missing session %s",t,l),await this.backgroundBridge.completeBackgroundNotification(l,e.profile,t,n);return}let a=await this.sessionStateForBackground(l);if(!a){await c();return}if(this.closing){await c();return}a.backgroundDelegations=a.backgroundDelegations||{},vHe(l,a,t,e.event||{});let s=a.backgroundDelegations[t];a.backgroundDelegations[t]={...s,delegationId:t,status:"delivering",profile:e.profile,updatedAt:Date.now()},this.emitExternalEvent(l,"delegation.updated",{event:"delegation.updated",profile:e.profile,delegation_id:t,status:e.status||"completed",delivery_status:"delivering",background_pending:this.backgroundPendingCount(a)});let d={queue_id:`delegation_${t}`,input:e.message,displayInput:null,storageMessage:e.message,model:G.model||void 0,provider:G.provider||void 0,profile:e.profile||G.profile||"default",workspace:G.workspace,source:RN(G.source||void 0,l),backgroundDelegationId:t,backgroundClaimId:n,autonomous:!0};if(a.isWorking){a.queue.push(d),h.info("[chat-run-socket] queued background delegation %s for busy session %s",t,l);return}a.isWorking=!0,a.profile=d.profile,a.source=d.source,this.runQueuedItem(this.socketForBackgroundRun(l),l,d,d.profile)}needsBackgroundPoll(){if(this.closing)return!1;if(this.backgroundRecoveryNeeded||Date.now()<this.backgroundActivityGraceUntil)return!0;for(let e of this.sessionMap.values())if(Object.values(e.backgroundDelegations||{}).some(l=>l.status==="running"||l.status==="delivering")||Object.values(e.backgroundTasks||{}).some(l=>l.status==="running"&&l.runtime!=="ekko"))return!0;return!1}backgroundRecoveryRoutes(){let e=Math.floor(Date.now()/1e3)-691200,l=new Map;for(let t of Gd(void 0,void 0,1e4)){if(t.last_active<e||!VCI(t))continue;let n=t.profile||"default",c=l.get(n)||[];c.push(t.id),l.set(n,c)}return[...l.entries()].map(([t,n])=>({profile:t,session_ids:n}))}async pollBackgroundWork(){if(!(this.closing||this.backgroundPollInFlight||Date.now()<this.backgroundPollRetryAt||!this.needsBackgroundPoll())){this.backgroundPollInFlight=!0;try{let e=this.backgroundRecoveryNeeded,l=e?this.backgroundRecoveryRoutes():void 0,t=await this.backgroundBridge.backgroundPoll(l,{timeoutMs:e?12e4:1e3});if(this.closing){await Promise.allSettled((t.notifications||[]).map(c=>this.backgroundBridge.releaseBackgroundNotification(c.session_id,c.profile,c.delegation_id,c.claim_id)));return}let n=!!(this.backgroundBrokerId&&t.broker_id&&t.broker_id!==this.backgroundBrokerId);t.broker_id&&(this.backgroundBrokerId=t.broker_id),this.backgroundRecoveryNeeded=n&&!e,this.backgroundPollRetryAt=0,(t.pending_count||0)>0&&(this.backgroundActivityGraceUntil=Date.now()+31e4);for(let c of t.sessions||[]){let G=String(c.session_id||"").trim();if(!G)continue;let a=await this.sessionStateForBackground(G);a&&this.applyBackgroundSessionPoll(c,a)}for(let c of t.notifications||[])await this.scheduleBackgroundNotification(c)}catch(e){this.backgroundPollRetryAt=Date.now()+5e3,h.debug(e,"[chat-run-socket] background bridge poll unavailable")}finally{this.backgroundPollInFlight=!1}}}async resumeSession(e,l){let t=this.sessionMap.get(l);t||(t=await R1(l,this.sessionMap),this.sessionMap.set(l,t)),await this.reattachBridgeRun(e,l,t);let n=t.isWorking?t.events:(t.events||[]).filter(G=>G?.event==="run.reattach_failed"),c=rA(l);e.emit("resumed",{session_id:l,messages:t.messages,messageTotal:t.messageTotal,messageLoadedCount:t.messageLoadedCount,messagePageLimit:t.messagePageLimit,hasMoreBefore:t.hasMoreBefore,parentSessionId:c?.parent_session_id||null,forkPointMessageId:c?.fork_point_message_id||null,parentTitle:c?.parent_title||null,parentLastMessage:c?.parent_last_message||null,parentLastMessageRole:c?.parent_last_message_role||null,workspace:c?.workspace||null,isWorking:t.isWorking,isAborting:t.isAborting||!1,events:n,inputTokens:t.inputTokens,outputTokens:t.outputTokens,contextTokens:t.contextTokens,queueLength:t.queue?.length||0,queueMessages:this.serializeQueuedMessages(t.queue||[]),backgroundTasks:Object.values(t.backgroundTasks||{}),backgroundPending:this.backgroundPendingCount(t)}),h.info("[chat-run-socket] socket %s resumed session %s (working: %s, messages: %d)",e.id,l,t.isWorking,t.messages.length)}async reattachBridgeRun(e,l,t){if(t.runId&&t.isWorking)return;let n=ZI(l),c=t.source||n?.source;if(!VCI({source:c,agent:n?.agent,agent_session_id:n?.agent_session_id}))return;let G=n?.profile||yHe(e),a;try{let s=await this.bridge.statusIfLoaded(l,G,{timeoutMs:1e3}),d=s.running===!0,r=typeof s.current_run_id=="string"?s.current_run_id:"";if(!d||!r||(a=`${l}:${r}`,this.bridgeResumePolls.has(a)))return;this.bridgeResumePolls.add(a),t.isWorking=!0,t.isAborting=t.isAborting===!0,t.runId=r,t.activeRunMarker=void 0,t.profile=G,t.source=c==="global_agent"?"global_agent":c==="group_chat"?"group_chat":c==="workflow"?"workflow":"cli",t.events=[];let o=this.resumeInstructionsForSession(l);ICI(this.nsp,e,{sessionId:l,runId:r,profile:G,instructions:o,model:n?.model,provider:n?.provider,workspace:n?.workspace,source:c,onEvent:(b,m)=>Yc({event:b,sessionId:l,profile:G,source:String(c||"cli"),agent:"bridge",payload:m})},this.sessionMap,this.bridge,this.dequeueNextQueuedRun.bind(this)).finally(()=>{a&&this.bridgeResumePolls.delete(a)}),h.info("[chat-run-socket] reattached running bridge run %s for session %s",r,l)}catch(s){if(a&&this.bridgeResumePolls.delete(a),EHe(s)){h.debug(s,"[chat-run-socket] bridge status lookup timed out while resuming session %s",l);return}h.warn(s,"[chat-run-socket] bridge status lookup failed while resuming session %s",l);let d=An().getRuntimeState?.().endpoint,r=Xj(s instanceof Error?s.message:String(s),d),o={event:"run.reattach_failed",session_id:l,error:r,message:`Unable to confirm Agent Bridge status while resuming: ${r}`,text:`Unable to confirm Agent Bridge status while resuming: ${r}`},b=[...t.events||[]],m=b[b.length-1];(m?.event!=="run.reattach_failed"||m?.data?.error!==r)&&(b.push({event:"run.reattach_failed",data:o}),t.events=b),this.emitToSession(e,l,"run.reattach_failed",o)}}resumeInstructionsForSession(e){let l=ZI(e);return Xc(void 0,{source:l?.source})}dequeueNextQueuedRun(e,l,t="default"){let n=this.sessionMap.get(l);if(!n?.queue.length)return!1;let c=n.queue.shift();return n.isWorking=!0,n.profile=c.profile||t,n.source=c.source,h.info("[chat-run-socket] dequeuing queued run for session %s (remaining: %d)",l,n.queue.length),this.nsp.to(`session:${l}`).emit("run.queued",{event:"run.queued",session_id:l,queue_length:n.queue.length,dequeued_queue_id:c.queue_id,queued_messages:this.serializeQueuedMessages(n.queue)}),this.runQueuedItem(e,l,c,t),!0}runQueuedItem(e,l,t,n="default"){let c=t.displayInput===null;this.handleRun(e,{input:t.input,display_input:t.displayInput,display_role:t.displayRole,storage_message:t.storageMessage,session_id:l,model:t.model,provider:t.provider,model_groups:t.model_groups,instructions:t.instructions,group_system_prompt:t.groupSystemPrompt,group_room_id:t.groupRoomId,group_agent_id:t.groupAgentId,workflow_id:t.workflowId,workflow_node_id:t.workflowNodeId,workspace:t.workspace,source:t.source,session_source:t.sessionSource,queue_id:t.queue_id,peerExcludeSocketId:t.originSocketId,coding_agent_id:t.codingAgentId,agent_id:t.agentId,mode:t.mode,baseUrl:t.baseUrl,base_url:t.base_url,apiKey:t.apiKey,api_key:t.api_key,apiMode:t.apiMode,api_mode:t.api_mode,mcpServers:t.mcpServers,mcp_servers:t.mcp_servers,one_shot_model:t.oneShotModel,allow_command_passthrough:t.commandPassthrough,reasoning_effort:t.reasoningEffort,background_delegation_id:t.backgroundDelegationId,background_claim_id:t.backgroundClaimId,autonomous:t.autonomous},t.profile||n,c)}async runAndWait(e,l={}){let t=String(e.session_id||"").trim();if(!t)throw new Error("session_id is required");let n=l.profile||e.profile||ZI(t)?.profile||uI()||"default",c=RN(e.source,t),G=vG(this.sessionMap,t);return G.events=[],G.isWorking=!Fj(c,e),G.profile=n,G.source=c,new Promise(a=>{let s=!1,d="",r="",o="",b=l.timeoutMs&&l.timeoutMs>0?l.timeoutMs:null,m=this.runWaiters.get(t)||new Set,i=W=>{s||(s=!0,p&&clearTimeout(p),m.delete(u),m.size===0&&this.runWaiters.delete(t),a({session_id:t,run_id:o||W.run_id,output:d||W.output,reasoning:r||W.reasoning,...W}))},Z=async(W={})=>{let N=l.approvalChoice;if(!N||s)return;let V=typeof W.approval_id=="string"?W.approval_id:"",R=Array.isArray(W.choices)?W.choices.map(X=>String(X)):[],F=R.length>0?R:["once","session","deny"];if(!V){i({ok:!1,event:"run.failed",output:d,reasoning:r,error:"approval required"});return}if(!F.includes(N)){i({ok:!1,event:"run.failed",output:d,reasoning:r,error:`approval choice "${N}" is not available`});return}try{let X=await this.bridge.approvalRespond(V,N),v={event:"approval.resolved",session_id:t,approval_id:V,choice:N,resolved:!!X?.resolved};Yc({event:"approval.resolved",sessionId:t,profile:n,source:c,agent:Hb(e),payload:v,roomId:e.group_room_id,workflowId:e.workflow_id,workflowNodeId:e.workflow_node_id}),this.nsp.to(`session:${t}`).emit("approval.resolved",v),u("approval.resolved",v)}catch(X){let v=X instanceof Error?X.message:String(X);this.nsp.to(`session:${t}`).emit("approval.resolved",{event:"approval.resolved",session_id:t,approval_id:V,choice:N,resolved:!1,error:v}),i({ok:!1,event:"run.failed",output:d,reasoning:r,error:v})}},u=(W,N={})=>{typeof N.run_id=="string"&&N.run_id&&(o=N.run_id),W==="message.delta"&&typeof N.delta=="string"&&(d+=N.delta),(W==="reasoning.delta"||W==="thinking.delta")&&typeof N.delta=="string"&&(r+=N.delta);try{l.onEvent?.(W,N)}catch(V){h.warn(V,"[chat-run-socket] runAndWait event observer failed for session %s",t)}W==="approval.requested"?Z(N):W==="run.completed"?i({ok:!0,event:"run.completed",run_id:N.run_id,output:typeof N.output=="string"&&N.output?N.output:d,reasoning:typeof N.reasoning=="string"&&N.reasoning?N.reasoning:r}):W==="run.failed"&&i({ok:!1,event:"run.failed",run_id:N.run_id,output:d,reasoning:r,error:N.error?String(N.error):"chat-run failed"})},p=b?setTimeout(()=>{let W=`chat-run timed out after ${b}ms`;i({ok:!1,event:"run.failed",error:W}),this.abortSession(t,W).catch(N=>{h.warn(N,"[chat-run-socket] failed to abort timed-out session %s",t)})},b):null;m.add(u),this.runWaiters.set(t,m);let Y={id:`workflow-run-${t}`,connected:!0,data:{user:l.user},join:()=>{},to:W=>({emit:(N,V)=>{this.nsp.to(W).emit(N,V),u(N,V)}}),emit:(W,N)=>u(W,N)};this.handleRun(Y,{...e,onEvent:u},n).catch(W=>{let N=W instanceof Error?W.message:String(W),V={event:"run.failed",session_id:t,error:N};Yc({event:"run.failed",sessionId:t,profile:n,source:c,agent:Hb(e),payload:V,roomId:e.group_room_id,workflowId:e.workflow_id,workflowNodeId:e.workflow_node_id}),i({ok:!1,event:"run.failed",error:N})})})}async abortSession(e,l="Run canceled"){let t=String(e||"").trim();if(!t)return;let n={id:`workflow-abort-${t}`,connected:!1,data:{},emit:()=>{},join:()=>{},to:c=>({emit:(G,a)=>this.nsp.to(c).emit(G,a)})};await d0(this.nsp,n,t,this.sessionMap,this.bridge,this.runQueuedItem.bind(this)),this.emitExternalEvent(t,"run.failed",{event:"run.failed",error:l})}async disposeSession(e){let l=String(e||"").trim();if(!l)return;Ae.stop(l,{reportClosed:!1}),this.sessionMap.get(l)?.abortController?.abort(),this.sessionMap.delete(l),this.runWaiters.delete(l),vr(l)}emitExternalEvent(e,l,t){let n={...t,session_id:e},c=this.resolvePetEventProfile(e,n),G=this.sessionMap.get(e),a=ZI(e),s=String(a?.agent||"");Yc({event:l,sessionId:e,profile:c,source:G?.source||a?.source||"coding_agent",agent:G?.webhookAgent||(s==="codex"?"codex":s==="ekko-agent"?"ekko":"claude-code"),payload:n,roomId:G?.webhookRoomId,workflowId:G?.webhookWorkflowId,workflowNodeId:G?.webhookWorkflowNodeId}),this.observePetEvent(c,l,n),G?.isWorking&&(G.events.push({event:l,data:n}),G.events.length>200&&G.events.splice(0,G.events.length-200)),this.nsp.to(`session:${e}`).emit(l,n);let d=this.runWaiters.get(e);if(d)for(let r of d)r(l,n)}markExternalRunCompleted(e,l){let t=this.sessionMap.get(e);if(t&&(t.isWorking=!1,t.abortController=void 0,t.runId=void 0,t.activeRunMarker=void 0,t.events=[],t.responseRun=void 0,t.profile=void 0,h.info("[chat-run-socket] external run completed for session %s (%s)",e,l),t.queue.length>0)){let n=this.socketForQueuedRun(e,t.queue[0]);n&&this.dequeueNextQueuedRun(n,e)}}clearSessionHistory(e){let l=$b(e),t=this.sessionMap.get(e),n=!!t,c=t?.messagePageLimit;if(t){if(t.abortController?.abort(),t.isWorking&&Rj(t.source)){let G=t.profile;this.bridge.interrupt(e,"Session cleared",G).catch(a=>h.warn(a,"[chat-run-socket] failed to interrupt bridge run while clearing session %s",e))}t.messages=[],t.messageTotal=0,t.messageLoadedCount=0,t.hasMoreBefore=!1,t.inputTokens=0,t.outputTokens=0,t.contextTokens=0,t.events=[],t.queue=[],t.bridgePendingAssistantContent=void 0,t.bridgePendingReasoningContent=void 0,t.bridgePendingToolCallMarkup=void 0,t.bridgeOutput=void 0,t.bridgePendingTools=void 0,t.bridgeCompressionResults=void 0,t.responseRun=void 0,t.activeRunMarker=void 0,t.runId=void 0,t.abortController=void 0,t.isAborting=!1,t.isWorking=!1,t.profile=void 0,this.sessionMap.delete(e)}return this.nsp.emit("session.command",{event:"session.command",session_id:e,command:"clear",ok:!0,action:"clear",clearHistory:!0,source:"mcu",deleted:l,memory_cleared:n}),this.nsp.emit("resumed",{session_id:e,messages:[],messageTotal:0,messageLoadedCount:0,messagePageLimit:c,hasMoreBefore:!1,isWorking:!1,isAborting:!1,events:[],inputTokens:0,outputTokens:0,contextTokens:0,queueLength:0,queueMessages:[]}),this.nsp.emit("run.queued",{event:"run.queued",session_id:e,queue_length:0,queued_messages:[]}),h.info({sessionId:e,deleted:l,hadMemoryState:n},"[chat-run-socket] cleared session history and memory state"),{deleted:l,hadMemoryState:n}}socketForQueuedRun(e,l){if(l?.originSocketId){let n=this.nsp.sockets.get(l.originSocketId);if(n)return n}let t=this.nsp.adapter.rooms.get(`session:${e}`);if(t)for(let n of t){let c=this.nsp.sockets.get(n);if(c)return c}return this.nsp.sockets.values().next().value||null}clearClarifyEventState(e,l){let t=this.sessionMap.get(e);if(!t?.events.length)return;let n=t.events.filter(({event:c,data:G})=>c!=="clarify.requested"&&c!=="clarify.resolved"?!0:G?.clarify_id!==l);n.length!==t.events.length&&(t.events=n)}emitToSession(e,l,t,n){let c={...n,session_id:l},G=this.resolvePetEventProfile(l,c),a=this.sessionMap.get(l),s=ZI(l),d=String(s?.agent||"");Yc({event:t,sessionId:l,profile:G,source:a?.source||s?.source||"chat",agent:a?.webhookAgent||(d==="codex"?"codex":d==="ekko-agent"?"ekko":"bridge"),payload:c,roomId:a?.webhookRoomId,workflowId:a?.webhookWorkflowId,workflowNodeId:a?.webhookWorkflowNodeId}),this.observePetEvent(G,t,c),this.emitPendingInteraction(G,t,c),this.nsp.to(`session:${l}`).emit(t,c),!this.nsp.adapter.rooms.get(`session:${l}`)?.size&&e.connected&&e.emit(t,c)}emitPendingInteraction(e,l,t){if(l!=="approval.requested"&&l!=="approval.resolved"&&l!=="clarify.requested"&&l!=="clarify.resolved")return;let n=typeof t?.session_id=="string"?t.session_id:"";(n?this.sessionMap.get(n)?.source||ZI(n)?.source:void 0)!=="group_chat"&&this.nsp.to(`pending-interactions:${e}`).emit(l,t)}serializeQueuedMessages(e){return e.filter(l=>l.displayInput!==null).map(l=>({id:l.queue_id,role:l.displayRole||(typeof l.displayInput=="string"&&l.displayInput.trim().startsWith("/")?"command":"user"),content:Ft(l.displayInput??l.input),timestamp:Math.floor(Date.now()/1e3),queued:!0}))}canAccessProfile(e,l){return e.role==="super_admin"||aG(e.id,l)}async close(){if(this.closing)return;this.closing=!0,this.backgroundPollTimer&&(clearInterval(this.backgroundPollTimer),this.backgroundPollTimer=void 0);let e=[];for(let[t,n]of this.sessionMap.entries()){if(n.abortController)try{n.abortController.abort()}catch(c){h.warn(c,"[chat-run-socket] failed to abort controller for session %s",t)}for(let c of n.queue)!c.backgroundDelegationId||!c.backgroundClaimId||e.push(this.backgroundBridge.releaseBackgroundNotification(t,c.profile,c.backgroundDelegationId,c.backgroundClaimId))}this.sessionMap.clear();let l=await Promise.allSettled(e);for(let t of l)t.status==="rejected"&&h.warn(t.reason,"[chat-run-socket] failed to release queued background notification on close");await Promise.allSettled([this.bridge.close(),this.backgroundBridge.close()]),h.info("[chat-run-socket] closed all connections and cleared state")}resolvePetEventProfile(e,l){let t=typeof l.profile=="string"?l.profile.trim():"";if(t)return t;let n=this.sessionMap.get(e)?.profile;return n||ZI(e)?.profile||"default"}observePetEvent(e,l,t){try{hN(e,l,t)}catch(n){h.debug(n,"[chat-run-socket] failed to update pet state")}}};xa();var Ss=require("node:fs"),FCI=require("node:os"),Gt=require("node:path");AI();Me();dI();fl();wI();var kHe="hermes-studio",r0=[{name:"hermes-studio-api",toolset:"api"},{name:"hermes-studio-browser",toolset:"browser"},{name:"hermes-studio-devices",toolset:"devices"},{name:"hermes-studio-use",toolset:"use"}],LHe=new Set(r0.map(I=>I.name)),fHe=1860,xHe=new Set([kHe,"hermes-web-ui-mcp","hermes-studio-mcp"]),X1="HERMES_WEB_UI_MANAGED_MCP",zHe=new Set(["hermes-lan-peer-mcp","hermes-devices-mcp","hermes-web-ui-mcp","hermes-studio-mcp"]);function XCI(I){return["1","true","yes","on"].includes(String(I||"").trim().toLowerCase())}function UHe(){return XCI(process.env.HERMES_WEB_UI_DISABLE_MCP_AUTOINJECT)}function OHe(){return XCI(process.env.HERMES_WEB_UI_ALLOW_TRANSIENT_MCP_AUTOINJECT)}function dZ(I){try{return(0,Ss.realpathSync)(I)}catch{return(0,Gt.resolve)(I)}}function RCI(I){let e=dZ(I);return[(0,FCI.tmpdir)(),"/tmp","/private/tmp"].filter(Boolean).some(l=>ce(e,dZ(l)))}function BHe(I){try{let e=(0,Ss.readFileSync)(I,"utf8").split(/\r?\n/,1)[0]?.trim()||"",l=/^gitdir:\s*(.+)$/i.exec(e);if(!l)return!1;let t=dZ((0,Gt.resolve)((0,Gt.dirname)(I),l[1].trim())),n=(0,Ss.readFileSync)((0,Gt.join)(t,"commondir"),"utf8").trim();if(!n)return!1;let c=dZ((0,Gt.resolve)(t,n));return dZ((0,Gt.dirname)(t))===dZ((0,Gt.join)(c,"worktrees"))}catch{return!1}}function MHe(I){let e=(0,Gt.dirname)(dZ(I));for(;;){let l=(0,Gt.join)(e,".git");if((0,Ss.existsSync)(l))try{let n=(0,Ss.statSync)(l);if(n.isFile())return BHe(l);if(n.isDirectory())return!1}catch{return!1}let t=(0,Gt.dirname)(e);if(t===e)return!1;e=t}}function SHe(I){return OHe()?!1:RCI(B.appHome)||I!==null&&(RCI(I)||MHe(I))}function jHe(){return String(process.env.HERMES_DESKTOP||"").trim().toLowerCase()==="true"}function gCI(){return[process.env.HERMES_WEB_UI_MCP_BIN,(0,Gt.join)(process.cwd(),"bin/hermes-studio-mcp.mjs"),(0,Gt.join)(__dirname,"../../bin/hermes-studio-mcp.mjs"),(0,Gt.join)(__dirname,"../../../../../bin/hermes-studio-mcp.mjs"),(0,Gt.join)(process.cwd(),"bin/hermes-web-ui-mcp.mjs"),(0,Gt.join)(__dirname,"../../bin/hermes-web-ui-mcp.mjs"),(0,Gt.join)(__dirname,"../../../../../bin/hermes-web-ui-mcp.mjs")].filter(I=>!!I)}function THe(){return gCI().find(I=>(0,Ss.existsSync)(I))||null}function KHe(){return process.env.HERMES_AGENT_NODE?.trim()||null}function DHe(I,e){return e?{command:KHe()||process.execPath,args:[e,I]}:jHe()?{command:"hermes-studio-mcp",args:[I]}:(h.warn({candidates:gCI()},"[mcp-autoinject] bundled MCP script not found; falling back to PATH command"),{command:"hermes-studio-mcp",args:[I]})}function HCI(I,e,l,t){let n={HERMES_WEB_UI_URL:`http://127.0.0.1:${B.port}`,HERMES_WEB_UI_HOME:B.appHome,HERMES_WEBUI_STATE_DIR:B.appHome,HERMES_WEB_UI_PROFILE:I,HERMES_MCP_SERVER_NAME:e,HERMES_MCP_TOOLSET:l,[X1]:"1"};return{...DHe(l,t),...l==="use"?{timeout:fHe}:{},env:n,enabled:!0}}function FN(I){return!!I&&typeof I=="object"&&!Array.isArray(I)}function gj(I){return FN(I)?FN(I.env)&&I.env[X1]==="1"?!0:typeof I.command=="string"&&zHe.has(I.command):!1}function _He(I,e){let l=Array.isArray(e.args)?e.args:void 0,t=Array.isArray(I.args)?I.args:void 0;return!l&&!t?!0:!l||!t?!1:l.length===t.length&&l.every((n,c)=>t[c]===n)}function qHe(I,e){let l=e.env;return I.command===e.command&&_He(I,e)&&(e.timeout===void 0||I.timeout===e.timeout)&&I.enabled!==!1&&FN(I.env)&&I.env.HERMES_WEB_UI_URL===l.HERMES_WEB_UI_URL&&I.env.HERMES_WEB_UI_HOME===l.HERMES_WEB_UI_HOME&&I.env.HERMES_WEBUI_STATE_DIR===l.HERMES_WEBUI_STATE_DIR&&I.env.HERMES_WEB_UI_PROFILE===l.HERMES_WEB_UI_PROFILE&&I.env.HERMES_MCP_SERVER_NAME===l.HERMES_MCP_SERVER_NAME&&I.env.HERMES_MCP_TOOLSET===l.HERMES_MCP_TOOLSET&&I.env.HERMES_WEB_UI_TOKEN===void 0&&I.env[X1]===l[X1]}async function PHe(I,e){return await zl(I,l=>{let t=FN(l)?l:{};FN(t.mcp_servers)||(t.mcp_servers={});let n=!1,c=!1,G=!1;for(let[a,s]of Object.entries(t.mcp_servers))if(!LHe.has(a)){if(xHe.has(a)&&!gj(s))return{data:t,write:!1,result:{profile:I,status:"skipped",reason:`existing ${a} MCP server is not managed by Hermes Web UI`}};gj(s)&&(delete t.mcp_servers[a],n=!0,G=!0)}for(let a of r0){let s=HCI(I,a.name,a.toolset,e),d=t.mcp_servers[a.name];if(!d){t.mcp_servers[a.name]=s,n=!0,c=!0;continue}if(G=!0,!gj(d))return{data:t,write:!1,result:{profile:I,status:"skipped",reason:`existing ${a.name} MCP server is not managed by Hermes Web UI`}};if(FN(d)&&d.enabled===!1)return{data:t,write:!1,result:{profile:I,status:"skipped",reason:`existing ${a.name} MCP server is disabled by user`}};qHe(d,s)||(t.mcp_servers[a.name]=s.timeout===void 0&&Object.hasOwn(d,"timeout")?{...s,timeout:d.timeout}:s,n=!0)}return n?{data:t,result:{profile:I,status:c&&!G?"injected":"updated"}}:{data:t,write:!1,result:{profile:I,status:"unchanged"}}})}async function wCI(){let I=THe(),e=HCI("default",r0[0].name,r0[0].toolset,I),l={serverNames:r0.map(c=>c.name),command:String(e.command),targets:[]};if(UHe())return h.info("[mcp-autoinject] disabled by HERMES_WEB_UI_DISABLE_MCP_AUTOINJECT"),l;if(SHe(I))return h.info({appHome:B.appHome,bundledScript:I},"[mcp-autoinject] skipped for transient Web UI home or MCP launcher"),l;for(let c of MI())l.targets.push(await PHe(c,I));let t=l.targets.filter(c=>c.status==="injected"||c.status==="updated");t.length>0&&h.info({serverNames:l.serverNames,command:e.command,targets:t},"[mcp-autoinject] synced bundled MCP server");let n=l.targets.filter(c=>c.status==="skipped");return n.length>0&&h.warn({serverNames:l.serverNames,targets:n},"[mcp-autoinject] skipped unmanaged MCP server entries"),l}hW();$y();di();un();v2();dI();tN();var $He="/workflow";function QCI(I){return(typeof I=="string"?I.trim():"")||null}function vCI(I){return!I||I.role==="super_admin"?null:new Set(tt(I.id).map(e=>e.profile_name))}function Hj(I,e){let l=vCI(I);return!l||l.has(e||"default")}function yCI(I,e){let l=vCI(I);return l?e.filter(t=>l.has(t.profile||"default")):e}function pr(I,e){typeof I=="function"&&I(e)}var g1=class{nsp;manager;removeStatusListener;constructor(e,l=be()){this.manager=l,this.nsp=e.of($He),this.removeStatusListener=this.manager.onRuntimeStatus(t=>this.emitRuntimeStatus(t))}init(){this.nsp.use(this.authMiddleware.bind(this)),this.nsp.on("connection",this.onConnection.bind(this)),h.info("[workflow-socket] Socket.IO ready at /workflow")}close(){this.removeStatusListener()}async authMiddleware(e,l){if(!await sG()){l();return}let t=e.handshake.auth?.token,n=await _n(t||"");if(!n){l(new Error("Authentication failed"));return}let c=QCI(e.handshake.query?.profile);if(c&&!Hj(n,c)){l(new Error("Profile access denied"));return}e.data.user=n,l()}onConnection(e){e.on("workflows.list",(l,t)=>{let n=typeof l=="function"?l:t,c=typeof l=="function"?{}:l||{};this.handleList(e,c,n)}),e.on("workflow.status.subscribe",(l,t)=>{let n=typeof l=="function"?l:t,c=typeof l=="function"?{}:l||{};this.handleStatusSubscribe(e,c,n)}),e.on("workflow.status.unsubscribe",(l,t)=>{this.handleStatusUnsubscribe(e,l||{},t)})}handleList(e,l,t){let n=e.data.user,c=QCI(l.profile);if(c&&!Hj(n,c)){pr(t,{ok:!1,error:`Profile "${c}" is not available for this user`});return}let G=yCI(n,this.manager.list(c));pr(t,{ok:!0,data:{workflows:G}})}handleStatusSubscribe(e,l,t){let n=typeof l.workflowId=="string"?l.workflowId.trim():"";if(n){let s=this.manager.get(n),d=e.data.user;if(!s){pr(t,{ok:!1,error:"workflow not found"});return}if(!Hj(d,s.profile)){pr(t,{ok:!1,error:`Profile "${s.profile}" is not available for this user`});return}try{let r=this.statusWithEvidence(this.manager.getRuntimeStatus(n));e.join(this.workflowRoom(n)),pr(t,{ok:!0,data:{statuses:[r]}})}catch(r){h.error(r,"[workflow-socket] failed to load persisted execution evidence for workflow %s",n),pr(t,{ok:!1,error:r?.message||"workflow evidence read failed"})}return}let c=e.data.user,G=yCI(c,this.manager.list()),a=new Set(G.map(s=>s.id));for(let s of a)e.join(this.workflowRoom(s));try{let s=this.manager.listRuntimeStatuses().filter(d=>a.has(d.workflowId)).map(d=>this.statusWithEvidence(d));pr(t,{ok:!0,data:{statuses:s}})}catch(s){h.error(s,"[workflow-socket] failed to load persisted execution evidence for workflow status subscription"),pr(t,{ok:!1,error:s?.message||"workflow evidence read failed"})}}handleStatusUnsubscribe(e,l,t){let n=typeof l.workflowId=="string"?l.workflowId.trim():"";if(n)e.leave(this.workflowRoom(n));else for(let c of e.rooms)c.startsWith("workflow:")&&c.endsWith(":status")&&e.leave(c);pr(t,{ok:!0,data:{ok:!0}})}statusWithEvidence(e){if(!e.runId)return{...e,run:null};let l=qp(e.runId);if(!l)throw new Error(`workflow run ${e.runId} is unavailable while loading persisted evidence`);return{...e,run:l}}emitRuntimeStatus(e){try{this.nsp.to(this.workflowRoom(e.workflowId)).emit("workflow.status.updated",this.statusWithEvidence(e))}catch(l){h.error(l,"[workflow-socket] failed to load persisted execution evidence for workflow %s",e.workflowId),this.nsp.to(this.workflowRoom(e.workflowId)).emit("workflow.status.error",{workflowId:e.workflowId,runId:e.runId,error:l?.message||"workflow evidence read failed"})}}workflowRoom(e){return`workflow:${e}:status`}};dI();var Ac=require("zlib"),Iwe=1024,CCI=256*1024,ewe=new Set(["application/ecmascript","application/javascript","application/json","application/ld+json","application/manifest+json","application/rss+xml","application/wasm","application/xhtml+xml","application/xml","application/x-javascript","image/svg+xml","text/javascript"]);function lwe(I){let e=I.split(";",1)[0]?.trim().toLowerCase()||"";return e?e.startsWith("text/")||ewe.has(e)||e.endsWith("+json")||e.endsWith("+xml"):!1}function ECI(I,e){let l=null,t=null;for(let n of I.split(",")){let[c,...G]=n.split(";"),a=c?.trim().toLowerCase();if(!a)continue;let s=1;for(let d of G){let[r,o]=d.split("=");if(r?.trim().toLowerCase()!=="q")continue;let b=Number(o?.trim());s=Number.isFinite(b)?Math.max(0,Math.min(b,1)):0}a===e&&(t=s),a==="*"&&(l=s)}return t??l??0}function twe(I,e={}){let l=ECI(I,"br"),t=ECI(I,"gzip"),n=e.bodyLength??null,c=e.maxBrotliBytes??CCI;return l<=0&&t<=0?null:l>=t?n!==null&&n>c?t>0?"gzip":null:"br":"gzip"}function JCI(I){return!!I&&typeof I.pipe=="function"}function ACI(I,e){if(Buffer.isBuffer(e))return e.byteLength;if(typeof e=="string")return Buffer.byteLength(e);let l=Number(I.response.get("Content-Length"));return Number.isFinite(l)&&l>=0?l:null}function nwe(I,e){if(I.method==="HEAD"||I.status<200||I.status>=300||I.status===204||I.get("Range")||I.response.get("Content-Encoding")||!lwe(I.response.get("Content-Type")||I.type||""))return!1;let l=I.body;if(!l||!(Buffer.isBuffer(l)||typeof l=="string"||JCI(l)))return!1;let t=ACI(I,l);return t===null||t>=e}function cwe(I,e){return e==="br"?(0,Ac.brotliCompressSync)(I,{params:{[Ac.constants.BROTLI_PARAM_QUALITY]:Ac.constants.BROTLI_DEFAULT_QUALITY}}):(0,Ac.gzipSync)(I)}function Gwe(I){return I==="br"?(0,Ac.createBrotliCompress)({params:{[Ac.constants.BROTLI_PARAM_QUALITY]:Ac.constants.BROTLI_DEFAULT_QUALITY}}):(0,Ac.createGzip)()}function kCI(I={}){let e=I.minBytes??Iwe,l=I.maxBrotliBytes??CCI;return async(t,n)=>{if(await n(),!nwe(t,e))return;let c=t.body,G=ACI(t,c);t.vary("Accept-Encoding");let a=twe(t.get("Accept-Encoding"),{bodyLength:G,maxBrotliBytes:l});if(a){if(t.set("Content-Encoding",a),Buffer.isBuffer(c)||typeof c=="string"){let s=Buffer.isBuffer(c)?c:Buffer.from(c),d=cwe(s,a);if(d.byteLength>=s.byteLength){t.remove("Content-Encoding");return}t.body=d,t.set("Content-Length",String(d.byteLength));return}JCI(c)&&(t.remove("Content-Length"),t.body=c.pipe(Gwe(a)))}}}var awe="public, max-age=31536000, immutable",wj="no-cache";function LCI(I){let e=I.replaceAll("\\","/").replace(/^\.\//,"");return e==="index.html"?wj:e.startsWith("assets/")?awe:null}var cAI=T(Q5I(),1),GAI=T(nAI(),1),aAI=T(MN(),1),dC=["json","form","text","xml"],sAI=class extends Error{constructor(I){super(),this.name="UnsupportedBodyTypeError",this.message=`Invalid enabled type '${I}'. make sure to pass an array contains supported types ([${dC}]).`}};function REe(I){for(let l of I)if(!dC.includes(l))throw new sAI(l);return dC.reduce((l,t)=>({...l,[t]:I.includes(t)}),{})}function FEe(I){for(let t of Object.keys(I)){let n=I[t];if(!dC.includes(t)||!Array.isArray(n))throw new sAI(t)}return(0,GAI.default)({json:["application/json","application/json-patch+json","application/vnd.api+json","application/csp-report","application/reports+json","application/scim+json"],form:["application/x-www-form-urlencoded"],text:["text/plain"],xml:["text/xml","application/xml"]},I)}function XEe(I,e){return typeof I=="string"&&(I=I.replace(/;$/,"")),aAI.default.is(I,e)}function dAI(I={}){let{patchNode:e=!1,parsedMethods:l=["POST","PUT","PATCH"],detectJSON:t,onError:n,enableTypes:c=["json","form"],extendTypes:G={},enableRawChecking:a=!1,...s}=I,d=REe(c),r=FEe(G);async function o(b){let m=u=>!!(d[u]&&XEe(b.request.get("content-type"),r[u])),i=t?.(b)||m("json")?"json":m("form")?"form":m("text")||m("xml")?"text":null;if(!i)return{};let Z={returnRawBody:!0,strict:i==="json"?s.jsonStrict:void 0,[`${i}Types`]:r[i],limit:s[`${m("xml")?"xml":i}Limit`],encoding:s.encoding||"utf-8"};return cAI.default[i](b,Z)}return async function(m,i){if(!l.includes(m.method.toUpperCase())||e&&m.req.body!==void 0||m.request.body!==void 0||m.disableBodyParser)return i();if(a&&m.req.body!==void 0)return m.request.body=m.req.body,i();if(m.req.closed){m.status=499,m.body="Request already closed";return}try{let Z=await o(m);e&&(m.req.body="parsed"in Z?Z.parsed:{},m.req.rawBody===void 0&&(m.req.rawBody=Z.raw)),m.request.body="parsed"in Z?Z.parsed:{},m.request.rawBody===void 0&&(m.request.rawBody=Z.raw)}catch(Z){if(!n)throw Z;n(Z,m)}return i()}}function rAI(){return dAI({encoding:"utf-8",enableTypes:["json","form","text"],jsonLimit:"20mb",formLimit:"20mb",textLimit:"20mb",parsedMethods:["POST","PUT","PATCH","DELETE"]})}var HEe="0.6.41";process.on("uncaughtException",I=>{console.error("FATAL: Uncaught exception"),console.error(I),h.fatal(I,"Uncaught exception"),process.exit(1)});process.on("unhandledRejection",I=>{console.error("Unhandled rejection"),console.error(I),h.error(I,"Unhandled rejection")});var iAI=null,Eb=[],Q0=null,mAI=null,ZAI=null,wEe=null,rC=null,zT=null;function QEe(I,e,l){return new Promise((t,n)=>{let c=I.listen(e,l);c.once("listening",()=>t(c)),c.once("error",n)})}async function yEe(I,e,l){let t=l||"0.0.0.0";console.log(`[bootstrap] listening on ${t}:${e}`);let n=await QEe(I,e,t);return{primary:n,servers:[n]}}function vEe(I){let e=I?.address?.();return`http://127.0.0.1:${typeof e=="object"&&e?.port?e.port:B.port}`}function EEe(){try{return NAI.default.networkInterfaces()}catch{return{}}}function UT(){return String(process.env.HERMES_DESKTOP||"").trim().toLowerCase()==="true"}function CEe(I){return I?I==="127.0.0.1"||I==="::1"||I==="::ffff:127.0.0.1"||I.startsWith("::ffff:127."):!1}function JEe(I){return I.get("authorization").match(/^Bearer\s+(.+)$/i)?.[1]?.trim()||""}function AEe(I){I.use(async(e,l)=>{if(e.method!=="POST"||e.path!=="/api/desktop/shutdown"){await l();return}if(!UT()){e.status=404,e.body={error:"not_found"};return}let t=e.req.socket.remoteAddress;if(!CEe(t)){e.status=403,e.body={error:"forbidden"};return}let n=String(process.env.AUTH_TOKEN||"").trim();if(!n||JEe(e)!==n){e.status=401,e.body={error:"unauthorized"};return}if(!zT){e.status=503,e.body={error:"shutdown_not_ready"};return}e.status=202,e.body={ok:!0},setTimeout(()=>{zT?.("desktop-api")},50).unref?.()})}function hAI(I){let e=String(process.env[I]||"").trim().toLowerCase();return["1","true","yes","on"].includes(e)}function YAI(){return hAI("HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART")}function kEe(){return hAI("HERMES_WEB_UI_DISABLE_SKILL_INJECTION")}async function LEe(){YAI()?console.log("[bootstrap] profile gateway check disabled by HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART"):Wx().then(()=>console.log("[bootstrap] profile gateways checked")).catch(I=>{h.warn(I,"[bootstrap] failed to ensure profile gateways"),console.warn("[bootstrap] failed to ensure profile gateways:",I instanceof Error?I.message:I)});try{rC=await xA(),console.log("[bootstrap] agent bridge started")}catch(I){h.warn(I,"[bootstrap] agent bridge failed to start"),console.warn("[bootstrap] agent bridge failed to start:",I instanceof Error?I.message:I)}}function fEe(){YAI()?console.log("[bootstrap] profile gateway check disabled by HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART"):(async()=>{try{await Wx(),console.log("[bootstrap] profile gateways checked")}catch(I){h.warn(I,"[bootstrap] failed to ensure profile gateways"),console.warn("[bootstrap] failed to ensure profile gateways:",I instanceof Error?I.message:I)}})(),(async()=>{try{rC=await xA(),console.log("[bootstrap] agent bridge started")}catch(I){h.warn(I,"[bootstrap] agent bridge failed to start"),console.warn("[bootstrap] agent bridge failed to start:",I instanceof Error?I.message:I);return}})()}function xEe(){let I=tmI({httpPort:B.port}),e=!1,l=()=>{e||(e=!0,Mw().catch(t=>h.warn(t,"[lan-discovery] initial scan failed")))};I?(I.once("listening",l),setTimeout(l,500).unref?.()):l()}async function VAI(){if(console.log(`hermes-web-ui v${HEe} starting...`),await(0,xT.mkdir)(B.uploadDir,{recursive:!0}),U6()&&await(0,xT.mkdir)(B.dataDir,{recursive:!0}),await s8(),kEe())console.log("[bootstrap] bundled skill injection disabled by HERMES_WEB_UI_DISABLE_SKILL_INJECTION");else try{let Z=await new vm().injectMissingSkills();Z.injected.length>0&&h.info({injected:[...new Set(Z.injected)],targetCount:Z.targets.length},"[bootstrap] bundled skills injected"),Z.updated.length>0&&h.info({updated:[...new Set(Z.updated)],targetCount:Z.targets.length},"[bootstrap] bundled skills updated")}catch(i){h.warn(i,"[bootstrap] failed to inject bundled skills"),console.warn("[bootstrap] failed to inject bundled skills:",i instanceof Error?i.message:i)}try{await wCI()}catch(i){h.warn(i,"[bootstrap] failed to inject bundled MCP server"),console.warn("[bootstrap] failed to inject bundled MCP server:",i instanceof Error?i.message:i)}HL(),console.log("[bootstrap] ekko-agent setup complete"),UT()||await LEe();let I=new LP,{initAllStores:e}=await Promise.resolve().then(()=>(bAI(),oAI));e(),NbI(),console.log("[bootstrap] all stores initialized"),I.use(liI()),I.use((0,uAI.default)({origin:IiI(B.corsOrigins)})),I.use(rAI()),console.log("[bootstrap] cors + bodyParser registered"),AEe(I),C1I(I,[PbI,$bI]),console.log("[bootstrap] routes registered");let l=(0,oC.resolve)(__dirname,"..","client");I.use(kCI()),I.use((0,WAI.default)(l,{setHeaders(i,Z){let u=LCI((0,oC.relative)(l,Z));u&&i.setHeader("Cache-Control",u)}})),I.use(async i=>{(i.method==="GET"||i.method==="HEAD")&&!i.path.startsWith("/api")&&i.path!=="/health"&&i.path!=="/upload"&&(i.set("Cache-Control",wj),await(0,pAI.default)(i,"index.html",{root:l}))}),console.log("[bootstrap] SPA fallback registered");let t=await yEe(I,B.port,B.host);iAI=t.primary,Eb=t.servers,console.log("[bootstrap] app.listen called"),ciI(Eb),wiI(Eb),Fc().setupServer(Eb),console.log("[bootstrap] terminal + kanban + LAN peer websocket setup");let n=new dy(Eb);VhI(n),wEe=new Wy(n.getIO(),n),Q0=new F1(n.getIO()),Cf(Q0),n.setChatRunService(Q0),Q0.init(),Vs(()=>n.getChatRunService()).restore();let{getWorkflowManager:c}=await Promise.resolve().then(()=>(tN(),qHI)),G=await c().recoverActiveRuns();G.runs>0&&h.warn("Recovered %d orphaned workflow runs and aborted %d sessions",G.runs,G.sessions);let{getWorkflowScheduleService:a}=await Promise.resolve().then(()=>($M(),hwI));a().start(),mAI=new g1(n.getIO()),mAI.init(),ZAI=new h1(n.getIO()),ZAI.init();let s=vEe(iAI);XZI(n.getIO(),{localBaseUrl:s}),console.log("[bootstrap] global agent server ready");let{SessionDeleter:d}=await Promise.resolve().then(()=>(TQ(),EpI)),r=d.getInstance(),o=process.env.PROFILE||"default";r.start(o),console.log("[bootstrap] session deleter started, profile=%s",o),Eb.forEach(i=>{i.on("upgrade",(Z,u)=>{let p=new URL(Z.url||"",`http://${Z.headers.host}`);p.pathname!=="/api/hermes/terminal"&&p.pathname!=="/api/hermes/kanban/events"&&p.pathname!==fmI()&&!p.pathname.startsWith("/socket.io/")&&u.destroy()})});let b=EEe(),m=Object.values(b).flat().find(i=>i?.family==="IPv4"&&!i?.internal)?.address||"localhost";console.log(`Server: http://localhost:${B.port} (LAN: http://${m}:${B.port})`),console.log(`Log: ${B.appHome}/logs/server.log`),h.info("Server: http://localhost:%d (LAN: http://%s:%d)",B.port,m,B.port),xEe(),QRI("bootstrap"),UT()&&(rC=An(),fEe()),n.restoreWhenReady(),Eb.forEach(i=>{i.on("error",Z=>{console.error("[bootstrap] server error:",Z.code||Z.message),h.error({err:Z},"Server error")})}),zT=FbI(Eb,n,Q0,rC),c9()}VAI().catch(I=>{console.error("FATAL: Failed to start Hermes Web UI"),console.error(I),h.fatal(I,"Fatal error during bootstrap"),process.exit(1)});0&&(module.exports={bootstrap});
|
|
2652
2652
|
/*! Bundled license information:
|
|
2653
2653
|
|
|
2654
2654
|
ee-first/index.js:
|