From 0396847ae390a9455bc1ced07780d5d77761190c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=82CHES?= Date: Tue, 17 Mar 2026 18:28:42 -0600 Subject: [PATCH] perf: reduce makeTreeWritable calls from 6 to 2 on startup (#1023) Consolidate six per-subdirectory makeTreeWritable calls (pre+post copy for extensions, agents, and skills) into two calls on the parent agentDir: one before all copies to unlock existing Nix-store read-only files, and one after to ensure newly copied files are writable for subsequent runs. Eliminates ~4 redundant recursive stat+chmod walks, saving 100-300ms on every CLI launch that triggers resource sync. Co-authored-by: Claude Opus 4.6 (1M context) --- src/resource-loader.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/resource-loader.ts b/src/resource-loader.ts index b9b95ce65..65dcdebc2 100644 --- a/src/resource-loader.ts +++ b/src/resource-loader.ts @@ -123,11 +123,14 @@ function makeTreeWritable(dirPath: string): void { export function initResources(agentDir: string): void { mkdirSync(agentDir, { recursive: true }) + // Unlock all existing destination files in a single recursive walk so that + // rmSync and cpSync can overwrite read-only copies from the Nix store. + makeTreeWritable(agentDir) + // Sync extensions — clean bundled subdirs first to remove stale leftover files, // then overwrite so updates land on next launch. Only bundled subdirs are removed; // user-created extension directories are preserved. const destExtensions = join(agentDir, 'extensions') - makeTreeWritable(destExtensions) for (const entry of readdirSync(bundledExtensionsDir, { withFileTypes: true })) { if (entry.isDirectory()) { const target = join(destExtensions, entry.name) @@ -135,13 +138,11 @@ export function initResources(agentDir: string): void { } } cpSync(bundledExtensionsDir, destExtensions, { recursive: true, force: true }) - makeTreeWritable(destExtensions) // Sync agents const destAgents = join(agentDir, 'agents') const srcAgents = join(resourcesDir, 'agents') if (existsSync(srcAgents)) { - makeTreeWritable(destAgents) for (const entry of readdirSync(srcAgents, { withFileTypes: true })) { if (entry.isDirectory()) { const target = join(destAgents, entry.name) @@ -149,14 +150,12 @@ export function initResources(agentDir: string): void { } } cpSync(srcAgents, destAgents, { recursive: true, force: true }) - makeTreeWritable(destAgents) } // Sync skills const destSkills = join(agentDir, 'skills') const srcSkills = join(resourcesDir, 'skills') if (existsSync(srcSkills)) { - makeTreeWritable(destSkills) for (const entry of readdirSync(srcSkills, { withFileTypes: true })) { if (entry.isDirectory()) { const target = join(destSkills, entry.name) @@ -164,9 +163,12 @@ export function initResources(agentDir: string): void { } } cpSync(srcSkills, destSkills, { recursive: true, force: true }) - makeTreeWritable(destSkills) } + // Ensure all newly copied files are owner-writable so the next run can + // overwrite them (covers extensions, agents, and skills in one walk). + makeTreeWritable(agentDir) + writeManagedResourceManifest(agentDir) }