flesh out the Claude prompt UX: options, stepper, collapse

Builds on the in-composer prompt surface (D-78):

- Permission prompts (T-175): Allow / Allow-and-don't-ask-again / Deny.
  "Don't ask again" appears only when the request carries a
  permission_suggestion and echoes it back as updatedPermissions. An
  optional note rides Deny as the message, or Allow as a follow-up user
  message (the protocol has no allow-with-message).
- AskUserQuestion picker (T-176): a single question renders bare; 2-4
  questions step one at a time (nav shows "N · Header", ✓ when answered)
  then a review/confirm screen. Each question offers an "Other" free-text
  choice and a per-choice note; multi-select joins labels. A "chat
  instead" escape denies the prompt so the user can type freely. On
  submit the answer is echoed into the log, since the card is ephemeral.
- Collapsed tool cards (T-177): multi-line tool_use / tool_result start
  collapsed behind a one-line summary; one-line output renders inline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-25 09:30:50 +02:00
co-authored by Claude Opus 4.7
parent fbf5a720a8
commit de264e7141
8 changed files with 324 additions and 16 deletions
+16 -1
View File
@@ -37,6 +37,7 @@ class ConversationCard extends StatefulWidget {
this.actions = const [],
this.collapsible = false,
this.collapsedByDefault = false,
this.collapsedSummary,
this.borderColor,
});
@@ -54,6 +55,11 @@ class ConversationCard extends StatefulWidget {
final bool collapsible;
final bool collapsedByDefault;
/// One-line gist shown next to the label while collapsed (e.g. the tool's
/// key arg, or a result's first line), so a collapsed card still says what
/// it holds. Null → just the label.
final String? collapsedSummary;
/// Border colour for the bordered variant (e.g. error red); defaults to the
/// panel border.
final Color? borderColor;
@@ -127,11 +133,20 @@ class _ConversationCardState extends State<ConversationCard> {
}
Widget _header(SurfaceTokens tokens) {
final summary = widget.collapsedSummary;
return Row(
children: [
if (widget.collapsible) _caret(tokens),
ClideText(widget.label, fontSize: clideFontSmall, color: widget.accent, fontFamily: clideMonoFamily),
const Spacer(),
// While collapsed, show a one-line gist next to the label so the card
// still says what it holds.
if (_collapsed && summary != null) ...[
const SizedBox(width: 10),
Expanded(
child: ClideText(summary, fontSize: clideFontMeta, color: tokens.globalTextMuted, fontFamily: clideMonoFamily, maxLines: 1),
),
] else
const Spacer(),
// Hover-revealed actions. (Always-reachable keyboard a11y for these is
// a follow-up detail; the collapse caret above is always visible.)
if (_hover) ..._actions(tokens),