@litmers/cursorflow-orchestrator 0.1.5 → 0.1.8

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 (45) hide show
  1. package/CHANGELOG.md +15 -6
  2. package/README.md +33 -2
  3. package/commands/cursorflow-doctor.md +24 -0
  4. package/commands/cursorflow-signal.md +19 -0
  5. package/dist/cli/doctor.d.ts +15 -0
  6. package/dist/cli/doctor.js +139 -0
  7. package/dist/cli/doctor.js.map +1 -0
  8. package/dist/cli/index.js +5 -0
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/cli/monitor.d.ts +1 -1
  11. package/dist/cli/monitor.js +640 -145
  12. package/dist/cli/monitor.js.map +1 -1
  13. package/dist/cli/resume.d.ts +1 -1
  14. package/dist/cli/resume.js +80 -10
  15. package/dist/cli/resume.js.map +1 -1
  16. package/dist/cli/run.js +60 -5
  17. package/dist/cli/run.js.map +1 -1
  18. package/dist/cli/setup-commands.d.ts +4 -0
  19. package/dist/cli/setup-commands.js +16 -0
  20. package/dist/cli/setup-commands.js.map +1 -1
  21. package/dist/cli/signal.d.ts +7 -0
  22. package/dist/cli/signal.js +99 -0
  23. package/dist/cli/signal.js.map +1 -0
  24. package/dist/core/orchestrator.d.ts +4 -2
  25. package/dist/core/orchestrator.js +92 -23
  26. package/dist/core/orchestrator.js.map +1 -1
  27. package/dist/core/runner.d.ts +9 -3
  28. package/dist/core/runner.js +182 -88
  29. package/dist/core/runner.js.map +1 -1
  30. package/dist/utils/doctor.d.ts +63 -0
  31. package/dist/utils/doctor.js +280 -0
  32. package/dist/utils/doctor.js.map +1 -0
  33. package/dist/utils/types.d.ts +3 -0
  34. package/package.json +1 -1
  35. package/src/cli/doctor.ts +127 -0
  36. package/src/cli/index.ts +5 -0
  37. package/src/cli/monitor.ts +693 -185
  38. package/src/cli/resume.ts +94 -12
  39. package/src/cli/run.ts +63 -7
  40. package/src/cli/setup-commands.ts +19 -0
  41. package/src/cli/signal.ts +89 -0
  42. package/src/core/orchestrator.ts +102 -27
  43. package/src/core/runner.ts +203 -99
  44. package/src/utils/doctor.ts +312 -0
  45. package/src/utils/types.ts +3 -0
@@ -90,7 +90,7 @@ function waitChild(proc) {
90
90
  });
91
91
  }
92
92
  /**
93
- * List lane task files in directory
93
+ * List lane task files in directory and load their configs for dependencies
94
94
  */
