@eldrforge/kodrdriv 1.2.28 → 1.2.123

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 (82) 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 +271 -88
  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/DynamicTaskPool.js +96 -9
  38. package/dist/execution/DynamicTaskPool.js.map +1 -1
  39. package/dist/execution/ResourceMonitor.js +26 -1
  40. package/dist/execution/ResourceMonitor.js.map +1 -1
  41. package/dist/execution/TreeExecutionAdapter.js +6 -3
  42. package/dist/execution/TreeExecutionAdapter.js.map +1 -1
  43. package/dist/util/checkpointManager.js +2 -4
  44. package/dist/util/checkpointManager.js.map +1 -1
  45. package/dist/util/dependencyGraph.js +2 -4
  46. package/dist/util/dependencyGraph.js.map +1 -1
  47. package/dist/util/general.js +7 -107
  48. package/dist/util/general.js.map +1 -1
  49. package/dist/util/gitMutex.js +63 -18
  50. package/dist/util/gitMutex.js.map +1 -1
  51. package/dist/util/precommitOptimizations.js +310 -0
  52. package/dist/util/precommitOptimizations.js.map +1 -0
  53. package/dist/util/storageAdapter.js +2 -6
  54. package/dist/util/storageAdapter.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-FIXES-IMPLEMENTED.md +0 -405
  68. package/PARALLEL-PUBLISH-IMPROVEMENTS-IMPLEMENTED.md +0 -439
  69. package/PARALLEL-PUBLISH-QUICK-REFERENCE.md +0 -375
  70. package/PARALLEL_EXECUTION_FIX.md +0 -146
  71. package/PUBLISH_IMPROVEMENTS_IMPLEMENTED.md +0 -294
  72. package/RECOVERY-FIXES.md +0 -72
  73. package/SUBMODULE-LOCK-FIX.md +0 -132
  74. package/VERSION-AUDIT-FIX.md +0 -333
  75. package/WORKFLOW-PRECHECK-IMPLEMENTATION.md +0 -239
  76. package/WORKFLOW-SKIP-SUMMARY.md +0 -121
  77. package/dist/util/safety.js +0 -166
  78. package/dist/util/safety.js.map +0 -1
  79. package/dist/util/stdin.js +0 -133
  80. package/dist/util/stdin.js.map +0 -1
  81. package/dist/util/storage.js +0 -187
  82. package/dist/util/storage.js.map +0 -1
