hermes-web-ui 0.3.7 → 0.4.0
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/README.md +28 -12
- package/dist/client/assets/{Add-Cc7cgBoB.js → Add-BChxDDdy.js} +1 -1
- package/dist/client/assets/{Button-EoeZgIFH.js → Button-uvjCWO-i.js} +1 -1
- package/dist/client/assets/{ChannelsView-Bfbq3w7n.js → ChannelsView-D3a0g0rb.js} +1 -1
- package/dist/client/assets/{ChatView-Vfi_jEpI.css → ChatView-DI3XN8vz.css} +1 -1
- package/dist/client/assets/ChatView-T8LH7dwU.js +127 -0
- package/dist/client/assets/{Close-CKHcXisf.js → Close-DbXijZpL.js} +1 -1
- package/dist/client/assets/{FormItem-CvZvjrtr.js → FormItem-BRiLD3TC.js} +1 -1
- package/dist/client/assets/{GatewaysView-Dp4-TFPE.js → GatewaysView-rfzh1nqy.js} +1 -1
- package/dist/client/assets/{Input-Bk7XdoG-.js → Input-CjlUbV0M.js} +1 -1
- package/dist/client/assets/{InputNumber-Dn0EHi-K.js → InputNumber-CPEjoOAv.js} +1 -1
- package/dist/client/assets/{JobsView-D4JN73Zz.js → JobsView-D6AFr9Xe.js} +2 -2
- package/dist/client/assets/{LoginView--hy5CI5O.js → LoginView-DJB_TSHN.js} +1 -1
- package/dist/client/assets/{LogsView-Dz2ZeYad.js → LogsView-Ul8pAp42.js} +1 -1
- package/dist/client/assets/{MarkdownRenderer-BbedVxvo.js → MarkdownRenderer-CY7d2L7Z.js} +1 -1
- package/dist/client/assets/{MemoryView-D2EHM35l.js → MemoryView-BR5Dl_fa.js} +1 -1
- package/dist/client/assets/{Modal-C5-Iw50K.js → Modal-DDUFP8vh.js} +1 -1
- package/dist/client/assets/{ModelsView-CtrRf4vK.js → ModelsView-DAi9Jdmk.js} +1 -1
- package/dist/client/assets/{Popconfirm-C-M2anVL.js → Popconfirm-Cnb_uQVo.js} +1 -1
- package/dist/client/assets/{Popover-mIRPCy7U.js → Popover-DiVI0l6E.js} +1 -1
- package/dist/client/assets/{ProfilesView-Dy9PivgB.js → ProfilesView-BB0Zrfhi.js} +1 -1
- package/dist/client/assets/{Select-uZBC8HC2.js → Select-BqUA1wxE.js} +1 -1
- package/dist/client/assets/{SettingRow-D9R65bDj.js → SettingRow-CK0bHtaz.js} +1 -1
- package/dist/client/assets/{SettingsView-DWEEXqSY.js → SettingsView-BKKk44FG.js} +1 -1
- package/dist/client/assets/{SkillsView-CdZSRy9_.js → SkillsView-whSlyc23.js} +1 -1
- package/dist/client/assets/{Spin-ChbFBUOD.js → Spin-DwHJdgNz.js} +1 -1
- package/dist/client/assets/{Suffix-DgzfIwzx.js → Suffix-D6x-7akR.js} +1 -1
- package/dist/client/assets/{Switch--HhY1uSh.js → Switch-BvHRSSqt.js} +1 -1
- package/dist/client/assets/{Tag-B2zrHMmZ.js → Tag-BMMlXaEi.js} +1 -1
- package/dist/client/assets/{TerminalView-BwfnH803.js → TerminalView-el6o2Q0a.js} +1 -1
- package/dist/client/assets/{Tooltip-9tdvSKGi.js → Tooltip-BM4wl764.js} +1 -1
- package/dist/client/assets/{UsageView-zL3a7F86.js → UsageView-DQ_YKoEV.js} +1 -1
- package/dist/client/assets/{Warning-CXXqHzLa.js → Warning-CEC7rgvY.js} +1 -1
- package/dist/client/assets/{_plugin-vue_export-helper-Cnn0Z73x.js → _plugin-vue_export-helper-DgUZPfuZ.js} +1 -1
- package/dist/client/assets/app-DPUhLGXq.js +1 -0
- package/dist/client/assets/{app-BMobzABI.js → app-DUt8TNq3.js} +1 -1
- package/dist/client/assets/{browser-CQRjhbaB.js → browser-vxCOMmsq.js} +1 -1
- package/dist/client/assets/chat-i_Ge_Lfr.js +6 -0
- package/dist/client/assets/composables-jrQPIjcq.js +1 -0
- package/dist/client/assets/{fade-in.cssr-lwO9nLky.js → fade-in.cssr-DVg2CkO3.js} +1 -1
- package/dist/client/assets/{index-Tg6M43Om.js → index-COwJ2oY0.js} +1 -1
- package/dist/client/assets/{jobs-Z2HS0j2d.js → jobs-Czr1RcSG.js} +1 -1
- package/dist/client/assets/{light-DgIst23O.js → light-3rSjNeC-.js} +1 -1
- package/dist/client/assets/{light-oE8MEiWL.js → light-CKDlpgGU.js} +1 -1
- package/dist/client/assets/{light-Dx6qj2pM.js → light-CiIDFs7y.js} +1 -1
- package/dist/client/assets/{light-DZ0Ns16h.js → light-CoJqT8Vu.js} +1 -1
- package/dist/client/assets/{light-CjCy-Dkn.js → light-DPRJ1OEN.js} +1 -1
- package/dist/client/assets/{light-DzpNsLai.js → light-vTpJevRf.js} +1 -1
- package/dist/client/assets/{models-DLQiHB7r.js → models-BzEeJuoO.js} +1 -1
- package/dist/client/assets/{pinia-Dp_b1vdW.js → pinia-BoNLlsLy.js} +1 -1
- package/dist/client/assets/{profiles-CNTHYFZE.js → profiles-B-DFTmc2.js} +1 -1
- package/dist/client/assets/{router-Dj-Nmg7q.js → router-HHMeDEaP.js} +2 -2
- package/dist/client/assets/{sessions-C0kvgvBm.js → sessions-BmxS_BoH.js} +1 -1
- package/dist/client/assets/{skills-G7EoEvdS.js → skills-Be8Mzr1r.js} +1 -1
- package/dist/client/assets/{use-message-BgToAqhv.js → use-message-DBTY4945.js} +1 -1
- package/dist/client/assets/{useTheme-BUShiwRu.js → useTheme-D58Cg7k2.js} +1 -1
- package/dist/client/index.html +27 -27
- package/dist/server/index.js +19 -194
- package/dist/server/routes/health.d.ts +4 -0
- package/dist/server/routes/health.js +109 -0
- package/dist/server/routes/hermes/group-chat.d.ts +4 -0
- package/dist/server/routes/hermes/group-chat.js +146 -0
- package/dist/server/routes/update.d.ts +2 -0
- package/dist/server/routes/update.js +69 -0
- package/dist/server/routes/upload.js +41 -11
- package/dist/server/services/auth.js +1 -1
- package/dist/server/services/gateway-bootstrap.d.ts +2 -0
- package/dist/server/services/gateway-bootstrap.js +51 -0
- package/dist/server/services/group-chat/coordinator.d.ts +14 -0
- package/dist/server/services/group-chat/coordinator.js +230 -0
- package/dist/server/services/group-chat/index.d.ts +5 -0
- package/dist/server/services/group-chat/index.js +115 -0
- package/dist/server/services/group-chat/rooms-db.d.ts +56 -0
- package/dist/server/services/group-chat/rooms-db.js +199 -0
- package/dist/server/services/hermes/group-chat/agent-clients.d.ts +133 -0
- package/dist/server/services/hermes/group-chat/agent-clients.js +364 -0
- package/dist/server/services/hermes/group-chat/index.d.ts +72 -0
- package/dist/server/services/hermes/group-chat/index.js +307 -0
- package/dist/server/services/shutdown.d.ts +1 -0
- package/dist/server/services/shutdown.js +37 -0
- package/package.json +1 -1
- package/dist/client/assets/ChatView-CDdyTo72.js +0 -127
- package/dist/client/assets/app-Bqu9Uz-1.js +0 -1
- package/dist/client/assets/chat-BIdq6ZXF.js +0 -6
- package/dist/client/assets/composables-ClIU-Ad1.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e}from"./router-
|
|
1
|
+
import{o as e}from"./router-HHMeDEaP.js";async function t(t,n){let r=new URLSearchParams;t&&r.set(`source`,t),n&&r.set(`limit`,String(n));let i=r.toString();return(await e(`/api/hermes/sessions${i?`?${i}`:``}`)).sessions}async function n(t){try{return(await e(`/api/hermes/sessions/${t}`)).session}catch{return null}}async function r(t){try{return await e(`/api/hermes/sessions/${t}`,{method:`DELETE`}),!0}catch{return!1}}async function i(t,n){try{return await e(`/api/hermes/sessions/${t}/rename`,{method:`POST`,body:JSON.stringify({title:n})}),!0}catch{return!1}}export{i,n,t as r,r as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{o as e}from"./router-
|
|
1
|
+
import{o as e}from"./router-HHMeDEaP.js";async function t(){return(await e(`/api/hermes/skills`)).categories}async function n(t){return(await e(`/api/hermes/skills/${t}`)).content}async function r(t,n){return(await e(`/api/hermes/skills/${t}/${n}/files`)).files}async function i(){return e(`/api/hermes/memory`)}async function a(t,n){await e(`/api/hermes/memory`,{method:`POST`,body:JSON.stringify({section:t,content:n})})}async function o(t,n){await e(`/api/hermes/skills/toggle`,{method:`PUT`,body:JSON.stringify({name:t,enabled:n})})}export{a,t as i,n,o,r,i as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{F as e}from"./router-
|
|
1
|
+
import{F as e}from"./router-HHMeDEaP.js";import{$ as t,Y as n}from"./browser-vxCOMmsq.js";var r=t(`n-message-api`),i=t(`n-message-provider`);function a(){let t=e(r,null);return t===null&&n(`use-message`,"No outer <n-message-provider /> founded. See prerequisite in https://www.naiveui.com/en-US/os-theme/components/message for more details. If you want to use `useMessage` outside setup, please check https://www.naiveui.com/zh-CN/os-theme/components/message#Q-&-A."),t}export{r as n,i as r,a as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{X as e,ct as t}from"./router-
|
|
1
|
+
import{X as e,ct as t}from"./router-HHMeDEaP.js";var n=`hermes_theme`,r=t(localStorage.getItem(n)||`system`),i=t(!1);function a(e){i.value=e,document.documentElement.classList.toggle(`dark`,e)}function o(e){return e===`system`?window.matchMedia(`(prefers-color-scheme: dark)`).matches:e===`dark`}a(o(r.value)),window.matchMedia(`(prefers-color-scheme: dark)`).addEventListener(`change`,()=>{r.value===`system`&&a(o(`system`))}),e(r,e=>{localStorage.setItem(n,e),a(o(e))});function s(){function e(e){r.value=e}function t(){r.value=i.value?`light`:`dark`}return{mode:r,isDark:i,setMode:e,toggleTheme:t}}export{s as t};
|
package/dist/client/index.html
CHANGED
|
@@ -6,36 +6,36 @@
|
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
8
|
<title>Hermes</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/router-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="/assets/browser-
|
|
13
|
-
<link rel="modulepreload" crossorigin href="/assets/fade-in.cssr-
|
|
14
|
-
<link rel="modulepreload" crossorigin href="/assets/Suffix-
|
|
15
|
-
<link rel="modulepreload" crossorigin href="/assets/Close-
|
|
16
|
-
<link rel="modulepreload" crossorigin href="/assets/Popover-
|
|
17
|
-
<link rel="modulepreload" crossorigin href="/assets/Button-
|
|
18
|
-
<link rel="modulepreload" crossorigin href="/assets/Tag-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-COwJ2oY0.js"></script>
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/router-HHMeDEaP.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-DgUZPfuZ.js">
|
|
12
|
+
<link rel="modulepreload" crossorigin href="/assets/browser-vxCOMmsq.js">
|
|
13
|
+
<link rel="modulepreload" crossorigin href="/assets/fade-in.cssr-DVg2CkO3.js">
|
|
14
|
+
<link rel="modulepreload" crossorigin href="/assets/Suffix-D6x-7akR.js">
|
|
15
|
+
<link rel="modulepreload" crossorigin href="/assets/Close-DbXijZpL.js">
|
|
16
|
+
<link rel="modulepreload" crossorigin href="/assets/Popover-DiVI0l6E.js">
|
|
17
|
+
<link rel="modulepreload" crossorigin href="/assets/Button-uvjCWO-i.js">
|
|
18
|
+
<link rel="modulepreload" crossorigin href="/assets/Tag-BMMlXaEi.js">
|
|
19
19
|
<link rel="modulepreload" crossorigin href="/assets/create-5zWq3BEB.js">
|
|
20
|
-
<link rel="modulepreload" crossorigin href="/assets/Select-
|
|
21
|
-
<link rel="modulepreload" crossorigin href="/assets/Warning-
|
|
22
|
-
<link rel="modulepreload" crossorigin href="/assets/Modal-
|
|
23
|
-
<link rel="modulepreload" crossorigin href="/assets/Input-
|
|
24
|
-
<link rel="modulepreload" crossorigin href="/assets/light-
|
|
20
|
+
<link rel="modulepreload" crossorigin href="/assets/Select-BqUA1wxE.js">
|
|
21
|
+
<link rel="modulepreload" crossorigin href="/assets/Warning-CEC7rgvY.js">
|
|
22
|
+
<link rel="modulepreload" crossorigin href="/assets/Modal-DDUFP8vh.js">
|
|
23
|
+
<link rel="modulepreload" crossorigin href="/assets/Input-CjlUbV0M.js">
|
|
24
|
+
<link rel="modulepreload" crossorigin href="/assets/light-CiIDFs7y.js">
|
|
25
25
|
<link rel="modulepreload" crossorigin href="/assets/omit-1BRB6K75.js">
|
|
26
|
-
<link rel="modulepreload" crossorigin href="/assets/pinia-
|
|
27
|
-
<link rel="modulepreload" crossorigin href="/assets/profiles-
|
|
28
|
-
<link rel="modulepreload" crossorigin href="/assets/sessions-
|
|
29
|
-
<link rel="modulepreload" crossorigin href="/assets/app-
|
|
30
|
-
<link rel="modulepreload" crossorigin href="/assets/chat-
|
|
31
|
-
<link rel="modulepreload" crossorigin href="/assets/light-
|
|
32
|
-
<link rel="modulepreload" crossorigin href="/assets/use-message-
|
|
33
|
-
<link rel="modulepreload" crossorigin href="/assets/light-
|
|
34
|
-
<link rel="modulepreload" crossorigin href="/assets/light-
|
|
26
|
+
<link rel="modulepreload" crossorigin href="/assets/pinia-BoNLlsLy.js">
|
|
27
|
+
<link rel="modulepreload" crossorigin href="/assets/profiles-B-DFTmc2.js">
|
|
28
|
+
<link rel="modulepreload" crossorigin href="/assets/sessions-BmxS_BoH.js">
|
|
29
|
+
<link rel="modulepreload" crossorigin href="/assets/app-DUt8TNq3.js">
|
|
30
|
+
<link rel="modulepreload" crossorigin href="/assets/chat-i_Ge_Lfr.js">
|
|
31
|
+
<link rel="modulepreload" crossorigin href="/assets/light-CoJqT8Vu.js">
|
|
32
|
+
<link rel="modulepreload" crossorigin href="/assets/use-message-DBTY4945.js">
|
|
33
|
+
<link rel="modulepreload" crossorigin href="/assets/light-vTpJevRf.js">
|
|
34
|
+
<link rel="modulepreload" crossorigin href="/assets/light-CKDlpgGU.js">
|
|
35
35
|
<link rel="modulepreload" crossorigin href="/assets/_common-Yp55QE79.js">
|
|
36
|
-
<link rel="modulepreload" crossorigin href="/assets/light-
|
|
37
|
-
<link rel="modulepreload" crossorigin href="/assets/light-
|
|
38
|
-
<link rel="modulepreload" crossorigin href="/assets/useTheme-
|
|
36
|
+
<link rel="modulepreload" crossorigin href="/assets/light-DPRJ1OEN.js">
|
|
37
|
+
<link rel="modulepreload" crossorigin href="/assets/light-3rSjNeC-.js">
|
|
38
|
+
<link rel="modulepreload" crossorigin href="/assets/useTheme-D58Cg7k2.js">
|
|
39
39
|
<link rel="modulepreload" crossorigin href="/assets/logo-Cd-t_oGE.js">
|
|
40
40
|
<link rel="stylesheet" crossorigin href="/assets/index-BEcRccNA.css">
|
|
41
41
|
</head>
|
package/dist/server/index.js
CHANGED
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
4
|
};
|
|
@@ -42,125 +9,41 @@ const cors_1 = __importDefault(require("@koa/cors"));
|
|
|
42
9
|
const bodyparser_1 = __importDefault(require("@koa/bodyparser"));
|
|
43
10
|
const koa_static_1 = __importDefault(require("koa-static"));
|
|
44
11
|
const koa_send_1 = __importDefault(require("koa-send"));
|
|
12
|
+
const os_1 = __importDefault(require("os"));
|
|
45
13
|
const path_1 = require("path");
|
|
46
14
|
const promises_1 = require("fs/promises");
|
|
47
|
-
const fs_1 = require("fs");
|
|
48
15
|
const config_1 = require("./config");
|
|
49
16
|
const hermes_1 = require("./routes/hermes");
|
|
50
17
|
const upload_1 = require("./routes/upload");
|
|
51
18
|
const webhook_1 = require("./routes/webhook");
|
|
52
|
-
const
|
|
19
|
+
const update_1 = require("./routes/update");
|
|
20
|
+
const health_1 = require("./routes/health");
|
|
53
21
|
const auth_1 = require("./services/auth");
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// dev: packages/server/src → ../../../package.json
|
|
57
|
-
const candidates = [
|
|
58
|
-
(0, path_1.resolve)(__dirname, '../../package.json'),
|
|
59
|
-
(0, path_1.resolve)(__dirname, '../../../package.json'),
|
|
60
|
-
];
|
|
61
|
-
for (const p of candidates) {
|
|
62
|
-
try {
|
|
63
|
-
return JSON.parse((0, fs_1.readFileSync)(p, 'utf-8')).version;
|
|
64
|
-
}
|
|
65
|
-
catch { }
|
|
66
|
-
}
|
|
67
|
-
return '0.0.0';
|
|
68
|
-
}
|
|
69
|
-
const LOCAL_VERSION = getLocalVersion();
|
|
70
|
-
let cachedLatestVersion = '';
|
|
71
|
-
async function checkLatestVersion() {
|
|
72
|
-
try {
|
|
73
|
-
const res = await fetch('https://registry.npmjs.org/hermes-web-ui/latest', {
|
|
74
|
-
signal: AbortSignal.timeout(5000),
|
|
75
|
-
});
|
|
76
|
-
if (res.ok) {
|
|
77
|
-
const data = await res.json();
|
|
78
|
-
const latest = data.version || '';
|
|
79
|
-
if (latest && latest !== cachedLatestVersion) {
|
|
80
|
-
cachedLatestVersion = latest;
|
|
81
|
-
if (latest !== LOCAL_VERSION) {
|
|
82
|
-
console.log(`⬆ New version available: v${LOCAL_VERSION} → v${latest}`);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
catch { }
|
|
88
|
-
}
|
|
89
|
-
const app = new koa_1.default();
|
|
90
|
-
const { restartGateway, startGateway, startGatewayBackground, getVersion } = hermesCli;
|
|
22
|
+
const gateway_bootstrap_1 = require("./services/gateway-bootstrap");
|
|
23
|
+
const shutdown_1 = require("./services/shutdown");
|
|
91
24
|
let server = null;
|
|
92
|
-
let isShuttingDown = false;
|
|
93
|
-
// 👉 如果你有子进程,一定要存
|
|
94
|
-
let gatewayPid = null;
|
|
95
|
-
let gatewayManager = null;
|
|
96
25
|
async function bootstrap() {
|
|
97
26
|
await (0, promises_1.mkdir)(config_1.config.uploadDir, { recursive: true });
|
|
98
27
|
await (0, promises_1.mkdir)(config_1.config.dataDir, { recursive: true });
|
|
99
|
-
// Auth (after mkdir so data dir exists)
|
|
100
28
|
const authToken = await (0, auth_1.getToken)();
|
|
29
|
+
const app = new koa_1.default();
|
|
101
30
|
if (authToken) {
|
|
102
31
|
app.use(await (0, auth_1.authMiddleware)(authToken));
|
|
103
32
|
console.log(`🔐 Auth enabled — token: ${authToken}`);
|
|
104
33
|
}
|
|
105
|
-
await initGatewayManager();
|
|
34
|
+
await (0, gateway_bootstrap_1.initGatewayManager)();
|
|
106
35
|
app.use((0, cors_1.default)({ origin: config_1.config.corsOrigins }));
|
|
107
36
|
app.use((0, bodyparser_1.default)());
|
|
37
|
+
// Shared routes (no agent prefix)
|
|
108
38
|
app.use(webhook_1.webhookRoutes.routes());
|
|
109
39
|
app.use(upload_1.uploadRoutes.routes());
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (ctx.path === '/api/hermes/update' && ctx.method === 'POST') {
|
|
113
|
-
const isWin = process.platform === 'win32';
|
|
114
|
-
const cmd = isWin
|
|
115
|
-
? 'cmd /c hermes-web-ui update'
|
|
116
|
-
: 'hermes-web-ui update';
|
|
117
|
-
try {
|
|
118
|
-
const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
119
|
-
const output = execSync(cmd, {
|
|
120
|
-
encoding: 'utf-8',
|
|
121
|
-
timeout: 120000,
|
|
122
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
123
|
-
});
|
|
124
|
-
ctx.body = { success: true, message: output.trim() };
|
|
125
|
-
}
|
|
126
|
-
catch (err) {
|
|
127
|
-
ctx.status = 500;
|
|
128
|
-
ctx.body = { success: false, message: err.stderr || err.message };
|
|
129
|
-
}
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
await next();
|
|
133
|
-
});
|
|
40
|
+
app.use(update_1.updateRoutes.routes());
|
|
41
|
+
// Hermes routes (must be after update — proxy catch-all matches everything)
|
|
134
42
|
app.use(hermes_1.hermesRoutes.routes());
|
|
135
43
|
app.use(hermes_1.proxyMiddleware);
|
|
136
|
-
//
|
|
137
|
-
app.use(
|
|
138
|
-
|
|
139
|
-
const raw = await getVersion();
|
|
140
|
-
const hermesVersion = raw.split('\n')[0].replace('Hermes Agent ', '') || '';
|
|
141
|
-
let gatewayOk = false;
|
|
142
|
-
try {
|
|
143
|
-
const upstream = gatewayManager?.getUpstream() || config_1.config.upstream;
|
|
144
|
-
const res = await fetch(`${upstream.replace(/\/$/, '')}/health`, {
|
|
145
|
-
signal: AbortSignal.timeout(5000),
|
|
146
|
-
});
|
|
147
|
-
gatewayOk = res.ok;
|
|
148
|
-
}
|
|
149
|
-
catch { }
|
|
150
|
-
ctx.body = {
|
|
151
|
-
status: gatewayOk ? 'ok' : 'error',
|
|
152
|
-
platform: 'hermes-agent',
|
|
153
|
-
version: hermesVersion,
|
|
154
|
-
gateway: gatewayOk ? 'running' : 'stopped',
|
|
155
|
-
webui_version: LOCAL_VERSION,
|
|
156
|
-
webui_latest: cachedLatestVersion,
|
|
157
|
-
webui_update_available: cachedLatestVersion && cachedLatestVersion !== LOCAL_VERSION,
|
|
158
|
-
};
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
await next();
|
|
162
|
-
});
|
|
163
|
-
// SPA
|
|
44
|
+
// Health check
|
|
45
|
+
app.use(health_1.healthRoutes.routes());
|
|
46
|
+
// SPA fallback
|
|
164
47
|
const distDir = (0, path_1.resolve)(__dirname, '..', 'client');
|
|
165
48
|
app.use((0, koa_static_1.default)(distDir));
|
|
166
49
|
app.use(async (ctx) => {
|
|
@@ -171,77 +54,19 @@ async function bootstrap() {
|
|
|
171
54
|
await (0, koa_send_1.default)(ctx, 'index.html', { root: distDir });
|
|
172
55
|
}
|
|
173
56
|
});
|
|
174
|
-
//
|
|
57
|
+
// Start server
|
|
175
58
|
server = app.listen(config_1.config.port, '0.0.0.0');
|
|
176
|
-
// Terminal WebSocket (must be after server is created)
|
|
177
59
|
(0, hermes_1.setupTerminalWebSocket)(server);
|
|
178
60
|
server.on('listening', () => {
|
|
179
|
-
|
|
61
|
+
const interfaces = os_1.default.networkInterfaces();
|
|
62
|
+
const localIp = Object.values(interfaces).flat().find(i => i?.family === 'IPv4' && !i?.internal)?.address || 'localhost';
|
|
63
|
+
console.log(`➜ Server: http://localhost:${config_1.config.port} (LAN: http://${localIp}:${config_1.config.port})`);
|
|
180
64
|
console.log(`➜ Upstream: ${config_1.config.upstream}`);
|
|
181
65
|
});
|
|
182
66
|
server.on('error', (err) => {
|
|
183
67
|
console.error('Server error:', err.message);
|
|
184
68
|
});
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
// Check for updates every 4 hours
|
|
188
|
-
checkLatestVersion();
|
|
189
|
-
setInterval(checkLatestVersion, 4 * 60 * 60 * 1000);
|
|
190
|
-
}
|
|
191
|
-
// ============================
|
|
192
|
-
// ✅ 统一关闭逻辑(核心)
|
|
193
|
-
// ============================
|
|
194
|
-
function bindShutdown() {
|
|
195
|
-
const shutdown = async (signal) => {
|
|
196
|
-
if (isShuttingDown)
|
|
197
|
-
return;
|
|
198
|
-
isShuttingDown = true;
|
|
199
|
-
console.log(`\n[${signal}] shutting down...`);
|
|
200
|
-
try {
|
|
201
|
-
// ✅ 1. 关闭 HTTP server
|
|
202
|
-
if (server) {
|
|
203
|
-
await new Promise((resolve) => {
|
|
204
|
-
server.close(() => {
|
|
205
|
-
console.log('✓ http server closed');
|
|
206
|
-
resolve();
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
// gateway 是系统服务,不随 dev server 退出而停止
|
|
211
|
-
}
|
|
212
|
-
catch (err) {
|
|
213
|
-
console.error('shutdown error:', err);
|
|
214
|
-
}
|
|
215
|
-
process.exit(0);
|
|
216
|
-
};
|
|
217
|
-
// 👉 nodemon 专用(必须 once)
|
|
218
|
-
process.once('SIGUSR2', shutdown);
|
|
219
|
-
// 👉 正常退出
|
|
220
|
-
process.on('SIGINT', shutdown);
|
|
221
|
-
process.on('SIGTERM', shutdown);
|
|
222
|
-
// 👉 防止异常退出没处理
|
|
223
|
-
process.on('uncaughtException', (err) => {
|
|
224
|
-
console.error('uncaughtException:', err);
|
|
225
|
-
shutdown('uncaughtException');
|
|
226
|
-
});
|
|
227
|
-
process.on('unhandledRejection', (err) => {
|
|
228
|
-
console.error('unhandledRejection:', err);
|
|
229
|
-
shutdown('unhandledRejection');
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
// ============================
|
|
233
|
-
// Gateway Manager
|
|
234
|
-
// ============================
|
|
235
|
-
async function initGatewayManager() {
|
|
236
|
-
const { GatewayManager } = await Promise.resolve().then(() => __importStar(require('./services/hermes/gateway-manager')));
|
|
237
|
-
const { getActiveProfileName } = await Promise.resolve().then(() => __importStar(require('./services/hermes/hermes-profile')));
|
|
238
|
-
const { setGatewayManager } = await Promise.resolve().then(() => __importStar(require('./routes/hermes/gateways')));
|
|
239
|
-
const activeProfile = getActiveProfileName();
|
|
240
|
-
gatewayManager = new GatewayManager(activeProfile);
|
|
241
|
-
setGatewayManager(gatewayManager);
|
|
242
|
-
// Detect all running gateways
|
|
243
|
-
await gatewayManager.detectAllOnStartup();
|
|
244
|
-
// Start all gateways that aren't running
|
|
245
|
-
await gatewayManager.startAll();
|
|
69
|
+
(0, shutdown_1.bindShutdown)(server);
|
|
70
|
+
(0, health_1.startVersionCheck)();
|
|
246
71
|
}
|
|
247
72
|
bootstrap();
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.healthRoutes = void 0;
|
|
40
|
+
exports.checkLatestVersion = checkLatestVersion;
|
|
41
|
+
exports.startVersionCheck = startVersionCheck;
|
|
42
|
+
const router_1 = __importDefault(require("@koa/router"));
|
|
43
|
+
const path_1 = require("path");
|
|
44
|
+
const fs_1 = require("fs");
|
|
45
|
+
const gateways_1 = require("./hermes/gateways");
|
|
46
|
+
const hermesCli = __importStar(require("../services/hermes/hermes-cli"));
|
|
47
|
+
const config_1 = require("../config");
|
|
48
|
+
function getLocalVersion() {
|
|
49
|
+
const candidates = [
|
|
50
|
+
(0, path_1.resolve)(__dirname, '../../../package.json'),
|
|
51
|
+
(0, path_1.resolve)(__dirname, '../../../../package.json'),
|
|
52
|
+
];
|
|
53
|
+
for (const p of candidates) {
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse((0, fs_1.readFileSync)(p, 'utf-8')).version;
|
|
56
|
+
}
|
|
57
|
+
catch { }
|
|
58
|
+
}
|
|
59
|
+
return '0.0.0';
|
|
60
|
+
}
|
|
61
|
+
const LOCAL_VERSION = getLocalVersion();
|
|
62
|
+
let cachedLatestVersion = '';
|
|
63
|
+
async function checkLatestVersion() {
|
|
64
|
+
try {
|
|
65
|
+
const res = await fetch('https://registry.npmjs.org/hermes-web-ui/latest', {
|
|
66
|
+
signal: AbortSignal.timeout(5000),
|
|
67
|
+
headers: { 'Cache-Control': 'no-cache' },
|
|
68
|
+
});
|
|
69
|
+
if (res.ok) {
|
|
70
|
+
const data = await res.json();
|
|
71
|
+
const latest = data.version || '';
|
|
72
|
+
if (latest && latest !== cachedLatestVersion) {
|
|
73
|
+
cachedLatestVersion = latest;
|
|
74
|
+
if (latest !== LOCAL_VERSION) {
|
|
75
|
+
console.log(`⬆ New version available: v${LOCAL_VERSION} → v${latest}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch { }
|
|
81
|
+
}
|
|
82
|
+
function startVersionCheck() {
|
|
83
|
+
checkLatestVersion();
|
|
84
|
+
setInterval(checkLatestVersion, 60 * 60 * 1000);
|
|
85
|
+
}
|
|
86
|
+
exports.healthRoutes = new router_1.default();
|
|
87
|
+
exports.healthRoutes.get('/health', async (ctx) => {
|
|
88
|
+
const raw = await hermesCli.getVersion();
|
|
89
|
+
const hermesVersion = raw.split('\n')[0].replace('Hermes Agent ', '') || '';
|
|
90
|
+
let gatewayOk = false;
|
|
91
|
+
try {
|
|
92
|
+
const mgr = (0, gateways_1.getGatewayManager)();
|
|
93
|
+
const upstream = mgr?.getUpstream() || config_1.config.upstream;
|
|
94
|
+
const res = await fetch(`${upstream.replace(/\/$/, '')}/health`, {
|
|
95
|
+
signal: AbortSignal.timeout(5000),
|
|
96
|
+
});
|
|
97
|
+
gatewayOk = res.ok;
|
|
98
|
+
}
|
|
99
|
+
catch { }
|
|
100
|
+
ctx.body = {
|
|
101
|
+
status: gatewayOk ? 'ok' : 'error',
|
|
102
|
+
platform: 'hermes-agent',
|
|
103
|
+
version: hermesVersion,
|
|
104
|
+
gateway: gatewayOk ? 'running' : 'stopped',
|
|
105
|
+
webui_version: LOCAL_VERSION,
|
|
106
|
+
webui_latest: cachedLatestVersion,
|
|
107
|
+
webui_update_available: cachedLatestVersion && cachedLatestVersion !== LOCAL_VERSION,
|
|
108
|
+
};
|
|
109
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import Router from '@koa/router';
|
|
2
|
+
import type { GroupChatServer } from '../../services/hermes/group-chat';
|
|
3
|
+
export declare const groupChatRoutes: Router<import("koa").DefaultState, import("koa").DefaultContext>;
|
|
4
|
+
export declare function setGroupChatServer(server: GroupChatServer): void;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.groupChatRoutes = void 0;
|
|
7
|
+
exports.setGroupChatServer = setGroupChatServer;
|
|
8
|
+
const router_1 = __importDefault(require("@koa/router"));
|
|
9
|
+
exports.groupChatRoutes = new router_1.default();
|
|
10
|
+
let chatServer = null;
|
|
11
|
+
function setGroupChatServer(server) {
|
|
12
|
+
chatServer = server;
|
|
13
|
+
}
|
|
14
|
+
function generateId() {
|
|
15
|
+
return Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
16
|
+
}
|
|
17
|
+
// Create room
|
|
18
|
+
exports.groupChatRoutes.post('/api/hermes/group-chat/rooms', async (ctx) => {
|
|
19
|
+
if (!chatServer) {
|
|
20
|
+
ctx.status = 503;
|
|
21
|
+
ctx.body = { error: 'Group chat not initialized' };
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const { name, inviteCode, agents } = ctx.request.body;
|
|
25
|
+
if (!name || !inviteCode) {
|
|
26
|
+
ctx.status = 400;
|
|
27
|
+
ctx.body = { error: 'name and inviteCode are required' };
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const roomId = generateId();
|
|
31
|
+
const storage = chatServer.getStorage();
|
|
32
|
+
storage.saveRoom(roomId, name, inviteCode);
|
|
33
|
+
// Save agents to DB and auto-connect via Socket.IO
|
|
34
|
+
const addedAgents = [];
|
|
35
|
+
for (const a of agents || []) {
|
|
36
|
+
const agentId = generateId();
|
|
37
|
+
const agent = storage.addRoomAgent(roomId, agentId, a.profile, a.name || a.profile, a.description || '', a.invited ? 1 : 0);
|
|
38
|
+
addedAgents.push(agent);
|
|
39
|
+
try {
|
|
40
|
+
const client = await chatServer.agentClients.createAgent({
|
|
41
|
+
profile: agent.profile,
|
|
42
|
+
name: agent.name,
|
|
43
|
+
description: agent.description,
|
|
44
|
+
invited: agent.invited,
|
|
45
|
+
});
|
|
46
|
+
await chatServer.agentClients.addAgentToRoom(roomId, client);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error(`[GroupChat] Failed to connect agent ${a.profile} to room ${roomId}: ${err.message}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const room = storage.getRoom(roomId);
|
|
53
|
+
ctx.body = { room, agents: addedAgents };
|
|
54
|
+
});
|
|
55
|
+
// List rooms
|
|
56
|
+
exports.groupChatRoutes.get('/api/hermes/group-chat/rooms', async (ctx) => {
|
|
57
|
+
if (!chatServer) {
|
|
58
|
+
ctx.status = 503;
|
|
59
|
+
ctx.body = { error: 'Group chat not initialized' };
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const rooms = chatServer.getStorage().getAllRooms();
|
|
63
|
+
ctx.body = { rooms };
|
|
64
|
+
});
|
|
65
|
+
// Get room by invite code
|
|
66
|
+
exports.groupChatRoutes.get('/api/hermes/group-chat/rooms/join/:code', async (ctx) => {
|
|
67
|
+
if (!chatServer) {
|
|
68
|
+
ctx.status = 503;
|
|
69
|
+
ctx.body = { error: 'Group chat not initialized' };
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const room = chatServer.getStorage().getRoomByInviteCode(ctx.params.code);
|
|
73
|
+
if (!room) {
|
|
74
|
+
ctx.status = 404;
|
|
75
|
+
ctx.body = { error: 'Room not found' };
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
ctx.body = { room };
|
|
79
|
+
});
|
|
80
|
+
// Update room invite code
|
|
81
|
+
exports.groupChatRoutes.put('/api/hermes/group-chat/rooms/:roomId/invite-code', async (ctx) => {
|
|
82
|
+
if (!chatServer) {
|
|
83
|
+
ctx.status = 503;
|
|
84
|
+
ctx.body = { error: 'Group chat not initialized' };
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const { inviteCode } = ctx.request.body;
|
|
88
|
+
if (!inviteCode) {
|
|
89
|
+
ctx.status = 400;
|
|
90
|
+
ctx.body = { error: 'inviteCode is required' };
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
chatServer.getStorage().updateRoomInviteCode(ctx.params.roomId, inviteCode);
|
|
94
|
+
ctx.body = { success: true };
|
|
95
|
+
});
|
|
96
|
+
// Add agent to room
|
|
97
|
+
exports.groupChatRoutes.post('/api/hermes/group-chat/rooms/:roomId/agents', async (ctx) => {
|
|
98
|
+
if (!chatServer) {
|
|
99
|
+
ctx.status = 503;
|
|
100
|
+
ctx.body = { error: 'Group chat not initialized' };
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const { profile, name, description, invited } = ctx.request.body;
|
|
104
|
+
if (!profile) {
|
|
105
|
+
ctx.status = 400;
|
|
106
|
+
ctx.body = { error: 'profile is required' };
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const agentId = generateId();
|
|
110
|
+
const agent = chatServer.getStorage().addRoomAgent(ctx.params.roomId, agentId, profile, name || profile, description || '', invited ? 1 : 0);
|
|
111
|
+
// Auto-connect agent via Socket.IO
|
|
112
|
+
try {
|
|
113
|
+
const client = await chatServer.agentClients.createAgent({
|
|
114
|
+
profile: agent.profile,
|
|
115
|
+
name: agent.name,
|
|
116
|
+
description: agent.description,
|
|
117
|
+
invited: agent.invited,
|
|
118
|
+
});
|
|
119
|
+
await chatServer.agentClients.addAgentToRoom(ctx.params.roomId, client);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
console.error(`[GroupChat] Failed to connect agent ${profile} to room ${ctx.params.roomId}: ${err.message}`);
|
|
123
|
+
}
|
|
124
|
+
ctx.body = { agent };
|
|
125
|
+
});
|
|
126
|
+
// List agents in room
|
|
127
|
+
exports.groupChatRoutes.get('/api/hermes/group-chat/rooms/:roomId/agents', async (ctx) => {
|
|
128
|
+
if (!chatServer) {
|
|
129
|
+
ctx.status = 503;
|
|
130
|
+
ctx.body = { error: 'Group chat not initialized' };
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const agents = chatServer.getStorage().getRoomAgents(ctx.params.roomId);
|
|
134
|
+
ctx.body = { agents };
|
|
135
|
+
});
|
|
136
|
+
// Remove agent from room
|
|
137
|
+
exports.groupChatRoutes.delete('/api/hermes/group-chat/rooms/:roomId/agents/:agentId', async (ctx) => {
|
|
138
|
+
if (!chatServer) {
|
|
139
|
+
ctx.status = 503;
|
|
140
|
+
ctx.body = { error: 'Group chat not initialized' };
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
chatServer.getStorage().removeRoomAgent(ctx.params.agentId);
|
|
144
|
+
chatServer.agentClients.removeAgentFromRoom(ctx.params.roomId, ctx.params.agentId);
|
|
145
|
+
ctx.body = { success: true };
|
|
146
|
+
});
|