{"version":3,"file":"codex.mjs","names":[],"sources":["../../../../../src/cli/commands/compat/providers/codex.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { JsonObject } from '@agimon-ai/doompi-core/runtime-json';\n\nimport type { CompatibilityContext } from '../context';\nimport { runCaptured, runChecked, runInteractive } from './process';\nimport {\n  ADD_DIRECTORY_OPTION,\n  AGIFLOW_PROXY_SERVER_NAME,\n  additionalDirectoryArgs,\n  MCP_CONFIG_OPTION,\n  MCP_PRESTART_OPTION,\n  MCP_PROXY_PACKAGE,\n  mcpProxyArguments,\n  NPX_COMMAND,\n  PLUGINS_DIRECTORY,\n} from './shared';\n\nexport const CODEX_PROVIDER = 'codex';\n\nconst PROFILE_FLAG = '--profile';\nconst PROFILE_V2_FLAG = '--profile-v2';\nconst PROFILE_CONFIG_NAME_PATTERN = /^[A-Za-z0-9_-]+$/;\nconst SYNC_SCRIPT_RELATIVE_PATH = ['tools', 'harness', 'sync-codex-state.cjs'];\n\n/** Codex options that consume the following argument, so it is not a subcommand. */\nfunction optionRequiresValue(argument: string): boolean {\n  return new Set([\n    PROFILE_FLAG,\n    PROFILE_V2_FLAG,\n    '-c',\n    MCP_CONFIG_OPTION,\n    '--enable',\n    '--disable',\n    '--remote',\n    '--remote-auth-token-env',\n    '-i',\n    '--image',\n    '-m',\n    '--model',\n    '--local-provider',\n    '-s',\n    '--sandbox',\n    '-C',\n    '--cd',\n    ADD_DIRECTORY_OPTION,\n    '-a',\n    '--ask-for-approval',\n  ]).has(argument);\n}\n\n/**\n * Whether the managed profile, persona, and proxy config apply to this run.\n *\n * Codex management subcommands reject session options, so injecting them would\n * turn `codex login` into an error.\n */\nexport function supportsCodexManagedProfile(args: string[]): boolean {\n  let previousRequiresValue = false;\n  let command = '';\n  let debugSubcommand = '';\n\n  for (const argument of args) {\n    if (previousRequiresValue) {\n      previousRequiresValue = false;\n      continue;\n    }\n    if (optionRequiresValue(argument)) {\n      previousRequiresValue = true;\n      continue;\n    }\n    if (argument.startsWith('-')) continue;\n    if (!command) {\n      command = argument;\n      continue;\n    }\n    if (command === 'debug' && !debugSubcommand) debugSubcommand = argument;\n    break;\n  }\n\n  if (!command || ['exec', 'e', 'review', 'resume', 'fork'].includes(command)) return true;\n  if (command === 'debug') return debugSubcommand === 'prompt-input';\n  if (\n    [\n      'login',\n      'logout',\n      'mcp',\n      'plugin',\n      'mcp-server',\n      'app-server',\n      'remote-control',\n      'app',\n      'completion',\n      'update',\n      'doctor',\n      'sandbox',\n      'apply',\n      'a',\n      'cloud',\n      'exec-server',\n      'features',\n      'archive',\n      'delete',\n      'unarchive',\n      'help',\n    ].includes(command)\n  ) {\n    return false;\n  }\n  return true;\n}\n\n/** Plugin directory names relative to `plugins/`, which is all Codex accepts. */\nexport function codexPluginDirectories(context: CompatibilityContext): string[] {\n  const pluginsRoot = path.join(context.options.repoRoot, PLUGINS_DIRECTORY);\n  return context.plugins.map((plugin) => {\n    const relative = path.relative(pluginsRoot, plugin.directory);\n    if (!relative || relative === '..' || relative.startsWith(`..${path.sep}`) || relative.includes(path.sep)) {\n      throw new Error(`Codex compatibility requires a direct repository plugin: ${plugin.directory}`);\n    }\n    return relative;\n  });\n}\n\n/** Codex's full-auto mode: no approval prompts and no sandbox. */\nconst YOLO_OPTION = '--yolo';\n\nfunction codexProxyArguments(context: CompatibilityContext): string[] {\n  return mcpProxyArguments(MCP_PROXY_PACKAGE, context.proxyConfigPath, true, true);\n}\n\nexport function codexCompatibilityArgs(\n  context: CompatibilityContext,\n  managedProfileName: string,\n  managedProfileFlag: string,\n): string[] {\n  const args = [\n    ...(context.options.skipPermissions ? [YOLO_OPTION] : []),\n    '--enable',\n    'hooks',\n    ...additionalDirectoryArgs(context),\n  ];\n  if (supportsCodexManagedProfile(context.options.providerArgs)) {\n    args.push(managedProfileFlag, managedProfileName);\n    if (context.personaFile) {\n      const persona = fs.readFileSync(context.personaFile, 'utf8');\n      args.push('-c', `developer_instructions=${JSON.stringify(persona)}`);\n    }\n    if (context.mcpAllowlist) {\n      args.push('-c', `mcp_servers.${AGIFLOW_PROXY_SERVER_NAME}.args=${JSON.stringify(codexProxyArguments(context))}`);\n    }\n  }\n  return [...args, ...context.options.providerArgs];\n}\n\nexport function codexEnvironment(context: CompatibilityContext): NodeJS.ProcessEnv {\n  const environment = { ...context.environment };\n  const originResult = spawnSync('git', ['-C', context.options.repoRoot, 'remote', 'get-url', 'origin'], {\n    encoding: 'utf8',\n    env: environment,\n  });\n  environment.CODEX_REPO_ORIGIN = originResult.status === 0 ? originResult.stdout.trim() : '';\n  environment.CODEX_PROFILE_NAMES = context.options.domains.join(',');\n  environment.CODEX_PLUGIN_DIRS = codexPluginDirectories(context).join(',');\n  environment.CODEX_ENABLE_XCODE_MCP =\n    spawnSync('xcrun', ['mcpbridge', '--help'], { env: environment, stdio: 'ignore' }).status === 0 ? '1' : '0';\n  return environment;\n}\n\nexport async function launchCodex(context: CompatibilityContext): Promise<number> {\n  const environment = codexEnvironment(context);\n  const syncScript = path.join(context.options.repoRoot, ...SYNC_SCRIPT_RELATIVE_PATH);\n  const stateName = runCaptured(process.execPath, [syncScript, 'owner-key'], context.options.repoRoot, environment);\n  const home = environment.HOME;\n  environment.CODEX_LEGACY_HOME = home ? path.join(home, '.codex', 'agirepo') : undefined;\n  environment.CODEX_HOME = home\n    ? path.join(home, '.codex', stateName)\n    : path.join(context.options.repoRoot, '.codex-local', 'state', stateName);\n\n  runChecked(\n    NPX_COMMAND,\n    [...mcpProxyArguments(MCP_PROXY_PACKAGE, context.proxyConfigPath, true), MCP_PRESTART_OPTION],\n    context.options.repoRoot,\n    environment,\n  );\n\n  const syncOutput = runCaptured(process.execPath, [syncScript, 'sync'], context.options.repoRoot, environment);\n  const syncResult = JSON.parse(syncOutput) as JsonObject;\n  if (\n    typeof syncResult.profileConfigName !== 'string' ||\n    !PROFILE_CONFIG_NAME_PATTERN.test(syncResult.profileConfigName)\n  ) {\n    throw new Error('Codex sync returned an invalid profile config name');\n  }\n  // Older Codex builds only understand --profile, so the flag is probed rather\n  // than assumed.\n  const help = runCaptured(CODEX_PROVIDER, ['--help'], context.options.repoRoot, environment);\n  const profileFlag = help.includes(PROFILE_V2_FLAG) ? PROFILE_V2_FLAG : PROFILE_FLAG;\n  return runInteractive(\n    CODEX_PROVIDER,\n    codexCompatibilityArgs(context, syncResult.profileConfigName, profileFlag),\n    context.options.repoRoot,\n    environment,\n  );\n}\n"],"mappings":"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"}