#!/usr/bin/env node
// Generate per-family skill counts from a magpie `skills/` directory.
//
// The website's skill-family counts used to be hand-edited in
// ImmersiveGradientHero.tsx and drifted every time a skill landed upstream.
// This script derives the counts from the actual SKILL.md directories so they
// stay in sync with apache/magpie. It is invoked by scripts/sync-docs.sh after
// the framework repo is checked out.
//
// Family membership is read straight from each skill's `family:` frontmatter
// key — the single source of truth apache/magpie declares (skills/setup/SKILL.md
// Golden rule 8; validated against ALLOWED_FAMILIES in the skill-and-tool-
// validator). It is never inferred from the skill's name prefix: a name-prefix
// heuristic cannot express families that span prefixes (e.g. contributor-growth,
// repo-health) and silently mis-classified skills whenever upstream added one.
//
// Usage: node gen-skill-counts.mjs <skills-dir> <out-json>
//
// Output is deterministic (no timestamps) so the committed JSON only changes
// when the counts actually change.

import {
  readdirSync,
  statSync,
  existsSync,
  readFileSync,
  writeFileSync,
} from "node:fs";
import { join } from "node:path";

const [, , skillsDir, outPath] = process.argv;
if (!skillsDir || !outPath) {
  console.error("usage: gen-skill-counts.mjs <skills-dir> <out-json>");
  process.exit(1);
}

// Read the `family:` frontmatter key from a skill's SKILL.md. Returns the
// declared family, or null when the SKILL.md is absent/unreadable or declares
// no family (mirrors read_family() in setup-status/collect_status.py). Family
// is never inferred from the name prefix.
function readFamily(name) {
  let text;
  try {
    text = readFileSync(join(skillsDir, name, "SKILL.md"), "utf8");
  } catch {
    return null;
  }
  if (!text.startsWith("---")) return null;
  const end = text.indexOf("\n---", 3);
  const frontmatter = end !== -1 ? text.slice(3, end) : text;
  for (const raw of frontmatter.split("\n")) {
    const line = raw.trim();
    if (line.startsWith("family:")) {
      return line.slice("family:".length).trim() || null;
    }
  }
  return null;
}

const dirs = readdirSync(skillsDir)
  .filter((d) => {
    try {
      return (
        statSync(join(skillsDir, d)).isDirectory() &&
        existsSync(join(skillsDir, d, "SKILL.md"))
      );
    } catch {
      return false;
    }
  })
  .sort();

const counts = {};
const uncategorized = [];
for (const name of dirs) {
  const family = readFamily(name);
  if (!family) {
    uncategorized.push(name);
    continue;
  }
  counts[family] = (counts[family] || 0) + 1;
}

if (uncategorized.length) {
  console.warn(
    `⚠ ${uncategorized.length} skill(s) declare no family: ${uncategorized.join(", ")}`,
  );
}

// Sort family keys for stable, diff-friendly output.
const sortedCounts = Object.fromEntries(
  Object.keys(counts)
    .sort()
    .map((k) => [k, counts[k]]),
);

const out = {
  _comment:
    "GENERATED by scripts/gen-skill-counts.mjs — do not edit by hand. Counts derive from the `family:` frontmatter of apache/magpie skills/.",
  total: dirs.length,
  uncategorized,
  counts: sortedCounts,
};

writeFileSync(outPath, JSON.stringify(out, null, 2) + "\n");
console.log(`✓ skill counts → ${outPath}: ${JSON.stringify(sortedCounts)}`);
