// hosts/codex/config-scaffold.ts — Scaffold .openai/ workspace config (SPEC-592)
// Exports scaffoldCodexConfig(projectPath) for integration into init_project.
// This module does NOT modify src/tools/init-project/handler.ts directly
// to avoid parallel-session merge conflicts with SPEC-591.
//
// Integration hook needed in handler.ts:
//   After the existing `configurePlanuHooks` call (~line 230), add:
//     await scaffoldCodexConfig(projectPath);
//   This is safe to call unconditionally — it is idempotent and a no-op
//   on non-Codex environments.
import { mkdir, writeFile, readFile, access } from 'node:fs/promises';
import { join } from 'node:path';
import { detectCodexWorkspace } from './workspace-scope.js';
import { buildRulesForHost } from '../../engine/host-rules-templates/index.js';
import { assertEnglishOnlyArtifactText } from '../../engine/spec-language/english-only.js';
import { generateImplementerRole, generateReviewerRole, generateSpecWriterRole, } from '../../engine/ai-integration/codex/agent-roles-generator.js';
const CODEX_CONFIG_TOML = `# .openai/config.toml — Planu Codex workspace configuration
# Auto-generated by Planu init_project. Safe to customize.

[mcp]
# Planu MCP server registered via stdio transport (native Codex MCP support).
# No REST shim needed — Codex supports MCP-over-stdio natively.

[[mcp.servers]]
name = "planu"
transport = "stdio"
command = "npx"
args = ["@planu/cli@latest"]
startup_timeout_sec = 120

[workspace]
# Spec files are stored under planu/ — do not gitignore this directory.
spec_path = "planu/specs"

[access]
# Role required to invoke destructive Planu tools (delete_spec, update_status).
# Valid values: owner, admin, member, viewer
min_role_for_mutations = "member"
`;
const AGENTS_MD_CONTENT = `# AGENTS.md — Planu SDD workflow for Codex

## Planu Integration
This project uses Planu for Spec-Driven Development. Planu is available as an
MCP server registered in .openai/config.toml.

## Spec workflow
1. Use \`create_spec\` to plan any feature before writing code.
2. Use \`update_status\` to move specs through the lifecycle.
3. Use \`validate\` after implementation to check compliance.

## Important
- Never write code without an approved spec.
- Planu spec files live in \`planu/specs/\` — never gitignore this directory.
`;
/**
 * Scaffold Codex workspace configuration files.
 * Creates .openai/config.toml and AGENTS.md if they do not exist.
 * SPEC-708: also injects a host-aware Planu rules block into AGENTS.md (idempotent).
 * The body of AGENTS.md is never overwritten; only the rules block between
 * `<!-- planu:rules:start -->` markers is replaced on subsequent runs.
 * Safe to call on non-Codex environments — skips silently unless markers are present.
 */
export async function scaffoldCodexConfig(projectPath, planuVersion = '1.96.0') {
    const markers = detectCodexWorkspace(projectPath);
    const isCodexEnv = markers.hasWorkspaceEnv || markers.hasCodexEnv || markers.isEnterprise;
    // Only scaffold if Codex env markers are present, or if .openai/ already exists
    if (!isCodexEnv && markers.configDir === undefined) {
        return;
    }
    const openaiDir = join(projectPath, '.openai');
    await mkdir(openaiDir, { recursive: true });
    await writeIfMissing(join(openaiDir, 'config.toml'), CODEX_CONFIG_TOML);
    await writeIfMissing(join(projectPath, 'AGENTS.md'), AGENTS_MD_CONTENT);
    await scaffoldCodexAgentRoles(projectPath);
    await injectRulesBlock(join(projectPath, 'AGENTS.md'), planuVersion);
}
// ---------------------------------------------------------------------------
// Private helpers
// ---------------------------------------------------------------------------
async function writeIfMissing(filePath, content) {
    try {
        await access(filePath);
        // File exists — skip (idempotent)
    }
    catch {
        if (filePath.endsWith('AGENTS.md')) {
            assertEnglishOnlyArtifactText(content, 'agent');
        }
        await writeFile(filePath, content, 'utf-8');
    }
}
async function scaffoldCodexAgentRoles(projectPath) {
    const agentsDir = join(projectPath, '.codex', 'agents');
    await mkdir(agentsDir, { recursive: true });
    await Promise.all([
        writeIfMissing(join(agentsDir, 'spec-writer.toml'), generateSpecWriterRole()),
        writeIfMissing(join(agentsDir, 'implementer.toml'), generateImplementerRole()),
        writeIfMissing(join(agentsDir, 'reviewer.toml'), generateReviewerRole()),
    ]);
}
const PLANU_RULES_BLOCK_REGEX = /<!-- planu:rules:start[\s\S]*?<!-- planu:rules:end -->/;
const PLANU_RULES_START_REGEX = /<!-- planu:rules:start[^>]* -->/;
/**
 * SPEC-708: idempotently inject the Planu rules block into the given file.
 * Uses host='codex' so the questions rule references Codex's native interactive prompt
 * instead of `AskUserQuestion`.
 */
async function injectRulesBlock(filePath, version) {
    const block = buildRulesForHost('codex', version).rules;
    assertEnglishOnlyArtifactText(block, 'rule');
    let existing;
    try {
        existing = await readFile(filePath, 'utf-8');
    }
    catch {
        return; // File doesn't exist — nothing to inject into
    }
    const updated = PLANU_RULES_START_REGEX.test(existing)
        ? existing.replace(PLANU_RULES_BLOCK_REGEX, block)
        : `${existing.trimEnd()}\n\n${block}\n`;
    if (updated !== existing) {
        await writeFile(filePath, updated, 'utf-8');
    }
}
//# sourceMappingURL=config-scaffold.js.map