faf-python-sdk 1.3.1__tar.gz → 1.4.0__tar.gz
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.
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/CHANGELOG.md +25 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/PKG-INFO +8 -8
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/README.md +7 -7
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/faf_sdk/__init__.py +13 -5
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/faf_sdk/interop.py +49 -5
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/pyproject.toml +1 -1
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/tests/test_interop.py +48 -17
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/.github/workflows/pypi.yml +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/.github/workflows/testpypi.yml +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/.gitignore +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/CLAUDE.md +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/CODE_OF_CONDUCT.md +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/CONTRIBUTING.md +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/LICENSE +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/SECURITY.md +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/docs/GROK-INTEGRATION.md +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/docs/TECHNICAL-SPEC.md +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/examples/basic_usage.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/examples/grok_integration.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/faf_sdk/dart_detection.json +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/faf_sdk/detect.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/faf_sdk/discovery.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/faf_sdk/mk4.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/faf_sdk/parser.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/faf_sdk/py.typed +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/faf_sdk/types.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/faf_sdk/validator.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/project.faf +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/scripts/sync-dart-spec.sh +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/tests/__init__.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/tests/dart_parity_fixtures.json +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/tests/stress_test.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/tests/test_dart_parity.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/tests/test_discovery.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/tests/test_mk4.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/tests/test_parser.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/tests/test_validator.py +0 -0
- {faf_python_sdk-1.3.1 → faf_python_sdk-1.4.0}/tests/test_wjttc.py +0 -0
|
@@ -3,6 +3,31 @@
|
|
|
3
3
|
All notable changes to faf-python-sdk are documented here.
|
|
4
4
|
Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
5
5
|
|
|
6
|
+
## [1.4.0] - 2026-09-08 — The Interop Edition
|
|
7
|
+
|
|
8
|
+
The interop functions get their real names: `author_agents_md` / `author_gemini_md` are public, `render_*` is the impl, `generate_*` is deprecated (removed in 2.0).
|
|
9
|
+
|
|
10
|
+
1.3.1 kept `generate_*` as "internal identifiers" — but a name that surfaces
|
|
11
|
+
reflexively when reasoning about the tool lands in `tools/list` descriptions,
|
|
12
|
+
host UIs, and docs. "Internal-only" holds only until someone documents it, so
|
|
13
|
+
the public name has to be right now.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- `author_agents_md(faf)` / `author_gemini_md(faf)` — the public API names, in
|
|
17
|
+
the "faf authors" voice used on every documented surface. This is what
|
|
18
|
+
`faf_sdk.interop.__all__` advertises.
|
|
19
|
+
- `render_agents_md(faf)` / `render_gemini_md(faf)` — the impl names: pure
|
|
20
|
+
`dict -> str` projection, pairs with the `write_*` helpers, greps clean. Same
|
|
21
|
+
split the canonical faf-cli TS uses.
|
|
22
|
+
|
|
23
|
+
### Deprecated
|
|
24
|
+
- `generate_agents_md` / `generate_gemini_md` — still work, now emit
|
|
25
|
+
`DeprecationWarning`, removed in 2.0. Point at `author_*`.
|
|
26
|
+
|
|
27
|
+
### Notes
|
|
28
|
+
- Additive + back-compatible: existing `from faf_sdk import generate_agents_md`
|
|
29
|
+
keeps working. No output change — the authored Markdown is byte-identical.
|
|
30
|
+
|
|
6
31
|
## [1.3.1] - 2026-09-07 — The Interop Edition
|
|
7
32
|
|
|
8
33
|
Docs / copy patch — no API change.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: faf-python-sdk
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Persistent project context for Python — parse, validate, and score `.faf` files. The foundation other Python FAF tools (gemini-faf-mcp, custom MCP servers, CI validators) build on. IANA-registered application/vnd.faf+yaml.
|
|
5
5
|
Project-URL: Homepage, https://faf.one
|
|
6
6
|
Project-URL: Documentation, https://github.com/Wolfe-Jam/faf-python-sdk
|
|
@@ -41,24 +41,24 @@ The foundation other Python FAF tools build on. If you're building MCP servers,
|
|
|
41
41
|
[](https://builder.faf.one)
|
|
42
42
|
[](https://pypi.org/project/faf-python-sdk/)
|
|
43
43
|
[](https://pypi.org/project/faf-python-sdk/)
|
|
44
|
-
[](https://github.com/Wolfe-Jam/faf-python-sdk)
|
|
45
45
|
[](https://www.iana.org/assignments/media-types/application/vnd.faf+yaml)
|
|
46
46
|
|
|
47
47
|
**Media Type:** `application/vnd.faf+yaml` (IANA registered)
|
|
48
48
|
|
|
49
|
-
## What's New in v1.
|
|
49
|
+
## What's New in v1.4.0 — The Interop Edition
|
|
50
50
|
|
|
51
|
-
The
|
|
51
|
+
The interop functions get their real names: `author_agents_md` / `author_gemini_md` are public, `render_*` is the impl, `generate_*` is deprecated (removed in 2.0).
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Output is byte-identical — a naming change, not a behaviour change. Existing `from faf_sdk import generate_agents_md` keeps working, now with a `DeprecationWarning`.
|
|
54
54
|
|
|
55
|
-
`faf_sdk.interop` — `
|
|
55
|
+
`faf_sdk.interop` — `author_agents_md(faf)` and `author_gemini_md(faf)`, Python ports of faf-cli's `src/interop/agents.ts` + `gemini.ts`, in parity with the canonical TypeScript. Deterministic BETTER-shaped projection: setup (install→build→dev ordered) · tests · layout · conventions · three-tier guardrails · definition of done · security · commit · stack. Human Context (who/why marketing) is intentionally omitted from AGENTS.md — it belongs in the README / .faf DNA, not agent ops.
|
|
56
56
|
|
|
57
57
|
```python
|
|
58
|
-
from faf_sdk import parse_file,
|
|
58
|
+
from faf_sdk import parse_file, author_agents_md
|
|
59
59
|
|
|
60
60
|
faf = parse_file("project.faf")
|
|
61
|
-
print(
|
|
61
|
+
print(author_agents_md(faf.data.raw)) # takes the raw dict — carries top-level commands / key_files / security
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
Any Python FAF tool that authors an AI-context file wraps this now — never hand-roll one. `gemini-faf-mcp` 2.7.0's `faf_agents` / `faf_gemini` are the reference wrappers.
|
|
@@ -9,24 +9,24 @@ The foundation other Python FAF tools build on. If you're building MCP servers,
|
|
|
9
9
|
[](https://builder.faf.one)
|
|
10
10
|
[](https://pypi.org/project/faf-python-sdk/)
|
|
11
11
|
[](https://pypi.org/project/faf-python-sdk/)
|
|
12
|
-
[](https://github.com/Wolfe-Jam/faf-python-sdk)
|
|
13
13
|
[](https://www.iana.org/assignments/media-types/application/vnd.faf+yaml)
|
|
14
14
|
|
|
15
15
|
**Media Type:** `application/vnd.faf+yaml` (IANA registered)
|
|
16
16
|
|
|
17
|
-
## What's New in v1.
|
|
17
|
+
## What's New in v1.4.0 — The Interop Edition
|
|
18
18
|
|
|
19
|
-
The
|
|
19
|
+
The interop functions get their real names: `author_agents_md` / `author_gemini_md` are public, `render_*` is the impl, `generate_*` is deprecated (removed in 2.0).
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Output is byte-identical — a naming change, not a behaviour change. Existing `from faf_sdk import generate_agents_md` keeps working, now with a `DeprecationWarning`.
|
|
22
22
|
|
|
23
|
-
`faf_sdk.interop` — `
|
|
23
|
+
`faf_sdk.interop` — `author_agents_md(faf)` and `author_gemini_md(faf)`, Python ports of faf-cli's `src/interop/agents.ts` + `gemini.ts`, in parity with the canonical TypeScript. Deterministic BETTER-shaped projection: setup (install→build→dev ordered) · tests · layout · conventions · three-tier guardrails · definition of done · security · commit · stack. Human Context (who/why marketing) is intentionally omitted from AGENTS.md — it belongs in the README / .faf DNA, not agent ops.
|
|
24
24
|
|
|
25
25
|
```python
|
|
26
|
-
from faf_sdk import parse_file,
|
|
26
|
+
from faf_sdk import parse_file, author_agents_md
|
|
27
27
|
|
|
28
28
|
faf = parse_file("project.faf")
|
|
29
|
-
print(
|
|
29
|
+
print(author_agents_md(faf.data.raw)) # takes the raw dict — carries top-level commands / key_files / security
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
Any Python FAF tool that authors an AI-context file wraps this now — never hand-roll one. `gemini-faf-mcp` 2.7.0's `faf_agents` / `faf_gemini` are the reference wrappers.
|
|
@@ -25,7 +25,15 @@ from .validator import validate, ValidationResult
|
|
|
25
25
|
from .mk4 import score_faf, Mk4Result, SlotState, LicenseTier
|
|
26
26
|
from .discovery import find_faf_file, find_project_root, load_fafignore
|
|
27
27
|
from .detect import detect_dart_project, DartProject
|
|
28
|
-
from .interop import
|
|
28
|
+
from .interop import (
|
|
29
|
+
author_agents_md,
|
|
30
|
+
author_gemini_md,
|
|
31
|
+
render_agents_md,
|
|
32
|
+
render_gemini_md,
|
|
33
|
+
generate_agents_md, # deprecated alias — removed in 2.0
|
|
34
|
+
generate_gemini_md, # deprecated alias — removed in 2.0
|
|
35
|
+
faf_meta_tag,
|
|
36
|
+
)
|
|
29
37
|
from .types import (
|
|
30
38
|
FafData,
|
|
31
39
|
ProjectInfo,
|
|
@@ -36,7 +44,7 @@ from .types import (
|
|
|
36
44
|
AIScoring
|
|
37
45
|
)
|
|
38
46
|
|
|
39
|
-
__version__ = "1.
|
|
47
|
+
__version__ = "1.4.0"
|
|
40
48
|
__all__ = [
|
|
41
49
|
# Parser
|
|
42
50
|
"parse",
|
|
@@ -58,9 +66,9 @@ __all__ = [
|
|
|
58
66
|
# Detection (Dart/Flutter — A+B hybrid, parity with faf-cli)
|
|
59
67
|
"detect_dart_project",
|
|
60
68
|
"DartProject",
|
|
61
|
-
# Interop — AGENTS.md / GEMINI.md
|
|
62
|
-
"
|
|
63
|
-
"
|
|
69
|
+
# Interop — AGENTS.md / GEMINI.md authoring (parity with faf-cli src/interop)
|
|
70
|
+
"author_agents_md",
|
|
71
|
+
"author_gemini_md",
|
|
64
72
|
"faf_meta_tag",
|
|
65
73
|
# Types
|
|
66
74
|
"FafData",
|
|
@@ -10,13 +10,23 @@ not agent ops.
|
|
|
10
10
|
Both take the raw parsed .faf dict (`FafFile.data.raw`) — the .faf format
|
|
11
11
|
carries top-level `commands` / `key_files` / `security` that the typed model
|
|
12
12
|
doesn't surface.
|
|
13
|
+
|
|
14
|
+
Naming: the impl functions are ``render_agents_md`` / ``render_gemini_md``
|
|
15
|
+
(pure ``dict -> str`` projection, pairs with the writers). The public API
|
|
16
|
+
name is ``author_agents_md`` / ``author_gemini_md`` — the surface consumers
|
|
17
|
+
import, in the "faf authors" voice used on every documented surface.
|
|
18
|
+
``generate_*`` is a deprecated alias, removed in 2.0.
|
|
13
19
|
"""
|
|
14
20
|
|
|
15
21
|
from __future__ import annotations
|
|
16
22
|
|
|
23
|
+
import warnings
|
|
17
24
|
from typing import Any
|
|
18
25
|
|
|
19
|
-
__all__ = [
|
|
26
|
+
__all__ = [
|
|
27
|
+
"author_agents_md", "author_gemini_md",
|
|
28
|
+
"faf_meta_tag", "title_label", "slot_label",
|
|
29
|
+
]
|
|
20
30
|
|
|
21
31
|
# --- shared helpers ----------------------------------------------------------
|
|
22
32
|
|
|
@@ -146,8 +156,11 @@ def _key_files(faf: dict) -> list:
|
|
|
146
156
|
|
|
147
157
|
# --- AGENTS.md -------------------------------------------------------------
|
|
148
158
|
|
|
149
|
-
def
|
|
150
|
-
"""Author a BETTER-shaped AGENTS.md from raw .faf data. Deterministic.
|
|
159
|
+
def render_agents_md(faf: dict) -> str:
|
|
160
|
+
"""Author a BETTER-shaped AGENTS.md from raw .faf data. Deterministic.
|
|
161
|
+
|
|
162
|
+
Public alias: :func:`author_agents_md`.
|
|
163
|
+
"""
|
|
151
164
|
lines: list[str] = []
|
|
152
165
|
|
|
153
166
|
def push(s: str = "") -> None:
|
|
@@ -344,8 +357,11 @@ def generate_agents_md(faf: dict) -> str:
|
|
|
344
357
|
|
|
345
358
|
# --- GEMINI.md ------------------------------------------------------------
|
|
346
359
|
|
|
347
|
-
def
|
|
348
|
-
"""GEMINI.md — Gemini CLI's own convention (hierarchical, @file-importable).
|
|
360
|
+
def render_gemini_md(faf: dict) -> str:
|
|
361
|
+
"""GEMINI.md — Gemini CLI's own convention (hierarchical, @file-importable).
|
|
362
|
+
|
|
363
|
+
Public alias: :func:`author_gemini_md`.
|
|
364
|
+
"""
|
|
349
365
|
lines: list[str] = []
|
|
350
366
|
proj = faf.get("project") or {}
|
|
351
367
|
cmds = _classify_commands(faf)
|
|
@@ -401,3 +417,31 @@ def generate_gemini_md(faf: dict) -> str:
|
|
|
401
417
|
"",
|
|
402
418
|
]
|
|
403
419
|
return "\n".join(lines)
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
# --- public + deprecated names --------------------------------------------
|
|
423
|
+
|
|
424
|
+
#: Public API name for :func:`render_agents_md` — "faf authors" voice.
|
|
425
|
+
author_agents_md = render_agents_md
|
|
426
|
+
#: Public API name for :func:`render_gemini_md`.
|
|
427
|
+
author_gemini_md = render_gemini_md
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
def generate_agents_md(faf: dict) -> str:
|
|
431
|
+
"""Deprecated alias for :func:`author_agents_md`. Removed in 2.0."""
|
|
432
|
+
warnings.warn(
|
|
433
|
+
"generate_agents_md is deprecated; use author_agents_md",
|
|
434
|
+
DeprecationWarning,
|
|
435
|
+
stacklevel=2,
|
|
436
|
+
)
|
|
437
|
+
return render_agents_md(faf)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def generate_gemini_md(faf: dict) -> str:
|
|
441
|
+
"""Deprecated alias for :func:`author_gemini_md`. Removed in 2.0."""
|
|
442
|
+
warnings.warn(
|
|
443
|
+
"generate_gemini_md is deprecated; use author_gemini_md",
|
|
444
|
+
DeprecationWarning,
|
|
445
|
+
stacklevel=2,
|
|
446
|
+
)
|
|
447
|
+
return render_gemini_md(faf)
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "faf-python-sdk"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.4.0"
|
|
8
8
|
description = "Persistent project context for Python — parse, validate, and score `.faf` files. The foundation other Python FAF tools (gemini-faf-mcp, custom MCP servers, CI validators) build on. IANA-registered application/vnd.faf+yaml."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
"""Tests for faf_sdk.interop — AGENTS.md / GEMINI.md
|
|
1
|
+
"""Tests for faf_sdk.interop — AGENTS.md / GEMINI.md authoring."""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from faf_sdk import faf_meta_tag, render_agents_md, render_gemini_md
|
|
4
6
|
from faf_sdk.interop import slot_label, title_label
|
|
5
7
|
|
|
6
8
|
# A representative .faf as the raw parsed dict.
|
|
@@ -64,7 +66,7 @@ def test_faf_meta_tag_two_lines():
|
|
|
64
66
|
# --- AGENTS.md -----------------------------------------------------------
|
|
65
67
|
|
|
66
68
|
def test_agents_md_sections_present():
|
|
67
|
-
md =
|
|
69
|
+
md = render_agents_md(SAMPLE)
|
|
68
70
|
for section in (
|
|
69
71
|
"# AGENTS.md — widget-api",
|
|
70
72
|
"## Setup & build",
|
|
@@ -82,14 +84,14 @@ def test_agents_md_sections_present():
|
|
|
82
84
|
|
|
83
85
|
|
|
84
86
|
def test_agents_md_omits_human_context():
|
|
85
|
-
md =
|
|
87
|
+
md = render_agents_md({**SAMPLE, "human_context": {"who": "devs", "why": "money"}})
|
|
86
88
|
assert "## Human Context" not in md
|
|
87
89
|
assert "## Context" not in md
|
|
88
90
|
assert "money" not in md
|
|
89
91
|
|
|
90
92
|
|
|
91
93
|
def test_agents_md_setup_ordered_install_build_dev():
|
|
92
|
-
md =
|
|
94
|
+
md = render_agents_md(SAMPLE)
|
|
93
95
|
block = md.split("## Setup & build")[1].split("```")[1]
|
|
94
96
|
# first line is the ```bash language tag
|
|
95
97
|
lines = [ln for ln in block.strip().splitlines()][1:]
|
|
@@ -99,7 +101,7 @@ def test_agents_md_setup_ordered_install_build_dev():
|
|
|
99
101
|
|
|
100
102
|
|
|
101
103
|
def test_agents_md_guardrails_always_render_even_with_no_data():
|
|
102
|
-
md =
|
|
104
|
+
md = render_agents_md({"faf_version": "3.0", "project": {"name": "bare"}})
|
|
103
105
|
assert "## Guardrails" in md
|
|
104
106
|
assert "## Definition of Done" in md
|
|
105
107
|
assert "## Commit & PR" in md
|
|
@@ -107,28 +109,28 @@ def test_agents_md_guardrails_always_render_even_with_no_data():
|
|
|
107
109
|
|
|
108
110
|
|
|
109
111
|
def test_agents_md_key_files_table_when_roles_present():
|
|
110
|
-
md =
|
|
112
|
+
md = render_agents_md(SAMPLE)
|
|
111
113
|
assert "| Path | Role |" in md
|
|
112
114
|
assert "| `src/server.ts` | the entry point |" in md
|
|
113
115
|
|
|
114
116
|
|
|
115
117
|
def test_agents_md_security_never_leaks_values():
|
|
116
|
-
md =
|
|
118
|
+
md = render_agents_md(SAMPLE)
|
|
117
119
|
assert "Secrets live in `.env`" in md
|
|
118
120
|
assert "see `.env.example`" in md
|
|
119
121
|
|
|
120
122
|
|
|
121
123
|
def test_agents_md_stack_drops_non_stack_marketing_keys():
|
|
122
|
-
md =
|
|
124
|
+
md = render_agents_md(SAMPLE)
|
|
123
125
|
assert "developers" not in md.split("## Stack")[1] # target_user filtered
|
|
124
126
|
|
|
125
127
|
|
|
126
128
|
def test_agents_md_deterministic():
|
|
127
|
-
assert
|
|
129
|
+
assert render_agents_md(SAMPLE) == render_agents_md(dict(SAMPLE))
|
|
128
130
|
|
|
129
131
|
|
|
130
132
|
def test_agents_md_human_prefs_excluded_from_conventions():
|
|
131
|
-
md =
|
|
133
|
+
md = render_agents_md(SAMPLE)
|
|
132
134
|
conv = md.split("## Conventions")[1].split("##")[0]
|
|
133
135
|
assert "communication" not in conv.lower()
|
|
134
136
|
assert "Testing" in conv
|
|
@@ -137,7 +139,7 @@ def test_agents_md_human_prefs_excluded_from_conventions():
|
|
|
137
139
|
# --- GEMINI.md ----------------------------------------------------------
|
|
138
140
|
|
|
139
141
|
def test_gemini_md_structure():
|
|
140
|
-
md =
|
|
142
|
+
md = render_gemini_md(SAMPLE)
|
|
141
143
|
assert md.startswith("<!-- faf:")
|
|
142
144
|
assert "# GEMINI.md — widget-api" in md
|
|
143
145
|
assert "Project: widget-api" in md
|
|
@@ -148,7 +150,7 @@ def test_gemini_md_structure():
|
|
|
148
150
|
|
|
149
151
|
def test_gemini_md_no_guardrail_ladder():
|
|
150
152
|
# GEMINI.md is lighter — no Definition of Done / When stuck
|
|
151
|
-
md =
|
|
153
|
+
md = render_gemini_md(SAMPLE)
|
|
152
154
|
assert "## Definition of Done" not in md
|
|
153
155
|
assert "## Guardrails" not in md
|
|
154
156
|
|
|
@@ -157,8 +159,8 @@ def test_gemini_md_no_guardrail_ladder():
|
|
|
157
159
|
|
|
158
160
|
def test_minimal_faf_does_not_crash():
|
|
159
161
|
minimal = {"faf_version": "3.0", "project": {"name": "x"}}
|
|
160
|
-
assert "# AGENTS.md — x" in
|
|
161
|
-
assert "# GEMINI.md — x" in
|
|
162
|
+
assert "# AGENTS.md — x" in render_agents_md(minimal)
|
|
163
|
+
assert "# GEMINI.md — x" in render_gemini_md(minimal)
|
|
162
164
|
|
|
163
165
|
|
|
164
166
|
def test_key_files_from_instant_context_fallback():
|
|
@@ -167,12 +169,41 @@ def test_key_files_from_instant_context_fallback():
|
|
|
167
169
|
"project": {"name": "y"},
|
|
168
170
|
"instant_context": {"key_files": ["a.py", "b.py"]},
|
|
169
171
|
}
|
|
170
|
-
md =
|
|
172
|
+
md = render_agents_md(faf)
|
|
171
173
|
assert "- `a.py`" in md
|
|
172
174
|
|
|
173
175
|
|
|
174
176
|
def test_commands_from_instant_context_are_not_used_at_toplevel():
|
|
175
177
|
# top-level `commands` is the source; instant_context.commands is separate
|
|
176
178
|
faf = {"faf_version": "3.0", "project": {"name": "z"}, "commands": {"test": "go test ./..."}}
|
|
177
|
-
md =
|
|
179
|
+
md = render_agents_md(faf)
|
|
178
180
|
assert "go test ./..." in md
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# --- naming: public alias + deprecated shim ------------------------------
|
|
184
|
+
|
|
185
|
+
def test_author_names_are_the_public_alias():
|
|
186
|
+
from faf_sdk import author_agents_md, author_gemini_md
|
|
187
|
+
|
|
188
|
+
assert author_agents_md is render_agents_md
|
|
189
|
+
assert author_gemini_md is render_gemini_md
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def test_generate_names_still_work_but_warn():
|
|
193
|
+
from faf_sdk import generate_agents_md, generate_gemini_md
|
|
194
|
+
|
|
195
|
+
with pytest.warns(DeprecationWarning, match="author_agents_md"):
|
|
196
|
+
md = generate_agents_md(SAMPLE)
|
|
197
|
+
assert md == render_agents_md(SAMPLE)
|
|
198
|
+
|
|
199
|
+
with pytest.warns(DeprecationWarning, match="author_gemini_md"):
|
|
200
|
+
assert generate_gemini_md(SAMPLE) == render_gemini_md(SAMPLE)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def test_interop_all_advertises_author_not_generate():
|
|
204
|
+
from faf_sdk import interop
|
|
205
|
+
|
|
206
|
+
assert "author_agents_md" in interop.__all__
|
|
207
|
+
assert "author_gemini_md" in interop.__all__
|
|
208
|
+
assert "generate_agents_md" not in interop.__all__
|
|
209
|
+
assert "render_agents_md" not in interop.__all__ # importable, not advertised
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|