@quantiya/codevibe-claude-plugin 2.0.13 → 2.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/server.js +15 -15
- package/node_modules/@quantiya/codevibe-core/dist/index.js +285 -285
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/anchored-cas.d.ts +84 -0
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/anchored-fs.d.ts +1 -1
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/shadow-protocol.d.ts +358 -0
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/shadow-recovery.d.ts +273 -0
- package/node_modules/@quantiya/codevibe-core/dist/local-executor/workspace-shadow.d.ts +8 -295
- package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +4169 -3958
- package/node_modules/@quantiya/codevibe-core/package.json +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type AnchoredFsIdentity } from './anchored-fs';
|
|
2
|
+
import { type WorkspaceRootAuthority } from './workspace-authority';
|
|
3
|
+
import { CasHelperCrashStage, CasRecoveryAuthority } from './shadow-protocol';
|
|
4
|
+
export declare function casRecoveryAuthorityFor(root: WorkspaceRootAuthority, rel: string, expectedHash: string | null, expectedMode: number | null, postHash: string | null, postMode: number | null): CasRecoveryAuthority;
|
|
5
|
+
export interface AcceptedAlternateImage {
|
|
6
|
+
hash: string | null;
|
|
7
|
+
mode: number | null;
|
|
8
|
+
}
|
|
9
|
+
export declare class WorkspaceCasUnresolvedError extends Error {
|
|
10
|
+
readonly recoveryName?: string;
|
|
11
|
+
constructor(recoveryName?: string, detail?: string);
|
|
12
|
+
}
|
|
13
|
+
export declare function replacePromotedFile(workingDir: string, rel: string, content: string, mode: number, expectedHash: string | null, expectedMode: number | null, beforeCommit?: () => Promise<void> | undefined, afterValidation?: () => Promise<void> | undefined, afterDisplacement?: (recoveryName: string) => Promise<void> | undefined, beforeTargetQuarantine?: (quarantineName: string) => Promise<void> | undefined, beforeFinalUnlink?: (recoveryName: string) => Promise<void> | undefined, afterPrepared?: () => Promise<void> | undefined, expectedRootIdentity?: AnchoredFsIdentity | WorkspaceRootAuthority, helperOpts?: {
|
|
14
|
+
helperTimeoutMs?: number;
|
|
15
|
+
testHangStage?: 'root' | 'parent' | 'target';
|
|
16
|
+
testCrashStage?: CasHelperCrashStage;
|
|
17
|
+
allowPostImageRecovery?: boolean;
|
|
18
|
+
acceptedAlternate?: AcceptedAlternateImage;
|
|
19
|
+
}): Promise<boolean>;
|
|
20
|
+
export declare function removePromotedFile(workingDir: string, rel: string, expectedHash: string | null, expectedMode: number | null, beforeCommit?: () => Promise<void> | undefined, afterValidation?: () => Promise<void> | undefined, afterDisplacement?: (recoveryName: string) => Promise<void> | undefined, beforeTargetQuarantine?: (quarantineName: string) => Promise<void> | undefined, beforeFinalUnlink?: (recoveryName: string) => Promise<void> | undefined, expectedRootIdentity?: AnchoredFsIdentity | WorkspaceRootAuthority, helperOpts?: {
|
|
21
|
+
helperTimeoutMs?: number;
|
|
22
|
+
testHangStage?: 'root' | 'parent' | 'target';
|
|
23
|
+
testCrashStage?: CasHelperCrashStage;
|
|
24
|
+
allowPostImageRecovery?: boolean;
|
|
25
|
+
acceptedAlternate?: AcceptedAlternateImage;
|
|
26
|
+
}): Promise<boolean>;
|
|
27
|
+
/** Hardened reverse-apply surface shared by promotion and durable revert. */
|
|
28
|
+
export declare function replaceWorkspaceFileIfMatches(args: {
|
|
29
|
+
workingDir: string;
|
|
30
|
+
workspaceRootAuthority: WorkspaceRootAuthority;
|
|
31
|
+
path: string;
|
|
32
|
+
content: string;
|
|
33
|
+
mode: number;
|
|
34
|
+
expectedHash: string | null;
|
|
35
|
+
expectedMode: number | null;
|
|
36
|
+
/** @internal deterministic last-commit race seam. */
|
|
37
|
+
beforeCommit?: () => Promise<void> | undefined;
|
|
38
|
+
/** @internal deterministic post-validation parent-swap seam. */
|
|
39
|
+
afterValidation?: () => Promise<void> | undefined;
|
|
40
|
+
/** @internal deterministic post-displacement recreation seam. */
|
|
41
|
+
afterDisplacement?: (recoveryName: string) => Promise<void> | undefined;
|
|
42
|
+
/** @internal deterministic public-target quarantine race seam. */
|
|
43
|
+
beforeTargetQuarantine?: (quarantineName: string) => Promise<void> | undefined;
|
|
44
|
+
/** @internal deterministic artifact-retirement race seam. */
|
|
45
|
+
beforeFinalUnlink?: (recoveryName: string) => Promise<void> | undefined;
|
|
46
|
+
/** @internal lower deterministic CAS-helper deadline for tests. */
|
|
47
|
+
helperTimeoutMs?: number;
|
|
48
|
+
/** @internal deterministic CAS-helper target-filesystem stall seam. */
|
|
49
|
+
testHangHelperStage?: 'root' | 'parent' | 'target';
|
|
50
|
+
/** @internal deterministic helper death after COMMIT/mutation. */
|
|
51
|
+
testCrashHelperStage?: CasHelperCrashStage;
|
|
52
|
+
/** Re-drive deterministic recovery names owned by an existing durable journal. */
|
|
53
|
+
allowPostImageRecovery?: boolean;
|
|
54
|
+
/** Exact terminal image that authorizes cleanup-only replay for same-path chains. */
|
|
55
|
+
acceptedAlternate?: AcceptedAlternateImage;
|
|
56
|
+
}): Promise<boolean>;
|
|
57
|
+
/** Hardened reverse-delete surface shared by promotion and durable revert. */
|
|
58
|
+
export declare function removeWorkspaceFileIfMatches(args: {
|
|
59
|
+
workingDir: string;
|
|
60
|
+
workspaceRootAuthority: WorkspaceRootAuthority;
|
|
61
|
+
path: string;
|
|
62
|
+
expectedHash: string | null;
|
|
63
|
+
expectedMode: number | null;
|
|
64
|
+
/** @internal deterministic last-commit race seam. */
|
|
65
|
+
beforeCommit?: () => Promise<void> | undefined;
|
|
66
|
+
/** @internal deterministic post-validation parent-swap seam. */
|
|
67
|
+
afterValidation?: () => Promise<void> | undefined;
|
|
68
|
+
/** @internal deterministic post-displacement recreation seam. */
|
|
69
|
+
afterDisplacement?: (recoveryName: string) => Promise<void> | undefined;
|
|
70
|
+
/** @internal deterministic public-target quarantine race seam. */
|
|
71
|
+
beforeTargetQuarantine?: (quarantineName: string) => Promise<void> | undefined;
|
|
72
|
+
/** @internal deterministic artifact-retirement race seam. */
|
|
73
|
+
beforeFinalUnlink?: (recoveryName: string) => Promise<void> | undefined;
|
|
74
|
+
/** @internal lower deterministic CAS-helper deadline for tests. */
|
|
75
|
+
helperTimeoutMs?: number;
|
|
76
|
+
/** @internal deterministic CAS-helper target-filesystem stall seam. */
|
|
77
|
+
testHangHelperStage?: 'root' | 'parent' | 'target';
|
|
78
|
+
/** @internal deterministic helper death after COMMIT/mutation. */
|
|
79
|
+
testCrashHelperStage?: CasHelperCrashStage;
|
|
80
|
+
/** Re-drive deterministic recovery names owned by an existing durable journal. */
|
|
81
|
+
allowPostImageRecovery?: boolean;
|
|
82
|
+
/** Exact terminal image that authorizes cleanup-only replay for same-path chains. */
|
|
83
|
+
acceptedAlternate?: AcceptedAlternateImage;
|
|
84
|
+
}): Promise<boolean>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type WorkspaceRootAuthority } from './workspace-authority.js';
|
|
2
|
-
type PublicationPrivateRetirementStage = 'commit-rename' | 'commit-unlink' | 'commit-sync' | 'pending-rename' | 'pending-unlink' | 'pending-sync' | 'retiring-rename' | 'retiring-unlink' | 'retiring-sync' | 'disposed-rename' | 'disposed-unlink' | 'disposed-sync';
|
|
2
|
+
type PublicationPrivateRetirementStage = 'disposed-publish' | 'commit-rename' | 'commit-unlink' | 'commit-sync' | 'pending-rename' | 'pending-unlink' | 'pending-sync' | 'retiring-rename' | 'retiring-unlink' | 'retiring-sync' | 'disposed-rename' | 'disposed-unlink' | 'disposed-sync';
|
|
3
3
|
export interface AnchoredPublicationAuthorityResidue {
|
|
4
4
|
recordName: string;
|
|
5
5
|
authorityId: string;
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import { type AnchoredFsIdentity, type AnchoredPathIdentity, type AnchoredWritePrecondition } from './anchored-fs';
|
|
3
|
+
import { type ProcessCleanupOwner } from './process-tree';
|
|
4
|
+
import { type ProcessIdentity } from './process-identity';
|
|
5
|
+
import { type WorkspaceRootAuthority } from './workspace-authority';
|
|
6
|
+
import { type MaterializationHangStage } from './workspace-materializer';
|
|
7
|
+
/** Directories never materialized into a new filesystem snapshot. */
|
|
8
|
+
export declare const SHADOW_SKIP_DIRS: ReadonlySet<string>;
|
|
9
|
+
/** IMAGE-ATTACHMENT-DESIGN.md §7 — the in-worktree attachments dir (never in the reviewed diff / promoted). */
|
|
10
|
+
export declare const SHADOW_ATTACHMENTS_DIR = ".codevibe-attachments";
|
|
11
|
+
/**
|
|
12
|
+
* Non-secret, gitignored BUILD-ENV files the agent's tooling (`npm test`,
|
|
13
|
+
* compile, format) reads from the workspace root. Copied/symlinked into the
|
|
14
|
+
* shadow as READ-ENV only (NEVER in the tracked set → never promoted). Each
|
|
15
|
+
* candidate is still checked against `matchesSecretDenyList` first — a secret
|
|
16
|
+
* `.env` is excluded even though it appears here. (Stage-2 r2 agy MED.)
|
|
17
|
+
*/
|
|
18
|
+
export declare const BUILD_ENV_FILENAMES: readonly string[];
|
|
19
|
+
/** Marker filename written inside the shadow (#PR-4). */
|
|
20
|
+
export declare const SHADOW_STATE_FILE = "shadow-state.json";
|
|
21
|
+
export declare const SHADOW_OWNER_FILE = ".codevibe-snapshot-owner.json";
|
|
22
|
+
export declare const SHADOW_ROOT_REGISTRY_FILE = ".codevibe-shadow-roots.json";
|
|
23
|
+
export declare const SHADOW_QUOTA_LOCK_DIR = ".codevibe-quota-locks";
|
|
24
|
+
export declare const SHADOW_QUOTA_LOCK_FILE = "physical-copy-quota.lock";
|
|
25
|
+
/** Alternate durable fail-closed anchor when the primary marker cannot be updated. */
|
|
26
|
+
export declare const SHADOW_CLEANUP_BLOCK_FILE = ".codevibe-cleanup-blocked.json";
|
|
27
|
+
export declare const SHADOW_STATE_FILE_RE: RegExp;
|
|
28
|
+
export declare const SHADOW_EXPOSURE_RETENTION_FILE_RE: RegExp;
|
|
29
|
+
export declare const SHADOW_DIR_RE: RegExp;
|
|
30
|
+
/** Private create name: never classified as a runnable/recoverable snapshot. */
|
|
31
|
+
export declare const SHADOW_STAGING_DIR_RE: RegExp;
|
|
32
|
+
export declare const SHADOW_TREE_TOMBSTONE_RE: RegExp;
|
|
33
|
+
export declare const SHADOW_UUID_SUFFIX_RE: RegExp;
|
|
34
|
+
export declare function isStateRootInfrastructureDirectory(name: string): boolean;
|
|
35
|
+
export declare function taskIdFromGeneratedShadowName(name: string): string | null;
|
|
36
|
+
/** Strict lifecycle-lock residue authored by `withAnchoredExclusiveLock`. */
|
|
37
|
+
export declare const SHADOW_LIFECYCLE_LOCK_ARTIFACT_RE: RegExp;
|
|
38
|
+
/** Never silently duplicate one enormous file when reflinks are unavailable. */
|
|
39
|
+
export declare const MAX_NON_COW_FILE_BYTES: number;
|
|
40
|
+
export declare const MAX_NON_COW_WORKSPACE_BYTES: number;
|
|
41
|
+
export declare const MAX_TRACKED_FILE_LOGICAL_BYTES: number;
|
|
42
|
+
export declare const MAX_TRACKED_WORKSPACE_LOGICAL_BYTES: number;
|
|
43
|
+
/** Metadata is bounded independently of content bytes (zero-byte files still cost memory/inodes). */
|
|
44
|
+
export declare const MAX_TRACKED_FILE_COUNT = 100000;
|
|
45
|
+
export declare const MAX_TRACKED_PATH_BYTES: number;
|
|
46
|
+
/** Reviewed text is intentionally bounded before any whole-file decode/read. */
|
|
47
|
+
export declare const MAX_REVIEW_FILE_BYTES: number;
|
|
48
|
+
export declare const MAX_PROMOTION_PREIMAGE_AGGREGATE_BYTES: number;
|
|
49
|
+
/** Exact UTF-8 ceiling shared by every durable state-marker writer and reader. */
|
|
50
|
+
export declare const MAX_STATE_MARKER_BYTES: number;
|
|
51
|
+
export declare function reservePhysicalCopyBytes(scopeId: string, reservationId: string, bytes: number, persistedBytes: number, limit?: number): void;
|
|
52
|
+
export declare function releasePhysicalCopyBytes(scopeId: string, reservationId: string, bytes?: number): void;
|
|
53
|
+
export declare function reservedPhysicalCopyBytes(scopeId: string, reservationId: string): number;
|
|
54
|
+
export declare function movePhysicalCopyReservation(scopeId: string, from: string, to: string): void;
|
|
55
|
+
/** Default TTL after which an orphaned shadow is GC-eligible (#GC-1). */
|
|
56
|
+
export declare const DEFAULT_SHADOW_TTL_MS: number;
|
|
57
|
+
/** `change_kind` values mirroring the pinned engine `ExecuteFirstFile` contract. */
|
|
58
|
+
export type ShadowChangeKind = 'created' | 'modified' | 'deleted';
|
|
59
|
+
/** One captured changed file in the shadow-vs-real diff (§D3). */
|
|
60
|
+
export interface ShadowDiffFile {
|
|
61
|
+
/** Path RELATIVE to the workspace root (matches the engine contract). */
|
|
62
|
+
path: string;
|
|
63
|
+
change_kind: ShadowChangeKind;
|
|
64
|
+
/** The captured content (created/modified) or empty for deleted. */
|
|
65
|
+
content: string;
|
|
66
|
+
/** POSIX permission bits for the reviewed post-image (omitted by legacy records). */
|
|
67
|
+
mode?: number;
|
|
68
|
+
}
|
|
69
|
+
/** A reviewed change plus the exact real-tree pre-image expected at promotion. */
|
|
70
|
+
export interface ReviewedShadowDiffFile extends ShadowDiffFile {
|
|
71
|
+
/** SHA-256 of the pre-task file, or null when the path was absent. */
|
|
72
|
+
base_hash: string | null;
|
|
73
|
+
/** POSIX permission bits of the pre-task file, or null when absent. */
|
|
74
|
+
base_mode?: number | null;
|
|
75
|
+
}
|
|
76
|
+
/** Persisted promote-state marker (#PR-4). */
|
|
77
|
+
export type ShadowPromoteState = 'pending' | 'applying' | 'promoted' | 'disposing';
|
|
78
|
+
export type CasHelperCrashStage = 'post-link' | 'post-displacement' | 'post-publication' | 'post-fsync' | 'post-close';
|
|
79
|
+
export interface UnresolvedBundlePublicationRetention {
|
|
80
|
+
taskGroupId: string;
|
|
81
|
+
trackIndex: number;
|
|
82
|
+
}
|
|
83
|
+
export interface CasRecoveryAuthority {
|
|
84
|
+
path: string;
|
|
85
|
+
operation: 'replace' | 'delete';
|
|
86
|
+
/** Deterministic from the persisted root/pre/post authority. */
|
|
87
|
+
recoveryName: string;
|
|
88
|
+
/** Deterministic public-entry quarantine used instead of check-then-unlink. */
|
|
89
|
+
quarantineName: string;
|
|
90
|
+
/** Deterministic prepared-byte name for replace/create operations. */
|
|
91
|
+
tempName?: string;
|
|
92
|
+
expectedHash: string | null;
|
|
93
|
+
expectedMode: number | null;
|
|
94
|
+
postHash: string | null;
|
|
95
|
+
postMode: number | null;
|
|
96
|
+
}
|
|
97
|
+
export interface ShadowStateFileV2 {
|
|
98
|
+
/** Version 3 is the first schema with complete snapshot-incarnation authority. */
|
|
99
|
+
version: 3;
|
|
100
|
+
taskId: string;
|
|
101
|
+
shadowDir: string;
|
|
102
|
+
workingDir: string;
|
|
103
|
+
shadowDirIdentity: AnchoredFsIdentity;
|
|
104
|
+
/** Exact snapshot-root incarnation captured when this snapshot was exposed. */
|
|
105
|
+
snapshotRootAuthority: WorkspaceRootAuthority;
|
|
106
|
+
workingDirIdentity: AnchoredFsIdentity;
|
|
107
|
+
workspaceRootAuthority: WorkspaceRootAuthority;
|
|
108
|
+
/** OS-authenticated creator lease; TTL never overrides a live process. */
|
|
109
|
+
ownerProcessIdentity: ProcessIdentity;
|
|
110
|
+
/** Actual non-COW bytes reserved against this durable session-state aggregate. */
|
|
111
|
+
physicalCopyBytes: number;
|
|
112
|
+
isGit: false;
|
|
113
|
+
promoteState: ShadowPromoteState;
|
|
114
|
+
createdAtMs: number;
|
|
115
|
+
/** Owned descendants could not be proven gone; cwd deletion is forbidden. */
|
|
116
|
+
cleanupBlocked?: boolean;
|
|
117
|
+
/** Persisted process-tree owners used to retry quiescence after restart. */
|
|
118
|
+
cleanupOwners?: ProcessCleanupOwner[];
|
|
119
|
+
/** Explicit recovery authority: cleanup is forbidden until publication is reconciled. */
|
|
120
|
+
unresolvedAuthorityRetention?: UnresolvedBundlePublicationRetention;
|
|
121
|
+
/** Exact immutable snapshot baseline, including paths later deleted by an implementor. */
|
|
122
|
+
baseline: Array<{
|
|
123
|
+
path: string;
|
|
124
|
+
hash: string | null;
|
|
125
|
+
mode?: number | null;
|
|
126
|
+
}>;
|
|
127
|
+
/** Exact intended post-images, present while/after promotion for crash reconciliation. */
|
|
128
|
+
promotePostHashes?: Array<{
|
|
129
|
+
path: string;
|
|
130
|
+
hash: string | null;
|
|
131
|
+
mode?: number | null;
|
|
132
|
+
}>;
|
|
133
|
+
/** Names + byte identities needed to resolve any post-COMMIT helper death. */
|
|
134
|
+
casRecovery?: CasRecoveryAuthority[];
|
|
135
|
+
/** Full snapshot incarnation claimed by immutable DISPOSING authority. */
|
|
136
|
+
disposalSnapshotAuthority?: WorkspaceRootAuthority;
|
|
137
|
+
/** Legacy v3 field: protected fail-closed, never accepted for deletion. */
|
|
138
|
+
disposalShadowIdentity?: AnchoredFsIdentity;
|
|
139
|
+
/**
|
|
140
|
+
* Exact artifact bytes submitted for review. This is persisted before the
|
|
141
|
+
* submission can resolve, so a restarted desktop never derives promotion
|
|
142
|
+
* authority from mutable snapshot bytes.
|
|
143
|
+
*/
|
|
144
|
+
reviewedDiff?: ShadowDiffFile[];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Non-operational authority published before a private snapshot name becomes
|
|
148
|
+
* visible. It never authorizes use of `finalShadowDir`; it only prevents that
|
|
149
|
+
* generated name from being freshly adopted and identifies the original bytes
|
|
150
|
+
* that CodeVibe may reclaim.
|
|
151
|
+
*/
|
|
152
|
+
export interface ExposureRetentionMarker {
|
|
153
|
+
version: 1 | 2;
|
|
154
|
+
taskId: string;
|
|
155
|
+
finalShadowDir: string;
|
|
156
|
+
originalSnapshotAuthority: WorkspaceRootAuthority;
|
|
157
|
+
currentSnapshotAuthority?: WorkspaceRootAuthority;
|
|
158
|
+
ownerProcessIdentity: ProcessIdentity;
|
|
159
|
+
physicalCopyScopeHash: string;
|
|
160
|
+
physicalCopyBytes: number;
|
|
161
|
+
phase: 'owned' | 'operational' | 'deleting' | 'reclaimed';
|
|
162
|
+
/** Fsynced authorization for deleting exactly this incarnation. */
|
|
163
|
+
deleteDisposition?: {
|
|
164
|
+
version: 1;
|
|
165
|
+
snapshotAuthority: WorkspaceRootAuthority;
|
|
166
|
+
nonce: string;
|
|
167
|
+
createdAtMs: number;
|
|
168
|
+
};
|
|
169
|
+
createdAtMs: number;
|
|
170
|
+
}
|
|
171
|
+
export interface ShadowStateSnapshot {
|
|
172
|
+
marker: ShadowStateFileV2;
|
|
173
|
+
precondition: Extract<AnchoredWritePrecondition, {
|
|
174
|
+
kind: 'existing';
|
|
175
|
+
}>;
|
|
176
|
+
/** Immediate state-directory inode carried from authority read to publication. */
|
|
177
|
+
parentIdentity: AnchoredFsIdentity & {
|
|
178
|
+
birthtimeNs: string;
|
|
179
|
+
canonicalPath: string;
|
|
180
|
+
};
|
|
181
|
+
/** Full marker incarnation used by identity-conditioned retirement. */
|
|
182
|
+
stateFileIdentity: AnchoredPathIdentity;
|
|
183
|
+
/** Exact state-root parent carried from the same bounded authority read. */
|
|
184
|
+
stateRootAuthority: WorkspaceRootAuthority;
|
|
185
|
+
}
|
|
186
|
+
export type RetainedStateFileAuthority = AnchoredFsIdentity & {
|
|
187
|
+
birthtimeNs: string;
|
|
188
|
+
canonicalPath: string;
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* A schema-valid marker whose snapshot pathname may no longer name the owned
|
|
192
|
+
* incarnation. This surface is deliberately cleanup-only: it can transition
|
|
193
|
+
* to DISPOSING and reclaim the exact persisted incarnation, but can never
|
|
194
|
+
* reopen, diff, promote, or launch from the pathname now occupying `shadowDir`.
|
|
195
|
+
*/
|
|
196
|
+
export interface StructurallyBoundStateSnapshot extends ShadowStateSnapshot {
|
|
197
|
+
stateFileIdentity: AnchoredPathIdentity;
|
|
198
|
+
stateDirAuthority: WorkspaceRootAuthority;
|
|
199
|
+
shadowRootAuthority: WorkspaceRootAuthority;
|
|
200
|
+
}
|
|
201
|
+
export interface DisplacedShadowMarkerRecord {
|
|
202
|
+
taskId: string;
|
|
203
|
+
stateDir: string;
|
|
204
|
+
stateFile: string;
|
|
205
|
+
}
|
|
206
|
+
export type SnapshotIncarnationIndex = ReadonlyMap<string, WorkspaceRootAuthority>;
|
|
207
|
+
/**
|
|
208
|
+
* The pre-task content hash of every TRACKED-SET path (#PR-2). `null` is a
|
|
209
|
+
* first-class state meaning "did not exist at shadow-create" — so a concurrent
|
|
210
|
+
* CREATE (real now exists, pre-task null) and concurrent DELETE (real now gone,
|
|
211
|
+
* pre-task hash) are both caught at promote time.
|
|
212
|
+
*/
|
|
213
|
+
export type PreTaskHashes = Map<string, string | null>;
|
|
214
|
+
export type PreTaskModes = Map<string, number | null>;
|
|
215
|
+
/** Injected for deterministic tests; production uses the real filesystem. */
|
|
216
|
+
export interface ShadowEnv {
|
|
217
|
+
/** @deprecated Compatibility-only; filesystem snapshots do not use Git retries. */
|
|
218
|
+
sleep?: (ms: number) => Promise<void>;
|
|
219
|
+
/** Override the per-task state dir root (default `~/.codevibe/shadow-state`). */
|
|
220
|
+
stateRootDir?: string;
|
|
221
|
+
/** Override the shadow temp-dir root (default `os.tmpdir()`). */
|
|
222
|
+
shadowRootDir?: string;
|
|
223
|
+
/** @internal lower deterministic limit for serialized-marker boundary tests. */
|
|
224
|
+
maxStateMarkerBytes?: number;
|
|
225
|
+
/** TTL for the GC reaper. */
|
|
226
|
+
ttlMs?: number;
|
|
227
|
+
/** @internal lower deterministic workspace-authority helper deadline. */
|
|
228
|
+
workspaceAuthorityHelperTimeoutMs?: number;
|
|
229
|
+
/** @internal deterministic root/recovery authority stall seam. */
|
|
230
|
+
testHangWorkspaceAuthorityStage?: (target: string, boundary: string) => 'realpath' | 'lstat' | 'open' | 'stat' | 'close' | undefined;
|
|
231
|
+
/** Hook to terminate task-spawned children rooted in the shadow before teardown. */
|
|
232
|
+
killChildrenInShadow?: (shadowDir: string) => Promise<void>;
|
|
233
|
+
/** @internal lower deterministic aggregate quota for tests. */
|
|
234
|
+
maxSessionPhysicalCopyBytes?: number;
|
|
235
|
+
/** @internal lower deterministic aggregate pre-image quota for tests. */
|
|
236
|
+
maxPromotionPreImageAggregateBytes?: number;
|
|
237
|
+
/** Test seam after the stable source handle is opened but before physical streaming. */
|
|
238
|
+
beforePhysicalCopy?: (source: string) => Promise<void>;
|
|
239
|
+
/** @internal force the production helper's bounded physical-copy branch. */
|
|
240
|
+
forcePhysicalMaterialization?: boolean;
|
|
241
|
+
/** @internal lower deterministic materialization-helper deadline for tests. */
|
|
242
|
+
materializationHelperTimeoutMs?: number;
|
|
243
|
+
/** @internal deterministic live-workspace helper stall seam. */
|
|
244
|
+
testHangMaterializationHelperStage?: (source: string) => MaterializationHangStage | undefined;
|
|
245
|
+
/** Test seam after a tracked hash handle opens and before its bounded read. */
|
|
246
|
+
beforeTrackedHashRead?: (filePath: string) => Promise<void>;
|
|
247
|
+
/** Test seam after materialization and before hashing/marker persistence. */
|
|
248
|
+
afterShadowMaterialized?: (shadowDir: string) => Promise<void>;
|
|
249
|
+
/** Test seam immediately before each recovery-byte/directory durability sync. */
|
|
250
|
+
beforeSnapshotDurabilitySync?: (kind: 'file' | 'directory' | 'parent', target: string) => Promise<void> | void;
|
|
251
|
+
/** Test seam after copy and before the final durability seal + atomic exposure. */
|
|
252
|
+
beforeSnapshotExpose?: (stagingDir: string, finalDir: string) => Promise<void> | void;
|
|
253
|
+
/** @internal race seam after rename while the lifecycle fence is still held. */
|
|
254
|
+
afterSnapshotExposeRename?: (finalDir: string) => Promise<void> | void;
|
|
255
|
+
/** Test seam while the lifecycle fence is held, immediately before owner publication. */
|
|
256
|
+
beforeSnapshotOwnerPublish?: (stagingDir: string) => Promise<void> | void;
|
|
257
|
+
/** @internal failure seam after inode capture but before external authority commits. */
|
|
258
|
+
beforeExposureRetentionPublish?: (stagingDir: string, retentionFile: string) => Promise<void> | void;
|
|
259
|
+
/** Test seam after merge planning and before an integration snapshot is created. */
|
|
260
|
+
beforePromotionWrite?: (path: string) => Promise<void>;
|
|
261
|
+
/** Test seam before COMMIT; no live-workspace mutation has occurred yet. */
|
|
262
|
+
beforePromotionCommit?: (path: string) => Promise<void>;
|
|
263
|
+
/** Test seam after a promote temp file is fsynced, immediately before final CAS checks. */
|
|
264
|
+
afterPromotionPrepared?: (path: string) => Promise<void>;
|
|
265
|
+
/** Test seam after final live-parent validation; helper operations stay fd-anchored. */
|
|
266
|
+
afterPromotionParentValidation?: (path: string) => Promise<void>;
|
|
267
|
+
/** @internal lower deterministic CAS-helper deadline for tests. */
|
|
268
|
+
promotionHelperTimeoutMs?: number;
|
|
269
|
+
/** @internal deterministic CAS-helper target-filesystem stall seam. */
|
|
270
|
+
testHangPromotionHelperStage?: (path: string) => 'root' | 'parent' | 'target' | undefined;
|
|
271
|
+
/** @internal deterministic helper-death seam after COMMIT/mutation. */
|
|
272
|
+
testCrashPromotionHelperStage?: (path: string) => CasHelperCrashStage | undefined;
|
|
273
|
+
/** Test seam after the exact target is displaced but before replacement/deletion. */
|
|
274
|
+
afterPromotionTargetDisplaced?: (path: string, recoveryName: string) => Promise<void>;
|
|
275
|
+
/** Test seam immediately before the public target is atomically quarantined. */
|
|
276
|
+
beforePromotionTargetQuarantine?: (path: string, quarantineName: string) => Promise<void>;
|
|
277
|
+
/** Test seam immediately before identity-conditioned promotion quarantine unlink. */
|
|
278
|
+
beforePromotionFinalUnlink?: (path: string, quarantineName: string) => Promise<void>;
|
|
279
|
+
/** Test seam before rollback verifies/reverses a just-promoted path. */
|
|
280
|
+
beforePromotionRollback?: (path: string) => Promise<void>;
|
|
281
|
+
/** Test seam after an anchored marker parent is validated but before commit. */
|
|
282
|
+
beforeMarkerWriteCommit?: (filePath: string) => Promise<void>;
|
|
283
|
+
/** Test seam after marker CAS validation while the cross-process lock is held. */
|
|
284
|
+
afterMarkerWriteValidation?: (filePath: string) => Promise<void>;
|
|
285
|
+
/** @internal inject a post-publication directory-sync failure for a marker write. */
|
|
286
|
+
failMarkerDirectorySync?: (filePath: string) => boolean;
|
|
287
|
+
/** @internal inject a post-publication directory-sync failure for the quota registry. */
|
|
288
|
+
failQuotaRegistryDirectorySync?: boolean;
|
|
289
|
+
/** @internal pause after quota-lock acquisition and before strict state enumeration. */
|
|
290
|
+
beforeQuotaFenceScan?: () => Promise<void>;
|
|
291
|
+
/** @internal deterministic replacement seam after a quota-reference task is enumerated. */
|
|
292
|
+
afterQuotaReferenceTaskEntry?: (stateDir: string) => Promise<void> | void;
|
|
293
|
+
/** @internal deterministic replacement seam after a quota-reference marker is enumerated. */
|
|
294
|
+
afterQuotaReferenceMarkerEntry?: (filePath: string) => Promise<void> | void;
|
|
295
|
+
/** @internal deterministic replacement seam after a quota-reference marker is opened. */
|
|
296
|
+
afterQuotaReferenceMarkerStat?: (filePath: string) => Promise<void> | void;
|
|
297
|
+
/** @internal fail initial/retry shadow-root durability before acknowledgement. */
|
|
298
|
+
failShadowRootDirectorySyncStage?: 'target-child' | 'target-parent';
|
|
299
|
+
/** @internal fail initial/retry state-root durability before acknowledgement. */
|
|
300
|
+
failStateRootDirectorySyncStage?: 'target-child' | 'target-parent';
|
|
301
|
+
/** Test seam after disposal reads semantic state but before its CAS transition. */
|
|
302
|
+
afterDisposalStateRead?: (state: ShadowPromoteState) => Promise<void>;
|
|
303
|
+
/** Test-only: exercise the cross-process lock without the parent-process queue. */
|
|
304
|
+
disableMarkerWriteProcessLock?: boolean;
|
|
305
|
+
/** Test seam after an anchored snapshot parent is validated but before deletion. */
|
|
306
|
+
beforeShadowDeleteCommit?: (shadowDir: string) => Promise<void>;
|
|
307
|
+
/** Test seam after the owned snapshot was renamed and inode-verified. */
|
|
308
|
+
afterShadowTombstoneRename?: (shadowDir: string, tombstoneDir: string) => Promise<void>;
|
|
309
|
+
/** @internal exact lifecycle-lock release seam after snapshot cleanup. */
|
|
310
|
+
beforeShadowLifecycleFinalRemove?: (artifactPath: string) => Promise<void> | void;
|
|
311
|
+
/** Test seam after snapshot removal but before DISPOSING marker retirement. */
|
|
312
|
+
afterShadowRemovedBeforeMarkerCleanup?: (shadowDir: string) => Promise<void>;
|
|
313
|
+
/** @internal deterministic state-directory replacement before residue cleanup. */
|
|
314
|
+
beforeCrashedStateArtifactCleanup?: (stateDir: string) => Promise<void> | void;
|
|
315
|
+
/** @internal deterministic cleanup-block replacement before exact retirement. */
|
|
316
|
+
beforeCleanupBlockFinalRemove?: (artifactPath: string) => Promise<void> | void;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Legacy migration contract from the branch-tip implementation. New creates
|
|
320
|
+
* ignore this option and always use a Git-independent snapshot. Historically it made a worktree a
|
|
321
|
+
* PERSISTENT track branch instead of a detached HEAD, so the merge-train can
|
|
322
|
+
* merge the track's committed tip. `baseSha` is the ONE group base pinned BEFORE
|
|
323
|
+
* the first track shadow is created (so every track roots at the same base — a
|
|
324
|
+
* deterministic merge-train input).
|
|
325
|
+
*/
|
|
326
|
+
export interface TrackBranchSpec {
|
|
327
|
+
/** The persistent branch name, e.g. `codevibe/track/<groupId>/<trackIndex>`. */
|
|
328
|
+
name: string;
|
|
329
|
+
/** The pinned group base commit the branch is created at. */
|
|
330
|
+
baseSha: string;
|
|
331
|
+
}
|
|
332
|
+
export declare function defaultStateRoot(): string;
|
|
333
|
+
export declare function hashContent(content: string): string;
|
|
334
|
+
export declare function openAnchoredDirectory(parent: string): Promise<fs.FileHandle>;
|
|
335
|
+
export declare function fsyncDirectory(dir: string): Promise<void>;
|
|
336
|
+
export declare function readShadowTextFile(shadowDir: string, rel: string, snapshotRootAuthority: WorkspaceRootAuthority): Promise<{
|
|
337
|
+
content: string;
|
|
338
|
+
hash: string;
|
|
339
|
+
mode: number;
|
|
340
|
+
}>;
|
|
341
|
+
export declare function assertSafeRelativePath(rel: string): void;
|
|
342
|
+
export declare function isInternalShadowPath(rel: string): boolean;
|
|
343
|
+
export declare function assertNotInternalShadowPath(rel: string): void;
|
|
344
|
+
export declare function normalizeFileMode(mode: number): number;
|
|
345
|
+
/**
|
|
346
|
+
* PHASE-589/469 W3.1 (C1) — read a real-tree file's CONTENT + hash by RELATIVE
|
|
347
|
+
* path BEFORE the promote mutates it; `{ content: null, hash: null }` if absent
|
|
348
|
+
* (a `created` file → an absent pre-image). NEVER logs the content (#589-G).
|
|
349
|
+
*/
|
|
350
|
+
export declare function readRealFileForManifest(workingDir: string, rel: string, expectedRoot: AnchoredFsIdentity | WorkspaceRootAuthority): Promise<{
|
|
351
|
+
content: string | null;
|
|
352
|
+
hash: string | null;
|
|
353
|
+
mode: number | null;
|
|
354
|
+
}>;
|
|
355
|
+
export declare function readRealFileMetadata(workingDir: string, rel: string, expectedRoot: AnchoredFsIdentity | WorkspaceRootAuthority): Promise<{
|
|
356
|
+
hash: string | null;
|
|
357
|
+
mode: number | null;
|
|
358
|
+
}>;
|