hermes-web-ui 0.3.8 → 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.
Files changed (75) hide show
  1. package/README.md +7 -10
  2. package/dist/client/assets/{Add-s316k4Av.js → Add-BChxDDdy.js} +1 -1
  3. package/dist/client/assets/{Button-BkA_RI8a.js → Button-uvjCWO-i.js} +1 -1
  4. package/dist/client/assets/{ChannelsView-DPmPn8DW.js → ChannelsView-D3a0g0rb.js} +1 -1
  5. package/dist/client/assets/{ChatView-DEtziOPB.js → ChatView-T8LH7dwU.js} +1 -1
  6. package/dist/client/assets/{Close-CrLD0IXG.js → Close-DbXijZpL.js} +1 -1
  7. package/dist/client/assets/{FormItem-CQLdFrl9.js → FormItem-BRiLD3TC.js} +1 -1
  8. package/dist/client/assets/{GatewaysView-CC1Y0tZZ.js → GatewaysView-rfzh1nqy.js} +1 -1
  9. package/dist/client/assets/{Input-nXKlujwJ.js → Input-CjlUbV0M.js} +1 -1
  10. package/dist/client/assets/{InputNumber-DLZwwIyX.js → InputNumber-CPEjoOAv.js} +1 -1
  11. package/dist/client/assets/{JobsView-BC0bBrJO.js → JobsView-D6AFr9Xe.js} +2 -2
  12. package/dist/client/assets/{LoginView-PqpFR9bV.js → LoginView-DJB_TSHN.js} +1 -1
  13. package/dist/client/assets/{LogsView-DtR88N0b.js → LogsView-Ul8pAp42.js} +1 -1
  14. package/dist/client/assets/{MarkdownRenderer-BSLfTurm.js → MarkdownRenderer-CY7d2L7Z.js} +1 -1
  15. package/dist/client/assets/{MemoryView-CJRWnePL.js → MemoryView-BR5Dl_fa.js} +1 -1
  16. package/dist/client/assets/{Modal-Bp9RK8LZ.js → Modal-DDUFP8vh.js} +1 -1
  17. package/dist/client/assets/{ModelsView-7Obe34Cz.js → ModelsView-DAi9Jdmk.js} +1 -1
  18. package/dist/client/assets/{Popconfirm-DTdUi7r_.js → Popconfirm-Cnb_uQVo.js} +1 -1
  19. package/dist/client/assets/{Popover-_M3o0B7L.js → Popover-DiVI0l6E.js} +1 -1
  20. package/dist/client/assets/{ProfilesView-1_GmRx-S.js → ProfilesView-BB0Zrfhi.js} +1 -1
  21. package/dist/client/assets/{Select-aHPR3urY.js → Select-BqUA1wxE.js} +1 -1
  22. package/dist/client/assets/{SettingRow-DKasLuS5.js → SettingRow-CK0bHtaz.js} +1 -1
  23. package/dist/client/assets/{SettingsView-DZCA7_CM.js → SettingsView-BKKk44FG.js} +1 -1
  24. package/dist/client/assets/{SkillsView-Dk7O05cK.js → SkillsView-whSlyc23.js} +1 -1
  25. package/dist/client/assets/{Spin-Bt_9cTiO.js → Spin-DwHJdgNz.js} +1 -1
  26. package/dist/client/assets/{Suffix-XaH8SDbR.js → Suffix-D6x-7akR.js} +1 -1
  27. package/dist/client/assets/{Switch-D1_psmjT.js → Switch-BvHRSSqt.js} +1 -1
  28. package/dist/client/assets/{Tag-3FaOhoJN.js → Tag-BMMlXaEi.js} +1 -1
  29. package/dist/client/assets/{TerminalView-DNU7oQxK.js → TerminalView-el6o2Q0a.js} +1 -1
  30. package/dist/client/assets/{Tooltip-YHrHWGPa.js → Tooltip-BM4wl764.js} +1 -1
  31. package/dist/client/assets/{UsageView-COCrOiiV.js → UsageView-DQ_YKoEV.js} +1 -1
  32. package/dist/client/assets/{Warning-B6CM9aBl.js → Warning-CEC7rgvY.js} +1 -1
  33. package/dist/client/assets/{_plugin-vue_export-helper-BGG8ORDx.js → _plugin-vue_export-helper-DgUZPfuZ.js} +1 -1
  34. package/dist/client/assets/app-DPUhLGXq.js +1 -0
  35. package/dist/client/assets/{app-B7ktf7Fh.js → app-DUt8TNq3.js} +1 -1
  36. package/dist/client/assets/{browser-f5W8abIG.js → browser-vxCOMmsq.js} +1 -1
  37. package/dist/client/assets/{chat-6q6pkzEW.js → chat-i_Ge_Lfr.js} +2 -2
  38. package/dist/client/assets/composables-jrQPIjcq.js +1 -0
  39. package/dist/client/assets/{fade-in.cssr-ifHK7yH1.js → fade-in.cssr-DVg2CkO3.js} +1 -1
  40. package/dist/client/assets/{index-CSCYx7ux.js → index-COwJ2oY0.js} +1 -1
  41. package/dist/client/assets/{jobs-DObWfhbO.js → jobs-Czr1RcSG.js} +1 -1
  42. package/dist/client/assets/{light-DgLcPjgU.js → light-3rSjNeC-.js} +1 -1
  43. package/dist/client/assets/{light-CxjyoF0s.js → light-CKDlpgGU.js} +1 -1
  44. package/dist/client/assets/{light-D1yfed_s.js → light-CiIDFs7y.js} +1 -1
  45. package/dist/client/assets/{light-TGFKT-UB.js → light-CoJqT8Vu.js} +1 -1
  46. package/dist/client/assets/{light-D_3MwJj1.js → light-DPRJ1OEN.js} +1 -1
  47. package/dist/client/assets/{light-DWy-mwyK.js → light-vTpJevRf.js} +1 -1
  48. package/dist/client/assets/{models-DQ4CT-vv.js → models-BzEeJuoO.js} +1 -1
  49. package/dist/client/assets/{pinia-DcAkZ8vx.js → pinia-BoNLlsLy.js} +1 -1
  50. package/dist/client/assets/{profiles-DzkigJwq.js → profiles-B-DFTmc2.js} +1 -1
  51. package/dist/client/assets/{router-D8sJ39Io.js → router-HHMeDEaP.js} +2 -2
  52. package/dist/client/assets/{sessions-Dg8n9PBo.js → sessions-BmxS_BoH.js} +1 -1
  53. package/dist/client/assets/{skills-BehzdECn.js → skills-Be8Mzr1r.js} +1 -1
  54. package/dist/client/assets/{use-message-DBz2JSTt.js → use-message-DBTY4945.js} +1 -1
  55. package/dist/client/assets/{useTheme-UdVT814n.js → useTheme-D58Cg7k2.js} +1 -1
  56. package/dist/client/index.html +27 -27
  57. package/dist/server/index.js +19 -199
  58. package/dist/server/routes/health.d.ts +4 -0
  59. package/dist/server/routes/health.js +109 -0
  60. package/dist/server/routes/hermes/group-chat.d.ts +2 -0
  61. package/dist/server/routes/hermes/group-chat.js +112 -101
  62. package/dist/server/routes/update.d.ts +2 -0
  63. package/dist/server/routes/update.js +69 -0
  64. package/dist/server/services/auth.js +1 -1
  65. package/dist/server/services/gateway-bootstrap.d.ts +2 -0
  66. package/dist/server/services/gateway-bootstrap.js +51 -0
  67. package/dist/server/services/hermes/group-chat/agent-clients.d.ts +133 -0
  68. package/dist/server/services/hermes/group-chat/agent-clients.js +364 -0
  69. package/dist/server/services/hermes/group-chat/index.d.ts +72 -0
  70. package/dist/server/services/hermes/group-chat/index.js +307 -0
  71. package/dist/server/services/shutdown.d.ts +1 -0
  72. package/dist/server/services/shutdown.js +37 -0
  73. package/package.json +1 -1
  74. package/dist/client/assets/app-BPvTl2-V.js +0 -1
  75. package/dist/client/assets/composables-xV7dhNpf.js +0 -1
