@eldrforge/kodrdriv 1.2.29 → 1.2.124

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 (84) hide show
  1. package/dist/application.js +16 -13
  2. package/dist/application.js.map +1 -1
  3. package/dist/arguments.js +5 -5
  4. package/dist/arguments.js.map +1 -1
  5. package/dist/commands/audio-review.js +2 -5
  6. package/dist/commands/audio-review.js.map +1 -1
  7. package/dist/commands/clean.js +2 -4
  8. package/dist/commands/clean.js.map +1 -1
  9. package/dist/commands/commit.js +3 -6
  10. package/dist/commands/commit.js.map +1 -1
  11. package/dist/commands/development.js +7 -7
  12. package/dist/commands/development.js.map +1 -1
  13. package/dist/commands/link.js +3 -7
  14. package/dist/commands/link.js.map +1 -1
  15. package/dist/commands/precommit.js +99 -0
  16. package/dist/commands/precommit.js.map +1 -0
  17. package/dist/commands/publish.js +47 -32
  18. package/dist/commands/publish.js.map +1 -1
  19. package/dist/commands/release.js +3 -7
  20. package/dist/commands/release.js.map +1 -1
  21. package/dist/commands/review.js +4 -6
  22. package/dist/commands/review.js.map +1 -1
  23. package/dist/commands/tree.js +213 -84
  24. package/dist/commands/tree.js.map +1 -1
  25. package/dist/commands/unlink.js +3 -7
  26. package/dist/commands/unlink.js.map +1 -1
  27. package/dist/commands/updates.js +2 -4
  28. package/dist/commands/updates.js.map +1 -1
  29. package/dist/commands/versions.js +3 -7
  30. package/dist/commands/versions.js.map +1 -1
  31. package/dist/constants.js +4 -2
  32. package/dist/constants.js.map +1 -1
  33. package/dist/content/files.js +2 -4
  34. package/dist/content/files.js.map +1 -1
  35. package/dist/execution/CommandValidator.js +33 -1
  36. package/dist/execution/CommandValidator.js.map +1 -1
  37. package/dist/execution/ResourceMonitor.js +26 -1
  38. package/dist/execution/ResourceMonitor.js.map +1 -1
  39. package/dist/execution/TreeExecutionAdapter.js +2 -2
  40. package/dist/execution/TreeExecutionAdapter.js.map +1 -1
  41. package/dist/util/checkpointManager.js +2 -4
  42. package/dist/util/checkpointManager.js.map +1 -1
  43. package/dist/util/dependencyGraph.js +2 -4
  44. package/dist/util/dependencyGraph.js.map +1 -1
  45. package/dist/util/general.js +8 -219
  46. package/dist/util/general.js.map +1 -1
  47. package/dist/util/gitMutex.js +63 -18
  48. package/dist/util/gitMutex.js.map +1 -1
  49. package/dist/util/precommitOptimizations.js +310 -0
  50. package/dist/util/precommitOptimizations.js.map +1 -0
  51. package/dist/util/storageAdapter.js +2 -6
  52. package/dist/util/storageAdapter.js.map +1 -1
  53. package/dist/util/validation.js +3 -3
  54. package/dist/util/validation.js.map +1 -1
  55. package/dist/utils/branchState.js +178 -45
  56. package/dist/utils/branchState.js.map +1 -1
  57. package/package.json +6 -5
  58. package/AI-FRIENDLY-LOGGING-GUIDE.md +0 -237
  59. package/AI-LOGGING-MIGRATION-COMPLETE.md +0 -371
  60. package/ALREADY-PUBLISHED-PACKAGES-FIX.md +0 -264
  61. package/AUDIT-BRANCHES-PROGRESS-FIX.md +0 -90
  62. package/AUDIT-EXAMPLE-OUTPUT.md +0 -113
  63. package/CHECKPOINT-RECOVERY-FIX.md +0 -450
  64. package/LOGGING-MIGRATION-STATUS.md +0 -186
  65. package/MONOREPO-PUBLISH-IMPROVEMENTS.md +0 -281
  66. package/PARALLEL-EXECUTION-FIXES.md +0 -132
  67. package/PARALLEL-PUBLISH-DEBUGGING-GUIDE.md +0 -441
  68. package/PARALLEL-PUBLISH-FIXES-IMPLEMENTED.md +0 -405
  69. package/PARALLEL-PUBLISH-IMPROVEMENTS-IMPLEMENTED.md +0 -439
  70. package/PARALLEL-PUBLISH-LOGGING-FIXES.md +0 -274
  71. package/PARALLEL-PUBLISH-QUICK-REFERENCE.md +0 -375
  72. package/PARALLEL_EXECUTION_FIX.md +0 -146
  73. package/PUBLISH_IMPROVEMENTS_IMPLEMENTED.md +0 -294
  74. package/RECOVERY-FIXES.md +0 -72
  75. package/SUBMODULE-LOCK-FIX.md +0 -132
  76. package/VERSION-AUDIT-FIX.md +0 -333
  77. package/WORKFLOW-PRECHECK-IMPLEMENTATION.md +0 -239
  78. package/WORKFLOW-SKIP-SUMMARY.md +0 -121
  79. package/dist/util/safety.js +0 -166
  80. package/dist/util/safety.js.map +0 -1
  81. package/dist/util/stdin.js +0 -133
  82. package/dist/util/stdin.js.map +0 -1
  83. package/dist/util/storage.js +0 -187
  84. package/dist/util/storage.js.map +0 -1
