diff --git a/packages/coding-agent/src/core/session-manager.ts b/packages/coding-agent/src/core/session-manager.ts index aab0c0e9..b8b930d8 100644 --- a/packages/coding-agent/src/core/session-manager.ts +++ b/packages/coding-agent/src/core/session-manager.ts @@ -1558,8 +1558,7 @@ export class SessionManager { */ static continueRecent(cwd: string, sessionDir?: string): SessionManager { const dir = sessionDir ? normalizePath(sessionDir) : getDefaultSessionDir(cwd); - const filterCwd = sessionDir !== undefined && dir !== getDefaultSessionDirPath(cwd); - const mostRecent = findMostRecentSession(dir, filterCwd ? cwd : undefined); + const mostRecent = findMostRecentSession(dir, cwd); if (mostRecent) { return new SessionManager(cwd, dir, mostRecent, true); } @@ -1639,10 +1638,9 @@ export class SessionManager { */ static async list(cwd: string, sessionDir?: string, onProgress?: SessionListProgress): Promise { const dir = sessionDir ? normalizePath(sessionDir) : getDefaultSessionDir(cwd); - const filterCwd = sessionDir !== undefined && dir !== getDefaultSessionDirPath(cwd); const resolvedCwd = resolvePath(cwd); - const sessions = (await listSessionsFromDir(dir, onProgress)).filter( - (session) => !filterCwd || sessionCwdMatches(session.cwd, resolvedCwd), + const sessions = (await listSessionsFromDir(dir, onProgress)).filter((session) => + sessionCwdMatches(session.cwd, resolvedCwd), ); sessions.sort((a, b) => b.modified.getTime() - a.modified.getTime()); return sessions; diff --git a/packages/coding-agent/test/feedback.test.ts b/packages/coding-agent/test/feedback.test.ts index 854471c0..cda4ee03 100644 --- a/packages/coding-agent/test/feedback.test.ts +++ b/packages/coding-agent/test/feedback.test.ts @@ -1153,7 +1153,7 @@ describe("feedback diagnostics and bundles", () => { note: expect.stringContaining("re-limited after redaction"), }); expect(result.bundle.files).toEqual(manifest.files); - }); + }, 90_000); test("redacts tail echoes using credentials discovered before both session limits", async () => { const root = await makeRoot(); diff --git a/packages/coding-agent/test/session-manager/project-isolation.test.ts b/packages/coding-agent/test/session-manager/project-isolation.test.ts new file mode 100644 index 00000000..c535b09e --- /dev/null +++ b/packages/coding-agent/test/session-manager/project-isolation.test.ts @@ -0,0 +1,45 @@ +import { mkdtempSync, readFileSync, rmSync, utimesSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { SessionManager } from "../../src/core/session-manager.ts"; +import { StepSessionManager } from "../../src/step/session.ts"; + +describe("colliding project session directories", () => { + const roots: string[] = []; + afterEach(() => { + vi.unstubAllEnvs(); + for (const root of roots) rmSync(root, { recursive: true, force: true }); + roots.length = 0; + }); + + for (const [name, manager] of [ + ["native", SessionManager], + ["Step", StepSessionManager], + ] as const) { + it(`${name} lists and continues only the current project`, async () => { + const root = mkdtempSync(join(tmpdir(), "step-session-isolation-")); + roots.push(root); + vi.stubEnv("STEP_CODING_AGENT_DIR", join(root, "agent")); + vi.stubEnv("STEP_CODING_AGENT_SESSION_DIR", undefined); + const projectA = join(root, "project-a"); + const projectB = join(root, "project", "a"); + const a = manager.create(projectA); + const b = manager.create(projectB); + expect(a.getSessionDir()).toBe(b.getSessionDir()); + const fileA = a.getSessionFile()!; + const fileB = b.getSessionFile()!; + writeFileSync(fileA, `${JSON.stringify(a.getHeader())}\n`); + writeFileSync(fileB, `${JSON.stringify(b.getHeader())}\n`); + utimesSync(fileA, 1, 1); + utimesSync(fileB, 2, 2); + const beforeB = readFileSync(fileB, "utf8"); + + expect.soft((await manager.list(projectA)).map((session) => session.path)).toEqual([fileA]); + const continued = manager.continueRecent(projectA); + expect.soft(continued.getSessionFile()).toBe(fileA); + continued.appendMessage({ role: "user", content: "project A only", timestamp: 1 }); + expect(readFileSync(fileB, "utf8")).toBe(beforeB); + }); + } +}); diff --git a/packages/coding-agent/vitest.config.ts b/packages/coding-agent/vitest.config.ts index 47f4de1f..d084ae02 100644 --- a/packages/coding-agent/vitest.config.ts +++ b/packages/coding-agent/vitest.config.ts @@ -7,6 +7,7 @@ export default mergeConfig( test: { globals: true, environment: "node", + maxWorkers: 2, testTimeout: 30000, unstubEnvs: true, reporters: process.env.GITHUB_ACTIONS ? ["dot", "github-actions"] : ["dot"],