@ibgib/vcs-gib 0.0.6

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 (202) hide show
  1. package/README.md +94 -0
  2. package/VCS_CLI_USER_GUIDE.md +198 -0
  3. package/dist/AUTO-GENERATED-version.d.mts +6 -0
  4. package/dist/AUTO-GENERATED-version.d.mts.map +1 -0
  5. package/dist/AUTO-GENERATED-version.mjs +6 -0
  6. package/dist/AUTO-GENERATED-version.mjs.map +1 -0
  7. package/dist/assumptions.respec.d.mts +2 -0
  8. package/dist/assumptions.respec.d.mts.map +1 -0
  9. package/dist/assumptions.respec.mjs +41 -0
  10. package/dist/assumptions.respec.mjs.map +1 -0
  11. package/dist/bootstrap/node-bootstrap.d.mts +35 -0
  12. package/dist/bootstrap/node-bootstrap.d.mts.map +1 -0
  13. package/dist/bootstrap/node-bootstrap.mjs +165 -0
  14. package/dist/bootstrap/node-bootstrap.mjs.map +1 -0
  15. package/dist/bootstrap/node-bootstrap.respec.node.d.mts +7 -0
  16. package/dist/bootstrap/node-bootstrap.respec.node.d.mts.map +1 -0
  17. package/dist/bootstrap/node-bootstrap.respec.node.mjs +28 -0
  18. package/dist/bootstrap/node-bootstrap.respec.node.mjs.map +1 -0
  19. package/dist/cli/cli-arg-parser.d.mts +27 -0
  20. package/dist/cli/cli-arg-parser.d.mts.map +1 -0
  21. package/dist/cli/cli-arg-parser.mjs +96 -0
  22. package/dist/cli/cli-arg-parser.mjs.map +1 -0
  23. package/dist/cli/cli-arg-parser.respec.node.d.mts +7 -0
  24. package/dist/cli/cli-arg-parser.respec.node.d.mts.map +1 -0
  25. package/dist/cli/cli-arg-parser.respec.node.mjs +35 -0
  26. package/dist/cli/cli-arg-parser.respec.node.mjs.map +1 -0
  27. package/dist/cli/cli-constants.d.mts +26 -0
  28. package/dist/cli/cli-constants.d.mts.map +1 -0
  29. package/dist/cli/cli-constants.mjs +67 -0
  30. package/dist/cli/cli-constants.mjs.map +1 -0
  31. package/dist/cli/cli-e2e.respec.node.d.mts +8 -0
  32. package/dist/cli/cli-e2e.respec.node.d.mts.map +1 -0
  33. package/dist/cli/cli-e2e.respec.node.mjs +263 -0
  34. package/dist/cli/cli-e2e.respec.node.mjs.map +1 -0
  35. package/dist/cli/commands/add-cmd.d.mts +20 -0
  36. package/dist/cli/commands/add-cmd.d.mts.map +1 -0
  37. package/dist/cli/commands/add-cmd.mjs +333 -0
  38. package/dist/cli/commands/add-cmd.mjs.map +1 -0
  39. package/dist/cli/commands/branch-checkout-cmd.respec.node.d.mts +7 -0
  40. package/dist/cli/commands/branch-checkout-cmd.respec.node.d.mts.map +1 -0
  41. package/dist/cli/commands/branch-checkout-cmd.respec.node.mjs +288 -0
  42. package/dist/cli/commands/branch-checkout-cmd.respec.node.mjs.map +1 -0
  43. package/dist/cli/commands/branch-cmd.d.mts +25 -0
  44. package/dist/cli/commands/branch-cmd.d.mts.map +1 -0
  45. package/dist/cli/commands/branch-cmd.mjs +187 -0
  46. package/dist/cli/commands/branch-cmd.mjs.map +1 -0
  47. package/dist/cli/commands/checkout-cmd.d.mts +21 -0
  48. package/dist/cli/commands/checkout-cmd.d.mts.map +1 -0
  49. package/dist/cli/commands/checkout-cmd.mjs +154 -0
  50. package/dist/cli/commands/checkout-cmd.mjs.map +1 -0
  51. package/dist/cli/commands/commit-cmd.d.mts +23 -0
  52. package/dist/cli/commands/commit-cmd.d.mts.map +1 -0
  53. package/dist/cli/commands/commit-cmd.mjs +326 -0
  54. package/dist/cli/commands/commit-cmd.mjs.map +1 -0
  55. package/dist/cli/commands/commit-log-cmd.respec.node.d.mts +7 -0
  56. package/dist/cli/commands/commit-log-cmd.respec.node.d.mts.map +1 -0
  57. package/dist/cli/commands/commit-log-cmd.respec.node.mjs +251 -0
  58. package/dist/cli/commands/commit-log-cmd.respec.node.mjs.map +1 -0
  59. package/dist/cli/commands/init-cmd.d.mts +20 -0
  60. package/dist/cli/commands/init-cmd.d.mts.map +1 -0
  61. package/dist/cli/commands/init-cmd.mjs +119 -0
  62. package/dist/cli/commands/init-cmd.mjs.map +1 -0
  63. package/dist/cli/commands/init-cmd.respec.node.d.mts +7 -0
  64. package/dist/cli/commands/init-cmd.respec.node.d.mts.map +1 -0
  65. package/dist/cli/commands/init-cmd.respec.node.mjs +40 -0
  66. package/dist/cli/commands/init-cmd.respec.node.mjs.map +1 -0
  67. package/dist/cli/commands/log-cmd.d.mts +27 -0
  68. package/dist/cli/commands/log-cmd.d.mts.map +1 -0
  69. package/dist/cli/commands/log-cmd.mjs +146 -0
  70. package/dist/cli/commands/log-cmd.mjs.map +1 -0
  71. package/dist/cli/commands/status-add-cmd.respec.node.d.mts +7 -0
  72. package/dist/cli/commands/status-add-cmd.respec.node.d.mts.map +1 -0
  73. package/dist/cli/commands/status-add-cmd.respec.node.mjs +215 -0
  74. package/dist/cli/commands/status-add-cmd.respec.node.mjs.map +1 -0
  75. package/dist/cli/commands/status-cmd.d.mts +25 -0
  76. package/dist/cli/commands/status-cmd.d.mts.map +1 -0
  77. package/dist/cli/commands/status-cmd.mjs +286 -0
  78. package/dist/cli/commands/status-cmd.mjs.map +1 -0
  79. package/dist/cli/vcs-cli-main.d.mts +14 -0
  80. package/dist/cli/vcs-cli-main.d.mts.map +1 -0
  81. package/dist/cli/vcs-cli-main.mjs +136 -0
  82. package/dist/cli/vcs-cli-main.mjs.map +1 -0
  83. package/dist/engine/branch/branch-graph-helper.d.mts +19 -0
  84. package/dist/engine/branch/branch-graph-helper.d.mts.map +1 -0
  85. package/dist/engine/branch/branch-graph-helper.mjs +49 -0
  86. package/dist/engine/branch/branch-graph-helper.mjs.map +1 -0
  87. package/dist/engine/branch/branch-helper.d.mts +26 -0
  88. package/dist/engine/branch/branch-helper.d.mts.map +1 -0
  89. package/dist/engine/branch/branch-helper.mjs +57 -0
  90. package/dist/engine/branch/branch-helper.mjs.map +1 -0
  91. package/dist/engine/branch/branch-space-helper.d.mts +22 -0
  92. package/dist/engine/branch/branch-space-helper.d.mts.map +1 -0
  93. package/dist/engine/branch/branch-space-helper.mjs +77 -0
  94. package/dist/engine/branch/branch-space-helper.mjs.map +1 -0
  95. package/dist/engine/branch/branch-space.respec.node.d.mts +8 -0
  96. package/dist/engine/branch/branch-space.respec.node.d.mts.map +1 -0
  97. package/dist/engine/branch/branch-space.respec.node.mjs +138 -0
  98. package/dist/engine/branch/branch-space.respec.node.mjs.map +1 -0
  99. package/dist/engine/branch/branch-types.d.mts +26 -0
  100. package/dist/engine/branch/branch-types.d.mts.map +1 -0
  101. package/dist/engine/branch/branch-types.mjs +7 -0
  102. package/dist/engine/branch/branch-types.mjs.map +1 -0
  103. package/dist/engine/diff/line-diff-helper.d.mts +76 -0
  104. package/dist/engine/diff/line-diff-helper.d.mts.map +1 -0
  105. package/dist/engine/diff/line-diff-helper.mjs +144 -0
  106. package/dist/engine/diff/line-diff-helper.mjs.map +1 -0
  107. package/dist/engine/diff/line-diff-helper.respec.node.d.mts +7 -0
  108. package/dist/engine/diff/line-diff-helper.respec.node.d.mts.map +1 -0
  109. package/dist/engine/diff/line-diff-helper.respec.node.mjs +66 -0
  110. package/dist/engine/diff/line-diff-helper.respec.node.mjs.map +1 -0
  111. package/dist/engine/filter/glob-helper.d.mts +51 -0
  112. package/dist/engine/filter/glob-helper.d.mts.map +1 -0
  113. package/dist/engine/filter/glob-helper.mjs +132 -0
  114. package/dist/engine/filter/glob-helper.mjs.map +1 -0
  115. package/dist/engine/filter/glob-helper.respec.node.d.mts +7 -0
  116. package/dist/engine/filter/glob-helper.respec.node.d.mts.map +1 -0
  117. package/dist/engine/filter/glob-helper.respec.node.mjs +78 -0
  118. package/dist/engine/filter/glob-helper.respec.node.mjs.map +1 -0
  119. package/dist/engine/index/index-helper.d.mts +78 -0
  120. package/dist/engine/index/index-helper.d.mts.map +1 -0
  121. package/dist/engine/index/index-helper.mjs +289 -0
  122. package/dist/engine/index/index-helper.mjs.map +1 -0
  123. package/dist/engine/index/index-types.d.mts +63 -0
  124. package/dist/engine/index/index-types.d.mts.map +1 -0
  125. package/dist/engine/index/index-types.mjs +7 -0
  126. package/dist/engine/index/index-types.mjs.map +1 -0
  127. package/dist/engine/item/item-atom-helper.d.mts +20 -0
  128. package/dist/engine/item/item-atom-helper.d.mts.map +1 -0
  129. package/dist/engine/item/item-atom-helper.mjs +30 -0
  130. package/dist/engine/item/item-atom-helper.mjs.map +1 -0
  131. package/dist/engine/item/item-helper.d.mts +37 -0
  132. package/dist/engine/item/item-helper.d.mts.map +1 -0
  133. package/dist/engine/item/item-helper.mjs +194 -0
  134. package/dist/engine/item/item-helper.mjs.map +1 -0
  135. package/dist/engine/item/item-types.d.mts +127 -0
  136. package/dist/engine/item/item-types.d.mts.map +1 -0
  137. package/dist/engine/item/item-types.mjs +16 -0
  138. package/dist/engine/item/item-types.mjs.map +1 -0
  139. package/dist/index.d.mts +7 -0
  140. package/dist/index.d.mts.map +1 -0
  141. package/dist/index.mjs +7 -0
  142. package/dist/index.mjs.map +1 -0
  143. package/dist/respec-gib.node.d.mts +7 -0
  144. package/dist/respec-gib.node.d.mts.map +1 -0
  145. package/dist/respec-gib.node.mjs +11 -0
  146. package/dist/respec-gib.node.mjs.map +1 -0
  147. package/dist/vcs-gib-constants.d.mts +7 -0
  148. package/dist/vcs-gib-constants.d.mts.map +1 -0
  149. package/dist/vcs-gib-constants.mjs +7 -0
  150. package/dist/vcs-gib-constants.mjs.map +1 -0
  151. package/dist/vcs-gib.respec.node.d.mts +8 -0
  152. package/dist/vcs-gib.respec.node.d.mts.map +1 -0
  153. package/dist/vcs-gib.respec.node.mjs +82 -0
  154. package/dist/vcs-gib.respec.node.mjs.map +1 -0
  155. package/generate-version-file.js +20 -0
  156. package/package.json +28 -0
  157. package/src/AUTO-GENERATED-version.mts +5 -0
  158. package/src/assumptions.respec.mts +50 -0
  159. package/src/bootstrap/node-bootstrap.mts +198 -0
  160. package/src/bootstrap/node-bootstrap.respec.node.mts +35 -0
  161. package/src/cli/cli-arg-parser.mts +119 -0
  162. package/src/cli/cli-arg-parser.respec.node.mts +45 -0
  163. package/src/cli/cli-constants.mts +77 -0
  164. package/src/cli/cli-e2e.respec.node.mts +318 -0
  165. package/src/cli/commands/add-cmd.mts +415 -0
  166. package/src/cli/commands/branch-checkout-cmd.respec.node.mts +322 -0
  167. package/src/cli/commands/branch-cmd.mts +243 -0
  168. package/src/cli/commands/checkout-cmd.mts +202 -0
  169. package/src/cli/commands/commit-cmd.mts +421 -0
  170. package/src/cli/commands/commit-log-cmd.respec.node.mts +276 -0
  171. package/src/cli/commands/init-cmd.mts +152 -0
  172. package/src/cli/commands/init-cmd.respec.node.mts +49 -0
  173. package/src/cli/commands/log-cmd.mts +197 -0
  174. package/src/cli/commands/status-add-cmd.respec.node.mts +246 -0
  175. package/src/cli/commands/status-cmd.mts +366 -0
  176. package/src/cli/vcs-cli-main.mts +153 -0
  177. package/src/engine/branch/branch-graph-helper.mts +69 -0
  178. package/src/engine/branch/branch-helper.mts +79 -0
  179. package/src/engine/branch/branch-space-helper.mts +104 -0
  180. package/src/engine/branch/branch-space.respec.node.mts +158 -0
  181. package/src/engine/branch/branch-types.mts +29 -0
  182. package/src/engine/diff/line-diff-helper.mts +210 -0
  183. package/src/engine/diff/line-diff-helper.respec.node.mts +84 -0
  184. package/src/engine/filter/glob-helper.mts +165 -0
  185. package/src/engine/filter/glob-helper.respec.node.mts +94 -0
  186. package/src/engine/index/index-helper.mts +378 -0
  187. package/src/engine/index/index-types.mts +66 -0
  188. package/src/engine/item/item-atom-helper.mts +30 -0
  189. package/src/engine/item/item-helper.mts +239 -0
  190. package/src/engine/item/item-types.mts +136 -0
  191. package/src/index.mts +7 -0
  192. package/src/respec-gib.node.mts +12 -0
  193. package/src/vcs-gib-constants.mts +7 -0
  194. package/src/vcs-gib.respec.node.mts +96 -0
  195. package/test_runs/001-hello-node/20260728_090100_0001-flow-core-main.md +39 -0
  196. package/test_runs/001-hello-node/20260728_090200_0003-flow-branching-worktree.md +54 -0
  197. package/test_runs/001-hello-node/20260728_090300_0002-flow-selective-add.md +45 -0
  198. package/test_runs/001-hello-node/20260728_142100_0007-flow-edge-cases.md +44 -0
  199. package/test_runs/001-hello-node/20260728_142400_0005-flow-hardcoded-ignores.md +36 -0
  200. package/tools/pack-for-test.mjs +73 -0
  201. package/tsconfig.json +18 -0
  202. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,415 @@
