import type { ExitIntentDTO, NodeStatusDTO } from './common.js'; import type { NodeSubjectDTO } from './nodes.js'; /** `POST /v1/nodes/{id}/broker/session-bound` body. Pi's session-start reason * distinguishes an ordinary boot/resume from `/new`, whose child-side session * reset is a different durable operation. `reviewBoundaryIds` reports only the * review markers visible in Pi's current branch; crtrd owns the node binding * used to decide whether that branch is valid. */ export interface BrokerSessionBoundRequest { executionId: string; piSessionId: string; sessionFile: string | null; pid: number; reason: string | null; reviewBoundaryIds: string[]; } /** Pi-side consequence selected by crtrd after binding the session. The * handler itself never calls back into the broker while servicing the request. */ export interface BrokerSessionBoundResultDTO { action: 'none' | 'relaunch_root' | 'shutdown'; } /** `POST /v1/nodes/{id}/broker/settle` body. These are the facts only Pi can * know at its settlement boundary; crtrd reads all current canvas state and * selects the durable consequence. */ export interface BrokerExecutionRequest { expected_execution_id: string; } export interface BrokerSettleRequest extends BrokerExecutionRequest { stopReason: string; backgroundJobsRunning: boolean; pushedFinal: boolean; } /** `POST /v1/nodes/{id}/broker/telemetry` body. Tokens are cumulative within * the broker's current Pi session; null context/activity values preserve the * last usable value in the daemon projection, matching telemetry.json. */ export interface BrokerTelemetryRequest extends BrokerExecutionRequest { tokens_in: number; context_tokens: number | null; last_activity: string | null; updated_at: string; } /** The only consequence a settle caller may enact. crtrd has already committed * every canvas and placement effect before returning this directive. */ export type BrokerSettleDirective = { action: 'reprompt'; prompt: string; } | { action: 'stay_dormant'; } | { action: 'shutdown'; }; /** A main-engine input has won broker admission while a parking summary may be * in flight. crtrd records it against the process-local pending marker before * Pi begins the input, making parking completion and input admission atomic. */ export interface BrokerParkActivityResultDTO { activity: 'recorded' | 'none'; } /** `POST /v1/nodes/{id}/broker/park-complete` body. The isolated parking turn * has ended; crtrd alone decides whether its pending park still applies. */ export interface BrokerParkCompleteRequest extends BrokerExecutionRequest { outcome: 'completed' | 'failed'; } /** Durable model recipe selected by the live broker after Pi accepts a model or thinking change. */ export interface BrokerModelCommitRequest extends BrokerExecutionRequest { spec: string; pinnedOverride?: boolean; userSelected: boolean; } export interface BrokerModelCommitResultDTO { modelOverride: string; } /** The dependency-light identity/runtime projection broker extensions need to * render their local Pi hooks without reading canvas.db themselves. */ export interface BrokerExtensionNodeDTO { node_id: string; name: string; description?: string; title?: string; icon?: string; kind: string; mode: 'base' | 'orchestrator'; lifecycle: 'terminal' | 'resident'; status: NodeStatusDTO; cwd: string; parent: string | null; fork_from: string | null; profile_id: string | null; managed_worktree?: { state: 'open' | 'closed' | 'abandoned'; cleanup?: 'pending' | 'complete'; path: string; branch: string; base_ref: string; base_sha: string; } | null; review_binding?: { kind?: 'review' | 'page_feedback'; review_id: string; origin_node_id: string; branch_file: string; target_file: string; } | null; intent: ExitIntentDTO; /** `kind` is absent on rows written before kind joined the drift key; a read * resolves it to the node's current kind. */ persona_ack?: { kind?: string; mode: 'base' | 'orchestrator'; lifecycle: 'terminal' | 'resident'; }; created: string; } export type BrokerExtensionSubjectDTO = NodeSubjectDTO; /** One resolved report sender. Report contents stay broker-local filesystem * data; this daemon projection supplies only existence and display metadata. */ export interface BrokerReportNodeDTO { node_id: string; name: string; created: string; } /** `GET /v1/nodes/{id}/broker/extension-state`. This is deliberately a fixed * extension rendering projection, not a generic node/state read API. */ export interface BrokerExtensionStateDTO { node: BrokerExtensionNodeDTO; warm_spare: boolean; ancestors: BrokerExtensionNodeDTO[]; children: BrokerExtensionNodeDTO[]; fork_source: BrokerExtensionNodeDTO | null; subject: BrokerExtensionSubjectDTO; report_nodes: BrokerReportNodeDTO[]; } /** Guarded generated-label update. `initial` can only fill a blank generated * description; `recap` additionally compares the exact automatic-name snapshot * captured before the headless naming call. */ export type BrokerGeneratedNameRequest = BrokerExecutionRequest & ({ kind: 'initial'; description: string; title: string; icon: string; } | { kind: 'recap'; description: string; title: string; icon: string; expected: { name: string; description: string; title: string; icon: string; kind: string; }; }); /** A daemon-selected Pi editor-label directive. No handler calls a broker. * `description`/`title`/`icon` are the values as STORED (an empty title or icon * is left unset), so the broker announces what the node now carries rather than * what it asked for. All four are present exactly when `applied`. */ export interface BrokerGeneratedNameResultDTO { applied: boolean; editorLabel?: string; description?: string; title?: string; icon?: string; } export interface BrokerPersonaAckRequest extends BrokerExecutionRequest { from: { kind: string; mode: 'base' | 'orchestrator'; lifecycle: 'terminal' | 'resident'; }; to: { kind: string; mode: 'base' | 'orchestrator'; lifecycle: 'terminal' | 'resident'; }; } export interface BrokerPersonaAckResultDTO { applied: boolean; }