@su-record/vibe 0.4.4 → 0.4.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/bin/vibe CHANGED
@@ -11,6 +11,18 @@ const fs = require('fs');
11
11
  const args = process.argv.slice(2);
12
12
  const command = args[0];
13
13
 
14
+ // 옵션 파싱
15
+ const options = {
16
+ silent: args.includes('--silent') || args.includes('-s')
17
+ };
18
+
19
+ // 로그 함수 (silent 모드 지원)
20
+ function log(message) {
21
+ if (!options.silent) {
22
+ console.log(message);
23
+ }
24
+ }
25
+
14
26
  // 유틸리티 함수
15
27
  function ensureDir(dir) {
16
28
  if (!fs.existsSync(dir)) {
@@ -43,6 +55,94 @@ function copyDirRecursive(sourceDir, targetDir) {
43
55
  });
44
56
  }
45
57
 
58
+ // 협업자 자동 설치 설정
59
+ function setupCollaboratorAutoInstall(projectRoot) {
60
+ const packageJsonPath = path.join(projectRoot, 'package.json');
61
+ const vibeDir = path.join(projectRoot, '.vibe');
62
+ const packageJson = require('../package.json');
63
+ const vibeVersion = packageJson.version;
64
+
65
+ // 1. Node.js 프로젝트: package.json에 devDependency + postinstall 추가
66
+ if (fs.existsSync(packageJsonPath)) {
67
+ try {
68
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
69
+
70
+ let modified = false;
71
+
72
+ // devDependencies에 vibe 추가
73
+ if (!pkg.devDependencies) {
74
+ pkg.devDependencies = {};
75
+ }
76
+ if (!pkg.devDependencies['@su-record/vibe']) {
77
+ pkg.devDependencies['@su-record/vibe'] = `^${vibeVersion}`;
78
+ modified = true;
79
+ }
80
+
81
+ // scripts에 postinstall 추가
82
+ if (!pkg.scripts) {
83
+ pkg.scripts = {};
84
+ }
85
+ if (!pkg.scripts.postinstall) {
86
+ pkg.scripts.postinstall = 'vibe update --silent';
87
+ modified = true;
88
+ } else if (!pkg.scripts.postinstall.includes('vibe update')) {
89
+ // 기존 postinstall이 있으면 vibe update 추가
90
+ pkg.scripts.postinstall = `${pkg.scripts.postinstall} && vibe update --silent`;
91
+ modified = true;
92
+ }
93
+
94
+ if (modified) {
95
+ fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n');
96
+ log(' ✅ package.json에 협업자 자동 설치 설정 추가\n');
97
+ } else {
98
+ log(' ℹ️ package.json 협업 설정 이미 존재\n');
99
+ }
100
+ } catch (e) {
101
+ log(' ⚠️ package.json 수정 실패: ' + e.message + '\n');
102
+ }
103
+ }
104
+
105
+ // 2. 범용: .vibe/setup.sh 생성 (비-Node 프로젝트 또는 추가 지원)
106
+ const setupShPath = path.join(vibeDir, 'setup.sh');
107
+ if (!fs.existsSync(setupShPath)) {
108
+ const setupScript = `#!/bin/bash
109
+ # Vibe 협업자 자동 설치 스크립트
110
+ # 사용법: ./.vibe/setup.sh
111
+
112
+ set -e
113
+
114
+ echo "🔧 Vibe 설치 확인 중..."
115
+
116
+ # npm/npx 확인
117
+ if ! command -v npx &> /dev/null; then
118
+ echo "❌ Node.js/npm이 설치되어 있지 않습니다."
119
+ echo " https://nodejs.org 에서 설치해주세요."
120
+ exit 1
121
+ fi
122
+
123
+ # vibe 설치 확인 및 업데이트
124
+ if command -v vibe &> /dev/null; then
125
+ echo "✅ Vibe가 이미 설치되어 있습니다."
126
+ vibe update --silent
127
+ echo "✅ Vibe 업데이트 완료!"
128
+ else
129
+ echo "📦 Vibe 설치 중..."
130
+ npm install -g @su-record/vibe
131
+ vibe update --silent
132
+ echo "✅ Vibe 설치 및 설정 완료!"
133
+ fi
134
+
135
+ echo ""
136
+ echo "다음 명령어로 시작하세요:"
137
+ echo " /vibe.spec \\"기능명\\" SPEC 작성"
138
+ echo " /vibe.run \\"기능명\\" 구현 실행"
139
+ `;
140
+ fs.writeFileSync(setupShPath, setupScript);
141
+ fs.chmodSync(setupShPath, '755');
142
+ log(' ✅ 협업자 설치 스크립트 생성 (.vibe/setup.sh)\n');
143
+ }
144
+ }
145
+
46
146
  // 프로젝트 초기화
