#!/usr/bin/env node
import {
  BaseCommand,
  EXIT_CODES
} from "../chunk-SRFNNOLC.js";
import {
  copySkillsToLocalFlattened,
  loadProjectSourceConfig,
  loadSkillsMatrixFromSource,
  resolveSource,
  saveSourceToProjectConfig
} from "../chunk-ZECXM7LP.js";
import {
  typedKeys
} from "../chunk-T4EXUIBY.js";
import {
  copy,
  directoryExists,
  ensureDir,
  fileExists,
  listDirectories,
  writeFile
} from "../chunk-473YHDYQ.js";
import {
  CLAUDE_SRC_DIR,
  DEFAULT_BRANDING,
  DIRS,
  LOCAL_SKILLS_PATH,
  PROJECT_ROOT,
  STANDARD_FILES,
  YAML_FORMATTING
} from "../chunk-FVN5PFFY.js";
import {
  init_esm_shims
} from "../chunk-DHET7RCE.js";

// src/cli/commands/eject.ts
init_esm_shims();
import { Args, Flags } from "@oclif/core";
import path from "path";
import os from "os";
import { stringify as stringifyYaml } from "yaml";
var EJECT_TYPES = ["agent-partials", "skills", "all"];
var Eject = class _Eject extends BaseCommand {
  static summary = "Eject skills or agent partials for local customization";
  static description = "Copy agent partials or skills to your project for customization. Agent partials are always copied from the CLI. Skills are copied from the configured source (public marketplace by default).";
  static examples = [
    {
      description: "Eject agent partials for customization",
      command: "<%= config.bin %> <%= command.id %> agent-partials"
    },
    {
      description: "Eject skills to local directory",
      command: "<%= config.bin %> <%= command.id %> skills"
    },
    {
      description: "Eject everything with force overwrite",
      command: "<%= config.bin %> <%= command.id %> all --force"
    },
    {
      description: "Eject to a custom output directory",
      command: "<%= config.bin %> <%= command.id %> skills -o ./custom-dir"
    },
    {
      description: "Eject only agent templates",
      command: "<%= config.bin %> <%= command.id %> agent-partials --templates"
    }
  ];
  static args = {
    type: Args.string({
      description: "What to eject: agent-partials, skills, all",
      required: false,
      options: EJECT_TYPES
    })
  };
  static flags = {
    ...BaseCommand.baseFlags,
    force: Flags.boolean({
      char: "f",
      description: "Overwrite existing files",
      default: false
    }),
    output: Flags.string({
      char: "o",
      description: "Output directory (default: .claude/ in current directory)"
    }),
    refresh: Flags.boolean({
      description: "Force refresh from remote source",
      default: false
    }),
    templates: Flags.boolean({
      char: "t",
      description: "Eject only agent templates (used with agent-partials)",
      default: false
    })
  };
  async run() {
    const { args, flags } = await this.parse(_Eject);
    const projectDir = process.cwd();
    if (!args.type) {
      this.error("Please specify what to eject: agent-partials, skills, or all", {
        exit: EXIT_CODES.INVALID_ARGS
      });
    }
    if (!EJECT_TYPES.includes(args.type)) {
      this.error(`Unknown eject type: ${args.type}`, {
        exit: EXIT_CODES.INVALID_ARGS
      });
    }
    let outputBase;
    if (flags.output) {
      const expandedPath = flags.output.startsWith("~") ? path.join(os.homedir(), flags.output.slice(1)) : flags.output;
      outputBase = path.resolve(projectDir, expandedPath);
      if (await fileExists(outputBase)) {
        this.error(`Output path exists as a file: ${outputBase}`, {
          exit: EXIT_CODES.INVALID_ARGS
        });
      }
    } else {
      outputBase = path.join(projectDir, CLAUDE_SRC_DIR);
    }
    this.log("");
    this.log(`${DEFAULT_BRANDING.NAME} Eject`);
    this.log("");
    if (flags.output) {
      this.log(`Output directory: ${outputBase}`);
    }
    const ejectType = args.type;
    const directOutput = !!flags.output;
    if (flags.templates && ejectType === "skills") {
      this.warn("The --templates flag only applies to agent-partials. Ignoring.");
    }
    let sourceResult;
    if (ejectType === "skills" || ejectType === "all") {
      sourceResult = await loadSkillsMatrixFromSource({
        sourceFlag: flags.source,
        projectDir,
        forceRefresh: flags.refresh
      });
    }
    switch (ejectType) {
      case "agent-partials":
        await this.ejectAgentPartials(outputBase, flags.force, directOutput, flags.templates);
        break;
      case "skills":
        await this.ejectSkills(
          projectDir,
          flags.force,
          sourceResult,
          directOutput,
          directOutput ? outputBase : void 0
        );
        break;
      case "all":
        await this.ejectAgentPartials(outputBase, flags.force, directOutput, flags.templates);
        await this.ejectSkills(
          projectDir,
          flags.force,
          sourceResult,
          directOutput,
          directOutput ? outputBase : void 0
        );
        break;
      default:
        break;
    }
    if (flags.source) {
      await saveSourceToProjectConfig(projectDir, flags.source);
      this.log(`Source saved to .claude-src/config.yaml`);
    }
    await this.ensureMinimalConfig(projectDir, flags.source, sourceResult);
    this.log("");
    this.logSuccess("Eject complete!");
    this.log("");
  }
  // Ensures a minimal config.yaml exists so `agentsinc compile` works after eject
  async ensureMinimalConfig(projectDir, sourceFlag, sourceResult) {
    const configPath = path.join(projectDir, CLAUDE_SRC_DIR, STANDARD_FILES.CONFIG_YAML);
    if (await fileExists(configPath)) {
      return;
    }
    const projectName = path.basename(projectDir);
    const config = {
      name: projectName,
      installMode: "local"
    };
    const resolvedConfig = sourceResult?.sourceConfig ?? await resolveSource(sourceFlag, projectDir);
    if (sourceFlag) {
      config.source = sourceFlag;
    } else if (resolvedConfig.source) {
      config.source = resolvedConfig.source;
    }
    if (resolvedConfig.marketplace) {
      config.marketplace = resolvedConfig.marketplace;
    }
    const existingProjectConfig = await loadProjectSourceConfig(projectDir);
    if (existingProjectConfig?.author) {
      config.author = existingProjectConfig.author;
    }
    if (existingProjectConfig?.agentsSource) {
      config.agentsSource = existingProjectConfig.agentsSource;
    }
    await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));
    let configContent = stringifyYaml(config, { indent: YAML_FORMATTING.INDENT });
    const exampleStackComment = `
# Example stack configuration (uncomment and customize):
#
# skills:
#   - web-framework-react
#   - web-styling-scss-modules
#   - api-framework-hono
#   - api-database-drizzle
#
# agents:
#   - web-developer
#   - api-developer
#   - web-reviewer
#
# stack:
#   web-developer:
#     framework: web-framework-react
#     styling: web-styling-scss-modules
#   api-developer:
#     api: api-framework-hono
#     database: api-database-drizzle
`;
    configContent += exampleStackComment;
    await writeFile(configPath, configContent);
    this.logSuccess(`Created ${CLAUDE_SRC_DIR}/config.yaml`);
  }
  async ejectAgentPartials(outputBase, force, directOutput = false, templatesFlag = false) {
    const sourceDir = templatesFlag ? path.join(PROJECT_ROOT, DIRS.templates) : path.join(PROJECT_ROOT, DIRS.agents);
    if (!await directoryExists(sourceDir)) {
      this.warn(
        templatesFlag ? "No agent templates found in CLI." : "No agent partials found in CLI."
      );
      return;
    }
    const destDir = directOutput ? outputBase : templatesFlag ? path.join(outputBase, path.basename(DIRS.agents), path.basename(DIRS.templates)) : path.join(outputBase, path.basename(DIRS.agents));
    const templatesBasename = path.basename(DIRS.templates);
    if (await directoryExists(destDir) && !force) {
      if (templatesFlag) {
        this.warn(`Agent templates already exist at ${destDir}. Use --force to overwrite.`);
        return;
      }
      const hasTemplates = await directoryExists(path.join(destDir, templatesBasename));
      if (await this.hasAgentPartialDirs(destDir) && !hasTemplates) {
        this.warn(`Agent partials already exist at ${destDir}. Use --force to overwrite.`);
        return;
      }
    }
    await ensureDir(destDir);
    const skipTemplates = !templatesFlag && !force && await directoryExists(path.join(destDir, templatesBasename));
    if (skipTemplates) {
      const sourceEntries = await listDirectories(sourceDir);
      const nonTemplateEntries = sourceEntries.filter((entry) => entry !== templatesBasename);
      for (const entry of nonTemplateEntries) {
        await copy(path.join(sourceDir, entry), path.join(destDir, entry));
      }
      this.warn(
        "Agent templates already exist \u2014 skipping templates, only ejecting agent partials."
      );
    } else {
      await copy(sourceDir, destDir);
    }
    this.logSuccess(
      `${templatesFlag ? "Agent templates" : "Agent partials"} ejected to ${destDir}`
    );
    this.log(
      templatesFlag ? "You can now customize agent templates locally." : "You can now customize templates, agent intro, workflow, and examples locally."
    );
  }
  /** Checks whether the agents directory contains any agent subdirectories (not just _templates). */
  async hasAgentPartialDirs(agentsDir) {
    const subdirs = await listDirectories(agentsDir);
    const templatesBasename = path.basename(DIRS.templates);
    return subdirs.some((dir) => dir !== templatesBasename);
  }
  async ejectSkills(projectDir, force, sourceResult, directOutput = false, customOutputBase) {
    const destDir = directOutput && customOutputBase ? customOutputBase : path.join(projectDir, LOCAL_SKILLS_PATH);
    if (await directoryExists(destDir) && !force) {
      this.warn(`Skills already exist at ${destDir}. Use --force to overwrite.`);
      return;
    }
    const skillIds = typedKeys(sourceResult.matrix.skills).filter(
      (skillId) => !sourceResult.matrix.skills[skillId]?.local
    );
    if (skillIds.length === 0) {
      this.warn("No skills found in source to eject.");
      return;
    }
    await ensureDir(destDir);
    const copiedSkills = await copySkillsToLocalFlattened(
      skillIds,
      destDir,
      sourceResult.matrix,
      sourceResult
    );
    const sourceLabel = sourceResult.isLocal ? sourceResult.sourcePath : sourceResult.marketplace || sourceResult.sourceConfig.source;
    this.logSuccess(`${copiedSkills.length} skills ejected to ${destDir} from ${sourceLabel}`);
    this.log("You can now customize skill content locally.");
  }
};
export {
  Eject as default
};
//# sourceMappingURL=eject.js.map