/**
 * @internal
 * auto-emit-artifact-ready.mjs — code-enforced plan-ready signal.
 *
 * Promotes the `artifact.ready{kind:'plan'}` emit from a markdown contract
 * in `skills/apt-plan/adapters/conductor.md` to a framework-level
 * postcondition of `apt-tools commit`. This closes the Conductor v2 gap
 * exposed during live verification 2026-05-15: the planner's QUICK /
 * SIMPLE track is hard-exempt from "new interaction discipline"
 * (Aperant Fast Path Guarantee ID-05), so the markdown emit step was
 * never executed for tasks router-classified as simple. The fleet
 * never saw artifact.ready, the PlanReadyCard never auto-promoted.
 *
 * The fix lives in `framework` rather than the skill so:
 *   - it works for QUICK + STANDARD + DEEP + COMPLEX uniformly
 *   - it doesn't violate the Fast Path Guarantee (a passive log emit
 *     is not interaction discipline)
 *   - it's the same code path every CLI consumer (Claude Code, Gemini,
 *     OpenCode, Codex) traverses via `apt-tools commit`
 *
 * Conditions for emit (ALL must hold — otherwise no-op):
 *   1. `APERANT_TERMINAL_ID` is set in process.env (Conductor PTY context).
 *   2. The committed files include a path matching
 *      `.aperant/tasks/{task-id}/implementation_plan.json`.
 *
 * The emit re-uses the same `event-schema` validator and JSONL writer
 * `commands/event.mjs` already uses, so the envelope structure stays
 * byte-identical with manually-emitted ones.
 */
import { createHash } from 'node:crypto';
import { appendFileSync, mkdirSync, readFileSync } from 'node:fs';
import { hostname } from 'node:os';
import { join } from 'node:path';
import { validateConductorEvent } from './event-schema.mjs';
const PLAN_PATH_RE = /^(?:\.\/)?\.aperant\/tasks\/([^/]+)\/implementation_plan\.json$/;
let _incarnationCounter = 0;
/**
 * @param {{ files: string[], projectRoot: string }} input
 * @returns {{ emitted: false, reason: string } | { emitted: true, envelope: object, file: string }}
 */
export function maybeAutoEmitPlanReady({ files, projectRoot }) {
    const terminalId = process.env.APERANT_TERMINAL_ID;
    if (!terminalId)
        return { emitted: false, reason: 'APERANT_TERMINAL_ID unset' };
    const match = files.map((f) => f.replace(/\\/g, '/').match(PLAN_PATH_RE)).find((m) => m !== null);
    if (!match)
        return { emitted: false, reason: 'no implementation_plan.json in committed files' };
    const taskId = match[1];
    const planRelPath = `.aperant/tasks/${taskId}/implementation_plan.json`;
    const absolutePath = join(projectRoot, planRelPath);
    let hash;
    try {
        const body = readFileSync(absolutePath);
        hash = createHash('sha256').update(body).digest('hex');
    }
    catch (err) {
        return { emitted: false, reason: `plan file unreadable: ${(err && err.message) || err}` };
    }
    const data = {
        kind: 'plan',
        path: planRelPath,
        hash,
        request_id: `plan-${taskId}-${Date.now()}`,
        task_id: taskId,
        terminal_id: terminalId,
    };
    const validation = validateConductorEvent('artifact.ready', data);
    if (!validation.ok) {
        return { emitted: false, reason: `schema violation: ${validation.error}` };
    }
    const envelope = {
        t: new Date().toISOString(),
        agent: `${hostname()}-${process.pid}`,
        pid: process.pid,
        hostname: hostname(),
        incarnation: ++_incarnationCounter,
        op: 'artifact.ready',
        task: taskId,
        data,
    };
    const eventsDir = join(projectRoot, '.aperant', 'events');
    mkdirSync(eventsDir, { recursive: true });
    const dayFile = `${new Date().toISOString().slice(0, 10)}.jsonl`;
    const fullPath = join(eventsDir, dayFile);
    appendFileSync(fullPath, `${JSON.stringify(envelope)}\n`, 'utf-8');
    return { emitted: true, envelope, file: dayFile };
}
//# sourceMappingURL=auto-emit-artifact-ready.mjs.map