Merge origin/main into refactor/frontend

Resolved conflict in apps/ui/tests/worktree-integration.spec.ts:
- Kept assertion verifying worktreePath is undefined (consistent with pattern)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alec Koifman
2025-12-19 10:17:35 -05:00
17 changed files with 442 additions and 186 deletions

View File

@@ -17,6 +17,9 @@ const logger = createLogger("Worktree");
const execAsync = promisify(exec);
const featureLoader = new FeatureLoader();
export const AUTOMAKER_INITIAL_COMMIT_MESSAGE =
"chore: automaker initial commit";
/**
* Normalize path separators to forward slashes for cross-platform consistency.
* This ensures paths from `path.join()` (backslashes on Windows) match paths
@@ -77,3 +80,30 @@ export function logWorktreeError(
// Re-export shared utilities
export { getErrorMessageShared as getErrorMessage };
export const logError = createLogError(logger);
/**
* Ensure the repository has at least one commit so git commands that rely on HEAD work.
* Returns true if an empty commit was created, false if the repo already had commits.
*/
export async function ensureInitialCommit(repoPath: string): Promise<boolean> {
try {
await execAsync("git rev-parse --verify HEAD", { cwd: repoPath });
return false;
} catch {
try {
await execAsync(
`git commit --allow-empty -m "${AUTOMAKER_INITIAL_COMMIT_MESSAGE}"`,
{ cwd: repoPath }
);
logger.info(
`[Worktree] Created initial empty commit to enable worktrees in ${repoPath}`
);
return true;
} catch (error) {
const reason = getErrorMessageShared(error);
throw new Error(
`Failed to create initial git commit. Please commit manually and retry. ${reason}`
);
}
}
}

View File

@@ -12,7 +12,13 @@ import { exec } from "child_process";
import { promisify } from "util";
import path from "path";
import { mkdir } from "fs/promises";
import { isGitRepo, getErrorMessage, logError, normalizePath } from "../common.js";
import {
isGitRepo,
getErrorMessage,
logError,
normalizePath,
ensureInitialCommit,
} from "../common.js";
import { trackBranch } from "./branch-tracking.js";
const execAsync = promisify(exec);
@@ -93,6 +99,9 @@ export function createCreateHandler() {
return;
}
// Ensure the repository has at least one commit so worktree commands referencing HEAD succeed
await ensureInitialCommit(projectPath);
// First, check if git already has a worktree for this branch (anywhere)
const existingWorktree = await findExistingWorktreeForBranch(projectPath, branchName);
if (existingWorktree) {