@@ -68,6 +68,13 @@ vi.mock('./config/settings.js', async (importOriginal) => {
6868 } ;
6969} ) ;
7070
71+ vi . mock ( './ui/utils/ConsolePatcher.js' , ( ) => ( {
72+ ConsolePatcher : vi . fn ( ) . mockImplementation ( ( ) => ( {
73+ patch : vi . fn ( ) ,
74+ cleanup : vi . fn ( ) ,
75+ } ) ) ,
76+ } ) ) ;
77+
7178vi . mock ( './config/config.js' , ( ) => ( {
7279 loadCliConfig : vi . fn ( ) . mockResolvedValue ( {
7380 getSandbox : vi . fn ( ( ) => false ) ,
@@ -150,6 +157,10 @@ vi.mock('./utils/cleanup.js', async (importOriginal) => {
150157 } ;
151158} ) ;
152159
160+ vi . mock ( './acp/acpClient.js' , ( ) => ( {
161+ runAcpClient : vi . fn ( ) . mockResolvedValue ( undefined ) ,
162+ } ) ) ;
163+
153164vi . mock ( './zed-integration/zedIntegration.js' , ( ) => ( {
154165 runZedIntegration : vi . fn ( ) . mockResolvedValue ( undefined ) ,
155166} ) ) ;
@@ -296,6 +307,120 @@ describe('gemini.tsx main function cleanup', () => {
296307 ) ;
297308 } ) ;
298309
310+ it ( 'should not register ConsolePatcher cleanup in ACP mode' , async ( ) => {
311+ const { registerCleanup } = await import ( './utils/cleanup.js' ) ;
312+ const { ConsolePatcher } = await import ( './ui/utils/ConsolePatcher.js' ) ;
313+ const { loadCliConfig, parseArguments } = await import (
314+ './config/config.js'
315+ ) ;
316+ const { loadSettings } = await import ( './config/settings.js' ) ;
317+
318+ vi . mocked ( parseArguments ) . mockResolvedValue ( {
319+ acp : true ,
320+ startupMessages : [ ] ,
321+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
322+ } as any ) ;
323+
324+ vi . mocked ( loadSettings ) . mockReturnValue ( {
325+ merged : {
326+ tools : { allowed : [ ] , exclude : [ ] } ,
327+ advanced : { dnsResolutionOrder : 'ipv4first' } ,
328+ security : { auth : { selectedType : 'google' } } ,
329+ ui : { theme : 'default' } ,
330+ } ,
331+ workspace : { settings : { } } ,
332+ errors : [ ] ,
333+ subscribe : vi . fn ( ) ,
334+ getSnapshot : vi . fn ( ) ,
335+ setValue : vi . fn ( ) ,
336+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
337+ } as any ) ;
338+
339+ vi . mocked ( loadCliConfig ) . mockResolvedValue (
340+ buildMockConfig ( {
341+ getAcpMode : ( ) => true ,
342+ } ) ,
343+ ) ;
344+
345+ let capturedCleanup : ( ) => void ;
346+ vi . mocked ( ConsolePatcher ) . mockImplementation ( ( ) => {
347+ const instance = {
348+ patch : vi . fn ( ) ,
349+ cleanup : vi . fn ( ) ,
350+ } ;
351+ capturedCleanup = instance . cleanup ;
352+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
353+ return instance as any ;
354+ } ) ;
355+
356+ await main ( ) ;
357+
358+ const registeredFunctions = vi
359+ . mocked ( registerCleanup )
360+ . mock . calls . map ( ( call ) => call [ 0 ] ) ;
361+ expect ( registeredFunctions ) . not . toContain ( capturedCleanup ! ) ;
362+ } ) ;
363+
364+ it ( 'should register ConsolePatcher cleanup in non-ACP mode' , async ( ) => {
365+ const { registerCleanup } = await import ( './utils/cleanup.js' ) ;
366+ const { ConsolePatcher } = await import ( './ui/utils/ConsolePatcher.js' ) ;
367+ const { loadCliConfig, parseArguments } = await import (
368+ './config/config.js'
369+ ) ;
370+ const { loadSettings } = await import ( './config/settings.js' ) ;
371+
372+ vi . mocked ( parseArguments ) . mockResolvedValue ( {
373+ acp : false ,
374+ query : 'test' ,
375+ startupMessages : [ ] ,
376+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
377+ } as any ) ;
378+
379+ vi . mocked ( loadSettings ) . mockReturnValue ( {
380+ merged : {
381+ tools : { allowed : [ ] , exclude : [ ] } ,
382+ advanced : { dnsResolutionOrder : 'ipv4first' } ,
383+ security : { auth : { selectedType : 'google' } } ,
384+ ui : { theme : 'default' } ,
385+ } ,
386+ workspace : { settings : { } } ,
387+ errors : [ ] ,
388+ subscribe : vi . fn ( ) ,
389+ getSnapshot : vi . fn ( ) ,
390+ setValue : vi . fn ( ) ,
391+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
392+ } as any ) ;
393+
394+ vi . mocked ( loadCliConfig ) . mockResolvedValue (
395+ buildMockConfig ( {
396+ getAcpMode : ( ) => false ,
397+ getQuestion : ( ) => 'test' ,
398+ } ) ,
399+ ) ;
400+
401+ let capturedCleanup : ( ) => void ;
402+ vi . mocked ( ConsolePatcher ) . mockImplementation ( ( ) => {
403+ const instance = {
404+ patch : vi . fn ( ) ,
405+ cleanup : vi . fn ( ) ,
406+ } ;
407+ capturedCleanup = instance . cleanup ;
408+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
409+ return instance as any ;
410+ } ) ;
411+
412+ try {
413+ await main ( ) ;
414+ } catch {
415+ // Ignore errors from incomplete mocks in full main() execution
416+ }
417+
418+ const registeredFunctions = vi
419+ . mocked ( registerCleanup )
420+ . mock . calls . map ( ( call ) => call [ 0 ] ) ;
421+ expect ( registeredFunctions ) . toContain ( capturedCleanup ! ) ;
422+ } ) ;
423+
299424 function buildMockConfig ( overrides : Partial < Config > = { } ) : Config {
300425 return {
301426 isInteractive : vi . fn ( ( ) => false ) ,
@@ -319,7 +444,6 @@ describe('gemini.tsx main function cleanup', () => {
319444 getListExtensions : vi . fn ( ( ) => false ) ,
320445 getListSessions : vi . fn ( ( ) => false ) ,
321446 getDeleteSession : vi . fn ( ( ) => undefined ) ,
322- getToolRegistry : vi . fn ( ) ,
323447 getExtensions : vi . fn ( ( ) => [ ] ) ,
324448 getModel : vi . fn ( ( ) => 'gemini-pro' ) ,
325449 getEmbeddingModel : vi . fn ( ( ) => 'embedding-001' ) ,
0 commit comments