MCPcopy
hub / github.com/coder/mux / BackgroundProcessManager

Class BackgroundProcessManager

src/node/services/backgroundProcessManager.ts:182–1366  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

180}
181
182export class BackgroundProcessManager extends EventEmitter<BackgroundProcessManagerEvents> {
183 // NOTE: This map is in-memory only. Background processes use nohup/setsid so they
184 // could survive app restarts, but we kill all tracked processes on shutdown via
185 // dispose(). Rehydrating from meta.json on startup is out of scope for now.
186 // All per-process state (read position, output lock) is stored in BackgroundProcess
187 // so cleanup is automatic when the process is removed from this map.
188 private processes = new Map<string, BackgroundProcess>();
189
190 // Base directory for process output files
191 private readonly bgOutputDir: string;
192 // Tracks foreground processes (started via runtime.exec) that can be backgrounded
193 // Key is toolCallId to support multiple parallel foreground processes per workspace
194 private foregroundProcesses = new Map<string, ForegroundProcess>();
195 // Tracks workspaces with queued messages (for bash_output to return early)
196 private queuedMessageWorkspaces = new Set<string>();
197
198 constructor(bgOutputDir: string) {
199 super();
200 // Background bash status can have many concurrent subscribers (e.g. multiple workspaces).
201 // Raise the default listener cap to avoid noisy MaxListenersExceededWarning.
202 this.setMaxListeners(50);
203 this.bgOutputDir = bgOutputDir;
204 }
205
206 /**
207 * Mark whether a workspace has a queued user message.
208 * Used by bash_output to return early when user has sent a new message.
209 */
210 setMessageQueued(workspaceId: string, queued: boolean): void {
211 if (queued) {
212 this.queuedMessageWorkspaces.add(workspaceId);
213 } else {
214 this.queuedMessageWorkspaces.delete(workspaceId);
215 }
216 }
217
218 /**
219 * Check if a workspace has a queued user message.
220 */
221 hasQueuedMessage(workspaceId: string): boolean {
222 return this.queuedMessageWorkspaces.has(workspaceId);
223 }
224
225 /** Emit a change event for a workspace */
226 private emitChange(workspaceId: string): void {
227 this.emit("change", workspaceId);
228 }
229
230 private createMonitorState(
231 config: BackgroundProcessMonitorConfig,
232 options: { pollIntervalMs: number }
233 ): BackgroundProcessMonitorState {
234 assert(config.filter.length > 0, "BackgroundProcessMonitorConfig requires a filter");
235 assert(config.cooldownMs >= 0, "BackgroundProcessMonitorConfig cooldown must be non-negative");
236 assert(options.pollIntervalMs > 0, "monitor poll interval must be positive");
237 return {
238 ...config,
239 matchesCount: 0,

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected