Skip to content

feat(pwa): PWA upgrade — installability, offline support, push notification actions#13

Open
maupet wants to merge 25 commits into
SGudbrandsson:masterfrom
maupet:feat/pwa-upgrade
Open

feat(pwa): PWA upgrade — installability, offline support, push notification actions#13
maupet wants to merge 25 commits into
SGudbrandsson:masterfrom
maupet:feat/pwa-upgrade

Conversation

@maupet
Copy link
Copy Markdown

@maupet maupet commented Apr 28, 2026

Summary

  • Icons & manifest: Generate PNG icons from source SVG at build time. Expanded manifest with icons, description, scope. Added iOS meta tags for home-screen install.
  • Service worker rewrite: Precache critical assets, cache-first for static files, offline session snapshot so the dashboard loads without network.
  • Resilient precache: Skip auth failures instead of blocking SW install; bypass auth middleware for manifest and icon routes.
  • Update detection: Toast prompt when a new SW version is waiting, with one-click reload.
  • Offline indicator: Stale session data badge when viewing cached snapshots.
  • Push notification actions: Wire up Approve/Deny buttons on permission notifications so responses reach the terminal via tmux. Handle notification body click to show inline permission block.
  • Deferred permission rendering: Store pending permission data and re-render the inline block when switching to a session with an unresolved prompt (fixes PWA background → foreground flow).
  • Hooks for quick sessions: Write hooks config for sessions created via POST /api/sessions (sidebar "+" button), so permission/elicitation notifications fire for all Claude sessions — not just case-based ones.

Commits

  • feat(pwa): add source SVG and icon generation build step
  • feat(pwa): expand manifest with icons, add iOS meta tags
  • feat(pwa): rewrite service worker with precache and offline session snapshot
  • fix(pwa): fix cache-first query string mismatch, await cache.put
  • feat(pwa): add service worker update detection and toast prompt
  • feat(pwa): add offline stale session data indicator
  • fix(pwa): resilient precache — skip auth failures instead of blocking SW install
  • fix(pwa): bypass auth for manifest and icons — required for installability
  • docs: update CLAUDE.md with dev/prod instance workflow
  • fix(pwa): wire up push notification actions to permission responses
  • fix(hooks): write hooks config for quick sessions created via POST /api/sessions

Test plan

  • PWA installs on iOS and Android — manifest and icons load correctly
  • Service worker precaches assets and serves offline session snapshots
  • Push notification Approve/Deny buttons send permission response to terminal
  • Opening PWA from notification body shows inline permission block
  • Quick sessions (sidebar "+") receive hook config and fire permission notifications
  • All existing tests pass

🤖 Generated with Claude Code

Maurizio Petrone and others added 19 commits April 25, 2026 09:22
…viewport

The keyboard accessory bar buttons (settings, commands, Terminal/Transcript
toggle, project picker, hamburger) had dark styling only in the <430px and
768-1023px breakpoints. The 430-768px tablet range had no styles, causing
buttons to render with default white browser styling.

Moves shared accessory bar component styles (buttons, command drawer, view
mode toggle) to the global scope in mobile.css so they apply at all sizes
where the file loads (<1024px). Breakpoint-specific blocks still override
sizes as needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…viewport

The keyboard accessory bar buttons (settings, commands, Terminal/Transcript
toggle, project picker, hamburger) had dark styling only in the <430px and
768-1023px breakpoints. The 430-768px tablet range had no styles, causing
buttons to render with default white browser styling.

Moves shared accessory bar component styles (buttons, command drawer, view
mode toggle) to the global scope in mobile.css so they apply at all sizes
where the file loads (<1024px). Breakpoint-specific blocks still override
sizes as needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Work items created from the Board UI had no caseId, so the orchestrator
could never dispatch them. Add a required Case dropdown to the creation
dialog that:
- Fetches cases from /api/cases (with fallback if app.cases not loaded)
- Pre-selects the current toolbar case
- Sends caseId in the POST body

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…viewport

The keyboard accessory bar buttons (settings, commands, Terminal/Transcript
toggle, project picker, hamburger) had dark styling only in the <430px and
768-1023px breakpoints. The 430-768px tablet range had no styles, causing
buttons to render with default white browser styling.