47
147
  async function init(projectName) {
48
148
  try {
@@ -53,34 +153,34 @@ async function init(projectName) {
53
153
  projectRoot = path.join(process.cwd(), projectName);
54
154
 
55
155
  if (fs.existsSync(projectRoot)) {
56
- console.log(`❌ 폴더가 이미 존재합니다: ${projectName}/`);
156
+ log(`❌ 폴더가 이미 존재합니다: ${projectName}/`);
57
157
  return;
58
158
  }
59
159
 
60
- console.log(`📁 새 프로젝트 생성: ${projectName}/\n`);
160
+ log(`📁 새 프로젝트 생성: ${projectName}/\n`);
61
161
  fs.mkdirSync(projectRoot, { recursive: true });
62
162
  isNewProject = true;
63
163
  }
64
164
 
65
165
  const vibeDir = path.join(projectRoot, '.vibe');
66
166
  if (fs.existsSync(vibeDir)) {
67
- console.log('❌ .vibe/ 폴더가 이미 존재합니다.');
167
+ log('❌ .vibe/ 폴더가 이미 존재합니다.');
68
168
  return;
69
169
  }
70
170
 
71
171
  // MCP 서버 등록 (Claude Code)
72
172
  const mcpPath = path.join(__dirname, '..', 'node_modules', '@su-record', 'hi-ai', 'dist', 'index.js');
73
173
 
74
- console.log('🔧 Claude Code MCP 서버 등록 중...\n');
174
+ log('🔧 Claude Code MCP 서버 등록 중...\n');
75
175
  const { execSync } = require('child_process');
76
176
  try {
77
177
  execSync(`claude mcp add vibe node "${mcpPath}"`, { stdio: 'pipe' });
78
- console.log(' ✅ MCP 서버 등록 완료\n');
178
+ log(' ✅ MCP 서버 등록 완료\n');
79
179
  } catch (e) {
80
180
  if (e.message.includes('already exists')) {
81
- console.log(' ℹ️ MCP 서버 이미 등록됨\n');
181
+ log(' ℹ️ MCP 서버 이미 등록됨\n');
82
182
  } else {
83
- console.log(' ⚠️ MCP 수동 등록 필요\n');
183
+ log(' ⚠️ MCP 수동 등록 필요\n');
84
184
  }
85
185
  }
86
186
 
@@ -98,7 +198,7 @@ async function init(projectName) {
98
198
 
99
199
  const sourceDir = path.join(__dirname, '../.claude/commands');
100
200
  copyDirContents(sourceDir, commandsDir);
101
- console.log(' ✅ 슬래시 커맨드 설치 완료 (7개)\n');
201
+ log(' ✅ 슬래시 커맨드 설치 완료 (7개)\n');
102
202
 
103
203
  // 설정 파일 생성
104
204
  const templatePath = path.join(__dirname, '../templates/constitution-template.md');
@@ -126,28 +226,28 @@ async function init(projectName) {
126
226
  // vibe 섹션이 없으면 끝에 추가
127
227
  const mergedContent = existingContent.trim() + '\n\n---\n\n' + vibeContent;
128
228
  fs.writeFileSync(projectClaudeMd, mergedContent);
129
- console.log(' ✅ CLAUDE.md에 vibe 섹션 추가\n');
229
+ log(' ✅ CLAUDE.md에 vibe 섹션 추가\n');
130
230
  } else {
131
- console.log(' ℹ️ CLAUDE.md에 vibe 섹션 이미 존재\n');
231
+ log(' ℹ️ CLAUDE.md에 vibe 섹션 이미 존재\n');
132
232
  }
133
233
  } else {
134
234
  // 없으면 새로 생성
135
235
  fs.copyFileSync(vibeClaudeMd, projectClaudeMd);
136
- console.log(' ✅ CLAUDE.md 생성\n');
236
+ log(' ✅ CLAUDE.md 생성\n');
137
237
  }
138
238
 
139
239
  // .agent/rules/ 복사 (코딩 규칙)
140
240
  const rulesSource = path.join(__dirname, '../.agent/rules');
141
241
  const rulesTarget = path.join(projectRoot, '.agent/rules');
142
242
  copyDirRecursive(rulesSource, rulesTarget);
143
- console.log(' ✅ 코딩 규칙 설치 완료 (.agent/rules/)\n');
243
+ log(' ✅ 코딩 규칙 설치 완료 (.agent/rules/)\n');
144
244
 
145
245
  // .claude/agents/ 복사 (서브에이전트)
146
246
  const agentsDir = path.join(claudeDir, 'agents');
147
247
  ensureDir(agentsDir);
148
248
  const agentsSourceDir = path.join(__dirname, '../.claude/agents');
149
249
  copyDirContents(agentsSourceDir, agentsDir);
150
- console.log(' ✅ 서브에이전트 설치 완료 (.claude/agents/)\n');
250
+ log(' ✅ 서브에이전트 설치 완료 (.claude/agents/)\n');
151
251
 
152
252
  // .claude/settings.local.json 생성 (Hooks 설정)
153
253
  const settingsPath = path.join(claudeDir, 'settings.local.json');
@@ -155,14 +255,17 @@ async function init(projectName) {
155
255
  const hooksTemplate = path.join(__dirname, '../templates/hooks-template.json');
156
256
  if (fs.existsSync(hooksTemplate)) {
157
257
  fs.copyFileSync(hooksTemplate, settingsPath);
158
- console.log(' ✅ Hooks 설정 설치 완료 (.claude/settings.local.json)\n');
258
+ log(' ✅ Hooks 설정 설치 완료 (.claude/settings.local.json)\n');
159
259
  }
160
260
  } else {
161
- console.log(' ℹ️ Hooks 설정 이미 존재\n');
261
+ log(' ℹ️ Hooks 설정 이미 존재\n');
162
262
  }
163
263
 
264
+ // 협업자 자동 설치 설정
265
+ setupCollaboratorAutoInstall(projectRoot);
266
+
164
267
  // 완료 메시지
165
- console.log(`
268
+ log(`
166
269
  ✅ vibe 초기화 완료!
167
270
 
168
271
  ${isNewProject ? `프로젝트 위치:
@@ -181,10 +284,12 @@ ${isNewProject ? `프로젝트 위치:
181
284
  .vibe/
182
285
  ├── config.json # 프로젝트 설정
183
286
  ├── constitution.md # 프로젝트 원칙
287
+ ├── setup.sh # 협업자 설치 스크립트
184
288
  ├── specs/ # SPEC 문서들
185
289
  └── features/ # BDD Feature 파일들
186
290
 
187
291
  MCP 서버 (hi-ai): ✓
292
+ 협업자 자동 설치: ✓
188
293
 
189
294
  사용법:
190
295
  /vibe.spec "기능명" SPEC 작성 (대화형)
@@ -244,27 +349,27 @@ async function update() {
244
349
  return;
245
350
  }
246
351
 
247
- console.log('🔄 vibe 업데이트 중...\n');
352
+ log('🔄 vibe 업데이트 중...\n');
248
353
 
249
354
  // .claude/commands 업데이트
250
355
  const commandsDir = path.join(claudeDir, 'commands');
251
356
  ensureDir(commandsDir);
252
357
  const sourceDir = path.join(__dirname, '../.claude/commands');
253
358
  copyDirContents(sourceDir, commandsDir);
254
- console.log(' ✅ 슬래시 커맨드 업데이트 완료 (7개)\n');
359
+ log(' ✅ 슬래시 커맨드 업데이트 완료 (7개)\n');
255
360
 
256
361
  // .agent/rules/ 업데이트
257
362
  const rulesSource = path.join(__dirname, '../.agent/rules');
258
363
  const rulesTarget = path.join(projectRoot, '.agent/rules');
259
364
  copyDirRecursive(rulesSource, rulesTarget);
260
- console.log(' ✅ 코딩 규칙 업데이트 완료 (.agent/rules/)\n');
365
+ log(' ✅ 코딩 규칙 업데이트 완료 (.agent/rules/)\n');
261
366
 
262
367
  // .claude/agents/ 업데이트
263
368
  const agentsDir = path.join(claudeDir, 'agents');
264
369
  ensureDir(agentsDir);
265
370
  const agentsSourceDir = path.join(__dirname, '../.claude/agents');
266
371
  copyDirContents(agentsSourceDir, agentsDir);
267
- console.log(' ✅ 서브에이전트 업데이트 완료 (.claude/agents/)\n');
372
+ log(' ✅ 서브에이전트 업데이트 완료 (.claude/agents/)\n');
268
373
 
269
374
  // settings.local.json에 hooks 병합
270
375
  const settingsPath = path.join(claudeDir, 'settings.local.json');
@@ -280,19 +385,29 @@ async function update() {
280
385
  if (!existingSettings.hooks) {
281
386
  existingSettings.hooks = vibeHooks.hooks;
282
387
  fs.writeFileSync(settingsPath, JSON.stringify(existingSettings, null, 2));
283
- console.log(' ✅ Hooks 설정 추가 완료\n');
388
+ log(' ✅ Hooks 설정 추가 완료\n');
284
389
  } else {
285
- console.log(' ℹ️ Hooks 설정 이미 존재\n');
390
+ log(' ℹ️ Hooks 설정 이미 존재\n');
286
391
  }
287
392
  } else {
288
393
  // 새로 생성
289
394
  fs.copyFileSync(hooksTemplate, settingsPath);
290
- console.log(' ✅ Hooks 설정 생성 완료\n');
395
+ log(' ✅ Hooks 설정 생성 완료\n');
291
396
  }
292
397
  }
293
398
 
399
+ // MCP 서버 등록 확인
400
+ const mcpPath = path.join(__dirname, '..', 'node_modules', '@su-record', 'hi-ai', 'dist', 'index.js');
401
+ const { execSync } = require('child_process');
402
+ try {
403
+ execSync(`claude mcp add vibe node "${mcpPath}"`, { stdio: 'pipe' });
404
+ log(' ✅ MCP 서버 등록 완료\n');
405
+ } catch (e) {
406
+ // 이미 등록됨 - silent
407
+ }
408
+
294
409
  const packageJson = require('../package.json');
295
- console.log(`
410
+ log(`
296
411
  ✅ vibe 업데이트 완료! (v${packageJson.version})
297
412
 
298
413
  업데이트된 항목:
@@ -300,6 +415,7 @@ async function update() {
300
415
  - 코딩 규칙 (.agent/rules/)
301
416
  - 서브에이전트 (.claude/agents/)
302
417
  - Hooks 설정
418
+ - MCP 서버
303
419
  `);
304
420
 
305
421
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "Vibe - Claude Code exclusive SPEC-driven AI coding framework",
5
5
  "bin": {
6
6
  "vibe": "./bin/vibe"