"use strict";
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 });
exports.githubCiWorkflowRelativePath = void 0;
exports.detectGithubCiRepositoryCapabilities = detectGithubCiRepositoryCapabilities;
exports.detectGithubCiWorkflowStrategy = detectGithubCiWorkflowStrategy;
exports.generateGithubCiGovernanceWorkflow = generateGithubCiGovernanceWorkflow;
exports.generateCiValidationWorkflow = generateCiValidationWorkflow;
const path = __importStar(require("node:path"));
const node_fs_1 = require("node:fs");
const defaultPnpmVersion = '10.0.0';
const defaultYarnVersion = '1.22.22';
exports.githubCiWorkflowRelativePath = '.github/workflows/archpilot-ci.yml';
async function pathExists(targetPath) {
    try {
        await node_fs_1.promises.access(targetPath);
        return true;
    }
    catch {
        return false;
    }
}
async function directoryExists(targetPath) {
    try {
        const stats = await node_fs_1.promises.stat(targetPath);
        return stats.isDirectory();
    }
    catch {
        return false;
    }
}
async function readJsonFile(filePath) {
    if (!(await pathExists(filePath))) {
        return undefined;
    }
    try {
        const raw = await node_fs_1.promises.readFile(filePath, 'utf8');
        return JSON.parse(raw);
    }
    catch {
        return undefined;
    }
}
async function readRootPackageJson(workspaceRoot) {
    return readJsonFile(path.join(workspaceRoot, 'package.json'));
}
function hasWorkspaceConfig(packageJson) {
    if (!packageJson) {
        return false;
    }
    const { workspaces } = packageJson;
    if (Array.isArray(workspaces)) {
        return workspaces.length > 0;
    }
    if (!workspaces || typeof workspaces !== 'object') {
        return false;
    }
    const packages = workspaces.packages;
    return Array.isArray(packages) && packages.length > 0;
}
function extractPackageManagerFromManifest(packageJson) {
    const packageManager = typeof packageJson?.packageManager === 'string'
        ? packageJson.packageManager.trim()
        : undefined;
    if (!packageManager) {
        return undefined;
    }
    if (packageManager.startsWith('pnpm@')) {
        return 'pnpm';
    }
    if (packageManager.startsWith('yarn@')) {
        return 'yarn';
    }
    if (packageManager.startsWith('npm@')) {
        return 'npm';
    }
    return undefined;
}
function hasPnpmPackageManagerDeclaration(packageJson) {
    return typeof packageJson?.packageManager === 'string' && packageJson.packageManager.trim().startsWith('pnpm@');
}
function extractPackageManagerVersion(packageJson, packageManager) {
    const declaration = typeof packageJson?.packageManager === 'string'
        ? packageJson.packageManager.trim()
        : undefined;
    if (!declaration) {
        return undefined;
    }
    const match = new RegExp(`^${packageManager}@([^+\\s]+)`, 'u').exec(declaration);
    return match?.[1];
}
function resolvePackageManager(options) {
    const packageManagerFromManifest = extractPackageManagerFromManifest(options.rootPackageJson);
    if (packageManagerFromManifest) {
        return packageManagerFromManifest;
    }
    if (options.hasPnpmLockfile) {
        return 'pnpm';
    }
    if (options.hasYarnLockfile) {
        return 'yarn';
    }
    if (options.hasNpmLockfile) {
        return 'npm';
    }
    return 'npm';
}
function normalizeScripts(value) {
    if (!value || typeof value !== 'object' || Array.isArray(value)) {
        return {};
    }
    return Object.fromEntries(Object.entries(value)
        .filter((entry) => typeof entry[1] === 'string')
        .map(([key, script]) => [key, script.trim()]));
}
function normalizeDependencies(packageJson) {
    const dependencies = new Set();
    for (const record of [packageJson?.dependencies, packageJson?.devDependencies]) {
        if (!record || typeof record !== 'object' || Array.isArray(record)) {
            continue;
        }
        for (const key of Object.keys(record)) {
            dependencies.add(key);
        }
    }
    return dependencies;
}
function usesLocalArchpilotCli(packageJson) {
    const bin = packageJson?.bin;
    if (!bin) {
        return false;
    }
    if (typeof bin === 'string') {
        return bin.includes('archpilot-cli');
    }
    const archpilotBin = bin.archpilot;
    return typeof archpilotBin === 'string' && archpilotBin.includes('archpilot-cli');
}
function hasScript(packageJson, scriptName) {
    return typeof packageJson?.scripts?.[scriptName] === 'string';
}
function findManifestByPackageName(manifests, packageName) {
    return manifests.find((manifest) => manifest.name === packageName);
}
function detectArchpilotGovernanceWorkspaceLayout(manifests) {
    const coreManifest = findManifestByPackageName(manifests, '@archpilot/core');
    const cliManifest = findManifestByPackageName(manifests, '@archpilotlabs/archpilot');
    const vscodeManifest = findManifestByPackageName(manifests, '@archpilot/vscode-extension') ??
        findManifestByPackageName(manifests, 'archpilot-vscode');
    if (!coreManifest || !cliManifest) {
        return undefined;
    }
    const toLayer = (manifest) => ({
        relativeDir: manifest.relativeDir,
        packageName: manifest.name ?? manifest.relativeDir,
        scripts: manifest.scripts,
    });
    return {
        core: toLayer(coreManifest),
        cli: toLayer(cliManifest),
        ...(vscodeManifest ? { vscode: toLayer(vscodeManifest) } : {}),
    };
}
async function collectPackageManifests(workspaceRoot, rootPackageJson) {
    const manifests = [];
    if (rootPackageJson) {
        manifests.push({
            relativeDir: '.',
            name: typeof rootPackageJson.name === 'string' ? rootPackageJson.name : undefined,
            scripts: normalizeScripts(rootPackageJson.scripts),
            dependencies: normalizeDependencies(rootPackageJson),
        });
    }
    async function walk(relativeDir) {
        const absoluteDir = path.join(workspaceRoot, relativeDir);
        let entries;
        try {
            entries = await node_fs_1.promises.readdir(absoluteDir, { withFileTypes: true });
        }
        catch {
            return;
        }
        for (const entry of entries) {
            if (!entry.isDirectory()) {
                continue;
            }
            if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'dist' || entry.name === '.next') {
                continue;
            }
            const childRelativeDir = relativeDir === '.' ? entry.name : path.posix.join(relativeDir.replace(/\\/g, '/'), entry.name);
            const packageJson = await readJsonFile(path.join(workspaceRoot, childRelativeDir, 'package.json'));
            if (packageJson) {
                manifests.push({
                    relativeDir: childRelativeDir.replace(/\\/g, '/'),
                    name: typeof packageJson.name === 'string' ? packageJson.name : undefined,
                    scripts: normalizeScripts(packageJson.scripts),
                    dependencies: normalizeDependencies(packageJson),
                });
            }
            await walk(childRelativeDir);
        }
    }
    for (const topLevelDir of ['apps', 'packages', 'services']) {
        if (await directoryExists(path.join(workspaceRoot, topLevelDir))) {
            await walk(topLevelDir);
        }
    }
    return manifests;
}
function hasArchpilotDependency(manifests) {
    return manifests.some((manifest) => manifest.dependencies.has('archpilot') || manifest.dependencies.has('archpilot'));
}
const ignoredCapabilityPathSegments = new Set([
    'node_modules',
    '.git',
    'dist',
    '.next',
    '.turbo',
    'coverage',
    'out',
    'build',
    'target',
    'vendor',
    '.venv',
    'venv',
    '__pycache__',
    'test',
    'tests',
    'fixture',
    'fixtures',
    'example',
    'examples',
    'sample',
    'samples',
    'snapshot',
    'snapshots',
    'docs',
    'doc',
]);
function shouldIgnoreCapabilityPath(relativeDir) {
    if (relativeDir === '.') {
        return false;
    }
    return relativeDir
        .replace(/\\/g, '/')
        .split('/')
        .some((segment) => ignoredCapabilityPathSegments.has(segment.toLowerCase()));
}
async function readTextFileSafe(filePath) {
    try {
        return await node_fs_1.promises.readFile(filePath, 'utf8');
    }
    catch {
        return undefined;
    }
}
async function collectRepositoryProjectRoots(workspaceRoot) {
    const projectRoots = new Set();
    async function walk(relativeDir, depth) {
        if (depth > 4 || shouldIgnoreCapabilityPath(relativeDir)) {
            return;
        }
        const absoluteDir = path.join(workspaceRoot, relativeDir);
        let entries;
        try {
            entries = await node_fs_1.promises.readdir(absoluteDir, { withFileTypes: true });
        }
        catch {
            return;
        }
        const fileNames = new Set(entries.filter((entry) => entry.isFile()).map((entry) => entry.name.toLowerCase()));
        const hasTerraformFiles = entries.some((entry) => entry.isFile() && entry.name.toLowerCase().endsWith('.tf'));
        const hasProjectMarker = fileNames.has('package.json') ||
            fileNames.has('pom.xml') ||
            fileNames.has('build.gradle') ||
            fileNames.has('build.gradle.kts') ||
            fileNames.has('requirements.txt') ||
            fileNames.has('pyproject.toml') ||
            fileNames.has('composer.json') ||
            fileNames.has('go.mod') ||
            fileNames.has('ansible.cfg') ||
            hasTerraformFiles;
        if (hasProjectMarker) {
            projectRoots.add(relativeDir);
        }
        for (const entry of entries) {
            if (!entry.isDirectory()) {
                continue;
            }
            if (['node_modules', '.git', 'dist', '.next', '.turbo', 'coverage', 'out', 'build', 'target', 'vendor'].includes(entry.name)) {
                continue;
            }
            const childRelativeDir = relativeDir === '.'
                ? entry.name
                : path.posix.join(relativeDir.replace(/\\/g, '/'), entry.name);
            await walk(childRelativeDir, depth + 1);
        }
    }
    await walk('.', 0);
    return [...projectRoots].sort((left, right) => left.localeCompare(right));
}
function buildPrismaGenerateCommand(packageManager, target) {
    const preferredScript = Object.entries(target.scripts).find(([, script]) => /\bprisma\s+generate\b/iu.test(script))?.[0] ??
        (['prisma:generate', 'db:generate', 'prisma:client'].find((name) => Boolean(target.scripts[name])));
    if (preferredScript) {
        if (target.relativeDir === '.') {
            return `${packageManager} run ${preferredScript}`;
        }
        if (packageManager === 'pnpm' && target.packageName) {
            return `pnpm --filter ${target.packageName} run ${preferredScript}`;
        }
        return `${packageManager} --prefix ${target.relativeDir} run ${preferredScript}`;
    }
    if (target.relativeDir === '.') {
        return `${packageManager} exec prisma generate`;
    }
    if (packageManager === 'pnpm' && target.packageName) {
        return `pnpm --filter ${target.packageName} exec prisma generate`;
    }
    return `${packageManager} --prefix ${target.relativeDir} exec prisma generate`;
}
function hasPrismaScript(scripts) {
    return Object.values(scripts).some((script) => /\bprisma\s+(generate|migrate)\b/iu.test(script));
}
async function detectPrismaTargets(workspaceRoot, packageManager, manifests) {
    const targets = new Map();
    for (const manifest of manifests) {
        const manifestDir = manifest.relativeDir === '.'
            ? workspaceRoot
            : path.join(workspaceRoot, ...manifest.relativeDir.split('/'));
        const schemaPath = path.join(manifestDir, 'prisma', 'schema.prisma');
        const hasSchema = await pathExists(schemaPath);
        const hasPrismaDependency = manifest.dependencies.has('prisma') || manifest.dependencies.has('@prisma/client');
        const hasPrismaEvidence = hasSchema || hasPrismaDependency || hasPrismaScript(manifest.scripts);
        if (!hasPrismaEvidence) {
            continue;
        }
        const normalizedSchemaPath = hasSchema
            ? path.posix.join(manifest.relativeDir === '.' ? '' : manifest.relativeDir, 'prisma', 'schema.prisma').replace(/^\/+/u, '')
            : path.posix.join(manifest.relativeDir === '.' ? '' : manifest.relativeDir, 'prisma', 'schema.prisma').replace(/^\/+/u, '');
        const relativeDir = manifest.relativeDir;
        const scripts = manifest.scripts;
        const packageName = manifest.name;
        const target = {
            relativeDir: relativeDir.length === 0 ? '.' : relativeDir,
            packageName,
            schemaPath: normalizedSchemaPath,
            generateCommand: buildPrismaGenerateCommand(packageManager, {
                relativeDir: relativeDir.length === 0 ? '.' : relativeDir,
                packageName,
                scripts,
            }),
        };
        const key = `${target.relativeDir}::${target.packageName ?? ''}::${target.generateCommand}`;
        if (!targets.has(key)) {
            targets.set(key, target);
        }
    }
    return [...targets.values()];
}
async function detectRootPackageManagerFiles(workspaceRoot) {
    const [hasPnpmLockfile, hasYarnLockfile, hasPackageLockfile, hasNpmShrinkwrap] = await Promise.all([
        pathExists(path.join(workspaceRoot, 'pnpm-lock.yaml')),
        pathExists(path.join(workspaceRoot, 'yarn.lock')),
        pathExists(path.join(workspaceRoot, 'package-lock.json')),
        pathExists(path.join(workspaceRoot, 'npm-shrinkwrap.json')),
    ]);
    return {
        hasPnpmLockfile,
        hasYarnLockfile,
        hasNpmLockfile: hasPackageLockfile || hasNpmShrinkwrap,
        ...(hasPackageLockfile
            ? { npmLockfilePath: 'package-lock.json' }
            : hasNpmShrinkwrap
                ? { npmLockfilePath: 'npm-shrinkwrap.json' }
                : {}),
    };
}
async function detectGithubCiRepositoryCapabilities(workspaceRoot) {
    const rootPackageJson = await readRootPackageJson(workspaceRoot);
    const [{ hasPnpmLockfile, hasNpmLockfile, hasYarnLockfile }, hasPnpmWorkspace, hasAppsDir, hasPackagesDir] = await Promise.all([
        detectRootPackageManagerFiles(workspaceRoot),
        pathExists(path.join(workspaceRoot, 'pnpm-workspace.yaml')),
        directoryExists(path.join(workspaceRoot, 'apps')),
        directoryExists(path.join(workspaceRoot, 'packages')),
    ]);
    const packageManager = resolvePackageManager({
        rootPackageJson,
        hasPnpmLockfile,
        hasNpmLockfile,
        hasYarnLockfile,
    });
    const manifests = await collectPackageManifests(workspaceRoot, rootPackageJson);
    const hasNodeProject = manifests.length > 0;
    const archpilotGovernanceWorkspaceLayout = detectArchpilotGovernanceWorkspaceLayout(manifests);
    const prismaTargets = hasNodeProject
        ? await detectPrismaTargets(workspaceRoot, packageManager, manifests)
        : [];
    const projectRoots = await collectRepositoryProjectRoots(workspaceRoot);
    let hasJavaProject = false;
    let hasPythonProject = false;
    let hasPhpProject = false;
    let hasGoProject = false;
    let hasTerraformProject = false;
    let hasAnsibleProject = false;
    let hasLiquibase = manifests.some((manifest) => Object.values(manifest.scripts).some((script) => /\bliquibase\b/iu.test(script)));
    let hasFlyway = manifests.some((manifest) => Object.values(manifest.scripts).some((script) => /\bflyway\b/iu.test(script)));
    let javaBuildTool;
    let javaBuildCommand;
    let pythonInstallCommand;
    let phpInstallCommand;
    let goBuildCommand;
    for (const relativeDir of projectRoots) {
        const absoluteDir = relativeDir === '.' ? workspaceRoot : path.join(workspaceRoot, ...relativeDir.split('/'));
        const [pomXml, buildGradle, buildGradleKts, mavenWrapper, gradleWrapper, requirementsTxt, pyprojectToml, composerJson, goMod, liquibaseProperties, ansibleCfg,] = await Promise.all([
            pathExists(path.join(absoluteDir, 'pom.xml')),
            pathExists(path.join(absoluteDir, 'build.gradle')),
            pathExists(path.join(absoluteDir, 'build.gradle.kts')),
            pathExists(path.join(absoluteDir, 'mvnw')),
            pathExists(path.join(absoluteDir, 'gradlew')),
            pathExists(path.join(absoluteDir, 'requirements.txt')),
            pathExists(path.join(absoluteDir, 'pyproject.toml')),
            pathExists(path.join(absoluteDir, 'composer.json')),
            pathExists(path.join(absoluteDir, 'go.mod')),
            pathExists(path.join(absoluteDir, 'liquibase.properties')),
            pathExists(path.join(absoluteDir, 'ansible.cfg')),
        ]);
        const [pomText, gradleText, gradleKtsText] = await Promise.all([
            pomXml ? readTextFileSafe(path.join(absoluteDir, 'pom.xml')) : Promise.resolve(undefined),
            buildGradle ? readTextFileSafe(path.join(absoluteDir, 'build.gradle')) : Promise.resolve(undefined),
            buildGradleKts ? readTextFileSafe(path.join(absoluteDir, 'build.gradle.kts')) : Promise.resolve(undefined),
        ]);
        const hasLiquibaseChangelog = await directoryExists(path.join(absoluteDir, 'db', 'changelog'));
        const hasFlywayMigrationDir = await directoryExists(path.join(absoluteDir, 'db', 'migration'));
        const hasFlywayConfig = (await pathExists(path.join(absoluteDir, 'flyway.conf'))) ||
            (await pathExists(path.join(absoluteDir, 'flyway.toml'))) ||
            (await pathExists(path.join(absoluteDir, 'flyway.properties')));
        const hasTerraformFiles = (await node_fs_1.promises.readdir(absoluteDir, { withFileTypes: true }).catch(() => []))
            .some((entry) => entry.isFile() && entry.name.toLowerCase().endsWith('.tf'));
        const hasPlaybookDir = await directoryExists(path.join(absoluteDir, 'playbooks'));
        const hasRolesDir = await directoryExists(path.join(absoluteDir, 'roles'));
        const hasAnsiblePlaybookFiles = (await node_fs_1.promises.readdir(absoluteDir, { withFileTypes: true }).catch(() => []))
            .some((entry) => entry.isFile() &&
            /site|playbook|deploy|provision/u.test(entry.name.toLowerCase()) &&
            (entry.name.toLowerCase().endsWith('.yml') || entry.name.toLowerCase().endsWith('.yaml')));
        if (pomXml || buildGradle || buildGradleKts) {
            hasJavaProject = true;
            if (!javaBuildTool) {
                javaBuildTool = pomXml ? 'maven' : 'gradle';
                javaBuildCommand = pomXml
                    ? (mavenWrapper ? `${relativeDir === '.' ? '.' : relativeDir}/mvnw -B verify` : 'mvn -B verify')
                    : (gradleWrapper ? `${relativeDir === '.' ? '.' : relativeDir}/gradlew build` : 'gradle build');
            }
        }
        if (requirementsTxt || pyprojectToml) {
            hasPythonProject = true;
            if (!pythonInstallCommand && requirementsTxt) {
                pythonInstallCommand = relativeDir === '.'
                    ? 'python -m pip install -r requirements.txt'
                    : `python -m pip install -r ${relativeDir}/requirements.txt`;
            }
        }
        if (composerJson) {
            hasPhpProject = true;
            if (!phpInstallCommand) {
                phpInstallCommand = relativeDir === '.'
                    ? 'composer install --no-interaction --no-progress --prefer-dist'
                    : `composer --working-dir=${relativeDir} install --no-interaction --no-progress --prefer-dist`;
            }
        }
        if (goMod) {
            hasGoProject = true;
            if (!goBuildCommand) {
                goBuildCommand = relativeDir === '.'
                    ? 'go test ./...'
                    : `(cd ${relativeDir} && go test ./...)`;
            }
        }
        if (hasTerraformFiles) {
            hasTerraformProject = true;
        }
        if (ansibleCfg || hasPlaybookDir || hasRolesDir || hasAnsiblePlaybookFiles) {
            hasAnsibleProject = true;
        }
        hasLiquibase =
            hasLiquibase ||
                liquibaseProperties ||
                hasLiquibaseChangelog ||
                /\bliquibase\b/iu.test(pomText ?? '') ||
                /\bliquibase\b/iu.test(gradleText ?? '') ||
                /\bliquibase\b/iu.test(gradleKtsText ?? '');
        hasFlyway =
            hasFlyway ||
                hasFlywayConfig ||
                hasFlywayMigrationDir ||
                /\bflyway\b/iu.test(pomText ?? '') ||
                /\bflyway\b/iu.test(gradleText ?? '') ||
                /\bflyway\b/iu.test(gradleKtsText ?? '');
    }
    return {
        hasNodeProject,
        hasJavaProject,
        hasPythonProject,
        hasPhpProject,
        hasGoProject,
        hasTerraformProject,
        hasAnsibleProject,
        hasMonorepoWorkspaces: hasPnpmWorkspace || hasWorkspaceConfig(rootPackageJson) || (hasAppsDir && hasPackagesDir),
        hasVsCodeExtensionPackaging: Boolean(rootPackageJson?.contributes) ||
            typeof rootPackageJson?.engines === 'object' &&
                typeof (rootPackageJson.engines?.vscode) === 'string',
        hasTurboRepo: await pathExists(path.join(workspaceRoot, 'turbo.json')),
        hasNxWorkspace: await pathExists(path.join(workspaceRoot, 'nx.json')),
        hasLiquibase,
        hasFlyway,
        packageManager: hasNodeProject ? packageManager : undefined,
        ...(javaBuildTool ? { javaBuildTool } : {}),
        ...(pythonInstallCommand ? { pythonInstallCommand } : {}),
        ...(phpInstallCommand ? { phpInstallCommand } : {}),
        ...(goBuildCommand ? { goBuildCommand } : {}),
        ...(javaBuildCommand ? { javaBuildCommand } : {}),
        prismaTargets,
        projectRoots,
        ...(archpilotGovernanceWorkspaceLayout
            ? {
                archpilotGovernanceWorkspaceLayout: {
                    corePackageName: archpilotGovernanceWorkspaceLayout.core.packageName,
                    cliPackageName: archpilotGovernanceWorkspaceLayout.cli.packageName,
                    ...(archpilotGovernanceWorkspaceLayout.vscode
                        ? { vscodePackageName: archpilotGovernanceWorkspaceLayout.vscode.packageName }
                        : {}),
                },
            }
            : {}),
    };
}
function buildValidationCommand(packageManager, options) {
    void options.usesLocalCli;
    void options.hasArchpilotBinary;
    const workspaceCliPrefix = buildArchpilotCliCommandPrefix(packageManager);
    if (options.usesLocalCli) {
        return {
            buildCommand: `${packageManager} run compile`,
            validationCommand: `${workspaceCliPrefix} validate --ci`,
            uploadCommand: `${workspaceCliPrefix} governance upload`,
            validationUsesLocalResolution: false,
        };
    }
    if (options.hasArchpilotBinary) {
        return {
            validationCommand: `${workspaceCliPrefix} validate --ci`,
            uploadCommand: `${workspaceCliPrefix} governance upload`,
            validationUsesLocalResolution: false,
        };
    }
    return {
        validationCommand: `${workspaceCliPrefix} validate --ci`,
        uploadCommand: `${workspaceCliPrefix} governance upload`,
        validationUsesLocalResolution: false,
    };
}
function buildBuildCommand(packageManager, rootPackageJson, isWorkspaceRepo, manifests) {
    if (hasScript(rootPackageJson, 'build')) {
        return `${packageManager} run build`;
    }
    if (isWorkspaceRepo && packageManager === 'pnpm') {
        const workspaceManifests = manifests.filter((manifest) => manifest.relativeDir !== '.');
        const buildableManifests = workspaceManifests.filter((manifest) => Boolean(manifest.scripts.build));
        if (buildableManifests.length === 0) {
            return undefined;
        }
        if (buildableManifests.length === workspaceManifests.length) {
            return 'pnpm -r build';
        }
        return 'pnpm -r --if-present build';
    }
    return undefined;
}
function buildScopedWorkspaceOption(flagName, values) {
    return values.map((value) => `${flagName} ${value}`).join(' ');
}
function buildArchpilotGovernanceInstallCommand(packageManager, hasRootLockfile, layout, packageManagerVersion) {
    const governancePackages = [layout.core.packageName, layout.cli.packageName];
    switch (packageManager) {
        case 'pnpm': {
            const installBase = hasRootLockfile ? 'pnpm install --frozen-lockfile' : 'pnpm install --no-frozen-lockfile';
            return installBase;
        }
        case 'yarn':
            return hasRootLockfile
                ? ((packageManagerVersion && !packageManagerVersion.startsWith('1.')) ? 'yarn install --immutable' : 'yarn install --frozen-lockfile')
                : 'yarn install';
        case 'npm':
        default: {
            const installBase = hasRootLockfile ? 'npm ci' : 'npm install';
            return `${installBase} ${buildScopedWorkspaceOption('--workspace', governancePackages)}`.trim();
        }
    }
}
function buildArchpilotGovernanceBuildCommand(packageManager, layout) {
    const buildablePackages = [layout.core, layout.cli].filter((pkg) => Boolean(pkg.scripts.build));
    if (buildablePackages.length === 0) {
        return undefined;
    }
    const commands = buildablePackages.map((pkg) => {
        switch (packageManager) {
            case 'pnpm':
                return `pnpm --filter ${pkg.packageName} run build`;
            case 'yarn':
                return `yarn workspace ${pkg.packageName} run build`;
            case 'npm':
            default:
                return `npm run build --workspace ${pkg.packageName}`;
        }
    });
    return commands.join('\n');
}
function filterPrismaTargetsForWorkspaceLayout(prismaTargets, layout) {
    if (!layout) {
        return prismaTargets;
    }
    const governancePackageNames = new Set([layout.core.packageName, layout.cli.packageName]);
    const governanceRelativeDirs = new Set([layout.core.relativeDir, layout.cli.relativeDir]);
    return prismaTargets.filter((target) => (target.packageName ? governancePackageNames.has(target.packageName) : false) ||
        governanceRelativeDirs.has(target.relativeDir));
}
function appendRunCommand(lines, command, indent = '        ') {
    if (command.includes('\n')) {
        lines.push(`${indent}run: |`);
        for (const line of command.split('\n')) {
            lines.push(`${indent}  ${line}`);
        }
        return;
    }
    lines.push(`${indent}run: ${command}`);
}
function buildArchpilotCliCommandPrefix(packageManager) {
    switch (packageManager) {
        case 'pnpm':
            return 'pnpm dlx @archpilotlabs/archpilot';
        case 'yarn':
            return 'yarn dlx @archpilotlabs/archpilot';
        case 'npm':
        default:
            return 'npx @archpilotlabs/archpilot';
    }
}
function renderSetupSteps(strategy) {
    const steps = [
        '      - name: Checkout repository',
        '        uses: actions/checkout@v4',
        '        with:',
        '          fetch-depth: 0',
        '',
    ];
    const usesCorepack = strategy.hasNodeProject && (strategy.packageManager === 'pnpm' ||
        strategy.packageManager === 'yarn');
    if (usesCorepack) {
        steps.push('      - name: Enable Corepack');
        steps.push('        run: corepack enable');
        steps.push('');
    }
    if (strategy.hasNodeProject) {
        steps.push('      - name: Setup Node.js');
        steps.push('        uses: actions/setup-node@v4');
        steps.push('        with:');
        steps.push(`          node-version: ${strategy.packageManager === 'pnpm' ? '20' : '22'}`);
        if ((strategy.packageManager === 'npm' && strategy.hasRootLockfile) ||
            strategy.packageManager === 'pnpm' ||
            strategy.packageManager === 'yarn') {
            steps.push(`          cache: ${strategy.packageManager}`);
            if (strategy.cacheDependencyPath) {
                steps.push(`          cache-dependency-path: ${strategy.cacheDependencyPath}`);
            }
        }
        steps.push('');
    }
    if (strategy.hasNodeProject && strategy.packageManager === 'pnpm') {
        steps.push('      - name: Prepare pnpm');
        steps.push(`        run: corepack prepare pnpm@${strategy.packageManagerVersion ?? defaultPnpmVersion} --activate`);
        steps.push('');
    }
    if (strategy.hasNodeProject && strategy.packageManager === 'yarn') {
        steps.push('      - name: Prepare Yarn');
        steps.push(`        run: corepack prepare yarn@${strategy.packageManagerVersion ?? defaultYarnVersion} --activate`);
        steps.push('');
    }
    if (strategy.capabilities.hasJavaProject) {
        steps.push('      - name: Setup Java');
        steps.push('        uses: actions/setup-java@v4');
        steps.push('        with:');
        steps.push('          distribution: temurin');
        steps.push('          java-version: 17');
        steps.push('');
    }
    if (strategy.capabilities.hasPythonProject) {
        steps.push('      - name: Setup Python');
        steps.push('        uses: actions/setup-python@v5');
        steps.push('        with:');
        steps.push('          python-version: "3.12"');
        steps.push('');
    }
    if (strategy.capabilities.hasPhpProject) {
        steps.push('      - name: Setup PHP');
        steps.push('        uses: shivammathur/setup-php@v2');
        steps.push('        with:');
        steps.push('          php-version: "8.2"');
        steps.push('');
    }
    if (strategy.capabilities.hasGoProject) {
        steps.push('      - name: Setup Go');
        steps.push('        uses: actions/setup-go@v5');
        steps.push('        with:');
        steps.push('          go-version: "1.22"');
        steps.push('');
    }
    return steps;
}
function renderInstallSteps(strategy) {
    const steps = [];
    if (strategy.hasNodeProject) {
        steps.push(`      - name: ${strategy.installStepName ?? 'Install dependencies'}`);
        appendRunCommand(steps, strategy.installCommand);
    }
    if (strategy.capabilities.pythonInstallCommand) {
        steps.push('');
        steps.push('      - name: Install Python dependencies');
        steps.push(`        run: ${strategy.capabilities.pythonInstallCommand}`);
    }
    if (strategy.capabilities.phpInstallCommand) {
        steps.push('');
        steps.push('      - name: Install PHP dependencies');
        steps.push(`        run: ${strategy.capabilities.phpInstallCommand}`);
    }
    return steps;
}
function renderBuildAndToolingSteps(strategy) {
    const steps = [];
    for (const prismaTarget of strategy.prismaTargets) {
        steps.push('');
        steps.push(`      - name: Generate Prisma client (${prismaTarget.relativeDir})`);
        appendRunCommand(steps, prismaTarget.generateCommand);
    }
    if (strategy.buildCommand) {
        steps.push('');
        steps.push(`      - name: ${strategy.buildStepName ?? 'Build repository'}`);
        appendRunCommand(steps, strategy.buildCommand);
    }
    if (strategy.capabilities.javaBuildCommand) {
        steps.push('');
        steps.push('      - name: Build Java project');
        steps.push(`        run: ${strategy.capabilities.javaBuildCommand}`);
    }
    if (strategy.capabilities.goBuildCommand) {
        steps.push('');
        steps.push('      - name: Test Go project');
        steps.push(`        run: ${strategy.capabilities.goBuildCommand}`);
    }
    return steps;
}
async function detectGithubCiWorkflowStrategy(workspaceRoot) {
    const rootPackageJson = await readRootPackageJson(workspaceRoot);
    const [{ hasPnpmLockfile, hasNpmLockfile, hasYarnLockfile, npmLockfilePath }, capabilities] = await Promise.all([
        detectRootPackageManagerFiles(workspaceRoot),
        detectGithubCiRepositoryCapabilities(workspaceRoot),
    ]);
    const packageManager = resolvePackageManager({
        rootPackageJson,
        hasPnpmLockfile,
        hasNpmLockfile,
        hasYarnLockfile,
    });
    const hasRootLockfile = packageManager === 'pnpm'
        ? hasPnpmLockfile
        : packageManager === 'yarn'
            ? hasYarnLockfile
            : hasNpmLockfile;
    const isWorkspaceRepo = capabilities.hasMonorepoWorkspaces;
    const manifests = await collectPackageManifests(workspaceRoot, rootPackageJson);
    const hasNodeProject = capabilities.hasNodeProject;
    const packageManagerVersion = extractPackageManagerVersion(rootPackageJson, packageManager);
    const archpilotGovernanceWorkspaceLayout = detectArchpilotGovernanceWorkspaceLayout(manifests);
    const prismaTargets = filterPrismaTargetsForWorkspaceLayout(capabilities.prismaTargets, archpilotGovernanceWorkspaceLayout);
    let installCommand = 'npm install';
    let cacheDependencyPath;
    switch (packageManager) {
        case 'pnpm':
            installCommand = hasRootLockfile ? 'pnpm install --frozen-lockfile' : 'pnpm install --no-frozen-lockfile';
            cacheDependencyPath = 'pnpm-lock.yaml';
            break;
        case 'yarn':
            installCommand = hasRootLockfile
                ? ((packageManagerVersion && !packageManagerVersion.startsWith('1.')) ? 'yarn install --immutable' : 'yarn install --frozen-lockfile')
                : 'yarn install';
            cacheDependencyPath = hasRootLockfile ? 'yarn.lock' : undefined;
            break;
        case 'npm':
        default:
            installCommand = hasRootLockfile ? 'npm ci' : 'npm install';
            cacheDependencyPath = hasRootLockfile ? npmLockfilePath : undefined;
            break;
    }
    if (archpilotGovernanceWorkspaceLayout) {
        installCommand = buildArchpilotGovernanceInstallCommand(packageManager, hasRootLockfile, archpilotGovernanceWorkspaceLayout, packageManagerVersion);
    }
    const localCliEnabled = usesLocalArchpilotCli(rootPackageJson);
    const hasArchpilotBinary = localCliEnabled || hasArchpilotDependency(manifests);
    const validationStrategy = buildValidationCommand(packageManager, {
        usesLocalCli: localCliEnabled && hasScript(rootPackageJson, 'compile'),
        hasArchpilotBinary,
    });
    const buildCommand = validationStrategy.buildCommand ??
        (archpilotGovernanceWorkspaceLayout
            ? buildArchpilotGovernanceBuildCommand(packageManager, archpilotGovernanceWorkspaceLayout)
            : undefined) ??
        buildBuildCommand(packageManager, rootPackageJson, isWorkspaceRepo, manifests);
    return {
        packageManager,
        ...(packageManagerVersion ? { packageManagerVersion } : {}),
        hasPnpmPackageManagerDeclaration: hasPnpmPackageManagerDeclaration(rootPackageJson),
        hasNodeProject,
        hasRootPackageJson: Boolean(rootPackageJson),
        hasRootLockfile,
        isWorkspaceRepo,
        installCommand,
        buildCommand,
        ...(validationStrategy.validationCommand
            ? { validationCommand: validationStrategy.validationCommand }
            : {}),
        ...(validationStrategy.uploadCommand ? { uploadCommand: validationStrategy.uploadCommand } : {}),
        validationUsesLocalResolution: validationStrategy.validationUsesLocalResolution,
        ...(validationStrategy.validationOmittedReason
            ? { validationOmittedReason: validationStrategy.validationOmittedReason }
            : {}),
        usesLocalArchpilotCli: localCliEnabled,
        hasArchpilotBinary,
        ...(cacheDependencyPath ? { cacheDependencyPath } : {}),
        prismaTargets,
        ...(archpilotGovernanceWorkspaceLayout
            ? {
                installStepName: 'Install ArchPilot governance dependencies',
            }
            : {}),
        capabilities,
    };
}
async function generateGithubCiGovernanceWorkflow(workspaceRoot) {
    const strategy = await detectGithubCiWorkflowStrategy(workspaceRoot);
    const setupSteps = renderSetupSteps(strategy);
    const archpilotCliPrefix = buildArchpilotCliCommandPrefix(strategy.packageManager);
    const workflowLines = [
        'name: ArchPilot CI Governance',
        '',
        'on:',
        '  pull_request:',
        '  workflow_dispatch:',
        '    inputs:',
        '      drift_policy:',
        "        description: 'How baseline drift should affect the workflow result'",
        '        required: false',
        "        default: 'warn'",
        '        type: choice',
        '        options:',
        "          - 'warn'",
        "          - 'fail'",
        '  push:',
        '    branches:',
        '      - main',
        '',
        'jobs:',
        '  validate-architecture:',
        '    runs-on: ubuntu-latest',
        '    permissions:',
        '      contents: read',
        '      pull-requests: write',
        '    steps:',
        ...setupSteps,
    ];
    const installSteps = renderInstallSteps(strategy);
    if (installSteps.length > 0) {
        workflowLines.push('');
        workflowLines.push(...installSteps);
    }
    const buildAndToolingSteps = renderBuildAndToolingSteps(strategy);
    if (buildAndToolingSteps.length > 0) {
        workflowLines.push(...buildAndToolingSteps);
    }
    workflowLines.push('');
    workflowLines.push('      - name: Print GitHub event context');
    workflowLines.push('        run: |');
    workflowLines.push('          echo "github.event_name=${{ github.event_name }}"');
    workflowLines.push('          echo "github.ref=${{ github.ref }}"');
    workflowLines.push('          echo "github.base_ref=${{ github.base_ref }}"');
    workflowLines.push('          echo "github.head_ref=${{ github.head_ref }}"');
    workflowLines.push('');
    workflowLines.push('      - name: Run ArchPilot CI validation');
    workflowLines.push('        id: archpilot_validate');
    workflowLines.push('        continue-on-error: true');
    workflowLines.push(`        run: ${strategy.validationCommand ?? `${archpilotCliPrefix} validate --ci`}`);
    workflowLines.push('');
    workflowLines.push('      - name: Run ArchPilot baseline drift check');
    workflowLines.push("        if: github.event_name == 'pull_request' && steps.archpilot_validate.outcome == 'success'");
    workflowLines.push('        id: archpilot_baseline');
    workflowLines.push('        continue-on-error: true');
    workflowLines.push('        shell: bash');
    workflowLines.push('        run: |');
    workflowLines.push('          set +e');
    workflowLines.push(`          ${archpilotCliPrefix} baseline check`);
    workflowLines.push('          drift_exit=$?');
    workflowLines.push('          echo "exit_code=$drift_exit" >> "$GITHUB_OUTPUT"');
    workflowLines.push('          exit "$drift_exit"');
    workflowLines.push('');
    workflowLines.push('      - name: Generate ArchPilot PR review');
    workflowLines.push("        if: github.event_name == 'pull_request' && steps.archpilot_validate.outcome == 'success'");
    workflowLines.push('        id: archpilot_pr_review');
    workflowLines.push('        continue-on-error: true');
    workflowLines.push(`        run: ${archpilotCliPrefix} review pr`);
    workflowLines.push('');
    workflowLines.push('      - name: Publish ArchPilot PR comment');
    workflowLines.push("        if: github.event_name == 'pull_request' && steps.archpilot_validate.outcome == 'success'");
    workflowLines.push('        id: archpilot_pr_comment');
    workflowLines.push('        continue-on-error: true');
    workflowLines.push('        env:');
    workflowLines.push('          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}');
    workflowLines.push(`        run: ${archpilotCliPrefix} ci github`);
    workflowLines.push('');
    workflowLines.push('      - name: Upload ArchPilot governance snapshot');
    workflowLines.push("        if: steps.archpilot_validate.outcome == 'success' && github.event_name == 'push' && github.ref == 'refs/heads/main'");
    workflowLines.push('        env:');
    workflowLines.push('          ARCHPILOT_API_TOKEN: ${{ secrets.ARCHPILOT_API_TOKEN }}');
    workflowLines.push('          ARCHPILOT_UPLOAD_MODE: ci');
    workflowLines.push('          CI: "true"');
    workflowLines.push('        shell: bash');
    workflowLines.push('        run: |');
    workflowLines.push('          if [ -z "$ARCHPILOT_API_TOKEN" ]; then');
    workflowLines.push('            echo "ArchPilot governance upload skipped because ARCHPILOT_API_TOKEN secret is not configured."');
    workflowLines.push('            exit 0');
    workflowLines.push('          fi');
    workflowLines.push('');
    workflowLines.push(`          ${(strategy.uploadCommand ?? `${archpilotCliPrefix} governance upload`)} --token "\${ARCHPILOT_API_TOKEN}"`);
    workflowLines.push('');
    workflowLines.push('      # Required repository secrets for main-branch upload:');
    workflowLines.push('      # - ARCHPILOT_API_TOKEN');
    workflowLines.push('');
    workflowLines.push('      - name: Finalize workflow result');
    workflowLines.push('        if: always()');
    workflowLines.push('        env:');
    workflowLines.push('          VALIDATION_OUTCOME: ${{ steps.archpilot_validate.outcome }}');
    workflowLines.push('          BASELINE_OUTCOME: ${{ steps.archpilot_baseline.outcome }}');
    workflowLines.push('          BASELINE_EXIT_CODE: ${{ steps.archpilot_baseline.outputs.exit_code }}');
    workflowLines.push('          PR_REVIEW_OUTCOME: ${{ steps.archpilot_pr_review.outcome }}');
    workflowLines.push('          PR_COMMENT_OUTCOME: ${{ steps.archpilot_pr_comment.outcome }}');
    workflowLines.push("          DRIFT_POLICY: ${{ github.event_name == 'workflow_dispatch' && inputs.drift_policy || 'warn' }}");
    workflowLines.push('        shell: bash');
    workflowLines.push('        run: |');
    workflowLines.push('          if [ "$VALIDATION_OUTCOME" = "failure" ]; then');
    workflowLines.push('            echo "ArchPilot validation failed."');
    workflowLines.push('            exit 1');
    workflowLines.push('          fi');
    workflowLines.push('');
    workflowLines.push('          if [ "$BASELINE_OUTCOME" = "failure" ]; then');
    workflowLines.push('            if [ "$BASELINE_EXIT_CODE" = "2" ]; then');
    workflowLines.push('              echo "ArchPilot baseline check could not complete because the baseline is missing or invalid."');
    workflowLines.push('              echo "Run `archpilot baseline create` to enable drift tracking. Continuing without failing CI."');
    workflowLines.push('              exit 0');
    workflowLines.push('            fi');
    workflowLines.push('');
    workflowLines.push('            if [ "$BASELINE_EXIT_CODE" = "1" ]; then');
    workflowLines.push('              if [ "$DRIFT_POLICY" = "fail" ]; then');
    workflowLines.push('                echo "ArchPilot baseline drift detected and drift policy is fail."');
    workflowLines.push('                exit 1');
    workflowLines.push('              fi');
    workflowLines.push('');
    workflowLines.push('              echo "ArchPilot baseline drift detected, but drift policy is warn. Continuing."');
    workflowLines.push('              exit 0');
    workflowLines.push('            fi');
    workflowLines.push('');
    workflowLines.push('            if [ -n "$BASELINE_EXIT_CODE" ]; then');
    workflowLines.push('              echo "ArchPilot baseline check failed unexpectedly with exit code $BASELINE_EXIT_CODE."');
    workflowLines.push('            else');
    workflowLines.push('              echo "ArchPilot baseline check failed unexpectedly without an exit code."');
    workflowLines.push('            fi');
    workflowLines.push('            exit 1');
    workflowLines.push('          fi');
    workflowLines.push('');
    workflowLines.push('          if [ "$PR_REVIEW_OUTCOME" = "failure" ]; then');
    workflowLines.push('            echo "ArchPilot PR review generation failed, but validation passed. Continuing because reporting is non-blocking."');
    workflowLines.push('          fi');
    workflowLines.push('');
    workflowLines.push('          if [ "$PR_COMMENT_OUTCOME" = "failure" ]; then');
    workflowLines.push('            echo "ArchPilot PR comment publishing failed, but validation passed. Continuing because reporting is non-blocking."');
    workflowLines.push('          fi');
    workflowLines.push('');
    workflowLines.push('          echo "ArchPilot workflow completed successfully."');
    workflowLines.push('');
    return workflowLines.join('\n');
}
async function generateCiValidationWorkflow(provider, workspaceRoot) {
    switch (provider) {
        case 'github':
            return generateGithubCiGovernanceWorkflow(workspaceRoot);
        case 'gitlab':
        case 'azure':
        case 'bitbucket':
        case 'jenkins':
        default:
            throw new Error(`CI provider '${provider}' is not supported yet.`);
    }
}
//# sourceMappingURL=ciWorkflowTemplates.js.map