@@ -1,90 +0,0 @@
1
- # Branch Audit Progress Feedback Improvements
2
-
3
- ## Problem
4
-
5
- The `kodrdriv tree publish --audit-branches` command takes a long time to run (several minutes for large monorepos) with no progress feedback, making it difficult to know if the command is actually running or stuck.
6
-
7
- ## Root Cause
8
-
9
- The `auditBranchState` function in `src/utils/branchState.ts` performs extensive checks on every package:
10
- - Git operations (fetch, ls-remote, rev-list, merge-tree)
11
- - GitHub API calls to check for existing PRs
12
- - Version validation
13
- - Target branch sync checks
14
-
15
- For a monorepo with 50+ packages, these sequential operations can take 2-3 seconds per package (100-150 seconds total) with no feedback during execution.
16
-
17
- ## Changes Made
18
-
19
- ### 1. Phase-based Progress Reporting
20
-
21
- Added two-phase execution with clear messaging:
22
-
23
- ```
24
- Phase 1/2: Detecting most common branch across packages...
25
- [1/50] Checking branch: package-a
26
- [2/50] Checking branch: package-b
27
- ...
28
- ✓ Most common branch: development (48/50 packages)
29
-
30
- Phase 2/2: Auditing package state (checking git status, conflicts, PRs, versions)...
31
- [1/50] Auditing: package-a
32
- [2/50] Auditing: package-b
33
- ...
34
- ✓ Audit complete: 45/50 packages have no issues
35
- Issues found in 5 package(s)
36
- ```
37
-
38
- ### 2. Per-Package Progress Counters
39
-
40
- Each package now shows its position in the queue `[N/Total]` so users can track overall progress.
41
-
42
- ### 3. Verbose Operation Logging
43
-
44
- Added verbose logging for expensive operations within each package check:
45
- - "Fetching latest from origin..."
46
- - "Checking for merge conflicts..."
47
- - "Checking GitHub for existing PRs..."
48
- - "Found existing PR #123..."
49
-
50
- These only appear when `--verbose` or `--debug` flags are used, providing more detailed feedback without cluttering default output.
51
-
52
- ### 4. Completion Summary
53
-
54
- Added clear completion message showing:
55
- - Number of packages with no issues
56
- - Number of packages with issues (if any)
57
-
58
- ## Impact
59
-
60
- Users can now:
61
- 1. **See that the command is running** - immediate feedback with progress counters
62
- 2. **Estimate completion time** - `[15/50]` indicates 30% complete
63
- 3. **Identify slow operations** - verbose mode shows which operation is taking time
64
- 4. **Know when it's done** - clear completion message
65
-
66
- ## Files Modified
67
-
68
- - `src/utils/branchState.ts` - Added progress logging to `auditBranchState` and `checkBranchStatus` functions
69
-
70
- ## Testing
71
-
72
- Compile check: ✅ Passed (`tsc --noEmit`)
73
-
74
- Manual testing recommended:
75
- ```bash
76
- kodrdriv tree publish --audit-branches
77
- kodrdriv tree publish --audit-branches --verbose
78
- kodrdriv tree publish --audit-branches --debug
79
- ```
80
-
81
- ## Future Optimizations (Not Implemented)
82
-
83
- Potential future improvements for faster execution:
84
- 1. **Parallel package checks** - Process multiple packages simultaneously (requires careful handling of git operations)
85
- 2. **Batch GitHub API calls** - Use GraphQL to query multiple PRs at once
86
- 3. **Cache git fetch results** - Avoid fetching the same remote multiple times
87
- 4. **Skip checks for packages with no changes** - Use git status to detect unchanged packages early
88
-
89
- These optimizations would require more significant refactoring and testing.
90
-
@@ -1,113 +0,0 @@
1
- # Example Output: Branch Audit with Progress Feedback
2
-
3
- ## Before (No Feedback)
4
-
5
- ```bash
6
- $ kodrdriv tree publish --audit-branches
7
- 🔍 Auditing branch state across all packages...
8
- BRANCH_STATE_AUDIT: Auditing branch state for packages | Package Count: 50 | Purpose: Verify synchronization
9
- Checking for merge conflicts with 'main' and existing pull requests...
10
-
11
- [... 2-3 minutes of silence ...]
12
-
13
- ✅ All 45 package(s) are in good state!
14
- ```
15
-
16
- **Problem:** Users don't know if the command is running or stuck.
17
-
18
- ---
19
-
20
- ## After (With Progress Feedback)
21
-
22
- ### Default Output
23
-
24
- ```bash
25
- $ kodrdriv tree publish --audit-branches
26
- 🔍 Auditing branch state across all packages...
27
- BRANCH_STATE_AUDIT: Auditing branch state for packages | Package Count: 50 | Purpose: Verify synchronization
28
- Checking for merge conflicts with 'main' and existing pull requests...
29
-
30
- 📋 Phase 1/2: Detecting most common branch across packages...
31
- [1/50] Checking branch: @myorg/core
32
- [2/50] Checking branch: @myorg/utils
33
- [3/50] Checking branch: @myorg/api
34
- ...
35
- [48/50] Checking branch: @myorg/tests
36
- [49/50] Checking branch: @myorg/docs
37
- [50/50] Checking branch: @myorg/cli
38
- ✓ Most common branch: development (48/50 packages)
39
-
40
- 📋 Phase 2/2: Auditing package state (checking git status, conflicts, PRs, versions)...
41
- [1/50] Auditing: @myorg/core
42
- [2/50] Auditing: @myorg/utils
43
- [3/50] Auditing: @myorg/api
44
- ...
45
- [48/50] Auditing: @myorg/tests
46
- [49/50] Auditing: @myorg/docs
47
- [50/50] Auditing: @myorg/cli
48
- ✓ Audit complete: 45/50 packages have no issues
49
- Issues found in 5 package(s)
50
-
51
- [... detailed issue report ...]
52
-
53
- ⚠️ Found issues in 5 package(s). Review the fixes above.
54
- ```
55
-
56
- ### Verbose Output (`--verbose`)
57
-
58
- ```bash
59
- $ kodrdriv tree publish --audit-branches --verbose
60
- 🔍 Auditing branch state across all packages...
61
- BRANCH_STATE_AUDIT: Auditing branch state for packages | Package Count: 50 | Purpose: Verify synchronization
62
- Checking for merge conflicts with 'main' and existing pull requests...
63
-
64
- 📋 Phase 1/2: Detecting most common branch across packages...
65
- [1/50] Checking branch: @myorg/core
66
- [2/50] Checking branch: @myorg/utils
67
- ...
68
- ✓ Most common branch: development (48/50 packages)
69
-
70
- 📋 Phase 2/2: Auditing package state (checking git status, conflicts, PRs, versions)...
71
- [1/50] Auditing: @myorg/core
72
- Fetching latest from origin for /path/to/core...
73
- Checking for merge conflicts with main...
74
- Checking GitHub for existing PRs...
75
- [2/50] Auditing: @myorg/utils
76
- Fetching latest from origin for /path/to/utils...
77
- Checking for merge conflicts with main...
78
- Checking GitHub for existing PRs...
79
- Found existing PR #123: https://github.com/myorg/utils/pull/123
80
- [3/50] Auditing: @myorg/api
81
- Fetching latest from origin for /path/to/api...
82
- Checking for merge conflicts with main...
83
- ⚠️ Merge conflicts detected with main
84
- Checking GitHub for existing PRs...
85
- ...
86
- ✓ Audit complete: 45/50 packages have no issues
87
- Issues found in 5 package(s)
88
- ```
89
-
90
- ## Benefits
91
-
92
- 1. **Immediate Feedback:** Users see progress start immediately
93
- 2. **Progress Tracking:** `[N/Total]` shows exactly where you are
94
- 3. **Time Estimation:** If `[10/50]` takes 30 seconds, expect ~2.5 minutes total
95
- 4. **Debug Support:** Verbose mode shows which operations are slow
96
- 5. **Clear Completion:** Final summary shows results at a glance
97
-
98
- ## Testing the Changes
99
-
100
- ```bash
101
- # Test in a monorepo with multiple packages
102
- cd /path/to/your/monorepo
103
-
104
- # Default output (progress with package names)
105
- kodrdriv tree publish --audit-branches
106
-
107
- # Verbose output (shows git operations)
108
- kodrdriv tree publish --audit-branches --verbose
109
-
110
- # Debug output (most detailed)
111
- kodrdriv tree publish --audit-branches --debug
112
- ```
113
-
@@ -1,450 +0,0 @@
1
- # Checkpoint Recovery Fix - Critical Bug Resolution
2
-
3
- ## Issue Summary
4
-
5
- **Date**: 2025-12-12
6
- **Version Fixed**: kodrdriv 1.2.29-dev.0
7
- **Priority**: CRITICAL
8
- **Impact**: Parallel publish checkpoint recovery was completely broken for the primary use case
9
-
10
- ### The Problem
11
-
12
- The parallel publish checkpoint/recovery system failed to proceed to dependent packages after marking a root dependency as completed, resulting in an infinite loop where all dependent packages remained "Skipped due to dependencies" even though the dependency was successfully marked as completed.
13
-
14
- This made recovery from ANY partial publish failure essentially impossible with parallel mode, defeating the entire purpose of the checkpoint/recovery system.
15
-
16
- ### Real-World Scenario
17
-
18
- Publishing all packages in a monorepo after one package was already published:
19
-
20
- 1. **Initial State**: Package `common-config` already published to npm as v1.1.36, working branch has v1.1.37-dev.0
21
- 2. **Attempt 1**: Run `kodrdriv tree publish --parallel` → `common-config` fails (expected - already published), all 15 dependent packages skipped
22
- 3. **Recovery Attempt**: Run `kodrdriv tree publish --parallel --mark-completed "common-config" --continue`
23
- 4. **Expected**: System marks `common-config` as completed, proceeds to level 2 packages (`logging`, `docs-template`)
24
- 5. **Actual**: All 15 packages remain perpetually skipped, execution completes immediately without attempting any publishes
25
-
26
- ## Root Cause Analysis
27
-
28
- ### The Bug
29
-
30
- The issue was in two places where checkpoint state was loaded without reassessing which packages could now proceed:
31
-
32
- #### 1. `DynamicTaskPool.loadCheckpoint()` (src/execution/DynamicTaskPool.ts)
33
-
34
- ```typescript
35
- // BEFORE (BROKEN)
36
- private async loadCheckpoint(): Promise<void> {
37
- const checkpoint = await this.checkpointManager.load();
38
- // ... restore metadata ...
39
-
40
- this.state = checkpoint.state; // Directly assigns checkpoint state
41
-
42
- // Clear running state
43
- for (const running of this.state.running) {
44
- this.state.pending.push(running.name);
45
- }
46
- this.state.running = [];
47
- }
48
- ```
49
-
50
- **Problem**: When the checkpoint state is directly assigned, packages in the `skipped` array remain there. The subsequent `updateReadyQueue()` call only checks packages in the `pending` array, so skipped packages are never reassessed even though their dependencies might now be complete.
51
-
52
- #### 2. `RecoveryManager.updateReadyState()` (src/execution/RecoveryManager.ts)
53
-
54
- ```typescript
55
- // BEFORE (BROKEN)
56
- private updateReadyState(): void {
57
- // Move packages from pending to ready if dependencies met
58
- const nowReady: string[] = [];
59
-
60
- for (const pkg of this.checkpoint.state.pending) { // Only checks pending!
61
- const deps = this.graph.edges.get(pkg) || new Set();
62
- const allDepsCompleted = Array.from(deps).every(dep =>
63
- this.checkpoint.state.completed.includes(dep)
64
- );
65
-
66
- if (allDepsCompleted) {
67
- nowReady.push(pkg);
68
- }
69
- }
70
-
71
- // Move to ready
72
- for (const pkg of nowReady) {
73
- this.checkpoint.state.pending = this.checkpoint.state.pending.filter(p => p !== pkg);
74
- this.checkpoint.state.ready.push(pkg);
75
- }
76
- }
77
- ```
78
-
79
- **Problem**: This method only evaluated packages in the `pending` state. Packages that were previously skipped due to failed dependencies were never reevaluated, even after their dependencies were marked as completed via `--mark-completed`.
80
-
81
- ### Execution Flow Showing the Bug
82
-
83
- ```
84
- Initial Run:
85
- common-config → FAILS
86
- [Dependency checker blocks all dependents]
87
- → logging, docs-template, core, ... → all moved to SKIPPED
88
-
89
- User runs --mark-completed "common-config":
90
- RecoveryManager.markCompleted():
91
- ✓ Adds common-config to completed array
92
- ✓ Calls updateReadyState()
93
- ✓ updateReadyState() only checks pending array (empty!)
94
- ✓ Skipped packages never reevaluated
95
- ✓ Checkpoint saved with skipped=[logging, docs-template, ...]
96
-
97
- User runs --continue:
98
- DynamicTaskPool.loadCheckpoint():
99
- ✓ Loads checkpoint
100
- ✓ this.state = checkpoint.state (skipped array restored!)
101
- ✓ Calls updateReadyQueue()
102
- ✓ updateReadyQueue() only checks pending array (empty!)
103
- ✓ Skipped packages never reevaluated
104
-
105
- Main execution loop:
106
- ✓ pending.length === 0
107
- ✓ ready.length === 0
108
- ✓ runningTasks.size === 0
109
- ✓ isComplete() returns true
110
- ✓ Execution exits immediately
111
-
112
- Result: "✅ Published (1): common-config, ⊘ Skipped (15): [all others]"
113
- ```
114
-
115
- ## The Fix
116
-
117
- ### 1. Dynamic Dependency Resolution in `DynamicTaskPool.loadCheckpoint()`
118
-
119
- Added logic to re-evaluate skipped packages after loading checkpoint:
120
-
121
- ```typescript
122
- // AFTER (FIXED)
123
- private async loadCheckpoint(): Promise<void> {
124
- const checkpoint = await this.checkpointManager.load();
125
- // ... restore metadata ...
126
-
127
- this.state = checkpoint.state;
128
-
129
- // Clear running state
130
- for (const running of this.state.running) {
131
- this.state.pending.push(running.name);
132
- }
133
- this.state.running = [];
134
-
135
- // CRITICAL FIX: Re-evaluate skipped packages
136
- // After loading checkpoint (especially with --mark-completed), packages that were
137
- // skipped due to failed dependencies might now be eligible to run if those
138
- // dependencies are now completed. Move them back to pending for reassessment.
139
- const unblocked: string[] = [];
140
- for (const packageName of this.state.skipped) {
141
- // Check if all dependencies are now completed
142
- const dependencies = this.graph.edges.get(packageName) || new Set();
143
- const allDepsCompleted = Array.from(dependencies).every(dep =>
144
- this.state.completed.includes(dep) || this.state.skippedNoChanges.includes(dep)
145
- );
146
-
147
- // Check if any dependencies are still failed
148
- const anyDepsFailed = Array.from(dependencies).some(dep =>
149
- this.state.failed.some(f => f.name === dep)
150
- );
151
-
152
- if (allDepsCompleted && !anyDepsFailed) {
153
- unblocked.push(packageName);
154
- }
155
- }
156
-
157
- // Move unblocked packages back to pending
158
- if (unblocked.length > 0) {
159
- this.logger.info(`✓ Unblocked ${unblocked.length} package(s): ${unblocked.join(', ')}`);
160
- for (const packageName of unblocked) {
161
- this.state.skipped = this.state.skipped.filter(p => p !== packageName);
162
- this.state.pending.push(packageName);
163
- }
164
- }
165
- }
166
- ```
167
-
168
- ### 2. Enhanced `RecoveryManager.updateReadyState()`
169
-
170
- Modified to check skipped packages first, then move eligible ones back to pending:
171
-
172
- ```typescript
173
- // AFTER (FIXED)
174
- private updateReadyState(): void {
175
- // CRITICAL FIX: First, re-evaluate skipped packages
176
- // Packages that were skipped due to failed dependencies might now be eligible
177
- // to run if those dependencies have been completed (e.g., via --mark-completed)
178
- const unblocked: string[] = [];
179
- for (const pkg of this.checkpoint.state.skipped) {
180
- const deps = this.graph.edges.get(pkg) || new Set();
181
- const allDepsCompleted = Array.from(deps).every(dep =>
182
- this.checkpoint.state.completed.includes(dep) ||
183
- this.checkpoint.state.skippedNoChanges.includes(dep)
184
- );
185
-
186
- // Check if any dependencies are still failed
187
- const anyDepsFailed = Array.from(deps).some(dep =>
188
- this.checkpoint.state.failed.some(f => f.name === dep)
189
- );
190
-
191
- if (allDepsCompleted && !anyDepsFailed) {
192
- unblocked.push(pkg);
193
- }
194
- }
195
-
196
- // Move unblocked packages back to pending
197
- for (const pkg of unblocked) {
198
- this.checkpoint.state.skipped = this.checkpoint.state.skipped.filter(p => p !== pkg);
199
- this.checkpoint.state.pending.push(pkg);
200
- this.logger.info(`↻ ${pkg} unblocked (dependencies now satisfied)`);
201
- }
202
-
203
- // Move packages from pending to ready if dependencies met
204
- const nowReady: string[] = [];
205
-
206
- for (const pkg of this.checkpoint.state.pending) {
207
- const deps = this.graph.edges.get(pkg) || new Set();
208
- const allDepsCompleted = Array.from(deps).every(dep =>
209
- this.checkpoint.state.completed.includes(dep) ||
210
- this.checkpoint.state.skippedNoChanges.includes(dep)
211
- );
212
-
213
- if (allDepsCompleted) {
214
- nowReady.push(pkg);
215
- }
216
- }
217
-
218
- for (const pkg of nowReady) {
219
- this.checkpoint.state.pending = this.checkpoint.state.pending.filter(p => p !== pkg);
220
- this.checkpoint.state.ready.push(pkg);
221
- }
222
- }
223
- ```
224
-
225
- ### 3. Improved User Feedback in `markCompleted()`
226
-
227
- Enhanced to show what was unblocked:
228
-
229
- ```typescript
230
- // Update ready queue and count what got unblocked
231
- const beforeSkipped = this.checkpoint.state.skipped.length;
232
- const beforeReady = this.checkpoint.state.ready.length;
233
-
234
- this.updateReadyState();
235
-
236
- const afterSkipped = this.checkpoint.state.skipped.length;
237
- const afterReady = this.checkpoint.state.ready.length;
238
-
239
- const unblockedCount = beforeSkipped - afterSkipped;
240
- const newReadyCount = afterReady - beforeReady;
241
-
242
- // Save checkpoint
243
- await this.saveCheckpoint();
244
-
245
- this.logger.info('State updated successfully');
246
-
247
- if (unblockedCount > 0) {
248
- this.logger.info(`✓ Unblocked ${unblockedCount} package(s)`);
249
- }
250
- if (newReadyCount > 0) {
251
- this.logger.info(`✓ ${newReadyCount} package(s) ready to execute`);
252
- }
253
- if (unblockedCount === 0 && newReadyCount === 0 && this.checkpoint.state.skipped.length > 0) {
254
- this.logger.warn(`⚠️ No packages unblocked. ${this.checkpoint.state.skipped.length} packages still blocked by dependencies.`);
255
- this.logger.warn(' Use --status to see what\'s blocking them.');
256
- }
257
- ```
258
-
259
- ### 4. Enhanced Status Display
260
-
261
- Improved `showStatus()` to show detailed dependency states:
262
-
263
- ```typescript
264
- // Skipped packages with dependency details
265
- if (skipped > 0) {
266
- lines.push('🔒 Blocked Packages (dependency issues):');
267
- for (const pkgName of this.checkpoint.state.skipped) {
268
- const deps = this.graph.edges.get(pkgName) || new Set();
269
- const depStatus = Array.from(deps).map(dep => {
270
- if (this.checkpoint.state.completed.includes(dep) ||
271
- this.checkpoint.state.skippedNoChanges.includes(dep)) {
272
- return `${dep} ✓`;
273
- } else if (this.checkpoint.state.failed.some(f => f.name === dep)) {
274
- return `${dep} ❌`;
275
- } else if (this.checkpoint.state.running.some(r => r.name === dep)) {
276
- return `${dep} ⏳`;
277
- } else if (this.checkpoint.state.skipped.includes(dep)) {
278
- return `${dep} 🔒`;
279
- } else if (this.checkpoint.state.pending.includes(dep) ||
280
- this.checkpoint.state.ready.includes(dep)) {
281
- return `${dep} ⏳`;
282
- } else {
283
- return `${dep} ❓`;
284
- }
285
- });
286
-
287
- lines.push(` • ${pkgName}`);
288
- if (depStatus.length > 0) {
289
- lines.push(` Dependencies: ${depStatus.join(', ')}`);
290
- }
291
- }
292
- lines.push('');
293
- lines.push('Legend: ✓ = complete, ❌ = failed, ⏳ = pending/running, 🔒 = blocked');
294
- lines.push('');
295
- }
296
-
297
- // Ready to execute
298
- if (this.checkpoint.state.ready.length > 0) {
299
- lines.push('⏳ Ready to Execute:');
300
- for (const pkgName of this.checkpoint.state.ready) {
301
- const deps = this.graph.edges.get(pkgName) || new Set();
302
- if (deps.size === 0) {
303
- lines.push(` • ${pkgName} (no dependencies)`);
304
- } else {
305
- const depList = Array.from(deps).join(', ');
306
- lines.push(` • ${pkgName} (depends on: ${depList})`);
307
- }
308
- }
309
- lines.push('');
310
- }
311
- ```
312
-
313
- ## Test Coverage
314
-
315
- Added comprehensive test cases in `tests/execution/RecoveryManager.test.ts`:
316
-
317
- ### Test Case 1: Basic Unblocking
318
- ```typescript
319
- it('should unblock skipped packages when dependencies are marked completed', async () => {
320
- // Simulates: A fails → B,C,D skipped → A marked complete → B,C move to ready, D stays blocked
321
- // Verifies packages with satisfied dependencies are immediately unblocked
322
- });
323
- ```
324
-
325
- ### Test Case 2: Multi-Level Dependencies
326
- ```typescript
327
- it('should handle multi-level dependency unblocking', async () => {
328
- // Tests cascading unblock: A → B → C
329
- // When A completes, B should be ready
330
- // When B completes, C should be ready
331
- });
332
- ```
333
-
334
- ### Test Case 3: Partial Dependency Satisfaction
335
- ```typescript
336
- it('should not unblock packages if some dependencies still failed', async () => {
337
- // Ensures packages stay blocked if ANY dependency is still failed
338
- // C depends on A and B, A completes but B is failed → C stays blocked
339
- });
340
- ```
341
-
342
- All 23 tests pass, including the 3 new critical test cases.
343
-
344
- ## Expected Behavior After Fix
345
-
346
- ### Scenario: Fjell Monorepo (16 packages)
347
-
348
- ```bash
349
- # Initial attempt - common-config already published
350
- $ kodrdriv tree publish --parallel --model "gpt-5-mini"
351
- ❌ @fjell/common-config (already published)
352
- ⊘ Skipped due to dependencies (15): [all others]
353
-
354
- # Recovery with fix
355
- $ kodrdriv tree publish --parallel --mark-completed "common-config" --continue
356
- ✓ Marked @fjell/common-config as completed
357
- ↻ @fjell/logging unblocked (dependencies now satisfied)
358
- ↻ @fjell/docs-template unblocked (dependencies now satisfied)
359
- ✓ Unblocked 2 package(s)
360
- ✓ 2 package(s) ready to execute
361
-
362
- 📦 Executing 2 packages in parallel
363
- [1/15] ✅ @fjell/logging
364
- [2/15] ✅ @fjell/docs-template
365
- [3/15] ✅ @fjell/core
366
- [4/15] ✅ @fjell/http-api
367
- ... continues publishing all remaining packages ...
368
- ```
369
-
370
- ### Status Output Example
371
-
372
- ```bash
373
- $ kodrdriv tree --status-parallel
374
-
375
- ═══════════════════════════════════════
376
- Parallel Execution Status
377
- ═══════════════════════════════════════
378
-
379
- Execution ID: 27ea3c44-e707-46d6-b411-bfaef689d240
380
- Started: 12/12/2025, 6:20:00 AM
381
- Last Updated: 12/12/2025, 6:21:30 AM
382
-
383
- 📊 Progress:
384
- Completed: 3/16 (18%)
385
- Skipped (no changes): 0
386
- Running: 2
387
- Pending: 8
388
- Failed: 0
389
- Skipped (dependency failed): 3
390
-
391
- Progress: [███░░░░░░░░░░░░░░░░░] 18%
392
-
393
- 🔄 Currently Running:
394
- • @fjell/core (1m 23s)
395
- • @fjell/http-api (45s)
396
-
397
- ⏳ Ready to Execute:
398
- • @fjell/registry (depends on: @fjell/core, @fjell/common-config)
399
- • @fjell/lib (depends on: @fjell/core)
400
-
401
- 🔒 Blocked Packages (dependency issues):
402
- • @fjell/client-api
403
- Dependencies: @fjell/core ⏳, @fjell/lib ⏳, @fjell/common-config ✓
404
- • @fjell/sample-app
405
- Dependencies: @fjell/client-api 🔒, @fjell/core ⏳
406
- • @fjell/express-router
407
- Dependencies: @fjell/http-api ⏳, @fjell/lib ⏳
408
-
409
- Legend: ✓ = complete, ❌ = failed, ⏳ = pending/running, 🔒 = blocked
410
- ```
411
-
412
- ## Impact
413
-
414
- ### Before Fix
415
- - ❌ Recovery from partial failures completely broken
416
- - ❌ `--mark-completed` effectively useless
417
- - ❌ Any scenario where a package was already published blocked entire tree
418
- - ❌ 20+ hours wasted on manual workarounds
419
-
420
- ### After Fix
421
- - ✅ Recovery works as designed
422
- - ✅ Packages unblock as soon as dependencies are satisfied
423
- - ✅ Clear feedback showing what was unblocked
424
- - ✅ Detailed status showing exactly why packages are blocked
425
- - ✅ Parallel publishing viable for production use
426
-
427
- ## Files Modified
428
-
429
- - `src/execution/DynamicTaskPool.ts` - Added checkpoint state reassessment
430
- - `src/execution/RecoveryManager.ts` - Enhanced updateReadyState() and markCompleted()
431
- - `tests/execution/RecoveryManager.test.ts` - Added 3 critical test cases
432
-
433
- ## Backward Compatibility
434
-
435
- ✅ **Fully backward compatible** - No breaking changes to API or command-line interface.
436
-
437
- Existing checkpoints will automatically benefit from the fix on next `--continue` attempt.
438
-
439
- ## Related Issues
440
-
441
- This fix resolves the core issue described in the user's detailed bug report, addressing:
442
- - ✅ Infinite loop after `--mark-completed`
443
- - ✅ All dependent packages remaining perpetually skipped
444
- - ✅ Checkpoint system defeating its own purpose
445
- - ✅ Impossible recovery from partial publish failures
446
-
447
- ## Version
448
-
449
- Fixed in: **kodrdriv 1.2.29-dev.0**
450
-