@scolladon/tsgit 1.0.0 → 1.2.0

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 (144) hide show
  1. package/README.md +29 -137
  2. package/dist/cjs/adapters/browser/index.cjs +1 -1
  3. package/dist/cjs/adapters/browser/index.cjs.map +1 -1
  4. package/dist/cjs/adapters/memory/index.cjs +1 -1
  5. package/dist/cjs/adapters/memory/index.cjs.map +1 -1
  6. package/dist/cjs/adapters/node/index.cjs +1 -1
  7. package/dist/cjs/adapters/node/index.cjs.map +1 -1
  8. package/dist/cjs/chunks/browser-http-transport-D4NH-8oJ.cjs +2 -0
  9. package/dist/cjs/chunks/browser-http-transport-D4NH-8oJ.cjs.map +1 -0
  10. package/dist/cjs/chunks/context-BcoAzPuU.cjs.map +1 -1
  11. package/dist/cjs/chunks/error-CDLOBdNU.cjs +2 -0
  12. package/dist/cjs/chunks/error-CDLOBdNU.cjs.map +1 -0
  13. package/dist/cjs/chunks/index-BVArBKuk.cjs +2 -0
  14. package/dist/cjs/chunks/index-BVArBKuk.cjs.map +1 -0
  15. package/dist/cjs/chunks/index-DE9HSiWf.cjs +2 -0
  16. package/dist/cjs/chunks/index-DE9HSiWf.cjs.map +1 -0
  17. package/dist/cjs/chunks/{logger-Cz9r6yt5.cjs → logger-CVG0zcPH.cjs} +2 -2
  18. package/dist/cjs/chunks/{logger-Cz9r6yt5.cjs.map → logger-CVG0zcPH.cjs.map} +1 -1
  19. package/dist/cjs/chunks/memory-http-transport-DXwDGKtR.cjs +2 -0
  20. package/dist/cjs/chunks/memory-http-transport-DXwDGKtR.cjs.map +1 -0
  21. package/dist/cjs/chunks/node-http-transport-vrbnNEDb.cjs +2 -0
  22. package/dist/cjs/chunks/node-http-transport-vrbnNEDb.cjs.map +1 -0
  23. package/dist/cjs/chunks/{progress-CK7CT9vU.cjs → progress-Bj2w-90A.cjs} +2 -2
  24. package/dist/cjs/chunks/{progress-CK7CT9vU.cjs.map → progress-Bj2w-90A.cjs.map} +1 -1
  25. package/dist/cjs/chunks/readable-stream-MTA6D0Zh.cjs +2 -0
  26. package/dist/cjs/chunks/readable-stream-MTA6D0Zh.cjs.map +1 -0
  27. package/dist/cjs/chunks/repository-BJwTSiGf.cjs +2 -0
  28. package/dist/cjs/chunks/repository-BJwTSiGf.cjs.map +1 -0
  29. package/dist/cjs/commands/index.cjs +1 -1
  30. package/dist/cjs/index.browser.cjs +1 -1
  31. package/dist/cjs/index.browser.cjs.map +1 -1
  32. package/dist/cjs/index.cjs +1 -1
  33. package/dist/cjs/index.default.cjs +1 -1
  34. package/dist/cjs/index.default.cjs.map +1 -1
  35. package/dist/cjs/index.node.cjs +1 -1
  36. package/dist/cjs/index.node.cjs.map +1 -1
  37. package/dist/cjs/operators/index.cjs +1 -1
  38. package/dist/cjs/operators/index.cjs.map +1 -1
  39. package/dist/cjs/primitives/index.cjs +1 -1
  40. package/dist/cjs/primitives/index.cjs.map +1 -1
  41. package/dist/cjs/transport/index.cjs.map +1 -1
  42. package/dist/esm/adapters/browser/index.js +1 -1
  43. package/dist/esm/adapters/browser/index.js.map +1 -1
  44. package/dist/esm/adapters/memory/index.js +1 -1
  45. package/dist/esm/adapters/memory/index.js.map +1 -1
  46. package/dist/esm/adapters/node/index.js +1 -1
  47. package/dist/esm/adapters/node/index.js.map +1 -1
  48. package/dist/esm/chunks/browser-http-transport-DL8bkNdg.js +2 -0
  49. package/dist/esm/chunks/browser-http-transport-DL8bkNdg.js.map +1 -0
  50. package/dist/esm/chunks/context-CumKOV7K.js.map +1 -1
  51. package/dist/esm/chunks/error-MOmSzp9Z.js +2 -0
  52. package/dist/esm/chunks/error-MOmSzp9Z.js.map +1 -0
  53. package/dist/esm/chunks/index-BjmofbKE.js +2 -0
  54. package/dist/esm/chunks/index-BjmofbKE.js.map +1 -0
  55. package/dist/esm/chunks/index-Jh5R-UmU.js +2 -0
  56. package/dist/esm/chunks/index-Jh5R-UmU.js.map +1 -0
  57. package/dist/esm/chunks/{logger-84ixEPbQ.js → logger-DP2cCpvL.js} +2 -2
  58. package/dist/esm/chunks/{logger-84ixEPbQ.js.map → logger-DP2cCpvL.js.map} +1 -1
  59. package/dist/esm/chunks/memory-http-transport-COJU6VOL.js +2 -0
  60. package/dist/esm/chunks/memory-http-transport-COJU6VOL.js.map +1 -0
  61. package/dist/esm/chunks/node-http-transport-DYCFIJbc.js +2 -0
  62. package/dist/esm/chunks/node-http-transport-DYCFIJbc.js.map +1 -0
  63. package/dist/esm/chunks/{progress-OTDhgmPO.js → progress-NePjO3Kd.js} +2 -2
  64. package/dist/esm/chunks/{progress-OTDhgmPO.js.map → progress-NePjO3Kd.js.map} +1 -1
  65. package/dist/esm/chunks/readable-stream-CGuf8k1J.js +2 -0
  66. package/dist/esm/chunks/readable-stream-CGuf8k1J.js.map +1 -0
  67. package/dist/esm/chunks/repository-Cs-dbHqO.js +2 -0
  68. package/dist/esm/chunks/repository-Cs-dbHqO.js.map +1 -0
  69. package/dist/esm/commands/index.js +1 -1
  70. package/dist/esm/index.browser.js +1 -1
  71. package/dist/esm/index.browser.js.map +1 -1
  72. package/dist/esm/index.default.js +1 -1
  73. package/dist/esm/index.default.js.map +1 -1
  74. package/dist/esm/index.js +1 -1
  75. package/dist/esm/index.node.js +1 -1
  76. package/dist/esm/index.node.js.map +1 -1
  77. package/dist/esm/operators/index.js +1 -1
  78. package/dist/esm/operators/index.js.map +1 -1
  79. package/dist/esm/primitives/index.js +1 -1
  80. package/dist/esm/primitives/index.js.map +1 -1
  81. package/dist/esm/transport/index.js.map +1 -1
  82. package/dist/types/adapters/browser/index.d.cts +2 -1
  83. package/dist/types/adapters/browser/index.d.ts +2 -1
  84. package/dist/types/adapters/memory/index.d.cts +23 -2
  85. package/dist/types/adapters/memory/index.d.ts +23 -2
  86. package/dist/types/adapters/node/index.d.cts +178 -3
  87. package/dist/types/adapters/node/index.d.ts +178 -3
  88. package/dist/types/chunks/{context-CTaXSPiP.d.ts → context-BORy7yXb.d.ts} +133 -20
  89. package/dist/types/chunks/{context-d36639-i.d.cts → context-CMrHCVwK.d.cts} +133 -20
  90. package/dist/types/chunks/reflog-entry-BIf-zt__.d.cts +331 -0
  91. package/dist/types/chunks/reflog-entry-D9P2hCgv.d.ts +331 -0
  92. package/dist/types/chunks/{repository-CFT9j9H6.d.cts → repository-BqibvTOu.d.cts} +23 -4
  93. package/dist/types/chunks/{repository-ntg7eXb2.d.ts → repository-C4rN09Am.d.ts} +23 -4
  94. package/dist/types/chunks/write-tree-B8G6kgTy.d.cts +154 -0
  95. package/dist/types/chunks/write-tree-BXCDChvv.d.ts +154 -0
  96. package/dist/types/commands/index.d.cts +229 -37
  97. package/dist/types/commands/index.d.ts +229 -37
  98. package/dist/types/index.browser.d.cts +4 -4
  99. package/dist/types/index.browser.d.ts +4 -4
  100. package/dist/types/index.d.cts +4 -4
  101. package/dist/types/index.d.ts +4 -4
  102. package/dist/types/index.default.d.cts +4 -4
  103. package/dist/types/index.default.d.ts +4 -4
  104. package/dist/types/index.node.d.cts +4 -4
  105. package/dist/types/index.node.d.ts +4 -4
  106. package/dist/types/operators/index.d.cts +17 -1
  107. package/dist/types/operators/index.d.ts +17 -1
  108. package/dist/types/primitives/index.d.cts +393 -171
  109. package/dist/types/primitives/index.d.ts +393 -171
  110. package/package.json +76 -10
  111. package/dist/cjs/chunks/browser-http-transport-BBF8uw-f.cjs +0 -2
  112. package/dist/cjs/chunks/browser-http-transport-BBF8uw-f.cjs.map +0 -1
  113. package/dist/cjs/chunks/error-DL4SHCBJ.cjs +0 -2
  114. package/dist/cjs/chunks/error-DL4SHCBJ.cjs.map +0 -1
  115. package/dist/cjs/chunks/error-DN8Vnwr4.cjs +0 -2
  116. package/dist/cjs/chunks/error-DN8Vnwr4.cjs.map +0 -1
  117. package/dist/cjs/chunks/index-iUd-bwwm.cjs +0 -2
  118. package/dist/cjs/chunks/index-iUd-bwwm.cjs.map +0 -1
  119. package/dist/cjs/chunks/memory-http-transport-DGll7Af4.cjs +0 -2
  120. package/dist/cjs/chunks/memory-http-transport-DGll7Af4.cjs.map +0 -1
  121. package/dist/cjs/chunks/merge-base-DlGWnkxP.cjs +0 -2
  122. package/dist/cjs/chunks/merge-base-DlGWnkxP.cjs.map +0 -1
  123. package/dist/cjs/chunks/node-http-transport-CuOgJlws.cjs +0 -2
  124. package/dist/cjs/chunks/node-http-transport-CuOgJlws.cjs.map +0 -1
  125. package/dist/cjs/chunks/repository-Cfo6Bj8T.cjs +0 -2
  126. package/dist/cjs/chunks/repository-Cfo6Bj8T.cjs.map +0 -1
  127. package/dist/esm/chunks/browser-http-transport-mZQKkInJ.js +0 -2
  128. package/dist/esm/chunks/browser-http-transport-mZQKkInJ.js.map +0 -1
  129. package/dist/esm/chunks/error-CnIcr6IG.js +0 -2
  130. package/dist/esm/chunks/error-CnIcr6IG.js.map +0 -1
  131. package/dist/esm/chunks/error-DTEP18A3.js +0 -2
  132. package/dist/esm/chunks/error-DTEP18A3.js.map +0 -1
  133. package/dist/esm/chunks/index-CJc-SKMj.js +0 -2
  134. package/dist/esm/chunks/index-CJc-SKMj.js.map +0 -1
  135. package/dist/esm/chunks/memory-http-transport-BmHjaEWj.js +0 -2
  136. package/dist/esm/chunks/memory-http-transport-BmHjaEWj.js.map +0 -1
  137. package/dist/esm/chunks/merge-base-DmuOYxfP.js +0 -2
  138. package/dist/esm/chunks/merge-base-DmuOYxfP.js.map +0 -1
  139. package/dist/esm/chunks/node-http-transport-Bz3noIS3.js +0 -2
  140. package/dist/esm/chunks/node-http-transport-Bz3noIS3.js.map +0 -1
  141. package/dist/esm/chunks/repository-qcX3-LkP.js +0 -2
  142. package/dist/esm/chunks/repository-qcX3-LkP.js.map +0 -1
  143. package/dist/types/chunks/diff-change-B09vxnxy.d.cts +0 -59
  144. package/dist/types/chunks/diff-change-D7xSeCn9.d.ts +0 -59
