Skip to content

feat(ui/launcher): single read-only page of views (hide developer/preview) + single-owner notifications - #11523

Merged
lalalune merged 8 commits into
developfrom
shaw/launcher-single-page
Jul 2, 2026
Merged

feat(ui/launcher): single read-only page of views (hide developer/preview) + single-owner notifications#11523
lalalune merged 8 commits into
developfrom
shaw/launcher-single-page

Conversation

@lalalune

@lalalune lalalune commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

The launcher is now one read-only page of views (the home dashboard is the adjacent rail page), with developer/preview views hidden by default. Removes the multi-page "next page of views" swipe, the sticky/featured header, and all edit/reorder machinery the user called out.

Stacked on #11316 (notification a11y/gesture follow-ups) — that PR's commits appear here until it merges.

Launcher structure

  • curateLauncherPages returns a single page: curated apps → developer tools (only when Developer Mode is on) → other loaded apps → AOSP native tiles.
  • Visibility follows the view-kind taxonomy for every tile: system + release always show; developer + preview hidden by default, shown only via their Settings toggle (developer defaults on in dev builds / off in production; preview off everywhere). The curated developer tools (trajectories/database/runtime/logs/skills/plugins) are treated as developer-kind so the whole set hides together — previously they bypassed the gate and forced a permanent second page.
  • Native-OS tiles stay AOSP-only (the "system ones that are not native" carve-out on web + the mobile app).

Read-only launcher (dead-code removal)

  • Removed edit mode, long-press-to-edit, drag-reorder, per-tile edit/delete, and the entire persisted free-form layout model (launcher-layout reduced to the two sizing constants; reconcile/move/read/write + type + storage + their tests deleted).
  • Removed the store's launcherEditing state + enter/exit/toggle/set setters, and HomeLauncherSurface's dead || launcherEditing gesture/button arms.
  • The launcher renders the curated group(s) directly (never chunks) → always one vertically-scrolling page. The only gesture it owns is the right-swipe back to home; the outer rail owns home→launcher — one smooth gesture per surface.

