@team-semicolon/semo-cli 2.0.2 → 2.0.5
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 +118 -118
- package/dist/index.js +412 -170
- package/package.json +48 -48
package/README.md
CHANGED
|
@@ -1,118 +1,118 @@
|
|
|
1
|
-
# @team-semicolon/semo-cli
|
|
2
|
-
|
|
3
|
-
> SEMO CLI - AI Agent Orchestration Framework Installer
|
|
4
|
-
|
|
5
|
-
## 개요
|
|
6
|
-
|
|
7
|
-
Gemini의 하이브리드 전략에 따라 SEMO를 자동 설치하는 CLI 도구입니다.
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npx @team-semicolon/semo-cli init
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## 동작 방식
|
|
14
|
-
|
|
15
|
-
`semo init` 명령어는 다음을 자동으로 수행합니다:
|
|
16
|
-
|
|
17
|
-
### 1. White Box 설정 (Git Subtree)
|
|
18
|
-
|
|
19
|
-
에이전트가 **읽고 학습**해야 하는 지식 베이스:
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
semo-system/
|
|
23
|
-
├── semo-core/ # Layer 0: 원칙, 오케스트레이션
|
|
24
|
-
└── semo-skills/ # Layer 1: coder, tester, planner
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### 2. Black Box 설정 (MCP Server)
|
|
28
|
-
|
|
29
|
-
토큰이 격리된 **외부 연동 도구**:
|
|
30
|
-
|
|
31
|
-
```json
|
|
32
|
-
// .claude/settings.json
|
|
33
|
-
{
|
|
34
|
-
"mcpServers": {
|
|
35
|
-
"semo-integrations": {
|
|
36
|
-
"command": "npx",
|
|
37
|
-
"args": ["-y", "@team-semicolon/semo-mcp"]
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### 3. Context Mesh 초기화
|
|
44
|
-
|
|
45
|
-
세션 간 **컨텍스트 영속화**:
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
.claude/memory/
|
|
49
|
-
├── context.md # 프로젝트 상태
|
|
50
|
-
├── decisions.md # 아키텍처 결정
|
|
51
|
-
└── rules/ # 프로젝트별 규칙
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## 명령어
|
|
55
|
-
|
|
56
|
-
### init
|
|
57
|
-
|
|
58
|
-
현재 프로젝트에 SEMO를 설치합니다.
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
semo init # 기본 설치
|
|
62
|
-
semo init --force # 기존 설정 덮어쓰기
|
|
63
|
-
semo init --skip-mcp # MCP 설정 생략
|
|
64
|
-
semo init --skip-subtree # Git Subtree 생략
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### status
|
|
68
|
-
|
|
69
|
-
SEMO 설치 상태를 확인합니다.
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
semo status
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### update
|
|
76
|
-
|
|
77
|
-
SEMO를 최신 버전으로 업데이트합니다.
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
semo update
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## 설치 후 구조
|
|
84
|
-
|
|
85
|
-
```
|
|
86
|
-
your-project/
|
|
87
|
-
├── .claude/
|
|
88
|
-
│ ├── CLAUDE.md # 프로젝트 설정
|
|
89
|
-
│ ├── settings.json # MCP 서버 설정
|
|
90
|
-
│ ├── memory/ # Context Mesh
|
|
91
|
-
│ ├── agents → semo-system/semo-core/agents
|
|
92
|
-
│ └── skills → semo-system/semo-skills
|
|
93
|
-
│
|
|
94
|
-
└── semo-system/ # White Box (읽기 전용)
|
|
95
|
-
├── semo-core/
|
|
96
|
-
└── semo-skills/
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## 환경변수
|
|
100
|
-
|
|
101
|
-
MCP 연동을 위해 다음 환경변수를 설정하세요:
|
|
102
|
-
|
|
103
|
-
| 변수 | 설명 |
|
|
104
|
-
|------|------|
|
|
105
|
-
| `GITHUB_TOKEN` | GitHub API 토큰 |
|
|
106
|
-
| `SLACK_BOT_TOKEN` | Slack Bot 토큰 |
|
|
107
|
-
| `SUPABASE_URL` | Supabase 프로젝트 URL |
|
|
108
|
-
| `SUPABASE_KEY` | Supabase 서비스 키 |
|
|
109
|
-
|
|
110
|
-
## 참조
|
|
111
|
-
|
|
112
|
-
- [SEMO 레포지토리](https://github.com/semicolon-devteam/semo)
|
|
113
|
-
- [SEMO MCP Server](../mcp-server/README.md)
|
|
114
|
-
- [Gemini 하이브리드 전략](../../docs/SEMO_ARCHITECTURE_REVIEW.md)
|
|
115
|
-
|
|
116
|
-
## 라이선스
|
|
117
|
-
|
|
118
|
-
MIT
|
|
1
|
+
# @team-semicolon/semo-cli
|
|
2
|
+
|
|
3
|
+
> SEMO CLI - AI Agent Orchestration Framework Installer
|
|
4
|
+
|
|
5
|
+
## 개요
|
|
6
|
+
|
|
7
|
+
Gemini의 하이브리드 전략에 따라 SEMO를 자동 설치하는 CLI 도구입니다.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx @team-semicolon/semo-cli init
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 동작 방식
|
|
14
|
+
|
|
15
|
+
`semo init` 명령어는 다음을 자동으로 수행합니다:
|
|
16
|
+
|
|
17
|
+
### 1. White Box 설정 (Git Subtree)
|
|
18
|
+
|
|
19
|
+
에이전트가 **읽고 학습**해야 하는 지식 베이스:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
semo-system/
|
|
23
|
+
├── semo-core/ # Layer 0: 원칙, 오케스트레이션
|
|
24
|
+
└── semo-skills/ # Layer 1: coder, tester, planner
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Black Box 설정 (MCP Server)
|
|
28
|
+
|
|
29
|
+
토큰이 격리된 **외부 연동 도구**:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
// .claude/settings.json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"semo-integrations": {
|
|
36
|
+
"command": "npx",
|
|
37
|
+
"args": ["-y", "@team-semicolon/semo-mcp"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 3. Context Mesh 초기화
|
|
44
|
+
|
|
45
|
+
세션 간 **컨텍스트 영속화**:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
.claude/memory/
|
|
49
|
+
├── context.md # 프로젝트 상태
|
|
50
|
+
├── decisions.md # 아키텍처 결정
|
|
51
|
+
└── rules/ # 프로젝트별 규칙
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 명령어
|
|
55
|
+
|
|
56
|
+
### init
|
|
57
|
+
|
|
58
|
+
현재 프로젝트에 SEMO를 설치합니다.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
semo init # 기본 설치
|
|
62
|
+
semo init --force # 기존 설정 덮어쓰기
|
|
63
|
+
semo init --skip-mcp # MCP 설정 생략
|
|
64
|
+
semo init --skip-subtree # Git Subtree 생략
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### status
|
|
68
|
+
|
|
69
|
+
SEMO 설치 상태를 확인합니다.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
semo status
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### update
|
|
76
|
+
|
|
77
|
+
SEMO를 최신 버전으로 업데이트합니다.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
semo update
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 설치 후 구조
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
your-project/
|
|
87
|
+
├── .claude/
|
|
88
|
+
│ ├── CLAUDE.md # 프로젝트 설정
|
|
89
|
+
│ ├── settings.json # MCP 서버 설정
|
|
90
|
+
│ ├── memory/ # Context Mesh
|
|
91
|
+
│ ├── agents → semo-system/semo-core/agents
|
|
92
|
+
│ └── skills → semo-system/semo-skills
|
|
93
|
+
│
|
|
94
|
+
└── semo-system/ # White Box (읽기 전용)
|
|
95
|
+
├── semo-core/
|
|
96
|
+
└── semo-skills/
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 환경변수
|
|
100
|
+
|
|
101
|
+
MCP 연동을 위해 다음 환경변수를 설정하세요:
|
|
102
|
+
|
|
103
|
+
| 변수 | 설명 |
|
|
104
|
+
|------|------|
|
|
105
|
+
| `GITHUB_TOKEN` | GitHub API 토큰 |
|
|
106
|
+
| `SLACK_BOT_TOKEN` | Slack Bot 토큰 |
|
|
107
|
+
| `SUPABASE_URL` | Supabase 프로젝트 URL |
|
|
108
|
+
| `SUPABASE_KEY` | Supabase 서비스 키 |
|
|
109
|
+
|
|
110
|
+
## 참조
|
|
111
|
+
|
|
112
|
+
- [SEMO 레포지토리](https://github.com/semicolon-devteam/semo)
|
|
113
|
+
- [SEMO MCP Server](../mcp-server/README.md)
|
|
114
|
+
- [Gemini 하이브리드 전략](../../docs/SEMO_ARCHITECTURE_REVIEW.md)
|
|
115
|
+
|
|
116
|
+
## 라이선스
|
|
117
|
+
|
|
118
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -59,7 +59,7 @@ const child_process_1 = require("child_process");
|
|
|
59
59
|
const fs = __importStar(require("fs"));
|
|
60
60
|
const path = __importStar(require("path"));
|
|
61
61
|
const os = __importStar(require("os"));
|
|
62
|
-
const VERSION = "
|
|
62
|
+
const VERSION = "3.0.0-alpha";
|
|
63
63
|
// === Windows 지원 유틸리티 ===
|
|
64
64
|
const isWindows = os.platform() === "win32";
|
|
65
65
|
/**
|
|
@@ -122,18 +122,36 @@ function copyRecursive(src, dest) {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
const SEMO_REPO = "https://github.com/semicolon-devteam/semo.git";
|
|
125
|
-
// 확장 패키지 정의
|
|
125
|
+
// 확장 패키지 정의 (v3.0 구조)
|
|
126
126
|
const EXTENSION_PACKAGES = {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
127
|
+
// Business Layer
|
|
128
|
+
"biz/discovery": { name: "Discovery", desc: "아이템 발굴, 시장 조사, Epic/Task", layer: "biz", detect: [] },
|
|
129
|
+
"biz/design": { name: "Design", desc: "컨셉 설계, 목업, UX", layer: "biz", detect: [] },
|
|
130
|
+
"biz/management": { name: "Management", desc: "일정/인력/스프린트 관리", layer: "biz", detect: [] },
|
|
131
|
+
"biz/poc": { name: "PoC", desc: "빠른 PoC, 패스트트랙", layer: "biz", detect: [] },
|
|
132
|
+
// Engineering Layer
|
|
133
|
+
"eng/nextjs": { name: "Next.js", desc: "Next.js 프론트엔드 개발", layer: "eng", detect: ["next.config.js", "next.config.mjs", "next.config.ts"] },
|
|
134
|
+
"eng/spring": { name: "Spring", desc: "Spring Boot 백엔드 개발", layer: "eng", detect: ["pom.xml", "build.gradle"] },
|
|
135
|
+
"eng/ms": { name: "Microservice", desc: "마이크로서비스 아키텍처", layer: "eng", detect: [] },
|
|
136
|
+
"eng/infra": { name: "Infra", desc: "인프라/배포 관리", layer: "eng", detect: ["docker-compose.yml", "Dockerfile"] },
|
|
137
|
+
// Operations Layer
|
|
138
|
+
"ops/qa": { name: "QA", desc: "테스트/품질 관리", layer: "ops", detect: [] },
|
|
139
|
+
"ops/monitor": { name: "Monitor", desc: "서비스 현황 모니터링", layer: "ops", detect: [] },
|
|
140
|
+
"ops/improve": { name: "Improve", desc: "개선 제안", layer: "ops", detect: [] },
|
|
141
|
+
// Meta
|
|
142
|
+
meta: { name: "Meta", desc: "SEMO 프레임워크 자체 개발/관리", layer: "meta", detect: ["semo-core", "semo-skills"] },
|
|
143
|
+
};
|
|
144
|
+
// 레거시 패키지 → 새 패키지 매핑 (하위호환성)
|
|
145
|
+
const LEGACY_MAPPING = {
|
|
146
|
+
next: "eng/nextjs",
|
|
147
|
+
backend: "eng/spring",
|
|
148
|
+
ms: "eng/ms",
|
|
149
|
+
infra: "eng/infra",
|
|
150
|
+
qa: "ops/qa",
|
|
151
|
+
po: "biz/discovery",
|
|
152
|
+
pm: "biz/management",
|
|
153
|
+
design: "biz/design",
|
|
154
|
+
mvp: "biz/poc",
|
|
137
155
|
};
|
|
138
156
|
const program = new commander_1.Command();
|
|
139
157
|
program
|
|
@@ -394,13 +412,9 @@ async function setupExtensionSymlinks(cwd, packages) {
|
|
|
394
412
|
const pkgPath = path.join(semoSystemDir, pkg);
|
|
395
413
|
if (!fs.existsSync(pkgPath))
|
|
396
414
|
continue;
|
|
397
|
-
//
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
createSymlinkOrJunction(pkgPath, semoPkgLink);
|
|
401
|
-
console.log(chalk_1.default.green(` ✓ .claude/semo-${pkg} → semo-system/${pkg}`));
|
|
402
|
-
}
|
|
403
|
-
// 2. Extension의 agents를 .claude/agents/에 개별 링크
|
|
415
|
+
// Note: .claude/semo-{pkg} 링크는 생성하지 않음 (불필요)
|
|
416
|
+
// Extension의 agents/skills만 개별 링크하여 병합
|
|
417
|
+
// 1. Extension의 agents를 .claude/agents/에 개별 링크
|
|
404
418
|
const extAgentsDir = path.join(pkgPath, "agents");
|
|
405
419
|
const claudeAgentsDir = path.join(claudeDir, "agents");
|
|
406
420
|
if (fs.existsSync(extAgentsDir)) {
|
|
@@ -430,6 +444,58 @@ async function setupExtensionSymlinks(cwd, packages) {
|
|
|
430
444
|
}
|
|
431
445
|
}
|
|
432
446
|
}
|
|
447
|
+
const BASE_MCP_SERVERS = [
|
|
448
|
+
{
|
|
449
|
+
name: "semo-integrations",
|
|
450
|
+
command: "npx",
|
|
451
|
+
args: ["-y", "@team-semicolon/semo-mcp"],
|
|
452
|
+
env: {
|
|
453
|
+
GITHUB_TOKEN: "${GITHUB_TOKEN}",
|
|
454
|
+
SLACK_BOT_TOKEN: "${SLACK_BOT_TOKEN}",
|
|
455
|
+
SUPABASE_URL: "${SUPABASE_URL}",
|
|
456
|
+
SUPABASE_KEY: "${SUPABASE_KEY}",
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
name: "context7",
|
|
461
|
+
command: "npx",
|
|
462
|
+
args: ["-y", "@upstash/context7-mcp"],
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
name: "sequential-thinking",
|
|
466
|
+
command: "npx",
|
|
467
|
+
args: ["-y", "@modelcontextprotocol/server-sequential-thinking"],
|
|
468
|
+
},
|
|
469
|
+
];
|
|
470
|
+
// === Claude MCP 등록 함수 ===
|
|
471
|
+
function registerMCPServer(server) {
|
|
472
|
+
try {
|
|
473
|
+
// 환경변수가 있는 경우 --env 옵션 추가
|
|
474
|
+
const envArgs = [];
|
|
475
|
+
if (server.env) {
|
|
476
|
+
for (const [key, value] of Object.entries(server.env)) {
|
|
477
|
+
envArgs.push("-e", `${key}=${value}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
// claude mcp add 명령어 실행
|
|
481
|
+
const args = [
|
|
482
|
+
"mcp", "add",
|
|
483
|
+
server.name,
|
|
484
|
+
"--",
|
|
485
|
+
server.command,
|
|
486
|
+
...server.args,
|
|
487
|
+
];
|
|
488
|
+
// 환경변수가 있으면 명령어 앞에 추가
|
|
489
|
+
if (envArgs.length > 0) {
|
|
490
|
+
args.splice(2, 0, ...envArgs);
|
|
491
|
+
}
|
|
492
|
+
(0, child_process_1.execSync)(`claude ${args.join(" ")}`, { stdio: "pipe" });
|
|
493
|
+
return { success: true };
|
|
494
|
+
}
|
|
495
|
+
catch (error) {
|
|
496
|
+
return { success: false, error: String(error) };
|
|
497
|
+
}
|
|
498
|
+
}
|
|
433
499
|
// === MCP 설정 ===
|
|
434
500
|
async function setupMCP(cwd, extensions, force) {
|
|
435
501
|
console.log(chalk_1.default.cyan("\n🔧 Black Box 설정 (MCP Server)"));
|
|
@@ -444,19 +510,10 @@ async function setupMCP(cwd, extensions, force) {
|
|
|
444
510
|
}
|
|
445
511
|
// Base settings (Standard)
|
|
446
512
|
const settings = {
|
|
447
|
-
mcpServers: {
|
|
448
|
-
"semo-integrations": {
|
|
449
|
-
command: "npx",
|
|
450
|
-
args: ["-y", "@team-semicolon/semo-mcp"],
|
|
451
|
-
env: {
|
|
452
|
-
GITHUB_TOKEN: "${GITHUB_TOKEN}",
|
|
453
|
-
SLACK_BOT_TOKEN: "${SLACK_BOT_TOKEN}",
|
|
454
|
-
SUPABASE_URL: "${SUPABASE_URL}",
|
|
455
|
-
SUPABASE_KEY: "${SUPABASE_KEY}",
|
|
456
|
-
},
|
|
457
|
-
},
|
|
458
|
-
},
|
|
513
|
+
mcpServers: {},
|
|
459
514
|
};
|
|
515
|
+
// MCP 서버 목록 수집
|
|
516
|
+
const allServers = [...BASE_MCP_SERVERS];
|
|
460
517
|
// Extension settings 병합
|
|
461
518
|
const semoSystemDir = path.join(cwd, "semo-system");
|
|
462
519
|
for (const pkg of extensions) {
|
|
@@ -466,8 +523,16 @@ async function setupMCP(cwd, extensions, force) {
|
|
|
466
523
|
const extSettings = JSON.parse(fs.readFileSync(extSettingsPath, "utf-8"));
|
|
467
524
|
// mcpServers 병합
|
|
468
525
|
if (extSettings.mcpServers) {
|
|
469
|
-
Object.
|
|
470
|
-
|
|
526
|
+
for (const [name, config] of Object.entries(extSettings.mcpServers)) {
|
|
527
|
+
const serverConfig = config;
|
|
528
|
+
allServers.push({
|
|
529
|
+
name,
|
|
530
|
+
command: serverConfig.command,
|
|
531
|
+
args: serverConfig.args,
|
|
532
|
+
env: serverConfig.env,
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
console.log(chalk_1.default.gray(` + ${pkg} MCP 설정 수집됨`));
|
|
471
536
|
}
|
|
472
537
|
// permissions 병합
|
|
473
538
|
if (extSettings.permissions) {
|
|
@@ -494,8 +559,53 @@ async function setupMCP(cwd, extensions, force) {
|
|
|
494
559
|
}
|
|
495
560
|
}
|
|
496
561
|
}
|
|
562
|
+
// settings.json에 mcpServers 저장 (백업용)
|
|
563
|
+
for (const server of allServers) {
|
|
564
|
+
const serverConfig = {
|
|
565
|
+
command: server.command,
|
|
566
|
+
args: server.args,
|
|
567
|
+
};
|
|
568
|
+
if (server.env) {
|
|
569
|
+
serverConfig.env = server.env;
|
|
570
|
+
}
|
|
571
|
+
settings.mcpServers[server.name] = serverConfig;
|
|
572
|
+
}
|
|
497
573
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
498
|
-
console.log(chalk_1.default.green("✓ .claude/settings.json 생성됨 (MCP 설정)"));
|
|
574
|
+
console.log(chalk_1.default.green("✓ .claude/settings.json 생성됨 (MCP 설정 백업)"));
|
|
575
|
+
// Claude Code에 MCP 서버 등록 시도
|
|
576
|
+
console.log(chalk_1.default.cyan("\n🔌 Claude Code에 MCP 서버 등록 중..."));
|
|
577
|
+
const successServers = [];
|
|
578
|
+
const failedServers = [];
|
|
579
|
+
for (const server of allServers) {
|
|
580
|
+
const spinner = (0, ora_1.default)(` ${server.name} 등록 중...`).start();
|
|
581
|
+
const result = registerMCPServer(server);
|
|
582
|
+
if (result.success) {
|
|
583
|
+
spinner.succeed(` ${server.name} 등록 완료`);
|
|
584
|
+
successServers.push(server.name);
|
|
585
|
+
}
|
|
586
|
+
else {
|
|
587
|
+
spinner.fail(` ${server.name} 등록 실패`);
|
|
588
|
+
failedServers.push(server);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
// 결과 요약
|
|
592
|
+
if (successServers.length > 0) {
|
|
593
|
+
console.log(chalk_1.default.green(`\n✓ ${successServers.length}개 MCP 서버 자동 등록 완료`));
|
|
594
|
+
}
|
|
595
|
+
// 실패한 서버가 있으면 수동 등록 안내
|
|
596
|
+
if (failedServers.length > 0) {
|
|
597
|
+
console.log(chalk_1.default.yellow(`\n⚠ ${failedServers.length}개 MCP 서버 자동 등록 실패`));
|
|
598
|
+
console.log(chalk_1.default.cyan("\n📋 수동 등록 명령어:"));
|
|
599
|
+
console.log(chalk_1.default.gray(" 다음 명령어를 터미널에서 실행하세요:\n"));
|
|
600
|
+
for (const server of failedServers) {
|
|
601
|
+
const envArgs = server.env
|
|
602
|
+
? Object.entries(server.env).map(([k, v]) => `-e ${k}="${v}"`).join(" ")
|
|
603
|
+
: "";
|
|
604
|
+
const cmd = `claude mcp add ${server.name} ${envArgs} -- ${server.command} ${server.args.join(" ")}`.trim();
|
|
605
|
+
console.log(chalk_1.default.white(` ${cmd}`));
|
|
606
|
+
}
|
|
607
|
+
console.log();
|
|
608
|
+
}
|
|
499
609
|
}
|
|
500
610
|
// === Extension settings 병합 (add 명령어용) ===
|
|
501
611
|
async function mergeExtensionSettings(cwd, packages) {
|
|
@@ -506,6 +616,7 @@ async function mergeExtensionSettings(cwd, packages) {
|
|
|
506
616
|
return;
|
|
507
617
|
}
|
|
508
618
|
const settings = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
|
|
619
|
+
const newServers = [];
|
|
509
620
|
for (const pkg of packages) {
|
|
510
621
|
const extSettingsPath = path.join(semoSystemDir, pkg, "settings.local.json");
|
|
511
622
|
if (fs.existsSync(extSettingsPath)) {
|
|
@@ -514,7 +625,16 @@ async function mergeExtensionSettings(cwd, packages) {
|
|
|
514
625
|
// mcpServers 병합
|
|
515
626
|
if (extSettings.mcpServers) {
|
|
516
627
|
settings.mcpServers = settings.mcpServers || {};
|
|
517
|
-
Object.
|
|
628
|
+
for (const [name, config] of Object.entries(extSettings.mcpServers)) {
|
|
629
|
+
const serverConfig = config;
|
|
630
|
+
settings.mcpServers[name] = serverConfig;
|
|
631
|
+
newServers.push({
|
|
632
|
+
name,
|
|
633
|
+
command: serverConfig.command,
|
|
634
|
+
args: serverConfig.args,
|
|
635
|
+
env: serverConfig.env,
|
|
636
|
+
});
|
|
637
|
+
}
|
|
518
638
|
console.log(chalk_1.default.gray(` + ${pkg} MCP 설정 병합됨`));
|
|
519
639
|
}
|
|
520
640
|
// permissions 병합
|
|
@@ -541,6 +661,39 @@ async function mergeExtensionSettings(cwd, packages) {
|
|
|
541
661
|
}
|
|
542
662
|
}
|
|
543
663
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
664
|
+
// 새 MCP 서버 Claude Code에 등록
|
|
665
|
+
if (newServers.length > 0) {
|
|
666
|
+
console.log(chalk_1.default.cyan("\n🔌 Claude Code에 MCP 서버 등록 중..."));
|
|
667
|
+
const successServers = [];
|
|
668
|
+
const failedServers = [];
|
|
669
|
+
for (const server of newServers) {
|
|
670
|
+
const spinner = (0, ora_1.default)(` ${server.name} 등록 중...`).start();
|
|
671
|
+
const result = registerMCPServer(server);
|
|
672
|
+
if (result.success) {
|
|
673
|
+
spinner.succeed(` ${server.name} 등록 완료`);
|
|
674
|
+
successServers.push(server.name);
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
spinner.fail(` ${server.name} 등록 실패`);
|
|
678
|
+
failedServers.push(server);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (successServers.length > 0) {
|
|
682
|
+
console.log(chalk_1.default.green(`\n✓ ${successServers.length}개 MCP 서버 자동 등록 완료`));
|
|
683
|
+
}
|
|
684
|
+
if (failedServers.length > 0) {
|
|
685
|
+
console.log(chalk_1.default.yellow(`\n⚠ ${failedServers.length}개 MCP 서버 자동 등록 실패`));
|
|
686
|
+
console.log(chalk_1.default.cyan("\n📋 수동 등록 명령어:"));
|
|
687
|
+
for (const server of failedServers) {
|
|
688
|
+
const envArgs = server.env
|
|
689
|
+
? Object.entries(server.env).map(([k, v]) => `-e ${k}="${v}"`).join(" ")
|
|
690
|
+
: "";
|
|
691
|
+
const cmd = `claude mcp add ${server.name} ${envArgs} -- ${server.command} ${server.args.join(" ")}`.trim();
|
|
692
|
+
console.log(chalk_1.default.white(` ${cmd}`));
|
|
693
|
+
}
|
|
694
|
+
console.log();
|
|
695
|
+
}
|
|
696
|
+
}
|
|
544
697
|
}
|
|
545
698
|
// === Context Mesh 초기화 ===
|
|
546
699
|
async function setupContextMesh(cwd) {
|
|
@@ -551,36 +704,36 @@ async function setupContextMesh(cwd) {
|
|
|
551
704
|
// context.md
|
|
552
705
|
const contextPath = path.join(memoryDir, "context.md");
|
|
553
706
|
if (!fs.existsSync(contextPath)) {
|
|
554
|
-
const contextContent = `# Project Context
|
|
555
|
-
|
|
556
|
-
> 세션 간 영속화되는 프로젝트 컨텍스트
|
|
557
|
-
> SEMO의 memory 스킬이 이 파일을 자동으로 업데이트합니다.
|
|
558
|
-
|
|
559
|
-
---
|
|
560
|
-
|
|
561
|
-
## 프로젝트 정보
|
|
562
|
-
|
|
563
|
-
| 항목 | 값 |
|
|
564
|
-
|------|-----|
|
|
565
|
-
| **이름** | ${path.basename(cwd)} |
|
|
566
|
-
| **SEMO 버전** | ${VERSION} |
|
|
567
|
-
| **설치일** | ${new Date().toISOString().split("T")[0]} |
|
|
568
|
-
|
|
569
|
-
---
|
|
570
|
-
|
|
571
|
-
## 현재 작업 상태
|
|
572
|
-
|
|
573
|
-
_아직 작업 기록이 없습니다._
|
|
574
|
-
|
|
575
|
-
---
|
|
576
|
-
|
|
577
|
-
## 기술 스택
|
|
578
|
-
|
|
579
|
-
_프로젝트 분석 후 자동으로 채워집니다._
|
|
580
|
-
|
|
581
|
-
---
|
|
582
|
-
|
|
583
|
-
*마지막 업데이트: ${new Date().toISOString().split("T")[0]}*
|
|
707
|
+
const contextContent = `# Project Context
|
|
708
|
+
|
|
709
|
+
> 세션 간 영속화되는 프로젝트 컨텍스트
|
|
710
|
+
> SEMO의 memory 스킬이 이 파일을 자동으로 업데이트합니다.
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
## 프로젝트 정보
|
|
715
|
+
|
|
716
|
+
| 항목 | 값 |
|
|
717
|
+
|------|-----|
|
|
718
|
+
| **이름** | ${path.basename(cwd)} |
|
|
719
|
+
| **SEMO 버전** | ${VERSION} |
|
|
720
|
+
| **설치일** | ${new Date().toISOString().split("T")[0]} |
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
## 현재 작업 상태
|
|
725
|
+
|
|
726
|
+
_아직 작업 기록이 없습니다._
|
|
727
|
+
|
|
728
|
+
---
|
|
729
|
+
|
|
730
|
+
## 기술 스택
|
|
731
|
+
|
|
732
|
+
_프로젝트 분석 후 자동으로 채워집니다._
|
|
733
|
+
|
|
734
|
+
---
|
|
735
|
+
|
|
736
|
+
*마지막 업데이트: ${new Date().toISOString().split("T")[0]}*
|
|
584
737
|
`;
|
|
585
738
|
fs.writeFileSync(contextPath, contextContent);
|
|
586
739
|
console.log(chalk_1.default.green("✓ .claude/memory/context.md 생성됨"));
|
|
@@ -588,36 +741,36 @@ _프로젝트 분석 후 자동으로 채워집니다._
|
|
|
588
741
|
// decisions.md
|
|
589
742
|
const decisionsPath = path.join(memoryDir, "decisions.md");
|
|
590
743
|
if (!fs.existsSync(decisionsPath)) {
|
|
591
|
-
const decisionsContent = `# Architecture Decisions
|
|
592
|
-
|
|
593
|
-
> 프로젝트 아키텍처 결정 기록 (ADR)
|
|
594
|
-
> 중요한 기술적 결정을 여기에 기록합니다.
|
|
595
|
-
|
|
596
|
-
---
|
|
597
|
-
|
|
598
|
-
## 결정 목록
|
|
599
|
-
|
|
600
|
-
_아직 기록된 결정이 없습니다._
|
|
601
|
-
|
|
602
|
-
---
|
|
603
|
-
|
|
604
|
-
## 템플릿
|
|
605
|
-
|
|
606
|
-
\`\`\`markdown
|
|
607
|
-
### ADR-XXX: 결정 제목
|
|
608
|
-
|
|
609
|
-
**날짜**: YYYY-MM-DD
|
|
610
|
-
**상태**: Proposed | Accepted | Deprecated
|
|
611
|
-
|
|
612
|
-
#### 배경
|
|
613
|
-
결정이 필요한 이유
|
|
614
|
-
|
|
615
|
-
#### 결정
|
|
616
|
-
선택한 방안
|
|
617
|
-
|
|
618
|
-
#### 근거
|
|
619
|
-
선택 이유
|
|
620
|
-
\`\`\`
|
|
744
|
+
const decisionsContent = `# Architecture Decisions
|
|
745
|
+
|
|
746
|
+
> 프로젝트 아키텍처 결정 기록 (ADR)
|
|
747
|
+
> 중요한 기술적 결정을 여기에 기록합니다.
|
|
748
|
+
|
|
749
|
+
---
|
|
750
|
+
|
|
751
|
+
## 결정 목록
|
|
752
|
+
|
|
753
|
+
_아직 기록된 결정이 없습니다._
|
|
754
|
+
|
|
755
|
+
---
|
|
756
|
+
|
|
757
|
+
## 템플릿
|
|
758
|
+
|
|
759
|
+
\`\`\`markdown
|
|
760
|
+
### ADR-XXX: 결정 제목
|
|
761
|
+
|
|
762
|
+
**날짜**: YYYY-MM-DD
|
|
763
|
+
**상태**: Proposed | Accepted | Deprecated
|
|
764
|
+
|
|
765
|
+
#### 배경
|
|
766
|
+
결정이 필요한 이유
|
|
767
|
+
|
|
768
|
+
#### 결정
|
|
769
|
+
선택한 방안
|
|
770
|
+
|
|
771
|
+
#### 근거
|
|
772
|
+
선택 이유
|
|
773
|
+
\`\`\`
|
|
621
774
|
`;
|
|
622
775
|
fs.writeFileSync(decisionsPath, decisionsContent);
|
|
623
776
|
console.log(chalk_1.default.green("✓ .claude/memory/decisions.md 생성됨"));
|
|
@@ -627,27 +780,27 @@ _아직 기록된 결정이 없습니다._
|
|
|
627
780
|
fs.mkdirSync(rulesDir, { recursive: true });
|
|
628
781
|
const rulesPath = path.join(rulesDir, "project-specific.md");
|
|
629
782
|
if (!fs.existsSync(rulesPath)) {
|
|
630
|
-
const rulesContent = `# Project-Specific Rules
|
|
631
|
-
|
|
632
|
-
> 이 프로젝트에만 적용되는 규칙
|
|
633
|
-
|
|
634
|
-
---
|
|
635
|
-
|
|
636
|
-
## 코딩 규칙
|
|
637
|
-
|
|
638
|
-
_프로젝트별 코딩 규칙을 여기에 추가하세요._
|
|
639
|
-
|
|
640
|
-
---
|
|
641
|
-
|
|
642
|
-
## 예외 사항
|
|
643
|
-
|
|
644
|
-
_SEMO 기본 규칙의 예외 사항을 여기에 추가하세요._
|
|
783
|
+
const rulesContent = `# Project-Specific Rules
|
|
784
|
+
|
|
785
|
+
> 이 프로젝트에만 적용되는 규칙
|
|
786
|
+
|
|
787
|
+
---
|
|
788
|
+
|
|
789
|
+
## 코딩 규칙
|
|
790
|
+
|
|
791
|
+
_프로젝트별 코딩 규칙을 여기에 추가하세요._
|
|
792
|
+
|
|
793
|
+
---
|
|
794
|
+
|
|
795
|
+
## 예외 사항
|
|
796
|
+
|
|
797
|
+
_SEMO 기본 규칙의 예외 사항을 여기에 추가하세요._
|
|
645
798
|
`;
|
|
646
799
|
fs.writeFileSync(rulesPath, rulesContent);
|
|
647
800
|
console.log(chalk_1.default.green("✓ .claude/memory/rules/project-specific.md 생성됨"));
|
|
648
801
|
}
|
|
649
802
|
}
|
|
650
|
-
// === CLAUDE.md 생성 ===
|
|
803
|
+
// === CLAUDE.md 생성 (패키지 CLAUDE.md 병합 지원) ===
|
|
651
804
|
async function setupClaudeMd(cwd, extensions, force) {
|
|
652
805
|
console.log(chalk_1.default.cyan("\n📄 CLAUDE.md 설정"));
|
|
653
806
|
const claudeMdPath = path.join(cwd, ".claude", "CLAUDE.md");
|
|
@@ -658,71 +811,160 @@ async function setupClaudeMd(cwd, extensions, force) {
|
|
|
658
811
|
return;
|
|
659
812
|
}
|
|
660
813
|
}
|
|
814
|
+
const semoSystemDir = path.join(cwd, "semo-system");
|
|
661
815
|
const extensionsList = extensions.length > 0
|
|
662
816
|
? extensions.map(pkg => `├── ${pkg}/ # ${EXTENSION_PACKAGES[pkg].name}`).join("\n")
|
|
663
817
|
: "";
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
\`\`\`
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
-
|
|
721
|
-
-
|
|
722
|
-
|
|
818
|
+
// 패키지별 CLAUDE.md 병합 섹션 생성
|
|
819
|
+
let packageClaudeMdSections = "";
|
|
820
|
+
for (const pkg of extensions) {
|
|
821
|
+
const pkgClaudeMdPath = path.join(semoSystemDir, pkg, "CLAUDE.md");
|
|
822
|
+
if (fs.existsSync(pkgClaudeMdPath)) {
|
|
823
|
+
const pkgContent = fs.readFileSync(pkgClaudeMdPath, "utf-8");
|
|
824
|
+
// 첫 헤더(#)를 ##로 변경하여 하위 섹션으로 만듦
|
|
825
|
+
const adjustedContent = pkgContent
|
|
826
|
+
.replace(/^# /gm, "### ")
|
|
827
|
+
.replace(/^## /gm, "#### ");
|
|
828
|
+
packageClaudeMdSections += `\n\n---\n\n## ${EXTENSION_PACKAGES[pkg].name} 패키지 컨텍스트\n\n${adjustedContent}`;
|
|
829
|
+
console.log(chalk_1.default.gray(` + ${pkg}/CLAUDE.md 병합됨`));
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
const claudeMdContent = `# SEMO Project Configuration
|
|
833
|
+
|
|
834
|
+
> SEMO (Semicolon Orchestrate) - AI Agent Orchestration Framework v${VERSION}
|
|
835
|
+
|
|
836
|
+
---
|
|
837
|
+
|
|
838
|
+
## 🔴 MANDATORY: Orchestrator-First Execution
|
|
839
|
+
|
|
840
|
+
> **⚠️ 이 규칙은 모든 사용자 요청에 적용됩니다. 예외 없음.**
|
|
841
|
+
|
|
842
|
+
### 실행 흐름 (필수)
|
|
843
|
+
|
|
844
|
+
\`\`\`
|
|
845
|
+
1. 사용자 요청 수신
|
|
846
|
+
2. [SEMO] Orchestrator 메시지 출력 (의도 분석)
|
|
847
|
+
3. Orchestrator가 적절한 Agent/Skill 라우팅
|
|
848
|
+
4. [SEMO] Agent/Skill 메시지 출력
|
|
849
|
+
5. 실행 결과 반환
|
|
850
|
+
\`\`\`
|
|
851
|
+
|
|
852
|
+
### 모든 응답은 다음으로 시작
|
|
853
|
+
|
|
854
|
+
\`\`\`
|
|
855
|
+
[SEMO] Orchestrator: 의도 분석 완료 → {intent_category}
|
|
856
|
+
[SEMO] {Agent/Skill} 호출: {target} (사유: {reason})
|
|
857
|
+
\`\`\`
|
|
858
|
+
|
|
859
|
+
### Orchestrator 참조
|
|
860
|
+
|
|
861
|
+
**반드시 읽어야 할 파일**: \`semo-system/semo-core/agents/orchestrator/orchestrator.md\`
|
|
862
|
+
|
|
863
|
+
이 파일에서 라우팅 테이블, 의도 분류, 메시지 포맷을 확인하세요.
|
|
864
|
+
|
|
865
|
+
---
|
|
866
|
+
|
|
867
|
+
## 🔴 NON-NEGOTIABLE RULES
|
|
868
|
+
|
|
869
|
+
### 1. Orchestrator-First Policy
|
|
870
|
+
|
|
871
|
+
> **모든 요청은 반드시 Orchestrator를 통해 라우팅됩니다. 직접 처리 금지.**
|
|
872
|
+
|
|
873
|
+
**직접 처리 금지 항목**:
|
|
874
|
+
- 코드 작성/수정 → \`implementation-master\` 또는 \`coder\` 스킬
|
|
875
|
+
- Git 커밋/푸시 → \`git-workflow\` 스킬
|
|
876
|
+
- 품질 검증 → \`quality-master\` 또는 \`verify\` 스킬
|
|
877
|
+
- 명세 작성 → \`spec-master\`
|
|
878
|
+
- 일반 작업 → Orchestrator 분석 후 라우팅
|
|
879
|
+
|
|
880
|
+
### 2. Pre-Commit Quality Gate
|
|
881
|
+
|
|
882
|
+
> **코드 변경이 포함된 커밋 전 반드시 Quality Gate를 통과해야 합니다.**
|
|
883
|
+
|
|
884
|
+
\`\`\`bash
|
|
885
|
+
# 필수 검증 순서
|
|
886
|
+
npm run lint # 1. ESLint 검사
|
|
887
|
+
npx tsc --noEmit # 2. TypeScript 타입 체크
|
|
888
|
+
npm run build # 3. 빌드 검증 (Next.js/TypeScript 프로젝트)
|
|
889
|
+
\`\`\`
|
|
890
|
+
|
|
891
|
+
**차단 항목**:
|
|
892
|
+
- \`--no-verify\` 플래그 사용 금지
|
|
893
|
+
- Quality Gate 우회 시도 거부
|
|
894
|
+
- "그냥 커밋해줘", "빌드 생략해줘" 등 거부
|
|
895
|
+
|
|
896
|
+
### 3. SEMO Message Format
|
|
897
|
+
|
|
898
|
+
모든 SEMO 동작은 시스템 메시지로 시작:
|
|
899
|
+
|
|
900
|
+
\`\`\`
|
|
901
|
+
[SEMO] {Component}: {Action} → {Result}
|
|
902
|
+
\`\`\`
|
|
903
|
+
|
|
904
|
+
---
|
|
905
|
+
|
|
906
|
+
## 설치된 구성
|
|
907
|
+
|
|
908
|
+
### Standard (필수)
|
|
909
|
+
- **semo-core**: 원칙, 오케스트레이터, 공통 커맨드
|
|
910
|
+
- **semo-skills**: 13개 통합 스킬
|
|
911
|
+
- 행동: coder, tester, planner, deployer, writer
|
|
912
|
+
- 운영: memory, notify-slack, feedback, version-updater, semo-help, semo-architecture-checker, circuit-breaker, list-bugs
|
|
913
|
+
|
|
914
|
+
${extensions.length > 0 ? `### Extensions (선택)
|
|
915
|
+
${extensions.map(pkg => `- **${pkg}**: ${EXTENSION_PACKAGES[pkg].desc}`).join("\n")}` : ""}
|
|
916
|
+
|
|
917
|
+
## 구조
|
|
918
|
+
|
|
919
|
+
\`\`\`
|
|
920
|
+
.claude/
|
|
921
|
+
├── settings.json # MCP 서버 설정 (Black Box)
|
|
922
|
+
├── memory/ # Context Mesh (장기 기억)
|
|
923
|
+
│ ├── context.md # 프로젝트 상태
|
|
924
|
+
│ ├── decisions.md # 아키텍처 결정
|
|
925
|
+
│ └── rules/ # 프로젝트별 규칙
|
|
926
|
+
├── agents → semo-system/semo-core/agents
|
|
927
|
+
├── skills → semo-system/semo-skills
|
|
928
|
+
└── commands/SEMO → semo-system/semo-core/commands/SEMO
|
|
929
|
+
|
|
930
|
+
semo-system/ # White Box (읽기 전용)
|
|
931
|
+
├── semo-core/ # Layer 0: 원칙, 오케스트레이션
|
|
932
|
+
├── semo-skills/ # Layer 1: 통합 스킬
|
|
933
|
+
${extensionsList}
|
|
934
|
+
\`\`\`
|
|
935
|
+
|
|
936
|
+
## 사용 가능한 커맨드
|
|
937
|
+
|
|
938
|
+
| 커맨드 | 설명 |
|
|
939
|
+
|--------|------|
|
|
940
|
+
| \`/SEMO:help\` | 도움말 |
|
|
941
|
+
| \`/SEMO:slack\` | Slack 메시지 전송 |
|
|
942
|
+
| \`/SEMO:feedback\` | 피드백 제출 |
|
|
943
|
+
| \`/SEMO:health\` | 환경 검증 |
|
|
944
|
+
| \`/SEMO:update\` | SEMO 업데이트 |
|
|
945
|
+
|
|
946
|
+
## Context Mesh 사용
|
|
947
|
+
|
|
948
|
+
SEMO는 \`.claude/memory/\`를 통해 세션 간 컨텍스트를 유지합니다:
|
|
949
|
+
|
|
950
|
+
- **context.md**: 프로젝트 상태, 진행 중인 작업
|
|
951
|
+
- **decisions.md**: 아키텍처 결정 기록 (ADR)
|
|
952
|
+
- **rules/**: 프로젝트별 커스텀 규칙
|
|
953
|
+
|
|
954
|
+
memory 스킬이 자동으로 이 파일들을 관리합니다.
|
|
955
|
+
|
|
956
|
+
## References
|
|
957
|
+
|
|
958
|
+
- [SEMO Principles](semo-system/semo-core/principles/PRINCIPLES.md)
|
|
959
|
+
- [SEMO Skills](semo-system/semo-skills/)
|
|
960
|
+
${extensions.length > 0 ? extensions.map(pkg => `- [${EXTENSION_PACKAGES[pkg].name} Package](semo-system/${pkg}/)`).join("\n") : ""}
|
|
961
|
+
${packageClaudeMdSections}
|
|
723
962
|
`;
|
|
724
963
|
fs.writeFileSync(claudeMdPath, claudeMdContent);
|
|
725
964
|
console.log(chalk_1.default.green("✓ .claude/CLAUDE.md 생성됨"));
|
|
965
|
+
if (packageClaudeMdSections) {
|
|
966
|
+
console.log(chalk_1.default.green(` + ${extensions.length}개 패키지 CLAUDE.md 병합 완료`));
|
|
967
|
+
}
|
|
726
968
|
}
|
|
727
969
|
// === add 명령어 ===
|
|
728
970
|
program
|
package/package.json
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@team-semicolon/semo-cli",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "SEMO CLI - AI Agent Orchestration Framework Installer",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"bin": {
|
|
7
|
-
"semo": "./dist/index.js",
|
|
8
|
-
"semo-cli": "./dist/index.js"
|
|
9
|
-
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsc",
|
|
12
|
-
"start": "node dist/index.js",
|
|
13
|
-
"dev": "ts-node src/index.ts"
|
|
14
|
-
},
|
|
15
|
-
"keywords": [
|
|
16
|
-
"semo",
|
|
17
|
-
"cli",
|
|
18
|
-
"ai-agent",
|
|
19
|
-
"claude",
|
|
20
|
-
"semicolon"
|
|
21
|
-
],
|
|
22
|
-
"author": "Semicolon DevTeam",
|
|
23
|
-
"license": "MIT",
|
|
24
|
-
"repository": {
|
|
25
|
-
"type": "git",
|
|
26
|
-
"url": "https://github.com/semicolon-devteam/semo.git",
|
|
27
|
-
"directory": "packages/cli"
|
|
28
|
-
},
|
|
29
|
-
"dependencies": {
|
|
30
|
-
"chalk": "^5.3.0",
|
|
31
|
-
"commander": "^12.0.0",
|
|
32
|
-
"ora": "^8.0.0",
|
|
33
|
-
"inquirer": "^9.2.0"
|
|
34
|
-
},
|
|
35
|
-
"devDependencies": {
|
|
36
|
-
"@types/node": "^20.0.0",
|
|
37
|
-
"@types/inquirer": "^9.0.0",
|
|
38
|
-
"typescript": "^5.0.0",
|
|
39
|
-
"ts-node": "^10.0.0"
|
|
40
|
-
},
|
|
41
|
-
"engines": {
|
|
42
|
-
"node": ">=18.0.0"
|
|
43
|
-
},
|
|
44
|
-
"files": [
|
|
45
|
-
"dist",
|
|
46
|
-
"README.md"
|
|
47
|
-
]
|
|
48
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@team-semicolon/semo-cli",
|
|
3
|
+
"version": "2.0.5",
|
|
4
|
+
"description": "SEMO CLI - AI Agent Orchestration Framework Installer",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"semo": "./dist/index.js",
|
|
8
|
+
"semo-cli": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "ts-node src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"semo",
|
|
17
|
+
"cli",
|
|
18
|
+
"ai-agent",
|
|
19
|
+
"claude",
|
|
20
|
+
"semicolon"
|
|
21
|
+
],
|
|
22
|
+
"author": "Semicolon DevTeam",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/semicolon-devteam/semo.git",
|
|
27
|
+
"directory": "packages/cli"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"chalk": "^5.3.0",
|
|
31
|
+
"commander": "^12.0.0",
|
|
32
|
+
"ora": "^8.0.0",
|
|
33
|
+
"inquirer": "^9.2.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^20.0.0",
|
|
37
|
+
"@types/inquirer": "^9.0.0",
|
|
38
|
+
"typescript": "^5.0.0",
|
|
39
|
+
"ts-node": "^10.0.0"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18.0.0"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"README.md"
|
|
47
|
+
]
|
|
48
|
+
}
|