diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-03-16 04:24:15 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-03-16 04:24:15 +0000 |
| commit | 16ff7ca46bfb4af44af488fa95bd3f8e981f4db2 (patch) | |
| tree | 7ae14d4943bfccaad94c70dd409efd06add39992 | |
| parent | 0e37086ee468e6e3b697c32b7f02280ee06f5116 (diff) | |
feat: improve next-task selection and rejection UX
- next-task script: exclude rejected tasks from fallback selection; only
pick PENDING tasks with no rejection comment and no prior executions,
or QUEUED tasks (e.g. BUDGET_EXCEEDED retries)
- web/app.js: prompt for optional rejection comment when rejecting a task,
passing it through to the API instead of always sending an empty string
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| -rwxr-xr-x | scripts/next-task | 4 | ||||
| -rw-r--r-- | web/app.js | 9 |
2 files changed, 9 insertions, 4 deletions
diff --git a/scripts/next-task b/scripts/next-task index 9df09f0..c36fc23 100755 --- a/scripts/next-task +++ b/scripts/next-task @@ -32,7 +32,9 @@ fi if [ -z "$next_task" ]; then # 4. No child/sibling found: fall back to highest-priority oldest PENDING task - FALLBACK_SQL="SELECT id FROM tasks WHERE state IN ('PENDING', 'QUEUED') AND id != '$id' + # Exclude tasks that have a rejection comment or have already been executed + # to avoid auto-approving rejected tasks. + FALLBACK_SQL="SELECT id FROM tasks WHERE (state = 'PENDING' AND (rejection_comment IS NULL OR rejection_comment = '') AND id NOT IN (SELECT task_id FROM executions)) OR state = 'QUEUED' ORDER BY CASE priority WHEN 'critical' THEN 4 @@ -996,11 +996,11 @@ async function acceptTask(taskId) { return res.json(); } -async function rejectTask(taskId) { +async function rejectTask(taskId, comment) { const res = await fetch(`${API_BASE}/api/tasks/${taskId}/reject`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ comment: '' }), + body: JSON.stringify({ comment: comment || '' }), }); if (!res.ok) { let msg = `HTTP ${res.status}`; @@ -1030,13 +1030,16 @@ async function handleAccept(taskId, btn, footer) { } async function handleReject(taskId, btn, footer) { + const comment = prompt('Reason for rejection (optional):', ''); + if (comment === null) return; // User cancelled prompt + btn.disabled = true; btn.textContent = 'Rejecting…'; const prev = footer.querySelector('.task-error'); if (prev) prev.remove(); try { - await rejectTask(taskId); + await rejectTask(taskId, comment); await poll(); } catch (err) { btn.disabled = false; |
