import assert from "node:assert/strict"; import test from "node:test"; import os from "node:os"; import path from "node:path"; import { mkdtemp, rm, writeFile } from "node:fs/promises"; import { getHermesBackendAvailabilityForTesting, getHermesBackendConfigForTesting, isHermesBackendConfiguredForTesting, } from "../src/lib/execution/backends/hermes-config.ts"; function snapshotEnv() { return { BOSS_HERMES_ENABLED: process.env.BOSS_HERMES_ENABLED, BOSS_HERMES_COMMAND: process.env.BOSS_HERMES_COMMAND, BOSS_HERMES_ARGS: process.env.BOSS_HERMES_ARGS, BOSS_HERMES_WORKDIR: process.env.BOSS_HERMES_WORKDIR, BOSS_HERMES_TIMEOUT_MS: process.env.BOSS_HERMES_TIMEOUT_MS, BOSS_HERMES_DEFAULT_MODEL: process.env.BOSS_HERMES_DEFAULT_MODEL, BOSS_HERMES_TOOLSETS: process.env.BOSS_HERMES_TOOLSETS, BOSS_HERMES_SKILLS: process.env.BOSS_HERMES_SKILLS, }; } function restoreEnv(snapshot: ReturnType) { process.env.BOSS_HERMES_ENABLED = snapshot.BOSS_HERMES_ENABLED; process.env.BOSS_HERMES_COMMAND = snapshot.BOSS_HERMES_COMMAND; process.env.BOSS_HERMES_ARGS = snapshot.BOSS_HERMES_ARGS; process.env.BOSS_HERMES_WORKDIR = snapshot.BOSS_HERMES_WORKDIR; process.env.BOSS_HERMES_TIMEOUT_MS = snapshot.BOSS_HERMES_TIMEOUT_MS; process.env.BOSS_HERMES_DEFAULT_MODEL = snapshot.BOSS_HERMES_DEFAULT_MODEL; process.env.BOSS_HERMES_TOOLSETS = snapshot.BOSS_HERMES_TOOLSETS; process.env.BOSS_HERMES_SKILLS = snapshot.BOSS_HERMES_SKILLS; } test("Hermes backend 在未配置时默认关闭", () => { const previous = snapshotEnv(); delete process.env.BOSS_HERMES_ENABLED; delete process.env.BOSS_HERMES_COMMAND; delete process.env.BOSS_HERMES_ARGS; delete process.env.BOSS_HERMES_WORKDIR; delete process.env.BOSS_HERMES_TIMEOUT_MS; delete process.env.BOSS_HERMES_DEFAULT_MODEL; delete process.env.BOSS_HERMES_TOOLSETS; delete process.env.BOSS_HERMES_SKILLS; const config = getHermesBackendConfigForTesting(); assert.equal(config.enabled, false); assert.equal(config.command, "hermes"); assert.equal(isHermesBackendConfiguredForTesting(config), false); restoreEnv(previous); }); test("Hermes backend 在配置完整时返回 command、args、toolsets 和 skills", () => { const previous = snapshotEnv(); process.env.BOSS_HERMES_ENABLED = "true"; process.env.BOSS_HERMES_COMMAND = "hermes"; process.env.BOSS_HERMES_ARGS = "--profile prod"; process.env.BOSS_HERMES_WORKDIR = "/tmp/hermes"; process.env.BOSS_HERMES_TIMEOUT_MS = "39000"; process.env.BOSS_HERMES_DEFAULT_MODEL = "gpt-5.4"; process.env.BOSS_HERMES_TOOLSETS = "web,terminal"; process.env.BOSS_HERMES_SKILLS = "boss-dev,github"; const config = getHermesBackendConfigForTesting(); assert.equal(config.enabled, true); assert.equal(config.command, "hermes"); assert.deepEqual(config.args, ["--profile", "prod"]); assert.equal(config.cwd, "/tmp/hermes"); assert.equal(config.timeoutMs, 39000); assert.equal(config.defaultModel, "gpt-5.4"); assert.deepEqual(config.toolsets, ["web", "terminal"]); assert.deepEqual(config.skills, ["boss-dev", "github"]); assert.equal(isHermesBackendConfiguredForTesting(config), true); restoreEnv(previous); }); test("Hermes backend availability 会在可执行命令和脚本都存在时返回 ready", async () => { const previous = snapshotEnv(); const tempDir = await mkdtemp(path.join(os.tmpdir(), "boss-hermes-config-")); const scriptPath = path.join(tempDir, "hermes-smoke.mjs"); await writeFile(scriptPath, "console.log('ok');\n", "utf8"); process.env.BOSS_HERMES_ENABLED = "true"; process.env.BOSS_HERMES_COMMAND = process.execPath; process.env.BOSS_HERMES_ARGS = scriptPath; process.env.BOSS_HERMES_WORKDIR = tempDir; try { const availability = await getHermesBackendAvailabilityForTesting(); assert.equal(availability.status, "ready"); assert.equal(availability.selectable, true); assert.equal(availability.reason, "ready"); } finally { restoreEnv(previous); await rm(tempDir, { recursive: true, force: true }); } }); test("Hermes backend availability 会在脚本参数不存在时返回不可选", async () => { const previous = snapshotEnv(); const tempDir = await mkdtemp(path.join(os.tmpdir(), "boss-hermes-config-")); const missingScript = path.join(tempDir, "missing-hermes-script.mjs"); process.env.BOSS_HERMES_ENABLED = "true"; process.env.BOSS_HERMES_COMMAND = process.execPath; process.env.BOSS_HERMES_ARGS = missingScript; process.env.BOSS_HERMES_WORKDIR = tempDir; try { const availability = await getHermesBackendAvailabilityForTesting(); assert.equal(availability.status, "misconfigured"); assert.equal(availability.selectable, false); assert.equal(availability.reason, "script_not_found"); } finally { restoreEnv(previous); await rm(tempDir, { recursive: true, force: true }); } });