Merge origin/main into feature/shared-packages

Resolved conflicts:
- list.ts: Keep @automaker/git-utils import, add worktree-metadata import
- feature-loader.ts: Use Feature type from @automaker/types
- automaker-paths.test.ts: Import from @automaker/platform
- kanban-card.tsx: Accept deletion (split into components/)
- subprocess.test.ts: Keep libs/platform location

Added missing exports to @automaker/platform:
- getGlobalSettingsPath, getCredentialsPath, getProjectSettingsPath, ensureDataDir

Added title and titleGenerating fields to @automaker/types Feature interface.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Kacper
2025-12-20 22:20:17 +01:00
108 changed files with 10834 additions and 3489 deletions

View File

@@ -203,6 +203,9 @@ export interface FeaturesAPI {
projectPath: string,
featureId: string
) => Promise<{ success: boolean; content?: string | null; error?: string }>;
generateTitle: (
description: string
) => Promise<{ success: boolean; title?: string; error?: string }>;
}
export interface AutoModeAPI {
@@ -505,7 +508,15 @@ const mockFileSystem: Record<string, string> = {};
// Check if we're in Electron (for UI indicators only)
export const isElectron = (): boolean => {
return typeof window !== "undefined" && window.isElectron === true;
if (typeof window === "undefined") {
return false;
}
if ((window as any).isElectron === true) {
return true;
}
return window.electronAPI?.isElectron === true;
};
// Check if backend server is available
@@ -1353,6 +1364,17 @@ function createMockWorktreeAPI(): WorktreeAPI {
},
};
},
getPRInfo: async (worktreePath: string, branchName: string) => {
console.log("[Mock] Getting PR info:", { worktreePath, branchName });
return {
success: true,
result: {
hasPR: false,
ghCliAvailable: false,
},
};
},
};
}
@@ -2595,6 +2617,14 @@ function createMockFeaturesAPI(): FeaturesAPI {
const content = mockFileSystem[agentOutputPath];
return { success: true, content: content || null };
},
generateTitle: async (description: string) => {
console.log("[Mock] Generating title for:", description.substring(0, 50));
// Mock title generation - just take first few words
const words = description.split(/\s+/).slice(0, 6).join(" ");
const title = words.length > 40 ? words.substring(0, 40) + "..." : words;
return { success: true, title: `Add ${title}` };
},
};
}

View File

@@ -512,6 +512,8 @@ export class HttpApiClient implements ElectronAPI {
this.post("/api/features/delete", { projectPath, featureId }),
getAgentOutput: (projectPath: string, featureId: string) =>
this.post("/api/features/agent-output", { projectPath, featureId }),
generateTitle: (description: string) =>
this.post("/api/features/generate-title", { description }),
};
// Auto Mode API
@@ -672,6 +674,8 @@ export class HttpApiClient implements ElectronAPI {
stopDevServer: (worktreePath: string) =>
this.post("/api/worktree/stop-dev", { worktreePath }),
listDevServers: () => this.post("/api/worktree/list-dev-servers", {}),
getPRInfo: (worktreePath: string, branchName: string) =>
this.post("/api/worktree/pr-info", { worktreePath, branchName }),
};
// Git API
@@ -833,6 +837,135 @@ export class HttpApiClient implements ElectronAPI {
this.post("/api/templates/clone", { repoUrl, projectName, parentDir }),
};
// Settings API - persistent file-based settings
settings = {
// Get settings status (check if migration needed)
getStatus: (): Promise<{
success: boolean;
hasGlobalSettings: boolean;
hasCredentials: boolean;
dataDir: string;
needsMigration: boolean;
}> => this.get("/api/settings/status"),
// Global settings
getGlobal: (): Promise<{
success: boolean;
settings?: {
version: number;
theme: string;
sidebarOpen: boolean;
chatHistoryOpen: boolean;
kanbanCardDetailLevel: string;
maxConcurrency: number;
defaultSkipTests: boolean;
enableDependencyBlocking: boolean;
useWorktrees: boolean;
showProfilesOnly: boolean;
defaultPlanningMode: string;
defaultRequirePlanApproval: boolean;
defaultAIProfileId: string | null;
muteDoneSound: boolean;
enhancementModel: string;
keyboardShortcuts: Record<string, string>;
aiProfiles: unknown[];
projects: unknown[];
trashedProjects: unknown[];
projectHistory: string[];
projectHistoryIndex: number;
lastProjectDir?: string;
recentFolders: string[];
worktreePanelCollapsed: boolean;
lastSelectedSessionByProject: Record<string, string>;
};
error?: string;
}> => this.get("/api/settings/global"),
updateGlobal: (updates: Record<string, unknown>): Promise<{
success: boolean;
settings?: Record<string, unknown>;
error?: string;
}> => this.put("/api/settings/global", updates),
// Credentials (masked for security)
getCredentials: (): Promise<{
success: boolean;
credentials?: {
anthropic: { configured: boolean; masked: string };
google: { configured: boolean; masked: string };
openai: { configured: boolean; masked: string };
};
error?: string;
}> => this.get("/api/settings/credentials"),
updateCredentials: (updates: {
apiKeys?: { anthropic?: string; google?: string; openai?: string };
}): Promise<{
success: boolean;
credentials?: {
anthropic: { configured: boolean; masked: string };
google: { configured: boolean; masked: string };
openai: { configured: boolean; masked: string };
};
error?: string;
}> => this.put("/api/settings/credentials", updates),
// Project settings
getProject: (projectPath: string): Promise<{
success: boolean;
settings?: {
version: number;
theme?: string;
useWorktrees?: boolean;
currentWorktree?: { path: string | null; branch: string };
worktrees?: Array<{
path: string;
branch: string;
isMain: boolean;
hasChanges?: boolean;
changedFilesCount?: number;
}>;
boardBackground?: {
imagePath: string | null;
imageVersion?: number;
cardOpacity: number;
columnOpacity: number;
columnBorderEnabled: boolean;
cardGlassmorphism: boolean;
cardBorderEnabled: boolean;
cardBorderOpacity: number;
hideScrollbar: boolean;
};
lastSelectedSessionId?: string;
};
error?: string;
}> => this.post("/api/settings/project", { projectPath }),
updateProject: (
projectPath: string,
updates: Record<string, unknown>
): Promise<{
success: boolean;
settings?: Record<string, unknown>;
error?: string;
}> => this.put("/api/settings/project", { projectPath, updates }),
// Migration from localStorage
migrate: (data: {
"automaker-storage"?: string;
"automaker-setup"?: string;
"worktree-panel-collapsed"?: string;
"file-browser-recent-folders"?: string;
"automaker:lastProjectDir"?: string;
}): Promise<{
success: boolean;
migratedGlobalSettings: boolean;
migratedCredentials: boolean;
migratedProjectCount: number;
errors: string[];
}> => this.post("/api/settings/migrate", { data }),
};
// Sessions API
sessions = {
list: (