feat(image): --file metadata payload for annotated image cards (T-316)

`clide image show --file meta.json` reads a {path,label,description,caption}
payload so an image can carry a title and a longer description, not just a
one-line caption. ImageMessage + the image card render the richer metadata;
the bare `image show <path> [--caption]` form is unchanged. Honest userError
on a malformed/missing payload. Text annotation only (option a) — visual
marker overlays stay a follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-29 12:58:30 +02:00
co-authored by Claude Opus 4.8
parent 5f8fa6af10
commit f0fb5a5134
10 changed files with 207 additions and 17 deletions
@@ -35,7 +35,8 @@ AssistantToolUse _tool(String name, Map<String, dynamic> input) =>
AssistantToolUse(uuid: 'tu', timestamp: _t, isSidechain: false, toolUseId: 'x1', name: name, input: input);
ToolResultMessage _result(String content, {bool isError = false}) =>
ToolResultMessage(uuid: 'r', timestamp: _t, isSidechain: false, toolUseId: 'x1', content: content, isError: isError);
ImageMessage _image(String path, {String? caption}) => ImageMessage(uuid: 'i', timestamp: _t, isSidechain: false, path: path, caption: caption);
ImageMessage _image(String path, {String? caption, String? label, String? description}) =>
ImageMessage(uuid: 'i', timestamp: _t, isSidechain: false, path: path, caption: caption, label: label, description: description);
class _MockClipboard {
Map<String, dynamic> _data = {'text': null};
@@ -472,6 +473,13 @@ void main() {
expect((img.image as FileImage).file.path, '/no/such/file.png');
});
testWidgets('an image card renders its --file label and description (T-316)', (tester) async {
await pumpWith(tester, [_image('/no/such/shot.png', label: 'HUD v3', description: 'note the cramped status row', caption: 'before')]);
expect(find.text('HUD v3'), findsOneWidget);
expect(find.text('note the cramped status row'), findsOneWidget);
expect(find.text('before'), findsOneWidget);
});
testWidgets('inject() drives a new image card into a live view (T-249)', (tester) async {
final c = await pumpWith(tester, [_user('hi')]);
expect(find.text('image'), findsNothing);