@bitseek/hermes-webui 0.1.0-beta.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 (233) hide show
  1. package/README.md +213 -0
  2. package/bin/hermes-webui.mjs +588 -0
  3. package/package.json +25 -0
  4. package/scripts/sync-vendor.mjs +74 -0
  5. package/templates/launchd/com.bitseek.hermes-webui.plist +21 -0
  6. package/templates/systemd/hermes-webui.service +13 -0
  7. package/templates/windows/hermes-webui-task.ps1 +3 -0
  8. package/vendor/agent-frontend-shell/.bitseek-source.json +6 -0
  9. package/vendor/agent-frontend-shell/.dockerignore +7 -0
  10. package/vendor/agent-frontend-shell/.env.docker.example +89 -0
  11. package/vendor/agent-frontend-shell/.env.example +34 -0
  12. package/vendor/agent-frontend-shell/.github/FUNDING.yml +3 -0
  13. package/vendor/agent-frontend-shell/.github/workflows/browser-smoke.yml +42 -0
  14. package/vendor/agent-frontend-shell/.github/workflows/docker-smoke.yml +233 -0
  15. package/vendor/agent-frontend-shell/.github/workflows/native-windows-startup.yml +132 -0
  16. package/vendor/agent-frontend-shell/.github/workflows/release.yml +57 -0
  17. package/vendor/agent-frontend-shell/.github/workflows/tests.yml +88 -0
  18. package/vendor/agent-frontend-shell/.vscode/launch.json +59 -0
  19. package/vendor/agent-frontend-shell/.vscode/settings.json +13 -0
  20. package/vendor/agent-frontend-shell/AGENTS.md +80 -0
  21. package/vendor/agent-frontend-shell/ARCHITECTURE.md +1658 -0
  22. package/vendor/agent-frontend-shell/BUGS.md +52 -0
  23. package/vendor/agent-frontend-shell/CHANGELOG.md +7295 -0
  24. package/vendor/agent-frontend-shell/CONTRIBUTING.md +205 -0
  25. package/vendor/agent-frontend-shell/CONTRIBUTORS.md +107 -0
  26. package/vendor/agent-frontend-shell/DESIGN.md +173 -0
  27. package/vendor/agent-frontend-shell/Dockerfile +91 -0
  28. package/vendor/agent-frontend-shell/LICENSE +21 -0
  29. package/vendor/agent-frontend-shell/README-CUSTOM.md +76 -0
  30. package/vendor/agent-frontend-shell/README.md +705 -0
  31. package/vendor/agent-frontend-shell/ROADMAP.md +351 -0
  32. package/vendor/agent-frontend-shell/SPRINTS.md +147 -0
  33. package/vendor/agent-frontend-shell/TESTING.md +1932 -0
  34. package/vendor/agent-frontend-shell/THEMES.md +170 -0
  35. package/vendor/agent-frontend-shell/api/__init__.py +1 -0
  36. package/vendor/agent-frontend-shell/api/agent_health.py +392 -0
  37. package/vendor/agent-frontend-shell/api/agent_sessions.py +782 -0
  38. package/vendor/agent-frontend-shell/api/auth.py +592 -0
  39. package/vendor/agent-frontend-shell/api/background.py +87 -0
  40. package/vendor/agent-frontend-shell/api/clarify.py +238 -0
  41. package/vendor/agent-frontend-shell/api/commands.py +124 -0
  42. package/vendor/agent-frontend-shell/api/compression_anchor.py +134 -0
  43. package/vendor/agent-frontend-shell/api/config.py +5178 -0
  44. package/vendor/agent-frontend-shell/api/dashboard_probe.py +255 -0
  45. package/vendor/agent-frontend-shell/api/extensions.py +253 -0
  46. package/vendor/agent-frontend-shell/api/gateway_chat.py +435 -0
  47. package/vendor/agent-frontend-shell/api/gateway_watcher.py +230 -0
  48. package/vendor/agent-frontend-shell/api/goals.py +608 -0
  49. package/vendor/agent-frontend-shell/api/helpers.py +474 -0
  50. package/vendor/agent-frontend-shell/api/kanban_bridge.py +1255 -0
  51. package/vendor/agent-frontend-shell/api/metering.py +194 -0
  52. package/vendor/agent-frontend-shell/api/models.py +4210 -0
  53. package/vendor/agent-frontend-shell/api/oauth.py +770 -0
  54. package/vendor/agent-frontend-shell/api/onboarding.py +1046 -0
  55. package/vendor/agent-frontend-shell/api/passkeys.py +365 -0
  56. package/vendor/agent-frontend-shell/api/profiles.py +1499 -0
  57. package/vendor/agent-frontend-shell/api/providers.py +2175 -0
  58. package/vendor/agent-frontend-shell/api/request_diagnostics.py +160 -0
  59. package/vendor/agent-frontend-shell/api/rollback.py +320 -0
  60. package/vendor/agent-frontend-shell/api/routes.py +13990 -0
  61. package/vendor/agent-frontend-shell/api/run_journal.py +284 -0
  62. package/vendor/agent-frontend-shell/api/runner_client.py +156 -0
  63. package/vendor/agent-frontend-shell/api/runtime_adapter.py +431 -0
  64. package/vendor/agent-frontend-shell/api/session_discoverability.py +640 -0
  65. package/vendor/agent-frontend-shell/api/session_events.py +45 -0
  66. package/vendor/agent-frontend-shell/api/session_lifecycle.py +208 -0
  67. package/vendor/agent-frontend-shell/api/session_ops.py +207 -0
  68. package/vendor/agent-frontend-shell/api/session_recovery.py +655 -0
  69. package/vendor/agent-frontend-shell/api/skill_usage.py +32 -0
  70. package/vendor/agent-frontend-shell/api/startup.py +128 -0
  71. package/vendor/agent-frontend-shell/api/state_sync.py +187 -0
  72. package/vendor/agent-frontend-shell/api/streaming.py +7048 -0
  73. package/vendor/agent-frontend-shell/api/system_health.py +167 -0
  74. package/vendor/agent-frontend-shell/api/terminal.py +410 -0
  75. package/vendor/agent-frontend-shell/api/turn_journal.py +214 -0
  76. package/vendor/agent-frontend-shell/api/updates.py +1261 -0
  77. package/vendor/agent-frontend-shell/api/upload.py +322 -0
  78. package/vendor/agent-frontend-shell/api/usage.py +26 -0
  79. package/vendor/agent-frontend-shell/api/workspace.py +867 -0
  80. package/vendor/agent-frontend-shell/api/workspace_git.py +1261 -0
  81. package/vendor/agent-frontend-shell/api/worktrees.py +357 -0
  82. package/vendor/agent-frontend-shell/bootstrap.py +492 -0
  83. package/vendor/agent-frontend-shell/ctl.sh +427 -0
  84. package/vendor/agent-frontend-shell/docker-compose.custom.yml +26 -0
  85. package/vendor/agent-frontend-shell/docker-compose.three-container.yml +168 -0
  86. package/vendor/agent-frontend-shell/docker-compose.two-container.yml +147 -0
  87. package/vendor/agent-frontend-shell/docker-compose.yml +57 -0
  88. package/vendor/agent-frontend-shell/docker_init.bash +459 -0
  89. package/vendor/agent-frontend-shell/docs/CONTRACTS.md +207 -0
  90. package/vendor/agent-frontend-shell/docs/EXTENSIONS.md +212 -0
  91. package/vendor/agent-frontend-shell/docs/ISSUES.md +23 -0
  92. package/vendor/agent-frontend-shell/docs/UIUX-GUIDE.md +196 -0
  93. package/vendor/agent-frontend-shell/docs/advanced-chat-setup.md +83 -0
  94. package/vendor/agent-frontend-shell/docs/docker.md +337 -0
  95. package/vendor/agent-frontend-shell/docs/onboarding-agent-checklist.md +207 -0
  96. package/vendor/agent-frontend-shell/docs/onboarding.md +202 -0
  97. package/vendor/agent-frontend-shell/docs/remote-access.md +75 -0
  98. package/vendor/agent-frontend-shell/docs/rfcs/README.md +53 -0
  99. package/vendor/agent-frontend-shell/docs/rfcs/agent-source-boundary.md +70 -0
  100. package/vendor/agent-frontend-shell/docs/rfcs/canonical-session-resolution.md +124 -0
  101. package/vendor/agent-frontend-shell/docs/rfcs/hermes-run-adapter-contract.md +1079 -0
  102. package/vendor/agent-frontend-shell/docs/rfcs/turn-journal.md +195 -0
  103. package/vendor/agent-frontend-shell/docs/rfcs/webui-run-state-consistency-contract.md +157 -0
  104. package/vendor/agent-frontend-shell/docs/supervisor.md +280 -0
  105. package/vendor/agent-frontend-shell/docs/troubleshooting.md +132 -0
  106. package/vendor/agent-frontend-shell/docs/ui-ux/index.html +863 -0
  107. package/vendor/agent-frontend-shell/docs/ui-ux/two-stage-proposal.html +768 -0
  108. package/vendor/agent-frontend-shell/docs/why-hermes.md +489 -0
  109. package/vendor/agent-frontend-shell/docs/workspace-git.md +92 -0
  110. package/vendor/agent-frontend-shell/docs/wsl-autostart.md +126 -0
  111. package/vendor/agent-frontend-shell/eslint.runtime-guard.config.mjs +35 -0
  112. package/vendor/agent-frontend-shell/extensions/bitseek-design-system.md +330 -0
  113. package/vendor/agent-frontend-shell/extensions/branding/assets/apple-touch-icon.png +0 -0
  114. package/vendor/agent-frontend-shell/extensions/branding/assets/empty-logo.svg +739 -0
  115. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon-192.png +0 -0
  116. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon-32.png +0 -0
  117. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon-512.png +0 -0
  118. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon-512.svg +745 -0
  119. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon.ico +0 -0
  120. package/vendor/agent-frontend-shell/extensions/branding/assets/favicon.svg +745 -0
  121. package/vendor/agent-frontend-shell/extensions/branding/assets/titlebar-icon-v2.svg +751 -0
  122. package/vendor/agent-frontend-shell/extensions/branding/assets/titlebar-icon-v3.svg +739 -0
  123. package/vendor/agent-frontend-shell/extensions/branding/assets/titlebar-icon.svg +745 -0
  124. package/vendor/agent-frontend-shell/extensions/branding/branding.js +112 -0
  125. package/vendor/agent-frontend-shell/extensions/branding/config.json +14 -0
  126. package/vendor/agent-frontend-shell/extensions/branding/manifest.json +53 -0
  127. package/vendor/agent-frontend-shell/extensions/index.js +67 -0
  128. package/vendor/agent-frontend-shell/extensions/loader/hermes-loader.js +77 -0
  129. package/vendor/agent-frontend-shell/extensions/manifest.json +16 -0
  130. package/vendor/agent-frontend-shell/extensions/pages/ai-teammates/page.css +333 -0
  131. package/vendor/agent-frontend-shell/extensions/pages/ai-teammates/page.js +487 -0
  132. package/vendor/agent-frontend-shell/extensions/pages/manifest.json +6 -0
  133. package/vendor/agent-frontend-shell/extensions/pages/registry.css +56 -0
  134. package/vendor/agent-frontend-shell/extensions/pages/registry.js +302 -0
  135. package/vendor/agent-frontend-shell/extensions/themes/bitseek/index.css +93 -0
  136. package/vendor/agent-frontend-shell/extensions/themes/bitseek/index.js +98 -0
  137. package/vendor/agent-frontend-shell/install.sh +63 -0
  138. package/vendor/agent-frontend-shell/mcp_server.py +567 -0
  139. package/vendor/agent-frontend-shell/package.json +12 -0
  140. package/vendor/agent-frontend-shell/pyproject.toml +56 -0
  141. package/vendor/agent-frontend-shell/pytest.ini +3 -0
  142. package/vendor/agent-frontend-shell/requirements.txt +5 -0
  143. package/vendor/agent-frontend-shell/server.py +624 -0
  144. package/vendor/agent-frontend-shell/start.ps1 +210 -0
  145. package/vendor/agent-frontend-shell/start.sh +65 -0
  146. package/vendor/agent-frontend-shell/static/apple-touch-icon.png +0 -0
  147. package/vendor/agent-frontend-shell/static/boot.js +1990 -0
  148. package/vendor/agent-frontend-shell/static/commands.js +1402 -0
  149. package/vendor/agent-frontend-shell/static/favicon-192.png +0 -0
  150. package/vendor/agent-frontend-shell/static/favicon-32.png +0 -0
  151. package/vendor/agent-frontend-shell/static/favicon-512.png +0 -0
  152. package/vendor/agent-frontend-shell/static/favicon-512.svg +18 -0
  153. package/vendor/agent-frontend-shell/static/favicon.ico +0 -0
  154. package/vendor/agent-frontend-shell/static/favicon.svg +20 -0
  155. package/vendor/agent-frontend-shell/static/i18n.js +15389 -0
  156. package/vendor/agent-frontend-shell/static/icons.js +92 -0
  157. package/vendor/agent-frontend-shell/static/index.html +1506 -0
  158. package/vendor/agent-frontend-shell/static/login.js +177 -0
  159. package/vendor/agent-frontend-shell/static/manifest.json +53 -0
  160. package/vendor/agent-frontend-shell/static/messages.js +3521 -0
  161. package/vendor/agent-frontend-shell/static/onboarding.js +800 -0
  162. package/vendor/agent-frontend-shell/static/panels.js +7995 -0
  163. package/vendor/agent-frontend-shell/static/pwa-startup.js +83 -0
  164. package/vendor/agent-frontend-shell/static/sessions.js +5165 -0
  165. package/vendor/agent-frontend-shell/static/style.css +4774 -0
  166. package/vendor/agent-frontend-shell/static/sw.js +173 -0
  167. package/vendor/agent-frontend-shell/static/terminal.js +632 -0
  168. package/vendor/agent-frontend-shell/static/ui.js +8997 -0
  169. package/vendor/agent-frontend-shell/static/vendor/js-yaml/4.1.0/js-yaml.min.js +2 -0
  170. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_AMS-Regular.ttf +0 -0
  171. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_AMS-Regular.woff +0 -0
  172. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  173. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  174. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  175. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  176. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  177. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  178. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  179. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  180. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  181. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  182. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  183. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  184. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  185. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Bold.ttf +0 -0
  186. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Bold.woff +0 -0
  187. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Bold.woff2 +0 -0
  188. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  189. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  190. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  191. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Italic.ttf +0 -0
  192. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Italic.woff +0 -0
  193. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Italic.woff2 +0 -0
  194. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Regular.ttf +0 -0
  195. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Regular.woff +0 -0
  196. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Main-Regular.woff2 +0 -0
  197. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  198. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  199. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  200. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-Italic.ttf +0 -0
  201. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-Italic.woff +0 -0
  202. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Math-Italic.woff2 +0 -0
  203. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  204. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  205. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  206. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  207. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  208. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  209. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  210. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  211. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  212. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Script-Regular.ttf +0 -0
  213. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Script-Regular.woff +0 -0
  214. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Script-Regular.woff2 +0 -0
  215. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size1-Regular.ttf +0 -0
  216. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size1-Regular.woff +0 -0
  217. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  218. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size2-Regular.ttf +0 -0
  219. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size2-Regular.woff +0 -0
  220. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  221. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size3-Regular.ttf +0 -0
  222. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size3-Regular.woff +0 -0
  223. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  224. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size4-Regular.ttf +0 -0
  225. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size4-Regular.woff +0 -0
  226. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  227. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  228. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  229. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  230. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/katex.min.css +1 -0
  231. package/vendor/agent-frontend-shell/static/vendor/katex/0.16.22/katex.min.js +1 -0
  232. package/vendor/agent-frontend-shell/static/vendor/smd.min.js +29 -0
  233. package/vendor/agent-frontend-shell/static/workspace.js +680 -0
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Hermes WebUI Extension Pages Registry
3
+ *
4
+ * Provides hermes.registerPanel() API for adding custom pages
5
+ * without modifying core files. Monkey-patches switchPanel() to
6
+ * support extension panels and dynamically injects DOM elements.
7
+ */
8
+ (function() {
9
+ 'use strict';
10
+
11
+ // Prevent double-loading
12
+ if (document.getElementById('hermes-pages-registry')) return;
13
+
14
+ // Built-in panel names (cannot be overridden)
15
+ var BUILTIN_PANELS = ['chat', 'tasks', 'kanban', 'skills', 'memory',
16
+ 'workspaces', 'profiles', 'todos', 'insights', 'logs', 'settings'];
17
+
18
+ // Namespace
19
+ var NS = (window.hermes = window.hermes || {});
20
+ var panels = new Map();
21
+ NS._panels = panels;
22
+
23
+ // Inject registry marker
24
+ var marker = document.createElement('script');
25
+ marker.id = 'hermes-pages-registry';
26
+ marker.type = 'text/html';
27
+ marker.textContent = 'registry-loaded';
28
+ document.head.appendChild(marker);
29
+
30
+ // Dynamic CSS element for catch-all override
31
+ var dynamicStyle = null;
32
+
33
+ function capitalize(s) {
34
+ return s.charAt(0).toUpperCase() + s.slice(1);
35
+ }
36
+
37
+ function createNavButton(name, label, icon, tooltip, isMobile, labelKey, tooltipKey) {
38
+ var btn = document.createElement('button');
39
+ btn.className = isMobile
40
+ ? 'nav-tab has-tooltip has-tooltip--bottom'
41
+ : 'rail-btn nav-tab has-tooltip';
42
+ btn.setAttribute('data-panel', name);
43
+ if (!isMobile) btn.setAttribute('data-label', label);
44
+ btn.setAttribute('data-tooltip', tooltip || label);
45
+ btn.setAttribute('onclick', "switchPanel('" + name + "',{fromRailClick:true})");
46
+ btn.setAttribute('aria-label', label);
47
+ btn.innerHTML = icon;
48
+
49
+ // Wire up i18n: applyLocaleToDOM() will auto-update on locale switch
50
+ if (labelKey) btn.setAttribute('data-i18n-aria-label', labelKey);
51
+ if (tooltipKey) {
52
+ btn.setAttribute('data-i18n-title', tooltipKey);
53
+ } else if (labelKey) {
54
+ btn.setAttribute('data-i18n-title', labelKey);
55
+ }
56
+
57
+ return btn;
58
+ }
59
+
60
+ function injectNavButton(name, label, icon, tooltip, position, labelKey, tooltipKey) {
61
+ // Desktop rail
62
+ var rail = document.querySelector('.rail');
63
+ if (rail) {
64
+ var railBtn = createNavButton(name, label, icon, tooltip, false, labelKey, tooltipKey);
65
+ var refPanel = position.replace(/^(before|after)-/, '');
66
+ var refBtn = rail.querySelector('[data-panel="' + refPanel + '"]');
67
+ if (refBtn) {
68
+ if (position.startsWith('after-')) {
69
+ refBtn.parentNode.insertBefore(railBtn, refBtn.nextSibling);
70
+ } else {
71
+ refBtn.parentNode.insertBefore(railBtn, refBtn);
72
+ }
73
+ } else {
74
+ rail.appendChild(railBtn);
75
+ }
76
+ }
77
+
78
+ // Mobile sidebar-nav
79
+ var sidebarNav = document.querySelector('.sidebar-nav');
80
+ if (sidebarNav) {
81
+ var mobileBtn = createNavButton(name, label, icon, tooltip, true, labelKey, tooltipKey);
82
+ var refMobile = sidebarNav.querySelector('[data-panel="' + refPanel + '"]');
83
+ if (refMobile) {
84
+ if (position.startsWith('after-')) {
85
+ refMobile.parentNode.insertBefore(mobileBtn, refMobile.nextSibling);
86
+ } else {
87
+ refMobile.parentNode.insertBefore(mobileBtn, refMobile);
88
+ }
89
+ } else {
90
+ sidebarNav.appendChild(mobileBtn);
91
+ }
92
+ }
93
+ }
94
+
95
+ function injectPanelView(name, panelContent) {
96
+ var sidebar = document.querySelector('.sidebar');
97
+ if (!sidebar) return null;
98
+
99
+ var el = document.createElement('div');
100
+ el.className = 'panel-view ext-panel-view';
101
+ el.id = 'panel' + capitalize(name);
102
+ if (typeof panelContent === 'string') {
103
+ el.innerHTML = panelContent;
104
+ } else if (panelContent instanceof HTMLElement) {
105
+ el.appendChild(panelContent);
106
+ }
107
+
108
+ // Insert before resize-handle (last element in sidebar)
109
+ var resizeHandle = sidebar.querySelector('.resize-handle');
110
+ if (resizeHandle) {
111
+ sidebar.insertBefore(el, resizeHandle);
112
+ } else {
113
+ sidebar.appendChild(el);
114
+ }
115
+ return el;
116
+ }
117
+
118
+ function injectMainView(name, mainContent) {
119
+ var main = document.querySelector('main.main');
120
+ if (!main) return null;
121
+
122
+ var el = document.createElement('div');
123
+ el.className = 'ext-main-view main-view';
124
+ el.id = 'main' + capitalize(name);
125
+ if (typeof mainContent === 'string') {
126
+ el.innerHTML = mainContent;
127
+ } else if (mainContent instanceof HTMLElement) {
128
+ el.appendChild(mainContent);
129
+ }
130
+
131
+ main.appendChild(el);
132
+ return el;
133
+ }
134
+
135
+ function updateDynamicCSS() {
136
+ if (!dynamicStyle) {
137
+ dynamicStyle = document.createElement('style');
138
+ dynamicStyle.id = 'hermes-ext-panel-css';
139
+ document.head.appendChild(dynamicStyle);
140
+ }
141
+
142
+ var extNames = [];
143
+ panels.forEach(function(cfg, name) {
144
+ if (cfg.showingClass !== false) {
145
+ extNames.push(name);
146
+ }
147
+ });
148
+
149
+ if (extNames.length === 0) {
150
+ dynamicStyle.textContent = '';
151
+ return;
152
+ }
153
+
154
+ var selectors = extNames.map(function(n) { return '.showing-' + n; });
155
+ var rules = [
156
+ 'main.main:is(' + selectors.join(',') + ') > #mainChat{display:none!important;}'
157
+ ];
158
+
159
+ extNames.forEach(function(n) {
160
+ rules.push('main.main.showing-' + n + ' > #main' + capitalize(n) + '{display:flex;}');
161
+ });
162
+
163
+ dynamicStyle.textContent = rules.join('\n');
164
+ }
165
+
166
+ /**
167
+ * Register a new panel/extension page
168
+ *
169
+ * @param {Object} config
170
+ * @param {string} config.name - Panel identifier (required)
171
+ * @param {string} config.label - Display name (fallback if no labelKey)
172
+ * @param {string} config.labelKey - i18n key for nav button label/aria-label
173
+ * @param {string} config.icon - SVG markup for nav button
174
+ * @param {string} config.tooltip - Hover tooltip (fallback if no tooltipKey)
175
+ * @param {string} config.tooltipKey - i18n key for nav button tooltip
176
+ * @param {string} config.position - 'before-settings' (default) or 'before-logs'
177
+ * @param {string|HTMLElement} config.panel - Sidebar panel content
178
+ * @param {string|HTMLElement} config.main - Main content area
179
+ * @param {Function} config.onActivate - Called when panel becomes active
180
+ * @param {Function} config.onDeactivate - Called when leaving panel
181
+ * @param {boolean} config.showingClass - Whether to add showing- class (default true)
182
+ */
183
+ NS.registerPanel = function(config) {
184
+ if (!config || !config.name) {
185
+ console.warn('[pages-registry] registerPanel requires a name');
186
+ return;
187
+ }
188
+
189
+ var name = config.name;
190
+
191
+ // Validate name
192
+ if (BUILTIN_PANELS.indexOf(name) !== -1) {
193
+ console.warn('[pages-registry] Cannot override built-in panel:', name);
194
+ return;
195
+ }
196
+ if (panels.has(name)) {
197
+ console.warn('[pages-registry] Panel already registered:', name);
198
+ return;
199
+ }
200
+
201
+ var labelKey = config.labelKey;
202
+ var tooltipKey = config.tooltipKey;
203
+ var label = (labelKey && typeof t === 'function') ? (t(labelKey) || config.label || name) : (config.label || name);
204
+ var tooltip = (tooltipKey && typeof t === 'function') ? (t(tooltipKey) || config.tooltip || label) : (config.tooltip || label);
205
+ var icon = config.icon || '<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/></svg>';
206
+ var position = config.position || 'before-settings';
207
+
208
+ // Inject DOM elements
209
+ var panelEl = injectPanelView(name, config.panel);
210
+ var mainEl = injectMainView(name, config.main);
211
+ injectNavButton(name, label, icon, tooltip, position, labelKey, tooltipKey);
212
+
213
+ // Register labelKey in APP_TITLEBAR_KEYS so syncAppTitlebar shows translated title
214
+ if (labelKey && typeof APP_TITLEBAR_KEYS !== 'undefined') {
215
+ APP_TITLEBAR_KEYS[name] = labelKey;
216
+ }
217
+
218
+ // Store in registry
219
+ panels.set(name, {
220
+ config: config,
221
+ panelEl: panelEl,
222
+ mainEl: mainEl,
223
+ showingClass: config.showingClass !== false
224
+ });
225
+
226
+ // Update CSS rules
227
+ updateDynamicCSS();
228
+
229
+ console.log('[pages-registry] Panel registered:', name);
230
+ };
231
+
232
+ /**
233
+ * Load a page script or stylesheet dynamically
234
+ */
235
+ NS.loadPage = function(url) {
236
+ if (url.endsWith('.css')) {
237
+ var link = document.createElement('link');
238
+ link.rel = 'stylesheet';
239
+ link.href = url;
240
+ document.head.appendChild(link);
241
+ } else {
242
+ var s = document.createElement('script');
243
+ s.src = url;
244
+ s.defer = true;
245
+ document.body.appendChild(s);
246
+ }
247
+ };
248
+
249
+ // Monkey-patch switchPanel()
250
+ var origSwitchPanel = window.switchPanel;
251
+ if (typeof origSwitchPanel === 'function') {
252
+ window.switchPanel = async function(name, opts) {
253
+ var result = await origSwitchPanel.call(this, name, opts);
254
+ var nextPanel = name || 'chat';
255
+ var mainEl = document.querySelector('main.main');
256
+
257
+ // Handle extension panels
258
+ if (mainEl) {
259
+ // Add showing- class for extension panels
260
+ if (panels.has(nextPanel)) {
261
+ var cfg = panels.get(nextPanel);
262
+ if (cfg.showingClass) {
263
+ mainEl.classList.add('showing-' + nextPanel);
264
+ }
265
+ }
266
+
267
+ // Remove showing- from extension panels when switching away
268
+ panels.forEach(function(cfg, pname) {
269
+ if (pname !== nextPanel && cfg.showingClass) {
270
+ mainEl.classList.remove('showing-' + pname);
271
+ }
272
+ });
273
+ }
274
+
275
+ // Call lifecycle hooks
276
+ panels.forEach(function(cfg, pname) {
277
+ if (pname === nextPanel && typeof cfg.config.onActivate === 'function') {
278
+ cfg.config.onActivate();
279
+ } else if (pname !== nextPanel && typeof cfg.config.onDeactivate === 'function') {
280
+ cfg.config.onDeactivate();
281
+ }
282
+ });
283
+
284
+ return result;
285
+ };
286
+ }
287
+
288
+ // Auto-load pages from manifest
289
+ (async function() {
290
+ try {
291
+ var resp = await fetch('/extensions/pages/manifest.json');
292
+ if (!resp.ok) return;
293
+ var manifest = await resp.json();
294
+ if (Array.isArray(manifest.pages)) {
295
+ manifest.pages.forEach(function(p) { NS.loadPage(p); });
296
+ }
297
+ } catch(e) {
298
+ // Manifest not found or invalid, skip
299
+ }
300
+ })();
301
+
302
+ })();
@@ -0,0 +1,93 @@
1
+ /* ═══════════════════════════════════════════════════════════════════════════
2
+ BitSeek Skin for Hermes WebUI
3
+ Coral Orange brand (#FF7F50) with warm dark / clean light palettes.
4
+ Loaded via HERMES_WEBUI_EXTENSION_STYLESHEET_URLS — no core files modified.
5
+ ═══════════════════════════════════════════════════════════════════════════ */
6
+
7
+ /* ── Light mode (B-end Dashboard) ── */
8
+ :root[data-skin="bitseek"] {
9
+ --bg:#FFFFFF;--sidebar:#FAFAFA;--surface:#F6F6F6;
10
+ --border:#ECEFF8;--border2:#DFDFDF;
11
+ --text:#404040;--muted:#A7A7A7;--strong:#404040;--em:#646464;
12
+ --accent:#FF7F50;--accent-hover:#FA4321;--accent-text:#DE360C;
13
+ --accent-bg:rgba(255,127,80,0.08);--accent-bg-strong:rgba(255,127,80,0.16);
14
+ --code-bg:#F6F6F6;--code-inline-bg:rgba(255,127,80,0.08);--code-text:#DE360C;--pre-text:#404040;
15
+ --topbar-bg:rgba(255,255,255,0.96);--main-bg:rgba(255,255,255,0.55);
16
+ --input-bg:rgba(0,0,0,0.03);--hover-bg:#FFF7ED;
17
+ --focus-ring:rgba(255,127,80,0.3);--focus-glow:rgba(255,127,80,0.1);
18
+ --blue:#4A90D9;--gold:#DE360C;
19
+ --error:#EF4444;--success:#83D04E;--warning:#E68A00;--info:#4A90D9;
20
+ --surface-subtle:rgba(255,127,80,0.03);--surface-subtle-hover:rgba(255,127,80,0.06);
21
+ --border-subtle:rgba(255,127,80,0.06);--border-muted:rgba(255,127,80,0.12);
22
+ --user-bubble-bg:#FFF7ED;--user-bubble-border:rgba(255,127,80,0.25);
23
+ --user-bubble-text:#404040;--user-bubble-placeholder:#A7A7A7;
24
+ --user-selection-bg:rgba(255,127,80,0.25);--user-selection-text:#404040;
25
+ }
26
+
27
+ /* ── Dark mode (C-end Marketing) ── */
28
+ :root.dark[data-skin="bitseek"] {
29
+ --bg:#160804;--sidebar:#1A1A1A;--surface:#1A1A1A;
30
+ --border:#040404;--border2:rgba(255,255,255,0.12);
31
+ --text:#FFFFFF;--muted:#C4BAB8;--strong:#FFFFFF;--em:#C4BAB8;
32
+ --accent:#FF7F50;--accent-hover:#FF9570;--accent-text:#FF9570;
33
+ --accent-bg:rgba(255,127,80,0.12);--accent-bg-strong:rgba(255,127,80,0.22);
34
+ --code-bg:#1A1A1A;--code-inline-bg:rgba(255,127,80,0.15);--code-text:#FF9570;--pre-text:#FFFFFF;
35
+ --topbar-bg:rgba(22,8,4,0.96);--main-bg:rgba(22,8,4,0.55);
36
+ --input-bg:rgba(255,255,255,0.04);--hover-bg:rgba(255,255,255,0.06);
37
+ --focus-ring:rgba(255,127,80,0.35);--focus-glow:rgba(255,127,80,0.1);
38
+ --blue:#6AABE8;--gold:#FF9570;
39
+ --error:#FF6B6B;--success:#83D04E;--warning:#FFB74D;--info:#6AABE8;
40
+ --surface-subtle:rgba(255,255,255,0.03);--surface-subtle-hover:rgba(255,255,255,0.06);
41
+ --border-subtle:rgba(255,255,255,0.06);--border-muted:rgba(255,255,255,0.12);
42
+ --user-bubble-bg:rgba(255,127,80,0.12);--user-bubble-border:rgba(255,127,80,0.20);
43
+ --user-bubble-text:#FFFFFF;--user-bubble-placeholder:#C4BAB8;
44
+ --user-selection-bg:rgba(255,127,80,0.28);--user-selection-text:#FFFFFF;
45
+ }
46
+
47
+ /* ── Onboarding: theme-aware overrides ── */
48
+ /* style.css hardcodes dark backgrounds for .onboarding-card etc.
49
+ These rules restore correct colors for both light and dark modes. */
50
+
51
+ /* -- Light mode onboarding -- */
52
+ :root[data-skin="bitseek"]:not(.dark) .onboarding-overlay{background:rgba(200,205,215,.72);}
53
+ :root[data-skin="bitseek"]:not(.dark) .onboarding-card{background:#fff;border-color:var(--border);box-shadow:0 24px 80px rgba(0,0,0,.10);}
54
+ :root[data-skin="bitseek"]:not(.dark) .onboarding-step{background:var(--input-bg);}
55
+ :root[data-skin="bitseek"]:not(.dark) .onboarding-step.active{background:var(--accent-bg);}
56
+ :root[data-skin="bitseek"]:not(.dark) .onboarding-step-index{background:rgba(0,0,0,.06);}
57
+ :root[data-skin="bitseek"]:not(.dark) .onboarding-status{background:var(--input-bg);}
58
+ :root[data-skin="bitseek"]:not(.dark) .onboarding-check{background:var(--input-bg);}
59
+
60
+ /* -- Dark mode onboarding (uses CSS vars, just fix overlay tint) -- */
61
+ :root.dark[data-skin="bitseek"] .onboarding-overlay{background:rgba(7,12,19,.82);}
62
+ :root.dark[data-skin="bitseek"] .onboarding-card{background:linear-gradient(180deg,rgba(22,8,4,.98),rgba(22,8,4,.96));}
63
+
64
+ /* ── Component overrides ── */
65
+ /* New chat button: solid coral, white text */
66
+ :root[data-skin="bitseek"]:not(.dark) .new-chat-btn,
67
+ :root.dark[data-skin="bitseek"] .new-chat-btn{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600;box-shadow:0 1px 2px rgba(255,127,80,0.15);}
68
+ :root[data-skin="bitseek"]:not(.dark) .new-chat-btn:hover,
69
+ :root.dark[data-skin="bitseek"] .new-chat-btn:hover{background:var(--accent-hover);border-color:var(--accent-hover);color:#fff;}
70
+
71
+ /* Tool / thinking cards */
72
+ :root[data-skin="bitseek"] .tool-card{background:rgba(255,127,80,0.025);border-color:var(--border);border-radius:10px;}
73
+ :root[data-skin="bitseek"] .tool-card:hover{border-color:var(--border2);}
74
+ :root[data-skin="bitseek"] .tool-card-running{background:var(--accent-bg);border-color:var(--accent-bg-strong);}
75
+ :root[data-skin="bitseek"] .tool-card-name{color:var(--muted);font-weight:500;}
76
+ :root[data-skin="bitseek"] .tool-arg-key{color:var(--accent-text);}
77
+ :root[data-skin="bitseek"] .tool-card-more{color:var(--accent-text);}
78
+ :root[data-skin="bitseek"] .tool-card-running-dot{background:var(--accent);}
79
+ :root.dark[data-skin="bitseek"] .tool-card{background:rgba(255,255,255,0.03);}
80
+
81
+ /* User bubble: warm tint pill */
82
+ :root[data-skin="bitseek"] .msg-row[data-role="user"] .msg-body{border-radius:16px;padding:12px 16px;}
83
+ :root[data-skin="bitseek"] .msg-row[data-role="user"] .msg-body code{color:var(--user-bubble-text);background:rgba(255,127,80,0.08);}
84
+
85
+ /* Send button pop and active session indicator */
86
+ :root[data-skin="bitseek"] button.send-btn{box-shadow:0 1px 3px rgba(255,127,80,0.3);}
87
+ :root[data-skin="bitseek"] button.send-btn:hover{box-shadow:0 2px 8px rgba(255,127,80,0.45);}
88
+ :root[data-skin="bitseek"] .session-item.active{border-left:2px solid var(--accent);}
89
+ :root[data-skin="bitseek"] .composer-box{border-radius:18px;}
90
+
91
+ :root[data-skin="bitseek"] .app-titlebar-inner {width:100%;}
92
+ :root[data-skin="bitseek"] .app-titlebar-icon {flex: 1;}
93
+ :root[data-skin="bitseek"] .app-titlebar-inner::after {content: ""; flex: 1;}
@@ -0,0 +1,98 @@
1
+ /* ═══════════════════════════════════════════════════════════════════════════
2
+ BitSeek Skin Extension for Hermes WebUI
3
+ Registers the "bitseek" skin into the live system without core edits.
4
+ Loaded via HERMES_WEBUI_EXTENSION_SCRIPT_URLS — runs after boot.js.
5
+ ═══════════════════════════════════════════════════════════════════════════ */
6
+ (() => {
7
+ if (document.getElementById('bitseek-skin-ext')) return;
8
+
9
+ const SKIN_KEY = 'bitseek';
10
+ const SKIN_LABEL = 'BitSeek';
11
+ const SKIN_COLORS = ['#FF7F50', '#FA4321', '#FFF7ED'];
12
+
13
+ /* ── 1. Inject into _VALID_SKINS so the system recognizes "bitseek" ── */
14
+ if (typeof _VALID_SKINS !== 'undefined' && _VALID_SKINS instanceof Set) {
15
+ _VALID_SKINS.add(SKIN_KEY);
16
+ }
17
+
18
+ /* ── 2. Inject into _SKINS array so /theme command and picker can find it ── */
19
+ if (typeof _SKINS !== 'undefined' && Array.isArray(_SKINS)) {
20
+ const alreadyExists = _SKINS.some(s => (s.value || s.name).toLowerCase() === SKIN_KEY);
21
+ if (!alreadyExists) {
22
+ _SKINS.push({ name: SKIN_LABEL, colors: SKIN_COLORS });
23
+ }
24
+ }
25
+
26
+ /* ── 3. Append BitSeek button to the skin picker grid ── */
27
+ function injectPickerButton() {
28
+ const grid = document.getElementById('skinPickerGrid');
29
+ if (!grid) return false;
30
+
31
+ // Check if already injected
32
+ if (grid.querySelector('[data-skin-val="' + SKIN_KEY + '"]')) return true;
33
+
34
+ const btn = document.createElement('button');
35
+ btn.type = 'button';
36
+ btn.className = 'skin-pick-btn';
37
+ btn.dataset.skinVal = SKIN_KEY;
38
+ btn.style.cssText = 'border:1px solid var(--border2);border-radius:8px;padding:8px 4px;text-align:center;cursor:pointer;background:none;transition:all .15s';
39
+ btn.onclick = () => {
40
+ if (typeof _pickSkin === 'function') _pickSkin(SKIN_KEY);
41
+ };
42
+
43
+ const dots = SKIN_COLORS.map(c =>
44
+ '<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:' + c + '"></span>'
45
+ ).join('');
46
+
47
+ btn.innerHTML =
48
+ '<div style="display:flex;gap:3px;justify-content:center;margin-bottom:4px">' + dots + '</div>' +
49
+ '<span style="font-size:11px;color:var(--text)">' + SKIN_LABEL + '</span>';
50
+
51
+ grid.appendChild(btn);
52
+
53
+ // Sync active state
54
+ const currentSkin = (localStorage.getItem('hermes-skin') || '').toLowerCase();
55
+ if (currentSkin === SKIN_KEY) {
56
+ btn.classList.add('active');
57
+ }
58
+
59
+ return true;
60
+ }
61
+
62
+ // Try immediately, then retry with observer if picker not yet rendered
63
+ if (!injectPickerButton()) {
64
+ const observer = new MutationObserver(() => {
65
+ if (injectPickerButton()) observer.disconnect();
66
+ });
67
+ observer.observe(document.body, { childList: true, subtree: true });
68
+ // Safety timeout — stop observing after 10s
69
+ setTimeout(() => observer.disconnect(), 10000);
70
+ }
71
+
72
+ /* ── 4. Sync active state when skin changes (observe attribute) ── */
73
+ const skinObserver = new MutationObserver(() => {
74
+ const active = document.documentElement.dataset.skin || '';
75
+ document.querySelectorAll('#skinPickerGrid .skin-pick-btn').forEach(btn => {
76
+ btn.classList.toggle('active', btn.dataset.skinVal === active);
77
+ });
78
+ });
79
+ skinObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['data-skin'] });
80
+
81
+ /* ── 5. Hook into /theme command for "bitseek" ── */
82
+ // Intercept keyboard submit to catch "/theme bitseek" before cmdTheme processes it
83
+ document.addEventListener('keydown', (e) => {
84
+ if (e.key !== 'Enter') return;
85
+ const input = document.getElementById('msg');
86
+ if (!input) return;
87
+ const val = (input.value || '').trim();
88
+ const match = val.match(/^\/theme\s+(bitseek)$/i);
89
+ if (!match) return;
90
+ e.preventDefault();
91
+ e.stopPropagation();
92
+ input.value = '';
93
+ if (typeof _pickSkin === 'function') _pickSkin(SKIN_KEY);
94
+ // Close any open command palette
95
+ const palette = document.getElementById('cmdPalette');
96
+ if (palette) palette.style.display = 'none';
97
+ }, true);
98
+ })();
@@ -0,0 +1,63 @@
1
+ #!/bin/bash
2
+ # Hermes WebUI 定制版一键安装脚本
3
+ # 适用于小白用户,自动安装所有依赖
4
+
5
+ set -e
6
+
7
+ echo "🚀 开始安装 Hermes WebUI 定制版..."
8
+
9
+ # 检查系统
10
+ if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
11
+ echo "❌ 不支持 Windows,请使用 WSL2 或虚拟机"
12
+ exit 1
13
+ fi
14
+
15
+ # 检查 Python
16
+ if ! command -v python3 &> /dev/null; then
17
+ echo "❌ 未找到 Python3,请先安装 Python 3.11+"
18
+ exit 1
19
+ fi
20
+
21
+ # 下载项目 - 使用 GitHub Release 方式
22
+ DOWNLOAD_URL="https://github.com/yourusername/hermes-webui/releases/latest/download/hermes-webui-custom.zip"
23
+ INSTALL_DIR="$HOME/hermes-webui-custom"
24
+
25
+ if [ -d "$INSTALL_DIR" ]; then
26
+ echo "📁 发现已存在的安装目录,正在删除旧版本..."
27
+ rm -rf "$INSTALL_DIR"
28
+ fi
29
+
30
+ echo "📥 正在下载项目..."
31
+ # 下载 zip 文件
32
+ curl -L -o "/tmp/hermes-webui-custom.zip" "$DOWNLOAD_URL" || {
33
+ echo "❌ 下载失败,请检查:"
34
+ echo " 1. 网络连接是否正常"
35
+ echo " 2. Release 地址是否正确: $DOWNLOAD_URL"
36
+ echo " 3. 确保 Release 已创建并包含 zip 文件"
37
+ exit 1
38
+ }
39
+
40
+ # 解压
41
+ cd "$HOME"
42
+ unzip -q "/tmp/hermes-webui-custom.zip" -d "$INSTALL_DIR" || {
43
+ echo "❌ 解压失败,请检查下载的文件"
44
+ exit 1
45
+ }
46
+
47
+ # 清理临时文件
48
+ rm "/tmp/hermes-webui-custom.zip"
49
+ cd "$INSTALL_DIR"
50
+
51
+ # 运行自动安装
52
+ echo "🔧 正在安装依赖和配置..."
53
+ python3 bootstrap.py --no-browser
54
+
55
+ echo "✅ 安装完成!"
56
+ echo ""
57
+ echo "🎯 启动方式:"
58
+ echo " cd $INSTALL_DIR"
59
+ echo " ./start.sh"
60
+ echo ""
61
+ echo "🌐 然后访问: http://localhost:8787"
62
+ echo ""
63
+ echo "💡 首次使用需要配置 AI 提供商 API 密钥"