diff --git a/src/preload/renderer-process-memory-reader.test.ts b/src/preload/renderer-process-memory-reader.test.ts index 7e40574c984..759ebbfd53b 100644 --- a/src/preload/renderer-process-memory-reader.test.ts +++ b/src/preload/renderer-process-memory-reader.test.ts @@ -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) - }) }) diff --git a/src/preload/updater-package-recovery.test.ts b/src/preload/updater-package-recovery.test.ts index 7b9da47e76b..15f3576de77 100644 --- a/src/preload/updater-package-recovery.test.ts +++ b/src/preload/updater-package-recovery.test.ts @@ -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') - }) }) diff --git a/src/relay/integration.test.ts b/src/relay/integration.test.ts index 71d09c78de6..f6b7cee2844 100644 --- a/src/relay/integration.test.ts +++ b/src/relay/integration.test.ts @@ -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 ────────────────────────────────────────── diff --git a/src/relay/port-scan-handler.test.ts b/src/relay/port-scan-handler.test.ts index e547e153cc9..6d17b78f543 100644 --- a/src/relay/port-scan-handler.test.ts +++ b/src/relay/port-scan-handler.test.ts @@ -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', () => { diff --git a/src/relay/pty-replay-buffer-equivalence.test.ts b/src/relay/pty-replay-buffer-equivalence.test.ts deleted file mode 100644 index 57b35ab8480..00000000000 --- a/src/relay/pty-replay-buffer-equivalence.test.ts +++ /dev/null @@ -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) - }) -}) diff --git a/src/relay/relay-oversized-notification-survival.test.ts b/src/relay/relay-oversized-notification-survival.test.ts index 41d3dd833e5..40eb6b62f32 100644 --- a/src/relay/relay-oversized-notification-survival.test.ts +++ b/src/relay/relay-oversized-notification-survival.test.ts @@ -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 diff --git a/src/relay/subprocess.test.ts b/src/relay/subprocess.test.ts index 39ef1988fac..460804f7ed6 100644 --- a/src/relay/subprocess.test.ts +++ b/src/relay/subprocess.test.ts @@ -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-')) diff --git a/src/shared/agent-hook-listener/providers/dsh-events.test.ts b/src/shared/agent-hook-listener/providers/dsh-events.test.ts index b552018845d..0c8cfb3bfcb 100644 --- a/src/shared/agent-hook-listener/providers/dsh-events.test.ts +++ b/src/shared/agent-hook-listener/providers/dsh-events.test.ts @@ -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() - }) }) diff --git a/src/shared/agent-hook-listener/providers/zcode-events.test.ts b/src/shared/agent-hook-listener/providers/zcode-events.test.ts index 31a1e764ba0..5a2cffb690b 100644 --- a/src/shared/agent-hook-listener/providers/zcode-events.test.ts +++ b/src/shared/agent-hook-listener/providers/zcode-events.test.ts @@ -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') - }) }) diff --git a/src/shared/agent-hook-relay.test.ts b/src/shared/agent-hook-relay.test.ts index 81615eaffb7..9b35bf09c59 100644 --- a/src/shared/agent-hook-relay.test.ts +++ b/src/shared/agent-hook-relay.test.ts @@ -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') diff --git a/src/shared/agent-session-resume.test.ts b/src/shared/agent-session-resume.test.ts index 397a1a9451f..8e4940876d1 100644 --- a/src/shared/agent-session-resume.test.ts +++ b/src/shared/agent-session-resume.test.ts @@ -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' }], diff --git a/src/shared/agent-status-osc-split-frame-scan-budget.test.ts b/src/shared/agent-status-osc-split-frame-scan-budget.test.ts index fda2e9b8f3e..e1fc011a0ff 100644 --- a/src/shared/agent-status-osc-split-frame-scan-budget.test.ts +++ b/src/shared/agent-status-osc-split-frame-scan-budget.test.ts @@ -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' }]) - }) }) diff --git a/src/shared/browser-grab-types.test.ts b/src/shared/browser-grab-types.test.ts index d2ca341cc18..12d26556074 100644 --- a/src/shared/browser-grab-types.test.ts +++ b/src/shared/browser-grab-types.test.ts @@ -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) - }) - }) }) diff --git a/src/shared/browser-grab-types.ts b/src/shared/browser-grab-types.ts index 09a0ae07bc8..7a800c32d3a 100644 --- a/src/shared/browser-grab-types.ts +++ b/src/shared/browser-grab-types.ts @@ -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' -] diff --git a/src/shared/constants.test.ts b/src/shared/constants.test.ts index 664ad7dc313..b69ebda0d2d 100644 --- a/src/shared/constants.test.ts +++ b/src/shared/constants.test.ts @@ -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' diff --git a/src/shared/freebuff-startup.test.ts b/src/shared/freebuff-startup.test.ts index 2d614c53d1a..65806790af4 100644 --- a/src/shared/freebuff-startup.test.ts +++ b/src/shared/freebuff-startup.test.ts @@ -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({ diff --git a/src/shared/git-rev-list-output.test.ts b/src/shared/git-rev-list-output.test.ts index b11b3c53de2..d71f787a9ed 100644 --- a/src/shared/git-rev-list-output.test.ts +++ b/src/shared/git-rev-list-output.test.ts @@ -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', () => { diff --git a/src/shared/github/project-ref-input.test.ts b/src/shared/github/project-ref-input.test.ts index 08f71c3e44a..d0b5e6c907b 100644 --- a/src/shared/github/project-ref-input.test.ts +++ b/src/shared/github/project-ref-input.test.ts @@ -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) diff --git a/src/shared/github/project-ref-input.ts b/src/shared/github/project-ref-input.ts index 8295617a0d1..a3420cf44c3 100644 --- a/src/shared/github/project-ref-input.ts +++ b/src/shared/github/project-ref-input.ts @@ -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 diff --git a/src/shared/github/work-items-query-bounds.test.ts b/src/shared/github/work-items-query-bounds.test.ts deleted file mode 100644 index 9b8bea74b4e..00000000000 --- a/src/shared/github/work-items-query-bounds.test.ts +++ /dev/null @@ -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) - }) -}) diff --git a/src/shared/hosted-review-ready-capabilities.test.ts b/src/shared/hosted-review-ready-capabilities.test.ts deleted file mode 100644 index 88058827716..00000000000 --- a/src/shared/hosted-review-ready-capabilities.test.ts +++ /dev/null @@ -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) - }) -}) diff --git a/src/shared/keybindings-parse-cache.test.ts b/src/shared/keybindings-parse-cache.test.ts index d2eb899b309..664791c5bf1 100644 --- a/src/shared/keybindings-parse-cache.test.ts +++ b/src/shared/keybindings-parse-cache.test.ts @@ -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) - } - } - }) -}) diff --git a/src/shared/linear/links.test.ts b/src/shared/linear/links.test.ts index 71148426e74..638e24ac722 100644 --- a/src/shared/linear/links.test.ts +++ b/src/shared/linear/links.test.ts @@ -151,19 +151,6 @@ describe('buildLinearIssueLinkUpdates', () => { expectNoUndefinedValues(result as Record) }) - 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() diff --git a/src/shared/network/server-share-address.test.ts b/src/shared/network/server-share-address.test.ts index e7be14d14d3..4f09f1f21d6 100644 --- a/src/shared/network/server-share-address.test.ts +++ b/src/shared/network/server-share-address.test.ts @@ -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) - }) }) diff --git a/src/shared/plugins/plugin-demo-fixture.test.ts b/src/shared/plugins/plugin-demo-fixture.test.ts deleted file mode 100644 index d499cb4e279..00000000000 --- a/src/shared/plugins/plugin-demo-fixture.test.ts +++ /dev/null @@ -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') - }) -}) diff --git a/src/shared/plugins/plugin-hostile-fixture.test.ts b/src/shared/plugins/plugin-hostile-fixture.test.ts deleted file mode 100644 index 27fe06eb1d2..00000000000 --- a/src/shared/plugins/plugin-hostile-fixture.test.ts +++ /dev/null @@ -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(/