From 90ae7fdb8317dffebf9ec5d0ad02e625cebdbb1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=B6=E5=85=AC?= Date: Wed, 8 Jul 2026 00:46:01 +0800 Subject: [PATCH] fix(cli): clarify memory folder opener behavior --- .../cli/src/ui/components/MemoryDialog.test.tsx | 16 ++++++++++++---- packages/cli/src/ui/components/MemoryDialog.tsx | 3 +++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/ui/components/MemoryDialog.test.tsx b/packages/cli/src/ui/components/MemoryDialog.test.tsx index ea4fe65df6..2926d94c74 100644 --- a/packages/cli/src/ui/components/MemoryDialog.test.tsx +++ b/packages/cli/src/ui/components/MemoryDialog.test.tsx @@ -81,6 +81,10 @@ const mockedFs = vi.mocked(fs); const originalPlatform = process.platform; type MockSpawnChild = EventEmitter & { unref: ReturnType }; +const folderOpenCommandByPlatform: Partial> = { + darwin: 'open', + win32: 'explorer', +}; function createMockSpawnChild( event: 'spawn' | 'error' = 'spawn', @@ -101,6 +105,10 @@ function stubPlatform(platform: NodeJS.Platform): void { }); } +function expectedFolderOpenCommand(platform = process.platform): string { + return folderOpenCommandByPlatform[platform] ?? 'xdg-open'; +} + describe('MemoryDialog', () => { beforeEach(() => { vi.clearAllMocks(); @@ -172,7 +180,7 @@ describe('MemoryDialog', () => { }); expect(mockedSpawn).toHaveBeenCalledWith( - expect.any(String), + expectedFolderOpenCommand(), [path.join(os.homedir(), '.qwen-memory-test', 'memories')], expect.objectContaining({ detached: true, stdio: 'ignore' }), ); @@ -208,7 +216,7 @@ describe('MemoryDialog', () => { }); expect(mockedSpawn).toHaveBeenCalledWith( - expect.any(String), + expectedFolderOpenCommand(platform), [path.join(os.homedir(), '.qwen-memory-test', 'memories')], expect.objectContaining({ detached: true, stdio: 'ignore' }), ); @@ -238,7 +246,7 @@ describe('MemoryDialog', () => { }); expect(mockedSpawn).toHaveBeenCalledWith( - expect.any(String), + expectedFolderOpenCommand(), [getAutoMemoryRoot('/tmp/project')], expect.objectContaining({ detached: true, stdio: 'ignore' }), ); @@ -258,7 +266,7 @@ describe('MemoryDialog', () => { }); expect(mockedSpawn).toHaveBeenCalledWith( - expect.any(String), + expectedFolderOpenCommand(), [getAutoMemoryRoot('/tmp/project')], expect.objectContaining({ detached: true, stdio: 'ignore' }), ); diff --git a/packages/cli/src/ui/components/MemoryDialog.tsx b/packages/cli/src/ui/components/MemoryDialog.tsx index 81992a53f3..740d536fb5 100644 --- a/packages/cli/src/ui/components/MemoryDialog.tsx +++ b/packages/cli/src/ui/components/MemoryDialog.tsx @@ -84,6 +84,9 @@ async function openFolderPath(folderPath: string): Promise { await new Promise((resolve, reject) => { child.once('error', reject); + // Exit codes are intentionally not observed: the folder opener is + // fire-and-forget, and waiting for exit can block until the file manager + // closes. child.once('spawn', () => resolve()); }); }