@calmo/task-runner 3.2.0 → 3.4.0

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 (63) hide show
  1. package/.jules/backlog_maniac.md +3 -0
  2. package/AGENTS.md +4 -0
  3. package/CHANGELOG.md +26 -0
  4. package/coverage/coverage-final.json +8 -7
  5. package/coverage/index.html +9 -9
  6. package/coverage/lcov-report/index.html +9 -9
  7. package/coverage/lcov-report/src/EventBus.ts.html +4 -4
  8. package/coverage/lcov-report/src/TaskGraphValidationError.ts.html +121 -0
  9. package/coverage/lcov-report/src/TaskGraphValidator.ts.html +38 -38
  10. package/coverage/lcov-report/src/TaskRunner.ts.html +34 -19
  11. package/coverage/lcov-report/src/TaskRunnerBuilder.ts.html +1 -1
  12. package/coverage/lcov-report/src/TaskRunnerExecutionConfig.ts.html +17 -2
  13. package/coverage/lcov-report/src/TaskStateManager.ts.html +35 -35
  14. package/coverage/lcov-report/src/WorkflowExecutor.ts.html +94 -34
  15. package/coverage/lcov-report/src/contracts/RunnerEvents.ts.html +1 -1
  16. package/coverage/lcov-report/src/contracts/index.html +1 -1
  17. package/coverage/lcov-report/src/index.html +23 -8
  18. package/coverage/lcov-report/src/strategies/DryRunExecutionStrategy.ts.html +1 -1
  19. package/coverage/lcov-report/src/strategies/RetryingExecutionStrategy.ts.html +5 -5
  20. package/coverage/lcov-report/src/strategies/StandardExecutionStrategy.ts.html +3 -3
  21. package/coverage/lcov-report/src/strategies/index.html +1 -1
  22. package/coverage/lcov.info +284 -258
  23. package/coverage/src/EventBus.ts.html +4 -4
  24. package/coverage/src/TaskGraphValidationError.ts.html +121 -0
  25. package/coverage/src/TaskGraphValidator.ts.html +38 -38
  26. package/coverage/src/TaskRunner.ts.html +34 -19
  27. package/coverage/src/TaskRunnerBuilder.ts.html +1 -1
  28. package/coverage/src/TaskRunnerExecutionConfig.ts.html +17 -2
  29. package/coverage/src/TaskStateManager.ts.html +35 -35
  30. package/coverage/src/WorkflowExecutor.ts.html +94 -34
  31. package/coverage/src/contracts/RunnerEvents.ts.html +1 -1
  32. package/coverage/src/contracts/index.html +1 -1
  33. package/coverage/src/index.html +23 -8
  34. package/coverage/src/strategies/DryRunExecutionStrategy.ts.html +1 -1
  35. package/coverage/src/strategies/RetryingExecutionStrategy.ts.html +5 -5
  36. package/coverage/src/strategies/StandardExecutionStrategy.ts.html +3 -3
  37. package/coverage/src/strategies/index.html +1 -1
  38. package/dist/TaskGraphValidationError.d.ts +9 -0
  39. package/dist/TaskGraphValidationError.js +13 -0
  40. package/dist/TaskGraphValidationError.js.map +1 -0
  41. package/dist/TaskRunner.js +3 -2
  42. package/dist/TaskRunner.js.map +1 -1
  43. package/dist/TaskRunnerExecutionConfig.d.ts +5 -0
  44. package/dist/WorkflowExecutor.d.ts +4 -1
  45. package/dist/WorkflowExecutor.js +19 -4
  46. package/dist/WorkflowExecutor.js.map +1 -1
  47. package/dist/index.d.ts +1 -0
  48. package/dist/index.js +1 -0
  49. package/dist/index.js.map +1 -1
  50. package/openspec/changes/archive/2026-01-18-add-concurrency-control/tasks.md +9 -0
  51. package/openspec/changes/archive/2026-01-18-add-task-retry-policy/tasks.md +10 -0
  52. package/openspec/project.md +1 -0
  53. package/package.json +1 -1
  54. package/src/TaskGraphValidationError.ts +12 -0
  55. package/src/TaskRunner.ts +7 -2
  56. package/src/TaskRunnerExecutionConfig.ts +5 -0
  57. package/src/WorkflowExecutor.ts +24 -4
  58. package/src/index.ts +1 -0
  59. package/test-report.xml +114 -102
  60. package/openspec/changes/add-concurrency-control/tasks.md +0 -9
  61. package/openspec/changes/add-task-retry-policy/tasks.md +0 -10
  62. /package/openspec/changes/{add-concurrency-control → archive/2026-01-18-add-concurrency-control}/proposal.md +0 -0
  63. /package/openspec/changes/{add-task-retry-policy → archive/2026-01-18-add-task-retry-policy}/proposal.md +0 -0
