diff --git a/src/features/member-log-stream/renderer/adapters/MemberLogStreamSection.tsx b/src/features/member-log-stream/renderer/adapters/MemberLogStreamSection.tsx index c383ffe9..f44e5e11 100644 --- a/src/features/member-log-stream/renderer/adapters/MemberLogStreamSection.tsx +++ b/src/features/member-log-stream/renderer/adapters/MemberLogStreamSection.tsx @@ -1,15 +1,13 @@ -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo } from 'react'; import { useAppTranslation } from '@features/localization/renderer'; -import { api } from '@renderer/api'; import { useStore } from '@renderer/store'; import { selectResolvedMembersForTeamName } from '@renderer/store/slices/teamSlice'; import { useMemberLogStream } from '../hooks/useMemberLogStream'; import { ExecutionLogStreamView } from '../ui/ExecutionLogStreamView'; -import { MemberRuntimeProcessLogsPanel } from '../ui/MemberRuntimeProcessLogsPanel'; -import type { MemberLogStreamSegment, MemberRuntimeLogKind } from '../../contracts'; +import type { MemberLogStreamSegment } from '../../contracts'; import type { ResolvedTeamMember } from '@shared/types'; interface MemberLogStreamSectionProps { @@ -19,10 +17,6 @@ interface MemberLogStreamSectionProps { onInitialLoadErrorChange?: (hasError: boolean) => void; } -function describeMemberStream(): string { - return 'Member-scoped transcript and runtime logs rendered with the same execution-log components used in Task Log Stream.'; -} - function getSegmentMetaLabel(segment: MemberLogStreamSegment): string { const details = [segment.source.label]; if (segment.source.laneId) { @@ -45,17 +39,8 @@ export const MemberLogStreamSection = ({ onInitialLoadErrorChange, }: Readonly): React.JSX.Element => { const { t } = useAppTranslation('team'); - const [selectedLogView, setSelectedLogView] = useState<'execution' | 'process'>('execution'); const teamMembers = useStore((s) => selectResolvedMembersForTeamName(s, teamName)); const { stream, loading, error } = useMemberLogStream({ teamName, member, enabled }); - const loadRuntimeLogTail = useCallback( - (input: { - readonly kind: MemberRuntimeLogKind; - readonly maxBytes: number; - readonly forceRefresh?: boolean; - }) => api.memberLogStream.getMemberRuntimeLogTail(teamName, member.name, input), - [member.name, teamName] - ); const hasInitialLoadError = Boolean(error && !stream && !loading); const boundedHistoryNote = useMemo(() => { if (!stream) return null; @@ -71,56 +56,24 @@ export const MemberLogStreamSection = ({ return (
-
- - -
- - {selectedLogView === 'execution' ? ( - - ) : ( - - )} +
); }; diff --git a/src/features/member-log-stream/renderer/ui/ExecutionLogStreamView.tsx b/src/features/member-log-stream/renderer/ui/ExecutionLogStreamView.tsx index 6e165141..b8fb2192 100644 --- a/src/features/member-log-stream/renderer/ui/ExecutionLogStreamView.tsx +++ b/src/features/member-log-stream/renderer/ui/ExecutionLogStreamView.tsx @@ -26,7 +26,7 @@ interface ParticipantVisual { export interface ExecutionLogStreamViewProps { title: string; - description: string; + description?: string; stream: TStream | null; loading: boolean; error: string | null; @@ -312,7 +312,9 @@ export const ExecutionLogStreamView = ({

{title}

-

{description}

+ {description ? ( +

{description}

+ ) : null} ) : null} {boundedHistoryNote ? ( diff --git a/test/renderer/components/team/members/MemberLogStreamSection.fixture-e2e.test.tsx b/test/renderer/components/team/members/MemberLogStreamSection.fixture-e2e.test.tsx index 6029a85a..2cadcfe0 100644 --- a/test/renderer/components/team/members/MemberLogStreamSection.fixture-e2e.test.tsx +++ b/test/renderer/components/team/members/MemberLogStreamSection.fixture-e2e.test.tsx @@ -1,18 +1,17 @@ /* eslint-disable security/detect-non-literal-fs-filename -- Fixture E2E reads a repo fixture and writes temp JSONL. */ -import { readFile, rm, stat, writeFile, mkdtemp } from 'fs/promises'; -import os from 'os'; -import path from 'path'; import React, { act } from 'react'; import { createRoot } from 'react-dom/client'; + +import { mkdtemp, readFile, rm, stat, writeFile } from 'fs/promises'; +import os from 'os'; +import path from 'path'; import { afterEach, describe, expect, it, vi } from 'vitest'; -import { GetMemberLogStreamUseCase } from '../../../../../src/features/member-log-stream/core/application/use-cases/GetMemberLogStreamUseCase'; import { type MemberLogStreamRequestOptions, type MemberLogStreamResponse, - type MemberRuntimeLogTailOptions, - type MemberRuntimeLogTailResponse, } from '../../../../../src/features/member-log-stream/contracts'; +import { GetMemberLogStreamUseCase } from '../../../../../src/features/member-log-stream/core/application/use-cases/GetMemberLogStreamUseCase'; import { ClaudeMemberTranscriptStreamSource } from '../../../../../src/features/member-log-stream/main/adapters/output/sources/ClaudeMemberTranscriptStreamSource'; import { OpenCodeMemberRuntimeStreamSource } from '../../../../../src/features/member-log-stream/main/adapters/output/sources/OpenCodeMemberRuntimeStreamSource'; import { BoardTaskExactLogChunkBuilder } from '../../../../../src/main/services/team/taskLogs/exact/BoardTaskExactLogChunkBuilder'; @@ -44,14 +43,6 @@ const apiState = { ) => Promise >(), setMemberLogStreamTracking: vi.fn<(teamName: string, enabled: boolean) => Promise>(), - getMemberRuntimeLogTail: - vi.fn< - ( - teamName: string, - memberName: string, - options: MemberRuntimeLogTailOptions - ) => Promise - >(), onTeamChange: vi.fn<(callback: (event: unknown, data: unknown) => void) => () => void>(), }; @@ -63,9 +54,6 @@ vi.mock('@renderer/api', () => ({ setMemberLogStreamTracking: ( ...args: Parameters ) => apiState.setMemberLogStreamTracking(...args), - getMemberRuntimeLogTail: ( - ...args: Parameters - ) => apiState.getMemberRuntimeLogTail(...args), }, teams: { onTeamChange: (...args: Parameters) => @@ -279,7 +267,6 @@ describe('MemberLogStreamSection real fixture e2e', () => { document.body.innerHTML = ''; apiState.getMemberLogStream.mockReset(); apiState.setMemberLogStreamTracking.mockReset(); - apiState.getMemberRuntimeLogTail.mockReset(); apiState.onTeamChange.mockReset(); vi.unstubAllGlobals(); await Promise.all( @@ -294,13 +281,6 @@ describe('MemberLogStreamSection real fixture e2e', () => { stubMatchMedia(); apiState.onTeamChange.mockImplementation(() => () => undefined); apiState.setMemberLogStreamTracking.mockResolvedValue(undefined); - apiState.getMemberRuntimeLogTail.mockResolvedValue({ - kind: 'stdout', - content: 'process stdout line', - truncated: false, - bytesRead: 19, - missing: false, - }); const { useCase, getOpenCodeTranscript, findRecentMemberLogFileRefsByMember } = await createFixtureUseCase(); @@ -339,8 +319,9 @@ describe('MemberLogStreamSection real fixture e2e', () => { content.includes('Member-wide Claude transcript final note for Jack.') ); - expect(text).toContain('Logs'); - expect(text).toContain('Member-scoped transcript and runtime logs'); + expect(text).not.toContain('Member-scoped transcript and runtime logs'); + expect(text).not.toContain('Execution'); + expect(text).not.toContain('Process'); expect(text).toContain('Claude transcript'); expect(text).toContain('OpenCode runtime'); expect(text).toContain('Calculator behavior'); @@ -396,75 +377,4 @@ describe('MemberLogStreamSection real fixture e2e', () => { expect(apiState.setMemberLogStreamTracking).toHaveBeenCalledWith(TEAM_NAME, true); expect(apiState.setMemberLogStreamTracking).toHaveBeenCalledWith(TEAM_NAME, false); }); - - it('loads bounded process runtime logs after switching the Logs UI to Process', async () => { - vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true); - stubMatchMedia(); - apiState.onTeamChange.mockImplementation(() => () => undefined); - apiState.setMemberLogStreamTracking.mockResolvedValue(undefined); - apiState.getMemberLogStream.mockResolvedValue({ - participants: [], - defaultFilter: 'all', - segments: [], - source: 'member_empty', - coverage: [], - warnings: [], - truncated: false, - generatedAt: GENERATED_AT, - metadata: { - scannedTranscriptFileCount: 0, - includedTranscriptFileCount: 0, - droppedSegmentCount: 0, - droppedChunkCount: 0, - droppedMessageCount: 0, - }, - }); - apiState.getMemberRuntimeLogTail.mockResolvedValue({ - kind: 'stdout', - content: 'process stdout line', - truncated: false, - bytesRead: 19, - missing: false, - }); - - const host = document.createElement('div'); - document.body.appendChild(host); - const root = createRoot(host); - - await act(async () => { - root.render( - React.createElement( - TooltipProvider, - null, - React.createElement(MemberLogStreamSection, { - teamName: TEAM_NAME, - member: createMember(), - }) - ) - ); - await flushMicrotasks(); - }); - - const processButton = Array.from(host.querySelectorAll('button')).find( - (button) => button.textContent?.trim() === 'Process' - ) as HTMLButtonElement | undefined; - expect(processButton).toBeTruthy(); - - await act(async () => { - processButton?.dispatchEvent(new MouseEvent('click', { bubbles: true })); - await flushAsyncWork(); - }); - - await waitForText(host, (content) => content.includes('process stdout line')); - expect(apiState.getMemberRuntimeLogTail).toHaveBeenCalledWith(TEAM_NAME, MEMBER_NAME, { - kind: 'stdout', - maxBytes: 128 * 1024, - forceRefresh: true, - }); - - await act(async () => { - root.unmount(); - await flushMicrotasks(); - }); - }); });