File size: 2,502 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
/**
 * Codex Config Manager - Writes MCP server configuration for Codex CLI
 */

import path from 'path';
import type { McpServerConfig } from '@automaker/types';
import * as secureFs from '../lib/secure-fs.js';

const CODEX_CONFIG_DIR = '.codex';
const CODEX_CONFIG_FILENAME = 'config.toml';
const CODEX_MCP_SECTION = 'mcp_servers';

function formatTomlString(value: string): string {
  return JSON.stringify(value);
}

function formatTomlArray(values: string[]): string {
  const formatted = values.map((value) => formatTomlString(value)).join(', ');
  return `[${formatted}]`;
}

function formatTomlInlineTable(values: Record<string, string>): string {
  const entries = Object.entries(values).map(
    ([key, value]) => `${key} = ${formatTomlString(value)}`
  );
  return `{ ${entries.join(', ')} }`;
}

function formatTomlKey(key: string): string {
  return `"${key.replace(/"/g, '\\"')}"`;
}

function buildServerBlock(name: string, server: McpServerConfig): string[] {
  const lines: string[] = [];
  const section = `${CODEX_MCP_SECTION}.${formatTomlKey(name)}`;
  lines.push(`[${section}]`);

  if (server.type) {
    lines.push(`type = ${formatTomlString(server.type)}`);
  }

  if ('command' in server && server.command) {
    lines.push(`command = ${formatTomlString(server.command)}`);
  }

  if ('args' in server && server.args && server.args.length > 0) {
    lines.push(`args = ${formatTomlArray(server.args)}`);
  }

  if ('env' in server && server.env && Object.keys(server.env).length > 0) {
    lines.push(`env = ${formatTomlInlineTable(server.env)}`);
  }

  if ('url' in server && server.url) {
    lines.push(`url = ${formatTomlString(server.url)}`);
  }

  if ('headers' in server && server.headers && Object.keys(server.headers).length > 0) {
    lines.push(`headers = ${formatTomlInlineTable(server.headers)}`);
  }

  return lines;
}

export class CodexConfigManager {
  async configureMcpServers(
    cwd: string,
    mcpServers: Record<string, McpServerConfig>
  ): Promise<void> {
    const configDir = path.join(cwd, CODEX_CONFIG_DIR);
    const configPath = path.join(configDir, CODEX_CONFIG_FILENAME);

    await secureFs.mkdir(configDir, { recursive: true });

    const blocks: string[] = [];
    for (const [name, server] of Object.entries(mcpServers)) {
      blocks.push(...buildServerBlock(name, server), '');
    }

    const content = blocks.join('\n').trim();
    if (content) {
      await secureFs.writeFile(configPath, content + '\n', 'utf-8');
    }
  }
}