test-repo/scripts/gantt-task-crud.ts
Matt Bruce 9cfd7843b8 docs: memory and task CRUD scripts
- Add gantt task CRUD bash and TypeScript utilities
- Update MEMORY.md with CRUD capabilities and rules
- Update daily memory with subagent completions
- Document: full task links, attach-then-delete rule
2026-02-21 16:32:24 -06:00

183 lines
4.8 KiB
TypeScript

/**
* Gantt Board Task CRUD Utilities
* Full CRUD operations on gantt board tasks via Supabase
*/
const SUPABASE_URL = "https://qnatchrjlpehiijwtreh.supabase.co";
const SERVICE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InFuYXRjaHJqbHBlaGlpand0cmVoIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc3MTY0MDQzNiwiZXhwIjoyMDg3MjE2NDM2fQ.rHoc3NfL59S4lejU4-ArSzox1krQkQG-TnfXb6sslm0";
const HEADERS = {
"apikey": SERVICE_KEY,
"Authorization": `Bearer ${SERVICE_KEY}`,
"Content-Type": "application/json",
};
/**
* Generate UUID v4
*/
function generateUUID(): string {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0;
const v = c === "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
/**
* Get current ISO timestamp
*/
function nowISO(): string {
return new Date().toISOString();
}
/**
* Task interface
*/
export interface GanttTask {
id: string;
title: string;
description?: string;
status: "open" | "todo" | "blocked" | "in-progress" | "review" | "validate" | "archived" | "canceled" | "done";
priority: "low" | "medium" | "high" | "urgent";
type?: "idea" | "task" | "bug" | "research" | "plan";
project_id: string;
sprint_id?: string;
assignee_id?: string;
created_at: string;
updated_at: string;
due_date?: string;
tags?: string[];
comments?: unknown[];
attachments?: unknown[];
}
/**
* LIST all tasks (optionally filtered by status)
*/
export async function listTasks(status?: string): Promise<GanttTask[]> {
let url = `${SUPABASE_URL}/rest/v1/tasks?select=*&order=created_at.desc`;
if (status) {
url = `${SUPABASE_URL}/rest/v1/tasks?select=*&status=eq.${status}&order=created_at.desc`;
}
const res = await fetch(url, { headers: HEADERS });
if (!res.ok) throw new Error(`Failed to list tasks: ${res.status}`);
return res.json();
}
/**
* GET a single task by ID
*/
export async function getTask(taskId: string): Promise<GanttTask | null> {
const url = `${SUPABASE_URL}/rest/v1/tasks?id=eq.${taskId}&select=*`;
const res = await fetch(url, { headers: HEADERS });
if (!res.ok) throw new Error(`Failed to get task: ${res.status}`);
const tasks = await res.json();
return tasks[0] || null;
}
/**
* CREATE a new task
*/
export async function createTask(params: {
title: string;
description?: string;
status?: GanttTask["status"];
priority?: GanttTask["priority"];
type?: GanttTask["type"];
projectId?: string;
assigneeId?: string;
dueDate?: string;
tags?: string[];
}): Promise<GanttTask> {
const task: Partial<GanttTask> = {
id: generateUUID(),
title: params.title,
description: params.description,
status: params.status || "open",
priority: params.priority || "medium",
type: params.type || "task",
project_id: params.projectId || "1",
assignee_id: params.assigneeId || "9c29cc99-81a1-4e75-8dff-cd7cc5ceb5aa", // Max
created_at: nowISO(),
updated_at: nowISO(),
due_date: params.dueDate,
tags: params.tags || [],
comments: [],
attachments: [],
};
const res = await fetch(`${SUPABASE_URL}/rest/v1/tasks`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify(task),
});
if (!res.ok) throw new Error(`Failed to create task: ${res.status}`);
return task as GanttTask;
}
/**
* UPDATE a task (partial update)
*/
export async function updateTask(
taskId: string,
updates: Partial<Omit<GanttTask, "id" | "created_at">>
): Promise<void> {
const payload = {
...updates,
updated_at: nowISO(),
};
const res = await fetch(`${SUPABASE_URL}/rest/v1/tasks?id=eq.${taskId}`, {
method: "PATCH",
headers: HEADERS,
body: JSON.stringify(payload),
});
if (!res.ok) throw new Error(`Failed to update task: ${res.status}`);
}
/**
* DELETE a task
*/
export async function deleteTask(taskId: string): Promise<void> {
const res = await fetch(`${SUPABASE_URL}/rest/v1/tasks?id=eq.${taskId}`, {
method: "DELETE",
headers: HEADERS,
});
if (!res.ok) throw new Error(`Failed to delete task: ${res.status}`);
}
/**
* Update task status (convenience method)
*/
export async function updateTaskStatus(
taskId: string,
status: GanttTask["status"]
): Promise<void> {
return updateTask(taskId, { status });
}
/**
* Assign task to user (convenience method)
*/
export async function assignTask(
taskId: string,
assigneeId: string
): Promise<void> {
return updateTask(taskId, { assignee_id: assigneeId });
}
/**
* Mark task as done (convenience method)
*/
export async function completeTask(taskId: string): Promise<void> {
return updateTask(taskId, { status: "done" });
}
// Example usage:
// const task = await createTask({ title: "New feature", priority: "high" });
// await updateTaskStatus(task.id, "in-progress");
// await completeTask(task.id);