Extract duplicate MCP bridge initialization code from codexLocalLauncher and
codexRemoteLauncher into a new buildHapiMcpBridge utility. This ensures both
modes use identical server setup logic and provides a single source of truth
for MCP configuration.
Update codexStartConfig to deliver system prompt via developer_instructions
instead of appending to the user message. This ensures consistent behavior
between local and remote modes and properly separates system guidance from
user intent.
Implements MCP server configuration and developer instructions support in
Codex local mode, bringing it to parity with remote mode.
Key additions:
- buildMcpServerConfigArgs() and buildDeveloperInstructionsArg() utilities
to construct -c config arguments for passing MCP servers and instructions
to the Codex CLI at runtime
- TITLE_INSTRUCTION for Codex to call hapi__change_title to update chat
session titles dynamically
- Codex local mode now starts hapi MCP bridge server and passes both MCP
configuration and developer instructions to Claude, enabling full feature
parity with remote mode
Files changed:
- New: codexMcpConfig.ts (utilities), systemPrompt.ts (prompt definition),
codexMcpConfig.test.ts (comprehensive tests)
- Updated: codexLocal.ts (accepts mcpServers, builds config args),
codexLocalLauncher.ts (starts hapi server, passes config),
codexStartConfig.ts (imports TITLE_INSTRUCTION)
Create BaseSessionScanner abstract class to consolidate common session
scanning logic shared between Claude and Codex session scanners. Both
scanners now inherit from this base, reducing duplication and providing
consistent patterns for file watching, event processing, and state
management.
Introduces support for displaying API error system messages in the web UI with
automatic folding of consecutive retry messages to show only the latest state.
Extract permission and model mode validation into reusable functions utilizing
@hapi/protocol schemas. Use isPermissionModeAllowedForFlavor and
isModelModeAllowedForFlavor to validate modes based on session flavor (claude/codex).
Replace inline type definitions with shared types from @hapi/protocol.
Consolidates duplicate cleanup, signal handling, and state management logic from
runClaude and runCodex into a reusable createRunnerLifecycle factory function.
Extracts mode switching handler and controlled user state updates into utilities.
Adds runLocalRemoteSession wrapper to handle session ready callbacks in loop base.
Extract permission mode display logic into shared utilities for better reusability and maintainability. Add PermissionModeTone type and related helpers to centralize mode-based styling rules across components. Update components to use new PermissionModeOption type for consistent permission mode presentation.
Extract duplicate version acknowledgment logic from apiMachine and
apiSession into a reusable applyVersionedAck utility. This handles
success, version-mismatch, and error responses consistently with
customizable parsing and error handling via options object.
Restructure CLI entry point and RPC handler registration to improve maintainability:
- Introduce command registry pattern with CommandDefinition interface for consistent command structure
- Extract individual command modules (claude, codex, daemon, doctor, gemini, auth, connect, etc.)
- Move RPC handlers into separate feature modules (bash, files, git, directories, ripgrep, difftastic, slashCommands)
- Create shared RPC types and response helpers (rpcTypes.ts, rpcResponses.ts)
- Move SpawnSessionOptions and SpawnSessionResult to rpcTypes for proper type organization
- Simplify index.ts to minimal entrypoint using command registry
- Update imports in apiMachine.ts and daemon/run.ts to use rpcTypes module
This enables:
- Better code organization by feature/command
- Easier testing of individual commands
- Safer RPC handler registration without side effects
- Clearer separation of concerns between routing and business logic
Extracted five focused modules from SyncEngine to improve maintainability
and separation of concerns:
- EventPublisher: handles event broadcasting and listener management
- SessionCache: manages session state and lifecycle
- MachineCache: manages machine state and lifecycle
- MessageService: handles message storage and retrieval
- RpcGateway: handles RPC communication with sessions and machines
- aliveTime: utility for clamping and validating alive timestamps
Removed unused members (sessionMessages cache, fetchMessages,
getSessionMessages, setPermissionMode, setModelMode) that added
complexity without clear value.
SyncEngine now orchestrates these services as a lightweight facade,
improving code organization and testability.
Instead of throwing a schema mismatch error when version is 0 but tables already exist, set the version and return. This allows the database to properly initialize without erroring.
Add close button to Chrome/Edge install prompt and respect dismissed state
when determining if prompt can be shown. iOS version already had dismiss
capability, so this brings feature parity across all supported browsers.
Replace legacy migration logic (ALTER TABLE, missing column checks) with explicit
schema version tracking. This prevents silent schema mismatches and simplifies the
database lifecycle—users must rebuild or offline-migrate on version mismatch.
Changes:
- Add SCHEMA_VERSION and REQUIRED_TABLES constants
- Refactor initSchema() to check version and table presence
- Extract createSchema() and helper methods (getUserVersion, setUserVersion, etc)
- Add compound indexes for better query performance (tag+namespace, platform+namespace)
- Store dbPath for better error messages
Extract notification logic from PushNotifier into a modular architecture
with NotificationHub as the central coordinator and NotificationChannel
interface for different notification providers (push, telegram). This
enables better separation of concerns and easier addition of new
notification channels in the future.
- Create NotificationHub to coordinate multiple notification channels
- Create NotificationChannel interface for channel implementations
- Move push notification logic to PushNotificationChannel
- Update HappyBot to implement NotificationChannel
- Simplify HappyBot by removing sync event handling (delegated to hub)
- Add notification helper utilities (sessionInfo, eventParsing)
- Update index.ts to use new notification architecture
Allow updateSessionMetadata to conditionally update the updated_at timestamp
by adding an optional touchUpdatedAt flag. When set to false, the timestamp is
not modified, enabling metadata updates without changing the last modified time.
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.
Implements comprehensive session lifecycle management with user-friendly interactions:
Rename: Update session metadata.name via PATCH endpoint with conflict detection
Archive: Abort active sessions via DELETE endpoint with validation
Delete: Permanently remove inactive sessions with cascade cleanup
Backend:
- Store.deleteSession() removes session and cascade-deletes messages
- SyncEngine.renameSession() with concurrency error handling
- SyncEngine.deleteSession() with active session validation
- PATCH /sessions/:id for rename, DELETE /sessions/:id for delete
Frontend Components:
- RenameSessionDialog: Text input with auto-focus and error display
- SessionActionMenu: Modal with rename, archive, delete buttons
- ConfirmDialog: Reusable confirmation with error feedback
- SessionHeader: Menu button (⋮) triggering action menu
- SessionList: Long-press detection triggering item actions
Interactions:
- Long-press on session list items (500ms threshold) opens action menu
- Menu button in session header (non-Telegram environments only)
- Confirmation dialogs with descriptive warnings for destructive actions
- Real-time error display in dialogs on operation failure
- Haptic feedback on long-press via usePlatform hook
Accessibility:
- Keyboard support (Enter/Space) for long-press handler
- Focus management in RenameSessionDialog
- Proper ARIA labels and semantic HTML