faf-taf-git 2.4.1 → 2.4.3

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +24 -1
  2. package/README.md +1 -4
  3. package/dist/parsers/junit.d.ts.map +1 -1
  4. package/dist/parsers/junit.js +6 -0
  5. package/dist/parsers/junit.js.map +1 -1
  6. package/dist/receipt-push.d.ts +21 -0
  7. package/dist/receipt-push.d.ts.map +1 -0
  8. package/dist/receipt-push.js +44 -0
  9. package/dist/receipt-push.js.map +1 -0
  10. package/package.json +14 -1
  11. package/project.faf +2 -2
  12. package/.faf-dna +0 -95
  13. package/.fafignore +0 -41
  14. package/.github/dependabot.yml +0 -10
  15. package/.github/workflows/ci.yml +0 -53
  16. package/.github/workflows/claude-code-review.yml +0 -36
  17. package/.github/workflows/claude.yml +0 -39
  18. package/.github/workflows/homebrew.yml +0 -19
  19. package/.taf +0 -98
  20. package/CLAUDE.md +0 -30
  21. package/CODE_OF_CONDUCT.md +0 -21
  22. package/CONTRIBUTING.md +0 -289
  23. package/SECURITY.md +0 -19
  24. package/action.yml +0 -50
  25. package/agent.fafa +0 -53
  26. package/badge.svg +0 -21
  27. package/dist/bundle/index.js +0 -36554
  28. package/dist/index.js +0 -42827
  29. package/dist/index.js.map +0 -1
  30. package/dist/licenses.txt +0 -126
  31. package/dist/sourcemap-register.js +0 -1
  32. package/docs/RELEASE-NOTES.md +0 -200
  33. package/docs/USER-GUIDE.md +0 -301
  34. package/jest.config.js +0 -13
  35. package/src/badge.ts +0 -138
  36. package/src/cli.ts +0 -311
  37. package/src/index.ts +0 -201
  38. package/src/parsers/bun.ts +0 -103
  39. package/src/parsers/index.ts +0 -50
  40. package/src/parsers/jest.ts +0 -104
  41. package/src/parsers/junit.ts +0 -110
  42. package/src/parsers/vitest.ts +0 -65
  43. package/src/parsers/wjttc.ts +0 -160
  44. package/src/taf-core.ts +0 -139
  45. package/test-mcp.ts +0 -83
  46. package/test-standalone.ts +0 -87
  47. package/tests/action-bundle.test.ts +0 -34
  48. package/tests/action-parse-error.test.ts +0 -47
  49. package/tests/badge.test.ts +0 -260
  50. package/tests/bun-parser.test.ts +0 -173
  51. package/tests/cli-version.test.ts +0 -31
  52. package/tests/jest-parser.test.ts +0 -122
  53. package/tests/junit-parser.test.ts +0 -109
  54. package/tests/vitest-parser.test.ts +0 -112
  55. package/tests/wjttc-parser.test.ts +0 -116
  56. package/tests/wjttc-taf.test.ts +0 -470
  57. package/tsconfig.json +0 -18
package/CHANGELOG.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <!-- faf: faf-taf-git | TypeScript | cli | A Test Receipt Printer for git -->
2
- <!-- faf: doc=changelog | latest=v2.4.1 | canonical=project.faf | family=TAF -->
2
+ <!-- faf: doc=changelog | latest=v2.4.3 | canonical=project.faf | family=TAF -->
3
3
 
4
4
  # Changelog
5
5
 
@@ -8,6 +8,29 @@ All notable changes to this project will be documented in this file.
8
8
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
9
9
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
10
10
 
