summaryrefslogtreecommitdiff
path: root/web/app.js
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-03-14 00:33:46 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-03-14 00:33:46 +0000
commit6ac15be438e3692cbc2ae2f36ab2d69468fc6372 (patch)
treef0fded632c7ade09ed4232a4ac0dd90bce795a31 /web/app.js
parente2656fcaaed85028785822493a93c7be50dd44c2 (diff)
fix: cancel blocked tasks + auto-complete completion reports
Two fixes for BLOCKED task issues: 1. Allow BLOCKED → CANCELLED state transition so users can cancel tasks stuck waiting for input. Adds Cancel button to BLOCKED task cards in the UI alongside the question/answer controls. 2. Detect when agents write completion reports to $CLAUDOMATOR_QUESTION_FILE instead of real questions. If the question JSON has no options and no "?" in the text, treat it as a summary (stored on the execution) and fall through to normal completion + sandbox teardown rather than blocking. Also tightened the preamble to make the distinction explicit. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'web/app.js')
-rw-r--r--web/app.js19
1 files changed, 16 insertions, 3 deletions
diff --git a/web/app.js b/web/app.js
index afb6a75..ad60f34 100644
--- a/web/app.js
+++ b/web/app.js
@@ -164,6 +164,14 @@ function createTaskCard(task) {
footer.appendChild(rejectBtn);
} else if (task.state === 'BLOCKED') {
renderQuestionFooter(task, footer);
+ const cancelBtn = document.createElement('button');
+ cancelBtn.className = 'btn-cancel';
+ cancelBtn.textContent = 'Cancel';
+ cancelBtn.addEventListener('click', (e) => {
+ e.stopPropagation();
+ handleCancel(task.id, cancelBtn, footer);
+ });
+ footer.appendChild(cancelBtn);
} else if (RESUME_STATES.has(task.state)) {
const resumeBtn = document.createElement('button');
resumeBtn.className = 'btn-resume';
@@ -869,8 +877,11 @@ async function handleReject(taskId, btn, footer) {
// ── Start-next-task ─────────────────────────────────────────────────────────────
-async function startNextTask() {
- const res = await fetch(`${API_BASE}/api/scripts/start-next-task`, { method: 'POST' });
+async function startNextTask(agent) {
+ const url = agent && agent !== 'auto'
+ ? `${API_BASE}/api/scripts/start-next-task?agent=${agent}`
+ : `${API_BASE}/api/scripts/start-next-task`;
+ const res = await fetch(url, { method: 'POST' });
if (!res.ok) {
let msg = `HTTP ${res.status}`;
try { const body = await res.json(); msg = body.error || msg; } catch {}
@@ -880,10 +891,12 @@ async function startNextTask() {
}
async function handleStartNextTask(btn) {
+ const agentSelector = document.getElementById('select-agent');
+ const agent = agentSelector ? agentSelector.value : 'auto';
btn.disabled = true;
btn.textContent = 'Starting…';
try {
- const result = await startNextTask();
+ const result = await startNextTask(agent);
const output = (result.output || '').trim();
btn.textContent = output || 'No task to start';
setTimeout(() => { btn.textContent = 'Start Next'; btn.disabled = false; }, 3000);