mirror of
https://github.com/stablyai/orca.git
synced 2026-10-09 08:02:35 +00:00
* feat(dashboard): open-worktree dialog control + finished-time parity Pop-out agent dashboard polish: - Terminal dialog: replace the footer Close button with the standard top-right X, rename the primary action from Focus worktree to Open worktree, and prefix it with an open-in-window icon. - Card time column: finished agents now read time-since-finish (matching the left worktree sidebar) instead of time-since-start. Extracts the sidebar's finished-timestamp logic into a shared helper so the two surfaces cannot drift, and threads finishedAt through the dashboard snapshot contract. * fix(dashboard): thread finishedAt through payload validator + test fixture CI typecheck caught a DashboardCard fixture in dashboard-payload-validation.test.ts missing the new finishedAt field; also validate finishedAt in the relay guard. * feat(dashboard): swap pending-question emoji for MessageCircleQuestion icon The amber pending-question chip used a raw hand emoji (renders differently per-OS and off the design system); use the lucide chat-with-question icon.
79 lines
3.3 KiB
TypeScript
79 lines
3.3 KiB
TypeScript
import type { AgentType } from './agent-status-types'
|
|
|
|
/**
|
|
* Serializable contract for the pop-out agent dashboard. The main renderer owns
|
|
* the live store, derives this snapshot, and relays it (through the main
|
|
* process) to the separate pop-out renderer, which renders it presentationally.
|
|
* Every field must be structured-clone-safe (no functions / class instances).
|
|
*/
|
|
|
|
/** The three kanban columns. "Idle" is everything that isn't actively working
|
|
* and isn't blocking you — this includes explicitly-completed ('done') agents,
|
|
* which Orca only reports when a completion hook fires, so they're folded in
|
|
* rather than split into a separate, inconsistently-populated column. */
|
|
export type DashboardBucket = 'attention' | 'working' | 'idle'
|
|
|
|
/** Column order shared by producer and pop-out so they never drift. */
|
|
export const DASHBOARD_BUCKET_ORDER: readonly DashboardBucket[] = ['attention', 'working', 'idle']
|
|
|
|
/** Precise per-card state marker (drives AgentStateDot). Kept distinct from
|
|
* `bucket` so the "Needs You" column can still show amber (waiting/permission)
|
|
* vs red (blocked) dots. */
|
|
export type DashboardCardDotState = 'working' | 'blocked' | 'waiting' | 'done' | 'idle'
|
|
|
|
export type DashboardCard = {
|
|
/** Stable identity for React keys. */
|
|
paneKey: string
|
|
/** Resolved live PTY id for the terminal preview, or null when the agent has
|
|
* no live pane (e.g. a retained/done row whose pane is gone). */
|
|
ptyId: string | null
|
|
agentType: AgentType
|
|
bucket: DashboardBucket
|
|
dotState: DashboardCardDotState
|
|
/** One-line task/prompt text shown on the card. */
|
|
task: string
|
|
/** The most recent message the user sent this agent (its current prompt). */
|
|
lastUserMessage?: string
|
|
/** The most recent message the agent sent back. */
|
|
lastAgentMessage?: string
|
|
/** Routing target for click-to-focus. leafId is null when unresolved. */
|
|
repoId: string
|
|
worktreeId: string
|
|
tabId: string
|
|
leafId: string | null
|
|
repoName: string
|
|
worktreeName: string
|
|
/** "Started … ago" display. */
|
|
startedAt: number
|
|
/** When the agent last entered `done`, or null if it never finished. Drives
|
|
* the card's time column: finished cards read time-since-finish (parity with
|
|
* the left worktree sidebar), active cards fall back to startedAt. */
|
|
finishedAt: number | null
|
|
/** When the agent entered its current state — column ordering key (cards
|
|
* that moved into a bucket most recently sort first). 0 when unknown. */
|
|
stateChangedAt: number
|
|
/** Mirrors the sidebar's unvisited signal: the agent changed state since the
|
|
* user last acknowledged it (visited its tab / opened its dashboard dialog).
|
|
* Derived from the app-wide ack map so both surfaces mute in lockstep. */
|
|
unseen: boolean
|
|
/** Short summary of the pending question when bucket === 'attention'. */
|
|
askSummary?: string
|
|
}
|
|
|
|
export type DashboardSnapshot = {
|
|
generatedAt: number
|
|
cards: DashboardCard[]
|
|
}
|
|
|
|
export const EMPTY_DASHBOARD_SNAPSHOT: DashboardSnapshot = { generatedAt: 0, cards: [] }
|
|
|
|
/** Routing payload for click-to-focus: reveal this agent's pane in the main
|
|
* window. leafId is null when the pane could not be resolved (best-effort:
|
|
* the worktree is still activated). */
|
|
export type DashboardRevealAgentArgs = {
|
|
repoId: string
|
|
worktreeId: string
|
|
tabId: string
|
|
leafId: string | null
|
|
}
|