#!/usr/bin/env node
import { jsx as _jsx } from "react/jsx-runtime";
import { render } from 'ink';
import { existsSync, mkdirSync } from 'node:fs';
import { createRequire } from 'node:module';
import { resolve } from 'node:path';
const require = createRequire(import.meta.url);
const pkg = (() => {
    try {
        return require('../package.json');
    }
    catch {
        return {
            version: typeof __GREEN_BUILD_VERSION__ === 'string'
                ? __GREEN_BUILD_VERSION__
                : '0.0.0',
        };
    }
})();
import { extractCwdArg } from './bootstrap/cwdArg.js';
import { initWorkingDir, getWorkingDir } from './bootstrap/workingDir.js';
import { applyToolKeysToEnv, loadProviderLayered } from './config.js';
import { clearContext, loadContext } from './context/persistContext.js';
import { migrateLegacyContext } from './context/sessionPath.js';
import { buildFullSystemPrompt } from './prompts/system.js';
import { ALL_TOOLS } from './tools/index.js';
import { Root } from './ui/Root.js';
import { runPrintMode } from './cli/print.js';
import { runStreamJsonMode } from './cli/streamJson.js';
import { extractFlagValue } from './cli/args.js';
// re-export：对外保持「main.tsx 提供 extractFlagValue」的语义；实现住在 cli/args.ts，
// 这样单测可零副作用 import（main.tsx 顶层 main() 自调用会启动整个 app，不可被测试 import）。
export { extractFlagValue };
async function main() {
    // ★ -d/--cwd：在锁定工作目录之前先建目录 + chdir，让后续逻辑全在 -d 下运行
    //   不存在则自动 mkdir -p；后续 initWorkingDir() 自然拿到新 cwd
    const args = process.argv.slice(2);
    const dirArg = extractCwdArg(args);
    if (dirArg) {
        const abs = resolve(dirArg);
        if (!existsSync(abs)) {
            mkdirSync(abs, { recursive: true });
        }
        process.chdir(abs);
    }
    // ★ 必须在所有其他逻辑之前——锁定工作目录，并迁移旧版 last-context.json
    initWorkingDir();
    await migrateLegacyContext(getWorkingDir());
    // ★ 把 saved config 里的工具 key（如 TAVILY_API_KEY）注入 process.env。
    //   npm 全局安装跑 `node dist/main.js` 不会自动加载 .env，靠这一步把向导
    //   收集到的 key 写回 env，否则 WebSearch 等工具 process.env.* 读不到。
    await applyToolKeysToEnv();
    // --help 优先显示
    if (args.includes('-h') || args.includes('--help')) {
        printHelp();
        return;
    }
    // --version: 零依赖快速返回（对齐 kakadeai fast-path 设计）
    if (args.includes('--version') || args.includes('-V')) {
        console.log(`minimal-agent v${pkg.version}`);
        return;
    }
    // --clear：清空当前工作目录的会话（归档 + 清空）后退出。供 webchat 的 /new 调用。
    //   无需 provider；上面 -d/--cwd 已 chdir + initWorkingDir，clearContext() 作用于该目录。
    if (args.includes('--clear')) {
        await clearContext();
        return;
    }
    const isPrintMode = args.includes('-p') || args.includes('--print');
    if (isPrintMode) {
        // 先把输出格式解析出来——provider 缺失分支也要按 json 契约给信号。
        // 只接受 'text' | 'json'，其它值（含拼错）一律回落 'text'（向后兼容）。
        const rawFormat = extractFlagValue(args, ['--output-format']);
        // text（默认，逐字节向后兼容）/ json（一行结局契约）/ stream-json（逐行 LoopEvent，webchat broker 用）
        const outputFormat = rawFormat === 'json'
            ? 'json'
            : rawFormat === 'stream-json'
                ? 'stream-json'
                : 'text';
        // --max-turns：parseInt，非法（NaN）→ undefined（走 loop 默认 50）
        const rawMaxTurns = extractFlagValue(args, ['--max-turns']);
        const parsedMaxTurns = rawMaxTurns !== undefined ? Number.parseInt(rawMaxTurns, 10) : Number.NaN;
        const maxTurns = Number.isNaN(parsedMaxTurns) ? undefined : parsedMaxTurns;
        // CLI 非交互模式：先 env，再 ~/.minimal-agent/config.json fallback；都没就退出
        // （宿主 spawn 子进程时通常没 export env，靠 TUI 向导写出的 config.json 持久化）
        const provider = await loadProviderLayered();
        if (!provider) {
            // json 模式：先给宿主一行结构化信号（stop_reason='config_error'），再退出。
            // 人类可读的中文提示仍走 stderr（json 契约只占 stdout 那一行）。
            if (outputFormat === 'json') {
                console.log(JSON.stringify({
                    ok: false,
                    result: '',
                    is_error: true,
                    stop_reason: 'config_error',
                    num_turns: 0,
                    error: 'provider config not found',
                }));
            }
            else if (outputFormat === 'stream-json') {
                // stream-json：吐一行 error 事件（webchat 前端识别为致命错误）
                console.log(JSON.stringify({ type: 'error', error: 'provider config not found', code: 'llm_error' }));
            }
            process.stderr.write(`\n未找到 provider 配置。\n\n` +
                `请二选一：\n` +
                `  1. 设置环境变量 MINIMAL_AGENT_BASE_URL / MINIMAL_AGENT_API_KEY / MINIMAL_AGENT_MODEL\n` +
                `  2. 先直接运行 \`minimal-agent\`（TUI）完成首次配置向导；向导会写出 ~/.minimal-agent/config.json，之后 -p 模式自动复用\n\n`);
            process.exit(1);
        }
        const initialHistory = await buildInitialHistory();
        const verbose = args.includes('--verbose') || args.includes('-v');
        // stream-json 走独立流式模式（webchat broker / 网关用）；text/json 仍走原 runPrintMode（契约不变）。
        if (outputFormat === 'stream-json') {
            await runStreamJsonMode(provider, args, initialHistory, {
                maxTurns,
                compact: args.includes('--compact'),
            });
            return;
        }
        await runPrintMode(provider, args, initialHistory, { verbose, outputFormat, maxTurns });
        return;
    }
    // TUI 交互模式：env 不全则 fallback 到 ~/.minimal-agent/config.json；
    // 都没有则 Root 渲染配置向导。
    const initialProvider = await loadProviderLayered();
    const { waitUntilExit } = render(_jsx(Root, { initialProvider: initialProvider }));
    await waitUntilExit();
}
/**
 * 启动时构造 history：用当前 cwd / 工具的最新 system prompt，
 * 后面接上 last-context.json 里上次保存的对话（如果有）。
 *
 * 总是用 fresh system prompt（即便 last-context.json 里也存了一份），
 * 这样换 cwd 或工具后也不会沿用错的环境上下文。
 */
