fix(skills): исключить исходники из обнаружения

This commit is contained in:
Gromov Sergei
2026-09-12 10:44:49 +03:00
parent e96eed9522
commit 518d1a4046
11 changed files with 186 additions and 8 deletions
+72
View File
@@ -0,0 +1,72 @@
import assert from 'node:assert/strict'
import { execFileSync } from 'node:child_process'
import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import test from 'node:test'
import { checkSkills } from '../scripts/check-skills.mjs'
const valid = '---\nname: example\ndescription: >-\n Проверенный skill\n---\n# Example\n'
function repository(t) {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'skill-check-'))
t.after(() => fs.rmSync(root, { recursive: true, force: true }))
const git = (...args) => execFileSync('git', ['-C', root, ...args], { stdio: 'pipe' })
git('init', '--quiet')
const write = (file, content) => {
const target = path.join(root, file)
fs.mkdirSync(path.dirname(target), { recursive: true })
fs.writeFileSync(target, content)
}
write('skills/example/SKILL.md', valid)
return { root, write, git }
}
test('проверяет новый skill с YAML block scalar и отдельным исходником', (t) => {
const { root, write } = repository(t)
write('src/example/SKILL.source.md', valid)
assert.deepEqual(checkSkills(root), ['example'])
})
test('отклоняет одинаковые SKILL.md в исходниках и готовом каталоге', (t) => {
const { root, write } = repository(t)
write('src/skills/example/SKILL.md', valid)
assert.throws(() => checkSkills(root), /Повторное имя example/)
})
test('находит заготовку без frontmatter в скрытом вложенном каталоге', (t) => {
const { root, write } = repository(t)
write('.hidden/src/en/SKILL.md', '# Заготовка\n')
assert.throws(() => checkSkills(root), /Нет YAML-frontmatter: .hidden\/src\/en\/SKILL.md/)
})
for (const [title, metadata, error] of [
['нет name', 'description: example', /Некорректное name/],
['нет description', 'name: example', /description должен/],
['description не строка', 'name: example\ndescription: true', /description должен/],
['пустое description', 'name: example\ndescription: " "', /description должен/],
['ошибка YAML', 'name: [example\ndescription: example', /Некорректный YAML/],
['повтор поля YAML', 'name: example\nname: example\ndescription: example', /Некорректный YAML/],
['имя другого каталога', 'name: another\ndescription: example', /name не совпадает/],
]) {
test(`отклоняет frontmatter: ${title}`, (t) => {
const { root, write } = repository(t)
write('skills/example/SKILL.md', `---\n${metadata}\n---\n# Example\n`)
assert.throws(() => checkSkills(root), error)
})
}
test('игнорирует локальные зависимости, но обнаруживает их в Git-поставке', (t) => {
const { root, write, git } = repository(t)
write('.gitignore', '/.agents/skills/\n')
write('.agents/skills/example/SKILL.md', valid)
assert.deepEqual(checkSkills(root), ['example'])
git('add', '--force', '.agents/skills/example/SKILL.md')
assert.throws(() => checkSkills(root), /SKILL.md вне skills/)
})
test('отклоняет каталог skill без точки входа', (t) => {
const { root, write } = repository(t)
write('skills/incomplete/reference.md', '# Reference\n')
assert.throws(() => checkSkills(root), /Отсутствует точка входа: skills\/incomplete\/SKILL.md/)
})