feat(ux): B3.1 + B3.4 — fresh-start re-entry + MicroStep where-was-I

B3.1: app shell tracks lastLaunchAt; >7-day gap opens a 24h
fresh-start window. While the window is active: a "Welcome back. This
week starts fresh." banner offers Archive old Inbox (Inbox-only via
archive_old_inbox_cmd, system-attributable copy on success), the
morning-triage modal is suppressed, the momentum sparkline is hidden,
and the nudge bus stays quiet. Banner is per-session dismissable.

B3.4: MicroSteps shows a "Last completed: X. Next: Y." re-orientation
banner when re-opening a parent task whose decomposition has been idle
>=30 min OR sat across a session boundary. Speaker button reads the
banner aloud via existing TTS. Per-parent last-activity timestamps are
persisted to a single localStorage key. Banner self-dismisses on first
interaction.

Shared inFreshStartWindow gate extracted to src/lib/utils/freshStart.ts
so ShutdownRitualPage (B3.14), TasksPage, MorningTriageModal, and
nudgeBus all read the same source of truth.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-26 19:38:31 +01:00
parent fc3a56c0dc
commit 2668401104
8 changed files with 453 additions and 12 deletions

View File

@@ -20,8 +20,18 @@
import Card from "$lib/components/Card.svelte";
import { formatTimestamp, todayLocalDate } from "$lib/utils/time.js";
import { resolveEnergyLabels } from "$lib/utils/energyLabels";
import { inFreshStartWindow } from "$lib/utils/freshStart.js";
import { BUCKET_COLORS, EFFORT_LABELS, EFFORT_ORDER } from "$lib/utils/constants.js";
// B3.1 — fresh-start gate. While the 24h re-entry window is open, the
// momentum sparkline is hidden so the header doesn't push a "look at
// your last 7 days" frame onto a user the app has just told "this
// week starts fresh". Same gate the shell banner / morning triage /
// nudge bus consult.
const inFreshStartNow = $derived(
inFreshStartWindow(settings.reentryFreshStartUntil),
);
// PR 1.2: default landing bucket is Today rather than All. The cold-open
// surface area for "what should I do now?" is now scoped to today's
// commitments, with All still reachable as a one-click filter.
@@ -479,7 +489,7 @@
</span>
{/if}
{#if settings.showMomentumSparkline}
{#if settings.showMomentumSparkline && !inFreshStartNow}
<CompletionSparkline data={recentCompletions} />
{/if}
</div>