gitx.do 0.0.2 → 0.0.3

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 (237) hide show
  1. package/dist/cli/commands/blame.d.ts +259 -0
  2. package/dist/cli/commands/blame.d.ts.map +1 -0
  3. package/dist/cli/commands/blame.js +609 -0
  4. package/dist/cli/commands/blame.js.map +1 -0
  5. package/dist/cli/commands/branch.d.ts +249 -0
  6. package/dist/cli/commands/branch.d.ts.map +1 -0
  7. package/dist/cli/commands/branch.js +693 -0
  8. package/dist/cli/commands/branch.js.map +1 -0
  9. package/dist/cli/commands/commit.d.ts +182 -0
  10. package/dist/cli/commands/commit.d.ts.map +1 -0
  11. package/dist/cli/commands/commit.js +437 -0
  12. package/dist/cli/commands/commit.js.map +1 -0
  13. package/dist/cli/commands/diff.d.ts +464 -0
  14. package/dist/cli/commands/diff.d.ts.map +1 -0
  15. package/dist/cli/commands/diff.js +958 -0
  16. package/dist/cli/commands/diff.js.map +1 -0
  17. package/dist/cli/commands/log.d.ts +239 -0
  18. package/dist/cli/commands/log.d.ts.map +1 -0
  19. package/dist/cli/commands/log.js +535 -0
  20. package/dist/cli/commands/log.js.map +1 -0
  21. package/dist/cli/commands/review.d.ts +457 -0
  22. package/dist/cli/commands/review.d.ts.map +1 -0
  23. package/dist/cli/commands/review.js +533 -0
  24. package/dist/cli/commands/review.js.map +1 -0
  25. package/dist/cli/commands/status.d.ts +269 -0
  26. package/dist/cli/commands/status.d.ts.map +1 -0
  27. package/dist/cli/commands/status.js +493 -0
  28. package/dist/cli/commands/status.js.map +1 -0
  29. package/dist/cli/commands/web.d.ts +199 -0
  30. package/dist/cli/commands/web.d.ts.map +1 -0
  31. package/dist/cli/commands/web.js +696 -0
  32. package/dist/cli/commands/web.js.map +1 -0
  33. package/dist/cli/fs-adapter.d.ts +656 -0
  34. package/dist/cli/fs-adapter.d.ts.map +1 -0
  35. package/dist/cli/fs-adapter.js +1179 -0
  36. package/dist/cli/fs-adapter.js.map +1 -0
  37. package/dist/cli/index.d.ts +387 -0
  38. package/dist/cli/index.d.ts.map +1 -0
  39. package/dist/cli/index.js +523 -0
  40. package/dist/cli/index.js.map +1 -0
  41. package/dist/cli/ui/components/DiffView.d.ts +7 -0
  42. package/dist/cli/ui/components/DiffView.d.ts.map +1 -0
  43. package/dist/cli/ui/components/DiffView.js +11 -0
  44. package/dist/cli/ui/components/DiffView.js.map +1 -0
  45. package/dist/cli/ui/components/ErrorDisplay.d.ts +6 -0
  46. package/dist/cli/ui/components/ErrorDisplay.d.ts.map +1 -0
  47. package/dist/cli/ui/components/ErrorDisplay.js +11 -0
  48. package/dist/cli/ui/components/ErrorDisplay.js.map +1 -0
  49. package/dist/cli/ui/components/FuzzySearch.d.ts +9 -0
  50. package/dist/cli/ui/components/FuzzySearch.d.ts.map +1 -0
  51. package/dist/cli/ui/components/FuzzySearch.js +12 -0
  52. package/dist/cli/ui/components/FuzzySearch.js.map +1 -0
  53. package/dist/cli/ui/components/LoadingSpinner.d.ts +6 -0
  54. package/dist/cli/ui/components/LoadingSpinner.d.ts.map +1 -0
  55. package/dist/cli/ui/components/LoadingSpinner.js +10 -0
  56. package/dist/cli/ui/components/LoadingSpinner.js.map +1 -0
  57. package/dist/cli/ui/components/NavigationList.d.ts +9 -0
  58. package/dist/cli/ui/components/NavigationList.d.ts.map +1 -0
  59. package/dist/cli/ui/components/NavigationList.js +11 -0
  60. package/dist/cli/ui/components/NavigationList.js.map +1 -0
  61. package/dist/cli/ui/components/ScrollableContent.d.ts +8 -0
  62. package/dist/cli/ui/components/ScrollableContent.d.ts.map +1 -0
  63. package/dist/cli/ui/components/ScrollableContent.js +11 -0
  64. package/dist/cli/ui/components/ScrollableContent.js.map +1 -0
  65. package/dist/cli/ui/components/index.d.ts +7 -0
  66. package/dist/cli/ui/components/index.d.ts.map +1 -0
  67. package/dist/cli/ui/components/index.js +9 -0
  68. package/dist/cli/ui/components/index.js.map +1 -0
  69. package/dist/cli/ui/terminal-ui.d.ts +52 -0
  70. package/dist/cli/ui/terminal-ui.d.ts.map +1 -0
  71. package/dist/cli/ui/terminal-ui.js +121 -0
  72. package/dist/cli/ui/terminal-ui.js.map +1 -0
  73. package/dist/durable-object/object-store.d.ts +401 -23
  74. package/dist/durable-object/object-store.d.ts.map +1 -1
  75. package/dist/durable-object/object-store.js +414 -25
  76. package/dist/durable-object/object-store.js.map +1 -1
  77. package/dist/durable-object/schema.d.ts +188 -0
  78. package/dist/durable-object/schema.d.ts.map +1 -1
  79. package/dist/durable-object/schema.js +160 -0
  80. package/dist/durable-object/schema.js.map +1 -1
  81. package/dist/durable-object/wal.d.ts +336 -31
  82. package/dist/durable-object/wal.d.ts.map +1 -1
  83. package/dist/durable-object/wal.js +272 -27
  84. package/dist/durable-object/wal.js.map +1 -1
  85. package/dist/index.d.ts +379 -3
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +379 -7
  88. package/dist/index.js.map +1 -1
  89. package/dist/mcp/adapter.d.ts +579 -38
  90. package/dist/mcp/adapter.d.ts.map +1 -1
  91. package/dist/mcp/adapter.js +426 -33
  92. package/dist/mcp/adapter.js.map +1 -1
  93. package/dist/mcp/sandbox.d.ts +532 -29
  94. package/dist/mcp/sandbox.d.ts.map +1 -1
  95. package/dist/mcp/sandbox.js +389 -22
  96. package/dist/mcp/sandbox.js.map +1 -1
  97. package/dist/mcp/sdk-adapter.d.ts +478 -56
  98. package/dist/mcp/sdk-adapter.d.ts.map +1 -1
  99. package/dist/mcp/sdk-adapter.js +346 -44
  100. package/dist/mcp/sdk-adapter.js.map +1 -1
  101. package/dist/mcp/tools.d.ts +445 -30
  102. package/dist/mcp/tools.d.ts.map +1 -1
  103. package/dist/mcp/tools.js +363 -33
  104. package/dist/mcp/tools.js.map +1 -1
  105. package/dist/ops/blame.d.ts +424 -21
  106. package/dist/ops/blame.d.ts.map +1 -1
  107. package/dist/ops/blame.js +303 -20
  108. package/dist/ops/blame.js.map +1 -1
  109. package/dist/ops/branch.d.ts +583 -32
  110. package/dist/ops/branch.d.ts.map +1 -1
  111. package/dist/ops/branch.js +365 -23
  112. package/dist/ops/branch.js.map +1 -1
  113. package/dist/ops/commit-traversal.d.ts +164 -24
  114. package/dist/ops/commit-traversal.d.ts.map +1 -1
  115. package/dist/ops/commit-traversal.js +68 -2
  116. package/dist/ops/commit-traversal.js.map +1 -1
  117. package/dist/ops/commit.d.ts +387 -53
  118. package/dist/ops/commit.d.ts.map +1 -1
  119. package/dist/ops/commit.js +249 -29
  120. package/dist/ops/commit.js.map +1 -1
  121. package/dist/ops/merge-base.d.ts +195 -21
  122. package/dist/ops/merge-base.d.ts.map +1 -1
  123. package/dist/ops/merge-base.js +122 -12
  124. package/dist/ops/merge-base.js.map +1 -1
  125. package/dist/ops/merge.d.ts +600 -130
  126. package/dist/ops/merge.d.ts.map +1 -1
  127. package/dist/ops/merge.js +408 -60
  128. package/dist/ops/merge.js.map +1 -1
  129. package/dist/ops/tag.d.ts +67 -2
  130. package/dist/ops/tag.d.ts.map +1 -1
  131. package/dist/ops/tag.js +42 -1
  132. package/dist/ops/tag.js.map +1 -1
  133. package/dist/ops/tree-builder.d.ts +102 -6
  134. package/dist/ops/tree-builder.d.ts.map +1 -1
  135. package/dist/ops/tree-builder.js +30 -5
  136. package/dist/ops/tree-builder.js.map +1 -1
  137. package/dist/ops/tree-diff.d.ts +50 -2
  138. package/dist/ops/tree-diff.d.ts.map +1 -1
  139. package/dist/ops/tree-diff.js +50 -2
  140. package/dist/ops/tree-diff.js.map +1 -1
  141. package/dist/pack/delta.d.ts +211 -39
  142. package/dist/pack/delta.d.ts.map +1 -1
  143. package/dist/pack/delta.js +232 -46
  144. package/dist/pack/delta.js.map +1 -1
  145. package/dist/pack/format.d.ts +390 -28
  146. package/dist/pack/format.d.ts.map +1 -1
  147. package/dist/pack/format.js +344 -33
  148. package/dist/pack/format.js.map +1 -1
  149. package/dist/pack/full-generation.d.ts +313 -28
  150. package/dist/pack/full-generation.d.ts.map +1 -1
  151. package/dist/pack/full-generation.js +238 -19
  152. package/dist/pack/full-generation.js.map +1 -1
  153. package/dist/pack/generation.d.ts +346 -23
  154. package/dist/pack/generation.d.ts.map +1 -1
  155. package/dist/pack/generation.js +269 -21
  156. package/dist/pack/generation.js.map +1 -1
  157. package/dist/pack/index.d.ts +407 -86
  158. package/dist/pack/index.d.ts.map +1 -1
  159. package/dist/pack/index.js +351 -70
  160. package/dist/pack/index.js.map +1 -1
  161. package/dist/refs/branch.d.ts +517 -71
  162. package/dist/refs/branch.d.ts.map +1 -1
  163. package/dist/refs/branch.js +410 -26
  164. package/dist/refs/branch.js.map +1 -1
  165. package/dist/refs/storage.d.ts +610 -57
  166. package/dist/refs/storage.d.ts.map +1 -1
  167. package/dist/refs/storage.js +481 -29
  168. package/dist/refs/storage.js.map +1 -1
  169. package/dist/refs/tag.d.ts +677 -67
  170. package/dist/refs/tag.d.ts.map +1 -1
  171. package/dist/refs/tag.js +497 -30
  172. package/dist/refs/tag.js.map +1 -1
  173. package/dist/storage/lru-cache.d.ts +556 -53
  174. package/dist/storage/lru-cache.d.ts.map +1 -1
  175. package/dist/storage/lru-cache.js +439 -36
  176. package/dist/storage/lru-cache.js.map +1 -1
  177. package/dist/storage/object-index.d.ts +483 -38
  178. package/dist/storage/object-index.d.ts.map +1 -1
  179. package/dist/storage/object-index.js +388 -22
  180. package/dist/storage/object-index.js.map +1 -1
  181. package/dist/storage/r2-pack.d.ts +957 -94
  182. package/dist/storage/r2-pack.d.ts.map +1 -1
  183. package/dist/storage/r2-pack.js +756 -48
  184. package/dist/storage/r2-pack.js.map +1 -1
  185. package/dist/tiered/cdc-pipeline.d.ts +1610 -38
  186. package/dist/tiered/cdc-pipeline.d.ts.map +1 -1
  187. package/dist/tiered/cdc-pipeline.js +1131 -22
  188. package/dist/tiered/cdc-pipeline.js.map +1 -1
  189. package/dist/tiered/migration.d.ts +903 -41
  190. package/dist/tiered/migration.d.ts.map +1 -1
  191. package/dist/tiered/migration.js +646 -24
  192. package/dist/tiered/migration.js.map +1 -1
  193. package/dist/tiered/parquet-writer.d.ts +944 -47
  194. package/dist/tiered/parquet-writer.d.ts.map +1 -1
  195. package/dist/tiered/parquet-writer.js +667 -39
  196. package/dist/tiered/parquet-writer.js.map +1 -1
  197. package/dist/tiered/read-path.d.ts +728 -34
  198. package/dist/tiered/read-path.d.ts.map +1 -1
  199. package/dist/tiered/read-path.js +310 -27
  200. package/dist/tiered/read-path.js.map +1 -1
  201. package/dist/types/objects.d.ts +457 -0
  202. package/dist/types/objects.d.ts.map +1 -1
  203. package/dist/types/objects.js +305 -4
  204. package/dist/types/objects.js.map +1 -1
  205. package/dist/types/storage.d.ts +407 -35
  206. package/dist/types/storage.d.ts.map +1 -1
  207. package/dist/types/storage.js +27 -3
  208. package/dist/types/storage.js.map +1 -1
  209. package/dist/utils/hash.d.ts +133 -12
  210. package/dist/utils/hash.d.ts.map +1 -1
  211. package/dist/utils/hash.js +133 -12
  212. package/dist/utils/hash.js.map +1 -1
  213. package/dist/utils/sha1.d.ts +102 -9
  214. package/dist/utils/sha1.d.ts.map +1 -1
  215. package/dist/utils/sha1.js +114 -11
  216. package/dist/utils/sha1.js.map +1 -1
  217. package/dist/wire/capabilities.d.ts +896 -88
  218. package/dist/wire/capabilities.d.ts.map +1 -1
  219. package/dist/wire/capabilities.js +566 -62
  220. package/dist/wire/capabilities.js.map +1 -1
  221. package/dist/wire/pkt-line.d.ts +293 -15
  222. package/dist/wire/pkt-line.d.ts.map +1 -1
  223. package/dist/wire/pkt-line.js +251 -15
  224. package/dist/wire/pkt-line.js.map +1 -1
  225. package/dist/wire/receive-pack.d.ts +814 -64
  226. package/dist/wire/receive-pack.d.ts.map +1 -1
  227. package/dist/wire/receive-pack.js +542 -41
  228. package/dist/wire/receive-pack.js.map +1 -1
  229. package/dist/wire/smart-http.d.ts +575 -97
  230. package/dist/wire/smart-http.d.ts.map +1 -1
  231. package/dist/wire/smart-http.js +337 -46
  232. package/dist/wire/smart-http.js.map +1 -1
  233. package/dist/wire/upload-pack.d.ts +492 -98
  234. package/dist/wire/upload-pack.d.ts.map +1 -1
  235. package/dist/wire/upload-pack.js +347 -59
  236. package/dist/wire/upload-pack.js.map +1 -1
  237. package/package.json +1 -1
