Skip to content

Commit cc2ea2f

Browse files
committed
fix: keep session inspection read-only
1 parent fad8b57 commit cc2ea2f

3 files changed

Lines changed: 145 additions & 1 deletion

File tree

‎src/lib/commands/session.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ export async function runSession(
170170
options: SessionOptions = {}
171171
): Promise<string> {
172172
const cwd = options.cwd ?? process.cwd();
173-
const runtime = await buildRuntimeContext(cwd);
174173
const scope = selectedScope(options.scope);
175174

176175
if (action === "save" || action === "refresh") {
176+
const runtime = await buildRuntimeContext(cwd);
177177
const persistenceRequest = await prepareSessionPersistenceRequest(
178178
runtime,
179179
action,
@@ -197,6 +197,7 @@ export async function runSession(
197197
}
198198

199199
if (action === "clear") {
200+
const runtime = await buildRuntimeContext(cwd);
200201
const cleared = await runtime.sessionContinuityStore.clear(scope);
201202
if (options.json) {
202203
return JSON.stringify({ cleared }, null, 2);
@@ -210,6 +211,7 @@ export async function runSession(
210211
}
211212

212213
if (action === "open") {
214+
const runtime = await buildRuntimeContext(cwd);
213215
await runtime.sessionContinuityStore.ensureLocalLayout();
214216
openPath(runtime.sessionContinuityStore.paths.localDir);
215217
return [
@@ -218,6 +220,9 @@ export async function runSession(
218220
].join("\n");
219221
}
220222

223+
const runtime = await buildRuntimeContext(cwd, {}, {
224+
ensureMemoryLayout: false
225+
});
221226
const view = await loadSessionInspectionView(runtime);
222227

223228
if (action === "load") {

‎test/dist-cli-smoke.test.ts‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ async function waitForFile(pathname: string, timeoutMs = 2_000): Promise<string>
5555
}
5656
}
5757

58+
async function pathExists(targetPath: string): Promise<boolean> {
59+
try {
60+
await fs.access(targetPath);
61+
return true;
62+
} catch {
63+
return false;
64+
}
65+
}
66+
5867
afterEach(async () => {
5968
if (originalCodexHome === undefined) {
6069
delete process.env.CODEX_HOME;
@@ -298,6 +307,68 @@ describe("dist cli smoke", () => {
298307
expect(forgetPayload.followUp.timelineRefs.length).toBeGreaterThan(0);
299308
}, 30_000);
300309

310+
it("keeps session inspection read-only from the compiled cli entrypoint", async () => {
311+
const homeDir = await tempDir("cam-dist-session-readonly-home-");
312+
const projectDir = await tempDir("cam-dist-session-readonly-project-");
313+
const memoryRootParent = await tempDir("cam-dist-session-readonly-memory-parent-");
314+
const memoryRoot = path.join(memoryRootParent, "memory-root");
315+
316+
await writeCamConfig(projectDir, makeAppConfig(), {
317+
autoMemoryDirectory: memoryRoot
318+
});
319+
320+
const sessionStatusResult = runCli(projectDir, ["session", "status", "--json"], {
321+
entrypoint: "dist",
322+
env: { HOME: homeDir }
323+
});
324+
const sessionLoadResult = runCli(
325+
projectDir,
326+
["session", "load", "--json", "--print-startup"],
327+
{
328+
entrypoint: "dist",
329+
env: { HOME: homeDir }
330+
}
331+
);
332+
333+
expect(sessionStatusResult.exitCode, sessionStatusResult.stderr).toBe(0);
334+
expect(sessionLoadResult.exitCode, sessionLoadResult.stderr).toBe(0);
335+
expect(JSON.parse(sessionStatusResult.stdout)).toMatchObject({
336+
projectLocation: {
337+
exists: false
338+
},
339+
localLocation: {
340+
exists: false
341+
},
342+
latestContinuityAuditEntry: null,
343+
latestContinuityDiagnostics: null,
344+
pendingContinuityRecovery: null,
345+
startup: {
346+
sourceFiles: [],
347+
candidateSourceFiles: [],
348+
continuityMode: "startup",
349+
continuityProvenanceKind: "temporary-continuity"
350+
}
351+
});
352+
expect(JSON.parse(sessionLoadResult.stdout)).toMatchObject({
353+
projectLocation: {
354+
exists: false
355+
},
356+
localLocation: {
357+
exists: false
358+
},
359+
latestContinuityAuditEntry: null,
360+
latestContinuityDiagnostics: null,
361+
pendingContinuityRecovery: null,
362+
startup: {
363+
sourceFiles: [],
364+
candidateSourceFiles: [],
365+
continuityMode: "startup",
366+
continuityProvenanceKind: "temporary-continuity"
367+
}
368+
});
369+
expect(await pathExists(memoryRoot)).toBe(false);
370+
});
371+
301372
it("uses the recommended recall search preset from the compiled cli entrypoint without creating memory layout on first lookup", async () => {
302373
const homeDir = await tempDir("cam-dist-recall-home-");
303374
const projectDir = await tempDir("cam-dist-recall-project-");

‎test/session-command.test.ts‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ process.exit(0);
5757
return mockCodexPath;
5858
}
5959

60+
async function pathExists(targetPath: string): Promise<boolean> {
61+
try {
62+
await fs.access(targetPath);
63+
return true;
64+
} catch {
65+
return false;
66+
}
67+
}
68+
6069
describe("runSession", () => {
6170
it("shows an empty compact prior preview when no continuity audit history exists", async () => {
6271
const repoDir = await tempDir("cam-session-empty-history-repo-");
@@ -576,6 +585,65 @@ describe("runSession", () => {
576585
expect(statusPayload.localLocation.exists).toBe(false);
577586
}, 30_000);
578587

588+
it("keeps session load and status read-only on an uninitialized project", async () => {
589+
const homeDir = await tempDir("cam-session-readonly-home-");
590+
const projectDir = await tempDir("cam-session-readonly-project-");
591+
const memoryRootParent = await tempDir("cam-session-readonly-memory-parent-");
592+
const memoryRoot = path.join(memoryRootParent, "memory-root");
593+
await initRepo(projectDir);
594+
595+
await writeProjectConfig(
596+
projectDir,
597+
configJson(),
598+
{ autoMemoryDirectory: memoryRoot }
599+
);
600+
601+
const statusResult = runCli(projectDir, ["session", "status", "--json"], {
602+
env: { HOME: homeDir }
603+
});
604+
const loadResult = runCli(projectDir, ["session", "load", "--json", "--print-startup"], {
605+
env: { HOME: homeDir }
606+
});
607+
608+
expect(statusResult.exitCode, statusResult.stderr).toBe(0);
609+
expect(loadResult.exitCode, loadResult.stderr).toBe(0);
610+
expect(JSON.parse(statusResult.stdout)).toMatchObject({
611+
projectLocation: {
612+
exists: false
613+
},
614+
localLocation: {
615+
exists: false
616+
},
617+
latestContinuityAuditEntry: null,
618+
latestContinuityDiagnostics: null,
619+
pendingContinuityRecovery: null,
620+
startup: {
621+
sourceFiles: [],
622+
candidateSourceFiles: [],
623+
continuityMode: "startup",
624+
continuityProvenanceKind: "temporary-continuity"
625+
}
626+
});
627+
expect(JSON.parse(loadResult.stdout)).toMatchObject({
628+
projectLocation: {
629+
exists: false
630+
},
631+
localLocation: {
632+
exists: false
633+
},
634+
latestContinuityAuditEntry: null,
635+
latestContinuityDiagnostics: null,
636+
pendingContinuityRecovery: null,
637+
startup: {
638+
sourceFiles: [],
639+
candidateSourceFiles: [],
640+
continuityMode: "startup",
641+
continuityProvenanceKind: "temporary-continuity"
642+
}
643+
});
644+
expect(await pathExists(memoryRoot)).toBe(false);
645+
}, 30_000);
646+
579647
it("refresh replaces only the selected scope", async () => {
580648
const repoDir = await tempDir("cam-session-refresh-scope-repo-");
581649
const memoryRoot = await tempDir("cam-session-refresh-scope-memory-");

0 commit comments

Comments
 (0)