"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("node:fs"));
const path = __importStar(require("node:path"));
const os = __importStar(require("node:os"));
const node_test_1 = require("node:test");
const strict_1 = __importDefault(require("node:assert/strict"));
const platform_1 = require("../platform");
const FAKE = '__aidev_definitely_not_a_real_binary_xyz__';
(0, node_test_1.describe)('commandExists', () => {
    (0, node_test_1.it)('returns true for node (always in PATH when tests run)', () => {
        strict_1.default.equal((0, platform_1.commandExists)('node'), true);
    });
    (0, node_test_1.it)('returns false for a non-existent binary', () => {
        strict_1.default.equal((0, platform_1.commandExists)(FAKE), false);
    });
});
(0, node_test_1.describe)('shouldRetryAgentCliAttempt', () => {
    (0, node_test_1.it)('returns true for unknown option style stderr', () => {
        strict_1.default.equal((0, platform_1.shouldRetryAgentCliAttempt)('error: unknown option --foo', ''), true);
    });
    (0, node_test_1.it)('returns true for Cursor-style invalid model message', () => {
        strict_1.default.equal((0, platform_1.shouldRetryAgentCliAttempt)("There's an issue with the selected model (auto). It may not exist or you may not have access to it.", ''), true);
    });
    (0, node_test_1.it)('returns false for unrelated stderr', () => {
        strict_1.default.equal((0, platform_1.shouldRetryAgentCliAttempt)('build failed: syntax error', ''), false);
    });
});
(0, node_test_1.describe)('findBin', () => {
    (0, node_test_1.it)('returns a non-null path for node', () => {
        const result = (0, platform_1.findBin)('node');
        strict_1.default.notEqual(result, null);
    });
    (0, node_test_1.it)('returned path contains "node"', () => {
        const result = (0, platform_1.findBin)('node');
        strict_1.default.ok(result?.toLowerCase().includes('node'));
    });
    (0, node_test_1.it)('returns null for a non-existent binary', () => {
        strict_1.default.equal((0, platform_1.findBin)(FAKE), null);
    });
});
(0, node_test_1.describe)('spawnCommand', () => {
    (0, node_test_1.it)('runs a command and returns stdout', () => {
        const result = (0, platform_1.spawnCommand)('node', ['--version'], { encoding: 'utf8' });
        strict_1.default.equal(result.status, 0);
        strict_1.default.ok(result.stdout.startsWith('v'));
    });
    (0, node_test_1.it)('returns non-zero status for invalid args', () => {
        const result = (0, platform_1.spawnCommand)('node', ['--invalid-flag-xyz'], { encoding: 'utf8' });
        strict_1.default.notEqual(result.status, 0);
    });
    (0, node_test_1.it)('passes through spawn errors for non-existent commands', () => {
        const result = (0, platform_1.spawnCommand)(FAKE, ['--version'], { encoding: 'utf8' });
        strict_1.default.ok(result.error);
    });
});
// ─── parseCmdShimTarget ──────────────────────────────────────────────────────
(0, node_test_1.describe)('parseCmdShimTarget', () => {
    let tmpDir;
    (0, node_test_1.beforeEach)(() => {
        tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-platform-test-'));
    });
    (0, node_test_1.afterEach)(() => {
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });
    (0, node_test_1.it)('extracts script path from standard npm .cmd shim (%dp0%)', () => {
        // Create the target script
        const nmDir = path.join(tmpDir, 'node_modules', '@anthropic-ai', 'claude-code');
        fs.mkdirSync(nmDir, { recursive: true });
        const scriptPath = path.join(nmDir, 'cli.js');
        fs.writeFileSync(scriptPath, '// cli', 'utf8');
        const relScript = path.relative(tmpDir, scriptPath);
        const cmdContent = [
            '@ECHO off',
            'GOTO start',
            ':find_dp0',
            'SET dp0=%~dp0',
            'EXIT /b',
            ':start',
            'SETLOCAL',
            'CALL :find_dp0',
            `endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%"  "%dp0%\\${relScript}" %*`,
        ].join('\r\n');
        const cmdPath = path.join(tmpDir, 'claude.cmd');
        fs.writeFileSync(cmdPath, cmdContent, 'utf8');
        const result = (0, platform_1.parseCmdShimTarget)(cmdPath);
        strict_1.default.equal(result, scriptPath);
    });
    (0, node_test_1.it)('extracts script path from shim using %~dp0 prefix', () => {
        const nmDir = path.join(tmpDir, 'node_modules', '.bin');
        fs.mkdirSync(nmDir, { recursive: true });
        const scriptPath = path.join(nmDir, 'agent.js');
        fs.writeFileSync(scriptPath, '// agent', 'utf8');
        const relScript = path.relative(tmpDir, scriptPath);
        const cmdContent = `@ECHO off\r\n"%~dp0\\${relScript}" %*\r\n`;
        const cmdPath = path.join(tmpDir, 'agent.cmd');
        fs.writeFileSync(cmdPath, cmdContent, 'utf8');
        const result = (0, platform_1.parseCmdShimTarget)(cmdPath);
        strict_1.default.equal(result, scriptPath);
    });
    (0, node_test_1.it)('returns null when script file does not exist on disk', () => {
        const cmdContent = [
            '@ECHO off',
            'endLocal & "%_prog%"  "%dp0%\\node_modules\\missing\\cli.js" %*',
        ].join('\r\n');
        const cmdPath = path.join(tmpDir, 'missing.cmd');
        fs.writeFileSync(cmdPath, cmdContent, 'utf8');
        const result = (0, platform_1.parseCmdShimTarget)(cmdPath);
        strict_1.default.equal(result, null);
    });
    (0, node_test_1.it)('returns null for non-npm .cmd files without a JS target', () => {
        const cmdContent = '@ECHO off\r\nsome-native.exe %*\r\n';
        const cmdPath = path.join(tmpDir, 'native.cmd');
        fs.writeFileSync(cmdPath, cmdContent, 'utf8');
        const result = (0, platform_1.parseCmdShimTarget)(cmdPath);
        strict_1.default.equal(result, null);
    });
    (0, node_test_1.it)('returns null for non-existent file', () => {
        const result = (0, platform_1.parseCmdShimTarget)(path.join(tmpDir, 'nope.cmd'));
        strict_1.default.equal(result, null);
    });
    (0, node_test_1.it)('extracts .mjs target scripts', () => {
        const nmDir = path.join(tmpDir, 'node_modules', 'pkg');
        fs.mkdirSync(nmDir, { recursive: true });
        const scriptPath = path.join(nmDir, 'cli.mjs');
        fs.writeFileSync(scriptPath, '// mjs', 'utf8');
        const relScript = path.relative(tmpDir, scriptPath);
        const cmdContent = `@ECHO off\r\n"%~dp0\\${relScript}" %*\r\n`;
        const cmdPath = path.join(tmpDir, 'pkg.cmd');
        fs.writeFileSync(cmdPath, cmdContent, 'utf8');
        const result = (0, platform_1.parseCmdShimTarget)(cmdPath);
        strict_1.default.equal(result, scriptPath);
    });
});
// ─── resolveWindowsCmd ────────────────────────────────────────────────────────
(0, node_test_1.describe)('resolveWindowsCmd', () => {
    let origComSpec;
    let tmpDir;
    (0, node_test_1.beforeEach)(() => {
        origComSpec = process.env.ComSpec;
        tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-resolve-test-'));
    });
    (0, node_test_1.afterEach)(() => {
        if (origComSpec !== undefined)
            process.env.ComSpec = origComSpec;
        else
            delete process.env.ComSpec;
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });
    (0, node_test_1.it)('spawns node.exe directly when .cmd shim has a parseable JS target', () => {
        // Create a realistic npm shim with a real JS target
        const nmDir = path.join(tmpDir, 'node_modules', '@anthropic-ai', 'claude-code');
        fs.mkdirSync(nmDir, { recursive: true });
        const scriptPath = path.join(nmDir, 'cli.js');
        fs.writeFileSync(scriptPath, '// cli', 'utf8');
        const relScript = path.relative(tmpDir, scriptPath);
        const cmdContent = `@ECHO off\r\n"%~dp0\\${relScript}" %*\r\n`;
        const cmdPath = path.join(tmpDir, 'claude.cmd');
        fs.writeFileSync(cmdPath, cmdContent, 'utf8');
        const prompt = 'Implement feature: use & and | operators in <template>';
        const result = (0, platform_1.resolveWindowsCmd)(cmdPath, ['-p', prompt, '--dangerously-skip-permissions']);
        strict_1.default.notEqual(result, null);
        // Should use node.exe, NOT cmd.exe
        strict_1.default.ok(result.bin.toLowerCase().includes('node'), `Expected node.exe but got: ${result.bin}`);
        // First arg is the script, then the original args
        strict_1.default.equal(result.args[0], scriptPath);
        strict_1.default.equal(result.args[1], '-p');
        strict_1.default.equal(result.args[2], prompt);
    });
    (0, node_test_1.it)('falls back to cmd.exe /c for non-parseable .cmd files', () => {
        const cmdContent = '@ECHO off\r\nsome-native.exe %*\r\n';
        const cmdPath = path.join(tmpDir, 'native.cmd');
        fs.writeFileSync(cmdPath, cmdContent, 'utf8');
        const result = (0, platform_1.resolveWindowsCmd)(cmdPath, ['arg1']);
        strict_1.default.notEqual(result, null);
        strict_1.default.deepEqual(result.args, ['/c', cmdPath, 'arg1']);
    });
    (0, node_test_1.it)('falls back to cmd.exe /c for .bat files', () => {
        const cmdPath = path.join(tmpDir, 'run.bat');
        fs.writeFileSync(cmdPath, '@ECHO off\r\nrun.exe %*\r\n', 'utf8');
        const result = (0, platform_1.resolveWindowsCmd)(cmdPath, ['arg1', 'arg2']);
        strict_1.default.notEqual(result, null);
        strict_1.default.deepEqual(result.args, ['/c', cmdPath, 'arg1', 'arg2']);
    });
    (0, node_test_1.it)('returns null for .exe files', () => {
        strict_1.default.equal((0, platform_1.resolveWindowsCmd)('C:\\node\\node.exe', ['--version']), null);
    });
    (0, node_test_1.it)('returns null for null path', () => {
        strict_1.default.equal((0, platform_1.resolveWindowsCmd)(null, ['--version']), null);
    });
    (0, node_test_1.it)('returns null for paths without extension', () => {
        strict_1.default.equal((0, platform_1.resolveWindowsCmd)('/usr/local/bin/claude', ['-p', 'test']), null);
    });
    (0, node_test_1.it)('uses ComSpec env var for fallback when set', () => {
        process.env.ComSpec = 'C:\\custom\\cmd.exe';
        // Non-parseable .cmd → falls back to cmd.exe
        const cmdPath = path.join(tmpDir, 'tool.cmd');
        fs.writeFileSync(cmdPath, '@ECHO off\r\ntool.exe %*\r\n', 'utf8');
        const result = (0, platform_1.resolveWindowsCmd)(cmdPath, []);
        strict_1.default.equal(result.bin, 'C:\\custom\\cmd.exe');
    });
    (0, node_test_1.it)('defaults to cmd.exe when ComSpec is not set (fallback path)', () => {
        delete process.env.ComSpec;
        const cmdPath = path.join(tmpDir, 'tool.cmd');
        fs.writeFileSync(cmdPath, '@ECHO off\r\ntool.exe %*\r\n', 'utf8');
        const result = (0, platform_1.resolveWindowsCmd)(cmdPath, []);
        strict_1.default.equal(result.bin, 'cmd.exe');
    });
    (0, node_test_1.it)('preserves argument order including prompt with special chars', () => {
        const nmDir = path.join(tmpDir, 'node_modules', 'cli');
        fs.mkdirSync(nmDir, { recursive: true });
        const scriptPath = path.join(nmDir, 'index.js');
        fs.writeFileSync(scriptPath, '// index', 'utf8');
        const relScript = path.relative(tmpDir, scriptPath);
        const cmdContent = `@ECHO off\r\n"%~dp0\\${relScript}" %*\r\n`;
        const cmdPath = path.join(tmpDir, 'cli.cmd');
        fs.writeFileSync(cmdPath, cmdContent, 'utf8');
        const prompt = 'Fix the bug: if (a && b) { return c | d; }';
        const result = (0, platform_1.resolveWindowsCmd)(cmdPath, ['-p', prompt, '--flag']);
        strict_1.default.deepEqual(result.args, [scriptPath, '-p', prompt, '--flag']);
    });
    (0, node_test_1.it)('handles empty args array', () => {
        const nmDir = path.join(tmpDir, 'node_modules', 'cli');
        fs.mkdirSync(nmDir, { recursive: true });
        const scriptPath = path.join(nmDir, 'index.js');
        fs.writeFileSync(scriptPath, '// index', 'utf8');
        const relScript = path.relative(tmpDir, scriptPath);
        const cmdContent = `@ECHO off\r\n"%~dp0\\${relScript}" %*\r\n`;
        const cmdPath = path.join(tmpDir, 'cli.cmd');
        fs.writeFileSync(cmdPath, cmdContent, 'utf8');
        const result = (0, platform_1.resolveWindowsCmd)(cmdPath, []);
        strict_1.default.deepEqual(result.args, [scriptPath]);
    });
});
// ─── Windows integration: spawnCommand through .cmd shim ──────────────────────
(0, node_test_1.describe)('spawnCommand via .cmd shim (Windows integration)', { skip: !platform_1.isWindows }, () => {
    let tmpDir;
    (0, node_test_1.beforeEach)(() => {
        tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-spawn-shim-'));
    });
    (0, node_test_1.afterEach)(() => {
        fs.rmSync(tmpDir, { recursive: true, force: true });
    });
    /**
     * Creates a .cmd shim that wraps a tiny Node.js script, mimicking how
     * npm-installed CLIs work on Windows.
     */
    function createShimmedScript(scriptBody) {
        const nmDir = path.join(tmpDir, 'node_modules', 'test-cli');
        fs.mkdirSync(nmDir, { recursive: true });
        const scriptPath = path.join(nmDir, 'cli.js');
        fs.writeFileSync(scriptPath, scriptBody, 'utf8');
        const relScript = path.relative(tmpDir, scriptPath);
        const cmdContent = [
            '@ECHO off',
            `"${process.execPath}"  "%~dp0\\${relScript}" %*`,
        ].join('\r\n');
        const cmdPath = path.join(tmpDir, 'test-cli.cmd');
        fs.writeFileSync(cmdPath, cmdContent, 'utf8');
        return cmdPath;
    }
    (0, node_test_1.it)('passes arguments with shell metacharacters intact', () => {
        // Script echoes its argv as JSON
        const cmdPath = createShimmedScript('process.stdout.write(JSON.stringify(process.argv.slice(2)));');
        const prompt = 'if (a && b) { return c | d; } // <check> "quoted" %var%';
        const result = (0, platform_1.spawnCommand)(cmdPath, ['-p', prompt, '--flag'], { encoding: 'utf8' });
        strict_1.default.equal(result.status, 0, `stderr: ${result.stderr}`);
        const argv = JSON.parse(result.stdout);
        strict_1.default.deepEqual(argv, ['-p', prompt, '--flag']);
    });
    (0, node_test_1.it)('forwards stdin to the child process', () => {
        // Script reads stdin and echoes it back
        const cmdPath = createShimmedScript(`
      let data = '';
      process.stdin.setEncoding('utf8');
      process.stdin.on('data', (chunk) => { data += chunk; });
      process.stdin.on('end', () => { process.stdout.write(data); });
    `);
        const stdinContent = 'Implement: use & and | operators\nLine 2: <html>';
        const result = (0, platform_1.spawnCommand)(cmdPath, [], { encoding: 'utf8', input: stdinContent });
        strict_1.default.equal(result.status, 0, `stderr: ${result.stderr}`);
        strict_1.default.equal(result.stdout, stdinContent);
    });
    (0, node_test_1.it)('handles very long prompts (>8KB, beyond cmd.exe limit)', () => {
        const cmdPath = createShimmedScript('process.stdout.write(String(process.argv[2].length));');
        // 10KB prompt — exceeds cmd.exe's ~8191 char command line limit
        const longPrompt = 'A'.repeat(10000);
        const result = (0, platform_1.spawnCommand)(cmdPath, [longPrompt], { encoding: 'utf8' });
        strict_1.default.equal(result.status, 0, `stderr: ${result.stderr}`);
        strict_1.default.equal(result.stdout.trim(), '10000');
    });
});
//# sourceMappingURL=platform.test.js.map