@ibgib/vcs-gib 0.0.21 → 0.0.26

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 (93) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/VCS_CLI_USER_GUIDE.md +94 -89
  3. package/dist/AUTO-GENERATED-version.d.mts +1 -1
  4. package/dist/AUTO-GENERATED-version.mjs +1 -1
  5. package/dist/bootstrap/node-bootstrap.mjs +1 -1
  6. package/dist/cli/cli-arg-parser.d.mts +1 -0
  7. package/dist/cli/cli-arg-parser.d.mts.map +1 -1
  8. package/dist/cli/cli-arg-parser.mjs +5 -1
  9. package/dist/cli/cli-arg-parser.mjs.map +1 -1
  10. package/dist/cli/cli-constants.d.mts +6 -0
  11. package/dist/cli/cli-constants.d.mts.map +1 -1
  12. package/dist/cli/cli-constants.mjs +12 -0
  13. package/dist/cli/cli-constants.mjs.map +1 -1
  14. package/dist/cli/commands/add-cmd.d.mts.map +1 -1
  15. package/dist/cli/commands/add-cmd.mjs +5 -2
  16. package/dist/cli/commands/add-cmd.mjs.map +1 -1
  17. package/dist/cli/commands/commit-cmd.d.mts +5 -4
  18. package/dist/cli/commands/commit-cmd.d.mts.map +1 -1
  19. package/dist/cli/commands/commit-cmd.mjs +149 -33
  20. package/dist/cli/commands/commit-cmd.mjs.map +1 -1
  21. package/dist/cli/commands/generate-comment-cmd.d.mts +19 -0
  22. package/dist/cli/commands/generate-comment-cmd.d.mts.map +1 -0
  23. package/dist/cli/commands/generate-comment-cmd.mjs +140 -0
  24. package/dist/cli/commands/generate-comment-cmd.mjs.map +1 -0
  25. package/dist/cli/commands/log-cmd.d.mts +12 -3
  26. package/dist/cli/commands/log-cmd.d.mts.map +1 -1
  27. package/dist/cli/commands/log-cmd.mjs +236 -38
  28. package/dist/cli/commands/log-cmd.mjs.map +1 -1
  29. package/dist/cli/commands/merge-cmd.d.mts +21 -8
  30. package/dist/cli/commands/merge-cmd.d.mts.map +1 -1
  31. package/dist/cli/commands/merge-cmd.mjs +138 -70
  32. package/dist/cli/commands/merge-cmd.mjs.map +1 -1
  33. package/dist/cli/commands/status-cmd.d.mts +5 -6
  34. package/dist/cli/commands/status-cmd.d.mts.map +1 -1
  35. package/dist/cli/commands/status-cmd.mjs +50 -205
  36. package/dist/cli/commands/status-cmd.mjs.map +1 -1
  37. package/dist/cli/vcs-cli-main.d.mts.map +1 -1
  38. package/dist/cli/vcs-cli-main.mjs +27 -6
  39. package/dist/cli/vcs-cli-main.mjs.map +1 -1
  40. package/dist/engine/index/index-helper.d.mts.map +1 -1
  41. package/dist/engine/index/index-helper.mjs +3 -0
  42. package/dist/engine/index/index-helper.mjs.map +1 -1
  43. package/dist/engine/item/item-helper.d.mts +31 -1
  44. package/dist/engine/item/item-helper.d.mts.map +1 -1
  45. package/dist/engine/item/item-helper.mjs +44 -2
  46. package/dist/engine/item/item-helper.mjs.map +1 -1
  47. package/dist/engine/merge/b2tfs-3way-graft-strategy.d.mts +74 -0
  48. package/dist/engine/merge/b2tfs-3way-graft-strategy.d.mts.map +1 -0
  49. package/dist/engine/merge/{b2tfs-3way-merge-strategy.mjs → b2tfs-3way-graft-strategy.mjs} +133 -304
  50. package/dist/engine/merge/b2tfs-3way-graft-strategy.mjs.map +1 -0
  51. package/dist/engine/merge/{b2tfs-3way-merge-types.d.mts → b2tfs-3way-graft-types.d.mts} +2 -9
  52. package/dist/engine/merge/b2tfs-3way-graft-types.d.mts.map +1 -0
  53. package/dist/engine/merge/b2tfs-3way-graft-types.mjs +2 -0
  54. package/dist/engine/merge/b2tfs-3way-graft-types.mjs.map +1 -0
  55. package/dist/engine/status/status-helper.d.mts +89 -0
  56. package/dist/engine/status/status-helper.d.mts.map +1 -0
  57. package/dist/engine/status/status-helper.mjs +285 -0
  58. package/dist/engine/status/status-helper.mjs.map +1 -0
  59. package/dist/test/test-helpers.d.mts +51 -0
  60. package/dist/test/test-helpers.d.mts.map +1 -0
  61. package/dist/test/test-helpers.mjs +135 -0
  62. package/dist/test/test-helpers.mjs.map +1 -0
  63. package/package.json +4 -4
  64. package/src/AUTO-GENERATED-version.mts +1 -1
  65. package/src/bootstrap/node-bootstrap.mts +1 -1
  66. package/src/cli/cli-arg-parser.mts +5 -0
  67. package/src/cli/cli-constants.mts +13 -0
  68. package/src/cli/commands/add-cmd.mts +5 -2
  69. package/src/cli/commands/branch-checkout-cmd.respec.log +8 -101
  70. package/src/cli/commands/branch-checkout-cmd.respec.mts +11 -10
  71. package/src/cli/commands/commit-cmd.mts +165 -42
  72. package/src/cli/commands/commit-log-cmd.respec.mts +216 -3
  73. package/src/cli/commands/generate-comment-cmd.mts +171 -0
  74. package/src/cli/commands/log-cmd.mts +288 -41
  75. package/src/cli/commands/merge-cmd.mts +154 -76
  76. package/src/cli/commands/status-cmd.mts +57 -256
  77. package/src/cli/vcs-cli-main.mts +28 -7
  78. package/src/engine/index/index-helper.mts +3 -0
  79. package/src/engine/item/item-helper.mts +76 -3
  80. package/src/engine/merge/{b2tfs-3way-merge-strategy.mts → b2tfs-3way-graft-strategy.mts} +152 -374
  81. package/src/engine/merge/{b2tfs-3way-merge-strategy.respec.mts → b2tfs-3way-graft-strategy.respec.mts} +27 -122
  82. package/src/engine/merge/{b2tfs-3way-merge-types.mts → b2tfs-3way-graft-types.mts} +34 -42
  83. package/src/engine/merge/b2tfs-sync-comments.respec.mts +399 -0
  84. package/src/engine/status/status-helper.mts +380 -0
  85. package/src/test/test-helpers.mts +168 -0
  86. package/tsconfig.test.tsbuildinfo +1 -1
  87. package/tsconfig.tsbuildinfo +1 -1
  88. package/dist/engine/merge/b2tfs-3way-merge-strategy.d.mts +0 -48
  89. package/dist/engine/merge/b2tfs-3way-merge-strategy.d.mts.map +0 -1
  90. package/dist/engine/merge/b2tfs-3way-merge-strategy.mjs.map +0 -1
  91. package/dist/engine/merge/b2tfs-3way-merge-types.d.mts.map +0 -1
  92. package/dist/engine/merge/b2tfs-3way-merge-types.mjs +0 -2
  93. package/dist/engine/merge/b2tfs-3way-merge-types.mjs.map +0 -1
