Files
nucleic-remote-ios/NucleicRemote/Shared/SessionActivityAttributes.swift
T
abkslmandNucleic 0dda487167 Live Activity Content Density
Nucleic-Session: B3643133-163C-4C5D-BE20-1A6B7FB83DA9
Co-authored-by: Nucleic <[email protected]>
2026-07-04 23:29:52 -07:00

78 lines
3.4 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import ActivityKit
import Foundation
/// The one aggregate Live Activity (UX_IOS §5.3, aggregate per §11.4 — a single Activity
/// respects iOS's budget better than one per session). It answers "what is Nucleic doing right
/// now?" at a glance: the headline counts (running / waiting / approvals), the total churn in
/// flight, and a few of the most urgent sessions with their state and diff. Shared between the
/// app (which starts/updates it) and the widget extension (which renders it).
///
/// Deliberately free of `NucleicProtocol` types — the widget extension links only this file, so
/// the state carries plain value types and its own small `Backend`/`Kind` enums rather than the
/// wire `BackendID`/`SessionStatus`.
struct NucleicSessionAttributes: ActivityAttributes {
/// The agent behind a session — drives a row's provider tag/tint.
enum Backend: String, Codable, Hashable {
case claude, codex, grok, other
var label: String {
switch self {
case .claude: "Claude"
case .codex: "Codex"
case .grok: "Grok"
case .other: "Agent"
}
}
}
/// A session's live state, collapsed to what the glance needs — drives each row's glyph/tint.
enum Kind: String, Codable, Hashable {
case running // agent actively working a turn
case provisioning // worktree/setup spinning up
case approval // blocked on a human approval decision (loudest)
case needsInput // turn ended asking the user something
case done // turn finished its work; nothing required
case error // errored / interrupted
case idle // created, not yet working
}
/// One agent session surfaced in the activity's detail rows.
struct SessionLine: Codable, Hashable, Identifiable {
var id: String
/// The session's title (falls back to the project name upstream).
var title: String
/// Project the session belongs to.
var project: String
var backend: Backend
var kind: Kind
/// A compact right-aligned status: its diff ("3 files +42 −7"), "2 to approve",
/// "Waiting on you", "Working…", etc.
var detail: String
}
struct ContentState: Codable, Hashable {
/// Sessions actively working a turn.
var runningCount: Int
/// Sessions blocked on the user (approval or next prompt) — the loud number.
var needsYouCount: Int
/// Total individual approval decisions waiting across all sessions — the "act now" count.
var approvalCount: Int
/// Aggregate worktree churn across the active sessions.
var filesChanged: Int
var linesAdded: Int
var linesRemoved: Int
/// The most urgent sessions, attention-first (capped, typically ≤3): the detail rows.
var lines: [SessionLine]
/// The single most urgent session (drives the compact/minimal regions).
var top: SessionLine? { lines.first }
/// Whether anything needs the user (waiting session or a pending approval).
var needsAttention: Bool { needsYouCount > 0 || approvalCount > 0 }
/// Whether any worktree has uncommitted changes to summarize.
var hasChurn: Bool { filesChanged > 0 }
}
/// The paired Mac's name (static for the Activity's lifetime).
var hostName: String
}