mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-03 21:03:08 +00:00
refactor(settings): extract CLI status into custom hook
- Create hooks/use-cli-status.ts to manage all CLI status logic - Move Claude and Codex CLI status state management to hook - Move CLI checking useEffect and refresh handlers to hook - Update settings-view.tsx to use new useCliStatus hook - Reduce settings-view.tsx by ~130 lines - Improve testability by isolating CLI status logic 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,8 @@ import {
|
|||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { KeyboardMap, ShortcutReferencePanel } from "@/components/ui/keyboard-map";
|
import { KeyboardMap, ShortcutReferencePanel } from "@/components/ui/keyboard-map";
|
||||||
|
// Import custom hooks
|
||||||
|
import { useCliStatus } from "./settings-view/hooks/use-cli-status";
|
||||||
// Import extracted sections
|
// Import extracted sections
|
||||||
import { ApiKeysSection } from "./settings-view/api-keys/api-keys-section";
|
import { ApiKeysSection } from "./settings-view/api-keys/api-keys-section";
|
||||||
import { ClaudeCliStatus } from "./settings-view/cli-status/claude-cli-status";
|
import { ClaudeCliStatus } from "./settings-view/cli-status/claude-cli-status";
|
||||||
@@ -83,128 +85,21 @@ export function SettingsView() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const [claudeCliStatus, setClaudeCliStatus] = useState<{
|
// Use CLI status hook
|
||||||
success: boolean;
|
const {
|
||||||
status?: string;
|
claudeCliStatus,
|
||||||
method?: string;
|
codexCliStatus,
|
||||||
version?: string;
|
isCheckingClaudeCli,
|
||||||
path?: string;
|
isCheckingCodexCli,
|
||||||
recommendation?: string;
|
handleRefreshClaudeCli,
|
||||||
installCommands?: {
|
handleRefreshCodexCli,
|
||||||
macos?: string;
|
} = useCliStatus();
|
||||||
windows?: string;
|
|
||||||
linux?: string;
|
|
||||||
npm?: string;
|
|
||||||
};
|
|
||||||
error?: string;
|
|
||||||
} | null>(null);
|
|
||||||
|
|
||||||
const [codexCliStatus, setCodexCliStatus] = useState<{
|
|
||||||
success: boolean;
|
|
||||||
status?: string;
|
|
||||||
method?: string;
|
|
||||||
version?: string;
|
|
||||||
path?: string;
|
|
||||||
hasApiKey?: boolean;
|
|
||||||
recommendation?: string;
|
|
||||||
installCommands?: {
|
|
||||||
macos?: string;
|
|
||||||
windows?: string;
|
|
||||||
linux?: string;
|
|
||||||
npm?: string;
|
|
||||||
};
|
|
||||||
error?: string;
|
|
||||||
} | null>(null);
|
|
||||||
|
|
||||||
const [activeSection, setActiveSection] = useState("api-keys");
|
const [activeSection, setActiveSection] = useState("api-keys");
|
||||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||||
const [showKeyboardMapDialog, setShowKeyboardMapDialog] = useState(false);
|
const [showKeyboardMapDialog, setShowKeyboardMapDialog] = useState(false);
|
||||||
const [isCheckingClaudeCli, setIsCheckingClaudeCli] = useState(false);
|
|
||||||
const [isCheckingCodexCli, setIsCheckingCodexCli] = useState(false);
|
|
||||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const checkCliStatus = async () => {
|
|
||||||
const api = getElectronAPI();
|
|
||||||
if (api?.checkClaudeCli) {
|
|
||||||
try {
|
|
||||||
const status = await api.checkClaudeCli();
|
|
||||||
setClaudeCliStatus(status);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to check Claude CLI status:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (api?.checkCodexCli) {
|
|
||||||
try {
|
|
||||||
const status = await api.checkCodexCli();
|
|
||||||
setCodexCliStatus(status);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to check Codex CLI status:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Claude auth status (re-fetch on mount to ensure persistence)
|
|
||||||
if (api?.setup?.getClaudeStatus) {
|
|
||||||
try {
|
|
||||||
const result = await api.setup.getClaudeStatus();
|
|
||||||
if (result.success && result.auth) {
|
|
||||||
const auth = result.auth;
|
|
||||||
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,
|
|
||||||
hasCredentialsFile: auth.hasCredentialsFile ?? false,
|
|
||||||
oauthTokenValid: auth.hasStoredOAuthToken,
|
|
||||||
apiKeyValid: auth.hasStoredApiKey || auth.hasEnvApiKey,
|
|
||||||
};
|
|
||||||
setClaudeAuthStatus(authStatus);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to check Claude auth status:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Codex auth status (re-fetch on mount to ensure persistence)
|
|
||||||
if (api?.setup?.getCodexStatus) {
|
|
||||||
try {
|
|
||||||
const result = await api.setup.getCodexStatus();
|
|
||||||
if (result.success && result.auth) {
|
|
||||||
const auth = result.auth;
|
|
||||||
// Determine method - prioritize cli_verified and cli_tokens over auth_file
|
|
||||||
const method =
|
|
||||||
auth.method === "cli_verified" || auth.method === "cli_tokens"
|
|
||||||
? auth.method === "cli_verified"
|
|
||||||
? "cli_verified" as const
|
|
||||||
: "cli_tokens" as const
|
|
||||||
: auth.method === "auth_file"
|
|
||||||
? "api_key" as const
|
|
||||||
: auth.method === "env_var"
|
|
||||||
? "env" as const
|
|
||||||
: "none" as const;
|
|
||||||
|
|
||||||
const authStatus = {
|
|
||||||
authenticated: auth.authenticated,
|
|
||||||
method,
|
|
||||||
// Only set apiKeyValid for actual API key methods, not CLI login
|
|
||||||
apiKeyValid:
|
|
||||||
method === "cli_verified" || method === "cli_tokens"
|
|
||||||
? undefined
|
|
||||||
: auth.hasAuthFile || auth.hasEnvKey,
|
|
||||||
};
|
|
||||||
setCodexAuthStatus(authStatus);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to check Codex auth status:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
checkCliStatus();
|
|
||||||
}, [setClaudeAuthStatus, setCodexAuthStatus]);
|
|
||||||
|
|
||||||
// Track scroll position to highlight active nav item
|
// Track scroll position to highlight active nav item
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const container = scrollContainerRef.current;
|
const container = scrollContainerRef.current;
|
||||||
@@ -267,36 +162,6 @@ export function SettingsView() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleRefreshClaudeCli = useCallback(async () => {
|
|
||||||
setIsCheckingClaudeCli(true);
|
|
||||||
try {
|
|
||||||
const api = getElectronAPI();
|
|
||||||
if (api?.checkClaudeCli) {
|
|
||||||
const status = await api.checkClaudeCli();
|
|
||||||
setClaudeCliStatus(status);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to refresh Claude CLI status:", error);
|
|
||||||
} finally {
|
|
||||||
setIsCheckingClaudeCli(false);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleRefreshCodexCli = useCallback(async () => {
|
|
||||||
setIsCheckingCodexCli(true);
|
|
||||||
try {
|
|
||||||
const api = getElectronAPI();
|
|
||||||
if (api?.checkCodexCli) {
|
|
||||||
const status = await api.checkCodexCli();
|
|
||||||
setCodexCliStatus(status);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to refresh Codex CLI status:", error);
|
|
||||||
} finally {
|
|
||||||
setIsCheckingCodexCli(false);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="flex-1 flex flex-col overflow-hidden content-bg"
|
className="flex-1 flex flex-col overflow-hidden content-bg"
|
||||||
|
|||||||
169
app/src/components/views/settings-view/hooks/use-cli-status.ts
Normal file
169
app/src/components/views/settings-view/hooks/use-cli-status.ts
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
import { useState, useEffect, useCallback } from "react";
|
||||||
|
import { useSetupStore } from "@/store/setup-store";
|
||||||
|
import { getElectronAPI } from "@/lib/electron";
|
||||||
|
|
||||||
|
interface CliStatusResult {
|
||||||
|
success: boolean;
|
||||||
|
status?: string;
|
||||||
|
method?: string;
|
||||||
|
version?: string;
|
||||||
|
path?: string;
|
||||||
|
recommendation?: string;
|
||||||
|
installCommands?: {
|
||||||
|
macos?: string;
|
||||||
|
windows?: string;
|
||||||
|
linux?: string;
|
||||||
|
npm?: string;
|
||||||
|
};
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CodexCliStatusResult extends CliStatusResult {
|
||||||
|
hasApiKey?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom hook for managing Claude and Codex CLI status
|
||||||
|
* Handles checking CLI installation, authentication, and refresh functionality
|
||||||
|
*/
|
||||||
|
export function useCliStatus() {
|
||||||
|
const { setClaudeAuthStatus, setCodexAuthStatus } = useSetupStore();
|
||||||
|
|
||||||
|
const [claudeCliStatus, setClaudeCliStatus] =
|
||||||
|
useState<CliStatusResult | null>(null);
|
||||||
|
|
||||||
|
const [codexCliStatus, setCodexCliStatus] =
|
||||||
|
useState<CodexCliStatusResult | null>(null);
|
||||||
|
|
||||||
|
const [isCheckingClaudeCli, setIsCheckingClaudeCli] = useState(false);
|
||||||
|
const [isCheckingCodexCli, setIsCheckingCodexCli] = useState(false);
|
||||||
|
|
||||||
|
// Check CLI status on mount
|
||||||
|
useEffect(() => {
|
||||||
|
const checkCliStatus = async () => {
|
||||||
|
const api = getElectronAPI();
|
||||||
|
|
||||||
|
// Check Claude CLI
|
||||||
|
if (api?.checkClaudeCli) {
|
||||||
|
try {
|
||||||
|
const status = await api.checkClaudeCli();
|
||||||
|
setClaudeCliStatus(status);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to check Claude CLI status:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Codex CLI
|
||||||
|
if (api?.checkCodexCli) {
|
||||||
|
try {
|
||||||
|
const status = await api.checkCodexCli();
|
||||||
|
setCodexCliStatus(status);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to check Codex CLI status:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Claude auth status (re-fetch on mount to ensure persistence)
|
||||||
|
if (api?.setup?.getClaudeStatus) {
|
||||||
|
try {
|
||||||
|
const result = await api.setup.getClaudeStatus();
|
||||||
|
if (result.success && result.auth) {
|
||||||
|
const auth = result.auth;
|
||||||
|
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),
|
||||||
|
hasCredentialsFile: auth.hasCredentialsFile ?? false,
|
||||||
|
oauthTokenValid: auth.hasStoredOAuthToken,
|
||||||
|
apiKeyValid: auth.hasStoredApiKey || auth.hasEnvApiKey,
|
||||||
|
};
|
||||||
|
setClaudeAuthStatus(authStatus);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to check Claude auth status:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Codex auth status (re-fetch on mount to ensure persistence)
|
||||||
|
if (api?.setup?.getCodexStatus) {
|
||||||
|
try {
|
||||||
|
const result = await api.setup.getCodexStatus();
|
||||||
|
if (result.success && result.auth) {
|
||||||
|
const auth = result.auth;
|
||||||
|
// Determine method - prioritize cli_verified and cli_tokens over auth_file
|
||||||
|
const method =
|
||||||
|
auth.method === "cli_verified" || auth.method === "cli_tokens"
|
||||||
|
? auth.method === "cli_verified"
|
||||||
|
? ("cli_verified" as const)
|
||||||
|
: ("cli_tokens" as const)
|
||||||
|
: auth.method === "auth_file"
|
||||||
|
? ("api_key" as const)
|
||||||
|
: auth.method === "env_var"
|
||||||
|
? ("env" as const)
|
||||||
|
: ("none" as const);
|
||||||
|
|
||||||
|
const authStatus = {
|
||||||
|
authenticated: auth.authenticated,
|
||||||
|
method,
|
||||||
|
// Only set apiKeyValid for actual API key methods, not CLI login
|
||||||
|
apiKeyValid:
|
||||||
|
method === "cli_verified" || method === "cli_tokens"
|
||||||
|
? undefined
|
||||||
|
: auth.hasAuthFile || auth.hasEnvKey,
|
||||||
|
};
|
||||||
|
setCodexAuthStatus(authStatus);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to check Codex auth status:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkCliStatus();
|
||||||
|
}, [setClaudeAuthStatus, setCodexAuthStatus]);
|
||||||
|
|
||||||
|
// Refresh Claude CLI status
|
||||||
|
const handleRefreshClaudeCli = useCallback(async () => {
|
||||||
|
setIsCheckingClaudeCli(true);
|
||||||
|
try {
|
||||||
|
const api = getElectronAPI();
|
||||||
|
if (api?.checkClaudeCli) {
|
||||||
|
const status = await api.checkClaudeCli();
|
||||||
|
setClaudeCliStatus(status);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to refresh Claude CLI status:", error);
|
||||||
|
} finally {
|
||||||
|
setIsCheckingClaudeCli(false);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Refresh Codex CLI status
|
||||||
|
const handleRefreshCodexCli = useCallback(async () => {
|
||||||
|
setIsCheckingCodexCli(true);
|
||||||
|
try {
|
||||||
|
const api = getElectronAPI();
|
||||||
|
if (api?.checkCodexCli) {
|
||||||
|
const status = await api.checkCodexCli();
|
||||||
|
setCodexCliStatus(status);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to refresh Codex CLI status:", error);
|
||||||
|
} finally {
|
||||||
|
setIsCheckingCodexCli(false);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
claudeCliStatus,
|
||||||
|
codexCliStatus,
|
||||||
|
isCheckingClaudeCli,
|
||||||
|
isCheckingCodexCli,
|
||||||
|
handleRefreshClaudeCli,
|
||||||
|
handleRefreshCodexCli,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user