- Hapus total interfaces: api (REST), ws (WebSocket), grpc, web, daemon (IPC) - Hapus infra server-only yang jadi dead code: infrastructure/ipc + seluruh stack auth (domain/auth, application/auth, persistence/iam, infrastructure/auth jwt/password/oauth_loopback) - TUI (OpenTUI) jadi interface utama: wire ke runSingleProcess() real runtime, ganti mock '(no LLM configured)' dengan turnService.runTurn asli + streaming stream_token/reasoning/tool_result/system_note/error ke transcript - Tampilkan model asli di header (mis. claude-opus-5), abort turn via Ctrl+C - CLI jadi mode headless tambahan: zesdex --headless '<prompt>' one-shot turn - Bersihkan package.json (script tui/headless), tsconfig paths, docker-compose, AGENTS.md; hapus StartOAuth/login stub - verified: tsc 0 err, 70 test pass, build dist/zesdex; headless 'pong' real; TUI interactive render + real turn 'say pong in one word' -> assistant 'pong'
97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
#!/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 "<p>"` → 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 <data-dir>/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<void> {
|
|
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 <prompt>` → one-shot turn. */
|
|
async function main(): Promise<void> {
|
|
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);
|
|
});
|