/**
 * Execution Context Detection
 *
 * Detects whether the CLI is running inside the agentics-cli development
 * repository (MODE 1: Development) or an end-user project repository
 * (MODE 2: Project). Routes MVP materialization accordingly:
 *
 *   Development mode: Sandbox/ephemeral — no git mutations, output only in ~/.agentics/runs/
 *   Project mode:     Writes files and commits directly on the current branch — no branch switching
 *
 * Detection precedence:
 *   1. AGENTICS_EXECUTION_MODE env var ('development' | 'project')
 *   2. Git remote URL or repo directory name containing "agentics-cli"
 */
import { execSync } from 'node:child_process';
import { CLIError } from '../errors/index.js';
// ============================================================================
// Git Helpers (silent — never throw on git absence)
// ============================================================================
function gitExec(command, cwd) {
    try {
        return execSync(command, {
            cwd,
            stdio: ['pipe', 'pipe', 'pipe'],
            timeout: 5000,
        }).toString().trim();
    }
    catch {
        return null;
    }
}
// ============================================================================
// Core Detection
// ============================================================================
/**
 * Detect the execution mode based on the current working directory.
 *
 * Returns a full ExecutionContext with mode, repo info, and git state.
 */
export function detectExecutionMode() {
    // Priority 1: Explicit env var override
    const envMode = process.env['AGENTICS_EXECUTION_MODE'];
    if (envMode === 'development' || envMode === 'project') {
        const ctx = gatherGitContext();
        return { ...ctx, mode: envMode };
    }
    const ctx = gatherGitContext();
    // Always use project mode — `agentics ask` must produce code on a new branch.
    // The old "development" guard silently suppressed branch creation and code commits,
    // leaving artifacts buried in ~/.agentics/runs/ with no visible output.
    return { ...ctx, mode: ctx.isGitRepo ? 'project' : 'project' };
}
/**
 * Gather git context from the current working directory.
 */
function gatherGitContext() {
    // Priority: AGENTICS_PROJECT_ROOT (from MCP client) → git rev-parse → null
    const projectRoot = process.env['AGENTICS_PROJECT_ROOT'] ?? null;
    const gitRoot = gitExec('git rev-parse --show-toplevel');
    const repoRoot = projectRoot ?? gitRoot;
    const isGitRepo = gitRoot !== null || projectRoot !== null;
    if (!isGitRepo) {
        return {
            repoRoot: null,
            remoteUrl: null,
            isGitRepo: false,
            isCleanTree: false,
            currentBranch: null,
        };
    }
    // Run git commands from the project root (not cwd, which may differ in MCP mode)
    const gitCwd = repoRoot ?? undefined;
    const remoteUrl = gitExec('git remote get-url origin', gitCwd);
    const currentBranch = gitExec('git rev-parse --abbrev-ref HEAD', gitCwd);
    const statusOutput = gitExec('git status --porcelain', gitCwd);
    const isCleanTree = statusOutput !== null && statusOutput.length === 0;
    return {
        repoRoot,
        remoteUrl,
        isGitRepo,
        isCleanTree,
        currentBranch,
    };
}
// ============================================================================
// Validation
// ============================================================================
/**
 * Validate that the working tree is clean. Throws if dirty.
 * Only called in project mode before creating a scenario branch.
 */
export function validateCleanWorkingTree() {
    const status = gitExec('git status --porcelain');
    if (status === null) {
        throw new CLIError({
            code: 'ECLI-GIT-004',
            category: 'INPUT_ERROR',
            message: 'Not inside a git repository. Initialize with `git init` first.',
            module: 'execution-context',
            recoverable: false,
            exitCode: 1,
        });
    }
    if (status.length > 0) {
        throw new CLIError({
            code: 'ECLI-GIT-001',
            category: 'INPUT_ERROR',
            message: 'Working tree is not clean. Commit or stash changes before running the pipeline.',
            details: { dirtyFiles: status.split('\n').length },
            module: 'execution-context',
            recoverable: true,
            exitCode: 1,
        });
    }
}
// ============================================================================
// Scenario Branch Utilities
// ============================================================================
/**
 * Generate a URL-safe slug from a scenario query string.
 *
 * Takes the first 40 characters, lowercases, replaces non-alphanumeric
 * with hyphens, collapses runs, trims edges, appends YYYYMMDD date.
 */
export function generateScenarioSlug(query) {
    const slug = query
        .slice(0, 40)
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, '-')
        .replace(/^-+|-+$/g, '')
        .replace(/-{2,}/g, '-');
    const now = new Date();
    const date = [
        now.getFullYear(),
        String(now.getMonth() + 1).padStart(2, '0'),
        String(now.getDate()).padStart(2, '0'),
    ].join('');
    const time = [
        String(now.getHours()).padStart(2, '0'),
        String(now.getMinutes()).padStart(2, '0'),
        String(now.getSeconds()).padStart(2, '0'),
    ].join('');
    return `${slug || 'scenario'}-${date}-${time}`;
}
/**
 * Generate the full branch name for a scenario simulation.
 *
 * Format: scenario/<slugified-query>-<YYYYMMDD>
 */
export function generateScenarioBranchName(query) {
    return `scenario/${generateScenarioSlug(query)}`;
}
/**
 * Generate a branch name for `agentics ask` results.
 *
 * Format: agentics/<slugified-query>-<YYYYMMDD>
 */
export function generateAskBranchName(query) {
    return `agentics/${generateScenarioSlug(query)}`;
}
/**
 * Create and checkout a new scenario branch. Throws on failure.
 */
export function createScenarioBranch(branchName) {
    // If branch already exists, delete it and recreate (same-day reruns)
    const exists = gitExec(`git rev-parse --verify ${branchName}`);
    if (exists !== null) {
        gitExec(`git branch -D ${branchName}`);
    }
    const result = gitExec(`git checkout -b ${branchName}`);
    if (result === null) {
        throw new CLIError({
            code: 'ECLI-GIT-003',
            category: 'INTERNAL_ERROR',
            message: `Failed to create branch '${branchName}'.`,
            details: { branchName },
            module: 'execution-context',
            recoverable: false,
            exitCode: 1,
        });
    }
}
/**
 * Commit all staged and unstaged files with a descriptive message.
 * Returns the commit SHA.
 */
export function commitScenarioFiles(query) {
    const commitMsg = query
        ? `feat: generated prototype — ${query.slice(0, 80)}`
        : 'feat: generated enterprise prototype';
    gitExec('git add -A');
    const commitResult = gitExec(`git commit -m "${commitMsg.replace(/"/g, '\\"')}"`);
    if (commitResult === null) {
        throw new CLIError({
            code: 'ECLI-GIT-003',
            category: 'INTERNAL_ERROR',
            message: 'Failed to commit scenario files.',
            module: 'execution-context',
            recoverable: false,
            exitCode: 1,
        });
    }
    const sha = gitExec('git rev-parse HEAD');
    return sha ?? 'unknown';
}
/**
 * Switch back to the original branch after scenario materialization.
 */
export function checkoutBranch(branchName) {
    const result = gitExec(`git checkout ${branchName}`);
    if (result === null) {
        // Non-fatal — warn but don't crash
        console.error(`  [WARN] Could not switch back to branch '${branchName}'`);
    }
}
//# sourceMappingURL=execution-context.js.map