@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.
- package/CHANGELOG.md +78 -0
- package/LICENSE +21 -0
- package/README.md +310 -0
- package/commands/cursorflow-clean.md +162 -0
- package/commands/cursorflow-init.md +67 -0
- package/commands/cursorflow-monitor.md +131 -0
- package/commands/cursorflow-prepare.md +134 -0
- package/commands/cursorflow-resume.md +181 -0
- package/commands/cursorflow-review.md +220 -0
- package/commands/cursorflow-run.md +129 -0
- package/package.json +52 -0
- package/scripts/postinstall.js +27 -0
- package/src/cli/clean.js +30 -0
- package/src/cli/index.js +93 -0
- package/src/cli/init.js +235 -0
- package/src/cli/monitor.js +29 -0
- package/src/cli/resume.js +31 -0
- package/src/cli/run.js +51 -0
- package/src/cli/setup-commands.js +210 -0
- package/src/core/orchestrator.js +185 -0
- package/src/core/reviewer.js +233 -0
- package/src/core/runner.js +343 -0
- package/src/utils/config.js +195 -0
- package/src/utils/cursor-agent.js +190 -0
- package/src/utils/git.js +311 -0
- package/src/utils/logger.js +178 -0
- package/src/utils/state.js +207 -0
|
@@ -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
|
+
`);
|
package/src/cli/clean.js
ADDED
|
@@ -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;
|
package/src/cli/index.js
ADDED
|
@@ -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;
|
package/src/cli/init.js
ADDED
|
@@ -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;
|