import type * as plugins from './plugins.js'; import type { IControllerFilesystemIdentity } from './interfaces.projects.js'; export type TGitReversionDirection = 'undo' | 'redo'; export type TGitReversionSideName = 'before' | 'after'; export type TGitReversionWalPhase = | 'intent' | 'preflighted' | 'applying' | 'targetVerified' | 'decision' | 'committed' | 'compensating' | 'compensated' | 'fenced'; export type TGitReversionWorktreeState = | 'intent' | 'created' | 'registered' | 'active' | 'removing' | 'retainedDirty' | 'removed' | 'fenced'; export type TGitReversionFaultPoint = | 'intent.before-fsync' | 'intent.after-fsync' | 'intent.before-ref-cas' | 'intent.after-ref-cas' | 'intent.before-commit-fsync' | 'intent.after-commit-fsync' | 'intent.before-remove' | 'intent.after-remove' | 'atomic.after-rename-before-directory-fsync' | 'capture.after-before-scan' | 'capture.before-finalize-record' | 'capture.after-finalize-record-fsync' | 'capture.after-staging-repository' | 'capture.after-intent-repository' | 'capture.after-state-repository' | 'capture.after-manifest-repository' | 'capture.before-store-create' | 'capture.after-store-create' | 'capture.before-generation-enrollment' | 'capture.after-generation-enrollment' | 'capture.after-publication-fsync' | 'capture.before-root-delete' | 'capture.after-root-delete' | 'capture.after-root-delete-fsync' | 'apply.after-intent' | 'apply.after-preflight' | 'apply.after-source-pack-import' | 'apply.after-source-pack-fsync' | 'apply.after-repository' | 'apply.after-target-verification' | 'apply.after-decision-repository' | 'apply.after-decision' | 'apply.after-state-repository' | 'apply.during-compensation' | 'apply.before-source-keep-remove' | 'apply.after-source-keep-quarantine' | 'apply.after-source-keep-remove' | 'apply.after-source-keep-remove-fsync' | 'worktree.after-intent' | 'worktree.after-create' | 'worktree.after-removed-record' | 'worktree.record-read.after-open' | 'index.before-sidecar-fsync' | 'index.after-sidecar-fsync' | 'index.after-link' | 'index.after-link-fsync' | 'index.after-rename' | 'index.after-rename-fsync' | 'index.after-cleanup' | 'index.after-cleanup-fsync'; export type TGitReversionReference = { schemaVersion: 1; captureKey: string; manifestId: string; }; export type TGitReversionFinalizedOutcome = plugins.flexharness.TFlexTurnReversionFinalizedOutcome; export type TGitReversionCaptureInspection = plugins.flexharness.TFlexTurnReversionCaptureInspectionV2; export type TGitReversionApplyInspection = plugins.flexharness.IFlexTurnReversionApplyInspection; export interface IGitReversionIdentity { projectId: string; sessionId: string; runId: string; captureId: string; } export interface IGitReversionCaptureRequest extends IGitReversionIdentity { signal?: AbortSignal; } export interface IGitReversionApplyRequest { identity: IGitReversionIdentity; reference: TGitReversionReference; operationId: string; direction: TGitReversionDirection; signal?: AbortSignal; } export interface IGitReversionReleaseRequest { identity: IGitReversionIdentity; reference: TGitReversionReference; signal?: AbortSignal; } export interface IGitReversionMetadataRequest { identity: IGitReversionIdentity; reference: TGitReversionReference; signal?: AbortSignal; } export interface IGitReversionWorktreeRequest { projectId: string; sessionId: string; signal?: AbortSignal; } export interface IGitReversionWorktreeRemoveRequest extends IGitReversionWorktreeRequest { worktreeId: string; } export interface IGitReversionLimits { maximumProjects: number; maximumRepositories: number; maximumScannedDirectories: number; maximumScanDepth: number; maximumPaths: number; maximumPathBytes: number; maximumMetadataBytes: number; maximumPrivateRefs: number; maximumPrivateMetadataAggregateBytes: number; maximumIntentFiles: number; maximumIntentEntries: number; maximumIntentFileBytes: number; maximumIntentAggregateBytes: number; maximumScavengeEntries: number; maximumIgnorePolicyFiles: number; maximumIgnorePolicyBytes: number; maximumWorktrees: number; maximumCaptureRecords: number; maximumCaptureRecordBytes: number; maximumCaptureAggregateBytes: number; maximumCaptures: number; maximumGenerationsPerCapture: number; maximumGenerationBytes: number; maximumGenerationObjects: number; maximumCaptureStoreBytes: number; maximumCaptureStoreObjects: number; maximumControllerStoreBytes: number; maximumControllerStoreObjects: number; maximumControllerGenerations: number; maximumMetadataRecordsPerCapture: number; maximumMetadataRecordBytes: number; maximumMetadataAggregateBytes: number; maximumLifecycleEntries: number; maximumLifecycleRecordBytes: number; maximumLifecycleAggregateBytes: number; maximumPrivateRefsPerCapture: number; commandTimeoutMs: number; worktreeCommandTimeoutMs: number; /** Bounded wait for a SIGKILLed Git child to confirm close before liveness is judged. */ commandCloseConfirmationMs: number; maximumCommandOutputBytes: number; maximumConcurrentGitCommands: number; maximumQueuedGitCommands: number; } export interface IGitReversionFaultContext { point: TGitReversionFaultPoint; captureKey?: string; operationId?: string; repositoryId?: string; worktreeId?: string; intentId?: string; ref?: string; } export interface IGitReversionOptions { ownerId: string; /** This path must be exclusively owned by one live controller process. */ temporaryRoot?: string; limits?: Partial; /** * Invoked once when the engine seals itself because a terminated Git child * survived SIGKILL. The owner must close this engine and construct a * replacement; the sealed engine rejects every further operation. */ onSealedForCleanup?: (error: Error) => void; testOnlyFaultInjector?: ( context: IGitReversionFaultContext, ) => Promise | void; } export interface IGitReversionRepositoryIdentity { scope: 'project' | 'owned-worktree'; repositoryId: string; commonId: string; objectFormat: 'sha1' | 'sha256'; root: string; rootIdentity: IControllerFilesystemIdentity; gitEntryPath: string; gitEntryIdentity: IControllerFilesystemIdentity; gitDir: string; gitDirIdentity: IControllerFilesystemIdentity; commonDir: string; commonDirIdentity: IControllerFilesystemIdentity; objectDir: string; objectDirIdentity: IControllerFilesystemIdentity; indexPath: string; indexParentIdentity: IControllerFilesystemIdentity; label: string; excludedRepositoryPaths: string[]; } export interface IGitReversionSide { objectGenerationId?: string; worktreeTree: string; indexTree: string; headOid: string; headRef: string | null; refs: Record; symbolicRefs: Record; topologyHash: string; ignorePolicyHash: string; operationHash: string; unsupportedReason?: string; } export interface IGitReversionRepositoryCapture { repository: IGitReversionRepositoryIdentity; before: IGitReversionSide; after?: IGitReversionSide; } export interface IGitReversionManifest { schemaVersion: 1; kind: 'manifest'; ownerKey: string; captureKey: string; identity: IGitReversionIdentity; projectDirectory: string; projectIdentity: IControllerFilesystemIdentity; phase: 'prepared' | 'finalized'; repositories: IGitReversionRepositoryCapture[]; reasonCode?: string; affectedWorkspaces: Array<{ id: string; label: string }>; } export interface IGitReversionCaptureState { schemaVersion: 1; kind: 'capture-state'; captureKey: string; manifestId: string; currentSide: TGitReversionSideName; revision: number; outcome: TGitReversionFinalizedOutcome; } export interface IGitReversionSourcePack { generationId: string; packHash: string; packBytes: number; objectCount: number; syntheticRootOid: string; keepToken: string; } export interface IGitReversionApplyPlan { captureKey: string; repository: IGitReversionRepositoryIdentity; initial: IGitReversionSide; source: IGitReversionSide; target: IGitReversionSide; desiredWorktreeTree: string; desiredIndexTree: string; scopedRefs: string[]; sourcePack: IGitReversionSourcePack; } export interface IGitReversionApplyWal { schemaVersion: 1; kind: 'apply-wal'; captureKey: string; manifestId: string; operationId: string; operationKey: string; direction: TGitReversionDirection; attempt: number; sourceSide: TGitReversionSideName; targetSide: TGitReversionSideName; sourceRevision: number; phase: TGitReversionWalPhase; decision?: 'source' | 'target'; touchedRepositoryIds: string[]; plans: IGitReversionApplyPlan[]; generationIds: Record; } export interface IGitReversionWorktreeDescriptor { worktreeId: string; projectId: string; sessionId: string; path: string; repositoryId: string; createdAt: string; state: Exclude; } export interface IGitReversionWorktreeRecord { schemaVersion: 1; kind: 'worktree'; ownerKey: string; worktreeId: string; projectId: string; sessionId: string; path: string; parentPath: string; parentIdentity: IControllerFilesystemIdentity; pathIdentity?: IControllerFilesystemIdentity; sourceRoot: string; sourceCommonDir: string; sourceRepository: IGitReversionRepositoryIdentity; repositoryId: string; createdAt: string; state: TGitReversionWorktreeState; } export interface IGitReversionMetadata { reference: TGitReversionReference; disposition: TGitReversionFinalizedOutcome['disposition']; currentSide: TGitReversionSideName; revision: number; affectedWorkspaces: Array<{ id: string; label: string }>; reasonCode?: string; }