@@ -1 +1 @@
1
- import{o as e}from"./router-D8sJ39Io.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
+ 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-D8sJ39Io.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
+ 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-D8sJ39Io.js";import{$ as t,Y as n}from"./browser-f5W8abIG.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
+ 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-D8sJ39Io.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};
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};
@@ -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-CSCYx7ux.js"></script>
10
- <link rel="modulepreload" crossorigin href="/assets/router-D8sJ39Io.js">
11
- <link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-BGG8ORDx.js">
12
- <link rel="modulepreload" crossorigin href="/assets/browser-f5W8abIG.js">
13
- <link rel="modulepreload" crossorigin href="/assets/fade-in.cssr-ifHK7yH1.js">
14
- <link rel="modulepreload" crossorigin href="/assets/Suffix-XaH8SDbR.js">
15
- <link rel="modulepreload" crossorigin href="/assets/Close-CrLD0IXG.js">
16
- <link rel="modulepreload" crossorigin href="/assets/Popover-_M3o0B7L.js">
17
- <link rel="modulepreload" crossorigin href="/assets/Button-BkA_RI8a.js">
18
- <link rel="modulepreload" crossorigin href="/assets/Tag-3FaOhoJN.js">
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-aHPR3urY.js">
21
- <link rel="modulepreload" crossorigin href="/assets/Warning-B6CM9aBl.js">
22
- <link rel="modulepreload" crossorigin href="/assets/Modal-Bp9RK8LZ.js">
23
- <link rel="modulepreload" crossorigin href="/assets/Input-nXKlujwJ.js">
24
- <link rel="modulepreload" crossorigin href="/assets/light-D1yfed_s.js">
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-DcAkZ8vx.js">
27
- <link rel="modulepreload" crossorigin href="/assets/profiles-DzkigJwq.js">
28
- <link rel="modulepreload" crossorigin href="/assets/sessions-Dg8n9PBo.js">
29
- <link rel="modulepreload" crossorigin href="/assets/app-B7ktf7Fh.js">
30
- <link rel="modulepreload" crossorigin href="/assets/chat-6q6pkzEW.js">
31
- <link rel="modulepreload" crossorigin href="/assets/light-TGFKT-UB.js">
32
- <link rel="modulepreload" crossorigin href="/assets/use-message-DBz2JSTt.js">
33
- <link rel="modulepreload" crossorigin href="/assets/light-DWy-mwyK.js">
34
- <link rel="modulepreload" crossorigin href="/assets/light-CxjyoF0s.js">
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-D_3MwJj1.js">
37
- <link rel="modulepreload" crossorigin href="/assets/light-DgLcPjgU.js">
38
- <link rel="modulepreload" crossorigin href="/assets/useTheme-UdVT814n.js">
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>
@@ -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,130 +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 hermesCli = __importStar(require("./services/hermes/hermes-cli"));
19
+ const update_1 = require("./routes/update");
20
+ const health_1 = require("./routes/health");
53
21
  const auth_1 = require("./services/auth");
