mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 16:39:42 +02:00
fix(session): keep a tab working while Claude waits for its own workers
When Claude hands work to an ultracode workflow or background agents, it ends its own turn and closes it with `✻ Waiting for 1 dynamic workflow to finish` instead of `✻ Brewed for 1m 18s`, then resumes by itself when the workers report back. The pane sits quiet with the composer up, so the idle probe called the session idle for the whole wait. At phone width the workflow's progress row also drops its ticking timer, so nothing on screen changes for minutes. A new optional registry field, `capabilities.workDetect.awaitingLine`, names that closing row, and `_probePaneWorking()` counts it as work. Claude renders the row once from a snapshot and never redraws it, so the same words stay on screen after the workers finish. `isAwaitingWorkers()` therefore tests only the newest column-0 row directly above the composer, never the whole pane and never the PTY stream; a follow-up turn always puts rows of its own there. The column-0 anchor also keeps an agent from holding its own tab busy by printing the sentence. Verified against the live Mac mini pane that reported the bug (2.1.283), and end to end on an isolated instance: an ultracode session running a 90 s workflow at 46 columns stayed busy through the wait and the follow-up turn, then went idle 6 s after that turn closed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -338,6 +338,15 @@ const capabilitiesSchema = z
|
||||
// Bounded hard: this is how far up the screen a config file may push the search,
|
||||
// and every row it adds is one more row the agent itself may be able to write.
|
||||
watchingLines: z.number().int().min(1).max(8).optional(),
|
||||
// Same guard again: tested against a pane row every time a session settles.
|
||||
awaitingLine: z
|
||||
.string()
|
||||
.min(1)
|
||||
.refine(
|
||||
(src) => compileVersionRegex(src) !== null,
|
||||
'awaitingLine must be a regex compileVersionRegex() accepts: at most 200 characters, no nested quantifiers'
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
.strict()
|
||||
// A window with nothing to search is a typo, not a configuration. Refused at LOAD
|
||||
|
||||
@@ -238,6 +238,14 @@ const CLAUDE: CliEntry = {
|
||||
// watching rather than open that door. See `watchingLabel()` in
|
||||
// `session-activity.ts`.
|
||||
watchingLine: String.raw`·\s*(\d+ (?:monitors?|shells?|teams?|local agents?|cloud sessions?|MCP tasks?|background tasks?|(?:background|remote) dynamic workflows?|Artifact comment monitors?))`,
|
||||
// When a turn ends while background agents or an ultracode workflow are still
|
||||
// running, Claude swaps its `✻ Brewed for 1m 18s` closing row for
|
||||
// `✻ Waiting for 2 background agents and 1 dynamic workflow to finish` and resumes
|
||||
// by itself when they report back. Read from the 2.1.283 bundle (the turn-duration
|
||||
// renderer) and a live pane on 2026-09-28. The row is a snapshot taken at turn end
|
||||
// and never redrawn, which is why only the newest row above the composer counts.
|
||||
// Anchored on column 0: Claude's own rows start there, the agent's prose never does.
|
||||
awaitingLine: String.raw`^✻ Waiting for \d+ (?:background agents?|dynamic workflows?)\b`,
|
||||
},
|
||||
requiresMux: false,
|
||||
// Claude installs Codeman's own hooks block into every workspace it runs in, so its
|
||||
|
||||
@@ -362,6 +362,19 @@ export interface CliCapabilities {
|
||||
* alert. See `watchingLabel()` in `session-activity.ts`.
|
||||
*/
|
||||
watchingLines?: number;
|
||||
/**
|
||||
* Source of a regex matching the row this CLI closes a turn with when it ended that
|
||||
* turn to WAIT for workers it started and will resume on its own once they finish,
|
||||
* e.g. Claude's `✻ Waiting for 1 dynamic workflow to finish`. A pane showing it counts
|
||||
* as working, not idle: nothing is being asked of the user, and the next turn starts
|
||||
* without them.
|
||||
*
|
||||
* Unlike `workingLine` this is never searched across the pane. The CLI prints the row
|
||||
* once and never updates it, so the copy from an earlier turn is still on screen after
|
||||
* the workers are done. Only the newest transcript row directly above the composer is
|
||||
* tested. See `isAwaitingWorkers()` in `session-activity.ts`.
|
||||
*/
|
||||
awaitingLine?: string;
|
||||
};
|
||||
/**
|
||||
* How many columns this CLI indents its transcript body by, so a copy taken from its
|
||||
|
||||
Reference in New Issue
Block a user