/**
 * @module        core/wiki/scaffold
 * @description   `sps wiki init` 的物理脚手架：建目录、写模板、安装 .gitignore 条目
 *
 * @layer         core
 *
 * doc-28 §4 目录结构 + §3 三层架构（per-repo）的实施面。
 *
 * 设计原则：
 *   - **幂等**：重复跑不破坏现有内容
 *   - **不覆盖**：所有写入前先 existsSync 检查
 *   - **单向同步 .gitignore**：只 append 缺失行，不重排已有内容
 *
 * 失败模式：mkdir 失败 → throw（让命令层报错）。
 */
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { wikiAttachmentsDir, wikiDir, wikiHotFile, wikiIndexFile, wikiMetaFile, wikiOverviewFile, wikiPageDir, wikiRawDir, } from '../../shared/wikiPaths.js';
// ─── Constants ────────────────────────────────────────────────────
const ALL_PAGE_TYPES = [
    'module',
    'concept',
    'decision',
    'lesson',
    'source',
];
/** Lines that wiki ownership requires in .gitignore */
const GITIGNORE_LINES = [
    '# Wiki per-instance drift (added by sps wiki init)',
    'wiki/.hot.md',
    'wiki/.log.md',
    'wiki/.manifest.json',
];
/**
 * Default WIKI.md template. Contains schema version + sources config.
 * Worker reads `sources:` to know what to ingest.
 */
function wikiMetaTemplate(projectName, today) {
    return `---
type: meta
title: ${projectName} Wiki
version: 1
created: ${today}
updated: ${today}
sources:
  code:
    - "src/**/*.ts"
  doc:
    - "docs/**/*.md"
    - "README.md"
  raw:
    - "wiki/.raw/**/*"
---

# ${projectName} Wiki

Project knowledge base. See [doc-28](../docs/design/28-wiki-system.md) for design.

## Page Types

- **modules/** — Code modules / services (auto-derived from \`src/\`)
- **concepts/** — Domain concepts and patterns
- **decisions/** — Architecture decisions
- **lessons/** — Bug post-mortems and gotchas
- **sources/** — External references (PDFs, articles, transcripts)

## Workflow

\`\`\`bash
sps wiki update <project>          # ingest source diff via Worker + skill
sps wiki read <project> "query"    # 5-layer retrieval for prompt injection
\`\`\`
`;
}
const INDEX_PLACEHOLDER = `---
type: meta
title: Wiki Index
updated: 1970-01-01T00:00:00Z
---

# Wiki Index

(empty — run \`sps wiki update\` to ingest sources)
`;
const OVERVIEW_TEMPLATE = (projectName, today) => `---
type: meta
title: ${projectName} Overview
created: ${today}
updated: ${today}
---

# ${projectName} Overview

(autogenerated summary — first \`sps wiki update\` will fill this in)
`;
const HOT_PLACEHOLDER = `---
type: meta
title: Hot Cache
updated: 1970-01-01T00:00:00Z
---

# Recent Context

## Last Updated
（尚无活动。第一次 \`sps wiki update\` 或卡片完成后会自动填充。）

## Key Recent Facts
（none yet）

## Recent Changes
（none yet）

## Active Threads
（none yet）
`;
/**
 * Idempotently scaffold wiki/ in the given repo.
 *
 * Creates:
 *   - wiki/, wiki/{modules,concepts,decisions,lessons,sources}/, wiki/.raw/, wiki/_attachments/
 *   - wiki/WIKI.md, wiki/index.md, wiki/overview.md, wiki/.hot.md
 *   - .gitignore: appends per-instance drift entries if missing
 *
 * Does NOT write .manifest.json — that's owned by `sps wiki update` and is empty
 * until first ingest.
 *
 * Re-runnable safely: existing files are preserved.
 */
export function initWiki(repoDir, opts) {
    const today = opts.today ?? new Date().toISOString().slice(0, 10);
    const created = [];
    const filesWritten = [];
    const filesSkipped = [];
    // 1) Subdirs
    const dirs = [
        wikiDir(repoDir),
        ...ALL_PAGE_TYPES.map((t) => wikiPageDir(repoDir, t)),
        wikiRawDir(repoDir),
        wikiAttachmentsDir(repoDir),
    ];
    for (const d of dirs) {
        if (!existsSync(d)) {
            mkdirSync(d, { recursive: true });
            created.push(d);
        }
    }
    // 2) Templated files (don't overwrite existing user content)
    const templated = [
        [wikiMetaFile(repoDir), wikiMetaTemplate(opts.projectName, today)],
        [wikiIndexFile(repoDir), INDEX_PLACEHOLDER],
        [wikiOverviewFile(repoDir), OVERVIEW_TEMPLATE(opts.projectName, today)],
        [wikiHotFile(repoDir), HOT_PLACEHOLDER],
    ];
    for (const [path, body] of templated) {
        if (existsSync(path)) {
            filesSkipped.push(path);
        }
        else {
            writeFileSync(path, body, { encoding: 'utf-8', mode: 0o644 });
            filesWritten.push(path);
        }
    }
    // 3) .gitignore — only append missing lines
    let gitignoreUpdated = false;
    if (!opts.skipGitignore) {
        gitignoreUpdated = ensureGitignoreEntries(repoDir);
    }
    return {
        wikiDir: wikiDir(repoDir),
        created,
        filesWritten,
        filesSkipped,
        gitignoreUpdated,
    };
}
/**
 * Append wiki drift entries to .gitignore if missing.
 *
 * Returns true when at least one line was appended.
 * Creates .gitignore if not present.
 */
export function ensureGitignoreEntries(repoDir) {
    const gitignorePath = resolve(repoDir, '.gitignore');
    let existing = '';
    if (existsSync(gitignorePath)) {
        existing = readFileSync(gitignorePath, 'utf-8');
    }
    const existingLines = new Set(existing.split('\n').map((l) => l.trim()));
    const toAppend = [];
    for (const line of GITIGNORE_LINES) {
        // skip comment header if any drift line already present (we don't want to
        // re-add the comment if user organized their .gitignore)
        if (line.startsWith('#'))
            continue;
        if (!existingLines.has(line)) {
            toAppend.push(line);
        }
    }
    if (toAppend.length === 0)
        return false;
    // If .gitignore is brand new or empty, include the comment header.
    const block = [];
    const needsHeader = !existing.includes('# Wiki per-instance drift');
    if (existing.length > 0 && !existing.endsWith('\n'))
        block.push('');
    if (existing.length > 0)
        block.push('');
    if (needsHeader)
        block.push(GITIGNORE_LINES[0]);
    block.push(...toAppend);
    block.push(''); // trailing newline
    if (existsSync(gitignorePath)) {
        appendFileSync(gitignorePath, block.join('\n'), { encoding: 'utf-8' });
    }
    else {
        writeFileSync(gitignorePath, block.join('\n').replace(/^\n+/, ''), {
            encoding: 'utf-8',
            mode: 0o644,
        });
    }
    return true;
}
//# sourceMappingURL=scaffold.js.map