mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 02:49:33 +01:00
Claude Code lets a subscription's one-hour prompt cache expire after an hour idle, and the first turn back re-writes the whole conversation at the cache-write rate; nearly every gap over an hour goes cold, while the saving is concentrated in gaps of one to four hours. Codeman now sends one short keep-alive turn five minutes before the expiry Claude Code reports on its statusline, so the next real prompt still reads the conversation from cache, and stops two hours (configurable) after the last real prompt. Codeman owns the idle policy for these sessions, as agreed in Discussion #554: a launch with keep-warm on also carries idleCompaction: false in its one --settings JSON, so Claude Code's own idle compaction cannot replace the conversation with a summary a minute before the nudge. It is decided once per launch (keep-warm on, the statusLine exporter injected, Claude Code 2.1.290 or newer, an unknown version fails closed like --name), recorded on the mux record, and picked up by any relaunch; a launch with keep-warm off is byte-identical. A session switched on after launch is kept warm best-effort and the readout says so. Every guard lives in one pure rulebook: the opt-in (an agent-spawned session does not inherit the app default), a launch that reports cache state, a warm 1h cache with enough tokens at stake and no compaction this gap, a live pane, no usage-limit pause, no respawn, Ralph, task or waiting agent, idle, no open dialog, an empty composer and no recent keystroke. The nudge is a submit and moves lastSubmitAt, which the response viewer's conversation correlation needs; the cap counts from its own persisted lastRealPromptAt instead. Read My Mind drops the exact nudge text, and the turn's stop hook and idle prompt open pre-acknowledged so nothing alerts. The last cache report and the clock survive a restart, so the timer re-arms.
726 lines
34 KiB
TypeScript
726 lines
34 KiB
TypeScript
/**
|
|
* @fileoverview Centralized SSE event type registry — single source of truth.
|
|
*
|
|
* All Server-Sent Event type strings used by the backend (`broadcast()` calls)
|
|
* and referenced by the frontend (`SSE_EVENTS` in `constants.js`).
|
|
* Both files MUST be kept in sync.
|
|
*
|
|
* 163 event constants organized by category:
|
|
* - **Core** (1): init
|
|
* - **Transport** (1): sse:heartbeat
|
|
* - **Session lifecycle** (25): created, updated, deleted, terminal, idle, working, ...
|
|
* - **Session: Ralph** (6): ralphLoopUpdate, todoUpdate, completionDetected, ...
|
|
* - **Session: Bash tools** (3): bashToolStart, bashToolEnd, bashToolsUpdate
|
|
* - **Session: Plan** (4): planTaskUpdate, planCheckpoint, planRollback, planTaskAdded
|
|
* - **Tasks** (4): created, completed, failed, updated
|
|
* - **Mux** (4): created, killed, died, statsUpdated
|
|
* - **Remote auto-reconnect / wake** (5): sessionDropped, sessionReconnected, reconnectExhausted, hostWaking, hostWakeFailed
|
|
* - **Respawn** (24): stateChanged, cycleStarted/Completed, step*, aiCheck*, planCheck*, timer*, log, ...
|
|
* - **Subagents** (7): discovered, updated, tool_call, tool_result, progress, message, completed
|
|
* - **Workflow runs** (3): run_discovered, run_updated, run_removed (ultracode / Workflow tool)
|
|
* - **Scheduled** (6): created, updated, completed, stopped, log, deleted
|
|
* - **Cron jobs** (4): jobsChanged, jobDeleted, runCreated, runUpdated
|
|
* - **Teams** (4): created, updated, removed, taskUpdated
|
|
* - **Transcript** (4): complete, plan_mode, tool_start, tool_end
|
|
* - **Plan orchestration** (5): started, progress, subagent, completed, cancelled
|
|
* - **Tunnel** (7): started, stopped, progress, error, qrRotated, qrRegenerated, qrAuthUsed
|
|
* - **Image / attachments** (2): image:detected, attachment:detected
|
|
* - **Hooks** (10): idle_prompt, permission_prompt, elicitation_dialog, elicitation_complete, elicitation_response, stop, agent_working, teammate_idle, task_completed, prompt_submitted
|
|
* (agent_working is the odd one out: reported by the DeepSeek Harness status bridge, not by a Claude Code hook;
|
|
* permission_prompt also arrives with `source: 'screen'` for a codex dialog read off its screen)
|
|
* - **Approvals** (3): pending, updated, resolved (cross-session Approvals Inbox)
|
|
* - **Custom Model Endpoint Profiles** (1): swapped-out (a session's model got evicted by another session on the same llama-swap endpoint)
|
|
* - **Orchestrator** (12): stateChanged, planProgress, planReady, phase*, verification, task*, completed, error
|
|
* - **Clipboard** (1): write
|
|
* - **Cases** (4): created, linked, deleted, order-changed
|
|
* - **Docker cases** (8): exportComplete/Failed, importComplete, imageBuild*, containerRecreated
|
|
* - **Multi-user** (3): admin:usersChanged, auth:passwordChangeRequired, session:orderChanged
|
|
* - **Web tabs** (2): webview:changed, tab:layoutChanged
|
|
*
|
|
* Naming convention: `domain:action` (e.g., `session:created`, `respawn:stateChanged`)
|
|
*
|
|
* Key export: `SseEvent` namespace object — import for destructured access.
|
|
*
|
|
* Usage:
|
|
* import { SseEvent } from './sse-events.js';
|
|
* ctx.broadcast(SseEvent.SessionCreated, { id: session.id });
|
|
*
|
|
* When adding a new event:
|
|
* 1. Add the constant here with JSDoc
|
|
* 2. Add the matching entry in `src/web/public/constants.js` SSE_EVENTS object
|
|
* 3. Add the frontend listener in the appropriate `addListener()` call
|
|
*/
|
|
|
|
// ─── Core ────────────────────────────────────────────────────────────────────
|
|
|
|
/** Sent to each SSE client on initial connection with full app state. */
|
|
export const Init = 'init' as const;
|
|
|
|
// ─── Transport ───────────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Liveness frame written to every SSE client every `SSE_HEARTBEAT_INTERVAL`.
|
|
* Payload: `{ t: <epoch ms> }`.
|
|
*
|
|
* Carries no application data; its only job is to be *observable*. This was a
|
|
* `:keepalive` SSE **comment**, and comments are invisible to `EventSource` by
|
|
* spec, so a stream that stopped delivering without erroring (a proxy that
|
|
* idle-closed it, a laptop resumed from sleep, a tailnet reconnect) was
|
|
* undetectable to the client: `onerror` never fires and the UI freezes until a
|
|
* reload. A named event reaches a listener, which is what lets the client's
|
|
* staleness watchdog notice the silence and force a reconnect.
|
|
*/
|
|
export const Heartbeat = 'sse:heartbeat' as const;
|
|
|
|
// ─── Session Lifecycle ───────────────────────────────────────────────────────
|
|
|
|
/** New session spawned. */
|
|
export const SessionCreated = 'session:created' as const;
|
|
/** Session state changed (status, config, tokens, etc.). */
|
|
export const SessionUpdated = 'session:updated' as const;
|
|
/** Session permanently removed. */
|
|
export const SessionDeleted = 'session:deleted' as const;
|
|
/** Raw PTY terminal output chunk. */
|
|
export const SessionTerminal = 'session:terminal' as const;
|
|
/** Client should re-fetch the full terminal buffer (e.g. after reconnect). */
|
|
export const SessionNeedsRefresh = 'session:needsRefresh' as const;
|
|
/** Terminal buffer cleared (e.g. /clear command). */
|
|
export const SessionClearTerminal = 'session:clearTerminal' as const;
|
|
/** Claude finished a prompt — includes result and cost. */
|
|
export const SessionCompletion = 'session:completion' as const;
|
|
/** Session-level error. */
|
|
export const SessionError = 'session:error' as const;
|
|
/** Claude CLI process exited. */
|
|
export const SessionExit = 'session:exit' as const;
|
|
/** Session transitioned to idle (waiting for input). */
|
|
export const SessionIdle = 'session:idle' as const;
|
|
/** Session transitioned to working (Claude is processing). */
|
|
export const SessionWorking = 'session:working' as const;
|
|
/** Auto-clear triggered for the session. */
|
|
export const SessionAutoClear = 'session:autoClear' as const;
|
|
/** Auto-compact triggered for the session. */
|
|
export const SessionAutoCompact = 'session:autoCompact' as const;
|
|
/** Usage-limit pause detected; auto-resume scheduled. */
|
|
export const SessionLimitPauseScheduled = 'session:limitPauseScheduled' as const;
|
|
/** Auto-resume prompt sent after a usage-limit reset. */
|
|
export const SessionLimitResume = 'session:limitResume' as const;
|
|
/** Pending usage-limit auto-resume cancelled (session resumed or feature disabled). */
|
|
export const SessionLimitResumeCancelled = 'session:limitResumeCancelled' as const;
|
|
/** Interactive-PTY exit circuit breaker tripped (COD-118): repeated non-zero exits; respawn blocked, session errored. */
|
|
export const SessionRespawnBreakerTripped = 'session:respawnBreakerTripped' as const;
|
|
/** CLI version/model info detected from session output. */
|
|
export const SessionCliInfo = 'session:cliInfo' as const;
|
|
/** Session pin state changed (COD-139): pinned/unpinned in the session manager list. */
|
|
export const SessionPinned = 'session:pinned' as const;
|
|
/** General session message (e.g. status text). */
|
|
export const SessionMessage = 'session:message' as const;
|
|
/** Session entered interactive mode (claude or shell). */
|
|
export const SessionInteractive = 'session:interactive' as const;
|
|
/** Prompt sent to session for execution. */
|
|
export const SessionRunning = 'session:running' as const;
|
|
/** Combined Claude and main Codex plan-usage telemetry for the shared header chip. */
|
|
export const SessionStatusTelemetry = 'session:statusTelemetry' as const;
|
|
/** Prompt-cache state of one session's main conversation changed (`{ sessionId, ...PromptCacheStatus }`). */
|
|
export const SessionPromptCache = 'session:promptCache' as const;
|
|
/** The prompt-cache keep-warm's status for one session changed (`{ sessionId, ...KeepWarmStatus }`). */
|
|
export const SessionKeepWarm = 'session:keepWarm' as const;
|
|
|
|
// ─── Session: Ralph ──────────────────────────────────────────────────────────
|
|
|
|
/** Ralph loop state changed (enabled/disabled, iteration count). */
|
|
export const SessionRalphLoopUpdate = 'session:ralphLoopUpdate' as const;
|
|
/** Ralph todo items updated. */
|
|
export const SessionRalphTodoUpdate = 'session:ralphTodoUpdate' as const;
|
|
/** Ralph completion phrase detected in output. */
|
|
export const SessionRalphCompletionDetected = 'session:ralphCompletionDetected' as const;
|
|
/** Ralph status block parsed from output. */
|
|
export const SessionRalphStatusUpdate = 'session:ralphStatusUpdate' as const;
|
|
/** Circuit breaker state changed (CLOSED/HALF_OPEN/OPEN). */
|
|
export const SessionCircuitBreakerUpdate = 'session:circuitBreakerUpdate' as const;
|
|
/** Exit gate condition met (e.g. completion phrase found). */
|
|
export const SessionExitGateMet = 'session:exitGateMet' as const;
|
|
|
|
// ─── Session: Bash Tools ─────────────────────────────────────────────────────
|
|
|
|
/** Bash tool invocation started. */
|
|
export const SessionBashToolStart = 'session:bashToolStart' as const;
|
|
/** Bash tool invocation completed. */
|
|
export const SessionBashToolEnd = 'session:bashToolEnd' as const;
|
|
/** Active bash tools list changed. */
|
|
export const SessionBashToolsUpdate = 'session:bashToolsUpdate' as const;
|
|
|
|
// ─── Session: Plan ───────────────────────────────────────────────────────────
|
|
|
|
/** Plan task status updated. */
|
|
export const SessionPlanTaskUpdate = 'session:planTaskUpdate' as const;
|
|
/** Plan checkpoint created. */
|
|
export const SessionPlanCheckpoint = 'session:planCheckpoint' as const;
|
|
/** Plan rolled back to a previous version. */
|
|
export const SessionPlanRollback = 'session:planRollback' as const;
|
|
/** New task added to plan. */
|
|
export const SessionPlanTaskAdded = 'session:planTaskAdded' as const;
|
|
|
|
// ─── Tasks ───────────────────────────────────────────────────────────────────
|
|
|
|
/** Background task created. */
|
|
export const TaskCreated = 'task:created' as const;
|
|
/** Background task completed successfully. */
|
|
export const TaskCompleted = 'task:completed' as const;
|
|
/** Background task failed. */
|
|
export const TaskFailed = 'task:failed' as const;
|
|
/** Background task state updated. */
|
|
export const TaskUpdated = 'task:updated' as const;
|
|
|
|
// ─── Mux (tmux) ──────────────────────────────────────────────────────────────
|
|
|
|
/** tmux session created. */
|
|
export const MuxCreated = 'mux:created' as const;
|
|
/** tmux session killed. */
|
|
export const MuxKilled = 'mux:killed' as const;
|
|
/** tmux session died unexpectedly. */
|
|
export const MuxDied = 'mux:died' as const;
|
|
/** tmux session stats refreshed. */
|
|
export const MuxStatsUpdated = 'mux:statsUpdated' as const;
|
|
|
|
// ─── Remote auto-reconnect (COD-108) + wake-on-LAN ───────────────────────────
|
|
// Session-scoped in multi-user mode (`deriveSseHint`): routed to the session's owner,
|
|
// or — for a wake with no session yet — to the requesting `username` in the payload.
|
|
|
|
/** A remote session's local ssh pane died; an auto-reconnect attempt is starting. */
|
|
export const RemoteSessionDropped = 'remote:sessionDropped' as const;
|
|
/** A dropped remote session was successfully re-established (reattached). */
|
|
export const RemoteSessionReconnected = 'remote:sessionReconnected' as const;
|
|
/** Auto-reconnect gave up after the bounded backoff cap — manual reconnect needed. */
|
|
export const RemoteReconnectExhausted = 'remote:reconnectExhausted' as const;
|
|
/**
|
|
* User input arrived for a session whose host is unreachable, so a Wake-on-LAN
|
|
* command was started (see `remote-wake.ts`). Input sent meanwhile is buffered.
|
|
* Payload: `sessionId` (session wake) or `forNewSession: true` + `username`
|
|
* (create/attach wake), `hostId`, `label`, `queuedInput`.
|
|
*/
|
|
export const RemoteHostWaking = 'remote:hostWaking' as const;
|
|
/** The host did not come back within the wake timeout — buffered input is still held. */
|
|
export const RemoteHostWakeFailed = 'remote:hostWakeFailed' as const;
|
|
|
|
// ─── Respawn ─────────────────────────────────────────────────────────────────
|
|
|
|
/** Respawn loop started for a session. */
|
|
export const RespawnStarted = 'respawn:started' as const;
|
|
/** Respawn loop stopped. */
|
|
export const RespawnStopped = 'respawn:stopped' as const;
|
|
/** Respawn state machine transitioned. */
|
|
export const RespawnStateChanged = 'respawn:stateChanged' as const;
|
|
/** New respawn cycle started. */
|
|
export const RespawnCycleStarted = 'respawn:cycleStarted' as const;
|
|
/** Respawn cycle completed. */
|
|
export const RespawnCycleCompleted = 'respawn:cycleCompleted' as const;
|
|
/** Respawn blocked (e.g. by circuit breaker or active teammates). */
|
|
export const RespawnBlocked = 'respawn:blocked' as const;
|
|
/** Respawn step sent to session (update prompt, clear, kickstart). */
|
|
export const RespawnStepSent = 'respawn:stepSent' as const;
|
|
/** Respawn step completed. */
|
|
export const RespawnStepCompleted = 'respawn:stepCompleted' as const;
|
|
/** Idle/completion detection status updated. */
|
|
export const RespawnDetectionUpdate = 'respawn:detectionUpdate' as const;
|
|
/** Auto-accept sent for permission prompt. */
|
|
export const RespawnAutoAcceptSent = 'respawn:autoAcceptSent' as const;
|
|
/** AI idle check started. */
|
|
export const RespawnAiCheckStarted = 'respawn:aiCheckStarted' as const;
|
|
/** AI idle check completed with result. */
|
|
export const RespawnAiCheckCompleted = 'respawn:aiCheckCompleted' as const;
|
|
/** AI idle check failed. */
|
|
export const RespawnAiCheckFailed = 'respawn:aiCheckFailed' as const;
|
|
/** AI check cooldown state changed. */
|
|
export const RespawnAiCheckCooldown = 'respawn:aiCheckCooldown' as const;
|
|
/** Plan completion check started. */
|
|
export const RespawnPlanCheckStarted = 'respawn:planCheckStarted' as const;
|
|
/** Plan completion check completed with result. */
|
|
export const RespawnPlanCheckCompleted = 'respawn:planCheckCompleted' as const;
|
|
/** Plan completion check failed. */
|
|
export const RespawnPlanCheckFailed = 'respawn:planCheckFailed' as const;
|
|
/** Respawn timer started (idle, duration, etc.). */
|
|
export const RespawnTimerStarted = 'respawn:timerStarted' as const;
|
|
/** Respawn timer cancelled. */
|
|
export const RespawnTimerCancelled = 'respawn:timerCancelled' as const;
|
|
/** Respawn timer completed. */
|
|
export const RespawnTimerCompleted = 'respawn:timerCompleted' as const;
|
|
/** Respawn action logged (for monitor UI). */
|
|
export const RespawnActionLog = 'respawn:actionLog' as const;
|
|
/** Respawn debug log message. */
|
|
export const RespawnLog = 'respawn:log' as const;
|
|
/** Respawn error occurred. */
|
|
export const RespawnError = 'respawn:error' as const;
|
|
/** Respawn configuration updated. */
|
|
export const RespawnConfigUpdated = 'respawn:configUpdated' as const;
|
|
|
|
// ─── Subagents ───────────────────────────────────────────────────────────────
|
|
|
|
/** New subagent (background agent) discovered. */
|
|
export const SubagentDiscovered = 'subagent:discovered' as const;
|
|
/** Subagent state updated. */
|
|
export const SubagentUpdated = 'subagent:updated' as const;
|
|
/** Subagent tool call detected. */
|
|
export const SubagentToolCall = 'subagent:tool_call' as const;
|
|
/** Subagent tool result received. */
|
|
export const SubagentToolResult = 'subagent:tool_result' as const;
|
|
/** Subagent progress update. */
|
|
export const SubagentProgress = 'subagent:progress' as const;
|
|
/** Subagent message (assistant text). */
|
|
export const SubagentMessage = 'subagent:message' as const;
|
|
/** Subagent finished. */
|
|
export const SubagentCompleted = 'subagent:completed' as const;
|
|
|
|
// ─── Workflow Runs (ultracode / Workflow tool) ───────────────────────────────
|
|
|
|
/** A workflow run was discovered (first time seen). Payload: WorkflowRunInfo. */
|
|
export const WorkflowRunDiscovered = 'workflow:run_discovered' as const;
|
|
/** A workflow run changed (agent state/token tick). Payload: WorkflowRunInfo. */
|
|
export const WorkflowRunUpdated = 'workflow:run_updated' as const;
|
|
/** A workflow run's file disappeared. Payload: { runId: string }. */
|
|
export const WorkflowRunRemoved = 'workflow:run_removed' as const;
|
|
|
|
// ─── Scheduled Runs ──────────────────────────────────────────────────────────
|
|
|
|
/** Scheduled run created. */
|
|
export const ScheduledCreated = 'scheduled:created' as const;
|
|
/** Scheduled run state updated. */
|
|
export const ScheduledUpdated = 'scheduled:updated' as const;
|
|
/** Scheduled run completed. */
|
|
export const ScheduledCompleted = 'scheduled:completed' as const;
|
|
/** Scheduled run stopped. */
|
|
export const ScheduledStopped = 'scheduled:stopped' as const;
|
|
/** Scheduled run log entry added. */
|
|
export const ScheduledLog = 'scheduled:log' as const;
|
|
/** Scheduled run deleted. */
|
|
export const ScheduledDeleted = 'scheduled:deleted' as const;
|
|
|
|
// ─── Cron Jobs ───────────────────────────────────
|
|
|
|
/** The scheduled-jobs list changed (created/updated/enabled/run-status). Payload: { jobs }. */
|
|
export const CronJobsChanged = 'cron:jobsChanged' as const;
|
|
/** A scheduled job was deleted. Payload: { id }. */
|
|
export const CronJobDeleted = 'cron:jobDeleted' as const;
|
|
/** A scheduled-job run (history record) was created. Payload: CronJobRun. */
|
|
export const CronRunCreated = 'cron:runCreated' as const;
|
|
/** A scheduled-job run (history record) was updated. Payload: CronJobRun. */
|
|
export const CronRunUpdated = 'cron:runUpdated' as const;
|
|
|
|
// ─── Teams ───────────────────────────────────────────────────────────────────
|
|
|
|
/** Agent team created. */
|
|
export const TeamCreated = 'team:created' as const;
|
|
/** Agent team config updated (e.g. new member joined). */
|
|
export const TeamUpdated = 'team:updated' as const;
|
|
/** Agent team removed. */
|
|
export const TeamRemoved = 'team:removed' as const;
|
|
/** Agent team task updated. */
|
|
export const TeamTaskUpdated = 'team:taskUpdated' as const;
|
|
|
|
// ─── Transcript ──────────────────────────────────────────────────────────────
|
|
|
|
/** Transcript complete event detected. */
|
|
export const TranscriptComplete = 'transcript:complete' as const;
|
|
/** Plan mode detected in transcript. */
|
|
export const TranscriptPlanMode = 'transcript:plan_mode' as const;
|
|
/** Tool invocation started in transcript. */
|
|
export const TranscriptToolStart = 'transcript:tool_start' as const;
|
|
/** Tool invocation ended in transcript. */
|
|
export const TranscriptToolEnd = 'transcript:tool_end' as const;
|
|
|
|
// ─── Plan Orchestration ──────────────────────────────────────────────────────
|
|
|
|
/** Plan generation started. */
|
|
export const PlanStarted = 'plan:started' as const;
|
|
/** Plan generation progress update. */
|
|
export const PlanProgress = 'plan:progress' as const;
|
|
/** Plan subagent event (research or planner agent). */
|
|
export const PlanSubagent = 'plan:subagent' as const;
|
|
/** Plan generation completed. */
|
|
export const PlanCompleted = 'plan:completed' as const;
|
|
/** Plan generation cancelled. */
|
|
export const PlanCancelled = 'plan:cancelled' as const;
|
|
|
|
// ─── Tunnel ──────────────────────────────────────────────────────────────────
|
|
|
|
/** Cloudflare tunnel started. */
|
|
export const TunnelStarted = 'tunnel:started' as const;
|
|
/** Cloudflare tunnel stopped. */
|
|
export const TunnelStopped = 'tunnel:stopped' as const;
|
|
/** Tunnel startup progress. */
|
|
export const TunnelProgress = 'tunnel:progress' as const;
|
|
/** Tunnel error. */
|
|
export const TunnelError = 'tunnel:error' as const;
|
|
/** QR code rotated (new token generated). */
|
|
export const TunnelQrRotated = 'tunnel:qrRotated' as const;
|
|
/** QR code force-regenerated. */
|
|
export const TunnelQrRegenerated = 'tunnel:qrRegenerated' as const;
|
|
/** QR auth token consumed by a client. */
|
|
export const TunnelQrAuthUsed = 'tunnel:qrAuthUsed' as const;
|
|
|
|
// ─── Image ───────────────────────────────────────────────────────────────────
|
|
|
|
/** New image file detected (e.g. screenshot upload). */
|
|
export const ImageDetected = 'image:detected' as const;
|
|
/** New document/image attachment detected in a session working directory. */
|
|
export const AttachmentDetected = 'attachment:detected' as const;
|
|
|
|
// ─── Hooks ───────────────────────────────────────────────────────────────────
|
|
|
|
/** Claude Code hook: session idle, waiting for input. */
|
|
export const HookIdlePrompt = 'hook:idle_prompt' as const;
|
|
/**
|
|
* Claude Code hook: tool requesting permission. Also raised by the server itself, with
|
|
* `source: 'screen'`, for a dialog read off a hook-less CLI's screen (codex; see
|
|
* `web/screen-blocked.ts`), which is cleared by `approval:resolved`.
|
|
*/
|
|
export const HookPermissionPrompt = 'hook:permission_prompt' as const;
|
|
/** Claude Code hook: elicitation dialog (Claude asking a question). */
|
|
export const HookElicitationDialog = 'hook:elicitation_dialog' as const;
|
|
/** Claude Code hook: elicitation dialog closed (question answered in the terminal). */
|
|
export const HookElicitationComplete = 'hook:elicitation_complete' as const;
|
|
/** Claude Code hook: elicitation answer submitted. */
|
|
export const HookElicitationResponse = 'hook:elicitation_response' as const;
|
|
/** Claude Code hook: response complete. */
|
|
export const HookStop = 'hook:stop' as const;
|
|
/**
|
|
* Agent started a turn. NOT a Claude Code hook: this one is reported by the
|
|
* DeepSeek Harness status bridge, which is why the name is agent-generic. It
|
|
* exists so a dialog answered in the terminal clears its alert immediately
|
|
* instead of waiting for the turn to end.
|
|
*/
|
|
export const HookAgentWorking = 'hook:agent_working' as const;
|
|
/** Claude Code hook: teammate went idle. */
|
|
export const HookTeammateIdle = 'hook:teammate_idle' as const;
|
|
/** Claude Code hook: teammate task completed. */
|
|
export const HookTaskCompleted = 'hook:task_completed' as const;
|
|
/** UserPromptSubmit fired in a Claude pane (#367): the pane learned its live conversation id first-hand. */
|
|
export const HookPromptSubmitted = 'hook:prompt_submitted' as const;
|
|
|
|
// ─── Approvals Inbox ─────────────────────────────────────────────────────────
|
|
|
|
/** A prompt is waiting on a human (permission dialog, question, idle prompt). */
|
|
export const ApprovalPending = 'approval:pending' as const;
|
|
/** A pending approval's captured context/options were refreshed. */
|
|
export const ApprovalUpdated = 'approval:updated' as const;
|
|
/** A pending approval left the inbox (answered, superseded, expired, ...). */
|
|
export const ApprovalResolved = 'approval:resolved' as const;
|
|
|
|
// ─── Custom Model Endpoint Profiles ──────────────────────────────────────────
|
|
|
|
/**
|
|
* A session's own custom-model selection is no longer the model llama-swap has loaded —
|
|
* ANOTHER session's activity on the same endpoint evicted it (llama.cpp/llama-swap runs
|
|
* one model at a time). Detected after the fact by a periodic sweep (`server.ts`), never
|
|
* at the moment of eviction itself, since llama-swap has no push notification of its own;
|
|
* this session's next prompt will trigger reloading its model, evicting whatever displaced
|
|
* it in turn. Fires at most once per displacement (cleared once the sweep sees the
|
|
* session's own model loaded again), so it can't spam on every sweep interval.
|
|
*/
|
|
export const CustomModelSwappedOut = 'custom-model:swapped-out' as const;
|
|
|
|
// ─── Orchestrator ────────────────────────────────────────────────────────────
|
|
|
|
/** Orchestrator state machine transitioned. */
|
|
export const OrchestratorStateChanged = 'orchestrator:stateChanged' as const;
|
|
/** Orchestrator plan generation progress update. */
|
|
export const OrchestratorPlanProgress = 'orchestrator:planProgress' as const;
|
|
/** Orchestrator plan generated and ready for approval. */
|
|
export const OrchestratorPlanReady = 'orchestrator:planReady' as const;
|
|
/** Orchestrator phase started executing. */
|
|
export const OrchestratorPhaseStarted = 'orchestrator:phaseStarted' as const;
|
|
/** Orchestrator phase completed successfully. */
|
|
export const OrchestratorPhaseCompleted = 'orchestrator:phaseCompleted' as const;
|
|
/** Orchestrator phase failed. */
|
|
export const OrchestratorPhaseFailed = 'orchestrator:phaseFailed' as const;
|
|
/** Orchestrator verification result for a phase. */
|
|
export const OrchestratorVerification = 'orchestrator:verification' as const;
|
|
/** Orchestrator task assigned to session. */
|
|
export const OrchestratorTaskAssigned = 'orchestrator:taskAssigned' as const;
|
|
/** Orchestrator task completed. */
|
|
export const OrchestratorTaskCompleted = 'orchestrator:taskCompleted' as const;
|
|
/** Orchestrator task failed. */
|
|
export const OrchestratorTaskFailed = 'orchestrator:taskFailed' as const;
|
|
/** All orchestrator phases completed successfully. */
|
|
export const OrchestratorCompleted = 'orchestrator:completed' as const;
|
|
/** Orchestrator error. */
|
|
export const OrchestratorError = 'orchestrator:error' as const;
|
|
|
|
// ─── Clipboard ──────────────────────────────────────────────────────────────
|
|
|
|
/** Clipboard content pushed to browser. */
|
|
export const ClipboardWrite = 'clipboard:write' as const;
|
|
|
|
// ─── Cases ───────────────────────────────────────────────────────────────────
|
|
|
|
/** New case directory created. */
|
|
export const CaseCreated = 'case:created' as const;
|
|
/** Existing directory linked as a case. */
|
|
export const CaseLinked = 'case:linked' as const;
|
|
/** Case deleted or unlinked. */
|
|
export const CaseDeleted = 'case:deleted' as const;
|
|
/** Case ordering changed. */
|
|
export const CaseOrderChanged = 'case:order-changed' as const;
|
|
|
|
// ─── Docker cases ────────────────────────────────────────────────────────────
|
|
/** A docker case export bundle finished writing. */
|
|
export const DockerExportComplete = 'docker:exportComplete' as const;
|
|
/** A docker case export failed. */
|
|
export const DockerExportFailed = 'docker:exportFailed' as const;
|
|
/** A docker bundle was imported into a new case. */
|
|
export const DockerImportComplete = 'docker:importComplete' as const;
|
|
/** The agent base image started building (first Docker case; auto-build on first use). */
|
|
export const DockerImageBuildStarted = 'docker:imageBuildStarted' as const;
|
|
/** A line of agent base-image build output (progress surfacing). */
|
|
export const DockerImageBuildProgress = 'docker:imageBuildProgress' as const;
|
|
/** The agent base image finished building successfully. */
|
|
export const DockerImageBuildComplete = 'docker:imageBuildComplete' as const;
|
|
/** The agent base image build failed. */
|
|
export const DockerImageBuildFailed = 'docker:imageBuildFailed' as const;
|
|
/** A case container was removed after a config-drift confirm (recreated with the new config on next launch). */
|
|
export const DockerContainerRecreated = 'docker:containerRecreated' as const;
|
|
|
|
// ─── Multi-user (admin-only / targeted) ──────────────────────────────────────
|
|
|
|
/** The user roster changed (admin-only); the Users panel re-fetches. */
|
|
export const AdminUsersChanged = 'admin:usersChanged' as const;
|
|
/** A user must change their password (targeted); the frontend shows the modal. */
|
|
export const AuthPasswordChangeRequired = 'auth:passwordChangeRequired' as const;
|
|
|
|
/** Global session tab order changed (synced across devices). COD-131. */
|
|
export const SessionOrderChanged = 'session:orderChanged' as const;
|
|
|
|
/** A saved web tab (dashboard URL) was created, updated or deleted.
|
|
* Payload: `{ action: 'created' | 'updated' | 'deleted', id, owner }`. The client
|
|
* re-fetches the list rather than patching from the payload. `owner` is the web
|
|
* tab's owner (`'@single'` when multi-user mode is off); in multi-user mode the
|
|
* event is delivered only to that owner and admins (`deriveWebviewSseHint`). */
|
|
export const WebviewChanged = 'webview:changed' as const;
|
|
/** Owner-scoped layout invalidation. Payload contains only `{ owner, version }`. */
|
|
export const TabLayoutChanged = 'tab:layoutChanged' as const;
|
|
|
|
// ─── Namespace Re-export ─────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* All SSE event types as a namespace object.
|
|
* Convenient for destructured imports or passing as a group.
|
|
*/
|
|
export const SseEvent = {
|
|
// Core
|
|
Init,
|
|
|
|
// Transport
|
|
Heartbeat,
|
|
|
|
// Session lifecycle
|
|
SessionCreated,
|
|
SessionUpdated,
|
|
SessionDeleted,
|
|
SessionTerminal,
|
|
SessionNeedsRefresh,
|
|
SessionClearTerminal,
|
|
SessionCompletion,
|
|
SessionError,
|
|
SessionExit,
|
|
SessionIdle,
|
|
SessionWorking,
|
|
SessionAutoClear,
|
|
SessionAutoCompact,
|
|
SessionLimitPauseScheduled,
|
|
SessionLimitResume,
|
|
SessionLimitResumeCancelled,
|
|
SessionRespawnBreakerTripped,
|
|
SessionCliInfo,
|
|
SessionPinned,
|
|
SessionMessage,
|
|
SessionInteractive,
|
|
SessionRunning,
|
|
SessionStatusTelemetry,
|
|
SessionPromptCache,
|
|
SessionKeepWarm,
|
|
|
|
// Session: Ralph
|
|
SessionRalphLoopUpdate,
|
|
SessionRalphTodoUpdate,
|
|
SessionRalphCompletionDetected,
|
|
SessionRalphStatusUpdate,
|
|
SessionCircuitBreakerUpdate,
|
|
SessionExitGateMet,
|
|
|
|
// Session: Bash tools
|
|
SessionBashToolStart,
|
|
SessionBashToolEnd,
|
|
SessionBashToolsUpdate,
|
|
|
|
// Session: Plan
|
|
SessionPlanTaskUpdate,
|
|
SessionPlanCheckpoint,
|
|
SessionPlanRollback,
|
|
SessionPlanTaskAdded,
|
|
|
|
// Tasks
|
|
TaskCreated,
|
|
TaskCompleted,
|
|
TaskFailed,
|
|
TaskUpdated,
|
|
|
|
// Mux
|
|
MuxCreated,
|
|
MuxKilled,
|
|
MuxDied,
|
|
MuxStatsUpdated,
|
|
|
|
// Remote auto-reconnect (COD-108)
|
|
RemoteSessionDropped,
|
|
RemoteSessionReconnected,
|
|
RemoteReconnectExhausted,
|
|
RemoteHostWaking,
|
|
RemoteHostWakeFailed,
|
|
|
|
// Respawn
|
|
RespawnStarted,
|
|
RespawnStopped,
|
|
RespawnStateChanged,
|
|
RespawnCycleStarted,
|
|
RespawnCycleCompleted,
|
|
RespawnBlocked,
|
|
RespawnStepSent,
|
|
RespawnStepCompleted,
|
|
RespawnDetectionUpdate,
|
|
RespawnAutoAcceptSent,
|
|
RespawnAiCheckStarted,
|
|
RespawnAiCheckCompleted,
|
|
RespawnAiCheckFailed,
|
|
RespawnAiCheckCooldown,
|
|
RespawnPlanCheckStarted,
|
|
RespawnPlanCheckCompleted,
|
|
RespawnPlanCheckFailed,
|
|
RespawnTimerStarted,
|
|
RespawnTimerCancelled,
|
|
RespawnTimerCompleted,
|
|
RespawnActionLog,
|
|
RespawnLog,
|
|
RespawnError,
|
|
RespawnConfigUpdated,
|
|
|
|
// Subagents
|
|
SubagentDiscovered,
|
|
SubagentUpdated,
|
|
SubagentToolCall,
|
|
SubagentToolResult,
|
|
SubagentProgress,
|
|
SubagentMessage,
|
|
SubagentCompleted,
|
|
|
|
// Workflow runs (ultracode)
|
|
WorkflowRunDiscovered,
|
|
WorkflowRunUpdated,
|
|
WorkflowRunRemoved,
|
|
|
|
// Scheduled runs
|
|
ScheduledCreated,
|
|
ScheduledUpdated,
|
|
ScheduledCompleted,
|
|
ScheduledStopped,
|
|
ScheduledLog,
|
|
ScheduledDeleted,
|
|
|
|
// Cron jobs
|
|
CronJobsChanged,
|
|
CronJobDeleted,
|
|
CronRunCreated,
|
|
CronRunUpdated,
|
|
|
|
// Teams
|
|
TeamCreated,
|
|
TeamUpdated,
|
|
TeamRemoved,
|
|
TeamTaskUpdated,
|
|
|
|
// Transcript
|
|
TranscriptComplete,
|
|
TranscriptPlanMode,
|
|
TranscriptToolStart,
|
|
TranscriptToolEnd,
|
|
|
|
// Plan orchestration
|
|
PlanStarted,
|
|
PlanProgress,
|
|
PlanSubagent,
|
|
PlanCompleted,
|
|
PlanCancelled,
|
|
|
|
// Tunnel
|
|
TunnelStarted,
|
|
TunnelStopped,
|
|
TunnelProgress,
|
|
TunnelError,
|
|
TunnelQrRotated,
|
|
TunnelQrRegenerated,
|
|
TunnelQrAuthUsed,
|
|
|
|
// Image
|
|
ImageDetected,
|
|
AttachmentDetected,
|
|
|
|
// Hooks
|
|
HookIdlePrompt,
|
|
HookPermissionPrompt,
|
|
HookElicitationDialog,
|
|
HookElicitationComplete,
|
|
HookElicitationResponse,
|
|
HookStop,
|
|
HookAgentWorking,
|
|
HookTeammateIdle,
|
|
HookTaskCompleted,
|
|
|
|
// Approvals Inbox
|
|
ApprovalPending,
|
|
ApprovalUpdated,
|
|
ApprovalResolved,
|
|
|
|
// Custom Model Endpoint Profiles
|
|
CustomModelSwappedOut,
|
|
|
|
// Orchestrator
|
|
OrchestratorStateChanged,
|
|
OrchestratorPlanProgress,
|
|
OrchestratorPlanReady,
|
|
OrchestratorPhaseStarted,
|
|
OrchestratorPhaseCompleted,
|
|
OrchestratorPhaseFailed,
|
|
OrchestratorVerification,
|
|
OrchestratorTaskAssigned,
|
|
OrchestratorTaskCompleted,
|
|
OrchestratorTaskFailed,
|
|
OrchestratorCompleted,
|
|
OrchestratorError,
|
|
|
|
// Clipboard
|
|
ClipboardWrite,
|
|
|
|
// Cases
|
|
CaseCreated,
|
|
CaseLinked,
|
|
CaseDeleted,
|
|
CaseOrderChanged,
|
|
|
|
// Docker cases
|
|
DockerExportComplete,
|
|
DockerExportFailed,
|
|
DockerImportComplete,
|
|
DockerImageBuildStarted,
|
|
DockerImageBuildProgress,
|
|
DockerImageBuildComplete,
|
|
DockerImageBuildFailed,
|
|
AdminUsersChanged,
|
|
AuthPasswordChangeRequired,
|
|
DockerContainerRecreated,
|
|
|
|
// Session order (global tab order sync)
|
|
SessionOrderChanged,
|
|
|
|
// Web tabs (dashboard URLs)
|
|
WebviewChanged,
|
|
TabLayoutChanged,
|
|
} as const;
|