@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,64 @@
1
+ import { createGraphProcessor } from '../graph-processor.js';
2
+ function isContextWithMessageBus(context) {
3
+ return (context !== null &&
4
+ context !== undefined &&
5
+ typeof context === 'object' &&
6
+ 'messageBus' in context &&
7
+ context.messageBus !== null &&
8
+ context.messageBus !== undefined &&
9
+ typeof context.messageBus === 'object');
10
+ }
11
+ function buildDispatch(context) {
12
+ if (typeof context.sendCommand !== 'function')
13
+ return undefined;
14
+ const ctxSendCommand = context.sendCommand;
15
+ return (cmd) => ctxSendCommand(cmd.type, cmd.data, cmd.correlationId);
16
+ }
17
+ function toProcessGraphCommand(command) {
18
+ const data = command.data;
19
+ return { type: command.type, data };
20
+ }
21
+ export const commandHandler = {
22
+ name: 'ProcessJobGraph',
23
+ displayName: 'Process Job Graph',
24
+ alias: 'process:job-graph',
25
+ description: 'Process a directed acyclic graph of jobs with dependency tracking and failure policies',
26
+ category: 'orchestration',
27
+ icon: 'git-branch',
28
+ fields: {
29
+ graphId: {
30
+ description: 'Unique identifier for the graph',
31
+ required: true,
32
+ },
33
+ jobs: {
34
+ description: 'Array of jobs with dependencies',
35
+ required: true,
36
+ },
37
+ failurePolicy: {
38
+ description: 'Policy for handling job failures: halt, skip-dependents, or continue',
39
+ required: true,
40
+ },
41
+ },
42
+ examples: [
43
+ '$ auto process:job-graph --graphId=g1 --jobs=\'[{"id":"a","dependsOn":[],"target":"build","payload":{}}]\' --failurePolicy=halt',
44
+ ],
45
+ events: [
46
+ { name: 'graph.dispatching', displayName: 'Graph Dispatching' },
47
+ { name: 'graph.failed', displayName: 'Graph Failed' },
48
+ { name: 'graph.completed', displayName: 'Graph Completed' },
49
+ ],
50
+ handle: async (command, context) => {
51
+ const { graphId } = command.data;
52
+ if (!isContextWithMessageBus(context)) {
53
+ return {
54
+ type: 'graph.failed',
55
+ data: { graphId, reason: 'messageBus not available in context' },
56
+ };
57
+ }
58
+ const dispatch = buildDispatch(context);
59
+ const processor = createGraphProcessor(context.messageBus, dispatch ? { dispatch } : undefined);
60
+ return processor.submit(toProcessGraphCommand(command));
61
+ },
62
+ };
63
+ export default commandHandler;
64
+ //# sourceMappingURL=process-job-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-job-graph.js","sourceRoot":"","sources":["../../../src/commands/process-job-graph.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAA4B,MAAM,oBAAoB,CAAC;AAQpF,SAAS,uBAAuB,CAAC,OAAgB;IAC/C,OAAO,CACL,OAAO,KAAK,IAAI;QAChB,OAAO,KAAK,SAAS;QACrB,OAAO,OAAO,KAAK,QAAQ;QAC3B,YAAY,IAAI,OAAO;QACvB,OAAO,CAAC,UAAU,KAAK,IAAI;QAC3B,OAAO,CAAC,UAAU,KAAK,SAAS;QAChC,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ,CACvC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,OAA8B;IACnD,IAAI,OAAO,OAAO,CAAC,WAAW,KAAK,UAAU;QAAE,OAAO,SAAS,CAAC;IAChE,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAC3C,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAgB;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAsE,CAAC;IAC5F,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE,mBAAmB;IAChC,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EAAE,wFAAwF;IACrG,QAAQ,EAAE,eAAe;IACzB,IAAI,EAAE,YAAY;IAClB,MAAM,EAAE;QACN,OAAO,EAAE;YACP,WAAW,EAAE,iCAAiC;YAC9C,QAAQ,EAAE,IAAI;SACf;QACD,IAAI,EAAE;YACJ,WAAW,EAAE,iCAAiC;YAC9C,QAAQ,EAAE,IAAI;SACf;QACD,aAAa,EAAE;YACb,WAAW,EAAE,sEAAsE;YACnF,QAAQ,EAAE,IAAI;SACf;KACF;IACD,QAAQ,EAAE;QACR,iIAAiI;KAClI;IACD,MAAM,EAAE;QACN,EAAE,IAAI,EAAE,mBAAmB,EAAE,WAAW,EAAE,mBAAmB,EAAE;QAC/D,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE;QACrD,EAAE,IAAI,EAAE,iBAAiB,EAAE,WAAW,EAAE,iBAAiB,EAAE;KAC5D;IACD,MAAM,EAAE,KAAK,EAAE,OAAgB,EAAE,OAAiB,EAA4B,EAAE;QAC9E,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;QAEjC,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,EAAE,CAAC;YACtC,OAAO;gBACL,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,qCAAqC,EAAE;aACjE,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAChG,OAAO,SAAS,CAAC,MAAM,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1D,CAAC;CACF,CAAC;AAEF,eAAe,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=process-job-graph.specs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-job-graph.specs.d.ts","sourceRoot":"","sources":["../../../src/commands/process-job-graph.specs.ts"],"names":[],"mappings":""}
@@ -0,0 +1,73 @@
1
+ import { createMessageBus } from '@auto-engineer/message-bus';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { commandHandler } from './process-job-graph.js';
4
+ describe('ProcessJobGraph command handler', () => {
5
+ it('returns graph.dispatching with dispatched jobs when given valid graph and messageBus', async () => {
6
+ const messageBus = createMessageBus();
7
+ const result = await commandHandler.handle({
8
+ type: 'ProcessJobGraph',
9
+ data: {
10
+ graphId: 'g1',
11
+ jobs: [
12
+ { id: 'a', dependsOn: [], target: 'build', payload: { src: './app' } },
13
+ { id: 'b', dependsOn: ['a'], target: 'test', payload: {} },
14
+ ],
15
+ failurePolicy: 'halt',
16
+ },
17
+ }, { messageBus });
18
+ expect(result).toEqual({
19
+ type: 'graph.dispatching',
20
+ data: {
21
+ graphId: 'g1',
22
+ dispatchedJobs: [{ jobId: 'a', target: 'build', payload: { src: './app' }, correlationId: 'graph:g1:a' }],
23
+ },
24
+ });
25
+ });
26
+ it('returns graph.failed when messageBus is not available in context', async () => {
27
+ const result = await commandHandler.handle({
28
+ type: 'ProcessJobGraph',
29
+ data: {
30
+ graphId: 'g1',
31
+ jobs: [{ id: 'a', dependsOn: [], target: 'build', payload: {} }],
32
+ failurePolicy: 'halt',
33
+ },
34
+ });
35
+ expect(result).toEqual({
36
+ type: 'graph.failed',
37
+ data: { graphId: 'g1', reason: 'messageBus not available in context' },
38
+ });
39
+ });
40
+ it('dispatches target commands via ctx.sendCommand when provided', async () => {
41
+ const messageBus = createMessageBus();
42
+ const dispatched = [];
43
+ const sendCommand = async (type, data, correlationId) => {
44
+ dispatched.push({ type, data, correlationId: correlationId });
45
+ };
46
+ await commandHandler.handle({
47
+ type: 'ProcessJobGraph',
48
+ data: {
49
+ graphId: 'g1',
50
+ jobs: [{ id: 'a', dependsOn: [], target: 'build', payload: { src: './app' } }],
51
+ failurePolicy: 'halt',
52
+ },
53
+ }, { messageBus, sendCommand });
54
+ await new Promise((r) => setTimeout(r, 10));
55
+ expect(dispatched).toEqual([{ type: 'build', data: { src: './app' }, correlationId: 'graph:g1:a' }]);
56
+ });
57
+ it('returns graph.failed for invalid graph', async () => {
58
+ const messageBus = createMessageBus();
59
+ const result = await commandHandler.handle({
60
+ type: 'ProcessJobGraph',
61
+ data: {
62
+ graphId: 'g1',
63
+ jobs: [],
64
+ failurePolicy: 'halt',
65
+ },
66
+ }, { messageBus });
67
+ expect(result).toEqual({
68
+ type: 'graph.failed',
69
+ data: { graphId: 'g1', reason: 'Graph must contain at least one job' },
70
+ });
71
+ });
72
+ });
73
+ //# sourceMappingURL=process-job-graph.specs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-job-graph.specs.js","sourceRoot":"","sources":["../../../src/commands/process-job-graph.specs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import type { Job } from './graph-validator';
2
+ export type JobStatus = 'pending' | 'dispatched' | 'succeeded' | 'failed' | 'skipped' | 'timed-out';
3
+ export type FailurePolicy = 'halt' | 'skip-dependents' | 'continue';
4
+ interface JobState {
5
+ jobId: string;
6
+ status: JobStatus;
7
+ dependsOn: readonly string[];
8
+ }
9
+ type GraphSubmitted = {
10
+ type: 'GraphSubmitted';
11
+ data: {
12
+ graphId: string;
13
+ jobs: readonly Job[];
14
+ failurePolicy: FailurePolicy;
15
+ };
16
+ };
17
+ type JobDispatched = {
18
+ type: 'JobDispatched';
19
+ data: {
20
+ jobId: string;
21
+ target: string;
22
+ correlationId: string;
23
+ };
24
+ };
25
+ type JobSucceeded = {
26
+ type: 'JobSucceeded';
27
+ data: {
28
+ jobId: string;
29
+ result?: unknown;
30
+ };
31
+ };
32
+ type JobFailed = {
33
+ type: 'JobFailed';
34
+ data: {
35
+ jobId: string;
36
+ error: string;
37
+ };
38
+ };
39
+ type JobSkipped = {
40
+ type: 'JobSkipped';
41
+ data: {
42
+ jobId: string;
43
+ reason: string;
44
+ };
45
+ };
46
+ type JobTimedOut = {
47
+ type: 'JobTimedOut';
48
+ data: {
49
+ jobId: string;
50
+ timeoutMs: number;
51
+ };
52
+ };
53
+ export type JobGraphEvent = GraphSubmitted | JobDispatched | JobSucceeded | JobFailed | JobSkipped | JobTimedOut;
54
+ type PendingGraphState = {
55
+ status: 'pending';
56
+ };
57
+ type ProcessingGraphState = {
58
+ status: 'processing';
59
+ graphId: string;
60
+ failurePolicy: FailurePolicy;
61
+ jobs: Map<string, JobState>;
62
+ };
63
+ export type GraphState = PendingGraphState | ProcessingGraphState;
64
+ export declare function initialState(): GraphState;
65
+ export declare function evolve(state: GraphState, event: JobGraphEvent): GraphState;
66
+ export declare function isGraphComplete(state: GraphState): boolean;
67
+ export declare function getTransitiveDependents(state: GraphState, jobId: string): string[];
68
+ export declare function getReadyJobs(state: GraphState): string[];
69
+ export {};
70
+ //# sourceMappingURL=evolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evolve.d.ts","sourceRoot":"","sources":["../../src/evolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAE7C,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;AACpG,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,iBAAiB,GAAG,UAAU,CAAC;AAEpE,UAAU,QAAQ;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B;AAED,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,gBAAgB,CAAC;IACvB,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,GAAG,EAAE,CAAC;QAAC,aAAa,EAAE,aAAa,CAAA;KAAE,CAAC;CAC/E,CAAC;AAEF,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CAChE,CAAC;AACF,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAAC;AACxF,KAAK,SAAS,GAAG;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAC/E,KAAK,UAAU,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAClF,KAAK,WAAW,GAAG;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAEvF,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,aAAa,GAAG,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;AAEjH,KAAK,iBAAiB,GAAG;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAC/C,KAAK,oBAAoB,GAAG;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,aAAa,CAAC;IAC7B,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,iBAAiB,GAAG,oBAAoB,CAAC;AAElE,wBAAgB,YAAY,IAAI,UAAU,CAEzC;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,GAAG,UAAU,CAyB1E;AAaD,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAM1D;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAclF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,CAiBxD"}
@@ -0,0 +1,82 @@
1
+ export function initialState() {
2
+ return { status: 'pending' };
3
+ }
4
+ export function evolve(state, event) {
5
+ switch (event.type) {
6
+ case 'GraphSubmitted':
7
+ return {
8
+ status: 'processing',
9
+ graphId: event.data.graphId,
10
+ failurePolicy: event.data.failurePolicy,
11
+ jobs: new Map(event.data.jobs.map((job) => [
12
+ job.id,
13
+ { jobId: job.id, status: 'pending', dependsOn: job.dependsOn },
14
+ ])),
15
+ };
16
+ case 'JobDispatched':
17
+ return updateJobStatus(state, event.data.jobId, 'dispatched');
18
+ case 'JobSucceeded':
19
+ return updateJobStatus(state, event.data.jobId, 'succeeded');
20
+ case 'JobFailed':
21
+ return updateJobStatus(state, event.data.jobId, 'failed');
22
+ case 'JobSkipped':
23
+ return updateJobStatus(state, event.data.jobId, 'skipped');
24
+ case 'JobTimedOut':
25
+ return updateJobStatus(state, event.data.jobId, 'timed-out');
26
+ }
27
+ }
28
+ function updateJobStatus(state, jobId, status) {
29
+ if (state.status !== 'processing')
30
+ return state;
31
+ const jobs = new Map(state.jobs);
32
+ const existing = jobs.get(jobId);
33
+ if (existing === undefined)
34
+ return state;
35
+ jobs.set(jobId, { ...existing, status });
36
+ return { ...state, jobs };
37
+ }
38
+ const TERMINAL_STATUSES = new Set(['succeeded', 'failed', 'skipped', 'timed-out']);
39
+ export function isGraphComplete(state) {
40
+ if (state.status !== 'processing')
41
+ return false;
42
+ for (const job of state.jobs.values()) {
43
+ if (!TERMINAL_STATUSES.has(job.status))
44
+ return false;
45
+ }
46
+ return true;
47
+ }
48
+ export function getTransitiveDependents(state, jobId) {
49
+ if (state.status !== 'processing')
50
+ return [];
51
+ const dependents = new Set();
52
+ const queue = [jobId];
53
+ while (queue.length > 0) {
54
+ const current = queue.pop();
55
+ for (const [id, job] of state.jobs) {
56
+ if (!dependents.has(id) && job.dependsOn.includes(current)) {
57
+ dependents.add(id);
58
+ queue.push(id);
59
+ }
60
+ }
61
+ }
62
+ return [...dependents];
63
+ }
64
+ export function getReadyJobs(state) {
65
+ if (state.status !== 'processing')
66
+ return [];
67
+ const ready = [];
68
+ for (const [id, job] of state.jobs) {
69
+ if (job.status !== 'pending')
70
+ continue;
71
+ const allDepsResolved = job.dependsOn.every((dep) => {
72
+ const depJob = state.jobs.get(dep);
73
+ return (depJob !== undefined &&
74
+ (depJob.status === 'succeeded' || (state.failurePolicy === 'continue' && TERMINAL_STATUSES.has(depJob.status))));
75
+ });
76
+ if (allDepsResolved) {
77
+ ready.push(id);
78
+ }
79
+ }
80
+ return ready;
81
+ }
82
+ //# sourceMappingURL=evolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evolve.js","sourceRoot":"","sources":["../../src/evolve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=evolve.specs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evolve.specs.d.ts","sourceRoot":"","sources":["../../src/evolve.specs.ts"],"names":[],"mappings":""}
@@ -0,0 +1,209 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { evolve, getReadyJobs, getTransitiveDependents, initialState, isGraphComplete } from './evolve.js';
3
+ describe('evolve', () => {
4
+ it('ignores job events before graph submission', () => {
5
+ const state = evolve(initialState(), { type: 'JobSucceeded', data: { jobId: 'a' } });
6
+ expect(getReadyJobs(state)).toEqual([]);
7
+ expect(isGraphComplete(state)).toBe(false);
8
+ });
9
+ it('ignores job events for unknown job IDs', () => {
10
+ const state = evolve(initialState(), {
11
+ type: 'GraphSubmitted',
12
+ data: {
13
+ graphId: 'g1',
14
+ jobs: [{ id: 'a', dependsOn: [], target: 'build', payload: {} }],
15
+ failurePolicy: 'halt',
16
+ },
17
+ });
18
+ const after = evolve(state, { type: 'JobSucceeded', data: { jobId: 'unknown' } });
19
+ expect(getReadyJobs(after)).toEqual(['a']);
20
+ });
21
+ });
22
+ describe('getReadyJobs', () => {
23
+ it('returns empty array before graph submission', () => {
24
+ expect(getReadyJobs(initialState())).toEqual([]);
25
+ });
26
+ it('returns root jobs after graph submission', () => {
27
+ const state = evolve(initialState(), {
28
+ type: 'GraphSubmitted',
29
+ data: {
30
+ graphId: 'g1',
31
+ jobs: [
32
+ { id: 'a', dependsOn: [], target: 'build', payload: {} },
33
+ { id: 'b', dependsOn: ['a'], target: 'test', payload: {} },
34
+ ],
35
+ failurePolicy: 'halt',
36
+ },
37
+ });
38
+ expect(getReadyJobs(state)).toEqual(['a']);
39
+ });
40
+ it('unlocks dependent jobs after dependency succeeds', () => {
41
+ let state = evolve(initialState(), {
42
+ type: 'GraphSubmitted',
43
+ data: {
44
+ graphId: 'g1',
45
+ jobs: [
46
+ { id: 'a', dependsOn: [], target: 'build', payload: {} },
47
+ { id: 'b', dependsOn: ['a'], target: 'test', payload: {} },
48
+ ],
49
+ failurePolicy: 'halt',
50
+ },
51
+ });
52
+ state = evolve(state, {
53
+ type: 'JobDispatched',
54
+ data: { jobId: 'a', target: 'build', correlationId: 'graph:g1:a' },
55
+ });
56
+ state = evolve(state, { type: 'JobSucceeded', data: { jobId: 'a' } });
57
+ expect(getReadyJobs(state)).toEqual(['b']);
58
+ });
59
+ it('unlocks dependents of failed job under continue policy', () => {
60
+ let state = evolve(initialState(), {
61
+ type: 'GraphSubmitted',
62
+ data: {
63
+ graphId: 'g1',
64
+ jobs: [
65
+ { id: 'a', dependsOn: [], target: 'build', payload: {} },
66
+ { id: 'b', dependsOn: ['a'], target: 'test', payload: {} },
67
+ ],
68
+ failurePolicy: 'continue',
69
+ },
70
+ });
71
+ state = evolve(state, {
72
+ type: 'JobDispatched',
73
+ data: { jobId: 'a', target: 'build', correlationId: 'graph:g1:a' },
74
+ });
75
+ state = evolve(state, { type: 'JobFailed', data: { jobId: 'a', error: 'build error' } });
76
+ expect(getReadyJobs(state)).toEqual(['b']);
77
+ });
78
+ it('does not unlock dependents of dispatched job under continue policy', () => {
79
+ let state = evolve(initialState(), {
80
+ type: 'GraphSubmitted',
81
+ data: {
82
+ graphId: 'g1',
83
+ jobs: [
84
+ { id: 'a', dependsOn: [], target: 'build', payload: {} },
85
+ { id: 'b', dependsOn: ['a'], target: 'test', payload: {} },
86
+ ],
87
+ failurePolicy: 'continue',
88
+ },
89
+ });
90
+ state = evolve(state, {
91
+ type: 'JobDispatched',
92
+ data: { jobId: 'a', target: 'build', correlationId: 'graph:g1:a' },
93
+ });
94
+ expect(getReadyJobs(state)).toEqual([]);
95
+ });
96
+ });
97
+ describe('getTransitiveDependents', () => {
98
+ it('returns empty array before graph submission', () => {
99
+ expect(getTransitiveDependents(initialState(), 'a')).toEqual([]);
100
+ });
101
+ it('returns direct and transitive dependents of a job', () => {
102
+ const state = evolve(initialState(), {
103
+ type: 'GraphSubmitted',
104
+ data: {
105
+ graphId: 'g1',
106
+ jobs: [
107
+ { id: 'a', dependsOn: [], target: 'build', payload: {} },
108
+ { id: 'b', dependsOn: ['a'], target: 'test', payload: {} },
109
+ { id: 'c', dependsOn: ['b'], target: 'deploy', payload: {} },
110
+ ],
111
+ failurePolicy: 'halt',
112
+ },
113
+ });
114
+ expect(getTransitiveDependents(state, 'a').sort()).toEqual(['b', 'c']);
115
+ });
116
+ });
117
+ describe('isGraphComplete', () => {
118
+ it('returns false before graph submission', () => {
119
+ expect(isGraphComplete(initialState())).toBe(false);
120
+ });
121
+ it('returns false when some jobs are still pending', () => {
122
+ let state = evolve(initialState(), {
123
+ type: 'GraphSubmitted',
124
+ data: {
125
+ graphId: 'g1',
126
+ jobs: [
127
+ { id: 'a', dependsOn: [], target: 'build', payload: {} },
128
+ { id: 'b', dependsOn: ['a'], target: 'test', payload: {} },
129
+ ],
130
+ failurePolicy: 'halt',
131
+ },
132
+ });
133
+ state = evolve(state, {
134
+ type: 'JobDispatched',
135
+ data: { jobId: 'a', target: 'build', correlationId: 'graph:g1:a' },
136
+ });
137
+ state = evolve(state, { type: 'JobSucceeded', data: { jobId: 'a' } });
138
+ expect(isGraphComplete(state)).toBe(false);
139
+ });
140
+ it('returns true when a job has been skipped', () => {
141
+ let state = evolve(initialState(), {
142
+ type: 'GraphSubmitted',
143
+ data: {
144
+ graphId: 'g1',
145
+ jobs: [{ id: 'a', dependsOn: [], target: 'build', payload: {} }],
146
+ failurePolicy: 'halt',
147
+ },
148
+ });
149
+ state = evolve(state, { type: 'JobSkipped', data: { jobId: 'a', reason: 'dependency failed' } });
150
+ expect(isGraphComplete(state)).toBe(true);
151
+ });
152
+ it('returns true when a job has timed out', () => {
153
+ let state = evolve(initialState(), {
154
+ type: 'GraphSubmitted',
155
+ data: {
156
+ graphId: 'g1',
157
+ jobs: [{ id: 'a', dependsOn: [], target: 'build', payload: {} }],
158
+ failurePolicy: 'halt',
159
+ },
160
+ });
161
+ state = evolve(state, {
162
+ type: 'JobDispatched',
163
+ data: { jobId: 'a', target: 'build', correlationId: 'graph:g1:a' },
164
+ });
165
+ state = evolve(state, { type: 'JobTimedOut', data: { jobId: 'a', timeoutMs: 5000 } });
166
+ expect(isGraphComplete(state)).toBe(true);
167
+ });
168
+ it('returns true when a job has failed', () => {
169
+ let state = evolve(initialState(), {
170
+ type: 'GraphSubmitted',
171
+ data: {
172
+ graphId: 'g1',
173
+ jobs: [{ id: 'a', dependsOn: [], target: 'build', payload: {} }],
174
+ failurePolicy: 'halt',
175
+ },
176
+ });
177
+ state = evolve(state, {
178
+ type: 'JobDispatched',
179
+ data: { jobId: 'a', target: 'build', correlationId: 'graph:g1:a' },
180
+ });
181
+ state = evolve(state, { type: 'JobFailed', data: { jobId: 'a', error: 'build error' } });
182
+ expect(isGraphComplete(state)).toBe(true);
183
+ });
184
+ it('returns true when all jobs have succeeded', () => {
185
+ let state = evolve(initialState(), {
186
+ type: 'GraphSubmitted',
187
+ data: {
188
+ graphId: 'g1',
189
+ jobs: [
190
+ { id: 'a', dependsOn: [], target: 'build', payload: {} },
191
+ { id: 'b', dependsOn: ['a'], target: 'test', payload: {} },
192
+ ],
193
+ failurePolicy: 'halt',
194
+ },
195
+ });
196
+ state = evolve(state, {
197
+ type: 'JobDispatched',
198
+ data: { jobId: 'a', target: 'build', correlationId: 'graph:g1:a' },
199
+ });
200
+ state = evolve(state, { type: 'JobSucceeded', data: { jobId: 'a' } });
201
+ state = evolve(state, {
202
+ type: 'JobDispatched',
203
+ data: { jobId: 'b', target: 'test', correlationId: 'graph:g1:b' },
204
+ });
205
+ state = evolve(state, { type: 'JobSucceeded', data: { jobId: 'b' } });
206
+ expect(isGraphComplete(state)).toBe(true);
207
+ });
208
+ });
209
+ //# sourceMappingURL=evolve.specs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evolve.specs.js","sourceRoot":"","sources":["../../src/evolve.specs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { Event, MessageBus } from '@auto-engineer/message-bus';
2
+ import type { FailurePolicy } from './evolve';
3
+ import type { Job } from './graph-validator';
4
+ export interface ProcessGraphCommand {
5
+ type: string;
6
+ data: {
7
+ graphId: string;
8
+ jobs: readonly Job[];
9
+ failurePolicy: FailurePolicy;
10
+ };
11
+ }
12
+ export type DispatchFn = (command: {
13
+ type: string;
14
+ data: unknown;
15
+ correlationId: string;
16
+ }) => Promise<void>;
17
+ export declare function createGraphProcessor(messageBus: MessageBus, options?: {
18
+ dispatch?: DispatchFn;
19
+ }): {
20
+ submit: (command: ProcessGraphCommand) => Event;
21
+ };
22
+ //# sourceMappingURL=graph-processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-processor.d.ts","sourceRoot":"","sources":["../../src/graph-processor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAEpE,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,UAAU,CAAC;AAE1D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAI7C,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,SAAS,GAAG,EAAE,CAAC;QACrB,aAAa,EAAE,aAAa,CAAC;KAC9B,CAAC;CACH;AASD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5G,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,UAAU,CAAA;CAAE;sBAWrE,mBAAmB,KAAG,KAAK;EAmFrD"}