You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- When the user enables the alarm, status transitions from `ALARM_DISABLED` to `NOTHING_TO_SHOW` and activity tracking begins fresh from that moment.
48
48
- When the user disables the alarm, activity tracking stops and status returns to `ALARM_DISABLED`.
49
-
-`todo: false | 'soft' | 'hard'`
50
-
- Reminder state for the Session. Default `false`.
51
-
-`'soft'`: auto-created when a ringing alarm is phantom-dismissed (any attention path). Dashed-outline pill. Auto-clears when the user types printable text into the terminal (synthetic terminal reports like focus events and cursor-position responses are excluded).
52
-
-`'hard'`: explicitly set by the user via `t` key or context menu. Solid-outline pill. Only clears via explicit toggle.
53
-
- Dismissing a ringing alarm when `todo` is already `'soft'` or `'hard'` does not downgrade it.
49
+
-`todo: TodoState` (numeric)
50
+
- Reminder state for the Session. Default `TODO_OFF` (`-1`).
51
+
-`TODO_OFF` (`-1`): no TODO.
52
+
-`[0, 1]` (soft TODO): auto-created when a ringing alarm is phantom-dismissed (any attention path). Dashed-outline pill rendered as the word `TODO`. The value is quantized to five strike levels (`1.0` = no strikes, `0.75 / 0.5 / 0.25` = 1 / 2 / 3 letters struck, `0` = about to clear). Each printable keypress strikes exactly one letter (4 keypresses clears the TODO). After `recoverySecondsPerLetter` seconds of idle, one struck letter un-strikes; this repeats until the pill is fully un-struck. Synthetic terminal reports (focus events, cursor-position responses) do not count as keypresses.
53
+
-`TODO_HARD` (`2`): explicitly set by the user via `t` key or context menu. Solid-outline pill. Only clears via explicit toggle.
54
+
- Dismissing a ringing alarm when `todo` is already soft or hard does not downgrade it.
- Strike-timing tuning parameter is in `cfg.todoBucket.recoverySecondsPerLetter`.
54
57
55
58
Each Session also owns:
56
59
@@ -203,7 +206,7 @@ The Session leaves `ALARM_RINGING` and returns to `NOTHING_TO_SHOW` when any of
203
206
- the user marks the Session as hard TODO (`t` key or context menu)
204
207
- new output arrives while the Session has attention (starts a new `MIGHT_BE_BUSY` cycle; without attention the alarm stays ringing — see latch in transition rules)
205
208
206
-
All attention-based dismissals (the first three above) create a soft TODO if `todo` is currently `false`. This prevents phantom dismissals where the alarm vanishes without a trace. Typing printable text into the terminal auto-clears soft TODOs, so users who engage with the output don't accumulate breadcrumbs. Synthetic terminal reports (focus events, cursor-position responses) do not count as typing.
209
+
All attention-based dismissals (the first three above) create a soft TODO if `todo` is not already `TODO_HARD`. If a partially-struck soft TODO already exists, the pill resets to fully un-struck — a fresh alarm ring deserves a full strike cycle. This prevents phantom dismissals where the alarm vanishes without a trace. Printable keypresses strike one letter of the `TODO` pill at a time (4 strikes clears it), so users who engage with the output don't accumulate breadcrumbs. After `cfg.todoBucket.recoverySecondsPerLetter` (default 1 s) of idle, one struck letter un-strikes; this repeats until the pill is fully un-struck. Synthetic terminal reports (focus events, cursor-position responses) do not count as keypresses.
207
210
208
211
The Session leaves `ALARM_RINGING` and returns to `ALARM_DISABLED` when:
209
212
@@ -215,7 +218,7 @@ The Session's alarm state is cleared entirely when:
215
218
216
219
If more output arrives later and the Session makes a fresh transition back into `ALARM_RINGING`, the alarm rings again.
217
220
218
-
Marking a Session as hard TODO resets the alarm to `NOTHING_TO_SHOW` and sets `todo = 'hard'`, but it does **not** disable future alarms. `todo` and the alarm toggle are separate concerns.
221
+
Marking a Session as hard TODO resets the alarm to `NOTHING_TO_SHOW` and sets `todo = TODO_HARD`, but it does **not** disable future alarms. `todo` and the alarm toggle are separate concerns.
219
222
220
223
Disabling alarms disposes the activity monitor and returns `status` to `ALARM_DISABLED`.
221
224
@@ -230,10 +233,11 @@ The Pane header exposes two independent concepts:
230
233
231
234
TODO pill:
232
235
233
-
- toggled in command mode with `t` (cycles: `false` → `'hard'`, `'soft'` → `'hard'`, `'hard'` → `false`)
234
-
- shown when `todo` is `'soft'` or `'hard'`
235
-
-`'soft'`: dashed-outline pill — auto-created on alarm dismiss, auto-clears on user input
236
-
-`'hard'`: solid-outline pill — explicitly set, only clears manually
236
+
- toggled in command mode with `t` (cycles: `TODO_OFF` → `TODO_HARD`, soft → `TODO_HARD`, `TODO_HARD` → `TODO_OFF`)
237
+
- shown when `hasTodo(todo)` is true (i.e. `todo !== TODO_OFF`)
238
+
- soft (`isSoftTodo(todo)`): dashed-outline pill — auto-created on alarm dismiss; each printable keypress strikes one letter of the word `TODO` (4 keypresses clears it), and one letter un-strikes per `recoverySecondsPerLetter` of idle
239
+
- when the 4th strike lands and the soft TODO clears, the pill briefly morphs to a `✓` glyph in the success color (~500 ms) before unmounting — this marks the moment of completion so the pill never vanishes silently
240
+
-`TODO_HARD` (`isHardTodo(todo)`): solid-outline pill — explicitly set, only clears manually
237
241
- clicking a soft pill shows a prompt: "Clear" / "Keep" (keep promotes to hard)
238
242
- clicking a hard pill clears it
239
243
- no empty placeholder when off
@@ -276,7 +280,7 @@ A Door is display-only for alarm state in v1. It must not replace the existing D
276
280
Door indicators:
277
281
278
282
- show bell indicator only when `status !== 'ALARM_DISABLED'`
279
-
- show TODO pill when `todo !== false` (`'soft'` or `'hard'`)
283
+
- show TODO pill when `hasTodo(todo)` (soft or hard)
280
284
- if `status === 'ALARM_RINGING'`, the Door itself gets the ringing treatment, not just a tiny icon
281
285
- the Door bell icon shows the same dot badge as the Pane header for `MIGHT_BE_BUSY`, `BUSY`, and `MIGHT_NEED_ATTENTION` states, but smaller (4px vs 6px) to match the smaller bell icon
282
286
@@ -366,7 +370,7 @@ Consequences:
366
370
- A Session rings.
367
371
- User clicks into the pane to read the output.
368
372
- The alarm clears, a soft TODO appears (dashed pill).
369
-
- User types a command → soft TODO auto-clears (they engaged).
373
+
- User types a command → each printable keypress strikes one letter of the `TODO` pill; after 4 keypresses the pill morphs to a `✓` and clears (they engaged).
370
374
- The Session later emits new output, progresses through `BUSY`, and eventually reaches `ALARM_RINGING` again.
0 commit comments