import { type StoreFs } from './store/index.js';
/**
 * The committed conversations (#908): the human turns and the agent's replies of a run, kept in
 * the Git repo so a clone carries the chat and not just the fact a run happened (#857).
 *
 * Deliberately not the verbose transcript — #857 leaves the tool-call-level log to the model
 * provider, which is also the standing policy in run-store.ts. What lands here is what a person
 * would reread: what was asked, and what came back.
 *
 * One file per run rather than one shared file, because run worktrees are live concurrently and
 * each auto-commits its own pending work on teardown; a shared file would be a merge conflict
 * every time two runs chatted at once. The run id is the join key back to the `- run:` field
 * LOGS.md records (#898), so the committed session list and the committed chat line up.
 *
 * Pure core over the same {@link StoreFs} seam as logs.ts.
 */
/** The directory, under `.the-framework/`, that holds one markdown file per conversation. */
export declare const CONVERSATIONS_DIR = "conversations";
/**
 * The `.the-framework/.gitignore` that keeps run state transient while committing the DB. The
 * conversations rules need both entries: the `*` rule makes git skip the directory without ever
 * descending into it, so un-ignoring the files alone would never be reached.
 */
export declare const CONVERSATIONS_GITIGNORE = "!conversations/\n!conversations/**\n";
/** Who said it. The transport is {@link ConversationMessage.via}, not this. */
export type ConversationRole = 'user' | 'agent';
/** One turn in a conversation. */
export interface ConversationMessage {
    /** ISO timestamp. */
    at: string;
    role: ConversationRole;
    /**
     * The surface the turn came through — `dashboard`, `discord`, … Recorded so a conversation
     * read back shows where it happened, while this module stays free of any transport.
     */
    via: string;
    /** The message. Multi-line and kept that way; only line-leading markers are escaped. */
    text: string;
}
/**
 * Whether a transport name is safe to record. Exported because #917 lets a surface name itself
 * over the control channel, so the name now arrives from outside this module: a `via` carrying
 * the heading separator, a newline or a `#` would forge structure in a file whose entries are
 * line-parsed, exactly the way #897 forged a LOGS.md title. Checked at the boundary rather than
 * trusted, and the same predicate {@link parseConversation} reads back with.
 */
export declare function isSafeVia(via: unknown): via is string;
/**
 * Escape a message body so it cannot forge structure (#897's threat model, applied to a
 * transcript). LOGS.md collapses free text to one line, which is right for a line-parsed record
 * and wrong here: a multi-paragraph reply has to stay readable in a `git diff`. So the text stays
 * as written and only a line's leading `#` or `\` is escaped, which is enough — an entry is only
 * ever started by a line beginning `## `. Reversed by {@link unescapeBody}.
 */
export declare function escapeBody(text: string): string;
/** Reverse {@link escapeBody}. */
export declare function unescapeBody(text: string): string;
/** The directory holding every conversation under `cwd`. */
export declare function conversationsDir(cwd: string): string;
/**
 * One conversation's path. `undefined` for an unsafe run id: the id reaches this from a run
 * store and, once #680 lands, indirectly from a chat surface, so it is checked rather than
 * trusted into a path.
 */
export declare function conversationPath(cwd: string, runId: string): string | undefined;
/** Markdown for one message, starting at `## ` (no file header, no blank lines around it). */
export declare function renderMessage(message: ConversationMessage): string;
/**
 * Parse every message out of the markdown, in file order (append order, so oldest-first — a
 * transcript reads forwards, unlike the newest-first project log). Forgiving: a malformed or
 * torn message is skipped, never thrown.
 */
export declare function parseConversation(md: string): ConversationMessage[];
/**
 * Make sure `.the-framework/.gitignore` un-ignores the conversations dir, returning whether it
 * wrote. Done lazily on append rather than only at install time: the seeded ignore file is
 * written once and only when absent (`install.ts`), so every repo activated before this feature
 * still carries the old three-line allow-list and would silently drop its own conversations.
 *
 * Only ours is upgraded — a file we do not recognize is left alone rather than appended to.
 */
export declare function ensureConversationsIgnored(cwd: string, fs?: StoreFs): Promise<boolean>;
/**
 * Append one message to `.the-framework/conversations/<runId>.md`, creating the dir, the
 * one-time file header, and the ignore rule when absent. A raw write (may reject); the caller
 * decides best-effort. A no-op for an unsafe run id.
 */
export declare function appendMessage(cwd: string, runId: string, message: ConversationMessage, fs?: StoreFs): Promise<void>;
/** Read one conversation, oldest-first. Missing file (or unsafe id) yields `[]`. */
export declare function readConversation(cwd: string, runId: string, fs?: StoreFs): Promise<ConversationMessage[]>;
/** The run ids that have a committed conversation, sorted. Missing dir yields `[]`. */
export declare function listConversations(cwd: string, fs?: StoreFs): Promise<string[]>;
//# sourceMappingURL=conversations.d.ts.map