@mhalle/vost 0.8.1

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.
Files changed (51) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +24 -0
  3. package/dist/batch.d.ts +82 -0
  4. package/dist/batch.js +152 -0
  5. package/dist/batch.js.map +1 -0
  6. package/dist/copy.d.ts +242 -0
  7. package/dist/copy.js +1229 -0
  8. package/dist/copy.js.map +1 -0
  9. package/dist/exclude.d.ts +68 -0
  10. package/dist/exclude.js +157 -0
  11. package/dist/exclude.js.map +1 -0
  12. package/dist/fileobj.d.ts +82 -0
  13. package/dist/fileobj.js +127 -0
  14. package/dist/fileobj.js.map +1 -0
  15. package/dist/fs.d.ts +581 -0
  16. package/dist/fs.js +1318 -0
  17. package/dist/fs.js.map +1 -0
  18. package/dist/gitstore.d.ts +74 -0
  19. package/dist/gitstore.js +131 -0
  20. package/dist/gitstore.js.map +1 -0
  21. package/dist/glob.d.ts +14 -0
  22. package/dist/glob.js +68 -0
  23. package/dist/glob.js.map +1 -0
  24. package/dist/index.d.ts +37 -0
  25. package/dist/index.js +51 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/lock.d.ts +15 -0
  28. package/dist/lock.js +71 -0
  29. package/dist/lock.js.map +1 -0
  30. package/dist/mirror.d.ts +53 -0
  31. package/dist/mirror.js +270 -0
  32. package/dist/mirror.js.map +1 -0
  33. package/dist/notes.d.ts +148 -0
  34. package/dist/notes.js +508 -0
  35. package/dist/notes.js.map +1 -0
  36. package/dist/paths.d.ts +16 -0
  37. package/dist/paths.js +44 -0
  38. package/dist/paths.js.map +1 -0
  39. package/dist/refdict.d.ts +117 -0
  40. package/dist/refdict.js +267 -0
  41. package/dist/refdict.js.map +1 -0
  42. package/dist/reflog.d.ts +33 -0
  43. package/dist/reflog.js +83 -0
  44. package/dist/reflog.js.map +1 -0
  45. package/dist/tree.d.ts +79 -0
  46. package/dist/tree.js +283 -0
  47. package/dist/tree.js.map +1 -0
  48. package/dist/types.d.ts +354 -0
  49. package/dist/types.js +302 -0
  50. package/dist/types.js.map +1 -0
  51. package/package.json +58 -0
