@eldrforge/kodrdriv 1.2.23 → 1.2.25

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 (67) hide show
  1. package/PARALLEL-EXECUTION-FIXES.md +132 -0
  2. package/PARALLEL_EXECUTION_FIX.md +146 -0
  3. package/RECOVERY-FIXES.md +72 -0
  4. package/SUBMODULE-LOCK-FIX.md +132 -0
  5. package/dist/arguments.js +26 -3
  6. package/dist/arguments.js.map +1 -1
  7. package/dist/commands/audio-commit.js +3 -3
  8. package/dist/commands/audio-commit.js.map +1 -1
  9. package/dist/commands/audio-review.js +13 -13
  10. package/dist/commands/audio-review.js.map +1 -1
  11. package/dist/commands/link.js +13 -13
  12. package/dist/commands/link.js.map +1 -1
  13. package/dist/commands/publish.js +200 -146
  14. package/dist/commands/publish.js.map +1 -1
  15. package/dist/commands/review.js +6 -6
  16. package/dist/commands/review.js.map +1 -1
  17. package/dist/commands/select-audio.js +4 -4
  18. package/dist/commands/select-audio.js.map +1 -1
  19. package/dist/commands/tree.js +242 -318
  20. package/dist/commands/tree.js.map +1 -1
  21. package/dist/commands/unlink.js +8 -8
  22. package/dist/commands/unlink.js.map +1 -1
  23. package/dist/commands/versions.js +3 -3
  24. package/dist/commands/versions.js.map +1 -1
  25. package/dist/constants.js +4 -4
  26. package/dist/constants.js.map +1 -1
  27. package/dist/content/diff.js +5 -2
  28. package/dist/content/diff.js.map +1 -1
  29. package/dist/content/files.js +4 -4
  30. package/dist/content/files.js.map +1 -1
  31. package/dist/execution/CommandValidator.js +160 -0
  32. package/dist/execution/CommandValidator.js.map +1 -0
  33. package/dist/execution/DependencyChecker.js +102 -0
  34. package/dist/execution/DependencyChecker.js.map +1 -0
  35. package/dist/execution/DynamicTaskPool.js +455 -0
  36. package/dist/execution/DynamicTaskPool.js.map +1 -0
  37. package/dist/execution/RecoveryManager.js +502 -0
  38. package/dist/execution/RecoveryManager.js.map +1 -0
  39. package/dist/execution/ResourceMonitor.js +125 -0
  40. package/dist/execution/ResourceMonitor.js.map +1 -0
  41. package/dist/execution/Scheduler.js +98 -0
  42. package/dist/execution/Scheduler.js.map +1 -0
  43. package/dist/execution/TreeExecutionAdapter.js +170 -0
  44. package/dist/execution/TreeExecutionAdapter.js.map +1 -0
  45. package/dist/logging.js +3 -3
  46. package/dist/logging.js.map +1 -1
  47. package/dist/ui/ProgressFormatter.js +230 -0
  48. package/dist/ui/ProgressFormatter.js.map +1 -0
  49. package/dist/util/checkpointManager.js +168 -0
  50. package/dist/util/checkpointManager.js.map +1 -0
  51. package/dist/util/dependencyGraph.js +224 -0
  52. package/dist/util/dependencyGraph.js.map +1 -0
  53. package/dist/util/fileLock.js +241 -0
  54. package/dist/util/fileLock.js.map +1 -0
  55. package/dist/util/general.js +5 -5
  56. package/dist/util/general.js.map +1 -1
  57. package/dist/util/gitMutex.js +116 -0
  58. package/dist/util/gitMutex.js.map +1 -0
  59. package/dist/util/mutex.js +96 -0
  60. package/dist/util/mutex.js.map +1 -0
  61. package/dist/util/performance.js +4 -4
  62. package/dist/util/performance.js.map +1 -1
  63. package/dist/util/safety.js +4 -4
  64. package/dist/util/safety.js.map +1 -1
  65. package/dist/util/storage.js +2 -2
  66. package/dist/util/storage.js.map +1 -1
  67. package/package.json +6 -6
