From 88b74b288801e3ce7d8f739f8dd6b79a844676ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sat, 25 Jul 2026 12:00:34 +0000 Subject: [PATCH] chat: OpenCode /chat cwd = general_chat_sessions (match Claude), drop home special-case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both harnesses now use the resolved chat cwd as their working directory: Claude runs in it natively, and OpenCode is told the same via its system prompt. Removes the earlier special-case that pointed OpenCode at the user's home for /chat, so `workingDir` collapses into `cwd` — which now both tags the session (metadata.officer.cwd) and drives the Officer system prompt. Co-Authored-By: Claude Opus 4.8 --- src/servers/api/chat/websocket.ts | 7 +------ src/servers/channels/send-opencode.ts | 5 ++--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/servers/api/chat/websocket.ts b/src/servers/api/chat/websocket.ts index 0e4e04f6..91756f76 100644 --- a/src/servers/api/chat/websocket.ts +++ b/src/servers/api/chat/websocket.ts @@ -4,7 +4,7 @@ import type { ClientMessage, ServerMessage, Message, ChatEvent } from './types'; import { sessionManager } from './session-manager'; import { sendClaudeCodeStreaming } from '@@/channels/send-claude-code'; import { sendOpenCodeStreaming } from '@@/channels/send-opencode'; -import { ensureGeneralChatSessionsCwd, getGeneralChatSessionsCwd } from './claude-sessions'; +import { ensureGeneralChatSessionsCwd } from './claude-sessions'; import * as sidecar from '@@/sidecar-registry'; import { join } from 'path'; import { getHomeDirForRole, getEmailAccountsDir } from '../../../servers/data-path'; @@ -459,10 +459,6 @@ async function handleOpenCodeChat( const onEvent = createEventHandler(sessionId, model, cwd); - // The dir the OpenCode model should treat as its cwd (via the Officer system prompt). For the general - // /chat, the resolved cwd is just the general_chat_sessions grouping placeholder, so use the user's home. - const workingDir = cwd === getGeneralChatSessionsCwd(email) ? getHomeDirForRole(email, ws.data.role) : cwd; - try { const handle = await sendOpenCodeStreaming({ userId, @@ -471,7 +467,6 @@ async function handleOpenCodeChat( prompt: effectivePrompt, sessionKey: sessionId, cwd, - workingDir, model, role: ws.data.role, resumeSessionId: msg.resumeSessionId, diff --git a/src/servers/channels/send-opencode.ts b/src/servers/channels/send-opencode.ts index 040ca734..8f400241 100644 --- a/src/servers/channels/send-opencode.ts +++ b/src/servers/channels/send-opencode.ts @@ -14,8 +14,7 @@ type OpenCodeStreamingParams = { username: string; prompt: string; sessionKey: string; - cwd?: string; // logical cwd for session tagging/listing (metadata.officer.cwd) - workingDir?: string; // the dir the model should treat as its cwd (Officer system prompt) + cwd?: string; // the session's working dir: tags it (metadata.officer.cwd) + told to the model (system prompt) model?: string; role?: string; resumeSessionId?: string; @@ -73,7 +72,7 @@ export async function sendOpenCodeStreaming(params: OpenCodeStreamingParams): Pr unsub = conn.subscribe(sessionId, mapper); const { providerID, modelID } = splitModel(params.model ?? ''); - const system = params.workingDir ? officerSystemPrompt(params.workingDir) : undefined; + const system = params.cwd ? officerSystemPrompt(params.cwd) : undefined; // Fire the turn; assistant tokens + tool calls stream back over the SSE subscription above. conn.postMessage(sessionId, providerID, modelID, params.prompt, system).catch((err) => {