ralph-cli-sandboxed 0.6.4 → 0.6.5
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/dist/commands/run.js +70 -14
- package/package.json +1 -1
package/dist/commands/run.js
CHANGED
|
@@ -118,11 +118,11 @@ function setupWorktreeRalphDir(worktreePath, branchItems, workspacePaths) {
|
|
|
118
118
|
}
|
|
119
119
|
/**
|
|
120
120
|
* Creates a filtered PRD file containing only incomplete items (passes: false).
|
|
121
|
-
* Optionally filters by category if specified.
|
|
121
|
+
* Optionally filters by category and/or branch if specified.
|
|
122
122
|
* Expands @{filepath} references to include file contents.
|
|
123
123
|
* Returns the path to the temp file, or null if all items pass.
|
|
124
124
|
*/
|
|
125
|
-
function createFilteredPrd(prdPath, baseDir, category) {
|
|
125
|
+
function createFilteredPrd(prdPath, baseDir, category, branchFilterActive, branchFilter) {
|
|
126
126
|
// Use readPrdFile to handle both JSON and YAML formats
|
|
127
127
|
const parsed = readPrdFile(prdPath);
|
|
128
128
|
if (!parsed) {
|
|
@@ -145,6 +145,10 @@ function createFilteredPrd(prdPath, baseDir, category) {
|
|
|
145
145
|
if (category) {
|
|
146
146
|
filteredItems = filteredItems.filter((item) => item.category === category);
|
|
147
147
|
}
|
|
148
|
+
// Apply branch filter if specified
|
|
149
|
+
if (branchFilterActive) {
|
|
150
|
+
filteredItems = applyBranchFilter(filteredItems, branchFilter);
|
|
151
|
+
}
|
|
148
152
|
// Expand @{filepath} references in description and steps
|
|
149
153
|
const expandedItems = expandPrdFileReferences(filteredItems, baseDir);
|
|
150
154
|
// Write to .ralph/prd-tasks.json so LLMs see a sensible path
|
|
@@ -406,11 +410,24 @@ function formatElapsedTime(startTime, endTime) {
|
|
|
406
410
|
parts.push(`${seconds}s`);
|
|
407
411
|
return parts.join(" ");
|
|
408
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* Filters PRD items by branch.
|
|
415
|
+
* - branchFilter = "name": only items whose branch field matches "name"
|
|
416
|
+
* - branchFilter = "": only items that have any branch field set (non-empty)
|
|
417
|
+
*/
|
|
418
|
+
function applyBranchFilter(items, branchFilter) {
|
|
419
|
+
if (branchFilter === "") {
|
|
420
|
+
// --branch without value: include only items that have a branch set
|
|
421
|
+
return items.filter((item) => item.branch && item.branch.length > 0);
|
|
422
|
+
}
|
|
423
|
+
// --branch <name>: include only items whose branch matches
|
|
424
|
+
return items.filter((item) => item.branch === branchFilter);
|
|
425
|
+
}
|
|
409
426
|
/**
|
|
410
427
|
* Counts total and incomplete items in the PRD.
|
|
411
|
-
* Optionally filters by category if specified.
|
|
428
|
+
* Optionally filters by category and/or branch if specified.
|
|
412
429
|
*/
|
|
413
|
-
function countPrdItems(prdPath, category) {
|
|
430
|
+
function countPrdItems(prdPath, category, branchFilterActive, branchFilter) {
|
|
414
431
|
// Use readPrdFile to handle both JSON and YAML formats
|
|
415
432
|
const parsed = readPrdFile(prdPath);
|
|
416
433
|
if (!parsed) {
|
|
@@ -430,7 +447,10 @@ function countPrdItems(prdPath, category) {
|
|
|
430
447
|
const items = parsed.content;
|
|
431
448
|
let filteredItems = items;
|
|
432
449
|
if (category) {
|
|
433
|
-
filteredItems =
|
|
450
|
+
filteredItems = filteredItems.filter((item) => item.category === category);
|
|
451
|
+
}
|
|
452
|
+
if (branchFilterActive) {
|
|
453
|
+
filteredItems = applyBranchFilter(filteredItems, branchFilter);
|
|
434
454
|
}
|
|
435
455
|
const complete = filteredItems.filter((item) => item.passes === true).length;
|
|
436
456
|
const incomplete = filteredItems.filter((item) => item.passes === false).length;
|
|
@@ -537,6 +557,8 @@ function loadValidPrd(prdPath) {
|
|
|
537
557
|
export async function run(args) {
|
|
538
558
|
// Parse flags
|
|
539
559
|
let category;
|
|
560
|
+
let branchFilter; // undefined = no filter, "" = any branch, "name" = specific branch
|
|
561
|
+
let branchFilterActive = false; // true when --branch flag is present
|
|
540
562
|
let model;
|
|
541
563
|
let loopMode = false;
|
|
542
564
|
let allModeExplicit = false;
|
|
@@ -554,6 +576,18 @@ export async function run(args) {
|
|
|
554
576
|
process.exit(1);
|
|
555
577
|
}
|
|
556
578
|
}
|
|
579
|
+
else if (args[i] === "--branch" || args[i] === "-b") {
|
|
580
|
+
branchFilterActive = true;
|
|
581
|
+
// Check if next arg is a branch name (not another flag)
|
|
582
|
+
if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
583
|
+
branchFilter = args[i + 1];
|
|
584
|
+
i++; // Skip the branch value
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
// --branch without a value: filter to items that have any branch set
|
|
588
|
+
branchFilter = "";
|
|
589
|
+
}
|
|
590
|
+
}
|
|
557
591
|
else if (args[i] === "--model" || args[i] === "-m") {
|
|
558
592
|
if (i + 1 < args.length) {
|
|
559
593
|
model = args[i + 1];
|
|
@@ -638,7 +672,7 @@ export async function run(args) {
|
|
|
638
672
|
// Container is required, so always run with skip-permissions
|
|
639
673
|
const sandboxed = true;
|
|
640
674
|
if (allMode) {
|
|
641
|
-
const counts = countPrdItems(paths.prd, category);
|
|
675
|
+
const counts = countPrdItems(paths.prd, category, branchFilterActive, branchFilter);
|
|
642
676
|
console.log("Starting ralph in --all mode (runs until all tasks complete)...");
|
|
643
677
|
console.log(`PRD Status: ${counts.complete}/${counts.total} complete, ${counts.incomplete} remaining`);
|
|
644
678
|
}
|
|
@@ -651,6 +685,25 @@ export async function run(args) {
|
|
|
651
685
|
if (category) {
|
|
652
686
|
console.log(`Filtering PRD items by category: ${category}`);
|
|
653
687
|
}
|
|
688
|
+
if (branchFilterActive) {
|
|
689
|
+
if (branchFilter === "") {
|
|
690
|
+
console.log("Filtering PRD items to only branched items");
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
console.log(`Filtering PRD items by branch: ${branchFilter}`);
|
|
694
|
+
}
|
|
695
|
+
// Check if any items match the branch filter; if not, exit early
|
|
696
|
+
const branchCounts = countPrdItems(paths.prd, category, branchFilterActive, branchFilter);
|
|
697
|
+
if (branchCounts.total === 0) {
|
|
698
|
+
if (branchFilter === "") {
|
|
699
|
+
console.error("\nNo PRD items have a branch field set.");
|
|
700
|
+
}
|
|
701
|
+
else {
|
|
702
|
+
console.error(`\nNo PRD items match branch "${branchFilter}".`);
|
|
703
|
+
}
|
|
704
|
+
process.exit(1);
|
|
705
|
+
}
|
|
706
|
+
}
|
|
654
707
|
if (streamJson?.enabled) {
|
|
655
708
|
console.log("Stream JSON output enabled - displaying formatted Claude output");
|
|
656
709
|
if (streamJson.saveRawJson) {
|
|
@@ -668,7 +721,7 @@ export async function run(args) {
|
|
|
668
721
|
let iterationCount = 0;
|
|
669
722
|
// Progress tracking for --all mode
|
|
670
723
|
// Progress = tasks completed OR new tasks added (allows ralph to expand the PRD)
|
|
671
|
-
const initialCounts = countPrdItems(paths.prd, category);
|
|
724
|
+
const initialCounts = countPrdItems(paths.prd, category, branchFilterActive, branchFilter);
|
|
672
725
|
let lastCompletedCount = initialCounts.complete;
|
|
673
726
|
let lastTotalCount = initialCounts.total;
|
|
674
727
|
let iterationsWithoutProgress = 0;
|
|
@@ -796,7 +849,7 @@ export async function run(args) {
|
|
|
796
849
|
try {
|
|
797
850
|
while (true) {
|
|
798
851
|
iterationCount++;
|
|
799
|
-
const currentCounts = countPrdItems(paths.prd, category);
|
|
852
|
+
const currentCounts = countPrdItems(paths.prd, category, branchFilterActive, branchFilter);
|
|
800
853
|
// Check if we should stop (not in loop mode)
|
|
801
854
|
if (!loopMode && !allMode) {
|
|
802
855
|
if (iterationCount > requestedIterations) {
|
|
@@ -823,6 +876,9 @@ export async function run(args) {
|
|
|
823
876
|
if (category) {
|
|
824
877
|
itemsForIteration = itemsForIteration.filter((item) => item.category === category);
|
|
825
878
|
}
|
|
879
|
+
if (branchFilterActive) {
|
|
880
|
+
itemsForIteration = applyBranchFilter(itemsForIteration, branchFilter);
|
|
881
|
+
}
|
|
826
882
|
const branchGroups = groupItemsByBranch(itemsForIteration);
|
|
827
883
|
// Check if there are any incomplete items
|
|
828
884
|
if (branchGroups.size === 0) {
|
|
@@ -838,7 +894,7 @@ export async function run(args) {
|
|
|
838
894
|
console.log("=".repeat(50));
|
|
839
895
|
while (true) {
|
|
840
896
|
await sleep(POLL_INTERVAL_MS);
|
|
841
|
-
const { hasIncomplete: newItems } = createFilteredPrd(paths.prd, paths.dir, category);
|
|
897
|
+
const { hasIncomplete: newItems } = createFilteredPrd(paths.prd, paths.dir, category, branchFilterActive, branchFilter);
|
|
842
898
|
if (newItems) {
|
|
843
899
|
console.log("\nNew incomplete item(s) detected! Resuming...");
|
|
844
900
|
break;
|
|
@@ -850,7 +906,7 @@ export async function run(args) {
|
|
|
850
906
|
else {
|
|
851
907
|
console.log("\n" + "=".repeat(50));
|
|
852
908
|
if (allMode) {
|
|
853
|
-
const counts = countPrdItems(paths.prd, category);
|
|
909
|
+
const counts = countPrdItems(paths.prd, category, branchFilterActive, branchFilter);
|
|
854
910
|
if (category) {
|
|
855
911
|
console.log(`PRD COMPLETE - All "${category}" tasks finished!`);
|
|
856
912
|
}
|
|
@@ -980,7 +1036,7 @@ export async function run(args) {
|
|
|
980
1036
|
console.log(`\n\x1b[36m--- No-branch items (${noBranchItems.length} item(s)) ---\x1b[0m`);
|
|
981
1037
|
}
|
|
982
1038
|
// Create filtered PRD for no-branch items only (or all items if no branches exist)
|
|
983
|
-
const { tempPath } = createFilteredPrd(paths.prd, paths.dir, category);
|
|
1039
|
+
const { tempPath } = createFilteredPrd(paths.prd, paths.dir, category, branchFilterActive, branchFilter);
|
|
984
1040
|
filteredPrdPath = tempPath;
|
|
985
1041
|
// If there are branch groups, rewrite prd-tasks.json to only include no-branch items
|
|
986
1042
|
if (hasBranches) {
|
|
@@ -999,7 +1055,7 @@ export async function run(args) {
|
|
|
999
1055
|
validateAndRecoverPrd(paths.prd, validPrd);
|
|
1000
1056
|
// Track progress for --all mode: stop if no progress after N iterations
|
|
1001
1057
|
if (allMode) {
|
|
1002
|
-
const progressCounts = countPrdItems(paths.prd, category);
|
|
1058
|
+
const progressCounts = countPrdItems(paths.prd, category, branchFilterActive, branchFilter);
|
|
1003
1059
|
const tasksCompleted = progressCounts.complete > lastCompletedCount;
|
|
1004
1060
|
const tasksAdded = progressCounts.total > lastTotalCount;
|
|
1005
1061
|
if (tasksCompleted || tasksAdded) {
|
|
@@ -1060,7 +1116,7 @@ export async function run(args) {
|
|
|
1060
1116
|
// so its COMPLETE signal means "this group is done", not "all PRD items are done".
|
|
1061
1117
|
// We must verify the full PRD before treating this as a global completion.
|
|
1062
1118
|
if (iterOutput.includes("<promise>COMPLETE</promise>")) {
|
|
1063
|
-
const fullCounts = countPrdItems(paths.prd, category);
|
|
1119
|
+
const fullCounts = countPrdItems(paths.prd, category, branchFilterActive, branchFilter);
|
|
1064
1120
|
if (fullCounts.incomplete > 0) {
|
|
1065
1121
|
// There are still incomplete items in other groups — continue the loop
|
|
1066
1122
|
if (debug) {
|
|
@@ -1074,7 +1130,7 @@ export async function run(args) {
|
|
|
1074
1130
|
console.log("=".repeat(50));
|
|
1075
1131
|
while (true) {
|
|
1076
1132
|
await sleep(POLL_INTERVAL_MS);
|
|
1077
|
-
const { hasIncomplete: newItems } = createFilteredPrd(paths.prd, paths.dir, category);
|
|
1133
|
+
const { hasIncomplete: newItems } = createFilteredPrd(paths.prd, paths.dir, category, branchFilterActive, branchFilter);
|
|
1078
1134
|
if (newItems) {
|
|
1079
1135
|
console.log("\nNew incomplete item(s) detected! Resuming...");
|
|
1080
1136
|
break;
|