#!/usr/bin/env node
// Copyright (c) 2026 Hellmai Ltd
// SPDX-License-Identifier: AGPL-3.0-only
/**
 * Plan Create Command (WU-1313)
 *
 * Creates plan files in the repo-native plansDir (not LUMENFLOW_HOME).
 * Plans can be linked to WUs (via spec_refs) or initiatives (via related_plan).
 *
 * Usage:
 *   pnpm plan:create --id WU-1313 --title "Feature plan"
 *   pnpm plan:create --id INIT-001 --title "Initiative plan"
 *
 * Features:
 * - Creates plan in repo directories.plansDir
 * - Supports both WU-XXX and INIT-XXX IDs
 * - Uses micro-worktree isolation for atomic commits
 * - Idempotent: fails if plan already exists (no overwrite)
 *
 * Context: WU-1313 (INIT-013 Plan Tooling)
 */
import { getGitForCwd } from '@lumenflow/core/git-adapter';
import { die } from '@lumenflow/core/error-handler';
import { existsSync, writeFileSync, mkdirSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import { createWUParser, WU_OPTIONS } from '@lumenflow/core/arg-parser';
import { ensureOnMain } from '@lumenflow/core/wu-helpers';
import { withMicroWorktree } from '@lumenflow/core/micro-worktree';
import { WU_PATHS } from '@lumenflow/core/wu-paths';
import { todayISO } from '@lumenflow/core/date-utils';
import { LOG_PREFIX as CORE_LOG_PREFIX } from '@lumenflow/core/wu-constants';
/** Log prefix for console output */
export const LOG_PREFIX = CORE_LOG_PREFIX.PLAN_CREATE ?? '[plan:create]';
/** Micro-worktree operation name */
const OPERATION_NAME = 'plan-create';
/** LumenFlow URI scheme for plan references */
const PLAN_URI_SCHEME = 'lumenflow://plans/';
/** WU ID pattern */
const WU_ID_PATTERN = /^WU-\d+$/;
/** Initiative ID pattern */
const INIT_ID_PATTERN = /^INIT-[A-Z0-9]+$/i;
/**
 * Validate that the ID is a valid WU or Initiative ID
 *
 * @param id - ID to validate (WU-XXX or INIT-XXX)
 * @throws Error if ID format is invalid
 */
export function validatePlanId(id) {
    if (!id) {
        die(`ID is required\n\nExpected format: WU-XXX or INIT-XXX`);
    }
    const isWU = WU_ID_PATTERN.test(id);
    const isInit = INIT_ID_PATTERN.test(id);
    if (!isWU && !isInit) {
        die(`Invalid ID format: "${id}"\n\n` +
            `Expected format:\n` +
            `  - WU ID: WU-<number> (e.g., WU-1313)\n` +
            `  - Initiative ID: INIT-<alphanumeric> (e.g., INIT-001, INIT-TOOLING)`);
    }
}
/**
 * Get the lumenflow:// URI for a plan
 *
 * @param id - WU or Initiative ID
 * @returns lumenflow://plans/{id}-plan.md URI
 */
export function getPlanUri(id) {
    return `${PLAN_URI_SCHEME}${id}-plan.md`;
}
/**
 * Validate that a --from source path is a readable .md file
 *
 * @param fromPath - Path to source file
 * @throws Error if file doesn't exist or isn't .md
 */
export function validateFromPath(fromPath) {
    if (!fromPath.endsWith('.md')) {
        die(`Invalid source file format: "${fromPath}"\n\nSource file must be markdown (.md)`);
    }
    if (!existsSync(fromPath)) {
        die(`Source file not found: "${fromPath}"\n\nProvide a valid path to an existing .md file`);
    }
}
/**
 * Create a plan file in the repo plansDir
 *
 * @param worktreePath - Path to repo root or worktree
 * @param id - WU or Initiative ID
 * @param title - Plan title
 * @param fromPath - Optional path to external file whose content replaces the template
 * @returns Path to created file
 * @throws Error if file already exists
 */
export function createPlan(worktreePath, id, title, fromPath) {
    const plansDir = join(worktreePath, WU_PATHS.PLANS_DIR());
    const planPath = join(plansDir, `${id}-plan.md`);
    if (existsSync(planPath)) {
        die(`Plan file already exists: ${planPath}\n\n` +
            `Options:\n` +
            `  1. Edit the existing plan: pnpm plan:edit --id ${id}\n` +
            `  2. Delete and recreate (not recommended)\n` +
            `  3. Use plan:link to link existing plan to a WU/initiative`);
    }
    // Ensure plans directory exists
    if (!existsSync(plansDir)) {
        mkdirSync(plansDir, { recursive: true });
    }
    let content;
    if (fromPath) {
        content = readFileSync(fromPath, { encoding: 'utf-8' });
        console.log(`${LOG_PREFIX} Imported content from: ${fromPath}`);
    }
    else {
        const today = todayISO();
        content = `# ${id} Plan - ${title}

Created: ${today}

## Goal

<!-- What is the primary objective? -->

## Scope

<!-- What is in scope and out of scope? -->

## Approach

<!-- How will you achieve the goal? Key phases or milestones? -->

## Success Criteria

<!-- How will you know when this is complete? Measurable outcomes? -->

## Risks

<!-- What could go wrong? How will you mitigate? -->

## Open Questions

<!-- Unresolved questions or decisions needed -->

## References

- ID: ${id}
- Created: ${today}
`;
    }
    writeFileSync(planPath, content, { encoding: 'utf-8' });
    console.log(`${LOG_PREFIX} Created plan: ${planPath}`);
    return planPath;
}
/**
 * Generate commit message for plan creation
 *
 * @param id - WU or Initiative ID
 * @param title - Plan title
 * @returns Commit message
 */
export function getCommitMessage(id, title) {
    const idLower = id.toLowerCase();
    return `docs: create plan for ${idLower} - ${title}`;
}
/** CLI option for importing content from an external file */
const FROM_OPTION = {
    name: 'from',
    flags: '--from <path>',
    description: 'Import content from an external markdown file instead of generating a blank template',
};
export async function main() {
    const args = createWUParser({
        name: 'plan-create',
        description: 'Create a new plan file in repo plansDir',
        options: [WU_OPTIONS.id, WU_OPTIONS.title, FROM_OPTION],
        required: ['id', 'title'],
        allowPositionalId: true,
    });
    const id = args.id;
    const title = args.title;
    const fromPath = args.from;
    // Validate inputs
    validatePlanId(id);
    if (fromPath) {
        validateFromPath(fromPath);
    }
    console.log(`${LOG_PREFIX} Creating plan for ${id}...`);
    // Ensure on main for micro-worktree operations
    await ensureOnMain(getGitForCwd());
    let createdPlanPath = '';
    const planRelPath = `${WU_PATHS.PLANS_DIR()}/${id}-plan.md`;
    try {
        const result = await withMicroWorktree({
            operation: OPERATION_NAME,
            id,
            logPrefix: LOG_PREFIX,
            pushOnly: true,
            execute: async ({ worktreePath }) => {
                // Create plan file (with optional external content)
                createdPlanPath = createPlan(worktreePath, id, title, fromPath);
                // Get relative path for commit
                const relPath = createdPlanPath.replace(worktreePath + '/', '');
                return {
                    commitMessage: getCommitMessage(id, title),
                    files: [relPath],
                };
            },
        });
        // WU-2391: Verify plan file actually landed on the target branch.
        // withMicroWorktree can resolve without error even when the commit
        // silently fails to land (observed in lumenflow-cloud WU-645).
        const mainGit = getGitForCwd();
        const verifyRef = result.ref;
        console.log(`${LOG_PREFIX} Verifying plan file on ${verifyRef}...`);
        const content = await mainGit.showFileAtRef(verifyRef, planRelPath);
        if (!content) {
            die(`Plan file not found on ${verifyRef} after push.\n\n` +
                `The micro-worktree reported success but the plan file ` +
                `"${planRelPath}" does not exist on the target branch.\n` +
                `This indicates a silent commit/push failure.\n\n` +
                `Suggestions:\n` +
                `  1. Retry: pnpm plan:create --id ${id} --title "${title}"${fromPath ? ` --from ${fromPath}` : ''}\n` +
                `  2. Check remote: git log origin/main --oneline -5\n` +
                `  3. Check for orphaned branches: git branch | grep tmp/${OPERATION_NAME}`);
        }
        const planUri = getPlanUri(id);
        console.log(`${LOG_PREFIX} ✅ Verified plan file on ${verifyRef}`);
        console.log(`\n${LOG_PREFIX} Plan created successfully!`);
        console.log(`\nPlan Details:`);
        console.log(`  ID:      ${id}`);
        console.log(`  Title:   ${title}`);
        console.log(`  URI:     ${planUri}`);
        console.log(`  File:    ${planRelPath}`);
        console.log(`\nNext steps:`);
        console.log(`  1. Edit the plan file with your goals and approach`);
        console.log(`  2. Link to WU/initiative: pnpm plan:link --id ${id} --plan ${planUri}`);
        console.log(`  3. When ready, promote: pnpm plan:promote --id ${id}`);
    }
    catch (error) {
        // Re-throw ProcessExitError from die() without wrapping
        if (error.exitCode !== undefined) {
            throw error;
        }
        die(`Plan creation failed: ${error.message}\n\n` +
            `Micro-worktree cleanup was attempted automatically.\n` +
            `If issue persists, check for orphaned branches: git branch | grep tmp/${OPERATION_NAME}`);
    }
}
// Guard main() for testability
import { runCLI } from './cli-entry-point.js';
if (import.meta.main) {
    void runCLI(main);
}
//# sourceMappingURL=plan-create.js.map