@groupchatai/claude-runner 0.4.2 → 0.4.3
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/index.js +76 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -461,15 +461,24 @@ function getDefaultBranch(repoDir) {
|
|
|
461
461
|
return "main";
|
|
462
462
|
}
|
|
463
463
|
}
|
|
464
|
-
function createWorktree(repoDir, taskId) {
|
|
464
|
+
function createWorktree(repoDir, taskId, existingBranch) {
|
|
465
465
|
const name = worktreeNameForTask(taskId);
|
|
466
|
-
const branchName = `agent/${name}-${Date.now()}`;
|
|
467
466
|
const worktreeBase = path.join(repoDir, WORKTREE_DIR);
|
|
468
467
|
const worktreePath = path.join(worktreeBase, name);
|
|
469
468
|
if (existsSync(worktreePath)) {
|
|
470
469
|
return worktreePath;
|
|
471
470
|
}
|
|
471
|
+
if (existingBranch) {
|
|
472
|
+
try {
|
|
473
|
+
execGit(["fetch", "origin", existingBranch, "--quiet"], repoDir);
|
|
474
|
+
} catch {
|
|
475
|
+
}
|
|
476
|
+
execGit(["worktree", "add", worktreePath, `origin/${existingBranch}`], repoDir);
|
|
477
|
+
writeFileSync(path.join(worktreePath, ".agent-branch"), existingBranch, "utf-8");
|
|
478
|
+
return worktreePath;
|
|
479
|
+
}
|
|
472
480
|
const baseBranch = getDefaultBranch(repoDir);
|
|
481
|
+
const branchName = `agent/${name}-${Date.now()}`;
|
|
473
482
|
try {
|
|
474
483
|
execGit(["fetch", "origin", baseBranch, "--quiet"], repoDir);
|
|
475
484
|
} catch {
|
|
@@ -478,6 +487,39 @@ function createWorktree(repoDir, taskId) {
|
|
|
478
487
|
writeFileSync(path.join(worktreePath, ".agent-branch"), branchName, "utf-8");
|
|
479
488
|
return worktreePath;
|
|
480
489
|
}
|
|
490
|
+
async function resolveExistingPrBranch(detail, workDir) {
|
|
491
|
+
try {
|
|
492
|
+
if (detail.branchName) return detail.branchName;
|
|
493
|
+
if (detail.pullRequestUrl) {
|
|
494
|
+
try {
|
|
495
|
+
const branch2 = await runShellCommand(
|
|
496
|
+
"gh",
|
|
497
|
+
["pr", "view", detail.pullRequestUrl, "--json", "headRefName", "--jq", ".headRefName"],
|
|
498
|
+
workDir
|
|
499
|
+
);
|
|
500
|
+
if (branch2?.trim()) return branch2.trim();
|
|
501
|
+
} catch {
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const prUrls = [];
|
|
505
|
+
for (const item of detail.activity) {
|
|
506
|
+
if (item.body) {
|
|
507
|
+
const matches = item.body.match(GITHUB_PR_URL_RE);
|
|
508
|
+
if (matches) prUrls.push(...matches);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
const prUrl = prUrls[prUrls.length - 1];
|
|
512
|
+
if (!prUrl) return void 0;
|
|
513
|
+
const branch = await runShellCommand(
|
|
514
|
+
"gh",
|
|
515
|
+
["pr", "view", prUrl, "--json", "headRefName", "--jq", ".headRefName"],
|
|
516
|
+
workDir
|
|
517
|
+
);
|
|
518
|
+
if (branch?.trim()) return branch.trim();
|
|
519
|
+
} catch {
|
|
520
|
+
}
|
|
521
|
+
return void 0;
|
|
522
|
+
}
|
|
481
523
|
async function listOurWorktrees(workDir) {
|
|
482
524
|
const worktreeDir = path.join(workDir, WORKTREE_DIR);
|
|
483
525
|
let entries;
|
|
@@ -640,12 +682,11 @@ Removing ${safe.length} safe worktree(s)\u2026`);
|
|
|
640
682
|
}
|
|
641
683
|
console.log();
|
|
642
684
|
}
|
|
643
|
-
async function processRun(client, run, config, worktreeDir) {
|
|
685
|
+
async function processRun(client, run, config, worktreeDir, detail) {
|
|
644
686
|
const runNum = ++runCounter;
|
|
645
687
|
const runTag = ` ${C.pid}[${runNum}]${C.reset}`;
|
|
646
688
|
const log = (msg) => console.log(`${runTag} ${msg}`);
|
|
647
689
|
const logGreen = (msg) => console.log(`${runTag} ${C.green}${msg}${C.reset}`);
|
|
648
|
-
const detail = await client.getRunDetail(run.id);
|
|
649
690
|
const ownerName = run.owner?.name ?? detail.owner?.name ?? "unknown";
|
|
650
691
|
log(`\u{1F4CB} "${run.taskTitle}" \u2014 delegated by ${ownerName}`);
|
|
651
692
|
if (detail.status !== "PENDING") {
|
|
@@ -919,6 +960,12 @@ var TaskScheduler = class {
|
|
|
919
960
|
return this.slots.size === 0;
|
|
920
961
|
}
|
|
921
962
|
};
|
|
963
|
+
function drainSchedulerSlot(scheduler, run) {
|
|
964
|
+
let current = run;
|
|
965
|
+
while (current) {
|
|
966
|
+
current = scheduler.complete(current);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
922
969
|
function handlePendingRuns(runs, scheduler, client, config) {
|
|
923
970
|
if (runs.length > 0 && config.verbose) {
|
|
924
971
|
console.log(`\u{1F4EC} ${runs.length} pending run(s)`);
|
|
@@ -943,27 +990,47 @@ function handlePendingRuns(runs, scheduler, client, config) {
|
|
|
943
990
|
}
|
|
944
991
|
}
|
|
945
992
|
async function processRunWithDrain(client, run, scheduler, config) {
|
|
993
|
+
let detail;
|
|
994
|
+
try {
|
|
995
|
+
detail = await client.getRunDetail(run.id);
|
|
996
|
+
} catch (err) {
|
|
997
|
+
console.error(` \u274C Failed to fetch run detail for ${run.id}:`, err);
|
|
998
|
+
drainSchedulerSlot(scheduler, run);
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
946
1001
|
let worktreeDir;
|
|
947
1002
|
if (config.useWorktrees) {
|
|
948
1003
|
try {
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
)
|
|
1004
|
+
const existingBranch = await resolveExistingPrBranch(detail, config.workDir);
|
|
1005
|
+
worktreeDir = createWorktree(config.workDir, run.taskId, existingBranch);
|
|
1006
|
+
const rel = path.relative(config.workDir, worktreeDir);
|
|
1007
|
+
if (existingBranch) {
|
|
1008
|
+
console.log(` \u{1F333} Worktree from existing PR branch ${existingBranch} \u2192 ${rel}`);
|
|
1009
|
+
} else {
|
|
1010
|
+
console.log(` \u{1F333} Worktree created from main \u2192 ${rel}`);
|
|
1011
|
+
}
|
|
953
1012
|
} catch (err) {
|
|
954
1013
|
console.error(` \u26A0 Failed to create worktree, running in-place:`, err);
|
|
955
1014
|
}
|
|
956
1015
|
}
|
|
957
1016
|
let current = run;
|
|
1017
|
+
let currentDetail = detail;
|
|
958
1018
|
while (current) {
|
|
959
1019
|
try {
|
|
960
|
-
await processRun(client, current, config, worktreeDir);
|
|
1020
|
+
await processRun(client, current, config, worktreeDir, currentDetail);
|
|
961
1021
|
} catch (err) {
|
|
962
1022
|
console.error(`Unhandled error processing run ${current.id}:`, err);
|
|
963
1023
|
}
|
|
964
1024
|
current = scheduler.complete(current);
|
|
965
1025
|
if (current) {
|
|
966
1026
|
console.log(` \u23ED Processing queued follow-up\u2026`);
|
|
1027
|
+
try {
|
|
1028
|
+
currentDetail = await client.getRunDetail(current.id);
|
|
1029
|
+
} catch (err) {
|
|
1030
|
+
console.error(` \u274C Failed to fetch detail for follow-up ${current.id}:`, err);
|
|
1031
|
+
drainSchedulerSlot(scheduler, current);
|
|
1032
|
+
break;
|
|
1033
|
+
}
|
|
967
1034
|
}
|
|
968
1035
|
}
|
|
969
1036
|
if (worktreeDir) {
|