// Local CLI: `executor web` used to mean "start a foreground server". The // first-time CLI setup path is now explicit: install the durable background // service first, then use `executor web` to open it. A fresh `web` invocation // should guide the user without minting local-server credentials/manifest state // or binding ports. import { execFile } from "node:child_process"; import { existsSync, mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; import { promisify } from "node:util"; import { expect } from "@effect/vitest"; import { Effect } from "effect"; import { scenario } from "../src/scenario"; const execFileAsync = promisify(execFile); const repoRoot = fileURLToPath(new URL("../../", import.meta.url)); scenario( "CLI web ยท a fresh install points users at setup instead of starting a foreground server", { timeout: 120_000 }, Effect.promise(async () => { const root = mkdtempSync(join(tmpdir(), "executor-web-transition-")); const dataDir = join(root, "data"); try { const { stdout, stderr } = await execFileAsync("bun", ["run", "dev:cli", "web"], { cwd: repoRoot, env: { ...process.env, EXECUTOR_DATA_DIR: dataDir }, }); const output = `${stdout}\n${stderr}`; expect(output, "plain web should not start the old foreground server").not.toContain("Open:"); expect(output, "plain web should explain that no service is running").toContain( "Executor is not running.", ); expect(output, "plain web should direct first-time users to durable setup").toContain( "install", ); expect( output, "plain web should keep the temporary-server escape hatch discoverable", ).toContain("web --foreground"); expect( existsSync(join(dataDir, "server-control", "auth.json")), "plain web should not mint a local auth token", ).toBe(false); expect( existsSync(join(dataDir, "server-control", "server.json")), "plain web should not write a foreground server manifest", ).toBe(false); } finally { rmSync(root, { recursive: true, force: true }); } }), );