faf-cli 7.10.1 → 7.12.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.
- package/README.md +13 -15
- package/dist/cli.js +216 -214
- package/dist/cli.js.map +23 -21
- package/dist/core/drift.d.ts +55 -0
- package/dist/detect/assemble.d.ts +9 -0
- package/dist/detect/enrich.d.ts +11 -0
- package/dist/index.d.ts +15 -4
- package/dist/index.js +130 -118
- package/dist/index.js.map +16 -7
- package/dist/interop/agents.d.ts +15 -0
- package/dist/interop/cards.d.ts +4 -1
- package/dist/interop/claude.d.ts +35 -0
- package/dist/interop/copilot-instructions.d.ts +26 -0
- package/dist/interop/cursorrules.d.ts +5 -0
- package/dist/interop/gemini.d.ts +12 -0
- package/dist/interop/inject.d.ts +45 -0
- package/dist/interop/labels.d.ts +26 -0
- package/dist/interop/projecthtml.d.ts +3 -1
- package/dist/interop/servercard.d.ts +4 -2
- package/package.json +1 -1
- package/project.faf +3 -3
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FafData } from '../core/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Author a BETTER-shaped AGENTS.md from .faf data (+ repo enrichment at export).
|
|
4
|
+
*
|
|
5
|
+
* Deterministic projection from curated TRUTH — facts, not hallucinated prose
|
|
6
|
+
* (Gloaguen: LLM freewrite hurts). Sections: orientation · setup · verify ·
|
|
7
|
+
* map · conventions · three-tier guardrails · DoD · when stuck · security ·
|
|
8
|
+
* commit. Human Context (who/why marketing) is intentionally omitted — that
|
|
9
|
+
* belongs in README / project.faf, not agent ops.
|
|
10
|
+
*
|
|
11
|
+
* Design: BETTER guide + hand exemplar (faf-cli AGENTS.md) + agents-md-facts.
|
|
12
|
+
*/
|
|
13
|
+
export declare function renderAgentsMd(data: FafData): string;
|
|
14
|
+
/** Write AGENTS.md — non-destructive: injects/updates the faf block, preserves the rest. */
|
|
15
|
+
export declare function writeAgentsMd(dir: string, data: FafData): void;
|
package/dist/interop/cards.d.ts
CHANGED
|
@@ -106,7 +106,10 @@ export declare function findFafaFile(dir?: string): string | null;
|
|
|
106
106
|
export declare function a2aEndpoints(fafa: FafaDoc): FafaEndpoint[];
|
|
107
107
|
/** Authored A2A endpoints, else a single `doorUrl`. Never invents a door. */
|
|
108
108
|
export declare function a2aDoors(fafa: FafaDoc, opts?: ProjectCardsOptions): FafaEndpoint[];
|
|
109
|
-
|
|
109
|
+
/** Build the A2A Agent Card (JSON) from a .fafa + .faf. */
|
|
110
|
+
export declare function buildA2ACard(fafa: FafaDoc, faf: FafData, opts?: ProjectCardsOptions): ProjectedA2A;
|
|
111
|
+
/** @deprecated Use {@link buildA2ACard}. Removed in the next major. */
|
|
112
|
+
export declare const generateA2ACard: typeof buildA2ACard;
|
|
110
113
|
export declare function catalogEntriesFor(fafa: FafaDoc, faf: FafData, opts?: ProjectCardsOptions): CatalogEntry[];
|
|
111
114
|
/** Upsert projector entries into an existing catalog. Leaves unknown rows alone.
|
|
112
115
|
* On match, only url / type / updatedAt move — host copy (title, tags) stays. */
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { FafData } from '../core/types.js';
|
|
2
|
+
/** Read CLAUDE.md from a directory */
|
|
3
|
+
export declare function readClaudeMd(dir: string): string | null;
|
|
4
|
+
/** Write CLAUDE.md — non-destructive: injects/updates the faf block, preserves the rest. */
|
|
5
|
+
export declare function writeClaudeMd(dir: string, content: string): void;
|
|
6
|
+
/** Get mtime of CLAUDE.md */
|
|
7
|
+
export declare function claudeMdMtime(dir: string): number | null;
|
|
8
|
+
/** Optional knobs for the 2-line FAF stamp. */
|
|
9
|
+
export interface FafMetaOpts {
|
|
10
|
+
/** Canonical structured-truth file the md claims (default `project.faf`).
|
|
11
|
+
* Use for AI-context md (CLAUDE/GEMINI/AGENTS/.cursorrules). */
|
|
12
|
+
claim?: string;
|
|
13
|
+
/** Role identifier (`readme`, `changelog`, `skill`, …).
|
|
14
|
+
* Use for repo-meta md whose primary reader is human. Mutually exclusive with `claim`. */
|
|
15
|
+
doc?: string;
|
|
16
|
+
/** Current AI-readiness score (0–100). */
|
|
17
|
+
score?: number;
|
|
18
|
+
/** Sister-product family — `FAF` (default), `TAF`, `WJTTC`, … */
|
|
19
|
+
family?: string;
|
|
20
|
+
/** Other docs in the repo the reader should know about. */
|
|
21
|
+
siblings?: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build the canonical 2-line FAF stamp.
|
|
25
|
+
*
|
|
26
|
+
* Line 1 — positional identity: `name | lang | type | description`
|
|
27
|
+
* Line 2 — key=value navigation/state: `claim=… | score=… | family=… | siblings=…`
|
|
28
|
+
*
|
|
29
|
+
* Spec: `memory/cross-ai-2-line-meta-stamp.md`. Issue #64.
|
|
30
|
+
*/
|
|
31
|
+
export declare function fafMetaTag(data: FafData, opts?: FafMetaOpts): string;
|
|
32
|
+
/** Render CLAUDE.md content from .faf data */
|
|
33
|
+
export declare function renderClaudeMd(data: FafData): string;
|
|
34
|
+
/** Extract project data from CLAUDE.md content (pull direction) */
|
|
35
|
+
export declare function parseClaudeMd(content: string): Partial<FafData>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { FafData } from '../core/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Render `.github/copilot-instructions.md` content from .faf data.
|
|
4
|
+
*
|
|
5
|
+
* GitHub Copilot's repository-wide custom-instructions file — the WIDEST-supported
|
|
6
|
+
* instruction surface (web chat, code review, VS Code, JetBrains, Visual Studio,
|
|
7
|
+
* Eclipse, Xcode, Copilot CLI, coding agent), injected into EVERY request.
|
|
8
|
+
*
|
|
9
|
+
* Built to GitHub's published custom-instructions guidance:
|
|
10
|
+
* short, self-contained, imperative INSTRUCTIONS — not a metadata dump. So we lead
|
|
11
|
+
* with the goal as a prose overview, Title-Case labels (acronym-aware), surface the
|
|
12
|
+
* build/run steps as copy-pasteable commands, keep it compact, and avoid every named
|
|
13
|
+
* anti-pattern (no tone/length rules, no external references). Deliberately NOT a
|
|
14
|
+
* clone of AGENTS.md (which it outranks in-repo) — they are complementary.
|
|
15
|
+
*
|
|
16
|
+
* Strictly faithful to the .faf — nothing invented (GitHub bans speculative,
|
|
17
|
+
* task-specific instructions). Future-proof: the command section + Title-Caser
|
|
18
|
+
* already consume the richer slots Option B will add (test/lint/run, …), so this
|
|
19
|
+
* emitter is built once and grows with the data.
|
|
20
|
+
*/
|
|
21
|
+
export declare function renderCopilotInstructions(data: FafData): string;
|
|
22
|
+
/**
|
|
23
|
+
* Write `.github/copilot-instructions.md` — non-destructive (injects/updates the
|
|
24
|
+
* faf block, preserves the rest). Creates the `.github/` directory if absent.
|
|
25
|
+
*/
|
|
26
|
+
export declare function writeCopilotInstructions(dir: string, data: FafData): void;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { FafData } from '../core/types.js';
|
|
2
|
+
/** Render .cursorrules content from .faf data */
|
|
3
|
+
export declare function renderCursorrules(data: FafData): string;
|
|
4
|
+
/** Write .cursorrules — non-destructive: injects/updates the faf block (hash-comment markers), preserves the rest. */
|
|
5
|
+
export declare function writeCursorrules(dir: string, data: FafData): void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FafData } from '../core/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Render GEMINI.md content from .faf data (+ repo enrichment at export).
|
|
4
|
+
*
|
|
5
|
+
* Matches Gemini CLI's own GEMINI.md convention (hierarchical, concatenation-
|
|
6
|
+
* friendly, `@file.md`-importable): commands, key files, and confirmation-
|
|
7
|
+
* required actions — not the AGENTS.md BETTER ladder, which is a different
|
|
8
|
+
* spec for a different reader.
|
|
9
|
+
*/
|
|
10
|
+
export declare function renderGeminiMd(data: FafData): string;
|
|
11
|
+
/** Write GEMINI.md — non-destructive: injects/updates the faf block, preserves the rest. */
|
|
12
|
+
export declare function writeGeminiMd(dir: string, data: FafData): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block markers for the faf-managed front section.
|
|
3
|
+
*
|
|
4
|
+
* Markdown files (AGENTS.md, CLAUDE.md, GEMINI.md) use HTML comments; non-markdown
|
|
5
|
+
* files (.cursorrules) pass hash-comment markers via the `start`/`end` args.
|
|
6
|
+
*/
|
|
7
|
+
export declare const FAF_START = "<!-- faf:start -->";
|
|
8
|
+
export declare const FAF_END = "<!-- faf:end -->";
|
|
9
|
+
/**
|
|
10
|
+
* Locate the faf-managed block in `text`: the first START marker line and the
|
|
11
|
+
* first END marker line after it. Returns the char range covering both marker
|
|
12
|
+
* lines (terminator of the END line excluded), or null when there is no
|
|
13
|
+
* complete block.
|
|
14
|
+
*
|
|
15
|
+
* Markers are matched as WHOLE LINES at column 0, never as substrings. Substring
|
|
16
|
+
* search was a real bug (7.1.4–7.11.0): renderAgentsMd quoted the marker tokens
|
|
17
|
+
* in its own blockquote, so on every re-run `indexOf(end)` hit the quote, cut
|
|
18
|
+
* the old block in half and appended its stale tail below the new block —
|
|
19
|
+
* `faf export --agents` grew AGENTS.md by ~49 lines per run. The same happened
|
|
20
|
+
* to users who documented the markers in a code fence above the block.
|
|
21
|
+
*
|
|
22
|
+
* Two passes. The first skips START candidates inside fenced code, so a fenced
|
|
23
|
+
* example is not mistaken for the block. Fence detection is a plain toggle and
|
|
24
|
+
* Markdown has shapes it misreads (list-item fences, ```` around ```, a stray
|
|
25
|
+
* unclosed fence), so if the first pass finds nothing the second ignores fences
|
|
26
|
+
* entirely. A miss must never be silent: the caller treats "no block" as a
|
|
27
|
+
* user file and prefixes — it does not overwrite.
|
|
28
|
+
*/
|
|
29
|
+
export declare function findFafBlock(text: string, start?: string, end?: string): {
|
|
30
|
+
start: number;
|
|
31
|
+
end: number;
|
|
32
|
+
} | null;
|
|
33
|
+
/**
|
|
34
|
+
* Non-destructively write a faf-managed block into a file.
|
|
35
|
+
*
|
|
36
|
+
* - file does not exist → create it containing just the block
|
|
37
|
+
* - file has the markers → replace ONLY the content between them (update in place)
|
|
38
|
+
* - legacy faf file → metastamp-led, no marker lines: reclaim in place
|
|
39
|
+
* - file exists, no block → PREFIX the block; everything the user wrote is preserved
|
|
40
|
+
*
|
|
41
|
+
* Idempotent: re-running updates the managed block in place and never duplicates
|
|
42
|
+
* it or touches a byte the user owns. faf owns what's between the markers; the
|
|
43
|
+
* user owns everything else. Enhance, never replace.
|
|
44
|
+
*/
|
|
45
|
+
export declare function injectFafBlock(path: string, block: string, start?: string, end?: string): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared label formatting for the AI-context emitters (CLAUDE.md, AGENTS.md,
|
|
3
|
+
* .github/copilot-instructions.md). ONE acronym-aware Title-Caser so `api_type`
|
|
4
|
+
* renders "API Type" everywhere — not "Api Type" in one file and a raw
|
|
5
|
+
* `api_type` key in another. Unified 2026-06-25 (faf-cli 6.15.1).
|
|
6
|
+
*
|
|
7
|
+
* Labels are registry-first: `slotLabel()` reads the canonical label from the
|
|
8
|
+
* slot registry ("know your stack"); the acronym-aware `titleLabel()` is only a
|
|
9
|
+
* fallback for off-registry freeform keys.
|
|
10
|
+
*/
|
|
11
|
+
/** All-caps acronym tokens that stay upper-cased inside a Title-Cased label. */
|
|
12
|
+
export declare const ACRONYMS: Set<string>;
|
|
13
|
+
/**
|
|
14
|
+
* snake_case → Title Case, acronym-aware.
|
|
15
|
+
* `api_type` → "API Type", `mcp_sdk` → "MCP SDK", `runtime` → "Runtime".
|
|
16
|
+
*/
|
|
17
|
+
export declare function titleLabel(key: string): string;
|
|
18
|
+
/** A slot value that carries real content (not empty, not slotignored). */
|
|
19
|
+
export declare function filled(v: unknown): v is string;
|
|
20
|
+
/**
|
|
21
|
+
* The canonical display label for a .faf slot path, sourced from the slot
|
|
22
|
+
* registry ("know your stack") — `stack.cicd` → "CI/CD", `stack.api_type` → "API".
|
|
23
|
+
* Resolves legacy OR canonical paths (SLOT_BY_PATH is dual-keyed). Falls back to
|
|
24
|
+
* the acronym-aware Title-Caser for off-registry freeform keys.
|
|
25
|
+
*/
|
|
26
|
+
export declare function slotLabel(path: string): string;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { FafData, ScoreResult } from '../core/types.js';
|
|
2
2
|
/** Render project.faf data + its score into a self-contained HTML string. */
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function renderProjectHtml(data: FafData, result: ScoreResult, fafPath?: string): string;
|
|
4
4
|
/** Write project.html beside project.faf (repo root). */
|
|
5
5
|
export declare function writeProjectHtml(dir: string, data: FafData, result: ScoreResult, fafPath?: string): void;
|
|
6
|
+
/** @deprecated Use {@link renderProjectHtml}. Removed in the next major. */
|
|
7
|
+
export declare const generateProjectHtml: typeof renderProjectHtml;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FafData } from '../core/types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Build an MCP Server Card (SEP-2127) from a .faf.
|
|
4
4
|
*
|
|
5
5
|
* The card is a published discovery manifest. By design it carries the FAF
|
|
6
6
|
* context-block in `_meta["one.faf/context"]` — so every Server Card produced
|
|
@@ -33,7 +33,7 @@ export interface ServerCardOptions {
|
|
|
33
33
|
*/
|
|
34
34
|
export declare function fafContextBlock(data: FafData, opts?: ServerCardOptions): Record<string, unknown>;
|
|
35
35
|
/** Build the Server Card object from .faf data. */
|
|
36
|
-
export declare function
|
|
36
|
+
export declare function buildServerCard(data: FafData, opts?: ServerCardOptions): Record<string, unknown>;
|
|
37
37
|
export declare const REGISTRY_PUBLISHER_KEY = "io.modelcontextprotocol.registry/publisher-provided";
|
|
38
38
|
/**
|
|
39
39
|
* Build the `_meta` for an MCP Registry `server.json`.
|
|
@@ -68,3 +68,5 @@ export declare function registryTitle(data: FafData): string | undefined;
|
|
|
68
68
|
* `<streamable-http-url>/server-card` (no longer `.well-known`); serve the
|
|
69
69
|
* emitted file there as `application/mcp-server-card+json`. */
|
|
70
70
|
export declare function writeServerCard(dir: string, data: FafData, opts?: ServerCardOptions): string;
|
|
71
|
+
/** @deprecated Use {@link buildServerCard}. Removed in the next major. */
|
|
72
|
+
export declare const generateServerCard: typeof buildServerCard;
|
package/package.json
CHANGED
package/project.faf
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
faf_version: "3.0"
|
|
2
2
|
project:
|
|
3
3
|
name: faf-cli
|
|
4
|
-
version: "7.
|
|
5
|
-
goal: "CLI for IANA-registered `.faf` + `.fafm` — context DNA and portable agent memory. TypeScript, Bun-native since v6. package faf-cli v7.
|
|
4
|
+
version: "7.12.0"
|
|
5
|
+
goal: "CLI for IANA-registered `.faf` + `.fafm` — context DNA and portable agent memory. TypeScript, Bun-native since v6. package faf-cli v7.12.0 The Open Renderers Edition."
|
|
6
6
|
main_language: TypeScript
|
|
7
7
|
type: cli # found: package.json bin
|
|
8
8
|
# Commands + key_files feed `faf export --agents` (hand values win over detection).
|
|
@@ -58,7 +58,7 @@ human_context:
|
|
|
58
58
|
what: Persistent AI Context Standard — project DNA for AI. IANA-registered. Anthropic-merged.
|
|
59
59
|
why: Eliminates 91% context re-discovery tax — define once, AI remembers forever
|
|
60
60
|
where: npm registry, Homebrew, GitHub
|
|
61
|
-
when: Production since September 2025; Bun-native since v6; current package 7.
|
|
61
|
+
when: Production since September 2025; Bun-native since v6; current package 7.12.0
|
|
62
62
|
how: bunx faf-cli auto, then project.faf versions with your code — faf show renders it human-visible
|
|
63
63
|
monorepo:
|
|
64
64
|
packages_count: slotignored
|