@schilling.mark.a/atdd-guardian 1.0.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.
- package/CHANGELOG.md +37 -0
- package/CONTRIBUTING.md +154 -0
- package/DISTRIBUTION.md +366 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +194 -0
- package/README.md +406 -0
- package/SHARING.md +223 -0
- package/dist/constants.d.ts +19 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +38 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/tool-schemas.d.ts +404 -0
- package/dist/schemas/tool-schemas.d.ts.map +1 -0
- package/dist/schemas/tool-schemas.js +267 -0
- package/dist/schemas/tool-schemas.js.map +1 -0
- package/dist/services/context-review.d.ts +65 -0
- package/dist/services/context-review.d.ts.map +1 -0
- package/dist/services/context-review.js +300 -0
- package/dist/services/context-review.js.map +1 -0
- package/dist/services/formatter.d.ts +10 -0
- package/dist/services/formatter.d.ts.map +1 -0
- package/dist/services/formatter.js +173 -0
- package/dist/services/formatter.js.map +1 -0
- package/dist/services/phase-gate.d.ts +38 -0
- package/dist/services/phase-gate.d.ts.map +1 -0
- package/dist/services/phase-gate.js +309 -0
- package/dist/services/phase-gate.js.map +1 -0
- package/dist/services/review-engine.d.ts +26 -0
- package/dist/services/review-engine.d.ts.map +1 -0
- package/dist/services/review-engine.js +235 -0
- package/dist/services/review-engine.js.map +1 -0
- package/dist/services/rule-loader.d.ts +19 -0
- package/dist/services/rule-loader.d.ts.map +1 -0
- package/dist/services/rule-loader.js +91 -0
- package/dist/services/rule-loader.js.map +1 -0
- package/dist/services/session-manager.d.ts +75 -0
- package/dist/services/session-manager.d.ts.map +1 -0
- package/dist/services/session-manager.js +244 -0
- package/dist/services/session-manager.js.map +1 -0
- package/dist/services/test-runner.d.ts +53 -0
- package/dist/services/test-runner.d.ts.map +1 -0
- package/dist/services/test-runner.js +199 -0
- package/dist/services/test-runner.js.map +1 -0
- package/dist/tools/review-tools.d.ts +26 -0
- package/dist/tools/review-tools.d.ts.map +1 -0
- package/dist/tools/review-tools.js +904 -0
- package/dist/tools/review-tools.js.map +1 -0
- package/dist/types.d.ts +339 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/types.js.map +1 -0
- package/examples/README.md +119 -0
- package/examples/mcp-config.json +11 -0
- package/examples/test-config.json +7 -0
- package/package.json +48 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule Loader Service
|
|
3
|
+
*
|
|
4
|
+
* Loads review rules from JSON config files.
|
|
5
|
+
* Supports loading from a default bundled ruleset
|
|
6
|
+
* or from a team's custom rules file.
|
|
7
|
+
*/
|
|
8
|
+
import { readFile } from "node:fs/promises";
|
|
9
|
+
import { join, dirname } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = dirname(__filename);
|
|
13
|
+
/** Path to the bundled default rules */
|
|
14
|
+
const DEFAULT_RULES_PATH = join(__dirname, "..", "rules", "team-standards.json");
|
|
15
|
+
/**
|
|
16
|
+
* Load rules from a JSON file path.
|
|
17
|
+
* Falls back to bundled defaults if no path provided.
|
|
18
|
+
*/
|
|
19
|
+
export async function loadRuleSet(customPath) {
|
|
20
|
+
const rulesPath = customPath ?? DEFAULT_RULES_PATH;
|
|
21
|
+
try {
|
|
22
|
+
const raw = await readFile(rulesPath, "utf-8");
|
|
23
|
+
const parsed = JSON.parse(raw);
|
|
24
|
+
// Basic validation
|
|
25
|
+
if (!parsed.rules || !Array.isArray(parsed.rules)) {
|
|
26
|
+
throw new Error("Rules file must contain a 'rules' array");
|
|
27
|
+
}
|
|
28
|
+
for (const rule of parsed.rules) {
|
|
29
|
+
validateRule(rule);
|
|
30
|
+
}
|
|
31
|
+
return parsed;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error instanceof Error &&
|
|
35
|
+
"code" in error &&
|
|
36
|
+
error.code === "ENOENT") {
|
|
37
|
+
throw new Error(`Rules file not found: ${rulesPath}. ` +
|
|
38
|
+
`Create a team-standards.json in your project root or specify a path.`);
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Merge multiple rule sets (e.g., base + team overrides).
|
|
45
|
+
* Later rules with the same ID override earlier ones.
|
|
46
|
+
*/
|
|
47
|
+
export function mergeRuleSets(...sets) {
|
|
48
|
+
const ruleMap = new Map();
|
|
49
|
+
for (const set of sets) {
|
|
50
|
+
for (const rule of set.rules) {
|
|
51
|
+
ruleMap.set(rule.id, rule);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
name: sets.map((s) => s.name).join(" + "),
|
|
56
|
+
version: sets[sets.length - 1].version,
|
|
57
|
+
description: "Merged rule set",
|
|
58
|
+
rules: Array.from(ruleMap.values()),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Validate a single rule has required fields.
|
|
63
|
+
*/
|
|
64
|
+
function validateRule(rule) {
|
|
65
|
+
const r = rule;
|
|
66
|
+
const required = [
|
|
67
|
+
"id",
|
|
68
|
+
"name",
|
|
69
|
+
"category",
|
|
70
|
+
"severity",
|
|
71
|
+
"description",
|
|
72
|
+
"matchIsViolation",
|
|
73
|
+
"appliesTo",
|
|
74
|
+
"suggestion",
|
|
75
|
+
];
|
|
76
|
+
for (const field of required) {
|
|
77
|
+
if (r[field] === undefined) {
|
|
78
|
+
throw new Error(`Rule ${r["id"] ?? "unknown"} is missing required field: ${field}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Validate regex compiles if present
|
|
82
|
+
if (typeof r["pattern"] === "string") {
|
|
83
|
+
try {
|
|
84
|
+
new RegExp(r["pattern"]);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
throw new Error(`Rule ${r["id"]} has invalid regex pattern: ${r["pattern"]}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=rule-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-loader.js","sourceRoot":"","sources":["../../src/services/rule-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager Service
|
|
3
|
+
*
|
|
4
|
+
* Persists the active feature context and workflow state
|
|
5
|
+
* to .atdd-guardian/session.json in the project root.
|
|
6
|
+
*
|
|
7
|
+
* This is what makes the reviewer context-aware:
|
|
8
|
+
* it knows WHAT story you're working on, WHERE you are
|
|
9
|
+
* in the ATDD workflow, and WHAT the team decided
|
|
10
|
+
* architecturally — across multiple tool calls.
|
|
11
|
+
*/
|
|
12
|
+
import type { SessionState, FeatureContext, ReviewHistoryEntry, PdcaEntry, AtddPhase, TestRunResult, TddViolationEntry } from "../types.js";
|
|
13
|
+
/**
|
|
14
|
+
* Load the current session state, or create a blank one.
|
|
15
|
+
*/
|
|
16
|
+
export declare function loadSession(projectRoot: string): Promise<SessionState>;
|
|
17
|
+
/**
|
|
18
|
+
* Save session state to disk.
|
|
19
|
+
*/
|
|
20
|
+
export declare function saveSession(projectRoot: string, session: SessionState): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Start working on a new feature/story.
|
|
23
|
+
* Sets the active context and resets review history.
|
|
24
|
+
*/
|
|
25
|
+
export declare function startFeature(projectRoot: string, feature: FeatureContext): Promise<SessionState>;
|
|
26
|
+
/**
|
|
27
|
+
* Update the current ATDD phase.
|
|
28
|
+
*/
|
|
29
|
+
export declare function advancePhase(projectRoot: string, phase: AtddPhase): Promise<SessionState>;
|
|
30
|
+
/**
|
|
31
|
+
* Record a review result in the session history.
|
|
32
|
+
*/
|
|
33
|
+
export declare function recordReview(projectRoot: string, entry: ReviewHistoryEntry): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Add a PDCA log entry.
|
|
36
|
+
*/
|
|
37
|
+
export declare function addPdcaEntry(projectRoot: string, entry: PdcaEntry): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Update acceptance criterion test status.
|
|
40
|
+
*/
|
|
41
|
+
export declare function updateCriterionStatus(projectRoot: string, criterionId: string, testStatus: "no-test" | "red" | "green" | "skipped", testFile?: string): Promise<SessionState>;
|
|
42
|
+
/**
|
|
43
|
+
* Update expected file status.
|
|
44
|
+
*/
|
|
45
|
+
export declare function updateFileStatus(projectRoot: string, filePath: string, status: "planned" | "created" | "modified" | "reviewed"): Promise<SessionState>;
|
|
46
|
+
/**
|
|
47
|
+
* Mark a DoD item as complete.
|
|
48
|
+
*/
|
|
49
|
+
export declare function completeDodItem(projectRoot: string, dodId: string): Promise<SessionState>;
|
|
50
|
+
/**
|
|
51
|
+
* Record a new unit TDD cycle starting in RED state.
|
|
52
|
+
* Enforces PC-1: unit test must exist before production code.
|
|
53
|
+
*/
|
|
54
|
+
export declare function startUnitCycle(projectRoot: string, criterionId: string, cycle: {
|
|
55
|
+
unitDescription: string;
|
|
56
|
+
testFile: string;
|
|
57
|
+
sourceFile: string;
|
|
58
|
+
}): Promise<{
|
|
59
|
+
session: SessionState;
|
|
60
|
+
cycleNumber: number;
|
|
61
|
+
}>;
|
|
62
|
+
/**
|
|
63
|
+
* Advance a unit cycle's state: red → green → refactored.
|
|
64
|
+
* Enforces strict sequence.
|
|
65
|
+
*/
|
|
66
|
+
export declare function advanceUnitCycle(projectRoot: string, criterionId: string, cycleNumber: number, targetState: "green" | "refactored" | "abandoned", notes?: string): Promise<SessionState>;
|
|
67
|
+
/**
|
|
68
|
+
* Record a test execution result in the session.
|
|
69
|
+
*/
|
|
70
|
+
export declare function recordTestRun(projectRoot: string, result: TestRunResult): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Log a TDD violation detected by the phase gate.
|
|
73
|
+
*/
|
|
74
|
+
export declare function logViolation(projectRoot: string, entry: TddViolationEntry): Promise<void>;
|
|
75
|
+
//# sourceMappingURL=session-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/services/session-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,SAAS,EAGT,aAAa,EACb,iBAAiB,EAClB,MAAM,aAAa,CAAC;AASrB;;GAEG;AACH,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CAOvB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,YAAY,CAAC,CAMvB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,YAAY,CAAC,CAUvB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,SAAS,GAAG,KAAK,GAAG,OAAO,GAAG,SAAS,EACnD,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,CAAC,CAmBvB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GACtD,OAAO,CAAC,YAAY,CAAC,CAuBvB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,CAgBvB;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE;IACL,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,GACA,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CA+BzD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,OAAO,GAAG,YAAY,GAAG,WAAW,EACjD,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,YAAY,CAAC,CAsDvB;AAID;;GAEG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,IAAI,CAAC,CAQf;AAID;;GAEG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,IAAI,CAAC,CAIf"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Manager Service
|
|
3
|
+
*
|
|
4
|
+
* Persists the active feature context and workflow state
|
|
5
|
+
* to .atdd-guardian/session.json in the project root.
|
|
6
|
+
*
|
|
7
|
+
* This is what makes the reviewer context-aware:
|
|
8
|
+
* it knows WHAT story you're working on, WHERE you are
|
|
9
|
+
* in the ATDD workflow, and WHAT the team decided
|
|
10
|
+
* architecturally — across multiple tool calls.
|
|
11
|
+
*/
|
|
12
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
const SESSION_DIR = ".atdd-guardian";
|
|
15
|
+
const SESSION_FILE = "session.json";
|
|
16
|
+
function sessionPath(projectRoot) {
|
|
17
|
+
return join(projectRoot, SESSION_DIR, SESSION_FILE);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Load the current session state, or create a blank one.
|
|
21
|
+
*/
|
|
22
|
+
export async function loadSession(projectRoot) {
|
|
23
|
+
try {
|
|
24
|
+
const raw = await readFile(sessionPath(projectRoot), "utf-8");
|
|
25
|
+
return JSON.parse(raw);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return createBlankSession();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Save session state to disk.
|
|
33
|
+
*/
|
|
34
|
+
export async function saveSession(projectRoot, session) {
|
|
35
|
+
const dir = join(projectRoot, SESSION_DIR);
|
|
36
|
+
await mkdir(dir, { recursive: true });
|
|
37
|
+
session.updatedAt = new Date().toISOString();
|
|
38
|
+
await writeFile(sessionPath(projectRoot), JSON.stringify(session, null, 2), "utf-8");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Start working on a new feature/story.
|
|
42
|
+
* Sets the active context and resets review history.
|
|
43
|
+
*/
|
|
44
|
+
export async function startFeature(projectRoot, feature) {
|
|
45
|
+
const session = await loadSession(projectRoot);
|
|
46
|
+
session.activeFeature = feature;
|
|
47
|
+
session.reviewHistory = [];
|
|
48
|
+
await saveSession(projectRoot, session);
|
|
49
|
+
return session;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Update the current ATDD phase.
|
|
53
|
+
*/
|
|
54
|
+
export async function advancePhase(projectRoot, phase) {
|
|
55
|
+
const session = await loadSession(projectRoot);
|
|
56
|
+
if (!session.activeFeature) {
|
|
57
|
+
throw new Error("No active feature. Use start_feature first to set the story context.");
|
|
58
|
+
}
|
|
59
|
+
session.activeFeature.currentPhase = phase;
|
|
60
|
+
await saveSession(projectRoot, session);
|
|
61
|
+
return session;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Record a review result in the session history.
|
|
65
|
+
*/
|
|
66
|
+
export async function recordReview(projectRoot, entry) {
|
|
67
|
+
const session = await loadSession(projectRoot);
|
|
68
|
+
session.reviewHistory.push(entry);
|
|
69
|
+
await saveSession(projectRoot, session);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Add a PDCA log entry.
|
|
73
|
+
*/
|
|
74
|
+
export async function addPdcaEntry(projectRoot, entry) {
|
|
75
|
+
const session = await loadSession(projectRoot);
|
|
76
|
+
session.pdcaLog.push(entry);
|
|
77
|
+
await saveSession(projectRoot, session);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Update acceptance criterion test status.
|
|
81
|
+
*/
|
|
82
|
+
export async function updateCriterionStatus(projectRoot, criterionId, testStatus, testFile) {
|
|
83
|
+
const session = await loadSession(projectRoot);
|
|
84
|
+
if (!session.activeFeature) {
|
|
85
|
+
throw new Error("No active feature.");
|
|
86
|
+
}
|
|
87
|
+
const criterion = session.activeFeature.acceptanceCriteria.find((ac) => ac.id === criterionId);
|
|
88
|
+
if (!criterion) {
|
|
89
|
+
throw new Error(`Criterion '${criterionId}' not found. Available: ${session.activeFeature.acceptanceCriteria.map((ac) => ac.id).join(", ")}`);
|
|
90
|
+
}
|
|
91
|
+
criterion.testStatus = testStatus;
|
|
92
|
+
if (testFile)
|
|
93
|
+
criterion.testFile = testFile;
|
|
94
|
+
await saveSession(projectRoot, session);
|
|
95
|
+
return session;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Update expected file status.
|
|
99
|
+
*/
|
|
100
|
+
export async function updateFileStatus(projectRoot, filePath, status) {
|
|
101
|
+
const session = await loadSession(projectRoot);
|
|
102
|
+
if (!session.activeFeature) {
|
|
103
|
+
throw new Error("No active feature.");
|
|
104
|
+
}
|
|
105
|
+
const file = session.activeFeature.expectedFiles.find((f) => f.path === filePath);
|
|
106
|
+
if (file) {
|
|
107
|
+
file.status = status;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// Auto-add unexpected files
|
|
111
|
+
session.activeFeature.expectedFiles.push({
|
|
112
|
+
path: filePath,
|
|
113
|
+
purpose: "Auto-detected during development",
|
|
114
|
+
fileType: "other",
|
|
115
|
+
status,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
await saveSession(projectRoot, session);
|
|
119
|
+
return session;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Mark a DoD item as complete.
|
|
123
|
+
*/
|
|
124
|
+
export async function completeDodItem(projectRoot, dodId) {
|
|
125
|
+
const session = await loadSession(projectRoot);
|
|
126
|
+
if (!session.activeFeature) {
|
|
127
|
+
throw new Error("No active feature.");
|
|
128
|
+
}
|
|
129
|
+
const item = session.activeFeature.definitionOfDone.find((d) => d.id === dodId);
|
|
130
|
+
if (!item) {
|
|
131
|
+
throw new Error(`DoD item '${dodId}' not found.`);
|
|
132
|
+
}
|
|
133
|
+
item.completed = true;
|
|
134
|
+
await saveSession(projectRoot, session);
|
|
135
|
+
return session;
|
|
136
|
+
}
|
|
137
|
+
// ─── Unit TDD Cycle Tracking ─────────────────────────────────────
|
|
138
|
+
/**
|
|
139
|
+
* Record a new unit TDD cycle starting in RED state.
|
|
140
|
+
* Enforces PC-1: unit test must exist before production code.
|
|
141
|
+
*/
|
|
142
|
+
export async function startUnitCycle(projectRoot, criterionId, cycle) {
|
|
143
|
+
const session = await loadSession(projectRoot);
|
|
144
|
+
if (!session.activeFeature) {
|
|
145
|
+
throw new Error("No active feature.");
|
|
146
|
+
}
|
|
147
|
+
const ac = session.activeFeature.acceptanceCriteria.find((a) => a.id === criterionId);
|
|
148
|
+
if (!ac) {
|
|
149
|
+
throw new Error(`Criterion '${criterionId}' not found. Available: ${session.activeFeature.acceptanceCriteria.map((a) => a.id).join(", ")}`);
|
|
150
|
+
}
|
|
151
|
+
const cycleNumber = ac.unitCycles.length + 1;
|
|
152
|
+
const newCycle = {
|
|
153
|
+
cycleNumber,
|
|
154
|
+
unitDescription: cycle.unitDescription,
|
|
155
|
+
testFile: cycle.testFile,
|
|
156
|
+
sourceFile: cycle.sourceFile,
|
|
157
|
+
state: "red",
|
|
158
|
+
timestamps: {
|
|
159
|
+
redAt: new Date().toISOString(),
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
ac.unitCycles.push(newCycle);
|
|
163
|
+
await saveSession(projectRoot, session);
|
|
164
|
+
return { session, cycleNumber };
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Advance a unit cycle's state: red → green → refactored.
|
|
168
|
+
* Enforces strict sequence.
|
|
169
|
+
*/
|
|
170
|
+
export async function advanceUnitCycle(projectRoot, criterionId, cycleNumber, targetState, notes) {
|
|
171
|
+
const session = await loadSession(projectRoot);
|
|
172
|
+
if (!session.activeFeature) {
|
|
173
|
+
throw new Error("No active feature.");
|
|
174
|
+
}
|
|
175
|
+
const ac = session.activeFeature.acceptanceCriteria.find((a) => a.id === criterionId);
|
|
176
|
+
if (!ac) {
|
|
177
|
+
throw new Error(`Criterion '${criterionId}' not found.`);
|
|
178
|
+
}
|
|
179
|
+
const cycle = ac.unitCycles.find((u) => u.cycleNumber === cycleNumber);
|
|
180
|
+
if (!cycle) {
|
|
181
|
+
throw new Error(`Unit cycle #${cycleNumber} not found in ${criterionId}. ` +
|
|
182
|
+
`Available: ${ac.unitCycles.map((u) => u.cycleNumber).join(", ")}`);
|
|
183
|
+
}
|
|
184
|
+
// Enforce state machine: red → green → refactored
|
|
185
|
+
const validTransitions = {
|
|
186
|
+
red: ["green", "abandoned"],
|
|
187
|
+
green: ["refactored", "abandoned"],
|
|
188
|
+
refactored: [],
|
|
189
|
+
abandoned: [],
|
|
190
|
+
};
|
|
191
|
+
const valid = validTransitions[cycle.state] ?? [];
|
|
192
|
+
if (!valid.includes(targetState)) {
|
|
193
|
+
throw new Error(`Cannot transition unit cycle from '${cycle.state}' to '${targetState}'. ` +
|
|
194
|
+
`Valid transitions: ${valid.join(", ") || "none (cycle is complete)"}.`);
|
|
195
|
+
}
|
|
196
|
+
cycle.state = targetState;
|
|
197
|
+
switch (targetState) {
|
|
198
|
+
case "green":
|
|
199
|
+
cycle.timestamps.greenAt = new Date().toISOString();
|
|
200
|
+
break;
|
|
201
|
+
case "refactored":
|
|
202
|
+
cycle.timestamps.refactoredAt = new Date().toISOString();
|
|
203
|
+
cycle.refactorNotes = notes;
|
|
204
|
+
break;
|
|
205
|
+
case "abandoned":
|
|
206
|
+
cycle.refactorNotes = notes ?? "Abandoned without reason";
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
await saveSession(projectRoot, session);
|
|
210
|
+
return session;
|
|
211
|
+
}
|
|
212
|
+
// ─── Test Run Recording ──────────────────────────────────────────
|
|
213
|
+
/**
|
|
214
|
+
* Record a test execution result in the session.
|
|
215
|
+
*/
|
|
216
|
+
export async function recordTestRun(projectRoot, result) {
|
|
217
|
+
const session = await loadSession(projectRoot);
|
|
218
|
+
session.testRunHistory.push(result);
|
|
219
|
+
// Keep last 50 runs to avoid unbounded growth
|
|
220
|
+
if (session.testRunHistory.length > 50) {
|
|
221
|
+
session.testRunHistory = session.testRunHistory.slice(-50);
|
|
222
|
+
}
|
|
223
|
+
await saveSession(projectRoot, session);
|
|
224
|
+
}
|
|
225
|
+
// ─── Violation Logging ───────────────────────────────────────────
|
|
226
|
+
/**
|
|
227
|
+
* Log a TDD violation detected by the phase gate.
|
|
228
|
+
*/
|
|
229
|
+
export async function logViolation(projectRoot, entry) {
|
|
230
|
+
const session = await loadSession(projectRoot);
|
|
231
|
+
session.violationLog.push(entry);
|
|
232
|
+
await saveSession(projectRoot, session);
|
|
233
|
+
}
|
|
234
|
+
function createBlankSession() {
|
|
235
|
+
return {
|
|
236
|
+
activeFeature: null,
|
|
237
|
+
reviewHistory: [],
|
|
238
|
+
pdcaLog: [],
|
|
239
|
+
testRunHistory: [],
|
|
240
|
+
violationLog: [],
|
|
241
|
+
updatedAt: new Date().toISOString(),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=session-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/services/session-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Runner Service
|
|
3
|
+
*
|
|
4
|
+
* Executes test commands and captures structured results.
|
|
5
|
+
* Implements TI-1 from the ATDD requirements:
|
|
6
|
+
* - Support for Playwright at acceptance level
|
|
7
|
+
* - Support for unit testing frameworks (Jest, Vitest, etc.)
|
|
8
|
+
* - Automated test execution and result capture
|
|
9
|
+
*
|
|
10
|
+
* This service runs the actual test commands and parses
|
|
11
|
+
* their output into structured TestRunResult entries
|
|
12
|
+
* that feed into the session state and phase gate checks.
|
|
13
|
+
*/
|
|
14
|
+
import type { TestRunResult, AtddPhase } from "../types.js";
|
|
15
|
+
/**
|
|
16
|
+
* Test commands loaded from a project config file or defaults.
|
|
17
|
+
* Lives in .atdd-guardian/test-config.json or is provided per-call.
|
|
18
|
+
*/
|
|
19
|
+
export interface TestConfig {
|
|
20
|
+
/** Command to run all tests */
|
|
21
|
+
allTests: string;
|
|
22
|
+
/** Command to run acceptance/e2e tests only */
|
|
23
|
+
acceptanceTests: string;
|
|
24
|
+
/** Command to run unit tests only */
|
|
25
|
+
unitTests: string;
|
|
26
|
+
/** Command to run a specific test file */
|
|
27
|
+
singleFilePattern: string;
|
|
28
|
+
/** Working directory (defaults to project root) */
|
|
29
|
+
cwd?: string;
|
|
30
|
+
/** Timeout in milliseconds */
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Load test config from the project, or return defaults.
|
|
35
|
+
*/
|
|
36
|
+
export declare function loadTestConfig(projectRoot: string): Promise<TestConfig>;
|
|
37
|
+
/**
|
|
38
|
+
* Run a test command and capture structured results.
|
|
39
|
+
*/
|
|
40
|
+
export declare function runTests(projectRoot: string, testLevel: "acceptance" | "unit" | "all", phase: AtddPhase, options?: {
|
|
41
|
+
/** Override the command to run */
|
|
42
|
+
command?: string;
|
|
43
|
+
/** Specific file to test */
|
|
44
|
+
testFile?: string;
|
|
45
|
+
/** Related AC id for traceability */
|
|
46
|
+
relatedCriterionId?: string;
|
|
47
|
+
/** Related unit cycle number */
|
|
48
|
+
relatedUnitCycle?: number;
|
|
49
|
+
/** Custom config */
|
|
50
|
+
config?: TestConfig;
|
|
51
|
+
}): Promise<TestRunResult>;
|
|
52
|
+
export declare function formatTestResult(result: TestRunResult): string;
|
|
53
|
+
//# sourceMappingURL=test-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../../src/services/test-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAY5D;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,eAAe,EAAE,MAAM,CAAC;IACxB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mDAAmD;IACnD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAUD;;GAEG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,CAAC,CASrB;AAID;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,YAAY,GAAG,MAAM,GAAG,KAAK,EACxC,KAAK,EAAE,SAAS,EAChB,OAAO,GAAE;IACP,kCAAkC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gCAAgC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CAChB,GACL,OAAO,CAAC,aAAa,CAAC,CAmGxB;AA+DD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAqB9D"}
|