Previously, useTerminalSocket used a relative path `/terminal` for Socket.IO,
which would connect to the frontend host instead of the actual HAPI server.
Now it uses the baseUrl from context to connect to the correct server, enabling
scenarios like hosting the frontend on GitHub Pages while the server runs elsewhere.
When relay mode is enabled, skip serving frontend assets through the relay tunnel to reduce bandwidth pressure. Instead, show a helpful page on root directing users to the official frontend at app.hapi.run.
Changes:
- server/src/web/server.ts: Add relayMode and officialWebUrl options, skip static serving in relay mode, show helpful page on root
- server/src/index.ts: Pass relayMode and officialWebUrl to startWebServer
Update documentation across README, installation, and quick-start guides
to highlight the new relay-based access method with WireGuard + TLS
end-to-end encryption. Changes include:
- Recommend `hapi server --relay` as the default startup command
- Explain URL and QR code generation in terminal for instant access
- Note end-to-end encryption for security assurance
- Reorganize self-hosted tunnel options (Cloudflare, Tailscale, IP)
- Update website installation steps and add E2EE badge
Add tlsGate module to validate tunnel TLS certificates before announcing public access. This ensures the tunnel has a valid, trusted certificate before displaying the public URL to users. The validation checks certificate validity period, hostname matching (including wildcard support), and handles both DNS names and IP addresses.
Refactor tunnel access announcement to wait for TLS readiness asynchronously, preventing premature display of access links.
Integrates tunwg (WireGuard tunnel) to enable optional public access
to the hapi server. Tunnel is disabled by default and enabled via
--relay flag or HAPI_TUNNEL=true environment variable.
Users can now run 'hapi server --relay' and get a direct link like:
https://app.hapi.run/?server=https://xxx.relay.hapi.run&token=xxx
CODEX_SESSION_SCANNER was incorrectly auto-resuming old sessions because
session files persist after Codex exits. Fixed by:
1. Only matching sessions created AFTER hapi startup (reject if
sessionTimestamp < referenceTimestampMs)
2. Snapshot resumeSessionId at startup so scanner callbacks don't
affect codexLocal's launch parameters
3. Updated session timestamp test to verify boundary conditions
Codex elicitation requests from MCP use the 'message' field (from
ElicitRequest schema), not 'command' or 'cwd'. Update the permission
handler to extract and pass this field, and display it as the card
subtitle with fallback to command.
Adds onRequest and onComplete callbacks to CodexPermissionHandler to track
permission request/response lifecycle. Includes helper functions to normalize
command and cwd inputs, and displays permission requests in the web UI.
Codex API sends 'shell_command' as the tool name for bash commands, but
the web app didn't recognize it, falling back to a generic wrench icon.
This adds proper presentation with a terminal icon, matching Claude's
Bash tool display.
Parse the "Exit code: X\nWall time: Y\nOutput:\n..." format from bash tool
results and display metadata (exit code and wall time) separately from the
output content as a code block.
- Updated useLongPress.ts to pass click coordinates to onLongPress callback
- Modified SessionList.tsx to use menuAnchorPoint state instead of menuAnchorRef
- Updated SessionActionMenu.tsx to position menu based on anchorPoint coordinates
- Enhanced SessionHeader.tsx to calculate anchorPoint from button position and added stopPropagation to fix toggle issue
The menu now appears at the exact touch/click position instead of being centered or aligned to the button edge.
- Improved preview output columns: Removed id and tag columns, added Title (from metadata.summary.text), First Message (first user message), and human-readable Updated date
- Reordered columns for clarity: Updated, Msgs (fixed width), Title, First Message, Path
- Added --message=PATTERN filter option for fuzzy matching on first user message (case-insensitive)
- Fixed deletion count to use actual session count instead of result.changes (which included CASCADE deleted messages)
- Added helper functions: formatDate(), truncate(), extractUserText()
Adds GitHub Actions workflow to auto-respond to new issues using OpenAI's Codex action.
Features:
- Triggers on newly opened issues
- Skips issues with duplicate/spam/bot-skip labels or existing bot responses
- Includes comprehensive prompt for context-aware responses
- Enhanced security constraints and response format guidelines
- Checks for existing HAPI Bot responses before processing
Files:
- .github/workflows/issue-auto-response.yml - GitHub Actions workflow
- .github/prompts/issue-auto-response.md - Codex prompt with project context and guidelines
Add exponential backoff retry mechanism to handle ECONNREFUSED errors when the
server isn't ready yet during daemon startup. This includes:
- New errorUtils module with error classification helpers
- withRetry function in time.ts supporting configurable exponential backoff
- Machine registration retry with sensible defaults (60 attempts, 1-30s delays)
- Error refactoring to consolidate extractErrorInfo utility
close#35
Windows global installs expose codex as codex.cmd; spawning 'codex' without shell hits ENOENT.
Enable shell to align with Claude's Windows behavior and resolve PATH lookup.
Shell spawn makes cmd.exe strip TOML double quotes in -c arrays, so args become a string.
Switch mcp args to TOML literal (single-quoted) arrays to preserve types; update tests.
The IntersectionObserver's useEffect had handleLoadMore in its dependency
array, but handleLoadMore depended on isLoadingMoreMessages. When loading
completed, isLoadingMoreMessages changed, causing handleLoadMore to be
recreated and the observer to rebuild, immediately firing again and
triggering continuous load requests.
Fixed by storing handleLoadMore in a ref and removing it from the
IntersectionObserver's dependency array, allowing it to rebuild only when
hasMoreMessages or isLoadingMessages change.