mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-04 09:13:08 +00:00
Added Authentication Status Settings to API Keys Tab in Settings
This commit is contained in:
3
.automaker/.gitignore
vendored
3
.automaker/.gitignore
vendored
@@ -6,3 +6,6 @@ agents-context/
|
|||||||
|
|
||||||
# Attached images - uploaded by users as feature context
|
# Attached images - uploaded by users as feature context
|
||||||
images/
|
images/
|
||||||
|
|
||||||
|
# Launch script - local development script
|
||||||
|
launch.sh
|
||||||
@@ -1,57 +1,3 @@
|
|||||||
---
|
|
||||||
name: Codex CLI OpenAI Model Support
|
|
||||||
overview: Extend the model support system to integrate OpenAI Codex CLI, enabling users to use OpenAI models (GPT-4o, o3, etc.) alongside existing Claude models. This includes CLI detection, model provider abstraction, execution wrapper, and UI updates.
|
|
||||||
todos:
|
|
||||||
- id: model-provider-abstraction
|
|
||||||
content: Create model provider abstraction layer with base interface and Claude/Codex implementations
|
|
||||||
status: pending
|
|
||||||
- id: codex-cli-detector
|
|
||||||
content: Implement Codex CLI detector service to check installation status and version
|
|
||||||
status: pending
|
|
||||||
- id: codex-executor
|
|
||||||
content: Create Codex CLI execution wrapper that spawns subprocess and parses JSON output
|
|
||||||
status: pending
|
|
||||||
- id: codex-config-manager
|
|
||||||
content: Implement Codex TOML configuration manager for model provider setup
|
|
||||||
status: pending
|
|
||||||
- id: model-registry
|
|
||||||
content: Create centralized model registry with provider mappings and metadata
|
|
||||||
status: pending
|
|
||||||
- id: update-feature-executor
|
|
||||||
content: Refactor feature-executor.js to use model provider abstraction instead of direct SDK calls
|
|
||||||
status: pending
|
|
||||||
- id: update-agent-service
|
|
||||||
content: Update agent-service.js to support configurable model selection via provider abstraction
|
|
||||||
status: pending
|
|
||||||
- id: message-converter
|
|
||||||
content: Create message format converter to translate Codex JSONL output to Claude SDK format
|
|
||||||
status: pending
|
|
||||||
- id: update-ui-types
|
|
||||||
content: Extend TypeScript types in app-store.ts to include OpenAI models and provider metadata
|
|
||||||
status: pending
|
|
||||||
- id: update-board-view
|
|
||||||
content: Expand model selection dropdown in board-view.tsx to include OpenAI models with provider grouping
|
|
||||||
status: pending
|
|
||||||
- id: update-settings-view
|
|
||||||
content: Add OpenAI API key input, Codex CLI status check, and test connection button to settings-view.tsx
|
|
||||||
status: pending
|
|
||||||
- id: openai-test-api
|
|
||||||
content: Create OpenAI API test endpoint at app/src/app/api/openai/test/route.ts
|
|
||||||
status: pending
|
|
||||||
- id: ipc-handlers
|
|
||||||
content: Add IPC handlers in main.js for model management (checkCodexCli, getAvailableModels, testOpenAI)
|
|
||||||
status: pending
|
|
||||||
- id: preload-api
|
|
||||||
content: Update preload.js and electron.d.ts to expose new IPC methods to renderer process
|
|
||||||
status: pending
|
|
||||||
- id: env-manager
|
|
||||||
content: Create environment variable manager for centralized API key and config handling
|
|
||||||
status: pending
|
|
||||||
- id: error-handling
|
|
||||||
content: Implement provider fallback logic and user-friendly error messages for missing CLI/API keys
|
|
||||||
status: pending
|
|
||||||
---
|
|
||||||
|
|
||||||
# Codex CLI OpenAI Model Support Implementation Plan
|
# Codex CLI OpenAI Model Support Implementation Plan
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|||||||
34
app/package-lock.json
generated
34
app/package-lock.json
generated
@@ -24,6 +24,7 @@
|
|||||||
"@tanstack/react-query": "^5.90.12",
|
"@tanstack/react-query": "^5.90.12",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
"lucide-react": "^0.556.0",
|
"lucide-react": "^0.556.0",
|
||||||
"next": "16.0.7",
|
"next": "16.0.7",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
@@ -4687,6 +4688,19 @@
|
|||||||
"electron-builder-squirrel-windows": "26.0.12"
|
"electron-builder-squirrel-windows": "26.0.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/app-builder-lib/node_modules/dotenv": {
|
||||||
|
"version": "16.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
||||||
|
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/app-builder-lib/node_modules/fs-extra": {
|
"node_modules/app-builder-lib/node_modules/fs-extra": {
|
||||||
"version": "10.1.0",
|
"version": "10.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
||||||
@@ -6308,10 +6322,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dotenv": {
|
"node_modules/dotenv": {
|
||||||
"version": "16.6.1",
|
"version": "17.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
||||||
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
|
||||||
"dev": true,
|
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
@@ -6336,6 +6349,19 @@
|
|||||||
"url": "https://dotenvx.com"
|
"url": "https://dotenvx.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dotenv-expand/node_modules/dotenv": {
|
||||||
|
"version": "16.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
|
||||||
|
"integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://dotenvx.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dunder-proto": {
|
"node_modules/dunder-proto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"@tanstack/react-query": "^5.90.12",
|
"@tanstack/react-query": "^5.90.12",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
"lucide-react": "^0.556.0",
|
"lucide-react": "^0.556.0",
|
||||||
"next": "16.0.7",
|
"next": "16.0.7",
|
||||||
"react": "19.2.0",
|
"react": "19.2.0",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import {
|
|||||||
TestTube,
|
TestTube,
|
||||||
Settings2,
|
Settings2,
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
|
Info,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { getElectronAPI } from "@/lib/electron";
|
import { getElectronAPI } from "@/lib/electron";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
@@ -50,6 +51,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
|
import { useSetupStore } from "@/store/setup-store";
|
||||||
|
|
||||||
// Navigation items for the side panel
|
// Navigation items for the side panel
|
||||||
const NAV_ITEMS = [
|
const NAV_ITEMS = [
|
||||||
@@ -137,7 +139,15 @@ export function SettingsView() {
|
|||||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||||
const [isCheckingClaudeCli, setIsCheckingClaudeCli] = useState(false);
|
const [isCheckingClaudeCli, setIsCheckingClaudeCli] = useState(false);
|
||||||
const [isCheckingCodexCli, setIsCheckingCodexCli] = useState(false);
|
const [isCheckingCodexCli, setIsCheckingCodexCli] = useState(false);
|
||||||
|
const [apiKeyStatus, setApiKeyStatus] = useState<{
|
||||||
|
hasAnthropicKey: boolean;
|
||||||
|
hasOpenAIKey: boolean;
|
||||||
|
hasGoogleKey: boolean;
|
||||||
|
} | null>(null);
|
||||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
// Get authentication status from setup store
|
||||||
|
const { claudeAuthStatus, codexAuthStatus } = useSetupStore();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAnthropicKey(apiKeys.anthropic);
|
setAnthropicKey(apiKeys.anthropic);
|
||||||
@@ -164,6 +174,21 @@ export function SettingsView() {
|
|||||||
console.error("Failed to check Codex CLI status:", error);
|
console.error("Failed to check Codex CLI status:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Check API key status from environment
|
||||||
|
if (api?.setup?.getApiKeys) {
|
||||||
|
try {
|
||||||
|
const status = await api.setup.getApiKeys();
|
||||||
|
if (status.success) {
|
||||||
|
setApiKeyStatus({
|
||||||
|
hasAnthropicKey: status.hasAnthropicKey,
|
||||||
|
hasOpenAIKey: status.hasOpenAIKey,
|
||||||
|
hasGoogleKey: status.hasGoogleKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to check API key status:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
checkCliStatus();
|
checkCliStatus();
|
||||||
}, []);
|
}, []);
|
||||||
@@ -738,6 +763,176 @@ export function SettingsView() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Authentication Status Display */}
|
||||||
|
<div className="space-y-4 pt-4 border-t border-border">
|
||||||
|
<div className="flex items-center gap-2 mb-3">
|
||||||
|
<Info className="w-4 h-4 text-brand-500" />
|
||||||
|
<Label className="text-foreground font-semibold">
|
||||||
|
Current Authentication Configuration
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
{/* Claude Authentication Status */}
|
||||||
|
<div className="p-3 rounded-lg bg-card border border-border">
|
||||||
|
<div className="flex items-center gap-2 mb-1.5">
|
||||||
|
<Terminal className="w-4 h-4 text-brand-500" />
|
||||||
|
<span className="text-sm font-medium text-foreground">
|
||||||
|
Claude (Anthropic)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1.5 text-xs min-h-[3rem]">
|
||||||
|
{claudeAuthStatus?.authenticated ? (
|
||||||
|
<>
|
||||||
|
<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>
|
||||||
|
</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">
|
||||||
|
<Info className="w-3 h-3 shrink-0" />
|
||||||
|
<span>Using environment variable (ANTHROPIC_API_KEY)</span>
|
||||||
|
</div>
|
||||||
|
) : apiKeys.anthropic ? (
|
||||||
|
<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-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>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Codex/OpenAI Authentication Status */}
|
||||||
|
<div className="p-3 rounded-lg bg-card border border-border">
|
||||||
|
<div className="flex items-center gap-2 mb-1.5">
|
||||||
|
<Atom className="w-4 h-4 text-green-500" />
|
||||||
|
<span className="text-sm font-medium text-foreground">
|
||||||
|
Codex (OpenAI)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1.5 text-xs min-h-[3rem]">
|
||||||
|
{codexAuthStatus?.authenticated ? (
|
||||||
|
<>
|
||||||
|
<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 === "api_key"
|
||||||
|
? "API Key (Auth File)"
|
||||||
|
: codexAuthStatus.method === "env"
|
||||||
|
? "API Key (Environment)"
|
||||||
|
: "Unknown"}
|
||||||
|
</span>
|
||||||
|
</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>
|
||||||
|
)}
|
||||||
|
{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">
|
||||||
|
<Info className="w-3 h-3 shrink-0" />
|
||||||
|
<span>Using environment variable (OPENAI_API_KEY)</span>
|
||||||
|
</div>
|
||||||
|
) : apiKeys.openai ? (
|
||||||
|
<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-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>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Google/Gemini Authentication Status */}
|
||||||
|
<div className="p-3 rounded-lg bg-card border border-border">
|
||||||
|
<div className="flex items-center gap-2 mb-1.5">
|
||||||
|
<Sparkles className="w-4 h-4 text-purple-500" />
|
||||||
|
<span className="text-sm font-medium text-foreground">
|
||||||
|
Gemini (Google)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1.5 text-xs min-h-[3rem]">
|
||||||
|
{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>
|
||||||
|
) : 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-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>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Security Notice */}
|
{/* Security Notice */}
|
||||||
<div className="flex items-start gap-3 p-4 rounded-lg bg-yellow-500/10 border border-yellow-500/20">
|
<div className="flex items-start gap-3 p-4 rounded-lg bg-yellow-500/10 border border-yellow-500/20">
|
||||||
<AlertCircle className="w-5 h-5 text-yellow-500 mt-0.5 shrink-0" />
|
<AlertCircle className="w-5 h-5 text-yellow-500 mt-0.5 shrink-0" />
|
||||||
|
|||||||
Reference in New Issue
Block a user