@@ -1,20 +1,38 @@
1
1
  import { run } from '@eldrforge/git-tools';
2
2
  import { getLogger } from '../logging.js';
3
+ import { getGitRepositoryRoot, isInGitRepository } from '../util/gitMutex.js';
3
4
 
4
5
  /**
5
6
  * Check the branch status for a package
6
- */ async function checkBranchStatus(packagePath, expectedBranch, targetBranch = 'main', checkPR = false) {
7
+ */ async function checkBranchStatus(packagePath, expectedBranch, targetBranch = 'main', checkPR = false, options = {}) {
7
8
  const logger = getLogger();
8
- const originalCwd = process.cwd();
9
+ // Check if path is in a git repository
10
+ if (!isInGitRepository(packagePath)) {
11
+ logger.debug(`Path is not in a git repository: ${packagePath}. Skipping branch status check.`);
12
+ return {
13
+ name: 'non-git',
14
+ isOnExpectedBranch: true,
15
+ ahead: 0,
16
+ behind: 0,
17
+ hasUnpushedCommits: false,
18
+ needsSync: false,
19
+ remoteExists: false
20
+ };
21
+ }
9
22
  try {
10
- process.chdir(packagePath);
11
23
  // Get current branch
12
- const { stdout: currentBranch } = await run('git rev-parse --abbrev-ref HEAD');
24
+ const { stdout: currentBranch } = await run('git rev-parse --abbrev-ref HEAD', {
25
+ cwd: packagePath,
26
+ suppressErrorLogging: true
27
+ });
13
28
  const branch = currentBranch.trim();
14
29
  // Check if remote exists
15
30
  let remoteExists = false;
16
31
  try {
17
- await run(`git ls-remote --exit-code --heads origin ${branch}`);
32
+ await run(`git ls-remote --exit-code --heads origin ${branch}`, {
33
+ cwd: packagePath,
34
+ suppressErrorLogging: true
35
+ });
18
36
  remoteExists = true;
19
37
  } catch {
20
38
  remoteExists = false;
@@ -24,7 +42,10 @@ import { getLogger } from '../logging.js';
24
42
  let behind = 0;
25
43
  if (remoteExists) {
26
44
  try {
27
- const { stdout: revList } = await run(`git rev-list --left-right --count origin/${branch}...HEAD`);
45
+ const { stdout: revList } = await run(`git rev-list --left-right --count origin/${branch}...HEAD`, {
46
+ cwd: packagePath,
47
+ suppressErrorLogging: true
48
+ });
28
49
  const [behindStr, aheadStr] = revList.trim().split('\t');
29
50
  behind = parseInt(behindStr, 10) || 0;
30
51
  ahead = parseInt(aheadStr, 10) || 0;
@@ -38,11 +59,19 @@ import { getLogger } from '../logging.js';
38
59
  if (branch !== targetBranch) {
39
60
  try {
40
61
  // Fetch latest to ensure we're checking against current target
41
- logger.verbose(` Fetching latest from origin for ${packagePath}...`);
42
- await run('git fetch origin --quiet');
62
+ if (!options.skipFetch) {
63
+ logger.verbose(` Fetching latest from origin for ${packagePath}...`);
64
+ await run('git fetch origin --quiet', {
65
+ cwd: packagePath,
66
+ suppressErrorLogging: true
67
+ });
68
+ }
43
69
  logger.verbose(` Checking for merge conflicts with ${targetBranch}...`);
44
70
  // Use git merge-tree to test for conflicts without actually merging
45
- const { stdout: mergeTree } = await run(`git merge-tree $(git merge-base ${branch} origin/${targetBranch}) ${branch} origin/${targetBranch}`);
71
+ const { stdout: mergeTree } = await run(`git merge-tree $(git merge-base ${branch} origin/${targetBranch}) ${branch} origin/${targetBranch}`, {
72
+ cwd: packagePath,
73
+ suppressErrorLogging: true
74
+ });
46
75
  // If merge-tree output contains conflict markers, there are conflicts
47
76
  if (mergeTree.includes('<<<<<<<') || mergeTree.includes('=======') || mergeTree.includes('>>>>>>>')) {
48
77
  hasMergeConflicts = true;
@@ -62,7 +91,7 @@ import { getLogger } from '../logging.js';
62
91
  try {
63
92
  logger.verbose(` Checking GitHub for existing PRs...`);
64
93
  const { findOpenPullRequestByHeadRef } = await import('@eldrforge/github-tools');
65
- const pr = await findOpenPullRequestByHeadRef(branch);
94
+ const pr = await findOpenPullRequestByHeadRef(branch, packagePath);
66
95
  if (pr) {
67
96
  hasOpenPR = true;
68
97
  prUrl = pr.html_url;
@@ -91,28 +120,54 @@ import { getLogger } from '../logging.js';
91
120
  prUrl,
92
121
  prNumber
93
122
  };
94
- } finally{
95
- process.chdir(originalCwd);
123
+ } catch (error) {
124
+ logger.error(`Error checking branch status for ${packagePath}: ${error.message}`);
125
+ return {
126
+ name: 'unknown',
127
+ isOnExpectedBranch: false,
128
+ ahead: 0,
129
+ behind: 0,
130
+ hasUnpushedCommits: false,
131
+ needsSync: false,
132
+ remoteExists: false
133
+ };
96
134
  }
97
135
  }
98
136
  /**
99
137
  * Check if target branch (e.g., main) is exactly in sync with remote
100
- */ async function checkTargetBranchSync(packagePath, targetBranch = 'main') {
138
+ */ async function checkTargetBranchSync(packagePath, targetBranch = 'main', options = {}) {
101
139
  const logger = getLogger();
102
- const originalCwd = process.cwd();
140
+ // Check if path is in a git repository
141
+ if (!isInGitRepository(packagePath)) {
142
+ return {
143
+ targetBranch,
144
+ localExists: false,
145
+ remoteExists: false,
146
+ exactMatch: true,
147
+ canFastForward: false,
148
+ needsReset: false
149
+ };
150
+ }
103
151
  try {
104
- process.chdir(packagePath);
105
152
  // Fetch latest from origin to ensure we have current info
106
- try {
107
- await run('git fetch origin --quiet');
108
- } catch (error) {
109
- logger.verbose(`Could not fetch from origin in ${packagePath}: ${error.message}`);
153
+ if (!options.skipFetch) {
154
+ try {
155
+ await run('git fetch origin --quiet', {
156
+ cwd: packagePath,
157
+ suppressErrorLogging: true
158
+ });
159
+ } catch (error) {
160
+ logger.verbose(`Could not fetch from origin in ${packagePath}: ${error.message}`);
161
+ }
110
162
  }
111
163
  // Check if local target branch exists
112
164
  let localExists = false;
113
165
  let localSha;
114
166
  try {
115
- const { stdout } = await run(`git rev-parse --verify ${targetBranch}`);
167
+ const { stdout } = await run(`git rev-parse --verify ${targetBranch}`, {
168
+ cwd: packagePath,
169
+ suppressErrorLogging: true
170
+ });
116
171
  localSha = stdout.trim();
117
172
  localExists = true;
118
173
  } catch {
@@ -122,7 +177,10 @@ import { getLogger } from '../logging.js';
122
177
  let remoteExists = false;
123
178
  let remoteSha;
124
179
  try {
125
- const { stdout } = await run(`git ls-remote origin ${targetBranch}`);
180
+ const { stdout } = await run(`git ls-remote origin ${targetBranch}`, {
181
+ cwd: packagePath,
182
+ suppressErrorLogging: true
183
+ });
126
184
  if (stdout.trim()) {
127
185
  remoteSha = stdout.split(/\s+/)[0];
128
186
  remoteExists = true;
@@ -137,7 +195,10 @@ import { getLogger } from '../logging.js';
137
195
  if (localExists && remoteExists && !exactMatch) {
138
196
  // Check if local is ancestor of remote (can fast-forward)
139
197
  try {
140
- await run(`git merge-base --is-ancestor ${targetBranch} origin/${targetBranch}`);
198
+ await run(`git merge-base --is-ancestor ${targetBranch} origin/${targetBranch}`, {
199
+ cwd: packagePath,
200
+ suppressErrorLogging: true
201
+ });
141
202
  canFastForward = true;
142
203
  needsReset = false;
143
204
  } catch {
@@ -166,50 +227,118 @@ import { getLogger } from '../logging.js';
166
227
  needsReset: false,
167
228
  error: error.message
168
229
  };
169
- } finally{
170
- process.chdir(originalCwd);
171
230
  }
172
231
  }
173
232
  /**
174
233
  * Audit branch state across multiple packages
175
234
  */ async function auditBranchState(packages, expectedBranch, options = {}) {
176
235
  const logger = getLogger();
177
- const audits = [];
178
236
  const targetBranch = options.targetBranch || 'main';
179
237
  const checkPR = options.checkPR !== false; // Default true
180
238
  const checkConflicts = options.checkConflicts !== false; // Default true
181
239
  const checkVersions = options.checkVersions !== false; // Default true
182
- logger.info(`BRANCH_STATE_AUDIT: Auditing branch state for packages | Package Count: ${packages.length} | Purpose: Verify synchronization`);
240
+ const concurrency = options.concurrency || 5;
241
+ logger.info(`BRANCH_STATE_AUDIT: Auditing branch state for packages | Package Count: ${packages.length} | Concurrency: ${concurrency} | Purpose: Verify synchronization`);
242
+ // Helper for concurrency-limited parallel map
243
+ const parallelMap = async (items, fn)=>{
244
+ const results = new Array(items.length);
245
+ const queue = items.map((item, index)=>({
246
+ item,
247
+ index
248
+ }));
249
+ let nextIndex = 0;
250
+ const workers = Array(Math.min(concurrency, items.length)).fill(null).map(async ()=>{
251
+ while(nextIndex < queue.length){
252
+ const task = queue[nextIndex++];
253
+ results[task.index] = await fn(task.item, task.index);
254
+ }
255
+ });
256
+ await Promise.all(workers);
257
+ return results;
258
+ };
183
259
  // If no expected branch specified, find the most common branch
184
260
  let actualExpectedBranch = expectedBranch;
185
261
  if (!expectedBranch) {
262
+ logger.info('šŸ“‹ Phase 1/3: Detecting most common branch across packages (optimized)...');
263
+ const branchNames = await parallelMap(packages, async (pkg)=>{
264
+ if (!isInGitRepository(pkg.path)) {
265
+ return 'non-git';
266
+ }
267
+ try {
268
+ const { stdout } = await run('git rev-parse --abbrev-ref HEAD', {
269
+ cwd: pkg.path,
270
+ suppressErrorLogging: true
271
+ });
272
+ return stdout.trim();
273
+ } catch {
274
+ return 'unknown';
275
+ }
276
+ });
186
277
  const branchCounts = new Map();
187
- logger.info('šŸ“‹ Phase 1/2: Detecting most common branch across packages...');
188
- // First pass: collect all branch names
189
- for(let i = 0; i < packages.length; i++){
190
- const pkg = packages[i];
191
- logger.info(` [${i + 1}/${packages.length}] Checking branch: ${pkg.name}`);
192
- const status = await checkBranchStatus(pkg.path);
193
- branchCounts.set(status.name, (branchCounts.get(status.name) || 0) + 1);
278
+ for (const name of branchNames){
279
+ branchCounts.set(name, (branchCounts.get(name) || 0) + 1);
194
280
  }
195
281
  // Find most common branch
196
282
  let maxCount = 0;
197
283
  for (const [branch, count] of branchCounts.entries()){
198
- if (count > maxCount) {
284
+ if (count > maxCount && branch !== 'unknown' && branch !== 'non-git') {
199
285
  maxCount = count;
200
286
  actualExpectedBranch = branch;
201
287
  }
202
288
  }
289
+ if (!actualExpectedBranch) actualExpectedBranch = 'main';
203
290
  logger.info(`āœ“ Most common branch: ${actualExpectedBranch} (${maxCount}/${packages.length} packages)`);
204
291
  }
205
- logger.info(`\nšŸ“‹ Phase 2/2: Auditing package state (checking git status, conflicts, PRs, versions)...`);
206
- for(let i = 0; i < packages.length; i++){
207
- const pkg = packages[i];
208
- logger.info(` [${i + 1}/${packages.length}] Auditing: ${pkg.name}`);
209
- const status = await checkBranchStatus(pkg.path, actualExpectedBranch, targetBranch, checkPR);
292
+ // Phase 2: Identify unique repos and fetch once per repo
293
+ logger.info(`\nšŸ“‹ Phase 2/3: Fetching latest from remotes (one fetch per repository)...`);
294
+ const repoRoots = new Set();
295
+ for (const pkg of packages){
296
+ const root = getGitRepositoryRoot(pkg.path);
297
+ if (root) repoRoots.add(root);
298
+ }
299
+ const repoList = Array.from(repoRoots);
300
+ await parallelMap(repoList, async (repo, i)=>{
301
+ try {
302
+ logger.verbose(` [${i + 1}/${repoList.length}] Fetching in: ${repo}`);
303
+ await run('git fetch origin --quiet', {
304
+ cwd: repo,
305
+ suppressErrorLogging: true
306
+ });
307
+ } catch (error) {
308
+ logger.debug(`Could not fetch in ${repo}: ${error.message}`);
309
+ }
310
+ });
311
+ logger.info(`āœ“ Fetched latest information for ${repoList.length} unique repositories`);
312
+ // Phase 3: Full audit in parallel
313
+ logger.info(`\nšŸ“‹ Phase 3/3: Auditing package state (git status, conflicts, PRs, versions)...`);
314
+ let completedCount = 0;
315
+ const audits = await parallelMap(packages, async (pkg)=>{
316
+ // Check target branch sync (e.g., is local main exactly in sync with remote main?)
317
+ const targetBranchSync = await checkTargetBranchSync(pkg.path, targetBranch, {
318
+ skipFetch: true
319
+ });
320
+ const status = await checkBranchStatus(pkg.path, actualExpectedBranch, targetBranch, checkPR, {
321
+ skipFetch: true
322
+ });
210
323
  const issues = [];
211
324
  const fixes = [];
212
325
  let versionStatus;
326
+ // Skip issues for non-git repositories
327
+ if (status.name === 'non-git') {
328
+ completedCount++;
329
+ if (completedCount % 5 === 0 || completedCount === packages.length) {
330
+ logger.info(` Progress: ${completedCount}/${packages.length} packages audited`);
331
+ }
332
+ return {
333
+ packageName: pkg.name,
334
+ path: pkg.path,
335
+ status,
336
+ versionStatus,
337
+ targetBranchSync,
338
+ issues,
339
+ fixes
340
+ };
341
+ }
213
342
  // Check for issues
214
343
  if (!status.isOnExpectedBranch && actualExpectedBranch) {
215
344
  issues.push(`On branch '${status.name}' (most packages are on '${actualExpectedBranch}')`);
@@ -261,7 +390,6 @@ import { getLogger } from '../logging.js';
261
390
  }
262
391
  }
263
392
  // Check target branch sync (e.g., is local main exactly in sync with remote main?)
264
- const targetBranchSync = await checkTargetBranchSync(pkg.path, targetBranch);
265
393
  if (targetBranchSync.localExists && targetBranchSync.remoteExists && !targetBranchSync.exactMatch) {
266
394
  if (targetBranchSync.needsReset) {
267
395
  issues.push(`Target branch '${targetBranch}' is NOT in sync with remote (local has diverged)`);
@@ -274,12 +402,17 @@ import { getLogger } from '../logging.js';
274
402
  fixes.push(`cd ${pkg.path} && git checkout ${targetBranch} && git pull origin ${targetBranch} && git checkout ${status.name}`);
275
403
  }
276
404
  } else if (!targetBranchSync.localExists && targetBranchSync.remoteExists) {
277
- // Local target branch doesn't exist (this is OK - will be created during publish)
278
- logger.verbose(`Local ${targetBranch} doesn't exist in ${pkg.name} - will be created when needed`);
405
+ // Local target branch doesn't exist but exists on remote
406
+ issues.push(`Target branch '${targetBranch}' does not exist locally (exists on remote)`);
407
+ fixes.push(`cd ${pkg.path} && git branch ${targetBranch} origin/${targetBranch}`);
279
408
  } else if (targetBranchSync.error) {
280
409
  logger.verbose(`Could not check target branch sync for ${pkg.name}: ${targetBranchSync.error}`);
281
410
  }
282
- audits.push({
411
+ completedCount++;
412
+ if (completedCount % 5 === 0 || completedCount === packages.length) {
413
+ logger.info(` Progress: ${completedCount}/${packages.length} packages audited`);
414
+ }
415
+ return {
283
416
  packageName: pkg.name,
284
417
  path: pkg.path,
285
418
  status,
@@ -287,8 +420,8 @@ import { getLogger } from '../logging.js';
287
420
  targetBranchSync,
288
421
  issues,
289
422
  fixes
290
- });
291
- }
423
+ };
424
+ });
292
425
  const issuesFound = audits.filter((a)=>a.issues.length > 0).length;
293
426
  const versionIssues = audits.filter((a)=>a.versionStatus && !a.versionStatus.isValid).length;
294
427
  const targetBranchSyncIssues = audits.filter((a)=>a.targetBranchSync && !a.targetBranchSync.exactMatch && a.targetBranchSync.localExists && a.targetBranchSync.remoteExists).length;