Files
Codewalkers/apps/server/db/repositories/drizzle/errand.ts
Lukas May 28521e1c20 chore: merge main into cw/small-change-flow
Integrates main branch changes (headquarters dashboard, task retry count,
agent prompt persistence, remote sync improvements) with the initiative's
errand agent feature. Both features coexist in the merged result.

Key resolutions:
- Schema: take main's errands table (nullable projectId, no conflictFiles,
  with errandsRelations); migrate to 0035_faulty_human_fly
- Router: keep both errandProcedures and headquartersProcedures
- Errand prompt: take main's simpler version (no question-asking flow)
- Manager: take main's status check (running|idle only, no waiting_for_input)
- Tests: update to match removed conflictFiles field and undefined vs null
2026-03-06 16:48:12 +01:00

90 lines
2.7 KiB
TypeScript

/**
* Drizzle Errand Repository Adapter
*
* Implements ErrandRepository interface using Drizzle ORM.
*/
import { eq, desc, and } from 'drizzle-orm';
import type { DrizzleDatabase } from '../../index.js';
import { errands, agents } from '../../schema.js';
import type {
ErrandRepository,
ErrandWithAlias,
ErrandStatus,
CreateErrandData,
UpdateErrandData,
} from '../errand-repository.js';
import type { Errand } from '../../schema.js';
export class DrizzleErrandRepository implements ErrandRepository {
constructor(private db: DrizzleDatabase) {}
async create(data: CreateErrandData): Promise<Errand> {
const now = new Date();
const [created] = await this.db
.insert(errands)
.values({ ...data, createdAt: now, updatedAt: now })
.returning();
return created;
}
async findById(id: string): Promise<ErrandWithAlias | undefined> {
const result = await this.db
.select({
id: errands.id,
description: errands.description,
branch: errands.branch,
baseBranch: errands.baseBranch,
agentId: errands.agentId,
projectId: errands.projectId,
status: errands.status,
createdAt: errands.createdAt,
updatedAt: errands.updatedAt,
agentAlias: agents.name,
})
.from(errands)
.leftJoin(agents, eq(errands.agentId, agents.id))
.where(eq(errands.id, id))
.limit(1);
return result[0] ?? undefined;
}
async findAll(opts?: { projectId?: string; status?: ErrandStatus }): Promise<ErrandWithAlias[]> {
const conditions = [];
if (opts?.projectId) conditions.push(eq(errands.projectId, opts.projectId));
if (opts?.status) conditions.push(eq(errands.status, opts.status));
return this.db
.select({
id: errands.id,
description: errands.description,
branch: errands.branch,
baseBranch: errands.baseBranch,
agentId: errands.agentId,
projectId: errands.projectId,
status: errands.status,
createdAt: errands.createdAt,
updatedAt: errands.updatedAt,
agentAlias: agents.name,
})
.from(errands)
.leftJoin(agents, eq(errands.agentId, agents.id))
.where(conditions.length > 0 ? and(...conditions) : undefined)
.orderBy(desc(errands.createdAt));
}
async update(id: string, data: UpdateErrandData): Promise<Errand> {
const [updated] = await this.db
.update(errands)
.set({ ...data, updatedAt: new Date() })
.where(eq(errands.id, id))
.returning();
if (!updated) throw new Error(`Errand not found: ${id}`);
return updated;
}
async delete(id: string): Promise<void> {
await this.db.delete(errands).where(eq(errands.id, id));
}
}