faf-taf-git 2.4.1 → 2.4.2

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 (50) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/README.md +1 -1
  3. package/package.json +14 -1
  4. package/project.faf +2 -2
  5. package/.faf-dna +0 -95
  6. package/.fafignore +0 -41
  7. package/.github/dependabot.yml +0 -10
  8. package/.github/workflows/ci.yml +0 -53
  9. package/.github/workflows/claude-code-review.yml +0 -36
  10. package/.github/workflows/claude.yml +0 -39
  11. package/.github/workflows/homebrew.yml +0 -19
  12. package/.taf +0 -98
  13. package/CLAUDE.md +0 -30
  14. package/CODE_OF_CONDUCT.md +0 -21
  15. package/CONTRIBUTING.md +0 -289
  16. package/SECURITY.md +0 -19
  17. package/action.yml +0 -50
  18. package/agent.fafa +0 -53
  19. package/badge.svg +0 -21
  20. package/dist/bundle/index.js +0 -36554
  21. package/dist/index.js +0 -42827
  22. package/dist/index.js.map +0 -1
  23. package/dist/licenses.txt +0 -126
  24. package/dist/sourcemap-register.js +0 -1
  25. package/docs/RELEASE-NOTES.md +0 -200
  26. package/docs/USER-GUIDE.md +0 -301
  27. package/jest.config.js +0 -13
  28. package/src/badge.ts +0 -138
  29. package/src/cli.ts +0 -311
  30. package/src/index.ts +0 -201
  31. package/src/parsers/bun.ts +0 -103
  32. package/src/parsers/index.ts +0 -50
  33. package/src/parsers/jest.ts +0 -104
  34. package/src/parsers/junit.ts +0 -110
  35. package/src/parsers/vitest.ts +0 -65
  36. package/src/parsers/wjttc.ts +0 -160
  37. package/src/taf-core.ts +0 -139
  38. package/test-mcp.ts +0 -83
  39. package/test-standalone.ts +0 -87
  40. package/tests/action-bundle.test.ts +0 -34
  41. package/tests/action-parse-error.test.ts +0 -47
  42. package/tests/badge.test.ts +0 -260
  43. package/tests/bun-parser.test.ts +0 -173
  44. package/tests/cli-version.test.ts +0 -31
  45. package/tests/jest-parser.test.ts +0 -122
  46. package/tests/junit-parser.test.ts +0 -109
  47. package/tests/vitest-parser.test.ts +0 -112
  48. package/tests/wjttc-parser.test.ts +0 -116
  49. package/tests/wjttc-taf.test.ts +0 -470
  50. package/tsconfig.json +0 -18