@@ -1,217 +1,439 @@
1
- import { O as ObjectId, d as FilePath, b as Context, R as RefName } from '../chunks/context-d36639-i.cjs';
2
- import { A as AuthorIdentity, F as FileMode, T as TreeDiff } from '../chunks/diff-change-B09vxnxy.cjs';
3
- import '../chunks/http-transport-DirKfK2S.cjs';
1
+ import { G as GitIndex, I as IndexEntry } from '../chunks/write-tree-B8G6kgTy.cjs';
2
+ export { H as HookInput, c as catFileBatch, a as createCommit, d as diffTrees, g as getRepoRoot, m as mergeBase, r as readBlob, b as readIndex, e as readObject, f as readTree, h as recordRefUpdate, i as resolveRef, j as runHook, s as sparseCheckoutPath, u as updateRef, w as walkCommits, k as walkSubmodules, l as walkTree, n as walkWorkingTree, o as writeObject, p as writeSymbolicRef, q as writeTree } from '../chunks/write-tree-B8G6kgTy.cjs';
3
+ import { d as FilePath, O as ObjectId, b as Context, R as RefName } from '../chunks/context-CMrHCVwK.cjs';
4
+ import { F as FileMode, A as AuthorIdentity, q as ReflogEntry } from '../chunks/reflog-entry-BIf-zt__.cjs';
5
+ export { C as CatFileBatchEntry, a as CatFileBatchOptions, c as CreateCommitInput, D as DiffTreesInput, d as DiffTreesOptions, M as MAX_COMMIT_MESSAGE_BYTES, e as MAX_GITIGNORE_BYTES, f as MAX_GITMODULES_BYTES, g as MAX_HAVES, h as MAX_INDEX_BYTES, i as MAX_PEEL_DEPTH, j as MAX_PUSH_OBJECTS, k as MAX_REFLOG_BYTES, l as MAX_SUBMODULE_DEPTH, m as MAX_SYMBOLIC_REF_DEPTH, n as MAX_WALK_QUEUE_SIZE, o as MAX_WALK_SEEDS, p as MAX_WORKING_TREE_BLOB_BYTES, R as ReadObjectOptions, r as ResolveRefOptions, S as SubmoduleEntry, s as TreeDiff, U as UpdateRefOptions, W as WalkCommitsOptions, u as WalkIgnorePredicate, v as WalkSubmodulesOptions, w as WalkTreeEntry, x as WalkTreeOptions, y as WalkWorkingTreeEntry, z as WalkWorkingTreeOptions } from '../chunks/reflog-entry-BIf-zt__.cjs';
6
+ import { b as HttpTransport } from '../chunks/http-transport-DirKfK2S.cjs';
4
7
 
