mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 16:39:42 +02:00
feat(session): say when a session is watching its own background work
An agent that arms a monitor, backgrounds a shell or hands a task to a cloud session is told to end its turn. The pane then falls quiet, Claude Code's idle_prompt notification arrives a minute later, and every surface files the session under NEEDS YOU with nothing for a human to answer. Claude states what it is still running on the last row of its screen (`⏵⏵ bypass permissions on · 1 monitor · ← for agents`). That row is now `capabilities.workDetect.watchingLine` in the CLI registry, guarded by compileVersionRegex() like every other config regex, and the idle probe reads it off the capture it already takes: `watchingLabel()` in session-activity.ts searches the last five lines only, so a session that PRINTS "1 monitor" is not mistaken for one running it. The label lands on Session.watching and rides toLightDetailedState() out to every surface. The phone overview, the desktop home rail and the rich sidebar rows wear it as a `watching` badge in the accent colour, beside the state pill and never in place of it: an agent can arm a monitor and ask a question in the same breath, and only the pill says which. Verified end to end against a throwaway session on an isolated beta instance: the payload carried `watching: "1 monitor"` once the turn ended, the badge rendered next to a yellow `waiting` pill, and both cleared when the monitor died. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9466acfc1a
commit
3f2cde2db7
@@ -61,6 +61,14 @@ const MOBILE_OVERVIEW_RUN_MODES = [
|
||||
];
|
||||
|
||||
/** Pill copy per state. Kept short: a phone row has ~90px for it. */
|
||||
/**
|
||||
* The one word every surface puts on the watching badge, and the tooltip that says
|
||||
* what the pane actually reported. Both live here so the phone overview, the desktop
|
||||
* home rail and the rich sidebar rows cannot word the same badge three ways.
|
||||
*/
|
||||
const WATCHING_BADGE_TEXT = 'watching';
|
||||
const watchingBadgeTitle = (label) => 'Still running in the background: ' + label;
|
||||
|
||||
const MOBILE_OVERVIEW_PILL_LABEL = {
|
||||
needs: 'needs you',
|
||||
error: 'error',
|
||||
@@ -185,6 +193,10 @@ Object.assign(CodemanApp.prototype, {
|
||||
dir: this._shortenHomePath ? this._shortenHomePath(session.workingDir) : session.workingDir || '',
|
||||
state,
|
||||
pill: MOBILE_OVERVIEW_PILL_LABEL[state] || state,
|
||||
// What the pane's own footer says is still running in the background ("1 monitor",
|
||||
// "2 shells"), straight off the session payload. A row that has one is quiet
|
||||
// because the agent is waiting for that, not because it is waiting for you.
|
||||
watching: typeof session.watching === 'string' ? session.watching : '',
|
||||
// Epoch ms, straight off the session payload; formatting happens at
|
||||
// render time so the clock can redo it without a re-render.
|
||||
createdAt: Number(session.createdAt) || 0,
|
||||
@@ -713,6 +725,8 @@ Object.assign(CodemanApp.prototype, {
|
||||
pill.textContent = row.pill;
|
||||
item.appendChild(pill);
|
||||
|
||||
if (row.watching) item.appendChild(this._buildWatchingBadge(row.watching, 'mobile-overview-pill'));
|
||||
|
||||
const chevron = document.createElement('span');
|
||||
chevron.className = 'mobile-overview-chevron';
|
||||
chevron.setAttribute('aria-hidden', 'true');
|
||||
@@ -734,6 +748,35 @@ Object.assign(CodemanApp.prototype, {
|
||||
return item;
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Watching badge
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* The badge a session wears while work it started in the background is still
|
||||
* running: a monitor, a backgrounded shell, a cloud session.
|
||||
*
|
||||
* It says one word, and the label the pane itself printed ("1 monitor") rides in
|
||||
* the tooltip, because the badge shares a row with the state pill on the narrowest
|
||||
* screen this app renders on. It does NOT replace that pill: an agent can arm a
|
||||
* monitor and ask the user a question in the same breath, so the row still says
|
||||
* "needs you" and this says what else is going on.
|
||||
*
|
||||
* Shared with the desktop home rail (home-sessions.js), for the same reason
|
||||
* `_mobileOverviewState` is: one badge, one wording, one place to change it. The
|
||||
* caller names its own pill class, because each surface styles its pills itself and
|
||||
* the phone's live inside a media query the desktop never enters.
|
||||
*/
|
||||
_buildWatchingBadge(label, baseClass) {
|
||||
const badge = document.createElement('span');
|
||||
const base = baseClass || 'mobile-overview-pill';
|
||||
badge.className = base + ' ' + base + '--watching';
|
||||
badge.setAttribute('data-i18n-skip', '');
|
||||
badge.textContent = WATCHING_BADGE_TEXT;
|
||||
badge.title = watchingBadgeTitle(label);
|
||||
return badge;
|
||||
},
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// Age stamps: started / how long in this state
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user