feat(draw): wire the drawing card into the conversation — end to end (T-318)

The last wire: a DrawingMessage conversation item + the Claude-extension
subscriber on the `draw` channel (buildSvgDocument → inject), the
conversation renderer (DrawingCard), the fold/summary switches, the i18n
`drawing` label, and registering `clide draw` at boot (empty template
registry for now — primitive SVG works; d2/icon/compare/image handlers
plug in as they land). `clide draw --file doc.json` now renders a card in
the conversation. Render widget-tested; analyze + format clean across the
repo. Templates + per-object overlay remain; the CHANGELOG entry lands
with the user-complete feature.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 22:18:53 +02:00
co-authored by Claude Opus 4.8
parent a5529577f2
commit 7acea8baa0
9 changed files with 110 additions and 1 deletions
@@ -326,6 +326,31 @@ void main() {
expect(find.byKey(const ValueKey('turn.B')), findsOneWidget);
});
testWidgets('a driven-in drawing card renders the SVG + caption (T-318)', (tester) async {
tester.view.physicalSize = const Size(900, 800);
tester.view.devicePixelRatio = 1.0;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
final stream = StreamController<ConversationItem>.broadcast();
final c = ConversationController(stream: stream.stream);
addTearDown(c.dispose);
await tester.pumpWidget(harness(f, ConversationView(controller: c, foldLevel: FoldLevel.none)));
stream.add(
DrawingMessage(
uuid: 'D',
timestamp: _t,
isSidechain: false,
svg: '<svg viewBox="0 0 20 10"><rect width="20" height="10" fill="#FF0000"/></svg>',
label: 'Build pipeline',
description: 'how it connects',
),
);
await tester.pumpAndSettle();
expect(find.byKey(const ValueKey('turn.D')), findsOneWidget);
expect(find.text('Build pipeline'), findsOneWidget);
expect(find.text('how it connects'), findsOneWidget);
});
testWidgets('a folded activity cluster carries a stable identity key (T-285)', (tester) async {
tester.view.physicalSize = const Size(900, 800);
tester.view.devicePixelRatio = 1.0;