@litmers/cursorflow-orchestrator 0.1.8 → 0.1.12

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 (66) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +113 -319
  3. package/commands/cursorflow-clean.md +24 -135
  4. package/commands/cursorflow-doctor.md +74 -18
  5. package/commands/cursorflow-init.md +33 -50
  6. package/commands/cursorflow-models.md +51 -0
  7. package/commands/cursorflow-monitor.md +56 -118
  8. package/commands/cursorflow-prepare.md +410 -108
  9. package/commands/cursorflow-resume.md +51 -148
  10. package/commands/cursorflow-review.md +38 -202
  11. package/commands/cursorflow-run.md +208 -86
  12. package/commands/cursorflow-signal.md +38 -12
  13. package/dist/cli/clean.d.ts +3 -1
  14. package/dist/cli/clean.js +145 -8
  15. package/dist/cli/clean.js.map +1 -1
  16. package/dist/cli/doctor.js +14 -1
  17. package/dist/cli/doctor.js.map +1 -1
  18. package/dist/cli/index.js +32 -21
  19. package/dist/cli/index.js.map +1 -1
  20. package/dist/cli/init.js +5 -4
  21. package/dist/cli/init.js.map +1 -1
  22. package/dist/cli/models.d.ts +7 -0
  23. package/dist/cli/models.js +104 -0
  24. package/dist/cli/models.js.map +1 -0
  25. package/dist/cli/monitor.js +56 -1
  26. package/dist/cli/monitor.js.map +1 -1
  27. package/dist/cli/prepare.d.ts +7 -0
  28. package/dist/cli/prepare.js +748 -0
  29. package/dist/cli/prepare.js.map +1 -0
  30. package/dist/cli/resume.js +56 -0
  31. package/dist/cli/resume.js.map +1 -1
  32. package/dist/cli/run.js +30 -1
  33. package/dist/cli/run.js.map +1 -1
  34. package/dist/cli/signal.js +18 -0
  35. package/dist/cli/signal.js.map +1 -1
  36. package/dist/core/runner.d.ts +9 -1
  37. package/dist/core/runner.js +139 -23
  38. package/dist/core/runner.js.map +1 -1
  39. package/dist/utils/cursor-agent.d.ts +4 -0
  40. package/dist/utils/cursor-agent.js +58 -10
  41. package/dist/utils/cursor-agent.js.map +1 -1
  42. package/dist/utils/doctor.d.ts +10 -0
  43. package/dist/utils/doctor.js +581 -1
  44. package/dist/utils/doctor.js.map +1 -1
  45. package/dist/utils/types.d.ts +11 -0
  46. package/examples/README.md +114 -59
  47. package/examples/demo-project/README.md +61 -79
  48. package/examples/demo-project/_cursorflow/tasks/demo-test/01-create-utils.json +17 -6
  49. package/examples/demo-project/_cursorflow/tasks/demo-test/02-add-tests.json +17 -6
  50. package/examples/demo-project/_cursorflow/tasks/demo-test/README.md +66 -25
  51. package/package.json +1 -1
  52. package/scripts/patches/test-cursor-agent.js +203 -0
  53. package/src/cli/clean.ts +156 -9
  54. package/src/cli/doctor.ts +18 -2
  55. package/src/cli/index.ts +33 -21
  56. package/src/cli/init.ts +6 -4
  57. package/src/cli/models.ts +83 -0
  58. package/src/cli/monitor.ts +60 -1
  59. package/src/cli/prepare.ts +844 -0
  60. package/src/cli/resume.ts +66 -0
  61. package/src/cli/run.ts +36 -2
  62. package/src/cli/signal.ts +22 -0
  63. package/src/core/runner.ts +164 -23
  64. package/src/utils/cursor-agent.ts +62 -10
  65. package/src/utils/doctor.ts +633 -5
  66. package/src/utils/types.ts +11 -0
package/src/cli/index.ts CHANGED
@@ -7,58 +7,70 @@ import * as logger from '../utils/logger';
7
7
  // Command functions signature
