@litmers/cursorflow-orchestrator 0.1.13 → 0.1.15

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 (76) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +83 -2
  3. package/commands/cursorflow-clean.md +20 -6
  4. package/commands/cursorflow-prepare.md +1 -1
  5. package/commands/cursorflow-resume.md +127 -6
  6. package/commands/cursorflow-run.md +2 -2
  7. package/commands/cursorflow-signal.md +11 -4
  8. package/dist/cli/clean.js +164 -12
  9. package/dist/cli/clean.js.map +1 -1
  10. package/dist/cli/index.d.ts +1 -0
  11. package/dist/cli/index.js +6 -1
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/cli/logs.d.ts +8 -0
  14. package/dist/cli/logs.js +759 -0
  15. package/dist/cli/logs.js.map +1 -0
  16. package/dist/cli/monitor.js +113 -30
  17. package/dist/cli/monitor.js.map +1 -1
  18. package/dist/cli/prepare.js +1 -1
  19. package/dist/cli/resume.js +367 -18
  20. package/dist/cli/resume.js.map +1 -1
  21. package/dist/cli/run.js +9 -0
  22. package/dist/cli/run.js.map +1 -1
  23. package/dist/cli/signal.js +34 -20
  24. package/dist/cli/signal.js.map +1 -1
  25. package/dist/core/orchestrator.d.ts +13 -1
  26. package/dist/core/orchestrator.js +396 -35
  27. package/dist/core/orchestrator.js.map +1 -1
  28. package/dist/core/reviewer.d.ts +2 -0
  29. package/dist/core/reviewer.js +24 -2
  30. package/dist/core/reviewer.js.map +1 -1
  31. package/dist/core/runner.d.ts +9 -3
  32. package/dist/core/runner.js +266 -61
  33. package/dist/core/runner.js.map +1 -1
  34. package/dist/utils/config.js +38 -1
  35. package/dist/utils/config.js.map +1 -1
  36. package/dist/utils/enhanced-logger.d.ts +210 -0
  37. package/dist/utils/enhanced-logger.js +1030 -0
  38. package/dist/utils/enhanced-logger.js.map +1 -0
  39. package/dist/utils/events.d.ts +59 -0
  40. package/dist/utils/events.js +37 -0
  41. package/dist/utils/events.js.map +1 -0
  42. package/dist/utils/git.d.ts +11 -0
  43. package/dist/utils/git.js +40 -0
  44. package/dist/utils/git.js.map +1 -1
  45. package/dist/utils/logger.d.ts +2 -0
  46. package/dist/utils/logger.js +4 -1
  47. package/dist/utils/logger.js.map +1 -1
  48. package/dist/utils/types.d.ts +132 -1
  49. package/dist/utils/webhook.d.ts +5 -0
  50. package/dist/utils/webhook.js +109 -0
  51. package/dist/utils/webhook.js.map +1 -0
  52. package/examples/README.md +1 -1
  53. package/package.json +2 -1
  54. package/scripts/patches/test-cursor-agent.js +1 -1
  55. package/scripts/simple-logging-test.sh +97 -0
  56. package/scripts/test-real-cursor-lifecycle.sh +289 -0
  57. package/scripts/test-real-logging.sh +289 -0
  58. package/scripts/test-streaming-multi-task.sh +247 -0
  59. package/src/cli/clean.ts +170 -13
  60. package/src/cli/index.ts +4 -1
  61. package/src/cli/logs.ts +863 -0
  62. package/src/cli/monitor.ts +123 -30
  63. package/src/cli/prepare.ts +1 -1
  64. package/src/cli/resume.ts +463 -22
  65. package/src/cli/run.ts +10 -0
  66. package/src/cli/signal.ts +43 -27
  67. package/src/core/orchestrator.ts +458 -36
  68. package/src/core/reviewer.ts +40 -4
  69. package/src/core/runner.ts +293 -60
  70. package/src/utils/config.ts +41 -1
  71. package/src/utils/enhanced-logger.ts +1166 -0
  72. package/src/utils/events.ts +117 -0
  73. package/src/utils/git.ts +40 -0
  74. package/src/utils/logger.ts +4 -1
  75. package/src/utils/types.ts +160 -1
  76. package/src/utils/webhook.ts +85 -0
@@ -41,7 +41,8 @@ enum View {
41
41
  MESSAGE_DETAIL,
42
42
  FLOW,
43
43
  TERMINAL,
44
- INTERVENE
44
+ INTERVENE,
45
+ TIMEOUT
45
46
  }
46
47
 