54
- function getLocalVersion() {
55
- // production: dist/server → ../../package.json
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
- headers: { 'Cache-Control': 'no-cache' },
76
- });
77
- if (res.ok) {
78
- const data = await res.json();
79
- const latest = data.version || '';
80
- if (latest && latest !== cachedLatestVersion) {
81
- cachedLatestVersion = latest;
82
- if (latest !== LOCAL_VERSION) {
83
- console.log(`⬆ New version available: v${LOCAL_VERSION} → v${latest}`);
84
- }
85
- }
86
- }
87
- }
88
- catch { }
89
- }
90
- const app = new koa_1.default();
91
- const { restartGateway, startGateway, startGatewayBackground, getVersion } = hermesCli;
22
+ const gateway_bootstrap_1 = require("./services/gateway-bootstrap");
23
+ const shutdown_1 = require("./services/shutdown");
92
24
  let server = null;
93
- let isShuttingDown = false;
94
- // 👉 如果你有子进程,一定要存
95
- let gatewayPid = null;
96
- let gatewayManager = null;
97
25
  async function bootstrap() {
98
26
  await (0, promises_1.mkdir)(config_1.config.uploadDir, { recursive: true });
99
27
  await (0, promises_1.mkdir)(config_1.config.dataDir, { recursive: true });
100
- // Auth (after mkdir so data dir exists)
101
28
  const authToken = await (0, auth_1.getToken)();
29
+ const app = new koa_1.default();
102
30
  if (authToken) {
103
31
  app.use(await (0, auth_1.authMiddleware)(authToken));
104
32
  console.log(`🔐 Auth enabled — token: ${authToken}`);
105
33
  }
106
- await initGatewayManager();
34
+ await (0, gateway_bootstrap_1.initGatewayManager)();
107
35
  app.use((0, cors_1.default)({ origin: config_1.config.corsOrigins }));
108
36
  app.use((0, bodyparser_1.default)());
37
+ // Shared routes (no agent prefix)
109
38
  app.use(webhook_1.webhookRoutes.routes());
110
39
  app.use(upload_1.uploadRoutes.routes());
111
- // update (must be before hermesRoutes which includes proxy routes)
112
- app.use(async (ctx, next) => {
113
- if (ctx.path === '/api/hermes/update' && ctx.method === 'POST') {
114
- const isWin = process.platform === 'win32';
115
- // Run npm install directly — calling `hermes-web-ui update` would kill this
116
- // process (stopDaemon) before the response can be sent to the client.
117
- const cmd = isWin
118
- ? 'cmd /c npm install -g hermes-web-ui@latest'
119
- : 'npm install -g hermes-web-ui@latest';
120
- try {
121
- const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
122
- const output = execSync(cmd, {
123
- encoding: 'utf-8',
124
- timeout: 120000,
125
- stdio: ['pipe', 'pipe', 'pipe'],
126
- });
127
- ctx.body = { success: true, message: output.trim() };
128
- // Restart the server after response is sent
129
- setTimeout(() => process.exit(0), 1000);
130
- }
131
- catch (err) {
132
- ctx.status = 500;
133
- ctx.body = { success: false, message: err.stderr || err.message };
134
- }
135
- return;
136
- }
137
- await next();
138
- });
40
+ app.use(update_1.updateRoutes.routes());
41
+ // Hermes routes (must be after update — proxy catch-all matches everything)
139
42
  app.use(hermes_1.hermesRoutes.routes());
140
43
  app.use(hermes_1.proxyMiddleware);
141
- // health
142
- app.use(async (ctx, next) => {
143
- if (ctx.path === '/health') {
144
- const raw = await getVersion();
145
- const hermesVersion = raw.split('\n')[0].replace('Hermes Agent ', '') || '';
146
- let gatewayOk = false;
147
- try {
148
- const upstream = gatewayManager?.getUpstream() || config_1.config.upstream;
149
- const res = await fetch(`${upstream.replace(/\/$/, '')}/health`, {
150
- signal: AbortSignal.timeout(5000),
151
- });
152
- gatewayOk = res.ok;
153
- }
154
- catch { }
155
- ctx.body = {
156
- status: gatewayOk ? 'ok' : 'error',
157
- platform: 'hermes-agent',
158
- version: hermesVersion,
159
- gateway: gatewayOk ? 'running' : 'stopped',
160
- webui_version: LOCAL_VERSION,
161
- webui_latest: cachedLatestVersion,
162
- webui_update_available: cachedLatestVersion && cachedLatestVersion !== LOCAL_VERSION,
163
- };
164
- return;
165
- }
166
- await next();
167
- });
168
- // SPA
44
+ // Health check
45
+ app.use(health_1.healthRoutes.routes());
46
+ // SPA fallback
169
47
  const distDir = (0, path_1.resolve)(__dirname, '..', 'client');
170
48
  app.use((0, koa_static_1.default)(distDir));
171
49
  app.use(async (ctx) => {
@@ -176,77 +54,19 @@ async function bootstrap() {
176
54
  await (0, koa_send_1.default)(ctx, 'index.html', { root: distDir });
177
55
  }
178
56
  });
179
- // 🚀 启动服务
57
+ // Start server
180
58
  server = app.listen(config_1.config.port, '0.0.0.0');
181
- // Terminal WebSocket (must be after server is created)
182
59
  (0, hermes_1.setupTerminalWebSocket)(server);
183
60
  server.on('listening', () => {
184
- console.log(`➜ Server: http://localhost:${config_1.config.port}`);
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})`);
185
64
  console.log(`➜ Upstream: ${config_1.config.upstream}`);
186
65
  });
187
66
  server.on('error', (err) => {
188
67
  console.error('Server error:', err.message);
189
68
  });
190
- // 👇 绑定退出信号
191
- bindShutdown();
192
- // Check for updates every 4 hours
193
- checkLatestVersion();
194
- setInterval(checkLatestVersion, 60 * 60 * 1000);
195
- }
196
- // ============================
197
- // ✅ 统一关闭逻辑(核心)
198
- // ============================
199
- function bindShutdown() {
200
- const shutdown = async (signal) => {
201
- if (isShuttingDown)
202
- return;
203
- isShuttingDown = true;
204
- console.log(`\n[${signal}] shutting down...`);
205
- try {
206
- // ✅ 1. 关闭 HTTP server
207
- if (server) {
208
- await new Promise((resolve) => {
209
- server.close(() => {
210
- console.log('✓ http server closed');
211
- resolve();
212
- });
213
- });
214
- }
215
- // gateway 是系统服务,不随 dev server 退出而停止
216
- }
217
- catch (err) {
218
- console.error('shutdown error:', err);
219
- }
220
- process.exit(0);
221
- };
222
- // 👉 nodemon 专用(必须 once)
223
- process.once('SIGUSR2', shutdown);
224
- // 👉 正常退出
225
- process.on('SIGINT', shutdown);
226
- process.on('SIGTERM', shutdown);
227
- // 👉 防止异常退出没处理
228
- process.on('uncaughtException', (err) => {
229
- console.error('uncaughtException:', err);
230
- shutdown('uncaughtException');
231
- });
232
- process.on('unhandledRejection', (err) => {
233
- console.error('unhandledRejection:', err);
234
- shutdown('unhandledRejection');
235
- });
236
- }
237
- // ============================
238
- // Gateway Manager
239
- // ============================
240
- async function initGatewayManager() {
241
- const { GatewayManager } = await Promise.resolve().then(() => __importStar(require('./services/hermes/gateway-manager')));
242
- const { getActiveProfileName } = await Promise.resolve().then(() => __importStar(require('./services/hermes/hermes-profile')));
243
- const { setGatewayManager } = await Promise.resolve().then(() => __importStar(require('./routes/hermes/gateways')));
244
- const activeProfile = getActiveProfileName();
245
- gatewayManager = new GatewayManager(activeProfile);
246
- setGatewayManager(gatewayManager);
247
- // Detect all running gateways
248
- await gatewayManager.detectAllOnStartup();
249
- // Start all gateways that aren't running
250
- await gatewayManager.startAll();
69
+ (0, shutdown_1.bindShutdown)(server);
70
+ (0, health_1.startVersionCheck)();
251
71
  }
252
72
  bootstrap();
@@ -0,0 +1,4 @@
1
+ import Router from '@koa/router';
2
+ export declare function checkLatestVersion(): Promise<void>;
3
+ export declare function startVersionCheck(): void;
4
+ export declare const healthRoutes: Router<import("koa").DefaultState, import("koa").DefaultContext>;
@@ -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
+ });
@@ -1,2 +1,4 @@
1
1
  import Router from '@koa/router';
2
+ import type { GroupChatServer } from '../../services/hermes/group-chat';
2
3
  export declare const groupChatRoutes: Router<import("koa").DefaultState, import("koa").DefaultContext>;
4
+ export declare function setGroupChatServer(server: GroupChatServer): void;