import type { FafData } from '../core/types.js'; import { type RenderedResult } from '../core/render-hash.js'; import { type CatalogHost, type FafaDoc, type ProjectedA2A } from './pack.js'; import { type ServerCardOptions } from './servercard.js'; /** A2A extension URI — dereference, not the MCP `_meta` key `one.faf/context`. */ export declare const A2A_CONTEXT_URI = "https://faf.one/ext/context/v1"; export { A2A_PROTOCOL_BINDING, A2A_PROTOCOL_VERSION, FAF_MEDIA_TYPES, a2aEndpoints, a2aDoors, } from './pack.js'; export type { FafaAgent, FafaCapability, FafaEndpoint, FafaDoc, ProjectedA2A } from './pack.js'; export type CardTarget = 'a2a' | 'mcp' | 'registry' | 'catalog' | 'ard'; export declare const CARD_TARGETS: CardTarget[]; export interface ProjectCardsOptions extends ServerCardOptions { /** Public URL of the emitted A2A card (catalog row). */ a2aCardUrl?: string; /** Caller-supplied A2A door when `.fafa` has no `endpoints[].protocol: a2a`. */ doorUrl?: string; } export interface CatalogEntry { identifier: string; displayName?: string; type: string; description?: string; url: string; updatedAt?: string; /** ARD's search hints — on the ARD manifest's rows only. */ tags?: string[]; representativeQueries?: string[]; } export interface AiCatalog { specVersion: string; host?: Record; entries: CatalogEntry[]; [key: string]: unknown; } export interface ProjectedCards { block: Record; a2a?: ProjectedA2A; mcp?: Record; registry?: { name: string; title?: string; _meta: Record; }; catalog?: CatalogEntry[]; /** The same rows, carrying ARD's search hints — the ARD manifest. */ ard?: CatalogEntry[]; /** Who publishes the catalog — written only into a catalog that names * nobody yet. An existing `host` is the site's, and is never touched. */ catalogHost?: CatalogHost; } export declare function readFafa(path: string): FafaDoc; /** Discover agent.fafa / .fafa (cwd, then one parent). */ export declare function findFafaFile(dir?: string): string | null; /** Build the A2A Agent Card (JSON) from a .fafa + .faf: the core card * ({@link projectA2ACard}) carrying FAF's context extension. */ export declare function buildA2ACard(fafa: FafaDoc, faf: FafData, opts?: ProjectCardsOptions): ProjectedA2A; /** @deprecated Use {@link buildA2ACard}. Removed in the next major. */ export declare const generateA2ACard: typeof buildA2ACard; /** * The catalog rows for this agent, keyed exactly as the pack projector keys * them: `urn:air:{publisher}:{namespace}:{name}`, where the publisher is the * domain the `.fafa` *declares* (`agent.id`'s urn:air, `metadata.cards.domain`, * else the homepage host) and the name is the handle — never the display name, * which is free text and may carry spaces a URN may not. * * Throws, rather than inventing either half, when the `.fafa` names no domain: * an identifier is a catalog's primary key, and `urn:air:local:…` published to * the world is worse than a refusal a line of YAML fixes. */ export declare function catalogEntriesFor(fafa: FafaDoc, faf: FafData, opts?: ProjectCardsOptions): CatalogEntry[]; /** Upsert projector entries into an existing catalog. Leaves every other row * alone: a row is faf's only when its identifier is exactly faf's (never by * type or URL). On match, only url / type / updatedAt move — host copy * (title, tags) stays; any other faf row is appended. `host` names the * publisher on a catalog that names none — an existing one is the site's own * and stays as it is. */ export declare function upsertCatalog(existing: AiCatalog | undefined, incoming: CatalogEntry[], host?: CatalogHost): AiCatalog; /** * {@link upsertCatalog} as a text edit of the catalog's JSON: faf's own rows * (identifier exactly faf's) get their url / type / updatedAt values changed * in place, faf's other rows are appended after the last entry, and every * other byte — your rows, their order and layout, other keys — stays. With no * text (no catalog yet) a new catalog is returned. `host` names the publisher * (AI Catalog Level 2 "discoverable") and is added, after `specVersion`, only * to a catalog that names none: a `host` already in the file is the site's own * and is left byte for byte. Throws a JsonEditError, changing nothing, when * the catalog cannot be edited that way (not a JSON object, `entries` not an * array, faf's row there twice, …). */ export declare function upsertCatalogText(text: string | null, incoming: CatalogEntry[], host?: CatalogHost): { text: string; changed: boolean; }; export declare function projectCards(input: { faf: FafData; fafa?: FafaDoc; targets?: CardTarget[]; opts?: ProjectCardsOptions; }): ProjectedCards; /** * Same underlying context on every emitted door. MCP and registry carry * {@link fafContextBlock} byte-identically. A2A's extension params are a * deliberate, richer superset (agentId, passport, mediaTypes — see * {@link fafaExtensionParams}), so the check there is narrower: its nested * `provenance.faf` / `provenance.mediaType` must match the same block's * `faf` / `mediaType` — the same pointer, not a byte-identical payload. */ export declare function assertSameBlock(cards: ProjectedCards): void; /** True when `bytes` are an A2A Agent Card faf wrote: JSON whose * `capabilities.extensions` carry the FAF context extension * ({@link A2A_CONTEXT_URI}), as every card faf has written does. */ export declare function hasA2ACardMark(bytes: Uint8Array): boolean; /** True when `bytes` carry any of faf's card marks: the MCP Server Card's * `_meta["one.faf/context"]`, a registry server.json's publisher-provided * `one.faf/context`, or the A2A card's FAF context extension. */ export declare function hasFafCardMark(bytes: Uint8Array): boolean; /** Options for {@link writeJson}. */ export interface WriteJsonOptions { /** True when the bytes already at the path carry faf's older mark (a file * faf wrote before render hashes). Default: one of faf's card marks * ({@link hasFafCardMark}). */ owns?: (existing: Buffer) => boolean; /** faf's mark in words, for the refusal. */ mark?: string; /** Replace a file faf cannot prove it wrote anyway — the explicit overwrite (`--force`). */ force?: boolean; } /** Write `value` as JSON (2-space, final newline) with faf's render hash at * `_meta["one.faf/render"]` — atomically, and never through a link that * leaves `root` (default: the file's own folder) or dangles. The folder is * created when missing, never through a link that leaves `root`. A file * already there is replaced only when it is byte for byte what faf last wrote * (its render hash still fits); a file edited since, one without faf's mark, * or one from before 7.13 that is not exactly this JSON is refused * (SafePathError `not-owned`) and left byte for byte, unless `force`. * Returns what it did: `created`, `updated`, or `unchanged` (the file * already held exactly these bytes, and nothing was written). */ export declare function writeJson(path: string, value: unknown, root?: string, write?: WriteJsonOptions): RenderedResult; /** True when `bytes` are JSON laid out exactly as faf writes it (2-space * JSON and a final newline), so re-writing it loses nothing: no hand * formatting, no repeated key, no number JSON cannot hold exactly. */ export declare function isFafJsonLayout(bytes: Uint8Array): boolean; export declare function parseTargets(raw?: string): CardTarget[] | undefined;