1
+ /**
2
+ * @module add-cmd
3
+ *
4
+ * Command handler for `vcs add <path...>`.
5
+ * Stages files and directories into candidate B2tFSItemIbGib_V1 and BinIbGib_V1 graph nodes
6
+ * and updates B2tFSIndexIbGib_V1 in localSpace.
7
+ */
8
+
9
+ import path from 'node:path';
10
+ import fs from 'node:fs/promises';
11
+ import crypto from 'node:crypto';
12
+
13
+ import { extractErrorMsg, getUUID } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
14
+ import { Factory_V1 } from '@ibgib/ts-gib/dist/V1/factory.mjs';
15
+ import { ROOT } from '@ibgib/ts-gib/dist/V1/constants.mjs';
16
+ import { getGib } from '@ibgib/ts-gib/dist/V1/transforms/transform-helper.mjs';
17
+ import { getIbGibAddr } from '@ibgib/ts-gib/dist/helper.mjs';
18
+ import { BinIbGib_V1 } from '@ibgib/core-gib/dist/common/bin/bin-types.mjs';
19
+ import { putInSpace, persistTransformResult } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
20
+
21
+ import { bootstrapVcsMetaspace } from '../../bootstrap/node-bootstrap.mjs';
22
+ import { getOrCreateBranchSpace } from '../../engine/branch/branch-space-helper.mjs';
23
+ import { getB2tFSItemIb } from '../../engine/item/item-atom-helper.mjs';
24
+ import { B2tFSItemIbGib_V1, B2TFS_CHILD_ITEM_REL8N_NAME } from '../../engine/item/item-types.mjs';
25
+ import { getIbGibWithMetaspaceFallback } from '../../engine/item/item-helper.mjs';
26
+ import { B2tFSBranchIbGib_V1 } from '../../engine/branch/branch-types.mjs';
27
+ import { isPathFiltered, parseFilterFileContent, globToRegExp } from '../../engine/filter/glob-helper.mjs';
28
+ import { getB2tFSIndexIbGib, updateB2tFSIndexIbGib } from '../../engine/index/index-helper.mjs';
29
+ import { B2tFSStagedItemRecord } from '../../engine/index/index-types.mjs';
30
+ import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
31
+
32
+ const lcFile = `[add-cmd]`;
33
+ const logalot = GLOBAL_LOG_A_LOT;
34
+
35
+ export interface AddCmdOpts {
36
+ paths?: string[];
37
+ targetDir?: string;
38
+ vcsFolderName?: string;
39
+ all?: boolean;
40
+ quiet?: boolean;
41
+ }
42
+
43
+ export interface AddCmdResult {
44
+ stagedPaths: string[];
45
+ stagedCount: number;
46
+ }
47
+
48
+ export async function executeAddCmd({
49
+ paths = [],
50
+ targetDir = process.cwd(),
51
+ vcsFolderName = '.vcsgib',
52
+ all = false,
53
+ quiet = false,
54
+ }: AddCmdOpts = {}): Promise<AddCmdResult> {
55
+ const lc = `${lcFile}[${executeAddCmd.name}]`;
56
+ try {
57
+ if (logalot) { console.log(`${lc} starting... (I: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d)`); }
58
+
59
+ const absTargetDir = path.resolve(targetDir);
60
+
61
+ const { metaspace, localSpace, vcsPath, repoRoot } = await bootstrapVcsMetaspace({
62
+ repoPath: absTargetDir,
63
+ vcsFolderName,
64
+ });
65
+
66
+ // Verify repo exists
67
+ try {
68
+ await fs.access(vcsPath);
69
+ } catch {
70
+ throw new Error(`Not an ibgib repository (directory ${vcsPath} does not exist) (E: 2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d)`);
71
+ }
72
+
73
+ // Retrieve authoritative B2tFSIndexIbGib_V1 from space
74
+ const indexIbGib = await getB2tFSIndexIbGib({ space: localSpace, vcsPath });
75
+ if (!indexIbGib) {
76
+ throw new Error(`Repository not initialized. Run 'vcs init' first. (E: 2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e)`);
77
+ }
78
+
79
+ const activeBranch = indexIbGib.data?.activeBranch || 'main';
80
+ const activeWorktreeDir = activeBranch === 'main' ? repoRoot : path.join(repoRoot, 'b', activeBranch);
81
+
82
+ // Target active branch space b2s_<activeBranch>
83
+ const { space: activeSpace } = await getOrCreateBranchSpace({
84
+ metaspace,
85
+ vcsPath,
86
+ branchName: activeBranch,
87
+ });
88
+
89
+ // Read .ibgibignore if present in active worktree
90
+ let filterPatterns: string[] = [];
91
+ const ignorePath = path.join(activeWorktreeDir, '.ibgibignore');
92
+ try {
93
+ const ignoreContent = await fs.readFile(ignorePath, 'utf8');
94
+ filterPatterns = parseFilterFileContent(ignoreContent);
95
+ } catch {
96
+ // Ignore file not found is fine
97
+ }
98
+
99
+ // Walk active branch graph items to find committed files in snapshot
100
+ const committedBranchItemsMap = new Map<string, { relPath: string; fileHash?: string; fsType: 'file' | 'folder' }>();
101
+ const branchAddrs = [
102
+ ...(indexIbGib?.rel8ns?.branch || []),
103
+ ...(indexIbGib?.rel8ns?.branch_tjp || []),
104
+ ];
105
+
106
+ if (branchAddrs.length > 0) {
107
+ let branchIbGibs: B2tFSBranchIbGib_V1[] = [];
108
+ for (const bAddr of branchAddrs) {
109
+ const bIbGib = await getIbGibWithMetaspaceFallback({
110
+ addr: bAddr,
111
+ space: activeSpace,
112
+ metaspace,
113
+ });
114
+ if (bIbGib) {
115
+ branchIbGibs.push(bIbGib as B2tFSBranchIbGib_V1);
116
+ }
117
+ }
118
+
119
+ const activeBranchIbGib = branchIbGibs.find(
120
+ (b) => (b as B2tFSBranchIbGib_V1)?.data?.name === activeBranch,
121
+ ) as B2tFSBranchIbGib_V1 || (branchIbGibs.at(0) as B2tFSBranchIbGib_V1);
122
+
123
+ const rootItemAddr = activeBranchIbGib?.rel8ns?.b2tfs_item?.at(0);
124
+ if (rootItemAddr) {
125
+ const rootItem = await getIbGibWithMetaspaceFallback({
126
+ addr: rootItemAddr,
127
+ space: activeSpace,
128
+ metaspace,
129
+ }) as B2tFSItemIbGib_V1;
130
+
131
+ if (rootItem) {
132
+ await addCmd_walkBranchGraph({
133
+ item: rootItem,
134
+ space: activeSpace,
135
+ metaspace,
136
+ currentRelPath: '',
137
+ outMap: committedBranchItemsMap,
138
+ });
139
+ }
140
+ }
141
+ }
142
+
143
+ // Determine candidate file paths to stage
144
+ const targetFilePaths: string[] = [];
145
+
146
+ if (all || paths.length === 0 || (paths.length === 1 && paths[0] === '.')) {
147
+ await addCmd_collectFilesRecursively({
148
+ dirPath: activeWorktreeDir,
149
+ baseDir: activeWorktreeDir,
150
+ vcsFolderName,
151
+ filterPatterns,
152
+ outFiles: targetFilePaths,
153
+ });
154
+ } else {
155
+ for (const relOrAbs of paths) {
156
+ if (relOrAbs.includes('*') || relOrAbs.includes('?')) {
157
+ const rx = globToRegExp(relOrAbs);
158
+
159
+ const candidateFiles: string[] = [];
160
+ await addCmd_collectFilesRecursively({
161
+ dirPath: activeWorktreeDir,
162
+ baseDir: activeWorktreeDir,
163
+ vcsFolderName,
164
+ filterPatterns,
165
+ outFiles: candidateFiles,
166
+ });
167
+
168
+ let matchedCount = 0;
169
+ for (const candidateAbsPath of candidateFiles) {
170
+ const candidateRelPath = path.relative(activeWorktreeDir, candidateAbsPath).replace(/\\/g, '/');
171
+ const pathBasename = candidateRelPath.split('/').pop() || candidateRelPath;
172
+
173
+ if (rx.test(candidateRelPath) || rx.test(pathBasename)) {
174
+ if (!targetFilePaths.includes(candidateAbsPath)) {
175
+ targetFilePaths.push(candidateAbsPath);
176
+ }
177
+ matchedCount++;
178
+ }
179
+ }
180
+
181
+ if (matchedCount === 0) {
182
+ throw new Error(`No files matched glob pattern: ${relOrAbs} (E: e23d4c5f6a7b8c9d0e1f2a3b4c5d6e7f)`);
183
+ }
184
+ } else {
185
+ const fullPath = path.resolve(activeWorktreeDir, relOrAbs);
186
+ let stat;
187
+ try {
188
+ stat = await fs.stat(fullPath);
189
+ } catch {
190
+ throw new Error(`Path does not exist: ${relOrAbs} (E: 10c11d12e13f14a15b16c17d18e19f20)`);
191
+ }
192
+
193
+ const relPath = path.relative(activeWorktreeDir, fullPath).replace(/\\/g, '/');
194
+
195
+ if (isPathFiltered({ relativePath: relPath, isDirectory: stat.isDirectory(), filterPatterns })) {
196
+ continue;
197
+ }
198
+
199
+ if (stat.isDirectory()) {
200
+ await addCmd_collectFilesRecursively({
201
+ dirPath: fullPath,
202
+ baseDir: activeWorktreeDir,
203
+ vcsFolderName,
204
+ filterPatterns,
205
+ outFiles: targetFilePaths,
206
+ });
207
+ } else if (stat.isFile()) {
208
+ if (!targetFilePaths.includes(fullPath)) {
209
+ targetFilePaths.push(fullPath);
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
215
+
216
+ const stagedItemAddrs: string[] = [...(indexIbGib.data?.staged_item || [])];
217
+ const stagedPathsMap: { [relPath: string]: B2tFSStagedItemRecord } = { ...(indexIbGib.data?.stagedPaths || {}) };
218
+ const newlyStagedPaths: string[] = [];
219
+
220
+ for (const absFilePath of targetFilePaths) {
221
+ const relPath = path.relative(activeWorktreeDir, absFilePath).replace(/\\/g, '/');
222
+
223
+ // Read file data & compute hash
224
+ const fileData = await fs.readFile(absFilePath);
225
+ const fileHash = crypto.createHash('sha256').update(fileData).digest('hex');
226
+
227
+ // Skip staging if candidate file matches active branch committed snapshot
228
+ const committedItem = committedBranchItemsMap.get(relPath);
229
+ if (committedItem && committedItem.fileHash && committedItem.fileHash === fileHash) {
230
+ continue;
231
+ }
232
+
233
+ // 1. Create BinIbGib_V1 graph node as Uint8Array
234
+ const binData = new Uint8Array(fileData);
235
+ const binIb = `bin ${fileHash}`;
236
+ const binGib = await getGib({ ibGib: { ib: binIb, data: binData as any } });
237
+ const binIbGib: BinIbGib_V1 = {
238
+ ib: binIb,
239
+ gib: binGib,
240
+ data: binData as any,
241
+ };
242
+ const binAddr = getIbGibAddr({ ibGib: binIbGib });
243
+ await putInSpace({ ibGib: binIbGib, space: activeSpace });
244
+ await metaspace.registerNewIbGib({ ibGib: binIbGib, space: activeSpace });
245
+
246
+ // 2. Create B2tFSItemIbGib_V1 candidate graph node
247
+ const fileName = path.basename(absFilePath);
248
+ const fileNameSansExt = path.parse(fileName).name;
249
+ const fileExt = path.parse(fileName).ext.replace(/^\./, '');
250
+ const nameHash = crypto.createHash('sha256').update(fileName).digest('hex');
251
+
252
+ const itemRes = await Factory_V1.firstGen({
253
+ parentIbGib: ROOT,
254
+ ib: getB2tFSItemIb('file', fileName, nameHash),
255
+ data: {
256
+ name: fileName,
257
+ nameHash,
258
+ fsType: 'file',
259
+ fileNameSansExt,
260
+ fileExt,
261
+ fileHash,
262
+ fileEncoding: 'utf8',
263
+ diffTransactionId: await getUUID(),
264
+ uuid: await getUUID(),
265
+ classname: 'B2tFSItemIbGib_V1',
266
+ },
267
+ rel8ns: {
268
+ bin: [binAddr],
269
+ },
270
+ });
271
+ const itemIbGib = itemRes.newIbGib as B2tFSItemIbGib_V1;
272
+ const itemAddr = getIbGibAddr({ ibGib: itemIbGib });
273
+ await persistTransformResult({ resTransform: itemRes, space: activeSpace });
274
+ await metaspace.registerNewIbGib({ ibGib: itemIbGib, space: activeSpace });
275
+
276
+ if (!stagedItemAddrs.includes(itemAddr)) {
277
+ stagedItemAddrs.push(itemAddr);
278
+ }
279
+
280
+ stagedPathsMap[relPath] = {
281
+ itemAddr,
282
+ binAddr,
283
+ fileHash,
284
+ fsType: 'file',
285
+ stagedAt: new Date().toISOString(),
286
+ };
287
+
288
+ newlyStagedPaths.push(relPath);
289
+
290
+ if (!quiet) {
291
+ console.log(`staged: ${relPath}`);
292
+ }
293
+ }
294
+
295
+ // 3. Update B2tFSIndexIbGib_V1 in activeSpace & localSpace
296
+ const updatedIndex = await updateB2tFSIndexIbGib({
297
+ space: activeSpace,
298
+ metaspace,
299
+ indexIbGib,
300
+ dataToUpdate: {
301
+ stagedPaths: stagedPathsMap,
302
+ staged_item: stagedItemAddrs,
303
+ },
304
+ vcsPath,
305
+ });
306
+
307
+ if (localSpace !== activeSpace) {
308
+ await putInSpace({ space: localSpace, ibGib: updatedIndex });
309
+ }
310
+
311
+ return {
312
+ stagedPaths: newlyStagedPaths,
313
+ stagedCount: newlyStagedPaths.length,
314
+ };
315
+ } catch (error) {
316
+ console.error(`${lc} ${extractErrorMsg(error)} (E: 3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f)`);
317
+ throw error;
318
+ } finally {
319
+ if (logalot) { console.log(`${lc} complete. (I: 4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a)`); }
320
+ }
321
+ }
322
+
323
+ // #region addCmd_walkBranchGraph
324
+ async function addCmd_walkBranchGraph({
325
+ item,
326
+ space,
327
+ metaspace,
328
+ currentRelPath,
329
+ outMap,
330
+ }: {
331
+ item: B2tFSItemIbGib_V1;
332
+ space: any;
333
+ metaspace?: any;
334
+ currentRelPath: string;
335
+ outMap: Map<string, { relPath: string; fileHash?: string; fsType: 'file' | 'folder' }>;
336
+ }): Promise<void> {
337
+ if (!item || !item.data) { return; }
338
+
339
+ const { fsType, fileHash } = item.data;
340
+ if (currentRelPath) {
341
+ outMap.set(currentRelPath, { relPath: currentRelPath, fileHash, fsType });
342
+ }
343
+
344
+ if (fsType === 'folder') {
345
+ const childAddrs = item.rel8ns?.[B2TFS_CHILD_ITEM_REL8N_NAME] || [];
346
+ for (const childAddr of childAddrs) {
347
+ const childItem = await getIbGibWithMetaspaceFallback({
348
+ addr: childAddr,
349
+ space,
350
+ metaspace,
351
+ }) as B2tFSItemIbGib_V1;
352
+ if (childItem && childItem.data) {
353
+ const childRelPath = currentRelPath
354
+ ? `${currentRelPath}/${childItem.data.name}`
355
+ : childItem.data.name;
356
+ await addCmd_walkBranchGraph({
357
+ item: childItem,
358
+ space,
359
+ metaspace,
360
+ currentRelPath: childRelPath,
361
+ outMap,
362
+ });
363
+ }
364
+ }
365
+ }
366
+ }
367
+ // #endregion addCmd_walkBranchGraph
368
+
369
+ // #region addCmd_collectFilesRecursively
370
+ async function addCmd_collectFilesRecursively({
371
+ dirPath,
372
+ baseDir,
373
+ vcsFolderName,
374
+ filterPatterns,
375
+ outFiles,
376
+ }: {
377
+ dirPath: string;
378
+ baseDir: string;
379
+ vcsFolderName: string;
380
+ filterPatterns: string[];
381
+ outFiles: string[];
382
+ }): Promise<void> {
383
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
384
+
385
+ for (const entry of entries) {
386
+ const fullPath = path.join(dirPath, entry.name);
387
+ const relPath = path.relative(baseDir, fullPath).replace(/\\/g, '/');
388
+
389
+ // Ignore vcs storage folder, .git, and worktrees folder b
390
+ if (
391
+ relPath === vcsFolderName || relPath.startsWith(vcsFolderName + '/') ||
392
+ relPath === '.git' || relPath.startsWith('.git/') ||
393
+ relPath === 'b' || relPath.startsWith('b/')
394
+ ) {
395
+ continue;
396
+ }
397
+
398
+ if (isPathFiltered({ relativePath: relPath, isDirectory: entry.isDirectory(), filterPatterns })) {
399
+ continue;
400
+ }
401
+
402
+ if (entry.isDirectory()) {
403
+ await addCmd_collectFilesRecursively({
404
+ dirPath: fullPath,
405
+ baseDir,
406
+ vcsFolderName,
407
+ filterPatterns,
408
+ outFiles,
409
+ });
410
+ } else if (entry.isFile()) {
411
+ outFiles.push(fullPath);
412
+ }
413
+ }
414
+ }
415
+ // #endregion addCmd_collectFilesRecursively