@ibgib/vcs-gib 0.0.17 → 0.0.20

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 (135) hide show
  1. package/dist/AUTO-GENERATED-version.d.mts +1 -1
  2. package/dist/AUTO-GENERATED-version.mjs +1 -1
  3. package/dist/bootstrap/node-bootstrap.d.mts.map +1 -1
  4. package/dist/bootstrap/node-bootstrap.mjs +3 -0
  5. package/dist/bootstrap/node-bootstrap.mjs.map +1 -1
  6. package/dist/cli/cli-constants.d.mts +1 -0
  7. package/dist/cli/cli-constants.d.mts.map +1 -1
  8. package/dist/cli/cli-constants.mjs +1 -0
  9. package/dist/cli/cli-constants.mjs.map +1 -1
  10. package/dist/cli/commands/add-cmd.d.mts.map +1 -1
  11. package/dist/cli/commands/add-cmd.mjs +2 -2
  12. package/dist/cli/commands/add-cmd.mjs.map +1 -1
  13. package/dist/cli/commands/branch-cmd.d.mts.map +1 -1
  14. package/dist/cli/commands/branch-cmd.mjs +2 -2
  15. package/dist/cli/commands/branch-cmd.mjs.map +1 -1
  16. package/dist/cli/commands/checkout-cmd.d.mts.map +1 -1
  17. package/dist/cli/commands/checkout-cmd.mjs +15 -7
  18. package/dist/cli/commands/checkout-cmd.mjs.map +1 -1
  19. package/dist/cli/commands/commit-cmd.d.mts.map +1 -1
  20. package/dist/cli/commands/commit-cmd.mjs +2 -2
  21. package/dist/cli/commands/commit-cmd.mjs.map +1 -1
  22. package/dist/cli/commands/merge-cmd.d.mts +23 -0
  23. package/dist/cli/commands/merge-cmd.d.mts.map +1 -0
  24. package/dist/cli/commands/merge-cmd.mjs +224 -0
  25. package/dist/cli/commands/merge-cmd.mjs.map +1 -0
  26. package/dist/cli/vcs-cli-main.d.mts.map +1 -1
  27. package/dist/cli/vcs-cli-main.mjs +7 -0
  28. package/dist/cli/vcs-cli-main.mjs.map +1 -1
  29. package/dist/engine/item/item-helper.d.mts +1 -0
  30. package/dist/engine/item/item-helper.d.mts.map +1 -1
  31. package/dist/engine/item/item-helper.mjs +13 -3
  32. package/dist/engine/item/item-helper.mjs.map +1 -1
  33. package/dist/engine/item/item-types.d.mts +1 -0
  34. package/dist/engine/item/item-types.d.mts.map +1 -1
  35. package/dist/engine/merge/b2tfs-3way-merge-strategy.d.mts +48 -0
  36. package/dist/engine/merge/b2tfs-3way-merge-strategy.d.mts.map +1 -0
  37. package/dist/engine/merge/b2tfs-3way-merge-strategy.mjs +741 -0
  38. package/dist/engine/merge/b2tfs-3way-merge-strategy.mjs.map +1 -0
  39. package/dist/engine/merge/b2tfs-3way-merge-types.d.mts +41 -0
  40. package/dist/engine/merge/b2tfs-3way-merge-types.d.mts.map +1 -0
  41. package/dist/engine/merge/b2tfs-3way-merge-types.mjs +2 -0
  42. package/dist/engine/merge/b2tfs-3way-merge-types.mjs.map +1 -0
  43. package/dist/respec-gib.node.mjs +1 -1
  44. package/dist/respec-gib.node.mjs.map +1 -1
  45. package/package.json +6 -6
  46. package/src/AUTO-GENERATED-version.mts +1 -1
  47. package/src/bootstrap/node-bootstrap.mts +6 -1
  48. package/src/cli/cli-constants.mts +1 -0
  49. package/src/cli/commands/add-cmd.mts +5 -3
  50. package/src/cli/commands/branch-checkout-cmd.respec.log +111 -0
  51. package/src/cli/commands/{branch-checkout-cmd.respec.node.mts → branch-checkout-cmd.respec.mts} +112 -9
  52. package/src/cli/commands/branch-cmd.mts +5 -6
  53. package/src/cli/commands/checkout-cmd.mts +23 -9
  54. package/src/cli/commands/commit-cmd.mts +5 -3
  55. package/src/cli/commands/merge-cmd.mts +285 -0
  56. package/src/cli/vcs-cli-main.mts +7 -0
  57. package/src/engine/item/item-helper.mts +15 -9
  58. package/src/engine/item/item-types.mts +2 -1
  59. package/src/engine/merge/b2tfs-3way-merge-strategy.mts +852 -0
  60. package/src/engine/merge/b2tfs-3way-merge-strategy.respec.log +39 -0
  61. package/src/engine/merge/b2tfs-3way-merge-strategy.respec.mts +441 -0
  62. package/src/engine/merge/b2tfs-3way-merge-types.mts +42 -0
  63. package/src/respec-gib.node.mts +2 -2
  64. package/tsconfig.json +3 -2
  65. package/tsconfig.test.json +10 -0
  66. package/tsconfig.test.tsbuildinfo +1 -0
  67. package/tsconfig.tsbuildinfo +1 -1
  68. package/dist/assumptions.respec.d.mts +0 -2
  69. package/dist/assumptions.respec.d.mts.map +0 -1
  70. package/dist/assumptions.respec.mjs +0 -41
  71. package/dist/assumptions.respec.mjs.map +0 -1
  72. package/dist/bootstrap/node-bootstrap.respec.node.d.mts +0 -7
  73. package/dist/bootstrap/node-bootstrap.respec.node.d.mts.map +0 -1
  74. package/dist/bootstrap/node-bootstrap.respec.node.mjs +0 -28
  75. package/dist/bootstrap/node-bootstrap.respec.node.mjs.map +0 -1
  76. package/dist/cli/cli-arg-parser.respec.node.d.mts +0 -7
  77. package/dist/cli/cli-arg-parser.respec.node.d.mts.map +0 -1
  78. package/dist/cli/cli-arg-parser.respec.node.mjs +0 -35
  79. package/dist/cli/cli-arg-parser.respec.node.mjs.map +0 -1
  80. package/dist/cli/cli-e2e.respec.node.d.mts +0 -8
  81. package/dist/cli/cli-e2e.respec.node.d.mts.map +0 -1
  82. package/dist/cli/cli-e2e.respec.node.mjs +0 -263
  83. package/dist/cli/cli-e2e.respec.node.mjs.map +0 -1
  84. package/dist/cli/commands/branch-checkout-cmd.respec.node.d.mts +0 -7
  85. package/dist/cli/commands/branch-checkout-cmd.respec.node.d.mts.map +0 -1
  86. package/dist/cli/commands/branch-checkout-cmd.respec.node.mjs +0 -358
  87. package/dist/cli/commands/branch-checkout-cmd.respec.node.mjs.map +0 -1
  88. package/dist/cli/commands/commit-log-cmd.respec.node.d.mts +0 -7
  89. package/dist/cli/commands/commit-log-cmd.respec.node.d.mts.map +0 -1
  90. package/dist/cli/commands/commit-log-cmd.respec.node.mjs +0 -251
  91. package/dist/cli/commands/commit-log-cmd.respec.node.mjs.map +0 -1
  92. package/dist/cli/commands/init-cmd.respec.node.d.mts +0 -7
  93. package/dist/cli/commands/init-cmd.respec.node.d.mts.map +0 -1
  94. package/dist/cli/commands/init-cmd.respec.node.mjs +0 -40
  95. package/dist/cli/commands/init-cmd.respec.node.mjs.map +0 -1
  96. package/dist/cli/commands/reset-restore-cmd.respec.node.d.mts +0 -7
  97. package/dist/cli/commands/reset-restore-cmd.respec.node.d.mts.map +0 -1
  98. package/dist/cli/commands/reset-restore-cmd.respec.node.mjs +0 -185
  99. package/dist/cli/commands/reset-restore-cmd.respec.node.mjs.map +0 -1
  100. package/dist/cli/commands/status-add-cmd.respec.node.d.mts +0 -7
  101. package/dist/cli/commands/status-add-cmd.respec.node.d.mts.map +0 -1
  102. package/dist/cli/commands/status-add-cmd.respec.node.mjs +0 -239
  103. package/dist/cli/commands/status-add-cmd.respec.node.mjs.map +0 -1
  104. package/dist/engine/branch/branch-space.respec.node.d.mts +0 -8
  105. package/dist/engine/branch/branch-space.respec.node.d.mts.map +0 -1
  106. package/dist/engine/branch/branch-space.respec.node.mjs +0 -143
  107. package/dist/engine/branch/branch-space.respec.node.mjs.map +0 -1
  108. package/dist/engine/diff/line-diff-helper.respec.node.d.mts +0 -7
  109. package/dist/engine/diff/line-diff-helper.respec.node.d.mts.map +0 -1
  110. package/dist/engine/diff/line-diff-helper.respec.node.mjs +0 -66
  111. package/dist/engine/diff/line-diff-helper.respec.node.mjs.map +0 -1
  112. package/dist/engine/filter/glob-helper.respec.node.d.mts +0 -7
  113. package/dist/engine/filter/glob-helper.respec.node.d.mts.map +0 -1
  114. package/dist/engine/filter/glob-helper.respec.node.mjs +0 -78
  115. package/dist/engine/filter/glob-helper.respec.node.mjs.map +0 -1
  116. package/dist/engine/item/item.respec.node.d.mts +0 -7
  117. package/dist/engine/item/item.respec.node.d.mts.map +0 -1
  118. package/dist/engine/item/item.respec.node.mjs +0 -75
  119. package/dist/engine/item/item.respec.node.mjs.map +0 -1
  120. package/dist/vcs-gib.respec.node.d.mts +0 -8
  121. package/dist/vcs-gib.respec.node.d.mts.map +0 -1
  122. package/dist/vcs-gib.respec.node.mjs +0 -82
  123. package/dist/vcs-gib.respec.node.mjs.map +0 -1
  124. /package/src/bootstrap/{node-bootstrap.respec.node.mts → node-bootstrap.respec.mts} +0 -0
  125. /package/src/cli/{cli-arg-parser.respec.node.mts → cli-arg-parser.respec.mts} +0 -0
  126. /package/src/cli/{cli-e2e.respec.node.mts → cli-e2e.respec.mts} +0 -0
  127. /package/src/cli/commands/{commit-log-cmd.respec.node.mts → commit-log-cmd.respec.mts} +0 -0
  128. /package/src/cli/commands/{init-cmd.respec.node.mts → init-cmd.respec.mts} +0 -0
  129. /package/src/cli/commands/{reset-restore-cmd.respec.node.mts → reset-restore-cmd.respec.mts} +0 -0
  130. /package/src/cli/commands/{status-add-cmd.respec.node.mts → status-add-cmd.respec.mts} +0 -0
  131. /package/src/engine/branch/{branch-space.respec.node.mts → branch-space.respec.mts} +0 -0
  132. /package/src/engine/diff/{line-diff-helper.respec.node.mts → line-diff-helper.respec.mts} +0 -0
  133. /package/src/engine/filter/{glob-helper.respec.node.mts → glob-helper.respec.mts} +0 -0
  134. /package/src/engine/item/{item.respec.node.mts → item.respec.mts} +0 -0
  135. /package/src/{vcs-gib.respec.node.mts → vcs-gib.respec.mts} +0 -0
