hermium 0.1.10 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/bin/hermium.mjs +201 -136
- package/dist/api.mjs +3513 -0
- package/dist/{web-server → server}/_chunks/ssr-renderer.mjs +1 -1
- package/dist/{web-server → server}/_libs/base-ui__react.mjs +338 -34
- package/dist/{web-server → server}/_libs/base-ui__utils.mjs +38 -33
- package/dist/server/_libs/comma-separated-tokens.mjs +10 -0
- package/dist/{web-server → server}/_libs/floating-ui__core.mjs +3 -3
- package/dist/{web-server → server}/_libs/floating-ui__dom.mjs +4 -4
- package/dist/{web-server → server}/_libs/floating-ui__react-dom.mjs +3 -3
- package/dist/{web-server → server}/_libs/floating-ui__utils.mjs +38 -38
- package/dist/{web-server → server}/_libs/h3.mjs +3 -3
- package/dist/server/_libs/hast-util-is-element.mjs +75 -0
- package/dist/{web-server → server}/_libs/hast-util-to-jsx-runtime.mjs +2 -2
- package/dist/server/_libs/hast-util-to-text.mjs +305 -0
- package/dist/server/_libs/highlight.js.mjs +14756 -0
- package/dist/server/_libs/lowlight.mjs +262 -0
- package/dist/{web-server → server}/_libs/mdast-util-from-markdown.mjs +1 -1
- package/dist/{web-server → server}/_libs/mdast-util-gfm-autolink-literal+[...].mjs +2 -2
- package/dist/{web-server → server}/_libs/mdast-util-to-hast.mjs +1 -1
- package/dist/{web-server → server}/_libs/micromark-core-commonmark.mjs +24 -24
- package/dist/{web-server → server}/_libs/micromark-extension-gfm-autolink-literal+[...].mjs +1 -1
- package/dist/{web-server → server}/_libs/micromark-extension-gfm-footnote+[...].mjs +2 -2
- package/dist/{web-server → server}/_libs/micromark-extension-gfm-table.mjs +1 -1
- package/dist/{web-server → server}/_libs/micromark-extension-gfm-task-list-item+[...].mjs +1 -1
- package/dist/{web-server → server}/_libs/micromark-factory-destination.mjs +1 -1
- package/dist/{web-server → server}/_libs/micromark-factory-label.mjs +1 -1
- package/dist/{web-server → server}/_libs/micromark-factory-space.mjs +1 -1
- package/dist/{web-server → server}/_libs/micromark-factory-whitespace.mjs +1 -1
- package/dist/{web-server → server}/_libs/micromark-util-character.mjs +12 -12
- package/dist/{web-server → server}/_libs/micromark-util-classify-character+[...].mjs +1 -1
- package/dist/{web-server → server}/_libs/micromark-util-html-tag-name.mjs +2 -2
- package/dist/{web-server → server}/_libs/micromark-util-sanitize-uri.mjs +1 -1
- package/dist/{web-server → server}/_libs/micromark.mjs +3 -3
- package/dist/{web-server → server}/_libs/property-information.mjs +2 -3
- package/dist/{web-server → server}/_libs/react-dom.mjs +1 -1
- package/dist/{web-server → server}/_libs/react.mjs +42 -42
- package/dist/server/_libs/rehype-highlight.mjs +94 -0
- package/dist/server/_libs/space-separated-tokens.mjs +6 -0
- package/dist/server/_libs/tabler__icons-react.mjs +140 -0
- package/dist/server/_libs/tailwind-merge.mjs +3255 -0
- package/dist/server/_libs/tanstack__history.mjs +29 -0
- package/dist/{web-server → server}/_libs/tanstack__react-router.mjs +3 -3
- package/dist/{web-server → server}/_libs/tanstack__router-core.mjs +47 -741
- package/dist/server/_libs/unist-util-find-after.mjs +41 -0
- package/dist/{web-server → server}/_libs/unist-util-position.mjs +2 -2
- package/dist/{web-server → server}/_libs/use-sync-external-store.mjs +1 -1
- package/dist/server/_libs/zustand.mjs +43 -0
- package/dist/server/_ssr/ChatInputBlock-Bu2-iop_.mjs +220 -0
- package/dist/server/_ssr/MarkdownMessage-CNS7OSKN.mjs +68 -0
- package/dist/server/_ssr/chat._sessionId-P02iSfut.mjs +477 -0
- package/dist/{web-server/_ssr/index-CoDfv1vI.mjs → server/_ssr/chat.index-BYB_48NC.mjs} +6 -8
- package/dist/server/_ssr/index-C1mT_2d8.mjs +4890 -0
- package/dist/server/_ssr/index-DFV9_oCk.mjs +43 -0
- package/dist/server/_ssr/memory-CW_fSOG9.mjs +257 -0
- package/dist/{web-server/_ssr/router-CS6Zq3md.mjs → server/_ssr/router-CUAfx91O.mjs} +1009 -1108
- package/dist/server/_ssr/settings-DoXurzvn.mjs +10 -0
- package/dist/server/_ssr/skills-Cs7A5ZwO.mjs +422 -0
- package/dist/server/_ssr/theme-BK4-7E2h.mjs +42 -0
- package/dist/server/_ssr/usage-Bs2-LXGz.mjs +298 -0
- package/dist/server/_tanstack-start-manifest_v-C7Upe2TI.mjs +4 -0
- package/dist/server/index.mjs +502 -240
- package/package.json +4 -3
- package/dist/public/assets/IconAlertCircle-BW147gsG.js +0 -1
- package/dist/public/assets/IconAlertTriangle-DCoTLVSd.js +0 -1
- package/dist/public/assets/IconCheck-DAO7Fpl9.js +0 -1
- package/dist/public/assets/IconCode-BqfTl5wU.js +0 -1
- package/dist/public/assets/IconLoader2-B_pehSXN.js +0 -1
- package/dist/public/assets/IconRefresh-BbMGoMV8.js +0 -1
- package/dist/public/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
- package/dist/public/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
- package/dist/public/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
- package/dist/public/assets/index-BL9a2Xg9.js +0 -1
- package/dist/public/assets/index-BSwXjgjr.js +0 -1
- package/dist/public/assets/index-BWl8tn18.js +0 -1
- package/dist/public/assets/index-CQh8SXb2.js +0 -94
- package/dist/public/assets/index-Cxd-kSUY.js +0 -1
- package/dist/public/assets/index-DA5SH--7.js +0 -2
- package/dist/public/assets/index-DCHbvtBS.js +0 -1
- package/dist/public/assets/index-DCYXJZEe.js +0 -1
- package/dist/public/assets/index-DFDfp0ca.js +0 -1
- package/dist/public/assets/index-GuAAqSCJ.js +0 -14
- package/dist/public/assets/index-WIDirTHx.js +0 -29
- package/dist/public/assets/index-X3XZcAzy.js +0 -1
- package/dist/public/assets/input-7TQEEJq6.js +0 -1
- package/dist/public/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/public/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/public/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/public/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/public/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/public/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/public/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/public/assets/models-BlUb1eaf.js +0 -1
- package/dist/public/assets/styles-PHtUFHUr.css +0 -1
- package/dist/public/assets/switch-B_iYUUM3.js +0 -1
- package/dist/public/assets/syntax-highlighter-DcBYfnEK.js +0 -6
- package/dist/public/assets/textarea-Dm4aaRqS.js +0 -1
- package/dist/public/favicon.ico +0 -0
- package/dist/public/favicon.png +0 -0
- package/dist/public/manifest.json +0 -25
- package/dist/public/nous-logo.png +0 -0
- package/dist/public/robots.txt +0 -3
- package/dist/web-server/_libs/babel__runtime.mjs +0 -237
- package/dist/web-server/_libs/character-entities-legacy.mjs +0 -111
- package/dist/web-server/_libs/character-reference-invalid.mjs +0 -33
- package/dist/web-server/_libs/comma-separated-tokens.mjs +0 -31
- package/dist/web-server/_libs/cookie-es.mjs +0 -44
- package/dist/web-server/_libs/hast-util-parse-selector.mjs +0 -39
- package/dist/web-server/_libs/hastscript.mjs +0 -200
- package/dist/web-server/_libs/is-alphabetical.mjs +0 -7
- package/dist/web-server/_libs/is-alphanumerical.mjs +0 -8
- package/dist/web-server/_libs/is-decimal.mjs +0 -7
- package/dist/web-server/_libs/is-hexadecimal.mjs +0 -7
- package/dist/web-server/_libs/lowlight.mjs +0 -1
- package/dist/web-server/_libs/parse-entities.mjs +0 -245
- package/dist/web-server/_libs/react-syntax-highlighter.mjs +0 -941
- package/dist/web-server/_libs/refractor.mjs +0 -2425
- package/dist/web-server/_libs/seroval-plugins.mjs +0 -58
- package/dist/web-server/_libs/seroval.mjs +0 -1775
- package/dist/web-server/_libs/space-separated-tokens.mjs +0 -11
- package/dist/web-server/_libs/tabler__icons-react.mjs +0 -233
- package/dist/web-server/_libs/tanstack__history.mjs +0 -204
- package/dist/web-server/_libs/tanstack__query-core.mjs +0 -2552
- package/dist/web-server/_libs/tanstack__react-query.mjs +0 -190
- package/dist/web-server/_libs/zod.mjs +0 -3915
- package/dist/web-server/_libs/zustand.mjs +0 -343
- package/dist/web-server/_ssr/index--Bo2_ipW.mjs +0 -277
- package/dist/web-server/_ssr/index-BEvygh5x.mjs +0 -612
- package/dist/web-server/_ssr/index-BFaKxYfN.mjs +0 -40
- package/dist/web-server/_ssr/index-BdrMzRTd.mjs +0 -513
- package/dist/web-server/_ssr/index-Cwp8Gyl1.mjs +0 -1812
- package/dist/web-server/_ssr/index-DQsfKYjV.mjs +0 -449
- package/dist/web-server/_ssr/index-Dbs9k8Ea.mjs +0 -251
- package/dist/web-server/_ssr/index-Dk93oyZD.mjs +0 -213
- package/dist/web-server/_ssr/index-KNJ7huw_.mjs +0 -369
- package/dist/web-server/_ssr/index.mjs +0 -1558
- package/dist/web-server/_ssr/input-BV1DMASc.mjs +0 -20
- package/dist/web-server/_ssr/models-MzrvbL2i.mjs +0 -43
- package/dist/web-server/_ssr/start-HYkvq4Ni.mjs +0 -4
- package/dist/web-server/_ssr/switch-Bd-Sg0HG.mjs +0 -33
- package/dist/web-server/_ssr/syntax-highlighter-5vezNTce.mjs +0 -62
- package/dist/web-server/_ssr/textarea-CB4kQp9w.mjs +0 -18
- package/dist/web-server/_tanstack-start-manifest_v-m5lY48LR.mjs +0 -4
- package/dist/web-server/index.mjs +0 -611
- /package/dist/{web-server → server}/__23tanstack-start-plugin-adapters-Cwee5PKy.mjs +0 -0
- /package/dist/{web-server → server}/_libs/bail.mjs +0 -0
- /package/dist/{web-server → server}/_libs/ccount.mjs +0 -0
- /package/dist/{web-server → server}/_libs/character-entities.mjs +0 -0
- /package/dist/{web-server → server}/_libs/class-variance-authority.mjs +0 -0
- /package/dist/{web-server → server}/_libs/clsx.mjs +0 -0
- /package/dist/{web-server/_libs/croner.mjs → server/_libs/cookie-es.mjs} +0 -0
- /package/dist/{web-server/_libs/crossws.mjs → server/_libs/croner.mjs} +0 -0
- /package/dist/{web-server/_libs/fault.mjs → server/_libs/crossws.mjs} +0 -0
- /package/dist/{web-server → server}/_libs/decode-named-character-reference+[...].mjs +0 -0
- /package/dist/{web-server → server}/_libs/devlop.mjs +0 -0
- /package/dist/{web-server → server}/_libs/escape-string-regexp.mjs +0 -0
- /package/dist/{web-server → server}/_libs/estree-util-is-identifier-name.mjs +0 -0
- /package/dist/{web-server → server}/_libs/extend.mjs +0 -0
- /package/dist/{web-server → server}/_libs/hast-util-whitespace.mjs +0 -0
- /package/dist/{web-server → server}/_libs/hookable.mjs +0 -0
- /package/dist/{web-server → server}/_libs/html-url-attributes.mjs +0 -0
- /package/dist/{web-server → server}/_libs/inline-style-parser.mjs +0 -0
- /package/dist/{web-server → server}/_libs/is-plain-obj.mjs +0 -0
- /package/dist/{web-server → server}/_libs/isbot.mjs +0 -0
- /package/dist/{web-server → server}/_libs/longest-streak.mjs +0 -0
- /package/dist/{web-server → server}/_libs/markdown-table.mjs +0 -0
- /package/dist/{web-server → server}/_libs/mdast-util-find-and-replace.mjs +0 -0
- /package/dist/{web-server → server}/_libs/mdast-util-gfm-footnote.mjs +0 -0
- /package/dist/{web-server → server}/_libs/mdast-util-gfm-strikethrough.mjs +0 -0
- /package/dist/{web-server → server}/_libs/mdast-util-gfm-table.mjs +0 -0
- /package/dist/{web-server → server}/_libs/mdast-util-gfm-task-list-item.mjs +0 -0
- /package/dist/{web-server → server}/_libs/mdast-util-gfm.mjs +0 -0
- /package/dist/{web-server → server}/_libs/mdast-util-phrasing.mjs +0 -0
- /package/dist/{web-server → server}/_libs/mdast-util-to-markdown.mjs +0 -0
- /package/dist/{web-server → server}/_libs/mdast-util-to-string.mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-extension-gfm-strikethrough+[...].mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-extension-gfm-tagfilter+[...].mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-extension-gfm.mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-factory-title.mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-util-chunked.mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-util-combine-extensions+[...].mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-util-decode-string.mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-util-encode.mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-util-normalize-identifier+[...].mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-util-resolve-all.mjs +0 -0
- /package/dist/{web-server → server}/_libs/micromark-util-subtokenize.mjs +0 -0
- /package/dist/{web-server → server}/_libs/ocache.mjs +0 -0
- /package/dist/{web-server → server}/_libs/ohash.mjs +0 -0
- /package/dist/{web-server → server}/_libs/react-markdown.mjs +0 -0
- /package/dist/{web-server → server}/_libs/remark-gfm.mjs +0 -0
- /package/dist/{web-server → server}/_libs/remark-parse.mjs +0 -0
- /package/dist/{web-server → server}/_libs/remark-rehype.mjs +0 -0
- /package/dist/{web-server → server}/_libs/reselect.mjs +0 -0
- /package/dist/{web-server → server}/_libs/rou3.mjs +0 -0
- /package/dist/{web-server/_libs/format.mjs → server/_libs/seroval-plugins.mjs} +0 -0
- /package/dist/{web-server/_libs/highlight.js.mjs → server/_libs/seroval.mjs} +0 -0
- /package/dist/{web-server → server}/_libs/srvx.mjs +0 -0
- /package/dist/{web-server → server}/_libs/style-to-js.mjs +0 -0
- /package/dist/{web-server → server}/_libs/style-to-object.mjs +0 -0
- /package/dist/{web-server → server}/_libs/tanstack__react-store.mjs +0 -0
- /package/dist/{web-server → server}/_libs/tanstack__store.mjs +0 -0
- /package/dist/{web-server → server}/_libs/trim-lines.mjs +0 -0
- /package/dist/{web-server → server}/_libs/trough.mjs +0 -0
- /package/dist/{web-server → server}/_libs/ufo.mjs +0 -0
- /package/dist/{web-server → server}/_libs/unctx.mjs +0 -0
- /package/dist/{web-server → server}/_libs/ungap__structured-clone.mjs +0 -0
- /package/dist/{web-server → server}/_libs/unified.mjs +0 -0
- /package/dist/{web-server → server}/_libs/unist-util-is.mjs +0 -0
- /package/dist/{web-server → server}/_libs/unist-util-stringify-position.mjs +0 -0
- /package/dist/{web-server → server}/_libs/unist-util-visit-parents.mjs +0 -0
- /package/dist/{web-server → server}/_libs/unist-util-visit.mjs +0 -0
- /package/dist/{web-server → server}/_libs/unstorage.mjs +0 -0
- /package/dist/{web-server → server}/_libs/vfile-message.mjs +0 -0
- /package/dist/{web-server → server}/_libs/vfile.mjs +0 -0
- /package/dist/{web-server → server}/_libs/zwitch.mjs +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Hermium CLI
|
|
2
|
+
|
|
3
|
+
Self-hosted AI chat dashboard for Hermes Agent.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g hermium
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or with Bun:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun install -g hermium
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- [Bun](https://bun.sh) >= 1.2
|
|
20
|
+
|
|
21
|
+
## Commands
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
hermium start # Start the server (daemon)
|
|
25
|
+
hermium stop # Stop the server
|
|
26
|
+
hermium restart # Restart the server
|
|
27
|
+
hermium status # Show running status
|
|
28
|
+
hermium build # Build from source (requires repo)
|
|
29
|
+
hermium dev # Run in dev mode (requires repo)
|
|
30
|
+
hermium help # Show help
|
|
31
|
+
hermium version # Show version
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Options
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
hermium start --port 47474 # Custom port (default: 47474)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Development
|
|
41
|
+
|
|
42
|
+
To run from source:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
git clone https://github.com/abboskhonov/hermium.git
|
|
46
|
+
cd hermium
|
|
47
|
+
bun install
|
|
48
|
+
bun run dev
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
To build the CLI package for publishing:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
cd packages/cli
|
|
55
|
+
bun run build
|
|
56
|
+
```
|
package/bin/hermium.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { spawn, execSync } from 'child_process'
|
|
3
3
|
import { resolve, dirname, join } from 'path'
|
|
4
4
|
import { fileURLToPath } from 'url'
|
|
5
|
-
import { readFileSync, writeFileSync, unlinkSync, mkdirSync,
|
|
5
|
+
import { readFileSync, writeFileSync, unlinkSync, mkdirSync, existsSync, statSync, openSync } from 'fs'
|
|
6
6
|
import { homedir } from 'os'
|
|
7
7
|
import pc from 'picocolors'
|
|
8
8
|
|
|
@@ -10,15 +10,9 @@ const pkgDir = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
|
10
10
|
const pkg = JSON.parse(readFileSync(resolve(pkgDir, 'package.json'), 'utf-8'))
|
|
11
11
|
const CURRENT_VERSION = pkg.version
|
|
12
12
|
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const webServerDir = resolve(pkgDir, 'dist', 'web-server')
|
|
17
|
-
const WEB_UI_HOME = resolve(homedir(), '.hermium')
|
|
18
|
-
const API_PID_FILE = join(WEB_UI_HOME, 'api.pid')
|
|
19
|
-
const WEB_PID_FILE = join(WEB_UI_HOME, 'web.pid')
|
|
20
|
-
const API_LOG_FILE = join(WEB_UI_HOME, 'api.log')
|
|
21
|
-
const WEB_LOG_FILE = join(WEB_UI_HOME, 'web.log')
|
|
13
|
+
const HERMIUM_HOME = resolve(homedir(), '.hermium')
|
|
14
|
+
const PID_FILE = join(HERMIUM_HOME, 'hermium.pid')
|
|
15
|
+
const LOG_FILE = join(HERMIUM_HOME, 'hermium.log')
|
|
22
16
|
const DEFAULT_API_PORT = 47474
|
|
23
17
|
const DEFAULT_WEB_PORT = 42424
|
|
24
18
|
|
|
@@ -44,7 +38,7 @@ function getRuntimeCmd() {
|
|
|
44
38
|
// ─── Version check ─────────────────────────────────────────────────────────
|
|
45
39
|
|
|
46
40
|
async function checkLatestVersion() {
|
|
47
|
-
const cacheFile = join(
|
|
41
|
+
const cacheFile = join(HERMIUM_HOME, '.version-check')
|
|
48
42
|
const now = Date.now()
|
|
49
43
|
try {
|
|
50
44
|
const cache = JSON.parse(readFileSync(cacheFile, 'utf-8'))
|
|
@@ -74,16 +68,18 @@ async function checkLatestVersion() {
|
|
|
74
68
|
|
|
75
69
|
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
76
70
|
|
|
77
|
-
function readPid(
|
|
71
|
+
function readPid() {
|
|
78
72
|
try {
|
|
79
|
-
const
|
|
80
|
-
|
|
73
|
+
const raw = readFileSync(PID_FILE, 'utf-8').trim()
|
|
74
|
+
const [apiPid, webPid] = raw.split(',').map(s => parseInt(s.trim()))
|
|
75
|
+
return { apiPid: Number.isFinite(apiPid) ? apiPid : null, webPid: Number.isFinite(webPid) ? webPid : null }
|
|
81
76
|
} catch {
|
|
82
|
-
return null
|
|
77
|
+
return { apiPid: null, webPid: null }
|
|
83
78
|
}
|
|
84
79
|
}
|
|
85
80
|
|
|
86
81
|
function isRunning(pid) {
|
|
82
|
+
if (!pid) return false
|
|
87
83
|
try {
|
|
88
84
|
process.kill(pid, 0)
|
|
89
85
|
return true
|
|
@@ -92,130 +88,136 @@ function isRunning(pid) {
|
|
|
92
88
|
}
|
|
93
89
|
}
|
|
94
90
|
|
|
95
|
-
function
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
function getPids() {
|
|
92
|
+
const { apiPid, webPid } = readPid()
|
|
93
|
+
const apiRunning = apiPid && isRunning(apiPid)
|
|
94
|
+
const webRunning = webPid && isRunning(webPid)
|
|
95
|
+
if (!apiRunning && !webRunning) {
|
|
96
|
+
removePid()
|
|
97
|
+
return { apiPid: null, webPid: null }
|
|
98
|
+
}
|
|
99
|
+
return { apiPid: apiRunning ? apiPid : null, webPid: webRunning ? webPid : null }
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
function
|
|
101
|
-
|
|
102
|
+
function writePid(apiPid, webPid) {
|
|
103
|
+
mkdirSync(HERMIUM_HOME, { recursive: true })
|
|
104
|
+
writeFileSync(PID_FILE, `${apiPid},${webPid}`)
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
function
|
|
105
|
-
|
|
106
|
-
if (pid && isRunning(pid)) return pid
|
|
107
|
-
removePid(file)
|
|
108
|
-
return null
|
|
107
|
+
function removePid() {
|
|
108
|
+
try { unlinkSync(PID_FILE) } catch {}
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
function
|
|
112
|
-
|
|
111
|
+
function getApiPort() {
|
|
112
|
+
const idx = process.argv.indexOf('--port')
|
|
113
|
+
if (idx !== -1 && process.argv[idx + 1]) {
|
|
114
|
+
const p = parseInt(process.argv[idx + 1])
|
|
115
|
+
if (!isNaN(p)) return p
|
|
116
|
+
}
|
|
117
|
+
return DEFAULT_API_PORT
|
|
118
|
+
}
|
|
113
119
|
|
|
114
|
-
function
|
|
115
|
-
const idx = process.argv.indexOf(
|
|
120
|
+
function getWebPort() {
|
|
121
|
+
const idx = process.argv.indexOf('--web-port')
|
|
116
122
|
if (idx !== -1 && process.argv[idx + 1]) {
|
|
117
123
|
const p = parseInt(process.argv[idx + 1])
|
|
118
124
|
if (!isNaN(p)) return p
|
|
119
125
|
}
|
|
120
|
-
return
|
|
126
|
+
return DEFAULT_WEB_PORT
|
|
121
127
|
}
|
|
122
128
|
|
|
123
|
-
function
|
|
124
|
-
if (!pid) return null
|
|
129
|
+
function rotateLog() {
|
|
125
130
|
try {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
const out = execSync(`lsof -Pan -p ${pid} -iTCP -sTCP:LISTEN`, { encoding: 'utf-8' }).trim()
|
|
134
|
-
const lines = out.split('\n').slice(1)
|
|
135
|
-
for (const line of lines) {
|
|
136
|
-
const match = line.match(/:(\d+)\s+\(LISTEN\)$/)
|
|
137
|
-
if (match) return parseInt(match[1], 10)
|
|
131
|
+
const st = statSync(LOG_FILE)
|
|
132
|
+
if (st.size > 3 * 1024 * 1024) {
|
|
133
|
+
const content = readFileSync(LOG_FILE, 'utf-8')
|
|
134
|
+
const kept = content.split('\n').slice(-2000)
|
|
135
|
+
writeFileSync(LOG_FILE, kept.join('\n'))
|
|
136
|
+
console.log(pc.cyan(` ↻ Rotated ${LOG_FILE.replace(homedir(), '~')}`))
|
|
138
137
|
}
|
|
139
138
|
} catch {}
|
|
140
|
-
return null
|
|
141
139
|
}
|
|
142
140
|
|
|
143
|
-
function
|
|
141
|
+
function stopPid(pid) {
|
|
142
|
+
if (!pid) return false
|
|
144
143
|
try {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
writeFileSync(file, kept.join('\n'))
|
|
150
|
-
console.log(pc.cyan(` ↻ Rotated ${file.replace(homedir(), '~')}`))
|
|
144
|
+
process.kill(pid, 'SIGTERM')
|
|
145
|
+
const start = Date.now()
|
|
146
|
+
while (isRunning(pid) && Date.now() - start < 5000) {
|
|
147
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 100)
|
|
151
148
|
}
|
|
152
|
-
|
|
149
|
+
if (isRunning(pid)) process.kill(pid, 'SIGKILL')
|
|
150
|
+
return true
|
|
151
|
+
} catch {
|
|
152
|
+
return true
|
|
153
|
+
}
|
|
153
154
|
}
|
|
154
155
|
|
|
155
|
-
function spawnServer({ name, entry, logFile,
|
|
156
|
+
function spawnServer({ name, entry, logFile, env, runtime }) {
|
|
156
157
|
if (!existsSync(entry)) {
|
|
157
158
|
console.log(pc.red(` ✗ ${name} not found: ${entry}`))
|
|
158
159
|
console.log(` Run "hermium build" first (or check your installation)`)
|
|
159
160
|
process.exit(1)
|
|
160
161
|
}
|
|
161
162
|
|
|
162
|
-
rotateLog(
|
|
163
|
+
rotateLog()
|
|
163
164
|
|
|
164
165
|
const logFd = openSync(logFile, 'a')
|
|
165
166
|
const child = spawn(runtime, [entry], {
|
|
166
167
|
detached: true,
|
|
167
168
|
stdio: ['ignore', logFd, logFd],
|
|
168
169
|
env: { ...process.env, ...env, NODE_ENV: 'production' },
|
|
169
|
-
cwd:
|
|
170
|
+
cwd: dirname(entry),
|
|
170
171
|
})
|
|
171
172
|
|
|
172
173
|
child.on('error', (err) => {
|
|
173
174
|
console.error(pc.red(` ✗ Failed to start ${name}: ${err.message}`))
|
|
174
|
-
removePid(
|
|
175
|
+
removePid()
|
|
175
176
|
process.exit(1)
|
|
176
177
|
})
|
|
177
178
|
|
|
178
179
|
child.unref()
|
|
179
|
-
writePid(pidFile, child.pid)
|
|
180
180
|
return child.pid
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
183
|
+
// ─── Path resolution ───────────────────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
function findApiEntry() {
|
|
186
|
+
const bundled = resolve(pkgDir, 'dist', 'api.mjs')
|
|
187
|
+
if (existsSync(bundled)) return bundled
|
|
188
|
+
|
|
189
|
+
const monorepo = resolve(pkgDir, '..', '..', 'packages', 'api', 'dist', 'index.js')
|
|
190
|
+
if (existsSync(monorepo)) return monorepo
|
|
191
|
+
|
|
192
|
+
return null
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function findWebServer() {
|
|
196
|
+
const bundled = resolve(pkgDir, 'dist', 'server', 'index.mjs')
|
|
197
|
+
if (existsSync(bundled)) return bundled
|
|
198
|
+
|
|
199
|
+
const monorepo = resolve(pkgDir, '..', '..', 'packages', 'web', '.output', 'server', 'index.mjs')
|
|
200
|
+
if (existsSync(monorepo)) return monorepo
|
|
201
|
+
|
|
202
|
+
return null
|
|
196
203
|
}
|
|
197
204
|
|
|
198
205
|
// ─── Commands ──────────────────────────────────────────────────────────────
|
|
199
206
|
|
|
200
207
|
function cmdStatus() {
|
|
201
|
-
const apiPid =
|
|
202
|
-
const webPid = getWebPid()
|
|
203
|
-
const apiPort = apiPid ? getRunningPort(apiPid) : null
|
|
204
|
-
const webPort = webPid ? getRunningPort(webPid) : null
|
|
205
|
-
|
|
208
|
+
const { apiPid, webPid } = getPids()
|
|
206
209
|
if (apiPid || webPid) {
|
|
207
210
|
console.log(pc.green(` ✓ Hermium is running`))
|
|
208
|
-
if (apiPid) console.log(` API : PID ${apiPid}, port ${
|
|
209
|
-
if (webPid) console.log(` Web : PID ${webPid}, port ${
|
|
210
|
-
console.log(` Logs : ${
|
|
211
|
+
if (apiPid) console.log(` API : PID ${apiPid}, port ${getApiPort()}`)
|
|
212
|
+
if (webPid) console.log(` Web : PID ${webPid}, port ${getWebPort()}`)
|
|
213
|
+
console.log(` Logs : ${LOG_FILE.replace(homedir(), '~')}`)
|
|
211
214
|
} else {
|
|
212
215
|
console.log(pc.yellow(` ⊘ Hermium is not running`))
|
|
213
216
|
}
|
|
214
217
|
}
|
|
215
218
|
|
|
216
219
|
async function cmdStart() {
|
|
217
|
-
const existingApi =
|
|
218
|
-
const existingWeb = getWebPid()
|
|
220
|
+
const { apiPid: existingApi, webPid: existingWeb } = getPids()
|
|
219
221
|
if (existingApi || existingWeb) {
|
|
220
222
|
console.log(pc.yellow(` ✗ Hermium is already running`))
|
|
221
223
|
if (existingApi) console.log(` API PID: ${existingApi}`)
|
|
@@ -224,80 +226,91 @@ async function cmdStart() {
|
|
|
224
226
|
process.exit(1)
|
|
225
227
|
}
|
|
226
228
|
|
|
227
|
-
const apiPort =
|
|
228
|
-
const webPort =
|
|
229
|
+
const apiPort = getApiPort()
|
|
230
|
+
const webPort = getWebPort()
|
|
229
231
|
const runtime = getRuntimeCmd()
|
|
232
|
+
const apiEntry = findApiEntry()
|
|
233
|
+
const webServer = findWebServer()
|
|
230
234
|
|
|
231
|
-
|
|
235
|
+
if (!apiEntry) {
|
|
236
|
+
console.log(pc.red(` ✗ API server not found. Run "hermium build" first.`))
|
|
237
|
+
process.exit(1)
|
|
238
|
+
}
|
|
232
239
|
|
|
233
|
-
|
|
240
|
+
if (!webServer) {
|
|
241
|
+
console.log(pc.red(` ✗ Web server not found. Run "hermium build" first.`))
|
|
242
|
+
process.exit(1)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
mkdirSync(HERMIUM_HOME, { recursive: true })
|
|
246
|
+
|
|
247
|
+
console.log(pc.cyan(` ⏳ Starting Hermium...`))
|
|
234
248
|
|
|
235
|
-
// 1. Start API server
|
|
236
249
|
const apiPid = spawnServer({
|
|
237
250
|
name: 'API server',
|
|
238
251
|
entry: apiEntry,
|
|
239
|
-
logFile:
|
|
240
|
-
pidFile: API_PID_FILE,
|
|
241
|
-
port: apiPort,
|
|
252
|
+
logFile: LOG_FILE,
|
|
242
253
|
runtime,
|
|
243
254
|
env: {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
WEB_STATIC_DIR: resolve(pkgDir, 'dist', 'public'),
|
|
255
|
+
PORT: String(apiPort),
|
|
256
|
+
APP_VERSION: CURRENT_VERSION,
|
|
257
|
+
AUTH_DISABLED: '1',
|
|
248
258
|
},
|
|
249
259
|
})
|
|
250
260
|
|
|
251
|
-
// 2. Start web SSR server
|
|
252
261
|
const webPid = spawnServer({
|
|
253
262
|
name: 'Web server',
|
|
254
|
-
entry:
|
|
255
|
-
logFile:
|
|
256
|
-
pidFile: WEB_PID_FILE,
|
|
257
|
-
port: webPort,
|
|
263
|
+
entry: webServer,
|
|
264
|
+
logFile: LOG_FILE,
|
|
258
265
|
runtime,
|
|
259
|
-
|
|
260
|
-
|
|
266
|
+
env: {
|
|
267
|
+
PORT: String(webPort),
|
|
268
|
+
NITRO_PORT: String(webPort),
|
|
269
|
+
HERMIUM_API_URL: `http://127.0.0.1:${apiPort}`,
|
|
270
|
+
APP_VERSION: CURRENT_VERSION,
|
|
271
|
+
},
|
|
261
272
|
})
|
|
262
273
|
|
|
263
|
-
|
|
264
|
-
|
|
274
|
+
writePid(apiPid, webPid)
|
|
275
|
+
|
|
276
|
+
console.log(` API PID: ${apiPid} (port ${apiPort})`)
|
|
277
|
+
console.log(` Web PID: ${webPid} (port ${webPort})`)
|
|
265
278
|
|
|
266
|
-
// Poll
|
|
279
|
+
// Poll health
|
|
267
280
|
const maxWait = 30000
|
|
268
281
|
const interval = 500
|
|
269
282
|
let waited = 0
|
|
270
|
-
const
|
|
283
|
+
const apiUrl = `http://127.0.0.1:${apiPort}`
|
|
284
|
+
const webUrl = `http://127.0.0.1:${webPort}`
|
|
271
285
|
|
|
272
286
|
function poll() {
|
|
273
287
|
waited += interval
|
|
274
288
|
|
|
275
|
-
if (!isRunning(apiPid)) {
|
|
276
|
-
console.log(pc.red(` ✗
|
|
277
|
-
console.log(` Check log: ${
|
|
278
|
-
|
|
279
|
-
removePid(API_PID_FILE)
|
|
280
|
-
removePid(WEB_PID_FILE)
|
|
281
|
-
process.exit(1)
|
|
282
|
-
}
|
|
283
|
-
if (!isRunning(webPid)) {
|
|
284
|
-
console.log(pc.red(` ✗ Web server crashed`))
|
|
285
|
-
console.log(` Check log: ${WEB_LOG_FILE}`)
|
|
286
|
-
stopPid(apiPid, 'api')
|
|
287
|
-
removePid(API_PID_FILE)
|
|
288
|
-
removePid(WEB_PID_FILE)
|
|
289
|
+
if (!isRunning(apiPid) || !isRunning(webPid)) {
|
|
290
|
+
console.log(pc.red(` ✗ Server crashed`))
|
|
291
|
+
console.log(` Check log: ${LOG_FILE}`)
|
|
292
|
+
removePid()
|
|
289
293
|
process.exit(1)
|
|
290
294
|
}
|
|
291
295
|
|
|
292
|
-
fetch(`${
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
+
fetch(`${apiUrl}/api/hermes/sessions`).catch(() => null).then((res) => {
|
|
297
|
+
if (!res || !res.ok) {
|
|
298
|
+
if (waited < maxWait) {
|
|
299
|
+
setTimeout(poll, interval)
|
|
300
|
+
} else {
|
|
301
|
+
console.log(pc.green(` ✓ Hermium started`))
|
|
302
|
+
console.log(` API : ${apiUrl}`)
|
|
303
|
+
console.log(` Web : ${webUrl}`)
|
|
304
|
+
console.log(` Logs: ${LOG_FILE.replace(homedir(), '~')}`)
|
|
305
|
+
checkLatestVersion()
|
|
306
|
+
}
|
|
296
307
|
} else {
|
|
297
308
|
console.log(pc.green(` ✓ Hermium started`))
|
|
298
|
-
console.log(` ${
|
|
299
|
-
console.log(`
|
|
300
|
-
|
|
309
|
+
console.log(` API : ${apiUrl}`)
|
|
310
|
+
console.log(` Web : ${webUrl}`)
|
|
311
|
+
console.log(` Logs: ${LOG_FILE.replace(homedir(), '~')}`)
|
|
312
|
+
checkLatestVersion()
|
|
313
|
+
// Open browser
|
|
301
314
|
const openCmd =
|
|
302
315
|
process.platform === 'win32' ? `start ${webUrl}` :
|
|
303
316
|
process.platform === 'darwin' ? `open ${webUrl}` :
|
|
@@ -311,24 +324,21 @@ async function cmdStart() {
|
|
|
311
324
|
}
|
|
312
325
|
|
|
313
326
|
function cmdStop() {
|
|
314
|
-
const apiPid =
|
|
315
|
-
const webPid = getWebPid()
|
|
316
|
-
|
|
327
|
+
const { apiPid, webPid } = getPids()
|
|
317
328
|
if (!apiPid && !webPid) {
|
|
318
329
|
console.log(pc.yellow(` ⊘ Hermium is not running`))
|
|
319
330
|
return
|
|
320
331
|
}
|
|
321
332
|
|
|
322
333
|
if (webPid) {
|
|
323
|
-
stopPid(webPid
|
|
324
|
-
removePid(WEB_PID_FILE)
|
|
334
|
+
stopPid(webPid)
|
|
325
335
|
console.log(pc.green(` ✓ Web server stopped (PID: ${webPid})`))
|
|
326
336
|
}
|
|
327
337
|
if (apiPid) {
|
|
328
|
-
stopPid(apiPid
|
|
329
|
-
removePid(API_PID_FILE)
|
|
338
|
+
stopPid(apiPid)
|
|
330
339
|
console.log(pc.green(` ✓ API server stopped (PID: ${apiPid})`))
|
|
331
340
|
}
|
|
341
|
+
removePid()
|
|
332
342
|
}
|
|
333
343
|
|
|
334
344
|
function cmdRestart() {
|
|
@@ -337,6 +347,53 @@ function cmdRestart() {
|
|
|
337
347
|
cmdStart()
|
|
338
348
|
}
|
|
339
349
|
|
|
350
|
+
function cmdBuild() {
|
|
351
|
+
console.log(pc.cyan(` 🔨 Building Hermium...`))
|
|
352
|
+
const runtime = getRuntimeCmd()
|
|
353
|
+
|
|
354
|
+
const rootDir = resolve(pkgDir, '..', '..')
|
|
355
|
+
const isMonorepo = existsSync(resolve(rootDir, 'packages', 'api')) && existsSync(resolve(rootDir, 'packages', 'web'))
|
|
356
|
+
|
|
357
|
+
if (!isMonorepo) {
|
|
358
|
+
console.log(pc.yellow(` ⚠ Not in a monorepo. Build must be done from the Hermium source repository.`))
|
|
359
|
+
process.exit(1)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
try {
|
|
363
|
+
console.log(` → Building shared...`)
|
|
364
|
+
execSync(`${runtime} run build:shared`, { cwd: rootDir, stdio: 'inherit' })
|
|
365
|
+
console.log(` → Building API...`)
|
|
366
|
+
execSync(`${runtime} run build:api`, { cwd: rootDir, stdio: 'inherit' })
|
|
367
|
+
console.log(` → Building Web...`)
|
|
368
|
+
execSync(`${runtime} run build:web`, { cwd: rootDir, stdio: 'inherit' })
|
|
369
|
+
console.log(` → Building CLI...`)
|
|
370
|
+
execSync(`${runtime} run build:cli`, { cwd: rootDir, stdio: 'inherit' })
|
|
371
|
+
console.log(pc.green(` ✓ Build complete`))
|
|
372
|
+
} catch (err) {
|
|
373
|
+
console.log(pc.red(` ✗ Build failed`))
|
|
374
|
+
process.exit(1)
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function cmdDev() {
|
|
379
|
+
console.log(pc.cyan(` 🔥 Starting Hermium in dev mode...`))
|
|
380
|
+
const runtime = getRuntimeCmd()
|
|
381
|
+
|
|
382
|
+
const rootDir = resolve(pkgDir, '..', '..')
|
|
383
|
+
const isMonorepo = existsSync(resolve(rootDir, 'packages', 'api')) && existsSync(resolve(rootDir, 'packages', 'web'))
|
|
384
|
+
|
|
385
|
+
if (!isMonorepo) {
|
|
386
|
+
console.log(pc.yellow(` ⚠ Not in a monorepo. Dev mode must be run from the Hermium source repository.`))
|
|
387
|
+
process.exit(1)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
try {
|
|
391
|
+
execSync(`${runtime} run dev`, { cwd: rootDir, stdio: 'inherit' })
|
|
392
|
+
} catch {
|
|
393
|
+
process.exit(1)
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
340
397
|
function cmdHelp() {
|
|
341
398
|
console.log(`
|
|
342
399
|
${pc.bold('Hermium CLI')} — Self-hosted AI chat for Hermes Agent
|
|
@@ -349,11 +406,14 @@ ${pc.bold('Commands:')}
|
|
|
349
406
|
stop Stop Hermium servers
|
|
350
407
|
restart Restart Hermium servers
|
|
351
408
|
status Show running status
|
|
409
|
+
build Build from source (requires repo)
|
|
410
|
+
dev Run in dev mode (requires repo)
|
|
352
411
|
help Show this help message
|
|
412
|
+
version Show version
|
|
353
413
|
|
|
354
414
|
${pc.bold('Options:')}
|
|
355
|
-
--port <n> API port (default: 47474)
|
|
356
|
-
--web-port <n> Web port (default: 42424)
|
|
415
|
+
--port <n> API server port (default: 47474)
|
|
416
|
+
--web-port <n> Web server port (default: 42424)
|
|
357
417
|
|
|
358
418
|
${pc.bold('Examples:')}
|
|
359
419
|
hermium start
|
|
@@ -364,8 +424,7 @@ ${pc.bold('Examples:')}
|
|
|
364
424
|
}
|
|
365
425
|
|
|
366
426
|
function cmdVersion() {
|
|
367
|
-
|
|
368
|
-
console.log(pkg.version)
|
|
427
|
+
console.log(CURRENT_VERSION)
|
|
369
428
|
}
|
|
370
429
|
|
|
371
430
|
// ─── Entrypoint ─────────────────────────────────────────────────────────────
|
|
@@ -385,6 +444,12 @@ switch (command) {
|
|
|
385
444
|
case 'status':
|
|
386
445
|
cmdStatus()
|
|
387
446
|
break
|
|
447
|
+
case 'build':
|
|
448
|
+
cmdBuild()
|
|
449
|
+
break
|
|
450
|
+
case 'dev':
|
|
451
|
+
cmdDev()
|
|
452
|
+
break
|
|
388
453
|
case 'version':
|
|
389
454
|
case '--version':
|
|
390
455
|
case '-v':
|