hermium 0.1.2 → 0.1.4
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/bin/hermium.mjs +184 -145
- package/dist/server/index.mjs +65 -65
- package/dist/web-server/__23tanstack-start-plugin-adapters-Cwee5PKy.mjs +6 -0
- package/dist/web-server/_chunks/ssr-renderer.mjs +22 -0
- package/dist/web-server/_libs/babel__runtime.mjs +237 -0
- package/dist/web-server/_libs/bail.mjs +8 -0
- package/dist/web-server/_libs/base-ui__react.mjs +9554 -0
- package/dist/web-server/_libs/base-ui__utils.mjs +1101 -0
- package/dist/web-server/_libs/ccount.mjs +16 -0
- package/dist/web-server/_libs/character-entities-legacy.mjs +111 -0
- package/dist/web-server/_libs/character-entities.mjs +2130 -0
- package/dist/web-server/_libs/character-reference-invalid.mjs +33 -0
- package/dist/web-server/_libs/class-variance-authority.mjs +44 -0
- package/dist/web-server/_libs/clsx.mjs +16 -0
- package/dist/web-server/_libs/comma-separated-tokens.mjs +31 -0
- package/dist/web-server/_libs/cookie-es.mjs +44 -0
- package/dist/web-server/_libs/croner.mjs +1 -0
- package/dist/web-server/_libs/crossws.mjs +1 -0
- package/dist/web-server/_libs/decode-named-character-reference+[...].mjs +8 -0
- package/dist/web-server/_libs/devlop.mjs +8 -0
- package/dist/web-server/_libs/escape-string-regexp.mjs +9 -0
- package/dist/web-server/_libs/estree-util-is-identifier-name.mjs +11 -0
- package/dist/web-server/_libs/extend.mjs +97 -0
- package/dist/web-server/_libs/fault.mjs +1 -0
- package/dist/web-server/_libs/floating-ui__core.mjs +663 -0
- package/dist/web-server/_libs/floating-ui__dom.mjs +624 -0
- package/dist/web-server/_libs/floating-ui__react-dom.mjs +279 -0
- package/dist/web-server/_libs/floating-ui__utils.mjs +322 -0
- package/dist/web-server/_libs/format.mjs +1 -0
- package/dist/web-server/_libs/h3.mjs +408 -0
- package/dist/web-server/_libs/hast-util-parse-selector.mjs +39 -0
- package/dist/web-server/_libs/hast-util-to-jsx-runtime.mjs +388 -0
- package/dist/web-server/_libs/hast-util-whitespace.mjs +10 -0
- package/dist/web-server/_libs/hastscript.mjs +200 -0
- package/dist/web-server/_libs/highlight.js.mjs +1 -0
- package/dist/web-server/_libs/hookable.mjs +1 -0
- package/dist/web-server/_libs/html-url-attributes.mjs +26 -0
- package/dist/web-server/_libs/inline-style-parser.mjs +142 -0
- package/dist/web-server/_libs/is-alphabetical.mjs +7 -0
- package/dist/web-server/_libs/is-alphanumerical.mjs +8 -0
- package/dist/web-server/_libs/is-decimal.mjs +7 -0
- package/dist/web-server/_libs/is-hexadecimal.mjs +7 -0
- package/dist/web-server/_libs/is-plain-obj.mjs +10 -0
- package/dist/web-server/_libs/isbot.mjs +21 -0
- package/dist/web-server/_libs/longest-streak.mjs +25 -0
- package/dist/web-server/_libs/lowlight.mjs +1 -0
- package/dist/web-server/_libs/markdown-table.mjs +142 -0
- package/dist/web-server/_libs/mdast-util-find-and-replace.mjs +109 -0
- package/dist/web-server/_libs/mdast-util-from-markdown.mjs +717 -0
- package/dist/web-server/_libs/mdast-util-gfm-autolink-literal+[...].mjs +156 -0
- package/dist/web-server/_libs/mdast-util-gfm-footnote.mjs +117 -0
- package/dist/web-server/_libs/mdast-util-gfm-strikethrough.mjs +54 -0
- package/dist/web-server/_libs/mdast-util-gfm-table.mjs +157 -0
- package/dist/web-server/_libs/mdast-util-gfm-task-list-item.mjs +77 -0
- package/dist/web-server/_libs/mdast-util-gfm.mjs +29 -0
- package/dist/web-server/_libs/mdast-util-phrasing.mjs +30 -0
- package/dist/web-server/_libs/mdast-util-to-hast.mjs +710 -0
- package/dist/web-server/_libs/mdast-util-to-markdown.mjs +798 -0
- package/dist/web-server/_libs/mdast-util-to-string.mjs +38 -0
- package/dist/web-server/_libs/micromark-core-commonmark.mjs +2259 -0
- package/dist/web-server/_libs/micromark-extension-gfm-autolink-literal+[...].mjs +344 -0
- package/dist/web-server/_libs/micromark-extension-gfm-footnote+[...].mjs +279 -0
- package/dist/web-server/_libs/micromark-extension-gfm-strikethrough+[...].mjs +98 -0
- package/dist/web-server/_libs/micromark-extension-gfm-table.mjs +491 -0
- package/dist/web-server/_libs/micromark-extension-gfm-tagfilter+[...].mjs +1 -0
- package/dist/web-server/_libs/micromark-extension-gfm-task-list-item+[...].mjs +77 -0
- package/dist/web-server/_libs/micromark-extension-gfm.mjs +18 -0
- package/dist/web-server/_libs/micromark-factory-destination.mjs +94 -0
- package/dist/web-server/_libs/micromark-factory-label.mjs +63 -0
- package/dist/web-server/_libs/micromark-factory-space.mjs +24 -0
- package/dist/web-server/_libs/micromark-factory-title.mjs +65 -0
- package/dist/web-server/_libs/micromark-factory-whitespace.mjs +22 -0
- package/dist/web-server/_libs/micromark-util-character.mjs +44 -0
- package/dist/web-server/_libs/micromark-util-chunked.mjs +36 -0
- package/dist/web-server/_libs/micromark-util-classify-character+[...].mjs +12 -0
- package/dist/web-server/_libs/micromark-util-combine-extensions+[...].mjs +41 -0
- package/dist/web-server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +19 -0
- package/dist/web-server/_libs/micromark-util-decode-string.mjs +21 -0
- package/dist/web-server/_libs/micromark-util-encode.mjs +1 -0
- package/dist/web-server/_libs/micromark-util-html-tag-name.mjs +69 -0
- package/dist/web-server/_libs/micromark-util-normalize-identifier+[...].mjs +6 -0
- package/dist/web-server/_libs/micromark-util-resolve-all.mjs +15 -0
- package/dist/web-server/_libs/micromark-util-sanitize-uri.mjs +41 -0
- package/dist/web-server/_libs/micromark-util-subtokenize.mjs +346 -0
- package/dist/web-server/_libs/micromark.mjs +906 -0
- package/dist/web-server/_libs/ocache.mjs +1 -0
- package/dist/web-server/_libs/ohash.mjs +1 -0
- package/dist/web-server/_libs/parse-entities.mjs +245 -0
- package/dist/web-server/_libs/property-information.mjs +1210 -0
- package/dist/web-server/_libs/react-dom.mjs +10779 -0
- package/dist/web-server/_libs/react-markdown.mjs +147 -0
- package/dist/web-server/_libs/react-syntax-highlighter.mjs +941 -0
- package/dist/web-server/_libs/react.mjs +513 -0
- package/dist/web-server/_libs/refractor.mjs +2425 -0
- package/dist/web-server/_libs/remark-gfm.mjs +20 -0
- package/dist/web-server/_libs/remark-parse.mjs +19 -0
- package/dist/web-server/_libs/remark-rehype.mjs +21 -0
- package/dist/web-server/_libs/reselect.mjs +1 -0
- package/dist/web-server/_libs/rou3.mjs +8 -0
- package/dist/web-server/_libs/seroval-plugins.mjs +58 -0
- package/dist/web-server/_libs/seroval.mjs +1775 -0
- package/dist/web-server/_libs/space-separated-tokens.mjs +11 -0
- package/dist/web-server/_libs/srvx.mjs +781 -0
- package/dist/web-server/_libs/style-to-js.mjs +72 -0
- package/dist/web-server/_libs/style-to-object.mjs +38 -0
- package/dist/web-server/_libs/tabler__icons-react.mjs +224 -0
- package/dist/web-server/_libs/tanstack__history.mjs +204 -0
- package/dist/web-server/_libs/tanstack__query-core.mjs +2552 -0
- package/dist/web-server/_libs/tanstack__react-query.mjs +190 -0
- package/dist/web-server/_libs/tanstack__react-router.mjs +1120 -0
- package/dist/web-server/_libs/tanstack__react-store.mjs +2 -0
- package/dist/web-server/_libs/tanstack__router-core.mjs +4288 -0
- package/dist/web-server/_libs/tanstack__store.mjs +1 -0
- package/dist/web-server/_libs/trim-lines.mjs +41 -0
- package/dist/web-server/_libs/trough.mjs +85 -0
- package/dist/web-server/_libs/ufo.mjs +54 -0
- package/dist/web-server/_libs/unctx.mjs +1 -0
- package/dist/web-server/_libs/ungap__structured-clone.mjs +224 -0
- package/dist/web-server/_libs/unified.mjs +661 -0
- package/dist/web-server/_libs/unist-util-is.mjs +100 -0
- package/dist/web-server/_libs/unist-util-position.mjs +27 -0
- package/dist/web-server/_libs/unist-util-stringify-position.mjs +27 -0
- package/dist/web-server/_libs/unist-util-visit-parents.mjs +83 -0
- package/dist/web-server/_libs/unist-util-visit.mjs +24 -0
- package/dist/web-server/_libs/unstorage.mjs +1 -0
- package/dist/web-server/_libs/use-sync-external-store.mjs +139 -0
- package/dist/web-server/_libs/vfile-message.mjs +138 -0
- package/dist/web-server/_libs/vfile.mjs +467 -0
- package/dist/web-server/_libs/zod.mjs +3915 -0
- package/dist/web-server/_libs/zustand.mjs +343 -0
- package/dist/web-server/_libs/zwitch.mjs +1 -0
- package/dist/web-server/_ssr/index-BLK6uN4p.mjs +612 -0
- package/dist/web-server/_ssr/index-BkkxTg0a.mjs +1855 -0
- package/dist/web-server/_ssr/index-Bp9a_nTf.mjs +66 -0
- package/dist/web-server/_ssr/index-C8t8AZQG.mjs +513 -0
- package/dist/web-server/_ssr/index-DSIu0x-q.mjs +449 -0
- package/dist/web-server/_ssr/index-DqFrn6kj.mjs +278 -0
- package/dist/web-server/_ssr/index-EKE8NFy_.mjs +189 -0
- package/dist/web-server/_ssr/index-JzLhPyir.mjs +213 -0
- package/dist/web-server/_ssr/index-wTy_4MhH.mjs +369 -0
- package/dist/web-server/_ssr/index.mjs +1558 -0
- package/dist/web-server/_ssr/input-BQFduUUo.mjs +20 -0
- package/dist/web-server/_ssr/router-59cN5lqo.mjs +1998 -0
- package/dist/web-server/_ssr/start-HYkvq4Ni.mjs +4 -0
- package/dist/web-server/_ssr/switch-Bim4kX8N.mjs +33 -0
- package/dist/web-server/_ssr/syntax-highlighter-5vezNTce.mjs +62 -0
- package/dist/web-server/_ssr/textarea-CK0ROhfF.mjs +18 -0
- package/dist/web-server/_tanstack-start-manifest_v-DLw6M7p4.mjs +4 -0
- package/dist/web-server/index.mjs +611 -0
- package/package.json +1 -1
package/bin/hermium.mjs
CHANGED
|
@@ -7,44 +7,42 @@ import { homedir } from 'os'
|
|
|
7
7
|
import pc from 'picocolors'
|
|
8
8
|
|
|
9
9
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
10
|
+
const pkgDir = resolve(__dirname, '..')
|
|
11
|
+
const apiEntry = resolve(pkgDir, 'dist', 'server', 'index.mjs')
|
|
12
|
+
const webEntry = resolve(pkgDir, 'dist', 'web-server', 'index.mjs')
|
|
13
|
+
const webServerDir = resolve(pkgDir, 'dist', 'web-server')
|
|
14
|
+
const WEB_UI_HOME = resolve(homedir(), '.hermium')
|
|
15
|
+
const API_PID_FILE = join(WEB_UI_HOME, 'api.pid')
|
|
16
|
+
const WEB_PID_FILE = join(WEB_UI_HOME, 'web.pid')
|
|
17
|
+
const API_LOG_FILE = join(WEB_UI_HOME, 'api.log')
|
|
18
|
+
const WEB_LOG_FILE = join(WEB_UI_HOME, 'web.log')
|
|
19
|
+
const DEFAULT_API_PORT = 8788
|
|
20
|
+
const DEFAULT_WEB_PORT = 3000
|
|
10
21
|
|
|
11
22
|
// ─── Runtime detection ─────────────────────────────────────────────────────
|
|
12
23
|
|
|
13
|
-
function
|
|
14
|
-
// Check if bun is available on PATH
|
|
24
|
+
function getRuntimeCmd() {
|
|
15
25
|
try {
|
|
16
26
|
execSync('bun --version', { stdio: 'ignore' })
|
|
17
|
-
return
|
|
27
|
+
return 'bun'
|
|
18
28
|
} catch {
|
|
19
|
-
// fall back to current process
|
|
20
29
|
const exe = process.execPath
|
|
21
30
|
const isBun = exe.includes('bun') || (process.versions && process.versions.bun)
|
|
22
|
-
|
|
31
|
+
if (!isBun) {
|
|
32
|
+
console.log(pc.red(' ✗ Bun is required to run Hermium.'))
|
|
33
|
+
console.log(' Install: curl -fsSL https://bun.sh/install | bash')
|
|
34
|
+
console.log(' Or: npm install -g bun')
|
|
35
|
+
process.exit(1)
|
|
36
|
+
}
|
|
37
|
+
return exe
|
|
23
38
|
}
|
|
24
39
|
}
|
|
25
40
|
|
|
26
|
-
function getRuntimeCmd() {
|
|
27
|
-
const rt = detectRuntime()
|
|
28
|
-
if (!rt.found) {
|
|
29
|
-
console.log(pc.red(' ✗ Bun is required to run Hermium.'))
|
|
30
|
-
console.log(' Install: curl -fsSL https://bun.sh/install | bash')
|
|
31
|
-
console.log(' Or: npm install -g bun')
|
|
32
|
-
process.exit(1)
|
|
33
|
-
}
|
|
34
|
-
return rt.cmd
|
|
35
|
-
}
|
|
36
|
-
const pkgDir = resolve(__dirname, '..')
|
|
37
|
-
const serverEntry = resolve(pkgDir, 'dist', 'server', 'index.mjs')
|
|
38
|
-
const WEB_UI_HOME = resolve(homedir(), '.hermium')
|
|
39
|
-
const PID_FILE = join(WEB_UI_HOME, 'server.pid')
|
|
40
|
-
const LOG_FILE = join(WEB_UI_HOME, 'server.log')
|
|
41
|
-
const DEFAULT_PORT = 8788
|
|
42
|
-
|
|
43
41
|
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
44
42
|
|
|
45
|
-
function readPid() {
|
|
43
|
+
function readPid(file) {
|
|
46
44
|
try {
|
|
47
|
-
const pid = parseInt(readFileSync(
|
|
45
|
+
const pid = parseInt(readFileSync(file, 'utf-8').trim())
|
|
48
46
|
return Number.isFinite(pid) ? pid : null
|
|
49
47
|
} catch {
|
|
50
48
|
return null
|
|
@@ -60,37 +58,36 @@ function isRunning(pid) {
|
|
|
60
58
|
}
|
|
61
59
|
}
|
|
62
60
|
|
|
63
|
-
function writePid(pid) {
|
|
61
|
+
function writePid(file, pid) {
|
|
64
62
|
mkdirSync(WEB_UI_HOME, { recursive: true })
|
|
65
|
-
writeFileSync(
|
|
63
|
+
writeFileSync(file, String(pid))
|
|
66
64
|
}
|
|
67
65
|
|
|
68
|
-
function removePid() {
|
|
69
|
-
try { unlinkSync(
|
|
66
|
+
function removePid(file) {
|
|
67
|
+
try { unlinkSync(file) } catch {}
|
|
70
68
|
}
|
|
71
69
|
|
|
72
|
-
function getPid() {
|
|
73
|
-
const pid = readPid()
|
|
70
|
+
function getPid(file) {
|
|
71
|
+
const pid = readPid(file)
|
|
74
72
|
if (pid && isRunning(pid)) return pid
|
|
75
|
-
removePid()
|
|
73
|
+
removePid(file)
|
|
76
74
|
return null
|
|
77
75
|
}
|
|
78
76
|
|
|
79
|
-
function
|
|
80
|
-
|
|
77
|
+
function getApiPid() { return getPid(API_PID_FILE) }
|
|
78
|
+
function getWebPid() { return getPid(WEB_PID_FILE) }
|
|
79
|
+
|
|
80
|
+
function getPort(argName, defaultPort) {
|
|
81
|
+
const idx = process.argv.indexOf(argName)
|
|
81
82
|
if (idx !== -1 && process.argv[idx + 1]) {
|
|
82
83
|
const p = parseInt(process.argv[idx + 1])
|
|
83
84
|
if (!isNaN(p)) return p
|
|
84
85
|
}
|
|
85
|
-
|
|
86
|
-
return parseInt(process.env.HERMIUM_PORT)
|
|
87
|
-
}
|
|
88
|
-
return DEFAULT_PORT
|
|
86
|
+
return defaultPort
|
|
89
87
|
}
|
|
90
88
|
|
|
91
89
|
function getRunningPort(pid) {
|
|
92
90
|
if (!pid) return null
|
|
93
|
-
|
|
94
91
|
try {
|
|
95
92
|
if (process.platform === 'win32') {
|
|
96
93
|
const out = execSync(`netstat -aon -p tcp | findstr LISTENING | findstr " ${pid}$"`, { encoding: 'utf-8' }).trim()
|
|
@@ -99,7 +96,6 @@ function getRunningPort(pid) {
|
|
|
99
96
|
const port = address?.split(':').pop()
|
|
100
97
|
return port ? parseInt(port, 10) : null
|
|
101
98
|
}
|
|
102
|
-
|
|
103
99
|
const out = execSync(`lsof -Pan -p ${pid} -iTCP -sTCP:LISTEN`, { encoding: 'utf-8' }).trim()
|
|
104
100
|
const lines = out.split('\n').slice(1)
|
|
105
101
|
for (const line of lines) {
|
|
@@ -110,150 +106,192 @@ function getRunningPort(pid) {
|
|
|
110
106
|
return null
|
|
111
107
|
}
|
|
112
108
|
|
|
109
|
+
function rotateLog(file) {
|
|
110
|
+
try {
|
|
111
|
+
const st = statSync(file)
|
|
112
|
+
if (st.size > 3 * 1024 * 1024) {
|
|
113
|
+
const content = readFileSync(file, 'utf-8')
|
|
114
|
+
const kept = content.split('\n').slice(-2000)
|
|
115
|
+
writeFileSync(file, kept.join('\n'))
|
|
116
|
+
console.log(pc.cyan(` ↻ Rotated ${file.replace(homedir(), '~')}`))
|
|
117
|
+
}
|
|
118
|
+
} catch {}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function spawnServer({ name, entry, logFile, pidFile, port, env, runtime, cwd }) {
|
|
122
|
+
if (!existsSync(entry)) {
|
|
123
|
+
console.log(pc.red(` ✗ ${name} not found: ${entry}`))
|
|
124
|
+
console.log(` Run "hermium build" first (or check your installation)`)
|
|
125
|
+
process.exit(1)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
rotateLog(logFile)
|
|
129
|
+
|
|
130
|
+
const logFd = openSync(logFile, 'a')
|
|
131
|
+
const child = spawn(runtime, [entry], {
|
|
132
|
+
detached: true,
|
|
133
|
+
stdio: ['ignore', logFd, logFd],
|
|
134
|
+
env: { ...process.env, ...env, NODE_ENV: 'production' },
|
|
135
|
+
cwd: cwd || dirname(entry),
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
child.on('error', (err) => {
|
|
139
|
+
console.error(pc.red(` ✗ Failed to start ${name}: ${err.message}`))
|
|
140
|
+
removePid(pidFile)
|
|
141
|
+
process.exit(1)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
child.unref()
|
|
145
|
+
writePid(pidFile, child.pid)
|
|
146
|
+
return child.pid
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function stopPid(pid, name) {
|
|
150
|
+
if (!pid) return false
|
|
151
|
+
try {
|
|
152
|
+
process.kill(pid, 'SIGTERM')
|
|
153
|
+
const start = Date.now()
|
|
154
|
+
while (isRunning(pid) && Date.now() - start < 5000) {
|
|
155
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 100)
|
|
156
|
+
}
|
|
157
|
+
if (isRunning(pid)) process.kill(pid, 'SIGKILL')
|
|
158
|
+
return true
|
|
159
|
+
} catch {
|
|
160
|
+
return true
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
113
164
|
// ─── Commands ──────────────────────────────────────────────────────────────
|
|
114
165
|
|
|
115
166
|
function cmdStatus() {
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
167
|
+
const apiPid = getApiPid()
|
|
168
|
+
const webPid = getWebPid()
|
|
169
|
+
const apiPort = apiPid ? getRunningPort(apiPid) : null
|
|
170
|
+
const webPort = webPid ? getRunningPort(webPid) : null
|
|
171
|
+
|
|
172
|
+
if (apiPid || webPid) {
|
|
119
173
|
console.log(pc.green(` ✓ Hermium is running`))
|
|
120
|
-
console.log(`
|
|
121
|
-
console.log(`
|
|
122
|
-
console.log(`
|
|
174
|
+
if (apiPid) console.log(` API : PID ${apiPid}, port ${apiPort || 'unknown'}`)
|
|
175
|
+
if (webPid) console.log(` Web : PID ${webPid}, port ${webPort || 'unknown'}`)
|
|
176
|
+
console.log(` Logs : ${WEB_UI_HOME}`)
|
|
123
177
|
} else {
|
|
124
178
|
console.log(pc.yellow(` ⊘ Hermium is not running`))
|
|
125
179
|
}
|
|
126
180
|
}
|
|
127
181
|
|
|
128
|
-
function cmdStart() {
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
console.log(`
|
|
182
|
+
async function cmdStart() {
|
|
183
|
+
const existingApi = getApiPid()
|
|
184
|
+
const existingWeb = getWebPid()
|
|
185
|
+
if (existingApi || existingWeb) {
|
|
186
|
+
console.log(pc.yellow(` ✗ Hermium is already running`))
|
|
187
|
+
if (existingApi) console.log(` API PID: ${existingApi}`)
|
|
188
|
+
if (existingWeb) console.log(` Web PID: ${existingWeb}`)
|
|
189
|
+
console.log(` Use "hermium stop" first`)
|
|
133
190
|
process.exit(1)
|
|
134
191
|
}
|
|
135
192
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
process.exit(1)
|
|
140
|
-
}
|
|
193
|
+
const apiPort = getPort('--port', DEFAULT_API_PORT)
|
|
194
|
+
const webPort = getPort('--web-port', DEFAULT_WEB_PORT)
|
|
195
|
+
const runtime = getRuntimeCmd()
|
|
141
196
|
|
|
142
|
-
const port = getPort()
|
|
143
197
|
mkdirSync(WEB_UI_HOME, { recursive: true })
|
|
144
198
|
|
|
145
|
-
|
|
146
|
-
try {
|
|
147
|
-
const st = statSync(LOG_FILE)
|
|
148
|
-
if (st.size > 3 * 1024 * 1024) {
|
|
149
|
-
const content = readFileSync(LOG_FILE, 'utf-8')
|
|
150
|
-
const kept = content.split('\n').slice(-2000)
|
|
151
|
-
writeFileSync(LOG_FILE, kept.join('\n'))
|
|
152
|
-
console.log(pc.cyan(` ↻ Log rotated`))
|
|
153
|
-
}
|
|
154
|
-
} catch {}
|
|
199
|
+
console.log(pc.cyan(` ⏳ Starting Hermium (API:${apiPort}, Web:${webPort})...`))
|
|
155
200
|
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
201
|
+
// 1. Start API server
|
|
202
|
+
const apiPid = spawnServer({
|
|
203
|
+
name: 'API server',
|
|
204
|
+
entry: apiEntry,
|
|
205
|
+
logFile: API_LOG_FILE,
|
|
206
|
+
pidFile: API_PID_FILE,
|
|
207
|
+
port: apiPort,
|
|
208
|
+
runtime,
|
|
161
209
|
env: {
|
|
162
|
-
|
|
163
|
-
|
|
210
|
+
HERMIUM_PORT: String(apiPort),
|
|
211
|
+
HERMIUM_WEB_PORT: String(webPort),
|
|
164
212
|
WEB_STATIC_DIR: resolve(pkgDir, 'dist', 'web'),
|
|
165
|
-
HERMIUM_PORT: String(port),
|
|
166
213
|
},
|
|
167
214
|
})
|
|
168
215
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
216
|
+
// 2. Start web SSR server
|
|
217
|
+
const webPid = spawnServer({
|
|
218
|
+
name: 'Web server',
|
|
219
|
+
entry: webEntry,
|
|
220
|
+
logFile: WEB_LOG_FILE,
|
|
221
|
+
pidFile: WEB_PID_FILE,
|
|
222
|
+
port: webPort,
|
|
223
|
+
runtime,
|
|
224
|
+
cwd: webServerDir,
|
|
225
|
+
env: { PORT: String(webPort) },
|
|
173
226
|
})
|
|
174
227
|
|
|
175
|
-
|
|
176
|
-
|
|
228
|
+
console.log(` API PID: ${apiPid}`)
|
|
229
|
+
console.log(` Web PID: ${webPid}`)
|
|
177
230
|
|
|
178
|
-
// Poll health
|
|
179
|
-
const healthUrl = `http://127.0.0.1:${port}/api/health`
|
|
231
|
+
// Poll web server health
|
|
180
232
|
const maxWait = 30000
|
|
181
233
|
const interval = 500
|
|
182
234
|
let waited = 0
|
|
183
|
-
|
|
184
|
-
console.log(pc.cyan(` ⏳ Starting Hermium (PID: ${child.pid}, port: ${port})...`))
|
|
235
|
+
const webUrl = `http://localhost:${webPort}`
|
|
185
236
|
|
|
186
237
|
function poll() {
|
|
187
238
|
waited += interval
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
console.log(`
|
|
191
|
-
|
|
239
|
+
|
|
240
|
+
if (!isRunning(apiPid)) {
|
|
241
|
+
console.log(pc.red(` ✗ API server crashed`))
|
|
242
|
+
console.log(` Check log: ${API_LOG_FILE}`)
|
|
243
|
+
stopPid(webPid, 'web')
|
|
244
|
+
removePid(API_PID_FILE)
|
|
245
|
+
removePid(WEB_PID_FILE)
|
|
246
|
+
process.exit(1)
|
|
247
|
+
}
|
|
248
|
+
if (!isRunning(webPid)) {
|
|
249
|
+
console.log(pc.red(` ✗ Web server crashed`))
|
|
250
|
+
console.log(` Check log: ${WEB_LOG_FILE}`)
|
|
251
|
+
stopPid(apiPid, 'api')
|
|
252
|
+
removePid(API_PID_FILE)
|
|
253
|
+
removePid(WEB_PID_FILE)
|
|
192
254
|
process.exit(1)
|
|
193
255
|
}
|
|
194
256
|
|
|
195
|
-
fetch(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
execSync(openCmd, { stdio: 'ignore' })
|
|
211
|
-
} catch {}
|
|
212
|
-
} else if (waited < maxWait) {
|
|
213
|
-
setTimeout(poll, interval)
|
|
214
|
-
} else {
|
|
215
|
-
console.log(pc.red(` ✗ Timed out waiting for server`))
|
|
216
|
-
console.log(` Check log: ${LOG_FILE}`)
|
|
217
|
-
removePid()
|
|
218
|
-
process.exit(1)
|
|
219
|
-
}
|
|
220
|
-
})
|
|
221
|
-
.catch(() => {
|
|
222
|
-
if (waited < maxWait) {
|
|
223
|
-
setTimeout(poll, interval)
|
|
224
|
-
} else {
|
|
225
|
-
console.log(pc.red(` ✗ Timed out waiting for server`))
|
|
226
|
-
console.log(` Check log: ${LOG_FILE}`)
|
|
227
|
-
removePid()
|
|
228
|
-
process.exit(1)
|
|
229
|
-
}
|
|
230
|
-
})
|
|
257
|
+
fetch(`${webUrl}/api/health`).catch(() => null).then((res) => {
|
|
258
|
+
// Web server doesn't have /api/health, this will 404 but we just want to check it's listening
|
|
259
|
+
if (waited < maxWait) {
|
|
260
|
+
setTimeout(poll, interval)
|
|
261
|
+
} else {
|
|
262
|
+
console.log(pc.green(` ✓ Hermium started`))
|
|
263
|
+
console.log(` ${webUrl}`)
|
|
264
|
+
console.log(` Logs: ${WEB_UI_HOME}`)
|
|
265
|
+
const openCmd =
|
|
266
|
+
process.platform === 'win32' ? `start ${webUrl}` :
|
|
267
|
+
process.platform === 'darwin' ? `open ${webUrl}` :
|
|
268
|
+
`xdg-open ${webUrl}`
|
|
269
|
+
try { execSync(openCmd, { stdio: 'ignore' }) } catch {}
|
|
270
|
+
}
|
|
271
|
+
})
|
|
231
272
|
}
|
|
232
273
|
|
|
233
274
|
setTimeout(poll, interval)
|
|
234
275
|
}
|
|
235
276
|
|
|
236
277
|
function cmdStop() {
|
|
237
|
-
const
|
|
238
|
-
|
|
278
|
+
const apiPid = getApiPid()
|
|
279
|
+
const webPid = getWebPid()
|
|
280
|
+
|
|
281
|
+
if (!apiPid && !webPid) {
|
|
239
282
|
console.log(pc.yellow(` ⊘ Hermium is not running`))
|
|
240
283
|
return
|
|
241
284
|
}
|
|
242
285
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
removePid()
|
|
253
|
-
console.log(pc.green(` ✓ Hermium stopped (PID: ${pid})`))
|
|
254
|
-
} catch {
|
|
255
|
-
removePid()
|
|
256
|
-
console.log(pc.green(` ✓ Hermium stopped (PID: ${pid})`))
|
|
286
|
+
if (webPid) {
|
|
287
|
+
stopPid(webPid, 'web')
|
|
288
|
+
removePid(WEB_PID_FILE)
|
|
289
|
+
console.log(pc.green(` ✓ Web server stopped (PID: ${webPid})`))
|
|
290
|
+
}
|
|
291
|
+
if (apiPid) {
|
|
292
|
+
stopPid(apiPid, 'api')
|
|
293
|
+
removePid(API_PID_FILE)
|
|
294
|
+
console.log(pc.green(` ✓ API server stopped (PID: ${apiPid})`))
|
|
257
295
|
}
|
|
258
296
|
}
|
|
259
297
|
|
|
@@ -271,18 +309,19 @@ ${pc.bold('Usage:')}
|
|
|
271
309
|
hermium <command> [options]
|
|
272
310
|
|
|
273
311
|
${pc.bold('Commands:')}
|
|
274
|
-
start Start Hermium
|
|
275
|
-
stop Stop Hermium
|
|
276
|
-
restart Restart Hermium
|
|
312
|
+
start Start Hermium servers (daemon)
|
|
313
|
+
stop Stop Hermium servers
|
|
314
|
+
restart Restart Hermium servers
|
|
277
315
|
status Show running status
|
|
278
316
|
help Show this help message
|
|
279
317
|
|
|
280
318
|
${pc.bold('Options:')}
|
|
281
|
-
--port <n>
|
|
319
|
+
--port <n> API port (default: 8788)
|
|
320
|
+
--web-port <n> Web port (default: 3000)
|
|
282
321
|
|
|
283
322
|
${pc.bold('Examples:')}
|
|
284
323
|
hermium start
|
|
285
|
-
hermium start --port
|
|
324
|
+
hermium start --port 9000 --web-port 3001
|
|
286
325
|
hermium stop
|
|
287
326
|
hermium status
|
|
288
327
|
`)
|