@flamecast/protocol 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ export type { Runtime, RuntimeNames, RuntimeConfigFor, RuntimeInstance, RuntimeInfo, SessionContext, SessionEndReason, } from "./runtime.js";
2
+ export type { FileSystemEntry, PermissionRequestEvent, FilesystemSnapshotEvent, FilePreviewEvent, PermissionRespondAction, FsSnapshotAction, FilePreviewAction, SessionHostStartRequest, SessionHostStartResponse, SessionHostHealthResponse, SessionCallbackEvent, PermissionCallbackResponse, } from "./session-host.js";
3
+ export type { AgentSpawn, AgentTemplate, AgentTemplateRuntime, Session, SessionLog, PendingPermission, PendingPermissionOption, FileSystemSnapshot, FilePreview, QueuedPromptResponse, PromptQueueItem, PromptQueueState, CreateSessionBody, RegisterAgentTemplateBody, PromptBody, PermissionResponseBody, WebhookConfig, WebhookEventType, WebhookPayload, } from "./session.js";
4
+ export type { FlamecastStorage, SessionMeta, SessionRuntimeInfo, StoredSession, } from "./storage.js";
5
+ export type { WsServerMessage, WsControlMessage, WsEventMessage, WsConnectedMessage, WsErrorMessage, WsPromptAction, WsPermissionRespondAction, WsCancelAction, WsTerminateAction, WsPingAction, WsQueueReorderAction, WsQueueClearAction, WsQueuePauseAction, WsQueueResumeAction, } from "./ws.js";
6
+ export type { RuntimeHostStartSessionRequest, RuntimeHostStartSessionResponse, RuntimeHostSessionStatus, RuntimeHostHealthResponse, RuntimeHostPromptRequest, RuntimeHostPermissionResponse, } from "./runtime-host.js";
7
+ export type { Channel, WsChannelServerMessage, WsChannelControlMessage, WsChannelConnectedMessage, WsSubscribedMessage, WsUnsubscribedMessage, WsChannelEventMessage, WsSessionCreatedMessage, WsSessionTerminatedMessage, WsChannelErrorMessage, WsPongMessage, WsSubscribeAction, WsUnsubscribeAction, WsChannelPromptAction, WsChannelPermissionRespondAction, WsChannelCancelAction, WsChannelTerminateAction, WsChannelQueueReorderAction, WsChannelQueueClearAction, WsChannelQueuePauseAction, WsChannelQueueResumeAction, WsChannelPingAction, } from "./ws-channels.js";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ export interface RuntimeHostStartSessionRequest {
2
+ sessionId: string;
3
+ command: string;
4
+ args: string[];
5
+ workspace: string;
6
+ setup?: string;
7
+ env?: Record<string, string>;
8
+ callbackUrl?: string;
9
+ }
10
+ export interface RuntimeHostStartSessionResponse {
11
+ acpSessionId: string;
12
+ sessionId: string;
13
+ }
14
+ export interface RuntimeHostSessionStatus {
15
+ sessionId: string;
16
+ status: "idle" | "running";
17
+ }
18
+ export interface RuntimeHostHealthResponse {
19
+ status: "ok";
20
+ sessions: RuntimeHostSessionStatus[];
21
+ }
22
+ export interface RuntimeHostPromptRequest {
23
+ text: string;
24
+ }
25
+ export interface RuntimeHostPermissionResponse {
26
+ optionId?: string;
27
+ outcome?: "cancelled";
28
+ }
@@ -0,0 +1,9 @@
1
+ // ---------------------------------------------------------------------------
2
+ // RuntimeHost HTTP contract
3
+ //
4
+ // A runtime-host is a long-lived process managing multiple sessions within a
5
+ // single runtime instance (e.g. one per Docker container or E2B sandbox).
6
+ // It exposes a single WebSocket endpoint implementing the ws-channels protocol
7
+ // and session-scoped HTTP endpoints under /sessions/{sessionId}/...
8
+ // ---------------------------------------------------------------------------
9
+ export {};
@@ -0,0 +1,90 @@
1
+ /**
2
+ * A Runtime knows how to ensure a SessionHost exists for a given session
3
+ * and how to route HTTP/WS traffic to it.
4
+ *
5
+ * Intentionally minimal for MVP. Covers start/forward/terminate via HTTP
6
+ * semantics. May be split into explicit lifecycle methods later.
7
+ */
8
+ export interface Runtime<TConfig extends Record<string, unknown> = {}> {
9
+ /** If true, only a single instance is allowed (e.g., local/node runtimes). Default: false. */
10
+ readonly onlyOne?: boolean;
11
+ fetchSession(sessionId: string, request: Request): Promise<Response>;
12
+ /**
13
+ * Proxy an instance-scoped request directly to the runtime instance.
14
+ *
15
+ * This is intended for runtime-level surfaces such as filesystem browsing
16
+ * or aggregate traces that should exist independently of any one session.
17
+ */
18
+ fetchInstance?(instanceId: string, request: Request): Promise<Response>;
19
+ /** Start (or resume) a runtime instance. Creates the instance if it doesn't exist. */
20
+ start?(instanceId: string): Promise<void>;
21
+ /** Stop a specific runtime instance and tear down its resources. */
22
+ stop?(instanceId: string): Promise<void>;
23
+ /** Pause a runtime instance (sessions survive, resources freeze). */
24
+ pause?(instanceId: string): Promise<void>;
25
+ /** Delete a runtime instance and permanently remove its resources. */
26
+ delete?(instanceId: string): Promise<void>;
27
+ /** Query the live status of an instance from the actual runtime (e.g. Docker). */
28
+ getInstanceStatus?(instanceId: string): Promise<"running" | "stopped" | "paused" | undefined>;
29
+ /** Return the WebSocket URL for a running instance's runtime-host. */
30
+ getWebsocketUrl?(instanceId: string): string | undefined;
31
+ /** Return the default working directory for new sessions on this runtime. */
32
+ getDefaultCwd?(): string | undefined;
33
+ dispose?(): Promise<void>;
34
+ /**
35
+ * Return runtime-specific metadata for a session that should be persisted
36
+ * for recovery after a server restart. Called after session creation.
37
+ */
38
+ getRuntimeMeta?(sessionId: string): Record<string, unknown> | null;
39
+ /**
40
+ * Re-register a previously-running session after a server restart.
41
+ *
42
+ * Called during recovery with the runtime-specific metadata that was persisted
43
+ * when the session was originally created. Returns `true` if the session is
44
+ * still alive and was successfully re-registered, `false` otherwise.
45
+ *
46
+ * Runtimes that don't support reconnection can omit this method; the recovery
47
+ * logic will fall back to a health-check probe against the persisted hostUrl.
48
+ */
49
+ reconnect?(sessionId: string, runtimeMeta: Record<string, unknown> | null): Promise<boolean>;
50
+ }
51
+ /** Persisted state of a runtime instance. */
52
+ export interface RuntimeInstance {
53
+ name: string;
54
+ typeName: string;
55
+ status: "running" | "stopped" | "paused";
56
+ /** WebSocket URL of the runtime-host for this instance (set when running). */
57
+ websocketUrl?: string;
58
+ }
59
+ /** Aggregated info for a runtime type and its instances. */
60
+ export interface RuntimeInfo {
61
+ typeName: string;
62
+ onlyOne: boolean;
63
+ instances: RuntimeInstance[];
64
+ }
65
+ /** Extract string keys from a runtime registry `R`. */
66
+ export type RuntimeNames<R> = Extract<keyof R, string>;
67
+ /**
68
+ * Union of valid runtime config objects for a given registry.
69
+ * Each branch carries the `provider` key narrowed to the specific runtime name
70
+ * plus the runtime's own config fields.
71
+ */
72
+ export type RuntimeConfigFor<R extends Record<string, Runtime<Record<string, unknown>>>> = {
73
+ [K in keyof R]: R[K] extends Runtime<infer C> ? {
74
+ provider: K;
75
+ setup?: string;
76
+ } & C : never;
77
+ }[keyof R];
78
+ /** Minimal session context exposed to event handlers. */
79
+ export interface SessionContext<R extends Record<string, Runtime<Record<string, unknown>>>> {
80
+ id: string;
81
+ agentName: string;
82
+ runtime: RuntimeNames<R>;
83
+ spawn: {
84
+ command: string;
85
+ args: string[];
86
+ };
87
+ startedAt: string;
88
+ }
89
+ /** Reason a session ended. */
90
+ export type SessionEndReason = "terminated" | "error" | "idle_timeout" | "agent_exit";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import { z } from "zod";
2
+ export declare const SessionHostStartRequestSchema: z.ZodObject<{
3
+ command: z.ZodString;
4
+ args: z.ZodArray<z.ZodString>;
5
+ workspace: z.ZodString;
6
+ setup: z.ZodOptional<z.ZodString>;
7
+ env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
8
+ callbackUrl: z.ZodOptional<z.ZodString>;
9
+ }, z.core.$strip>;
@@ -0,0 +1,9 @@
1
+ import { z } from "zod";
2
+ export const SessionHostStartRequestSchema = z.object({
3
+ command: z.string(),
4
+ args: z.array(z.string()),
5
+ workspace: z.string(),
6
+ setup: z.string().optional(),
7
+ env: z.record(z.string(), z.string()).optional(),
8
+ callbackUrl: z.string().optional(),
9
+ });
@@ -0,0 +1,102 @@
1
+ export interface FileSystemEntryGitInfo {
2
+ branch: string;
3
+ origin?: string;
4
+ }
5
+ export interface FileSystemEntry {
6
+ path: string;
7
+ type: "file" | "directory" | "symlink" | "other";
8
+ /** Present when the entry is a directory that is a git repository. */
9
+ git?: FileSystemEntryGitInfo;
10
+ }
11
+ export interface PermissionRequestEvent {
12
+ requestId: string;
13
+ toolCallId: string;
14
+ title: string;
15
+ kind?: string;
16
+ options: Array<{
17
+ optionId: string;
18
+ name: string;
19
+ kind: string;
20
+ }>;
21
+ }
22
+ export interface FilesystemSnapshotEvent {
23
+ snapshot: {
24
+ root: string;
25
+ entries: FileSystemEntry[];
26
+ };
27
+ }
28
+ export interface FilePreviewEvent {
29
+ path: string;
30
+ content: string;
31
+ }
32
+ export interface PermissionRespondAction {
33
+ action: "permission.respond";
34
+ requestId: string;
35
+ response: {
36
+ optionId: string;
37
+ };
38
+ }
39
+ export interface FsSnapshotAction {
40
+ action: "fs.snapshot";
41
+ path?: string;
42
+ }
43
+ export interface FilePreviewAction {
44
+ action: "file.preview";
45
+ path: string;
46
+ }
47
+ /** Union of all events the session-host can POST to the control plane. */
48
+ export type SessionCallbackEvent = {
49
+ type: "permission_request";
50
+ data: PermissionRequestEvent;
51
+ } | {
52
+ type: "session_end";
53
+ data: {
54
+ exitCode: number | null;
55
+ };
56
+ } | {
57
+ type: "end_turn";
58
+ data: {
59
+ promptResponse: unknown;
60
+ };
61
+ } | {
62
+ type: "agent_message";
63
+ data: {
64
+ sessionUpdate: unknown;
65
+ };
66
+ } | {
67
+ type: "error";
68
+ data: {
69
+ message: string;
70
+ };
71
+ };
72
+ /** Response from the control plane for a permission_request callback. */
73
+ export type PermissionCallbackResponse = {
74
+ optionId: string;
75
+ } | {
76
+ outcome: "cancelled";
77
+ } | {
78
+ deferred: true;
79
+ };
80
+ export interface SessionHostStartRequest {
81
+ /** Flamecast-level session ID (used for callbacks to the control plane). */
82
+ sessionId?: string;
83
+ command: string;
84
+ args: string[];
85
+ workspace: string;
86
+ setup?: string;
87
+ env?: Record<string, string>;
88
+ callbackUrl?: string;
89
+ }
90
+ export interface SessionHostStartResponse {
91
+ acpSessionId: string;
92
+ /** Set by the runtime after proxying the response from the runtime-host. */
93
+ hostUrl: string;
94
+ /** Set by the runtime after proxying the response from the runtime-host. */
95
+ websocketUrl: string;
96
+ /** The Flamecast-level session ID (echoed back from the runtime-host). */
97
+ sessionId?: string;
98
+ }
99
+ export interface SessionHostHealthResponse {
100
+ status: "idle" | "running";
101
+ sessionId?: string;
102
+ }
@@ -0,0 +1,4 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Shared types for filesystem entries (used by snapshot events)
3
+ // ---------------------------------------------------------------------------
4
+ export {};
@@ -0,0 +1,129 @@
1
+ import type { FileSystemEntry } from "./session-host.js";
2
+ export interface AgentSpawn {
3
+ command: string;
4
+ args: string[];
5
+ }
6
+ export interface AgentTemplateRuntime {
7
+ provider: string;
8
+ image?: string;
9
+ dockerfile?: string;
10
+ setup?: string;
11
+ env?: Record<string, string>;
12
+ }
13
+ export interface AgentTemplate {
14
+ id: string;
15
+ name: string;
16
+ spawn: AgentSpawn;
17
+ runtime: AgentTemplateRuntime;
18
+ env?: Record<string, string>;
19
+ }
20
+ export interface SessionLog {
21
+ timestamp: string;
22
+ type: string;
23
+ data: Record<string, unknown>;
24
+ }
25
+ export interface PendingPermissionOption {
26
+ optionId: string;
27
+ name: string;
28
+ kind: string;
29
+ }
30
+ export interface PendingPermission {
31
+ requestId: string;
32
+ toolCallId: string;
33
+ title: string;
34
+ kind?: string;
35
+ options: PendingPermissionOption[];
36
+ }
37
+ export interface FileSystemSnapshot {
38
+ root: string;
39
+ /** The absolute path of the directory being listed. Absent for legacy recursive snapshots. */
40
+ path?: string;
41
+ /** If the listed directory is inside a git repo, the absolute path to the repo root. */
42
+ gitPath?: string;
43
+ entries: FileSystemEntry[];
44
+ truncated: boolean;
45
+ maxEntries: number;
46
+ }
47
+ export interface FilePreview {
48
+ path: string;
49
+ content: string;
50
+ truncated: boolean;
51
+ maxChars: number;
52
+ }
53
+ export interface QueuedPromptResponse {
54
+ queued: true;
55
+ queueId: string;
56
+ position: number;
57
+ }
58
+ export interface PromptQueueItem {
59
+ queueId: string;
60
+ text: string;
61
+ enqueuedAt: string;
62
+ position: number;
63
+ }
64
+ export interface PromptQueueState {
65
+ processing: boolean;
66
+ paused: boolean;
67
+ items: PromptQueueItem[];
68
+ size: number;
69
+ }
70
+ export interface Session {
71
+ id: string;
72
+ agentName: string;
73
+ spawn: AgentSpawn;
74
+ startedAt: string;
75
+ lastUpdatedAt: string;
76
+ status: "active" | "killed";
77
+ logs: SessionLog[];
78
+ pendingPermission: PendingPermission | null;
79
+ fileSystem: FileSystemSnapshot | null;
80
+ promptQueue: PromptQueueState | null;
81
+ websocketUrl?: string;
82
+ /** Runtime instance name this session is scoped to. */
83
+ runtime?: string;
84
+ }
85
+ export interface CreateSessionBody {
86
+ /** Client-generated session ID. If omitted the server generates one. */
87
+ sessionId?: string;
88
+ cwd?: string;
89
+ agentTemplateId?: string;
90
+ spawn?: AgentSpawn;
91
+ name?: string;
92
+ /** Runtime instance name to run this session on. Required for multi-instance runtimes. */
93
+ runtimeInstance?: string;
94
+ webhooks?: Omit<WebhookConfig, "id">[];
95
+ }
96
+ export interface RegisterAgentTemplateBody {
97
+ name: string;
98
+ spawn: AgentSpawn;
99
+ runtime?: AgentTemplateRuntime;
100
+ env?: Record<string, string>;
101
+ }
102
+ export interface PromptBody {
103
+ text: string;
104
+ }
105
+ export type PermissionResponseBody = {
106
+ optionId: string;
107
+ } | {
108
+ outcome: "cancelled";
109
+ };
110
+ /** Event types deliverable via webhooks. */
111
+ export type WebhookEventType = "permission_request" | "end_turn" | "error" | "session_end";
112
+ /** Webhook registration — per-session or global. */
113
+ export interface WebhookConfig {
114
+ /** Stable internal ID assigned at registration. */
115
+ id: string;
116
+ url: string;
117
+ secret: string;
118
+ events?: WebhookEventType[];
119
+ }
120
+ /** Payload delivered to webhook endpoints. */
121
+ export interface WebhookPayload {
122
+ sessionId: string;
123
+ eventId: string;
124
+ timestamp: string;
125
+ event: {
126
+ type: WebhookEventType;
127
+ data: Record<string, unknown>;
128
+ };
129
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,50 @@
1
+ import type { RuntimeInstance } from "./runtime.js";
2
+ import type { AgentTemplate, Session, WebhookConfig } from "./session.js";
3
+ /** Durable slice of {@link Session} (everything except runtime-only state). */
4
+ export type SessionMeta = Omit<Session, "fileSystem" | "logs" | "promptQueue">;
5
+ /** Runtime connection info persisted alongside a session for recovery after restart. */
6
+ export interface SessionRuntimeInfo {
7
+ hostUrl: string;
8
+ websocketUrl: string;
9
+ runtimeName: string;
10
+ runtimeMeta?: Record<string, unknown> | null;
11
+ }
12
+ /** Storage view of a session, including durable routing metadata. */
13
+ export interface StoredSession {
14
+ meta: SessionMeta;
15
+ runtimeInfo: SessionRuntimeInfo | null;
16
+ webhooks: WebhookConfig[];
17
+ }
18
+ /**
19
+ * Durable backing store for orchestrator state. Runtime (child process, ACP stream)
20
+ * stays in memory; storage is the source of truth for metadata.
21
+ */
22
+ export interface FlamecastStorage {
23
+ /**
24
+ * Synchronize the constructor-provided template set.
25
+ * Managed templates are upserted and any previously managed templates that are
26
+ * no longer present are pruned. User-registered templates are preserved.
27
+ */
28
+ seedAgentTemplates(templates: AgentTemplate[]): Promise<void>;
29
+ listAgentTemplates(): Promise<AgentTemplate[]>;
30
+ getAgentTemplate(id: string): Promise<AgentTemplate | null>;
31
+ saveAgentTemplate(template: AgentTemplate): Promise<void>;
32
+ updateAgentTemplate(id: string, patch: {
33
+ name?: string;
34
+ spawn?: AgentTemplate["spawn"];
35
+ runtime?: Partial<AgentTemplate["runtime"]>;
36
+ env?: Record<string, string>;
37
+ }): Promise<AgentTemplate | null>;
38
+ createSession(meta: SessionMeta, runtimeInfo?: SessionRuntimeInfo, webhooks?: WebhookConfig[]): Promise<void>;
39
+ updateSession(id: string, patch: Partial<Pick<SessionMeta, "lastUpdatedAt" | "pendingPermission">>): Promise<void>;
40
+ getSessionMeta(id: string): Promise<SessionMeta | null>;
41
+ getStoredSession(id: string): Promise<StoredSession | null>;
42
+ /** Return all sessions (active + killed), ordered by lastUpdatedAt desc. */
43
+ listAllSessions(): Promise<SessionMeta[]>;
44
+ /** Return active sessions with their persisted runtime connection info for recovery. */
45
+ listActiveSessionsWithRuntime(): Promise<StoredSession[]>;
46
+ finalizeSession(id: string, reason: "terminated"): Promise<void>;
47
+ saveRuntimeInstance(instance: RuntimeInstance): Promise<void>;
48
+ listRuntimeInstances(): Promise<RuntimeInstance[]>;
49
+ deleteRuntimeInstance(name: string): Promise<void>;
50
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Verify an incoming webhook signature.
3
+ *
4
+ * Usage:
5
+ * const body = await req.text();
6
+ * const sig = req.headers.get("X-Flamecast-Signature")!;
7
+ * if (!verifyWebhookSignature(secret, body, sig)) return new Response("unauthorized", { status: 401 });
8
+ */
9
+ export declare function verifyWebhookSignature(secret: string, body: string, signature: string): boolean;
10
+ /** Sign a webhook payload body. Returns the full signature string including the "sha256=" prefix. */
11
+ export declare function signWebhookPayload(secret: string, body: string): string;
package/dist/verify.js ADDED
@@ -0,0 +1,19 @@
1
+ import { createHmac, timingSafeEqual } from "node:crypto";
2
+ /**
3
+ * Verify an incoming webhook signature.
4
+ *
5
+ * Usage:
6
+ * const body = await req.text();
7
+ * const sig = req.headers.get("X-Flamecast-Signature")!;
8
+ * if (!verifyWebhookSignature(secret, body, sig)) return new Response("unauthorized", { status: 401 });
9
+ */
10
+ export function verifyWebhookSignature(secret, body, signature) {
11
+ const expected = "sha256=" + createHmac("sha256", secret).update(body).digest("hex");
12
+ if (expected.length !== signature.length)
13
+ return false;
14
+ return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
15
+ }
16
+ /** Sign a webhook payload body. Returns the full signature string including the "sha256=" prefix. */
17
+ export function signWebhookPayload(secret, body) {
18
+ return "sha256=" + createHmac("sha256", secret).update(body).digest("hex");
19
+ }
@@ -0,0 +1,124 @@
1
+ /** A channel identifier, e.g. "session:abc", "agent:xyz:fs", "agents". */
2
+ export type Channel = string;
3
+ export interface WsChannelConnectedMessage {
4
+ type: "connected";
5
+ connectionId: string;
6
+ }
7
+ export interface WsSubscribedMessage {
8
+ type: "subscribed";
9
+ channel: Channel;
10
+ }
11
+ export interface WsUnsubscribedMessage {
12
+ type: "unsubscribed";
13
+ channel: Channel;
14
+ }
15
+ export interface WsChannelEventMessage {
16
+ type: "event";
17
+ channel: Channel;
18
+ sessionId: string;
19
+ agentId: string;
20
+ seq: number;
21
+ event: {
22
+ type: string;
23
+ data: Record<string, unknown>;
24
+ timestamp: string;
25
+ };
26
+ }
27
+ export interface WsSessionCreatedMessage {
28
+ type: "session.created";
29
+ sessionId: string;
30
+ agentId: string;
31
+ }
32
+ export interface WsSessionTerminatedMessage {
33
+ type: "session.terminated";
34
+ sessionId: string;
35
+ agentId: string;
36
+ }
37
+ export interface WsChannelErrorMessage {
38
+ type: "error";
39
+ message: string;
40
+ channel?: Channel;
41
+ }
42
+ export interface WsPongMessage {
43
+ type: "pong";
44
+ }
45
+ export type WsChannelServerMessage = WsChannelConnectedMessage | WsSubscribedMessage | WsUnsubscribedMessage | WsChannelEventMessage | WsSessionCreatedMessage | WsSessionTerminatedMessage | WsChannelErrorMessage | WsPongMessage;
46
+ export interface WsSubscribeAction {
47
+ action: "subscribe";
48
+ channel: Channel;
49
+ /** Optional sequence number — replay only events with seq > since. */
50
+ since?: number;
51
+ }
52
+ export interface WsUnsubscribeAction {
53
+ action: "unsubscribe";
54
+ channel: Channel;
55
+ }
56
+ export interface WsChannelPromptAction {
57
+ action: "prompt";
58
+ sessionId: string;
59
+ text: string;
60
+ }
61
+ export interface WsChannelPermissionRespondAction {
62
+ action: "permission.respond";
63
+ sessionId: string;
64
+ requestId: string;
65
+ body: {
66
+ optionId: string;
67
+ } | {
68
+ outcome: "cancelled";
69
+ };
70
+ }
71
+ export interface WsChannelCancelAction {
72
+ action: "cancel";
73
+ sessionId: string;
74
+ queueId?: string;
75
+ }
76
+ export interface WsChannelTerminateAction {
77
+ action: "terminate";
78
+ sessionId: string;
79
+ }
80
+ export interface WsChannelQueueReorderAction {
81
+ action: "queue.reorder";
82
+ sessionId: string;
83
+ order: string[];
84
+ }
85
+ export interface WsChannelQueueClearAction {
86
+ action: "queue.clear";
87
+ sessionId: string;
88
+ }
89
+ export interface WsChannelQueuePauseAction {
90
+ action: "queue.pause";
91
+ sessionId: string;
92
+ }
93
+ export interface WsChannelQueueResumeAction {
94
+ action: "queue.resume";
95
+ sessionId: string;
96
+ }
97
+ export interface WsChannelPingAction {
98
+ action: "ping";
99
+ }
100
+ export interface WsChannelTerminalCreateAction {
101
+ action: "terminal.create";
102
+ /** Optional session ID — if provided, terminal opens in that session's workspace. */
103
+ sessionId?: string;
104
+ /** Shell command to run (defaults to /bin/sh). */
105
+ data?: string;
106
+ cols?: number;
107
+ rows?: number;
108
+ }
109
+ export interface WsChannelTerminalInputAction {
110
+ action: "terminal.input";
111
+ terminalId: string;
112
+ data: string;
113
+ }
114
+ export interface WsChannelTerminalResizeAction {
115
+ action: "terminal.resize";
116
+ terminalId: string;
117
+ cols: number;
118
+ rows: number;
119
+ }
120
+ export interface WsChannelTerminalKillAction {
121
+ action: "terminal.kill";
122
+ terminalId: string;
123
+ }
124
+ export type WsChannelControlMessage = WsSubscribeAction | WsUnsubscribeAction | WsChannelPromptAction | WsChannelPermissionRespondAction | WsChannelCancelAction | WsChannelTerminateAction | WsChannelQueueReorderAction | WsChannelQueueClearAction | WsChannelQueuePauseAction | WsChannelQueueResumeAction | WsChannelPingAction | WsChannelTerminalCreateAction | WsChannelTerminalInputAction | WsChannelTerminalResizeAction | WsChannelTerminalKillAction;
@@ -0,0 +1,7 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Multi-session WebSocket adapter — channel-based protocol (SMI-1704)
3
+ //
4
+ // These types define the multiplexed WS endpoint at ws://host/ws.
5
+ // The existing per-session types in ws.ts remain unchanged for backward compat.
6
+ // ---------------------------------------------------------------------------
7
+ export {};
@@ -0,0 +1,44 @@
1
+ import { z } from "zod";
2
+ export declare const WsServerMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
3
+ type: z.ZodLiteral<"event">;
4
+ timestamp: z.ZodString;
5
+ event: z.ZodObject<{
6
+ type: z.ZodString;
7
+ data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
8
+ timestamp: z.ZodString;
9
+ }, z.core.$strip>;
10
+ }, z.core.$strip>, z.ZodObject<{
11
+ type: z.ZodLiteral<"connected">;
12
+ sessionId: z.ZodString;
13
+ }, z.core.$strip>, z.ZodObject<{
14
+ type: z.ZodLiteral<"error">;
15
+ message: z.ZodString;
16
+ }, z.core.$strip>]>;
17
+ export declare const WsControlMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
18
+ action: z.ZodLiteral<"prompt">;
19
+ text: z.ZodString;
20
+ }, z.core.$strip>, z.ZodObject<{
21
+ action: z.ZodLiteral<"permission.respond">;
22
+ requestId: z.ZodString;
23
+ body: z.ZodUnion<readonly [z.ZodObject<{
24
+ optionId: z.ZodString;
25
+ }, z.core.$strip>, z.ZodObject<{
26
+ outcome: z.ZodLiteral<"cancelled">;
27
+ }, z.core.$strip>]>;
28
+ }, z.core.$strip>, z.ZodObject<{
29
+ action: z.ZodLiteral<"cancel">;
30
+ queueId: z.ZodOptional<z.ZodString>;
31
+ }, z.core.$strip>, z.ZodObject<{
32
+ action: z.ZodLiteral<"terminate">;
33
+ }, z.core.$strip>, z.ZodObject<{
34
+ action: z.ZodLiteral<"ping">;
35
+ }, z.core.$strip>, z.ZodObject<{
36
+ action: z.ZodLiteral<"queue.reorder">;
37
+ order: z.ZodArray<z.ZodString>;
38
+ }, z.core.$strip>, z.ZodObject<{
39
+ action: z.ZodLiteral<"queue.clear">;
40
+ }, z.core.$strip>, z.ZodObject<{
41
+ action: z.ZodLiteral<"queue.pause">;
42
+ }, z.core.$strip>, z.ZodObject<{
43
+ action: z.ZodLiteral<"queue.resume">;
44
+ }, z.core.$strip>]>;
package/dist/ws-zod.js ADDED
@@ -0,0 +1,75 @@
1
+ import { z } from "zod";
2
+ // ---------------------------------------------------------------------------
3
+ // Server → Client message schemas
4
+ // ---------------------------------------------------------------------------
5
+ const WsEventMessageSchema = z.object({
6
+ type: z.literal("event"),
7
+ timestamp: z.string(),
8
+ event: z.object({
9
+ type: z.string(),
10
+ data: z.record(z.string(), z.unknown()),
11
+ timestamp: z.string(),
12
+ }),
13
+ });
14
+ const WsConnectedMessageSchema = z.object({
15
+ type: z.literal("connected"),
16
+ sessionId: z.string(),
17
+ });
18
+ const WsErrorMessageSchema = z.object({
19
+ type: z.literal("error"),
20
+ message: z.string(),
21
+ });
22
+ export const WsServerMessageSchema = z.union([
23
+ WsEventMessageSchema,
24
+ WsConnectedMessageSchema,
25
+ WsErrorMessageSchema,
26
+ ]);
27
+ // ---------------------------------------------------------------------------
28
+ // Client → Server message schemas
29
+ // ---------------------------------------------------------------------------
30
+ const WsPromptActionSchema = z.object({
31
+ action: z.literal("prompt"),
32
+ text: z.string(),
33
+ });
34
+ const WsPermissionRespondActionSchema = z.object({
35
+ action: z.literal("permission.respond"),
36
+ requestId: z.string(),
37
+ body: z.union([
38
+ z.object({ optionId: z.string() }),
39
+ z.object({ outcome: z.literal("cancelled") }),
40
+ ]),
41
+ });
42
+ const WsCancelActionSchema = z.object({
43
+ action: z.literal("cancel"),
44
+ queueId: z.string().optional(),
45
+ });
46
+ const WsTerminateActionSchema = z.object({
47
+ action: z.literal("terminate"),
48
+ });
49
+ const WsPingActionSchema = z.object({
50
+ action: z.literal("ping"),
51
+ });
52
+ const WsQueueReorderActionSchema = z.object({
53
+ action: z.literal("queue.reorder"),
54
+ order: z.array(z.string()),
55
+ });
56
+ const WsQueueClearActionSchema = z.object({
57
+ action: z.literal("queue.clear"),
58
+ });
59
+ const WsQueuePauseActionSchema = z.object({
60
+ action: z.literal("queue.pause"),
61
+ });
62
+ const WsQueueResumeActionSchema = z.object({
63
+ action: z.literal("queue.resume"),
64
+ });
65
+ export const WsControlMessageSchema = z.union([
66
+ WsPromptActionSchema,
67
+ WsPermissionRespondActionSchema,
68
+ WsCancelActionSchema,
69
+ WsTerminateActionSchema,
70
+ WsPingActionSchema,
71
+ WsQueueReorderActionSchema,
72
+ WsQueueClearActionSchema,
73
+ WsQueuePauseActionSchema,
74
+ WsQueueResumeActionSchema,
75
+ ]);
package/dist/ws.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ export interface WsEventMessage {
2
+ type: "event";
3
+ timestamp: string;
4
+ event: {
5
+ type: string;
6
+ data: Record<string, unknown>;
7
+ timestamp: string;
8
+ };
9
+ }
10
+ export interface WsConnectedMessage {
11
+ type: "connected";
12
+ sessionId: string;
13
+ }
14
+ export interface WsErrorMessage {
15
+ type: "error";
16
+ message: string;
17
+ }
18
+ export type WsServerMessage = WsEventMessage | WsConnectedMessage | WsErrorMessage;
19
+ export interface WsPromptAction {
20
+ action: "prompt";
21
+ text: string;
22
+ }
23
+ export interface WsPermissionRespondAction {
24
+ action: "permission.respond";
25
+ requestId: string;
26
+ body: {
27
+ optionId: string;
28
+ } | {
29
+ outcome: "cancelled";
30
+ };
31
+ }
32
+ export interface WsCancelAction {
33
+ action: "cancel";
34
+ queueId?: string;
35
+ }
36
+ export interface WsTerminateAction {
37
+ action: "terminate";
38
+ }
39
+ export interface WsPingAction {
40
+ action: "ping";
41
+ }
42
+ export interface WsQueueReorderAction {
43
+ action: "queue.reorder";
44
+ order: string[];
45
+ }
46
+ export interface WsQueueClearAction {
47
+ action: "queue.clear";
48
+ }
49
+ export interface WsQueuePauseAction {
50
+ action: "queue.pause";
51
+ }
52
+ export interface WsQueueResumeAction {
53
+ action: "queue.resume";
54
+ }
55
+ export type WsControlMessage = WsPromptAction | WsPermissionRespondAction | WsCancelAction | WsTerminateAction | WsPingAction | WsQueueReorderAction | WsQueueClearAction | WsQueuePauseAction | WsQueueResumeAction;
package/dist/ws.js ADDED
@@ -0,0 +1,4 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Server → Client messages (WebSocket only — real-time events)
3
+ // ---------------------------------------------------------------------------
4
+ export {};
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@flamecast/protocol",
3
+ "version": "0.1.1",
4
+ "files": [
5
+ "dist"
6
+ ],
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./runtime": {
14
+ "types": "./dist/runtime.d.ts",
15
+ "import": "./dist/runtime.js"
16
+ },
17
+ "./session-host": {
18
+ "types": "./dist/session-host.d.ts",
19
+ "import": "./dist/session-host.js"
20
+ },
21
+ "./session": {
22
+ "types": "./dist/session.d.ts",
23
+ "import": "./dist/session.js"
24
+ },
25
+ "./storage": {
26
+ "types": "./dist/storage.d.ts",
27
+ "import": "./dist/storage.js"
28
+ },
29
+ "./ws": {
30
+ "types": "./dist/ws.d.ts",
31
+ "import": "./dist/ws.js"
32
+ },
33
+ "./ws/channels": {
34
+ "types": "./dist/ws-channels.d.ts",
35
+ "import": "./dist/ws-channels.js"
36
+ },
37
+ "./ws/zod": {
38
+ "types": "./dist/ws-zod.d.ts",
39
+ "import": "./dist/ws-zod.js"
40
+ },
41
+ "./session-host/zod": {
42
+ "types": "./dist/session-host-zod.d.ts",
43
+ "import": "./dist/session-host-zod.js"
44
+ },
45
+ "./verify": {
46
+ "types": "./dist/verify.d.ts",
47
+ "import": "./dist/verify.js"
48
+ }
49
+ },
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "dependencies": {
54
+ "zod": "^4.3.6"
55
+ },
56
+ "devDependencies": {
57
+ "typescript": "^5.8.3"
58
+ },
59
+ "scripts": {
60
+ "build": "tsc",
61
+ "build:package": "tsc"
62
+ }
63
+ }