#!/usr/bin/env node
import {
  SkillSearch
} from "../chunk-BFD5NZQ4.js";
import "../chunk-XUDTFI4M.js";
import "../chunk-U3IGFMCY.js";
import {
  INFO_MESSAGES,
  STATUS_MESSAGES,
  SUCCESS_MESSAGES
} from "../chunk-MR6OBL3B.js";
import {
  fetchFromSource,
  loadSkillsMatrixFromSource,
  resolveAllSources
} from "../chunk-TZXYBG3R.js";
import {
  parseFrontmatter
} from "../chunk-OCEFD7V6.js";
import "../chunk-T4EXUIBY.js";
import {
  BaseCommand,
  EXIT_CODES
} from "../chunk-VR3CDXDT.js";
import {
  copy,
  ensureDir,
  fileExists,
  listDirectories,
  readFile
} from "../chunk-LWXRUR6B.js";
import {
  DEFAULT_SKILLS_SUBDIR,
  LOCAL_SKILLS_PATH,
  STANDARD_FILES
} from "../chunk-6OWHQ7HM.js";
import "../chunk-EC3UJRKZ.js";
import {
  init_esm_shims
} from "../chunk-DHET7RCE.js";

// src/cli/commands/search.tsx
init_esm_shims();
import { Args, Flags } from "@oclif/core";
import { printTable } from "@oclif/table";
import { render } from "ink";
import path from "path";
import { sortBy } from "remeda";

// src/cli/components/skill-search/index.ts
init_esm_shims();

