#!/usr/bin/env bun /** * Zesdex CLI — main entry point. * * Zesdex is a pure CLI/TUI tool: * - `zesdex` → boots the interactive OpenTUI (primary interface) * - `zesdex --headless "

"` → runs a single one-shot agent turn and exits * * All server modes (REST API / WebSocket / gRPC / web / daemon) were removed in * the "full cli tui" rombak. The TUI owns the interactive agent runtime; this * entry point only routes to it or runs a one-shot headless turn. */ import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; import { parseCli } from "./args.ts"; /** Initialise file logging (append to /zesdex/zesdex.log). */ function initLogging(): void { const dataDir = os.homedir(); const logDir = path.join(dataDir, ".local", "share", "zesdex"); fs.mkdirSync(logDir, { recursive: true }); const logPath = path.join(logDir, "zesdex.log"); const stream = fs.createWriteStream(logPath, { flags: "a" }); const originalLog = console.log; const originalError = console.error; const write = (level: string, args: unknown[]) => { const line = `[${new Date().toISOString()}] ${level} ${args .map((a) => (typeof a === "string" ? a : JSON.stringify(a))) .join(" ")}`; stream.write(line + "\n"); if (level === "ERROR") originalError(...args); else originalLog(...args); }; console.log = (...a: unknown[]) => write("LOG", a); console.info = (...a: unknown[]) => write("INFO", a); console.warn = (...a: unknown[]) => write("WARN", a); console.error = (...a: unknown[]) => write("ERROR", a); } /** Run a single one-shot agent turn non-interactively, printing the outcome. */ async function runHeadless(prompt: string): Promise { const { runSingleProcess, buildTurnParams } = await import("./compose.ts"); const runtime = await runSingleProcess(); const events: import("@zesdex/domain").TurnEvent[] = []; const abort = new AbortController(); const params = buildTurnParams(runtime, prompt, events, abort); await runtime.turnService.runTurn(params); const tokens: string[] = []; for (const ev of events) { if (ev.kind === "stream_token") tokens.push(ev.content); } const full = tokens.join(""); process.stdout.write("\n"); if (full.trim() !== "") console.log(full.trim()); else console.log("(no response content)"); } /** Main entry. `zesdex` → TUI; `--headless ` → one-shot turn. */ async function main(): Promise { initLogging(); const args = process.argv.slice(2); let parsed; try { parsed = parseCli(args); } catch (e) { console.error((e as Error).message); process.exit(2); } if ("help" in parsed) { console.log(parsed.text); process.exit(0); } if (parsed.headless !== null) { await runHeadless(parsed.headless); process.exit(0); } // Default: boot the interactive TUI. const { runTui } = await import("@zesdex/tui"); await runTui(); process.exit(0); } main().catch((e) => { console.error(e instanceof Error ? e.message : String(e)); process.exit(1); });