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.

91 lines • 4.04 kB
import { loadCredentials } from "../cloud/credential-store.js"; import { pollOnce } from "./poll-client.js"; import { notify as notifyOs } from "./notifier.js"; import { selectFreshDirected } from "./filter.js"; /** Parse `watch` flags. Throws if --peer is missing. */ export function parseWatchArgs(argv) { const get = (flag) => { const i = argv.indexOf(flag); return i >= 0 && i + 1 < argv.length ? argv[i + 1] : undefined; }; const peerId = get("--peer"); if (!peerId) throw new Error("watch: --peer <peerId> is required"); const label = get("--label"); const cwd = get("--cwd"); const intervalRaw = Number(get("--interval")); const intervalSec = Number.isFinite(intervalRaw) && intervalRaw > 0 ? intervalRaw : 15; return { peerId, ...(label ? { label } : {}), ...(cwd ? { cwd } : {}), intervalSec }; } function snippet(s) { return s.replace(/\s+/g, " ").trim().slice(0, 140); } /** One poll → notify cycle. Advances state; never re-notifies a seen message. */ export async function runTick(state, ctx) { const { messages } = await ctx.poll({ endpoint: ctx.creds.endpoint, sessionId: ctx.creds.sessionId, peerId: ctx.target.peerId, token: ctx.creds.token, lastMessageId: state.lastMessageId, }); const fresh = selectFreshDirected(messages, ctx.target, state.seen); for (const m of fresh) { await ctx.notify(`Cogent: ${m.fromPeerId} → ${ctx.target.peerId}`, snippet(m.message)); } if (messages.length > 0) { state.lastMessageId = messages[messages.length - 1].id; } } /** * Entry point for `cogent-bridge watch`. Loads creds, primes state (seeds `seen` * from the current backlog WITHOUT notifying), then loops with exponential backoff * on error. Runs until SIGINT/SIGTERM. */ export async function runWatch(argv) { const cfg = parseWatchArgs(argv); // Credentials resolve per-cwd via process.cwd() or COGENT_CREDENTIALS_FILE. `--cwd` is // informational in v1 — run the watcher from the directory you registered in (documented in README). const creds = await loadCredentials(); if (!creds) { process.stderr.write("watch: no saved credentials for this directory. Join the channel first " + "(/cogent:register), or run watch from the same cwd, or set COGENT_CREDENTIALS_FILE.\n"); process.exit(1); return; } const target = { peerId: cfg.peerId, ...(cfg.label ? { label: cfg.label } : {}) }; const ctx = { creds, target, poll: pollOnce, notify: notifyOs }; const state = { seen: new Set() }; // Prime: seed lastMessageId + seen from the backlog without notifying. try { const primed = await pollOnce({ endpoint: creds.endpoint, sessionId: creds.sessionId, peerId: cfg.peerId, token: creds.token }); selectFreshDirected(primed.messages, target, state.seen); if (primed.messages.length > 0) state.lastMessageId = primed.messages[primed.messages.length - 1].id; } catch (err) { process.stderr.write(`watch: initial poll failed (${err.message}); will retry.\n`); } process.stdout.write(`watch: notifying for [→ ${cfg.peerId}] on ${creds.label ?? creds.sessionId} every ${cfg.intervalSec}s. Ctrl-C to stop.\n`); let stopped = false; const stop = () => { stopped = true; }; process.on("SIGINT", stop); process.on("SIGTERM", stop); let backoff = 0; while (!stopped) { const waitMs = (backoff > 0 ? Math.min(cfg.intervalSec * 2 ** backoff, 120) : cfg.intervalSec) * 1000; await new Promise((r) => setTimeout(r, waitMs)); if (stopped) break; try { await runTick(state, ctx); backoff = 0; } catch (err) { backoff = Math.min(backoff + 1, 6); process.stderr.write(`watch: poll error (${err.message}); backing off.\n`); } } process.stdout.write("watch: stopped.\n"); } //# sourceMappingURL=index.js.map