@@ -0,0 +1,132 @@
1
+ # Parallel Execution Fixes
2
+
3
+ ## Critical Bugs Fixed
4
+
5
+ ### 1. Recovery System - Checkpoint Deleted When Packages Skipped (Commit b6deb3f)
6
+
7
+ **Problem**: When using `--mark-completed` during recovery, the checkpoint was deleted even though dependent packages were skipped, making recovery impossible.
8
+
9
+ **Symptoms**:
10
+ - Misleading "All X packages completed successfully!" message when packages were actually skipped
11
+ - Lost checkpoint, unable to continue execution
12
+ - No way to resume and complete skipped packages
13
+
14
+ **Fix**: Modified checkpoint cleanup logic to preserve checkpoint when packages are skipped.
15
+
16
+ **Files Changed**:
17
+ - `src/execution/DynamicTaskPool.ts`: Only cleanup if NO failures AND NO skipped packages
18
+ - `src/execution/TreeExecutionAdapter.ts`: Show accurate message for skipped packages
19
+ - `src/execution/RecoveryManager.ts`: Accept both directory names and package names
20
+ - `src/arguments.ts`: Updated help text for consistency
21
+ - `src/ui/ProgressFormatter.ts`: Updated recovery guidance
22
+
23
+ ### 2. Parallel Execution - Race Conditions in Dependency Updates (Commit 371050c)
24
+
25
+ **Problem**: When running `kodrdriv tree publish --parallel`, multiple packages updated dependencies simultaneously, causing catastrophic failures.
26
+
27
+ **Symptoms**:
28
+ ```
29
+ 1. ENOTEMPTY errors:
30
+ npm error ENOTEMPTY: directory not empty, rename
31
+ '/path/node_modules/@eldrforge/git-tools' ->
32
+ '/path/node_modules/@eldrforge/.git-tools-xxx'
33
+
34
+ 2. "not a git repository" errors:
35
+ fatal: not a git repository (or any of the parent directories): .git
36
+
37
+ 3. Git state conflicts:
38
+ error: Working directory has uncommitted changes
39
+ ```
40
+
41
+ **Root Cause**:
42
+ - Dependency update operations (npm install + git commit) ran in parallel
43
+ - Multiple packages tried to:
44
+ - Update same dependencies → filesystem race conditions
45
+ - Commit at same time → git state conflicts
46
+ - Run in different working directories → lost git context
47
+
48
+ **Solution**: Wrapped dependency update + commit section with per-repository lock (`runGitWithLock`):
49
+ - Operations serialize within each repository
50
+ - Maintains parallelism across different repositories
51
+ - Prevents npm install race conditions
52
+ - Prevents git commit conflicts
53
+ - Preserves working directory context
54
+
55
+ **Files Changed**:
56
+ - `src/commands/tree.ts`: Import `runGitWithLock` and wrap dependency update section
57
+
58
+ ## Impact
59
+
60
+ ### Before Fixes:
61
+ ```bash
62
+ # Parallel publish would fail catastrophically:
63
+ kodrdriv tree publish --parallel
64
+ # → ENOTEMPTY errors
65
+ # → Git repository errors
66
+ # → Unable to recover
67
+ ```
68
+
69
+ ### After Fixes:
70
+ ```bash
71
+ # Parallel publish works reliably:
72
+ kodrdriv tree publish --parallel
73
+ # → Dependency updates happen serially per repo
74
+ # → Git operations don't conflict
75
+ # → If something fails, recovery actually works
76
+
77
+ # Recovery now works:
78
+ kodrdriv tree publish --continue --mark-completed "git-tools"
79
+ # → Checkpoint preserved
80
+ # → Remaining packages execute
81
+ # → Can use simple directory names
82
+ ```
83
+
84
+ ## Technical Details
85
+
86
+ ### Git Lock Mechanism
87
+
88
+ The fix uses `runGitWithLock()` from `src/util/gitMutex.ts`:
89
+
90
+ ```typescript
91
+ await runGitWithLock(packageDir, async () => {
92
+ // Update scoped dependencies (npm install)
93
+ await updateScopedDependencies(...);
94
+
95
+ // Update inter-project dependencies (npm install)
96
+ await updateInterProjectDependencies(...);
97
+
98
+ // Commit changes (git operations)
99
+ await Commit.execute(...);
100
+ }, `${packageName}: dependency updates`);
101
+ ```
102
+
103
+ This ensures that:
104
+ 1. Operations are serialized within each git repository
105
+ 2. Parallel execution continues across different repositories
106
+ 3. File-based locks coordinate across processes
107
+ 4. No race conditions on npm install or git operations
108
+
109
+ ### Checkpoint Preservation
110
+
111
+ The checkpoint cleanup now checks both conditions:
112
+
113
+ ```typescript
114
+ const allCompleted = this.state.failed.length === 0 &&
115
+ this.state.skipped.length === 0;
116
+ if (allCompleted) {
117
+ await this.checkpointManager.cleanup();
118
+ } else {
119
+ await this.saveCheckpoint(); // Keep checkpoint for recovery
120
+ }
121
+ ```
122
+
123
+ ## Testing
124
+
125
+ Both fixes have been tested and work correctly:
126
+ - Recovery system preserves checkpoints when needed
127
+ - Parallel execution no longer causes race conditions
128
+ - Directory names work for `--mark-completed`
129
+
130
+ ## Version
131
+
132
+ These fixes are in version `1.2.24-dev.0` commit `371050c`.
@@ -0,0 +1,146 @@
1
+ # Parallel Execution Freeze Fix
2
+
3
+ ## Problem
4
+
5
+ When running `kodrdriv tree publish --parallel`, the execution would freeze because:
6
+
7
+ 1. **Multiple child processes** were spawned (one per package)
8
+ 2. All packages were in the **same git repository** (`/Users/tobrien/gitw/calenvarek`)
9
+ 3. Each child process had its own **in-memory mutex** (SimpleMutex)
10
+ 4. In-memory mutexes **cannot coordinate across separate processes**
11
+ 5. Multiple processes tried to run git operations concurrently
12
+ 6. Git created `.git/index.lock` files, causing conflicts and hangs
13
+
14
+ ## Root Cause
15
+
16
+ The `SimpleMutex` class in `src/util/mutex.ts` was designed for **single-process** synchronization. It uses in-memory state that cannot be shared between separate Node.js processes.
17
+
18
+ When `kodrdriv tree publish --parallel` spawns child processes using `exec()`, each child process:
19
+ - Gets its own memory space
20
+ - Creates its own `RepositoryMutexManager` singleton
21
+ - Has no way to coordinate with other processes
22
+
23
+ ## Solution
24
+
25
+ Implemented a **file-based locking mechanism** in `src/util/fileLock.ts`:
26
+
27
+ ### Key Features
28
+
29
+ 1. **Cross-Process Safety**: Uses atomic file operations (`wx` flag) that work across processes
30
+ 2. **Exponential Backoff**: Retries lock acquisition with increasing delays (100ms → 2000ms max)
31
+ 3. **Stale Lock Detection**: Automatically removes locks older than 30 seconds
32
+ 4. **Automatic Cleanup**: Releases locks on process exit (normal, SIGINT, SIGTERM, uncaughtException)
33
+ 5. **Per-Repository Locking**: Creates `.git/kodrdriv.lock` file in each repository
34
+
35
+ ### Implementation Details
36
+
37
+ #### FileLock Class
38
+ ```typescript
39
+ class FileLock {
40
+ async lock(): Promise<void> {
41
+ // Attempts to create lock file atomically with 'wx' flag
42
+ // Retries with exponential backoff if file exists
43
+ // Detects and removes stale locks (>30 seconds old)
44
+ }
45
+
46
+ unlock(): void {
47
+ // Removes lock file
48
+ }
49
+ }
50
+ ```
51
+
52
+ #### RepositoryFileLockManager Class
53
+ ```typescript
54
+ class RepositoryFileLockManager {
55
+ getRepositoryLock(repoPath: string): FileLock {
56
+ // Returns file lock for .git/kodrdriv.lock
57
+ }
58
+
59
+ async withGitLock<T>(repoPath, operation, operationName): Promise<T> {
60
+ // Acquires lock, executes operation, releases lock
61
+ }
62
+ }
63
+ ```
64
+
65
+ ### Changes Made
66
+
67
+ 1. **Created** `src/util/fileLock.ts` - New file-based locking implementation
68
+ 2. **Modified** `src/util/gitMutex.ts` - Now uses FileLock instead of SimpleMutex
69
+ 3. **No Breaking Changes** - API remains the same, only implementation changed
70
+
71
+ ### How It Works
72
+
73
+ ```
74
+ Parent Process (kodrdriv tree publish --parallel)
75
+ ├── Spawns: kodrdriv publish [git-tools]
76
+ │ └── Tries to acquire .git/kodrdriv.lock
77
+ │ ✓ Success! Executes git operations
78
+ │ ✓ Releases lock
79
+ ├── Spawns: kodrdriv publish [ai-service]
80
+ │ └── Tries to acquire .git/kodrdriv.lock
81
+ │ ⏳ Waits... lock file exists
82
+ │ ✓ Previous process released lock
83
+ │ ✓ Acquires lock, executes, releases
84
+ ├── Spawns: kodrdriv publish [github-tools]
85
+ │ └── (same pattern)
86
+ └── Spawns: kodrdriv publish [kodrdriv]
87
+ └── (same pattern)
88
+ ```
89
+
90
+ ### Testing
91
+
92
+ - ✅ All 283 existing tests pass
93
+ - ✅ Build succeeds with no linter errors
94
+ - ✅ Lock files are automatically cleaned up on exit
95
+ - ✅ Stale locks (>30s) are automatically removed
96
+
97
+ ## Usage
98
+
99
+ No changes needed! The fix is transparent:
100
+
101
+ ```bash
102
+ # This now works without freezing
103
+ kodrdriv tree publish --parallel
104
+
105
+ # Same for other commands that use git operations
106
+ kodrdriv tree commit --parallel
107
+ ```
108
+
109
+ ## Lock File Location
110
+
111
+ Lock files are created at:
112
+ ```
113
+ /path/to/repo/.git/kodrdriv.lock
114
+ ```
115
+
116
+ These files:
117
+ - Are automatically created/removed
118
+ - Are gitignored (in .git directory)
119
+ - Are safe to manually delete if stale
120
+ - Contain diagnostic info (PID, timestamp, hostname)
121
+
122
+ ## Performance Impact
123
+
124
+ - **Minimal overhead**: File operations are fast (microseconds)
125
+ - **Better than deadlock**: Small delay is better than infinite freeze
126
+ - **Automatic backoff**: Reduces contention with exponential delays
127
+ - **Stale lock cleanup**: Prevents indefinite blocking
128
+
129
+ ## Future Improvements
130
+
131
+ Potential enhancements:
132
+ 1. Make lock timeout configurable
133
+ 2. Add lock health monitoring/metrics
134
+ 3. Implement lock priority/queueing
135
+ 4. Add verbose lock acquisition logging
136
+
137
+ ## Verification
138
+
139
+ To verify the fix works:
140
+ ```bash
141
+ cd /Users/tobrien/gitw/calenvarek/kodrdriv
142
+ npm run build
143
+ kodrdriv tree publish --parallel --dry-run
144
+ ```
145
+
146
+ The parallel execution should now proceed without freezing.
@@ -0,0 +1,72 @@
1
+ # Recovery System Fixes
2
+
3
+ ## Issues Fixed
4
+
5
+ ### 1. Checkpoint Deleted When Packages Are Skipped
6
+
7
+ **Problem**: When using `--mark-completed` to mark a failed package as done, the system would delete the checkpoint even though dependent packages were skipped. This resulted in:
8
+ - Misleading "All X packages completed successfully! 🎉" message when packages were actually skipped
9
+ - Lost checkpoint making it impossible to continue the execution
10
+ - No way to resume and complete the skipped packages
11
+
12
+ **Root Cause**: In `DynamicTaskPool.ts`, the cleanup logic only checked for failed packages, not skipped packages:
13
+
14
+ ```typescript
15
+ // Before (WRONG)
16
+ if (this.state.failed.length === 0) {
17
+ await this.checkpointManager.cleanup(); // Deletes checkpoint
18
+ }
19
+
20
+ // After (FIXED)
21
+ const allCompleted = this.state.failed.length === 0 && this.state.skipped.length === 0;
22
+ if (allCompleted) {
23
+ await this.checkpointManager.cleanup();
24
+ }
25
+ ```
26
+
27
+ **Fix**: Modified `src/execution/DynamicTaskPool.ts` to preserve the checkpoint when packages are skipped, and updated `src/execution/TreeExecutionAdapter.ts` to show the correct message when packages are skipped.
28
+
29
+ ### 2. Inconsistent Package Identifier Format
30
+
31
+ **Problem**: The `--mark-completed` option required NPM package names (e.g., `"@eldrforge/git-tools"`), while `--start-from` accepted directory names (e.g., `"git-tools"`). This was confusing and inconsistent.
32
+
33
+ **Fix**: Updated `src/execution/RecoveryManager.ts` to accept both directory names and package names for `--mark-completed`, matching the behavior of `--start-from`:
34
+
35
+ ```typescript
36
+ // Now both work:
37
+ kodrdriv tree publish --continue --mark-completed "git-tools"
38
+ kodrdriv tree publish --continue --mark-completed "@eldrforge/git-tools"
39
+ ```
40
+
41
+ The system will:
42
+ 1. Try exact package name match first
43
+ 2. Fall back to directory name match
44
+ 3. Provide helpful error with available packages if not found
45
+
46
+ **Updated Files**:
47
+ - `src/execution/RecoveryManager.ts` - Added `resolvePackageName()` helper and updated `markCompleted()`
48
+ - `src/arguments.ts` - Updated help text
49
+ - `src/ui/ProgressFormatter.ts` - Updated recovery guidance to use directory names
50
+
51
+ ## Testing
52
+
53
+ All existing tests pass, including the specific RecoveryManager tests.
54
+
55
+ ## Usage
56
+
57
+ Now you can use directory names (much simpler):
58
+
59
+ ```bash
60
+ # Start a parallel publish
61
+ kodrdriv tree publish --parallel
62
+
63
+ # If git-tools fails due to merge conflict, fix it manually, then:
64
+ kodrdriv tree publish --continue --mark-completed "git-tools"
65
+
66
+ # The remaining packages (ai-service, github-tools, kodrdriv) will now execute
67
+ ```
68
+
69
+ The system will:
70
+ 1. Keep the checkpoint if packages are skipped
71
+ 2. Show accurate status messages
72
+ 3. Allow you to continue execution to complete the skipped packages
@@ -0,0 +1,132 @@
1
+ # Git Submodule Lock File Fix
2
+
3
+ ## Problem
4
+
5
+ The file-based lock mechanism used to prevent concurrent git operations was failing when used with git submodules. The issue occurred because:
6
+
7
+ 1. In regular git repositories, `.git` is a directory
8
+ 2. In git submodules, `.git` is a file containing a `gitdir:` reference pointing to the actual git directory
9
+ 3. The code assumed `.git` was always a directory and tried to create lock files in `.git/kodrdriv.lock`
10
+ 4. This caused `ENOTDIR` errors when operating on submodules
11
+
12
+ ## Example Submodule Structure
13
+
14
+ ```
15
+ my-submodule/
16
+ ├── .git # FILE (not directory) containing: "gitdir: ../.git/modules/my-submodule"
17
+ ├── src/
18
+ └── package.json
19
+
20
+ parent-repo/
21
+ └── .git/
22
+ └── modules/
23
+ └── my-submodule/ # Actual git directory for the submodule
24
+ ├── HEAD
25
+ ├── refs/
26
+ └── objects/
27
+ ```
28
+
29
+ ## Solution
30
+
31
+ Modified `src/util/fileLock.ts` to handle both regular repositories and submodules:
32
+
33
+ ### Key Changes
34
+
35
+ 1. **Added `resolveGitDirectory()` method** that:
36
+ - Checks if `.git` is a directory (regular repo) or file (submodule)
37
+ - If it's a file, reads and parses the `gitdir:` reference
38
+ - Resolves the gitdir path (handles both relative and absolute paths)
39
+ - Returns the actual git directory path where locks can be created
40
+
41
+ 2. **Updated `getRepositoryLock()` method** to:
42
+ - Use `resolveGitDirectory()` instead of assuming `.git` is a directory
43
+ - Create lock files in the resolved git directory
44
+ - Log the actual lock path for debugging
45
+
46
+ ### Code Implementation
47
+
48
+ ```typescript
49
+ private resolveGitDirectory(repoPath: string): string {
50
+ const gitPath = path.join(repoPath, '.git');
51
+
52
+ try {
53
+ const stat = fs.statSync(gitPath);
54
+
55
+ if (stat.isDirectory()) {
56
+ // Regular git repository
57
+ return gitPath;
58
+ } else if (stat.isFile()) {
59
+ // Git submodule - .git is a file with format: gitdir: <path>
60
+ const gitFileContent = fs.readFileSync(gitPath, 'utf-8').trim();
61
+ const match = gitFileContent.match(/^gitdir:\s*(.+)$/);
62
+
63
+ if (match && match[1]) {
64
+ // Resolve the gitdir path (it's relative to the repo path)
65
+ const gitDirPath = path.resolve(repoPath, match[1]);
66
+ this.logger.debug(`Resolved submodule gitdir: ${gitDirPath}`);
67
+
68
+ // Ensure the git directory exists
69
+ if (!fs.existsSync(gitDirPath)) {
70
+ throw new Error(`Submodule git directory does not exist: ${gitDirPath}`);
71
+ }
72
+
73
+ return gitDirPath;
74
+ }
75
+
76
+ throw new Error(`Invalid .git file format in ${gitPath}: ${gitFileContent}`);
77
+ }
78
+ } catch (error: any) {
79
+ // Check if error is from statSync (file doesn't exist)
80
+ if (error.code === 'ENOENT') {
81
+ throw new Error(`No .git directory or file found in ${repoPath}`);
82
+ }
83
+ throw new Error(`Failed to resolve git directory for ${repoPath}: ${error.message}`);
84
+ }
85
+
86
+ throw new Error(`No .git directory or file found in ${repoPath}`);
87
+ }
88
+ ```
89
+
90
+ ## Testing
91
+
92
+ Comprehensive test suite added in `tests/fileLock.test.ts` covering:
93
+
94
+ 1. **Basic lock operations**
95
+ - Acquire and release locks
96
+ - Block concurrent lock acquisition
97
+ - Handle stale locks
98
+
99
+ 2. **Regular repository support**
100
+ - Create locks in `.git` directory
101
+
102
+ 3. **Submodule support** (NEW)
103
+ - Handle `.git` file with `gitdir:` reference
104
+ - Resolve relative gitdir paths
105
+ - Create locks in the actual git directory
106
+ - Proper error handling for missing submodule directories
107
+ - Proper error handling for invalid `.git` file format
108
+
109
+ 4. **Lock manager functionality**
110
+ - Execute operations under lock
111
+ - Release locks on operation failure
112
+ - Serialize multiple operations on same repo
113
+
114
+ All 12 tests pass successfully with 86%+ coverage on the fileLock module.
115
+
116
+ ## Impact
117
+
118
+ This fix enables kodrdriv to work correctly in monorepo setups where packages are organized as git submodules, such as:
119
+
120
+ - Multi-repository projects using git submodules for shared libraries
121
+ - Projects with external dependencies included as submodules
122
+ - Monorepos with complex submodule hierarchies
123
+
124
+ The fix maintains backward compatibility with regular git repositories while adding robust support for submodules.
125
+
126
+ ## Related Files
127
+
128
+ - `src/util/fileLock.ts` - Core fix implementation
129
+ - `tests/fileLock.test.ts` - Comprehensive test suite
130
+ - `src/util/gitMutex.ts` - Uses RepositoryFileLockManager
131
+ - `src/commands/publish.ts` - Uses git locks during publish operations
132
+
package/dist/arguments.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Command } from 'commander';
2
- import path from 'path';
2
+ import path__default from 'path';
3
3
  import { z } from 'zod';
