Commit Graph
19 Commits
Author SHA1 Message Date
Junmo KimandGitHub e35c06b36a feat(agy): add Antigravity as an interactive PTY agent (#1320) 2026-08-04 10:50:03 +08:00
Haoqing WangandGitHub 87e88743e5 fix(web): dedupe react and pre-bundle workbox deps in dev (#1211)
Radix Popover crashed with "Invalid hook call" because
@radix-ui/react-popover is not linked into web/node_modules and
resolves react from the repo root — a different instance than the
one app code imports. Two React copies make every hook-using third
party component throw on render and unmount the whole tree.

The VitePWA dev service worker also pulls its workbox imports only
after registration, so Vite re-optimizes deps and force-reloads the
page mid-run, which nondeterministically kills whichever e2e test is
in flight.
2026-07-29 10:05:06 +08:00
2643f17840 feat(web): Web Share Target -> Android system share sheet integration (#933)
* feat(web): Web Share Target -> composer attachment preload

PWA manifest now declares a `share_target` so Android Chrome surfaces
HAPI in the system share sheet for any app (Photos, Files, browser).

Pipeline on share:
  1. Service worker intercepts POST /share, parses the multipart payload
     (title/text/url + N files), persists it in IndexedDB under a
     transfer id, and 303-redirects to /share?id=<id>. The 303 forces
     Chrome to convert the POST into a GET so the SPA route mounts.
  2. New /share route loads the transfer, previews the content, and
     lets the user pick a recent active session (top 5 by activeAt) or
     a "+ New session". Tapping a session stashes the transfer id in
     sessionStorage and navigates to /sessions/:id.
  3. SessionChat mounts a ShareSeedConsumer once the AssistantRuntime
     is up; it consumes the pending transfer once per mount, seeds
     composer text + per-file attachments via the existing
     attachmentAdapter, then deletes the IDB row so a refresh of the
     session page does not replay the upload.

The whole feature reuses the existing /sessions/:id/upload endpoint;
no hub or shared changes.

Limitations (also disclosed in the PR body):
  - PWA must be installed; Android Chrome only registers share_target
    on install. iOS Safari ignores the manifest field entirely.
  - File MIME accept list is broad (`*/*` fallback); some Chrome
    versions still filter despite this.

Tests:
  - shareTransfer.test.ts (8) covers payload parse, multi-file order,
    type fallback, ingest redirect shape and error propagation.
  - sharePendingState.test.ts (3) covers atomic consume + overwrite.

Closes: pending upstream issue (filed before PR per intake doc).
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web/share): freeze picker session list at mount, sort by updatedAt, drop top-5 cap

The /share picker was visually re-shuffling under the operator's finger
as SSE events rolled in: every session metadata patch refreshed the
React Query cache, the useMemo recomputed, and items reordered (often
within a second of opening the share sheet). Sort key was activeAt,
which heartbeats every few seconds while a session is connected,
making the noise floor even higher.

Three changes:
  - Snapshot the active-session list once when sessions finish loading
    via useState + a deferred useEffect. The picker is a one-shot
    interaction; closing the share sheet and re-sharing produces a
    fresh snapshot, so freezing for the duration of the picker view is
    the right trade.
  - Sort by updatedAt desc to match SessionList's canonical "most
    recent interaction first" order. updatedAt only moves on
    user-meaningful events, not heartbeats.
  - Drop the TOP_SESSIONS=5 cap. The picker is already inside an
    app-scroll-y container, so showing all active sessions and letting
    the operator scroll matches the operator's mental model better
    than an arbitrary truncation.

Per operator dogfood report: "list of recent sessions is constantly
updating; should be just a scrollable list, from most recent
interaction to not."

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web/share): base-aware share_target paths for subpath PWA deploys

Manifest share_target.action, SW POST matching, and ingest 303 redirects
were hard-coded to /share. Standalone builds with --base /<repo>/ put
scope/start_url under the subpath but left the share action at origin
root, so Chrome posted outside the SW scope and the handler never ran.

Extract shareTargetPathnameFromBase() (used at build time in
vite.config.ts and at runtime via import.meta.env.BASE_URL in sw.ts and
shareTransfer.ts). Normalizes base to a trailing slash before URL
resolution so /repo and /repo/ both resolve to /repo/share.

Addresses upstream PR #933 review (Major).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web/share): defer sessionStorage arm until new session spawn succeeds

The "+ New session" picker path called setSharePendingTransfer before a
session existed. Cancel, spawn failure, or backing out left a stale id in
sessionStorage that the next unrelated SessionChat mount would consume.

Pass shareTransferId via /sessions/new search params instead; arm the
consumer only in handleSuccess after spawn, and delete the IDB row on
cancel.

Addresses upstream PR #933 review (Major).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web/share): append share text to existing composer draft

ShareSeedConsumer called setText(seedText) unconditionally, clobbering
per-session drafts restored by useComposerDraft from sessionStorage.

Merge share title/text/url after any in-composer text or saved draft,
joined with a blank line. Pass sessionId into ShareSeedConsumer so
getDraft() can be consulted when the composer is still empty.

Addresses upstream PR #933 review (Major).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web/share): preserve shareTransferId through /browse detour

New-session spawn from the share picker could lose shareTransferId when
the operator opened /browse to pick a folder: handleChooseFolder and
BrowsePage handleStartSession dropped the search param, so handleSuccess
never armed the composer consumer.

Thread shareTransferId through browseRoute search validation and both
navigation hops.

Addresses upstream PR #933 review (Major).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web/share): consume pending transfer in effect for StrictMode

ShareSeedConsumer called consumeSharePendingTransfer during render.
React.StrictMode double-invokes render in dev; the discarded pass
deleted the sessionStorage key before the committed render seeded.

Move consume into a mount-only useEffect and gate the seed effect on
transferReady.

Addresses upstream PR #933 review (Minor).

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-18 10:16:03 +08:00
5f27abddd4 feat(web): in-app PWA update prompt when new service worker is available (#946)
* feat(web): in-app PWA update prompt when new service worker is available (closes #938)

User-controlled reload with a persistent banner, visibility-triggered SW
checks, and an expandable rationale. Switches registerType to prompt.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): align vite.config with soup layers for clean driver merge

Keeps registerType prompt while matching garden IWER stubs and PWA
share_target shape expected by feat/pwa-share-target in the manifest.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Revert "fix(web): align vite.config with soup layers for clean driver merge"

This reverts commit 6f0915b0884d029a2413d8819a4dfe81d7c4e595.

* fix(web): make PWA reload apply waiting service worker updates

Handle SKIP_WAITING in injectManifest sw.ts and reload via controllerchange
with a timed fallback when vite-plugin-pwa prompt mode does not navigate.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): satisfy setTimeout mock typing in PWA reload tests

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): register PWA service worker before auth gates

