@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
@@ -129,16 +129,18 @@ export async function executeCommitCmd({
129
129
  }
130
130
  }
131
131
 
132
- currentBranchIbGib = branchIbGibs.find(
132
+ currentBranchIbGib = branchIbGibs.findLast(
133
133
  (b) => (b as B2tFSBranchIbGib_V1)?.data?.name === branchName,
134
- ) as B2tFSBranchIbGib_V1 || (branchIbGibs.at(0) as B2tFSBranchIbGib_V1);
134
+ ) as B2tFSBranchIbGib_V1 || (branchIbGibs.at(-1) as B2tFSBranchIbGib_V1);
135
+
135
136
 
136
137
  if (currentBranchIbGib) {
137
138
  currentBranchAddr = getIbGibAddr({ ibGib: currentBranchIbGib });
138
139
  }
139
140
  }
140
141
 
141
- const currentRootAddr = currentBranchIbGib?.rel8ns?.b2tfs_item?.at(0);
142
+ const currentRootAddr = currentBranchIbGib?.rel8ns?.b2tfs_item?.at(-1);
143
+
142
144
 
143
145
  // 1. Create CommentIbGib_V1 commit comment node in activeSpace
144
146
  const commentRes = await createCommentIbGib({
@@ -0,0 +1,285 @@
1
+ /**
2
+ * @module merge-cmd
3
+ *
4
+ * Command handler for `vcs merge <branchName>`.
5
+ * Merges target branch into active branch using SyncSagaCoordinator sync and 3-way graft merge strategy.
6
+ * Projects merged branch snapshot onto active branch physical worktree path.
7
+ */
8
+
9
+ import path from 'node:path';
10
+ import fs from 'node:fs/promises';
11
+
12
+ import { clone, extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
13
+ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
14
+ import { putInSpace, getLatestAddrs, } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
15
+ import { SyncSagaCoordinator } from '@ibgib/core-gib/dist/sync/sync-saga-coordinator.mjs';
16
+ import { SyncPeerInnerspace_V1 } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs';
17
+ import { SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1 } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs';
18
+ import { SyncConflictStrategy } from '@ibgib/core-gib/dist/sync/sync-constants.mjs';
19
+ import { GraftPreference } from '@ibgib/core-gib/dist/sync/graft-info/graft-info-types.mjs';
20
+
21
+
22
+ import { bootstrapVcsMetaspace } from '../../bootstrap/node-bootstrap.mjs';
23
+ import { B2tFSBranchIbGib_V1 } from '../../engine/branch/branch-types.mjs';
24
+ import { getOrCreateBranchSpace } from '../../engine/branch/branch-space-helper.mjs';
25
+ import { B2tFSItemIbGib_V1, B2TFS_CHILD_ITEM_REL8N_NAME } from '../../engine/item/item-types.mjs';
26
+ import { writeB2tFSItemToFS, getIbGibWithMetaspaceFallback } from '../../engine/item/item-helper.mjs';
27
+ import { getB2tFSIndexIbGib, updateB2tFSIndexIbGib } from '../../engine/index/index-helper.mjs';
28
+ import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
29
+
30
+ const lcFile = `[merge-cmd]`;
31
+ const logalot = GLOBAL_LOG_A_LOT;
32
+
33
+ export interface MergeCmdOpts {
34
+ targetBranchName?: string;
35
+ targetDir?: string;
36
+ vcsFolderName?: string;
37
+ quiet?: boolean;
38
+ }
39
+
40
+ export interface MergeCmdResult {
41
+ activeBranch: string;
42
+ targetBranch: string;
43
+ activeSpaceId: string;
44
+ targetSpaceId: string;
45
+ mergedBranchAddr?: string;
46
+ worktreePath: string;
47
+ }
48
+
49
+ export async function executeMergeCmd({
50
+ targetBranchName,
51
+ targetDir = process.cwd(),
52
+ vcsFolderName = '.vcsgib',
53
+ quiet = false,
54
+ }: MergeCmdOpts = {}): Promise<MergeCmdResult> {
55
+ const lc = `${lcFile}[${executeMergeCmd.name}]`;
56
+ try {
57
+ if (logalot) {
58
+ console.log(`${lc} starting... (I: 4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f)`);
59
+ }
60
+
61
+ const trimmedTargetBranch = targetBranchName?.trim();
62
+ if (!trimmedTargetBranch) {
63
+ throw new Error(`Branch name is required for merge (E: 5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a)`);
64
+ }
65
+
66
+ const absTargetDir = path.resolve(targetDir);
67
+
68
+ const { metaspace, localSpace, repoRoot, vcsPath } = await bootstrapVcsMetaspace({
69
+ repoPath: absTargetDir,
70
+ vcsFolderName,
71
+ });
72
+
73
+ // Verify repo exists
74
+ try {
75
+ await fs.access(vcsPath);
76
+ } catch {
77
+ throw new Error(`Not an ibgib repository (directory ${vcsPath} does not exist) (E: 6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b)`);
78
+ }
79
+
80
+ // 1. Fetch authoritative repository index from localSpace
81
+ const indexIbGib = await getB2tFSIndexIbGib({ space: localSpace, vcsPath });
82
+ if (!indexIbGib) {
83
+ throw new Error(`Repository index B2tFSIndexIbGib_V1 not found in localSpace (E: 7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c)`);
84
+ }
85
+
86
+ const activeBranchName = indexIbGib.data?.activeBranch || 'main';
87
+
88
+ if (activeBranchName === trimmedTargetBranch) {
89
+ throw new Error(`Cannot merge branch '${trimmedTargetBranch}' into itself (E: 8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d)`);
90
+ }
91
+
92
+ // 2. Fetch all registered branch ibgibs
93
+ const branchAddrs = [
94
+ ...(indexIbGib.rel8ns?.branch || []),
95
+ ...(indexIbGib.rel8ns?.branch_tjp || []),
96
+ ];
97
+
98
+ let branchIbGibs: B2tFSBranchIbGib_V1[] = [];
99
+ if (branchAddrs.length > 0) {
100
+ for (const bAddr of branchAddrs) {
101
+ const bIbGib = await getIbGibWithMetaspaceFallback({
102
+ addr: bAddr,
103
+ space: localSpace,
104
+ metaspace,
105
+ });
106
+ if (bIbGib) {
107
+ branchIbGibs.push(bIbGib as B2tFSBranchIbGib_V1);
108
+ }
109
+ }
110
+ }
111
+
112
+ // Resolve active branch node & target branch node
113
+ const activeBranchIbGib = branchIbGibs.findLast(
114
+ (b) => b?.data?.name === activeBranchName,
115
+ );
116
+ if (!activeBranchIbGib) {
117
+ throw new Error(`Active branch '${activeBranchName}' not found in repository (E: 9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e)`);
118
+ }
119
+
120
+ const targetBranchIbGib = branchIbGibs.findLast(
121
+ (b) => b?.data?.name === trimmedTargetBranch,
122
+ );
123
+
124
+ if (!targetBranchIbGib) {
125
+ throw new Error(`Branch '${trimmedTargetBranch}' does not exist (E: 0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f)`);
126
+ }
127
+
128
+ // 3. Resolve active branch space & target branch space
129
+ const activeSpaceRes = await getOrCreateBranchSpace({
130
+ metaspace,
131
+ vcsPath,
132
+ branchName: activeBranchName,
133
+ });
134
+ const activeSpace = activeSpaceRes.space;
135
+
136
+ const targetSpaceRes = await getOrCreateBranchSpace({
137
+ metaspace,
138
+ vcsPath,
139
+ branchName: trimmedTargetBranch,
140
+ });
141
+ const targetSpace = targetSpaceRes.space;
142
+
143
+ await putInSpace({ space: activeSpace, ibGib: activeBranchIbGib });
144
+ await putInSpace({ space: targetSpace, ibGib: targetBranchIbGib });
145
+
146
+ // Resolve latest branch tip inside targetSpace (in case commits occurred on target branch)
147
+ const targetBranchTjpAddr = targetBranchIbGib.rel8ns?.tjp?.at(0) || getIbGibAddr({ ibGib: targetBranchIbGib });
148
+ const latestTargetBranchRes = await getLatestAddrs({ space: targetSpace, addrs: [targetBranchTjpAddr] });
149
+ const latestTargetBranchAddr = (latestTargetBranchRes?.data as any)?.latestAddrs?.[0] || getIbGibAddr({ ibGib: targetBranchIbGib });
150
+
151
+ const latestTargetBranchIbGib = (await getIbGibWithMetaspaceFallback({
152
+ addr: latestTargetBranchAddr,
153
+ space: targetSpace,
154
+ metaspace,
155
+ })) as B2tFSBranchIbGib_V1 || targetBranchIbGib;
156
+
157
+ const targetRootAddr = latestTargetBranchIbGib.rel8ns?.b2tfs_item?.at(-1);
158
+
159
+ if (!targetRootAddr) {
160
+ throw new Error(`Target branch '${trimmedTargetBranch}' has no valid root item address (E: 3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e)`);
161
+ }
162
+ const targetRootItem = await getIbGibWithMetaspaceFallback({
163
+ addr: targetRootAddr,
164
+ space: targetSpace,
165
+ metaspace,
166
+ });
167
+ if (!targetRootItem) {
168
+ throw new Error(`Target root item '${targetRootAddr}' not found in target space (E: 4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f)`);
169
+ }
170
+
171
+ // 4. Setup SyncPeerInnerspace and SyncSagaCoordinator syncing target branch space into active branch space
172
+ const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
173
+ await peer.initialized;
174
+ await peer.initializeOpts({
175
+ localMetaspace: metaspace,
176
+ localSpace: targetSpace,
177
+ receiverSpace: activeSpace,
178
+ receiverCoordinator: new SyncSagaCoordinator(),
179
+ receiverMetaspace: metaspace,
180
+ });
181
+
182
+ const senderCoordinator = new SyncSagaCoordinator();
183
+ const syncSaga = await senderCoordinator.sync({
184
+ peer,
185
+ localSpace: targetSpace,
186
+ metaspace,
187
+ domainIbGibs: [targetRootItem],
188
+ conflictStrategy: SyncConflictStrategy.optimisticWithLCS,
189
+ graftPreference: GraftPreference.receiver,
190
+ });
191
+
192
+ await syncSaga.done;
193
+
194
+ // 5. Query activeSpace for updated active branch node & root item evolved natively by sync graft strategy
195
+ const activeBranchTjpAddr = activeBranchIbGib.rel8ns?.tjp?.at(0) || getIbGibAddr({ ibGib: activeBranchIbGib });
196
+ const latestBranchRes = await getLatestAddrs({ space: activeSpace, addrs: [activeBranchTjpAddr] });
197
+ const mergedBranchAddr = (latestBranchRes?.data as any)?.latestAddrs?.[0] || getIbGibAddr({ ibGib: activeBranchIbGib });
198
+
199
+ const mergedBranchIbGib = (await getIbGibWithMetaspaceFallback({
200
+ addr: mergedBranchAddr,
201
+ space: activeSpace,
202
+ metaspace,
203
+ })) as B2tFSBranchIbGib_V1 || activeBranchIbGib;
204
+
205
+ const mergedRootItemAddr = mergedBranchIbGib.rel8ns?.b2tfs_item?.at(-1);
206
+
207
+ // Update indexIbGib to reference new merged branch node
208
+ await updateB2tFSIndexIbGib({
209
+ space: activeSpace,
210
+ metaspace,
211
+ indexIbGib,
212
+ rel8nsToUpdate: {
213
+ branch: [mergedBranchAddr],
214
+ },
215
+ vcsPath,
216
+ });
217
+
218
+
219
+ // 6. Project merged branch snapshot files onto physical worktree disk
220
+ const isDefaultBranch = activeBranchName === 'main';
221
+ const worktreePath = isDefaultBranch
222
+ ? repoRoot
223
+ : path.join(repoRoot, 'b', activeBranchName);
224
+
225
+ await fs.mkdir(worktreePath, { recursive: true });
226
+
227
+ if (mergedRootItemAddr) {
228
+ const mergedRootItem = await getIbGibWithMetaspaceFallback({
229
+ addr: mergedRootItemAddr,
230
+ space: activeSpace,
231
+ metaspace,
232
+ }) as B2tFSItemIbGib_V1;
233
+
234
+ if (mergedRootItem) {
235
+ if (mergedRootItem.data?.fsType === 'file') {
236
+ await writeB2tFSItemToFS({
237
+ item: mergedRootItem,
238
+ destPath: worktreePath,
239
+ space: activeSpace,
240
+ metaspace,
241
+ });
242
+ } else {
243
+ const childAddrs = mergedRootItem.rel8ns?.[B2TFS_CHILD_ITEM_REL8N_NAME] || [];
244
+ for (const childAddr of childAddrs) {
245
+ const childItem = await getIbGibWithMetaspaceFallback({
246
+ addr: childAddr,
247
+ space: activeSpace,
248
+ metaspace,
249
+ }) as B2tFSItemIbGib_V1;
250
+
251
+ if (childItem) {
252
+ await writeB2tFSItemToFS({
253
+ item: childItem,
254
+ destPath: worktreePath,
255
+ space: activeSpace,
256
+ metaspace,
257
+ });
258
+ }
259
+ }
260
+ }
261
+ }
262
+ }
263
+
264
+ if (!quiet) {
265
+ console.log(`Successfully merged branch '${trimmedTargetBranch}' into '${activeBranchName}' (I: 1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a)`);
266
+ console.log(` Worktree projection: ${worktreePath}`);
267
+ }
268
+
269
+ return {
270
+ activeBranch: activeBranchName,
271
+ targetBranch: trimmedTargetBranch,
272
+ activeSpaceId: activeSpaceRes.spaceId,
273
+ targetSpaceId: targetSpaceRes.spaceId,
274
+ mergedBranchAddr: getIbGibAddr({ ibGib: mergedBranchIbGib }),
275
+ worktreePath,
276
+ };
277
+ } catch (error) {
278
+ console.error(`${lc} ${extractErrorMsg(error)} (E: 2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b)`);
279
+ throw error;
280
+ } finally {
281
+ if (logalot) {
282
+ console.log(`${lc} complete. (I: 3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c)`);
283
+ }
284
+ }
285
+ }
@@ -17,6 +17,7 @@ import { executeCommitCmd } from './commands/commit-cmd.mjs';
17
17
  import { executeLogCmd } from './commands/log-cmd.mjs';
18
18
  import { executeBranchCmd } from './commands/branch-cmd.mjs';
19
19
  import { executeCheckoutCmd } from './commands/checkout-cmd.mjs';
20
+ import { executeMergeCmd } from './commands/merge-cmd.mjs';
20
21
  import { executeResetCmd } from './commands/reset-cmd.mjs';
21
22
  import { executeRestoreCmd } from './commands/restore-cmd.mjs';
22
23
  import { AUTO_GENERATED_VERSION } from '../AUTO-GENERATED-version.mjs';
@@ -44,6 +45,7 @@ Commands:
44
45
  log Show commit logs
45
46
  branch [name] List or create branches
46
47
  checkout <branch> Switch to a specified branch and project worktree
48
+ merge <branch> Merge specified branch into active branch
47
49
  reset [path...] Unstage specified files from index (-a, --all for all)
48
50
  restore [path...] Restore working tree files or unstage (--staged)
49
51
 
@@ -120,6 +122,11 @@ export async function main({
120
122
  await executeCheckoutCmd({ branchName });
121
123
  break;
122
124
  }
125
+ case VCS_SUBCOMMANDS.MERGE: {
126
+ const targetBranchName = parsed.positionals[0] || parsed.flags.branchName;
127
+ await executeMergeCmd({ targetBranchName });
128
+ break;
129
+ }
123
130
  case VCS_SUBCOMMANDS.RESET: {
124
131
  await executeResetCmd({
125
132
  paths: parsed.positionals,
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @module item-helper
3
- *
3
+ *
4
4
  * B2tFS Item Helper functions: graph diff generation, filesystem projection materialization,
5
5
  * and two-pass transform application.
6
6
  */
@@ -13,23 +13,29 @@ import { extractErrorMsg, getUUID } from '@ibgib/helper-gib/dist/helpers/utils-h
13
13
  import { Factory_V1 } from '@ibgib/ts-gib/dist/V1/factory.mjs';
14
14
  import { mut8 } from '@ibgib/ts-gib/dist/V1/transforms/mut8.mjs';
15
15
  import { rel8 } from '@ibgib/ts-gib/dist/V1/transforms/rel8.mjs';
16
- import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
17
16
  import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
18
17
  import { TransformResult } from '@ibgib/ts-gib/dist/types.mjs';
19
18
  import { MetaspaceService } from '@ibgib/core-gib/dist/witness/space/metaspace/metaspace-types.mjs';
20
19
  import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
21
- import { getIbGibsFromCache_fallbackToSpaces } from '@ibgib/core-gib/dist/common/other/ibgib-helper.mjs';
22
- import { putInSpace, persistTransformResult, getFromSpace } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
20
+ import { isIbGib } from '@ibgib/core-gib/dist/common/other/ibgib-helper.mjs';
21
+ import { persistTransformResult, getFromSpace } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
23
22
 
23
+ import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
24
24
  import { parseSpaceQualifiedIbGibAddr } from '../index/index-helper.mjs';
25
25
  import { B2TFS_ITEM_ATOM, getB2tFSItemIb } from './item-atom-helper.mjs';
26
- import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
27
26
  import {
28
- B2tFSItemIbGib_V1, B2tFSItemData_V1, B2tFSItemRel8ns_V1, B2TFS_CHILD_ITEM_REL8N_NAME, BINARY_REL8N_NAME, B2tFSItemDiffInfo
27
+ B2tFSItemIbGib_V1, B2tFSItemData_V1, B2tFSItemRel8ns_V1,
28
+ B2TFS_CHILD_ITEM_REL8N_NAME, BINARY_REL8N_NAME, B2tFSItemDiffInfo
29
29
  } from './item-types.mjs';
30
30
 
31
- const lcFile = `[item-helper]`;
32
31
  const logalot = GLOBAL_LOG_A_LOT;
32
+ const lcFile = `[item-helper]`;
33
+
34
+ export function isB2tFSItemIbGib(x: any): x is B2tFSItemIbGib_V1 {
35
+ if (!x) { return false; }
36
+ if (!isIbGib(x)) { return false; }
37
+ return x.ib.startsWith(B2TFS_ITEM_ATOM) || x.data?.classname === 'B2tFSItemIbGib_V1';
38
+ }
33
39
 
34
40
  export interface CreateB2tFSItemIbGibOpts {
35
41
  fsType: 'file' | 'folder';
@@ -153,7 +159,7 @@ export async function evolveB2tFSItemIbGib({
153
159
 
154
160
  const hasDataChanges = dataToUpdate && Object.keys(dataToUpdate).length > 0;
155
161
  const hasRel8nsChanges = (rel8nsToUpdate && Object.keys(rel8nsToUpdate).length > 0) ||
156
- (rel8nsToRemove && Object.keys(rel8nsToRemove).length > 0);
162
+ (rel8nsToRemove && Object.keys(rel8nsToRemove).length > 0);
157
163
 
158
164
  // If neither data nor rel8ns explicitly specified, update diffTransactionId to evolve timeline
159
165
  const patchData: Partial<B2tFSItemData_V1> = {
@@ -166,7 +172,7 @@ export async function evolveB2tFSItemIbGib({
166
172
  src: currentItem,
167
173
  dataToAddOrPatch: patchData,
168
174
  dna: true,
169
- nCounter: true,
175
+ nCounter: patchData.n ? false : true, // if we manually set data.n, turn nCounter off
170
176
  });
171
177
 
172
178
  currentItem = resMut8.newIbGib as B2tFSItemIbGib_V1;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @module item-types
3
- *
3
+ *
4
4
  * Baseline type definitions for B2tFS filesystem item IbGibs.
5
5
  */
6
6
 
@@ -93,6 +93,7 @@ export interface B2tFSItemRel8ns_V1 extends IbGibRel8ns_V1 {
93
93
  * B2tFS Item IbGib object structure.
94
94
  */
95
95
  export interface B2tFSItemIbGib_V1 extends IbGib_V1<B2tFSItemData_V1, B2tFSItemRel8ns_V1> {
96
+ data: B2tFSItemData_V1;
96
97
  }
97
98
 
98
99
  /**