@litmers/cursorflow-orchestrator 0.1.9 → 0.1.13

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 (60) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +90 -72
  3. package/commands/cursorflow-clean.md +24 -135
  4. package/commands/cursorflow-doctor.md +66 -38
  5. package/commands/cursorflow-init.md +33 -50
  6. package/commands/cursorflow-models.md +51 -0
  7. package/commands/cursorflow-monitor.md +52 -72
  8. package/commands/cursorflow-prepare.md +426 -147
  9. package/commands/cursorflow-resume.md +51 -159
  10. package/commands/cursorflow-review.md +38 -202
  11. package/commands/cursorflow-run.md +197 -84
  12. package/commands/cursorflow-signal.md +27 -72
  13. package/dist/cli/clean.js +23 -0
  14. package/dist/cli/clean.js.map +1 -1
  15. package/dist/cli/doctor.js +14 -1
  16. package/dist/cli/doctor.js.map +1 -1
  17. package/dist/cli/index.js +14 -3
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/cli/init.js +5 -4
  20. package/dist/cli/init.js.map +1 -1
  21. package/dist/cli/models.d.ts +7 -0
  22. package/dist/cli/models.js +104 -0
  23. package/dist/cli/models.js.map +1 -0
  24. package/dist/cli/monitor.js +17 -0
  25. package/dist/cli/monitor.js.map +1 -1
  26. package/dist/cli/prepare.d.ts +7 -0
  27. package/dist/cli/prepare.js +748 -0
  28. package/dist/cli/prepare.js.map +1 -0
  29. package/dist/cli/resume.js +56 -0
  30. package/dist/cli/resume.js.map +1 -1
  31. package/dist/cli/run.js +30 -1
  32. package/dist/cli/run.js.map +1 -1
  33. package/dist/cli/signal.js +18 -0
  34. package/dist/cli/signal.js.map +1 -1
  35. package/dist/utils/cursor-agent.d.ts +4 -0
  36. package/dist/utils/cursor-agent.js +58 -10
  37. package/dist/utils/cursor-agent.js.map +1 -1
  38. package/dist/utils/doctor.d.ts +10 -0
  39. package/dist/utils/doctor.js +588 -1
  40. package/dist/utils/doctor.js.map +1 -1
  41. package/dist/utils/types.d.ts +2 -0
  42. package/examples/README.md +114 -59
  43. package/examples/demo-project/README.md +61 -79
  44. package/examples/demo-project/_cursorflow/tasks/demo-test/01-create-utils.json +17 -6
  45. package/examples/demo-project/_cursorflow/tasks/demo-test/02-add-tests.json +17 -6
  46. package/examples/demo-project/_cursorflow/tasks/demo-test/README.md +66 -25
  47. package/package.json +1 -1
  48. package/src/cli/clean.ts +27 -0
  49. package/src/cli/doctor.ts +18 -2
  50. package/src/cli/index.ts +15 -3
  51. package/src/cli/init.ts +6 -4
  52. package/src/cli/models.ts +83 -0
  53. package/src/cli/monitor.ts +20 -0
  54. package/src/cli/prepare.ts +844 -0
  55. package/src/cli/resume.ts +66 -0
  56. package/src/cli/run.ts +36 -2
  57. package/src/cli/signal.ts +22 -0
  58. package/src/utils/cursor-agent.ts +62 -10
  59. package/src/utils/doctor.ts +643 -5
  60. package/src/utils/types.ts +2 -0
@@ -2,53 +2,70 @@
2
2
 
3
3
  This directory contains test tasks for demonstrating CursorFlow with real LLM execution.
4
4
 
5
+ ## Alternative: Generate with Prepare Command
6
+
7
+ Instead of using these pre-made files, you can generate similar tasks using:
8
+
9
+ ```bash
10
+ # Simple approach
11
+ cursorflow prepare CreateUtils --preset simple --prompt "Create src/utils.js with capitalize, sum, unique functions"
12
+ cursorflow prepare AddTests --preset simple --prompt "Create src/utils.test.js with tests for utils"
13
+
14
+ # Or use a single complex task
15
+ cursorflow prepare UtilsWithTests --preset complex --prompt "Create utility module with tests"
16
+ ```
17
+
5
18
  ## Tasks Overview
6
19
 
7
20
  ### 01-create-utils.json
8
21
  Creates a utility module with basic functions:
