UNPKG

@essentialai/cogent-bridge

Version:

Cogent Bridge — cross-agent comms for Claude Code, OpenAI Codex and Slack. Codex users: install with `curl -fsSL https://cogent.tools/install.sh | sh`, then start with `cogent-codex` for real-time peer wake.

92 lines • 5.02 kB
/** One process as reported by `ps`. */ export interface ProcInfo { pid: number; ppid: number; /** Milliseconds since epoch when the process started. */ startedAt: number; /** Full command line. */ argv: string; } export interface ReapCandidate { proc: ProcInfo; /** Human-readable justification, logged before any signal is sent. */ reason: string; } /** * Does this command line launch a cogent BRIDGE? * * Deliberately anchored on the entry-point FILE, never on the word "cogent" appearing somewhere. * A substring match would catch this repo's own gate harnesses (`wake-dedup-matrix-test.mjs`, * `slack-roundtrip-test.mjs`) and an editor with the source open — and a harness matching its own * command line is a mistake this codebase has already made twice. */ export declare function isBridgeCommand(argv: string): boolean; /** Best-effort version parsed out of a plugin-cache path, e.g. `/cogent/3.21.5/bridge/...`. */ export declare function versionFromArgv(argv: string): string | null; /** The first version that announces itself and stands down on its own (wake-ownership.ts). */ export declare const SELF_SUPERSESSION_VERSION = "3.23.4"; /** `a >= b` for plain x.y.z versions; a pre-release/build suffix is ignored. */ export declare function versionAtLeast(a: string, b: string): boolean; /** * The bridge's version: from the plugin-cache path, else from the package.json beside a versionless * npm/npx entry point (`.../node_modules/.bin/cogent-bridge`, `.../@essentialai/cogent-bridge/dist/cli.js`). * Null when neither is readable — and null is never a reason to kill (signal 4b). * * A package.json can be newer than the process reading it describes (an unpinned npx re-resolves * into the SAME `_npx/<hash>` folder, measured 2026-10-01): a ghost then reads as current and is * spared, the same outcome as an unreadable version. */ export declare function bridgeVersion(argv: string, readFile?: (p: string) => string): string | null; /** Every running process, from `ps`. Returns [] on any failure — never throws. */ export declare function listProcesses(): ProcInfo[]; /** * Resolve a process's working directory, or null when it cannot be determined. * * NULL IS A REFUSAL, NOT A GUESS. If we cannot prove the process is in our cwd we must not touch * it — an unresolvable cwd is the single most likely way this reaper would kill something innocent. */ export declare function processCwd(pid: number): string | null; /** * Canonical form of a path for COMPARISON — symlinks resolved. * * 🔴 macOS. `lsof` reports a process's cwd already realpath'd (`/private/var/...`) while * `process.cwd()` keeps the symlinked spelling (`/var/...`), because `/var -> /private/var`. A * `path.resolve`-only comparison therefore NEVER matches on macOS and the reaper is silently inert * — it fails safe, but it heals nobody, which is the whole point of it. Found by running the * platform probe on a real Mac; no Linux test could have shown it. * * Falls back to `path.resolve` when the path no longer exists, so a vanished cwd degrades to a * non-match (a refusal) rather than an exception. */ export declare function canonicalPath(p: string): string; /** Every ancestor pid of `pid`, walking ppid to init. Cycle-safe. */ export declare function ancestorsOf(pid: number, procs: ProcInfo[]): Set<number>; /** * Which running processes are leftover bridges for `cwd` that cannot stand down by themselves? * * `procs` is injectable so the decision logic is unit-testable without spawning anything, and * `cwdOf` so a test can supply cwds without /proc. * * 🔴 "OLDER THAN US" COMPARES LIKE WITH LIKE: our own start time is read from the SAME `ps` listing * as theirs. `ps` reports whole seconds rounded down twice (boot time, then ticks since boot) — * measured up to 1.8 s behind the clock on Linux — so against our own millisecond clock a bridge * started up to two seconds AFTER us looked older and was selected (stale-bridge-reap-test, red on * main). If we are not in the listing, order cannot be proven and nothing is reaped. */ export declare function findStaleBridges(cwd: string, procs?: ProcInfo[], opts?: { selfPid?: number; selfStartedAt?: number; cwdOf?: (pid: number) => string | null; announced?: Set<number>; versionOf?: (argv: string) => string | null; }): ReapCandidate[]; /** Is the reaper enabled? Default ON; opt out with a falsey COGENT_REAP_STALE_BRIDGES. */ export declare function reaperEnabled(env?: NodeJS.ProcessEnv): boolean; /** * SIGTERM every leftover bridge for this cwd. Returns the candidates acted on. * * Graceful on purpose: the bridge's SIGTERM handler stops auto-relay, disconnects the WebSocket and * exits cleanly, so a mistargeted kill is a clean shutdown rather than a corrupted one. */ export declare function reapStaleBridges(cwd: string, opts?: Parameters<typeof findStaleBridges>[2]): ReapCandidate[]; //# sourceMappingURL=stale-bridge-reaper.d.ts.map