@fermindi/pwn-cli 0.9.0 → 0.9.1
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/package.json
CHANGED
|
@@ -9,10 +9,13 @@
|
|
|
9
9
|
* Completed files are cleaned up at the end; failed are kept for review.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { spawn } from 'child_process';
|
|
12
|
+
import { spawn, exec } from 'child_process';
|
|
13
13
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, createWriteStream, appendFileSync, unlinkSync, readdirSync } from 'fs';
|
|
14
14
|
import { join } from 'path';
|
|
15
|
+
import { promisify } from 'util';
|
|
15
16
|
import ora from 'ora';
|
|
17
|
+
|
|
18
|
+
const execAsync = promisify(exec);
|
|
16
19
|
import chalk from 'chalk';
|
|
17
20
|
import {
|
|
18
21
|
parsePrdTasks,
|
|
@@ -434,7 +437,10 @@ export async function runBatch(options = {}, cwd = process.cwd()) {
|
|
|
434
437
|
if (result.signal) {
|
|
435
438
|
console.log(chalk.yellow(` Killed by ${result.signal}`));
|
|
436
439
|
if (taskBranch) {
|
|
437
|
-
try {
|
|
440
|
+
try {
|
|
441
|
+
try { await execAsync('git stash --include-untracked', { cwd }); } catch {}
|
|
442
|
+
await checkoutBranch(batchBranch, cwd, { force: true });
|
|
443
|
+
} catch {}
|
|
438
444
|
}
|
|
439
445
|
clearBatchState(cwd);
|
|
440
446
|
printSummary(cwd, iteration, storiesCompleted, batchStart, branchesCreated, batchBranch, originalBranch, mergedCount, unmergedBranches);
|
|
@@ -544,15 +550,21 @@ export async function runBatch(options = {}, cwd = process.cwd()) {
|
|
|
544
550
|
// Merge successful task branch into batch branch
|
|
545
551
|
if (taskBranch) {
|
|
546
552
|
try {
|
|
553
|
+
// Stash uncommitted metadata (task files etc.) before switching
|
|
554
|
+
await execAsync('git stash --include-untracked', { cwd });
|
|
547
555
|
await checkoutBranch(batchBranch, cwd);
|
|
548
556
|
await mergeBranch(taskBranch, cwd);
|
|
549
557
|
mergedCount++;
|
|
550
558
|
mergedBranches.push(taskBranch);
|
|
551
559
|
console.log(chalk.green(` Merged ${taskBranch} → ${batchBranch}`));
|
|
560
|
+
// Restore stashed metadata on batch branch
|
|
561
|
+
try { await execAsync('git stash pop', { cwd }); } catch {}
|
|
552
562
|
} catch (err) {
|
|
553
563
|
console.log(chalk.red(` Merge failed: ${err.message}`));
|
|
554
564
|
console.log(chalk.yellow(` Branch ${taskBranch} available for manual merge`));
|
|
555
565
|
unmergedBranches.push(taskBranch);
|
|
566
|
+
// Drop stash if checkout/merge failed (still on feat branch)
|
|
567
|
+
try { await execAsync('git stash drop', { cwd }); } catch {}
|
|
556
568
|
}
|
|
557
569
|
}
|
|
558
570
|
} else {
|
|
@@ -586,10 +598,12 @@ export async function runBatch(options = {}, cwd = process.cwd()) {
|
|
|
586
598
|
noProgressCount++;
|
|
587
599
|
}
|
|
588
600
|
|
|
589
|
-
// --- Return to batch branch (force
|
|
601
|
+
// --- Return to batch branch (stash untracked + force for dirty state) ---
|
|
590
602
|
if (taskBranch) {
|
|
591
603
|
try {
|
|
604
|
+
try { await execAsync('git stash --include-untracked', { cwd }); } catch {}
|
|
592
605
|
await checkoutBranch(batchBranch, cwd, { force: true });
|
|
606
|
+
try { await execAsync('git stash pop', { cwd }); } catch {}
|
|
593
607
|
console.log(chalk.dim(` Returned to branch: ${batchBranch}`));
|
|
594
608
|
} catch (err) {
|
|
595
609
|
console.log(chalk.red(` Warning: failed to return to ${batchBranch}: ${err.message}`));
|
|
@@ -34,16 +34,22 @@ export async function getCurrentBranch(cwd = process.cwd()) {
|
|
|
34
34
|
*/
|
|
35
35
|
export async function createTaskBranch(taskId, cwd = process.cwd()) {
|
|
36
36
|
const branch = `feat/${taskId}`;
|
|
37
|
+
let exists = false;
|
|
37
38
|
try {
|
|
38
39
|
await execAsync(`git rev-parse --verify ${branch}`, { cwd });
|
|
39
|
-
|
|
40
|
+
exists = true;
|
|
41
|
+
} catch {
|
|
42
|
+
// Branch doesn't exist
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (exists) {
|
|
46
|
+
// Rerun — checkout and reset to current HEAD
|
|
40
47
|
// so we don't carry stale/dirty state from previous attempt
|
|
41
48
|
const { stdout } = await execAsync('git rev-parse HEAD', { cwd });
|
|
42
49
|
const baseRef = stdout.trim();
|
|
43
50
|
await execAsync(`git checkout ${branch}`, { cwd });
|
|
44
51
|
await execAsync(`git reset --hard ${baseRef}`, { cwd });
|
|
45
|
-
}
|
|
46
|
-
// Branch doesn't exist — create
|
|
52
|
+
} else {
|
|
47
53
|
await execAsync(`git checkout -b ${branch}`, { cwd });
|
|
48
54
|
}
|
|
49
55
|
return branch;
|