Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 141 additions & 18 deletions apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,25 +184,80 @@ export async function initializeWorkspaceWorktree({
);
const hasRemote = await hasOriginRemote(mainRepoPath);

type LocalStartPointResult = {
ref: string;
fallbackBranch?: string;
} | null;

const resolveLocalStartPoint = async (
reason: string,
): Promise<string | null> => {
const originRef = `origin/${effectiveBaseBranch}`;
if (await refExistsLocally(mainRepoPath, originRef)) {
console.log(
`[workspace-init] ${reason}. Using local tracking ref: ${originRef}`,
);
return originRef;
checkOriginRefs: boolean,
): Promise<LocalStartPointResult> => {
// Try origin tracking ref first (only if remote exists)
if (checkOriginRefs) {
const originRef = `origin/${effectiveBaseBranch}`;
if (await refExistsLocally(mainRepoPath, originRef)) {
console.log(
`[workspace-init] ${reason}. Using local tracking ref: ${originRef}`,
);
return { ref: originRef };
}
}

// Try local branch
if (await refExistsLocally(mainRepoPath, effectiveBaseBranch)) {
console.log(
`[workspace-init] ${reason}. Using local branch: ${effectiveBaseBranch}`,
);
return effectiveBaseBranch;
return { ref: effectiveBaseBranch };
}

// Only try fallback branches if the base branch was auto-derived
if (baseBranchWasExplicit) {
console.log(
`[workspace-init] ${reason}. Base branch "${effectiveBaseBranch}" was explicitly set, not using fallback.`,
);
return null;
}

// Fallback: try common default branch names
const commonBranches = ["main", "master", "develop", "trunk"];
for (const branch of commonBranches) {
if (branch === effectiveBaseBranch) continue; // Already tried
// Only check origin refs if remote exists
if (checkOriginRefs) {
const fallbackOriginRef = `origin/${branch}`;
if (await refExistsLocally(mainRepoPath, fallbackOriginRef)) {
console.log(
`[workspace-init] ${reason}. Using fallback tracking ref: ${fallbackOriginRef}`,
);
return { ref: fallbackOriginRef, fallbackBranch: branch };
}
}
if (await refExistsLocally(mainRepoPath, branch)) {
console.log(
`[workspace-init] ${reason}. Using fallback local branch: ${branch}`,
);
return { ref: branch, fallbackBranch: branch };
}
}

return null;
};

// Helper to update baseBranch when fallback is used
const applyFallbackBranch = (fallbackBranch: string) => {
console.log(
`[workspace-init] Updating baseBranch from "${effectiveBaseBranch}" to "${fallbackBranch}" for workspace ${workspaceId}`,
);
effectiveBaseBranch = fallbackBranch;
localDb
.update(worktrees)
.set({ baseBranch: fallbackBranch })
.where(eq(worktrees.id, worktreeId))
.run();
};

let startPoint: string;
if (hasRemote) {
const branchCheck = await branchExistsOnRemote(
Expand All @@ -223,17 +278,31 @@ export async function initializeWorkspaceWorktree({
sanitizedError,
);

const localRef = await resolveLocalStartPoint("Remote unavailable");
if (!localRef) {
const localResult = await resolveLocalStartPoint(
"Remote unavailable",
true,
);
if (!localResult) {
manager.updateProgress(
workspaceId,
"failed",
"No local reference available",
`Cannot reach remote and no local ref for "${effectiveBaseBranch}" exists. Please check your network connection and try again.`,
baseBranchWasExplicit
? `Cannot reach remote and branch "${effectiveBaseBranch}" doesn't exist locally. Please check your network connection and try again.`
: `Cannot reach remote and no local ref for "${effectiveBaseBranch}" exists. Please check your network connection and try again.`,
);
return;
}
startPoint = localRef;
if (localResult.fallbackBranch) {
applyFallbackBranch(localResult.fallbackBranch);
manager.updateProgress(
workspaceId,
"verifying",
`Using "${localResult.fallbackBranch}" branch`,
`Branch "${baseBranch}" not found locally. Using "${localResult.fallbackBranch}" instead.`,
);
}
startPoint = localResult.ref;
} else if (branchCheck.status === "not_found") {
manager.updateProgress(
workspaceId,
Expand All @@ -246,17 +315,31 @@ export async function initializeWorkspaceWorktree({
startPoint = `origin/${effectiveBaseBranch}`;
}
} else {
const localRef = await resolveLocalStartPoint("No remote configured");
if (!localRef) {
const localResult = await resolveLocalStartPoint(
"No remote configured",
false,
);
if (!localResult) {
manager.updateProgress(
workspaceId,
"failed",
"No local reference available",
`No remote configured and no local ref for "${effectiveBaseBranch}" exists.`,
baseBranchWasExplicit
? `No remote configured and branch "${effectiveBaseBranch}" doesn't exist locally.`
: `No remote configured and no local ref for "${effectiveBaseBranch}" exists.`,
);
return;
}
startPoint = localRef;
if (localResult.fallbackBranch) {
applyFallbackBranch(localResult.fallbackBranch);
manager.updateProgress(
workspaceId,
"verifying",
`Using "${localResult.fallbackBranch}" branch`,
`Branch "${baseBranch}" not found locally. Using "${localResult.fallbackBranch}" instead.`,
);
}
startPoint = localResult.ref;
}

if (manager.isCancellationRequested(workspaceId)) {
Expand All @@ -271,8 +354,48 @@ export async function initializeWorkspaceWorktree({
if (hasRemote) {
try {
await fetchDefaultBranch(mainRepoPath, effectiveBaseBranch);
} catch {
// Silently continue - branch exists on remote, just couldn't fetch
} catch (fetchError) {
// Fetch failed - verify local tracking ref exists before proceeding
const originRef = `origin/${effectiveBaseBranch}`;
if (!(await refExistsLocally(mainRepoPath, originRef))) {
console.warn(
`[workspace-init] Fetch failed and local ref "${originRef}" doesn't exist. Attempting local fallback.`,
);
const localResult = await resolveLocalStartPoint(
"Fetch failed and remote tracking ref unavailable",
true,
);
if (!localResult) {
const sanitizedError = sanitizeGitError(
fetchError instanceof Error
? fetchError.message
: String(fetchError),
);
manager.updateProgress(
workspaceId,
"failed",
"Cannot fetch branch",
baseBranchWasExplicit
? `Failed to fetch "${effectiveBaseBranch}" and it doesn't exist locally. ` +
`Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` +
`Error: ${sanitizedError}`
: `Failed to fetch "${effectiveBaseBranch}" and no local reference exists. ` +
`Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` +
`Error: ${sanitizedError}`,
);
return;
}
if (localResult.fallbackBranch) {
applyFallbackBranch(localResult.fallbackBranch);
manager.updateProgress(
workspaceId,
"fetching",
`Using "${localResult.fallbackBranch}" branch`,
`Could not fetch "${baseBranch}". Using local "${localResult.fallbackBranch}" branch instead.`,
);
}
startPoint = localResult.ref;
}
}
Comment on lines +357 to 399
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Silent continuation when fetch fails but local ref exists.

When fetchDefaultBranch fails but originRef exists locally, the code silently continues using the potentially stale local ref. The user sees "Fetching latest changes..." but isn't informed that fetch failed and they're working from cached data.

Consider adding a progress message to warn users, similar to the fallback paths:

🛠️ Suggested improvement
 } catch (fetchError) {
     // Fetch failed - verify local tracking ref exists before proceeding
     const originRef = `origin/${effectiveBaseBranch}`;
     if (!(await refExistsLocally(mainRepoPath, originRef))) {
         // ... existing fallback logic
+    } else {
+        const sanitizedError = sanitizeGitError(
+            fetchError instanceof Error ? fetchError.message : String(fetchError),
+        );
+        console.warn(
+            `[workspace-init] Fetch failed but local ref "${originRef}" exists. Proceeding with local ref. Error: ${sanitizedError}`,
+        );
+        manager.updateProgress(
+            workspaceId,
+            "fetching",
+            "Using cached reference",
+            `Could not fetch latest changes. Using local "${effectiveBaseBranch}" reference.`,
+        );
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (fetchError) {
// Fetch failed - verify local tracking ref exists before proceeding
const originRef = `origin/${effectiveBaseBranch}`;
if (!(await refExistsLocally(mainRepoPath, originRef))) {
console.warn(
`[workspace-init] Fetch failed and local ref "${originRef}" doesn't exist. Attempting local fallback.`,
);
const localResult = await resolveLocalStartPoint(
"Fetch failed and remote tracking ref unavailable",
true,
);
if (!localResult) {
const sanitizedError = sanitizeGitError(
fetchError instanceof Error
? fetchError.message
: String(fetchError),
);
manager.updateProgress(
workspaceId,
"failed",
"Cannot fetch branch",
baseBranchWasExplicit
? `Failed to fetch "${effectiveBaseBranch}" and it doesn't exist locally. ` +
`Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` +
`Error: ${sanitizedError}`
: `Failed to fetch "${effectiveBaseBranch}" and no local reference exists. ` +
`Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` +
`Error: ${sanitizedError}`,
);
return;
}
if (localResult.fallbackBranch) {
applyFallbackBranch(localResult.fallbackBranch);
manager.updateProgress(
workspaceId,
"fetching",
`Using "${localResult.fallbackBranch}" branch`,
`Could not fetch "${baseBranch}". Using local "${localResult.fallbackBranch}" branch instead.`,
);
}
startPoint = localResult.ref;
}
}
} catch (fetchError) {
// Fetch failed - verify local tracking ref exists before proceeding
const originRef = `origin/${effectiveBaseBranch}`;
if (!(await refExistsLocally(mainRepoPath, originRef))) {
console.warn(
`[workspace-init] Fetch failed and local ref "${originRef}" doesn't exist. Attempting local fallback.`,
);
const localResult = await resolveLocalStartPoint(
"Fetch failed and remote tracking ref unavailable",
true,
);
if (!localResult) {
const sanitizedError = sanitizeGitError(
fetchError instanceof Error
? fetchError.message
: String(fetchError),
);
manager.updateProgress(
workspaceId,
"failed",
"Cannot fetch branch",
baseBranchWasExplicit
? `Failed to fetch "${effectiveBaseBranch}" and it doesn't exist locally. ` +
`Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` +
`Error: ${sanitizedError}`
: `Failed to fetch "${effectiveBaseBranch}" and no local reference exists. ` +
`Please check your network connection or try running "git fetch origin ${effectiveBaseBranch}" manually. ` +
`Error: ${sanitizedError}`,
);
return;
}
if (localResult.fallbackBranch) {
applyFallbackBranch(localResult.fallbackBranch);
manager.updateProgress(
workspaceId,
"fetching",
`Using "${localResult.fallbackBranch}" branch`,
`Could not fetch "${baseBranch}". Using local "${localResult.fallbackBranch}" branch instead.`,
);
}
startPoint = localResult.ref;
} else {
const sanitizedError = sanitizeGitError(
fetchError instanceof Error ? fetchError.message : String(fetchError),
);
console.warn(
`[workspace-init] Fetch failed but local ref "${originRef}" exists. Proceeding with local ref. Error: ${sanitizedError}`,
);
manager.updateProgress(
workspaceId,
"fetching",
"Using cached reference",
`Could not fetch latest changes. Using local "${effectiveBaseBranch}" reference.`,
);
}
}
🤖 Prompt for AI Agents
In `@apps/desktop/src/lib/trpc/routers/workspaces/utils/workspace-init.ts` around
lines 357 - 399, When a fetch fails but the remote tracking ref exists locally
(the fetchError branch that checks refExistsLocally(originRef)), add a progress
update so the user is informed we couldn't fetch and are using the local cached
ref; specifically call manager.updateProgress(workspaceId, "warning" or
"fetching", a short title like `Using cached "${effectiveBaseBranch}"`, and a
message that includes a sanitized error from sanitizeGitError(fetchError) and
explains that the local origin/${effectiveBaseBranch} will be used until a
manual git fetch succeeds). Place this update inside the catch after confirming
refExistsLocally and before continuing to use startPoint (and before any
resolveLocalStartPoint logic) so callers of applyFallbackBranch/startPoint see
the warning.

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export function WorkspaceInitializingView({
</h2>
<p className="text-sm text-muted-foreground">{workspaceName}</p>
{progress?.error && (
<p className="text-xs text-destructive/80 mt-2 bg-destructive/5 rounded-md px-3 py-2">
<p className="text-xs text-destructive/80 mt-2 bg-destructive/5 rounded-md px-3 py-2 select-text cursor-text break-words">
{progress.error}
</p>
)}
Expand Down
Loading