@@ -7,30 +7,16 @@
7
7
 
8
8
  import path from 'node:path';
9
9
  import fs from 'node:fs/promises';
10
- import { Dirent } from 'node:fs';
11
- import crypto from 'node:crypto';
12
10
 
13
11
  import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
14
- import { getIbGibsFromCache_fallbackToSpaces } from '@ibgib/core-gib/dist/common/other/ibgib-helper.mjs';
15
-
16
12
  import { bootstrapVcsMetaspace } from '../../bootstrap/node-bootstrap.mjs';
17
- import { getOrCreateBranchSpace } from '../../engine/branch/branch-space-helper.mjs';
18
- import { B2tFSItemIbGib_V1, B2TFS_CHILD_ITEM_REL8N_NAME } from '../../engine/item/item-types.mjs';
19
- import { getIbGibWithMetaspaceFallback } from '../../engine/item/item-helper.mjs';
20
- import { B2tFSBranchIbGib_V1 } from '../../engine/branch/branch-types.mjs';
21
- import { isPathFiltered, parseFilterFileContent } from '../../engine/filter/glob-helper.mjs';
22
- import { getB2tFSIndexIbGib } from '../../engine/index/index-helper.mjs';
23
- import { B2tFSStagedItemRecord } from '../../engine/index/index-types.mjs';
24
13
  import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
