teqo-backup/tests/unit/opencodeCommands.unit.spec.ts
Francisco Solla e5e1ae7ee8 feat(C190): dossiê Solla por tema/área + boletim modelo (skill + builder)
Terceira variante da família de dossiês: recorte pela área canônica do
acervo (SPEECH_TOPICS), com o pipeline C186/C187 generalizado para a forma
subject via THEME_UNIT (generalização aditiva; C186/C187 byte-idênticos).

- resolveSpeechTopic no dono speechFacets (fail-closed, sem slug inventado)
- themeSnapshot + extract-theme-snapshot (THEME_REPORT_CONFIRM=1, read-only)
- build-dossie-solla-tema (pack medido, PDF A4 + .md + boletim 1 página)
- skill/comando/2 subagentes (researcher por era + redator) + specs
- cenas theme-only no descritor (acervo universo/amostra, abrangência,
  lacunas, hierarquia de fontes, pills do boletim) certificadas pelo designer

Closes #1143
2026-09-18 17:02:56 -03:00

50 lines
2 KiB
TypeScript

import { existsSync, readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
// Programmatic guard for the OPS25 coupling: each `.opencode/commands/<name>.md`
// must keep pointing at the skill of the same name (`.agents/skills/<name>/SKILL.md`).
// The command body deliberately does NOT transcribe the skill — the canonical
// source is the SKILL.md. If a skill is renamed, this spec fails the build so the
// command is renamed together instead of breaking silently at the `/` prompt.
const repoRoot = process.cwd()
const commands = [
'work-issue',
'plan-issue',
'testing-audit',
'bug-fix',
'relatorio-cidade',
'dossie-solla-cidade',
'dossie-solla-instituicao',
'dossie-solla-tema',
] as const
describe('opencode commands couple to their skill by exact name', () => {
it.each(commands)('command /%s references the existing skill of the same name', (name) => {
const commandPath = resolve(repoRoot, `.opencode/commands/${name}.md`)
const skillPath = resolve(repoRoot, `.agents/skills/${name}/SKILL.md`)
expect(existsSync(commandPath), 'command file must exist').toBe(true)
expect(existsSync(skillPath), 'referenced skill must exist').toBe(true)
const content = readFileSync(commandPath, 'utf8')
expect(content, 'command must reference the skill by exact name').toContain(`\`${name}\``)
expect(content, 'command must pass arguments through').toContain('$ARGUMENTS')
expect(content, 'command must point at the canonical skill file').toContain(
`.agents/skills/${name}/SKILL.md`,
)
const frontmatter = content.match(/^---\n([\s\S]*?)\n---/)
expect(frontmatter, 'frontmatter must be delimited by ---').not.toBeNull()
expect(frontmatter![1], 'frontmatter must declare a TUI description').toMatch(
/^description: .+$/m,
)
expect(
frontmatter![1],
'frontmatter must NOT pin a model — the command inherits the session model (OPS101)',
).not.toMatch(/^\s*["']?model["']?\s*:/m)
})
})