UNPKG

@phren/cli

Version:

Knowledge layer for AI agents - CLI, MCP server, and data layer

66 lines (65 loc) • 2.15 kB
import { BridgeError } from "./protocol.js"; /** A bounded process pool. Cancelled waiters never start work. */ export class ProcessPool { limit; active = 0; waiting = []; constructor(limit) { this.limit = limit; } async run(signal, work) { signal?.throwIfAborted(); if (this.active >= this.limit) { await new Promise((resolve, reject) => { const ready = () => { signal?.removeEventListener("abort", abort); resolve(); }; const abort = () => { this.waiting = this.waiting.filter(w => w !== ready); reject(signal.reason); }; this.waiting.push(ready); signal?.addEventListener("abort", abort, { once: true }); }); } else this.active++; try { signal?.throwIfAborted(); return await work(); } finally { const next = this.waiting.shift(); if (next) next(); else this.active--; } } } /** Shared by workspace and tab creation, including agent startup. */ export class LaunchLimiter { now; active = false; starts = []; constructor(now = Date.now) { this.now = now; } async run(work) { const now = this.now(); this.starts = this.starts.filter(at => now - at < 60_000); if (this.active || this.starts.length >= 6) throw new BridgeError(429, "Workspace launches are busy. Try again shortly."); this.active = true; this.starts.push(now); try { return await work(); } finally { this.active = false; } } } /** A millisecond interval read once at startup from the environment variable * `name`, when it is a number within `[min, max]`; otherwise `fallback`. * Tests shorten these. */ export function intervalFromEnv(name, fallback, min = 0, max = 60_000) { const raw = process.env[name]; const value = Number(raw); return raw && Number.isFinite(value) && value >= min && value <= max ? Math.floor(value) : fallback; }