wireframe: permission-mode control beside the Claude composer (T-275)
Frame0 wireframe driving T-275: a persistent permission-mode icon-button trailing the composer text box, with per-mode resting variants (default / accept-edits / plan), the open-dropdown state (active marked, bypass divided off + guarded), and the D-78 interaction-zone state (prompt replaces the composer; status-bar badge persists as the mirror). Embedded design notes capture the prompt-mode interaction and the keep-the-status-badge decision. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -876,3 +876,4 @@ INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by,
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-285', 'status', 'backlog', 'in_progress', NULL, '2026-06-08 15:22:35', '2026-06-08 15:22:35', '2026-06-08 15:22:35', NULL, 'd4ed6a44830ac6e7cac90547d9a027a9', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-285', 'status', 'in_progress', 'done', NULL, '2026-06-08 15:37:29', '2026-06-08 15:37:29', '2026-06-08 15:37:29', NULL, 'b8289629265f19b4f41318863e744804', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-282', 'status', 'in_progress', 'done', NULL, '2026-06-08 15:42:01', '2026-06-08 15:42:01', '2026-06-08 15:42:01', NULL, '3ebc8c4a480cb16b403e562a4829912a', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-275', 'status', 'ready', 'in_progress', NULL, '2026-06-08 15:45:13', '2026-06-08 15:45:13', '2026-06-08 15:45:13', NULL, '2745334e049523152af749102abe31e5', 1) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -2261,3 +2261,14 @@ Acceptance:
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-282', 'bug', 'T-276', 'Collapsed conversation card has inconsistent bottom padding', 'The collapsed Agent (tool-call) card in the Claude conversation view has different padding beneath it than the spacing around all other cards — see the gap flagged below the `> Agent` disclosure in the conversation. Make the collapsed card''s bottom padding match the standard inter-card spacing used everywhere else.
|
||||
|
||||
Card layout lives in lib/builtin/claude/src/conversation_card.dart: the outer wrapper applies EdgeInsets.only(bottom: 14) (line ~188) and the stripe variant adds inner EdgeInsets.fromLTRB(12, 8, 12, 8) (line ~210). When collapsed, only the header renders, so the combined bottom spacing (inner 8 + outer 14) reads differently from expanded cards. Reconcile so the visible gap below a collapsed card equals the gap below other cards.', 'done', 'low', NULL, NULL, NULL, '2026-06-08 13:39:15', '2026-06-08 15:42:01', NULL, '131affd221f44586d3a960dcaff57867', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (id, type, parent_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('T-275', 'task', 'T-276', 'Frame0 design: permission-mode dropdown beside the Claude composer', 'Produce a Frame0 wireframe for a persistent permission-mode control next to the Claude conversation composer, then use it to drive implementation.
|
||||
|
||||
Goal: surface the current permission mode (default · accept-edits · plan; bypass behind the cockpit guard) AT ALL TIMES, not only in the bottom status bar. Move/duplicate the mode affordance to an icon button sitting to the RIGHT of the composer text box (ClaudeComposer), showing the current mode via icon (+ short label), and opening a dropdown/popover menu to switch mode on click.
|
||||
|
||||
Design to wireframe (frame0-wireframe skill):
|
||||
- Composer row with the mode icon-button anchored at its right edge (trailing), aligned with the send/interrupt control; show resting state for each mode (distinct icon/color per mode) and the open-dropdown state listing selectable modes with the active one marked.
|
||||
- Account for the interaction zone (D-78): when a permission/AskUserQuestion prompt replaces the composer, define what happens to the mode button (hidden? disabled? persists above?).
|
||||
- Keep it consistent with the existing status-bar mode badge (T-226: click or Ctrl/Cmd+M cycles the safe trio) — decide whether the status-bar badge stays, is removed, or mirrors the new control.
|
||||
- Token/geometry per the ui-design skill (no hardcoded hex; trailing-control geometry like the composer''s existing buttons).
|
||||
|
||||
Deliverable: a Frame0 wireframe (resting + open states, per-mode variants) exported, plus a short note on the chosen prompt-mode interaction, ready to implement. Relevant code: lib/builtin/claude/src/claude_composer.dart, claude_pane.dart (_ModeBadge / _statusWidget / _cycleMode), claude_status.dart (nextSafePermissionMode / permissionModeLabel).', 'in_progress', 'medium', NULL, NULL, 'D-78', '2026-06-08 07:28:34', '2026-06-08 15:45:13', NULL, '9411b3c37dec05c0efb130b120a574de', 1) ON CONFLICT(id) DO UPDATE SET type=excluded.type, parent_id=excluded.parent_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "T-275 Permission-mode composer control",
|
||||
"shapes": {
|
||||
"title": {"type": "Text", "left": 40, "top": 24, "text": "T-275 · Permission-mode control beside the Claude composer", "fontColor": "#c8d0e0", "fontSize": 20},
|
||||
|
||||
"secA": {"type": "Text", "left": 40, "top": 66, "text": "RESTING — mode button trailing the composer (per mode)", "fontColor": "#7d8694", "fontSize": 13},
|
||||
|
||||
"a1": {"type": "Rectangle", "left": 40, "top": 96, "width": 600, "height": 72, "fillColor": "#1b1f26", "strokeColor": "#2c323c", "corners": [6, 6, 6, 6]},
|
||||
"a1hint": {"type": "Text", "left": 58, "top": 110, "text": "Message Claude…", "fontColor": "#7d8694", "fontSize": 14},
|
||||
"a1sub": {"type": "Text", "left": 58, "top": 134, "text": "Enter to send · Shift+Enter newline", "fontColor": "#525a64", "fontSize": 11},
|
||||
"a1btn": {"type": "Rectangle", "left": 478, "top": 124, "width": 150, "height": 32, "fillColor": "#20252e", "strokeColor": "#3a414d", "corners": [4, 4, 4, 4]},
|
||||
"a1ic": {"type": "Ellipse", "left": 490, "top": 133, "width": 14, "height": 14, "fillColor": "#7d8694", "strokeColor": "#7d8694"},
|
||||
"a1lbl": {"type": "Text", "left": 512, "top": 131, "text": "default", "fontColor": "#c8d0e0", "fontSize": 13},
|
||||
"a1car": {"type": "Text", "left": 606, "top": 130, "text": "v", "fontColor": "#7d8694", "fontSize": 12},
|
||||
|
||||
"a2": {"type": "Rectangle", "left": 40, "top": 196, "width": 600, "height": 72, "fillColor": "#1b1f26", "strokeColor": "#2c323c", "corners": [6, 6, 6, 6]},
|
||||
"a2hint": {"type": "Text", "left": 58, "top": 210, "text": "Message Claude…", "fontColor": "#7d8694", "fontSize": 14},
|
||||
"a2sub": {"type": "Text", "left": 58, "top": 234, "text": "Enter to send · Shift+Enter newline", "fontColor": "#525a64", "fontSize": 11},
|
||||
"a2btn": {"type": "Rectangle", "left": 478, "top": 224, "width": 150, "height": 32, "fillColor": "#20252e", "strokeColor": "#d8a657", "corners": [4, 4, 4, 4]},
|
||||
"a2ic": {"type": "Ellipse", "left": 490, "top": 233, "width": 14, "height": 14, "fillColor": "#d8a657", "strokeColor": "#d8a657"},
|
||||
"a2lbl": {"type": "Text", "left": 512, "top": 231, "text": "accept-edits", "fontColor": "#c8d0e0", "fontSize": 13},
|
||||
"a2car": {"type": "Text", "left": 606, "top": 230, "text": "v", "fontColor": "#7d8694", "fontSize": 12},
|
||||
|
||||
"a3": {"type": "Rectangle", "left": 40, "top": 296, "width": 600, "height": 72, "fillColor": "#1b1f26", "strokeColor": "#2c323c", "corners": [6, 6, 6, 6]},
|
||||
"a3hint": {"type": "Text", "left": 58, "top": 310, "text": "Message Claude…", "fontColor": "#7d8694", "fontSize": 14},
|
||||
"a3sub": {"type": "Text", "left": 58, "top": 334, "text": "Enter to send · Shift+Enter newline", "fontColor": "#525a64", "fontSize": 11},
|
||||
"a3btn": {"type": "Rectangle", "left": 478, "top": 324, "width": 150, "height": 32, "fillColor": "#20252e", "strokeColor": "#7fb0c8", "corners": [4, 4, 4, 4]},
|
||||
"a3ic": {"type": "Ellipse", "left": 490, "top": 333, "width": 14, "height": 14, "fillColor": "#7fb0c8", "strokeColor": "#7fb0c8"},
|
||||
"a3lbl": {"type": "Text", "left": 512, "top": 331, "text": "plan", "fontColor": "#c8d0e0", "fontSize": 13},
|
||||
"a3car": {"type": "Text", "left": 606, "top": 330, "text": "v", "fontColor": "#7d8694", "fontSize": 12},
|
||||
|
||||
"secB": {"type": "Text", "left": 700, "top": 66, "text": "OPEN — dropdown on click (active marked; bypass guarded)", "fontColor": "#7d8694", "fontSize": 13},
|
||||
|
||||
"pop": {"type": "Rectangle", "left": 1118, "top": 140, "width": 200, "height": 182, "fillColor": "#1b1f26", "strokeColor": "#3a414d", "corners": [6, 6, 6, 6]},
|
||||
"r1bg": {"type": "Rectangle", "left": 1124, "top": 147, "width": 188, "height": 34, "fillColor": "#232b34", "strokeColor": "#232b34", "corners": [4, 4, 4, 4]},
|
||||
"r1ic": {"type": "Ellipse", "left": 1134, "top": 157, "width": 14, "height": 14, "fillColor": "#7d8694", "strokeColor": "#7d8694"},
|
||||
"r1lbl": {"type": "Text", "left": 1156, "top": 155, "text": "default", "fontColor": "#c8d0e0", "fontSize": 13},
|
||||
"r1chk": {"type": "Text", "left": 1292, "top": 154, "text": "ok", "fontColor": "#7fb0c8", "fontSize": 12},
|
||||
"r2ic": {"type": "Ellipse", "left": 1134, "top": 193, "width": 14, "height": 14, "fillColor": "#d8a657", "strokeColor": "#d8a657"},
|
||||
"r2lbl": {"type": "Text", "left": 1156, "top": 191, "text": "accept-edits", "fontColor": "#c8d0e0", "fontSize": 13},
|
||||
"r3ic": {"type": "Ellipse", "left": 1134, "top": 229, "width": 14, "height": 14, "fillColor": "#7fb0c8", "strokeColor": "#7fb0c8"},
|
||||
"r3lbl": {"type": "Text", "left": 1156, "top": 227, "text": "plan", "fontColor": "#c8d0e0", "fontSize": 13},
|
||||
"rdiv": {"type": "Rectangle", "left": 1124, "top": 260, "width": 188, "height": 1, "fillColor": "#2c323c", "strokeColor": "#2c323c"},
|
||||
"r4ic": {"type": "Ellipse", "left": 1134, "top": 273, "width": 14, "height": 14, "fillColor": "#6b4f54", "strokeColor": "#6b4f54"},
|
||||
"r4lbl": {"type": "Text", "left": 1156, "top": 269, "text": "bypass", "fontColor": "#7a6166", "fontSize": 13},
|
||||
"r4note": {"type": "Text", "left": 1156, "top": 288, "text": "[lock] needs confirm", "fontColor": "#6b5358", "fontSize": 10},
|
||||
|
||||
"b1": {"type": "Rectangle", "left": 700, "top": 300, "width": 600, "height": 72, "fillColor": "#1b1f26", "strokeColor": "#2c323c", "corners": [6, 6, 6, 6]},
|
||||
"b1hint": {"type": "Text", "left": 718, "top": 314, "text": "Message Claude…", "fontColor": "#7d8694", "fontSize": 14},
|
||||
"b1sub": {"type": "Text", "left": 718, "top": 338, "text": "Enter to send · Shift+Enter newline", "fontColor": "#525a64", "fontSize": 11},
|
||||
"b1btn": {"type": "Rectangle", "left": 1138, "top": 328, "width": 150, "height": 32, "fillColor": "#232b34", "strokeColor": "#7fb0c8", "corners": [4, 4, 4, 4]},
|
||||
"b1ic": {"type": "Ellipse", "left": 1150, "top": 337, "width": 14, "height": 14, "fillColor": "#7d8694", "strokeColor": "#7d8694"},
|
||||
"b1lbl": {"type": "Text", "left": 1172, "top": 335, "text": "default", "fontColor": "#c8d0e0", "fontSize": 13},
|
||||
"b1car": {"type": "Text", "left": 1266, "top": 334, "text": "^", "fontColor": "#7fb0c8", "fontSize": 12},
|
||||
|
||||
"secC": {"type": "Text", "left": 700, "top": 408, "text": "INTERACTION ZONE (D-78) — a prompt replaces the composer", "fontColor": "#7d8694", "fontSize": 13},
|
||||
"c1": {"type": "Rectangle", "left": 700, "top": 438, "width": 600, "height": 96, "fillColor": "#20252e", "strokeColor": "#d8a657", "corners": [6, 6, 6, 6]},
|
||||
"c1q": {"type": "Text", "left": 718, "top": 452, "text": "Allow Edit lib/main.dart ?", "fontColor": "#c8d0e0", "fontSize": 14},
|
||||
"c1allow": {"type": "Rectangle", "left": 718, "top": 488, "width": 90, "height": 30, "fillColor": "#27332b", "strokeColor": "#7fae7f", "corners": [4, 4, 4, 4]},
|
||||
"c1allowt": {"type": "Text", "left": 740, "top": 495, "text": "Allow", "fontColor": "#c8d0e0", "fontSize": 13},
|
||||
"c1deny": {"type": "Rectangle", "left": 818, "top": 488, "width": 90, "height": 30, "fillColor": "#33272b", "strokeColor": "#c87f7f", "corners": [4, 4, 4, 4]},
|
||||
"c1denyt": {"type": "Text", "left": 842, "top": 495, "text": "Deny", "fontColor": "#c8d0e0", "fontSize": 13},
|
||||
"c1note": {"type": "Text", "left": 930, "top": 462, "text": "Composer + its mode button are replaced here.", "fontColor": "#7d8694", "fontSize": 11},
|
||||
"c1note2": {"type": "Text", "left": 930, "top": 480, "text": "Mode stays readable in the status bar below.", "fontColor": "#7d8694", "fontSize": 11},
|
||||
|
||||
"sb": {"type": "Rectangle", "left": 700, "top": 548, "width": 600, "height": 26, "fillColor": "#14171c", "strokeColor": "#2c323c"},
|
||||
"sbt": {"type": "Text", "left": 716, "top": 553, "text": "opus 4.8 ·", "fontColor": "#7d8694", "fontSize": 12},
|
||||
"sbbadge": {"type": "Rectangle", "left": 800, "top": 551, "width": 64, "height": 20, "fillColor": "#1b1f26", "strokeColor": "#3a414d", "corners": [3, 3, 3, 3]},
|
||||
"sbbadget": {"type": "Text", "left": 808, "top": 553, "text": "default", "fontColor": "#c8d0e0", "fontSize": 11},
|
||||
"sbt2": {"type": "Text", "left": 874, "top": 553, "text": "· 21k ctx · $0.12", "fontColor": "#7d8694", "fontSize": 12},
|
||||
|
||||
"nhdr": {"type": "Text", "left": 40, "top": 600, "text": "DESIGN NOTES", "fontColor": "#7d8694", "fontSize": 13},
|
||||
"n1": {"type": "Text", "left": 40, "top": 624, "text": "1. Mode button trails the composer text box (bottom-right) — the slot where the Stop button appears when busy.", "fontColor": "#c8d0e0", "fontSize": 12},
|
||||
"n2": {"type": "Text", "left": 40, "top": 646, "text": "2. Per-mode icon + accent: default (neutral grey), accept-edits (amber), plan (blue). bypass (red) shows only when active.", "fontColor": "#c8d0e0", "fontSize": 12},
|
||||
"n3": {"type": "Text", "left": 40, "top": 668, "text": "3. Click opens a popover ABOVE the button; active mode marked. bypass is divided off + guarded (confirm), never one click away (T-181).", "fontColor": "#c8d0e0", "fontSize": 12},
|
||||
"n4": {"type": "Text", "left": 40, "top": 690, "text": "4. D-78: while a permission / AskUserQuestion prompt replaces the composer, the mode button rides away with it; the status-bar badge stays as the persistent mirror.", "fontColor": "#c8d0e0", "fontSize": 12},
|
||||
"n5": {"type": "Text", "left": 40, "top": 712, "text": "5. Status-bar badge is kept (mirrors the new control). Ctrl/Cmd+M still cycles the safe trio (T-226); the dropdown is the discoverable peer.", "fontColor": "#c8d0e0", "fontSize": 12}
|
||||
},
|
||||
"connectors": {
|
||||
"pop-anchor": {"tailId": "pop", "headId": "b1btn", "strokeColor": "#3a414d"}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 157 KiB |
Reference in New Issue
Block a user