@auto-engineer/job-graph-processor 1.12.1

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 (116) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/.turbo/turbo-test.log +14 -0
  3. package/.turbo/turbo-type-check.log +4 -0
  4. package/CHANGELOG.md +12 -0
  5. package/LICENSE +10 -0
  6. package/README.md +408 -0
  7. package/dist/src/apply-policy.d.ts +3 -0
  8. package/dist/src/apply-policy.d.ts.map +1 -0
  9. package/dist/src/apply-policy.js +24 -0
  10. package/dist/src/apply-policy.js.map +1 -0
  11. package/dist/src/apply-policy.specs.d.ts +2 -0
  12. package/dist/src/apply-policy.specs.d.ts.map +1 -0
  13. package/dist/src/apply-policy.specs.js +75 -0
  14. package/dist/src/apply-policy.specs.js.map +1 -0
  15. package/dist/src/commands/process-job-graph.d.ts +31 -0
  16. package/dist/src/commands/process-job-graph.d.ts.map +1 -0
  17. package/dist/src/commands/process-job-graph.js +64 -0
  18. package/dist/src/commands/process-job-graph.js.map +1 -0
  19. package/dist/src/commands/process-job-graph.specs.d.ts +2 -0
  20. package/dist/src/commands/process-job-graph.specs.d.ts.map +1 -0
  21. package/dist/src/commands/process-job-graph.specs.js +73 -0
  22. package/dist/src/commands/process-job-graph.specs.js.map +1 -0
  23. package/dist/src/evolve.d.ts +70 -0
  24. package/dist/src/evolve.d.ts.map +1 -0
  25. package/dist/src/evolve.js +82 -0
  26. package/dist/src/evolve.js.map +1 -0
  27. package/dist/src/evolve.specs.d.ts +2 -0
  28. package/dist/src/evolve.specs.d.ts.map +1 -0
  29. package/dist/src/evolve.specs.js +209 -0
  30. package/dist/src/evolve.specs.js.map +1 -0
  31. package/dist/src/graph-processor.d.ts +22 -0
  32. package/dist/src/graph-processor.d.ts.map +1 -0
  33. package/dist/src/graph-processor.js +82 -0
  34. package/dist/src/graph-processor.js.map +1 -0
  35. package/dist/src/graph-processor.specs.d.ts +2 -0
  36. package/dist/src/graph-processor.specs.d.ts.map +1 -0
  37. package/dist/src/graph-processor.specs.js +286 -0
  38. package/dist/src/graph-processor.specs.js.map +1 -0
  39. package/dist/src/graph-validator.d.ts +19 -0
  40. package/dist/src/graph-validator.d.ts.map +1 -0
  41. package/dist/src/graph-validator.js +65 -0
  42. package/dist/src/graph-validator.js.map +1 -0
  43. package/dist/src/graph-validator.specs.d.ts +2 -0
  44. package/dist/src/graph-validator.specs.d.ts.map +1 -0
  45. package/dist/src/graph-validator.specs.js +86 -0
  46. package/dist/src/graph-validator.specs.js.map +1 -0
  47. package/dist/src/handle-job-event.d.ts +16 -0
  48. package/dist/src/handle-job-event.d.ts.map +1 -0
  49. package/dist/src/handle-job-event.js +46 -0
  50. package/dist/src/handle-job-event.js.map +1 -0
  51. package/dist/src/handle-job-event.specs.d.ts +2 -0
  52. package/dist/src/handle-job-event.specs.d.ts.map +1 -0
  53. package/dist/src/handle-job-event.specs.js +136 -0
  54. package/dist/src/handle-job-event.specs.js.map +1 -0
  55. package/dist/src/index.d.ts +41 -0
  56. package/dist/src/index.d.ts.map +1 -0
  57. package/dist/src/index.js +11 -0
  58. package/dist/src/index.js.map +1 -0
  59. package/dist/src/integration.specs.d.ts +2 -0
  60. package/dist/src/integration.specs.d.ts.map +1 -0
  61. package/dist/src/integration.specs.js +225 -0
  62. package/dist/src/integration.specs.js.map +1 -0
  63. package/dist/src/process-graph.d.ts +14 -0
  64. package/dist/src/process-graph.d.ts.map +1 -0
  65. package/dist/src/process-graph.js +26 -0
  66. package/dist/src/process-graph.js.map +1 -0
  67. package/dist/src/process-graph.specs.d.ts +2 -0
  68. package/dist/src/process-graph.specs.d.ts.map +1 -0
  69. package/dist/src/process-graph.specs.js +41 -0
  70. package/dist/src/process-graph.specs.js.map +1 -0
  71. package/dist/src/process-job-graph.e2e.specs.d.ts +2 -0
  72. package/dist/src/process-job-graph.e2e.specs.d.ts.map +1 -0
  73. package/dist/src/process-job-graph.e2e.specs.js +81 -0
  74. package/dist/src/process-job-graph.e2e.specs.js.map +1 -0
  75. package/dist/src/retry-manager.d.ts +10 -0
  76. package/dist/src/retry-manager.d.ts.map +1 -0
  77. package/dist/src/retry-manager.js +17 -0
  78. package/dist/src/retry-manager.js.map +1 -0
  79. package/dist/src/retry-manager.specs.d.ts +2 -0
  80. package/dist/src/retry-manager.specs.d.ts.map +1 -0
  81. package/dist/src/retry-manager.specs.js +55 -0
  82. package/dist/src/retry-manager.specs.js.map +1 -0
  83. package/dist/src/timeout-manager.d.ts +7 -0
  84. package/dist/src/timeout-manager.d.ts.map +1 -0
  85. package/dist/src/timeout-manager.js +25 -0
  86. package/dist/src/timeout-manager.js.map +1 -0
  87. package/dist/src/timeout-manager.specs.d.ts +2 -0
  88. package/dist/src/timeout-manager.specs.d.ts.map +1 -0
  89. package/dist/src/timeout-manager.specs.js +44 -0
  90. package/dist/src/timeout-manager.specs.js.map +1 -0
  91. package/dist/tsconfig.tsbuildinfo +1 -0
  92. package/ketchup-plan.md +31 -0
  93. package/package.json +25 -0
  94. package/src/apply-policy.specs.ts +85 -0
  95. package/src/apply-policy.ts +27 -0
  96. package/src/commands/process-job-graph.specs.ts +93 -0
  97. package/src/commands/process-job-graph.ts +80 -0
  98. package/src/evolve.specs.ts +235 -0
  99. package/src/evolve.ts +121 -0
  100. package/src/graph-processor.specs.ts +331 -0
  101. package/src/graph-processor.ts +121 -0
  102. package/src/graph-validator.specs.ts +105 -0
  103. package/src/graph-validator.ts +94 -0
  104. package/src/handle-job-event.specs.ts +154 -0
  105. package/src/handle-job-event.ts +59 -0
  106. package/src/index.ts +17 -0
  107. package/src/integration.specs.ts +249 -0
  108. package/src/process-graph.specs.ts +44 -0
  109. package/src/process-graph.ts +42 -0
  110. package/src/process-job-graph.e2e.specs.ts +121 -0
  111. package/src/retry-manager.specs.ts +66 -0
  112. package/src/retry-manager.ts +29 -0
  113. package/src/timeout-manager.specs.ts +55 -0
  114. package/src/timeout-manager.ts +34 -0
  115. package/tsconfig.json +9 -0
  116. package/vitest.config.ts +22 -0
