diff --git a/.automaker/.gitignore b/.automaker/.gitignore index 3eb536ef..41e83493 100644 --- a/.automaker/.gitignore +++ b/.automaker/.gitignore @@ -6,3 +6,6 @@ agents-context/ # Attached images - uploaded by users as feature context images/ + +# Launch script - local development script +launch.sh \ No newline at end of file diff --git a/.cursor/plans/codex_cli_openai_model_support_9987f5e4.plan.md b/.cursor/plans/codex_cli_openai_model_support_9987f5e4.plan.md index ebec34f8..d0da6a95 100644 --- a/.cursor/plans/codex_cli_openai_model_support_9987f5e4.plan.md +++ b/.cursor/plans/codex_cli_openai_model_support_9987f5e4.plan.md @@ -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 ## Overview diff --git a/app/package-lock.json b/app/package-lock.json index 9a8449c1..b45f727a 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -24,6 +24,7 @@ "@tanstack/react-query": "^5.90.12", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "dotenv": "^17.2.3", "lucide-react": "^0.556.0", "next": "16.0.7", "react": "19.2.0", @@ -4687,6 +4688,19 @@ "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": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -6308,10 +6322,9 @@ } }, "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "dev": true, + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -6336,6 +6349,19 @@ "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": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", diff --git a/app/package.json b/app/package.json index a0d5faa0..6d3515f3 100644 --- a/app/package.json +++ b/app/package.json @@ -31,6 +31,7 @@ "@tanstack/react-query": "^5.90.12", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "dotenv": "^17.2.3", "lucide-react": "^0.556.0", "next": "16.0.7", "react": "19.2.0", diff --git a/app/src/components/views/settings-view.tsx b/app/src/components/views/settings-view.tsx index 57f2c839..7a91d602 100644 --- a/app/src/components/views/settings-view.tsx +++ b/app/src/components/views/settings-view.tsx @@ -39,6 +39,7 @@ import { TestTube, Settings2, RefreshCw, + Info, } from "lucide-react"; import { getElectronAPI } from "@/lib/electron"; import { Checkbox } from "@/components/ui/checkbox"; @@ -50,6 +51,7 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { useSetupStore } from "@/store/setup-store"; // Navigation items for the side panel const NAV_ITEMS = [ @@ -137,7 +139,15 @@ export function SettingsView() { const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [isCheckingClaudeCli, setIsCheckingClaudeCli] = useState(false); const [isCheckingCodexCli, setIsCheckingCodexCli] = useState(false); + const [apiKeyStatus, setApiKeyStatus] = useState<{ + hasAnthropicKey: boolean; + hasOpenAIKey: boolean; + hasGoogleKey: boolean; + } | null>(null); const scrollContainerRef = useRef(null); + + // Get authentication status from setup store + const { claudeAuthStatus, codexAuthStatus } = useSetupStore(); useEffect(() => { setAnthropicKey(apiKeys.anthropic); @@ -164,6 +174,21 @@ export function SettingsView() { 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(); }, []); @@ -738,6 +763,176 @@ export function SettingsView() { )} + {/* Authentication Status Display */} +
+
+ + +
+ +
+ {/* Claude Authentication Status */} +
+
+ + + Claude (Anthropic) + +
+
+ {claudeAuthStatus?.authenticated ? ( + <> +
+ + + Method:{" "} + + {claudeAuthStatus.method === "oauth" + ? "OAuth Token" + : claudeAuthStatus.method === "api_key" + ? "API Key" + : "Unknown"} + + +
+ {claudeAuthStatus.oauthTokenValid && ( +
+ + OAuth token configured +
+ )} + {claudeAuthStatus.apiKeyValid && ( +
+ + API key configured +
+ )} + {apiKeyStatus?.hasAnthropicKey && ( +
+ + Environment variable detected +
+ )} + {apiKeys.anthropic && ( +
+ + Manual API key in settings +
+ )} + + ) : apiKeyStatus?.hasAnthropicKey ? ( +
+ + Using environment variable (ANTHROPIC_API_KEY) +
+ ) : apiKeys.anthropic ? ( +
+ + Using manual API key from settings +
+ ) : ( +
+ + Not Setup +
+ )} +
+
+ + {/* Codex/OpenAI Authentication Status */} +
+
+ + + Codex (OpenAI) + +
+
+ {codexAuthStatus?.authenticated ? ( + <> +
+ + + Method:{" "} + + {codexAuthStatus.method === "api_key" + ? "API Key (Auth File)" + : codexAuthStatus.method === "env" + ? "API Key (Environment)" + : "Unknown"} + + +
+ {codexAuthStatus.apiKeyValid && ( +
+ + API key configured +
+ )} + {apiKeyStatus?.hasOpenAIKey && ( +
+ + Environment variable detected +
+ )} + {apiKeys.openai && ( +
+ + Manual API key in settings +
+ )} + + ) : apiKeyStatus?.hasOpenAIKey ? ( +
+ + Using environment variable (OPENAI_API_KEY) +
+ ) : apiKeys.openai ? ( +
+ + Using manual API key from settings +
+ ) : ( +
+ + Not Setup +
+ )} +
+
+ + {/* Google/Gemini Authentication Status */} +
+
+ + + Gemini (Google) + +
+
+ {apiKeyStatus?.hasGoogleKey ? ( +
+ + Using environment variable (GOOGLE_API_KEY) +
+ ) : apiKeys.google ? ( +
+ + Using manual API key from settings +
+ ) : ( +
+ + Not Setup +
+ )} +
+
+
+
+ {/* Security Notice */}