chat: root the OpenCode server at the chat cwd (email chat now runs in the account dir)

OpenCode has no per-session `directory` — a session inherits the server's cwd (POST
/session ignores extra fields). So the previous "pass directory on create" was a no-op
and every OpenCode chat ran in the fixed server's dir (~), including the email chat.

Fix: hybrid server model. server-manager.ensureServer(cwd?, home?) returns the fixed
pm2 server (OPENCODE_SERVER_URL, :4096) for the general /chat, but for a context-scoped
cwd (email account dir, project dir) it spawns/pools an `opencode serve` rooted at that
directory — so the session's agent actually operates there. send-opencode passes the
resolved cwd + the user's home; createSession drops the ignored directory param.

Verified live: a cwd-scoped server reports the session directory as the target dir
(not ~), while /chat still uses :4096.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 20:20:15 +00:00
co-authored by Claude Opus 4.8
parent cbe83f39a9
commit d60c73b3a3
3 changed files with 124 additions and 18 deletions
+4 -7
View File
@@ -105,13 +105,10 @@ class ServerConnection {
return (await res.json()) as T;
}
async createSession(directory?: string, title?: string): Promise<string> {
// `directory` binds the session's working dir (e.g. an email account dir). Omit it for the general
// /chat, so the session lives in the fixed server's own project (its cwd).
const body: Record<string, unknown> = {};
if (directory) body.directory = directory;
if (title) body.title = title;
const session = await this.postJson<{ id?: string }>('/session', body);
async createSession(title?: string): Promise<string> {
// OpenCode has no per-session `directory` — the working dir is the server's cwd (server-manager
// roots the server at the desired dir). So we only optionally set a title here.
const session = await this.postJson<{ id?: string }>('/session', title ? { title } : {});
if (!session.id) throw new Error('opencode POST /session returned no id');
return session.id;
}