diff --git a/src/servers/sidecar/claude/user-instance.ts b/src/servers/sidecar/claude/user-instance.ts index cf7abb46..c820a3b5 100644 --- a/src/servers/sidecar/claude/user-instance.ts +++ b/src/servers/sidecar/claude/user-instance.ts @@ -86,7 +86,19 @@ const homeDir = homedir(); const globalToolsDir = join(DATA_PATH, 'tools'); // The email_db MCP tool reads one account's SQLite store; match the API's choice (first enabled). -const emailAccounts = await getEmailAccounts(dbUser.id); +// +// Guarded for the same reason `resolveOwner` above is, and it is the same bug in a second place: this +// is a top-level await, so a query that THROWS rejects it and exits the process — straight into the PM2 +// restart loop, taking every live agent session with it. `resolveOwner` was hardened after that cost a +// session on 2026-08-10; this line has the identical shape and was not. +// +// It throws for real now: email is a plugin, so `email_accounts` is commented out of the schema +// (officerdb/src/schema.ts) and does not exist on a core install. An agent must start without it — the +// email tool is one tool, not a prerequisite for chat. +const emailAccounts = await getEmailAccounts(dbUser.id).catch(() => { + console.warn('[agent] no email accounts (the email plugin is not installed) — the email_db tool will be idle'); + return [] as Awaited>; +}); const emailAccount = emailAccounts.find((a) => a.enabled) ?? emailAccounts[0]; const emailDbRel = join('email_accounts', emailAccount?.email ?? 'none', 'emails.db'); const userToolsDir = join(DATA_PATH, email, 'tools');