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:
@@ -149,26 +149,34 @@ class _ConversationTurn extends StatelessWidget {
|
||||
|
||||
Widget _toolUse(AssistantToolUse t) {
|
||||
final pretty = const JsonEncoder.withIndent(' ').convert(t.input);
|
||||
// Collapse only the bulky multi-line form; a trivial one-liner just shows.
|
||||
final multiline = pretty.contains('\n');
|
||||
return ConversationCard(
|
||||
variant: ConversationCardVariant.bordered,
|
||||
accent: tokens.globalFocus,
|
||||
label: t.name,
|
||||
copyText: pretty,
|
||||
collapsible: true,
|
||||
collapsible: multiline,
|
||||
collapsedByDefault: multiline,
|
||||
collapsedSummary: multiline ? _toolUseSummary(t) : null,
|
||||
body: ClideCodeBlock(source: pretty, language: 'json'),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _toolResult(ToolResultMessage t) {
|
||||
final accent = t.isError ? tokens.statusError : tokens.globalTextMuted;
|
||||
// A one-line result is all chrome to collapse — show it inline. Only fold
|
||||
// away multi-line output, behind a summary of its first line.
|
||||
final multiline = t.content.contains('\n');
|
||||
return ConversationCard(
|
||||
variant: ConversationCardVariant.bordered,
|
||||
accent: accent,
|
||||
borderColor: t.isError ? tokens.statusError : tokens.panelBorder,
|
||||
label: t.isError ? 'error' : 'result',
|
||||
copyText: t.content,
|
||||
collapsible: true,
|
||||
collapsedByDefault: true,
|
||||
collapsible: multiline,
|
||||
collapsedByDefault: multiline,
|
||||
collapsedSummary: multiline ? _firstLine(t.content) : null,
|
||||
body: ClideText(
|
||||
t.content,
|
||||
fontSize: clideFontMeta,
|
||||
@@ -177,4 +185,18 @@ class _ConversationTurn extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// A compact one-liner for a collapsed tool-use card: the most telling arg.
|
||||
String _toolUseSummary(AssistantToolUse t) {
|
||||
final input = t.input;
|
||||
final key =
|
||||
input['file_path'] ?? input['command'] ?? input['path'] ?? input['pattern'] ?? input['url'] ?? (input.values.isNotEmpty ? input.values.first : null);
|
||||
final s = key?.toString().replaceAll('\n', ' ') ?? '';
|
||||
return s.length > 80 ? '${s.substring(0, 80)}…' : s;
|
||||
}
|
||||
|
||||
String _firstLine(String content) {
|
||||
final line = content.split('\n').first.trim();
|
||||
return line.length > 80 ? '${line.substring(0, 80)}…' : line;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user