/**
 * 파일시스템 유틸리티
 */
import path from 'path';
import fs from 'fs';
import { getGlobalConfigDir } from '../../infra/lib/llm/auth/ConfigManager.js';
/**
 * 전역 vibe 설정 디렉토리 경로 (getCoreConfigDir = getGlobalConfigDir alias)
 */
export const getCoreConfigDir = getGlobalConfigDir;
/**
 * 디렉토리 내 모든 .md 파일에서 {{VIBE_PATH}} / {{VIBE_PATH_URL}} 템플릿 치환
 * - {{VIBE_PATH}}     → ~/.vibe  (forward slash)
 * - {{VIBE_PATH_URL}} → file:///~/.vibe/
 */
export function replaceTemplatesInDir(dirPath) {
    const corePath = getCoreConfigDir().replace(/\\/g, '/');
    const corePathUrl = 'file:///' + corePath.replace(/^\//, '');
    const entries = fs.readdirSync(dirPath, { withFileTypes: true });
    for (const entry of entries) {
        const fullPath = path.join(dirPath, entry.name);
        if (entry.isDirectory()) {
            replaceTemplatesInDir(fullPath);
        }
        else if (entry.name.endsWith('.md')) {
            let content = fs.readFileSync(fullPath, 'utf-8');
            if (content.includes('{{VIBE_PATH_URL}}') || content.includes('{{VIBE_PATH}}')) {
                content = content.replace(/\{\{VIBE_PATH_URL\}\}/g, corePathUrl);
                content = content.replace(/\{\{VIBE_PATH\}\}/g, corePath);
                fs.writeFileSync(fullPath, content);
            }
        }
    }
}
/**
 * 디렉토리 생성 (재귀)
 */
export function ensureDir(dir) {
    if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
    }
}
/** Directories to skip during recursive copy */
const COPY_SKIP_DIRS = new Set(['node_modules', '.git']);
/**
 * 디렉토리 복사 (재귀, node_modules/.git 제외)
 */
export function copyDirRecursive(src, dest) {
    ensureDir(dest);
    const entries = fs.readdirSync(src, { withFileTypes: true });
    for (const entry of entries) {
        if (COPY_SKIP_DIRS.has(entry.name))
            continue;
        const srcPath = path.join(src, entry.name);
        const destPath = path.join(dest, entry.name);
        if (entry.isDirectory()) {
            copyDirRecursive(srcPath, destPath);
        }
        else {
            fs.copyFileSync(srcPath, destPath);
        }
    }
}
/**
 * 디렉토리 삭제 (재귀)
 */
export function removeDirRecursive(dir) {
    if (fs.existsSync(dir)) {
        fs.rmSync(dir, { recursive: true, force: true });
    }
}
/**
 * 스킬 복사 (항상 덮어쓰기 — 패키지 업데이트 시 최신 버전 반영)
 */
export function copySkillsOverwrite(src, dest) {
    ensureDir(dest);
    const entries = fs.readdirSync(src, { withFileTypes: true });
    for (const entry of entries) {
        const srcPath = path.join(src, entry.name);
        const destPath = path.join(dest, entry.name);
        if (entry.isDirectory()) {
            copySkillsOverwrite(srcPath, destPath);
        }
        else {
            fs.copyFileSync(srcPath, destPath);
        }
    }
}
/**
 * 레거시 스킬 디렉토리 삭제 (이름 변경된 구 디렉토리 정리)
 */
export function removeLegacySkills(skillsDir, legacyDirs) {
    for (const name of legacyDirs) {
        const dir = path.join(skillsDir, name);
        if (fs.existsSync(dir)) {
            fs.rmSync(dir, { recursive: true, force: true });
        }
    }
}
/**
 * 디렉토리 기반 스킬 모두 정리 — ~/.claude/vibe/skills/ 에 남아있는 {name}/ 디렉토리 제거
 * Claude Code가 ~/.claude/ 재귀 스캔 시 ~/.claude/skills/와 중복 발견되므로 제거 필요
 * flat .md 파일(인라인 스킬)은 유지
 */
export function cleanupDuplicateSkillDirs(skillsDir) {
    if (!fs.existsSync(skillsDir))
        return;
    const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
    for (const entry of entries) {
        if (!entry.isDirectory())
            continue;
        fs.rmSync(path.join(skillsDir, entry.name), { recursive: true, force: true });
    }
}
/**
 * 스킬 필터링 복사 — 허용 목록에 있는 스킬 디렉토리만 복사
 * @param src - 스킬 소스 디렉토리 (skills/)
 * @param dest - 설치 대상 디렉토리
 * @param allowedSkills - 복사할 스킬 이름 목록
 */
export function copySkillsFiltered(src, dest, allowedSkills) {
    ensureDir(dest);
    const entries = fs.readdirSync(src, { withFileTypes: true });
    for (const entry of entries) {
        if (!entry.isDirectory())
            continue;
        if (!allowedSkills.includes(entry.name))
            continue;
        const srcPath = path.join(src, entry.name);
        const destPath = path.join(dest, entry.name);
        copySkillsOverwrite(srcPath, destPath);
    }
}
const CODEX_POLICY_MARKER = '# VIBE managed Codex skill policy';
const CODEX_POLICY_CONTENT = `${CODEX_POLICY_MARKER}
policy:
  allow_implicit_invocation: false
`;
function readUserInvocableFalse(skillPath) {
    const raw = fs.readFileSync(skillPath, 'utf-8');
    const match = raw.match(/^user-invocable:\s*(true|false)\s*$/m);
    return match?.[1] === 'false';
}
function cleanupManagedCodexPolicy(skillDir) {
    const metadataPath = path.join(skillDir, 'agents', 'openai.yaml');
    if (!fs.existsSync(metadataPath))
        return;
    const raw = fs.readFileSync(metadataPath, 'utf-8');
    if (!raw.includes(CODEX_POLICY_MARKER))
        return;
    fs.rmSync(metadataPath, { force: true });
    const agentsDir = path.dirname(metadataPath);
    if (fs.existsSync(agentsDir) && fs.readdirSync(agentsDir).length === 0) {
        fs.rmdirSync(agentsDir);
    }
}
function writeManagedCodexPolicy(skillDir) {
    const agentsDir = path.join(skillDir, 'agents');
    const metadataPath = path.join(agentsDir, 'openai.yaml');
    if (fs.existsSync(metadataPath)) {
        const raw = fs.readFileSync(metadataPath, 'utf-8');
        if (!raw.includes(CODEX_POLICY_MARKER))
            return;
    }
    ensureDir(agentsDir);
    fs.writeFileSync(metadataPath, CODEX_POLICY_CONTENT);
}
/**
 * Codex는 Vibe의 `user-invocable: false` 메타데이터를 직접 해석하지 않는다.
 * 내부 체인 전용 스킬은 공식 Codex skill policy로 implicit invocation을 막는다.
 */
export function applyCodexSkillInvocationPolicies(skillsDir) {
    if (!fs.existsSync(skillsDir))
        return;
    const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
    for (const entry of entries) {
        if (!entry.isDirectory())
            continue;
        const skillDir = path.join(skillsDir, entry.name);
        const skillPath = path.join(skillDir, 'SKILL.md');
        if (!fs.existsSync(skillPath))
            continue;
        if (readUserInvocableFalse(skillPath))
            writeManagedCodexPolicy(skillDir);
        else
            cleanupManagedCodexPolicy(skillDir);
    }
}
//# sourceMappingURL=fs-utils.js.map