47
48
  class InteractiveMonitor {
@@ -58,6 +59,7 @@ class InteractiveMonitor {
58
59
  private terminalScrollOffset: number = 0;
59
60
  private lastTerminalTotalLines: number = 0;
60
61
  private interventionInput: string = '';
62
+ private timeoutInput: string = '';
61
63
  private notification: { message: string; type: 'info' | 'error' | 'success'; time: number } | null = null;
62
64
 
63
65
  constructor(runDir: string, interval: number) {
@@ -96,7 +98,9 @@ class InteractiveMonitor {
96
98
  this.handleTerminalKey(keyName);
97
99
  } else if (this.view === View.INTERVENE) {
98
100
  this.handleInterveneKey(str, key);
99
- } else {
101
+ } else if (this.view === View.TIMEOUT) {
102
+ this.handleTimeoutKey(str, key);
103
+ } else if (this.view === View.MESSAGE_DETAIL) {
100
104
  this.handleMessageDetailKey(keyName);
101
105
  }
102
106
  });
@@ -182,9 +186,20 @@ class InteractiveMonitor {
182
186
  this.interventionInput = '';
183
187
  this.render();
184
188
  } else {
185
- // Show a temporary message that it's only for running lanes
186
- console.log(`\n\x1b[31m Intervention is only available for RUNNING lanes.\x1b[0m`);
187
- setTimeout(() => this.render(), 1500);
189
+ this.showNotification('Intervention only available for RUNNING lanes', 'error');
190
+ }
191
+ }
192
+ break;
193
+ case 'o':
194
+ const timeoutLane = this.lanes.find(l => l.name === this.selectedLaneName);
195
+ if (timeoutLane) {
196
+ const status = this.getLaneStatus(timeoutLane.path, timeoutLane.name);
197
+ if (status.status === 'running') {
198
+ this.view = View.TIMEOUT;
199
+ this.timeoutInput = '';
200
+ this.render();
201
+ } else {
202
+ this.showNotification('Timeout update only available for RUNNING lanes', 'error');
188
203
  }
189
204
  }
190
205
  break;
@@ -244,44 +259,60 @@ class InteractiveMonitor {
244
259
  }
245
260
 
