hermes-web-ui 0.2.6 → 0.2.7

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 (117) hide show
  1. package/README.md +15 -5
  2. package/dist/{assets/Button-BHvh9zmj.js → client/assets/Button-zECKCotA.js} +1 -1
  3. package/dist/{assets/ChannelsView-DZMniRoi.js → client/assets/ChannelsView-Bvh3tnio.js} +1 -1
  4. package/dist/client/assets/ChannelsView-xCdAEZam.css +1 -0
  5. package/dist/{assets/ChatView-Dt1eqp6-.js → client/assets/ChatView-CJZahJ1V.js} +3 -3
  6. package/dist/client/assets/ChatView-Ds8Q3Yrv.css +1 -0
  7. package/dist/{assets/Close-DYPlamoH.js → client/assets/Close-DjLWDodG.js} +1 -1
  8. package/dist/{assets/FormItem-C75Y2lpf.js → client/assets/FormItem-CZ9auYA2.js} +1 -1
  9. package/dist/{assets/Input-CS0p63GR.js → client/assets/Input-DxJk6pT-.js} +1 -1
  10. package/dist/{assets/InputNumber-lHTE1DBf.js → client/assets/InputNumber-BTqp81h0.js} +1 -1
  11. package/dist/client/assets/JobsView-Bbg7Yvse.css +1 -0
  12. package/dist/{assets/JobsView-kGXDpDGq.js → client/assets/JobsView-DsfGyjnT.js} +2 -2
  13. package/dist/client/assets/LoginView-BiWaCYS0.js +1 -0
  14. package/dist/client/assets/LoginView-Bt3yT3yN.css +1 -0
  15. package/dist/client/assets/LogsView-D9Es8tZb.css +1 -0
  16. package/dist/client/assets/LogsView-DuORyFFY.js +1 -0
  17. package/dist/{assets/MarkdownRenderer-Bp-uAEtp.js → client/assets/MarkdownRenderer-BA3oPVqT.js} +1 -1
  18. package/dist/client/assets/MemoryView-CU3JHweh.css +1 -0
  19. package/dist/{assets/MemoryView-CWEya0jB.js → client/assets/MemoryView-VgQFNMsP.js} +2 -2
  20. package/dist/{assets/Modal-mFCAbKPD.js → client/assets/Modal-WQKdvHJY.js} +1 -1
  21. package/dist/client/assets/ModelsView-HlT7QxLF.css +1 -0
  22. package/dist/{assets/ModelsView-BdPt2Mo_.js → client/assets/ModelsView-QDRloKd5.js} +1 -1
  23. package/dist/{assets/Popconfirm-C2OzcGTX.js → client/assets/Popconfirm-02A7vL_z.js} +1 -1
  24. package/dist/{assets/Popover-CRZpNb8Q.js → client/assets/Popover-2C1zuptC.js} +1 -1
  25. package/dist/{assets/Scrollbar-CA0Mq0os.js → client/assets/Scrollbar-Bg2FeTtI.js} +1 -1
  26. package/dist/{assets/Select-DLECSo9D.js → client/assets/Select-C_hKaXgI.js} +1 -1
  27. package/dist/client/assets/SettingRow-CLLFxWP3.js +1 -0
  28. package/dist/client/assets/SettingRow-DsjrPlmy.css +1 -0
  29. package/dist/{assets/SettingsView-DWXjfdpD.js → client/assets/SettingsView-CeScqhwO.js} +2 -2
  30. package/dist/client/assets/SettingsView-vVdZjtPc.css +1 -0
  31. package/dist/{assets/SkillsView-Gb4tyJjH.js → client/assets/SkillsView-D6CegW4w.js} +1 -1
  32. package/dist/client/assets/SkillsView-l8q6J0Ov.css +1 -0
  33. package/dist/{assets/Spin-BbbA3R-G.js → client/assets/Spin-lybeIDeX.js} +1 -1
  34. package/dist/{assets/Suffix-BMwB7UJK.js → client/assets/Suffix-Dv1UElLH.js} +1 -1
  35. package/dist/{assets/Switch-Xa0U6jwA.js → client/assets/Switch-mgeu-lpD.js} +1 -1
  36. package/dist/{assets/Tag-NMAaTGW7.js → client/assets/Tag-DWc4lbAm.js} +1 -1
  37. package/dist/{assets/TerminalView-B7iMIrM8.css → client/assets/TerminalView-CuqATvpq.css} +1 -1
  38. package/dist/{assets/TerminalView-CvTXTM3W.js → client/assets/TerminalView-DmnXOHFu.js} +2 -2
  39. package/dist/{assets/Tooltip-C9RmASqV.js → client/assets/Tooltip-DrDTmrj3.js} +1 -1
  40. package/dist/client/assets/UsageView-BgU-h2NT.css +1 -0
  41. package/dist/{assets/UsageView-DiCHVrs8.js → client/assets/UsageView-C3O6-vbW.js} +1 -1
  42. package/dist/{assets/Warning-CmJYhk3M.js → client/assets/Warning-t1i_4T5i.js} +1 -1
  43. package/dist/{assets/_plugin-vue_export-helper-NLzeiXdV.js → client/assets/_plugin-vue_export-helper-BkT4A29V.js} +1 -1
  44. package/dist/client/assets/app-BUjbfMSg.js +1 -0
  45. package/dist/client/assets/app-p59ZckFN.js +1 -0
  46. package/dist/{assets/browser-DNwI2j4X.js → client/assets/browser-DzAOCZtm.js} +1 -1
  47. package/dist/client/assets/chat-CX1Hza8X.js +6 -0
  48. package/dist/client/assets/context-BM8ZQCOz.js +1 -0
  49. package/dist/{assets/fade-in-scale-up.cssr-BMJXPg-3.js → client/assets/fade-in-scale-up.cssr-DQl-Z54c.js} +1 -1
  50. package/dist/{assets/index-DlNQjiQP.js → client/assets/index-95z-iQoj.js} +2 -2
  51. package/dist/{assets/index-TVVcuwR0.css → client/assets/index-C33O1KZm.css} +1 -1
  52. package/dist/client/assets/jobs-B9NHIxuL.js +1 -0
  53. package/dist/{assets/pinia-DKSOddVw.js → client/assets/pinia-bPUFQqFK.js} +1 -1
  54. package/dist/{assets/router-CpYvE976.js → client/assets/router-COwpqexM.js} +2 -2
  55. package/dist/client/assets/sessions-B1SPfe-R.js +1 -0
  56. package/dist/client/assets/skills-CRtljpt6.js +1 -0
  57. package/dist/client/assets/use-compitable-BnlNjEug.js +1 -0
  58. package/dist/{assets/use-message-17mZlZe3.js → client/assets/use-message-g8F4Z57w.js} +1 -1
  59. package/dist/client/index.html +38 -0
  60. package/dist/server/index.js +6 -26
  61. package/dist/server/routes/{config.js → hermes/config.js} +4 -4
  62. package/dist/server/routes/{filesystem.js → hermes/filesystem.js} +13 -13
  63. package/dist/server/routes/hermes/index.d.ts +5 -0
  64. package/dist/server/routes/hermes/index.js +25 -0
  65. package/dist/server/routes/{logs.js → hermes/logs.js} +3 -3
  66. package/dist/server/routes/hermes/profiles.d.ts +2 -0
  67. package/dist/server/routes/hermes/profiles.js +222 -0
  68. package/dist/server/routes/{proxy-handler.js → hermes/proxy-handler.js} +6 -2
  69. package/dist/server/routes/{proxy.d.ts → hermes/proxy.d.ts} +2 -0
  70. package/dist/server/routes/hermes/proxy.js +20 -0
  71. package/dist/server/routes/{sessions.js → hermes/sessions.js} +5 -5
  72. package/dist/server/routes/{terminal.js → hermes/terminal.js} +2 -2
  73. package/dist/server/routes/{weixin.js → hermes/weixin.js} +4 -4
  74. package/dist/server/services/auth.js +1 -1
  75. package/dist/server/services/hermes-cli.d.ts +53 -0
  76. package/dist/server/services/hermes-cli.js +195 -0
  77. package/package.json +5 -5
  78. package/dist/assets/ChannelsView-C7Wor1FB.css +0 -1
  79. package/dist/assets/ChatView-gR62J-Xr.css +0 -1
  80. package/dist/assets/JobsView-DoUtVQm_.css +0 -1
  81. package/dist/assets/LoginView-BXByybMK.css +0 -1
  82. package/dist/assets/LoginView-HQwDR5A7.js +0 -1
  83. package/dist/assets/LogsView-COSQTXoG.css +0 -1
  84. package/dist/assets/LogsView-KPcTBGzh.js +0 -1
  85. package/dist/assets/MemoryView-CL5H-3mE.css +0 -1
  86. package/dist/assets/ModelsView-DbBXgw4g.css +0 -1
  87. package/dist/assets/SettingRow-CsKwX-jv.js +0 -1
  88. package/dist/assets/SettingRow-Dwpo-tP0.css +0 -1
  89. package/dist/assets/SettingsView-Citzr3ci.css +0 -1
  90. package/dist/assets/SkillsView-BNEWlriU.css +0 -1
  91. package/dist/assets/UsageView-DKigFrVY.css +0 -1
  92. package/dist/assets/app-CQZfHgyy.js +0 -1
  93. package/dist/assets/app-DeeNNd_a.js +0 -1
  94. package/dist/assets/chat-DnFbBAAK.js +0 -6
  95. package/dist/assets/context-DLFTSrww.js +0 -1
  96. package/dist/assets/jobs-B7U8gZia.js +0 -1
  97. package/dist/assets/sessions-DTV2WuAE.js +0 -1
  98. package/dist/assets/skills-DwX9oZGG.js +0 -1
  99. package/dist/assets/use-compitable-D2-fMbL2.js +0 -1
  100. package/dist/index.html +0 -38
  101. package/dist/server/routes/proxy.js +0 -12
  102. /package/dist/{assets → client/assets}/MarkdownRenderer-Bd-nS4jK.css +0 -0
  103. /package/dist/{assets → client/assets}/dance-gGRu7JHG.mp4 +0 -0
  104. /package/dist/{assets → client/assets}/logo-Cd-t_oGE.js +0 -0
  105. /package/dist/{assets → client/assets}/omit-C4dR5R2G.js +0 -0
  106. /package/dist/{assets → client/assets}/thinking-Cwsva50h.mp4 +0 -0
  107. /package/dist/{favicon.ico → client/favicon.ico} +0 -0
  108. /package/dist/{favicon.svg → client/favicon.svg} +0 -0
  109. /package/dist/{icons.svg → client/icons.svg} +0 -0
  110. /package/dist/{logo.png → client/logo.png} +0 -0
  111. /package/dist/server/routes/{config.d.ts → hermes/config.d.ts} +0 -0
  112. /package/dist/server/routes/{filesystem.d.ts → hermes/filesystem.d.ts} +0 -0
  113. /package/dist/server/routes/{logs.d.ts → hermes/logs.d.ts} +0 -0
  114. /package/dist/server/routes/{proxy-handler.d.ts → hermes/proxy-handler.d.ts} +0 -0
  115. /package/dist/server/routes/{sessions.d.ts → hermes/sessions.d.ts} +0 -0
  116. /package/dist/server/routes/{terminal.d.ts → hermes/terminal.d.ts} +0 -0
  117. /package/dist/server/routes/{weixin.d.ts → hermes/weixin.d.ts} +0 -0