Moves shared accessory bar component styles (buttons, command drawer, view
mode toggle) to the global scope in mobile.css so they apply at all sizes
where the file loads (<1024px). Breakpoint-specific blocks still override
sizes as needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Work items created from the Board UI had no caseId, so the orchestrator
could never dispatch them. Add a required Case dropdown to the creation
dialog that:
- Fetches cases from /api/cases (with fallback if app.cases not loaded)
- Pre-selects the current toolbar case
- Sends caseId in the POST body

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nt phantom projects

Three fixes to the orchestrator's work item dispatch:

1. Include externalRef and externalUrl in the prompt sent to Claude,
   so issue links and references aren't silently dropped.

2. Name dispatched sessions after the work item title instead of
   the branch name, for easier tracking in the session list.

3. Move dispatch worktrees to ~/.codeman/dispatch-worktrees/ instead
   of creating sibling directories in ~/codeman-cases/ which appeared
   as phantom projects in the case list.

4. Use writeViaMux() instead of sendInput() to deliver the prompt.
   sendInput() calls runPrompt() which fails with "Session already has
   a running process" because the interactive PTY is already running.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Spec for closing PWA gaps — icons, iOS meta tags, offline app shell
caching, session list snapshot, and SW update toast prompt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6-task plan covering icons, manifest, iOS meta tags, SW rewrite with
precache/offline caching, update toast, and stale data indicator.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ignoreSearch:true to caches.match — build injects ?v= hashes that
  prevented cache hits on precached assets
- Await cache.put in networkFirstSessions to prevent silent write drops
- Add CACHE_VERSION bump reminder comment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… SW install

cache.addAll() rejects if any URL returns non-2xx (e.g. 401 from auth
middleware). This blocked the entire SW installation, preventing PWA
installability. Switch to individual fetch+put with graceful skip on
failure.

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

Browsers fetch manifest.json and /icons/* without credentials during
PWA installability checks and "Add to Home Screen". These must be
publicly accessible or Chrome won't detect the manifest at all.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@maupet
Copy link
Copy Markdown
Author

maupet commented Apr 28, 2026

Proper PWA now :)

Permission requests from push notifications were ignored — the SW
message listener extracted only sessionId and discarded the action
field. Also, when switching to a session with a pending permission
hook, the inline block was never re-rendered.

- Extract `action` from SW notification-click messages and map
  approve→'y', deny→'n' to sendPermissionResponse
- Store hook data in _pendingPermissionData for deferred rendering
- Re-render permission block on selectSession if one is pending
- Handle notification body click (no action) to show the modal
- Clean up _pendingPermissionData on response, reset, and session delete

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@maupet
Copy link
Copy Markdown
Author

maupet commented Apr 29, 2026

fixed permissions requests in notifications and modals

…pi/sessions

Sessions created via the "+" button in the sidebar use POST /api/sessions
with a workingDir but no casePath. This route never called writeHooksConfig(),
so permission_prompt and elicitation hooks were missing — notifications
never fired for these sessions.

Now writes hooks config to {workingDir}/.claude/settings.local.json
for Claude-mode sessions, matching the quick-start flow behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@maupet maupet changed the title feat: PWA upgrade — installability, offline shell, update prompt feat(pwa): PWA upgrade — installability, offline support, push notification actions Apr 29, 2026
Maurizio Petrone and others added 4 commits May 5, 2026 06:28
Expired session cookies (no Authorization header) no longer increment
the per-IP failure counter. This prevents the 2s system-stats poller
from triggering a 15-minute IP ban when the session expires.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
An empty Authorization header (`''`) is falsy but represents a deliberate
probing attempt — it should still count toward rate limiting. Only truly
absent headers (undefined) should be excluded.

Also adds a clarifying comment to the test explaining state dependency
between sequential rate-limit tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a 401 is detected, _api() sets authExpired flag and short-circuits
all subsequent calls. _onAuthExpired() stops SSE, system stats (2s),
transcript sync (30s), and ActionDashboard (30s) pollers. A full-screen
overlay prompts the user to re-authenticate via page reload.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@maupet
Copy link
Copy Markdown
Author

maupet commented May 5, 2026

Fixed the logout + rate limiter trigger with PWA

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