feat: enhance worktree management and UI integration

- Refactored BoardView and WorktreeSelector components for improved readability and maintainability, including consistent formatting and structure.
- Updated feature handling to ensure correct worktree assignment and reset logic when worktrees are deleted, enhancing user experience.
- Enhanced KanbanCard to display priority badges with improved styling and layout.
- Removed deprecated revert feature logic from the server and client, streamlining the codebase.
- Introduced new tests for feature lifecycle and worktree integration, ensuring robust functionality and error handling.
This commit is contained in:
Cody Seibert
2025-12-16 21:49:33 -05:00
parent f9ec7222f2
commit 58d6ae02a5
20 changed files with 2316 additions and 504 deletions

View File

@@ -158,7 +158,10 @@ export interface SpecRegenerationAPI {
analyzeProject?: boolean,
maxFeatures?: number
) => Promise<{ success: boolean; error?: string }>;
generateFeatures: (projectPath: string, maxFeatures?: number) => Promise<{
generateFeatures: (
projectPath: string,
maxFeatures?: number
) => Promise<{
success: boolean;
error?: string;
}>;
@@ -321,7 +324,11 @@ export interface ElectronAPI {
features?: FeaturesAPI;
runningAgents?: RunningAgentsAPI;
enhancePrompt?: {
enhance: (originalText: string, enhancementMode: string, model?: string) => Promise<{
enhance: (
originalText: string,
enhancementMode: string,
model?: string
) => Promise<{
success: boolean;
enhancedText?: string;
error?: string;
@@ -1042,11 +1049,6 @@ function createMockSetupAPI(): SetupAPI {
// Mock Worktree API implementation
function createMockWorktreeAPI(): WorktreeAPI {
return {
revertFeature: async (projectPath: string, featureId: string) => {
console.log("[Mock] Reverting feature:", { projectPath, featureId });
return { success: true, removedPath: `/mock/worktree/${featureId}` };
},
mergeFeature: async (
projectPath: string,
featureId: string,
@@ -1093,17 +1095,36 @@ function createMockWorktreeAPI(): WorktreeAPI {
},
listAll: async (projectPath: string, includeDetails?: boolean) => {
console.log("[Mock] Listing all worktrees:", { projectPath, includeDetails });
console.log("[Mock] Listing all worktrees:", {
projectPath,
includeDetails,
});
return {
success: true,
worktrees: [
{ path: projectPath, branch: "main", isMain: true, isCurrent: true, hasWorktree: true, hasChanges: false, changedFilesCount: 0 },
{
path: projectPath,
branch: "main",
isMain: true,
isCurrent: true,
hasWorktree: true,
hasChanges: false,
changedFilesCount: 0,
},
],
};
},
create: async (projectPath: string, branchName: string, baseBranch?: string) => {
console.log("[Mock] Creating worktree:", { projectPath, branchName, baseBranch });
create: async (
projectPath: string,
branchName: string,
baseBranch?: string
) => {
console.log("[Mock] Creating worktree:", {
projectPath,
branchName,
baseBranch,
});
return {
success: true,
worktree: {
@@ -1114,8 +1135,16 @@ function createMockWorktreeAPI(): WorktreeAPI {
};
},
delete: async (projectPath: string, worktreePath: string, deleteBranch?: boolean) => {
console.log("[Mock] Deleting worktree:", { projectPath, worktreePath, deleteBranch });
delete: async (
projectPath: string,
worktreePath: string,
deleteBranch?: boolean
) => {
console.log("[Mock] Deleting worktree:", {
projectPath,
worktreePath,
deleteBranch,
});
return {
success: true,
deleted: {
@@ -1208,7 +1237,10 @@ function createMockWorktreeAPI(): WorktreeAPI {
},
checkoutBranch: async (worktreePath: string, branchName: string) => {
console.log("[Mock] Creating and checking out branch:", { worktreePath, branchName });
console.log("[Mock] Creating and checking out branch:", {
worktreePath,
branchName,
});
return {
success: true,
result: {
@@ -1281,18 +1313,6 @@ function createMockWorktreeAPI(): WorktreeAPI {
};
},
activate: async (projectPath: string, worktreePath: string | null) => {
console.log("[Mock] Activating worktree:", { projectPath, worktreePath });
return {
success: true,
result: {
previousBranch: "main",
currentBranch: worktreePath ? "feature-branch" : "main",
message: worktreePath ? "Switched to worktree branch" : "Switched to main",
},
};
},
startDevServer: async (projectPath: string, worktreePath: string) => {
console.log("[Mock] Starting dev server:", { projectPath, worktreePath });
return {
@@ -1465,7 +1485,11 @@ function createMockAutoModeAPI(): AutoModeAPI {
return { success: true, passes: true };
},
resumeFeature: async (projectPath: string, featureId: string, useWorktrees?: boolean) => {
resumeFeature: async (
projectPath: string,
featureId: string,
useWorktrees?: boolean
) => {
if (mockRunningFeatures.has(featureId)) {
return {
success: false,
@@ -1629,8 +1653,16 @@ function createMockAutoModeAPI(): AutoModeAPI {
return { success: true };
},
commitFeature: async (projectPath: string, featureId: string, worktreePath?: string) => {
console.log("[Mock] Committing feature:", { projectPath, featureId, worktreePath });
commitFeature: async (
projectPath: string,
featureId: string,
worktreePath?: string
) => {
console.log("[Mock] Committing feature:", {
projectPath,
featureId,
worktreePath,
});
// Simulate commit operation
emitAutoModeEvent({

View File

@@ -468,7 +468,9 @@ export class HttpApiClient implements ElectronAPI {
isLinux: boolean;
}> => this.get("/api/setup/platform"),
verifyClaudeAuth: (authMethod?: "cli" | "api_key"): Promise<{
verifyClaudeAuth: (
authMethod?: "cli" | "api_key"
): Promise<{
success: boolean;
authenticated: boolean;
error?: string;
@@ -536,8 +538,16 @@ export class HttpApiClient implements ElectronAPI {
}),
verifyFeature: (projectPath: string, featureId: string) =>
this.post("/api/auto-mode/verify-feature", { projectPath, featureId }),
resumeFeature: (projectPath: string, featureId: string, useWorktrees?: boolean) =>
this.post("/api/auto-mode/resume-feature", { projectPath, featureId, useWorktrees }),
resumeFeature: (
projectPath: string,
featureId: string,
useWorktrees?: boolean
) =>
this.post("/api/auto-mode/resume-feature", {
projectPath,
featureId,
useWorktrees,
}),
contextExists: (projectPath: string, featureId: string) =>
this.post("/api/auto-mode/context-exists", { projectPath, featureId }),
analyzeProject: (projectPath: string) =>
@@ -556,8 +566,16 @@ export class HttpApiClient implements ElectronAPI {
imagePaths,
worktreePath,
}),
commitFeature: (projectPath: string, featureId: string, worktreePath?: string) =>
this.post("/api/auto-mode/commit-feature", { projectPath, featureId, worktreePath }),
commitFeature: (
projectPath: string,
featureId: string,
worktreePath?: string
) =>
this.post("/api/auto-mode/commit-feature", {
projectPath,
featureId,
worktreePath,
}),
onEvent: (callback: (event: AutoModeEvent) => void) => {
return this.subscribeToEvent(
"auto-mode:event",
@@ -582,8 +600,6 @@ export class HttpApiClient implements ElectronAPI {
// Worktree API
worktree: WorktreeAPI = {
revertFeature: (projectPath: string, featureId: string) =>
this.post("/api/worktree/revert", { projectPath, featureId }),
mergeFeature: (projectPath: string, featureId: string, options?: object) =>
this.post("/api/worktree/merge", { projectPath, featureId, options }),
getInfo: (projectPath: string, featureId: string) =>
@@ -595,9 +611,21 @@ export class HttpApiClient implements ElectronAPI {
listAll: (projectPath: string, includeDetails?: boolean) =>
this.post("/api/worktree/list", { projectPath, includeDetails }),
create: (projectPath: string, branchName: string, baseBranch?: string) =>
this.post("/api/worktree/create", { projectPath, branchName, baseBranch }),
delete: (projectPath: string, worktreePath: string, deleteBranch?: boolean) =>
this.post("/api/worktree/delete", { projectPath, worktreePath, deleteBranch }),
this.post("/api/worktree/create", {
projectPath,
branchName,
baseBranch,
}),
delete: (
projectPath: string,
worktreePath: string,
deleteBranch?: boolean
) =>
this.post("/api/worktree/delete", {
projectPath,
worktreePath,
deleteBranch,
}),
commit: (worktreePath: string, message: string) =>
this.post("/api/worktree/commit", { worktreePath, message }),
push: (worktreePath: string, force?: boolean) =>
@@ -622,18 +650,14 @@ export class HttpApiClient implements ElectronAPI {
this.post("/api/worktree/switch-branch", { worktreePath, branchName }),
openInEditor: (worktreePath: string) =>
this.post("/api/worktree/open-in-editor", { worktreePath }),
getDefaultEditor: () =>
this.get("/api/worktree/default-editor"),
getDefaultEditor: () => this.get("/api/worktree/default-editor"),
initGit: (projectPath: string) =>
this.post("/api/worktree/init-git", { projectPath }),
activate: (projectPath: string, worktreePath: string | null) =>
this.post("/api/worktree/activate", { projectPath, worktreePath }),
startDevServer: (projectPath: string, worktreePath: string) =>
this.post("/api/worktree/start-dev", { projectPath, worktreePath }),
stopDevServer: (worktreePath: string) =>
this.post("/api/worktree/stop-dev", { worktreePath }),
listDevServers: () =>
this.post("/api/worktree/list-dev-servers", {}),
listDevServers: () => this.post("/api/worktree/list-dev-servers", {}),
};
// Git API
@@ -689,7 +713,10 @@ export class HttpApiClient implements ElectronAPI {
maxFeatures,
}),
generateFeatures: (projectPath: string, maxFeatures?: number) =>
this.post("/api/spec-regeneration/generate-features", { projectPath, maxFeatures }),
this.post("/api/spec-regeneration/generate-features", {
projectPath,
maxFeatures,
}),
stop: () => this.post("/api/spec-regeneration/stop"),
status: () => this.get("/api/spec-regeneration/status"),
onEvent: (callback: (event: SpecRegenerationEvent) => void) => {