Files
logbuch/tests/docs/skill.test.ts
T
Matthias G 5072ff7249 Ship a Logbuch skill and record token use
- docs/skill.md teaches a Claude what Logbuch is for, how an entry sounds
  and in which order the calls go, served at GET /api/v1/skill and as a
  download next to the spec and the guide
- a test keeps the skill from drifting: frontmatter, only endpoints that
  exist, house rules
- resolveClient stamps last_used_at, the access list said never used even
  after eleven entries
2026-08-03 10:40:48 +02:00

60 lines
1.7 KiB
TypeScript

import { readFileSync, readdirSync, statSync } from 'node:fs'
import { join } from 'node:path'
import { describe, expect, it } from 'vitest'
const skill = readFileSync(join(process.cwd(), 'docs', 'skill.md'), 'utf8')
function routes(): string[] {
const found: string[] = []
function walk(dir: string, url: string) {
for (const name of readdirSync(dir)) {
const path = join(dir, name)
if (statSync(path).isDirectory()) {
walk(path, `${url}/${name}`)
continue
}
if (name === 'route.ts') {
found.push(url)
}
}
}
walk(join(process.cwd(), 'src', 'app', 'api', 'v1'), '/api/v1')
return found
}
describe('Skill für Claude', () => {
it('trägt Frontmatter mit Namen und Beschreibung', () => {
const head = skill.split('---')[1] ?? ''
expect(head).toMatch(/\nname: logbuch\n/u)
expect(head).toMatch(/\ndescription: .{40,}/u)
})
it('nennt nur Endpunkte, die es gibt', () => {
const known = new Set(routes().map(url => url.replace(/\/\[[^\]]+\]/gu, '')))
const mentioned = [...skill.matchAll(/`?(?:GET|POST|PUT|PATCH|DELETE) (\/api\/v1[a-z0-9./-]*)/giu)]
.map(match => match[1]!.replace(/\/(?::[a-z]+|<[a-z-]+>)/giu, '').replace(/\/$/u, ''))
expect(mentioned.length).toBeGreaterThan(5)
for (const url of new Set(mentioned)) {
expect(known.has(url), `${url} steht im Skill, aber nicht im Code`).toBe(true)
}
})
it('hält sich an die Hausregeln', () => {
expect(skill).not.toMatch(/[—–]/u)
expect(skill).not.toMatch(/\p{Extended_Pictographic}/u)
expect(skill).not.toMatch(/\b(fuer|ueber|koennen|muessen|loeschen|aendern|groesser|gehoert|laesst|veroeffentlich\w*)\b/iu)
})
it('sagt, dass ein Zugang nicht veröffentlichen kann', () => {
expect(skill).toMatch(/niemals veröffentlichen/u)
})
})