@su-record/vibe 3.2.15 → 3.2.16

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 (58) hide show
  1. package/dist/cli/commands/index.d.ts +1 -1
  2. package/dist/cli/commands/index.d.ts.map +1 -1
  3. package/dist/cli/commands/index.js +1 -1
  4. package/dist/cli/commands/index.js.map +1 -1
  5. package/dist/cli/commands/info.d.ts +3 -1
  6. package/dist/cli/commands/info.d.ts.map +1 -1
  7. package/dist/cli/commands/info.js +12 -3
  8. package/dist/cli/commands/info.js.map +1 -1
  9. package/dist/cli/commands/init.d.ts +0 -7
  10. package/dist/cli/commands/init.d.ts.map +1 -1
  11. package/dist/cli/commands/init.js +5 -37
  12. package/dist/cli/commands/init.js.map +1 -1
  13. package/dist/cli/commands/update.d.ts.map +1 -1
  14. package/dist/cli/commands/update.js +4 -6
  15. package/dist/cli/commands/update.js.map +1 -1
  16. package/dist/cli/commands/upgrade.d.ts +1 -1
  17. package/dist/cli/commands/upgrade.d.ts.map +1 -1
  18. package/dist/cli/commands/upgrade.js +7 -2
  19. package/dist/cli/commands/upgrade.js.map +1 -1
  20. package/dist/cli/postinstall/claude-agents.js +1 -1
  21. package/dist/cli/postinstall/claude-agents.js.map +1 -1
  22. package/dist/cli/postinstall/constants.d.ts +0 -1
  23. package/dist/cli/postinstall/constants.d.ts.map +1 -1
  24. package/dist/cli/postinstall/constants.js +0 -8
  25. package/dist/cli/postinstall/constants.js.map +1 -1
  26. package/dist/cli/postinstall/main.d.ts.map +1 -1
  27. package/dist/cli/postinstall/main.js +20 -13
  28. package/dist/cli/postinstall/main.js.map +1 -1
  29. package/dist/cli/postinstall.d.ts +0 -3
  30. package/dist/cli/postinstall.d.ts.map +1 -1
  31. package/dist/cli/postinstall.js +0 -3
  32. package/dist/cli/postinstall.js.map +1 -1
  33. package/dist/cli/setup/InstallHome.d.ts +27 -0
  34. package/dist/cli/setup/InstallHome.d.ts.map +1 -0
  35. package/dist/cli/setup/InstallHome.js +105 -0
  36. package/dist/cli/setup/InstallHome.js.map +1 -0
  37. package/dist/cli/setup/ProjectSetup.d.ts +0 -8
  38. package/dist/cli/setup/ProjectSetup.d.ts.map +1 -1
  39. package/dist/cli/setup/ProjectSetup.js +0 -96
  40. package/dist/cli/setup/ProjectSetup.js.map +1 -1
  41. package/dist/cli/setup.d.ts +1 -1
  42. package/dist/cli/setup.d.ts.map +1 -1
  43. package/dist/cli/setup.js +1 -1
  44. package/dist/cli/setup.js.map +1 -1
  45. package/hooks/scripts/utils.js +32 -2
  46. package/package.json +1 -1
  47. package/dist/cli/postinstall/cursor-agents.d.ts +0 -13
  48. package/dist/cli/postinstall/cursor-agents.d.ts.map +0 -1
  49. package/dist/cli/postinstall/cursor-agents.js +0 -89
  50. package/dist/cli/postinstall/cursor-agents.js.map +0 -1
  51. package/dist/cli/postinstall/cursor-rules.d.ts +0 -11
  52. package/dist/cli/postinstall/cursor-rules.d.ts.map +0 -1
  53. package/dist/cli/postinstall/cursor-rules.js +0 -205
  54. package/dist/cli/postinstall/cursor-rules.js.map +0 -1
  55. package/dist/cli/postinstall/cursor-skills.d.ts +0 -9
  56. package/dist/cli/postinstall/cursor-skills.d.ts.map +0 -1
  57. package/dist/cli/postinstall/cursor-skills.js +0 -796
  58. package/dist/cli/postinstall/cursor-skills.js.map +0 -1
