hermium 0.1.10 → 0.2.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 +185 -164
- package/dist/api.mjs +3513 -0
- package/dist/public/assets/css/index-Dfs9RUU9.css +1 -0
- package/dist/public/assets/css/styles-B8p6jk5Z.css +1 -0
- package/dist/public/assets/js/ChatInputBlock-Bw7AL70H.js +1 -0
- package/dist/public/assets/js/MarkdownMessage-8d7Y6VL-.js +1 -0
- package/dist/public/assets/js/base-ui-BvQbAt_1.js +1 -0
- package/dist/public/assets/js/chat._sessionId-BG6lVraH.js +1 -0
- package/dist/public/assets/js/chat.index-D2zdMPTT.js +1 -0
- package/dist/public/assets/js/index-C0AK45FU.js +60 -0
- package/dist/public/assets/js/index-Cx5En4FK.js +1 -0
- package/dist/public/assets/js/memory-CeSRdTkW.js +3 -0
- package/dist/public/assets/js/router-8uDKazL-.js +1 -0
- package/dist/public/assets/js/settings-Bc3Y5zXO.js +1 -0
- package/dist/public/assets/js/skills-DZv7sA_5.js +1 -0
- package/dist/public/assets/js/theme-CPkdkpaj.js +1 -0
- package/dist/public/assets/js/usage-DXQsT9_b.js +1 -0
- package/dist/public/assets/woff2/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/public/assets/woff2/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/public/assets/woff2/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/public/assets/woff2/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/public/assets/woff2/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/public/favicon.ico +0 -0
- package/dist/public/logo.png +0 -0
- package/package.json +1 -1
- 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.png +0 -0
- package/dist/public/nous-logo.png +0 -0
- package/dist/server/index.mjs +0 -244
- package/dist/web-server/__23tanstack-start-plugin-adapters-Cwee5PKy.mjs +0 -6
- package/dist/web-server/_chunks/ssr-renderer.mjs +0 -22
- package/dist/web-server/_libs/babel__runtime.mjs +0 -237
- package/dist/web-server/_libs/bail.mjs +0 -8
- package/dist/web-server/_libs/base-ui__react.mjs +0 -9554
- package/dist/web-server/_libs/base-ui__utils.mjs +0 -1101
- package/dist/web-server/_libs/ccount.mjs +0 -16
- package/dist/web-server/_libs/character-entities-legacy.mjs +0 -111
- package/dist/web-server/_libs/character-entities.mjs +0 -2130
- package/dist/web-server/_libs/character-reference-invalid.mjs +0 -33
- package/dist/web-server/_libs/class-variance-authority.mjs +0 -44
- package/dist/web-server/_libs/clsx.mjs +0 -16
- 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/croner.mjs +0 -1
- package/dist/web-server/_libs/crossws.mjs +0 -1
- package/dist/web-server/_libs/decode-named-character-reference+[...].mjs +0 -8
- package/dist/web-server/_libs/devlop.mjs +0 -8
- package/dist/web-server/_libs/escape-string-regexp.mjs +0 -9
- package/dist/web-server/_libs/estree-util-is-identifier-name.mjs +0 -11
- package/dist/web-server/_libs/extend.mjs +0 -97
- package/dist/web-server/_libs/fault.mjs +0 -1
- package/dist/web-server/_libs/floating-ui__core.mjs +0 -663
- package/dist/web-server/_libs/floating-ui__dom.mjs +0 -624
- package/dist/web-server/_libs/floating-ui__react-dom.mjs +0 -279
- package/dist/web-server/_libs/floating-ui__utils.mjs +0 -322
- package/dist/web-server/_libs/format.mjs +0 -1
- package/dist/web-server/_libs/h3.mjs +0 -408
- package/dist/web-server/_libs/hast-util-parse-selector.mjs +0 -39
- package/dist/web-server/_libs/hast-util-to-jsx-runtime.mjs +0 -388
- package/dist/web-server/_libs/hast-util-whitespace.mjs +0 -10
- package/dist/web-server/_libs/hastscript.mjs +0 -200
- package/dist/web-server/_libs/highlight.js.mjs +0 -1
- package/dist/web-server/_libs/hookable.mjs +0 -1
- package/dist/web-server/_libs/html-url-attributes.mjs +0 -26
- package/dist/web-server/_libs/inline-style-parser.mjs +0 -142
- 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/is-plain-obj.mjs +0 -10
- package/dist/web-server/_libs/isbot.mjs +0 -21
- package/dist/web-server/_libs/longest-streak.mjs +0 -25
- package/dist/web-server/_libs/lowlight.mjs +0 -1
- package/dist/web-server/_libs/markdown-table.mjs +0 -142
- package/dist/web-server/_libs/mdast-util-find-and-replace.mjs +0 -109
- package/dist/web-server/_libs/mdast-util-from-markdown.mjs +0 -717
- package/dist/web-server/_libs/mdast-util-gfm-autolink-literal+[...].mjs +0 -156
- package/dist/web-server/_libs/mdast-util-gfm-footnote.mjs +0 -117
- package/dist/web-server/_libs/mdast-util-gfm-strikethrough.mjs +0 -54
- package/dist/web-server/_libs/mdast-util-gfm-table.mjs +0 -157
- package/dist/web-server/_libs/mdast-util-gfm-task-list-item.mjs +0 -77
- package/dist/web-server/_libs/mdast-util-gfm.mjs +0 -29
- package/dist/web-server/_libs/mdast-util-phrasing.mjs +0 -30
- package/dist/web-server/_libs/mdast-util-to-hast.mjs +0 -710
- package/dist/web-server/_libs/mdast-util-to-markdown.mjs +0 -798
- package/dist/web-server/_libs/mdast-util-to-string.mjs +0 -38
- package/dist/web-server/_libs/micromark-core-commonmark.mjs +0 -2259
- package/dist/web-server/_libs/micromark-extension-gfm-autolink-literal+[...].mjs +0 -344
- package/dist/web-server/_libs/micromark-extension-gfm-footnote+[...].mjs +0 -279
- package/dist/web-server/_libs/micromark-extension-gfm-strikethrough+[...].mjs +0 -98
- package/dist/web-server/_libs/micromark-extension-gfm-table.mjs +0 -491
- package/dist/web-server/_libs/micromark-extension-gfm-tagfilter+[...].mjs +0 -1
- package/dist/web-server/_libs/micromark-extension-gfm-task-list-item+[...].mjs +0 -77
- package/dist/web-server/_libs/micromark-extension-gfm.mjs +0 -18
- package/dist/web-server/_libs/micromark-factory-destination.mjs +0 -94
- package/dist/web-server/_libs/micromark-factory-label.mjs +0 -63
- package/dist/web-server/_libs/micromark-factory-space.mjs +0 -24
- package/dist/web-server/_libs/micromark-factory-title.mjs +0 -65
- package/dist/web-server/_libs/micromark-factory-whitespace.mjs +0 -22
- package/dist/web-server/_libs/micromark-util-character.mjs +0 -44
- package/dist/web-server/_libs/micromark-util-chunked.mjs +0 -36
- package/dist/web-server/_libs/micromark-util-classify-character+[...].mjs +0 -12
- package/dist/web-server/_libs/micromark-util-combine-extensions+[...].mjs +0 -41
- package/dist/web-server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +0 -19
- package/dist/web-server/_libs/micromark-util-decode-string.mjs +0 -21
- package/dist/web-server/_libs/micromark-util-encode.mjs +0 -1
- package/dist/web-server/_libs/micromark-util-html-tag-name.mjs +0 -69
- package/dist/web-server/_libs/micromark-util-normalize-identifier+[...].mjs +0 -6
- package/dist/web-server/_libs/micromark-util-resolve-all.mjs +0 -15
- package/dist/web-server/_libs/micromark-util-sanitize-uri.mjs +0 -41
- package/dist/web-server/_libs/micromark-util-subtokenize.mjs +0 -346
- package/dist/web-server/_libs/micromark.mjs +0 -906
- package/dist/web-server/_libs/ocache.mjs +0 -1
- package/dist/web-server/_libs/ohash.mjs +0 -1
- package/dist/web-server/_libs/parse-entities.mjs +0 -245
- package/dist/web-server/_libs/property-information.mjs +0 -1210
- package/dist/web-server/_libs/react-dom.mjs +0 -10779
- package/dist/web-server/_libs/react-markdown.mjs +0 -147
- package/dist/web-server/_libs/react-syntax-highlighter.mjs +0 -941
- package/dist/web-server/_libs/react.mjs +0 -513
- package/dist/web-server/_libs/refractor.mjs +0 -2425
- package/dist/web-server/_libs/remark-gfm.mjs +0 -20
- package/dist/web-server/_libs/remark-parse.mjs +0 -19
- package/dist/web-server/_libs/remark-rehype.mjs +0 -21
- package/dist/web-server/_libs/reselect.mjs +0 -1
- package/dist/web-server/_libs/rou3.mjs +0 -8
- 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/srvx.mjs +0 -781
- package/dist/web-server/_libs/style-to-js.mjs +0 -72
- package/dist/web-server/_libs/style-to-object.mjs +0 -38
- 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/tanstack__react-router.mjs +0 -1120
- package/dist/web-server/_libs/tanstack__react-store.mjs +0 -2
- package/dist/web-server/_libs/tanstack__router-core.mjs +0 -4288
- package/dist/web-server/_libs/tanstack__store.mjs +0 -1
- package/dist/web-server/_libs/trim-lines.mjs +0 -41
- package/dist/web-server/_libs/trough.mjs +0 -85
- package/dist/web-server/_libs/ufo.mjs +0 -54
- package/dist/web-server/_libs/unctx.mjs +0 -1
- package/dist/web-server/_libs/ungap__structured-clone.mjs +0 -224
- package/dist/web-server/_libs/unified.mjs +0 -661
- package/dist/web-server/_libs/unist-util-is.mjs +0 -100
- package/dist/web-server/_libs/unist-util-position.mjs +0 -27
- package/dist/web-server/_libs/unist-util-stringify-position.mjs +0 -27
- package/dist/web-server/_libs/unist-util-visit-parents.mjs +0 -83
- package/dist/web-server/_libs/unist-util-visit.mjs +0 -24
- package/dist/web-server/_libs/unstorage.mjs +0 -1
- package/dist/web-server/_libs/use-sync-external-store.mjs +0 -139
- package/dist/web-server/_libs/vfile-message.mjs +0 -138
- package/dist/web-server/_libs/vfile.mjs +0 -467
- package/dist/web-server/_libs/zod.mjs +0 -3915
- package/dist/web-server/_libs/zustand.mjs +0 -343
- package/dist/web-server/_libs/zwitch.mjs +0 -1
- 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-CoDfv1vI.mjs +0 -66
- 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/router-CS6Zq3md.mjs +0 -2134
- 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/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,17 +10,10 @@ 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
|
|
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')
|
|
22
|
-
const DEFAULT_API_PORT = 47474
|
|
23
|
-
const DEFAULT_WEB_PORT = 42424
|
|
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')
|
|
16
|
+
const DEFAULT_PORT = 47474
|
|
24
17
|
|
|
25
18
|
// ─── Runtime detection ─────────────────────────────────────────────────────
|
|
26
19
|
|
|
@@ -44,7 +37,7 @@ function getRuntimeCmd() {
|
|
|
44
37
|
// ─── Version check ─────────────────────────────────────────────────────────
|
|
45
38
|
|
|
46
39
|
async function checkLatestVersion() {
|
|
47
|
-
const cacheFile = join(
|
|
40
|
+
const cacheFile = join(HERMIUM_HOME, '.version-check')
|
|
48
41
|
const now = Date.now()
|
|
49
42
|
try {
|
|
50
43
|
const cache = JSON.parse(readFileSync(cacheFile, 'utf-8'))
|
|
@@ -74,9 +67,9 @@ async function checkLatestVersion() {
|
|
|
74
67
|
|
|
75
68
|
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
76
69
|
|
|
77
|
-
function readPid(
|
|
70
|
+
function readPid() {
|
|
78
71
|
try {
|
|
79
|
-
const pid = parseInt(readFileSync(
|
|
72
|
+
const pid = parseInt(readFileSync(PID_FILE, 'utf-8').trim())
|
|
80
73
|
return Number.isFinite(pid) ? pid : null
|
|
81
74
|
} catch {
|
|
82
75
|
return null
|
|
@@ -92,216 +85,200 @@ function isRunning(pid) {
|
|
|
92
85
|
}
|
|
93
86
|
}
|
|
94
87
|
|
|
95
|
-
function
|
|
96
|
-
|
|
97
|
-
|
|
88
|
+
function getPid() {
|
|
89
|
+
const pid = readPid()
|
|
90
|
+
if (pid && isRunning(pid)) return pid
|
|
91
|
+
removePid()
|
|
92
|
+
return null
|
|
98
93
|
}
|
|
99
94
|
|
|
100
|
-
function
|
|
101
|
-
|
|
95
|
+
function writePid(pid) {
|
|
96
|
+
mkdirSync(HERMIUM_HOME, { recursive: true })
|
|
97
|
+
writeFileSync(PID_FILE, String(pid))
|
|
102
98
|
}
|
|
103
99
|
|
|
104
|
-
function
|
|
105
|
-
|
|
106
|
-
if (pid && isRunning(pid)) return pid
|
|
107
|
-
removePid(file)
|
|
108
|
-
return null
|
|
100
|
+
function removePid() {
|
|
101
|
+
try { unlinkSync(PID_FILE) } catch {}
|
|
109
102
|
}
|
|
110
103
|
|
|
111
|
-
function
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
function getPort(argName, defaultPort) {
|
|
115
|
-
const idx = process.argv.indexOf(argName)
|
|
104
|
+
function getPort() {
|
|
105
|
+
const idx = process.argv.indexOf('--port')
|
|
116
106
|
if (idx !== -1 && process.argv[idx + 1]) {
|
|
117
107
|
const p = parseInt(process.argv[idx + 1])
|
|
118
108
|
if (!isNaN(p)) return p
|
|
119
109
|
}
|
|
120
|
-
return
|
|
110
|
+
return DEFAULT_PORT
|
|
121
111
|
}
|
|
122
112
|
|
|
123
|
-
function
|
|
124
|
-
if (!pid) return null
|
|
113
|
+
function rotateLog() {
|
|
125
114
|
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)
|
|
115
|
+
const st = statSync(LOG_FILE)
|
|
116
|
+
if (st.size > 3 * 1024 * 1024) {
|
|
117
|
+
const content = readFileSync(LOG_FILE, 'utf-8')
|
|
118
|
+
const kept = content.split('\n').slice(-2000)
|
|
119
|
+
writeFileSync(LOG_FILE, kept.join('\n'))
|
|
120
|
+
console.log(pc.cyan(` ↻ Rotated ${LOG_FILE.replace(homedir(), '~')}`))
|
|
138
121
|
}
|
|
139
122
|
} catch {}
|
|
140
|
-
return null
|
|
141
123
|
}
|
|
142
124
|
|
|
143
|
-
function
|
|
125
|
+
function stopPid(pid) {
|
|
126
|
+
if (!pid) return false
|
|
144
127
|
try {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
writeFileSync(file, kept.join('\n'))
|
|
150
|
-
console.log(pc.cyan(` ↻ Rotated ${file.replace(homedir(), '~')}`))
|
|
128
|
+
process.kill(pid, 'SIGTERM')
|
|
129
|
+
const start = Date.now()
|
|
130
|
+
while (isRunning(pid) && Date.now() - start < 5000) {
|
|
131
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 100)
|
|
151
132
|
}
|
|
152
|
-
|
|
133
|
+
if (isRunning(pid)) process.kill(pid, 'SIGKILL')
|
|
134
|
+
return true
|
|
135
|
+
} catch {
|
|
136
|
+
return true
|
|
137
|
+
}
|
|
153
138
|
}
|
|
154
139
|
|
|
155
|
-
function spawnServer({ name, entry, logFile, pidFile, port, env, runtime
|
|
140
|
+
function spawnServer({ name, entry, logFile, pidFile, port, env, runtime }) {
|
|
156
141
|
if (!existsSync(entry)) {
|
|
157
142
|
console.log(pc.red(` ✗ ${name} not found: ${entry}`))
|
|
158
143
|
console.log(` Run "hermium build" first (or check your installation)`)
|
|
159
144
|
process.exit(1)
|
|
160
145
|
}
|
|
161
146
|
|
|
162
|
-
rotateLog(
|
|
147
|
+
rotateLog()
|
|
163
148
|
|
|
164
149
|
const logFd = openSync(logFile, 'a')
|
|
165
150
|
const child = spawn(runtime, [entry], {
|
|
166
151
|
detached: true,
|
|
167
152
|
stdio: ['ignore', logFd, logFd],
|
|
168
153
|
env: { ...process.env, ...env, NODE_ENV: 'production' },
|
|
169
|
-
cwd:
|
|
154
|
+
cwd: dirname(entry),
|
|
170
155
|
})
|
|
171
156
|
|
|
172
157
|
child.on('error', (err) => {
|
|
173
158
|
console.error(pc.red(` ✗ Failed to start ${name}: ${err.message}`))
|
|
174
|
-
removePid(
|
|
159
|
+
removePid()
|
|
175
160
|
process.exit(1)
|
|
176
161
|
})
|
|
177
162
|
|
|
178
163
|
child.unref()
|
|
179
|
-
writePid(
|
|
164
|
+
writePid(child.pid)
|
|
180
165
|
return child.pid
|
|
181
166
|
}
|
|
182
167
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
168
|
+
// ─── Path resolution ───────────────────────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
function findApiEntry() {
|
|
171
|
+
// Production: bundled in cli/dist/api.mjs
|
|
172
|
+
const bundled = resolve(pkgDir, 'dist', 'api.mjs')
|
|
173
|
+
if (existsSync(bundled)) return bundled
|
|
174
|
+
|
|
175
|
+
// Dev: from monorepo packages/api
|
|
176
|
+
const monorepo = resolve(pkgDir, '..', '..', 'packages', 'api', 'dist', 'index.js')
|
|
177
|
+
if (existsSync(monorepo)) return monorepo
|
|
178
|
+
|
|
179
|
+
return null
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function findWebDist() {
|
|
183
|
+
// Production: bundled in cli/dist/public/
|
|
184
|
+
const bundled = resolve(pkgDir, 'dist', 'public')
|
|
185
|
+
if (existsSync(bundled)) return bundled
|
|
186
|
+
|
|
187
|
+
// Dev: from monorepo packages/web/dist
|
|
188
|
+
const monorepo = resolve(pkgDir, '..', '..', 'packages', 'web', 'dist')
|
|
189
|
+
if (existsSync(monorepo)) return monorepo
|
|
190
|
+
|
|
191
|
+
return null
|
|
196
192
|
}
|
|
197
193
|
|
|
198
194
|
// ─── Commands ──────────────────────────────────────────────────────────────
|
|
199
195
|
|
|
200
196
|
function cmdStatus() {
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (apiPid || webPid) {
|
|
207
|
-
console.log(pc.green(` ✓ Hermium is running`))
|
|
208
|
-
if (apiPid) console.log(` API : PID ${apiPid}, port ${apiPort || 'unknown'}`)
|
|
209
|
-
if (webPid) console.log(` Web : PID ${webPid}, port ${webPort || 'unknown'}`)
|
|
210
|
-
console.log(` Logs : ${WEB_UI_HOME}`)
|
|
197
|
+
const pid = getPid()
|
|
198
|
+
if (pid) {
|
|
199
|
+
console.log(pc.green(` ✓ Hermium is running (PID: ${pid})`))
|
|
200
|
+
console.log(` URL : http://localhost:${getPort()}`)
|
|
201
|
+
console.log(` Log : ${LOG_FILE.replace(homedir(), '~')}`)
|
|
211
202
|
} else {
|
|
212
203
|
console.log(pc.yellow(` ⊘ Hermium is not running`))
|
|
213
204
|
}
|
|
214
205
|
}
|
|
215
206
|
|
|
216
207
|
async function cmdStart() {
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
console.log(pc.yellow(` ✗ Hermium is already running`))
|
|
221
|
-
if (existingApi) console.log(` API PID: ${existingApi}`)
|
|
222
|
-
if (existingWeb) console.log(` Web PID: ${existingWeb}`)
|
|
208
|
+
const existing = getPid()
|
|
209
|
+
if (existing) {
|
|
210
|
+
console.log(pc.yellow(` ✗ Hermium is already running (PID: ${existing})`))
|
|
223
211
|
console.log(` Use "hermium stop" first`)
|
|
224
212
|
process.exit(1)
|
|
225
213
|
}
|
|
226
214
|
|
|
227
|
-
const
|
|
228
|
-
const webPort = getPort('--web-port', DEFAULT_WEB_PORT)
|
|
215
|
+
const port = getPort()
|
|
229
216
|
const runtime = getRuntimeCmd()
|
|
217
|
+
const apiEntry = findApiEntry()
|
|
218
|
+
const webDist = findWebDist()
|
|
219
|
+
|
|
220
|
+
if (!apiEntry) {
|
|
221
|
+
console.log(pc.red(` ✗ API server not found. Run "hermium build" first.`))
|
|
222
|
+
process.exit(1)
|
|
223
|
+
}
|
|
230
224
|
|
|
231
|
-
mkdirSync(
|
|
225
|
+
mkdirSync(HERMIUM_HOME, { recursive: true })
|
|
232
226
|
|
|
233
|
-
console.log(pc.cyan(` ⏳ Starting Hermium
|
|
227
|
+
console.log(pc.cyan(` ⏳ Starting Hermium on port ${port}...`))
|
|
234
228
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
name: 'API server',
|
|
229
|
+
const pid = spawnServer({
|
|
230
|
+
name: 'Hermium server',
|
|
238
231
|
entry: apiEntry,
|
|
239
|
-
logFile:
|
|
240
|
-
pidFile:
|
|
241
|
-
port
|
|
232
|
+
logFile: LOG_FILE,
|
|
233
|
+
pidFile: PID_FILE,
|
|
234
|
+
port,
|
|
242
235
|
runtime,
|
|
243
236
|
env: {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
237
|
+
PORT: String(port),
|
|
238
|
+
APP_VERSION: CURRENT_VERSION,
|
|
239
|
+
WEB_STATIC_DIR: webDist || '',
|
|
240
|
+
AUTH_DISABLED: '1',
|
|
248
241
|
},
|
|
249
242
|
})
|
|
250
243
|
|
|
251
|
-
|
|
252
|
-
const webPid = spawnServer({
|
|
253
|
-
name: 'Web server',
|
|
254
|
-
entry: webEntry,
|
|
255
|
-
logFile: WEB_LOG_FILE,
|
|
256
|
-
pidFile: WEB_PID_FILE,
|
|
257
|
-
port: webPort,
|
|
258
|
-
runtime,
|
|
259
|
-
cwd: webServerDir,
|
|
260
|
-
env: { PORT: String(webPort) },
|
|
261
|
-
})
|
|
244
|
+
console.log(` PID: ${pid}`)
|
|
262
245
|
|
|
263
|
-
|
|
264
|
-
console.log(` Web PID: ${webPid}`)
|
|
265
|
-
|
|
266
|
-
// Poll web server health
|
|
246
|
+
// Poll health
|
|
267
247
|
const maxWait = 30000
|
|
268
248
|
const interval = 500
|
|
269
249
|
let waited = 0
|
|
270
|
-
const
|
|
250
|
+
const url = `http://localhost:${port}`
|
|
271
251
|
|
|
272
252
|
function poll() {
|
|
273
253
|
waited += interval
|
|
274
254
|
|
|
275
|
-
if (!isRunning(
|
|
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)
|
|
255
|
+
if (!isRunning(pid)) {
|
|
256
|
+
console.log(pc.red(` ✗ Server crashed`))
|
|
257
|
+
console.log(` Check log: ${LOG_FILE}`)
|
|
258
|
+
removePid()
|
|
289
259
|
process.exit(1)
|
|
290
260
|
}
|
|
291
261
|
|
|
292
|
-
fetch(`${
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
262
|
+
fetch(`${url}/api/health`).catch(() => null).then((res) => {
|
|
263
|
+
if (!res || !res.ok) {
|
|
264
|
+
if (waited < maxWait) {
|
|
265
|
+
setTimeout(poll, interval)
|
|
266
|
+
} else {
|
|
267
|
+
console.log(pc.green(` ✓ Hermium started`))
|
|
268
|
+
console.log(` ${url}`)
|
|
269
|
+
console.log(` Logs: ${LOG_FILE.replace(homedir(), '~')}`)
|
|
270
|
+
checkLatestVersion()
|
|
271
|
+
}
|
|
296
272
|
} else {
|
|
297
273
|
console.log(pc.green(` ✓ Hermium started`))
|
|
298
|
-
console.log(` ${
|
|
299
|
-
console.log(` Logs: ${
|
|
300
|
-
checkLatestVersion()
|
|
274
|
+
console.log(` ${url}`)
|
|
275
|
+
console.log(` Logs: ${LOG_FILE.replace(homedir(), '~')}`)
|
|
276
|
+
checkLatestVersion()
|
|
277
|
+
// Open browser
|
|
301
278
|
const openCmd =
|
|
302
|
-
process.platform === 'win32' ? `start ${
|
|
303
|
-
process.platform === 'darwin' ? `open ${
|
|
304
|
-
`xdg-open ${
|
|
279
|
+
process.platform === 'win32' ? `start ${url}` :
|
|
280
|
+
process.platform === 'darwin' ? `open ${url}` :
|
|
281
|
+
`xdg-open ${url}`
|
|
305
282
|
try { execSync(openCmd, { stdio: 'ignore' }) } catch {}
|
|
306
283
|
}
|
|
307
284
|
})
|
|
@@ -311,24 +288,15 @@ async function cmdStart() {
|
|
|
311
288
|
}
|
|
312
289
|
|
|
313
290
|
function cmdStop() {
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if (!apiPid && !webPid) {
|
|
291
|
+
const pid = getPid()
|
|
292
|
+
if (!pid) {
|
|
318
293
|
console.log(pc.yellow(` ⊘ Hermium is not running`))
|
|
319
294
|
return
|
|
320
295
|
}
|
|
321
296
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
console.log(pc.green(` ✓ Web server stopped (PID: ${webPid})`))
|
|
326
|
-
}
|
|
327
|
-
if (apiPid) {
|
|
328
|
-
stopPid(apiPid, 'api')
|
|
329
|
-
removePid(API_PID_FILE)
|
|
330
|
-
console.log(pc.green(` ✓ API server stopped (PID: ${apiPid})`))
|
|
331
|
-
}
|
|
297
|
+
stopPid(pid)
|
|
298
|
+
removePid()
|
|
299
|
+
console.log(pc.green(` ✓ Hermium stopped (PID: ${pid})`))
|
|
332
300
|
}
|
|
333
301
|
|
|
334
302
|
function cmdRestart() {
|
|
@@ -337,6 +305,52 @@ function cmdRestart() {
|
|
|
337
305
|
cmdStart()
|
|
338
306
|
}
|
|
339
307
|
|
|
308
|
+
function cmdBuild() {
|
|
309
|
+
console.log(pc.cyan(` 🔨 Building Hermium...`))
|
|
310
|
+
const runtime = getRuntimeCmd()
|
|
311
|
+
|
|
312
|
+
// Detect if we're in a monorepo
|
|
313
|
+
const rootDir = resolve(pkgDir, '..', '..')
|
|
314
|
+
const isMonorepo = existsSync(resolve(rootDir, 'packages', 'api')) && existsSync(resolve(rootDir, 'packages', 'web'))
|
|
315
|
+
|
|
316
|
+
if (!isMonorepo) {
|
|
317
|
+
console.log(pc.yellow(` ⚠ Not in a monorepo. Build must be done from the Hermium source repository.`))
|
|
318
|
+
process.exit(1)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
console.log(` → Building shared...`)
|
|
323
|
+
execSync(`${runtime} run build:shared`, { cwd: rootDir, stdio: 'inherit' })
|
|
324
|
+
console.log(` → Building API...`)
|
|
325
|
+
execSync(`${runtime} run build:api`, { cwd: rootDir, stdio: 'inherit' })
|
|
326
|
+
console.log(` → Building Web...`)
|
|
327
|
+
execSync(`${runtime} run build:web`, { cwd: rootDir, stdio: 'inherit' })
|
|
328
|
+
console.log(pc.green(` ✓ Build complete`))
|
|
329
|
+
} catch (err) {
|
|
330
|
+
console.log(pc.red(` ✗ Build failed`))
|
|
331
|
+
process.exit(1)
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function cmdDev() {
|
|
336
|
+
console.log(pc.cyan(` 🔥 Starting Hermium in dev mode...`))
|
|
337
|
+
const runtime = getRuntimeCmd()
|
|
338
|
+
|
|
339
|
+
const rootDir = resolve(pkgDir, '..', '..')
|
|
340
|
+
const isMonorepo = existsSync(resolve(rootDir, 'packages', 'api')) && existsSync(resolve(rootDir, 'packages', 'web'))
|
|
341
|
+
|
|
342
|
+
if (!isMonorepo) {
|
|
343
|
+
console.log(pc.yellow(` ⚠ Not in a monorepo. Dev mode must be run from the Hermium source repository.`))
|
|
344
|
+
process.exit(1)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
execSync(`${runtime} run dev`, { cwd: rootDir, stdio: 'inherit' })
|
|
349
|
+
} catch {
|
|
350
|
+
process.exit(1)
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
340
354
|
function cmdHelp() {
|
|
341
355
|
console.log(`
|
|
342
356
|
${pc.bold('Hermium CLI')} — Self-hosted AI chat for Hermes Agent
|
|
@@ -345,27 +359,28 @@ ${pc.bold('Usage:')}
|
|
|
345
359
|
hermium <command> [options]
|
|
346
360
|
|
|
347
361
|
${pc.bold('Commands:')}
|
|
348
|
-
start Start Hermium
|
|
349
|
-
stop Stop Hermium
|
|
350
|
-
restart Restart Hermium
|
|
362
|
+
start Start Hermium server (daemon)
|
|
363
|
+
stop Stop Hermium server
|
|
364
|
+
restart Restart Hermium server
|
|
351
365
|
status Show running status
|
|
366
|
+
build Build from source (requires repo)
|
|
367
|
+
dev Run in dev mode (requires repo)
|
|
352
368
|
help Show this help message
|
|
369
|
+
version Show version
|
|
353
370
|
|
|
354
371
|
${pc.bold('Options:')}
|
|
355
|
-
--port <n>
|
|
356
|
-
--web-port <n> Web port (default: 42424)
|
|
372
|
+
--port <n> Server port (default: 47474)
|
|
357
373
|
|
|
358
374
|
${pc.bold('Examples:')}
|
|
359
375
|
hermium start
|
|
360
|
-
hermium start --port 47474
|
|
376
|
+
hermium start --port 47474
|
|
361
377
|
hermium stop
|
|
362
378
|
hermium status
|
|
363
379
|
`)
|
|
364
380
|
}
|
|
365
381
|
|
|
366
382
|
function cmdVersion() {
|
|
367
|
-
|
|
368
|
-
console.log(pkg.version)
|
|
383
|
+
console.log(CURRENT_VERSION)
|
|
369
384
|
}
|
|
370
385
|
|
|
371
386
|
// ─── Entrypoint ─────────────────────────────────────────────────────────────
|
|
@@ -385,6 +400,12 @@ switch (command) {
|
|
|
385
400
|
case 'status':
|
|
386
401
|
cmdStatus()
|
|
387
402
|
break
|
|
403
|
+
case 'build':
|
|
404
|
+
cmdBuild()
|
|
405
|
+
break
|
|
406
|
+
case 'dev':
|
|
407
|
+
cmdDev()
|
|
408
|
+
break
|
|
388
409
|
case 'version':
|
|
389
410
|
case '--version':
|
|
390
411
|
case '-v':
|