Files
Kilo-Org_kilocode/packages/opencode/test/kilo-sessions/remote-protocol.test.ts
T
Evgeny Shurakov 37b866f1ef feat(cli): add remote session relay over WebSocket
Introduce WebSocket-based remote session relay so external clients can
subscribe to sessions, send messages, answer questions, and respond to
permissions in real time.

- RemoteWS manages the authenticated WebSocket lifecycle with reconnect
- RemoteSender dispatches inbound commands and forwards server events
- Backfill pending questions/permissions when a client subscribes
- Add question_reject command for dismissing questions remotely
- Consolidate /remote TUI command into kilo-commands
- Add session.viewed endpoint to the generated SDK
- RemoteProtocol.Preview schema for diagnostic logging
2026-03-24 13:54:30 +01:00

229 lines
6.6 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import { RemoteProtocol } from "../../src/kilo-sessions/remote-protocol"
describe("RemoteProtocol", () => {
// --- Outbound (CLI → DO) ---
test("valid heartbeat parses", () => {
const msg = {
type: "heartbeat",
sessions: [{ id: "ses_1", status: "busy", title: "Fix auth" }],
}
const result = RemoteProtocol.Heartbeat.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.sessions).toHaveLength(1)
expect(result.data.sessions[0].id).toBe("ses_1")
}
})
test("valid event parses", () => {
const msg = {
type: "event",
sessionId: "ses_1",
event: "message.updated",
data: { text: "hello" },
}
const result = RemoteProtocol.Event.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.sessionId).toBe("ses_1")
expect(result.data.event).toBe("message.updated")
}
})
test("valid response parses", () => {
const msg = { type: "response", id: "req_1", result: { ok: true } }
const result = RemoteProtocol.Response.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.id).toBe("req_1")
expect(result.data.result).toEqual({ ok: true })
expect(result.data.error).toBeUndefined()
}
})
test("response with error parses", () => {
const msg = { type: "response", id: "req_2", error: "not found" }
const result = RemoteProtocol.Response.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.error).toBe("not found")
expect(result.data.result).toBeUndefined()
}
})
// --- Inbound (DO → CLI) ---
test("valid subscribe parses", () => {
const msg = { type: "subscribe", sessionId: "ses_1" }
const result = RemoteProtocol.Subscribe.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.sessionId).toBe("ses_1")
}
})
test("valid unsubscribe parses", () => {
const msg = { type: "unsubscribe", sessionId: "ses_1" }
const result = RemoteProtocol.Unsubscribe.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.sessionId).toBe("ses_1")
}
})
test("valid command parses", () => {
const msg = {
type: "command",
id: "cmd_1",
command: "send_message",
sessionId: "ses_1",
data: { text: "hi" },
}
const result = RemoteProtocol.Command.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.id).toBe("cmd_1")
expect(result.data.command).toBe("send_message")
expect(result.data.sessionId).toBe("ses_1")
}
})
test("command without sessionId parses", () => {
const msg = {
type: "command",
id: "cmd_2",
command: "list_sessions",
data: null,
}
const result = RemoteProtocol.Command.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.sessionId).toBeUndefined()
}
})
test("valid system parses", () => {
const msg = {
type: "system",
event: "cli.connected",
data: { pid: 1234 },
}
const result = RemoteProtocol.System.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.event).toBe("cli.connected")
}
})
// --- Discriminated unions ---
test("outbound union picks heartbeat", () => {
const msg = { type: "heartbeat", sessions: [] }
const result = RemoteProtocol.Outbound.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.type).toBe("heartbeat")
}
})
test("outbound union picks event", () => {
const msg = {
type: "event",
sessionId: "ses_1",
event: "session.updated",
data: {},
}
const result = RemoteProtocol.Outbound.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.type).toBe("event")
}
})
test("outbound union picks response", () => {
const msg = { type: "response", id: "r1" }
const result = RemoteProtocol.Outbound.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.type).toBe("response")
}
})
test("inbound union picks subscribe", () => {
const msg = { type: "subscribe", sessionId: "ses_1" }
const result = RemoteProtocol.Inbound.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.type).toBe("subscribe")
}
})
test("inbound union picks command", () => {
const msg = {
type: "command",
id: "c1",
command: "ping",
data: null,
}
const result = RemoteProtocol.Inbound.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.type).toBe("command")
}
})
test("inbound union picks system", () => {
const msg = { type: "system", event: "shutdown", data: null }
const result = RemoteProtocol.Inbound.safeParse(msg)
expect(result.success).toBe(true)
if (result.success) {
expect(result.data.type).toBe("system")
}
})
// --- Rejection ---
test("outbound rejects unknown type", () => {
const msg = { type: "bogus", data: 1 }
const result = RemoteProtocol.Outbound.safeParse(msg)
expect(result.success).toBe(false)
})
test("inbound rejects unknown type", () => {
const msg = { type: "bogus", data: 1 }
const result = RemoteProtocol.Inbound.safeParse(msg)
expect(result.success).toBe(false)
})
test("heartbeat rejects missing sessions", () => {
const msg = { type: "heartbeat" }
const result = RemoteProtocol.Heartbeat.safeParse(msg)
expect(result.success).toBe(false)
})
test("event rejects missing sessionId", () => {
const msg = { type: "event", event: "x", data: null }
const result = RemoteProtocol.Event.safeParse(msg)
expect(result.success).toBe(false)
})
test("command rejects missing id", () => {
const msg = { type: "command", command: "ping", data: null }
const result = RemoteProtocol.Command.safeParse(msg)
expect(result.success).toBe(false)
})
test("subscribe rejects missing sessionId", () => {
const msg = { type: "subscribe" }
const result = RemoteProtocol.Subscribe.safeParse(msg)
expect(result.success).toBe(false)
})
test("session info rejects missing fields", () => {
const result = RemoteProtocol.SessionInfo.safeParse({ id: "x" })
expect(result.success).toBe(false)
})
})