9
- - capitalize(str)
10
- - sum(arr)
11
- - unique(arr)
22
+ - `capitalize(str)` - Capitalizes first letter
23
+ - `sum(arr)` - Sums array of numbers
24
+ - `unique(arr)` - Returns unique elements
12
25
 
13
26
  **Model**: sonnet-4.5
14
27
  **Estimated time**: 1-2 minutes
28
+ **Acceptance Criteria**: 5 criteria including function verification
15
29
 
16
30
  ### 02-add-tests.json
17
31
  Adds simple tests for the utility functions without requiring any testing framework.
18
32
 
19
33
  **Model**: sonnet-4.5
20
34
  **Estimated time**: 1-2 minutes
35
+ **Acceptance Criteria**: 5 criteria including test coverage
21
36
 
22
37
  ## Running the Demo
23
38
 
24
39
  ### Prerequisites
25
40
  - cursor-agent CLI installed (`npm install -g @cursor/agent`)
26
- - Valid Cursor API key configured
41
+ - Valid Cursor authentication (sign in via Cursor IDE)
27
42
 
28
- ### Run the test
43
+ ### 1. Validate first
44
+ ```bash
45
+ cursorflow doctor --tasks-dir _cursorflow/tasks/demo-test/
46
+ ```
29
47
 
48
+ ### 2. Run the test
30
49
  ```bash
31
- # From your project directory (after cursorflow init)
32
50
  cursorflow run _cursorflow/tasks/demo-test/
33
51
  ```
34
52
 
35
- ### Monitor execution
36
-
37
- In a separate terminal:
53
+ ### 3. Monitor execution
38
54
  ```bash
39
- # Watch mode (updates every 2 seconds)
55
+ # Interactive dashboard (recommended)
56
+ cursorflow monitor latest
57
+
58
+ # Or watch mode
40
59
  cursorflow monitor --watch --interval 2
41
60
  ```
42
61
 
43
- ### Check results
44
-
45
- After completion:
62
+ ### 4. Check results
46
63
  ```bash
47
- # View the logs
48
- ls -la _cursorflow/logs/runs/
49
-
50
- # Check the latest run
64
+ # View lane status
51
65
  cursorflow monitor
66
+
67
+ # Check git branches
68
+ git branch | grep cursorflow
52
69
  ```
53
70
 
54
71
  ## What to Expect
@@ -56,14 +73,16 @@ cursorflow monitor
56
73
  1. **Orchestrator** will create 2 lanes (one per task)
57
74
  2. **Each lane** will:
58
75
  - Create a Git worktree
59
- - Create a branch (`cursorflow/demo-XXXXX--01-create-utils`, etc.)
76
+ - Create a branch (`cursorflow/demo-utils-*`, `cursorflow/demo-tests-*`)
60
77
  - Execute the LLM agent with the prompt
78
+ - Run AI code review (if enabled)
61
79
  - Commit changes
62
80
  - Push the branch
63
81
  3. **Monitor** will show:
64
- - Lane status (running, completed, failed)
82
+ - Lane status (pending, running, completed, failed)
65
83
  - Progress (current task / total tasks)
66
- - Real-time updates in watch mode
84
+ - Dependencies (if any)
85
+ - Real-time updates
67
86
 
68
87
  ## Expected Output Structure
69
88
 
@@ -88,6 +107,16 @@ _cursorflow/
88
107
  └── README.md (this file)
89
108
  ```
90
109
 
110
+ ## Cleanup
111
+
112
+ After testing:
113
+ ```bash
114
+ # Clean branches and worktrees
115
+ cursorflow clean branches --dry-run # Preview
116
+ cursorflow clean branches # Execute
117
+ cursorflow clean worktrees # Clean worktrees
118
+ ```
119
+
91
120
  ## Troubleshooting
92
121
 
93
122
  ### If cursor-agent is not found
@@ -95,15 +124,27 @@ _cursorflow/
95
124
  npm install -g @cursor/agent
96
125
  ```
97
126
 
98
- ### If API key is missing
99
- Check your Cursor IDE settings and ensure you're authenticated.
127
+ ### If authentication fails
128
+ 1. Open Cursor IDE
129
+ 2. Sign in to your account
130
+ 3. Verify AI features work in the IDE
131
+ 4. Run `cursorflow doctor` to check
100
132
 
101
133
  ### If worktree creation fails