@@ -2,6 +2,7 @@ import { TaskGraphValidator } from "./TaskGraphValidator.js";
2
2
  import { EventBus } from "./EventBus.js";
3
3
  import { WorkflowExecutor } from "./WorkflowExecutor.js";
4
4
  import { TaskStateManager } from "./TaskStateManager.js";
5
+ import { TaskGraphValidationError } from "./TaskGraphValidationError.js";
5
6
  import { StandardExecutionStrategy } from "./strategies/StandardExecutionStrategy.js";
6
7
  import { RetryingExecutionStrategy } from "./strategies/RetryingExecutionStrategy.js";
7
8
  import { DryRunExecutionStrategy } from "./strategies/DryRunExecutionStrategy.js";
@@ -105,14 +106,14 @@ export class TaskRunner {
105
106
  };
106
107
  const validationResult = this.validator.validate(taskGraph);
107
108
  if (!validationResult.isValid) {
108
- throw new Error(this.validator.createErrorMessage(validationResult));
109
+ throw new TaskGraphValidationError(validationResult, this.validator.createErrorMessage(validationResult));
109
110
  }
110
111
  const stateManager = new TaskStateManager(this.eventBus);
111
112
  let strategy = this.executionStrategy;
112
113
  if (config?.dryRun) {
113
114
  strategy = new DryRunExecutionStrategy();
114
115
  }
115
- const executor = new WorkflowExecutor(this.context, this.eventBus, stateManager, strategy);
116
+ const executor = new WorkflowExecutor(this.context, this.eventBus, stateManager, strategy, config?.concurrency);
116
117
  // We need to handle the timeout cleanup properly.
