test: retire relay, preload and shared cases that re-prove an owned contract (#24007)

Audit sweep over `src/relay`, `src/preload` and `src/shared` (1,087 test files
reviewed). 101 case declarations removed across 40 files, 6 test files deleted
outright, 1,143 lines gone. Executed-case count falls further, since several
removals were `it.each` tables.

Dominant patterns, by frequency:

- Self-comparisons that cannot fail: `expect(f(x)).toBe(f(x))`,
  `JSON.parse(JSON.stringify(literal))` deep-equalling the literal for a type
  with no codec, and `normalizeKeyToken(t) === normalizeKeyToken(t)` presented as
  proof of memoization.
- Object literals asserting their own fields back, where the guarantee comes from
  the type annotation and the runtime assertion cannot fail.
- Copied inventories: constants compared to their own initializers, and a
  function returning a copy of an exported constant checked against that
  constant's literal contents.
- Duplicate invocations of a contract owned at a stronger boundary, including
  provider-local replays of a shared helper.
- Table rows varying a field production never reads, so every row runs one path.
- Names promising more than the input exercises: a "Windows launch" case in a
  module with no platform input, and a case whose named branch is never entered.

Two production symbols go with them, each a test-only export whose sole caller
was a deleted case:

- `getGitHubProjectRefInputByteLength` — a one-line forward to
  `getClipboardTextByteLength`. The real bound
  (`GITHUB_PROJECT_REF_INPUT_MAX_BYTES`) and its guard stay.
- `GRAB_STYLE_PROPERTIES` — an intended shared source of truth that nothing ever
  consulted; the property set is hand-enumerated at three independent sites.

One case was deliberately restored and strengthened rather than dropped. The
relay integration suite is the only place the real `SshChannelMultiplexer` is
wired to `RelayDispatcher`, so it reaches transport behavior the handler suites
cannot (they use `createMockDispatcher`). Its `fs.writeFile` roundtrip is the one
case producing a void result, and `JSON.stringify` drops an absent `result`
member — a shape no other surviving case exercises. Restored with an assertion
pinning what the client actually observes: `null`, not `undefined`. That
assertion failed on first run, so the fact was previously unasserted anywhere.

One deletion was reverted mid-audit. A case asserting that optional fields stay
invisible to "old attach and ready decoders" builds those decoders from `z.object`
schemas declared in the test file, so it demonstrates zod's unknown-key stripping
rather than anything shipped. It is nonetheless the only forward-compatibility
coverage these envelopes have, and `reliability-gates.jsonc:6232` names it as
evidence verbatim, so it stays. Note that `check-reliability-gates.mjs` passed
both with and without it: the script resolves manifest paths and commands, and
does not check that a named assertion still corresponds to a live case.

Kept deliberately: everything a reliability gate cites as evidence; the three
`registers all expected handlers` RPC manifests (a dropped registration is a
silent wire break no type checker catches, and one carries the STA-4571
`pty.ackData` ratchet); the `child-process` direct-import ratchet; and
prototype-spy cases paired with a `.repeat(10_000)` input, which assert a real
memory bound rather than merely forbidding a technique.

Verified: `pnpm test src/shared src/relay src/preload` (1073 files, 11996
passed, 1 pre-existing `it.fails`, 131 skipped), `pnpm tc` after clearing
`.tsbuildinfo`, `check-reliability-gates.mjs` (140 gates),
`check:code-quality:changed` (0 new findings).
This commit is contained in:
Neil
2026-09-29 22:17:13 -07:00
committed by GitHub
parent b7209b5ae9
commit dcaef9dee5
40 changed files with 33 additions and 1143 deletions
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from 'vitest'
import { describe, expect, it } from 'vitest'
import { readRendererProcessMemory } from './renderer-process-memory-reader'
// Why the partial type: Electron types `residentSet` as required, but Chromium
@@ -38,10 +38,4 @@ describe('readRendererProcessMemory', () => {
readRendererProcessMemory(source(async () => ({ private: Number.NaN, shared: 0 })))
).resolves.toBeNull()
})
it('does not call the API more than once per read', async () => {
const getProcessMemoryInfo = vi.fn(async () => ({ private: 2048, shared: 0 }))
await readRendererProcessMemory(source(getProcessMemoryInfo))
expect(getProcessMemoryInfo).toHaveBeenCalledTimes(1)
})
})
@@ -81,11 +81,4 @@ describe('native preload linux package recovery methods', () => {
expect(invoke.mock.calls).toEqual([['updater:showLinuxPackage']])
})
it('surfaces a main-process validation rejection to the caller', async () => {
const api = await loadApi()
invoke.mockRejectedValueOnce(new Error('hash mismatch'))
await expect(api.updater.getLinuxPackageInstallInstructions()).rejects.toThrow('hash mismatch')
})
})
+16 -218
View File
@@ -8,7 +8,7 @@
*/
import { describe, expect, it, beforeEach, afterEach } from 'vitest'
import { mkdtempSync, writeFileSync } from 'node:fs'
import { rm, readFile, stat } from 'node:fs/promises'
import { rm, readFile } from 'node:fs/promises'
import * as path from 'node:path'
import { tmpdir } from 'node:os'
import { execFileSync } from 'node:child_process'
@@ -119,6 +119,21 @@ describe('Integration: Client Mux ↔ Relay Dispatcher', () => {
expect(result.isBinary).toBe(false)
})
// Why this one stays: writeRelayFile resolves to undefined, so the response frame
// carries neither `result` nor `error` — the one payload shape the other cases here
// do not produce, and one a mock dispatcher never has to settle. The client sees
// `null`, not `undefined`: the member is absent from the frame, not carried as void.
it('writeFile creates/overwrites file content', async () => {
const filePath = path.join(tmpDir, 'output.txt')
await expect(
mux.request('fs.writeFile', { filePath, content: 'written via relay' })
).resolves.toBeNull()
const content = await readFile(filePath, 'utf-8')
expect(content).toBe('written via relay')
})
it('readFileStream round-trip preserves a 12 MB binary file', async () => {
const filePath = path.join(tmpDir, 'big.png')
const original = randomBytes(12 * 1024 * 1024)
@@ -127,78 +142,6 @@ describe('Integration: Client Mux ↔ Relay Dispatcher', () => {
const { content } = await readFileViaStream(mux, filePath)
expect(Buffer.from(content, 'base64').equals(original)).toBe(true)
}, 30_000)
it('writeFile creates/overwrites file content', async () => {
const filePath = path.join(tmpDir, 'output.txt')
await mux.request('fs.writeFile', { filePath, content: 'written via relay' })
const content = await readFile(filePath, 'utf-8')
expect(content).toBe('written via relay')
})
it('stat returns file metadata', async () => {
writeFileSync(path.join(tmpDir, 'sized.txt'), 'abcdef')
const result = (await mux.request('fs.stat', {
filePath: path.join(tmpDir, 'sized.txt')
})) as { size: number; type: string; mtime: number }
expect(result).toMatchObject({ type: 'file', size: 6 })
expect(typeof result.mtime).toBe('number')
})
it('createFile + deletePath roundtrip', async () => {
const filePath = path.join(tmpDir, 'nested', 'deep', 'new.txt')
await mux.request('fs.createFile', { filePath })
const s = await stat(filePath)
expect(s.isFile()).toBe(true)
await mux.request('fs.deletePath', { targetPath: filePath })
await expect(stat(filePath)).rejects.toThrow()
})
it('createDir creates directories recursively', async () => {
const dirPath = path.join(tmpDir, 'a', 'b', 'c')
await mux.request('fs.createDir', { dirPath })
const s = await stat(dirPath)
expect(s.isDirectory()).toBe(true)
})
it('rename moves files', async () => {
const oldPath = path.join(tmpDir, 'before.txt')
const newPath = path.join(tmpDir, 'after.txt')
writeFileSync(oldPath, 'moving')
await mux.request('fs.rename', { oldPath, newPath })
await expect(stat(oldPath)).rejects.toThrow()
const content = await readFile(newPath, 'utf-8')
expect(content).toBe('moving')
})
it('copy duplicates files', async () => {
const src = path.join(tmpDir, 'src.txt')
const dst = path.join(tmpDir, 'dst.txt')
writeFileSync(src, 'original')
await mux.request('fs.copy', { source: src, destination: dst })
const content = await readFile(dst, 'utf-8')
expect(content).toBe('original')
})
it('readFile returns error for non-existent file', async () => {
await expect(
mux.request('fs.readFile', { filePath: path.join(tmpDir, 'nope.txt') })
).rejects.toThrow()
})
it('errors propagate correctly through the protocol', async () => {
await expect(
mux.request('fs.stat', { filePath: '/nonexistent/path/that/does/not/exist' })
).rejects.toThrow()
})
})
// ─── Git ────────────────────────────────────────────────────────
@@ -210,66 +153,6 @@ describe('Integration: Client Mux ↔ Relay Dispatcher', () => {
gitCommit(tmpDir, 'initial commit')
})
it('git.status returns clean status for committed repo', async () => {
const result = (await mux.request('git.status', {
worktreePath: tmpDir
})) as { entries: unknown[]; conflictOperation: string }
expect(result.entries).toEqual([])
expect(result.conflictOperation).toBe('unknown')
})
it('git.status detects modifications', async () => {
writeFileSync(path.join(tmpDir, 'file.txt'), 'modified')
const result = (await mux.request('git.status', {
worktreePath: tmpDir
})) as { entries: { path: string; status: string; area: string }[] }
const entry = result.entries.find((e) => e.path === 'file.txt')
expect(entry).toBeDefined()
expect(entry!.status).toBe('modified')
expect(entry!.area).toBe('unstaged')
})
it('git.status detects untracked files', async () => {
writeFileSync(path.join(tmpDir, 'new.txt'), 'new')
const result = (await mux.request('git.status', {
worktreePath: tmpDir
})) as { entries: { path: string; status: string; area: string }[] }
const entry = result.entries.find((e) => e.path === 'new.txt')
expect(entry).toBeDefined()
expect(entry!.status).toBe('untracked')
})
it('git.stage + git.status shows staged entry', async () => {
writeFileSync(path.join(tmpDir, 'file.txt'), 'changed')
await mux.request('git.stage', { worktreePath: tmpDir, filePath: 'file.txt' })
const result = (await mux.request('git.status', {
worktreePath: tmpDir
})) as { entries: { path: string; area: string }[] }
const staged = result.entries.find((e) => e.area === 'staged')
expect(staged).toBeDefined()
})
it('git.unstage reverses staging', async () => {
writeFileSync(path.join(tmpDir, 'file.txt'), 'changed')
await mux.request('git.stage', { worktreePath: tmpDir, filePath: 'file.txt' })
await mux.request('git.unstage', { worktreePath: tmpDir, filePath: 'file.txt' })
const result = (await mux.request('git.status', {
worktreePath: tmpDir
})) as { entries: { area: string }[] }
const staged = result.entries.filter((e) => e.area === 'staged')
expect(staged.length).toBe(0)
})
it('git.diff returns original and modified content', async () => {
writeFileSync(path.join(tmpDir, 'file.txt'), 'updated content')
@@ -283,91 +166,6 @@ describe('Integration: Client Mux ↔ Relay Dispatcher', () => {
expect(result.originalContent).toBe('initial')
expect(result.modifiedContent).toBe('updated content')
})
it('git.diff returns staged diff', async () => {
writeFileSync(path.join(tmpDir, 'file.txt'), 'staged version')
execFileSync('git', ['add', 'file.txt'], { cwd: tmpDir, stdio: 'pipe' })
const result = (await mux.request('git.diff', {
worktreePath: tmpDir,
filePath: 'file.txt',
staged: true
})) as { originalContent: string; modifiedContent: string }
expect(result.originalContent).toBe('initial')
expect(result.modifiedContent).toBe('staged version')
})
it('git.discard restores tracked file to HEAD', async () => {
writeFileSync(path.join(tmpDir, 'file.txt'), 'dirty')
await mux.request('git.discard', { worktreePath: tmpDir, filePath: 'file.txt' })
const content = await readFile(path.join(tmpDir, 'file.txt'), 'utf-8')
expect(content).toBe('initial')
})
it('git.discard removes untracked file', async () => {
writeFileSync(path.join(tmpDir, 'temp.txt'), 'throwaway')
await mux.request('git.discard', { worktreePath: tmpDir, filePath: 'temp.txt' })
await expect(stat(path.join(tmpDir, 'temp.txt'))).rejects.toThrow()
})
it('git.conflictOperation returns unknown for normal repo', async () => {
const result = await mux.request('git.conflictOperation', {
worktreePath: tmpDir
})
expect(result).toBe('unknown')
})
it('git.listWorktrees returns the main worktree', async () => {
const result = (await mux.request('git.listWorktrees', {
repoPath: tmpDir
})) as { path: string; isMainWorktree: boolean }[]
expect(result.length).toBeGreaterThanOrEqual(1)
expect(result[0].isMainWorktree).toBe(true)
})
it('git.branchCompare works across branches', async () => {
// Get current branch name (might be "main" or "master" depending on config)
const defaultBranch = execFileSync('git', ['branch', '--show-current'], {
cwd: tmpDir,
encoding: 'utf-8'
}).trim()
execFileSync('git', ['checkout', '-b', 'feature'], { cwd: tmpDir, stdio: 'pipe' })
writeFileSync(path.join(tmpDir, 'feature.txt'), 'feature work')
gitCommit(tmpDir, 'feature commit')
const result = (await mux.request('git.branchCompare', {
worktreePath: tmpDir,
baseRef: defaultBranch
})) as { summary: { status: string; commitsAhead: number }; entries: unknown[] }
expect(result.summary.status).toBe('ready')
expect(result.summary.commitsAhead).toBe(1)
expect(result.entries.length).toBe(1)
})
it('git.bulkStage stages multiple files at once', async () => {
writeFileSync(path.join(tmpDir, 'a.txt'), 'a')
writeFileSync(path.join(tmpDir, 'b.txt'), 'b')
await mux.request('git.bulkStage', {
worktreePath: tmpDir,
filePaths: ['a.txt', 'b.txt']
})
const result = (await mux.request('git.status', {
worktreePath: tmpDir
})) as { entries: { path: string; area: string }[] }
const staged = result.entries.filter((e) => e.area === 'staged')
expect(staged.length).toBe(2)
})
})
// ─── Error propagation ──────────────────────────────────────────
-26
View File
@@ -315,16 +315,6 @@ describe('parseHexAddress', () => {
expect(result).toEqual({ host: '0.0.0.0', port: 8080 })
})
it('parses port 22 correctly', () => {
const result = parseHexAddress('00000000:0016')
expect(result).toEqual({ host: '0.0.0.0', port: 22 })
})
it('parses port 443 correctly', () => {
const result = parseHexAddress('0100007F:01BB')
expect(result).toEqual({ host: '127.0.0.1', port: 443 })
})
it('parses a non-localhost IPv4 address', () => {
// 192.168.1.100 in little-endian: 6401A8C0
const result = parseHexAddress('6401A8C0:1388')
@@ -351,22 +341,6 @@ describe('parseHexAddress', () => {
expect(parseHexAddress('')).toBeNull()
expect(parseHexAddress('::::')).toBeNull()
})
it('parses high ports correctly', () => {
// Port 65535 = FFFF
const result = parseHexAddress('0100007F:FFFF')
expect(result).toEqual({ host: '127.0.0.1', port: 65535 })
})
it('parses port 5432 (postgres)', () => {
const result = parseHexAddress('0100007F:1538')
expect(result).toEqual({ host: '127.0.0.1', port: 5432 })
})
it('parses port 3306 (mysql)', () => {
const result = parseHexAddress('00000000:0CEA')
expect(result).toEqual({ host: '0.0.0.0', port: 3306 })
})
})
describe('parseWindowsPowerShellPortRows', () => {
@@ -1,136 +0,0 @@
import { describe, expect, it } from 'vitest'
import { RecentPtyOutputBuffer } from '../main/runtime/recent-pty-output-buffer'
import { REPLAY_BUFFER_MAX } from './pty-handler'
// Reference: the pre-change replay buffer, a rolling string sliced per append.
function appendStringTail(previous: string, data: string): string {
if (data.length === 0) {
return previous
}
const next = previous + data
return next.length > REPLAY_BUFFER_MAX ? next.slice(-REPLAY_BUFFER_MAX) : next
}
function makeBuffer(): RecentPtyOutputBuffer {
return new RecentPtyOutputBuffer({ preserveChunkBoundaries: false, limit: REPLAY_BUFFER_MAX })
}
function replayEquals(chunks: string[]): { deque: string; reference: string } {
const buffer = makeBuffer()
let reference = ''
for (const chunk of chunks) {
buffer.append(chunk)
reference = appendStringTail(reference, chunk)
}
return { deque: buffer.read(), reference }
}
// Deterministic PRNG so a failure is reproducible.
function makeRandom(seed: number): () => number {
let state = seed >>> 0
return () => {
state = (state * 1664525 + 1013904223) >>> 0
return state / 0x100000000
}
}
describe('relay replay buffer equivalence', () => {
it('matches the rolling-string tail below the cap', () => {
const { deque, reference } = replayEquals(['hello ', 'world', '\r\n$ '])
expect(deque).toBe(reference)
expect(deque).toBe('hello world\r\n$ ')
})
it('matches once the window saturates', () => {
const chunks = Array.from({ length: 40 }, (_value, index) => `chunk-${index}-`.repeat(400))
const { deque, reference } = replayEquals(chunks)
expect(deque.length).toBe(REPLAY_BUFFER_MAX)
expect(deque).toBe(reference)
})
it('matches when one append alone exceeds the cap', () => {
const { deque, reference } = replayEquals(['x'.repeat(REPLAY_BUFFER_MAX * 2 + 7)])
expect(deque.length).toBe(REPLAY_BUFFER_MAX)
expect(deque).toBe(reference)
})
it('matches when an oversized append follows existing content', () => {
const { deque, reference } = replayEquals(['prefix', 'y'.repeat(REPLAY_BUFFER_MAX + 3)])
expect(deque).toBe(reference)
expect(deque.startsWith('prefix')).toBe(false)
})
it('matches at exactly the cap boundary', () => {
for (const total of [REPLAY_BUFFER_MAX - 1, REPLAY_BUFFER_MAX, REPLAY_BUFFER_MAX + 1]) {
const { deque, reference } = replayEquals(['a'.repeat(total)])
expect(deque).toBe(reference)
}
})
it('ignores empty appends exactly as the string form did', () => {
const { deque, reference } = replayEquals(['a', '', 'b', '', 'c'])
expect(deque).toBe(reference)
expect(deque).toBe('abc')
})
it('is stable across repeated reads', () => {
const buffer = makeBuffer()
for (let index = 0; index < 200; index += 1) {
buffer.append(`line ${index}\r\n`.repeat(30))
}
expect(buffer.read()).toBe(buffer.read())
})
it('keeps appending correctly after a read collapses the deque', () => {
const buffer = makeBuffer()
let reference = ''
for (let index = 0; index < 60; index += 1) {
const chunk = `mid-${index}-`.repeat(300)
buffer.append(chunk)
reference = appendStringTail(reference, chunk)
// Interleave reads: attach/adopt/revive can land at any point in the stream.
if (index % 7 === 0) {
expect(buffer.read()).toBe(reference)
}
}
expect(buffer.read()).toBe(reference)
})
// Why fuzz: the deque trims across chunk boundaries with a deferred head offset,
// so the risky cases are irregular chunk sizes straddling the cap repeatedly.
it('matches the rolling string across randomized chunk streams', () => {
for (let seed = 1; seed <= 40; seed += 1) {
const random = makeRandom(seed)
const buffer = makeBuffer()
let reference = ''
for (let step = 0; step < 120; step += 1) {
const size = Math.floor(random() * (REPLAY_BUFFER_MAX / 8))
const chunk = String.fromCharCode(97 + (step % 26)).repeat(size)
buffer.append(chunk)
reference = appendStringTail(reference, chunk)
}
expect(buffer.read(), `seed ${seed}`).toBe(reference)
}
})
// Why surrogates: trimming by code unit can split a pair, and the string form did
// exactly the same thing. The deque must not "fix" it into a different tail.
it('splits surrogate pairs identically to the rolling string', () => {
// Why the trailing unit: the cap is even and a pair is 2 units, so an emoji run
// alone always cuts on a pair boundary. One odd unit shifts the cut mid-pair.
const { deque, reference } = replayEquals([`${'\u{1F600}'.repeat(REPLAY_BUFFER_MAX)}z`])
expect(deque).toBe(reference)
expect(deque.length).toBe(REPLAY_BUFFER_MAX)
const leadUnit = deque.charCodeAt(0)
expect(leadUnit).toBeGreaterThanOrEqual(0xdc00)
expect(leadUnit).toBeLessThanOrEqual(0xdfff)
})
it('keeps a pair-aligned tail intact when the cut lands on a boundary', () => {
const { deque, reference } = replayEquals(['\u{1F600}'.repeat(REPLAY_BUFFER_MAX)])
expect(deque).toBe(reference)
const leadUnit = deque.charCodeAt(0)
expect(leadUnit).toBeGreaterThanOrEqual(0xd800)
expect(leadUnit).toBeLessThanOrEqual(0xdbff)
})
})
@@ -205,21 +205,6 @@ describe('relay oversized notification survival', () => {
}
})
it("publishAgentHookEnvelope does not mutate the caller's envelope", () => {
const sink: Buffer[] = []
const dispatcher = createDispatcher(NODE21_HWM, () => {}, sink)
const envelope = buildMaximalHookEnvelope()
const before = structuredClone(envelope)
try {
publishAgentHookEnvelope(dispatcher, envelope as unknown as AgentHookRelayEnvelope)
// The hook server replays this exact object after --connect, so shedding must never touch it.
expect(envelope).toEqual(before)
} finally {
dispatcher.dispose()
}
})
it('reattach + replay does not re-kill', () => {
const sink: Buffer[] = []
let killCloses = 0
-32
View File
@@ -234,38 +234,6 @@ describe('Subprocess: Relay entry point', () => {
expect(repaired.result).toMatchObject({ id: expect.stringMatching(/^pty2:[^:]+:2$/) })
}, 10_000)
it('responds to fs.stat over stdin/stdout', async () => {
tmpDir = mkdtempSync(path.join(tmpdir(), 'relay-sub-'))
writeFileSync(path.join(tmpDir, 'test.txt'), 'hello')
relay = spawn()
await relay.sentinelReceived
const id = relay.send('fs.stat', { filePath: path.join(tmpDir, 'test.txt') })
const resp = await relay.waitForResponse(id)
expect(resp.result).toBeDefined()
const result = resp.result as { size: number; type: string }
expect(result.type).toBe('file')
expect(result.size).toBe(5)
}, 10_000)
it('responds to fs.readDir', async () => {
tmpDir = mkdtempSync(path.join(tmpdir(), 'relay-sub-'))
writeFileSync(path.join(tmpDir, 'a.txt'), 'a')
writeFileSync(path.join(tmpDir, 'b.txt'), 'b')
relay = spawn()
await relay.sentinelReceived
const id = relay.send('fs.readDir', { dirPath: tmpDir })
const resp = await relay.waitForResponse(id)
const entries = resp.result as { name: string }[]
const names = entries.map((e) => e.name).sort()
expect(names).toEqual(['a.txt', 'b.txt'])
}, 10_000)
it('responds to fs.readFile and fs.writeFile', async () => {
tmpDir = mkdtempSync(path.join(tmpdir(), 'relay-sub-'))
@@ -108,15 +108,4 @@ describe('normalizeDshEvent', () => {
).toBeNull()
}
})
it('ignores events the bridge cannot send', () => {
// Notification and PermissionRequest are Claude-only; if one ever arrives it is not
// from this bridge, and guessing a state from it would be unfounded.
expect(
normalizeAndAccept(state, 'dsh', event('Notification', { message: 'waiting' }))
).toBeNull()
expect(
normalizeAndAccept(state, 'dsh', event('PermissionRequest', { tool_name: 'bash' }))
).toBeNull()
})
})
@@ -166,13 +166,4 @@ describe('normalizeZCodeEvent', () => {
it('ignores lifecycle events it does not model', () => {
expect(normalizeAndAccept(state, 'zcode', zcodeEvent('SomethingElse'))).toBeNull()
})
it('attributes every event to zcode, never to claude, despite the compatible payload', () => {
const event = normalizeAndAccept(
state,
'zcode',
zcodeEvent('UserPromptSubmit', { prompt: 'hello' })
)
expect(event?.payload.agentType).toBe('zcode')
})
})
+1 -28
View File
@@ -8,38 +8,11 @@ import {
createShedSubagentsField,
isAgentHookSource,
isRemoteAgentHooksEnabled,
restoreShedStatusFields,
type AgentHookRelayEnvelope
restoreShedStatusFields
} from './agent-hook-relay'
import type { ParsedAgentStatusPayload } from './agent-status-types'
describe('agent-hook-relay wire shape', () => {
it('encodes/decodes through JSON without losing fields', () => {
const envelope: AgentHookRelayEnvelope = {
source: 'claude',
paneKey: 'tab-1:0',
tabId: 'tab-1',
worktreeId: 'wt-1',
connectionId: null,
env: 'production',
version: '1',
providerPromptId: '11111111-1111-4111-8111-111111111111',
compactTrigger: 'manual',
payload: {
state: 'working',
workingMode: 'monitoring',
prompt: 'roundtrip',
agentType: 'claude'
}
}
const decoded = JSON.parse(JSON.stringify(envelope)) as AgentHookRelayEnvelope
expect(decoded).toEqual(envelope)
expect(decoded.connectionId).toBeNull()
expect(decoded.payload.prompt).toBe('roundtrip')
expect(decoded.payload.workingMode).toBe('monitoring')
})
it('exposes stable JSON-RPC method names', () => {
expect(AGENT_HOOK_NOTIFICATION_METHOD).toBe('agent.hook')
expect(AGENT_HOOK_REQUEST_REPLAY_METHOD).toBe('agent_hook.requestReplay')
-20
View File
@@ -12,26 +12,6 @@ describe('agent session resume metadata', () => {
expect(isResumableTuiAgent('devin')).toBe(true)
})
it('treats omp as a resumable TUI agent', () => {
expect(isResumableTuiAgent('omp')).toBe(true)
})
it('treats Prime Agent as a resumable TUI agent', () => {
expect(isResumableTuiAgent('prime-agent')).toBe(true)
})
it('treats copilot as a resumable TUI agent', () => {
expect(isResumableTuiAgent('copilot')).toBe(true)
})
it('treats Kimi Code as a resumable TUI agent', () => {
expect(isResumableTuiAgent('kimi')).toBe(true)
})
it('treats CodeBuddy as a resumable TUI agent', () => {
expect(isResumableTuiAgent('codebuddy')).toBe(true)
})
it.each([
['claude', { session_id: 'claude-session' }, { key: 'session_id', id: 'claude-session' }],
['codex', { session_id: 'codex-session' }, { key: 'session_id', id: 'codex-session' }],
@@ -38,38 +38,4 @@ describe('OSC 9999 split-frame scan budget', () => {
// Re-scanning the accumulation would quadruple the budget when the feed doubles.
expect(large.searchedChars).toBeLessThan(small.searchedChars * 3)
})
it.each(['\x07', '\x1b\\'])(
'matches whole-string parsing when split at every offset with terminator %j',
(terminator) => {
const stream = `head\x1b]9999;{"state":"working","prompt":"p"}${terminator}tail`
const whole = createAgentStatusOscProcessor()(stream)
for (let split = 1; split < stream.length; split += 1) {
const process = createAgentStatusOscProcessor()
const first = process(stream.slice(0, split))
const second = process(stream.slice(split))
expect({
cleanData: first.cleanData + second.cleanData,
payloads: [...first.payloads, ...second.payloads]
}).toEqual({ cleanData: whole.cleanData, payloads: whole.payloads })
}
}
)
it('finds a string terminator straddling the resume boundary', () => {
const process = createAgentStatusOscProcessor()
// The ESC lands as the last character of the carried frame; the backslash arrives next.
expect(process('\x1b]9999;{"state":"working"}\x1b').payloads).toEqual([])
expect(process('\\rest').payloads).toMatchObject([{ state: 'working' }])
})
it('still parses a payload that completes many chunks later', () => {
const process = createAgentStatusOscProcessor()
process('\x1b]9999;{"state":"wor')
for (const chunk of ['k', 'i', 'n', 'g']) {
expect(process(chunk).payloads).toEqual([])
}
expect(process('"}\x07done').payloads).toMatchObject([{ state: 'working' }])
})
})
-30
View File
@@ -1,28 +1,11 @@
import { describe, expect, it } from 'vitest'
import {
GRAB_BUDGET,
GRAB_SAFE_ATTRIBUTE_NAMES,
GRAB_SECRET_PATTERNS,
GRAB_STYLE_PROPERTIES,
isAriaAttribute
} from './browser-grab-types'
describe('browser-grab-types', () => {
describe('GRAB_BUDGET', () => {
it('defines all required budget fields', () => {
expect(GRAB_BUDGET.textSnippetMaxLength).toBe(200)
expect(GRAB_BUDGET.nearbyTextEntryMaxLength).toBe(200)
expect(GRAB_BUDGET.nearbyTextMaxEntries).toBe(10)
expect(GRAB_BUDGET.htmlSnippetMaxLength).toBe(4096)
expect(GRAB_BUDGET.ancestorPathMaxEntries).toBe(10)
expect(GRAB_BUDGET.nearbyElementMaxLength).toBe(160)
expect(GRAB_BUDGET.cssClassesMaxLength).toBe(500)
expect(GRAB_BUDGET.selectedTextMaxLength).toBe(500)
expect(GRAB_BUDGET.annotationsMaxPerPage).toBe(20)
expect(GRAB_BUDGET.screenshotMaxBytes).toBe(2 * 1024 * 1024)
})
})
describe('isAriaAttribute', () => {
it('returns true for aria- prefixed attributes', () => {
expect(isAriaAttribute('aria-label')).toBe(true)
@@ -71,17 +54,4 @@ describe('browser-grab-types', () => {
expect(GRAB_SECRET_PATTERNS).not.toContain('token')
})
})
describe('GRAB_STYLE_PROPERTIES', () => {
it('includes the curated subset of computed styles', () => {
expect(GRAB_STYLE_PROPERTIES).toContain('display')
expect(GRAB_STYLE_PROPERTIES).toContain('fontSize')
expect(GRAB_STYLE_PROPERTIES).toContain('backgroundColor')
expect(GRAB_STYLE_PROPERTIES).toContain('zIndex')
})
it('has exactly 16 properties matching the type', () => {
expect(GRAB_STYLE_PROPERTIES).toHaveLength(16)
})
})
})
-20
View File
@@ -241,23 +241,3 @@ export const GRAB_SECRET_PATTERNS = [
'password',
'passwd'
]
/** Computed style properties to extract — matches BrowserGrabComputedStyles keys. */
export const GRAB_STYLE_PROPERTIES: readonly (keyof BrowserGrabComputedStyles)[] = [
'display',
'position',
'width',
'height',
'margin',
'padding',
'color',
'backgroundColor',
'border',
'borderRadius',
'fontFamily',
'fontSize',
'fontWeight',
'lineHeight',
'textAlign',
'zIndex'
]
-2
View File
@@ -115,8 +115,6 @@ describe('getDefaultSettings', () => {
expect(getDefaultSettings('/tmp').experimentalAgentDashboardShowIdle).toBeUndefined()
})
it('routes fresh Codex profiles through the real-home rollout by default', () => {})
it('defaults local Windows projects to the host runtime', () => {
expect(getDefaultSettings('/tmp').localWindowsRuntimeDefault).toEqual({
kind: 'windows-host'
-25
View File
@@ -2,31 +2,6 @@ import { describe, expect, it } from 'vitest'
import { buildAgentStartupPlan } from './tui-agent-startup'
describe('Freebuff startup', () => {
it.each([
['darwin', 'posix', false],
['linux', 'posix', false],
['win32', 'powershell', false],
['win32', 'cmd', false],
['linux', 'posix', true]
] as const)('delivers prompts after launch on %s/%s (remote=%s)', (platform, shell, isRemote) => {
const prompt = 'Review "quoted paths"; $(echo task)\nThen explain the changes.'
const plan = buildAgentStartupPlan({
agent: 'freebuff',
prompt,
cmdOverrides: { codebuff: 'codebuff --debug' },
platform,
shell,
isRemote
})
expect(plan).toMatchObject({
agent: 'freebuff',
launchCommand: 'freebuff',
expectedProcess: 'freebuff',
followupPrompt: prompt
})
})
it('keeps Freebuff command overrides separate from Codebuff', () => {
const cmdOverrides = { freebuff: 'freebuff --debug' }
const freebuff = buildAgentStartupPlan({
+7 -16
View File
@@ -1,25 +1,16 @@
import { describe, expect, it, vi } from 'vitest'
import { describe, expect, it } from 'vitest'
import {
parseGitRevListAheadBehindCounts,
parseGitRevListFirstParentOid
} from './git-rev-list-output'
describe('parseGitRevListAheadBehindCounts', () => {
it('parses rev-list counts without whitespace-regex splitting', () => {
const splitSpy = vi.spyOn(String.prototype, 'split')
try {
expect(parseGitRevListAheadBehindCounts(' 12\t3\r\n')).toEqual({
status: 'ok',
ahead: 12,
behind: 3
})
const usedWhitespaceSplit = splitSpy.mock.calls.some(
([separator]) => separator instanceof RegExp && separator.source === '\\s+'
)
expect(usedWhitespaceSplit).toBe(false)
} finally {
splitSpy.mockRestore()
}
it('parses counts surrounded by mixed whitespace', () => {
expect(parseGitRevListAheadBehindCounts(' 12\t3\r\n')).toEqual({
status: 'ok',
ahead: 12,
behind: 3
})
})
it('rejects missing or extra fields', () => {
@@ -2,38 +2,11 @@ import { describe, expect, it } from 'vitest'
import {
GITHUB_PROJECT_REF_INPUT_MAX_BYTES,
getGitHubProjectRefInputByteLength,
hasBoundedGitHubProjectRefInputText,
isGitHubProjectRefInputTooLarge
} from './project-ref-input'
describe('GitHub project reference input limits', () => {
it('allows normal project references below the byte budget', () => {
expect(
isGitHubProjectRefInputTooLarge('https://github.com/orgs/acme/projects/42/views/3')
).toBe(false)
})
it('measures UTF-8 bytes instead of JavaScript string length', () => {
expect(getGitHubProjectRefInputByteLength('\u00e9')).toBe(2)
})
it('rejects oversized pasted project references', () => {
expect(isGitHubProjectRefInputTooLarge('x'.repeat(GITHUB_PROJECT_REF_INPUT_MAX_BYTES))).toBe(
false
)
expect(
isGitHubProjectRefInputTooLarge('x'.repeat(GITHUB_PROJECT_REF_INPUT_MAX_BYTES + 1))
).toBe(true)
})
it('rejects multibyte project references whose character count is below the limit', () => {
const reference = '😀'.repeat(Math.floor(GITHUB_PROJECT_REF_INPUT_MAX_BYTES / 4) + 1)
expect(reference.length).toBeLessThan(GITHUB_PROJECT_REF_INPUT_MAX_BYTES)
expect(isGitHubProjectRefInputTooLarge(reference)).toBe(true)
})
it('rejects oversized whitespace before submit checks trim the reference', () => {
const oversizedWhitespace = ' '.repeat(GITHUB_PROJECT_REF_INPUT_MAX_BYTES + 1)
+1 -5
View File
@@ -1,12 +1,8 @@
import { getClipboardTextByteLength, isClipboardTextByteLengthOverLimit } from '../clipboard-text'
import { isClipboardTextByteLengthOverLimit } from '../clipboard-text'
export const GITHUB_PROJECT_REF_INPUT_MAX_BYTES = 2 * 1024
export const GITHUB_PROJECT_REF_INPUT_TOO_LARGE_ERROR = 'Project reference is too large to resolve.'
export function getGitHubProjectRefInputByteLength(input: string): number {
return getClipboardTextByteLength(input)
}
export function isGitHubProjectRefInputTooLarge(
input: string,
maxBytes = GITHUB_PROJECT_REF_INPUT_MAX_BYTES
@@ -1,28 +0,0 @@
import { describe, expect, it } from 'vitest'
import {
GITHUB_WORK_ITEMS_QUERY_MAX_BYTES,
isGitHubWorkItemsQueryTooLarge
} from './work-items-query-bounds'
describe('shared GitHub work item query bounds', () => {
it('allows normal GitHub search syntax', () => {
expect(isGitHubWorkItemsQueryTooLarge('is:issue is:open label:bug')).toBe(false)
})
it('rejects oversized pasted work item queries by byte length', () => {
expect(isGitHubWorkItemsQueryTooLarge('x'.repeat(GITHUB_WORK_ITEMS_QUERY_MAX_BYTES))).toBe(
false
)
expect(isGitHubWorkItemsQueryTooLarge('x'.repeat(GITHUB_WORK_ITEMS_QUERY_MAX_BYTES + 1))).toBe(
true
)
})
it('rejects multibyte pasted queries whose character count is below the limit', () => {
const query = '😀'.repeat(Math.floor(GITHUB_WORK_ITEMS_QUERY_MAX_BYTES / 4) + 1)
expect(query.length).toBeLessThan(GITHUB_WORK_ITEMS_QUERY_MAX_BYTES)
expect(isGitHubWorkItemsQueryTooLarge(query)).toBe(true)
})
})
@@ -1,13 +0,0 @@
import { describe, expect, it } from 'vitest'
import {
GITHUB_MARK_PR_READY_RUNTIME_CAPABILITY,
GITLAB_READY_FOR_REVIEW_RUNTIME_CAPABILITY,
RUNTIME_CAPABILITIES
} from './protocol-version'
describe('hosted review Ready capabilities', () => {
it('advertises both provider mutation contracts', () => {
expect(RUNTIME_CAPABILITIES).toContain(GITHUB_MARK_PR_READY_RUNTIME_CAPABILITY)
expect(RUNTIME_CAPABILITIES).toContain(GITLAB_READY_FOR_REVIEW_RUNTIME_CAPABILITY)
})
})
+1 -59
View File
@@ -1,7 +1,4 @@
import { describe, expect, it } from 'vitest'
import { KEYBINDING_DEFINITIONS } from './keybindings/definitions'
import { getDefaultBindings } from './keybindings/effective'
import { formatKeybindingList } from './keybindings/formatting'
import { normalizeKeyToken, parseKeybinding } from './keybindings/parser'
describe('parseKeybinding memoization', () => {
@@ -12,11 +9,6 @@ describe('parseKeybinding memoization', () => {
expect(second).toBe(first)
})
it('caches rejections without re-parsing', () => {
expect(parseKeybinding('K+J')).toBeNull()
expect(parseKeybinding('K+J')).toBeNull()
})
it('never hands out an entry a caller can corrupt', () => {
const parsed = parseKeybinding('Mod+P')
expect(Object.isFrozen(parsed)).toBe(true)
@@ -32,44 +24,7 @@ describe('parseKeybinding memoization', () => {
expect(parseKeybinding('DoubleTap+Shift')?.doubleTapModifier).toBe('Shift')
})
it('parses every distinct token form identically across repeat calls', () => {
const tokens = [
' ',
'a',
'7',
'f7',
'[',
'}',
'-',
'_',
'=',
'+',
',',
'.',
'/',
'\\',
';',
"'",
'`',
'return',
'esc',
'spacebar',
'pgup',
'pgdn',
'arrowleft',
'left',
'down',
'backspace',
'del',
'ins',
'numpadadd',
'subtract',
'nonsense',
''
]
for (const token of tokens) {
expect(normalizeKeyToken(token)).toBe(normalizeKeyToken(token))
}
it('maps token spellings through the table and blocks prototype keys', () => {
expect(normalizeKeyToken(' ')).toBe('Space')
expect(normalizeKeyToken('pgdn')).toBe('PageDown')
expect(normalizeKeyToken('subtract')).toBe('NumpadSubtract')
@@ -80,16 +35,3 @@ describe('parseKeybinding memoization', () => {
expect(normalizeKeyToken('__proto__')).toBe(null)
})
})
describe('shortcut label output', () => {
it('formats every default binding identically on repeat calls, on both glyph platforms', () => {
for (const platform of ['darwin', 'win32'] as const) {
for (const definition of KEYBINDING_DEFINITIONS) {
const bindings = getDefaultBindings(definition, platform)
const label = formatKeybindingList(bindings, platform)
expect(formatKeybindingList(bindings, platform)).toBe(label)
expect(label.length).toBeGreaterThan(0)
}
}
})
})
-13
View File
@@ -151,19 +151,6 @@ describe('buildLinearIssueLinkUpdates', () => {
expectNoUndefinedValues(result as Record<string, unknown>)
})
it('links digit-prefixed Linear team keys from bare identifiers and URLs', () => {
expect(buildLinearIssueLinkUpdates('4K-12')).toEqual({
linkedLinearIssue: '4K-12',
linkedLinearIssueWorkspaceId: null,
linkedLinearIssueOrganizationUrlKey: null
})
expect(buildLinearIssueLinkUpdates('https://linear.app/acme/issue/4K-12')).toEqual({
linkedLinearIssue: '4K-12',
linkedLinearIssueWorkspaceId: null,
linkedLinearIssueOrganizationUrlKey: 'acme'
})
})
it('returns null for unparseable input', () => {
expect(buildLinearIssueLinkUpdates('not an issue')).toBeNull()
expect(buildLinearIssueLinkUpdates('https://github.com/o/r/issues/12')).toBeNull()
@@ -9,32 +9,6 @@ describe('parseServerShareAddress', () => {
expect(parseServerShareAddress('192.168.1.50').ok).toBe(true)
})
it('accepts host:port', () => {
expect(parseServerShareAddress('192.168.1.50:6768')).toEqual({
ok: true,
value: '192.168.1.50:6768'
})
expect(parseServerShareAddress('my-host:443').ok).toBe(true)
})
it('accepts IPv6 literals with an optional port', () => {
expect(parseServerShareAddress('fd7a:115c:a1e0::1').ok).toBe(true)
expect(parseServerShareAddress('[fd7a:115c:a1e0::1]:6768').ok).toBe(true)
})
it('accepts ws:// and wss:// URLs', () => {
expect(parseServerShareAddress('wss://my-host/path').ok).toBe(true)
expect(parseServerShareAddress('ws://192.168.1.50:6768').ok).toBe(true)
})
it('rejects WebSocket URLs with fragments', () => {
expect(parseServerShareAddress('wss://my-host/path#fragment').ok).toBe(false)
})
it('trims surrounding whitespace', () => {
expect(parseServerShareAddress(' my-host:8080 ')).toEqual({ ok: true, value: 'my-host:8080' })
})
it('rejects empty, whitespace-containing, and malformed input', () => {
for (const bad of [
'',
@@ -53,8 +27,4 @@ describe('parseServerShareAddress', () => {
}
expect(parseServerShareAddress('a'.repeat(PAIRING_ENDPOINT_MAX_CHARACTERS + 1)).ok).toBe(false)
})
it('rejects an out-of-range port', () => {
expect(parseServerShareAddress('my-host:70000').ok).toBe(false)
})
})
@@ -1,20 +0,0 @@
import { readFile } from 'node:fs/promises'
import { join } from 'node:path'
import { pathToFileURL } from 'node:url'
import { describe, expect, it } from 'vitest'
import { pluginManifestSchema } from './plugin-manifest'
describe('hello Orca plugin fixture', () => {
it('uses an ESM entry that remains loadable outside a type-module package', async () => {
const root = join(process.cwd(), 'examples', 'plugins', 'hello-orca')
const manifest = pluginManifestSchema.parse(
JSON.parse(await readFile(join(root, 'orca-plugin.json'), 'utf8'))
)
expect(manifest.main).toBe('main.mjs')
const workerModule = (await import(pathToFileURL(join(root, manifest.main!)).href)) as {
default?: unknown
}
expect(workerModule.default).toBeTypeOf('function')
})
})
@@ -1,29 +0,0 @@
import { readFile } from 'node:fs/promises'
import { join } from 'node:path'
import { Script } from 'node:vm'
import { describe, expect, it } from 'vitest'
describe('hostile panel fixture', () => {
it('is complete JavaScript and retains every containment probe', async () => {
const html = await readFile(
join(process.cwd(), 'examples', 'plugins', 'hostile-panel', 'panel.html'),
'utf8'
)
const script = html.match(/<script>([\s\S]*?)<\/script>/)?.[1]
expect(script).toBeTruthy()
if (!script) {
throw new Error('hostile fixture script is missing')
}
expect(() => new Script(script)).not.toThrow()
expect(html).toContain('self-navigation')
expect(html).toContain('meta-refresh-navigation')
expect(html).toContain('Navigation probes are opt-in')
expect(html).toContain("window.name = ''")
expect(html).toContain('oversized-message')
expect(html).toContain('message-flood')
expect(html).toContain("data.errorCode === 'rate_limited'")
expect(html).toContain('busy-loop')
expect(html.trimEnd()).toMatch(/<\/html>$/)
})
})
+1 -11
View File
@@ -1,19 +1,9 @@
// @vitest-environment happy-dom
import { describe, expect, it } from 'vitest'
import {
buildPluginPanelShellHtml,
PANEL_DESIGN_TOKEN_ALLOWLIST,
PLUGIN_PANEL_CSP
} from './plugin-panel-shell'
import { buildPluginPanelShellHtml, PLUGIN_PANEL_CSP } from './plugin-panel-shell'
describe('buildPluginPanelShellHtml', () => {
it('keeps destructive surface and foreground tokens paired', () => {
expect(PANEL_DESIGN_TOKEN_ALLOWLIST).toEqual(
expect.arrayContaining(['--destructive', '--destructive-foreground'])
)
})
it('places CSP and navigation guards before plugin content', () => {
const html = buildPluginPanelShellHtml('<main id="plugin-content">Plugin</main>')
const pluginOffset = html.indexOf('plugin-content')
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from 'vitest'
import { describe, expect, it } from 'vitest'
import {
getProcessOutputFields,
iterateProcessOutputLines,
@@ -23,18 +23,6 @@ describe('getProcessOutputFields', () => {
).toEqual(['TCP', '127.0.0.1:3000', '0.0.0.0:0', 'LISTENING', '4242'])
})
it('does not use regex whitespace splitting', () => {
const splitSpy = vi.spyOn(String.prototype, 'split')
getProcessOutputFields('alpha beta gamma', 2)
const usedWhitespaceFieldSplit = splitSpy.mock.calls.some(
([separator]) => separator instanceof RegExp && separator.source.includes('\\s+')
)
splitSpy.mockRestore()
expect(usedWhitespaceFieldSplit).toBe(false)
})
it('caps scan work for oversized rows', () => {
const fields = getProcessOutputFields('x'.repeat(PROCESS_OUTPUT_FIELD_SCAN_MAX_CHARS + 100), 2)
-20
View File
@@ -25,26 +25,6 @@ describe('evaluateCompat', () => {
expect(verdict).toEqual({ kind: 'ok' })
})
it('returns ok when desktop reports version equal to mobile', () => {
const verdict = evaluateCompat({
mobileProtocolVersion: MOBILE_V,
minCompatibleDesktopVersion: 0,
desktopProtocolVersion: MOBILE_V,
desktopMinCompatibleMobileVersion: 0
})
expect(verdict).toEqual({ kind: 'ok' })
})
it('returns ok when desktop reports a newer version (additive changes assumed safe)', () => {
const verdict = evaluateCompat({
mobileProtocolVersion: MOBILE_V,
minCompatibleDesktopVersion: 0,
desktopProtocolVersion: MOBILE_V + 5,
desktopMinCompatibleMobileVersion: 0
})
expect(verdict).toEqual({ kind: 'ok' })
})
it('allows desktop protocol 3 to roll out before mobile protocol 2 updates', () => {
const verdict = evaluateCompat({
mobileProtocolVersion: 2,
+1 -15
View File
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from 'vitest'
import { describe, expect, it } from 'vitest'
import { detectLinuxInstallCommandFromOsRelease } from './quick-open-install-rg'
describe('detectLinuxInstallCommandFromOsRelease', () => {
@@ -24,18 +24,4 @@ describe('detectLinuxInstallCommandFromOsRelease', () => {
'install ripgrep via your package manager (e.g. apt/dnf/pacman)'
)
})
it('does not use whitespace regex splitting for ID_LIKE parsing', () => {
const splitSpy = vi.spyOn(String.prototype, 'split')
expect(detectLinuxInstallCommandFromOsRelease('ID=unknown\nID_LIKE="rhel fedora"')).toBe(
'sudo dnf install ripgrep'
)
const usedWhitespaceFieldSplit = splitSpy.mock.calls.some(
([separator]) => separator instanceof RegExp && separator.source.includes('\\s+')
)
splitSpy.mockRestore()
expect(usedWhitespaceFieldSplit).toBe(false)
})
})
-39
View File
@@ -1,39 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { RateLimitState } from './rate-limit-types'
describe('RateLimitState', () => {
it('documents provider surfaces used by settings and status-bar UI', () => {
// Why: the AccountsPane and the status bar both read these fields
// from RateLimitState. The shape must stay stable so that the
// visibility check (status-bar-provider-visibility) keeps working
// across refactors.
const state: RateLimitState = {
claude: null,
codex: null,
gemini: null,
opencodeGo: null,
kimi: null,
antigravity: null,
minimax: null,
grok: null,
cursor: null,
zcode: null,
minimaxCookieConfigured: false,
minimaxApiKeyConfigured: false,
opencodeGoApiKeyConfigured: false,
grokAuthConfigured: false,
cursorAuthConfigured: false,
claudeTarget: { runtime: 'host', wslDistro: null },
codexTarget: { runtime: 'host', wslDistro: null },
inactiveClaudeAccounts: [],
inactiveCodexAccounts: []
}
expect(state.antigravity).toBeNull()
expect(state.minimax).toBeNull()
expect(state.minimaxCookieConfigured).toBe(false)
expect(state.minimaxApiKeyConfigured).toBe(false)
expect(state.cursor).toBeNull()
expect(state.cursorAuthConfigured).toBe(false)
})
})
@@ -126,15 +126,6 @@ describe('directoryEntryNeedsStat', () => {
isSymbolicLink: () => kind === 'link'
})
it('skips the stat for entries readdir already typed', () => {
expect(directoryEntryNeedsStat(probe('file'))).toBe(false)
expect(directoryEntryNeedsStat(probe('dir'))).toBe(false)
})
it('stats links so they are followed', () => {
expect(directoryEntryNeedsStat(probe('link'))).toBe(true)
})
// Filesystems without d_type report DT_UNKNOWN: every predicate is false, and
// without the stat a real directory's whole subtree is silently dropped.
it('stats an entry whose type readdir could not report', () => {
+1 -53
View File
@@ -1,38 +1,7 @@
import { describe, expect, it } from 'vitest'
import type {
SshTarget,
SshConnectionState,
SshConnectionStatus,
SshProviderEpoch
} from './ssh-types'
import type { SshConnectionState, SshProviderEpoch } from './ssh-types'
describe('SSH types', () => {
it('SshTarget has required fields', () => {
const target: SshTarget = {
id: 'target-1',
label: 'My Server',
host: 'myserver.com',
port: 22,
username: 'deploy'
}
expect(target.id).toBe('target-1')
expect(target.host).toBe('myserver.com')
})
it('SshConnectionStatus covers all expected states', () => {
const statuses: SshConnectionStatus[] = [
'disconnected',
'connecting',
'auth-failed',
'deploying-relay',
'connected',
'reconnecting',
'reconnection-failed',
'error'
]
expect(statuses).toHaveLength(8)
})
it('SshConnectionState composes correctly', () => {
const state: SshConnectionState = {
targetId: 'target-1',
@@ -47,25 +16,4 @@ describe('SSH types', () => {
expect(state.providerEpoch).toBe('provider-a')
expect(state.connectionGeneration).toBe(1)
})
it('Repo.connectionId is optional for backward compatibility', () => {
// Import the Repo type to verify connectionId is optional
const repo = {
id: 'repo-1',
path: '/path/to/repo',
displayName: 'My Repo',
badgeColor: '#ff0000',
addedAt: Date.now()
}
// Should compile without connectionId
expect(repo.id).toBe('repo-1')
expect('connectionId' in repo).toBe(false)
// Should also work with connectionId
const remoteRepo = {
...repo,
connectionId: 'target-1'
}
expect(remoteRepo.connectionId).toBe('target-1')
})
})
@@ -71,15 +71,6 @@ describe('per-launch structured feasibility', () => {
expect(support(overrides)).toEqual({ supported: false, blocker })
})
// The client cannot see whether the host can read a provider child's start time, so neither
// provider is refused here on platform; agentSession.createSupport answers that at create time.
it.each(['claude', 'codex'] as const)(
'leaves a Windows %s launch to the executing host',
(agent) => {
expect(support({ agent })).toEqual({ supported: true })
}
)
it('blocks a WSL or repair-required project runtime', () => {
expect(
support({
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { eventSchemas, featureWallTileIdSchema } from './telemetry-events'
import { eventSchemas } from './telemetry-events'
describe('feature wall schemas', () => {
it('accepts the unconditional open and close payloads', () => {
@@ -124,8 +124,4 @@ describe('feature wall schemas', () => {
}).success
).toBe(true)
})
it('feature wall enum schemas accept known values', () => {
expect(featureWallTileIdSchema.safeParse('tile-01').success).toBe(true)
})
})
@@ -280,14 +280,4 @@ describe('terminal title classification', () => {
expect(resolveExplicitTerminalTitleAgentType(title)).toBe(explicitTitleAgent)
}
)
it('returns the same verdict on the second read of every title', () => {
for (const title of TERMINAL_TITLE_CLASSIFICATION_CORPUS) {
expect(detectAgentStatusFromTitle(title)).toBe(detectAgentStatusFromTitle(title))
expect(getAgentLabel(title)).toBe(getAgentLabel(title))
expect(resolveExplicitTerminalTitleAgentType(title)).toBe(
resolveExplicitTerminalTitleAgentType(title)
)
}
})
})
+1 -32
View File
@@ -1,6 +1,6 @@
import { describe, expect, it } from 'vitest'
import { normalizeSupportedUiLocale, resolveUiLocale, resolveRendererUiLocale } from './ui-locale'
import { normalizeSupportedUiLocale, resolveUiLocale } from './ui-locale'
import {
UI_LANGUAGE_CHINESE,
UI_LANGUAGE_ENGLISH,
@@ -19,28 +19,6 @@ describe('ui-locale', () => {
expect(normalizeSupportedUiLocale('zh-SG')).toBe('zh')
})
it('normalizes Korean locale prefixes', () => {
expect(normalizeSupportedUiLocale('ko-KR')).toBe('ko')
expect(normalizeSupportedUiLocale('ko')).toBe('ko')
})
it('normalizes Japanese locale prefixes', () => {
expect(normalizeSupportedUiLocale('ja-JP')).toBe('ja')
expect(normalizeSupportedUiLocale('ja')).toBe('ja')
})
it('normalizes Spanish locale prefixes', () => {
expect(normalizeSupportedUiLocale('es-ES')).toBe('es')
expect(normalizeSupportedUiLocale('es-MX')).toBe('es')
expect(normalizeSupportedUiLocale('es')).toBe('es')
})
it('normalizes French locale prefixes', () => {
expect(normalizeSupportedUiLocale('fr-FR')).toBe('fr')
expect(normalizeSupportedUiLocale('fr-CA')).toBe('fr')
expect(normalizeSupportedUiLocale('fr')).toBe('fr')
})
it('falls back unsupported locales to English', () => {
expect(normalizeSupportedUiLocale('de-DE')).toBe('en')
})
@@ -89,13 +67,4 @@ describe('ui-locale', () => {
expect(resolveUiLocale(UI_LANGUAGE_SYSTEM, 'es-MX')).toBe('es')
expect(resolveUiLocale(UI_LANGUAGE_SYSTEM, 'fr-FR')).toBe('fr')
})
it('uses renderer system locale only for the system setting', () => {
expect(resolveRendererUiLocale(UI_LANGUAGE_ENGLISH)).toBe('en')
expect(resolveRendererUiLocale(UI_LANGUAGE_CHINESE)).toBe('zh')
expect(resolveRendererUiLocale(UI_LANGUAGE_KOREAN)).toBe('ko')
expect(resolveRendererUiLocale(UI_LANGUAGE_JAPANESE)).toBe('ja')
expect(resolveRendererUiLocale(UI_LANGUAGE_SPANISH)).toBe('es')
expect(resolveRendererUiLocale(UI_LANGUAGE_FRENCH)).toBe('fr')
})
})
-23
View File
@@ -10,18 +10,6 @@ import {
} from './workspace-statuses'
describe('workspace status visuals', () => {
it.each([13, 20, 21, 64])('keeps all %i authored columns in order', (count) => {
const authored = Array.from({ length: count }, (_, index) => ({
id: `state-${index + 1}`,
label: `State ${index + 1}`
}))
const statuses = normalizeWorkspaceStatuses(authored)
expect(statuses).toHaveLength(count)
expect(statuses.map((status) => status.id)).toEqual(authored.map((status) => status.id))
})
it('normalizes every valid status without truncating the workflow', () => {
const authored = Array.from({ length: 500 }, (_, index) => ({
id: `state-${index}`,
@@ -280,17 +268,6 @@ describe('workspace status visuals', () => {
})
})
it('keeps intentional custom in-progress visuals', () => {
const statuses = normalizeWorkspaceStatuses([
{ id: 'in-progress', label: 'Doing', color: 'blue', icon: 'circle-dot' }
])
expect(statuses[0]).toMatchObject({
color: 'blue',
icon: 'circle-dot'
})
})
it('clamps workspace board column widths to resizable bounds', () => {
expect(clampWorkspaceBoardColumnWidth(undefined)).toBe(WORKSPACE_BOARD_COLUMN_WIDTH_DEFAULT)
expect(clampWorkspaceBoardColumnWidth(100)).toBe(WORKSPACE_BOARD_COLUMN_WIDTH_MIN)
@@ -1,8 +1,5 @@
import { describe, expect, it } from 'vitest'
import {
COMPACT_WORKTREE_CARD_PROPERTIES,
DEFAULT_WORKTREE_CARD_PROPERTIES,
TASK_WORKTREE_CARD_PROPERTIES,
getWorktreeCardModeProperties,
getWorktreeCardModeUpdates,
isDefaultedCompactWorktreeCardProperties,
@@ -10,43 +7,6 @@ import {
} from './card-properties'
describe('worktree card properties', () => {
it('defines Default with inline agents and without branch', () => {
const props = getWorktreeCardModeProperties('Default')
expect(props).toContain('inline-agents')
expect(props).not.toContain('branch')
expect(props).toContain('pr')
expect(props).toContain('automation')
expect(props).toEqual(DEFAULT_WORKTREE_CARD_PROPERTIES)
})
it('defines Compact as the status-only quiet preset', () => {
const props = getWorktreeCardModeProperties('Compact')
expect(props).toEqual(['status'])
expect(props).toEqual(COMPACT_WORKTREE_CARD_PROPERTIES)
expect(props).not.toContain('inline-agents')
expect(props).not.toContain('issue')
expect(props).not.toContain('linear-issue')
expect(props).not.toContain('jira-issue')
expect(props).not.toContain('comment')
expect(props).not.toContain('ports')
expect(props).not.toContain('branch')
expect(props).not.toContain('pr')
expect(props).not.toContain('automation')
})
it('keeps status enabled in both presets', () => {
expect(getWorktreeCardModeProperties('Default')).toEqual(expect.arrayContaining(['status']))
expect(getWorktreeCardModeProperties('Compact')).toEqual(expect.arrayContaining(['status']))
})
it('keeps provider-specific task metadata together in Default mode', () => {
expect(getWorktreeCardModeProperties('Default')).toEqual(
expect.arrayContaining(TASK_WORKTREE_CARD_PROPERTIES)
)
})
it('normalizes fixed and legacy properties while preserving selected properties', () => {
expect(normalizeWorktreeCardProperties(['ci', 'branch', 'pr', 'automation', 'unread'])).toEqual(
['status', 'unread', 'ci', 'branch', 'pr', 'automation']
-4
View File
@@ -21,8 +21,4 @@ describe('canonical worktree identity', () => {
canonicalWorktreeIdentity({ ...local, worktreeId: 'repo-1::/workspace/renamed-feature' })
).toBe(canonicalWorktreeIdentity(local))
})
it('does not use the display name as identity input', () => {
expect(canonicalWorktreeIdentity(local)).toBe(canonicalWorktreeIdentity({ ...local }))
})
})