Files
orca/src/shared/claude-task-notification-text.ts
T
Kelvin AmoabaandNeil 634c43787c Fix premature Claude automation completion and inherited CI failures (#24878)
* fix(agent-status): keep a Claude pane working until owed task wake-ups arrive

Claude wakes the main agent for each background task that ends, after the
task stops running. "Nothing running" was read as done, so automations
closed the terminal before the final turn.

Fixes #23942

* fix(agent-status): keep owed task wake-ups through failed turns, the cap and nested exits

A failed turn's task list now marks a vanished shell owed like a normal turn end does. Past
the cap only an already-announced sub-agent is forgotten. A process exit clears what is owed
only where the server admits it from the pane's owner.

* refactor(agent-status): move pane-scoped cache entry helpers out of listener-state

listener-state.ts passed the 300-line limit once main's and this branch's additions met.

* fix(agent-status): verify Claude task wake-up completion on its execution host

* fix(agent-status): canonicalize Claude background task identifiers

* Preserve out-of-order Claude task notification evidence

* Verify retained released parser in cross-version checkout test

* Reuse watcher directory-cache enumeration without losing fresh keys

---------

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
2026-10-06 01:02:18 -07:00

23 lines
1.0 KiB
TypeScript

/** Claude tells a parent agent about a background task with a user turn that starts with this tag. */
export const CLAUDE_TASK_NOTIFICATION_MARKER = '<task-notification>'
const TASK_ID_PATTERN = /<task-id>([^<]+)<\/task-id>/
const TASK_STATUS_PATTERN = /<status>([a-z_]+)<\/status>/
/** `status` is present only once the task has ended: a Monitor's `<event>` turns reuse the tag and
* the task id while the task is still running (captured on Claude Code 2.1.287). Claude writes it
* before `<summary>`; anything after is task output, which may itself contain a status tag. */
export function readClaudeTaskNotification(
text: string
): { taskId: string; status?: string } | null {
if (!text.startsWith(CLAUDE_TASK_NOTIFICATION_MARKER)) {
return null
}
const taskId = TASK_ID_PATTERN.exec(text)?.[1]?.trim()
if (!taskId) {
return null
}
const summaryAt = text.indexOf('<summary>')
const status = TASK_STATUS_PATTERN.exec(summaryAt === -1 ? text : text.slice(0, summaryAt))?.[1]
return { taskId, ...(status ? { status } : {}) }
}