"use strict";
// Done-State Verifier — validates that work products meet their completion criteria.
//
// For code: runs typecheck, lint, tests (if available).
// For services: checks state exists, commands work, schedule exists, promise recorded.
// For general tasks: checks that outputs match the request intent.
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;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyCode = verifyCode;
exports.verifyService = verifyService;
exports.verifyPromiseFulfillability = verifyPromiseFulfillability;
const path = __importStar(require("path"));
const fs = __importStar(require("fs/promises"));
const child_process_1 = require("child_process");
const util_1 = require("util");
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
async function runCommand(cwd, cmd, args, timeout = 60_000) {
    const start = Date.now();
    try {
        const { stdout, stderr } = await execFileAsync(cmd, args, { cwd, timeout, windowsHide: true });
        return { ok: true, output: (stdout + '\n' + stderr).trim(), duration_ms: Date.now() - start };
    }
    catch (err) {
        const e = err;
        return { ok: false, output: (e.stdout ?? '') + '\n' + (e.stderr ?? e.message ?? ''), duration_ms: Date.now() - start };
    }
}
async function verifyCode(options) {
    const { projectDir, quick = false, timeout = 60_000 } = options;
    const checks = [];
    // TypeScript check
    const tsconfigExists = await fileExists(path.join(projectDir, 'tsconfig.json'));
    if (tsconfigExists) {
        const tsc = await runCommand(projectDir, 'npx', ['tsc', '--noEmit', '--pretty'], timeout);
        checks.push({ name: 'typecheck', domain: 'code', status: tsc.ok ? 'pass' : 'fail', detail: tsc.ok ? undefined : tsc.output.slice(0, 500), duration_ms: tsc.duration_ms });
    }
    else {
        checks.push({ name: 'typecheck', domain: 'code', status: 'skip', detail: 'No tsconfig.json found' });
    }
    // Lint check (eslint)
    if (!quick) {
        const eslintConfig = await hasAnyFile(projectDir, ['.eslintrc', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yml', 'eslint.config.js', 'eslint.config.mjs']);
        if (eslintConfig) {
            const lint = await runCommand(projectDir, 'npx', ['eslint', '.', '--max-warnings=0'], timeout);
            checks.push({ name: 'lint', domain: 'code', status: lint.ok ? 'pass' : 'fail', detail: lint.ok ? undefined : lint.output.slice(0, 500), duration_ms: lint.duration_ms });
        }
        else {
            checks.push({ name: 'lint', domain: 'code', status: 'skip', detail: 'No ESLint config found' });
        }
    }
    // Test check
    if (!quick) {
        const packageJson = await readPackageJson(projectDir);
        if (packageJson?.scripts?.test) {
            const test = await runCommand(projectDir, 'npm', ['test', '--', '--passWithNoTests'], timeout * 2);
            checks.push({ name: 'tests', domain: 'code', status: test.ok ? 'pass' : 'fail', detail: test.ok ? undefined : test.output.slice(0, 500), duration_ms: test.duration_ms });
        }
        else {
            checks.push({ name: 'tests', domain: 'code', status: 'skip', detail: 'No test script in package.json' });
        }
    }
    return {
        domain: 'code',
        overall: deriveOverall(checks),
        checks,
        timestamp: new Date().toISOString(),
    };
}
// ─── Service verification ───────────────────────────────────────────
async function verifyService(projectDir, serviceId) {
    const checks = [];
    const serviceDir = path.join(projectDir, '.harness', 'services', serviceId);
    // service.json exists and is valid
    const serviceOk = await isValidJson(path.join(serviceDir, 'service.json'));
    checks.push({ name: 'service_definition', domain: 'service', status: serviceOk ? 'pass' : 'fail', detail: serviceOk ? undefined : 'service.json missing or invalid' });
    // state.json exists and is valid
    const stateOk = await isValidJson(path.join(serviceDir, 'state.json'));
    checks.push({ name: 'state_exists', domain: 'service', status: stateOk ? 'pass' : 'fail', detail: stateOk ? undefined : 'state.json missing or invalid' });
    // lifecycle.json exists
    const lifecycleOk = await isValidJson(path.join(serviceDir, 'lifecycle.json'));
    checks.push({ name: 'lifecycle_tracked', domain: 'service', status: lifecycleOk ? 'pass' : 'warn', detail: lifecycleOk ? undefined : 'No lifecycle tracking (optional)' });
    // Has supported commands
    if (serviceOk) {
        try {
            const raw = await fs.readFile(path.join(serviceDir, 'service.json'), 'utf-8');
            const def = JSON.parse(raw);
            const hasCmds = Array.isArray(def.supported_commands) && def.supported_commands.length > 0;
            checks.push({ name: 'commands_defined', domain: 'service', status: hasCmds ? 'pass' : 'warn', detail: hasCmds ? `${def.supported_commands.length} commands` : 'No commands defined' });
            const hasSchedule = Array.isArray(def.schedules) && def.schedules.length > 0;
            checks.push({ name: 'schedule_defined', domain: 'service', status: hasSchedule ? 'pass' : 'warn', detail: hasSchedule ? undefined : 'No schedule defined' });
        }
        catch {
            checks.push({ name: 'commands_defined', domain: 'service', status: 'skip' });
        }
    }
    return {
        domain: 'service',
        overall: deriveOverall(checks),
        checks,
        timestamp: new Date().toISOString(),
    };
}
function verifyPromiseFulfillability(input) {
    const checks = [];
    // Can actually schedule if time-based
    const isTimeBased = /remind|daily|weekly|every|check|monitor|recurring/i.test(input.commitment);
    if (isTimeBased) {
        checks.push({ name: 'schedule_backing', domain: 'promise', status: input.schedule_exists ? 'pass' : 'fail', detail: input.schedule_exists ? undefined : 'Time-based promise has no backing schedule' });
        checks.push({ name: 'notification_path', domain: 'promise', status: input.notification_path_available ? 'pass' : 'warn', detail: input.notification_path_available ? undefined : 'No notification channel — will use service inbox fallback' });
    }
    // Capability check
    if (input.capability_required) {
        checks.push({ name: 'capability_available', domain: 'promise', status: 'warn', detail: `Requires capability: ${input.capability_required}` });
    }
    return {
        domain: 'promise',
        overall: deriveOverall(checks),
        checks,
        timestamp: new Date().toISOString(),
    };
}
// ─── Helpers ────────────────────────────────────────────────────────
function deriveOverall(checks) {
    if (checks.some((c) => c.status === 'fail'))
        return 'fail';
    if (checks.some((c) => c.status === 'warn'))
        return 'warn';
    if (checks.every((c) => c.status === 'skip'))
        return 'skip';
    return 'pass';
}
async function fileExists(fp) {
    try {
        await fs.access(fp);
        return true;
    }
    catch {
        return false;
    }
}
async function hasAnyFile(dir, names) {
    for (const name of names) {
        if (await fileExists(path.join(dir, name)))
            return true;
    }
    return false;
}
async function isValidJson(fp) {
    try {
        const raw = await fs.readFile(fp, 'utf-8');
        JSON.parse(raw);
        return true;
    }
    catch {
        return false;
    }
}
async function readPackageJson(dir) {
    try {
        const raw = await fs.readFile(path.join(dir, 'package.json'), 'utf-8');
        return JSON.parse(raw);
    }
    catch {
        return null;
    }
}
//# sourceMappingURL=doneStateVerifier.js.map