import { describe, expect, it, vi } from 'vitest'; import { CodexNativeTaskLogStreamSource } from '../../../../src/main/services/team/taskLogs/stream/CodexNativeTaskLogStreamSource'; import type { ParsedMessage } from '../../../../src/main/types'; import type { CodexNativeTraceRun } from '../../../../src/main/services/team/taskLogs/stream/CodexNativeTraceReader'; import type { TeamTask } from '../../../../src/shared/types'; function task(overrides: Partial = {}): TeamTask { return { id: '8421e1bb-2f3b-4656-9983-6e0fd4b15963', displayId: '8421e1bb', subject: 'Investigate Codex tools', owner: 'atlas', status: 'in_progress', createdAt: '2026-05-01T17:10:00.000Z', updatedAt: '2026-05-01T17:20:00.000Z', ...overrides, } as TeamTask; } function message(uuid: string, timestamp: string, toolName: string): ParsedMessage { const toolUseId = `${uuid}-tool`; return { uuid, parentUuid: null, type: 'assistant', role: 'assistant', timestamp: new Date(timestamp), content: [{ type: 'tool_use', id: toolUseId, name: toolName, input: { command: 'pwd' } } as never], toolCalls: [{ id: toolUseId, name: toolName, input: { command: 'pwd' }, isTask: false }], toolResults: [], sessionId: 'run-1', isSidechain: false, isMeta: false, }; } describe('CodexNativeTaskLogStreamSource', () => { it('resolves short task refs, verifies Codex owner, and reads full/display/short trace candidates', async () => { const taskReader = { getTasks: vi.fn(async () => [task()]), getDeletedTasks: vi.fn(async () => []), }; const membersMetaStore = { getMembers: vi.fn(async () => [{ name: 'atlas', providerId: 'codex' }]), }; const configReader = { getConfig: vi.fn(async () => null), }; const traceRuns: CodexNativeTraceRun[] = [ { filePath: '/trace/run-1.jsonl', runId: 'run-1', teamName: 'vector-room-131313', taskId: '8421e1bb-2f3b-4656-9983-6e0fd4b15963', ownerName: 'atlas', cwd: '/repo', startedAt: '2026-05-01T17:10:00.000Z', mtimeMs: Date.parse('2026-05-01T17:10:00.000Z'), size: 100, events: [], partial: false, }, ]; const traceReader = { readTaskRuns: vi.fn(async () => traceRuns), }; const projector = { project: vi.fn(() => [message('bash-start', '2026-05-01T17:10:02.000Z', 'Bash')]), }; const chunkBuilder = { buildBundleChunks: vi.fn((messages: ParsedMessage[]) => [{ id: 'chunk-1', messages }]), }; const source = new CodexNativeTaskLogStreamSource( taskReader as never, membersMetaStore as never, configReader as never, traceReader as never, projector as never, chunkBuilder as never ); const response = await source.getTaskLogStream('vector-room-131313', '#8421e1bb'); expect(traceReader.readTaskRuns).toHaveBeenCalledWith({ teamName: 'vector-room-131313', taskIds: [ '8421e1bb-2f3b-4656-9983-6e0fd4b15963', '8421e1bb', ], includeIncoming: true, }); expect(response).toMatchObject({ defaultFilter: 'member:atlas', source: 'codex_native_trace_fallback', runtimeProjection: { provider: 'codex_native', mode: 'trace', nativeToolCount: 1, traceFileCount: 1, traceRunCount: 1, }, }); expect(response?.participants.map((participant) => participant.key)).toEqual(['member:atlas']); expect(response?.segments[0]?.participantKey).toBe('member:atlas'); }); it('does not expose traces for non-Codex task owners', async () => { const traceReader = { readTaskRuns: vi.fn(async () => { throw new Error('should not read traces for non-Codex owners'); }), }; const source = new CodexNativeTaskLogStreamSource( { getTasks: vi.fn(async () => [task({ owner: 'alice' })]), getDeletedTasks: vi.fn(async () => []), } as never, { getMembers: vi.fn(async () => [{ name: 'alice', providerId: 'anthropic' }]), } as never, { getConfig: vi.fn(async () => null), } as never, traceReader as never ); await expect(source.getTaskLogStream('vector-room-131313', '8421e1bb')).resolves.toBeNull(); expect(traceReader.readTaskRuns).not.toHaveBeenCalled(); }); });