@team-semicolon/semo-cli 3.0.6 → 3.0.9
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 +168 -55
- package/dist/index.js +174 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,70 +1,71 @@
|
|
|
1
1
|
# @team-semicolon/semo-cli
|
|
2
2
|
|
|
3
|
-
> SEMO CLI - AI Agent Orchestration Framework Installer
|
|
3
|
+
> SEMO CLI v3.0 - AI Agent Orchestration Framework Installer
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
Gemini의 하이브리드 전략에 따라 SEMO를 자동 설치하는 CLI 도구입니다.
|
|
5
|
+
## 설치
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
|
-
|
|
8
|
+
npm install -g @team-semicolon/semo-cli
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
`semo init` 명령어는 다음을 자동으로 수행합니다:
|
|
11
|
+
## 빠른 시작
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
```bash
|
|
14
|
+
# 프로젝트에 SEMO 설치
|
|
15
|
+
semo init
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
# Extension 패키지 추가
|
|
18
|
+
semo add eng/nextjs
|
|
20
19
|
|
|
20
|
+
# 버전 확인 및 업데이트 체크
|
|
21
|
+
semo -v
|
|
21
22
|
```
|
|
22
|
-
semo-system/
|
|
23
|
-
├── semo-core/ # Layer 0: 원칙, 오케스트레이션
|
|
24
|
-
└── semo-skills/ # Layer 1: coder, tester, planner
|
|
25
|
-
```
|
|
26
23
|
|
|
27
|
-
|
|
24
|
+
## 명령어
|
|
25
|
+
|
|
26
|
+
### `semo init`
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
현재 프로젝트에 SEMO를 설치합니다.
|
|
30
29
|
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"command": "npx",
|
|
37
|
-
"args": ["-y", "@team-semicolon/semo-mcp"]
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
30
|
+
```bash
|
|
31
|
+
semo init # 기본 설치 (프로젝트 유형 자동 감지)
|
|
32
|
+
semo init --force # 기존 설정 덮어쓰기
|
|
33
|
+
semo init --skip-mcp # MCP 설정 생략
|
|
34
|
+
semo init --with next,infra # 특정 패키지와 함께 설치
|
|
41
35
|
```
|
|
42
36
|
|
|
43
|
-
###
|
|
37
|
+
### `semo add <packages>`
|
|
44
38
|
|
|
45
|
-
|
|
39
|
+
Extension 패키지를 추가로 설치합니다.
|
|
46
40
|
|
|
41
|
+
```bash
|
|
42
|
+
# 개별 패키지 설치
|
|
43
|
+
semo add eng/nextjs
|
|
44
|
+
semo add biz/discovery
|
|
45
|
+
|
|
46
|
+
# 그룹 일괄 설치
|
|
47
|
+
semo add biz # Business 전체 (discovery, design, management, poc)
|
|
48
|
+
semo add eng # Engineering 전체 (nextjs, spring, ms, infra)
|
|
49
|
+
semo add ops # Operations 전체 (qa, monitor, improve)
|
|
50
|
+
|
|
51
|
+
# 여러 패키지 동시 설치
|
|
52
|
+
semo add eng/nextjs,eng/infra
|
|
53
|
+
|
|
54
|
+
# 레거시 별칭 지원
|
|
55
|
+
semo add next # → eng/nextjs
|
|
56
|
+
semo add backend # → eng/spring
|
|
57
|
+
semo add mvp # → biz/poc
|
|
47
58
|
```
|
|
48
|
-
.claude/memory/
|
|
49
|
-
├── context.md # 프로젝트 상태
|
|
50
|
-
├── decisions.md # 아키텍처 결정
|
|
51
|
-
└── rules/ # 프로젝트별 규칙
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## 명령어
|
|
55
59
|
|
|
56
|
-
###
|
|
60
|
+
### `semo list`
|
|
57
61
|
|
|
58
|
-
|
|
62
|
+
사용 가능한 모든 패키지를 표시합니다.
|
|
59
63
|
|
|
60
64
|
```bash
|
|
61
|
-
semo
|
|
62
|
-
semo init --force # 기존 설정 덮어쓰기
|
|
63
|
-
semo init --skip-mcp # MCP 설정 생략
|
|
64
|
-
semo init --skip-subtree # Git Subtree 생략
|
|
65
|
+
semo list
|
|
65
66
|
```
|
|
66
67
|
|
|
67
|
-
### status
|
|
68
|
+
### `semo status`
|
|
68
69
|
|
|
69
70
|
SEMO 설치 상태를 확인합니다.
|
|
70
71
|
|
|
@@ -72,31 +73,117 @@ SEMO 설치 상태를 확인합니다.
|
|
|
72
73
|
semo status
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
###
|
|
76
|
+
### `semo version` / `semo -v`
|
|
77
|
+
|
|
78
|
+
버전 정보 및 업데이트 확인을 표시합니다.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
semo version
|
|
82
|
+
semo -v
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
출력 예시:
|
|
86
|
+
```
|
|
87
|
+
📦 SEMO CLI 버전 정보
|
|
88
|
+
|
|
89
|
+
현재 버전: 3.0.7
|
|
90
|
+
최신 버전: 3.0.7
|
|
91
|
+
|
|
92
|
+
✓ 최신 버전을 사용 중입니다.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `semo update`
|
|
76
96
|
|
|
77
97
|
SEMO를 최신 버전으로 업데이트합니다.
|
|
78
98
|
|
|
79
99
|
```bash
|
|
80
|
-
semo update
|
|
100
|
+
semo update # CLI + semo-system 전체 업데이트
|
|
101
|
+
semo update --self # CLI만 업데이트
|
|
102
|
+
semo update --system # semo-system만 업데이트
|
|
103
|
+
semo update --skip-cli # CLI 업데이트 건너뛰기
|
|
81
104
|
```
|
|
82
105
|
|
|
106
|
+
## 패키지 구조
|
|
107
|
+
|
|
108
|
+
### Standard (필수)
|
|
109
|
+
|
|
110
|
+
모든 프로젝트에 기본 설치됩니다.
|
|
111
|
+
|
|
112
|
+
| 패키지 | 설명 |
|
|
113
|
+
|--------|------|
|
|
114
|
+
| `semo-core` | 원칙, 오케스트레이터, 공통 커맨드 |
|
|
115
|
+
| `semo-skills` | 13개 통합 스킬 (coder, tester, planner, deployer 등) |
|
|
116
|
+
|
|
117
|
+
### Extensions (선택)
|
|
118
|
+
|
|
119
|
+
프로젝트 유형에 맞게 선택적으로 설치합니다.
|
|
120
|
+
|
|
121
|
+
#### Business Layer (`biz`)
|
|
122
|
+
|
|
123
|
+
| 패키지 | 설명 | 설치 |
|
|
124
|
+
|--------|------|------|
|
|
125
|
+
| `biz/discovery` | 아이템 발굴, 시장 조사, Epic/Task | `semo add biz/discovery` |
|
|
126
|
+
| `biz/design` | 컨셉 설계, 목업, UX | `semo add biz/design` |
|
|
127
|
+
| `biz/management` | 일정/인력/스프린트 관리 | `semo add biz/management` |
|
|
128
|
+
| `biz/poc` | 빠른 PoC, 패스트트랙 | `semo add biz/poc` |
|
|
129
|
+
|
|
130
|
+
#### Engineering Layer (`eng`)
|
|
131
|
+
|
|
132
|
+
| 패키지 | 설명 | 자동 감지 | 설치 |
|
|
133
|
+
|--------|------|----------|------|
|
|
134
|
+
| `eng/nextjs` | Next.js 프론트엔드 개발 | `next.config.*` | `semo add eng/nextjs` |
|
|
135
|
+
| `eng/spring` | Spring Boot 백엔드 개발 | `pom.xml`, `build.gradle` | `semo add eng/spring` |
|
|
136
|
+
| `eng/ms` | 마이크로서비스 아키텍처 | - | `semo add eng/ms` |
|
|
137
|
+
| `eng/infra` | 인프라/배포 관리 | `Dockerfile`, `docker-compose.yml` | `semo add eng/infra` |
|
|
138
|
+
|
|
139
|
+
#### Operations Layer (`ops`)
|
|
140
|
+
|
|
141
|
+
| 패키지 | 설명 | 설치 |
|
|
142
|
+
|--------|------|------|
|
|
143
|
+
| `ops/qa` | 테스트/품질 관리 | `semo add ops/qa` |
|
|
144
|
+
| `ops/monitor` | 서비스 현황 모니터링 | `semo add ops/monitor` |
|
|
145
|
+
| `ops/improve` | 개선 제안 | `semo add ops/improve` |
|
|
146
|
+
|
|
147
|
+
#### Meta
|
|
148
|
+
|
|
149
|
+
| 패키지 | 설명 | 설치 |
|
|
150
|
+
|--------|------|------|
|
|
151
|
+
| `meta` | SEMO 프레임워크 자체 개발/관리 | `semo add meta` |
|
|
152
|
+
|
|
83
153
|
## 설치 후 구조
|
|
84
154
|
|
|
85
155
|
```
|
|
86
156
|
your-project/
|
|
87
157
|
├── .claude/
|
|
88
|
-
│ ├── CLAUDE.md
|
|
89
|
-
│ ├── settings.json
|
|
90
|
-
│ ├── memory/
|
|
91
|
-
│ ├──
|
|
92
|
-
│
|
|
158
|
+
│ ├── CLAUDE.md # 프로젝트 설정 (Extension CLAUDE.md 병합)
|
|
159
|
+
│ ├── settings.json # MCP 서버 설정
|
|
160
|
+
│ ├── memory/ # Context Mesh (세션 간 컨텍스트)
|
|
161
|
+
│ │ ├── context.md # 프로젝트 상태
|
|
162
|
+
│ │ ├── decisions.md # 아키텍처 결정
|
|
163
|
+
│ │ └── rules/ # 프로젝트별 규칙
|
|
164
|
+
│ ├── agents/ # 에이전트 심볼릭 링크
|
|
165
|
+
│ ├── skills/ # 스킬 심볼릭 링크
|
|
166
|
+
│ └── commands/SEMO/ # SEMO 커맨드
|
|
93
167
|
│
|
|
94
|
-
└── semo-system/
|
|
95
|
-
├── semo-core/
|
|
96
|
-
|
|
168
|
+
└── semo-system/ # White Box (읽기 전용)
|
|
169
|
+
├── semo-core/ # Layer 0: 원칙, 오케스트레이션
|
|
170
|
+
├── semo-skills/ # Layer 1: 통합 스킬
|
|
171
|
+
├── biz/ # Business Layer (선택)
|
|
172
|
+
├── eng/ # Engineering Layer (선택)
|
|
173
|
+
└── ops/ # Operations Layer (선택)
|
|
97
174
|
```
|
|
98
175
|
|
|
99
|
-
##
|
|
176
|
+
## MCP 서버
|
|
177
|
+
|
|
178
|
+
SEMO CLI는 다음 MCP 서버를 자동으로 등록합니다:
|
|
179
|
+
|
|
180
|
+
| 서버 | 설명 |
|
|
181
|
+
|------|------|
|
|
182
|
+
| `semo-integrations` | GitHub, Slack, Supabase 연동 |
|
|
183
|
+
| `context7` | 라이브러리 문서 조회 |
|
|
184
|
+
| `sequential-thinking` | 순차적 사고 지원 |
|
|
185
|
+
|
|
186
|
+
### 환경변수
|
|
100
187
|
|
|
101
188
|
MCP 연동을 위해 다음 환경변수를 설정하세요:
|
|
102
189
|
|
|
@@ -107,11 +194,37 @@ MCP 연동을 위해 다음 환경변수를 설정하세요:
|
|
|
107
194
|
| `SUPABASE_URL` | Supabase 프로젝트 URL |
|
|
108
195
|
| `SUPABASE_KEY` | Supabase 서비스 키 |
|
|
109
196
|
|
|
197
|
+
## 프로젝트 유형 자동 감지
|
|
198
|
+
|
|
199
|
+
`semo init` 실행 시 프로젝트 파일을 분석하여 적절한 패키지를 추천합니다:
|
|
200
|
+
|
|
201
|
+
| 감지 파일 | 추천 패키지 |
|
|
202
|
+
|----------|-------------|
|
|
203
|
+
| `next.config.js`, `next.config.mjs`, `next.config.ts` | `eng/nextjs` |
|
|
204
|
+
| `pom.xml`, `build.gradle` | `eng/spring` |
|
|
205
|
+
| `Dockerfile`, `docker-compose.yml` | `eng/infra` |
|
|
206
|
+
| `semo-core`, `semo-skills` | `meta` |
|
|
207
|
+
|
|
208
|
+
## 레거시 명령어 호환
|
|
209
|
+
|
|
210
|
+
이전 버전 사용자를 위해 레거시 패키지명도 지원합니다:
|
|
211
|
+
|
|
212
|
+
| 레거시 | 현재 |
|
|
213
|
+
|--------|------|
|
|
214
|
+
| `semo add next` | `semo add eng/nextjs` |
|
|
215
|
+
| `semo add backend` | `semo add eng/spring` |
|
|
216
|
+
| `semo add ms` | `semo add eng/ms` |
|
|
217
|
+
| `semo add infra` | `semo add eng/infra` |
|
|
218
|
+
| `semo add qa` | `semo add ops/qa` |
|
|
219
|
+
| `semo add po` | `semo add biz/discovery` |
|
|
220
|
+
| `semo add pm` | `semo add biz/management` |
|
|
221
|
+
| `semo add design` | `semo add biz/design` |
|
|
222
|
+
| `semo add mvp` | `semo add biz/poc` |
|
|
223
|
+
|
|
110
224
|
## 참조
|
|
111
225
|
|
|
112
226
|
- [SEMO 레포지토리](https://github.com/semicolon-devteam/semo)
|
|
113
|
-
- [SEMO MCP Server](
|
|
114
|
-
- [Gemini 하이브리드 전략](../../docs/SEMO_ARCHITECTURE_REVIEW.md)
|
|
227
|
+
- [SEMO MCP Server](https://www.npmjs.com/package/@team-semicolon/semo-mcp)
|
|
115
228
|
|
|
116
229
|
## 라이선스
|
|
117
230
|
|
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 = "3.0.
|
|
62
|
+
const VERSION = "3.0.9";
|
|
63
63
|
const PACKAGE_NAME = "@team-semicolon/semo-cli";
|
|
64
64
|
// === 버전 비교 유틸리티 ===
|
|
65
65
|
/**
|
|
@@ -313,17 +313,92 @@ function detectProjectType(cwd) {
|
|
|
313
313
|
}
|
|
314
314
|
return detected;
|
|
315
315
|
}
|
|
316
|
+
function checkRequiredTools() {
|
|
317
|
+
const tools = [
|
|
318
|
+
{
|
|
319
|
+
name: "GitHub CLI (gh)",
|
|
320
|
+
installed: false,
|
|
321
|
+
installCmd: isWindows ? "winget install GitHub.cli" : "brew install gh",
|
|
322
|
+
description: "GitHub API 연동 (이슈, PR, 배포)",
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
name: "Supabase CLI",
|
|
326
|
+
installed: false,
|
|
327
|
+
installCmd: isWindows ? "npm install -g supabase" : "brew install supabase/tap/supabase",
|
|
328
|
+
description: "Supabase 데이터베이스 연동",
|
|
329
|
+
},
|
|
330
|
+
];
|
|
331
|
+
// GitHub CLI 확인
|
|
332
|
+
try {
|
|
333
|
+
const ghVersion = (0, child_process_1.execSync)("gh --version", { stdio: "pipe", encoding: "utf-8" });
|
|
334
|
+
tools[0].installed = true;
|
|
335
|
+
tools[0].version = ghVersion.split("\n")[0].replace("gh version ", "").trim();
|
|
336
|
+
}
|
|
337
|
+
catch {
|
|
338
|
+
// gh not installed
|
|
339
|
+
}
|
|
340
|
+
// Supabase CLI 확인
|
|
341
|
+
try {
|
|
342
|
+
const supabaseVersion = (0, child_process_1.execSync)("supabase --version", { stdio: "pipe", encoding: "utf-8" });
|
|
343
|
+
tools[1].installed = true;
|
|
344
|
+
tools[1].version = supabaseVersion.trim();
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
// supabase not installed
|
|
348
|
+
}
|
|
349
|
+
return tools;
|
|
350
|
+
}
|
|
351
|
+
async function showToolsStatus() {
|
|
352
|
+
console.log(chalk_1.default.cyan("\n🔍 필수 도구 확인"));
|
|
353
|
+
const tools = checkRequiredTools();
|
|
354
|
+
const missingTools = tools.filter(t => !t.installed);
|
|
355
|
+
for (const tool of tools) {
|
|
356
|
+
if (tool.installed) {
|
|
357
|
+
console.log(chalk_1.default.green(` ✓ ${tool.name} ${tool.version ? `(${tool.version})` : ""}`));
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
console.log(chalk_1.default.yellow(` ✗ ${tool.name} - 미설치`));
|
|
361
|
+
console.log(chalk_1.default.gray(` ${tool.description}`));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (missingTools.length > 0) {
|
|
365
|
+
console.log(chalk_1.default.yellow("\n⚠ 일부 도구가 설치되어 있지 않습니다."));
|
|
366
|
+
console.log(chalk_1.default.gray(" SEMO의 일부 기능이 제한될 수 있습니다.\n"));
|
|
367
|
+
console.log(chalk_1.default.cyan("📋 설치 명령어:"));
|
|
368
|
+
for (const tool of missingTools) {
|
|
369
|
+
console.log(chalk_1.default.white(` ${tool.installCmd}`));
|
|
370
|
+
}
|
|
371
|
+
console.log();
|
|
372
|
+
const { continueWithout } = await inquirer_1.default.prompt([
|
|
373
|
+
{
|
|
374
|
+
type: "confirm",
|
|
375
|
+
name: "continueWithout",
|
|
376
|
+
message: "도구 없이 계속 설치를 진행할까요?",
|
|
377
|
+
default: true,
|
|
378
|
+
},
|
|
379
|
+
]);
|
|
380
|
+
return continueWithout;
|
|
381
|
+
}
|
|
382
|
+
return true;
|
|
383
|
+
}
|
|
316
384
|
// === init 명령어 ===
|
|
317
385
|
program
|
|
318
386
|
.command("init")
|
|
319
387
|
.description("현재 프로젝트에 SEMO를 설치합니다")
|
|
320
388
|
.option("-f, --force", "기존 설정 덮어쓰기")
|
|
321
389
|
.option("--skip-mcp", "MCP 설정 생략")
|
|
390
|
+
.option("--no-gitignore", ".gitignore 수정 생략")
|
|
322
391
|
.option("--with <packages>", "추가 설치할 패키지 (쉼표 구분: next,backend)")
|
|
323
392
|
.action(async (options) => {
|
|
324
393
|
console.log(chalk_1.default.cyan.bold("\n🚀 SEMO 설치 시작\n"));
|
|
325
394
|
console.log(chalk_1.default.gray("Gemini 하이브리드 전략: White Box + Black Box\n"));
|
|
326
395
|
const cwd = process.cwd();
|
|
396
|
+
// 0. 필수 도구 확인
|
|
397
|
+
const shouldContinue = await showToolsStatus();
|
|
398
|
+
if (!shouldContinue) {
|
|
399
|
+
console.log(chalk_1.default.yellow("\n설치가 취소되었습니다. 필수 도구 설치 후 다시 시도하세요.\n"));
|
|
400
|
+
process.exit(0);
|
|
401
|
+
}
|
|
327
402
|
// 1. Git 레포지토리 확인
|
|
328
403
|
const spinner = (0, ora_1.default)("Git 레포지토리 확인 중...").start();
|
|
329
404
|
try {
|
|
@@ -375,9 +450,13 @@ program
|
|
|
375
450
|
}
|
|
376
451
|
// 7. Context Mesh 초기화
|
|
377
452
|
await setupContextMesh(cwd);
|
|
378
|
-
// 8.
|
|
453
|
+
// 8. .gitignore 업데이트
|
|
454
|
+
if (options.gitignore !== false) {
|
|
455
|
+
updateGitignore(cwd);
|
|
456
|
+
}
|
|
457
|
+
// 9. CLAUDE.md 생성
|
|
379
458
|
await setupClaudeMd(cwd, extensionsToInstall, options.force);
|
|
380
|
-
//
|
|
459
|
+
// 10. Extensions 심볼릭 링크 (agents/skills 병합)
|
|
381
460
|
if (extensionsToInstall.length > 0) {
|
|
382
461
|
await setupExtensionSymlinks(cwd, extensionsToInstall);
|
|
383
462
|
}
|
|
@@ -488,13 +567,20 @@ async function createStandardSymlinks(cwd) {
|
|
|
488
567
|
const commandsDir = path.join(claudeDir, "commands");
|
|
489
568
|
fs.mkdirSync(commandsDir, { recursive: true });
|
|
490
569
|
const semoCommandsLink = path.join(commandsDir, "SEMO");
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
570
|
+
const commandsTarget = path.join(semoSystemDir, "semo-core", "commands", "SEMO");
|
|
571
|
+
// 기존 링크가 있으면 삭제 후 재생성 (업데이트 시에도 최신 반영)
|
|
572
|
+
if (fs.existsSync(semoCommandsLink)) {
|
|
573
|
+
if (fs.lstatSync(semoCommandsLink).isSymbolicLink()) {
|
|
574
|
+
fs.unlinkSync(semoCommandsLink);
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
removeRecursive(semoCommandsLink);
|
|
496
578
|
}
|
|
497
579
|
}
|
|
580
|
+
if (fs.existsSync(commandsTarget)) {
|
|
581
|
+
createSymlinkOrJunction(commandsTarget, semoCommandsLink);
|
|
582
|
+
console.log(chalk_1.default.green(" ✓ .claude/commands/SEMO → semo-system/semo-core/commands/SEMO"));
|
|
583
|
+
}
|
|
498
584
|
}
|
|
499
585
|
// === Extensions 다운로드 (심볼릭 링크 제외) ===
|
|
500
586
|
async function downloadExtensions(cwd, packages, force) {
|
|
@@ -511,6 +597,27 @@ async function downloadExtensions(cwd, packages, force) {
|
|
|
511
597
|
(0, child_process_1.execSync)(`git clone --depth 1 ${SEMO_REPO} "${tempDir}"`, { stdio: "pipe" });
|
|
512
598
|
}
|
|
513
599
|
const semoSystemDir = path.join(cwd, "semo-system");
|
|
600
|
+
// 그룹 추출 (중복 제거) - 그룹 레벨 CLAUDE.md 복사용
|
|
601
|
+
const groups = [...new Set(packages.map(pkg => pkg.split("/")[0]).filter(g => ["biz", "eng", "ops"].includes(g)))];
|
|
602
|
+
// 그룹 레벨 파일 복사 (CLAUDE.md, VERSION 등)
|
|
603
|
+
for (const group of groups) {
|
|
604
|
+
const groupSrcDir = path.join(tempDir, "packages", group);
|
|
605
|
+
const groupDestDir = path.join(semoSystemDir, group);
|
|
606
|
+
// 그룹 디렉토리의 루트 파일만 복사 (CLAUDE.md, VERSION)
|
|
607
|
+
if (fs.existsSync(groupSrcDir)) {
|
|
608
|
+
fs.mkdirSync(groupDestDir, { recursive: true });
|
|
609
|
+
const groupFiles = fs.readdirSync(groupSrcDir);
|
|
610
|
+
for (const file of groupFiles) {
|
|
611
|
+
const srcFile = path.join(groupSrcDir, file);
|
|
612
|
+
const destFile = path.join(groupDestDir, file);
|
|
613
|
+
if (fs.statSync(srcFile).isFile()) {
|
|
614
|
+
fs.copyFileSync(srcFile, destFile);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
console.log(chalk_1.default.green(` ✓ ${group}/ 그룹 파일 복사 (CLAUDE.md 등)`));
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
// 개별 패키지 복사
|
|
514
621
|
for (const pkg of packages) {
|
|
515
622
|
const srcPath = path.join(tempDir, "packages", pkg);
|
|
516
623
|
const destPath = path.join(semoSystemDir, pkg);
|
|
@@ -520,6 +627,8 @@ async function downloadExtensions(cwd, packages, force) {
|
|
|
520
627
|
continue;
|
|
521
628
|
}
|
|
522
629
|
removeRecursive(destPath);
|
|
630
|
+
// 상위 디렉토리 생성 (biz/discovery -> biz/ 먼저 생성)
|
|
631
|
+
fs.mkdirSync(path.dirname(destPath), { recursive: true });
|
|
523
632
|
copyRecursive(srcPath, destPath);
|
|
524
633
|
}
|
|
525
634
|
}
|
|
@@ -1020,6 +1129,33 @@ async function mergeExtensionSettings(cwd, packages) {
|
|
|
1020
1129
|
}
|
|
1021
1130
|
}
|
|
1022
1131
|
}
|
|
1132
|
+
// === .gitignore 업데이트 ===
|
|
1133
|
+
function updateGitignore(cwd) {
|
|
1134
|
+
console.log(chalk_1.default.cyan("\n📝 .gitignore 업데이트"));
|
|
1135
|
+
const gitignorePath = path.join(cwd, ".gitignore");
|
|
1136
|
+
const semoIgnoreBlock = `
|
|
1137
|
+
# === SEMO ===
|
|
1138
|
+
.claude/*
|
|
1139
|
+
!.claude/memory/
|
|
1140
|
+
!.claude/memory/**
|
|
1141
|
+
`;
|
|
1142
|
+
if (fs.existsSync(gitignorePath)) {
|
|
1143
|
+
const content = fs.readFileSync(gitignorePath, "utf-8");
|
|
1144
|
+
// 이미 SEMO 블록이 있으면 스킵
|
|
1145
|
+
if (content.includes("# === SEMO ===")) {
|
|
1146
|
+
console.log(chalk_1.default.gray(" → SEMO 블록 이미 존재 (건너뜀)"));
|
|
1147
|
+
return;
|
|
1148
|
+
}
|
|
1149
|
+
// 기존 파일에 추가
|
|
1150
|
+
fs.appendFileSync(gitignorePath, semoIgnoreBlock);
|
|
1151
|
+
console.log(chalk_1.default.green("✓ .gitignore에 SEMO 규칙 추가됨"));
|
|
1152
|
+
}
|
|
1153
|
+
else {
|
|
1154
|
+
// 새로 생성
|
|
1155
|
+
fs.writeFileSync(gitignorePath, semoIgnoreBlock.trim() + "\n");
|
|
1156
|
+
console.log(chalk_1.default.green("✓ .gitignore 생성됨 (SEMO 규칙 포함)"));
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1023
1159
|
// === Context Mesh 초기화 ===
|
|
1024
1160
|
async function setupContextMesh(cwd) {
|
|
1025
1161
|
console.log(chalk_1.default.cyan("\n🧠 Context Mesh 초기화"));
|
|
@@ -1140,8 +1276,25 @@ async function setupClaudeMd(cwd, extensions, force) {
|
|
|
1140
1276
|
const extensionsList = extensions.length > 0
|
|
1141
1277
|
? extensions.map(pkg => `├── ${pkg}/ # ${EXTENSION_PACKAGES[pkg].name}`).join("\n")
|
|
1142
1278
|
: "";
|
|
1143
|
-
// 패키지별 CLAUDE.md 병합 섹션 생성
|
|
1279
|
+
// 그룹 및 패키지별 CLAUDE.md 병합 섹션 생성
|
|
1144
1280
|
let packageClaudeMdSections = "";
|
|
1281
|
+
// 1. 설치된 패키지에서 그룹 추출 (중복 제거)
|
|
1282
|
+
const installedGroups = [...new Set(extensions.map(pkg => pkg.split("/")[0]).filter(g => PACKAGE_GROUPS.includes(g)))];
|
|
1283
|
+
// 2. 그룹 레벨 CLAUDE.md 먼저 병합 (biz, eng, ops)
|
|
1284
|
+
for (const group of installedGroups) {
|
|
1285
|
+
const groupClaudeMdPath = path.join(semoSystemDir, group, "CLAUDE.md");
|
|
1286
|
+
if (fs.existsSync(groupClaudeMdPath)) {
|
|
1287
|
+
const groupContent = fs.readFileSync(groupClaudeMdPath, "utf-8");
|
|
1288
|
+
// 그룹 CLAUDE.md 헤더 레벨 조정 (# → ##, ## → ###)
|
|
1289
|
+
const adjustedContent = groupContent
|
|
1290
|
+
.replace(/^# /gm, "## ")
|
|
1291
|
+
.replace(/^## /gm, "### ")
|
|
1292
|
+
.replace(/^### /gm, "#### ");
|
|
1293
|
+
packageClaudeMdSections += `\n\n---\n\n${adjustedContent}`;
|
|
1294
|
+
console.log(chalk_1.default.green(` + ${group}/ 그룹 CLAUDE.md 병합됨`));
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
// 3. 개별 패키지 CLAUDE.md 병합
|
|
1145
1298
|
for (const pkg of extensions) {
|
|
1146
1299
|
const pkgClaudeMdPath = path.join(semoSystemDir, pkg, "CLAUDE.md");
|
|
1147
1300
|
if (fs.existsSync(pkgClaudeMdPath)) {
|
|
@@ -1592,7 +1745,18 @@ program
|
|
|
1592
1745
|
}
|
|
1593
1746
|
}
|
|
1594
1747
|
}
|
|
1595
|
-
//
|
|
1748
|
+
// commands 링크도 정리 (신규 commands 반영 위해)
|
|
1749
|
+
const claudeCommandsDir = path.join(claudeDir, "commands");
|
|
1750
|
+
const semoCommandsLink = path.join(claudeCommandsDir, "SEMO");
|
|
1751
|
+
if (fs.existsSync(semoCommandsLink)) {
|
|
1752
|
+
if (fs.lstatSync(semoCommandsLink).isSymbolicLink()) {
|
|
1753
|
+
fs.unlinkSync(semoCommandsLink);
|
|
1754
|
+
}
|
|
1755
|
+
else {
|
|
1756
|
+
removeRecursive(semoCommandsLink);
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
// Standard 심볼릭 링크 재생성 (agents, skills, commands 포함)
|
|
1596
1760
|
await createStandardSymlinks(cwd);
|
|
1597
1761
|
// Extensions 심볼릭 링크 재생성
|
|
1598
1762
|
if (installedExtensions.length > 0) {
|