mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-31 06:42:03 +00:00
feature/codex-cli
This commit is contained in:
@@ -93,6 +93,9 @@ export {
|
||||
getClaudeSettingsPath,
|
||||
getClaudeStatsCachePath,
|
||||
getClaudeProjectsDir,
|
||||
getCodexCliPaths,
|
||||
getCodexConfigDir,
|
||||
getCodexAuthPath,
|
||||
getShellPaths,
|
||||
getExtendedPath,
|
||||
// Node.js paths
|
||||
@@ -120,6 +123,9 @@ export {
|
||||
findClaudeCliPath,
|
||||
getClaudeAuthIndicators,
|
||||
type ClaudeAuthIndicators,
|
||||
findCodexCliPath,
|
||||
getCodexAuthIndicators,
|
||||
type CodexAuthIndicators,
|
||||
// Electron userData operations
|
||||
setElectronUserDataPath,
|
||||
getElectronUserDataPath,
|
||||
|
||||
@@ -71,6 +71,49 @@ export function getClaudeCliPaths(): string[] {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get common paths where Codex CLI might be installed
|
||||
*/
|
||||
export function getCodexCliPaths(): string[] {
|
||||
const isWindows = process.platform === 'win32';
|
||||
|
||||
if (isWindows) {
|
||||
const appData = process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming');
|
||||
return [
|
||||
path.join(os.homedir(), '.local', 'bin', 'codex.exe'),
|
||||
path.join(appData, 'npm', 'codex.cmd'),
|
||||
path.join(appData, 'npm', 'codex'),
|
||||
path.join(appData, '.npm-global', 'bin', 'codex.cmd'),
|
||||
path.join(appData, '.npm-global', 'bin', 'codex'),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
path.join(os.homedir(), '.local', 'bin', 'codex'),
|
||||
'/opt/homebrew/bin/codex',
|
||||
'/usr/local/bin/codex',
|
||||
path.join(os.homedir(), '.npm-global', 'bin', 'codex'),
|
||||
];
|
||||
}
|
||||
|
||||
const CODEX_CONFIG_DIR_NAME = '.codex';
|
||||
const CODEX_AUTH_FILENAME = 'auth.json';
|
||||
const CODEX_TOKENS_KEY = 'tokens';
|
||||
|
||||
/**
|
||||
* Get the Codex configuration directory path
|
||||
*/
|
||||
export function getCodexConfigDir(): string {
|
||||
return path.join(os.homedir(), CODEX_CONFIG_DIR_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path to Codex auth file
|
||||
*/
|
||||
export function getCodexAuthPath(): string {
|
||||
return path.join(getCodexConfigDir(), CODEX_AUTH_FILENAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Claude configuration directory path
|
||||
*/
|
||||
@@ -413,6 +456,11 @@ function getAllAllowedSystemPaths(): string[] {
|
||||
getClaudeSettingsPath(),
|
||||
getClaudeStatsCachePath(),
|
||||
getClaudeProjectsDir(),
|
||||
// Codex CLI paths
|
||||
...getCodexCliPaths(),
|
||||
// Codex config directory and files
|
||||
getCodexConfigDir(),
|
||||
getCodexAuthPath(),
|
||||
// Shell paths
|
||||
...getShellPaths(),
|
||||
// Node.js system paths
|
||||
@@ -432,6 +480,8 @@ function getAllAllowedSystemDirs(): string[] {
|
||||
// Claude config
|
||||
getClaudeConfigDir(),
|
||||
getClaudeProjectsDir(),
|
||||
// Codex config
|
||||
getCodexConfigDir(),
|
||||
// Version managers (need recursive access for version directories)
|
||||
...getNvmPaths(),
|
||||
...getFnmPaths(),
|
||||
@@ -740,6 +790,10 @@ export async function findClaudeCliPath(): Promise<string | null> {
|
||||
return findFirstExistingPath(getClaudeCliPaths());
|
||||
}
|
||||
|
||||
export async function findCodexCliPath(): Promise<string | null> {
|
||||
return findFirstExistingPath(getCodexCliPaths());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Claude authentication status by checking various indicators
|
||||
*/
|
||||
@@ -818,3 +872,56 @@ export async function getClaudeAuthIndicators(): Promise<ClaudeAuthIndicators> {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export interface CodexAuthIndicators {
|
||||
hasAuthFile: boolean;
|
||||
hasOAuthToken: boolean;
|
||||
hasApiKey: boolean;
|
||||
}
|
||||
|
||||
const CODEX_OAUTH_KEYS = ['access_token', 'oauth_token'] as const;
|
||||
const CODEX_API_KEY_KEYS = ['api_key', 'OPENAI_API_KEY'] as const;
|
||||
|
||||
function hasNonEmptyStringField(record: Record<string, unknown>, keys: readonly string[]): boolean {
|
||||
return keys.some((key) => typeof record[key] === 'string' && record[key]);
|
||||
}
|
||||
|
||||
function getNestedTokens(record: Record<string, unknown>): Record<string, unknown> | null {
|
||||
const tokens = record[CODEX_TOKENS_KEY];
|
||||
if (tokens && typeof tokens === 'object' && !Array.isArray(tokens)) {
|
||||
return tokens as Record<string, unknown>;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function getCodexAuthIndicators(): Promise<CodexAuthIndicators> {
|
||||
const result: CodexAuthIndicators = {
|
||||
hasAuthFile: false,
|
||||
hasOAuthToken: false,
|
||||
hasApiKey: false,
|
||||
};
|
||||
|
||||
try {
|
||||
const authContent = await systemPathReadFile(getCodexAuthPath());
|
||||
result.hasAuthFile = true;
|
||||
|
||||
try {
|
||||
const authJson = JSON.parse(authContent) as Record<string, unknown>;
|
||||
result.hasOAuthToken = hasNonEmptyStringField(authJson, CODEX_OAUTH_KEYS);
|
||||
result.hasApiKey = hasNonEmptyStringField(authJson, CODEX_API_KEY_KEYS);
|
||||
const nestedTokens = getNestedTokens(authJson);
|
||||
if (nestedTokens) {
|
||||
result.hasOAuthToken =
|
||||
result.hasOAuthToken || hasNonEmptyStringField(nestedTokens, CODEX_OAUTH_KEYS);
|
||||
result.hasApiKey =
|
||||
result.hasApiKey || hasNonEmptyStringField(nestedTokens, CODEX_API_KEY_KEYS);
|
||||
}
|
||||
} catch {
|
||||
// Ignore parse errors; file exists but contents are unreadable
|
||||
}
|
||||
} catch {
|
||||
// Auth file not found or inaccessible
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user