Reorganizes email storage: the DB moves from DATA_PATH/<user>/emails.db to
DATA_PATH/<user>/email_accounts/<accountEmail>/emails.db, with a shared
email_accounts/attachment_cache/ (was Gmail/emails/attachments). openEmailDb now
takes (owner, account); a new openUserEmailDb(owner, userId) resolves the user's
configured account (first enabled) for read paths. Threads the account through
email.ts, accounts, resync, queue sync, channel handlers, and the email_db MCP
tool path. Drops the dead getUserEmailDir helper.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The API and email sidecar both open emails.db; without a busy timeout a write
overlap (resync, or the thread_id backfill) throws "database is locked" and
500s a request. Wait up to 5s for the other writer instead.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hybrid grouping via a new thread_id column: new mail threads exactly on
References/In-Reply-To (id is sha1(Message-Id), so a referenced id hashes to
the ancestor's own id); already-synced mail is backfilled with a
normalized-subject + counterpart key. Folder views collapse to one row per
thread with a count badge; the reader shows the thread as a collapsible stack.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- add getValidGoogleAccessToken helper and use it in email-cron, email account auth resolver, and the new gmail proxy
- POST /api/integrations/google/gmail-proxy forwards arbitrary gmail rest calls server-side, with auto-refreshed oauth
- pi-manager and claude user-instance inject OFFICER_API_URL + per-session JWT so tools can call back as the user
- claude anthropic proxy uses Authorization: Bearer + preserves any anthropic-beta headers (pro oauth tokens are rejected via x-api-key, and overwriting the beta header broke context_management)
- pi --list-models: fall back to stderr when stdout is empty (pi v0.73.1 writes the table to stderr)
- mcp tool server + pi tool loader: accept type: object inputs so json bodies stay structured
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First sync still uses IMAP with app password. Subsequent syncs use
Gmail API history.list + messages.get with OAuth for faster, more
reliable incremental sync. Dispatch gmail-sync handler for gmail
accounts instead of generic email-sync. Show sync button for synced
accounts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Flips the connection model so sidecars register themselves with the API
server via WebSocket at /api/sidecar/register, enabling dynamic discovery,
location independence, and automatic reconnection from either side.
- Add registration protocol types and PTY command/event types
- Create sidecar-registry.ts (replaces sidecar-client.ts) as passive registry
- Create sidecar connector (connect.ts) with exponential backoff reconnect
- Convert process sidecar from WS server to WS client
- Convert PTY sidecar from WS server to multiplexed WS client
- Simplify terminal bridge to thin adapter using registry
- Add PTY sidecar as PM2-managed process
- Update all consumer imports
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rewired EmailList sync button to call /email/accounts/:id/sync instead
of the old gmail-sync job. Shows sync button for connected and synced
accounts. Allow manual incremental sync for synced accounts.
Added duration logging to queue runner: start/complete/fail markers
with elapsed time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sidecar/queue runner no longer needs job-specific context. API server
resolves account details, IMAP auth, and user email at enqueue time —
all persisted in the job file. Handler reads directly from job meta.
Removed "Load account" step. Sync step auto-reconnects up to 10 times
when Gmail drops the connection, resuming from saved UIDs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Issues:
1. User directories created with chmod 770 (too restrictive)
- Prevents service user from reading/writing even though in group
- Changed to chmod 775 (recursive) to allow group access
2. openEmailDb tries to chmod file it may not own
- If file owned by different user (e.g., andrepadez), chmod fails
- Wrapped chmodSync in try/catch to gracefully skip
Changes:
- src/servers/api/users/provision.ts:
* Changed chmod 770 → 775 (owner/group rwx, others rx)
* Applied recursively to all subdirectories
* Added chmod after seeding files to ensure consistency
- src/servers/api/email/email-db.ts:
* Wrapped chmodSync in try/catch
* Logs silently skip if file not owned by current process
* Database still works even if chmod fails
Fixes /email endpoint 500 errors for users with email data.
- add claude-code as virtual model in channel messaging (telegram/discord/whatsapp)
- new send-claude-code.ts: docker exec claude -p with session resumption
- route claude-code model in sendAndAwait before Pi pipeline
- append claude-code to listPiModels output
- fix container .claude mount (rw for sub-mounts), hooks format (matcher-based)
- pre-seed hasTrustDialogAccepted and bypassPermissions in container settings
- git init in entrypoint to skip workspace trust prompt
- fix ~/~ double-tilde in CommandTerminalWrapper cwd resolution
- remove --continue from claude-code panel command
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- respect charset from Content-Type when decoding body and headers
- detect inline attachments with filenames (not just disposition: attachment)
- fix broken decodeQuotedPrintable reference in parseAttachments
- white background for email iframe (emails designed for light bg)
- sticky header in email list, scrollable message area
- arrow key navigation between emails with scroll-into-view
- /email/:id routing for deep linking to specific emails
- empty folder shows "No emails in this folder" instead of losing header
- fix attachment viewer header overlap with dialog close button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>