import { getTranscriptArchiveRoot } from "./paths/paths.js";
import { type IndexEntry, type ProjectsRegistry, type RunManifest } from "./transcript-archive-types.js";
export interface ProjectIdentity {
prefix: string;
name: string;
projectDir: string;
}
/**
* Read `{prefix, name, projectDir}` from a `.forge/config.json`. Defaults on
* any failure (missing file, malformed JSON, absent fields) — never throws.
* `projectDir` is derived from the config path itself (`
/.forge/config.json`).
*/
export declare function readProjectIdentity(configPath: string): ProjectIdentity;
/**
* `-` — prefix alone can
* collide across projects (two repos both named "FORGE"); the path hash
* disambiguates. Falls back to the raw path when realpath throws (deleted
* or unmounted project dir — archive entries must remain addressable).
*/
export declare function computeProjectKey(projectDir: string, prefix: string): string;
interface PhaseFileInfo {
/** Absolute path to the project-local phase transcript JSON. */
absPath: string;
/** Basename, e.g. "20260601T100100Z__CART-BUG-001__triage.json". */
file: string;
/** Compact ISO prefix from the filename. */
ts: string;
/** Role segment from the filename (third "__" part onward). */
role: string;
}
/** One discovered run: source files + the manifest built from them. */
export interface DiscoveredRun {
runId: string;
jsonlPath: string;
phaseFiles: PhaseFileInfo[];
/** Live tail-view logs (`*.tail.jsonl`) belonging to this run. */
tailFiles: PhaseFileInfo[];
manifest: RunManifest;
}
interface BuildOptions {
/** Sprint back-reference stamped onto the manifest (run-sprint wiring). */
sprintId?: string;
}
/**
* Discover every run in a project-local entity transcript dir
* (`.forge/transcripts//`) and build a RunManifest for each.
*
* A "run" is one orchestrator JSONL file; its runId is the compact-ISO
* pipeline-start timestamp (falling back to the filename prefix). Phase
* transcript files are assigned to the latest run whose start precedes
* them — compact ISO prefixes compare lexicographically as timestamps.
*/
export declare function buildRunsForEntityDir(entityDir: string, identity: ProjectIdentity, projectKey: string, opts?: BuildOptions): DiscoveredRun[];
export interface ArchiveRunResult {
archived: boolean;
runDir?: string;
error?: string;
}
export interface ArchiveRunOptions {
/** Project dir (the dir containing `.forge/`). */
cwd: string;
/** Project-local orchestrator JSONL path for the run to archive. */
orchestratorJsonlPath: string;
/** Sprint back-reference for sprint-nested task runs. */
sprintId?: string;
/** Override for `/.forge/config.json` (tests). */
configPath?: string;
}
/**
* Archive the run identified by its project-local orchestrator transcript.
* Called by orchestrators after the pipeline result is known. Best-effort,
* never throws.
*/
export declare function archiveRun(opts: ArchiveRunOptions): ArchiveRunResult;
export interface SweepResult {
adopted: number;
errors: number;
}
/**
* Adopt orphans: archive every project-local run whose runId isn't in the
* central index. Covers crash recovery (pipeline died before its archive
* call) and adoption of pre-existing history (transcripts written before
* this feature shipped). Called best-effort at pipeline start; never throws.
*/
export declare function sweepProjectTranscripts(cwd: string, configPath?: string): SweepResult;
/** Read index.jsonl — skips malformed/truncated lines, never throws. */
export declare function readIndex(): IndexEntry[];
/** Read projects.json — empty registry on any failure, never throws. */
export declare function readProjects(): ProjectsRegistry;
/** Read `/manifest.json` — null on missing/truncated/mismatched. */
export declare function readManifest(runDir: string): RunManifest | null;
/**
* Gunzip + parse an archived phase transcript. `file` is the manifest's
* phase `file` field (without `.gz`). Null on any failure, never throws.
*/
export declare function gunzipPhase(runDir: string, file: string): Record | null;
/** One persisted live tail-view line (see viewport/events.ts TailLogEntry). */
export interface ArchivedTailEntry {
line: string;
warning?: boolean;
}
/**
* Gunzip + parse an archived live tail log (`*.tail.jsonl.gz`). Returns the
* exact lines the dashboard rendered during the run, in order. Tolerant of
* truncated tails; null when the file is missing/unreadable. Never throws.
*/
export declare function gunzipTailLog(runDir: string, file: string): ArchivedTailEntry[] | null;
/** Resolve the archive dir for an index entry. */
export declare function runDirForEntry(entry: IndexEntry): string;
/**
* Per-turn digest of a gunzipped phase payload — never a raw JSON dump.
* Each assistant message is a turn: first text line + tool-call names;
* toolResult messages render as compact result markers.
*/
export declare function digestPhasePayload(payload: Record): string[];
/**
* VERBOSE digest of a gunzipped phase payload — the replay-dashboard feed.
* Unlike digestPhasePayload (compact markers for the `show` table), this
* carries the actual transcript content so a replayed run is readable:
* full assistant text (capped per turn), thinking first-lines, tool-call
* argument previews, and tool-result first-line previews.
*
* Multi-line assistant text is pushed as ONE entry — the dashboard splits
* lines at display time, and the tree's per-entry char cap still applies.
*/
export declare function digestPhasePayloadVerbose(payload: Record): string[];
export { getTranscriptArchiveRoot };