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.
@@ -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 a Claude Code skill generator. You MUST respond with ONLY a valid JSON object. No markdown, no code blocks, no explanations - just pure JSON.
7
+ const SYSTEM_PROMPT = `You are an expert Claude Code skill generator. Generate production-quality skills with complete, working code.
8
8
 
9
- Your response must follow this exact JSON schema:
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 readable skill name",
14
+ "skillName": "Human Readable Skill Name",
13
15
  "skillId": "skill-id-in-kebab-case",
14
- "description": "Brief description of what this skill does",
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 here",
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 content here",
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 must follow this format:
36
+ ## SKILL.md Format (MUST follow exactly)
37
+
35
38
  ---
36
39
  name: skill-id
37
- description: One line 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
- ## When to use
43
- - Use case 1
44
- - Use case 2
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
- ## Usage
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
- ## Parameters
52
- - \`--param1\`: Description
171
+ if __name__ == "__main__":
172
+ main()
173
+ \\\`\\\`\\\`
53
174
 
54
- ## Example
55
- [Usage example]
175
+ ## Critical Rules
56
176
 
57
- RULES:
58
- 1. Generate COMPLETE, WORKING code - no placeholders
59
- 2. Include proper error handling with try-except
60
- 3. Use Korean for user-facing messages
61
- 4. Scripts run with .venv/bin/python (project local virtual environment)
62
- 5. List all required packages in requirements.txt
63
- 6. RESPOND WITH JSON ONLY - NO OTHER TEXT`;
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.18",
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