@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.
- package/dist/cli/commands/index.d.ts +1 -1
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +1 -1
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/info.d.ts +3 -1
- package/dist/cli/commands/info.d.ts.map +1 -1
- package/dist/cli/commands/info.js +12 -3
- package/dist/cli/commands/info.js.map +1 -1
- package/dist/cli/commands/init.d.ts +0 -7
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +5 -37
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +4 -6
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/upgrade.d.ts +1 -1
- package/dist/cli/commands/upgrade.d.ts.map +1 -1
- package/dist/cli/commands/upgrade.js +7 -2
- package/dist/cli/commands/upgrade.js.map +1 -1
- package/dist/cli/postinstall/claude-agents.js +1 -1
- package/dist/cli/postinstall/claude-agents.js.map +1 -1
- package/dist/cli/postinstall/constants.d.ts +0 -1
- package/dist/cli/postinstall/constants.d.ts.map +1 -1
- package/dist/cli/postinstall/constants.js +0 -8
- package/dist/cli/postinstall/constants.js.map +1 -1
- package/dist/cli/postinstall/main.d.ts.map +1 -1
- package/dist/cli/postinstall/main.js +20 -13
- package/dist/cli/postinstall/main.js.map +1 -1
- package/dist/cli/postinstall.d.ts +0 -3
- package/dist/cli/postinstall.d.ts.map +1 -1
- package/dist/cli/postinstall.js +0 -3
- package/dist/cli/postinstall.js.map +1 -1
- package/dist/cli/setup/InstallHome.d.ts +27 -0
- package/dist/cli/setup/InstallHome.d.ts.map +1 -0
- package/dist/cli/setup/InstallHome.js +105 -0
- package/dist/cli/setup/InstallHome.js.map +1 -0
- package/dist/cli/setup/ProjectSetup.d.ts +0 -8
- package/dist/cli/setup/ProjectSetup.d.ts.map +1 -1
- package/dist/cli/setup/ProjectSetup.js +0 -96
- package/dist/cli/setup/ProjectSetup.js.map +1 -1
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +1 -1
- package/dist/cli/setup.js.map +1 -1
- package/hooks/scripts/utils.js +32 -2
- package/package.json +1 -1
- package/dist/cli/postinstall/cursor-agents.d.ts +0 -13
- package/dist/cli/postinstall/cursor-agents.d.ts.map +0 -1
- package/dist/cli/postinstall/cursor-agents.js +0 -89
- package/dist/cli/postinstall/cursor-agents.js.map +0 -1
- package/dist/cli/postinstall/cursor-rules.d.ts +0 -11
- package/dist/cli/postinstall/cursor-rules.d.ts.map +0 -1
- package/dist/cli/postinstall/cursor-rules.js +0 -205
- package/dist/cli/postinstall/cursor-rules.js.map +0 -1
- package/dist/cli/postinstall/cursor-skills.d.ts +0 -9
- package/dist/cli/postinstall/cursor-skills.d.ts.map +0 -1
- package/dist/cli/postinstall/cursor-skills.js +0 -796
- package/dist/cli/postinstall/cursor-skills.js.map +0 -1
package/hooks/scripts/utils.js
CHANGED
|
@@ -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
|
-
|
|
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)
|
|
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,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"}
|