/** * Configuration editing service for the web console. * * Owns the read → draft → validate → review → atomic-save cycle over the sole * `tmux-pilot.config.yaml` entry document: * * - `readSnapshot` composes entry + imports and resolves every catalogued field * to an effective value plus a source classification (entry / import / global * / harness / default); * - `applyOperations` replays typed draft operations against a CLONED YAML * `Document`, so unrelated comments, imports, nodes, and ordering survive; * - `reviewDraft` composes the candidate without writing and returns candidate * YAML, refreshed state, diagnostics, and a before/after change summary; * - `saveDraft` re-reads the entry, enforces the expected revision, and writes * through a sibling temp file + atomic rename. * * Imported documents are READ-ONLY inputs: every write targets the entry * document only. No server-side draft is retained — the browser holds the draft * and the revision keeps concurrent tabs and external editors honest. * * Core module — no pi imports, no harness-implementation imports. Registered * harness facts arrive as plain `RegisteredHarnessInfo` data from the host. */ import { type Document } from "yaml"; import { type ConfigScopeId } from "#src/config-catalog"; import type { ConfigDiagnostic } from "#src/config-diagnostics"; /** Where a field's effective value came from. */ export type ConfigSource = "entry" | "import" | "global" | "harness" | "default"; /** Facts the host knows about a registered harness. Plain data — no harness types. */ export interface RegisteredHarnessInfo { id: string; /** True when the harness declares a `configProfile` (config-dir override support). */ supportsConfigDirectory: boolean; /** Declared stop combo, when the harness publishes one. */ defaultStopKeyCombo?: string; /** Declared identity, when the harness publishes one. */ colorHex?: string; sigil?: string; /** Declared completion-sentinel kind, when the harness publishes one. */ sentinelKind?: string; } export interface HarnessMeta extends RegisteredHarnessInfo { /** Registered in the running extension. */ registered: boolean; /** Mentioned by the configuration (harness defaults or a routing field). */ configured: boolean; /** Effective stop combo default before any YAML override. */ stopKeyComboDefault: string; /** * Fully resolved identity (declaration > core token map > neutral fallback) * — the exact color/sigil the terminal widget renders for this harness. The * client consumes these and never re-implements identity resolution. */ resolvedColorHex: string; resolvedSigil: string; } export interface ResolvedField { /** Concrete canonical path (placeholders substituted). */ path: string[]; /** Catalog pattern this field resolves. */ pattern: string; scope: ConfigScopeId; /** Effective value after composition and inheritance; absent when unset. */ effective?: unknown; /** The entry document's own value, when it has one. */ local?: unknown; source: ConfigSource; /** Canonical path the inherited value came from (source global/harness). */ inheritedFrom?: string[]; } export interface RoleSummary { name: string; /** The entry document declares this role (wholly or as overrides). */ hasLocalOverrides: boolean; /** An imported document declares this role. */ imported: boolean; /** * Owned solely by the entry document. Only a local-only role may be renamed * or deleted — merge semantics cannot express removing an imported role. */ localOnly: boolean; /** Resolved harness id — the harness inheritance layer for this role's fields. */ harness: string; /** * The exact portrait glyph the terminal widget renders for this role * (customized portrait glyph, else role-keyword glyph when customized, else * the harness sigil) — mirrors the widget's `resolvePortraitIcon`. */ portraitGlyph: string; /** The exact resolved portrait color (role-color, else harness identity). */ portraitColor: string; /** Optional effective agent-definition frontmatter description. */ description?: string; /** Primary model id (first in the resolved fallback list). */ primaryModel?: string; /** Provider for the primary model. */ primaryProvider?: string; /** Resolved context window tokens for the primary model. */ contextWindow: number; } export interface ImportSummary { /** Declared import patterns, in entry-document order. */ declared: string[]; /** Resolved absolute file paths, depth-first. */ files: string[]; } export interface ConfigSnapshot { entryPath: string; /** Revision of the exact entry bytes, or the missing-file sentinel. */ revision: string; /** True when the entry file does not exist yet. */ missing: boolean; /** Exact entry file text ("" when missing). */ entryText: string; /** The entry document's own canonical data (imports stripped). */ entryData: Record; /** What the imports alone contribute. */ importedData: Record; /** Composed canonical data (imports ← entry). */ composed: Record; fields: ResolvedField[]; roles: RoleSummary[]; harnesses: HarnessMeta[]; imports: ImportSummary; diagnostics: ConfigDiagnostic[]; } /** A typed draft operation against the entry document. */ export type ConfigOperation = /** Create or update a local override at a canonical path. */ { op: "set"; path: string[]; value: unknown; } /** Remove a local override, restoring the inherited or default value. */ | { op: "delete"; path: string[]; } /** Replace an ordered collection wholesale (models / turn-thresholds). */ | { op: "replace-sequence"; path: string[]; items: unknown[]; } | { op: "create-role"; name: string; } | { op: "duplicate-role"; from: string; name: string; } | { op: "rename-role"; from: string; to: string; } | { op: "delete-role"; name: string; } | { op: "remove-role-overrides"; name: string; }; export type ConfigDraft = { kind: "operations"; operations: ConfigOperation[]; } /** Advanced mode: complete candidate text for the sole entry document. */ | { kind: "text"; text: string; }; export interface ChangeSummary { path: string[]; kind: "added" | "changed" | "removed"; /** Effective value before the draft. */ before?: unknown; /** Effective value after the draft. */ after?: unknown; /** True when the entry document itself carries the value after the draft. */ local: boolean; } export interface DraftReview { /** Candidate entry YAML, exactly as it would be written. */ candidateText: string; /** Revision the review is based on. */ revision: string; diagnostics: ConfigDiagnostic[]; errors: ConfigDiagnostic[]; warnings: ConfigDiagnostic[]; changes: ChangeSummary[]; /** Refreshed effective state from the candidate; absent when it will not compose. */ snapshot?: ConfigSnapshot; /** False when a blocking error is present. */ canSave: boolean; } export type SaveResult = { status: "saved"; revision: string; snapshot: ConfigSnapshot; review: DraftReview; } /** The entry file changed under the draft; nothing was written. */ | { status: "conflict"; revision: string; snapshot: ConfigSnapshot; } /** The candidate has blocking errors; nothing was written. */ | { status: "invalid"; review: DraftReview; } /** The write itself failed; the prior file is intact where the platform permits. */ | { status: "error"; message: string; }; /** Sentinel revision for an entry file that does not exist yet. */ export declare const MISSING_REVISION = "missing"; /** The entry path for a config directory. */ export declare function entryPathFor(configDir: string): string; export interface SnapshotOptions { entryPath: string; /** Harnesses registered in the running extension. */ harnesses?: readonly RegisteredHarnessInfo[]; /** Compose this text instead of the file's bytes (candidate review). */ candidateText?: string; } /** * Compose the configuration and resolve every catalogued field. * * Reads the entry file's exact bytes for the revision, composes imports from * disk, and classifies each field's source. Never writes. */ export declare function readSnapshot(options: SnapshotOptions): ConfigSnapshot; /** * Replay draft operations against `doc` (which the caller must already have * cloned). Returns diagnostics for operations that are unsafe or impossible; * an operation that produces an error is not applied. */ export declare function applyOperations(doc: Document, operations: readonly ConfigOperation[], snapshot: ConfigSnapshot): ConfigDiagnostic[]; export interface ReviewOptions { entryPath: string; draft: ConfigDraft; harnesses?: readonly RegisteredHarnessInfo[]; /** Pre-read base snapshot; re-read from disk when absent. */ base?: ConfigSnapshot; } /** * Apply a draft to a fresh entry document, compose the candidate, and report * what would happen. Writes nothing. */ export declare function reviewDraft(options: ReviewOptions): DraftReview; export interface SaveOptions extends ReviewOptions { /** Revision the draft was based on. A mismatch is a conflict. */ expectedRevision: string; /** Save despite warnings. Warnings alone never block; errors always do. */ acceptWarnings?: boolean; } /** * Validate and atomically save a draft. * * Re-reads the entry file first: a revision mismatch is reported as a conflict * and nothing is written. */ export declare function saveDraft(options: SaveOptions): SaveResult; //# sourceMappingURL=config-editor.d.ts.map