@ibgib/vcs-gib 0.0.33 → 0.0.36

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.
@@ -27,95 +27,95 @@ const lc = `[apps/vcs-gib/src/cli/commands/branch-checkout-cmd.respec.mts]`;
27
27
 
28
28
  await respecfully(lc, `vcs branch, checkout, and merge Command Handlers`, async () => {
29
29
 
30
- // await ifWe(lc, `lists default branch main for new repository`, async () => {
31
- // const testDir = path.join(process.cwd(), '.test_branch_checkout_1');
32
- // const vcsFolderName = '.vcsgib_test_bc_1';
33
- // try {
34
- // await executeInitCmd({
35
- // targetDir: testDir,
36
- // vcsFolderName,
37
- // quiet: true,
38
- // });
39
-
40
- // const branchRes = await executeBranchCmd({
41
- // targetDir: testDir,
42
- // vcsFolderName,
43
- // quiet: true,
44
- // });
45
-
46
- // iReckon(lc, branchRes.branches.length).willEqual(1);
47
- // iReckon(lc, branchRes.branches[0].name).willEqual('main');
48
- // iReckon(lc, branchRes.branches[0].isActive).isGonnaBeTrue();
49
- // } finally {
50
- // await fs.rm(testDir, { recursive: true, force: true });
51
- // }
52
- // });
53
-
54
- // await ifWe(lc, `creates new branch from active branch root item and rejects duplicates`, async () => {
55
- // const testDir = path.join(process.cwd(), '.test_branch_checkout_2');
56
- // const vcsFolderName = '.vcsgib_test_bc_2';
57
- // try {
58
- // await executeInitCmd({
59
- // targetDir: testDir,
60
- // vcsFolderName,
61
- // quiet: true,
62
- // });
63
-
64
- // // Create feature branch
65
- // debugger; // walk through branch exec
66
- // const createRes = await executeBranchCmd({
67
- // branchName: 'feature-auth',
68
- // targetDir: testDir,
69
- // vcsFolderName,
70
- // quiet: true,
71
- // });
72
-
73
- // iReckon(lc, createRes.createdBranchName).willEqual('feature-auth');
74
- // iReckon(lc, Boolean(createRes.createdBranchAddr)).isGonnaBeTrue();
75
-
76
- // // List branches
77
- // const listRes = await executeBranchCmd({
78
- // targetDir: testDir,
79
- // vcsFolderName,
80
- // quiet: true,
81
- // });
82
- // console.dir(listRes)
83
-
84
- // iReckon(lc, listRes.branches.length).willEqual(2);
85
- // const featureBranch = listRes.branches.find(b => b.name === 'feature-auth');
86
- // iReckon(lc, Boolean(featureBranch)).isGonnaBeTrue();
87
- // iReckon(lc, featureBranch?.isActive).isGonnaBeFalse();
88
-
89
- // // Verify dedicated branch space subfolders exist in .vcsgib
90
- // const mainSpaceDir = path.join(testDir, vcsFolderName, 'ibgib', 'b2s_main');
91
- // const featureSpaceDir = path.join(testDir, vcsFolderName, 'ibgib', 'b2s_feature-auth');
92
- // const mainSpaceExists = await fs.stat(mainSpaceDir).then(s => s.isDirectory()).catch(() =>
93
- // fs.stat(path.join(testDir, vcsFolderName, 'b2s_main')).then(s => s.isDirectory()).catch(() => false)
94
- // );
95
- // const featureSpaceExists = await fs.stat(featureSpaceDir).then(s => s.isDirectory()).catch(() =>
96
- // fs.stat(path.join(testDir, vcsFolderName, 'b2s_feature-auth')).then(s => s.isDirectory()).catch(() => false)
97
- // );
98
- // iReckon(lc, mainSpaceExists).isGonnaBeTrue();
99
- // iReckon(lc, featureSpaceExists).isGonnaBeTrue();
100
-
101
- // // Duplicate branch attempt
102
- // let errorThrown = false;
103
- // try {
104
- // await executeBranchCmd({
105
- // branchName: 'feature-auth',
106
- // targetDir: testDir,
107
- // vcsFolderName,
108
- // quiet: true,
109
- // });
110
- // } catch (err: any) {
111
- // errorThrown = true;
112
- // iReckon(lc, err.message).includes("already exists");
113
- // }
114
- // iReckon(lc, errorThrown).isGonnaBeTrue();
115
- // } finally {
116
- // await fs.rm(testDir, { recursive: true, force: true });
117
- // }
118
- // });
30
+ await ifWe(lc, `lists default branch main for new repository`, async () => {
31
+ const testDir = path.join(process.cwd(), '.test_branch_checkout_1');
32
+ const vcsFolderName = '.vcsgib_test_bc_1';
33
+ try {
34
+ await executeInitCmd({
35
+ targetDir: testDir,
36
+ vcsFolderName,
37
+ quiet: true,
38
+ });
39
+
40
+ const branchRes = await executeBranchCmd({
41
+ targetDir: testDir,
42
+ vcsFolderName,
43
+ quiet: true,
44
+ });
45
+
46
+ iReckon(lc, branchRes.branches.length).willEqual(1);
47
+ iReckon(lc, branchRes.branches[0].name).willEqual('main');
48
+ iReckon(lc, branchRes.branches[0].isActive).isGonnaBeTrue();
49
+ } finally {
50
+ await fs.rm(testDir, { recursive: true, force: true });
51
+ }
52
+ });
53
+
54
+ await ifWe(lc, `creates new branch from active branch root item and rejects duplicates`, async () => {
55
+ const testDir = path.join(process.cwd(), '.test_branch_checkout_2');
56
+ const vcsFolderName = '.vcsgib_test_bc_2';
57
+ try {
58
+ await executeInitCmd({
59
+ targetDir: testDir,
60
+ vcsFolderName,
61
+ quiet: true,
62
+ });
63
+
64
+ // Create feature branch
65
+ debugger; // walk through branch exec
66
+ const createRes = await executeBranchCmd({
67
+ branchName: 'feature-auth',
68
+ targetDir: testDir,
69
+ vcsFolderName,
70
+ quiet: true,
71
+ });
72
+
73
+ iReckon(lc, createRes.createdBranchName).willEqual('feature-auth');
74
+ iReckon(lc, Boolean(createRes.createdBranchAddr)).isGonnaBeTrue();
75
+
76
+ // List branches
77
+ const listRes = await executeBranchCmd({
78
+ targetDir: testDir,
79
+ vcsFolderName,
80
+ quiet: true,
81
+ });
82
+ console.dir(listRes)
83
+
84
+ iReckon(lc, listRes.branches.length).willEqual(2);
85
+ const featureBranch = listRes.branches.find(b => b.name === 'feature-auth');
86
+ iReckon(lc, Boolean(featureBranch)).isGonnaBeTrue();
87
+ iReckon(lc, featureBranch?.isActive).isGonnaBeFalse();
88
+
89
+ // Verify dedicated branch space subfolders exist in .vcsgib
90
+ const mainSpaceDir = path.join(testDir, vcsFolderName, 'ibgib', 'b2s_main');
91
+ const featureSpaceDir = path.join(testDir, vcsFolderName, 'ibgib', 'b2s_feature-auth');
92
+ const mainSpaceExists = await fs.stat(mainSpaceDir).then(s => s.isDirectory()).catch(() =>
93
+ fs.stat(path.join(testDir, vcsFolderName, 'b2s_main')).then(s => s.isDirectory()).catch(() => false)
94
+ );
95
+ const featureSpaceExists = await fs.stat(featureSpaceDir).then(s => s.isDirectory()).catch(() =>
96
+ fs.stat(path.join(testDir, vcsFolderName, 'b2s_feature-auth')).then(s => s.isDirectory()).catch(() => false)
97
+ );
98
+ iReckon(lc, mainSpaceExists).isGonnaBeTrue();
99
+ iReckon(lc, featureSpaceExists).isGonnaBeTrue();
100
+
101
+ // Duplicate branch attempt
102
+ let errorThrown = false;
103
+ try {
104
+ await executeBranchCmd({
105
+ branchName: 'feature-auth',
106
+ targetDir: testDir,
107
+ vcsFolderName,
108
+ quiet: true,
109
+ });
110
+ } catch (err: any) {
111
+ errorThrown = true;
112
+ iReckon(lc, err.message).includes("already exists");
113
+ }
114
+ iReckon(lc, errorThrown).isGonnaBeTrue();
115
+ } finally {
116
+ await fs.rm(testDir, { recursive: true, force: true });
117
+ }
118
+ });
119
119
 
120
120
  await ifWe(lc, `switches active branch with checkout and projects branch snapshot onto worktree subfolder`, async () => {
121
121
  const testDir = path.join(process.cwd(), '.test_branch_checkout_3');
@@ -254,320 +254,320 @@ await respecfully(lc, `vcs branch, checkout, and merge Command Handlers`, async
254
254
  }
255
255
  });
256
256
 
257
- // await ifWe(lc, `rejects checkout when branch does not exist or branchName missing`, async () => {
258
- // const testDir = path.join(process.cwd(), '.test_branch_checkout_4');
259
- // const vcsFolderName = '.vcsgib_test_bc_4';
260
- // try {
261
- // await executeInitCmd({
262
- // targetDir: testDir,
263
- // vcsFolderName,
264
- // quiet: true,
265
- // });
266
-
267
- // let err1 = false;
268
- // try {
269
- // await executeCheckoutCmd({
270
- // branchName: '',
271
- // targetDir: testDir,
272
- // vcsFolderName,
273
- // quiet: true,
274
- // });
275
- // } catch (err: any) {
276
- // err1 = true;
277
- // iReckon(lc, err.message).includes('Branch name is required');
278
- // }
279
- // iReckon(lc, err1).isGonnaBeTrue();
280
-
281
- // let err2 = false;
282
- // try {
283
- // await executeCheckoutCmd({
284
- // branchName: 'non-existent-branch',
285
- // targetDir: testDir,
286
- // vcsFolderName,
287
- // quiet: true,
288
- // });
289
- // } catch (err: any) {
290
- // err2 = true;
291
- // iReckon(lc, err.message).includes("not found");
292
- // }
293
- // iReckon(lc, err2).isGonnaBeTrue();
294
- // } finally {
295
- // await fs.rm(testDir, { recursive: true, force: true });
296
- // }
297
- // });
298
-
299
- // await ifWe(lc, `lists branches silently on secondary branch without error noise`, async () => {
300
- // const testDir = path.join(process.cwd(), '.test_branch_checkout_secondary');
301
- // const vcsFolderName = '.vcsgib_test_bc_sec';
302
- // try {
303
- // await executeInitCmd({
304
- // targetDir: testDir,
305
- // vcsFolderName,
306
- // quiet: true,
307
- // });
308
-
309
- // // Create and checkout secondary branch feature-math
310
- // await executeBranchCmd({
311
- // branchName: 'feature-math',
312
- // targetDir: testDir,
313
- // vcsFolderName,
314
- // quiet: true,
315
- // });
316
-
317
- // await executeCheckoutCmd({
318
- // branchName: 'feature-math',
319
- // targetDir: testDir,
320
- // vcsFolderName,
321
- // quiet: true,
322
- // });
323
-
324
- // // Run branch list while on secondary branch
325
- // const listRes = await executeBranchCmd({
326
- // targetDir: testDir,
327
- // vcsFolderName,
328
- // quiet: true,
329
- // });
330
-
331
- // iReckon(lc, listRes.branches.length).willEqual(2);
332
- // const mathBranch = listRes.branches.find(b => b.name === 'feature-math');
333
- // const mainBranch = listRes.branches.find(b => b.name === 'main');
334
- // iReckon(lc, mathBranch?.isActive).isGonnaBeTrue();
335
- // iReckon(lc, mainBranch?.isActive).isGonnaBeFalse();
336
- // } finally {
337
- // await fs.rm(testDir, { recursive: true, force: true });
338
- // }
339
- // });
340
-
341
- // await ifWe(lc, `branches single file-root item and projects into file-branch worktree on checkout`, async () => {
342
- // const testDir = path.join(process.cwd(), '.test_branch_checkout_file_root');
343
- // const vcsFolderName = '.vcsgib_test_bc_file';
344
- // try {
345
- // await executeInitCmd({
346
- // targetDir: testDir,
347
- // vcsFolderName,
348
- // quiet: true,
349
- // });
350
-
351
- // // Create nested file structure src/utils/math.js and commit on main
352
- // const mathRelPath = 'src/utils/math.js';
353
- // await fs.mkdir(path.join(testDir, 'src', 'utils'), { recursive: true });
354
- // await fs.writeFile(path.join(testDir, mathRelPath), 'export function add(a, b) { return a + b; }', 'utf8');
355
-
356
- // await executeAddCmd({
357
- // paths: [mathRelPath],
358
- // targetDir: testDir,
359
- // vcsFolderName,
360
- // quiet: true,
361
- // });
362
-
363
- // await executeCommitCmd({
364
- // message: 'Add math.js',
365
- // targetDir: testDir,
366
- // vcsFolderName,
367
- // quiet: true,
368
- // });
369
-
370
- // // Execute branch command for single file math-opt targeting src/utils/math.js
371
- // const branchRes = await executeBranchCmd({
372
- // branchName: 'math-opt',
373
- // itemPath: mathRelPath,
374
- // targetDir: testDir,
375
- // vcsFolderName,
376
- // quiet: true,
377
- // });
378
-
379
- // iReckon(lc, branchRes.createdBranchName).willEqual('math-opt');
380
-
381
- // // Attempt branching uncommitted/non-existent item
382
- // let uncommittedErr = false;
383
- // try {
384
- // await executeBranchCmd({
385
- // branchName: 'invalid-file-branch',
386
- // itemPath: 'src/utils/non-existent.js',
387
- // targetDir: testDir,
388
- // vcsFolderName,
389
- // quiet: true,
390
- // });
391
- // } catch (err: any) {
392
- // uncommittedErr = true;
393
- // iReckon(lc, err.message).includes("not found in active branch snapshot");
394
- // }
395
- // iReckon(lc, uncommittedErr).isGonnaBeTrue();
396
-
397
- // // Execute checkout command for math-opt
398
- // const checkoutRes = await executeCheckoutCmd({
399
- // branchName: 'math-opt',
400
- // targetDir: testDir,
401
- // vcsFolderName,
402
- // quiet: true,
403
- // });
404
-
405
- // const expectedWorktree = path.join(testDir, 'b', 'math-opt');
406
- // iReckon(lc, checkoutRes.worktreePath).willEqual(expectedWorktree);
407
-
408
- // // Verify single file projected at expectedWorktree/math.js (my-repo/b/math-opt/math.js)
409
- // const projectedFilePath = path.join(expectedWorktree, 'math.js');
410
- // const fileExists = await fs.stat(projectedFilePath).then(s => s.isFile()).catch(() => false);
411
- // iReckon(lc, fileExists).isGonnaBeTrue();
412
-
413
- // const fileContent = await fs.readFile(projectedFilePath, 'utf8');
414
- // iReckon(lc, fileContent).willEqual('export function add(a, b) { return a + b; }');
415
- // } finally {
416
- // await fs.rm(testDir, { recursive: true, force: true });
417
- // }
418
- // });
419
-
420
- // await ifWe(lc, `performs vcs merge end-to-end between main and secondary branch`, async () => {
421
- // const testDir = path.join(process.cwd(), '.test_vcs_merge_e2e');
422
- // const vcsFolderName = '.vcsgib_test_merge_e2e';
423
- // try {
424
- // await executeInitCmd({
425
- // targetDir: testDir,
426
- // vcsFolderName,
427
- // quiet: true,
428
- // });
429
-
430
- // // 1. Initial commit on main
431
- // const initialContent = "line 1\nline 2\nline 3";
432
- // await fs.writeFile(path.join(testDir, 'app.ts'), initialContent, 'utf8');
433
- // await executeAddCmd({
434
- // paths: [path.join(testDir, 'app.ts')],
435
- // targetDir: testDir,
436
- // vcsFolderName,
437
- // quiet: true,
438
- // });
439
- // await executeCommitCmd({
440
- // message: 'Initial commit on main',
441
- // targetDir: testDir,
442
- // vcsFolderName,
443
- // quiet: true,
444
- // });
445
-
446
- // // 2. Create secondary branch feature-merge
447
- // await executeBranchCmd({
448
- // branchName: 'feature-merge',
449
- // targetDir: testDir,
450
- // vcsFolderName,
451
- // quiet: true,
452
- // });
453
-
454
- // // 3. Checkout feature-merge branch and make a commit (modify line 3)
455
- // await executeCheckoutCmd({
456
- // branchName: 'feature-merge',
457
- // targetDir: testDir,
458
- // vcsFolderName,
459
- // quiet: true,
460
- // });
461
- // const featureWorktree = path.join(testDir, 'b', 'feature-merge');
462
- // const featureContent = "line 1\nline 2\nline 3 modified by secondary";
463
- // await fs.writeFile(path.join(featureWorktree, 'app.ts'), featureContent, 'utf8');
464
- // await executeAddCmd({
465
- // paths: [path.join(featureWorktree, 'app.ts')],
466
- // targetDir: testDir,
467
- // vcsFolderName,
468
- // quiet: true,
469
- // });
470
- // await executeCommitCmd({
471
- // message: 'Update app.ts on feature-merge',
472
- // targetDir: testDir,
473
- // vcsFolderName,
474
- // quiet: true,
475
- // });
476
-
477
- // // 4. Checkout main branch and make a commit (modify line 1)
478
- // await executeCheckoutCmd({
479
- // branchName: 'main',
480
- // targetDir: testDir,
481
- // vcsFolderName,
482
- // quiet: true,
483
- // });
484
- // const mainContent = "line 1 modified by main\nline 2\nline 3";
485
- // await fs.writeFile(path.join(testDir, 'app.ts'), mainContent, 'utf8');
486
- // await executeAddCmd({
487
- // paths: [path.join(testDir, 'app.ts')],
488
- // targetDir: testDir,
489
- // vcsFolderName,
490
- // quiet: true,
491
- // });
492
- // await executeCommitCmd({
493
- // message: 'Update app.ts on main',
494
- // targetDir: testDir,
495
- // vcsFolderName,
496
- // quiet: true,
497
- // });
498
-
499
- // // 5. Execute vcs merge feature-merge into main
500
- // const mergeRes = await executeMergeCmd({
501
- // incomingBranchName: 'feature-merge',
502
- // targetDir: testDir,
503
- // vcsFolderName,
504
- // quiet: true,
505
- // });
506
-
507
- // iReckon(lc, mergeRes.baseBranch).willEqual('main');
508
- // iReckon(lc, mergeRes.incomingBranch).willEqual('feature-merge');
509
-
510
- // // 6. Verify projected file on physical worktree disk contains merged lines
511
- // const mergedAppTs = await fs.readFile(path.join(testDir, 'app.ts'), 'utf8');
512
- // iReckon(lc, mergedAppTs).includes('line 1 modified by main');
513
- // iReckon(lc, mergedAppTs).includes('line 2');
514
- // iReckon(lc, mergedAppTs).includes('line 3 modified by secondary');
515
- // } finally {
516
- // await fs.rm(testDir, { recursive: true, force: true });
517
- // }
518
- // });
519
-
520
- // await ifWe(lc, `resolves contextual branch for log and status inside secondary branch worktree`, async () => {
521
- // const testDir = path.join(process.cwd(), '.test_contextual_worktree_branch');
522
- // const vcsFolderName = '.vcsgib_test_cwb';
523
- // try {
524
- // await executeInitCmd({ targetDir: testDir, vcsFolderName, quiet: true });
525
-
526
- // await fs.writeFile(path.join(testDir, 'app.ts'), 'console.log("main");\n', 'utf8');
527
- // await executeAddCmd({ paths: [path.join(testDir, 'app.ts')], targetDir: testDir, vcsFolderName, quiet: true });
528
- // await executeCommitCmd({ message: 'Main initial commit', targetDir: testDir, vcsFolderName, quiet: true });
529
-
530
- // // Create and switch to feature branch
531
- // await executeBranchCmd({
532
- // branchName: 'feature-calc',
533
- // targetDir: testDir,
534
- // vcsFolderName,
535
- // quiet: true,
536
- // });
537
- // const checkoutRes = await executeCheckoutCmd({
538
- // branchName: 'feature-calc',
539
- // targetDir: testDir,
540
- // vcsFolderName,
541
- // quiet: true,
542
- // });
543
- // const featureWorktree = checkoutRes.worktreePath;
544
- // iReckon(lc, featureWorktree).isGonnaBeTruthy();
545
-
546
- // // Commit on feature branch inside worktree
547
- // await fs.writeFile(path.join(featureWorktree!, 'calc.ts'), 'export const add = (a, b) => a + b;\n', 'utf8');
548
- // await executeAddCmd({ paths: [path.join(featureWorktree!, 'calc.ts')], targetDir: featureWorktree!, vcsFolderName, quiet: true });
549
- // await executeCommitCmd({ message: 'Add calc on feature-calc', targetDir: featureWorktree!, vcsFolderName, quiet: true });
550
-
551
- // // Checkout main again so index.activeBranch is 'main'
552
- // await executeCheckoutCmd({ branchName: 'main', targetDir: testDir, vcsFolderName, quiet: true });
553
-
554
- // // Now query log from inside featureWorktree
555
- // const featureLogRes = await executeLogCmd({ targetDir: featureWorktree!, vcsFolderName, quiet: true });
556
- // iReckon(lc, featureLogRes.branchName).willEqual('feature-calc');
557
- // const featureMessages = featureLogRes.commits.map(c => c.message);
558
- // iReckon(lc, featureMessages.some(m => m.includes('Add calc on feature-calc'))).isGonnaBeTrue();
559
-
560
- // // Query status from inside featureWorktree
561
- // const featureStatusRes = await executeStatusCmd({ targetDir: featureWorktree!, vcsFolderName, quiet: true });
562
- // iReckon(lc, featureStatusRes.branchName).willEqual('feature-calc');
563
-
564
- // // Query log from main repoRoot
565
- // const mainLogRes = await executeLogCmd({ targetDir: testDir, vcsFolderName, quiet: true });
566
- // iReckon(lc, mainLogRes.branchName).willEqual('main');
567
- // } finally {
568
- // await fs.rm(testDir, { recursive: true, force: true });
569
- // }
570
- // });
257
+ await ifWe(lc, `rejects checkout when branch does not exist or branchName missing`, async () => {
258
+ const testDir = path.join(process.cwd(), '.test_branch_checkout_4');
259
+ const vcsFolderName = '.vcsgib_test_bc_4';
260
+ try {
261
+ await executeInitCmd({
262
+ targetDir: testDir,
263
+ vcsFolderName,
264
+ quiet: true,
265
+ });
266
+
267
+ let err1 = false;
268
+ try {
269
+ await executeCheckoutCmd({
270
+ branchName: '',
271
+ targetDir: testDir,
272
+ vcsFolderName,
273
+ quiet: true,
274
+ });
275
+ } catch (err: any) {
276
+ err1 = true;
277
+ iReckon(lc, err.message).includes('Branch name is required');
278
+ }
279
+ iReckon(lc, err1).isGonnaBeTrue();
280
+
281
+ let err2 = false;
282
+ try {
283
+ await executeCheckoutCmd({
284
+ branchName: 'non-existent-branch',
285
+ targetDir: testDir,
286
+ vcsFolderName,
287
+ quiet: true,
288
+ });
289
+ } catch (err: any) {
290
+ err2 = true;
291
+ iReckon(lc, err.message).includes("not found");
292
+ }
293
+ iReckon(lc, err2).isGonnaBeTrue();
294
+ } finally {
295
+ await fs.rm(testDir, { recursive: true, force: true });
296
+ }
297
+ });
298
+
299
+ await ifWe(lc, `lists branches silently on secondary branch without error noise`, async () => {
300
+ const testDir = path.join(process.cwd(), '.test_branch_checkout_secondary');
301
+ const vcsFolderName = '.vcsgib_test_bc_sec';
302
+ try {
303
+ await executeInitCmd({
304
+ targetDir: testDir,
305
+ vcsFolderName,
306
+ quiet: true,
307
+ });
308
+
309
+ // Create and checkout secondary branch feature-math
310
+ await executeBranchCmd({
311
+ branchName: 'feature-math',
312
+ targetDir: testDir,
313
+ vcsFolderName,
314
+ quiet: true,
315
+ });
316
+
317
+ await executeCheckoutCmd({
318
+ branchName: 'feature-math',
319
+ targetDir: testDir,
320
+ vcsFolderName,
321
+ quiet: true,
322
+ });
323
+
324
+ // Run branch list while on secondary branch
325
+ const listRes = await executeBranchCmd({
326
+ targetDir: testDir,
327
+ vcsFolderName,
328
+ quiet: true,
329
+ });
330
+
331
+ iReckon(lc, listRes.branches.length).willEqual(2);
332
+ const mathBranch = listRes.branches.find(b => b.name === 'feature-math');
333
+ const mainBranch = listRes.branches.find(b => b.name === 'main');
334
+ iReckon(lc, mathBranch?.isActive).isGonnaBeTrue();
335
+ iReckon(lc, mainBranch?.isActive).isGonnaBeFalse();
336
+ } finally {
337
+ await fs.rm(testDir, { recursive: true, force: true });
338
+ }
339
+ });
340
+
341
+ await ifWe(lc, `branches single file-root item and projects into file-branch worktree on checkout`, async () => {
342
+ const testDir = path.join(process.cwd(), '.test_branch_checkout_file_root');
343
+ const vcsFolderName = '.vcsgib_test_bc_file';
344
+ try {
345
+ await executeInitCmd({
346
+ targetDir: testDir,
347
+ vcsFolderName,
348
+ quiet: true,
349
+ });
350
+
351
+ // Create nested file structure src/utils/math.js and commit on main
352
+ const mathRelPath = 'src/utils/math.js';
353
+ await fs.mkdir(path.join(testDir, 'src', 'utils'), { recursive: true });
354
+ await fs.writeFile(path.join(testDir, mathRelPath), 'export function add(a, b) { return a + b; }', 'utf8');
355
+
356
+ await executeAddCmd({
357
+ paths: [mathRelPath],
358
+ targetDir: testDir,
359
+ vcsFolderName,
360
+ quiet: true,
361
+ });
362
+
363
+ await executeCommitCmd({
364
+ message: 'Add math.js',
365
+ targetDir: testDir,
366
+ vcsFolderName,
367
+ quiet: true,
368
+ });
369
+
370
+ // Execute branch command for single file math-opt targeting src/utils/math.js
371
+ const branchRes = await executeBranchCmd({
372
+ branchName: 'math-opt',
373
+ itemPath: mathRelPath,
374
+ targetDir: testDir,
375
+ vcsFolderName,
376
+ quiet: true,
377
+ });
378
+
379
+ iReckon(lc, branchRes.createdBranchName).willEqual('math-opt');
380
+
381
+ // Attempt branching uncommitted/non-existent item
382
+ let uncommittedErr = false;
383
+ try {
384
+ await executeBranchCmd({
385
+ branchName: 'invalid-file-branch',
386
+ itemPath: 'src/utils/non-existent.js',
387
+ targetDir: testDir,
388
+ vcsFolderName,
389
+ quiet: true,
390
+ });
391
+ } catch (err: any) {
392
+ uncommittedErr = true;
393
+ iReckon(lc, err.message).includes("not found in active branch");
394
+ }
395
+ iReckon(lc, uncommittedErr).isGonnaBeTrue();
396
+
397
+ // Execute checkout command for math-opt
398
+ const checkoutRes = await executeCheckoutCmd({
399
+ branchName: 'math-opt',
400
+ targetDir: testDir,
401
+ vcsFolderName,
402
+ quiet: true,
403
+ });
404
+
405
+ const expectedWorktree = path.join(testDir, 'b', 'math-opt');
406
+ iReckon(lc, checkoutRes.worktreePath).willEqual(expectedWorktree);
407
+
408
+ // Verify single file projected at expectedWorktree/math.js (my-repo/b/math-opt/math.js)
409
+ const projectedFilePath = path.join(expectedWorktree, 'math.js');
410
+ const fileExists = await fs.stat(projectedFilePath).then(s => s.isFile()).catch(() => false);
411
+ iReckon(lc, fileExists).isGonnaBeTrue();
412
+
413
+ const fileContent = await fs.readFile(projectedFilePath, 'utf8');
414
+ iReckon(lc, fileContent).willEqual('export function add(a, b) { return a + b; }');
415
+ } finally {
416
+ await fs.rm(testDir, { recursive: true, force: true });
417
+ }
418
+ });
419
+
420
+ await ifWe(lc, `performs vcs merge end-to-end between main and secondary branch`, async () => {
421
+ const testDir = path.join(process.cwd(), '.test_vcs_merge_e2e');
422
+ const vcsFolderName = '.vcsgib_test_merge_e2e';
423
+ try {
424
+ await executeInitCmd({
425
+ targetDir: testDir,
426
+ vcsFolderName,
427
+ quiet: true,
428
+ });
429
+
430
+ // 1. Initial commit on main
431
+ const initialContent = "line 1\nline 2\nline 3";
432
+ await fs.writeFile(path.join(testDir, 'app.ts'), initialContent, 'utf8');
433
+ await executeAddCmd({
434
+ paths: [path.join(testDir, 'app.ts')],
435
+ targetDir: testDir,
436
+ vcsFolderName,
437
+ quiet: true,
438
+ });
439
+ await executeCommitCmd({
440
+ message: 'Initial commit on main',
441
+ targetDir: testDir,
442
+ vcsFolderName,
443
+ quiet: true,
444
+ });
445
+
446
+ // 2. Create secondary branch feature-merge
447
+ await executeBranchCmd({
448
+ branchName: 'feature-merge',
449
+ targetDir: testDir,
450
+ vcsFolderName,
451
+ quiet: true,
452
+ });
453
+
454
+ // 3. Checkout feature-merge branch and make a commit (modify line 3)
455
+ await executeCheckoutCmd({
456
+ branchName: 'feature-merge',
457
+ targetDir: testDir,
458
+ vcsFolderName,
459
+ quiet: true,
460
+ });
461
+ const featureWorktree = path.join(testDir, 'b', 'feature-merge');
462
+ const featureContent = "line 1\nline 2\nline 3 modified by secondary";
463
+ await fs.writeFile(path.join(featureWorktree, 'app.ts'), featureContent, 'utf8');
464
+ await executeAddCmd({
465
+ paths: [path.join(featureWorktree, 'app.ts')],
466
+ targetDir: testDir,
467
+ vcsFolderName,
468
+ quiet: true,
469
+ });
470
+ await executeCommitCmd({
471
+ message: 'Update app.ts on feature-merge',
472
+ targetDir: testDir,
473
+ vcsFolderName,
474
+ quiet: true,
475
+ });
476
+
477
+ // 4. Checkout main branch and make a commit (modify line 1)
478
+ await executeCheckoutCmd({
479
+ branchName: 'main',
480
+ targetDir: testDir,
481
+ vcsFolderName,
482
+ quiet: true,
483
+ });
484
+ const mainContent = "line 1 modified by main\nline 2\nline 3";
485
+ await fs.writeFile(path.join(testDir, 'app.ts'), mainContent, 'utf8');
486
+ await executeAddCmd({
487
+ paths: [path.join(testDir, 'app.ts')],
488
+ targetDir: testDir,
489
+ vcsFolderName,
490
+ quiet: true,
491
+ });
492
+ await executeCommitCmd({
493
+ message: 'Update app.ts on main',
494
+ targetDir: testDir,
495
+ vcsFolderName,
496
+ quiet: true,
497
+ });
498
+
499
+ // 5. Execute vcs merge feature-merge into main
500
+ const mergeRes = await executeMergeCmd({
501
+ incomingBranchName: 'feature-merge',
502
+ targetDir: testDir,
503
+ vcsFolderName,
504
+ quiet: true,
505
+ });
506
+
507
+ iReckon(lc, mergeRes.baseBranch).willEqual('main');
508
+ iReckon(lc, mergeRes.incomingBranch).willEqual('feature-merge');
509
+
510
+ // 6. Verify projected file on physical worktree disk contains merged lines
511
+ const mergedAppTs = await fs.readFile(path.join(testDir, 'app.ts'), 'utf8');
512
+ iReckon(lc, mergedAppTs).includes('line 1 modified by main');
513
+ iReckon(lc, mergedAppTs).includes('line 2');
514
+ iReckon(lc, mergedAppTs).includes('line 3 modified by secondary');
515
+ } finally {
516
+ await fs.rm(testDir, { recursive: true, force: true });
517
+ }
518
+ });
519
+
520
+ await ifWe(lc, `resolves contextual branch for log and status inside secondary branch worktree`, async () => {
521
+ const testDir = path.join(process.cwd(), '.test_contextual_worktree_branch');
522
+ const vcsFolderName = '.vcsgib_test_cwb';
523
+ try {
524
+ await executeInitCmd({ targetDir: testDir, vcsFolderName, quiet: true });
525
+
526
+ await fs.writeFile(path.join(testDir, 'app.ts'), 'console.log("main");\n', 'utf8');
527
+ await executeAddCmd({ paths: [path.join(testDir, 'app.ts')], targetDir: testDir, vcsFolderName, quiet: true });
528
+ await executeCommitCmd({ message: 'Main initial commit', targetDir: testDir, vcsFolderName, quiet: true });
529
+
530
+ // Create and switch to feature branch
531
+ await executeBranchCmd({
532
+ branchName: 'feature-calc',
533
+ targetDir: testDir,
534
+ vcsFolderName,
535
+ quiet: true,
536
+ });
537
+ const checkoutRes = await executeCheckoutCmd({
538
+ branchName: 'feature-calc',
539
+ targetDir: testDir,
540
+ vcsFolderName,
541
+ quiet: true,
542
+ });
543
+ const featureWorktree = checkoutRes.worktreePath;
544
+ iReckon(lc, featureWorktree).isGonnaBeTruthy();
545
+
546
+ // Commit on feature branch inside worktree
547
+ await fs.writeFile(path.join(featureWorktree!, 'calc.ts'), 'export const add = (a, b) => a + b;\n', 'utf8');
548
+ await executeAddCmd({ paths: [path.join(featureWorktree!, 'calc.ts')], targetDir: featureWorktree!, vcsFolderName, quiet: true });
549
+ await executeCommitCmd({ message: 'Add calc on feature-calc', targetDir: featureWorktree!, vcsFolderName, quiet: true });
550
+
551
+ // Checkout main again so index.activeBranch is 'main'
552
+ await executeCheckoutCmd({ branchName: 'main', targetDir: testDir, vcsFolderName, quiet: true });
553
+
554
+ // Now query log from inside featureWorktree
555
+ const featureLogRes = await executeLogCmd({ targetDir: featureWorktree!, vcsFolderName, quiet: true });
556
+ iReckon(lc, featureLogRes.branchName).willEqual('feature-calc');
557
+ const featureMessages = featureLogRes.commits.map(c => c.message);
558
+ iReckon(lc, featureMessages.some(m => m.includes('Add calc on feature-calc'))).asTo('featureMessages has Add calc on feature-calc').isGonnaBeTrue();
559
+
560
+ // Query status from inside featureWorktree
561
+ const featureStatusRes = await executeStatusCmd({ targetDir: featureWorktree!, vcsFolderName, quiet: true });
562
+ iReckon(lc, featureStatusRes.branchName).willEqual('feature-calc');
563
+
564
+ // Query log from main repoRoot
565
+ const mainLogRes = await executeLogCmd({ targetDir: testDir, vcsFolderName, quiet: true });
566
+ iReckon(lc, mainLogRes.branchName).willEqual('main');
567
+ } finally {
568
+ await fs.rm(testDir, { recursive: true, force: true });
569
+ }
570
+ });
571
571
  });
572
572
 
573
573