@team-semicolon/semo-cli 3.0.7 → 3.0.10

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.
Files changed (3) hide show
  1. package/README.md +168 -55
  2. package/dist/index.js +189 -13
  3. 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
- npx @team-semicolon/semo-cli init
8
+ npm install -g @team-semicolon/semo-cli
11
9
  ```
12
10
 
13
- ## 동작 방식
14
-
15
- `semo init` 명령어는 다음을 자동으로 수행합니다:
11
+ ## 빠른 시작
16
12
 
17
- ### 1. White Box 설정 (Git Subtree)
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
- ### 2. Black Box 설정 (MCP Server)
24
+ ## 명령어
25
+
26
+ ### `semo init`
28
27
 
29
- 토큰이 격리된 **외부 연동 도구**:
28
+ 현재 프로젝트에 SEMO를 설치합니다.
30
29
 
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
- }
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
- ### 3. Context Mesh 초기화
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
- ### init
60
+ ### `semo list`
57
61
 
58
- 현재 프로젝트에 SEMO를 설치합니다.
62
+ 사용 가능한 모든 패키지를 표시합니다.
59
63
 
60
64
  ```bash
61
- semo init # 기본 설치
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
- ### update
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 # MCP 서버 설정
90
- │ ├── memory/ # Context Mesh
91
- │ ├── agents semo-system/semo-core/agents
92
- └── skills semo-system/semo-skills
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/ # White Box (읽기 전용)
95
- ├── semo-core/
96
- └── semo-skills/
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](../mcp-server/README.md)
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.7";
62
+ const VERSION = "3.0.10";
63
63
  const PACKAGE_NAME = "@team-semicolon/semo-cli";
64
64
  // === 버전 비교 유틸리티 ===
