/** * The Staves format (spec/) in and out. * * A board is stored as an op log; the format is the interchange: one readable snapshot other tools can * validate and diff. `toStavesDocument` follows spec/DECISIONS.md: the core carries what the spec defines, * `io.staves.measures` and `io.staves.detail` carry the optional detail, and `io.staves.app` carries * Staves' own state so a board read back is the board that was written. Tombstones are not exported, and * neither is inline instruction text. */ import type { Artifact, Board, Job, Provenance, Track } from "./model.js"; import type { Prerequisites } from "./flow.js"; export declare const STAVES_FORMAT_VERSION = "0.1"; export declare const STAVES_SCHEMA_ID = "https://staves.io/spec/0.1/board.schema.json"; export declare const APP = "io.staves.app"; export declare const MEASURES = "io.staves.measures"; export declare const DETAIL = "io.staves.detail"; export type Method = "interview" | "drawn" | "document" | "code" | "trace" | "inferred"; export interface Source { method: Method; by?: string; at?: string; ref?: string; confidence?: number; confirmed?: boolean; } export type ProvenanceMap = Record; export interface Dispute { field: string; claims: { value: unknown; source: Source; }[]; } export interface Ref { type: string; uri?: string; id?: string; path?: string; symbol?: string; server?: string; name?: string; } export type Extensions = Record>; interface Common { provenance?: ProvenanceMap; disputes?: Dispute[]; refs?: Ref[]; extensions?: Extensions; } export interface DocTrack extends Common { id: string; name: string; kind: Track["kind"]; description?: string; } export interface DocArtifact extends Common { id: string; name: string; kind: Artifact["kind"]; external?: boolean; livesIn?: string; note?: string; } export interface DocExit { condition: string; target?: string; share?: number; } export interface DocGate { rule: string; accountable?: string; ruleOwner?: string; } export interface DocTool { name: string; reach: "api" | "mcp" | "screen" | "none"; personal?: boolean; does?: string; limits?: string; refs?: Ref[]; extensions?: Extensions; } export interface DocEvidence { system: string; traceId: string; spanId?: string; graphNodeId?: string; observedAt: string; status: "ok" | "error"; durationMs?: number; mapping?: { method: "instrumented" | "proposed" | "reviewed"; by?: string; at?: string; }; } export interface DocJob extends Common { id: string; name: string; track: string; parent?: string; kind?: "work" | "queue" | "store" | "watch" | "outside"; outcome?: string; beneficiary?: string; doneWhen?: string[]; inputs: string[]; outputs: string[]; trigger?: NonNullable; triggerNote?: string; prerequisites?: { kind: Prerequisites["kind"]; inputs: string[]; condition?: string; }; exits?: DocExit[]; gate?: DocGate; loop?: { to: string; limit?: number; then?: string; }; tools?: DocTool[]; status?: "draft" | "confirmed"; change?: "added" | "changed" | "moved" | "removed" | "unchanged"; order?: number; evidence?: DocEvidence[]; } export interface DocHandoff { id: string; from: string; to: string; kind: "artifact" | "exit" | "loop"; artifact?: string; condition?: string; } export interface StavesDocument extends Common { $schema?: string; staves: string; id: string; title: string; goal?: string; stance: "as-is" | "to-be"; base?: string; tracks: DocTrack[]; artifacts: DocArtifact[]; jobs: DocJob[]; handoffs?: DocHandoff[]; } /** Kept as written, with the view the board would have written in its place. */ interface Kept { value: T; basis: string; } /** * What a document held that a board has no field for: unknown extensions, evidence from systems other * than Langfuse, reference types Staves does not model, provenance finer than Staves records. Each part is * kept exactly as written and put back on export, unless the board has since changed what that part * describes — then the board's own view is written instead. */ export interface Passthrough { board?: { provenance?: ProvenanceMap; refs?: Ref[]; extensions?: Extensions; }; tracks?: Record; refs?: Ref[]; extensions?: Extensions; }>; artifacts?: Record; jobs?: Record; refs?: Kept; tools?: Kept; evidence?: DocEvidence[]; extensions?: Extensions; }>; } /** A board read from a document carries its passthrough under the app namespace. src/model.ts has no * field for it, so it lives on the board object only: it survives a JSON copy and a write back to the * format, but not a save to a Staves store. */ export type StavesBoard = Board & { [APP]?: { passthrough: Passthrough; }; }; export declare const passthroughOf: (board: Board) => Passthrough | undefined; /** A Staves provenance as a format source. `agent` is `code` when it names a commit or the job names its * code, and `inferred` otherwise; a person's word is `drawn` on a drawn board and `interview` elsewhere. */ export declare function toSource(p: Provenance, context?: { drawn?: boolean; code?: { path: string; symbol?: string; }; }): Source; /** A format source as a Staves provenance. */ export declare function fromSource(s: Source): Provenance; export interface ToStavesOptions { /** list derived handoffs for consumers that cannot derive them (default true) */ handoffs?: boolean; } export declare function toStavesDocument(board: Board, options?: ToStavesOptions): StavesDocument; /** Handoffs, derived as spec §4.9 says, with its deterministic ids. */ export declare function documentHandoffs(doc: Pick): DocHandoff[]; export interface ImportedBoard { board: Board; /** what the document held that a Staves board cannot yet carry */ notes: string[]; } export declare function fromStavesDocument(doc: unknown): Board; export declare function importStavesDocument(input: unknown): ImportedBoard; /** Drop undefined properties, so a document has no keys a schema would read as present. */ export declare function compact(value: T): T; export {};