feat(reader): Gitea client + config + board orchestrator

closes board-viewer-gitea-reader

- src/gitea.ts: HTTP client (getFile, getLatestCommitIso, rawUrl); DI'd fetch
- src/reader.ts: readBoard(client, repos) → TaskRecord[]
- src/config.ts: TOML config loader with board_viewer_repos whitelist
- 25 tests total (9 parser incl. 3 real-repo fixtures, 7 gitea, 5 reader, 4 config)
- emoji contract 🔴🟡🔵🟢 (open/in_progress/paused/blocked/done)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
vitya
2026-05-22 12:48:37 +03:00
parent 1c7e372abf
commit d093693795
14 changed files with 2543 additions and 15 deletions

View File

@@ -33,6 +33,22 @@ describe('parseStatus', () => {
expect(parseStatus('# Task Board\n_Updated: 2026-05-22_\n\nNo tasks yet.\n')).toEqual([]);
});
test.each([
'real-books-STATUS.md',
'real-claude-skills-STATUS.md',
'real-projects-meta-mcp-STATUS.md',
])('parses real STATUS.md fixture %s without crashing and yields ≥1 block', (name) => {
const blocks = parseStatus(fixture(name));
expect(blocks.length).toBeGreaterThan(0);
for (const b of blocks) {
expect(b.slug).toMatch(/^[a-z0-9][a-z0-9-]*$/);
expect(b.status).toMatch(/^(open|in_progress|paused|blocked|done)$/);
expect(b.status_emoji).toMatch(/^(|🔴|🟡|🔵|🟢)$/u);
expect(b.title.length).toBeGreaterThan(0);
}
});
test('ignores blocks whose H2 has no known status emoji', () => {
const text = '## 🚀 [some-task] — title\n**Status:** custom\n**Branch:** master\n---\n';
expect(parseStatus(text)).toEqual([]);