/** Schema version stamped on every record, so a later reader can migrate. */ export declare const JOURNAL_RECORD_VERSION = 1; export type JournalRunStatus = "active" | "completed" | "failed" | "cancelled"; /** How a run ended. `active` is the absence of an end record, not a value. */ export type JournalEndStatus = Exclude; export interface JournalNote { at: number; text: string; } export interface JournalArtifact { at: number; /** Whatever the caller called the thing it produced: a content path * (`/Game/Materials/PBR/M_Rock`), a file on disk, or a URL. */ path: string; /** Free-form label for what kind of thing it is (`asset`, `screenshot`, * `log`, `report`). Not an enum: the journal does not know what an agent * will produce, and refusing an unlisted word would lose the record. */ kind?: string; note?: string; } /** One step of an automatically journalled flow run. */ export interface JournalStep { stepNumber: number; name: string; type: string; success: boolean; skipped: boolean; durationMs: number; error?: string; } export interface JournalRun { runId: string; title: string; /** Set when this run was a `flow(action="run")`, absent when a caller * opened it by hand. */ flowName?: string; status: JournalRunStatus; tags: string[]; startedAt: number; endedAt?: number; durationMs?: number; summary?: string; /** Why a cancelled run was cancelled. */ reason?: string; notes: JournalNote[]; artifacts: JournalArtifact[]; steps?: JournalStep[]; /** The project root this run was recorded against, when one was known. */ project?: string; } type StartRecord = { v: number; e: "start"; t: number; id: string; title: string; flowName?: string; tags?: string[]; project?: string; }; type NoteRecord = { v: number; e: "note"; t: number; id: string; text: string; }; type ArtifactRecord = { v: number; e: "artifact"; t: number; id: string; path: string; kind?: string; note?: string; }; type EndRecord = { v: number; e: "end"; t: number; id: string; status: JournalEndStatus; summary?: string; reason?: string; durationMs?: number; steps?: JournalStep[]; }; export type JournalRecord = StartRecord | NoteRecord | ArtifactRecord | EndRecord; /** * The directory holding every project's journal. * * `UE_MCP_JOURNAL_DIR` redirects it, which is what the unit tests use and * what a CI runner that wants the journal as a build artifact would set. */ export declare function journalDir(): string; /** * The journal file for one project root. * * Named `-.jsonl` rather than by a bare basename: two * checkouts of the same project on one machine are the common case, and a * bare `ue_mcp.jsonl` would merge their histories into one unreadable stream. * The hash is taken over the case-folded absolute path because Windows hands * back the same directory under two spellings. */ export declare function journalFile(projectRoot?: string | null): string; /** * Whether the journal records anything at all. * * On by default. An audit trail a user has to remember to switch on is not an * audit trail, and the cost is a few hundred bytes per run in the user's own * `~/.ue-mcp`. `UE_MCP_JOURNAL=0` switches it off for a machine or a session, * and every action reports the setting it is running under. */ export declare function journalEnabled(): boolean; /** Fold the record stream into runs, newest start first. */ export declare function readRuns(file: string): JournalRun[]; /** One run by id, or undefined. */ export declare function readRun(file: string, runId: string): JournalRun | undefined; /** * The run a call means when it names none: the most recently started run that * has not ended. Concurrent runs are possible (two flows, two agents), so this * is a convenience, never an assumption - every mutating action accepts an * explicit runId and says so when it had to guess. */ export declare function activeRun(file: string): JournalRun | undefined; /** A run id unique within this process and sortable by start time. */ export declare function newRunId(): string; export interface StartOptions { title: string; runId?: string; flowName?: string; tags?: string[]; project?: string | null; } /** * Open a run. Idempotent on `runId`: starting an id that already exists * returns the run untouched and reports `existed`, so a retried call after a * timeout does not fork the history into two runs. */ export declare function startRun(file: string, opts: StartOptions): { run: JournalRun; existed: boolean; }; /** Append a note to an open run. */ export declare function addNote(file: string, runId: string, text: string): JournalNote; /** * Attach an artifact to a run. Idempotent on `path` within one run: attaching * the same path twice reports the existing entry rather than duplicating it, * because the common retry is "did that attach land?". */ export declare function addArtifact(file: string, runId: string, artifact: { path: string; kind?: string; note?: string; }): { artifact: JournalArtifact; existed: boolean; }; export interface EndOptions { status: JournalEndStatus; summary?: string; reason?: string; durationMs?: number; steps?: JournalStep[]; } /** * Close a run. Idempotent: ending a run that already ended leaves the first * ending in place and reports `existed`, so the first verdict on a run is the * one that stands. */ export declare function endRun(file: string, runId: string, opts: EndOptions): { run: JournalRun; existed: boolean; } | undefined; /** * Drop one run, or every run, rewriting the file without those records. * * The only operation that does not append. It reports how many runs and how * many records went, because a delete that reports nothing cannot be told * apart from a delete that matched nothing. */ export declare function deleteRuns(file: string, match: { runId?: string; all?: boolean; }): { deletedRuns: string[]; deletedRecords: number; remainingRuns: number; }; export interface JournalFilter { status?: JournalRunStatus; flowName?: string; tag?: string; /** Epoch milliseconds; runs started strictly before this are dropped. */ since?: number; /** Case-insensitive substring over the title, summary and note text. */ contains?: string; limit?: number; } /** The filters `journal_list` accepts, applied in one place so the action and * its tests cannot disagree about what a filter means. */ export declare function filterRuns(runs: JournalRun[], filter: JournalFilter): JournalRun[]; /** Parse a `since` parameter written as epoch milliseconds, an ISO date, or a * relative age like `2h` / `7d` / `30m`. Returns undefined when unparseable, * which the caller turns into an error naming the accepted spellings. */ export declare function parseSince(value: unknown, now?: number): number | undefined; /** A run trimmed to a listing row: enough to choose one, small enough that * twenty of them do not fill a context window. */ export declare function summariseRun(run: JournalRun): Record; /** A run in full, with its notes and artifacts stamped as ISO times. */ export declare function detailRun(run: JournalRun): Record; export {};