( state: SessionState, details?: RequiresActionDetails, )
| 90 | } |
| 91 | |
| 92 | export function notifySessionStateChanged( |
| 93 | state: SessionState, |
| 94 | details?: RequiresActionDetails, |
| 95 | ): void { |
| 96 | currentState = state |
| 97 | stateListener?.(state, details) |
| 98 | |
| 99 | // Mirror details into external_metadata so GetSession carries the |
| 100 | // pending-action context without proto changes. Cleared via RFC 7396 |
| 101 | // null on the next non-blocked transition. |
| 102 | if (state === 'requires_action' && details) { |
| 103 | hasPendingAction = true |
| 104 | metadataListener?.({ |
| 105 | pending_action: details, |
| 106 | }) |
| 107 | } else if (hasPendingAction) { |
| 108 | hasPendingAction = false |
| 109 | metadataListener?.({ pending_action: null }) |
| 110 | } |
| 111 | |
| 112 | // task_summary is written mid-turn by the forked summarizer; clear it at |
| 113 | // idle so the next turn doesn't briefly show the previous turn's progress. |
| 114 | if (state === 'idle') { |
| 115 | metadataListener?.({ task_summary: null }) |
| 116 | } |
| 117 | |
| 118 | // Mirror to the SDK event stream so non-CCR consumers (scmuxd, VS Code) |
| 119 | // see the same authoritative idle/running signal the CCR bridge does. |
| 120 | // 'idle' fires after heldBackResult flushes — lets scmuxd flip IDLE and |
| 121 | // show the bg-task dot instead of a stuck generating spinner. |
| 122 | // |
| 123 | // Opt-in until CCR web + mobile clients learn to ignore this subtype in |
| 124 | // their isWorking() last-message heuristics — the trailing idle event |
| 125 | // currently pins them at "Running...". |
| 126 | // https://anthropic.slack.com/archives/C093BJBD1CP/p1774152406752229 |
| 127 | if (isEnvTruthy(process.env.CLAUDE_CODE_EMIT_SESSION_STATE_EVENTS)) { |
| 128 | enqueueSdkEvent({ |
| 129 | type: 'system', |
| 130 | subtype: 'session_state_changed', |
| 131 | state, |
| 132 | }) |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | export function notifySessionMetadataChanged( |
| 137 | metadata: SessionExternalMetadata, |
no test coverage detected