246
261
  private handleInterveneKey(str: string, key: any) {
247
- if (key.name === 'return' || key.name === 'enter') {
262
+ if (key && key.name === 'escape') {
263
+ this.view = View.LANE_DETAIL;
264
+ this.render();
265
+ return;
266
+ }
267
+
268
+ if (key && (key.name === 'return' || key.name === 'enter')) {
248
269
  if (this.interventionInput.trim()) {
249
270
  this.sendIntervention(this.interventionInput.trim());
250
271
  }
251
272
  this.view = View.LANE_DETAIL;
252
273
  this.render();
253
- } else if (key.name === 'escape') {
254
- this.view = View.LANE_DETAIL;
255
- this.render();
256
- } else if (key.name === 'backspace') {
274
+ return;
275
+ }
276
+
277
+ if (key && key.name === 'backspace') {
257
278
  this.interventionInput = this.interventionInput.slice(0, -1);
258
279
  this.render();
259
- } else if (str && str.length === 1) {
280
+ return;
281
+ }
282
+
283
+ if (str && str.length === 1 && !key.ctrl && !key.meta) {
260
284
  this.interventionInput += str;
261
285
  this.render();
262
286
  }
263
287
  }
264
288
 
265
- private sendIntervention(message: string) {
266
- if (!this.selectedLaneName) return;
267
- const lane = this.lanes.find(l => l.name === this.selectedLaneName);
268
- if (!lane) return;
289
+ private handleTimeoutKey(str: string, key: any) {
290
+ if (key && key.name === 'escape') {
291
+ this.view = View.LANE_DETAIL;
292
+ this.render();
293
+ return;
294
+ }
269
295
 
270
- // Write to intervention.txt which runner.ts is watching
271
- const interventionPath = path.join(path.dirname(lane.path), 'intervention.txt');
272
- fs.writeFileSync(interventionPath, message, 'utf8');
296
+ if (key && (key.name === 'return' || key.name === 'enter')) {
297
+ if (this.timeoutInput.trim()) {
298
+ this.sendTimeoutUpdate(this.timeoutInput.trim());
299
+ }
300
+ this.view = View.LANE_DETAIL;
301
+ this.render();
302
+ return;
303
+ }
273
304
 
274
- // Also log it to the conversation
275
- const convoPath = path.join(lane.path, 'conversation.jsonl');
276
- const entry = {
277
- timestamp: new Date().toISOString(),
278
- role: 'user',
279
- task: 'INTERVENTION',
280
- fullText: `[HUMAN INTERVENTION]: ${message}`,
281
- textLength: message.length + 20,
282
- model: 'manual'
283
- };
284
- fs.appendFileSync(convoPath, JSON.stringify(entry) + '\n', 'utf8');
305
+ if (key && key.name === 'backspace') {
306
+ this.timeoutInput = this.timeoutInput.slice(0, -1);
307
+ this.render();
308
+ return;
309
+ }
310
+
311
+ // Only allow numbers
312
+ if (str && /^\d$/.test(str)) {
313
+ this.timeoutInput += str;
314
+ this.render();
315
+ }
285
316
  }
286
317
 
287
318
  private handleFlowKey(key: string) {
@@ -302,6 +333,54 @@ class InteractiveMonitor {
302
333
  }
303
334
  }
304
335
 
336
+ private sendIntervention(message: string) {
337
+ if (!this.selectedLaneName) return;
338
+ const lane = this.lanes.find(l => l.name === this.selectedLaneName);
339
+ if (!lane) return;
340
+
341
+ try {
342
+ const interventionPath = path.join(lane.path, 'intervention.txt');
343
+ fs.writeFileSync(interventionPath, message, 'utf8');
344
+
345
+ // Also log it to the conversation
346
+ const convoPath = path.join(lane.path, 'conversation.jsonl');
347
+ const entry = {
348
+ timestamp: new Date().toISOString(),
349
+ role: 'user',
350
+ task: 'INTERVENTION',
351
+ fullText: `[HUMAN INTERVENTION]: ${message}`,
352
+ textLength: message.length + 20,
353
+ model: 'manual'
354
+ };
355
+ fs.appendFileSync(convoPath, JSON.stringify(entry) + '\n', 'utf8');
356
+
357
+ this.showNotification('Intervention message sent', 'success');
358
+ } catch (e) {
359
+ this.showNotification('Failed to send intervention', 'error');
360
+ }
361
+ }
362
+
363
+ private sendTimeoutUpdate(timeoutStr: string) {
364
+ if (!this.selectedLaneName) return;
365
+ const lane = this.lanes.find(l => l.name === this.selectedLaneName);
366
+ if (!lane) return;
367
+
368
+ try {
369
+ const timeoutMs = parseInt(timeoutStr);
370
+ if (isNaN(timeoutMs) || timeoutMs <= 0) {
371
+ this.showNotification('Invalid timeout value', 'error');
372
+ return;
373
+ }
374
+
375
+ const timeoutPath = path.join(lane.path, 'timeout.txt');
376
+ fs.writeFileSync(timeoutPath, String(timeoutMs), 'utf8');
377
+
378
+ this.showNotification(`Timeout updated to ${Math.round(timeoutMs/1000)}s`, 'success');
379
+ } catch (e) {
380
+ this.showNotification('Failed to update timeout', 'error');
381
+ }
382
+ }
383
+
305
384
  private refreshLogs() {
306
385
  if (!this.selectedLaneName) return;
307
386
  const lane = this.lanes.find(l => l.name === this.selectedLaneName);
@@ -378,6 +457,9 @@ class InteractiveMonitor {
378
457
  case View.INTERVENE:
379
458
  this.renderIntervene();
380
459
  break;
460
+ case View.TIMEOUT:
461
+ this.renderTimeout();
462
+ break;
381
463
  }
382
464
  }
383
465
 
@@ -460,7 +542,7 @@ class InteractiveMonitor {
460
542
 
461
543
  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
462
544
  console.log(`🔍 Lane: ${lane.name}`);
463
- console.log(`🕒 Updated: ${new Date().toLocaleTimeString()} | [↑/↓/→] Browse History [Esc/←] Back`);
545
+ console.log(`🕒 Updated: ${new Date().toLocaleTimeString()} | [↑/↓] Browse [T] Term [I] Intervene [O] Timeout [Esc] Back`);
464
546
  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
465
547
 
466
548
  process.stdout.write(` Status: ${this.getStatusIcon(status.status)} ${status.status}\n`);
@@ -659,6 +741,17 @@ class InteractiveMonitor {
659
741
  console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
660
742
  }
661
743
 
744
+ private renderTimeout() {
745
+ console.clear();
746
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
747
+ console.log(`⏱ UPDATE TIMEOUT: ${this.selectedLaneName}`);
748
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
749
+ console.log('\n Enter new timeout in milliseconds (e.g., 600000 for 10 minutes).');
750
+ console.log(` Press \x1b[1mENTER\x1b[0m to apply, \x1b[1mESC\x1b[0m to cancel.\n`);
751
+ console.log(`\x1b[33m > \x1b[0m${this.timeoutInput}\x1b[37m█\x1b[0m`);
752
+ console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
753
+ }
754
+
662
755
  private listLanesWithDeps(runDir: string): LaneWithDeps[] {
663
756
  const lanesDir = path.join(runDir, 'lanes');
664
757
  if (!fs.existsSync(lanesDir)) return [];
@@ -515,7 +515,7 @@ function getDefaultConfig(laneNumber: number, featureName: string, tasks: Task[]
515
515
  branchPrefix: `${featureName.toLowerCase()}/lane-${laneNumber}-`,
516
516
 
517
517
  // Execution Settings
518
- timeout: 300000,
518
+ timeout: 600000,
519
519
  enableIntervention: false,
520
520
 
521
521
  // Dependency Policy