Files
paseo/packages/protocol/src/messages.ts
T
706ae3d9bb Read Claude subagents from the SDK task protocol (#2498)
* refactor(claude): derive subagents from the SDK task protocol

Claude Code announces subagent identity and lifecycle on the SDK stream
(task_started, task_updated, task_notification). Paseo consumed only
task_notification and reconstructed the rest from sidechain frames, in two
independent derivations that had drifted apart.

Both paths now translate into one small observation vocabulary and fold it
with one function, so identity and status are derived once. The fold is
stateless: the task protocol is edge-triggered and the store's sticky merge
already accumulates.

- Replay links a subagent through the agent-<id>.meta.json sidecar, which
  carries the same Task tool_use id the live stream keys on. The agentId
  text scrape stays as a fallback for sessions recorded without it.
- The sidechain tracker keeps mapping frames to timeline items but no longer
  owns the descriptor when the task protocol is active, detected from the
  session rather than from a version string.
- Adds replay coverage, which did not exist.

Subagent ids are unchanged, so no protocol, store, or client change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(claude): keep non-subagent tasks out of the track, open the child timeline with its prompt

Backgrounded shell commands announce as task_started with a tool_use_id but
task_type local_bash and no subagent_type, so filtering on the id alone put
`sleep 20` in the subagents track. Discriminate on task_type, falling back to
subagent_type for releases that predate it.

task_started also carries the prompt. Emitting it as the child's first timeline
item means the pane no longer opens mid-conversation, and matches replay, where
the sidechain transcript already begins with the prompt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(claude): drop status for tasks that were never declared as subagents

task_notification also fires for backgrounded shell commands and carries a
tool_use_id. Routing status off that id readmitted exactly what the declaration
filter rejected, as a descriptor with a status and no identity — rendered in the
track as a nameless "Loading..." row.

Status now routes only through the task_id map populated at declaration.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(app): name a subagent row after its task, not its type

The descriptor carries the subagent type in title and the task in description.
The client collapsed them and rendered only the type, so every child in a
fan-out read "general-purpose". The task is what tells siblings apart, so it
names the row and the type moves to the muted secondary line, which the track
computed but never drew.

Providers that report no task keep the previous behavior.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(claude): label the parent's Task card from the subagent declaration

A backgrounded Task subagent emits no frames carrying parent_tool_use_id, so
the sidechain tracker never runs for one and never supplies the sub_agent
detail. Its card in the parent transcript rendered as a bare "Task".

The declaration already carries the type and the task, so the card is built
from it. For a foreground subagent the tracker still emits the same card
enriched with the child's action log; the two collapse on the shared tool-call
id, so that case is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(subagents): surface a subagent's model, effort, and cost

Adds model, effort and usage to the provider subagent descriptor, populated
from observations the child itself reports.

- model: read per assistant frame, live and on replay. Never snapshotted, since
  a provider can swap models mid-flight on overload or refusal fallback, and
  never inherited from the parent.
- effort: replay only. The SDK's assistant message does not carry it and it can
  be silently downgraded for the chosen model, so a live value would be a guess.
- usage: task_progress reports tokens and tool count once per tool use, and
  task_notification reports the terminal totals. This matters most for
  backgrounded subagents, which emit no sidechain frames and would otherwise
  show no sign of activity at all.

Status becomes optional on the upsert event: a report that only carries a model
or a cost says nothing about whether the child is still running, and must not
revert a finished one. Usage merges rather than replaces, because duration only
arrives at the end.

Fields are optional on the wire, so an older daemon simply omits them and the
client renders nothing rather than substituting the parent's settings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(claude): read subagent effort from hooks

Effort appears nowhere on the SDK message stream — verified by scanning every
message type at depth — and the level Paseo requests is not necessarily the one
that runs, since a model that does not support it is silently downgraded.

Hooks are the source. Every hook input carries agent_id and effort.level, the
active level for that turn after any downgrade, and agent_id is the same id
task_started calls task_id, so it routes through the table already built at
declaration. PreToolUse, PostToolUse and SubagentStop are registered purely to
observe; they record what they see and always return empty, so they cannot
affect tool execution or turn control.

Paseo's hooks merge with any the user configured rather than replacing them:
extraClaudeOptions is spread after the base options, so assigning would have
silently stopped effort being observed for anyone with their own hooks.

Verified end to end through ClaudeAgentClient against a real session: a
subagent descriptor now carries model, effort and usage together.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* feat(subagents): show a subagent's runtime facts in its pane, and its cost on replay

The track row carried model, effort and cost; the pane carried none of it, so
opening a subagent showed only its task.

The pane gets a header strip rather than a longer tab subtitle: the subtitle
feeds the width-constrained tab strip, whose job is to name the task. Duration
appears in the pane, which has room, and stays out of the dense row.

Replay had no usage source, so a reopened agent lost its subagents' token and
tool counts permanently — descriptors are in-memory and cleared when an agent
closes. Usage is now derived from the child's own transcript, matching the live
producer exactly: total tokens are the four counters summed on the last
assistant turn (a context reading, not a cumulative sum, which would multiply
the cached prefix by the turn count), and tool uses are tool_use blocks across
assistant entries. Duration is an approximation — the transcript's first entry
is written after the task starts — and is the one field replay cannot match.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(claude): record the task protocol's undocumented wire facts

The subagent sources depend on Claude Code internals the SDK types do not
explain: which announced tasks are subagents, why a status for an undeclared
task is dropped, why task ids outlive a turn, why effort is only reachable
through hooks, and why a replayed session must skip its grandchildren.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Generalize provider subagent presentation

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-31 17:22:44 +00:00

5878 lines
199 KiB
TypeScript

import { z } from "zod";
import { TerminalActivitySchema } from "./terminal-activity.js";
import { CLIENT_CAPS } from "./client-capabilities.js";
import { AGENT_LIFECYCLE_STATUSES } from "./agent-lifecycle.js";
import { MAX_EXPLICIT_AGENT_TITLE_CHARS } from "./agent-title-limits.js";
import { AgentProviderSchema } from "./provider-manifest.js";
import { TOOL_CALL_ICON_NAMES } from "./agent-types.js";
import {
ChatCreateRequestSchema,
ChatListRequestSchema,
ChatInspectRequestSchema,
ChatDeleteRequestSchema,
ChatPostRequestSchema,
ChatReadRequestSchema,
ChatWaitRequestSchema,
ChatCreateResponseSchema,
ChatListResponseSchema,
ChatInspectResponseSchema,
ChatDeleteResponseSchema,
ChatPostResponseSchema,
ChatReadResponseSchema,
ChatWaitResponseSchema,
} from "./chat/rpc-schemas.js";
import {
ScheduleCreateRequestSchema,
ScheduleListRequestSchema,
ScheduleInspectRequestSchema,
ScheduleLogsRequestSchema,
SchedulePauseRequestSchema,
ScheduleResumeRequestSchema,
ScheduleDeleteRequestSchema,
ScheduleRunOnceRequestSchema,
ScheduleUpdateRequestSchema,
ScheduleCreateResponseSchema,
ScheduleListResponseSchema,
ScheduleInspectResponseSchema,
ScheduleLogsResponseSchema,
SchedulePauseResponseSchema,
ScheduleResumeResponseSchema,
ScheduleDeleteResponseSchema,
ScheduleRunOnceResponseSchema,
ScheduleUpdateResponseSchema,
} from "./schedule/rpc-schemas.js";
import {
LoopRunRequestSchema,
LoopListRequestSchema,
LoopInspectRequestSchema,
LoopLogsRequestSchema,
LoopStopRequestSchema,
LoopRunResponseSchema,
LoopListResponseSchema,
LoopInspectResponseSchema,
LoopLogsResponseSchema,
LoopStopResponseSchema,
} from "./loop/rpc-schemas.js";
import {
BrowserAutomationExecuteRequestSchema,
BrowserAutomationExecuteResponseSchema,
} from "./browser-automation/rpc-schemas.js";
import { BrowserAutomationHostCapabilitySchema } from "./browser-automation/capabilities.js";
import {
PaseoConfigRawSchema,
PaseoLifecycleCommandRawSchema,
PaseoMetadataGenerationEntrySchema,
PaseoMetadataGenerationSchema,
PaseoScriptEntryRawSchema,
PaseoWorktreeConfigRawSchema,
PaseoConfigRevisionSchema,
ProjectConfigRpcErrorSchema,
type PaseoConfigRaw,
type PaseoConfigRevision,
type PaseoMetadataGeneration,
type PaseoMetadataGenerationEntry,
type PaseoScriptEntryRaw,
type ProjectConfigRpcError,
} from "./paseo-config-schema.js";
export {
PaseoConfigRawSchema,
PaseoLifecycleCommandRawSchema,
PaseoMetadataGenerationEntrySchema,
PaseoMetadataGenerationSchema,
PaseoScriptEntryRawSchema,
PaseoWorktreeConfigRawSchema,
type PaseoConfigRaw,
type PaseoConfigRevision,
type PaseoMetadataGeneration,
type PaseoMetadataGenerationEntry,
type PaseoScriptEntryRaw,
type ProjectConfigRpcError,
};
// ---------------------------------------------------------------------------
// Mutable daemon config schemas (shared between server store and client)
// ---------------------------------------------------------------------------
const MutableDaemonProviderModelSchema = z
.object({
id: z.string().min(1),
label: z.string().min(1),
description: z.string().optional(),
isDefault: z.boolean().optional(),
})
.passthrough();
const MutableDaemonProviderConfigSchema = z
.object({
enabled: z.boolean().optional(),
additionalModels: z.array(MutableDaemonProviderModelSchema).optional(),
})
.passthrough();
const MutableStructuredGenerationProviderSchema = z
.object({
provider: z.string().min(1),
model: z.string().min(1).optional(),
thinkingOptionId: z.string().min(1).optional(),
})
.passthrough();
const MutableMetadataGenerationConfigSchema = z
.object({
providers: z.array(MutableStructuredGenerationProviderSchema).default([]),
})
.passthrough();
export const TerminalProfileSchema = z
.object({
id: z.string(),
name: z.string(),
command: z.string(),
args: z.array(z.string()).optional(),
icon: z.string().optional(),
})
.passthrough();
export type TerminalProfile = z.infer<typeof TerminalProfileSchema>;
const MutableBrowserToolsConfigSchema = z
.object({
enabled: z.boolean().default(false),
})
.passthrough();
export const MutableDaemonConfigSchema = z
.object({
mcp: z
.object({
injectIntoAgents: z.boolean(),
})
.passthrough(),
browserTools: MutableBrowserToolsConfigSchema.default({ enabled: false }),
providers: z.record(z.string(), MutableDaemonProviderConfigSchema).default({}),
metadataGeneration: MutableMetadataGenerationConfigSchema.default({ providers: [] }),
autoArchiveAfterMerge: z.boolean().default(false),
enableTerminalAgentHooks: z.boolean().default(false),
appendSystemPrompt: z.string().default(""),
terminalProfiles: z.array(TerminalProfileSchema).optional(),
})
.passthrough();
export const MutableDaemonConfigPatchSchema = z
.object({
mcp: MutableDaemonConfigSchema.shape.mcp.partial().optional(),
browserTools: MutableBrowserToolsConfigSchema.partial().optional(),
providers: z
.record(z.string(), MutableDaemonProviderConfigSchema.partial().passthrough())
.optional(),
removeProviders: z.array(z.string().min(1)).optional(),
metadataGeneration: MutableMetadataGenerationConfigSchema.partial().optional(),
autoArchiveAfterMerge: z.boolean().optional(),
enableTerminalAgentHooks: z.boolean().optional(),
appendSystemPrompt: z.string().optional(),
terminalProfiles: z.array(TerminalProfileSchema).optional(),
})
.partial()
.passthrough();
export type MutableDaemonConfig = z.infer<typeof MutableDaemonConfigSchema>;
export type MutableDaemonConfigPatch = z.infer<typeof MutableDaemonConfigPatchSchema>;
import type {
AgentCapabilityFlags,
AgentModelDefinition,
AgentMode,
AgentPermissionRequest,
AgentPermissionResponse,
AgentPersistenceHandle,
ProviderStatus,
AgentRuntimeInfo,
AgentTimelineItem,
AgentProviderNotice,
ToolCallDetail,
ToolCallTimelineItem,
AgentUsage,
} from "./agent-types.js";
export const AgentStatusSchema = z.enum(AGENT_LIFECYCLE_STATUSES);
const AgentModeSchema: z.ZodType<AgentMode> = z.object({
id: z.string(),
label: z.string(),
description: z.string().optional(),
icon: z.string().optional(),
colorTier: z.string().optional(),
});
const ProviderStatusSchema: z.ZodType<ProviderStatus> = z.enum([
"ready",
"loading",
"error",
"unavailable",
]);
const AgentSelectOptionSchema = z.object({
id: z.string(),
label: z.string(),
description: z.string().optional(),
isDefault: z.boolean().optional(),
metadata: z.record(z.string(), z.unknown()).optional(),
});
const AgentProviderNoticeSchema: z.ZodType<AgentProviderNotice> = z.discriminatedUnion("type", [
z.object({ type: z.literal("info"), message: z.string() }),
z.object({ type: z.literal("warning"), message: z.string() }),
z.object({ type: z.literal("error"), message: z.string() }),
]);
export const AgentFeatureToggleSchema = z.object({
type: z.literal("toggle"),
id: z.string(),
label: z.string(),
description: z.string().optional(),
tooltip: z.string().optional(),
icon: z.string().optional(),
value: z.boolean(),
});
export const AgentFeatureSelectSchema = z.object({
type: z.literal("select"),
id: z.string(),
label: z.string(),
description: z.string().optional(),
tooltip: z.string().optional(),
icon: z.string().optional(),
value: z.string().nullable(),
options: z.array(AgentSelectOptionSchema),
});
export const AgentFeatureSchema = z.discriminatedUnion("type", [
AgentFeatureToggleSchema,
AgentFeatureSelectSchema,
]);
const AgentModelDefinitionSchema: z.ZodType<AgentModelDefinition> = z.object({
provider: AgentProviderSchema,
id: z.string(),
label: z.string(),
description: z.string().optional(),
isDefault: z.boolean().optional(),
metadata: z.record(z.string(), z.unknown()).optional(),
contextWindowMaxTokens: z.number().optional(),
thinkingOptions: z.array(AgentSelectOptionSchema).optional(),
defaultThinkingOptionId: z.string().optional(),
});
export const ProviderSnapshotEntrySchema = z.object({
provider: AgentProviderSchema,
status: ProviderStatusSchema,
enabled: z.boolean().optional().default(true),
source: z.enum(["builtin", "custom"]).optional(),
error: z.string().optional(),
models: z.array(AgentModelDefinitionSchema).optional(),
modes: z.array(AgentModeSchema).optional(),
fetchedAt: z.string().optional(),
label: z.string().optional(),
description: z.string().optional(),
defaultModeId: z.string().nullable().optional(),
});
const AgentCapabilityFlagsSchema: z.ZodType<AgentCapabilityFlags> = z
.object({
supportsStreaming: z.boolean(),
supportsSessionPersistence: z.boolean(),
supportsSessionListing: z.boolean().optional(),
supportsDynamicModes: z.boolean(),
supportsMcpServers: z.boolean(),
supportsReasoningStream: z.boolean(),
supportsToolInvocations: z.boolean(),
// COMPAT(rewind): added in v0.1.X, drop when floor >= v0.1.X.
supportsRewindConversation: z.boolean().optional().default(false),
// COMPAT(rewind): added in v0.1.X, drop when floor >= v0.1.X.
supportsRewindFiles: z.boolean().optional().default(false),
// COMPAT(rewind): added in v0.1.X, drop when floor >= v0.1.X.
supportsRewindBoth: z.boolean().optional().default(false),
})
.catchall(z.boolean());
const AgentUsageSchema: z.ZodType<AgentUsage> = z.object({
inputTokens: z.number().optional(),
cachedInputTokens: z.number().optional(),
outputTokens: z.number().optional(),
totalCostUsd: z.number().optional(),
contextWindowMaxTokens: z.number().optional(),
contextWindowUsedTokens: z.number().optional(),
});
const McpStdioServerConfigSchema = z.object({
type: z.literal("stdio"),
command: z.string(),
args: z.array(z.string()).optional(),
env: z.record(z.string(), z.string()).optional(),
alwaysLoad: z.boolean().optional(),
});
const McpHttpServerConfigSchema = z.object({
type: z.literal("http"),
url: z.string(),
headers: z.record(z.string(), z.string()).optional(),
alwaysLoad: z.boolean().optional(),
});
const McpSseServerConfigSchema = z.object({
type: z.literal("sse"),
url: z.string(),
headers: z.record(z.string(), z.string()).optional(),
alwaysLoad: z.boolean().optional(),
});
const McpServerConfigSchema = z.discriminatedUnion("type", [
McpStdioServerConfigSchema,
McpHttpServerConfigSchema,
McpSseServerConfigSchema,
]);
const AgentSessionConfigSchema = z.object({
provider: AgentProviderSchema,
cwd: z.string(),
modeId: z.string().optional(),
model: z.string().optional(),
thinkingOptionId: z.string().optional(),
featureValues: z.record(z.string(), z.unknown()).optional(),
title: z.string().trim().min(1).max(MAX_EXPLICIT_AGENT_TITLE_CHARS).optional().nullable(),
approvalPolicy: z.string().optional(),
sandboxMode: z.string().optional(),
networkAccess: z.boolean().optional(),
webSearch: z.boolean().optional(),
extra: z
.object({
codex: z.record(z.string(), z.unknown()).optional(),
claude: z.record(z.string(), z.unknown()).optional(),
})
.partial()
.optional(),
systemPrompt: z.string().optional(),
mcpServers: z.record(z.string(), McpServerConfigSchema).optional(),
});
const AgentPermissionUpdateSchema = z.record(z.string(), z.unknown());
const AgentPermissionActionSchema = z.object({
id: z.string(),
label: z.string(),
behavior: z.enum(["allow", "deny"]),
variant: z.enum(["primary", "secondary", "danger"]).optional(),
intent: z.enum(["implement", "implement_resume", "dismiss"]).optional(),
});
export const AgentPermissionResponseSchema: z.ZodType<AgentPermissionResponse> =
z.discriminatedUnion("behavior", [
z.object({
behavior: z.literal("allow"),
selectedActionId: z.string().optional(),
updatedInput: z.record(z.string(), z.unknown()).optional(),
updatedPermissions: z.array(AgentPermissionUpdateSchema).optional(),
}),
z.object({
behavior: z.literal("deny"),
selectedActionId: z.string().optional(),
message: z.string().optional(),
interrupt: z.boolean().optional(),
}),
]);
export const AgentPermissionRequestPayloadSchema: z.ZodType<AgentPermissionRequest, unknown> =
z.object({
id: z.string(),
provider: AgentProviderSchema,
name: z.string(),
kind: z.enum(["tool", "plan", "question", "mode", "other"]),
title: z.string().optional(),
description: z.string().optional(),
input: z.record(z.string(), z.unknown()).optional(),
detail: z.lazy(() => ToolCallDetailPayloadSchema).optional(),
suggestions: z.array(AgentPermissionUpdateSchema).optional(),
actions: z.array(AgentPermissionActionSchema).optional(),
metadata: z.record(z.string(), z.unknown()).optional(),
});
const UnknownValueSchema = z.union([
z.null(),
z.boolean(),
z.number(),
z.string(),
z.array(z.unknown()),
z.object({}).passthrough(),
]);
const NonNullUnknownSchema = z.union([
z.boolean(),
z.number(),
z.string(),
z.array(z.unknown()),
z.object({}).passthrough(),
]);
const WorktreeSetupCommandSnapshotSchema = z.object({
index: z.number().int().positive(),
command: z.string(),
cwd: z.string(),
log: z.string().optional().default(""),
status: z.enum(["running", "completed", "failed"]),
exitCode: z.number().nullable(),
durationMs: z.number().nonnegative().optional(),
});
const WorktreeSetupDetailPayloadSchema = z.object({
type: z.literal("worktree_setup"),
worktreePath: z.string(),
branchName: z.string(),
log: z.string(),
commands: z.array(WorktreeSetupCommandSnapshotSchema),
truncated: z.boolean().optional(),
});
const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail, unknown> = z.discriminatedUnion(
"type",
[
WorktreeSetupDetailPayloadSchema,
z.object({
type: z.literal("shell"),
command: z.string(),
cwd: z.string().optional(),
output: z.string().optional(),
exitCode: z.number().nullable().optional(),
}),
z.object({
type: z.literal("read"),
filePath: z.string(),
content: z.string().optional(),
offset: z.number().optional(),
limit: z.number().optional(),
}),
z.object({
type: z.literal("edit"),
filePath: z.string(),
oldString: z.string().optional(),
newString: z.string().optional(),
unifiedDiff: z.string().optional(),
}),
z.object({
type: z.literal("write"),
filePath: z.string(),
content: z.string().optional(),
}),
z.object({
type: z.literal("search"),
query: z.string(),
toolName: z.enum(["search", "grep", "glob", "web_search"]).optional(),
content: z.string().optional(),
filePaths: z.array(z.string()).optional(),
webResults: z
.array(
z.object({
title: z.string(),
url: z.string(),
}),
)
.optional(),
annotations: z.array(z.string()).optional(),
numFiles: z.number().optional(),
numMatches: z.number().optional(),
durationMs: z.number().optional(),
durationSeconds: z.number().optional(),
truncated: z.boolean().optional(),
mode: z.enum(["content", "files_with_matches", "count"]).optional(),
}),
z.object({
type: z.literal("fetch"),
url: z.string(),
prompt: z.string().optional(),
result: z.string().optional(),
code: z.number().optional(),
codeText: z.string().optional(),
bytes: z.number().optional(),
durationMs: z.number().optional(),
}),
z.object({
type: z.literal("sub_agent"),
subAgentType: z.string().optional(),
description: z.string().optional(),
childSessionId: z.string().optional(),
log: z.string(),
// Compat cruft for clients <= 0.1.65-beta.3 that required this field. Producers still
// emit `[]`; nothing reads it. Drop the field (and the `[]` emissions) once those
// clients are no longer in the field.
actions: z
.array(
z.object({
index: z.number().int().positive(),
toolName: z.string(),
summary: z.string().optional(),
}),
)
.optional(),
}),
z.object({
type: z.literal("plain_text"),
label: z.string().optional(),
text: z.string().optional(),
icon: z.enum(TOOL_CALL_ICON_NAMES).optional(),
}),
z.object({
type: z.literal("plan"),
text: z.string(),
}),
z.object({
type: z.literal("unknown"),
input: UnknownValueSchema,
output: UnknownValueSchema,
}),
],
);
const ToolCallBasePayloadSchema = z.object({
type: z.literal("tool_call"),
callId: z.string(),
name: z.string(),
detail: ToolCallDetailPayloadSchema,
metadata: z.record(z.string(), z.unknown()).optional(),
});
const ToolCallRunningPayloadSchema = ToolCallBasePayloadSchema.extend({
status: z.literal("running"),
error: z.null(),
});
const ToolCallCompletedPayloadSchema = ToolCallBasePayloadSchema.extend({
status: z.literal("completed"),
error: z.null(),
});
const ToolCallFailedPayloadSchema = ToolCallBasePayloadSchema.extend({
status: z.literal("failed"),
error: NonNullUnknownSchema,
});
const ToolCallCanceledPayloadSchema = ToolCallBasePayloadSchema.extend({
status: z.literal("canceled"),
error: z.null(),
});
const ToolCallTimelineItemPayloadSchema: z.ZodType<ToolCallTimelineItem, unknown> =
z.discriminatedUnion("status", [
ToolCallRunningPayloadSchema,
ToolCallCompletedPayloadSchema,
ToolCallFailedPayloadSchema,
ToolCallCanceledPayloadSchema,
]);
// zod-aot 0.20.4 miscompiles this as a nested discriminated union by omitting
// the inner tool_call branch from the generated outer dispatch.
export const AgentTimelineItemPayloadSchema: z.ZodType<AgentTimelineItem, unknown> = z.union([
z.object({
type: z.literal("user_message"),
text: z.string(),
messageId: z.string().optional(),
clientMessageId: z.string().optional(),
}),
z.object({
type: z.literal("assistant_message"),
text: z.string(),
messageId: z.string().optional(),
}),
z.object({
type: z.literal("reasoning"),
text: z.string(),
}),
ToolCallTimelineItemPayloadSchema,
z.object({
type: z.literal("todo"),
items: z.array(
z.object({
text: z.string(),
completed: z.boolean(),
}),
),
}),
z.object({
type: z.literal("error"),
message: z.string(),
}),
z.object({
type: z.literal("compaction"),
status: z.enum(["loading", "completed"]),
trigger: z.enum(["auto", "manual"]).optional(),
preTokens: z.number().optional(),
}),
]);
export const AgentStreamEventPayloadSchema = z.discriminatedUnion("type", [
z.object({
type: z.literal("thread_started"),
sessionId: z.string(),
provider: AgentProviderSchema,
}),
z.object({
type: z.literal("turn_started"),
provider: AgentProviderSchema,
}),
z.object({
type: z.literal("turn_completed"),
provider: AgentProviderSchema,
usage: AgentUsageSchema.optional(),
}),
z.object({
type: z.literal("turn_failed"),
provider: AgentProviderSchema,
error: z.string(),
code: z.string().optional(),
diagnostic: z.string().optional(),
}),
z.object({
type: z.literal("turn_canceled"),
provider: AgentProviderSchema,
reason: z.string(),
}),
z.object({
type: z.literal("timeline"),
provider: AgentProviderSchema,
item: AgentTimelineItemPayloadSchema,
}),
z.object({
type: z.literal("permission_requested"),
provider: AgentProviderSchema,
request: AgentPermissionRequestPayloadSchema,
}),
z.object({
type: z.literal("permission_resolved"),
provider: AgentProviderSchema,
requestId: z.string(),
resolution: AgentPermissionResponseSchema,
}),
z.object({
type: z.literal("attention_required"),
provider: AgentProviderSchema,
reason: z.enum(["finished", "error", "permission"]),
timestamp: z.string(),
shouldNotify: z.boolean(),
notification: z
.object({
title: z.string(),
body: z.string(),
data: z.object({
serverId: z.string(),
workspaceId: z.string().optional(),
agentId: z.string(),
reason: z.enum(["finished", "error", "permission"]),
}),
})
.optional(),
}),
]);
const AgentPersistenceHandleSchema: z.ZodType<AgentPersistenceHandle | null> = z
.object({
provider: AgentProviderSchema,
sessionId: z.string(),
nativeHandle: z.string().optional(),
metadata: z.record(z.string(), z.unknown()).optional(),
})
.nullable();
const AgentRuntimeInfoSchema: z.ZodType<AgentRuntimeInfo> = z.object({
provider: AgentProviderSchema,
sessionId: z.string().nullable(),
model: z.string().nullable().optional(),
thinkingOptionId: z.string().nullable().optional(),
modeId: z.string().nullable().optional(),
extra: z.record(z.string(), z.unknown()).optional(),
});
export const AgentSnapshotPayloadSchema = z.object({
id: z.string(),
provider: AgentProviderSchema,
cwd: z.string(),
workspaceId: z.string().optional(),
model: z.string().nullable(),
features: z.array(AgentFeatureSchema).optional(),
thinkingOptionId: z.string().nullable().optional(),
effectiveThinkingOptionId: z.string().nullable().optional(),
createdAt: z.string(),
updatedAt: z.string(),
lastUserMessageAt: z.string().nullable(),
status: AgentStatusSchema,
capabilities: AgentCapabilityFlagsSchema,
currentModeId: z.string().nullable(),
availableModes: z.array(AgentModeSchema),
pendingPermissions: z.array(AgentPermissionRequestPayloadSchema),
persistence: AgentPersistenceHandleSchema.nullable(),
runtimeInfo: AgentRuntimeInfoSchema.optional(),
lastUsage: AgentUsageSchema.optional(),
lastError: z.string().optional(),
title: z.string().nullable(),
labels: z.record(z.string(), z.string()).default({}),
requiresAttention: z.boolean().optional(),
attentionReason: z.enum(["finished", "error", "permission"]).nullable().optional(),
attentionTimestamp: z.string().nullable().optional(),
archivedAt: z.string().nullable().optional(),
providerUnavailable: z.boolean().optional(),
});
export type AgentSnapshotPayload = z.infer<typeof AgentSnapshotPayloadSchema>;
export const AgentListItemPayloadSchema = z.object({
id: z.string(),
shortId: z.string(),
title: z.string().nullable(),
provider: AgentProviderSchema,
model: z.string().nullable(),
thinkingOptionId: z.string().nullable().optional(),
effectiveThinkingOptionId: z.string().nullable().optional(),
status: AgentStatusSchema,
cwd: z.string(),
createdAt: z.string(),
updatedAt: z.string(),
lastUserMessageAt: z.string().nullable(),
archivedAt: z.string().nullable().optional(),
requiresAttention: z.boolean().optional(),
attentionReason: z.enum(["finished", "error", "permission"]).nullable().optional(),
attentionTimestamp: z.string().nullable().optional(),
labels: z.record(z.string(), z.string()).default({}),
providerUnavailable: z.boolean().optional(),
});
export type AgentListItemPayload = z.infer<typeof AgentListItemPayloadSchema>;
export type AgentStreamEventPayload = z.infer<typeof AgentStreamEventPayloadSchema>;
export const RecentProviderSessionDescriptorPayloadSchema = z.object({
providerId: z.string(),
providerLabel: z.string(),
providerHandleId: z.string(),
cwd: z.string(),
title: z.string().nullable(),
firstPromptPreview: z.string().nullable(),
lastPromptPreview: z.string().nullable(),
lastActivityAt: z.string(),
});
export type RecentProviderSessionDescriptorPayload = z.infer<
typeof RecentProviderSessionDescriptorPayloadSchema
>;
// ============================================================================
// Session Inbound Messages (Session receives these)
// ============================================================================
export const VoiceAudioChunkMessageSchema = z.object({
type: z.literal("voice_audio_chunk"),
audio: z.string(), // base64 encoded
format: z.string(),
isLast: z.boolean(),
});
export const AbortRequestMessageSchema = z.object({
type: z.literal("abort_request"),
});
export const AudioPlayedMessageSchema = z.object({
type: z.literal("audio_played"),
id: z.string(),
});
const AgentDirectoryFilterSchema = z.object({
labels: z.record(z.string(), z.string()).optional(),
projectKeys: z.array(z.string()).optional(),
statuses: z.array(AgentStatusSchema).optional(),
includeArchived: z.boolean().optional(),
requiresAttention: z.boolean().optional(),
thinkingOptionId: z.string().nullable().optional(),
});
export const DeleteAgentRequestMessageSchema = z.object({
type: z.literal("delete_agent_request"),
agentId: z.string(),
requestId: z.string(),
});
export const ArchiveAgentRequestMessageSchema = z.object({
type: z.literal("archive_agent_request"),
agentId: z.string(),
requestId: z.string(),
});
export const CloseItemsRequestMessageSchema = z.object({
type: z.literal("close_items_request"),
agentIds: z.array(z.string()).default([]),
terminalIds: z.array(z.string()).default([]),
requestId: z.string(),
});
export const UpdateAgentRequestMessageSchema = z.object({
type: z.literal("update_agent_request"),
agentId: z.string(),
name: z.string().optional(),
labels: z.record(z.string(), z.string()).optional(),
requestId: z.string(),
});
export const ProjectRenameRequestSchema = z.object({
type: z.literal("project.rename.request"),
projectId: z.string(),
// Null or empty string clears the override and reverts to the derived name.
customName: z.string().nullable(),
requestId: z.string(),
});
export const ProjectRemoveRequestSchema = z.object({
type: z.literal("project.remove.request"),
projectId: z.string(),
requestId: z.string(),
});
export const WorkspaceTitleSetRequestSchema = z.object({
type: z.literal("workspace.title.set.request"),
workspaceId: z.string(),
// Null or empty string clears the title and reverts to the derived name.
title: z.string().nullable(),
requestId: z.string(),
});
export const WorkspacePinSetRequestSchema = z.object({
type: z.literal("workspace.pin.set.request"),
workspaceId: z.string(),
pinned: z.boolean(),
requestId: z.string(),
});
export const WorkspaceRecoveryInspectRequestSchema = z.object({
type: z.literal("workspace.recovery.inspect.request"),
workspaceId: z.string(),
requestId: z.string(),
});
export const WorkspaceRecoveryRestoreRequestSchema = z.object({
type: z.literal("workspace.recovery.restore.request"),
workspaceId: z.string(),
requestId: z.string(),
});
export const SetVoiceModeMessageSchema = z.object({
type: z.literal("set_voice_mode"),
enabled: z.boolean(),
agentId: z.string().optional(),
requestId: z.string().optional(),
});
export const GitHubPrAttachmentSchema = z.object({
type: z.literal("github_pr"),
mimeType: z.literal("application/github-pr"),
number: z.number().int().positive(),
title: z.string(),
url: z.string(),
body: z.string().nullable().optional(),
baseRefName: z.string().nullable().optional(),
headRefName: z.string().nullable().optional(),
});
export const ForgeChangeRequestAttachmentSchema = z.object({
type: z.literal("forge_change_request"),
mimeType: z.literal("application/paseo-forge-change-request"),
forge: z.string().optional().default("github"),
number: z.number().int().positive(),
title: z.string(),
url: z.string(),
body: z.string().nullable().optional(),
projectPath: z.string().optional(),
baseRefName: z.string().nullable().optional(),
headRefName: z.string().nullable().optional(),
});
export const GitHubIssueAttachmentSchema = z.object({
type: z.literal("github_issue"),
mimeType: z.literal("application/github-issue"),
number: z.number().int().positive(),
title: z.string(),
url: z.string(),
body: z.string().nullable().optional(),
});
export const ForgeIssueAttachmentSchema = z.object({
type: z.literal("forge_issue"),
mimeType: z.literal("application/paseo-forge-issue"),
forge: z.string().optional().default("github"),
number: z.number().int().positive(),
title: z.string(),
url: z.string(),
body: z.string().nullable().optional(),
projectPath: z.string().optional(),
});
export const TextAttachmentSchema = z
.object({
type: z.literal("text"),
mimeType: z.literal("text/plain"),
contextKind: z.string().optional(),
title: z.string().nullable().optional(),
text: z.string(),
})
.transform(({ contextKind, ...attachment }) => ({
...attachment,
...(contextKind === "chat_history" ? { contextKind } : {}),
}));
export const ReviewAttachmentContextLineSchema = z.object({
oldLineNumber: z.number().int().positive().nullable(),
newLineNumber: z.number().int().positive().nullable(),
type: z.enum(["add", "remove", "context"]),
content: z.string(),
});
export const ReviewAttachmentCommentSchema = z.object({
filePath: z.string(),
side: z.enum(["old", "new"]),
lineNumber: z.number().int().positive(),
body: z.string(),
context: z.object({
hunkHeader: z.string(),
targetLine: ReviewAttachmentContextLineSchema,
lines: z.array(ReviewAttachmentContextLineSchema),
}),
});
export const ReviewAttachmentSchema = z.object({
type: z.literal("review"),
mimeType: z.literal("application/paseo-review"),
cwd: z.string(),
mode: z.enum(["uncommitted", "base"]),
baseRef: z.string().nullable().optional(),
comments: z.array(ReviewAttachmentCommentSchema),
});
export const UploadedFileAttachmentSchema = z.object({
type: z.literal("uploaded_file"),
id: z.string(),
fileName: z.string(),
mimeType: z.string(),
size: z.number().int().nonnegative(),
path: z.string(),
});
export const AgentAttachmentSchema = z.discriminatedUnion("type", [
ForgeChangeRequestAttachmentSchema,
ForgeIssueAttachmentSchema,
GitHubPrAttachmentSchema,
GitHubIssueAttachmentSchema,
TextAttachmentSchema,
ReviewAttachmentSchema,
UploadedFileAttachmentSchema,
]);
function normalizeAgentAttachments(input: unknown): AgentAttachment[] {
if (!Array.isArray(input)) {
return [];
}
const normalized: AgentAttachment[] = [];
for (const item of input) {
const parsed = AgentAttachmentSchema.safeParse(item);
if (parsed.success) {
normalized.push(parsed.data);
}
}
return normalized;
}
const AgentAttachmentsSchema = z.unknown().transform(normalizeAgentAttachments).optional();
export const ChangeRequestCheckoutSourceSchema = z.object({
kind: z.literal("change_request"),
forge: z.string().optional(),
number: z.number().int().positive(),
projectPath: z.string().optional(),
});
const ImageAttachmentSchema = z.object({
data: z.string(), // base64 encoded image
mimeType: z.string(), // e.g., "image/jpeg", "image/png"
});
export const SendAgentMessageSchema = z.object({
type: z.literal("send_agent_message"),
agentId: z.string(),
text: z.string(),
messageId: z.string().optional(), // Client-provided ID for deduplication
images: z.array(ImageAttachmentSchema).optional(),
attachments: AgentAttachmentsSchema,
});
// ============================================================================
// Agent RPCs (requestId-correlated)
// ============================================================================
export const FetchAgentsRequestMessageSchema = z.object({
type: z.literal("fetch_agents_request"),
requestId: z.string(),
scope: z.enum(["active"]).optional(),
filter: AgentDirectoryFilterSchema.optional(),
sort: z
.array(
z.object({
key: z.enum(["status_priority", "created_at", "updated_at", "title"]),
direction: z.enum(["asc", "desc"]),
}),
)
.optional(),
page: z
.object({
limit: z.number().int().positive().max(200),
cursor: z.string().min(1).optional(),
})
.optional(),
subscribe: z
.object({
subscriptionId: z.string().optional(),
})
.optional(),
});
const WorkspaceStateBucketSchema = z.enum([
"needs_input",
"failed",
"running",
"attention",
"done",
]);
export const FetchWorkspacesRequestMessageSchema = z.object({
type: z.literal("fetch_workspaces_request"),
requestId: z.string(),
filter: z
.object({
query: z.string().optional(),
projectId: z.string().optional(),
// Unused: accepted so older clients still parse, but the server does not filter on it.
idPrefix: z.string().optional(),
})
.optional(),
sort: z
.array(
z.object({
key: z.enum(["status_priority", "activity_at", "name", "project_id"]),
direction: z.enum(["asc", "desc"]),
}),
)
.optional(),
page: z
.object({
limit: z.number().int().positive().max(200),
cursor: z.string().min(1).optional(),
})
.optional(),
subscribe: z
.object({
subscriptionId: z.string().optional(),
})
.optional(),
});
export const ProjectListRequestMessageSchema = z.object({
type: z.literal("project.list.request"),
requestId: z.string(),
});
export const FetchAgentHistoryRequestMessageSchema = z.object({
type: z.literal("fetch_agent_history_request"),
requestId: z.string(),
filter: AgentDirectoryFilterSchema.optional(),
sort: z
.array(
z.object({
key: z.enum(["status_priority", "created_at", "updated_at", "title"]),
direction: z.enum(["asc", "desc"]),
}),
)
.optional(),
page: z
.object({
limit: z.number().int().positive().max(200),
cursor: z.string().min(1).optional(),
})
.optional(),
});
export const FetchRecentProviderSessionsRequestMessageSchema = z.object({
type: z.literal("fetch_recent_provider_sessions_request"),
requestId: z.string(),
cwd: z.string().optional(),
providers: z.array(z.string()).optional(),
since: z.string().optional(),
limit: z.number().int().positive().max(200).optional(),
});
export const FetchAgentRequestMessageSchema = z.object({
type: z.literal("fetch_agent_request"),
requestId: z.string(),
/** Accepts full ID, unique prefix, or exact full title (server resolves). */
agentId: z.string(),
});
export const SendAgentMessageRequestSchema = z.object({
type: z.literal("send_agent_message_request"),
requestId: z.string(),
/** Accepts full ID, unique prefix, or exact full title (server resolves). */
agentId: z.string(),
text: z.string(),
messageId: z.string().optional(), // Client-provided ID for deduplication
images: z.array(ImageAttachmentSchema).optional(),
attachments: AgentAttachmentsSchema,
});
export const WaitForFinishRequestSchema = z.object({
type: z.literal("wait_for_finish_request"),
requestId: z.string(),
/** Accepts full ID, unique prefix, or exact full title (server resolves). */
agentId: z.string(),
timeoutMs: z.number().int().positive().optional(),
});
export const DaemonGetStatusRequestSchema = z.object({
type: z.literal("daemon.get_status.request"),
requestId: z.string(),
});
export const DaemonGetPairingOfferRequestSchema = z.object({
type: z.literal("daemon.get_pairing_offer.request"),
requestId: z.string(),
});
export const HubManagementDaemonConnectRequestSchema = z.object({
type: z.literal("hub.management.daemon.connect.request"),
requestId: z.string(),
hubUrl: z.string(),
token: z.string(),
});
export const HubManagementDaemonGetStatusRequestSchema = z.object({
type: z.literal("hub.management.daemon.get_status.request"),
requestId: z.string(),
});
export const HubManagementDaemonDisconnectRequestSchema = z.object({
type: z.literal("hub.management.daemon.disconnect.request"),
requestId: z.string(),
force: z.boolean().optional(),
});
export const DiagnosticsRequestSchema = z.object({
type: z.literal("diagnostics.request"),
requestId: z.string(),
});
export const GetDaemonConfigRequestMessageSchema = z.object({
type: z.literal("get_daemon_config_request"),
requestId: z.string(),
});
export const SetDaemonConfigRequestMessageSchema = z.object({
type: z.literal("set_daemon_config_request"),
requestId: z.string(),
config: MutableDaemonConfigPatchSchema,
});
export const ReadProjectConfigRequestMessageSchema = z.object({
type: z.literal("read_project_config_request"),
requestId: z.string(),
repoRoot: z.string(),
});
export const WriteProjectConfigRequestMessageSchema = z.object({
type: z.literal("write_project_config_request"),
requestId: z.string(),
repoRoot: z.string(),
config: PaseoConfigRawSchema,
expectedRevision: PaseoConfigRevisionSchema.nullable(),
});
// ============================================================================
// Dictation Streaming (lossless, resumable)
// ============================================================================
export const DictationStreamStartMessageSchema = z.object({
type: z.literal("dictation_stream_start"),
dictationId: z.string(),
format: z.string(), // e.g. "audio/pcm;rate=16000;bits=16"
});
export const DictationStreamChunkMessageSchema = z.object({
type: z.literal("dictation_stream_chunk"),
dictationId: z.string(),
seq: z.number().int().nonnegative(),
audio: z.string(), // base64 encoded chunk
format: z.string(), // e.g. "audio/pcm;rate=16000;bits=16"
});
export const DictationStreamFinishMessageSchema = z.object({
type: z.literal("dictation_stream_finish"),
dictationId: z.string(),
finalSeq: z.number().int().nonnegative(),
});
export const DictationStreamCancelMessageSchema = z.object({
type: z.literal("dictation_stream_cancel"),
dictationId: z.string(),
});
const GitSetupOptionsSchema = z.object({
baseBranch: z.string().optional(),
createNewBranch: z.boolean().optional(),
newBranchName: z.string().optional(),
createWorktree: z.boolean().optional(),
worktreeSlug: z.string().optional(),
refName: z.string().min(1).optional(),
action: z.enum(["branch-off", "checkout"]).optional(),
checkoutSource: ChangeRequestCheckoutSourceSchema.optional(),
// COMPAT(githubPrNumber): added in v0.1.106, remove after 2026-12-28 once
// clients send checkoutSource.
githubPrNumber: z.number().int().positive().optional(),
});
export type GitSetupOptions = z.infer<typeof GitSetupOptionsSchema>;
export const CreateAgentWorktreeTargetSchema = z.discriminatedUnion("mode", [
z.object({
mode: z.literal("branch-off"),
newBranch: z.string().min(1),
base: z.string().min(1).optional(),
}),
z.object({
mode: z.literal("checkout-branch"),
branch: z.string().min(1),
}),
z.object({
mode: z.literal("checkout-pr"),
prNumber: z.number().int().positive(),
}),
]);
export type CreateAgentWorktreeTarget = z.infer<typeof CreateAgentWorktreeTargetSchema>;
export const CreateAgentRequestMessageSchema = z.object({
type: z.literal("create_agent_request"),
config: AgentSessionConfigSchema,
env: z.record(z.string(), z.string()).optional(),
workspaceId: z.string().optional(),
// Optional caller context lets managed CLI invocations use the same daemon-owned
// workspace and parentage policy as agent-scoped MCP creation.
callerAgentId: z.string().optional(),
worktreeName: z.string().optional(),
initialPrompt: z.string().optional(),
clientMessageId: z.string().optional(),
outputSchema: z.record(z.string(), z.unknown()).optional(),
images: z.array(ImageAttachmentSchema).optional(),
attachments: AgentAttachmentsSchema,
git: GitSetupOptionsSchema.optional(),
worktree: CreateAgentWorktreeTargetSchema.optional(),
autoArchive: z.boolean().optional(),
labels: z.record(z.string(), z.string()).default({}),
requestId: z.string(),
});
export const ListProviderModelsRequestMessageSchema = z.object({
type: z.literal("list_provider_models_request"),
provider: AgentProviderSchema,
cwd: z.string().optional(),
requestId: z.string(),
});
export const ListProviderModesRequestMessageSchema = z.object({
type: z.literal("list_provider_modes_request"),
provider: AgentProviderSchema,
cwd: z.string().optional(),
requestId: z.string(),
});
export const ListAvailableProvidersRequestMessageSchema = z.object({
type: z.literal("list_available_providers_request"),
requestId: z.string(),
});
export const GetProvidersSnapshotRequestMessageSchema = z.object({
type: z.literal("get_providers_snapshot_request"),
cwd: z.string().optional(),
requestId: z.string(),
});
export const RefreshProvidersSnapshotRequestMessageSchema = z.object({
type: z.literal("refresh_providers_snapshot_request"),
cwd: z.string().optional(),
providers: z.array(AgentProviderSchema).optional(),
requestId: z.string(),
});
export const ProviderDiagnosticRequestMessageSchema = z.object({
type: z.literal("provider_diagnostic_request"),
provider: AgentProviderSchema,
requestId: z.string(),
});
export const ProviderUsageListRequestMessageSchema = z.object({
type: z.literal("provider.usage.list.request"),
requestId: z.string(),
});
export const ResumeAgentRequestMessageSchema = z.object({
type: z.literal("resume_agent_request"),
handle: AgentPersistenceHandleSchema,
overrides: AgentSessionConfigSchema.partial().optional(),
requestId: z.string(),
});
export const ImportAgentRequestMessageSchema = z.object({
type: z.literal("import_agent_request"),
provider: AgentProviderSchema.optional(),
providerId: z.string().optional(),
sessionId: z.string().optional(),
providerHandleId: z.string().optional(),
cwd: z.string().optional(),
workspaceId: z.string().optional(),
labels: z.record(z.string(), z.string()).optional(),
requestId: z.string(),
});
export const RefreshAgentRequestMessageSchema = z.object({
type: z.literal("refresh_agent_request"),
agentId: z.string(),
requestId: z.string(),
});
export const CancelAgentRequestMessageSchema = z.object({
type: z.literal("cancel_agent_request"),
agentId: z.string(),
requestId: z.string().optional(),
});
export const RestartServerRequestMessageSchema = z.object({
type: z.literal("restart_server_request"),
reason: z.string().optional(),
requestId: z.string(),
});
export const ShutdownServerRequestMessageSchema = z.object({
type: z.literal("shutdown_server_request"),
requestId: z.string(),
});
export const DaemonUpdateRequestMessageSchema = z.object({
type: z.literal("daemon.update.request"),
requestId: z.string(),
});
export const AgentTimelineCursorSchema = z.object({
epoch: z.string(),
seq: z.number().int().nonnegative(),
});
export const FetchAgentTimelineRequestMessageSchema = z.object({
type: z.literal("fetch_agent_timeline_request"),
agentId: z.string(),
requestId: z.string(),
direction: z.enum(["tail", "before", "after"]).optional(),
cursor: AgentTimelineCursorSchema.optional(),
// 0 means "all matching rows for this query window".
limit: z.number().int().nonnegative().optional(),
// Default should be projected for app timeline loading.
projection: z.enum(["projected", "canonical"]).optional(),
});
export const ProviderSubagentListRequestMessageSchema = z.object({
type: z.literal("agent.provider_subagents.list.request"),
parentAgentId: z.string(),
requestId: z.string(),
});
export const ProviderSubagentTimelineRequestMessageSchema = z.object({
type: z.literal("agent.provider_subagents.timeline.get.request"),
parentAgentId: z.string(),
subagentId: z.string(),
requestId: z.string(),
direction: z.enum(["tail", "before", "after"]).optional(),
cursor: AgentTimelineCursorSchema.optional(),
limit: z.number().int().nonnegative().optional(),
});
export const SetAgentTimelineSubscriptionRequestMessageSchema = z.object({
type: z.literal("agent.timeline.set_subscription.request"),
agentIds: z.array(z.string()),
requestId: z.string(),
});
export const AgentForkContextRequestMessageSchema = z.object({
type: z.literal("agent.fork_context.request"),
agentId: z.string(),
boundaryCursor: AgentTimelineCursorSchema.optional(),
boundaryMessageId: z.string().optional(),
requestId: z.string(),
});
export const SetAgentModeRequestMessageSchema = z.object({
type: z.literal("set_agent_mode_request"),
agentId: z.string(),
modeId: z.string(),
requestId: z.string(),
});
const AgentActionResponsePayloadSchema = z.object({
requestId: z.string(),
agentId: z.string(),
accepted: z.boolean(),
error: z.string().nullable(),
notice: AgentProviderNoticeSchema.nullable().optional(),
});
export const SetAgentModeResponseMessageSchema = z.object({
type: z.literal("set_agent_mode_response"),
payload: AgentActionResponsePayloadSchema,
});
export const SetAgentModelRequestMessageSchema = z.object({
type: z.literal("set_agent_model_request"),
agentId: z.string(),
modelId: z.string().nullable(),
requestId: z.string(),
});
export const SetAgentModelResponseMessageSchema = z.object({
type: z.literal("set_agent_model_response"),
payload: AgentActionResponsePayloadSchema,
});
export const SetAgentThinkingRequestMessageSchema = z.object({
type: z.literal("set_agent_thinking_request"),
agentId: z.string(),
thinkingOptionId: z.string().nullable(),
requestId: z.string(),
});
export const SetAgentThinkingResponseMessageSchema = z.object({
type: z.literal("set_agent_thinking_response"),
payload: AgentActionResponsePayloadSchema,
});
export const SetAgentFeatureRequestMessageSchema = z.object({
type: z.literal("set_agent_feature_request"),
agentId: z.string(),
featureId: z.string(),
value: z.unknown(),
requestId: z.string(),
});
export const SetAgentFeatureResponseMessageSchema = z.object({
type: z.literal("set_agent_feature_response"),
payload: AgentActionResponsePayloadSchema,
});
export const AgentDetachRequestMessageSchema = z.object({
type: z.literal("agent.detach.request"),
agentId: z.string(),
requestId: z.string(),
});
export const AgentDetachResponseMessageSchema = z.object({
type: z.literal("agent.detach.response"),
payload: AgentActionResponsePayloadSchema,
});
export const AgentRewindModeSchema = z.enum(["conversation", "files", "both"]);
export const AgentRewindRequestMessageSchema = z.object({
type: z.literal("agent.rewind.request"),
agentId: z.string(),
messageId: z.string(),
mode: AgentRewindModeSchema,
requestId: z.string(),
});
export const AgentRewindResponseMessageSchema = z.object({
type: z.literal("agent.rewind.response"),
payload: z.object({
requestId: z.string(),
agentId: z.string(),
ok: z.boolean(),
error: z.string().nullable(),
}),
});
export const UpdateAgentResponseMessageSchema = z.object({
type: z.literal("update_agent_response"),
payload: AgentActionResponsePayloadSchema,
});
export const ProjectRenameResponsePayloadSchema = z.object({
requestId: z.string(),
projectId: z.string(),
accepted: z.boolean(),
customName: z.string().nullable(),
error: z.string().nullable(),
});
export const ProjectRenameResponseSchema = z.object({
type: z.literal("project.rename.response"),
payload: ProjectRenameResponsePayloadSchema,
});
export const ProjectRemoveResponsePayloadSchema = z.object({
requestId: z.string(),
projectId: z.string(),
accepted: z.boolean(),
removedWorkspaceIds: z.array(z.string()).default([]),
error: z.string().nullable(),
});
export const ProjectRemoveResponseSchema = z.object({
type: z.literal("project.remove.response"),
payload: ProjectRemoveResponsePayloadSchema,
});
export const WorkspaceTitleSetResponsePayloadSchema = z.object({
requestId: z.string(),
workspaceId: z.string(),
accepted: z.boolean(),
title: z.string().nullable(),
error: z.string().nullable(),
});
export const WorkspaceTitleSetResponseSchema = z.object({
type: z.literal("workspace.title.set.response"),
payload: WorkspaceTitleSetResponsePayloadSchema,
});
export const WorkspacePinSetResponsePayloadSchema = z.object({
requestId: z.string(),
workspaceId: z.string(),
accepted: z.boolean(),
pinnedAt: z.string().nullable(),
error: z.string().nullable(),
});
export const WorkspacePinSetResponseSchema = z.object({
type: z.literal("workspace.pin.set.response"),
payload: WorkspacePinSetResponsePayloadSchema,
});
export const WorkspaceRecoveryStateSchema = z.discriminatedUnion("kind", [
z.object({
kind: z.literal("recoverable"),
workspaceId: z.string(),
workspaceName: z.string(),
action: z.string(),
branch: z.string().nullable(),
}),
z.object({
kind: z.literal("unavailable"),
workspaceId: z.string(),
reason: z.string(),
message: z.string(),
}),
]);
export const WorkspaceRecoveryInspectResponseSchema = z.object({
type: z.literal("workspace.recovery.inspect.response"),
payload: z.object({
requestId: z.string(),
state: WorkspaceRecoveryStateSchema,
}),
});
export const WorkspaceRecoveryRestoreResponseSchema = z.object({
type: z.literal("workspace.recovery.restore.response"),
payload: z.object({
requestId: z.string(),
workspaceId: z.string(),
accepted: z.boolean(),
error: z.string().nullable(),
}),
});
export const SetVoiceModeResponseMessageSchema = z.object({
type: z.literal("set_voice_mode_response"),
payload: z.object({
requestId: z.string(),
enabled: z.boolean(),
agentId: z.string().nullable(),
accepted: z.boolean(),
error: z.string().nullable(),
reasonCode: z.string().optional(),
retryable: z.boolean().optional(),
missingModelIds: z.array(z.string()).optional(),
}),
});
export const AgentPermissionResponseMessageSchema = z.object({
type: z.literal("agent_permission_response"),
agentId: z.string(),
requestId: z.string(),
response: AgentPermissionResponseSchema,
});
const CheckoutErrorCodeSchema = z.enum([
"NOT_GIT_REPO",
"NOT_ALLOWED",
"MERGE_CONFLICT",
"UNKNOWN",
]);
const CheckoutErrorSchema = z.object({
code: CheckoutErrorCodeSchema,
message: z.string(),
});
const CheckoutDiffCompareSchema = z.object({
mode: z.enum(["uncommitted", "base"]),
baseRef: z.string().optional(),
ignoreWhitespace: z.boolean().optional(),
});
export const CheckoutStatusRequestSchema = z.object({
type: z.literal("checkout_status_request"),
cwd: z.string(),
requestId: z.string(),
});
export const SubscribeCheckoutDiffRequestSchema = z.object({
type: z.literal("subscribe_checkout_diff_request"),
subscriptionId: z.string(),
cwd: z.string(),
compare: CheckoutDiffCompareSchema,
requestId: z.string(),
});
export const UnsubscribeCheckoutDiffRequestSchema = z.object({
type: z.literal("unsubscribe_checkout_diff_request"),
subscriptionId: z.string(),
});
export const CheckoutCommitRequestSchema = z.object({
type: z.literal("checkout_commit_request"),
cwd: z.string(),
message: z.string().optional(),
addAll: z.boolean().optional(),
requestId: z.string(),
});
export const CheckoutMergeRequestSchema = z.object({
type: z.literal("checkout_merge_request"),
cwd: z.string(),
baseRef: z.string().optional(),
strategy: z.enum(["merge", "squash"]).optional(),
requireCleanTarget: z.boolean().optional(),
requestId: z.string(),
});
export const CheckoutMergeFromBaseRequestSchema = z.object({
type: z.literal("checkout_merge_from_base_request"),
cwd: z.string(),
baseRef: z.string().optional(),
requireCleanTarget: z.boolean().optional(),
requestId: z.string(),
});
export const CheckoutPullRequestSchema = z.object({
type: z.literal("checkout_pull_request"),
cwd: z.string(),
requestId: z.string(),
});
export const CheckoutPushRequestSchema = z.object({
type: z.literal("checkout_push_request"),
cwd: z.string(),
requestId: z.string(),
});
export const CheckoutRefreshRequestSchema = z.object({
type: z.literal("checkout.refresh.request"),
cwd: z.string(),
requestId: z.string(),
});
export const CheckoutPrCreateRequestSchema = z.object({
type: z.literal("checkout_pr_create_request"),
cwd: z.string(),
title: z.string().optional(),
body: z.string().optional(),
baseRef: z.string().optional(),
requestId: z.string(),
});
export const CheckoutPrMergeRequestSchema = z.object({
type: z.literal("checkout_pr_merge_request"),
cwd: z.string(),
mergeMethod: z.enum(["merge", "squash", "rebase"]),
requestId: z.string(),
});
export const CheckoutForgeSetAutoMergeRequestSchema = z.object({
type: z.literal("checkout.forge.set_auto_merge.request"),
cwd: z.string(),
enabled: z.boolean(),
mergeMethod: z.enum(["merge", "squash", "rebase"]).optional(),
requestId: z.string(),
});
// COMPAT(githubAutoMergeRpc): added in v0.1.106, remove after 2026-12-28 once
// all supported clients use checkout.forge.set_auto_merge.*.
export const CheckoutGithubSetAutoMergeRequestSchema = z.object({
type: z.literal("checkout.github.set_auto_merge.request"),
cwd: z.string(),
enabled: z.boolean(),
mergeMethod: z.enum(["merge", "squash", "rebase"]).optional(),
requestId: z.string(),
});
const CheckoutCommitFileSchema = z.object({
path: z.string(),
additions: z.number(),
deletions: z.number(),
status: z.enum(["added", "modified", "deleted", "renamed"]).optional(),
});
const CheckoutCommitSchema = z.object({
sha: z.string(),
shortSha: z.string(),
subject: z.string(),
authorName: z.string(),
authorDate: z.string(), // ISO 8601
isOnRemote: z.boolean(), // false = local-only (unpushed)
// COMPAT(commitBaseClassification): added in v0.2.0, remove optional after 2027-01-23.
isOnBase: z.boolean().optional(),
files: z.array(CheckoutCommitFileSchema),
});
export const CheckoutCommitsListRequestSchema = z.object({
type: z.literal("checkout.commits.list.request"),
cwd: z.string(),
requestId: z.string(),
});
export const CheckoutCommitFileDiffRequestSchema = z.object({
type: z.literal("checkout.commits.file_diff.request"),
cwd: z.string(),
sha: z.string(),
path: z.string(),
requestId: z.string(),
});
const GitHubRepoSegmentSchema = z.string().regex(/^[A-Za-z0-9._-]+$/);
const CheckoutCheckDetailsRequestPayloadSchema = z.object({
cwd: z.string(),
// GitHub addresses check runs by owner/name. GitLab resolves the project from
// cwd and omits these GitHub-only single-segment fields.
repoOwner: GitHubRepoSegmentSchema.optional(),
repoName: GitHubRepoSegmentSchema.optional(),
// Permanently optional: a check addressed only by workflowRunId (Gitea
// Actions runs carry no check-run id) is fetchable. Callers send at least one
// of checkRunId/workflowRunId; the gated forge RPC only reaches daemons that
// understand this.
checkRunId: z.number().int().positive().optional(),
workflowRunId: z.number().int().positive().optional(),
// Permanent forge-routing field, optional because only some forges need it:
// GitLab routes check details to the MR's head pipeline; Gitea-family adapters
// resolve the PR head SHA by number, including after merge/close. GitHub
// ignores it.
changeRequestNumber: z.number().int().positive().optional(),
requestId: z.string(),
});
export const CheckoutForgeGetCheckDetailsRequestSchema =
CheckoutCheckDetailsRequestPayloadSchema.extend({
type: z.literal("checkout.forge.get_check_details.request"),
});
// COMPAT(githubCheckDetailsRpc): added in v0.1.106, remove after 2026-12-28 once
// all supported clients use checkout.forge.get_check_details.*.
export const CheckoutGithubGetCheckDetailsRequestSchema =
CheckoutCheckDetailsRequestPayloadSchema.extend({
type: z.literal("checkout.github.get_check_details.request"),
});
export const CheckoutPrStatusRequestSchema = z.object({
type: z.literal("checkout_pr_status_request"),
cwd: z.string(),
requestId: z.string(),
});
export const PullRequestTimelineRequestSchema = z.object({
type: z.literal("pull_request_timeline_request"),
cwd: z.string(),
prNumber: z.number(),
repoOwner: z.string(),
repoName: z.string(),
requestId: z.string(),
});
export const ValidateBranchRequestSchema = z.object({
type: z.literal("validate_branch_request"),
cwd: z.string(),
branchName: z.string(),
requestId: z.string(),
});
export const CheckoutSwitchBranchRequestSchema = z.object({
type: z.literal("checkout_switch_branch_request"),
cwd: z.string(),
branch: z.string(),
requestId: z.string(),
});
export const CheckoutRenameBranchRequestSchema = z.object({
type: z.literal("checkout.rename_branch.request"),
cwd: z.string(),
branch: z.string(),
requestId: z.string(),
});
export const StashSaveRequestSchema = z.object({
type: z.literal("stash_save_request"),
cwd: z.string(),
/** Branch name to tag the stash with for later identification. */
branch: z.string().optional(),
requestId: z.string(),
});
export const StashPopRequestSchema = z.object({
type: z.literal("stash_pop_request"),
cwd: z.string(),
/** Zero-based index from stash_list_response. */
stashIndex: z.number().int().min(0),
requestId: z.string(),
});
export const StashListRequestSchema = z.object({
type: z.literal("stash_list_request"),
cwd: z.string(),
/** If true, only return paseo-created stashes. Default true. */
paseoOnly: z.boolean().optional(),
requestId: z.string(),
});
export const BranchSuggestionsRequestSchema = z.object({
type: z.literal("branch_suggestions_request"),
cwd: z.string(),
query: z.string().optional(),
limit: z.number().int().min(1).max(200).optional(),
requestId: z.string(),
});
export const GitHubSearchItemSchema = z.object({
kind: z.enum(["issue", "pr"]),
forge: z.string().optional(),
number: z.number(),
title: z.string(),
url: z.string(),
state: z.string(),
body: z.string().nullable(),
labels: z.array(z.string()),
projectPath: z.string().optional(),
baseRefName: z.string().nullable().optional(),
headRefName: z.string().nullable().optional(),
updatedAt: z.string().optional(),
});
export const ForgeSearchItemSchema = GitHubSearchItemSchema.extend({
kind: z.enum(["issue", "change_request"]),
});
// COMPAT(githubSearchKind): added in v0.1.106, remove with the legacy
// github_search_request RPC after 2026-12-28.
export const ForgeSearchKindSchema = z.enum([
"issue",
"change_request",
"github-issue",
"github-pr",
"pr",
]);
export const GitHubSearchKindSchema = ForgeSearchKindSchema;
export const ForgeSearchRequestSchema = z.object({
type: z.literal("forge.search.request"),
cwd: z.string(),
query: z.string(),
limit: z.number().int().min(1).max(50).optional(),
kinds: z.array(ForgeSearchKindSchema).optional(),
requestId: z.string(),
});
// COMPAT(githubSearchRpc): added in v0.1.106, remove after 2026-12-28 once
// clients use forge.search.*.
export const GitHubSearchRequestSchema = z.object({
type: z.literal("github_search_request"),
cwd: z.string(),
query: z.string(),
limit: z.number().int().min(1).max(50).optional(),
kinds: z.array(GitHubSearchKindSchema).optional(),
requestId: z.string(),
});
export const DirectorySuggestionsRequestSchema = z.object({
type: z.literal("directory_suggestions_request"),
query: z.string(),
cwd: z.string().optional(),
includeFiles: z.boolean().optional(),
includeDirectories: z.boolean().optional(),
matchMode: z.enum(["fuzzy", "suffix"]).optional(),
limit: z.number().int().min(1).max(100).optional(),
requestId: z.string(),
});
export const PaseoWorktreeListRequestSchema = z.object({
type: z.literal("paseo_worktree_list_request"),
cwd: z.string().optional(),
repoRoot: z.string().optional(),
requestId: z.string(),
});
export const PaseoWorktreeArchiveRequestSchema = z.object({
type: z.literal("paseo_worktree_archive_request"),
worktreePath: z.string().optional(),
repoRoot: z.string().optional(),
branchName: z.string().optional(),
// COMPAT(worktreeArchiveWorkspaceId): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
// Explicit workspace record to archive. A directory can back multiple workspaces
// (Model B), so resolving the target by cwd alone picks the wrong record. When
// present the daemon archives this exact workspace; when absent it falls back to
// resolving by worktreePath, preferring the worktree-kind record on a cwd tie.
workspaceId: z.string().optional(),
// COMPAT(worktreeArchiveScope): added in v0.1.97, drop the gate when floor >= v0.1.97.
// Scope of the archive operation. "workspace" archives a single workspace record
// (today's default UI behavior). "worktree" archives every active workspace whose
// cwd resolves to the target directory, then removes the directory if it is
// Paseo-owned. Omitted/unknown values default to "workspace" for old-client safety.
scope: z.enum(["workspace", "worktree"]).optional().default("workspace"),
// COMPAT(worktreeDiskDeletion): added in v0.1.97, ignored as of v0.1.97
// (disk removal derived from scope + last-reference + ownership); field
// retained for wire parse-compat, drop when floor >= v0.1.97.
deleteWorktreeFromDisk: z.boolean().optional().default(false),
requestId: z.string(),
});
export const FirstAgentContextSchema = z.object({
prompt: z.string().optional(),
attachments: AgentAttachmentsSchema,
});
export const CreatePaseoWorktreeRequestSchema = z.object({
type: z.literal("create_paseo_worktree_request"),
cwd: z.string(),
projectId: z.string().optional(),
worktreeSlug: z.string().optional(),
nameContext: z.string().optional(),
attachments: AgentAttachmentsSchema.optional(),
firstAgentContext: FirstAgentContextSchema.optional(),
refName: z.string().min(1).optional(),
action: z.enum(["branch-off", "checkout"]).optional(),
checkoutSource: ChangeRequestCheckoutSourceSchema.optional(),
// COMPAT(githubPrNumber): added in v0.1.106, remove after 2026-12-28 once
// clients send checkoutSource: { kind: "change_request", forge, number }.
githubPrNumber: z.number().int().positive().optional(),
requestId: z.string(),
});
export const WorkspaceSetupStatusRequestSchema = z.object({
type: z.literal("workspace_setup_status_request"),
workspaceId: z.string(),
requestId: z.string(),
});
// COMPAT(desktopEditorBridge): added in v0.1.88, remove after 2026-12-03 once old clients no longer call daemon editor RPCs.
export const LegacyListAvailableEditorsRequestSchema = z.object({
type: z.literal("list_available_editors_request"),
requestId: z.string(),
});
export const LegacyOpenInEditorRequestSchema = z.object({
type: z.literal("open_in_editor_request"),
path: z.string(),
editorId: z.string().trim().min(1),
mode: z.enum(["open", "reveal"]).optional(),
cwd: z.string().optional(),
requestId: z.string(),
});
export const OpenProjectRequestSchema = z.object({
type: z.literal("open_project_request"),
// Path used only for workspace lookup/creation. Use the returned workspace.id for all subsequent references.
cwd: z.string(),
requestId: z.string(),
});
// Smallest shorthand repo path is "a/b": owner, slash, repository.
const MIN_REPOSITORY_PATH_LENGTH = 3;
export const ProjectAddRequestSchema = z.object({
type: z.literal("project.add.request"),
cwd: z.string(),
requestId: z.string(),
});
export const ProjectCreateDirectoryRequestSchema = z.object({
type: z.literal("project.create_directory.request"),
parentPath: z.string(),
name: z.string(),
requestId: z.string(),
});
export const GithubRepositorySchema = z.object({
id: z.string().min(1),
name: z.string().min(1),
nameWithOwner: z.string().min(MIN_REPOSITORY_PATH_LENGTH),
description: z.string().nullable(),
visibility: z.enum(["public", "private", "internal"]),
updatedAt: z.string(),
cloneUrl: z.string().min(MIN_REPOSITORY_PATH_LENGTH),
});
export const WorkspaceGithubSearchRepositoriesRequestSchema = z.object({
type: z.literal("workspace.github.search_repositories.request"),
query: z.string(),
limit: z.number().int().min(1).max(50).optional(),
requestId: z.string(),
});
export const ProjectGithubCloneProtocolSchema = z.enum(["https", "ssh"]);
export const ProjectGithubCloneRequestSchema = z.object({
type: z.literal("project.github.clone.request"),
repo: z.string().trim().min(MIN_REPOSITORY_PATH_LENGTH),
cloneProtocol: ProjectGithubCloneProtocolSchema.optional(),
targetDirectory: z.string().trim().min(1),
requestId: z.string(),
});
export const ArchiveWorkspaceRequestSchema = z.object({
type: z.literal("archive_workspace_request"),
workspaceId: z.string(),
requestId: z.string(),
});
// Create a new workspace record. Unlike open_project, this never deduplicates by
// directory: it always produces a fresh workspace. The source discriminates
// between an existing local directory and a newly created paseo worktree.
export const WorkspaceCreateRequestSchema = z.object({
type: z.literal("workspace.create.request"),
requestId: z.string(),
// Optional user-set title applied to the created workspace.
title: z.string().optional(),
// Optional prompt context for workspace-level name/branch generation.
firstAgentContext: FirstAgentContextSchema.optional(),
source: z.discriminatedUnion("kind", [
z.object({
kind: z.literal("directory"),
// Path of the existing checkout/directory to back the workspace.
path: z.string(),
projectId: z.string().optional(),
}),
z.object({
kind: z.literal("worktree"),
// The project whose repo the worktree is cut from.
cwd: z.string().optional(),
projectId: z.string().optional(),
action: z.enum(["branch-off", "checkout"]).optional(),
// Target branch for checkout, or base ref for branch-off.
refName: z.string().min(1).optional(),
baseBranch: z.string().optional(),
// New branch name for branch-off. The worktree path may use a different slug.
branchName: z.string().min(1).optional(),
checkoutSource: ChangeRequestCheckoutSourceSchema.optional(),
// COMPAT(githubPrNumber): added in v0.1.106, remove after 2026-12-28 once
// clients send checkoutSource.
githubPrNumber: z.number().int().positive().optional(),
worktreeSlug: z.string().optional(),
}),
]),
});
export const WorkspaceClearAttentionRequestSchema = z.object({
type: z.literal("workspace.clear_attention.request"),
workspaceId: z.union([z.string(), z.array(z.string())]),
requestId: z.string(),
});
// Highlighted diff token schema
// Note: style can be a compound class name (e.g., "heading meta") from the syntax highlighter
const HighlightTokenSchema = z.object({
text: z.string(),
style: z.string().nullable(),
});
const DiffLineSchema = z.object({
type: z.enum(["add", "remove", "context", "header"]),
content: z.string(),
tokens: z.array(HighlightTokenSchema).optional(),
});
const DiffHunkSchema = z.object({
oldStart: z.number(),
oldCount: z.number(),
newStart: z.number(),
newCount: z.number(),
lines: z.array(DiffLineSchema),
});
const ParsedDiffFileSchema = z.object({
path: z.string(),
isNew: z.boolean(),
isDeleted: z.boolean(),
additions: z.number(),
deletions: z.number(),
hunks: z.array(DiffHunkSchema),
status: z.enum(["ok", "too_large", "binary"]).optional(),
});
const FileExplorerEntrySchema = z.object({
name: z.string(),
path: z.string(),
kind: z.enum(["file", "directory"]),
size: z.number(),
modifiedAt: z.string(),
});
const FileExplorerFileSchema = z.object({
path: z.string(),
kind: z.enum(["text", "image", "binary"]),
encoding: z.enum(["utf-8", "base64", "none"]),
content: z.string().optional(),
mimeType: z.string().optional(),
size: z.number(),
modifiedAt: z.string(),
revision: z.string().optional(),
});
const FileExplorerDirectorySchema = z.object({
path: z.string(),
entries: z.array(FileExplorerEntrySchema),
});
export const FileExplorerRequestSchema = z.object({
type: z.literal("file_explorer_request"),
cwd: z.string(),
path: z.string().optional(),
mode: z.enum(["list", "file"]),
requestId: z.string(),
acceptBinary: z.boolean().optional(),
});
export const FileVersionSchema = z.discriminatedUnion("status", [
z.object({
status: z.literal("ready"),
cwd: z.string(),
path: z.string(),
size: z.number().int().nonnegative(),
modifiedAt: z.string(),
revision: z.string().optional(),
}),
z.object({
status: z.literal("missing"),
cwd: z.string(),
path: z.string(),
}),
z.object({
status: z.literal("error"),
cwd: z.string(),
path: z.string(),
error: z.string(),
}),
]);
export const FileSubscribeRequestSchema = z.object({
type: z.literal("fs.file.subscribe.request"),
cwd: z.string(),
path: z.string(),
subscriptionId: z.string(),
requestId: z.string(),
});
export const FileUnsubscribeRequestSchema = z.object({
type: z.literal("fs.file.unsubscribe.request"),
subscriptionId: z.string(),
requestId: z.string(),
});
export const FileWriteRequestSchema = z.object({
type: z.literal("fs.file.write.request"),
cwd: z.string(),
path: z.string(),
content: z.string(),
expectedModifiedAt: z.string(),
expectedRevision: z.string().optional(),
requestId: z.string(),
});
export const ProjectIconRequestSchema = z.object({
type: z.literal("project_icon_request"),
cwd: z.string(),
requestId: z.string(),
});
export const FileDownloadTokenRequestSchema = z.object({
type: z.literal("file_download_token_request"),
cwd: z.string(),
path: z.string(),
requestId: z.string(),
});
export const FileUploadRequestSchema = z.object({
type: z.literal("file.upload.request"),
fileName: z.string().min(1),
mimeType: z.string().min(1),
size: z.number().int().nonnegative(),
modifiedAt: z.string(),
requestId: z.string(),
});
export const ClearAgentAttentionMessageSchema = z.object({
type: z.literal("clear_agent_attention"),
agentId: z.union([z.string(), z.array(z.string())]),
requestId: z.string().optional(),
});
export const ClientHeartbeatMessageSchema = z.object({
type: z.literal("client_heartbeat"),
deviceType: z.enum(["web", "mobile"]),
focusedAgentId: z.string().nullable(),
// COMPAT(terminalFocusHeartbeat): added in v0.1.97, remove optional default after 2026-12-13 once old clients no longer send heartbeats without terminal focus.
focusedTerminalId: z.string().nullable().optional().default(null),
lastActivityAt: z.string(),
appVisible: z.boolean(),
appVisibilityChangedAt: z.string().optional(),
});
export const PingMessageSchema = z.object({
type: z.literal("ping"),
requestId: z.string(),
clientSentAt: z.number().int().optional(),
});
const ListCommandsDraftConfigSchema = z.object({
provider: AgentProviderSchema,
cwd: z.string(),
modeId: z.string().optional(),
model: z.string().optional(),
thinkingOptionId: z.string().optional(),
featureValues: z.record(z.string(), z.unknown()).optional(),
});
export const ListProviderFeaturesRequestMessageSchema = z.object({
type: z.literal("list_provider_features_request"),
draftConfig: ListCommandsDraftConfigSchema,
requestId: z.string(),
});
export const ListCommandsRequestSchema = z.object({
type: z.literal("list_commands_request"),
agentId: z.string(),
draftConfig: ListCommandsDraftConfigSchema.optional(),
requestId: z.string(),
});
export const RegisterPushTokenMessageSchema = z.object({
type: z.literal("register_push_token"),
token: z.string(),
});
// ============================================================================
// Terminal Messages
// ============================================================================
export const ListTerminalsRequestSchema = z.object({
type: z.literal("list_terminals_request"),
cwd: z.string().optional(),
workspaceId: z.string().optional(),
requestId: z.string(),
});
export const SubscribeTerminalsRequestSchema = z.object({
type: z.literal("subscribe_terminals_request"),
cwd: z.string(),
workspaceId: z.string().optional(),
});
export const UnsubscribeTerminalsRequestSchema = z.object({
type: z.literal("unsubscribe_terminals_request"),
cwd: z.string(),
workspaceId: z.string().optional(),
});
export const CreateTerminalRequestSchema = z.object({
type: z.literal("create_terminal_request"),
cwd: z.string(),
workspaceId: z.string().optional(),
name: z.string().optional(),
agentId: z.string().optional(),
command: z.string().optional(),
args: z.array(z.string()).optional(),
// Initial PTY size. Added in v0.1.107; the app no longer sends it (the estimate cache that fed
// it was removed — the pane-focus resize claim sizes the PTY instead). Kept and honored
// permanently: released v0.1.107 clients still send it, and programmatic callers may pass an
// exact size. Daemons without it start at 80x24 and the first resize corrects that.
size: z
.object({
rows: z.number().int().positive(),
cols: z.number().int().positive(),
})
.optional(),
requestId: z.string(),
});
export const RenameTerminalRequestSchema = z.object({
type: z.literal("terminal.rename.request"),
terminalId: z.string(),
title: z.string(),
requestId: z.string(),
});
export const StartWorkspaceScriptRequestSchema = z.object({
type: z.literal("start_workspace_script_request"),
workspaceId: z.string(),
scriptName: z.string(),
requestId: z.string(),
});
export const WorkspaceScriptListRequestSchema = z.object({
type: z.literal("workspace.script.list.request"),
workspaceId: z.string(),
requestId: z.string(),
});
export const WorkspaceScriptStartRequestSchema = z.object({
type: z.literal("workspace.script.start.request"),
workspaceId: z.string(),
scriptName: z.string(),
requestId: z.string(),
});
export const WorkspaceScriptStopRequestSchema = z.object({
type: z.literal("workspace.script.stop.request"),
workspaceId: z.string(),
scriptName: z.string(),
requestId: z.string(),
});
export const SubscribeTerminalRequestSchema = z.object({
type: z.literal("subscribe_terminal_request"),
terminalId: z.string(),
requestId: z.string(),
restore: z
.object({
mode: z.enum(["live", "visible-snapshot", "full-snapshot"]),
scrollbackLines: z.number().int().nonnegative().optional(),
size: z
.object({
rows: z.number().int().positive(),
cols: z.number().int().positive(),
})
.optional(),
})
.optional(),
});
export const UnsubscribeTerminalRequestSchema = z.object({
type: z.literal("unsubscribe_terminal_request"),
terminalId: z.string(),
});
const TerminalClientMessageSchema = z.discriminatedUnion("type", [
z.object({ type: z.literal("input"), data: z.string() }),
z.object({ type: z.literal("resize"), rows: z.number(), cols: z.number() }),
z.object({
type: z.literal("mouse"),
row: z.number(),
col: z.number(),
button: z.number(),
action: z.enum(["down", "up", "move"]),
}),
]);
export const TerminalInputSchema = z.object({
type: z.literal("terminal_input"),
terminalId: z.string(),
message: TerminalClientMessageSchema,
});
export const KillTerminalRequestSchema = z.object({
type: z.literal("kill_terminal_request"),
terminalId: z.string(),
requestId: z.string(),
});
export const CaptureTerminalRequestSchema = z.object({
type: z.literal("capture_terminal_request"),
terminalId: z.string(),
start: z.number().int().optional(),
end: z.number().int().optional(),
stripAnsi: z.boolean().default(true),
requestId: z.string(),
});
export const HubExecutionAgentCreateRequestSchema = z.object({
type: z.literal("hub.execution.agent.create.request"),
requestId: z.string(),
executionId: z.string(),
provider: z.string(),
cwd: z.string(),
prompt: z.string(),
workspaceId: z.string().optional(),
model: z.string().optional(),
modeId: z.string().optional(),
thinkingOptionId: z.string().optional(),
featureValues: z.record(z.string(), z.unknown()).optional(),
env: z.record(z.string(), z.string()).optional(),
worktree: CreateAgentWorktreeTargetSchema.optional(),
});
export type HubExecutionAgentCreateRequest = z.infer<typeof HubExecutionAgentCreateRequestSchema>;
export const HubExecutionControlActionSchema = z.enum(["interrupt", "archive"]);
export type HubExecutionControlAction = z.infer<typeof HubExecutionControlActionSchema>;
export const HubExecutionControlRequestSchema = z.object({
type: z.literal("hub.execution.control.request"),
requestId: z.string(),
executionId: z.string(),
action: HubExecutionControlActionSchema,
});
export type HubExecutionControlRequest = z.infer<typeof HubExecutionControlRequestSchema>;
export const SessionInboundMessageSchema = z.discriminatedUnion("type", [
HubExecutionAgentCreateRequestSchema,
HubExecutionControlRequestSchema,
BrowserAutomationExecuteResponseSchema,
VoiceAudioChunkMessageSchema,
AbortRequestMessageSchema,
AudioPlayedMessageSchema,
FetchAgentsRequestMessageSchema,
FetchAgentHistoryRequestMessageSchema,
FetchRecentProviderSessionsRequestMessageSchema,
FetchWorkspacesRequestMessageSchema,
ProjectListRequestMessageSchema,
FetchAgentRequestMessageSchema,
DeleteAgentRequestMessageSchema,
ArchiveAgentRequestMessageSchema,
CloseItemsRequestMessageSchema,
UpdateAgentRequestMessageSchema,
ProjectRenameRequestSchema,
ProjectRemoveRequestSchema,
WorkspaceTitleSetRequestSchema,
WorkspacePinSetRequestSchema,
WorkspaceRecoveryInspectRequestSchema,
WorkspaceRecoveryRestoreRequestSchema,
SetVoiceModeMessageSchema,
SendAgentMessageRequestSchema,
WaitForFinishRequestSchema,
DaemonGetStatusRequestSchema,
DaemonGetPairingOfferRequestSchema,
HubManagementDaemonConnectRequestSchema,
HubManagementDaemonGetStatusRequestSchema,
HubManagementDaemonDisconnectRequestSchema,
DiagnosticsRequestSchema,
GetDaemonConfigRequestMessageSchema,
SetDaemonConfigRequestMessageSchema,
ReadProjectConfigRequestMessageSchema,
WriteProjectConfigRequestMessageSchema,
DictationStreamStartMessageSchema,
DictationStreamChunkMessageSchema,
DictationStreamFinishMessageSchema,
DictationStreamCancelMessageSchema,
CreateAgentRequestMessageSchema,
ListProviderModelsRequestMessageSchema,
ListProviderModesRequestMessageSchema,
ListProviderFeaturesRequestMessageSchema,
ListAvailableProvidersRequestMessageSchema,
GetProvidersSnapshotRequestMessageSchema,
RefreshProvidersSnapshotRequestMessageSchema,
ProviderDiagnosticRequestMessageSchema,
ProviderUsageListRequestMessageSchema,
ResumeAgentRequestMessageSchema,
ImportAgentRequestMessageSchema,
RefreshAgentRequestMessageSchema,
CancelAgentRequestMessageSchema,
ShutdownServerRequestMessageSchema,
RestartServerRequestMessageSchema,
DaemonUpdateRequestMessageSchema,
FetchAgentTimelineRequestMessageSchema,
ProviderSubagentListRequestMessageSchema,
ProviderSubagentTimelineRequestMessageSchema,
SetAgentTimelineSubscriptionRequestMessageSchema,
AgentForkContextRequestMessageSchema,
SetAgentModeRequestMessageSchema,
SetAgentModelRequestMessageSchema,
SetAgentThinkingRequestMessageSchema,
SetAgentFeatureRequestMessageSchema,
AgentDetachRequestMessageSchema,
AgentRewindRequestMessageSchema,
AgentPermissionResponseMessageSchema,
CheckoutStatusRequestSchema,
SubscribeCheckoutDiffRequestSchema,
UnsubscribeCheckoutDiffRequestSchema,
CheckoutCommitRequestSchema,
CheckoutMergeRequestSchema,
CheckoutMergeFromBaseRequestSchema,
CheckoutPullRequestSchema,
CheckoutPushRequestSchema,
CheckoutRefreshRequestSchema,
CheckoutPrCreateRequestSchema,
CheckoutPrMergeRequestSchema,
CheckoutForgeSetAutoMergeRequestSchema,
CheckoutGithubSetAutoMergeRequestSchema,
CheckoutCommitsListRequestSchema,
CheckoutCommitFileDiffRequestSchema,
CheckoutForgeGetCheckDetailsRequestSchema,
CheckoutGithubGetCheckDetailsRequestSchema,
CheckoutPrStatusRequestSchema,
PullRequestTimelineRequestSchema,
CheckoutSwitchBranchRequestSchema,
CheckoutRenameBranchRequestSchema,
StashSaveRequestSchema,
StashPopRequestSchema,
StashListRequestSchema,
ValidateBranchRequestSchema,
BranchSuggestionsRequestSchema,
ForgeSearchRequestSchema,
GitHubSearchRequestSchema,
DirectorySuggestionsRequestSchema,
PaseoWorktreeListRequestSchema,
PaseoWorktreeArchiveRequestSchema,
CreatePaseoWorktreeRequestSchema,
WorkspaceSetupStatusRequestSchema,
LegacyListAvailableEditorsRequestSchema,
LegacyOpenInEditorRequestSchema,
OpenProjectRequestSchema,
ProjectAddRequestSchema,
ProjectCreateDirectoryRequestSchema,
WorkspaceGithubSearchRepositoriesRequestSchema,
ProjectGithubCloneRequestSchema,
ArchiveWorkspaceRequestSchema,
WorkspaceCreateRequestSchema,
WorkspaceClearAttentionRequestSchema,
FileExplorerRequestSchema,
FileSubscribeRequestSchema,
FileUnsubscribeRequestSchema,
FileWriteRequestSchema,
ProjectIconRequestSchema,
FileDownloadTokenRequestSchema,
FileUploadRequestSchema,
ClearAgentAttentionMessageSchema,
ClientHeartbeatMessageSchema,
PingMessageSchema,
ListCommandsRequestSchema,
RegisterPushTokenMessageSchema,
ListTerminalsRequestSchema,
SubscribeTerminalsRequestSchema,
UnsubscribeTerminalsRequestSchema,
CreateTerminalRequestSchema,
RenameTerminalRequestSchema,
StartWorkspaceScriptRequestSchema,
WorkspaceScriptListRequestSchema,
WorkspaceScriptStartRequestSchema,
WorkspaceScriptStopRequestSchema,
SubscribeTerminalRequestSchema,
UnsubscribeTerminalRequestSchema,
TerminalInputSchema,
KillTerminalRequestSchema,
CaptureTerminalRequestSchema,
ChatCreateRequestSchema,
ChatListRequestSchema,
ChatInspectRequestSchema,
ChatDeleteRequestSchema,
ChatPostRequestSchema,
ChatReadRequestSchema,
ChatWaitRequestSchema,
ScheduleCreateRequestSchema,
ScheduleListRequestSchema,
ScheduleInspectRequestSchema,
ScheduleLogsRequestSchema,
SchedulePauseRequestSchema,
ScheduleResumeRequestSchema,
ScheduleDeleteRequestSchema,
ScheduleRunOnceRequestSchema,
ScheduleUpdateRequestSchema,
LoopRunRequestSchema,
LoopListRequestSchema,
LoopInspectRequestSchema,
LoopLogsRequestSchema,
LoopStopRequestSchema,
]);
export type SessionInboundMessage = z.infer<typeof SessionInboundMessageSchema>;
// ============================================================================
// Session Outbound Messages (Session emits these)
// ============================================================================
export const ActivityLogPayloadSchema = z.object({
id: z.string(),
timestamp: z.coerce.date(),
type: z.enum(["transcript", "assistant", "tool_call", "tool_result", "error", "system"]),
content: z.string(),
metadata: z.record(z.string(), z.unknown()).optional(),
});
export const ActivityLogMessageSchema = z.object({
type: z.literal("activity_log"),
payload: ActivityLogPayloadSchema,
});
export const AssistantChunkMessageSchema = z.object({
type: z.literal("assistant_chunk"),
payload: z.object({
chunk: z.string(),
}),
});
export const AudioOutputMessageSchema = z.object({
type: z.literal("audio_output"),
payload: z.object({
audio: z.string(), // base64 encoded
format: z.string(),
id: z.string(),
isVoiceMode: z.boolean(), // Mode when audio was generated (for drift protection)
groupId: z.string().optional(), // Logical utterance id
chunkIndex: z.number().int().nonnegative().optional(),
isLastChunk: z.boolean().optional(),
}),
});
export const TranscriptionResultMessageSchema = z.object({
type: z.literal("transcription_result"),
payload: z.object({
text: z.string(),
language: z.string().optional(),
duration: z.number().optional(),
requestId: z.string(), // Echoed back from request for tracking
avgLogprob: z.number().optional(),
isLowConfidence: z.boolean().optional(),
byteLength: z.number().optional(),
format: z.string().optional(),
debugRecordingPath: z.string().optional(),
}),
});
export const VoiceInputStateMessageSchema = z.object({
type: z.literal("voice_input_state"),
payload: z.object({
isSpeaking: z.boolean(),
}),
});
export const DictationStreamAckMessageSchema = z.object({
type: z.literal("dictation_stream_ack"),
payload: z.object({
dictationId: z.string(),
ackSeq: z.number().int(),
}),
});
export const DictationStreamFinishAcceptedMessageSchema = z.object({
type: z.literal("dictation_stream_finish_accepted"),
payload: z.object({
dictationId: z.string(),
timeoutMs: z.number().int().positive(),
}),
});
export const DictationStreamPartialMessageSchema = z.object({
type: z.literal("dictation_stream_partial"),
payload: z.object({
dictationId: z.string(),
text: z.string(),
}),
});
export const DictationStreamFinalMessageSchema = z.object({
type: z.literal("dictation_stream_final"),
payload: z.object({
dictationId: z.string(),
text: z.string(),
debugRecordingPath: z.string().optional(),
}),
});
export const DictationStreamErrorMessageSchema = z.object({
type: z.literal("dictation_stream_error"),
payload: z.object({
dictationId: z.string(),
error: z.string(),
retryable: z.boolean(),
reasonCode: z.string().optional(),
missingModelIds: z.array(z.string()).optional(),
debugRecordingPath: z.string().optional(),
}),
});
export const ServerCapabilityStateSchema = z.object({
enabled: z.boolean(),
reason: z.string(),
});
export const ServerVoiceCapabilitiesSchema = z.object({
dictation: ServerCapabilityStateSchema,
voice: ServerCapabilityStateSchema,
});
export const ServerCapabilitiesSchema = z
.object({
voice: ServerVoiceCapabilitiesSchema.optional(),
})
.passthrough();
const ServerInfoHostnameSchema = z.unknown().transform((value): string | null => {
if (typeof value !== "string") {
return null;
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : null;
});
const ServerInfoVersionSchema = z.unknown().transform((value): string | null => {
if (typeof value !== "string") {
return null;
}
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : null;
});
const ServerCapabilitiesFromUnknownSchema = z
.unknown()
.optional()
.transform((value): z.infer<typeof ServerCapabilitiesSchema> | undefined => {
if (value === undefined) {
return undefined;
}
const parsed = ServerCapabilitiesSchema.safeParse(value);
if (!parsed.success) {
return undefined;
}
return parsed.data;
});
export const ServerInfoStatusPayloadSchema = z
.object({
status: z.literal("server_info"),
serverId: z.string().trim().min(1),
hostname: ServerInfoHostnameSchema.optional(),
version: ServerInfoVersionSchema.optional(),
// COMPAT(desktopManaged): added in v0.1.X, remove optional parsing after 2027-01-16.
desktopManaged: z.boolean().optional(),
capabilities: ServerCapabilitiesFromUnknownSchema.optional(),
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
features: z
.object({
providersSnapshot: z.boolean().optional(),
// COMPAT(checkoutForgeSetAutoMerge): added in v0.1.106, remove old
// checkoutGithubSetAutoMerge fallback after 2026-12-28.
checkoutForgeSetAutoMerge: z.boolean().optional(),
checkoutGithubSetAutoMerge: z.boolean().optional(),
// COMPAT(githubCheckDetails): added in v0.1.92, remove gate after 2026-12-08.
githubCheckDetails: z.boolean().optional(),
// COMPAT(forgeCheckDetails): added in v0.1.106, remove githubCheckDetails fallback after 2026-12-28.
forgeCheckDetails: z.boolean().optional(),
// COMPAT(forgeSearch): added in v0.1.106, remove github_search fallback after 2026-12-28.
forgeSearch: z.boolean().optional(),
// COMPAT(daemonStatusRpc): added in v0.1.76, remove gate after 2026-11-18.
daemonStatusRpc: z.boolean().optional(),
// COMPAT(terminalRestoreModes): added in v0.1.81, remove gate after 2026-11-23.
"terminal-restore-modes": z.boolean().optional(),
// COMPAT(rewind): added in v0.1.X, drop the gate when floor >= v0.1.X.
rewind: z.boolean().optional(),
// COMPAT(checkoutRefresh): added in v0.1.86, remove gate after 2026-11-29.
checkoutRefresh: z.boolean().optional(),
// COMPAT(workspaceMultiplicity): added in v0.1.97, drop the gate when floor >= v0.1.97
workspaceMultiplicity: z.boolean().optional(),
// COMPAT(projectRemove): added in v0.1.97, drop the gate when floor >= v0.1.97.
projectRemove: z.boolean().optional(),
// COMPAT(projectAdd): added in v0.1.97, drop the gate when floor >= v0.1.97.
projectAdd: z.boolean().optional(),
// COMPAT(worktreeRestore): added in v0.1.97, drop the gate when floor >= v0.1.97
worktreeRestore: z.boolean().optional(),
// COMPAT(workspaceRecovery): added in v0.1.105, remove after 2027-01-11 once daemon floor >= v0.1.105.
workspaceRecovery: z.boolean().optional(),
// COMPAT(workspaceFileEditing): added in v0.2.0, remove after 2027-01-18 once daemon floor >= v0.2.0.
workspaceFileEditing: z.boolean().optional(),
// COMPAT(providerUsageList): added in v0.1.98, drop the gate when daemon floor >= v0.1.98.
providerUsageList: z.boolean().optional(),
// COMPAT(agentDetach): added in v0.1.98, remove gate after 2026-12-19 once daemon floor >= v0.1.98.
agentDetach: z.boolean().optional(),
// COMPAT(agentThinkingUpdate): added in v0.2.4, remove gate after 2027-01-28.
agentThinkingUpdate: z.boolean().optional(),
// COMPAT(daemonDiagnostics): added in v0.1.100, remove gate after 2026-12-25 once daemon floor >= v0.1.100.
daemonDiagnostics: z.boolean().optional(),
// COMPAT(daemonSelfUpdate): added in v0.1.93, remove gate after 2026-12-13.
daemonSelfUpdate: z.boolean().optional(),
// COMPAT(agentForkContext): added in v0.1.102, remove gate after 2026-12-28.
agentForkContext: z.boolean().optional(),
// COMPAT(agentForkContextCursor): added in v0.1.108, remove gate after 2027-01-14.
agentForkContextCursor: z.boolean().optional(),
// COMPAT(providerSubagents): added in v0.1.107, remove gate after 2027-01-12.
providerSubagents: z.boolean().optional(),
// COMPAT(workspacePinning): added in v0.1.107, remove gate after 2027-01-12.
workspacePinning: z.boolean().optional(),
// COMPAT(hubRelationship): added in v0.1.X, drop the gate when floor >= v0.1.X.
hubRelationship: z.boolean().optional(),
// COMPAT(projectGithubClone): added in v0.1.108, remove gate after 2027-01-15.
projectGithubClone: z.boolean().optional(),
// COMPAT(workspaceGithubRepositorySearch): added in v0.1.108, remove gate after 2027-01-15.
workspaceGithubRepositorySearch: z.boolean().optional(),
// COMPAT(projectCreateDirectory): added in v0.1.108, remove gate after 2027-01-15.
projectCreateDirectory: z.boolean().optional(),
// COMPAT(projectList): added in v0.2.4, drop the gate when floor >= v0.2.4.
projectList: z.boolean().optional(),
// COMPAT(commitsList): added in v0.1.110, remove gate after 2027-01-16.
commitsList: z.boolean().optional(),
// COMPAT(commitBaseClassification): added in v0.2.0, remove gate after 2027-01-23.
commitBaseClassification: z.boolean().optional(),
// COMPAT(providerRemoval): added in v0.1.105, drop the gate when floor >= v0.1.105.
providerRemoval: z.boolean().optional(),
// COMPAT(importSessionWorkspaceTarget): added in v0.1.110, remove gate after 2027-01-16.
importSessionWorkspaceTarget: z.boolean().optional(),
// COMPAT(forgeProviders): added in v0.1.106, drop the gate when daemon floor >= v0.1.106.
// Daemon advertises pluggable non-GitHub forge support (the forge registry);
// the client gates non-GitHub setup UI on it.
forgeProviders: z.boolean().optional(),
// COMPAT(selectiveAgentTimeline): added in v0.1.106, remove after 2027-01-12.
selectiveAgentTimeline: z.boolean().optional(),
// COMPAT(stableProjectIdentity): added in v0.1.109, remove gate after 2027-01-15.
stableProjectIdentity: z.boolean().optional(),
// COMPAT(workspaceScriptManagement): added in v0.1.105, remove gate after 2027-01-10.
workspaceScriptManagement: z.boolean().optional(),
})
.optional(),
})
.passthrough()
.transform((payload) => ({
...payload,
hostname: payload.hostname ?? null,
version: payload.version ?? null,
}));
export const StatusMessageSchema = z.object({
type: z.literal("status"),
payload: z
.object({
status: z.string(),
})
.passthrough(), // Allow additional fields
});
export const PongMessageSchema = z.object({
type: z.literal("pong"),
payload: z.object({
requestId: z.string(),
clientSentAt: z.number().int().optional(),
serverReceivedAt: z.number().int(),
serverSentAt: z.number().int(),
}),
});
export const RpcErrorMessageSchema = z.object({
type: z.literal("rpc_error"),
payload: z.object({
requestId: z.string(),
requestType: z.string().optional(),
error: z.string(),
code: z.string().optional(),
}),
});
const AgentStatusWithRequestSchema = z.object({
agentId: z.string(),
requestId: z.string(),
});
const AgentStatusWithTimelineSchema = AgentStatusWithRequestSchema.extend({
timelineSize: z.number().optional(),
});
export const AgentCreatedStatusPayloadSchema = z
.object({
status: z.literal("agent_created"),
agent: AgentSnapshotPayloadSchema,
})
.extend(AgentStatusWithRequestSchema.shape);
export const AgentCreateFailedStatusPayloadSchema = z.object({
status: z.literal("agent_create_failed"),
requestId: z.string(),
error: z.string(),
errorCode: z.string().optional(),
});
export const AgentResumedStatusPayloadSchema = z
.object({
status: z.literal("agent_resumed"),
agent: AgentSnapshotPayloadSchema,
})
.extend(AgentStatusWithTimelineSchema.shape);
export const AgentRefreshedStatusPayloadSchema = z
.object({
status: z.literal("agent_refreshed"),
})
.extend(AgentStatusWithTimelineSchema.shape);
export const RestartRequestedStatusPayloadSchema = z.object({
status: z.literal("restart_requested"),
clientId: z.string(),
reason: z.string().optional(),
requestId: z.string(),
});
export const ShutdownRequestedStatusPayloadSchema = z.object({
status: z.literal("shutdown_requested"),
clientId: z.string(),
requestId: z.string(),
});
export const DaemonConfigChangedStatusPayloadSchema = z
.object({
status: z.literal("daemon_config_changed"),
config: MutableDaemonConfigSchema,
})
.passthrough();
export const KnownStatusPayloadSchema = z.discriminatedUnion("status", [
AgentCreatedStatusPayloadSchema,
AgentCreateFailedStatusPayloadSchema,
AgentResumedStatusPayloadSchema,
AgentRefreshedStatusPayloadSchema,
ShutdownRequestedStatusPayloadSchema,
RestartRequestedStatusPayloadSchema,
DaemonConfigChangedStatusPayloadSchema,
]);
export type KnownStatusPayload = z.infer<typeof KnownStatusPayloadSchema>;
export const ArtifactMessageSchema = z.object({
type: z.literal("artifact"),
payload: z.object({
type: z.enum(["markdown", "diff", "image", "code"]),
id: z.string(),
title: z.string(),
content: z.string(),
isBase64: z.boolean(),
}),
});
export const ProjectCheckoutLiteNotGitPayloadSchema = z
.object({
cwd: z.string(),
isGit: z.literal(false),
currentBranch: z.null(),
remoteUrl: z.null(),
worktreeRoot: z.null().optional(),
isPaseoOwnedWorktree: z.literal(false),
mainRepoRoot: z.null(),
})
.transform((value) => ({
...value,
worktreeRoot: null,
}));
export const ProjectCheckoutLiteGitNonPaseoPayloadSchema = z
.object({
cwd: z.string(),
isGit: z.literal(true),
currentBranch: z.string().nullable(),
remoteUrl: z.string().nullable(),
worktreeRoot: z.string().optional(),
isPaseoOwnedWorktree: z.literal(false),
mainRepoRoot: z.string().nullable().optional().default(null),
})
.transform((value) => ({
...value,
worktreeRoot: value.worktreeRoot ?? value.cwd,
}));
export const ProjectCheckoutLiteGitPaseoPayloadSchema = z
.object({
cwd: z.string(),
isGit: z.literal(true),
currentBranch: z.string().nullable(),
remoteUrl: z.string().nullable(),
worktreeRoot: z.string().optional(),
isPaseoOwnedWorktree: z.literal(true),
mainRepoRoot: z.string(),
})
.transform((value) => ({
...value,
worktreeRoot: value.worktreeRoot ?? value.cwd,
}));
export const ProjectCheckoutLitePayloadSchema = z.union([
ProjectCheckoutLiteNotGitPayloadSchema,
ProjectCheckoutLiteGitNonPaseoPayloadSchema,
ProjectCheckoutLiteGitPaseoPayloadSchema,
]);
export const ProjectPlacementPayloadSchema = z.object({
projectKey: z.string(),
projectName: z.string(),
workspaceName: z.string().nullable().optional(),
checkout: ProjectCheckoutLitePayloadSchema,
});
export const WorkspaceScriptLifecycleSchema = z.enum(["running", "stopped"]);
export const WorkspaceScriptHealthSchema = z.enum(["healthy", "unhealthy"]);
export const WorkspaceScriptPayloadSchema = z.object({
scriptName: z.string(),
type: z.enum(["script", "service"]).optional().default("service"),
hostname: z.string(),
port: z.number().int().positive().nullable(),
localProxyUrl: z.string().nullable().optional(),
publicProxyUrl: z.string().nullable().optional(),
proxyUrl: z.string().nullable().optional().default(null),
lifecycle: WorkspaceScriptLifecycleSchema,
health: WorkspaceScriptHealthSchema.nullable(),
exitCode: z.number().nullable().optional().default(null),
terminalId: z.string().nullable().optional().default(null),
});
const WorkspaceGitRuntimePayloadSchema = z
.object({
currentBranch: z.string().nullable().optional(),
remoteUrl: z.string().nullable().optional(),
isPaseoOwnedWorktree: z.boolean().optional(),
isDirty: z.boolean().nullable().optional(),
aheadBehind: z
.object({
ahead: z.number(),
behind: z.number(),
})
.nullable()
.optional(),
aheadOfOrigin: z.number().nullable().optional(),
behindOfOrigin: z.number().nullable().optional(),
})
.optional()
.nullable();
const WorkspaceGitHubRuntimePayloadSchema = z
.object({
featuresEnabled: z.boolean().optional(),
pullRequest: z
.object({
number: z.number().optional(),
url: z.string(),
title: z.string(),
state: z.string(),
baseRefName: z.string(),
headRefName: z.string(),
isMerged: z.boolean(),
isDraft: z.boolean().optional(),
mergeable: z.enum(["MERGEABLE", "CONFLICTING", "UNKNOWN"]).catch("UNKNOWN").optional(),
checks: z
.array(
z.object({
name: z.string(),
status: z.enum(["success", "failure", "pending", "skipped", "cancelled"]),
url: z.string().nullable(),
workflow: z.string().optional(),
duration: z.string().optional(),
}),
)
.optional(),
checksStatus: z.enum(["none", "pending", "success", "failure"]).optional(),
reviewDecision: z.enum(["approved", "changes_requested", "pending"]).nullable().optional(),
repoOwner: z.string().optional(),
repoName: z.string().optional(),
github: z.unknown().optional(),
})
.nullable()
.optional(),
error: z
.object({
message: z.string(),
})
.nullable()
.optional(),
refreshedAt: z.string().nullable().optional(),
})
.optional()
.nullable();
export const WorkspaceDescriptorPayloadSchema = z
.object({
id: z.string(),
projectId: z.string(),
projectDisplayName: z.string(),
// COMPAT(projectCustomName): added in v0.1.76, drop the optional gate when floor >= v0.1.76.
// When the user has renamed a project, projectDisplayName carries the resolved
// value (customName) and projectCustomName mirrors the raw override so the
// settings UI can prefill its input and offer a "reset" action.
projectCustomName: z.string().nullable().optional(),
projectRootPath: z.string(),
workspaceDirectory: z.string().optional(),
projectKind: z.enum(["git", "non_git", "directory"]),
// COMPAT(workspaces): keep legacy directory workspace kind parseable.
workspaceKind: z.enum(["directory", "local_checkout", "checkout", "worktree"]),
name: z.string(),
// COMPAT(workspaceTitles): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
// When the user has titled a workspace, `name` carries the resolved value
// (title) and `title` mirrors the raw override so the rename UI can prefill
// its input and offer a "reset to branch name" action. Null means the name
// is derived from the branch/directory.
title: z.string().nullable().optional(),
// COMPAT(workspacePinning): added in v0.1.107, remove optional after 2027-01-12.
pinnedAt: z.string().nullable().optional(),
archivingAt: z.string().nullable().optional().default(null),
status: WorkspaceStateBucketSchema,
// Best-effort workspace status entry timestamp. Old daemons omit the
// field; old clients treat missing and null equivalently. The transform
// coerces a missing field to `null` so downstream code never has to
// handle `undefined`.
statusEnteredAt: z
.string()
.nullish()
.transform((value) => value ?? null),
activityAt: z.string().nullable(),
diffStat: z
.object({
additions: z.number(),
deletions: z.number(),
})
.nullable()
.optional(),
scripts: z.array(WorkspaceScriptPayloadSchema).default([]),
gitRuntime: WorkspaceGitRuntimePayloadSchema,
githubRuntime: WorkspaceGitHubRuntimePayloadSchema,
// COMPAT(forge): added in v0.1.106, remove after 2026-12-27. The forge resolved
// for this workspace, so the sidebar/hover-card render the right brand mark.
// Old daemons omit it; absent means the client falls back to GitHub.
forge: z.string().optional(),
project: ProjectPlacementPayloadSchema.optional(),
})
.transform((workspace) => ({
...workspace,
workspaceDirectory: workspace.workspaceDirectory ?? workspace.projectRootPath,
}));
export const AgentUpdateMessageSchema = z.object({
type: z.literal("agent_update"),
payload: z.discriminatedUnion("kind", [
z.object({
kind: z.literal("upsert"),
agent: AgentSnapshotPayloadSchema,
project: ProjectPlacementPayloadSchema.nullable().optional(),
}),
z.object({
kind: z.literal("remove"),
agentId: z.string(),
}),
]),
});
export const AgentStreamMessageSchema = z.object({
type: z.literal("agent_stream"),
payload: z.object({
agentId: z.string(),
event: AgentStreamEventPayloadSchema,
timestamp: z.string(),
// Present for timeline events. Maps 1:1 to canonical in-memory timeline rows.
seq: z.number().int().nonnegative().optional(),
epoch: z.string().optional(),
}),
});
export const AgentStatusMessageSchema = z.object({
type: z.literal("agent_status"),
payload: z.object({
agentId: z.string(),
status: z.string(),
info: AgentSnapshotPayloadSchema,
}),
});
export const AgentListMessageSchema = z.object({
type: z.literal("agent_list"),
payload: z.object({
agents: z.array(AgentSnapshotPayloadSchema),
}),
});
const AgentDirectoryResponseEntrySchema = z.object({
agent: AgentSnapshotPayloadSchema,
project: ProjectPlacementPayloadSchema,
});
const AgentDirectoryPageInfoSchema = z.object({
nextCursor: z.string().nullable(),
prevCursor: z.string().nullable(),
hasMore: z.boolean(),
});
export const FetchAgentsResponseMessageSchema = z.object({
type: z.literal("fetch_agents_response"),
payload: z.object({
requestId: z.string(),
subscriptionId: z.string().nullable().optional(),
entries: z.array(AgentDirectoryResponseEntrySchema),
pageInfo: AgentDirectoryPageInfoSchema,
}),
});
export const FetchAgentHistoryResponseMessageSchema = z.object({
type: z.literal("fetch_agent_history_response"),
payload: z.object({
requestId: z.string(),
entries: z.array(AgentDirectoryResponseEntrySchema),
pageInfo: AgentDirectoryPageInfoSchema,
}),
});
export const FetchRecentProviderSessionsResponseMessageSchema = z.object({
type: z.literal("fetch_recent_provider_sessions_response"),
payload: z.object({
requestId: z.string(),
entries: z.array(RecentProviderSessionDescriptorPayloadSchema),
filteredAlreadyImportedCount: z.number().int().nonnegative().optional(),
}),
});
// COMPAT(workspaceProjects): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
// A project parent that has zero active workspaces. The sidebar renders the
// project row with a new-workspace child so projects persist after their last
// workspace is archived.
export const WorkspaceProjectDescriptorPayloadSchema = z.object({
projectId: z.string(),
// COMPAT(projectKey): added in v0.2.4 on 2026-07-28; remove optional after 2027-01-28.
projectKey: z.string().optional(),
projectDisplayName: z.string(),
projectCustomName: z.string().nullable().optional(),
projectRootPath: z.string(),
projectKind: z.enum(["git", "non_git", "directory"]),
});
export const FetchWorkspacesResponseMessageSchema = z.object({
type: z.literal("fetch_workspaces_response"),
payload: z.object({
requestId: z.string(),
subscriptionId: z.string().nullable().optional(),
entries: z.array(WorkspaceDescriptorPayloadSchema),
// COMPAT(workspaceProjects): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
// Project parents with no active workspaces. Old daemons omit it; old clients
// ignore it. Only populated on the first page (no cursor).
emptyProjects: z.array(WorkspaceProjectDescriptorPayloadSchema).optional().default([]),
pageInfo: z.object({
nextCursor: z.string().nullable(),
prevCursor: z.string().nullable(),
hasMore: z.boolean(),
}),
}),
});
export const WorkspaceUpdateMessageSchema = z.object({
type: z.literal("workspace_update"),
payload: z.discriminatedUnion("kind", [
z.object({
kind: z.literal("upsert"),
workspace: WorkspaceDescriptorPayloadSchema,
}),
z.object({
kind: z.literal("remove"),
id: z.string(),
// COMPAT(workspaceProjects): added in v0.1.97, drop the optional gate when floor >= v0.1.97.
// When archiving this workspace leaves its project with no active
// workspaces, the daemon includes the project parent so the sidebar keeps
// rendering it without waiting for a full re-hydration. Old daemons omit
// it; old clients ignore it and surface the project on their next
// workspace fetch instead.
emptyProject: WorkspaceProjectDescriptorPayloadSchema.optional(),
// Project removal is represented on the existing workspace update channel
// so old clients can still parse the message and ignore the extra field.
removedProjectId: z.string().optional(),
}),
]),
});
export const ProjectUpdateMessageSchema = z.object({
type: z.literal("project.update"),
payload: z.discriminatedUnion("kind", [
z.object({ kind: z.literal("upsert"), project: WorkspaceProjectDescriptorPayloadSchema }),
z.object({ kind: z.literal("remove"), projectId: z.string() }),
]),
});
export const ProjectListResponseMessageSchema = z.object({
type: z.literal("project.list.response"),
payload: z.object({
requestId: z.string(),
projects: z.array(WorkspaceProjectDescriptorPayloadSchema),
}),
});
export const ScriptStatusUpdateMessageSchema = z.object({
type: z.literal("script_status_update"),
payload: z.object({
workspaceId: z.string(),
scripts: z.array(WorkspaceScriptPayloadSchema),
}),
});
export const WorkspaceSetupProgressMessageSchema = z.object({
type: z.literal("workspace_setup_progress"),
payload: z.object({
workspaceId: z.string(),
status: z.enum(["running", "completed", "failed"]),
detail: WorktreeSetupDetailPayloadSchema,
error: z.string().nullable(),
}),
});
export const WorkspaceSetupSnapshotSchema = z.object({
status: z.enum(["running", "completed", "failed"]),
detail: WorktreeSetupDetailPayloadSchema,
error: z.string().nullable(),
});
export const WorkspaceSetupStatusResponseMessageSchema = z.object({
type: z.literal("workspace_setup_status_response"),
payload: z.object({
requestId: z.string(),
workspaceId: z.string(),
snapshot: WorkspaceSetupSnapshotSchema.nullable(),
}),
});
export const OpenProjectResponseMessageSchema = z.object({
type: z.literal("open_project_response"),
payload: z.object({
requestId: z.string(),
workspace: WorkspaceDescriptorPayloadSchema.nullable(),
error: z.string().nullable(),
// Unknown codes from newer daemons degrade to null; clients fall back to `error`.
errorCode: z.enum(["directory_not_found"]).nullish().catch(null),
}),
});
export const ProjectAddResponseSchema = z.object({
type: z.literal("project.add.response"),
payload: z.object({
requestId: z.string(),
project: WorkspaceProjectDescriptorPayloadSchema.nullable(),
error: z.string().nullable(),
errorCode: z.enum(["directory_not_found"]).nullish().catch(null),
}),
});
export const ProjectCreateDirectoryErrorCodeSchema = z.enum([
"invalid_name",
"parent_directory_not_found",
"directory_exists",
"permission_denied",
"registration_failed",
"filesystem_error",
]);
export const ProjectCreateDirectoryResponseSchema = z.object({
type: z.literal("project.create_directory.response"),
payload: z.object({
requestId: z.string(),
directoryPath: z.string().nullable(),
project: WorkspaceProjectDescriptorPayloadSchema.nullable(),
error: z.string().nullable(),
// Error codes are open-ended on the wire so older clients can still parse
// responses after a newer daemon learns another failure reason.
errorCode: z.string().nullable(),
}),
});
export const WorkspaceGithubSearchRepositoriesResponseSchema = z.object({
type: z.literal("workspace.github.search_repositories.response"),
payload: z.discriminatedUnion("status", [
z.object({
status: z.literal("success"),
requestId: z.string(),
repositories: z.array(GithubRepositorySchema),
available: z.literal(true),
error: z.null(),
}),
z.object({
status: z.literal("unavailable"),
requestId: z.string(),
repositories: z.array(GithubRepositorySchema),
reason: z.literal("gh_missing"),
available: z.literal(false),
error: z.string(),
}),
z.object({
status: z.literal("unauthenticated"),
requestId: z.string(),
repositories: z.array(GithubRepositorySchema),
available: z.literal(false),
error: z.string(),
}),
z.object({
status: z.literal("error"),
requestId: z.string(),
repositories: z.array(GithubRepositorySchema),
available: z.literal(true),
error: z.string(),
}),
]),
});
export const ProjectGithubCloneResponseSchema = z.object({
type: z.literal("project.github.clone.response"),
payload: z.object({
requestId: z.string(),
repo: z.string().trim().min(MIN_REPOSITORY_PATH_LENGTH),
checkoutPath: z.string().nullable(),
project: WorkspaceProjectDescriptorPayloadSchema.nullable(),
error: z.string().nullable(),
}),
});
export const StartWorkspaceScriptResponseMessageSchema = z.object({
type: z.literal("start_workspace_script_response"),
payload: z.object({
requestId: z.string(),
workspaceId: z.string(),
scriptName: z.string(),
terminalId: z.string().nullable(),
error: z.string().nullable(),
}),
});
const WorkspaceScriptOperationPayloadSchema = z.object({
requestId: z.string(),
workspaceId: z.string(),
scriptName: z.string().optional(),
script: WorkspaceScriptPayloadSchema.nullable().optional(),
scripts: z.array(WorkspaceScriptPayloadSchema).optional(),
error: z.string().nullable(),
});
export const WorkspaceScriptListResponseMessageSchema = z.object({
type: z.literal("workspace.script.list.response"),
payload: WorkspaceScriptOperationPayloadSchema,
});
export const WorkspaceScriptStartResponseMessageSchema = z.object({
type: z.literal("workspace.script.start.response"),
payload: WorkspaceScriptOperationPayloadSchema,
});
export const WorkspaceScriptStopResponseMessageSchema = z.object({
type: z.literal("workspace.script.stop.response"),
payload: WorkspaceScriptOperationPayloadSchema,
});
// COMPAT(desktopEditorBridge): added in v0.1.88, remove after 2026-12-03 once old clients no longer parse daemon editor RPC responses.
export const LegacyListAvailableEditorsResponseMessageSchema = z.object({
type: z.literal("list_available_editors_response"),
payload: z.object({
requestId: z.string(),
editors: z.array(
z.object({
id: z.string().trim().min(1),
label: z.string(),
}),
),
error: z.string().nullable(),
}),
});
export const LegacyOpenInEditorResponseMessageSchema = z.object({
type: z.literal("open_in_editor_response"),
payload: z.object({
requestId: z.string(),
error: z.string().nullable(),
}),
});
export const ArchiveWorkspaceResponseMessageSchema = z.object({
type: z.literal("archive_workspace_response"),
payload: z.object({
requestId: z.string(),
workspaceId: z.string(),
archivedAt: z.string().nullable(),
error: z.string().nullable(),
}),
});
export const FetchAgentResponseMessageSchema = z.object({
type: z.literal("fetch_agent_response"),
payload: z.object({
requestId: z.string(),
agent: AgentSnapshotPayloadSchema.nullable(),
project: ProjectPlacementPayloadSchema.nullable().optional(),
error: z.string().nullable(),
}),
});
const AgentTimelineSeqRangeSchema = z.object({
startSeq: z.number().int().nonnegative(),
endSeq: z.number().int().nonnegative(),
});
export const AgentTimelineEntryPayloadSchema = z.object({
provider: AgentProviderSchema,
item: AgentTimelineItemPayloadSchema,
timestamp: z.string(),
seqStart: z.number().int().nonnegative(),
seqEnd: z.number().int().nonnegative(),
sourceSeqRanges: z.array(AgentTimelineSeqRangeSchema),
collapsed: z.array(z.enum(["assistant_merge", "reasoning_merge", "tool_lifecycle"])),
});
export const FetchAgentTimelineResponseMessageSchema = z.object({
type: z.literal("fetch_agent_timeline_response"),
payload: z.object({
requestId: z.string(),
agentId: z.string(),
agent: AgentSnapshotPayloadSchema.nullable(),
direction: z.enum(["tail", "before", "after"]),
projection: z.enum(["projected", "canonical"]),
epoch: z.string(),
reset: z.boolean(),
staleCursor: z.boolean(),
gap: z.boolean(),
window: z.object({
minSeq: z.number().int().nonnegative(),
maxSeq: z.number().int().nonnegative(),
nextSeq: z.number().int().nonnegative(),
}),
startCursor: AgentTimelineCursorSchema.nullable(),
endCursor: AgentTimelineCursorSchema.nullable(),
hasOlder: z.boolean(),
hasNewer: z.boolean(),
entries: z.array(AgentTimelineEntryPayloadSchema),
error: z.string().nullable(),
}),
});
export const ProviderSubagentDescriptorPayloadSchema = z.object({
id: z.string(),
parentAgentId: z.string(),
provider: AgentProviderSchema,
title: z.string().nullable(),
description: z.string().nullable(),
status: z.enum(["running", "completed", "failed", "canceled"]),
createdAt: z.string(),
updatedAt: z.string(),
toolCallId: z.string().nullable(),
cwd: z.string().nullable().optional(),
// Compact provider-owned context for the shared track. Providers choose what belongs here and
// format it for display; clients must not parse provider-specific facts out of this string.
subtitle: z.string().nullable().optional(),
});
export type ProviderSubagentDescriptorPayload = z.infer<
typeof ProviderSubagentDescriptorPayloadSchema
>;
export const ProviderSubagentListResponseMessageSchema = z.object({
type: z.literal("agent.provider_subagents.list.response"),
payload: z.object({
requestId: z.string(),
parentAgentId: z.string(),
subagents: z.array(ProviderSubagentDescriptorPayloadSchema),
error: z.string().nullable(),
}),
});
export const ProviderSubagentTimelineResponseMessageSchema = z.object({
type: z.literal("agent.provider_subagents.timeline.get.response"),
payload: z.object({
requestId: z.string(),
parentAgentId: z.string(),
subagentId: z.string(),
provider: AgentProviderSchema.nullable(),
direction: z.enum(["tail", "before", "after"]),
epoch: z.string(),
reset: z.boolean(),
staleCursor: z.boolean(),
gap: z.boolean(),
window: z.object({
minSeq: z.number().int().nonnegative(),
maxSeq: z.number().int().nonnegative(),
nextSeq: z.number().int().nonnegative(),
}),
hasOlder: z.boolean(),
hasNewer: z.boolean(),
rows: z.array(
z.object({
item: AgentTimelineItemPayloadSchema,
timestamp: z.string(),
seq: z.number().int().nonnegative(),
}),
),
error: z.string().nullable(),
}),
});
export const ProviderSubagentUpdateMessageSchema = z.object({
type: z.literal("agent.provider_subagents.update"),
payload: z.discriminatedUnion("kind", [
z.object({
kind: z.literal("upsert"),
subagent: ProviderSubagentDescriptorPayloadSchema,
}),
z.object({
kind: z.literal("timeline"),
parentAgentId: z.string(),
subagentId: z.string(),
provider: AgentProviderSchema,
item: AgentTimelineItemPayloadSchema,
timestamp: z.string(),
seq: z.number().int().nonnegative(),
epoch: z.string(),
}),
z.object({
kind: z.literal("remove"),
parentAgentId: z.string(),
subagentId: z.string(),
}),
]),
});
export const SetAgentTimelineSubscriptionResponseMessageSchema = z.object({
type: z.literal("agent.timeline.set_subscription.response"),
payload: z.object({
agentIds: z.array(z.string()),
requestId: z.string(),
}),
});
export const AgentAttentionRequiredMessageSchema = z.object({
type: z.literal("agent_attention_required"),
payload: z.object({
agentId: z.string(),
reason: z.enum(["finished", "error", "permission"]),
timestamp: z.string(),
shouldNotify: z.boolean(),
notification: z
.object({
title: z.string(),
body: z.string(),
data: z.object({
serverId: z.string(),
workspaceId: z.string().optional(),
agentId: z.string(),
reason: z.enum(["finished", "error", "permission"]),
}),
})
.optional(),
}),
});
export const AgentForkContextResponseMessageSchema = z.object({
type: z.literal("agent.fork_context.response"),
payload: z.object({
requestId: z.string(),
agentId: z.string(),
attachment: TextAttachmentSchema.nullable(),
itemCount: z.number().int().nonnegative(),
boundaryMessageId: z.string().nullable(),
boundaryCursor: AgentTimelineCursorSchema.nullable().optional(),
error: z.string().nullable(),
}),
});
export const CancelAgentResponseMessageSchema = z.object({
type: z.literal("cancel_agent_response"),
payload: z.object({
requestId: z.string(),
agentId: z.string(),
agent: AgentSnapshotPayloadSchema.nullable(),
error: z.string().nullable().optional(),
}),
});
export const ClearAgentAttentionResponseMessageSchema = z.object({
type: z.literal("clear_agent_attention_response"),
payload: z.object({
requestId: z.string(),
agentId: z.string().or(z.array(z.string())),
agents: z.array(AgentSnapshotPayloadSchema),
}),
});
export const WorkspaceCreateResponseSchema = z.object({
type: z.literal("workspace.create.response"),
payload: z.object({
workspace: WorkspaceDescriptorPayloadSchema.nullable(),
setupTerminalId: z.string().nullable(),
error: z.string().nullable(),
errorCode: z.string().optional(),
requestId: z.string(),
}),
});
export const WorkspaceClearAttentionResponseSchema = z.object({
type: z.literal("workspace.clear_attention.response"),
payload: z.object({
requestId: z.string(),
workspaceId: z.union([z.string(), z.array(z.string())]),
clearedAgentIds: z.array(z.string()),
results: z.array(
z.object({
workspaceId: z.string(),
clearedAgentIds: z.array(z.string()),
success: z.boolean(),
error: z.string().nullable(),
}),
),
success: z.boolean(),
error: z.string().nullable(),
}),
});
export const SendAgentMessageResponseMessageSchema = z.object({
type: z.literal("send_agent_message_response"),
payload: z.object({
requestId: z.string(),
agentId: z.string(),
accepted: z.boolean(),
error: z.string().nullable(),
}),
});
export const WaitForFinishResponseMessageSchema = z.object({
type: z.literal("wait_for_finish_response"),
payload: z.object({
requestId: z.string(),
status: z.enum(["idle", "error", "permission", "timeout"]),
final: AgentSnapshotPayloadSchema.nullable(),
error: z.string().nullable(),
lastMessage: z.string().nullable(),
}),
});
export const GetDaemonConfigResponseMessageSchema = z.object({
type: z.literal("get_daemon_config_response"),
payload: z
.object({
requestId: z.string(),
config: MutableDaemonConfigSchema,
})
.passthrough(),
});
export const DaemonGetStatusResponseSchema = z.object({
type: z.literal("daemon.get_status.response"),
payload: z
.object({
requestId: z.string(),
serverId: z.string(),
version: z.string().nullable().optional(),
pid: z.number(),
nodePath: z.string(),
startedAt: z.string().nullable().optional(),
listen: z.string().nullable(),
relay: z
.object({
enabled: z.boolean(),
endpoint: z.string(),
publicEndpoint: z.string(),
useTls: z.boolean(),
publicUseTls: z.boolean(),
})
.nullable()
.optional(),
providers: z.array(
z.object({
provider: z.string(),
available: z.boolean(),
error: z.string().nullable().optional(),
}),
),
})
.passthrough(),
});
export const HubRelationshipStatusSchema = z.object({
state: z.enum([
"not_connected",
"connecting",
"connected",
"reconnecting",
"disconnecting",
"revoked",
]),
daemonId: z.string().nullable(),
hubOrigin: z.string().nullable(),
scopes: z.array(z.string()),
connectedAt: z.string().nullable(),
lastError: z.string().nullable(),
});
export const HubManagementDaemonConnectResponseSchema = z.object({
type: z.literal("hub.management.daemon.connect.response"),
payload: z.object({ requestId: z.string(), status: HubRelationshipStatusSchema }),
});
export const HubManagementDaemonGetStatusResponseSchema = z.object({
type: z.literal("hub.management.daemon.get_status.response"),
payload: z.object({ requestId: z.string(), status: HubRelationshipStatusSchema }),
});
export const HubManagementDaemonDisconnectResponseSchema = z.object({
type: z.literal("hub.management.daemon.disconnect.response"),
payload: z.object({
requestId: z.string(),
status: HubRelationshipStatusSchema,
warning: z.string().optional(),
}),
});
export const DaemonGetPairingOfferResponseSchema = z.object({
type: z.literal("daemon.get_pairing_offer.response"),
payload: z
.object({
requestId: z.string(),
url: z.string(),
qr: z.string().nullable().optional(),
relayEnabled: z.boolean(),
})
.passthrough(),
});
export const DiagnosticsResponseSchema = z.object({
type: z.literal("diagnostics.response"),
payload: z
.object({
requestId: z.string(),
diagnostic: z.string(),
})
.passthrough(),
});
export const SetDaemonConfigResponseMessageSchema = z.object({
type: z.literal("set_daemon_config_response"),
payload: z
.object({
requestId: z.string(),
config: MutableDaemonConfigSchema,
})
.passthrough(),
});
export const ReadProjectConfigResponseMessageSchema = z.object({
type: z.literal("read_project_config_response"),
// zod-aot 0.2.0 miscompiles boolean discriminators as string options
// (`"true"`/`"false"`), so keep this sequential until upstream fixes it.
payload: z.union([
z.object({
requestId: z.string(),
repoRoot: z.string(),
ok: z.literal(true),
config: PaseoConfigRawSchema.nullable(),
revision: PaseoConfigRevisionSchema.nullable(),
}),
z.object({
requestId: z.string(),
repoRoot: z.string(),
ok: z.literal(false),
error: ProjectConfigRpcErrorSchema,
}),
]),
});
export const WriteProjectConfigResponseMessageSchema = z.object({
type: z.literal("write_project_config_response"),
// zod-aot 0.2.0 miscompiles boolean discriminators as string options
// (`"true"`/`"false"`), so keep this sequential until upstream fixes it.
payload: z.union([
z.object({
requestId: z.string(),
repoRoot: z.string(),
ok: z.literal(true),
config: PaseoConfigRawSchema,
revision: PaseoConfigRevisionSchema,
}),
z.object({
requestId: z.string(),
repoRoot: z.string(),
ok: z.literal(false),
error: ProjectConfigRpcErrorSchema,
}),
]),
});
export const AgentPermissionRequestMessageSchema = z.object({
type: z.literal("agent_permission_request"),
payload: z.object({
agentId: z.string(),
request: AgentPermissionRequestPayloadSchema,
}),
});
export const AgentPermissionResolvedMessageSchema = z.object({
type: z.literal("agent_permission_resolved"),
payload: z.object({
agentId: z.string(),
requestId: z.string(),
resolution: AgentPermissionResponseSchema,
}),
});
export const AgentDeletedMessageSchema = z.object({
type: z.literal("agent_deleted"),
payload: z.object({
agentId: z.string(),
requestId: z.string(),
}),
});
export const AgentArchivedMessageSchema = z.object({
type: z.literal("agent_archived"),
payload: z.object({
agentId: z.string(),
archivedAt: z.string(),
requestId: z.string(),
}),
});
const CloseItemsAgentResultSchema = z.object({
agentId: z.string(),
archivedAt: z.string(),
});
const CloseItemsTerminalResultSchema = z.object({
terminalId: z.string(),
success: z.boolean(),
});
export const CloseItemsResponseSchema = z.object({
type: z.literal("close_items_response"),
payload: z.object({
agents: z.array(CloseItemsAgentResultSchema),
terminals: z.array(CloseItemsTerminalResultSchema),
requestId: z.string(),
}),
});
const AheadBehindSchema = z.object({
ahead: z.number(),
behind: z.number(),
});
const CheckoutStatusCommonSchema = z.object({
cwd: z.string(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
});
const CheckoutStatusNotGitSchema = CheckoutStatusCommonSchema.extend({
isGit: z.literal(false),
isPaseoOwnedWorktree: z.literal(false),
repoRoot: z.null(),
currentBranch: z.null(),
isDirty: z.null(),
baseRef: z.null(),
aheadBehind: z.null(),
aheadOfOrigin: z.null(),
behindOfOrigin: z.null(),
hasRemote: z.boolean(),
remoteUrl: z.null(),
});
const CheckoutStatusGitNonPaseoSchema = CheckoutStatusCommonSchema.extend({
isGit: z.literal(true),
isPaseoOwnedWorktree: z.literal(false),
repoRoot: z.string(),
mainRepoRoot: z.string().nullable().optional().default(null),
currentBranch: z.string().nullable(),
isDirty: z.boolean(),
baseRef: z.string().nullable(),
aheadBehind: AheadBehindSchema.nullable(),
aheadOfOrigin: z.number().nullable(),
behindOfOrigin: z.number().nullable(),
hasRemote: z.boolean(),
remoteUrl: z.string().nullable(),
});
const CheckoutStatusGitPaseoSchema = CheckoutStatusCommonSchema.extend({
isGit: z.literal(true),
isPaseoOwnedWorktree: z.literal(true),
repoRoot: z.string(),
mainRepoRoot: z.string(),
currentBranch: z.string().nullable(),
isDirty: z.boolean(),
baseRef: z.string(),
aheadBehind: AheadBehindSchema.nullable(),
aheadOfOrigin: z.number().nullable(),
behindOfOrigin: z.number().nullable(),
hasRemote: z.boolean(),
remoteUrl: z.string().nullable(),
});
export const CheckoutStatusResponseSchema = z.object({
type: z.literal("checkout_status_response"),
payload: z.union([
CheckoutStatusNotGitSchema,
CheckoutStatusGitNonPaseoSchema,
CheckoutStatusGitPaseoSchema,
]),
});
const CheckoutPrGithubAutoMergeRequestSchema = z
.object({
enabledAt: z.string().nullable().optional().default(null),
mergeMethod: z.string().nullable().optional().default(null),
enabledBy: z.string().nullable().optional().default(null),
})
.nullable()
.optional()
.default(null);
const CheckoutPrGithubRepositoryPolicySchema = z
.object({
autoMergeAllowed: z.boolean().optional().default(false),
mergeCommitAllowed: z.boolean().optional().default(false),
squashMergeAllowed: z.boolean().optional().default(false),
rebaseMergeAllowed: z.boolean().optional().default(false),
viewerDefaultMergeMethod: z.string().nullable().optional().default(null),
})
.optional()
.default({
autoMergeAllowed: false,
mergeCommitAllowed: false,
squashMergeAllowed: false,
rebaseMergeAllowed: false,
viewerDefaultMergeMethod: null,
});
const CheckoutPrGithubStatusObjectSchema = z.object({
mergeStateStatus: z.string().nullable().optional().default(null),
autoMergeRequest: CheckoutPrGithubAutoMergeRequestSchema,
viewerCanEnableAutoMerge: z.boolean().optional().default(false),
viewerCanDisableAutoMerge: z.boolean().optional().default(false),
viewerCanMergeAsAdmin: z.boolean().optional().default(false),
viewerCanUpdateBranch: z.boolean().optional().default(false),
repository: CheckoutPrGithubRepositoryPolicySchema,
isMergeQueueEnabled: z.boolean().optional().default(false),
isInMergeQueue: z.boolean().optional().default(false),
});
const CheckoutPrGithubStatusSchema = CheckoutPrGithubStatusObjectSchema.optional();
// The open facts envelope for forge-specific PR facts. Permanent — non-GitHub
// forges deliver their native facts through it. The transitional piece is the
// `github` mirror above, which stays populated for clients predating this
// envelope; see COMPAT(forgeSpecific) in status-projection.ts for the shim.
//
// NOTE: `forgeSpecific.forge` is a FACTS-FAMILY tag, not the workspace brand id.
// The whole Gitea family (gitea, forgejo, codeberg) emits `forge: "gitea"` here
// because they share one facts shape, while the top-level `forge` above carries
// the specific brand. Validation of family-specific payloads happens at runtime
// in the consumer that knows that forge family.
const CheckoutPrForgeSpecificSchema = z.unknown().optional();
export const CheckoutPrStatusSchema = z.object({
// COMPAT(forge): added in v0.1.106, remove the default after 2026-12-27 once daemon floor >= v0.1.106.
forge: z.string().optional().default("github"),
projectPath: z.string().optional(),
number: z.number().optional(),
url: z.string(),
title: z.string(),
state: z.string(),
baseRefName: z.string(),
headRefName: z.string(),
isMerged: z.boolean(),
isDraft: z.boolean().optional().default(false),
mergeable: z
.enum(["MERGEABLE", "CONFLICTING", "UNKNOWN"])
.catch("UNKNOWN")
.optional()
.default("UNKNOWN"),
checks: z
.array(
z.object({
name: z.string(),
status: z.string(),
url: z.string().nullable(),
workflow: z.string().optional(),
duration: z.string().optional(),
checkRunId: z.number().optional(),
workflowRunId: z.number().optional(),
}),
)
.optional()
.default([]),
checksStatus: z.string().optional(),
reviewDecision: z.string().nullable().optional(),
repoOwner: z.string().optional(),
repoName: z.string().optional(),
github: CheckoutPrGithubStatusSchema,
forgeSpecific: CheckoutPrForgeSpecificSchema,
});
// Why a forge's PR/MR features are (un)available, so the client can offer the
// precise next step instead of a generic dead-end. Kept open on the wire so
// feature consumers can ignore values introduced by newer daemons.
export type ForgeAuthState =
| "authenticated"
| "unauthenticated"
| "cli_missing"
| "no_remote"
| "error";
export const ForgeAuthStateSchema = z.unknown().optional();
const CheckoutPrStatusPayloadSchema = z.object({
cwd: z.string(),
status: CheckoutPrStatusSchema.nullable(),
githubFeaturesEnabled: z.boolean(),
// COMPAT(forgeAuthState): added in v0.1.106, remove after 2026-12-27. Optional richer
// signal that supersedes githubFeaturesEnabled. The legacy boolean stays for old clients
// and may remain true for non-auth error payloads so old clients still show the error.
// Drop the boolean once the daemon floor >= v0.1.106.
authState: ForgeAuthStateSchema,
// COMPAT(forge): added in v0.1.106, remove the default after 2026-12-27 once daemon floor >= v0.1.106.
forge: z.string().optional().default("github"),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
});
const CheckoutStatusUpdateMetadataSchema = z.object({
prStatus: CheckoutPrStatusPayloadSchema.optional(),
});
export const CheckoutStatusUpdateSchema = z.object({
type: z.literal("checkout_status_update"),
payload: z
.union([
CheckoutStatusNotGitSchema,
CheckoutStatusGitNonPaseoSchema,
CheckoutStatusGitPaseoSchema,
])
.and(CheckoutStatusUpdateMetadataSchema),
});
const CheckoutDiffSubscriptionPayloadSchema = z.object({
subscriptionId: z.string(),
cwd: z.string(),
files: z.array(ParsedDiffFileSchema),
error: CheckoutErrorSchema.nullable(),
// COMPAT(diffTooLarge): added in v0.2.4, keep optional until the daemon floor is v0.2.4.
diffTooLarge: z.boolean().optional(),
});
export const SubscribeCheckoutDiffResponseSchema = z.object({
type: z.literal("subscribe_checkout_diff_response"),
payload: CheckoutDiffSubscriptionPayloadSchema.extend({
requestId: z.string(),
}),
});
export const CheckoutDiffUpdateSchema = z.object({
type: z.literal("checkout_diff_update"),
payload: CheckoutDiffSubscriptionPayloadSchema,
});
export const CheckoutCommitResponseSchema = z.object({
type: z.literal("checkout_commit_response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutMergeResponseSchema = z.object({
type: z.literal("checkout_merge_response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutMergeFromBaseResponseSchema = z.object({
type: z.literal("checkout_merge_from_base_response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutPullResponseSchema = z.object({
type: z.literal("checkout_pull_response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutPushResponseSchema = z.object({
type: z.literal("checkout_push_response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutRefreshResponseSchema = z.object({
type: z.literal("checkout.refresh.response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutPrCreateResponseSchema = z.object({
type: z.literal("checkout_pr_create_response"),
payload: z.object({
cwd: z.string(),
url: z.string().nullable(),
number: z.number().nullable(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutPrMergeResponseSchema = z.object({
type: z.literal("checkout_pr_merge_response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutForgeSetAutoMergeResponseSchema = z.object({
type: z.literal("checkout.forge.set_auto_merge.response"),
payload: z.object({
cwd: z.string(),
enabled: z.boolean(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
// COMPAT(githubAutoMergeRpc): added in v0.1.106, remove after 2026-12-28 once
// all supported clients use checkout.forge.set_auto_merge.*.
export const CheckoutGithubSetAutoMergeResponseSchema = z.object({
type: z.literal("checkout.github.set_auto_merge.response"),
payload: z.object({
cwd: z.string(),
enabled: z.boolean(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutCommitsListResponseSchema = z.object({
type: z.literal("checkout.commits.list.response"),
payload: z.object({
cwd: z.string(),
baseRef: z.string().nullable(),
commits: z.array(CheckoutCommitSchema),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutCommitFileDiffResponseSchema = z.object({
type: z.literal("checkout.commits.file_diff.response"),
payload: z.object({
cwd: z.string(),
sha: z.string(),
path: z.string(),
// null when the file is absent from the commit or carries no textual diff
// (e.g. binary-only changes).
file: ParsedDiffFileSchema.nullable(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
const CheckoutGithubCheckAnnotationSchema = z.object({
path: z.string().optional(),
startLine: z.number().optional(),
endLine: z.number().optional(),
annotationLevel: z.string().optional(),
message: z.string().optional(),
title: z.string().optional(),
rawDetails: z.string().optional(),
});
const CheckoutGithubCheckJobSchema = z.object({
jobId: z.number(),
name: z.string(),
status: z.string().nullable().optional(),
conclusion: z.string().nullable().optional(),
url: z.string().nullable().optional(),
logTail: z.string().optional(),
logTruncated: z.boolean().optional(),
});
// Statuses stay open strings so future forge values cannot break parsing.
const CheckoutPipelineJobSchema = z.object({
id: z.number(),
name: z.string(),
stage: z.string(),
status: z.string(),
rawStatus: z.string(),
url: z.string().nullable().optional().default(null),
allowFailure: z.boolean().optional().default(false),
durationSeconds: z.number().nullable().optional().default(null),
});
const CheckoutPipelineStageSchema = z.object({
name: z.string(),
status: z.string(),
jobs: z.array(CheckoutPipelineJobSchema).optional().default([]),
});
const CheckoutPipelineSchema = z.object({
id: z.number(),
status: z.string(),
rawStatus: z.string(),
url: z.string().nullable().optional().default(null),
ref: z.string().nullable().optional().default(null),
sha: z.string().nullable().optional().default(null),
stages: z.array(CheckoutPipelineStageSchema).optional().default([]),
});
export const CheckoutGithubCheckDetailsSchema = z.object({
checkRunId: z.number(),
workflowRunId: z.number().nullable().optional(),
name: z.string(),
status: z.string().nullable().optional(),
conclusion: z.string().nullable().optional(),
url: z.string().nullable().optional(),
detailsUrl: z.string().nullable().optional(),
output: z
.object({
title: z.string().nullable().optional(),
summary: z.string().nullable().optional(),
text: z.string().nullable().optional(),
})
.nullable()
.optional(),
annotations: z.array(CheckoutGithubCheckAnnotationSchema).optional().default([]),
failedJobs: z.array(CheckoutGithubCheckJobSchema).optional().default([]),
truncated: z.boolean().optional().default(false),
// No default: server CheckDetails keeps this optional and GitHub leaves it absent.
pipeline: CheckoutPipelineSchema.nullable().optional(),
});
export const CheckoutCheckDetailsSchema = CheckoutGithubCheckDetailsSchema;
export const CheckoutForgeGetCheckDetailsResponseSchema = z.object({
type: z.literal("checkout.forge.get_check_details.response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
details: CheckoutCheckDetailsSchema.nullable().optional().default(null),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
// COMPAT(githubCheckDetailsRpc): added in v0.1.106, remove after 2026-12-28 once
// all supported clients use checkout.forge.get_check_details.*.
export const CheckoutGithubGetCheckDetailsResponseSchema = z.object({
type: z.literal("checkout.github.get_check_details.response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
details: CheckoutCheckDetailsSchema.nullable().optional().default(null),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutPrStatusResponseSchema = z.object({
type: z.literal("checkout_pr_status_response"),
payload: CheckoutPrStatusPayloadSchema,
});
const PullRequestTimelineKnownErrorSchema = z.discriminatedUnion("kind", [
z.object({
kind: z.literal("not_found"),
message: z.string().optional().default(""),
}),
z.object({
kind: z.literal("forbidden"),
message: z.string().optional().default(""),
}),
z.object({
kind: z.literal("unknown"),
message: z.string().optional().default(""),
}),
]);
const PullRequestTimelineErrorSchema = z.preprocess((value) => {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return { kind: "unknown", message: "" };
}
const error = value as Record<string, unknown>;
if (error.kind === "not_found" || error.kind === "forbidden" || error.kind === "unknown") {
return error;
}
return { ...error, kind: "unknown" };
}, PullRequestTimelineKnownErrorSchema);
const PullRequestTimelineReviewItemSchema = z.object({
id: z.string().optional().default(""),
kind: z.literal("review"),
author: z.string().optional().default("unknown"),
authorUrl: z.string().nullable().optional(),
avatarUrl: z.string().nullable().optional(),
body: z.string().optional().default(""),
createdAt: z.number().optional().default(0),
url: z.string().optional().default(""),
reviewState: z
.enum(["approved", "changes_requested", "commented"])
.optional()
.default("commented"),
});
const PullRequestTimelineCommentItemSchema = z.object({
id: z.string().optional().default(""),
kind: z.literal("comment"),
author: z.string().optional().default("unknown"),
authorUrl: z.string().nullable().optional(),
avatarUrl: z.string().nullable().optional(),
body: z.string().optional().default(""),
createdAt: z.number().optional().default(0),
url: z.string().optional().default(""),
// GitHub review id this inline comment belongs to; lets clients nest review
// threads under their parent review. Absent on issue comments and on
// timelines from daemons that predate the field.
reviewId: z.string().optional(),
// Forge-neutral discussion/thread id this comment belongs to, independent of a
// file position. GitLab maps its discussion id here so general (non-file)
// reply chains group into one thread; file-position threads also carry it.
// Absent on standalone comments and on timelines from daemons that predate it.
threadId: z.string().optional(),
// Forge-neutral resolution state for a thread that has no file position, e.g. a
// GitLab general (non-file) discussion that is resolvable. File-position threads
// carry their resolution under `location.isResolved` instead. Absent on ordinary
// comments, on forges that expose no thread resolution, and on older timelines.
threadIsResolved: z.boolean().optional(),
location: z
.object({
path: z.string(),
line: z.number().optional(),
startLine: z.number().optional(),
threadId: z.string().optional(),
isResolved: z.boolean().optional(),
isOutdated: z.boolean().optional(),
})
.optional(),
});
export const PullRequestTimelineItemSchema = z.preprocess(
(value) => {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return value;
}
const item = value as Record<string, unknown>;
if (item.kind === "review" || item.kind === "comment") {
return item;
}
return { ...item, kind: "comment" };
},
z.discriminatedUnion("kind", [
PullRequestTimelineReviewItemSchema,
PullRequestTimelineCommentItemSchema,
]),
);
export const PullRequestTimelineResponseSchema = z.object({
type: z.literal("pull_request_timeline_response"),
payload: z
.object({
cwd: z.string().optional().default(""),
prNumber: z.number().nullable().optional().default(null),
items: z.array(PullRequestTimelineItemSchema).optional().default([]),
truncated: z.boolean().optional().default(false),
error: PullRequestTimelineErrorSchema.nullable().optional().default(null),
requestId: z.string().optional().default(""),
githubFeaturesEnabled: z.boolean().optional().default(true),
// COMPAT(forgeAuthState): added in v0.1.106, remove after 2026-12-27. Optional richer
// signal that supersedes githubFeaturesEnabled, mirroring CheckoutPrStatusPayloadSchema.
// Drop the boolean once the daemon floor >= v0.1.106.
authState: ForgeAuthStateSchema,
})
.optional()
.prefault({}),
});
export const CheckoutSwitchBranchResponseSchema = z.object({
type: z.literal("checkout_switch_branch_response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
branch: z.string(),
source: z.enum(["local", "remote"]).optional(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CheckoutRenameBranchResponseSchema = z.object({
type: z.literal("checkout.rename_branch.response"),
payload: z.object({
requestId: z.string(),
success: z.boolean(),
cwd: z.string(),
currentBranch: z.string().nullable(),
error: CheckoutErrorSchema.nullable(),
}),
});
const StashEntrySchema = z.object({
index: z.number().int().min(0),
message: z.string(),
branch: z.string().nullable(),
isPaseo: z.boolean(),
});
export const StashSaveResponseSchema = z.object({
type: z.literal("stash_save_response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const StashPopResponseSchema = z.object({
type: z.literal("stash_pop_response"),
payload: z.object({
cwd: z.string(),
success: z.boolean(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const StashListResponseSchema = z.object({
type: z.literal("stash_list_response"),
payload: z.object({
cwd: z.string(),
entries: z.array(StashEntrySchema),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const ValidateBranchResponseSchema = z.object({
type: z.literal("validate_branch_response"),
payload: z.object({
exists: z.boolean(),
resolvedRef: z.string().nullable(),
isRemote: z.boolean(),
error: z.string().nullable(),
requestId: z.string(),
}),
});
export const BranchSuggestionsResponseSchema = z.object({
type: z.literal("branch_suggestions_response"),
payload: z.object({
branches: z.array(z.string()),
branchDetails: z
.array(
z.object({
name: z.string(),
committerDate: z.number(),
hasLocal: z.boolean().optional(),
hasRemote: z.boolean().optional(),
}),
)
.optional(),
error: z.string().nullable(),
requestId: z.string(),
}),
});
const ForgeSearchResponsePayloadSchema = z.object({
items: z.array(z.unknown()),
authState: z.unknown().optional(),
error: z.string().nullable(),
requestId: z.string(),
});
const GitHubSearchResponsePayloadSchema = z.object({
items: z.array(z.unknown()),
featuresEnabled: z.boolean().optional(),
authState: z.unknown().optional(),
githubFeaturesEnabled: z.boolean().optional(),
error: z.string().nullable(),
requestId: z.string(),
});
export const ForgeSearchResponseSchema = z.object({
type: z.literal("forge.search.response"),
payload: ForgeSearchResponsePayloadSchema,
});
// COMPAT(githubSearchRpc): added in v0.1.106, remove after 2026-12-28 once
// clients use forge.search.*.
export const GitHubSearchResponseSchema = z.object({
type: z.literal("github_search_response"),
payload: GitHubSearchResponsePayloadSchema,
});
export const DirectorySuggestionsResponseSchema = z.object({
type: z.literal("directory_suggestions_response"),
payload: z.object({
directories: z.array(z.string()),
entries: z
.array(
z.object({
path: z.string(),
kind: z.enum(["file", "directory"]),
}),
)
.optional()
.default([]),
error: z.string().nullable(),
requestId: z.string(),
}),
});
const PaseoWorktreeSchema = z.object({
worktreePath: z.string(),
createdAt: z.string(),
branchName: z.string().nullable().optional(),
head: z.string().nullable().optional(),
});
export const PaseoWorktreeListResponseSchema = z.object({
type: z.literal("paseo_worktree_list_response"),
payload: z.object({
worktrees: z.array(PaseoWorktreeSchema),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const PaseoWorktreeArchiveResponseSchema = z.object({
type: z.literal("paseo_worktree_archive_response"),
payload: z.object({
success: z.boolean(),
removedAgents: z.array(z.string()).optional(),
error: CheckoutErrorSchema.nullable(),
requestId: z.string(),
}),
});
export const CreatePaseoWorktreeResponseSchema = z.object({
type: z.literal("create_paseo_worktree_response"),
payload: z.object({
workspace: WorkspaceDescriptorPayloadSchema.nullable(),
error: z.string().nullable(),
errorCode: z.string().optional(),
setupTerminalId: z.string().nullable(),
requestId: z.string(),
}),
});
export const FileExplorerResponseSchema = z.object({
type: z.literal("file_explorer_response"),
payload: z.object({
cwd: z.string(),
path: z.string(),
mode: z.enum(["list", "file"]),
directory: FileExplorerDirectorySchema.nullable(),
file: FileExplorerFileSchema.nullable(),
error: z.string().nullable(),
requestId: z.string(),
}),
});
export const FileSubscribeResponseSchema = z.object({
type: z.literal("fs.file.subscribe.response"),
payload: z.object({
subscriptionId: z.string(),
initial: FileVersionSchema,
requestId: z.string(),
}),
});
export const FileUnsubscribeResponseSchema = z.object({
type: z.literal("fs.file.unsubscribe.response"),
payload: z.object({
subscriptionId: z.string(),
requestId: z.string(),
}),
});
export const FileWriteResultSchema = z.discriminatedUnion("status", [
z.object({
status: z.literal("written"),
modifiedAt: z.string(),
size: z.number(),
revision: z.string().optional(),
}),
z.object({ status: z.literal("conflict"), version: FileVersionSchema }),
z.object({ status: z.literal("error"), error: z.string() }),
]);
export const FileWriteResponseSchema = z.object({
type: z.literal("fs.file.write.response"),
payload: z.object({
result: FileWriteResultSchema,
requestId: z.string(),
}),
});
export const FileUpdateSchema = z.object({
type: z.literal("fs.file.update"),
payload: z.object({
subscriptionId: z.string(),
version: FileVersionSchema,
}),
});
const ProjectIconSchema = z.object({
data: z.string(),
mimeType: z.string(),
});
export const ProjectIconResponseSchema = z.object({
type: z.literal("project_icon_response"),
payload: z.object({
cwd: z.string(),
icon: ProjectIconSchema.nullable(),
error: z.string().nullable(),
requestId: z.string(),
}),
});
export const FileDownloadTokenResponseSchema = z.object({
type: z.literal("file_download_token_response"),
payload: z.object({
cwd: z.string(),
path: z.string(),
token: z.string().nullable(),
fileName: z.string().nullable(),
mimeType: z.string().nullable(),
size: z.number().nullable(),
error: z.string().nullable(),
requestId: z.string(),
}),
});
export const FileUploadResponseSchema = z.object({
type: z.literal("file.upload.response"),
payload: z.object({
requestId: z.string(),
file: UploadedFileAttachmentSchema.nullable(),
error: z.string().nullable(),
}),
});
export const ListProviderModelsResponseMessageSchema = z.object({
type: z.literal("list_provider_models_response"),
payload: z.object({
provider: AgentProviderSchema,
models: z.array(AgentModelDefinitionSchema).optional(),
error: z.string().nullable().optional(),
fetchedAt: z.string(),
requestId: z.string(),
}),
});
export const ListProviderModesResponseMessageSchema = z.object({
type: z.literal("list_provider_modes_response"),
payload: z.object({
provider: AgentProviderSchema,
modes: z.array(AgentModeSchema).optional(),
error: z.string().nullable().optional(),
fetchedAt: z.string(),
requestId: z.string(),
}),
});
export const ListProviderFeaturesResponseMessageSchema = z.object({
type: z.literal("list_provider_features_response"),
payload: z.object({
provider: AgentProviderSchema,
features: z.array(AgentFeatureSchema).optional(),
error: z.string().nullable().optional(),
fetchedAt: z.string(),
requestId: z.string(),
}),
});
const ProviderAvailabilitySchema = z.object({
provider: AgentProviderSchema,
available: z.boolean(),
error: z.string().nullable().optional(),
});
export const ListAvailableProvidersResponseSchema = z.object({
type: z.literal("list_available_providers_response"),
payload: z.object({
providers: z.array(ProviderAvailabilitySchema),
error: z.string().nullable().optional(),
fetchedAt: z.string(),
requestId: z.string(),
}),
});
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
export const GetProvidersSnapshotResponseMessageSchema = z.object({
type: z.literal("get_providers_snapshot_response"),
payload: z.object({
entries: z.array(ProviderSnapshotEntrySchema),
generatedAt: z.string(),
requestId: z.string(),
}),
});
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
export const ProvidersSnapshotUpdateMessageSchema = z.object({
type: z.literal("providers_snapshot_update"),
payload: z.object({
cwd: z.string().optional(),
entries: z.array(ProviderSnapshotEntrySchema),
generatedAt: z.string(),
}),
});
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
export const RefreshProvidersSnapshotResponseMessageSchema = z.object({
type: z.literal("refresh_providers_snapshot_response"),
payload: z.object({
requestId: z.string(),
acknowledged: z.boolean(),
}),
});
// COMPAT(providersSnapshot): added in v0.1.48, remove gating when all clients use snapshot
export const ProviderDiagnosticResponseMessageSchema = z.object({
type: z.literal("provider_diagnostic_response"),
payload: z.object({
provider: AgentProviderSchema,
diagnostic: z.string(),
requestId: z.string(),
}),
});
export const ProviderUsageToneSchema = z.enum(["default", "ok", "warning", "danger"]);
export const ProviderUsageStatusSchema = z.enum(["available", "unavailable", "error"]);
export const ProviderUsageWindowSchema = z.object({
id: z.string(),
label: z.string(),
usedPct: z.number().nullable().optional(),
remainingPct: z.number().nullable().optional(),
resetsAt: z.string().nullable().optional(),
runsOutAt: z.string().nullable().optional(),
shortfallPct: z.number().nullable().optional(),
tone: ProviderUsageToneSchema.optional(),
});
export const ProviderUsageBalanceSchema = z.object({
id: z.string(),
label: z.string(),
used: z.number().nullable().optional(),
remaining: z.number().nullable().optional(),
limit: z.number().nullable().optional(),
unit: z.enum(["usd", "credits", "requests", "tokens"]),
resetsAt: z.string().nullable().optional(),
tone: ProviderUsageToneSchema.optional(),
});
export const ProviderUsageDetailSchema = z.object({
id: z.string(),
label: z.string(),
value: z.string(),
tone: ProviderUsageToneSchema.optional(),
});
export const ProviderUsageSchema = z.object({
providerId: z.string(),
displayName: z.string(),
status: ProviderUsageStatusSchema,
planLabel: z.string().nullable(),
sourceLabel: z.string().nullable().optional(),
fetchedAt: z.string().nullable().optional(),
nextRefreshAt: z.string().nullable().optional(),
windows: z.array(ProviderUsageWindowSchema),
balances: z.array(ProviderUsageBalanceSchema).optional(),
details: z.array(ProviderUsageDetailSchema).optional(),
error: z.string().nullable().optional(),
});
export const ProviderUsageListResponseMessageSchema = z.object({
type: z.literal("provider.usage.list.response"),
payload: z.object({
requestId: z.string(),
fetchedAt: z.string(),
providers: z.array(ProviderUsageSchema),
}),
});
const AgentSlashCommandSchema = z.object({
name: z.string(),
description: z.string(),
argumentHint: z.string(),
kind: z.enum(["command", "skill"]).optional().catch("command"),
});
export const ListCommandsResponseSchema = z.object({
type: z.literal("list_commands_response"),
payload: z.object({
agentId: z.string(),
commands: z.array(AgentSlashCommandSchema),
error: z.string().nullable(),
requestId: z.string(),
}),
});
// ============================================================================
// Terminal Outbound Messages
// ============================================================================
const TerminalInfoSchema = z.object({
id: z.string(),
name: z.string(),
cwd: z.string(),
workspaceId: z.string().optional(),
title: z.string().optional(),
activity: TerminalActivitySchema.nullable().optional(),
});
export const TerminalCellSchema = z.object({
char: z.string(),
fg: z.number().optional(),
bg: z.number().optional(),
fgMode: z.number().optional(),
bgMode: z.number().optional(),
bold: z.boolean().optional(),
italic: z.boolean().optional(),
underline: z.boolean().optional(),
dim: z.boolean().optional(),
inverse: z.boolean().optional(),
strikethrough: z.boolean().optional(),
});
export const TerminalCursorStyleSchema = z.enum(["block", "underline", "bar"]);
export const TerminalCursorSchema = z.object({
row: z.number(),
col: z.number(),
hidden: z.boolean().optional(),
style: TerminalCursorStyleSchema.optional(),
blink: z.boolean().optional(),
});
export const TerminalStateSchema = z.object({
rows: z.number(),
cols: z.number(),
grid: z.array(z.array(TerminalCellSchema)),
scrollback: z.array(z.array(TerminalCellSchema)),
cursor: TerminalCursorSchema,
title: z.string().optional(),
// Per-row soft-wrap flags aligned 1:1 with `grid` / `scrollback`. `true` means
// the row continued onto the next row (xterm's GRID_LINE_WRAPPED equivalent),
// so the client can re-wrap the logical line on resize instead of freezing it
// at the snapshot width. Optional: only sent to clients that advertise the
// `terminalReflowableSnapshot` capability, so old daemons/clients are unaffected.
gridWrapped: z.array(z.boolean()).optional(),
scrollbackWrapped: z.array(z.boolean()).optional(),
});
export const ListTerminalsResponseSchema = z.object({
type: z.literal("list_terminals_response"),
payload: z.object({
cwd: z.string().optional(),
terminals: z.array(TerminalInfoSchema.omit({ cwd: true })),
requestId: z.string(),
}),
});
export const TerminalsChangedSchema = z.object({
type: z.literal("terminals_changed"),
payload: z.object({
cwd: z.string(),
terminals: z.array(TerminalInfoSchema.omit({ cwd: true })),
}),
});
export const CreateTerminalResponseSchema = z.object({
type: z.literal("create_terminal_response"),
payload: z.object({
terminal: TerminalInfoSchema.nullable(),
error: z.string().nullable(),
requestId: z.string(),
}),
});
export const RenameTerminalResponseSchema = z.object({
type: z.literal("terminal.rename.response"),
payload: z.object({
requestId: z.string(),
success: z.boolean(),
error: z.string().nullable(),
}),
});
export const SubscribeTerminalResponseSchema = z.object({
type: z.literal("subscribe_terminal_response"),
payload: z.union([
z.object({
terminalId: z.string(),
slot: z.number().int().min(0).max(255),
error: z.null(),
requestId: z.string(),
}),
z.object({
terminalId: z.string(),
error: z.string(),
requestId: z.string(),
}),
]),
});
export const KillTerminalResponseSchema = z.object({
type: z.literal("kill_terminal_response"),
payload: z.object({
terminalId: z.string(),
success: z.boolean(),
requestId: z.string(),
}),
});
export const CaptureTerminalResponseSchema = z.object({
type: z.literal("capture_terminal_response"),
payload: z.object({
terminalId: z.string(),
lines: z.array(z.string()),
totalLines: z.number().int().nonnegative(),
requestId: z.string(),
}),
});
export const TerminalStreamExitSchema = z.object({
type: z.literal("terminal_stream_exit"),
payload: z.object({
terminalId: z.string(),
}),
});
export const TerminalAttentionRequiredSchema = z.object({
type: z.literal("terminal_attention_required"),
payload: z.object({
serverId: z.string().optional(),
terminalId: z.string(),
cwd: z.string(),
workspaceId: z.string().optional(),
reason: z.enum(["finished", "needs_input"]),
title: z.string(),
body: z.string(),
shouldNotify: z.boolean(),
}),
});
export const DaemonUpdateResponseSchema = z.object({
type: z.literal("daemon.update.response"),
payload: z.object({
requestId: z.string(),
success: z.boolean(),
error: z.string().nullable(),
previousVersion: z.string().nullable(),
newVersion: z.string().nullable(),
}),
});
export type DaemonUpdateResponse = z.infer<typeof DaemonUpdateResponseSchema>;
export const DaemonUpdateProgressMessageSchema = z.object({
type: z.literal("daemon.update.progress"),
payload: z.object({
requestId: z.string(),
phase: z.enum(["starting", "downloading", "installing", "complete"]),
}),
});
export const HubExecutionAgentCreateResponseSchema = z.object({
type: z.literal("hub.execution.agent.create.response"),
payload: z.object({
requestId: z.string(),
executionId: z.string(),
agentId: z.string().nullable(),
agent: AgentSnapshotPayloadSchema.nullable(),
success: z.boolean(),
error: z.string().nullable(),
}),
});
export const HubExecutionControlResponseSchema = z.object({
type: z.literal("hub.execution.control.response"),
payload: z.object({
requestId: z.string(),
executionId: z.string(),
action: HubExecutionControlActionSchema,
success: z.boolean(),
error: z.string().nullable(),
}),
});
export const HubExecutionAgentUpdateSchema = z.object({
type: z.literal("hub.execution.agent.update"),
payload: z.object({
executionId: z.string(),
agentId: z.string(),
agent: AgentSnapshotPayloadSchema,
}),
});
export const HubExecutionAgentStreamSchema = z.object({
type: z.literal("hub.execution.agent.stream"),
payload: z.object({
executionId: z.string(),
agentId: z.string(),
event: AgentStreamEventPayloadSchema,
}),
});
export type HubExecutionAgentCreateResponse = z.infer<typeof HubExecutionAgentCreateResponseSchema>;
export type HubExecutionControlResponse = z.infer<typeof HubExecutionControlResponseSchema>;
export type HubExecutionAgentUpdate = z.infer<typeof HubExecutionAgentUpdateSchema>;
export type HubExecutionAgentStream = z.infer<typeof HubExecutionAgentStreamSchema>;
export const HubExecutionOutboundMessageSchema = z.discriminatedUnion("type", [
HubExecutionAgentCreateResponseSchema,
HubExecutionControlResponseSchema,
HubExecutionAgentUpdateSchema,
HubExecutionAgentStreamSchema,
]);
export type HubExecutionOutboundMessage = z.infer<typeof HubExecutionOutboundMessageSchema>;
export class HubMessageCorrelationError extends Error {
constructor(messageType: HubExecutionOutboundMessage["type"]) {
super(`Hub message ${messageType} has mismatched agent correlation`);
this.name = "HubMessageCorrelationError";
}
}
export function parseHubExecutionOutboundMessage(value: unknown): HubExecutionOutboundMessage {
const message = HubExecutionOutboundMessageSchema.parse(value);
const payload = message.payload;
if (
"agent" in payload &&
payload.agent !== null &&
"agentId" in payload &&
payload.agentId !== null &&
payload.agent.id !== payload.agentId
) {
throw new HubMessageCorrelationError(message.type);
}
return message;
}
export type DaemonUpdateProgressMessage = z.infer<typeof DaemonUpdateProgressMessageSchema>;
export const SessionOutboundMessageSchema = z.discriminatedUnion("type", [
HubExecutionAgentCreateResponseSchema,
HubExecutionControlResponseSchema,
HubExecutionAgentUpdateSchema,
HubExecutionAgentStreamSchema,
BrowserAutomationExecuteRequestSchema,
ActivityLogMessageSchema,
AssistantChunkMessageSchema,
AudioOutputMessageSchema,
TranscriptionResultMessageSchema,
VoiceInputStateMessageSchema,
DictationStreamAckMessageSchema,
DictationStreamFinishAcceptedMessageSchema,
DictationStreamPartialMessageSchema,
DictationStreamFinalMessageSchema,
DictationStreamErrorMessageSchema,
StatusMessageSchema,
PongMessageSchema,
RpcErrorMessageSchema,
ArtifactMessageSchema,
AgentUpdateMessageSchema,
WorkspaceUpdateMessageSchema,
ProjectUpdateMessageSchema,
ProjectListResponseMessageSchema,
ScriptStatusUpdateMessageSchema,
WorkspaceSetupProgressMessageSchema,
WorkspaceSetupStatusResponseMessageSchema,
AgentStreamMessageSchema,
AgentStatusMessageSchema,
FetchAgentsResponseMessageSchema,
FetchAgentHistoryResponseMessageSchema,
FetchRecentProviderSessionsResponseMessageSchema,
FetchWorkspacesResponseMessageSchema,
ProjectAddResponseSchema,
ProjectCreateDirectoryResponseSchema,
OpenProjectResponseMessageSchema,
WorkspaceGithubSearchRepositoriesResponseSchema,
ProjectGithubCloneResponseSchema,
StartWorkspaceScriptResponseMessageSchema,
WorkspaceScriptListResponseMessageSchema,
WorkspaceScriptStartResponseMessageSchema,
WorkspaceScriptStopResponseMessageSchema,
LegacyListAvailableEditorsResponseMessageSchema,
LegacyOpenInEditorResponseMessageSchema,
ArchiveWorkspaceResponseMessageSchema,
FetchAgentResponseMessageSchema,
FetchAgentTimelineResponseMessageSchema,
ProviderSubagentListResponseMessageSchema,
ProviderSubagentTimelineResponseMessageSchema,
ProviderSubagentUpdateMessageSchema,
SetAgentTimelineSubscriptionResponseMessageSchema,
AgentAttentionRequiredMessageSchema,
AgentForkContextResponseMessageSchema,
CancelAgentResponseMessageSchema,
ClearAgentAttentionResponseMessageSchema,
WorkspaceCreateResponseSchema,
WorkspaceClearAttentionResponseSchema,
SendAgentMessageResponseMessageSchema,
SetVoiceModeResponseMessageSchema,
DaemonGetStatusResponseSchema,
DaemonGetPairingOfferResponseSchema,
HubManagementDaemonConnectResponseSchema,
HubManagementDaemonGetStatusResponseSchema,
HubManagementDaemonDisconnectResponseSchema,
DiagnosticsResponseSchema,
GetDaemonConfigResponseMessageSchema,
SetDaemonConfigResponseMessageSchema,
ReadProjectConfigResponseMessageSchema,
WriteProjectConfigResponseMessageSchema,
SetAgentModeResponseMessageSchema,
SetAgentModelResponseMessageSchema,
SetAgentThinkingResponseMessageSchema,
SetAgentFeatureResponseMessageSchema,
AgentDetachResponseMessageSchema,
AgentRewindResponseMessageSchema,
UpdateAgentResponseMessageSchema,
ProjectRenameResponseSchema,
ProjectRemoveResponseSchema,
WorkspaceTitleSetResponseSchema,
WorkspacePinSetResponseSchema,
WorkspaceRecoveryInspectResponseSchema,
WorkspaceRecoveryRestoreResponseSchema,
WaitForFinishResponseMessageSchema,
AgentPermissionRequestMessageSchema,
AgentPermissionResolvedMessageSchema,
AgentDeletedMessageSchema,
AgentArchivedMessageSchema,
CloseItemsResponseSchema,
CheckoutStatusResponseSchema,
CheckoutStatusUpdateSchema,
SubscribeCheckoutDiffResponseSchema,
CheckoutDiffUpdateSchema,
CheckoutCommitResponseSchema,
CheckoutMergeResponseSchema,
CheckoutMergeFromBaseResponseSchema,
CheckoutPullResponseSchema,
CheckoutPushResponseSchema,
CheckoutRefreshResponseSchema,
CheckoutPrCreateResponseSchema,
CheckoutPrMergeResponseSchema,
CheckoutForgeSetAutoMergeResponseSchema,
CheckoutGithubSetAutoMergeResponseSchema,
CheckoutCommitsListResponseSchema,
CheckoutCommitFileDiffResponseSchema,
CheckoutForgeGetCheckDetailsResponseSchema,
CheckoutGithubGetCheckDetailsResponseSchema,
CheckoutPrStatusResponseSchema,
PullRequestTimelineResponseSchema,
CheckoutSwitchBranchResponseSchema,
CheckoutRenameBranchResponseSchema,
StashSaveResponseSchema,
StashPopResponseSchema,
StashListResponseSchema,
ValidateBranchResponseSchema,
BranchSuggestionsResponseSchema,
ForgeSearchResponseSchema,
GitHubSearchResponseSchema,
DirectorySuggestionsResponseSchema,
PaseoWorktreeListResponseSchema,
PaseoWorktreeArchiveResponseSchema,
CreatePaseoWorktreeResponseSchema,
FileExplorerResponseSchema,
FileSubscribeResponseSchema,
FileUnsubscribeResponseSchema,
FileWriteResponseSchema,
FileUpdateSchema,
ProjectIconResponseSchema,
FileDownloadTokenResponseSchema,
FileUploadResponseSchema,
ListProviderModelsResponseMessageSchema,
ListProviderModesResponseMessageSchema,
ListProviderFeaturesResponseMessageSchema,
ListAvailableProvidersResponseSchema,
GetProvidersSnapshotResponseMessageSchema,
ProvidersSnapshotUpdateMessageSchema,
RefreshProvidersSnapshotResponseMessageSchema,
ProviderDiagnosticResponseMessageSchema,
ProviderUsageListResponseMessageSchema,
ListCommandsResponseSchema,
ListTerminalsResponseSchema,
TerminalsChangedSchema,
CreateTerminalResponseSchema,
RenameTerminalResponseSchema,
SubscribeTerminalResponseSchema,
KillTerminalResponseSchema,
CaptureTerminalResponseSchema,
TerminalStreamExitSchema,
TerminalAttentionRequiredSchema,
ChatCreateResponseSchema,
ChatListResponseSchema,
ChatInspectResponseSchema,
ChatDeleteResponseSchema,
ChatPostResponseSchema,
ChatReadResponseSchema,
ChatWaitResponseSchema,
ScheduleCreateResponseSchema,
ScheduleListResponseSchema,
ScheduleInspectResponseSchema,
ScheduleLogsResponseSchema,
SchedulePauseResponseSchema,
ScheduleResumeResponseSchema,
ScheduleDeleteResponseSchema,
ScheduleRunOnceResponseSchema,
ScheduleUpdateResponseSchema,
LoopRunResponseSchema,
LoopListResponseSchema,
LoopInspectResponseSchema,
LoopLogsResponseSchema,
LoopStopResponseSchema,
DaemonUpdateProgressMessageSchema,
DaemonUpdateResponseSchema,
]);
export type SessionOutboundMessage = z.infer<typeof SessionOutboundMessageSchema>;
// Type exports for individual message types
export type ActivityLogMessage = z.infer<typeof ActivityLogMessageSchema>;
export type AssistantChunkMessage = z.infer<typeof AssistantChunkMessageSchema>;
export type AudioOutputMessage = z.infer<typeof AudioOutputMessageSchema>;
export type TranscriptionResultMessage = z.infer<typeof TranscriptionResultMessageSchema>;
export type StatusMessage = z.infer<typeof StatusMessageSchema>;
export type ServerCapabilityState = z.infer<typeof ServerCapabilityStateSchema>;
export type ServerVoiceCapabilities = z.infer<typeof ServerVoiceCapabilitiesSchema>;
export type ServerCapabilities = z.infer<typeof ServerCapabilitiesSchema>;
export type ServerInfoStatusPayload = z.infer<typeof ServerInfoStatusPayloadSchema>;
export type RpcErrorMessage = z.infer<typeof RpcErrorMessageSchema>;
export type ArtifactMessage = z.infer<typeof ArtifactMessageSchema>;
export type AgentUpdateMessage = z.infer<typeof AgentUpdateMessageSchema>;
export type WorkspaceSetupProgressMessage = z.infer<typeof WorkspaceSetupProgressMessageSchema>;
export type WorkspaceSetupSnapshot = z.infer<typeof WorkspaceSetupSnapshotSchema>;
export type WorkspaceSetupStatusResponseMessage = z.infer<
typeof WorkspaceSetupStatusResponseMessageSchema
>;
export type AgentStreamMessage = z.infer<typeof AgentStreamMessageSchema>;
export type AgentStatusMessage = z.infer<typeof AgentStatusMessageSchema>;
export type ProjectCheckoutLitePayload = z.infer<typeof ProjectCheckoutLitePayloadSchema>;
export type ProjectPlacementPayload = z.infer<typeof ProjectPlacementPayloadSchema>;
export type WorkspaceStateBucket = z.infer<typeof WorkspaceStateBucketSchema>;
export type WorkspaceDescriptorPayload = z.infer<typeof WorkspaceDescriptorPayloadSchema>;
export type WorkspaceProjectDescriptorPayload = z.infer<
typeof WorkspaceProjectDescriptorPayloadSchema
>;
export type ProjectListResponseMessage = z.infer<typeof ProjectListResponseMessageSchema>;
export type WorkspaceScriptLifecycle = z.infer<typeof WorkspaceScriptLifecycleSchema>;
export type WorkspaceScriptHealth = z.infer<typeof WorkspaceScriptHealthSchema>;
export type WorkspaceScriptPayload = z.infer<typeof WorkspaceScriptPayloadSchema>;
export type FetchAgentsResponseMessage = z.infer<typeof FetchAgentsResponseMessageSchema>;
export type FetchAgentHistoryResponseMessage = z.infer<
typeof FetchAgentHistoryResponseMessageSchema
>;
export type FetchRecentProviderSessionsResponseMessage = z.infer<
typeof FetchRecentProviderSessionsResponseMessageSchema
>;
export type FetchWorkspacesResponseMessage = z.infer<typeof FetchWorkspacesResponseMessageSchema>;
export type ProjectAddResponse = z.infer<typeof ProjectAddResponseSchema>;
export type ProjectCreateDirectoryResponse = z.infer<typeof ProjectCreateDirectoryResponseSchema>;
export type ScriptStatusUpdateMessage = z.infer<typeof ScriptStatusUpdateMessageSchema>;
export type OpenProjectResponseMessage = z.infer<typeof OpenProjectResponseMessageSchema>;
export type WorkspaceGithubSearchRepositoriesResponse = z.infer<
typeof WorkspaceGithubSearchRepositoriesResponseSchema
>;
export type GithubRepository = z.infer<typeof GithubRepositorySchema>;
export type ProjectGithubCloneResponse = z.infer<typeof ProjectGithubCloneResponseSchema>;
export type StartWorkspaceScriptResponseMessage = z.infer<
typeof StartWorkspaceScriptResponseMessageSchema
>;
export type WorkspaceScriptListRequest = z.infer<typeof WorkspaceScriptListRequestSchema>;
export type WorkspaceScriptStartRequest = z.infer<typeof WorkspaceScriptStartRequestSchema>;
export type WorkspaceScriptStopRequest = z.infer<typeof WorkspaceScriptStopRequestSchema>;
export type WorkspaceScriptListResponseMessage = z.infer<
typeof WorkspaceScriptListResponseMessageSchema
>;
export type WorkspaceScriptStartResponseMessage = z.infer<
typeof WorkspaceScriptStartResponseMessageSchema
>;
export type WorkspaceScriptStopResponseMessage = z.infer<
typeof WorkspaceScriptStopResponseMessageSchema
>;
export type LegacyListAvailableEditorsResponseMessage = z.infer<
typeof LegacyListAvailableEditorsResponseMessageSchema
>;
export type LegacyOpenInEditorResponseMessage = z.infer<
typeof LegacyOpenInEditorResponseMessageSchema
>;
export type ArchiveWorkspaceResponseMessage = z.infer<typeof ArchiveWorkspaceResponseMessageSchema>;
export type FetchAgentResponseMessage = z.infer<typeof FetchAgentResponseMessageSchema>;
export type FetchAgentTimelineResponseMessage = z.infer<
typeof FetchAgentTimelineResponseMessageSchema
>;
export type AgentForkContextResponseMessage = z.infer<typeof AgentForkContextResponseMessageSchema>;
export type CancelAgentResponseMessage = z.infer<typeof CancelAgentResponseMessageSchema>;
export type SendAgentMessageResponseMessage = z.infer<typeof SendAgentMessageResponseMessageSchema>;
export type SetVoiceModeResponseMessage = z.infer<typeof SetVoiceModeResponseMessageSchema>;
export type SetAgentModeResponseMessage = z.infer<typeof SetAgentModeResponseMessageSchema>;
export type SetAgentModelResponseMessage = z.infer<typeof SetAgentModelResponseMessageSchema>;
export type SetAgentThinkingResponseMessage = z.infer<typeof SetAgentThinkingResponseMessageSchema>;
export type SetAgentFeatureResponseMessage = z.infer<typeof SetAgentFeatureResponseMessageSchema>;
export type AgentDetachResponseMessage = z.infer<typeof AgentDetachResponseMessageSchema>;
export type AgentRewindResponseMessage = z.infer<typeof AgentRewindResponseMessageSchema>;
export type UpdateAgentResponseMessage = z.infer<typeof UpdateAgentResponseMessageSchema>;
export type ProjectRenameResponse = z.infer<typeof ProjectRenameResponseSchema>;
export type ProjectRemoveResponse = z.infer<typeof ProjectRemoveResponseSchema>;
export type WorkspaceTitleSetResponse = z.infer<typeof WorkspaceTitleSetResponseSchema>;
export type WorkspaceTitleSetResponsePayload = z.infer<
typeof WorkspaceTitleSetResponsePayloadSchema
>;
export type WorkspacePinSetResponse = z.infer<typeof WorkspacePinSetResponseSchema>;
export type WorkspacePinSetResponsePayload = z.infer<typeof WorkspacePinSetResponsePayloadSchema>;
export type WorkspaceRecoveryState = z.infer<typeof WorkspaceRecoveryStateSchema>;
export type WorkspaceRecoveryInspectResponse = z.infer<
typeof WorkspaceRecoveryInspectResponseSchema
>;
export type WorkspaceRecoveryRestoreResponse = z.infer<
typeof WorkspaceRecoveryRestoreResponseSchema
>;
export type WorkspaceCreateRequest = z.infer<typeof WorkspaceCreateRequestSchema>;
export type WorkspaceCreateResponse = z.infer<typeof WorkspaceCreateResponseSchema>;
export type ProjectRenameResponsePayload = z.infer<typeof ProjectRenameResponsePayloadSchema>;
export type ProjectRemoveResponsePayload = z.infer<typeof ProjectRemoveResponsePayloadSchema>;
export type WaitForFinishResponseMessage = z.infer<typeof WaitForFinishResponseMessageSchema>;
export type AgentPermissionRequestMessage = z.infer<typeof AgentPermissionRequestMessageSchema>;
export type AgentPermissionResolvedMessage = z.infer<typeof AgentPermissionResolvedMessageSchema>;
export type AgentDeletedMessage = z.infer<typeof AgentDeletedMessageSchema>;
export type ListProviderModelsResponseMessage = z.infer<
typeof ListProviderModelsResponseMessageSchema
>;
export type ListProviderModesResponseMessage = z.infer<
typeof ListProviderModesResponseMessageSchema
>;
export type ListProviderFeaturesResponseMessage = z.infer<
typeof ListProviderFeaturesResponseMessageSchema
>;
export type ListAvailableProvidersResponse = z.infer<typeof ListAvailableProvidersResponseSchema>;
export type DaemonGetStatusResponse = z.infer<typeof DaemonGetStatusResponseSchema>;
export type DaemonGetPairingOfferResponse = z.infer<typeof DaemonGetPairingOfferResponseSchema>;
export type DiagnosticsResponse = z.infer<typeof DiagnosticsResponseSchema>;
export type GetProvidersSnapshotResponseMessage = z.infer<
typeof GetProvidersSnapshotResponseMessageSchema
>;
export type ProvidersSnapshotUpdateMessage = z.infer<typeof ProvidersSnapshotUpdateMessageSchema>;
export type RefreshProvidersSnapshotResponseMessage = z.infer<
typeof RefreshProvidersSnapshotResponseMessageSchema
>;
export type ProviderDiagnosticResponseMessage = z.infer<
typeof ProviderDiagnosticResponseMessageSchema
>;
export type ProviderUsageTone = z.infer<typeof ProviderUsageToneSchema>;
export type ProviderUsageStatus = z.infer<typeof ProviderUsageStatusSchema>;
export type ProviderUsage = z.infer<typeof ProviderUsageSchema>;
export type ProviderUsageWindow = z.infer<typeof ProviderUsageWindowSchema>;
export type ProviderUsageBalance = z.infer<typeof ProviderUsageBalanceSchema>;
export type ProviderUsageDetail = z.infer<typeof ProviderUsageDetailSchema>;
export type ProviderUsageListResponseMessage = z.infer<
typeof ProviderUsageListResponseMessageSchema
>;
export type ChatCreateResponse = z.infer<typeof ChatCreateResponseSchema>;
export type ChatListResponse = z.infer<typeof ChatListResponseSchema>;
export type ChatInspectResponse = z.infer<typeof ChatInspectResponseSchema>;
export type ChatDeleteResponse = z.infer<typeof ChatDeleteResponseSchema>;
export type ChatPostResponse = z.infer<typeof ChatPostResponseSchema>;
export type ChatReadResponse = z.infer<typeof ChatReadResponseSchema>;
export type ChatWaitResponse = z.infer<typeof ChatWaitResponseSchema>;
export type ScheduleCreateResponse = z.infer<typeof ScheduleCreateResponseSchema>;
export type ScheduleListResponse = z.infer<typeof ScheduleListResponseSchema>;
export type ScheduleInspectResponse = z.infer<typeof ScheduleInspectResponseSchema>;
export type ScheduleLogsResponse = z.infer<typeof ScheduleLogsResponseSchema>;
export type SchedulePauseResponse = z.infer<typeof SchedulePauseResponseSchema>;
export type ScheduleResumeResponse = z.infer<typeof ScheduleResumeResponseSchema>;
export type ScheduleDeleteResponse = z.infer<typeof ScheduleDeleteResponseSchema>;
export type ScheduleRunOnceResponse = z.infer<typeof ScheduleRunOnceResponseSchema>;
export type ScheduleUpdateResponse = z.infer<typeof ScheduleUpdateResponseSchema>;
export type LoopRunResponse = z.infer<typeof LoopRunResponseSchema>;
export type LoopListResponse = z.infer<typeof LoopListResponseSchema>;
export type LoopInspectResponse = z.infer<typeof LoopInspectResponseSchema>;
export type LoopLogsResponse = z.infer<typeof LoopLogsResponseSchema>;
export type LoopStopResponse = z.infer<typeof LoopStopResponseSchema>;
// Type exports for payload types
export type ActivityLogPayload = z.infer<typeof ActivityLogPayloadSchema>;
// Type exports for inbound message types
export type VoiceAudioChunkMessage = z.infer<typeof VoiceAudioChunkMessageSchema>;
export type FetchAgentsRequestMessage = z.infer<typeof FetchAgentsRequestMessageSchema>;
export type FetchAgentHistoryRequestMessage = z.infer<typeof FetchAgentHistoryRequestMessageSchema>;
export type FetchRecentProviderSessionsRequestMessage = z.infer<
typeof FetchRecentProviderSessionsRequestMessageSchema
>;
export type FetchWorkspacesRequestMessage = z.infer<typeof FetchWorkspacesRequestMessageSchema>;
export type ProjectListRequestMessage = z.infer<typeof ProjectListRequestMessageSchema>;
export type FetchAgentRequestMessage = z.infer<typeof FetchAgentRequestMessageSchema>;
export type AgentForkContextRequestMessage = z.infer<typeof AgentForkContextRequestMessageSchema>;
export type SendAgentMessageRequest = z.infer<typeof SendAgentMessageRequestSchema>;
export type WaitForFinishRequest = z.infer<typeof WaitForFinishRequestSchema>;
export type DictationStreamStartMessage = z.infer<typeof DictationStreamStartMessageSchema>;
export type DictationStreamChunkMessage = z.infer<typeof DictationStreamChunkMessageSchema>;
export type DictationStreamFinishMessage = z.infer<typeof DictationStreamFinishMessageSchema>;
export type DictationStreamCancelMessage = z.infer<typeof DictationStreamCancelMessageSchema>;
export type CreateAgentRequestMessage = z.infer<typeof CreateAgentRequestMessageSchema>;
export type AgentAttachment = z.infer<typeof AgentAttachmentSchema>;
export type ForgeChangeRequestAttachment = z.infer<typeof ForgeChangeRequestAttachmentSchema>;
export type ForgeIssueAttachment = z.infer<typeof ForgeIssueAttachmentSchema>;
export type UploadedFileAttachment = z.infer<typeof UploadedFileAttachmentSchema>;
export type FirstAgentContext = z.infer<typeof FirstAgentContextSchema>;
export type ReviewAttachment = z.infer<typeof ReviewAttachmentSchema>;
export type ListProviderModelsRequestMessage = z.infer<
typeof ListProviderModelsRequestMessageSchema
>;
export type ListProviderModesRequestMessage = z.infer<typeof ListProviderModesRequestMessageSchema>;
export type ListProviderFeaturesRequestMessage = z.infer<
typeof ListProviderFeaturesRequestMessageSchema
>;
export type ListAvailableProvidersRequestMessage = z.infer<
typeof ListAvailableProvidersRequestMessageSchema
>;
export type GetProvidersSnapshotRequestMessage = z.infer<
typeof GetProvidersSnapshotRequestMessageSchema
>;
export type RefreshProvidersSnapshotRequestMessage = z.infer<
typeof RefreshProvidersSnapshotRequestMessageSchema
>;
export type ProviderDiagnosticRequestMessage = z.infer<
typeof ProviderDiagnosticRequestMessageSchema
>;
export type ChatCreateRequest = z.infer<typeof ChatCreateRequestSchema>;
export type ChatListRequest = z.infer<typeof ChatListRequestSchema>;
export type ChatInspectRequest = z.infer<typeof ChatInspectRequestSchema>;
export type ChatDeleteRequest = z.infer<typeof ChatDeleteRequestSchema>;
export type ChatPostRequest = z.infer<typeof ChatPostRequestSchema>;
export type ChatReadRequest = z.infer<typeof ChatReadRequestSchema>;
export type ChatWaitRequest = z.infer<typeof ChatWaitRequestSchema>;
export type ScheduleCreateRequest = z.infer<typeof ScheduleCreateRequestSchema>;
export type ScheduleListRequest = z.infer<typeof ScheduleListRequestSchema>;
export type ScheduleInspectRequest = z.infer<typeof ScheduleInspectRequestSchema>;
export type ScheduleLogsRequest = z.infer<typeof ScheduleLogsRequestSchema>;
export type SchedulePauseRequest = z.infer<typeof SchedulePauseRequestSchema>;
export type ScheduleResumeRequest = z.infer<typeof ScheduleResumeRequestSchema>;
export type ScheduleDeleteRequest = z.infer<typeof ScheduleDeleteRequestSchema>;
export type ScheduleRunOnceRequest = z.infer<typeof ScheduleRunOnceRequestSchema>;
export type ScheduleUpdateRequest = z.infer<typeof ScheduleUpdateRequestSchema>;
export type LoopRunRequest = z.infer<typeof LoopRunRequestSchema>;
export type LoopListRequest = z.infer<typeof LoopListRequestSchema>;
export type LoopInspectRequest = z.infer<typeof LoopInspectRequestSchema>;
export type LoopLogsRequest = z.infer<typeof LoopLogsRequestSchema>;
export type LoopStopRequest = z.infer<typeof LoopStopRequestSchema>;
export type ResumeAgentRequestMessage = z.infer<typeof ResumeAgentRequestMessageSchema>;
export type DeleteAgentRequestMessage = z.infer<typeof DeleteAgentRequestMessageSchema>;
export type UpdateAgentRequestMessage = z.infer<typeof UpdateAgentRequestMessageSchema>;
export type ProjectRenameRequest = z.infer<typeof ProjectRenameRequestSchema>;
export type ProjectRemoveRequest = z.infer<typeof ProjectRemoveRequestSchema>;
export type WorkspaceTitleSetRequest = z.infer<typeof WorkspaceTitleSetRequestSchema>;
export type WorkspacePinSetRequest = z.infer<typeof WorkspacePinSetRequestSchema>;
export type WorkspaceRecoveryInspectRequest = z.infer<typeof WorkspaceRecoveryInspectRequestSchema>;
export type WorkspaceRecoveryRestoreRequest = z.infer<typeof WorkspaceRecoveryRestoreRequestSchema>;
export type SetAgentModeRequestMessage = z.infer<typeof SetAgentModeRequestMessageSchema>;
export type SetAgentModelRequestMessage = z.infer<typeof SetAgentModelRequestMessageSchema>;
export type SetAgentThinkingRequestMessage = z.infer<typeof SetAgentThinkingRequestMessageSchema>;
export type SetAgentFeatureRequestMessage = z.infer<typeof SetAgentFeatureRequestMessageSchema>;
export type AgentDetachRequestMessage = z.infer<typeof AgentDetachRequestMessageSchema>;
export type AgentPermissionResponseMessage = z.infer<typeof AgentPermissionResponseMessageSchema>;
export type CheckoutStatusRequest = z.infer<typeof CheckoutStatusRequestSchema>;
export type CheckoutStatusResponse = z.infer<typeof CheckoutStatusResponseSchema>;
export type CheckoutStatusUpdate = z.infer<typeof CheckoutStatusUpdateSchema>;
export type SubscribeCheckoutDiffRequest = z.infer<typeof SubscribeCheckoutDiffRequestSchema>;
export type UnsubscribeCheckoutDiffRequest = z.infer<typeof UnsubscribeCheckoutDiffRequestSchema>;
export type SubscribeCheckoutDiffResponse = z.infer<typeof SubscribeCheckoutDiffResponseSchema>;
export type CheckoutDiffUpdate = z.infer<typeof CheckoutDiffUpdateSchema>;
export type CheckoutCommitRequest = z.infer<typeof CheckoutCommitRequestSchema>;
export type CheckoutCommitResponse = z.infer<typeof CheckoutCommitResponseSchema>;
export type CheckoutMergeRequest = z.infer<typeof CheckoutMergeRequestSchema>;
export type CheckoutMergeResponse = z.infer<typeof CheckoutMergeResponseSchema>;
export type CheckoutMergeFromBaseRequest = z.infer<typeof CheckoutMergeFromBaseRequestSchema>;
export type CheckoutMergeFromBaseResponse = z.infer<typeof CheckoutMergeFromBaseResponseSchema>;
export type CheckoutPullRequest = z.infer<typeof CheckoutPullRequestSchema>;
export type CheckoutPullResponse = z.infer<typeof CheckoutPullResponseSchema>;
export type CheckoutPushRequest = z.infer<typeof CheckoutPushRequestSchema>;
export type CheckoutPushResponse = z.infer<typeof CheckoutPushResponseSchema>;
export type CheckoutRefreshRequest = z.infer<typeof CheckoutRefreshRequestSchema>;
export type CheckoutRefreshResponse = z.infer<typeof CheckoutRefreshResponseSchema>;
export type CheckoutCommitFile = z.infer<typeof CheckoutCommitFileSchema>;
export type CheckoutCommit = z.infer<typeof CheckoutCommitSchema>;
export type CheckoutCommitsListRequest = z.infer<typeof CheckoutCommitsListRequestSchema>;
export type CheckoutCommitsListResponse = z.infer<typeof CheckoutCommitsListResponseSchema>;
export type CheckoutCommitFileDiffRequest = z.infer<typeof CheckoutCommitFileDiffRequestSchema>;
export type CheckoutCommitFileDiffResponse = z.infer<typeof CheckoutCommitFileDiffResponseSchema>;
export type ParsedDiffFile = z.infer<typeof ParsedDiffFileSchema>;
export type CheckoutPrCreateRequest = z.infer<typeof CheckoutPrCreateRequestSchema>;
export type CheckoutPrCreateResponse = z.infer<typeof CheckoutPrCreateResponseSchema>;
export type CheckoutPrMergeRequest = z.infer<typeof CheckoutPrMergeRequestSchema>;
export type CheckoutPrMergeResponse = z.infer<typeof CheckoutPrMergeResponseSchema>;
export type CheckoutPrMergeMethod = z.infer<typeof CheckoutPrMergeRequestSchema>["mergeMethod"];
export type CheckoutForgeSetAutoMergeRequest = z.infer<
typeof CheckoutForgeSetAutoMergeRequestSchema
>;
export type CheckoutForgeSetAutoMergeResponse = z.infer<
typeof CheckoutForgeSetAutoMergeResponseSchema
>;
export type CheckoutGithubSetAutoMergeRequest = z.infer<
typeof CheckoutGithubSetAutoMergeRequestSchema
>;
export type CheckoutGithubSetAutoMergeResponse = z.infer<
typeof CheckoutGithubSetAutoMergeResponseSchema
>;
export type CheckoutForgeGetCheckDetailsRequest = z.infer<
typeof CheckoutForgeGetCheckDetailsRequestSchema
>;
export type CheckoutGithubGetCheckDetailsRequest = z.infer<
typeof CheckoutGithubGetCheckDetailsRequestSchema
>;
export type CheckoutCheckDetails = z.infer<typeof CheckoutCheckDetailsSchema>;
export type CheckoutGithubCheckDetails = z.infer<typeof CheckoutGithubCheckDetailsSchema>;
export type CheckoutPipeline = z.infer<typeof CheckoutPipelineSchema>;
export type CheckoutPipelineStage = z.infer<typeof CheckoutPipelineStageSchema>;
export type CheckoutPipelineJob = z.infer<typeof CheckoutPipelineJobSchema>;
export type CheckoutForgeGetCheckDetailsResponse = z.infer<
typeof CheckoutForgeGetCheckDetailsResponseSchema
>;
export type CheckoutGithubGetCheckDetailsResponse = z.infer<
typeof CheckoutGithubGetCheckDetailsResponseSchema
>;
export type PullRequestMergeable = z.infer<typeof CheckoutPrStatusSchema>["mergeable"];
export type CheckoutPrStatusRequest = z.infer<typeof CheckoutPrStatusRequestSchema>;
export type CheckoutPrStatusResponse = z.infer<typeof CheckoutPrStatusResponseSchema>;
export type PullRequestTimelineRequest = z.infer<typeof PullRequestTimelineRequestSchema>;
export type PullRequestTimelineItem = z.infer<typeof PullRequestTimelineItemSchema>;
export type PullRequestTimelineResponse = z.infer<typeof PullRequestTimelineResponseSchema>;
export type CheckoutSwitchBranchRequest = z.infer<typeof CheckoutSwitchBranchRequestSchema>;
export type CheckoutSwitchBranchResponse = z.infer<typeof CheckoutSwitchBranchResponseSchema>;
export type CheckoutRenameBranchRequest = z.infer<typeof CheckoutRenameBranchRequestSchema>;
export type CheckoutRenameBranchResponse = z.infer<typeof CheckoutRenameBranchResponseSchema>;
export type StashSaveRequest = z.infer<typeof StashSaveRequestSchema>;
export type StashSaveResponse = z.infer<typeof StashSaveResponseSchema>;
export type StashPopRequest = z.infer<typeof StashPopRequestSchema>;
export type StashPopResponse = z.infer<typeof StashPopResponseSchema>;
export type StashListRequest = z.infer<typeof StashListRequestSchema>;
export type StashListResponse = z.infer<typeof StashListResponseSchema>;
export type StashEntry = z.infer<typeof StashEntrySchema>;
export type ValidateBranchRequest = z.infer<typeof ValidateBranchRequestSchema>;
export type ValidateBranchResponse = z.infer<typeof ValidateBranchResponseSchema>;
export type BranchSuggestionsRequest = z.infer<typeof BranchSuggestionsRequestSchema>;
export type BranchSuggestionsResponse = z.infer<typeof BranchSuggestionsResponseSchema>;
export type ForgeSearchItem = z.infer<typeof ForgeSearchItemSchema>;
export type ForgeSearchKind = "issue" | "change_request";
export type ForgeSearchRequest = z.infer<typeof ForgeSearchRequestSchema>;
export type ForgeSearchResponse = z.infer<typeof ForgeSearchResponseSchema>;
export type GitHubSearchItem = z.infer<typeof GitHubSearchItemSchema>;
export type GitHubSearchKind = z.infer<typeof GitHubSearchKindSchema>;
export type GitHubSearchRequest = z.infer<typeof GitHubSearchRequestSchema>;
export type GitHubSearchResponse = z.infer<typeof GitHubSearchResponseSchema>;
export type ChangeRequestCheckoutSource = z.infer<typeof ChangeRequestCheckoutSourceSchema>;
export type CreatePaseoWorktreeRequest = z.infer<typeof CreatePaseoWorktreeRequestSchema>;
export type DirectorySuggestionsRequest = z.infer<typeof DirectorySuggestionsRequestSchema>;
export type DirectorySuggestionsResponse = z.infer<typeof DirectorySuggestionsResponseSchema>;
export type PaseoWorktreeListRequest = z.infer<typeof PaseoWorktreeListRequestSchema>;
export type PaseoWorktreeListResponse = z.infer<typeof PaseoWorktreeListResponseSchema>;
export type PaseoWorktreeArchiveRequest = z.infer<typeof PaseoWorktreeArchiveRequestSchema>;
export type PaseoWorktreeArchiveResponse = z.infer<typeof PaseoWorktreeArchiveResponseSchema>;
export type WorkspaceSetupStatusRequest = z.infer<typeof WorkspaceSetupStatusRequestSchema>;
export type LegacyListAvailableEditorsRequest = z.infer<
typeof LegacyListAvailableEditorsRequestSchema
>;
export type LegacyOpenInEditorRequest = z.infer<typeof LegacyOpenInEditorRequestSchema>;
export type OpenProjectRequest = z.infer<typeof OpenProjectRequestSchema>;
export type ProjectAddRequest = z.infer<typeof ProjectAddRequestSchema>;
export type ProjectCreateDirectoryRequest = z.infer<typeof ProjectCreateDirectoryRequestSchema>;
export type ProjectCreateDirectoryErrorCode = z.infer<typeof ProjectCreateDirectoryErrorCodeSchema>;
export type WorkspaceGithubSearchRepositoriesRequest = z.infer<
typeof WorkspaceGithubSearchRepositoriesRequestSchema
>;
export type ProjectGithubCloneRequest = z.infer<typeof ProjectGithubCloneRequestSchema>;
export type ProjectGithubCloneProtocol = z.infer<typeof ProjectGithubCloneProtocolSchema>;
export type ArchiveWorkspaceRequest = z.infer<typeof ArchiveWorkspaceRequestSchema>;
export type WorkspaceClearAttentionRequest = z.infer<typeof WorkspaceClearAttentionRequestSchema>;
export type FileExplorerRequest = z.infer<typeof FileExplorerRequestSchema>;
export type FileExplorerResponse = z.infer<typeof FileExplorerResponseSchema>;
export type FileVersion = z.infer<typeof FileVersionSchema>;
export type FileSubscribeRequest = z.infer<typeof FileSubscribeRequestSchema>;
export type FileSubscribeResponse = z.infer<typeof FileSubscribeResponseSchema>;
export type FileUnsubscribeRequest = z.infer<typeof FileUnsubscribeRequestSchema>;
export type FileUnsubscribeResponse = z.infer<typeof FileUnsubscribeResponseSchema>;
export type FileWriteRequest = z.infer<typeof FileWriteRequestSchema>;
export type FileWriteResponse = z.infer<typeof FileWriteResponseSchema>;
export type FileWriteResult = z.infer<typeof FileWriteResultSchema>;
export type FileUpdate = z.infer<typeof FileUpdateSchema>;
export type ProjectIconRequest = z.infer<typeof ProjectIconRequestSchema>;
export type ProjectIconResponse = z.infer<typeof ProjectIconResponseSchema>;
export type ProjectIcon = z.infer<typeof ProjectIconSchema>;
export type FileDownloadTokenRequest = z.infer<typeof FileDownloadTokenRequestSchema>;
export type FileDownloadTokenResponse = z.infer<typeof FileDownloadTokenResponseSchema>;
export type FileUploadRequest = z.infer<typeof FileUploadRequestSchema>;
export type FileUploadResponse = z.infer<typeof FileUploadResponseSchema>;
export type RestartServerRequestMessage = z.infer<typeof RestartServerRequestMessageSchema>;
export type ShutdownServerRequestMessage = z.infer<typeof ShutdownServerRequestMessageSchema>;
export type ClearAgentAttentionMessage = z.infer<typeof ClearAgentAttentionMessageSchema>;
export type ClearAgentAttentionResponseMessage = z.infer<
typeof ClearAgentAttentionResponseMessageSchema
>;
export type ClientHeartbeatMessage = z.infer<typeof ClientHeartbeatMessageSchema>;
export type ListCommandsRequest = z.infer<typeof ListCommandsRequestSchema>;
export type ListCommandsResponse = z.infer<typeof ListCommandsResponseSchema>;
export type RegisterPushTokenMessage = z.infer<typeof RegisterPushTokenMessageSchema>;
// Terminal message types
export type ListTerminalsRequest = z.infer<typeof ListTerminalsRequestSchema>;
export type ListTerminalsResponse = z.infer<typeof ListTerminalsResponseSchema>;
export type SubscribeTerminalsRequest = z.infer<typeof SubscribeTerminalsRequestSchema>;
export type UnsubscribeTerminalsRequest = z.infer<typeof UnsubscribeTerminalsRequestSchema>;
export type TerminalsChanged = z.infer<typeof TerminalsChangedSchema>;
export type CreateTerminalRequest = z.infer<typeof CreateTerminalRequestSchema>;
export type CreateTerminalResponse = z.infer<typeof CreateTerminalResponseSchema>;
export type RenameTerminalRequest = z.infer<typeof RenameTerminalRequestSchema>;
export type RenameTerminalResponse = z.infer<typeof RenameTerminalResponseSchema>;
export type StartWorkspaceScriptRequest = z.infer<typeof StartWorkspaceScriptRequestSchema>;
export type StartWorkspaceScriptResponse = z.infer<
typeof StartWorkspaceScriptResponseMessageSchema
>;
export type SubscribeTerminalRequest = z.infer<typeof SubscribeTerminalRequestSchema>;
export type SubscribeTerminalResponse = z.infer<typeof SubscribeTerminalResponseSchema>;
export type UnsubscribeTerminalRequest = z.infer<typeof UnsubscribeTerminalRequestSchema>;
export type TerminalInput = z.infer<typeof TerminalInputSchema>;
export type TerminalCell = z.infer<typeof TerminalCellSchema>;
export type TerminalCursorStyle = z.infer<typeof TerminalCursorStyleSchema>;
export type TerminalCursor = z.infer<typeof TerminalCursorSchema>;
export type TerminalState = z.infer<typeof TerminalStateSchema>;
export type CloseItemsRequest = z.infer<typeof CloseItemsRequestMessageSchema>;
export type CloseItemsResponse = z.infer<typeof CloseItemsResponseSchema>;
export type KillTerminalRequest = z.infer<typeof KillTerminalRequestSchema>;
export type KillTerminalResponse = z.infer<typeof KillTerminalResponseSchema>;
export type CaptureTerminalRequest = z.infer<typeof CaptureTerminalRequestSchema>;
export type CaptureTerminalResponse = z.infer<typeof CaptureTerminalResponseSchema>;
export type TerminalStreamExit = z.infer<typeof TerminalStreamExitSchema>;
// ============================================================================
// WebSocket Level Messages (wraps session messages)
// ============================================================================
// WebSocket-only messages (not session messages)
export const WSPingMessageSchema = z.object({
type: z.literal("ping"),
});
export const WSPongMessageSchema = z.object({
type: z.literal("pong"),
});
export const WSHelloMessageSchema = z.object({
type: z.literal("hello"),
clientId: z.string().min(1),
clientType: z.enum(["mobile", "browser", "cli", "mcp"]),
protocolVersion: z.number().int(),
appVersion: z.string().optional(),
capabilities: z
.object({
voice: z.boolean().optional(),
pushNotifications: z.boolean().optional(),
[CLIENT_CAPS.reasoningMergeEnum]: z.boolean().optional(),
[CLIENT_CAPS.selectiveAgentTimeline]: z.boolean().optional(),
[CLIENT_CAPS.customModeIcons]: z.boolean().optional(),
[CLIENT_CAPS.terminalReflowableSnapshot]: z.boolean().optional(),
[CLIENT_CAPS.providerSubagents]: z.boolean().optional(),
[CLIENT_CAPS.projectUpdates]: z.boolean().optional(),
[CLIENT_CAPS.browserHost]: BrowserAutomationHostCapabilitySchema.optional(),
})
.passthrough()
.optional(),
});
export const WSRecordingStateMessageSchema = z.object({
type: z.literal("recording_state"),
isRecording: z.boolean(),
});
// Wrapped session message
export const WSSessionInboundSchema = z.object({
type: z.literal("session"),
message: SessionInboundMessageSchema,
});
export const WSSessionOutboundSchema = z.object({
type: z.literal("session"),
message: SessionOutboundMessageSchema,
});
// Complete WebSocket message schemas
export const WSInboundMessageSchema = z.discriminatedUnion("type", [
WSPingMessageSchema,
WSHelloMessageSchema,
WSRecordingStateMessageSchema,
WSSessionInboundSchema,
]);
export const WSOutboundMessageSchema = z.discriminatedUnion("type", [
WSPongMessageSchema,
WSSessionOutboundSchema,
]);
export type WSInboundMessage = z.infer<typeof WSInboundMessageSchema>;
export type WSOutboundMessage = z.infer<typeof WSOutboundMessageSchema>;
export type WSHelloMessage = z.infer<typeof WSHelloMessageSchema>;
// ============================================================================
// Helper functions for message conversion
// ============================================================================
/**
* Extract session message from WebSocket message
* Returns null if message should be handled at WS level only
*/
export function extractSessionMessage(wsMsg: WSInboundMessage): SessionInboundMessage | null {
if (wsMsg.type === "session") {
return wsMsg.message;
}
// Ping and recording_state are WS-level only
return null;
}
/**
* Wrap session message in WebSocket envelope
*/
export function wrapSessionMessage(sessionMsg: SessionOutboundMessage): WSOutboundMessage {
return {
type: "session",
message: sessionMsg,
};
}
export function parseServerInfoStatusPayload(payload: unknown): ServerInfoStatusPayload | null {
const parsed = ServerInfoStatusPayloadSchema.safeParse(payload);
if (!parsed.success) {
return null;
}
return parsed.data;
}