// The JSON the watch app reads and sends. This is the contract between the gateway and the // watch's Codable models (watch/WristCode/API/Models.swift). docs/api.md describes it for humans. // Change both sides together. import type { Phase } from "./awareness.ts"; import type { ApprovalDecision } from "./t3/types.ts"; import type { HostStatus } from "./t3/host.ts"; export interface HostSummary { id: string; label: string; status: HostStatus; error: string | null; } /** Something a thread is waiting on: an approval, or questions for the user. */ export interface PendingRequest { id: string; /** `command`, `file-change`, `permission`, `user_input`, ... */ kind: string; /** What the agent wants to do, such as the command line. Null when the server gave none. */ prompt: string | null; reason: string | null; /** Approval choices, in the server's order. Empty for questions. */ options: Array<{ decision: ApprovalDecision; label: string }>; /** Questions for the user. Empty for approvals. */ questions: Array<{ id: string; header: string; question: string; options: Array<{ label: string; value: string }>; allowCustomAnswer: boolean; }>; } export interface FeedItem { hostId: string; hostLabel: string; threadId: string; projectId: string; projectTitle: string; title: string; phase: Phase; updatedAt: string; /** The agent's latest message, trimmed for the watch. Null until the gateway has read it. */ lastMessage: string | null; request: PendingRequest | null; } export interface Feed { /** Waiting for approval or input. Oldest request first. */ needsYou: FeedItem[]; /** Starting or running. Most recently updated first. */ working: FeedItem[]; /** Completed or failed in the last 24 hours. Most recent first, at most 10. */ recent: FeedItem[]; hosts: HostSummary[]; } export interface Message { id: string; role: "user" | "assistant" | "system"; text: string; createdAt: string; } export interface ThreadDetail { item: FeedItem; /** Oldest first, at most 20. */ messages: Message[]; /** True while a run is active, so Stop makes sense. */ canStop: boolean; } export interface ProjectsResponse { hosts: Array< HostSummary & { projects: Array<{ id: string; title: string; /** The model a new thread will use, such as `claude-opus-5-5`. Null when none is configured. */ model: string | null; }>; } >; } export interface PairRequest { code: string; deviceName: string; } export interface PairResponse { deviceId: string; deviceToken: string; } export interface PushRegistration { apnsToken: string; apnsEnvironment: "sandbox" | "production"; } export interface SendMessageRequest { text: string; } export type RespondRequest = | { requestId: string; decision: ApprovalDecision } | { requestId: string; answers: Record }; export interface NewThreadRequest { hostId: string; projectId: string; text: string; } export interface NewThreadResponse { hostId: string; threadId: string; } export interface ErrorResponse { error: string; } /** Custom keys on every push notification, beside `aps`. */ export interface PushPayload { hostId: string; threadId: string; requestId?: string; } /** Notification categories the watch registers actions for. */ export type PushCategory = "approval" | "finished" | "failed" | "input" | "host";