4
4
  import { PROGRAM_NAME, VERSION, KODRDRIV_DEFAULTS, ALLOWED_COMMANDS, DEFAULT_COMMAND } from './constants.js';
5
5
  import { getLogger } from './logging.js';
@@ -263,6 +263,29 @@ const transformCliArgs = (finalCliArgs, commandName)=>{
263
263
  if (packageArgument !== undefined) transformedCliArgs.tree.packageArgument = packageArgument;
264
264
  if (finalCliArgs.cleanNodeModules !== undefined) transformedCliArgs.tree.cleanNodeModules = finalCliArgs.cleanNodeModules;
265
265
  if (finalCliArgs.externals !== undefined) transformedCliArgs.tree.externals = finalCliArgs.externals;
266
+ // Parallel execution options (using any cast for new properties)
267
+ const cliArgs = finalCliArgs;
268
+ if (cliArgs.parallel !== undefined) transformedCliArgs.tree.parallel = cliArgs.parallel;
269
+ if (cliArgs.maxConcurrency !== undefined) transformedCliArgs.tree.maxConcurrency = cliArgs.maxConcurrency;
270
+ if (cliArgs.maxRetries !== undefined || cliArgs.retryDelay !== undefined) {
271
+ transformedCliArgs.tree.retry = {
272
+ maxAttempts: cliArgs.maxRetries || 3,
273
+ initialDelayMs: cliArgs.retryDelay || 5000,
274
+ maxDelayMs: 60000,
275
+ backoffMultiplier: 2
276
+ };
277
+ }
278
+ // Recovery options
279
+ if (cliArgs.statusParallel !== undefined) transformedCliArgs.tree.statusParallel = cliArgs.statusParallel;
280
+ if (cliArgs.markCompleted !== undefined) {
281
+ transformedCliArgs.tree.markCompleted = cliArgs.markCompleted.split(',').map((s)=>s.trim());
282
+ }
283
+ if (cliArgs.skip !== undefined) {
284
+ transformedCliArgs.tree.skipPackages = cliArgs.skip.split(',').map((s)=>s.trim());
285
+ }
286
+ if (cliArgs.retryFailed !== undefined) transformedCliArgs.tree.retryFailed = cliArgs.retryFailed;
287
+ if (cliArgs.skipFailed !== undefined) transformedCliArgs.tree.skipFailed = cliArgs.skipFailed;
288
+ if (cliArgs.validateState !== undefined) transformedCliArgs.tree.validateState = cliArgs.validateState;
266
289
  }
