faf-cli 3.0.6 → 3.1.0

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 (106) hide show
  1. package/README.md +200 -18
  2. package/assets/screenshots/package-json+project-faf.png +0 -0
  3. package/dist/big-orange/compare.d.ts.map +1 -1
  4. package/dist/big-orange/compare.js +14 -16
  5. package/dist/big-orange/compare.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +137 -1
  8. package/dist/cli.js.map +1 -1
  9. package/dist/commands/auto.d.ts.map +1 -1
  10. package/dist/commands/auto.js +69 -12
  11. package/dist/commands/auto.js.map +1 -1
  12. package/dist/commands/bi-sync.d.ts.map +1 -1
  13. package/dist/commands/bi-sync.js +10 -3
  14. package/dist/commands/bi-sync.js.map +1 -1
  15. package/dist/commands/drift.d.ts +16 -0
  16. package/dist/commands/drift.d.ts.map +1 -0
  17. package/dist/commands/drift.js +517 -0
  18. package/dist/commands/drift.js.map +1 -0
  19. package/dist/commands/git.d.ts +25 -0
  20. package/dist/commands/git.d.ts.map +1 -0
  21. package/dist/commands/git.js +355 -0
  22. package/dist/commands/git.js.map +1 -0
  23. package/dist/commands/init.d.ts.map +1 -1
  24. package/dist/commands/init.js +5 -4
  25. package/dist/commands/init.js.map +1 -1
  26. package/dist/commands/migrate.d.ts +11 -0
  27. package/dist/commands/migrate.d.ts.map +1 -0
  28. package/dist/commands/migrate.js +85 -0
  29. package/dist/commands/migrate.js.map +1 -0
  30. package/dist/commands/rename.d.ts +18 -0
  31. package/dist/commands/rename.d.ts.map +1 -0
  32. package/dist/commands/rename.js +211 -0
  33. package/dist/commands/rename.js.map +1 -0
  34. package/dist/commands/taf-init.d.ts +14 -0
  35. package/dist/commands/taf-init.d.ts.map +1 -0
  36. package/dist/commands/taf-init.js +138 -0
  37. package/dist/commands/taf-init.js.map +1 -0
  38. package/dist/commands/taf-log.d.ts +27 -0
  39. package/dist/commands/taf-log.d.ts.map +1 -0
  40. package/dist/commands/taf-log.js +241 -0
  41. package/dist/commands/taf-log.js.map +1 -0
  42. package/dist/commands/taf-stats.d.ts +8 -0
  43. package/dist/commands/taf-stats.d.ts.map +1 -0
  44. package/dist/commands/taf-stats.js +133 -0
  45. package/dist/commands/taf-stats.js.map +1 -0
  46. package/dist/commands/taf-validate.d.ts +8 -0
  47. package/dist/commands/taf-validate.d.ts.map +1 -0
  48. package/dist/commands/taf-validate.js +108 -0
  49. package/dist/commands/taf-validate.js.map +1 -0
  50. package/dist/commands/taf.d.ts +13 -0
  51. package/dist/commands/taf.d.ts.map +1 -0
  52. package/dist/commands/taf.js +85 -0
  53. package/dist/commands/taf.js.map +1 -0
  54. package/dist/compiler/faf-compiler.d.ts.map +1 -1
  55. package/dist/compiler/faf-compiler.js +18 -0
  56. package/dist/compiler/faf-compiler.js.map +1 -1
  57. package/dist/generators/faf-generator-championship.d.ts.map +1 -1
  58. package/dist/generators/faf-generator-championship.js +1 -0
  59. package/dist/generators/faf-generator-championship.js.map +1 -1
  60. package/dist/github/github-extractor.d.ts +56 -0
  61. package/dist/github/github-extractor.d.ts.map +1 -0
  62. package/dist/github/github-extractor.js +328 -0
  63. package/dist/github/github-extractor.js.map +1 -0
  64. package/dist/github/popular-repos.d.ts +43 -0
  65. package/dist/github/popular-repos.d.ts.map +1 -0
  66. package/dist/github/popular-repos.js +205 -0
  67. package/dist/github/popular-repos.js.map +1 -0
  68. package/dist/github/repo-selector.d.ts +48 -0
  69. package/dist/github/repo-selector.d.ts.map +1 -0
  70. package/dist/github/repo-selector.js +277 -0
  71. package/dist/github/repo-selector.js.map +1 -0
  72. package/dist/taf/index.d.ts +17 -0
  73. package/dist/taf/index.d.ts.map +1 -0
  74. package/dist/taf/index.js +57 -0
  75. package/dist/taf/index.js.map +1 -0
  76. package/dist/taf/logger.d.ts +86 -0
  77. package/dist/taf/logger.d.ts.map +1 -0
  78. package/dist/taf/logger.js +135 -0
  79. package/dist/taf/logger.js.map +1 -0
  80. package/dist/taf/parser.d.ts +32 -0
  81. package/dist/taf/parser.d.ts.map +1 -0
  82. package/dist/taf/parser.js +161 -0
  83. package/dist/taf/parser.js.map +1 -0
  84. package/dist/taf/stats.d.ts +31 -0
  85. package/dist/taf/stats.d.ts.map +1 -0
  86. package/dist/taf/stats.js +182 -0
  87. package/dist/taf/stats.js.map +1 -0
  88. package/dist/taf/types.d.ts +66 -0
  89. package/dist/taf/types.d.ts.map +1 -0
  90. package/dist/taf/types.js +9 -0
  91. package/dist/taf/types.js.map +1 -0
  92. package/dist/taf/validator.d.ts +18 -0
  93. package/dist/taf/validator.d.ts.map +1 -0
  94. package/dist/taf/validator.js +148 -0
  95. package/dist/taf/validator.js.map +1 -0
  96. package/dist/utils/file-utils.d.ts +10 -0
  97. package/dist/utils/file-utils.d.ts.map +1 -1
  98. package/dist/utils/file-utils.js +196 -33
  99. package/dist/utils/file-utils.js.map +1 -1
  100. package/dist/utils/native-file-finder.js +1 -1
  101. package/dist/utils/native-file-finder.js.map +1 -1
  102. package/dist/utils/yaml-generator.d.ts +1 -0
  103. package/dist/utils/yaml-generator.d.ts.map +1 -1
  104. package/dist/utils/yaml-generator.js +1 -0
  105. package/dist/utils/yaml-generator.js.map +1 -1
  106. package/package.json +9 -4
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ /**
3
+ * TAF Core Library - MCP-Portable Functions
4
+ *
5
+ * This module contains ALL pure, MCP-portable functions for .taf
6
+ * Can be extracted directly to claude-faf-mcp or claude-taf-mcp
7
+ *
8
+ * Zero CLI dependencies - only uses:
9
+ * - yaml (for parsing)
10
+ * - TypeScript types
11
+ * - Pure functions
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
25
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
26
+ };
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ exports.updateFAFIntegration = exports.getRunsInRange = exports.getRecentRuns = exports.calculateRecovery = exports.detectResult = exports.createDetailedRun = exports.createMinimalRun = exports.appendTestRun = exports.getFailurePatterns = exports.getPassRateTrend = exports.calculateScoreContribution = exports.calculateStats = exports.isTAFValid = exports.validateTAF = exports.formatTAF = exports.createTAF = exports.serializeTAF = exports.parseTAF = void 0;
29
+ // Types
30
+ __exportStar(require("./types"), exports);
31
+ // Parser functions
32
+ var parser_1 = require("./parser");
33
+ Object.defineProperty(exports, "parseTAF", { enumerable: true, get: function () { return parser_1.parseTAF; } });
34
+ Object.defineProperty(exports, "serializeTAF", { enumerable: true, get: function () { return parser_1.serializeTAF; } });
35
+ Object.defineProperty(exports, "createTAF", { enumerable: true, get: function () { return parser_1.createTAF; } });
36
+ Object.defineProperty(exports, "formatTAF", { enumerable: true, get: function () { return parser_1.formatTAF; } });
37
+ // Validation functions
38
+ var validator_1 = require("./validator");
39
+ Object.defineProperty(exports, "validateTAF", { enumerable: true, get: function () { return validator_1.validateTAF; } });
40
+ Object.defineProperty(exports, "isTAFValid", { enumerable: true, get: function () { return validator_1.isTAFValid; } });
41
+ // Statistics functions
42
+ var stats_1 = require("./stats");
43
+ Object.defineProperty(exports, "calculateStats", { enumerable: true, get: function () { return stats_1.calculateStats; } });
44
+ Object.defineProperty(exports, "calculateScoreContribution", { enumerable: true, get: function () { return stats_1.calculateScoreContribution; } });
45
+ Object.defineProperty(exports, "getPassRateTrend", { enumerable: true, get: function () { return stats_1.getPassRateTrend; } });
46
+ Object.defineProperty(exports, "getFailurePatterns", { enumerable: true, get: function () { return stats_1.getFailurePatterns; } });
47
+ // Logger functions
48
+ var logger_1 = require("./logger");
49
+ Object.defineProperty(exports, "appendTestRun", { enumerable: true, get: function () { return logger_1.appendTestRun; } });
50
+ Object.defineProperty(exports, "createMinimalRun", { enumerable: true, get: function () { return logger_1.createMinimalRun; } });
51
+ Object.defineProperty(exports, "createDetailedRun", { enumerable: true, get: function () { return logger_1.createDetailedRun; } });
52
+ Object.defineProperty(exports, "detectResult", { enumerable: true, get: function () { return logger_1.detectResult; } });
53
+ Object.defineProperty(exports, "calculateRecovery", { enumerable: true, get: function () { return logger_1.calculateRecovery; } });
54
+ Object.defineProperty(exports, "getRecentRuns", { enumerable: true, get: function () { return logger_1.getRecentRuns; } });
55
+ Object.defineProperty(exports, "getRunsInRange", { enumerable: true, get: function () { return logger_1.getRunsInRange; } });
56
+ Object.defineProperty(exports, "updateFAFIntegration", { enumerable: true, get: function () { return logger_1.updateFAFIntegration; } });
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/taf/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;;;;;;;;;;;;;;;AAEH,QAAQ;AACR,0CAAwB;AAExB,mBAAmB;AACnB,mCAKkB;AAJhB,kGAAA,QAAQ,OAAA;AACR,sGAAA,YAAY,OAAA;AACZ,mGAAA,SAAS,OAAA;AACT,mGAAA,SAAS,OAAA;AAGX,uBAAuB;AACvB,yCAGqB;AAFnB,wGAAA,WAAW,OAAA;AACX,uGAAA,UAAU,OAAA;AAGZ,uBAAuB;AACvB,iCAKiB;AAJf,uGAAA,cAAc,OAAA;AACd,mHAAA,0BAA0B,OAAA;AAC1B,yGAAA,gBAAgB,OAAA;AAChB,2GAAA,kBAAkB,OAAA;AAGpB,mBAAmB;AACnB,mCASkB;AARhB,uGAAA,aAAa,OAAA;AACb,0GAAA,gBAAgB,OAAA;AAChB,2GAAA,iBAAiB,OAAA;AACjB,sGAAA,YAAY,OAAA;AACZ,2GAAA,iBAAiB,OAAA;AACjB,uGAAA,aAAa,OAAA;AACb,wGAAA,cAAc,OAAA;AACd,8GAAA,oBAAoB,OAAA"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * TAF Logger - MCP-portable test run logging
3
+ *
4
+ * Pure functions for appending test runs
5
+ * Ready for MCP extraction
6
+ */
7
+ import { TAFFile, TestRun, TestResult } from './types';
8
+ /**
9
+ * Append a test run to TAF history
10
+ * MCP-portable: pure function (immutable)
11
+ */
12
+ export declare function appendTestRun(taf: TAFFile, run: TestRun): TAFFile;
13
+ /**
14
+ * Create a minimal test run entry (Phase 1 Minimal Mode)
15
+ * MCP-portable: pure function
16
+ */
17
+ export declare function createMinimalRun(options: {
18
+ result: TestResult;
19
+ total: number;
20
+ passed: number;
21
+ failed: number;
22
+ skipped?: number;
23
+ }): TestRun;
24
+ /**
25
+ * Create a detailed test run entry (Phase 1 Detailed Mode)
26
+ * MCP-portable: pure function
27
+ */
28
+ export declare function createDetailedRun(options: {
29
+ run_id?: string;
30
+ command?: string;
31
+ trigger?: string;
32
+ result: TestResult;
33
+ suites?: {
34
+ total: number;
35
+ passed: number;
36
+ failed: number;
37
+ };
38
+ tests: {
39
+ total: number;
40
+ passed: number;
41
+ failed: number;
42
+ skipped?: number;
43
+ };
44
+ duration_ms?: number;
45
+ exit_code?: number;
46
+ issues?: string[];
47
+ root_cause?: string;
48
+ resolution?: string;
49
+ changes_since_last?: string[];
50
+ }): TestRun;
51
+ /**
52
+ * Detect test result from test counts
53
+ * MCP-portable: pure function
54
+ */
55
+ export declare function detectResult(current: {
56
+ passed: number;
57
+ total: number;
58
+ }, previous?: {
59
+ passed: number;
60
+ total: number;
61
+ }): TestResult;
62
+ /**
63
+ * Calculate recovery info from previous run
64
+ * MCP-portable: pure function
65
+ */
66
+ export declare function calculateRecovery(currentRun: TestRun, previousRun?: TestRun): TestRun;
67
+ /**
68
+ * Get last N test runs
69
+ * MCP-portable: pure function
70
+ */
71
+ export declare function getRecentRuns(taf: TAFFile, count: number): TestRun[];
72
+ /**
73
+ * Get test runs within time range
74
+ * MCP-portable: pure function
75
+ */
76
+ export declare function getRunsInRange(taf: TAFFile, startDate: Date, endDate: Date): TestRun[];
77
+ /**
78
+ * Update FAF integration fields
79
+ * MCP-portable: pure function
80
+ */
81
+ export declare function updateFAFIntegration(taf: TAFFile, options: {
82
+ faf_associated: boolean;
83
+ faf_location?: string;
84
+ faf_score?: number;
85
+ }): TAFFile;
86
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/taf/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEvD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAMjE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IACxC,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAWV;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,GAAG,OAAO,CAgBV;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAC1C,QAAQ,CAAC,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3C,UAAU,CAkBZ;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,OAAO,EACnB,WAAW,CAAC,EAAE,OAAO,GACpB,OAAO,CAkBT;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,CAEpE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,IAAI,EACf,OAAO,EAAE,IAAI,GACZ,OAAO,EAAE,CAKX;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE;IACP,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACA,OAAO,CAQT"}
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ /**
3
+ * TAF Logger - MCP-portable test run logging
4
+ *
5
+ * Pure functions for appending test runs
6
+ * Ready for MCP extraction
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.appendTestRun = appendTestRun;
10
+ exports.createMinimalRun = createMinimalRun;
11
+ exports.createDetailedRun = createDetailedRun;
12
+ exports.detectResult = detectResult;
13
+ exports.calculateRecovery = calculateRecovery;
14
+ exports.getRecentRuns = getRecentRuns;
15
+ exports.getRunsInRange = getRunsInRange;
16
+ exports.updateFAFIntegration = updateFAFIntegration;
17
+ /**
18
+ * Append a test run to TAF history
19
+ * MCP-portable: pure function (immutable)
20
+ */
21
+ function appendTestRun(taf, run) {
22
+ return {
23
+ ...taf,
24
+ last_updated: new Date().toISOString(),
25
+ test_history: [...taf.test_history, run],
26
+ };
27
+ }
28
+ /**
29
+ * Create a minimal test run entry (Phase 1 Minimal Mode)
30
+ * MCP-portable: pure function
31
+ */
32
+ function createMinimalRun(options) {
33
+ return {
34
+ timestamp: new Date().toISOString(),
35
+ result: options.result,
36
+ tests: {
37
+ total: options.total,
38
+ passed: options.passed,
39
+ failed: options.failed,
40
+ skipped: options.skipped,
41
+ },
42
+ };
43
+ }
44
+ /**
45
+ * Create a detailed test run entry (Phase 1 Detailed Mode)
46
+ * MCP-portable: pure function
47
+ */
48
+ function createDetailedRun(options) {
49
+ return {
50
+ timestamp: new Date().toISOString(),
51
+ run_id: options.run_id,
52
+ command: options.command,
53
+ trigger: options.trigger,
54
+ result: options.result,
55
+ suites: options.suites,
56
+ tests: options.tests,
57
+ duration_ms: options.duration_ms,
58
+ exit_code: options.exit_code,
59
+ issues: options.issues,
60
+ root_cause: options.root_cause,
61
+ resolution: options.resolution,
62
+ changes_since_last: options.changes_since_last,
63
+ };
64
+ }
65
+ /**
66
+ * Detect test result from test counts
67
+ * MCP-portable: pure function
68
+ */
69
+ function detectResult(current, previous) {
70
+ if (current.passed === current.total) {
71
+ return 'PASSED';
72
+ }
73
+ if (!previous) {
74
+ return current.passed > 0 ? 'FAILED' : 'FAILED';
75
+ }
76
+ if (current.passed > previous.passed) {
77
+ return 'IMPROVED';
78
+ }
79
+ if (current.passed < previous.passed) {
80
+ return 'DEGRADED';
81
+ }
82
+ return 'FAILED';
83
+ }
84
+ /**
85
+ * Calculate recovery info from previous run
86
+ * MCP-portable: pure function
87
+ */
88
+ function calculateRecovery(currentRun, previousRun) {
89
+ if (!previousRun || previousRun.result === 'PASSED') {
90
+ return currentRun;
91
+ }
92
+ // Calculate time to fix
93
+ const currentTime = new Date(currentRun.timestamp).getTime();
94
+ const previousTime = new Date(previousRun.timestamp).getTime();
95
+ const time_to_fix_minutes = Math.round((currentTime - previousTime) / 1000 / 60);
96
+ return {
97
+ ...currentRun,
98
+ recovery: {
99
+ previous_result: previousRun.result,
100
+ time_to_fix_minutes,
101
+ fix_summary: currentRun.resolution,
102
+ },
103
+ };
104
+ }
105
+ /**
106
+ * Get last N test runs
107
+ * MCP-portable: pure function
108
+ */
109
+ function getRecentRuns(taf, count) {
110
+ return taf.test_history.slice(-count);
111
+ }
112
+ /**
113
+ * Get test runs within time range
114
+ * MCP-portable: pure function
115
+ */
116
+ function getRunsInRange(taf, startDate, endDate) {
117
+ return taf.test_history.filter(run => {
118
+ const runDate = new Date(run.timestamp);
119
+ return runDate >= startDate && runDate <= endDate;
120
+ });
121
+ }
122
+ /**
123
+ * Update FAF integration fields
124
+ * MCP-portable: pure function
125
+ */
126
+ function updateFAFIntegration(taf, options) {
127
+ return {
128
+ ...taf,
129
+ last_updated: new Date().toISOString(),
130
+ faf_associated: options.faf_associated,
131
+ faf_location: options.faf_location,
132
+ faf_score: options.faf_score,
133
+ };
134
+ }
135
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/taf/logger.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAQH,sCAMC;AAMD,4CAiBC;AAMD,8CAsCC;AAMD,oCAqBC;AAMD,8CAqBC;AAMD,sCAEC;AAMD,wCASC;AAMD,oDAeC;AA/KD;;;GAGG;AACH,SAAgB,aAAa,CAAC,GAAY,EAAE,GAAY;IACtD,OAAO;QACL,GAAG,GAAG;QACN,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACtC,YAAY,EAAE,CAAC,GAAG,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC;KACzC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,OAMhC;IACC,OAAO;QACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE;YACL,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAAC,OAsBjC;IACC,OAAO;QACL,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;KAC/C,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY,CAC1B,OAA0C,EAC1C,QAA4C;IAE5C,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC;QACrC,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IAClD,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,SAAgB,iBAAiB,CAC/B,UAAmB,EACnB,WAAqB;IAErB,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACpD,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,wBAAwB;IACxB,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;IAC7D,MAAM,YAAY,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;IAC/D,MAAM,mBAAmB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,YAAY,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC;IAEjF,OAAO;QACL,GAAG,UAAU;QACb,QAAQ,EAAE;YACR,eAAe,EAAE,WAAW,CAAC,MAAM;YACnC,mBAAmB;YACnB,WAAW,EAAE,UAAU,CAAC,UAAU;SACnC;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,aAAa,CAAC,GAAY,EAAE,KAAa;IACvD,OAAO,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAC5B,GAAY,EACZ,SAAe,EACf,OAAa;IAEb,OAAO,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE;QACnC,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACxC,OAAO,OAAO,IAAI,SAAS,IAAI,OAAO,IAAI,OAAO,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAgB,oBAAoB,CAClC,GAAY,EACZ,OAIC;IAED,OAAO;QACL,GAAG,GAAG;QACN,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACtC,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * TAF Parser - MCP-portable YAML parsing
3
+ *
4
+ * Pure functions for reading/writing .taf files
5
+ * No CLI dependencies - ready for MCP extraction
6
+ */
7
+ import { TAFFile } from './types';
8
+ /**
9
+ * Parse .taf file content from YAML string
10
+ * MCP-portable: takes string, returns object
11
+ */
12
+ export declare function parseTAF(content: string): TAFFile;
13
+ /**
14
+ * Serialize TAF object to YAML string
15
+ * MCP-portable: takes object, returns string
16
+ */
17
+ export declare function serializeTAF(taf: TAFFile): string;
18
+ /**
19
+ * Create a new TAF file structure
20
+ * MCP-portable: pure function
21
+ */
22
+ export declare function createTAF(project: string, options?: {
23
+ faf_associated?: boolean;
24
+ faf_location?: string;
25
+ faf_score?: number;
26
+ }): TAFFile;
27
+ /**
28
+ * Format TAF file with proper comments and structure
29
+ * MCP-portable: string transformation
30
+ */
31
+ export declare function formatTAF(content: string): string;
32
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/taf/parser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAyCjD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAMjD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IACnD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAeV;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA2CjD"}
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ /**
3
+ * TAF Parser - MCP-portable YAML parsing
4
+ *
5
+ * Pure functions for reading/writing .taf files
6
+ * No CLI dependencies - ready for MCP extraction
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.parseTAF = parseTAF;
43
+ exports.serializeTAF = serializeTAF;
44
+ exports.createTAF = createTAF;
45
+ exports.formatTAF = formatTAF;
46
+ const yaml = __importStar(require("yaml"));
47
+ /**
48
+ * Parse .taf file content from YAML string
49
+ * MCP-portable: takes string, returns object
50
+ */
51
+ function parseTAF(content) {
52
+ try {
53
+ // Split on document separator and take only first document
54
+ const lines = content.split('\n');
55
+ const yamlLines = [];
56
+ for (const line of lines) {
57
+ // Stop at document separator (but skip initial one if present)
58
+ if (line.trim() === '---' && yamlLines.length > 0) {
59
+ break;
60
+ }
61
+ // Skip initial document separator
62
+ if (line.trim() === '---' && yamlLines.length === 0) {
63
+ continue;
64
+ }
65
+ yamlLines.push(line);
66
+ }
67
+ const parsed = yaml.parse(yamlLines.join('\n'));
68
+ // Validate required fields
69
+ if (!parsed.format_version) {
70
+ throw new Error('Missing required field: format_version');
71
+ }
72
+ if (!parsed.project) {
73
+ throw new Error('Missing required field: project');
74
+ }
75
+ if (!parsed.created) {
76
+ throw new Error('Missing required field: created');
77
+ }
78
+ if (!parsed.test_history || !Array.isArray(parsed.test_history)) {
79
+ throw new Error('Missing or invalid field: test_history');
80
+ }
81
+ return parsed;
82
+ }
83
+ catch (error) {
84
+ if (error instanceof Error) {
85
+ throw new Error(`Failed to parse .taf file: ${error.message}`);
86
+ }
87
+ throw error;
88
+ }
89
+ }
90
+ /**
91
+ * Serialize TAF object to YAML string
92
+ * MCP-portable: takes object, returns string
93
+ */
94
+ function serializeTAF(taf) {
95
+ return yaml.stringify(taf, {
96
+ lineWidth: 0, // No line wrapping
97
+ defaultStringType: 'QUOTE_DOUBLE',
98
+ defaultKeyType: 'PLAIN',
99
+ });
100
+ }
101
+ /**
102
+ * Create a new TAF file structure
103
+ * MCP-portable: pure function
104
+ */
105
+ function createTAF(project, options) {
106
+ const now = new Date().toISOString();
107
+ return {
108
+ format_version: '1.0.0',
109
+ project,
110
+ created: now,
111
+ last_updated: now,
112
+ ...(options?.faf_associated !== undefined && {
113
+ faf_associated: options.faf_associated,
114
+ faf_location: options.faf_location || '.faf',
115
+ faf_score: options.faf_score,
116
+ }),
117
+ test_history: [],
118
+ };
119
+ }
120
+ /**
121
+ * Format TAF file with proper comments and structure
122
+ * MCP-portable: string transformation
123
+ */
124
+ function formatTAF(content) {
125
+ const lines = content.split('\n');
126
+ const formatted = [];
127
+ // Add header comment
128
+ formatted.push('# .taf - Testing Activity Feed');
129
+ // Process lines
130
+ let inTestHistory = false;
131
+ for (const line of lines) {
132
+ if (line.startsWith('format_version:')) {
133
+ formatted.push(line);
134
+ continue;
135
+ }
136
+ if (line.startsWith('project:') || line.startsWith('created:') || line.startsWith('last_updated:')) {
137
+ formatted.push(line);
138
+ continue;
139
+ }
140
+ if (line.startsWith('faf_associated:')) {
141
+ if (!formatted.some(l => l.includes('# FAF Integration'))) {
142
+ formatted.push('');
143
+ formatted.push('# FAF Integration (Optional - Native Reference)');
144
+ }
145
+ formatted.push(line);
146
+ continue;
147
+ }
148
+ if (line.startsWith('test_history:')) {
149
+ if (!inTestHistory) {
150
+ formatted.push('');
151
+ formatted.push('# Test execution history (append-only)');
152
+ inTestHistory = true;
153
+ }
154
+ formatted.push(line);
155
+ continue;
156
+ }
157
+ formatted.push(line);
158
+ }
159
+ return formatted.join('\n');
160
+ }
161
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/taf/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * TAF Stats Calculator - MCP-portable statistics
3
+ *
4
+ * Pure functions for calculating test statistics
5
+ * Ready for MCP extraction
6
+ */
7
+ import { TAFFile, TAFStats, TAFScoreContribution } from './types';
8
+ /**
9
+ * Calculate statistics from TAF file
10
+ * MCP-portable: pure function
11
+ */
12
+ export declare function calculateStats(taf: TAFFile): TAFStats;
13
+ /**
14
+ * Calculate .taf contribution to .faf AI-readiness score
15
+ * MCP-portable: pure function
16
+ */
17
+ export declare function calculateScoreContribution(taf: TAFFile): TAFScoreContribution;
18
+ /**
19
+ * Get pass rate trend (improving/declining/stable)
20
+ * MCP-portable: pure function
21
+ */
22
+ export declare function getPassRateTrend(taf: TAFFile, window?: number): string;
23
+ /**
24
+ * Get failure patterns for WJTTC analysis
25
+ * MCP-portable: pure function
26
+ */
27
+ export declare function getFailurePatterns(taf: TAFFile): {
28
+ most_common_issues: string[];
29
+ failure_rate_by_hour: Record<number, number>;
30
+ };
31
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/taf/stats.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAElE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CAsErD;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,CAyB7E;AAcD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,MAAW,GAAG,MAAM,CAiB1E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG;IAChD,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9C,CAuCA"}