@@ -0,0 +1,741 @@
1
+ /**
2
+ * @module b2tfs-3way-merge-strategy
3
+ *
4
+ * Extensible Graft Merge Strategy for 3-way B2tFS filesystem snapshot trees and text files.
5
+ */
6
+ import { extractErrorMsg, hash } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
7
+ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
8
+ import { getGib } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
9
+ import { rel8 } from '@ibgib/ts-gib/dist/V1/transforms/rel8.mjs';
10
+ import { GraftMergeStrategyBase_V1 } from '@ibgib/core-gib/dist/sync/graft-info/graft-merge-strategy-base-v1.mjs';
11
+ import { getFromSpace, persistTransformResult, registerNewIbGib, putInSpace } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
12
+ import { getBinIb, getIbGibsFromCache_fallbackToSpaces } from '@ibgib/core-gib/dist/common/other/ibgib-helper.mjs';
13
+ import { createGraftInfo } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-helpers.mjs';
14
+ import { GRAFT_INFO_REL8N_NAME } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-constants.mjs';
15
+ import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.mjs';
16
+ import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
17
+ import { isBinaryBuffer, decodeToLines, computeLineLcsDiff } from '../diff/line-diff-helper.mjs';
18
+ import { B2TFS_CHILD_ITEM_REL8N_NAME, BINARY_REL8N_NAME, B2tFSType } from '../item/item-types.mjs';
19
+ import { evolveB2tFSItemIbGib, isB2tFSItemIbGib } from '../item/item-helper.mjs';
20
+ const lcFile = `[b2tfs-3way-merge-strategy]`;
21
+ const logalot = GLOBAL_LOG_A_LOT || true;
22
+ const mergeDiag = `[MERGE DIAGNOSTIC]`;
23
+ /**
24
+ * Performs 3-way line diff merging across LCA, Base, and Orphan text lines.
25
+ * Inserts Git conflict markers (`<<<<<<< HEAD`, `=======`, `>>>>>>>`) when overlapping
26
+ * line changes conflict.
27
+ */
28
+ export function perform3WayTextLineMerge({ textLCA, textBase, textOrphan, }) {
29
+ console.log(`[DEBUG 3WAY] textLCA: ${JSON.stringify(textLCA)}`);
30
+ console.log(`[DEBUG 3WAY] textBase: ${JSON.stringify(textBase)}`);
31
+ console.log(`[DEBUG 3WAY] textOrphan: ${JSON.stringify(textOrphan)}`);
32
+ if (textBase === textOrphan) {
33
+ return { mergedText: textBase, hasConflict: false };
34
+ }
35
+ if (textBase === textLCA) {
36
+ return { mergedText: textOrphan, hasConflict: false };
37
+ }
38
+ if (textOrphan === textLCA) {
39
+ return { mergedText: textBase, hasConflict: false };
40
+ }
41
+ const linesLCA = textLCA.split(/\r?\n/);
42
+ const linesBase = textBase.split(/\r?\n/);
43
+ const linesOrphan = textOrphan.split(/\r?\n/);
44
+ const chunksBase = computeLineLcsDiff(linesLCA, linesBase);
45
+ const chunksOrphan = computeLineLcsDiff(linesLCA, linesOrphan);
46
+ if (chunksBase.length === 0) {
47
+ return { mergedText: textOrphan, hasConflict: false };
48
+ }
49
+ if (chunksOrphan.length === 0) {
50
+ return { mergedText: textBase, hasConflict: false };
51
+ }
52
+ let hasConflict = false;
53
+ const outputLines = [];
54
+ let lcaIdx = 0;
55
+ let baseChunkIdx = 0;
56
+ let orphanChunkIdx = 0;
57
+ while (lcaIdx < linesLCA.length || baseChunkIdx < chunksBase.length || orphanChunkIdx < chunksOrphan.length) {
58
+ const nextBaseChunk = chunksBase[baseChunkIdx];
59
+ const nextOrphanChunk = chunksOrphan[orphanChunkIdx];
60
+ const baseAtLca = nextBaseChunk && nextBaseChunk.old_i === lcaIdx;
61
+ const orphanAtLca = nextOrphanChunk && nextOrphanChunk.old_i === lcaIdx;
62
+ if (baseAtLca && orphanAtLca) {
63
+ const bLines = nextBaseChunk.newLines;
64
+ const oLines = nextOrphanChunk.newLines;
65
+ const bOldLen = nextBaseChunk.oldLines.length;
66
+ const oOldLen = nextOrphanChunk.oldLines.length;
67
+ if (bLines.join('\n') === oLines.join('\n') && bOldLen === oOldLen) {
68
+ outputLines.push(...bLines);
69
+ }
70
+ else {
71
+ hasConflict = true;
72
+ outputLines.push('<<<<<<< HEAD');
73
+ outputLines.push(...bLines);
74
+ outputLines.push('=======');
75
+ outputLines.push(...oLines);
76
+ outputLines.push('>>>>>>>');
77
+ }
78
+ const consumedLca = Math.max(bOldLen, oOldLen, 1);
79
+ lcaIdx += consumedLca;
80
+ baseChunkIdx++;
81
+ orphanChunkIdx++;
82
+ }
83
+ else if (baseAtLca) {
84
+ outputLines.push(...nextBaseChunk.newLines);
85
+ const consumedLca = Math.max(nextBaseChunk.oldLines.length, 1);
86
+ lcaIdx += consumedLca;
87
+ baseChunkIdx++;
88
+ }
89
+ else if (orphanAtLca) {
90
+ outputLines.push(...nextOrphanChunk.newLines);
91
+ const consumedLca = Math.max(nextOrphanChunk.oldLines.length, 1);
92
+ lcaIdx += consumedLca;
93
+ orphanChunkIdx++;
94
+ }
95
+ else {
96
+ if (lcaIdx < linesLCA.length) {
97
+ outputLines.push(linesLCA[lcaIdx]);
98
+ lcaIdx++;
99
+ }
100
+ else {
101
+ if (nextBaseChunk && baseChunkIdx < chunksBase.length) {
102
+ outputLines.push(...nextBaseChunk.newLines);
103
+ baseChunkIdx++;
104
+ }
105
+ if (nextOrphanChunk && orphanChunkIdx < chunksOrphan.length) {
106
+ outputLines.push(...nextOrphanChunk.newLines);
107
+ orphanChunkIdx++;
108
+ }
109
+ }
110
+ }
111
+ }
112
+ return {
113
+ mergedText: outputLines.join('\n'),
114
+ hasConflict,
115
+ };
116
+ }
117
+ export class B2tFS3WayGraftStrategy extends GraftMergeStrategyBase_V1 {
118
+ strategyId = 'B2tFS3WayGraftStrategy';
119
+ lc = '[B2tFS3WayGraftStrategy]';
120
+ /**
121
+ * Returns true only if the graft context has two tips that are text-based file b2tfs item ibgibs.
122
+ *
123
+ * ## notes
124
+ *
125
+ * atow (08/12/2026) implementation is guantlet style: if cannot graft, return early
126
+ *
127
+ * @param context info about the divergent timelines {@link GraftContext}
128
+ *
129
+ * @returns true if it's a text file item ibgib, else false
130
+ */
131
+ async canGraft(context) {
132
+ const lc = `${this.lc}[${this.canGraft.name}]`;
133
+ try {
134
+ const { conflictStrategy, timelineAddrsA, timelineAddrsB, ibGibReadCache, space } = context;
135
+ // todo: refactor conflict strategy to be more generic: 'graft' | 'abort' | maybe something else.
136
+ const hasRelevantStrategy = conflictStrategy === SyncConflictStrategy.optimisticWithLCS || conflictStrategy === 'b2tfs3WayMerge';
137
+ if (!hasRelevantStrategy) {
138
+ // immediately return false because we are not the chosen strategy.
139
+ // todo: after refactor, really this should be out of the hands of the implementation and we should have a discriminator as part of the strategy interface. So the graft strategy pipeline executor can just check that first, and then if multiple found, it will delegate to this `canGraft` method.
140
+ return false; /* <<<< returns early */
141
+ }
142
+ const tipAddrA = timelineAddrsA.at(-1);
143
+ const tipAddrB = timelineAddrsB.at(-1);
144
+ if (!tipAddrA || !tipAddrB) {
145
+ if (logalot) {
146
+ console.log(`${lc} we don't have two tip addrs? how was a graft decided upon? (I: b20b6de462c35e0e74360cc8d317f126)`);
147
+ }
148
+ return false; /* <<<< returns early */
149
+ }
150
+ const [tipA, tipB] = await getIbGibsFromCache_fallbackToSpaces({
151
+ addrs: [tipAddrA, tipAddrB],
152
+ readCache_graph: ibGibReadCache,
153
+ space,
154
+ });
155
+ if (!tipA) {
156
+ throw new Error(`(UNEXPECTED) tipA falsy? couldn't get tipA? should have been available to us in the temp space or cache.(E: 752101026888140f074614e893531826)`);
157
+ }
158
+ if (!tipB) {
159
+ throw new Error(`(UNEXPECTED) tipB falsy? couldn't get tipB? should have been available to us in the temp space or cache. (E: d4d4a876cad8c7869830d33832bfde26)`);
160
+ }
161
+ const bothTipsAreB2tFSNodes = isB2tFSItemIbGib(tipA) && isB2tFSItemIbGib(tipB);
162
+ if (!bothTipsAreB2tFSNodes) {
163
+ // at this point, we're returning false. But I'm being extra defensive since this algorithm is so difficult to implement. So throw if somehow only one is a b2tfs item
164
+ if (isB2tFSItemIbGib(tipA) || isB2tFSItemIbGib(tipB)) {
165
+ console.error(`${lc}${mergeDiag} (UNEXPECTED)(NOT THROWN) only tipA or tipB but not both are b2tfs items? (E: cacb38796da881268898e9d1af245826)`);
166
+ }
167
+ return false; /* <<<< returns early */
168
+ }
169
+ if (tipA.data.fsType !== tipB.data.fsType) {
170
+ throw new Error(`(UNEXPECTED) tipA.data.fsType (${tipA.data.fsType}) !== tipB.data.fsType (${tipB.data.fsType})? both tips are expected to be the same B2tFSType. (E: c01c1885ac738f679813117852c48426)`);
171
+ }
172
+ // only do files. folders can use the replay dna strategy.
173
+ const isFile = tipA.data.fsType === B2tFSType.file;
174
+ if (!isFile) {
175
+ return false; /* <<<< returns early */
176
+ }
177
+ // passed gauntlet, we have a b2tfs file item that we can merge
178
+ return true;
179
+ }
180
+ catch (error) {
181
+ console.error(`${lc} ${extractErrorMsg(error)} (E: 8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e)`);
182
+ return false;
183
+ }
184
+ }
185
+ async graft(context) {
186
+ const lc = `${lcFile}[${this.strategyId}][${this.graft.name}]`;
187
+ try {
188
+ if (logalot) {
189
+ console.log(`${lc} starting 3-way B2tFS snapshot graft... (I: 91a82b3c4d5e6f7a8b9c0d1e2f3a4b5c)`);
190
+ }
191
+ const { conflictStrategy, timelineAddrsA, timelineAddrsB, latestCommonFrameAddr, ibGibReadCache, space, graftPreference, } = context;
192
+ // 1. Fetch branch slices since LCA (timeline A = Sender, timeline B = Receiver)
193
+ const indexLCA_A = timelineAddrsA.lastIndexOf(latestCommonFrameAddr);
194
+ const addrsA_sinceLCA = timelineAddrsA.slice(indexLCA_A + 1);
195
+ const branchA_sender_sinceLCA = await getIbGibsFromCache_fallbackToSpaces({
196
+ readCache_graph: ibGibReadCache,
197
+ addrs: addrsA_sinceLCA,
198
+ space,
199
+ });
200
+ const tipA_sender = branchA_sender_sinceLCA.at(-1);
201
+ const indexLCA_B = timelineAddrsB.lastIndexOf(latestCommonFrameAddr);
202
+ const addrsB_sinceLCA = timelineAddrsB.slice(indexLCA_B + 1);
203
+ const branchB_receiver_sinceLCA = await getIbGibsFromCache_fallbackToSpaces({
204
+ readCache_graph: ibGibReadCache,
205
+ addrs: addrsB_sinceLCA,
206
+ space,
207
+ });
208
+ const tipB_receiver = branchB_receiver_sinceLCA.at(-1);
209
+ // 2. Base & Orphan tip determination (directional preference) via DRY base helper
210
+ const { baseTip, baseBranch, orphanTip, orphanBranch, } = this.resolveBaseAndOrphan({
211
+ graftPreference,
212
+ tipA_sender,
213
+ branchA_sender_sinceLCA,
214
+ tipB_receiver,
215
+ branchB_receiver_sinceLCA,
216
+ });
217
+ const baseTipAddr = getIbGibAddr({ ibGib: baseTip });
218
+ const baseBranchAddrs = baseBranch.map(x => getIbGibAddr({ ibGib: x }));
219
+ const orphanTipAddr = getIbGibAddr({ ibGib: orphanTip });
220
+ const orphanBranchAddrs = orphanBranch.map(x => getIbGibAddr({ ibGib: x }));
221
+ if (logalot) {
222
+ console.log(`${lc} baseBranchAddrs:\n${baseBranchAddrs.join('\n')}\n(I: 2cad420d7bc822f798b8a8785f1f8c26)`);
223
+ }
224
+ if (logalot) {
225
+ console.log(`${lc} orphanBranchAddrs:\n${orphanBranchAddrs.join('\n')}\n(I: cc86489d6737e2aced42b585cba13526)`);
226
+ }
227
+ // 3. Replay orphan branch transforms onto base tip
228
+ const [latestCommonFrameIbGib] = await getIbGibsFromCache_fallbackToSpaces({
229
+ addrs: [latestCommonFrameAddr],
230
+ space,
231
+ });
232
+ // It is non-trivial and not at all obvious, but the following approach is WRONG!!
233
+ //
234
+ // This is not a generic timeline, rather, this is a timeline that
235
+ // is restricted to a b2tfs node, which itself has two
236
+ // possibilities: file or folder. So we can't replay dna blindly
237
+ // between the two branches and then try to do some kind of text
238
+ // merge later. We must analyze each branch and decide how to handle
239
+ // each change.
240
+ //
241
+ // NOTE: I have tweaked canGraft to only return true on
242
+ // B2tFSType.file and not folders, to see if the dna replay is good
243
+ // enough for folders, so we can concentrate on just files. Keep
244
+ // that in mind when I discuss the following notes.
245
+ //
246
+ // what we know at this point:
247
+ // * graft was invoked, so the sync engine detected divergence in
248
+ // the two spaces, i.e., our two branches (branch-per-space)
249
+ // * IOW, this is NOT a FF merge. That would have already been
250
+ // applied and not triggered this graft.
251
+ // * This is either a file or a folder b2tfs item.
252
+ // * If it is a folder...
253
+ // * How does git handle two folders merging, or does it?
254
+ // * git is file-based, and handles folders only secondarily.
255
+ // * How does our current vcs-gib diffing engine even detect if a
256
+ // folder has moved? does it?
257
+ // * If it is a file...
258
+ // * Is there anything that can happen besides the related binary file changing?
259
+ // * If there are multiple changes to the binary file, should we
260
+ // do each of those file changes in the graft?
261
+ // * we need to game out multiple scenarios to answer this.
262
+ // * What about multiple changes to each branch? Do we squash
263
+ // the orphan to a single change and then merge the final?
264
+ // * It is possible we can even parameterize this in this
265
+ // strategy object, but the caller would need to configure
266
+ // this strategy ahead of each sync call if that is the case I
267
+ // think.
268
+ // * One thing to parameterize would be how to handle graft
269
+ // points, as I just realized in the context of version
270
+ // control systems, it is possible that we may want to
271
+ // configure the sync/merge to drop/do something with large
272
+ // binaries (or just files in general) in a specific way.
273
+ // const dnaAddrsAlreadyAccountedFor: IbGibAddr[] = (latestCommonFrameIbGib?.rel8ns?.dna ?? []).concat();
274
+ // const dnaAddrsToApply: IbGibAddr[] = [];
275
+ // for (const orphanFrame of orphanBranch) {
276
+ // if (!orphanFrame.rel8ns) { throw new Error(`(UNEXPECTED) orphanFrame.rel8ns falsy? (E: bc9a78ef8dbcd9748305d898bf1b2826)`); }
277
+ // // I don't know if this is expected or not, but seems like if
278
+ // // we're doing a merge, we are expecting the ibgib frames to
279
+ // // have dna
280
+ // if (!orphanFrame.rel8ns.dna || orphanFrame.rel8ns.dna.length === 0) {
281
+ // throw new Error(`(UNEXPECTED) !orphanFrame.rel8ns.dna || orphanFrame.rel8ns.dna.length === 0? How can we be grafting when the orphan slice has no dna? (E: 7e58797aa2f98dfa811e8fa88c693826)`);
282
+ // }
283
+ // const orphanDnaAddrsToApply = getUniqueDnas({
284
+ // base: dnaAddrsAlreadyAccountedFor,
285
+ // extended: orphanFrame.rel8ns.dna,
286
+ // throwIfExtendedDoesntContainBase: true,
287
+ // });
288
+ // orphanDnaAddrsToApply.forEach(x => dnaAddrsAlreadyAccountedFor.push(x));
289
+ // orphanDnaAddrsToApply.forEach(x => dnaAddrsToApply.push(x));
290
+ // }
291
+ // const dnaIbGibsToApply = await getIbGibsFromCache_fallbackToSpaces({
292
+ // addrs: dnaAddrsToApply,
293
+ // readCache_graph: ibGibReadCache,
294
+ // space,
295
+ // });
296
+ // if (logalot) { console.log(`${lc}${mergeDiag} dnaAddrsToApply addrs (${dnaAddrsToApply.length}): ${dnaAddrsToApply} (I: 78a8a82f540d520682664aa806f1b826)`); }
297
+ // const createdIbGibs_Running: IbGib_V1[] = [];
298
+ // const newGraftedIntermediateIbGibs_ordered: IbGib_V1[] = [];
299
+ // const newGraftDnaIbGibs: IbGib_V1[] = [];
300
+ // let currentGraftTip = await applyTransforms({
301
+ // src: baseTip,
302
+ // dnaAddrsToApplyToStoreVersion_MUTATES_IN_PLACE: dnaAddrsToApply.concat(),
303
+ // allLocalIbGibs: dnaIbGibsToApply,
304
+ // createdIbGibs_Running,
305
+ // });
306
+ // if (createdIbGibs_Running.length > 0) {
307
+ // await putInSpace({ space, ibGibs: createdIbGibs_Running });
308
+ // const { mapWithTjp_YesDna: newGraftedIbGibsMap } = splitPerTjpAndOrDna({ ibGibs: createdIbGibs_Running });
309
+ // const newGraftedIbGibs_orderNotGuaranteed = Object.values(newGraftedIbGibsMap);
310
+ // const newGraftedIbGibsByTjp = getTimelinesGroupedByTjp({ ibGibs: newGraftedIbGibs_orderNotGuaranteed });
311
+ // if (Object.keys(newGraftedIbGibsByTjp).length > 0) {
312
+ // Object.values(newGraftedIbGibsByTjp)[0].forEach(x => newGraftedIntermediateIbGibs_ordered.push(x));
313
+ // for (const item of newGraftedIntermediateIbGibs_ordered) {
314
+ // await registerNewIbGib({ ibGib: item, space });
315
+ // }
316
+ // }
317
+ // }
318
+ // 4. Perform 3-way filesystem tree merge across lcaItem, baseItem, orphanItem
319
+ const lcaNode = await this.fetchIbGib({ addr: latestCommonFrameAddr, space, readCache_graph: ibGibReadCache });
320
+ if (!lcaNode) {
321
+ throw new Error(`(UNEXPECTED) lcaNode falsy? (E: a8b2d80dc4f8ba1448fa280d89dfb626)`);
322
+ }
323
+ const lcaItem = await this.resolveRootItemNode({ nodeOrAddr: lcaNode, space, readCache_graph: ibGibReadCache });
324
+ if (!lcaItem) {
325
+ throw new Error(`(UNEXPECTED) lcaItem falsy? (E: 0944f88dde58cbabf82342b814955826)`);
326
+ }
327
+ const baseItem = await this.resolveRootItemNode({ nodeOrAddr: baseTip, space, readCache_graph: ibGibReadCache });
328
+ if (!baseItem) {
329
+ throw new Error(`(UNEXPECTED) baseItem falsy? (E: fac3087884cbebc7083e580514002826)`);
330
+ }
331
+ const orphanItem = await this.resolveRootItemNode({ nodeOrAddr: orphanTip, space, readCache_graph: ibGibReadCache });
332
+ if (!orphanItem) {
333
+ throw new Error(`(UNEXPECTED) orphanItem falsy? (E: 8e7e383753a8814f283280ee82156826)`);
334
+ }
335
+ if (lcaItem.data.fsType !== baseItem.data.fsType) {
336
+ throw new Error(`(UNEXPECTED) lcaItem.data.fsType !== baseItem.data.fsType? (E: 794608f3e678a399ed670388629a6826)`);
337
+ }
338
+ if (lcaItem.data.fsType !== orphanItem.data.fsType) {
339
+ throw new Error(`(UNEXPECTED) lcaItem.data.fsType !== orphanItem.data.fsType? (E: 2813981c8c422b41f85a02fd8aa88226)`);
340
+ }
341
+ // all three fsTypes are equal
342
+ const fsType = lcaItem.data.fsType;
343
+ if (fsType === B2tFSType.folder) {
344
+ throw new Error(`(UNEXPECTED) fsType === B2tFSType.folder? I have tweaked the canGraft so we should only be handling files atow (08/11/2026) (E: b282b8f77b18575378edb902bd80a826)`);
345
+ }
346
+ if (fsType !== B2tFSType.file) {
347
+ throw new Error(`(UNEXPECTED) fsType (${fsType}) is not a file? (E: 272418fe2067ea3e16dac028e86d1a26)`);
348
+ }
349
+ const lcaPayload = await this.getFilePayloadBuffer({
350
+ fileItem: lcaItem, space, readCache_graph: ibGibReadCache
351
+ });
352
+ if (lcaPayload === undefined) {
353
+ if (logalot) {
354
+ console.log(`${lc}${mergeDiag} lcaPayload undefined? (I: 59b25835cce856cea883cf989ceb3826)`);
355
+ }
356
+ }
357
+ const basePayload = await this.getFilePayloadBuffer({
358
+ fileItem: baseItem, space, readCache_graph: ibGibReadCache
359
+ });
360
+ if (basePayload === undefined) {
361
+ if (logalot) {
362
+ console.log(`${lc}${mergeDiag} basePayload undefined? (I: 54f05406dca85eb98821b79f7325c826)`);
363
+ }
364
+ }
365
+ const orphanPayload = await this.getFilePayloadBuffer({
366
+ fileItem: orphanItem, space, readCache_graph: ibGibReadCache
367
+ });
368
+ if (orphanPayload === undefined) {
369
+ if (logalot) {
370
+ console.log(`${lc}${mergeDiag} orphanPayload undefined? (I: cd8b785875b43fc6684c65d818edd826)`);
371
+ }
372
+ }
373
+ const isBaseBin = basePayload ? isBinaryBuffer(basePayload.buffer) : false;
374
+ const isOrphanBin = orphanPayload ? isBinaryBuffer(orphanPayload.buffer) : false;
375
+ const isLcaBin = lcaPayload ? isBinaryBuffer(lcaPayload.buffer) : false;
376
+ if (isBaseBin || isOrphanBin || isLcaBin) {
377
+ if (logalot) {
378
+ console.log(`${lc} Non-text binary file detected (${baseItem.data?.name}). Skipping 3-way line diff. (I: 4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b)`);
379
+ }
380
+ // even though we've gotten this far into this `graft` method,
381
+ // we can still return `undefined` early if we decide we can't
382
+ // handle it and we haven't persisted/registered any ibgibs. In
383
+ // this particular case of 3-way text merges, we don't graft
384
+ // non-text binary divergences, e.g., pics, sound files, etc.
385
+ return undefined; /* <<<< returns early */
386
+ }
387
+ if (!lcaPayload) {
388
+ throw new Error(`(UNEXPECTED) lcaPayload falsy? By this point in code, we have guaranteed that we are dealing with a text payload. (E: 0b82892204482f5538a430b8915b7826)`);
389
+ }
390
+ if (!basePayload) {
391
+ throw new Error(`(UNEXPECTED) basePayload falsy? By this point in code, we have guaranteed that we are dealing with a text payload. (E: af1f68a020280b3a5d6ed4a812acd426)`);
392
+ }
393
+ if (!orphanPayload) {
394
+ throw new Error(`(UNEXPECTED) orphanPayload falsy? By this point in code, we have guaranteed that we are dealing with a text payload. (E: 6a521b684763862c3a2e0ca315d62826)`);
395
+ }
396
+ const textLCA = decodeToLines(lcaPayload.buffer).join('\n');
397
+ const textBase = decodeToLines(basePayload.buffer).join('\n');
398
+ const textOrphan = decodeToLines(orphanPayload.buffer).join('\n');
399
+ console.log(`${lc}${mergeDiag} file: ${baseItem.data.name}`);
400
+ console.log(`${lc}${mergeDiag} textLCA:\n${textLCA}`);
401
+ console.log(`${lc}${mergeDiag} textBase:\n${textBase}`);
402
+ console.log(`${lc}${mergeDiag} textOrphan:\n${textOrphan}`);
403
+ const { mergedText } = perform3WayTextLineMerge({ textLCA, textBase, textOrphan });
404
+ console.log(`${lc}${mergeDiag} mergedText:\n${mergedText}`);
405
+ const dataBuffer = Buffer.from(mergedText, 'utf8');
406
+ const fileHash = await hash({ s: mergedText });
407
+ if (baseItem.data.fileExt !== orphanItem.data.fileExt) {
408
+ console.warn(`${lc} baseItem.data.fileExt (${baseItem.data.fileExt}) !== orphanItem.data.fileExt (${orphanItem.data.fileExt})? Using baseItem.data.fileExt for merged fileExt (W: a999b54235bb231fa49224842e212326)`);
409
+ }
410
+ const fileExt = baseItem.data.fileExt;
411
+ const binIb = getBinIb({
412
+ binHash: fileHash,
413
+ binExt: fileExt,
414
+ binEncoding: 'utf8',
415
+ });
416
+ const binIbGib = {
417
+ ib: binIb,
418
+ data: dataBuffer,
419
+ };
420
+ binIbGib.gib = await getGib({ ibGib: binIbGib, hasTjp: false });
421
+ const binAddr = getIbGibAddr({ ibGib: binIbGib });
422
+ // at this point, we are committed to performing the 3-way merge.
423
+ await putInSpace({ ibGib: binIbGib, space });
424
+ await registerNewIbGib({ ibGib: binIbGib, space });
425
+ const fnGetN = (item) => {
426
+ if (item.data.n || item.data.n === 0) {
427
+ return item.data.n;
428
+ }
429
+ else {
430
+ throw new Error(`(UNEXPECTED) item.data.n not a number? (E: 896ceae089c83ca67817fff826be5826)`);
431
+ }
432
+ };
433
+ const baseItemDataN = fnGetN(baseItem);
434
+ const orphanItemDataN = fnGetN(orphanItem);
435
+ const lowestDataN = baseItemDataN <= orphanItemDataN ?
436
+ baseItemDataN :
437
+ orphanItemDataN;
438
+ const evolveRes = await evolveB2tFSItemIbGib({
439
+ existingItem: baseItem,
440
+ dataToUpdate: {
441
+ fileHash,
442
+ n: lowestDataN + 1,
443
+ },
444
+ rel8nsToUpdate: {
445
+ [BINARY_REL8N_NAME]: [binAddr],
446
+ },
447
+ });
448
+ // sanity checks
449
+ if (!evolveRes.dnas) {
450
+ throw new Error(`(UNEXPECTED) evolveRes.dnas falsy? We should be using dna when working with B2tFS items. (E: e640e892cc76c77f98f3881301035826)`);
451
+ }
452
+ if (!evolveRes.newIbGib) {
453
+ throw new Error(`(UNEXPECTED) evolveRes.newIbGib falsy? we just did the merge, so this should be truthy. (E: 9e488d07772827b66a2aff4801905426)`);
454
+ }
455
+ const newItemWithNewBinPayload = evolveRes.newIbGib;
456
+ const newItemAddr = getIbGibAddr({ ibGib: newItemWithNewBinPayload });
457
+ if (logalot) {
458
+ console.log(`${lc} newItemAddr: ${newItemAddr} (I: d23eef651b88be1248ee29ca179eff26)`);
459
+ }
460
+ const newGraftDnaIbGibs = [];
461
+ const newGraftedIntermediateIbGibs_ordered = [];
462
+ newGraftDnaIbGibs.push(...evolveRes.dnas);
463
+ if (evolveRes.intermediateIbGibs) {
464
+ // todo: when we have this completed, we should know whether or not there are intermediate ibgibs in all cases, some cases, or no cases (never). we should change this from an `if` block with no else to throw an unexpected error (assertion) if it is indeed unexpected
465
+ evolveRes.intermediateIbGibs.forEach(x => newGraftedIntermediateIbGibs_ordered.push(x));
466
+ }
467
+ await persistTransformResult({ resTransform: evolveRes, space });
468
+ await registerNewIbGib({ ibGib: evolveRes.newIbGib, space });
469
+ const baseItemAddr = getIbGibAddr({ ibGib: baseItem });
470
+ const mergedRootAddr = getIbGibAddr({ ibGib: newItemWithNewBinPayload });
471
+ const currentRootAddr = baseItem ? getIbGibAddr({ ibGib: baseItem }) : undefined;
472
+ /**
473
+ * stupid word "details" is plural and I have this set to be an
474
+ * array. don't have the ability to refactor right now, so this will
475
+ * be mildly confusing unfortunately. Agents should not try to just
476
+ * refactor this on the fly.
477
+ */
478
+ const b2tfsAddlGraftDetails = {
479
+ baseTextB2tFSItemAddr: baseTipAddr,
480
+ baseTextBinAddr: basePayload.binIbGib ? getIbGibAddr({ ibGib: basePayload.binIbGib }) : undefined,
481
+ orphanTextB2tFSItemAddr: orphanTipAddr,
482
+ orphanTextBinAddr: orphanPayload.binIbGib ? getIbGibAddr({ ibGib: orphanPayload.binIbGib }) : undefined,
483
+ };
484
+ // 6. Attach GraftInfo frame
485
+ const graftInfo = await createGraftInfo({
486
+ conflictStrategy,
487
+ details: `Merged orphan tip text with the baseTip as a starting point.`,
488
+ addlGraftDetails: [b2tfsAddlGraftDetails],
489
+ latestCommonFrameAddr,
490
+ baseAddrsSinceLCA: baseBranchAddrs,
491
+ orphanAddrsSinceLCA: orphanBranchAddrs,
492
+ dnaAddrsApplied: [],
493
+ });
494
+ await putInSpace({ ibGib: graftInfo, space });
495
+ await registerNewIbGib({ ibGib: graftInfo, space });
496
+ const graftInfoAddr = getIbGibAddr({ ibGib: graftInfo });
497
+ const resRel8GraftInfo = await rel8({
498
+ src: newItemWithNewBinPayload,
499
+ rel8nsToAddByAddr: {
500
+ [GRAFT_INFO_REL8N_NAME]: [graftInfoAddr],
501
+ },
502
+ dna: true,
503
+ nCounter: true,
504
+ });
505
+ if (!resRel8GraftInfo.dnas) {
506
+ throw new Error(`(UNEXPECTED) resRel8GraftInfo.dnas falsy? (E: f3f4a83d3a08bd8de84250c389aed826)`);
507
+ }
508
+ const finalGraftTip = resRel8GraftInfo.newIbGib;
509
+ const finalGraftTipAddr = getIbGibAddr({ ibGib: finalGraftTip });
510
+ if (logalot) {
511
+ console.log(`${lc} finalGraftTipAddr: ${finalGraftTipAddr} (I: 583ac81fb0a84827b85c3076ffeeaf26)`);
512
+ }
513
+ newGraftedIntermediateIbGibs_ordered.push(newItemWithNewBinPayload);
514
+ for (const dna of resRel8GraftInfo.dnas) {
515
+ newGraftDnaIbGibs.push(dna);
516
+ }
517
+ await persistTransformResult({ resTransform: resRel8GraftInfo, space });
518
+ await registerNewIbGib({ ibGib: finalGraftTip, space });
519
+ return {
520
+ dnasReplayed: [],
521
+ dnasCreatedInGraft: newGraftDnaIbGibs,
522
+ intermediateIbGibsCreatedInGraft: newGraftedIntermediateIbGibs_ordered,
523
+ ancillaryIbGibsCreated: [binIbGib],
524
+ newGraftTip: finalGraftTip,
525
+ graftInfoCreated: graftInfo,
526
+ };
527
+ }
528
+ catch (error) {
529
+ console.error(`${lc} ${extractErrorMsg(error)} (E: 7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e)`);
530
+ throw error;
531
+ }
532
+ finally {
533
+ if (logalot) {
534
+ console.log(`${lc} complete. (I: 6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f)`);
535
+ }
536
+ }
537
+ }
538
+ async fetchIbGib({ addr, space, readCache_graph, }) {
539
+ if (!addr) {
540
+ return undefined;
541
+ }
542
+ const cleanAddr = addr.includes('^') ? addr.split('^')[0] : addr;
543
+ if (readCache_graph) {
544
+ if (readCache_graph[cleanAddr]) {
545
+ return readCache_graph[cleanAddr];
546
+ }
547
+ if (readCache_graph[addr]) {
548
+ return readCache_graph[addr];
549
+ }
550
+ const matchingKey = Object.keys(readCache_graph).find(k => k === cleanAddr || k.startsWith(cleanAddr + '^') || (k.includes('^') && k.split('^')[0] === cleanAddr));
551
+ if (matchingKey) {
552
+ return readCache_graph[matchingKey];
553
+ }
554
+ }
555
+ try {
556
+ const res = await getFromSpace({ space, addrs: [addr, cleanAddr] });
557
+ if (res && res.success && res.ibGibs && res.ibGibs.length > 0) {
558
+ const found = res.ibGibs.find((x) => !!x);
559
+ if (found) {
560
+ return found;
561
+ }
562
+ }
563
+ }
564
+ catch {
565
+ // Suppress fetch error if address not found
566
+ // why suppress? any ibgibs available to us here should be in space
567
+ // (the temp space of the sync receiver)
568
+ }
569
+ return undefined;
570
+ }
571
+ async resolveRootItemNode({ nodeOrAddr, space, readCache_graph, }) {
572
+ if (!nodeOrAddr) {
573
+ throw new Error(`(UNEXPECTED) nodeOrAddr falsy? (E: 524108327b9caa00586207ea399f7226)`);
574
+ }
575
+ let node;
576
+ if (typeof nodeOrAddr === 'string') {
577
+ node = await this.fetchIbGib({ addr: nodeOrAddr, space, readCache_graph });
578
+ }
579
+ else {
580
+ node = nodeOrAddr;
581
+ }
582
+ if (!node) {
583
+ throw new Error(`(UNEXPECTED) node falsy? couldn't get node? (E: bd7d1c3b4a3881ff882746281869d826)`);
584
+ }
585
+ if (isB2tFSItemIbGib(node)) {
586
+ // it's an item ibgib
587
+ return node;
588
+ }
589
+ else {
590
+ // not an item ibgib
591
+ throw new Error(`(UNEXPECTED) node is not a B2tFSItemIbGib_V1? canGraft should have returned false then and we should never have gotten here. (E: ddabb281ccb2fb1a181109a82046b826)`);
592
+ }
593
+ }
594
+ async getFilePayloadBuffer({ fileItem, space, readCache_graph, }) {
595
+ if (!fileItem || !fileItem.rel8ns) {
596
+ return undefined;
597
+ }
598
+ const binAddrs = fileItem.rel8ns[BINARY_REL8N_NAME] || [];
599
+ const latestBinAddr = binAddrs.at(-1);
600
+ if (!latestBinAddr) {
601
+ return undefined;
602
+ }
603
+ const binIbGib = await this.fetchIbGib({ addr: latestBinAddr, space, readCache_graph });
604
+ if (!binIbGib) {
605
+ throw new Error(`(UNEXPECTED) couldn't fetch binIbGib? latestBinAddr: ${latestBinAddr}. space.ib: ${space.ib} (E: 3d1238b3a348924038a79f88264d8226)`);
606
+ }
607
+ if (binIbGib.data === undefined) {
608
+ return undefined;
609
+ } // what if it's an empty file. will data be undefined? do we handle this at the b2tfs item level for fsType === 'file'?
610
+ let fileData;
611
+ const dataObj = binIbGib.data;
612
+ if (dataObj && typeof dataObj === 'object' && dataObj._dataType === 'Uint8Array_Base64' && typeof dataObj.value === 'string') {
613
+ fileData = Buffer.from(dataObj.value, 'base64');
614
+ }
615
+ else if (typeof dataObj === 'string') {
616
+ fileData = Buffer.from(dataObj, 'utf8');
617
+ }
618
+ else if (dataObj instanceof Uint8Array || Buffer.isBuffer(dataObj)) {
619
+ fileData = dataObj;
620
+ }
621
+ else if (typeof dataObj === 'object' && dataObj !== null) {
622
+ if (typeof dataObj.text === 'string') {
623
+ fileData = Buffer.from(dataObj.text, 'utf8');
624
+ }
625
+ else if (typeof dataObj.data === 'string') {
626
+ fileData = Buffer.from(dataObj.data, 'utf8');
627
+ }
628
+ else {
629
+ const vals = Object.values(dataObj);
630
+ fileData = new Uint8Array(vals);
631
+ }
632
+ }
633
+ else {
634
+ fileData = new Uint8Array(0);
635
+ }
636
+ return { buffer: fileData, binIbGib };
637
+ }
638
+ async getChildItemsMap({ folderItem, space, readCache_graph, }) {
639
+ const map = new Map();
640
+ if (!folderItem || !folderItem.rel8ns) {
641
+ return map;
642
+ }
643
+ const childAddrs = folderItem.rel8ns[B2TFS_CHILD_ITEM_REL8N_NAME] || [];
644
+ for (const addr of childAddrs) {
645
+ const childNode = await this.fetchIbGib({ addr, space, readCache_graph });
646
+ if (childNode && childNode.data?.name) {
647
+ map.set(childNode.data.name, childNode);
648
+ }
649
+ }
650
+ return map;
651
+ }
652
+ async mergeTreeNodes({ lcaItem, baseItem, orphanItem, space, readCache_graph, newGraftDnaIbGibs, newGraftedIntermediateIbGibs_ordered, }) {
653
+ const lc = `${lcFile}[${this.mergeTreeNodes.name}]`;
654
+ const baseAddr = baseItem ? getIbGibAddr({ ibGib: baseItem }) : undefined;
655
+ const orphanAddr = orphanItem ? getIbGibAddr({ ibGib: orphanItem }) : undefined;
656
+ const lcaAddr = lcaItem ? getIbGibAddr({ ibGib: lcaItem }) : undefined;
657
+ if (baseAddr && orphanAddr && baseAddr === orphanAddr) {
658
+ return baseItem;
659
+ }
660
+ if (lcaAddr && baseAddr && baseAddr === lcaAddr && orphanItem) {
661
+ return orphanItem;
662
+ }
663
+ if (lcaAddr && orphanAddr && orphanAddr === lcaAddr && baseItem) {
664
+ return baseItem;
665
+ }
666
+ if (!baseItem && !orphanItem) {
667
+ return undefined;
668
+ }
669
+ if (baseItem && !orphanItem) {
670
+ if (lcaAddr && baseAddr === lcaAddr) {
671
+ return undefined;
672
+ }
673
+ return baseItem;
674
+ }
675
+ if (orphanItem && !baseItem) {
676
+ if (lcaAddr && orphanAddr === lcaAddr) {
677
+ return undefined;
678
+ }
679
+ return orphanItem;
680
+ }
681
+ if (!baseItem || !orphanItem) {
682
+ throw new Error(`(UNEXPECTED) baseItem or orphanItem missing in 3-way merge branch (E: 5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a)`);
683
+ }
684
+ const fsType = baseItem.data?.fsType || orphanItem.data?.fsType;
685
+ if (fsType === 'file') {
686
+ }
687
+ else if (fsType === 'folder') {
688
+ // const lcaChildrenMap = await this.getChildItemsMap({ folderItem: lcaItem, space, readCache_graph });
689
+ // const baseChildrenMap = await this.getChildItemsMap({ folderItem: baseItem, space, readCache_graph });
690
+ // const orphanChildrenMap = await this.getChildItemsMap({ folderItem: orphanItem, space, readCache_graph });
691
+ // const allChildAddrs = new Set([
692
+ // ...lcaChildrenMap.keys(),
693
+ // ...baseChildrenMap.keys(),
694
+ // ...orphanChildrenMap.keys(),
695
+ // ]);
696
+ // const mergedChildAddrs: string[] = [];
697
+ // for (const childItemAddr of allChildAddrs) {
698
+ // const childLCA = lcaChildrenMap.get(childItemAddr);
699
+ // const childBase = baseChildrenMap.get(childItemAddr);
700
+ // const childOrphan = orphanChildrenMap.get(childItemAddr);
701
+ // const mergedChild = await this.mergeTreeNodes({
702
+ // lcaItem: childLCA,
703
+ // baseItem: childBase,
704
+ // orphanItem: childOrphan,
705
+ // space,
706
+ // readCache_graph,
707
+ // newGraftDnaIbGibs,
708
+ // newGraftedIntermediateIbGibs_ordered,
709
+ // });
710
+ // if (mergedChild) {
711
+ // mergedChildAddrs.push(getIbGibAddr({ ibGib: mergedChild }));
712
+ // }
713
+ // }
714
+ // const currentChildAddrs = baseItem.rel8ns?.[B2TFS_CHILD_ITEM_REL8N_NAME] || [];
715
+ // const addrsChanged = mergedChildAddrs.length !== currentChildAddrs.length ||
716
+ // mergedChildAddrs.some((addr, idx) => addr !== currentChildAddrs[idx]);
717
+ // if (!addrsChanged) {
718
+ // return baseItem;
719
+ // }
720
+ // const evolveRes = await evolveB2tFSItemIbGib({
721
+ // existingItem: baseItem,
722
+ // rel8nsToUpdate: {
723
+ // [B2TFS_CHILD_ITEM_REL8N_NAME]: mergedChildAddrs,
724
+ // },
725
+ // rel8nsToRemove: {
726
+ // [B2TFS_CHILD_ITEM_REL8N_NAME]: baseItem.rel8ns?.[B2TFS_CHILD_ITEM_REL8N_NAME] || [],
727
+ // },
728
+ // });
729
+ // if (evolveRes.dnas) { newGraftDnaIbGibs.push(...evolveRes.dnas); }
730
+ // if (evolveRes.newIbGib) { newGraftedIntermediateIbGibs_ordered.push(evolveRes.newIbGib); }
731
+ // if (space) {
732
+ // await persistTransformResult({ resTransform: evolveRes, space });
733
+ // await registerNewIbGib({ ibGib: evolveRes.newIbGib, space });
734
+ // }
735
+ // return evolveRes.newIbGib as B2tFSItemIbGib_V1;
736
+ }
737
+ return baseItem;
738
+ }
739
+ }
740
+ export const B2tFSItem3WayMergeStrategy = B2tFS3WayGraftStrategy;
741
+ //# sourceMappingURL=b2tfs-3way-merge-strategy.mjs.map