#!/usr/bin/env node
"use strict";
/**
 * pack-enforcement-bridge — Node CLI invokable from bash hooks.
 *
 * Thomas directive 2026-05-17 evening: "It must start up and report findings
 * to a local database on the compliance and company packs, including what
 * they are allowed and not allowed to do. It must have SHA-256 installed,
 * and everything we plan on offering our clients must work when this works."
 *
 * Pre-fix audit (Explore agent 2026-05-17): shell hooks (audit-logger.sh,
 * destructive-command-guard.sh, secret-leak-scanner.sh) use HARDCODED
 * patterns + never load the bound packs from .governance.json. HIPAA / SOC 2
 * rules are dead data on the customer's machine.
 *
 * This bridge closes the gap. A shell hook runs:
 *
 *   node dist/cli/pack-enforcement-bridge.js \
 *     --tool=Bash \
 *     --input='{"command":"rm -rf /etc"}'
 *
 * and gets a one-line JSON verdict on stdout:
 *
 *   {"verdict":"DENY","triggeringPackIds":["hipaa"],"reason":"Pack policy
 *    enforced: Category 'PHI' (action=BLOCK, packs=[hipaa])",
 *    "categoryMatched":"PHI","timestamp":1715900000000}
 *
 * Exit code is 0 on ALLOW + LOG + WARN, 1 on DENY, 2 on REQUIRE_APPROVAL,
 * 3 on internal error (so hooks can branch on the exit code without
 * parsing JSON if they want a fast path).
 *
 * The bridge reads `.governance.json` from process.cwd() (the project root
 * where the hook fires). If the file is missing, malformed, or has no
 * `packs[]` array, the bridge prints `{"verdict":"ALLOW","reason":"no
 * packs bound"}` and exits 0 — Invariant 2 (advisory, never blocks).
 *
 * @connexum/ai-governance — runtime
 */
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 });
const fs = __importStar(require("node:fs"));
const path = __importStar(require("node:path"));
const governed_agent_js_1 = require("../governed-agent.js");
const index_js_1 = require("../packs/index.js");
const pack_evaluator_js_1 = require("../governance/pack-evaluator.js");
function parseArgs(argv) {
    const args = { cwd: process.cwd() };
    for (const a of argv) {
        const m = a.match(/^--([^=]+)=(.*)$/);
        if (!m)
            continue;
        const key = m[1];
        if (key === 'tool' || key === 'input' || key === 'cwd') {
            args[key] = m[2];
        }
    }
    if (!args.tool)
        return null;
    if (typeof args.input !== 'string')
        args.input = '{}';
    return args;
}
function readGovernanceConfig(cwd) {
    const p = path.join(cwd, '.governance.json');
    if (!fs.existsSync(p))
        return null;
    try {
        const raw = fs.readFileSync(p, 'utf8');
        return JSON.parse(raw);
    }
    catch {
        return null;
    }
}
// ---------------------------------------------------------------------------
// Build PackRegistry from bound packs
// ---------------------------------------------------------------------------
function buildRegistry(packIds) {
    const registry = new index_js_1.PackRegistry();
    const resolved = [];
    for (const rawId of packIds) {
        const normalizedId = rawId.toLowerCase().replace(/[\s-_]/g, '');
        const pack = governed_agent_js_1.BUILT_IN_PACKS[rawId] ?? governed_agent_js_1.BUILT_IN_PACKS[normalizedId];
        if (pack) {
            // PackRegistry.register is idempotent on the same pack id.
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            registry.register(pack);
            resolved.push(pack.id);
        }
    }
    return { registry, resolved };
}
// ---------------------------------------------------------------------------
// Main
// ---------------------------------------------------------------------------
function emitJsonAndExit(payload, exitCode) {
    process.stdout.write(JSON.stringify(payload) + '\n');
    process.exit(exitCode);
}
function main() {
    const args = parseArgs(process.argv.slice(2));
    if (!args) {
        emitJsonAndExit({
            verdict: 'ALLOW',
            reason: 'pack-enforcement-bridge: --tool=<name> required',
            triggeringPackIds: [],
        }, 0);
    }
    const config = readGovernanceConfig(args.cwd);
    if (!config || !Array.isArray(config.packs) || config.packs.length === 0) {
        emitJsonAndExit({
            verdict: 'ALLOW',
            reason: 'No packs bound in .governance.json — no policy to evaluate',
            triggeringPackIds: [],
            boundPacks: [],
        }, 0);
    }
    const { registry, resolved } = buildRegistry(config.packs);
    if (resolved.length === 0) {
        emitJsonAndExit({
            verdict: 'ALLOW',
            reason: `No bound pack id matched a built-in pack (configured: ${config.packs.join(',')})`,
            triggeringPackIds: [],
            boundPacks: config.packs,
        }, 0);
    }
    // Synthesize ActionContext for the PackEvaluator
    let inputObj = {};
    try {
        inputObj = JSON.parse(args.input);
    }
    catch {
        inputObj = { raw: args.input };
    }
    const tenantId = config.runtime?.orgId ?? 'local';
    const agentId = config.runtime?.agentId ?? 'local-agent';
    const actionContext = {
        toolName: args.tool,
        input: inputObj,
        agent: { name: agentId },
        timestamp: new Date().toISOString(),
    };
    // Use single-tenant mode (no activateForTenant call) so the evaluator
    // considers every registered pack — this matches the "all bound packs
    // are active" customer-side semantics.
    //
    // PackEvaluator only consumes EventBus.on() for cache-flush events.
    // The bridge is short-lived (one-shot per hook fire) so a no-op stub
    // satisfies the contract without dragging in EventBus's file-system
    // event-store dependencies (eventDir / agentName / rotation).
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const noopEventBus = { on: () => undefined };
    const evaluator = new pack_evaluator_js_1.PackEvaluator(registry, noopEventBus);
    const verdict = evaluator.evaluate(tenantId, agentId, actionContext);
    const exitCode = verdict.verdict === 'DENY' ? 1 : verdict.verdict === 'PENDING' ? 2 : 0;
    emitJsonAndExit({
        verdict: verdict.verdict,
        triggeringPackIds: verdict.triggeringPackIds,
        triggeringClassifierIds: verdict.triggeringClassifierIds,
        reason: verdict.reason,
        timestamp: verdict.timestamp,
        boundPacks: resolved,
        tool: args.tool,
    }, exitCode);
}
try {
    main();
}
catch (err) {
    // Invariant 2: never throw on a hook-path. Fall back to ALLOW with the
    // error in the reason so the customer can diagnose without being blocked.
    emitJsonAndExit({
        verdict: 'ALLOW',
        reason: `pack-enforcement-bridge internal error: ${err.message}`,
        triggeringPackIds: [],
        error: true,
    }, 3);
}
//# sourceMappingURL=pack-enforcement-bridge.js.map