/**
 * WikiIngestService — write canonical pages into a vault's `llm-curated/`.
 *
 * Phase A scope per v2.1 spec: append entries to `llm-curated/log.md` for
 * every chat/spec/learning source. Decisions/pattern pages (separate files
 * under `llm-curated/decisions/`) are gated behind the LLM routing layer
 * which lands in Phase B.
 *
 * Frozen-path contract (§2): refuses ANY write whose target lives under a
 * `hardcoded:` folder. SchemaLoaderService.isFrozenPath() is the gate.
 *
 * @module services/wiki/wiki-ingest.service
 */
import { SchemaLoaderService } from './schema-loader.service.js';
/**
 * Categories of sources that trigger ingest. Mirrors §4 (ingest trigger
 * taxonomy) plus `user_chat` for the demo path.
 */
export type WikiSourceType = 'user_chat' | 'slack_message' | 'spec_file' | 'pr_merge' | 'record_learning' | 'task_verified';
export interface WikiIngestInput {
    /** Absolute path to the vault root (containing SCHEMA.md). */
    vaultPath: string;
    /** Where the content came from. */
    sourceType: WikiSourceType;
    /** Stable reference for audit (URL, file path, WI id, chat msg id). */
    sourceRef: string;
    /** Body content to ingest. Empty bodies are rejected. */
    sourceBody: string;
    /** Session/user that authored the source — appears in the log header. */
    callerSession?: string;
    /** Optional override of the relative target path; defaults to `llm-curated/log.md`. */
    targetRelativePath?: string;
}
export interface WikiIngestResult {
    ok: true;
    pagesWritten: string[];
    logEntry: string;
    frozenPathsTouched: string[];
}
export interface WikiIngestRefusedFrozen {
    ok: false;
    reason: 'frozen_path';
    attemptedPath: string;
    frozenFolders: string[];
}
export interface WikiIngestRefusedInvalid {
    ok: false;
    reason: 'invalid_input' | 'schema_missing' | 'empty_body';
    message: string;
}
export type WikiIngestOutcome = WikiIngestResult | WikiIngestRefusedFrozen | WikiIngestRefusedInvalid;
/**
 * Writes ingest pages to a vault. Construct one per process; stateless.
 */
export declare class WikiIngestService {
    private static instance;
    private readonly logger;
    private readonly schemaLoader;
    constructor(schemaLoader?: SchemaLoaderService);
    static getInstance(): WikiIngestService;
    /** Test-only reset. */
    static _resetForTesting(): void;
    /**
     * Ingest a single source into the vault.
     *
     * Errors are returned as structured outcomes — this method never throws
     * on legitimate refusals (frozen path, missing schema, empty body) so
     * callers can fold the result into their normal control flow.
     */
    ingest(input: WikiIngestInput): Promise<WikiIngestOutcome>;
    private validateInput;
    /**
     * Build the markdown entry. Format is chosen to be safely append-only
     * (no preceding section to rewrite) and grep-friendly:
     *
     *   ## [<ISO>] <sourceType> | <callerSession or sourceRef>
     *
     *   ref: <sourceRef>
     *
     *   <body>
     */
    private formatLogEntry;
    private appendOrCreate;
    /**
     * Pick the right header for a freshly-created page:
     *   - `log.md`            → audit-log preamble (append-only)
     *   - `decisions/*.md`    → decision-page title + provenance block
     *   - anything else       → minimal title block from the source ref
     */
    private buildPageHeader;
    /**
     * Defuse markers a future skill might mis-route on: `[CHAT]`, `[NOTIFY]`,
     * `[EVENT]`, `[ESCALATION]` get a zero-width space inserted so they're
     * still human-readable but don't trigger regex matchers downstream.
     * (Mirrors the escalation-router sanitizer from PR #606.)
     */
    private sanitizeBody;
    private sanitizeOneLine;
}
//# sourceMappingURL=wiki-ingest.service.d.ts.map