@litmers/cursorflow-orchestrator 0.1.0 → 0.1.2
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/README.md +375 -310
- package/commands/cursorflow-clean.md +162 -162
- package/commands/cursorflow-init.md +67 -67
- package/commands/cursorflow-monitor.md +131 -131
- package/commands/cursorflow-prepare.md +134 -134
- package/commands/cursorflow-resume.md +181 -181
- package/commands/cursorflow-review.md +220 -220
- package/commands/cursorflow-run.md +129 -129
- package/package.json +13 -4
- package/scripts/ai-security-check.js +224 -0
- package/scripts/release.sh +109 -0
- package/scripts/setup-security.sh +105 -0
- package/src/cli/init.js +69 -4
- package/src/cli/monitor.js +196 -9
- package/src/core/runner.js +187 -9
- package/src/utils/config.js +2 -2
- package/src/utils/cursor-agent.js +96 -0
|
@@ -1,129 +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>` |
|
|
41
|
-
| `--no-review` |
|
|
42
|
-
| `--config <path>` |
|
|
43
|
-
|
|
44
|
-
##
|
|
45
|
-
|
|
46
|
-
###
|
|
47
|
-
```bash
|
|
48
|
-
cursorflow run _cursorflow/tasks/2512191700_MyFeature/
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Cloud
|
|
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
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
|
|
74
|
-
3.
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
4.
|
|
80
|
-
-
|
|
81
|
-
- PR
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
##
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
100
|
-
- [ ]
|
|
101
|
-
- [ ]
|
|
102
|
-
- [ ]
|
|
103
|
-
|
|
104
|
-
##
|
|
105
|
-
|
|
106
|
-
###
|
|
107
|
-
```bash
|
|
108
|
-
#
|
|
109
|
-
cursorflow clean branches --pattern "feature/my-*"
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Worktree
|
|
113
|
-
```bash
|
|
114
|
-
#
|
|
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
|
|
127
|
-
1. `cursorflow monitor --watch
|
|
128
|
-
2.
|
|
129
|
-
3.
|
|
1
|
+
# CursorFlow Run
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Execute prepared tasks with single-lane or multi-lane orchestration.
|
|
5
|
+
|
|
6
|
+
## Steps
|
|
7
|
+
|
|
8
|
+
1. **Check the task directory**
|
|
9
|
+
```bash
|
|
10
|
+
ls _cursorflow/tasks/
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
2. **Run multiple lanes**
|
|
14
|
+
```bash
|
|
15
|
+
cursorflow run _cursorflow/tasks/MyFeature/
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
3. **Run a single lane**
|
|
19
|
+
```bash
|
|
20
|
+
cursorflow lane _cursorflow/tasks/MyFeature/01-task.json
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
4. **Dry run (preview the plan)**
|
|
24
|
+
```bash
|
|
25
|
+
cursorflow run _cursorflow/tasks/MyFeature/ --dry-run
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
5. **Monitor execution**
|
|
29
|
+
|
|
30
|
+
Watch progress from another terminal while the run is in progress:
|
|
31
|
+
```bash
|
|
32
|
+
cursorflow monitor --watch
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Options
|
|
36
|
+
|
|
37
|
+
| Option | Description |
|
|
38
|
+
|------|------|
|
|
39
|
+
| `--dry-run` | Preview the plan without executing |
|
|
40
|
+
| `--executor <type>` | Execution mode (`cursor-agent` \| `cloud`) |
|
|
41
|
+
| `--no-review` | Disable code review |
|
|
42
|
+
| `--config <path>` | Use a custom config file |
|
|
43
|
+
|
|
44
|
+
## Examples
|
|
45
|
+
|
|
46
|
+
### Standard run
|
|
47
|
+
```bash
|
|
48
|
+
cursorflow run _cursorflow/tasks/2512191700_MyFeature/
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Cloud run (requires API key)
|
|
52
|
+
```bash
|
|
53
|
+
export CURSOR_API_KEY=your_key
|
|
54
|
+
cursorflow run _cursorflow/tasks/MyFeature/ --executor cloud
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Fast run without review
|
|
58
|
+
```bash
|
|
59
|
+
cursorflow run _cursorflow/tasks/MyFeature/ --no-review
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Execution process
|
|
63
|
+
|
|
64
|
+
1. **Initialization**
|
|
65
|
+
- Load configuration
|
|
66
|
+
- Verify the `cursor-agent` CLI
|
|
67
|
+
- Confirm Git repository status
|
|
68
|
+
|
|
69
|
+
2. **Prepare lanes**
|
|
70
|
+
- Create worktrees
|
|
71
|
+
- Check out branches
|
|
72
|
+
- Configure the environment
|
|
73
|
+
|
|
74
|
+
3. **Run tasks**
|
|
75
|
+
- Execute tasks sequentially
|
|
76
|
+
- Commit after each task
|
|
77
|
+
- Trigger automatic review when enabled
|
|
78
|
+
|
|
79
|
+
4. **Complete**
|
|
80
|
+
- Push changes
|
|
81
|
+
- Create a PR (depending on settings)
|
|
82
|
+
- Store logs
|
|
83
|
+
|
|
84
|
+
## Log location
|
|
85
|
+
|
|
86
|
+
Run logs are stored in `_cursorflow/logs/runs/`:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
_cursorflow/logs/runs/<lane>-<timestamp>/
|
|
90
|
+
├── state.json # Lane status
|
|
91
|
+
├── results.json # Task results
|
|
92
|
+
├── conversation.jsonl # Agent conversation
|
|
93
|
+
├── git-operations.jsonl # Git activity log
|
|
94
|
+
└── events.jsonl # Event log
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Checklist
|
|
98
|
+
- [ ] Is the `cursor-agent` CLI installed?
|
|
99
|
+
- [ ] Are Git worktrees available?
|
|
100
|
+
- [ ] Are the task files valid?
|
|
101
|
+
- [ ] Do branch names avoid collisions?
|
|
102
|
+
- [ ] Are required environment variables set? (for cloud runs)
|
|
103
|
+
|
|
104
|
+
## Troubleshooting
|
|
105
|
+
|
|
106
|
+
### Branch conflicts
|
|
107
|
+
```bash
|
|
108
|
+
# Clean up existing branches
|
|
109
|
+
cursorflow clean branches --pattern "feature/my-*"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Worktree conflicts
|
|
113
|
+
```bash
|
|
114
|
+
# Clean up existing worktrees
|
|
115
|
+
cursorflow clean worktrees --all
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Run failures
|
|
119
|
+
```bash
|
|
120
|
+
# Inspect logs
|
|
121
|
+
cursorflow monitor
|
|
122
|
+
# or
|
|
123
|
+
cat _cursorflow/logs/runs/latest/*/state.json
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Next steps
|
|
127
|
+
1. Monitor progress with `cursorflow monitor --watch`.
|
|
128
|
+
2. Review the PR when the run completes.
|
|
129
|
+
3. If a run fails, resume with `cursorflow resume <lane>`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@litmers/cursorflow-orchestrator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Git worktree-based parallel AI agent orchestration system for Cursor",
|
|
5
5
|
"main": "src/cli/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,8 +8,17 @@
|
|
|
8
8
|
"cursorflow-setup": "src/cli/setup-commands.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"
|
|
12
|
-
"
|
|
11
|
+
"postinstall": "node scripts/postinstall.js",
|
|
12
|
+
"prepublishOnly": "npm run validate",
|
|
13
|
+
"validate": "npm pack --dry-run",
|
|
14
|
+
"release": "scripts/release.sh",
|
|
15
|
+
"release:patch": "scripts/release.sh patch",
|
|
16
|
+
"release:minor": "scripts/release.sh minor",
|
|
17
|
+
"release:major": "scripts/release.sh major",
|
|
18
|
+
"security:check": "npm audit && node scripts/ai-security-check.js",
|
|
19
|
+
"security:audit": "npm audit",
|
|
20
|
+
"security:audit:fix": "npm audit fix",
|
|
21
|
+
"security:setup": "scripts/setup-security.sh"
|
|
13
22
|
},
|
|
14
23
|
"keywords": [
|
|
15
24
|
"cursor",
|
|
@@ -44,7 +53,7 @@
|
|
|
44
53
|
"scripts/",
|
|
45
54
|
"commands/",
|
|
46
55
|
"templates/",
|
|
47
|
-
"
|
|
56
|
+
"examples/",
|
|
48
57
|
"README.md",
|
|
49
58
|
"LICENSE",
|
|
50
59
|
"CHANGELOG.md"
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AI 기반 보안 검사 스크립트
|
|
5
|
+
* OpenAI API를 사용하여 코드의 보안 취약점을 분석합니다.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { execSync } = require('child_process');
|
|
11
|
+
|
|
12
|
+
// 색상 정의
|
|
13
|
+
const colors = {
|
|
14
|
+
red: '\x1b[31m',
|
|
15
|
+
green: '\x1b[32m',
|
|
16
|
+
yellow: '\x1b[33m',
|
|
17
|
+
blue: '\x1b[34m',
|
|
18
|
+
reset: '\x1b[0m'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// OpenAI API 키 확인
|
|
22
|
+
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
|
|
23
|
+
if (!OPENAI_API_KEY) {
|
|
24
|
+
console.log(`${colors.yellow}⚠️ OPENAI_API_KEY not set. Skipping AI security check.${colors.reset}`);
|
|
25
|
+
process.exit(0);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 변경된 파일 가져오기 (PR인 경우)
|
|
29
|
+
function getChangedFiles() {
|
|
30
|
+
try {
|
|
31
|
+
const baseBranch = process.env.GITHUB_BASE_REF || 'main';
|
|
32
|
+
const diffCommand = `git diff --name-only origin/${baseBranch}...HEAD`;
|
|
33
|
+
const files = execSync(diffCommand, { encoding: 'utf-8' })
|
|
34
|
+
.split('\n')
|
|
35
|
+
.filter(f => f.endsWith('.js') || f.endsWith('.ts') || f.endsWith('.jsx') || f.endsWith('.tsx'))
|
|
36
|
+
.filter(f => f && fs.existsSync(f));
|
|
37
|
+
return files;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// PR이 아닌 경우 최근 커밋의 파일들
|
|
40
|
+
try {
|
|
41
|
+
const files = execSync('git diff-tree --no-commit-id --name-only -r HEAD', { encoding: 'utf-8' })
|
|
42
|
+
.split('\n')
|
|
43
|
+
.filter(f => f.endsWith('.js') || f.endsWith('.ts') || f.endsWith('.jsx') || f.endsWith('.tsx'))
|
|
44
|
+
.filter(f => f && fs.existsSync(f));
|
|
45
|
+
return files;
|
|
46
|
+
} catch {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// AI 보안 검사 프롬프트
|
|
53
|
+
function createSecurityPrompt(code, filename) {
|
|
54
|
+
return `You are a security expert analyzing code for vulnerabilities. Analyze the following code and identify any security issues.
|
|
55
|
+
|
|
56
|
+
File: ${filename}
|
|
57
|
+
|
|
58
|
+
Code:
|
|
59
|
+
\`\`\`javascript
|
|
60
|
+
${code}
|
|
61
|
+
\`\`\`
|
|
62
|
+
|
|
63
|
+
Please analyze for:
|
|
64
|
+
1. **Injection vulnerabilities** (SQL, NoSQL, Command, XSS, etc.)
|
|
65
|
+
2. **Authentication/Authorization issues**
|
|
66
|
+
3. **Sensitive data exposure** (hardcoded secrets, credentials, API keys)
|
|
67
|
+
4. **Insecure dependencies or imports**
|
|
68
|
+
5. **Path traversal vulnerabilities**
|
|
69
|
+
6. **Insecure randomness or cryptography**
|
|
70
|
+
7. **Unsafe deserialization**
|
|
71
|
+
8. **Rate limiting or DoS vulnerabilities**
|
|
72
|
+
9. **CSRF/SSRF vulnerabilities**
|
|
73
|
+
10. **Any OWASP Top 10 issues**
|
|
74
|
+
|
|
75
|
+
Respond in JSON format:
|
|
76
|
+
{
|
|
77
|
+
"has_issues": true/false,
|
|
78
|
+
"severity": "critical" | "high" | "medium" | "low" | "none",
|
|
79
|
+
"issues": [
|
|
80
|
+
{
|
|
81
|
+
"type": "vulnerability type",
|
|
82
|
+
"severity": "critical/high/medium/low",
|
|
83
|
+
"line": "approximate line number or area",
|
|
84
|
+
"description": "detailed description",
|
|
85
|
+
"recommendation": "how to fix"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"summary": "overall security assessment"
|
|
89
|
+
}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// OpenAI API 호출
|
|
93
|
+
async function analyzeCodeWithAI(code, filename) {
|
|
94
|
+
const prompt = createSecurityPrompt(code, filename);
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
headers: {
|
|
100
|
+
'Content-Type': 'application/json',
|
|
101
|
+
'Authorization': `Bearer ${OPENAI_API_KEY}`
|
|
102
|
+
},
|
|
103
|
+
body: JSON.stringify({
|
|
104
|
+
model: 'gpt-4o',
|
|
105
|
+
messages: [
|
|
106
|
+
{
|
|
107
|
+
role: 'system',
|
|
108
|
+
content: 'You are a security expert specializing in code security analysis. Provide detailed, actionable security assessments in JSON format.'
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
role: 'user',
|
|
112
|
+
content: prompt
|
|
113
|
+
}
|
|
114
|
+
],
|
|
115
|
+
temperature: 0.3,
|
|
116
|
+
response_format: { type: "json_object" }
|
|
117
|
+
})
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (!response.ok) {
|
|
121
|
+
throw new Error(`OpenAI API error: ${response.status} ${response.statusText}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const data = await response.json();
|
|
125
|
+
const content = data.choices[0].message.content;
|
|
126
|
+
return JSON.parse(content);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error(`${colors.red}Error calling OpenAI API: ${error.message}${colors.reset}`);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 보안 이슈 출력
|
|
134
|
+
function printSecurityIssues(filename, analysis) {
|
|
135
|
+
if (!analysis.has_issues) {
|
|
136
|
+
console.log(`${colors.green}✓ ${filename}: No security issues found${colors.reset}`);
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
console.log(`\n${colors.red}⚠️ Security issues found in ${filename}${colors.reset}`);
|
|
141
|
+
console.log(`${colors.yellow}Severity: ${analysis.severity.toUpperCase()}${colors.reset}`);
|
|
142
|
+
console.log(`\n${analysis.summary}\n`);
|
|
143
|
+
|
|
144
|
+
analysis.issues.forEach((issue, index) => {
|
|
145
|
+
const severityColor = {
|
|
146
|
+
critical: colors.red,
|
|
147
|
+
high: colors.red,
|
|
148
|
+
medium: colors.yellow,
|
|
149
|
+
low: colors.blue
|
|
150
|
+
}[issue.severity] || colors.reset;
|
|
151
|
+
|
|
152
|
+
console.log(`${index + 1}. ${severityColor}[${issue.severity.toUpperCase()}]${colors.reset} ${issue.type}`);
|
|
153
|
+
console.log(` Location: ${issue.line}`);
|
|
154
|
+
console.log(` ${issue.description}`);
|
|
155
|
+
console.log(` ${colors.green}Fix: ${issue.recommendation}${colors.reset}\n`);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
return analysis.severity === 'critical' || analysis.severity === 'high';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 메인 실행
|
|
162
|
+
async function main() {
|
|
163
|
+
console.log(`${colors.blue}🔍 Starting AI Security Analysis...${colors.reset}\n`);
|
|
164
|
+
|
|
165
|
+
const changedFiles = getChangedFiles();
|
|
166
|
+
|
|
167
|
+
if (changedFiles.length === 0) {
|
|
168
|
+
console.log(`${colors.yellow}No code files changed. Skipping AI security check.${colors.reset}`);
|
|
169
|
+
process.exit(0);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
console.log(`Analyzing ${changedFiles.length} file(s):\n`);
|
|
173
|
+
changedFiles.forEach(f => console.log(` - ${f}`));
|
|
174
|
+
console.log('');
|
|
175
|
+
|
|
176
|
+
let hasBlockingIssues = false;
|
|
177
|
+
let totalIssues = 0;
|
|
178
|
+
|
|
179
|
+
for (const file of changedFiles) {
|
|
180
|
+
try {
|
|
181
|
+
const code = fs.readFileSync(file, 'utf-8');
|
|
182
|
+
|
|
183
|
+
// 파일이 너무 크면 스킵
|
|
184
|
+
if (code.length > 50000) {
|
|
185
|
+
console.log(`${colors.yellow}⚠️ ${file}: File too large, skipping${colors.reset}`);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
console.log(`Analyzing ${file}...`);
|
|
190
|
+
const analysis = await analyzeCodeWithAI(code, file);
|
|
191
|
+
|
|
192
|
+
if (analysis) {
|
|
193
|
+
const hasIssues = printSecurityIssues(file, analysis);
|
|
194
|
+
if (hasIssues) {
|
|
195
|
+
hasBlockingIssues = true;
|
|
196
|
+
totalIssues += analysis.issues.length;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
} catch (error) {
|
|
200
|
+
console.error(`${colors.red}Error analyzing ${file}: ${error.message}${colors.reset}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
console.log(`\n${colors.blue}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
|
|
205
|
+
console.log(`${colors.blue}📊 Security Analysis Summary${colors.reset}`);
|
|
206
|
+
console.log(`${colors.blue}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${colors.reset}`);
|
|
207
|
+
console.log(`Files analyzed: ${changedFiles.length}`);
|
|
208
|
+
console.log(`Security issues found: ${totalIssues}`);
|
|
209
|
+
|
|
210
|
+
if (hasBlockingIssues) {
|
|
211
|
+
console.log(`\n${colors.red}❌ CRITICAL/HIGH severity security issues found!${colors.reset}`);
|
|
212
|
+
console.log(`${colors.red}Deployment blocked. Please fix the issues above.${colors.reset}\n`);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
} else {
|
|
215
|
+
console.log(`\n${colors.green}✅ No blocking security issues found${colors.reset}\n`);
|
|
216
|
+
process.exit(0);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
main().catch(error => {
|
|
221
|
+
console.error(`${colors.red}Fatal error: ${error.message}${colors.reset}`);
|
|
222
|
+
process.exit(1);
|
|
223
|
+
});
|
|
224
|
+
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# NPM 배포 스크립트
|
|
4
|
+
# 사용법: ./scripts/release.sh [patch|minor|major]
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
# 색상 정의
|
|
9
|
+
RED='\033[0;31m'
|
|
10
|
+
GREEN='\033[0;32m'
|
|
11
|
+
YELLOW='\033[1;33m'
|
|
12
|
+
BLUE='\033[0;34m'
|
|
13
|
+
NC='\033[0m' # No Color
|
|
14
|
+
|
|
15
|
+
# 버전 타입 확인
|
|
16
|
+
VERSION_TYPE=${1:-patch}
|
|
17
|
+
|
|
18
|
+
if [[ ! "$VERSION_TYPE" =~ ^(patch|minor|major|prerelease)$ ]]; then
|
|
19
|
+
echo -e "${RED}Error: Invalid version type. Use: patch, minor, major, or prerelease${NC}"
|
|
20
|
+
exit 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
echo -e "${BLUE}=== CursorFlow Release Script ===${NC}\n"
|
|
24
|
+
|
|
25
|
+
# Git 상태 확인
|
|
26
|
+
echo -e "${YELLOW}Checking git status...${NC}"
|
|
27
|
+
if [[ -n $(git status -s) ]]; then
|
|
28
|
+
echo -e "${RED}Error: Working directory is not clean. Commit or stash your changes first.${NC}"
|
|
29
|
+
git status -s
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
echo -e "${GREEN}✓ Working directory is clean${NC}\n"
|
|
33
|
+
|
|
34
|
+
# 현재 브랜치 확인
|
|
35
|
+
CURRENT_BRANCH=$(git branch --show-current)
|
|
36
|
+
echo -e "${YELLOW}Current branch: ${CURRENT_BRANCH}${NC}"
|
|
37
|
+
if [[ "$CURRENT_BRANCH" != "main" ]] && [[ "$CURRENT_BRANCH" != "master" ]]; then
|
|
38
|
+
echo -e "${YELLOW}Warning: You are not on main/master branch${NC}"
|
|
39
|
+
read -p "Continue anyway? (y/N): " -n 1 -r
|
|
40
|
+
echo
|
|
41
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# 최신 코드 받기
|
|
47
|
+
echo -e "\n${YELLOW}Pulling latest changes...${NC}"
|
|
48
|
+
git pull origin "$CURRENT_BRANCH"
|
|
49
|
+
echo -e "${GREEN}✓ Up to date${NC}\n"
|
|
50
|
+
|
|
51
|
+
# 현재 버전 확인
|
|
52
|
+
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
53
|
+
echo -e "${BLUE}Current version: ${CURRENT_VERSION}${NC}"
|
|
54
|
+
|
|
55
|
+
# 버전 업데이트
|
|
56
|
+
echo -e "\n${YELLOW}Updating version ($VERSION_TYPE)...${NC}"
|
|
57
|
+
NEW_VERSION=$(npm version $VERSION_TYPE --no-git-tag-version)
|
|
58
|
+
echo -e "${GREEN}✓ New version: ${NEW_VERSION}${NC}\n"
|
|
59
|
+
|
|
60
|
+
# CHANGELOG 업데이트 확인
|
|
61
|
+
echo -e "${YELLOW}Have you updated CHANGELOG.md for this release?${NC}"
|
|
62
|
+
read -p "Press Enter to edit CHANGELOG.md, or 's' to skip: " -n 1 -r
|
|
63
|
+
echo
|
|
64
|
+
if [[ ! $REPLY =~ ^[Ss]$ ]]; then
|
|
65
|
+
${EDITOR:-nano} CHANGELOG.md
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# 변경사항 커밋
|
|
69
|
+
echo -e "\n${YELLOW}Committing version bump...${NC}"
|
|
70
|
+
git add package.json CHANGELOG.md
|
|
71
|
+
git commit -m "chore: bump version to ${NEW_VERSION}"
|
|
72
|
+
echo -e "${GREEN}✓ Version bump committed${NC}\n"
|
|
73
|
+
|
|
74
|
+
# 태그 생성
|
|
75
|
+
TAG_NAME="v${NEW_VERSION#v}"
|
|
76
|
+
echo -e "${YELLOW}Creating tag: ${TAG_NAME}${NC}"
|
|
77
|
+
git tag -a "$TAG_NAME" -m "Release ${TAG_NAME}"
|
|
78
|
+
echo -e "${GREEN}✓ Tag created${NC}\n"
|
|
79
|
+
|
|
80
|
+
# 푸시 전 확인
|
|
81
|
+
echo -e "${BLUE}Ready to push:${NC}"
|
|
82
|
+
echo -e " - Commit: chore: bump version to ${NEW_VERSION}"
|
|
83
|
+
echo -e " - Tag: ${TAG_NAME}"
|
|
84
|
+
echo -e " - Branch: ${CURRENT_BRANCH}"
|
|
85
|
+
echo
|
|
86
|
+
|
|
87
|
+
read -p "Push to GitHub and trigger deployment? (y/N): " -n 1 -r
|
|
88
|
+
echo
|
|
89
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
90
|
+
echo -e "${YELLOW}Aborted. To push manually later:${NC}"
|
|
91
|
+
echo -e " git push origin ${CURRENT_BRANCH}"
|
|
92
|
+
echo -e " git push origin ${TAG_NAME}"
|
|
93
|
+
exit 0
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# 푸시
|
|
97
|
+
echo -e "\n${YELLOW}Pushing to GitHub...${NC}"
|
|
98
|
+
git push origin "$CURRENT_BRANCH"
|
|
99
|
+
git push origin "$TAG_NAME"
|
|
100
|
+
echo -e "${GREEN}✓ Pushed successfully${NC}\n"
|
|
101
|
+
|
|
102
|
+
# 완료 메시지
|
|
103
|
+
echo -e "${GREEN}=== Release Process Complete! ===${NC}\n"
|
|
104
|
+
echo -e "${BLUE}Next steps:${NC}"
|
|
105
|
+
echo -e " 1. Monitor GitHub Actions: https://github.com/eungjin-cigro/cursorflow/actions"
|
|
106
|
+
echo -e " 2. Check npm package: https://www.npmjs.com/package/@litmers/cursorflow-orchestrator"
|
|
107
|
+
echo -e " 3. Verify GitHub Release: https://github.com/eungjin-cigro/cursorflow/releases/tag/${TAG_NAME}"
|
|
108
|
+
echo -e "\n${GREEN}Release ${NEW_VERSION} is being deployed! 🚀${NC}"
|
|
109
|
+
|