Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
50b3be768This file is pinned to the selected release. Download the original to open it in your design tool.
import { afterEach, describe, expect, it, vi } from 'vitest'
import { readFileSync } from 'fs'
import { homedir } from 'os'
import { fileURLToPath } from 'url'
import { BackendSocket, compactRuntimePickerModels, deviceAgentListItem, deviceAgentRow, grokHistoryPage } from './backendSocket.js'
import { AuthSessionError, type AuthSessionManager } from './lib/authSession.js'
import { WS_IDLE_DEADLINE_MS as IDLE_DEADLINE_MS } from './lib/wsLiveness.js'
import type { TerminalStreamManager } from './lib/terminalStreamManager.js'
import { decodeTerminalLocal, TerminalBinaryKind } from './lib/terminalBinary.js'
import { registry, type RegisteredSession } from './lib/registry.js'
import * as mediaPreview from './lib/mediaPreview.js'
import * as projectFolder from './lib/projectFolder.js'
import * as projectPreview from './lib/projectPreview.js'
import * as storeCatalog from './dsh/catalog.js'
import { randomUUID } from 'node:crypto'
import { fakeGridAnswers, installFakeGrid, type FakeGrid } from './lib/__fixtures__/fakeGrid.js'
import { clearGridMcpUrlCache } from './lib/gridMcpUrl.js'
describe('viewer forwarding authentication', () => {
it('requires encryption and a web-role session remotely, while permitting trusted local clients', async () => {
const socket = new BackendSocket('token')
const internals = socket as any
const handle = vi.spyOn(socket.viewerForwarder, 'handle').mockImplementation(() => {})
const role = vi.spyOn(internals.e2ee, 'sessionRole').mockReturnValue('web')
const frame = { type: 'viewer_request', payload: { streamId: 'v', agentId: 'a' } }
const unwrap = vi.spyOn(internals.e2ee, 'unwrapDown').mockReturnValue(frame)
await internals.dispatchDown(frame, 'remote')
expect(unwrap).not.toHaveBeenCalled()
expect(handle).not.toHaveBeenCalled()
const encrypted = { type: 'viewer_request', payload: { __e2e: { v: 1, k: 'p', n: 1, ct: 'fixture' } } }
role.mockReturnValue('device')
await internals.dispatchDown(encrypted, 'remote')
expect(handle).not.toHaveBeenCalled()
role.mockReturnValue('web')
await internals.dispatchDown(encrypted, 'remote')
expect(handle).toHaveBeenCalledWith('remote', 'viewer_request', frame.payload)
socket.registerLocalClient('local:viewer', { sendFrame: () => true, sendBinary: () => true })
await internals.dispatchDown(frame, 'local:viewer')
expect(handle).toHaveBeenCalledWith('local:viewer', 'viewer_request', frame.payload)
handle.mockClear()
await internals.dispatchDown({ type: 'viewer_arbitrary', payload: {} }, 'local:viewer')
expect(handle).not.toHaveBeenCalled()
await socket.unregisterLocalClient('local:viewer')
await socket.stop()
})
})
const wsMock = vi.hoisted(() => {
const instances: MockWebSocket[] = []
class MockWebSocket {
static CONNECTING = 0
static OPEN = 1
static CLOSED = 3
readyState = MockWebSocket.CONNECTING
sent: string[] = []
failNextSend: Error | null = null
/** Peer stopped answering pings (a half-open TCP link, a laptop coming back from sleep). */
silent = false
pings = 0
private handlers = new Map<string, Array<(...args: unknown[]) => void>>()
constructor(readonly url: string, readonly protocols: string[], readonly options?: { handshakeTimeout?: number }) {
instances.push(this)
}
on(event: string, cb: (...args: unknown[]) => void): this {
const list = this.handlers.get(event) ?? []
list.push(cb)
this.handlers.set(event, list)
return this
}
once(event: string, cb: (...args: unknown[]) => void): this {
const wrapped = (...args: unknown[]): void => {
const list = this.handlers.get(event) ?? []
this.handlers.set(event, list.filter((fn) => fn !== wrapped))
cb(...args)
}
return this.on(event, wrapped)
}
private emit(event: string, ...args: unknown[]): void {
for (const cb of this.handlers.get(event) ?? []) cb(...args)
}
open(): void {
this.readyState = MockWebSocket.OPEN
this.emit('open')
}
message(value: unknown): void {
this.emit('message', Buffer.from(JSON.stringify(value)))
}
send(data: string, cb?: (err?: Error) => void): void {
if (this.failNextSend) {
const err = this.failNextSend
this.failNextSend = null
cb?.(err)
return
}
this.sent.push(data)
cb?.()
}
close(): void {
this.readyState = MockWebSocket.CLOSED
this.emit('close', 1006)
}
/** What `ws` does when `handshakeTimeout` elapses: abort the upgrade, then report the socket gone. */
handshakeTimeout(): void {
this.emit('error', new Error('Opening handshake has timed out'))
this.close()
}
/** What `ws` does when the upgrade is answered with an HTTP status: 'error', then 'close'. */
refused(status: number): void {
this.emit('error', new Error(`Unexpected server response: ${status}`))
this.close()
}
terminate(): void {
this.close()
}
ping(): void {
this.pings++
if (!this.silent) this.emit('pong')
}
/** The backend's own liveness ping (every 25s from `trackSocketLiveness`). */
peerPing(): void {
this.emit('ping')
}
}
return { instances, MockWebSocket }
})
vi.mock('ws', () => ({ WebSocket: wsMock.MockWebSocket }))
function parseSent(ws: InstanceType<typeof wsMock.MockWebSocket>): Array<Record<string, unknown>> {
return ws.sent.map((s) => JSON.parse(s) as Record<string, unknown>)
}
describe('BackendSocket outbound queue', () => {
afterEach(() => {
wsMock.instances.length = 0
vi.restoreAllMocks()
vi.useRealTimers()
})
it('queues web and device frames before open and flushes them in FIFO order', async () => {
const socket = new BackendSocket('token')
socket.connect()
const ws = wsMock.instances[0]
socket.send({ type: 'turn_summary_pending', dbSessionId: 's1', payload: { sessionId: 's1' } })
socket.sendCommander({ type: 'commander_event', agentId: 's1', dbSessionId: 's1', payload: { kind: 'done', text: 'done' } })
expect(ws.sent).toHaveLength(0)
ws.open()
const sent = parseSent(ws)
expect(sent).toHaveLength(2)
expect((sent[0].frame as { type?: string }).type).toBe('turn_summary_pending')
expect((sent[1].frame as { type?: string }).type).toBe('commander_event')
expect(sent[1]).toMatchObject({ webEligible: false, commanderEligible: true })
await socket.stop()
})
it('bounds the opening handshake and reconnects when it times out', async () => {
// A connect attempt whose TCP side came up but whose upgrade was never answered used to sit in
// CONNECTING forever: no 'open', so no heartbeat to terminate it, and `this.ws` set, so every
// later connect() returned early. The daemon then showed "cloud reconnecting…" until restarted.
vi.useFakeTimers()
const socket = new BackendSocket('token')
socket.connect()
const ws1 = wsMock.instances[0]
expect(ws1.options?.handshakeTimeout).toBe(15_000)
expect(ws1.readyState).toBe(wsMock.MockWebSocket.CONNECTING)
// Still connecting: a second connect() must not open a competing socket …
socket.connect()
expect(wsMock.instances).toHaveLength(1)
// … but once the handshake is abandoned, the ordinary backoff schedules a fresh attempt.
ws1.handshakeTimeout()
expect(socket.isConnected()).toBe(false)
await vi.advanceTimersByTimeAsync(1_000)
expect(wsMock.instances).toHaveLength(2)
const ws2 = wsMock.instances[1]
expect(ws2.options?.handshakeTimeout).toBe(15_000)
ws2.open()
expect(socket.isConnected()).toBe(true)
await socket.stop()
})
it('gives a silent peer the whole deadline, not one missed pong, before terminating', async () => {
// The old heartbeat killed the link the first time a ping went unanswered (20–40s), which is
// what every macOS DarkWake looked like from inside the daemon: the pre-sleep ping's pong never
// came, so the first tick after wake terminated a link that was about to work again.
vi.useFakeTimers()
const socket = new BackendSocket('token')
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.silent = true
await vi.advanceTimersByTimeAsync(IDLE_DEADLINE_MS - 1_000)
expect(socket.isConnected()).toBe(true)
expect(ws.pings).toBeGreaterThanOrEqual(2) // it kept asking the whole time
expect(wsMock.instances).toHaveLength(1)
await vi.advanceTimersByTimeAsync(20_000)
expect(socket.isConnected()).toBe(false)
await vi.advanceTimersByTimeAsync(1_000)
expect(wsMock.instances).toHaveLength(2) // and re-entered the ordinary backoff
await socket.stop()
})
it('counts data and the backend\'s own pings as proof of life, not only pongs', async () => {
// A backend busy streaming data can answer a control-frame ping late; the data itself is the
// stronger proof, and the backend pings this socket every 25s on its own.
vi.useFakeTimers()
const socket = new BackendSocket('token')
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.silent = true
await vi.advanceTimersByTimeAsync(40_000)
ws.message({ t: 'down', connId: 'c1', frame: { type: 'noop' } })
await vi.advanceTimersByTimeAsync(40_000) // 80s in, 40s since the last frame
expect(socket.isConnected()).toBe(true)
ws.peerPing()
await vi.advanceTimersByTimeAsync(40_000)
expect(socket.isConnected()).toBe(true)
await vi.advanceTimersByTimeAsync(IDLE_DEADLINE_MS)
expect(socket.isConnected()).toBe(false)
await socket.stop()
})
describe('a 401 on the upgrade', () => {
// A stub in the shape the socket needs: the first token is what the backend refuses, and the
// refresh answers with whatever the case under test says.
function authStub(refresh: () => Promise<string>): { auth: AuthSessionManager; calls: Array<{ force?: boolean; failedToken?: string }> } {
const calls: Array<{ force?: boolean; failedToken?: string }> = []
let current = 'stale-token'
const auth = {
accessToken: async (opts: { force?: boolean; failedToken?: string } = {}) => {
if (opts.force) { calls.push(opts); current = await refresh() }
return current
},
} as unknown as AuthSessionManager
return { auth, calls }
}
it('refreshes the token, reports the link down meanwhile, and reconnects with the new token', async () => {
vi.useFakeTimers()
const statuses: boolean[] = []
const { auth, calls } = authStub(async () => 'fresh-token')
const socket = new BackendSocket('0123456789abcdef0123456789abcdef', auth, (connected) => statuses.push(connected))
const revoked = vi.fn()
socket.onRevoked = revoked
socket.connect()
await vi.advanceTimersByTimeAsync(0)
const ws1 = wsMock.instances[0]
expect(ws1.protocols).toEqual(['stale-token'])
ws1.open()
ws1.refused(401)
await vi.advanceTimersByTimeAsync(0)
// The socket is gone the ordinary way: status says so, no session was wiped.
expect(statuses).toEqual([true, false])
expect(calls).toEqual([{ force: true, failedToken: 'stale-token' }])
expect(revoked).not.toHaveBeenCalled()
// And the refresh, not a backoff timer, opened the next socket — with the new token.
expect(wsMock.instances).toHaveLength(2)
expect(wsMock.instances[1].protocols).toEqual(['fresh-token'])
await vi.advanceTimersByTimeAsync(60_000)
expect(wsMock.instances).toHaveLength(2) // no second dial racing the first
await socket.stop()
})
it('keeps the session and backs off when the refresh merely fails', async () => {
vi.useFakeTimers()
const { auth } = authStub(async () => { throw new AuthSessionError('service unavailable', 'UNAVAILABLE') })
const socket = new BackendSocket('0123456789abcdef0123456789abcdef', auth)
const revoked = vi.fn()
socket.onRevoked = revoked
socket.connect()
await vi.advanceTimersByTimeAsync(0)
wsMock.instances[0].open()
wsMock.instances[0].refused(401)
await vi.advanceTimersByTimeAsync(0)
expect(revoked).not.toHaveBeenCalled()
expect(wsMock.instances).toHaveLength(1)
await vi.advanceTimersByTimeAsync(1_000)
expect(wsMock.instances).toHaveLength(2) // the ordinary backoff, session intact
await socket.stop()
})
it('signs out only when the refresh token itself is rejected', async () => {
vi.useFakeTimers()
const { auth } = authStub(async () => { throw new AuthSessionError('refresh token is invalid', 'INVALID_REFRESH') })
const socket = new BackendSocket('0123456789abcdef0123456789abcdef', auth)
const revoked = vi.fn()
socket.onRevoked = revoked
socket.connect()
await vi.advanceTimersByTimeAsync(0)
wsMock.instances[0].open()
wsMock.instances[0].refused(401)
await vi.advanceTimersByTimeAsync(0)
expect(revoked).toHaveBeenCalledTimes(1)
await vi.advanceTimersByTimeAsync(60_000)
expect(wsMock.instances).toHaveLength(1)
await socket.stop()
})
})
it('keeps a frame queued when ws.send reports an error and retries after reconnect', async () => {
vi.useFakeTimers()
const socket = new BackendSocket('token')
socket.connect()
const ws1 = wsMock.instances[0]
ws1.open()
ws1.failNextSend = new Error('boom')
socket.sendTo('conn-1', { type: 'e2e_rekey', payload: { n: 1 } })
expect(ws1.sent).toHaveLength(0)
await vi.advanceTimersByTimeAsync(1_000)
const ws2 = wsMock.instances[1]
ws2.open()
const sent = parseSent(ws2)
expect(sent).toHaveLength(1)
expect(sent[0]).toMatchObject({ t: 'up', targetConnId: 'conn-1' })
await socket.stop()
})
it('routes e2e control frames to the handshake manager instead of the RPC fallback', async () => {
const socket = new BackendSocket('token')
const handle = vi.spyOn(socket.e2ee, 'handleFrame').mockReturnValue(true)
socket.connect()
const ws = wsMock.instances[0]
ws.open()
const frame = {
type: 'e2e_setup_claim',
payload: { requestId: 'setup-1', token: 'signed-setup-token' },
}
ws.message({ t: 'down', connId: 'web-1', frame })
await vi.waitFor(() => expect(handle).toHaveBeenCalledWith('web-1', frame))
expect(parseSent(ws).some((item) =>
(item.frame as { type?: string } | undefined)?.type === 'e2e_setup_claim_result',
)).toBe(false)
await socket.stop()
})
it('serves the opaque runtime catalog through the existing models_list RPC', async () => {
const socket = new BackendSocket('token')
socket.runtimeModelsProvider = async () => [
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@high', displayName: 'GPT-5.6 Sol / High' },
]
socket.connect()
const ws = wsMock.instances[0]
ws.open()
vi.spyOn(socket.e2ee, 'unwrapDown').mockReturnValue({
type: 'models_list', payload: { requestId: 'models-1' },
})
vi.spyOn(socket.e2ee, 'hasSession').mockReturnValue(true)
const wrapReply = vi.spyOn(socket.e2ee, 'wrapRpcReply').mockReturnValue({
type: 'models_list_result', payload: { __e2e: { v: 1, k: 's', n: 1, ct: 'ciphertext' } },
})
ws.message({
t: 'down',
connId: 'web-1',
frame: { type: 'models_list', payload: { __e2e: { v: 1, k: 's', n: 1, ct: 'ciphertext' } } },
})
await vi.waitFor(() => {
const result = parseSent(ws).find((item) => (item.frame as { type?: string })?.type === 'models_list_result')
expect(result).toMatchObject({
targetConnId: 'web-1',
frame: { payload: { __e2e: { ct: 'ciphertext' } } },
})
})
expect(wrapReply).toHaveBeenCalledWith('web-1', 'models_list_result', 'models-1', {
models: [{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@high', displayName: 'GPT-5.6 Sol / High' }],
})
await socket.stop()
})
it('hands theme_set to the host-theme sink and acknowledges it to the requester', async () => {
const socket = new BackendSocket('token')
const received: unknown[] = []
socket.hostThemeSink = (theme) => received.push(theme)
socket.connect()
const ws = wsMock.instances[0]
ws.open()
const unwrap = vi.spyOn(socket.e2ee, 'unwrapDown')
vi.spyOn(socket.e2ee, 'hasSession').mockReturnValue(true)
const wrapReply = vi.spyOn(socket.e2ee, 'wrapRpcReply').mockReturnValue({
type: 'theme_set_result', payload: { __e2e: { v: 1, k: 's', n: 1, ct: 'ciphertext' } },
})
const envelope = { __e2e: { v: 1, k: 's', n: 1, ct: 'ciphertext' } }
unwrap.mockReturnValueOnce({
type: 'theme_set', payload: { requestId: 't-1', background: '#171B29', foreground: '#f5f5f5' },
})
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'theme_set', payload: envelope } })
await vi.waitFor(() => {
expect(wrapReply).toHaveBeenCalledWith('web-1', 'theme_set_result', 't-1', { applied: true })
})
// Normalised to lowercase, and a full pair — never half a style.
expect(received).toEqual([{ background: '#171b29', foreground: '#f5f5f5' }])
// A malformed colour is refused, not half-applied.
unwrap.mockReturnValueOnce({ type: 'theme_set', payload: { requestId: 't-2', background: 'dark' } })
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'theme_set', payload: envelope } })
await vi.waitFor(() => {
expect(wrapReply).toHaveBeenCalledWith('web-1', 'theme_set_result', 't-2', { error: 'BAD_THEME' })
})
expect(received).toHaveLength(1)
await socket.stop()
})
it('answers usage_read with this machine\'s own readings, wrapped for the requester', async () => {
// What goes back names what the person spends and on whose account, so it must leave encrypted.
// The reader is the socket's own field: this never touches a real home, Keychain or network.
const socket = new BackendSocket('token')
const readings = [
{
provider: 'claude' as const,
account: 'k1',
outcome: 'answered' as const,
httpStatus: 200,
body: { seven_day: { utilization: 42 } },
},
]
socket.accountUsageReader = async () => readings
socket.connect()
const ws = wsMock.instances[0]
ws.open()
vi.spyOn(socket.e2ee, 'unwrapDown').mockReturnValue({
type: 'usage_read', payload: { requestId: 'usage-1' },
})
vi.spyOn(socket.e2ee, 'hasSession').mockReturnValue(true)
const wrapReply = vi.spyOn(socket.e2ee, 'wrapRpcReply').mockReturnValue({
type: 'usage_read_result', payload: { __e2e: { v: 1, k: 's', n: 1, ct: 'ciphertext' } },
})
ws.message({
t: 'down',
connId: 'web-1',
frame: { type: 'usage_read', payload: { __e2e: { v: 1, k: 's', n: 1, ct: 'ciphertext' } } },
})
await vi.waitFor(() => {
expect(wrapReply).toHaveBeenCalledWith('web-1', 'usage_read_result', 'usage-1', { providers: readings })
})
await socket.stop()
})
it('returns project previews only to the requesting encrypted connection', async () => {
vi.spyOn(registry, 'list').mockReturnValue([{ cwd: '/remote/workspace' }] as RegisteredSession[])
const preview = { path: '/remote/workspace', readme: 'Private project README', branch: 'main', files: ['README.md'], contributors: [] }
const read = vi.spyOn(projectPreview, 'projectPreview').mockResolvedValue(preview)
const socket = new BackendSocket('token')
socket.connect()
const ws = wsMock.instances[0]
ws.open()
vi.spyOn(socket.e2ee, 'unwrapDown').mockReturnValue({ type: 'project_preview', payload: {
requestId: 'preview-1', path: '/remote/workspace',
} })
vi.spyOn(socket.e2ee, 'hasSession').mockReturnValue(true)
const wrap = vi.spyOn(socket.e2ee, 'wrapRpcReply').mockReturnValue({
type: 'project_preview_result', payload: { __e2e: { v: 1, k: 'p', n: 1, ct: 'encrypted-preview' } },
})
ws.message({ t: 'down', connId: 'viewer-a', frame: {
type: 'project_preview', payload: { __e2e: { v: 1, k: 'p', n: 1, ct: 'encrypted-request' } },
} })
await vi.waitFor(() => expect(wrap).toHaveBeenCalledWith('viewer-a', 'project_preview_result', 'preview-1', preview))
expect(read).toHaveBeenCalledWith('/remote/workspace', ['/remote/workspace'])
expect(parseSent(ws)).toContainEqual(expect.objectContaining({ targetConnId: 'viewer-a', frame: {
type: 'project_preview_result', payload: { __e2e: { v: 1, k: 'p', n: 1, ct: 'encrypted-preview' } },
} }))
expect(JSON.stringify(parseSent(ws))).not.toContain('Private project README')
await socket.stop()
})
it('serves media only to the requesting encrypted connection', async () => {
vi.spyOn(registry, 'resolve').mockReturnValue({ cwd: '/remote/workspace' } as RegisteredSession)
const media = { media: true as const, filename: 'preview.png', offset: 0, totalBytes: 3,
revision: 'a'.repeat(64), contentBase64: 'AQID' }
const read = vi.spyOn(mediaPreview, 'readMediaPreviewChunk').mockResolvedValue(media)
const socket = new BackendSocket('token')
socket.connect()
const ws = wsMock.instances[0]
ws.open()
vi.spyOn(socket.e2ee, 'unwrapDown').mockReturnValue({ type: 'agent_read_file', payload: {
requestId: 'media-1', agentId: 'agent-b', path: '/tmp/preview.png', media: true, offset: 0,
} })
vi.spyOn(socket.e2ee, 'hasSession').mockReturnValue(true)
const wrap = vi.spyOn(socket.e2ee, 'wrapRpcReply').mockReturnValue({
type: 'agent_read_file_result', payload: { __e2e: { v: 1, k: 'p', n: 1, ct: 'encrypted-media' } },
})
ws.message({ t: 'down', connId: 'viewer-a', frame: {
type: 'agent_read_file', payload: { __e2e: { v: 1, k: 'p', n: 1, ct: 'encrypted-request' } },
} })
await vi.waitFor(() => expect(wrap).toHaveBeenCalledWith('viewer-a', 'agent_read_file_result', 'media-1', media))
expect(read).toHaveBeenCalledWith('/remote/workspace', '/tmp/preview.png', 0, undefined)
const sent = parseSent(ws)
expect(sent).toContainEqual(expect.objectContaining({ targetConnId: 'viewer-a', frame: {
type: 'agent_read_file_result', payload: { __e2e: { v: 1, k: 'p', n: 1, ct: 'encrypted-media' } },
} }))
expect(JSON.stringify(sent)).not.toContain('AQID')
await socket.stop()
})
it('refuses a plaintext media request before reading any file', async () => {
const read = vi.spyOn(mediaPreview, 'readMediaPreviewChunk')
const socket = new BackendSocket('token')
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.message({ t: 'down', connId: 'unpaired-viewer', frame: {
type: 'agent_read_file', payload: { requestId: 'media-unsafe', agentId: 'agent-b', path: '/tmp/preview.png', media: true, offset: 0 },
} })
await vi.waitFor(() => expect(parseSent(ws)).toContainEqual(expect.objectContaining({
targetConnId: 'unpaired-viewer', frame: expect.objectContaining({ payload: { requestId: 'media-unsafe', error: 'E2EE_REQUIRED' } }),
})))
expect(read).not.toHaveBeenCalled()
await socket.stop()
})
it('includes engine session correlation in the web agent list', async () => {
const session: RegisteredSession = {
schemaVersion: 2,
active: true,
agentId: 'agent-1',
sessionId: 'session-1',
boundAt: 1,
engine: 'codex',
transcriptPath: null,
projectDir: 'workspace',
cwd: '/tmp/workspace',
runtimes: [],
primaryRuntimeKey: '',
tmuxPane: '',
source: null,
title: 'Agent one',
model: null,
cliVersion: null,
processIdentity: null,
registeredAt: 1,
updatedAt: 1,
lastHookAt: 1,
lastTranscriptAt: 1,
}
vi.spyOn(registry, 'advertised').mockReturnValue([session])
vi.spyOn(registry, 'terminalAvailable').mockReturnValue(true)
const socket = new BackendSocket('token')
socket.connect()
const ws = wsMock.instances[0]
ws.open()
vi.spyOn(socket.e2ee, 'unwrapDown').mockReturnValue({
type: 'agents_list', payload: { requestId: 'agents-1' },
})
vi.spyOn(socket.e2ee, 'hasSession').mockReturnValue(true)
const wrapReply = vi.spyOn(socket.e2ee, 'wrapRpcReply').mockReturnValue({
type: 'agents_list_result', payload: { __e2e: { v: 1, k: 's', n: 1, ct: 'ciphertext' } },
})
ws.message({
t: 'down',
connId: 'web-1',
frame: { type: 'agents_list', payload: { __e2e: { v: 1, k: 's', n: 1, ct: 'ciphertext' } } },
})
await vi.waitFor(() => {
expect(wrapReply).toHaveBeenCalledWith('web-1', 'agents_list_result', 'agents-1', {
agents: [expect.objectContaining({
id: 'agent-1', sessionId: 'session-1', engine: 'codex',
terminal: expect.objectContaining({ available: true }),
})],
})
})
await socket.stop()
})
it('filters and compacts the runtime catalog for a device agent', async () => {
const socket = new BackendSocket('token')
const provider = vi.fn(async (_sessionId?: string) => [
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@high', displayName: 'GPT-5.6 Sol / High' },
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@auto', displayName: 'GPT-5.6 Sol / Auto' },
{ id: 'runtime-v1:s1:codex:o3@medium', displayName: 'o3 / Medium' },
{ id: 'runtime-v1:s1:codex:o3@auto', displayName: 'o3 / Auto' },
])
socket.runtimeModelsProvider = provider
socket.connect()
const ws = wsMock.instances[0]
ws.open()
vi.spyOn(socket.e2ee, 'unwrapDown').mockReturnValue({
type: 'models_list',
payload: {
requestId: 'models-compact',
agentId: 's1',
compact: true,
pickerMode: 'model',
selectedModel: 'runtime-v1:s1:codex:gpt-5.6-sol@high',
},
})
vi.spyOn(socket.e2ee, 'hasSession').mockReturnValue(true)
const wrapReply = vi.spyOn(socket.e2ee, 'wrapRpcReply').mockReturnValue({
type: 'models_list_result', payload: { __e2e: { v: 1, k: 's', n: 1, ct: 'ciphertext' } },
})
ws.message({
t: 'down',
connId: 'device-1',
frame: { type: 'models_list', payload: { __e2e: { v: 1, k: 's', n: 1, ct: 'ciphertext' } } },
})
await vi.waitFor(() => {
expect(wrapReply).toHaveBeenCalledWith('device-1', 'models_list_result', 'models-compact', {
models: [
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@high' },
{ id: 'runtime-v1:s1:codex:o3@auto' },
],
})
})
expect(provider).toHaveBeenCalledWith('s1')
await socket.stop()
})
it('fails a plaintext runtime catalog request closed before reading local data', async () => {
const socket = new BackendSocket('token')
const provider = vi.fn(async () => [
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@high', displayName: 'sensitive' },
])
socket.runtimeModelsProvider = provider
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.message({
t: 'down', connId: 'unpaired-web',
frame: { type: 'models_list', payload: { requestId: 'plaintext-models' } },
})
await vi.waitFor(() => {
const result = parseSent(ws).find((item) => (item.frame as { type?: string })?.type === 'models_list_result')
expect(result).toMatchObject({
targetConnId: 'unpaired-web',
frame: { payload: { requestId: 'plaintext-models', error: 'E2EE_REQUIRED' } },
})
})
expect(provider).not.toHaveBeenCalled()
await socket.stop()
})
it('serves authenticated local RPCs in cleartext without weakening cloud E2EE', async () => {
const socket = new BackendSocket('token')
socket.runtimeModelsProvider = async () => [
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@high', displayName: 'Sol / High' },
]
const frames: Array<Record<string, unknown>> = []
expect(socket.registerLocalClient('local:test', {
sendFrame: (frame) => { frames.push(frame); return true },
sendBinary: () => true,
})).toBe(true)
socket.handleLocalFrame('local:test', {
type: 'models_list', payload: { requestId: 'harness-computes' },
})
await vi.waitFor(() => expect(frames).toContainEqual({
type: 'models_list_result',
payload: {
requestId: 'harness-computes',
models: [{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@high', displayName: 'Sol / High' }],
},
}))
await socket.unregisterLocalClient('local:test')
await socket.stop()
})
it('dsh_remove uninstalls through the daemon and refuses a malformed id', async () => {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:store', { sendFrame: (frame) => { frames.push(frame); return true }, sendBinary: () => true })
const removed: string[] = []
socket.onDshRemove = (id) => { removed.push(id); return id === 'autonomous/marp' ? { ok: true } : { ok: false, error: 'NOT_INSTALLED', detail: `${id} is not installed` } }
socket.handleLocalFrame('local:store', { type: 'dsh_remove', payload: { requestId: 'rm-1', id: 'autonomous/marp' } })
socket.handleLocalFrame('local:store', { type: 'dsh_remove', payload: { requestId: 'rm-2', id: 'autonomous/none' } })
socket.handleLocalFrame('local:store', { type: 'dsh_remove', payload: { requestId: 'rm-3', id: '../../etc' } })
await vi.waitFor(() => expect(frames.filter((f) => f.type === 'dsh_remove_result')).toHaveLength(3))
const results = frames.filter((f) => f.type === 'dsh_remove_result').map((f) => f.payload as Record<string, unknown>)
expect(results).toEqual([
expect.objectContaining({ requestId: 'rm-1', ok: true, id: 'autonomous/marp' }),
expect.objectContaining({ requestId: 'rm-2', error: 'NOT_INSTALLED' }),
expect.objectContaining({ requestId: 'rm-3', error: 'INVALID_DSH' }),
])
expect(removed).toEqual(['autonomous/marp', 'autonomous/none'])
await socket.unregisterLocalClient('local:store')
await socket.stop()
})
it('serves live catalog entries without making unrelated RPCs wait for catalog I/O', async () => {
let finish!: (entries: Awaited<ReturnType<typeof storeCatalog.refreshDshRegistry>>) => void
vi.spyOn(storeCatalog, 'refreshDshRegistry').mockImplementation(() => new Promise(resolve => { finish = resolve }))
const socket = new BackendSocket('token')
socket.runtimeModelsProvider = async () => []
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:catalog', { sendFrame: frame => { frames.push(frame); return true }, sendBinary: () => true })
socket.handleLocalFrame('local:catalog', { type: 'dsh_list', payload: { requestId: 'catalog' } })
socket.handleLocalFrame('local:catalog', { type: 'models_list', payload: { requestId: 'models' } })
await vi.waitFor(() => expect(frames.some(frame => frame.type === 'models_list_result')).toBe(true))
expect(frames.some(frame => frame.type === 'dsh_list_result')).toBe(false)
finish([{ id: 'acme/published-today', name: 'Published today', engine: 'claude', repo: 'https://example.test/project', tier: 2, viewerUse: 'acme/viewer' }])
await vi.waitFor(() => expect(frames).toContainEqual({
type: 'dsh_list_result', payload: { requestId: 'catalog', dsh: [expect.objectContaining({ id: 'acme/published-today', installed: false, viewerUse: 'acme/viewer' })] },
}))
await socket.unregisterLocalClient('local:catalog')
await socket.stop()
})
it('does not let a slow engines_probe block agent_create on the same connection', async () => {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:create', {
sendFrame: (frame) => { frames.push(frame); return true },
sendBinary: () => true,
})
let finishProbe!: () => void
socket.engineProbeProvider = () => new Promise((resolve) => { finishProbe = () => resolve([]) })
const pending: RegisteredSession = {
schemaVersion: 2, active: true, launch: { state: 'starting' },
agentId: 'pending-1', sessionId: '', boundAt: null, engine: 'claude',
transcriptPath: null, projectDir: 'work', cwd: '/tmp/work',
runtimes: [{ backend: 'tmux', paneId: '%9' }], primaryRuntimeKey: 'tmux/%9', tmuxPane: '%9',
source: null, title: null, model: null, cliVersion: null, processIdentity: null,
registeredAt: 1, updatedAt: 1, lastHookAt: 1, lastTranscriptAt: 1,
}
socket.onCreateAgent = async () => ({ ok: true, session: pending })
socket.handleLocalFrame('local:create', {
type: 'engines_probe', payload: { requestId: 'probe-1', engines: ['claude'] },
})
socket.handleLocalFrame('local:create', {
type: 'agent_create', payload: { requestId: 'create-1', engine: 'claude', cwd: '/tmp/work' },
})
await vi.waitFor(() => expect(frames).toContainEqual(expect.objectContaining({
type: 'agent_create_result', payload: expect.objectContaining({ requestId: 'create-1' }),
})))
expect(frames.some((frame) => frame.type === 'engines_probe_result')).toBe(false)
finishProbe()
await vi.waitFor(() => expect(frames.some((frame) => frame.type === 'engines_probe_result')).toBe(true))
await socket.unregisterLocalClient('local:create')
await socket.stop()
})
it('creates with approvals bypassed unless the client turns that off', async () => {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:bypass', {
sendFrame: (frame) => { frames.push(frame); return true }, sendBinary: () => true,
})
const pending = (agentId: string): RegisteredSession => ({
schemaVersion: 2, active: true, launch: { state: 'starting' },
agentId, sessionId: '', boundAt: null, engine: 'claude',
transcriptPath: null, projectDir: 'work', cwd: '/tmp/work',
runtimes: [{ backend: 'tmux', paneId: '%9' }], primaryRuntimeKey: 'tmux/%9', tmuxPane: '%9',
source: null, title: null, model: null, cliVersion: null, processIdentity: null,
registeredAt: 1, updatedAt: 1, lastHookAt: 1, lastTranscriptAt: 1,
})
const create = vi.fn(async (input: { bypassPermission: boolean; permissionMode: string | null }) => ({ ok: true as const, session: pending(`b-${create.mock.calls.length}`) }))
socket.onCreateAgent = create
const ask = (requestId: string, extra: Record<string, unknown>) => socket.handleLocalFrame('local:bypass', {
type: 'agent_create', payload: { requestId, engine: 'claude', cwd: '/tmp/work', ...extra },
})
try {
ask('unsaid', {})
ask('on', { bypassPermission: true })
ask('off', { bypassPermission: false })
await vi.waitFor(() => expect(create).toHaveBeenCalledTimes(3))
expect(create.mock.calls.map(([input]) => input.bypassPermission)).toEqual([true, true, false])
// A mode decides, whatever bypassPermission says; one the engine lacks is refused.
ask('plan', { permissionMode: 'plan', bypassPermission: true })
ask('full', { permissionMode: 'full', bypassPermission: false })
await vi.waitFor(() => expect(create).toHaveBeenCalledTimes(5))
expect(create.mock.calls.slice(3).map(([input]) => [input.permissionMode, input.bypassPermission]))
.toEqual([['plan', false], ['full', true]])
ask('bogus', { permissionMode: 'readOnly' })
ask('shape', { permissionMode: 7 })
await vi.waitFor(() => expect(frames.filter((frame) => (frame.payload as { error?: string } | undefined)?.error === 'INVALID_PERMISSION_MODE')).toHaveLength(2))
expect(create).toHaveBeenCalledTimes(5)
} finally {
await socket.unregisterLocalClient('local:bypass')
await socket.stop()
}
})
it('creates a terminal with no folder at home, and refuses it a grid or a project to prepare', async () => {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:terminal', {
sendFrame: (frame) => { frames.push(frame); return true }, sendBinary: () => true,
})
const pending: RegisteredSession = {
schemaVersion: 2, active: true, launch: { state: 'ready' }, terminalHost: true,
agentId: 'term-1', sessionId: '', boundAt: null, engine: 'terminal',
transcriptPath: null, projectDir: 'nqhieu84', cwd: homedir(),
runtimes: [{ backend: 'tmux', paneId: '%9' }], primaryRuntimeKey: 'tmux/%9', tmuxPane: '%9',
source: null, title: null, model: null, cliVersion: null, processIdentity: null,
registeredAt: 1, updatedAt: 1, lastHookAt: 1, lastTranscriptAt: 1,
}
const create = vi.fn(async (_input: { engine: string; cwd: string }) => ({ ok: true as const, session: pending }))
socket.onCreateAgent = create
const ask = (requestId: string, payload: Record<string, unknown>) => socket.handleLocalFrame('local:terminal', {
type: 'agent_create', payload: { requestId, engine: 'terminal', ...payload },
})
const errorOf = (requestId: string) => (frames.find((frame) => frame.type === 'agent_create_result'
&& (frame.payload as { requestId?: string }).requestId === requestId)?.payload as { error?: string } | undefined)?.error
try {
ask('home', {})
ask('folder', { cwd: '/tmp/work' })
await vi.waitFor(() => expect(create).toHaveBeenCalledTimes(2))
expect(create.mock.calls.map(([input]) => [input.engine, input.cwd])).toEqual([['terminal', homedir()], ['terminal', '/tmp/work']])
ask('relative', { cwd: 'work' })
ask('grid', { grid: { networkId: 'n', networkName: 'net', baseUrl: 'https://grid.example', apiKey: 'k' } })
ask('prompt', { prompt: 'hello' })
await vi.waitFor(() => expect(['relative', 'grid', 'prompt'].map(errorOf)).toEqual(['INVALID_CWD', 'INVALID_GRID', 'PROMPT_UNSUPPORTED']))
expect(create).toHaveBeenCalledTimes(2)
} finally {
await socket.unregisterLocalClient('local:terminal')
await socket.stop()
}
})
it('recovers a delayed creation on the same connection without starting another agent', async () => {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:receipt', {
sendFrame: (frame) => { frames.push(frame); return true }, sendBinary: () => true,
})
const pending: RegisteredSession = {
schemaVersion: 2, active: true, launch: { state: 'starting' },
agentId: 'receipt-agent', sessionId: '', boundAt: null, engine: 'claude',
transcriptPath: null, projectDir: 'work', cwd: '/tmp/work',
runtimes: [{ backend: 'tmux', paneId: '%receipt' }], primaryRuntimeKey: 'tmux/%receipt', tmuxPane: '%receipt',
source: null, title: null, model: null, cliVersion: null, processIdentity: null,
registeredAt: 1, updatedAt: 1, lastHookAt: 1, lastTranscriptAt: 1,
}
const lookup = vi.spyOn(registry, 'byAgent').mockReturnValue(pending)
let finish!: () => void
const create = vi.fn(() => new Promise<{ ok: true; session: RegisteredSession }>((resolve) => {
finish = () => resolve({ ok: true, session: pending })
}))
socket.onCreateAgent = create
const creationId = randomUUID()
const ask = (type: string, requestId: string, choices = {}) => socket.handleLocalFrame('local:receipt', {
type, payload: { requestId, creationId, ...choices },
})
try {
ask('agent_create', 'first', { engine: 'claude', cwd: '/tmp/work' })
await vi.waitFor(() => expect(create).toHaveBeenCalledTimes(1))
ask('agent_create_status', 'while-pending')
await vi.waitFor(() => expect(frames).toContainEqual({
type: 'agent_create_status_result', payload: { requestId: 'while-pending', creationId, state: 'pending' },
}))
// New transport request id, same deliberate creation intent.
ask('agent_create', 'retry', { engine: 'claude', cwd: '/tmp/work' })
finish()
for (const requestId of ['first', 'retry']) {
await vi.waitFor(() => expect(frames).toContainEqual(expect.objectContaining({
type: 'agent_create_result', payload: expect.objectContaining({ requestId, creationId, state: 'created', agent: expect.objectContaining({ id: pending.agentId }) }),
})))
}
expect(create).toHaveBeenCalledTimes(1)
ask('agent_create_status', 'recovered')
await vi.waitFor(() => expect(frames).toContainEqual(expect.objectContaining({
type: 'agent_create_status_result', payload: expect.objectContaining({ requestId: 'recovered', creationId, state: 'created', agent: expect.objectContaining({ id: pending.agentId }) }),
})))
ask('agent_create', 'changed', { engine: 'codex', cwd: '/tmp/work' })
await vi.waitFor(() => expect(frames).toContainEqual(expect.objectContaining({
type: 'agent_create_result', payload: expect.objectContaining({ requestId: 'changed', error: 'CREATION_CONFLICT' }),
})))
lookup.mockReturnValue(undefined)
ask('agent_create', 'deleted', { engine: 'claude', cwd: '/tmp/work' })
await vi.waitFor(() => expect(frames).toContainEqual(expect.objectContaining({
type: 'agent_create_result', payload: expect.objectContaining({ requestId: 'deleted', creationId, state: 'unavailable' }),
})))
expect(create).toHaveBeenCalledTimes(1)
} finally {
finish?.()
await socket.unregisterLocalClient('local:receipt')
await socket.stop()
}
})
it('prepares a remote project once under its creation receipt and retains its folder after a refused launch', async () => {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:project', { sendFrame: frame => { frames.push(frame); return true }, sendBinary: () => true })
let finish!: (folder: string) => void
const prepare = vi.spyOn(projectFolder, 'prepareProjectFolder').mockImplementation(() => new Promise(resolve => { finish = resolve }))
const create = vi.fn(async () => ({ ok: false as const, error: 'TMUX_UNAVAILABLE' }))
socket.onCreateAgent = create
const creationId = randomUUID()
const payload = { creationId, engine: 'claude', projectSource: 'remote', repositoryUrl: 'owner/repo' }
const ask = (type: string, requestId: string, choices = payload) => socket.handleLocalFrame('local:project', { type, payload: { requestId, ...choices } })
try {
ask('agent_create', 'first')
await vi.waitFor(() => expect(prepare).toHaveBeenCalledTimes(1))
ask('agent_create', 'retry')
ask('agent_create_status', 'pending')
await vi.waitFor(() => expect(frames).toContainEqual(expect.objectContaining({ payload: expect.objectContaining({ requestId: 'pending', state: 'pending' }) })))
expect(create).not.toHaveBeenCalled()
finish('/remote/Harness Projects/repo')
for (const requestId of ['first', 'retry']) {
await vi.waitFor(() => expect(frames).toContainEqual(expect.objectContaining({ payload: expect.objectContaining({ requestId, state: 'failed', preparedFolder: '/remote/Harness Projects/repo', failure: { code: 'TMUX_UNAVAILABLE' } }) })))
}
expect(create).toHaveBeenCalledExactlyOnceWith(expect.objectContaining({ cwd: '/remote/Harness Projects/repo' }))
expect(prepare).toHaveBeenCalledTimes(1)
ask('agent_create', 'changed', { ...payload, repositoryUrl: 'owner/different' })
await vi.waitFor(() => expect(frames).toContainEqual(expect.objectContaining({ payload: expect.objectContaining({ requestId: 'changed', error: 'CREATION_CONFLICT' }) })))
expect(prepare).toHaveBeenCalledTimes(1)
ask('agent_create_status', 'saved')
await vi.waitFor(() => expect(frames).toContainEqual(expect.objectContaining({ payload: expect.objectContaining({ requestId: 'saved', preparedFolder: '/remote/Harness Projects/repo' }) })))
} finally {
finish?.('/remote/Harness Projects/repo')
await socket.unregisterLocalClient('local:project')
await socket.stop()
}
})
it('checks an unknown creation without spawning and rejects malformed creation ids before launch', async () => {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:missing-receipt', {
sendFrame: (frame) => { frames.push(frame); return true }, sendBinary: () => true,
})
const create = vi.fn(async () => ({ ok: false as const, error: 'CWD_NOT_FOUND' }))
socket.onCreateAgent = create
const creationId = randomUUID()
try {
socket.handleLocalFrame('local:missing-receipt', {
type: 'agent_create_status', payload: { requestId: 'missing', creationId },
})
await vi.waitFor(() => expect(frames).toContainEqual({
type: 'agent_create_status_result', payload: { requestId: 'missing', creationId, state: 'missing' },
}))
socket.handleLocalFrame('local:missing-receipt', {
type: 'agent_create', payload: { requestId: 'invalid', creationId: '../bad', engine: 'claude', cwd: '/tmp/work' },
})
await vi.waitFor(() => expect(frames).toContainEqual(expect.objectContaining({
type: 'agent_create_result', payload: expect.objectContaining({ requestId: 'invalid', error: 'INVALID_CREATION_ID' }),
})))
expect(create).not.toHaveBeenCalled()
} finally {
await socket.unregisterLocalClient('local:missing-receipt')
await socket.stop()
}
})
it.each([
['CWD_NOT_FOUND', 'failed'],
['SPAWN_FAILED', 'unconfirmed'],
['REGISTRATION_FAILED', 'unconfirmed'],
])('does not relaunch a recorded %s outcome', async (error, state) => {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:refusal', {
sendFrame: (frame) => { frames.push(frame); return true }, sendBinary: () => true,
})
const create = vi.fn(async () => ({ ok: false as const, error }))
socket.onCreateAgent = create
const creationId = randomUUID()
try {
for (const requestId of ['initial', 'retry']) {
socket.handleLocalFrame('local:refusal', {
type: 'agent_create', payload: { requestId, creationId, engine: 'claude', cwd: '/tmp/work' },
})
await vi.waitFor(() => expect(frames).toContainEqual({
type: 'agent_create_result',
payload: { requestId, creationId, state, ...(state === 'failed' ? { failure: { code: error } } : {}) },
}))
}
expect(create).toHaveBeenCalledTimes(1)
} finally {
await socket.unregisterLocalClient('local:refusal')
await socket.stop()
}
})
it('sends a device focus request to one desktop window only', async () => {
const socket = new BackendSocket('token')
const first = vi.fn(() => true), second = vi.fn(() => true)
const frame = { type: 'device_focus', payload: { agentId: 'first' } }
expect(socket.sendFirstLocal(frame)).toBe(false)
socket.registerLocalClient('local:first', { sendFrame: first, sendBinary: () => true })
socket.registerLocalClient('local:second', { sendFrame: second, sendBinary: () => true })
first.mockClear(); second.mockClear()
expect(socket.sendFirstLocal(frame)).toBe(true)
expect(first).toHaveBeenCalledExactlyOnceWith(frame)
expect(second).not.toHaveBeenCalled()
await socket.unregisterLocalClient('local:first')
await socket.unregisterLocalClient('local:second')
await socket.stop()
})
it('hands a blocked agent to the window without putting the question on the cloud leg', async () => {
const socket = new BackendSocket('token')
expect(socket.hasLocalClient()).toBe(false)
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:window', {
sendFrame: (frame) => { frames.push(frame); return true },
sendBinary: () => true,
})
// The watcher's whole gate: polling a pane for a dialog is waste with nobody rendering it, and
// "nobody" used to mean "no device" — which is what kept the window in the dark.
expect(socket.hasLocalClient()).toBe(true)
socket.connect()
const ws = wsMock.instances[0]
ws.open()
const asked = {
type: 'commander_question',
agentId: 'a1',
dbSessionId: 's1',
payload: { requestId: 'q_1', questions: [{ key: 'Which theme?', q: 'Which theme?', options: ['Blue', 'Red'], multi: false }] },
}
socket.sendLocal(asked)
// The window reads it in the clear, which is what loopback is for...
expect(frames).toContainEqual(asked)
// ...and it never reaches the relay. `commander_question` is deliberately NOT in ENCRYPTED_UP_TYPES,
// so `send()` here would have travelled the cloud leg as plaintext question text and option labels.
expect(parseSent(ws).some((item) => (item.frame as { type?: string })?.type === 'commander_question')).toBe(false)
await socket.unregisterLocalClient('local:window')
expect(socket.hasLocalClient()).toBe(false)
await socket.stop()
})
it('routes local terminal binary directly and preserves local streams when cloud disconnects', async () => {
vi.useFakeTimers()
const socket = new BackendSocket('token')
const handleBinary = vi.fn(async () => undefined)
const closeConnection = vi.fn(async () => undefined)
const closeConnectionsWhere = vi.fn(async (
_predicate: (connId: string) => boolean,
_reason: string,
_notify?: boolean,
) => undefined)
const stop = vi.fn(async () => undefined)
socket.setTerminalStreamManager({
handleBinary,
closeConnection,
closeConnectionsWhere,
stop,
} as unknown as TerminalStreamManager)
const binary: Uint8Array[] = []
socket.registerLocalClient('local:terminal', {
sendFrame: () => true,
sendBinary: (frame) => { binary.push(frame); return true },
})
const clear = {
kind: TerminalBinaryKind.input,
streamId: '00112233-4455-6677-8899-aabbccddeeff',
seq: 1,
bytes: Uint8Array.of(1, 2),
compressed: false,
}
await socket.handleLocalBinary('local:terminal', clear)
expect(handleBinary).toHaveBeenCalledWith('local:terminal', clear)
expect(socket.sendTerminalBinaryTo('local:terminal', clear)).toBe(true)
expect(decodeTerminalLocal(binary[0])).toEqual(clear)
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.close()
expect(closeConnectionsWhere).toHaveBeenCalledOnce()
const predicate = closeConnectionsWhere.mock.calls[0][0] as (connId: string) => boolean
expect(predicate('web-1')).toBe(true)
expect(predicate('local:terminal')).toBe(false)
await socket.unregisterLocalClient('local:terminal')
expect(closeConnection).toHaveBeenCalledWith('local:terminal', 'local client disconnected', false)
await socket.stop()
})
it('reports the window itself: open when it attaches, ping once a minute while it stays, nothing while offline', async () => {
vi.useFakeTimers()
const socket = new BackendSocket('token')
const sink = { sendFrame: () => true, sendBinary: () => true }
const kinds = (ws: InstanceType<typeof wsMock.MockWebSocket>) => parseSent(ws)
.filter((m) => (m.frame as { type?: string } | undefined)?.type === 'app_presence')
.map((m) => (m.frame as { payload: { kind: string } }).payload.kind)
// A window attaching to a not-yet-dialed daemon (the cold start): nothing can be sent yet, and
// nothing is queued behind real frames — but the session is owed to the link that comes up.
expect(socket.registerLocalClient('local:1', sink)).toBe(true)
socket.connect()
const ws = wsMock.instances[0]
expect(kinds(ws)).toEqual([])
ws.open()
expect(kinds(ws)).toEqual(['open'])
// While the window stays: once a minute on the app-ping tick, not once a tick.
vi.advanceTimersByTime(45_000)
expect(kinds(ws)).toEqual(['open'])
vi.advanceTimersByTime(15_000)
expect(kinds(ws)).toEqual(['open', 'ping'])
// A second window is a session in its own right — up at once, floor or not.
expect(socket.registerLocalClient('local:2', sink)).toBe(true)
expect(kinds(ws)).toEqual(['open', 'ping', 'open'])
// Registering the same window twice is refused, and says nothing.
expect(socket.registerLocalClient('local:2', sink)).toBe(false)
expect(kinds(ws)).toHaveLength(3)
// Every window gone: the tick falls silent.
await socket.unregisterLocalClient('local:1')
await socket.unregisterLocalClient('local:2')
vi.advanceTimersByTime(120_000)
expect(kinds(ws)).toHaveLength(3)
// A window that came and went while the link was down was never a session the backend can hear
// about — the next link is told nothing. Both remaining windows gone first, so the count is clean.
ws.close()
expect(socket.registerLocalClient('local:3', sink)).toBe(true)
await socket.unregisterLocalClient('local:3')
vi.advanceTimersByTime(60_000)
const ws2 = wsMock.instances[1]
ws2.open()
vi.advanceTimersByTime(15_000)
expect(kinds(ws2)).toEqual([])
// Bookkeeping about the person, for the backend alone: never fanned out to a client.
expect(parseSent(ws).find((m) => (m.frame as { type?: string } | undefined)?.type === 'app_presence'))
.toMatchObject({ t: 'up', webEligible: false, commanderEligible: false })
await socket.stop()
})
it('reports commander presence only when it crosses zero', async () => {
const socket = new BackendSocket('token')
const changes: boolean[] = []
socket.onCommanderPresenceChanged = (connected) => changes.push(connected)
socket.connect()
const ws = wsMock.instances[0]
ws.open()
const clients = (commander: number) => ws.message({
t: 'down', connId: '', frame: { type: '__clients', payload: { commander } },
})
clients(1)
clients(2)
clients(0)
clients(0)
clients(1)
await vi.waitFor(() => expect(changes).toEqual([true, false, true]))
await socket.stop()
expect(changes).toEqual([true, false, true, false])
})
// "The device is gone" reaches us two ways: the backend says so (`__clients` → 0), or our own link to
// the backend dies and we can no longer know. Both have to release the device's E2EE session — the
// dashboard's device dot reads `deviceE2eeConnected()`, so a session left behind reports a device that
// may have been gone for hours.
it('drops the device E2EE session when the count reaches zero', async () => {
const socket = new BackendSocket('token')
const drop = vi.spyOn(socket.e2ee, 'dropSessionsByRole')
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.message({ t: 'down', connId: '', frame: { type: '__clients', payload: { commander: 1 } } })
expect(drop).not.toHaveBeenCalled()
ws.message({ t: 'down', connId: '', frame: { type: '__clients', payload: { commander: 0 } } })
await vi.waitFor(() => expect(drop).toHaveBeenCalledWith('device'))
await socket.stop()
})
it('drops the device E2EE session when OUR backend link dies, not just when the backend says so', async () => {
vi.useFakeTimers()
const socket = new BackendSocket('token')
const drop = vi.spyOn(socket.e2ee, 'dropSessionsByRole')
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.message({ t: 'down', connId: '', frame: { type: '__clients', payload: { commander: 1 } } })
drop.mockClear()
ws.close() // transport gone — no `__clients` frame will ever tell us the device left
expect(socket.hasCommander()).toBe(false)
expect(drop).toHaveBeenCalledWith('device')
await socket.stop()
})
it('releases E2EE and terminal state for the exact disconnected web connId', async () => {
const socket = new BackendSocket('token')
const closeConnection = vi.fn(async () => undefined)
const stop = vi.fn(async () => undefined)
socket.setTerminalStreamManager({
closeConnection,
stop,
} as unknown as TerminalStreamManager)
const dropSession = vi.spyOn(socket.e2ee, 'dropSession')
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.message({
t: 'down',
connId: 'web-terminal-1',
frame: { type: '__client_disconnected', payload: {} },
})
await vi.waitFor(() => {
expect(dropSession).toHaveBeenCalledWith('web-terminal-1')
expect(closeConnection).toHaveBeenCalledWith(
'web-terminal-1',
'client connection closed',
false,
)
})
await socket.stop()
expect(stop).toHaveBeenCalledOnce()
})
})
describe('agent_fork RPC', () => {
afterEach(() => {
wsMock.instances.length = 0
vi.restoreAllMocks()
})
const FORK: RegisteredSession = {
schemaVersion: 2, active: true, agentId: 'agent-2', sessionId: '', boundAt: null, engine: 'claude',
forkedFrom: { agentId: 'agent-1', name: 'Agent one' },
transcriptPath: null, projectDir: 'workspace', cwd: '/tmp/workspace', runtimes: [], primaryRuntimeKey: '',
tmuxPane: '%2', source: null, title: null, model: null, cliVersion: null, processIdentity: null,
registeredAt: 2, updatedAt: 2, lastHookAt: 2, lastTranscriptAt: 2,
}
function localSocket(): { socket: BackendSocket; frames: Array<Record<string, unknown>> } {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:fork', { sendFrame: (frame) => { frames.push(frame); return true }, sendBinary: () => true })
return { socket, frames }
}
it('validates the frame before touching the daemon', async () => {
const { socket, frames } = localSocket()
socket.handleLocalFrame('local:fork', { type: 'agent_fork', payload: { requestId: 'r1' } })
await vi.waitFor(() => expect(frames).toContainEqual({ type: 'agent_fork_result', payload: { requestId: 'r1', error: 'MISSING_AGENT_ID' } }))
socket.handleLocalFrame('local:fork', { type: 'agent_fork', payload: { requestId: 'r2', agentId: 'agent-1' } })
await vi.waitFor(() => expect(frames).toContainEqual({ type: 'agent_fork_result', payload: { requestId: 'r2', error: 'UNSUPPORTED_ON_REMOTE' } }))
socket.onForkAgent = async () => ({ ok: true, session: FORK, level: 'native' })
socket.handleLocalFrame('local:fork', { type: 'agent_fork', payload: { requestId: 'r3', agentId: 'agent-1', prompt: 'x'.repeat(2001) } })
await vi.waitFor(() => expect(frames).toContainEqual({ type: 'agent_fork_result', payload: { requestId: 'r3', error: 'PROMPT_TOO_LONG' } }))
await socket.unregisterLocalClient('local:fork')
await socket.stop()
})
it('hands name and prompt to the daemon and answers with the fork, its level, and who it came from', async () => {
const { socket, frames } = localSocket()
const seen: unknown[] = []
socket.onForkAgent = async (input) => { seen.push(input); return { ok: true, session: FORK, level: 'native' } }
socket.handleLocalFrame('local:fork', { type: 'agent_fork', payload: { requestId: 'r1', agentId: 'agent-1', name: ' Agent one - fork ', prompt: 'ship it' } })
await vi.waitFor(() => {
const result = frames.find((f) => f.type === 'agent_fork_result')
expect(result).toMatchObject({
payload: { requestId: 'r1', level: 'native', agent: expect.objectContaining({ id: 'agent-2', forkedFrom: { agentId: 'agent-1', name: 'Agent one' } }) },
})
})
expect(seen).toEqual([{ agentId: 'agent-1', name: 'Agent one - fork', prompt: 'ship it' }])
await socket.unregisterLocalClient('local:fork')
await socket.stop()
})
it('relays the daemon\'s refusal with its reason', async () => {
const { socket, frames } = localSocket()
socket.onForkAgent = async () => ({ ok: false, error: 'AGENT_BUSY', detail: 'Wait for it to finish, then fork.' })
socket.handleLocalFrame('local:fork', { type: 'agent_fork', payload: { requestId: 'r1', agentId: 'agent-1' } })
await vi.waitFor(() => expect(frames).toContainEqual({
type: 'agent_fork_result', payload: { requestId: 'r1', error: 'AGENT_BUSY', detail: 'Wait for it to finish, then fork.' },
}))
await socket.unregisterLocalClient('local:fork')
await socket.stop()
})
})
describe('agent_restart RPC', () => {
afterEach(() => {
wsMock.instances.length = 0
vi.restoreAllMocks()
})
const BASE_SESSION: RegisteredSession = {
schemaVersion: 2,
active: true,
agentId: 'agent-1',
sessionId: 'session-1',
boundAt: 1,
engine: 'claude',
transcriptPath: null,
projectDir: 'workspace',
cwd: '/tmp/workspace',
runtimes: [],
primaryRuntimeKey: '',
tmuxPane: '%1',
source: null,
title: 'Agent one',
model: null,
cliVersion: null,
processIdentity: null,
registeredAt: 1,
updatedAt: 1,
lastHookAt: 1,
lastTranscriptAt: 1,
}
function localSocket(): { socket: BackendSocket; frames: Array<Record<string, unknown>> } {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:restart', {
sendFrame: (frame) => { frames.push(frame); return true },
sendBinary: () => true,
})
return { socket, frames }
}
it('replies MISSING_AGENT_ID when no agentId is given', async () => {
const { socket, frames } = localSocket()
socket.handleLocalFrame('local:restart', { type: 'agent_restart', payload: { requestId: 'r1' } })
await vi.waitFor(() => expect(frames).toContainEqual({
type: 'agent_restart_result', payload: { requestId: 'r1', error: 'MISSING_AGENT_ID' },
}))
await socket.unregisterLocalClient('local:restart')
await socket.stop()
})
it('replies UNSUPPORTED_ON_REMOTE when no handler is wired', async () => {
const { socket, frames } = localSocket()
socket.handleLocalFrame('local:restart', { type: 'agent_restart', payload: { requestId: 'r1', agentId: 'agent-1' } })
await vi.waitFor(() => expect(frames).toContainEqual({
type: 'agent_restart_result', payload: { requestId: 'r1', error: 'UNSUPPORTED_ON_REMOTE' },
}))
await socket.unregisterLocalClient('local:restart')
await socket.stop()
})
it('delegates to onRestartAgent and replies with the agent projection and the resumed flag on success', async () => {
const { socket, frames } = localSocket()
let seenAgentId: string | undefined
socket.onRestartAgent = async (agentId) => {
seenAgentId = agentId
return { ok: true, session: BASE_SESSION, resumed: true }
}
socket.handleLocalFrame('local:restart', { type: 'agent_restart', payload: { requestId: 'r1', agentId: 'agent-1' } })
await vi.waitFor(() => {
const result = frames.find((f) => f.type === 'agent_restart_result')
expect(result).toMatchObject({
type: 'agent_restart_result',
payload: {
requestId: 'r1',
resumed: true,
agent: expect.objectContaining({ id: 'agent-1', sessionId: 'session-1', engine: 'claude' }),
},
})
})
expect(seenAgentId).toBe('agent-1')
await socket.unregisterLocalClient('local:restart')
await socket.stop()
})
it('reports a fresh (non-resumed) relaunch through the same resumed flag', async () => {
const { socket, frames } = localSocket()
socket.onRestartAgent = async () => ({ ok: true, session: BASE_SESSION, resumed: false })
socket.handleLocalFrame('local:restart', { type: 'agent_restart', payload: { requestId: 'r1', agentId: 'agent-1' } })
await vi.waitFor(() => {
const result = frames.find((f) => f.type === 'agent_restart_result')
expect(result).toMatchObject({ payload: { requestId: 'r1', resumed: false } })
})
await socket.unregisterLocalClient('local:restart')
await socket.stop()
})
it('replies with error+detail on failure, matching agent_create/agent_delete\'s reply shape', async () => {
const { socket, frames } = localSocket()
socket.onRestartAgent = async () => (
{ ok: false, error: 'RESTART_FAILED', detail: 'claude did not come back up after restart' }
)
socket.handleLocalFrame('local:restart', { type: 'agent_restart', payload: { requestId: 'r1', agentId: 'agent-1' } })
await vi.waitFor(() => expect(frames).toContainEqual({
type: 'agent_restart_result',
payload: { requestId: 'r1', error: 'RESTART_FAILED', detail: 'claude did not come back up after restart' },
}))
await socket.unregisterLocalClient('local:restart')
await socket.stop()
})
it('omits detail on failure when the handler did not supply one', async () => {
const { socket, frames } = localSocket()
socket.onRestartAgent = async () => ({ ok: false, error: 'AGENT_NOT_FOUND' })
socket.handleLocalFrame('local:restart', { type: 'agent_restart', payload: { requestId: 'r1', agentId: 'agent-1' } })
await vi.waitFor(() => expect(frames).toContainEqual({
type: 'agent_restart_result', payload: { requestId: 'r1', error: 'AGENT_NOT_FOUND' },
}))
await socket.unregisterLocalClient('local:restart')
await socket.stop()
})
})
describe('compact runtime picker catalog', () => {
const models = [
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@auto', displayName: 'Sol / Auto' },
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@medium', displayName: 'Sol / Medium' },
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@high', displayName: 'Sol / High' },
{ id: 'runtime-v1:s1:codex:o3@high', displayName: 'o3 / High' },
{ id: 'runtime-v1:s2:claude:sonnet@high', displayName: 'Sonnet / High' },
]
it('returns only explicit efforts for the selected session model', () => {
expect(compactRuntimePickerModels(
models,
's1',
'effort',
'runtime-v1:s1:codex:gpt-5.6-sol@medium',
)).toEqual([
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@medium' },
{ id: 'runtime-v1:s1:codex:gpt-5.6-sol@high' },
])
})
it('caps the device model list and keeps the running model in it', () => {
// Devin publishes 72 models; a 49-row wheel already tripped the device's task watchdog once.
const many = Array.from({ length: 40 }, (_, i) => ({
id: `runtime-v1:s1:devin:model-${i}@auto`,
displayName: `Model ${i}`,
}))
const capped = compactRuntimePickerModels(many, 's1', 'model', 'runtime-v1:s1:devin:model-39@auto')
expect(capped).toHaveLength(24)
// The model the agent is running would have fallen off the end of the catalog order.
expect(capped[0]).toEqual({ id: 'runtime-v1:s1:devin:model-39@auto' })
// The web asks without a picker mode and still gets the whole catalog.
expect(compactRuntimePickerModels(many, 's1', undefined, null)).toHaveLength(40)
})
})
describe('device agent list contract', () => {
it('keeps the engine discriminator while trimming web-only fields', () => {
expect(deviceAgentListItem({ id: 's1', name: 'Codex agent', engine: 'codex', userId: 'secret' })).toEqual({
id: 's1', name: 'Codex agent', engine: 'codex',
})
})
it('surfaces the runtime-v1 model/effort profile so the device can render + change it', () => {
const profile = 'runtime-v1:s1:codex:gpt-5.6-sol@high'
expect(deviceAgentListItem({ id: 's1', name: 'A', engine: 'codex', selectedModel: profile })).toEqual({
id: 's1', name: 'A', engine: 'codex', selectedModel: profile,
})
expect(deviceAgentListItem({ id: 's1', name: 'A', engine: 'claude', selectedModel: null })).toEqual({
id: 's1', name: 'A', engine: 'claude', selectedModel: null,
})
})
it('preserves Grok on the device agent contract', () => {
expect(deviceAgentListItem({ id: 'g1', name: 'Grok agent', engine: 'grok' })).toEqual({
id: 'g1', name: 'Grok agent', engine: 'grok',
})
})
it('keeps a terminal off the device: not a row for it, and never an engine it would understand', () => {
expect(deviceAgentRow({ id: 't1', name: 'Terminal 1', engine: 'terminal' })).toBe(false)
expect(deviceAgentRow({ id: 'c1', name: 'Claude 1', engine: 'claude' })).toBe(true)
expect(deviceAgentListItem({ id: 't1', name: 'Terminal 1', engine: 'terminal' })).toEqual({ id: 't1', name: 'Terminal 1' })
})
})
describe('Grok session_get history', () => {
const fixture = readFileSync(
fileURLToPath(new URL('./lib/__fixtures__/grok-session.jsonl', import.meta.url)),
'utf8',
).split('\n').filter(Boolean)
it('replays the real transcript for both legacy and web-paginated requests', () => {
const full = grokHistoryPage(fixture, false)
const paginated = grokHistoryPage(fixture, true)
expect(full.events).toEqual(paginated.events)
expect(full.events[0]).toMatchObject({ type: 'user_message' })
expect(full.events.at(-1)).toEqual({ type: 'done', payload: { result: 'success' } })
expect(full).not.toHaveProperty('hasMore')
expect(paginated).toMatchObject({ hasMore: false, oldestCursor: null })
})
})
describe('adapter-ws dial url', () => {
const dialUrl = (socket: BackendSocket): string => (socket as unknown as { url: string }).url
it('carries the machine id this daemon still holds, so a revoked one gets 403 not a new machine', () => {
const machineId = 'b'.repeat(32)
expect(dialUrl(new BackendSocket(machineId, undefined, () => {}, 'computer-1')))
.toContain(`&machine=${machineId}`)
})
it('omits the claim when the first argument is a test token rather than a machine id', () => {
// Constructed without an AuthSessionManager, the first argument is a token — sending it as a
// machine id would be a lie the backend then has to reject.
expect(dialUrl(new BackendSocket('token', undefined, () => {}, 'computer-1'))).not.toContain('&machine=')
})
})
describe('agent_retarget clearGrid', () => {
afterEach(() => {
wsMock.instances.length = 0
vi.restoreAllMocks()
})
const WIRE_GRID = {
networkId: 'grid-abc',
networkName: 'autonomous.ai',
baseUrl: 'https://grid.autonomous.ai/grid-abc/relay/v1',
apiKey: 'gridkey-abc123',
}
async function retarget(payload: Record<string, unknown>) {
const seen: Array<{ agentId: string; grid: unknown }> = []
const socket = new BackendSocket('token')
socket.onRetargetAgent = async (input) => { seen.push(input); return { ok: true } }
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'agent_retarget', payload } })
await vi.waitFor(() => expect(ws.sent.length).toBeGreaterThan(0))
const reply = parseSent(ws)
.map((item) => item.frame as { type?: string; payload?: Record<string, unknown> } | undefined)
.find((frame) => frame?.type === 'agent_retarget_result')
await socket.stop()
return { seen, reply }
}
it('passes a null grid when clearGrid is true', async () => {
const { seen } = await retarget({ requestId: 'r', agentId: 'a1', clearGrid: true })
expect(seen).toEqual([{ agentId: 'a1', grid: null }])
})
// Both is a contradiction, and answering it would mean guessing which one the client meant.
it('refuses grid and clearGrid together', async () => {
const { seen, reply } = await retarget({ requestId: 'r', agentId: 'a1', clearGrid: true, grid: WIRE_GRID })
expect(reply?.payload?.error).toBe('INVALID_GRID')
expect(seen).toHaveLength(0)
})
// Unchanged: a client that simply forgot the field is still an error, which is the whole reason
// clearGrid is a separate field rather than `grid: null`.
it('still refuses a frame with neither', async () => {
const { seen, reply } = await retarget({ requestId: 'r', agentId: 'a1' })
expect(reply?.payload?.error).toBe('INVALID_GRID')
expect(seen).toHaveLength(0)
})
})
/**
* The desktop's retarget names a Local model and nothing else; the daemon resolves everything from
* its own signed-in `grid`. This is that resolution through the real frame handler, against the
* plan-driven fake `grid` — the seam `gridEnsure.spec.ts` established.
*/
describe('agent_retarget onto a Local model resolves web tools', () => {
const { gridName: GRID_NAME, networkId, baseUrl: BASE_URL, mcpUrl: MCP_URL, token: TOKEN, plan } = fakeGridAnswers()
let fake: FakeGrid | null = null
afterEach(async () => {
fake?.dispose()
fake = null
clearGridMcpUrlCache()
wsMock.instances.length = 0
vi.restoreAllMocks()
})
async function retargetOntoLocalModel(model: string) {
const seen: Array<{ agentId: string; grid: unknown }> = []
const socket = new BackendSocket('token')
socket.onRetargetAgent = async (input) => { seen.push(input); return { ok: true } }
socket.connect()
const ws = wsMock.instances[0]
ws.open()
// The grid name is the backend's, pushed on connect; the daemon holds it in memory only.
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'machine_meta', payload: { name: 'mac', gridName: GRID_NAME } } })
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'agent_retarget', payload: { requestId: 'r', agentId: 'a1', gridModel: model } } })
await vi.waitFor(() => expect(parseSent(ws).some((item) => (item.frame as { type?: string } | undefined)?.type === 'agent_retarget_result')).toBe(true), { timeout: 10_000 })
const reply = parseSent(ws)
.map((item) => item.frame as { type?: string; payload?: Record<string, unknown> } | undefined)
.find((frame) => frame?.type === 'agent_retarget_result')
await socket.stop()
return { seen, reply }
}
it('yields a launch override whose MCP URL is exactly the printed url, asking `mcp config` before `info --env`', async () => {
fake = installFakeGrid(plan)
const { seen, reply } = await retargetOntoLocalModel('GLM-4.7-Flash')
expect(reply?.payload).toMatchObject({ retargeted: true })
expect(seen).toEqual([{
agentId: 'a1',
grid: {
networkId,
networkName: GRID_NAME,
baseUrl: BASE_URL,
apiKey: TOKEN,
model: 'GLM-4.7-Flash',
mcpUrl: MCP_URL,
},
}])
expect(fake.verbs()).toEqual(['mcp', 'info', 'ls'])
expect(fake.calls()[0]).toEqual(['--remote', 'mcp', 'config', GRID_NAME, '--json'])
})
it('still retargets, with no MCP URL, when the binary is too old for `mcp config`', async () => {
const warned: string[] = []
vi.spyOn(console, 'warn').mockImplementation((...parts: unknown[]) => { warned.push(parts.map(String).join(' ')) })
fake = installFakeGrid({ ...plan, mcp: { exit: 2, stderr: "grid: error: invalid choice: 'mcp'\n" } })
const { seen, reply } = await retargetOntoLocalModel('GLM-4.7-Flash')
expect(reply?.payload).toMatchObject({ retargeted: true })
expect(seen).toHaveLength(1)
expect(seen[0]!.grid).toMatchObject({ baseUrl: BASE_URL, apiKey: TOKEN, model: 'GLM-4.7-Flash' })
expect(seen[0]!.grid).not.toHaveProperty('mcpUrl')
// The reason reaches the daemon log, and nothing else — the retarget error path is untouched.
expect(warned.join('\n')).toMatch(/web tools unavailable .* older than/)
expect(reply?.payload).not.toHaveProperty('error')
})
})
/**
* `agent_create` carrying a first prompt, a name and a named agent — the fields the run-a-harness-compute
* entry can send (it sends `name` and `agent`). All are validated at the wire, before any pane
* exists; what reaches `onCreateAgent` is exactly what cli.ts hands to the launch and the registry.
*/
describe('agent_create with a prompt, a name and a named agent', () => {
afterEach(() => {
vi.restoreAllMocks()
})
const pending: RegisteredSession = {
schemaVersion: 2, active: true, launch: { state: 'starting' },
agentId: 'named-1', sessionId: '', boundAt: null, engine: 'opencode',
transcriptPath: null, projectDir: 'home', cwd: '/home/someone', defaultName: 'Local model',
runtimes: [{ backend: 'tmux', paneId: '%11' }], primaryRuntimeKey: 'tmux/%11', tmuxPane: '%11',
source: null, title: null, model: null, cliVersion: null, processIdentity: null,
registeredAt: 1, updatedAt: 1, lastHookAt: 1, lastTranscriptAt: 1,
}
async function create(choices: Record<string, unknown>) {
const socket = new BackendSocket('token')
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:named', { sendFrame: (frame) => { frames.push(frame); return true }, sendBinary: () => true })
const seen: unknown[] = []
socket.onCreateAgent = async (input) => { seen.push(input); return { ok: true, session: pending } }
try {
socket.handleLocalFrame('local:named', { type: 'agent_create', payload: { requestId: 'r', engine: 'opencode', cwd: '/home/someone', ...choices } })
await vi.waitFor(() => expect(frames.some((frame) => frame.type === 'agent_create_result')).toBe(true))
} finally {
await socket.unregisterLocalClient('local:named')
await socket.stop()
}
const reply = frames.find((frame) => frame.type === 'agent_create_result')?.payload as Record<string, unknown>
return { seen, reply }
}
it('passes both through, trimmed, and the name becomes the row\'s defaultName', async () => {
const { seen, reply } = await create({ prompt: ' Start a local model on this machine ', name: ' Local model ' })
expect(seen).toEqual([expect.objectContaining({ engine: 'opencode', prompt: 'Start a local model on this machine', name: 'Local model' })])
expect(reply).toMatchObject({ agent: expect.objectContaining({ id: 'named-1', name: 'Local model' }) })
})
it('sends null for both when neither was given, or when they are blank', async () => {
expect((await create({})).seen).toEqual([expect.objectContaining({ prompt: null, name: null })])
expect((await create({ prompt: ' ', name: '' })).seen).toEqual([expect.objectContaining({ prompt: null, name: null })])
})
it('refuses an over-long prompt before any pane exists', async () => {
const { seen, reply } = await create({ prompt: 'x'.repeat(2001) })
expect(reply).toMatchObject({ error: 'PROMPT_TOO_LONG' })
expect(seen).toHaveLength(0)
expect((await create({ prompt: 'x'.repeat(2000) })).seen).toHaveLength(1)
})
it('refuses a prompt for an engine with no documented mechanism, naming the engine', async () => {
const { seen, reply } = await create({ engine: 'cursor', prompt: 'Start a local model on this machine' })
expect(reply).toMatchObject({ error: 'PROMPT_UNSUPPORTED', detail: expect.stringContaining('cursor') })
expect(seen).toHaveLength(0)
})
it('refuses a prompt that is not text', async () => {
const { seen, reply } = await create({ prompt: ['Start a local model'] })
expect(reply).toMatchObject({ error: 'INVALID_PROMPT' })
expect(seen).toHaveLength(0)
})
it('passes the named agent through for opencode, and null when none was given', async () => {
const { seen, reply } = await create({ agent: 'harness-compute', name: 'Local model' })
expect(seen).toEqual([expect.objectContaining({ engine: 'opencode', agent: 'harness-compute', name: 'Local model', prompt: null })])
expect(reply).toMatchObject({ agent: expect.objectContaining({ id: 'named-1' }) })
expect((await create({})).seen).toEqual([expect.objectContaining({ agent: null })])
expect((await create({ agent: null })).seen).toEqual([expect.objectContaining({ agent: null })])
})
it('refuses a named agent for an engine with no documented mechanism, naming the engine, before any pane exists', async () => {
for (const engine of ['claude', 'codex', 'cursor']) {
const { seen, reply } = await create({ engine, agent: 'harness-compute' })
expect(reply).toMatchObject({ error: 'AGENT_UNSUPPORTED', detail: expect.stringContaining(engine) })
expect(seen).toHaveLength(0)
}
})
it('refuses a named agent that is not an identifier — a path, prose, blank, over-long, or not text', async () => {
for (const agent of ['', ' ', 'local model', '../etc/passwd', 'a/b', 'x'.repeat(65), ['harness-compute'], 7]) {
const { seen, reply } = await create({ agent })
expect(reply).toMatchObject({ error: 'INVALID_AGENT' })
expect(seen).toHaveLength(0)
}
})
})
/**
* The picker and the Local model dialog gate on `gridName` — whether the ACCOUNT has a grid — and
* had nothing to tell them whether the MACHINE has a `grid` to run at all. A user with no CLI got a
* dialog that started an agent, which died at the skill's second step. The answer travels beside
* the list, as `localModelEngines` does, and says which grid it is: the managed runtime, one found
* on PATH, or none.
*/
describe('grid_models_list says whether this machine has a grid CLI', () => {
const { gridName: GRID_NAME, plan } = fakeGridAnswers()
let fake: FakeGrid | null = null
afterEach(async () => {
fake?.dispose()
fake = null
wsMock.instances.length = 0
})
async function listModels(): Promise<Record<string, unknown> | undefined> {
const socket = new BackendSocket('token')
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'machine_meta', payload: { name: 'mac', gridName: GRID_NAME } } })
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'grid_models_list', payload: { requestId: 'r' } } })
await vi.waitFor(() => expect(parseSent(ws).some((item) => (item.frame as { type?: string } | undefined)?.type === 'grid_models_list_result')).toBe(true), { timeout: 10_000 })
const reply = parseSent(ws)
.map((item) => item.frame as { type?: string; payload?: Record<string, unknown> } | undefined)
.find((frame) => frame?.type === 'grid_models_list_result')
await socket.stop()
return reply?.payload
}
it('names the grid it would run — the fixture is a developer override, so `path`', async () => {
fake = installFakeGrid(plan)
expect(await listModels()).toMatchObject({ gridName: GRID_NAME, gridCli: 'path' })
})
it('waits for an in-flight grid reconcile before answering, so the first open after an update is not empty', async () => {
fake = installFakeGrid(plan)
const socket = new BackendSocket('token')
// No local fallback and no machine_meta: the name can only come from the reconcile below, so a
// non-empty answer proves the RPC waited for it rather than answering "no grid" straight away.
socket.deriveGridName = async () => null
let settle: () => void = () => {}
const reconcile = new Promise<void>((resolve) => {
settle = () => { socket.setHarnessGridName(GRID_NAME); resolve() }
})
socket.gridReadyProbe = () => reconcile
socket.connect()
const ws = wsMock.instances[0]
ws.open()
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'grid_models_list', payload: { requestId: 'r' } } })
// The reconcile lands a moment later, within the RPC's wait window.
setTimeout(() => settle(), 20)
await vi.waitFor(() => expect(parseSent(ws).some((item) => (item.frame as { type?: string } | undefined)?.type === 'grid_models_list_result')).toBe(true), { timeout: 10_000 })
const reply = parseSent(ws)
.map((item) => item.frame as { type?: string; payload?: Record<string, unknown> } | undefined)
.find((frame) => frame?.type === 'grid_models_list_result')
await socket.stop()
expect(reply?.payload).toMatchObject({ gridName: GRID_NAME })
})
})
describe('the connect burst with no network', () => {
afterEach(() => { wsMock.instances.length = 0 })
it('a grid_models_list that never answers does not hold agents_list or usage_read behind it', async () => {
// Measured 2026-09-18, wifi off, daemon restarted: the desktop asks grid_models_list,
// terminal_capabilities and agents_list in one breath on every connect. grid_models_list waited
// on a grid reconcile that could not finish, and the ordered per-connection chain held the other
// two behind it past the app's 10s timeout — on which the app forced a reconnect and asked all
// three again, for as long as the wifi stayed off. The terminal on the same computer read
// "offline" the whole time.
const socket = new BackendSocket('token')
socket.deriveGridName = async () => null
socket.gridReadyProbe = () => new Promise<void>(() => {}) // a reconcile that never lands
socket.accountUsageReader = () => new Promise(() => {}) // a vendor that never answers
const frames: Array<Record<string, unknown>> = []
socket.registerLocalClient('local:burst', { sendFrame: (frame) => { frames.push(frame); return true }, sendBinary: () => true })
socket.handleLocalFrame('local:burst', { type: 'grid_models_list', payload: { requestId: 'grid' } })
socket.handleLocalFrame('local:burst', { type: 'usage_read', payload: { requestId: 'usage' } })
socket.handleLocalFrame('local:burst', { type: 'agents_list', payload: { requestId: 'agents' } })
await vi.waitFor(() => expect(frames.some((f) => f.type === 'agents_list_result')).toBe(true))
expect(frames.some((f) => f.type === 'grid_models_list_result')).toBe(false)
expect(frames.some((f) => f.type === 'usage_read_result')).toBe(false)
await socket.unregisterLocalClient('local:burst')
await socket.stop()
})
})
describe('machine_meta carries the grid name without clobbering it on rename', () => {
afterEach(() => { wsMock.instances.length = 0 })
it('keeps the grid name when a later rename frame omits gridName, and clears it only on an explicit null', async () => {
const socket = new BackendSocket('token')
// Frames are processed through a queue, so `onMachineMeta` is how a test knows one has landed.
const namesSeen: Array<string | null> = []
socket.onMachineMeta = (n) => { namesSeen.push(n) }
socket.connect()
const ws = wsMock.instances[0]
ws.open()
// Connect frame: name and grid together.
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'machine_meta', payload: { name: 'mac', gridName: 'someone-7f3a91c4' } } })
await vi.waitFor(() => expect(socket.gridName()).toBe('someone-7f3a91c4'))
// A rename pushes `{ name }` alone — it must NOT wipe the grid name (the bug that left the picker
// empty the moment a machine was renamed). Wait until the rename is observably processed, then
// confirm the grid name survived it.
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'machine_meta', payload: { name: 'renamed' } } })
await vi.waitFor(() => expect(namesSeen).toContain('renamed'))
expect(socket.gridName()).toBe('someone-7f3a91c4')
// An explicit null is the account genuinely having no grid, and does clear it.
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'machine_meta', payload: { name: 'renamed', gridName: null } } })
await vi.waitFor(() => expect(socket.gridName()).toBeNull())
await socket.stop()
})
it('refuses a machine_meta that arrived over the LOCAL socket — only the backend may name the grid', async () => {
const socket = new BackendSocket('token')
const namesSeen: Array<string | null> = []
socket.onMachineMeta = (n) => { namesSeen.push(n) }
socket.connect()
const ws = wsMock.instances[0]
ws.open()
// The backend's own frame sets it, as always.
ws.message({ t: 'down', connId: 'web-1', frame: { type: 'machine_meta', payload: { name: 'mac', gridName: 'someone-7f3a91c4' } } })
await vi.waitFor(() => expect(socket.gridName()).toBe('someone-7f3a91c4'))
// Now the same frame from a process on this machine, through the local socket — the shape of the
// leftover script that once redirected this account's agents onto a grid of its choosing.
const local = 'local:1'
socket.registerLocalClient(local, { sendFrame: () => true, sendBinary: () => true })
socket.handleLocalFrame(local, { type: 'machine_meta', payload: { name: 'hijacked', gridName: 'attacker-deadbeef' } })
// Give the queue a turn: the frame must be dropped whole, so neither half of it lands.
await new Promise((r) => setTimeout(r, 50))
expect(socket.gridName()).toBe('someone-7f3a91c4')
expect(namesSeen).not.toContain('hijacked')
await socket.stop()
})
it('refuses a machine_revoked over the LOCAL socket — one frame would otherwise sign this computer out', async () => {
const socket = new BackendSocket('token')
let revoked = 0
socket.onRevoked = () => { revoked += 1 }
socket.connect()
const ws = wsMock.instances[0]
ws.open()
// `onRevoked` clears the stored SSO session and exits the daemon, so accepting this from a local
// process is a one-frame forced sign-out and denial of service.
const local = 'local:1'
socket.registerLocalClient(local, { sendFrame: () => true, sendBinary: () => true })
socket.handleLocalFrame(local, { type: 'machine_revoked', payload: {} })
await new Promise((r) => setTimeout(r, 50))
expect(revoked).toBe(0)
// The backend's own frame still works — the gate is about the sender, not the frame.
ws.message({ t: 'down', connId: '', frame: { type: 'machine_revoked', payload: {} } })
await vi.waitFor(() => expect(revoked).toBe(1))
await socket.stop()
})
})
/** The read-only hardware line for the run-a-harness-compute dialog, answered next to `grid_models_list`. */
describe('Autonomous direct isolation from existing relay/browser behavior', () => {
it('permits offline PAKE only for the exact live direct pending connection', async () => {
const backend = new BackendSocket('direct-offline-test')
const send = vi.fn()
backend.attachDirectDevice('autonomous-direct:test', send)
const pairId = Buffer.alloc(16, 1).toString('base64')
backend.e2ee.handleFrame('browser', { type: 'e2e_pair_intent', payload: { pairId, role: 'web', label: 'Browser' } })
expect(await backend.pair('K7P4X9')).toEqual({ ok: false, error: 'BACKEND_DOWN' })
await backend.receiveDirectDevice('autonomous-direct:test', { type: 'e2e_pair_intent', payload: { pairId, role: 'device', label: 'Autonomous device' } }, true)
const paired = backend.pair('K7P4X9')
expect(send).toHaveBeenCalledWith(expect.objectContaining({ type: 'e2e_pake' }))
await backend.receiveDirectDevice('autonomous-direct:test', { type: 'e2e_pair_cancel', payload: { pairId } }, true)
expect(await paired).toEqual({ ok: false, error: 'CANCELLED' })
backend.detachDirectDevice('autonomous-direct:test')
})
it('never dispatches setup/password/admin/terminal frames from a discovered endpoint', async () => {
const backend = new BackendSocket('direct-whitelist-test')
backend.attachDirectDevice('autonomous-direct:test', vi.fn())
const handle = vi.spyOn(backend.e2ee, 'handleFrame').mockReturnValue(true)
for (const type of ['e2e_setup_claim', 'e2e_pw_pair_intent', 'e2e_pw_pake', 'terminal_open', 'machine_revoked', '__clients']) {
await backend.receiveDirectDevice('autonomous-direct:test', { type, payload: {} }, true)
}
expect(handle).not.toHaveBeenCalled()
await backend.receiveDirectDevice('autonomous-direct:test', { type: 'e2e_pair_intent', payload: {} }, false)
expect(handle).not.toHaveBeenCalled()
await backend.receiveDirectDevice('autonomous-direct:test', { type: 'e2e_hello', payload: {} }, false)
expect(handle).toHaveBeenCalledOnce()
backend.detachDirectDevice('autonomous-direct:test')
})
})