Mount PwaUpdateProvider at app root and show the update banner on login
and error screens so registerSW runs for logged-out users too.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): offset PWA update banner below top status banners

Reserve top-12 when syncing or reconnecting so the reload prompt stays
visible above SyncingBanner and ReconnectingBanner.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): offset PWA update banner below voice error banner

Use PwaUpdateBannerWithStatusOffset inside VoiceProvider so voice errors
share the same top-12 reservation as sync and reconnect banners.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-18 10:15:10 +08:00
weishu c53ee0ed90 fix web vitest config loading 2026-05-20 20:47:16 +08:00
weishu 83795c0630 Clean up cross-package build coupling 2026-05-20 19:29:43 +08:00
weishu 900ee2eccb fix PWA icon 2026-03-24 12:32:37 +08:00
weishu 5f8f33c998 Fix web build 2026-03-08 11:41:17 +08:00
06b71dbe98 feat: Add Claude Code Agent Teams support (#258)
* feat: Add Claude Code Agent Teams support

- Add TeamState schemas and types for team collaboration
- Extract team state from TeamCreate, SendMessage, Task tools
- Add database migration V3→V4 for team_state storage
- Add TeamPanel component to display team members, tasks, messages
- Add team tool icons and presentation rules
- Support vite proxy configuration via VITE_HUB_PROXY env var

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

* fix: Add timestamp protection for team_state updates

Prevent old messages from overwriting newer team state by checking
team_state_updated_at before updating.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

* fix: Extract team tasks from Task/TaskCreate/TaskUpdate tools

- Enhance processTaskToolWithTeam to also generate task entries from
  the Task tool's description field when spawning teammates
- Add processTaskCreate handler for TaskCreate tool calls
- Add processTaskUpdate handler for TaskUpdate tool calls
- Register both new tools in the extraction switch statement

This fixes the gap where the Tasks section in TeamPanel could never
populate because team task data was not being extracted from the
message stream.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

* fix: Skip orphan TaskUpdate without title to prevent schema validation failure

When TaskUpdate arrives before TaskCreate (message ordering), skip inserting
incomplete tasks that lack required title field, preventing entire teamState
from being dropped by schema validation.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

* test: Add unit tests for orphan TaskUpdate handling

Verify that applyTeamStateDelta correctly skips inserting tasks without
title field (orphan TaskUpdate) while still allowing normal task creation
and updates to existing tasks.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

---------

Co-authored-by: tfq <tfq@gmail.com>
Co-authored-by: HAPI <noreply@hapi.run>
2026-03-08 11:26:11 +08:00
Trustin LeeandGitHub 7cad11ca27 Add About section to settings page with version info and tests (#119)
* feat(web): add About section to settings page

- Add website link to hapi.run
- Display app version from CLI package
- Display protocol version from shared module
- Add Vitest testing setup with settings page tests

🤖 Generated with Claude Code

* test(web): add tests for website link and i18n key usage

Address residual risks mentioned in PR review:
- Test website link URL and security attributes (target, rel)
- Verify correct i18n keys are used for About section via spy

Simplify test setup by using real I18nProvider and en locale.

🤖 Generated with Claude Code
2026-01-30 09:48:49 +08:00
weishu 43519621f3 feat: add web push notifications support
Implement push notification system with VAPID keys, client service worker integration, and push subscription management. Includes server-side PushService for sending notifications and PushNotifier for reactive event handling, plus client-side usePushNotifications hook and service worker support.
2026-01-02 19:19:40 +08:00
weishu e758efb0ec feat: unify app name 2025-12-29 14:36:24 +08:00
weishu 1a6099cd6f ci: add GitHub Pages deployment workflow for web app
Adds automated deployment to GitHub Pages with custom domain app.hapi.run, and updates vite.config.ts to support dynamic base URL via VITE_BASE_URL environment variable
2025-12-29 09:30:53 +08:00
weishu 24d5056169 feat: add Vite dev server proxy configuration for local development
Enable concurrent web development workflow with Vite HMR instead of requiring pre-build. Configure Vite server to listen on 0.0.0.0 for LAN access, proxy /api and /socket.io to backend (127.0.0.1:3006), and run dev:server and dev:web together.
2025-12-19 11:43:11 +08:00
weishu 7042596c90 Revert "feat: optimize PWA service worker update strategy for better caching"
This reverts commit 5856db6781.
2025-12-18 23:24:39 +08:00
weishu 5856db6781 feat: optimize PWA service worker update strategy for better caching
Improve service worker update handling to fix caching issues during development:
- Add skipWaiting and clientsClaim in Workbox config for immediate SW activation
- Remove user confirmation prompt and switch to silent automatic updates
- Replace hourly polling with visibility-based update checks via visibilitychange event

This resolves the issue where web updates would not take effect without manual cache clearing.
2025-12-18 18:18:35 +08:00
weishu be00343289 feat: add iOS Safari install guide and improve PWA UX with neutral theme
- Add iOS Safari install prompt with step-by-step modal guide
- Fix Telegram environment detection (check initData, not just SDK presence)
- Fix install prompt re-entrancy issue (clear deferredPrompt immediately)
- Extract icon components to separate file (web/src/components/icons.tsx)
- Rename "Happy App" to "Hapi" throughout the UI and manifests
- Change button/icon colors from blue (--app-button) to neutral theme (--app-fg/--app-bg)
- Add install dismiss state to prevent repeated prompts
- Improve iOS Safari detection with robust user agent parsing
2025-12-18 14:05:50 +08:00
weishu ea9f0f3b1a feat: implement progressive web app support with offline capabilities
Add complete PWA implementation including service worker registration,
offline support, and installation prompts:

- Add vite-plugin-pwa and workbox-window dependencies for PWA tooling
- Configure VitePWA plugin with web app manifest and app metadata
- Set up Workbox caching strategies for API endpoints and CDN assets
- Implement service worker auto-update with user-triggered refresh
- Create usePWAInstall hook to handle beforeinstallprompt events
- Create useOnlineStatus hook for monitoring network connectivity
- Add InstallPrompt component with haptic feedback integration
- Add OfflineBanner component to notify users of offline status
- Configure PWA icons and assets (64x64, 192x192, 512x512 variants)
- Add TypeScript type declarations for virtual PWA register module
- Integrate PWA components and service worker into App.tsx and main.tsx
- Add PWA meta tags and viewport configuration to index.html
2025-12-18 13:40:36 +08:00
weishu b4654acb92 init 2025-12-16 15:03:50 +08:00