| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| import { desc, eq } from "drizzle-orm"; |
| import { |
| db, |
| executionPlans, |
| type ExecutionPlanRow, |
| type InsertExecutionPlanRow, |
| } from "@workspace/db"; |
| import { newId } from "./ids"; |
|
|
| export type PlanStatus = |
| | "draft" |
| | "approved" |
| | "running" |
| | "completed" |
| | "failed" |
| | "cancelled"; |
|
|
| export interface BlueprintBody { |
| |
| networkName: string; |
| |
| input: Record<string, unknown>; |
| |
| tasks: Array<{ taskKey: string; params: Record<string, unknown> }>; |
| |
| notes?: string; |
| } |
|
|
| export interface CreateBlueprintInput { |
| conversationId?: string | null; |
| ownerUserId?: string | null; |
| problemClassPath: string; |
| networkId: string; |
| versionId: string; |
| body: BlueprintBody; |
| notes?: string; |
| } |
|
|
| export async function createBlueprint( |
| input: CreateBlueprintInput, |
| ): Promise<ExecutionPlanRow> { |
| const row: InsertExecutionPlanRow = { |
| id: newId("eplan"), |
| conversationId: input.conversationId ?? null, |
| ownerUserId: input.ownerUserId ?? null, |
| problemClassPath: input.problemClassPath, |
| networkId: input.networkId, |
| versionId: input.versionId, |
| blueprint: input.body, |
| status: "draft", |
| notes: input.notes ?? "", |
| }; |
| const [inserted] = await db.insert(executionPlans).values(row).returning(); |
| return inserted!; |
| } |
|
|
| export async function getBlueprint( |
| id: string, |
| ): Promise<ExecutionPlanRow | null> { |
| const rows = await db |
| .select() |
| .from(executionPlans) |
| .where(eq(executionPlans.id, id)) |
| .limit(1); |
| return rows[0] ?? null; |
| } |
|
|
| export async function listBlueprints( |
| ownerUserId?: string | null, |
| limit = 50, |
| ): Promise<ExecutionPlanRow[]> { |
| let q = db.select().from(executionPlans).$dynamic(); |
| if (ownerUserId) q = q.where(eq(executionPlans.ownerUserId, ownerUserId)); |
| return q.orderBy(desc(executionPlans.createdAt)).limit(limit); |
| } |
|
|
| export async function approveBlueprint( |
| id: string, |
| approvedBy: string, |
| ): Promise<ExecutionPlanRow> { |
| const [updated] = await db |
| .update(executionPlans) |
| .set({ |
| status: "approved", |
| approvedBy, |
| approvedAt: new Date(), |
| updatedAt: new Date(), |
| }) |
| .where(eq(executionPlans.id, id)) |
| .returning(); |
| if (!updated) throw new Error(`blueprint ${id} not found`); |
| return updated; |
| } |
|
|
| export async function setBlueprintStatus( |
| id: string, |
| status: PlanStatus, |
| patch?: { artifactPath?: string | null; notes?: string }, |
| ): Promise<ExecutionPlanRow> { |
| const [updated] = await db |
| .update(executionPlans) |
| .set({ |
| status, |
| ...(patch?.artifactPath !== undefined |
| ? { outputArtifactPath: patch.artifactPath } |
| : {}), |
| ...(patch?.notes !== undefined ? { notes: patch.notes } : {}), |
| updatedAt: new Date(), |
| }) |
| .where(eq(executionPlans.id, id)) |
| .returning(); |
| if (!updated) throw new Error(`blueprint ${id} not found`); |
| return updated; |
| } |
|
|
| export function blueprintBody(row: ExecutionPlanRow): BlueprintBody { |
| return row.blueprint as BlueprintBody; |
| } |
|
|