resolve transcripts and cwd against the caller's home, not the owner's
The history layer, and the last change that could be made without a live member.
claude-sessions.ts had `claudeHome = process.env.HOME_DIR ?? join(DATA_PATH,
email, 'home')`, which discards its argument whenever HOME_DIR is set — always,
on a real install. Every transcript read therefore resolved to the OWNER'S
~/.claude no matter who asked, and the comment above it asserted "single-user
platform" as though that were a property rather than an assumption. A member
reaching these functions would have been handed the owner's conversation list.
Now every read takes a ChatIdentity {email, home} with the home resolved from
resolveHomeDir(userId), and this file has no way to invent one. Both fields
travel together because they are genuinely different: general_chat_sessions
lives under DATA_PATH/<email>, not under a home. Collapsing them would be the
same class of mistake as undefined meaning "the owner".
websocket.ts's resolveCwd takes a home, so `~` expands against the caller's own.
Identity is resolved BEFORE the cwd — expanding `~` before knowing whose home it
is would be exactly the bug being removed — which also let a duplicate
resolveTurnIdentity call from 6aeb304 be deleted.
chat.ts resolves per request and throws FORBIDDEN rather than falling back, same
posture as resolveTurnIdentity. agent-runner passes the owner's home explicitly
rather than inheriting it, since that path really is owner-only.
Made at 01:00 after saying it should not be. Three things I am least sure of are
listed in COMMS 29 rather than left for the reviewer to find: chat routes now
have a failure mode they did not have, resolveBaseCwd's exported parameter
changed meaning rather than shape, and the bare-email rewrite in chat.ts was
mechanical with hand repair.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -87,7 +87,7 @@ export function buildAgentPrompt(agent: AgentRecord, inputs: Record<string, unkn
|
||||
* which is fine: while a run is live you find it as the newest entry in the agent's project group.
|
||||
*/
|
||||
function titleRun(
|
||||
email: string,
|
||||
who: { email: string; home: string },
|
||||
cwd: string,
|
||||
claudeSessionId: string,
|
||||
agentName: string,
|
||||
@@ -99,7 +99,7 @@ function titleRun(
|
||||
const title = [agentName, subject, when].filter(Boolean).join(' · ');
|
||||
|
||||
try {
|
||||
if (!renameClaudeSession(email, cwd, claudeSessionId, title)) {
|
||||
if (!renameClaudeSession(who, cwd, claudeSessionId, title)) {
|
||||
logger.warn('Could not title agent run — transcript not found', { claudeSessionId, cwd });
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -171,7 +171,13 @@ export async function startAgentRun(params: StartAgentRunParams): Promise<StartA
|
||||
run.finishedAt = Date.now();
|
||||
if (msg.claudeSessionId) {
|
||||
run.claudeSessionId = msg.claudeSessionId;
|
||||
titleRun(params.user.email, cwd, msg.claudeSessionId, agent.name || agent.dirName, inputs);
|
||||
titleRun(
|
||||
{ email: params.user.email, home: homeDir },
|
||||
cwd,
|
||||
msg.claudeSessionId,
|
||||
agent.name || agent.dirName,
|
||||
inputs,
|
||||
);
|
||||
}
|
||||
} else if (msg.type === 'error') {
|
||||
run.status = 'failed';
|
||||
|
||||
Reference in New Issue
Block a user