diff --git a/src/services/AgentSummary/__tests__/agentSummary.test.ts b/src/services/AgentSummary/__tests__/agentSummary.test.ts index cffc614a3..39fff199c 100644 --- a/src/services/AgentSummary/__tests__/agentSummary.test.ts +++ b/src/services/AgentSummary/__tests__/agentSummary.test.ts @@ -33,6 +33,7 @@ describe('startAgentSummarization', () => { let debugLogs: string[] let loggedErrors: Error[] let clearedHandles: unknown[] + let scheduledCount: number function startTestSummarization( dependencies: AgentSummaryDependencies = {}, @@ -81,8 +82,9 @@ describe('startAgentSummarization', () => { if (typeof callback !== 'function') { throw new Error('Expected timer callback') } + scheduledCount += 1 scheduled = callback as () => void | Promise - return 1 as unknown as ReturnType + return scheduledCount as unknown as ReturnType }) as unknown as typeof setTimeout, updateAgentSummary: (taskId: string, summary: string) => { updateCalls.push({ taskId, summary }) @@ -101,6 +103,7 @@ describe('startAgentSummarization', () => { debugLogs = [] loggedErrors = [] clearedHandles = [] + scheduledCount = 0 }) test('summarizes bounded transcript once and skips unchanged fingerprints', async () => { @@ -175,6 +178,7 @@ describe('startAgentSummarization', () => { }) expect(typeof scheduled).toBe('function') + const initialScheduledCount = scheduledCount await scheduled!() expect(forkCalls).toEqual([]) @@ -182,6 +186,7 @@ describe('startAgentSummarization', () => { expect(debugLogs).toContain( '[AgentSummary] Skipping summary — poor mode active', ) + expect(scheduledCount).toBe(initialScheduledCount + 1) }) test('logs summary errors and keeps the next timer owned by the summarizer', async () => { @@ -193,10 +198,12 @@ describe('startAgentSummarization', () => { }) expect(typeof scheduled).toBe('function') + const initialScheduledCount = scheduledCount await scheduled!() expect(loggedErrors).toEqual([error]) expect(updateCalls).toEqual([]) + expect(scheduledCount).toBe(initialScheduledCount + 1) }) test('stop clears the pending summary timer', () => { diff --git a/src/utils/__tests__/teammateMailbox.test.ts b/src/utils/__tests__/teammateMailbox.test.ts index 44a586562..d3dc36e54 100644 --- a/src/utils/__tests__/teammateMailbox.test.ts +++ b/src/utils/__tests__/teammateMailbox.test.ts @@ -1,9 +1,10 @@ import { afterEach, beforeEach, describe, expect, test } from 'bun:test' -import { mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import { mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises' import { mkdtempSync } from 'node:fs' import { tmpdir } from 'node:os' import { dirname, join } from 'node:path' import type { Message } from 'src/types/message.js' +import { getErrnoCode } from 'src/utils/errors.js' import { compactMailboxMessages, getLastPeerDmSummary, @@ -356,10 +357,16 @@ describe('teammate mailbox retention', () => { 'alpha', ).then( () => undefined, - error => error as NodeJS.ErrnoException, + err => err, ) - expect(error?.code).toBe('EISDIR') + const code = getErrnoCode(error) + expect(code).toBeDefined() + if (code === undefined) { + throw new Error('Expected filesystem errno code') + } + expect(['EISDIR', 'EPERM', 'EACCES']).toContain(code) + expect((await stat(inboxPath)).isDirectory()).toBe(true) }) test('readMailbox fails closed on corrupt mailbox content', async () => { diff --git a/src/utils/__tests__/udsMessaging.test.ts b/src/utils/__tests__/udsMessaging.test.ts index ed7454e0b..3f0b6dd3d 100644 --- a/src/utils/__tests__/udsMessaging.test.ts +++ b/src/utils/__tests__/udsMessaging.test.ts @@ -227,11 +227,20 @@ describe('UDS inbox retention', () => { JSON.stringify({ socketPath: path, authToken: 'test-token' }), 'utf-8', ) - const { sendToUdsSocket } = await import('../udsClient.js') - - await expect(sendToUdsSocket(path, 'hello')).rejects.toThrow( - 'Failed to connect to peer', + const { sendToUdsSocket, UdsPeerConnectionError } = await import( + '../udsClient.js' ) + + const error = await sendToUdsSocket(path, 'hello').then( + () => undefined, + err => err, + ) + expect(error).toBeInstanceOf(UdsPeerConnectionError) + if (!(error instanceof UdsPeerConnectionError)) { + throw new Error('Expected UDS peer connection error') + } + expect(error.socketPath).toBe(path) + expect(error.message).not.toContain('test-token') }) test('sendUdsMessage fails closed before connecting without an auth token', async () => { diff --git a/src/utils/udsClient.ts b/src/utils/udsClient.ts index e33ef3fdb..63792ef72 100644 --- a/src/utils/udsClient.ts +++ b/src/utils/udsClient.ts @@ -36,6 +36,18 @@ export type PeerSession = { alive: boolean } +export class UdsPeerConnectionError extends Error { + readonly socketPath: string + readonly cause: unknown + + constructor(socketPath: string, cause: unknown) { + super(`Failed to connect to peer at ${socketPath}: ${errorMessage(cause)}`) + this.name = 'UdsPeerConnectionError' + this.socketPath = socketPath + this.cause = cause + } +} + // --------------------------------------------------------------------------- // Session directory // --------------------------------------------------------------------------- @@ -237,9 +249,7 @@ export async function sendToUdsSocket( maxFrameBytes: MAX_UDS_FRAME_BYTES, onSettled: finish, formatSocketError: err => - new Error( - `Failed to connect to peer at ${target.socketPath}: ${errorMessage(err)}`, - ), + new UdsPeerConnectionError(target.socketPath, err), }) conn.setTimeout(5000, () => { finish(new Error('Connection timed out'))