UNPKG

@phren/cli

Version:

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

97 lines (96 loc) • 4.03 kB
import { z } from "zod"; import { type Json, type Target } from "./protocol.js"; export declare const queuedHandOffSchema: z.ZodObject<{ target: z.ZodObject<{ server: z.ZodString; workspace: z.ZodString; tab: z.ZodString; pane: z.ZodString; source: z.ZodEnum<{ claude: "claude"; codex: "codex"; copilot: "copilot"; opencode: "opencode"; phren: "phren"; }>; session: z.ZodUnion<readonly [z.ZodString, z.ZodString]>; }, z.core.$strip>; text: z.ZodString; deliveryId: z.ZodOptional<z.ZodString>; origin: z.ZodOptional<z.ZodObject<{ server: z.ZodString; workspace: z.ZodString; tab: z.ZodString; pane: z.ZodString; source: z.ZodEnum<{ claude: "claude"; codex: "codex"; copilot: "copilot"; opencode: "opencode"; phren: "phren"; }>; session: z.ZodUnion<readonly [z.ZodString, z.ZodString]>; }, z.core.$strip>>; originComputer: z.ZodOptional<z.ZodString>; }, z.core.$strict>; export interface QueueOptions { validate: (target: Target) => Promise<Json>; send: (target: Target, text: string, deliveryId: string, typing: () => Promise<void>) => Promise<Json>; forward?: (target: Target, text: string, deliveryId: string) => Promise<{ delivered: boolean; } | undefined>; notify?: (target: Target, text: string, deliveryId: string, computer: string) => Promise<Json>; /** The conversation the target's pane shows now, and its terminal. */ current?: (target: Target) => Promise<{ session: string; terminal: unknown; } | undefined>; now?: () => number; root?: string; } /** Settled rows (and notice tombstones) are kept this long, so a late retry of * an old delivery id still replays instead of typing again. */ export declare const HAND_OFF_RETENTION_MS: number; /** At most this many rows stay on disk; the oldest settled rows go first. */ export declare const HAND_OFF_MAX_ROWS = 512; /** A durable outbox on the receiving Hook. Persist 'attempting' before input, * so a crash in the input/ack gap recovers as uncertain, never as a retry. * Tombstones are retained for HAND_OFF_RETENTION_MS, so a retried delivery id * replays instead of typing a second time; a queued or attempting row is never * pruned. The sweep runs on enqueue and at most daily from tick(). */ export declare class HandOffQueue { private options; private pending; private root; private now; private lastPrune; private ticking?; constructor(options: QueueOptions); private serial; private file; private save; private read; private rows; /** Drops settled rows past retention, then the oldest settled rows over the * cap (those still owing their sender a notice last). Returns what is kept. */ private prune; private reply; enqueue(input: unknown): Promise<Json>; status(id: string, target: Target): Promise<Json>; /** Validates the row's target. When the pane's conversation was replaced * in the same terminal (a Codex thread change, a Claude /clear), the row * follows it: a queued message is for the pane, not for a conversation * that is no longer there. Saved by the caller's next state change. */ private validate; private attempt; /** Coalesced: the Hook calls this every 5 s whether or not the last tick * finished, and queuing each behind the lock would hold every enqueue and * status behind a backlog that grows faster than a slow tick drains it. */ tick(): Promise<void>; private sweep; private noticeId; /** Hold enqueues and delivery while the Hook validates and closes a worker. * A new hand-off cannot be accepted between the pending check and closure. */ whenNoPending(target: Target, close: () => Promise<Json>): Promise<Json>; hasPending(target: Target): Promise<boolean>; }