diff --git a/packages/sdk/src/actions/exec-approval.ts b/packages/sdk/src/actions/exec-approval.ts index 80fb44d5..cd098273 100644 --- a/packages/sdk/src/actions/exec-approval.ts +++ b/packages/sdk/src/actions/exec-approval.ts @@ -22,7 +22,7 @@ export interface ExecApprovalRequestPayload { riskLevel: "safe" | "needs-review" | "dangerous"; /** Reasons for the risk assessment */ riskReasons: string[]; - /** When this approval expires (ms since epoch) */ + /** When this approval expires (ms since epoch). -1 means no timeout. */ expiresAtMs: number; } diff --git a/packages/ui/src/components/exec-approval-item.tsx b/packages/ui/src/components/exec-approval-item.tsx index 4487e0f3..662d6136 100644 --- a/packages/ui/src/components/exec-approval-item.tsx +++ b/packages/ui/src/components/exec-approval-item.tsx @@ -20,12 +20,17 @@ export interface ExecApprovalItemProps { onDecision: (decision: "allow-once" | "allow-always" | "deny") => void } -function useCountdown(expiresAtMs: number): number { - const [remaining, setRemaining] = useState(() => - Math.max(0, Math.ceil((expiresAtMs - Date.now()) / 1000)), +function useCountdown(expiresAtMs: number): number | null { + const [remaining, setRemaining] = useState(() => + expiresAtMs < 0 ? null : Math.max(0, Math.ceil((expiresAtMs - Date.now()) / 1000)), ) useEffect(() => { + if (expiresAtMs < 0) { + setRemaining(null) + return + } + const id = setInterval(() => { const next = Math.max(0, Math.ceil((expiresAtMs - Date.now()) / 1000)) setRemaining(next) @@ -73,7 +78,7 @@ export const ExecApprovalItem = memo(function ExecApprovalItem({ {riskLabel} - {remaining > 0 && !decided && ( + {remaining !== null && remaining > 0 && !decided && ( {remaining}s @@ -100,7 +105,7 @@ export const ExecApprovalItem = memo(function ExecApprovalItem({ )} {/* Actions */} - {!decided && remaining > 0 ? ( + {!decided && (remaining === null || remaining > 0) ? (