"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 node_test_1 = require("node:test");
const strict_1 = __importDefault(require("node:assert/strict"));
const fs = __importStar(require("node:fs"));
const os = __importStar(require("node:os"));
const path = __importStar(require("node:path"));
const logger_1 = require("../logger");
const permissions_1 = require("../permissions");
// ─── permissionCovers ─────────────────────────────────────────────────────
(0, node_test_1.describe)('permissionCovers', () => {
    (0, node_test_1.it)('exact match returns true', () => {
        strict_1.default.equal((0, permissions_1.permissionCovers)('Bash(git:*)', 'Bash(git:*)'), true);
    });
    (0, node_test_1.it)('broader command covers narrower one', () => {
        strict_1.default.equal((0, permissions_1.permissionCovers)('Bash(npm:*)', 'Bash(npm install:*)'), true);
        strict_1.default.equal((0, permissions_1.permissionCovers)('Bash(npm:*)', 'Bash(npm run:*)'), true);
        strict_1.default.equal((0, permissions_1.permissionCovers)('Bash(npm:*)', 'Bash(npm test:*)'), true);
    });
    (0, node_test_1.it)('narrower command does not cover broader one', () => {
        strict_1.default.equal((0, permissions_1.permissionCovers)('Bash(npm install:*)', 'Bash(npm:*)'), false);
    });
    (0, node_test_1.it)('wildcard * covers everything', () => {
        strict_1.default.equal((0, permissions_1.permissionCovers)('Bash(*)', 'Bash(git:*)'), true);
        strict_1.default.equal((0, permissions_1.permissionCovers)('Bash(*)', 'Bash(npm:*)'), true);
    });
    (0, node_test_1.it)('different tools do not cover each other', () => {
        strict_1.default.equal((0, permissions_1.permissionCovers)('Read', 'Write'), false);
        strict_1.default.equal((0, permissions_1.permissionCovers)('Bash(git:*)', 'Edit'), false);
    });
    (0, node_test_1.it)('different tool types return false', () => {
        strict_1.default.equal((0, permissions_1.permissionCovers)('Bash(git:*)', 'Bash(npm:*)'), false);
    });
    (0, node_test_1.it)('similar prefix without word boundary returns false', () => {
        strict_1.default.equal((0, permissions_1.permissionCovers)('Bash(npm:*)', 'Bash(npx:*)'), false);
    });
    (0, node_test_1.it)('simple tool names match exactly', () => {
        strict_1.default.equal((0, permissions_1.permissionCovers)('Read', 'Read'), true);
        strict_1.default.equal((0, permissions_1.permissionCovers)('Write', 'Write'), true);
    });
});
// ─── getMissingPermissions ────────────────────────────────────────────────
(0, node_test_1.describe)('getMissingPermissions', () => {
    (0, node_test_1.it)('returns all when nothing is allowed', () => {
        const required = ['Bash(git:*)', 'Bash(npm:*)'];
        const missing = (0, permissions_1.getMissingPermissions)(required, []);
        strict_1.default.deepEqual(missing, required);
    });
    (0, node_test_1.it)('returns empty when all are covered', () => {
        const required = ['Bash(git:*)', 'Bash(npm:*)'];
        const missing = (0, permissions_1.getMissingPermissions)(required, ['Bash(git:*)', 'Bash(npm:*)']);
        strict_1.default.deepEqual(missing, []);
    });
    (0, node_test_1.it)('returns only the missing ones', () => {
        const required = ['Bash(git:*)', 'Bash(npm:*)', 'Bash(node:*)'];
        const missing = (0, permissions_1.getMissingPermissions)(required, ['Bash(git:*)', 'Bash(node:*)']);
        strict_1.default.deepEqual(missing, ['Bash(npm:*)']);
    });
    (0, node_test_1.it)('recognises broader existing permissions', () => {
        const required = ['Bash(npm install:*)', 'Bash(npm run:*)'];
        const missing = (0, permissions_1.getMissingPermissions)(required, ['Bash(npm:*)']);
        strict_1.default.deepEqual(missing, []);
    });
    (0, node_test_1.it)('does not accept narrower existing as coverage for broader required', () => {
        const required = ['Bash(npm:*)'];
        const missing = (0, permissions_1.getMissingPermissions)(required, ['Bash(npm install:*)', 'Bash(npm run:*)']);
        strict_1.default.deepEqual(missing, ['Bash(npm:*)']);
    });
});
// ─── readClaudeSettings ──────────────────────────────────────────────────
function withTmpDir(fn) {
    const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'aidev-perm-test-'));
    try {
        fn(dir);
    }
    finally {
        fs.rmSync(dir, { recursive: true, force: true });
    }
}
// ─── validateAgentPermissions: anthropic-sdk ─────────────────────────────
function spyLogger() {
    return {
        info: node_test_1.mock.method(logger_1.logger, 'info', () => { }),
        warn: node_test_1.mock.method(logger_1.logger, 'warn', () => { }),
    };
}
// readline is only used by the Claude flow; anthropic-sdk does not consult it.
const stubRl = {};
(0, node_test_1.describe)('validateAgentPermissions (anthropic-sdk)', () => {
    const savedKey = process.env.ANTHROPIC_API_KEY;
    (0, node_test_1.beforeEach)(() => node_test_1.mock.restoreAll());
    (0, node_test_1.afterEach)(() => {
        node_test_1.mock.restoreAll();
        if (savedKey === undefined)
            delete process.env.ANTHROPIC_API_KEY;
        else
            process.env.ANTHROPIC_API_KEY = savedKey;
    });
    (0, node_test_1.it)('warns when no ANTHROPIC_API_KEY is configured', async () => {
        delete process.env.ANTHROPIC_API_KEY;
        const spies = spyLogger();
        await (0, permissions_1.validateAgentPermissions)(['anthropic-sdk'], stubRl);
        const warnings = spies.warn.mock.calls.map((c) => c.arguments[0]);
        strict_1.default.ok(warnings.some((m) => m?.includes('ANTHROPIC_API_KEY')), `expected an ANTHROPIC_API_KEY warning, got: ${warnings.join(' | ')}`);
    });
    (0, node_test_1.it)('logs success info with the token count when SDK and key are present', async () => {
        process.env.ANTHROPIC_API_KEY = 'sk-1,sk-2,sk-3';
        const spies = spyLogger();
        await (0, permissions_1.validateAgentPermissions)(['anthropic-sdk'], stubRl);
        const infos = spies.info.mock.calls.map((c) => c.arguments[0]);
        const warnings = spies.warn.mock.calls.map((c) => c.arguments[0]);
        // Should not warn about missing key
        strict_1.default.ok(!warnings.some((m) => m?.includes('no ANTHROPIC_API_KEY')));
        // Should report token count (3 keys)
        strict_1.default.ok(infos.some((m) => m?.includes('3 API keys')), `expected info mentioning 3 API keys, got: ${infos.join(' | ')}`);
    });
    (0, node_test_1.it)('uses singular "key" wording when exactly one token is configured', async () => {
        process.env.ANTHROPIC_API_KEY = 'sk-only';
        const spies = spyLogger();
        await (0, permissions_1.validateAgentPermissions)(['anthropic-sdk'], stubRl);
        const infos = spies.info.mock.calls.map((c) => c.arguments[0]);
        strict_1.default.ok(infos.some((m) => m?.includes('1 API key') && !m.includes('1 API keys')), `expected singular "1 API key", got: ${infos.join(' | ')}`);
    });
});
(0, node_test_1.describe)('readClaudeSettings', () => {
    (0, node_test_1.it)('returns empty when no settings files exist', () => {
        withTmpDir((dir) => {
            const settings = (0, permissions_1.readClaudeSettings)(dir);
            strict_1.default.deepEqual(settings, {});
        });
    });
    (0, node_test_1.it)('reads from .claude/settings.local.json', () => {
        withTmpDir((dir) => {
            const claudeDir = path.join(dir, '.claude');
            fs.mkdirSync(claudeDir);
            fs.writeFileSync(path.join(claudeDir, 'settings.local.json'), JSON.stringify({ permissions: { allow: ['Bash(git:*)'] } }), 'utf8');
            const settings = (0, permissions_1.readClaudeSettings)(dir);
            strict_1.default.deepEqual(settings.permissions?.allow, ['Bash(git:*)']);
        });
    });
    (0, node_test_1.it)('merges project and local settings', () => {
        withTmpDir((dir) => {
            const claudeDir = path.join(dir, '.claude');
            fs.mkdirSync(claudeDir);
            fs.writeFileSync(path.join(claudeDir, 'settings.json'), JSON.stringify({ permissions: { allow: ['Bash(git:*)'] } }), 'utf8');
            fs.writeFileSync(path.join(claudeDir, 'settings.local.json'), JSON.stringify({ permissions: { allow: ['Bash(npm:*)'] } }), 'utf8');
            const settings = (0, permissions_1.readClaudeSettings)(dir);
            strict_1.default.deepEqual(settings.permissions?.allow, ['Bash(git:*)', 'Bash(npm:*)']);
        });
    });
    (0, node_test_1.it)('handles malformed JSON gracefully', () => {
        withTmpDir((dir) => {
            const claudeDir = path.join(dir, '.claude');
            fs.mkdirSync(claudeDir);
            fs.writeFileSync(path.join(claudeDir, 'settings.local.json'), '{bad json', 'utf8');
            const settings = (0, permissions_1.readClaudeSettings)(dir);
            strict_1.default.deepEqual(settings, {});
        });
    });
});
//# sourceMappingURL=permissions.test.js.map