102
- Make sure you're in a Git repository with at least one commit.
134
+ Make sure you're in a Git repository with at least one commit:
135
+ ```bash
136
+ git log --oneline -1
137
+ ```
138
+
139
+ ### If branch conflicts occur
140
+ ```bash
141
+ cursorflow doctor --tasks-dir _cursorflow/tasks/demo-test/
142
+ ```
103
143
 
104
144
  ## Notes
105
145
 
106
- - These tasks are designed to be simple and quick
107
- - No external dependencies required
146
+ - These tasks run in parallel (no dependencies)
147
+ - Each task creates its own isolated branch
148
+ - AI code review is enabled by default
108
149
  - All operations are Git-safe (branches only, no main changes)
109
150
  - Logs are preserved for inspection
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litmers/cursorflow-orchestrator",
3
- "version": "0.1.9",
3
+ "version": "0.1.13",
4
4
  "description": "Git worktree-based parallel AI agent orchestration system for Cursor",
5
5
  "main": "dist/cli/index.js",
6
6
  "bin": {
package/src/cli/clean.ts CHANGED
@@ -16,6 +16,26 @@ interface CleanOptions {
16
16
  dryRun: boolean;
17
17
  force: boolean;
18
18
  all: boolean;
19
+ help: boolean;
20
+ }
21
+
22
+ function printHelp(): void {
23
+ console.log(`
24
+ Usage: cursorflow clean <type> [options]
25
+
26
+ Clean up resources created by CursorFlow.
27
+
28
+ Types:
29
+ branches Remove local feature branches
30
+ worktrees Remove temporary Git worktrees
31
+ logs Clear log directories
32
+ all Remove all of the above (default)
33
+
34
+ Options:
35
+ --dry-run Show what would be removed without deleting
36
+ --force Force removal (ignore uncommitted changes)
37
+ --help, -h Show help
38
+ `);
19
39
  }
20
40
 
21
41
  function parseArgs(args: string[]): CleanOptions {
@@ -25,11 +45,18 @@ function parseArgs(args: string[]): CleanOptions {
25
45
  dryRun: args.includes('--dry-run'),
26
46
  force: args.includes('--force'),
27
47
  all: args.includes('--all'),
48
+ help: args.includes('--help') || args.includes('-h'),
28
49
  };
29
50
  }
30
51
 
31
52
  async function clean(args: string[]): Promise<void> {
32
53
  const options = parseArgs(args);
54
+
55
+ if (options.help) {
56
+ printHelp();
57
+ return;
58
+ }
59
+
33
60
  const config = loadConfig();
34
61
  const repoRoot = git.getRepoRoot();
35
62
 
package/src/cli/doctor.ts CHANGED
@@ -13,13 +13,15 @@
13
13
  */
14
14
 
15
15
  import * as logger from '../utils/logger';
16
- import { runDoctor } from '../utils/doctor';
16
+ import { runDoctor, saveDoctorStatus } from '../utils/doctor';
17
+ import { runInteractiveAgentTest } from '../utils/cursor-agent';
17
18
 
18
19
  interface DoctorCliOptions {
19
20
  json: boolean;
20
21
  tasksDir: string | null;
21
22
  executor: string | null;
22
23
  includeCursorAgentChecks: boolean;
24
+ testAgent: boolean;
23
25
  }
24
26
 
25
27
  function printHelp(): void {
@@ -33,12 +35,13 @@ Options:
33
35
  --tasks-dir <path> Also validate lane files (run preflight)
34
36
  --executor <type> cursor-agent | cloud
35
37
  --no-cursor Skip Cursor Agent install/auth checks
38
+ --test-agent Run interactive agent test (to approve MCP/permissions)
36
39
  --help, -h Show help
37
40
 
38
41
  Examples:
39
42
  cursorflow doctor
43
+ cursorflow doctor --test-agent
40
44
  cursorflow doctor --tasks-dir _cursorflow/tasks/demo-test/
41
- cursorflow doctor --json
42
45
  `);
43
46
  }
44
47
 
@@ -51,6 +54,7 @@ function parseArgs(args: string[]): DoctorCliOptions {
51
54
  tasksDir: tasksDirIdx >= 0 ? (args[tasksDirIdx + 1] || null) : null,
52
55
  executor: executorIdx >= 0 ? (args[executorIdx + 1] || null) : null,
53
56
  includeCursorAgentChecks: !args.includes('--no-cursor'),
57
+ testAgent: args.includes('--test-agent'),
54
58
  };
55
59
 
56
60
  if (args.includes('--help') || args.includes('-h')) {
@@ -69,6 +73,8 @@ function printHumanReport(report: ReturnType<typeof runDoctor>): void {
69
73
 
70
74
  if (report.issues.length === 0) {
71
75
  logger.success('All checks passed');
76
+ console.log('\nšŸ’” Tip: If this is your first run, we recommend running:');
77
+ console.log(' cursorflow doctor --test-agent\n');
72
78
  return;
73
79
  }
74
80
 
@@ -106,6 +112,11 @@ function printHumanReport(report: ReturnType<typeof runDoctor>): void {
106
112
  async function doctor(args: string[]): Promise<void> {
107
113
  const options = parseArgs(args);
108
114
 
115
+ if (options.testAgent) {
116
+ const success = runInteractiveAgentTest();
117
+ process.exit(success ? 0 : 1);
118
+ }
119
+
109
120
  const report = runDoctor({
110
121
  cwd: process.cwd(),
111
122
  tasksDir: options.tasksDir || undefined,
@@ -119,6 +130,11 @@ async function doctor(args: string[]): Promise<void> {
119
130
  printHumanReport(report);
120
131
  }
121
132
 
133
+ // Save successful doctor run status
134
+ if (report.ok && report.context.repoRoot) {
135
+ saveDoctorStatus(report.context.repoRoot, report);
136
+ }
137
+
122
138
  process.exit(report.ok ? 0 : 1);
123
139
  }
124
140
 
package/src/cli/index.ts CHANGED
@@ -7,15 +7,21 @@ 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 {
@@ -27,12 +33,14 @@ function printHelp(): void {
27
33
 
28
34
  \x1b[1mCOMMANDS\x1b[0m
29
35
  \x1b[33minit\x1b[0m [options] Initialize CursorFlow in project
36
+ \x1b[33mprepare\x1b[0m <feature> [opts] Prepare task directory and JSON files
30
37
  \x1b[33mrun\x1b[0m <tasks-dir> [options] Run orchestration (DAG-based)
31
38
  \x1b[33mmonitor\x1b[0m [run-dir] [options] \x1b[36mInteractive\x1b[0m lane dashboard
32
39
  \x1b[33mclean\x1b[0m <type> [options] Clean branches/worktrees/logs
33
40
  \x1b[33mresume\x1b[0m <lane> [options] Resume interrupted lane
34
41
  \x1b[33mdoctor\x1b[0m [options] Check environment and preflight
35
42
  \x1b[33msignal\x1b[0m <lane> <msg> Directly intervene in a running lane
43
+ \x1b[33mmodels\x1b[0m [options] List available AI models
36
44
 
37
45
  \x1b[1mGLOBAL OPTIONS\x1b[0m
38
46
  --config <path> Config file path
@@ -41,9 +49,10 @@ function printHelp(): void {
41
49
 
42
50
  \x1b[1mEXAMPLES\x1b[0m
43
51
  $ \x1b[32mcursorflow init --example\x1b[0m
52
+ $ \x1b[32mcursorflow prepare NewFeature --lanes 3\x1b[0m
44
53
  $ \x1b[32mcursorflow run _cursorflow/tasks/MyFeature/\x1b[0m
45
54
  $ \x1b[32mcursorflow monitor latest\x1b[0m
46
- $ \x1b[32mcursorflow signal lane-1 "Please use pnpm instead of npm"\x1b[0m
55
+ $ \x1b[32mcursorflow models\x1b[0m
47
56
 
48
57
  \x1b[1mDOCUMENTATION\x1b[0m
49
58
  https://github.com/eungjin-cigro/cursorflow#readme
@@ -58,7 +67,10 @@ function printVersion(): void {
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') || args[0] === 'help') {
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 {
@@ -754,6 +768,12 @@ function findLatestRunDir(logsDir: string): string | null {
754
768
  * Monitor lanes
755
769
  */
756
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
+
757
777
  const watchIdx = args.indexOf('--watch');
758
778
  const intervalIdx = args.indexOf('--interval');
759
779
  const interval = intervalIdx >= 0 ? parseInt(args[intervalIdx + 1] || '2') || 2 : 2;