makecc 0.2.16 → 0.2.17

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.
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>makecc</title>
8
- <script type="module" crossorigin src="/assets/index-Bir6nP2a.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-Dlx6ST3a.css">
8
+ <script type="module" crossorigin src="/assets/index-CzDuVmB7.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-1V3GQ_8q.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -219,7 +219,7 @@ app.post('/api/generate/skill', async (req, res) => {
219
219
  app.get('/api/load/claude-config', async (req, res) => {
220
220
  try {
221
221
  const config = await configLoaderService.loadAll();
222
- console.log(`Loaded config: ${config.skills.length} skills, ${config.subagents.length} agents, ` +
222
+ console.log(`Loaded config: ${config.skills.length} skills, ${config.agents.length} agents, ` +
223
223
  `${config.commands.length} commands, ${config.hooks.length} hooks`);
224
224
  res.json(config);
225
225
  }
@@ -161,7 +161,7 @@ function findNewFiles(before, after) {
161
161
  */
162
162
  export function buildNodePrompt(nodeType, nodeData, previousResults) {
163
163
  const lines = [];
164
- if (nodeType === 'subagent') {
164
+ if (nodeType === 'agent') {
165
165
  const role = nodeData.role || 'assistant';
166
166
  const description = nodeData.description || '';
167
167
  const systemPrompt = nodeData.systemPrompt || '';
@@ -21,7 +21,7 @@ export class ClaudeService {
21
21
  switch (node.type) {
22
22
  case 'input':
23
23
  return this.executeInputNode(node.id, node.data);
24
- case 'subagent':
24
+ case 'agent':
25
25
  return this.executeSubagentNode(node.id, node.data, onProgress);
26
26
  case 'skill':
27
27
  return this.executeSkillNode(node.id, node.data);
@@ -9,13 +9,13 @@ export class ConfigLoaderService {
9
9
  * .claude/ 디렉토리에서 모든 설정 로드
10
10
  */
11
11
  async loadAll() {
12
- const [skills, subagents, commands, hooks] = await Promise.all([
12
+ const [skills, agents, commands, hooks] = await Promise.all([
13
13
  this.loadSkills(),
14
14
  this.loadSubagents(),
15
15
  this.loadCommands(),
16
16
  this.loadHooks(),
17
17
  ]);
18
- return { skills, subagents, commands, hooks };
18
+ return { skills, agents, commands, hooks };
19
19
  }
20
20
  /**
21
21
  * .claude/skills/ 에서 스킬 로드
@@ -56,7 +56,7 @@ export class ConfigLoaderService {
56
56
  */
57
57
  async loadSubagents() {
58
58
  const agentsDir = path.join(this.projectRoot, '.claude', 'agents');
59
- const subagents = [];
59
+ const agents = [];
60
60
  try {
61
61
  const entries = await fs.readdir(agentsDir, { withFileTypes: true });
62
62
  for (const entry of entries) {
@@ -66,9 +66,9 @@ export class ConfigLoaderService {
66
66
  const content = await fs.readFile(agentPath, 'utf-8');
67
67
  const parsed = this.parseFrontmatter(content);
68
68
  const agentName = entry.name.replace('.md', '');
69
- subagents.push({
70
- id: `subagent-${agentName}`,
71
- type: 'subagent',
69
+ agents.push({
70
+ id: `agent-${agentName}`,
71
+ type: 'agent',
72
72
  label: parsed.frontmatter.name || agentName,
73
73
  description: parsed.frontmatter.description || '',
74
74
  tools: this.parseList(parsed.frontmatter.tools),
@@ -86,7 +86,7 @@ export class ConfigLoaderService {
86
86
  catch {
87
87
  // agents 디렉토리가 없으면 빈 배열 반환
88
88
  }
89
- return subagents;
89
+ return agents;
90
90
  }
91
91
  /**
92
92
  * .claude/commands/ 에서 커맨드 로드
@@ -13,10 +13,8 @@ export class NodeSyncService {
13
13
  switch (node.type) {
14
14
  case 'skill':
15
15
  return await this.syncSkillNode(node);
16
- case 'subagent':
17
- return await this.syncSubagentNode(node);
18
- case 'command':
19
- return await this.syncCommandNode(node);
16
+ case 'agent':
17
+ return await this.syncAgentNode(node);
20
18
  case 'hook':
21
19
  return await this.syncHookNode(node);
22
20
  case 'input':
@@ -50,16 +48,11 @@ export class NodeSyncService {
50
48
  await fs.rm(skillPath, { recursive: true, force: true });
51
49
  }
52
50
  break;
53
- case 'subagent':
51
+ case 'agent':
54
52
  const agentName = this.toKebabCase(node.label);
55
53
  const agentPath = path.join(this.projectRoot, '.claude', 'agents', `${agentName}.md`);
56
54
  await fs.unlink(agentPath).catch(() => { });
57
55
  break;
58
- case 'command':
59
- const cmdName = node.commandName || this.toKebabCase(node.label);
60
- const cmdPath = path.join(this.projectRoot, '.claude', 'commands', `${cmdName}.md`);
61
- await fs.unlink(cmdPath).catch(() => { });
62
- break;
63
56
  case 'hook':
64
57
  await this.removeHookFromSettings(node);
65
58
  break;
@@ -76,11 +69,11 @@ export class NodeSyncService {
76
69
  */
77
70
  async removeReferencesToNode(nodeId, nodeType, allNodes) {
78
71
  for (const relatedNode of allNodes) {
79
- if (relatedNode.type === 'subagent') {
72
+ if (relatedNode.type === 'agent') {
80
73
  // 서브에이전트의 skills 배열에서 삭제된 노드 제거
81
74
  if (relatedNode.skills?.includes(nodeId)) {
82
75
  relatedNode.skills = relatedNode.skills.filter(s => s !== nodeId);
83
- await this.syncSubagentNode(relatedNode);
76
+ await this.syncAgentNode(relatedNode);
84
77
  }
85
78
  }
86
79
  else if (relatedNode.type === 'skill') {
@@ -116,13 +109,13 @@ export class NodeSyncService {
116
109
  const sourceId = this.getNodeIdentifier(sourceNode);
117
110
  const targetId = this.getNodeIdentifier(targetNode);
118
111
  // 서브에이전트 → 스킬 연결
119
- if (sourceNode.type === 'subagent' && targetNode.type === 'skill') {
112
+ if (sourceNode.type === 'agent' && targetNode.type === 'skill') {
120
113
  // 에이전트의 skills 필드 업데이트
121
114
  const skills = sourceNode.skills || [];
122
115
  if (!skills.includes(targetId)) {
123
116
  skills.push(targetId);
124
117
  sourceNode.skills = skills;
125
- await this.syncSubagentNode(sourceNode);
118
+ await this.syncAgentNode(sourceNode);
126
119
  }
127
120
  // 스킬의 upstream 필드 업데이트
128
121
  const upstream = targetNode.upstream || [];
@@ -150,13 +143,13 @@ export class NodeSyncService {
150
143
  }
151
144
  }
152
145
  // 스킬 → 서브에이전트 연결
153
- if (sourceNode.type === 'skill' && targetNode.type === 'subagent') {
146
+ if (sourceNode.type === 'skill' && targetNode.type === 'agent') {
154
147
  // 에이전트의 upstream skills 필드 업데이트
155
148
  const skills = targetNode.skills || [];
156
149
  if (!skills.includes(sourceId)) {
157
150
  skills.push(sourceId);
158
151
  targetNode.skills = skills;
159
- await this.syncSubagentNode(targetNode);
152
+ await this.syncAgentNode(targetNode);
160
153
  }
161
154
  // 스킬의 downstream 필드 업데이트
162
155
  const downstream = sourceNode.downstream || [];
@@ -167,13 +160,13 @@ export class NodeSyncService {
167
160
  }
168
161
  }
169
162
  // 서브에이전트 → 서브에이전트 연결
170
- if (sourceNode.type === 'subagent' && targetNode.type === 'subagent') {
163
+ if (sourceNode.type === 'agent' && targetNode.type === 'agent') {
171
164
  // source의 downstream agents
172
165
  const sourceDownstream = sourceNode.skills || [];
173
166
  if (!sourceDownstream.includes(targetId)) {
174
167
  sourceDownstream.push(targetId);
175
168
  sourceNode.skills = sourceDownstream;
176
- await this.syncSubagentNode(sourceNode);
169
+ await this.syncAgentNode(sourceNode);
177
170
  }
178
171
  }
179
172
  return { success: true };
@@ -205,10 +198,10 @@ export class NodeSyncService {
205
198
  const sourceId = this.getNodeIdentifier(sourceNode);
206
199
  const targetId = this.getNodeIdentifier(targetNode);
207
200
  // 서브에이전트 → 스킬 연결 해제
208
- if (sourceNode.type === 'subagent' && targetNode.type === 'skill') {
201
+ if (sourceNode.type === 'agent' && targetNode.type === 'skill') {
209
202
  // 에이전트에서 스킬 제거
210
203
  sourceNode.skills = (sourceNode.skills || []).filter(s => s !== targetId);
211
- await this.syncSubagentNode(sourceNode);
204
+ await this.syncAgentNode(sourceNode);
212
205
  // 스킬에서 upstream 제거
213
206
  targetNode.upstream = (targetNode.upstream || []).filter(s => s !== sourceId);
214
207
  await this.syncSkillNode(targetNode);
@@ -221,16 +214,16 @@ export class NodeSyncService {
221
214
  await this.syncSkillNode(targetNode);
222
215
  }
223
216
  // 스킬 → 서브에이전트 연결 해제
224
- if (sourceNode.type === 'skill' && targetNode.type === 'subagent') {
217
+ if (sourceNode.type === 'skill' && targetNode.type === 'agent') {
225
218
  targetNode.skills = (targetNode.skills || []).filter(s => s !== sourceId);
226
- await this.syncSubagentNode(targetNode);
219
+ await this.syncAgentNode(targetNode);
227
220
  sourceNode.downstream = (sourceNode.downstream || []).filter(s => s !== targetId);
228
221
  await this.syncSkillNode(sourceNode);
229
222
  }
230
223
  // 서브에이전트 → 서브에이전트 연결 해제
231
- if (sourceNode.type === 'subagent' && targetNode.type === 'subagent') {
224
+ if (sourceNode.type === 'agent' && targetNode.type === 'agent') {
232
225
  sourceNode.skills = (sourceNode.skills || []).filter(s => s !== targetId);
233
- await this.syncSubagentNode(sourceNode);
226
+ await this.syncAgentNode(sourceNode);
234
227
  }
235
228
  return { success: true };
236
229
  }
@@ -292,7 +285,7 @@ ${frontmatterStr}
292
285
  await fs.writeFile(skillMdPath, content, 'utf-8');
293
286
  return { success: true, path: skillPath };
294
287
  }
295
- async syncSubagentNode(node) {
288
+ async syncAgentNode(node) {
296
289
  const agentName = this.toKebabCase(node.label);
297
290
  const agentsDir = path.join(this.projectRoot, '.claude', 'agents');
298
291
  const agentPath = path.join(agentsDir, `${agentName}.md`);
@@ -368,22 +361,6 @@ ${body}
368
361
  }
369
362
  return { frontmatter, body };
370
363
  }
371
- async syncCommandNode(node) {
372
- const cmdName = node.commandName || this.toKebabCase(node.label);
373
- const commandsDir = path.join(this.projectRoot, '.claude', 'commands');
374
- const cmdPath = path.join(commandsDir, `${cmdName}.md`);
375
- await fs.mkdir(commandsDir, { recursive: true });
376
- const content = node.commandContent || `---
377
- description: ${node.description || node.label}
378
- ---
379
-
380
- ${node.description || '커맨드 내용을 여기에 작성하세요'}
381
-
382
- $ARGUMENTS
383
- `;
384
- await fs.writeFile(cmdPath, content, 'utf-8');
385
- return { success: true, path: cmdPath };
386
- }
387
364
  async syncHookNode(node) {
388
365
  const settingsPath = path.join(this.projectRoot, '.claude', 'settings.json');
389
366
  // 기존 settings 읽기
@@ -28,7 +28,7 @@ function generateClaudePrompt(options) {
28
28
  executionOrder.forEach((node) => {
29
29
  if (node.type === 'input')
30
30
  return;
31
- if (node.type === 'subagent') {
31
+ if (node.type === 'agent') {
32
32
  const data = node.data;
33
33
  lines.push(`${stepNum}. **${data.label}** (${data.role})`);
34
34
  if (data.description) {
@@ -22,7 +22,7 @@ const SYSTEM_PROMPT = `당신은 Claude Code 워크플로우 설계 전문가입
22
22
  ## 사용 가능한 공식 스킬
23
23
  ${AVAILABLE_SKILLS.map(s => `- ${s.id}: ${s.description}`).join('\n')}
24
24
 
25
- ## 사용 가능한 도구 (subagent의 tools에 사용)
25
+ ## 사용 가능한 도구 (agent의 tools에 사용)
26
26
  ${AVAILABLE_TOOLS.join(', ')}
27
27
 
28
28
  ## 응답 형식 (JSON)
@@ -42,7 +42,7 @@ ${AVAILABLE_TOOLS.join(', ')}
42
42
  }
43
43
  },
44
44
  {
45
- "type": "subagent",
45
+ "type": "agent",
46
46
  "label": "에이전트 이름",
47
47
  "description": "에이전트 역할 설명",
48
48
  "config": {
@@ -90,7 +90,7 @@ ${AVAILABLE_TOOLS.join(', ')}
90
90
  1. 항상 input 노드로 시작하고 output 노드로 종료
91
91
  2. 기존 공식 스킬로 가능하면 official 스킬 사용
92
92
  3. 새로운 기능이 필요하면 custom 스킬 생성 (skillContent에 SKILL.md 형식)
93
- 4. subagent는 복잡한 추론이나 다단계 작업에 사용
93
+ 4. agent는 복잡한 추론이나 다단계 작업에 사용
94
94
  5. edges의 from/to는 nodes 배열의 인덱스 (0부터 시작)
95
95
  6. 순차적으로 연결되지 않아도 됨 (병렬 처리, 합류 가능)
96
96
  7. systemPrompt는 구체적이고 실행 가능한 지시사항으로 작성
@@ -115,8 +115,8 @@ ${AVAILABLE_TOOLS.join(', ')}
115
115
  "description": "데이터를 분석하고 보고서를 작성하는 워크플로우",
116
116
  "nodes": [
117
117
  { "type": "input", "label": "데이터 파일", "description": "분석할 데이터 파일", "config": { "inputType": "file" } },
118
- { "type": "subagent", "label": "데이터 분석가", "description": "데이터를 분석하고 인사이트 도출", "config": { "role": "analyst", "tools": ["Read", "Grep", "Glob"], "model": "sonnet", "systemPrompt": "주어진 데이터를 분석하여 핵심 인사이트를 도출하세요. 통계적 요약, 트렌드, 이상치를 파악하세요." } },
119
- { "type": "subagent", "label": "보고서 작성자", "description": "분석 결과로 보고서 작성", "config": { "role": "writer", "tools": ["Read", "Write"], "model": "opus", "systemPrompt": "분석 결과를 바탕으로 경영진을 위한 간결하고 명확한 보고서를 작성하세요." } },
118
+ { "type": "agent", "label": "데이터 분석가", "description": "데이터를 분석하고 인사이트 도출", "config": { "role": "analyst", "tools": ["Read", "Grep", "Glob"], "model": "sonnet", "systemPrompt": "주어진 데이터를 분석하여 핵심 인사이트를 도출하세요. 통계적 요약, 트렌드, 이상치를 파악하세요." } },
119
+ { "type": "agent", "label": "보고서 작성자", "description": "분석 결과로 보고서 작성", "config": { "role": "writer", "tools": ["Read", "Write"], "model": "opus", "systemPrompt": "분석 결과를 바탕으로 경영진을 위한 간결하고 명확한 보고서를 작성하세요." } },
120
120
  { "type": "output", "label": "분석 보고서", "description": "최종 분석 보고서", "config": { "outputType": "document" } }
121
121
  ],
122
122
  "edges": [{ "from": 0, "to": 1 }, { "from": 1, "to": 2 }, { "from": 2, "to": 3 }]
@@ -57,7 +57,7 @@ export class WorkflowExecutionService {
57
57
  switch (node.type) {
58
58
  case 'input':
59
59
  return this.executeInputNode(node, context.inputs);
60
- case 'subagent':
60
+ case 'agent':
61
61
  return this.executeSubagentNode(node, previousResults, onProgress, onLog);
62
62
  case 'skill':
63
63
  return this.executeSkillNode(node, previousResults, onProgress, onLog);
@@ -89,7 +89,7 @@ export class WorkflowExecutionService {
89
89
  onProgress?.({ nodeId: node.id, status: 'running', progress: 20 });
90
90
  onLog?.('info', `claude -c 실행 중: ${data.label} (${data.role})`);
91
91
  // 프롬프트 생성
92
- const prompt = buildNodePrompt('subagent', data, previousResults);
92
+ const prompt = buildNodePrompt('agent', data, previousResults);
93
93
  try {
94
94
  onProgress?.({ nodeId: node.id, status: 'running', progress: 40 });
95
95
  const result = await executeClaudeCli({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makecc",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
4
4
  "type": "module",
5
5
  "description": "Visual workflow builder for Claude Code agents and skills",
6
6
  "keywords": [
package/server/index.ts CHANGED
@@ -242,7 +242,7 @@ app.get('/api/load/claude-config', async (req, res) => {
242
242
  try {
243
243
  const config = await configLoaderService.loadAll();
244
244
  console.log(
245
- `Loaded config: ${config.skills.length} skills, ${config.subagents.length} agents, ` +
245
+ `Loaded config: ${config.skills.length} skills, ${config.agents.length} agents, ` +
246
246
  `${config.commands.length} commands, ${config.hooks.length} hooks`
247
247
  );
248
248
  res.json(config);
@@ -208,7 +208,7 @@ export function buildNodePrompt(
208
208
  ): string {
209
209
  const lines: string[] = [];
210
210
 
211
- if (nodeType === 'subagent') {
211
+ if (nodeType === 'agent') {
212
212
  const role = nodeData.role as string || 'assistant';
213
213
  const description = nodeData.description as string || '';
214
214
  const systemPrompt = nodeData.systemPrompt as string || '';
@@ -40,7 +40,7 @@ export class ClaudeService {
40
40
  case 'input':
41
41
  return this.executeInputNode(node.id, node.data as InputNodeData);
42
42
 
43
- case 'subagent':
43
+ case 'agent':
44
44
  return this.executeSubagentNode(
45
45
  node.id,
46
46
  node.data as SubagentNodeData,
@@ -12,7 +12,7 @@ interface LoadedSkill {
12
12
 
13
13
  interface LoadedSubagent {
14
14
  id: string;
15
- type: 'subagent';
15
+ type: 'agent';
16
16
  label: string;
17
17
  description: string;
18
18
  tools: string[];
@@ -44,7 +44,7 @@ export type LoadedNode = LoadedSkill | LoadedSubagent | LoadedCommand | LoadedHo
44
44
 
45
45
  export interface ClaudeConfig {
46
46
  skills: LoadedSkill[];
47
- subagents: LoadedSubagent[];
47
+ agents: LoadedSubagent[];
48
48
  commands: LoadedCommand[];
49
49
  hooks: LoadedHook[];
50
50
  }
@@ -60,14 +60,14 @@ export class ConfigLoaderService {
60
60
  * .claude/ 디렉토리에서 모든 설정 로드
61
61
  */
62
62
  async loadAll(): Promise<ClaudeConfig> {
63
- const [skills, subagents, commands, hooks] = await Promise.all([
63
+ const [skills, agents, commands, hooks] = await Promise.all([
64
64
  this.loadSkills(),
65
65
  this.loadSubagents(),
66
66
  this.loadCommands(),
67
67
  this.loadHooks(),
68
68
  ]);
69
69
 
70
- return { skills, subagents, commands, hooks };
70
+ return { skills, agents, commands, hooks };
71
71
  }
72
72
 
73
73
  /**
@@ -112,7 +112,7 @@ export class ConfigLoaderService {
112
112
  */
113
113
  async loadSubagents(): Promise<LoadedSubagent[]> {
114
114
  const agentsDir = path.join(this.projectRoot, '.claude', 'agents');
115
- const subagents: LoadedSubagent[] = [];
115
+ const agents: LoadedSubagent[] = [];
116
116
 
117
117
  try {
118
118
  const entries = await fs.readdir(agentsDir, { withFileTypes: true });
@@ -125,9 +125,9 @@ export class ConfigLoaderService {
125
125
  const parsed = this.parseFrontmatter(content);
126
126
  const agentName = entry.name.replace('.md', '');
127
127
 
128
- subagents.push({
129
- id: `subagent-${agentName}`,
130
- type: 'subagent',
128
+ agents.push({
129
+ id: `agent-${agentName}`,
130
+ type: 'agent',
131
131
  label: parsed.frontmatter.name || agentName,
132
132
  description: parsed.frontmatter.description || '',
133
133
  tools: this.parseList(parsed.frontmatter.tools),
@@ -144,7 +144,7 @@ export class ConfigLoaderService {
144
144
  // agents 디렉토리가 없으면 빈 배열 반환
145
145
  }
146
146
 
147
- return subagents;
147
+ return agents;
148
148
  }
149
149
 
150
150
  /**
@@ -3,7 +3,7 @@ import * as path from 'path';
3
3
 
4
4
  interface NodeData {
5
5
  id: string;
6
- type: 'skill' | 'subagent' | 'command' | 'hook' | 'input' | 'output';
6
+ type: 'skill' | 'agent' | 'hook' | 'input' | 'output';
7
7
  label: string;
8
8
  description?: string;
9
9
  // Skill specific
@@ -11,14 +11,11 @@ interface NodeData {
11
11
  skillPath?: string;
12
12
  upstream?: string[]; // Connected upstream agents/skills
13
13
  downstream?: string[]; // Connected downstream agents/skills
14
- // Subagent specific
14
+ // Agent specific
15
15
  tools?: string[];
16
16
  model?: string;
17
17
  skills?: string[]; // Connected downstream skills
18
18
  systemPrompt?: string;
19
- // Command specific
20
- commandName?: string;
21
- commandContent?: string;
22
19
  // Hook specific
23
20
  hookEvent?: string;
24
21
  hookMatcher?: string;
@@ -47,10 +44,8 @@ export class NodeSyncService {
47
44
  switch (node.type) {
48
45
  case 'skill':
49
46
  return await this.syncSkillNode(node);
50
- case 'subagent':
51
- return await this.syncSubagentNode(node);
52
- case 'command':
53
- return await this.syncCommandNode(node);
47
+ case 'agent':
48
+ return await this.syncAgentNode(node);
54
49
  case 'hook':
55
50
  return await this.syncHookNode(node);
56
51
  case 'input':
@@ -86,16 +81,11 @@ export class NodeSyncService {
86
81
  await fs.rm(skillPath, { recursive: true, force: true });
87
82
  }
88
83
  break;
89
- case 'subagent':
84
+ case 'agent':
90
85
  const agentName = this.toKebabCase(node.label);
91
86
  const agentPath = path.join(this.projectRoot, '.claude', 'agents', `${agentName}.md`);
92
87
  await fs.unlink(agentPath).catch(() => {});
93
88
  break;
94
- case 'command':
95
- const cmdName = node.commandName || this.toKebabCase(node.label);
96
- const cmdPath = path.join(this.projectRoot, '.claude', 'commands', `${cmdName}.md`);
97
- await fs.unlink(cmdPath).catch(() => {});
98
- break;
99
89
  case 'hook':
100
90
  await this.removeHookFromSettings(node);
101
91
  break;
@@ -112,11 +102,11 @@ export class NodeSyncService {
112
102
  */
113
103
  private async removeReferencesToNode(nodeId: string, nodeType: string, allNodes: NodeData[]): Promise<void> {
114
104
  for (const relatedNode of allNodes) {
115
- if (relatedNode.type === 'subagent') {
105
+ if (relatedNode.type === 'agent') {
116
106
  // 서브에이전트의 skills 배열에서 삭제된 노드 제거
117
107
  if (relatedNode.skills?.includes(nodeId)) {
118
108
  relatedNode.skills = relatedNode.skills.filter(s => s !== nodeId);
119
- await this.syncSubagentNode(relatedNode);
109
+ await this.syncAgentNode(relatedNode);
120
110
  }
121
111
  } else if (relatedNode.type === 'skill') {
122
112
  let updated = false;
@@ -155,13 +145,13 @@ export class NodeSyncService {
155
145
  const targetId = this.getNodeIdentifier(targetNode);
156
146
 
157
147
  // 서브에이전트 → 스킬 연결
158
- if (sourceNode.type === 'subagent' && targetNode.type === 'skill') {
148
+ if (sourceNode.type === 'agent' && targetNode.type === 'skill') {
159
149
  // 에이전트의 skills 필드 업데이트
160
150
  const skills = sourceNode.skills || [];
161
151
  if (!skills.includes(targetId)) {
162
152
  skills.push(targetId);
163
153
  sourceNode.skills = skills;
164
- await this.syncSubagentNode(sourceNode);
154
+ await this.syncAgentNode(sourceNode);
165
155
  }
166
156
 
167
157
  // 스킬의 upstream 필드 업데이트
@@ -193,13 +183,13 @@ export class NodeSyncService {
193
183
  }
194
184
 
195
185
  // 스킬 → 서브에이전트 연결
196
- if (sourceNode.type === 'skill' && targetNode.type === 'subagent') {
186
+ if (sourceNode.type === 'skill' && targetNode.type === 'agent') {
197
187
  // 에이전트의 upstream skills 필드 업데이트
198
188
  const skills = targetNode.skills || [];
199
189
  if (!skills.includes(sourceId)) {
200
190
  skills.push(sourceId);
201
191
  targetNode.skills = skills;
202
- await this.syncSubagentNode(targetNode);
192
+ await this.syncAgentNode(targetNode);
203
193
  }
204
194
 
205
195
  // 스킬의 downstream 필드 업데이트
@@ -212,13 +202,13 @@ export class NodeSyncService {
212
202
  }
213
203
 
214
204
  // 서브에이전트 → 서브에이전트 연결
215
- if (sourceNode.type === 'subagent' && targetNode.type === 'subagent') {
205
+ if (sourceNode.type === 'agent' && targetNode.type === 'agent') {
216
206
  // source의 downstream agents
217
207
  const sourceDownstream = sourceNode.skills || [];
218
208
  if (!sourceDownstream.includes(targetId)) {
219
209
  sourceDownstream.push(targetId);
220
210
  sourceNode.skills = sourceDownstream;
221
- await this.syncSubagentNode(sourceNode);
211
+ await this.syncAgentNode(sourceNode);
222
212
  }
223
213
  }
224
214
 
@@ -255,10 +245,10 @@ export class NodeSyncService {
255
245
  const targetId = this.getNodeIdentifier(targetNode);
256
246
 
257
247
  // 서브에이전트 → 스킬 연결 해제
258
- if (sourceNode.type === 'subagent' && targetNode.type === 'skill') {
248
+ if (sourceNode.type === 'agent' && targetNode.type === 'skill') {
259
249
  // 에이전트에서 스킬 제거
260
250
  sourceNode.skills = (sourceNode.skills || []).filter(s => s !== targetId);
261
- await this.syncSubagentNode(sourceNode);
251
+ await this.syncAgentNode(sourceNode);
262
252
 
263
253
  // 스킬에서 upstream 제거
264
254
  targetNode.upstream = (targetNode.upstream || []).filter(s => s !== sourceId);
@@ -275,18 +265,18 @@ export class NodeSyncService {
275
265
  }
276
266
 
277
267
  // 스킬 → 서브에이전트 연결 해제
278
- if (sourceNode.type === 'skill' && targetNode.type === 'subagent') {
268
+ if (sourceNode.type === 'skill' && targetNode.type === 'agent') {
279
269
  targetNode.skills = (targetNode.skills || []).filter(s => s !== sourceId);
280
- await this.syncSubagentNode(targetNode);
270
+ await this.syncAgentNode(targetNode);
281
271
 
282
272
  sourceNode.downstream = (sourceNode.downstream || []).filter(s => s !== targetId);
283
273
  await this.syncSkillNode(sourceNode);
284
274
  }
285
275
 
286
276
  // 서브에이전트 → 서브에이전트 연결 해제
287
- if (sourceNode.type === 'subagent' && targetNode.type === 'subagent') {
277
+ if (sourceNode.type === 'agent' && targetNode.type === 'agent') {
288
278
  sourceNode.skills = (sourceNode.skills || []).filter(s => s !== targetId);
289
- await this.syncSubagentNode(sourceNode);
279
+ await this.syncAgentNode(sourceNode);
290
280
  }
291
281
 
292
282
  return { success: true };
@@ -357,7 +347,7 @@ ${frontmatterStr}
357
347
  return { success: true, path: skillPath };
358
348
  }
359
349
 
360
- private async syncSubagentNode(node: NodeData): Promise<{ success: boolean; path?: string; error?: string }> {
350
+ private async syncAgentNode(node: NodeData): Promise<{ success: boolean; path?: string; error?: string }> {
361
351
  const agentName = this.toKebabCase(node.label);
362
352
  const agentsDir = path.join(this.projectRoot, '.claude', 'agents');
363
353
  const agentPath = path.join(agentsDir, `${agentName}.md`);
@@ -446,26 +436,6 @@ ${body}
446
436
  return { frontmatter, body };
447
437
  }
448
438
 
449
- private async syncCommandNode(node: NodeData): Promise<{ success: boolean; path?: string; error?: string }> {
450
- const cmdName = node.commandName || this.toKebabCase(node.label);
451
- const commandsDir = path.join(this.projectRoot, '.claude', 'commands');
452
- const cmdPath = path.join(commandsDir, `${cmdName}.md`);
453
-
454
- await fs.mkdir(commandsDir, { recursive: true });
455
-
456
- const content = node.commandContent || `---
457
- description: ${node.description || node.label}
458
- ---
459
-
460
- ${node.description || '커맨드 내용을 여기에 작성하세요'}
461
-
462
- $ARGUMENTS
463
- `;
464
-
465
- await fs.writeFile(cmdPath, content, 'utf-8');
466
- return { success: true, path: cmdPath };
467
- }
468
-
469
439
  private async syncHookNode(node: NodeData): Promise<{ success: boolean; path?: string; error?: string }> {
470
440
  const settingsPath = path.join(this.projectRoot, '.claude', 'settings.json');
471
441
 
@@ -49,7 +49,7 @@ function generateClaudePrompt(options: TerminalExecutionOptions): string {
49
49
  executionOrder.forEach((node) => {
50
50
  if (node.type === 'input') return;
51
51
 
52
- if (node.type === 'subagent') {
52
+ if (node.type === 'agent') {
53
53
  const data = node.data as SubagentNodeData;
54
54
  lines.push(`${stepNum}. **${data.label}** (${data.role})`);
55
55
  if (data.description) {