97 lines
3.1 KiB
TypeScript
97 lines
3.1 KiB
TypeScript
import { spawn } from 'node:child_process'
|
|
import { existsSync, mkdirSync } from 'node:fs'
|
|
import { delimiter, dirname, join } from 'node:path'
|
|
import {
|
|
bundledBrowserExecutable,
|
|
bundledGit,
|
|
bundledNode,
|
|
bundledPython,
|
|
gitPathDirs,
|
|
hermesBin,
|
|
hermesHome,
|
|
nodeBinDir,
|
|
pythonDir,
|
|
webUiHome,
|
|
} from './paths'
|
|
import { HERMES_CLI_ARG } from './cli-constants'
|
|
import { ensureDesktopRuntime } from './runtime-manager'
|
|
|
|
export function parseHermesCliArgs(argv: string[] = process.argv): string[] | null {
|
|
const index = argv.indexOf(HERMES_CLI_ARG)
|
|
if (index < 0) return null
|
|
return argv.slice(index + 1)
|
|
}
|
|
|
|
export async function runBundledHermesCli(args: string[]): Promise<number> {
|
|
try {
|
|
await ensureDesktopRuntime()
|
|
} catch (err) {
|
|
console.error(`Failed to prepare Hermes runtime: ${err instanceof Error ? err.message : String(err)}`)
|
|
return 1
|
|
}
|
|
|
|
const command = hermesBin()
|
|
if (!existsSync(command)) {
|
|
console.error(`hermes binary missing at ${command}`)
|
|
console.error('Run: npm run prepare:runtime (to build a local Hermes runtime)')
|
|
return 127
|
|
}
|
|
|
|
mkdirSync(webUiHome(), { recursive: true })
|
|
mkdirSync(hermesHome(), { recursive: true })
|
|
|
|
const binDir = dirname(command)
|
|
const bundledNodeBin = nodeBinDir()
|
|
const bundledAgentBrowserBin = process.platform === 'win32'
|
|
? join(pythonDir(), 'node')
|
|
: join(pythonDir(), 'node', 'bin')
|
|
const inheritedPath = process.env.PATH || process.env.Path || ''
|
|
const pathValue = [
|
|
binDir,
|
|
bundledAgentBrowserBin,
|
|
bundledNodeBin,
|
|
gitPathDirs().join(delimiter),
|
|
inheritedPath,
|
|
].filter(Boolean).join(delimiter)
|
|
const gitBin = bundledGit()
|
|
const browserExecutable = process.env.AGENT_BROWSER_EXECUTABLE_PATH?.trim() || bundledBrowserExecutable()
|
|
const env: NodeJS.ProcessEnv = {
|
|
...process.env,
|
|
HERMES_DESKTOP: 'true',
|
|
HERMES_BIN: command,
|
|
HERMES_AGENT_BRIDGE_PYTHON: bundledPython(),
|
|
HERMES_AGENT_CLI_PYTHON: bundledPython(),
|
|
HERMES_AGENT_ROOT: pythonDir(),
|
|
HERMES_AGENT_NODE: bundledNode(),
|
|
HERMES_AGENT_NODE_ROOT: process.platform === 'win32' ? bundledNodeBin : dirname(bundledNodeBin),
|
|
AGENT_BROWSER_HOME: process.env.AGENT_BROWSER_HOME?.trim() || join(hermesHome(), 'agent-browser'),
|
|
...(browserExecutable ? { AGENT_BROWSER_EXECUTABLE_PATH: browserExecutable } : {}),
|
|
PLAYWRIGHT_BROWSERS_PATH: process.env.PLAYWRIGHT_BROWSERS_PATH || join(pythonDir(), 'ms-playwright'),
|
|
...(gitBin ? { HERMES_AGENT_GIT: gitBin } : {}),
|
|
HERMES_HOME: hermesHome(),
|
|
HERMES_WEB_UI_HOME: webUiHome(),
|
|
HERMES_WEBUI_STATE_DIR: webUiHome(),
|
|
PATH: pathValue,
|
|
}
|
|
|
|
return await new Promise(resolve => {
|
|
const child = spawn(command, args, {
|
|
env,
|
|
stdio: 'inherit',
|
|
windowsHide: false,
|
|
})
|
|
child.once('error', (err) => {
|
|
console.error(`Failed to run bundled Hermes CLI: ${err.message}`)
|
|
resolve(1)
|
|
})
|
|
child.once('exit', (code, signal) => {
|
|
if (typeof code === 'number') {
|
|
resolve(code)
|
|
return
|
|
}
|
|
console.error(`Bundled Hermes CLI exited from signal ${signal || 'unknown'}`)
|
|
resolve(1)
|
|
})
|
|
})
|
|
}
|