UNPKG

@phren/cli

Version:

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

145 lines (144 loc) • 6.53 kB
import { z } from "zod"; import { type RequestKind } from "./approval-summary.js"; import type { SudoRequestView } from "./sudo.js"; /** A phone registered through the phren push relay: the relay knows where to * deliver, and `key` (32 bytes, base64url) encrypts what the notification says * so only the phone reads it. The phone made the key and sent it over SSH. */ declare const relaySchema: z.ZodObject<{ url: z.ZodString; relayId: z.ZodString; secret: z.ZodString; key: z.ZodString; }, z.core.$strip>; declare const deviceSchema: z.ZodObject<{ deviceID: z.ZodString; hostID: z.ZodString; token: z.ZodOptional<z.ZodString>; relay: z.ZodOptional<z.ZodObject<{ url: z.ZodString; relayId: z.ZodString; secret: z.ZodString; key: z.ZodString; }, z.core.$strip>>; environment: z.ZodEnum<{ development: "development"; production: "production"; }>; kinds: z.ZodDefault<z.ZodArray<z.ZodEnum<{ approval: "approval"; scheduleBlocked: "scheduleBlocked"; scheduleFailed: "scheduleFailed"; scheduleFinished: "scheduleFinished"; scheduleStarted: "scheduleStarted"; }>>>; }, z.core.$strip>; export type PushDevice = z.infer<typeof deviceSchema>; export interface ApprovalPush { binding: string; provider: string; question: boolean; expiresAt: string; project?: string; computer?: string; request?: string; requestKind?: RequestKind; } export interface FanoutBlockedPush { job: string; label: string; provider: string; reason: string; } export type SchedulePushKind = "scheduleStarted" | "scheduleFinished" | "scheduleFailed" | "scheduleBlocked"; export interface SchedulePush { kind: SchedulePushKind; scheduleId: string; project: string; name: string; computer: string; runId: string; status: "running" | "finished" | "needs-you" | "failed" | "blocked"; reason?: string; route?: string; } export interface SchedulePushResult { notified: boolean; reason?: string; } export declare function scheduleCollapseId(kind: SchedulePushKind, runId: string): string; export declare function approvalPushPayload(value: ApprovalPush, host?: string): Record<string, unknown>; /** A sudo request waiting for its password. The command is what the owner * approves; the password itself is typed only in the app, never in a * notification action. */ export declare function sudoPushPayload(value: SudoRequestView, host?: string): Record<string, unknown>; export declare function fanoutBlockedPushPayload(value: FanoutBlockedPush): Record<string, unknown>; export declare function schedulePushPayload(value: SchedulePush): Record<string, unknown>; /** What `phren bridge doctor` prints when the Hook has no APNs sender. */ export declare function apnsSetupSteps(configFile?: string): string; /** The capability a phone reads: a Hook with its own APNs key sends direct; * one whose phones registered through the relay sends through it. */ export declare function approvalPushCapability(status: { configured: boolean; direct?: boolean; }): "direct-apns" | "relay" | undefined; export declare function upsertPushDevice(devices: PushDevice[], value: unknown): PushDevice[]; /** The relay refuses ciphertext longer than this (it keeps the APNs payload under 4 KB). */ export declare const RELAY_MAX_CIPHERTEXT = 2800; /** What the phone's notification extension shows, encrypted with the phone's * key: ChaCha20-Poly1305, base64url of nonce (12) + ciphertext + tag (16), the * layout CryptoKit's `ChaChaPoly.SealedBox(combined:)` reads. A long body is * shortened until it fits the relay's limit. */ export declare function relayCiphertext(key: string, payload: Record<string, unknown>, nonce?: NonSharedBuffer): string; /** Signs a relay send: base64url HMAC-SHA256 of `${timestamp}.${body}` under the phone's send secret. */ export declare function relaySignature(secret: string, timestamp: string, body: string): string; type RelayRegistration = z.infer<typeof relaySchema>; /** "gone" means the relay (Apple) no longer knows the phone: stop sending until it registers again. */ export type RelayResult = "sent" | "failed" | "gone"; export declare function sendThroughRelay(relay: RelayRegistration, payload: Record<string, unknown>, headers: { expiration: string; collapseId: string; }, fetcher?: typeof fetch, now?: () => number): Promise<RelayResult>; /** Direct Hook -> APNs delivery. Apple receives only a short-lived opaque * binding; conversation identity, action id, command and SSH key stay local. */ export declare class ApprovalPushService { private devices; private sender?; private readonly devicesFile; start(): Promise<void>; /** Phones this Hook can reach: through the relay, or direct with its own key. */ private get reachable(); get available(): boolean; get status(): { supported: boolean; configured: boolean; direct: boolean; devices: number; relay: number; }; register(value: unknown): Promise<void>; /** One phone: the relay when it registered through one, otherwise direct. */ private send; /** Until when the owner is at Phren desktop (ms epoch): approval pushes wait for the desk to go quiet. */ private deskUntil; private held; /** Whether an approval is still unanswered; AgentHooks sets it. Unset means "assume pending". */ stillPending?: (binding: string) => boolean; /** Phren desktop saw the owner's keyboard or mouse: hold phone alerts for `activeForMs` (at most 2 min). */ markDesk(activeForMs: number): void; get deskActive(): boolean; /** * Desk first: while the owner is at the desktop, the desktop shows the * approval and the phone stays quiet. Once the desk has been idle past its * window and the approval is still pending, the phone gets the alert. */ notify(value: ApprovalPush): Promise<boolean>; private holdForDesk; protected notifyNow(value: ApprovalPush): Promise<boolean>; notifySudo(value: SudoRequestView): Promise<boolean>; /** A headless worker whose permission the plugin refused. Approval-registered * phones already accept agent alerts; the payload carries the reason so the * notification is actionable on its own. */ notifyFanoutBlocked(value: FanoutBlockedPush): Promise<boolean>; notifySchedule(value: SchedulePush): Promise<SchedulePushResult>; } export {};