@@ -0,0 +1 @@
1
+ import{o as e}from"./router-COwpqexM.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};
@@ -0,0 +1 @@
1
+ import{o as e}from"./router-COwpqexM.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};
@@ -0,0 +1 @@
1
+ import{C as e}from"./router-COwpqexM.js";function t(t,n){return e(()=>{for(let e of n)if(t[e]!==void 0)return t[e];return t[n[n.length-1]]})}export{t};
@@ -1 +1 @@
1
- import{F as e}from"./router-CpYvE976.js";import{J as t}from"./browser-DNwI2j4X.js";import{t as n}from"./context-DLFTSrww.js";function r(){let r=e(n,null);return r===null&&t(`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."),r}export{r as t};
1
+ import{F as e}from"./router-COwpqexM.js";import{J as t}from"./browser-DzAOCZtm.js";import{t as n}from"./context-BM8ZQCOz.js";function r(){let r=e(n,null);return r===null&&t(`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."),r}export{r as t};
@@ -0,0 +1,38 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
+ <title>Hermes</title>
9
+ <script type="module" crossorigin src="/assets/index-95z-iQoj.js"></script>
10
+ <link rel="modulepreload" crossorigin href="/assets/router-COwpqexM.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-BkT4A29V.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/browser-DzAOCZtm.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/Scrollbar-Bg2FeTtI.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/use-compitable-BnlNjEug.js">
15
+ <link rel="modulepreload" crossorigin href="/assets/Popover-2C1zuptC.js">
16
+ <link rel="modulepreload" crossorigin href="/assets/Close-DjLWDodG.js">
17
+ <link rel="modulepreload" crossorigin href="/assets/Button-zECKCotA.js">
18
+ <link rel="modulepreload" crossorigin href="/assets/Suffix-Dv1UElLH.js">
19
+ <link rel="modulepreload" crossorigin href="/assets/fade-in-scale-up.cssr-DQl-Z54c.js">
20
+ <link rel="modulepreload" crossorigin href="/assets/Tag-DWc4lbAm.js">
21
+ <link rel="modulepreload" crossorigin href="/assets/Select-C_hKaXgI.js">
22
+ <link rel="modulepreload" crossorigin href="/assets/Warning-t1i_4T5i.js">
23
+ <link rel="modulepreload" crossorigin href="/assets/Modal-WQKdvHJY.js">
24
+ <link rel="modulepreload" crossorigin href="/assets/omit-C4dR5R2G.js">
25
+ <link rel="modulepreload" crossorigin href="/assets/context-BM8ZQCOz.js">
26
+ <link rel="modulepreload" crossorigin href="/assets/pinia-bPUFQqFK.js">
27
+ <link rel="modulepreload" crossorigin href="/assets/sessions-B1SPfe-R.js">
28
+ <link rel="modulepreload" crossorigin href="/assets/app-BUjbfMSg.js">
29
+ <link rel="modulepreload" crossorigin href="/assets/chat-CX1Hza8X.js">
30
+ <link rel="modulepreload" crossorigin href="/assets/logo-Cd-t_oGE.js">
31
+ <link rel="stylesheet" crossorigin href="/assets/index-C33O1KZm.css">
32
+ </head>
33
+
34
+ <body>
35
+ <div id="app"></div>
36
+ </body>
37
+
38
+ </html>
@@ -45,15 +45,9 @@ const koa_send_1 = __importDefault(require("koa-send"));
45
45
  const path_1 = require("path");
46
46
  const promises_1 = require("fs/promises");
47
47
  const config_1 = require("./config");
48
- const proxy_1 = require("./routes/proxy");
48
+ const hermes_1 = require("./routes/hermes");
49
49
  const upload_1 = require("./routes/upload");
50
- const sessions_1 = require("./routes/sessions");
51
50
  const webhook_1 = require("./routes/webhook");
52
- const logs_1 = require("./routes/logs");
53
- const filesystem_1 = require("./routes/filesystem");
54
- const config_2 = require("./routes/config");
55
- const weixin_1 = require("./routes/weixin");
56
- const terminal_1 = require("./routes/terminal");
57
51
  const hermesCli = __importStar(require("./services/hermes-cli"));
58
52
  const auth_1 = require("./services/auth");
59
53
  const app = new koa_1.default();
@@ -76,12 +70,9 @@ async function bootstrap() {
76
70
  app.use((0, cors_1.default)({ origin: config_1.config.corsOrigins }));
77
71
  app.use((0, bodyparser_1.default)());
78
72
  app.use(webhook_1.webhookRoutes.routes());
79
- app.use(logs_1.logRoutes.routes());
80
73
  app.use(upload_1.uploadRoutes.routes());
81
- app.use(sessions_1.sessionRoutes.routes());
82
- app.use(filesystem_1.fsRoutes.routes());
83
- app.use(config_2.configRoutes.routes());
84
- app.use(weixin_1.weixinRoutes.routes());
74
+ app.use(hermes_1.hermesRoutes.routes());
75
+ app.use(hermes_1.proxyMiddleware);
85
76
  // health
86
77
  app.use(async (ctx, next) => {
87
78
  if (ctx.path === '/health') {
@@ -105,13 +96,11 @@ async function bootstrap() {
105
96
  }
106
97
  await next();
107
98
  });
108
- app.use(proxy_1.proxyRoutes.routes());
109
99
  // SPA
110
- const distDir = (0, path_1.resolve)(__dirname, '..');
100
+ const distDir = (0, path_1.resolve)(__dirname, '..', 'client');
111
101
  app.use((0, koa_static_1.default)(distDir));
112
102
  app.use(async (ctx) => {
113
103
  if (!ctx.path.startsWith('/api') &&
114
- !ctx.path.startsWith('/v1') &&
115
104
  ctx.path !== '/health' &&
116
105
  ctx.path !== '/upload' &&
117
106
  ctx.path !== '/webhook') {
@@ -121,7 +110,7 @@ async function bootstrap() {
121
110
  // 🚀 启动服务
122
111
  server = app.listen(config_1.config.port, '0.0.0.0');
123
112
  // Terminal WebSocket (must be after server is created)
124
- (0, terminal_1.setupTerminalWebSocket)(server);
113
+ (0, hermes_1.setupTerminalWebSocket)(server);
125
114
  server.on('listening', () => {
126
115
  console.log(`➜ Server: http://localhost:${config_1.config.port}`);
127
116
  console.log(`➜ Upstream: ${config_1.config.upstream}`);
@@ -206,16 +195,7 @@ async function ensureApiServerConfig() {
206
195
  cfg.platforms = {};
207
196
  if (!cfg.platforms.api_server)
208
197
  cfg.platforms.api_server = {};
209
- const api = cfg.platforms.api_server;
210
- let changed = false;
211
- for (const [k, v] of Object.entries(defaults)) {
212
- if (api[k] != null && api[k] !== v) {
213
- api[k] = v;
214
- changed = true;
215
- }
216
- }
217
- if (!changed)
218
- return;
198
+ cfg.platforms.api_server = defaults;
219
199
  copyFileSync(configPath, configPath + '.bak');
220
200
  writeFileSync(configPath, yaml.dump(cfg), 'utf-8');
221
201
  await restartGateway();
@@ -10,7 +10,7 @@ const promises_2 = require("fs/promises");
10
10
  const path_1 = require("path");
11
11
  const os_1 = require("os");
12
12
  const js_yaml_1 = __importDefault(require("js-yaml"));
13
- const hermes_cli_1 = require("../services/hermes-cli");
13
+ const hermes_cli_1 = require("../../services/hermes-cli");
14
14
  // Platform sections that require gateway restart after config change
15
15
  const PLATFORM_SECTIONS = new Set([
16
16
  'telegram', 'discord', 'slack', 'whatsapp', 'matrix',
@@ -174,7 +174,7 @@ async function writeConfig(data) {
174
174
  }
175
175
  exports.configRoutes = new router_1.default();
176
176
  // GET /api/config — read config sections
177
- exports.configRoutes.get('/api/config', async (ctx) => {
177
+ exports.configRoutes.get('/api/hermes/config', async (ctx) => {
178
178
  try {
179
179
  const config = await readConfig();
180
180
  // Merge .env platform credentials into platforms section
@@ -209,7 +209,7 @@ exports.configRoutes.get('/api/config', async (ctx) => {
209
209
  }
210
210
  });
211
211
  // PUT /api/config — update a config section (writes to config.yaml)
212
- exports.configRoutes.put('/api/config', async (ctx) => {
212
+ exports.configRoutes.put('/api/hermes/config', async (ctx) => {
213
213
  const { section, values } = ctx.request.body;
214
214
  if (!section || !values) {
215
215
  ctx.status = 400;
@@ -234,7 +234,7 @@ exports.configRoutes.put('/api/config', async (ctx) => {
234
234
  // PUT /api/config/credentials — save platform credentials to .env
235
235
  // Body: { platform: string, values: Record<string, any> }
236
236
  // values keys match PlatformConfig paths: 'token', 'extra.app_id', 'extra.app_secret', etc.
237
- exports.configRoutes.put('/api/config/credentials', async (ctx) => {
237
+ exports.configRoutes.put('/api/hermes/config/credentials', async (ctx) => {
238
238
  const { platform, values } = ctx.request.body;
239
239
  if (!platform || !values) {
240
240
  ctx.status = 400;
@@ -46,7 +46,7 @@ async function fetchProviderModels(baseUrl, apiKey) {
46
46
  }
47
47
  }
48
48
  // --- Hardcoded model catalogs (single source: src/shared/providers.ts) ---
49
- const providers_1 = require("../shared/providers");
49
+ const providers_1 = require("../../shared/providers");
50
50
  const PROVIDER_MODEL_CATALOG = (0, providers_1.buildProviderModelMap)();
51
51
  exports.fsRoutes = new router_1.default();
52
52
  const hermesDir = (0, path_1.resolve)((0, os_1.homedir)(), '.hermes');
@@ -113,7 +113,7 @@ async function writeConfigYaml(config) {
113
113
  }
114
114
  // --- Skills Routes ---
115
115
  // List all skills grouped by category
116
- exports.fsRoutes.get('/api/skills', async (ctx) => {
116
+ exports.fsRoutes.get('/api/hermes/skills', async (ctx) => {
117
117
  const skillsDir = (0, path_1.join)(hermesDir, 'skills');
118
118
  try {
119
119
  // Read disabled skills list from config.yaml
@@ -157,7 +157,7 @@ exports.fsRoutes.get('/api/skills', async (ctx) => {
157
157
  }
158
158
  });
159
159
  // Toggle skill enabled/disabled via config.yaml skills.disabled
160
- exports.fsRoutes.put('/api/skills/toggle', async (ctx) => {
160
+ exports.fsRoutes.put('/api/hermes/skills/toggle', async (ctx) => {
161
161
  const { name, enabled } = ctx.request.body;
162
162
  if (!name || typeof enabled !== 'boolean') {
163
163
  ctx.status = 400;
@@ -211,7 +211,7 @@ async function listFilesRecursive(dir, prefix) {
211
211
  }
212
212
  return result;
213
213
  }
214
- exports.fsRoutes.get('/api/skills/:category/:skill/files', async (ctx) => {
214
+ exports.fsRoutes.get('/api/hermes/skills/:category/:skill/files', async (ctx) => {
215
215
  const { category, skill } = ctx.params;
216
216
  const skillDir = (0, path_1.join)(hermesDir, 'skills', category, skill);
217
217
  try {
@@ -224,8 +224,8 @@ exports.fsRoutes.get('/api/skills/:category/:skill/files', async (ctx) => {
224
224
  ctx.body = { error: err.message };
225
225
  }
226
226
  });
227
- // Read a specific file under skills/
228
- exports.fsRoutes.get('/api/skills/:path(.+)', async (ctx) => {
227
+ // Read a specific file under skills/ (must be registered after the /files route)
228
+ exports.fsRoutes.get('/api/hermes/skills/{*path}', async (ctx) => {
229
229
  const filePath = ctx.params.path;
230
230
  const fullPath = (0, path_1.resolve)((0, path_1.join)(hermesDir, 'skills', filePath));
231
231
  if (!fullPath.startsWith((0, path_1.join)(hermesDir, 'skills'))) {
@@ -242,7 +242,7 @@ exports.fsRoutes.get('/api/skills/:path(.+)', async (ctx) => {
242
242
  ctx.body = { content };
243
243
  });
244
244
  // --- Memory Routes ---
245
- exports.fsRoutes.get('/api/memory', async (ctx) => {
245
+ exports.fsRoutes.get('/api/hermes/memory', async (ctx) => {
246
246
  const memoryPath = (0, path_1.join)(hermesDir, 'memories', 'MEMORY.md');
247
247
  const userPath = (0, path_1.join)(hermesDir, 'memories', 'USER.md');
248
248
  const [memory, user, memoryStat, userStat] = await Promise.all([
@@ -258,7 +258,7 @@ exports.fsRoutes.get('/api/memory', async (ctx) => {
258
258
  user_mtime: userStat?.mtime || null,
259
259
  };
260
260
  });
261
- exports.fsRoutes.post('/api/memory', async (ctx) => {
261
+ exports.fsRoutes.post('/api/hermes/memory', async (ctx) => {
262
262
  const { section, content } = ctx.request.body;
263
263
  if (!section || !content) {
264
264
  ctx.status = 400;
@@ -321,7 +321,7 @@ function buildModelGroups(config) {
321
321
  return { default: defaultModel, groups };
322
322
  }
323
323
  // GET /api/available-models — fetch models from all credential pool endpoints
324
- exports.fsRoutes.get('/api/available-models', async (ctx) => {
324
+ exports.fsRoutes.get('/api/hermes/available-models', async (ctx) => {
325
325
  try {
326
326
  const auth = await loadAuthJson();
327
327
  const pool = auth?.credential_pool || {};
@@ -395,7 +395,7 @@ exports.fsRoutes.get('/api/available-models', async (ctx) => {
395
395
  }
396
396
  });
397
397
  // GET /api/config/models
398
- exports.fsRoutes.get('/api/config/models', async (ctx) => {
398
+ exports.fsRoutes.get('/api/hermes/config/models', async (ctx) => {
399
399
  try {
400
400
  const config = await readConfigYaml();
401
401
  ctx.body = buildModelGroups(config);
@@ -406,7 +406,7 @@ exports.fsRoutes.get('/api/config/models', async (ctx) => {
406
406
  }
407
407
  });
408
408
  // PUT /api/config/model
409
- exports.fsRoutes.put('/api/config/model', async (ctx) => {
409
+ exports.fsRoutes.put('/api/hermes/config/model', async (ctx) => {
410
410
  const { default: defaultModel, provider: reqProvider } = ctx.request.body;
411
411
  if (!defaultModel) {
412
412
  ctx.status = 400;
@@ -431,7 +431,7 @@ exports.fsRoutes.put('/api/config/model', async (ctx) => {
431
431
  }
432
432
  });
433
433
  // POST /api/config/providers
434
- exports.fsRoutes.post('/api/config/providers', async (ctx) => {
434
+ exports.fsRoutes.post('/api/hermes/config/providers', async (ctx) => {
435
435
  const { name, base_url, api_key, model, providerKey } = ctx.request.body;
436
436
  if (!name || !base_url || !model) {
437
437
  ctx.status = 400;
@@ -484,7 +484,7 @@ exports.fsRoutes.post('/api/config/providers', async (ctx) => {
484
484
  }
485
485
  });
486
486
  // DELETE /api/config/providers/:poolKey
487
- exports.fsRoutes.delete('/api/config/providers/:poolKey', async (ctx) => {
487
+ exports.fsRoutes.delete('/api/hermes/config/providers/:poolKey', async (ctx) => {
488
488
  const poolKey = decodeURIComponent(ctx.params.poolKey);
489
489
  try {
490
490
  const auth = await loadAuthJson();
@@ -0,0 +1,5 @@
1
+ import Router from '@koa/router';
2
+ import { proxyMiddleware } from './proxy';
3
+ import { setupTerminalWebSocket } from './terminal';
4
+ export declare const hermesRoutes: Router<import("koa").DefaultState, import("koa").DefaultContext>;
5
+ export { setupTerminalWebSocket, proxyMiddleware };
@@ -0,0 +1,25 @@
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.proxyMiddleware = exports.setupTerminalWebSocket = exports.hermesRoutes = void 0;
7
+ const router_1 = __importDefault(require("@koa/router"));
8
+ const sessions_1 = require("./sessions");
9
+ const profiles_1 = require("./profiles");
10
+ const config_1 = require("./config");
11
+ const filesystem_1 = require("./filesystem");
12
+ const logs_1 = require("./logs");
13
+ const weixin_1 = require("./weixin");
14
+ const proxy_1 = require("./proxy");
15
+ Object.defineProperty(exports, "proxyMiddleware", { enumerable: true, get: function () { return proxy_1.proxyMiddleware; } });
16
+ const terminal_1 = require("./terminal");
17
+ Object.defineProperty(exports, "setupTerminalWebSocket", { enumerable: true, get: function () { return terminal_1.setupTerminalWebSocket; } });
18
+ exports.hermesRoutes = new router_1.default();
19
+ exports.hermesRoutes.use(sessions_1.sessionRoutes.routes());
20
+ exports.hermesRoutes.use(profiles_1.profileRoutes.routes());
21
+ exports.hermesRoutes.use(config_1.configRoutes.routes());
22
+ exports.hermesRoutes.use(filesystem_1.fsRoutes.routes());
23
+ exports.hermesRoutes.use(logs_1.logRoutes.routes());
24
+ exports.hermesRoutes.use(weixin_1.weixinRoutes.routes());
25
+ exports.hermesRoutes.use(proxy_1.proxyRoutes.routes());
@@ -38,10 +38,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.logRoutes = void 0;
40
40
  const router_1 = __importDefault(require("@koa/router"));
41
- const hermesCli = __importStar(require("../services/hermes-cli"));
41
+ const hermesCli = __importStar(require("../../services/hermes-cli"));
42
42
  exports.logRoutes = new router_1.default();
43
43
  // List available log files
44
- exports.logRoutes.get('/api/logs', async (ctx) => {
44
+ exports.logRoutes.get('/api/hermes/logs', async (ctx) => {
45
45
  const files = await hermesCli.listLogFiles();
46
46
  ctx.body = { files };
47
47
  });
@@ -62,7 +62,7 @@ function parseLine(line) {
62
62
  return null;
63
63
  }
64
64
  // Read log lines (parsed)
65
- exports.logRoutes.get('/api/logs/:name', async (ctx) => {
65
+ exports.logRoutes.get('/api/hermes/logs/:name', async (ctx) => {
66
66
  const logName = ctx.params.name;
67
67
  const lines = ctx.query.lines ? parseInt(ctx.query.lines, 10) : 100;
68
68
  const level = ctx.query.level || undefined;
@@ -0,0 +1,2 @@
1
+ import Router from '@koa/router';
2
+ export declare const profileRoutes: Router<import("koa").DefaultState, import("koa").DefaultContext>;
@@ -0,0 +1,222 @@
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.profileRoutes = void 0;
40
+ const router_1 = __importDefault(require("@koa/router"));
41
+ const hermesCli = __importStar(require("../../services/hermes-cli"));
42
+ exports.profileRoutes = new router_1.default();
43
+ // GET /api/profiles - List all profiles
44
+ exports.profileRoutes.get('/api/hermes/profiles', async (ctx) => {
45
+ try {
46
+ const profiles = await hermesCli.listProfiles();
47
+ ctx.body = { profiles };
48
+ }
49
+ catch (err) {
50
+ ctx.status = 500;
51
+ ctx.body = { error: err.message };
52
+ }
53
+ });
54
+ // POST /api/profiles - Create a new profile
55
+ exports.profileRoutes.post('/api/hermes/profiles', async (ctx) => {
56
+ const { name, clone } = ctx.request.body;
57
+ if (!name) {
58
+ ctx.status = 400;
59
+ ctx.body = { error: 'Missing profile name' };
60
+ return;
61
+ }
62
+ try {
63
+ const output = await hermesCli.createProfile(name, clone);
64
+ ctx.body = { success: true, message: output.trim() };
65
+ }
66
+ catch (err) {
67
+ ctx.status = 500;
68
+ ctx.body = { error: err.message };
69
+ }
70
+ });
71
+ // GET /api/profiles/:name - Get profile details
72
+ exports.profileRoutes.get('/api/hermes/profiles/:name', async (ctx) => {
73
+ const { name } = ctx.params;
74
+ try {
75
+ const profile = await hermesCli.getProfile(name);
76
+ ctx.body = { profile };
77
+ }
78
+ catch (err) {
79
+ ctx.status = err.message.includes('not found') ? 404 : 500;
80
+ ctx.body = { error: err.message };
81
+ }
82
+ });
83
+ // DELETE /api/profiles/:name - Delete a profile
84
+ exports.profileRoutes.delete('/api/hermes/profiles/:name', async (ctx) => {
85
+ const { name } = ctx.params;
86
+ if (name === 'default') {
87
+ ctx.status = 400;
88
+ ctx.body = { error: 'Cannot delete the default profile' };
89
+ return;
90
+ }
91
+ try {
92
+ const ok = await hermesCli.deleteProfile(name);
93
+ if (ok) {
94
+ ctx.body = { success: true };
95
+ }
96
+ else {
97
+ ctx.status = 500;
98
+ ctx.body = { error: 'Failed to delete profile' };
99
+ }
100
+ }
101
+ catch (err) {
102
+ ctx.status = 500;
103
+ ctx.body = { error: err.message };
104
+ }
105
+ });
106
+ // POST /api/profiles/:name/rename - Rename a profile
107
+ exports.profileRoutes.post('/api/hermes/profiles/:name/rename', async (ctx) => {
108
+ const { name } = ctx.params;
109
+ const { new_name } = ctx.request.body;
110
+ if (!new_name) {
111
+ ctx.status = 400;
112
+ ctx.body = { error: 'Missing new_name' };
113
+ return;
114
+ }
115
+ try {
116
+ const ok = await hermesCli.renameProfile(name, new_name);
117
+ if (ok) {
118
+ ctx.body = { success: true };
119
+ }
120
+ else {
121
+ ctx.status = 500;
122
+ ctx.body = { error: 'Failed to rename profile' };
123
+ }
124
+ }
125
+ catch (err) {
126
+ ctx.status = 500;
127
+ ctx.body = { error: err.message };
128
+ }
129
+ });
130
+ // PUT /api/profiles/active - Switch active profile
131
+ exports.profileRoutes.put('/api/hermes/profiles/active', async (ctx) => {
132
+ const { name } = ctx.request.body;
133
+ if (!name) {
134
+ ctx.status = 400;
135
+ ctx.body = { error: 'Missing profile name' };
136
+ return;
137
+ }
138
+ try {
139
+ // 1. Stop gateway (try launchd/systemd first, ignore if unavailable e.g. WSL)
140
+ try {
141
+ await hermesCli.stopGateway();
142
+ }
143
+ catch { }
144
+ // 2. Kill gateway by port if still running (for WSL / background mode)
145
+ try {
146
+ const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
147
+ const isWin = process.platform === 'win32';
148
+ let pids = '';
149
+ if (isWin) {
150
+ const out = execSync('netstat -aon | findstr :8642', { encoding: 'utf-8', timeout: 5000 }).trim();
151
+ const lines = out.split('\n').filter(l => l.includes('LISTENING'));
152
+ pids = Array.from(new Set(lines.map(l => l.trim().split(/\s+/).pop()).filter(Boolean))).join(' ');
153
+ }
154
+ else {
155
+ pids = execSync('lsof -ti:8642', { encoding: 'utf-8', timeout: 5000 }).trim();
156
+ }
157
+ if (pids) {
158
+ if (isWin) {
159
+ execSync(`taskkill /F /PID ${pids.split(' ').join(' /PID ')}`, { timeout: 5000 });
160
+ }
161
+ else {
162
+ execSync(`kill -9 ${pids}`, { timeout: 5000 });
163
+ }
164
+ await new Promise(r => setTimeout(r, 2000));
165
+ }
166
+ }
167
+ catch { }
168
+ // 3. Switch profile
169
+ const output = await hermesCli.useProfile(name);
170
+ await new Promise(r => setTimeout(r, 1000));
171
+ // 4. Start gateway — try launchd/systemd first, fall back to background mode
172
+ try {
173
+ await hermesCli.restartGateway();
174
+ }
175
+ catch {
176
+ // Fallback for WSL / environments without launchd/systemd
177
+ try {
178
+ const pid = await hermesCli.startGatewayBackground();
179
+ await new Promise(r => setTimeout(r, 3000));
180
+ console.log(`[Profile] Gateway started in background mode (PID: ${pid})`);
181
+ }
182
+ catch (err) {
183
+ console.error('[Profile] Gateway start failed:', err.message);
184
+ }
185
+ }
186
+ ctx.body = { success: true, message: output.trim() };
187
+ }
188
+ catch (err) {
189
+ ctx.status = 500;
190
+ ctx.body = { error: err.message };
191
+ }
192
+ });
193
+ // POST /api/profiles/:name/export - Export profile to archive
194
+ exports.profileRoutes.post('/api/hermes/profiles/:name/export', async (ctx) => {
195
+ const { name } = ctx.params;
196
+ const { output } = ctx.request.body;
197
+ try {
198
+ const result = await hermesCli.exportProfile(name, output);
199
+ ctx.body = { success: true, message: result.trim() };
200
+ }
201
+ catch (err) {
202
+ ctx.status = 500;
203
+ ctx.body = { error: err.message };
204
+ }
205
+ });
206
+ // POST /api/profiles/import - Import profile from archive
207
+ exports.profileRoutes.post('/api/hermes/profiles/import', async (ctx) => {
208
+ const { archive, name } = ctx.request.body;
209
+ if (!archive) {
210
+ ctx.status = 400;
211
+ ctx.body = { error: 'Missing archive path' };
212
+ return;
213
+ }
214
+ try {
215
+ const result = await hermesCli.importProfile(archive, name);
216
+ ctx.body = { success: true, message: result.trim() };
217
+ }
218
+ catch (err) {
219
+ ctx.status = 500;
220
+ ctx.body = { error: err.message };
221
+ }
222
+ });
@@ -1,10 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.proxy = proxy;
4
- const config_1 = require("../config");
4
+ const config_1 = require("../../config");
5
5
  async function proxy(ctx) {
6
6
  const upstream = config_1.config.upstream.replace(/\/$/, '');
7
- const url = `${upstream}${ctx.path}${ctx.search || ''}`;
7
+ // Rewrite path for upstream gateway:
8
+ // /api/hermes/v1/* -> /v1/* (upstream uses /v1/ prefix)
9
+ // /api/hermes/* -> /api/* (upstream uses /api/ prefix)
10
+ const upstreamPath = ctx.path.replace(/^\/api\/hermes\/v1/, '/v1').replace(/^\/api\/hermes/, '/api');
11
+ const url = `${upstream}${upstreamPath}${ctx.search || ''}`;
8
12
  console.log(`[PROXY] ${ctx.method} ${ctx.path} -> ${url}`);
9
13
  // Build headers — forward most, strip browser-specific ones
10
14
  const headers = {};
@@ -1,2 +1,4 @@
1
1
  import Router from '@koa/router';
2
+ import type { Context, Next } from 'koa';
2
3
  export declare const proxyRoutes: Router<import("koa").DefaultState, import("koa").DefaultContext>;
4
+ export declare function proxyMiddleware(ctx: Context, next: Next): Promise<void>;
@@ -0,0 +1,20 @@
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.proxyRoutes = void 0;
7
+ exports.proxyMiddleware = proxyMiddleware;
8
+ const router_1 = __importDefault(require("@koa/router"));
9
+ const proxy_handler_1 = require("./proxy-handler");
10
+ exports.proxyRoutes = new router_1.default();
11
+ // Proxy unmatched /api/hermes/* and /v1/* to upstream Hermes API
12
+ exports.proxyRoutes.all('/api/hermes/{*any}', proxy_handler_1.proxy);
13
+ exports.proxyRoutes.all('/v1/{*any}', proxy_handler_1.proxy);
14
+ // Also register as middleware so it works reliably with nested .use()
15
+ async function proxyMiddleware(ctx, next) {
16
+ if (ctx.path.startsWith('/api/hermes/') || ctx.path.startsWith('/v1/')) {
17
+ return (0, proxy_handler_1.proxy)(ctx);
18
+ }
19
+ await next();
20
+ }
@@ -38,17 +38,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.sessionRoutes = void 0;
40
40
  const router_1 = __importDefault(require("@koa/router"));
41
- const hermesCli = __importStar(require("../services/hermes-cli"));
41
+ const hermesCli = __importStar(require("../../services/hermes-cli"));
42
42
  exports.sessionRoutes = new router_1.default();
43
43
  // List sessions from Hermes
44
- exports.sessionRoutes.get('/api/sessions', async (ctx) => {
44
+ exports.sessionRoutes.get('/api/hermes/sessions', async (ctx) => {
45
45
  const source = ctx.query.source || undefined;
46
46
  const limit = ctx.query.limit ? parseInt(ctx.query.limit, 10) : undefined;
47
47
  const sessions = await hermesCli.listSessions(source, limit);
48
48
  ctx.body = { sessions };
49
49
  });
50
50
  // Get single session with messages
51
- exports.sessionRoutes.get('/api/sessions/:id', async (ctx) => {
51
+ exports.sessionRoutes.get('/api/hermes/sessions/:id', async (ctx) => {
52
52
  const session = await hermesCli.getSession(ctx.params.id);
53
53
  if (!session) {
54
54
  ctx.status = 404;
@@ -58,7 +58,7 @@ exports.sessionRoutes.get('/api/sessions/:id', async (ctx) => {
58
58
  ctx.body = { session };
59
59
  });
60
60
  // Delete session from Hermes
61
- exports.sessionRoutes.delete('/api/sessions/:id', async (ctx) => {
61
+ exports.sessionRoutes.delete('/api/hermes/sessions/:id', async (ctx) => {
62
62
  const ok = await hermesCli.deleteSession(ctx.params.id);
63
63
  if (!ok) {
64
64
  ctx.status = 500;
@@ -68,7 +68,7 @@ exports.sessionRoutes.delete('/api/sessions/:id', async (ctx) => {
68
68
  ctx.body = { ok: true };
69
69
  });
70
70
  // Rename session
71
- exports.sessionRoutes.post('/api/sessions/:id/rename', async (ctx) => {
71
+ exports.sessionRoutes.post('/api/hermes/sessions/:id/rename', async (ctx) => {
72
72
  const { title } = ctx.request.body;
73
73
  if (!title || typeof title !== 'string') {
74
74
  ctx.status = 400;