faf-taf-git 2.3.1 → 2.4.1
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/.github/dependabot.yml +10 -0
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/claude-code-review.yml +8 -1
- package/.github/workflows/claude.yml +1 -1
- package/CHANGELOG.md +25 -1
- package/CLAUDE.md +12 -20
- package/README.md +92 -473
- package/RECEIPT-FORMAT.md +1 -1
- package/action.yml +4 -1
- package/agent.fafa +53 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -1
- package/dist/cli.js.map +1 -1
- package/dist/index.js +123 -5
- package/dist/index.js.map +1 -1
- package/dist/parsers/index.d.ts +1 -0
- package/dist/parsers/index.d.ts.map +1 -1
- package/dist/parsers/index.js +11 -5
- package/dist/parsers/index.js.map +1 -1
- package/dist/parsers/junit.d.ts +22 -0
- package/dist/parsers/junit.d.ts.map +1 -0
- package/dist/parsers/junit.js +104 -0
- package/dist/parsers/junit.js.map +1 -0
- package/package.json +5 -5
- package/project.faf +43 -241
- package/src/cli.ts +15 -1
- package/src/index.ts +1 -0
- package/src/parsers/index.ts +9 -4
- package/src/parsers/junit.ts +110 -0
- package/tests/cli-version.test.ts +31 -0
- package/tests/junit-parser.test.ts +109 -0
package/dist/parsers/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { TestResults } from './jest';
|
|
7
7
|
export { TestResults } from './jest';
|
|
8
|
+
export { parseJunitOutput } from './junit';
|
|
8
9
|
export { parseWjttcOutput } from './wjttc';
|
|
9
10
|
export declare const SUPPORTED_PARSERS: readonly string[];
|
|
10
11
|
/** What the CLI and the Action report when no parser matches. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["file:///Users/wolfejam/FAF/faf-taf-git/src/parsers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["file:///Users/wolfejam/FAF/faf-taf-git/src/parsers/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAOrC,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAmB3C,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAAkC,CAAC;AAElF,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,QAA6E,CAAC;AAE7G;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAMlE"}
|
package/dist/parsers/index.js
CHANGED
|
@@ -5,22 +5,28 @@
|
|
|
5
5
|
* Tries each framework parser in order until one succeeds.
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.UNPARSEABLE_OUTPUT = exports.SUPPORTED_PARSERS = exports.parseWjttcOutput = void 0;
|
|
8
|
+
exports.UNPARSEABLE_OUTPUT = exports.SUPPORTED_PARSERS = exports.parseWjttcOutput = exports.parseJunitOutput = void 0;
|
|
9
9
|
exports.parseTestOutput = parseTestOutput;
|
|
10
10
|
const bun_1 = require("./bun");
|
|
11
11
|
const jest_1 = require("./jest");
|
|
12
|
+
const junit_1 = require("./junit");
|
|
12
13
|
const vitest_1 = require("./vitest");
|
|
13
14
|
const wjttc_1 = require("./wjttc");
|
|
15
|
+
var junit_2 = require("./junit");
|
|
16
|
+
Object.defineProperty(exports, "parseJunitOutput", { enumerable: true, get: function () { return junit_2.parseJunitOutput; } });
|
|
14
17
|
var wjttc_2 = require("./wjttc");
|
|
15
18
|
Object.defineProperty(exports, "parseWjttcOutput", { enumerable: true, get: function () { return wjttc_2.parseWjttcOutput; } });
|
|
16
19
|
/**
|
|
17
20
|
* Every parser, in the order parseTestOutput tries them. Order matters:
|
|
18
|
-
* 1.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
21
|
+
* 1. JUnit XML — a `<testsuite>` element; first, because a report's captured
|
|
22
|
+
* stdout can hold another runner's summary line.
|
|
23
|
+
* 2. Bun — `Ran N tests across M files` is bun-unique.
|
|
24
|
+
* 3. WJTTC — `pc-ai WJTTC` / suite `pc-ai-wjttc` (FAF bar; not Jest-shaped).
|
|
25
|
+
* 4. Jest — `Tests: … total`.
|
|
26
|
+
* 5. Vitest — `Tests … (N)`.
|
|
22
27
|
*/
|
|
23
28
|
const PARSERS = [
|
|
29
|
+
['JUnit XML', junit_1.parseJunitOutput],
|
|
24
30
|
['Bun', bun_1.parseBunOutput],
|
|
25
31
|
['WJTTC', wjttc_1.parseWjttcOutput],
|
|
26
32
|
['Jest', jest_1.parseJestOutput],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAuCH,0CAMC;AA1CD,+BAAuC;AACvC,iCAAyC;AACzC,mCAA2C;AAC3C,qCAA6C;AAC7C,mCAA2C;AAG3C,iCAA2C;AAAlC,yGAAA,gBAAgB,OAAA;AACzB,iCAA2C;AAAlC,yGAAA,gBAAgB,OAAA;AAEzB;;;;;;;;GAQG;AACH,MAAM,OAAO,GAA0F;IACrG,CAAC,WAAW,EAAE,wBAAgB,CAAC;IAC/B,CAAC,KAAK,EAAE,oBAAc,CAAC;IACvB,CAAC,OAAO,EAAE,wBAAgB,CAAC;IAC3B,CAAC,MAAM,EAAE,sBAAe,CAAC;IACzB,CAAC,QAAQ,EAAE,0BAAiB,CAAC;CAC9B,CAAC;AAEW,QAAA,iBAAiB,GAAsB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AAElF,iEAAiE;AACpD,QAAA,kBAAkB,GAAG,2CAA2C,yBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAE7G;;;GAGG;AACH,SAAgB,eAAe,CAAC,MAAc;IAC5C,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JUnit XML parser
|
|
3
|
+
*
|
|
4
|
+
* Extracts test counts from a JUnit XML report — the common format nearly every
|
|
5
|
+
* test runner can write: pytest (--junitxml), cargo (nextest, cargo2junit), Go
|
|
6
|
+
* (go-junit-report, gotestsum), Maven/Gradle, .NET, PHPUnit, Jest (jest-junit).
|
|
7
|
+
*/
|
|
8
|
+
import { TestResults } from './jest';
|
|
9
|
+
/**
|
|
10
|
+
* Parse a JUnit XML report to extract test results
|
|
11
|
+
*
|
|
12
|
+
* Handles:
|
|
13
|
+
* - a <testsuites> root that carries the totals (gotestsum, Maven)
|
|
14
|
+
* - a <testsuites> root without totals, around counted <testsuite>s (pytest)
|
|
15
|
+
* - a single <testsuite> root
|
|
16
|
+
* - nested <testsuite>s (only the outermost level is counted, never twice)
|
|
17
|
+
* - suites with no counts at all (the <testcase> elements are counted instead)
|
|
18
|
+
*
|
|
19
|
+
* failures + errors count as failed; skipped + disabled count as skipped.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseJunitOutput(output: string): TestResults | null;
|
|
22
|
+
//# sourceMappingURL=junit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"junit.d.ts","sourceRoot":"","sources":["file:///Users/wolfejam/FAF/faf-taf-git/src/parsers/junit.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAyCrC;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAgDnE"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JUnit XML parser
|
|
4
|
+
*
|
|
5
|
+
* Extracts test counts from a JUnit XML report — the common format nearly every
|
|
6
|
+
* test runner can write: pytest (--junitxml), cargo (nextest, cargo2junit), Go
|
|
7
|
+
* (go-junit-report, gotestsum), Maven/Gradle, .NET, PHPUnit, Jest (jest-junit).
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.parseJunitOutput = parseJunitOutput;
|
|
11
|
+
const SUITE_TAG = /<(\/?)testsuite\b([^>]*?)(\/?)>/g;
|
|
12
|
+
/** Read one numeric attribute; undefined when the attribute is absent. */
|
|
13
|
+
function attr(attrs, name) {
|
|
14
|
+
const match = attrs.match(new RegExp(`\\b${name}\\s*=\\s*["'](\\d+)["']`));
|
|
15
|
+
return match ? parseInt(match[1], 10) : undefined;
|
|
16
|
+
}
|
|
17
|
+
/** Counts from a <testsuite> or <testsuites> attribute list, or null without a `tests` count. */
|
|
18
|
+
function countsFromAttrs(attrs) {
|
|
19
|
+
const tests = attr(attrs, 'tests');
|
|
20
|
+
if (tests === undefined)
|
|
21
|
+
return null;
|
|
22
|
+
return {
|
|
23
|
+
tests,
|
|
24
|
+
failed: (attr(attrs, 'failures') ?? 0) + (attr(attrs, 'errors') ?? 0),
|
|
25
|
+
skipped: (attr(attrs, 'skipped') ?? 0) + (attr(attrs, 'disabled') ?? 0),
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Fallback when suites carry no counts: walk the <testcase> elements themselves. */
|
|
29
|
+
function countsFromTestcases(xml) {
|
|
30
|
+
const counts = { tests: 0, failed: 0, skipped: 0 };
|
|
31
|
+
const testcase = /<testcase\b[^>]*?(?:\/>|>([\s\S]*?)<\/testcase>)/g;
|
|
32
|
+
let match;
|
|
33
|
+
while ((match = testcase.exec(xml)) !== null) {
|
|
34
|
+
counts.tests++;
|
|
35
|
+
const body = match[1] ?? '';
|
|
36
|
+
if (/<(failure|error)\b/.test(body))
|
|
37
|
+
counts.failed++;
|
|
38
|
+
else if (/<skipped\b/.test(body))
|
|
39
|
+
counts.skipped++;
|
|
40
|
+
}
|
|
41
|
+
return counts;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Parse a JUnit XML report to extract test results
|
|
45
|
+
*
|
|
46
|
+
* Handles:
|
|
47
|
+
* - a <testsuites> root that carries the totals (gotestsum, Maven)
|
|
48
|
+
* - a <testsuites> root without totals, around counted <testsuite>s (pytest)
|
|
49
|
+
* - a single <testsuite> root
|
|
50
|
+
* - nested <testsuite>s (only the outermost level is counted, never twice)
|
|
51
|
+
* - suites with no counts at all (the <testcase> elements are counted instead)
|
|
52
|
+
*
|
|
53
|
+
* failures + errors count as failed; skipped + disabled count as skipped.
|
|
54
|
+
*/
|
|
55
|
+
function parseJunitOutput(output) {
|
|
56
|
+
const xml = output.replace(/<!--[\s\S]*?-->/g, '');
|
|
57
|
+
if (!/<testsuites?\b/.test(xml))
|
|
58
|
+
return null;
|
|
59
|
+
let counts = null;
|
|
60
|
+
const root = xml.match(/<testsuites\b([^>]*)>/);
|
|
61
|
+
if (root)
|
|
62
|
+
counts = countsFromAttrs(root[1]);
|
|
63
|
+
if (!counts) {
|
|
64
|
+
// Sum the outermost <testsuite>s; a suite without counts sends us to the testcases.
|
|
65
|
+
let depth = 0;
|
|
66
|
+
let summed = { tests: 0, failed: 0, skipped: 0 };
|
|
67
|
+
let seen = 0;
|
|
68
|
+
let match;
|
|
69
|
+
SUITE_TAG.lastIndex = 0;
|
|
70
|
+
while ((match = SUITE_TAG.exec(xml)) !== null) {
|
|
71
|
+
const [, closing, attrs, selfClosing] = match;
|
|
72
|
+
if (closing) {
|
|
73
|
+
depth--;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (depth === 0 && summed) {
|
|
77
|
+
seen++;
|
|
78
|
+
const suite = countsFromAttrs(attrs);
|
|
79
|
+
if (suite) {
|
|
80
|
+
summed.tests += suite.tests;
|
|
81
|
+
summed.failed += suite.failed;
|
|
82
|
+
summed.skipped += suite.skipped;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
summed = null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!selfClosing)
|
|
89
|
+
depth++;
|
|
90
|
+
}
|
|
91
|
+
counts = seen > 0 && summed ? summed : countsFromTestcases(xml);
|
|
92
|
+
}
|
|
93
|
+
if (counts.tests === 0)
|
|
94
|
+
return null;
|
|
95
|
+
const passed = Math.max(0, counts.tests - counts.failed - counts.skipped);
|
|
96
|
+
return {
|
|
97
|
+
total: counts.tests,
|
|
98
|
+
passed,
|
|
99
|
+
failed: counts.failed,
|
|
100
|
+
skipped: counts.skipped > 0 ? counts.skipped : undefined,
|
|
101
|
+
result: counts.failed > 0 ? 'FAILED' : 'PASSED',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=junit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"junit.js","sourceRoot":"","sources":["../../src/parsers/junit.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "faf-taf-git",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "A Test Receipt Printer for git. Every CI run prints a receipt to .taf — append-only, timestamped,
|
|
3
|
+
"version": "2.4.1",
|
|
4
|
+
"description": "A Test Receipt Printer for git. Every CI run prints a receipt to .taf — append-only, timestamped, kept in git. Proof over time.",
|
|
5
5
|
"main": "dist/cli.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"faf-taf-git": "dist/cli.js"
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"yaml": "^2.3.4"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/jest": "^
|
|
39
|
+
"@types/jest": "^30.0.0",
|
|
40
40
|
"@types/node": "^20.10.6",
|
|
41
41
|
"@vercel/ncc": "^0.38.1",
|
|
42
|
-
"jest": "^
|
|
43
|
-
"ts-jest": "^29.
|
|
42
|
+
"jest": "^30.5.2",
|
|
43
|
+
"ts-jest": "^29.4.15",
|
|
44
44
|
"typescript": "^5.3.3"
|
|
45
45
|
},
|
|
46
46
|
"overrides": {
|
package/project.faf
CHANGED
|
@@ -1,255 +1,57 @@
|
|
|
1
|
-
faf_version:
|
|
2
|
-
ai_scoring_system: 2025-09-20
|
|
3
|
-
ai_score: 65%
|
|
4
|
-
ai_confidence: MODERATE
|
|
5
|
-
ai_value: 30_seconds_replaces_20_minutes_of_questions
|
|
6
|
-
ai_tldr:
|
|
7
|
-
project: faf-taf-git v2.1.1 - A Test Receipt Printer for git. Proof over time, cannot be gamed.
|
|
8
|
-
stack: TypeScript CLI + GitHub Action (pre-capture architecture)
|
|
9
|
-
quality_bar: ZERO_ERRORS_F1_STANDARDS
|
|
10
|
-
status: PRODUCTION_READY (working in faf-cli repo)
|
|
11
|
-
breakthrough: v2.0.0 pre-capture pattern (tested 19 methods before this)
|
|
12
|
-
current_focus: Ecosystem adoption and user onboarding
|
|
13
|
-
your_role: Support users, fix bugs, add test framework support
|
|
14
|
-
instant_context:
|
|
15
|
-
what_building: A Test Receipt Printer for git. CLI runs on any CI/CD; prints append-only test receipts to .taf, kept in git. FAF-aware optionally — receipts can carry FAF score/identity, but TAF works on any repo.
|
|
16
|
-
tech_stack: TypeScript
|
|
17
|
-
main_language: TypeScript
|
|
18
|
-
deployment: npm + GitHub Actions Marketplace
|
|
19
|
-
architecture: v2.0.0 pre-capture pattern (separate test execution from receipt generation)
|
|
20
|
-
use_cases: Standalone CLI, GitHub Action, GitLab CI, Jenkins, CircleCI, Local development
|
|
21
|
-
test_support: Jest (fully supported) with plans for Mocha, Vitest, Pytest, Go test, Rust cargo
|
|
22
|
-
golden_triangle: .faf (project DNA) + repo (code) + .taf (test proof)
|
|
23
|
-
key_files:
|
|
24
|
-
- src/index.ts (v2.0.0 rewrite - reads test output file)
|
|
25
|
-
- src/parsers/jest.ts (v2.0.4 fix - correct pattern matching)
|
|
26
|
-
- src/taf-core.ts (MCP-portable core)
|
|
27
|
-
- action.yml (v2.0.2 fix - correct bundle path)
|
|
28
|
-
- README.md (6Ws format)
|
|
29
|
-
- CHANGELOG.md (22 versions documented)
|
|
30
|
-
documentation:
|
|
31
|
-
- README: 6Ws format (What/Who/Why/Where/When/How)
|
|
32
|
-
- CHANGELOG: Complete debugging journey (v1.0.4 → v2.0.4)
|
|
33
|
-
- Migration guide: v1.x → v2.x breaking changes
|
|
34
|
-
context_quality:
|
|
35
|
-
slots_filled: 11/21 (52%)
|
|
36
|
-
ai_confidence: MODERATE
|
|
37
|
-
handoff_ready: true
|
|
38
|
-
missing_context: []
|
|
1
|
+
faf_version: "3.0"
|
|
39
2
|
project:
|
|
40
3
|
name: faf-taf-git
|
|
41
|
-
goal:
|
|
42
|
-
innovation: On-the-fly Testing Audit Files - Unheard of in CI/CD
|
|
43
|
-
taf_meaning:
|
|
44
|
-
file: Testing Audit File (.taf)
|
|
45
|
-
feed: Testing Activity Feed (live updates)
|
|
4
|
+
goal: "A Test Receipt Printer for git. Every CI run prints a receipt to .taf: append-only, timestamped, kept in git. Proof over time."
|
|
46
5
|
main_language: TypeScript
|
|
47
|
-
type: cli
|
|
48
|
-
generated: 2025-10-28T01:26:05.656Z
|
|
49
|
-
repository: https://github.com/Wolfe-Jam/faf-taf-git
|
|
50
|
-
license: MIT
|
|
51
|
-
author: wolfejam
|
|
52
|
-
keywords: testing, taf, ci-cd, github-actions, gitlab-ci, platform-agnostic, jest, faf, git
|
|
53
|
-
mission: 🚀 Make Your AI Happy! 🧡 Trust-Driven 🤖
|
|
54
|
-
revolution: 30 seconds replaces 20 minutes of questions
|
|
55
|
-
brand: F1-Inspired Software Engineering - Championship AI Context
|
|
56
|
-
ai_instructions:
|
|
57
|
-
priority_order:
|
|
58
|
-
- 1. Read THIS .faf file first
|
|
59
|
-
- 2. Check CLAUDE.md for session context
|
|
60
|
-
- 3. Review package.json for dependencies
|
|
61
|
-
working_style:
|
|
62
|
-
code_first: true
|
|
63
|
-
explanations: minimal
|
|
64
|
-
quality_bar: zero_errors
|
|
65
|
-
testing: required
|
|
66
|
-
warnings:
|
|
67
|
-
- Never modify dial components without approval
|
|
68
|
-
- All TypeScript must pass strict mode
|
|
69
|
-
- Test coverage required for new features
|
|
6
|
+
type: cli # found: package.json bin
|
|
70
7
|
stack:
|
|
71
8
|
frontend: slotignored
|
|
72
9
|
css_framework: slotignored
|
|
73
10
|
ui_library: slotignored
|
|
74
11
|
state_management: slotignored
|
|
75
12
|
backend: slotignored
|
|
76
|
-
|
|
13
|
+
api_type: slotignored
|
|
14
|
+
runtime: slotignored
|
|
77
15
|
database: slotignored
|
|
78
16
|
connection: slotignored
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
api_type: REST
|
|
82
|
-
hosting: npm Registry
|
|
17
|
+
hosting: npm registry + GitHub Actions Marketplace
|
|
18
|
+
build: TypeScript (tsc)
|
|
83
19
|
cicd: GitHub Actions
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
- npx faf-taf-git
|
|
92
|
-
- --file (test output file - v2.0.0+)
|
|
93
|
-
- --command (custom test command - legacy v1.x)
|
|
94
|
-
- --commit (auto-commit .taf changes)
|
|
95
|
-
- --verbose (detailed output)
|
|
96
|
-
- --message (custom commit message)
|
|
97
|
-
- --cwd (working directory)
|
|
98
|
-
github_action_inputs:
|
|
99
|
-
test-output-file: required (v2.0.0+)
|
|
100
|
-
auto-commit: true (default)
|
|
101
|
-
commit-message: "chore(taf): update .taf receipt [skip ci] (default)"
|
|
102
|
-
architecture:
|
|
103
|
-
version: v2.0.0
|
|
104
|
-
pattern: pre-capture
|
|
105
|
-
breakthrough: Separate test execution from receipt generation
|
|
106
|
-
why: Avoids GitHub Actions execution context corruption
|
|
107
|
-
reliability: Tested 19 methods before this solution
|
|
108
|
-
benefits:
|
|
109
|
-
- More reliable (no execution context issues)
|
|
110
|
-
- Platform-agnostic (works everywhere)
|
|
111
|
-
- Simpler (400+ lines removed, 11KB smaller)
|
|
112
|
-
test_frameworks:
|
|
113
|
-
- Jest (fully supported)
|
|
114
|
-
supported_platforms:
|
|
115
|
-
- GitHub Actions
|
|
116
|
-
- GitLab CI
|
|
117
|
-
- Bitbucket Pipelines
|
|
118
|
-
- Jenkins
|
|
119
|
-
- CircleCI
|
|
120
|
-
- Travis CI
|
|
121
|
-
- Azure Pipelines
|
|
122
|
-
- Local development
|
|
123
|
-
taf_format:
|
|
124
|
-
format: YAML
|
|
125
|
-
file_location: .taf (hidden dotfile)
|
|
126
|
-
purpose: Git-tracked testing timeline - permanent proof your code works
|
|
127
|
-
links_to_faf: true
|
|
128
|
-
snapshots_faf_score: true
|
|
129
|
-
closed_loop_system: .faf (DNA) + repo (code) + .taf (proof) = Golden Triangle
|
|
130
|
-
deployment:
|
|
131
|
-
npm_package: faf-taf-git@2.1.1
|
|
132
|
-
github_action: Wolfe-Jam/faf-taf-git@v2.1.1
|
|
133
|
-
marketplaces:
|
|
134
|
-
- npm Registry
|
|
135
|
-
- GitHub Actions Marketplace
|
|
136
|
-
install: npx faf-taf-git
|
|
137
|
-
production_users:
|
|
138
|
-
- faf-cli (working in CI)
|
|
139
|
-
testing:
|
|
140
|
-
framework: Jest
|
|
141
|
-
coverage: Core functionality
|
|
142
|
-
ci_integration: GitHub Actions
|
|
143
|
-
test_files:
|
|
144
|
-
- tests/ (unit tests)
|
|
145
|
-
quality_gates:
|
|
146
|
-
- All tests must pass
|
|
147
|
-
- TypeScript strict mode
|
|
148
|
-
- Zero build errors
|
|
149
|
-
examples:
|
|
150
|
-
github_actions: README.md Quick Start section
|
|
151
|
-
standalone_cli: README.md Standalone CLI section
|
|
152
|
-
gitlab_ci: README.md GitLab CI section
|
|
153
|
-
jenkins: README.md Jenkins section
|
|
154
|
-
migration: README.md Migration from v1.x section
|
|
155
|
-
performance:
|
|
156
|
-
bundle_size: 1.2MB (v2.0.0 - reduced 11KB from v1.x)
|
|
157
|
-
startup_time: <100ms
|
|
158
|
-
parse_time: <10ms for typical Jest output
|
|
159
|
-
reliability: 100% success rate in faf-cli CI (after v2.0.4)
|
|
160
|
-
preferences:
|
|
161
|
-
quality_bar: zero_errors
|
|
162
|
-
commit_style: conventional_emoji
|
|
163
|
-
response_style: concise_code_first
|
|
164
|
-
explanation_level: minimal
|
|
165
|
-
communication: direct
|
|
166
|
-
testing: required
|
|
167
|
-
documentation: as_needed
|
|
168
|
-
contributing:
|
|
169
|
-
guidelines: CONTRIBUTING.md
|
|
170
|
-
code_style: TypeScript strict mode
|
|
171
|
-
pr_process: Fork, branch, PR with tests
|
|
172
|
-
commit_format: Conventional commits with Co-Authored-By
|
|
173
|
-
testing_required: true
|
|
174
|
-
documentation_required: For new features
|
|
175
|
-
resources:
|
|
176
|
-
readme: README.md (6Ws format)
|
|
177
|
-
changelog: CHANGELOG.md (22 versions documented)
|
|
178
|
-
license: MIT
|
|
179
|
-
repository: https://github.com/Wolfe-Jam/faf-taf-git
|
|
180
|
-
npm: https://npmjs.com/package/faf-taf-git
|
|
181
|
-
issues: https://github.com/Wolfe-Jam/faf-taf-git/issues
|
|
182
|
-
discussions: https://github.com/Wolfe-Jam/faf/discussions
|
|
183
|
-
state:
|
|
184
|
-
phase: production
|
|
185
|
-
version: 2.3.1
|
|
186
|
-
focus: ecosystem_adoption
|
|
187
|
-
status: production_ready
|
|
188
|
-
achievements:
|
|
189
|
-
- v2.0.0 architectural redesign (pre-capture pattern)
|
|
190
|
-
- v2.0.4 parser fix (working in CI)
|
|
191
|
-
- Updated README (6Ws format)
|
|
192
|
-
- Updated CHANGELOG (22 versions documented)
|
|
193
|
-
- TAF Receipt generating successfully in faf-cli repo
|
|
194
|
-
next_milestone: user_adoption
|
|
195
|
-
blockers: null
|
|
196
|
-
tags:
|
|
197
|
-
auto_generated:
|
|
198
|
-
- faf-taf-action
|
|
199
|
-
- none
|
|
200
|
-
- typescript
|
|
201
|
-
smart_defaults:
|
|
202
|
-
- .faf
|
|
203
|
-
- ai-ready
|
|
204
|
-
- "2025"
|
|
205
|
-
- software
|
|
206
|
-
- open-source
|
|
207
|
-
user_defined: null
|
|
20
|
+
monorepo_tool: slotignored
|
|
21
|
+
package_manager: slotignored
|
|
22
|
+
workspaces: slotignored
|
|
23
|
+
admin: slotignored
|
|
24
|
+
cache: slotignored
|
|
25
|
+
search: slotignored
|
|
26
|
+
storage: slotignored
|
|
208
27
|
human_context:
|
|
209
|
-
who:
|
|
210
|
-
what:
|
|
211
|
-
why:
|
|
212
|
-
where:
|
|
213
|
-
when:
|
|
214
|
-
how:
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
ai_score: 65
|
|
223
|
-
total_slots: 21
|
|
224
|
-
filled_slots: 11
|
|
225
|
-
scoring_method: Honest percentage - no fake minimums
|
|
226
|
-
trust_embedded: COUNT ONCE architecture - trust MY embedded scores
|
|
227
|
-
ai_scoring_details:
|
|
228
|
-
system_date: 2025-09-20
|
|
229
|
-
slot_based_percentage: 52
|
|
230
|
-
ai_score: 65
|
|
231
|
-
total_slots: 21
|
|
232
|
-
filled_slots: 11
|
|
233
|
-
scoring_method: Honest percentage - no fake minimums
|
|
234
|
-
trust_embedded: COUNT ONCE architecture - trust MY embedded scores
|
|
235
|
-
faf_dna:
|
|
236
|
-
birth_dna: 22
|
|
237
|
-
birth_certificate: FAF-2025-FAFTAFAC-TMZU
|
|
238
|
-
birth_date: 2025-10-28T01:26:05.692Z
|
|
239
|
-
current_score: 50
|
|
240
|
-
projectName: faf-taf-git
|
|
241
|
-
projectGoal: A Test Receipt Printer for git — append-only test receipts on every CI run. Proof over time, cannot be gamed.
|
|
242
|
-
generated: 2026-02-17T20:14:09.215Z
|
|
243
|
-
last_major_update: v2.0.4 (2026-02-17)
|
|
244
|
-
production_status: Working in faf-cli repository
|
|
245
|
-
stack_signature: typescript-nodejs-javascript
|
|
246
|
-
detected_frameworks:
|
|
247
|
-
- Claude Code
|
|
248
|
-
- Jest
|
|
249
|
-
- Node.js
|
|
250
|
-
- JavaScript
|
|
28
|
+
who: Maintainers and teams who want proof their tests kept passing on main, and the reviewers, auditors and AI agents who check it
|
|
29
|
+
what: "A Test Receipt Printer for git. Every CI run prints a receipt to .taf: append-only, timestamped, kept in git. Proof over time."
|
|
30
|
+
why: Test results vanish when CI logs expire. Receipts stay in git, so anyone can look back and check whether main was green before a release.
|
|
31
|
+
where: https://github.com/Wolfe-Jam/faf-taf-git
|
|
32
|
+
when: v2.4.1 (2026-10-30), --version fix; v2.4.0 (2026-10-29) JUnit XML parser; live since v1.0.0 (2025-10-27)
|
|
33
|
+
how: "Run tests, save the output (or a JUnit XML report), then `uses: Wolfe-Jam/faf-taf-git@v2.4.1` with `target-branch: taf-receipts`. Anywhere else: `npx faf-taf-git --file test-output.txt --commit`. The taf-receipts branch only grows: never rewrite it."
|
|
34
|
+
monorepo:
|
|
35
|
+
packages_count: slotignored
|
|
36
|
+
build_orchestrator: slotignored
|
|
37
|
+
versioning_strategy: slotignored
|
|
38
|
+
shared_configs: slotignored
|
|
39
|
+
remote_cache: slotignored
|
|
40
|
+
tech_stack:
|
|
251
41
|
- TypeScript
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
42
|
+
- "@actions/core"
|
|
43
|
+
- "@actions/exec"
|
|
44
|
+
- "@actions/github"
|
|
45
|
+
- yaml
|
|
46
|
+
key_files:
|
|
47
|
+
- package.json
|
|
48
|
+
- src/index.ts
|
|
49
|
+
- src/cli.ts
|
|
50
|
+
- src/parsers/
|
|
51
|
+
- action.yml
|
|
52
|
+
- RECEIPT-FORMAT.md
|
|
53
|
+
- README.md
|
|
54
|
+
- tsconfig.json
|
|
55
|
+
commands:
|
|
56
|
+
build: npm run build
|
|
57
|
+
test: npm run test
|
package/src/cli.ts
CHANGED
|
@@ -222,12 +222,26 @@ function handleBadgeCommand(args: string[]): void {
|
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
+
/**
|
|
226
|
+
* The installed package's version. package.json sits one level above both
|
|
227
|
+
* src/ (tests) and dist/ (the published bin).
|
|
228
|
+
*/
|
|
229
|
+
export function cliVersion(): string {
|
|
230
|
+
return JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8')).version;
|
|
231
|
+
}
|
|
232
|
+
|
|
225
233
|
/**
|
|
226
234
|
* CLI entry point
|
|
227
235
|
*/
|
|
228
236
|
async function main() {
|
|
229
237
|
const args = process.argv.slice(2);
|
|
230
238
|
|
|
239
|
+
// --version / -V (-v is --verbose)
|
|
240
|
+
if (args.includes('--version') || args.includes('-V')) {
|
|
241
|
+
console.log(cliVersion());
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
231
245
|
// Subcommand: badge
|
|
232
246
|
if (args[0] === 'badge') {
|
|
233
247
|
handleBadgeCommand(args.slice(1));
|
|
@@ -236,7 +250,7 @@ async function main() {
|
|
|
236
250
|
|
|
237
251
|
// Show help
|
|
238
252
|
if (args.includes('--help') || args.includes('-h')) {
|
|
239
|
-
console.log(`\nfaf-taf-git - The Git-Native Receipt Printer\n\nUSAGE:\n npm test 2>&1 | tee test-output.txt\n npx faf-taf-git --file test-output.txt [OPTIONS]\n\n # WJTTC / pc-ai bar\n node tests/wjttc/run-wjttc.mjs 2>&1 | tee wjttc-out.txt\n npx faf-taf-git --file wjttc-out.txt\n\nCOMMANDS:\n badge Generate a shields.io-style SVG badge from .taf\n\nOPTIONS:\n --file <path> Path to test output file (required)\n --commit Auto-commit .taf changes to git\n --message <msg> Custom commit message\n --cwd <dir> Working directory (default: current)\n --verbose, -v Verbose output\n --help, -h Show this help\n\nPARSERS:\n Bun, WJTTC (pc-ai bar), Jest, Vitest\n\nEXAMPLES:\n npm test 2>&1 | tee test-output.txt\n npx faf-taf-git --file test-output.txt\n\n npx faf-taf-git --file test-output.txt --commit\n\n npx faf-taf-git badge --output badge.svg\n\nPLATFORM SUPPORT:\n Works in ANY CI/CD that runs Node.js:\n GitHub Actions, GitLab CI, Jenkins, CircleCI,\n Bitbucket Pipelines, Azure Pipelines, local dev\n\nLEARN MORE:\n https://github.com/Wolfe-Jam/faf-taf-git\n`);
|
|
253
|
+
console.log(`\nfaf-taf-git - The Git-Native Receipt Printer\n\nUSAGE:\n npm test 2>&1 | tee test-output.txt\n npx faf-taf-git --file test-output.txt [OPTIONS]\n\n # WJTTC / pc-ai bar\n node tests/wjttc/run-wjttc.mjs 2>&1 | tee wjttc-out.txt\n npx faf-taf-git --file wjttc-out.txt\n\nCOMMANDS:\n badge Generate a shields.io-style SVG badge from .taf\n\nOPTIONS:\n --file <path> Path to test output file (required)\n --commit Auto-commit .taf changes to git\n --message <msg> Custom commit message\n --cwd <dir> Working directory (default: current)\n --verbose, -v Verbose output\n --version, -V Print the version\n --help, -h Show this help\n\nPARSERS:\n JUnit XML (pytest, cargo, Go, Java, .NET ...), Bun, WJTTC (pc-ai bar), Jest, Vitest\n\nEXAMPLES:\n npm test 2>&1 | tee test-output.txt\n npx faf-taf-git --file test-output.txt\n\n npx faf-taf-git --file test-output.txt --commit\n\n npx faf-taf-git badge --output badge.svg\n\nPLATFORM SUPPORT:\n Works in ANY CI/CD that runs Node.js:\n GitHub Actions, GitLab CI, Jenkins, CircleCI,\n Bitbucket Pipelines, Azure Pipelines, local dev\n\nLEARN MORE:\n https://github.com/Wolfe-Jam/faf-taf-git\n`);
|
|
240
254
|
process.exit(0);
|
|
241
255
|
}
|
|
242
256
|
|
package/src/index.ts
CHANGED
|
@@ -149,6 +149,7 @@ async function run(): Promise<void> {
|
|
|
149
149
|
core.setOutput('passed', testResults.passed.toString());
|
|
150
150
|
core.setOutput('failed', testResults.failed.toString());
|
|
151
151
|
core.setOutput('total', testResults.total.toString());
|
|
152
|
+
core.setOutput('skipped', (testResults.skipped ?? 0).toString());
|
|
152
153
|
|
|
153
154
|
// If target-branch is set, save .taf seed and switch branches
|
|
154
155
|
let tafSeed: string | null = null;
|
package/src/parsers/index.ts
CHANGED
|
@@ -7,20 +7,25 @@
|
|
|
7
7
|
import { TestResults } from './jest';
|
|
8
8
|
import { parseBunOutput } from './bun';
|
|
9
9
|
import { parseJestOutput } from './jest';
|
|
10
|
+
import { parseJunitOutput } from './junit';
|
|
10
11
|
import { parseVitestOutput } from './vitest';
|
|
11
12
|
import { parseWjttcOutput } from './wjttc';
|
|
12
13
|
|
|
13
14
|
export { TestResults } from './jest';
|
|
15
|
+
export { parseJunitOutput } from './junit';
|
|
14
16
|
export { parseWjttcOutput } from './wjttc';
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
* Every parser, in the order parseTestOutput tries them. Order matters:
|
|
18
|
-
* 1.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
20
|
+
* 1. JUnit XML — a `<testsuite>` element; first, because a report's captured
|
|
21
|
+
* stdout can hold another runner's summary line.
|
|
22
|
+
* 2. Bun — `Ran N tests across M files` is bun-unique.
|
|
23
|
+
* 3. WJTTC — `pc-ai WJTTC` / suite `pc-ai-wjttc` (FAF bar; not Jest-shaped).
|
|
24
|
+
* 4. Jest — `Tests: … total`.
|
|
25
|
+
* 5. Vitest — `Tests … (N)`.
|
|
22
26
|
*/
|
|
23
27
|
const PARSERS: ReadonlyArray<readonly [name: string, parse: (output: string) => TestResults | null]> = [
|
|
28
|
+
['JUnit XML', parseJunitOutput],
|
|
24
29
|
['Bun', parseBunOutput],
|
|
25
30
|
['WJTTC', parseWjttcOutput],
|
|
26
31
|
['Jest', parseJestOutput],
|