@@ -1,104 +0,0 @@
1
- /**
2
- * Jest output parser
3
- *
4
- * Extracts test counts from Jest CLI output
5
- */
6
-
7
- export interface TestResults {
8
- total: number;
9
- passed: number;
10
- failed: number;
11
- skipped?: number;
12
- result: 'PASSED' | 'FAILED' | 'IMPROVED' | 'DEGRADED';
13
- }
14
-
15
- /**
16
- * Parse Jest output to extract test results
17
- *
18
- * Jest output formats:
19
- * - "Tests: 1 failed, 172 passed, 173 total"
20
- * - "Tests: 173 passed, 173 total"
21
- * - "Test Suites: 2 failed, 16 passed, 18 total"
22
- * - "Tests: 9 skipped, 799 passed, 808 total" (with padding)
23
- */
24
- export function parseJestOutput(output: string): TestResults | null {
25
- // Strip ANSI color codes and other control characters
26
- // eslint-disable-next-line no-control-regex
27
- let cleanOutput = output.replace(/\x1b\[[0-9;]*m/g, '');
28
- // Also strip carriage returns and normalize line endings
29
- cleanOutput = cleanOutput.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
30
-
31
- // Find the Jest test summary line
32
- // CRITICAL: Must match "Tests:" line that contains "total" to avoid matching
33
- // test descriptions like "Brake Tests: Critical dogfooding scenarios"
34
- const testSummaryPattern = /Tests:\s+(.+?\d+\s+total)/im;
35
- const testLineMatch = cleanOutput.match(testSummaryPattern);
36
-
37
- if (!testLineMatch || !testLineMatch[1]) {
38
- return null;
39
- }
40
-
41
- const testLine = testLineMatch[1];
42
-
43
- // Extract counts using flexible patterns
44
- let total = 0;
45
- let passed = 0;
46
- let failed = 0;
47
- let skipped = 0;
48
-
49
- // Parse numbers - use global search on the whole output near the Tests: line
50
- const totalMatch = testLine.match(/(\d+)\s+total/i);
51
- if (totalMatch) {
52
- total = parseInt(totalMatch[1], 10);
53
- }
54
-
55
- const passedMatch = testLine.match(/(\d+)\s+passed/i);
56
- if (passedMatch) {
57
- passed = parseInt(passedMatch[1], 10);
58
- }
59
-
60
- const failedMatch = testLine.match(/(\d+)\s+failed/i);
61
- if (failedMatch) {
62
- failed = parseInt(failedMatch[1], 10);
63
- }
64
-
65
- const skippedMatch = testLine.match(/(\d+)\s+skipped/i);
66
- if (skippedMatch) {
67
- skipped = parseInt(skippedMatch[1], 10);
68
- }
69
-
70
- // Validate
71
- if (total === 0) {
72
- return null;
73
- }
74
-
75
- // Determine result
76
- let result: 'PASSED' | 'FAILED' | 'IMPROVED' | 'DEGRADED' = 'PASSED';
77
- if (failed > 0) {
78
- result = 'FAILED';
79
- }
80
-
81
- return {
82
- total,
83
- passed,
84
- failed,
85
- skipped: skipped > 0 ? skipped : undefined,
86
- result,
87
- };
88
- }
89
-
90
- /**
91
- * Example Jest outputs for testing:
92
- *
93
- * All passing:
94
- * "Tests: 173 passed, 173 total"
95
- *
96
- * Some failing:
97
- * "Tests: 1 failed, 172 passed, 173 total"
98
- *
99
- * With skipped:
100
- * "Tests: 1 failed, 2 skipped, 170 passed, 173 total"
101
- *
102
- * With padding (CI):
103
- * "Tests: 9 skipped, 799 passed, 808 total"
104
- */
@@ -1,110 +0,0 @@
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
-
9
- import { TestResults } from './jest';
10
-
11
- const SUITE_TAG = /<(\/?)testsuite\b([^>]*?)(\/?)>/g;
12
-
13
- /** Read one numeric attribute; undefined when the attribute is absent. */
14
- function attr(attrs: string, name: string): number | undefined {
15
- const match = attrs.match(new RegExp(`\\b${name}\\s*=\\s*["'](\\d+)["']`));
16
- return match ? parseInt(match[1], 10) : undefined;
17
- }
18
-
19
- interface Counts {
20
- tests: number;
21
- failed: number;
22
- skipped: number;
23
- }
24
-
25
- /** Counts from a <testsuite> or <testsuites> attribute list, or null without a `tests` count. */
26
- function countsFromAttrs(attrs: string): Counts | null {
27
- const tests = attr(attrs, 'tests');
28
- if (tests === undefined) return null;
29
- return {
30
- tests,
31
- failed: (attr(attrs, 'failures') ?? 0) + (attr(attrs, 'errors') ?? 0),
32
- skipped: (attr(attrs, 'skipped') ?? 0) + (attr(attrs, 'disabled') ?? 0),
33
- };
34
- }
35
-
36
- /** Fallback when suites carry no counts: walk the <testcase> elements themselves. */
37
- function countsFromTestcases(xml: string): Counts {
38
- const counts: Counts = { tests: 0, failed: 0, skipped: 0 };
39
- const testcase = /<testcase\b[^>]*?(?:\/>|>([\s\S]*?)<\/testcase>)/g;
40
- let match: RegExpExecArray | null;
41
- while ((match = testcase.exec(xml)) !== null) {
42
- counts.tests++;
43
- const body = match[1] ?? '';
44
- if (/<(failure|error)\b/.test(body)) counts.failed++;
45
- else if (/<skipped\b/.test(body)) counts.skipped++;
46
- }
47
- return counts;
48
- }
49
-
50
- /**
51
- * Parse a JUnit XML report to extract test results
52
- *
53
- * Handles:
54
- * - a <testsuites> root that carries the totals (gotestsum, Maven)
55
- * - a <testsuites> root without totals, around counted <testsuite>s (pytest)
56
- * - a single <testsuite> root
57
- * - nested <testsuite>s (only the outermost level is counted, never twice)
58
- * - suites with no counts at all (the <testcase> elements are counted instead)
59
- *
60
- * failures + errors count as failed; skipped + disabled count as skipped.
61
- */
62
- export function parseJunitOutput(output: string): TestResults | null {
63
- const xml = output.replace(/<!--[\s\S]*?-->/g, '');
64
- if (!/<testsuites?\b/.test(xml)) return null;
65
-
66
- let counts: Counts | null = null;
67
-
68
- const root = xml.match(/<testsuites\b([^>]*)>/);
69
- if (root) counts = countsFromAttrs(root[1]);
70
-
71
- if (!counts) {
72
- // Sum the outermost <testsuite>s; a suite without counts sends us to the testcases.
73
- let depth = 0;
74
- let summed: Counts | null = { tests: 0, failed: 0, skipped: 0 };
75
- let seen = 0;
76
- let match: RegExpExecArray | null;
77
- SUITE_TAG.lastIndex = 0;
78
- while ((match = SUITE_TAG.exec(xml)) !== null) {
79
- const [, closing, attrs, selfClosing] = match;
80
- if (closing) {
81
- depth--;
82
- continue;
83
- }
84
- if (depth === 0 && summed) {
85
- seen++;
86
- const suite = countsFromAttrs(attrs);
87
- if (suite) {
88
- summed.tests += suite.tests;
89
- summed.failed += suite.failed;
90
- summed.skipped += suite.skipped;
91
- } else {
92
- summed = null;
93
- }
94
- }
95
- if (!selfClosing) depth++;
96
- }
97
- counts = seen > 0 && summed ? summed : countsFromTestcases(xml);
98
- }
99
-
100
- if (counts.tests === 0) return null;
101
-
102
- const passed = Math.max(0, counts.tests - counts.failed - counts.skipped);
103
- return {
104
- total: counts.tests,
105
- passed,
106
- failed: counts.failed,
107
- skipped: counts.skipped > 0 ? counts.skipped : undefined,
108
- result: counts.failed > 0 ? 'FAILED' : 'PASSED',
109
- };
110
- }
@@ -1,65 +0,0 @@
1
- /**
2
- * Vitest output parser
3
- *
4
- * Extracts test counts from Vitest CLI output
5
- */
6
-
7
- import { TestResults } from './jest';
8
-
9
- /**
10
- * Parse Vitest output to extract test results
11
- *
12
- * Vitest output formats:
13
- * - " Tests 8 passed (8)"
14
- * - " Tests 2 failed | 6 passed (8)"
15
- * - " Tests 1 skipped | 7 passed (8)"
16
- * - " Tests 1 failed | 2 skipped | 5 passed (8)"
17
- */
18
- export function parseVitestOutput(output: string): TestResults | null {
19
- // Strip ANSI color codes
20
- // eslint-disable-next-line no-control-regex
21
- let cleanOutput = output.replace(/\x1b\[[0-9;]*m/g, '');
22
- cleanOutput = cleanOutput.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
23
-
24
- // Vitest summary pattern: " Tests ... (N)" where N is total in parens
25
- const testSummaryPattern = /^\s*Tests\s+(.+?\(\d+\))/m;
26
- const testLineMatch = cleanOutput.match(testSummaryPattern);
27
-
28
- if (!testLineMatch || !testLineMatch[1]) {
29
- return null;
30
- }
31
-
32
- const testLine = testLineMatch[1];
33
-
34
- // Extract total from parentheses at end
35
- const totalMatch = testLine.match(/\((\d+)\)\s*$/);
36
- if (!totalMatch) return null;
37
- const total = parseInt(totalMatch[1], 10);
38
- if (total === 0) return null;
39
-
40
- let passed = 0;
41
- let failed = 0;
42
- let skipped = 0;
43
-
44
- const passedMatch = testLine.match(/(\d+)\s+passed/i);
45
- if (passedMatch) passed = parseInt(passedMatch[1], 10);
46
-
47
- const failedMatch = testLine.match(/(\d+)\s+failed/i);
48
- if (failedMatch) failed = parseInt(failedMatch[1], 10);
49
-
50
- const skippedMatch = testLine.match(/(\d+)\s+skipped/i);
51
- if (skippedMatch) skipped = parseInt(skippedMatch[1], 10);
52
-
53
- const todoMatch = testLine.match(/(\d+)\s+todo/i);
54
- if (todoMatch) skipped += parseInt(todoMatch[1], 10);
55
-
56
- let result: 'PASSED' | 'FAILED' = failed > 0 ? 'FAILED' : 'PASSED';
57
-
58
- return {
59
- total,
60
- passed,
61
- failed,
62
- skipped: skipped > 0 ? skipped : undefined,
63
- result,
64
- };
65
- }
@@ -1,160 +0,0 @@
1
- /**
2
- * WJTTC output parser
3
- *
4
- * Extracts test counts from the FAF / pc-ai WJTTC bar runner
5
- * (tests/wjttc/run-wjttc.mjs and sibling suite runners).
6
- *
7
- * Two shapes:
8
- *
9
- * 1) Human log (default):
10
- * ```
11
- * pc-ai WJTTC
12
- * ----------
13
- * PASS VAL-01 valid-simple portfolio accepts
14
- * FAIL OPT-01 …
15
- * ----------
16
- * 31/33 passed
17
- * ```
18
- *
19
- * 2) Machine JSON (`--json`):
20
- * ```
21
- * {
22
- * "suite": "pc-ai-wjttc",
23
- * "total": 33,
24
- * "passed": 31,
25
- * "failed": 2,
26
- * "results": [ … ]
27
- * }
28
- * ```
29
- *
30
- * Anchors are WJTTC-specific so this never false-matches Jest/Vitest/Bun.
31
- * Prefer JSON when both appear in a teed stream (structured totals win).
32
- */
33
-
34
- import { TestResults } from './jest';
35
-
36
- function stripAnsi(output: string): string {
37
- // eslint-disable-next-line no-control-regex
38
- return output
39
- .replace(/\x1b\[[0-9;]*m/g, '')
40
- .replace(/\r\n/g, '\n')
41
- .replace(/\r/g, '\n');
42
- }
43
-
44
- /**
45
- * Try to parse a WJTTC --json summary object from output.
46
- * Handles pure JSON or JSON embedded after build noise in a tee file.
47
- */
48
- function parseJsonSuite(clean: string): TestResults | null {
49
- // Prefer a top-level object that names the suite.
50
- const candidates: string[] = [];
51
-
52
- const trimmed = clean.trim();
53
- if (trimmed.startsWith('{')) {
54
- candidates.push(trimmed);
55
- }
56
-
57
- // Last {...} block often is the suite when logs precede JSON.
58
- const lastBrace = clean.lastIndexOf('{');
59
- if (lastBrace !== -1) {
60
- candidates.push(clean.slice(lastBrace));
61
- }
62
-
63
- for (const raw of candidates) {
64
- try {
65
- const body = JSON.parse(raw);
66
- if (!body || typeof body !== 'object') continue;
67
- if (body.suite !== 'pc-ai-wjttc') continue;
68
-
69
- const total = Number(body.total);
70
- const passed = Number(body.passed);
71
- const failed = Number(body.failed);
72
- if (!Number.isFinite(total) || total <= 0) continue;
73
- if (!Number.isFinite(passed) || !Number.isFinite(failed)) continue;
74
-
75
- // Prefer explicit fields; fall back to results[] length if needed.
76
- let p = passed;
77
- let f = failed;
78
- let t = total;
79
- if (Array.isArray(body.results) && body.results.length > 0) {
80
- const fromRows = body.results.length;
81
- if (t !== fromRows && fromRows > 0) {
82
- // Trust results array as the executed set (partition honesty).
83
- t = fromRows;
84
- p = body.results.filter((r: { ok?: boolean }) => r && r.ok === true).length;
85
- f = t - p;
86
- }
87
- }
88
-
89
- return {
90
- total: t,
91
- passed: p,
92
- failed: f,
93
- result: f > 0 ? 'FAILED' : 'PASSED',
94
- };
95
- } catch {
96
- // try next candidate
97
- }
98
- }
99
-
100
- return null;
101
- }
102
-
103
- /**
104
- * Human WJTTC log: header + optional PASS/FAIL lines + "N/N passed".
105
- */
106
- function parseHumanLog(clean: string): TestResults | null {
107
- // Require the suite banner so we do not steal "12/12 passed" from other tools.
108
- if (!/pc-ai\s+WJTTC/i.test(clean)) {
109
- return null;
110
- }
111
-
112
- const summary = clean.match(/(\d+)\s*\/\s*(\d+)\s+passed\b/i);
113
- if (!summary) return null;
114
-
115
- const passedFromSummary = parseInt(summary[1], 10);
116
- const totalFromSummary = parseInt(summary[2], 10);
117
- if (totalFromSummary <= 0) return null;
118
-
119
- // Cross-check with PASS/FAIL lines when present (stronger than summary alone).
120
- const passLines = clean.match(/^PASS\s+\S+/gm);
121
- const failLines = clean.match(/^FAIL\s+\S+/gm);
122
- const linePassed = passLines ? passLines.length : -1;
123
- const lineFailed = failLines ? failLines.length : -1;
124
-
125
- let total = totalFromSummary;
126
- let passed = passedFromSummary;
127
- let failed = total - passed;
128
-
129
- if (linePassed >= 0 && lineFailed >= 0) {
130
- const lineTotal = linePassed + lineFailed;
131
- if (lineTotal === totalFromSummary) {
132
- passed = linePassed;
133
- failed = lineFailed;
134
- total = lineTotal;
135
- }
136
- // If lines disagree with summary, still use summary (runner is source of truth)
137
- // but failed must be non-negative.
138
- if (failed < 0) failed = 0;
139
- }
140
-
141
- return {
142
- total,
143
- passed,
144
- failed,
145
- result: failed > 0 ? 'FAILED' : 'PASSED',
146
- };
147
- }
148
-
149
- /**
150
- * Parse WJTTC (pc-ai bar) output to TestResults, or null if not WJTTC.
151
- */
152
- export function parseWjttcOutput(output: string): TestResults | null {
153
- const clean = stripAnsi(output);
154
-
155
- // JSON first — structured totals when --json was used.
156
- const fromJson = parseJsonSuite(clean);
157
- if (fromJson) return fromJson;
158
-
159
- return parseHumanLog(clean);
160
- }
package/src/taf-core.ts DELETED
@@ -1,139 +0,0 @@
1
- /**
2
- * TAF Core - Simplified for GitHub Action
3
- *
4
- * Pure functions for reading, parsing, and updating .taf files
5
- * Derived from faf-cli TAF implementation (MCP-portable)
6
- */
7
-
8
- import * as fs from 'fs';
9
- import * as yaml from 'yaml';
10
- import { TestResults } from './parsers/jest';
11
-
12
- interface TAFFile {
13
- format_version?: string;
14
- project?: string;
15
- created?: string;
16
- last_updated?: string;
17
- test_history: TestRun[];
18
- [key: string]: any; // Allow other fields
19
- }
20
-
21
- interface TestRun {
22
- timestamp: string;
23
- result: 'PASSED' | 'FAILED' | 'IMPROVED' | 'DEGRADED';
24
- tests: {
25
- total: number;
26
- passed: number;
27
- failed: number;
28
- skipped?: number;
29
- };
30
- command?: string;
31
- trigger?: string;
32
- }
33
-
34
- /**
35
- * Update .taf file with new test results
36
- * Creates the file if it doesn't exist
37
- */
38
- export function updateTafFile(
39
- tafPath: string,
40
- testResults: TestResults
41
- ): boolean {
42
- try {
43
- let taf: TAFFile;
44
-
45
- // Check if .taf exists, create if not
46
- if (fs.existsSync(tafPath)) {
47
- const content = fs.readFileSync(tafPath, 'utf-8');
48
- taf = parseTAF(content);
49
- } else {
50
- // Create new .taf file
51
- const projectName = require('path').basename(require('path').dirname(tafPath));
52
- taf = createTAF(projectName);
53
- }
54
-
55
- // Create test run entry
56
- const run: TestRun = {
57
- timestamp: new Date().toISOString(),
58
- result: testResults.result,
59
- tests: {
60
- total: testResults.total,
61
- passed: testResults.passed,
62
- failed: testResults.failed,
63
- skipped: testResults.skipped,
64
- },
65
- trigger: 'github-actions',
66
- };
67
-
68
- // Append to history
69
- taf.test_history.push(run);
70
-
71
- // Serialize and write back
72
- const updated = serializeTAF(taf);
73
- fs.writeFileSync(tafPath, updated, 'utf-8');
74
-
75
- return true;
76
- } catch (error) {
77
- console.error('Failed to update .taf file:', error);
78
- return false;
79
- }
80
- }
81
-
82
- /**
83
- * Create a new TAF file structure
84
- */
85
- function createTAF(projectName: string): TAFFile {
86
- return {
87
- format_version: '1.0.0',
88
- project: projectName,
89
- created: new Date().toISOString(),
90
- last_updated: new Date().toISOString(),
91
- test_history: [],
92
- };
93
- }
94
-
95
- /**
96
- * Parse .taf file content
97
- */
98
- function parseTAF(content: string): TAFFile {
99
- // Split on document separator and take only first document
100
- const lines = content.split('\n');
101
- const yamlLines: string[] = [];
102
-
103
- for (const line of lines) {
104
- // Stop at document separator (but skip initial one if present)
105
- if (line.trim() === '---' && yamlLines.length > 0) {
106
- break;
107
- }
108
- // Skip initial document separator
109
- if (line.trim() === '---' && yamlLines.length === 0) {
110
- continue;
111
- }
112
- yamlLines.push(line);
113
- }
114
-
115
- const parsed = yaml.parse(yamlLines.join('\n'));
116
-
117
- // Basic validation
118
- if (!parsed || typeof parsed !== 'object') {
119
- throw new Error('Invalid .taf file: not a valid YAML object');
120
- }
121
-
122
- if (!parsed.test_history || !Array.isArray(parsed.test_history)) {
123
- throw new Error('Invalid .taf file: missing or invalid test_history');
124
- }
125
-
126
- return parsed as TAFFile;
127
- }
128
-
129
- /**
130
- * Serialize TAF object back to YAML
131
- * Uses yaml library to maintain existing format
132
- */
133
- function serializeTAF(taf: TAFFile): string {
134
- // Update last_updated timestamp
135
- taf.last_updated = new Date().toISOString();
136
-
137
- // Use yaml.stringify to preserve format
138
- return yaml.stringify(taf);
139
- }
package/test-mcp.ts DELETED
@@ -1,83 +0,0 @@
1
- /**
2
- * Test action with claude-faf-mcp repository
3
- */
4
-
5
- import * as fs from 'fs';
6
- import * as path from 'path';
7
- import { parseJestOutput } from './src/parsers/jest';
8
- import { updateTafFile } from './src/taf-core';
9
-
10
- async function testMCP() {
11
- console.log('Testing action with claude-faf-mcp repo...\n');
12
-
13
- // Simulate Jest output (based on typical MCP test output)
14
- const jestOutput = `
15
- PASS tests/tools.test.ts
16
- PASS tests/validation.test.ts
17
-
18
- Test Suites: 2 passed, 2 total
19
- Tests: 15 passed, 15 total
20
- Snapshots: 0 total
21
- Time: 1.234 s
22
- `;
23
-
24
- console.log('1. Parsing Jest output...');
25
- const testResults = parseJestOutput(jestOutput);
26
-
27
- if (!testResults) {
28
- console.error('❌ Failed to parse Jest output');
29
- process.exit(1);
30
- }
31
-
32
- console.log('✅ Parsed successfully:');
33
- console.log(` - Total: ${testResults.total}`);
34
- console.log(` - Passed: ${testResults.passed}`);
35
- console.log(` - Failed: ${testResults.failed}`);
36
- console.log(` - Result: ${testResults.result}\n`);
37
-
38
- // Test with MCP .taf file
39
- const tafPath = path.join('/Users/wolfejam/FAF/claude-faf-mcp', '.taf');
40
-
41
- console.log('2. Checking .taf file...');
42
- if (!fs.existsSync(tafPath)) {
43
- console.error('❌ No .taf file found at:', tafPath);
44
- process.exit(1);
45
- }
46
- console.log('✅ Found .taf file\n');
47
-
48
- console.log('3. Reading current .taf file...');
49
- const beforeContent = fs.readFileSync(tafPath, 'utf-8');
50
- const beforeLines = beforeContent.split('\n').filter(line => line.includes('timestamp')).length;
51
- console.log(`✅ Current test runs: ${beforeLines}\n`);
52
-
53
- console.log('4. Updating .taf file...');
54
- const updated = await updateTafFile(tafPath, testResults);
55
-
56
- if (!updated) {
57
- console.error('❌ Failed to update .taf file');
58
- process.exit(1);
59
- }
60
- console.log('✅ .taf file updated\n');
61
-
62
- console.log('5. Verifying update...');
63
- const afterContent = fs.readFileSync(tafPath, 'utf-8');
64
- const afterLines = afterContent.split('\n').filter(line => line.includes('timestamp')).length;
65
- console.log(`✅ Test runs after update: ${afterLines}`);
66
-
67
- if (afterLines !== beforeLines + 1) {
68
- console.error('❌ Expected one additional run');
69
- process.exit(1);
70
- }
71
-
72
- console.log('\n✅ MCP test PASSED');
73
- console.log('\nThe action successfully:');
74
- console.log(' - Parsed Jest output (15/15 tests)');
75
- console.log(' - Updated .taf file');
76
- console.log(' - Added new test run entry');
77
- console.log(' - Maintained proper format');
78
- }
79
-
80
- testMCP().catch(error => {
81
- console.error('❌ Test failed:', error);
82
- process.exit(1);
83
- });