spawnee 1.0.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.
- package/LICENSE +22 -0
- package/README.md +265 -0
- package/dist/core/orchestrator.d.ts +45 -0
- package/dist/core/orchestrator.js +240 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/task-queue.d.ts +49 -0
- package/dist/core/task-queue.js +113 -0
- package/dist/core/task-queue.js.map +1 -0
- package/dist/cursor/client.d.ts +20 -0
- package/dist/cursor/client.js +133 -0
- package/dist/cursor/client.js.map +1 -0
- package/dist/cursor/types.d.ts +60 -0
- package/dist/cursor/types.js +2 -0
- package/dist/cursor/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +274 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/index.d.ts +241 -0
- package/dist/parsers/index.js +119 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/storage/file-adapter.d.ts +10 -0
- package/dist/storage/file-adapter.js +46 -0
- package/dist/storage/file-adapter.js.map +1 -0
- package/dist/storage/state-store.d.ts +31 -0
- package/dist/storage/state-store.js +2 -0
- package/dist/storage/state-store.js.map +1 -0
- package/dist/utils/config.d.ts +42 -0
- package/dist/utils/config.js +74 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +16 -0
- package/dist/utils/logger.js +47 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/retry.d.ts +8 -0
- package/dist/utils/retry.js +20 -0
- package/dist/utils/retry.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 spencech
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# spawnee
|
|
2
|
+
|
|
3
|
+
Spawn and orchestrate Cursor Cloud Agents from task templates with dependency resolution, parallel execution, and automatic retries.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g spawnee
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Initialize a config file
|
|
15
|
+
spawnee init
|
|
16
|
+
|
|
17
|
+
# Edit .spawneerc.json with your API key
|
|
18
|
+
|
|
19
|
+
# Validate a template
|
|
20
|
+
spawnee validate my-tasks.yaml
|
|
21
|
+
|
|
22
|
+
# Dry run (preview without spawning agents)
|
|
23
|
+
spawnee run my-tasks.yaml --dry-run
|
|
24
|
+
|
|
25
|
+
# Execute the template
|
|
26
|
+
spawnee run my-tasks.yaml
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
spawnee supports three configuration methods with the following priority (highest to lowest):
|
|
32
|
+
|
|
33
|
+
1. **CLI flags** - Override everything
|
|
34
|
+
2. **Environment variables** - Override config file and defaults
|
|
35
|
+
3. **Config file** (`.spawneerc.json`) - Override defaults
|
|
36
|
+
4. **Built-in defaults**
|
|
37
|
+
|
|
38
|
+
### Configuration Options
|
|
39
|
+
|
|
40
|
+
| Option | CLI Flag | Environment Variable | Config Key | Default |
|
|
41
|
+
|--------|----------|---------------------|------------|---------|
|
|
42
|
+
| API Key | `--api-key, -k` | `SPAWNEE_API_KEY` | `apiKey` | (required) |
|
|
43
|
+
| API Base URL | `--api-url` | `SPAWNEE_API_URL` | `apiBaseUrl` | `https://api.cursor.com` |
|
|
44
|
+
| Max Concurrent | `--concurrency, -c` | `SPAWNEE_CONCURRENCY` | `maxConcurrent` | `10` |
|
|
45
|
+
| Poll Interval | `--poll-interval` | `SPAWNEE_POLL_INTERVAL` | `pollInterval` | `15000` (ms) |
|
|
46
|
+
| Default Timeout | `--timeout, -t` | `SPAWNEE_TIMEOUT` | `defaultTimeout` | `3600000` (ms) |
|
|
47
|
+
| State File | `--state-file` | `SPAWNEE_STATE_FILE` | `stateFile` | `.spawnee-state.json` |
|
|
48
|
+
| Config File | `--config` | `SPAWNEE_CONFIG` | - | `.spawneerc.json` |
|
|
49
|
+
| Verbose | `--verbose, -v` | `SPAWNEE_VERBOSE` | `verbose` | `false` |
|
|
50
|
+
|
|
51
|
+
### Config File
|
|
52
|
+
|
|
53
|
+
Create a `.spawneerc.json` file in your project root:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"apiKey": "your-cursor-api-key",
|
|
58
|
+
"apiBaseUrl": "https://api.cursor.com",
|
|
59
|
+
"maxConcurrent": 10,
|
|
60
|
+
"pollInterval": 15000,
|
|
61
|
+
"defaultTimeout": 3600000,
|
|
62
|
+
"stateFile": ".spawnee-state.json",
|
|
63
|
+
"verbose": false
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Or generate one with:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
spawnee init
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Environment Variables
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
export SPAWNEE_API_KEY="your-cursor-api-key"
|
|
77
|
+
export SPAWNEE_CONCURRENCY=5
|
|
78
|
+
export SPAWNEE_TIMEOUT=7200000
|
|
79
|
+
export SPAWNEE_VERBOSE=true
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### CLI Flags
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
spawnee run my-tasks.yaml \
|
|
86
|
+
--api-key "your-key" \
|
|
87
|
+
--concurrency 5 \
|
|
88
|
+
--timeout 7200000 \
|
|
89
|
+
--poll-interval 10000 \
|
|
90
|
+
--state-file ".my-state.json" \
|
|
91
|
+
--verbose
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Commands
|
|
95
|
+
|
|
96
|
+
### `spawnee run <template>`
|
|
97
|
+
|
|
98
|
+
Execute a task template.
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
spawnee run my-tasks.yaml [options]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Options:**
|
|
105
|
+
- `-k, --api-key <key>` - Cursor API key
|
|
106
|
+
- `--api-url <url>` - API base URL
|
|
107
|
+
- `-c, --concurrency <n>` - Max concurrent agents
|
|
108
|
+
- `-t, --timeout <ms>` - Default task timeout
|
|
109
|
+
- `--poll-interval <ms>` - Status poll interval
|
|
110
|
+
- `--state-file <path>` - State file for persistence
|
|
111
|
+
- `-d, --dry-run` - Preview without spawning agents
|
|
112
|
+
- `--no-persist` - Disable state persistence
|
|
113
|
+
- `-v, --verbose` - Enable verbose output
|
|
114
|
+
|
|
115
|
+
### `spawnee validate <template>`
|
|
116
|
+
|
|
117
|
+
Validate a task template without running it.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
spawnee validate my-tasks.yaml
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### `spawnee status`
|
|
124
|
+
|
|
125
|
+
Check status of running agents.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
spawnee status [options]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Options:**
|
|
132
|
+
- `-k, --api-key <key>` - Cursor API key
|
|
133
|
+
- `--api-url <url>` - API base URL
|
|
134
|
+
|
|
135
|
+
### `spawnee cancel <agent-id>`
|
|
136
|
+
|
|
137
|
+
Cancel a running agent.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
spawnee cancel abc123def456
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### `spawnee init`
|
|
144
|
+
|
|
145
|
+
Create a `.spawneerc.json` config file.
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
spawnee init # Create config file
|
|
149
|
+
spawnee init --force # Overwrite existing
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### `spawnee config`
|
|
153
|
+
|
|
154
|
+
Show the resolved configuration (useful for debugging).
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
spawnee config
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Task Templates
|
|
161
|
+
|
|
162
|
+
Templates can be JSON or YAML. Here's a complete example:
|
|
163
|
+
|
|
164
|
+
```yaml
|
|
165
|
+
name: "My Task Plan"
|
|
166
|
+
repository:
|
|
167
|
+
url: "https://github.com/your-org/your-repo"
|
|
168
|
+
branch: "main"
|
|
169
|
+
baseBranch: "develop"
|
|
170
|
+
|
|
171
|
+
defaults:
|
|
172
|
+
model: "auto"
|
|
173
|
+
timeout: 3600000
|
|
174
|
+
retries: 2
|
|
175
|
+
|
|
176
|
+
context:
|
|
177
|
+
instructions: |
|
|
178
|
+
You are implementing features for a Node.js application.
|
|
179
|
+
Follow existing code patterns and conventions.
|
|
180
|
+
files:
|
|
181
|
+
- "README.md"
|
|
182
|
+
- "package.json"
|
|
183
|
+
|
|
184
|
+
tasks:
|
|
185
|
+
- id: "setup"
|
|
186
|
+
name: "Project Setup"
|
|
187
|
+
priority: 100
|
|
188
|
+
branch: "feature/setup"
|
|
189
|
+
prompt: |
|
|
190
|
+
Initialize the project structure:
|
|
191
|
+
1. Create necessary directories
|
|
192
|
+
2. Set up configuration files
|
|
193
|
+
|
|
194
|
+
- id: "feature-a"
|
|
195
|
+
name: "Feature A"
|
|
196
|
+
dependsOn: ["setup"]
|
|
197
|
+
priority: 80
|
|
198
|
+
branch: "feature/a"
|
|
199
|
+
prompt: |
|
|
200
|
+
Implement Feature A with tests.
|
|
201
|
+
files:
|
|
202
|
+
- "src/features/"
|
|
203
|
+
|
|
204
|
+
- id: "feature-b"
|
|
205
|
+
name: "Feature B"
|
|
206
|
+
dependsOn: ["setup"]
|
|
207
|
+
priority: 80
|
|
208
|
+
branch: "feature/b"
|
|
209
|
+
prompt: |
|
|
210
|
+
Implement Feature B with tests.
|
|
211
|
+
|
|
212
|
+
- id: "integration"
|
|
213
|
+
name: "Integration"
|
|
214
|
+
dependsOn: ["feature-a", "feature-b"]
|
|
215
|
+
priority: 60
|
|
216
|
+
branch: "feature/integration"
|
|
217
|
+
prompt: |
|
|
218
|
+
Integrate features and add integration tests.
|
|
219
|
+
validation:
|
|
220
|
+
command: "npm test"
|
|
221
|
+
successPattern: "passed"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Template Schema
|
|
225
|
+
|
|
226
|
+
**Required fields:**
|
|
227
|
+
- `name` - Template name
|
|
228
|
+
- `repository.url` - GitHub repository URL
|
|
229
|
+
- `tasks` - Array of tasks
|
|
230
|
+
|
|
231
|
+
**Task fields:**
|
|
232
|
+
- `id` (required) - Unique task identifier
|
|
233
|
+
- `name` (required) - Human-readable name
|
|
234
|
+
- `prompt` (required) - Instructions for the agent
|
|
235
|
+
- `dependsOn` - Array of task IDs this task depends on
|
|
236
|
+
- `priority` - Higher runs first (default: 0)
|
|
237
|
+
- `branch` - Git branch for the task
|
|
238
|
+
- `files` - Files to include in context
|
|
239
|
+
- `timeout` - Task-specific timeout (ms)
|
|
240
|
+
- `retries` - Max retry attempts
|
|
241
|
+
- `complete` - Mark as already complete (skip)
|
|
242
|
+
- `validation.command` - Command to verify completion
|
|
243
|
+
- `validation.successPattern` - Expected output pattern
|
|
244
|
+
|
|
245
|
+
## Features
|
|
246
|
+
|
|
247
|
+
- **Dependency Resolution** - Tasks run in correct order based on `dependsOn`
|
|
248
|
+
- **Parallel Execution** - Independent tasks run concurrently (up to `maxConcurrent`)
|
|
249
|
+
- **Automatic Retries** - Failed tasks retry with configurable attempts
|
|
250
|
+
- **State Persistence** - Resume interrupted runs from where they left off
|
|
251
|
+
- **Validation** - Optional command validation for task completion
|
|
252
|
+
- **Dry Run** - Preview task graph without spawning agents
|
|
253
|
+
|
|
254
|
+
## Limits
|
|
255
|
+
|
|
256
|
+
- Maximum 256 concurrent agents per API key
|
|
257
|
+
- Usage-based pricing (same as Cursor Background Agents)
|
|
258
|
+
|
|
259
|
+
## Getting Your API Key
|
|
260
|
+
|
|
261
|
+
Get your Cursor API key from: **Cursor Dashboard → Integrations → User API Keys**
|
|
262
|
+
|
|
263
|
+
## License
|
|
264
|
+
|
|
265
|
+
MIT
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { TaskInput } from './task-queue.js';
|
|
3
|
+
import { StateStore } from '../storage/state-store.js';
|
|
4
|
+
import { Config } from '../utils/config.js';
|
|
5
|
+
export interface OrchestratorOptions {
|
|
6
|
+
config: Config;
|
|
7
|
+
stateStore?: StateStore;
|
|
8
|
+
repository: string;
|
|
9
|
+
baseBranch: string;
|
|
10
|
+
globalContext?: string;
|
|
11
|
+
globalFiles?: string[];
|
|
12
|
+
}
|
|
13
|
+
export declare class Orchestrator extends EventEmitter {
|
|
14
|
+
private client;
|
|
15
|
+
private queue;
|
|
16
|
+
private stateStore?;
|
|
17
|
+
private logger;
|
|
18
|
+
private options;
|
|
19
|
+
private activeAgents;
|
|
20
|
+
private timeouts;
|
|
21
|
+
private isRunning;
|
|
22
|
+
private templateName;
|
|
23
|
+
constructor(options: OrchestratorOptions);
|
|
24
|
+
private setupEventHandlers;
|
|
25
|
+
loadTasks(templateName: string, tasks: TaskInput[]): void;
|
|
26
|
+
start(): Promise<void>;
|
|
27
|
+
private trySpawnAgents;
|
|
28
|
+
private spawnAgent;
|
|
29
|
+
private buildPrompt;
|
|
30
|
+
private handleAgentComplete;
|
|
31
|
+
private handleAgentFailed;
|
|
32
|
+
private clearTimeout;
|
|
33
|
+
private clearAllTimeouts;
|
|
34
|
+
private saveState;
|
|
35
|
+
stop(): Promise<void>;
|
|
36
|
+
getStatus(): {
|
|
37
|
+
isRunning: boolean;
|
|
38
|
+
queue: Record<string, number>;
|
|
39
|
+
activeAgents: Array<{
|
|
40
|
+
agentId: string;
|
|
41
|
+
taskId: string;
|
|
42
|
+
}>;
|
|
43
|
+
};
|
|
44
|
+
sendFollowUp(taskId: string, message: string): Promise<void>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { CursorClient } from '../cursor/client.js';
|
|
3
|
+
import { TaskQueue } from './task-queue.js';
|
|
4
|
+
import { Logger } from '../utils/logger.js';
|
|
5
|
+
export class Orchestrator extends EventEmitter {
|
|
6
|
+
client;
|
|
7
|
+
queue;
|
|
8
|
+
stateStore;
|
|
9
|
+
logger;
|
|
10
|
+
options;
|
|
11
|
+
activeAgents = new Map(); // agentId -> taskId
|
|
12
|
+
timeouts = new Map();
|
|
13
|
+
isRunning = false;
|
|
14
|
+
templateName = '';
|
|
15
|
+
constructor(options) {
|
|
16
|
+
super();
|
|
17
|
+
this.options = options;
|
|
18
|
+
this.client = new CursorClient(options.config.apiKey, options.config.apiBaseUrl);
|
|
19
|
+
this.queue = new TaskQueue();
|
|
20
|
+
this.stateStore = options.stateStore;
|
|
21
|
+
this.logger = new Logger('Orchestrator');
|
|
22
|
+
this.setupEventHandlers();
|
|
23
|
+
}
|
|
24
|
+
setupEventHandlers() {
|
|
25
|
+
this.queue.on('taskReady', () => this.trySpawnAgents());
|
|
26
|
+
this.queue.on('taskCompleted', (task) => {
|
|
27
|
+
this.logger.success(`Task completed: ${task.id}`);
|
|
28
|
+
this.emit('taskCompleted', task);
|
|
29
|
+
this.saveState();
|
|
30
|
+
});
|
|
31
|
+
this.queue.on('taskFailed', (task) => {
|
|
32
|
+
this.logger.error(`Task failed: ${task.id} - ${task.error}`);
|
|
33
|
+
this.emit('taskFailed', task);
|
|
34
|
+
this.saveState();
|
|
35
|
+
});
|
|
36
|
+
this.queue.on('taskRetry', (task) => {
|
|
37
|
+
this.logger.warn(`Retrying task: ${task.id} (attempt ${task.attempts + 1})`);
|
|
38
|
+
this.emit('taskRetry', task);
|
|
39
|
+
});
|
|
40
|
+
this.queue.on('allComplete', (results) => {
|
|
41
|
+
this.isRunning = false;
|
|
42
|
+
this.client.stopAllMonitoring();
|
|
43
|
+
this.clearAllTimeouts();
|
|
44
|
+
this.logger.info('All tasks complete');
|
|
45
|
+
this.emit('complete', results);
|
|
46
|
+
this.stateStore?.clear();
|
|
47
|
+
});
|
|
48
|
+
this.client.on('completed', ({ agentId, ...agent }) => {
|
|
49
|
+
this.handleAgentComplete(agentId, agent);
|
|
50
|
+
});
|
|
51
|
+
this.client.on('failed', ({ agentId, ...agent }) => {
|
|
52
|
+
const errorMsg = agent.summary || 'Agent failed';
|
|
53
|
+
this.handleAgentFailed(agentId, errorMsg);
|
|
54
|
+
});
|
|
55
|
+
this.client.on('cancelled', ({ agentId }) => {
|
|
56
|
+
this.handleAgentFailed(agentId, 'Agent was stopped');
|
|
57
|
+
});
|
|
58
|
+
this.client.on('error', ({ agentId, error }) => {
|
|
59
|
+
this.logger.error(`Agent ${agentId} error: ${error.message}`);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
loadTasks(templateName, tasks) {
|
|
63
|
+
this.templateName = templateName;
|
|
64
|
+
this.queue.addTasks(tasks);
|
|
65
|
+
const completedCount = tasks.filter(t => t.complete).length;
|
|
66
|
+
const activeCount = tasks.length - completedCount;
|
|
67
|
+
this.logger.info(`Loaded ${tasks.length} tasks from "${templateName}"${completedCount > 0 ? ` (${completedCount} already completed, ${activeCount} active)` : ''}`);
|
|
68
|
+
}
|
|
69
|
+
async start() {
|
|
70
|
+
if (this.isRunning)
|
|
71
|
+
throw new Error('Orchestrator is already running');
|
|
72
|
+
this.isRunning = true;
|
|
73
|
+
this.logger.info('Starting orchestration...');
|
|
74
|
+
this.emit('started', this.queue.getStatus());
|
|
75
|
+
await this.saveState();
|
|
76
|
+
await this.trySpawnAgents();
|
|
77
|
+
}
|
|
78
|
+
async trySpawnAgents() {
|
|
79
|
+
if (!this.isRunning)
|
|
80
|
+
return;
|
|
81
|
+
const availableSlots = this.options.config.maxConcurrent - this.activeAgents.size;
|
|
82
|
+
if (availableSlots <= 0)
|
|
83
|
+
return;
|
|
84
|
+
const readyTasks = this.queue.getReadyTasks().slice(0, availableSlots);
|
|
85
|
+
for (const task of readyTasks) {
|
|
86
|
+
try {
|
|
87
|
+
await this.spawnAgent(task);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
this.logger.error(`Failed to spawn agent for ${task.id}: ${error}`);
|
|
91
|
+
this.queue.markFailed(task.id, error.message);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async spawnAgent(task) {
|
|
96
|
+
const prompt = this.buildPrompt(task);
|
|
97
|
+
this.logger.info(`Spawning agent for task: ${task.id}`);
|
|
98
|
+
const agent = await this.client.createAgent({
|
|
99
|
+
prompt,
|
|
100
|
+
repository: this.options.repository,
|
|
101
|
+
branchName: task.branch || `task/${task.id}`,
|
|
102
|
+
ref: this.options.baseBranch,
|
|
103
|
+
autoCreatePr: true,
|
|
104
|
+
});
|
|
105
|
+
this.activeAgents.set(agent.id, task.id);
|
|
106
|
+
this.queue.markRunning(task.id, agent.id);
|
|
107
|
+
this.client.startMonitoring(agent.id, this.options.config.pollInterval);
|
|
108
|
+
const timeout = task.timeout || this.options.config.defaultTimeout;
|
|
109
|
+
const timer = setTimeout(() => {
|
|
110
|
+
if (!this.activeAgents.has(agent.id))
|
|
111
|
+
return;
|
|
112
|
+
this.logger.warn(`Task ${task.id} timed out`);
|
|
113
|
+
this.client.stopAgent(agent.id).catch(() => { });
|
|
114
|
+
this.handleAgentFailed(agent.id, 'Timeout exceeded');
|
|
115
|
+
}, timeout);
|
|
116
|
+
this.timeouts.set(agent.id, timer);
|
|
117
|
+
this.emit('agentSpawned', { taskId: task.id, agentId: agent.id });
|
|
118
|
+
await this.saveState();
|
|
119
|
+
}
|
|
120
|
+
buildPrompt(task) {
|
|
121
|
+
const parts = [];
|
|
122
|
+
if (this.options.globalContext) {
|
|
123
|
+
parts.push(`## Global Instructions\n${this.options.globalContext}`);
|
|
124
|
+
}
|
|
125
|
+
if (this.options.globalFiles?.length) {
|
|
126
|
+
parts.push(`## Reference Files\n${this.options.globalFiles.map(f => `- ${f}`).join('\n')}`);
|
|
127
|
+
}
|
|
128
|
+
// Add dependency context - reference previous agents' work
|
|
129
|
+
if (task.dependsOn.length > 0) {
|
|
130
|
+
const dependencyInfo = [];
|
|
131
|
+
for (const depId of task.dependsOn) {
|
|
132
|
+
const depTask = this.queue.getTask(depId);
|
|
133
|
+
if (depTask?.result) {
|
|
134
|
+
const branchInfo = depTask.result.branch ? ` (branch: ${depTask.result.branch})` : '';
|
|
135
|
+
const prInfo = depTask.result.pullRequestUrl ? `\n PR: ${depTask.result.pullRequestUrl}` : '';
|
|
136
|
+
dependencyInfo.push(`- **${depTask.name}**${branchInfo}${prInfo}`);
|
|
137
|
+
}
|
|
138
|
+
else if (depTask) {
|
|
139
|
+
dependencyInfo.push(`- **${depTask.name}** (in progress)`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (dependencyInfo.length > 0) {
|
|
143
|
+
parts.push(`## Dependencies\nThis task depends on the following completed tasks:\n${dependencyInfo.join('\n')}\n\nPlease review the work from these dependencies before proceeding. If they created documentation or files, reference those in your work.`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (task.files?.length) {
|
|
147
|
+
parts.push(`## Task-Specific Files\n${task.files.map(f => `- ${f}`).join('\n')}`);
|
|
148
|
+
}
|
|
149
|
+
parts.push(`## Task\n${task.prompt}`);
|
|
150
|
+
if (task.validation) {
|
|
151
|
+
parts.push(`## Validation\nAfter completing the task, verify by running:\n\`${task.validation.command}\`\nExpected output should match: ${task.validation.successPattern}`);
|
|
152
|
+
}
|
|
153
|
+
return parts.join('\n\n');
|
|
154
|
+
}
|
|
155
|
+
handleAgentComplete(agentId, agent) {
|
|
156
|
+
const taskId = this.activeAgents.get(agentId);
|
|
157
|
+
if (!taskId)
|
|
158
|
+
return;
|
|
159
|
+
this.activeAgents.delete(agentId);
|
|
160
|
+
this.clearTimeout(agentId);
|
|
161
|
+
this.queue.markCompleted(taskId, {
|
|
162
|
+
branch: agent.target?.branchName,
|
|
163
|
+
pullRequestUrl: agent.target?.prUrl
|
|
164
|
+
});
|
|
165
|
+
this.trySpawnAgents();
|
|
166
|
+
}
|
|
167
|
+
handleAgentFailed(agentId, error) {
|
|
168
|
+
const taskId = this.activeAgents.get(agentId);
|
|
169
|
+
if (!taskId)
|
|
170
|
+
return;
|
|
171
|
+
this.activeAgents.delete(agentId);
|
|
172
|
+
this.clearTimeout(agentId);
|
|
173
|
+
this.client.stopMonitoring(agentId);
|
|
174
|
+
this.queue.markFailed(taskId, error);
|
|
175
|
+
this.trySpawnAgents();
|
|
176
|
+
}
|
|
177
|
+
clearTimeout(agentId) {
|
|
178
|
+
const timer = this.timeouts.get(agentId);
|
|
179
|
+
if (!timer)
|
|
180
|
+
return;
|
|
181
|
+
clearTimeout(timer);
|
|
182
|
+
this.timeouts.delete(agentId);
|
|
183
|
+
}
|
|
184
|
+
clearAllTimeouts() {
|
|
185
|
+
for (const timer of this.timeouts.values())
|
|
186
|
+
clearTimeout(timer);
|
|
187
|
+
this.timeouts.clear();
|
|
188
|
+
}
|
|
189
|
+
async saveState() {
|
|
190
|
+
if (!this.stateStore)
|
|
191
|
+
return;
|
|
192
|
+
const tasks = this.queue.getAllTasks().map(t => ({
|
|
193
|
+
id: t.id,
|
|
194
|
+
name: t.name,
|
|
195
|
+
status: t.status,
|
|
196
|
+
agentId: t.agentId,
|
|
197
|
+
attempts: t.attempts,
|
|
198
|
+
error: t.error,
|
|
199
|
+
result: t.result,
|
|
200
|
+
}));
|
|
201
|
+
const state = {
|
|
202
|
+
templateName: this.templateName,
|
|
203
|
+
startedAt: new Date().toISOString(),
|
|
204
|
+
updatedAt: new Date().toISOString(),
|
|
205
|
+
repository: this.options.repository,
|
|
206
|
+
tasks,
|
|
207
|
+
activeAgents: Array.from(this.activeAgents.entries()).map(([agentId, taskId]) => ({ agentId, taskId })),
|
|
208
|
+
};
|
|
209
|
+
await this.stateStore.save(state);
|
|
210
|
+
}
|
|
211
|
+
async stop() {
|
|
212
|
+
this.isRunning = false;
|
|
213
|
+
this.client.stopAllMonitoring();
|
|
214
|
+
this.clearAllTimeouts();
|
|
215
|
+
for (const agentId of this.activeAgents.keys()) {
|
|
216
|
+
try {
|
|
217
|
+
await this.client.stopAgent(agentId);
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
// Ignore cancellation errors
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
this.logger.info('Orchestrator stopped');
|
|
224
|
+
this.emit('stopped', this.queue.getStatus());
|
|
225
|
+
}
|
|
226
|
+
getStatus() {
|
|
227
|
+
return {
|
|
228
|
+
isRunning: this.isRunning,
|
|
229
|
+
queue: this.queue.getStatus(),
|
|
230
|
+
activeAgents: Array.from(this.activeAgents.entries()).map(([agentId, taskId]) => ({ agentId, taskId })),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
async sendFollowUp(taskId, message) {
|
|
234
|
+
const task = this.queue.getTask(taskId);
|
|
235
|
+
if (!task?.agentId)
|
|
236
|
+
throw new Error(`No active agent for task ${taskId}`);
|
|
237
|
+
await this.client.sendFollowUp(task.agentId, message);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/core/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
export interface Task {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
prompt: string;
|
|
6
|
+
dependsOn: string[];
|
|
7
|
+
priority: number;
|
|
8
|
+
branch?: string;
|
|
9
|
+
files?: string[];
|
|
10
|
+
timeout?: number;
|
|
11
|
+
retries?: number;
|
|
12
|
+
validation?: {
|
|
13
|
+
command: string;
|
|
14
|
+
successPattern: string;
|
|
15
|
+
};
|
|
16
|
+
complete?: boolean;
|
|
17
|
+
status: TaskStatus;
|
|
18
|
+
agentId?: string;
|
|
19
|
+
attempts: number;
|
|
20
|
+
error?: string;
|
|
21
|
+
result?: TaskResult;
|
|
22
|
+
}
|
|
23
|
+
export type TaskStatus = 'pending' | 'ready' | 'running' | 'completed' | 'failed';
|
|
24
|
+
export interface TaskResult {
|
|
25
|
+
branch?: string;
|
|
26
|
+
pullRequestUrl?: string;
|
|
27
|
+
completedAt: string;
|
|
28
|
+
}
|
|
29
|
+
export type TaskInput = Omit<Task, 'status' | 'attempts' | 'agentId' | 'error' | 'result'>;
|
|
30
|
+
export declare class TaskQueue extends EventEmitter {
|
|
31
|
+
private tasks;
|
|
32
|
+
private completed;
|
|
33
|
+
addTask(input: TaskInput): void;
|
|
34
|
+
addTasks(inputs: TaskInput[]): void;
|
|
35
|
+
private updateReadyTasks;
|
|
36
|
+
getReadyTasks(): Task[];
|
|
37
|
+
getTask(id: string): Task | undefined;
|
|
38
|
+
getAllTasks(): Task[];
|
|
39
|
+
markRunning(id: string, agentId: string): void;
|
|
40
|
+
markCompleted(id: string, result?: Partial<TaskResult>, checkComplete?: boolean): void;
|
|
41
|
+
markFailed(id: string, error: string, maxRetries?: number): void;
|
|
42
|
+
private checkAllComplete;
|
|
43
|
+
getResults(): {
|
|
44
|
+
completed: Task[];
|
|
45
|
+
failed: Task[];
|
|
46
|
+
};
|
|
47
|
+
getStatus(): Record<string, number>;
|
|
48
|
+
reset(): void;
|
|
49
|
+
}
|