a chat with no chosen directory runs in the caller's own home
The default was DATA_PATH/<email>/general_chat_sessions, a dedicated directory so /chat sessions formed their own Claude project group instead of cluttering the home. It is a sibling of the home, and confineUserTree makes every sibling the platform's at 0700 because the others are attachments and email_accounts. So it was unreachable for a member: the first live member turn started there and every Bash call failed on its own working directory before doing anything. A per-member copy inside each home fixed the symptom and left two rules to remember. The owner chose one rule instead — the account's own home, whoever they are — and accepted the trade knowingly: /chat sessions now share a project group with anything else run from that home, which was the reason the dedicated directory existed. Removed rather than left dangling: getGeneralChatSessionsCwd, ensureGeneralChatSessionsCwd, ensureMemberChatCwd, and general_chat_sessions from USER_DIRS so new accounts stop getting it. Existing directories are untouched and their transcripts stay where they are — Claude groups by cwd, so the owner's old /chat history remains under its own project slug rather than moving. The UI labels move with it: the default group now reads "home" rather than naming a directory that no longer has a role. ChatIdentity keeps carrying both email and home. The pairing was justified in the comment by general_chat_sessions being email-derived, which is now gone — but the distinction it encodes is real (the email says who, the home says where), so the comment explains that instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,13 +13,12 @@ import { sessionManager } from './session-manager';
|
||||
import { rememberOpenCodePrompt } from './opencode/state';
|
||||
import { sendClaudeCodeStreaming } from '@@/channels/send-claude-code';
|
||||
import { sendOpenCodeStreaming } from '@@/channels/send-opencode';
|
||||
import { ensureGeneralChatSessionsCwd } from './claude-sessions';
|
||||
import * as sidecar from '@@/sidecar-registry';
|
||||
import { join } from 'path';
|
||||
import { getOwnerHomeDir, getEmailAccountsDir } from '../../../servers/data-path';
|
||||
import { getUserSettings, getEmailAccounts, getChatEventsSince, appendChatEvent, getUserById } from 'officerdb';
|
||||
import { resolveHomeDir } from '@@/user-home';
|
||||
import { claudeLoginState, ensureMemberChatCwd } from '@@/os-user-claude';
|
||||
import { claudeLoginState } from '@@/os-user-claude';
|
||||
import { mkdirSync } from 'node:fs';
|
||||
import { logger } from './logger';
|
||||
|
||||
@@ -132,21 +131,29 @@ async function resolveEmailCwd(userId: number, ownerEmail: string, accountEmail?
|
||||
}
|
||||
|
||||
// The working directory a chat turn runs in, by context: email → the account dir; /chat → a chosen
|
||||
// pwd or the default general_chat_sessions dir; everything else (browser/project/dashboard) → the given cwd.
|
||||
// pwd or the caller's own home; everything else (browser/project/dashboard) → the given cwd.
|
||||
async function resolveChatCwd(
|
||||
msg: { context?: string; contextId?: string; cwd?: string },
|
||||
email: string,
|
||||
userId: number,
|
||||
home: string,
|
||||
member?: { osUser: string; home: string },
|
||||
): Promise<string> {
|
||||
if (msg.context === 'email') return resolveEmailCwd(userId, email, msg.contextId);
|
||||
if (msg.context === 'chat') {
|
||||
if (msg.cwd?.trim()) return resolveCwd(home, msg.cwd);
|
||||
// The default chat directory. The owner's is a sibling of their home; a member's is INSIDE theirs,
|
||||
// because that sibling is platform-owned at 0700 by design and a member cannot enter it — which is
|
||||
// exactly how the first live member turn failed, with every Bash call dying on its own cwd.
|
||||
return member ? ensureMemberChatCwd(member) : ensureGeneralChatSessionsCwd(email);
|
||||
// The caller's own home, for everyone.
|
||||
//
|
||||
// This used to be `DATA_PATH/<email>/general_chat_sessions`, a dedicated directory so /chat sessions
|
||||
// formed their own Claude project group and did not clutter the home. That is a sibling of the home,
|
||||
// and `confineUserTree` makes every sibling the platform's at 0700 because the others are `attachments`
|
||||
// and `email_accounts` — so it was unreachable for a member. The first live member turn ran there and
|
||||
// every Bash call failed on its own working directory before doing anything.
|
||||
//
|
||||
// A per-member copy inside each home would have worked and would have left two rules to remember. The
|
||||
// owner chose one: a chat with no chosen directory runs in the account's own home, whoever they are.
|
||||
// The cost is that /chat sessions now share a project group with anything else run from that home,
|
||||
// which was the reason the dedicated directory existed and is a trade the owner made knowingly.
|
||||
return home;
|
||||
}
|
||||
return resolveCwd(home, msg.cwd);
|
||||
}
|
||||
@@ -402,7 +409,7 @@ async function handleClaudeCodeChat(
|
||||
|
||||
const home = identity.kind === 'member' ? identity.run.home : getOwnerHomeDir(email);
|
||||
|
||||
const cwd = await resolveChatCwd(msg, email, userId, home, identity.kind === 'member' ? identity.run : undefined);
|
||||
const cwd = await resolveChatCwd(msg, email, userId, home);
|
||||
|
||||
const groupSlug = msg.groupSlug || null;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user