@litmers/cursorflow-orchestrator 0.1.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.
@@ -0,0 +1,129 @@
1
+ # CursorFlow Run
2
+
3
+ ## Overview
4
+ 준비된 태스크를 실행합니다. 단일 레인 또는 멀티 레인 오케스트레이션을 수행합니다.
5
+
6
+ ## Steps
7
+
8
+ 1. **태스크 디렉토리 확인**
9
+ ```bash
10
+ ls _cursorflow/tasks/
11
+ ```
12
+
13
+ 2. **멀티 레인 실행**
14
+ ```bash
15
+ cursorflow run _cursorflow/tasks/MyFeature/
16
+ ```
17
+
18
+ 3. **단일 레인 실행**
19
+ ```bash
20
+ cursorflow lane _cursorflow/tasks/MyFeature/01-task.json
21
+ ```
22
+
23
+ 4. **Dry run (실행 계획 확인)**
24
+ ```bash
25
+ cursorflow run _cursorflow/tasks/MyFeature/ --dry-run
26
+ ```
27
+
28
+ 5. **실행 모니터링**
29
+
30
+ 실행 중에는 다른 터미널에서 모니터링:
31
+ ```bash
32
+ cursorflow monitor --watch
33
+ ```
34
+
35
+ ## 옵션
36
+
37
+ | 옵션 | 설명 |
38
+ |------|------|
39
+ | `--dry-run` | 실제 실행 없이 계획만 확인 |
40
+ | `--executor <type>` | 실행 방식 (cursor-agent \| cloud) |
41
+ | `--no-review` | 코드 리뷰 비활성화 |
42
+ | `--config <path>` | 커스텀 설정 파일 경로 |
43
+
44
+ ## 예제
45
+
46
+ ### 기본 실행
47
+ ```bash
48
+ cursorflow run _cursorflow/tasks/2512191700_MyFeature/
49
+ ```
50
+
51
+ ### Cloud 실행 (API 키 필요)
52
+ ```bash
53
+ export CURSOR_API_KEY=your_key
54
+ cursorflow run _cursorflow/tasks/MyFeature/ --executor cloud
55
+ ```
56
+
57
+ ### 리뷰 없이 빠른 실행
58
+ ```bash
59
+ cursorflow run _cursorflow/tasks/MyFeature/ --no-review
60
+ ```
61
+
62
+ ## 실행 프로세스
63
+
64
+ 1. **초기화**
65
+ - 설정 로드
66
+ - cursor-agent CLI 확인
67
+ - Git 저장소 확인
68
+
69
+ 2. **레인 준비**
70
+ - Worktree 생성
71
+ - 브랜치 체크아웃
72
+ - 환경 설정
73
+
74
+ 3. **태스크 실행**
75
+ - 순차적으로 태스크 수행
76
+ - 각 태스크 완료 후 커밋
77
+ - 리뷰 활성화 시 자동 리뷰
78
+
79
+ 4. **완료**
80
+ - 변경사항 푸시
81
+ - PR 생성 (설정에 따라)
82
+ - 로그 저장
83
+
84
+ ## 로그 위치
85
+
86
+ 실행 로그는 `_cursorflow/logs/runs/` 에 저장됩니다:
87
+
88
+ ```
89
+ _cursorflow/logs/runs/<lane>-<timestamp>/
90
+ ├── state.json # 레인 상태
91
+ ├── results.json # 태스크 결과
92
+ ├── conversation.jsonl # 에이전트 대화
93
+ ├── git-operations.jsonl # Git 작업 로그
94
+ └── events.jsonl # 이벤트 로그
95
+ ```
96
+
97
+ ## Checklist
98
+ - [ ] cursor-agent CLI가 설치되어 있는가?
99
+ - [ ] Git worktree가 사용 가능한가?
100
+ - [ ] 태스크 파일이 올바른가?
101
+ - [ ] 브랜치 이름이 충돌하지 않는가?
102
+ - [ ] 필요한 환경 변수가 설정되었는가? (Cloud 실행 시)
103
+
104
+ ## 트러블슈팅
105
+
106
+ ### 브랜치 충돌
107
+ ```bash
108
+ # 기존 브랜치 정리
109
+ cursorflow clean branches --pattern "feature/my-*"
110
+ ```
111
+
112
+ ### Worktree 충돌
113
+ ```bash
114
+ # 기존 worktree 정리
115
+ cursorflow clean worktrees --all
116
+ ```
117
+
118
+ ### 실행 실패
119
+ ```bash
120
+ # 로그 확인
121
+ cursorflow monitor
122
+ # 또는
123
+ cat _cursorflow/logs/runs/latest/*/state.json
124
+ ```
125
+
126
+ ## Next Steps
127
+ 1. `cursorflow monitor --watch`로 진행 상황 모니터링
128
+ 2. 완료 후 PR 확인 및 리뷰
129
+ 3. 실패 시 `cursorflow resume <lane>`로 재개
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@litmers/cursorflow-orchestrator",
3
+ "version": "0.1.0",
4
+ "description": "Git worktree-based parallel AI agent orchestration system for Cursor",
5
+ "main": "src/cli/index.js",
6
+ "bin": {
7
+ "cursorflow": "src/cli/index.js",
8
+ "cursorflow-setup": "src/cli/setup-commands.js"
9
+ },
10
+ "scripts": {
11
+ "test": "node test/run.js",
12
+ "postinstall": "node scripts/postinstall.js"
13
+ },
14
+ "keywords": [
15
+ "cursor",
16
+ "cursor-ide",
17
+ "ai-agent",
18
+ "orchestration",
19
+ "git-worktree",
20
+ "parallel-execution",
21
+ "code-review",
22
+ "automation",
23
+ "devops",
24
+ "ci-cd"
25
+ ],
26
+ "author": "Eugene Jin <eungjin.cigro@gmail.com>",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/eungjin-cigro/cursorflow.git"
31
+ },
32
+ "bugs": {
33
+ "url": "https://github.com/eungjin-cigro/cursorflow/issues"
34
+ },
35
+ "homepage": "https://github.com/eungjin-cigro/cursorflow#readme",
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "dependencies": {},
40
+ "devDependencies": {},
41
+ "peerDependencies": {},
42
+ "files": [
43
+ "src/",
44
+ "scripts/",
45
+ "commands/",
46
+ "templates/",
47
+ "docs/",
48
+ "README.md",
49
+ "LICENSE",
50
+ "CHANGELOG.md"
51
+ ]
52
+ }
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Post-install script
4
+ *
5
+ * Shows a message after package installation
6
+ */
7
+
8
+ console.log(`
9
+ 📦 CursorFlow installed successfully!
10
+
11
+ To get started:
12
+
13
+ 1. Initialize CursorFlow in your project:
14
+ npx cursorflow init
15
+
16
+ 2. Install Cursor commands:
17
+ npx cursorflow-setup
18
+
19
+ 3. Start using CursorFlow:
20
+ cursorflow run _cursorflow/tasks/example/
21
+
22
+ Documentation:
23
+ https://github.com/eungjin-cigro/cursorflow#readme
24
+
25
+ Need help?
26
+ cursorflow --help
27
+ `);
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CursorFlow clean command (stub)
4
+ */
5
+
6
+ const logger = require('../utils/logger');
7
+
8
+ function parseArgs(args) {
9
+ return {
10
+ type: args[0], // branches | worktrees | logs | all
11
+ pattern: null,
12
+ dryRun: args.includes('--dry-run'),
13
+ force: args.includes('--force'),
14
+ };
15
+ }
16
+
17
+ async function clean(args) {
18
+ logger.section('🧹 Cleaning CursorFlow Resources');
19
+
20
+ const options = parseArgs(args);
21
+
22
+ logger.info('This command will be fully implemented in the next phase');
23
+ logger.info(`Clean type: ${options.type}`);
24
+ logger.info(`Dry run: ${options.dryRun}`);
25
+
26
+ logger.warn('\n⚠️ Implementation pending');
27
+ logger.info('This will clean branches, worktrees, and logs');
28
+ }
29
+
30
+ module.exports = clean;
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CursorFlow CLI - Main entry point
4
+ */
5
+
6
+ const logger = require('../utils/logger');
7
+
8
+ const COMMANDS = {
9
+ init: require('./init'),
10
+ run: require('./run'),
11
+ monitor: require('./monitor'),
12
+ clean: require('./clean'),
13
+ resume: require('./resume'),
14
+ };
15
+
16
+ function printHelp() {
17
+ console.log(`
18
+ CursorFlow - Git worktree-based parallel AI agent orchestration
19
+
20
+ Usage: cursorflow <command> [options]
21
+
22
+ Commands:
23
+ init [options] Initialize CursorFlow in project
24
+ run <tasks-dir> [options] Run orchestration
25
+ monitor [run-dir] [options] Monitor lane execution
26
+ clean <type> [options] Clean branches/worktrees/logs
27
+ resume <lane> [options] Resume interrupted lane
28
+
29
+ Global Options:
30
+ --config <path> Config file path
31
+ --help, -h Show help
32
+ --version, -v Show version
33
+
34
+ Examples:
35
+ cursorflow init --example
36
+ cursorflow run _cursorflow/tasks/MyFeature/
37
+ cursorflow monitor --watch
38
+ cursorflow clean branches --all
39
+
40
+ Documentation:
41
+ https://github.com/eungjin-cigro/cursorflow#readme
42
+ `);
43
+ }
44
+
45
+ function printVersion() {
46
+ const pkg = require('../../package.json');
47
+ console.log(`CursorFlow v${pkg.version}`);
48
+ }
49
+
50
+ async function main() {
51
+ const args = process.argv.slice(2);
52
+
53
+ if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
54
+ printHelp();
55
+ process.exit(0);
56
+ }
57
+
58
+ if (args.includes('--version') || args.includes('-v')) {
59
+ printVersion();
60
+ process.exit(0);
61
+ }
62
+
63
+ const command = args[0];
64
+ const commandArgs = args.slice(1);
65
+
66
+ if (!COMMANDS[command]) {
67
+ logger.error(`Unknown command: ${command}`);
68
+ console.log('\nRun "cursorflow --help" for usage information.');
69
+ process.exit(1);
70
+ }
71
+
72
+ try {
73
+ await COMMANDS[command](commandArgs);
74
+ } catch (error) {
75
+ logger.error(error.message);
76
+ if (process.env.DEBUG) {
77
+ console.error(error.stack);
78
+ }
79
+ process.exit(1);
80
+ }
81
+ }
82
+
83
+ if (require.main === module) {
84
+ main().catch(error => {
85
+ logger.error(`Fatal error: ${error.message}`);
86
+ if (process.env.DEBUG) {
87
+ console.error(error.stack);
88
+ }
89
+ process.exit(1);
90
+ });
91
+ }
92
+
93
+ module.exports = main;
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CursorFlow init command
4
+ *
5
+ * Initialize CursorFlow in a project
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const logger = require('../utils/logger');
11
+ const { findProjectRoot, createDefaultConfig } = require('../utils/config');
12
+ const { setupCommands } = require('./setup-commands');
13
+
14
+ function parseArgs(args) {
15
+ const options = {
16
+ example: false,
17
+ withCommands: true,
18
+ configOnly: false,
19
+ force: false,
20
+ };
21
+
22
+ for (let i = 0; i < args.length; i++) {
23
+ const arg = args[i];
24
+
25
+ switch (arg) {
26
+ case '--example':
27
+ options.example = true;
28
+ break;
29
+ case '--with-commands':
30
+ options.withCommands = true;
31
+ break;
32
+ case '--no-commands':
33
+ options.withCommands = false;
34
+ break;
35
+ case '--config-only':
36
+ options.configOnly = true;
37
+ break;
38
+ case '--force':
39
+ options.force = true;
40
+ break;
41
+ case '--help':
42
+ case '-h':
43
+ printHelp();
44
+ process.exit(0);
45
+ break;
46
+ }
47
+ }
48
+
49
+ return options;
50
+ }
51
+
52
+ function printHelp() {
53
+ console.log(`
54
+ Usage: cursorflow init [options]
55
+
56
+ Initialize CursorFlow in your project
57
+
58
+ Options:
59
+ --example Create example tasks
60
+ --with-commands Install Cursor commands (default: true)
61
+ --no-commands Skip Cursor commands installation
62
+ --config-only Only create config file
63
+ --force Overwrite existing files
64
+ --help, -h Show help
65
+
66
+ Examples:
67
+ cursorflow init
68
+ cursorflow init --example
69
+ cursorflow init --config-only
70
+ `);
71
+ }
72
+
73
+ function createDirectories(projectRoot, config) {
74
+ const tasksDir = path.join(projectRoot, config.tasksDir);
75
+ const logsDir = path.join(projectRoot, config.logsDir);
76
+
77
+ if (!fs.existsSync(tasksDir)) {
78
+ fs.mkdirSync(tasksDir, { recursive: true });
79
+ logger.success(`Created directory: ${config.tasksDir}`);
80
+ } else {
81
+ logger.info(`Directory already exists: ${config.tasksDir}`);
82
+ }
83
+
84
+ if (!fs.existsSync(logsDir)) {
85
+ fs.mkdirSync(logsDir, { recursive: true });
86
+ logger.success(`Created directory: ${config.logsDir}`);
87
+ } else {
88
+ logger.info(`Directory already exists: ${config.logsDir}`);
89
+ }
90
+ }
91
+
92
+ function createExampleTasks(projectRoot, config) {
93
+ const exampleDir = path.join(projectRoot, config.tasksDir, 'example');
94
+
95
+ if (!fs.existsSync(exampleDir)) {
96
+ fs.mkdirSync(exampleDir, { recursive: true });
97
+ }
98
+
99
+ const exampleTask = {
100
+ repository: "https://github.com/your-org/your-repo",
101
+ baseBranch: "main",
102
+ branchPrefix: "cursorflow/example-",
103
+ executor: "cursor-agent",
104
+ autoCreatePr: false,
105
+ pollInterval: 60,
106
+ tasks: [
107
+ {
108
+ name: "hello",
109
+ model: "sonnet-4.5",
110
+ prompt: `# Example Task
111
+
112
+ ## Goal
113
+ Create a simple hello.txt file with a greeting message.
114
+
115
+ ## Steps
116
+ 1. Create a file called hello.txt
117
+ 2. Write "Hello from CursorFlow!" in the file
118
+ 3. Commit the change with message: "feat: add hello file"
119
+ `
120
+ }
121
+ ]
122
+ };
123
+
124
+ const taskPath = path.join(exampleDir, '01-hello.json');
125
+ fs.writeFileSync(taskPath, JSON.stringify(exampleTask, null, 2) + '\n', 'utf8');
126
+
127
+ logger.success(`Created example task: ${path.relative(projectRoot, taskPath)}`);
128
+
129
+ // Create README
130
+ const readmePath = path.join(exampleDir, 'README.md');
131
+ const readme = `# Example Task
132
+
133
+ This is an example CursorFlow task to help you get started.
134
+
135
+ ## Running the example
136
+
137
+ \`\`\`bash
138
+ cursorflow run ${config.tasksDir}/example/
139
+ \`\`\`
140
+
141
+ ## What it does
142
+
143
+ - Creates a simple hello.txt file
144
+ - Demonstrates basic task structure
145
+ - Shows how to write task prompts
146
+
147
+ ## Next steps
148
+
149
+ 1. Review the task configuration in \`01-hello.json\`
150
+ 2. Run the task to see CursorFlow in action
151
+ 3. Create your own tasks based on this example
152
+ `;
153
+
154
+ fs.writeFileSync(readmePath, readme, 'utf8');
155
+ logger.success(`Created example README: ${path.relative(projectRoot, readmePath)}`);
156
+ }
157
+
158
+ async function init(args) {
159
+ logger.section('🚀 Initializing CursorFlow');
160
+
161
+ const options = parseArgs(args);
162
+ const projectRoot = findProjectRoot();
163
+
164
+ logger.info(`Project root: ${projectRoot}`);
165
+
166
+ // 1. Create config file
167
+ const configPath = path.join(projectRoot, 'cursorflow.config.js');
168
+ const configExists = fs.existsSync(configPath);
169
+
170
+ if (configExists && !options.force) {
171
+ logger.warn(`Config file already exists: ${configPath}`);
172
+ logger.info('Use --force to overwrite');
173
+ } else {
174
+ try {
175
+ createDefaultConfig(projectRoot);
176
+ logger.success(`Created config file: cursorflow.config.js`);
177
+ } catch (error) {
178
+ if (error.message.includes('already exists') && !options.force) {
179
+ logger.warn(error.message);
180
+ } else {
181
+ throw error;
182
+ }
183
+ }
184
+ }
185
+
186
+ const config = require(configPath);
187
+
188
+ if (options.configOnly) {
189
+ logger.section('✅ Configuration initialized');
190
+ logger.info('\nNext steps:');
191
+ logger.info(' 1. Review cursorflow.config.js');
192
+ logger.info(' 2. Run: cursorflow init (without --config-only) to set up directories');
193
+ return;
194
+ }
195
+
196
+ // 2. Create directories
197
+ logger.info('\n📁 Creating directories...');
198
+ createDirectories(projectRoot, config);
199
+
200
+ // 3. Install Cursor commands
201
+ if (options.withCommands) {
202
+ logger.info('\n📋 Installing Cursor commands...');
203
+ try {
204
+ await setupCommands({ force: options.force, silent: false });
205
+ } catch (error) {
206
+ logger.warn(`Failed to install Cursor commands: ${error.message}`);
207
+ logger.info('You can install them later with: npx cursorflow-setup');
208
+ }
209
+ }
210
+
211
+ // 4. Create example tasks
212
+ if (options.example) {
213
+ logger.info('\n📝 Creating example tasks...');
214
+ createExampleTasks(projectRoot, config);
215
+ }
216
+
217
+ // 5. Summary
218
+ logger.section('✅ CursorFlow initialized successfully!');
219
+
220
+ console.log('\n📚 Next steps:\n');
221
+ console.log(' 1. Review cursorflow.config.js');
222
+ console.log(' 2. Type "/" in Cursor IDE to see available commands');
223
+
224
+ if (options.example) {
225
+ console.log(` 3. Run: cursorflow run ${config.tasksDir}/example/`);
226
+ } else {
227
+ console.log(' 3. Create tasks with: cursorflow prepare MyFeature');
228
+ }
229
+
230
+ console.log('\n📖 Documentation:');
231
+ console.log(' https://github.com/eungjin-cigro/cursorflow#readme');
232
+ console.log('');
233
+ }
234
+
235
+ module.exports = init;
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CursorFlow monitor command (stub)
4
+ */
5
+
6
+ const logger = require('../utils/logger');
7
+
8
+ function parseArgs(args) {
9
+ return {
10
+ runDir: args[0],
11
+ watch: args.includes('--watch'),
12
+ interval: 2,
13
+ };
14
+ }
15
+
16
+ async function monitor(args) {
17
+ logger.section('📡 Monitoring Lane Execution');
18
+
19
+ const options = parseArgs(args);
20
+
21
+ logger.info('This command will be fully implemented in the next phase');
22
+ logger.info(`Run directory: ${options.runDir || 'latest'}`);
23
+ logger.info(`Watch mode: ${options.watch}`);
24
+
25
+ logger.warn('\n⚠️ Implementation pending');
26
+ logger.info('This will show real-time lane status from logs');
27
+ }
28
+
29
+ module.exports = monitor;
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CursorFlow resume command (stub)
4
+ */
5
+
6
+ const logger = require('../utils/logger');
7
+
8
+ function parseArgs(args) {
9
+ return {
10
+ lane: args[0],
11
+ runDir: null,
12
+ clean: args.includes('--clean'),
13
+ restart: args.includes('--restart'),
14
+ };
15
+ }
16
+
17
+ async function resume(args) {
18
+ logger.section('🔁 Resuming Lane');
19
+
20
+ const options = parseArgs(args);
21
+
22
+ logger.info('This command will be fully implemented in the next phase');
23
+ logger.info(`Lane: ${options.lane}`);
24
+ logger.info(`Clean: ${options.clean}`);
25
+ logger.info(`Restart: ${options.restart}`);
26
+
27
+ logger.warn('\n⚠️ Implementation pending');
28
+ logger.info('This will resume interrupted lanes');
29
+ }
30
+
31
+ module.exports = resume;
package/src/cli/run.js ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CursorFlow run command
4
+ */
5
+
6
+ const path = require('path');
7
+ const fs = require('fs');
8
+ const logger = require('../utils/logger');
9
+ const { orchestrate } = require('../core/orchestrator');
10
+ const { loadConfig } = require('../utils/config');
11
+
12
+ function parseArgs(args) {
13
+ return {
14
+ tasksDir: args.find(a => !a.startsWith('--')),
15
+ dryRun: args.includes('--dry-run'),
16
+ executor: args[args.indexOf('--executor') + 1] || null,
17
+ };
18
+ }
19
+
20
+ async function run(args) {
21
+ const options = parseArgs(args);
22
+
23
+ if (!options.tasksDir) {
24
+ logger.error('Tasks directory required');
25
+ console.log('\nUsage: cursorflow run <tasks-dir> [options]');
26
+ process.exit(1);
27
+ }
28
+
29
+ if (!fs.existsSync(options.tasksDir)) {
30
+ logger.error(`Tasks directory not found: ${options.tasksDir}`);
31
+ process.exit(1);
32
+ }
33
+
34
+ const config = loadConfig();
35
+
36
+ try {
37
+ await orchestrate(options.tasksDir, {
38
+ executor: options.executor || config.executor,
39
+ pollInterval: config.pollInterval * 1000,
40
+ runDir: path.join(config.logsDir, 'runs', `run-${Date.now()}`),
41
+ });
42
+ } catch (error) {
43
+ logger.error(`Orchestration failed: ${error.message}`);
44
+ if (process.env.DEBUG) {
45
+ console.error(error.stack);
46
+ }
47
+ process.exit(1);
48
+ }
49
+ }
50
+
51
+ module.exports = run;