(input: CreateTaskInput)
| 46 | } |
| 47 | |
| 48 | export function createTask(input: CreateTaskInput): Task { |
| 49 | const db = getDb(); |
| 50 | const now = new Date().toISOString(); |
| 51 | |
| 52 | // If a blocker is named AND it isn't already terminal, force this task |
| 53 | // into `blocked` so it won't be picked up before the blocker resolves. |
| 54 | // Race-free because better-sqlite3 is synchronous in this process: by |
| 55 | // the time the propagation hook fires on the blocker's `done`, this |
| 56 | // row exists and is visible to the SELECT inside the hook. |
| 57 | let initialStatus: TaskStatus = input.status ?? "proposed"; |
| 58 | let blocked_by_task_id: string | null = input.blocked_by_task_id ?? null; |
| 59 | if (blocked_by_task_id) { |
| 60 | const blocker = getTask(blocked_by_task_id); |
| 61 | if (blocker && !isTerminal(blocker.status)) { |
| 62 | initialStatus = "blocked"; |
| 63 | } else { |
| 64 | // Blocker already done / failed / cancelled — no point gating. |
| 65 | // Drop the pointer so the dependent isn't permanently stuck. |
| 66 | blocked_by_task_id = null; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | const task: Task = { |
| 71 | id: randomUUID(), |
| 72 | display_id: nextDisplayId(input.project_slug), |
| 73 | project_slug: input.project_slug, |
| 74 | agent_id: input.agent_id, |
| 75 | title: input.title ?? null, |
| 76 | brief: input.brief, |
| 77 | success_criteria: input.success_criteria ?? null, |
| 78 | deadline_iso: input.deadline_iso ?? null, |
| 79 | status: initialStatus, |
| 80 | result_json: null, |
| 81 | error_message: null, |
| 82 | thread_id: null, |
| 83 | assigner_agent_id: input.assigner_agent_id ?? null, |
| 84 | blocked_by_task_id, |
| 85 | created_at: now, |
| 86 | updated_at: now, |
| 87 | }; |
| 88 | db.prepare( |
| 89 | `INSERT INTO tasks |
| 90 | (id, display_id, project_slug, agent_id, title, brief, success_criteria, deadline_iso, |
| 91 | status, result_json, error_message, thread_id, assigner_agent_id, blocked_by_task_id, created_at, updated_at) |
| 92 | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, NULL, ?, ?, ?, ?)`, |
| 93 | ).run( |
| 94 | task.id, |
| 95 | task.display_id, |
| 96 | task.project_slug, |
| 97 | task.agent_id, |
| 98 | task.title, |
| 99 | task.brief, |
| 100 | task.success_criteria, |
| 101 | task.deadline_iso, |
| 102 | task.status, |
| 103 | task.assigner_agent_id, |
| 104 | task.blocked_by_task_id, |
| 105 | task.created_at, |
no test coverage detected