@ibgib/vcs-gib 0.0.18 → 0.0.21

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