package/dist/ops/merge.js CHANGED
@@ -1,35 +1,111 @@
1
1
  /**
2
- * Three-way merge implementation for Git
2
+ * @fileoverview Three-way Merge Implementation for Git
3
3
  *
4
- * This module provides functionality for merging branches using
5
- * three-way merge algorithm, including conflict detection and resolution.
4
+ * This module provides a complete implementation of Git's three-way merge algorithm,
5
+ * enabling branch merging with automatic conflict detection and resolution capabilities.
6
+ *
7
+ * ## Overview
8
+ *
9
+ * The three-way merge algorithm works by:
10
+ * 1. Finding the common ancestor (merge base) of two commits
11
+ * 2. Comparing both branches against this base to identify changes
12
+ * 3. Automatically merging non-conflicting changes
13
+ * 4. Detecting and reporting conflicts for manual resolution
14
+ *
15
+ * ## Supported Features
16
+ *
17
+ * - Fast-forward merges when possible
18
+ * - Three-way content merging for text files
19
+ * - Binary file detection and handling
20
+ * - Multiple conflict types (content, add-add, modify-delete, etc.)
21
+ * - Conflict resolution strategies (ours, theirs, custom)
22
+ * - Merge state persistence for multi-step conflict resolution
23
+ *
24
+ * ## Usage Example
25
+ *
26
+ * ```typescript
27
+ * import { merge, resolveConflict, continueMerge } from './ops/merge'
28
+ *
29
+ * // Perform a merge
30
+ * const result = await merge(storage, currentBranchSha, featureBranchSha, {
31
+ * message: 'Merge feature branch',
32
+ * allowFastForward: true
33
+ * })
34
+ *
35
+ * if (result.status === 'conflicted') {
36
+ * // Resolve conflicts
37
+ * for (const conflict of result.conflicts) {
38
+ * await resolveConflict(storage, conflict.path, { resolution: 'ours' })
39
+ * }
40
+ * // Complete the merge
41
+ * await continueMerge(storage)
42
+ * }
43
+ * ```
44
+ *
45
+ * @module ops/merge
6
46
  */
