Activity tab: session controls + live usage block (T-415)
The Activity tab gains the power-panel's session strip and a usage block: - SESSION controls (clear / compact / fork / resume + refresh-usage) publish their slash command on builtin.claude/command — the same path as typing it, so /clear semantics (and any future confirm behavior) live in exactly one place. - The usage block revisits T-158's "blocked on upstream": probed against claude 2.1.175, a forwarded /usage IS answered headless, free (num_turns 0), as parseable text. parseUsageText() extracts session / week / week-Sonnet percentages (timezone parentheticals stripped); the sidebar watches the primary session's synthetic output for usage-shaped responses and renders them as a USAGE section. Refresh is user-initiated (the control sends /usage) — no polling, no background calls (D-64). - The runtime row gains the session's effort level (T-412's status field). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -133,6 +133,22 @@ void main() {
|
||||
expect(find.text('Claude environment not loaded.'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Activity session controls publish their slash commands (T-415)', (tester) async {
|
||||
final published = <Message>[];
|
||||
final sub = f.services.messages.subscribe(publisher: 'builtin.claude', channel: 'command').listen(published.add);
|
||||
addTearDown(sub.cancel);
|
||||
|
||||
await tester.pumpWidget(harness(f, sidebar(stats: stats)));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('SESSION'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.bySemanticsLabel('clear session'));
|
||||
await tester.tap(find.bySemanticsLabel('compact session'));
|
||||
await tester.tap(find.bySemanticsLabel('refresh usage session'));
|
||||
await tester.pump();
|
||||
expect(published.map((m) => m.data['text']), ['/clear', '/compact', '/usage']);
|
||||
});
|
||||
|
||||
testWidgets('a settings control publishes its slash command on pick (T-414)', (tester) async {
|
||||
final dir = Directory.systemTemp.createTempSync('cfg');
|
||||
addTearDown(() => dir.deleteSync(recursive: true));
|
||||
|
||||
@@ -106,4 +106,33 @@ void main() {
|
||||
expect(seg.trailing, isNull);
|
||||
});
|
||||
});
|
||||
|
||||
group('parseUsageText (T-415)', () {
|
||||
// The probed 2.1.175 /usage response shape.
|
||||
const probed =
|
||||
'You are currently using your subscription to power your Claude Code usage\n'
|
||||
'\n'
|
||||
'Current session: 15% used · resets Jun 12, 3:39pm (Europe/Amsterdam)\n'
|
||||
'Current week (all models): 53% used · resets Jun 15, 6:59pm (Europe/Amsterdam)\n'
|
||||
'Current week (Sonnet only): 0% used';
|
||||
|
||||
test('parses the probed response, stripping timezone parentheticals', () {
|
||||
final u = parseUsageText(probed)!;
|
||||
expect(u.session, '15% used · resets Jun 12, 3:39pm');
|
||||
expect(u.week, '53% used · resets Jun 15, 6:59pm');
|
||||
expect(u.weekSonnet, '0% used');
|
||||
});
|
||||
|
||||
test('tolerates missing lines', () {
|
||||
final u = parseUsageText('Current session: 9% used')!;
|
||||
expect(u.session, '9% used');
|
||||
expect(u.week, isNull);
|
||||
expect(u.weekSonnet, isNull);
|
||||
});
|
||||
|
||||
test('non-usage text parses to null', () {
|
||||
expect(parseUsageText("/effort isn't available in this environment."), isNull);
|
||||
expect(parseUsageText('plain prose'), isNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user