create-claude-workspace 2.3.13 → 2.3.15

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.
@@ -905,40 +905,82 @@ const PR_MAX_POLL_TIME = 30 * 60_000;
905
905
  async function pollAndMergePR(task, pipeline, branch, platform, projectDir, worktreePath, agents, deps) {
906
906
  const { pool, logger, state, onMessage, onSpawnStart, onSpawnEnd } = deps;
907
907
  const startTime = Date.now();
908
+ let lastSeenCIStatus = 'none'; // Track CI transitions to detect stale status
909
+ // Initial wait — give CI time to pick up the new push
910
+ logger.info(`[${task.id}] Waiting for CI pipeline to start...`);
911
+ await sleep(PR_POLL_INTERVAL);
908
912
  while (Date.now() - startTime < PR_MAX_POLL_TIME) {
909
913
  const prStatus = getPRStatus(projectDir, platform, branch);
910
914
  if (prStatus.status === 'merged')
911
915
  return true;
912
916
  if (prStatus.status === 'closed')
913
917
  return false;
914
- // CI failedspawn agent to fix
915
- if (prStatus.ciStatus === 'failed' && pipeline.ciFixes < MAX_CI_FIXES) {
918
+ // Ready to merge CI passed and mergeable
919
+ if (prStatus.mergeable) {
920
+ logger.info(`[${task.id}] PR mergeable — merging`);
921
+ const merged = mergePR(projectDir, platform, prStatus.number);
922
+ return merged;
923
+ }
924
+ // CI still running or not started — wait
925
+ if (prStatus.ciStatus === 'pending' || prStatus.ciStatus === 'not-found') {
926
+ if (prStatus.ciStatus !== lastSeenCIStatus) {
927
+ logger.info(`[${task.id}] CI: ${prStatus.ciStatus} — waiting...`);
928
+ lastSeenCIStatus = prStatus.ciStatus;
929
+ }
930
+ await sleep(PR_POLL_INTERVAL);
931
+ continue;
932
+ }
933
+ // CI passed but not mergeable (needs approval, merge checks, etc.)
934
+ if (prStatus.ciStatus === 'passed' && !prStatus.mergeable) {
935
+ if (lastSeenCIStatus !== 'passed-not-mergeable') {
936
+ logger.info(`[${task.id}] CI passed but not mergeable — waiting for approval or checks`);
937
+ lastSeenCIStatus = 'passed-not-mergeable';
938
+ }
939
+ await sleep(PR_POLL_INTERVAL);
940
+ continue;
941
+ }
942
+ // CI failed — delegate to implementing agent to fix
943
+ if (prStatus.ciStatus === 'failed') {
944
+ // Avoid re-fixing if we just pushed and the old pipeline result is stale
945
+ if (lastSeenCIStatus === 'fix-pushed') {
946
+ // We just pushed a fix — wait for new pipeline to start
947
+ logger.info(`[${task.id}] Waiting for new CI pipeline after fix push...`);
948
+ lastSeenCIStatus = 'pending-after-fix';
949
+ await sleep(PR_POLL_INTERVAL * 2); // Extra wait for new pipeline
950
+ continue;
951
+ }
952
+ if (pipeline.ciFixes >= MAX_CI_FIXES) {
953
+ logger.error(`[${task.id}] CI fix limit (${MAX_CI_FIXES}) reached — giving up`);
954
+ return false;
955
+ }
916
956
  pipeline.ciFixes++;
917
- logger.warn(`[${task.id}] CI failed — fix attempt ${pipeline.ciFixes}/${MAX_CI_FIXES}`);
957
+ logger.warn(`[${task.id}] CI failed — delegating fix to agent (attempt ${pipeline.ciFixes}/${MAX_CI_FIXES})`);
918
958
  const logs = fetchFailureLogs(branch, platform === 'github' ? 'github' : 'gitlab', projectDir);
919
- if (logs) {
920
- const fixResult = await spawnAgent(pool, pipeline.workerId, {
921
- agent: pipeline.assignedAgent ?? undefined,
922
- cwd: worktreePath,
923
- prompt: buildCIFixPrompt({ task, worktreePath, projectDir }, logs),
924
- model: getAgentModel(pipeline.assignedAgent, agents, task),
925
- }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
926
- if (fixResult.success) {
927
- commitInWorktree(worktreePath, `fix: CI failure for ${task.title}`);
959
+ const fixResult = await spawnAgent(pool, pipeline.workerId, {
960
+ agent: pipeline.assignedAgent ?? undefined,
961
+ cwd: worktreePath,
962
+ prompt: buildCIFixPrompt({ task, worktreePath, projectDir }, logs ?? 'No logs available — check the CI pipeline manually'),
963
+ model: getAgentModel(pipeline.assignedAgent, agents, task),
964
+ }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
965
+ if (fixResult.success) {
966
+ const sha = commitInWorktree(worktreePath, `fix: CI failure for ${task.title}`);
967
+ if (sha) {
928
968
  forcePushWorktree(worktreePath);
969
+ lastSeenCIStatus = 'fix-pushed';
970
+ logger.info(`[${task.id}] Fix pushed — waiting for new CI pipeline`);
971
+ await sleep(PR_POLL_INTERVAL * 2); // Wait for new pipeline to start
929
972
  continue;
930
973
  }
931
974
  }
932
- if (pipeline.ciFixes >= MAX_CI_FIXES) {
933
- logger.error(`[${task.id}] CI fix limit (${MAX_CI_FIXES}) reached`);
934
- return false;
935
- }
975
+ // Fix didn't produce changes or failed — wait and retry
976
+ await sleep(PR_POLL_INTERVAL);
977
+ continue;
936
978
  }
937
979
  // Unresolved PR comments — spawn agent to address
938
980
  const comments = getPRComments(projectDir, platform, prStatus.number);
939
981
  const unresolved = comments.filter(c => !c.resolved);
940
982
  if (unresolved.length > 0) {
941
- logger.info(`[${task.id}] ${unresolved.length} unresolved PR comments — addressing`);
983
+ logger.info(`[${task.id}] ${unresolved.length} unresolved PR comments — delegating to agent`);
942
984
  const commentText = unresolved
943
985
  .map(c => `${c.path ?? 'general'}${c.line ? `:${c.line}` : ''} — ${c.author}: ${c.body}`)
944
986
  .join('\n\n');
@@ -949,25 +991,13 @@ async function pollAndMergePR(task, pipeline, branch, platform, projectDir, work
949
991
  model: getAgentModel(pipeline.assignedAgent, agents, task),
950
992
  }, state, task.id, logger, onMessage, onSpawnStart, onSpawnEnd);
951
993
  if (commentResult.success) {
952
- commitInWorktree(worktreePath, `fix: address PR review comments`);
953
- forcePushWorktree(worktreePath);
954
- appendEvent(projectDir, createEvent('pr_comment_resolved', { taskId: task.id, detail: `${unresolved.length} comments` }));
955
- continue;
994
+ const sha = commitInWorktree(worktreePath, 'fix: address PR review comments');
995
+ if (sha) {
996
+ forcePushWorktree(worktreePath);
997
+ lastSeenCIStatus = 'fix-pushed';
998
+ appendEvent(projectDir, createEvent('pr_comment_resolved', { taskId: task.id, detail: `${unresolved.length} comments` }));
999
+ }
956
1000
  }
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
1001
  await sleep(PR_POLL_INTERVAL);
972
1002
  continue;
973
1003
  }
@@ -290,8 +290,8 @@ export class TUI {
290
290
  return '';
291
291
  const cur = this.state.agents[this.state.agents.length - 1];
292
292
  const col = ANSI_COLORS[agentColor(cur)] || '';
293
- const name = cur.length > 14 ? cur.slice(0, 14) : cur;
294
- return `${col}${name.padEnd(15)}${RESET}`;
293
+ const name = cur.length > 24 ? cur.slice(0, 24) : cur;
294
+ return `${col}${name.padEnd(25)}${RESET}`;
295
295
  }
296
296
  // ─── Public API ───
297
297
  banner() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-claude-workspace",
3
- "version": "2.3.13",
3
+ "version": "2.3.15",
4
4
  "author": "",
5
5
  "repository": {
6
6
  "type": "git",