5
- interface Blob {
6
- readonly type: 'blob';
7
- readonly id: ObjectId;
8
- readonly content: Uint8Array;
9
- }
8
+ /** `true` ⇒ the path is in the sparse set (materialise it). */
9
+ type SparseMatcher = (path: FilePath) => boolean;
10
10
 
11
- interface ExtraHeader {
12
- readonly key: string;
13
- readonly value: string;
11
+ /**
12
+ * Pure helper that diffs a current GitIndex against a target tree's flat
13
+ * entry list and emits an ordered ChangesetEntry list. No FS, no ctx; the
14
+ * impure write side lives in `apply-changeset.ts`.
15
+ *
16
+ * Stage-0 entries only — unmerged stages are invisible to checkout (Phase
17
+ * 13.1 design step 5).
18
+ */
19
+
20
+ interface ChangesetEntry {
21
+ readonly kind: 'add' | 'update' | 'delete' | 'noop';
22
+ readonly path: FilePath;
23
+ readonly mode: FileMode;
24
+ readonly id: ObjectId | undefined;
25
+ readonly previousId: ObjectId | undefined;
26
+ readonly previousMode: FileMode | undefined;
14
27
  }
15
- interface CommitData {
16
- readonly tree: ObjectId;
17
- readonly parents: ReadonlyArray<ObjectId>;
18
- readonly author: AuthorIdentity;
19
- readonly committer: AuthorIdentity;
20
- readonly message: string;
21
- readonly gpgSignature?: string;
22
- readonly extraHeaders: ReadonlyArray<ExtraHeader>;
23
- }
24
- interface Commit {
25
- readonly type: 'commit';
26
- readonly id: ObjectId;
27
- readonly data: CommitData;
28
+ interface ChangesetStats {
29
+ readonly add: number;
30
+ readonly update: number;
31
+ readonly delete: number;
32
+ readonly noop: number;
28
33
  }
29
-
30
- type ObjectType = 'blob' | 'tree' | 'commit' | 'tag';
31
-
32
- interface TagData {
33
- readonly object: ObjectId;
34
- readonly objectType: ObjectType;
35
- readonly tagName: string;
36
- readonly tagger?: AuthorIdentity;
37
- readonly message: string;
38
- readonly gpgSignature?: string;
39
- readonly extraHeaders: ReadonlyArray<ExtraHeader>;
34
+ interface Changeset {
35
+ readonly entries: ReadonlyArray<ChangesetEntry>;
36
+ readonly stats: ChangesetStats;
40
37
  }
41
- interface Tag {
42
- readonly type: 'tag';
38
+ interface TargetEntry {
39
+ readonly path: FilePath;
43
40
  readonly id: ObjectId;
44
- readonly data: TagData;
41
+ readonly mode: FileMode;
45
42
  }
43
+ declare const computeChangeset: (currentIndex: GitIndex, targetTree: ReadonlyArray<TargetEntry>) => Changeset;
46
44
 
47
- interface TreeEntry {
48
- readonly mode: FileMode;
49
- readonly name: string;
50
- readonly id: ObjectId;
45
+ interface ApplyChangesetOpts {
46
+ readonly changeset: Changeset;
47
+ readonly force: boolean;
48
+ readonly workdir: string;
51
49
  }
52
- interface Tree {
53
- readonly type: 'tree';
54
- readonly id: ObjectId;
55
- readonly entries: ReadonlyArray<TreeEntry>;
50
+ interface ApplyChangesetResult {
51
+ readonly writtenEntries: ReadonlyArray<IndexEntry>;
52
+ readonly written: number;
53
+ readonly deleted: number;
56
54
  }
55
+ /**
56
+ * `true` when a working-tree file exists at `absPath` but its blob content
57
+ * hash differs from `expectedId`. An absent file is not dirty. Shared by
58
+ * `applySparseCheckout`'s narrowing pre-scan (design §9).
59
+ */
60
+ declare const isWorkingTreeDirty: (ctx: Context, absPath: string, expectedId: string) => Promise<boolean>;
61
+ declare const applyChangeset: (ctx: Context, opts: ApplyChangesetOpts) => Promise<ApplyChangesetResult>;
57
62
 
58
- type GitObject = Blob | Tree | Commit | Tag;
63
+ /**
64
+ * Project a target tree onto a fresh stage-0 IndexEntry list, preserving
65
+ * stat-cache fields from the prior index where the path's `id` AND `mode`
66
+ * both match (the "stat-cache donor" strategy).
67
+ *
68
+ * Pure with respect to the working tree: this primitive never calls
69
+ * `fs.lstat`, `fs.read`, or any working-tree-side API. It only reads git
70
+ * objects via `walkTree` → `readObject` for nested trees.
71
+ *
72
+ * Used by `reset --mixed` to rebuild the index from a target
73
+ * commit's tree. Will be re-used by `reset --hard` composed
74
+ * with `materializeTree` to also write the working tree.
75
+ *
76
+ * ## Preconditions
77
+ *
78
+ * `currentIndex` MUST be read under the same `acquireIndexLock` that will
79
+ * later commit the result. Reading the index BEFORE the lock is acquired
80
+ * lets a concurrent writer mutate it between the donor-map build and the
81
+ * commit, producing a result that reflects neither the pre-reset nor the
82
+ * post-reset state. See `reset.ts:rebuildIndexFromCommit` for the
83
+ * canonical pattern: acquire → read → build → commit → release-in-finally.
84
+ */
59
85
 
60
- interface IndexEntryFlags {
61
- readonly assumeValid: boolean;
62
- readonly extended: boolean;
63
- readonly stage: 0 | 1 | 2 | 3;
86
+ interface BuildIndexFromTreeOpts {
87
+ readonly targetTree: ObjectId;
88
+ readonly currentIndex: GitIndex;
89
+ /**
90
+ * Sparse-checkout filter. When supplied, an excluded path is rebuilt as a
91
+ * zero-stat skip-worktree entry and an in-pattern path has any stale
92
+ * skip-worktree bit cleared. `undefined` ⇒ sparse inactive — the rebuilt
93
+ * index is byte-identical to the non-sparse behaviour.
94
+ */
95
+ readonly sparse?: SparseMatcher;
64
96
  }
65
- interface IndexEntry {
66
- readonly ctimeSeconds: number;
67
- readonly ctimeNanoseconds: number;
68
- readonly mtimeSeconds: number;
69
- readonly mtimeNanoseconds: number;
70
- readonly dev: number;
71
- readonly ino: number;
72
- readonly mode: FileMode;
73
- readonly uid: number;
74
- readonly gid: number;
75
- readonly fileSize: number;
76
- readonly id: ObjectId;
77
- readonly flags: IndexEntryFlags;
78
- readonly path: FilePath;
97
+ declare const buildIndexFromTree: (ctx: Context, opts: BuildIndexFromTreeOpts) => Promise<ReadonlyArray<IndexEntry>>;
98
+
99
+ interface BuildPackInput {
100
+ readonly oids: ReadonlyArray<ObjectId>;
79
101
  }
80
- interface IndexExtension {
81
- readonly signature: string;
82
- readonly data: Uint8Array;
102
+ interface BuildPackResult {
103
+ readonly bytes: Uint8Array;
104
+ /** Hex SHA of the pack body, also the trailer (last 20 bytes). */
105
+ readonly sha: string;
106
+ readonly objectCount: number;
83
107
  }
84
- interface GitIndex {
85
- readonly version: 2;
86
- readonly entries: ReadonlyArray<IndexEntry>;
87
- readonly extensions: ReadonlyArray<IndexExtension>;
108
+ declare const buildPack: (ctx: Context, input: BuildPackInput) => Promise<BuildPackResult>;
109
+
110
+ /**
111
+ * Subset of `.git/config` that v1 commands consume. Only fields actually used by
112
+ * commands are typed — the parser ignores everything else (lenient, like git itself).
113
+ */
114
+ interface ParsedConfig {
115
+ readonly core?: {
116
+ readonly bare?: boolean;
117
+ readonly excludesFile?: string;
118
+ readonly logAllRefUpdates?: boolean | 'always';
119
+ readonly hooksPath?: string;
120
+ readonly sparseCheckout?: boolean;
121
+ readonly sparseCheckoutCone?: boolean;
122
+ };
123
+ readonly user?: {
124
+ readonly name: string;
125
+ readonly email: string;
126
+ };
127
+ readonly remote?: ReadonlyMap<string, {
128
+ readonly url?: string;
129
+ readonly fetch?: ReadonlyArray<string>;
130
+ /** `remote.<name>.promisor` — true when this is a partial-clone promisor remote. */
131
+ readonly promisor?: boolean;
132
+ /** `remote.<name>.partialclonefilter` — the canonical filter spec applied at clone. */
133
+ readonly partialCloneFilter?: string;
134
+ }>;
135
+ readonly branch?: ReadonlyMap<string, {
136
+ readonly remote?: string;
137
+ readonly merge?: string;
138
+ }>;
139
+ /** `[extensions]` — `partialClone` names the promisor remote of a partial clone. */
140
+ readonly extensions?: {
141
+ readonly partialClone?: string;
142
+ };
88
143
  }
144
+ /**
145
+ * Read and cache `${gitDir}/config`. Missing → empty config (not an error).
146
+ *
147
+ * The cache is keyed on `Context` identity; a new context (e.g., after a write
148
+ * that re-creates the repo) gets a fresh read. Concurrent calls share the same
149
+ * in-flight promise (per-context single-flight).
150
+ */
151
+ declare const readConfig: (ctx: Context) => Promise<ParsedConfig>;
152
+ /**
153
+ * Drop the cached `readConfig` entry for a single `Context`. The production
154
+ * invalidator: a config write (`updateCoreConfig`) calls this so a subsequent
155
+ * `readConfig` on the same context re-reads the file instead of serving the
156
+ * stale parse.
157
+ */
158
+ declare const invalidateConfigCache: (ctx: Context) => void;
89
159
 
90
- interface RenameDetectOptions {
91
- readonly limit?: number;
92
- readonly maxSameIdDeletes?: number;
160
+ interface EnumeratePushObjectsInput {
161
+ /**
162
+ * Object ids the caller wants on the remote. Each MUST resolve to a
163
+ * commit or an annotated tag (tags are unwrapped to commits before the
164
+ * commit walk).
165
+ */
166
+ readonly wants: ReadonlyArray<ObjectId>;
167
+ /** Object ids the remote already has (server's advertised ref tips). */
168
+ readonly haves: ReadonlyArray<ObjectId>;
169
+ /** Hard cap on objects emitted. Defaults to MAX_PUSH_OBJECTS. */
170
+ readonly maxObjects?: number;
93
171
  }
172
+ declare function enumeratePushObjects(ctx: Context, input: EnumeratePushObjectsInput): AsyncIterable<ObjectId>;
94
173
 
95
174
  /**
96
- * Phase 7 primitive option shapes, walker value types, and shared constants.
97
- * Defined in one location to avoid circular imports between primitive modules.
175
+ * Enumerate every current ref: `HEAD`, loose refs under `.git/refs/**`, and
176
+ * packed-refs entries deduplicated. Used by `reflog expire` to seed the
177
+ * reachable-commit walk; not on any hot path.
98
178
  */
99
179
 
100
- /** Max symbolic-ref dereferences resolveRef will follow. */
101
- declare const MAX_SYMBOLIC_REF_DEPTH = 5;
102
- /** Max tag-peel hops resolveRef / readTree will follow when peeling. */
103
- declare const MAX_PEEL_DEPTH = 5;
104
- /** Max seeds walkCommits.from can contain. */
105
- declare const MAX_WALK_SEEDS = 1024;
106
- /** Hard cap on walkCommits' pending queue size to prevent unbounded heap growth. */
107
- declare const MAX_WALK_QUEUE_SIZE: number;
108
- /** Max .git/index file size readIndex will accept. */
109
- declare const MAX_INDEX_BYTES: number;
110
- /** Max commit message byte length createCommit will accept. */
111
- declare const MAX_COMMIT_MESSAGE_BYTES: number;
112
- interface ReadObjectOptions {
113
- readonly verifyHash?: boolean;
114
- }
115
- interface ResolveRefOptions {
116
- readonly peel?: boolean;
117
- readonly maxSymbolicDepth?: number;
118
- readonly maxPeelDepth?: number;
119
- }
120
- interface UpdateRefOptions {
121
- readonly expected?: ObjectId | 'absent';
122
- readonly delete?: boolean;
123
- }
124
- interface WalkCommitsOptions {
125
- readonly from: ReadonlyArray<ObjectId>;
126
- readonly until?: ReadonlyArray<ObjectId>;
127
- readonly order?: 'topo' | 'first-parent';
128
- readonly ignoreMissing?: boolean;
129
- readonly verifyHash?: boolean;
130
- }
131
- interface WalkTreeEntry {
132
- readonly path: FilePath;
133
- readonly id: ObjectId;
134
- readonly mode: FileMode;
135
- }
136
- interface WalkTreeOptions {
137
- readonly recursive?: boolean;
138
- readonly maxDepth?: number;
139
- readonly maxEntries?: number;
140
- }
141
- interface CreateCommitInput {
142
- readonly tree: ObjectId;
143
- readonly parents: ReadonlyArray<ObjectId>;
144
- readonly author: AuthorIdentity;
145
- readonly committer: AuthorIdentity;
146
- readonly message: string;
147
- readonly gpgSignature?: string;
148
- readonly extraHeaders?: ReadonlyArray<ExtraHeader>;
180
+ declare function enumerateRefs(ctx: Context): Promise<ReadonlyArray<RefName>>;
181
+
182
+ interface FetchPackInput {
183
+ /** Advertised refs the caller wants. MUST be non-empty (server-side requirement). */
184
+ readonly wants: ReadonlyArray<ObjectId>;
185
+ /** Objects the caller already has (negotiation). Empty for clone, populated for fetch. */
186
+ readonly haves: ReadonlyArray<ObjectId>;
187
+ /** Negotiated capabilities (intersection of advertised + supported). */
188
+ readonly capabilities: ReadonlyArray<string>;
189
+ /** Base remote URL (the same URL passed to clone). */
190
+ readonly url: string;
191
+ /** Progress op label — clone uses 'clone:write-objects', fetch uses 'fetch:write-objects'. */
192
+ readonly progressOp: string;
193
+ /**
194
+ * Shallow clone depth. When set, sends `deepen N` and consumes the
195
+ * accompanying `shallow <oid>` / `unshallow <oid>` response block.
196
+ *
197
+ */
198
+ readonly depth?: number;
199
+ /**
200
+ * Partial-clone object filter — a canonical filter spec. When set, a
201
+ * `filter` line is emitted; the caller must have negotiated the `filter`
202
+ * capability.
203
+ */
204
+ readonly filter?: string;
205
+ /**
206
+ * When true, write an empty `pack-<sha>.promisor` sentinel beside the pack
207
+ * so the objects it references but omits are treated as promised.
208
+ */
209
+ readonly promisor?: boolean;
149
210
  }
150
- type DiffTreesInput = Tree | ObjectId | undefined;
151
- interface DiffTreesOptions {
152
- readonly detectRenames?: boolean;
153
- readonly renameOptions?: RenameDetectOptions;
211
+ interface FetchPackResult {
212
+ readonly packPath: string;
213
+ readonly idxPath: string;
214
+ readonly objectCount: number;
215
+ /** Hex-encoded SHA of the pack trailer; also the on-disk filename stem. */
216
+ readonly packSha: string;
217
+ /** Commits the server advertised as new shallow boundaries (empty when depth is unset). */
218
+ readonly shallow: ReadonlyArray<ObjectId>;
219
+ /** Commits the server advertised as no-longer-shallow (empty when depth is unset). */
220
+ readonly unshallow: ReadonlyArray<ObjectId>;
154
221
  }
155
-
156
- declare function createCommit(ctx: Context, input: CreateCommitInput): Promise<ObjectId>;
157
-
158
- declare function diffTrees(ctx: Context, a: DiffTreesInput, b: DiffTreesInput, options?: DiffTreesOptions): Promise<TreeDiff>;
222
+ declare const fetchPack: (ctx: Context, transport: HttpTransport, input: FetchPackInput) => Promise<FetchPackResult>;
159
223
 
160
224
  /**
161
- * Compute a merge base the first commit reachable from BOTH `a` and `b`.
225
+ * Compose `walkTree computeChangeset applyChangeset` to update the
226
+ * working tree to a target tree's contents.
227
+ *
228
+ * - Branch switch mode: `paths === undefined` — diff the entire current
229
+ * index against the entire target tree.
230
+ * - Path-restore mode: `paths !== undefined` — restrict both sides of
231
+ * the diff to those paths.
162
232
  *
163
- * Algorithm: bidirectional BFS with two visited sets. After each layer
164
- * advance, check the intersection. When non-empty, return the
165
- * lexicographically smallest oid (deterministic tie-breaker).
233
+ * Returns the new IndexEntry list for the caller to commit, plus
234
+ * written/deleted counts. The primitive does NOT commit the index — the
235
+ * caller decides.
166
236
  *
167
- * Returns `undefined` for unrelated histories. Documented limitation: cherry-picks
168
- * and criss-cross merges may yield non-optimal bases — `recursive`-strategy
169
- * multi-base resolution is v2.
237
+ * ## Stat-source contract for `newIndexEntries` (load-bearing for)
238
+ *
239
+ * - **Paths that were written/added** (`add` or `update` changeset entries):
240
+ * the IndexEntry carries **post-write `lstat`-derived stat fields**
241
+ * (ctime/mtime/dev/ino/uid/gid/fileSize). These reflect the file we just
242
+ * wrote, so the next `status` runs the fast `isStatClean` path.
243
+ * - **Paths whose changeset classification was `noop`** (skipped — index
244
+ * already matched target by `id + mode`): the IndexEntry is the caller's
245
+ * `currentIndex` entry verbatim. Donor stats survive across the call.
246
+ * - `reset --hard` therefore MUST set `forceRewriteAll: true` so every noop
247
+ * upgrades to update and the post-write stats land in the output. Without
248
+ * that, a locally-modified working-tree file that the index still records
249
+ * as clean would survive the reset, AND the donor stats would be stale
250
+ * relative to the actual disk state.
170
251
  */
171
- declare const mergeBase: (ctx: Context, a: ObjectId, b: ObjectId) => Promise<ObjectId | undefined>;
252
+
253
+ interface MaterializeTreeOpts {
254
+ readonly targetTree: ObjectId;
255
+ readonly currentIndex: GitIndex;
256
+ readonly force?: boolean;
257
+ readonly paths?: ReadonlySet<FilePath>;
258
+ /**
259
+ * When true, every target-tree path is written to the working tree
260
+ * unconditionally — even paths the index→target diff classified as `noop`
261
+ * (same `id` AND `mode`). Required by `reset --hard`, where the working
262
+ * tree may diverge from the index (uncommitted local modifications); the
263
+ * standard index→target diff cannot see that drift, so noops would skip
264
+ * paths the caller wants overwritten. Default `false` keeps the Phase
265
+ * 13.1 checkout behaviour: clean files are never spuriously rewritten.
266
+ */
267
+ readonly forceRewriteAll?: boolean;
268
+ /**
269
+ * Branch-switch sparse-checkout filter. Honoured ONLY when `paths` is
270
+ * undefined. A target-tree path the matcher rejects is NOT written to the
271
+ * working tree; its `newIndexEntries` record carries `skipWorktree: true`
272
+ * (the index keeps every path — git-faithful). A path the matcher accepts
273
+ * that the *current* index records as skip-worktree (absent on disk) is
274
+ * materialised even when its `id` matches, because the current index is
275
+ * filtered to drop skip-worktree entries before the diff — such a path
276
+ * classifies as `add`, never `noop`.
277
+ */
278
+ readonly sparse?: SparseMatcher;
279
+ }
280
+ interface MaterializeTreeResult {
281
+ readonly newIndexEntries: ReadonlyArray<IndexEntry>;
282
+ readonly written: number;
283
+ readonly deleted: number;
284
+ }
285
+ declare const materializeTree: (ctx: Context, opts: MaterializeTreeOpts) => Promise<MaterializeTreeResult>;
172
286
 
173
287
  /**
174
- * Pure path helpers composing `ctx.layout.gitDir` with known sub-paths.
175
- * No I/O. No port access. Primitive step 3.
288
+ * Hard cap on the `.git/info/sparse-checkout` file 1 MiB, mirroring
289
+ * `MAX_GITIGNORE_BYTES`. A plain literal (not `1024 * 1024`) so a boundary test
290
+ * keyed on the constant cannot drift with an arithmetic mutation of it.
176
291
  */
177
-
292
+ declare const MAX_SPARSE_PATTERN_FILE_BYTES = 1048576;
178
293
  /**
179
- * Repository working-tree root. Returns the workDir from the current context;
180
- * facade-tier code (Phase 10) is responsible for discovery / realpath pinning
181
- * at construction time. Primitives consume the already-resolved path.
294
+ * Read `.git/info/sparse-checkout` as UTF-8 text. An absent file yields
295
+ * `undefined`; a file whose byte length exceeds
296
+ * `MAX_SPARSE_PATTERN_FILE_BYTES` throws `SPARSE_PATTERN_FILE_TOO_LARGE`
297
+ * (checked before decode so an over-cap file never reaches the decoder).
182
298
  */
183
- declare const getRepoRoot: (ctx: Context) => FilePath;
184
-
185
- declare function readBlob(ctx: Context, id: ObjectId, options?: ReadObjectOptions): Promise<Blob>;
186
-
187
- declare function readIndex(ctx: Context): Promise<GitIndex>;
188
-
189
- declare function readObject(ctx: Context, id: ObjectId, options?: ReadObjectOptions): Promise<GitObject>;
299
+ declare const readSparsePatternText: (ctx: Context) => Promise<string | undefined>;
300
+ /**
301
+ * Build the sparse matcher for the current repository. Returns `undefined`
302
+ * when `core.sparseCheckout` is falsy/absent — sparse is inactive and callers
303
+ * behave exactly as a non-sparse repo. When active, the matcher is parsed in
304
+ * the mode `core.sparseCheckoutCone` dictates; a cone file that degrades to
305
+ * non-cone matching logs one warning.
306
+ */
307
+ declare const loadSparseMatcher: (ctx: Context) => Promise<SparseMatcher | undefined>;
190
308
 
191
- declare function readTree(ctx: Context, ref: RefName | ObjectId): Promise<Tree>;
309
+ /**
310
+ * Committer identity for reflog entries: config `user.*` plus a fresh
311
+ * timestamp, or a portable fallback when `user.*` is unset. Never throws —
312
+ * reflog logging must not abort a ref update.
313
+ */
314
+ declare function resolveReflogIdentity(ctx: Context): Promise<AuthorIdentity>;
192
315
 
193
- declare function resolveRef(ctx: Context, name: RefName | 'HEAD', options?: ResolveRefOptions): Promise<ObjectId>;
316
+ /**
317
+ * Thin I/O layer over `.git/logs/<ref>` reflog files. Append is the hot path;
318
+ * whole-file rewrite and delete back the `reflog` command's expire / delete.
319
+ */
194
320
 
195
- declare function updateRef(ctx: Context, name: RefName, newId: ObjectId, options?: UpdateRefOptions): Promise<void>;
321
+ /** Append one entry to `ref`'s reflog, creating the file and parents as needed. */
322
+ declare function appendReflog(ctx: Context, ref: RefName, entry: ReflogEntry): Promise<void>;
323
+ /** Read `ref`'s reflog, oldest-first. Returns `[]` when the file is absent. */
324
+ declare function readReflog(ctx: Context, ref: RefName): Promise<ReadonlyArray<ReflogEntry>>;
325
+ /** Whether `ref` has a reflog file at all. */
326
+ declare function reflogExists(ctx: Context, ref: RefName): Promise<boolean>;
327
+ /** Replace `ref`'s reflog with exactly `entries`. Used by expire / delete. */
328
+ declare function writeReflog(ctx: Context, ref: RefName, entries: ReadonlyArray<ReflogEntry>): Promise<void>;
329
+ /** Remove `ref`'s reflog file. A no-op when the file is already absent. */
330
+ declare function deleteReflog(ctx: Context, ref: RefName): Promise<void>;
331
+ /** Every reflog under `.git/logs/`, each as the `RefName` it logs. */
332
+ declare function listReflogs(ctx: Context): Promise<ReadonlyArray<RefName>>;
196
333
 
197
- declare function walkCommits(ctx: Context, options: WalkCommitsOptions): AsyncIterable<Commit>;
334
+ /**
335
+ * Read `.git/shallow`. Returns an empty set when the file does not exist or
336
+ * contains no oids. Malformed lines are tolerated (skipped) — canonical
337
+ * git behaves the same; a corrupted shallow file should not block a fetch.
338
+ */
339
+ declare const readShallow: (ctx: Context) => Promise<ReadonlySet<ObjectId>>;
340
+ interface ShallowUpdate {
341
+ readonly shallow: ReadonlyArray<ObjectId>;
342
+ readonly unshallow: ReadonlyArray<ObjectId>;
343
+ }
344
+ /**
345
+ * Apply a set of shallow / unshallow updates to `.git/shallow`. Writes
346
+ * atomically via lock-rename; deletes the file when the resulting set is
347
+ * empty.
348
+ */
349
+ declare const updateShallow: (ctx: Context, updates: ShallowUpdate) => Promise<void>;
198
350
 
199
- declare function walkTree(ctx: Context, treeIdOrObject: ObjectId | Tree, options?: WalkTreeOptions): AsyncIterable<WalkTreeEntry>;
351
+ /**
352
+ * Synthesise a nested `Tree` object from a flat `GitIndex` and return the
353
+ * root tree's `ObjectId`. Sub-trees are written to the object store as a
354
+ * side-effect of the recursive descent — only stage-0 entries contribute.
355
+ *
356
+ * Used by `checkout({ paths, source: 'index' })` to restore
357
+ * the working tree from staged content even when the index has diverged
358
+ * from HEAD via `add` / `rm`. The previous placeholder fell back to
359
+ * HEAD's tree, which silently lost the divergence.
360
+ *
361
+ * The synthesis is the inverse of `buildIndexFromTree`:
362
+ * "tree → index" and "index → tree" form a round-trip identity for any
363
+ * stage-0-only index.
364
+ *
365
+ * Pure with respect to the working tree — never calls `fs.lstat`,
366
+ * `fs.read`, or any working-tree-side API. Only writes git objects via
367
+ * the existing `writeTree` primitive.
368
+ *
369
+ * ## Safety
370
+ *
371
+ * - **Path validation**:.7 hoisted segment-level validation into
372
+ * `parseIndex` (`src/domain/git-index/path-validator.ts`). Every
373
+ * `IndexEntry` reaching this primitive THROUGH THE CANONICAL PARSER
374
+ * carries a `FilePath` value already free of `..`, `.`, empty segments,
375
+ * and leading-slash absolute paths. However, the primitive is also
376
+ * reachable from callers that construct `IndexEntry` records outside
377
+ * the parser (test fixtures, in-memory adapters, future synthesisers).
378
+ * Defence-in-depth: every entry is re-validated here so the primitive
379
+ * stays safe even when the parser-trusted path is bypassed.
380
+ * - **Depth cap**: synthesis bounds recursion at `MAX_TREE_DEPTH` (4096,
381
+ * matching git's canonical limit). The cap is enforced at the input
382
+ * boundary by counting slashes — by the time recursion would catch a
383
+ * pathological depth, the JS engine has already exhausted its call
384
+ * stack. Path validation does NOT subsume this check: a path can be
385
+ * safe segment-by-segment (no `..`/`.`/empty) and still be 10 000
386
+ * levels deep.
387
+ */
200
388
 
201
- declare function writeObject(ctx: Context, object: GitObject): Promise<ObjectId>;
389
+ /**
390
+ * Public entry: pass the `entries` array directly (typically
391
+ * `index.entries`, but callers holding a filtered list may supply it
392
+ * without wrapping in a fake `GitIndex`).
393
+ */
394
+ declare const synthesizeTreeFromIndex: (ctx: Context, entries: ReadonlyArray<IndexEntry>) => Promise<ObjectId>;
202
395
 
203
396
  /**
204
- * Write a symbolic ref atomically. Used for HEAD updates that point at a
205
- * branch, branch renames affecting the current HEAD, and `clone`/`init`
206
- * to set the initial HEAD.
397
+ * Set `key` under `[section]` / `[section "subsection"]`, preserving every
398
+ * other byte verbatim.
207
399
  *
208
- * Single-level only in v1: target MUST be a direct ref name (no chained
209
- * symrefs). Validation runs through `validateRefName` for both `name` and
210
- * `target` invalid inputs throw INVALID_REF before any I/O.
400
+ * - existing section with that key its value is replaced;
401
+ * - existing section without that key a `\t<key> = <value>` line is
402
+ * inserted right after the header;
403
+ * - no such section ⇒ `[section]\n\t<key> = <value>\n` is appended.
404
+ */
405
+ declare const setConfigEntry: (text: string, section: string, subsection: string | undefined, key: string, value: string) => string;
406
+ /** `setConfigEntry` bound to the `[core]` section — kept for legacy callers. */
407
+ declare const setCoreConfigEntry: (text: string, key: string, value: string) => string;
408
+ /** One `key = value` write under `[section]` / `[section "subsection"]`. */
409
+ interface ConfigEntry {
410
+ readonly section: string;
411
+ readonly subsection?: string;
412
+ readonly key: string;
413
+ readonly value: string;
414
+ }
415
+ /**
416
+ * Read `${gitDir}/config` (a missing file is treated as `''`), fold
417
+ * `setConfigEntry` over `entries`, write the result, and invalidate the
418
+ * per-`Context` `readConfig` cache so a later read sees the new values.
211
419
  */
212
- declare const writeSymbolicRef: (ctx: Context, name: RefName, target: RefName) => Promise<void>;
420
+ declare const updateConfigEntries: (ctx: Context, entries: ReadonlyArray<ConfigEntry>) => Promise<void>;
421
+ /** Fold a batch of `[core]` `key = value` writes via `updateConfigEntries`. */
422
+ declare const updateCoreConfig: (ctx: Context, entries: Record<string, string>) => Promise<void>;
213
423
 
214
- declare function writeTree(ctx: Context, entries: ReadonlyArray<TreeEntry>): Promise<ObjectId>;
424
+ /**
425
+ * Write the `.git/info/sparse-checkout` pattern file. The command tier
426
+ * computes the text (via `serializeCone` or raw non-cone lines); this
427
+ * primitive only persists it (design §7.3).
428
+ */
429
+
430
+ /**
431
+ * Persist `text` to `.git/info/sparse-checkout`. The `.git/info` directory is
432
+ * created defensively first — `writeUtf8` creates parents on every adapter,
433
+ * but an explicit `mkdir` keeps the contract clear and survives adapters that
434
+ * tighten that guarantee.
435
+ */
436
+ declare const writeSparsePatternText: (ctx: Context, text: string) => Promise<void>;
215
437
 
216
- export { MAX_COMMIT_MESSAGE_BYTES, MAX_INDEX_BYTES, MAX_PEEL_DEPTH, MAX_SYMBOLIC_REF_DEPTH, MAX_WALK_QUEUE_SIZE, MAX_WALK_SEEDS, TreeDiff, createCommit, diffTrees, getRepoRoot, mergeBase, readBlob, readIndex, readObject, readTree, resolveRef, updateRef, walkCommits, walkTree, writeObject, writeSymbolicRef, writeTree };
217
- export type { CreateCommitInput, DiffTreesInput, DiffTreesOptions, ReadObjectOptions, ResolveRefOptions, UpdateRefOptions, WalkCommitsOptions, WalkTreeEntry, WalkTreeOptions };
438
+ export { MAX_SPARSE_PATTERN_FILE_BYTES, appendReflog, applyChangeset, buildIndexFromTree, buildPack, computeChangeset, deleteReflog, enumeratePushObjects, enumerateRefs, fetchPack, invalidateConfigCache, isWorkingTreeDirty, listReflogs, loadSparseMatcher, materializeTree, readConfig, readReflog, readShallow, readSparsePatternText, reflogExists, resolveReflogIdentity, setConfigEntry, setCoreConfigEntry, synthesizeTreeFromIndex, updateConfigEntries, updateCoreConfig, updateShallow, writeReflog, writeSparsePatternText };
439
+ export type { ApplyChangesetOpts, ApplyChangesetResult, BuildIndexFromTreeOpts, BuildPackInput, BuildPackResult, Changeset, ChangesetEntry, ChangesetStats, ConfigEntry, EnumeratePushObjectsInput, FetchPackInput, FetchPackResult, MaterializeTreeOpts, MaterializeTreeResult, ParsedConfig };