import type { InterruptOutcome, SessionEvent, SessionSnapshot } from '../session/types.js'; import type { RoomOrchestrationRecord, TaskOutcome, TaskRecord, TaskTerminalIntent, TaskListRecord } from '../rooms-tasks/types.js'; import { type OwnerCommentsState } from './notices.js'; import type { CreateRoomRequest, CreateTaskRequest, TaskProvisioningOutcome, TaskRoomApplicationService } from '../application/task-room-service.js'; import type { TaskState } from '../rooms-tasks/types.js'; /** * Fleet-level effects a deterministic owner command may trigger. Production * uses the detached CLI (`fleetCliOps`); tests inject fakes so no command can * ever bounce a real service from the suite. */ export interface OwnerFleetOps { /** `ours-fleet restart` (keep) or `ours-fleet force-restart` (fresh) of this role. */ restart(mode: 'keep' | 'fresh'): Promise; /** `ours-fleet ls` output. */ list(): Promise; /** Start a room-close worker outside the caller role's supervisor lifecycle. */ closeRoom(roomId: string): Promise; /** Resume a task terminal intent outside the caller role's supervisor lifecycle. */ settleTask(taskId: string): Promise; /** Settle an accepted task deletion outside the caller role's supervisor lifecycle. */ settleTaskDeletion(taskId: string): Promise; /** Continue an accepted provisioning saga until convergence. */ provisionTask(taskId: string): Promise; } /** * The narrow capability surface a command executor sees. Everything here is * already scoped to the one role whose channel received the message; commands * cannot name another agent or another recipient. */ export interface OwnerCommandContext { authenticatedCid?: string; role: string; /** Harness id of the role (e.g. 'claude-code', 'codex'); gates forwarding. */ harness: string; version: string; snapshot(): SessionSnapshot; interrupt(): Promise; /** * Deliver raw slash text to the agent harness. Only commands the bundled * ACP adapter for `harness` verifiably executes locally may be forwarded * (see HARNESS_LOCAL_COMMANDS); anything else would reach the model as an * ordinary prompt. The channel sends the acceptance and outcome notices * itself. */ runHarnessCommand(command: string): Promise; restart(mode: 'keep' | 'fresh'): Promise; /** Effective ACP live-comment relay state of this running channel. */ comments(): OwnerCommentsState; /** * Change the RUNNING session's effective live-comment relaying. The fleet.yaml * baseline is never rewritten, so a restart returns to the declared value. */ setComments(enabled: boolean): OwnerCommentsState; fleetList(): Promise; /** Persist acceptance, acknowledge it, then launch the external close worker. */ closeRoom(roomId: string): Promise; /** Persist terminal intent, acknowledge it, then launch the external settle worker. */ terminalTask(taskId: string, kind: TaskTerminalIntent['kind'], outcome?: TaskOutcome): Promise; createTask(input: Omit): Promise; startTask(taskId: string): Promise; taskProvisioningOutcome?(taskId: string): TaskProvisioningOutcome; listTasks(filter?: { state?: TaskState | TaskState[]; list?: string; }): TaskRecord[]; groupedTasks(filter?: { state?: TaskState | TaskState[]; list?: string; }): Array<{ list: TaskListRecord; tasks: TaskRecord[]; }>; listTaskLists(): TaskListRecord[]; createTaskList(name: string): Promise; renameTaskList(name: string, newName: string): Promise; deleteTaskList(name: string, destination?: string): Promise<{ deleted: TaskListRecord; moved: number; destination?: TaskListRecord; }>; moveTask(taskId: string, list: string): Promise; getTask(taskId: string): { task: TaskRecord; orchestration: RoomOrchestrationRecord | undefined; }; blockTask(taskId: string, reason: string): TaskRecord; unblockTask(taskId: string): TaskRecord; reviewTask(taskId: string): TaskRecord; /** Accept a permanent any-state deletion, acknowledge it, then launch the external delete worker. */ deleteTask(taskId: string): Promise; listRoomQueries(filter?: { state?: 'active' | 'provisioning'; }): ReturnType; getRoomQuery(id: string): ReturnType; listTemplateQueries(): ReturnType; getTemplateQuery(name: string): ReturnType; createRoom(input: Omit): Promise; recentEvents(limit: number): SessionEvent[]; readWorklogTail(maxChars: number): Promise; reply(text: string): Promise; replyHtml(filename: string, html: string): Promise; } export interface OwnerCommand { /** Primary name without the leading slash. */ name: string; aliases?: string[]; /** Shown in help; defaults to `/`. */ usage?: string; /** One-line description shown in help. */ summary: string; execute(ctx: OwnerCommandContext, args: string): Promise; } export interface OwnerTypedCommandDefinition { name: string; description: string; input_schema: Record; } /** * Commands each harness's bundled ACP adapter verifiably executes locally, * pinned by test/acp-adapter-commands.test.ts against the shipped adapter * artifacts. claude-agent-acp routes slash commands into the Claude SDK, * which runs its builtins (/clear, /compact, /model) without a model turn; * codex-acp intercepts only /compact — /clear and /model are not builtins * and would fall through into sendPrompt, i.e. reach the model as an * ordinary prompt. Unlisted harnesses forward nothing. */ export declare const HARNESS_LOCAL_COMMANDS: Record; /** * The single source of truth for the deterministic owner-channel command set: * /help renders exactly this table, so adding an entry here is the whole * registration step for a new command. */ export declare const ownerCommands: OwnerCommand[]; /** * Project the slash-command registry into the SDK catalog. Only primary names * are advertised: aliases remain accepted by the slash dispatcher without * cluttering the typed menu with duplicate actions. * * Typed arguments deliberately stay as the exact text following the command * name. That adapter is what lets typed and slash invocations share every * existing parser, usage error, lifecycle guard, and result path. */ export declare function ownerTypedCommandCatalog(): OwnerTypedCommandDefinition[]; /** Convert one typed invocation back into the canonical slash input. */ export declare function ownerTypedCommandText(name: string, input: unknown): string; /** Trimmed slash-prefixed text is a command attempt and is never forwarded. */ export declare const isOwnerCommandText: (text: string) => boolean; export declare function ownerCommandHelp(error?: string): string; /** * Execute one authenticated owner command. `text` must already be trimmed, * slash-prefixed, and from an authorized owner CID — the channel enforces the * authority boundary before dispatch ever sees the message. */ export declare function dispatchOwnerCommand(text: string, ctx: OwnerCommandContext): Promise; /** * Production fleet effects: the detached ours-fleet CLI. The restart child is * detached and unreferenced because a successful restart kills this very * process; the reply and the durable wire record must already be on disk. */ export declare function fleetCliOps(role: string, configPath?: string): OwnerFleetOps;