// src/cli/commands/search.tsx
import { jsx } from "react/jsx-runtime";
var MAX_DESCRIPTION_WIDTH = 50;
function truncate(str, maxLength) {
  if (str.length <= maxLength) return str;
  return `${str.slice(0, maxLength - 3)}...`;
}
function matchesQuery(skill, query) {
  const lowerQuery = query.toLowerCase();
  if (skill.id.toLowerCase().includes(lowerQuery)) return true;
  if (skill.displayName.toLowerCase().includes(lowerQuery)) return true;
  if (skill.slug?.toLowerCase().includes(lowerQuery)) return true;
  if (skill.description.toLowerCase().includes(lowerQuery)) return true;
  if (skill.category.toLowerCase().includes(lowerQuery)) return true;
  return skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery));
}
function matchesCategory(skill, category) {
  const lowerCategory = category.toLowerCase();
  return skill.category.toLowerCase().includes(lowerCategory);
}
function toSourcedSkill(skill, sourceName, sourceUrl) {
  return {
    ...skill,
    sourceName,
    sourceUrl
  };
}
async function fetchSkillsFromSource(source, forceRefresh) {
  try {
    const result = await fetchFromSource(source.url, { forceRefresh });
    const skillsDir = path.join(result.path, DEFAULT_SKILLS_SUBDIR);
    if (!await fileExists(skillsDir)) {
      return [];
    }
    const skillDirs = await listDirectories(skillsDir);
    const skills = [];
    for (const skillDir of skillDirs) {
      const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);
      if (!await fileExists(skillMdPath)) continue;
      const content = await readFile(skillMdPath);
      const frontmatter = parseFrontmatter(content, skillMdPath);
      if (!frontmatter) continue;
      skills.push({
        id: frontmatter.name,
        description: frontmatter.description,
        // Boundary cast: directory name used as slug for third-party source skill
        slug: skillDir,
        displayName: skillDir,
        // Boundary cast: external source skills have no category metadata
        category: "imported",
        tags: [],
        author: `@${source.name}`,
        conflictsWith: [],
        isRecommended: false,
        requires: [],
        alternatives: [],
        discourages: [],
        compatibleWith: [],
        requiresSetup: [],
        providesSetupFor: [],
        sourceName: source.name,
        sourceUrl: source.url,
        path: path.join(skillsDir, skillDir)
      });
    }
    return skills;
  } catch {
    return [];
  }
}
var Search = class _Search extends BaseCommand {
  static summary = "Search available skills";
  static description = "Search skills by ID, alias, description, category, or tags. Run without arguments or with -i for interactive mode with multi-select.";
  static examples = [
    {
      description: "Search for React skills",
      command: "<%= config.bin %> search react"
    },
    {
      description: "Interactive search mode",
      command: "<%= config.bin %> search"
    },
    {
      description: "Interactive with pre-filled query",
      command: "<%= config.bin %> search -i react"
    },
    {
      description: "Search with category filter",
      command: "<%= config.bin %> search state -c frontend"
    }
  ];
  static args = {
    query: Args.string({
      description: "Search query (matches name, description, category, tags)",
      required: false
    })
  };
  static flags = {
    ...BaseCommand.baseFlags,
    interactive: Flags.boolean({
      char: "i",
      description: "Launch interactive search with multi-select",
      default: false
    }),
    category: Flags.string({
      char: "c",
      description: "Filter by category",
      required: false
    }),
    refresh: Flags.boolean({
      description: "Force refresh from remote sources",
      default: false
    })
  };
  async run() {
    const { args, flags } = await this.parse(_Search);
    const projectDir = process.cwd();
    const isInteractive = flags.interactive || !args.query;
    if (isInteractive) {
      await this.runInteractive(args.query, flags.refresh, projectDir);
    } else {
      await this.runStatic(args.query, flags);
    }
  }
  async runInteractive(initialQuery, forceRefresh, projectDir) {
    this.log("Loading skills from all sources...");
    try {
      const { matrix, sourcePath } = await loadSkillsMatrixFromSource({
        sourceFlag: void 0,
        projectDir,
        forceRefresh
      });
      const primarySkills = Object.values(matrix.skills).filter((skill) => skill !== void 0).map((skill) => toSourcedSkill(skill, "marketplace", sourcePath));
      const { extras } = await resolveAllSources(projectDir);
      const extraSkillArrays = await Promise.all(
        extras.map((source) => fetchSkillsFromSource(source, forceRefresh))
      );
      const allSkills = [...primarySkills, ...extraSkillArrays.flat()];
      const sourceCount = 1 + extras.length;
      this.log(`Loaded ${allSkills.length} skills from ${sourceCount} source(s)`);
      this.log("");
      const searchResultPromise = new Promise((resolve) => {
        const { waitUntilExit } = render(
          /* @__PURE__ */ jsx(
            SkillSearch,
            {
              skills: allSkills,
              sourceCount,
              initialQuery,
              onComplete: (result) => {
                resolve(result);
              },
              onCancel: () => {
                resolve({ selectedSkills: [], cancelled: true });
              }
            }
          )
        );
        waitUntilExit().then(() => {
          resolve({ selectedSkills: [], cancelled: true });
        });
      });
      const searchResult = await searchResultPromise;
      if (searchResult.cancelled) {
        this.log("Search cancelled");
        this.exit(EXIT_CODES.CANCELLED);
      }
      if (searchResult.selectedSkills.length === 0) {
        this.log("No skills selected");
        return;
      }
      this.log("");
      this.log(`Importing ${searchResult.selectedSkills.length} skill(s)...`);
      const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);
      for (const skill of searchResult.selectedSkills) {
        if (skill.path) {
          const destPath = path.join(destDir, skill.id);
          await ensureDir(path.dirname(destPath));
          await copy(skill.path, destPath);
          this.logSuccess(`Imported: ${skill.id}`);
        } else {
          this.warn(`Skipping ${skill.id}: No source path available`);
        }
      }
      this.log("");
      this.logSuccess(SUCCESS_MESSAGES.IMPORT_COMPLETE);
      this.log(`Skills location: ${destDir}`);
      this.log(INFO_MESSAGES.RUN_COMPILE);
    } catch (error) {
      this.handleError(error);
    }
  }
  async runStatic(query, flags) {
    try {
      this.log(STATUS_MESSAGES.LOADING_SKILLS);
      const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({
        sourceFlag: flags.source
      });
      this.log(`Loaded from ${isLocal ? "local" : "remote"}: ${sourcePath}`);
      const allSkills = Object.values(matrix.skills).filter(
        (skill) => skill !== void 0
      );
      let results = allSkills.filter((skill) => matchesQuery(skill, query));
      if (flags.category) {
        results = results.filter((skill) => matchesCategory(skill, flags.category));
      }
      results = sortBy(results, (r) => (r.displayName || r.id).toLowerCase());
      this.log("");
      if (results.length === 0) {
        this.warn(`No skills found matching "${query}"`);
        if (flags.category) {
          this.logInfo(`Category filter: ${flags.category}`);
        }
      } else {
        this.logInfo(
          `Found ${results.length} skill${results.length === 1 ? "" : "s"} matching "${query}"`
        );
        if (flags.category) {
          this.logInfo(`Category filter: ${flags.category}`);
        }
        this.log("");
        printTable({
          data: results.map((skill) => ({
            id: skill.displayName || skill.id,
            category: skill.category,
            description: truncate(skill.description, MAX_DESCRIPTION_WIDTH)
          })),
          columns: [
            { key: "id", name: "ID" },
            { key: "category", name: "Category" },
            { key: "description", name: "Description" }
          ],
          headerOptions: { bold: true }
        });
      }
      this.log("");
    } catch (error) {
      this.handleError(error);
    }
  }
};
export {
  Search as default
};
//# sourceMappingURL=search.js.map