From 0a300e6c7924efd3b5d87cbc2c9716ca0c19e761 Mon Sep 17 00:00:00 2001 From: Prateek Date: Wed, 18 Feb 2026 14:09:08 +0530 Subject: [PATCH] fix: cache registry promise and cap stderr buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Cache the Promise instead of the resolved PluginRegistry to prevent concurrent callers from racing past the null check and creating multiple registries before loadFromConfig completes. - Cap stderrChunks to 100 entries since only early startup errors (stale build detection) are checked — unbounded growth wastes memory for long-running dashboard processes. Co-Authored-By: Claude Sonnet 4.6 --- packages/cli/src/commands/dashboard.ts | 6 +++++- packages/cli/src/lib/create-session-manager.ts | 16 ++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/commands/dashboard.ts b/packages/cli/src/commands/dashboard.ts index 8c94f542e..dd8b19a8d 100644 --- a/packages/cli/src/commands/dashboard.ts +++ b/packages/cli/src/commands/dashboard.ts @@ -69,9 +69,13 @@ export function registerDashboard(program: Command): void { const stderrChunks: string[] = []; + const MAX_STDERR_CHUNKS = 100; + child.stderr?.on("data", (data: Buffer) => { const text = data.toString(); - stderrChunks.push(text); + if (stderrChunks.length < MAX_STDERR_CHUNKS) { + stderrChunks.push(text); + } // Still show stderr to the user process.stderr.write(data); }); diff --git a/packages/cli/src/lib/create-session-manager.ts b/packages/cli/src/lib/create-session-manager.ts index c40e2896f..82b1b42f5 100644 --- a/packages/cli/src/lib/create-session-manager.ts +++ b/packages/cli/src/lib/create-session-manager.ts @@ -15,18 +15,22 @@ import { type PluginRegistry, } from "@composio/ao-core"; -let cachedRegistry: PluginRegistry | null = null; +let registryPromise: Promise | null = null; /** * Get or create the plugin registry. - * Cached to avoid re-importing all plugins on every call. + * Caches the Promise (not the resolved value) so concurrent callers + * await the same initialization rather than racing. */ async function getRegistry(config: OrchestratorConfig): Promise { - if (!cachedRegistry) { - cachedRegistry = createPluginRegistry(); - await cachedRegistry.loadFromConfig(config); + if (!registryPromise) { + registryPromise = (async () => { + const registry = createPluginRegistry(); + await registry.loadFromConfig(config); + return registry; + })(); } - return cachedRegistry; + return registryPromise; } /**