import type { PluginOption } from 'vite'; import type { QaCaptureRunner, QaCaptureServiceOptions, } from './qa.js'; export * from './qa.js'; export interface PygmalionInventoryContext { sourceRoot: string; outputRoot: string; projectRoot: string; mirrorRoot: string; commit: string; } export interface PygmalionInventoryConfig { script?: string; command?: string; args?: string[] | ((context: PygmalionInventoryContext) => string[]); cwd?: string; outputRoot?: string; /** * Generator-owned paths relative to the host application root. The dedicated * mirror restores these paths before synchronization and rejects any change * the generator leaves outside them. */ outputs?: string[]; /** * Ignored runtime/configuration files the generator must not change. Paths * are relative to appRoot; each entry must name a file, not a directory. * Pygmalion compares bounded content signatures immediately around generation * without walking .git, node_modules, or other unrelated trees. At most 64 * files totaling 16 MiB may be declared. */ runtimeInputs?: string[]; /** Reuse generated outputs only while the declared external generator inputs match. */ cache?: { /** Change when generator behavior not represented by inputs changes. */ key: string; /** Files relative to editorRoot, including the generator and its local imports. */ inputs: string[]; }; generate?: (context: PygmalionInventoryContext) => void | Promise; } export interface PygmalionDependencyConfig { lockFile?: string; modulesDirectory?: string; installCommand?: string; installArgs?: string[]; } export interface PygmalionInspectConfig { endpoint?: string; legacyEndpoints?: string[]; normalizeValue?: (property: string, value: string) => string; } export interface PygmalionMirrorConfig { root?: string; appRoot?: string; prefix?: string; control?: string; previewPort?: number; /** Bounded reuse of recently visited preview servers. Defaults to two entries and five minutes. */ runtimePool?: { maxEntries?: 1 | 2; idleMs?: number }; } export interface PygmalionHistoryQaContext { phase: 'before' | 'after'; sessionId: string; sourceRevision: string; headSha: string; revision: number; files: string[]; appRoot: string; previous?: Record; signal?: AbortSignal; } export interface PygmalionSessionConfig { /** Both phases must pass before a history mutation is retained. Failure restores HEAD, files and audit history. */ historyQa?(context: PygmalionHistoryQaContext): Promise<{ status: 'passed' | 'failed' | 'blocked'; [key: string]: unknown }>; prefix?: string; control?: string; previewPort?: number; worktreesRoot?: string; } export interface PygmalionPreviewCaptureWorkerConfig { /** * Host-owned warm capture worker script, relative to the application root. * The script speaks the preview capture worker protocol (JSON lines over * stdio) and keeps its expensive boot warm across artifact requests. */ script: string; args?: readonly string[]; env?: Record; /** Idle shutdown delay for the worker process. Default: 300000. */ idleMs?: number; /** Per-job timeout before the worker is killed and restarted. Default: 1200000. */ jobTimeoutMs?: number; } export interface PygmalionRevisionCatalogConfig { /** * JSON catalog generated inside each source checkout, relative to appRoot. * The mirror inventory step should own this file and stamp its exact commit. */ file: string; /** Defaults to `${artifactEndpoint}/catalog`. */ endpoint?: string; } export interface PygmalionPreviewCaptureProgressEvent { phase: 'queued' | 'preparing' | 'capturing' | 'retrying' | 'finalizing'; completed: number; total: number; frameId?: string; captureStatus?: string; } export interface PygmalionPreviewCaptureGeneratorOptions { onProgress?: (progress: PygmalionPreviewCaptureProgressEvent) => void; /** Stop obsolete work and settle only after it has stopped reading the source. */ signal?: AbortSignal; } export interface PygmalionPreviewFrameRequest { id: string; fingerprint?: string; /** Identity of the complete capture recipe represented by `fingerprint`. */ recipeFingerprint?: string; /** Opaque JSON recipe forwarded unchanged to the host capture generator. */ recipe?: Readonly>; } export interface PygmalionPreviewConfig { configFile?: string; viteConfig?: string; viteBin?: string; /** * Vite mode for the mirror and session preview servers. * * Those run as separate Vite processes, so the editor's own `--mode` never * reaches the previewed application. Set this when a captured screen depends * on a specific env file — for example a feature flag that has to be off for * the screen to exist at all. Defaults to Vite's own default mode. */ mode?: string; mirrorPort?: number; sessionPort?: number; artifactFile?: string; artifactEndpoint?: string; /** * Source files, relative to the app root, that every captured screen depends * on although no rendered element names them: boot code, host bridges, test * doubles. A change to any of them retires reusable captures. */ bootSourceFiles?: readonly string[]; generateArtifact?: ( request: { namespace: string; sourceRevision: string; frames?: readonly PygmalionPreviewFrameRequest[]; captureBaseUrl?: string; }, options?: PygmalionPreviewCaptureGeneratorOptions, ) => unknown | Promise; /** * Warm capture worker used to satisfy artifact generation requests when * `generateArtifact` is absent. When both are set, `generateArtifact` wins. */ captureWorker?: PygmalionPreviewCaptureWorkerConfig; /** Exact-checkout screen catalog served before preview artifacts are probed. */ catalog?: false | PygmalionRevisionCatalogConfig; } export interface PygmalionQaConfig extends Omit { /** * Host-owned capture CLI, relative to the application root. Pygmalion owns * orchestration, validation, baseline storage, and pixel comparison. */ captureScript?: string; captureRunner?: QaCaptureRunner; } export interface PygmalionProjectConfig { configRoot?: string; projectRoot: string; appRoot?: string; editorRoot?: string; /** * Page paths that mount the editor, such as `/design`. During development * their HTML carries a loading bar with real module-loading progress until * the editor renders, instead of a blank page. Paths below one also match. */ editorPaths?: string[]; appDirectory?: string; sourceDirectory?: string; mirrorRoot?: string; mirrorAppRoot?: string; source?: { remote?: string; branch?: string; /** * Local git ref or commit used as the source revision for both the mirror * and design editing sessions, without fetching the configured remote. */ ref?: string; }; inventory?: PygmalionInventoryConfig; dependencies?: PygmalionDependencyConfig; inspect?: false | PygmalionInspectConfig; mirror?: false | PygmalionMirrorConfig; sessions?: false | PygmalionSessionConfig; preview?: PygmalionPreviewConfig; qa?: false | PygmalionQaConfig; } export interface ResolvedPygmalionProject { configRoot: string; projectRoot: string; appRoot: string; editorRoot: string; editorPaths: string[]; appDirectory: string; sourceDirectory: string; branch: string; remote: string; ref?: string; mirrorRoot: string; mirrorAppRoot: string; mirror: false | PygmalionMirrorConfig; sessions: false | PygmalionSessionConfig; inspect: false | PygmalionInspectConfig; preview: PygmalionPreviewConfig; qa: false | PygmalionQaConfig; dependencies: PygmalionDependencyConfig; inventory?: PygmalionInventoryConfig; } export declare function definePygmalionProject< T extends PygmalionProjectConfig, >(config: T): T; export declare function resolvePygmalionProject( config: PygmalionProjectConfig, ): ResolvedPygmalionProject; export declare function createPygmalionVitePlugins( config: PygmalionProjectConfig, ): PluginOption[]; export declare const PYGMALION_PREVIEW_ARTIFACT_ENDPOINT: string; export declare const PYGMALION_PREVIEW_CAPTURE_PROGRESS_SUFFIX: string; export declare const PYGMALION_REVISION_CATALOG_SUFFIX: string; export declare const DEFAULT_PYGMALION_PREVIEW_ARTIFACT_FILE: string; export declare function pygmalionPreviewArtifactPlugin(options?: { root?: string; artifactFile?: string; endpoint?: string; /** Requires `acquireSourceLease`; the catalog is never read without one. */ catalogFile?: string; catalogEndpoint?: string; disabled?: () => boolean; generateArtifact?: ( request: { namespace: string; sourceRevision: string; frames?: readonly PygmalionPreviewFrameRequest[]; captureBaseUrl?: string; }, options?: PygmalionPreviewCaptureGeneratorOptions, ) => unknown | Promise; acquireLease?: ( reason: string, ) => | { release(): void | Promise } | null | Promise<{ release(): void | Promise } | null>; /** Holds an exact checkout for catalog reads and the whole artifact capture. */ acquireSourceLease?: ( sourceRevision: string, label: string, ) => | { sourceRoot: string; sourceRevision: string; /** Revalidates direct worktrees that cannot be held by a mirror lease. */ validate?(): boolean | Promise; release(): void | Promise; } | null | Promise<{ sourceRoot: string; sourceRevision: string; /** Revalidates direct worktrees that cannot be held by a mirror lease. */ validate?(): boolean | Promise; release(): void | Promise; } | null>; requestRuntime?: () => void; runtimePrepared?: () => boolean; artifactStoreMaxBytes?: number; /** Source files every capture depends on; see `PygmalionPreviewConfig.bootSourceFiles`. */ artifactBootSourceFiles?: readonly string[]; }): PluginOption; export interface PygmalionPreviewCaptureWorkerPayload { namespace: string; sourceRevision: string; captureBaseUrl?: string; frames: PygmalionPreviewFrameRequest[] | null; } export type PygmalionPreviewCaptureWorkerRequest = | { type: 'ping'; id: string | null } | { type: 'capture'; id: string; payload: PygmalionPreviewCaptureWorkerPayload }; export declare function parsePreviewCaptureWorkerRequestLine(line: string): PygmalionPreviewCaptureWorkerRequest; /** Executors must make close terminal: no pending job may reopen a source reader after close. */ export declare function createPreviewCaptureWorkerRuntime(options: { input?: NodeJS.ReadableStream; output?: NodeJS.WritableStream; executor: { runJob(payload: PygmalionPreviewCaptureWorkerPayload, options: PygmalionPreviewCaptureGeneratorOptions): Promise<{ artifactFile: string }>; close(): Promise; }; once?: boolean; exit?: (code: number) => void; log?: (message: string) => void; }): { handleLine(line: string): Promise | null; requestShutdown(options?: { cancel?: boolean }): Promise; cancel(): Promise; }; export interface PygmalionPreviewCaptureWorkerChannel { generateArtifact( request: { namespace: string; sourceRevision: string; frames?: readonly PygmalionPreviewFrameRequest[]; captureBaseUrl?: string; }, options?: PygmalionPreviewCaptureGeneratorOptions, ): Promise; dispose(): Promise; } export declare function createPreviewCaptureWorkerChannel( options: PygmalionPreviewCaptureWorkerConfig & { cwd?: string; maxRestarts?: number; restartWindowMs?: number; pingTimeoutMs?: number; }, ): PygmalionPreviewCaptureWorkerChannel; export interface PygmalionGitSourceState { commit: string; revision: string; dirty: boolean; fingerprint: string | null; } export declare function resolveGitSourceState( root?: string, ): PygmalionGitSourceState; export declare const PYGMALION_INSPECT_CONTROL: string; export declare const PYGMALION_DEV_PREFIX: string; export declare const PYGMALION_DEV_CONTROL: string; export declare const PYGMALION_SESSION_PREFIX: string; export declare const PYGMALION_SESSION_CONTROL: string; export declare function pygmalionInspectPlugin( options: Record, ): PluginOption; export declare function pygmalionDevMirrorPlugin( options: Record, ): PluginOption; export declare function pygmalionDesignSessionPlugin( options: Record, ): PluginOption; export declare function writeStyleEdit( root: string, input: unknown, options?: PygmalionInspectConfig & { sourceDirectory?: string }, ): Promise; export declare function writeTextEdit( root: string, input: unknown, options?: { sourceDirectory?: string }, ): Promise; export interface PygmalionInspectWritebackOptions { sourceDirectory?: string; normalizeValue?: (property: string, value: string) => string; } export interface PygmalionInspectPreviewResult { files: { file: string; diff: string }[]; affectedFiles: string[]; } export interface PygmalionInspectWriteResult { applied: number; changed: number; files: string[]; } export declare function previewInspectChanges( root: string, input: import('./dist-lib/types/lib.js').InspectApplyPayload, options?: PygmalionInspectWritebackOptions, ): Promise; export declare function writeInspectChanges( root: string, input: import('./dist-lib/types/lib.js').InspectApplyPayload, options?: PygmalionInspectWritebackOptions, ): Promise; export interface PygmalionSourceOperationApplyResult { code: string; changed: boolean; operations: import('./dist-lib/types/lib.js').SourceEditOperation[]; } export interface PygmalionSourceOperationWriteResult { ok: true; /** Number of source files changed. */ changed: number; files: string[]; /** Number of source operations verified and processed. */ operations: number; } export interface PygmalionPreparedSourceFile { file: string; before: string; after: string; changed: boolean; } export interface PygmalionSourceOperationPrepareResult { ok: true; /** Number of source files to be changed. */ changed: number; files: PygmalionPreparedSourceFile[]; /** Number of source operations verified and processed. */ operations: number; } export declare function applySourceOperations( source: string, componentFile: string, operations: import('./dist-lib/types/lib.js').SourceEditOperation[], ): PygmalionSourceOperationApplyResult; export declare function prepareSourceOperations( root: string, operations: import('./dist-lib/types/lib.js').SourceEditOperation[], options?: { sourceDirectory?: string }, ): Promise; export declare function writeSourceOperations( root: string, operations: import('./dist-lib/types/lib.js').SourceEditOperation[], options?: { sourceDirectory?: string }, ): Promise; export interface PygmalionSourceGraphOptions { sourceDirectory?: string; } export type PygmalionStoryboardEnvironmentKind = 'permission' | 'media-devices' | 'storage'; export interface PygmalionStoryboardEnvironmentEvidence { id: string; kind: string; capability: string; sourcePath: string; line: number; column: number; operation?: string; } export interface PygmalionStoryboardEnvironmentDimension { id: string; kind: PygmalionStoryboardEnvironmentKind; name: string; values: string[]; evidenceIds: string[]; } export interface PygmalionStoryboardEnvironmentScenario { id: string; label: string; environment: import('./dist-lib/types/lib.js').StoryboardEnvironment; evidenceIds: string[]; } export interface PygmalionStoryboardEnvironmentUnresolved { id: string; kind: string; reason: string; sourcePath: string; line: number; column: number; } export interface PygmalionStoryboardEnvironmentManifest { /** Present when discovery was read from an exact source checkout. */ sourceRevision?: string; version: 1; sourceRoot: string; dimensions: PygmalionStoryboardEnvironmentDimension[]; scenarios: PygmalionStoryboardEnvironmentScenario[]; evidence: PygmalionStoryboardEnvironmentEvidence[]; routes: { id: string; path: string; sourcePaths: string[]; rootSpecifiers: string[]; resolvedRoots: string[]; hasExplicitRoot: boolean; declarations: { sourcePath: string; line: number; column: number; }[]; evidenceIds: string[]; scenarioIds: string[]; }[]; candidates: { id: string; route: string; scenarioId: string; environment: import('./dist-lib/types/lib.js').StoryboardEnvironment; evidenceIds: string[]; }[]; edges: { id: string; from: string; to: string; kind: string; evidence: { sourcePath: string; line: number; column: number; }; unresolvedTarget: boolean; }[]; coverage: { routes: number; candidates: number; environmentDimensions: number; unresolved: number; unresolvedTargets: number; }; unresolved: PygmalionStoryboardEnvironmentUnresolved[]; } export interface PygmalionStoryboardEnvironmentScanOptions { sourceDirectory?: string; maxFiles?: number; } export interface PygmalionStoryboardCandidateExecution { candidateId: string; status: 'captured' | 'failed'; snapshot?: string; error?: string; } export interface PygmalionStoryboardCandidateExecutionContext { signal: AbortSignal; index: number; total: number; } export type PygmalionStoryboardCanonicalWarningCode = | 'branch-not-observed' | 'capture-failed' | 'duplicate-execution' | 'invalid-snapshot' | 'missing-execution' | 'unknown-candidate'; export interface PygmalionStoryboardCanonicalWarning { code: PygmalionStoryboardCanonicalWarningCode; severity: 'warning' | 'error'; candidateId: string; route: string; scenarioId: string; evidenceIds: string[]; message: string; } export interface PygmalionStoryboardCanonicalFrame { id: string; fingerprint: string; snapshot: string; candidateIds: string[]; routes: string[]; scenarioIds: string[]; evidenceIds: string[]; } export interface PygmalionStoryboardCanonicalManifest { version: 1; frames: PygmalionStoryboardCanonicalFrame[]; aliases: Record; warnings: PygmalionStoryboardCanonicalWarning[]; coverage: { expected: number; executed: number; captured: number; canonical: number; duplicates: number; failed: number; missing: number; unreproduced: number; complete: boolean; }; } export declare function normalizeStoryboardSnapshot( snapshot: string, ): string | null; export declare function fingerprintStoryboardSnapshot( snapshot: string, ): string | null; export declare function canonicalizeStoryboardExecutions( candidates: PygmalionStoryboardEnvironmentManifest['candidates'], executions: PygmalionStoryboardCandidateExecution[], ): PygmalionStoryboardCanonicalManifest; export declare function executeStoryboardCandidates( candidates: PygmalionStoryboardEnvironmentManifest['candidates'], capture: ( candidate: PygmalionStoryboardEnvironmentManifest['candidates'][number], context: PygmalionStoryboardCandidateExecutionContext, ) => string | Promise, options?: { concurrency?: number; timeoutMs?: number; }, ): Promise; export declare function recommendedStoryboardExecutionConcurrency(capabilities?: { parallelism?: number; totalMemoryBytes?: number; }): number; export interface PygmalionRoutePreviewArtifactV1 { version: 1; namespace: string; sourceRevision?: string; snapshots: Record; } export interface PygmalionRoutePreviewArtifactV2 { readonly version: 2; readonly namespace: string; readonly sourceRevision?: string; readonly assets: { readonly head: Readonly>; readonly stylesheets: Readonly>; }; readonly frames: Readonly< Record< string, { readonly document: { readonly doctype: string; readonly htmlAttributes: string; readonly headAttributes: string; readonly bodyAttributes: string; }; readonly head: readonly { readonly kind: 'head' | 'stylesheet'; readonly hash: string; }[]; readonly body: string; } > >; } export interface PygmalionRoutePreviewArtifactV2Validation { valid: boolean; errors: string[]; bytes: number; } export declare const ROUTE_PREVIEW_ARTIFACT_V2_LIMITS: Readonly< Record >; export declare function isSafeFrozenRoutePreviewSnapshot( snapshot: unknown, ): snapshot is string; export declare function createRoutePreviewArtifactV2( input: | { namespace: string; sourceRevision?: string; snapshots: Record; } | PygmalionRoutePreviewArtifactV1, ): PygmalionRoutePreviewArtifactV2; export declare function convertRoutePreviewArtifactV1ToV2( bundle: PygmalionRoutePreviewArtifactV1, ): PygmalionRoutePreviewArtifactV2; export declare function convertRoutePreviewArtifactV2ToV1( bundle: PygmalionRoutePreviewArtifactV2, ): PygmalionRoutePreviewArtifactV1; export declare function validateRoutePreviewArtifactV2( bundle: unknown, ): PygmalionRoutePreviewArtifactV2Validation; export declare function reconstructRoutePreviewArtifactSnapshot( bundle: PygmalionRoutePreviewArtifactV2, frameId: string, ): string | null; export declare function reconstructRoutePreviewArtifactSnapshots( bundle: PygmalionRoutePreviewArtifactV2, ): Record; export { ROUTE_PREVIEW_ARTIFACT_V3_LIMITS, createRoutePreviewArtifactV3, mergeRoutePreviewArtifactV3, reconstructRoutePreviewArtifactScreenshotV3, reconstructRoutePreviewArtifactSnapshotV3, reconstructRoutePreviewArtifactSnapshotsV3, selectRoutePreviewArtifactFrames, validateRoutePreviewArtifactBundle, validateRoutePreviewArtifactV3, } from './storyboard.js'; export declare function resolvePreviewRouteDependencyDigest( route: string, entries: readonly { path?: string; dependencyDigest?: string }[], ): string | undefined; export type { RoutePreviewArtifactBundleV3, RoutePreviewArtifactFrameRequest, RoutePreviewArtifactV3Capture, StoryboardCaptureDiagnostic, StoryboardCaptureStatus, StoryboardCaptureViewport, } from './storyboard.js'; export declare function scanStoryboardEnvironment( root: string, options?: PygmalionStoryboardEnvironmentScanOptions, ): Promise; export declare function storyboardEnvironmentBootstrapSource(): string; export declare function pygmalionStoryboardRuntimePlugin(): PluginOption; export declare function pygmalionStoryboardPlugin(options: { root: string; sourceDirectory?: string; endpoint?: string; canonicalEndpoint?: string; acquireSourceLease?: NonNullable[0]>['acquireSourceLease']; requestRuntime?: () => unknown; }): PluginOption; export declare const PYGMALION_STORYBOARD_CANONICAL_CONTROL: string; export declare const PYGMALION_STORYBOARD_ENVIRONMENT_CONTROL: string; export declare const PYGMALION_STORYBOARD_ENVIRONMENT_QUERY: string; export interface PygmalionSourceGraph { sourceDirectory: string; files: string[]; dependencies: Record; reverseDependencies: Record; } export declare function buildSourceGraph( root: string, options?: PygmalionSourceGraphOptions, ): Promise; export declare function collectAffectedSourceFiles( graph: PygmalionSourceGraph, componentFiles: string[], ): string[]; export declare function findAffectedSourceFiles( root: string, componentFiles: string[], options?: PygmalionSourceGraphOptions, ): Promise; /** source.ref value that previews the current working tree, uncommitted changes included. */ export declare const PYGMALION_WORKTREE_SOURCE_REF: 'worktree'; // ── Component branch scanner ──────────────────────────────────────────────── export interface ScannedComponentBranch { kind: 'conditional' | 'enum'; condition: string; element?: string; renders?: string; values?: readonly string[]; line?: number; } export interface ComponentBranchManifest { sourcePath: string; branches: readonly ScannedComponentBranch[]; } export declare const PYGMALION_COMPONENT_BRANCHES_CONTROL: string; /** Extracts conditional-render guards and string-literal enum chains. */ export declare function scanComponentBranches( source: string, sourcePath: string, ): ComponentBranchManifest; /** Reads and scans one source file, refusing paths outside the root. */ export declare function scanComponentBranchesFile( root: string, sourcePath: string, ): Promise;