- Install @libsql/client@^0.17.2 to server package - Create skill-registry-schema.ts with 4 sqliteTable definitions (skills, skillVersions, skillFiles, communityRatings) - Create skill-registry-db.ts with lazy singleton getSkillRegistryDb() and resetSkillRegistryDb() - Add resolveSkillRegistryDbPath() and resolveSkillCacheDir() to home-paths.ts - Add skill-registry-schema.test.ts with 8 passing tests (TDD green)
73 lines
1.9 KiB
TypeScript
73 lines
1.9 KiB
TypeScript
import { mkdir } from "node:fs/promises";
|
|
import { dirname } from "node:path";
|
|
import { drizzle } from "drizzle-orm/libsql";
|
|
import { createClient } from "@libsql/client";
|
|
import * as schema from "./skill-registry-schema.js";
|
|
import { resolveSkillRegistryDbPath } from "../home-paths.js";
|
|
|
|
export type SkillRegistryDb = ReturnType<typeof drizzle<typeof schema>>;
|
|
|
|
let _db: SkillRegistryDb | null = null;
|
|
|
|
const CREATE_SKILLS_TABLE = `
|
|
CREATE TABLE IF NOT EXISTS skills (
|
|
id TEXT PRIMARY KEY,
|
|
source_id TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
description TEXT,
|
|
source_url TEXT,
|
|
active_version_id TEXT,
|
|
removed_at INTEGER,
|
|
created_at INTEGER NOT NULL,
|
|
updated_at INTEGER NOT NULL
|
|
)`;
|
|
|
|
const CREATE_SKILL_VERSIONS_TABLE = `
|
|
CREATE TABLE IF NOT EXISTS skill_versions (
|
|
id TEXT PRIMARY KEY,
|
|
skill_id TEXT NOT NULL,
|
|
version TEXT NOT NULL,
|
|
fetched_at INTEGER NOT NULL,
|
|
cache_dir TEXT
|
|
)`;
|
|
|
|
const CREATE_SKILL_FILES_TABLE = `
|
|
CREATE TABLE IF NOT EXISTS skill_files (
|
|
id TEXT PRIMARY KEY,
|
|
version_id TEXT NOT NULL,
|
|
path TEXT NOT NULL,
|
|
kind TEXT NOT NULL,
|
|
size_bytes INTEGER
|
|
)`;
|
|
|
|
const CREATE_COMMUNITY_RATINGS_TABLE = `
|
|
CREATE TABLE IF NOT EXISTS community_ratings (
|
|
id TEXT PRIMARY KEY,
|
|
skill_id TEXT NOT NULL,
|
|
fetched_at INTEGER NOT NULL,
|
|
average_rating REAL,
|
|
rating_count INTEGER,
|
|
source TEXT
|
|
)`;
|
|
|
|
export async function getSkillRegistryDb(): Promise<SkillRegistryDb> {
|
|
if (_db !== null) return _db;
|
|
|
|
const dbPath = resolveSkillRegistryDbPath();
|
|
await mkdir(dirname(dbPath), { recursive: true });
|
|
|
|
const client = createClient({ url: `file:${dbPath}` });
|
|
_db = drizzle({ client, schema });
|
|
|
|
await client.execute(CREATE_SKILLS_TABLE);
|
|
await client.execute(CREATE_SKILL_VERSIONS_TABLE);
|
|
await client.execute(CREATE_SKILL_FILES_TABLE);
|
|
await client.execute(CREATE_COMMUNITY_RATINGS_TABLE);
|
|
|
|
return _db;
|
|
}
|
|
|
|
/** Reset the singleton — used for test cleanup */
|
|
export function resetSkillRegistryDb(): void {
|
|
_db = null;
|
|
}
|