@eldrforge/kodrdriv 1.2.129 → 1.2.131

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 (48) hide show
  1. package/DUPLICATION-CLEANUP.md +104 -0
  2. package/dist/application.js +1 -2
  3. package/dist/application.js.map +1 -1
  4. package/dist/commands/audio-commit.js +1 -2
  5. package/dist/commands/audio-commit.js.map +1 -1
  6. package/dist/commands/clean.js +1 -2
  7. package/dist/commands/clean.js.map +1 -1
  8. package/dist/commands/commit.js +1 -2
  9. package/dist/commands/commit.js.map +1 -1
  10. package/dist/commands/review.js +1 -2
  11. package/dist/commands/review.js.map +1 -1
  12. package/dist/commands/tree.js +5 -5
  13. package/dist/commands/tree.js.map +1 -1
  14. package/dist/commands/versions.js.map +1 -1
  15. package/dist/constants.js +1 -1
  16. package/dist/content/diff.js +1 -1
  17. package/dist/content/diff.js.map +1 -1
  18. package/dist/content/log.js +1 -1
  19. package/dist/content/log.js.map +1 -1
  20. package/package.json +9 -7
  21. package/dist/error/CancellationError.js +0 -9
  22. package/dist/error/CancellationError.js.map +0 -1
  23. package/dist/error/CommandErrors.js +0 -63
  24. package/dist/error/CommandErrors.js.map +0 -1
  25. package/dist/error/ExitError.js +0 -9
  26. package/dist/error/ExitError.js.map +0 -1
  27. package/dist/execution/CommandValidator.js +0 -192
  28. package/dist/execution/CommandValidator.js.map +0 -1
  29. package/dist/execution/DependencyChecker.js +0 -102
  30. package/dist/execution/DependencyChecker.js.map +0 -1
  31. package/dist/execution/DynamicTaskPool.js +0 -661
  32. package/dist/execution/DynamicTaskPool.js.map +0 -1
  33. package/dist/execution/RecoveryManager.js +0 -584
  34. package/dist/execution/RecoveryManager.js.map +0 -1
  35. package/dist/execution/ResourceMonitor.js +0 -150
  36. package/dist/execution/ResourceMonitor.js.map +0 -1
  37. package/dist/execution/Scheduler.js +0 -98
  38. package/dist/execution/Scheduler.js.map +0 -1
  39. package/dist/execution/TreeExecutionAdapter.js +0 -225
  40. package/dist/execution/TreeExecutionAdapter.js.map +0 -1
  41. package/dist/ui/ProgressFormatter.js +0 -250
  42. package/dist/ui/ProgressFormatter.js.map +0 -1
  43. package/dist/util/checkpointManager.js +0 -166
  44. package/dist/util/checkpointManager.js.map +0 -1
  45. package/dist/util/dependencyGraph.js +0 -222
  46. package/dist/util/dependencyGraph.js.map +0 -1
  47. package/dist/util/mutex.js +0 -96
  48. package/dist/util/mutex.js.map +0 -1
