consortium
Version:
Remote control and session sharing CLI for AI coding agents
1,414 lines (1,404 loc) • 61.7 kB
text/typescript
import { z } from 'zod';
import { EventEmitter } from 'node:events';
import { Socket } from 'socket.io-client';
import { ExpoPushMessage } from 'expo-server-sdk';
/**
* Simplified schema that only validates fields actually used in the codebase
* while preserving all other fields through passthrough()
*/
declare const UsageSchema: z.ZodObject<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>;
declare const RawJSONLinesSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
type: z.ZodLiteral<"user">;
isSidechain: z.ZodOptional<z.ZodBoolean>;
isMeta: z.ZodOptional<z.ZodBoolean>;
uuid: z.ZodString;
message: z.ZodObject<{
content: z.ZodUnion<[z.ZodString, z.ZodAny]>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
content: z.ZodUnion<[z.ZodString, z.ZodAny]>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
content: z.ZodUnion<[z.ZodString, z.ZodAny]>;
}, z.ZodTypeAny, "passthrough">>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
type: z.ZodLiteral<"user">;
isSidechain: z.ZodOptional<z.ZodBoolean>;
isMeta: z.ZodOptional<z.ZodBoolean>;
uuid: z.ZodString;
message: z.ZodObject<{
content: z.ZodUnion<[z.ZodString, z.ZodAny]>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
content: z.ZodUnion<[z.ZodString, z.ZodAny]>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
content: z.ZodUnion<[z.ZodString, z.ZodAny]>;
}, z.ZodTypeAny, "passthrough">>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
type: z.ZodLiteral<"user">;
isSidechain: z.ZodOptional<z.ZodBoolean>;
isMeta: z.ZodOptional<z.ZodBoolean>;
uuid: z.ZodString;
message: z.ZodObject<{
content: z.ZodUnion<[z.ZodString, z.ZodAny]>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
content: z.ZodUnion<[z.ZodString, z.ZodAny]>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
content: z.ZodUnion<[z.ZodString, z.ZodAny]>;
}, z.ZodTypeAny, "passthrough">>;
}, z.ZodTypeAny, "passthrough">>, z.ZodObject<{
uuid: z.ZodString;
type: z.ZodLiteral<"assistant">;
message: z.ZodOptional<z.ZodObject<{
usage: z.ZodOptional<z.ZodObject<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
model: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
usage: z.ZodOptional<z.ZodObject<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
model: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
usage: z.ZodOptional<z.ZodObject<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
model: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
uuid: z.ZodString;
type: z.ZodLiteral<"assistant">;
message: z.ZodOptional<z.ZodObject<{
usage: z.ZodOptional<z.ZodObject<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
model: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
usage: z.ZodOptional<z.ZodObject<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
model: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
usage: z.ZodOptional<z.ZodObject<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
model: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
uuid: z.ZodString;
type: z.ZodLiteral<"assistant">;
message: z.ZodOptional<z.ZodObject<{
usage: z.ZodOptional<z.ZodObject<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
model: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
usage: z.ZodOptional<z.ZodObject<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
model: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
usage: z.ZodOptional<z.ZodObject<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
input_tokens: z.ZodNumber;
cache_creation_input_tokens: z.ZodOptional<z.ZodNumber>;
cache_read_input_tokens: z.ZodOptional<z.ZodNumber>;
output_tokens: z.ZodNumber;
service_tier: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
model: z.ZodOptional<z.ZodString>;
}, z.ZodTypeAny, "passthrough">>>;
}, z.ZodTypeAny, "passthrough">>, z.ZodObject<{
type: z.ZodLiteral<"summary">;
summary: z.ZodString;
leafUuid: z.ZodString;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
type: z.ZodLiteral<"summary">;
summary: z.ZodString;
leafUuid: z.ZodString;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
type: z.ZodLiteral<"summary">;
summary: z.ZodString;
leafUuid: z.ZodString;
}, z.ZodTypeAny, "passthrough">>, z.ZodObject<{
type: z.ZodLiteral<"system">;
uuid: z.ZodString;
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
type: z.ZodLiteral<"system">;
uuid: z.ZodString;
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
type: z.ZodLiteral<"system">;
uuid: z.ZodString;
}, z.ZodTypeAny, "passthrough">>]>;
type RawJSONLines = z.infer<typeof RawJSONLinesSchema>;
/**
* Permission mode type - includes both Claude and Codex modes
* Must match MessageMetaSchema.permissionMode enum values
*
* Claude modes: default, acceptEdits, bypassPermissions, plan
* Codex modes: read-only, safe-yolo, yolo
*
* When calling Claude SDK, Codex modes are mapped at the SDK boundary:
* - yolo → bypassPermissions
* - safe-yolo → default
* - read-only → default
*/
type PermissionMode = 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan' | 'read-only' | 'safe-yolo' | 'yolo';
/**
* Usage data type from Claude
*/
type Usage = z.infer<typeof UsageSchema>;
/**
* Update event from server
*/
declare const UpdateSchema: z.ZodObject<{
id: z.ZodString;
seq: z.ZodNumber;
body: z.ZodUnion<[z.ZodObject<{
message: z.ZodObject<{
id: z.ZodString;
seq: z.ZodNumber;
content: z.ZodObject<{
c: z.ZodString;
t: z.ZodLiteral<"encrypted">;
}, "strip", z.ZodTypeAny, {
c: string;
t: "encrypted";
}, {
c: string;
t: "encrypted";
}>;
}, "strip", z.ZodTypeAny, {
content: {
c: string;
t: "encrypted";
};
id: string;
seq: number;
}, {
content: {
c: string;
t: "encrypted";
};
id: string;
seq: number;
}>;
sid: z.ZodString;
t: z.ZodLiteral<"new-message">;
}, "strip", z.ZodTypeAny, {
message: {
content: {
c: string;
t: "encrypted";
};
id: string;
seq: number;
};
t: "new-message";
sid: string;
}, {
message: {
content: {
c: string;
t: "encrypted";
};
id: string;
seq: number;
};
t: "new-message";
sid: string;
}>, z.ZodObject<{
t: z.ZodLiteral<"update-session">;
sid: z.ZodString;
metadata: z.ZodOptional<z.ZodNullable<z.ZodObject<{
version: z.ZodNumber;
value: z.ZodString;
}, "strip", z.ZodTypeAny, {
value: string;
version: number;
}, {
value: string;
version: number;
}>>>;
agentState: z.ZodOptional<z.ZodNullable<z.ZodObject<{
version: z.ZodNumber;
value: z.ZodString;
}, "strip", z.ZodTypeAny, {
value: string;
version: number;
}, {
value: string;
version: number;
}>>>;
}, "strip", z.ZodTypeAny, {
t: "update-session";
sid: string;
metadata?: {
value: string;
version: number;
} | null | undefined;
agentState?: {
value: string;
version: number;
} | null | undefined;
}, {
t: "update-session";
sid: string;
metadata?: {
value: string;
version: number;
} | null | undefined;
agentState?: {
value: string;
version: number;
} | null | undefined;
}>, z.ZodObject<{
t: z.ZodLiteral<"update-machine">;
machineId: z.ZodString;
metadata: z.ZodOptional<z.ZodNullable<z.ZodObject<{
version: z.ZodNumber;
value: z.ZodString;
}, "strip", z.ZodTypeAny, {
value: string;
version: number;
}, {
value: string;
version: number;
}>>>;
daemonState: z.ZodOptional<z.ZodNullable<z.ZodObject<{
version: z.ZodNumber;
value: z.ZodString;
}, "strip", z.ZodTypeAny, {
value: string;
version: number;
}, {
value: string;
version: number;
}>>>;
}, "strip", z.ZodTypeAny, {
t: "update-machine";
machineId: string;
metadata?: {
value: string;
version: number;
} | null | undefined;
daemonState?: {
value: string;
version: number;
} | null | undefined;
}, {
t: "update-machine";
machineId: string;
metadata?: {
value: string;
version: number;
} | null | undefined;
daemonState?: {
value: string;
version: number;
} | null | undefined;
}>]>;
createdAt: z.ZodNumber;
}, "strip", z.ZodTypeAny, {
id: string;
seq: number;
body: {
message: {
content: {
c: string;
t: "encrypted";
};
id: string;
seq: number;
};
t: "new-message";
sid: string;
} | {
t: "update-session";
sid: string;
metadata?: {
value: string;
version: number;
} | null | undefined;
agentState?: {
value: string;
version: number;
} | null | undefined;
} | {
t: "update-machine";
machineId: string;
metadata?: {
value: string;
version: number;
} | null | undefined;
daemonState?: {
value: string;
version: number;
} | null | undefined;
};
createdAt: number;
}, {
id: string;
seq: number;
body: {
message: {
content: {
c: string;
t: "encrypted";
};
id: string;
seq: number;
};
t: "new-message";
sid: string;
} | {
t: "update-session";
sid: string;
metadata?: {
value: string;
version: number;
} | null | undefined;
agentState?: {
value: string;
version: number;
} | null | undefined;
} | {
t: "update-machine";
machineId: string;
metadata?: {
value: string;
version: number;
} | null | undefined;
daemonState?: {
value: string;
version: number;
} | null | undefined;
};
createdAt: number;
}>;
type Update = z.infer<typeof UpdateSchema>;
/**
* Session information
*/
type Session = {
id: string;
/**
* Server-side idempotency tag for this session. Two `getOrCreateSession`
* calls with the same `tag` return the same row, so callers who want
* to resume an existing session (e.g. `consortium code --resume <id>`)
* must pass the original tag — not a fresh random one. Surfacing it
* here so the TUI wizard can hand it to the spawned agent process.
*/
tag: string;
seq: number;
encryptionKey: Uint8Array;
encryptionVariant: 'legacy' | 'dataKey';
metadata: Metadata;
metadataVersion: number;
agentState: AgentState | null;
agentStateVersion: number;
};
/**
* Machine metadata - static information (rarely changes)
*/
declare const MachineMetadataSchema: z.ZodObject<{
host: z.ZodString;
platform: z.ZodString;
consortiumCliVersion: z.ZodString;
homeDir: z.ZodString;
consortiumHomeDir: z.ZodString;
consortiumLibDir: z.ZodString;
cpuCount: z.ZodOptional<z.ZodNumber>;
memoryTotalMb: z.ZodOptional<z.ZodNumber>;
openclawInstalled: z.ZodOptional<z.ZodBoolean>;
openclawVersion: z.ZodOptional<z.ZodNullable<z.ZodString>>;
openclawWorkspaceExists: z.ZodOptional<z.ZodBoolean>;
openclawGatewayRunning: z.ZodOptional<z.ZodBoolean>;
openclawGatewayPort: z.ZodOptional<z.ZodNumber>;
openclawChannels: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
openclawAgentCount: z.ZodOptional<z.ZodNumber>;
openclawAgents: z.ZodOptional<z.ZodArray<z.ZodObject<{
name: z.ZodString;
workspace: z.ZodString;
agentDir: z.ZodString;
model: z.ZodString;
routingRules: z.ZodNumber;
isDefault: z.ZodBoolean;
}, "strip", z.ZodTypeAny, {
model: string;
name: string;
workspace: string;
agentDir: string;
routingRules: number;
isDefault: boolean;
}, {
model: string;
name: string;
workspace: string;
agentDir: string;
routingRules: number;
isDefault: boolean;
}>, "many">>;
terminalCapabilities: z.ZodOptional<z.ZodObject<{
tmux: z.ZodBoolean;
zellij: z.ZodBoolean;
}, "strip", z.ZodTypeAny, {
tmux: boolean;
zellij: boolean;
}, {
tmux: boolean;
zellij: boolean;
}>>;
}, "strip", z.ZodTypeAny, {
host: string;
platform: string;
consortiumCliVersion: string;
homeDir: string;
consortiumHomeDir: string;
consortiumLibDir: string;
cpuCount?: number | undefined;
memoryTotalMb?: number | undefined;
openclawInstalled?: boolean | undefined;
openclawVersion?: string | null | undefined;
openclawWorkspaceExists?: boolean | undefined;
openclawGatewayRunning?: boolean | undefined;
openclawGatewayPort?: number | undefined;
openclawChannels?: string[] | undefined;
openclawAgentCount?: number | undefined;
openclawAgents?: {
model: string;
name: string;
workspace: string;
agentDir: string;
routingRules: number;
isDefault: boolean;
}[] | undefined;
terminalCapabilities?: {
tmux: boolean;
zellij: boolean;
} | undefined;
}, {
host: string;
platform: string;
consortiumCliVersion: string;
homeDir: string;
consortiumHomeDir: string;
consortiumLibDir: string;
cpuCount?: number | undefined;
memoryTotalMb?: number | undefined;
openclawInstalled?: boolean | undefined;
openclawVersion?: string | null | undefined;
openclawWorkspaceExists?: boolean | undefined;
openclawGatewayRunning?: boolean | undefined;
openclawGatewayPort?: number | undefined;
openclawChannels?: string[] | undefined;
openclawAgentCount?: number | undefined;
openclawAgents?: {
model: string;
name: string;
workspace: string;
agentDir: string;
routingRules: number;
isDefault: boolean;
}[] | undefined;
terminalCapabilities?: {
tmux: boolean;
zellij: boolean;
} | undefined;
}>;
type MachineMetadata = z.infer<typeof MachineMetadataSchema>;
/**
* Daemon state - dynamic runtime information (frequently updated)
*/
declare const DaemonStateSchema: z.ZodObject<{
status: z.ZodUnion<[z.ZodEnum<["running", "shutting-down"]>, z.ZodString]>;
pid: z.ZodOptional<z.ZodNumber>;
httpPort: z.ZodOptional<z.ZodNumber>;
startedAt: z.ZodOptional<z.ZodNumber>;
shutdownRequestedAt: z.ZodOptional<z.ZodNumber>;
shutdownSource: z.ZodOptional<z.ZodUnion<[z.ZodEnum<["mobile-app", "cli", "os-signal", "unknown"]>, z.ZodString]>>;
}, "strip", z.ZodTypeAny, {
status: string;
pid?: number | undefined;
httpPort?: number | undefined;
startedAt?: number | undefined;
shutdownRequestedAt?: number | undefined;
shutdownSource?: string | undefined;
}, {
status: string;
pid?: number | undefined;
httpPort?: number | undefined;
startedAt?: number | undefined;
shutdownRequestedAt?: number | undefined;
shutdownSource?: string | undefined;
}>;
type DaemonState = z.infer<typeof DaemonStateSchema>;
type Machine = {
id: string;
encryptionKey: Uint8Array;
encryptionVariant: 'legacy' | 'dataKey';
metadata: MachineMetadata;
metadataVersion: number;
daemonState: DaemonState | null;
daemonStateVersion: number;
};
declare const UserMessageSchema: z.ZodObject<{
role: z.ZodLiteral<"user">;
content: z.ZodObject<{
type: z.ZodLiteral<"text">;
text: z.ZodString;
attachmentIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
localId: z.ZodOptional<z.ZodString>;
driveId: z.ZodOptional<z.ZodString>;
driveNodeIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
driveDek: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
type: "text";
text: string;
attachmentIds?: string[] | undefined;
localId?: string | undefined;
driveId?: string | undefined;
driveNodeIds?: string[] | undefined;
driveDek?: string | undefined;
}, {
type: "text";
text: string;
attachmentIds?: string[] | undefined;
localId?: string | undefined;
driveId?: string | undefined;
driveNodeIds?: string[] | undefined;
driveDek?: string | undefined;
}>;
localKey: z.ZodOptional<z.ZodString>;
meta: z.ZodOptional<z.ZodObject<{
sentFrom: z.ZodOptional<z.ZodString>;
permissionMode: z.ZodOptional<z.ZodEnum<["default", "acceptEdits", "bypassPermissions", "plan", "read-only", "safe-yolo", "yolo"]>>;
model: z.ZodOptional<z.ZodNullable<z.ZodString>>;
fallbackModel: z.ZodOptional<z.ZodNullable<z.ZodString>>;
customSystemPrompt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
appendSystemPrompt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
allowedTools: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
disallowedTools: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
}, "strip", z.ZodTypeAny, {
model?: string | null | undefined;
sentFrom?: string | undefined;
permissionMode?: "default" | "acceptEdits" | "bypassPermissions" | "plan" | "read-only" | "safe-yolo" | "yolo" | undefined;
fallbackModel?: string | null | undefined;
customSystemPrompt?: string | null | undefined;
appendSystemPrompt?: string | null | undefined;
allowedTools?: string[] | null | undefined;
disallowedTools?: string[] | null | undefined;
}, {
model?: string | null | undefined;
sentFrom?: string | undefined;
permissionMode?: "default" | "acceptEdits" | "bypassPermissions" | "plan" | "read-only" | "safe-yolo" | "yolo" | undefined;
fallbackModel?: string | null | undefined;
customSystemPrompt?: string | null | undefined;
appendSystemPrompt?: string | null | undefined;
allowedTools?: string[] | null | undefined;
disallowedTools?: string[] | null | undefined;
}>>;
attachmentIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
localId: z.ZodOptional<z.ZodString>;
driveId: z.ZodOptional<z.ZodString>;
driveDek: z.ZodOptional<z.ZodString>;
}, "strip", z.ZodTypeAny, {
content: {
type: "text";
text: string;
attachmentIds?: string[] | undefined;
localId?: string | undefined;
driveId?: string | undefined;
driveNodeIds?: string[] | undefined;
driveDek?: string | undefined;
};
role: "user";
attachmentIds?: string[] | undefined;
localId?: string | undefined;
driveId?: string | undefined;
driveDek?: string | undefined;
localKey?: string | undefined;
meta?: {
model?: string | null | undefined;
sentFrom?: string | undefined;
permissionMode?: "default" | "acceptEdits" | "bypassPermissions" | "plan" | "read-only" | "safe-yolo" | "yolo" | undefined;
fallbackModel?: string | null | undefined;
customSystemPrompt?: string | null | undefined;
appendSystemPrompt?: string | null | undefined;
allowedTools?: string[] | null | undefined;
disallowedTools?: string[] | null | undefined;
} | undefined;
}, {
content: {
type: "text";
text: string;
attachmentIds?: string[] | undefined;
localId?: string | undefined;
driveId?: string | undefined;
driveNodeIds?: string[] | undefined;
driveDek?: string | undefined;
};
role: "user";
attachmentIds?: string[] | undefined;
localId?: string | undefined;
driveId?: string | undefined;
driveDek?: string | undefined;
localKey?: string | undefined;
meta?: {
model?: string | null | undefined;
sentFrom?: string | undefined;
permissionMode?: "default" | "acceptEdits" | "bypassPermissions" | "plan" | "read-only" | "safe-yolo" | "yolo" | undefined;
fallbackModel?: string | null | undefined;
customSystemPrompt?: string | null | undefined;
appendSystemPrompt?: string | null | undefined;
allowedTools?: string[] | null | undefined;
disallowedTools?: string[] | null | undefined;
} | undefined;
}>;
type UserMessage = z.infer<typeof UserMessageSchema>;
type Metadata = {
path: string;
host: string;
version?: string;
name?: string;
os?: string;
summary?: {
text: string;
updatedAt: number;
};
machineId?: string;
claudeSessionId?: string;
agentSessionId?: string;
codexRolloutPath?: string;
tools?: string[];
slashCommands?: string[];
homeDir: string;
consortiumHomeDir: string;
consortiumLibDir: string;
consortiumToolsDir: string;
startedFromDaemon?: boolean;
hostPid?: number;
startedBy?: 'daemon' | 'terminal';
lifecycleState?: 'running' | 'archiveRequested' | 'archived' | string;
lifecycleStateSince?: number;
archivedBy?: string;
archiveReason?: string;
flavor?: string;
firstMessage?: string;
/** Resolved model id (cli-set; Pi updates per message_start). */
model?: string;
/** Resolved provider id (cli-set alongside `model`). */
provider?: string;
};
type AgentState = {
controlledByUser?: boolean | null | undefined;
requests?: {
[id: string]: {
tool: string;
arguments: any;
createdAt: number;
};
};
completedRequests?: {
[id: string]: {
tool: string;
arguments: any;
createdAt: number;
completedAt: number;
status: 'canceled' | 'denied' | 'approved';
reason?: string;
mode?: PermissionMode;
decision?: 'approved' | 'approved_for_session' | 'denied' | 'abort';
allowTools?: string[];
};
};
};
/**
* Common RPC types and interfaces for both session and machine clients
*/
/**
* Generic RPC handler function type
* @template TRequest - The request data type
* @template TResponse - The response data type
*/
type RpcHandler<TRequest = any, TResponse = any> = (data: TRequest) => TResponse | Promise<TResponse>;
/**
* RPC request data from server
*/
interface RpcRequest {
method: string;
params: string;
}
/**
* Configuration for RPC handler manager
*/
interface RpcHandlerConfig {
scopePrefix: string;
encryptionKey: Uint8Array;
encryptionVariant: 'legacy' | 'dataKey';
logger?: (message: string, data?: any) => void;
}
/**
* Generic RPC handler manager for session and machine clients
* Manages RPC method registration, encryption/decryption, and handler execution
*/
declare class RpcHandlerManager {
private handlers;
private readonly scopePrefix;
private readonly encryptionKey;
private readonly encryptionVariant;
private readonly logger;
private socket;
constructor(config: RpcHandlerConfig);
/**
* Register an RPC handler for a specific method
* @param method - The method name (without prefix)
* @param handler - The handler function
*/
registerHandler<TRequest = any, TResponse = any>(method: string, handler: RpcHandler<TRequest, TResponse>): void;
/**
* Handle an incoming RPC request
* @param request - The RPC request data
* @param callback - The response callback
*/
handleRequest(request: RpcRequest): Promise<any>;
onSocketConnect(socket: Socket): Promise<void>;
onSocketDisconnect(): void;
/**
* Get the number of registered handlers
*/
getHandlerCount(): number;
/**
* Check if a handler is registered
* @param method - The method name (without prefix)
*/
hasHandler(method: string): boolean;
/**
* Invoke a registered handler in-process with already-decrypted params.
* Used by the generic harness dispatcher to fall through to a legacy
* per-harness RPC (e.g. `openclaw-agent-add`) when the harness provider
* doesn't expose the dispatcher-facing method directly.
*/
callLocal<TRequest = any, TResponse = any>(method: string, params: TRequest): Promise<TResponse | undefined>;
/**
* Clear all handlers
*/
clearHandlers(): void;
/**
* Get the prefixed method name
* @param method - The method name
*/
private getPrefixedMethod;
}
/**
* ACP (Agent Communication Protocol) message data types.
* This is the unified format for all agent messages - CLI adapts each provider's format to ACP.
*/
type ACPMessageData = {
type: 'message';
message: string;
} | {
type: 'reasoning';
message: string;
} | {
type: 'thinking';
text: string;
} | {
type: 'tool-call';
callId: string;
name: string;
input: unknown;
id: string;
} | {
type: 'tool-result';
callId: string;
output: unknown;
id: string;
isError?: boolean;
} | {
type: 'file-edit';
description: string;
filePath: string;
diff?: string;
oldContent?: string;
newContent?: string;
id: string;
} | {
type: 'terminal-output';
data: string;
callId: string;
} | {
type: 'task_started';
id: string;
} | {
type: 'task_complete';
id: string;
} | {
type: 'turn_aborted';
id: string;
} | {
type: 'permission-request';
permissionId: string;
toolName: string;
description: string;
options?: unknown;
} | {
type: 'artifact';
artifactId: string;
mime: string;
name?: string;
sizeBytes?: number;
} | {
type: 'token_count';
[key: string]: unknown;
};
type ACPProvider = 'gemini' | 'grok' | 'pi' | 'codex' | 'claude' | 'consortium-code';
declare class ApiSessionClient extends EventEmitter {
private readonly token;
readonly sessionId: string;
private metadata;
private metadataVersion;
private agentState;
private agentStateVersion;
private socket;
private pendingMessages;
private pendingMessageCallback;
readonly rpcHandlerManager: RpcHandlerManager;
private agentStateLock;
private metadataLock;
private encryptionKey;
private encryptionVariant;
private lastClaudeModel;
private pendingEmits;
private static readonly MAX_PENDING_EMITS;
private reconnectTimer;
private manualReconnectAttempts;
private destroyed;
private flushWatchdog;
private static readonly FLUSH_WATCHDOG_MS;
/** Get encryption details for passing to child processes. */
getEncryptionDetails(): {
key: Uint8Array;
variant: 'legacy' | 'dataKey';
};
/**
* Upload an agent-produced media blob to the server as a SessionArtifact.
*
* Phase 1: bytes are POSTed as base64 *plaintext*. The S3 path is in a
* `private/` prefix, served only via short-lived presigned URLs to
* authenticated session owners — same security model as
* SupportTicketAttachment. Phase 1.5 will layer client-side encryption
* with libsodium secretbox under the session data key (the primitive is
* already used by Drive content, so it's cross-platform on both sides).
*
* Returns the artifact id and metadata so the caller can immediately
* reference it in an outgoing agent message
* (`{ type: 'artifact', artifactId, mime }`).
*/
uploadArtifact(args: {
bytes: Uint8Array;
mime: string;
}): Promise<{
id: string;
mime: string;
sizeBytes: number;
}>;
constructor(token: string, session: Session);
onUserMessage(callback: (data: UserMessage) => void): void;
/**
* Emit a 'message' payload, buffering it if the socket is currently
* disconnected. Drained on the next 'connect' event.
*/
private reliableEmitMessage;
private flushPendingEmits;
/**
* Send message to session
* @param body - Message body (can be MessageContent or raw content for agent messages)
*/
sendClaudeSessionMessage(body: RawJSONLines): void;
sendCodexMessage(body: any): void;
/**
* Send a generic agent message to the session using ACP (Agent Communication Protocol) format.
* Works for any agent type (Gemini, Codex, Claude, etc.) - CLI normalizes to unified ACP format.
*
* @param provider - The agent provider sending the message (e.g., 'gemini', 'codex', 'claude')
* @param body - The message payload (type: 'message' | 'reasoning' | 'tool-call' | 'tool-result')
*/
/**
* Send a user message to the session, rendered as a chat bubble on the web client.
* Used to mirror terminal TUI input to the web session.
*/
sendUserChatMessage(text: string): void;
sendAgentMessage(provider: ACPProvider, body: ACPMessageData): void;
sendSessionEvent(event: {
type: 'switch';
mode: 'local' | 'remote';
} | {
type: 'message';
message: string;
} | {
type: 'permission-mode-changed';
mode: 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan';
} | {
type: 'ready';
}, id?: string): void;
/**
* Send a ping message to keep the connection alive
*/
keepAlive(thinking: boolean, mode: 'local' | 'remote'): void;
/**
* Send session death message
*/
sendSessionDeath(): void;
/**
* Infers the LLM provider ID from a model name string.
*/
private inferProvider;
/**
* Detects the usage mode based on environment variables.
* If base URL points to the consortium proxy, it's managed mode.
* Otherwise defaults to wrapped (backward-compatible).
*/
private detectUsageMode;
/**
* Send usage data to the server
*/
sendUsageData(usage: Usage, model?: string): void;
/**
* Update session metadata
* @param handler - Handler function that returns the updated metadata
*/
updateMetadata(handler: (metadata: Metadata) => Metadata): void;
/**
* Update session agent state
* @param handler - Handler function that returns the updated agent state
*/
updateAgentState(handler: (metadata: AgentState) => AgentState): void;
/**
* Wait for socket buffer to flush
*/
flush(): Promise<void>;
close(): Promise<void>;
/**
* Schedule a manual reconnect after a connect_error. Mirrors
* ApiMachineClient.scheduleManualReconnect; see comment there for the
* Socket.IO middleware-rejection rationale. Session sockets don't
* carry their own refresh path — the session token comes from the
* parent process, so the only thing we can do here is retry with
* the existing token until it works (or until close() is called).
*/
private scheduleManualReconnect;
}
/**
* Shared types for the persistent terminal multiplexer subsystem.
*
* TerminalBackend is the common interface implemented by tmux, zellij, and
* the fallback ephemeral (node-pty) backend. TerminalManager owns backend
* instances and dispatches I/O through them.
*/
type TerminalMode = 'tmux' | 'zellij' | 'ephemeral';
type TerminalStatus = 'running' | 'exited';
interface TerminalDescriptor {
id: string;
mode: TerminalMode;
status: TerminalStatus;
/** Epoch ms; best-effort, may be 0 if unknown post-restart */
createdAt: number;
}
interface SpawnSessionOptions {
machineId?: string;
directory: string;
sessionId?: string;
approvedNewDirectoryCreation?: boolean;
agent?: 'claude' | 'codex' | 'gemini' | 'grok' | 'pi' | 'consortium-code';
token?: string;
/** Start as Project Manager agent with session orchestration tools */
pmMode?: boolean;
/** When true, create a worktree before spawning the agent process */
worktreeMode?: boolean;
/** Card ID for worktree branch naming */
cardId?: string;
/** Card slug for worktree directory naming */
cardSlug?: string;
/** Base branch for worktree (defaults to 'main') */
repoBaseBranch?: string;
/**
* Legacy: Claude session ID to resume (uses `claude --resume <id>`).
* Still honored for claude agents when `resume` is not set. Prefer `resume`
* below for all new callers — it carries agent-specific resume data.
*/
resumeSessionId?: string;
/**
* Agent-specific resume hint. Only one of these is consulted, based on
* `agent`:
* - claude → uses `sessionId` as `--resume <id>`
* - codex → uses `rolloutPath` via `experimental_resume`
* config (daemon writes it to a --config arg)
* and passes `sessionId` for logging.
* - consortium-code → uses `--continue` (no id). `sessionId` carried
* for logging only; actual resume is last-session.
* - gemini → resume not supported; daemon rejects with a
* user-visible error if this is set.
*/
resume?: {
sessionId?: string;
rolloutPath?: string;
};
environmentVariables?: {
ANTHROPIC_BASE_URL?: string;
ANTHROPIC_AUTH_TOKEN?: string;
ANTHROPIC_MODEL?: string;
TMUX_SESSION_NAME?: string;
TMUX_TMPDIR?: string;
};
/** Per-provider key mode from profile: managed, byok, or none */
profileKeyMode?: Record<string, 'managed' | 'byok' | 'none'>;
/**
* How auth credentials should be sourced for this session. Mirrors
* `AuthSource` in `src/auth/types.ts` — duplicated as a string-literal
* union here to avoid a circular import between the common RPC layer
* and the auth module. Defaults to `'auto'` server-side: prefer
* machine creds if the probe finds them, else fall back to managed
* proxy if the user has credits, else error.
*/
authSource?: 'machine' | 'managed' | 'byok' | 'auto';
/**
* Optional expectation about the resolved identity. When supplied,
* the daemon verifies the probe's identity matches before spawning;
* a mismatch surfaces a clear error rather than silently using the
* wrong account.
*/
authIdentity?: {
agent: 'claude' | 'codex' | 'gemini' | 'consortium';
email?: string;
};
/**
* Provider id picked in the mobile Provider button (W3A). When set and
* non-`consortium`, the daemon injects this provider's keyEnvVar from
* the encrypted BYOK keystore so the agent CLI talks directly to the
* native upstream instead of routing through the Consortium proxy.
* Higher precedence than `profileKeyMode` for choosing the BYOK
* provider id.
*/
providerId?: string;
/**
* Selected model id (W3A). Currently advisory — the agent CLI reads
* the model from its own per-agent flags or environment. Carried so
* future telemetry / provider-routing decisions can avoid re-parsing
* provider:model strings.
*/
modelId?: string;
/**
* Explicit environment variable name to bind the BYOK key under when
* the daemon can't infer it from its catalogs (custom providers).
* Mobile supplies this for `customProviders` entries; the daemon uses
* it verbatim instead of looking up via AGENT_PROVIDERS or
* OPENCODE_PROVIDERS. Ignored when the daemon already knows the
* provider.
*/
byokEnvVar?: string;
/**
* Optional OpenAI-compatible base URL for the custom provider. When
* present the daemon exports `OPENCODE_CUSTOM_BASE_URL` so users can
* reference it from their opencode.json provider config.
*/
byokBaseURL?: string;
}
type SpawnSessionResult = {
type: 'success';
sessionId: string;
} | {
type: 'requestToApproveDirectoryCreation';
directory: string;
} | {
type: 'error';
errorMessage: string;
}
/**
* Proxy-token mint failed for a required scope. Distinct from the
* generic 'error' so the app can route to billing/upgrade UI instead
* of a generic "Failed to spawn" alert. `errorCode` mirrors the
* structured server response (`spending_cap_required`,
* `subscription_canceled`, `daily_limit_hit`, `insufficient_credits`,
* etc.). The CLI never silently downgrades to direct upstream — a
* failed mint is a hard spawn refusal.
*/
| {
type: 'mint_failed';
errorCode: string;
message: string;
scope: 'consortium' | 'anthropic' | 'openai' | 'google' | 'zai';
};
interface ServerToDaemonEvents {
update: (data: Update) => void;
'rpc-request': (data: {
method: string;
params: string;
}, callback: (response: string) => void) => void;
'rpc-registered': (data: {
method: string;
}) => void;
'rpc-unregistered': (data: {
method: string;
}) => void;
'rpc-error': (data: {
type: string;
error: string;
}) => void;
auth: (data: {
success: boolean;
user: string;
}) => void;
error: (data: {
message: string;
}) => void;
'pty:open': (data: {
terminalId: string;
cols: number;
rows: number;
persistentTerminalId?: string;
}, callback: (response: {
ok: boolean;
error?: string;
}) => void) => void;
'pty:data': (data: {
terminalId: string;
data: string;
}) => void;
'pty:resize': (data: {
terminalId: string;
cols: number;
rows: number;
}) => void;
'pty:close': (data: {
terminalId: string;
}) => void;
'terminal:create': (data: {
terminalId: string;
persistenceMode?: string;
cols?: number;
rows?: number;
cwd?: string;
shell?: string;
}, callback: (response: {
ok: boolean;
mode: string;
error?: string;
}) => void) => void;
'terminal:list': (data: unknown, callback: (response: {
ok: boolean;
terminals: TerminalDescriptor[];
}) => void) => void;
'terminal:destroy': (data: {
terminalId: string;
}, callback: (response: {
ok: boolean;
error?: string;
}) => void) => void;
'server-shutting-down': (data: {
reason: string;
timestamp: number;
}) => void;
'machine:fs-readdir': (data: {
machineId: string;
path: string;
requestId: string;
}) => void;
'machine:fs-stat': (data: {
machineId: string;
path: string;
requestId: string;
}) => void;
}
interface DaemonToServerEvents {
'machine-alive': (data: {
machineId: string;
time: number;
}) => void;
'machine-update-metadata': (data: {
machineId: string;
metadata: string;
expectedVersion: number;
}, cb: (answer: {
result: 'error';
} | {
result: 'version-mismatch';
version: number;
metadata: string;
} | {
result: 'success';
version: number;
metadata: string;
}) => void) => void;
'machine-update-state': (data: {
machineId: string;
daemonState: string;
expectedVersion: number;
}, cb: (answer: {
result: 'error';
} | {
result: 'version-mismatch';
version: number;
daemonState: string;
} | {
result: 'success';
version: number;
daemonState: string;
}) => void) => void;
'openclaw:activity': (data: {
machineId: string;
eventType: s