#!/usr/bin/env node
// build-time gate: rejects prose that tells an agent to load a
// SKILL.md via `plugin-read`. `skill-load skillName=<name>` is the canonical
// resolve+read primitive for skills; `plugin-read` retains ownership of
// `references/*` and `PLUGIN.md` (both inherently plugin-scoped).
//
// Two phrasing classes regressed historically (corrections ledger:
// `path-as-pluginName`, count >= 1):
//   1. Literal-path:  "Load `<plugin>/skills/<slug>/SKILL.md` via `plugin-read`"
//   2. Manifest-pointer: "load via `plugin-read` (find its path in the manifest ...)"
// Both surface the same failure — the LLM packs the path into the `pluginName`
// argument and hits the not-found branch. This gate fails CI if either phrasing
// reappears in `platform/templates/` or in any plugin's `SKILL.md` / `PLUGIN.md`.
//
// Scope: prose-only Markdown the agent reads as instructions. Code files are
// out of scope (TypeScript / shell already lint elsewhere). References under
// `skills/*/references/` are out of scope because they document end-user
// behaviour, not agent routing. The MCP server's `index.ts` and tests are
// covered by their own type checks + the `skill-load.test.ts` suite.

import { readFileSync, readdirSync, statSync, existsSync } from 'node:fs'
import { dirname, join, basename } from 'node:path'
import { fileURLToPath } from 'node:url'

const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url))
const REPO_ROOT = join(SCRIPT_DIR, '..', '..')

const SCAN_ROOTS = [
  join(REPO_ROOT, 'platform', 'templates'),
  join(REPO_ROOT, 'platform', 'plugins'),
]

// Phrasing 1 — literal SKILL.md path with `via plugin-read`. Matches every
// historical site that named a path string.
const PATH_PHRASING_RE = /Load\s+[`"]?[\w/-]*skills\/[a-z0-9-]+\/SKILL\.md[`"]?\s+via\s+`?plugin-read`?/i

// Phrasing 2 — manifest-pointer "via plugin-read (find its path in the manifest ...)"
// from sites that referred the agent to the manifest instead of naming a path.
const MANIFEST_PHRASING_RE = /via\s+`?plugin-read`?\s*\(\s*find its path in the manifest/i

// Only scan files that an agent reads as routing instructions.
function shouldScanFile(filePath) {
  const base = basename(filePath)
  if (base === 'SKILL.md' || base === 'PLUGIN.md' || base === 'IDENTITY.md' || base === 'SOUL.md') return true
  // Specialist agent files live under platform/templates/specialists/agents/*.md
  if (filePath.includes('/templates/specialists/agents/') && filePath.endsWith('.md')) return true
  // Other markdown under templates/agents/ (admin/public IDENTITY.md handled by base check)
  if (filePath.includes('/templates/agents/') && filePath.endsWith('.md')) return true
  return false
}

const SKIP_DIR_NAMES = new Set(['node_modules', 'dist', '.git', 'references', 'archive'])

function* walk(root) {
  if (!existsSync(root)) return
  for (const entry of readdirSync(root)) {
    if (SKIP_DIR_NAMES.has(entry)) continue
    const full = join(root, entry)
    let stat
    try { stat = statSync(full) } catch { continue }
    if (stat.isDirectory()) {
      yield* walk(full)
    } else if (stat.isFile()) {
      yield full
    }
  }
}

const violations = []

for (const root of SCAN_ROOTS) {
  for (const file of walk(root)) {
    if (!shouldScanFile(file)) continue
    let text
    try { text = readFileSync(file, 'utf-8') } catch { continue }
    const lines = text.split('\n')
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i]
      if (PATH_PHRASING_RE.test(line)) {
        violations.push({ file, line: i + 1, phrasing: 'literal-path', text: line.trim() })
      } else if (MANIFEST_PHRASING_RE.test(line)) {
        violations.push({ file, line: i + 1, phrasing: 'manifest-pointer', text: line.trim() })
      }
    }
  }
}

if (violations.length > 0) {
  console.error(`check-skill-load-coverage: ${violations.length} prose site(s) still tell the agent to load a skill via plugin-read.`)
  console.error(`Rewrite each to: Run \`skill-load skillName=<name>\``)
  console.error(``)
  for (const v of violations) {
    const rel = v.file.replace(REPO_ROOT + '/', '')
    console.error(`  ${rel}:${v.line}  [${v.phrasing}]`)
    console.error(`    ${v.text.slice(0, 200)}${v.text.length > 200 ? '…' : ''}`)
  }
  process.exit(1)
}

console.log(`check-skill-load-coverage: ok (0 prose sites use legacy plugin-read for skills)`)
