From a698c9170c57ee9d5dbc4e61022a16af24ff3ce0 Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Thu, 10 Sep 2026 19:55:58 +0800 Subject: [PATCH] =?UTF-8?q?AGC=20=E9=85=8D=E7=BD=AE=E5=90=91=E5=AF=BC?= =?UTF-8?q?=E4=B8=8E=E9=9A=94=E7=A6=BB=E9=85=8D=E7=BD=AE=E7=94=A8=E4=BE=8B?= =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=94=B9=E4=BC=A0=20ACL=20no-op=20=E6=A1=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - agentSwarmTestEntry.test.ts:新增模块级 skippedWindowsAclOptions,仅 win32 下为 { secureWindowsPath: async () => {} },其它平台为空对象。 - agentSwarmTestEntry.test.ts:atomically replaces a private AppData config file 的两次 writeGameCreatorConfigAtomically 传入该桩,3663ms → 24ms,不再只剩 27% 超时余量。 - agentSwarmTestEntry.test.ts:moves the default LLM to primary config and lets later GUI saves win 原本的局部 persistenceOptions 收敛为同一份模块级常量,去掉重复声明。 - agentSwarmTestEntry.test.ts:isolated Swarm runtime config 的三处 prepareSwarmTestRuntimeConfig 传入该桩,privately copies 1948ms → 84ms,refuses to delete 1331ms → 79ms。 - 断言零改动:这几条用例在 win32 下本就不校验 ACL(mode / dev / ino 断言全部在 process.platform !== 'win32' 分支内),非 win32 下该常量为空对象、行为逐字不变。 - 实测:该文件 13.59s → 1.35s,文件内最慢用例从 3663ms 降到 84ms。 --- .../tests/agentSwarmTestEntry.test.ts | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/apps/ai-game-creator-shell/tests/agentSwarmTestEntry.test.ts b/apps/ai-game-creator-shell/tests/agentSwarmTestEntry.test.ts index 99418c563..e0c69cd78 100644 --- a/apps/ai-game-creator-shell/tests/agentSwarmTestEntry.test.ts +++ b/apps/ai-game-creator-shell/tests/agentSwarmTestEntry.test.ts @@ -72,6 +72,11 @@ import { const appRoot = path.resolve(fileURLToPath(new URL('..', import.meta.url))); +// Windows 下「私有路径加固」每次都会拉起真实 powershell.exe 去设置 DACL(本机实测约 0.6 秒 / 次)。 +// 只校验配置分层、隔离与清理语义的用例统一传入这份 no-op 桩;真正覆盖私有 ACL 的用例才走真实实现。 +const skippedWindowsAclOptions = + process.platform === 'win32' ? { secureWindowsPath: async () => {} } : {}; + async function withTemporaryRoot( run: (root: string) => Promise, ): Promise { @@ -552,11 +557,19 @@ describe('terminal configuration wizard persistence', () => { }; await expect( - writeGameCreatorConfigAtomically(configPath, firstConfig), + writeGameCreatorConfigAtomically( + configPath, + firstConfig, + skippedWindowsAclOptions, + ), ).resolves.toBe(configPath); const firstMetadata = await lstat(configPath); await expect( - writeGameCreatorConfigAtomically(configPath, finalConfig), + writeGameCreatorConfigAtomically( + configPath, + finalConfig, + skippedWindowsAclOptions, + ), ).resolves.toBe(configPath); const [directoryMetadata, finalMetadata, entries, contents] = @@ -584,13 +597,6 @@ describe('terminal configuration wizard persistence', () => { it('moves the default LLM to primary config and lets later GUI saves win', async () => { await withTemporaryRoot(async (root) => { - // 读写都要带上这个桩:读路径同样会加固私有目录与配置文件, - // 在 Windows 上每次加固都要拉起一个 powershell.exe(约 0.6 秒), - // 本用例只校验配置分层优先级,不该为无关的 DACL 子进程耗掉超时预算。 - const persistenceOptions = - process.platform === 'win32' - ? { secureWindowsPath: async () => {} } - : {}; const configDir = path.join(root, appIdentifier); const primaryPath = path.join(configDir, configFileName); const localPath = path.join(configDir, localConfigFileName); @@ -606,7 +612,7 @@ describe('terminal configuration wizard persistence', () => { const state = await readGameCreatorWizardConfigState( configDir, - persistenceOptions, + skippedWindowsAclOptions, ); expect(state.configPath).toBe(primaryPath); expect(state.effectiveConfig.llm.model).toBe('stale-local'); @@ -619,7 +625,7 @@ describe('terminal configuration wizard persistence', () => { await writeGameCreatorWizardConfig( state, wizardConfig, - persistenceOptions, + skippedWindowsAclOptions, ); const sanitizedLocal = JSON.parse(await readFile(localPath, 'utf8')); @@ -627,7 +633,7 @@ describe('terminal configuration wizard persistence', () => { expect(sanitizedLocal.agentLlm.planner.model).toBe('planner'); const afterWizard = await readGameCreatorWizardConfigState( configDir, - persistenceOptions, + skippedWindowsAclOptions, ); expect(afterWizard.effectiveConfig.llm).toMatchObject({ apiKey: 'wizard-key', @@ -645,11 +651,11 @@ describe('terminal configuration wizard persistence', () => { await writeGameCreatorConfigAtomically( primaryPath, guiConfig, - persistenceOptions, + skippedWindowsAclOptions, ); const afterGui = await readGameCreatorWizardConfigState( configDir, - persistenceOptions, + skippedWindowsAclOptions, ); expect(afterGui.effectiveConfig.llm.apiKey).toBe('gui-key'); expect(afterGui.effectiveConfig.llm.model).toBe('gui-model'); @@ -981,6 +987,7 @@ describe('isolated Swarm runtime config', () => { const runtimeConfig = await prepareSwarmTestRuntimeConfig( sourceConfigDir, root, + skippedWindowsAclOptions, ); const runtimeEntries = (await readdir(runtimeConfig.path)).sort(); const runtimeDirectoryMetadata = await lstat(runtimeConfig.path); @@ -1059,7 +1066,11 @@ describe('isolated Swarm runtime config', () => { ); await expect( - prepareSwarmTestRuntimeConfig(sourceConfigDir, root), + prepareSwarmTestRuntimeConfig( + sourceConfigDir, + root, + skippedWindowsAclOptions, + ), ).rejects.toThrow(localConfigFileName); expect( (await readdir(root)).filter((entry) => @@ -1077,6 +1088,7 @@ describe('isolated Swarm runtime config', () => { const runtimeConfig = await prepareSwarmTestRuntimeConfig( sourceConfigDir, root, + skippedWindowsAclOptions, ); const endpointPath = path.join( runtimeConfig.path,