create-claude-workspace 2.3.14 → 2.3.16
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/scheduler/loop.mjs +65 -35
- package/package.json +1 -1
package/dist/scheduler/loop.mjs
CHANGED
|
@@ -911,34 +911,57 @@ async function pollAndMergePR(task, pipeline, branch, platform, projectDir, work
|
|
|
911
911
|
return true;
|
|
912
912
|
if (prStatus.status === 'closed')
|
|
913
913
|
return false;
|
|
914
|
-
//
|
|
915
|
-
if (prStatus.
|
|
914
|
+
// Ready to merge — CI passed and mergeable
|
|
915
|
+
if (prStatus.mergeable) {
|
|
916
|
+
logger.info(`[${task.id}] PR mergeable — merging`);
|
|
917
|
+
return mergePR(projectDir, platform, prStatus.number);
|
|
918
|
+
}
|
|
919
|
+
// CI still running or not started — poll
|
|
920
|
+
if (prStatus.ciStatus === 'pending' || prStatus.ciStatus === 'not-found') {
|
|
921
|
+
logger.info(`[${task.id}] CI: ${prStatus.ciStatus} — polling...`);
|
|
922
|
+
await sleep(PR_POLL_INTERVAL);
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
// CI passed but not mergeable (needs approval, merge checks, etc.) — poll
|
|
926
|
+
if (prStatus.ciStatus === 'passed' && !prStatus.mergeable) {
|
|
927
|
+
logger.info(`[${task.id}] CI passed, not yet mergeable — polling...`);
|
|
928
|
+
await sleep(PR_POLL_INTERVAL);
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
// CI failed — delegate to implementing agent to fix
|
|
932
|
+
if (prStatus.ciStatus === 'failed') {
|
|
933
|
+
if (pipeline.ciFixes >= MAX_CI_FIXES) {
|
|
934
|
+
logger.error(`[${task.id}] CI fix limit (${MAX_CI_FIXES}) reached — giving up`);
|
|
935
|
+
return false;
|
|
936
|
+
}
|
|
916
937
|
pipeline.ciFixes++;
|
|
917
|
-
logger.warn(`[${task.id}] CI failed — fix attempt ${pipeline.ciFixes}/${MAX_CI_FIXES}`);
|
|
938
|
+
logger.warn(`[${task.id}] CI failed — delegating fix to agent (attempt ${pipeline.ciFixes}/${MAX_CI_FIXES})`);
|
|
918
939
|
const logs = fetchFailureLogs(branch, platform === 'github' ? 'github' : 'gitlab', projectDir);
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
940
|
+
const fixResult = await spawnAgent(pool, pipeline.workerId, {
|
|
941
|
+
agent: pipeline.assignedAgent ?? undefined,
|
|
942
|
+
cwd: worktreePath,
|
|
943
|
+
prompt: buildCIFixPrompt({ task, worktreePath, projectDir }, logs ?? 'No logs available — check the CI pipeline manually'),
|
|
944
|
+
model: getAgentModel(pipeline.assignedAgent, agents, task),
|
|
945
|
+
}, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
|
|
946
|
+
if (fixResult.success) {
|
|
947
|
+
const sha = commitInWorktree(worktreePath, `fix: CI failure for ${task.title}`);
|
|
948
|
+
if (sha) {
|
|
928
949
|
forcePushWorktree(worktreePath);
|
|
950
|
+
logger.info(`[${task.id}] Fix pushed — polling for new CI pipeline`);
|
|
951
|
+
// Poll until CI status changes from 'failed' (= new pipeline picked up)
|
|
952
|
+
await waitForCIRefresh(task.id, projectDir, platform, branch, logger);
|
|
929
953
|
continue;
|
|
930
954
|
}
|
|
931
955
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
}
|
|
956
|
+
// Fix didn't produce changes — poll and let next iteration re-evaluate
|
|
957
|
+
await sleep(PR_POLL_INTERVAL);
|
|
958
|
+
continue;
|
|
936
959
|
}
|
|
937
960
|
// Unresolved PR comments — spawn agent to address
|
|
938
961
|
const comments = getPRComments(projectDir, platform, prStatus.number);
|
|
939
962
|
const unresolved = comments.filter(c => !c.resolved);
|
|
940
963
|
if (unresolved.length > 0) {
|
|
941
|
-
logger.info(`[${task.id}] ${unresolved.length} unresolved PR comments —
|
|
964
|
+
logger.info(`[${task.id}] ${unresolved.length} unresolved PR comments — delegating to agent`);
|
|
942
965
|
const commentText = unresolved
|
|
943
966
|
.map(c => `${c.path ?? 'general'}${c.line ? `:${c.line}` : ''} — ${c.author}: ${c.body}`)
|
|
944
967
|
.join('\n\n');
|
|
@@ -949,25 +972,14 @@ async function pollAndMergePR(task, pipeline, branch, platform, projectDir, work
|
|
|
949
972
|
model: getAgentModel(pipeline.assignedAgent, agents, task),
|
|
950
973
|
}, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
|
|
951
974
|
if (commentResult.success) {
|
|
952
|
-
commitInWorktree(worktreePath,
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
975
|
+
const sha = commitInWorktree(worktreePath, 'fix: address PR review comments');
|
|
976
|
+
if (sha) {
|
|
977
|
+
forcePushWorktree(worktreePath);
|
|
978
|
+
appendEvent(projectDir, createEvent('pr_comment_resolved', { taskId: task.id, detail: `${unresolved.length} comments` }));
|
|
979
|
+
await waitForCIRefresh(task.id, projectDir, platform, branch, logger);
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
956
982
|
}
|
|
957
|
-
}
|
|
958
|
-
// Ready to merge
|
|
959
|
-
if (prStatus.mergeable) {
|
|
960
|
-
const merged = mergePR(projectDir, platform, prStatus.number);
|
|
961
|
-
return merged;
|
|
962
|
-
}
|
|
963
|
-
// CI pending or waiting for approval — keep polling
|
|
964
|
-
if (prStatus.ciStatus === 'pending' || prStatus.ciStatus === 'not-found') {
|
|
965
|
-
await sleep(PR_POLL_INTERVAL);
|
|
966
|
-
continue;
|
|
967
|
-
}
|
|
968
|
-
// CI passed but not mergeable (needs approval?) — wait
|
|
969
|
-
if (prStatus.ciStatus === 'passed' && !prStatus.mergeable) {
|
|
970
|
-
logger.info(`[${task.id}] CI passed but not mergeable (waiting for approval?)`);
|
|
971
983
|
await sleep(PR_POLL_INTERVAL);
|
|
972
984
|
continue;
|
|
973
985
|
}
|
|
@@ -976,6 +988,24 @@ async function pollAndMergePR(task, pipeline, branch, platform, projectDir, work
|
|
|
976
988
|
logger.warn(`[${task.id}] PR poll timeout (${PR_MAX_POLL_TIME / 60_000}min)`);
|
|
977
989
|
return false;
|
|
978
990
|
}
|
|
991
|
+
/** Poll until CI status is no longer the previous 'failed' (= new pipeline started) */
|
|
992
|
+
async function waitForCIRefresh(taskId, projectDir, platform, branch, logger) {
|
|
993
|
+
const maxWait = 5 * 60_000; // 5 min max to wait for new pipeline
|
|
994
|
+
const start = Date.now();
|
|
995
|
+
while (Date.now() - start < maxWait) {
|
|
996
|
+
await sleep(PR_POLL_INTERVAL);
|
|
997
|
+
try {
|
|
998
|
+
const status = getPRStatus(projectDir, platform, branch);
|
|
999
|
+
if (status.ciStatus !== 'failed') {
|
|
1000
|
+
logger.info(`[${taskId}] New CI pipeline detected: ${status.ciStatus}`);
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
logger.info(`[${taskId}] CI still shows previous failure — polling...`);
|
|
1004
|
+
}
|
|
1005
|
+
catch { /* ignore */ }
|
|
1006
|
+
}
|
|
1007
|
+
logger.warn(`[${taskId}] Timed out waiting for new CI pipeline`);
|
|
1008
|
+
}
|
|
979
1009
|
function buildPRBody(task, pipeline) {
|
|
980
1010
|
const lines = [
|
|
981
1011
|
`## Summary`,
|