test / unit + widget + golden + a11y (push) Failing after 31s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 29s
The teammate status was emitted by each TranscriptPublisher's statusStream
but never reached the bus. The observer now forwards it onto a shared
member-status channel ({agentId, model, permissionMode, contextTokens});
the meta sidebar subscribes and folds each member's live permission-mode
and context-token count into its roster row. No re-tailing — reuses the
existing stream (D-75).
T-157.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
98 lines
3.3 KiB
Dart
98 lines
3.3 KiB
Dart
import 'package:clide/builtin/claude/src/claude_meta_sidebar.dart';
|
|
import 'package:clide/builtin/claude/src/claude_stats.dart';
|
|
import 'package:clide/builtin/claude/src/transcript_publisher.dart';
|
|
import 'package:clide/builtin/claude/src/transcript_reader.dart';
|
|
import 'package:clide/kernel/kernel.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
import '../../helpers/kernel_fixture.dart';
|
|
import '../../helpers/widget_harness.dart';
|
|
|
|
void main() {
|
|
late KernelFixture f;
|
|
setUp(() async => f = await KernelFixture.create());
|
|
tearDown(() => f.dispose());
|
|
|
|
ClaudeMetaSidebar sidebar({ClaudeStats stats = const ClaudeStats()}) => ClaudeMetaSidebar(
|
|
statsLoader: () async => stats,
|
|
pollInterval: Duration.zero,
|
|
);
|
|
|
|
testWidgets('shows the latest day + lifetime activity from stats', (tester) async {
|
|
const stats = ClaudeStats(
|
|
lastComputed: '2026-05-22',
|
|
daily: [
|
|
DailyActivity(date: '2026-05-01', messageCount: 100, sessionCount: 2, toolCallCount: 30),
|
|
DailyActivity(date: '2026-05-22', messageCount: 250, sessionCount: 5, toolCallCount: 80),
|
|
],
|
|
);
|
|
await tester.pumpWidget(harness(f, sidebar(stats: stats)));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('2026-05-22'), findsOneWidget);
|
|
expect(find.text('250 msgs · 5 sessions · 80 tools'), findsOneWidget);
|
|
expect(find.text('Lifetime: 350 msgs over 2 days'), findsOneWidget);
|
|
expect(find.text('No team active.'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('adds and removes team members from the roster', (tester) async {
|
|
await tester.pumpWidget(harness(f, sidebar()));
|
|
await tester.pumpAndSettle();
|
|
|
|
f.services.events.emit(const TeamMemberJoined(
|
|
team: 't',
|
|
agentId: 'a1',
|
|
name: 'Scout',
|
|
agentType: 'explorer',
|
|
paneId: '%1',
|
|
model: 'claude-opus-4-7',
|
|
color: 'blue',
|
|
));
|
|
await tester.pump();
|
|
await tester.pump();
|
|
expect(find.text('Scout'), findsOneWidget);
|
|
expect(find.text('explorer · opus 4.7'), findsOneWidget);
|
|
|
|
f.services.events.emit(const TeamMemberLeft(team: 't', agentId: 'a1', paneId: '%1'));
|
|
await tester.pump();
|
|
await tester.pump();
|
|
expect(find.text('Scout'), findsNothing);
|
|
expect(find.text('No team active.'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('folds live per-member status (mode + context) into the roster row', (tester) async {
|
|
await tester.pumpWidget(harness(f, sidebar()));
|
|
await tester.pumpAndSettle();
|
|
|
|
f.services.events.emit(const TeamMemberJoined(
|
|
team: 't',
|
|
agentId: 'a1',
|
|
name: 'Scout',
|
|
agentType: 'explorer',
|
|
paneId: '%1',
|
|
color: 'blue',
|
|
));
|
|
await tester.pump();
|
|
await tester.pump();
|
|
|
|
f.services.messages.publish(
|
|
ClaudeConversation.publisher,
|
|
ClaudeConversation.memberStatusChannel,
|
|
ClaudeConversation.memberStatusData(
|
|
'a1',
|
|
const SessionStatus(model: 'claude-opus-4-7', permissionMode: 'acceptEdits', contextTokens: 21000),
|
|
),
|
|
);
|
|
await tester.pump();
|
|
await tester.pump();
|
|
|
|
expect(find.text('explorer · opus 4.7 · accept-edits · 21k ctx'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('degrades to a no-activity message with empty stats', (tester) async {
|
|
await tester.pumpWidget(harness(f, sidebar()));
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('No activity recorded yet.'), findsOneWidget);
|
|
});
|
|
}
|