feat: ingestion pipeline — ingestSource, atomic swap, examples, integration tests (tasks 4.5-4.8)#5
Conversation
- Add transaction<T> method to SkillRepository interface and SqliteSkillRepository - Implement ingestFromClonedPath (inner pipeline: discover→parse→bundle→atomicSwap) - Implement ingestSource (full pipeline with clone + cleanup in try/finally) - Implement atomicSwap using repository transaction for atomic delete+upsert - Implement loadExamplesIfEmpty seeding 3 built-in skills on first boot - Wire loadExamplesIfEmpty into buildServer startup sequence - Add integration tests for all 3 spec scenarios using real local git repos Co-authored-by: Cursor <cursoragent@cursor.com>
PR Summary by Qodofeat: ingestion pipeline — ingestSource, atomic swap, examples, integration tests Description
Diagram
High-Level Assessment
Files changed (7)
|
Code Review by Qodo
1.
|
- ingest: move clone() inside try/finally so partial clones are always cleaned up on failure (temp dir leak) - ingest: bundle first and reuse artifact content for frontmatter parsing on skill-md type, eliminating duplicate SKILL.md reads - examples: wrap source create + skill upsert in transactionSync so a transient failure cannot leave a permanent orphaned source row - db: rename transaction<T> → transactionSync<T> with doc comment making the sync-only contract explicit and preventing async misuse - test: remove unused beforeEach import (CI lint failure) Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Implements the full ingestion pipeline in
src/server/ingestion/, wiring the primitives from PR #4 into an end-to-end sync flow.ingest.ts—ingestSourceorchestrator (clone → discover → parse → bundle → atomic swap → cleanup); exportsingestFromClonedPathfor testability; best-effort per-skill error handling; temp dir always cleaned up viatry/finally; clone failures propagate to calleringest.ts—atomicSwapwrapsdeleteBySource+upsertManyin a single SQLite transaction via a newSkillRepository.transaction<T>()method — catalog is never in a partial state during re-syncexamples.ts—loadExamplesIfEmptyseeds the catalog with 3 built-in skills (git-conventional-commit,code-review-checklist,explain-code) on first boot when both the sources and skills tables are emptysrc/server/index.ts— wiresawait loadExamplesIfEmpty(db)at startupDesign note — examples source identity
The built-in examples source is created as a real source record (
slug: "examples",url: "built-in") to satisfy the SQLite FK constraint (source_id REFERENCES sources(id)).sourceId: 0is not usable — there is no source record at id=0 and auto-increment starts at 1. ThesourceSlug: "examples"sentinel is the reliable identifier for downstream code (e.g., filtering built-ins from the Sources API in Epic 6).Test plan
npm run build:server— zero TypeScript errorsnpm test— 46/46 passing (3 test files)Related
rhess-enterprise-skills-serverMade with Cursor