makecc 0.2.18 → 0.2.19
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/dist/client/assets/index-NJhP4DZc.js +69 -0
- package/dist/client/assets/index-yCwPL34L.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/server/index.js +71 -0
- package/dist/server/services/projectService.js +332 -0
- package/dist/server/services/skillGeneratorService.js +147 -26
- package/dist/server/services/workflowAIService.js +5 -3
- package/package.json +2 -1
- package/server/index.ts +75 -0
- package/server/services/projectService.ts +424 -0
- package/server/services/skillGeneratorService.ts +147 -26
- package/server/services/workflowAIService.ts +6 -3
- package/dist/client/assets/index-1V3GQ_8q.css +0 -1
- package/dist/client/assets/index-j_MJWOjN.js +0 -67
|
@@ -4,23 +4,25 @@ import * as path from 'path';
|
|
|
4
4
|
import { existsSync } from 'fs';
|
|
5
5
|
import { spawn } from 'child_process';
|
|
6
6
|
import { claudeMdService } from './claudeMdService';
|
|
7
|
-
const SYSTEM_PROMPT = `You are
|
|
7
|
+
const SYSTEM_PROMPT = `You are an expert Claude Code skill generator. Generate production-quality skills with complete, working code.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
RESPOND WITH ONLY A VALID JSON OBJECT - NO MARKDOWN, NO CODE BLOCKS, NO EXPLANATIONS.
|
|
10
|
+
|
|
11
|
+
## JSON Schema
|
|
10
12
|
|
|
11
13
|
{
|
|
12
|
-
"skillName": "Human
|
|
14
|
+
"skillName": "Human Readable Skill Name",
|
|
13
15
|
"skillId": "skill-id-in-kebab-case",
|
|
14
|
-
"description": "
|
|
16
|
+
"description": "Comprehensive description including what it does AND when to use it. Include trigger phrases in Korean. Example: 'PDF 문서에서 텍스트 추출 및 분석. \"PDF 읽어줘\", \"PDF 분석해줘\", \"PDF에서 텍스트 추출\" 등의 요청 시 사용.'",
|
|
15
17
|
"files": [
|
|
16
18
|
{
|
|
17
19
|
"path": "SKILL.md",
|
|
18
|
-
"content": "Full SKILL.md content
|
|
20
|
+
"content": "Full SKILL.md content (see format below)",
|
|
19
21
|
"language": "markdown"
|
|
20
22
|
},
|
|
21
23
|
{
|
|
22
24
|
"path": "scripts/main.py",
|
|
23
|
-
"content": "Full Python script
|
|
25
|
+
"content": "Full Python script (150-300 lines, production quality)",
|
|
24
26
|
"language": "python"
|
|
25
27
|
},
|
|
26
28
|
{
|
|
@@ -31,36 +33,155 @@ Your response must follow this exact JSON schema:
|
|
|
31
33
|
]
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
SKILL.md
|
|
36
|
+
## SKILL.md Format (MUST follow exactly)
|
|
37
|
+
|
|
35
38
|
---
|
|
36
39
|
name: skill-id
|
|
37
|
-
description:
|
|
40
|
+
description: Detailed description with trigger phrases. Include what it does AND specific Korean trigger phrases like "~해줘", "~만들어줘". This is the PRIMARY mechanism for skill activation.
|
|
38
41
|
---
|
|
39
42
|
|
|
40
43
|
# Skill Name
|
|
41
44
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
Brief description of what this skill does.
|
|
46
|
+
|
|
47
|
+
## 실행 전 요구사항 (필수)
|
|
48
|
+
|
|
49
|
+
List any prerequisites:
|
|
50
|
+
- API keys needed (with instructions to check/request)
|
|
51
|
+
- Environment setup
|
|
52
|
+
- Dependencies
|
|
53
|
+
|
|
54
|
+
## 빠른 시작
|
|
55
|
+
|
|
56
|
+
\\\`\\\`\\\`bash
|
|
57
|
+
.venv/bin/python .claude/skills/skill-id/scripts/main.py \\\\
|
|
58
|
+
--required-arg "value" \\\\
|
|
59
|
+
--output output.ext
|
|
60
|
+
\\\`\\\`\\\`
|
|
61
|
+
|
|
62
|
+
## 스크립트 옵션
|
|
63
|
+
|
|
64
|
+
| 옵션 | 설명 | 기본값 |
|
|
65
|
+
|------|------|--------|
|
|
66
|
+
| \\\`--arg1\\\`, \\\`-a\\\` | Description | default |
|
|
67
|
+
| \\\`--output\\\`, \\\`-o\\\` | 출력 경로 (필수) | - |
|
|
68
|
+
|
|
69
|
+
## 사용 예시
|
|
70
|
+
|
|
71
|
+
### 예시 1: Basic Usage
|
|
72
|
+
\\\`\\\`\\\`bash
|
|
73
|
+
.venv/bin/python .claude/skills/skill-id/scripts/main.py \\\\
|
|
74
|
+
--arg "value" --output result.ext
|
|
75
|
+
\\\`\\\`\\\`
|
|
76
|
+
|
|
77
|
+
### 예시 2: Advanced Usage
|
|
78
|
+
\\\`\\\`\\\`bash
|
|
79
|
+
.venv/bin/python .claude/skills/skill-id/scripts/main.py \\\\
|
|
80
|
+
--arg "value" --advanced-option
|
|
81
|
+
\\\`\\\`\\\`
|
|
82
|
+
|
|
83
|
+
## 제한사항
|
|
84
|
+
|
|
85
|
+
- List any limitations or constraints
|
|
86
|
+
|
|
87
|
+
## Python Script Requirements (scripts/main.py)
|
|
88
|
+
|
|
89
|
+
The script MUST:
|
|
90
|
+
1. Be 150-300 lines of COMPLETE, WORKING code
|
|
91
|
+
2. Use argparse with --help support
|
|
92
|
+
3. Include comprehensive error handling (try-except)
|
|
93
|
+
4. Print Korean status messages with emoji (✅ 완료, ❌ 오류, ⏳ 처리 중)
|
|
94
|
+
5. Check dependencies at startup with helpful install instructions
|
|
95
|
+
6. Support common use cases with sensible defaults
|
|
96
|
+
7. Include docstring with usage examples
|
|
97
|
+
|
|
98
|
+
## Script Template Structure
|
|
99
|
+
|
|
100
|
+
\\\`\\\`\\\`python
|
|
101
|
+
#!/usr/bin/env python3
|
|
102
|
+
"""
|
|
103
|
+
Skill Name - Brief description
|
|
104
|
+
|
|
105
|
+
Usage:
|
|
106
|
+
python main.py --arg "value" --output output.ext
|
|
107
|
+
|
|
108
|
+
Examples:
|
|
109
|
+
python main.py --input data.txt --output result.txt
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
import argparse
|
|
113
|
+
import sys
|
|
114
|
+
from pathlib import Path
|
|
115
|
+
|
|
116
|
+
def check_dependencies():
|
|
117
|
+
"""Check required packages"""
|
|
118
|
+
try:
|
|
119
|
+
import required_package
|
|
120
|
+
return True
|
|
121
|
+
except ImportError:
|
|
122
|
+
print("❌ required_package가 설치되어 있지 않습니다.")
|
|
123
|
+
print(" 설치: uv pip install --python .venv/bin/python required_package")
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
def main_function(arg1, arg2, output_path):
|
|
127
|
+
"""Main processing logic with error handling"""
|
|
128
|
+
print(f"⏳ 처리 중...")
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
# Processing logic here
|
|
132
|
+
result = process(arg1, arg2)
|
|
133
|
+
|
|
134
|
+
# Save output
|
|
135
|
+
output_file = Path(output_path)
|
|
136
|
+
output_file.parent.mkdir(parents=True, exist_ok=True)
|
|
137
|
+
|
|
138
|
+
with open(output_file, 'w') as f:
|
|
139
|
+
f.write(result)
|
|
140
|
+
|
|
141
|
+
print(f"✅ 완료!")
|
|
142
|
+
print(f" 파일: {output_file}")
|
|
143
|
+
return str(output_file)
|
|
144
|
+
|
|
145
|
+
except Exception as e:
|
|
146
|
+
print(f"❌ 오류 발생: {e}")
|
|
147
|
+
sys.exit(1)
|
|
148
|
+
|
|
149
|
+
def main():
|
|
150
|
+
parser = argparse.ArgumentParser(
|
|
151
|
+
description="Skill description",
|
|
152
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
153
|
+
epilog=\"\"\"
|
|
154
|
+
예시:
|
|
155
|
+
python main.py --input data.txt --output result.txt
|
|
156
|
+
python main.py --input data.txt --output result.txt --option
|
|
157
|
+
\"\"\"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
parser.add_argument("--input", "-i", required=True, help="입력 파일")
|
|
161
|
+
parser.add_argument("--output", "-o", required=True, help="출력 경로")
|
|
162
|
+
parser.add_argument("--option", action="store_true", help="옵션 설명")
|
|
163
|
+
|
|
164
|
+
args = parser.parse_args()
|
|
165
|
+
|
|
166
|
+
if not check_dependencies():
|
|
167
|
+
sys.exit(1)
|
|
45
168
|
|
|
46
|
-
|
|
47
|
-
\`\`\`bash
|
|
48
|
-
.venv/bin/python .claude/skills/skill-id/scripts/main.py [args]
|
|
49
|
-
\`\`\`
|
|
169
|
+
main_function(args.input, args.option, args.output)
|
|
50
170
|
|
|
51
|
-
|
|
52
|
-
|
|
171
|
+
if __name__ == "__main__":
|
|
172
|
+
main()
|
|
173
|
+
\\\`\\\`\\\`
|
|
53
174
|
|
|
54
|
-
##
|
|
55
|
-
[Usage example]
|
|
175
|
+
## Critical Rules
|
|
56
176
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
177
|
+
1. GENERATE COMPLETE, WORKING CODE - NO PLACEHOLDERS, NO "# TODO", NO "pass"
|
|
178
|
+
2. Scripts must be 150-300 lines with real implementation
|
|
179
|
+
3. Include ALL necessary imports and helper functions
|
|
180
|
+
4. Use Korean for user-facing messages, English for code/logs
|
|
181
|
+
5. description field MUST include Korean trigger phrases
|
|
182
|
+
6. SKILL.md MUST have complete usage examples with actual commands
|
|
183
|
+
7. Always include requirements.txt with specific packages needed
|
|
184
|
+
8. RESPOND WITH JSON ONLY - NO OTHER TEXT`;
|
|
64
185
|
export class SkillGeneratorService {
|
|
65
186
|
projectRoot;
|
|
66
187
|
constructor(projectRoot) {
|
|
@@ -39,7 +39,8 @@ ${AVAILABLE_TOOLS.join(', ')}
|
|
|
39
39
|
"description": "입력 설명 (한글 가능)",
|
|
40
40
|
"config": {
|
|
41
41
|
"inputType": "text",
|
|
42
|
-
"placeholder": "입력 안내"
|
|
42
|
+
"placeholder": "입력 안내",
|
|
43
|
+
"defaultValue": "워크플로우에 적합한 예시 입력값"
|
|
43
44
|
}
|
|
44
45
|
},
|
|
45
46
|
{
|
|
@@ -97,6 +98,7 @@ ${AVAILABLE_TOOLS.join(', ')}
|
|
|
97
98
|
7. systemPrompt는 구체적이고 실행 가능한 지시사항으로 작성
|
|
98
99
|
8. **중요: label은 반드시 영어로, kebab-case 형식으로 작성 (예: blog-writer, data-analyzer)**
|
|
99
100
|
9. workflowName도 영어로 작성
|
|
101
|
+
10. **필수: input 노드의 config에 반드시 defaultValue 포함 - 워크플로우 목적에 맞는 구체적인 예시 값을 한글로 제공**
|
|
100
102
|
|
|
101
103
|
## 예시
|
|
102
104
|
|
|
@@ -105,7 +107,7 @@ ${AVAILABLE_TOOLS.join(', ')}
|
|
|
105
107
|
"workflowName": "Image Generation",
|
|
106
108
|
"description": "3개의 이미지를 생성하는 워크플로우",
|
|
107
109
|
"nodes": [
|
|
108
|
-
{ "type": "input", "label": "image-prompt", "description": "생성할 이미지에 대한 설명", "config": { "inputType": "text", "placeholder": "이미지 프롬프트 입력" } },
|
|
110
|
+
{ "type": "input", "label": "image-prompt", "description": "생성할 이미지에 대한 설명", "config": { "inputType": "text", "placeholder": "이미지 프롬프트 입력", "defaultValue": "미래적인 도시 야경, 네온 사인이 빛나는 사이버펑크 스타일" } },
|
|
109
111
|
{ "type": "skill", "label": "image-generator", "description": "AI로 이미지 생성", "config": { "skillType": "official", "skillId": "image-gen-nanobanana" } },
|
|
110
112
|
{ "type": "output", "label": "generated-images", "description": "생성된 이미지 결과", "config": { "outputType": "image" } }
|
|
111
113
|
],
|
|
@@ -117,7 +119,7 @@ ${AVAILABLE_TOOLS.join(', ')}
|
|
|
117
119
|
"workflowName": "Data Analysis Report",
|
|
118
120
|
"description": "데이터를 분석하고 보고서를 작성하는 워크플로우",
|
|
119
121
|
"nodes": [
|
|
120
|
-
{ "type": "input", "label": "data-file", "description": "분석할 데이터 파일", "config": { "inputType": "file" } },
|
|
122
|
+
{ "type": "input", "label": "data-file", "description": "분석할 데이터 파일", "config": { "inputType": "file", "defaultValue": "2024년 1~3분기 매출 데이터: 1월 1200만, 2월 1350만, 3월 1100만, 4월 1500만, 5월 1650만, 6월 1400만, 7월 1800만, 8월 1750만, 9월 1900만" } },
|
|
121
123
|
{ "type": "agent", "label": "data-analyzer", "description": "데이터를 분석하고 인사이트 도출", "config": { "role": "analyst", "tools": ["Read", "Grep", "Glob"], "model": "sonnet", "systemPrompt": "주어진 데이터를 분석하여 핵심 인사이트를 도출하세요. 통계적 요약, 트렌드, 이상치를 파악하세요." } },
|
|
122
124
|
{ "type": "agent", "label": "report-writer", "description": "분석 결과로 보고서 작성", "config": { "role": "writer", "tools": ["Read", "Write"], "model": "opus", "systemPrompt": "분석 결과를 바탕으로 경영진을 위한 간결하고 명확한 보고서를 작성하세요." } },
|
|
123
125
|
{ "type": "output", "label": "analysis-report", "description": "최종 분석 보고서", "config": { "outputType": "document" } }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "makecc",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.19",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Visual workflow builder for Claude Code agents and skills",
|
|
6
6
|
"keywords": [
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"react": "^19.2.0",
|
|
56
56
|
"react-dom": "^19.2.0",
|
|
57
57
|
"react-markdown": "^10.1.0",
|
|
58
|
+
"react-router-dom": "^7.13.0",
|
|
58
59
|
"remark-gfm": "^4.0.1",
|
|
59
60
|
"sharp": "^0.34.5",
|
|
60
61
|
"socket.io": "^4.8.3",
|
package/server/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { configLoaderService } from './services/configLoaderService';
|
|
|
27
27
|
import { workflowExecutionService } from './services/workflowExecutionService';
|
|
28
28
|
import { executeInTerminal, getClaudeCommand } from './services/terminalService';
|
|
29
29
|
import { claudeMdService } from './services/claudeMdService';
|
|
30
|
+
import { projectService } from './services/projectService';
|
|
30
31
|
import type { WorkflowExecutionRequest, NodeExecutionUpdate } from './types';
|
|
31
32
|
import type { ClaudeConfigExport, SaveOptions } from './services/fileService';
|
|
32
33
|
|
|
@@ -70,6 +71,72 @@ app.get('/api/project-path', (req, res) => {
|
|
|
70
71
|
res.json({ path: fileService.getProjectPath() });
|
|
71
72
|
});
|
|
72
73
|
|
|
74
|
+
// ============================================
|
|
75
|
+
// Project Management API
|
|
76
|
+
// ============================================
|
|
77
|
+
|
|
78
|
+
// List all projects
|
|
79
|
+
app.get('/api/projects', async (req, res) => {
|
|
80
|
+
try {
|
|
81
|
+
const projects = await projectService.listProjects();
|
|
82
|
+
const gallery = projectService.getGalleryItems();
|
|
83
|
+
res.json({ projects, gallery });
|
|
84
|
+
} catch (error) {
|
|
85
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
86
|
+
console.error('List projects error:', errorMessage);
|
|
87
|
+
res.status(500).json({ message: errorMessage });
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Create a new project
|
|
92
|
+
app.post('/api/projects', async (req, res) => {
|
|
93
|
+
try {
|
|
94
|
+
const { name, description } = req.body as { name: string; description: string };
|
|
95
|
+
|
|
96
|
+
if (!name || typeof name !== 'string') {
|
|
97
|
+
return res.status(400).json({ message: 'Project name is required' });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const project = await projectService.createProject(name, description || '');
|
|
101
|
+
res.json(project);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
104
|
+
console.error('Create project error:', errorMessage);
|
|
105
|
+
res.status(500).json({ message: errorMessage });
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Get a specific project
|
|
110
|
+
app.get('/api/projects/:id', async (req, res) => {
|
|
111
|
+
try {
|
|
112
|
+
const project = await projectService.getProject(req.params.id);
|
|
113
|
+
if (!project) {
|
|
114
|
+
return res.status(404).json({ message: 'Project not found' });
|
|
115
|
+
}
|
|
116
|
+
res.json(project);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
119
|
+
res.status(500).json({ message: errorMessage });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Delete a project
|
|
124
|
+
app.delete('/api/projects/:id', async (req, res) => {
|
|
125
|
+
try {
|
|
126
|
+
await projectService.deleteProject(req.params.id);
|
|
127
|
+
res.json({ success: true });
|
|
128
|
+
} catch (error) {
|
|
129
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
130
|
+
console.error('Delete project error:', errorMessage);
|
|
131
|
+
res.status(500).json({ message: errorMessage });
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Get makecc home directory
|
|
136
|
+
app.get('/api/makecc-home', (req, res) => {
|
|
137
|
+
res.json({ path: projectService.getMakeccHome() });
|
|
138
|
+
});
|
|
139
|
+
|
|
73
140
|
// Save workflow as Claude Code configuration
|
|
74
141
|
app.post('/api/save/workflow', async (req, res) => {
|
|
75
142
|
try {
|
|
@@ -648,8 +715,16 @@ async function startServer() {
|
|
|
648
715
|
// 초기화 실패해도 서버는 시작
|
|
649
716
|
}
|
|
650
717
|
|
|
718
|
+
// 샘플 프로젝트 생성 (~/makecc에 없는 경우)
|
|
719
|
+
try {
|
|
720
|
+
await projectService.createSampleProjects();
|
|
721
|
+
} catch (error) {
|
|
722
|
+
console.error('Sample projects creation warning:', error);
|
|
723
|
+
}
|
|
724
|
+
|
|
651
725
|
httpServer.listen(PORT, () => {
|
|
652
726
|
console.log(`Server running on http://localhost:${PORT}`);
|
|
727
|
+
console.log(`makecc home: ${projectService.getMakeccHome()}`);
|
|
653
728
|
});
|
|
654
729
|
}
|
|
655
730
|
|