"use strict";
/**
 * CursorIdeAdapter -- Cursor IDE adapter.
 *
 * Refactored from src/adapters/cursor.ts into the IdeAdapter contract.
 * Extends BaseIdeAdapter and preserves all existing destructive-command
 * denial logic.
 *
 * Cursor has no per-tool hook API equivalent to Claude Code PreToolUse.
 * The adapter ships in three modes (selectable by config.integrationMode):
 *
 *   'mcp-server'          -- Cursor connects to a governance MCP server
 *   'vscode-extension'    -- Governance ships as a VS Code extension Cursor
 *                            inherits
 *   'filesystem-sidecar'  -- A separate daemon watches the project tree and
 *                            flags AI-initiated writes
 *
 * The default mode is 'filesystem-sidecar' (AC 7 -- safest floor, does not
 * depend on Cursor-specific API stability).
 *
 * Full implementations of 'mcp-server' and 'vscode-extension' modes are
 * deferred to later cycles. They currently throw IdeUnsupportedError with
 * an explicit helpful message -- explicit deferral, not silent skip.
 *
 * Research task (AC 6-7): validate all three modes against Cursor 0.50+
 * before full implementation.
 *
 * User identity resolution: Cursor composer session ID from the action
 * context (attributionMethod: 'cursor-composer').
 *
 * Spec: P3-IDE-01 AC 6-7
 *
 * @connexum/ai-governance
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.CursorIdeAdapter = void 0;
const base_1 = require("./base");
const index_1 = require("./index");
const CURSOR_TOOL_MAP = {
    edit_file: 'Edit',
    run_terminal: 'Bash',
    search: 'Grep',
    read_file: 'Read',
};
// ---------------------------------------------------------------------------
// Destructive command patterns (preserved from legacy adapter)
// ---------------------------------------------------------------------------
const DEFAULT_DESTRUCTIVE_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/,
];
// ---------------------------------------------------------------------------
// Sensitive path patterns
// ---------------------------------------------------------------------------
const SENSITIVE_PATH_PATTERNS = [
    /^\/etc\//,
    /^\/root\//,
    /^\/?\.env$/,
    /\.env\./,
    /secrets?\//i,
    /private_?key/i,
    /\.pem$/i,
    /\.key$/i,
];
// ---------------------------------------------------------------------------
// CursorIdeAdapter
// ---------------------------------------------------------------------------
class CursorIdeAdapter extends base_1.BaseIdeAdapter {
    adapterId = 'cursor';
    ideId = 'cursor';
    integrationMode = 'filesystem-sidecar';
    blockedPatterns = [];
    // ---------------------------------------------------------------------------
    // Lifecycle
    // ---------------------------------------------------------------------------
    initialize(config) {
        // Base performs pack-binding guard
        super.initialize(config);
        // Set integration mode (default: filesystem-sidecar)
        const mode = config.integrationMode;
        this.integrationMode = mode ?? 'filesystem-sidecar';
        // Merge default destructive patterns with custom ones from config
        const customPatterns = config.options?.['blockedCommands'] ?? [];
        this.blockedPatterns = [...DEFAULT_DESTRUCTIVE_PATTERNS, ...customPatterns];
    }
    // ---------------------------------------------------------------------------
    // IdeAdapter: resolveUserIdentity
    //
    // Cursor identity comes from the composer session context.
    // If no composerSessionId is resolvable, and anonymous sessions are not
    // permitted, throws IdeAttributionError (fail-closed).
    // ---------------------------------------------------------------------------
    async resolveUserIdentity(session) {
        this.ensureInitialized();
        const composerId = (session.identity?.userId) ??
            session.metadata?.['composerSessionId'] ??
            (session.clientSessionId);
        if (composerId && composerId.trim()) {
            const identity = {
                userId: composerId.trim(),
                attributionMethod: 'cursor-composer',
            };
            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;
        }
        const allowAnon = this.config?.allowAnonymousIdeSessions === true;
        if (allowAnon) {
            const anon = {
                userId: 'anonymous',
                attributionMethod: 'cursor-composer',
            };
            this.emitIdentityResolved(anon.userId);
            return anon;
        }
        this.emitIdentityUnresolved(session.clientSessionId, 'CursorIdeAdapter: no composer session ID found and anonymous sessions are not permitted.');
        throw new index_1.IdeAttributionError({
            message: 'CursorIdeAdapter: cannot resolve user identity. Provide a ' +
                'composerSessionId in the session context, or set ' +
                'allowAnonymousIdeSessions: true in adapter config.',
            ideId: this.ideId,
            adapterId: this.adapterId,
        });
    }
    // ---------------------------------------------------------------------------
    // IdeAdapter: interceptToolInvocation
    //
    // Dispatches to the appropriate mode handler. mcp-server and vscode-extension
    // modes throw IdeUnsupportedError (explicit deferral per AC 7).
    // filesystem-sidecar is the active enforcement path.
    // ---------------------------------------------------------------------------
    async interceptToolInvocation(ctx) {
        this.ensureInitialized();
        switch (this.integrationMode) {
            case 'mcp-server':
                return this.interceptViaMcpServer(ctx);
            case 'vscode-extension':
                return this.interceptViaVsCodeExtension(ctx);
            case 'filesystem-sidecar':
                return this.interceptViaFilesystemSidecar(ctx);
            default: {
                // TypeScript exhaustive-check guard
                const _exhaustive = this.integrationMode;
                throw new index_1.IdeUnsupportedError({
                    message: `CursorIdeAdapter: unknown integration mode '${_exhaustive}'.`,
                    ideId: this.ideId,
                    adapterId: this.adapterId,
                    surface: 'interceptToolInvocation',
                });
            }
        }
    }
    // ---------------------------------------------------------------------------
    // Mode handlers
    // ---------------------------------------------------------------------------
    /**
     * MCP server mode -- deferred (AC 7 explicit deferral).
     * Cursor 0.50+ MCP server integration requires empirical validation.
     */
    async interceptViaMcpServer(_ctx) {
        throw new index_1.IdeUnsupportedError({
            message: "Cursor mcp-server mode is not yet implemented. Use 'filesystem-sidecar' " +
                "or 'vscode-extension' mode, or contact support. Full MCP server mode " +
                'implementation is pending empirical validation against Cursor 0.50+.',
            ideId: this.ideId,
            adapterId: this.adapterId,
            surface: 'mcp-server',
        });
    }
    /**
     * VS Code extension mode -- deferred (AC 7 explicit deferral).
     * Cursor inherits VS Code extension APIs; governance extension implementation
     * is pending.
     */
    async interceptViaVsCodeExtension(_ctx) {
        throw new index_1.IdeUnsupportedError({
            message: "Cursor vscode-extension mode is not yet implemented. Use 'filesystem-sidecar' " +
                'mode or contact support. VS Code extension implementation is pending ' +
                'validation of the Cursor extension host API surface.',
            ideId: this.ideId,
            adapterId: this.adapterId,
            surface: 'vscode-extension',
        });
    }
    /**
     * Filesystem sidecar mode -- the active enforcement floor (AC 7).
     *
     * Applies destructive-command denial and sensitive-path protection on
     * every tool invocation. In production the sidecar correlates IDE process
     * heritage; this enforcement layer covers the policy evaluation side.
     */
    async interceptViaFilesystemSidecar(ctx) {
        // Map Cursor tool names to canonical governance tool names for evaluation
        const canonicalTool = this.mapCursorTool(ctx.tool);
        const resolvedCtx = { ...ctx, tool: canonicalTool };
        // 1. Destructive command check
        if (canonicalTool === 'Bash') {
            const command = String(ctx.input['command'] ?? '');
            for (const pattern of this.blockedPatterns) {
                if (pattern.test(command)) {
                    const decision = {
                        decision: 'DENY',
                        reason: `Destructive command blocked by Cursor governance adapter (filesystem-sidecar). Pattern: ${pattern.source}`,
                        metadata: { pattern: pattern.source, mode: 'filesystem-sidecar' },
                    };
                    return this.routeToolInvocation(resolvedCtx, decision);
                }
            }
        }
        // 2. Sensitive path check
        if (['Edit', 'Write', 'Read'].includes(canonicalTool)) {
            const filePath = String(ctx.input['filePath'] ?? 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 Cursor governance adapter: ${filePath}`,
                            metadata: { filePath, pattern: pattern.source, mode: 'filesystem-sidecar' },
                        };
                        return this.routeToolInvocation(resolvedCtx, decision);
                    }
                }
            }
        }
        // 3. Default: allow
        const decision = {
            decision: 'ALLOW',
            reason: `Tool '${ctx.tool}' permitted by Cursor governance adapter (filesystem-sidecar)`,
            metadata: { mode: 'filesystem-sidecar' },
        };
        return this.routeToolInvocation(resolvedCtx, decision);
    }
    // ---------------------------------------------------------------------------
    // Capabilities
    // ---------------------------------------------------------------------------
    getIdeCapabilities() {
        return {
            runtimeHooks: this.integrationMode === 'filesystem-sidecar',
            prBoundary: false,
            userIdentity: true,
            reviewerRouting: true,
            integrationMode: this.integrationMode,
        };
    }
    // ---------------------------------------------------------------------------
    // Helpers
    // ---------------------------------------------------------------------------
    /**
     * Map Cursor tool names to canonical governance tool names.
     * Falls through to the original name if not in the map (pass-through).
     */
    mapCursorTool(tool) {
        return CURSOR_TOOL_MAP[tool] ?? tool;
    }
    /** Expose integration mode for diagnostics / tests */
    getIntegrationMode() {
        return this.integrationMode;
    }
}
exports.CursorIdeAdapter = CursorIdeAdapter;
//# sourceMappingURL=cursor.js.map