faf-cli 8.1.0 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,8 +2,7 @@ import type { FafData } from '../core/types.js';
2
2
  import { type RenderedResult } from '../core/render-hash.js';
3
3
  import { type CatalogHost, type FafaDoc, type ProjectedA2A } from './pack.js';
4
4
  import { type ServerCardOptions } from './servercard.js';
5
- /** A2A extension URI — dereference, not the MCP `_meta` key `one.faf/context`. */
6
- export declare const A2A_CONTEXT_URI = "https://faf.one/ext/context/v1";
5
+ export { A2A_CONTEXT_URI } from './context-block.js';
7
6
  export { A2A_PROTOCOL_BINDING, A2A_PROTOCOL_VERSION, FAF_MEDIA_TYPES, a2aEndpoints, a2aDoors, } from './pack.js';
8
7
  export type { FafaAgent, FafaCapability, FafaEndpoint, FafaDoc, ProjectedA2A } from './pack.js';
9
8
  export type CardTarget = 'a2a' | 'mcp' | 'registry' | 'catalog' | 'ard';
@@ -32,13 +31,15 @@ export interface AiCatalog {
32
31
  [key: string]: unknown;
33
32
  }
34
33
  export interface ProjectedCards {
35
- block: Record<string, unknown>;
34
+ /** faf's context block — only when a project.faf was given (BEST). */
35
+ block?: Record<string, unknown>;
36
36
  a2a?: ProjectedA2A;
37
37
  mcp?: Record<string, unknown>;
38
38
  registry?: {
39
39
  name: string;
40
40
  title?: string;
41
- _meta: Record<string, unknown>;
41
+ /** FAF's context block (BEST); absent from a plain registry identity (BETTER). */
42
+ _meta?: Record<string, unknown>;
42
43
  };
43
44
  catalog?: CatalogEntry[];
44
45
  /** The same rows, carrying ARD's search hints — the ARD manifest. */
@@ -50,23 +51,27 @@ export interface ProjectedCards {
50
51
  export declare function readFafa(path: string): FafaDoc;
51
52
  /** Discover agent.fafa / .fafa (cwd, then one parent). */
52
53
  export declare function findFafaFile(dir?: string): string | null;
53
- /** Build the A2A Agent Card (JSON) from a .fafa + .faf: the core card
54
- * ({@link projectA2ACard}) carrying FAF's context extension. */
55
- export declare function buildA2ACard(fafa: FafaDoc, faf: FafData, opts?: ProjectCardsOptions): ProjectedA2A;
54
+ /** Build the A2A Agent Card (JSON) from a .fafa: the core card
55
+ * ({@link projectA2ACard}). With a project.faf (BEST) it carries FAF's
56
+ * context extension; with none (BETTER) it is the plain A2A card — the
57
+ * .fafa is its source, and nothing on it points at a project.faf. */
58
+ export declare function buildA2ACard(fafa: FafaDoc, faf?: FafData, opts?: ProjectCardsOptions): ProjectedA2A;
56
59
  /** @deprecated Use {@link buildA2ACard}. Removed in the next major. */
57
60
  export declare const generateA2ACard: typeof buildA2ACard;
58
61
  /**
59
- * The catalog rows for this agent, keyed exactly as the pack projector keys
60
- * them: `urn:air:{publisher}:{namespace}:{name}`, where the publisher is the
61
- * domain the `.fafa` *declares* (`agent.id`'s urn:air, `metadata.cards.domain`,
62
- * else the homepage host) and the name is the handle — never the display name,
63
- * which is free text and may carry spaces a URN may not.
62
+ * The catalog rows for this agent — the pack projector's own
63
+ * ({@link catalogRows}), so `faf cards` and the pack list the same rows: the
64
+ * A2A card (when the `.fafa` names an A2A door), the Server Card (when it names
65
+ * a remote MCP URL) and the `.fafa` itself, keyed
66
+ * `urn:air:{publisher}:{namespace}:{name}`, where the publisher is the domain
67
+ * the `.fafa` *declares* (`agent.id`'s urn:air, `metadata.cards.domain`, else
68
+ * the homepage host) and the name is the handle.
64
69
  *
65
70
  * Throws, rather than inventing either half, when the `.fafa` names no domain:
66
71
  * an identifier is a catalog's primary key, and `urn:air:local:…` published to
67
72
  * the world is worse than a refusal a line of YAML fixes.
68
73
  */
69
- export declare function catalogEntriesFor(fafa: FafaDoc, faf: FafData, opts?: ProjectCardsOptions): CatalogEntry[];
74
+ export declare function catalogEntriesFor(fafa: FafaDoc, faf?: FafData, opts?: ProjectCardsOptions): CatalogEntry[];
70
75
  /** Upsert projector entries into an existing catalog. Leaves every other row
71
76
  * alone: a row is faf's only when its identifier is exactly faf's (never by
72
77
  * type or URL). On match, only url / type / updatedAt move — host copy
@@ -90,8 +95,22 @@ export declare function upsertCatalogText(text: string | null, incoming: Catalog
90
95
  text: string;
91
96
  changed: boolean;
92
97
  };
98
+ /** The cards an agent.fafa gives with no project.faf (BETTER): the A2A card
99
+ * (when it names an A2A door), the MCP Server Card (when it names a remote MCP
100
+ * URL), the registry server.json (a remote or a package), the AI Catalog, ARD. */
101
+ export declare function betterTargets(fafa: FafaDoc, opts?: ProjectCardsOptions): CardTarget[];
102
+ /**
103
+ * Project the cards. The ladder — BETTER is the .fafa, BEST is project.faf:
104
+ * an agent.fafa alone gives the plain cards ({@link betterTargets}); a
105
+ * project.faf, resident and used, adds FAF's context block to each (the A2A
106
+ * card's extension, the Server Card's and server.json's `_meta`). A card's
107
+ * identity comes from the .fafa at both rungs. With a project.faf and no MCP
108
+ * endpoint in the .fafa (an MCP server's own repo), the Server Card and the
109
+ * registry identity come from project.faf, as `faf server-card` writes them.
110
+ */
93
111
  export declare function projectCards(input: {
94
- faf: FafData;
112
+ /** project.faf — absent means BETTER. */
113
+ faf?: FafData;
95
114
  fafa?: FafaDoc;
96
115
  targets?: CardTarget[];
97
116
  opts?: ProjectCardsOptions;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * FAF's context block — what BEST adds to a card. Pure (no Node built-ins), so
3
+ * `faf cards` and the browser-safe pack projector add the same block.
4
+ *
5
+ * The cards ladder: an agent.fafa gives the plain cards (BETTER); a project.faf,
6
+ * resident and used, adds this block to each of them (BEST) — the A2A card's
7
+ * context extension, the Server Card's `_meta["one.faf/context"]`, the registry
8
+ * `server.json`'s publisher-provided `_meta`.
9
+ */
10
+ import type { FafData } from '../core/types.js';
11
+ /** project.faf's IANA media type. */
12
+ export declare const FAF_MEDIA_TYPE = "application/vnd.faf+yaml";
13
+ /** A2A extension URI — dereference, not the MCP `_meta` key `one.faf/context`. */
14
+ export declare const A2A_CONTEXT_URI = "https://faf.one/ext/context/v1";
15
+ export declare const REGISTRY_PUBLISHER_KEY = "io.modelcontextprotocol.registry/publisher-provided";
16
+ export interface ContextBlockOptions {
17
+ /** Pointer to the .faf context (default: ./project.faf). Pass an absolute URL
18
+ * for a remote/served card (e.g. faf-server-card-ref at context.faf.one). */
19
+ fafPointer?: string;
20
+ /** Optional "verify the score here" URL — makes verify-don't-trust actionable
21
+ * (faf-server-card-ref uses https://faf.one). Omitted from the block if unset. */
22
+ scoreEndpoint?: string;
23
+ /** Override timestamp (tests); otherwise .faf `generated`, else now. */
24
+ now?: string;
25
+ }
26
+ /**
27
+ * The canonical FAF context-block — the value of `_meta["one.faf/context"]`,
28
+ * identical across every surface (Server Card, registry `server.json`, `.fafa`):
29
+ * one context, every door. Honest-first: no score baked (it would go stale on
30
+ * disk); it points to the .faf and asserts the score is deterministic.
31
+ */
32
+ export declare function fafContextBlock(data: FafData, opts?: ContextBlockOptions): Record<string, unknown>;
33
+ /**
34
+ * Build the `_meta` for an MCP Registry `server.json`.
35
+ *
36
+ * The SAME canonical context-block as the Server Card, but nested under
37
+ * `io.modelcontextprotocol.registry/publisher-provided` — the ONLY `_meta` key
38
+ * the official registry preserves on publish. Top-level keys (the way the card
39
+ * carries `one.faf/context`) are silently dropped by the registry. Throws if the
40
+ * block exceeds the registry's 4KB cap. Merge the result into an existing
41
+ * `server.json` `_meta`; don't regenerate the manifest (packages/mcpb are tuned).
42
+ */
43
+ export declare function registryMeta(data: FafData, opts?: ContextBlockOptions): Record<string, unknown>;
@@ -1,3 +1,5 @@
1
+ import type { FafData } from '../core/types.js';
2
+ import { type ContextBlockOptions } from './context-block.js';
1
3
  export declare const A2A_PROTOCOL_BINDING = "JSONRPC";
2
4
  export declare const A2A_PROTOCOL_VERSION = "1.0";
3
5
  /** The three FAF-family media types, in family order. */
@@ -108,6 +110,16 @@ export declare function a2aEndpoints(fafa: FafaDoc): FafaEndpoint[];
108
110
  export declare function a2aDoors(fafa: FafaDoc, opts?: {
109
111
  doorUrl?: string;
110
112
  }): FafaEndpoint[];
113
+ /**
114
+ * FAF's context extension for the A2A card (BEST). Its `params` are a superset
115
+ * of {@link fafContextBlock}, enriched with `.fafa`-specific identity that only
116
+ * makes sense for an agent card (agentId, passport, the full FAF media-type
117
+ * family). Nests the base block's `faf`/`mediaType` under `provenance` rather
118
+ * than flattening them, per the extension's own shape (`§7` of the field
119
+ * mapping). The Server Card and registry `_meta` stay on the plain
120
+ * {@link fafContextBlock} shape.
121
+ */
122
+ export declare function fafaContextExtension(fafa: FafaDoc, faf: FafData, opts?: ContextBlockOptions): A2AExtension;
111
123
  /**
112
124
  * The A2A Agent Card from a `.fafa`: every field comes from the document, and
113
125
  * `capabilities.extensions` holds exactly the extensions passed (none by default).
@@ -154,10 +166,25 @@ export declare function fafaDomain(fafa: FafaDoc): string;
154
166
  export declare function fafaHandle(fafa: FafaDoc): string;
155
167
  /** MCP names are reverse-DNS: example.com + weather → com.example/weather. */
156
168
  export declare function mcpName(fafa: FafaDoc): string;
157
- /** The MCP Server Card for a remote MCP server. */
158
- export declare function projectServerCard(fafa: FafaDoc): Record<string, unknown>;
159
- /** The MCP Registry `server.json` (publishing it stays the owner's step). */
160
- export declare function projectServerJson(fafa: FafaDoc): Record<string, unknown>;
169
+ /** The `.fafa`'s MCP endpoints at an http(s) URL — what a Server Card describes. */
170
+ export declare function mcpRemotes(fafa: FafaDoc): Array<{
171
+ type: string;
172
+ url: string;
173
+ }>;
174
+ /** True when the `.fafa` gives a registry entry: a package or a remote MCP URL. */
175
+ export declare function hasRegistryEntry(fafa: FafaDoc): boolean;
176
+ /** The registry identity from the `.fafa`: `name`, and `title` when it has one. */
177
+ export declare function registryIdentity(fafa: FafaDoc): {
178
+ name: string;
179
+ title?: string;
180
+ };
181
+ /** The MCP Server Card for a remote MCP server. With a project.faf (`faf`,
182
+ * BEST) it carries FAF's context block at `_meta["one.faf/context"]`. */
183
+ export declare function projectServerCard(fafa: FafaDoc, faf?: FafData, opts?: ContextBlockOptions): Record<string, unknown>;
184
+ /** The MCP Registry `server.json` (publishing it stays the owner's step). With
185
+ * a project.faf (`faf`, BEST) it carries FAF's context block in the registry's
186
+ * publisher-provided `_meta`. */
187
+ export declare function projectServerJson(fafa: FafaDoc, faf?: FafData, opts?: ContextBlockOptions): Record<string, unknown>;
161
188
  export type PackCard = 'a2a' | 'server_card' | 'server_json' | 'ai_catalog' | 'ard' | 'fafa';
162
189
  export interface CatalogRow {
163
190
  identifier: string;
@@ -168,11 +195,21 @@ export interface CatalogRow {
168
195
  version?: string;
169
196
  updatedAt: string;
170
197
  }
171
- /** One row per card the domain serves: the A2A card, the Server Card, and the `.fafa` only when asked. */
172
- export declare function catalogRows(fafa: FafaDoc, cards: PackCard[], opts?: {
198
+ /** Options for the catalog rows. */
199
+ export interface CatalogRowOptions {
200
+ /** `updatedAt` for the rows; otherwise now. */
173
201
  now?: string;
202
+ /** List the `.fafa` itself (served at /.well-known/fafa). Default true: it is
203
+ * the source of the cards — what makes them BETTER. */
174
204
  listFafa?: boolean;
175
- }): CatalogRow[];
205
+ /** Public URL of the A2A card; default the domain's /.well-known/agent-card.json. */
206
+ a2aCardUrl?: string;
207
+ /** An A2A door when the `.fafa` names none (as `faf cards --door-url`). */
208
+ doorUrl?: string;
209
+ }
210
+ /** One row per card the domain serves: the A2A card (when the `.fafa` names an
211
+ * A2A door), the Server Card (when it names a remote MCP URL), and the `.fafa`. */
212
+ export declare function catalogRows(fafa: FafaDoc, cards: PackCard[], opts?: CatalogRowOptions): CatalogRow[];
176
213
  /** Who publishes a catalog: AI Catalog's `host` object. */
177
214
  export interface CatalogHost {
178
215
  displayName: string;
@@ -189,10 +226,7 @@ export interface CatalogHost {
189
226
  */
190
227
  export declare function catalogHost(fafa: FafaDoc): CatalogHost | undefined;
191
228
  /** The AI Catalog for the domain: every row above, with the host named. */
192
- export declare function projectAiCatalog(fafa: FafaDoc, cards: PackCard[], opts?: {
193
- now?: string;
194
- listFafa?: boolean;
195
- }): Record<string, unknown>;
229
+ export declare function projectAiCatalog(fafa: FafaDoc, cards: PackCard[], opts?: CatalogRowOptions): Record<string, unknown>;
196
230
  /**
197
231
  * The search hints ARD reads, from the `.fafa`: `metadata.cards.keywords` and
198
232
  * `metadata.cards.examples`. An entry with no `representativeQueries` is, in
@@ -206,19 +240,20 @@ export declare function ardHints(fafa: FafaDoc): {
206
240
  /** The ARD manifest: the catalog, plus the search hints ARD reads. ARD builds
207
241
  * on ai-catalog (spec §4), so the document is the same shape — the entries
208
242
  * carry more. */
209
- export declare function projectArd(fafa: FafaDoc, cards: PackCard[], opts?: {
210
- now?: string;
211
- listFafa?: boolean;
212
- }): Record<string, unknown>;
213
- export interface PackOptions {
243
+ export declare function projectArd(fafa: FafaDoc, cards: PackCard[], opts?: CatalogRowOptions): Record<string, unknown>;
244
+ export interface PackOptions extends ContextBlockOptions {
214
245
  /** Which cards to build; the `.fafa` is always written. */
215
246
  cards: PackCard[];
216
247
  /** `updatedAt` for catalog rows (tests); otherwise now. */
217
248
  now?: string;
218
- /** List the `.fafa` itself in the catalog and ARD manifest (it is then served at /.well-known/fafa). */
249
+ /** List the `.fafa` itself in the catalog and ARD manifest (it is then served
250
+ * at /.well-known/fafa). Default true; `false` leaves it out. */
219
251
  listFafa?: boolean;
220
- /** Extensions to put on the A2A card; none by default. */
252
+ /** Extensions to put on the A2A card, besides FAF's own (added with `faf`). */
221
253
  a2aExtensions?: A2AExtension[];
254
+ /** project.faf (BEST): adds FAF's context block to the A2A card, the Server
255
+ * Card and server.json. Without it the cards are plain (BETTER). */
256
+ faf?: FafData;
222
257
  }
223
258
  export interface Pack {
224
259
  fafa: FafaDoc;
@@ -1,4 +1,5 @@
1
1
  import type { FafData } from '../core/types.js';
2
+ export { REGISTRY_PUBLISHER_KEY, fafContextBlock, registryMeta } from './context-block.js';
2
3
  /**
3
4
  * Build an MCP Server Card (SEP-2127) from a .faf.
4
5
  *
@@ -25,27 +26,8 @@ export interface ServerCardOptions {
25
26
  /** Override timestamp (tests); otherwise .faf `generated`, else now. */
26
27
  now?: string;
27
28
  }
28
- /**
29
- * The canonical FAF context-block — the value of `_meta["one.faf/context"]`,
30
- * identical across every surface (Server Card, registry `server.json`, `.fafa`):
31
- * one context, every door. Honest-first: no score baked (it would go stale on
32
- * disk); it points to the .faf and asserts the score is deterministic.
33
- */
34
- export declare function fafContextBlock(data: FafData, opts?: ServerCardOptions): Record<string, unknown>;
35
29
  /** Build the Server Card object from .faf data. */
36
30
  export declare function buildServerCard(data: FafData, opts?: ServerCardOptions): Record<string, unknown>;
37
- export declare const REGISTRY_PUBLISHER_KEY = "io.modelcontextprotocol.registry/publisher-provided";
38
- /**
39
- * Build the `_meta` for an MCP Registry `server.json`.
40
- *
41
- * The SAME canonical context-block as the Server Card, but nested under
42
- * `io.modelcontextprotocol.registry/publisher-provided` — the ONLY `_meta` key
43
- * the official registry preserves on publish. Top-level keys (the way the card
44
- * carries `one.faf/context`) are silently dropped by the registry. Throws if the
45
- * block exceeds the registry's 4KB cap. Merge the result into an existing
46
- * `server.json` `_meta`; don't regenerate the manifest (packages/mcpb are tuned).
47
- */
48
- export declare function registryMeta(data: FafData, opts?: ServerCardOptions): Record<string, unknown>;
49
31
  /** The canonical reverse-DNS registry name, e.g. `one.faf/claude-faf-mcp`.
50
32
  *
51
33
  * HOMEPAGE REQUIRED: the namespace is derived from `project.homepage`'s host
@@ -99,8 +81,9 @@ export interface ServerJsonIdentity {
99
81
  title?: string;
100
82
  /** A version to set (`--set-version`); when undefined the file's own is kept. */
101
83
  version?: string;
102
- /** The `_meta` faf writes ({@link registryMeta}). */
103
- meta: Record<string, unknown>;
84
+ /** The `_meta` faf writes ({@link registryMeta}); absent for a plain
85
+ * registry identity from a .fafa (BETTER), which leaves `_meta` as it is. */
86
+ meta?: Record<string, unknown>;
104
87
  }
105
88
  /**
106
89
  * Put faf's identity into the text of a registry `server.json`, changing