mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 20:43:36 +00:00
Merge branch 'main' into fix-build
This commit is contained in:
@@ -768,16 +768,14 @@ ${Object.entries(projectAnalysis.filesByExtension)
|
||||
throw new Error("Features API not available");
|
||||
}
|
||||
|
||||
// Convert DetectedFeature to Feature by adding required id and status
|
||||
for (const detectedFeature of detectedFeatures) {
|
||||
const feature: Feature = {
|
||||
await api.features.create(currentProject.path, {
|
||||
id: crypto.randomUUID(),
|
||||
category: detectedFeature.category,
|
||||
description: detectedFeature.description,
|
||||
steps: detectedFeature.steps,
|
||||
status: "backlog" as const,
|
||||
};
|
||||
await api.features.create(currentProject.path, feature);
|
||||
status: "backlog",
|
||||
});
|
||||
}
|
||||
|
||||
setFeatureListGenerated(true);
|
||||
|
||||
@@ -325,6 +325,7 @@ export function InterviewView() {
|
||||
],
|
||||
skipTests: true,
|
||||
};
|
||||
|
||||
if (!api.features) {
|
||||
throw new Error("Features API not available");
|
||||
}
|
||||
|
||||
@@ -53,41 +53,22 @@ export function AuthenticationStatusDisplay({
|
||||
<>
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckCircle2 className="w-3 h-3 text-green-500 shrink-0" />
|
||||
<span className="text-muted-foreground">
|
||||
Method:{" "}
|
||||
<span className="font-mono text-foreground">
|
||||
{claudeAuthStatus.method === "oauth"
|
||||
? "OAuth Token"
|
||||
: claudeAuthStatus.method === "api_key"
|
||||
? "API Key"
|
||||
: "Unknown"}
|
||||
</span>
|
||||
<span className="text-green-400 font-medium">Authenticated</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-muted-foreground">
|
||||
<Info className="w-3 h-3 shrink-0" />
|
||||
<span>
|
||||
{claudeAuthStatus.method === "oauth_token_env"
|
||||
? "Using CLAUDE_CODE_OAUTH_TOKEN"
|
||||
: claudeAuthStatus.method === "oauth_token"
|
||||
? "Using stored OAuth token"
|
||||
: claudeAuthStatus.method === "api_key_env"
|
||||
? "Using ANTHROPIC_API_KEY"
|
||||
: claudeAuthStatus.method === "api_key"
|
||||
? "Using stored API key"
|
||||
: "Unknown method"}
|
||||
</span>
|
||||
</div>
|
||||
{claudeAuthStatus.oauthTokenValid && (
|
||||
<div className="flex items-center gap-2 text-green-400">
|
||||
<CheckCircle2 className="w-3 h-3 shrink-0" />
|
||||
<span>OAuth token configured</span>
|
||||
</div>
|
||||
)}
|
||||
{claudeAuthStatus.apiKeyValid && (
|
||||
<div className="flex items-center gap-2 text-green-400">
|
||||
<CheckCircle2 className="w-3 h-3 shrink-0" />
|
||||
<span>API key configured</span>
|
||||
</div>
|
||||
)}
|
||||
{apiKeyStatus?.hasAnthropicKey && (
|
||||
<div className="flex items-center gap-2 text-blue-400">
|
||||
<Info className="w-3 h-3 shrink-0" />
|
||||
<span>Environment variable detected</span>
|
||||
</div>
|
||||
)}
|
||||
{apiKeys.anthropic && (
|
||||
<div className="flex items-center gap-2 text-blue-400">
|
||||
<Info className="w-3 h-3 shrink-0" />
|
||||
<span>Manual API key in settings</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : apiKeyStatus?.hasAnthropicKey ? (
|
||||
<div className="flex items-center gap-2 text-blue-400">
|
||||
@@ -100,9 +81,9 @@ export function AuthenticationStatusDisplay({
|
||||
<span>Using manual API key from settings</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-1.5 text-muted-foreground py-0.5">
|
||||
<AlertCircle className="w-2.5 h-2.5 shrink-0" />
|
||||
<span className="text-xs">Not Setup</span>
|
||||
<div className="flex items-center gap-1.5 text-yellow-500 py-0.5">
|
||||
<AlertCircle className="w-3 h-3 shrink-0" />
|
||||
<span className="text-xs">Not configured</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -121,44 +102,21 @@ export function AuthenticationStatusDisplay({
|
||||
<>
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckCircle2 className="w-3 h-3 text-green-500 shrink-0" />
|
||||
<span className="text-muted-foreground">
|
||||
Method:{" "}
|
||||
<span className="font-mono text-foreground">
|
||||
{codexAuthStatus.method === "cli_verified" ||
|
||||
codexAuthStatus.method === "cli_tokens"
|
||||
? "CLI Login (OpenAI Account)"
|
||||
: codexAuthStatus.method === "api_key"
|
||||
? "API Key (Auth File)"
|
||||
: codexAuthStatus.method === "env"
|
||||
? "API Key (Environment)"
|
||||
: "Unknown"}
|
||||
</span>
|
||||
<span className="text-green-400 font-medium">Authenticated</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-muted-foreground">
|
||||
<Info className="w-3 h-3 shrink-0" />
|
||||
<span>
|
||||
{codexAuthStatus.method === "cli_verified" ||
|
||||
codexAuthStatus.method === "cli_tokens"
|
||||
? "Using CLI login (OpenAI account)"
|
||||
: codexAuthStatus.method === "api_key"
|
||||
? "Using stored API key"
|
||||
: codexAuthStatus.method === "env"
|
||||
? "Using OPENAI_API_KEY"
|
||||
: "Unknown method"}
|
||||
</span>
|
||||
</div>
|
||||
{codexAuthStatus.method === "cli_verified" ||
|
||||
codexAuthStatus.method === "cli_tokens" ? (
|
||||
<div className="flex items-center gap-2 text-green-400">
|
||||
<CheckCircle2 className="w-3 h-3 shrink-0" />
|
||||
<span>Account authenticated</span>
|
||||
</div>
|
||||
) : codexAuthStatus.apiKeyValid ? (
|
||||
<div className="flex items-center gap-2 text-green-400">
|
||||
<CheckCircle2 className="w-3 h-3 shrink-0" />
|
||||
<span>API key configured</span>
|
||||
</div>
|
||||
) : null}
|
||||
{apiKeyStatus?.hasOpenAIKey && (
|
||||
<div className="flex items-center gap-2 text-blue-400">
|
||||
<Info className="w-3 h-3 shrink-0" />
|
||||
<span>Environment variable detected</span>
|
||||
</div>
|
||||
)}
|
||||
{apiKeys.openai && (
|
||||
<div className="flex items-center gap-2 text-blue-400">
|
||||
<Info className="w-3 h-3 shrink-0" />
|
||||
<span>Manual API key in settings</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : apiKeyStatus?.hasOpenAIKey ? (
|
||||
<div className="flex items-center gap-2 text-blue-400">
|
||||
@@ -171,9 +129,9 @@ export function AuthenticationStatusDisplay({
|
||||
<span>Using manual API key from settings</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-1.5 text-muted-foreground py-0.5">
|
||||
<AlertCircle className="w-2.5 h-2.5 shrink-0" />
|
||||
<span className="text-xs">Not Setup</span>
|
||||
<div className="flex items-center gap-1.5 text-yellow-500 py-0.5">
|
||||
<AlertCircle className="w-3 h-3 shrink-0" />
|
||||
<span className="text-xs">Not configured</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -189,19 +147,31 @@ export function AuthenticationStatusDisplay({
|
||||
</div>
|
||||
<div className="space-y-1.5 text-xs min-h-12">
|
||||
{apiKeyStatus?.hasGoogleKey ? (
|
||||
<div className="flex items-center gap-2 text-blue-400">
|
||||
<Info className="w-3 h-3 shrink-0" />
|
||||
<span>Using environment variable (GOOGLE_API_KEY)</span>
|
||||
</div>
|
||||
<>
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckCircle2 className="w-3 h-3 text-green-500 shrink-0" />
|
||||
<span className="text-green-400 font-medium">Authenticated</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-muted-foreground">
|
||||
<Info className="w-3 h-3 shrink-0" />
|
||||
<span>Using GOOGLE_API_KEY</span>
|
||||
</div>
|
||||
</>
|
||||
) : apiKeys.google ? (
|
||||
<div className="flex items-center gap-2 text-blue-400">
|
||||
<Info className="w-3 h-3 shrink-0" />
|
||||
<span>Using manual API key from settings</span>
|
||||
</div>
|
||||
<>
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckCircle2 className="w-3 h-3 text-green-500 shrink-0" />
|
||||
<span className="text-green-400 font-medium">Authenticated</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-muted-foreground">
|
||||
<Info className="w-3 h-3 shrink-0" />
|
||||
<span>Using stored API key</span>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="flex items-center gap-1.5 text-muted-foreground py-0.5">
|
||||
<AlertCircle className="w-2.5 h-2.5 shrink-0" />
|
||||
<span className="text-xs">Not Setup</span>
|
||||
<div className="flex items-center gap-1.5 text-yellow-500 py-0.5">
|
||||
<AlertCircle className="w-3 h-3 shrink-0" />
|
||||
<span className="text-xs">Not configured</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -69,17 +69,20 @@ export function useCliStatus() {
|
||||
const result = await api.setup.getClaudeStatus();
|
||||
if (result.success && result.auth) {
|
||||
const auth = result.auth;
|
||||
// Validate method is one of the expected values, default to "none"
|
||||
const validMethods = ["oauth_token_env", "oauth_token", "api_key", "api_key_env", "none"] as const;
|
||||
type AuthMethod = typeof validMethods[number];
|
||||
const method: AuthMethod = validMethods.includes(auth.method as AuthMethod)
|
||||
? (auth.method as AuthMethod)
|
||||
: "none";
|
||||
const authStatus = {
|
||||
authenticated: auth.authenticated,
|
||||
method:
|
||||
auth.method === "oauth_token"
|
||||
? ("oauth" as const)
|
||||
: auth.method?.includes("api_key")
|
||||
? ("api_key" as const)
|
||||
: ("none" as const),
|
||||
method,
|
||||
hasCredentialsFile: auth.hasCredentialsFile ?? false,
|
||||
oauthTokenValid: auth.hasStoredOAuthToken,
|
||||
oauthTokenValid: auth.hasStoredOAuthToken || auth.hasEnvOAuthToken,
|
||||
apiKeyValid: auth.hasStoredApiKey || auth.hasEnvApiKey,
|
||||
hasEnvOAuthToken: auth.hasEnvOAuthToken,
|
||||
hasEnvApiKey: auth.hasEnvApiKey,
|
||||
};
|
||||
setClaudeAuthStatus(authStatus);
|
||||
}
|
||||
|
||||
@@ -250,21 +250,32 @@ function ClaudeSetupStep({
|
||||
setClaudeCliStatus(cliStatus);
|
||||
|
||||
if (result.auth) {
|
||||
// Validate method is one of the expected values, default to "none"
|
||||
const validMethods = [
|
||||
"oauth_token_env",
|
||||
"oauth_token",
|
||||
"api_key",
|
||||
"api_key_env",
|
||||
"none",
|
||||
] as const;
|
||||
type AuthMethod = (typeof validMethods)[number];
|
||||
const method: AuthMethod = validMethods.includes(
|
||||
result.auth.method as AuthMethod
|
||||
)
|
||||
? (result.auth.method as AuthMethod)
|
||||
: "none";
|
||||
const authStatus = {
|
||||
authenticated: result.auth.authenticated,
|
||||
method:
|
||||
result.auth.method === "oauth_token"
|
||||
? "oauth"
|
||||
: result.auth.method?.includes("api_key")
|
||||
? "api_key"
|
||||
: "none",
|
||||
method,
|
||||
hasCredentialsFile: false,
|
||||
oauthTokenValid: result.auth.hasStoredOAuthToken,
|
||||
oauthTokenValid:
|
||||
result.auth.hasStoredOAuthToken || result.auth.hasEnvOAuthToken,
|
||||
apiKeyValid:
|
||||
result.auth.hasStoredApiKey || result.auth.hasEnvApiKey,
|
||||
hasEnvOAuthToken: result.auth.hasEnvOAuthToken,
|
||||
hasEnvApiKey: result.auth.hasEnvApiKey,
|
||||
};
|
||||
console.log("[Claude Setup] Auth Status:", authStatus);
|
||||
setClaudeAuthStatus(authStatus as any);
|
||||
setClaudeAuthStatus(authStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -385,7 +396,7 @@ function ClaudeSetupStep({
|
||||
if (result.success) {
|
||||
setClaudeAuthStatus({
|
||||
authenticated: true,
|
||||
method: "oauth",
|
||||
method: "oauth_token",
|
||||
hasCredentialsFile: false,
|
||||
oauthTokenValid: true,
|
||||
});
|
||||
@@ -463,8 +474,16 @@ function ClaudeSetupStep({
|
||||
|
||||
const getAuthMethodLabel = () => {
|
||||
if (!isAuthenticated) return null;
|
||||
if (claudeAuthStatus?.method === "oauth") return "Subscription Token";
|
||||
if (apiKeys.anthropic || claudeAuthStatus?.method === "api_key")
|
||||
if (
|
||||
claudeAuthStatus?.method === "oauth_token_env" ||
|
||||
claudeAuthStatus?.method === "oauth_token"
|
||||
)
|
||||
return "Subscription Token";
|
||||
if (
|
||||
apiKeys.anthropic ||
|
||||
claudeAuthStatus?.method === "api_key" ||
|
||||
claudeAuthStatus?.method === "api_key_env"
|
||||
)
|
||||
return "API Key";
|
||||
return "Authenticated";
|
||||
};
|
||||
|
||||
@@ -41,8 +41,8 @@ export interface StatResult {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// Auto Mode types - Import from electron.d.ts to avoid duplication
|
||||
import type {
|
||||
// Re-export types from electron.d.ts for external use
|
||||
export type {
|
||||
AutoModeEvent,
|
||||
ModelDefinition,
|
||||
ProviderStatus,
|
||||
@@ -55,6 +55,15 @@ import type {
|
||||
FileStatus,
|
||||
} from "@/types/electron";
|
||||
|
||||
// Import types for internal use in this file
|
||||
import type {
|
||||
AutoModeEvent,
|
||||
WorktreeAPI,
|
||||
GitAPI,
|
||||
ModelDefinition,
|
||||
ProviderStatus,
|
||||
} from "@/types/electron";
|
||||
|
||||
// Feature type - Import from app-store
|
||||
import type { Feature } from "@/store/app-store";
|
||||
|
||||
@@ -101,7 +110,11 @@ export interface SuggestionsEvent {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export type SuggestionType = "features" | "refactoring" | "security" | "performance";
|
||||
export type SuggestionType =
|
||||
| "features"
|
||||
| "refactoring"
|
||||
| "security"
|
||||
| "performance";
|
||||
|
||||
export interface SuggestionsAPI {
|
||||
generate: (
|
||||
@@ -176,7 +189,9 @@ export interface AutoModeAPI {
|
||||
projectPath: string,
|
||||
maxConcurrency?: number
|
||||
) => Promise<{ success: boolean; error?: string }>;
|
||||
stop: (projectPath: string) => Promise<{ success: boolean; error?: string; runningFeatures?: number }>;
|
||||
stop: (
|
||||
projectPath: string
|
||||
) => Promise<{ success: boolean; error?: string; runningFeatures?: number }>;
|
||||
stopFeature: (
|
||||
featureId: string
|
||||
) => Promise<{ success: boolean; error?: string }>;
|
||||
@@ -231,7 +246,9 @@ export interface SaveImageResult {
|
||||
|
||||
export interface ElectronAPI {
|
||||
ping: () => Promise<string>;
|
||||
openExternalLink: (url: string) => Promise<{ success: boolean; error?: string }>;
|
||||
openExternalLink: (
|
||||
url: string
|
||||
) => Promise<{ success: boolean; error?: string }>;
|
||||
openDirectory: () => Promise<DialogResult>;
|
||||
openFile: (options?: object) => Promise<DialogResult>;
|
||||
readFile: (filePath: string) => Promise<FileResult>;
|
||||
@@ -308,17 +325,19 @@ export interface ElectronAPI {
|
||||
getClaudeStatus: () => Promise<{
|
||||
success: boolean;
|
||||
status?: string;
|
||||
installed?: boolean;
|
||||
method?: string;
|
||||
version?: string;
|
||||
path?: string;
|
||||
auth?: {
|
||||
authenticated: boolean;
|
||||
method: string;
|
||||
hasCredentialsFile: boolean;
|
||||
hasToken: boolean;
|
||||
hasCredentialsFile?: boolean;
|
||||
hasToken?: boolean;
|
||||
hasStoredOAuthToken?: boolean;
|
||||
hasStoredApiKey?: boolean;
|
||||
hasEnvApiKey?: boolean;
|
||||
hasEnvOAuthToken?: boolean;
|
||||
};
|
||||
error?: string;
|
||||
}>;
|
||||
@@ -1481,7 +1500,10 @@ let mockSuggestionsTimeout: NodeJS.Timeout | null = null;
|
||||
|
||||
function createMockSuggestionsAPI(): SuggestionsAPI {
|
||||
return {
|
||||
generate: async (projectPath: string, suggestionType: SuggestionType = "features") => {
|
||||
generate: async (
|
||||
projectPath: string,
|
||||
suggestionType: SuggestionType = "features"
|
||||
) => {
|
||||
if (mockSuggestionsRunning) {
|
||||
return {
|
||||
success: false,
|
||||
@@ -1490,7 +1512,9 @@ function createMockSuggestionsAPI(): SuggestionsAPI {
|
||||
}
|
||||
|
||||
mockSuggestionsRunning = true;
|
||||
console.log(`[Mock] Generating ${suggestionType} suggestions for: ${projectPath}`);
|
||||
console.log(
|
||||
`[Mock] Generating ${suggestionType} suggestions for: ${projectPath}`
|
||||
);
|
||||
|
||||
// Simulate async suggestion generation
|
||||
simulateSuggestionsGeneration(suggestionType);
|
||||
@@ -1529,7 +1553,9 @@ function emitSuggestionsEvent(event: SuggestionsEvent) {
|
||||
mockSuggestionsCallbacks.forEach((cb) => cb(event));
|
||||
}
|
||||
|
||||
async function simulateSuggestionsGeneration(suggestionType: SuggestionType = "features") {
|
||||
async function simulateSuggestionsGeneration(
|
||||
suggestionType: SuggestionType = "features"
|
||||
) {
|
||||
const typeLabels: Record<SuggestionType, string> = {
|
||||
features: "feature suggestions",
|
||||
refactoring: "refactoring opportunities",
|
||||
@@ -1588,7 +1614,8 @@ async function simulateSuggestionsGeneration(suggestionType: SuggestionType = "f
|
||||
{
|
||||
id: `suggestion-${Date.now()}-0`,
|
||||
category: "Code Smell",
|
||||
description: "Extract duplicate validation logic into reusable utility",
|
||||
description:
|
||||
"Extract duplicate validation logic into reusable utility",
|
||||
steps: [
|
||||
"Identify all files with similar validation patterns",
|
||||
"Create a validation utilities module",
|
||||
@@ -1601,7 +1628,8 @@ async function simulateSuggestionsGeneration(suggestionType: SuggestionType = "f
|
||||
{
|
||||
id: `suggestion-${Date.now()}-1`,
|
||||
category: "Complexity",
|
||||
description: "Break down large handleSubmit function into smaller functions",
|
||||
description:
|
||||
"Break down large handleSubmit function into smaller functions",
|
||||
steps: [
|
||||
"Identify the handleSubmit function in form components",
|
||||
"Extract validation logic into separate function",
|
||||
@@ -1609,7 +1637,8 @@ async function simulateSuggestionsGeneration(suggestionType: SuggestionType = "f
|
||||
"Extract success/error handling into separate functions",
|
||||
],
|
||||
priority: 2,
|
||||
reasoning: "Function is too long and handles multiple responsibilities",
|
||||
reasoning:
|
||||
"Function is too long and handles multiple responsibilities",
|
||||
},
|
||||
{
|
||||
id: `suggestion-${Date.now()}-2`,
|
||||
@@ -1728,7 +1757,8 @@ async function simulateSuggestionsGeneration(suggestionType: SuggestionType = "f
|
||||
"Add localStorage persistence for user preference",
|
||||
],
|
||||
priority: 1,
|
||||
reasoning: "Dark mode is a standard feature that improves accessibility and user comfort",
|
||||
reasoning:
|
||||
"Dark mode is a standard feature that improves accessibility and user comfort",
|
||||
},
|
||||
{
|
||||
id: `suggestion-${Date.now()}-1`,
|
||||
@@ -1753,7 +1783,8 @@ async function simulateSuggestionsGeneration(suggestionType: SuggestionType = "f
|
||||
"Add ARIA labels and roles where needed",
|
||||
],
|
||||
priority: 3,
|
||||
reasoning: "Improves accessibility for users who rely on keyboard navigation",
|
||||
reasoning:
|
||||
"Improves accessibility for users who rely on keyboard navigation",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -19,7 +19,10 @@ export interface ProjectInitResult {
|
||||
* Required files and directories in the .automaker directory
|
||||
* Note: app_spec.txt is NOT created automatically - user must set it up via the spec editor
|
||||
*/
|
||||
const REQUIRED_STRUCTURE = {
|
||||
const REQUIRED_STRUCTURE: {
|
||||
directories: string[];
|
||||
files: Record<string, string>;
|
||||
} = {
|
||||
directories: [
|
||||
".automaker",
|
||||
".automaker/context",
|
||||
|
||||
@@ -13,10 +13,12 @@ export interface CliStatus {
|
||||
// Claude Auth Status
|
||||
export interface ClaudeAuthStatus {
|
||||
authenticated: boolean;
|
||||
method: "oauth" | "api_key" | "none";
|
||||
hasCredentialsFile: boolean;
|
||||
method: "oauth_token_env" | "oauth_token" | "api_key" | "api_key_env" | "none";
|
||||
hasCredentialsFile?: boolean;
|
||||
oauthTokenValid?: boolean;
|
||||
apiKeyValid?: boolean;
|
||||
hasEnvOAuthToken?: boolean;
|
||||
hasEnvApiKey?: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user