7
47
  /**
8
48
  * Performs a three-way merge between the current branch and another commit.
9
49
  *
50
+ * @description
10
51
  * This function implements Git's three-way merge algorithm:
11
52
  * 1. Find the common ancestor (merge base) of the two commits
12
53
  * 2. Compare both sides against the base to identify changes
13
54
  * 3. Apply non-conflicting changes automatically
14
55
  * 4. Identify and report conflicts for manual resolution
15
56
  *
16
- * @param storage - The storage interface for reading/writing objects
57
+ * The merge can result in several outcomes:
58
+ * - **fast-forward**: If the current branch is an ancestor of the target,
59
+ * the branch pointer is simply moved forward
60
+ * - **merged**: Changes were successfully combined into a merge commit
61
+ * - **conflicted**: Some changes conflict and require manual resolution
62
+ * - **up-to-date**: The target is already merged; nothing to do
63
+ *
64
+ * @param storage - The storage interface for reading/writing Git objects
17
65
  * @param oursSha - SHA of the current branch's HEAD commit
18
- * @param theirsSha - SHA of the commit to merge
19
- * @param options - Merge options
20
- * @returns MergeResult with status and any conflicts
66
+ * @param theirsSha - SHA of the commit to merge into the current branch
67
+ * @param options - Configuration options for the merge operation
68
+ *
69
+ * @returns A promise resolving to the merge result with status and any conflicts
70
+ *
71
+ * @throws {Error} When commit objects cannot be read
72
+ * @throws {Error} When tree objects cannot be parsed
73
+ * @throws {Error} When fastForwardOnly is true but fast-forward is not possible
21
74
  *
22
75
  * @example
23
76
  * ```typescript
77
+ * // Basic merge
24
78
  * const result = await merge(storage, 'abc123', 'def456', {
25
- * message: 'Merge feature branch',
26
- * allowFastForward: true
79
+ * message: 'Merge feature branch'
27
80
  * })
28
81
  *
29
- * if (result.status === 'conflicted') {
30
- * console.log('Conflicts:', result.conflicts)
82
+ * if (result.status === 'merged') {
83
+ * console.log('Merge successful:', result.commitSha)
31
84
  * }
32
85
  * ```
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * // Fast-forward only merge
90
+ * try {
91
+ * const result = await merge(storage, 'abc123', 'def456', {
92
+ * fastForwardOnly: true
93
+ * })
94
+ * console.log('Fast-forwarded to:', result.treeSha)
95
+ * } catch (error) {
96
+ * console.log('Cannot fast-forward, branches have diverged')
97
+ * }
98
+ * ```
99
+ *
100
+ * @example
101
+ * ```typescript
102
+ * // Merge with auto-resolve conflicts using 'ours' strategy
103
+ * const result = await merge(storage, 'abc123', 'def456', {
104
+ * autoResolve: true,
105
+ * conflictStrategy: 'ours',
106
+ * message: 'Merge with our changes taking precedence'
107
+ * })
108
+ * ```
33
109
  */