async function buildInitialHistory() {
    const content = await buildFullSystemPrompt(getWorkingDir(), ALL_TOOLS);
    const fresh = { role: 'system', content };
    const persisted = await loadContext();
    if (!persisted || persisted.length === 0)
        return [fresh];
    const rest = persisted[0]?.role === 'system' ? persisted.slice(1) : persisted;
    return [fresh, ...rest];
}
function printHelp() {
    console.log(`
minimal-agent - 轻量级 AI 编程助手

用法:
  minimal-agent [选项] [提示...]
  echo "提示" | minimal-agent [选项]

选项:
  -p, --print        非交互模式，直接执行单次问答
  -v, --verbose      显示详细输出（工具调用、压缩信息）
  -d, --cwd <dir>    指定工作目录（不存在自动创建）；启动时 chdir 到这里，
                     上下文文件、工具相对路径、.env 加载都以此为基准
  --output-format <fmt>  text（默认）= 纯文本答案；json = 一行结局契约
                         （ok / result / stop_reason / num_turns / error）；
                         stream-json = 逐行 LoopEvent（webchat / 网关 broker 用）
  --max-turns <n>    最大工具循环轮数（防失控；缺省 50）
  --clear            清空当前工作目录的会话（归档 + 清空）后退出
  --compact          与 -p --output-format stream-json 连用：压缩当前会话
  -h, --help         显示帮助信息

会话记忆:
  按当前工作目录隔离，自动加载 / 保存到
  ~/.minimal-agent/sessions/<目录哈希>.json
  TUI 与 -p 共享同一目录的上下文；TUI 中输入 /new 仅清当前目录的会话

示例:
  minimal-agent -p "帮我写一个 hello world"
  echo "解释代码" | minimal-agent -p
  minimal-agent -p --verbose "运行测试并报告结果"
  minimal-agent -p "处理资料" -d /tmp/job-123        # 工作目录隔离
  minimal-agent -p --output-format json "做点事"     # 宿主程序 spawn：一行 JSON 结局
  `);
}
main().catch((e) => {
    process.stderr.write(`\n未捕获异常：${e.message}\n${e.stack ?? ''}\n`);
    process.exit(1);
});
