jinhak-ai-standard 2.6.0
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/.claude/scripts/prompt-track.cjs +89 -0
- package/.claude/scripts/session-briefing.cjs +128 -0
- package/.claude/settings.json +110 -0
- package/.claude/skills/apply-standard/SKILL.md +252 -0
- package/.claude/skills/commit/SKILL.md +71 -0
- package/.claude/skills/debug/SKILL.md +84 -0
- package/.claude/skills/deep-plan/SKILL.md +468 -0
- package/.claude/skills/orchestrate/SKILL.md +220 -0
- package/.claude/skills/prompt-quality-check/SKILL.md +134 -0
- package/.claude/skills/prompt-register/SKILL.md +146 -0
- package/.claude/skills/prompt-report/SKILL.md +83 -0
- package/.claude/skills/prompt-search/SKILL.md +117 -0
- package/.claude/skills/review-pr/SKILL.md +76 -0
- package/.claude/skills/security-check/SKILL.md +128 -0
- package/.claude/skills/session-end/SKILL.md +64 -0
- package/.claude/skills/session-start/SKILL.md +85 -0
- package/.claude/skills/test/SKILL.md +99 -0
- package/ARCHITECTURE.md +463 -0
- package/CHANGELOG.md +683 -0
- package/CLAUDE.md +1168 -0
- package/CODING_CONVENTIONS.md +558 -0
- package/PROJECT_STRUCTURE.md +475 -0
- package/PROMPT-LIBRARY.md +217 -0
- package/PROMPT_LIBRARY_USAGE.md +343 -0
- package/QUICK_START_PROMPT.md +132 -0
- package/README.md +342 -0
- package/SECURITY_ISMS.md +514 -0
- package/VIBE_CODING_GUIDE.md +680 -0
- package/bin/cli.cjs +276 -0
- package/package.json +42 -0
- package/prompts/_template/metadata.json +22 -0
- package/prompts/_template/prompt.md +41 -0
- package/prompts/code-gen/react-component/metadata.json +22 -0
- package/prompts/code-gen/react-component/prompt.md +79 -0
- package/prompts/code-review/security-review/metadata.json +22 -0
- package/prompts/code-review/security-review/prompt.md +75 -0
- package/prompts/testing/unit-test-gen/metadata.json +22 -0
- package/prompts/testing/unit-test-gen/prompt.md +71 -0
- package/scripts/batch-apply.cjs +520 -0
- package/scripts/check-standard.cjs +66 -0
- package/scripts/install-global-hook.cjs +217 -0
- package/scripts/security-check-hook.cjs +139 -0
- package/scripts/session-briefing.cjs +151 -0
- package/scripts/session-end-reminder.cjs +42 -0
- package/security/AI_SECURITY_GUARDRAILS.md +379 -0
- package/security/DATA_CLASSIFICATION.md +242 -0
- package/security/FORBIDDEN_PATTERNS.md +484 -0
- package/security/INCIDENT_RESPONSE.md +301 -0
- package/security/NIGHTBUILDER_SECURITY.md +234 -0
- package/security/OWASP_LLM_CHECKLIST.md +231 -0
- package/templates/.eslintrc.security.js +98 -0
- package/templates/.secretlintrc.json +69 -0
- package/templates/.semgreprc.yml +137 -0
- package/templates/ai-folder-templates.md +372 -0
- package/templates/claude-local-template.md +143 -0
- package/templates/component-template.md +316 -0
- package/templates/husky-security-hooks.md +182 -0
- package/templates/memory-templates.md +122 -0
- package/templates/project-claude.md +232 -0
- package/templates/skill-testing-guide.md +35 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* prompt-track.cjs
|
|
3
|
+
* PostToolUse Hook — 프롬프트 사용 시 JABIS API에 자동 트래킹
|
|
4
|
+
*
|
|
5
|
+
* 환경변수:
|
|
6
|
+
* JABIS_API_URL - JABIS API Gateway URL (기본값: https://jabis-api.jinhakapply.com)
|
|
7
|
+
* PROMPT_API_KEY - 프롬프트 API Key
|
|
8
|
+
*
|
|
9
|
+
* 동작:
|
|
10
|
+
* - Edit/Write 도구 실행 후, 변경된 파일이 prompts/ 하위이면 'use' 이벤트 기록
|
|
11
|
+
* - 실패 시 무시 (사용자 워크플로우 차단 방지)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const https = require('https');
|
|
15
|
+
const http = require('http');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
const API_URL = process.env.JABIS_API_URL || 'https://jabis-api.jinhakapply.com';
|
|
19
|
+
const API_KEY = process.env.PROMPT_API_KEY || '';
|
|
20
|
+
|
|
21
|
+
// stdin에서 도구 실행 정보 읽기
|
|
22
|
+
let input = '';
|
|
23
|
+
process.stdin.setEncoding('utf8');
|
|
24
|
+
process.stdin.on('data', (chunk) => { input += chunk; });
|
|
25
|
+
process.stdin.on('end', () => {
|
|
26
|
+
try {
|
|
27
|
+
const data = JSON.parse(input);
|
|
28
|
+
const filePath = data.tool_input?.file_path || data.tool_input?.path || '';
|
|
29
|
+
|
|
30
|
+
// prompts/ 하위 파일 변경인지 확인
|
|
31
|
+
if (!filePath || !filePath.includes('prompts/')) return;
|
|
32
|
+
|
|
33
|
+
// _template 폴더는 제외
|
|
34
|
+
if (filePath.includes('_template/')) return;
|
|
35
|
+
|
|
36
|
+
// 프롬프트 ID 추출 (prompts/{category}/{id}/ 패턴)
|
|
37
|
+
const parts = filePath.split('/');
|
|
38
|
+
const promptsIdx = parts.indexOf('prompts');
|
|
39
|
+
if (promptsIdx < 0 || promptsIdx + 2 >= parts.length) return;
|
|
40
|
+
|
|
41
|
+
const promptId = parts[promptsIdx + 2];
|
|
42
|
+
if (!promptId) return;
|
|
43
|
+
|
|
44
|
+
// API Key가 없으면 무시
|
|
45
|
+
if (!API_KEY) return;
|
|
46
|
+
|
|
47
|
+
// 트래킹 API 호출
|
|
48
|
+
const body = JSON.stringify({
|
|
49
|
+
action: 'track',
|
|
50
|
+
prompt_id: promptId,
|
|
51
|
+
event: 'use',
|
|
52
|
+
context: {
|
|
53
|
+
project: path.basename(process.cwd()),
|
|
54
|
+
source: 'claude-code-hook',
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const url = new URL(`${API_URL}/api/prompts`);
|
|
59
|
+
const isHttps = url.protocol === 'https:';
|
|
60
|
+
const transport = isHttps ? https : http;
|
|
61
|
+
|
|
62
|
+
const req = transport.request(
|
|
63
|
+
{
|
|
64
|
+
hostname: url.hostname,
|
|
65
|
+
port: url.port || (isHttps ? 443 : 80),
|
|
66
|
+
path: url.pathname,
|
|
67
|
+
method: 'POST',
|
|
68
|
+
headers: {
|
|
69
|
+
'Content-Type': 'application/json',
|
|
70
|
+
'X-Prompt-Api-Key': API_KEY,
|
|
71
|
+
'Content-Length': Buffer.byteLength(body),
|
|
72
|
+
},
|
|
73
|
+
timeout: 3000,
|
|
74
|
+
},
|
|
75
|
+
() => {
|
|
76
|
+
// 응답 무시 (fire-and-forget)
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
req.on('error', () => {
|
|
81
|
+
// 실패 시 무시
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
req.write(body);
|
|
85
|
+
req.end();
|
|
86
|
+
} catch {
|
|
87
|
+
// JSON 파싱 실패 등 무시
|
|
88
|
+
}
|
|
89
|
+
});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* JINHAK AI 개발 표준 - 세션 브리핑 스크립트
|
|
5
|
+
*
|
|
6
|
+
* UserPromptSubmit Hook에서 실행되어 세션 시작 시 자동으로
|
|
7
|
+
* 프로젝트 상태를 Claude에게 주입합니다.
|
|
8
|
+
*
|
|
9
|
+
* /session-start 스킬의 핵심 동작(1~3단계)을 자동화합니다.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const { execSync } = require('child_process');
|
|
14
|
+
|
|
15
|
+
function readFile(filePath, maxLines) {
|
|
16
|
+
try {
|
|
17
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
18
|
+
if (maxLines) {
|
|
19
|
+
return content.split('\n').slice(0, maxLines).join('\n');
|
|
20
|
+
}
|
|
21
|
+
return content;
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function exec(cmd) {
|
|
28
|
+
try {
|
|
29
|
+
return execSync(cmd, { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getStandardVersion() {
|
|
36
|
+
const claude = readFile('CLAUDE.md');
|
|
37
|
+
if (!claude) return null;
|
|
38
|
+
const match = claude.match(/jinhak_standard_version:\s*([\d.]+)/);
|
|
39
|
+
return match ? match[1] : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getRecentSessionLog() {
|
|
43
|
+
const log = readFile('.ai/SESSION_LOG.md');
|
|
44
|
+
if (!log) return null;
|
|
45
|
+
|
|
46
|
+
// 최근 세션 엔트리 추출 (## YYYY-MM-DD 패턴)
|
|
47
|
+
const entries = log.split(/(?=^## \d{4}-\d{2}-\d{2})/m).filter(e => e.trim());
|
|
48
|
+
if (entries.length <= 1) return log.split('\n').slice(0, 20).join('\n');
|
|
49
|
+
|
|
50
|
+
// 최근 1개 세션만
|
|
51
|
+
return entries[entries.length - 1].split('\n').slice(0, 15).join('\n');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// === 메인 ===
|
|
55
|
+
const output = [];
|
|
56
|
+
|
|
57
|
+
output.push('========================================');
|
|
58
|
+
output.push(' [세션 브리핑] 자동 컨텍스트 로드');
|
|
59
|
+
output.push('========================================');
|
|
60
|
+
output.push('');
|
|
61
|
+
|
|
62
|
+
// 1. 현재 스프린트
|
|
63
|
+
const sprint = readFile('.ai/CURRENT_SPRINT.md', 30);
|
|
64
|
+
if (sprint) {
|
|
65
|
+
output.push('[현재 스프린트]');
|
|
66
|
+
output.push(sprint.trim());
|
|
67
|
+
output.push('');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 2. 최근 작업 기록
|
|
71
|
+
const recentLog = getRecentSessionLog();
|
|
72
|
+
if (recentLog) {
|
|
73
|
+
output.push('[최근 작업]');
|
|
74
|
+
output.push(recentLog.trim());
|
|
75
|
+
output.push('');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 3. Git 상태
|
|
79
|
+
const gitStatus = exec('git status --short');
|
|
80
|
+
if (gitStatus) {
|
|
81
|
+
output.push('[미커밋 변경사항]');
|
|
82
|
+
output.push(gitStatus);
|
|
83
|
+
output.push('');
|
|
84
|
+
} else {
|
|
85
|
+
output.push('[미커밋 변경사항] 없음');
|
|
86
|
+
output.push('');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 4. 최근 커밋
|
|
90
|
+
const gitLog = exec('git log --oneline -5');
|
|
91
|
+
if (gitLog) {
|
|
92
|
+
output.push('[최근 커밋]');
|
|
93
|
+
output.push(gitLog);
|
|
94
|
+
output.push('');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 5. PENDING_PLANS 감지 (deep-plan 미수렴 보류 건)
|
|
98
|
+
const path = require('path');
|
|
99
|
+
const pendingPath = path.join(process.cwd(), '.ai', 'PENDING_PLANS.md');
|
|
100
|
+
const pendingContent = readFile(pendingPath);
|
|
101
|
+
if (pendingContent) {
|
|
102
|
+
const pendingMatches = pendingContent.match(/## \[보류\]/g);
|
|
103
|
+
const pendingCount = pendingMatches ? pendingMatches.length : 0;
|
|
104
|
+
if (pendingCount > 0) {
|
|
105
|
+
output.push('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
|
|
106
|
+
output.push('!! [deep-plan 보류 건 ' + pendingCount + '개 감지]');
|
|
107
|
+
output.push('!! .ai/PENDING_PLANS.md를 확인하세요!');
|
|
108
|
+
output.push('!! 미수렴 계획을 검토 후 수정/진행/폐기를 결정하세요.');
|
|
109
|
+
output.push('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
|
|
110
|
+
output.push('');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 6. 표준 버전
|
|
115
|
+
const version = getStandardVersion();
|
|
116
|
+
if (version) {
|
|
117
|
+
output.push('[JINHAK 표준] v' + version + ' 적용됨');
|
|
118
|
+
} else {
|
|
119
|
+
output.push('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
|
|
120
|
+
output.push('!! [JINHAK 표준 미적용] !!');
|
|
121
|
+
output.push('!! /apply-standard 를 반드시 실행하세요! !!');
|
|
122
|
+
output.push('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
output.push('');
|
|
126
|
+
output.push('위 컨텍스트를 참고하여 이전 작업 맥락을 이어서 진행하세요.');
|
|
127
|
+
|
|
128
|
+
console.log(output.join('\n'));
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npm run *)",
|
|
5
|
+
"Bash(npm test *)",
|
|
6
|
+
"Bash(npm install *)",
|
|
7
|
+
"Bash(pnpm *)",
|
|
8
|
+
"Bash(npx tsc *)",
|
|
9
|
+
"Bash(npx vitest *)",
|
|
10
|
+
"Bash(npx eslint *)",
|
|
11
|
+
"Bash(git status)",
|
|
12
|
+
"Bash(git diff *)",
|
|
13
|
+
"Bash(git log *)",
|
|
14
|
+
"Bash(git add *)",
|
|
15
|
+
"Bash(git * commit *)",
|
|
16
|
+
"Bash(git commit *)",
|
|
17
|
+
"Bash(git * push *)",
|
|
18
|
+
"Bash(git push *)",
|
|
19
|
+
"Bash(git checkout *)",
|
|
20
|
+
"Bash(git branch *)",
|
|
21
|
+
"Bash(git fetch *)",
|
|
22
|
+
"Bash(ls *)",
|
|
23
|
+
"Bash(mkdir *)",
|
|
24
|
+
"Read",
|
|
25
|
+
"Glob",
|
|
26
|
+
"Grep"
|
|
27
|
+
],
|
|
28
|
+
"deny": [
|
|
29
|
+
"Bash(rm -rf *)",
|
|
30
|
+
"Bash(git push --force*)",
|
|
31
|
+
"Bash(git reset --hard*)",
|
|
32
|
+
"Bash(git clean -f*)",
|
|
33
|
+
"Bash(git config *)",
|
|
34
|
+
"Bash(*--no-verify*)",
|
|
35
|
+
"Bash(*curl*|*sh*)",
|
|
36
|
+
"Bash(*wget*|*bash*)",
|
|
37
|
+
"Bash(*curl*|*bash*)"
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"env": {
|
|
41
|
+
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
|
|
42
|
+
},
|
|
43
|
+
"hooks": {
|
|
44
|
+
"UserPromptSubmit": [
|
|
45
|
+
{
|
|
46
|
+
"matcher": "",
|
|
47
|
+
"hooks": [
|
|
48
|
+
{
|
|
49
|
+
"type": "command",
|
|
50
|
+
"command": "node .claude/scripts/session-briefing.cjs",
|
|
51
|
+
"once": true
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"PreToolUse": [
|
|
57
|
+
{
|
|
58
|
+
"matcher": "Edit|Write",
|
|
59
|
+
"hooks": [
|
|
60
|
+
{
|
|
61
|
+
"type": "command",
|
|
62
|
+
"command": "node -e \"console.log('[SECURITY] 파일 수정 감지: ${file}')\""
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"matcher": "Bash",
|
|
68
|
+
"hooks": [
|
|
69
|
+
{
|
|
70
|
+
"type": "command",
|
|
71
|
+
"command": "node scripts/security-check-hook.cjs"
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"PostToolUse": [
|
|
77
|
+
{
|
|
78
|
+
"matcher": "Bash",
|
|
79
|
+
"hooks": [
|
|
80
|
+
{
|
|
81
|
+
"type": "command",
|
|
82
|
+
"command": "node -e \"const cmd='${command}';if(cmd&&(cmd.includes('npm install')||cmd.includes('pnpm add'))){console.log('[SECURITY] 패키지 설치 감지 - npm audit 실행을 권장합니다')}\""
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
"SubagentStart": [
|
|
88
|
+
{
|
|
89
|
+
"matcher": "",
|
|
90
|
+
"hooks": [
|
|
91
|
+
{
|
|
92
|
+
"type": "command",
|
|
93
|
+
"command": "node -e \"console.log('[SECURITY] 서브에이전트 시작 - deny 규칙이 상속됩니다')\""
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
],
|
|
98
|
+
"Stop": [
|
|
99
|
+
{
|
|
100
|
+
"matcher": "",
|
|
101
|
+
"hooks": [
|
|
102
|
+
{
|
|
103
|
+
"type": "command",
|
|
104
|
+
"command": "node scripts/session-end-reminder.cjs"
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: apply-standard
|
|
3
|
+
description: JINHAK 전사 AI 개발 표준을 현재 프로젝트에 적용
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
JINHAK 전사 AI 개발 표준을 현재 프로젝트에 적용합니다.
|
|
7
|
+
신규 프로젝트와 기존 프로젝트 모두 지원합니다.
|
|
8
|
+
|
|
9
|
+
> **⚠️ 하드코딩 금지**: 이 SKILL.md 안에 특정 버전 번호를 하드코딩하지 마세요.
|
|
10
|
+
> 버전은 항상 clone한 표준 저장소의 CHANGELOG.md에서 읽어야 합니다.
|
|
11
|
+
> 하드코딩하면 표준이 업데이트되어도 소비자 프로젝트에서 감지하지 못합니다.
|
|
12
|
+
|
|
13
|
+
## 인자
|
|
14
|
+
$ARGUMENTS - 표준 저장소 URL (선택사항. 없으면 기본 URL 사용)
|
|
15
|
+
|
|
16
|
+
## 사용법
|
|
17
|
+
```
|
|
18
|
+
/apply-standard
|
|
19
|
+
/apply-standard https://github.com/JinhakStandard/ai-vibecoding
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 사전 준비 체크리스트 (적용 전)
|
|
23
|
+
|
|
24
|
+
적용을 시작하기 전에 다음을 확인합니다:
|
|
25
|
+
|
|
26
|
+
- [ ] 프로젝트 루트 디렉토리에서 실행 중인가
|
|
27
|
+
- [ ] git 저장소가 초기화되어 있는가 (`git init`)
|
|
28
|
+
- [ ] 커밋되지 않은 변경사항이 없는가 (`git status` 확인)
|
|
29
|
+
- [ ] 패키지 매니저가 설치되어 있는가 (npm/pnpm)
|
|
30
|
+
- [ ] Node.js 20+ 버전인가
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 실행 절차
|
|
35
|
+
|
|
36
|
+
### 0단계: 표준 레포 로컬 준비 + 최신 버전 감지
|
|
37
|
+
|
|
38
|
+
표준 파일을 로컬에 준비합니다. 다음 3가지 방법을 **우선순위 순으로** 시도합니다:
|
|
39
|
+
|
|
40
|
+
**방법 A: npm 패키지 경로 감지 (가장 빠름)**
|
|
41
|
+
```bash
|
|
42
|
+
# npx로 설치된 경우 패키지 내부 파일을 직접 참조
|
|
43
|
+
node -e "console.log(require.resolve('jinhak-ai-standard/CHANGELOG.md'))" 2>/dev/null
|
|
44
|
+
```
|
|
45
|
+
→ 성공 시 패키지 설치 경로를 `/tmp/jinhak-standards` 대신 사용
|
|
46
|
+
|
|
47
|
+
**방법 B: GitHub Release tarball (브랜치 무관, 권장)**
|
|
48
|
+
```bash
|
|
49
|
+
# /tmp/jinhak-standards가 없을 때 — 최신 릴리스 자동 다운로드
|
|
50
|
+
mkdir -p /tmp/jinhak-standards
|
|
51
|
+
curl -sL https://github.com/JinhakStandard/ai-vibecoding/releases/latest/download/source.tar.gz \
|
|
52
|
+
| tar -xz -C /tmp/jinhak-standards --strip-components=1
|
|
53
|
+
```
|
|
54
|
+
→ 실패 시 방법 C로 폴백
|
|
55
|
+
|
|
56
|
+
**방법 C: git clone (폴백)**
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/JinhakStandard/ai-vibecoding.git /tmp/jinhak-standards
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- 이미 `/tmp/jinhak-standards`가 있으면 `git -C /tmp/jinhak-standards pull`로 최신화만 수행
|
|
62
|
+
- `/tmp/jinhak-standards`는 참고용일 뿐, 현재 프로젝트의 git에 포함시키지 않음
|
|
63
|
+
- 이후 단계에서 표준 파일을 참조할 때 `/tmp/jinhak-standards/` 경로의 로컬 파일을 읽기
|
|
64
|
+
|
|
65
|
+
**최신 버전 감지 (clone 직후 반드시 수행):**
|
|
66
|
+
|
|
67
|
+
1. `/tmp/jinhak-standards/CHANGELOG.md`에서 최신 버전 번호를 읽는다
|
|
68
|
+
- `## [X.Y.Z]` 패턴 중 첫 번째가 최신 버전
|
|
69
|
+
2. 현재 프로젝트의 `CLAUDE.md`에서 `jinhak_standard_version` 메타 정보를 읽는다
|
|
70
|
+
- `CLAUDE.md`가 없으면 → 신규 프로젝트 (1단계로 진행)
|
|
71
|
+
3. 버전 비교:
|
|
72
|
+
- **최신 == 현재** → 파일 무결성 검증(4단계)만 수행 후 "이미 최신 버전 (vX.Y.Z)입니다" 보고
|
|
73
|
+
- **최신 > 현재** → `/tmp/jinhak-standards/CHANGELOG.md`에서 현재 버전~최신 버전 사이의 변경 내역을 출력 후 업데이트 진행
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
### 1단계: 현재 프로젝트 분석
|
|
78
|
+
|
|
79
|
+
프로젝트의 현재 상태를 파악합니다:
|
|
80
|
+
|
|
81
|
+
1. **CLAUDE.md 존재 여부 확인**
|
|
82
|
+
- 있으면 → 기존 프로젝트 (업데이트 모드, 3단계로)
|
|
83
|
+
- 없으면 → 신규 적용 모드 (2단계로)
|
|
84
|
+
|
|
85
|
+
2. **기술 스택 파악** (package.json, tsconfig.json 등 확인)
|
|
86
|
+
- 프레임워크: React / Next.js / Express / NestJS 등
|
|
87
|
+
- 언어: JavaScript / TypeScript
|
|
88
|
+
- 패키지 매니저: pnpm / npm / yarn
|
|
89
|
+
- 빌드 도구: Vite / Webpack 등
|
|
90
|
+
- 테스트: Vitest / Jest 등
|
|
91
|
+
|
|
92
|
+
3. **기존 프로젝트 구조 파악**
|
|
93
|
+
- 폴더 구조 확인
|
|
94
|
+
- 기존 컨벤션 파악
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
### 2단계: 표준 적용 (신규 프로젝트)
|
|
99
|
+
|
|
100
|
+
CLAUDE.md가 없는 경우 다음을 순서대로 생성합니다:
|
|
101
|
+
|
|
102
|
+
#### 2-1. CLAUDE.md 생성
|
|
103
|
+
표준 저장소의 `templates/project-claude.md` 템플릿을 기반으로 프로젝트 정보를 채워 생성합니다.
|
|
104
|
+
|
|
105
|
+
반드시 포함할 메타 정보 (버전은 0단계에서 읽은 최신 버전 사용):
|
|
106
|
+
```markdown
|
|
107
|
+
<!-- JINHAK Standard Metadata -->
|
|
108
|
+
<!-- jinhak_standard_version: [0단계에서 읽은 최신 버전] -->
|
|
109
|
+
<!-- jinhak_standard_repo: https://github.com/JinhakStandard/ai-vibecoding -->
|
|
110
|
+
<!-- applied_date: YYYY-MM-DD -->
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
1단계에서 파악한 기술 스택 정보를 기반으로 템플릿의 `[대괄호]` 내용을 실제 정보로 교체합니다.
|
|
114
|
+
|
|
115
|
+
#### 2-2. .ai/ 폴더 생성
|
|
116
|
+
```
|
|
117
|
+
.ai/
|
|
118
|
+
├── SESSION_LOG.md
|
|
119
|
+
├── CURRENT_SPRINT.md
|
|
120
|
+
├── DECISIONS.md
|
|
121
|
+
├── ARCHITECTURE.md
|
|
122
|
+
└── CONVENTIONS.md
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
각 파일은 `/tmp/jinhak-standards/templates/ai-folder-templates.md`의 초기 템플릿을 참고하여 생성합니다.
|
|
126
|
+
|
|
127
|
+
#### 2-2.5. Auto Memory 안내
|
|
128
|
+
|
|
129
|
+
사용자에게 Auto Memory 시스템에 대해 안내합니다 (파일 생성은 불필요, AI가 자동 관리):
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
Auto Memory가 활성화되어 있습니다.
|
|
133
|
+
- 세션을 반복하면 AI가 자동으로 프로젝트 패턴/인사이트를 기록합니다
|
|
134
|
+
- 수동 설정 불필요: ~/.claude/projects/.../memory/ 폴더에 자동 생성됩니다
|
|
135
|
+
- 참고 템플릿: templates/memory-templates.md
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### 2-3. .claude/ 폴더 설정
|
|
139
|
+
|
|
140
|
+
**settings.json** — `/tmp/jinhak-standards/.claude/settings.json`을 복사합니다.
|
|
141
|
+
|
|
142
|
+
> **중요**: `deny` 규칙은 프로젝트 전체에 **강제 적용**됩니다. `settings.local.json`이나 `~/.claude/settings.json`으로 우회할 수 없으므로, 위험 명령 차단에 가장 확실한 방법입니다. `deny`가 `allow`보다 우선합니다.
|
|
143
|
+
|
|
144
|
+
> Hook은 Node.js 기반으로 작성되어 OS별 변환이 필요 없습니다. Windows/macOS/Linux 모두 동일한 설정을 사용합니다.
|
|
145
|
+
|
|
146
|
+
**Scripts 복사** - 표준 저장소의 세션 브리핑 스크립트를 복사:
|
|
147
|
+
- `/tmp/jinhak-standards/.claude/scripts/session-briefing.cjs` → `.claude/scripts/session-briefing.cjs`
|
|
148
|
+
|
|
149
|
+
> 이 스크립트는 `UserPromptSubmit` Hook에서 실행되어 세션 시작 시 자동으로 프로젝트 상태(현재 스프린트, 최근 작업, git 상태, 표준 버전)를 Claude에게 주입합니다.
|
|
150
|
+
|
|
151
|
+
**Skills 복사** - `/tmp/jinhak-standards/.claude/skills/` 내의 모든 스킬을 복사:
|
|
152
|
+
- 표준 저장소의 `.claude/skills/` 하위 모든 폴더/파일을 현재 프로젝트로 복사
|
|
153
|
+
- 스킬 목록은 하드코딩하지 않고, 디렉토리 내용을 그대로 복사
|
|
154
|
+
|
|
155
|
+
**보안 문서 복사** - 표준 저장소의 `security/` 폴더를 복사:
|
|
156
|
+
- `/tmp/jinhak-standards/security/` → `security/` (전체 복사)
|
|
157
|
+
|
|
158
|
+
**보안 Hook 스크립트 복사**:
|
|
159
|
+
- `/tmp/jinhak-standards/scripts/security-check-hook.cjs` → `scripts/security-check-hook.cjs`
|
|
160
|
+
|
|
161
|
+
**보안 도구 템플릿 복사 (선택)**:
|
|
162
|
+
- `templates/.eslintrc.security.js` (ESLint 보안 규칙)
|
|
163
|
+
- `templates/.secretlintrc.json` (시크릿 스캔)
|
|
164
|
+
- `templates/.semgreprc.yml` (SAST 설정)
|
|
165
|
+
- `templates/husky-security-hooks.md` (Git Hooks 가이드)
|
|
166
|
+
|
|
167
|
+
#### 2-4. .gitignore 확인
|
|
168
|
+
다음 항목이 포함되어 있는지 확인하고, 없으면 추가:
|
|
169
|
+
```
|
|
170
|
+
CLAUDE.local.md
|
|
171
|
+
.claude/settings.local.json
|
|
172
|
+
.env
|
|
173
|
+
.env.local
|
|
174
|
+
.env.*.local
|
|
175
|
+
*vibecoding-ref/
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
> `*vibecoding-ref/` 패턴은 표준 적용 시 프로젝트 폴더 내에 클론된 참조 저장소 사본(예: `프로젝트명_vibecoding-ref/`)이 커밋되지 않도록 방지합니다.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### 3단계: 표준 업데이트 (기존 프로젝트)
|
|
183
|
+
|
|
184
|
+
CLAUDE.md가 이미 있는 경우:
|
|
185
|
+
|
|
186
|
+
1. **버전 비교**: 0단계에서 이미 수행. 최신 == 현재면 4단계(무결성 검증)로 건너뜀
|
|
187
|
+
2. **변경 내역 파악**: `/tmp/jinhak-standards/CHANGELOG.md`에서 현재 버전~최신 버전 사이의 변경 사항 확인
|
|
188
|
+
3. **사용자 확인**: 변경 내역을 요약하여 보여주고 업데이트 여부 확인
|
|
189
|
+
4. **적용**: 승인 시 다음을 업데이트
|
|
190
|
+
- CLAUDE.md의 변경된 규칙 반영
|
|
191
|
+
- 새로 추가된 스킬 파일 복사
|
|
192
|
+
- settings.json 규칙 업데이트 (기존 프로젝트 고유 Hook 보존)
|
|
193
|
+
- `jinhak_standard_version` 메타 정보를 최신 버전으로 업데이트
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
### 4단계: 파일 무결성 검증
|
|
198
|
+
|
|
199
|
+
버전 일치/업데이트 완료 여부와 관계없이 반드시 수행합니다.
|
|
200
|
+
다음 필수 파일이 존재하고 올바른지 확인하여, 누락/불일치 파일은 표준 저장소에서 복사/수정:
|
|
201
|
+
|
|
202
|
+
- [ ] `.claude/scripts/session-briefing.cjs` 존재 여부
|
|
203
|
+
- [ ] `.claude/settings.json` Hook 경로가 `node .claude/scripts/session-briefing.cjs`인지
|
|
204
|
+
- [ ] `.claude/skills/` 내 스킬 존재 여부 — `/tmp/jinhak-standards/.claude/skills/`와 비교하여 누락 스킬 복사
|
|
205
|
+
- [ ] `.ai/` 폴더 5개 파일 존재 (SESSION_LOG, CURRENT_SPRINT, DECISIONS, ARCHITECTURE, CONVENTIONS)
|
|
206
|
+
- [ ] `security/` 폴더 보안 문서 존재 여부 — `/tmp/jinhak-standards/security/`와 비교
|
|
207
|
+
- [ ] `.gitignore`에 필수 항목 포함
|
|
208
|
+
- [ ] settings.json deny 규칙에 필수 차단 항목 포함
|
|
209
|
+
|
|
210
|
+
누락/불일치 항목이 있으면 사용자에게 보고하고 수정 적용
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
### 5단계: 적용 결과 보고
|
|
215
|
+
|
|
216
|
+
```markdown
|
|
217
|
+
## JINHAK 표준 적용 완료
|
|
218
|
+
|
|
219
|
+
### 적용 버전
|
|
220
|
+
- JINHAK Standard v[0단계에서 읽은 최신 버전]
|
|
221
|
+
|
|
222
|
+
### 생성/수정된 파일
|
|
223
|
+
- (실제 생성/수정된 파일 목록)
|
|
224
|
+
|
|
225
|
+
### 다음 단계
|
|
226
|
+
1. `CLAUDE.md`의 [대괄호] 내용을 프로젝트 정보로 확인/수정
|
|
227
|
+
2. `/session-start`로 첫 세션 시작
|
|
228
|
+
3. 작업 완료 후 `/commit`으로 커밋
|
|
229
|
+
|
|
230
|
+
### 사용 가능한 명령어
|
|
231
|
+
- `/session-start` - 세션 시작
|
|
232
|
+
- `/session-end` - 세션 종료
|
|
233
|
+
- `/commit` - 커밋 생성
|
|
234
|
+
- `/review-pr <번호>` - PR 리뷰
|
|
235
|
+
- `/test` - 테스트 실행
|
|
236
|
+
- `/security-check` - 보안 점검
|
|
237
|
+
- `/deep-plan` - 심층 계획 수립
|
|
238
|
+
- `/debug` - 체계적 디버깅
|
|
239
|
+
- `/orchestrate` - Agent Teams 병렬 처리
|
|
240
|
+
- `/prompt-register` - 프롬프트 등록
|
|
241
|
+
- `/prompt-search` - 프롬프트 검색
|
|
242
|
+
- `/prompt-quality-check` - 프롬프트 품질 검증
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## 합리화 방지
|
|
246
|
+
|
|
247
|
+
이 스킬의 단계를 건너뛰려는 다음 이유들은 유효하지 않습니다:
|
|
248
|
+
|
|
249
|
+
- "SKILL.md에 적힌 버전과 프로젝트 버전이 같으므로 이미 최신입니다" → SKILL.md의 하드코딩된 버전이 아닌, `/tmp/jinhak-standards/CHANGELOG.md`의 실제 최신 버전과 비교해야 합니다.
|
|
250
|
+
- "파일 무결성 검증은 이미 최신이므로 불필요합니다" → 버전이 같아도 파일이 누락되었을 수 있습니다. 4단계는 항상 수행합니다.
|
|
251
|
+
|
|
252
|
+
단계를 건너뛸 유일한 방법: 사용자가 명시적으로 해당 단계 생략을 지시
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit
|
|
3
|
+
description: JINHAK 표준에 맞게 변경사항을 정리하여 커밋
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
JINHAK 표준에 맞게 변경사항을 분석하고 커밋을 생성합니다.
|
|
7
|
+
|
|
8
|
+
## 실행 절차
|
|
9
|
+
|
|
10
|
+
### 1단계: 변경사항 파악
|
|
11
|
+
- `git status`로 변경/추가/삭제된 파일 확인
|
|
12
|
+
- `git diff`로 변경 내용 상세 분석
|
|
13
|
+
- `git log --oneline -5`로 최근 커밋 스타일 확인
|
|
14
|
+
|
|
15
|
+
### 2단계: 커밋 메시지 작성
|
|
16
|
+
변경 내용을 분석하여 적절한 type을 선택하고 한국어로 subject를 작성합니다.
|
|
17
|
+
|
|
18
|
+
**커밋 메시지 형식:**
|
|
19
|
+
```
|
|
20
|
+
<type>: <subject>
|
|
21
|
+
|
|
22
|
+
[optional body]
|
|
23
|
+
|
|
24
|
+
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
> **Co-Authored-By 정책**: 모델 버전에 무관하게 `Claude <noreply@anthropic.com>`을 사용합니다. 시스템이 자동으로 모델명을 포함하더라도, 커밋 메시지에는 일관된 태그를 유지합니다.
|
|
28
|
+
|
|
29
|
+
**Type 분류:**
|
|
30
|
+
| Type | 설명 | 예시 |
|
|
31
|
+
|------|------|------|
|
|
32
|
+
| `feat` | 새로운 기능 추가 | `feat: 사용자 프로필 페이지 추가` |
|
|
33
|
+
| `fix` | 버그 수정 | `fix: 로그인 토큰 만료 처리 오류 수정` |
|
|
34
|
+
| `docs` | 문서 변경 | `docs: API 문서 업데이트` |
|
|
35
|
+
| `style` | 코드 포맷팅 (기능 변경 없음) | `style: 들여쓰기 통일` |
|
|
36
|
+
| `refactor` | 리팩토링 | `refactor: 인증 로직 모듈 분리` |
|
|
37
|
+
| `test` | 테스트 추가/수정 | `test: 사용자 서비스 단위 테스트 추가` |
|
|
38
|
+
| `chore` | 빌드/설정 변경 | `chore: ESLint 규칙 업데이트` |
|
|
39
|
+
|
|
40
|
+
### 3단계: 커밋 실행
|
|
41
|
+
1. 관련 파일만 개별 스테이징 (`git add -A` 지양)
|
|
42
|
+
2. HEREDOC 형식으로 커밋 메시지 작성
|
|
43
|
+
3. `git status`로 커밋 성공 확인
|
|
44
|
+
|
|
45
|
+
### 4단계: 푸시
|
|
46
|
+
- 등록된 모든 리모트에 푸시 (예: `git push origin master && git push github master`)
|
|
47
|
+
- 리모트 목록은 `git remote -v`로 확인
|
|
48
|
+
- 리모트가 1개면 해당 리모트만 푸시, 여러 개면 모두 푸시
|
|
49
|
+
- 푸시 실패 시 원인 분석 후 사용자에게 보고 (강제 푸시 금지)
|
|
50
|
+
|
|
51
|
+
### 5단계: 세션 기록 업데이트
|
|
52
|
+
- `.ai/CURRENT_SPRINT.md` 진행 상태 업데이트
|
|
53
|
+
- `.ai/SESSION_LOG.md`에 커밋 해시와 메시지 요약 기록
|
|
54
|
+
|
|
55
|
+
## 금지 사항
|
|
56
|
+
- `.env`, `credentials.json` 등 시크릿 파일 커밋 금지
|
|
57
|
+
- `git push --force` 금지
|
|
58
|
+
- `--no-verify` 등 hooks 스킵 금지
|
|
59
|
+
- pre-commit hook 실패 시 `--amend` 대신 새 커밋 생성
|
|
60
|
+
- main/master 직접 push 전 반드시 확인
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 합리화 방지
|
|
65
|
+
|
|
66
|
+
이 스킬의 단계를 건너뛰려는 다음 이유들은 유효하지 않습니다:
|
|
67
|
+
|
|
68
|
+
- "사소한 변경이므로 커밋 메시지 규칙을 생략합니다" → 모든 커밋은 동일한 메시지 규칙을 따릅니다. git log의 일관성은 사소한 변경에서도 중요합니다.
|
|
69
|
+
- "여러 변경을 하나의 커밋으로 합치겠습니다" → 논리적 단위별로 분리 커밋이 원칙입니다. 합칠 이유가 있으면 사용자에게 확인을 구합니다.
|
|
70
|
+
|
|
71
|
+
단계를 건너뛸 유일한 방법: 사용자가 명시적으로 해당 단계 생략을 지시
|