"use strict";
/**
 * event-plan-parser — canonical parser for `<installDir>/.amplitude-events.json`.
 *
 * Single source of truth for reading the event-plan file the agent writes via
 * `confirm_event_plan`. Both the TUI's Event Plan viewer (which imports
 * `parseEventPlanContent` from `agent-interface.ts`) and the CLI plan reader
 * (`agent-ops.ts#runPlan`) ultimately route through this module so the schema
 * and fallback chains stay in lock-step.
 *
 * Lightweight on purpose — only depends on `zod`. Pure-ops modules can import
 * it without dragging in the Claude Agent SDK loader, the wizard UI singleton,
 * analytics, or any other agent-runtime surface.
 *
 * History: extracted from `agent-interface.ts` after Bugbot flagged that the
 * inlined parser in `agent-ops.ts` had drifted from the TUI's copy. See PR
 * #295.
 */
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.parseEventPlanContent = parseEventPlanContent;
exports.readLocalEventPlan = readLocalEventPlan;
const fs = __importStar(require("node:fs"));
const path = __importStar(require("node:path"));
const zod_1 = require("zod");
const storage_paths_js_1 = require("../utils/storage-paths.js");
const debug_js_1 = require("../utils/debug.js");
// The agent doesn't always use the same field casing in .amplitude-events.json
// — observed in the wild: name, event, eventName, event_name (and the same
// for description: description, event_description, eventDescription,
// eventDescriptionAndReasoning). Accept every common variant so the event
// plan renders instead of falling back to an empty name. Some skills also
// imply a top-level `{ events: [...] }` wrapper; we unwrap it before parsing.
const eventPlanSchema = zod_1.z.array(zod_1.z.looseObject({
    name: zod_1.z.string().optional(),
    event: zod_1.z.string().optional(),
    eventName: zod_1.z.string().optional(),
    event_name: zod_1.z.string().optional(),
    description: zod_1.z.string().optional(),
    event_description: zod_1.z.string().optional(),
    eventDescription: zod_1.z.string().optional(),
    eventDescriptionAndReasoning: zod_1.z.string().optional(),
}));
/**
 * Parse the agent-written `.amplitude-events.json` into a normalized
 * `[{ name, description }]` array. Returns `null` if the input isn't valid
 * JSON or doesn't match the schema, so callers can distinguish "not ready
 * yet" from a structural problem.
 *
 * Tolerates all observed agent-written field variants:
 *   name        → name | event | eventName | event_name
 *   description → description | event_description | eventDescription
 *                 | eventDescriptionAndReasoning
 *
 * Description fallback prefers concise standard aliases over the verbose
 * `eventDescriptionAndReasoning` legacy field — if an agent emits both,
 * the concise one wins so the plan stays scannable.
 *
 * Also unwraps a `{ events: [...] }` wrapper some skills produce.
 */
function parseEventPlanContent(content) {
    let parsed;
    try {
        parsed = JSON.parse(content);
    }
    catch {
        return null;
    }
    // Tolerate `{ events: [...] }` wrapper objects — some skills imply this
    // shape and the parser would otherwise reject them outright.
    if (parsed &&
        typeof parsed === 'object' &&
        !Array.isArray(parsed) &&
        Array.isArray(parsed.events)) {
        parsed = parsed.events;
    }
    const result = eventPlanSchema.safeParse(parsed);
    if (!result.success)
        return null;
    return result.data.map((e) => ({
        name: e.name ?? e.event ?? e.eventName ?? e.event_name ?? '',
        description: e.description ??
            e.event_description ??
            e.eventDescription ??
            e.eventDescriptionAndReasoning ??
            '',
    }));
}
/**
 * Read the agent-written event plan from a project's install dir.
 *
 * Tries the canonical path first (`<installDir>/.amplitude/events.json`),
 * then the legacy dotfile (`<installDir>/.amplitude-events.json`) that
 * older context-hub integration skills still emit. Returns whichever has
 * the more recent mtime so a stale canonical from a previous run can't
 * shadow a fresh legacy write — mirroring the `pickFreshestExisting`
 * logic in `agent-interface.ts`.
 *
 * Returns `[]` for any non-fatal failure (file missing, malformed JSON,
 * schema mismatch). Empty entries (no name) are dropped. Logs to the
 * debug file so issues are recoverable post-mortem.
 *
 * Used by the Event Verification screen to render the planned tracking
 * list inline so users can see what they need to trigger.
 */
function readLocalEventPlan(installDir) {
    const candidates = [
        (0, storage_paths_js_1.getEventsFile)(installDir),
        path.join(installDir, '.amplitude-events.json'),
    ];
    let winner = null;
    let winnerMtime = -Infinity;
    for (const candidate of candidates) {
        try {
            const stat = fs.statSync(candidate);
            const mtime = stat.mtimeMs;
            if (mtime > winnerMtime) {
                winner = candidate;
                winnerMtime = mtime;
            }
        }
        catch (e) {
            const err = e;
            if (err.code !== 'ENOENT') {
                (0, debug_js_1.logToFile)(`[readLocalEventPlan] stat ${candidate} failed: ${err.message ?? err}`);
            }
        }
    }
    if (!winner)
        return [];
    let raw;
    try {
        raw = fs.readFileSync(winner, 'utf8');
    }
    catch (e) {
        const err = e;
        (0, debug_js_1.logToFile)(`[readLocalEventPlan] read ${winner} failed: ${err.message ?? err}`);
        return [];
    }
    const parsed = parseEventPlanContent(raw);
    if (parsed === null) {
        (0, debug_js_1.logToFile)(`[readLocalEventPlan] ${winner} could not be parsed as an event plan`);
        return [];
    }
    return parsed.filter((e) => e.name.trim().length > 0);
}