@@ -201,11 +201,18 @@ function npmRootFallback() {
201
201
  }
202
202
  const homeDir = os.homedir();
203
203
  const candidates = [
204
+ // node 바이너리에서 유도 — prefix 를 어떻게 잡았든 따라간다. 가장 확실하므로 먼저 본다.
205
+ // (/usr/bin/node → /usr/lib/node_modules, ~/.local/bin/node → ~/.local/lib/node_modules)
206
+ path.resolve(path.dirname(process.execPath), '..', 'lib', 'node_modules'),
204
207
  '/usr/local/lib/node_modules',
208
+ '/usr/lib/node_modules', // 배포판 npm (apt/dnf, prefix=/usr)
209
+ path.join(homeDir, '.local', 'lib', 'node_modules'), // 사용자 prefix — 격리 서버에서 흔하다
205
210
  path.join(homeDir, '.npm-global', 'lib', 'node_modules'),
206
211
  path.join(homeDir, '.nvm', 'versions', 'node', process.version, 'lib', 'node_modules'),
207
212
  ];
208
- return candidates.find(p => fs.existsSync(p)) || candidates[0];
213
+ // 패키지가 실제로 있는 후보를 고른다 — 디렉토리 존재만으로는 엉뚱한 prefix 를 집는다
214
+ const withPackage = candidates.find(p => fs.existsSync(path.join(p, '@su-record', 'vibe')));
215
+ return withPackage || candidates.find(p => fs.existsSync(p)) || candidates[0];
209
216
  }
210
217
 
211
218
  // L1 인-프로세스 캐시
