Merge branch 'v0.9.0rc' into remove-sandbox-as-it-is-broken

This commit is contained in:
webdevcody
2026-01-07 15:01:31 -05:00
115 changed files with 8734 additions and 401 deletions

View File

@@ -13,8 +13,10 @@ import { toast } from 'sonner';
export function ApiKeysSection() {
const { apiKeys, setApiKeys } = useAppStore();
const { claudeAuthStatus, setClaudeAuthStatus } = useSetupStore();
const { claudeAuthStatus, setClaudeAuthStatus, codexAuthStatus, setCodexAuthStatus } =
useSetupStore();
const [isDeletingAnthropicKey, setIsDeletingAnthropicKey] = useState(false);
const [isDeletingOpenaiKey, setIsDeletingOpenaiKey] = useState(false);
const { providerConfigParams, handleSave, saved } = useApiKeyManagement();
@@ -49,6 +51,34 @@ export function ApiKeysSection() {
}
}, [apiKeys, setApiKeys, claudeAuthStatus, setClaudeAuthStatus]);
// Delete OpenAI API key
const deleteOpenaiKey = useCallback(async () => {
setIsDeletingOpenaiKey(true);
try {
const api = getElectronAPI();
if (!api.setup?.deleteApiKey) {
toast.error('Delete API not available');
return;
}
const result = await api.setup.deleteApiKey('openai');
if (result.success) {
setApiKeys({ ...apiKeys, openai: '' });
setCodexAuthStatus({
authenticated: false,
method: 'none',
});
toast.success('OpenAI API key deleted');
} else {
toast.error(result.error || 'Failed to delete API key');
}
} catch (error) {
toast.error('Failed to delete API key');
} finally {
setIsDeletingOpenaiKey(false);
}
}, [apiKeys, setApiKeys, setCodexAuthStatus]);
return (
<div
className={cn(
@@ -119,6 +149,23 @@ export function ApiKeysSection() {
Delete Anthropic Key
</Button>
)}
{apiKeys.openai && (
<Button
onClick={deleteOpenaiKey}
disabled={isDeletingOpenaiKey}
variant="outline"
className="h-10 border-red-500/30 text-red-500 hover:bg-red-500/10 hover:border-red-500/50"
data-testid="delete-openai-key"
>
{isDeletingOpenaiKey ? (
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
) : (
<Trash2 className="w-4 h-4 mr-2" />
)}
Delete OpenAI Key
</Button>
)}
</div>
</div>
</div>

View File

@@ -1,3 +1,4 @@
// @ts-nocheck
import { useState, useEffect } from 'react';
import { createLogger } from '@automaker/utils/logger';
import { useAppStore } from '@/store/app-store';
@@ -14,6 +15,7 @@ interface TestResult {
interface ApiKeyStatus {
hasAnthropicKey: boolean;
hasGoogleKey: boolean;
hasOpenaiKey: boolean;
}
/**
@@ -26,16 +28,20 @@ export function useApiKeyManagement() {
// API key values
const [anthropicKey, setAnthropicKey] = useState(apiKeys.anthropic);
const [googleKey, setGoogleKey] = useState(apiKeys.google);
const [openaiKey, setOpenaiKey] = useState(apiKeys.openai);
// Visibility toggles
const [showAnthropicKey, setShowAnthropicKey] = useState(false);
const [showGoogleKey, setShowGoogleKey] = useState(false);
const [showOpenaiKey, setShowOpenaiKey] = useState(false);
// Test connection states
const [testingConnection, setTestingConnection] = useState(false);
const [testResult, setTestResult] = useState<TestResult | null>(null);
const [testingGeminiConnection, setTestingGeminiConnection] = useState(false);
const [geminiTestResult, setGeminiTestResult] = useState<TestResult | null>(null);
const [testingOpenaiConnection, setTestingOpenaiConnection] = useState(false);
const [openaiTestResult, setOpenaiTestResult] = useState<TestResult | null>(null);
// API key status from environment
const [apiKeyStatus, setApiKeyStatus] = useState<ApiKeyStatus | null>(null);
@@ -47,6 +53,7 @@ export function useApiKeyManagement() {
useEffect(() => {
setAnthropicKey(apiKeys.anthropic);
setGoogleKey(apiKeys.google);
setOpenaiKey(apiKeys.openai);
}, [apiKeys]);
// Check API key status from environment on mount
@@ -60,6 +67,7 @@ export function useApiKeyManagement() {
setApiKeyStatus({
hasAnthropicKey: status.hasAnthropicKey,
hasGoogleKey: status.hasGoogleKey,
hasOpenaiKey: status.hasOpenaiKey,
});
}
} catch (error) {
@@ -135,11 +143,42 @@ export function useApiKeyManagement() {
setTestingGeminiConnection(false);
};
// Test OpenAI/Codex connection
const handleTestOpenaiConnection = async () => {
setTestingOpenaiConnection(true);
setOpenaiTestResult(null);
try {
const api = getElectronAPI();
const data = await api.setup.verifyCodexAuth('api_key', openaiKey);
if (data.success && data.authenticated) {
setOpenaiTestResult({
success: true,
message: 'Connection successful! Codex responded.',
});
} else {
setOpenaiTestResult({
success: false,
message: data.error || 'Failed to connect to OpenAI API.',
});
}
} catch {
setOpenaiTestResult({
success: false,
message: 'Network error. Please check your connection.',
});
} finally {
setTestingOpenaiConnection(false);
}
};
// Save API keys
const handleSave = () => {
setApiKeys({
anthropic: anthropicKey,
google: googleKey,
openai: openaiKey,
});
setSaved(true);
setTimeout(() => setSaved(false), 2000);
@@ -166,6 +205,15 @@ export function useApiKeyManagement() {
onTest: handleTestGeminiConnection,
result: geminiTestResult,
},
openai: {
value: openaiKey,
setValue: setOpenaiKey,
show: showOpenaiKey,
setShow: setShowOpenaiKey,
testing: testingOpenaiConnection,
onTest: handleTestOpenaiConnection,
result: openaiTestResult,
},
};
return {