@@ -1260,35 +1260,37 @@ function workflowFolderRelativePath(rawPath: string): string {
12601260}
12611261
12621262/**
1263- * Resolve a workflow- folder VFS path (e.g. `workflows/Marketing/Q3 Campaigns`)
1264- * to its folderId by inverting the same {@link buildVfsFolderPathMap} the VFS
1265- * uses to serve folder paths, so a path the agent sees via glob round-trips to
1266- * the right id. Returns null for the workspace root or an unknown path .
1263+ * Load a lookup from each folder's canonical encoded VFS path to its id by
1264+ * inverting the same {@link buildVfsFolderPathMap} the VFS uses to serve folder
1265+ * paths, so a path the agent sees via glob round-trips to the right id. Fetched
1266+ * once per manage_folder call and reused across target + parent resolution .
12671267 */
1268- async function resolveWorkflowFolderIdByPath (
1269- workspaceId : string ,
1270- rawPath : string
1271- ) : Promise < string | null > {
1268+ async function loadFolderPathToIdMap ( workspaceId : string ) : Promise < Map < string , string > > {
1269+ const byPath = new Map < string , string > ( )
1270+ for ( const [ folderId , encodedPath ] of buildVfsFolderPathMap (
1271+ await listFolders ( workspaceId )
1272+ ) . entries ( ) ) {
1273+ byPath . set ( encodedPath , folderId )
1274+ }
1275+ return byPath
1276+ }
1277+
1278+ function lookupFolderIdByPath ( rawPath : string , byPath : Map < string , string > ) : string | null {
12721279 const relative = workflowFolderRelativePath ( rawPath )
12731280 if ( ! relative ) return null
1274- const canonical = encodeVfsPathSegments ( decodeVfsPathSegments ( relative ) )
1275- const folders = await listFolders ( workspaceId )
1276- for ( const [ folderId , encodedPath ] of buildVfsFolderPathMap ( folders ) . entries ( ) ) {
1277- if ( encodedPath === canonical ) return folderId
1278- }
1279- return null
1281+ return byPath . get ( encodeVfsPathSegments ( decodeVfsPathSegments ( relative ) ) ) ?? null
12801282}
12811283
12821284/** Resolve the folder a manage_folder op targets, preferring folderId over path. */
12831285async function resolveManageFolderTarget (
1284- workspaceId : string ,
1285- params : ManageFolderParams
1286+ params : ManageFolderParams ,
1287+ getFolderPaths : ( ) => Promise < Map < string , string > >
12861288) : Promise < { folderId : string } | { error : string } > {
12871289 const directId = typeof params . folderId === 'string' ? params . folderId . trim ( ) : ''
12881290 if ( directId ) return { folderId : directId }
12891291 const path = typeof params . path === 'string' ? params . path . trim ( ) : ''
12901292 if ( ! path ) return { error : 'Provide the folder path (e.g. "workflows/Marketing") or folderId.' }
1291- const folderId = await resolveWorkflowFolderIdByPath ( workspaceId , path )
1293+ const folderId = lookupFolderIdByPath ( path , await getFolderPaths ( ) )
12921294 if ( ! folderId ) return { error : `Folder not found at ${ path } ` }
12931295 return { folderId }
12941296}
@@ -1299,15 +1301,15 @@ async function resolveManageFolderTarget(
12991301 * (parentId null).
13001302 */
13011303async function resolveManageFolderParent (
1302- workspaceId : string ,
1303- params : ManageFolderParams
1304+ params : ManageFolderParams ,
1305+ getFolderPaths : ( ) => Promise < Map < string , string > >
13041306) : Promise < { parentId : string | null } | { error : string } > {
13051307 const directId = typeof params . parentId === 'string' ? params . parentId . trim ( ) : ''
13061308 if ( directId ) return { parentId : directId }
13071309 if ( params . parentId === null ) return { parentId : null }
13081310 const dest = typeof params . destinationPath === 'string' ? params . destinationPath . trim ( ) : ''
13091311 if ( ! dest || ! workflowFolderRelativePath ( dest ) ) return { parentId : null }
1310- const parentId = await resolveWorkflowFolderIdByPath ( workspaceId , dest )
1312+ const parentId = lookupFolderIdByPath ( dest , await getFolderPaths ( ) )
13111313 if ( ! parentId ) return { error : `Destination folder not found at ${ dest } ` }
13121314 return { parentId }
13131315}
@@ -1326,6 +1328,12 @@ export async function executeManageFolder(
13261328 const operation = typeof params ?. operation === 'string' ? params . operation . trim ( ) : ''
13271329 const workspaceId = context . workspaceId || ( await getDefaultWorkspaceId ( context . userId ) )
13281330
1331+ // Fetch the workspace folder list at most once, lazily — only when a path
1332+ // (vs an explicit id) actually needs resolving, and shared across the
1333+ // target + parent lookups a single move/create performs.
1334+ let folderPathsPromise : Promise < Map < string , string > > | undefined
1335+ const getFolderPaths = ( ) => ( folderPathsPromise ??= loadFolderPathToIdMap ( workspaceId ) )
1336+
13291337 switch ( operation ) {
13301338 case 'create' : {
13311339 let name = typeof params . name === 'string' ? params . name . trim ( ) : ''
@@ -1339,17 +1347,17 @@ export async function executeManageFolder(
13391347 name = segments [ segments . length - 1 ]
13401348 const parentSegments = segments . slice ( 0 , - 1 )
13411349 if ( parentSegments . length > 0 ) {
1342- const resolved = await resolveWorkflowFolderIdByPath (
1343- workspaceId ,
1344- encodeVfsPathSegments ( parentSegments )
1350+ const resolved = lookupFolderIdByPath (
1351+ encodeVfsPathSegments ( parentSegments ) ,
1352+ await getFolderPaths ( )
13451353 )
13461354 if ( ! resolved ) {
13471355 return { success : false , error : `Parent folder not found for ${ path } ` }
13481356 }
13491357 parentId = resolved
13501358 }
13511359 } else {
1352- const parent = await resolveManageFolderParent ( workspaceId , params )
1360+ const parent = await resolveManageFolderParent ( params , getFolderPaths )
13531361 if ( 'error' in parent ) return { success : false , error : parent . error }
13541362 parentId = parent . parentId
13551363 }
@@ -1359,19 +1367,19 @@ export async function executeManageFolder(
13591367 case 'rename' : {
13601368 const name = typeof params . name === 'string' ? params . name . trim ( ) : ''
13611369 if ( ! name ) return { success : false , error : 'rename requires a new name' }
1362- const target = await resolveManageFolderTarget ( workspaceId , params )
1370+ const target = await resolveManageFolderTarget ( params , getFolderPaths )
13631371 if ( 'error' in target ) return { success : false , error : target . error }
13641372 return executeRenameFolder ( { folderId : target . folderId , name } , context )
13651373 }
13661374 case 'move' : {
1367- const target = await resolveManageFolderTarget ( workspaceId , params )
1375+ const target = await resolveManageFolderTarget ( params , getFolderPaths )
13681376 if ( 'error' in target ) return { success : false , error : target . error }
1369- const parent = await resolveManageFolderParent ( workspaceId , params )
1377+ const parent = await resolveManageFolderParent ( params , getFolderPaths )
13701378 if ( 'error' in parent ) return { success : false , error : parent . error }
13711379 return executeMoveFolder ( { folderId : target . folderId , parentId : parent . parentId } , context )
13721380 }
13731381 case 'delete' : {
1374- const target = await resolveManageFolderTarget ( workspaceId , params )
1382+ const target = await resolveManageFolderTarget ( params , getFolderPaths )
13751383 if ( 'error' in target ) return { success : false , error : target . error }
13761384 return executeDeleteFolder ( { folderIds : [ target . folderId ] } , context )
13771385 }
0 commit comments