fix(coding-agent): start new sessions in the cwd's default directory

SessionManager.open() without a session directory used the file's
folder for new sessions. When the session's cwd differs from the project
the folder belongs to, for example after choosing "continue in current
cwd" at the missing-cwd prompt, pi treated that folder as a custom
--session-dir: /resume All listed only that folder, the resume hint
added --session-dir, and /new, /fork and /clone saved into the old
project's folder.

For a file in the sessions directory, open() now uses the default
directory of the session's cwd. Files elsewhere, such as in a custom
--session-dir, keep their folder.
This commit is contained in:
Juan Ibiapina 2026-10-29 12:17:18 +01:00
parent babe30a7e6
commit 0a60e18cc3
No known key found for this signature in database
GPG key ID: 1C474BBC910209AE
2 changed files with 44 additions and 2 deletions

View file

@ -1790,8 +1790,11 @@ export class SessionManager {
}
}
const cwd = cwdOverride ?? (header ? getSessionHeaderCwd(header) : undefined) ?? process.cwd();
// If no sessionDir provided, derive from file's parent directory
const dir = sessionDir ? normalizePath(sessionDir) : resolve(resolvedPath, "..");
// If no sessionDir provided, use the cwd's default directory for files in the sessions directory,
// otherwise the file's parent directory
const parentDir = resolve(resolvedPath, "..");
const inSessionsDir = resolve(parentDir, "..") === resolvePath(getSessionsDir());
const dir = sessionDir ? normalizePath(sessionDir) : inSessionsDir ? getDefaultSessionDirPath(cwd) : parentDir;
return new SessionManager(cwd, dir, resolvedPath, true, undefined, preloadedFileEntries);
}

View file

@ -15,6 +15,7 @@ import {
import { tmpdir } from "os";
import { join } from "path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { ENV_AGENT_DIR } from "../../src/config.ts";
import { findMostRecentSession, loadEntriesFromFile, SessionManager } from "../../src/core/session-manager.ts";
import { assistantMsg, readSessionFileRoles, userMsg } from "../utilities.ts";
@ -356,6 +357,44 @@ describe("SessionManager custom flat session directory", () => {
});
});
describe("SessionManager.open session directory", () => {
let tempDir: string;
let savedAgentDir: string | undefined;
beforeEach(() => {
tempDir = mkdtempSync(join(tmpdir(), "session-default-dir-"));
savedAgentDir = process.env[ENV_AGENT_DIR];
process.env[ENV_AGENT_DIR] = join(tempDir, "agent");
mkdirSync(join(tempDir, "a"));
mkdirSync(join(tempDir, "b"));
});
afterEach(() => {
if (savedAgentDir === undefined) delete process.env[ENV_AGENT_DIR];
else process.env[ENV_AGENT_DIR] = savedAgentDir;
rmSync(tempDir, { recursive: true, force: true });
});
it("uses the default directory of the cwd for a session opened with another cwd", () => {
const session = SessionManager.create(join(tempDir, "a"));
session.appendMessage(userMsg("hello"));
const reopened = SessionManager.open(session.getSessionFile()!, undefined, join(tempDir, "b"));
expect(reopened.getSessionDir()).toBe(SessionManager.create(join(tempDir, "b")).getSessionDir());
expect(reopened.usesDefaultSessionDir()).toBe(true);
});
it("keeps a custom session directory", () => {
const customDir = join(tempDir, "custom");
const session = SessionManager.create(join(tempDir, "a"), customDir);
session.appendMessage(userMsg("hello"));
const reopened = SessionManager.open(session.getSessionFile()!, undefined, join(tempDir, "b"));
expect(reopened.getSessionDir()).toBe(customDir);
expect(reopened.usesDefaultSessionDir()).toBe(false);
});
});
describe("SessionManager.setSessionFile with corrupted files", () => {
let tempDir: string;