65
65
  /**
@@ -313,17 +313,104 @@ function detectProjectType(cwd) {
313
313
  }
314
314
  return detected;
315
315
  }
316
+ // === 설치된 Extension 패키지 스캔 ===
317
+ function getInstalledExtensions(cwd) {
318
+ const semoSystemDir = path.join(cwd, "semo-system");
319
+ const installed = [];
320
+ for (const key of Object.keys(EXTENSION_PACKAGES)) {
321
+ const pkgPath = path.join(semoSystemDir, key);
322
+ if (fs.existsSync(pkgPath)) {
323
+ installed.push(key);
324
+ }
325
+ }
326
+ return installed;
327
+ }
328
+ function checkRequiredTools() {
329
+ const tools = [
330
+ {
331
+ name: "GitHub CLI (gh)",
332
+ installed: false,
333
+ installCmd: isWindows ? "winget install GitHub.cli" : "brew install gh",
334
+ description: "GitHub API 연동 (이슈, PR, 배포)",
335
+ },
336
+ {
337
+ name: "Supabase CLI",
338
+ installed: false,
339
+ installCmd: isWindows ? "npm install -g supabase" : "brew install supabase/tap/supabase",
340
+ description: "Supabase 데이터베이스 연동",
341
+ },
342
+ ];
343
+ // GitHub CLI 확인
344
+ try {
345
+ const ghVersion = (0, child_process_1.execSync)("gh --version", { stdio: "pipe", encoding: "utf-8" });
346
+ tools[0].installed = true;
347
+ tools[0].version = ghVersion.split("\n")[0].replace("gh version ", "").trim();
348
+ }
349
+ catch {
350
+ // gh not installed
351
+ }
352
+ // Supabase CLI 확인
353
+ try {
354
+ const supabaseVersion = (0, child_process_1.execSync)("supabase --version", { stdio: "pipe", encoding: "utf-8" });
355
+ tools[1].installed = true;
356
+ tools[1].version = supabaseVersion.trim();
357
+ }
358
+ catch {
359
+ // supabase not installed
360
+ }
361
+ return tools;
362
+ }
363
+ async function showToolsStatus() {
364
+ console.log(chalk_1.default.cyan("\n🔍 필수 도구 확인"));
365
+ const tools = checkRequiredTools();
366
+ const missingTools = tools.filter(t => !t.installed);
367
+ for (const tool of tools) {
368
+ if (tool.installed) {
369
+ console.log(chalk_1.default.green(` ✓ ${tool.name} ${tool.version ? `(${tool.version})` : ""}`));
370
+ }
371
+ else {
372
+ console.log(chalk_1.default.yellow(` ✗ ${tool.name} - 미설치`));
373
+ console.log(chalk_1.default.gray(` ${tool.description}`));
374
+ }
375
+ }
376
+ if (missingTools.length > 0) {
377
+ console.log(chalk_1.default.yellow("\n⚠ 일부 도구가 설치되어 있지 않습니다."));
378
+ console.log(chalk_1.default.gray(" SEMO의 일부 기능이 제한될 수 있습니다.\n"));
379
+ console.log(chalk_1.default.cyan("📋 설치 명령어:"));
380
+ for (const tool of missingTools) {
381
+ console.log(chalk_1.default.white(` ${tool.installCmd}`));
382
+ }
383
+ console.log();
384
+ const { continueWithout } = await inquirer_1.default.prompt([
385
+ {
386
+ type: "confirm",
387
+ name: "continueWithout",
388
+ message: "도구 없이 계속 설치를 진행할까요?",
389
+ default: true,
390
+ },
391
+ ]);
392
+ return continueWithout;
393
+ }
394
+ return true;
395
+ }
316
396
  // === init 명령어 ===
317
397
  program
318
398
  .command("init")
319
399
  .description("현재 프로젝트에 SEMO를 설치합니다")
320
400
  .option("-f, --force", "기존 설정 덮어쓰기")
321
401
  .option("--skip-mcp", "MCP 설정 생략")
402
+ .option("--no-gitignore", ".gitignore 수정 생략")
322
403
  .option("--with <packages>", "추가 설치할 패키지 (쉼표 구분: next,backend)")
323
404
  .action(async (options) => {
324
405
  console.log(chalk_1.default.cyan.bold("\n🚀 SEMO 설치 시작\n"));
325
406
  console.log(chalk_1.default.gray("Gemini 하이브리드 전략: White Box + Black Box\n"));
326
407
  const cwd = process.cwd();
408
+ // 0. 필수 도구 확인
409
+ const shouldContinue = await showToolsStatus();
410
+ if (!shouldContinue) {
411
+ console.log(chalk_1.default.yellow("\n설치가 취소되었습니다. 필수 도구 설치 후 다시 시도하세요.\n"));
412
+ process.exit(0);
413
+ }
327
414
  // 1. Git 레포지토리 확인
328
415
  const spinner = (0, ora_1.default)("Git 레포지토리 확인 중...").start();
329
416
  try {
@@ -375,9 +462,13 @@ program
375
462
  }
376
463
  // 7. Context Mesh 초기화
377
464
  await setupContextMesh(cwd);
378
- // 8. CLAUDE.md 생성
465
+ // 8. .gitignore 업데이트
466
+ if (options.gitignore !== false) {
467
+ updateGitignore(cwd);
468
+ }
469
+ // 9. CLAUDE.md 생성
379
470
  await setupClaudeMd(cwd, extensionsToInstall, options.force);
380
- // 9. Extensions 심볼릭 링크 (agents/skills 병합)
471
+ // 10. Extensions 심볼릭 링크 (agents/skills 병합)
381
472
  if (extensionsToInstall.length > 0) {
382
473
  await setupExtensionSymlinks(cwd, extensionsToInstall);
383
474
  }
@@ -488,13 +579,20 @@ async function createStandardSymlinks(cwd) {
488
579
  const commandsDir = path.join(claudeDir, "commands");
489
580
  fs.mkdirSync(commandsDir, { recursive: true });
490
581
  const semoCommandsLink = path.join(commandsDir, "SEMO");
491
- if (!fs.existsSync(semoCommandsLink)) {
492
- const commandsTarget = path.join(semoSystemDir, "semo-core", "commands", "SEMO");
493
- if (fs.existsSync(commandsTarget)) {
494
- createSymlinkOrJunction(commandsTarget, semoCommandsLink);
495
- console.log(chalk_1.default.green(" ✓ .claude/commands/SEMO → semo-system/semo-core/commands/SEMO"));
582
+ const commandsTarget = path.join(semoSystemDir, "semo-core", "commands", "SEMO");
583
+ // 기존 링크가 있으면 삭제 후 재생성 (업데이트 시에도 최신 반영)
584
+ if (fs.existsSync(semoCommandsLink)) {
585
+ if (fs.lstatSync(semoCommandsLink).isSymbolicLink()) {
586
+ fs.unlinkSync(semoCommandsLink);
587
+ }
588
+ else {
589
+ removeRecursive(semoCommandsLink);
496
590
  }
497
591
  }
592
+ if (fs.existsSync(commandsTarget)) {
593
+ createSymlinkOrJunction(commandsTarget, semoCommandsLink);
594
+ console.log(chalk_1.default.green(" ✓ .claude/commands/SEMO → semo-system/semo-core/commands/SEMO"));
595
+ }
498
596
  }
499
597
  // === Extensions 다운로드 (심볼릭 링크 제외) ===
500
598
  async function downloadExtensions(cwd, packages, force) {
@@ -511,6 +609,27 @@ async function downloadExtensions(cwd, packages, force) {
511
609
  (0, child_process_1.execSync)(`git clone --depth 1 ${SEMO_REPO} "${tempDir}"`, { stdio: "pipe" });
512
610
  }
513
611
  const semoSystemDir = path.join(cwd, "semo-system");
612
+ // 그룹 추출 (중복 제거) - 그룹 레벨 CLAUDE.md 복사용
613
+ const groups = [...new Set(packages.map(pkg => pkg.split("/")[0]).filter(g => ["biz", "eng", "ops"].includes(g)))];
614
+ // 그룹 레벨 파일 복사 (CLAUDE.md, VERSION 등)
615
+ for (const group of groups) {
616
+ const groupSrcDir = path.join(tempDir, "packages", group);
617
+ const groupDestDir = path.join(semoSystemDir, group);
618
+ // 그룹 디렉토리의 루트 파일만 복사 (CLAUDE.md, VERSION)
619
+ if (fs.existsSync(groupSrcDir)) {
620
+ fs.mkdirSync(groupDestDir, { recursive: true });
621
+ const groupFiles = fs.readdirSync(groupSrcDir);
622
+ for (const file of groupFiles) {
623
+ const srcFile = path.join(groupSrcDir, file);
624
+ const destFile = path.join(groupDestDir, file);
625
+ if (fs.statSync(srcFile).isFile()) {
626
+ fs.copyFileSync(srcFile, destFile);
627
+ }
628
+ }
629
+ console.log(chalk_1.default.green(` ✓ ${group}/ 그룹 파일 복사 (CLAUDE.md 등)`));
630
+ }
631
+ }
632
+ // 개별 패키지 복사
514
633
  for (const pkg of packages) {
515
634
  const srcPath = path.join(tempDir, "packages", pkg);
516
635
  const destPath = path.join(semoSystemDir, pkg);
@@ -1022,6 +1141,33 @@ async function mergeExtensionSettings(cwd, packages) {
1022
1141
  }
1023
1142
  }
1024
1143
  }
1144
+ // === .gitignore 업데이트 ===
1145
+ function updateGitignore(cwd) {
1146
+ console.log(chalk_1.default.cyan("\n📝 .gitignore 업데이트"));
1147
+ const gitignorePath = path.join(cwd, ".gitignore");
1148
+ const semoIgnoreBlock = `
1149
+ # === SEMO ===
1150
+ .claude/*
1151
+ !.claude/memory/
1152
+ !.claude/memory/**
1153
+ `;
1154
+ if (fs.existsSync(gitignorePath)) {
1155
+ const content = fs.readFileSync(gitignorePath, "utf-8");
1156
+ // 이미 SEMO 블록이 있으면 스킵
1157
+ if (content.includes("# === SEMO ===")) {
1158
+ console.log(chalk_1.default.gray(" → SEMO 블록 이미 존재 (건너뜀)"));
1159
+ return;
1160
+ }
1161
+ // 기존 파일에 추가
1162
+ fs.appendFileSync(gitignorePath, semoIgnoreBlock);
1163
+ console.log(chalk_1.default.green("✓ .gitignore에 SEMO 규칙 추가됨"));
1164
+ }
1165
+ else {
1166
+ // 새로 생성
1167
+ fs.writeFileSync(gitignorePath, semoIgnoreBlock.trim() + "\n");
1168
+ console.log(chalk_1.default.green("✓ .gitignore 생성됨 (SEMO 규칙 포함)"));
1169
+ }
1170
+ }
1025
1171
  // === Context Mesh 초기화 ===
1026
1172
  async function setupContextMesh(cwd) {
1027
1173
  console.log(chalk_1.default.cyan("\n🧠 Context Mesh 초기화"));
@@ -1142,8 +1288,25 @@ async function setupClaudeMd(cwd, extensions, force) {
1142
1288
  const extensionsList = extensions.length > 0
1143
1289
  ? extensions.map(pkg => `├── ${pkg}/ # ${EXTENSION_PACKAGES[pkg].name}`).join("\n")
1144
1290
  : "";
1145
- // 패키지별 CLAUDE.md 병합 섹션 생성
1291
+ // 그룹 및 패키지별 CLAUDE.md 병합 섹션 생성
1146
1292
  let packageClaudeMdSections = "";
1293
+ // 1. 설치된 패키지에서 그룹 추출 (중복 제거)
1294
+ const installedGroups = [...new Set(extensions.map(pkg => pkg.split("/")[0]).filter(g => PACKAGE_GROUPS.includes(g)))];
1295
+ // 2. 그룹 레벨 CLAUDE.md 먼저 병합 (biz, eng, ops)
1296
+ for (const group of installedGroups) {
1297
+ const groupClaudeMdPath = path.join(semoSystemDir, group, "CLAUDE.md");
1298
+ if (fs.existsSync(groupClaudeMdPath)) {
1299
+ const groupContent = fs.readFileSync(groupClaudeMdPath, "utf-8");
1300
+ // 그룹 CLAUDE.md 헤더 레벨 조정 (# → ##, ## → ###)
1301
+ const adjustedContent = groupContent
1302
+ .replace(/^# /gm, "## ")
1303
+ .replace(/^## /gm, "### ")
1304
+ .replace(/^### /gm, "#### ");
1305
+ packageClaudeMdSections += `\n\n---\n\n${adjustedContent}`;
1306
+ console.log(chalk_1.default.green(` + ${group}/ 그룹 CLAUDE.md 병합됨`));
1307
+ }
1308
+ }
1309
+ // 3. 개별 패키지 CLAUDE.md 병합
1147
1310
  for (const pkg of extensions) {
1148
1311
  const pkgClaudeMdPath = path.join(semoSystemDir, pkg, "CLAUDE.md");
1149
1312
  if (fs.existsSync(pkgClaudeMdPath)) {
@@ -1337,7 +1500,9 @@ program
1337
1500
  }
1338
1501
  console.log();
1339
1502
  }
1340
- // 이미 설치된 패키지 확인
1503
+ // 기존에 설치된 모든 Extension 패키지 스캔
1504
+ const previouslyInstalled = getInstalledExtensions(cwd);
1505
+ // 요청한 패키지 중 이미 설치된 것과 새로 설치할 것 분류
1341
1506
  const alreadyInstalled = [];
1342
1507
  const toInstall = [];
1343
1508
  for (const pkg of packages) {
@@ -1364,8 +1529,8 @@ program
1364
1529
  await downloadExtensions(cwd, toInstall, options.force);
1365
1530
  // 2. settings.json 병합
1366
1531
  await mergeExtensionSettings(cwd, toInstall);
1367
- // 3. 심볼릭 링크 설정 (모든 설치된 패키지 포함하여 orchestrator 병합)
1368
- const allInstalledPackages = [...new Set([...alreadyInstalled, ...toInstall])];
1532
+ // 3. 심볼릭 링크 설정 (기존 + 새로 설치한 모든 패키지 포함)
1533
+ const allInstalledPackages = [...new Set([...previouslyInstalled, ...toInstall])];
1369
1534
  await setupExtensionSymlinks(cwd, allInstalledPackages);
1370
1535
  // 4. CLAUDE.md 재생성 (모든 설치된 패키지 반영)
1371
1536
  await setupClaudeMd(cwd, allInstalledPackages, options.force);
@@ -1594,7 +1759,18 @@ program
1594
1759
  }
1595
1760
  }
1596
1761
  }
1597
- // Standard 심볼릭 링크 재생성
1762
+ // commands 링크도 정리 (신규 commands 반영 위해)
1763
+ const claudeCommandsDir = path.join(claudeDir, "commands");
1764
+ const semoCommandsLink = path.join(claudeCommandsDir, "SEMO");
1765
+ if (fs.existsSync(semoCommandsLink)) {
1766
+ if (fs.lstatSync(semoCommandsLink).isSymbolicLink()) {
1767
+ fs.unlinkSync(semoCommandsLink);
1768
+ }
1769
+ else {
1770
+ removeRecursive(semoCommandsLink);
1771
+ }
1772
+ }
1773
+ // Standard 심볼릭 링크 재생성 (agents, skills, commands 포함)
1598
1774
  await createStandardSymlinks(cwd);
1599
1775
  // Extensions 심볼릭 링크 재생성
1600
1776
  if (installedExtensions.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@team-semicolon/semo-cli",
3
- "version": "3.0.7",
3
+ "version": "3.0.10",
4
4
  "description": "SEMO CLI - AI Agent Orchestration Framework Installer",
5
5
  "main": "dist/index.js",
6
6
  "bin": {