import { eq, and, or, type Db, agents } from '@mosaic/db'; export type Agent = typeof agents.$inferSelect; export type NewAgent = typeof agents.$inferInsert; export function createAgentsRepo(db: Db) { return { async findAll(): Promise { return db.select().from(agents); }, async findById(id: string): Promise { const rows = await db.select().from(agents).where(eq(agents.id, id)); return rows[0]; }, async findByName(name: string): Promise { const rows = await db.select().from(agents).where(eq(agents.name, name)); return rows[0]; }, async findByProject(projectId: string): Promise { return db.select().from(agents).where(eq(agents.projectId, projectId)); }, async findSystem(): Promise { return db.select().from(agents).where(eq(agents.isSystem, true)); }, /** * Return only agents the user may access: their own agents plus all system agents. * Never returns other users' private agents. */ async findAccessible(ownerId: string): Promise { return db .select() .from(agents) .where(or(eq(agents.ownerId, ownerId), eq(agents.isSystem, true))); }, async create(data: NewAgent): Promise { const rows = await db.insert(agents).values(data).returning(); return rows[0]!; }, /** * Update an agent. * * For user-owned agents pass `ownerId` — the WHERE clause will enforce ownership so that * one user cannot overwrite another user's agent. For system agents the caller must * omit `ownerId` (admin-only path) and the WHERE clause only matches on `id`. * * Returns undefined when no row was matched (not found or ownership mismatch). */ async update( id: string, data: Partial, ownerId?: string, ): Promise { const condition = ownerId !== undefined ? and(eq(agents.id, id), eq(agents.ownerId, ownerId)) : eq(agents.id, id); const rows = await db .update(agents) .set({ ...data, updatedAt: new Date() }) .where(condition) .returning(); return rows[0]; }, /** * Delete a user-owned agent, scoped to the given owner. * Will not match system agents even if the id is correct, because system agents have * `ownerId = null` which cannot equal a real user id. * Returns false when no row was matched (not found, wrong owner, or system agent). */ async remove(id: string, ownerId: string): Promise { const rows = await db .delete(agents) .where(and(eq(agents.id, id), eq(agents.ownerId, ownerId))) .returning(); return rows.length > 0; }, }; } export type AgentsRepo = ReturnType;