ralph-mcp 1.0.3 → 1.0.6

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,5 +1,8 @@
1
1
  import { z } from "zod";
2
2
  import notifier from "node-notifier";
3
+ import { appendFile, mkdir } from "fs/promises";
4
+ import { existsSync } from "fs";
5
+ import { join, dirname } from "path";
3
6
  import { findExecutionByBranch, findMergeQueueItemByExecutionId, findUserStoryById, insertMergeQueueItem, listMergeQueue, listUserStoriesByExecutionId, updateExecution, updateUserStory, } from "../store/state.js";
4
7
  import { mergeQueueAction } from "./merge.js";
5
8
  export const updateInputSchema = z.object({
@@ -8,6 +11,15 @@ export const updateInputSchema = z.object({
8
11
  passes: z.boolean().describe("Whether the story passes"),
9
12
  notes: z.string().optional().describe("Implementation notes"),
10
13
  });
14
+ function formatDate(date) {
15
+ const pad = (n) => n.toString().padStart(2, '0');
16
+ const yyyy = date.getFullYear();
17
+ const MM = pad(date.getMonth() + 1);
18
+ const dd = pad(date.getDate());
19
+ const HH = pad(date.getHours());
20
+ const mm = pad(date.getMinutes());
21
+ return `${yyyy}-${MM}-${dd} ${HH}:${mm}`;
22
+ }
11
23
  export async function update(input) {
12
24
  // Find execution by branch
13
25
  const exec = await findExecutionByBranch(input.branch);
@@ -25,6 +37,24 @@ export async function update(input) {
25
37
  passes: input.passes,
26
38
  notes: input.notes || story.notes,
27
39
  });
40
+ // Append to ralph-progress.md if passed
41
+ if (input.passes && exec.worktreePath) {
42
+ try {
43
+ const progressPath = join(exec.worktreePath, "ralph-progress.md");
44
+ const dir = dirname(progressPath);
45
+ if (!existsSync(dir)) {
46
+ await mkdir(dir, { recursive: true });
47
+ }
48
+ const timestamp = formatDate(new Date());
49
+ const notesContent = input.notes || story.notes || "No notes provided.";
50
+ const entry = `## [${timestamp}] ${story.storyId}: ${story.title}\n${notesContent}\n\n`;
51
+ await appendFile(progressPath, entry, "utf-8");
52
+ }
53
+ catch (e) {
54
+ console.error("Failed to write to ralph-progress.md:", e);
55
+ // Continue execution even if logging fails
56
+ }
57
+ }
28
58
  // Update execution timestamp and status
29
59
  const allStories = await listUserStoriesByExecutionId(exec.id);
30
60
  // Check if this update completes all stories
@@ -14,41 +14,55 @@ export function generateAgentPrompt(branch, description, worktreePath, stories)
14
14
  return "All user stories are complete. No action needed.";
15
15
  }
16
16
  const storiesText = pendingStories
17
- .map((s) => `
18
- ### ${s.storyId}: ${s.title}
19
- ${s.description}
20
-
21
- **Acceptance Criteria:**
22
- ${s.acceptanceCriteria.map((ac) => `- ${ac}`).join("\n")}
17
+ .map((s) => `
18
+ ### ${s.storyId}: ${s.title}
19
+ ${s.description}
20
+
21
+ **Acceptance Criteria:**
22
+ ${s.acceptanceCriteria.map((ac) => `- ${ac}`).join("\n")}
23
23
  `)
24
24
  .join("\n");
25
- return `You are an autonomous coding agent working on the "${branch}" branch.
26
-
27
- ## Working Directory
28
- ${worktreePath}
29
-
30
- ## PRD: ${description}
31
-
32
- ## Pending User Stories
33
- ${storiesText}
34
-
35
- ## Instructions
36
-
37
- 1. Work on ONE user story at a time, starting with the highest priority
38
- 2. Implement the feature to satisfy all acceptance criteria
39
- 3. Run quality checks: \`pnpm check-types\` and \`pnpm --filter api build\`
40
- 4. Commit changes with message: \`feat: [${pendingStories[0].storyId}] - ${pendingStories[0].title}\`
41
- 5. After completing a story, call \`ralph_update\` to mark it as passed:
42
- \`ralph_update({ branch: "${branch}", storyId: "${pendingStories[0].storyId}", passes: true, notes: "..." })\`
43
- 6. Continue to the next story until all are complete
44
-
45
- ## Quality Requirements
46
- - ALL commits must pass typecheck and build
47
- - Keep changes focused and minimal
48
- - Follow existing code patterns
49
-
50
- ## Stop Condition
51
- When all stories are complete, report completion.
25
+ // Read progress log if it exists
26
+ let progressLog = "";
27
+ const progressPath = join(worktreePath, "ralph-progress.md");
28
+ if (existsSync(progressPath)) {
29
+ try {
30
+ progressLog = readFileSync(progressPath, "utf-8");
31
+ }
32
+ catch (e) {
33
+ // Ignore read errors
34
+ }
35
+ }
36
+ return `You are an autonomous coding agent working on the "${branch}" branch.
37
+
38
+ ## Working Directory
39
+ ${worktreePath}
40
+
41
+ ## PRD: ${description}
42
+
43
+ ${progressLog ? `## Progress & Learnings\n${progressLog}\n` : ""}
44
+
45
+ ## Pending User Stories
46
+ ${storiesText}
47
+
48
+ ## Instructions
49
+
50
+ 1. Work on ONE user story at a time, starting with the highest priority.
51
+ 2. ${progressLog ? "Review the 'Progress & Learnings' section above to understand previous decisions and context." : "Check if 'ralph-progress.md' exists and review it for context."}
52
+ 3. Implement the feature to satisfy all acceptance criteria.
53
+ 4. Run quality checks: \`pnpm check-types\` and \`pnpm --filter api build\` (adjust command for the specific repo structure if needed).
54
+ 5. Commit changes with message: \`feat: [${pendingStories[0].storyId}] - ${pendingStories[0].title}\`
55
+ 6. After completing a story, call \`ralph_update\` to mark it as passed:
56
+ \`ralph_update({ branch: "${branch}", storyId: "${pendingStories[0].storyId}", passes: true, notes: "Brief summary of implementation, key decisions, and any learnings." })\`
57
+ 7. Continue to the next story until all are complete.
58
+
59
+ ## Quality Requirements
60
+ - ALL commits must pass typecheck and build
61
+ - Keep changes focused and minimal
62
+ - Follow existing code patterns
63
+
64
+ ## Stop Condition
65
+ When all stories are complete, report completion.
52
66
  `;
53
67
  }
54
68
  /**
@@ -66,31 +80,31 @@ export function generateMergeAgentPrompt(projectRoot, branch, description, confl
66
80
  if (prdPath && existsSync(prdPath)) {
67
81
  prdContent = readFileSync(prdPath, "utf-8");
68
82
  }
69
- return `You are a Git merge expert. Please resolve the following merge conflicts.
70
-
71
- ## Project Architecture
72
- ${architectureContext || "No CLAUDE.md found. Use your best judgment based on the code."}
73
-
74
- ## PRD Context
75
- ${prdContent || `Branch: ${branch}\nDescription: ${description}`}
76
-
77
- ## Conflict Files
78
- ${conflictFiles.map((f) => `- ${f}`).join("\n")}
79
-
80
- ## Tasks
81
-
82
- 1. Read each conflict file to understand both sides of the conflict
83
- 2. Analyze the intent of changes from both branches based on the PRD
84
- 3. Resolve conflicts by keeping valuable changes from both sides
85
- 4. Ensure the PRD requirements are satisfied
86
- 5. Run \`git add <file>\` for each resolved file
87
- 6. Run \`git commit -m "resolve: merge conflicts for ${branch}"\`
88
-
89
- ## Guidelines
90
- - Prefer keeping both changes when they don't conflict logically
91
- - If changes conflict logically, prefer the feature branch changes (they implement the PRD)
92
- - Ensure the code compiles after resolution
93
- - Run \`pnpm check-types\` to verify
83
+ return `You are a Git merge expert. Please resolve the following merge conflicts.
84
+
85
+ ## Project Architecture
86
+ ${architectureContext || "No CLAUDE.md found. Use your best judgment based on the code."}
87
+
88
+ ## PRD Context
89
+ ${prdContent || `Branch: ${branch}\nDescription: ${description}`}
90
+
91
+ ## Conflict Files
92
+ ${conflictFiles.map((f) => `- ${f}`).join("\n")}
93
+
94
+ ## Tasks
95
+
96
+ 1. Read each conflict file to understand both sides of the conflict
97
+ 2. Analyze the intent of changes from both branches based on the PRD
98
+ 3. Resolve conflicts by keeping valuable changes from both sides
99
+ 4. Ensure the PRD requirements are satisfied
100
+ 5. Run \`git add <file>\` for each resolved file
101
+ 6. Run \`git commit -m "resolve: merge conflicts for ${branch}"\`
102
+
103
+ ## Guidelines
104
+ - Prefer keeping both changes when they don't conflict logically
105
+ - If changes conflict logically, prefer the feature branch changes (they implement the PRD)
106
+ - Ensure the code compiles after resolution
107
+ - Run \`pnpm check-types\` to verify
94
108
  `;
95
109
  }
96
110
  /**
@@ -1,5 +1,5 @@
1
1
  import { execSync, exec } from "child_process";
2
- import { existsSync } from "fs";
2
+ import { existsSync, appendFileSync } from "fs";
3
3
  import { join } from "path";
4
4
  import { promisify } from "util";
5
5
  const execAsync = promisify(exec);
@@ -25,6 +25,17 @@ export async function createWorktree(projectRoot, branch) {
25
25
  // Create new branch from main
26
26
  await execAsync(`git worktree add -b "${branch}" "${worktreePath}" main`, { cwd: projectRoot });
27
27
  }
28
+ // Prevent ralph-progress.md from being committed
29
+ try {
30
+ const excludePath = join(worktreePath, ".git", "info", "exclude");
31
+ if (existsSync(excludePath)) {
32
+ appendFileSync(excludePath, "\nralph-progress.md\n", "utf-8");
33
+ }
34
+ }
35
+ catch (e) {
36
+ console.error("Failed to update .git/info/exclude:", e);
37
+ // Non-fatal error
38
+ }
28
39
  return worktreePath;
29
40
  }
30
41
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ralph-mcp",
3
- "version": "1.0.3",
3
+ "version": "1.0.6",
4
4
  "description": "MCP server for autonomous PRD execution with Claude Code. Git worktree isolation, progress tracking, auto-merge.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",