package/dist/tree.js ADDED
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Low-level tree manipulation for vost.
3
+ *
4
+ * Provides recursive tree rebuild and path-based read helpers
5
+ * on top of isomorphic-git's readTree/writeTree/writeBlob.
6
+ */
7
+ import git from 'isomorphic-git';
8
+ import { MODE_TREE, MODE_BLOB, MODE_BLOB_EXEC, typeForMode, FileNotFoundError, IsADirectoryError, NotADirectoryError, } from './types.js';
9
+ import { normalizePath, isRootPath } from './paths.js';
10
+ // ---------------------------------------------------------------------------
11
+ // Detect executable bit from filesystem
12
+ // ---------------------------------------------------------------------------
13
+ /**
14
+ * Detect the git filemode for a local file by checking its executable bit.
15
+ *
16
+ * @param fsModule - Node.js-compatible fs module.
17
+ * @param localPath - Path to the local file.
18
+ * @returns MODE_BLOB_EXEC if executable, MODE_BLOB otherwise.
19
+ * @throws IsADirectoryError if the path is a directory.
20
+ */
21
+ export async function modeFromDisk(fsModule, localPath) {
22
+ const stat = await fsModule.promises.stat(localPath);
23
+ if (stat.isDirectory())
24
+ throw new IsADirectoryError(localPath);
25
+ // Check executable bit (any of owner/group/other)
26
+ if ((stat.mode & 0o111) !== 0)
27
+ return MODE_BLOB_EXEC;
28
+ return MODE_BLOB;
29
+ }
30
+ /**
31
+ * Walk through tree to the object at the given path.
32
+ * Returns the final tree entry.
33
+ */
34
+ export async function walkTo(fsModule, gitdir, treeOid, path) {
35
+ const segments = path.split('/');
36
+ let currentOid = treeOid;
37
+ for (let i = 0; i < segments.length; i++) {
38
+ const { tree } = await git.readTree({ fs: fsModule, gitdir, oid: currentOid });
39
+ const entry = tree.find((e) => e.path === segments[i]);
40
+ if (!entry)
41
+ throw new FileNotFoundError(path);
42
+ if (i < segments.length - 1) {
43
+ if (entry.mode !== MODE_TREE) {
44
+ throw new NotADirectoryError(segments.slice(0, i + 1).join('/'));
45
+ }
46
+ currentOid = entry.oid;
47
+ }
48
+ else {
49
+ return entry;
50
+ }
51
+ }
52
+ throw new FileNotFoundError(path);
53
+ }
54
+ /**
55
+ * Return { oid, mode } of the entry at path, or null if missing.
56
+ */
57
+ export async function entryAtPath(fsModule, gitdir, treeOid, path) {
58
+ const segments = path.split('/');
59
+ let currentOid = treeOid;
60
+ for (let i = 0; i < segments.length; i++) {
61
+ let tree;
62
+ try {
63
+ const result = await git.readTree({ fs: fsModule, gitdir, oid: currentOid });
64
+ tree = result.tree;
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ const entry = tree.find((e) => e.path === segments[i]);
70
+ if (!entry)
71
+ return null;
72
+ if (i < segments.length - 1) {
73
+ if (entry.mode !== MODE_TREE)
74
+ return null;
75
+ currentOid = entry.oid;
76
+ }
77
+ else {
78
+ return { oid: entry.oid, mode: entry.mode };
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+ /**
84
+ * Read a blob at the given path in the tree.
85
+ */
86
+ export async function readBlobAtPath(fsModule, gitdir, treeOid, path) {
87
+ const normalized = normalizePath(path);
88
+ const entry = await walkTo(fsModule, gitdir, treeOid, normalized);
89
+ if (entry.mode === MODE_TREE)
90
+ throw new IsADirectoryError(normalized);
91
+ const { blob } = await git.readBlob({ fs: fsModule, gitdir, oid: entry.oid });
92
+ return blob;
93
+ }
94
+ /**
95
+ * List entry names at the given path (or root if path is null/empty).
96
+ */
97
+ export async function listTreeAtPath(fsModule, gitdir, treeOid, path) {
98
+ const entries = await listEntriesAtPath(fsModule, gitdir, treeOid, path);
99
+ return entries.map((e) => e.name);
100
+ }
101
+ /**
102
+ * List full entries at the given path (or root if path is null/empty).
103
+ */
104
+ export async function listEntriesAtPath(fsModule, gitdir, treeOid, path) {
105
+ let targetOid = treeOid;
106
+ if (path != null && !isRootPath(path)) {
107
+ const normalized = normalizePath(path);
108
+ const entry = await walkTo(fsModule, gitdir, treeOid, normalized);
109
+ if (entry.mode !== MODE_TREE)
110
+ throw new NotADirectoryError(normalized);
111
+ targetOid = entry.oid;
112
+ }
113
+ const { tree } = await git.readTree({ fs: fsModule, gitdir, oid: targetOid });
114
+ return tree.map((e) => ({ name: e.path, oid: e.oid, mode: e.mode }));
115
+ }
116
+ /**
117
+ * Walk the tree recursively, yielding (dirpath, dirnames, fileEntries).
118
+ */
119
+ export async function* walkTree(fsModule, gitdir, treeOid, prefix = '') {
120
+ const { tree } = await git.readTree({ fs: fsModule, gitdir, oid: treeOid });
121
+ const dirs = [];
122
+ const files = [];
123
+ const dirOids = [];
124
+ for (const entry of tree) {
125
+ if (entry.mode === MODE_TREE) {
126
+ dirs.push(entry.path);
127
+ dirOids.push([entry.path, entry.oid]);
128
+ }
129
+ else {
130
+ files.push({ name: entry.path, oid: entry.oid, mode: entry.mode });
131
+ }
132
+ }
133
+ yield [prefix, dirs, files];
134
+ for (const [name, oid] of dirOids) {
135
+ const childPrefix = prefix ? `${prefix}/${name}` : name;
136
+ yield* walkTree(fsModule, gitdir, oid, childPrefix);
137
+ }
138
+ }
139
+ /**
140
+ * Check if a path exists in the tree.
141
+ */
142
+ export async function existsAtPath(fsModule, gitdir, treeOid, path) {
143
+ const normalized = normalizePath(path);
144
+ const entry = await entryAtPath(fsModule, gitdir, treeOid, normalized);
145
+ return entry !== null;
146
+ }
147
+ // ---------------------------------------------------------------------------
148
+ // Count subdirectories (for stat nlink)
149
+ // ---------------------------------------------------------------------------
150
+ /**
151
+ * Count the number of immediate subdirectories in a tree (for stat nlink).
152
+ *
153
+ * @param fsModule - Node.js-compatible fs module.
154
+ * @param gitdir - Path to the bare git repository.
155
+ * @param treeOid - 40-char hex SHA of the tree object.
156
+ * @returns Number of subdirectory entries in the tree.
157
+ */
158
+ export async function countSubdirs(fsModule, gitdir, treeOid) {
159
+ const { tree } = await git.readTree({ fs: fsModule, gitdir, oid: treeOid });
160
+ return tree.filter(e => e.mode === MODE_TREE).length;
161
+ }
162
+ // ---------------------------------------------------------------------------
163
+ // Recursive tree rebuild
164
+ // ---------------------------------------------------------------------------
165
+ /**
166
+ * Rebuild a tree with writes and removes applied.
167
+ *
168
+ * Only the ancestor chain from changed leaves to root is rebuilt.
169
+ * Sibling subtrees are shared by hash reference.
170
+ */
171
+ export async function rebuildTree(fsModule, gitdir, baseTreeOid, writes, removes) {
172
+ // Group changes by first path segment
173
+ const subWrites = new Map();
174
+ const leafWrites = new Map();
175
+ const subRemoves = new Map();
176
+ const leafRemoves = new Set();
177
+ for (const [path, write] of writes) {
178
+ const slashIdx = path.indexOf('/');
179
+ if (slashIdx < 0) {
180
+ leafWrites.set(path, write);
181
+ }
182
+ else {
183
+ const first = path.slice(0, slashIdx);
184
+ const rest = path.slice(slashIdx + 1);
185
+ if (!subWrites.has(first))
186
+ subWrites.set(first, new Map());
187
+ subWrites.get(first).set(rest, write);
188
+ }
189
+ }
190
+ for (const path of removes) {
191
+ const slashIdx = path.indexOf('/');
192
+ if (slashIdx < 0) {
193
+ leafRemoves.add(path);
194
+ }
195
+ else {
196
+ const first = path.slice(0, slashIdx);
197
+ const rest = path.slice(slashIdx + 1);
198
+ if (!subRemoves.has(first))
199
+ subRemoves.set(first, new Set());
200
+ subRemoves.get(first).add(rest);
201
+ }
202
+ }
203
+ // Read existing tree entries
204
+ let entries = [];
205
+ if (baseTreeOid) {
206
+ const { tree } = await git.readTree({ fs: fsModule, gitdir, oid: baseTreeOid });
207
+ entries = tree.map((e) => ({ ...e }));
208
+ }
209
+ // Build lookup: name → existing entry
210
+ const entryMap = new Map();
211
+ for (const e of entries) {
212
+ entryMap.set(e.path, e);
213
+ }
214
+ // Apply leaf writes (may overwrite existing entries)
215
+ for (const [name, write] of leafWrites) {
216
+ let blobOid;
217
+ if (write.oid) {
218
+ blobOid = write.oid;
219
+ }
220
+ else if (write.data) {
221
+ blobOid = await git.writeBlob({ fs: fsModule, gitdir, blob: write.data });
222
+ }
223
+ else {
224
+ throw new Error(`Write for '${name}' has neither data nor oid`);
225
+ }
226
+ entryMap.set(name, {
227
+ mode: write.mode,
228
+ path: name,
229
+ oid: blobOid,
230
+ type: typeForMode(write.mode),
231
+ });
232
+ }
233
+ // Apply leaf removes
234
+ for (const name of leafRemoves) {
235
+ entryMap.delete(name);
236
+ }
237
+ // Collect existing subtree OIDs
238
+ const existingSubtrees = new Map();
239
+ for (const [name, entry] of entryMap) {
240
+ if (entry.mode === MODE_TREE) {
241
+ existingSubtrees.set(name, entry.oid);
242
+ }
243
+ }
244
+ // Recurse into subdirectories
245
+ const allSubdirs = new Set([...subWrites.keys(), ...subRemoves.keys()]);
246
+ for (const subdir of allSubdirs) {
247
+ let existingOid = existingSubtrees.get(subdir) ?? null;
248
+ // If there's a non-tree entry at this name, remove it to make way for a tree
249
+ if (existingOid === null) {
250
+ const existing = entryMap.get(subdir);
251
+ if (existing && existing.mode !== MODE_TREE) {
252
+ entryMap.delete(subdir);
253
+ }
254
+ }
255
+ const newSubtreeOid = await rebuildTree(fsModule, gitdir, existingOid, subWrites.get(subdir) ?? new Map(), subRemoves.get(subdir) ?? new Set());
256
+ // Check if subtree is empty (prune empty directories)
257
+ const { tree: subtreeEntries } = await git.readTree({
258
+ fs: fsModule,
259
+ gitdir,
260
+ oid: newSubtreeOid,
261
+ });
262
+ if (subtreeEntries.length === 0) {
263
+ entryMap.delete(subdir);
264
+ }
265
+ else {
266
+ entryMap.set(subdir, {
267
+ mode: MODE_TREE,
268
+ path: subdir,
269
+ oid: newSubtreeOid,
270
+ type: 'tree',
271
+ });
272
+ }
273
+ }
274
+ // Write new tree from modified entries
275
+ const treeEntries = Array.from(entryMap.values()).map((e) => ({
276
+ mode: e.mode,
277
+ path: e.path,
278
+ oid: e.oid,
279
+ type: typeForMode(e.mode),
280
+ }));
281
+ return await git.writeTree({ fs: fsModule, gitdir, tree: treeEntries });
282
+ }
283
+ //# sourceMappingURL=tree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.js","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,354 @@
1
+ /**
2
+ * Shared types, constants, enums, and error classes for vost.
3
+ */
4
+ /** Git filemode for tree (directory) entries. */
5
+ export declare const MODE_TREE = "040000";
6
+ /** Git filemode for regular blob (file) entries. */
7
+ export declare const MODE_BLOB = "100644";
8
+ /** Git filemode for executable blob entries. */
9
+ export declare const MODE_BLOB_EXEC = "100755";
10
+ /** Git filemode for symbolic link entries. */
11
+ export declare const MODE_LINK = "120000";
12
+ /** Convert an octal mode string (e.g. '100644') to an integer. */
13
+ export declare function modeToInt(mode: string): number;
14
+ /** Convert an integer filemode to a zero-padded octal string. */
15
+ export declare function modeFromInt(mode: number): string;
16
+ /** Return the isomorphic-git object type for a given mode string. */
17
+ export declare function typeForMode(mode: string): 'blob' | 'tree' | 'commit';
18
+ /**
19
+ * File type classification for git tree entries.
20
+ *
21
+ * - `BLOB` - Regular file (mode 100644).
22
+ * - `EXECUTABLE` - Executable file (mode 100755).
23
+ * - `LINK` - Symbolic link (mode 120000).
24
+ * - `TREE` - Directory (mode 040000).
25
+ */
26
+ export declare const FileType: {
27
+ /** Regular file (mode 100644). */
28
+ readonly BLOB: "blob";
29
+ /** Executable file (mode 100755). */
30
+ readonly EXECUTABLE: "executable";
31
+ /** Symbolic link (mode 120000). */
32
+ readonly LINK: "link";
33
+ /** Directory (mode 040000). */
34
+ readonly TREE: "tree";
35
+ };
36
+ /** Union type of all FileType values. */
37
+ export type FileType = (typeof FileType)[keyof typeof FileType];
38
+ /**
39
+ * Convert a git filemode string to a FileType enum value.
40
+ *
41
+ * @param mode - Octal mode string (e.g. '100644').
42
+ * @returns The corresponding FileType.
43
+ * @throws {Error} If the mode is not recognized.
44
+ */
45
+ export declare function fileTypeFromMode(mode: string): FileType;
46
+ /**
47
+ * Convert a FileType enum value to a git filemode string.
48
+ *
49
+ * @param ft - FileType value.
50
+ * @returns The corresponding octal mode string.
51
+ */
52
+ export declare function fileModeFromType(ft: FileType): string;
53
+ /** Base error class for all vost errors. */
54
+ export declare class GitStoreError extends Error {
55
+ constructor(message: string);
56
+ }
57
+ /**
58
+ * Raised when a branch has advanced since the FS snapshot was taken,
59
+ * causing a compare-and-swap (CAS) failure on commit.
60
+ */
61
+ export declare class StaleSnapshotError extends GitStoreError {
62
+ constructor(message: string);
63
+ }
64
+ /** Raised when a path does not exist in the repository tree. */
65
+ export declare class FileNotFoundError extends GitStoreError {
66
+ code: string;
67
+ constructor(path: string);
68
+ }
69
+ /** Raised when an operation expected a file but found a directory. */
70
+ export declare class IsADirectoryError extends GitStoreError {
71
+ code: string;
72
+ constructor(path: string);
73
+ }
74
+ /** Raised when an operation expected a directory but found a file. */
75
+ export declare class NotADirectoryError extends GitStoreError {
76
+ code: string;
77
+ constructor(path: string);
78
+ }
79
+ /** Raised when a write is attempted on a read-only snapshot (e.g. a tag). */
80
+ export declare class PermissionError extends GitStoreError {
81
+ code: string;
82
+ constructor(message: string);
83
+ }
84
+ /** Raised when a branch, tag, or note key is not found. */
85
+ export declare class KeyNotFoundError extends GitStoreError {
86
+ constructor(message: string);
87
+ }
88
+ /** Raised when a tag already exists and cannot be overwritten. */
89
+ export declare class KeyExistsError extends GitStoreError {
90
+ constructor(message: string);
91
+ }
92
+ /** Raised when a ref name contains invalid characters. */
93
+ export declare class InvalidRefNameError extends GitStoreError {
94
+ constructor(message: string);
95
+ }
96
+ /** Raised when a path is empty or contains invalid segments. */
97
+ export declare class InvalidPathError extends GitStoreError {
98
+ constructor(message: string);
99
+ }
100
+ /** Raised when a batch is used after it has been committed or closed. */
101
+ export declare class BatchClosedError extends GitStoreError {
102
+ constructor(message: string);
103
+ }
104
+ /**
105
+ * A file or directory entry yielded by `FS.walk()` and `FS.listdir()`.
106
+ */
107
+ export interface WalkEntry {
108
+ /** Entry name (file or directory basename). */
109
+ name: string;
110
+ /** 40-char hex object ID (SHA). */
111
+ oid: string;
112
+ /** Git filemode string (e.g. '100644', '040000'). */
113
+ mode: string;
114
+ }
115
+ /**
116
+ * POSIX-like stat result for a vost path.
117
+ *
118
+ * Combines file type, size, OID, nlink, and mtime in a single structure,
119
+ * optimized for the FUSE `getattr` hot path.
120
+ */
121
+ export interface StatResult {
122
+ /** Raw git filemode as integer (e.g. 0o100644, 0o040000). */
123
+ mode: number;
124
+ /** File type classification. */
125
+ fileType: FileType;
126
+ /** Object size in bytes (0 for directories). */
127
+ size: number;
128
+ /** 40-char hex SHA of the object (inode proxy). */
129
+ hash: string;
130
+ /** 1 for files/symlinks, 2 + subdirectory count for directories. */
131
+ nlink: number;
132
+ /** Commit timestamp as POSIX epoch seconds. */
133
+ mtime: number;
134
+ }
135
+ /**
136
+ * Return the FileType for a WalkEntry.
137
+ *
138
+ * @param entry - A walk entry from `FS.walk()` or `FS.listdir()`.
139
+ * @returns The FileType corresponding to the entry's mode.
140
+ */
141
+ export declare function walkEntryFileType(entry: WalkEntry): FileType;
142
+ /**
143
+ * Describes a single file write for `FS.apply()`.
144
+ *
145
+ * Exactly one of `data` or `target` must be provided.
146
+ * `target` creates a symbolic link entry; `mode` is not allowed with it.
147
+ */
148
+ export interface WriteEntry {
149
+ /** Raw data (bytes) or text (string). Mutually exclusive with `target`. */
150
+ data?: Uint8Array | string;
151
+ /** Git filemode override (e.g. FileType.EXECUTABLE). */
152
+ mode?: FileType | string;
153
+ /** Symlink target string. Mutually exclusive with `data`. */
154
+ target?: string;
155
+ }
156
+ /**
157
+ * Validate a WriteEntry, throwing if both `data` and `target` are set,
158
+ * neither is set, or `mode` is combined with `target`.
159
+ */
160
+ export declare function validateWriteEntry(entry: WriteEntry): void;
161
+ /**
162
+ * A file entry in a change report, with path and type information.
163
+ */
164
+ export interface FileEntry {
165
+ /** Repo-relative path. */
166
+ path: string;
167
+ /** File type (blob, executable, link, or tree). */
168
+ type: FileType;
169
+ /** Optional source path (for copy operations). */
170
+ src?: string;
171
+ }
172
+ /**
173
+ * Create a FileEntry from a path and git filemode string.
174
+ *
175
+ * @param path - Repo-relative path.
176
+ * @param mode - Git filemode string.
177
+ * @param src - Optional source path.
178
+ */
179
+ export declare function fileEntryFromMode(path: string, mode: string, src?: string): FileEntry;
180
+ /** A single action entry (add, update, or delete) for a path. */
181
+ export interface ChangeAction {
182
+ /** Repo-relative path. */
183
+ path: string;
184
+ /** The kind of change. */
185
+ action: 'add' | 'update' | 'delete';
186
+ }
187
+ /** An error or warning associated with a path during a copy/sync operation. */
188
+ export interface ChangeError {
189
+ /** Repo-relative path that caused the error. */
190
+ path: string;
191
+ /** Human-readable error description. */
192
+ error: string;
193
+ }
194
+ /**
195
+ * Report of changes from a write, copy, sync, remove, or move operation.
196
+ *
197
+ * Available on the resulting FS via `fs.changes`.
198
+ */
199
+ export interface ChangeReport {
200
+ /** Files that were added. */
201
+ add: FileEntry[];
202
+ /** Files that were updated. */
203
+ update: FileEntry[];
204
+ /** Files that were deleted. */
205
+ delete: FileEntry[];
206
+ /** Errors encountered during the operation. */
207
+ errors: ChangeError[];
208
+ /** Warnings encountered during the operation. */
209
+ warnings: ChangeError[];
210
+ }
211
+ /** Create an empty ChangeReport with no actions or errors. */
212
+ export declare function emptyChangeReport(): ChangeReport;
213
+ /** Return true if the report contains no adds, updates, or deletes. */
214
+ export declare function changeReportInSync(cr: ChangeReport): boolean;
215
+ /** Return the total number of adds, updates, and deletes. */
216
+ export declare function changeReportTotal(cr: ChangeReport): number;
217
+ /** Flatten a ChangeReport into a sorted list of ChangeAction entries. */
218
+ export declare function changeReportActions(cr: ChangeReport): ChangeAction[];
219
+ /** Return null if the report is completely empty, otherwise return it as-is. */
220
+ export declare function finalizeChanges(cr: ChangeReport): ChangeReport | null;
221
+ /**
222
+ * Generate a commit message from a ChangeReport.
223
+ *
224
+ * If `customMessage` is provided and contains `{` placeholders, they are
225
+ * expanded (e.g. `{add_count}`, `{total_count}`, `{default}`).
226
+ * Otherwise, an auto-generated summary is used.
227
+ *
228
+ * @param changes - The change report to summarize.
229
+ * @param customMessage - Optional user-provided message template.
230
+ * @param operation - Optional operation name for auto messages (e.g. 'cp').
231
+ */
232
+ export declare function formatCommitMessage(changes: ChangeReport, customMessage?: string | null, operation?: string | null): string;
233
+ /** A single ref change in a mirror operation (backup or restore). */
234
+ export interface RefChange {
235
+ /** Full ref name (e.g. 'refs/heads/main'). */
236
+ ref: string;
237
+ /** Previous target SHA, or undefined for newly created refs. */
238
+ oldTarget?: string;
239
+ /** New target SHA, or undefined for deleted refs. */
240
+ newTarget?: string;
241
+ }
242
+ /**
243
+ * Report of ref changes from a `backup()` or `restore()` mirror operation.
244
+ */
245
+ export interface MirrorDiff {
246
+ /** Refs that were created. */
247
+ add: RefChange[];
248
+ /** Refs whose target changed. */
249
+ update: RefChange[];
250
+ /** Refs that were deleted. */
251
+ delete: RefChange[];
252
+ }
253
+ /** Return true if the mirror diff contains no changes. */
254
+ export declare function mirrorDiffInSync(md: MirrorDiff): boolean;
255
+ /** Return the total number of ref changes. */
256
+ export declare function mirrorDiffTotal(md: MirrorDiff): number;
257
+ /**
258
+ * A single reflog entry recording a branch movement.
259
+ */
260
+ export interface ReflogEntry {
261
+ /** Previous 40-char hex commit SHA. */
262
+ oldSha: string;
263
+ /** New 40-char hex commit SHA. */
264
+ newSha: string;
265
+ /** Identity string of the committer. */
266
+ committer: string;
267
+ /** POSIX epoch seconds of the entry. */
268
+ timestamp: number;
269
+ /** Reflog message (e.g. 'commit: + file.txt'). */
270
+ message: string;
271
+ }
272
+ /**
273
+ * The filesystem interface expected by vost.
274
+ * Compatible with Node.js `fs` module and isomorphic-git's FsClient.
275
+ */
276
+ export interface FsModule {
277
+ promises: {
278
+ readFile(path: string, options?: {
279
+ encoding?: string;
280
+ }): Promise<Uint8Array | string>;
281
+ writeFile(path: string, data: Uint8Array | string, options?: {
282
+ mode?: number;
283
+ }): Promise<void>;
284
+ unlink(path: string): Promise<void>;
285
+ readdir(path: string): Promise<string[]>;
286
+ mkdir(path: string, options?: {
287
+ recursive?: boolean;
288
+ }): Promise<string | undefined>;
289
+ rmdir(path: string): Promise<void>;
290
+ stat(path: string): Promise<{
291
+ mode: number;
292
+ size: number;
293
+ isDirectory(): boolean;
294
+ isFile(): boolean;
295
+ isSymbolicLink(): boolean;
296
+ mtimeMs: number;
297
+ }>;
298
+ lstat(path: string): Promise<{
299
+ mode: number;
300
+ size: number;
301
+ isDirectory(): boolean;
302
+ isFile(): boolean;
303
+ isSymbolicLink(): boolean;
304
+ mtimeMs: number;
305
+ }>;
306
+ readlink(path: string): Promise<string>;
307
+ symlink(target: string, path: string): Promise<void>;
308
+ chmod(path: string, mode: number): Promise<void>;
309
+ access(path: string, mode?: number): Promise<void>;
310
+ appendFile(path: string, data: Uint8Array | string): Promise<void>;
311
+ rename(path: string, newPath: string): Promise<void>;
312
+ open(path: string, flags: string | number, mode?: number): Promise<{
313
+ close(): Promise<void>;
314
+ }>;
315
+ rm?(path: string, options?: {
316
+ recursive?: boolean;
317
+ force?: boolean;
318
+ }): Promise<void>;
319
+ };
320
+ realpathSync(path: string): string;
321
+ readFile: Function;
322
+ writeFile: Function;
323
+ unlink: Function;
324
+ readdir: Function;
325
+ mkdir: Function;
326
+ rmdir: Function;
327
+ stat: Function;
328
+ lstat: Function;
329
+ readlink: Function;
330
+ symlink: Function;
331
+ chmod: Function;
332
+ }
333
+ /** HTTP client interface for mirror operations (compatible with isomorphic-git). */
334
+ export interface HttpClient {
335
+ request: Function;
336
+ }
337
+ /** Author/committer identity used for commits. */
338
+ export interface Signature {
339
+ /** Author name (e.g. 'vost'). */
340
+ name: string;
341
+ /** Author email (e.g. 'vost@localhost'). */
342
+ email: string;
343
+ }
344
+ /** Metadata extracted from a git commit object. */
345
+ export interface CommitInfo {
346
+ /** Commit message (trailing newline stripped). */
347
+ message: string;
348
+ /** Timezone-aware commit timestamp. */
349
+ time: Date;
350
+ /** Commit author's name. */
351
+ authorName: string;
352
+ /** Commit author's email address. */
353
+ authorEmail: string;
354
+ }