11
+ ## [Unreleased]
12
+
13
+ ## [2.4.3] - 2026-10-31
14
+
15
+ A receipt that loses a push race is retried instead of lost, and skipped Go tests count as skipped, not passed.
16
+
17
+ ### Fixed
18
+ - **A receipt that lost a push race is no longer lost.** Two runs finishing close together both commit on the same `taf-receipts` tip, and the second push was rejected with a warning. The Action now fetches the branch again, adds its receipt on top of the winner's, and pushes, up to 5 tries. Only with `target-branch`: that branch holds nothing but `.taf`. Nothing is force-pushed; the branch only grows. Pushing to the current branch is unchanged
19
+ - **Skipped tests in a JUnit report no longer count as passed** when the report leaves `skipped` out of its counts. gotestsum (Go) writes `tests` and `failures` on its root and nothing else, so 1 pass, 1 fail and 1 skip read as 2 passed. The `<skipped>` testcases are counted instead
20
+
21
+ ### Changed
22
+ - **The README recipe no longer has a `concurrency` group.** GitHub cancels a waiting run when a newer one joins the group, so a run could end with no tests and no receipt. Runs that race for the push are retried instead (above)
23
+
24
+ ## [2.4.2] - 2026-10-30
25
+
26
+ undici 6.29.1 in the Action bundle (security), and the npm package ships only the CLI: 34 kB instead of 1.0 MB.
27
+
28
+ ### Security
29
+ - **undici 6.28.1 → 6.29.1** in the lockfile and the rebuilt Action bundle (`dist/index.js`). Clears 5 Dependabot alerts (TLS certificate check bypass, denial of service). undici comes in through `@actions/core`; faf-taf-git makes no HTTP requests itself, so the risk was low, but the bundle no longer carries a known-vulnerable copy.
30
+
31
+ ### Changed
32
+ - **The npm package ships only the CLI:** a `files` list in package.json. 1.0 MB → 34 kB packed, 94 → 48 files. Out: `src/`, `tests/`, `.github/`, dev configs, and the GitHub Action bundle (`dist/index.js`), which workflows run from the git tag, never from npm. The Action itself is unchanged.
33
+
11
34
  ## [2.4.1] - 2026-10-30
12
35
 
13
36
  `faf-taf-git --version` answers, and the descriptions say tamper-evident, not "cannot be gamed".
package/README.md CHANGED
@@ -51,9 +51,6 @@ on:
51
51
  pull_request:
52
52
  workflow_dispatch:
53
53
 
54
- concurrency:
55
- group: tests-${{ github.ref }} # one run at a time per branch, so receipts never collide
56
-
57
54
  jobs:
58
55
  test:
59
56
  runs-on: ubuntu-latest
@@ -76,7 +73,7 @@ jobs:
76
73
 
77
74
  - name: Print the receipt
78
75
  if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
79
- uses: Wolfe-Jam/faf-taf-git@v2.4.1
76
+ uses: Wolfe-Jam/faf-taf-git@v2.4.3
80
77
  with:
81
78
  test-output-file: test-output.txt
82
79
  target-branch: taf-receipts
@@ -1 +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"}
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,CAuDnE"}
@@ -92,6 +92,12 @@ function parseJunitOutput(output) {
92
92
  }
93
93
  if (counts.tests === 0)
94
94
  return null;
95
+ // Some writers leave `skipped` off their counts (gotestsum's <testsuites> root
96
+ // has tests and failures only), which would count every skip as a pass. The
97
+ // <skipped> testcases are the truth then.
98
+ if (counts.skipped === 0) {
99
+ counts.skipped = Math.min(countsFromTestcases(xml).skipped, counts.tests - counts.failed);
100
+ }
95
101
  const passed = Math.max(0, counts.tests - counts.failed - counts.skipped);