8
8
  type CommandFn = (args: string[]) => Promise<void>;
9
9
 
10
- // Lazy load commands to speed up help/version output
10
+ /**
11
+ * Command Registry
12
+ */
11
13
  const COMMANDS: Record<string, CommandFn> = {
12
14
  init: require('./init'),
15
+ prepare: require('./prepare'),
13
16
  run: require('./run'),
14
17
  monitor: require('./monitor'),
15
18
  clean: require('./clean'),
16
19
  resume: require('./resume'),
17
20
  doctor: require('./doctor'),
18
21
  signal: require('./signal'),
22
+ models: require('./models'),
23
+ setup: require('./setup-commands').main,
24
+ 'setup-commands': require('./setup-commands').main,
19
25
  };
20
26
 
21
27
  function printHelp(): void {
22
28
  console.log(`
23
- CursorFlow - Git worktree-based parallel AI agent orchestration
29
+ \x1b[1m\x1b[36mCursorFlow\x1b[0m - Git worktree-based parallel AI agent orchestration
24
30
 
25
- Usage: cursorflow <command> [options]
31
+ \x1b[1mUSAGE\x1b[0m
32
+ $ \x1b[32mcursorflow\x1b[0m <command> [options]
26
33
 
27
- Commands:
28
- init [options] Initialize CursorFlow in project
29
- run <tasks-dir> [options] Run orchestration
30
- monitor [run-dir] [options] Monitor lane execution
31
- clean <type> [options] Clean branches/worktrees/logs
32
- resume <lane> [options] Resume interrupted lane
33
- doctor [options] Check environment and preflight
34
- signal <lane> <msg> Directly intervene in a running lane
34
+ \x1b[1mCOMMANDS\x1b[0m
35
+ \x1b[33minit\x1b[0m [options] Initialize CursorFlow in project
36
+ \x1b[33mprepare\x1b[0m <feature> [opts] Prepare task directory and JSON files
37
+ \x1b[33mrun\x1b[0m <tasks-dir> [options] Run orchestration (DAG-based)
38
+ \x1b[33mmonitor\x1b[0m [run-dir] [options] \x1b[36mInteractive\x1b[0m lane dashboard
39
+ \x1b[33mclean\x1b[0m <type> [options] Clean branches/worktrees/logs
40
+ \x1b[33mresume\x1b[0m <lane> [options] Resume interrupted lane
41
+ \x1b[33mdoctor\x1b[0m [options] Check environment and preflight
42
+ \x1b[33msignal\x1b[0m <lane> <msg> Directly intervene in a running lane
43
+ \x1b[33mmodels\x1b[0m [options] List available AI models
35
44
 
36
- Global Options:
45
+ \x1b[1mGLOBAL OPTIONS\x1b[0m
37
46
  --config <path> Config file path
38
47
  --help, -h Show help
39
48
  --version, -v Show version
40
49
 
41
- Examples:
42
- cursorflow init --example
43
- cursorflow run _cursorflow/tasks/MyFeature/
44
- cursorflow monitor --watch
45
- cursorflow clean branches --all
46
- cursorflow doctor
50
+ \x1b[1mEXAMPLES\x1b[0m
51
+ $ \x1b[32mcursorflow init --example\x1b[0m
52
+ $ \x1b[32mcursorflow prepare NewFeature --lanes 3\x1b[0m
53
+ $ \x1b[32mcursorflow run _cursorflow/tasks/MyFeature/\x1b[0m
54
+ $ \x1b[32mcursorflow monitor latest\x1b[0m
55
+ $ \x1b[32mcursorflow models\x1b[0m
47
56
 
48
- Documentation:
57
+ \x1b[1mDOCUMENTATION\x1b[0m
49
58
  https://github.com/eungjin-cigro/cursorflow#readme
50
59
  `);
51
60
  }
52
61
 