267
290
  }
268
291
  // Nested mappings for 'development' options
@@ -364,7 +387,7 @@ const configure = async (cardigantime)=>{
364
387
  const transformedCliArgs = transformCliArgs(cliArgs);
365
388
  // Use CardiganTime's built-in generateConfig method
366
389
  const configDir = transformedCliArgs.configDirectory || KODRDRIV_DEFAULTS.configDirectory;
367
- const absoluteConfigDir = path.isAbsolute(configDir) ? configDir : path.resolve(process.cwd(), configDir);
390
+ const absoluteConfigDir = path__default.isAbsolute(configDir) ? configDir : path__default.resolve(process.cwd(), configDir);
368
391
  await cardigantime.generateConfig(absoluteConfigDir);
369
392
  // Return minimal config for consistency, but main processing is done
370
393
  const config = await validateAndProcessOptions({});
@@ -598,7 +621,7 @@ async function getCliConfig(program, commands) {
598
621
  addSharedOptions(releaseCommand);
599
622
  const publishCommand = program.command('publish').option('--merge-method <method>', 'method to merge PR (merge, squash, rebase)', 'squash').option('--from <from>', 'branch/tag to generate release notes from (default: previous release tag)').option('--target-version <targetVersion>', 'target version for release (explicit version like "4.30.0" or semantic bump: "patch", "minor", "major")').option('--interactive', 'present release notes for interactive review and editing').option('--sendit', 'skip all confirmation prompts and proceed automatically').option('--sync-target', 'attempt to automatically sync target branch with remote before publishing').option('--no-milestones', 'disable GitHub milestone integration').option('--from-main', 'force comparison against main branch instead of previous release tag').description('Publish a release');
600
623
  addSharedOptions(publishCommand);
601
- const treeCommand = program.command('tree [command] [packageArgument]').option('--directory <directory>', 'target directory containing multiple packages (defaults to current directory)').option('--directories [directories...]', 'target directories containing multiple packages (defaults to current directory)').option('--start-from <startFrom>', 'resume execution from this package directory name (useful for restarting failed builds)').option('--stop-at <stopAt>', 'stop execution at this package directory name (the specified package will not be executed)').option('--cmd <cmd>', 'shell command to execute in each package directory (e.g., "npm install", "git status")').option('--parallel', 'execute packages in parallel when dependencies allow (packages with no interdependencies run simultaneously)').option('--excluded-patterns [excludedPatterns...]', 'patterns to exclude packages from processing (e.g., "**/node_modules/**", "dist/*")').option('--continue', 'continue from previous tree publish execution').option('--status', 'check status of running tree publish processes').option('--promote <packageName>', 'mark a package as completed in the execution context (useful for recovery after timeouts)').option('--clean-node-modules', 'for unlink command: remove node_modules and package-lock.json, then reinstall dependencies').description('Analyze package dependencies in workspace and execute commands in dependency order. Supports built-in commands: commit, publish, link, unlink, development, branches, run, checkout');
624
+ const treeCommand = program.command('tree [command] [packageArgument]').option('--directory <directory>', 'target directory containing multiple packages (defaults to current directory)').option('--directories [directories...]', 'target directories containing multiple packages (defaults to current directory)').option('--start-from <startFrom>', 'resume execution from this package directory name (useful for restarting failed builds)').option('--stop-at <stopAt>', 'stop execution at this package directory name (the specified package will not be executed)').option('--cmd <cmd>', 'shell command to execute in each package directory (e.g., "npm install", "git status")').option('--parallel', 'execute packages in parallel when dependencies allow (packages with no interdependencies run simultaneously)').option('--max-concurrency <number>', 'maximum number of packages to execute concurrently (default: number of CPU cores)', parseInt).option('--max-retries <number>', 'maximum retry attempts for failed packages (default: 3)', parseInt).option('--retry-delay <ms>', 'initial retry delay in milliseconds (default: 5000)', parseInt).option('--excluded-patterns [excludedPatterns...]', 'patterns to exclude packages from processing (e.g., "**/node_modules/**", "dist/*")').option('--continue', 'continue from previous tree publish execution').option('--status', 'check status of running tree publish processes').option('--status-parallel', 'show detailed parallel execution status').option('--promote <packageName>', 'mark a package as completed in the execution context (useful for recovery after timeouts)').option('--mark-completed <packages>', 'mark packages as completed using directory names (comma-separated, for recovery)').option('--skip <packages>', 'skip packages and their dependents (comma-separated)').option('--retry-failed', 'retry all previously failed packages').option('--skip-failed', 'skip failed packages and continue with remaining').option('--validate-state', 'validate checkpoint state integrity').option('--clean-node-modules', 'for unlink command: remove node_modules and package-lock.json, then reinstall dependencies').description('Analyze package dependencies in workspace and execute commands in dependency order. Supports built-in commands: commit, publish, link, unlink, development, branches, run, checkout');
602
625
  addSharedOptions(treeCommand);
603
626
  const linkCommand = program.command('link [packageArgument]').option('--scope-roots <scopeRoots>', 'JSON mapping of scopes to root directories (e.g., \'{"@company": "../"}\')').description('Create npm file: dependencies for local development');
604
627
  addSharedOptions(linkCommand);