Skip to content

Commit 7a4baea

Browse files
release: 2.0.0 (#13)
* release: 2.0.0 Two things had to land before the meaning of anything froze at stable. AGF002 carried two unrelated meanings: "configuration file not found" and "the repository scan stopped early". Different problems, different severities, and one code. The consequences were user-facing, not cosmetic: `agentfile rule AGF002` explained the wrong problem, a SARIF ruleId mislabelled it, and a `severity: AGF002: off` written to quiet truncation noise also silenced genuine missing-file errors. Truncation is now AGF006. Codes are append-only, so after 2.0.0 this would have been permanent. The existing test asserted the word "truncated" appeared in the message, which is exactly why the overload survived unnoticed. It now pins the code, and a second test asserts truncation is never reported as AGF002. The other thing is the release itself. `latest` pointed at the v1 CLI for the whole beta, so all eighty `npx @agentfile/cli` commands in the README failed for anyone who followed them — the first one with `error: unknown command 'doctor'`. Publishing 2.0.0 to `latest` is what fixes that, and it is why the Action's `version` default moves from `next` to `latest` in the same commit. Verified: AGF006 end to end through discover, JSON and SARIF, with AGF002 no longer emitted for truncation; the release workflow's own gate simulated green (three manifests at 2.0.0, CHANGELOG section present, classified stable so it publishes to `latest`); build, typecheck, lint unchanged from baseline, 930 tests. * fix(action): a SARIF log we cannot parse is not a clean scan Flipping the version default to `latest` in the release commit was premature: `latest` is the v1 CLI until 2.0.0 actually publishes, so the action's own tests ran a CLI with no `check` and no `--format sarif`. Default back to `next`; it flips after the tag, when `latest` means what the default claims. That mistake exposed a real bug worth keeping. v1 exited 1, which the action read as "findings", wrote an empty file, and reported sarif-file=agentfile.sarif with findings=0 — a broken scan indistinguishable from a clean one, until upload-sarif rejected it: ##[error]Invalid SARIF. JSON syntax error: Unexpected end of JSON input The counting snippet had `catch {}` around the parse, which swallowed exactly this. It now requires a SARIF 2.1.0 log with a results array, and treats anything else as exit 2 — the tool could not run — with sarif-file left empty so an `if: always()` upload step skips rather than uploads rubbish. Verified both ways locally: pinning version to 0.4.0 now exits 2 with "Version '0.4.0' may not support --format sarif", and the normal path still exits 0 with findings=1 and a valid log. --------- Co-authored-by: Dennis Havermans <dennis.havermans@ae.be>
1 parent 0a0832e commit 7a4baea

14 files changed

Lines changed: 122 additions & 30 deletions

File tree

CHANGELOG.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,46 @@ Versioning follows [Semantic Versioning](https://semver.org/).
99

1010
## [Unreleased]
1111

12+
## [2.0.0] — 2026-08-31
13+
14+
The 2.0 line, stable. `npm install @agentfile/cli` now resolves to it, which is
15+
the substantive part of this release: `latest` pointed at the v1 CLI throughout
16+
the beta, so every command in the README failed for anyone who followed it.
17+
[docs/migration-v2.md](docs/migration-v2.md) covers what changes for an existing
18+
repository; the three beta entries below carry the detail of what 2.0 is.
19+
20+
### Breaking
21+
22+
- **Truncation is `AGF006`, not `AGF002`.** One code carried two unrelated
23+
meanings: "configuration file not found" and "the repository scan stopped
24+
early". They are different problems with different severities, and merging
25+
them meant `agentfile rule AGF002` explained the wrong one, a SARIF `ruleId`
26+
mislabelled it, and a `severity: AGF002: off` written to quiet truncation
27+
noise also silenced genuine missing-file errors. Diagnostic codes are
28+
append-only, so this had to land before the meaning froze at stable.
29+
30+
`AGF002` keeps its registered meaning and is unchanged. Anything matching on
31+
the truncation warning by code needs to look for `AGF006`.
32+
33+
### Added
34+
35+
- **A GitHub Action.** `uses: dennishavermans/agentfile@v1` runs `check`, writes
36+
SARIF, and fails the step on findings. It deliberately does not upload the
37+
SARIF: that needs `security-events: write`, and a job asking for write access
38+
to security alerts should say so where a reader can see it rather than acquire
39+
it inside a step called "run the linter". The README shows the upload step.
40+
41+
### Fixed
42+
43+
- **`--format sarif` is discoverable.** It has worked on `check`, `validate`,
44+
`lint` and `audit` since it landed, but every command's `--help` said
45+
`human or json`, so the CLI contradicted the README. Corrected on those four;
46+
the rest reject SARIF deliberately and were already accurate.
47+
48+
- **The truncation warning is covered by a test that pins its code.** The
49+
existing test asserted the word "truncated" appeared in the message, which is
50+
exactly why the `AGF002` overload survived unnoticed.
51+
1252
## [2.0.0-beta.3] — 2026-08-28
1353

1454
### Fixed

README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ skipped exactly when there is something to upload.
378378
| --- | --- | --- |
379379
| `command` | `check` | `check`, `validate`, `lint` or `audit` — the four that produce findings against a file |
380380
| `root` | `.` | directory to analyse |
381-
| `version` | `next` | version or dist-tag of `@agentfile/cli`; pin it for a reproducible job |
381+
| `version` | `next` | version or dist-tag of `@agentfile/cli`; pin an exact version for a job that cannot change under you |
382382
| `sarif-file` | `agentfile.sarif` | where to write SARIF; empty string skips it |
383383
| `fail-on-findings` | `true` | whether findings fail the step |
384384
| `args` | none | extra arguments, e.g. `--strict` or `--max-warnings 5` |
@@ -395,9 +395,6 @@ Running more than one command means more than one upload, and each needs its
395395
own `category` (`agentfile-check`, `agentfile-audit`) or the second will close
396396
the first one's alerts.
397397

398-
`version` defaults to `next` because 2.0 is in beta and `latest` still points at
399-
the v1 CLI. That default becomes `latest` at 2.0 stable.
400-
401398
---
402399

403400
## CI output

action.yml

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ inputs:
2727
required: false
2828
default: .
2929
version:
30-
description: 'Version or dist-tag of @agentfile/cli to run. Pin this for a reproducible job; `next` is the 2.0 line while it is in beta, and becomes `latest` at 2.0 stable.'
30+
description: 'Version or dist-tag of @agentfile/cli to run. Pin it to an exact version for a job that cannot change under you.'
3131
required: false
3232
default: next
3333
sarif-file:
@@ -136,13 +136,27 @@ runs:
136136
fi
137137
sarif_out="$AGENTFILE_SARIF"
138138
139-
read -r findings errors warnings < <(node -e '
139+
if ! counts=$(node -e '
140140
const fs = require("node:fs");
141-
let results = [];
142-
try { results = JSON.parse(fs.readFileSync(process.argv[1], "utf8")).runs?.[0]?.results ?? []; } catch {}
143-
const at = (level) => results.filter((r) => r.level === level).length;
144-
console.log(results.length, at("error"), at("warning"));
145-
' "$AGENTFILE_SARIF")
141+
try {
142+
const log = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
143+
const results = log.runs?.[0]?.results;
144+
if (log.version !== "2.1.0" || !Array.isArray(results)) throw new Error("not a SARIF 2.1.0 log");
145+
const at = (level) => results.filter((r) => r.level === level).length;
146+
console.log(results.length, at("error"), at("warning"));
147+
} catch (error) {
148+
// A stack trace here would bury the one line that explains it.
149+
process.stderr.write(error.message + "\n");
150+
process.exit(1);
151+
}
152+
' "$AGENTFILE_SARIF" 2>&1); then
153+
echo "::error::agentfile did not produce a valid SARIF log. Version '$AGENTFILE_VERSION' may not support --format sarif."
154+
echo "$counts"
155+
echo "exit-code=2" >> "$GITHUB_OUTPUT"
156+
echo "sarif-file=" >> "$GITHUB_OUTPUT"
157+
exit 2
158+
fi
159+
read -r findings errors warnings <<< "$counts"
146160
147161
{
148162
echo "### agentfile $AGENTFILE_COMMAND"

docs/diagnostics.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ finding it was meant to silence. A warning rather than an error: a stale
5454
directive is untidy, not broken, and failing a build over one would push people
5555
towards blanket `agentfile-disable` comments that silence everything.
5656

57+
### `AGF006` scan-truncated · warning · active
58+
The repository scan hit a limit and stopped early, so agentfile did not read
59+
every file. Nothing in the configuration is necessarily wrong; the report is
60+
simply incomplete, and every finding below it that rests on absence — a
61+
reference that "does not exist", a glob that matches "nothing" — is weaker than
62+
it looks. Raise the scan limits, or exclude large generated directories, and run
63+
it again.
64+
65+
Reported under its own code since 2.0.0. Before that it shared `AGF002` with
66+
"configuration file not found", which meant `agentfile rule AGF002` explained
67+
the wrong problem and turning one off silenced the other.
68+
5769
Directives are written as a comment in the configuration file itself, in
5870
whichever comment syntax that file already uses:
5971

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/agentfile/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@agentfile/agentfile",
3-
"version": "2.0.0-beta.3",
3+
"version": "2.0.0",
44
"description": "Find what is wrong with the AI agent configuration your repository already has",
55
"type": "module",
66
"bin": {
@@ -42,7 +42,7 @@
4242
"access": "public"
4343
},
4444
"dependencies": {
45-
"@agentfile/cli": "^2.0.0-beta.3"
45+
"@agentfile/cli": "^2.0.0"
4646
},
4747
"devDependencies": {
4848
"@types/node": "^22.19.0",

packages/cli/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@agentfile/cli",
3-
"version": "2.0.0-beta.3",
4-
"description": "Find what is wrong with the AI agent configuration your repository already has \u2014 doctor, check, lint, audit, adopt, compile, eval",
3+
"version": "2.0.0",
4+
"description": "Find what is wrong with the AI agent configuration your repository already has doctor, check, lint, audit, adopt, compile, eval",
55
"type": "module",
66
"main": "./dist/bin.js",
77
"bin": {
@@ -45,7 +45,7 @@
4545
"access": "public"
4646
},
4747
"dependencies": {
48-
"@agentfile/core": "^2.0.0-beta.3",
48+
"@agentfile/core": "^2.0.0",
4949
"chalk": "^6.0.0",
5050
"commander": "^14.0.3",
5151
"enquirer": "^2.4.1"

packages/core/__tests__/discovery.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,25 @@ describe("discover", () => {
844844
for (let index = 0; index < 20; index++) files[`/repo/file-${index}.md`] = "x";
845845

846846
const result = discover({ root: ROOT, fs: memoryFileSystem(files), maxFiles: 5 });
847-
expect(result.diagnostics.some((item) => item.message.includes("truncated"))).toBe(true);
847+
const finding = result.diagnostics.find((item) => item.code === "AGF006");
848+
849+
expect(finding).toBeDefined();
850+
expect(finding?.message).toContain("truncated");
851+
expect(finding?.severity).toBe("warning");
852+
});
853+
854+
// This assertion is the one that was missing. The truncation warning used to
855+
// be emitted as AGF002, "configuration file not found", and no test noticed
856+
// because the only assertion was on the word "truncated" in the message. A
857+
// code carries its meaning into `agentfile rule`, into a SARIF ruleId, and
858+
// into whatever `severity:` entry a user writes to silence it, so the code is
859+
// the part worth pinning.
860+
it("does not report truncation as a missing configuration file", () => {
861+
const files: Record<string, string> = { "/repo/AGENTS.md": "x" };
862+
for (let index = 0; index < 20; index++) files[`/repo/file-${index}.md`] = "x";
863+
864+
const result = discover({ root: ROOT, fs: memoryFileSystem(files), maxFiles: 5 });
865+
expect(result.diagnostics.map((item) => item.code)).not.toContain("AGF002");
848866
});
849867

850868
it("resolves discovered configuration for a path", () => {

packages/core/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@agentfile/core",
3-
"version": "2.0.0-beta.3",
4-
"description": "Read, analyse and compile AI agent configuration \u2014 discovery, a normalized IR, a resolver, diagnostics, and static security analysis",
3+
"version": "2.0.0",
4+
"description": "Read, analyse and compile AI agent configuration discovery, a normalized IR, a resolver, diagnostics, and static security analysis",
55
"type": "module",
66
"main": "./dist/index.js",
77
"types": "./dist/index.d.ts",

packages/core/src/diagnostics/codes.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,17 @@ export const DIAGNOSTIC_CODES = {
8585
defaultSeverity: "warning",
8686
status: "active",
8787
},
88+
AGF006: {
89+
name: "scan-truncated",
90+
title: "Repository scan stopped early, so the report is incomplete",
91+
band: "configuration",
92+
// A warning about the report rather than about the repository. Nothing in
93+
// the configuration is wrong; agentfile simply did not read all of it, and
94+
// every "nothing matches" and "does not exist" below it is weaker as a
95+
// result.
96+
defaultSeverity: "warning",
97+
status: "active",
98+
},
8899

89100
// ─── AGF1xx — skills ────────────────────────────────────────────────────
90101
AGF101: {

0 commit comments

Comments
 (0)