@quanthermes/hermes-web-ui 0.6.18 → 0.6.19
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/{ChannelsView-DNfeMm-1.js → ChannelsView-BhvSQz3q.js} +1 -1
- package/dist/client/assets/js/{ChatView-CJ5xzaMG.js → ChatView-BBWSbOTc.js} +1 -1
- package/dist/client/assets/js/{CodingAgentsView-Dvtip0gX.js → CodingAgentsView-TsPWnQ-e.js} +1 -1
- package/dist/client/assets/js/{DevicesView-_WSWarB0.js → DevicesView-gWT295OX.js} +1 -1
- package/dist/client/assets/js/{FileRenameModal-yIh1kICM.js → FileRenameModal-CEFCYODC.js} +1 -1
- package/dist/client/assets/js/{FilesView-COieCqv9.js → FilesView-ClheDLjZ.js} +1 -1
- package/dist/client/assets/js/{GroupChatView-CMMdH9qi.js → GroupChatView-DN8mpn70.js} +1 -1
- package/dist/client/assets/js/{HistoryMessageList-63JhmxYI.js → HistoryMessageList-B2QMRyzN.js} +1 -1
- package/dist/client/assets/js/{HistoryView-CIZhEOTj.js → HistoryView-DYCFFpGg.js} +1 -1
- package/dist/client/assets/js/{JobsView-lL7xjV0S.js → JobsView-B-iy-ie4.js} +1 -1
- package/dist/client/assets/js/{KanbanView-qn0UtlHi.js → KanbanView-C0rUTSNF.js} +1 -1
- package/dist/client/assets/js/{LoginView-63v15BI4.js → LoginView-Dc3El_qw.js} +1 -1
- package/dist/client/assets/js/{LogsView-BSvpf5U4.js → LogsView-DwyBT7qp.js} +1 -1
- package/dist/client/assets/js/{MarkdownRenderer-THTJMUql.js → MarkdownRenderer-DZb1wMbL.js} +1 -1
- package/dist/client/assets/js/{McpManagerView-CA1rzPZs.js → McpManagerView-Dr_hv62e.js} +1 -1
- package/dist/client/assets/js/{MemoryView-CnEwNN35.js → MemoryView-CI2_Cy3L.js} +1 -1
- package/dist/client/assets/js/{MessageItem-C09jnu6X.js → MessageItem-CVPb7Btj.js} +1 -1
- package/dist/client/assets/js/{ModelsView-D9xMGX4E.js → ModelsView-CVsIIan4.js} +1 -1
- package/dist/client/assets/js/{OutlinePanel-HsWM7mLO.js → OutlinePanel-C_mZy_cq.js} +1 -1
- package/dist/client/assets/js/{PerformanceView-BTqaCcZT.js → PerformanceView-CVfmqAtJ.js} +1 -1
- package/dist/client/assets/js/{PluginsView-CRYHgkbM.js → PluginsView-DyuTCtts.js} +1 -1
- package/dist/client/assets/js/{ProfilesView-DEI5M20S.js → ProfilesView-B_g8Q3Cy.js} +1 -1
- package/dist/client/assets/js/{SettingRow-BlmnHYa0.js → SettingRow-BMYsP5uq.js} +1 -1
- package/dist/client/assets/js/{SettingsView-CE9zvzef.js → SettingsView-w0qkQi4m.js} +1 -1
- package/dist/client/assets/js/{SkillsUsageView-DurYN8k5.js → SkillsUsageView-KLg_9UJX.js} +1 -1
- package/dist/client/assets/js/{SkillsView-CMkth-Fm.js → SkillsView-O7EXzlgA.js} +1 -1
- package/dist/client/assets/js/{TerminalPanel-CeRILXkF.js → TerminalPanel-DVuhjZrt.js} +1 -1
- package/dist/client/assets/js/{TerminalView-BOCX7lvf.js → TerminalView-DVRlT_-o.js} +1 -1
- package/dist/client/assets/js/{UsageView-BuPt2L6B.js → UsageView-C6M2Id1b.js} +1 -1
- package/dist/client/assets/js/{VersionPreviewView-DQyROuWd.js → VersionPreviewView-wn0OxFjS.js} +1 -1
- package/dist/client/assets/js/{VirtualMessageList-Dty9wvSA.js → VirtualMessageList-ftkWv6i1.js} +1 -1
- package/dist/client/assets/js/{_plugin-vue_export-helper-BYiIU0Pd.js → _plugin-vue_export-helper-BIeGRfrQ.js} +2 -2
- package/dist/client/assets/js/{index-j9YvpyYe.js → index-Bkiif2Pf.js} +1 -1
- package/dist/client/assets/js/{models-ChbKk2Oo.js → models-BxWy-mRj.js} +1 -1
- package/dist/client/assets/js/{session-browser-prefs-BHcPARE8.js → session-browser-prefs-Byq_ViZP.js} +1 -1
- package/dist/client/assets/js/{skills-Fvhr-K4b.js → skills-aFq9azFz.js} +1 -1
- package/dist/client/assets/js/{system-BHEG2KFs.js → system-Bm5rA-WZ.js} +1 -1
- package/dist/client/assets/js/{useSttSettings-Cqov9Pdt.js → useSttSettings-DEm4lbwe.js} +1 -1
- package/dist/client/index.html +3 -3
- package/dist/server/index.js +3 -3
- package/package.json +7 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as y}from"./rolldown-runtime-M0oDzQ_3.js";import{Wn as r,Wt as w,nn as d}from"./ui-vendor-dYn1tJGA.js";import{_ as b,g as C}from"./vue-vendor-DZ4A_GHn.js";import{l as v,u as S}from"./_plugin-vue_export-helper-
|
|
1
|
+
import{n as y}from"./rolldown-runtime-M0oDzQ_3.js";import{Wn as r,Wt as w,nn as d}from"./ui-vendor-dYn1tJGA.js";import{_ as b,g as C}from"./vue-vendor-DZ4A_GHn.js";import{l as v,u as S}from"./_plugin-vue_export-helper-BIeGRfrQ.js";import{a as W,h as A,n as D,p as F,u as g,y as x}from"./system-Bm5rA-WZ.js";import{Q as l,X as K,Y as N,Z as Q}from"./index-Bkiif2Pf.js";var R,E=y((()=>{b(),w(),g(),S(),Q(),N(),R=C("models",()=>{const t=r([]),f=r([]),o=r(""),i=r(""),n=r(!1),u=r(!1),c=d(()=>t.value.filter(e=>e.provider.startsWith("custom:"))),m=d(()=>t.value.filter(e=>!e.provider.startsWith("custom:"))),p=d(()=>t.value.flatMap(e=>e.models.map(a=>({id:a,provider:e.provider,label:e.label,base_url:e.base_url,isDefault:a===o.value&&e.provider===i.value}))));async function s(){if(v()){n.value=!0;try{const e=K().activeProfileName||"default",a=await W(e);t.value=a.groups,f.value=a.allProviders,o.value=a.default,i.value=a.default_provider||""}catch(e){console.error("Failed to fetch providers:",e)}finally{n.value=!1}}}async function _(){if(v()){u.value=!0;try{await F(),await s(),await l().reloadModels()}finally{u.value=!1}}}async function M(e,a){await x({default:e,provider:a}),o.value=e,i.value=a,l().reloadModels()}async function h(e){await D(e),await s(),await l().reloadModels()}async function P(e){await A(e),await s(),await l().reloadModels()}return{providers:t,allProviders:f,defaultModel:o,defaultProvider:i,loading:n,refreshingModelCache:u,customProviders:c,builtinProviders:m,allModels:p,fetchProviders:s,refreshModelCache:_,setDefaultModel:M,addProvider:h,removeProvider:P}})}));export{R as n,E as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as w}from"./rolldown-runtime-M0oDzQ_3.js";import{Mn as I,Wn as l,Wt as E}from"./ui-vendor-dYn1tJGA.js";import{_ as J,g as K}from"./vue-vendor-DZ4A_GHn.js";import{X as p,Y as M}from"./index-
|
|
1
|
+
import{n as w}from"./rolldown-runtime-M0oDzQ_3.js";import{Mn as I,Wn as l,Wt as E}from"./ui-vendor-dYn1tJGA.js";import{_ as J,g as K}from"./vue-vendor-DZ4A_GHn.js";import{X as p,Y as M}from"./index-Bkiif2Pf.js";function v(){try{return p().activeProfileName||"default"}catch{return localStorage.getItem("hermes_active_profile_name")||"default"}}function f(n){return`${g}${n}`}function c(n){return`${h}${n}`}function a(n,e){try{const t=localStorage.getItem(n);return t?JSON.parse(t):e}catch{return e}}function m(n,e){try{localStorage.setItem(n,JSON.stringify(e))}catch{}}function Y(n,e){return n.length===e.length&&n.every((t,u)=>t===e[u])}var g,h,$,W=w((()=>{J(),E(),M(),g="hermes_session_pins_v1_",h="hermes_human_only_v1_",$=K("session-browser-prefs",()=>{const n=l(v()),e=l(a(f(n.value),[])),t=l(a(c(n.value),!0));function u(){n.value=v(),e.value=a(f(n.value),[]),t.value=a(c(n.value),!0)}function s(){m(f(n.value),e.value)}function d(){m(c(n.value),t.value)}function o(r){return e.value.includes(r)}function y(r){o(r)?e.value=e.value.filter(i=>i!==r):e.value=[...e.value,r],s()}function P(r){return o(r)?(e.value=e.value.filter(i=>i!==r),s(),!0):!1}function S(r){t.value!==r&&(t.value=r,d())}function N(r){if(r.length===0)return!1;const i=new Set(r),_=e.value.filter(O=>i.has(O));return Y(_,e.value)?!1:(e.value=_,s(),!0)}return I(()=>p().activeProfileName,()=>u()),{profileName:n,pinnedIds:e,humanOnly:t,reload:u,isPinned:o,togglePinned:y,removePinned:P,setHumanOnly:S,pruneMissingSessions:N}})}));export{$ as n,W as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as p}from"./rolldown-runtime-M0oDzQ_3.js";import{a as y,f as t,o as u,s as d,u as k}from"./_plugin-vue_export-helper-
|
|
1
|
+
import{n as p}from"./rolldown-runtime-M0oDzQ_3.js";import{a as y,f as t,o as u,s as d,u as k}from"./_plugin-vue_export-helper-BIeGRfrQ.js";async function w(){const e=await t("/api/hermes/skills");return{categories:e.categories,archived:e.archived??[],paths:e.paths}}async function P(e=7){return t(`/api/hermes/skills/usage/stats?${new URLSearchParams({days:String(e)})}`)}async function U(e){return(await t(`/api/hermes/skills/${e}`)).content}async function $(e,s){return(await t(`/api/hermes/skills/${e}/${s}/files`)).files}async function b(){return t("/api/hermes/memory")}async function v(e,s){await t("/api/hermes/memory",{method:"POST",body:JSON.stringify({section:e,content:s})})}async function x(e,s){await t("/api/hermes/skills/toggle",{method:"PUT",body:JSON.stringify({name:e,enabled:s})})}async function O(e,s){await t("/api/hermes/skills/pin",{method:"PUT",body:JSON.stringify({name:e,pinned:s})})}async function E(){return(await t("/api/hermes/skills/external-dirs")).dirs??[]}async function N(e){await t("/api/hermes/skills/external-dirs",{method:"PUT",body:JSON.stringify({dirs:e})})}async function T(e,s){await t(`/api/hermes/skills/${encodeURIComponent(e)}/${encodeURIComponent(s)}`,{method:"DELETE"})}async function A(e,s){const m=d(),c=u(),a={};c&&(a.Authorization=`Bearer ${c}`);const f=y();f&&(a["X-Hermes-Profile"]=f);const i=new FormData;for(const l of e){const h=l.webkitRelativePath||l.name;i.append("file",l,h)}s&&i.append("category",s);const n=await fetch(`${m}/api/hermes/skills/import`,{method:"POST",headers:a,body:i}),r=await n.text();let o=null;try{o=r?JSON.parse(r):null}catch{}if(!n.ok)throw new Error(o?.error||r||`Import failed (${n.status})`);return o||{name:""}}var D=p((()=>{k()}));export{$ as a,A as c,N as d,v as f,U as i,D as l,E as n,P as o,x as p,b as r,w as s,T as t,O as u};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as r}from"./rolldown-runtime-M0oDzQ_3.js";import{f as t,u as s}from"./_plugin-vue_export-helper-
|
|
1
|
+
import{n as r}from"./rolldown-runtime-M0oDzQ_3.js";import{f as t,u as s}from"./_plugin-vue_export-helper-BIeGRfrQ.js";async function o(){return t("/health")}async function d(){return t("/api/hermes/update",{method:"POST"})}async function c(){return t("/api/hermes/update/status")}async function m(){return t("/api/hermes/update/preview")}async function u(){return t("/api/hermes/update/preview/tags")}async function p(e){return t("/api/hermes/update/preview/prepare",{method:"POST",body:JSON.stringify({tag:e})})}async function h(){return t("/api/hermes/update/preview/install",{method:"POST"})}async function f(e){return t("/api/hermes/update/preview/start",{method:"POST",body:JSON.stringify({tag:e})})}async function l(){return t("/api/hermes/update/preview/stop",{method:"POST"})}async function y(){return t("/api/hermes/available-models")}async function v(e){const a=new URLSearchParams;return a.set("profile",e||"default"),t(`/api/hermes/available-models?${a.toString()}`)}async function P(e){return t("/api/hermes/provider-models",{method:"POST",body:JSON.stringify(e)})}async function S(){return t("/api/hermes/provider-models/cache/refresh",{method:"POST"})}async function g(e){await t("/api/hermes/config/model",{method:"PUT",body:JSON.stringify(e)})}async function w(e){await t("/api/hermes/model-alias",{method:"PUT",body:JSON.stringify(e)})}async function O(e){await t("/api/hermes/config/providers",{method:"POST",body:JSON.stringify(e)})}async function b(e){await t(`/api/hermes/config/providers/${encodeURIComponent(e)}`,{method:"DELETE"})}async function T(e,a){await t(`/api/hermes/config/providers/${encodeURIComponent(e)}`,{method:"PUT",body:JSON.stringify(a)})}async function U(e){return t("/api/hermes/model-visibility",{method:"PUT",body:JSON.stringify(e)})}async function M(e){return t("/api/hermes/custom-model",{method:"PUT",body:JSON.stringify(e)})}async function J(e){const a=new URLSearchParams;return a.set("provider",e.provider),a.set("model",e.model),t(`/api/hermes/custom-model?${a.toString()}`,{method:"DELETE"})}var N=r((()=>{s()}));export{T as S,l as _,v as a,w as b,P as c,h as d,p as f,f as g,b as h,y as i,c as l,J as m,O as n,m as o,S as p,o as r,u as s,M as t,N as u,d as v,U as x,g as y};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as Y}from"./rolldown-runtime-M0oDzQ_3.js";import{Mn as he,Wn as s,Wt as ie,nn as Ae}from"./ui-vendor-dYn1tJGA.js";import{f as k,u as se}from"./_plugin-vue_export-helper-
|
|
1
|
+
import{n as Y}from"./rolldown-runtime-M0oDzQ_3.js";import{Mn as he,Wn as s,Wt as ie,nn as Ae}from"./ui-vendor-dYn1tJGA.js";import{f as k,u as se}from"./_plugin-vue_export-helper-BIeGRfrQ.js";function Je(e={}){const t=s({status:"idle",error:null,startedAt:null,mimeType:null}),o=Ae(()=>t.value.status==="recording");let u=null,V=null,F=[],I=null,h=null,b=null,L=null,_=null,w=null,E=null,U=0;function B(){t.value={status:"idle",error:null,startedAt:null,mimeType:null}}function R(r){const n=be(r);return t.value={status:"error",error:n,startedAt:null,mimeType:t.value.mimeType},n}function Z(){I!==null&&(clearTimeout(I),I=null)}function te(r){if(r)for(const n of r.getTracks())n.stop()}function l({stopStream:r=!0,clearChunks:n=!0}={}){Z(),r&&te(V),u=null,V=null,n&&(F=[])}function re(r){const n=b;h=null,b=null,L=null,n?.(r)}function q(r){const n=L;h=null,b=null,L=null,n?.(r)}function ve(){!b&&!L||re(J(t.value.mimeType??u?.mimeType??null))}function N(r){if(r!==void 0&&r!==_)return;const n=w;_=null,w=null,E=null,n?.()}function fe(r,n){if(n!==void 0&&n!==_)return;const S=E;_=null,w=null,E=null,S?.(r)}function ne(){!w&&!E||N()}function J(r){return new Blob([],{type:r||x})}function ye(){return typeof MediaRecorder>"u"?null:MediaRecorder}function Se(){const r=ye();if(!r||typeof navigator>"u"||!navigator.mediaDevices?.getUserMedia)throw new Error(e.messages?.unsupported||le);return r}function Pe(r,n){const S=n?.length?n:[...ae];return typeof r.isTypeSupported!="function"?S[0]:S.find(O=>r.isTypeSupported(O))}function Te(){if(t.value.status==="recording"||t.value.status==="requesting"||t.value.status==="stopping")return Promise.resolve();try{const r=Se(),n=++U;return t.value={status:"requesting",error:null,startedAt:null,mimeType:null},new Promise((S,O)=>{_=n,w=S,E=O,navigator.mediaDevices.getUserMedia(e.constraints??{audio:!0}).then(a=>{if(n!==U){te(a),N(n);return}const P=Pe(r,e.mimeTypes),D=P?new r(a,{mimeType:P}):new r(a);V=a,u=D,F=[],D.ondataavailable=ee=>{const K=ee.data;K&&K.size>0&&F.push(K)},D.onerror=ee=>{const K=R(ee.error??new Error(e.messages?.recordingFailed||"Microphone recording failed."));l(),q(K)},D.start(),t.value={status:"recording",error:null,startedAt:Date.now(),mimeType:D.mimeType||P||x},I=setTimeout(()=>{oe()},e.maxDurationMs??ue),N(n)}).catch(a=>{if(n!==U){N(n);return}l(),fe(R(a),n)})})}catch(r){return l(),Promise.reject(R(r))}}async function oe(){if(t.value.status==="requesting")return U+=1,ne(),l(),B(),J();const r=u;if(!r){const n=t.value.mimeType;return B(),J(n)}if(h)return h;if(r.state==="inactive"){const n=r.mimeType||t.value.mimeType;return l(),B(),J(n)}return t.value={...t.value,status:"stopping",error:null},Z(),h=new Promise((n,S)=>{b=n,L=S;const O=r.mimeType||t.value.mimeType||x;r.onstop=()=>{const a=new Blob(F,{type:O});l(),B(),re(a)},r.onerror=a=>{const P=R(a.error??new Error(e.messages?.recordingFailed||"Microphone recording failed."));l(),q(P)};try{r.stop()}catch(a){const P=R(a);l(),q(P)}}),h}function Me(){U+=1;const r=u;if(Z(),r&&(r.ondataavailable=null,r.onstop=null,r.onerror=null,r.state!=="inactive"))try{r.stop()}catch{}l(),ne(),ve(),B()}return{state:t,isRecording:o,start:Te,stop:oe,cancel:Me}}function be(e){return e instanceof Error?e:new Error(String(e))}var ae,x,ue,le,xe=Y((()=>{ie(),ae=["audio/webm;codecs=opus","audio/webm","audio/mp4","audio/wav"],x="audio/webm",ue=12e4,le="Microphone capture is not supported in this browser."}));async function Ge(e){if(!e.provider)throw new Error("STT provider is required");const t=new FormData;return t.append("audio",e.audio,"speech.webm"),t.append("provider",e.provider),typeof e.language=="string"&&e.language&&t.append("language",e.language),typeof e.prompt=="string"&&e.prompt&&t.append("prompt",e.prompt),k("/api/hermes/stt/transcribe",{method:"POST",body:t})}var We=Y((()=>{se()}));function Le(e){return e==="browser"||e==="openai"||e==="custom"?e:null}function _e(e){if(e&&typeof e=="object"){const t=e,o=Le(t.activeProvider);if(Array.isArray(t.providers))return{providers:t.providers,activeProvider:o};if(Array.isArray(t.settings))return{providers:t.settings,activeProvider:o}}return{providers:[],activeProvider:null}}async function we(){return _e(await k("/api/hermes/stt/settings"))}async function Ye(e,t){const o=await k(`/api/hermes/stt/settings/${e}`,{method:"PUT",body:JSON.stringify(t)});return typeof o=="object"&&o!==null&&"setting"in o?o.setting:o}async function $e(e){return(await k("/api/hermes/stt/settings/active",{method:"PUT",body:JSON.stringify({provider:e})})).activeProvider}async function He(e,t){const o=await k(`/api/hermes/stt/settings/${e}/secret/${t}`,{method:"DELETE"});return o&&typeof o=="object"&&"setting"in o?o.setting??null:o}var Ee=Y((()=>{se()}));function Ue(){if(typeof window>"u")return!1;const e=window;return typeof e.SpeechRecognition<"u"||typeof e.webkitSpeechRecognition<"u"}function ce(){return Ue()?"browser":"openai"}function Be(e){return{provider:e.provider==="browser"||e.provider==="openai"||e.provider==="custom"?e.provider:i.provider,openaiModel:typeof e.openaiModel=="string"&&e.openaiModel.trim()?e.openaiModel:i.openaiModel,openaiLanguage:typeof e.openaiLanguage=="string"?e.openaiLanguage:i.openaiLanguage,openaiPrompt:typeof e.openaiPrompt=="string"?e.openaiPrompt:i.openaiPrompt,customBaseUrl:typeof e.customBaseUrl=="string"?e.customBaseUrl:i.customBaseUrl,customModel:typeof e.customModel=="string"&&e.customModel.trim()?e.customModel:i.customModel,customLanguage:typeof e.customLanguage=="string"?e.customLanguage:i.customLanguage,customPrompt:typeof e.customPrompt=="string"?e.customPrompt:i.customPrompt}}function Re(){try{const e=localStorage.getItem(j);if(e){const t=Be(JSON.parse(e)),o=JSON.stringify(t);return e!==o&&localStorage.setItem(j,o),t}}catch{}return{...i}}function Oe(){return{provider:M.value,openaiModel:p.value,openaiLanguage:m.value,openaiPrompt:g.value,customBaseUrl:d.value,customModel:v.value,customLanguage:f.value,customPrompt:y.value}}function De(){try{localStorage.setItem(j,JSON.stringify(Oe()))}catch(e){console.warn("[useSttSettings] Failed to persist STT settings:",e)}}function pe(){p.value=i.openaiModel,m.value=i.openaiLanguage,g.value=i.openaiPrompt,z.value="",$.value="",H.value=!1,d.value=i.customBaseUrl,A.value=[],v.value=i.customModel,f.value=i.customLanguage,y.value=i.customPrompt,C.value="",X.value="",Q.value=!1}function Ke(){M.value=ce(),p.value=i.openaiModel,m.value=i.openaiLanguage,g.value=i.openaiPrompt,d.value=i.customBaseUrl,A.value=[],v.value=i.customModel,f.value=i.customLanguage,y.value=i.customPrompt}function me(){W+=1,G=!1,T=null,Ke(),pe();try{localStorage.removeItem(j)}catch{}}function ge(e){return Array.isArray(e)?Array.from(new Set(e.filter(t=>typeof t=="string"&&!!t.trim()).map(t=>t.trim()))):[]}function je(e){e.provider==="openai"&&(p.value=typeof e.settings.model=="string"&&e.settings.model.trim()?e.settings.model:p.value,m.value=typeof e.settings.language=="string"?e.settings.language:m.value,g.value=typeof e.settings.prompt=="string"?e.settings.prompt:g.value,$.value=e.secrets.apiKey||"",H.value=!!e.secrets.apiKey,z.value=""),e.provider==="custom"&&(d.value=typeof e.settings.baseUrl=="string"?e.settings.baseUrl:d.value,A.value=ge(e.settings.baseUrlPresets),v.value=typeof e.settings.model=="string"&&e.settings.model.trim()?e.settings.model:v.value,f.value=typeof e.settings.language=="string"?e.settings.language:f.value,y.value=typeof e.settings.prompt=="string"?e.settings.prompt:y.value,X.value=e.secrets.apiKey||"",Q.value=!!e.secrets.apiKey,C.value="")}function de(e,t=!1){t&&pe();const o=Array.isArray(e)?e:e.providers;for(const u of o)je(u);!Array.isArray(e)&&e.activeProvider&&(M.value=e.activeProvider)}async function ze(e=!1){if(G&&!e)return;if(T&&!e)return T;const t=W,o=we().then(u=>{t===W&&(de(u,!0),G=!0)}).finally(()=>{T===o&&(T=null)});return T=o,o}function Xe(){return{provider:M,openaiModel:p,openaiLanguage:m,openaiPrompt:g,openaiApiKey:z,openaiApiKeyPreview:$,openaiHasApiKey:H,customBaseUrl:d,customBaseUrlPresets:A,customModel:v,customLanguage:f,customPrompt:y,customApiKey:C,customApiKeyPreview:X,customHasApiKey:Q,setProvider(e){M.value=e},setOpenaiModel(e){p.value=e},setOpenaiLanguage(e){m.value=e},setOpenaiPrompt(e){g.value=e},setOpenaiApiKey(e){z.value=e},setCustomBaseUrl(e){d.value=e},setCustomBaseUrlPresets(e){A.value=ge(e)},setCustomModel(e){v.value=e},setCustomLanguage(e){f.value=e},setCustomPrompt(e){y.value=e},setCustomApiKey(e){C.value=e},applyServerSttSettings:de,loadServerSttSettings:ze,reset(){me()}}}var j,i,c,M,p,m,g,z,$,H,d,A,v,f,y,C,X,Q,G,T,W,Qe=Y((()=>{ie(),Ee(),j="hermes-stt-settings-v1",i={provider:ce(),openaiModel:"gpt-4o-transcribe",openaiLanguage:"",openaiPrompt:"",customBaseUrl:"",customModel:"gpt-4o-transcribe",customLanguage:"",customPrompt:""},c=Re(),M=s(c.provider),p=s(c.openaiModel),m=s(c.openaiLanguage),g=s(c.openaiPrompt),z=s(""),$=s(""),H=s(!1),d=s(c.customBaseUrl),A=s([]),v=s(c.customModel),f=s(c.customLanguage),y=s(c.customPrompt),C=s(""),X=s(""),Q=s(!1),G=!1,T=null,W=0,typeof window<"u"&&window.addEventListener("hermes-auth-cleared",me),he([M,p,m,g,d,v,f,y],De)}));export{Ee as a,We as c,Je as d,we as i,Ge as l,Xe as n,$e as o,He as r,Ye as s,Qe as t,xe as u};
|
package/dist/client/index.html
CHANGED
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
}
|
|
34
34
|
})();
|
|
35
35
|
</script>
|
|
36
|
-
<script type="module" crossorigin src="/assets/js/index-
|
|
36
|
+
<script type="module" crossorigin src="/assets/js/index-Bkiif2Pf.js"></script>
|
|
37
37
|
<link rel="modulepreload" crossorigin href="/assets/js/rolldown-runtime-M0oDzQ_3.js">
|
|
38
38
|
<link rel="modulepreload" crossorigin href="/assets/js/mermaid-CWQI515T.js">
|
|
39
39
|
<link rel="modulepreload" crossorigin href="/assets/js/ui-vendor-dYn1tJGA.js">
|
|
40
40
|
<link rel="modulepreload" crossorigin href="/assets/js/vendor-B1Lfatlz.js">
|
|
41
41
|
<link rel="modulepreload" crossorigin href="/assets/js/vue-vendor-DZ4A_GHn.js">
|
|
42
|
-
<link rel="modulepreload" crossorigin href="/assets/js/_plugin-vue_export-helper-
|
|
43
|
-
<link rel="modulepreload" crossorigin href="/assets/js/system-
|
|
42
|
+
<link rel="modulepreload" crossorigin href="/assets/js/_plugin-vue_export-helper-BIeGRfrQ.js">
|
|
43
|
+
<link rel="modulepreload" crossorigin href="/assets/js/system-Bm5rA-WZ.js">
|
|
44
44
|
<link rel="stylesheet" crossorigin href="/assets/css/vendor-DX3NCGtF.css">
|
|
45
45
|
<link rel="stylesheet" crossorigin href="/assets/css/vue-vendor-WE_HbAyV.css">
|
|
46
46
|
<link rel="stylesheet" crossorigin href="/assets/css/index-C-LxXPm3.css">
|
package/dist/server/index.js
CHANGED
|
@@ -272,7 +272,7 @@ const isVersionPreview = import.meta.env.VITE_HERMES_PREVIEW === '1';`)),l=l.rep
|
|
|
272
272
|
`),b.destroy();return}l.handleUpgrade(e,b,d,n=>{l.emit("connection",n,e)})}})}),l.on("connection",(c,e)=>{let b=e.kanbanBoard||"default",d=lj({board:b,interval:.5}),Z=!1;zs(c,{type:"connected",board:b});let n=()=>{Z||(Z=!0,d.killed||d.kill())};d.stdout?.on("data",uj(t=>{t.toLowerCase().startsWith("watching kanban events")||zs(c,{type:"event",board:b})})),d.stderr?.on("data",uj(t=>{zs(c,{type:"error",board:b,message:t})})),d.on("error",t=>{V.error(t,"Hermes CLI: kanban watch failed"),zs(c,{type:"error",board:b,message:t.message}),c.readyState===c.OPEN&&c.close()}),d.on("exit",(t,a)=>{zs(c,{type:"stopped",board:b,code:t,signal:a}),c.readyState===c.OPEN&&c.close()}),c.on("close",n),c.on("error",n)}),V.info("WebSocket ready at /api/hermes/kanban/events (kanban watch bridge)")}var Qj=C(Xm(),1),cvI=C(fh(),1),vj=C(Xm(),1),pQ=C(fh(),1),oo=require("url"),La=C(Fj(),1),yj=C(require("http"),1),gj=C(ol(),1),wj={NotFound:"not-found"};function lvI(I){return typeof I=="function"?I(wj):I}var GvI=class{_handlers=new Map;register(I,l){let G=this._handlers.get(I)??[];G.push(l),this._handlers.set(I,G)}emit(I,l,G){let c=this._handlers.get(I);return c&&c.length>0?(0,Qj.default)(c)(l,G):G()}};function po(I,l={}){let G={...l};"strict"in G&&!("trailing"in G)&&(G.trailing=G.strict!==!0,delete G.strict),delete G.pathAsRegExp,delete G.ignoreCaptures,delete G.prefix;let{regexp:c,keys:e}=(0,La.pathToRegexp)(I,G);return{regexp:c,keys:e}}function evI(I,l={}){return(0,La.compile)(I,l)}function bvI(I,l){return(0,La.parse)(I,l)}function hQ(I={}){let l={sensitive:I.sensitive,end:I.end,strict:I.strict,trailing:I.trailing};"strict"in l&&!("trailing"in l)&&(l.trailing=l.strict!==!0,delete l.strict);for(let G of Object.keys(l))l[G]===void 0&&delete l[G];return l}function dvI(I){try{return decodeURIComponent(I)}catch{return I}}var Xj=class{opts;name;methods;paramNames;stack;path;regexp;constructor(I,l,G,c={}){this.opts=c,this.name=this.opts.name||void 0,this.methods=this._normalizeHttpMethods(l),this.stack=this._normalizeAndValidateMiddleware(G,l,I),this.path=I,this.paramNames=[],this._configurePathMatching()}_normalizeHttpMethods(I){let l=[];for(let G of I){let c=G.toUpperCase();l.push(c),c==="GET"&&l.unshift("HEAD")}return l}_normalizeAndValidateMiddleware(I,l,G){let c=Array.isArray(I)?I:[I];for(let e of c){let b=typeof e;if(b!=="function"){let d=this.opts.name||G;throw new Error(`${l.toString()} \`${d}\`: \`middleware\` must be a function, not \`${b}\``)}}return c}_configurePathMatching(){this.opts.pathAsRegExp===!0?this.regexp=this.path instanceof RegExp?this.path:new RegExp(this.path):this.path&&this._configurePathToRegexp()}_configurePathToRegexp(){let I=hQ(this.opts),{regexp:l,keys:G}=po(this.path,I);this.regexp=l,this.paramNames=G}match(I){return this.regexp.test(I)}params(I,l,G={}){let c={...G};for(let[e,b]of l.entries()){let d=this.paramNames[e];if(d&&b&&b.length>0){let Z=d.name;c[Z]=dvI(b)}}return c}captures(I){if(this.opts.ignoreCaptures)return[];let l=I.match(this.regexp);return l?l.slice(1):[]}url(...I){if(this.path instanceof RegExp)throw new TypeError("Cannot generate URL for routes defined with RegExp paths. Use string paths with named parameters instead.");let{params:l,options:G}=this._parseUrlArguments(I),c=this.path.replaceAll("(.*)",""),e=evI(c,{encode:encodeURIComponent,...G}),b=this._buildParamReplacements(l,c),d=e(b);return G&&G.query?this._addQueryString(d,G.query):d}_parseUrlArguments(I){let l=I[0]??{},G=I[1];if(typeof l!="object"||l===null){let c=[...I],e=c.at(-1);typeof e=="object"&&e!==null?(G=e,l=c.slice(0,-1)):l=c}else if(l&&!G){let c=Object.keys(l);if(c.length===1&&c[0]==="query")G=l,l={};else if("query"in l&&l.query){let{query:b,...d}=l;G={query:b},l=d}}return{params:l,options:G}}_buildParamReplacements(I,l){let{tokens:G}=bvI(l),c=G.some(b=>"name"in b&&b.name),e={};if(Array.isArray(I)){let b=0;for(let d of G)"name"in d&&d.name&&(e[d.name]=String(I[b++]))}else if(c&&typeof I=="object"&&!("query"in I))for(let[b,d]of Object.entries(I))e[b]=String(d);return e}_addQueryString(I,l){let G=(0,oo.parse)(I),c={...G,query:G.query??void 0};return typeof l=="string"?(c.search=l,c.query=void 0):(c.search=void 0,c.query=l),(0,oo.format)(c)}param(I,l){let G=this.stack,c=this.paramNames,e=this._createParamMiddleware(I,l),b=c.map(Z=>Z.name),d=b.indexOf(I);return d!==-1&&this._insertParamMiddleware(G,e,b,d),this}_createParamMiddleware(I,l){let G=((c,e)=>(c._matchedParams||(c._matchedParams=new WeakMap),c._matchedParams.has(l)?e():(c._matchedParams.set(l,!0),l(c.params[I],c,e))));return G.param=I,G._originalFn=l,G}_insertParamMiddleware(I,l,G,c){let e=!1;for(let b=0;b<I.length;b++){let d=I[b];if(!d.param){I.splice(b,0,l),e=!0;break}if(G.indexOf(d.param)>c){I.splice(b,0,l),e=!0;break}}e||I.push(l)}setPrefix(I){return this.path?this.path instanceof RegExp?this:(this.path=this._applyPrefix(I),this._reconfigurePathMatching(I),this):this}_applyPrefix(I){let l=this.path==="/",G=this.opts.strict===!0,c=I.includes(":"),e=this.opts.pathAsRegExp===!0&&typeof this.path=="string";if(c&&e){let b=this.path;(b===String.raw`(?:\/|$)`||b===String.raw`(?:\\\/|$)`)&&(this.path="{/*rest}",this.opts.pathAsRegExp=!1)}return l&&!G?I:`${I}${this.path}`}_reconfigurePathMatching(I){let l=this.opts.pathAsRegExp===!0;if(I&&I.includes(":")&&l){let c=hQ(this.opts),{regexp:e,keys:b}=po(this.path,c);this.regexp=e,this.paramNames=b,this.opts.pathAsRegExp=!1}else if(l){let c=this.path,e=c.startsWith("^")?c:`^${c}`;this.regexp=this.path instanceof RegExp?this.path:new RegExp(e)}else{let c=hQ(this.opts),{regexp:e,keys:b}=po(this.path,c);this.regexp=e,this.paramNames=b}}};function ZvI(){return yj.default.METHODS.map(I=>I.toLowerCase())}var nvI=["get","post","put","patch","delete","del","head","options"];function tvI(I){return I?Array.isArray(I)?I:[I]:[]}function Ej(I,l,G){let c=tvI(G);for(let e of c)I.param(l,e)}function avI(I,l){let G=Object.keys(l);for(let c of G){let e=l[c];Ej(I,c,e)}}function Hj(I,l={}){if(!I)return!1;let{keys:G}=po(I,l);return G.length>0}function WvI(I,l){return I!==void 0?typeof I=="string"?I===""?{path:"{/*rest}",pathAsRegExp:!1}:I==="/"?{path:"/",pathAsRegExp:!1}:{path:I,pathAsRegExp:!1}:{path:I,pathAsRegExp:!0}:l?{path:"{/*rest}",pathAsRegExp:!1}:{path:String.raw`(?:\/|$)`,pathAsRegExp:!0}}var uQ=(0,gj.default)("koa-router"),Jj=ZvI(),oQ=class{opts;methods;exclusive;params;stack;host;_events=new GvI;constructor(I={}){this.opts=I,this.methods=this.opts.methods||["HEAD","OPTIONS","GET","PUT","PATCH","POST","DELETE"],this.exclusive=!!this.opts.exclusive,this.params={},this.stack=[],this.host=this.opts.host}static url(I,...l){return new Xj(I,[],()=>{}).url(...l)}use(...I){let l;if(this._isPathArray(I[0]))return this._useWithPathArray(I);let G=this._hasExplicitPath(I[0]);if(G&&(l=I.shift()),I.length===0)throw new Error("You must provide at least one middleware function to router.use()");for(let c of I)this._isNestedRouter(c)?this._mountNestedRouter(c,l):this._registerMiddleware(c,l,G);return this}_isPathArray(I){return Array.isArray(I)&&I.length>0&&I.every(l=>typeof l=="string")}_hasExplicitPath(I){return typeof I=="string"||I instanceof RegExp}_isNestedRouter(I){return typeof I=="function"&&"router"in I&&I.router!==void 0}_useWithPathArray(I){let l=I[0],G=I.slice(1);for(let c of l)Reflect.apply(this.use,this,[c,...G]);return this}_mountNestedRouter(I,l){let G=I.router,c=this._cloneRouter(G),e=l&&typeof l=="string"&&Hj(l,this.opts);for(let b=0;b<c.stack.length;b++){let d=c.stack[b],Z=this._cloneLayer(d);l&&typeof l=="string"&&Z.setPrefix(l),this.opts.prefix&&Z.setPrefix(this.opts.prefix),Z.methods.length===0&&e&&(Z.opts.ignoreCaptures=!1),this.stack.push(Z),c.stack[b]=Z}this.params&&this._applyParamMiddlewareToRouter(c)}_cloneRouter(I){return Object.assign(Object.create(Object.getPrototypeOf(I)),I,{stack:[...I.stack]})}_cloneLayer(I){return Object.assign(Object.create(Object.getPrototypeOf(I)),I,{stack:[...I.stack],methods:[...I.methods],paramNames:[...I.paramNames],opts:{...I.opts}})}_applyParamMiddlewareToRouter(I){let l=Object.keys(this.params);for(let G of l){let c=this.params[G];Ej(I,G,c)}}_registerMiddleware(I,l,G){let c=Hj(this.opts.prefix||"",this.opts),e=(()=>{if(l!==void 0)return l;if(c)return""})(),b=G||l===void 0&&c,{path:d,pathAsRegExp:Z}=WvI(e,c),n=d,t=Z,a=b&&d==="/";b&&typeof d=="string"&&(n=d,t=!1),this.register(n,[],I,{end:a,ignoreCaptures:!b&&!c,pathAsRegExp:t})}prefix(I){let l=I.replace(/\/$/,""),G=this.opts.prefix||"";this.opts.prefix=l;for(let c of this.stack){if(typeof c.path=="string"&&G){let e=G+"/";(c.path===G||c.path.startsWith(e))&&(c.path=c.path.slice(G.length)||"/")}c.setPrefix(l)}return this}middleware(){let I=function(l,G){if(uQ("%s %s",l.method,l.path),!this.matchHost(l.host))return G();let c=this._getRequestPath(l),e=this.match(c,l.method);if(this._storeMatchedRoutes(l,e),l.router=this,l.routeMatched=e.route,!e.route)return this._events.emit(wj.NotFound,l,G);let b=e.pathAndMethod;this._setMatchedRouteInfo(l,b);let d=this._buildMiddlewareChain(b,c);return(0,vj.default)(d)(l,G)}.bind(this);return I.router=this,I}_getRequestPath(I){let l=I;return this.opts.routerPath||l.newRouterPath||l.path||l.routerPath||""}_storeMatchedRoutes(I,l){let G=I;G.matched?G.matched.push(...l.path):G.matched=l.path}_setMatchedRouteInfo(I,l){let G=I,c=l.toReversed().find(e=>e.methods.length>0);c&&(G._matchedRoute=c.path,c.name&&(G._matchedRouteName=c.name))}_buildMiddlewareChain(I,l){let G;if(this.exclusive){let e;if(this.opts.exclusive==="specificity")for(let b of I)(!e||b.paramNames.length<e.paramNames.length)&&(e=b);else e=I.at(-1);G=e?[e]:[]}else G=I;let c=[];for(let e of G)c.push((b,d)=>{let Z=b;return Z.captures=e.captures(l),Z.request.params=e.params(l,Z.captures||[],Z.params),Z.params=Z.request.params,Z.routerPath=e.path,Z.routerName=e.name||void 0,Z._matchedRoute=e.path,e.name&&(Z._matchedRouteName=e.name),d()},...e.stack);return c}routes(){return this.middleware()}on(I,l){return this._events.register(lvI(I),l),this}allowedMethods(I={}){let l=this.methods;return(G,c)=>{let e=G;return c().then(()=>{if(!this._shouldProcessAllowedMethods(e))return;let b=e.matched||[],d=this._collectAllowedMethods(b),Z=Object.keys(d),n=G.method.toUpperCase();if(!l.includes(n)){this._handleNotImplemented(e,Z,I);return}if(n==="OPTIONS"&&Z.length>0){this._handleOptionsRequest(e,Z);return}Z.length>0&&!d[n]&&this._handleMethodNotAllowed(e,Z,I)})}}_shouldProcessAllowedMethods(I){return!!(I.matched&&(!I.status||I.status===404))}_collectAllowedMethods(I){let l={};for(let G of I)for(let c of G.methods)l[c]=c;return l}_handleNotImplemented(I,l,G){if(G.throw)throw typeof G.notImplemented=="function"?G.notImplemented():new pQ.default.NotImplemented;I.status=501,I.set("Allow",l.join(", "))}_handleOptionsRequest(I,l){I.status=200,I.body="",I.set("Allow",l.join(", "))}_handleMethodNotAllowed(I,l,G){if(G.throw)throw typeof G.methodNotAllowed=="function"?G.methodNotAllowed():new pQ.default.MethodNotAllowed;I.status=405,I.set("Allow",l.join(", "))}all(...I){let l,G,c;if(I.length>=2&&(typeof I[1]=="string"||I[1]instanceof RegExp)?(l=I[0],G=I[1],c=I.slice(2)):(l=void 0,G=I[0],c=I.slice(1)),typeof G!="string"&&!(G instanceof RegExp)&&(!Array.isArray(G)||G.length===0))throw new Error("You have to provide a path when adding an all handler");let e={name:l,pathAsRegExp:G instanceof RegExp};return this.register(G,Jj,c,{...this.opts,...e}),this}redirect(I,l,G){let c=I,e=l;if(typeof I=="symbol"||typeof I=="string"&&I[0]!=="/"){let d=this.url(I);if(d instanceof Error)throw d;c=d}if(typeof l=="symbol"||typeof l=="string"&&l[0]!=="/"&&!l.includes("://")){let d=this.url(l);if(d instanceof Error)throw d;e=d}return this.all(c,d=>{d.redirect(e),d.status=G||301})}register(I,l,G,c={}){let e={...this.opts,...c};if(Array.isArray(I))return this._registerMultiplePaths(I,l,G,e);let b=this._createRouteLayer(I,l,G,e);return this.opts.prefix&&b.setPrefix(this.opts.prefix),avI(b,this.params),this.stack.push(b),uQ("defined route %s %s",b.methods,b.path),b}_registerMultiplePaths(I,l,G,c){for(let e of I)this.register.call(this,e,l,G,c);return this}_createRouteLayer(I,l,G,c){return new Xj(I,l,G,{end:c.end===!1?c.end:!0,name:c.name,sensitive:c.sensitive||!1,strict:c.strict||!1,prefix:c.prefix||"",ignoreCaptures:c.ignoreCaptures,pathAsRegExp:c.pathAsRegExp})}route(I){return this.stack.find(G=>G.name===I)||!1}url(I,...l){let G=this.route(I);return G?G.url(...l):new Error(`No route found for name: ${String(I)}`)}match(I,l){let G={path:[],pathAndMethod:[],route:!1},c=l.toUpperCase();for(let e of this.stack)if(uQ("test %s %s",e.path,e.regexp),e.match(I)){G.path.push(e);let b=e.methods.length===0,d=e.methods.includes(c);(b||d)&&(G.pathAndMethod.push(e),e.methods.length>0&&(G.route=!0))}return G}matchHost(I){let{host:l}=this;return l?I?typeof l=="string"?I===l:Array.isArray(l)?l.includes(I):l instanceof RegExp?l.test(I):!1:!1:!0}param(I,l){this.params[I]||(this.params[I]=[]),Array.isArray(this.params[I])||(this.params[I]=[this.params[I]]),this.params[I].push(l);for(let G of this.stack)G.param(I,l);return this}_registerMethod(I,...l){let G,c,e;if(l.length>=2&&(typeof l[1]=="string"||l[1]instanceof RegExp)?(G=l[0],c=l[1],e=l.slice(2)):(G=void 0,c=l[0],e=l.slice(1)),typeof c!="string"&&!(c instanceof RegExp)&&(!Array.isArray(c)||c.length===0))throw new Error(`You have to provide a path when adding a ${I} handler`);let b={name:G,pathAsRegExp:c instanceof RegExp};return this.register(c,[I],e,{...this.opts,...b}),this}get(...I){return this._registerMethod("get",...I)}post(...I){return this._registerMethod("post",...I)}put(...I){return this._registerMethod("put",...I)}patch(...I){return this._registerMethod("patch",...I)}delete(...I){return this._registerMethod("delete",...I)}del(...I){return this.delete.apply(this,I)}head(...I){return this._registerMethod("head",...I)}options(...I){return this._registerMethod("options",...I)}},mvI=oQ,B=mvI;for(let I of Jj)nvI.includes(I)||I in oQ.prototype||Object.defineProperty(oQ.prototype,I,{value:function(...G){return this._registerMethod(I,...G)},writable:!0,configurable:!0,enumerable:!1});Xn();CI();var jd=require("child_process"),Uc=require("fs"),fQ=require("net"),NI=require("path");GI();ac();var AQ=require("timers/promises"),LQ=require("net"),rK=require("os"),VK=require("url"),kQ=require("path");GI();VI();function OvI(){return process.env.VITEST?process.platform==="win32"?`tcp://127.0.0.1:${28e3+process.pid%1e4}`:`ipc://${(0,kQ.join)((0,rK.tmpdir)(),`hermes-agent-bridge-test-${process.pid}.sock`)}`:process.platform==="win32"?"tcp://127.0.0.1:18765":"ipc:///tmp/hermes-agent-bridge.sock"}var xQ=OvI(),MvI=12e4;function oK(I){let l=process.env[I];if(!l)return;let G=Number(l);return Number.isFinite(G)&&G>0?G:void 0}var go=class extends Error{response},PI=class{endpoint;timeoutMs;connectRetryMs;lock=Promise.resolve();constructor(l={}){this.endpoint=l.endpoint||process.env.HERMES_AGENT_BRIDGE_ENDPOINT||xQ,this.timeoutMs=l.timeoutMs??oK("HERMES_AGENT_BRIDGE_TIMEOUT_MS")??MvI,this.connectRetryMs=l.connectRetryMs??oK("HERMES_AGENT_BRIDGE_CONNECT_RETRY_MS")??5e3}summarizePayload(l){let c={action:String(l.action||"")};for(let e of["session_id","run_id","request_id","approval_id","profile","worker_key"])l[e]!=null&&(c[e]=l[e]);return Array.isArray(l.conversation_history)&&(c.conversation_history_count=l.conversation_history.length),Array.isArray(l.messages)&&(c.messages_count=l.messages.length),typeof l.message=="string"?c.message_chars=l.message.length:Array.isArray(l.message)&&(c.message_parts=l.message.length),typeof l.command=="string"&&(c.command=l.command),typeof l.text=="string"&&(c.text_chars=l.text.length),typeof l.error=="string"&&(c.error=l.error),l.force_compress===!0&&(c.force_compress=!0),c}summarizeResponse(l){let G={ok:l.ok===!0};for(let c of["session_id","run_id","request_id","status","cursor","event_cursor"])l[c]!=null&&(G[c]=l[c]);return typeof l.delta=="string"&&(G.delta_chars=l.delta.length),typeof l.output=="string"&&(G.output_chars=l.output.length),Array.isArray(l.events)&&(G.events_count=l.events.length),typeof l.error=="string"&&(G.error=l.error),Array.isArray(l.history)&&(G.history_count=l.history.length),G}runtimeContext(l){let G=typeof l.profile=="string"?l.profile.trim():"",c=G||"default";try{G||(c=cI())}catch{}let e={profile:c,cwd:process.cwd()};try{let b=T(c);e.profile_dir=b,e.config_path=(0,kQ.join)(b,"config.yaml")}catch{}return e}async connect(){return this}async close(){}connectSocketOnce(){return new Promise((l,G)=>{let c=this.endpoint,e;if(c.startsWith("ipc://"))e=(0,LQ.createConnection)(c.slice(6));else if(c.startsWith("tcp://")){let n=new VK.URL(c);e=(0,LQ.createConnection)({host:n.hostname||"127.0.0.1",port:Number(n.port)})}else{G(new Error(`unsupported agent bridge endpoint: ${c}`));return}let b=()=>{e.off("connect",d),e.off("error",Z)},d=()=>{b(),l(e)},Z=n=>{b(),e.destroy(),G(n)};e.once("connect",d),e.once("error",Z)})}isRetryableConnectError(l){let G=String(l?.code||"");return["ECONNREFUSED","ENOENT","ECONNRESET","EPIPE","ETIMEDOUT"].includes(G)}async connectSocket(){let l=Date.now()+Math.max(0,this.connectRetryMs);for(;;)try{return await this.connectSocketOnce()}catch(G){if(!this.isRetryableConnectError(G)||Date.now()>=l)throw G;await(0,AQ.setTimeout)(100)}}readResponse(l,G){return new Promise((c,e)=>{let b="",d=G>0?setTimeout(()=>{Z(),l.destroy(),e(new Error(`Agent bridge request timed out after ${G}ms`))},G):null,Z=()=>{d&&clearTimeout(d),l.off("data",t),l.off("error",a),l.off("end",W),l.off("close",m)},n=s=>{Z(),l.end(),c(s)},t=s=>{b+=s.toString("utf8");let N=b.indexOf(`
|
|
273
273
|
`);N>=0&&n(b.slice(0,N))},a=s=>{Z(),l.destroy(),e(s)},W=()=>{let s=b.trim();s&&n(s)},m=()=>{b.trim()||(Z(),e(new Error("Agent bridge socket closed without a response")))};l.on("data",t),l.once("error",a),l.once("end",W),l.once("close",m)})}async request(l,G={}){let c=async()=>{let b=G.timeoutMs||this.timeoutMs,d=Date.now(),n=String(l.action||"")!=="get_output",t=n?this.runtimeContext(l):void 0;n&&rl.info({endpoint:this.endpoint,timeoutMs:b,runtime:t,request:this.summarizePayload(l)},"[agent-bridge-client] request");try{let a=await this.connectSocket();a.write(`${JSON.stringify(l)}
|
|
274
274
|
`);let W=await this.readResponse(a,b),m=JSON.parse(W);if(!m.ok){let s=new go(m.error||"Agent bridge request failed");throw s.response=m,rl.warn({durationMs:Date.now()-d,runtime:t,response:this.summarizeResponse(m)},"[agent-bridge-client] request rejected"),s}return n&&rl.info({durationMs:Date.now()-d,runtime:t,response:this.summarizeResponse(m)},"[agent-bridge-client] response"),m}catch(a){throw a instanceof go||rl.error({durationMs:Date.now()-d,err:{message:a?.message,name:a?.name},runtime:t,request:this.summarizePayload(l)},"[agent-bridge-client] request failed"),a}};if(!G.serialize)return c();let e=this.lock.then(c,c);return this.lock=e.catch(()=>{}),e}ping(){return this.request({action:"ping"})}chat(l,G,c,e,b,d={}){return this.request({action:"chat",session_id:l,message:G,...d.storage_message!==void 0?{storage_message:d.storage_message}:{},...c?{conversation_history:c}:{},...e?{instructions:e}:{},...b?{profile:b}:{},...d.model?{model:d.model}:{},...d.provider?{provider:d.provider}:{},...d.source?{source:d.source}:{},...d.wait?{wait:!0}:{},...d.timeout?{timeout:d.timeout}:{},...d.force_compress?{force_compress:!0}:{},...d.reasoning_effort?{reasoning_effort:d.reasoning_effort}:{}})}contextEstimate(l,G,c,e,b={}){return this.request({action:"context_estimate",session_id:l,messages:G,...c?{instructions:c}:{},...e?{profile:e}:{},...b.model?{model:b.model}:{},...b.provider?{provider:b.provider}:{}})}command(l,G,c){return this.request({action:"command",session_id:l,command:G,...c?{profile:c}:{}})}goalEvaluate(l,G,c){return this.request({action:"goal_evaluate",session_id:l,final_response:G,...c?{profile:c}:{}})}getOutput(l,G=0,c=0,e={}){return this.request({action:"get_output",run_id:l,cursor:G,event_cursor:c},e)}getSessionTitle(l,G,c={}){return this.request({action:"get_session_title",session_id:l,...G?{profile:G}:{}},c)}async*streamOutput(l,G={}){let c=G.intervalMs||100,e=0,b=0;for(;;){let d=await this.getOutput(l,e,b,G);if(e=d.cursor,b=d.event_cursor,(d.delta||d.done||d.events&&d.events.length>0)&&(yield d),d.done)return;await(0,AQ.setTimeout)(c)}}async chatStream(l,G,c,e={}){let b=await this.chat(l,G),d=null;for await(let Z of this.streamOutput(b.run_id,e))d=Z,Z.delta&&await c(Z.delta,Z);if(!d)throw new Error(`Agent bridge run ${b.run_id} produced no output state`);return d}getResult(l,G={}){return this.request({action:"get_result",run_id:l},G)}interrupt(l,G,c){return this.request({action:"interrupt",session_id:l,message:G,...c?{profile:c}:{}})}goalPause(l,G,c){return this.request({action:"goal_pause",session_id:l,reason:G,...c?{profile:c}:{}})}steer(l,G,c){return this.request({action:"steer",session_id:l,text:G,...c?{profile:c}:{}})}approvalRespond(l,G){return this.request({action:"approval_respond",approval_id:l,choice:G})}clarifyRespond(l,G){return this.request({action:"clarify_respond",clarify_id:l,response:G})}compressionRespond(l,G){return this.request({action:"compression_respond",request_id:l,...G},{timeoutMs:this.timeoutMs})}destroyAll(){return this.request({action:"destroy_all"},{serialize:!0})}destroyProfile(l){return this.request({action:"destroy_profile",profile:l},{serialize:!0})}getHistory(l,G){return this.request({action:"get_history",session_id:l,...G?{profile:G}:{}})}status(l,G){return this.request({action:"status",session_id:l,...G?{profile:G}:{}})}statusIfLoaded(l,G,c={}){return this.request({action:"status_if_loaded",session_id:l,...G?{profile:G}:{}},c)}destroy(l,G,c){return this.request({action:"destroy",session_id:l,...G?{profile:G}:{},...c?{worker_key:c}:{}})}list(){return this.request({action:"list"})}shutdown(){return this.request({action:"shutdown"},{serialize:!0})}mcpList(l){return this.request({action:"mcp_list",...l?{profile:l}:{}})}mcpAdd(l,G,c){return this.request({action:"mcp_server_add",name:l,config:G,...c?{profile:c}:{}},{serialize:!0})}mcpUpdate(l,G,c){return this.request({action:"mcp_server_update",name:l,config:G,...c?{profile:c}:{}},{serialize:!0})}mcpRemove(l,G){return this.request({action:"mcp_server_remove",name:l,...G?{profile:G}:{}},{serialize:!0})}mcpTest(l,G){return this.request({action:"mcp_server_test",name:l,...G?{profile:G}:{}},{timeoutMs:18e4})}mcpTools(l,G,c){return this.request({action:"mcp_tools_list",...l?{server:l}:{},...G?{profile:G}:{},...c?{raw:c}:{}})}mcpReload(l,G){return this.request({action:"mcp_reload",...l?{server:l}:{},...G?{profile:G}:{}},{serialize:!0})}};var fvI=12e4,jvI=1e3,KvI=3e4,SvI=5e3,TvI=250,zQ={HERMES_OPENROUTER_APP_REFERER:"https://hermes-studio.ai",HERMES_OPENROUTER_APP_TITLE:"Hermes Studio",HERMES_OPENROUTER_APP_CATEGORIES:"cli-agent,personal-agent"};function Hn(I){let l=process.env[I];if(!l)return;let G=Number(l);return Number.isFinite(G)&&G>0?G:void 0}function DvI(I){let l=I.trim().toLowerCase();return l==="ipc:///tmp/hermes-agent-bridge.sock"||l==="tcp://127.0.0.1:18765"||l==="tcp://localhost:18765"}function qvI(I,l,G){return{...process.env,HERMES_AGENT_BRIDGE_ENDPOINT:I,HERMES_HOME:l,HERMES_OPENROUTER_APP_REFERER:process.env.HERMES_OPENROUTER_APP_REFERER||zQ.HERMES_OPENROUTER_APP_REFERER,HERMES_OPENROUTER_APP_TITLE:process.env.HERMES_OPENROUTER_APP_TITLE||zQ.HERMES_OPENROUTER_APP_TITLE,HERMES_OPENROUTER_APP_CATEGORIES:process.env.HERMES_OPENROUTER_APP_CATEGORIES||zQ.HERMES_OPENROUTER_APP_CATEGORIES,HERMES_AGENT_ROOT:G?.trim()||""}}function PvI(I){return I?process.platform==="win32"?[(0,NI.join)(I,"venv","Scripts","python.exe"),(0,NI.join)(I,"venv","Scripts","python3.exe"),(0,NI.join)(I,".venv","Scripts","python.exe"),(0,NI.join)(I,".venv","Scripts","python3.exe")]:[(0,NI.join)(I,"venv","bin","python3"),(0,NI.join)(I,"venv","bin","python"),(0,NI.join)(I,".venv","bin","python3"),(0,NI.join)(I,".venv","bin","python")]:[]}function _vI(I){return I?[process.env.HERMES_AGENT_BRIDGE_UV,process.env.UV,...process.platform==="win32"?[I?(0,NI.join)(I,"venv","Scripts","uv.exe"):"",I?(0,NI.join)(I,"venv","Scripts","uv.cmd"):"",I?(0,NI.join)(I,".venv","Scripts","uv.exe"):"",I?(0,NI.join)(I,".venv","Scripts","uv.cmd"):""]:[I?(0,NI.join)(I,"venv","bin","uv"):"",I?(0,NI.join)(I,".venv","bin","uv"):""],"uv"].filter(l=>!!l&&l.trim().length>0):[process.env.HERMES_AGENT_BRIDGE_UV,process.env.UV].filter(l=>!!l&&l.trim().length>0)}function jQ(I){let l=I.trim();if(l){if((0,NI.isAbsolute)(l)||l.includes("/")||l.includes("\\"))return(0,Uc.existsSync)(l)?(0,NI.resolve)(l):void 0;try{return(process.platform==="win32"?(0,jd.execFileSync)("where.exe",[l],{encoding:"utf-8",windowsHide:!0}):(0,jd.execFileSync)("which",[l],{encoding:"utf-8"})).split(/\r?\n/).map(c=>c.trim()).find(Boolean)}catch{return}}}function $vI(){let I=jQ(Hs());if(!I)return;let l=(0,NI.dirname)(I),c=[(0,NI.resolve)(l,".."),(0,NI.resolve)(l,"..",".."),(0,NI.resolve)(l,"..","hermes-agent"),(0,NI.resolve)(l,"..","lib","hermes-agent"),(0,NI.resolve)(l,"..","..","hermes-agent")].find(e=>(0,Uc.existsSync)((0,NI.join)(e,"run_agent.py")));if(c)return c;try{let d=(0,Uc.readFileSync)(I,"utf-8").split(/\r?\n/,1)[0].match(/^#!\s*(.+)$/)?.[1]?.trim().split(/\s+/)[0];if(d){let Z=(0,NI.dirname)(d);return[(0,NI.resolve)(Z,"..",".."),(0,NI.resolve)(Z,"..","..","hermes-agent"),(0,NI.resolve)(Z,"..","..","lib","hermes-agent")].find(t=>(0,Uc.existsSync)((0,NI.join)(t,"run_agent.py")))}}catch{}}function IyI(){let I=jQ(Hs());if(I)try{let c=(0,Uc.readFileSync)(I,"utf-8").split(/\r?\n/,1)[0].match(/^#!\s*(.+)$/)?.[1]?.trim().split(/\s+/)[0];return c&&(0,Uc.existsSync)(c)?c:void 0}catch{return}}function UQ(I){for(let l of I){if(!(0,NI.isAbsolute)(l)&&!l.includes("/")&&!l.includes("\\")){let G=jQ(l);if(G)return G;continue}try{if((0,Uc.existsSync)(l))return l}catch{}}}function lyI(I,l=Ld()){return[I,process.env.HERMES_AGENT_ROOT,(0,NI.join)(l,"hermes-agent"),$vI(),process.cwd(),(0,NI.join)(process.cwd(),"hermes-agent"),"/usr/local/lib/hermes-agent","/usr/local/hermes-agent","/opt/hermes/hermes-agent","/opt/hermes-agent"].filter(c=>!!c&&c.trim().length>0).find(c=>(0,Uc.existsSync)((0,NI.join)(c,"run_agent.py")))}function KQ(I={}){let l=I.hermesHome||Ld(),G=lyI(I.agentRoot,l),c=I.python||process.env.HERMES_AGENT_BRIDGE_PYTHON;if(c)return{command:c,argsPrefix:[],agentRoot:G,hermesHome:l};let e=UQ(PvI(G));if(e)return{command:e,argsPrefix:[],agentRoot:G,hermesHome:l};let b=IyI();if(b&&(0,Uc.existsSync)(b))return{command:b,argsPrefix:[],agentRoot:G,hermesHome:l};let d=UQ(_vI(G));if(d){let n=["run"];return G&&n.push("--project",G),n.push("python"),{command:d,argsPrefix:n,agentRoot:G,hermesHome:l}}return{command:UQ([process.env.PYTHON||"",...process.platform==="win32"?["py","python","python3"]:["python3","python"]])||(process.platform==="win32"?"python":"python3"),argsPrefix:[],agentRoot:G,hermesHome:l}}function GyI(){let I=[(0,NI.resolve)(__dirname,"agent-bridge","hermes_bridge.py"),(0,NI.resolve)(__dirname,"services/hermes/agent-bridge/hermes_bridge.py"),(0,NI.resolve)(process.cwd(),"packages/server/src/services/hermes/agent-bridge/hermes_bridge.py")],l=I.find(G=>(0,Uc.existsSync)(G));if(!l)throw new Error(`agent bridge Python script not found. Tried: ${I.join(", ")}`);return l}function RK(I){return I.startsWith("tcp://")}function iK(I){return I.startsWith("ipc://")?"ipc":I.startsWith("tcp://")?"tcp":"unknown"}function Jo(I,l){return I.trim()?(l instanceof Error?l.message:typeof l=="string"?l:void 0)?.replace(/^Error:\s*/,"").trim()||"agent bridge is unreachable":"agent bridge endpoint is not configured"}function cyI(I,l){if(I.reachable)return;let G=I.error?.trim(),c=Jo(I.endpoint,l);return G&&G!==c?`${G}; start failed: ${c}`:G||c}function eyI(){let I=String(process.env.HERMES_AGENT_BRIDGE_KILL_STALE_IPC||"").trim().toLowerCase();return["1","true","yes","on"].includes(I)}async function OQ(I){let l=new URL(I),G=l.hostname||"127.0.0.1",c=Number(l.port);return!Number.isFinite(c)||c<=0?!1:await new Promise(e=>{let b=(0,fQ.createServer)(),d=Z=>{b.removeAllListeners(),e(Z)};b.once("error",()=>d(!1)),b.listen(c,G,()=>{b.close(()=>d(!0))})})}function byI(I){if(!RK(I))return;let l=new URL(I),G=Number(l.port);return Number.isFinite(G)&&G>0?G:void 0}function dyI(I){try{let l=(0,jd.execFileSync)("netstat.exe",["-ano","-p","tcp"],{windowsHide:!0}).toString("utf8"),G=new Set;for(let c of l.split(/\r?\n/)){let e=c.trim().split(/\s+/);if(e.length<5)continue;let[b,d,,Z,n]=e;if(b.toUpperCase()!=="TCP"||Z.toUpperCase()!=="LISTENING"||!d.endsWith(`:${I}`))continue;let t=Number(n);Number.isFinite(t)&&t>0&&t!==process.pid&&G.add(t)}return[...G]}catch{return[]}}async function ZyI(I,l){let G=Date.now()+l;for(;Date.now()<G;){if(await OQ(I))return!0;await new Promise(c=>setTimeout(c,100))}return OQ(I)}async function nyI(I){let l=byI(I);if(!l)return;let G=dyI(l);if(G.length){for(let c of G)try{V.warn("[agent-bridge] killing stale process tree pid=%d on bridge port %d",c,l),(0,jd.execFileSync)("taskkill.exe",["/PID",String(c),"/T","/F"],{encoding:"utf-8",windowsHide:!0})}catch(e){V.warn(e,"[agent-bridge] failed to kill stale bridge process pid=%d",c)}await ZyI(I,3e3)}}async function tyI(I){let l=I.replace(/^ipc:\/\//,"");if(!l)return;let G=l.includes("hermes-agent-bridge-workers"),c=`${l.replace(/\/[^/]+$/,"")}`.replace(/hermes-agent-bridge-workers$/,"hermes-agent-bridge-workers"),e=[l];if(!G){let d=require("path").join(require("path").dirname(l),"hermes-agent-bridge-workers");try{let Z=await import("fs");for(let n of await Z.promises.readdir(d))e.push(require("path").join(d,n))}catch{}}let b=new Set;for(let d of e)try{let Z=(0,jd.execFileSync)("lsof",["-F","p","-U","--",d],{encoding:"utf-8",timeout:5e3,stdio:["pipe","pipe","pipe"]}).trim();for(let n of Z.split(`
|
|
275
|
-
`)){let t=Number(n.replace(/^p/,""));Number.isFinite(t)&&t>0&&t!==process.pid&&b.add(t)}}catch{}if(b.size){for(let d of b)try{V.warn("[agent-bridge] killing stale bridge process pid=%d on IPC socket %s",d,l),process.kill(d,"SIGKILL")}catch(Z){V.warn(Z,"[agent-bridge] failed to kill stale bridge process pid=%d",d)}await new Promise(d=>setTimeout(d,500))}}var MQ=class{endpoint;options;explicitEndpoint;child=null;attached=!1;starting=null;recovery=null;ready=!1;stopping=!1;stopGeneration=0;restartTimer=null;restartAttempts=0;constructor(l={}){this.options=l,this.explicitEndpoint=!!(l.endpoint||process.env.HERMES_AGENT_BRIDGE_ENDPOINT),this.endpoint=l.endpoint||process.env.HERMES_AGENT_BRIDGE_ENDPOINT||xQ}get running(){return this.ready&&(this.attached||!!this.child&&!this.child.killed)}getRuntimeState(){return{endpoint:this.endpoint,running:this.running,ready:this.ready,attached:this.attached,pid:this.child?.pid,starting:!!this.starting,stopping:this.stopping,restartScheduled:!!this.restartTimer,restartAttempts:this.restartAttempts}}transientReadiness(l,G){let c=this.getRuntimeState(),e=c.endpoint,b={endpoint:e,endpointKind:iK(e),status:l,reachable:!1,ready:!1,running:!1,attached:c.attached,starting:c.starting,stopping:c.stopping,restartScheduled:c.restartScheduled,restartAttempts:c.restartAttempts,pid:c.pid};return G?{...b,error:G}:b}async waitForPromiseSettlementWithin(l,G){if(!G||G<=0){try{await l}catch{}return!0}return new Promise(c=>{let e=!1,b=setTimeout(()=>{e||(e=!0,c(!1))},G);l.finally(()=>{e||(e=!0,clearTimeout(b),c(!0))}).catch(()=>{})})}async waitForReadinessWithin(l,G){return!G||G<=0?l:new Promise(c=>{let e=!1,b=setTimeout(()=>{e||(e=!0,c(null))},G);l.then(d=>{e||(e=!0,clearTimeout(b),c(d))},d=>{e||(e=!0,clearTimeout(b),c(this.transientReadiness("recovering",Jo(this.endpoint,d))))})})}async checkReadinessInternal(l={},G=!1){let c=this.getRuntimeState(),e=c.endpoint,b=iK(e),d={endpoint:e,endpointKind:b,status:"unreachable",reachable:!1,ready:c.ready,running:c.running,attached:c.attached,starting:c.starting,stopping:c.stopping,restartScheduled:c.restartScheduled,restartAttempts:c.restartAttempts,pid:c.pid};if(c.stopping)return{...d,status:"stopping",reachable:!1,ready:!1,running:!1};if(!G&&this.recovery)return{...d,status:"recovering",reachable:!1,ready:!1,running:!1};if(c.starting)return{...d,status:"starting",reachable:!1,ready:!1,running:!1};if(c.restartScheduled)return{...d,status:"restarting",reachable:!1,ready:!1,running:!1};if(!e.trim())return{...d,ready:!1,running:!1,error:Jo(e,void 0)};try{return await new PI({endpoint:e,timeoutMs:l.timeoutMs??1e3,connectRetryMs:l.connectRetryMs??0}).ping(),{...d,status:"ready",reachable:!0,ready:!0,running:!0}}catch(Z){return{...d,ready:!1,running:!1,error:Jo(e,Z)}}}async checkReadiness(l={}){return this.checkReadinessInternal(l)}async performManagedRecovery(l,G){let c=this.stopGeneration;if(this.ready=!1,!await this.waitForManagedChildExit(l)){let b=`managed child pid=${l.pid} did not exit after SIGTERM/SIGKILL during recovery`,d=await this.checkReadinessInternal({...G,connectRetryMs:0},!0);return{...d,status:"unreachable",reachable:!1,ready:!1,running:!1,error:d.error?`${b}; ${d.error}`:b}}if(this.stopGeneration!==c||this.stopping)return this.checkReadinessInternal({...G,connectRetryMs:0},!0);try{return await this.start(),await this.checkReadinessInternal(G,!0)}catch(b){let d=await this.checkReadinessInternal({...G,connectRetryMs:0},!0),Z=cyI(d,b);return Z?{...d,error:Z}:d}}async ensureReady(l={}){let G=await this.checkReadiness(l);if(G.reachable||l.recover===!1)return G;if(this.recovery)return await this.waitForReadinessWithin(this.recovery,l.timeoutMs)??this.transientReadiness("recovering");if(G.status==="starting"&&this.starting)return await this.waitForPromiseSettlementWithin(this.starting,l.timeoutMs)?this.checkReadiness(l):this.transientReadiness("starting");if(G.status!=="unreachable")return G;let c=this.child;if(!c||this.attached)return this.ready=!1,G;if(DvI(this.endpoint)){this.ready=!1;let d="managed bridge recovery is disabled for legacy global default endpoint; merge endpoint scoping before enabling recovery";return{...G,error:G.error?`${G.error}; ${d}`:d}}let e;return e=this.performManagedRecovery(c,l).finally(()=>{this.recovery===e&&(this.recovery=null)}),this.recovery=e,await this.waitForReadinessWithin(e,l.timeoutMs)??this.transientReadiness("recovering")}async start(){if(!this.running){if(this.starting)return this.starting;this.stopping=!1,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null),this.starting=this.startProcess();try{await this.starting}finally{this.starting=null}}}async waitForManagedChildExit(l){return new Promise(G=>{let c=Hn("HERMES_AGENT_BRIDGE_RECOVERY_EXIT_TIMEOUT_MS")??SvI,e=Hn("HERMES_AGENT_BRIDGE_RECOVERY_SIGKILL_WAIT_MS")??TvI,b=!1,d=null,Z=null,n=()=>{d&&clearTimeout(d),Z&&clearTimeout(Z),l.off("exit",a)},t=m=>{b||(b=!0,n(),G(m))},a=()=>{this.child===l&&(this.child=null),t(!0)},W=m=>{try{(m==="SIGKILL"||!l.killed)&&l.kill(m)}catch(s){V.warn(s,"[agent-bridge] failed to signal managed child pid=%s signal=%s",l.pid,m)}};if(l.exitCode!=null||l.signalCode!=null){a();return}l.once("exit",a),d=setTimeout(()=>{b||(V.warn("[agent-bridge] managed child pid=%s did not exit after SIGTERM within %dms; sending SIGKILL",l.pid,c),W("SIGKILL"),Z=setTimeout(()=>{b||(V.warn("[agent-bridge] managed child pid=%s still has not exited %dms after SIGKILL; not starting a replacement",l.pid,e),t(!1))},e))},c),W("SIGTERM")})}async startProcess(){if(await this.attachExistingBridge())return;let l=GyI(),G=KQ(this.options);await this.prepareEndpoint();let c=[...G.argsPrefix,l,"--endpoint",this.endpoint],e=G.agentRoot,b=G.hermesHome;e&&c.push("--agent-root",e),b&&c.push("--hermes-home",b);let d=qvI(this.endpoint,b,e);V.info("[agent-bridge] starting: %s %s",G.command,c.join(" "));let Z=(0,jd.spawn)(G.command,c,{env:d,cwd:process.cwd(),stdio:["ignore","ignore","ignore"],detached:process.platform!=="win32",windowsHide:!0});this.child=Z,this.attached=!1,this.ready=!1,Z.once("exit",(n,t)=>{if(!(this.child===Z)){V.warn("[agent-bridge] stale managed child exit ignored code=%s signal=%s pid=%s",n,t,Z.pid);return}let W=this.ready&&!this.stopping&&this.autoRestartEnabled();V.warn("[agent-bridge] exited code=%s signal=%s",n,t),this.ready=!1,this.child=null,W&&this.scheduleRestart(n,t)}),await new Promise((n,t)=>{let a=this.options.startupTimeoutMs??Hn("HERMES_AGENT_BRIDGE_STARTUP_TIMEOUT_MS")??fvI,W=setTimeout(()=>{m(),t(new Error(`agent bridge did not become ready within ${a}ms`))},a),m=()=>{clearTimeout(W),Z.off("exit",Y),Z.off("error",N)},s=()=>{u||(this.ready=!0,this.restartAttempts=0,u=!0,m(),n())},N=p=>{m(),t(p)},Y=(p,h)=>{m(),t(new Error(`agent bridge exited before ready code=${p} signal=${h}`))},u=!1;Z.once("error",N),Z.once("exit",Y),(async()=>{let p=new PI({endpoint:this.endpoint,timeoutMs:1e3,connectRetryMs:0});for(;!u&&!Z.killed;)try{await p.ping(),s();return}catch{await new Promise(h=>setTimeout(h,100))}})().catch(N)}),V.info("[agent-bridge] ready at %s",this.endpoint),process.platform!=="win32"&&Z.unref()}async attachExistingBridge(){try{return await new PI({endpoint:this.endpoint,timeoutMs:Hn("HERMES_AGENT_BRIDGE_ATTACH_TIMEOUT_MS")??5e3,connectRetryMs:Hn("HERMES_AGENT_BRIDGE_ATTACH_RETRY_MS")??5e3}).ping(),this.child=null,this.attached=!0,this.ready=!0,this.restartAttempts=0,V.info("[agent-bridge] attached to existing bridge at %s",this.endpoint),!0}catch(l){return V.debug(l,"[agent-bridge] no reusable bridge at %s",this.endpoint),this.attached=!1,this.ready=!1,!1}}async prepareEndpoint(){!this.explicitEndpoint&&process.platform==="win32"&&RK(this.endpoint)&&(await OQ(this.endpoint)||await nyI(this.endpoint)),this.endpoint.startsWith("ipc://")&&process.platform!=="win32"&&eyI()&&await tyI(this.endpoint),process.env.HERMES_AGENT_BRIDGE_ENDPOINT=this.endpoint}autoRestartEnabled(){let l=String(process.env.HERMES_AGENT_BRIDGE_AUTO_RESTART||"").trim().toLowerCase();return!["0","false","no","off"].includes(l)}scheduleRestart(l,G){if(this.restartTimer||this.stopping)return;this.restartAttempts+=1;let c=Hn("HERMES_AGENT_BRIDGE_RESTART_DELAY_MS")??jvI,e=Math.min(KvI,c*Math.max(1,this.restartAttempts));V.warn("[agent-bridge] broker exited unexpectedly code=%s signal=%s; restarting in %dms (attempt %d)",l,G,e,this.restartAttempts),this.restartTimer=setTimeout(()=>{this.restartTimer=null,!this.stopping&&this.start().catch(b=>{V.warn(b,"[agent-bridge] automatic restart failed"),this.stopping||this.scheduleRestart(null,null)})},e)}async stop(){this.stopGeneration+=1,this.stopping=!0,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null);let l=this.child;if(!l){if(this.attached||this.ready)try{await new PI({endpoint:this.endpoint,timeoutMs:Hn("HERMES_AGENT_BRIDGE_SHUTDOWN_TIMEOUT_MS")??5e3,connectRetryMs:0}).shutdown()}catch(G){V.warn(G,"[agent-bridge] failed to request attached bridge shutdown")}this.ready=!1,this.attached=!1,this.stopping=!1;return}this.ready=!1,this.attached=!1,this.child=null,await new Promise(G=>{let c=setTimeout(()=>{try{l.kill("SIGKILL")}catch{}G()},1e4);l.once("exit",()=>{clearTimeout(c),G()}),l.killed||l.kill("SIGTERM")}),this.stopping=!1}},BQ=null;function Ib(){return BQ||(BQ=new MQ),BQ}async function SQ(){let I=Ib();return await I.start(),I}function fs(I,l,G="[redacted endpoint]"){if(!I)return I;let c=I,e=l?.trim(),b=new Set;if(e){if(b.add(e),e.startsWith("ipc://")){let d=e.slice(6);d&&b.add(d)}if(e.startsWith("tcp://"))try{let d=new URL(e);d.host&&b.add(d.host)}catch{}}for(let d of b)c=c.split(d).join(G);return c.replace(/ipc:\/\/[^\s),;]+/g,G).replace(/(?:[A-Za-z]:)?[^\s),;]*agent-bridge\.sock/g,G)}var ayI="0.6.18",Qn={latestVersion:"",sourceLabel:y.update.sourceLabel,channel:y.update.channel,packageType:y.update.packageType,strategy:y.update.strategy,detectionSource:"npm-registry"},WyI=bs(),Ao=tp(ayI),QK=75,FK=1e3,wn=null,Co=null;function wK(){if(ca(y.update))return!1;let I=(process.env.HERMES_WEB_UI_DISABLE_UPDATE_CHECK||"").trim().toLowerCase();return I==="true"||I==="1"||I==="on"||I==="yes"}async function XK(){if(!(y.update.packageName&&y.update.registry))return null;let I=y.update.packageName||WyI?.name||"hermes-web-ui",l=y.update.registry||"https://registry.npmjs.org",G=y.update.distTag||"latest",c=encodeURIComponent(I),e=`${l}/${c}`,b=await fetch(e,{signal:AbortSignal.timeout(1e4)});if(!b.ok)throw new Error(`Failed to resolve the latest published version from ${l}: HTTP ${b.status}`);let d=await b.json(),Z=d["dist-tags"]?.[G]||d.version||d["dist-tags"]?.latest||"";return Z?{latestVersion:Z,sourceLabel:y.update.sourceLabel,channel:y.update.channel,packageType:y.update.packageType,strategy:y.update.strategy,detectionSource:"npm-registry"}:null}async function HK(){if(ca(y.update))try{let I=RX(y.update)?await TU(y.update):await XK();I?.latestVersion&&(Qn=I,X0(Ao,I.latestVersion)&&console.log(`Update available: ${Ao} \u2192 ${I.latestVersion}`))}catch{if(!RX(y.update))return;try{let I=await XK();I?.latestVersion&&(Qn=I)}catch{}}}function TQ(){!ca(y.update)||wK()||(setTimeout(HK,5e3),setInterval(HK,1800*1e3))}async function myI(){let I=Date.now();return wn&&wn.expiresAt>I||(Co||(Co=syI().finally(()=>{Co=null})),wn)?wn.value:await Promise.race([Co,new Promise(G=>{setTimeout(()=>G({status:"unknown",reachable:!1}),QK)})])}async function syI(){let I;try{let l=Ib();I=typeof l.getRuntimeState=="function"?l.getRuntimeState().endpoint:void 0;let G=await l.checkReadiness({timeoutMs:QK,connectRetryMs:0}),c={status:G.status,reachable:G.reachable,ready:G.ready,running:G.running,attached:G.attached,starting:G.starting,stopping:G.stopping,restart_scheduled:G.restartScheduled,restart_attempts:G.restartAttempts,endpoint_kind:G.endpointKind,pid:G.pid,error:fs(G.error,G.endpoint)};return wn={value:c,expiresAt:Date.now()+FK},c}catch(l){let G={status:"unknown",reachable:!1,error:fs(l instanceof Error?l.message:String(l),I)};return wn={value:G,expiresAt:Date.now()+FK},G}}async function vK(I){let G=(await Eo()).split(`
|
|
275
|
+
`)){let t=Number(n.replace(/^p/,""));Number.isFinite(t)&&t>0&&t!==process.pid&&b.add(t)}}catch{}if(b.size){for(let d of b)try{V.warn("[agent-bridge] killing stale bridge process pid=%d on IPC socket %s",d,l),process.kill(d,"SIGKILL")}catch(Z){V.warn(Z,"[agent-bridge] failed to kill stale bridge process pid=%d",d)}await new Promise(d=>setTimeout(d,500))}}var MQ=class{endpoint;options;explicitEndpoint;child=null;attached=!1;starting=null;recovery=null;ready=!1;stopping=!1;stopGeneration=0;restartTimer=null;restartAttempts=0;constructor(l={}){this.options=l,this.explicitEndpoint=!!(l.endpoint||process.env.HERMES_AGENT_BRIDGE_ENDPOINT),this.endpoint=l.endpoint||process.env.HERMES_AGENT_BRIDGE_ENDPOINT||xQ}get running(){return this.ready&&(this.attached||!!this.child&&!this.child.killed)}getRuntimeState(){return{endpoint:this.endpoint,running:this.running,ready:this.ready,attached:this.attached,pid:this.child?.pid,starting:!!this.starting,stopping:this.stopping,restartScheduled:!!this.restartTimer,restartAttempts:this.restartAttempts}}transientReadiness(l,G){let c=this.getRuntimeState(),e=c.endpoint,b={endpoint:e,endpointKind:iK(e),status:l,reachable:!1,ready:!1,running:!1,attached:c.attached,starting:c.starting,stopping:c.stopping,restartScheduled:c.restartScheduled,restartAttempts:c.restartAttempts,pid:c.pid};return G?{...b,error:G}:b}async waitForPromiseSettlementWithin(l,G){if(!G||G<=0){try{await l}catch{}return!0}return new Promise(c=>{let e=!1,b=setTimeout(()=>{e||(e=!0,c(!1))},G);l.finally(()=>{e||(e=!0,clearTimeout(b),c(!0))}).catch(()=>{})})}async waitForReadinessWithin(l,G){return!G||G<=0?l:new Promise(c=>{let e=!1,b=setTimeout(()=>{e||(e=!0,c(null))},G);l.then(d=>{e||(e=!0,clearTimeout(b),c(d))},d=>{e||(e=!0,clearTimeout(b),c(this.transientReadiness("recovering",Jo(this.endpoint,d))))})})}async checkReadinessInternal(l={},G=!1){let c=this.getRuntimeState(),e=c.endpoint,b=iK(e),d={endpoint:e,endpointKind:b,status:"unreachable",reachable:!1,ready:c.ready,running:c.running,attached:c.attached,starting:c.starting,stopping:c.stopping,restartScheduled:c.restartScheduled,restartAttempts:c.restartAttempts,pid:c.pid};if(c.stopping)return{...d,status:"stopping",reachable:!1,ready:!1,running:!1};if(!G&&this.recovery)return{...d,status:"recovering",reachable:!1,ready:!1,running:!1};if(c.starting)return{...d,status:"starting",reachable:!1,ready:!1,running:!1};if(c.restartScheduled)return{...d,status:"restarting",reachable:!1,ready:!1,running:!1};if(!e.trim())return{...d,ready:!1,running:!1,error:Jo(e,void 0)};try{return await new PI({endpoint:e,timeoutMs:l.timeoutMs??1e3,connectRetryMs:l.connectRetryMs??0}).ping(),{...d,status:"ready",reachable:!0,ready:!0,running:!0}}catch(Z){return{...d,ready:!1,running:!1,error:Jo(e,Z)}}}async checkReadiness(l={}){return this.checkReadinessInternal(l)}async performManagedRecovery(l,G){let c=this.stopGeneration;if(this.ready=!1,!await this.waitForManagedChildExit(l)){let b=`managed child pid=${l.pid} did not exit after SIGTERM/SIGKILL during recovery`,d=await this.checkReadinessInternal({...G,connectRetryMs:0},!0);return{...d,status:"unreachable",reachable:!1,ready:!1,running:!1,error:d.error?`${b}; ${d.error}`:b}}if(this.stopGeneration!==c||this.stopping)return this.checkReadinessInternal({...G,connectRetryMs:0},!0);try{return await this.start(),await this.checkReadinessInternal(G,!0)}catch(b){let d=await this.checkReadinessInternal({...G,connectRetryMs:0},!0),Z=cyI(d,b);return Z?{...d,error:Z}:d}}async ensureReady(l={}){let G=await this.checkReadiness(l);if(G.reachable||l.recover===!1)return G;if(this.recovery)return await this.waitForReadinessWithin(this.recovery,l.timeoutMs)??this.transientReadiness("recovering");if(G.status==="starting"&&this.starting)return await this.waitForPromiseSettlementWithin(this.starting,l.timeoutMs)?this.checkReadiness(l):this.transientReadiness("starting");if(G.status!=="unreachable")return G;let c=this.child;if(!c||this.attached)return this.ready=!1,G;if(DvI(this.endpoint)){this.ready=!1;let d="managed bridge recovery is disabled for legacy global default endpoint; merge endpoint scoping before enabling recovery";return{...G,error:G.error?`${G.error}; ${d}`:d}}let e;return e=this.performManagedRecovery(c,l).finally(()=>{this.recovery===e&&(this.recovery=null)}),this.recovery=e,await this.waitForReadinessWithin(e,l.timeoutMs)??this.transientReadiness("recovering")}async start(){if(!this.running){if(this.starting)return this.starting;this.stopping=!1,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null),this.starting=this.startProcess();try{await this.starting}finally{this.starting=null}}}async waitForManagedChildExit(l){return new Promise(G=>{let c=Hn("HERMES_AGENT_BRIDGE_RECOVERY_EXIT_TIMEOUT_MS")??SvI,e=Hn("HERMES_AGENT_BRIDGE_RECOVERY_SIGKILL_WAIT_MS")??TvI,b=!1,d=null,Z=null,n=()=>{d&&clearTimeout(d),Z&&clearTimeout(Z),l.off("exit",a)},t=m=>{b||(b=!0,n(),G(m))},a=()=>{this.child===l&&(this.child=null),t(!0)},W=m=>{try{(m==="SIGKILL"||!l.killed)&&l.kill(m)}catch(s){V.warn(s,"[agent-bridge] failed to signal managed child pid=%s signal=%s",l.pid,m)}};if(l.exitCode!=null||l.signalCode!=null){a();return}l.once("exit",a),d=setTimeout(()=>{b||(V.warn("[agent-bridge] managed child pid=%s did not exit after SIGTERM within %dms; sending SIGKILL",l.pid,c),W("SIGKILL"),Z=setTimeout(()=>{b||(V.warn("[agent-bridge] managed child pid=%s still has not exited %dms after SIGKILL; not starting a replacement",l.pid,e),t(!1))},e))},c),W("SIGTERM")})}async startProcess(){if(await this.attachExistingBridge())return;let l=GyI(),G=KQ(this.options);await this.prepareEndpoint();let c=[...G.argsPrefix,l,"--endpoint",this.endpoint],e=G.agentRoot,b=G.hermesHome;e&&c.push("--agent-root",e),b&&c.push("--hermes-home",b);let d=qvI(this.endpoint,b,e);V.info("[agent-bridge] starting: %s %s",G.command,c.join(" "));let Z=(0,jd.spawn)(G.command,c,{env:d,cwd:process.cwd(),stdio:["ignore","ignore","ignore"],detached:process.platform!=="win32",windowsHide:!0});this.child=Z,this.attached=!1,this.ready=!1,Z.once("exit",(n,t)=>{if(!(this.child===Z)){V.warn("[agent-bridge] stale managed child exit ignored code=%s signal=%s pid=%s",n,t,Z.pid);return}let W=this.ready&&!this.stopping&&this.autoRestartEnabled();V.warn("[agent-bridge] exited code=%s signal=%s",n,t),this.ready=!1,this.child=null,W&&this.scheduleRestart(n,t)}),await new Promise((n,t)=>{let a=this.options.startupTimeoutMs??Hn("HERMES_AGENT_BRIDGE_STARTUP_TIMEOUT_MS")??fvI,W=setTimeout(()=>{m(),t(new Error(`agent bridge did not become ready within ${a}ms`))},a),m=()=>{clearTimeout(W),Z.off("exit",Y),Z.off("error",N)},s=()=>{u||(this.ready=!0,this.restartAttempts=0,u=!0,m(),n())},N=p=>{m(),t(p)},Y=(p,h)=>{m(),t(new Error(`agent bridge exited before ready code=${p} signal=${h}`))},u=!1;Z.once("error",N),Z.once("exit",Y),(async()=>{let p=new PI({endpoint:this.endpoint,timeoutMs:1e3,connectRetryMs:0});for(;!u&&!Z.killed;)try{await p.ping(),s();return}catch{await new Promise(h=>setTimeout(h,100))}})().catch(N)}),V.info("[agent-bridge] ready at %s",this.endpoint),process.platform!=="win32"&&Z.unref()}async attachExistingBridge(){try{return await new PI({endpoint:this.endpoint,timeoutMs:Hn("HERMES_AGENT_BRIDGE_ATTACH_TIMEOUT_MS")??5e3,connectRetryMs:Hn("HERMES_AGENT_BRIDGE_ATTACH_RETRY_MS")??5e3}).ping(),this.child=null,this.attached=!0,this.ready=!0,this.restartAttempts=0,V.info("[agent-bridge] attached to existing bridge at %s",this.endpoint),!0}catch(l){return V.debug(l,"[agent-bridge] no reusable bridge at %s",this.endpoint),this.attached=!1,this.ready=!1,!1}}async prepareEndpoint(){!this.explicitEndpoint&&process.platform==="win32"&&RK(this.endpoint)&&(await OQ(this.endpoint)||await nyI(this.endpoint)),this.endpoint.startsWith("ipc://")&&process.platform!=="win32"&&eyI()&&await tyI(this.endpoint),process.env.HERMES_AGENT_BRIDGE_ENDPOINT=this.endpoint}autoRestartEnabled(){let l=String(process.env.HERMES_AGENT_BRIDGE_AUTO_RESTART||"").trim().toLowerCase();return!["0","false","no","off"].includes(l)}scheduleRestart(l,G){if(this.restartTimer||this.stopping)return;this.restartAttempts+=1;let c=Hn("HERMES_AGENT_BRIDGE_RESTART_DELAY_MS")??jvI,e=Math.min(KvI,c*Math.max(1,this.restartAttempts));V.warn("[agent-bridge] broker exited unexpectedly code=%s signal=%s; restarting in %dms (attempt %d)",l,G,e,this.restartAttempts),this.restartTimer=setTimeout(()=>{this.restartTimer=null,!this.stopping&&this.start().catch(b=>{V.warn(b,"[agent-bridge] automatic restart failed"),this.stopping||this.scheduleRestart(null,null)})},e)}async stop(){this.stopGeneration+=1,this.stopping=!0,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null);let l=this.child;if(!l){if(this.attached||this.ready)try{await new PI({endpoint:this.endpoint,timeoutMs:Hn("HERMES_AGENT_BRIDGE_SHUTDOWN_TIMEOUT_MS")??5e3,connectRetryMs:0}).shutdown()}catch(G){V.warn(G,"[agent-bridge] failed to request attached bridge shutdown")}this.ready=!1,this.attached=!1,this.stopping=!1;return}this.ready=!1,this.attached=!1,this.child=null,await new Promise(G=>{let c=setTimeout(()=>{try{l.kill("SIGKILL")}catch{}G()},1e4);l.once("exit",()=>{clearTimeout(c),G()}),l.killed||l.kill("SIGTERM")}),this.stopping=!1}},BQ=null;function Ib(){return BQ||(BQ=new MQ),BQ}async function SQ(){let I=Ib();return await I.start(),I}function fs(I,l,G="[redacted endpoint]"){if(!I)return I;let c=I,e=l?.trim(),b=new Set;if(e){if(b.add(e),e.startsWith("ipc://")){let d=e.slice(6);d&&b.add(d)}if(e.startsWith("tcp://"))try{let d=new URL(e);d.host&&b.add(d.host)}catch{}}for(let d of b)c=c.split(d).join(G);return c.replace(/ipc:\/\/[^\s),;]+/g,G).replace(/(?:[A-Za-z]:)?[^\s),;]*agent-bridge\.sock/g,G)}var ayI="0.6.19",Qn={latestVersion:"",sourceLabel:y.update.sourceLabel,channel:y.update.channel,packageType:y.update.packageType,strategy:y.update.strategy,detectionSource:"npm-registry"},WyI=bs(),Ao=tp(ayI),QK=75,FK=1e3,wn=null,Co=null;function wK(){if(ca(y.update))return!1;let I=(process.env.HERMES_WEB_UI_DISABLE_UPDATE_CHECK||"").trim().toLowerCase();return I==="true"||I==="1"||I==="on"||I==="yes"}async function XK(){if(!(y.update.packageName&&y.update.registry))return null;let I=y.update.packageName||WyI?.name||"hermes-web-ui",l=y.update.registry||"https://registry.npmjs.org",G=y.update.distTag||"latest",c=encodeURIComponent(I),e=`${l}/${c}`,b=await fetch(e,{signal:AbortSignal.timeout(1e4)});if(!b.ok)throw new Error(`Failed to resolve the latest published version from ${l}: HTTP ${b.status}`);let d=await b.json(),Z=d["dist-tags"]?.[G]||d.version||d["dist-tags"]?.latest||"";return Z?{latestVersion:Z,sourceLabel:y.update.sourceLabel,channel:y.update.channel,packageType:y.update.packageType,strategy:y.update.strategy,detectionSource:"npm-registry"}:null}async function HK(){if(ca(y.update))try{let I=RX(y.update)?await TU(y.update):await XK();I?.latestVersion&&(Qn=I,X0(Ao,I.latestVersion)&&console.log(`Update available: ${Ao} \u2192 ${I.latestVersion}`))}catch{if(!RX(y.update))return;try{let I=await XK();I?.latestVersion&&(Qn=I)}catch{}}}function TQ(){!ca(y.update)||wK()||(setTimeout(HK,5e3),setInterval(HK,1800*1e3))}async function myI(){let I=Date.now();return wn&&wn.expiresAt>I||(Co||(Co=syI().finally(()=>{Co=null})),wn)?wn.value:await Promise.race([Co,new Promise(G=>{setTimeout(()=>G({status:"unknown",reachable:!1}),QK)})])}async function syI(){let I;try{let l=Ib();I=typeof l.getRuntimeState=="function"?l.getRuntimeState().endpoint:void 0;let G=await l.checkReadiness({timeoutMs:QK,connectRetryMs:0}),c={status:G.status,reachable:G.reachable,ready:G.ready,running:G.running,attached:G.attached,starting:G.starting,stopping:G.stopping,restart_scheduled:G.restartScheduled,restart_attempts:G.restartAttempts,endpoint_kind:G.endpointKind,pid:G.pid,error:fs(G.error,G.endpoint)};return wn={value:c,expiresAt:Date.now()+FK},c}catch(l){let G={status:"unknown",reachable:!1,error:fs(l instanceof Error?l.message:String(l),I)};return wn={value:G,expiresAt:Date.now()+FK},G}}async function vK(I){let G=(await Eo()).split(`
|
|
276
276
|
`)[0].replace("Hermes Agent ","")||"",c=Lu(y.update),e=ca(y.update),b=wK(),d=await myI();I.body={status:"ok",platform:"hermes-agent",version:G,gateway:"running",webui_version:Ao,webui_latest:b?"":Qn.latestVersion,webui_update_enabled:c,webui_update_source_label:e?Qn.sourceLabel||y.update.sourceLabel:"",webui_update_channel:e?Qn.channel||y.update.channel:"",webui_update_strategy:e?y.update.strategy:"",webui_update_package_type:e?Qn.packageType||y.update.packageType:"",webui_update_available:b?!1:X0(Ao,Qn.latestVersion),node_version:process.versions.node,agent_bridge:d}}var DQ=new B;DQ.get("/health",vK);GI();async function yK(I){let l=I.request.body;if(!l||!l.event){I.status=400,I.body={error:"Missing event field"};return}V.info("Received webhook event: %s",l.event),I.body={ok:!0}}var qQ=new B;qQ.post("/webhook",yK);var JK=require("crypto"),ko=require("fs/promises"),CK=require("path");VI();var Lo=require("path");CI();ac();function hyI(I){let l=(I||"default").trim()||"default";if(l.includes("/")||l.includes("\\")||l.includes(".."))throw Object.assign(new Error("Invalid profile name"),{code:"invalid_profile"});return l}function EK(I){return(0,Lo.resolve)((0,Lo.join)(y.uploadDir,hyI(I)))}var gK=50*1024*1024;function uyI(I){return I.state?.profile?.name||cI()||"default"}async function AK(I){let l=I.get("content-type")||"";if(!l.startsWith("multipart/form-data")){I.status=400,I.body={error:"Expected multipart/form-data"};return}let G="--"+l.split("boundary=")[1];if(!G||G==="--undefined"){I.status=400,I.body={error:"Missing boundary"};return}let c=[],e=0;for await(let a of I.req){if(e+=a.length,e>gK){I.status=413,I.body={error:`File too large (max ${gK/1024/1024}MB)`};return}c.push(a)}let b=Buffer.concat(c),d=Buffer.from(G),Z=pyI(b,d),n=[],t=EK(uyI(I));await(0,ko.mkdir)(t,{recursive:!0});for(let a of Z){let W=a.indexOf(Buffer.from(`\r
|
|
277
277
|
\r
|
|
278
278
|
`));if(W===-1)continue;let s=a.subarray(0,W).toString("utf-8"),N=a.subarray(W+4,a.length-2),Y="",u=s.match(/filename\*=UTF-8''(.+)/i);if(u)Y=decodeURIComponent(u[1]);else{let r=s.match(/filename="([^"]+)"/);if(!r)continue;Y=r[1]}let o=Y.includes(".")?"."+Y.split(".").pop():"",p=(0,JK.randomBytes)(8).toString("hex")+o,h=(0,CK.join)(t,p);await(0,ko.writeFile)(h,N),n.push({name:Y,path:h})}I.body={files:n}}function pyI(I,l){let G=[],c=0;for(;;){let e=I.indexOf(l,c);if(e===-1)break;c>0&&G.push(I.subarray(c+2,e)),c=e+l.length}return G}var PQ=new B;PQ.post("/upload",AK);var pe=new B;pe.post("/api/hermes/update",EB);pe.get("/api/hermes/update/status",vB);pe.post("/api/hermes/update/status/clear-stale",yB);pe.get("/api/hermes/update/preview",gB);pe.get("/api/hermes/update/preview/tags",JB);pe.post("/api/hermes/update/preview/prepare",CB);pe.post("/api/hermes/update/preview/install",AB);pe.post("/api/hermes/update/preview/start",LB);pe.post("/api/hermes/update/preview/stop",kB);VI();async function kK(I){I.body={hasPasswordLogin:!0,hasUsers:Wo()>0}}async function xK(I){let l=I.state.user?.id,G=l?Lc(l):null;if(!G){I.status=404,I.body={error:"User not found"};return}I.body={user:{id:G.id,username:G.username,role:G.role,status:G.status,created_at:G.created_at,updated_at:G.updated_at,last_login_at:G.last_login_at,avatar:G.avatar||"",requiresCredentialChange:process.env.HERMES_DESKTOP==="true"?!1:G.username===Ls&&ks(to,G.password_hash)}}}var _Q=500*1024;function LK(I){if(!I||typeof I!="object")return{ok:!1,error:"Invalid avatar payload"};let l=I,G=l.type;if(G!=="image"&&G!=="default")return{ok:!1,error:'Avatar type must be "image" or "default"'};if(G==="image"){if(typeof l.dataUrl!="string"||!l.dataUrl.startsWith("data:image/"))return{ok:!1,error:"Image avatar must include a dataUrl"};if(l.dataUrl.length>_Q)return{ok:!1,error:`Avatar image is too large (max ${_Q} bytes)`}}return l.seed!=null&&typeof l.seed!="string"?{ok:!1,error:"Avatar seed must be a string"}:{ok:!0,json:JSON.stringify(I)}}async function zK(I){let l=I.state.user?.id;if(!l){I.status=401,I.body={error:"Unauthorized"};return}I.body={avatar:ga(l)}}async function UK(I){let l=I.state.user?.id;if(!l){I.status=401,I.body={error:"Unauthorized"};return}let G=I.request.body,c=G&&Object.prototype.hasOwnProperty.call(G,"avatar")?G.avatar:G;if(typeof c=="string"){if(c.length>_Q*2){I.status=400,I.body={error:"Avatar string is too large"};return}try{let d=JSON.parse(c),Z=LK(d);if(!Z.ok){I.status=400,I.body={error:Z.error};return}if(!IQ(l,c)){I.status=500,I.body={error:"Failed to save avatar"};return}I.body={success:!0,avatar:c};return}catch{I.status=400,I.body={error:"Avatar string is not valid JSON"};return}}let e=LK(c);if(!e.ok){I.status=400,I.body={error:e.error};return}if(!IQ(l,e.json)){I.status=500,I.body={error:"Failed to save avatar"};return}I.body={success:!0,avatar:e.json}}async function BK(I){let{username:l,password:G}=I.request.body;if(!l||!G){I.status=400,I.body={error:"Username and password are required"};return}let c=QX(I),e=dx(c);if(!e.allowed){I.status=e.status,I.body={error:"Too many login attempts, please try again later"};return}let b=Wo(),d=b===0?gf(l,G):Ne(l);if(!d||d.status!=="active"||b>0&&!ks(G,d.password_hash)){Zx(c),I.status=401,I.body={error:"Invalid username or password"};return}let Z;try{Z=await kf(d)}catch(n){I.status=500,I.body={error:n?.message||"Failed to issue login token"};return}nx(c),I.body={token:Z}}async function OK(I){I.status=400,I.body={error:"Password login is managed by user accounts"}}async function MK(I){let{currentPassword:l,newPassword:G}=I.request.body;if(!l||!G){I.status=400,I.body={error:"Current password and new password are required"};return}if(G.length<6){I.status=400,I.body={error:"New password must be at least 6 characters"};return}let c=I.state.user?.id,e=c?Lc(c):null;if(!e||!ks(l,e.password_hash)){I.status=400,I.body={error:"Current password is incorrect"};return}Hf(e.id,G),I.body={success:!0}}async function fK(I){let{currentPassword:l,newUsername:G}=I.request.body;if(!l||!G){I.status=400,I.body={error:"Current password and new username are required"};return}if(G.length<2){I.status=400,I.body={error:"Username must be at least 2 characters"};return}let c=I.state.user?.id,e=c?Lc(c):null;if(!e||!ks(l,e.password_hash)){I.status=400,I.body={error:"Current password is incorrect"};return}let b=Ne(G);if(b&&b.id!==e.id){I.status=409,I.body={error:"Username already exists"};return}Qf(e.id,G),I.body={success:!0}}async function jK(I){I.status=400,I.body={error:"Password login cannot be removed for user accounts"}}function KK(I){return I==="super_admin"||I==="admin"?I:null}function SK(I){return I==="active"||I==="disabled"?I:null}function TK(I){return Array.isArray(I)?[...new Set(I.map(l=>String(l||"").trim()).filter(Boolean))]:[]}function DK(I){let l=new Set(DI());return I.find(c=>!l.has(c))||null}async function qK(I){I.body={users:xs(),profiles:DI()}}async function PK(I){let l=I.request.body,G=String(l.username||"").trim(),c=String(l.password||""),e=KK(l.role||"admin"),b=SK(l.status||"active"),d=TK(l.profiles);if(G.length<2){I.status=400,I.body={error:"Username must be at least 2 characters"};return}if(c.length<6){I.status=400,I.body={error:"Password must be at least 6 characters"};return}if(!e||!b){I.status=400,I.body={error:"Invalid role or status"};return}if(Ne(G)){I.status=409,I.body={error:"Username already exists"};return}let Z=DK(d);if(Z){I.status=400,I.body={error:`Profile "${Z}" does not exist`};return}let n=wf({username:G,password:c,role:e,status:b,profiles:e==="super_admin"?[]:d,defaultProfile:l.defaultProfile});I.status=201,I.body={user:n,users:xs()}}async function _K(I){let l=Number(I.params.id),G=Number.isInteger(l)?Lc(l):null;if(!G){I.status=404,I.body={error:"User not found"};return}let c=I.request.body,e=c.username==null?void 0:String(c.username).trim(),b=c.password==null?void 0:String(c.password),d=c.role==null?void 0:KK(c.role),Z=c.status==null?void 0:SK(c.status),n=c.profiles==null?void 0:TK(c.profiles);if(e!==void 0&&e.length<2){I.status=400,I.body={error:"Username must be at least 2 characters"};return}if(b!==void 0&&b.length>0&&b.length<6){I.status=400,I.body={error:"Password must be at least 6 characters"};return}if(c.role!=null&&!d||c.status!=null&&!Z){I.status=400,I.body={error:"Invalid role or status"};return}if(e&&e!==G.username){let m=Ne(e);if(m&&m.id!==G.id){I.status=409,I.body={error:"Username already exists"};return}}let t=d||G.role,a=Z||G.status,W=I.state.user?.id;if(G.id===W&&a!=="active"){I.status=400,I.body={error:"You cannot disable your own account"};return}if(G.role==="super_admin"&&G.status==="active"&&(t!=="super_admin"||a!=="active")&&$H(G.id)===0){I.status=400,I.body={error:"At least one active super administrator is required"};return}if(n){let m=DK(n);if(m){I.status=400,I.body={error:`Profile "${m}" does not exist`};return}}vf({userId:G.id,username:e,password:b||void 0,role:d||void 0,status:Z||void 0,profiles:t==="super_admin"?[]:n,defaultProfile:c.defaultProfile}),I.body={user:Lc(G.id),users:xs()}}async function $K(I){let l=Number(I.params.id),G=Number.isInteger(l)?Lc(l):null;if(!G){I.status=404,I.body={error:"User not found"};return}if(I.state.user?.id===G.id){I.status=400,I.body={error:"You cannot delete your own account"};return}if(G.role==="super_admin"&&G.status==="active"&&$H(G.id)===0){I.status=400,I.body={error:"At least one active super administrator is required"};return}yf(G.id),I.body={success:!0,users:xs()}}async function IS(I){let l=vX();I.body={locks:l}}async function lS(I){let l=I.query.ip;if(l){if(!tx(l)){I.status=404,I.body={error:"IP not locked"};return}I.body={success:!0};return}let G=ax();I.body={success:!0,count:G}}var xo=new B;xo.get("/api/auth/status",kK);xo.post("/api/auth/login",BK);var CG=new B;CG.post("/api/auth/setup",OK);CG.get("/api/auth/me",xK);CG.post("/api/auth/change-password",MK);CG.post("/api/auth/change-username",fK);CG.get("/api/auth/avatar",zK);CG.put("/api/auth/avatar",UK);CG.delete("/api/auth/password",jK);CG.get("/api/auth/users",nG,qK);CG.post("/api/auth/users",nG,PK);CG.put("/api/auth/users/:id",nG,_K);CG.delete("/api/auth/users/:id",nG,$K);CG.get("/api/auth/locked-ips",IS);CG.delete("/api/auth/locked-ips",lS);wG();me();var js=class extends Error{constructor(){super("Duplicate pairing request"),this.name="DuplicateDeviceRequestError"}};function VyI(I){if(typeof I=="number")return I;if(!I)return Date.now();let l=Date.parse(I);return Number.isNaN(l)?Date.now():l}function iyI(I){return I==="pending"||I==="approved"||I==="rejected"||I==="blocked"?I:"none"}function RyI(I){return I==="pending"||I==="approved"||I==="rejected"||I==="blocked"?I:"none"}function Ks(I){let l={type:"",platform:"",release:"",arch:""};try{l=JSON.parse(String(I.os_json||"{}"))}catch{}return{id:String(I.id),device_id:String(I.id),inbound_status:iyI(I.inbound_status||I.status),outbound_status:RyI(I.outbound_status),device_public_key:String(I.device_public_key||""),computer_name:String(I.computer_name||""),endpoint_kind:I.endpoint_kind==="web"||I.endpoint_kind==="desktop"?I.endpoint_kind:"custom",ip:String(I.ip||""),http_port:Number(I.http_port||0),url:String(I.url||""),os:l,hermes_agent_version:String(I.hermes_agent_version||""),hermes_web_ui_version:String(I.hermes_web_ui_version||""),response_ms:Number(I.response_ms||0),requested_at:Number(I.requested_at||0),decided_at:I.decided_at==null?null:Number(I.decided_at),outbound_requested_at:Number(I.outbound_requested_at||0),outbound_decided_at:I.outbound_decided_at==null?null:Number(I.outbound_decided_at),inbound_history_deleted_at:I.inbound_history_deleted_at==null?null:Number(I.inbound_history_deleted_at),last_seen_at:Number(I.last_seen_at||0),updated_at:Number(I.updated_at||0)}}function zo(I,l,G){return{id:I.id,status:l?.inbound_status||"none",inbound_status:l?.inbound_status||"none",outbound_status:l?.outbound_status||"none",device_public_key:I.device_public_key,computer_name:I.computer_name,endpoint_kind:I.endpoint_kind,ip:I.ip,http_port:I.http_port,url:I.url,os_json:JSON.stringify(I.os||{}),hermes_agent_version:I.hermes_agent_version,hermes_web_ui_version:I.hermes_web_ui_version,response_ms:I.response_ms,requested_at:l?.requested_at||0,decided_at:l?.decided_at||null,outbound_requested_at:l?.outbound_requested_at||0,outbound_decided_at:l?.outbound_decided_at||null,inbound_history_deleted_at:l?.inbound_history_deleted_at||null,last_seen_at:VyI(I.last_seen_at),updated_at:G}}function Ss(I){let l=O();return l?(l.prepare(`
|
|
@@ -304,7 +304,7 @@ const isVersionPreview = import.meta.env.VITE_HERMES_PREVIEW === '1';`)),l=l.rep
|
|
|
304
304
|
inbound_history_deleted_at = excluded.inbound_history_deleted_at,
|
|
305
305
|
last_seen_at = excluded.last_seen_at,
|
|
306
306
|
updated_at = excluded.updated_at
|
|
307
|
-
`).run(I.id,I.status||I.inbound_status||"none",I.inbound_status||"none",I.outbound_status||"none",I.computer_name,I.endpoint_kind,I.ip,I.http_port,I.url,I.os_json,I.hermes_agent_version,I.hermes_web_ui_version,I.response_ms,I.device_public_key,I.requested_at,I.decided_at,I.outbound_requested_at||0,I.outbound_decided_at||null,I.inbound_history_deleted_at||null,I.last_seen_at,I.updated_at),Bc(I.id)):(dp(nc,I.id,I),Ks(I))}function Uo(){FyI();let I=O();return I?I.prepare(`SELECT * FROM ${nc} ORDER BY updated_at DESC`).all().map(Ks):Object.values(cs(nc)).map(Ks).sort((G,c)=>c.updated_at-G.updated_at)}function Bc(I){let l=O();if(!l){let c=bp(nc,I);return c?Ks(c):null}let G=l.prepare(`SELECT * FROM ${nc} WHERE id = ?`).get(I);return G?Ks(G):null}function FyI(){let I=O();if(!I){let G=cs(nc),c=0;for(let[e,b]of Object.entries(G))b.inbound_history_deleted_at!=null&&(es(nc,e),c+=1);return c}let l=I.prepare(`DELETE FROM ${nc} WHERE inbound_history_deleted_at IS NOT NULL`).run();return Number(l.changes)}function GS(){return Uo().filter(I=>I.inbound_status!=="none"&&I.inbound_history_deleted_at==null).sort((I,l)=>(l.requested_at||l.updated_at)-(I.requested_at||I.updated_at))}function cS(I){return Ss(zo(I,Bc(I.id),Date.now()))}function eS(I){let l=Date.now(),G=Bc(I.id),c=zo(I,G,l);if(G?.inbound_status==="pending")throw new js;return G?.inbound_status==="blocked"||G?.inbound_status==="approved"||(c.status="pending",c.inbound_status="pending",c.requested_at=l,c.decided_at=null,c.inbound_history_deleted_at=null),Ss(c)}function bS(I,l,G){let c=G?cS(G):Bc(I);if(!c)throw new Error("Device not found");let e=Date.now(),b=zo(c,c,e);return b.status=l,b.inbound_status=l,b.decided_at=l==="pending"||l==="none"?null:e,l==="pending"&&!b.requested_at&&(b.requested_at=e),l==="pending"&&(b.inbound_history_deleted_at=null),Ss(b)}function Bo(I,l,G){let c=cS(G),e=Date.now(),b=zo(c,c,e);return b.outbound_status=l,l==="pending"?(b.outbound_requested_at=e,b.outbound_decided_at=null):b.outbound_decided_at=e,Ss(b)}function dS(I){if(!Bc(I))return!1;let G=O();return G?G.prepare(`DELETE FROM ${nc} WHERE id = ?`).run(I).changes>0:(es(nc,I),!0)}var Gw=C(require("dgram")),tS=require("os");CI();GI();var lb=require("os"),Kd=require("crypto");var Ua=require("fs/promises"),Oo=require("path");CI();Xn();var $Q=(0,Oo.resolve)(y.appHome,"device-identity.json"),Iw=null;function Mo(){return"0.6.
|
|
307
|
+
`).run(I.id,I.status||I.inbound_status||"none",I.inbound_status||"none",I.outbound_status||"none",I.computer_name,I.endpoint_kind,I.ip,I.http_port,I.url,I.os_json,I.hermes_agent_version,I.hermes_web_ui_version,I.response_ms,I.device_public_key,I.requested_at,I.decided_at,I.outbound_requested_at||0,I.outbound_decided_at||null,I.inbound_history_deleted_at||null,I.last_seen_at,I.updated_at),Bc(I.id)):(dp(nc,I.id,I),Ks(I))}function Uo(){FyI();let I=O();return I?I.prepare(`SELECT * FROM ${nc} ORDER BY updated_at DESC`).all().map(Ks):Object.values(cs(nc)).map(Ks).sort((G,c)=>c.updated_at-G.updated_at)}function Bc(I){let l=O();if(!l){let c=bp(nc,I);return c?Ks(c):null}let G=l.prepare(`SELECT * FROM ${nc} WHERE id = ?`).get(I);return G?Ks(G):null}function FyI(){let I=O();if(!I){let G=cs(nc),c=0;for(let[e,b]of Object.entries(G))b.inbound_history_deleted_at!=null&&(es(nc,e),c+=1);return c}let l=I.prepare(`DELETE FROM ${nc} WHERE inbound_history_deleted_at IS NOT NULL`).run();return Number(l.changes)}function GS(){return Uo().filter(I=>I.inbound_status!=="none"&&I.inbound_history_deleted_at==null).sort((I,l)=>(l.requested_at||l.updated_at)-(I.requested_at||I.updated_at))}function cS(I){return Ss(zo(I,Bc(I.id),Date.now()))}function eS(I){let l=Date.now(),G=Bc(I.id),c=zo(I,G,l);if(G?.inbound_status==="pending")throw new js;return G?.inbound_status==="blocked"||G?.inbound_status==="approved"||(c.status="pending",c.inbound_status="pending",c.requested_at=l,c.decided_at=null,c.inbound_history_deleted_at=null),Ss(c)}function bS(I,l,G){let c=G?cS(G):Bc(I);if(!c)throw new Error("Device not found");let e=Date.now(),b=zo(c,c,e);return b.status=l,b.inbound_status=l,b.decided_at=l==="pending"||l==="none"?null:e,l==="pending"&&!b.requested_at&&(b.requested_at=e),l==="pending"&&(b.inbound_history_deleted_at=null),Ss(b)}function Bo(I,l,G){let c=cS(G),e=Date.now(),b=zo(c,c,e);return b.outbound_status=l,l==="pending"?(b.outbound_requested_at=e,b.outbound_decided_at=null):b.outbound_decided_at=e,Ss(b)}function dS(I){if(!Bc(I))return!1;let G=O();return G?G.prepare(`DELETE FROM ${nc} WHERE id = ?`).run(I).changes>0:(es(nc,I),!0)}var Gw=C(require("dgram")),tS=require("os");CI();GI();var lb=require("os"),Kd=require("crypto");var Ua=require("fs/promises"),Oo=require("path");CI();Xn();var $Q=(0,Oo.resolve)(y.appHome,"device-identity.json"),Iw=null;function Mo(){return"0.6.19"}function XyI(I){return I.split(`
|
|
308
308
|
`)[0]?.replace(/^Hermes Agent\s+/,"").trim()||""}function HyI(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 Ba(I){return`hwui_${(0,Kd.createHash)("sha256").update(I).digest("base64url").slice(0,32)}`}async function QyI(){try{let G=JSON.parse(await(0,Ua.readFile)($Q,"utf-8"));if(HyI(G))return G}catch{}let I=(0,Kd.generateKeyPairSync)("ed25519",{publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem"}}),l={device_id:Ba(I.publicKey),device_public_key:I.publicKey,device_private_key:I.privateKey};return await(0,Ua.mkdir)((0,Oo.dirname)($Q),{recursive:!0}),await(0,Ua.writeFile)($Q,JSON.stringify(l,null,2),{encoding:"utf-8",mode:384}),l}function ZS(){return Iw||(Iw=QyI()),Iw}function nS(I){return`${I.device_id}.${I.nonce}.${I.timestamp}`}async function Ts(I,l){let G=await ZS();return(0,Kd.sign)(null,Buffer.from(nS({device_id:G.device_id,nonce:I,timestamp:l})),G.device_private_key).toString("base64url")}function Ds(I){if(Ba(I.device_public_key)!==I.device_id)return!1;try{return(0,Kd.verify)(null,Buffer.from(nS(I)),I.device_public_key,Buffer.from(I.signature,"base64url"))}catch{return!1}}async function Sd(){let I=XyI(await Eo()),l=await ZS();return{device_id:l.device_id,device_public_key:l.device_public_key,computer_name:(0,lb.hostname)(),os:{type:(0,lb.type)(),platform:(0,lb.platform)(),release:(0,lb.release)(),arch:(0,lb.arch)()},hermes_agent_version:I,hermes_web_ui_version:Mo()}}var jo=1,wyI=4e4,vyI=[8648,8748],yyI=1e3,lw=null,Oa={scanning:!1,last_scanned_at:null,devices:[]},qs=null,fo=null;function EyI(I){let l=String(process.env[I]||"").trim().toLowerCase();return["0","false","no","off"].includes(l)}function aS(){return!EyI("HERMES_LAN_DISCOVERY_ENABLED")}function gyI(I){return String(I||"").split(/[\s,]+/).map(l=>Number.parseInt(l,10)).filter(l=>Number.isInteger(l)&&l>0&&l<=65535)}function WS(I){let l=wyI+I;if(l>65535)throw new Error(`HTTP port ${I} cannot be mapped to a UDP discovery port`);return l}function vn(I){return I===8648?"web":I===8748?"desktop":"custom"}function JyI(I=y.port){let l=gyI(process.env.HERMES_LAN_DISCOVERY_HTTP_PORTS);return[...new Set([...l.length?l:vyI,I])]}function Ma(I){let l=I.split(".").map(G=>Number.parseInt(G,10));return l.length!==4||l.some(G=>!Number.isInteger(G)||G<0||G>255)?null:(l[0]<<24>>>0)+(l[1]<<16)+(l[2]<<8)+l[3]>>>0}function CyI(I){return[I>>>24&255,I>>>16&255,I>>>8&255,I&255].join(".")}function mS(I){let l=Ma(I);if(l===null)return!1;let G=l>>>24&255,c=l>>>16&255;return G===10||G===127||G===172&&c>=16&&c<=31||G===192&&c===168||G===169&&c===254}function cw(){try{return Object.values((0,tS.networkInterfaces)()).flat().filter(I=>I&&I.family==="IPv4"&&!I.internal&&I.address&&I.netmask).map(I=>({address:I.address,netmask:I.netmask}))}catch{return[]}}function AyI(){return new Set(["127.0.0.1",...cw().map(I=>I.address)])}function LyI(I,l){let G=Ma(I),c=Ma(l);return G===null||c===null?null:CyI((G|~c>>>0)>>>0)}function kyI(I){let l=Ma(I),G=cw();if(l!==null)for(let c of G){let e=Ma(c.address),b=Ma(c.netmask);if(e!==null&&b!==null&&(e&b)===(l&b))return c.address}return G[0]?.address||"127.0.0.1"}function xyI(){let I=new Set(["255.255.255.255"]);for(let l of cw()){let G=LyI(l.address,l.netmask);G&&I.add(G)}return[...I]}async function zyI(I){let l=Date.now();if(fo&&fo.expiresAt>l)return fo.value;let G=await I();return fo={value:G,expiresAt:l+6e4},G}function sS(I){try{return JSON.parse(I.toString("utf8"))}catch{return null}}async function UyI(I,l,G,c){let e=await zyI(c),b=kyI(l);return{type:"hermes.announce",version:jo,request_id:I.request_id,http_port:G,endpoint_kind:vn(G),url:`http://${b}:${G}`,...e}}function NS(I={}){if(!aS())return null;if(lw)return lw;let l=I.httpPort||y.port,G=WS(l),c=I.getSystemInfo||Sd,e=Gw.default.createSocket("udp4");return e.on("message",(b,d)=>{if(!mS(d.address))return;let Z=sS(b);!Z||Z.type!=="hermes.discover"||Z.version!==jo||UyI(Z,d.address,l,c).then(n=>{let t=Buffer.from(JSON.stringify(n));e.send(t,d.port,d.address)}).catch(n=>V.warn(n,"[lan-discovery] failed to build discovery response"))}),e.on("error",b=>{V.warn(b,"[lan-discovery] UDP responder error")}),e.bind(G,"0.0.0.0",()=>{e.setBroadcast(!0),e.unref(),V.info("[lan-discovery] responder listening on udp://0.0.0.0:%d for http port %d",G,l)}),lw=e,e}function ByI(I,l,G,c){if(!I||I.type!=="hermes.announce"||I.version!==jo)return null;let e=Number(I.http_port);if(!Number.isInteger(e)||e<=0||e>65535)return null;let b=typeof I.device_id=="string"&&I.device_id?I.device_id:"",d=typeof I.device_public_key=="string"?I.device_public_key:"";if(!b||!d||Ba(d)!==b)return null;let Z=I.endpoint_kind==="web"||I.endpoint_kind==="desktop"||I.endpoint_kind==="custom"?I.endpoint_kind:vn(e),n=`http://${l}:${e}`;return{id:b,device_id:b,device_public_key:d,ip:l,http_port:e,endpoint_kind:Z,url:n,computer_name:String(I.computer_name||""),os:{type:String(I.os?.type||""),platform:String(I.os?.platform||""),release:String(I.os?.release||""),arch:String(I.os?.arch||"")},hermes_agent_version:String(I.hermes_agent_version||""),hermes_web_ui_version:String(I.hermes_web_ui_version||""),response_ms:G,last_seen_at:c}}function OyI(I,l){return l.has(I.ip)}function Ps(){return{scanning:Oa.scanning,last_scanned_at:Oa.last_scanned_at,devices:[...Oa.devices]}}async function Ko(I={}){if(!aS())return Ps();if(qs)return qs;let l=Math.max(100,Math.min(I.timeoutMs||yyI,5e3)),G=[...new Set(I.httpPorts||JyI())],c=I.targetAddresses||xyI(),e=AyI(),b=`${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;Oa={...Oa,scanning:!0};let d=Date.now();return qs=new Promise(Z=>{let n=Gw.default.createSocket("udp4"),t=new Map;n.on("message",(a,W)=>{if(!mS(W.address))return;let m=sS(a);if(m?.request_id&&m.request_id!==b)return;let s=ByI(m,W.address,Date.now()-d,new Date().toISOString());s&&!I.includeSelf&&OyI(s,e)||s&&t.set(s.id,s)}),n.on("error",a=>{V.warn(a,"[lan-discovery] UDP scan error")}),n.bind(0,"0.0.0.0",()=>{n.setBroadcast(!0);let a=Buffer.from(JSON.stringify({type:"hermes.discover",version:jo,request_id:b}));for(let W of G){let m;try{m=WS(W)}catch{continue}for(let s of c)n.send(a,m,s)}}),setTimeout(()=>{try{n.close()}catch{}Oa={scanning:!1,last_scanned_at:new Date().toISOString(),devices:[...t.values()].sort((a,W)=>a.id.localeCompare(W.id))},Z(Ps())},l)}).finally(()=>{qs=null}),qs}var yn=require("crypto"),Do=require("fs"),_s=require("fs"),oS=require("os"),qo=require("path"),rS=require("child_process");VI();GI();CI();var nw="/api/devices/peer-socket",VS=300*1e3,ew=64*1024,MyI=5,fyI=1e3,jyI=3e4,YS=5*1024*1024,KyI=3e4,hS=tw("HERMES_LAN_PEER_MAX_TERMINALS",4,1,32),So=tw("HERMES_LAN_PEER_TERMINAL_IDLE_MS",600*1e3,3e4,1440*60*1e3),SyI=tw("HERMES_LAN_PEER_TERMINAL_BUFFER_BYTES",1024*1024,64*1024,16*1024*1024),dw=null;try{dw=require("node-pty")}catch(I){V.warn(I,"[lan-peer] node-pty failed to load; peer terminal disabled")}function En(){return Date.now()}function tw(I,l,G,c){let e=Number(process.env[I]);return Number.isFinite(e)?Math.max(G,Math.min(c,Math.floor(e))):l}function TyI(I,l,G,c){let e=En();for(let[d,Z]of I)Z<=e&&I.delete(d);let b=`${l}:${G}`;return I.has(b)?!1:(I.set(b,c+VS),!0)}function uS(I){return I.split("/").pop()||I}function DyI(){return process.platform==="win32"?"powershell.exe":[process.env.SHELL,"/bin/zsh","/bin/bash"].filter(Boolean).find(l=>(0,_s.existsSync)(l))||"/bin/bash"}function pS(){let I=(0,_s.existsSync)(nl())?nl():(0,oS.homedir)(),l=Cs().cwd?.trim();if(!l)return I;let G=(0,qo.isAbsolute)(l)?l:(0,qo.resolve)(I,l);return(0,_s.existsSync)(G)?G:I}function qyI(I){let l=I.url.replace(/\/$/,""),G=new URL(l);return G.protocol=G.protocol==="https:"?"wss:":"ws:",G.pathname=nw,G.search="",G.toString()}function PyI(I){let l=Buffer.isBuffer(I)?I.toString("utf8"):String(I);if(!l||l.charCodeAt(0)!==123)return null;try{return JSON.parse(l)}catch{return null}}var To=class{constructor(l,G,c,e,b,d){this.manager=l;this.ws=G;this.role=c;this.deviceId=e;this.computerName=b;this.url=d;this.ws.on("pong",()=>{this.alive=!0}),this.ws.on("message",Z=>this.handleMessage(Z)),this.ws.on("close",()=>this.close({intentional:!1})),this.ws.on("error",Z=>{V.warn(Z,"[lan-peer] websocket error"),this.close({intentional:!1})}),this.startHeartbeat(),this.sendJson({type:"peer.ready",connection_id:this.id,device_id:this.deviceId,role:this.role})}manager;ws;role;deviceId;computerName;url;id=(0,yn.randomUUID)();connectedAt=En();terminalSessions=new Map;remoteTerminals=new Map;uploads=new Map;pendingRequests=new Map;pendingDownloads=new Map;heartbeatTimer=null;alive=!0;closed=!1;info(){return{id:this.id,role:this.role,device_id:this.deviceId,computer_name:this.computerName,url:this.url,connected_at:this.connectedAt,local_terminal_sessions:this.terminalSessions.size,remote_terminal_sessions:this.remoteTerminals.size,reconnect_attempts:this.role==="client"?this.manager.getReconnectAttempts(this.deviceId):void 0}}close(l={}){if(!this.closed){this.closed=!0,this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null);for(let G of this.terminalSessions.values())this.disposeTerminalSession(G,{notify:!1});this.terminalSessions.clear(),this.remoteTerminals.clear();for(let G of this.uploads.values())try{G.stream.destroy()}catch{}this.uploads.clear();for(let G of this.pendingRequests.values())clearTimeout(G.timer),G.reject(new Error("Peer connection closed"));this.pendingRequests.clear();for(let G of this.pendingDownloads.values())clearTimeout(G.timer),G.reject(new Error("Peer connection closed"));if(this.pendingDownloads.clear(),this.ws.readyState===Ad.OPEN||this.ws.readyState===Ad.CONNECTING)try{this.ws.close()}catch{}this.manager.removeConnection(this.id),this.role==="client"&&!l.intentional&&this.manager.scheduleReconnect(this.deviceId)}}startHeartbeat(){this.heartbeatTimer=setInterval(()=>{if(this.ws.readyState===Ad.OPEN){if(!this.alive){try{this.ws.terminate()}catch{}return}this.alive=!1;try{this.ws.ping()}catch{}}},jyI),this.heartbeatTimer.unref?.()}sendJson(l){this.ws.readyState===Ad.OPEN&&this.ws.send(JSON.stringify(l))}disposeTerminalSession(l,G={}){l.idleTimer&&(clearTimeout(l.idleTimer),l.idleTimer=null),this.terminalSessions.delete(l.id);try{l.pty.kill()}catch{}G.notify&&this.sendJson({type:"terminal.exit",terminal_id:l.id,exit_code:G.exitCode??0})}touchTerminalSession(l){l.lastActiveAt=En(),this.scheduleTerminalIdleTimeout(l,So)}scheduleTerminalIdleTimeout(l,G){l.idleTimer&&clearTimeout(l.idleTimer),l.idleTimer=setTimeout(()=>{let c=this.terminalSessions.get(l.id);if(!c)return;let e=So-(En()-c.lastActiveAt);if(e>0){this.scheduleTerminalIdleTimeout(c,e);return}V.info({connectionId:this.id,terminalId:c.id,idleMs:So},"[lan-peer] closing idle terminal"),this.disposeTerminalSession(c,{notify:!0,exitCode:0})},G),l.idleTimer.unref?.()}request(l,G,c=["error"],e=3e4){if(this.ws.readyState!==Ad.OPEN)return Promise.reject(new Error("Peer connection is not open"));let b=(0,yn.randomUUID)();return new Promise((d,Z)=>{let n=setTimeout(()=>{this.pendingRequests.delete(b),Z(new Error("Peer request timed out"))},e);n.unref?.(),this.pendingRequests.set(b,{resolve:d,reject:Z,successTypes:new Set(G),errorTypes:new Set(c),timer:n}),this.sendJson({...l,request_id:b})})}async createRemoteTerminal(l={}){let G=await this.request({type:"terminal.create",shell:l.shell,cols:l.cols,rows:l.rows},["terminal.created"],["terminal.error","error"]),c=G.terminal_id||"";if(!c)throw new Error("Peer did not return a terminal id");return this.remoteTerminals.set(c,{id:c,buffer:[],bufferBytes:0,exitCode:null}),{terminal_id:c,pid:Number(G.pid||0),shell:String(G.shell||"")}}listTerminals(){return{remote_terminals:[...this.remoteTerminals.values()].map(l=>({terminal_id:l.id,buffered_bytes:l.bufferBytes,buffered_chunks:l.buffer.length,exited:l.exitCode!==null,exit_code:l.exitCode})),local_terminal_sessions:[...this.terminalSessions.values()].map(l=>({terminal_id:l.id,pid:l.pid,shell:uS(l.shell),last_active_at:l.lastActiveAt,idle_timeout_ms:So}))}}writeRemoteTerminal(l,G){if(!this.remoteTerminals.has(l))throw new Error("Remote terminal not found");this.sendJson({type:"terminal.input",terminal_id:l,data:G})}resizeRemoteTerminal(l,G,c){if(!this.remoteTerminals.has(l))throw new Error("Remote terminal not found");this.sendJson({type:"terminal.resize",terminal_id:l,cols:G,rows:c})}closeRemoteTerminal(l){if(!this.remoteTerminals.has(l))throw new Error("Remote terminal not found");this.sendJson({type:"terminal.close",terminal_id:l}),this.remoteTerminals.delete(l)}readRemoteTerminal(l){let G=this.remoteTerminals.get(l);if(!G)throw new Error("Remote terminal not found");let c=G.buffer.join("");return G.buffer.length=0,G.bufferBytes=0,{terminal_id:l,data:c,exited:G.exitCode!==null,exit_code:G.exitCode}}async execRemoteCommand(l){let G=await this.request({type:"terminal.exec",command:l.command,args:l.args||[],cwd:l.cwd,timeout_ms:l.timeoutMs},["terminal.exec.result"],["terminal.exec.error","error"],Math.max(1e3,(l.timeoutMs||3e4)+1e3));return{stdout:String(G.stdout||""),stderr:String(G.stderr||""),exit_code:typeof G.exit_code=="number"?G.exit_code:null,timed_out:!!G.timed_out}}downloadFileToBuffer(l,G=6e4){if(this.ws.readyState!==Ad.OPEN)return Promise.reject(new Error("Peer connection is not open"));let c=(0,yn.randomUUID)();return new Promise((e,b)=>{let d=setTimeout(()=>{this.pendingDownloads.delete(c),b(new Error("Peer file download timed out"))},G);d.unref?.(),this.pendingDownloads.set(c,{chunks:[],resolve:e,reject:b,timer:d}),this.sendJson({type:"file.download",transfer_id:c,path:l})})}async uploadFileFromBuffer(l,G,c=6e4){let e=(0,yn.randomUUID)();await this.request({type:"file.upload.start",transfer_id:e,path:l},["file.upload.ready"],["file.error","error"],c);for(let b=0;b<G.length;b+=ew)this.sendJson({type:"file.upload.chunk",transfer_id:e,data:G.subarray(b,b+ew).toString("base64")});return await this.request({type:"file.upload.complete",transfer_id:e},["file.upload.complete"],["file.error","error"],c),{path:l,size:G.length}}handleMessage(l){let G=PyI(l);if(!G?.type){this.sendJson({type:"error",message:"Invalid peer message"});return}if(!this.handlePendingMessage(G))switch(G.type){case"terminal.data":this.bufferRemoteTerminalData(G);break;case"terminal.exit":this.markRemoteTerminalExit(G);break;case"terminal.create":this.createTerminal(G);break;case"terminal.input":this.writeTerminal(G);break;case"terminal.resize":this.resizeTerminal(G);break;case"terminal.close":this.closeTerminal(G);break;case"terminal.exec":this.execCommand(G);break;case"file.download":this.downloadFile(G);break;case"file.download.started":break;case"file.download.chunk":case"file.download.complete":case"file.error":this.handleFileTransferMessage(G);break;case"file.upload.start":this.startUpload(G);break;case"file.upload.chunk":this.writeUploadChunk(G);break;case"file.upload.complete":this.completeUpload(G);break;default:this.sendJson({type:"error",request_id:G.request_id,message:`Unsupported peer message: ${G.type}`})}}handlePendingMessage(l){if(l.request_id){let G=this.pendingRequests.get(l.request_id);if(G){if(G.successTypes.has(l.type||""))return clearTimeout(G.timer),this.pendingRequests.delete(l.request_id),G.resolve(l),!0;if(G.errorTypes.has(l.type||""))return clearTimeout(G.timer),this.pendingRequests.delete(l.request_id),G.reject(new Error(l.message||`Peer request failed: ${l.type}`)),!0}}return!1}bufferRemoteTerminalData(l){let G=l.terminal_id?this.remoteTerminals.get(l.terminal_id):null;if(!G||typeof l.data!="string")return;let c=Buffer.byteLength(l.data,"utf8");for(G.buffer.push(l.data),G.bufferBytes+=c;G.bufferBytes>SyI&&G.buffer.length>1;){let e=G.buffer.shift()||"";G.bufferBytes-=Buffer.byteLength(e,"utf8")}}markRemoteTerminalExit(l){let G=l.terminal_id?this.remoteTerminals.get(l.terminal_id):null;G&&(G.exitCode=typeof l.exit_code=="number"?l.exit_code:0)}handleFileTransferMessage(l){let G=l.transfer_id?this.pendingDownloads.get(l.transfer_id):null;return G?l.type==="file.download.chunk"&&typeof l.data=="string"?(G.chunks.push(Buffer.from(l.data,"base64")),!0):l.type==="file.download.complete"?(clearTimeout(G.timer),this.pendingDownloads.delete(l.transfer_id),G.resolve(Buffer.concat(G.chunks)),!0):l.type==="file.error"?(clearTimeout(G.timer),this.pendingDownloads.delete(l.transfer_id),G.reject(new Error(l.message||"Peer file transfer failed")),!0):!1:!1}createTerminal(l){if(!dw){this.sendJson({type:"terminal.error",request_id:l.request_id,message:"Terminal is not available"});return}if(this.terminalSessions.size>=hS){this.sendJson({type:"terminal.error",request_id:l.request_id,message:`Terminal limit reached (${hS} per peer connection)`});return}let G=l.shell||DyI(),c;try{c=dw.spawn(G,[],{name:"xterm-color",cols:Math.max(1,l.cols||80),rows:Math.max(1,l.rows||24),cwd:pS()})}catch(d){this.sendJson({type:"terminal.error",request_id:l.request_id,message:d?.message||"Failed to create terminal"});return}let e=(0,yn.randomUUID)(),b={id:e,pty:c,shell:G,pid:c.pid,lastActiveAt:En(),idleTimer:null};this.terminalSessions.set(e,b),this.touchTerminalSession(b),b.pty.onData(d=>{this.terminalSessions.has(e)&&(this.touchTerminalSession(b),this.sendJson({type:"terminal.data",terminal_id:e,data:d}))}),b.pty.onExit(({exitCode:d})=>{this.terminalSessions.has(e)&&(b.idleTimer&&clearTimeout(b.idleTimer),this.terminalSessions.delete(e),this.sendJson({type:"terminal.exit",terminal_id:e,exit_code:d}))}),this.sendJson({type:"terminal.created",request_id:l.request_id,terminal_id:e,pid:b.pid,shell:uS(G)})}writeTerminal(l){let G=l.terminal_id?this.terminalSessions.get(l.terminal_id):null;!G||typeof l.data!="string"||(this.touchTerminalSession(G),G.pty.write(l.data))}resizeTerminal(l){let G=l.terminal_id?this.terminalSessions.get(l.terminal_id):null;if(G){this.touchTerminalSession(G);try{G.pty.resize(Math.max(1,l.cols||80),Math.max(1,l.rows||24))}catch{}}}closeTerminal(l){let G=l.terminal_id?this.terminalSessions.get(l.terminal_id):null;G&&this.disposeTerminalSession(G,{notify:!1})}execCommand(l){let G=typeof l.command=="string"?l.command.trim():"",c=Array.isArray(l.args)?l.args.filter(u=>typeof u=="string"):[];if(!G){this.sendJson({type:"terminal.exec.error",request_id:l.request_id,message:"Missing command"});return}let e=pS();if(l.cwd)try{let u=K(l.cwd);e=(0,_s.existsSync)(u)?u:e}catch(u){this.sendJson({type:"terminal.exec.error",request_id:l.request_id,message:u?.message||"Invalid cwd"});return}let b=Math.max(1e3,Math.min(Number(l.timeout_ms)||KyI,600*1e3)),d=[],Z=[],n=0,t=0,a=!1,W=!1,m;try{m=(0,rS.spawn)(G,c,{cwd:e,shell:!1,windowsHide:!0})}catch(u){this.sendJson({type:"terminal.exec.error",request_id:l.request_id,message:u?.message||"Failed to start command"});return}let s=u=>{a||(a=!0,clearTimeout(Y),this.sendJson({type:"terminal.exec.result",request_id:l.request_id,stdout:Buffer.concat(d).toString("utf8"),stderr:Buffer.concat(Z).toString("utf8"),exit_code:u,timed_out:W}))},N=(u,o,p)=>{if(o>=YS)return o;let h=YS-o,r=p.subarray(0,h);return u.push(r),o+r.length},Y=setTimeout(()=>{W=!0;try{m.kill()}catch{}s(null)},b);Y.unref?.(),m.stdout?.on("data",u=>{n=N(d,n,Buffer.from(u))}),m.stderr?.on("data",u=>{t=N(Z,t,Buffer.from(u))}),m.on("error",u=>{a||(a=!0,clearTimeout(Y),this.sendJson({type:"terminal.exec.error",request_id:l.request_id,message:u.message}))}),m.on("close",u=>s(u))}downloadFile(l){if(!l.transfer_id||!l.path){this.sendJson({type:"file.error",request_id:l.request_id,transfer_id:l.transfer_id,message:"Missing file path"});return}let G;try{G=K(l.path)}catch(e){this.sendJson({type:"file.error",request_id:l.request_id,transfer_id:l.transfer_id,message:e?.message||"Invalid file path"});return}let c=(0,Do.createReadStream)(G,{highWaterMark:ew});this.sendJson({type:"file.download.started",request_id:l.request_id,transfer_id:l.transfer_id}),c.on("data",e=>{this.sendJson({type:"file.download.chunk",transfer_id:l.transfer_id,data:Buffer.from(e).toString("base64")})}),c.on("error",e=>{this.sendJson({type:"file.error",transfer_id:l.transfer_id,message:e.message})}),c.on("end",()=>{this.sendJson({type:"file.download.complete",transfer_id:l.transfer_id})})}startUpload(l){if(!l.transfer_id||!l.path){this.sendJson({type:"file.error",request_id:l.request_id,transfer_id:l.transfer_id,message:"Missing upload path"});return}let G;try{G=K(l.path)}catch(e){this.sendJson({type:"file.error",request_id:l.request_id,transfer_id:l.transfer_id,message:e?.message||"Invalid upload path"});return}let c=(0,Do.createWriteStream)(G);c.on("error",e=>{this.uploads.delete(l.transfer_id),this.sendJson({type:"file.error",transfer_id:l.transfer_id,message:e.message})}),this.uploads.set(l.transfer_id,{id:l.transfer_id,path:G,stream:c}),this.sendJson({type:"file.upload.ready",request_id:l.request_id,transfer_id:l.transfer_id})}writeUploadChunk(l){let G=l.transfer_id?this.uploads.get(l.transfer_id):null;!G||typeof l.data!="string"||G.stream.write(Buffer.from(l.data,"base64"))}completeUpload(l){let G=l.transfer_id?this.uploads.get(l.transfer_id):null;G&&G.stream.end(()=>{this.uploads.delete(G.id),this.sendJson({type:"file.upload.complete",request_id:l.request_id,transfer_id:G.id,path:G.path})})}},Zw=class{wss=new hn.default({noServer:!0});connections=new Map;clientTargets=new Map;seenNonces=new Map;setupDone=!1;setupServer(l){if(this.setupDone)return;this.setupDone=!0,(Array.isArray(l)?l:[l]).forEach(c=>{c.on("upgrade",async(e,b,d)=>{let Z=new URL(e.url||"",`http://${e.headers.host}`);if(Z.pathname!==nw)return;if(Od(e,y.corsOrigins)){Ja(b);return}let n=await this.authenticateUpgrade(Z,e);if(!n.ok){b.write(`HTTP/1.1 ${n.status} ${n.message}\r
|
|
309
309
|
\r
|
|
310
310
|
`),b.destroy();return}this.wss.handleUpgrade(e,b,d,t=>{let a=new To(this,t,"server",n.device.id,n.device.computerName,n.device.url);this.connections.set(a.id,a),this.wss.emit("connection",t,e)})})})}async connectToDevice(l){let G=this.findConnectionByDevice(l.id,"client");if(G)return G.info();let c=this.getOrCreateClientTarget(l);c.device=l,c.disabled=!1,c.reconnectTimer&&(clearTimeout(c.reconnectTimer),c.reconnectTimer=null);let e=await this.openClientConnection(l);return c.attempts=0,e.info()}async openClientConnection(l){let G=await Sd(),c=En(),e=(0,yn.randomUUID)(),b=await Ts(e,c),d=new URL(qyI(l));d.searchParams.set("device_id",G.device_id),d.searchParams.set("device_public_key",G.device_public_key),d.searchParams.set("computer_name",G.computer_name),d.searchParams.set("timestamp",String(c)),d.searchParams.set("nonce",e),d.searchParams.set("signature",b);let Z=new Ad(d);await new Promise((t,a)=>{let W=setTimeout(()=>{Z.close(),a(new Error("Peer socket connection timeout"))},5e3);Z.once("open",()=>{clearTimeout(W),t()}),Z.once("error",m=>{clearTimeout(W),a(m)})});let n=new To(this,Z,"client",l.id,l.computer_name,l.url);return this.connections.set(n.id,n),n}listConnections(){return[...this.connections.values()].map(l=>l.info()).sort((l,G)=>G.connected_at-l.connected_at)}getConnection(l){return this.connections.get(l)||null}disconnect(l){let G=this.connections.get(l);return G?(G.role==="client"&&this.disableClientReconnect(G.deviceId),G.close({intentional:!0}),!0):!1}disconnectDevice(l){this.disableClientReconnect(l);let G=[...this.connections.values()].filter(c=>c.deviceId===l);return G.forEach(c=>c.close({intentional:!0})),G.length}removeConnection(l){this.connections.delete(l)}getReconnectAttempts(l){return this.clientTargets.get(l)?.attempts||0}scheduleReconnect(l){let G=this.clientTargets.get(l);if(!G||G.disabled||this.findConnectionByDevice(l,"client")||G.reconnectTimer)return;if(G.attempts>=MyI){V.warn({deviceId:l},"[lan-peer] client reconnect limit reached");return}G.attempts+=1;let c=fyI*2**(G.attempts-1);G.reconnectTimer=setTimeout(()=>{G.reconnectTimer=null,this.openClientConnection(G.device).then(()=>{G.attempts=0}).catch(e=>{V.warn({err:e,deviceId:l,attempt:G.attempts},"[lan-peer] client reconnect failed"),this.scheduleReconnect(l)})},c),G.reconnectTimer.unref?.()}getOrCreateClientTarget(l){let G=this.clientTargets.get(l.id);return G||(G={device:l,attempts:0,reconnectTimer:null,disabled:!1},this.clientTargets.set(l.id,G)),G}disableClientReconnect(l){let G=this.clientTargets.get(l);G&&(G.disabled=!0,G.reconnectTimer&&(clearTimeout(G.reconnectTimer),G.reconnectTimer=null))}findConnectionByDevice(l,G){return[...this.connections.values()].find(c=>c.deviceId===l&&(!G||c.role===G))||null}async authenticateUpgrade(l,G){let c=l.searchParams.get("device_id")?.trim()||"",e=l.searchParams.get("device_public_key")||"",b=Number(l.searchParams.get("timestamp")||""),d=l.searchParams.get("nonce")||"",Z=l.searchParams.get("signature")||"",n=l.searchParams.get("computer_name")||"";if(!c||!e||!Number.isFinite(b)||!d||!Z)return{ok:!1,status:400,message:"Bad Request"};if(Math.abs(En()-b)>VS)return{ok:!1,status:400,message:"Expired Request"};if(!Ds({device_id:c,device_public_key:e,nonce:d,timestamp:b,signature:Z}))return{ok:!1,status:401,message:"Unauthorized"};if(!TyI(this.seenNonces,c,d,b))return{ok:!1,status:409,message:"Replay Request"};if(Bc(c)?.inbound_status!=="approved")return{ok:!1,status:403,message:"Forbidden"};let a=G.socket.remoteAddress?.startsWith("::ffff:")?G.socket.remoteAddress.slice(7):G.socket.remoteAddress||"";return{ok:!0,device:{id:c,computerName:n,url:a?`ws://${a}`:""}}}},bw=null;function mc(){return bw||(bw=new Zw),bw}function iS(){return nw}var Po=require("fs/promises");var Ww=class{listConnections(){return mc().listConnections()}disconnect(l){return mc().disconnect(l)}async createTerminal(l,G={}){return this.requireConnection(l).createRemoteTerminal(G)}listTerminals(l){return this.requireConnection(l).listTerminals()}writeTerminal(l){return this.requireConnection(l.connectionId).writeRemoteTerminal(l.terminalId,l.data),{ok:!0}}resizeTerminal(l){return this.requireConnection(l.connectionId).resizeRemoteTerminal(l.terminalId,l.cols,l.rows),{ok:!0}}closeTerminal(l){return this.requireConnection(l.connectionId).closeRemoteTerminal(l.terminalId),{ok:!0}}readTerminal(l){return this.requireConnection(l.connectionId).readRemoteTerminal(l.terminalId)}exec(l){return this.requireConnection(l.connectionId).execRemoteCommand({command:l.command,args:l.args,cwd:l.cwd,timeoutMs:l.timeoutMs})}async downloadFile(l){let G=K(l.localPath),c=await this.requireConnection(l.connectionId).downloadFileToBuffer(l.remotePath,l.timeoutMs);return await(0,Po.writeFile)(G,c),{remote_path:l.remotePath,local_path:G,size:c.length}}async uploadFile(l){let G=K(l.localPath),c=await(0,Po.readFile)(G);return{...await this.requireConnection(l.connectionId).uploadFileFromBuffer(l.remotePath,c,l.timeoutMs),local_path:G,remote_path:l.remotePath}}requireConnection(l){let G=mc().getConnection(l);if(!G)throw Object.assign(new Error("Peer connection not found"),{status:404});return G}},aw=null;function Gb(){return aw||(aw=new Ww),aw}var FS=C(require("http")),XS=C(require("https")),_o=class extends Error{primaryError;fallbackError;constructor(l,G){super(`fetch failed: ${l.message}; node-http fallback failed: ${G.message}`),this.name="LanJsonPostError",this.primaryError=l,this.fallbackError=G}};function RS(I){return{name:String(I?.name||"Error"),message:String(I?.message||I||"request failed"),code:typeof I?.code=="string"?I.code:void 0,syscall:typeof I?.syscall=="string"?I.syscall:void 0,address:typeof I?.address=="string"?I.address:void 0,port:typeof I?.port=="number"?I.port:void 0}}async function _yI(I,l,G,c){let e=new AbortController,b=setTimeout(()=>e.abort(),c);try{let d=await fetch(I,{method:l,headers:l==="POST"?{"Content-Type":"application/json"}:{Accept:"application/json"},...l==="POST"?{body:JSON.stringify(G)}:{},signal:e.signal}),Z=await d.json().catch(()=>({}));return{ok:d.ok,status:d.status,data:Z,transport:"fetch"}}finally{clearTimeout(b)}}function $yI(I){if(!I)return{};try{let l=JSON.parse(I);return l&&typeof l=="object"&&!Array.isArray(l)?l:{}}catch{return{}}}function IEI(I,l,G,c,e){let b=new URL(I),d=l==="POST"?JSON.stringify(G):"",Z=b.protocol==="https:"?XS.default:FS.default;return new Promise((n,t)=>{let a=Z.request(b,{method:l,headers:{Accept:"application/json",...l==="POST"?{"Content-Type":"application/json","Content-Length":Buffer.byteLength(d)}:{}},timeout:c},W=>{let m=[];W.on("data",s=>m.push(Buffer.isBuffer(s)?s:Buffer.from(s))),W.on("end",()=>{let s=W.statusCode||0;n({ok:s>=200&&s<300,status:s,data:$yI(Buffer.concat(m).toString("utf-8")),transport:"node-http",primaryError:e})})});a.on("timeout",()=>{let W=new Error(`request timed out after ${c}ms`);W.code="ETIMEDOUT",a.destroy(W)}),a.on("error",t),a.end(d||void 0)})}async function HS(I,l,G,c){try{return await _yI(I,l,G,c)}catch(e){let b=RS(e);try{return await IEI(I,l,G,c,b)}catch(d){throw new _o(b,RS(d))}}}async function QS(I,l=5e3){return HS(I,"GET",void 0,l)}async function mw(I,l,G=5e3){return HS(I,"POST",l,G)}function sw(I){return I instanceof _o?{message:I.message,primary:I.primaryError,fallback:I.fallbackError}:I?{message:String(I?.message||I)}:null}CI();var Nw=require("crypto"),Yw=300*1e3,$o=new Map;function wS(I,l,G){let c=Date.now();for(let[b,d]of $o)d<=c&&$o.delete(b);let e=`${I}:${l}`;return $o.has(e)?!1:($o.set(e,G+Yw),!0)}function vS(I){return I==="none"||I==="pending"||I==="approved"||I==="rejected"||I==="blocked"?I:null}async function lEI(I){let l=Date.now(),G=(0,Nw.randomUUID)(),c=await Sd(),e=await Ts(G,l);try{let b=await mw(`${I.url.replace(/\/$/,"")}/api/devices/link-status`,{device_id:c.device_id,device_public_key:c.device_public_key,timestamp:l,nonce:G,signature:e},1500);return b.ok?vS(b.data.status):null}catch{return null}}async function GEI(I){let l=new Map;return await Promise.all(I.map(async G=>{let c=await lEI(G);if(!c)return;l.set(G.id,c);let e=Bc(G.id);c!=="pending"&&(c!=="none"||e?.outbound_status!=="none")&&Bo(G.id,c,G)})),l}function yS(I){return{id:I.id,device_id:I.device_id,device_public_key:I.device_public_key,ip:I.ip,http_port:I.http_port,endpoint_kind:I.endpoint_kind,url:I.url,computer_name:I.computer_name,os:I.os,hermes_agent_version:I.hermes_agent_version,hermes_web_ui_version:I.hermes_web_ui_version,response_ms:I.response_ms,last_seen_at:new Date(I.last_seen_at||I.updated_at||Date.now()).toISOString()}}function cEI(I,l){let G=new Map(I.map(c=>[c.id,c]));for(let c of l)G.has(c.id)||c.inbound_status==="none"&&c.outbound_status==="none"||!c.device_public_key||!c.url||!c.http_port||G.set(c.id,yS(c));return[...G.values()]}async function fa(){let I=Ps(),l=Uo(),G=new Set(I.devices.map(Z=>Z.id)),c=cEI(I.devices,l),e=await GEI(c),b=new Map(Uo().map(Z=>[Z.id,Z])),d=c.map(Z=>{let n=b.get(Z.id),t=e.get(Z.id)||n?.outbound_status||"none",a=G.has(Z.id)||e.has(Z.id);return a&&t==="approved"&&mc().connectToDevice(Z).catch(W=>{console.warn("[lan-peer] failed to connect paired device:",W?.message||W)}),{...Z,online:a,inbound_status:n?.inbound_status||"none",outbound_status:t,requested_at:n?.requested_at||0,decided_at:n?.decided_at||null,outbound_requested_at:n?.outbound_requested_at||0,outbound_decided_at:n?.outbound_decided_at||null,updated_at:n?.updated_at||0}});return{scanning:I.scanning,last_scanned_at:I.last_scanned_at,devices:d,requests:GS()}}async function ES(I){I.body=await fa()}function eEI(I){let l=String(I||"").trim();if(!l)return null;try{let G=new URL(l.includes("://")?l:`http://${l}`);return G.protocol!=="http:"&&G.protocol!=="https:"?null:(G.username="",G.password="",G.pathname="",G.search="",G.hash="",G)}catch{return null}}function bEI(I){return Math.max(0,Date.now()-I)}function dEI(I,l,G){let c=typeof l.device_id=="string"?l.device_id.trim():"",e=typeof l.device_public_key=="string"?l.device_public_key:"";if(!c||!e||Ba(e)!==c)return null;let b=Number(l.http_port)||Number(I.port)||(I.protocol==="https:"?443:80);if(!Number.isInteger(b)||b<=0||b>65535)return null;let d=l.endpoint_kind==="web"||l.endpoint_kind==="desktop"||l.endpoint_kind==="custom"?l.endpoint_kind:vn(b);return{id:c,device_id:c,device_public_key:e,ip:I.hostname,http_port:b,endpoint_kind:d,url:I.origin,computer_name:String(l.computer_name||""),os:{type:String(l.os?.type||""),platform:String(l.os?.platform||""),release:String(l.os?.release||""),arch:String(l.os?.arch||"")},hermes_agent_version:String(l.hermes_agent_version||""),hermes_web_ui_version:String(l.hermes_web_ui_version||""),response_ms:G,last_seen_at:new Date().toISOString()}}async function ZEI(I){let l=Date.now(),G=await QS(`${I.origin}/api/devices/link-info`,5e3);if(!G.ok)throw new Error(`Device info request failed: ${G.status}`);let c=dEI(I,G.data,bEI(l));if(!c)throw new Error("Remote URL did not return valid device info");return c}async function gS(I){let l=Date.now(),G=(0,Nw.randomUUID)(),c=await Sd(),e=await Ts(G,l),b={...c,http_port:y.port,endpoint_kind:vn(y.port),timestamp:l,nonce:G,signature:e},d=await mw(`${I.url.replace(/\/$/,"")}/api/devices/link-request`,b,5e3),Z=d.data;if(!d.ok){let n=new Error(typeof Z.error=="string"?Z.error:`Request failed: ${d.status}`);throw n.status=d.status===409?409:502,n}return vS(Z.status)||"pending"}async function JS(I){let l=await Sd();I.body={...l,http_port:y.port,endpoint_kind:vn(y.port)}}async function CS(I){let l=eEI(I.request.body?.url);if(!l){I.status=400,I.body={error:"Invalid device URL"};return}try{let G=await ZEI(l),c=await gS(G);c!=="none"&&Bo(G.id,c,G),I.body=await fa()}catch(G){I.status=Number(G?.status)||502,I.body={error:G?.message?`Failed to request device pairing: ${G.message}`:"Failed to request device pairing",detail:sw(G)}}}async function AS(I){await Ko(),I.body=await fa()}function hw(I){let l=Ps().devices.find(c=>c.id===I);if(l)return l;let G=Bc(I);return G?yS(G):null}function nEI(I){let l=String(I.ip||I.request?.ip||"");return l.startsWith("::ffff:")?l.slice(7):l}function tEI(I,l){let G=typeof l?.device_id=="string"?l.device_id.trim():"",c=typeof l?.device_public_key=="string"?l.device_public_key:"",e=Number(l?.http_port);if(!G||!c||!Number.isInteger(e)||e<=0||e>65535)return null;let b=nEI(I),d=l.endpoint_kind==="web"||l.endpoint_kind==="desktop"||l.endpoint_kind==="custom"?l.endpoint_kind:vn(e);return{id:G,device_id:G,device_public_key:c,ip:b,http_port:e,endpoint_kind:d,url:typeof l?.url=="string"&&l.url?l.url:`http://${b}:${e}`,computer_name:String(l?.computer_name||""),os:{type:String(l?.os?.type||""),platform:String(l?.os?.platform||""),release:String(l?.os?.release||""),arch:String(l?.os?.arch||"")},hermes_agent_version:String(l?.hermes_agent_version||""),hermes_web_ui_version:String(l?.hermes_web_ui_version||""),response_ms:0,last_seen_at:new Date().toISOString()}}async function LS(I){let l=I.request.body,G=Number(l?.timestamp),c=typeof l?.nonce=="string"?l.nonce:"",e=typeof l?.signature=="string"?l.signature:"",b=tEI(I,l);if(!b||!Number.isFinite(G)||!c||!e){I.status=400,I.body={error:"Invalid device request"};return}if(Math.abs(Date.now()-G)>Yw){I.status=400,I.body={error:"Device request expired"};return}if(!Ds({device_id:b.id,device_public_key:b.device_public_key,nonce:c,timestamp:G,signature:e})){I.status=401,I.body={error:"Invalid device signature"};return}if(!wS(b.id,c,G)){I.status=409,I.body={error:"Device request replayed"};return}try{let d=eS(b);I.body={status:d.inbound_status}}catch(d){if(d instanceof js){I.status=409,I.body={error:"Duplicate pairing request"};return}throw d}}async function kS(I){let l=I.request.body,G=typeof l?.device_id=="string"?l.device_id.trim():"",c=typeof l?.device_public_key=="string"?l.device_public_key:"",e=Number(l?.timestamp),b=typeof l?.nonce=="string"?l.nonce:"",d=typeof l?.signature=="string"?l.signature:"";if(!G||!c||!Number.isFinite(e)||!b||!d){I.status=400,I.body={error:"Invalid device status request"};return}if(Math.abs(Date.now()-e)>Yw){I.status=400,I.body={error:"Device status request expired"};return}if(!Ds({device_id:G,device_public_key:c,nonce:b,timestamp:e,signature:d})){I.status=401,I.body={error:"Invalid device signature"};return}if(!wS(G,b,e)){I.status=409,I.body={error:"Device status request replayed"};return}I.body={status:Bc(G)?.inbound_status||"none"}}async function Ir(I,l){try{bS(I.params.id,l,hw(I.params.id)||void 0),I.body=await fa()}catch{I.status=404,I.body={error:"Device not found"}}}async function xS(I){await Ir(I,"approved")}async function zS(I){await Ir(I,"rejected")}async function US(I){await Ir(I,"blocked")}async function BS(I){await Ir(I,"none")}async function OS(I){if(!dS(I.params.id)){I.status=404,I.body={error:"Device request not found"};return}mc().disconnectDevice(I.params.id),I.body=await fa()}async function MS(I){I.body={connections:mc().listConnections()}}async function fS(I){let l=hw(I.params.id);if(!l){I.status=404,I.body={error:"Device not found"};return}if(Bc(I.params.id)?.outbound_status!=="approved"){I.status=403,I.body={error:"Device pairing has not been approved"};return}try{let c=await mc().connectToDevice(l);I.body={connection:c}}catch(c){I.status=502,I.body={error:c?.message||"Failed to connect peer device"}}}async function jS(I){if(!mc().disconnect(I.params.connectionId)){I.status=404,I.body={error:"Peer connection not found"};return}I.body={connections:mc().listConnections()}}function gn(I,l){let G=Number(I);return Number.isFinite(G)?G:l}function Ub(I,l){I.status=Number(l?.status)||502,I.body={error:l?.message||"Peer operation failed"}}async function KS(I){let l=I.request.body;try{let G=await Gb().createTerminal(I.params.connectionId,{shell:typeof l?.shell=="string"?l.shell:void 0,cols:gn(l?.cols,80),rows:gn(l?.rows,24)});I.body={terminal:G}}catch(G){Ub(I,G)}}async function SS(I){try{I.body={terminals:Gb().listTerminals(I.params.connectionId)}}catch(l){Ub(I,l)}}async function TS(I){let l=I.request.body;try{I.body=Gb().writeTerminal({connectionId:I.params.connectionId,terminalId:String(I.params.terminalId||""),data:String(l?.data||"")})}catch(G){Ub(I,G)}}async function DS(I){let l=I.request.body;try{I.body=Gb().resizeTerminal({connectionId:I.params.connectionId,terminalId:String(I.params.terminalId||""),cols:gn(l?.cols,80),rows:gn(l?.rows,24)})}catch(G){Ub(I,G)}}async function qS(I){try{I.body={terminal:Gb().readTerminal({connectionId:I.params.connectionId,terminalId:String(I.params.terminalId||"")})}}catch(l){Ub(I,l)}}async function PS(I){try{I.body=Gb().closeTerminal({connectionId:I.params.connectionId,terminalId:String(I.params.terminalId||"")})}catch(l){Ub(I,l)}}async function _S(I){let l=I.request.body;try{let G=await Gb().exec({connectionId:I.params.connectionId,command:String(l?.command||""),args:Array.isArray(l?.args)?l.args.map(String):[],cwd:typeof l?.cwd=="string"?l.cwd:void 0,timeoutMs:gn(l?.timeout_ms,3e4)});I.body={result:G}}catch(G){Ub(I,G)}}async function $S(I){let l=I.request.body;try{I.body=await Gb().downloadFile({connectionId:I.params.connectionId,remotePath:String(l?.remote_path||l?.path||""),localPath:String(l?.local_path||""),timeoutMs:gn(l?.timeout_ms,6e4)})}catch(G){Ub(I,G)}}async function IT(I){let l=I.request.body;try{I.body=await Gb().uploadFile({connectionId:I.params.connectionId,localPath:String(l?.local_path||""),remotePath:String(l?.remote_path||l?.path||""),timeoutMs:gn(l?.timeout_ms,6e4)})}catch(G){Ub(I,G)}}async function lT(I){let l=hw(I.params.id);if(!l){I.status=404,I.body={error:"Device not found"};return}try{let G=await gS(l);G!=="none"&&Bo(l.id,G,l),I.body=await fa()}catch(G){let c=sw(G);I.status=Number(G?.status)||502,I.body={error:G?.message?`Failed to request device pairing: ${G.message}`:"Failed to request device pairing",detail:c}}}var $s=new B,tl=new B;$s.post("/api/devices/link-request",LS);$s.post("/api/devices/link-status",kS);$s.get("/api/devices/link-info",JS);tl.get("/api/devices",ES);tl.post("/api/devices/scan",AS);tl.post("/api/devices/manual-request",CS);tl.post("/api/devices/:id/request",lT);tl.post("/api/devices/:id/approve",xS);tl.post("/api/devices/:id/reject",zS);tl.post("/api/devices/:id/block",US);tl.post("/api/devices/:id/unblock",BS);tl.delete("/api/devices/:id/request-history",OS);tl.get("/api/devices/peer-connections",MS);tl.post("/api/devices/:id/connect",fS);tl.post("/api/devices/peer-connections/:connectionId/disconnect",jS);tl.post("/api/devices/peer-connections/:connectionId/terminal",KS);tl.get("/api/devices/peer-connections/:connectionId/terminals",SS);tl.get("/api/devices/peer-connections/:connectionId/terminal/:terminalId/read",qS);tl.post("/api/devices/peer-connections/:connectionId/terminal/:terminalId/input",TS);tl.post("/api/devices/peer-connections/:connectionId/terminal/:terminalId/resize",DS);tl.post("/api/devices/peer-connections/:connectionId/terminal/:terminalId/close",PS);tl.post("/api/devices/peer-connections/:connectionId/exec",_S);tl.post("/api/devices/peer-connections/:connectionId/download",$S);tl.post("/api/devices/peer-connections/:connectionId/upload",IT);var TT=require("child_process"),DT=require("crypto"),sc=require("fs"),WG=require("fs/promises"),ar=require("os"),oI=require("path"),qT=require("util");CI();Sl();var gw=require("stream");CI();function uw(I){let l=String(I||"").trim().replace(/\/+$/,"");if(!l)throw new Error("baseUrl is required");return new URL(l)}function pw(I){return I.pathname.replace(/\/+$/,"")}function ja(I,l){return`${I.replace(/\/+$/,"")}/${l.replace(/^\/+/,"")}`}function ow(I,l){return I.toLowerCase().endsWith(`/${l.toLowerCase()}`)}function GT(I){let l=I.toLowerCase(),G=l.split("/").filter(Boolean),c=G[G.length-1]||"";return!!(/^v\d+(?:beta)?$/.test(c)||c==="openai"||/\/api\/paas\/v\d+$/.test(l)||/\/coding\/v\d+$/.test(l)||/\/step_plan\/v\d+$/.test(l))}function WEI(I){let G=I.toLowerCase().split("/").filter(Boolean),c=G[G.length-1]||"";return/^v\d+(?:beta)?$/.test(c)}function IN(I){let l=uw(I),G=pw(l),c=l.toString().replace(/\/+$/,"");return ow(G,"chat/completions")?c:GT(G)?ja(c,"chat/completions"):ja(c,"v1/chat/completions")}function Ka(I){let l=uw(I),G=pw(l),c=l.toString().replace(/\/+$/,"");return ow(G,"responses")?c:GT(G)?ja(c,"responses"):ja(c,"v1/responses")}function lr(I){let l=uw(I),G=pw(l),c=l.toString().replace(/\/+$/,"");return ow(G,"messages")?c:WEI(G)?ja(c,"messages"):ja(c,"v1/messages")}function rw(I){let l,G=[];for(let c of I.split(/\r?\n/))if(!(!c||c.startsWith(":"))){if(c.startsWith("event:")){l=c.slice(6).trim();continue}c.startsWith("data:")&&G.push(c.slice(5).trimStart())}return G.length?{event:l,data:G.join(`
|
|
@@ -1215,7 +1215,7 @@ ${G.instructions}`:ce();if(G.session_id){let t=hI(G.session_id)?.workspace||Stri
|
|
|
1215
1215
|
${`[Current working directory: ${t}]`}
|
|
1216
1216
|
${Z}`)}await QdI(this.nsp,l,{...G,instructions:Z},c,this.sessionMap,this.bridge,e,AR,this.dequeueNextQueuedRun.bind(this));return}if(b==="coding_agent"){await ydI(this.nsp,l,G,c,this.sessionMap);return}await mdI(this.nsp,l,G,c,this.sessionMap,e,this.dequeueNextQueuedRun.bind(this))}}async resumeSession(l,G){let c=this.sessionMap.get(G);c||(c=await AR(G,this.sessionMap),this.sessionMap.set(G,c)),await this.reattachBridgeRun(l,G,c);let e=c.isWorking?c.events:(c.events||[]).filter(b=>b?.event==="run.reattach_failed");l.emit("resumed",{session_id:G,messages:c.messages,messageTotal:c.messageTotal,messageLoadedCount:c.messageLoadedCount,messagePageLimit:c.messagePageLimit,hasMoreBefore:c.hasMoreBefore,isWorking:c.isWorking,isAborting:c.isAborting||!1,events:e,inputTokens:c.inputTokens,outputTokens:c.outputTokens,contextTokens:c.contextTokens,queueLength:c.queue?.length||0,queueMessages:this.serializeQueuedMessages(c.queue||[])}),V.info("[chat-run-socket] socket %s resumed session %s (working: %s, messages: %d)",l.id,G,c.isWorking,c.messages.length)}async reattachBridgeRun(l,G,c){if(c.runId&&c.isWorking)return;let e=hI(G),b=e?.profile||MMI(l),d;try{let Z=await this.bridge.statusIfLoaded(G,b,{timeoutMs:1e3}),n=Z.running===!0,t=typeof Z.current_run_id=="string"?Z.current_run_id:"";if(!n||!t||(d=`${G}:${t}`,this.bridgeResumePolls.has(d)))return;this.bridgeResumePolls.add(d),c.isWorking=!0,c.isAborting=c.isAborting===!0,c.runId=t,c.activeRunMarker=void 0,c.profile=b,c.source="cli",c.events=[];let a=this.resumeInstructionsForSession(G);wdI(this.nsp,l,{sessionId:G,runId:t,profile:b,instructions:a,model:e?.model,provider:e?.provider},this.sessionMap,this.bridge,this.dequeueNextQueuedRun.bind(this)).finally(()=>{d&&this.bridgeResumePolls.delete(d)}),V.info("[chat-run-socket] reattached running bridge run %s for session %s",t,G)}catch(Z){d&&this.bridgeResumePolls.delete(d),V.warn(Z,"[chat-run-socket] bridge status lookup failed while resuming session %s",G);let n=Ib().getRuntimeState?.().endpoint,t=NJ(Z instanceof Error?Z.message:String(Z),n),a={event:"run.reattach_failed",session_id:G,error:t,message:`Unable to confirm Agent Bridge status while resuming: ${t}`,text:`Unable to confirm Agent Bridge status while resuming: ${t}`},W=[...c.events||[]],m=W[W.length-1];(m?.event!=="run.reattach_failed"||m?.data?.error!==t)&&(W.push({event:"run.reattach_failed",data:a}),c.events=W),this.emitToSession(l,G,"run.reattach_failed",a)}}resumeInstructionsForSession(l){let G=ce(),c=hI(l);return c?.workspace&&(G=`
|
|
1217
1217
|
[Current working directory: ${c.workspace}]
|
|
1218
|
-
${G}`),G}dequeueNextQueuedRun(l,G,c="default"){let e=this.sessionMap.get(G);if(!e?.queue.length)return!1;let b=e.queue.shift();return e.isWorking=!0,e.profile=b.profile||c,e.source=b.source,V.info("[chat-run-socket] dequeuing queued run for session %s (remaining: %d)",G,e.queue.length),this.nsp.to(`session:${G}`).emit("run.queued",{event:"run.queued",session_id:G,queue_length:e.queue.length,dequeued_queue_id:b.queue_id,queued_messages:this.serializeQueuedMessages(e.queue)}),this.runQueuedItem(l,G,b,c),!0}runQueuedItem(l,G,c,e="default"){let b=c.displayInput===null;this.handleRun(l,{input:c.input,display_input:c.displayInput,display_role:c.displayRole,storage_message:c.storageMessage,session_id:G,model:c.model,provider:c.provider,model_groups:c.model_groups,instructions:c.instructions,workspace:c.workspace,source:c.source,queue_id:c.queue_id,peerExcludeSocketId:c.originSocketId,coding_agent_id:c.codingAgentId,agent_id:c.agentId,mode:c.mode,baseUrl:c.baseUrl,base_url:c.base_url,apiKey:c.apiKey,api_key:c.api_key,apiMode:c.apiMode,api_mode:c.api_mode},c.profile||e,b)}emitExternalEvent(l,G,c){let e={...c,session_id:l},b=this.sessionMap.get(l);b?.isWorking&&(b.events.push({event:G,data:e}),b.events.length>200&&b.events.splice(0,b.events.length-200)),this.nsp.to(`session:${l}`).emit(G,e)}markExternalRunCompleted(l,G){let c=this.sessionMap.get(l);if(c&&(c.isWorking=!1,c.abortController=void 0,c.runId=void 0,c.activeRunMarker=void 0,c.events=[],c.responseRun=void 0,c.profile=void 0,V.info("[chat-run-socket] external run completed for session %s (%s)",l,G),c.queue.length>0)){let e=this.socketForQueuedRun(l,c.queue[0]);e&&this.dequeueNextQueuedRun(e,l)}}socketForQueuedRun(l,G){if(G?.originSocketId){let e=this.nsp.sockets.get(G.originSocketId);if(e)return e}let c=this.nsp.adapter.rooms.get(`session:${l}`);if(c)for(let e of c){let b=this.nsp.sockets.get(e);if(b)return b}return this.nsp.sockets.values().next().value||null}clearClarifyEventState(l,G){let c=this.sessionMap.get(l);if(!c?.events.length)return;let e=c.events.filter(({event:b,data:d})=>b!=="clarify.requested"&&b!=="clarify.resolved"?!0:d?.clarify_id!==G);e.length!==c.events.length&&(c.events=e)}emitToSession(l,G,c,e){let b={...e,session_id:G};this.nsp.to(`session:${G}`).emit(c,b),!this.nsp.adapter.rooms.get(`session:${G}`)?.size&&l.connected&&l.emit(c,b)}serializeQueuedMessages(l){return l.filter(G=>G.displayInput!==null).map(G=>({id:G.queue_id,role:G.displayRole||(typeof G.displayInput=="string"&&G.displayInput.trim().startsWith("/")?"command":"user"),content:Ge(G.displayInput??G.input),timestamp:Math.floor(Date.now()/1e3),queued:!0}))}canAccessProfile(l,G){return l.role==="super_admin"||Ea(l.id,G)}close(){for(let[l,G]of this.sessionMap.entries())if(G.abortController)try{G.abortController.abort()}catch(c){V.warn(c,"[chat-run-socket] failed to abort controller for session %s",l)}this.sessionMap.clear(),V.info("[chat-run-socket] closed all connections and cleared state")}};var zdI=require("node:fs"),UdI=require("node:os"),UR=require("node:path");CI();Sl();GI();VI();var JZ="hermes-studio",BR="HERMES_WEB_UI_MANAGED_MCP",jMI=new Set(["hermes-lan-peer-mcp","hermes-devices-mcp","hermes-web-ui-mcp","hermes-studio-mcp"]);function BdI(I){return["1","true","yes","on"].includes(String(I||"").trim().toLowerCase())}function KMI(){return BdI(process.env.HERMES_WEB_UI_DISABLE_MCP_AUTOINJECT)}function SMI(){return BdI(process.env.HERMES_WEB_UI_ALLOW_TRANSIENT_MCP_AUTOINJECT)}function xdI(I){return I.replace(/\/+$/,"")+"/"}function TMI(I){let l=xdI(I);return[(0,UdI.tmpdir)(),"/tmp","/private/tmp"].filter(Boolean).map(c=>xdI(c)).some(c=>l.startsWith(c))}function DMI(){return TMI(y.appHome)&&!SMI()}function qMI(){return String(process.env.HERMES_DESKTOP||"").trim().toLowerCase()==="true"}function OdI(){return[process.env.HERMES_WEB_UI_MCP_BIN,(0,UR.join)(process.cwd(),"bin/hermes-web-ui-mcp.mjs"),(0,UR.join)(__dirname,"../../bin/hermes-web-ui-mcp.mjs"),(0,UR.join)(__dirname,"../../../../../bin/hermes-web-ui-mcp.mjs")].filter(I=>!!I)}function PMI(){return OdI().find(I=>(0,zdI.existsSync)(I))||null}function _MI(){if(qMI())return{command:"hermes-studio-mcp"};let I=PMI();return I?{command:process.execPath,args:[I]}:(V.warn({candidates:OdI()},"[mcp-autoinject] bundled MCP script not found; falling back to PATH command"),{command:"hermes-web-ui-mcp"})}function $MI(){let I={HERMES_WEB_UI_URL:`http://127.0.0.1:${y.port}`,HERMES_WEB_UI_HOME:y.appHome,HERMES_WEBUI_STATE_DIR:y.appHome,[BR]:"1"};return{..._MI(),env:I,enabled:!0}}function sm(I){return!!I&&typeof I=="object"&&!Array.isArray(I)}function IfI(I){return sm(I)?sm(I.env)&&I.env[BR]==="1"?!0:typeof I.command=="string"&&jMI.has(I.command):!1}function lfI(I,l){let G=Array.isArray(l.args)?l.args:void 0,c=Array.isArray(I.args)?I.args:void 0;return!G&&!c?!0:!G||!c?!1:G.length===c.length&&G.every((e,b)=>c[b]===e)}function GfI(I,l){let G=l.env;return I.command===l.command&&lfI(I,l)&&I.enabled!==!1&&sm(I.env)&&I.env.HERMES_WEB_UI_URL===G.HERMES_WEB_UI_URL&&I.env.HERMES_WEB_UI_HOME===G.HERMES_WEB_UI_HOME&&I.env.HERMES_WEBUI_STATE_DIR===G.HERMES_WEBUI_STATE_DIR&&I.env.HERMES_WEB_UI_TOKEN===void 0&&I.env[BR]===G[BR]}async function cfI(I,l){return await qG(I,G=>{let c=sm(G)?G:{};sm(c.mcp_servers)||(c.mcp_servers={});let e=c.mcp_servers[JZ];return e?IfI(e)?sm(e)&&e.enabled===!1?{data:c,write:!1,result:{profile:I,status:"skipped",reason:`existing ${JZ} MCP server is disabled by user`}}:GfI(e,l)?{data:c,write:!1,result:{profile:I,status:"unchanged"}}:(c.mcp_servers[JZ]=l,{data:c,result:{profile:I,status:"updated"}}):{data:c,write:!1,result:{profile:I,status:"skipped",reason:`existing ${JZ} MCP server is not managed by Hermes Web UI`}}:(c.mcp_servers[JZ]=l,{data:c,result:{profile:I,status:"injected"}})})}async function MdI(){let I=$MI(),l={serverName:JZ,command:String(I.command),targets:[]};if(KMI())return V.info("[mcp-autoinject] disabled by HERMES_WEB_UI_DISABLE_MCP_AUTOINJECT"),l;if(DMI())return V.info({appHome:y.appHome},"[mcp-autoinject] skipped for transient Web UI home"),l;for(let e of DI())l.targets.push(await cfI(e,I));let G=l.targets.filter(e=>e.status==="injected"||e.status==="updated");G.length>0&&V.info({serverName:JZ,command:I.command,targets:G},"[mcp-autoinject] synced bundled MCP server");let c=l.targets.filter(e=>e.status==="skipped");return c.length>0&&V.warn({serverName:JZ,targets:c},"[mcp-autoinject] skipped unmanaged MCP server entries"),l}za();GI();var bfI="0.6.18";process.on("uncaughtException",I=>{console.error("FATAL: Uncaught exception"),console.error(I),V.fatal(I,"Uncaught exception"),process.exit(1)});process.on("unhandledRejection",I=>{console.error("Unhandled rejection"),console.error(I),V.error(I,"Unhandled rejection")});var dfI=null,CZ=[],OR=null,MR=null;function ZfI(I,l,G){return new Promise((c,e)=>{let b=I.listen(l,G);b.once("listening",()=>c(b)),b.once("error",e)})}async function nfI(I,l,G){let c=G||"0.0.0.0";console.log(`[bootstrap] listening on ${c}:${l}`);let e=await ZfI(I,l,c);return{primary:e,servers:[e]}}function tfI(){try{return qdI.default.networkInterfaces()}catch{return{}}}function KdI(){return String(process.env.HERMES_DESKTOP||"").trim().toLowerCase()==="true"}function _dI(I){let l=String(process.env[I]||"").trim().toLowerCase();return["1","true","yes","on"].includes(l)}function $dI(){return _dI("HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART")}function afI(){return _dI("HERMES_WEB_UI_DISABLE_SKILL_INJECTION")}async function WfI(){if($dI())console.log("[bootstrap] profile gateway check disabled by HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART");else try{await gQ(),console.log("[bootstrap] profile gateways checked")}catch(I){V.warn(I,"[bootstrap] failed to ensure profile gateways"),console.warn("[bootstrap] failed to ensure profile gateways:",I instanceof Error?I.message:I)}try{MR=await SQ(),console.log("[bootstrap] agent bridge started")}catch(I){V.warn(I,"[bootstrap] agent bridge failed to start"),console.warn("[bootstrap] agent bridge failed to start:",I instanceof Error?I.message:I)}}function mfI(){$dI()?console.log("[bootstrap] profile gateway check disabled by HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART"):(async()=>{try{await gQ(),console.log("[bootstrap] profile gateways checked")}catch(I){V.warn(I,"[bootstrap] failed to ensure profile gateways"),console.warn("[bootstrap] failed to ensure profile gateways:",I instanceof Error?I.message:I)}})(),(async()=>{try{MR=await SQ(),console.log("[bootstrap] agent bridge started")}catch(I){V.warn(I,"[bootstrap] agent bridge failed to start"),console.warn("[bootstrap] agent bridge failed to start:",I instanceof Error?I.message:I);return}})()}function sfI(){let I=NS({httpPort:y.port}),l=!1,G=()=>{l||(l=!0,Ko().catch(c=>V.warn(c,"[lan-discovery] initial scan failed")))};I?(I.once("listening",G),setTimeout(G,500).unref?.()):G()}async function IZI(){if(console.log(`hermes-web-ui v${bfI} starting...`),await(0,YJ.mkdir)(y.uploadDir,{recursive:!0}),Ix()&&await(0,YJ.mkdir)(y.dataDir,{recursive:!0}),await Wx(),afI())console.log("[bootstrap] bundled skill injection disabled by HERMES_WEB_UI_DISABLE_SKILL_INJECTION");else try{let m=await new xn().injectMissingSkills();m.injected.length>0&&V.info({injected:[...new Set(m.injected)],targetCount:m.targets.length},"[bootstrap] bundled skills injected"),m.updated.length>0&&V.info({updated:[...new Set(m.updated)],targetCount:m.targets.length},"[bootstrap] bundled skills updated")}catch(W){V.warn(W,"[bootstrap] failed to inject bundled skills"),console.warn("[bootstrap] failed to inject bundled skills:",W instanceof Error?W.message:W)}try{await MdI()}catch(W){V.warn(W,"[bootstrap] failed to inject bundled MCP server"),console.warn("[bootstrap] failed to inject bundled MCP server:",W instanceof Error?W.message:W)}KdI()||await WfI();let I=new aL;await new Promise(W=>setTimeout(W,1e3));let{initAllStores:l}=await Promise.resolve().then(()=>(jdI(),fdI));l(),await new Promise(W=>setTimeout(W,1e3)),console.log("[bootstrap] all stores initialized"),I.use(Mf()),I.use((0,SdI.default)({origin:Bf(y.corsOrigins)})),I.use(K3({encoding:"utf-8",jsonLimit:"20mb",formLimit:"20mb",textLimit:"20mb",parsedMethods:["POST","PUT","PATCH","DELETE"]})),console.log("[bootstrap] cors + bodyParser registered");let G=jcI(I,[zf,Uf]);I.use(G),console.log("[bootstrap] routes registered");let c=(0,PdI.resolve)(__dirname,"..","client");I.use((0,TdI.default)(c)),I.use(async W=>{!W.path.startsWith("/api")&&W.path!=="/health"&&W.path!=="/upload"&&W.path!=="/webhook"&&await(0,DdI.default)(W,"index.html",{root:c})}),console.log("[bootstrap] SPA fallback registered");let e=await nfI(I,y.port,y.host);dfI=e.primary,CZ=e.servers,console.log("[bootstrap] app.listen called"),Kf(CZ),pj(CZ),mc().setupServer(CZ),console.log("[bootstrap] terminal + kanban + LAN peer websocket setup");let b=new yR(CZ);Iq(b),OR=new zR(b.getIO()),ZH(OR),OR.init();let{SessionDeleter:d}=await Promise.resolve().then(()=>(Cr(),Hq)),Z=d.getInstance(),n=process.env.PROFILE||"default";Z.start(n),console.log("[bootstrap] session deleter started, profile=%s",n),CZ.forEach(W=>{W.on("upgrade",(m,s)=>{let N=new URL(m.url||"",`http://${m.headers.host}`);N.pathname!=="/api/hermes/terminal"&&N.pathname!=="/api/hermes/kanban/events"&&N.pathname!==iS()&&!N.pathname.startsWith("/socket.io/")&&s.destroy()})});let t=tfI(),a=Object.values(t).flat().find(W=>W?.family==="IPv4"&&!W?.internal)?.address||"localhost";console.log(`Server: http://localhost:${y.port} (LAN: http://${a}:${y.port})`),console.log(`Log: ${y.appHome}/logs/server.log`),V.info("Server: http://localhost:%d (LAN: http://%s:%d)",y.port,a,y.port),sfI(),hP("bootstrap"),KdI()&&(MR=Ib(),mfI()),b.restoreWhenReady(),CZ.forEach(W=>{W.on("error",m=>{console.error("[bootstrap] server error:",m.code||m.message),V.error({err:m},"Server error")})}),dO(CZ,b,OR,MR),TQ()}IZI().catch(I=>{console.error("FATAL: Failed to start Hermes Web UI"),console.error(I),V.fatal(I,"Fatal error during bootstrap"),process.exit(1)});0&&(module.exports={bootstrap});
|
|
1218
|
+
${G}`),G}dequeueNextQueuedRun(l,G,c="default"){let e=this.sessionMap.get(G);if(!e?.queue.length)return!1;let b=e.queue.shift();return e.isWorking=!0,e.profile=b.profile||c,e.source=b.source,V.info("[chat-run-socket] dequeuing queued run for session %s (remaining: %d)",G,e.queue.length),this.nsp.to(`session:${G}`).emit("run.queued",{event:"run.queued",session_id:G,queue_length:e.queue.length,dequeued_queue_id:b.queue_id,queued_messages:this.serializeQueuedMessages(e.queue)}),this.runQueuedItem(l,G,b,c),!0}runQueuedItem(l,G,c,e="default"){let b=c.displayInput===null;this.handleRun(l,{input:c.input,display_input:c.displayInput,display_role:c.displayRole,storage_message:c.storageMessage,session_id:G,model:c.model,provider:c.provider,model_groups:c.model_groups,instructions:c.instructions,workspace:c.workspace,source:c.source,queue_id:c.queue_id,peerExcludeSocketId:c.originSocketId,coding_agent_id:c.codingAgentId,agent_id:c.agentId,mode:c.mode,baseUrl:c.baseUrl,base_url:c.base_url,apiKey:c.apiKey,api_key:c.api_key,apiMode:c.apiMode,api_mode:c.api_mode},c.profile||e,b)}emitExternalEvent(l,G,c){let e={...c,session_id:l},b=this.sessionMap.get(l);b?.isWorking&&(b.events.push({event:G,data:e}),b.events.length>200&&b.events.splice(0,b.events.length-200)),this.nsp.to(`session:${l}`).emit(G,e)}markExternalRunCompleted(l,G){let c=this.sessionMap.get(l);if(c&&(c.isWorking=!1,c.abortController=void 0,c.runId=void 0,c.activeRunMarker=void 0,c.events=[],c.responseRun=void 0,c.profile=void 0,V.info("[chat-run-socket] external run completed for session %s (%s)",l,G),c.queue.length>0)){let e=this.socketForQueuedRun(l,c.queue[0]);e&&this.dequeueNextQueuedRun(e,l)}}socketForQueuedRun(l,G){if(G?.originSocketId){let e=this.nsp.sockets.get(G.originSocketId);if(e)return e}let c=this.nsp.adapter.rooms.get(`session:${l}`);if(c)for(let e of c){let b=this.nsp.sockets.get(e);if(b)return b}return this.nsp.sockets.values().next().value||null}clearClarifyEventState(l,G){let c=this.sessionMap.get(l);if(!c?.events.length)return;let e=c.events.filter(({event:b,data:d})=>b!=="clarify.requested"&&b!=="clarify.resolved"?!0:d?.clarify_id!==G);e.length!==c.events.length&&(c.events=e)}emitToSession(l,G,c,e){let b={...e,session_id:G};this.nsp.to(`session:${G}`).emit(c,b),!this.nsp.adapter.rooms.get(`session:${G}`)?.size&&l.connected&&l.emit(c,b)}serializeQueuedMessages(l){return l.filter(G=>G.displayInput!==null).map(G=>({id:G.queue_id,role:G.displayRole||(typeof G.displayInput=="string"&&G.displayInput.trim().startsWith("/")?"command":"user"),content:Ge(G.displayInput??G.input),timestamp:Math.floor(Date.now()/1e3),queued:!0}))}canAccessProfile(l,G){return l.role==="super_admin"||Ea(l.id,G)}close(){for(let[l,G]of this.sessionMap.entries())if(G.abortController)try{G.abortController.abort()}catch(c){V.warn(c,"[chat-run-socket] failed to abort controller for session %s",l)}this.sessionMap.clear(),V.info("[chat-run-socket] closed all connections and cleared state")}};var zdI=require("node:fs"),UdI=require("node:os"),UR=require("node:path");CI();Sl();GI();VI();var JZ="hermes-studio",BR="HERMES_WEB_UI_MANAGED_MCP",jMI=new Set(["hermes-lan-peer-mcp","hermes-devices-mcp","hermes-web-ui-mcp","hermes-studio-mcp"]);function BdI(I){return["1","true","yes","on"].includes(String(I||"").trim().toLowerCase())}function KMI(){return BdI(process.env.HERMES_WEB_UI_DISABLE_MCP_AUTOINJECT)}function SMI(){return BdI(process.env.HERMES_WEB_UI_ALLOW_TRANSIENT_MCP_AUTOINJECT)}function xdI(I){return I.replace(/\/+$/,"")+"/"}function TMI(I){let l=xdI(I);return[(0,UdI.tmpdir)(),"/tmp","/private/tmp"].filter(Boolean).map(c=>xdI(c)).some(c=>l.startsWith(c))}function DMI(){return TMI(y.appHome)&&!SMI()}function qMI(){return String(process.env.HERMES_DESKTOP||"").trim().toLowerCase()==="true"}function OdI(){return[process.env.HERMES_WEB_UI_MCP_BIN,(0,UR.join)(process.cwd(),"bin/hermes-web-ui-mcp.mjs"),(0,UR.join)(__dirname,"../../bin/hermes-web-ui-mcp.mjs"),(0,UR.join)(__dirname,"../../../../../bin/hermes-web-ui-mcp.mjs")].filter(I=>!!I)}function PMI(){return OdI().find(I=>(0,zdI.existsSync)(I))||null}function _MI(){if(qMI())return{command:"hermes-studio-mcp"};let I=PMI();return I?{command:process.execPath,args:[I]}:(V.warn({candidates:OdI()},"[mcp-autoinject] bundled MCP script not found; falling back to PATH command"),{command:"hermes-web-ui-mcp"})}function $MI(){let I={HERMES_WEB_UI_URL:`http://127.0.0.1:${y.port}`,HERMES_WEB_UI_HOME:y.appHome,HERMES_WEBUI_STATE_DIR:y.appHome,[BR]:"1"};return{..._MI(),env:I,enabled:!0}}function sm(I){return!!I&&typeof I=="object"&&!Array.isArray(I)}function IfI(I){return sm(I)?sm(I.env)&&I.env[BR]==="1"?!0:typeof I.command=="string"&&jMI.has(I.command):!1}function lfI(I,l){let G=Array.isArray(l.args)?l.args:void 0,c=Array.isArray(I.args)?I.args:void 0;return!G&&!c?!0:!G||!c?!1:G.length===c.length&&G.every((e,b)=>c[b]===e)}function GfI(I,l){let G=l.env;return I.command===l.command&&lfI(I,l)&&I.enabled!==!1&&sm(I.env)&&I.env.HERMES_WEB_UI_URL===G.HERMES_WEB_UI_URL&&I.env.HERMES_WEB_UI_HOME===G.HERMES_WEB_UI_HOME&&I.env.HERMES_WEBUI_STATE_DIR===G.HERMES_WEBUI_STATE_DIR&&I.env.HERMES_WEB_UI_TOKEN===void 0&&I.env[BR]===G[BR]}async function cfI(I,l){return await qG(I,G=>{let c=sm(G)?G:{};sm(c.mcp_servers)||(c.mcp_servers={});let e=c.mcp_servers[JZ];return e?IfI(e)?sm(e)&&e.enabled===!1?{data:c,write:!1,result:{profile:I,status:"skipped",reason:`existing ${JZ} MCP server is disabled by user`}}:GfI(e,l)?{data:c,write:!1,result:{profile:I,status:"unchanged"}}:(c.mcp_servers[JZ]=l,{data:c,result:{profile:I,status:"updated"}}):{data:c,write:!1,result:{profile:I,status:"skipped",reason:`existing ${JZ} MCP server is not managed by Hermes Web UI`}}:(c.mcp_servers[JZ]=l,{data:c,result:{profile:I,status:"injected"}})})}async function MdI(){let I=$MI(),l={serverName:JZ,command:String(I.command),targets:[]};if(KMI())return V.info("[mcp-autoinject] disabled by HERMES_WEB_UI_DISABLE_MCP_AUTOINJECT"),l;if(DMI())return V.info({appHome:y.appHome},"[mcp-autoinject] skipped for transient Web UI home"),l;for(let e of DI())l.targets.push(await cfI(e,I));let G=l.targets.filter(e=>e.status==="injected"||e.status==="updated");G.length>0&&V.info({serverName:JZ,command:I.command,targets:G},"[mcp-autoinject] synced bundled MCP server");let c=l.targets.filter(e=>e.status==="skipped");return c.length>0&&V.warn({serverName:JZ,targets:c},"[mcp-autoinject] skipped unmanaged MCP server entries"),l}za();GI();var bfI="0.6.19";process.on("uncaughtException",I=>{console.error("FATAL: Uncaught exception"),console.error(I),V.fatal(I,"Uncaught exception"),process.exit(1)});process.on("unhandledRejection",I=>{console.error("Unhandled rejection"),console.error(I),V.error(I,"Unhandled rejection")});var dfI=null,CZ=[],OR=null,MR=null;function ZfI(I,l,G){return new Promise((c,e)=>{let b=I.listen(l,G);b.once("listening",()=>c(b)),b.once("error",e)})}async function nfI(I,l,G){let c=G||"0.0.0.0";console.log(`[bootstrap] listening on ${c}:${l}`);let e=await ZfI(I,l,c);return{primary:e,servers:[e]}}function tfI(){try{return qdI.default.networkInterfaces()}catch{return{}}}function KdI(){return String(process.env.HERMES_DESKTOP||"").trim().toLowerCase()==="true"}function _dI(I){let l=String(process.env[I]||"").trim().toLowerCase();return["1","true","yes","on"].includes(l)}function $dI(){return _dI("HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART")}function afI(){return _dI("HERMES_WEB_UI_DISABLE_SKILL_INJECTION")}async function WfI(){if($dI())console.log("[bootstrap] profile gateway check disabled by HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART");else try{await gQ(),console.log("[bootstrap] profile gateways checked")}catch(I){V.warn(I,"[bootstrap] failed to ensure profile gateways"),console.warn("[bootstrap] failed to ensure profile gateways:",I instanceof Error?I.message:I)}try{MR=await SQ(),console.log("[bootstrap] agent bridge started")}catch(I){V.warn(I,"[bootstrap] agent bridge failed to start"),console.warn("[bootstrap] agent bridge failed to start:",I instanceof Error?I.message:I)}}function mfI(){$dI()?console.log("[bootstrap] profile gateway check disabled by HERMES_WEB_UI_DISABLE_GATEWAY_AUTOSTART"):(async()=>{try{await gQ(),console.log("[bootstrap] profile gateways checked")}catch(I){V.warn(I,"[bootstrap] failed to ensure profile gateways"),console.warn("[bootstrap] failed to ensure profile gateways:",I instanceof Error?I.message:I)}})(),(async()=>{try{MR=await SQ(),console.log("[bootstrap] agent bridge started")}catch(I){V.warn(I,"[bootstrap] agent bridge failed to start"),console.warn("[bootstrap] agent bridge failed to start:",I instanceof Error?I.message:I);return}})()}function sfI(){let I=NS({httpPort:y.port}),l=!1,G=()=>{l||(l=!0,Ko().catch(c=>V.warn(c,"[lan-discovery] initial scan failed")))};I?(I.once("listening",G),setTimeout(G,500).unref?.()):G()}async function IZI(){if(console.log(`hermes-web-ui v${bfI} starting...`),await(0,YJ.mkdir)(y.uploadDir,{recursive:!0}),Ix()&&await(0,YJ.mkdir)(y.dataDir,{recursive:!0}),await Wx(),afI())console.log("[bootstrap] bundled skill injection disabled by HERMES_WEB_UI_DISABLE_SKILL_INJECTION");else try{let m=await new xn().injectMissingSkills();m.injected.length>0&&V.info({injected:[...new Set(m.injected)],targetCount:m.targets.length},"[bootstrap] bundled skills injected"),m.updated.length>0&&V.info({updated:[...new Set(m.updated)],targetCount:m.targets.length},"[bootstrap] bundled skills updated")}catch(W){V.warn(W,"[bootstrap] failed to inject bundled skills"),console.warn("[bootstrap] failed to inject bundled skills:",W instanceof Error?W.message:W)}try{await MdI()}catch(W){V.warn(W,"[bootstrap] failed to inject bundled MCP server"),console.warn("[bootstrap] failed to inject bundled MCP server:",W instanceof Error?W.message:W)}KdI()||await WfI();let I=new aL;await new Promise(W=>setTimeout(W,1e3));let{initAllStores:l}=await Promise.resolve().then(()=>(jdI(),fdI));l(),await new Promise(W=>setTimeout(W,1e3)),console.log("[bootstrap] all stores initialized"),I.use(Mf()),I.use((0,SdI.default)({origin:Bf(y.corsOrigins)})),I.use(K3({encoding:"utf-8",jsonLimit:"20mb",formLimit:"20mb",textLimit:"20mb",parsedMethods:["POST","PUT","PATCH","DELETE"]})),console.log("[bootstrap] cors + bodyParser registered");let G=jcI(I,[zf,Uf]);I.use(G),console.log("[bootstrap] routes registered");let c=(0,PdI.resolve)(__dirname,"..","client");I.use((0,TdI.default)(c)),I.use(async W=>{!W.path.startsWith("/api")&&W.path!=="/health"&&W.path!=="/upload"&&W.path!=="/webhook"&&await(0,DdI.default)(W,"index.html",{root:c})}),console.log("[bootstrap] SPA fallback registered");let e=await nfI(I,y.port,y.host);dfI=e.primary,CZ=e.servers,console.log("[bootstrap] app.listen called"),Kf(CZ),pj(CZ),mc().setupServer(CZ),console.log("[bootstrap] terminal + kanban + LAN peer websocket setup");let b=new yR(CZ);Iq(b),OR=new zR(b.getIO()),ZH(OR),OR.init();let{SessionDeleter:d}=await Promise.resolve().then(()=>(Cr(),Hq)),Z=d.getInstance(),n=process.env.PROFILE||"default";Z.start(n),console.log("[bootstrap] session deleter started, profile=%s",n),CZ.forEach(W=>{W.on("upgrade",(m,s)=>{let N=new URL(m.url||"",`http://${m.headers.host}`);N.pathname!=="/api/hermes/terminal"&&N.pathname!=="/api/hermes/kanban/events"&&N.pathname!==iS()&&!N.pathname.startsWith("/socket.io/")&&s.destroy()})});let t=tfI(),a=Object.values(t).flat().find(W=>W?.family==="IPv4"&&!W?.internal)?.address||"localhost";console.log(`Server: http://localhost:${y.port} (LAN: http://${a}:${y.port})`),console.log(`Log: ${y.appHome}/logs/server.log`),V.info("Server: http://localhost:%d (LAN: http://%s:%d)",y.port,a,y.port),sfI(),hP("bootstrap"),KdI()&&(MR=Ib(),mfI()),b.restoreWhenReady(),CZ.forEach(W=>{W.on("error",m=>{console.error("[bootstrap] server error:",m.code||m.message),V.error({err:m},"Server error")})}),dO(CZ,b,OR,MR),TQ()}IZI().catch(I=>{console.error("FATAL: Failed to start Hermes Web UI"),console.error(I),V.fatal(I,"Fatal error during bootstrap"),process.exit(1)});0&&(module.exports={bootstrap});
|
|
1219
1219
|
/*! Bundled license information:
|
|
1220
1220
|
|
|
1221
1221
|
ee-first/index.js:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quanthermes/hermes-web-ui",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.19",
|
|
4
4
|
"description": "Self-hosted AI chat dashboard for Hermes Agent — multi-model web UI with multi-platform integration",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -52,11 +52,13 @@
|
|
|
52
52
|
"desktop:install": "npm ci --prefix packages/desktop --no-audit --no-fund",
|
|
53
53
|
"desktop:prepare-runtime": "npm --prefix packages/desktop run prepare:runtime",
|
|
54
54
|
"desktop:prepare-python": "npm --prefix packages/desktop run prepare:python",
|
|
55
|
-
"build:desktop": "npm run build && npm run desktop:install && npm --prefix packages/desktop run dist -- --publish never",
|
|
56
|
-
"build:desktop:mac": "npm run build && npm run desktop:install && npm --prefix packages/desktop run dist -- --mac --publish never",
|
|
57
|
-
"build:desktop:win": "npm run build && npm run desktop:install && npm --prefix packages/desktop run dist -- --win --publish never",
|
|
58
|
-
"build:desktop:linux": "npm run build && npm run desktop:install && npm --prefix packages/desktop run dist -- --linux --publish never",
|
|
55
|
+
"build:desktop": "npm run build && npm run desktop:install && npm --prefix packages/desktop run write:runtime-release && npm --prefix packages/desktop run dist -- --publish never",
|
|
56
|
+
"build:desktop:mac": "npm run build && npm run desktop:install && npm --prefix packages/desktop run write:runtime-release && npm --prefix packages/desktop run dist -- --mac --publish never",
|
|
57
|
+
"build:desktop:win": "npm run build && npm run desktop:install && npm --prefix packages/desktop run write:runtime-release && npm --prefix packages/desktop run dist -- --win --publish never",
|
|
58
|
+
"build:desktop:linux": "npm run build && npm run desktop:install && npm --prefix packages/desktop run write:runtime-release && npm --prefix packages/desktop run dist -- --linux --publish never",
|
|
59
59
|
"build:device-package": "node scripts/build-device-package.mjs",
|
|
60
|
+
"check:release-consistency": "node scripts/check-release-consistency.mjs",
|
|
61
|
+
"test:device-package-release": "npm run check:release-consistency && vitest run tests/server/update-manifest-client.test.ts tests/server/build-device-package-script.test.ts tests/server/device-package-strategy.test.ts tests/server/update-controller.test.ts tests/server/device-package-contract.test.ts tests/server/config.test.ts tests/server/update-task-store.test.ts",
|
|
60
62
|
"openapi:generate": "node scripts/generate-openapi.mjs",
|
|
61
63
|
"prepublishOnly": "npm run build",
|
|
62
64
|
"release:npm": "npm publish --access public",
|