Notifications — single-owner (the 2nd deferred item from #11316)

  • HomeScreen's pull-down + pull-zone now dispatch OPEN_NOTIFICATION_CENTER_EVENT; the always-mounted headless NotificationCenter is the sole renderer, so two shells can never stack.

Tests / evidence

  • 129 launcher/home/store/notification unit tests green; packages/ui typecheck + biome clean.
  • launcher-e2e + home-screen-e2e PASS end-to-end (read-only single page, dev tools on one page when enabled, no page 2, swipe-back-home, single notification shell). Screenshots regenerated (output-launcher/mobile-rest.png shows the clean single page).
  • Pre-existing, unrelated: 13 chat-stories-smoke widget play() timeouts (model-download/needs-attention/calendar/finances/etc.) — outside this diff, unreachable from these changes (that glob only loads chat/** stories), and develop already has a "model-download story mock-fetch timing" fix commit in this area.

🤖 Generated with Claude Code

Follow-up: full 3-dimension UI audit (16 more verified bugs, 15 fixed)

A fable audit of the remaining UI dimensions (responsive/brand, chat-overlay, home-widgets) surfaced 16 confirmed in-scope bugs on top of the launcher redesign; 15 fixed here:

  • HIGH — text-2xs/text-3xs/text-xs-tight generated NO CSS (registered under Tailwind v4's wrong --font-size-* namespace instead of --text-*): 413 usages across packages/ui rendered at inherited size. Renamed; verified the utilities now emit via a real @tailwindcss/node compile probe.
  • HIGH — Android back never dismissed the notification sheet/panel (collapsed the chat underneath / backgrounded the app) → NotificationCenter registers a back-intent handler while open; the chat overlay defers to a topmost notification shell.
  • HIGH — home→launcher swipe self-cancelled when it started over the notification pull-strip (bubbled lostpointercapture) → target === currentTarget guard.
  • MEDIUM: urgent-notification dead token (status-errorstatus-danger), launcher portrait:gap-y-14 cascade (→ max-sm:portrait), dismiss-X 22→44px touch target, --android-gesture-inset-bottom clearance occlusion, --eliza-continuous-chat-clearance published from the real composer height, DefaultHomeWidgets first-paint CLS.
  • LOW: sort-toggle roundedrounded-sm, notification z-index via Z_NOTIFICATION_* constants, Escape defers to stacked Radix dialogs, chat-overlay orange literals→text-accent, isWidgetEnabled gate for calendar/relationships/workflow, notification pull-strip content-shadow padding.

One deferred (medium, documented): HOME_RENDER_CAP can slice wallet.balance/workflow.running — the fix is per-widget usePublishHomeAttention wiring in those widget internals, out of scope for this UI sweep.

+9 unit tests added across the two rounds. Full packages/ui typecheck + biome clean; launcher-e2e + home-screen-e2e PASS.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8942bb8a-eb2a-4d49-b1e4-a81d80913de8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch shaw/launcher-single-page

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@lalalune
lalalune force-pushed the shaw/launcher-single-page branch from 291bf57 to e1a95fc Compare July 2, 2026 20:18

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

Shaw and others added 8 commits July 2, 2026 16:49
…esture follow-ups)

Home-screen e2e passes end-to-end on the rebased tree: mobile sheet + desktop
panel render on-screen, read-only launcher, swipe-back returns home, 0 page errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eview by default, drop edit-mode + multi-page

The launcher is now ONE page of views (the home dashboard is the adjacent rail
page). No more "next page of views" swipe, no sticky/featured header, no
edit/reorder machinery.

Curation (curateLauncherPages):
- Returns a SINGLE page. Ordering: curated apps → developer tools (only when
  Developer Mode is on) → other loaded apps (alphabetical) → AOSP native tiles.
- Visibility now follows the view-kind taxonomy for EVERY tile: system + release
  always show; developer + preview are hidden by default and appear only when
  their Settings toggle is on (developer defaults on in dev builds, off in
  production; preview off everywhere). The curated developer TOOLS (trajectories/
  database/runtime/logs/skills/plugins) are treated as developer-kind regardless
  of how each is declared, so the whole set hides together in production —
  previously they bypassed the gate and always forced a second "Developer" page.
- Native-OS tiles stay AOSP-only (the "system ones that are not native" carve-out
  on web + the mobile app).

Launcher is READ-ONLY: removed edit mode, long-press-to-edit, drag-reorder,
per-tile edit/delete, and the entire persisted free-form layout model
(launcher-layout reduced to the two sizing constants; reconcile/move/read/write +
LauncherLayout type + storage keys + their tests deleted). The store's
launcherEditing state + enter/exit/toggle/set setters are gone, and
HomeLauncherSurface's dead `|| launcherEditing` gesture/button arms with them.
It renders the curated group(s) directly (never chunks), so it is always one
vertically-scrolling page; the only gesture it owns is the right-swipe back to
home (onEdgeSwipeRight). The outer rail owns the home→launcher direction — one
gesture per surface, smooth.

Tests/e2e updated for the read-only single-page model (Launcher.test 17,
gestures 8, curation 17, LauncherSurface, composed, store 8; launcher-fixture +
run-launcher-e2e rewritten — tiles/tap-launch/no-edit-affordances/one-page/
swipe-back-home, screenshots regenerated). 129 launcher/home/store/notification
unit tests green; ui typecheck + biome clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… for single-page launcher

Two notification shells could stack: HomeScreen rendered its own controlled
NotificationCenter AND the app shell mounts the always-on headless owner, each
with independent open state. Now HomeScreen's pull-down + pull-zone button just
DISPATCH OPEN_NOTIFICATION_CENTER_EVENT; the headless owner is the sole renderer,
so the home path and the desktop tray/menu/deep-link path converge on one open
state and stacking is structurally impossible.

- HomeScreen: drop the local notificationsOpen state + <NotificationCenter> render;
  dispatchOpenNotificationCenter() on pull-down and on click/keyboard activation.
- home-screen e2e fixture: mount the single <NotificationCenter headless /> owner
  (mirrors App.tsx) so the pull→event→shell flow is exercised end-to-end.
- HomeScreen tests: assert the pull/click DISPATCHES the open event (the shell
  itself is covered by NotificationCenter.test).

e2e updated for the single-page read-only launcher: the home-screen-e2e core
stub gains real resolveViewKind/isViewKindEnabled (own-keys, so esbuild __toESM
exposes them), the developer-tools-on-page-2 + nested-pager-mouse-paging asserts
are replaced with single-page asserts (dev tools on page 0 when developer on, no
page 2, left-swipe rubber-bands), and the launcher-e2e is read-only (tap-launch +
no edit affordances + one page + swipe-back-home). HOME-SCREEN + LAUNCHER e2e
PASS; screenshots regenerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…entries)

HomeDashboard.stories + other standalone <Launcher> callers render without
pageGroups; default to a single page of every entry so they don't crash
(shell-stories-smoke green). LauncherSurface still passes curated groups.
Regenerated launcher + home-screen e2e screenshots.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…base

The read-only single-page launcher removed edit mode and the longPressTile
helper; develop's edit-mode ghost-click suppression suite (auto-merged in on
rebase onto develop) tested that deleted behavior and referenced the removed
helper. Remove the whole describe block — the launcher no longer has an
edit-mode path to guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t audit

Fable audit of the 3 remaining UI dimensions surfaced 12 confirmed in-scope bugs;
all fixed here:

HIGH
- text-2xs / text-3xs / text-xs-tight generated NO CSS: the @theme block
  registered them under Tailwind v4's WRONG namespace (`--font-size-*` instead of
  `--text-*`), so 413 usages across packages/ui rendered at inherited size (and
  call sites had drifted to arbitrary text-[9px]/[11px]). Renamed to `--text-*`;
  verified via a real @tailwindcss/node 4.3.1 compile probe that the utilities
  now emit.
- Android back never dismissed the notification sheet/panel — it collapsed the
  chat UNDERNEATH the modal or backgrounded the app. NotificationCenter now
  registers an ELIZA_BACK_INTENT_EVENT handler while a shell is open (marks the
  intent handled; covers the bell popover too); ContinuousChatOverlay's back
  handler gains the same topmost-surface guard its Escape path already had.

MEDIUM
- Urgent-notification styling was dead CSS (bg-status-error/text-status-error =
  no token) → bg-status-danger/text-status-danger (the registered tokens).
- Launcher grid row gap: portrait:gap-y-14 beat sm:gap-y-5 on tablet-portrait /
  portrait desktop → 56px gaps. Now max-sm:portrait:gap-y-14 (phone-portrait
  only), so ≥sm gets the compact 20px gap.
- Notification dismiss X was a 22px touch target on the phone sheet → 44px on
  coarse pointers via the house pointer-coarse:min-*-touch convention (+ row
  pr bump so it doesn't overlap the body).
- Content clearance dropped --android-gesture-inset-bottom while the composer
  lifts by it → occluded content on Android gesture-nav. App.tsx
  MOBILE_NAV_PADDING + HomeScreen + LauncherSurface now use
  max(safe-area-bottom, android-gesture-inset-bottom).
- --eliza-continuous-chat-clearance was never set (every surface rode the 5.25rem
  fallback while a multi-line/attachment composer overgrew it and covered
  content). The overlay now publishes its RESTING composer height to that var via
  ResizeObserver (only while collapsed).

LOW
- Sort toggles: bare `rounded` (4px) → rounded-sm (3px brand token).
- Notification z-indexes: z-[9550]/[9560] literals → Z_NOTIFICATION_BACKDROP/
  OVERLAY inline styles from floating-layers (single source of truth).
- Escape double-dismiss: NotificationCenter now defers Escape to a stacked open
  Radix dialog (e.g. Cmd+K), peeling one layer per press.
- Chat overlay orange literals (#FF5800 / var(--brand-orange)) → text-accent /
  bg-accent tokens.

+4 unit tests (Android-back handled/idle, Escape-defer-to-stacked-dialog). 364
notification/launcher/home/chat tests green; ui typecheck + biome clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… widget gating (4 of 5)

Resumed audit (home-widgets dimension) confirmed 5 more; 4 fixed here:

HIGH
- Home→launcher swipe self-cancelled when it started over the notification
  pull-strip: lostpointercapture BUBBLES, so the strip button's implicit-capture
  release fired the pager's onLostPointerCapture (bound on the rail half) and
  aborted the drag. Guard with target === currentTarget (same fix use-pull-gesture
  already has); genuine mouse/pen capture loss still has target === currentTarget.

MEDIUM
- DefaultHomeWidgets returned null on first paint (now === 0) then popped the
  whole time/weather grid in — a guaranteed CLS on every home mount. Now the grid
  + time tile render immediately (footprint reserved); only the time TEXT stays
  `invisible` until the live clock ticks.

LOW
- isWidgetEnabled: calendar/relationships/workflow ARE backed by real plugins but
  bypassed the enabled+active gate via the always-visible short-circuit. Consult
  the snapshot first: an explicit present+disabled plugin now hides its widget;
  core non-plugin ids (never in the snapshot) still pass untouched.
- Notification pull-strip tap-shadowed the top ~30-50px of home content; the home
  scroller now reserves that band with matching top padding.

Deferred (medium): HOME_RENDER_CAP can slice wallet.balance / workflow.running
when the declared set exceeds the cap — the fix is per-widget usePublishHomeAttention
wiring in those two widget internals (their own preferred fix), out of scope for
this UI sweep; it only bites the pathological all-active state.

+1 pager unit test (child's bubbled lostpointercapture doesn't self-cancel).
137 pager/home/widget/registry tests green; ui typecheck + biome clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…fixes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@lalalune
lalalune force-pushed the shaw/launcher-single-page branch from 82c6595 to 0c51746 Compare July 2, 2026 20:51

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@lalalune
lalalune merged commit 778eb02 into develop Jul 2, 2026
37 of 63 checks passed
@lalalune
lalalune deleted the shaw/launcher-single-page branch July 2, 2026 20:51
lalalune pushed a commit that referenced this pull request Jul 3, 2026
…r gate, 5 coverage-ratchet drifts, deterministic #11030 deadlock guard

packages/ui no-backdrop-blur-gate (#9141 battery): #11829's new
NotificationCenter reintroduced backdrop-blur-2xl/backdrop-saturate-150 on the
sheet/panel shell. Drop the GPU backdrop filter and carry readability with a
near-opaque base (bg-neutral-950/[0.87]) instead; refresh the committed
home-screen e2e artifacts (sheet + panel verified readable over the live
launcher in headless chromium, 10 screenshots + walkthrough video).

packages/app coverage/ratchet gates (5 reds, all real drift, no baselines
loosened):
- core-view-action-surface + view-switching matrices: track the automations
  core view (added by b07f3d9 without a surface owner) and the background
  settings subsection (#10994 registered it in SETTINGS_SECTION_META only) —
  AutomationsFeed + BackgroundSettings* are real agent-surface owners.
- route-coverage: plugin-birdclaw (#11385) declares a production collapsed
  gui/xr/tui view that was never added to the manifest ratchet. Wire it fully:
  manifest list, XR ratchet, runtime-plugin boot classification,
  gui+tui visual-matrix cases, tracked visual-review rows, manager-visible
  tile case, HMR lockstep probe, GUI interaction owners (its real
  plugin.test.ts + BirdclawView.test.tsx), and the ui-smoke stub
  (view registration + honest zero-key /api/birdclaw/status "not installed"
  state). Both birdclaw Playwright visual cases pass live (real BirdclawView
  bundle renders the setup card; audit JSON + screenshots reviewed).
- ui-smoke-coverage: scenario-pr.yml still hand-named the 10 pre-#11442
  voice-workbench spec filenames; point the slice at the renamed specs.
- view-interaction-coverage: the launcher owner declaration still claimed
  edit-mode/drag-to-reorder coverage that #11523's read-only launcher removed;
  declare what run-launcher-e2e.mjs actually proves now (no-edit long-press,
  tap-launch telemetry).

ios-local-agent-transport #11030 deadlock guard (both ui + app-core copies,
~1-in-4 flaky under a loaded suite): the 10s wall-clock Promise.race lost to a
CPU-starved event loop. Replace it with a deterministic detector — promise
assimilation invoking the hostile proxy's fabricated `then` proves the raw
Capacitor proxy crossed an await (the exact #11030 regression) and rejects
instantly with the descriptive error. Verified: reintroducing the raw-proxy
bug fails the test immediately with the #11030 message; fixed transport never
touches `then` (asserted).

Suites: packages/ui 544 files / 5532 pass; packages/app 37 files / 316 pass;
app-core transport suite 30 pass; typecheck green (ui, app, app-core); biome
clean on touched files.
lalalune pushed a commit that referenced this pull request Jul 3, 2026
…r gate, 5 coverage-ratchet drifts, deterministic #11030 deadlock guard (#11898)

packages/ui no-backdrop-blur-gate (#9141 battery): #11829's new
NotificationCenter reintroduced backdrop-blur-2xl/backdrop-saturate-150 on the
sheet/panel shell. Drop the GPU backdrop filter and carry readability with a
near-opaque base (bg-neutral-950/[0.87]) instead; refresh the committed
home-screen e2e artifacts (sheet + panel verified readable over the live
launcher in headless chromium, 10 screenshots + walkthrough video).

packages/app coverage/ratchet gates (5 reds, all real drift, no baselines
loosened):
- core-view-action-surface + view-switching matrices: track the automations
  core view (added by b07f3d9 without a surface owner) and the background
  settings subsection (#10994 registered it in SETTINGS_SECTION_META only) —
  AutomationsFeed + BackgroundSettings* are real agent-surface owners.
- route-coverage: plugin-birdclaw (#11385) declares a production collapsed
  gui/xr/tui view that was never added to the manifest ratchet. Wire it fully:
  manifest list, XR ratchet, runtime-plugin boot classification,
  gui+tui visual-matrix cases, tracked visual-review rows, manager-visible
  tile case, HMR lockstep probe, GUI interaction owners (its real
  plugin.test.ts + BirdclawView.test.tsx), and the ui-smoke stub
  (view registration + honest zero-key /api/birdclaw/status "not installed"
  state). Both birdclaw Playwright visual cases pass live (real BirdclawView
  bundle renders the setup card; audit JSON + screenshots reviewed).
- ui-smoke-coverage: scenario-pr.yml still hand-named the 10 pre-#11442
  voice-workbench spec filenames; point the slice at the renamed specs.
- view-interaction-coverage: the launcher owner declaration still claimed
  edit-mode/drag-to-reorder coverage that #11523's read-only launcher removed;
  declare what run-launcher-e2e.mjs actually proves now (no-edit long-press,
  tap-launch telemetry).

ios-local-agent-transport #11030 deadlock guard (both ui + app-core copies,
~1-in-4 flaky under a loaded suite): the 10s wall-clock Promise.race lost to a
CPU-starved event loop. Replace it with a deterministic detector — promise
assimilation invoking the hostile proxy's fabricated `then` proves the raw
Capacitor proxy crossed an await (the exact #11030 regression) and rejects
instantly with the descriptive error. Verified: reintroducing the raw-proxy
bug fails the test immediately with the #11030 message; fixed transport never
touches `then` (asserted).

Suites: packages/ui 544 files / 5532 pass; packages/app 37 files / 316 pass;
app-core transport suite 30 pass; typecheck green (ui, app, app-core); biome
clean on touched files.
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

❌ PR title does not match the required pattern. Please use one of these formats:

  • 'type: description' (e.g., 'feat: add new feature')
  • 'type(scope): description' (e.g., 'chore(core): update dependencies')
    Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, release

@claude

claude Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant