| … | … | @@ -1300,17 +1275,19 @@ export function NewTaskDraftScreen(props: { | |
| 1301 | 1276 | // for the local outbox write; server and worktree setup run on the thread. | |
| 1302 | 1277 | flow.setSubmitting(true); | |
| 1303 | - | try { | |
| 1278 | + | await (async () => { | |
🔴 Critical threads/NewTaskDraftScreen.tsx:1278
When enqueueThreadOutboxMessage rejects, handleStart still clears the composer draft, schedules attachment cleanup, and navigates away, losing the unsent task instead of leaving it available for retry. The return inside .catch() only exits that callback; return from an outer catch before the draft-clearing logic.
No longer relevant as of 5cd02090b810614db2dc0de340d2e214cad69c52
| … | … | @@ -22,6 +22,25 @@ export function UsageLimitRecoveryCard({ | |
| 39 | + | // Beyond setTimeout's 32-bit range the card re-renders long before then. | |
| 40 | + | if (delay > 2_147_483_647) return; | |
| 41 | + | const timer = setTimeout(flip, delay); | |
| 42 | + | return () => clearTimeout(timer); | |
🟡 Medium threads/UsageLimitRecoveryCard.tsx:39
When resetAt is initially more than 2,147,483,647 ms away, this effect returns without a timer, so if the card stays mounted, resetPassed never becomes true and “Snooze until reset” stays enabled after the reset; pressing it only shows the passed-reset error. Because resetAtMs remains unchanged, subsequent renders do not rerun the effect. Schedule bounded timer chunks that recheck the remaining delay until the reset.
| 1 | - // Beyond setTimeout's 32-bit range the card re-renders long before then. |
| 2 | - if (delay > 2_147_483_647) return; |
| 3 | - const timer = setTimeout(flip, delay); |
| 4 | - return () => clearTimeout(timer); |
| 5 | + let timer: ReturnType<typeof setTimeout>; |
| 6 | + const schedule = () => { |
| 7 | + const remaining = resetAtMs - Date.now(); |
| 8 | + if (remaining <= 0) { |
| 9 | + flip(); |
| 10 | + return; |
| 11 | + } |
| 12 | + timer = setTimeout(schedule, Math.min(remaining, 2_147_483_647)); |
| 13 | + }; |
| 14 | + timer = setTimeout(schedule, Math.min(delay, 2_147_483_647)); |
| 15 | + return () => clearTimeout(timer); |
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @apps/mobile/src/features/threads/UsageLimitRecoveryCard.tsx around lines 39-42: |
| 2 | |
| 3 | When `resetAt` is initially more than 2,147,483,647 ms away, this effect returns without a timer, so if the card stays mounted, `resetPassed` never becomes true and “Snooze until reset” stays enabled after the reset; pressing it only shows the passed-reset error. Because `resetAtMs` remains unchanged, subsequent renders do not rerun the effect. Schedule bounded timer chunks that recheck the remaining delay until the reset. |