@phren/cli
Version:
Knowledge layer for AI agents - CLI, MCP server, and data layer
110 lines (109 loc) • 4.18 kB
TypeScript
import { type Computer } from "./computer-identity.js";
import { type HookPeer } from "./peers.js";
import { type Json } from "./protocol.js";
import type { SetName } from "./conductor-role.js";
/**
* Linked computer sets (docs/conductor-sets.md). A link runs both ways when
* each computer's hooks.yaml lists the other; a set is the computers joined by
* such links. This Hook sees its set from itself and one hop: each peer
* answers `GET /v1/conductor` with its live conductor, its own peers, whether
* it lists the caller back and the set name it holds. A set has one conductor.
*/
type Ask = (peer: HookPeer, route: string, data?: Json, timeout?: number) => Promise<Json>;
/** What this computer tells a peer about itself, so the peer can say whether it links back. */
export interface Caller {
name: string;
hostKey?: string;
}
export declare function localCaller(): Promise<Caller>;
export declare function callerQuery(caller: Caller): string;
/** One peer's answer to `GET /v1/conductor`, or why it gave none. */
export type PeerAnswer = {
peer: HookPeer;
} & ({
ok: true;
id?: string;
names: string[];
conductor?: Json;
/** Its hooks.yaml names; absent from a Hook older than sets. */
peers?: string[];
/** Whether it lists this computer back; absent when its Hook cannot say. */
knowsCaller?: boolean;
set?: SetName;
} | {
ok: false;
error: string;
code?: string;
/** Its conductor module is off, so it cannot run a conductor. */
disabled?: boolean;
});
export declare function askPeers(peers: readonly HookPeer[], caller: Caller, ask?: Ask): Promise<PeerAnswer[]>;
export interface GroupConductor {
/** A live conductor on a member of this computer's set. */
found?: {
computer: string;
target?: Json;
};
/** Members that could not say, so a conductor there cannot be ruled out. */
unchecked: {
computer: string;
error: string;
code?: string;
}[];
}
/** The names members report that are neither this computer nor one of its
* peers: computers in the set that this Hook cannot ask directly. */
export declare function indirectMembers(answers: readonly PeerAnswer[], localNames: readonly string[]): string[];
export declare const linkHint: (name: string) => string;
export declare const oneWayHint: (name: string) => string;
/** One conductor per set: a live conductor on any member, and the members that could not say. */
export declare function setConductor(answers: readonly PeerAnswer[], localNames: readonly string[]): GroupConductor;
export declare function groupConductor(peers: readonly HookPeer[], localNames: readonly string[], ask?: Ask, caller?: Caller): Promise<GroupConductor>;
export interface SetComputer {
name: string;
id?: string;
local?: true;
/** Whether its Hook answered just now; absent when this Hook cannot ask it. */
reachable?: boolean;
link: "self" | "two-way" | "one-way" | "indirect" | "unknown";
conductor?: Json;
error?: string;
code?: string;
hint?: string;
}
export interface ComputerSet {
id: string;
name?: string;
namedAt?: string;
/** This computer's own set. */
local: boolean;
computers: SetComputer[];
/** The set's conductor; with `conductors` above 1, the first of several. */
conductor?: {
computer: string;
target?: Json;
};
conductors: number;
}
/**
* Every set this Hook can see: its own (itself, its two-way and not yet known
* peers, and computers they link that this Hook does not), then one set per
* one-way peer. `unlinked` are computers the store knows with no link here.
*/
export declare function buildSets(input: {
local: {
name: string;
id?: string;
conductor?: Json;
set?: SetName;
names: readonly string[];
};
answers: readonly PeerAnswer[];
computers: readonly Computer[];
/** Identity rows from peers, used only to recognize names in their set reports. */
reportedComputers?: readonly Pick<Computer, "id" | "name" | "aliases">[];
}): {
sets: ComputerSet[];
unlinked: Computer[];
};
export {};