import { mkdir, mkdtemp, readFile, rm, stat, writeFile, } from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import { afterEach, describe, expect, test } from 'vitest'; import { prepareCodexWorkspaceFiles } from '../../src/codex-runtime'; const tempDirs: string[] = []; const mode = async (filePath: string) => (await stat(filePath)).mode & 0o777; describe('Codex runtime preparation', () => { afterEach(async () => { await Promise.all( tempDirs.map((dir) => rm(dir, { force: true, recursive: true })), ); tempDirs.length = 0; }); test('prepares writable Codex directories and preserves project config contents', async () => { const workdir = await mkdtemp(path.join(os.tmpdir(), 'spoon-codex-')); tempDirs.push(workdir); const repoDir = path.join(workdir, 'repo'); await mkdir(path.join(repoDir, '.codex'), { recursive: true }); const projectConfig = path.join(repoDir, '.codex', 'config.toml'); await writeFile(projectConfig, '[features]\ncodex_hooks = true\n'); await prepareCodexWorkspaceFiles({ workdir, repoDir }); await expect(readFile(projectConfig, 'utf8')).resolves.toBe( '[features]\ncodex_hooks = true\n', ); await expect(mode(workdir)).resolves.toBe(0o755); await expect(mode(repoDir)).resolves.toBe(0o755); await expect(mode(path.join(workdir, '.codex'))).resolves.toBe(0o755); await expect(mode(path.join(workdir, '.config'))).resolves.toBe(0o755); await expect(mode(path.join(workdir, '.local', 'share'))).resolves.toBe( 0o755, ); await expect(mode(path.join(repoDir, '.codex'))).resolves.toBe(0o755); await expect(mode(projectConfig)).resolves.toBe(0o644); }); });