#!/usr/bin/env node
import { spawnSync } from "node:child_process";
import { createInterface } from "node:readline";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { connectDaemonClient } from "@best-agent/sdk-ts";
import { renderThreadHandoffText } from "@best-agent/protocol";
import { runHttpServer, runSocketDaemon, runStdioAcpServer, runStdioServer, } from "@best-agent/server";
import { unwrapStrictRespondText } from "./dimsdk/core/strict-respond.js";
import { getProviderConfigFromEnv } from "./provider-config-env.js";
import { resolveCliStorageRoot } from "./runtime.js";
async function main() {
    const [command, ...args] = process.argv.slice(2);
    loadDotEnv(resolveCliEnvRoot(args));
    if (command === "server") {
        const options = parseCommonOptions(args);
        await runStdioServer(options);
        return;
    }
    if (command === "daemon") {
        const options = parseCommonOptions(args);
        await runSocketDaemon(options);
        return;
    }
    if (command === "serve") {
        const options = parseServeOptions(args);
        await runHttpServer(options);
        return;
    }
    if (command === "acp") {
        const options = parseCommonOptions(args);
        await runStdioAcpServer(options);
        return;
    }
    if (command === "run") {
        const { prompt, ...options } = parseRunOptions(args);
        if (!prompt) {
            process.stderr.write("Usage: best-agent run [--provider <kind>] [--model <id>] [--base-url <url>] [--compatibility <auto|native|compatible>] [--storage-root <path>] [--extensions-root <path>] [--agent <name>] [--cwd <path>] [--approval-timeout-ms <ms>] [--guardian-enabled <true|false>] [--guardian-model <id>] [--guardian-threshold <0-100>] [--guardian-timeout-ms <ms>] [--plan] <prompt>\n");
            process.exitCode = 1;
            return;
        }
        await runSinglePrompt(prompt, options);
        return;
    }
    if (command === "chat") {
        const options = parseChatOptions(args);
        if (shouldUseTuiChat()) {
            const tuiBundle = "./dimsdk-tui.bundle.js";
            const { runDimSdkTuiChat } = await import(tuiBundle);
            await runDimSdkTuiChat(options);
            return;
        }
        await runInteractiveChat(options);
        return;
    }
    process.stderr.write("Usage: best-agent server [--storage-root <path>] [--extensions-root <path>] [--cwd <path>] [--provider <kind>] [--model <id>] [--base-url <url>] [--compatibility <auto|native|compatible>] [--approval-timeout-ms <ms>] [--guardian-enabled <true|false>] [--guardian-model <id>] [--guardian-threshold <0-100>] [--guardian-timeout-ms <ms>]\n");
    process.stderr.write("   or: best-agent daemon [--storage-root <path>] [--extensions-root <path>] [--cwd <path>] [--provider <kind>] [--model <id>] [--base-url <url>] [--compatibility <auto|native|compatible>] [--approval-timeout-ms <ms>] [--guardian-enabled <true|false>] [--guardian-model <id>] [--guardian-threshold <0-100>] [--guardian-timeout-ms <ms>]\n");
    process.stderr.write("   or: best-agent serve [--host <host>] [--port <port>] [--storage-root <path>] [--extensions-root <path>] [--cwd <path>] [--provider <kind>] [--model <id>] [--base-url <url>] [--compatibility <auto|native|compatible>] [--approval-timeout-ms <ms>] [--guardian-enabled <true|false>] [--guardian-model <id>] [--guardian-threshold <0-100>] [--guardian-timeout-ms <ms>]\n");
    process.stderr.write("   or: best-agent acp [--storage-root <path>] [--extensions-root <path>] [--cwd <path>] [--provider <kind>] [--model <id>] [--base-url <url>] [--compatibility <auto|native|compatible>] [--approval-timeout-ms <ms>] [--guardian-enabled <true|false>] [--guardian-model <id>] [--guardian-threshold <0-100>] [--guardian-timeout-ms <ms>]\n");
    process.stderr.write("   or: best-agent run [--storage-root <path>] [--extensions-root <path>] [--agent <name>] [--cwd <path>] [--provider <kind>] [--model <id>] [--base-url <url>] [--compatibility <auto|native|compatible>] [--approval-timeout-ms <ms>] [--guardian-enabled <true|false>] [--guardian-model <id>] [--guardian-threshold <0-100>] [--guardian-timeout-ms <ms>] [--plan] <prompt>\n");
    process.stderr.write("   or: best-agent chat [--storage-root <path>] [--extensions-root <path>] [--agent <name>] [--cwd <path>] [--provider <kind>] [--model <id>] [--base-url <url>] [--compatibility <auto|native|compatible>] [--approval-timeout-ms <ms>] [--guardian-enabled <true|false>] [--guardian-model <id>] [--guardian-threshold <0-100>] [--guardian-timeout-ms <ms>] [--resume <thread-id>] [--latest] [--plan] [--no-mouse] [--no-alt-screen]\n");
    process.exitCode = 1;
}
async function runSinglePrompt(prompt, options) {
    const entrypoint = process.argv[1];
    if (!entrypoint) {
        throw new Error("CLI entrypoint path is not available.");
    }
    const storageRoot = resolveCliStorageRoot(options);
    const terminal = createTerminalPrompter();
    const client = await connectDaemonClient(process.execPath, [entrypoint], {
        approvalTimeoutMs: options.approvalTimeoutMs,
        cwd: options.cwd,
        extensionsRoot: options.extensionsRoot,
        guardian: options.guardian,
        providerConfig: options.providerConfig,
        storageRoot,
    });
    let inputQueue = Promise.resolve();
    const unsubscribe = client.onEvent((event) => {
        const runtimeEvent = event.event;
        if (runtimeEvent.type === "approval.requested") {
            inputQueue = inputQueue.then(async () => {
                const resolution = await promptForApprovalWithInterface(runtimeEvent.approval, terminal);
                await client.respondToApproval(runtimeEvent.approval.id, resolution.decision, resolution.scope);
            });
            return;
        }
        if (runtimeEvent.type === "action.required" && runtimeEvent.kind === "ask_user") {
            inputQueue = inputQueue.then(async () => {
                const answers = await promptForAskUserWithInterface(runtimeEvent, terminal);
                await client.respondToAction(runtimeEvent.actionId, answers);
            });
        }
    });
    try {
        await client.initialize("best-agent-cli-run", "0.0.0");
        const { thread } = await client.startThread({ mode: options.threadMode });
        const result = await client.run(thread.id, buildRunPrompt(prompt, options.agentProfile));
        await inputQueue;
        const resumed = await client.resumeThread(thread.id);
        const displayText = findLatestDisplayText(resumed.items);
        if (displayText) {
            process.stdout.write(`${displayText}\n`);
            return;
        }
        process.stdout.write(`${result.turn.status}\n`);
    }
    finally {
        unsubscribe();
        terminal.close();
        client.close();
    }
}
async function runInteractiveChat(options) {
    const entrypoint = process.argv[1];
    if (!entrypoint) {
        throw new Error("CLI entrypoint path is not available.");
    }
    const storageRoot = resolveCliStorageRoot(options);
    const client = await connectDaemonClient(process.execPath, [entrypoint], {
        approvalTimeoutMs: options.approvalTimeoutMs,
        cwd: options.cwd,
        extensionsRoot: options.extensionsRoot,
        guardian: options.guardian,
        providerConfig: options.providerConfig,
        storageRoot,
    });
    try {
        await client.initialize("best-agent-cli", "0.0.0");
        const thread = await resolveInitialChatThread(client, options);
        let activeAgentProfile = options.agentProfile;
        let activeThreadId = thread.id;
        let activeThreadMode = thread.mode;
        const activeSkillIds = new Set();
        let hasSkillOverride = false;
        const terminal = createTerminalPrompter();
        process.stdout.write(`thread> ${activeThreadId}\n`);
        process.stdout.write(`mode> ${activeThreadMode}\n`);
        if (activeAgentProfile) {
            process.stdout.write(`agent> ${activeAgentProfile}\n`);
        }
        if (options.providerConfig) {
            process.stdout.write(`provider> ${options.providerConfig.kind}/${options.providerConfig.model}\n`);
        }
        else {
            process.stdout.write("provider> none (tool-only prompts will still work)\n");
        }
        process.stdout.write("type /exit to quit\n");
        try {
            while (true) {
                const prompt = ((await terminal.ask("you> ", process.stderr)) ?? "/exit").trim();
                if (!prompt) {
                    continue;
                }
                if (prompt === "/exit" || prompt === "/quit") {
                    return;
                }
                if (prompt === "/help") {
                    process.stdout.write("commands> /help /exit /quit /thread /threads [all] /resume <threadId> /new [title] /archive [threadId] /unarchive <threadId> /delete [threadId] /status /memory [show|set|add|edit|clear] /diagnostics /compact /forks /agents /agent <name|clear> /plan <on|off|status|show|todos|approve|reject|export> /skills /use-skill <id> /drop-skill <id> /tools /handoff /research [runId] /evidence [runId] /fork [title]\n");
                    continue;
                }
                if (prompt === "/thread") {
                    process.stdout.write(`thread> ${activeThreadId}\n`);
                    continue;
                }
                if (prompt === "/threads" || prompt === "/threads all" || prompt === "/threads --all") {
                    const listed = await client.listThreads({
                        includeArchived: prompt !== "/threads",
                        limit: 50,
                    });
                    if (listed.threads.length === 0) {
                        process.stdout.write("threads> (none)\n");
                        continue;
                    }
                    for (const thread of listed.threads) {
                        const selected = thread.id === activeThreadId ? "*" : " ";
                        process.stdout.write(`${selected} ${thread.id} [${thread.status}] - ${thread.title}\n`);
                    }
                    continue;
                }
                if (prompt.startsWith("/resume ")) {
                    const threadId = prompt.slice("/resume ".length).trim();
                    if (!threadId) {
                        process.stdout.write("error> Missing thread id\n");
                        continue;
                    }
                    try {
                        const resumed = await resumeChatThread(client, threadId);
                        activeThreadId = resumed.id;
                        activeThreadMode = resumed.mode;
                    }
                    catch (error) {
                        process.stdout.write(`error> ${error instanceof Error ? error.message : "Unknown thread error"}\n`);
                        continue;
                    }
                    activeSkillIds.clear();
                    hasSkillOverride = false;
                    process.stdout.write(`thread> ${activeThreadId}\n`);
                    process.stdout.write(`mode> ${activeThreadMode}\n`);
                    continue;
                }
                if (prompt === "/new" || prompt.startsWith("/new ")) {
                    const title = prompt === "/new" ? undefined : prompt.slice("/new ".length).trim() || undefined;
                    const { thread } = await client.startThread({ mode: activeThreadMode, title });
                    activeThreadId = thread.id;
                    activeThreadMode = thread.mode;
                    activeSkillIds.clear();
                    hasSkillOverride = false;
                    process.stdout.write(`thread> ${activeThreadId}\n`);
                    process.stdout.write(`mode> ${activeThreadMode}\n`);
                    continue;
                }
                if (prompt === "/archive" || prompt.startsWith("/archive ")) {
                    const targetThreadId = prompt === "/archive" ? activeThreadId : prompt.slice("/archive ".length).trim();
                    if (!targetThreadId) {
                        process.stdout.write("error> Missing thread id\n");
                        continue;
                    }
                    try {
                        await client.archiveThread(targetThreadId);
                    }
                    catch (error) {
                        process.stdout.write(`error> ${error instanceof Error ? error.message : "Unknown thread error"}\n`);
                        continue;
                    }
                    process.stdout.write(`archived> ${targetThreadId}\n`);
                    if (targetThreadId === activeThreadId) {
                        const fallback = await resolveFallbackChatThread(client, targetThreadId, activeThreadMode);
                        activeThreadId = fallback.id;
                        activeThreadMode = fallback.mode;
                        activeSkillIds.clear();
                        hasSkillOverride = false;
                        process.stdout.write(`thread> ${activeThreadId}\n`);
                        process.stdout.write(`mode> ${activeThreadMode}\n`);
                    }
                    continue;
                }
                if (prompt.startsWith("/unarchive ")) {
                    const threadId = prompt.slice("/unarchive ".length).trim();
                    if (!threadId) {
                        process.stdout.write("error> Missing thread id\n");
                        continue;
                    }
                    try {
                        await client.unarchiveThread(threadId);
                    }
                    catch (error) {
                        process.stdout.write(`error> ${error instanceof Error ? error.message : "Unknown thread error"}\n`);
                        continue;
                    }
                    process.stdout.write(`unarchived> ${threadId}\n`);
                    continue;
                }
                if (prompt === "/delete" ||
                    prompt.startsWith("/delete ") ||
                    prompt === "/purge" ||
                    prompt.startsWith("/purge ")) {
                    const targetThreadId = prompt === "/delete" || prompt === "/purge"
                        ? activeThreadId
                        : prompt.startsWith("/delete ")
                            ? prompt.slice("/delete ".length).trim()
                            : prompt.slice("/purge ".length).trim();
                    if (!targetThreadId) {
                        process.stdout.write("error> Missing thread id\n");
                        continue;
                    }
                    try {
                        await client.purgeThread(targetThreadId);
                    }
                    catch (error) {
                        process.stdout.write(`error> ${error instanceof Error ? error.message : "Unknown thread error"}\n`);
                        continue;
                    }
                    process.stdout.write(`deleted> ${targetThreadId}\n`);
                    if (targetThreadId === activeThreadId) {
                        const fallback = await resolveFallbackChatThread(client, targetThreadId, activeThreadMode);
                        activeThreadId = fallback.id;
                        activeThreadMode = fallback.mode;
                        activeSkillIds.clear();
                        hasSkillOverride = false;
                        process.stdout.write(`thread> ${activeThreadId}\n`);
                        process.stdout.write(`mode> ${activeThreadMode}\n`);
                    }
                    continue;
                }
                if (prompt === "/status") {
                    const detail = await client.getThread(activeThreadId);
                    const { plan } = await client.getThreadPlan(activeThreadId);
                    process.stdout.write(`thread> ${activeThreadId}\n`);
                    process.stdout.write(`mode> ${detail.thread.mode}\n`);
                    process.stdout.write(`agent> ${activeAgentProfile ?? "orchestrator"}\n`);
                    process.stdout.write(`skills> ${hasSkillOverride ? Array.from(activeSkillIds).join(", ") || "(none)" : "(runtime default)"}\n`);
                    process.stdout.write(`plan> ${plan ? `${plan.status} rev${plan.graphRevision}` : "(none)"}\n`);
                    if (detail.thread.forkedFromThreadId) {
                        process.stdout.write(`forked-from> ${detail.thread.forkedFromThreadId}\n`);
                    }
                    process.stdout.write(`forks> ${detail.thread.childCount}\n`);
                    continue;
                }
                if (prompt === "/memory" || prompt === "/memory show") {
                    const { memory } = await client.getProjectMemory();
                    process.stdout.write(`memory> ${memory.path}${memory.updatedAt ? ` [updated ${memory.updatedAt}]` : " [empty]"}\n`);
                    if (memory.auto) {
                        process.stdout.write(`memory-auto> ${memory.auto.path}${memory.auto.updatedAt ? ` [updated ${memory.auto.updatedAt}]` : memory.auto.exists ? " [present]" : " [empty]"} entries=${memory.auto.entryCount}\n`);
                    }
                    if (memory.sync) {
                        const modeLabel = memory.sync.enabled
                            ? `shared ${memory.sync.projectKey ?? ""}`.trim()
                            : `local-only${memory.sync.reason ? ` (${memory.sync.reason})` : ""}`;
                        process.stdout.write(`memory-sync> ${modeLabel}\n`);
                        if (memory.sync.lastPullAt) {
                            process.stdout.write(`memory-sync-pull> ${memory.sync.lastPullAt}\n`);
                        }
                        if (memory.sync.lastPushAt) {
                            process.stdout.write(`memory-sync-push> ${memory.sync.lastPushAt}\n`);
                        }
                        if (memory.sync.lastConflictAt) {
                            process.stdout.write(`memory-sync-conflict> ${memory.sync.lastConflictAt}\n`);
                        }
                        if (memory.sync.lastError) {
                            process.stdout.write(`memory-sync-error> ${memory.sync.lastError}\n`);
                        }
                    }
                    process.stdout.write(`${memory.renderedContent.trim() || "(empty)"}\n`);
                    continue;
                }
                if (prompt === "/memory clear") {
                    const { memory } = await client.clearProjectMemory();
                    process.stdout.write(`memory> cleared ${memory.path}\n`);
                    continue;
                }
                if (prompt === "/memory edit") {
                    const editor = process.env.VISUAL ?? process.env.EDITOR;
                    if (!editor) {
                        process.stdout.write("error> Set VISUAL or EDITOR to use /memory edit\n");
                        continue;
                    }
                    const { memory } = await client.getProjectMemory();
                    if (!memory.exists) {
                        mkdirSync(dirname(memory.path), { recursive: true });
                        writeFileSync(memory.path, "", "utf8");
                    }
                    const result = spawnSync(editor, [memory.path], {
                        cwd: options.cwd ?? process.cwd(),
                        shell: true,
                        stdio: "inherit",
                    });
                    if (result.status !== 0) {
                        process.stdout.write(`error> Editor exited with status ${result.status ?? "unknown"}\n`);
                        continue;
                    }
                    const nextContent = existsSync(memory.path) ? readFileSync(memory.path, "utf8") : "";
                    const updated = await client.setProjectMemory(nextContent);
                    process.stdout.write(`memory> updated ${updated.memory.path}\n`);
                    continue;
                }
                if (prompt.startsWith("/memory set ")) {
                    const content = prompt.slice("/memory set ".length).trim();
                    if (!content) {
                        process.stdout.write("error> Missing memory text\n");
                        continue;
                    }
                    const { memory } = await client.setProjectMemory(content);
                    process.stdout.write(`memory> updated ${memory.path}\n`);
                    continue;
                }
                if (prompt.startsWith("/memory add ")) {
                    const content = prompt.slice("/memory add ".length).trim();
                    if (!content) {
                        process.stdout.write("error> Missing memory text\n");
                        continue;
                    }
                    const current = await client.getProjectMemory();
                    const nextContent = current.memory.content.trim()
                        ? `${current.memory.content.trimEnd()}\n\n${content}`
                        : content;
                    const { memory } = await client.setProjectMemory(nextContent);
                    process.stdout.write(`memory> updated ${memory.path}\n`);
                    continue;
                }
                if (prompt === "/plan" || prompt === "/plan status") {
                    process.stdout.write(`mode> ${activeThreadMode}\n`);
                    continue;
                }
                if (prompt === "/plan on" || prompt === "/plan off") {
                    const nextMode = prompt === "/plan on" ? "plan" : "default";
                    const { thread } = await client.setThreadMode(activeThreadId, nextMode);
                    activeThreadMode = thread.mode;
                    if (activeThreadMode === "plan" &&
                        activeAgentProfile &&
                        activeAgentProfile !== "plan" &&
                        activeAgentProfile !== "explore") {
                        activeAgentProfile = undefined;
                    }
                    process.stdout.write(`mode> ${activeThreadMode}\n`);
                    continue;
                }
                if (prompt === "/plan show") {
                    const { plan } = await client.getThreadPlan(activeThreadId);
                    if (!plan) {
                        process.stdout.write("plan> (none)\n");
                        continue;
                    }
                    process.stdout.write(`plan> ${plan.title} [${plan.status}] rev${plan.graphRevision}\n`);
                    process.stdout.write(`${plan.summary}\n`);
                    continue;
                }
                if (prompt === "/plan todos") {
                    const { plan } = await client.getThreadPlan(activeThreadId);
                    if (!plan || plan.todos.length === 0) {
                        process.stdout.write("plan-todos> (none)\n");
                        continue;
                    }
                    for (const todo of plan.todos) {
                        const checkbox = todo.status === "done" ? "[x]" : "[ ]";
                        const suffix = todo.status === "in_progress"
                            ? " (in progress)"
                            : todo.status === "blocked"
                                ? " (blocked)"
                                : todo.status === "cancelled"
                                    ? " (cancelled)"
                                    : "";
                        process.stdout.write(`plan-todo> ${checkbox} ${todo.content}${suffix}\n`);
                    }
                    continue;
                }
                if (prompt === "/plan approve") {
                    const { plan } = await client.approveThreadPlan(activeThreadId);
                    process.stdout.write(`plan> approved ${plan.title}\n`);
                    continue;
                }
                if (prompt === "/plan reject") {
                    const { plan } = await client.rejectThreadPlan(activeThreadId);
                    process.stdout.write(`plan> rejected ${plan.title}\n`);
                    continue;
                }
                if (prompt === "/plan export") {
                    const exported = await client.exportThreadPlan(activeThreadId);
                    process.stdout.write(`plan-export>\n${exported.text ?? "(none)"}\n`);
                    continue;
                }
                if (prompt === "/diagnostics") {
                    const { diagnostics } = await client.getThreadDiagnostics(activeThreadId);
                    process.stdout.write(`cache> builds=${diagnostics.cache.buildCount} exact-hit-rate=${diagnostics.cache.hitRate} effective-hit-rate=${diagnostics.cache.effectiveHitRate} prefix-hit-rate=${diagnostics.cache.prefixHitRate} segment-hit-rate=${diagnostics.cache.segmentHitRate} token-reuse=${diagnostics.cache.tokenReuseRatio}\n`);
                    process.stdout.write(`memory> commits=${diagnostics.compaction.commitCount} reason=${diagnostics.compaction.lastReason ?? "none"} budget=${diagnostics.compaction.lastBudgetTokens ?? 0} estimated=${diagnostics.compaction.lastEstimatedTokens ?? 0} segments=${diagnostics.segments.totalCount} drift=${diagnostics.segments.driftCount}\n`);
                    process.stdout.write(`provider> calls=${diagnostics.provider.callCount} metered=${diagnostics.provider.reportedUsageCallCount} input-tokens=${diagnostics.provider.inputTokens} output-tokens=${diagnostics.provider.outputTokens} cache-read=${diagnostics.provider.cacheReadTokens} cache-read-ratio=${diagnostics.provider.cacheReadRatio} cache-write=${diagnostics.provider.cacheWriteTokens} cache-write-ratio=${diagnostics.provider.cacheWriteRatio}\n`);
                    process.stdout.write(`session> thread=${diagnostics.session.threadId} root=${diagnostics.session.rootThreadId} exclusive-total=${diagnostics.session.exclusive.totalTokens} inclusive-total=${diagnostics.session.inclusive.totalTokens} reported-ratio=${diagnostics.session.coverage.inclusive.reportedTokenRatio} tools=${diagnostics.session.runtime.inclusive.toolCallCount} subagents=${diagnostics.session.runtime.inclusive.subagentThreadCount} wall-ms=${diagnostics.session.runtime.inclusive.wallTimeMs.toFixed(1)} cpu-user-ms=${diagnostics.session.runtime.inclusive.cpuUserMs.toFixed(1)} cpu-system-ms=${diagnostics.session.runtime.inclusive.cpuSystemMs.toFixed(1)} compact-saved=${diagnostics.session.compaction.inclusive.totalEstimatedTokensSaved}\n`);
                    continue;
                }
                if (prompt === "/compact") {
                    const compacted = await client.compactThread(activeThreadId, {
                        activeSkills: hasSkillOverride ? Array.from(activeSkillIds) : undefined,
                    });
                    process.stdout.write(`compact> ${compacted.summary.summaryText || "(empty)"}\n`);
                    continue;
                }
                if (prompt === "/forks") {
                    const children = await client.listThreads({
                        forkedFromThreadId: activeThreadId,
                        includeArchived: true,
                    });
                    if (children.threads.length === 0) {
                        process.stdout.write("forks> (none)\n");
                        continue;
                    }
                    for (const child of children.threads) {
                        process.stdout.write(`${child.id} - ${child.title} [${child.status}]\n`);
                    }
                    continue;
                }
                if (prompt === "/agents") {
                    const profiles = await client.listAgentProfiles();
                    for (const profile of profiles.profiles) {
                        const selected = profile.name === activeAgentProfile ? "*" : " ";
                        process.stdout.write(`${selected} ${profile.name} [${profile.source}] - ${profile.description}\n`);
                    }
                    continue;
                }
                if (prompt.startsWith("/agent ")) {
                    const nextProfile = prompt.slice("/agent ".length).trim();
                    if (!nextProfile || nextProfile === "clear") {
                        activeAgentProfile = undefined;
                        process.stdout.write("agent> orchestrator\n");
                        continue;
                    }
                    if (activeThreadMode === "plan" && nextProfile !== "plan" && nextProfile !== "explore") {
                        process.stdout.write("error> Plan mode only allows the plan or explore profiles\n");
                        continue;
                    }
                    const profiles = await client.listAgentProfiles();
                    if (!profiles.profiles.some((profile) => profile.name === nextProfile)) {
                        process.stdout.write(`error> Unknown agent profile ${nextProfile}\n`);
                        continue;
                    }
                    activeAgentProfile = nextProfile;
                    process.stdout.write(`agent> ${activeAgentProfile}\n`);
                    continue;
                }
                if (prompt === "/skills") {
                    const skills = await client.listSkills();
                    for (const skill of skills.skills) {
                        const selected = activeSkillIds.has(skill.id) ? "*" : " ";
                        process.stdout.write(`${selected} ${skill.id} - ${skill.description}\n`);
                    }
                    continue;
                }
                if (prompt.startsWith("/use-skill ")) {
                    const skillId = prompt.slice("/use-skill ".length).trim();
                    const skills = await client.listSkills();
                    if (!skills.skills.some((skill) => skill.id === skillId)) {
                        process.stdout.write(`error> Unknown skill ${skillId}\n`);
                        continue;
                    }
                    activeSkillIds.add(skillId);
                    hasSkillOverride = true;
                    process.stdout.write(`skill> enabled ${skillId}\n`);
                    continue;
                }
                if (prompt.startsWith("/drop-skill ")) {
                    const skillId = prompt.slice("/drop-skill ".length).trim();
                    activeSkillIds.delete(skillId);
                    hasSkillOverride = true;
                    process.stdout.write(`skill> disabled ${skillId}\n`);
                    continue;
                }
                if (prompt === "/tools") {
                    const toolProfile = activeAgentProfile ?? (activeThreadMode === "plan" ? "plan" : undefined);
                    const tools = await client.listTools({ agentProfile: toolProfile });
                    for (const tool of tools.tools) {
                        process.stdout.write(`${tool.name} [${tool.source}] - ${tool.description}\n`);
                    }
                    continue;
                }
                if (prompt === "/handoff") {
                    const { handoff } = await client.getThreadHandoff(activeThreadId);
                    process.stdout.write(`handoff> ${renderThreadHandoffText(handoff) || "(empty)"}\n`);
                    continue;
                }
                if (prompt === "/research" || prompt.startsWith("/research ")) {
                    const runId = prompt === "/research"
                        ? undefined
                        : prompt.slice("/research ".length).trim() || undefined;
                    const { report, run } = await client.getThreadResearchReport(activeThreadId, { runId });
                    if (!run || !report) {
                        process.stdout.write("research> (none)\n");
                        continue;
                    }
                    process.stdout.write(`research> ${run.runId} [${run.status}] ${report.executiveSummary || "(empty)"}\n`);
                    continue;
                }
                if (prompt === "/evidence" || prompt.startsWith("/evidence ")) {
                    const runId = prompt === "/evidence"
                        ? undefined
                        : prompt.slice("/evidence ".length).trim() || undefined;
                    const { evidence, run } = await client.listThreadResearchEvidence(activeThreadId, {
                        runId,
                    });
                    if (!run || evidence.length === 0) {
                        process.stdout.write("evidence> (none)\n");
                        continue;
                    }
                    process.stdout.write(`evidence> ${run.runId} (${evidence.length})\n`);
                    for (const card of evidence) {
                        process.stdout.write(`- ${card.evidenceId}: ${truncateForTerminal(card.summary)}\n`);
                    }
                    continue;
                }
                if (prompt.startsWith("/fork")) {
                    const title = prompt.slice("/fork".length).trim() || undefined;
                    const forked = await client.forkThread(activeThreadId, { title });
                    activeThreadId = forked.thread.id;
                    activeThreadMode = forked.thread.mode;
                    process.stdout.write(`thread> ${activeThreadId}\n`);
                    process.stdout.write(`mode> ${activeThreadMode}\n`);
                    continue;
                }
                const stream = client.runStreamed(activeThreadId, prompt, {
                    activeSkills: hasSkillOverride ? Array.from(activeSkillIds) : undefined,
                    agentProfile: activeAgentProfile,
                });
                for await (const event of stream.events) {
                    await renderChatEvent(client, event, terminal);
                }
                const result = await stream.completed;
                if (result.turn.status === "interrupted") {
                    process.stdout.write("status> interrupted\n");
                }
            }
        }
        finally {
            terminal.close();
        }
    }
    finally {
        client.close();
    }
}
function buildRunPrompt(prompt, agentProfile) {
    if (!agentProfile) {
        return prompt;
    }
    return `agent:${agentProfile} ${prompt}`;
}
function findLatestDisplayText(items) {
    for (const item of [...items].reverse()) {
        if (item.kind === "message" && item.role === "agent") {
            return unwrapStrictRespondText(item.text);
        }
        if (item.kind === "error") {
            return item.message;
        }
    }
    return undefined;
}
function describeApprovalSubject(approval) {
    if (approval.group === "exec") {
        return `command ${approval.action}`;
    }
    return `${approval.group} ${approval.action}`;
}
function describeApprovalReviewMode(approval) {
    if (approval.reviewMode !== "guardian") {
        return undefined;
    }
    return "Guardian review required due to the current risk classification.";
}
function describeGuardianAssessment(approval) {
    const assessment = approval.guardianAssessment;
    if (!assessment) {
        return undefined;
    }
    const evidence = assessment.evidence.length > 0 ? ` Evidence: ${assessment.evidence.join(" | ")}` : "";
    return `Guardian scored this ${assessment.riskScore}/100 (${assessment.riskLevel}). ${assessment.rationale}${evidence}`;
}
async function promptForApproval(approval) {
    const choices = [
        "[a]llow once",
        ...(approval.availableScopes.includes("session") ? ["[s]ession"] : []),
        ...(approval.availableScopes.includes("thread") ? ["[t]hread"] : []),
        ...(approval.availableScopes.includes("workspace") ? ["[w]orkspace"] : []),
        "[r]eject",
    ];
    const prompt = [
        `Approval required for ${describeApprovalSubject(approval)}.`,
        describeApprovalReviewMode(approval),
        describeGuardianAssessment(approval),
        approval.reason,
        `Choose ${choices.join(", ")}: `,
    ]
        .filter(Boolean)
        .join(" ");
    try {
        const answer = (await promptForLine(prompt, process.stderr)).trim().toLowerCase();
        if ((answer === "t" || answer === "thread") && approval.availableScopes.includes("thread")) {
            return { decision: "allow", scope: "thread" };
        }
        if ((answer === "w" || answer === "workspace") &&
            approval.availableScopes.includes("workspace")) {
            return { decision: "allow", scope: "workspace" };
        }
        if ((answer === "s" || answer === "session") && approval.availableScopes.includes("session")) {
            return { decision: "allow", scope: "session" };
        }
        if (answer === "a" ||
            answer === "allow" ||
            answer === "y" ||
            answer === "yes" ||
            answer === "once") {
            return { decision: "allow", scope: "once" };
        }
    }
    catch {
        return { decision: "reject", scope: "once" };
    }
    return { decision: "reject", scope: "once" };
}
async function renderChatEvent(client, event, terminal) {
    const runtimeEvent = event.event;
    switch (runtimeEvent.type) {
        case "approval.requested": {
            const resolution = await promptForApprovalWithInterface(runtimeEvent.approval, terminal);
            await client.respondToApproval(runtimeEvent.approval.id, resolution.decision, resolution.scope);
            return;
        }
        case "action.required": {
            if (runtimeEvent.kind !== "ask_user") {
                return;
            }
            const answers = await promptForAskUserWithInterface(runtimeEvent, terminal);
            await client.respondToAction(runtimeEvent.actionId, answers);
            return;
        }
        case "turn.item.added": {
            const item = runtimeEvent.item;
            if (item.kind === "reasoning") {
                process.stdout.write(`reasoning> ${item.summary}\n`);
                return;
            }
            if (item.kind === "tool-call") {
                process.stdout.write(`tool-call> ${item.toolName} ${item.input}\n`);
                return;
            }
            if (item.kind === "tool-result") {
                process.stdout.write(`tool-result> ${item.toolName}: ${truncateForTerminal(item.output)}\n`);
                return;
            }
            if (item.kind === "message" && item.role === "agent") {
                process.stdout.write(`assistant> ${item.text}\n`);
                return;
            }
            if (item.kind === "error") {
                process.stdout.write(`error> ${item.message}\n`);
                return;
            }
            if (item.kind === "control") {
                process.stdout.write(`control> ${item.action} ${truncateForTerminal(item.summary)}\n`);
            }
            return;
        }
        case "turn.queued":
            process.stdout.write(`queue> queued ${runtimeEvent.queuedTurn.id}\n`);
            return;
        case "turn.dequeued":
            process.stdout.write(`queue> dequeued ${runtimeEvent.queuedTurn.id}\n`);
            return;
        case "turn.steered":
            process.stdout.write(`steer> ${truncateForTerminal(runtimeEvent.prompt)}\n`);
            return;
        case "turn.queue.drained":
            process.stdout.write(`queue> drained ${runtimeEvent.threadId}\n`);
            return;
        case "workflow.phase.started":
            process.stdout.write(`workflow> ${runtimeEvent.workflowName} ${runtimeEvent.phaseName} started in ${runtimeEvent.childThreadId}\n`);
            return;
        case "workflow.phase.completed":
            process.stdout.write(`workflow> ${runtimeEvent.workflowName} ${runtimeEvent.phaseName} completed: ${truncateForTerminal(runtimeEvent.output)}\n`);
            return;
        case "workflow.phase.failed":
            process.stdout.write(`workflow> ${runtimeEvent.workflowName} ${runtimeEvent.phaseName} failed: ${runtimeEvent.message}\n`);
            return;
        case "child-thread.item.added": {
            const scope = runtimeEvent.relation.kind === "workflow-phase"
                ? `${runtimeEvent.relation.workflowName}/${runtimeEvent.relation.phaseName}`
                : runtimeEvent.relation.kind === "coordinator-worker"
                    ? `${runtimeEvent.relation.workflowName}/${runtimeEvent.relation.workerId}`
                    : `research/${runtimeEvent.relation.subquestionId}`;
            const item = runtimeEvent.item;
            if (item.kind === "reasoning") {
                process.stdout.write(`subagent> [${scope}] reasoning ${item.summary}\n`);
                return;
            }
            if (item.kind === "tool-call") {
                process.stdout.write(`subagent> [${scope}] tool-call ${item.toolName} ${item.input}\n`);
                return;
            }
            if (item.kind === "tool-result") {
                process.stdout.write(`subagent> [${scope}] tool-result ${item.toolName}: ${truncateForTerminal(item.output)}\n`);
                return;
            }
            if (item.kind === "message" && item.role === "agent") {
                process.stdout.write(`subagent> [${scope}] assistant ${truncateForTerminal(item.text)}\n`);
                return;
            }
            if (item.kind === "error") {
                process.stdout.write(`subagent> [${scope}] error ${item.message}\n`);
            }
            return;
        }
        case "thread.compacted":
            process.stdout.write(`compact> ${runtimeEvent.reason} commits=${runtimeEvent.diagnostics.compaction.commitCount} saved=${runtimeEvent.estimatedTokensSaved ?? 0} hit-rate=${runtimeEvent.diagnostics.cache.hitRate}\n`);
            return;
        case "thread.compaction.started":
            process.stdout.write(`compact-start> ${runtimeEvent.reason} estimated-before=${runtimeEvent.estimatedTokensBefore ?? 0}\n`);
            return;
        case "thread.usage.updated":
            process.stdout.write(`usage> ${runtimeEvent.operation} thread=${runtimeEvent.threadId} source=${runtimeEvent.sourceThreadId} total=${runtimeEvent.inclusive.totalTokens} delta=${runtimeEvent.last.totalTokens} reported=${runtimeEvent.reported}\n`);
            return;
        case "thread.forked":
            if (runtimeEvent.turnId) {
                process.stdout.write(`fork> ${runtimeEvent.thread.id}\n`);
            }
            return;
        case "plan.started":
            process.stdout.write(`plan> started ${runtimeEvent.plan.title}\n`);
            return;
        case "plan.updated":
            process.stdout.write(`plan> updated ${runtimeEvent.plan.title} [${runtimeEvent.plan.status}] rev${runtimeEvent.plan.graphRevision}\n`);
            return;
        case "plan.todo.updated":
            process.stdout.write(`plan> todos ${runtimeEvent.plan.todos.length}\n`);
            return;
        case "plan.review_ready":
            process.stdout.write(`plan> review-ready ${runtimeEvent.plan.title}\n`);
            return;
        case "plan.approval.requested":
            process.stdout.write(`plan> approval requested ${runtimeEvent.plan.title}\n`);
            return;
        case "plan.approved":
            process.stdout.write(`plan> approved ${runtimeEvent.plan.title}\n`);
            return;
        case "plan.rejected":
            process.stdout.write(`plan> rejected ${runtimeEvent.plan.title}\n`);
            return;
        case "plan.handoff.ready":
            process.stdout.write(`plan> handoff ready ${runtimeEvent.plan.title}\n`);
            return;
        case "research.started":
            process.stdout.write(`research> started ${runtimeEvent.run.runId}\n`);
            return;
        case "research.subquestion.started":
            process.stdout.write(`research> ${runtimeEvent.subquestion.profileName}/${runtimeEvent.subquestion.subquestionId} started in ${runtimeEvent.subquestion.childThreadId}\n`);
            return;
        case "research.subquestion.completed":
            process.stdout.write(`research> ${runtimeEvent.subquestionId} completed with ${runtimeEvent.evidenceCount} evidence cards\n`);
            return;
        case "research.subquestion.failed":
            process.stdout.write(`research> ${runtimeEvent.subquestionId} failed: ${runtimeEvent.message}\n`);
            return;
        case "research.evidence.added":
            process.stdout.write(`evidence> ${runtimeEvent.evidence.evidenceId}: ${truncateForTerminal(runtimeEvent.evidence.summary)}\n`);
            return;
        case "research.synthesis.started":
            process.stdout.write(`research> synthesis started for ${runtimeEvent.runId}\n`);
            return;
        case "research.audit.completed":
            process.stdout.write(`research> audit completed contradictions=${runtimeEvent.contradictionCount} unsupported=${runtimeEvent.unsupportedClaimCount}\n`);
            return;
        case "research.completed":
            process.stdout.write(`research> completed ${runtimeEvent.runId}\n`);
            return;
        case "research.failed":
            process.stdout.write(`research> failed ${runtimeEvent.runId}: ${runtimeEvent.message}\n`);
            return;
        default:
            return;
    }
}
async function promptForLine(prompt, output = process.stdout) {
    output.write(prompt);
    const lineInterface = createInterface({
        input: process.stdin,
        crlfDelay: Number.POSITIVE_INFINITY,
    });
    try {
        return await new Promise((resolve) => {
            let settled = false;
            const finish = (value) => {
                if (settled) {
                    return;
                }
                settled = true;
                resolve(value);
            };
            lineInterface.once("line", finish);
            lineInterface.once("close", () => {
                finish("");
            });
        });
    }
    finally {
        lineInterface.close();
    }
}
async function promptForApprovalWithInterface(approval, terminal) {
    if (!terminal) {
        return promptForApproval(approval);
    }
    const choices = [
        "[a]llow once",
        ...(approval.availableScopes.includes("session") ? ["[s]ession"] : []),
        ...(approval.availableScopes.includes("thread") ? ["[t]hread"] : []),
        ...(approval.availableScopes.includes("workspace") ? ["[w]orkspace"] : []),
        "[r]eject",
    ];
    const prompt = [
        `Approval required for ${describeApprovalSubject(approval)}.`,
        describeApprovalReviewMode(approval),
        describeGuardianAssessment(approval),
        approval.reason,
        `Choose ${choices.join(", ")}: `,
    ]
        .filter(Boolean)
        .join(" ");
    const answer = ((await terminal.ask(prompt, process.stderr)) ?? "").trim().toLowerCase();
    if ((answer === "t" || answer === "thread") && approval.availableScopes.includes("thread")) {
        return { decision: "allow", scope: "thread" };
    }
    if ((answer === "w" || answer === "workspace") &&
        approval.availableScopes.includes("workspace")) {
        return { decision: "allow", scope: "workspace" };
    }
    if ((answer === "s" || answer === "session") && approval.availableScopes.includes("session")) {
        return { decision: "allow", scope: "session" };
    }
    if (answer === "a" ||
        answer === "allow" ||
        answer === "y" ||
        answer === "yes" ||
        answer === "once") {
        return { decision: "allow", scope: "once" };
    }
    return { decision: "reject", scope: "once" };
}
async function promptForAskUserWithInterface(action, terminal) {
    const answers = {};
    const total = action.questions.length;
    const ask = async (prompt) => {
        const answer = terminal
            ? await terminal.ask(prompt, process.stderr)
            : await promptForLine(prompt, process.stderr);
        return (answer ?? "").trim();
    };
    for (const [index, question] of action.questions.entries()) {
        const header = question.header?.trim() || `Question ${index + 1}`;
        process.stdout.write(`ask-user> ${header}: ${question.question}\n`);
        if (isAskUserChoiceQuestion(question)) {
            for (const [optionIndex, option] of question.options.entries()) {
                const detail = option.description ? ` - ${option.description}` : "";
                process.stdout.write(`ask-user-option> ${optionIndex + 1}. ${option.label}${detail}\n`);
            }
            if (question.allowCustom !== false) {
                process.stdout.write(`ask-user-option> ${question.options.length + 1}. Other - Enter a custom answer\n`);
            }
        }
        else if (question.placeholder?.trim()) {
            process.stdout.write(`ask-user-hint> ${question.placeholder.trim()}\n`);
        }
        const raw = await ask(buildAskUserPromptLabel(question, index, total));
        answers[question.id] = await resolveAskUserAnswer(question, raw, ask);
    }
    return answers;
}
function buildAskUserPromptLabel(question, index, total) {
    const base = total > 1 ? `Answer ${index + 1}/${total}` : "Answer";
    if (!isAskUserInputQuestion(question)) {
        return `${base}: `;
    }
    const placeholder = question.placeholder?.trim();
    return placeholder ? `${base} (${placeholder}): ` : `${base}: `;
}
async function resolveAskUserAnswer(question, raw, ask) {
    if (isAskUserInputQuestion(question)) {
        return raw.trim();
    }
    if (question.multiSelect) {
        const selections = raw
            .split(",")
            .map((part) => resolveAskUserOption(question, part.trim()))
            .filter((part) => Boolean(part));
        const labels = selections.filter((part) => typeof part === "string" && part.length > 0);
        if (selections.some((part) => typeof part !== "string")) {
            const custom = (await ask("Custom answer: ")).trim();
            if (custom) {
                labels.push(custom);
            }
        }
        return labels;
    }
    const selection = resolveAskUserOption(question, raw);
    if (typeof selection === "string") {
        return selection;
    }
    return (await ask("Custom answer: ")).trim();
}
function resolveAskUserOption(question, raw) {
    const normalized = raw.trim();
    if (!normalized) {
        return "";
    }
    const options = question.options;
    const numericIndex = Number(normalized);
    if (Number.isInteger(numericIndex) && numericIndex >= 1 && numericIndex <= options.length) {
        return options[numericIndex - 1]?.label ?? normalized;
    }
    if (question.allowCustom !== false &&
        Number.isInteger(numericIndex) &&
        numericIndex === options.length + 1) {
        return { kind: "other" };
    }
    const exact = options.find((option) => option.label.toLowerCase() === normalized.toLowerCase());
    if (exact?.label) {
        return exact.label;
    }
    if (question.allowCustom !== false && normalized.toLowerCase() === "other") {
        return { kind: "other" };
    }
    return normalized;
}
function isAskUserChoiceQuestion(question) {
    if (question.kind === "choice") {
        return true;
    }
    return "options" in question && Array.isArray(question.options) && question.options.length > 0;
}
function isAskUserInputQuestion(question) {
    return question.kind === "input";
}
function createTerminalPrompter() {
    if (!process.stdin.isTTY) {
        const input = readFileSync(0, "utf8");
        const buffered = input.length === 0 ? [] : input.split(/\r?\n/);
        if (buffered.at(-1) === "") {
            buffered.pop();
        }
        return {
            async ask(prompt, output = process.stderr) {
                output.write(prompt);
                return buffered.shift() ?? null;
            },
            close() { },
        };
    }
    const lineInterface = createInterface({
        input: process.stdin,
        crlfDelay: Number.POSITIVE_INFINITY,
        terminal: false,
    });
    const buffered = [];
    let closed = false;
    let pending;
    lineInterface.on("line", (line) => {
        if (pending) {
            const resolve = pending;
            pending = undefined;
            resolve(line);
            return;
        }
        buffered.push(line);
    });
    lineInterface.on("close", () => {
        closed = true;
        if (pending) {
            const resolve = pending;
            pending = undefined;
            resolve(null);
        }
    });
    return {
        async ask(prompt, output = process.stderr) {
            output.write(prompt);
            if (buffered.length > 0) {
                return buffered.shift() ?? null;
            }
            if (closed) {
                return null;
            }
            return new Promise((resolve) => {
                pending = resolve;
            });
        },
        close() {
            lineInterface.close();
        },
    };
}
function parseRunOptions(args) {
    const options = parseCommonOptions(args);
    const promptParts = [];
    for (let index = 0; index < args.length; index += 1) {
        const arg = args[index];
        const next = args[index + 1];
        if (arg === "--plan") {
            continue;
        }
        if (takesValue(arg) && next) {
            index += 1;
            continue;
        }
        promptParts.push(arg);
    }
    return {
        ...options,
        prompt: promptParts.join(" ").trim() || undefined,
    };
}
function parseChatOptions(args) {
    const options = parseCommonOptions(args);
    let latest = false;
    let altScreen;
    let enableMouse;
    let resumeThreadId;
    let threadMode = options.threadMode;
    for (let index = 0; index < args.length; index += 1) {
        const arg = args[index];
        const value = args[index + 1];
        if (arg === "--latest") {
            latest = true;
            continue;
        }
        if (arg === "--plan") {
            threadMode = "plan";
            continue;
        }
        if (arg === "--no-mouse") {
            enableMouse = false;
            continue;
        }
        if (arg === "--no-alt-screen") {
            altScreen = false;
            continue;
        }
        if (arg === "--resume" && value) {
            resumeThreadId = value;
            index += 1;
        }
    }
    return {
        ...options,
        altScreen,
        enableMouse,
        latest,
        resumeThreadId,
        threadMode,
    };
}
function parseServeOptions(args) {
    const options = parseCommonOptions(args);
    let host;
    let port;
    for (let index = 0; index < args.length; index += 1) {
        const arg = args[index];
        const value = args[index + 1];
        if (arg === "--host" && value) {
            host = value;
            index += 1;
            continue;
        }
        if (arg === "--port" && value) {
            port = Number(value);
            index += 1;
        }
    }
    return {
        approvalTimeoutMs: options.approvalTimeoutMs,
        cwd: options.cwd,
        extensionsRoot: options.extensionsRoot,
        guardian: options.guardian,
        host,
        port,
        providerConfig: options.providerConfig,
        storageRoot: options.storageRoot,
    };
}
function parseCommonOptions(args) {
    const options = {};
    const envProviderConfig = getProviderConfigFromEnv();
    if (envProviderConfig) {
        options.providerConfig = envProviderConfig;
    }
    for (let index = 0; index < args.length; index += 1) {
        const arg = args[index];
        const value = args[index + 1];
        if (!takesValue(arg) || !value) {
            if (arg === "--plan") {
                options.threadMode = "plan";
            }
            continue;
        }
        if (arg === "--storage-root") {
            options.storageRoot = value;
            index += 1;
            continue;
        }
        if (arg === "--extensions-root") {
            options.extensionsRoot = value;
            index += 1;
            continue;
        }
        if (arg === "--cwd") {
            options.cwd = value;
            index += 1;
            continue;
        }
        if (arg === "--agent") {
            options.agentProfile = value;
            index += 1;
            continue;
        }
        if (arg === "--approval-timeout-ms") {
            options.approvalTimeoutMs = Number(value);
            index += 1;
            continue;
        }
        if (arg === "--guardian-enabled") {
            options.guardian = {
                ...options.guardian,
                enabled: value === "1" || value === "true" || value === "yes",
            };
            index += 1;
            continue;
        }
        if (arg === "--guardian-model") {
            options.guardian = {
                ...options.guardian,
                model: value,
            };
            index += 1;
            continue;
        }
        if (arg === "--guardian-threshold") {
            options.guardian = {
                ...options.guardian,
                threshold: Number(value),
            };
            index += 1;
            continue;
        }
        if (arg === "--guardian-timeout-ms") {
            options.guardian = {
                ...options.guardian,
                timeoutMs: Number(value),
            };
            index += 1;
            continue;
        }
        if (arg === "--provider") {
            options.providerConfig = {
                ...options.providerConfig,
                compatibilityMode: options.providerConfig?.compatibilityMode,
                kind: value,
                model: options.providerConfig?.model ?? "",
            };
            index += 1;
            continue;
        }
        if (arg === "--model") {
            options.providerConfig = {
                ...options.providerConfig,
                compatibilityMode: options.providerConfig?.compatibilityMode,
                kind: options.providerConfig?.kind ?? "openai",
                model: value,
            };
            index += 1;
            continue;
        }
        if (arg === "--base-url") {
            options.providerConfig = {
                ...options.providerConfig,
                compatibilityMode: options.providerConfig?.compatibilityMode,
                kind: options.providerConfig?.kind ?? "openai",
                model: options.providerConfig?.model ?? "",
                baseURL: value,
            };
            index += 1;
            continue;
        }
        if (arg === "--compatibility") {
            options.providerConfig = {
                ...options.providerConfig,
                compatibilityMode: value,
                kind: options.providerConfig?.kind ?? "openai",
                model: options.providerConfig?.model ?? "",
            };
            index += 1;
            continue;
        }
        if (arg === "--system-prompt") {
            options.providerConfig = {
                ...options.providerConfig,
                compatibilityMode: options.providerConfig?.compatibilityMode,
                kind: options.providerConfig?.kind ?? "openai",
                model: options.providerConfig?.model ?? "",
                systemPrompt: value,
            };
            index += 1;
        }
    }
    if (options.providerConfig && !options.providerConfig.model) {
        process.stderr.write("A provider model is required when provider configuration is supplied.\n");
        process.exitCode = 1;
        process.exit();
    }
    return options;
}
function takesValue(arg) {
    return (arg === "--storage-root" ||
        arg === "--extensions-root" ||
        arg === "--cwd" ||
        arg === "--agent" ||
        arg === "--provider" ||
        arg === "--model" ||
        arg === "--base-url" ||
        arg === "--compatibility" ||
        arg === "--system-prompt" ||
        arg === "--approval-timeout-ms" ||
        arg === "--guardian-enabled" ||
        arg === "--guardian-model" ||
        arg === "--guardian-threshold" ||
        arg === "--guardian-timeout-ms" ||
        arg === "--resume" ||
        arg === "--host" ||
        arg === "--port");
}
async function resolveInitialChatThread(client, options) {
    if (options.resumeThreadId) {
        return resumeChatThread(client, options.resumeThreadId, options.threadMode);
    }
    if (options.latest) {
        const listed = await client.listThreads({ limit: 1 });
        if (listed.threads[0]) {
            return resumeChatThread(client, listed.threads[0].id, options.threadMode);
        }
    }
    const { thread } = await client.startThread({ mode: options.threadMode });
    return thread;
}
async function resumeChatThread(client, threadId, requestedMode) {
    const detail = await client.getThread(threadId);
    if (detail.thread.status === "archived") {
        await client.unarchiveThread(threadId);
    }
    if (requestedMode && detail.thread.mode !== requestedMode) {
        await client.setThreadMode(threadId, requestedMode);
        await client.resumeThread(threadId);
        return (await client.getThread(threadId)).thread;
    }
    await client.resumeThread(threadId);
    return detail.thread.status === "archived"
        ? (await client.getThread(threadId)).thread
        : detail.thread;
}
async function resolveFallbackChatThread(client, excludedThreadId, mode) {
    const listed = await client.listThreads({ limit: 50 });
    const fallback = listed.threads.find((thread) => thread.id !== excludedThreadId);
    if (fallback) {
        return fallback;
    }
    const { thread } = await client.startThread({ mode });
    return thread;
}
function truncateForTerminal(value) {
    const normalized = value.replace(/\s+/g, " ").trim();
    return normalized.length <= 160 ? normalized : `${normalized.slice(0, 157)}...`;
}
function resolveCliEnvRoot(args) {
    for (let index = 0; index < args.length; index += 1) {
        if (args[index] === "--cwd" && args[index + 1]) {
            return resolve(args[index + 1]);
        }
    }
    return process.cwd();
}
function shouldUseTuiChat() {
    return Boolean(process.stdin.isTTY && process.stdout.isTTY && process.env.BEST_AGENT_DISABLE_TUI_CHAT !== "1");
}
function loadDotEnv(root) {
    const envPath = resolve(root, ".env");
    if (!existsSync(envPath)) {
        return;
    }
    const source = readFileSync(envPath, "utf8");
    for (const line of source.split(/\r?\n/)) {
        const trimmed = line.trim();
        if (!trimmed || trimmed.startsWith("#")) {
            continue;
        }
        const normalized = trimmed.startsWith("export ")
            ? trimmed.slice("export ".length).trim()
            : trimmed;
        const separator = normalized.indexOf("=");
        if (separator <= 0) {
            continue;
        }
        const key = normalized.slice(0, separator).trim();
        if (!key || process.env[key] !== undefined) {
            continue;
        }
        let value = normalized.slice(separator + 1).trim();
        if ((value.startsWith('"') && value.endsWith('"')) ||
            (value.startsWith("'") && value.endsWith("'"))) {
            value = value.slice(1, -1);
        }
        process.env[key] = value;
    }
}
void main();
//# sourceMappingURL=index.js.map