tdd-enforcer 0.2.5 → 0.2.7

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.
@@ -1,39 +1,51 @@
1
- import { appendFileSync, existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
1
+ import {
2
+ appendFileSync,
3
+ existsSync,
4
+ mkdirSync,
5
+ readFileSync,
6
+ writeFileSync,
7
+ } from "node:fs";
2
8
  import { join } from "node:path";
3
9
 
4
10
  const MAX_LINES = 1000;
5
11
 
6
12
  type FsDeps = {
7
- existsSync: typeof existsSync;
8
- mkdirSync: typeof mkdirSync;
9
- appendFileSync: typeof appendFileSync;
10
- writeFileSync: typeof writeFileSync;
11
- readFileSync: typeof readFileSync;
13
+ existsSync: typeof existsSync;
14
+ mkdirSync: typeof mkdirSync;
15
+ appendFileSync: typeof appendFileSync;
16
+ writeFileSync: typeof writeFileSync;
17
+ readFileSync: typeof readFileSync;
12
18
  };
13
19
 
14
20
  export function tddLog(
15
- tddDir: string,
16
- level: "INFO" | "WARN" | "ERROR" | "DEBUG",
17
- msg: string,
18
- data?: Record<string, unknown>,
19
- deps: FsDeps = { existsSync, mkdirSync, appendFileSync, writeFileSync, readFileSync },
21
+ tddDir: string,
22
+ level: "INFO" | "WARN" | "ERROR" | "DEBUG",
23
+ msg: string,
24
+ data?: Record<string, unknown>,
25
+ deps: FsDeps = {
26
+ existsSync,
27
+ mkdirSync,
28
+ appendFileSync,
29
+ writeFileSync,
30
+ readFileSync,
31
+ },
20
32
  ): void {
21
- try {
22
- const logPath = join(tddDir, "tdd.log");
23
- const timestamp = new Date().toISOString();
24
- const dataStr = data !== undefined ? ` ${JSON.stringify(data)}` : "";
25
- const line = `[${timestamp}] [${level}] ${msg}${dataStr}\n`;
33
+ try {
34
+ const logPath = join(tddDir, "tdd.log");
35
+ const timestamp = new Date().toISOString();
36
+ const dataStr = data !== undefined ? ` ${JSON.stringify(data)}` : "";
37
+ const line = `[${timestamp}] [${level}] ${msg}${dataStr}\n`;
26
38
 
27
- deps.appendFileSync(logPath, line, "utf-8");
39
+ deps.appendFileSync(logPath, line, "utf-8");
28
40
 
29
- // Trim to last MAX_LINES
30
- const content = deps.readFileSync(logPath, "utf-8");
31
- const lines = content.trimEnd().split("\n");
32
- if (lines.length > MAX_LINES) {
33
- const trimmed = lines.slice(-MAX_LINES).join("\n") + "\n";
34
- deps.writeFileSync(logPath, trimmed, "utf-8");
35
- }
36
- } catch {
37
- // Logging never throws — fail silently
38
- }
41
+ // Trim to last MAX_LINES
42
+ const content = deps.readFileSync(logPath, "utf-8");
43
+ const lines = content.trimEnd().split("\n");
44
+ if (lines.length > MAX_LINES) {
45
+ const trimmed = `${lines.slice(-MAX_LINES).join("\n")}\n`;
46
+ deps.writeFileSync(logPath, trimmed, "utf-8");
47
+ }
48
+ } catch {
49
+ // Logging never throws — fail silently
50
+ }
39
51
  }
@@ -1,35 +1,35 @@
1
- import { describe, it, expect } from "vitest";
2
- import { getNudgePrompt } from "./prompts.js";
1
+ import { describe, expect, it } from "vitest";
3
2
  import type { Config } from "../../engine/types.js";
3
+ import { getNudgePrompt } from "./prompts.js";
4
4
 
5
5
  const config: Config = {
6
- blockedInRed: ["tests/**/*.test.ts"],
7
- blockedInGreen: ["src/**/*.ts"],
8
- testCommands: ["npm test"],
9
- timeoutSeconds: 30,
6
+ blockedInRed: ["tests/**/*.test.ts"],
7
+ blockedInGreen: ["src/**/*.ts"],
8
+ testCommands: ["npm test"],
9
+ timeoutSeconds: 30,
10
10
  };
11
11
 
12
12
  describe("getNudgePrompt", () => {
13
- it("returns RED prompt with blocked files", () => {
14
- const result = getNudgePrompt("red", config);
15
- expect(result).toContain("RED");
16
- expect(result).toContain("Blocked files: tests/**/*.test.ts");
17
- });
13
+ it("returns RED prompt with blocked files", () => {
14
+ const result = getNudgePrompt("red", config);
15
+ expect(result).toContain("RED");
16
+ expect(result).toContain("Blocked files: tests/**/*.test.ts");
17
+ });
18
18
 
19
- it("returns GREEN prompt with blocked files", () => {
20
- const result = getNudgePrompt("green", config);
21
- expect(result).toContain("GREEN");
22
- expect(result).toContain("Blocked files: src/**/*.ts");
23
- });
19
+ it("returns GREEN prompt with blocked files", () => {
20
+ const result = getNudgePrompt("green", config);
21
+ expect(result).toContain("GREEN");
22
+ expect(result).toContain("Blocked files: src/**/*.ts");
23
+ });
24
24
 
25
- it("returns REFACTOR prompt", () => {
26
- const result = getNudgePrompt("refactor", config);
27
- expect(result).toContain("REFACTOR");
28
- expect(result).toContain("free to modify");
29
- });
25
+ it("returns REFACTOR prompt", () => {
26
+ const result = getNudgePrompt("refactor", config);
27
+ expect(result).toContain("REFACTOR");
28
+ expect(result).toContain("free to modify");
29
+ });
30
30
 
31
- it("returns empty string for unknown phase", () => {
32
- const result = getNudgePrompt("blurple" as any, config);
33
- expect(result).toBe("");
34
- });
31
+ it("returns empty string for unknown phase", () => {
32
+ const result = getNudgePrompt("blurple" as any, config);
33
+ expect(result).toBe("");
34
+ });
35
35
  });
@@ -1,34 +1,32 @@
1
- import type { Phase, Config } from "../../engine/types.js";
1
+ import type { Config, Phase } from "../../engine/types.js";
2
2
 
3
3
  export function getNudgePrompt(phase: Phase, config: Config): string {
4
- const redBlock = config.blockedInRed.join(", ");
5
- const greenBlock = config.blockedInGreen.join(", ");
4
+ const redBlock = config.blockedInRed.join(", ");
5
+ const greenBlock = config.blockedInGreen.join(", ");
6
6
 
7
- switch (phase) {
8
- case "red":
9
- return (
10
- `You are now in **RED** phase. Write failing tests.\n` +
11
- `Blocked files: ${redBlock}\n` +
12
- "All other files are free to modify. Call `next_tdd_phase` to proceed to GREEN.\n" +
13
- "Think about what could go wrong and test for it — don't just verify the happy path, " +
14
- "cover unhappy paths and edge cases too. Keep cycles small so reverting is cheap."
15
- );
16
- case "green":
17
- return (
18
- `You are now in **GREEN** phase. Implement features.\n` +
19
- `Blocked files: ${greenBlock}\n` +
20
- "All other files are free to modify. Call `next_tdd_phase` to proceed to REFACTOR.\n" +
21
- "Write minimal code to make the failing tests pass — nothing more.\n" +
22
- "If the RED phase tests were wrong, call `previous_tdd_phase` to go back and fix them."
23
- );
24
- case "refactor":
25
- return (
26
- "You are now in **REFACTOR** phase. Both test and implementation files are free to modify. " +
27
- "Refactor without changing behavior. Call `next_tdd_phase` to start a new RED cycle."
28
- );
29
- default:
30
- return "";
31
- }
7
+ switch (phase) {
8
+ case "red":
9
+ return (
10
+ `You are now in **RED** phase. Write failing tests.\n` +
11
+ `Blocked files: ${redBlock}\n` +
12
+ "All other files are free to modify. Call `next_tdd_phase` to proceed to GREEN.\n" +
13
+ "Think about what could go wrong and test for it — don't just verify the happy path, " +
14
+ "cover unhappy paths and edge cases too. Keep cycles small so reverting is cheap."
15
+ );
16
+ case "green":
17
+ return (
18
+ `You are now in **GREEN** phase. Implement features.\n` +
19
+ `Blocked files: ${greenBlock}\n` +
20
+ "All other files are free to modify. Call `next_tdd_phase` to proceed to REFACTOR.\n" +
21
+ "Write minimal code to make the failing tests pass — nothing more.\n" +
22
+ "If the RED phase tests were wrong, call `previous_tdd_phase` to go back and fix them."
23
+ );
24
+ case "refactor":
25
+ return (
26
+ "You are now in **REFACTOR** phase. Both test and implementation files are free to modify. " +
27
+ "Refactor without changing behavior. Call `next_tdd_phase` to start a new RED cycle."
28
+ );
29
+ default:
30
+ return "";
31
+ }
32
32
  }
33
-
34
-