117
118
  if (config?.timeout !== undefined) {
118
119
  const controller = new AbortController();
@@ -1 +1 @@
1
- {"version":3,"file":"TaskRunner.js","sourceRoot":"","sources":["../src/TaskRunner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"TaskRunner.js","sourceRoot":"","sources":["../src/TaskRunner.ts"],"names":[],"mappings":"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"}
@@ -15,4 +15,9 @@ export interface TaskRunnerExecutionConfig {
15
15
  * Useful for verifying the execution order and graph structure.
16
16
  */
17
17
  dryRun?: boolean;
18
+ /**
19
+ * The maximum number of tasks to run concurrently.
20
+ * If undefined, all ready tasks will be run in parallel.
21
+ */
22
+ concurrency?: number;
18
23
  }
@@ -12,13 +12,16 @@ export declare class WorkflowExecutor<TContext> {
12
12
  private eventBus;
13
13
  private stateManager;
14
14
  private strategy;
15
+ private concurrency?;
16
+ private readyQueue;
15
17
  /**
16
18
  * @param context The shared context object.
17
19
  * @param eventBus The event bus to emit events.
18
20
  * @param stateManager Manages execution state.
19
21
  * @param strategy Execution strategy.
22
+ * @param concurrency Maximum number of concurrent tasks.
20
23
  */
21
- constructor(context: TContext, eventBus: EventBus<TContext>, stateManager: TaskStateManager<TContext>, strategy: IExecutionStrategy<TContext>);
24
+ constructor(context: TContext, eventBus: EventBus<TContext>, stateManager: TaskStateManager<TContext>, strategy: IExecutionStrategy<TContext>, concurrency?: number | undefined);
22
25
  /**
23
26
  * Executes the given steps.
24
27
  * @param steps The list of steps to execute.
@@ -7,17 +7,21 @@ export class WorkflowExecutor {
7
7
  eventBus;
8
8
  stateManager;
9
9
  strategy;
10
+ concurrency;
11
+ readyQueue = [];
10
12
  /**
11
13
  * @param context The shared context object.
12
14
  * @param eventBus The event bus to emit events.
13
15
  * @param stateManager Manages execution state.
14
16
  * @param strategy Execution strategy.
17
+ * @param concurrency Maximum number of concurrent tasks.
15
18
  */
16
- constructor(context, eventBus, stateManager, strategy) {
19
+ constructor(context, eventBus, stateManager, strategy, concurrency) {
17
20
  this.context = context;
18
21
  this.eventBus = eventBus;
19
22
  this.stateManager = stateManager;
20
23
  this.strategy = strategy;
24
+ this.concurrency = concurrency;
21
25
  }
22
26
  /**
23
27
  * Executes the given steps.
@@ -82,9 +86,18 @@ export class WorkflowExecutor {
82
86
  * Logic to identify tasks that can be started and run them.
83
87
  */
84
88
  processLoop(executingPromises, signal) {
85
- const toRun = this.stateManager.processDependencies();
86
- // Execute ready tasks
87
- for (const step of toRun) {
89
+ const newlyReady = this.stateManager.processDependencies();
90
+ // Add newly ready tasks to the queue
91
+ for (const task of newlyReady) {
92
+ this.readyQueue.push(task);
93
+ }
94
+ // Execute ready tasks while respecting concurrency limit
95
+ while (this.readyQueue.length > 0) {
96
+ if (this.concurrency !== undefined &&
97
+ executingPromises.size >= this.concurrency) {
98
+ break;
99
+ }
100
+ const step = this.readyQueue.shift();
88
101
  this.stateManager.markRunning(step);
89
102
  const taskPromise = this.strategy.execute(step, this.context, signal)
90
103
  .then((result) => {
@@ -92,6 +105,8 @@ export class WorkflowExecutor {
92
105
  })
93
106
  .finally(() => {
94
107
  executingPromises.delete(taskPromise);
108
+ // When a task finishes, we try to run more
109
+ this.processLoop(executingPromises, signal);
95
110
  });
96
111
  executingPromises.add(taskPromise);
97
112
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WorkflowExecutor.js","sourceRoot":"","sources":["../src/WorkflowExecutor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WorkflowExecutor.js","sourceRoot":"","sources":["../src/WorkflowExecutor.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { TaskRunner } from "./TaskRunner.js";
2
2
  export { TaskRunnerBuilder } from "./TaskRunnerBuilder.js";
3
3
  export { TaskStateManager } from "./TaskStateManager.js";
4
+ export { TaskGraphValidationError } from "./TaskGraphValidationError.js";
4
5
  export { StandardExecutionStrategy } from "./strategies/StandardExecutionStrategy.js";
5
6
  export { RetryingExecutionStrategy } from "./strategies/RetryingExecutionStrategy.js";
6
7
  export type { IExecutionStrategy } from "./strategies/IExecutionStrategy.js";
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { TaskRunner } from "./TaskRunner.js";
2
2
  export { TaskRunnerBuilder } from "./TaskRunnerBuilder.js";
3
3
  export { TaskStateManager } from "./TaskStateManager.js";
4
+ export { TaskGraphValidationError } from "./TaskGraphValidationError.js";
4
5
  export { StandardExecutionStrategy } from "./strategies/StandardExecutionStrategy.js";
5
6
  export { RetryingExecutionStrategy } from "./strategies/RetryingExecutionStrategy.js";
6
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC"}
@@ -0,0 +1,9 @@
1
+ ## Implementation
2
+ - [x] 1.1 Update `TaskRunnerExecutionConfig` to include an optional `concurrency` property.
3
+ - [x] 1.2 Update `WorkflowExecutor` to accept the `concurrency` limit.
4
+ - [x] 1.3 Implement a task queueing mechanism in `WorkflowExecutor` to manage pending tasks.
5
+ - [x] 1.4 Update execution logic to check available concurrency slots before starting a task.
6
+ - [x] 1.5 Ensure task completion triggers the execution of queued tasks.
7
+ - [x] 1.6 Verify that unlimited concurrency (default behavior) is preserved when no limit is set.
8
+ - [x] 1.7 Add unit tests for concurrency limits (e.g., ensure no more than N tasks run at once).
9
+ - [x] 1.8 Add integration tests with mixed dependencies and concurrency limits.
@@ -0,0 +1,10 @@
1
+ ## Implementation
2
+ - [x] 1.1 Create `TaskRetryConfig` interface with `attempts`, `delay`, and `backoff`.
3
+ - [x] 1.2 Update `TaskStep` interface to include optional `retry: TaskRetryConfig`.
4
+ - [x] 1.3 Update execution logic to catch task failures.
5
+ - [x] 1.4 Implement retry loop/recursion checking `attempts` count.
6
+ - [x] 1.5 Implement delay logic with support for `fixed` and `exponential` backoff.
7
+ - [x] 1.6 Ensure `TaskResult` reflects the final status after retries (success if eventually succeeds, failure if all attempts fail).
8
+ - [x] 1.7 Add unit tests for successful retry after failure.
9
+ - [x] 1.8 Add unit tests for exhaustion of retry attempts (final failure).
10
+ - [x] 1.9 Add unit tests for backoff timing (mock timers).
@@ -23,6 +23,7 @@ The project follows a modular architecture with distinct components for managing
23
23
  - **Commit Messages:** Follows conventional commits enforced by Commitlint.
24
24
  - **Git Hooks:** Utilizes Husky for pre-commit and commit-msg hooks.
25
25
  - **Testing:** Uses Vitest for unit and integration testing.
26
+ - **Atomic Commits:** When working on complex multi-task features, commit after each distinct task, ensuring build, lint, and test success to establish safe rollback points.
26
27
 
27
28
  ## Build/Test/Run Commands
28
29
  - **Install Dependencies:** `pnpm install`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calmo/task-runner",
3
- "version": "3.2.0",
3
+ "version": "3.4.0",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -0,0 +1,12 @@
1
+ import { ValidationResult } from "./contracts/ValidationResult.js";
2
+
3
+ /**
4
+ * Error thrown when a task graph fails validation.
5
+ * Contains the validation result with detailed error information.
6
+ */
7
+ export class TaskGraphValidationError extends Error {
8
+ constructor(public result: ValidationResult, message: string) {
9
+ super(message);
10
+ this.name = "TaskGraphValidationError";
11
+ }
12
+ }
package/src/TaskRunner.ts CHANGED
@@ -7,6 +7,7 @@ import { EventBus } from "./EventBus.js";
7
7
  import { WorkflowExecutor } from "./WorkflowExecutor.js";
8
8
  import { TaskRunnerExecutionConfig } from "./TaskRunnerExecutionConfig.js";
9
9
  import { TaskStateManager } from "./TaskStateManager.js";
10
+ import { TaskGraphValidationError } from "./TaskGraphValidationError.js";
10
11
  import { IExecutionStrategy } from "./strategies/IExecutionStrategy.js";
11
12
  import { StandardExecutionStrategy } from "./strategies/StandardExecutionStrategy.js";
12
13
  import { RetryingExecutionStrategy } from "./strategies/RetryingExecutionStrategy.js";
@@ -138,7 +139,10 @@ export class TaskRunner<TContext> {
138
139
 
139
140
  const validationResult = this.validator.validate(taskGraph);
140
141
  if (!validationResult.isValid) {
141
- throw new Error(this.validator.createErrorMessage(validationResult));
142
+ throw new TaskGraphValidationError(
143
+ validationResult,
144
+ this.validator.createErrorMessage(validationResult)
145
+ );
142
146
  }
143
147
 
144
148
  const stateManager = new TaskStateManager(this.eventBus);
@@ -152,7 +156,8 @@ export class TaskRunner<TContext> {
152
156
  this.context,
153
157
  this.eventBus,
154
158
  stateManager,
155
- strategy
159
+ strategy,
160
+ config?.concurrency
156
161
  );
157
162
 
158
163
  // We need to handle the timeout cleanup properly.
@@ -15,4 +15,9 @@ export interface TaskRunnerExecutionConfig {
15
15
  * Useful for verifying the execution order and graph structure.
16
16
  */
17
17
  dryRun?: boolean;
18
+ /**
19
+ * The maximum number of tasks to run concurrently.
20
+ * If undefined, all ready tasks will be run in parallel.
21
+ */
22
+ concurrency?: number;
18
23
  }
@@ -9,17 +9,21 @@ import { IExecutionStrategy } from "./strategies/IExecutionStrategy.js";
9
9
  * @template TContext The shape of the shared context object.
10
10
  */
11
11
  export class WorkflowExecutor<TContext> {
12
+ private readyQueue: TaskStep<TContext>[] = [];
13
+
12
14
  /**
13
15
  * @param context The shared context object.
14
16
  * @param eventBus The event bus to emit events.
15
17
  * @param stateManager Manages execution state.
16
18
  * @param strategy Execution strategy.
19
+ * @param concurrency Maximum number of concurrent tasks.
17
20
  */
18
21
  constructor(
19
22
  private context: TContext,
20
23
  private eventBus: EventBus<TContext>,
21
24
  private stateManager: TaskStateManager<TContext>,
22
- private strategy: IExecutionStrategy<TContext>
25
+ private strategy: IExecutionStrategy<TContext>,
26
+ private concurrency?: number
23
27
  ) {}
24
28
 
25
29
  /**
@@ -100,10 +104,24 @@ export class WorkflowExecutor<TContext> {
100
104
  executingPromises: Set<Promise<void>>,
101
105
  signal?: AbortSignal
102
106
  ): void {
103
- const toRun = this.stateManager.processDependencies();
107
+ const newlyReady = this.stateManager.processDependencies();
108
+
109
+ // Add newly ready tasks to the queue
110
+ for (const task of newlyReady) {
111
+ this.readyQueue.push(task);
112
+ }
113
+
114
+ // Execute ready tasks while respecting concurrency limit
115
+ while (this.readyQueue.length > 0) {
116
+ if (
117
+ this.concurrency !== undefined &&
118
+ executingPromises.size >= this.concurrency
119
+ ) {
120
+ break;
121
+ }
122
+
123
+ const step = this.readyQueue.shift()!;
104
124
 
105
- // Execute ready tasks
106
- for (const step of toRun) {
107
125
  this.stateManager.markRunning(step);
108
126
 
109
127
  const taskPromise = this.strategy.execute(step, this.context, signal)
@@ -112,6 +130,8 @@ export class WorkflowExecutor<TContext> {
112
130
  })
113
131
  .finally(() => {
114
132
  executingPromises.delete(taskPromise);
133
+ // When a task finishes, we try to run more
134
+ this.processLoop(executingPromises, signal);
115
135
  });
116
136
 
117
137
  executingPromises.add(taskPromise);
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { TaskRunner } from "./TaskRunner.js";
2
2
  export { TaskRunnerBuilder } from "./TaskRunnerBuilder.js";
3
3
  export { TaskStateManager } from "./TaskStateManager.js";
4
+ export { TaskGraphValidationError } from "./TaskGraphValidationError.js";
4
5
  export { StandardExecutionStrategy } from "./strategies/StandardExecutionStrategy.js";
5
6
  export { RetryingExecutionStrategy } from "./strategies/RetryingExecutionStrategy.js";
6
7
  export type { IExecutionStrategy } from "./strategies/IExecutionStrategy.js";