UNPKG

@phren/cli

Version:

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

65 lines (64 loc) • 2.44 kB
import { pollStore } from "./pull.js"; /** One running pull and one pending wakeup per store; also respects sibling-process locks. */ export class ImmediatePulls { pull; intervalMs; states = new Map(); stopped = false; constructor(pull = store => pollStore(store, 0, undefined, Date.now(), true), intervalMs = 10_000) { this.pull = pull; this.intervalMs = intervalMs; } request(store) { if (this.stopped) return; let state = this.states.get(store); if (!state) { state = { pending: false, running: false, last: -Infinity, retries: 0 }; this.states.set(store, state); } state.pending = true; state.retries = 0; if (state.running || state.timer) return; const run = async () => { state.timer = undefined; if (this.stopped) return; state.pending = false; state.running = true; state.last = Date.now(); try { const result = await this.pull(store); // A sibling process may own either coordination lock. Keep one wakeup until it releases. if (result.status === "deferred" && (result.detail === "Coordinated pull is running." || result.detail === "Periodic pull deferred: another Phren Git operation is running." || result.detail === "Periodic pull deferred: a Git operation is in progress.")) { if (state.retries < 2) { state.retries++; state.pending = true; } } else state.retries = 0; } catch { /* The next nudge or fallback poll retries failures. */ } finally { state.running = false; if (state.pending && !this.stopped) schedule(); } }; const schedule = () => { const delay = Math.max(0, state.last + this.intervalMs * Math.max(1, state.retries) - Date.now()); state.timer = setTimeout(() => { void run(); }, delay); state.timer.unref(); }; schedule(); } stop() { this.stopped = true; for (const state of this.states.values()) clearTimeout(state.timer); } }