95
95
  function listLaneFiles(tasksDir) {
96
96
  if (!fs.existsSync(tasksDir)) {
@@ -100,10 +100,23 @@ function listLaneFiles(tasksDir) {
100
100
  return files
101
101
  .filter(f => f.endsWith('.json'))
102
102
  .sort()
103
- .map(f => ({
104
- name: path.basename(f, '.json'),
105
- path: path.join(tasksDir, f),
106
- }));
103
+ .map(f => {
104
+ const filePath = path.join(tasksDir, f);
105
+ const name = path.basename(f, '.json');
106
+ let dependsOn = [];
107
+ try {
108
+ const config = JSON.parse(fs.readFileSync(filePath, 'utf8'));
109
+ dependsOn = config.dependsOn || [];
110
+ }
111
+ catch (e) {
112
+ logger.warn(`Failed to parse config for lane ${name}: ${e}`);
113
+ }
114
+ return {
115
+ name,
116
+ path: filePath,
117
+ dependsOn,
118
+ };
119
+ });
107
120
  }
108
121
  /**
109
122
  * Monitor lane states
@@ -116,7 +129,8 @@ function printLaneStatus(lanes, laneRunDirs) {
116
129
  const statePath = path.join(dir, 'state.json');
117
130
  const state = (0, state_1.loadState)(statePath);
118
131
  if (!state) {
119
- return { lane: lane.name, status: '(no state)', task: '-' };
132
+ const isWaiting = lane.dependsOn.length > 0;
133
+ return { lane: lane.name, status: isWaiting ? 'waiting' : 'pending', task: '-' };
120
134
  }
121
135
  const idx = (state.currentTaskIndex || 0) + 1;
122
136
  return {
@@ -131,7 +145,7 @@ function printLaneStatus(lanes, laneRunDirs) {
131
145
  }
132
146
  }
133
147
  /**
134
- * Run orchestration
148
+ * Run orchestration with dependency management
135
149
  */
136
150
  async function orchestrate(tasksDir, options = {}) {
137
151
  const lanes = listLaneFiles(tasksDir);
@@ -143,31 +157,86 @@ async function orchestrate(tasksDir, options = {}) {
143
157
  const laneRunDirs = {};
144
158
  for (const lane of lanes) {
145
159
  laneRunDirs[lane.name] = path.join(runRoot, 'lanes', lane.name);
160
+ fs.mkdirSync(laneRunDirs[lane.name], { recursive: true });
146
161
  }
147
162
  logger.section('🧭 Starting Orchestration');
148
163
  logger.info(`Tasks directory: ${tasksDir}`);
149
164
  logger.info(`Run directory: ${runRoot}`);
150
165
  logger.info(`Lanes: ${lanes.length}`);
151
- // Spawn all lanes
152
- const running = [];
153
- for (const lane of lanes) {
154
- const { child, logPath } = spawnLane({
155
- laneName: lane.name,
156
- tasksFile: lane.path,
157
- laneRunDir: laneRunDirs[lane.name],
158
- executor: options.executor || 'cursor-agent',
159
- });
160
- running.push({ lane: lane.name, child, logPath });
161
- logger.info(`Lane started: ${lane.name}`);
162
- }
166
+ const maxConcurrent = options.maxConcurrentLanes || 10;
167
+ const running = new Map();
168
+ const exitCodes = {};
169
+ const completedLanes = new Set();
170
+ const failedLanes = new Set();
163
171
  // Monitor lanes
164
172
  const monitorInterval = setInterval(() => {
165
173
  printLaneStatus(lanes, laneRunDirs);
166
174
  }, options.pollInterval || 60000);
167
- // Wait for all lanes
168
- const exitCodes = {};
169
- for (const r of running) {
170
- exitCodes[r.lane] = await waitChild(r.child);
175
+ while (completedLanes.size + failedLanes.size < lanes.length) {
176
+ // 1. Identify lanes ready to start
177
+ const readyToStart = lanes.filter(lane => {
178
+ // Not already running or completed
179
+ if (running.has(lane.name) || completedLanes.has(lane.name) || failedLanes.has(lane.name)) {
180
+ return false;
181
+ }
182
+ // Check dependencies
183
+ for (const dep of lane.dependsOn) {
184
+ if (failedLanes.has(dep)) {
185
+ // If a dependency failed, this lane fails too
186
+ logger.error(`Lane ${lane.name} failed because dependency ${dep} failed`);
187
+ failedLanes.add(lane.name);
188
+ exitCodes[lane.name] = 1;
189
+ return false;
190
+ }
191
+ if (!completedLanes.has(dep)) {
192
+ return false;
193
+ }
194
+ }
195
+ return true;
196
+ });
197
+ // 2. Spawn ready lanes up to maxConcurrent
198
+ for (const lane of readyToStart) {
199
+ if (running.size >= maxConcurrent)
200
+ break;
201
+ logger.info(`Lane started: ${lane.name}`);
202
+ const spawnResult = spawnLane({
203
+ laneName: lane.name,
204
+ tasksFile: lane.path,
205
+ laneRunDir: laneRunDirs[lane.name],
206
+ executor: options.executor || 'cursor-agent',
207
+ });
208
+ running.set(lane.name, spawnResult);
209
+ }
210
+ // 3. Wait for any running lane to finish
211
+ if (running.size > 0) {
212
+ // We need to wait for at least one to finish
213
+ const promises = Array.from(running.entries()).map(async ([name, { child }]) => {
214
+ const code = await waitChild(child);
215
+ return { name, code };
216
+ });
217
+ const finished = await Promise.race(promises);
218
+ running.delete(finished.name);
219
+ exitCodes[finished.name] = finished.code;
220
+ if (finished.code === 0 || finished.code === 2) {
221
+ completedLanes.add(finished.name);
222
+ }
223
+ else {
224
+ failedLanes.add(finished.name);
225
+ }
226
+ printLaneStatus(lanes, laneRunDirs);
227
+ }
228
+ else {
229
+ // Nothing running and nothing ready (but not all finished)
230
+ // This could happen if there's a circular dependency or some logic error
231
+ if (readyToStart.length === 0 && completedLanes.size + failedLanes.size < lanes.length) {
232
+ const remaining = lanes.filter(l => !completedLanes.has(l.name) && !failedLanes.has(l.name));
233
+ logger.error(`Deadlock detected! Remaining lanes cannot start: ${remaining.map(l => l.name).join(', ')}`);
234
+ for (const l of remaining) {
235
+ failedLanes.add(l.name);
236
+ exitCodes[l.name] = 1;
237
+ }
238
+ }
239
+ }
171
240
  }
172
241
  clearInterval(monitorInterval);
173
242
  printLaneStatus(lanes, laneRunDirs);
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/core/orchestrator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/core/orchestrator.ts"],"names":[],"mappings":"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"}
@@ -8,12 +8,16 @@ import { RunnerConfig, Task, TaskExecutionResult, AgentSendResult, DependencyPol
8
8
  * Execute cursor-agent command with timeout and better error handling
9
9
  */
10
10
  export declare function cursorAgentCreateChat(): string;
11
- export declare function cursorAgentSend({ workspaceDir, chatId, prompt, model }: {
11
+ /**
12
+ * Execute cursor-agent command with streaming and better error handling
13
+ */
14
+ export declare function cursorAgentSend({ workspaceDir, chatId, prompt, model, signalDir }: {
12
15
  workspaceDir: string;
13
16
  chatId: string;
14
17
  prompt: string;
15
18
  model?: string;
16
- }): AgentSendResult;
19
+ signalDir?: string;
20
+ }): Promise<AgentSendResult>;
17
21
  /**
18
22
  * Extract dependency change request from agent response
19
23
  */
@@ -46,4 +50,6 @@ export declare function runTask({ task, config, index, worktreeDir, taskBranch,
46
50
  /**
47
51
  * Run all tasks in sequence
48
52
  */
49
- export declare function runTasks(config: RunnerConfig, runDir: string): Promise<TaskExecutionResult[]>;
53
+ export declare function runTasks(tasksFile: string, config: RunnerConfig, runDir: string, options?: {
54
+ startIndex?: number;
55
+ }): Promise<TaskExecutionResult[]>;
@@ -123,7 +123,10 @@ function parseJsonFromStdout(stdout) {
123
123
  }
124
124
  return null;
125
125
  }
126
- function cursorAgentSend({ workspaceDir, chatId, prompt, model }) {
126
+ /**
127
+ * Execute cursor-agent command with streaming and better error handling
128
+ */
129
+ async function cursorAgentSend({ workspaceDir, chatId, prompt, model, signalDir }) {
127
130
  const args = [
128
131
  '--print',
129
132
  '--output-format', 'json',
@@ -133,65 +136,93 @@ function cursorAgentSend({ workspaceDir, chatId, prompt, model }) {
133
136
  prompt,
134
137
  ];
135
138
  logger.info('Executing cursor-agent...');
136
- const res = (0, child_process_1.spawnSync)('cursor-agent', args, {
137
- encoding: 'utf8',
138
- stdio: 'pipe',
139
- timeout: 300000, // 5 minute timeout for LLM response
140
- });
141
- // Check for timeout
142
- if (res.error) {
143
- if (res.error.code === 'ETIMEDOUT') {
144
- return {
139
+ return new Promise((resolve) => {
140
+ const child = (0, child_process_1.spawn)('cursor-agent', args, {
141
+ stdio: ['pipe', 'pipe', 'pipe'], // Enable stdin piping
142
+ env: process.env,
143
+ });
144
+ let fullStdout = '';
145
+ let fullStderr = '';
146
+ // Watch for "intervention.txt" signal file if any
147
+ const interventionPath = signalDir ? path.join(signalDir, 'intervention.txt') : null;
148
+ let interventionWatcher = null;
149
+ if (interventionPath && fs.existsSync(path.dirname(interventionPath))) {
150
+ interventionWatcher = fs.watch(path.dirname(interventionPath), (event, filename) => {
151
+ if (filename === 'intervention.txt' && fs.existsSync(interventionPath)) {
152
+ try {
153
+ const message = fs.readFileSync(interventionPath, 'utf8').trim();
154
+ if (message) {
155
+ logger.info(`Injecting intervention: ${message}`);
156
+ child.stdin.write(message + '\n');
157
+ fs.unlinkSync(interventionPath); // Clear it
158
+ }
159
+ }
160
+ catch (e) {
161
+ logger.warn('Failed to read intervention file');
162
+ }
163
+ }
164
+ });
165
+ }
166
+ child.stdout.on('data', (data) => {
167
+ const str = data.toString();
168
+ fullStdout += str;
169
+ // Also pipe to our own stdout so it goes to terminal.log
170
+ process.stdout.write(data);
171
+ });
172
+ child.stderr.on('data', (data) => {
173
+ fullStderr += data.toString();
174
+ // Pipe to our own stderr so it goes to terminal.log
175
+ process.stderr.write(data);
176
+ });
177
+ const timeout = setTimeout(() => {
178
+ child.kill();
179
+ resolve({
145
180
  ok: false,
146
181
  exitCode: -1,
147
182
  error: 'cursor-agent timed out after 5 minutes. The LLM request may be taking too long or there may be network issues.',
148
- };
149
- }
150
- return {
151
- ok: false,
152
- exitCode: -1,
153
- error: `cursor-agent error: ${res.error.message}`,
154
- };
155
- }
156
- const json = parseJsonFromStdout(res.stdout);
157
- if (res.status !== 0 || !json || json.type !== 'result') {
158
- let errorMsg = res.stderr?.trim() || res.stdout?.trim() || `exit=${res.status}`;
159
- // Check for authentication errors
160
- if (errorMsg.includes('not authenticated') ||
161
- errorMsg.includes('login') ||
162
- errorMsg.includes('auth')) {
163
- errorMsg = 'Authentication error. Please:\n' +
164
- ' 1. Open Cursor IDE\n' +
165
- ' 2. Sign in to your account\n' +
166
- ' 3. Verify AI features are working\n' +
167
- ' 4. Try again\n\n' +
168
- `Details: ${errorMsg}`;
169
- }
170
- // Check for rate limit errors
171
- if (errorMsg.includes('rate limit') || errorMsg.includes('quota')) {
172
- errorMsg = 'API rate limit or quota exceeded. Please:\n' +
173
- ' 1. Check your Cursor subscription\n' +
174
- ' 2. Wait a few minutes and try again\n\n' +
175
- `Details: ${errorMsg}`;
176
- }
177
- // Check for model errors
178
- if (errorMsg.includes('model')) {
179
- errorMsg = `Model error (requested: ${model || 'default'}). ` +
180
- 'Please check if the model is available in your Cursor subscription.\n\n' +
181
- `Details: ${errorMsg}`;
182
- }
183
- return {
184
- ok: false,
185
- exitCode: res.status ?? -1,
186
- error: errorMsg,
187
- };
188
- }
189
- return {
190
- ok: !json.is_error,
191
- exitCode: res.status ?? 0,
192
- sessionId: json.session_id || chatId,
193
- resultText: json.result || '',
194
- };
183
+ });
184
+ }, 300000);
185
+ child.on('close', (code) => {
186
+ clearTimeout(timeout);
187
+ if (interventionWatcher)
188
+ interventionWatcher.close();
189
+ const json = parseJsonFromStdout(fullStdout);
190
+ if (code !== 0 || !json || json.type !== 'result') {
191
+ let errorMsg = fullStderr.trim() || fullStdout.trim() || `exit=${code}`;
192
+ // Check for common errors
193
+ if (errorMsg.includes('not authenticated') || errorMsg.includes('login') || errorMsg.includes('auth')) {
194
+ errorMsg = 'Authentication error. Please sign in to Cursor IDE.';
195
+ }
196
+ else if (errorMsg.includes('rate limit') || errorMsg.includes('quota')) {
197
+ errorMsg = 'API rate limit or quota exceeded.';
198
+ }
199
+ else if (errorMsg.includes('model')) {
200
+ errorMsg = `Model error (requested: ${model || 'default'}). Check your subscription.`;
201
+ }
202
+ resolve({
203
+ ok: false,
204
+ exitCode: code ?? -1,
205
+ error: errorMsg,
206
+ });
207
+ }
208
+ else {
209
+ resolve({
210
+ ok: !json.is_error,
211
+ exitCode: code ?? 0,
212
+ sessionId: json.session_id || chatId,
213
+ resultText: json.result || '',
214
+ });
215
+ }
216
+ });
217
+ child.on('error', (err) => {
218
+ clearTimeout(timeout);
219
+ resolve({
220
+ ok: false,
221
+ exitCode: -1,
222
+ error: `Failed to start cursor-agent: ${err.message}`,
223
+ });
224
+ });
225
+ });
195
226
  }
196
227
  /**
197
228
  * Extract dependency change request from agent response
@@ -293,11 +324,12 @@ async function runTask({ task, config, index, worktreeDir, taskBranch, chatId, r
293
324
  model,
294
325
  }));
295
326
  logger.info('Sending prompt to agent...');
296
- const r1 = cursorAgentSend({
327
+ const r1 = await cursorAgentSend({
297
328
  workspaceDir: worktreeDir,
298
329
  chatId,
299
330
  prompt: prompt1,
300
331
  model,
332
+ signalDir: runDir
301
333
  });
302
334
  (0, state_1.appendLog)(convoPath, (0, state_1.createConversationEntry)('assistant', r1.resultText || r1.error || 'No response', {
303
335
  task: task.name,
@@ -332,7 +364,8 @@ async function runTask({ task, config, index, worktreeDir, taskBranch, chatId, r
332
364
  /**
333
365
  * Run all tasks in sequence
334
366
  */
335
- async function runTasks(config, runDir) {
367
+ async function runTasks(tasksFile, config, runDir, options = {}) {
368
+ const startIndex = options.startIndex || 0;
336
369
  // Ensure cursor-agent is installed
337
370
  (0, cursor_agent_1.ensureCursorAgent)();
338
371
  // Check authentication before starting
@@ -353,37 +386,96 @@ async function runTasks(config, runDir) {
353
386
  }
354
387
  logger.success('✓ Cursor authentication OK');
355
388
  const repoRoot = git.getRepoRoot();
356
- const pipelineBranch = config.pipelineBranch || `${config.branchPrefix || 'cursorflow/'}${Date.now().toString(36)}`;
357
- const worktreeDir = path.join(repoRoot, config.worktreeRoot || '_cursorflow/worktrees', pipelineBranch);
358
- logger.section('🚀 Starting Pipeline');
389
+ // Load existing state if resuming
390
+ const statePath = path.join(runDir, 'state.json');
391
+ let state = null;
392
+ if (startIndex > 0 && fs.existsSync(statePath)) {
393
+ state = JSON.parse(fs.readFileSync(statePath, 'utf8'));
394
+ }
395
+ const pipelineBranch = state?.pipelineBranch || config.pipelineBranch || `${config.branchPrefix || 'cursorflow/'}${Date.now().toString(36)}`;
396
+ const worktreeDir = state?.worktreeDir || path.join(repoRoot, config.worktreeRoot || '_cursorflow/worktrees', pipelineBranch);
397
+ if (startIndex === 0) {
398
+ logger.section('🚀 Starting Pipeline');
399
+ }
400
+ else {
401
+ logger.section(`🔁 Resuming Pipeline from task ${startIndex + 1}`);
402
+ }
359
403
  logger.info(`Pipeline Branch: ${pipelineBranch}`);
360
404
  logger.info(`Worktree: ${worktreeDir}`);
361
405
  logger.info(`Tasks: ${config.tasks.length}`);
362
- // Create worktree
363
- git.createWorktree(worktreeDir, pipelineBranch, {
364
- baseBranch: config.baseBranch || 'main',
365
- cwd: repoRoot,
366
- });
406
+ // Create worktree only if starting fresh
407
+ if (startIndex === 0 || !fs.existsSync(worktreeDir)) {
408
+ git.createWorktree(worktreeDir, pipelineBranch, {
409
+ baseBranch: config.baseBranch || 'main',
410
+ cwd: repoRoot,
411
+ });
412
+ }
367
413
  // Create chat
368
414
  logger.info('Creating chat session...');
369
415
  const chatId = cursorAgentCreateChat();
370
- // Save initial state
371
- const state = {
372
- status: 'running',
373
- pipelineBranch,
374
- worktreeDir,
375
- totalTasks: config.tasks.length,
376
- currentTaskIndex: 0,
377
- label: pipelineBranch,
378
- startTime: Date.now(),
379
- endTime: null,
380
- error: null,
381
- dependencyRequest: null,
382
- };
383
- (0, state_1.saveState)(path.join(runDir, 'state.json'), state);
416
+ // Initialize state if not loaded
417
+ if (!state) {
418
+ state = {
419
+ status: 'running',
420
+ pipelineBranch,
421
+ worktreeDir,
422
+ totalTasks: config.tasks.length,
423
+ currentTaskIndex: 0,
424
+ label: pipelineBranch,
425
+ startTime: Date.now(),
426
+ endTime: null,
427
+ error: null,
428
+ dependencyRequest: null,
429
+ tasksFile, // Store tasks file for resume
430
+ dependsOn: config.dependsOn || [],
431
+ };
432
+ }
433
+ else {
434
+ state.status = 'running';
435
+ state.error = null;
436
+ state.dependencyRequest = null;
437
+ state.dependsOn = config.dependsOn || [];
438
+ }
439
+ (0, state_1.saveState)(statePath, state);
440
+ // Merge dependencies if any
441
+ if (startIndex === 0 && config.dependsOn && config.dependsOn.length > 0) {
442
+ logger.section('🔗 Merging Dependencies');
443
+ // The runDir for the lane is passed in. Dependencies are in ../<depName> relative to this runDir
444
+ const lanesRoot = path.dirname(runDir);
445
+ for (const depName of config.dependsOn) {
446
+ const depRunDir = path.join(lanesRoot, depName);
447
+ const depStatePath = path.join(depRunDir, 'state.json');
448
+ if (!fs.existsSync(depStatePath)) {
449
+ logger.warn(`Dependency state not found for ${depName} at ${depStatePath}`);
450
+ continue;
451
+ }
452
+ try {
453
+ const depState = JSON.parse(fs.readFileSync(depStatePath, 'utf8'));
454
+ if (depState.status !== 'completed') {
455
+ logger.warn(`Dependency ${depName} is in status ${depState.status}, merge might be incomplete`);
456
+ }
457
+ if (depState.pipelineBranch) {
458
+ logger.info(`Merging dependency branch: ${depState.pipelineBranch} (${depName})`);
459
+ // Fetch first to ensure we have the branch
460
+ git.runGit(['fetch', 'origin', depState.pipelineBranch], { cwd: worktreeDir, silent: true });
461
+ // Merge
462
+ git.merge(depState.pipelineBranch, {
463
+ cwd: worktreeDir,
464
+ noFf: true,
465
+ message: `chore: merge dependency ${depName} (${depState.pipelineBranch})`
466
+ });
467
+ }
468
+ }
469
+ catch (e) {
470
+ logger.error(`Failed to merge dependency ${depName}: ${e}`);
471
+ }
472
+ }
473
+ // Push the merged state
474
+ git.push(pipelineBranch, { cwd: worktreeDir });
475
+ }
384
476
  // Run tasks
385
477
  const results = [];
386
- for (let i = 0; i < config.tasks.length; i++) {
478
+ for (let i = startIndex; i < config.tasks.length; i++) {
387
479
  const task = config.tasks[i];
388
480
  const taskBranch = `${pipelineBranch}--${String(i + 1).padStart(2, '0')}-${task.name}`;
389
481
  const result = await runTask({
@@ -399,19 +491,19 @@ async function runTasks(config, runDir) {
399
491
  results.push(result);
400
492
  // Update state
401
493
  state.currentTaskIndex = i + 1;
402
- (0, state_1.saveState)(path.join(runDir, 'state.json'), state);
494
+ (0, state_1.saveState)(statePath, state);
403
495
  // Handle blocked or error
404
496
  if (result.status === 'BLOCKED_DEPENDENCY') {
405
- state.status = 'failed'; // Or blocked if we had a blocked status in LaneState
497
+ state.status = 'failed';
406
498
  state.dependencyRequest = result.dependencyRequest || null;
407
- (0, state_1.saveState)(path.join(runDir, 'state.json'), state);
499
+ (0, state_1.saveState)(statePath, state);
408
500
  logger.warn('Task blocked on dependency change');
409
501
  process.exit(2);
410
502
  }
411
503
  if (result.status !== 'FINISHED') {
412
504
  state.status = 'failed';
413
505
  state.error = result.error || 'Unknown error';
414
- (0, state_1.saveState)(path.join(runDir, 'state.json'), state);
506
+ (0, state_1.saveState)(statePath, state);
415
507
  logger.error(`Task failed: ${result.error}`);
416
508
  process.exit(1);
417
509
  }
@@ -423,7 +515,7 @@ async function runTasks(config, runDir) {
423
515
  // Complete
424
516
  state.status = 'completed';
425
517
  state.endTime = Date.now();
426
- (0, state_1.saveState)(path.join(runDir, 'state.json'), state);
518
+ (0, state_1.saveState)(statePath, state);
427
519
  logger.success('All tasks completed!');
428
520
  return results;
429
521
  }
@@ -438,8 +530,10 @@ if (require.main === module) {
438
530
  }
439
531
  const tasksFile = args[0];
440
532
  const runDirIdx = args.indexOf('--run-dir');
533
+ const startIdxIdx = args.indexOf('--start-index');
441
534
  // const executorIdx = args.indexOf('--executor');
442
535
  const runDir = runDirIdx >= 0 ? args[runDirIdx + 1] : '.';
536
+ const startIndex = startIdxIdx >= 0 ? parseInt(args[startIdxIdx + 1] || '0') : 0;
443
537
  // const executor = executorIdx >= 0 ? args[executorIdx + 1] : 'cursor-agent';
444
538
  if (!fs.existsSync(tasksFile)) {
445
539
  console.error(`Tasks file not found: ${tasksFile}`);
@@ -460,7 +554,7 @@ if (require.main === module) {
460
554
  lockfileReadOnly: true,
461
555
  };
462
556
  // Run tasks
463
- runTasks(config, runDir)
557
+ runTasks(tasksFile, config, runDir, { startIndex })
464
558
  .then(() => {
465
559
  process.exit(0);
466
560
  })