Mode picker: caution icon on Bypass approvals; note line machinery

- Icon.tsx: "warning" caution triangle (24px grid, 1.7 stroke, Lucide-style
  rounded triangle + exclamation) matching the existing icon set.
- Composer.tsx: ModeOption extends Dropdown's Option with `caution` (warning
  triangle before the label, themed via text-warnInk so it follows
  light/dark) and `note` (a second, dimmer italic line under the
  description). Bypass approvals carries the caution icon.

The Auto-Approve picker entry itself remains unshipped until the settings
pass gates it on the server-exposed auto_approve flag; its copy is decided
(owner, 2026-08-12): description "A reviewer clears routine actions;
doubtful ones still ask", note "Uses your session model for judgement - one
extra model call per check".

tsc clean; 111 GUI unit tests pass; rendered live and verified (note line
under Auto-Approve, warnInk triangle on Bypass).
This commit is contained in:
Devika Verma
2026-08-12 13:51:32 -07:00
parent 57002fac71
commit 17cd6b281f
2 changed files with 32 additions and 3 deletions
+21 -3
View File
@@ -24,10 +24,19 @@ import {
// kept so saved sessions and configs keep working. Auto-Approve ("auto-approve") is the
// reviewer mode (spec: reviewed-auto-mode.md); it appears only when the server says the
// feature flag is on, wired in the settings pass — until then the picker omits it.
const PERMISSION_OPTIONS: Option[] = [
// `note` renders as a second, dimmer line under the description; `caution` prefixes the
// label with a warning triangle. Both are picker-local extensions of Dropdown's Option.
type ModeOption = Option & { note?: string; caution?: boolean };
const PERMISSION_OPTIONS: ModeOption[] = [
{ value: "discuss", label: "Discuss", description: "Chat and explore — no edits or commands" },
{ value: "interactive", label: "Ask for approval", description: "Ask before edits and commands" },
{ value: "auto", label: "Bypass approvals", description: "Run everything without asking — approvals off" },
{
value: "auto",
label: "Bypass approvals",
description: "Run everything without asking — approvals off",
caution: true,
},
];
// No hardcoded model fallback: until the server supplies the list (a few seconds after a
@@ -877,13 +886,22 @@ function ModeMenu({
>
<span
className={
"text-[13px] " + (o.value === mode ? "font-medium text-accent" : "text-ink")
"flex items-center text-[13px] " +
(o.value === mode ? "font-medium text-accent" : "text-ink")
}
>
{o.caution && (
<Icon name="warning" size={13} className="mr-1.5 shrink-0 text-warnInk" />
)}
{o.label}
{o.value === mode && <span className="ml-1.5"></span>}
</span>
<span className="text-[11px] text-faint leading-snug">{o.description}</span>
{o.note && (
<span className="text-[10.5px] text-faint/80 italic leading-snug mt-0.5">
{o.note}
</span>
)}
</button>
))}
{onUnattendedChange && (
+11
View File
@@ -42,6 +42,7 @@ export type IconName =
| "table"
| "mic"
| "stop"
| "warning"
| "x";
export function Icon({
@@ -182,6 +183,16 @@ export function Icon({
<path d="M6 6l12 12M18 6L6 18" />
</svg>
);
case "warning":
// Caution triangle (Lucide-style): rounded triangle + exclamation. Marks the
// bypass-approvals mode in the picker — the one option that switches approvals off.
return (
<svg {...s}>
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
<path d="M12 9v4" />
<path d="M12 17h.01" />
</svg>
);
case "folderPlus":
// Same clean folder body + a centered plus (Lucide-style).
return (