File size: 3,440 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import { test } from "node:test";
import assert from "node:assert/strict";
import { readdir, readFile, access } from "node:fs/promises";
import { join } from "node:path";

// Lint dos manifests de skills da CLI (skills/<dir>/SKILL.md).
//
// Religado pela auditoria 6A.1 (2026-06-09): este arquivo era órfão (nenhum runner
// coletava tests/unit/docs/) e apodreceu — filtrava dirs `omniroute*`, mas os skills
// foram renomeados para `cli-*`; com 0 dirs o segundo teste passava VACUOSAMENTE.
// Atualizado para o estado real: todo dir de skills/ com SKILL.md é validado, e o
// invariante de uso é "referencia as env vars ($OMNIROUTE_URL/OMNIROUTE_KEY) OU
// comandos da CLI (`omniroute …`)" — 3 skills (health/keys/batches) usam só a CLI.
const SKILLS_DIR = join(process.cwd(), "skills");
const REQUIRED_FRONTMATTER = ["name:", "description:"];

async function listSkillDirs(): Promise<string[]> {
  const entries = await readdir(SKILLS_DIR, { withFileTypes: true });
  const dirs: string[] = [];
  for (const e of entries) {
    if (!e.isDirectory()) continue;
    try {
      await access(join(SKILLS_DIR, e.name, "SKILL.md"));
      dirs.push(e.name);
    } catch {
      // dir sem SKILL.md é coberto pelo teste de completude abaixo
    }
  }
  return dirs;
}

test("each skill dir has SKILL.md with frontmatter", async () => {
  const dirs = await listSkillDirs();
  assert.ok(dirs.length >= 40, `Expected ≥40 skill dirs, got ${dirs.length}`);
  for (const dir of dirs) {
    const path = join(SKILLS_DIR, dir, "SKILL.md");
    const content = await readFile(path, "utf-8");
    assert.ok(content.startsWith("---\n"), `${dir}: missing opening frontmatter`);
    for (const key of REQUIRED_FRONTMATTER) {
      assert.ok(content.includes(key), `${dir}: missing frontmatter key ${key}`);
    }
    // Skills `omni-*` são GERADOS por src/lib/agentSkills/generator.ts (alguns em
    // estado "no endpoints mapped yet", sem refs de uso) — o invariante de uso vale
    // só para os manifests manuscritos (cli-* e config-*).
    if (!dir.startsWith("omni-")) {
      assert.ok(
        content.includes("OMNIROUTE_") || content.includes("omniroute "),
        `${dir}: missing usage references (OMNIROUTE_* env vars or omniroute CLI commands)`
      );
    }
  }
});

test("every directory under skills/ ships a SKILL.md", async () => {
  const entries = await readdir(SKILLS_DIR, { withFileTypes: true });
  const missing: string[] = [];
  for (const e of entries) {
    if (!e.isDirectory()) continue;
    try {
      await access(join(SKILLS_DIR, e.name, "SKILL.md"));
    } catch {
      missing.push(e.name);
    }
  }
  assert.deepEqual(missing, [], `skill dirs without SKILL.md: ${missing.join(", ")}`);
});

test("description field is meaningful (≥50 chars)", async () => {
  const dirs = await listSkillDirs();
  assert.ok(dirs.length > 0, "no skill dirs found — listSkillDirs is broken");
  for (const dir of dirs) {
    const content = await readFile(join(SKILLS_DIR, dir, "SKILL.md"), "utf-8");
    const match = content.match(/^description:\s*(.+?)$/m);
    assert.ok(match, `${dir}: no description field`);
    const desc = match![1];
    // Nota: o assert antigo exigia a frase-gatilho "Use when" — nenhum dos 43 skills
    // reais a usa; o invariante verificável é descrição substantiva (≥50 chars).
    assert.ok(desc.length >= 50, `${dir}: description too short (${desc.length})`);
  }
});