Skip to content

Commit 5824589

Browse files
committed
feat: auto-retry workspace creation with new names on conflict
- Add retry logic in TaskQueue when worktree branch name already exists - Generate new random city names automatically (up to 5 retries) - Update session name dynamically to match new worktree name - Add name field to SessionUpdate interface - Improve user experience by avoiding manual name conflicts
1 parent a6946c4 commit 5824589

File tree

3 files changed

+58
-8
lines changed

3 files changed

+58
-8
lines changed

packages/core/src/types/session.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export interface Session {
3737
}
3838

3939
export interface SessionUpdate {
40+
name?: string;
4041
status?: Session['status'];
4142
statusMessage?: string;
4243
pid?: number;

packages/desktop/src/features/queue/TaskQueue.ts

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -247,14 +247,59 @@ export class TaskQueue {
247247
sessionManager.updateSessionStatus(session.id, 'initializing', 'Creating worktree…');
248248
sessionManager.emitSessionCreated(session);
249249

250-
const { worktreePath, baseCommit, baseBranch: actualBaseBranch } = await worktreeManager.createWorktree(
251-
targetProject.path,
252-
worktreeName,
253-
undefined,
254-
baseBranch,
255-
targetProject.worktree_folder || undefined,
256-
sessionId
257-
);
250+
// Try to create worktree, retry with new name if branch already exists
251+
let worktreePath: string;
252+
let baseCommit: string;
253+
let actualBaseBranch: string;
254+
let retryCount = 0;
255+
const maxRetries = 5;
256+
257+
while (retryCount < maxRetries) {
258+
try {
259+
const result = await worktreeManager.createWorktree(
260+
targetProject.path,
261+
worktreeName,
262+
undefined,
263+
baseBranch,
264+
targetProject.worktree_folder || undefined,
265+
sessionId
266+
);
267+
worktreePath = result.worktreePath;
268+
baseCommit = result.baseCommit;
269+
actualBaseBranch = result.baseBranch;
270+
break; // Success, exit retry loop
271+
} catch (error) {
272+
const errorMessage = error instanceof Error ? error.message : String(error);
273+
274+
// Check if this is a "branch already exists" error
275+
if (errorMessage.includes('already exists') && retryCount < maxRetries - 1) {
276+
console.log(`[TaskQueue] Worktree name '${worktreeName}' already exists, generating new name (retry ${retryCount + 1}/${maxRetries - 1})`);
277+
278+
// Generate a new name
279+
const newSessionName = this.options.worktreeNameGenerator.generateSessionName();
280+
const newWorktreeName = newSessionName.toLowerCase();
281+
282+
// Ensure uniqueness for both names
283+
const { sessionName: uniqueSessionName, worktreeName: uniqueWorktreeName } =
284+
await this.ensureUniqueNames(newSessionName, newWorktreeName, targetProject, index);
285+
sessionName = uniqueSessionName;
286+
worktreeName = uniqueWorktreeName;
287+
288+
// Update session with new name
289+
const newPlannedWorktreePath = join(plannedBaseDir, worktreeName);
290+
sessionManager.updateSession(session.id, {
291+
name: sessionName,
292+
worktreePath: newPlannedWorktreePath,
293+
worktreeName: worktreeName
294+
});
295+
296+
retryCount++;
297+
} else {
298+
// Not a "branch already exists" error, or max retries reached
299+
throw error;
300+
}
301+
}
302+
}
258303

259304
// Persist canonical worktree+base info once worktree is ready.
260305
sessionManager.updateSession(session.id, {

packages/desktop/src/features/session/SessionManager.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,10 @@ export class SessionManager extends EventEmitter {
685685

686686
const dbUpdate: UpdateSessionData = {};
687687

688+
if (update.name !== undefined) {
689+
dbUpdate.name = update.name;
690+
}
691+
688692
if (update.status !== undefined) {
689693
dbUpdate.status = this.mapSessionStatusToDbStatus(update.status);
690694
}

0 commit comments

Comments
 (0)