Skip to content

feat(staged): add PWA support with SWR cache and page lifecycle reload#734

Open
matt2e wants to merge 1 commit into
mainfrom
reload-when-i-leave-web
Open

feat(staged): add PWA support with SWR cache and page lifecycle reload#734
matt2e wants to merge 1 commit into
mainfrom
reload-when-i-leave-web

Conversation

@matt2e
Copy link
Copy Markdown
Contributor

@matt2e matt2e commented May 18, 2026

Summary

Adds PWA support to the staged app with a service worker, web app manifest, and a stale-while-revalidate (SWR) cache layer. The cache is persisted to IndexedDB, invalidated on mutations and external events, and refreshed when the page returns from a frozen/hidden state.

Changes

  • PWA scaffolding: service worker, web app manifest, and Vite config to automate cache version bumps.
  • SWR cache infrastructure (lib/cache.ts): IndexedDB-backed cache with Tier 1/2/3 tiers and LRU eviction for size management.
  • Cached commands: Tier 1 commands wired to the cache and return { data, revalidating }; post-mutation invalidation is awaited; side-effectful refresh commands bypass the cache.
  • Cache invalidation: branch-scoped diff invalidation, event-driven invalidation for real-time updates, in-flight reads no longer repopulate invalidated entries, and markAllStale yields stale data before revalidating.
  • Page Lifecycle listener: detects when the page returns from a hidden/frozen state and marks the cache stale so components re-fetch.
  • Component wiring: ProjectHome, ProjectsList, BranchCard, SessionModal, and others re-fetch on cache-stale events.

Test plan

  • Verify PWA installs and service worker registers on a fresh load.
  • Confirm cached lists/details show immediately and revalidate in the background.
  • Mutations (create/delete/rename) reflect without a manual refresh.
  • Leaving the tab for a while and returning triggers a re-fetch.
  • No stale data persists after branch switch (diff cache scoping).

@matt2e matt2e requested review from baxen and wesbillman as code owners May 18, 2026 00:03
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b817705aa3

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +623 to +624
export function getSessionMessages(sessionId: string): Promise<SwrResult<SessionMessage[]>> {
return cachedCommand('get_session_messages', { sessionId }, { ttl: 5 * 60_000 });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid caching live session message snapshots

In web/PWA mode this caches get_session_messages for five minutes, including empty or partial results while a session is still running. SessionModal.poll() calls getSessionMessages(sessionId) whenever messages.length === 0 and ignores revalidating; if the first poll caches [] before the agent emits output, every subsequent poll hits this fresh cache and never reaches the backend until the TTL expires, so live session output can appear frozen for up to five minutes. Running sessions should bypass this cache or use a much shorter/stale-only policy.

Useful? React with 👍 / 👎.

Comment on lines +254 to +255
export function listBranchesForProject(projectId: string): Promise<SwrResult<Branch[]>> {
return cachedCommand('list_branches_for_project', { projectId }, { ttl: 2 * 60_000 });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Invalidate branch-list cache after branch mutations

This introduces a two-minute fresh cache for branch lists, but branch-mutating commands such as renameBranch still update only local UI state and do not invalidate list_branches_for_project. After renaming a branch, any remount/navigation or cache-stale refresh that calls listBranchesForProject(projectId) within the TTL can reuse the old cached branch list and restore stale branch data until the cache expires. Please either invalidate this cache in all branch mutators or avoid fresh short-circuiting for branch lists.

Useful? React with 👍 / 👎.

Add service worker and web app manifest support with automated cache versioning.

Introduce IndexedDB-backed SWR caching with stale/revalidating state, LRU eviction, scoped invalidation, and page lifecycle handling.

Wire project, branch, session, diff, and settings flows to cache revalidation and post-mutation invalidation events.

Signed-off-by: Matt Toohey <contact@matttoohey.com>
@matt2e matt2e force-pushed the reload-when-i-leave-web branch from b817705 to d84b179 Compare May 18, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant