UNPKG

@phren/cli

Version:

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

72 lines (71 loc) • 2.8 kB
/** * Watch mode for the terminal graph. * * Every memory phren lands on — an MCP `search_knowledge` hit, a memory a * hook injected before a prompt, a finding just written — is appended to * `.runtime/lookup-events.jsonl`. Watch mode tails that log so a graph open * in one terminal lights up as an agent works in another: the node pulses, * the camera flies to it, and the finding's full text lands in the pane. * * This module owns the event plumbing only. Drawing lives in graph-view.ts * and camera/selection in controller.ts. */ import { type LookupEvent } from "../../governance/activity.js"; /** How long a touched node stays lit, in ms. */ export declare const HEAT_MS = 6000; /** Events kept for the activity feed. */ export declare const ACTIVITY_LIMIT = 60; export interface ActivityItem { event: LookupEvent; /** Wall-clock ms when this arrived; drives heat decay and the feed's age column. */ seenAt: number; /** Graph node this event points at, when resolvable. */ nodeId?: string; /** True for rows loaded as history rather than seen live. */ historical: boolean; } export interface GraphWatchOptions { pollMs?: number; /** Injected in tests so no real file or timer is needed. */ tail?: { poll: () => LookupEvent[]; }; backfill?: (phrenPath: string, limit: number) => LookupEvent[]; now?: () => number; } export declare class GraphWatch { readonly phrenPath: string; /** Newest first. */ activity: ActivityItem[]; private heat; private tail; private timer; private onEvents; private readonly pollMs; private readonly injectedTail?; private readonly backfillFn; private readonly now; constructor(phrenPath: string, opts?: GraphWatchOptions); get running(): boolean; /** * Begin tailing. Recent history is loaded into the feed immediately but is * never treated as live: it does not pulse and never moves the camera. */ start(onEvents: (items: ActivityItem[]) => void): void; stop(): void; /** Drain the log. Returns the new items, newest last, and lights their nodes. */ poll(): ActivityItem[]; /** 1 right after a node was touched, easing to 0 over HEAT_MS. */ heatOf(nodeId: string): number; /** True while any node is still lit, so the host keeps animating. */ get hot(): boolean; clearActivity(): void; } /** * The graph node an event points at. Findings carry a precomputed `nodeId` * (the same id `buildGraph` assigns); everything else falls back to the * project node, whose id is the project name. */ export declare function targetNodeId(event: LookupEvent): string | undefined; /** "just now", "4s", "2m" — the feed's age column. */ export declare function formatAge(ms: number): string;