UNPKG

@phren/cli

Version:

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

45 lines (44 loc) • 2.35 kB
import { bridgeRoot } from "./protocol.js"; const pending = new Set(); const samePane = (left, right) => left.server === right.server && left.pane === right.pane && (left.terminal === undefined || left.terminal === right.terminal); /** Register before a dispatch's first await; only these live operations can * inherit a hand-over alias. A later dispatch starts with no aliases. */ export function trackDispatchOrigin() { const entry = { root: bridgeRoot(), aliases: [] }; pending.add(entry); return { rewrite: origin => origin && (entry.aliases.find(alias => samePane(alias.from, origin))?.to ?? origin), finish: () => { pending.delete(entry); entry.aliases = []; }, }; } /** Prepare while holding the receipt lock, then seal only after role commit. * Keep prior chains in this snapshot because the role write invalidates them. * Operations started during the commit are included; later ones never are. */ export function prepareDispatchOriginHandover(from, to) { const root = bridgeRoot(); const before = new Map([...pending].filter(entry => entry.root === root).map(entry => [entry, entry.aliases])); return () => { for (const entry of pending) { if (entry.root !== root) continue; entry.aliases = (before.get(entry) ?? entry.aliases) .filter(alias => !samePane(alias.from, to) && !samePane(alias.from, from)) .map(alias => samePane(alias.to, from) ? { ...alias, to } : alias); entry.aliases.push({ from, to }); } }; } /** Called after every successful role write, without acquiring another lock. * A stop or reassignment must not let an earlier move redirect late workers * away from the newly chosen conductor. No aliases survive a Hook restart. */ export function conductorOriginChanged(conductor) { const root = bridgeRoot(); for (const entry of pending) { if (entry.root !== root) continue; entry.aliases = entry.aliases.filter(alias => conductor && samePane(alias.to, conductor) && (conductor.source === undefined || alias.to.agent === conductor.source) && (conductor.workspace === undefined || alias.to.workspace === conductor.workspace) && (conductor.tab === undefined || alias.to.tab === conductor.tab)); } }