@@ -1,661 +0,0 @@
1
- import { EventEmitter } from 'events';
2
- import { randomUUID } from 'crypto';
3
- import { getLogger } from '../logging.js';
4
- import { findAllDependents } from '../util/dependencyGraph.js';
5
- import { CheckpointManager } from '../util/checkpointManager.js';
6
- import { DependencyChecker } from './DependencyChecker.js';
7
- import { ResourceMonitor } from './ResourceMonitor.js';
8
- import { Scheduler } from './Scheduler.js';
9
-
10
- function _define_property(obj, key, value) {
11
- if (key in obj) {
12
- Object.defineProperty(obj, key, {
13
- value: value,
14
- enumerable: true,
15
- configurable: true,
16
- writable: true
17
- });
18
- } else {
19
- obj[key] = value;
20
- }
21
- return obj;
22
- }
23
- /**
24
- * DynamicTaskPool manages parallel execution of packages with dependency awareness
25
- */ class DynamicTaskPool extends EventEmitter {
26
- /**
27
- * Main execution entry point
28
- */ async execute() {
29
- this.logger.info(`EXECUTION_STARTING: Starting parallel execution | Max Concurrency: ${this.config.maxConcurrency} | Mode: parallel | Purpose: Execute packages with dependency awareness`);
30
- this.emit('execution:started', {
31
- totalPackages: this.graph.packages.size
32
- });
33
- try {
34
- // Load checkpoint if continuing
35
- if (this.config.continue) {
36
- await this.loadCheckpoint();
37
- }
38
- // Initialize ready queue
39
- this.updateReadyQueue();
40
- // Main execution loop
41
- while(!this.isComplete()){
42
- // Schedule as many packages as we can
43
- const availableSlots = this.resourceMonitor.getAvailableSlots();
44
- if (availableSlots > 0 && this.state.ready.length > 0) {
45
- const toSchedule = this.scheduler.getNext(availableSlots, this.state);
46
- for (const packageName of toSchedule){
47
- await this.schedulePackage(packageName);
48
- }
49
- }
50
- // Check if we're stuck
51
- if (this.runningTasks.size === 0) {
52
- if (this.state.ready.length > 0) {
53
- throw new Error('Deadlock detected: packages ready but cannot execute');
54
- }
55
- break; // No more work to do
56
- }
57
- // Wait for next package to complete
58
- const completedTask = await this.waitForNext();
59
- await this.handleTaskCompletion(completedTask);
60
- // Update ready queue
61
- this.updateReadyQueue();
62
- // Save checkpoint periodically
63
- if (this.shouldCheckpoint()) {
64
- await this.saveCheckpoint();
65
- }
66
- }
67
- // Final checkpoint and cleanup
68
- // Only cleanup if everything completed (no failures, no skipped packages due to dependencies)
69
- // Note: skippedNoChanges is OK - those packages successfully ran but had nothing to do
70
- const allCompleted = this.state.failed.length === 0 && this.state.skipped.length === 0;
71
- if (allCompleted) {
72
- await this.checkpointManager.cleanup();
73
- } else {
74
- await this.saveCheckpoint();
75
- }
76
- // Build and return result
77
- const result = this.buildExecutionResult();
78
- this.emit('execution:completed', {
79
- result
80
- });
81
- return result;
82
- } catch (error) {
83
- // Save checkpoint on error
84
- await this.saveCheckpoint();
85
- throw error;
86
- }
87
- }
88
- /**
89
- * Initialize execution state
90
- */ initializeState() {
91
- const buildOrder = Array.from(this.graph.packages.keys());
92
- return {
93
- pending: [
94
- ...buildOrder
95
- ],
96
- ready: [],
97
- running: [],
98
- completed: [],
99
- failed: [],
100
- skipped: [],
101
- skippedNoChanges: []
102
- };
103
- }
104
- /**
105
- * Schedule a package for execution
106
- */ async schedulePackage(packageName) {
107
- // Move from ready to running
108
- this.state.ready = this.state.ready.filter((p)=>p !== packageName);
109
- // Allocate resource
110
- if (!this.resourceMonitor.allocate()) {
111
- throw new Error(`Failed to allocate resource for ${packageName}`);
112
- }
113
- // Record start time
114
- this.packageStartTimes.set(packageName, new Date());
115
- // Create abort controller
116
- const controller = new AbortController();
117
- // Start execution
118
- const promise = this.executePackage(packageName, controller.signal);
119
- // Track running task
120
- const task = {
121
- packageName,
122
- startTime: new Date(),
123
- promise,
124
- controller
125
- };
126
- this.runningTasks.set(packageName, task);
127
- // Update state
128
- this.state.running.push({
129
- name: packageName,
130
- startTime: task.startTime.toISOString(),
131
- elapsedTime: 0
132
- });
133
- // Emit event
134
- this.emit('package:started', {
135
- packageName
136
- });
137
- this.logger.verbose(`Scheduled ${packageName} (${this.runningTasks.size}/${this.config.maxConcurrency} slots used)`);
138
- }
139
- /**
140
- * Execute a single package (placeholder - will be overridden or use callback)
141
- */ async executePackage(_packageName, _signal) {
142
- // This is a placeholder that will be replaced with actual execution logic
143
- // In the real implementation, this would call the tree.ts executePackage function
144
- throw new Error('executePackage must be implemented');
145
- }
146
- /**
147
- * Wait for next task to complete
148
- */ async waitForNext() {
149
- const runningTasks = Array.from(this.runningTasks.entries());
150
- const promises = runningTasks.map(([name, task])=>task.promise.then((result)=>({
151
- packageName: name,
152
- result,
153
- error: null
154
- })).catch((error)=>({
155
- packageName: name,
156
- result: null,
157
- error
158
- })));
159
- return await Promise.race(promises);
160
- }
161
- /**
162
- * Handle task completion
163
- */ async handleTaskCompletion(task) {
164
- const { packageName, result, error } = task;
165
- // Remove from running
166
- this.runningTasks.delete(packageName);
167
- this.state.running = this.state.running.filter((r)=>r.name !== packageName);
168
- this.resourceMonitor.release();
169
- // Record timing
170
- const endTime = new Date();
171
- this.packageEndTimes.set(packageName, endTime);
172
- const startTime = this.packageStartTimes.get(packageName);
173
- const duration = endTime.getTime() - startTime.getTime();
174
- this.packageDurations.set(packageName, duration);
175
- if (error) {
176
- await this.handleFailure(packageName, error);
177
- } else {
178
- await this.handleSuccess(packageName, result);
179
- }
180
- }
181
- /**
182
- * Handle successful package completion
183
- */ async handleSuccess(packageName, result) {
184
- // Check if this was skipped due to no changes
185
- if (result.skippedNoChanges) {
186
- this.state.skippedNoChanges.push(packageName);
187
- const duration = this.packageDurations.get(packageName);
188
- this.logger.info(`PACKAGE_SKIPPED_NO_CHANGES: Package skipped due to no code changes | Package: ${packageName} | Duration: ${this.formatDuration(duration)} | Reason: no-changes`);
189
- this.emit('package:skipped-no-changes', {
190
- packageName,
191
- result
192
- });
193
- } else {
194
- this.state.completed.push(packageName);
195
- const duration = this.packageDurations.get(packageName);
196
- this.logger.info(`PACKAGE_EXECUTION_COMPLETE: Package execution finished successfully | Package: ${packageName} | Duration: ${this.formatDuration(duration)} | Status: success`);
197
- this.emit('package:completed', {
198
- packageName,
199
- result
200
- });
201
- // Track published version if applicable
202
- if (result.publishedVersion) {
203
- this.publishedVersions.push({
204
- name: packageName,
205
- version: result.publishedVersion,
206
- time: new Date()
207
- });
208
- }
209
- }
210
- }
211
- /**
212
- * Handle package failure
213
- */ async handleFailure(packageName, error) {
214
- const attemptNumber = (this.retryAttempts.get(packageName) || 0) + 1;
215
- this.retryAttempts.set(packageName, attemptNumber);
216
- const isRetriable = this.isRetriableError(error);
217
- const maxRetries = this.config.maxRetries || 3;
218
- const canRetry = isRetriable && attemptNumber < maxRetries;
219
- if (canRetry) {
220
- // Schedule retry
221
- this.logger.warn(`⟳ ${packageName} failed (attempt ${attemptNumber}/${maxRetries}), will retry`);
222
- this.state.pending.push(packageName);
223
- this.emit('package:retrying', {
224
- packageName,
225
- attemptNumber
226
- });
227
- // Apply backoff delay
228
- const delay = this.calculateRetryDelay(attemptNumber);
229
- await new Promise((resolve)=>setTimeout(resolve, delay));
230
- } else {
231
- // Permanent failure
232
- const dependencies = Array.from(this.graph.edges.get(packageName) || []);
233
- const dependents = Array.from(findAllDependents(packageName, this.graph));
234
- // Extract detailed error information
235
- const errorDetails = this.extractErrorDetails(error, packageName);
236
- const failureInfo = {
237
- name: packageName,
238
- error: error.message,
239
- stack: error.stack,
240
- isRetriable,
241
- attemptNumber,
242
- failedAt: new Date().toISOString(),
243
- dependencies,
244
- dependents,
245
- errorDetails
246
- };
247
- this.state.failed.push(failureInfo);
248
- this.logger.error(`PACKAGE_FAILED_PERMANENT: Package failed permanently | Package: ${packageName} | Error: ${error.message} | Status: failed | Retriable: false`);
249
- this.emit('package:failed', {
250
- packageName,
251
- error
252
- });
253
- // Cascade failure to dependents
254
- await this.cascadeFailure(packageName);
255
- }
256
- }
257
- /**
258
- * Cascade failure to dependent packages
259
- */ async cascadeFailure(failedPackage) {
260
- const toSkip = findAllDependents(failedPackage, this.graph);
261
- for (const dependent of toSkip){
262
- // Remove from pending/ready
263
- this.state.pending = this.state.pending.filter((p)=>p !== dependent);
264
- this.state.ready = this.state.ready.filter((p)=>p !== dependent);
265
- // Add to skipped
266
- if (!this.state.skipped.includes(dependent)) {
267
- this.state.skipped.push(dependent);
268
- this.logger.warn(`PACKAGE_SKIPPED_DEPENDENCY: Package skipped due to failed dependency | Package: ${dependent} | Failed Dependency: ${failedPackage} | Reason: dependency-failed`);
269
- this.emit('package:skipped', {
270
- packageName: dependent,
271
- reason: `Depends on failed ${failedPackage}`
272
- });
273
- }
274
- }
275
- }
276
- /**
277
- * Update ready queue
278
- */ updateReadyQueue() {
279
- const nowReady = [];
280
- for (const packageName of this.state.pending){
281
- if (this.dependencyChecker.isReady(packageName, this.state)) {
282
- nowReady.push(packageName);
283
- }
284
- }
285
- for (const packageName of nowReady){
286
- this.state.pending = this.state.pending.filter((p)=>p !== packageName);
287
- this.state.ready.push(packageName);
288
- }
289
- }
290
- /**
291
- * Check if execution is complete
292
- */ isComplete() {
293
- return this.state.pending.length === 0 && this.state.ready.length === 0 && this.runningTasks.size === 0;
294
- }
295
- /**
296
- * Determine if should save checkpoint
297
- */ shouldCheckpoint() {
298
- // Checkpoint after each completion for now
299
- // Could be optimized to checkpoint less frequently
300
- return true;
301
- }
302
- /**
303
- * Save checkpoint
304
- */ async saveCheckpoint() {
305
- const checkpoint = {
306
- version: '1.0.0',
307
- executionId: this.executionId,
308
- createdAt: this.startTime.toISOString(),
309
- lastUpdated: new Date().toISOString(),
310
- command: this.config.command,
311
- originalConfig: this.config.config,
312
- dependencyGraph: {
313
- packages: Array.from(this.graph.packages.values()).map((pkg)=>({
314
- name: pkg.name,
315
- version: pkg.version,
316
- path: pkg.path,
317
- dependencies: Array.from(pkg.dependencies)
318
- })),
319
- edges: Array.from(this.graph.edges.entries()).map(([pkg, deps])=>[
320
- pkg,
321
- Array.from(deps)
322
- ])
323
- },
324
- buildOrder: [
325
- ...this.state.pending,
326
- ...this.state.ready,
327
- ...this.state.running.map((r)=>r.name),
328
- ...this.state.completed,
329
- ...this.state.failed.map((f)=>f.name),
330
- ...this.state.skipped
331
- ],
332
- executionMode: 'parallel',
333
- maxConcurrency: this.config.maxConcurrency,
334
- state: this.state,
335
- publishedVersions: this.publishedVersions.map((pv)=>({
336
- packageName: pv.name,
337
- version: pv.version,
338
- publishTime: pv.time.toISOString()
339
- })),
340
- retryAttempts: Object.fromEntries(this.retryAttempts),
341
- lastRetryTime: {},
342
- packageStartTimes: Object.fromEntries(Array.from(this.packageStartTimes.entries()).map(([k, v])=>[
343
- k,
344
- v.toISOString()
345
- ])),
346
- packageEndTimes: Object.fromEntries(Array.from(this.packageEndTimes.entries()).map(([k, v])=>[
347
- k,
348
- v.toISOString()
349
- ])),
350
- packageDurations: Object.fromEntries(this.packageDurations),
351
- totalStartTime: this.startTime.toISOString(),
352
- recoveryHints: [],
353
- canRecover: true
354
- };
355
- await this.checkpointManager.save(checkpoint);
356
- this.emit('checkpoint:saved', {
357
- timestamp: new Date()
358
- });
359
- }
360
- /**
361
- * Load checkpoint
362
- */ async loadCheckpoint() {
363
- const checkpoint = await this.checkpointManager.load();
364
- if (!checkpoint) {
365
- this.logger.warn('CHECKPOINT_NOT_FOUND: No checkpoint file found | Action: Starting fresh execution | Path: ' + this.config.checkpointPath);
366
- return;
367
- }
368
- this.logger.info('CHECKPOINT_LOADING: Loading execution checkpoint | Purpose: Resume previous execution | Path: ' + this.config.checkpointPath);
369
- this.logger.info(`CHECKPOINT_EXECUTION_ID: Checkpoint execution identifier | ID: ${checkpoint.executionId}`);
370
- this.logger.info(`CHECKPOINT_STATE_COMPLETED: Completed packages from checkpoint | Count: ${checkpoint.state.completed.length} packages`);
371
- this.logger.info(`CHECKPOINT_STATE_FAILED: Failed packages from checkpoint | Count: ${checkpoint.state.failed.length} packages`);
372
- // Restore state
373
- this.executionId = checkpoint.executionId;
374
- this.startTime = new Date(checkpoint.totalStartTime);
375
- this.state = checkpoint.state;
376
- // Restore timing data
377
- for (const [pkg, time] of Object.entries(checkpoint.packageStartTimes)){
378
- this.packageStartTimes.set(pkg, new Date(time));
379
- }
380
- for (const [pkg, time] of Object.entries(checkpoint.packageEndTimes)){
381
- this.packageEndTimes.set(pkg, new Date(time));
382
- }
383
- for (const [pkg, duration] of Object.entries(checkpoint.packageDurations)){
384
- this.packageDurations.set(pkg, duration);
385
- }
386
- // Restore retry attempts
387
- for (const [pkg, attempts] of Object.entries(checkpoint.retryAttempts)){
388
- this.retryAttempts.set(pkg, attempts);
389
- }
390
- // Clear running state (cannot resume mid-execution)
391
- for (const running of this.state.running){
392
- this.state.pending.push(running.name);
393
- }
394
- this.state.running = [];
395
- // CRITICAL FIX: Re-evaluate skipped packages
396
- // After loading checkpoint (especially with --mark-completed), packages that were
397
- // skipped due to failed dependencies might now be eligible to run if those
398
- // dependencies are now completed. Move them back to pending for reassessment.
399
- const unblocked = [];
400
- for (const packageName of this.state.skipped){
401
- // Check if all dependencies are now completed
402
- const dependencies = this.graph.edges.get(packageName) || new Set();
403
- const allDepsCompleted = Array.from(dependencies).every((dep)=>this.state.completed.includes(dep) || this.state.skippedNoChanges.includes(dep));
404
- // Check if any dependencies are still failed
405
- const anyDepsFailed = Array.from(dependencies).some((dep)=>this.state.failed.some((f)=>f.name === dep));
406
- if (allDepsCompleted && !anyDepsFailed) {
407
- unblocked.push(packageName);
408
- }
409
- }
410
- // Move unblocked packages back to pending
411
- if (unblocked.length > 0) {
412
- this.logger.info(`PACKAGES_UNBLOCKED: Dependencies satisfied, packages now ready | Count: ${unblocked.length} | Packages: ${unblocked.join(', ')} | Status: ready-to-execute`);
413
- for (const packageName of unblocked){
414
- this.state.skipped = this.state.skipped.filter((p)=>p !== packageName);
415
- this.state.pending.push(packageName);
416
- }
417
- }
418
- }
419
- /**
420
- * Build execution result
421
- */ buildExecutionResult() {
422
- const totalDuration = Date.now() - this.startTime.getTime();
423
- const completedDurations = Array.from(this.packageDurations.values());
424
- const averageDuration = completedDurations.length > 0 ? completedDurations.reduce((a, b)=>a + b, 0) / completedDurations.length : 0;
425
- const metrics = {
426
- totalDuration,
427
- averagePackageDuration: averageDuration,
428
- peakConcurrency: this.resourceMonitor.getMetrics().peakConcurrency,
429
- averageConcurrency: this.resourceMonitor.getMetrics().averageConcurrency
430
- };
431
- return {
432
- success: this.state.failed.length === 0,
433
- totalPackages: this.graph.packages.size,
434
- completed: this.state.completed,
435
- failed: this.state.failed,
436
- skipped: this.state.skipped,
437
- skippedNoChanges: this.state.skippedNoChanges,
438
- metrics
439
- };
440
- }
441
- /**
442
- * Check if error is retriable
443
- */ isRetriableError(error) {
444
- const errorText = error.message || String(error);
445
- const stackText = error.stack || '';
446
- const fullText = `${errorText}\n${stackText}`;
447
- const retriablePatterns = [
448
- // Network errors
449
- /ETIMEDOUT/i,
450
- /ECONNRESET/i,
451
- /ENOTFOUND/i,
452
- /ECONNREFUSED/i,
453
- /rate limit/i,
454
- /temporary failure/i,
455
- /try again/i,
456
- /gateway timeout/i,
457
- /service unavailable/i,
458
- // Git lock file errors (common in parallel execution)
459
- /index\.lock/i,
460
- /\.git\/index\.lock/i,
461
- /unable to create.*lock/i,
462
- /lock file.*exists/i,
463
- // npm install race conditions
464
- /ENOENT.*npm-cache/i,
465
- /EBUSY.*npm/i,
466
- /npm.*EEXIST/i,
467
- // GitHub API temporary errors
468
- /abuse detection/i,
469
- /secondary rate limit/i,
470
- /GitHub API.*unavailable/i,
471
- // Timeout errors (might be transient)
472
- /timeout waiting for/i,
473
- /timed out after/i
474
- ];
475
- const isRetriable = retriablePatterns.some((pattern)=>pattern.test(fullText));
476
- // Non-retriable errors that should fail immediately
477
- const nonRetriablePatterns = [
478
- /test.*failed/i,
479
- /coverage.*below.*threshold/i,
480
- /compilation.*failed/i,
481
- /build.*failed/i,
482
- /merge.*conflict/i,
483
- /uncommitted changes/i,
484
- /working.*dirty/i,
485
- /authentication.*failed/i,
486
- /permission denied/i
487
- ];
488
- const isNonRetriable = nonRetriablePatterns.some((pattern)=>pattern.test(fullText));
489
- // If explicitly non-retriable, don't retry
490
- if (isNonRetriable) {
491
- return false;
492
- }
493
- return isRetriable;
494
- }
495
- /**
496
- * Calculate retry delay with exponential backoff
497
- */ calculateRetryDelay(attemptNumber) {
498
- const initialDelay = this.config.initialRetryDelay || 5000;
499
- const maxDelay = this.config.maxRetryDelay || 60000;
500
- const multiplier = this.config.backoffMultiplier || 2;
501
- const delay = Math.min(initialDelay * Math.pow(multiplier, attemptNumber - 1), maxDelay);
502
- // Add jitter
503
- const jitter = Math.random() * 0.1 * delay;
504
- return delay + jitter;
505
- }
506
- /**
507
- * Format duration in human-readable format
508
- */ formatDuration(ms) {
509
- const seconds = Math.floor(ms / 1000);
510
- const minutes = Math.floor(seconds / 60);
511
- if (minutes > 0) {
512
- return `${minutes}m ${seconds % 60}s`;
513
- }
514
- return `${seconds}s`;
515
- }
516
- /**
517
- * Extract detailed error information from error message and stack
518
- */ extractErrorDetails(error, packageName) {
519
- const errorMsg = error.message || '';
520
- const errorStack = error.stack || '';
521
- const fullText = `${errorMsg}\n${errorStack}`;
522
- // Get log file path from error if attached, otherwise use default
523
- const logFile = error.logFilePath || this.getLogFilePath(packageName);
524
- // Test coverage failure
525
- if (fullText.match(/coverage.*below.*threshold|coverage.*insufficient/i)) {
526
- const coverageMatch = fullText.match(/(\w+):\s*(\d+\.?\d*)%.*threshold:\s*(\d+\.?\d*)%/i);
527
- return {
528
- type: 'test_coverage',
529
- context: coverageMatch ? `${coverageMatch[1]}: ${coverageMatch[2]}% (threshold: ${coverageMatch[3]}%)` : 'Coverage below threshold',
530
- logFile,
531
- suggestion: `cd ${this.getPackagePath(packageName)} && npm test -- --coverage`
532
- };
533
- }
534
- // Build/compile errors
535
- if (fullText.match(/compilation.*failed|build.*failed|tsc.*error/i)) {
536
- return {
537
- type: 'build_error',
538
- context: this.extractFirstErrorLine(fullText),
539
- logFile,
540
- suggestion: `cd ${this.getPackagePath(packageName)} && npm run build`
541
- };
542
- }
543
- // Merge conflicts
544
- if (fullText.match(/merge.*conflict|conflict.*marker|<<<<<<<|>>>>>>>/i)) {
545
- return {
546
- type: 'merge_conflict',
547
- context: 'Unresolved merge conflicts detected',
548
- logFile,
549
- suggestion: `cd ${this.getPackagePath(packageName)} && git status`
550
- };
551
- }
552
- // Test failures
553
- if (fullText.match(/test.*failed|tests.*failed|\d+\s+failing/i)) {
554
- const failMatch = fullText.match(/(\d+)\s+failing/i);
555
- return {
556
- type: 'test_failure',
557
- context: failMatch ? `${failMatch[1]} test(s) failing` : 'Tests failed',
558
- logFile,
559
- suggestion: `cd ${this.getPackagePath(packageName)} && npm test`
560
- };
561
- }
562
- // Timeout errors
563
- if (fullText.match(/timeout|timed.*out/i)) {
564
- return {
565
- type: 'timeout',
566
- context: this.extractFirstErrorLine(fullText),
567
- logFile,
568
- suggestion: 'Consider increasing timeout or checking for stuck processes'
569
- };
570
- }
571
- // PR/Git errors
572
- if (fullText.match(/pull request|pr|github/i) && fullText.match(/not mergeable|conflict/i)) {
573
- return {
574
- type: 'pr_conflict',
575
- context: 'Pull request has merge conflicts',
576
- logFile,
577
- suggestion: 'Resolve conflicts in the PR and re-run with --continue'
578
- };
579
- }
580
- // Git state errors
581
- if (fullText.match(/uncommitted changes|working.*dirty|not.*clean/i)) {
582
- return {
583
- type: 'git_state',
584
- context: 'Working directory has uncommitted changes',
585
- logFile,
586
- suggestion: `cd ${this.getPackagePath(packageName)} && git status`
587
- };
588
- }
589
- // npm install / dependency errors
590
- if (fullText.match(/npm.*install|ERESOLVE|Cannot find module/i)) {
591
- return {
592
- type: 'dependency_error',
593
- context: this.extractFirstErrorLine(fullText),
594
- logFile,
595
- suggestion: `cd ${this.getPackagePath(packageName)} && rm -rf node_modules package-lock.json && npm install`
596
- };
597
- }
598
- // Git lock file errors
599
- if (fullText.match(/index\.lock|\.git\/index\.lock|unable to create.*lock/i)) {
600
- return {
601
- type: 'git_lock',
602
- context: 'Git lock file conflict - another git process running',
603
- logFile,
604
- suggestion: `cd ${this.getPackagePath(packageName)} && rm -f .git/index.lock`
605
- };
606
- }
607
- // No changes detected (not really an error, but handle it)
608
- if (fullText.match(/no.*changes|already.*published|nothing.*to.*publish/i)) {
609
- return {
610
- type: 'no_changes',
611
- context: 'No changes detected - package already published',
612
- logFile,
613
- suggestion: 'This is expected if package was previously published'
614
- };
615
- }
616
- // Generic error with log file
617
- return {
618
- type: 'unknown',
619
- context: errorMsg.split('\n')[0].substring(0, 200),
620
- logFile
621
- };
622
- }
623
- extractFirstErrorLine(text) {
624
- const lines = text.split('\n');
625
- for (const line of lines){
626
- if (line.match(/error|failed|exception/i) && line.trim().length > 10) {
627
- return line.trim().substring(0, 200);
628
- }
629
- }
630
- return text.split('\n')[0].substring(0, 200);
631
- }
632
- getPackagePath(packageName) {
633
- const pkgInfo = this.graph.packages.get(packageName);
634
- return (pkgInfo === null || pkgInfo === void 0 ? void 0 : pkgInfo.path) || '.';
635
- }
636
- getLogFilePath(packageName) {
637
- const pkgPath = this.getPackagePath(packageName);
638
- const outputDir = this.config.config.outputDirectory || 'output/kodrdriv';
639
- // Return wildcard pattern as fallback (log file should be attached to error directly)
640
- // This is used as a fallback when log file path isn't attached to the error
641
- return `${pkgPath}/${outputDir}/publish_*.log`;
642
- }
643
- constructor(config){
644
- super(), _define_property(this, "config", void 0), _define_property(this, "graph", void 0), _define_property(this, "state", void 0), _define_property(this, "dependencyChecker", void 0), _define_property(this, "resourceMonitor", void 0), _define_property(this, "scheduler", void 0), _define_property(this, "checkpointManager", void 0), _define_property(this, "logger", getLogger()), // Execution tracking
645
- _define_property(this, "executionId", void 0), _define_property(this, "startTime", void 0), _define_property(this, "runningTasks", new Map()), _define_property(this, "packageStartTimes", new Map()), _define_property(this, "packageEndTimes", new Map()), _define_property(this, "packageDurations", new Map()), _define_property(this, "retryAttempts", new Map()), _define_property(this, "publishedVersions", []);
646
- this.config = config;
647
- this.graph = config.graph;
648
- this.executionId = randomUUID();
649
- this.startTime = new Date();
650
- // Initialize components
651
- this.dependencyChecker = new DependencyChecker(this.graph);
652
- this.resourceMonitor = new ResourceMonitor(config.maxConcurrency);
653
- this.scheduler = new Scheduler(this.graph, this.dependencyChecker);
654
- this.checkpointManager = new CheckpointManager(config.checkpointPath || process.cwd());
655
- // Initialize state
656
- this.state = this.initializeState();
657
- }
658
- }
659
-
660
- export { DynamicTaskPool };
661
- //# sourceMappingURL=DynamicTaskPool.js.map