From 0294ccdd296bee6386c0106643bd5a45dc009384 Mon Sep 17 00:00:00 2001 From: Mikkel Georgsen Date: Wed, 1 Apr 2026 03:21:33 +0200 Subject: [PATCH] feat(11-01): add group table DDL and built-in group seeding to skill-registry-db - Import LibSQLClient type for seedBuiltinGroups parameter typing - Add DDL constants for 5 new tables: skill_groups, skill_group_members, skill_group_inheritance, agent_skill_groups, agent_skills - Add BUILTIN_GROUPS constant with 5 entries (pm-essentials, engineer-core, frontend, backend, creative) - Add seedBuiltinGroups() using INSERT OR IGNORE for idempotent seeding - Extend getSkillRegistryDb() to execute all 5 new DDL statements and seed --- server/src/services/skill-registry-db.ts | 89 +++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/server/src/services/skill-registry-db.ts b/server/src/services/skill-registry-db.ts index 9b26656a..63c078e4 100644 --- a/server/src/services/skill-registry-db.ts +++ b/server/src/services/skill-registry-db.ts @@ -1,7 +1,7 @@ import { mkdir } from "node:fs/promises"; import { dirname } from "node:path"; import { drizzle } from "drizzle-orm/libsql"; -import { createClient } from "@libsql/client"; +import { createClient, type Client as LibSQLClient } from "@libsql/client"; import * as schema from "./skill-registry-schema.js"; import { resolveSkillRegistryDbPath } from "../home-paths.js"; @@ -50,6 +50,85 @@ CREATE TABLE IF NOT EXISTS community_ratings ( source TEXT )`; +const CREATE_SKILL_GROUPS_TABLE = ` +CREATE TABLE IF NOT EXISTS skill_groups ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + description TEXT, + is_builtin INTEGER NOT NULL DEFAULT 0, + created_at INTEGER NOT NULL, + updated_at INTEGER NOT NULL +)`; + +const CREATE_SKILL_GROUP_MEMBERS_TABLE = ` +CREATE TABLE IF NOT EXISTS skill_group_members ( + group_id TEXT NOT NULL, + skill_id TEXT NOT NULL, + added_at INTEGER NOT NULL, + PRIMARY KEY (group_id, skill_id) +)`; + +const CREATE_SKILL_GROUP_INHERITANCE_TABLE = ` +CREATE TABLE IF NOT EXISTS skill_group_inheritance ( + child_group_id TEXT NOT NULL, + parent_group_id TEXT NOT NULL, + PRIMARY KEY (child_group_id, parent_group_id) +)`; + +const CREATE_AGENT_SKILL_GROUPS_TABLE = ` +CREATE TABLE IF NOT EXISTS agent_skill_groups ( + agent_id TEXT NOT NULL, + group_id TEXT NOT NULL, + assigned_at INTEGER NOT NULL, + PRIMARY KEY (agent_id, group_id) +)`; + +const CREATE_AGENT_SKILLS_TABLE = ` +CREATE TABLE IF NOT EXISTS agent_skills ( + agent_id TEXT NOT NULL, + skill_id TEXT NOT NULL, + installed_at INTEGER NOT NULL, + PRIMARY KEY (agent_id, skill_id) +)`; + +const BUILTIN_GROUPS = [ + { + id: "builtin/pm-essentials", + name: "PM Essentials", + description: "Core planning and project-management skills", + }, + { + id: "builtin/engineer-core", + name: "Engineer Core", + description: "Foundational engineering skills", + }, + { + id: "builtin/frontend", + name: "Frontend", + description: "UI and frontend development skills", + }, + { + id: "builtin/backend", + name: "Backend", + description: "API, database, and infrastructure skills", + }, + { + id: "builtin/creative", + name: "Creative", + description: "Writing, branding, and creative production", + }, +] as const; + +async function seedBuiltinGroups(client: LibSQLClient): Promise { + const now = Date.now(); + for (const group of BUILTIN_GROUPS) { + await client.execute({ + sql: `INSERT OR IGNORE INTO skill_groups (id, name, description, is_builtin, created_at, updated_at) VALUES (?, ?, ?, 1, ?, ?)`, + args: [group.id, group.name, group.description, now, now], + }); + } +} + export async function getSkillRegistryDb(): Promise { if (_db !== null) return _db; @@ -64,6 +143,14 @@ export async function getSkillRegistryDb(): Promise { await client.execute(CREATE_SKILL_FILES_TABLE); await client.execute(CREATE_COMMUNITY_RATINGS_TABLE); + await client.execute(CREATE_SKILL_GROUPS_TABLE); + await client.execute(CREATE_SKILL_GROUP_MEMBERS_TABLE); + await client.execute(CREATE_SKILL_GROUP_INHERITANCE_TABLE); + await client.execute(CREATE_AGENT_SKILL_GROUPS_TABLE); + await client.execute(CREATE_AGENT_SKILLS_TABLE); + + await seedBuiltinGroups(client); + return _db; }