53
62
  function printVersion(): void {
54
63
  const pkg = require('../../package.json');
55
- console.log(`CursorFlow v${pkg.version}`);
64
+ console.log(`\x1b[1m\x1b[36mCursorFlow\x1b[0m v${pkg.version}`);
56
65
  }
57
66
 
58
67
  async function main(): Promise<void> {
59
68
  const args = process.argv.slice(2);
60
69
 
61
- if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
70
+ // Only show global help if no arguments provided or if first argument is help-related
71
+ const isGlobalHelp = args.length === 0 || args[0] === 'help' || (args.length === 1 && (args[0] === '--help' || args[0] === '-h'));
72
+
73
+ if (isGlobalHelp) {
62
74
  printHelp();
63
75
  return;
64
76
  }
package/src/cli/init.ts CHANGED
@@ -291,15 +291,17 @@ async function init(args: string[]): Promise<void> {
291
291
  logger.section('āœ… CursorFlow initialized successfully!');
292
292
 
293
293
  console.log('\nšŸ“š Next steps:\n');
294
- console.log(' 1. Review cursorflow.config.js');
295
- console.log(' 2. Type "/" in Cursor IDE to see available commands');
294
+ console.log(' 1. Review \x1b[32mcursorflow.config.js\x1b[0m');
295
+ console.log(' 2. Type \x1b[33m"/"\x1b[0m in Cursor IDE to see available commands');
296
296
 
297
297
  if (options.example) {
298
- console.log(` 3. Run: cursorflow run ${config.tasksDir}/example/`);
298
+ console.log(` 3. Run: \x1b[32mcursorflow run ${config.tasksDir}/example/\x1b[0m`);
299
299
  } else {
300
- console.log(' 3. Create tasks with: cursorflow prepare MyFeature');
300
+ console.log(' 3. Create your first task: \x1b[32mcursorflow prepare MyFeature\x1b[0m');
301
301
  }
302
302
 
303
+ console.log('\nšŸ’” Tip: Use \x1b[33mcursorflow models\x1b[0m to see available AI models.');
304
+
303
305
  console.log('\nšŸ“– Documentation:');
304
306
  console.log(' https://github.com/eungjin-cigro/cursorflow#readme');
305
307
  console.log('');
@@ -0,0 +1,83 @@
1
+ /**
2
+ * CursorFlow models command
3
+ *
4
+ * List available models
5
+ */
6
+
7
+ import * as logger from '../utils/logger';
8
+ import { getAvailableModels } from '../utils/cursor-agent';
9
+
10
+ /**
11
+ * Model details metadata
12
+ */
13
+ const MODEL_METADATA: Record<string, { name: string; provider: string; description: string }> = {
14
+ 'sonnet-4.5': { name: 'Claude 3.7 Sonnet', provider: 'Anthropic', description: 'General implementation, fast work (Most versatile)' },
15
+ 'sonnet-4.5-thinking': { name: 'Claude 3.7 Sonnet (Thinking)', provider: 'Anthropic', description: 'Code review, deeper reasoning (Thinking model)' },
16
+ 'opus-4.5': { name: 'Claude 4.0 Opus', provider: 'Anthropic', description: 'Complex tasks, high quality (Advanced)' },
17
+ 'opus-4.5-thinking': { name: 'Claude 4.0 Opus (Thinking)', provider: 'Anthropic', description: 'Architecture design (Premium)' },
18
+ 'gpt-5.2': { name: 'GPT-5.2', provider: 'OpenAI', description: 'General tasks' },
19
+ 'gpt-5.2-high': { name: 'GPT-5.2 High Reasoning', provider: 'OpenAI', description: 'Advanced reasoning (High performance)' },
20
+ 'gemini-3-flash': { name: 'Gemini 3 Flash', provider: 'Google', description: 'General tasks' },
21
+ 'gemini-3-pro': { name: 'Gemini 3 Pro', provider: 'Google', description: 'Advanced reasoning (High performance)' }
22
+ };
23
+
24
+ function printHelp(): void {
25
+ console.log(`
26
+ Usage: cursorflow models [options]
27
+
28
+ List available AI models for use in tasks.
29
+
30
+ Options:
31
+ --list, -l List models in a table (default)
32
+ --json Output as JSON
33
+ --help, -h Show help
34
+
35
+ Examples:
36
+ cursorflow models
37
+ cursorflow models --json
38
+ `);
39
+ }
40
+
41
+ async function models(args: string[]): Promise<void> {
42
+ const isJson = args.includes('--json');
43
+ const isHelp = args.includes('--help') || args.includes('-h');
44
+
45
+ if (isHelp) {
46
+ printHelp();
47
+ return;
48
+ }
49
+
50
+ // Fetch available models from cursor-agent
51
+ const availableModelIds = getAvailableModels();
52
+
53
+ const modelsData = availableModelIds.map(id => {
54
+ const meta = MODEL_METADATA[id] || {
55
+ name: id,
56
+ provider: 'Unknown',
57
+ description: 'Discovered via cursor-agent'
58
+ };
59
+ return { id, ...meta };
60
+ });
61
+
62
+ if (isJson) {
63
+ console.log(JSON.stringify(modelsData, null, 2));
64
+ return;
65
+ }
66
+
67
+ logger.section('šŸ¤– Available AI Models (from cursor-agent)');
68
+
69
+ const maxIdLen = Math.max(...modelsData.map(m => m.id.length), 10);
70
+ const maxNameLen = Math.max(...modelsData.map(m => m.name.length), 15);
71
+ const maxProviderLen = Math.max(...modelsData.map(m => m.provider.length), 10);
72
+
73
+ console.log(` ${'ID'.padEnd(maxIdLen)} ${'Name'.padEnd(maxNameLen)} ${'Provider'.padEnd(maxProviderLen)} Description`);
74
+ console.log(` ${'─'.repeat(maxIdLen)} ${'─'.repeat(maxNameLen)} ${'─'.repeat(maxProviderLen)} ${'─'.repeat(30)}`);
75
+
76
+ for (const m of modelsData) {
77
+ console.log(` ${m.id.padEnd(maxIdLen)} ${m.name.padEnd(maxNameLen)} ${m.provider.padEnd(maxProviderLen)} ${m.description}`);
78
+ }
79
+
80
+ console.log('\nšŸ’” Tip: Use these IDs in your task JSON files under the "model" field.\n');
81
+ }
82
+
83
+ export = models;
@@ -19,6 +19,20 @@ interface LaneWithDeps {
19
19
  interface MonitorOptions {
20
20
  runDir?: string;
21
21
  interval: number;
22
+ help: boolean;
23
+ }
24
+
25
+ function printHelp(): void {
26
+ console.log(`
27
+ Usage: cursorflow monitor [run-dir] [options]
28
+
29
+ Interactive lane dashboard to track progress and dependencies.
30
+
31
+ Options:
32
+ [run-dir] Run directory to monitor (default: latest)
33
+ --interval <seconds> Refresh interval (default: 2)
34
+ --help, -h Show help
35
+ `);
22
36
  }
23
37
 
24
38
  enum View {
@@ -44,6 +58,7 @@ class InteractiveMonitor {
44
58
  private terminalScrollOffset: number = 0;
45
59
  private lastTerminalTotalLines: number = 0;
46
60
  private interventionInput: string = '';
61
+ private notification: { message: string; type: 'info' | 'error' | 'success'; time: number } | null = null;
47
62
 
48
63
  constructor(runDir: string, interval: number) {
49
64
  this.runDir = runDir;
@@ -155,6 +170,9 @@ class InteractiveMonitor {
155
170
  this.terminalScrollOffset = 0;
156
171
  this.render();
157
172
  break;
173
+ case 'k':
174
+ this.killLane();
175
+ break;
158
176
  case 'i':
159
177
  const lane = this.lanes.find(l => l.name === this.selectedLaneName);
160
178
  if (lane) {
@@ -304,10 +322,43 @@ class InteractiveMonitor {
304
322
  this.render();
305
323
  }
306
324
 
325
+ private killLane() {
326
+ if (!this.selectedLaneName) return;
327
+ const lane = this.lanes.find(l => l.name === this.selectedLaneName);
328
+ if (!lane) return;
329
+
330
+ const status = this.getLaneStatus(lane.path, lane.name);
331
+ if (status.pid && status.status === 'running') {
332
+ try {
333
+ process.kill(status.pid, 'SIGTERM');
334
+ this.showNotification(`Sent SIGTERM to PID ${status.pid}`, 'success');
335
+ } catch (e) {
336
+ this.showNotification(`Failed to kill PID ${status.pid}`, 'error');
337
+ }
338
+ } else {
339
+ this.showNotification(`No running process found for ${this.selectedLaneName}`, 'info');
340
+ }
341
+ }
342
+
343
+ private showNotification(message: string, type: 'info' | 'error' | 'success') {
344
+ this.notification = { message, type, time: Date.now() };
345
+ this.render();
346
+ }
347
+
307
348
  private render() {
308
349
  // Clear screen
309
350
  process.stdout.write('\x1Bc');
310
351
 
352
+ // Clear old notifications
353
+ if (this.notification && Date.now() - this.notification.time > 3000) {
354
+ this.notification = null;
355
+ }
356
+
357
+ if (this.notification) {
358
+ const color = this.notification.type === 'error' ? '\x1b[31m' : this.notification.type === 'success' ? '\x1b[32m' : '\x1b[36m';
359
+ console.log(`${color}šŸ”” ${this.notification.message}\x1b[0m\n`);
360
+ }
361
+
311
362
  switch (this.view) {
312
363
  case View.LIST:
313
364
  this.renderList();
@@ -413,6 +464,7 @@ class InteractiveMonitor {
413
464
  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
414
465
 
415
466
  process.stdout.write(` Status: ${this.getStatusIcon(status.status)} ${status.status}\n`);
467
+ process.stdout.write(` PID: ${status.pid || '-'}\n`);
416
468
  process.stdout.write(` Progress: ${status.progress} (${status.currentTask}/${status.totalTasks} tasks)\n`);
417
469
  process.stdout.write(` Time: ${this.formatDuration(status.duration)}\n`);
418
470
  process.stdout.write(` Branch: ${status.pipelineBranch}\n`);
@@ -429,7 +481,7 @@ class InteractiveMonitor {
429
481
 
430
482
  console.log('\nšŸ’¬ Conversation History (Select to see full details):');
431
483
  console.log('─'.repeat(80));
432
- process.stdout.write(' [↑/↓] Browse | [→/Enter] Full Msg | [I] Intervene | [T] Live Terminal | [Esc/←] Back\n\n');
484
+ process.stdout.write(' [↑/↓] Browse | [→/Enter] Full Msg | [I] Intervene | [K] Kill | [T] Live Terminal | [Esc/←] Back\n\n');
433
485
 
434
486
  if (this.currentLogs.length === 0) {
435
487
  console.log(' (No messages yet)');
@@ -670,6 +722,7 @@ class InteractiveMonitor {
670
722
  dependsOn,
671
723
  duration,
672
724
  error: state.error,
725
+ pid: state.pid
673
726
  };
674
727
  }
675
728
 
@@ -715,6 +768,12 @@ function findLatestRunDir(logsDir: string): string | null {
715
768
  * Monitor lanes
716
769
  */
717
770
  async function monitor(args: string[]): Promise<void> {
771
+ const help = args.includes('--help') || args.includes('-h');
772
+ if (help) {
773
+ printHelp();
774
+ return;
775
+ }
776
+
718
777
  const watchIdx = args.indexOf('--watch');
719
778
  const intervalIdx = args.indexOf('--interval');
720
779
  const interval = intervalIdx >= 0 ? parseInt(args[intervalIdx + 1] || '2') || 2 : 2;