"use strict";
// src/orchestrator/ProjectMetadata.ts
// Read/write `.openlife/project.json` — records the project's mode
// (greenfield / brownfield / not-applicable), detected stack, and
// recommended entry workflow. Consumed by `/openlife:start` and the
// install wizard's project-mode phase.
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.projectMetadataPath = projectMetadataPath;
exports.readProjectMetadata = readProjectMetadata;
exports.writeProjectMetadata = writeProjectMetadata;
exports.detectStack = detectStack;
exports.detectMode = detectMode;
exports.recommendWorkflow = recommendWorkflow;
exports.buildMetadata = buildMetadata;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const FILE_REL = path.join('.openlife', 'project.json');
/** Resolve the metadata file path relative to a root (default: process.cwd()). */
function projectMetadataPath(root = process.cwd()) {
    return path.join(root, FILE_REL);
}
/** Read existing metadata, returning null if file is missing or unparseable. */
function readProjectMetadata(root = process.cwd()) {
    const fp = projectMetadataPath(root);
    if (!fs.existsSync(fp))
        return null;
    try {
        const parsed = JSON.parse(fs.readFileSync(fp, 'utf-8'));
        if (!parsed.mode || !parsed.createdAt)
            return null;
        return {
            mode: parsed.mode,
            createdAt: parsed.createdAt,
            updatedAt: parsed.updatedAt || parsed.createdAt,
            detectedStack: parsed.detectedStack || [],
            recommendedWorkflow: parsed.recommendedWorkflow || recommendWorkflow(parsed.mode, parsed.detectedStack || []),
            notes: parsed.notes,
        };
    }
    catch {
        return null;
    }
}
/** Write metadata, creating .openlife/ if necessary. */
function writeProjectMetadata(meta, root = process.cwd()) {
    const fp = projectMetadataPath(root);
    fs.mkdirSync(path.dirname(fp), { recursive: true });
    fs.writeFileSync(fp, JSON.stringify(meta, null, 2) + '\n');
    return fp;
}
/**
 * Detect the project's stack from cwd. Cheap heuristic — file presence only,
 * does not parse contents. Used to suggest a default mode and a recommended
 * workflow in the install wizard.
 */
function detectStack(root = process.cwd()) {
    const stack = [];
    if (fs.existsSync(path.join(root, 'package.json'))) {
        stack.push('node');
        try {
            const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf-8'));
            if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript)
                stack.push('typescript');
            if (pkg.dependencies?.react || pkg.dependencies?.next)
                stack.push('react');
            if (pkg.dependencies?.vue || pkg.dependencies?.nuxt)
                stack.push('vue');
            if (pkg.dependencies?.svelte)
                stack.push('svelte');
            if (pkg.dependencies?.express || pkg.dependencies?.fastify || pkg.dependencies?.hono)
                stack.push('node-server');
        }
        catch { /* ignore */ }
    }
    if (fs.existsSync(path.join(root, 'go.mod')))
        stack.push('go');
    if (fs.existsSync(path.join(root, 'Cargo.toml')))
        stack.push('rust');
    if (fs.existsSync(path.join(root, 'pyproject.toml')) || fs.existsSync(path.join(root, 'requirements.txt')))
        stack.push('python');
    if (fs.existsSync(path.join(root, 'Gemfile')))
        stack.push('ruby');
    if (fs.existsSync(path.join(root, 'composer.json')))
        stack.push('php');
    if (fs.existsSync(path.join(root, 'pubspec.yaml')))
        stack.push('flutter');
    if (fs.existsSync(path.join(root, 'docker-compose.yml')) || fs.existsSync(path.join(root, 'Dockerfile')))
        stack.push('docker');
    if (fs.existsSync(path.join(root, 'supabase')))
        stack.push('supabase');
    if (fs.existsSync(path.join(root, 'prisma')))
        stack.push('prisma');
    return stack;
}
/**
 * Detect mode hint from cwd. Returns `brownfield` if cwd appears to be an
 * established project (presence of stack files AND > 10 git commits OR a
 * non-trivial src/ folder); `greenfield` otherwise.
 */
function detectMode(root = process.cwd()) {
    const stack = detectStack(root);
    if (stack.length === 0)
        return 'greenfield';
    const gitDir = path.join(root, '.git');
    if (fs.existsSync(gitDir)) {
        try {
            const { execFileSync } = require('child_process');
            const count = execFileSync('git', ['rev-list', '--count', 'HEAD'], {
                cwd: root, encoding: 'utf-8', timeout: 5000,
            }).trim();
            if (parseInt(count, 10) > 10)
                return 'brownfield';
        }
        catch { /* ignore */ }
    }
    // Has stack but no git history → likely greenfield setup-in-progress
    return 'greenfield';
}
/** Map (mode, stack) to a recommended workflow id from dist-templates/workflows/. */
function recommendWorkflow(mode, stack) {
    if (mode === 'not-applicable')
        return 'spec-pipeline';
    const hasUI = stack.some((s) => ['react', 'vue', 'svelte', 'flutter'].includes(s));
    const hasServer = stack.some((s) => ['node-server', 'go', 'rust', 'python', 'ruby', 'php'].includes(s));
    if (mode === 'brownfield') {
        // Brownfield always starts with discovery the first time.
        return 'brownfield-blueprint';
    }
    // Greenfield
    if (hasUI && hasServer)
        return 'greenfield-fullstack';
    if (hasUI)
        return 'greenfield-ui';
    if (hasServer)
        return 'greenfield-service';
    return 'greenfield-fullstack';
}
/** Convenience: build a fresh ProjectMetadata for a chosen mode. */
function buildMetadata(mode, root = process.cwd(), notes) {
    const now = new Date().toISOString();
    const stack = detectStack(root);
    return {
        mode,
        createdAt: now,
        updatedAt: now,
        detectedStack: stack,
        recommendedWorkflow: recommendWorkflow(mode, stack),
        notes,
    };
}
