function generateCommand(context) {
  const { command } = context;
  if (!command) {
    throw new Error("Command is required in template context");
  }
  const name = command.name;
  const description = command.description || "";
  const args = command.arguments || {};
  const flags = command.flags || {};
  const exitCodes = command.exitCodes || {};
  const subcommands = command.subcommands || {};
  const serviceRef = command.serviceRef;
  const positionalArgs = Object.entries(args).filter(([_, arg]) => arg.positional).sort((a, b) => (a[1].position || 0) - (b[1].position || 0)).map(([argName, arg]) => {
    const required = arg.required;
    return required ? `<${argName}>` : `[${argName}]`;
  }).join(" ");
  const commandStr = positionalArgs ? `${name} ${positionalArgs}` : name;
  const optionDefs = Object.entries(flags).map(([flagName, flag]) => {
    const alias = flag.alias ? `${flag.alias}, ` : "";
    const flagType = flag.type?.toLowerCase();
    const valuePart = flagType === "boolean" ? "" : ` <${flagName.replace(/^--/, "")}>`;
    const defaultVal = flag.default !== void 0 ? `, ${commanderDefault(flag.default, flagType)}` : "";
    const desc = escapeSingleQuotes(flag.description || `${flagName} option`);
    return `    .option('${alias}${flagName}${valuePart}', '${desc}'${defaultVal})`;
  });
  const optionTypes = Object.entries(flags).map(([flagName, flag]) => {
    const tsType = mapFlagTypeToTS(flag.type);
    const key = flagName.replace(/^--/, "").replace(/-([a-z])/g, (_, c) => c.toUpperCase());
    return `  ${key}${flag.required ? "" : "?"}: ${tsType};`;
  });
  const argTypes = Object.entries(args).filter(([_, arg]) => arg.positional).map(([argName, arg]) => {
    const tsType = mapArgTypeToTS(arg.type);
    return `${argName}: ${tsType}`;
  });
  const actionParams = argTypes.length > 0 ? argTypes.join(", ") + ", options: CommandOptions" : "options: CommandOptions";
  const exitCodeComments = Object.entries(exitCodes).length > 0 ? Object.entries(exitCodes).map(
    ([code, meaning]) => `  //   ${code}: ${meaning}`
  ).join("\n") : "";
  const hasSubcommands = Object.keys(subcommands).length > 0;
  const subcommandRegistrations = hasSubcommands ? generateSubcommandRegistrations(name, subcommands) : "";
  const serviceImport = serviceRef ? `import { ${serviceRef} } from '../services/${serviceRef}.js';` : "";
  const allImportSets = [];
  if (ENGINE_HANDLERS[name]?.imports) allImportSets.push(ENGINE_HANDLERS[name].imports);
  if (hasSubcommands) {
    for (const subName of Object.keys(subcommands)) {
      const key = `${name}.${subName}`;
      if (ENGINE_HANDLERS[key]?.imports) allImportSets.push(ENGINE_HANDLERS[key].imports);
    }
  }
  const registerBody = hasSubcommands ? generateCommandWithSubcommands(name, description, subcommands, optionDefs) : generateLeafCommand(name, description, commandStr, optionDefs, actionParams, serviceRef, exitCodes);
  const bodyForUsage = `${serviceImport}
${registerBody}
${subcommandRegistrations}`;
  const commandOptionsUsed = new RegExp("\\bCommandOptions\\b").test(bodyForUsage);
  const engineImports = deduplicateImports(allImportSets, bodyForUsage);
  const commandOptionsDecl = commandOptionsUsed ? `interface CommandOptions {
${optionTypes.length > 0 ? optionTypes.join("\n") : "  [key: string]: any;"}
}
` : "";
  return `/**
 * ${name} command
 * ${description}
 * Generated from SpecVerse specification
 */

import { Command } from 'commander';
${serviceImport}
${engineImports}

${commandOptionsDecl}
${exitCodeComments ? `/**
 * Exit codes:
${exitCodeComments}
 */` : ""}

/**
 * Register the ${name} command on the program.
 */
export function register${capitalize(name)}Command(program: Command): void {
  ${registerBody}
}
${subcommandRegistrations}
`;
}
const ENGINE_HANDLERS = {
  validate: {
    imports: `import { readFileSync, existsSync } from 'fs';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `if (!existsSync(file)) {
          console.error('File not found:', file);
          process.exit(1);
        }

        // Discover and initialize parser engine
        const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) {
          console.error('No parser engine found. Install @specverse/engines.');
          process.exit(1);
        }
        await parser.initialize();

        const content = readFileSync(file, 'utf8');
        const result = parser.parseContent(content, file);

        if (result.errors.length > 0) {
          console.error('Validation failed');
          result.errors.forEach((e: string) => console.error(' ', e));
          if (result.warnings && result.warnings.length > 0) {
            console.warn('Warnings:');
            result.warnings.forEach((w: string) => console.warn(' ', w));
          }
          process.exit(1);
        }

        if (options.json) {
          console.log(JSON.stringify({ valid: true, warnings: result.warnings }, null, 2));
        } else {
          console.log('Validation successful');
          if (result.warnings && result.warnings.length > 0) {
            console.warn('Warnings:');
            result.warnings.forEach((w: string) => console.warn(' ', w));
          }
        }

        // L3 verification \u2014 opt-in via --verify flag. Runs the
        // transpiled Quint guards against the parsed spec. Guards
        // whose state-var dependencies aren't present in this spec
        // are reported as skipped (not failed).
        if (options.verify) {
          try {
            const { verifySpec, formatVerificationResult } = await import('@specverse/engines/inference');
            const verification = await verifySpec(result.ast);
            if (options.json) {
              console.log(JSON.stringify({ valid: true, verification }, null, 2));
            } else {
              console.log('');
              console.log(formatVerificationResult(verification, options.verbose));
            }
            if (verification.failed.length > 0) process.exit(1);
          } catch (ve: any) {
            console.error('Verification error:', ve.message);
            process.exit(1);
          }
        }`
  },
  infer: {
    imports: `import { readFileSync, writeFileSync, existsSync } from 'fs';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine, InferenceEngine } from '@specverse/types';`,
    handler: `if (!existsSync(file)) {
          console.error('File not found:', file);
          process.exit(1);
        }

        console.log('Running inference on', file, '...');

        // Discover engines
        const registry = new EngineRegistry();
        await registry.discover();

        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        const inferEngine = registry.getEngineForCapability('infer') as InferenceEngine;
        if (!inferEngine) { console.error('No inference engine found.'); process.exit(1); }
        await inferEngine.initialize({ options: { verbose: options.verbose } });

        const content = readFileSync(file, 'utf8');
        const parseResult = parser.parseContent(content, file);

        if (parseResult.errors.length > 0) {
          console.error('Cannot infer from invalid specification:');
          parseResult.errors.forEach((e: string) => console.error(' ', e));
          process.exit(1);
        }

        const ast = parseResult.ast!;
        const inferResult = await inferEngine.infer(ast, {
          generateControllers: true,
          generateServices: true,
          generateEvents: true,
          generateViews: true,
          generateDeployment: options.deployment || false,
          verbose: options.verbose || false,
        });

        const outputFile = options.output || file.replace(/\\.specly$/, '-inferred.specly');
        writeFileSync(outputFile, inferResult.yaml, 'utf8');
        console.log('Inferred specification written to:', outputFile);`
  },
  realize: {
    imports: `import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { resolve, join } from 'path';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine, InferenceEngine, RealizeEngine } from '@specverse/types';`,
    handler: `if (!existsSync(file)) {
          console.error('File not found:', file);
          process.exit(1);
        }

        // Discover engines
        const registry = new EngineRegistry();
        await registry.discover();

        // Parse \u2014 let the parser engine handle its own schema
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        const content = readFileSync(file, 'utf8');
        const parseResult = parser.parseContent(content, file);
        if (parseResult.errors.length > 0) {
          console.error('Invalid spec:');
          parseResult.errors.forEach((e: string) => console.error(' ', e));
          process.exit(1);
        }

        // Infer \u2014 let the inference engine handle its own rules
        const inferEngine = registry.getEngineForCapability('infer') as InferenceEngine;
        if (!inferEngine) { console.error('No inference engine found.'); process.exit(1); }
        await inferEngine.initialize();
        const inferResult = await inferEngine.infer(parseResult.ast!, {
          generateControllers: true, generateServices: true,
          generateEvents: true, generateViews: true,
        });

        // Load inferred YAML and flatten component data for realize
        const yaml = await import('js-yaml');
        const inferredYaml = yaml.load(inferResult.yaml) as any;
        // Inference output: { components: { Name: { models, controllers, ... } } }
        // realizeAll expects: { models: {...}, controllers: {...}, ... } (flat component data)
        const componentName = Object.keys(inferredYaml?.components || {})[0];
        const componentData = componentName ? inferredYaml.components[componentName] : {};

        // Merge original spec's services/events/views that inference didn't generate
        // (inference generates from models; explicit services in the spec are preserved here)
        const origComponent = parseResult.ast!.components?.[0] || {};
        for (const section of ['services', 'events', 'views']) {
          const origData = (origComponent as any)[section];
          if (origData && (!componentData[section] || JSON.stringify(componentData[section]) === '{}')) {
            // Convert array form (from parser) to object form (for realize)
            if (Array.isArray(origData)) {
              componentData[section] = {};
              for (const item of origData) {
                componentData[section][item.name] = item;
              }
            } else {
              componentData[section] = origData;
            }
          }
        }

        // Merge custom actions from original spec controllers into inferred controllers
        // Inference generates standard CURED; custom actions (openPoll, castVote) come from the spec
        const origControllers = Array.isArray((origComponent as any).controllers)
          ? (origComponent as any).controllers
          : Object.values((origComponent as any).controllers || {});
        const inferredControllers = componentData.controllers || {};
        for (const origCtrl of origControllers) {
          const ctrlName = (origCtrl as any).name;
          if (ctrlName && (origCtrl as any).actions) {
            const inferredCtrl = inferredControllers[ctrlName];
            if (inferredCtrl) {
              inferredCtrl.actions = { ...(inferredCtrl.actions || {}), ...(origCtrl as any).actions };
            }
          }
        }

        // Merge service operation steps from original spec into inferred services
        // Inference generates service shells with preconditions/returns but drops
        // the declarative steps arrays \u2014 we restore them from the parsed AST.
        const origServices = Array.isArray((origComponent as any).services)
          ? (origComponent as any).services
          : Object.values((origComponent as any).services || {});
        const inferredServices = componentData.services || {};
        for (const origSvc of origServices) {
          const svcName = (origSvc as any).name;
          if (!svcName) continue;
          const inferredSvc = inferredServices[svcName];
          if (!inferredSvc) continue;

          const origOps = (origSvc as any).operations || {};
          const inferredOps = inferredSvc.operations || {};
          for (const [opName, origOp] of Object.entries(origOps) as [string, any][]) {
            if (inferredOps[opName] && origOp.steps) {
              inferredOps[opName].steps = origOp.steps;
            }
          }
        }

        // Inject key as name into entity maps, and expand convention-format attributes
        // Iterate all object-valued sections (not hardcoded \u2014 covers any entity type)
        const entitySections = Object.keys(componentData).filter(k =>
          componentData[k] && typeof componentData[k] === 'object' && !Array.isArray(componentData[k])
          && !['version', 'description', 'name', 'componentName', 'commonDefinitions'].includes(k)
        );
        for (const section of entitySections) {
          if (componentData[section] && typeof componentData[section] === 'object' && !Array.isArray(componentData[section])) {
            for (const [key, value] of Object.entries(componentData[section])) {
              if (value && typeof value === 'object') {
                (value as any).name = key;
                // Expand convention-format attributes: { attrName: "Type modifiers" } \u2192 [{ name, type, ... }]
                if ((value as any).attributes && typeof (value as any).attributes === 'object' && !Array.isArray((value as any).attributes)) {
                  (value as any).attributes = Object.entries((value as any).attributes).map(([attrName, attrDef]: [string, any]) => {
                    if (typeof attrDef === 'string') {
                      const parts = attrDef.split(' ');
                      const kv = (key: string) => parts.find((p: string) => p.startsWith(key + '='))?.split('=')[1];
                      return { name: attrName, type: parts[0], required: parts.includes('required'), unique: parts.includes('unique'), auto: kv('auto'), category: kv('category') || 'business' };
                    }
                    return { name: attrName, ...(typeof attrDef === 'object' ? attrDef : {}) };
                  });
                }
                // Expand convention-format relationships: { relName: "type Target modifiers" } \u2192 array
                if ((value as any).relationships && typeof (value as any).relationships === 'object' && !Array.isArray((value as any).relationships)) {
                  (value as any).relationships = Object.entries((value as any).relationships).map(([relName, relDef]: [string, any]) => {
                    if (typeof relDef === 'object') return { name: relName, ...relDef };
                    if (typeof relDef === 'string') {
                      const parts = relDef.split(' ');
                      return { name: relName, type: parts[0], target: parts[1], cascade: parts.includes('cascade') };
                    }
                    return { name: relName };
                  });
                }
              }
            }
          }
        }
        const inferredSpec = { ...componentData, componentName, components: inferredYaml?.components || {} };

        // Realize \u2014 let the realize engine handle its own library
        const manifestPath = options.manifest || resolve((process.env.SPECVERSE_USER_CWD || process.cwd()), 'manifests/implementation.yaml');
        if (!existsSync(manifestPath)) {
          console.error('Manifest not found:', manifestPath);
          process.exit(1);
        }

        // Runtime mode (default): swap ReactApp \u2192 ReactAppRuntime in manifest
        let effectiveManifestPath = manifestPath;
        if (!options.static) {
          const manifestContent = readFileSync(manifestPath, 'utf8');
          if (/instanceFactory:\\s*["']?ReactApp["']?\\s*$/m.test(manifestContent)) {
            const { tmpdir } = await import('os');
            const runtimeManifest = manifestContent.replace(
              /instanceFactory:\\s*["']?ReactApp["']?\\s*$/gm,
              'instanceFactory: "ReactAppRuntime"'
            );
            effectiveManifestPath = join(tmpdir(), 'specverse-runtime-manifest.yaml');
            writeFileSync(effectiveManifestPath, runtimeManifest, 'utf8');
            console.log('  Using runtime mode (slim frontend with @specverse/runtime)');
          }
        } else {
          console.log('  Using static mode (full frontend generation)');
        }

        const realizeEngine = registry.getEngineForCapability('realize') as RealizeEngine;
        if (!realizeEngine) { console.error('No realize engine found.'); process.exit(1); }
        await realizeEngine.initialize({ manifestPath: effectiveManifestPath, workingDir: (process.env.SPECVERSE_USER_CWD || process.cwd()) });

        const outputDir = resolve((process.env.SPECVERSE_USER_CWD || process.cwd()), options.output || 'generated/code');
        console.log('Realizing ' + type + ' from ' + file + '...');
        await (realizeEngine as any).realizeAll(inferredSpec, outputDir);

        // Write dev.specly for runtime mode
        if (!options.static && inferResult.devYaml) {
          const frontendDir = join(outputDir, 'frontend', 'src');
          mkdirSync(frontendDir, { recursive: true });
          const devSpeclyPath = join(frontendDir, 'dev.specly');
          writeFileSync(devSpeclyPath, inferResult.devYaml, 'utf8');
          console.log('  Wrote dev.specly \u2192', devSpeclyPath);
        }`
  },
  init: {
    imports: `import { existsSync, mkdirSync, readdirSync, statSync, readFileSync, writeFileSync, copyFileSync } from 'fs';
import { resolve, join, dirname } from 'path';
import { fileURLToPath } from 'url';`,
    handler: `const __fn = fileURLToPath(import.meta.url);
        const __dn = dirname(__fn);

        // Resolve templates from package.json "specverse.templateDir" config
        const templatesDir = await (async () => {
          const { createRequire } = await import('module');
          const require = createRequire(import.meta.url);

          // Find our own package.json by walking up
          let dir = __dn;
          while (dir !== dirname(dir)) {
            const pkgPath = join(dir, 'package.json');
            if (existsSync(pkgPath)) {
              const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
              if (pkg.specverse?.templateDir) {
                const candidate = resolve(dir, pkg.specverse.templateDir);
                if (existsSync(candidate)) return candidate;
              }
            }
            dir = dirname(dir);
          }

          // Fallback: engine-realize assets
          try {
            const realizePkg = dirname(require.resolve('@specverse/engine-realize/package.json'));
            const candidate = join(realizePkg, 'assets', 'templates');
            if (existsSync(candidate)) return candidate;
          } catch { /* not installed */ }

          return null;
        })();

        if (!templatesDir) {
          console.error('Templates not found. Set "specverse.templateDir" in package.json or install @specverse/engine-realize.');
          process.exit(1);
        }

        if (options.list) {
          const templates = readdirSync(templatesDir).filter(
            d => statSync(join(templatesDir!, d)).isDirectory()
          );
          console.log('Available templates:');
          templates.forEach(t => console.log('  ' + t));
          return;
        }

        const projectName = name || 'my-project';
        const templateName = options.template || 'default';
        const templateDir = join(templatesDir, templateName);

        if (!existsSync(templateDir)) {
          console.error('Template not found: ' + templateName);
          console.error('Available: ' + readdirSync(templatesDir).filter(
            d => statSync(join(templatesDir!, d)).isDirectory()
          ).join(', '));
          process.exit(1);
        }

        const destDir = resolve((process.env.SPECVERSE_USER_CWD || process.cwd()), projectName);
        if (existsSync(destDir)) {
          console.error('Directory already exists: ' + destDir);
          process.exit(1);
        }

        // Copy template with variable substitution
        const kebab = projectName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
        const component = projectName.charAt(0).toUpperCase() + projectName.slice(1);
        const vars: Record<string, string> = {
          '{{PROJECT_NAME}}': projectName,
          '{{projectName}}': projectName,
          '{{projectNameKebab}}': kebab,
          '{{componentName}}': component,
          '{{DB_USER}}': 'postgres',
          '{{DB_PASSWORD}}': 'postgres',
        };

        function copyDir(src: string, dest: string) {
          mkdirSync(dest, { recursive: true });
          for (const item of readdirSync(src)) {
            const srcPath = join(src, item);
            let destName = item;
            if (item === 'gitignore') destName = '.gitignore';
            if (item === 'dot.env.example') destName = '.env.example';
            const destPath = join(dest, destName);

            if (statSync(srcPath).isDirectory()) {
              copyDir(srcPath, destPath);
            } else {
              let content = readFileSync(srcPath, 'utf8');
              for (const [key, val] of Object.entries(vars)) {
                content = content.split(key).join(val);
              }
              writeFileSync(destPath, content);
            }
          }
        }

        copyDir(templateDir, destDir);
        console.log('Project created: ' + destDir);
        console.log('Template: ' + templateName);
        console.log('');
        console.log('Next steps:');
        console.log('  cd ' + projectName);
        console.log('  npm run setup          # validate, generate code, install deps, setup db');
        console.log('  npm run dev:backend    # start backend (terminal 1)');
        console.log('  npm run dev:frontend   # start frontend (terminal 2)');`
  },
  // === gen subcommands ===
  "gen.diagrams": {
    imports: `import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { resolve, dirname, basename, join } from 'path';
import { fileURLToPath } from 'url';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        const content = readFileSync(file, 'utf8');
        const parseResult = parser.parseContent(content, file);
        if (parseResult.errors.length > 0) {
          console.error('Invalid spec:');
          parseResult.errors.forEach((e: string) => console.error(' ', e));
          process.exit(1);
        }

        const gen = registry.getEngineForCapability('generate-diagrams') as any;
        if (!gen) { console.error('No generators engine found.'); process.exit(1); }
        await gen.initialize();

        const diagrams = await gen.generateDiagrams(parseResult.ast!, { type: options.type || 'all' });
        const outputDir = options.output || basename(file, '.specly') + '-diagrams';
        if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true });
        for (const [diagramType, diagramContent] of diagrams.entries()) {
          writeFileSync(join(outputDir, diagramType + '.mmd'), diagramContent);
          console.log('  ' + diagramType);
        }
        console.log('Generated ' + diagrams.size + ' diagrams in: ' + outputDir);`
  },
  "gen.docs": {
    imports: `import { readFileSync, writeFileSync, existsSync } from 'fs';
