File size: 4,433 Bytes
1dbc34b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { useState, useCallback } from 'react';
import { createLogger } from '@automaker/utils/logger';
import type { ModelProvider } from '@automaker/types';
import type { CliStatus, ClaudeAuthStatus, CodexAuthStatus } from '@/store/setup-store';

interface CliStatusApiResponse {
  success: boolean;
  status?: string;
  installed?: boolean;
  method?: string;
  version?: string;
  path?: string;
  auth?: {
    authenticated: boolean;
    method: string;
    hasCredentialsFile?: boolean;
    hasToken?: boolean;
    hasStoredOAuthToken?: boolean;
    hasStoredApiKey?: boolean;
    hasEnvApiKey?: boolean;
    hasEnvOAuthToken?: boolean;
    hasCliAuth?: boolean;
    hasRecentActivity?: boolean;
    hasAuthFile?: boolean;
    hasApiKey?: boolean;
    hasOAuthToken?: boolean;
  };
  error?: string;
}

interface UseCliStatusOptions {
  cliType: ModelProvider;
  statusApi: () => Promise<CliStatusApiResponse>;
  setCliStatus: (status: CliStatus | null) => void;
  setAuthStatus: (status: ClaudeAuthStatus | CodexAuthStatus | null) => void;
}

const VALID_AUTH_METHODS = {
  claude: [
    'oauth_token_env',
    'oauth_token',
    'api_key',
    'api_key_env',
    'credentials_file',
    'cli_authenticated',
    'none',
  ],
  codex: ['cli_authenticated', 'api_key', 'api_key_env', 'none'],
} as const;

// Create logger outside of the hook to avoid re-creating it on every render
const logger = createLogger('CliStatus');

export function useCliStatus({
  cliType,
  statusApi,
  setCliStatus,
  setAuthStatus,
}: UseCliStatusOptions) {
  const [isChecking, setIsChecking] = useState(false);

  const checkStatus = useCallback(async () => {
    logger.info(`Starting status check for ${cliType}...`);
    setIsChecking(true);
    try {
      const result = await statusApi();
      logger.info(`Raw status result for ${cliType}:`, result);

      if (result.success) {
        // Handle both response formats:
        // - Claude API returns {status: 'installed' | 'not_installed'}
        // - Codex API returns {installed: boolean}
        const isInstalled =
          typeof result.installed === 'boolean' ? result.installed : result.status === 'installed';
        const cliStatus = {
          installed: isInstalled,
          path: result.path || null,
          version: result.version || null,
          method: result.method || 'none',
        };
        logger.info(`CLI Status for ${cliType}:`, cliStatus);
        setCliStatus(cliStatus);

        if (result.auth) {
          if (cliType === 'claude') {
            // Validate method is one of the expected Claude values, default to "none"
            const validMethods = VALID_AUTH_METHODS.claude;
            type ClaudeAuthMethod = (typeof validMethods)[number];
            const method: ClaudeAuthMethod = validMethods.includes(
              result.auth.method as ClaudeAuthMethod
            )
              ? (result.auth.method as ClaudeAuthMethod)
              : 'none';

            setAuthStatus({
              authenticated: result.auth.authenticated,
              method,
              hasCredentialsFile: false,
              oauthTokenValid: result.auth.hasStoredOAuthToken || result.auth.hasEnvOAuthToken,
              apiKeyValid: result.auth.hasStoredApiKey || result.auth.hasEnvApiKey,
              hasEnvOAuthToken: result.auth.hasEnvOAuthToken,
              hasEnvApiKey: result.auth.hasEnvApiKey,
            });
          } else {
            // Validate method is one of the expected Codex values, default to "none"
            const validMethods = VALID_AUTH_METHODS.codex;
            type CodexAuthMethod = (typeof validMethods)[number];
            const method: CodexAuthMethod = validMethods.includes(
              result.auth.method as CodexAuthMethod
            )
              ? (result.auth.method as CodexAuthMethod)
              : 'none';

            setAuthStatus({
              authenticated: result.auth.authenticated,
              method,
              hasAuthFile: result.auth.hasAuthFile ?? false,
              hasApiKey: result.auth.hasApiKey ?? false,
              hasEnvApiKey: result.auth.hasEnvApiKey ?? false,
            });
          }
        }
      }
    } catch (error) {
      logger.error(`Failed to check status for ${cliType}:`, error);
    } finally {
      setIsChecking(false);
    }
  }, [cliType, statusApi, setCliStatus, setAuthStatus]);

  return { isChecking, checkStatus };
}