/**
 * ClaudeCodeIdeAdapter -- Claude Code IDE adapter.
 *
 * Wraps the existing Claude Code PreToolUse / PostToolUse hook system under
 * the IdeAdapter contract. The adapter provides the governance-runtime
 * dispatch side; the hook scripts themselves live in the customer's Claude
 * Code install and invoke this adapter.
 *
 * This is the reference adapter for the IDE contract: Claude Code's hook
 * surface is native and fully tested. Behaviour-preserving: existing
 * customer deployments require no migration.
 *
 * User identity resolution order (fail-closed per AC 21):
 *   1. CLAUDE_SESSION_USER environment variable
 *   2. .claude/session.json file (userId field)
 *   3. Throws IdeAttributionError at initialize time
 *      (never defaults to 'unknown')
 *
 * Spec: P3-IDE-01 AC 4-5
 *
 * @connexum/ai-governance
 */
import { BaseIdeAdapter } from './base.js';
import { IdeAttributionError, IdeUnsupportedError, } from './index.js';
import { resolveClaudeCodeUserIdentity } from './shared.js';
// ---------------------------------------------------------------------------
// Sensitive path patterns -- deny any tool that writes to these paths
// ---------------------------------------------------------------------------
const SENSITIVE_PATH_PATTERNS = [
    /^\/etc\//,
    /^\/root\//,
    /^\/?\.env$/,
    /\.env\./,
    /^\/proc\//,
    /^\/sys\//,
    /secrets?\//i,
    /private_?key/i,
    /\.pem$/i,
    /\.key$/i,
];
// ---------------------------------------------------------------------------
// Destructive command patterns (inherited from legacy cursor.ts and extended)
// ---------------------------------------------------------------------------
const DESTRUCTIVE_COMMAND_PATTERNS = [
    /\brm\s+(-[rR]f?|--recursive)\b/,
    /\bgit\s+push\s+--force\b/,
    /\bgit\s+reset\s+--hard\b/,
    /\bgit\s+clean\s+-f/,
    /\bdrop\s+(table|database)\b/i,
    /\btruncate\s+table\b/i,
    /\bnpm\s+publish\b/,
    /\bcurl\b.*\|\s*(bash|sh)\b/,
    /\bdd\s+if=/,
    /\bchmod\s+777\b/,
    /\bsudo\s+rm\b/,
];
// ---------------------------------------------------------------------------
// ClaudeCodeIdeAdapter
// ---------------------------------------------------------------------------
export class ClaudeCodeIdeAdapter extends BaseIdeAdapter {
    adapterId = 'claude-code';
    ideId = 'claude-code';
    /** Resolved at initialize time; used for subsequent sessions */
    resolvedIdentity = null;
    // ---------------------------------------------------------------------------
    // Lifecycle
    // ---------------------------------------------------------------------------
    /**
     * Initialize the adapter.
     *
     * Immediately resolves user identity so failures surface at initialize
     * time, not mid-session (AC 21: fail-closed at adapter init).
     */
    initialize(config) {
        // Base performs pack-binding guard (throws IdeSessionError if no packId)
        super.initialize(config);
        // Resolve identity eagerly: fail-closed if not resolvable and anonymous
        // sessions are not explicitly permitted.
        const allowAnon = config.allowAnonymousIdeSessions === true;
        const sessionFilePath = config.sessionFilePath ?? '.claude/session.json';
        try {
            this.resolvedIdentity = resolveClaudeCodeUserIdentity(sessionFilePath, allowAnon);
        }
        catch (err) {
            // Emit CRITICAL before re-throwing so the audit chain captures it.
            this.emitIdentityUnresolved(undefined, err instanceof Error ? err.message : String(err));
            throw err;
        }
        this.emitIdentityResolved(this.resolvedIdentity.userId);
    }
    // ---------------------------------------------------------------------------
    // IdeAdapter: resolveUserIdentity
    // ---------------------------------------------------------------------------
    async resolveUserIdentity(session) {
        this.ensureInitialized();
        // Re-resolve on each call to pick up env var changes in long-lived processes
        const allowAnon = this.config?.allowAnonymousIdeSessions === true;
        const sessionFilePath = this.config?.sessionFilePath ?? '.claude/session.json';
        const identity = resolveClaudeCodeUserIdentity(sessionFilePath, allowAnon);
        // Merge optional fields from session context if provided
        if (session.identity?.email)
            identity.email = session.identity.email;
        if (session.identity?.orgId)
            identity.orgId = session.identity.orgId;
        if (session.identity?.githubLogin)
            identity.githubLogin = session.identity.githubLogin;
        this.emitIdentityResolved(identity.userId);
        return identity;
    }
    // ---------------------------------------------------------------------------
    // IdeAdapter: interceptToolInvocation (AC 4)
    //
    // Receives the normalised ToolInvocationContext (built from a PreToolUse
    // hook payload by the hook dispatch script) and returns a decision.
    // The hook script enforces the decision by exiting 0 (allow) or 2 (deny).
    // ---------------------------------------------------------------------------
    async interceptToolInvocation(ctx) {
        this.ensureInitialized();
        // 1. Destructive command check (Bash / run_terminal tools)
        if (ctx.tool === 'Bash') {
            const command = String(ctx.input['command'] ?? '');
            for (const pattern of DESTRUCTIVE_COMMAND_PATTERNS) {
                if (pattern.test(command)) {
                    const decision = {
                        decision: 'DENY',
                        reason: `Destructive command blocked by governance runtime. Pattern: ${pattern.source}`,
                        metadata: { pattern: pattern.source },
                    };
                    return this.routeToolInvocation(ctx, decision);
                }
            }
        }
        // 2. Sensitive path check (Edit, Write, Read, Glob tools)
        if (['Edit', 'Write', 'Read', 'Glob'].includes(ctx.tool)) {
            const filePath = String(ctx.input['file_path'] ?? ctx.input['path'] ?? '');
            if (filePath) {
                for (const pattern of SENSITIVE_PATH_PATTERNS) {
                    if (pattern.test(filePath)) {
                        const decision = {
                            decision: 'DENY',
                            reason: `Sensitive path blocked by governance runtime: ${filePath}`,
                            metadata: { filePath, pattern: pattern.source },
                        };
                        return this.routeToolInvocation(ctx, decision);
                    }
                }
            }
        }
        // 3. Default: allow and route through the governance runtime
        const decision = {
            decision: 'ALLOW',
            reason: `Tool '${ctx.tool}' permitted by Claude Code governance adapter`,
        };
        return this.routeToolInvocation(ctx, decision);
    }
    // ---------------------------------------------------------------------------
    // IdeAdapter: routeToolToReviewer (override to attach Claude Code context)
    // ---------------------------------------------------------------------------
    async routeToolToReviewer(tool, ctx, tier) {
        const result = await super.routeToolToReviewer(tool, ctx, tier);
        // In a full implementation this delegates to the ApprovalQueue.
        // For now the base generates the ticket ID and emits the audit event.
        return result;
    }
    // ---------------------------------------------------------------------------
    // IdeAdapter: getIdeCapabilities
    // ---------------------------------------------------------------------------
    getIdeCapabilities() {
        return {
            runtimeHooks: true,
            prBoundary: false,
            userIdentity: true,
            reviewerRouting: true,
            integrationMode: 'pre-post-tool-hook',
        };
    }
    // ---------------------------------------------------------------------------
    // IdeAdapter: translateError
    // ---------------------------------------------------------------------------
    translateError(raw) {
        if (raw instanceof IdeAttributionError)
            return raw;
        if (raw instanceof IdeUnsupportedError)
            return raw;
        return super.translateError(raw);
    }
}
//# sourceMappingURL=claude-code.js.map