seedproject-web/api/cli/tasks-next.php
Carlos Arias 7fc99415b4 web designer: task queue engine + CLI-native design skills
- .claude/skills/: brand skill (from BRAND.md) + ui-ux symlink, so the CLI
  loads design skills natively
- cja_tasks queue (migration 011) + admintasks controller (create/list/get/cancel)
- api/cli/tasks-next.php (atomic claim) + tasks-finish.php
- runner: buildDesignPrompt, runDesignTask (clean-tree guard, build-gate,
  auto-publish commit or revert), drainTasks loop, POST /devconsole/tasks/run
2026-07-24 00:16:39 +00:00

53 lines
1.7 KiB
PHP

<?php
/**
* Atomically claim the oldest queued Web Designer task and print it as JSON.
* Prints an empty JSON object ({}) when the queue is empty. Used by the console
* runner's drain loop (agents/console/server.mjs) — the runner has no DB driver,
* so it shells out to this.
*
* php api/cli/tasks-next.php
*
* The claim is a single conditional UPDATE (status queued -> running) guarded by
* task_id, so two concurrent callers can never claim the same row.
*/
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../config.php';
$pdo = new PDO(
sprintf('mysql:host=%s;dbname=%s;charset=utf8mb4', DB_HOST, DB_NAME),
DB_USER,
DB_PASS,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]
);
// Find + claim in a loop: SELECT the next candidate, then a guarded UPDATE.
// If the UPDATE affects 0 rows (someone else took it), try the next candidate.
for ($attempt = 0; $attempt < 20; $attempt++) {
$row = $pdo->query(
"SELECT task_id FROM cja_tasks WHERE status = 'queued'
ORDER BY sort_order ASC, task_id ASC LIMIT 1"
)->fetch();
if (!$row) {
echo "{}";
exit;
}
$id = (int) $row['task_id'];
$upd = $pdo->prepare(
"UPDATE cja_tasks SET status = 'running', started_at = NOW()
WHERE task_id = ? AND status = 'queued'"
);
$upd->execute([$id]);
if ($upd->rowCount() === 1) {
$task = $pdo->prepare('SELECT task_id, title, target_page, prompt, draft, assets FROM cja_tasks WHERE task_id = ?');
$task->execute([$id]);
echo json_encode($task->fetch(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
exit;
}
// lost the race — loop and grab the next one
}
echo "{}";