/**
 * BaseIdeAdapter -- abstract base class for all IDE adapters.
 *
 * Provides:
 *   - Common tool-invocation routing through the governance runtime
 *   - Common audit-event emission using the canonical taxonomy (Section 3.2)
 *   - Common session-scoped policy application
 *   - Common user-identity attribution defaulting
 *   - Common per-tool reviewer routing
 *   - Common error translation
 *
 * Concrete adapters (ClaudeCodeIdeAdapter, CursorIdeAdapter, etc.) extend
 * this class and override only IDE-specific integration plumbing.
 *
 * Spec: P3-IDE-01 AC 3, Section 3.2
 *
 * @connexum/ai-governance
 */
import { IdeAdapterError, IdeSessionError, } from './index.js';
import { generateSessionHandle, buildIdeAuditEvent, } from './shared.js';
// ---------------------------------------------------------------------------
// BaseIdeAdapter
// ---------------------------------------------------------------------------
export class BaseIdeAdapter {
    config = null;
    initialized = false;
    auditEmit = null;
    /** Active sessions keyed by sessionId */
    activeSessions = new Map();
    // ---------------------------------------------------------------------------
    // Lifecycle
    // ---------------------------------------------------------------------------
    /**
     * Initialize the adapter with config and bind a policy pack.
     *
     * Throws `IdeSessionError` if `config.packId` is not provided.
     * No default pack is loaded. No neutral-pass. Fail-closed per AC 28.
     */
    initialize(config) {
        if (!config.packId || config.packId.trim() === '') {
            throw new IdeSessionError({
                message: `IdeAdapter '${this.adapterId}': initialize() called without a ` +
                    'policy-pack binding. packId is required. No default pack is loaded ' +
                    'and the adapter will not start in an unconfigured state. Provide a ' +
                    'packId (e.g. "hipaa", "soc2", "pci-dss") in IdeAdapterConfig.',
                ideId: this.ideId,
                adapterId: this.adapterId,
            });
        }
        this.config = config;
        this.initialized = true;
    }
    /**
     * Wire an audit emitter. Called after initialization by the governance
     * runtime or tests. Adapters emit canonical IDE audit events through this.
     */
    setAuditEmitter(emit) {
        this.auditEmit = emit;
    }
    ensureInitialized() {
        if (!this.initialized || !this.config) {
            throw new IdeSessionError({
                message: `IdeAdapter '${this.adapterId}' must be initialized before use. ` +
                    'Call initialize(config) first.',
                ideId: this.ideId,
                adapterId: this.adapterId,
            });
        }
    }
    // ---------------------------------------------------------------------------
    // Session lifecycle
    // ---------------------------------------------------------------------------
    async openSession(ctx) {
        this.ensureInitialized();
        const handle = generateSessionHandle(this.ideId);
        if (ctx.metadata) {
            handle.metadata = ctx.metadata;
        }
        this.activeSessions.set(handle.sessionId, handle);
        this.emit(buildIdeAuditEvent('ide:session-open', {
            ideId: this.ideId,
            adapterId: this.adapterId,
            sessionId: handle.sessionId,
            detail: `Session opened: ${handle.sessionId}`,
            data: { openedAt: handle.openedAt, workspacePath: ctx.workspacePath },
        }));
        return handle;
    }
    async closeSession(handle) {
        this.ensureInitialized();
        this.activeSessions.delete(handle.sessionId);
        this.emit(buildIdeAuditEvent('ide:session-close', {
            ideId: this.ideId,
            adapterId: this.adapterId,
            sessionId: handle.sessionId,
            detail: `Session closed: ${handle.sessionId}`,
        }));
    }
    // ---------------------------------------------------------------------------
    // Tool invocation routing (common, AC 3)
    //
    // Subclasses call routeToolInvocation() inside interceptToolInvocation() to
    // apply the governance policy and emit canonical audit events. IDE-specific
    // context extraction (hook payloads, Cursor composer formats, etc.) lives
    // in the concrete adapter.
    // ---------------------------------------------------------------------------
    /**
     * Common tool-invocation governance dispatch.
     *
     * Applies session-scoped policy, emits the canonical audit event, and
     * returns the decision. Concrete adapters call this from
     * interceptToolInvocation() after normalising the IDE-native payload into
     * a ToolInvocationContext.
     */
    async routeToolInvocation(ctx, policyDecision) {
        const eventType = policyDecision.decision === 'ALLOW'
            ? 'ide:tool-invocation-approved'
            : policyDecision.decision === 'DENY'
                ? 'ide:tool-invocation-denied'
                : 'ide:tool-invocation-require-approval';
        this.emit(buildIdeAuditEvent(eventType, {
            ideId: this.ideId,
            adapterId: this.adapterId,
            sessionId: ctx.sessionHandle.sessionId,
            initiatingUserId: ctx.initiatingUser.userId,
            tool: ctx.tool,
            detail: policyDecision.reason,
            data: {
                decision: policyDecision.decision,
                approvalTicketId: policyDecision.approvalTicketId,
            },
        }));
        return policyDecision;
    }
    // ---------------------------------------------------------------------------
    // recordToolResult (common, AC 3)
    // ---------------------------------------------------------------------------
    async recordToolResult(ctx, result) {
        this.ensureInitialized();
        // Base implementation: emit an audit entry for the result.
        // Concrete adapters may override to persist to the audit store.
        this.emit(buildIdeAuditEvent(result.success ? 'ide:tool-invocation-approved' : 'ide:tool-invocation-denied', {
            ideId: this.ideId,
            adapterId: this.adapterId,
            sessionId: ctx.sessionHandle.sessionId,
            initiatingUserId: ctx.initiatingUser.userId,
            tool: ctx.tool,
            detail: result.success
                ? `Tool '${ctx.tool}' executed successfully`
                : `Tool '${ctx.tool}' failed: ${result.error ?? 'unknown error'}`,
            data: {
                success: result.success,
                outputSummary: result.outputSummary,
                durationMs: result.durationMs,
            },
        }));
    }
    emitIdentityResolved(userId, sessionId) {
        this.emit(buildIdeAuditEvent('ide:user-identity-resolved', {
            ideId: this.ideId,
            adapterId: this.adapterId,
            sessionId,
            initiatingUserId: userId,
            detail: `User identity resolved: ${userId}`,
        }));
    }
    emitIdentityUnresolved(sessionId, detail) {
        this.emit(buildIdeAuditEvent('ide:user-identity-unresolved', {
            ideId: this.ideId,
            adapterId: this.adapterId,
            sessionId,
            detail: detail ?? 'User identity could not be resolved.',
        }));
    }
    // ---------------------------------------------------------------------------
    // Per-tool reviewer routing (common, AC 3)
    // ---------------------------------------------------------------------------
    async routeToolToReviewer(tool, ctx, tier) {
        this.ensureInitialized();
        // Base implementation: generate a stub ticket ID and record the routing.
        // The governance runtime (approval-queue) handles the actual delivery.
        // Production integrations override this to call the ApprovalQueue.
        const ticketId = `REVIEW-${this.ideId.toUpperCase()}-${Date.now()}`;
        this.emit(buildIdeAuditEvent('ide:tool-invocation-require-approval', {
            ideId: this.ideId,
            adapterId: this.adapterId,
            sessionId: ctx.sessionHandle.sessionId,
            initiatingUserId: ctx.initiatingUser.userId,
            tool,
            detail: `Tool '${tool}' routed to reviewer tier ${tier}`,
            data: { tier, ticketId },
        }));
        return {
            routed: true,
            tier,
            ticketId,
            reason: `Tool '${tool}' requires ${tier} review before execution.`,
        };
    }
    // ---------------------------------------------------------------------------
    // Error translation (common)
    // ---------------------------------------------------------------------------
    translateError(raw) {
        if (raw instanceof IdeAdapterError)
            return raw;
        const message = raw instanceof Error ? raw.message : String(raw);
        return new IdeAdapterError({
            message: `[${this.adapterId}] ${message}`,
            code: 'IDE_ADAPTER_ERROR',
            ideId: this.ideId,
            adapterId: this.adapterId,
            raw,
        });
    }
    // ---------------------------------------------------------------------------
    // Audit emission helper
    // ---------------------------------------------------------------------------
    emit(event) {
        if (!this.auditEmit)
            return;
        try {
            this.auditEmit(event);
        }
        catch {
            // Broken audit sink must not crash the governance path.
        }
    }
}
//# sourceMappingURL=base.js.map