34
110
  export async function merge(storage, oursSha, theirsSha, options = {}) {
35
111
  // Check if merging with self
@@ -210,7 +286,16 @@ export async function merge(storage, oursSha, theirsSha, options = {}) {
210
286
  };
211
287
  }
212
288
  /**
213
- * Generate a proper hex SHA string
289
+ * Generates a deterministic 40-character hex SHA from a seed string.
290
+ *
291
+ * @description
292
+ * Creates a SHA-like string for internal use. This is a simplified
293
+ * implementation for testing; production code should use proper SHA-1.
294
+ *
295
+ * @param seed - Input string to generate SHA from
296
+ * @returns 40-character hexadecimal string
297
+ *
298
+ * @internal
214
299
  */
215
300
  function generateHexSha(seed) {
216
301
  // Generate a proper 40-character hex string
@@ -225,7 +310,18 @@ function generateHexSha(seed) {
225
310
  return hex.padStart(8, '0').repeat(5).slice(0, 40);
226
311
  }
227
312
  /**
228
- * Get all entries from a tree recursively
313
+ * Recursively retrieves all entries from a tree object.
314
+ *
315
+ * @description
316
+ * Walks the tree structure recursively, collecting all file entries
317
+ * with their full paths from the repository root.
318
+ *
319
+ * @param storage - Storage interface for reading tree objects
320
+ * @param treeSha - SHA of the tree to read
321
+ * @param prefix - Path prefix for nested entries
322
+ * @returns Map of full path to tree entry info
323
+ *
324
+ * @internal
229
325
  */
230
326
  async function getTreeEntries(storage, treeSha, prefix = '') {
231
327
  const entries = new Map();
@@ -262,7 +358,16 @@ async function getTreeEntries(storage, treeSha, prefix = '') {
262
358
  return entries;
263
359
  }
264
360
  /**
265
- * Parse tree entries from raw tree data
361
+ * Parses tree entries from raw Git tree object data.
362
+ *
363
+ * @description
364
+ * Git tree format is: mode SP name NUL sha (20 bytes binary)
365
+ * This function parses that binary format into structured entries.
366
+ *
367
+ * @param data - Raw tree object content
368
+ * @returns Array of parsed tree entries
369
+ *
370
+ * @internal
266
371
  */
267
372
  function parseTreeEntries(data) {
268
373
  const entries = [];
@@ -291,7 +396,24 @@ function parseTreeEntries(data) {
291
396
  return entries;
292
397
  }
293
398
  /**
294
- * Merge a single file/entry
399
+ * Merges a single file entry using three-way merge logic.
400
+ *
401
+ * @description
402
+ * Compares the base, ours, and theirs versions of a single file
403
+ * and determines the merge result. Handles various cases:
404
+ * - File unchanged in one or both sides
405
+ * - File added/deleted on one or both sides
406
+ * - File modified on one or both sides (with content merge)
407
+ *
408
+ * @param storage - Storage interface for reading blob content
409
+ * @param path - Path of the file being merged
410
+ * @param baseEntry - Entry from the base (common ancestor)
411
+ * @param oursEntry - Entry from our branch
412
+ * @param theirsEntry - Entry from their branch
413
+ * @param stats - Statistics object to update
414
+ * @returns Merge result with either an entry or a conflict
415
+ *
416
+ * @internal
295
417
  */
296
418
  async function mergeEntry(storage, path, baseEntry, oursEntry, theirsEntry, stats) {
297
419
  // Case 1: File unchanged in both (same SHA and mode)
@@ -468,7 +590,13 @@ async function mergeEntry(storage, path, baseEntry, oursEntry, theirsEntry, stat
468
590
  return {};
469
591
  }
470
592
  /**
471
- * Get blob content from storage
593
+ * Retrieves blob content from storage.
594
+ *
595
+ * @param storage - Storage interface
596
+ * @param sha - SHA of the blob to read
597
+ * @returns Blob content or null if not found
598
+ *
599
+ * @internal
472
600
  */
473
601
  async function getBlobContent(storage, sha) {
474
602
  const obj = await storage.readObject(sha);
@@ -478,7 +606,17 @@ async function getBlobContent(storage, sha) {
478
606
  return obj.data;
479
607
  }
480
608
  /**
481
- * Build a tree from entries and write it to storage
609
+ * Builds a tree object from entries and writes it to storage.
610
+ *
611
+ * @description
612
+ * Takes a flat map of paths to entries and constructs the nested
613
+ * tree structure required by Git, writing subtrees as needed.
614
+ *
615
+ * @param storage - Storage interface for writing tree objects
616
+ * @param entries - Map of full paths to tree entries
617
+ * @returns SHA of the root tree object
618
+ *
619
+ * @internal
482
620
  */
483
621
  async function buildAndWriteTree(storage, entries) {
484
622
  // Group entries by top-level directory
@@ -553,7 +691,12 @@ async function buildAndWriteTree(storage, entries) {
553
691
  return storage.writeObject('tree', treeData);
554
692
  }
555
693
  /**
556
- * Convert hex string to bytes
694
+ * Converts a hex string to a 20-byte Uint8Array.
695
+ *
696
+ * @param hex - 40-character hexadecimal string
697
+ * @returns 20-byte array
698
+ *
699
+ * @internal
557
700
  */
558
701
  function hexToBytes(hex) {
559
702
  const bytes = new Uint8Array(20);
@@ -563,26 +706,54 @@ function hexToBytes(hex) {
563
706
  return bytes;
564
707
  }
565
708
  /**
566
- * Resolves a single merge conflict.
709
+ * Resolves a single merge conflict with the specified strategy.
567
710
  *
711
+ * @description
568
712
  * After a merge results in conflicts, use this function to resolve
569
- * individual files. Once all conflicts are resolved, use continueMerge()
570
- * to complete the merge.
713
+ * individual files. The resolution can use one of the three versions
714
+ * (ours, theirs, base) or provide custom merged content.
571
715
  *
572
- * @param storage - The storage interface
573
- * @param path - Path to the conflicted file
574
- * @param options - Resolution options
575
- * @returns ResolveResult indicating success and remaining conflicts
716
+ * Once all conflicts are resolved, use {@link continueMerge} to create
717
+ * the merge commit and complete the operation.
718
+ *
719
+ * @param storage - The storage interface for reading/writing objects
720
+ * @param path - Path to the conflicted file to resolve
721
+ * @param options - Resolution options specifying which version to use
722
+ *
723
+ * @returns A promise resolving to the resolution result
724
+ *
725
+ * @throws {Error} When no merge is in progress
726
+ * @throws {Error} When the specified path has no conflict
576
727
  *
577
728
  * @example
578
729
  * ```typescript
579
- * // Resolve using "ours" strategy
580
- * await resolveConflict(storage, 'src/file.ts', { resolution: 'ours' })
730
+ * // Resolve using our version
731
+ * const result = await resolveConflict(storage, 'src/file.ts', {
732
+ * resolution: 'ours'
733
+ * })
734
+ * console.log(`${result.remainingConflicts} conflicts remaining`)
735
+ * ```
581
736
  *
582
- * // Resolve with custom content
583
- * await resolveConflict(storage, 'src/file.ts', {
737
+ * @example
738
+ * ```typescript
739
+ * // Resolve using their version
740
+ * await resolveConflict(storage, 'config.json', {
741
+ * resolution: 'theirs'
742
+ * })
743
+ * ```
744
+ *
745
+ * @example
746
+ * ```typescript
747
+ * // Resolve with manually merged content
748
+ * const mergedContent = new TextEncoder().encode(`
749
+ * // Manually resolved: kept both features
750
+ * export function feature1() { ... }
751
+ * export function feature2() { ... }
752
+ * `)
753
+ *
754
+ * await resolveConflict(storage, 'src/features.ts', {
584
755
  * resolution: 'custom',
585
- * customContent: new TextEncoder().encode('merged content')
756
+ * customContent: mergedContent
586
757
  * })
587
758
  * ```
588
759
  */
@@ -691,17 +862,28 @@ export async function resolveConflict(storage, path, options) {
691
862
  /**
692
863
  * Aborts an in-progress merge operation.
693
864
  *
694
- * This restores the repository to its state before the merge began,
695
- * discarding any changes made during conflict resolution.
865
+ * @description
866
+ * Cancels the current merge and restores the repository to its state
867
+ * before the merge began. Any conflict resolutions or staged changes
868
+ * from the merge will be discarded.
869
+ *
870
+ * This is equivalent to `git merge --abort`.
696
871
  *
697
872
  * @param storage - The storage interface
698
- * @returns MergeOperationResult indicating success
873
+ *
874
+ * @returns A promise resolving to the operation result
875
+ *
876
+ * @throws {Error} When no merge is in progress
699
877
  *
700
878
  * @example
701
879
  * ```typescript
880
+ * // User decides to cancel the merge
702
881
  * const result = await abortMerge(storage)
882
+ *
703
883
  * if (result.success) {
704
- * console.log('Merge aborted, HEAD is now', result.headSha)
884
+ * console.log('Merge aborted, HEAD restored to', result.headSha)
885
+ * } else {
886
+ * console.error('Failed to abort:', result.error)
705
887
  * }
706
888
  * ```
707
889
  */
@@ -728,21 +910,39 @@ export async function abortMerge(storage) {
728
910
  /**
729
911
  * Continues a merge after all conflicts have been resolved.
730
912
  *
731
- * This creates the merge commit with the resolved files and
732
- * cleans up the merge state.
913
+ * @description
914
+ * After resolving all conflicts using {@link resolveConflict}, call this
915
+ * function to create the merge commit and complete the merge operation.
916
+ * The merge state will be cleaned up automatically.
917
+ *
918
+ * This is equivalent to `git merge --continue` or `git commit` after
919
+ * resolving conflicts.
733
920
  *
734
921
  * @param storage - The storage interface
735
- * @param message - Optional commit message (overrides stored message)
736
- * @returns MergeOperationResult with the new commit SHA
922
+ * @param message - Optional commit message (overrides the stored message)
923
+ *
924
+ * @returns A promise resolving to the operation result with the new commit SHA
925
+ *
926
+ * @throws {Error} When no merge is in progress
927
+ * @throws {Error} When unresolved conflicts remain
737
928
  *
738
929
  * @example
739
930
  * ```typescript
740
931
  * // After resolving all conflicts
741
932
  * const result = await continueMerge(storage)
933
+ *
742
934
  * if (result.success) {
743
- * console.log('Merge completed with commit', result.headSha)
935
+ * console.log('Merge completed:', result.headSha)
936
+ * } else {
937
+ * console.error('Cannot continue:', result.error)
744
938
  * }
745
939
  * ```
940
+ *
941
+ * @example
942
+ * ```typescript
943
+ * // Continue with a custom commit message
944
+ * const result = await continueMerge(storage, 'Merge feature-x with conflict resolution')
945
+ * ```
746
946
  */
747
947
  export async function continueMerge(storage, message) {
748
948
  // Get current merge state
@@ -777,18 +977,42 @@ export async function continueMerge(storage, message) {
777
977
  };
778
978
  }
779
979
  /**
780
- * Helper to generate SHA-like strings
980
+ * Creates a SHA-like string from a prefix.
981
+ *
982
+ * @param prefix - String to use as the basis for the SHA
983
+ * @returns 40-character string
984
+ *
985
+ * @internal
781
986
  */
782
987
  function makeSha(prefix) {
783
988
  return prefix.padEnd(40, '0');
784
989
  }
785
990
  /**
786
- * Finds the best common ancestor (merge base) for two commits.
991
+ * Finds the best common ancestor (merge base) of two commits.
787
992
  *
788
- * @param storage - The storage interface
789
- * @param commit1 - First commit SHA
790
- * @param commit2 - Second commit SHA
791
- * @returns SHA of the merge base, or null if no common ancestor exists
993
+ * @description
994
+ * Implements the merge base algorithm by finding the most recent commit
995
+ * that is an ancestor of both input commits. This is the commit from
996
+ * which both branches diverged.
997
+ *
998
+ * Uses a breadth-first search from both commits to find their
999
+ * intersection in the commit graph.
1000
+ *
1001
+ * @param storage - The storage interface for reading commit objects
1002
+ * @param commit1 - SHA of the first commit
1003
+ * @param commit2 - SHA of the second commit
1004
+ *
1005
+ * @returns A promise resolving to the merge base SHA, or null if no common ancestor exists
1006
+ *
1007
+ * @example
1008
+ * ```typescript
1009
+ * const base = await findMergeBase(storage, 'feature-sha', 'main-sha')
1010
+ * if (base) {
1011
+ * console.log('Common ancestor:', base)
1012
+ * } else {
1013
+ * console.log('No common history')
1014
+ * }
1015
+ * ```
792
1016
  */
793
1017
  export async function findMergeBase(storage, commit1, commit2) {
794
1018
  // Get all ancestors of commit1 (including itself)
@@ -836,7 +1060,13 @@ export async function findMergeBase(storage, commit1, commit2) {
836
1060
  return null;
837
1061
  }
838
1062
  /**
839
- * Parse parent SHAs from commit data or get from extended object
1063
+ * Parses parent commit SHAs from raw commit data.
1064
+ *
1065
+ * @param data - Raw commit object content
1066
+ * @param extendedParents - Pre-parsed parents if available
1067
+ * @returns Array of parent commit SHAs
1068
+ *
1069
+ * @internal
840
1070
  */
841
1071
  function parseCommitParents(data, extendedParents) {
842
1072
  // If extended parents are provided, use them directly
@@ -857,7 +1087,13 @@ function parseCommitParents(data, extendedParents) {
857
1087
  return parents;
858
1088
  }
859
1089
  /**
860
- * Parse tree SHA from commit data or get from extended object
1090
+ * Parses the tree SHA from raw commit data.
1091
+ *
1092
+ * @param data - Raw commit object content
1093
+ * @param treeSha - Pre-parsed tree SHA if available
1094
+ * @returns Tree SHA or null if not found
1095
+ *
1096
+ * @internal
861
1097
  */
862
1098
  function parseCommitTree(data, treeSha) {
863
1099
  // If extended tree SHA is provided, use it directly
@@ -876,7 +1112,12 @@ function parseCommitTree(data, treeSha) {
876
1112
  const encoder = new TextEncoder();
877
1113
  const decoder = new TextDecoder();
878
1114
  /**
879
- * Split content into lines, preserving line endings
1115
+ * Splits content into lines while preserving line endings.
1116
+ *
1117
+ * @param content - Binary content to split
1118
+ * @returns Array of lines (without line ending characters)
1119
+ *
1120
+ * @internal
880
1121
  */
881
1122
  function splitLines(content) {
882
1123
  const text = decoder.decode(content);
@@ -888,7 +1129,18 @@ function splitLines(content) {
888
1129
  return text.split(/\r?\n/);
889
1130
  }
890
1131
  /**
891
- * Compute the longest common subsequence of two arrays
1132
+ * Computes the longest common subsequence of two arrays.
1133
+ *
1134
+ * @description
1135
+ * Uses dynamic programming to find the longest subsequence common
1136
+ * to both arrays. Used as a building block for the diff algorithm.
1137
+ *
1138
+ * @param a - First array
1139
+ * @param b - Second array
1140
+ * @param equals - Function to compare elements for equality
1141
+ * @returns Array containing the longest common subsequence
1142
+ *
1143
+ * @internal
892
1144
  */
893
1145
  function lcs(a, b, equals) {
894
1146
  const m = a.length;
@@ -925,7 +1177,13 @@ function lcs(a, b, equals) {
925
1177
  return result;
926
1178
  }
927
1179
  /**
928
- * Compute diff hunks between base and target
1180
+ * Computes diff hunks between base and target line arrays.
1181
+ *
1182
+ * @param base - Original lines
1183
+ * @param target - Modified lines
1184
+ * @returns Array of hunks describing the differences
1185
+ *
1186
+ * @internal
929
1187
  */
930
1188
  function computeHunks(base, target) {
931
1189
  const hunks = [];
@@ -966,7 +1224,13 @@ function computeHunks(base, target) {
966
1224
  return hunks;
967
1225
  }
968
1226
  /**
969
- * Check if two hunks overlap in the base
1227
+ * Checks if two hunks overlap in their base ranges.
1228
+ *
1229
+ * @param h1 - First hunk
1230
+ * @param h2 - Second hunk
1231
+ * @returns true if the hunks overlap
1232
+ *
1233
+ * @internal
970
1234
  */
971
1235
  function hunksOverlap(h1, h2) {
972
1236
  // Hunks overlap if their base ranges intersect
@@ -975,7 +1239,13 @@ function hunksOverlap(h1, h2) {
975
1239
  return !(end1 <= h2.baseStart || end2 <= h1.baseStart);
976
1240
  }
977
1241
  /**
978
- * Check if two hunks are at the same position (same base range and direction)
1242
+ * Checks if two hunks represent the same change.
1243
+ *
1244
+ * @param h1 - First hunk
1245
+ * @param h2 - Second hunk
1246
+ * @returns true if the hunks are identical
1247
+ *
1248
+ * @internal
979
1249
  */
980
1250
  function hunksSameChange(h1, h2) {
981
1251
  if (h1.baseStart !== h2.baseStart || h1.baseCount !== h2.baseCount) {
@@ -994,10 +1264,39 @@ function hunksSameChange(h1, h2) {
994
1264
  /**
995
1265
  * Performs a content-level three-way merge on text files.
996
1266
  *
1267
+ * @description
1268
+ * Takes three versions of a file (base, ours, theirs) and attempts to
1269
+ * automatically merge them. Non-conflicting changes are combined
1270
+ * automatically. Conflicting changes are marked with standard Git
1271
+ * conflict markers.
1272
+ *
1273
+ * The algorithm:
1274
+ * 1. Compute the diff hunks from base to ours
1275
+ * 2. Compute the diff hunks from base to theirs
1276
+ * 3. Process hunks in order, detecting overlaps
1277
+ * 4. Non-overlapping hunks are applied automatically
1278
+ * 5. Overlapping hunks with identical changes are deduplicated
1279
+ * 6. Overlapping hunks with different changes create conflict markers
1280
+ *
997
1281
  * @param base - Content of the base (common ancestor) version
998
- * @param ours - Content of our (current) version
999
- * @param theirs - Content of their (merged) version
1000
- * @returns Merged content and any conflict markers
1282
+ * @param ours - Content of our (current branch) version
1283
+ * @param theirs - Content of their (merged branch) version
1284
+ *
1285
+ * @returns Object containing merged content, conflict flag, and marker locations
1286
+ *
1287
+ * @example
1288
+ * ```typescript
1289
+ * const result = mergeContent(baseContent, oursContent, theirsContent)
1290
+ *
1291
+ * if (result.hasConflicts) {
1292
+ * console.log('Content has conflicts at:', result.markers)
1293
+ * // Write file with conflict markers for manual resolution
1294
+ * await writeFile(path, result.merged)
1295
+ * } else {
1296
+ * console.log('Content merged cleanly')
1297
+ * await writeFile(path, result.merged)
1298
+ * }
1299
+ * ```
1001
1300
  */
1002
1301
  export function mergeContent(base, ours, theirs) {
1003
1302
  const baseLines = splitLines(base);
@@ -1143,10 +1442,27 @@ export function mergeContent(base, ours, theirs) {
1143
1442
  };
1144
1443
  }
1145
1444
  /**
1146
- * Checks if a file is binary (non-text).
1445
+ * Determines if a file is binary (non-text) based on its content.
1446
+ *
1447
+ * @description
1448
+ * Uses Git's heuristic: a file is considered binary if it contains
1449
+ * null bytes (0x00) within the first 8000 bytes, or if it has
1450
+ * specific binary file magic numbers (PNG, JPEG, GIF).
1147
1451
  *
1148
- * @param content - File content to check
1149
- * @returns true if the file appears to be binary
1452
+ * Binary files cannot be automatically merged and always result
1453
+ * in conflicts when both sides modify them.
1454
+ *
1455
+ * @param content - File content to analyze
1456
+ *
1457
+ * @returns true if the file appears to be binary, false for text files
1458
+ *
1459
+ * @example
1460
+ * ```typescript
1461
+ * const content = await readFile('image.png')
1462
+ * if (isBinaryFile(content)) {
1463
+ * console.log('Cannot perform text merge on binary file')
1464
+ * }
1465
+ * ```
1150
1466
  */
1151
1467
  export function isBinaryFile(content) {
1152
1468
  // Empty files are considered text
@@ -1184,8 +1500,25 @@ export function isBinaryFile(content) {
1184
1500
  /**
1185
1501
  * Gets the current merge state if a merge is in progress.
1186
1502
  *
1503
+ * @description
1504
+ * Returns the persisted merge state, which includes information about
1505
+ * the merge in progress, any unresolved conflicts, and the original
1506
+ * merge options.
1507
+ *
1187
1508
  * @param storage - The storage interface
1188
- * @returns MergeState if merge is in progress, null otherwise
1509
+ *
1510
+ * @returns A promise resolving to the merge state, or null if no merge is in progress
1511
+ *
1512
+ * @example
1513
+ * ```typescript
1514
+ * const state = await getMergeState(storage)
1515
+ * if (state) {
1516
+ * console.log('Merging', state.mergeHead, 'into', state.origHead)
1517
+ * console.log('Unresolved conflicts:', state.unresolvedConflicts.length)
1518
+ * } else {
1519
+ * console.log('No merge in progress')
1520
+ * }
1521
+ * ```
1189
1522
  */
1190
1523
  export async function getMergeState(storage) {
1191
1524
  return storage.readMergeState();
@@ -1193,8 +1526,23 @@ export async function getMergeState(storage) {
1193
1526
  /**
1194
1527
  * Checks if a merge is currently in progress.
1195
1528
  *
1529
+ * @description
1530
+ * Quick check to determine if there's an active merge that hasn't
1531
+ * been completed or aborted. Useful for UI state and command validation.
1532
+ *
1196
1533
  * @param storage - The storage interface
1197
- * @returns true if a merge is in progress
1534
+ *
1535
+ * @returns A promise resolving to true if a merge is in progress
1536
+ *
1537
+ * @example
1538
+ * ```typescript
1539
+ * if (await isMergeInProgress(storage)) {
1540
+ * console.log('Please complete or abort the current merge first')
1541
+ * } else {
1542
+ * // Safe to start a new merge
1543
+ * await merge(storage, oursSha, theirsSha, options)
1544
+ * }
1545
+ * ```
1198
1546
  */
1199
1547
  export async function isMergeInProgress(storage) {
1200
1548
  const state = await storage.readMergeState();