Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions mcp-task-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,13 @@ const TOOLS = [
},
{
name: 'report_result',
description: 'Store a structured result for this task. Other tasks that depend on you can read this via get_task_result. Use this to pass data to downstream tasks — issue lists, PR URLs, analysis results, etc.',
description: 'Store a structured result for this task. Other tasks that depend on you can read this via get_task_result. Use this to pass data to downstream tasks — issue lists, PR URLs, analysis results, etc. Also the ONLY correct way to escalate: if you genuinely cannot complete the task (a required resource is unavailable, you need a human decision, access is missing), pass blocked:true + reason instead of ending the turn silently or claiming success. A blocked task stays visible on the board, separate from both done and failed work, until a human resolves it.',
inputSchema: {
type: 'object',
properties: {
data: { description: 'Structured result data (string or JSON object). This is what dependent tasks will receive.' },
data: { description: 'Structured result data (string or JSON object). This is what dependent tasks will receive. Still required even when blocked:true — summarize what you tried.' },
blocked: { type: 'boolean', description: 'Set true when you cannot complete this task right now and it needs a human to unblock it. Do not use this for an ordinary error you can retry past — only for a real external blocker.' },
reason: { type: 'string', description: 'Required with blocked:true — one or two sentences: what is blocking you, and what a human needs to do about it.' },
},
required: ['data'],
},
Expand Down Expand Up @@ -249,7 +251,9 @@ async function handleMessage(msg) {
text = JSON.stringify(result, null, 2);
break;
case 'report_result':
text = 'Result stored successfully. Dependent tasks will be able to read it.';
text = result.blocked
? 'Result stored, task marked BLOCKED — a human will follow up. Finish your turn now; nothing further will run in this task.'
: 'Result stored successfully. Dependent tasks will be able to read it.';
break;
case 'get_task_result':
text = JSON.stringify(result, null, 2);
Expand Down
54 changes: 54 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"scripts": {
"start": "node server.js",
"dev": "node --watch server.js",
"test": "node --test test/render/*.test.mjs && node test/overload-detector.test.js && node test/usage-limit.test.js && node test/auth-errors.test.js && node test/env-load-order.test.js && node test/multi-agent-result.test.js && node test/terminal-session.test.js && node test/terminal-schema.test.js && node test/bots.test.js && node test/bot-inbox.test.js && node test/bots-api.test.js && node test/running-sessions.test.js && node test/session-liveness.test.js && node test/terminal-bridge.integration.test.js && node test/tmux-composite.test.js && node test/engine-spawn-cmd.test.js && node test/telegram-format.test.js && node test/telegram-behaviour.test.js && node test/ask-user-question.test.js && node test/delegate-terminal.test.js && node test/update-flow.test.js && node test/kanban-schedule.test.js && node test/kanban-run-badges.test.js && node test/task-backlog.test.js && node test/i18n-completeness.test.js && node test/config-resolve.test.js && node test/chat-defaults.test.js && node test/chat-defaults-api.test.js && node test/run-continuation.test.js && node test/cli-tool-names.test.js && node test/mcp-web.test.js && node test/gateway-models.test.js && node test/plan-lib.test.js && node test/plan-import.test.js && node test/plans-api.test.js && node test/room-files.test.js && node test/room-git.test.js && node test/room-run.test.js && node test/worktree-manager.test.js && node test/setup-gate.test.js && node test/path-guard.test.js && node test/subscribe-nocatchup.test.js && node test/cli-import-remote.test.js && node test/remote-list-parse.test.js && node test/config-migrate.test.js && node test/engine-pane.test.js && node test/global-workspace.test.js && node test/ssh-secret.test.js && node test/agent-dag.test.js && node test/ssh-parser.test.js && node test/ssh-termination.test.js && node test/session-restart.test.js && node test/remote-env.test.js && node test/remote-files.test.js && node test/remote-files-api.test.js && node test/auth-token.test.js && node test/cmd-model.test.js && node test/origin-guard.test.js && node test/interrupted-recovery.test.js && node test/queue-persistence.test.js && node test/interrupt-idle-config.test.js && node test/agents-md.test.js && node test/editor-links.test.js && node test/editor-open-api.test.js && node test/interrupt-delivery.test.js && node test/terminal-pane-guard.integration.test.js && node test/composer-terminal.test.js && node test/claude-cli-status.test.js && node test/asar-helpers.test.js && node test/task-workers.test.js && node test/git-clone.test.js",
"test": "node --test test/render/*.test.mjs && node test/overload-detector.test.js && node test/usage-limit.test.js && node test/auth-errors.test.js && node test/env-load-order.test.js && node test/multi-agent-result.test.js && node test/terminal-session.test.js && node test/terminal-schema.test.js && node test/bots.test.js && node test/bot-inbox.test.js && node test/bots-api.test.js && node test/running-sessions.test.js && node test/session-liveness.test.js && node test/terminal-bridge.integration.test.js && node test/tmux-composite.test.js && node test/engine-spawn-cmd.test.js && node test/telegram-format.test.js && node test/telegram-behaviour.test.js && node test/ask-user-question.test.js && node test/delegate-terminal.test.js && node test/update-flow.test.js && node test/kanban-schedule.test.js && node test/kanban-run-badges.test.js && node test/task-backlog.test.js && node test/i18n-completeness.test.js && node test/config-resolve.test.js && node test/chat-defaults.test.js && node test/chat-defaults-api.test.js && node test/run-continuation.test.js && node test/cli-tool-names.test.js && node test/mcp-web.test.js && node test/gateway-models.test.js && node test/plan-lib.test.js && node test/plan-import.test.js && node test/plans-api.test.js && node test/room-files.test.js && node test/room-git.test.js && node test/room-run.test.js && node test/worktree-manager.test.js && node test/setup-gate.test.js && node test/path-guard.test.js && node test/subscribe-nocatchup.test.js && node test/cli-import-remote.test.js && node test/remote-list-parse.test.js && node test/config-migrate.test.js && node test/engine-pane.test.js && node test/global-workspace.test.js && node test/ssh-secret.test.js && node test/agent-dag.test.js && node test/ssh-parser.test.js && node test/ssh-termination.test.js && node test/session-restart.test.js && node test/remote-env.test.js && node test/remote-files.test.js && node test/remote-files-api.test.js && node test/auth-token.test.js && node test/cmd-model.test.js && node test/origin-guard.test.js && node test/interrupted-recovery.test.js && node test/queue-persistence.test.js && node test/interrupt-idle-config.test.js && node test/agents-md.test.js && node test/editor-links.test.js && node test/editor-open-api.test.js && node test/interrupt-delivery.test.js && node test/terminal-pane-guard.integration.test.js && node test/composer-terminal.test.js && node test/claude-cli-status.test.js && node test/asar-helpers.test.js && node test/task-workers.test.js && node test/git-clone.test.js && node test/task-blocked-and-empty-response.test.js",
"postinstall": "node scripts/install-hooks.js",
"release": "node scripts/release.js",
"electron:dev": "electron .",
Expand All @@ -35,6 +35,7 @@
},
"dependencies": {
"bcryptjs": "^2.4.3",
"compression": "^1.8.2",
"cookie-parser": "^1.4.6",
"electron-updater": "^6.8.9",
"express": "^4.21.0",
Expand Down
26 changes: 13 additions & 13 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13129,6 +13129,19 @@ <h2 id="dlgModalTitle" data-i18n="dlg.title">Delegate to Agent</h2>
} catch {
w.querySelector('.msg').innerHTML = renderMd(m.content);
}
} else if (m.role === 'assistant' && m.type === 'plan_review') {
// Same shape as the agent_plan branch above: the card REPLACES the raw-JSON message body, it
// does not sit next to it — an earlier version inserted the card in front of the bubble and
// left the raw JSON visible right under it ("что за странное сообщение под карточкой",
// reported live). review.imported (set once the card's own outcome is known) renders the
// done state on reload, same as a live plan_import_result would show.
try {
const review = JSON.parse(m.content);
_planReviews[String(m.id)] = review;
w.querySelector('.msg').innerHTML = planReviewCardHtml(review, String(m.id), review.imported || null);
} catch {
w.querySelector('.msg').innerHTML = renderMd(m.content);
}
} else if (m.role === 'assistant') {
w.querySelector('.msg').innerHTML = renderMd(m.content);
} else {
Expand Down Expand Up @@ -13159,19 +13172,6 @@ <h2 id="dlgModalTitle" data-i18n="dlg.title">Delegate to Agent</h2>
}
// Add "Done" footer for completed assistant messages in history
// Show on the last assistant msg before a user msg or end of conversation
if (m.role === 'assistant' && m.type === 'plan_review') {
try {
const review = JSON.parse(m.content);
// Set BEFORE rendering: planReviewCardHtml reads _planReviews[messageId] nowhere itself, but
// _prTogglePlanTask/_prApprove do once the user clicks something on this restored card, and
// without this they silently no-op (the bug this fixes: checkboxes drawn checked, the "N
// selected" count and the button both stuck at 0, because nothing had computed the default yet).
_planReviews[String(m.id)] = review;
const wrap = document.createElement('div');
wrap.innerHTML = planReviewCardHtml(review, String(m.id), review.imported || null);
w.querySelector('.msg').before(wrap.firstElementChild);
} catch {}
}
if (m.role === 'assistant' && m.type !== 'agent_plan' && m.type !== 'plan_review') {
const next = _allMsgs[idx + 1];
if (!next || next.role === 'user') {
Expand Down
Loading
Loading