ralph-mcp 1.0.9 → 1.0.10
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.
|
@@ -5,6 +5,7 @@ import { execSync } from "child_process";
|
|
|
5
5
|
import { parsePrdFile } from "../utils/prd-parser.js";
|
|
6
6
|
import { createWorktree } from "../utils/worktree.js";
|
|
7
7
|
import { generateAgentPrompt } from "../utils/agent.js";
|
|
8
|
+
import { detectPackageManager, getInstallCommand, } from "../utils/package-manager.js";
|
|
8
9
|
import { areDependenciesSatisfied, findExecutionByBranch, insertExecution, insertUserStories, } from "../store/state.js";
|
|
9
10
|
export const batchStartInputSchema = z.object({
|
|
10
11
|
prdPaths: z.array(z.string()).describe("Array of paths to PRD markdown files"),
|
|
@@ -20,7 +21,7 @@ export const batchStartInputSchema = z.object({
|
|
|
20
21
|
.string()
|
|
21
22
|
.optional()
|
|
22
23
|
.describe("Path to a file (e.g., CLAUDE.md) to inject into the agent prompt"),
|
|
23
|
-
preheat: z.boolean().default(true).describe("Run
|
|
24
|
+
preheat: z.boolean().default(true).describe("Run install command serially before starting agents (avoids store lock)"),
|
|
24
25
|
});
|
|
25
26
|
/**
|
|
26
27
|
* Topological sort to determine execution order based on dependencies.
|
|
@@ -53,23 +54,30 @@ function topologicalSort(prds) {
|
|
|
53
54
|
return result;
|
|
54
55
|
}
|
|
55
56
|
/**
|
|
56
|
-
* Run
|
|
57
|
+
* Run install command in a worktree directory.
|
|
57
58
|
*/
|
|
58
|
-
function preheatWorktree(worktreePath) {
|
|
59
|
+
function preheatWorktree(worktreePath, installCmd) {
|
|
60
|
+
const cmd = `${installCmd.command} ${installCmd.args.join(" ")}`;
|
|
59
61
|
try {
|
|
60
|
-
execSync(
|
|
62
|
+
execSync(cmd, {
|
|
61
63
|
cwd: worktreePath,
|
|
62
64
|
stdio: "pipe",
|
|
63
65
|
timeout: 300000, // 5 minutes
|
|
64
66
|
});
|
|
65
67
|
}
|
|
66
68
|
catch (error) {
|
|
67
|
-
// Try
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
// Try fallback if available
|
|
70
|
+
if (installCmd.fallbackArgs.length > 0) {
|
|
71
|
+
const fallbackCmd = `${installCmd.command} ${installCmd.fallbackArgs.join(" ")}`;
|
|
72
|
+
execSync(fallbackCmd, {
|
|
73
|
+
cwd: worktreePath,
|
|
74
|
+
stdio: "pipe",
|
|
75
|
+
timeout: 300000,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
73
81
|
}
|
|
74
82
|
}
|
|
75
83
|
export async function batchStart(input) {
|
|
@@ -78,6 +86,9 @@ export async function batchStart(input) {
|
|
|
78
86
|
const contextPath = input.contextInjectionPath
|
|
79
87
|
? resolve(projectRoot, input.contextInjectionPath)
|
|
80
88
|
: undefined;
|
|
89
|
+
// Detect package manager
|
|
90
|
+
const pm = detectPackageManager(projectRoot);
|
|
91
|
+
const installCmd = getInstallCommand(pm);
|
|
81
92
|
const skipped = [];
|
|
82
93
|
const prdInfos = [];
|
|
83
94
|
// Phase 1: Parse all PRDs and create execution records
|
|
@@ -159,13 +170,13 @@ export async function batchStart(input) {
|
|
|
159
170
|
}
|
|
160
171
|
// Phase 2: Topological sort for preheat order
|
|
161
172
|
const sortedPrds = topologicalSort(prdInfos);
|
|
162
|
-
// Phase 3: Preheat worktrees serially (avoids
|
|
173
|
+
// Phase 3: Preheat worktrees serially (avoids store lock contention)
|
|
163
174
|
let preheatCompleted = false;
|
|
164
175
|
if (input.preheat && input.worktree) {
|
|
165
176
|
for (const prd of sortedPrds) {
|
|
166
177
|
if (prd.worktreePath) {
|
|
167
178
|
try {
|
|
168
|
-
preheatWorktree(prd.worktreePath);
|
|
179
|
+
preheatWorktree(prd.worktreePath, installCmd);
|
|
169
180
|
}
|
|
170
181
|
catch (error) {
|
|
171
182
|
console.error(`Preheat failed for ${prd.branch}:`, error);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type PackageManager = "pnpm" | "npm" | "yarn" | "bun";
|
|
2
|
+
export interface InstallCommand {
|
|
3
|
+
command: string;
|
|
4
|
+
args: string[];
|
|
5
|
+
fallbackArgs: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function detectPackageManager(projectRoot: string): PackageManager;
|
|
8
|
+
export declare function getInstallCommand(pm: PackageManager): InstallCommand;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
export function detectPackageManager(projectRoot) {
|
|
4
|
+
if (existsSync(join(projectRoot, "pnpm-lock.yaml"))) {
|
|
5
|
+
return "pnpm";
|
|
6
|
+
}
|
|
7
|
+
if (existsSync(join(projectRoot, "yarn.lock"))) {
|
|
8
|
+
return "yarn";
|
|
9
|
+
}
|
|
10
|
+
if (existsSync(join(projectRoot, "bun.lockb"))) {
|
|
11
|
+
return "bun";
|
|
12
|
+
}
|
|
13
|
+
// Default to npm if package-lock.json exists or as fallback
|
|
14
|
+
return "npm";
|
|
15
|
+
}
|
|
16
|
+
export function getInstallCommand(pm) {
|
|
17
|
+
switch (pm) {
|
|
18
|
+
case "pnpm":
|
|
19
|
+
return {
|
|
20
|
+
command: "pnpm",
|
|
21
|
+
args: ["install", "--frozen-lockfile"],
|
|
22
|
+
fallbackArgs: ["install"],
|
|
23
|
+
};
|
|
24
|
+
case "yarn":
|
|
25
|
+
return {
|
|
26
|
+
command: "yarn",
|
|
27
|
+
args: ["install", "--frozen-lockfile"],
|
|
28
|
+
fallbackArgs: ["install"],
|
|
29
|
+
};
|
|
30
|
+
case "bun":
|
|
31
|
+
return {
|
|
32
|
+
command: "bun",
|
|
33
|
+
args: ["install", "--frozen-lockfile"],
|
|
34
|
+
fallbackArgs: ["install"],
|
|
35
|
+
};
|
|
36
|
+
case "npm":
|
|
37
|
+
default:
|
|
38
|
+
return {
|
|
39
|
+
command: "npm",
|
|
40
|
+
args: ["ci"],
|
|
41
|
+
fallbackArgs: ["install"],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
package/package.json
CHANGED