Skip to content

Commit edd25a6

Browse files
committed
Ensure sessions are only recorded when persist is called
1 parent e6f587d commit edd25a6

2 files changed

Lines changed: 32 additions & 11 deletions

File tree

apps/cli/commands/ai/index.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,16 @@ export async function runCommand(
7474

7575
if ( options.noSessionPersistence ) {
7676
ui.showInfo( 'Session persistence disabled (--no-session-persistence).' );
77-
} else {
77+
}
78+
79+
const ensureSessionRecorder = async (): Promise< AiSessionRecorder | undefined > => {
80+
if ( didDisableSessionPersistence ) {
81+
return undefined;
82+
}
83+
if ( sessionRecorder ) {
84+
return sessionRecorder;
85+
}
86+
7887
try {
7988
if ( options.resumeSession ) {
8089
sessionRecorder = await AiSessionRecorder.open( {
@@ -89,16 +98,19 @@ export async function runCommand(
8998
didDisableSessionPersistence = true;
9099
ui.showError( `Session persistence disabled: ${ getErrorMessage( error ) }` );
91100
}
92-
}
101+
102+
return sessionRecorder;
103+
};
93104

94105
const persist = ( callback: ( recorder: AiSessionRecorder ) => Promise< void > ) => {
95106
persistQueue = persistQueue.then( async () => {
96-
if ( ! sessionRecorder ) {
107+
const recorder = await ensureSessionRecorder();
108+
if ( ! recorder ) {
97109
return;
98110
}
99111

100112
try {
101-
await callback( sessionRecorder );
113+
await callback( recorder );
102114
} catch ( error ) {
103115
sessionRecorder = undefined;
104116
if ( ! didDisableSessionPersistence ) {

apps/cli/commands/ai/tests/ai.test.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,15 @@ describe( 'CLI: studio ai sessions command', () => {
184184
return parser;
185185
}
186186

187-
it( 'records sessions by default when running studio ai', async () => {
187+
it( 'does not record an empty session when running studio ai and exiting immediately', async () => {
188+
await buildParser().parseAsync( [ 'ai' ] );
189+
190+
expect( ( AiSessionRecorder as typeof AiSessionRecorder ).create ).not.toHaveBeenCalled();
191+
} );
192+
193+
it( 'records sessions by default once a prompt is submitted', async () => {
194+
waitForInputMock.mockResolvedValueOnce( 'Hello' ).mockResolvedValueOnce( '/exit' );
195+
188196
await buildParser().parseAsync( [ 'ai' ] );
189197

190198
expect( ( AiSessionRecorder as typeof AiSessionRecorder ).create ).toHaveBeenCalledTimes( 1 );
@@ -231,12 +239,7 @@ describe( 'CLI: studio ai sessions command', () => {
231239
await buildParser().parseAsync( [ 'ai', 'sessions', 'resume', 'latest' ] );
232240

233241
expect( loadAiSession ).toHaveBeenCalledWith( 'session-latest' );
234-
expect( ( AiSessionRecorder as typeof AiSessionRecorder ).open ).toHaveBeenCalledWith(
235-
expect.objectContaining( {
236-
sessionId: 'session-latest',
237-
filePath: '/tmp/session-latest.jsonl',
238-
} )
239-
);
242+
expect( ( AiSessionRecorder as typeof AiSessionRecorder ).open ).not.toHaveBeenCalled();
240243
expect( process.exit ).toHaveBeenCalledWith( 0 );
241244
} );
242245

@@ -376,6 +379,12 @@ describe( 'CLI: studio ai sessions command', () => {
376379
await buildParser().parseAsync( [ 'ai', 'sessions', 'resume', 'latest' ] );
377380

378381
expect( resolveAiEnvironment ).toHaveBeenCalledWith( 'anthropic-api-key' );
382+
expect( ( AiSessionRecorder as typeof AiSessionRecorder ).open ).toHaveBeenCalledWith(
383+
expect.objectContaining( {
384+
sessionId: 'session-latest',
385+
filePath: '/tmp/session-latest.jsonl',
386+
} )
387+
);
379388
expect( startAiAgent ).toHaveBeenCalledWith(
380389
expect.objectContaining( {
381390
model: 'claude-opus-4-6',

0 commit comments

Comments
 (0)