96
102
  return {
97
103
  total: counts.tests,
@@ -1 +1 @@
1
- {"version":3,"file":"junit.js","sourceRoot":"","sources":["../../src/parsers/junit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"junit.js","sourceRoot":"","sources":["../../src/parsers/junit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Push a receipt to the receipts branch, and try again when another run got
3
+ * there first.
4
+ *
5
+ * Two runs that finish close together both commit a receipt on top of the
6
+ * same branch tip; the second push is rejected (non-fast-forward). Before
7
+ * 2.4.3 that was a warning and the receipt was lost. Now the run fetches the
8
+ * branch again, resets to it, adds its receipt to the fresh .taf, and pushes,
9
+ * up to `attempts` times.
10
+ *
11
+ * Only for a dedicated receipts branch (`target-branch`): it holds nothing
12
+ * but .taf, so resetting to the remote throws away only this run's own
13
+ * rejected commit. Pushing to the current branch never resets.
14
+ */
15
+ /** Runs git with these args in the repo; resolves to the exit code. */
16
+ export type Git = (args: string[]) => Promise<number>;
17
+ export interface PushResult {
18
+ pushed: boolean;
19
+ attempts: number;
20
+ }
21
+ export declare function pushReceipt(git: Git, targetBranch: string, message: string, addReceipt: () => boolean, attempts?: number): Promise<PushResult>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"","sourceRoot":"","sources":["file:///Users/wolfejam/FAF/faf-taf-git/src/receipt-push.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,uEAAuE;AACvE,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEtD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,GAAG,EACR,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,OAAO,EACzB,QAAQ,SAAI,GACX,OAAO,CAAC,UAAU,CAAC,CAarB"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ /**
3
+ * Push a receipt to the receipts branch, and try again when another run got
4
+ * there first.
5
+ *
6
+ * Two runs that finish close together both commit a receipt on top of the
7
+ * same branch tip; the second push is rejected (non-fast-forward). Before
8
+ * 2.4.3 that was a warning and the receipt was lost. Now the run fetches the
9
+ * branch again, resets to it, adds its receipt to the fresh .taf, and pushes,
10
+ * up to `attempts` times.
11
+ *
12
+ * Only for a dedicated receipts branch (`target-branch`): it holds nothing
13
+ * but .taf, so resetting to the remote throws away only this run's own
14
+ * rejected commit. Pushing to the current branch never resets.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.pushReceipt = pushReceipt;
18
+ async function pushReceipt(git, targetBranch, message, addReceipt, attempts = 5) {
19
+ for (let attempt = 1; attempt <= attempts; attempt++) {
20
+ if (attempt > 1) {
21
+ // Another run pushed first: start again from its receipts.
22
+ if ((await git(['fetch', 'origin', targetBranch])) !== 0) {
23
+ break;
24
+ }
25
+ if ((await git(['reset', '--hard', `origin/${targetBranch}`])) !== 0) {
26
+ break;
27
+ }
28
+ if (!addReceipt()) {
29
+ break;
30
+ }
31
+ }
32
+ if ((await git(['add', '.taf'])) !== 0) {
33
+ break;
34
+ }
35
+ if ((await git(['commit', '-m', message])) !== 0) {
36
+ break;
37
+ }
38
+ if ((await git(['push', 'origin', targetBranch])) === 0) {
39
+ return { pushed: true, attempts: attempt };
40
+ }
41
+ }
42
+ return { pushed: false, attempts };
43
+ }
44
+ //# sourceMappingURL=receipt-push.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipt-push.js","sourceRoot":"","sources":["../src/receipt-push.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAUH,kCAmBC;AAnBM,KAAK,UAAU,WAAW,CAC/B,GAAQ,EACR,YAAoB,EACpB,OAAe,EACf,UAAyB,EACzB,QAAQ,GAAG,CAAC;IAEZ,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC;QACrD,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,2DAA2D;YAC3D,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBAAA,MAAM;YAAA,CAAC;YAClE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;gBAAA,MAAM;YAAA,CAAC;YAC9E,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;gBAAA,MAAM;YAAA,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YAAA,MAAM;QAAA,CAAC;QAChD,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YAAA,MAAM;QAAA,CAAC;QAC1D,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;QAAA,CAAC;IACxG,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;AACrC,CAAC"}
package/package.json CHANGED
@@ -1,11 +1,24 @@
1
1
  {
2
2
  "name": "faf-taf-git",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
4
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"
8
8
  },
9
+ "files": [
10
+ "dist/**/*",
11
+ "!dist/index.js",
12
+ "!dist/index.js.map",
13
+ "!dist/bundle",
14
+ "!dist/sourcemap-register.js",
15
+ "!dist/licenses.txt",
16
+ "README.md",
17
+ "RECEIPT-FORMAT.md",
18
+ "CHANGELOG.md",
19
+ "LICENSE",
20
+ "project.faf"
21
+ ],
9
22
  "scripts": {
10
23
  "build": "tsc && ncc build src/index.ts -o dist --source-map --license licenses.txt",
11
24
  "test": "jest"
package/project.faf CHANGED
@@ -29,8 +29,8 @@ human_context:
29
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
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
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."
32
+ when: v2.4.3 (2026-10-31), push-race retry + JUnit skipped count; v2.4.2 undici security fix + CLI-only npm package; v2.4.1 --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.3` 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
34
  monorepo:
35
35
  packages_count: slotignored
36
36
  build_orchestrator: slotignored
package/.faf-dna DELETED
@@ -1,95 +0,0 @@
1
- {
2
- "birthCertificate": {
3
- "born": "2025-10-28T01:26:05.692Z",
4
- "birthDNA": 22,
5
- "birthDNASource": "CLAUDE.md",
6
- "projectDNA": "1785d1ac1c20876b",
7
- "authenticated": false,
8
- "certificate": "FAF-2025-FAFTAFAC-TMZU"
9
- },
10
- "versions": [
11
- {
12
- "version": "v1.0.0",
13
- "timestamp": "2025-10-28T01:26:05.693Z",
14
- "score": 22,
15
- "changes": [
16
- "Initial context from CLAUDE.md"
17
- ],
18
- "approved": false,
19
- "growth": 0,
20
- "growthRate": 0
21
- },
22
- {
23
- "version": "v1.0.1",
24
- "timestamp": "2025-10-28T01:26:05.721Z",
25
- "score": 50,
26
- "changes": [
27
- "Initial .faf generation from project"
28
- ],
29
- "approved": false,
30
- "growth": 28,
31
- "growthRate": 28
32
- }
33
- ],
34
- "current": {
35
- "version": "v1.0.1",
36
- "score": 50,
37
- "approved": false,
38
- "lastSync": "2025-10-28T01:26:05.721Z"
39
- },
40
- "recovery": {
41
- "claudeMD": "/Users/wolfejam/FAF/faf-taf-action/CLAUDE.md",
42
- "lastBackup": "2025-10-28T01:26:05.693Z",
43
- "syncStatus": "active",
44
- "autoRecover": true
45
- },
46
- "growth": {
47
- "totalGrowth": 28,
48
- "daysActive": 0,
49
- "averageDailyGrowth": 28,
50
- "bestDay": {
51
- "date": "2025-10-28T01:26:05.721Z",
52
- "growth": 28
53
- },
54
- "bestWeek": {
55
- "start": "2025-10-28T01:26:05.693Z",
56
- "growth": 0
57
- },
58
- "milestones": [
59
- {
60
- "type": "birth",
61
- "score": 22,
62
- "date": "2025-10-28T01:26:05.693Z",
63
- "version": "v1.0.0",
64
- "label": "Birth",
65
- "emoji": "🐣"
66
- },
67
- {
68
- "type": "doubled",
69
- "score": 50,
70
- "date": "2025-10-28T01:26:05.721Z",
71
- "version": "v1.0.1",
72
- "label": "Doubled",
73
- "emoji": "2️⃣"
74
- },
75
- {
76
- "type": "peak",
77
- "score": 50,
78
- "date": "2025-10-28T01:26:05.721Z",
79
- "version": "v1.0.1",
80
- "label": "Peak",
81
- "emoji": "🏔️"
82
- },
83
- {
84
- "type": "current",
85
- "score": 50,
86
- "date": "2025-10-28T01:26:05.721Z",
87
- "version": "v1.0.1",
88
- "label": "Current",
89
- "emoji": "📍"
90
- }
91
- ]
92
- },
93
- "lastModified": "2025-10-28T01:26:05.721Z",
94
- "format": "faf-dna-v1"
95
- }
package/.fafignore DELETED
@@ -1,41 +0,0 @@
1
- # .fafignore - Exclude files/directories from .faf context
2
- # Similar to .gitignore syntax
3
- # Lines starting with # are comments
4
-
5
- # Dependencies and build outputs
6
- node_modules/
7
- dist/
8
- build/
9
- coverage/
10
-
11
- # Python environments
12
- __pycache__/
13
- venv/
14
- .venv/
15
-
16
- # IDE and system files
17
- .vscode/
18
- .idea/
19
- .DS_Store
20
-
21
- # Sensitive files
22
- .env
23
- .env.*
24
- *.key
25
- *.pem
26
-
27
- # Logs and temporary files
28
- *.log
29
- logs/
30
- tmp/
31
- temp/
32
-
33
- # Large media files
34
- *.jpg
35
- *.png
36
- *.mp4
37
- *.pdf
38
-
39
- # Custom exclusions (add your own below)
40
- # example: my-large-data-folder/
41
- # example: *.generated.ts
@@ -1,10 +0,0 @@
1
- version: 2
2
- updates:
3
- # Keeps workflow `uses:` pins current (e.g. Wolfe-Jam/faf-taf-git) so they
4
- # don't drift behind new releases. Security alerts don't need this file.
5
- - package-ecosystem: "github-actions"
6
- directory: "/"
7
- schedule:
8
- interval: "monthly"
9
- commit-message:
10
- prefix: "ci"
@@ -1,53 +0,0 @@
1
- name: CAR Pipeline
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- pull_request:
7
- branches: [main]
8
- workflow_dispatch:
9
-
10
- jobs:
11
- car:
12
- name: Claim → Audit → Receipt
13
- runs-on: ubuntu-latest
14
- permissions:
15
- contents: write
16
-
17
- steps:
18
- - uses: actions/checkout@v7
19
-
20
- - name: Setup Node.js
21
- uses: actions/setup-node@v7
22
- with:
23
- node-version: '24.x'
24
-
25
- - name: Install dependencies
26
- run: npm ci
27
-
28
- # ── C: CLAIM ──────────────────────────────────
29
- - name: 'C: Validate project.faf (Claim)'
30
- run: |
31
- if [ ! -f project.faf ]; then
32
- echo "::error::No project.faf found. Run 'faf init' to create one."
33
- exit 1
34
- fi
35
- node -e "require('yaml').parse(require('fs').readFileSync('project.faf','utf-8')); console.log('project.faf: valid YAML')"
36
- echo "Claim validated"
37
-
38
- # ── A: AUDIT ──────────────────────────────────
39
- - name: Build
40
- run: npm run build
41
-
42
- - name: 'A: Run tests (Audit)'
43
- run: npm test 2>&1 | tee test-output.txt
44
-
45
- # ── R: RECEIPT ────────────────────────────────
46
- - name: 'R: Generate TAF Receipt'
47
- if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main'
48
- uses: Wolfe-Jam/faf-taf-git@v2.3.1
49
- with:
50
- test-output-file: test-output.txt
51
- auto-commit: 'true'
52
- commit-message: 'chore(taf): update receipt [skip ci]'
53
- target-branch: taf-receipts
@@ -1,36 +0,0 @@
1
- name: Claude Code Review
2
-
3
- on:
4
- pull_request:
5
- types: [opened, synchronize, ready_for_review, reopened]
6
-
7
- jobs:
8
- claude-review:
9
- # A Dependabot PR cannot read this repo's Actions secrets — GitHub withholds
10
- # them from bot-authored runs — so the action fails its own env validation
11
- # and the PR carries a red that says nothing about the change it proposes.
12
- # Receipt (faf-cli, 2026-09-23): the last 8 human PRs all passed this
13
- # workflow and both Dependabot PRs failed on that error alone. A dependency
14
- # bump is Dependabot's diff to justify, not Claude's.
15
- if: github.actor != 'dependabot[bot]'
16
- runs-on: ubuntu-latest
17
- permissions:
18
- contents: read
19
- pull-requests: write
20
- issues: read
21
- id-token: write
22
-
23
- steps:
24
- - name: Checkout repository
25
- uses: actions/checkout@v7
26
- with:
27
- fetch-depth: 1
28
-
29
- - name: Run Claude Code Review
30
- id: claude-review
31
- uses: anthropics/claude-code-action@v1
32
- with:
33
- claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
34
- plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
35
- plugins: 'code-review@claude-code-plugins'
36
- prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
@@ -1,39 +0,0 @@
1
- name: Claude Code
2
-
3
- on:
4
- issue_comment:
5
- types: [created]
6
- pull_request_review_comment:
7
- types: [created]
8
- issues:
9
- types: [opened, assigned]
10
- pull_request_review:
11
- types: [submitted]
12
-
13
- jobs:
14
- claude:
15
- if: |
16
- (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
17
- (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
18
- (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
19
- (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
20
- runs-on: ubuntu-latest
21
- permissions:
22
- contents: write
23
- pull-requests: write
24
- issues: write
25
- id-token: write
26
- actions: read
27
- steps:
28
- - name: Checkout repository
29
- uses: actions/checkout@v7
30
- with:
31
- fetch-depth: 1
32
-
33
- - name: Run Claude Code
34
- id: claude
35
- uses: anthropics/claude-code-action@v1
36
- with:
37
- claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
38
- additional_permissions: |
39
- actions: read
@@ -1,19 +0,0 @@
1
- name: Update Homebrew
2
- on:
3
- push:
4
- tags: ["v*"]
5
-
6
- jobs:
7
- homebrew:
8
- runs-on: ubuntu-latest
9
- steps:
10
- - name: Update Homebrew formula
11
- run: |
12
- VERSION="${GITHUB_REF#refs/tags/v}"
13
- gh workflow run update-formula.yml \
14
- -R Wolfe-Jam/homebrew-faf \
15
- -f formula=faf-taf-git \
16
- -f version=$VERSION \
17
- -f npm_package=faf-taf-git
18
- env:
19
- GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
package/.taf DELETED
@@ -1,98 +0,0 @@
1
- format_version: 1.0.0
2
- project: faf-taf-git
3
- created: 2025-10-28T01:26:12.944Z
4
- last_updated: 2026-02-19T05:56:11.741Z
5
- faf_associated: true
6
- faf_location: project.faf
7
- faf_score: 65
8
- test_history:
9
- - timestamp: 2025-10-28T01:28:38.600Z
10
- result: PASSED
11
- tests:
12
- total: 7
13
- passed: 7
14
- failed: 0
15
- - timestamp: 2025-10-28T01:40:23.935Z
16
- result: PASSED
17
- tests:
18
- total: 7
19
- passed: 7
20
- failed: 0
21
- trigger: github-actions
22
- - timestamp: 2026-02-18T02:24:34.363Z
23
- result: PASSED
24
- tests:
25
- total: 38
26
- passed: 38
27
- failed: 0
28
- trigger: github-actions
29
- - timestamp: 2026-02-18T02:45:42.500Z
30
- result: PASSED
31
- tests:
32
- total: 55
33
- passed: 55
34
- failed: 0
35
- trigger: github-actions
36
- - timestamp: 2026-02-18T03:07:37.867Z
37
- result: PASSED
38
- tests:
39
- total: 55
40
- passed: 55
41
- failed: 0
42
- trigger: github-actions
43
- - timestamp: 2026-02-18T03:11:02.179Z
44
- result: PASSED
45
- tests:
46
- total: 55
47
- passed: 55
48
- failed: 0
49
- trigger: github-actions
50
- - timestamp: 2026-02-18T03:24:05.159Z
51
- result: PASSED
52
- tests:
53
- total: 55
54
- passed: 55
55
- failed: 0
56
- trigger: github-actions
57
- - timestamp: 2026-02-18T03:28:51.125Z
58
- result: PASSED
59
- tests:
60
- total: 55
61
- passed: 55
62
- failed: 0
63
- trigger: github-actions
64
- - timestamp: 2026-02-18T05:59:46.851Z
65
- result: PASSED
66
- tests:
67
- total: 55
68
- passed: 55
69
- failed: 0
70
- trigger: github-actions
71
- - timestamp: 2026-02-18T06:24:51.475Z
72
- result: PASSED
73
- tests:
74
- total: 55
75
- passed: 55
76
- failed: 0
77
- trigger: github-actions
78
- - timestamp: 2026-02-18T06:37:15.943Z
79
- result: PASSED
80
- tests:
81
- total: 55
82
- passed: 55
83
- failed: 0
84
- trigger: github-actions
85
- - timestamp: 2026-02-18T20:33:40.820Z
86
- result: PASSED
87
- tests:
88
- total: 55
89
- passed: 55
90
- failed: 0
91
- trigger: github-actions
92
- - timestamp: 2026-02-19T05:56:11.741Z
93
- result: PASSED
94
- tests:
95
- total: 55
96
- passed: 55
97
- failed: 0
98
- trigger: github-actions
package/CLAUDE.md DELETED
@@ -1,30 +0,0 @@
1
- <!-- faf:start -->
2
- <!-- faf: faf-taf-git | TypeScript | cli | A Test Receipt Printer for git. Every CI run prints a receipt to .taf: append-only, timestamped, kept in git. Proof over time. -->
3
- <!-- faf: claim=project.faf | family=FAF -->
4
-
5
- # CLAUDE.md — faf-taf-git
6
-
7
- ## What This Is
8
-
9
- A Test Receipt Printer for git. Every CI run prints a receipt to .taf: append-only, timestamped, kept in git. Proof over time.
10
-
11
- ## Stack
12
-
13
- - **Language:** TypeScript
14
- - **Hosting:** npm registry + GitHub Actions Marketplace
15
- - **Build:** TypeScript (tsc)
16
- - **CI/CD:** GitHub Actions
17
-
18
- ## Context
19
-
20
- - **Who:** Maintainers and teams who want proof their tests kept passing on main, and the reviewers, auditors and AI agents who check it
21
- - **What:** A Test Receipt Printer for git. Every CI run prints a receipt to .taf: append-only, timestamped, kept in git. Proof over time.
22
- - **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.
23
- - **Where:** https://github.com/Wolfe-Jam/faf-taf-git
24
- - **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)
25
- - **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.
26
-
27
- ---
28
-
29
- *STATUS: SYNC ACTIVE — 2026-10-30T04:26:00.762Z*
30
- <!-- faf:end -->
@@ -1,21 +0,0 @@
1
- # Code of Conduct
2
-
3
- This project adopts the [Contributor Covenant, v2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) as its code of conduct. The full text of that covenant governs behavior in this project and its community spaces.
4
-
5
- ## Summary
6
-
7
- - We commit to maintaining a respectful, harassment-free environment for everyone who participates, regardless of background.
8
- - Participation includes contributing code, opening issues, reviewing pull requests, and interacting in any official channel.
9
- - The Contributor Covenant defines the full scope, expected conduct, and enforcement guidelines. See the link above for the complete text.
10
-
11
- ## Reporting
12
-
13
- If you observe conduct that violates this Code of Conduct, please email **team@faf.one**. Reports are handled confidentially. Maintainers will review, respond, and take appropriate action consistent with the Contributor Covenant's enforcement guidelines.
14
-
15
- ## Scope
16
-
17
- This Code of Conduct applies to all project spaces — the repository, issues, pull requests, discussions, and any public communication channels operated by the project. It also applies when representing the project in other forums.
18
-
19
- ## Attribution
20
-
21
- This Code of Conduct adopts the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/), available under the CC BY 4.0 license.