14
+ import { getRepoStatus, VcsStatusItem, PendingCommentInfo } from '../../engine/status/status-helper.mjs';
25
15
 
26
16
  const lcFile = `[status-cmd]`;
27
17
  const logalot = GLOBAL_LOG_A_LOT;
28
18
 
29
- export interface VcsStatusItem {
30
- path: string;
31
- fsType: 'file' | 'folder';
32
- status: 'untracked' | 'modified' | 'deleted' | 'staged';
33
- }
19
+ export { VcsStatusItem, PendingCommentInfo };
34
20
 
35
21
  export interface StatusCmdResult {
36
22
  branchName: string;
@@ -38,18 +24,21 @@ export interface StatusCmdResult {
38
24
  modified: VcsStatusItem[];
39
25
  deleted: VcsStatusItem[];
40
26
  untracked: VcsStatusItem[];
27
+ pendingComments: PendingCommentInfo[];
41
28
  }
42
29
 
43
30
  export interface StatusCmdOpts {
44
31
  targetDir?: string;
45
32
  vcsFolderName?: string;
46
33
  quiet?: boolean;
34
+ comments?: boolean;
47
35
  }
48
36
 
49
37
  export async function executeStatusCmd({
50
38
  targetDir = process.cwd(),
51
39
  vcsFolderName = '.vcsgib',
52
40
  quiet = false,
41
+ comments = false,
53
42
  }: StatusCmdOpts = {}): Promise<StatusCmdResult> {
54
43
  const lc = `${lcFile}[${executeStatusCmd.name}]`;
55
44
 
@@ -72,170 +61,88 @@ export async function executeStatusCmd({
72
61
  throw new Error(`Not an ibgib repository (directory ${vcsPath} does not exist) (E: 4d5e6f7a8b9c10d11e12f13a14b15c6d)`);
73
62
  }
74
63
 
75
- // 1. Fetch authoritative B2tFSIndexIbGib_V1 directly from localSpace
76
- const indexIbGib = await getB2tFSIndexIbGib({ space: localSpace, vcsPath });
77
- const branchName = indexIbGib?.data?.activeBranch || 'main';
78
-
79
- const activeWorktreeDir = branchName === 'main' ? repoRoot : path.join(repoRoot, 'b', branchName);
80
-
81
- // Target active branch space b2s_<activeBranch>
82
- const { space: activeBranchSpace } = await getOrCreateBranchSpace({
64
+ const statusRes = await getRepoStatus({
83
65
  metaspace,
66
+ localSpace,
84
67
  vcsPath,
85
- branchName,
86
- });
87
-
88
- // 2. Extract staged items directly from in-band B2tFSIndexIbGib_V1 data
89
- const stagedMap = new Map<string, B2tFSStagedItemRecord>();
90
- const indexStagedPaths = indexIbGib?.data?.stagedPaths || {};
91
- for (const [relPath, itemRec] of Object.entries(indexStagedPaths)) {
92
- stagedMap.set(relPath, itemRec);
93
- }
94
-
95
- // 3. Find active branch root item address from in-band branch graph node
96
- let rootItemAddr: string | undefined;
97
- const branchAddrs = [
98
- ...(indexIbGib?.rel8ns?.branch || []),
99
- ...(indexIbGib?.rel8ns?.branch_tjp || []),
100
- ];
101
-
102
- if (branchAddrs.length > 0) {
103
- let branchIbGibs: B2tFSBranchIbGib_V1[] = [];
104
- for (const bAddr of branchAddrs) {
105
- const bIbGib = await getIbGibWithMetaspaceFallback({
106
- addr: bAddr,
107
- space: activeBranchSpace,
108
- metaspace,
109
- });
110
- if (bIbGib) {
111
- branchIbGibs.push(bIbGib as B2tFSBranchIbGib_V1);
112
- }
113
- }
114
-
115
- const activeBranchIbGib = branchIbGibs.find(
116
- (b) => (b as B2tFSBranchIbGib_V1)?.data?.name === branchName,
117
- ) as B2tFSBranchIbGib_V1 || (branchIbGibs.at(0) as B2tFSBranchIbGib_V1);
118
-
119
- rootItemAddr = activeBranchIbGib?.rel8ns?.b2tfs_item?.at(0);
120
- }
121
-
122
- // Read .ibgibignore patterns
123
- let filterPatterns: string[] = [];
124
- const ignorePath = path.join(activeWorktreeDir, '.ibgibignore');
125
- try {
126
- const ignoreContent = await fs.readFile(ignorePath, 'utf8');
127
- filterPatterns = parseFilterFileContent(ignoreContent);
128
- } catch {
129
- // Ignore file missing is fine
130
- }
131
-
132
- // 4. Walk active branch graph items
133
- const branchItemsMap = new Map<string, { relPath: string; fileHash?: string; fsType: 'file' | 'folder' }>();
134
-
135
- if (rootItemAddr) {
136
- const rootItem = await getIbGibWithMetaspaceFallback({
137
- addr: rootItemAddr,
138
- space: activeBranchSpace,
139
- metaspace,
140
- }) as B2tFSItemIbGib_V1;
141
-
142
- if (rootItem) {
143
- await statusCmd_walkBranchGraph({
144
- item: rootItem,
145
- space: activeBranchSpace,
146
- metaspace,
147
- currentRelPath: '',
148
- outMap: branchItemsMap,
149
- });
150
- }
151
- }
152
-
153
- // 5. Scan physical workspace
154
- const physicalItemsMap = new Map<string, { relPath: string; fullPath: string; isDirectory: boolean; fileHash?: string }>();
155
- await statusCmd_scanPhysicalWorkspace({
156
- dirPath: activeWorktreeDir,
157
- baseDir: activeWorktreeDir,
68
+ repoRoot,
158
69
  vcsFolderName,
159
- filterPatterns,
160
- outMap: physicalItemsMap,
161
70
  });
162
71
 
163
- // 6. Categorize items into staged, modified, deleted, untracked
164
- const staged: VcsStatusItem[] = [];
165
- const modified: VcsStatusItem[] = [];
166
- const deleted: VcsStatusItem[] = [];
167
- const untracked: VcsStatusItem[] = [];
168
-
169
- // Add staged items
170
- for (const [relPath, stagedRec] of stagedMap.entries()) {
171
- staged.push({
172
- path: relPath,
173
- fsType: stagedRec.fsType || 'file',
174
- status: 'staged',
175
- });
176
- }
177
-
178
- // Compare physical items against branch items and staged
179
- for (const [relPath, physItem] of physicalItemsMap.entries()) {
180
- if (stagedMap.has(relPath)) {
181
- continue; // Staged item already reported
182
- }
183
-
184
- const branchItem = branchItemsMap.get(relPath);
185
- if (!branchItem) {
186
- // Not in active branch snapshot and not staged => untracked
187
- untracked.push({
188
- path: relPath,
189
- fsType: physItem.isDirectory ? 'folder' : 'file',
190
- status: 'untracked',
191
- });
192
- } else {
193
- // Tracked in branch -> check if modified
194
- if (!physItem.isDirectory && physItem.fileHash && branchItem.fileHash && physItem.fileHash !== branchItem.fileHash) {
195
- modified.push({
196
- path: relPath,
197
- fsType: 'file',
198
- status: 'modified',
199
- });
200
- }
201
- }
202
- }
72
+ const { branchName, staged, modified, deleted, untracked, pendingComments } = statusRes;
203
73
 
204
- // Check for deleted items (in branch snapshot, but not in physical workspace and not staged)
205
- for (const [relPath, branchItem] of branchItemsMap.entries()) {
206
- if (!relPath || relPath === '.' || relPath === '') { continue; }
207
- if (!physicalItemsMap.has(relPath) && !stagedMap.has(relPath)) {
208
- deleted.push({
209
- path: relPath,
210
- fsType: branchItem.fsType,
211
- status: 'deleted',
212
- });
213
- }
74
+ const commentsByTarget = new Map<string, PendingCommentInfo[]>();
75
+ for (const c of pendingComments) {
76
+ const list = commentsByTarget.get(c.targetRelPath) || [];
77
+ list.push(c);
78
+ commentsByTarget.set(c.targetRelPath, list);
214
79
  }
215
80
 
216
81
  if (!quiet) {
217
82
  console.log(`On branch ${branchName} (I: 9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b)`);
83
+
218
84
  if (staged.length > 0) {
219
85
  console.log('\nChanges to be committed:');
220
86
  for (const item of staged) {
87
+ const itemComments = commentsByTarget.get(item.path) || [];
221
88
  console.log(` staged: ${item.path}`);
89
+ if (itemComments.length === 0) {
90
+ console.log(` (hint: no comment file found for ${item.path} - run 'vcs gmsg')`);
91
+ } else if (comments) {
92
+ for (const comm of itemComments) {
93
+ console.log(` [comment: ${comm.commentRelPath}]`);
94
+ const lines = comm.content.trim().split('\n');
95
+ for (const line of lines) {
96
+ console.log(` ${line}`);
97
+ }
98
+ }
99
+ }
222
100
  }
223
101
  }
102
+
224
103
  if (modified.length > 0 || deleted.length > 0) {
225
104
  console.log('\nChanges not staged for commit:');
226
105
  for (const item of modified) {
106
+ const itemComments = commentsByTarget.get(item.path) || [];
227
107
  console.log(` modified: ${item.path}`);
108
+ if (comments && itemComments.length > 0) {
109
+ for (const comm of itemComments) {
110
+ console.log(` [comment: ${comm.commentRelPath}]`);
111
+ const lines = comm.content.trim().split('\n');
112
+ for (const line of lines) {
113
+ console.log(` ${line}`);
114
+ }
115
+ }
116
+ }
228
117
  }
229
118
  for (const item of deleted) {
230
119
  console.log(` deleted: ${item.path}`);
231
120
  }
232
121
  }
122
+
233
123
  if (untracked.length > 0) {
234
124
  console.log('\nUntracked files:');
235
125
  for (const item of untracked) {
236
126
  console.log(` untracked:${item.path}`);
237
127
  }
238
128
  }
129
+
130
+ // Pending folder-level comments
131
+ const folderComments = pendingComments.filter(c => c.targetType === 'folder');
132
+ if (folderComments.length > 0) {
133
+ console.log('\nPending folder comments:');
134
+ for (const fc of folderComments) {
135
+ const folderLabel = fc.targetRelPath ? fc.targetRelPath : '(root)';
136
+ console.log(` folder: ${folderLabel} [${fc.commentRelPath}]`);
137
+ if (comments) {
138
+ const lines = fc.content.trim().split('\n');
139
+ for (const line of lines) {
140
+ console.log(` ${line}`);
141
+ }
142
+ }
143
+ }
144
+ }
145
+
239
146
  if (staged.length === 0 && modified.length === 0 && deleted.length === 0 && untracked.length === 0) {
240
147
  console.log('nothing to commit, working tree clean');
241
148
  }
@@ -247,6 +154,7 @@ export async function executeStatusCmd({
247
154
  modified,
248
155
  deleted,
249
156
  untracked,
157
+ pendingComments,
250
158
  };
251
159
  } catch (error) {
252
160
  console.error(`${lc} ${extractErrorMsg(error)} (E: 5e6f7a8b9c10d11e12f13a14b15c6d7e)`);
@@ -257,110 +165,3 @@ export async function executeStatusCmd({
257
165
  }
258
166
  }
259
167
  }
260
-
261
- // #region statusCmd_walkBranchGraph
262
- async function statusCmd_walkBranchGraph({
263
- item,
264
- space,
265
- metaspace,
266
- currentRelPath,
267
- outMap,
268
- }: {
269
- item: B2tFSItemIbGib_V1;
270
- space: any;
271
- metaspace?: any;
272
- currentRelPath: string;
273
- outMap: Map<string, { relPath: string; fileHash?: string; fsType: 'file' | 'folder' }>;
274
- }): Promise<void> {
275
- if (!item || !item.data) { return; }
276
-
277
- const { fsType, fileHash } = item.data;
278
- if (currentRelPath) {
279
- outMap.set(currentRelPath, { relPath: currentRelPath, fileHash, fsType });
280
- }
281
-
282
- if (fsType === 'folder') {
283
- const childAddrs = item.rel8ns?.[B2TFS_CHILD_ITEM_REL8N_NAME] || [];
284
- for (const childAddr of childAddrs) {
285
- const childItem = await getIbGibWithMetaspaceFallback({
286
- addr: childAddr,
287
- space,
288
- metaspace,
289
- }) as B2tFSItemIbGib_V1;
290
- if (childItem && childItem.data) {
291
- const childRelPath = currentRelPath
292
- ? `${currentRelPath}/${childItem.data.name}`
293
- : childItem.data.name;
294
- await statusCmd_walkBranchGraph({
295
- item: childItem,
296
- space,
297
- metaspace,
298
- currentRelPath: childRelPath,
299
- outMap,
300
- });
301
- }
302
- }
303
- }
304
- }
305
- // #endregion statusCmd_walkBranchGraph
306
-
307
- // #region statusCmd_scanPhysicalWorkspace
308
- async function statusCmd_scanPhysicalWorkspace({
309
- dirPath,
310
- baseDir,
311
- vcsFolderName,
312
- filterPatterns,
313
- outMap,
314
- }: {
315
- dirPath: string;
316
- baseDir: string;
317
- vcsFolderName: string;
318
- filterPatterns: string[];
319
- outMap: Map<string, { relPath: string; fullPath: string; isDirectory: boolean; fileHash?: string }>;
320
- }): Promise<void> {
321
- let entries: Dirent[] = [];
322
- try {
323
- entries = await fs.readdir(dirPath, { withFileTypes: true });
324
- } catch {
325
- return;
326
- }
327
-
328
- for (const entry of entries) {
329
- const fullEntryPath = path.join(dirPath, entry.name);
330
- const relPath = path.relative(baseDir, fullEntryPath).replace(/\\/g, '/');
331
-
332
- // Ignore vcs storage folder, .git, and worktrees folder b
333
- if (
334
- relPath === vcsFolderName || relPath.startsWith(vcsFolderName + '/') ||
335
- relPath === '.git' || relPath.startsWith('.git/') ||
336
- relPath === 'b' || relPath.startsWith('b/')
337
- ) {
338
- continue;
339
- }
340
-
341
- if (isPathFiltered({ relativePath: relPath, isDirectory: entry.isDirectory(), filterPatterns })) {
342
- continue;
343
- }
344
-
345
- if (entry.isDirectory()) {
346
- outMap.set(relPath, { relPath, fullPath: fullEntryPath, isDirectory: true });
347
- await statusCmd_scanPhysicalWorkspace({
348
- dirPath: fullEntryPath,
349
- baseDir,
350
- vcsFolderName,
351
- filterPatterns,
352
- outMap,
353
- });
354
- } else if (entry.isFile()) {
355
- let fileHash: string | undefined;
356
- try {
357
- const fileData = await fs.readFile(fullEntryPath);
358
- fileHash = crypto.createHash('sha256').update(fileData).digest('hex');
359
- } catch {
360
- // File unreadable
361
- }
362
- outMap.set(relPath, { relPath, fullPath: fullEntryPath, isDirectory: false, fileHash });
363
- }
364
- }
365
- }
366
- // #endregion statusCmd_scanPhysicalWorkspace
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
3
  * @module vcs-cli-main
4
- *
4
+ *
5
5
  * Executable CLI entry point for the `vcs` command line interface.
6
6
  * Parses command line arguments and dispatches execution to subcommand handlers.
7
7
  */
@@ -20,6 +20,7 @@ import { executeCheckoutCmd } from './commands/checkout-cmd.mjs';
20
20
  import { executeMergeCmd } from './commands/merge-cmd.mjs';
21
21
  import { executeResetCmd } from './commands/reset-cmd.mjs';
22
22
  import { executeRestoreCmd } from './commands/restore-cmd.mjs';
23
+ import { executeGenerateCommentCmd } from './commands/generate-comment-cmd.mjs';
23
24
  import { AUTO_GENERATED_VERSION } from '../AUTO-GENERATED-version.mjs';
24
25
  import { GLOBAL_LOG_A_LOT } from '../vcs-gib-constants.mjs';
25
26
 
@@ -39,7 +40,8 @@ Usage:
39
40
 
40
41
  Commands:
41
42
  init [dir] Initialize a new ibgib repository
42
- status Show repository working tree status
43
+ status Show repository working tree status (-c, --comments for comment text)
44
+ generate-comment Generate .ib.<file>.md metadata comment templates (synonyms: gmsg, gcomm, gen-msg, gen-comment)
43
45
  add <path...> Stage file/folder changes (-a, --all to stage all)
44
46
  commit -m "message" Record snapshot changes to the repository
45
47
  log Show commit logs
@@ -54,6 +56,7 @@ Flags:
54
56
  -v, --version Show version information
55
57
  -m <message> Commit message
56
58
  -b <branch> Target branch name
59
+ -c, --comments Show full comment content in status
57
60
  -a, --all Stage all tracked/untracked files (for add/reset)
58
61
  -s, --staged Unstage specified files from index (for restore)
59
62
  -w, --worktree Revert physical working tree files (for restore)
@@ -91,7 +94,20 @@ export async function main({
91
94
  }
92
95
  case VCS_SUBCOMMANDS.STATUS: {
93
96
  const targetDir = parsed.positionals[0] || process.cwd();
94
- await executeStatusCmd({ targetDir });
97
+ await executeStatusCmd({
98
+ targetDir,
99
+ comments: parsed.flags.comments,
100
+ });
101
+ break;
102
+ }
103
+ case VCS_SUBCOMMANDS.GENERATE_COMMENT:
104
+ case VCS_SUBCOMMANDS.GEN_COMMENT:
105
+ case VCS_SUBCOMMANDS.GEN_MSG:
106
+ case VCS_SUBCOMMANDS.GCOMM:
107
+ case VCS_SUBCOMMANDS.GMSG: {
108
+ await executeGenerateCommentCmd({
109
+ paths: parsed.positionals,
110
+ });
95
111
  break;
96
112
  }
97
113
  case VCS_SUBCOMMANDS.ADD: {
@@ -108,8 +124,13 @@ export async function main({
108
124
  break;
109
125
  }
110
126
  case VCS_SUBCOMMANDS.LOG: {
111
- const targetDir = parsed.positionals[0] || process.cwd();
112
- await executeLogCmd({ targetDir });
127
+ const targetDir = process.cwd();
128
+ const filePath = parsed.positionals[0];
129
+ await executeLogCmd({
130
+ targetDir,
131
+ filePath,
132
+ allComments: parsed.flags.all,
133
+ });
113
134
  break;
114
135
  }
115
136
  case VCS_SUBCOMMANDS.BRANCH: {
@@ -123,8 +144,8 @@ export async function main({
123
144
  break;
124
145
  }
125
146
  case VCS_SUBCOMMANDS.MERGE: {
126
- const targetBranchName = parsed.positionals[0] || parsed.flags.branchName;
127
- await executeMergeCmd({ targetBranchName });
147
+ const incomingBranchName = parsed.positionals[0] || parsed.flags.branchName;
148
+ await executeMergeCmd({ incomingBranchName });
128
149
  break;
129
150
  }
130
151
  case VCS_SUBCOMMANDS.RESET: {
@@ -321,6 +321,9 @@ export async function updateB2tFSIndexIbGib({
321
321
 
322
322
  const newIndexIbGib = res.newIbGib as B2tFSIndexIbGib_V1;
323
323
  await persistTransformResult({ resTransform: res, space });
324
+ if (metaspace.zeroSpace && metaspace.zeroSpace !== space) {
325
+ await persistTransformResult({ resTransform: res, space: metaspace.zeroSpace });
326
+ }
324
327
  await metaspace.registerNewIbGib({ ibGib: newIndexIbGib });
325
328
 
326
329
  if (vcsPath) {
@@ -14,11 +14,12 @@ 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
16
  import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
17
- import { TransformResult } from '@ibgib/ts-gib/dist/types.mjs';
17
+ import { TransformResult, IbGibAddr } from '@ibgib/ts-gib/dist/types.mjs';
18
18
  import { MetaspaceService } from '@ibgib/core-gib/dist/witness/space/metaspace/metaspace-types.mjs';
19
19
  import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
20
20
  import { isIbGib } from '@ibgib/core-gib/dist/common/other/ibgib-helper.mjs';
21
21
  import { persistTransformResult, getFromSpace } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
22
+ import { reifyDependencyGraph } from '@ibgib/core-gib/dist/common/other/graph-helper.mjs';
22
23
 
23
24
  import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
24
25
  import { parseSpaceQualifiedIbGibAddr } from '../index/index-helper.mjs';
@@ -241,8 +242,11 @@ function getSpacesArray(metaAny: any): IbGibSpaceAny[] {
241
242
  async function fetchFromSpaceSilently(spaceToQuery: IbGibSpaceAny, addrToGet: string): Promise<any> {
242
243
  try {
243
244
  const resGet = await getFromSpace({ space: spaceToQuery, addrs: [addrToGet] });
244
- if (resGet && resGet.success && resGet.ibGibs && resGet.ibGibs.length > 0) {
245
- return resGet.ibGibs[0];
245
+ if (resGet) {
246
+ const found = resGet.ibGibs?.find(x => !!x) || (resGet.rawResultIbGib as any)?.ibGibs?.find((x: any) => !!x);
247
+ if (found) {
248
+ return found;
249
+ }
246
250
  }
247
251
  } catch {
248
252
  // Suppress missing address error
@@ -469,3 +473,72 @@ export async function applyB2tFSItemDiff({
469
473
  }
470
474
  }
471
475
  }
476
+
477
+ // #region reifyB2tFSHierarchy
478
+
479
+ export interface ReifyB2tFSHierarchyOpts {
480
+ /** Root B2tFS item (folder or file). Either rootItem or rootItemAddr required. */
481
+ rootItem?: B2tFSItemIbGib_V1;
482
+ /** Address of root B2tFS item. Either rootItem or rootItemAddr required. */
483
+ rootItemAddr?: IbGibAddr;
484
+ /** Space containing the branch items and updated timeline tips. */
485
+ space: IbGibSpaceAny;
486
+ /** Metaspace service instance for lookups and registrations. */
487
+ metaspace: MetaspaceService;
488
+ }
489
+
490
+ export interface ReifyB2tFSHierarchyResult {
491
+ /** The reified root B2tFS item (evolved if any descendants changed, or unchanged if no descendants changed). */
492
+ reifiedRootItem: B2tFSItemIbGib_V1;
493
+ /** True if one or more folder/file nodes in the hierarchy evolved to new tips. */
494
+ hasChanges: boolean;
495
+ /** Map of old address -> new address for every node that evolved in this reification run. */
496
+ reifiedAddrsMap: { [oldAddr: string]: string };
497
+ /** All newly evolved and persisted intermediate/root folder items created during reification. */
498
+ evolvedItems: B2tFSItemIbGib_V1[];
499
+ }
500
+
501
+ /**
502
+ * Reifies a B2tFS filesystem item hierarchy (folders and files) bottom-up.
503
+ *
504
+ * Traverses `b2tfs_child` relationship edges. If any child timeline advanced
505
+ * in `space` (e.g. during a 3-way merge or parallel commit), the parent folders
506
+ * are evolved in-place using `rel8` with the updated child tip addresses.
507
+ */
508
+ export async function reifyB2tFSHierarchy({
509
+ rootItem,
510
+ rootItemAddr,
511
+ space,
512
+ metaspace,
513
+ }: ReifyB2tFSHierarchyOpts): Promise<ReifyB2tFSHierarchyResult> {
514
+ const lc = `${lcFile}[${reifyB2tFSHierarchy.name}]`;
515
+ try {
516
+ if (logalot) {
517
+ console.log(`${lc} starting... (I: 3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a)`);
518
+ }
519
+
520
+ const res = await reifyDependencyGraph({
521
+ ibGib: rootItem,
522
+ ibGibAddr: rootItemAddr,
523
+ onlyRel8nNames: [B2TFS_CHILD_ITEM_REL8N_NAME],
524
+ space,
525
+ metaspace,
526
+ });
527
+
528
+ return {
529
+ reifiedRootItem: res.reifiedIbGib as B2tFSItemIbGib_V1,
530
+ hasChanges: res.hasChanges,
531
+ reifiedAddrsMap: res.reifiedAddrsMap,
532
+ evolvedItems: res.evolvedIbGibs as B2tFSItemIbGib_V1[],
533
+ };
534
+ } catch (error) {
535
+ console.error(`${lc} ${extractErrorMsg(error)} (E: 4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b)`);
536
+ throw error;
537
+ } finally {
538
+ if (logalot) {
539
+ console.log(`${lc} complete. (I: 5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c)`);
540
+ }
541
+ }
542
+ }
543
+
544
+ // #endregion reifyB2tFSHierarchy