@@ -248,6 +255,23 @@ function hasRuntimeDeps(packageRoot) {
248
255
  * 프로세스 내 메모이제이션: getToolsBaseUrl/getLibBaseUrl/getCliBaseUrl이 한 훅
249
256
  * 프로세스에서 각각 호출되면 최악 6회 동기 stat이 반복되므로 결과를 캐싱한다.
250
257
  */
258
+ /**
259
+ * 패키지 루트 해석 실패를 1회만 보고한다.
260
+ *
261
+ * 훅 호출부는 전부 fail-open(try/catch) 이라, 해석이 틀려도 사용자에게는
262
+ * "아무 일도 안 일어남" 으로만 보인다 — 조용히 죽은 가드다. 진단 단서를 남긴다.
263
+ */
264
+ let _warnedUnresolved = false;
265
+ function warnUnresolvedPackageRoot(subpath, candidates) {
266
+ if (_warnedUnresolved) return;
267
+ _warnedUnresolved = true;
268
+ process.stderr.write(
269
+ `[vibe] 패키지 루트를 찾지 못했습니다 (${subpath}).\n`
270
+ + ` 확인한 경로: ${candidates.join(', ')}\n`
271
+ + ` VIBE_PATH 를 설치 경로로 지정하거나 'vibe upgrade' 로 재설치하세요.\n`
272
+ );
273
+ }
274
+
251
275
  const _packageUrlCache = new Map();
252
276
  function getPackageUrl(subpath, probeFile) {
253
277
  const cacheKey = `${subpath}|${probeFile}`;
@@ -267,7 +291,13 @@ function getPackageUrl(subpath, probeFile) {
267
291
  break;
268
292
  }
269
293
  }
270
- if (result === null) result = toFileUrl(path.join(globalRoot, subpath));
294
+ if (result === null) {
295
+ // 후보가 전부 검증에 실패했다 — 지어낸 경로를 돌려주면 이후 모든 import 가
296
+ // 조용히 실패하고 도구 계층 전체가 죽은 채로 돈다. 경로는 종전대로 돌려주되
297
+ // (호출부는 fail-open 이므로 동작은 유지) 무슨 일이 있었는지는 남긴다.
298
+ result = toFileUrl(path.join(globalRoot, subpath));
299
+ warnUnresolvedPackageRoot(subpath, candidates);
300
+ }
271
301
  _packageUrlCache.set(cacheKey, result);
272
302
  return result;
273
303
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@su-record/vibe",
3
- "version": "3.2.15",
3
+ "version": "3.2.16",
4
4
  "description": "AI Coding Framework for Claude Code — 7+ agents, 52 skills, multi-LLM orchestration",
5
5
  "type": "module",
6
6
  "main": "dist/cli/index.js",
@@ -1,13 +0,0 @@
1
- /**
2
- * Cursor 에이전트 변환 및 설치
3
- *
4
- * 통합 리뷰어 2종(code-reviewer, security-reviewer)을 Cursor 서브에이전트로 설치.
5
- * (구 12종 리뷰어 매트릭스는 harness-review-2026-07-01 P2-1 에서 통합됨 —
6
- * survivor 에이전트는 goal+constraints 본문이라 Checklist/Output 섹션 파싱 대신
7
- * 본문 전체를 그대로 싣는다.)
8
- */
9
- /**
10
- * Cursor 서브에이전트 설치
11
- */
12
- export declare function installCursorAgents(agentsSource: string, cursorAgentsDir: string): void;
13
- //# sourceMappingURL=cursor-agents.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cursor-agents.d.ts","sourceRoot":"","sources":["../../../src/cli/postinstall/cursor-agents.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAgEH;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,CA0BvF"}
@@ -1,89 +0,0 @@
1
- /**
2
- * Cursor 에이전트 변환 및 설치
3
- *
4
- * 통합 리뷰어 2종(code-reviewer, security-reviewer)을 Cursor 서브에이전트로 설치.
5
- * (구 12종 리뷰어 매트릭스는 harness-review-2026-07-01 P2-1 에서 통합됨 —
6
- * survivor 에이전트는 goal+constraints 본문이라 Checklist/Output 섹션 파싱 대신
7
- * 본문 전체를 그대로 싣는다.)
8
- */
9
- import path from 'path';
10
- import fs from 'fs';
11
- import { ensureDir } from './fs-utils.js';
12
- import { CURSOR_MODEL_MAPPING } from './constants.js';
13
- /** Cursor 로 내보낼 리뷰어 에이전트 (agents/ 최상위 파일명) */
14
- const CURSOR_REVIEWER_FILES = [
15
- 'code-reviewer.md',
16
- 'security-reviewer.md',
17
- ];
18
- /**
19
- * VIBE 에이전트를 Cursor 서브에이전트 형식으로 변환
20
- */
21
- function convertAgentToCursor(content, filename) {
22
- // Windows CRLF → LF 정규화
23
- const normalizedContent = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
24
- const name = path.basename(filename, '.md');
25
- const model = CURSOR_MODEL_MAPPING[name] || 'auto';
26
- // 제목 추출
27
- const titleMatch = normalizedContent.match(/^# (.+)$/m);
28
- const title = titleMatch ? titleMatch[1].trim() : name;
29
- // Role 섹션 추출 (## Role 다음 내용을 다음 ## 전까지)
30
- const roleMatch = normalizedContent.match(/## Role\s*\n([\s\S]*?)(?=\n## )/);
31
- const roleLines = roleMatch
32
- ? roleMatch[1]
33
- .split('\n')
34
- .filter((line) => line.trim().startsWith('- '))
35
- .map((line) => line.trim().replace(/^- /, '').trim())
36
- .slice(0, 3)
37
- : [];
38
- const roleDesc = roleLines.join(', ');
39
- const descriptions = {
40
- 'code-reviewer': `Parameterized code reviewer (focus: correctness, architecture, performance, complexity, data-integrity, test-coverage, idioms, git-history). ${roleDesc}. Use proactively after code edits with an explicit focus.`,
41
- 'security-reviewer': `Threat-model-first security reviewer. ${roleDesc}. Use proactively after changes involving authentication, user input, or data handling.`,
42
- };
43
- const description = descriptions[name] || `${title}. ${roleDesc}. Use proactively after code edits.`;
44
- // 기존 frontmatter 제거 후 본문 유지 (survivor 에이전트는 goal+constraints 본문)
45
- const body = normalizedContent.replace(/^---\n[\s\S]*?\n---\n/, '').trim();
46
- return `---
47
- name: ${name}
48
- model: ${model}
49
- description: ${description}
50
- ---
51
-
52
- ## When Invoked
53
-
54
- 1. Run \`git diff\` to see recent changes
55
- 2. Focus on modified files relevant to this review
56
- 3. Begin review immediately without asking questions
57
-
58
- ${body}
59
- `;
60
- }
61
- /**
62
- * Cursor 서브에이전트 설치
63
- */
64
- export function installCursorAgents(agentsSource, cursorAgentsDir) {
65
- if (!fs.existsSync(agentsSource)) {
66
- console.log(` ⚠️ agents directory not found: ${agentsSource}`);
67
- return;
68
- }
69
- ensureDir(cursorAgentsDir);
70
- let installed = 0;
71
- for (const file of CURSOR_REVIEWER_FILES) {
72
- const sourcePath = path.join(agentsSource, file);
73
- if (!fs.existsSync(sourcePath)) {
74
- console.warn(` ⚠️ Cursor reviewer source missing: ${file}`);
75
- continue;
76
- }
77
- try {
78
- const content = fs.readFileSync(sourcePath, 'utf-8');
79
- const cursorContent = convertAgentToCursor(content, file);
80
- fs.writeFileSync(path.join(cursorAgentsDir, file), cursorContent, 'utf-8');
81
- installed++;
82
- }
83
- catch (err) {
84
- console.warn(` ⚠️ Failed to convert ${file}: ${err.message}`);
85
- }
86
- }
87
- console.log(` 📦 Cursor agents: ${installed}/${CURSOR_REVIEWER_FILES.length} installed`);
88
- }
89
- //# sourceMappingURL=cursor-agents.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cursor-agents.js","sourceRoot":"","sources":["../../../src/cli/postinstall/cursor-agents.ts"],"names":[],"mappings":"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"}
@@ -1,11 +0,0 @@
1
- /**
2
- * Cursor 룰 변환 및 생성
3
- */
4
- /**
5
- * Cursor 프로젝트 룰 템플릿 생성 (VIBE 언어 룰 기반)
6
- * @param cursorRulesDir - 룰 파일 저장 경로
7
- * @param detectedStacks - 감지된 기술 스택 배열 (예: ['typescript-react', 'python-fastapi'])
8
- * @param languagesDir - VIBE 언어 룰 디렉토리 (optional)
9
- */
10
- export declare function generateCursorRules(cursorRulesDir: string, detectedStacks?: string[], languagesDir?: string): void;
11
- //# sourceMappingURL=cursor-rules.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cursor-rules.d.ts","sourceRoot":"","sources":["../../../src/cli/postinstall/cursor-rules.ts"],"names":[],"mappings":"AAAA;;GAEG;AAiGH;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,MAAM,EACtB,cAAc,GAAE,MAAM,EAAO,EAC7B,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI,CAiIN"}
@@ -1,205 +0,0 @@
1
- /**
2
- * Cursor 룰 변환 및 생성
3
- */
4
- import path from 'path';
5
- import fs from 'fs';
6
- import { ensureDir } from './fs-utils.js';
7
- import { STACK_TO_LANGUAGE_FILE, LANGUAGE_GLOBS, LANGUAGE_RULE_PREFIXES, LEGACY_RULE_FILES, } from './constants.js';
8
- /**
9
- * VIBE 언어 룰 파일을 Cursor .mdc 형식으로 변환
10
- */
11
- function convertLanguageRuleToCursor(content, filename) {
12
- // Windows CRLF → LF 정규화
13
- const normalizedContent = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
14
- // 제목 추출
15
- const titleMatch = normalizedContent.match(/^# (.+)$/m);
16
- const title = titleMatch ? titleMatch[1].trim() : filename.replace('.md', '');
17
- // 설명 생성 - 제목에서 "Quality Rules" 제거하고 간결하게
18
- const description = title
19
- .replace(' Quality Rules', ' coding standards')
20
- .replace(' Specific Rules', ' best practices');
21
- // glob 패턴 가져오기
22
- const globs = LANGUAGE_GLOBS[filename] || '**/*';
23
- // .mdc frontmatter + 본문
24
- return `---
25
- description: ${description} - complexity limits, type safety, error handling
26
- globs: "${globs}"
27
- alwaysApply: false
28
- ---
29
-
30
- ${normalizedContent}
31
- `;
32
- }
33
- /**
34
- * VIBE 언어 룰 디렉토리에서 .mdc 파일 생성
35
- * @param languagesDir - VIBE 언어 룰 디렉토리 (~/.claude/vibe/languages/ 또는 패키지 내 languages/)
36
- * @param outputDir - Cursor 룰 출력 디렉토리 (~/.cursor/rules-template/)
37
- * @param detectedStacks - 감지된 기술 스택 배열 (예: ['typescript-react', 'python-fastapi'])
38
- * @returns 생성된 파일 수
39
- */
40
- function generateCursorRulesFromCoreLanguages(languagesDir, outputDir, detectedStacks = []) {
41
- if (!fs.existsSync(languagesDir)) {
42
- return 0;
43
- }
44
- ensureDir(outputDir);
45
- // 감지된 스택에 해당하는 언어 파일 결정
46
- const targetFiles = new Set();
47
- if (detectedStacks.length === 0) {
48
- // 스택 감지 없으면 공통 룰만 생성 (hardcoded fallback)
49
- return 0;
50
- }
51
- for (const stack of detectedStacks) {
52
- const languageFile = STACK_TO_LANGUAGE_FILE[stack.toLowerCase()];
53
- if (languageFile) {
54
- targetFiles.add(languageFile);
55
- }
56
- }
57
- let generated = 0;
58
- for (const file of targetFiles) {
59
- const sourcePath = path.join(languagesDir, file);
60
- if (!fs.existsSync(sourcePath)) {
61
- continue;
62
- }
63
- try {
64
- const content = fs.readFileSync(sourcePath, 'utf-8');
65
- const mdcContent = convertLanguageRuleToCursor(content, file);
66
- const destPath = path.join(outputDir, file.replace('.md', '.mdc'));
67
- fs.writeFileSync(destPath, mdcContent, 'utf-8');
68
- generated++;
69
- }
70
- catch {
71
- // 무시 - 파일 읽기/쓰기 실패
72
- }
73
- }
74
- return generated;
75
- }
76
- /**
77
- * Cursor 프로젝트 룰 템플릿 생성 (VIBE 언어 룰 기반)
78
- * @param cursorRulesDir - 룰 파일 저장 경로
79
- * @param detectedStacks - 감지된 기술 스택 배열 (예: ['typescript-react', 'python-fastapi'])
80
- * @param languagesDir - VIBE 언어 룰 디렉토리 (optional)
81
- */
82
- export function generateCursorRules(cursorRulesDir, detectedStacks = [], languagesDir) {
83
- ensureDir(cursorRulesDir);
84
- // 0. 기존 언어 룰 + 레거시 파일 정리
85
- try {
86
- const existingFiles = fs.readdirSync(cursorRulesDir).filter(f => f.endsWith('.mdc'));
87
- for (const file of existingFiles) {
88
- const isLanguageRule = LANGUAGE_RULE_PREFIXES.some(prefix => file.startsWith(prefix));
89
- const isLegacy = LEGACY_RULE_FILES.includes(file);
90
- if (isLanguageRule || isLegacy) {
91
- fs.unlinkSync(path.join(cursorRulesDir, file));
92
- }
93
- }
94
- }
95
- catch {
96
- // 무시
97
- }
98
- // 1. VIBE 언어 룰에서 .mdc 생성 시도
99
- let coreRulesGenerated = 0;
100
- if (languagesDir && detectedStacks.length > 0) {
101
- coreRulesGenerated = generateCursorRulesFromCoreLanguages(languagesDir, cursorRulesDir, detectedStacks);
102
- }
103
- // 2. 공통 룰 (모든 프로젝트에 적용)
104
- const commonRules = [
105
- {
106
- filename: 'code-quality.mdc',
107
- content: `---
108
- description: General code quality rules for all files
109
- alwaysApply: true
110
- ---
111
-
112
- # Code Quality Rules
113
-
114
- ## Core Principles
115
- - **Modify only requested scope** - Don't touch unrelated code
116
- - **Preserve existing style** - Follow project conventions
117
- - **Keep working code** - No unnecessary refactoring
118
-
119
- ## Forbidden Patterns
120
- - No \`console.log\` in production code (remove after debugging)
121
- - No hardcoded strings/numbers → Extract to constants
122
- - No commented-out code in commits
123
- - No incomplete code without TODO marker
124
-
125
- ## Naming Conventions
126
- - Variables/functions: camelCase
127
- - Classes/types: PascalCase
128
- - Constants: UPPER_SNAKE_CASE
129
- - Files: kebab-case or PascalCase (match project style)
130
-
131
- ## Function Design
132
- - Single responsibility per function
133
- - Max 5 parameters (use object for more)
134
- - Descriptive names (verb + noun)
135
- - Document non-obvious behavior
136
-
137
- ## Complexity Limits
138
- | Metric | Limit |
139
- |--------|-------|
140
- | Function length | ≤30 lines (recommended), ≤50 lines (max) |
141
- | Nesting depth | ≤3 levels |
142
- | Parameters | ≤5 |
143
- | Cyclomatic complexity | ≤10 |
144
-
145
- ## Dependency Management
146
- - Avoid circular dependencies
147
- - Keep loose coupling (depend on interfaces)
148
- - High cohesion (group related functions)
149
- `,
150
- },
151
- {
152
- filename: 'security-checklist.mdc',
153
- content: `---
154
- description: Security checklist for code changes
155
- globs: "**/*.ts,**/*.tsx,**/*.js,**/*.jsx,**/*.py,**/*.go,**/*.rs,**/*.java,**/*.kt,**/*.swift"
156
- alwaysApply: false
157
- ---
158
-
159
- # Security Checklist
160
-
161
- ## Input Validation
162
- - [ ] Validate all user inputs
163
- - [ ] Sanitize data before database queries
164
- - [ ] Use parameterized queries (prevent SQL injection)
165
-
166
- ## Authentication
167
- - [ ] Secure password handling (never store plain text)
168
- - [ ] Session management is secure
169
- - [ ] Tokens have appropriate expiry
170
-
171
- ## Data Protection
172
- - [ ] Sensitive data is encrypted
173
- - [ ] API keys not committed to code
174
- - [ ] Error messages don't leak sensitive info
175
-
176
- ## OWASP Top 10 Awareness
177
- - Injection (SQL, XSS, Command)
178
- - Broken authentication
179
- - Sensitive data exposure
180
- - XML external entities (XXE)
181
- - Broken access control
182
- - Security misconfiguration
183
- - Cross-site scripting (XSS)
184
- - Insecure deserialization
185
- - Using components with known vulnerabilities
186
- - Insufficient logging & monitoring
187
- `,
188
- },
189
- ];
190
- let commonUpdated = 0;
191
- for (const rule of commonRules) {
192
- const destPath = path.join(cursorRulesDir, rule.filename);
193
- try {
194
- fs.writeFileSync(destPath, rule.content, 'utf-8');
195
- commonUpdated++;
196
- }
197
- catch {
198
- // 무시 - 권한 문제 등
199
- }
200
- }
201
- const totalUpdated = coreRulesGenerated + commonUpdated;
202
- const stackInfo = detectedStacks.length > 0 ? ` (${detectedStacks.slice(0, 3).join(', ')}${detectedStacks.length > 3 ? '...' : ''})` : '';
203
- console.log(` 📏 Cursor rules: ${totalUpdated} updated (${coreRulesGenerated} language + ${commonUpdated} common)${stackInfo}`);
204
- }
205
- //# sourceMappingURL=cursor-rules.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cursor-rules.js","sourceRoot":"","sources":["../../../src/cli/postinstall/cursor-rules.ts"],"names":[],"mappings":"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"}
@@ -1,9 +0,0 @@
1
- /**
2
- * Cursor Skills 생성 (VIBE 커맨드 → Cursor 스킬 변환)
3
- */
4
- /**
5
- * Cursor Skills 생성 (VIBE 커맨드 → Cursor 스킬 변환)
6
- * 설치 경로: ~/.cursor/skills/[skill-name]/SKILL.md
7
- */
8
- export declare function generateCursorSkills(cursorSkillsDir: string): void;
9
- //# sourceMappingURL=cursor-skills.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cursor-skills.d.ts","sourceRoot":"","sources":["../../../src/cli/postinstall/cursor-skills.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAixBlE"}