From cb6987b0a2b08811c6e23418ab3133916fdf9bba Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Fri, 24 Apr 2026 01:33:07 +0700 Subject: [PATCH] chore(lint): parallelize safe await-in-loop in server --- .../server/src/server/agent/agent-storage.ts | 23 +++++--- packages/server/src/server/bootstrap.ts | 16 ++--- packages/server/src/server/editor-targets.ts | 17 +++--- .../server/paseo-worktree-archive-service.ts | 54 +++++++++-------- .../server/src/server/push/push-service.ts | 4 +- .../src/server/script-health-monitor.ts | 16 ++--- .../workspace-reconciliation-service.ts | 58 ++++++++++--------- .../server/workspace-registry-bootstrap.ts | 19 +++--- .../src/server/workspace-registry-model.ts | 11 +++- packages/server/src/tasks/task-store.ts | 13 +---- .../server/src/utils/directory-suggestions.ts | 44 +++++++------- 11 files changed, 147 insertions(+), 128 deletions(-) diff --git a/packages/server/src/server/agent/agent-storage.ts b/packages/server/src/server/agent/agent-storage.ts index 95ba4325d..731394128 100644 --- a/packages/server/src/server/agent/agent-storage.ts +++ b/packages/server/src/server/agent/agent-storage.ts @@ -163,16 +163,21 @@ export class AgentStorage { this.beginDelete(agentId); await (this.pendingWrites.get(agentId) ?? Promise.resolve()); const paths = Array.from(this.pathsById.get(agentId) ?? []); - for (const filePath of paths) { - try { - await fs.unlink(filePath); - } catch (error) { - const code = (error as NodeJS.ErrnoException).code; - if (code && code !== "ENOENT") { - this.logger.warn({ err: error, agentId, filePath }, "Failed to remove agent record file"); + await Promise.all( + paths.map(async (filePath) => { + try { + await fs.unlink(filePath); + } catch (error) { + const code = (error as NodeJS.ErrnoException).code; + if (code && code !== "ENOENT") { + this.logger.warn( + { err: error, agentId, filePath }, + "Failed to remove agent record file", + ); + } } - } - } + }), + ); this.cache.delete(agentId); this.pathById.delete(agentId); diff --git a/packages/server/src/server/bootstrap.ts b/packages/server/src/server/bootstrap.ts index 20901df71..8ee1e5aa5 100644 --- a/packages/server/src/server/bootstrap.ts +++ b/packages/server/src/server/bootstrap.ts @@ -858,11 +858,13 @@ export async function createPaseoDaemon( async function closeAllAgents(logger: Logger, agentManager: AgentManager): Promise { const agents = agentManager.listAgents(); - for (const agent of agents) { - try { - await agentManager.closeAgent(agent.id); - } catch (err) { - logger.error({ err, agentId: agent.id }, "Failed to close agent"); - } - } + await Promise.all( + agents.map(async (agent) => { + try { + await agentManager.closeAgent(agent.id); + } catch (err) { + logger.error({ err, agentId: agent.id }, "Failed to close agent"); + } + }), + ); } diff --git a/packages/server/src/server/editor-targets.ts b/packages/server/src/server/editor-targets.ts index 5774fc35e..d7d6d217f 100644 --- a/packages/server/src/server/editor-targets.ts +++ b/packages/server/src/server/editor-targets.ts @@ -72,15 +72,16 @@ export async function listAvailableEditorTargets( const platform = dependencies.platform ?? process.platform; const findExecutableFn = dependencies.findExecutable ?? findExecutable; + const supportedTargets = EDITOR_TARGETS.filter((target) => + isTargetSupportedOnPlatform(target, platform), + ); + const executables = await Promise.all( + supportedTargets.map((target) => findExecutableFn(target.command)), + ); const results: EditorTargetDescriptorPayload[] = []; - for (const target of EDITOR_TARGETS) { - if (!isTargetSupportedOnPlatform(target, platform)) { - continue; - } - const executable = await findExecutableFn(target.command); - if (!executable) { - continue; - } + for (let i = 0; i < supportedTargets.length; i += 1) { + if (!executables[i]) continue; + const target = supportedTargets[i]!; results.push({ id: target.id, label: target.label, diff --git a/packages/server/src/server/paseo-worktree-archive-service.ts b/packages/server/src/server/paseo-worktree-archive-service.ts index efe1590b2..9001c365f 100644 --- a/packages/server/src/server/paseo-worktree-archive-service.ts +++ b/packages/server/src/server/paseo-worktree-archive-service.ts @@ -143,16 +143,18 @@ export async function archivePaseoWorktree( dependencies.github.invalidate({ cwd }); } - for (const workspaceId of affectedWorkspaceIds) { - try { - await dependencies.archiveWorkspaceRecord(workspaceId); - } catch (error) { - dependencies.sessionLogger?.warn( - { err: error, workspaceId }, - "Failed to archive workspace record; worktree FS already removed", - ); - } - } + await Promise.all( + Array.from(affectedWorkspaceIds).map(async (workspaceId) => { + try { + await dependencies.archiveWorkspaceRecord(workspaceId); + } catch (error) { + dependencies.sessionLogger?.warn( + { err: error, workspaceId }, + "Failed to archive workspace record; worktree FS already removed", + ); + } + }), + ); for (const agentId of removedAgents) { dependencies.emit({ @@ -179,21 +181,25 @@ export async function killTerminalsUnderPath( } const terminalIds: string[] = []; - const terminalDirectories = [...terminalManager.listDirectories()]; - for (const terminalCwd of terminalDirectories) { - if (!dependencies.isPathWithinRoot(rootPath, terminalCwd)) { - continue; - } - try { - const terminals = await terminalManager.getTerminals(terminalCwd); - for (const terminal of terminals) { - terminalIds.push(terminal.id); + const relevantCwds = [...terminalManager.listDirectories()].filter((terminalCwd) => + dependencies.isPathWithinRoot(rootPath, terminalCwd), + ); + const terminalLists = await Promise.all( + relevantCwds.map(async (terminalCwd) => { + try { + return await terminalManager.getTerminals(terminalCwd); + } catch (error) { + dependencies.sessionLogger.warn( + { err: error, cwd: terminalCwd }, + "Failed to enumerate worktree terminals during archive", + ); + return []; } - } catch (error) { - dependencies.sessionLogger.warn( - { err: error, cwd: terminalCwd }, - "Failed to enumerate worktree terminals during archive", - ); + }), + ); + for (const terminals of terminalLists) { + for (const terminal of terminals) { + terminalIds.push(terminal.id); } } diff --git a/packages/server/src/server/push/push-service.ts b/packages/server/src/server/push/push-service.ts index b78f193d1..8a792862a 100644 --- a/packages/server/src/server/push/push-service.ts +++ b/packages/server/src/server/push/push-service.ts @@ -57,9 +57,7 @@ export class PushService { batches.push(messages.slice(i, i + MAX_BATCH_SIZE)); } - for (const batch of batches) { - await this.sendBatch(batch); - } + await Promise.all(batches.map((batch) => this.sendBatch(batch))); } private async sendBatch(messages: ExpoPushMessage[]): Promise { diff --git a/packages/server/src/server/script-health-monitor.ts b/packages/server/src/server/script-health-monitor.ts index 738e61303..6da0f7cfd 100644 --- a/packages/server/src/server/script-health-monitor.ts +++ b/packages/server/src/server/script-health-monitor.ts @@ -98,13 +98,15 @@ export class ScriptHealthMonitor { const changedWorkspaceIds = new Set(); const now = Date.now(); - for (const route of routes) { - const state = this.getOrCreateState(route, now); - if (now - state.registeredAt < this.graceMs) { - continue; - } - - const isHealthy = await this.probeRoute(route.port); + const probeTargets = routes + .map((route) => ({ route, state: this.getOrCreateState(route, now) })) + .filter(({ state }) => now - state.registeredAt >= this.graceMs); + const healthResults = await Promise.all( + probeTargets.map(({ route }) => this.probeRoute(route.port)), + ); + for (let i = 0; i < probeTargets.length; i += 1) { + const { route, state } = probeTargets[i]!; + const isHealthy = healthResults[i]!; const previousHealth = state.health; if (isHealthy) { diff --git a/packages/server/src/server/workspace-reconciliation-service.ts b/packages/server/src/server/workspace-reconciliation-service.ts index d4f164aa3..1a3ff1331 100644 --- a/packages/server/src/server/workspace-reconciliation-service.ts +++ b/packages/server/src/server/workspace-reconciliation-service.ts @@ -150,13 +150,18 @@ export class WorkspaceReconciliationService { } // 3. Reconcile git metadata for active projects whose directories still exist - for (const project of activeProjects) { - if (project.archivedAt) continue; + const projectsToReconcile = activeProjects.filter((project) => { + if (project.archivedAt) return false; const siblings = workspacesByProject.get(project.projectId) ?? []; - if (siblings.length === 0) continue; - if (!existsSync(project.rootPath)) continue; - await this.reconcileProject(project, siblings, changes); - } + if (siblings.length === 0) return false; + if (!existsSync(project.rootPath)) return false; + return true; + }); + await Promise.all( + projectsToReconcile.map((project) => + this.reconcileProject(project, workspacesByProject.get(project.projectId) ?? [], changes), + ), + ); if (changes.length > 0 && this.onChanges) { this.onChanges(changes); @@ -208,27 +213,28 @@ export class WorkspaceReconciliationService { }); } - for (const workspace of siblings) { - if (!existsSync(workspace.cwd)) continue; + const existingSiblings = siblings.filter((workspace) => existsSync(workspace.cwd)); + await Promise.all( + existingSiblings.map(async (workspace) => { + const wsDirName = workspace.cwd.split(/[\\/]/).filter(Boolean).at(-1) ?? workspace.cwd; + const wsGit = await this.readWorkspaceGitMetadata(workspace.cwd, wsDirName); - const wsDirName = workspace.cwd.split(/[\\/]/).filter(Boolean).at(-1) ?? workspace.cwd; - const wsGit = await this.readWorkspaceGitMetadata(workspace.cwd, wsDirName); - - if (wsGit.projectKind === "git" && workspace.displayName !== wsGit.workspaceDisplayName) { - const timestamp = new Date().toISOString(); - await this.workspaceRegistry.upsert({ - ...workspace, - displayName: wsGit.workspaceDisplayName, - updatedAt: timestamp, - }); - changes.push({ - kind: "workspace_updated", - workspaceId: workspace.workspaceId, - directory: workspace.cwd, - fields: { displayName: wsGit.workspaceDisplayName }, - }); - } - } + if (wsGit.projectKind === "git" && workspace.displayName !== wsGit.workspaceDisplayName) { + const timestamp = new Date().toISOString(); + await this.workspaceRegistry.upsert({ + ...workspace, + displayName: wsGit.workspaceDisplayName, + updatedAt: timestamp, + }); + changes.push({ + kind: "workspace_updated", + workspaceId: workspace.workspaceId, + directory: workspace.cwd, + fields: { displayName: wsGit.workspaceDisplayName }, + }); + } + }), + ); } private async readWorkspaceGitMetadata(cwd: string, directoryName: string) { diff --git a/packages/server/src/server/workspace-registry-bootstrap.ts b/packages/server/src/server/workspace-registry-bootstrap.ts index 9ed0345ef..f2a39c67f 100644 --- a/packages/server/src/server/workspace-registry-bootstrap.ts +++ b/packages/server/src/server/workspace-registry-bootstrap.ts @@ -77,13 +77,18 @@ export async function bootstrapWorkspaceRegistries(options: { records: StoredAgentRecord[]; } >(); - for (const record of activeRecords) { - const normalizedCwd = normalizeWorkspaceId(record.cwd); - const placement = await buildProjectPlacementForCwd({ - cwd: normalizedCwd, - workspaceGitService: options.workspaceGitService, - }); - const workspaceId = deriveWorkspaceId(normalizedCwd, placement.checkout); + const placements = await Promise.all( + activeRecords.map(async (record) => { + const normalizedCwd = normalizeWorkspaceId(record.cwd); + const placement = await buildProjectPlacementForCwd({ + cwd: normalizedCwd, + workspaceGitService: options.workspaceGitService, + }); + const workspaceId = deriveWorkspaceId(normalizedCwd, placement.checkout); + return { record, placement, workspaceId }; + }), + ); + for (const { record, placement, workspaceId } of placements) { const existing = recordsByWorkspaceId.get(workspaceId) ?? { placement, records: [] }; existing.records.push(record); recordsByWorkspaceId.set(workspaceId, existing); diff --git a/packages/server/src/server/workspace-registry-model.ts b/packages/server/src/server/workspace-registry-model.ts index 5062fdcd9..5cf281c99 100644 --- a/packages/server/src/server/workspace-registry-model.ts +++ b/packages/server/src/server/workspace-registry-model.ts @@ -188,9 +188,14 @@ export async function detectStaleWorkspaces( ): Promise> { const staleWorkspaceIds = new Set(); - for (const workspace of input.activeWorkspaces) { - const dirExists = await input.checkDirectoryExists(workspace.cwd); - if (!dirExists) { + const existenceChecks = await Promise.all( + input.activeWorkspaces.map(async (workspace) => ({ + workspace, + exists: await input.checkDirectoryExists(workspace.cwd), + })), + ); + for (const { workspace, exists } of existenceChecks) { + if (!exists) { staleWorkspaceIds.add(workspace.workspaceId); } } diff --git a/packages/server/src/tasks/task-store.ts b/packages/server/src/tasks/task-store.ts index 0bafe172d..c94aab27f 100644 --- a/packages/server/src/tasks/task-store.ts +++ b/packages/server/src/tasks/task-store.ts @@ -181,16 +181,9 @@ export class FileTaskStore implements TaskStore { await this.ensureDir(); try { const files = await readdir(this.dir); - const tasks: Task[] = []; - for (const file of files) { - if (file.endsWith(".md")) { - const id = file.slice(0, -3); - const task = await this.readTask(id); - if (task) { - tasks.push(task); - } - } - } + const ids = files.filter((file) => file.endsWith(".md")).map((file) => file.slice(0, -3)); + const loaded = await Promise.all(ids.map((id) => this.readTask(id))); + const tasks: Task[] = loaded.filter((task): task is Task => task !== null); // Sort by created date (oldest first) for consistent ordering return tasks.sort((a, b) => a.created.localeCompare(b.created)); } catch (error) { diff --git a/packages/server/src/utils/directory-suggestions.ts b/packages/server/src/utils/directory-suggestions.ts index b27aac9df..7614843e6 100644 --- a/packages/server/src/utils/directory-suggestions.ts +++ b/packages/server/src/utils/directory-suggestions.ts @@ -764,30 +764,26 @@ async function listWorkspaceChildEntries(input: { const dirents = await readdir(input.directory, { withFileTypes: true }).catch( () => [] as Dirent[], ); - const entries: ChildWorkspaceEntry[] = []; - for (const dirent of dirents) { - if (isHiddenDirectoryName(dirent.name)) { - continue; - } - if (isIgnoredWorkspaceDirectoryName(dirent.name)) { - continue; - } - - const candidatePath = path.join(input.directory, dirent.name); - const entry = await resolveWorkspaceCandidate({ - candidatePath, - dirent, - workspaceRoot: input.workspaceRoot, - }); - if (!entry) { - continue; - } - entries.push({ - name: dirent.name, - absolutePath: entry.absolutePath, - kind: entry.kind, - }); - } + const candidates = dirents.filter( + (dirent) => + !isHiddenDirectoryName(dirent.name) && !isIgnoredWorkspaceDirectoryName(dirent.name), + ); + const resolved = await Promise.all( + candidates.map(async (dirent) => { + const candidatePath = path.join(input.directory, dirent.name); + const entry = await resolveWorkspaceCandidate({ + candidatePath, + dirent, + workspaceRoot: input.workspaceRoot, + }); + return entry + ? { name: dirent.name, absolutePath: entry.absolutePath, kind: entry.kind } + : null; + }), + ); + const entries: ChildWorkspaceEntry[] = resolved.filter( + (entry): entry is ChildWorkspaceEntry => entry !== null, + ); setWorkspaceEntryListCache(input.directory, { expiresAt: now + DIRECTORY_LIST_CACHE_TTL_MS,