import { resolve, dirname, basename } from 'path';
import { fileURLToPath } from 'url';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        const content = readFileSync(file, 'utf8');
        const parseResult = parser.parseContent(content, file);
        if (parseResult.errors.length > 0) {
          console.error('Invalid spec:');
          parseResult.errors.forEach((e: string) => console.error(' ', e));
          process.exit(1);
        }

        const gen = registry.getEngineForCapability('generate-docs') as any;
        if (!gen) { console.error('No generators engine found.'); process.exit(1); }
        await gen.initialize();

        const docs = await gen.generateDocs(parseResult.ast!, { format: options.format || 'markdown' });
        const ext = options.format === 'html' ? '.html' : '.md';
        const outputFile = options.output || basename(file, '.specly') + '-docs' + ext;
        writeFileSync(outputFile, docs);
        console.log('Documentation generated: ' + outputFile);`
  },
  "gen.uml": {
    imports: `import { readFileSync, writeFileSync, existsSync } from 'fs';
import { resolve, dirname, basename } from 'path';
import { fileURLToPath } from 'url';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        const content = readFileSync(file, 'utf8');
        const parseResult = parser.parseContent(content, file);
        if (parseResult.errors.length > 0) {
          console.error('Invalid spec:');
          parseResult.errors.forEach((e: string) => console.error(' ', e));
          process.exit(1);
        }

        const gen = registry.getEngineForCapability('generate-uml') as any;
        if (!gen) { console.error('No generators engine found.'); process.exit(1); }
        await gen.initialize();

        const uml = await gen.generateUML(parseResult.ast!, { type: options.type || 'all' });
        const outputFile = basename(file, '.specly') + '-uml.puml';
        writeFileSync(outputFile, uml);
        console.log('UML generated: ' + outputFile);`
  },
  // === dev subcommands ===
  "dev.format": {
    imports: `import { readFileSync, writeFileSync, existsSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        const content = readFileSync(file, 'utf8');
        const result = parser.parseContent(content, file);
        if (result.errors.length > 0) {
          console.error('Cannot format invalid spec:');
          result.errors.forEach((e: string) => console.error(' ', e));
          process.exit(1);
        }
        const yaml = await import('js-yaml');
        const formatted = yaml.dump(yaml.load(content), { lineWidth: 120, noRefs: true });
        if (options.write) {
          writeFileSync(file, formatted);
          console.log('Formatted and saved: ' + file);
        } else {
          console.log(formatted);
        }`
  },
  "dev.watch": {
    imports: `import { readFileSync, existsSync, watch } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        console.log('Watching ' + file + ' for changes...');
        const doValidate = () => {
          try {
            const c = readFileSync(file, 'utf8');
            const r = parser.parseContent(c, file);
            if (r.errors.length > 0) {
              console.log('[' + new Date().toLocaleTimeString() + '] FAILED');
              r.errors.forEach((e: string) => console.error(' ', e));
            } else {
              console.log('[' + new Date().toLocaleTimeString() + '] Valid');
            }
          } catch (e: any) { console.error('Watch error:', e.message); }
        };
        doValidate();
        watch(file, doValidate);
        await new Promise(() => {});`
  },
  "dev.quick": {
    imports: `import { readFileSync, existsSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        const content = readFileSync(file, 'utf8');
        const result = parser.parseContent(content, file);
        if (result.errors.length > 0) {
          console.error('Quick check: FAILED');
          result.errors.forEach((e: string) => console.error(' ', e));
          process.exit(1);
        }
        console.log('Quick check: OK');`
  },
  // === cache command (leaf, not subcommand) ===
  cache: {
    imports: `import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        // Access ImportResolver cache via parser
        const resolverModule = await import('@specverse/engines/parser');
        const resolver = new resolverModule.ImportResolver({ basePath: (process.env.SPECVERSE_USER_CWD || process.cwd()) });

        const cacheDir = (resolver as any).getCacheDir ? (resolver as any).getCacheDir() : null;
        if (options.stats) {
          console.log('Cache directory:', cacheDir || 'default');
        } else if (options.list) {
          if (cacheDir) {
            const fs = await import('fs');
            if (fs.existsSync(cacheDir)) {
              const items = fs.readdirSync(cacheDir);
              if (items.length === 0) { console.log('Cache is empty'); }
              else { items.forEach((item: string) => console.log(' ', item)); }
            } else { console.log('Cache directory does not exist'); }
          } else { console.log('No cache directory configured'); }
        } else if (options.clear) {
          if (resolver.clearCache) { resolver.clearCache(); }
          console.log('Cache cleared');
        } else {
          console.log('Use --stats, --list, or --clear');
        }`
  },
  // === ai subcommands ===
  "ai.docs": {
    imports: `import { readFileSync, writeFileSync, existsSync } from 'fs';
import { resolve, dirname, basename } from 'path';
import { fileURLToPath } from 'url';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        const content = readFileSync(file, 'utf8');
        const parseResult = parser.parseContent(content, file);
        if (parseResult.errors.length > 0) {
          console.error('Invalid spec:');
          parseResult.errors.forEach((e: string) => console.error(' ', e));
          process.exit(1);
        }

        const aiEngine = registry.getEngineForCapability('ai-prompts') as any;
        if (!aiEngine) {
          console.error('AI engine not available. Install @specverse/engines.');
          process.exit(1);
        }
        await aiEngine.initialize({ provider: options.provider });
        const prompt = await aiEngine.generatePrompt(parseResult.ast!, { type: 'docs' });
        const outputFile = options.output || basename(file, '.specly') + '-ai-docs.md';
        writeFileSync(outputFile, prompt);
        console.log('AI documentation prompt generated: ' + outputFile);`
  },
  "ai.suggest": {
    imports: `import { readFileSync, existsSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        const content = readFileSync(file, 'utf8');
        const parseResult = parser.parseContent(content, file);
        if (parseResult.errors.length > 0) {
          console.error('Invalid spec:');
          parseResult.errors.forEach((e: string) => console.error(' ', e));
          process.exit(1);
        }

        const aiEngine = registry.getEngineForCapability('ai-suggestions') as any;
        if (!aiEngine) {
          console.error('AI engine not available. Install @specverse/engines.');
          process.exit(1);
        }
        await aiEngine.initialize();
        const suggestions = await aiEngine.suggest(parseResult.ast!);
        if (suggestions.length === 0) {
          console.log('No suggestions \u2014 spec looks good!');
        } else {
          const warnings = suggestions.filter((s: any) => s.severity === 'warning');
          const improvements = suggestions.filter((s: any) => s.severity === 'improvement');
          const info = suggestions.filter((s: any) => s.severity === 'info');
          if (warnings.length > 0) {
            console.log('\\nWarnings:');
            warnings.forEach((s: any) => console.log('  [' + s.target + '] ' + s.description));
          }
          if (improvements.length > 0) {
            console.log('\\nSuggested improvements:');
            improvements.forEach((s: any) => console.log('  [' + s.target + '] ' + s.description));
          }
          if (info.length > 0) {
            console.log('\\nInfo:');
            info.forEach((s: any) => console.log('  [' + s.target + '] ' + s.description));
          }
          console.log('\\n' + suggestions.length + ' suggestion(s): ' + warnings.length + ' warning, ' + improvements.length + ' improvement, ' + info.length + ' info');
        }`
  },
  "ai.template": {
    imports: `import { writeFileSync } from 'fs';
import { EngineRegistry } from '@specverse/entities';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const aiEngine = registry.getEngineForCapability('ai-templates') as any;
        if (!aiEngine) {
          console.error('AI engine not available. Install @specverse/engines.');
          process.exit(1);
        }
        await aiEngine.initialize();
        const template = await aiEngine.template(operation, { config: options.config });
        if (options.output) {
          writeFileSync(options.output, template);
          console.log('Template written to: ' + options.output);
        } else {
          console.log(template);
        }`
  },
  "ai.regenerate": {
    imports: `import { readFileSync, existsSync } from 'fs';
import { resolve } from 'path';
import { EngineRegistry } from '@specverse/entities';
import type { ParserEngine } from '@specverse/types';`,
    handler: `// Parse Owner.functionName \u2014 or just Owner with --all
        const target = fn;
        const dotIdx = target.indexOf('.');
        const ownerName = dotIdx >= 0 ? target.slice(0, dotIdx) : target;
        const functionName = dotIdx >= 0 ? target.slice(dotIdx + 1) : null;
        if (!functionName && !options.all) {
          console.error('Function must be specified as Owner.functionName, or use --all to regenerate every AI function in the owner.');
          process.exit(1);
        }

        // Resolve spec file \u2014 default to specs/main-inferred.specly next to cwd
        const userCwd = process.env.SPECVERSE_USER_CWD || process.cwd();
        const specCandidates = options.spec
          ? [resolve(userCwd, options.spec)]
          : [resolve(userCwd, 'specs/main-inferred.specly'), resolve(userCwd, 'specs/main.specly')];
        const specPath = specCandidates.find(p => existsSync(p));
        if (!specPath) {
          console.error('Spec not found. Tried: ' + specCandidates.join(', '));
          console.error('Pass --spec <file> or run from a project root with specs/main.specly.');
          process.exit(1);
        }
        console.log('Using spec: ' + specPath);

        const registry = new EngineRegistry();
        await registry.discover();
        const parser = registry.getEngineForCapability('parse') as ParserEngine;
        if (!parser) { console.error('No parser engine found.'); process.exit(1); }
        await parser.initialize();

        const specContent = readFileSync(specPath, 'utf8');
        const parseResult = parser.parseContent(specContent, specPath);
        if (parseResult.errors.length > 0) {
          console.error('Invalid spec:');
          parseResult.errors.forEach((e: string) => console.error('  ' + e));
          process.exit(1);
        }

        // Flatten components down to a realize-shaped spec
        // (controllers, services, models at top level) \u2014 matches what
        // regenerateBehavior expects. Collections may be arrays (parser
        // output) or objects (inferred spec); preserve the incoming shape.
        const ast: any = parseResult.ast;
        const flat: any = { ...ast };
        const components = ast?.components || {};
        for (const comp of Object.values(components) as any[]) {
          for (const key of ['models', 'controllers', 'services']) {
            const collection = comp?.[key];
            if (!collection) continue;
            if (Array.isArray(collection)) {
              flat[key] = [...(Array.isArray(flat[key]) ? flat[key] : []), ...collection];
            } else {
              flat[key] = { ...(flat[key] && !Array.isArray(flat[key]) ? flat[key] : {}), ...collection };
            }
          }
        }

        const { regenerateBehavior } = await import('@specverse/engines/ai');
        const outputDir = resolve(userCwd, options.output || 'generated/code');
        try {
          const result = await regenerateBehavior({
            spec: flat,
            ownerName,
            targetFunction: options.all ? null : functionName,
            outputDir,
            allFunctions: !!options.all,
          });
          console.log(\`\u2705 Regenerated \${result.filePath}\`);
          console.log(\`   Owner: \${ownerName}\`);
          console.log(\`   Unmatched functions: \${result.unmatchedCount}\`);
          console.log(\`   Target: \${options.all ? 'all' : functionName}\`);
          console.log(\`   Cache entries cleared: \${result.cacheCleared}\`);
        } catch (err: any) {
          console.error('Regeneration failed: ' + (err?.message || err));
          process.exit(1);
        }`
  },
  // === session subcommands ===
  "session.create": {
    imports: `import { EngineRegistry } from '@specverse/entities';`,
    handler: `const registry = new EngineRegistry();
        await registry.discover();
        const aiEngine = registry.getEngineForCapability('ai-prompts') as any;
        if (!aiEngine) { console.error('AI engine not available.'); process.exit(1); }
        await aiEngine.initialize();

        const { SessionManager } = await import('@specverse/engines/ai');
        const manager = new SessionManager();
        const session = await manager.create({ name: options.name, pver: options.pver });

        if (options.json) {
          console.log(JSON.stringify(session, null, 2));
        } else {
          console.log('Session created: ' + session.sessionId);
          console.log('Status: ' + session.status);
          if (session.name) console.log('Name: ' + session.name);
          console.log('Prompt version: ' + session.pver);
        }`
  },
  "session.list": {
    imports: ``,
    handler: `const { SessionManager } = await import('@specverse/engines/ai');
        const manager = new SessionManager();
        const sessions = await manager.list({ all: options.all });

        if (options.json) {
          console.log(JSON.stringify(sessions, null, 2));
        } else if (sessions.length === 0) {
          console.log('No sessions found. Create one with: specverse session create');
        } else {
          console.log('Sessions (' + sessions.length + '):');
          for (const s of sessions) {
            console.log('  ' + (s.status === 'active' ? '*' : ' ') + ' ' + s.sessionId + (s.name ? ' (' + s.name + ')' : '') + ' \u2014 ' + s.status + ', ' + s.jobsProcessed + ' jobs');
          }
        }`
  },
  "session.delete": {
    imports: ``,
    handler: `const { SessionManager } = await import('@specverse/engines/ai');
        const manager = new SessionManager();
        await manager.delete(sessionId, { force: options.force });
        console.log('Session deleted: ' + sessionId);`
  },
  "session.submit": {
    imports: ``,
    handler: `const { SessionManager } = await import('@specverse/engines/ai');
        const manager = new SessionManager();
        const job = await manager.submit({
          jobId: options.jobId || ('job-' + Date.now()),
          sessionId,
          operation: (options.operation || 'create') as 'create' | 'analyse' | 'materialise' | 'realize',
          requirements,
          output: options.output,
        });
        console.log('Job submitted: ' + job.jobId);
        console.log('Status: ' + job.status);
        if (options.output) console.log('Output: ' + options.output);`
  },
  "session.status": {
    imports: ``,
    handler: `const { SessionManager } = await import('@specverse/engines/ai');
        const manager = new SessionManager();
        const status = await manager.status(id);
        if (options.json) {
          console.log(JSON.stringify(status, null, 2));
        } else {
          console.log('ID: ' + (status.sessionId || status.jobId));
          console.log('Status: ' + status.status);
          if (status.submitted) console.log('Submitted: ' + new Date(status.submitted).toLocaleString());
          if (status.started) console.log('Started: ' + new Date(status.started).toLocaleString());
          if (status.completed) console.log('Completed: ' + new Date(status.completed).toLocaleString());
          if (status.duration) console.log('Duration: ' + status.duration);
        }`
  },
  "session.process": {
    imports: ``,
    handler: `const { SessionManager } = await import('@specverse/engines/ai');
        const manager = new SessionManager();
        console.log('Processing job: ' + jobId);
        await manager.processJob(jobId);
        console.log('Job processed successfully');`
  }
};
function generateLeafCommand(name, description, commandStr, optionDefs, actionParams, serviceRef, exitCodes) {
  const engineHandler = ENGINE_HANDLERS[name];
  const handler = engineHandler ? engineHandler.handler : serviceRef ? `const service = new ${serviceRef}();
      const result = await service.execute(${actionParams.includes(":") ? "{ " + actionParams.split(",").map((p) => p.trim().split(":")[0].trim()).join(", ") + ", ...options }" : "options"});
      console.log(result);` : `console.log('Executing ${name}...');
      // TODO: Wire to service`;
  const finalActionParams = renameUnusedActionParams(actionParams, handler);
  return `program
    .command('${commandStr}')
    .description('${escapeSingleQuotes(description)}')
${optionDefs.join("\n")}
    .action(async (${finalActionParams}) => {
      try {
        ${handler}
      } catch (error: any) {
        console.error('Error:', error.message);
        process.exit(${Object.keys(exitCodes).find((k) => k !== "0") || "1"});
      }
    });`;
}
function escapeSingleQuotes(s) {
  return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
}
function commanderDefault(value, flagType) {
  if (flagType === "boolean") return JSON.stringify(Boolean(value));
  if (typeof value === "number") return JSON.stringify(String(value));
  return JSON.stringify(value);
}
function renameUnusedActionParams(actionParams, handler) {
  if (!actionParams.trim()) return actionParams;
  return actionParams.split(",").map((param) => {
    const trimmed = param.trim();
    const nameMatch = trimmed.match(/^(\w+)/);
    if (!nameMatch) return param;
    const name = nameMatch[1];
    if (name.startsWith("_")) return param;
    const re = new RegExp(`\\b${name}\\b`);
    if (re.test(handler)) return param;
    return param.replace(new RegExp(`\\b${name}\\b`), `_${name}`);
  }).join(", ");
}
function generateCommandWithSubcommands(name, description, subcommands, optionDefs) {
  const subcmdRegistrations = Object.entries(subcommands).map(([subName, subDef]) => {
    const subDesc = subDef.description || "";
    const subArgs = subDef.arguments || {};
    const subFlags = subDef.flags || {};
    const positionalStr = Object.entries(subArgs).filter(([_, a]) => a.positional).map(([n, a]) => a.required ? `<${n}>` : `[${n}]`).join(" ");
    const subCmdStr = positionalStr ? `${subName} ${positionalStr}` : subName;
    const subOptionDefs = Object.entries(subFlags).map(([flagName, flag]) => {
      const alias = flag.alias ? `${flag.alias}, ` : "";
      const flagType = flag.type?.toLowerCase();
      const valuePart = flagType === "boolean" ? "" : ` <${flagName.replace(/^--/, "")}>`;
      const defaultVal = flag.default !== void 0 ? `, ${commanderDefault(flag.default, flagType)}` : "";
      const desc = escapeSingleQuotes(flag.description || flagName);
      return `    .option('${alias}${flagName}${valuePart}', '${desc}'${defaultVal})`;
    });
    const handlerKey = `${name}.${subName}`;
    const engineHandler = ENGINE_HANDLERS[handlerKey];
    const subArgTypes = Object.entries(subArgs).filter(([_, a]) => a.positional).map(([n, a]) => `${n}: ${mapArgTypeToTS(a.type)}`);
    const subActionParams = subArgTypes.length > 0 ? subArgTypes.join(", ") + ", options: any" : "options: any";
    const handler = engineHandler ? engineHandler.handler : `console.log('${name} ${subName}: not yet implemented via engine');`;
    const finalSubActionParams = renameUnusedActionParams(subActionParams, handler);
    return `
  cmd
    .command('${subCmdStr}')
    .description('${escapeSingleQuotes(subDesc)}')
${subOptionDefs.join("\n")}
    .action(async (${finalSubActionParams}) => {
      try {
        ${handler}
      } catch (error: any) {
        console.error('Error:', error.message);
        process.exit(1);
      }
    });`;
  });
  return `const cmd = program
    .command('${name}')
    .description('${escapeSingleQuotes(description)}');
${subcmdRegistrations.join("\n")}`;
}
function generateSubcommandRegistrations(_parentName, _subcommands) {
  return "";
}
function mapFlagTypeToTS(type) {
  if (!type) return "string";
  const lower = type.toLowerCase();
  if (lower === "boolean") return "boolean";
  if (lower === "number" || lower === "integer") return "number";
  return "string";
}
function mapArgTypeToTS(type) {
  if (!type) return "string";
  const lower = type.toLowerCase();
  if (lower === "filepath" || lower === "string") return "string";
  if (lower === "number" || lower === "integer") return "number";
  if (lower === "boolean") return "boolean";
  return "string";
}
function capitalize(str) {
  return str.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
}
function deduplicateImports(importBlocks, usedIn) {
  const seen = /* @__PURE__ */ new Map();
  const typeImports = /* @__PURE__ */ new Map();
  const rawLines = /* @__PURE__ */ new Set();
  const isUsed = (name) => {
    if (!usedIn) return true;
    return new RegExp(`\\b${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`).test(usedIn);
  };
  for (const block of importBlocks) {
    for (const line of block.split("\n").map((l) => l.trim()).filter((l) => l)) {
      const namedMatch = line.match(/^import\s+\{\s*(.+?)\s*\}\s+from\s+'(.+?)';?$/);
      if (namedMatch) {
        const names = namedMatch[1].split(",").map((n) => n.trim());
        const mod = namedMatch[2];
        if (!seen.has(mod)) seen.set(mod, /* @__PURE__ */ new Set());
        names.forEach((n) => seen.get(mod).add(n));
        continue;
      }
      const typeMatch = line.match(/^import\s+type\s+\{\s*(.+?)\s*\}\s+from\s+'(.+?)';?$/);
      if (typeMatch) {
        const names = typeMatch[1].split(",").map((n) => n.trim());
        const mod = typeMatch[2];
        if (!typeImports.has(mod)) typeImports.set(mod, /* @__PURE__ */ new Set());
        names.forEach((n) => typeImports.get(mod).add(n));
        continue;
      }
      rawLines.add(line);
    }
  }
  const result = [];
  for (const [mod, names] of seen.entries()) {
    const used = [...names].filter(isUsed);
    if (used.length > 0) {
      result.push(`import { ${used.join(", ")} } from '${mod}';`);
    }
  }
  for (const [mod, names] of typeImports.entries()) {
    const regularNames = seen.get(mod) || /* @__PURE__ */ new Set();
    const typeOnly = [...names].filter((n) => !regularNames.has(n)).filter(isUsed);
    if (typeOnly.length > 0) {
      result.push(`import type { ${typeOnly.join(", ")} } from '${mod}';`);
    }
  }
  for (const line of rawLines) {
    result.push(line);
  }
  return result.join("\n");
}
export {
  generateCommand as default
};