@@ -0,0 +1,66 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { createRetryManager } from './retry-manager';
3
+
4
+ describe('createRetryManager', () => {
5
+ it('schedules retry with initial backoff on first failure', () => {
6
+ vi.useFakeTimers();
7
+ const onRetry = vi.fn();
8
+ const manager = createRetryManager(onRetry);
9
+
10
+ manager.recordFailure('job-a', { maxRetries: 3, backoffMs: 100, maxBackoffMs: 5000 });
11
+ vi.advanceTimersByTime(100);
12
+
13
+ expect(onRetry).toHaveBeenCalledWith('job-a', 1);
14
+ vi.useRealTimers();
15
+ });
16
+
17
+ it('uses exponential backoff on subsequent failures', () => {
18
+ vi.useFakeTimers();
19
+ const onRetry = vi.fn();
20
+ const manager = createRetryManager(onRetry);
21
+ const config = { maxRetries: 3, backoffMs: 100, maxBackoffMs: 5000 };
22
+
23
+ manager.recordFailure('job-a', config);
24
+ vi.advanceTimersByTime(100);
25
+ manager.recordFailure('job-a', config);
26
+ vi.advanceTimersByTime(199);
27
+ expect(onRetry).toHaveBeenCalledTimes(1);
28
+ vi.advanceTimersByTime(1);
29
+
30
+ expect(onRetry).toHaveBeenCalledTimes(2);
31
+ expect(onRetry).toHaveBeenLastCalledWith('job-a', 2);
32
+ vi.useRealTimers();
33
+ });
34
+
35
+ it('returns true when max retries exhausted', () => {
36
+ vi.useFakeTimers();
37
+ const onRetry = vi.fn();
38
+ const manager = createRetryManager(onRetry);
39
+ const config = { maxRetries: 1, backoffMs: 100, maxBackoffMs: 5000 };
40
+
41
+ manager.recordFailure('job-a', config);
42
+ vi.advanceTimersByTime(100);
43
+ const exhausted = manager.recordFailure('job-a', config);
44
+
45
+ expect(exhausted).toBe(true);
46
+ expect(onRetry).toHaveBeenCalledTimes(1);
47
+ vi.useRealTimers();
48
+ });
49
+
50
+ it('caps backoff at maxBackoffMs', () => {
51
+ vi.useFakeTimers();
52
+ const onRetry = vi.fn();
53
+ const manager = createRetryManager(onRetry);
54
+ const config = { maxRetries: 10, backoffMs: 1000, maxBackoffMs: 2000 };
55
+
56
+ manager.recordFailure('job-a', config);
57
+ vi.advanceTimersByTime(1000);
58
+ manager.recordFailure('job-a', config);
59
+ vi.advanceTimersByTime(2000);
60
+ manager.recordFailure('job-a', config);
61
+ vi.advanceTimersByTime(2000);
62
+
63
+ expect(onRetry).toHaveBeenCalledTimes(3);
64
+ vi.useRealTimers();
65
+ });
66
+ });
@@ -0,0 +1,29 @@
1
+ export interface RetryConfig {
2
+ maxRetries: number;
3
+ backoffMs: number;
4
+ maxBackoffMs: number;
5
+ }
6
+
7
+ export interface RetryManager {
8
+ recordFailure(jobId: string, config: RetryConfig): boolean;
9
+ }
10
+
11
+ export function createRetryManager(onRetry: (jobId: string, attempt: number) => void): RetryManager {
12
+ const attempts = new Map<string, number>();
13
+
14
+ return {
15
+ recordFailure(jobId: string, config: RetryConfig): boolean {
16
+ const current = attempts.get(jobId) ?? 0;
17
+ const next = current + 1;
18
+
19
+ if (next > config.maxRetries) {
20
+ return true;
21
+ }
22
+
23
+ attempts.set(jobId, next);
24
+ const delay = Math.min(config.backoffMs * 2 ** (next - 1), config.maxBackoffMs);
25
+ setTimeout(() => onRetry(jobId, next), delay);
26
+ return false;
27
+ },
28
+ };
29
+ }
@@ -0,0 +1,55 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { createTimeoutManager } from './timeout-manager';
3
+
4
+ describe('createTimeoutManager', () => {
5
+ it('fires callback when timer expires', () => {
6
+ vi.useFakeTimers();
7
+ const onTimeout = vi.fn();
8
+ const manager = createTimeoutManager(onTimeout);
9
+
10
+ manager.start('job-a', 1000);
11
+ vi.advanceTimersByTime(1000);
12
+
13
+ expect(onTimeout).toHaveBeenCalledWith('job-a');
14
+ vi.useRealTimers();
15
+ });
16
+
17
+ it('does not fire callback before timeout', () => {
18
+ vi.useFakeTimers();
19
+ const onTimeout = vi.fn();
20
+ const manager = createTimeoutManager(onTimeout);
21
+
22
+ manager.start('job-a', 1000);
23
+ vi.advanceTimersByTime(999);
24
+
25
+ expect(onTimeout).not.toHaveBeenCalled();
26
+ vi.useRealTimers();
27
+ });
28
+
29
+ it('cancels timer and prevents callback', () => {
30
+ vi.useFakeTimers();
31
+ const onTimeout = vi.fn();
32
+ const manager = createTimeoutManager(onTimeout);
33
+
34
+ manager.start('job-a', 1000);
35
+ manager.clear('job-a');
36
+ vi.advanceTimersByTime(1000);
37
+
38
+ expect(onTimeout).not.toHaveBeenCalled();
39
+ vi.useRealTimers();
40
+ });
41
+
42
+ it('clearAll cancels all active timers', () => {
43
+ vi.useFakeTimers();
44
+ const onTimeout = vi.fn();
45
+ const manager = createTimeoutManager(onTimeout);
46
+
47
+ manager.start('job-a', 1000);
48
+ manager.start('job-b', 2000);
49
+ manager.clearAll();
50
+ vi.advanceTimersByTime(2000);
51
+
52
+ expect(onTimeout).not.toHaveBeenCalled();
53
+ vi.useRealTimers();
54
+ });
55
+ });
@@ -0,0 +1,34 @@
1
+ export interface TimeoutManager {
2
+ start(jobId: string, timeoutMs: number): void;
3
+ clear(jobId: string): void;
4
+ clearAll(): void;
5
+ }
6
+
7
+ export function createTimeoutManager(onTimeout: (jobId: string) => void): TimeoutManager {
8
+ const timers = new Map<string, ReturnType<typeof setTimeout>>();
9
+
10
+ return {
11
+ start(jobId: string, timeoutMs: number) {
12
+ timers.set(
13
+ jobId,
14
+ setTimeout(() => {
15
+ timers.delete(jobId);
16
+ onTimeout(jobId);
17
+ }, timeoutMs),
18
+ );
19
+ },
20
+ clear(jobId: string) {
21
+ const timer = timers.get(jobId);
22
+ if (timer !== undefined) {
23
+ clearTimeout(timer);
24
+ timers.delete(jobId);
25
+ }
26
+ },
27
+ clearAll() {
28
+ for (const timer of timers.values()) {
29
+ clearTimeout(timer);
30
+ }
31
+ timers.clear();
32
+ },
33
+ };
34
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "composite": true
6
+ },
7
+ "include": ["src/**/*"],
8
+ "exclude": ["node_modules", "dist"]
9
+ }
@@ -0,0 +1,22 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ include: ['src/**/*.specs.ts'],
8
+ passWithNoTests: true,
9
+ coverage: {
10
+ provider: 'v8',
11
+ reporter: ['text', 'json', 'html'],
12
+ thresholds: {
13
+ lines: 100,
14
+ functions: 100,
15
+ branches: 100,
16
+ statements: 100,
17
+ },
18
+ include: ['src/**/*.ts'],
19
+ exclude: ['src/**/*.specs.ts', 'src/**/index.ts'],
20
+ },
21
+ },
22
+ });