summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/next-task4
-rw-r--r--web/app.js9
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
diff --git a/web/app.js b/web/app.js
index 0e13543..e1782dd 100644
--- a/web/app.js
+++ b/web/app.js
@@ -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;