jinhak-ai-standard 2.7.0 → 3.7.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/cleanup-nul.cjs +20 -0
- package/.claude/scripts/commit-guard.cjs +82 -0
- package/.claude/scripts/npm-tag-guard.cjs +85 -0
- package/.claude/scripts/readme-guard.cjs +99 -0
- package/.claude/scripts/session-briefing.cjs +2 -0
- package/.claude/settings.json +29 -2
- package/.claude/skills/apply-standard/SKILL.md +1 -1
- package/.claude/skills/code-garden/SKILL.md +112 -0
- package/.claude/skills/debug/SKILL.md +5 -0
- package/.claude/skills/deep-plan/SKILL.md +36 -21
- package/.claude/skills/dependency-guardian/SKILL.md +97 -0
- package/.claude/skills/dependency-guardian/assets/ALLOWLIST_STRICT.md +72 -0
- package/.claude/skills/dependency-guardian/assets/BLOCKLIST.md +32 -0
- package/.claude/skills/dependency-guardian/references/audit-lockfile.md +47 -0
- package/.claude/skills/dependency-guardian/references/check-package.md +56 -0
- package/.claude/skills/dependency-guardian/references/jabis-api-guide.md +42 -0
- package/.claude/skills/dependency-guardian/references/scoring-criteria.md +37 -0
- package/.claude/skills/dependency-guardian/scripts/check-npm-meta.sh +36 -0
- package/.claude/skills/dependency-guardian/scripts/sync-jabis-cache.sh +60 -0
- package/.claude/skills/doc-garden/SKILL.md +80 -0
- package/.claude/skills/lint-check/SKILL.md +57 -0
- package/.claude/skills/metrics-report/SKILL.md +59 -0
- package/.claude/skills/session-end/SKILL.md +78 -2
- package/CHANGELOG.md +235 -16
- package/CLAUDE.md +80 -1151
- package/PROMPT-LIBRARY.md +15 -5
- package/QUICK_START_PROMPT.md +3 -3
- package/README.md +161 -63
- package/SECURITY_ISMS.md +3 -4
- package/VIBE_CODING_GUIDE.md +4 -5
- package/docs/api/EXECUTION_RECORD_API_SPEC.md +206 -0
- package/docs/architecture/dependencies.md +148 -0
- package/docs/architecture/domain-map.md +127 -0
- package/{ARCHITECTURE.md → docs/architecture/layers.md} +37 -184
- package/docs/concepts/AI_WORK_PATTERN.md +172 -0
- package/docs/concepts/HARNESS_ENGINEERING.md +285 -0
- package/docs/concepts/V3_FULL_TECHNICAL_SPEC.md +717 -0
- package/docs/domain/domain-template.md +43 -0
- package/docs/plans/decision-context-pack-consolidation.md +52 -0
- package/docs/plans/decision-log-template.md +34 -0
- package/docs/plans/plan-template.md +72 -0
- package/docs/quality/daily-report-template.md +33 -0
- package/docs/quality/execution-record.md +170 -0
- package/docs/quality/grades-template.md +27 -0
- package/docs/quality/session-metrics.md +119 -0
- package/docs/quality/tech-debt-template.md +31 -0
- package/docs/security/AI_SECURITY_GUARDRAILS.md +377 -0
- package/docs/security/DATA_CLASSIFICATION.md +242 -0
- package/docs/security/FORBIDDEN_PATTERNS.md +485 -0
- package/docs/security/INCIDENT_RESPONSE.md +300 -0
- package/docs/security/OWASP_LLM_CHECKLIST.md +229 -0
- package/docs/standards/api-patterns.md +222 -0
- package/docs/standards/clarification-protocol.md +130 -0
- package/{CODING_CONVENTIONS.md → docs/standards/coding.md} +36 -76
- package/docs/standards/difficulty-guide.md +132 -0
- package/docs/standards/lint-architecture-rules.md +425 -0
- package/docs/standards/lint-architecture-technical-spec.md +604 -0
- package/docs/standards/naming.md +148 -0
- package/docs/standards/phase-gates.md +175 -0
- package/{PROJECT_STRUCTURE.md → docs/standards/project-structure.md} +30 -9
- package/docs/standards/prompt-structure.md +119 -0
- package/package.json +3 -1
- package/prompts/_template/metadata.json +20 -1
- package/prompts/code-review/security-review/metadata.json +30 -3
- package/prompts/testing/unit-test-gen/metadata.json +29 -3
- package/scripts/doc-coverage-check.cjs +236 -0
- package/scripts/doc-freshness-check.cjs +157 -0
- package/scripts/execution-record-collect.cjs +197 -0
- package/scripts/install-global-hook.cjs +34 -12
- package/scripts/retry-pending-records.cjs +127 -0
- package/scripts/security-check-hook.cjs +16 -3
- package/security/AI_SECURITY_GUARDRAILS.md +5 -6
- package/security/FORBIDDEN_PATTERNS.md +1 -1
- package/security/INCIDENT_RESPONSE.md +3 -4
- package/security/OWASP_LLM_CHECKLIST.md +3 -4
- package/templates/ai-folder-templates.md +1 -1
- package/templates/ci-architecture-lint.yml +55 -0
- package/templates/project-claude.md +1 -1
- package/tracking/TRACKING_SETUP.md +123 -0
- package/tracking/grade-history-collector.cjs +86 -0
- package/tracking/lint-metrics-collector.cjs +121 -0
- package/tracking/prompt-usage-tracker.cjs +210 -0
- package/tracking/schemas/lint-metrics.schema.json +18 -0
- package/tracking/schemas/usage-event.schema.json +52 -0
- package/tracking/test-fixtures/generate-sample.cjs +39 -0
- package/tracking/test-fixtures/sample-usage.jsonl +20 -0
- package/.claude/skills/orchestrate/SKILL.md +0 -220
- package/security/NIGHTBUILDER_SECURITY.md +0 -234
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PostToolUse Hook — Windows nul 파일 자동 삭제
|
|
5
|
+
*
|
|
6
|
+
* Windows에서 `> nul` 리다이렉션 사용 시 예약 디바이스 이름 충돌로
|
|
7
|
+
* 실제 `nul` 파일이 생성되는 문제를 방지합니다.
|
|
8
|
+
* \\?\ prefix로 Windows 예약어를 우회하여 삭제합니다.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
const nulPath = '\\\\?\\' + path.resolve('nul');
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
fs.unlinkSync(nulPath);
|
|
18
|
+
} catch {
|
|
19
|
+
// 파일이 없으면 무시
|
|
20
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* commit-guard.cjs
|
|
4
|
+
*
|
|
5
|
+
* PreToolUse Hook — git commit 실행 시 JINHAK 표준 커밋 형식을 검증합니다.
|
|
6
|
+
*
|
|
7
|
+
* 검증 항목:
|
|
8
|
+
* 1. 커밋 메시지가 <type>: <한글 설명> 형식인가
|
|
9
|
+
* 2. Co-Authored-By 태그가 포함되어 있는가
|
|
10
|
+
* 3. /commit 스킬을 통하지 않은 직접 커밋이면 경고
|
|
11
|
+
*
|
|
12
|
+
* Hook 결과:
|
|
13
|
+
* - exit 0 + stdout 비어있음 → 통과 (아무 출력도 안 하면 통과)
|
|
14
|
+
* - exit 0 + stdout에 메시지 → 경고 표시 (진행은 됨)
|
|
15
|
+
* - exit 2 → 차단 (커밋 실행 불가)
|
|
16
|
+
*/
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const VALID_TYPES = ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore'];
|
|
20
|
+
const TYPE_PATTERN = new RegExp(`^(${VALID_TYPES.join('|')}):\\s*.+`);
|
|
21
|
+
const CO_AUTHOR_PATTERN = /Co-Authored-By:/i;
|
|
22
|
+
|
|
23
|
+
// Hook에서 전달받는 환경변수/인자에서 커밋 메시지 추출
|
|
24
|
+
const input = process.env.CLAUDE_TOOL_INPUT || process.argv.slice(2).join(' ');
|
|
25
|
+
|
|
26
|
+
// git commit 명령인지 확인
|
|
27
|
+
if (!input.includes('git commit') && !input.includes('git -c') ) {
|
|
28
|
+
// git commit이 아니면 무시
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 커밋 메시지 추출 시도
|
|
33
|
+
let commitMsg = '';
|
|
34
|
+
|
|
35
|
+
// -m "메시지" 또는 -m '메시지' 패턴
|
|
36
|
+
const mFlag = input.match(/-m\s+["']([\s\S]*?)["']/);
|
|
37
|
+
if (mFlag) {
|
|
38
|
+
commitMsg = mFlag[1];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// HEREDOC 패턴: -m "$(cat <<'EOF' ... EOF )"
|
|
42
|
+
const heredoc = input.match(/cat\s*<<['"]?EOF['"]?\n([\s\S]*?)\nEOF/);
|
|
43
|
+
if (heredoc) {
|
|
44
|
+
commitMsg = heredoc[1];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!commitMsg) {
|
|
48
|
+
// 메시지를 파싱할 수 없으면 경고만
|
|
49
|
+
console.log('⚠️ [commit-guard] 커밋 메시지를 파싱할 수 없습니다. /commit 스킬 사용을 권장합니다.');
|
|
50
|
+
process.exit(0);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 첫 줄(subject) 추출
|
|
54
|
+
const subject = commitMsg.split('\n')[0].trim();
|
|
55
|
+
const errors = [];
|
|
56
|
+
|
|
57
|
+
// 1. type: 한글 형식 검증
|
|
58
|
+
if (!TYPE_PATTERN.test(subject)) {
|
|
59
|
+
errors.push(`커밋 메시지 형식 위반: "${subject}"`);
|
|
60
|
+
errors.push(` 필수 형식: <type>: <한글 설명>`);
|
|
61
|
+
errors.push(` 유효 type: ${VALID_TYPES.join(', ')}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 2. Co-Authored-By 검증
|
|
65
|
+
if (!CO_AUTHOR_PATTERN.test(commitMsg)) {
|
|
66
|
+
errors.push(`Co-Authored-By 태그 누락`);
|
|
67
|
+
errors.push(` 필수: Co-Authored-By: Claude <noreply@anthropic.com>`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (errors.length > 0) {
|
|
71
|
+
console.log('');
|
|
72
|
+
console.log('❌ [commit-guard] JINHAK 커밋 표준 위반:');
|
|
73
|
+
errors.forEach(e => console.log(` ${e}`));
|
|
74
|
+
console.log('');
|
|
75
|
+
console.log('💡 /commit 스킬을 사용하면 자동으로 표준에 맞는 커밋이 생성됩니다.');
|
|
76
|
+
console.log('');
|
|
77
|
+
// exit 2 = 차단
|
|
78
|
+
process.exit(2);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 통과 — 아무것도 출력하지 않음
|
|
82
|
+
process.exit(0);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* npm Tag Guard Hook
|
|
4
|
+
*
|
|
5
|
+
* git push 시점에 package.json 버전이 변경되었는데
|
|
6
|
+
* 해당 버전의 git tag가 없으면 push를 차단합니다.
|
|
7
|
+
*
|
|
8
|
+
* 이 프로젝트는 npm 패키지(jinhak-ai-standard)이므로
|
|
9
|
+
* 버전 변경 시 반드시 태그를 생성해야 npm publish가 트리거됩니다.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
|
|
14
|
+
// push 명령이 아니면 무시
|
|
15
|
+
const command = process.env.command || '';
|
|
16
|
+
if (!command.includes('push')) {
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const pkg = require('../../package.json');
|
|
22
|
+
const version = pkg.version;
|
|
23
|
+
const tagName = `v${version}`;
|
|
24
|
+
|
|
25
|
+
// 해당 버전의 태그가 존재하는지 확인
|
|
26
|
+
let tagExists = false;
|
|
27
|
+
try {
|
|
28
|
+
execSync(`git tag -l "${tagName}"`, { encoding: 'utf-8' }).trim();
|
|
29
|
+
const result = execSync(`git tag -l "${tagName}"`, { encoding: 'utf-8' }).trim();
|
|
30
|
+
tagExists = result === tagName;
|
|
31
|
+
} catch {
|
|
32
|
+
tagExists = false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (tagExists) {
|
|
36
|
+
// 태그가 이미 push되었는지 확인
|
|
37
|
+
let tagPushed = false;
|
|
38
|
+
try {
|
|
39
|
+
const remoteTag = execSync(`git ls-remote --tags origin "refs/tags/${tagName}"`, { encoding: 'utf-8' }).trim();
|
|
40
|
+
tagPushed = remoteTag.length > 0;
|
|
41
|
+
} catch {
|
|
42
|
+
tagPushed = false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!tagPushed) {
|
|
46
|
+
console.log(`[npm Guard] ⚠️ 태그 ${tagName}가 로컬에 있지만 원격에 push되지 않았습니다.
|
|
47
|
+
|
|
48
|
+
이 프로젝트는 npm 패키지이므로 태그를 push해야 npm publish가 트리거됩니다.
|
|
49
|
+
코드 push 후 반드시 실행하세요:
|
|
50
|
+
git push origin ${tagName}`);
|
|
51
|
+
}
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 태그가 없음 — 버전이 원격의 최신 태그와 다른지 확인
|
|
56
|
+
let latestRemoteTag = '';
|
|
57
|
+
try {
|
|
58
|
+
latestRemoteTag = execSync('git describe --tags --abbrev=0 2>/dev/null', { encoding: 'utf-8' }).trim();
|
|
59
|
+
} catch {
|
|
60
|
+
// 태그가 하나도 없는 경우
|
|
61
|
+
latestRemoteTag = '';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const latestVersion = latestRemoteTag.replace(/^v/, '');
|
|
65
|
+
|
|
66
|
+
if (version !== latestVersion) {
|
|
67
|
+
// 버전이 변경되었는데 태그가 없음 → 차단
|
|
68
|
+
console.log(`[npm Guard] 🚫 PUSH 차단 — package.json 버전(${version})에 대한 태그(${tagName})가 없습니다!
|
|
69
|
+
|
|
70
|
+
이 프로젝트는 npm 패키지(jinhak-ai-standard)입니다.
|
|
71
|
+
버전을 올렸으면 반드시 태그를 생성하고 함께 push해야 합니다.
|
|
72
|
+
|
|
73
|
+
필요한 명령:
|
|
74
|
+
git tag ${tagName}
|
|
75
|
+
git push origin master ${tagName}
|
|
76
|
+
|
|
77
|
+
태그 없이 push하면 npm에 새 버전이 배포되지 않습니다.
|
|
78
|
+
반드시 태그를 먼저 생성한 후 push를 진행하세요.`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
} catch (e) {
|
|
83
|
+
// 스크립트 오류 시 push를 막지 않음
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* README Guard Hook
|
|
4
|
+
*
|
|
5
|
+
* git commit 시점에 README.md 업데이트 누락을 감지합니다.
|
|
6
|
+
* PreToolUse (Bash - git commit) 에서 실행됩니다.
|
|
7
|
+
*
|
|
8
|
+
* 동작:
|
|
9
|
+
* 1. staged 파일 목록을 확인
|
|
10
|
+
* 2. "중요 파일"이 변경되었는데 README.md가 staged에 없으면 경고
|
|
11
|
+
* 3. additionalContext로 Claude에게 README 업데이트를 요청
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { execSync } = require('child_process');
|
|
15
|
+
|
|
16
|
+
// 커밋 명령이 아니면 무시
|
|
17
|
+
const command = process.env.command || '';
|
|
18
|
+
if (!command.includes('commit')) {
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
// staged 파일 목록
|
|
24
|
+
const staged = execSync('git diff --cached --name-only', { encoding: 'utf-8' })
|
|
25
|
+
.trim()
|
|
26
|
+
.split('\n')
|
|
27
|
+
.filter(Boolean);
|
|
28
|
+
|
|
29
|
+
if (staged.length === 0) {
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// README.md가 이미 staged에 포함되어 있으면 OK
|
|
34
|
+
const readmeIncluded = staged.some(f =>
|
|
35
|
+
f.toLowerCase() === 'readme.md'
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
if (readmeIncluded) {
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// README 업데이트가 필요할 수 있는 "중요 변경" 패턴
|
|
43
|
+
const significantPatterns = [
|
|
44
|
+
// 구조/설정 변경
|
|
45
|
+
/^CLAUDE\.md$/,
|
|
46
|
+
/^CHANGELOG\.md$/,
|
|
47
|
+
/^RELEASE_NOTES\.md$/,
|
|
48
|
+
/^QUICK_START_PROMPT\.md$/,
|
|
49
|
+
/^package\.json$/,
|
|
50
|
+
/^bin\//,
|
|
51
|
+
// 새 기능/스킬 추가
|
|
52
|
+
/^\.claude\/skills\//,
|
|
53
|
+
/^\.claude\/settings\.json$/,
|
|
54
|
+
/^\.claude\/scripts\//,
|
|
55
|
+
// 문서 구조 변경
|
|
56
|
+
/^templates\//,
|
|
57
|
+
/^security\//,
|
|
58
|
+
/^prompts\//,
|
|
59
|
+
// 주요 가이드 문서
|
|
60
|
+
/^VIBE_CODING_GUIDE\.md$/,
|
|
61
|
+
/^CODING_CONVENTIONS\.md$/,
|
|
62
|
+
/^ARCHITECTURE\.md$/,
|
|
63
|
+
/^PROJECT_STRUCTURE\.md$/,
|
|
64
|
+
/^SECURITY_ISMS\.md$/,
|
|
65
|
+
/^PROMPT-LIBRARY\.md$/,
|
|
66
|
+
/^PROMPT_LIBRARY_USAGE\.md$/,
|
|
67
|
+
// 스크립트/자동화
|
|
68
|
+
/^scripts\//,
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
const significantChanges = staged.filter(file =>
|
|
72
|
+
significantPatterns.some(pattern => pattern.test(file))
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (significantChanges.length === 0) {
|
|
76
|
+
// 중요 변경이 아니면 무시
|
|
77
|
+
process.exit(0);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 경고 출력 (additionalContext로 Claude에게 전달)
|
|
81
|
+
const fileList = significantChanges.map(f => ` - ${f}`).join('\n');
|
|
82
|
+
|
|
83
|
+
console.log(`[README Guard] ⚠️ README.md 업데이트 필요 가능성 감지
|
|
84
|
+
|
|
85
|
+
다음 중요 파일이 변경되었지만 README.md가 커밋에 포함되지 않았습니다:
|
|
86
|
+
${fileList}
|
|
87
|
+
|
|
88
|
+
README.md에 반영이 필요한 변경인지 확인하세요.
|
|
89
|
+
- 새 기능/스킬 추가 → README에 설명 추가
|
|
90
|
+
- 버전 변경 → README 버전 번호 갱신
|
|
91
|
+
- 구조 변경 → README 구조 설명 업데이트
|
|
92
|
+
- 적용 방법 변경 → README 설치/적용 가이드 업데이트
|
|
93
|
+
|
|
94
|
+
커밋을 진행하기 전에 사용자에게 README.md 업데이트 여부를 확인하세요.`);
|
|
95
|
+
|
|
96
|
+
} catch (e) {
|
|
97
|
+
// git 명령 실패 시 조용히 무시 (hook이 커밋을 막지 않도록)
|
|
98
|
+
process.exit(0);
|
|
99
|
+
}
|
|
@@ -126,3 +126,5 @@ output.push('');
|
|
|
126
126
|
output.push('위 컨텍스트를 참고하여 이전 작업 맥락을 이어서 진행하세요.');
|
|
127
127
|
|
|
128
128
|
console.log(output.join('\n'));
|
|
129
|
+
|
|
130
|
+
try { require(require('path').join(require('os').homedir(), '.claude', 'scripts', 'retry-pending-records.cjs')); } catch(e) { /* 글로벌 스크립트 미설치 시 무시 */ }
|
package/.claude/settings.json
CHANGED
|
@@ -68,7 +68,34 @@
|
|
|
68
68
|
"hooks": [
|
|
69
69
|
{
|
|
70
70
|
"type": "command",
|
|
71
|
-
"command": "node scripts/security-check-hook.cjs"
|
|
71
|
+
"command": "node \"$(git rev-parse --show-toplevel)/scripts/security-check-hook.cjs\""
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"matcher": "Bash",
|
|
77
|
+
"hooks": [
|
|
78
|
+
{
|
|
79
|
+
"type": "command",
|
|
80
|
+
"command": "node .claude/scripts/readme-guard.cjs"
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"matcher": "Bash(git*commit*)",
|
|
86
|
+
"hooks": [
|
|
87
|
+
{
|
|
88
|
+
"type": "command",
|
|
89
|
+
"command": "node .claude/scripts/commit-guard.cjs"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"matcher": "Bash",
|
|
95
|
+
"hooks": [
|
|
96
|
+
{
|
|
97
|
+
"type": "command",
|
|
98
|
+
"command": "node .claude/scripts/npm-tag-guard.cjs"
|
|
72
99
|
}
|
|
73
100
|
]
|
|
74
101
|
}
|
|
@@ -101,7 +128,7 @@
|
|
|
101
128
|
"hooks": [
|
|
102
129
|
{
|
|
103
130
|
"type": "command",
|
|
104
|
-
"command": "node scripts/session-end-reminder.cjs"
|
|
131
|
+
"command": "node \"$(git rev-parse --show-toplevel)/scripts/session-end-reminder.cjs\""
|
|
105
132
|
}
|
|
106
133
|
]
|
|
107
134
|
}
|
|
@@ -141,7 +141,7 @@ Auto Memory가 활성화되어 있습니다.
|
|
|
141
141
|
|
|
142
142
|
> **중요**: `deny` 규칙은 프로젝트 전체에 **강제 적용**됩니다. `settings.local.json`이나 `~/.claude/settings.json`으로 우회할 수 없으므로, 위험 명령 차단에 가장 확실한 방법입니다. `deny`가 `allow`보다 우선합니다.
|
|
143
143
|
|
|
144
|
-
> Hook은
|
|
144
|
+
> Hook은 bash 셸에서 실행됩니다. Unix 문법을 사용할 수 있으며, Windows 전용 문법(`> nul`, `powershell`)만 피하면 OS 무관하게 동작합니다.
|
|
145
145
|
|
|
146
146
|
**Scripts 복사** - 표준 저장소의 세션 브리핑 스크립트를 복사:
|
|
147
147
|
- `/tmp/jinhak-standards/.claude/scripts/session-briefing.cjs` → `.claude/scripts/session-briefing.cjs`
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-garden
|
|
3
|
+
description: 코드 품질 점검 및 엔트로피 관리 — 아키텍처 린트, 중복 코드, 복잡도 급증, 미사용 코드 탐지
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /code-garden
|
|
7
|
+
|
|
8
|
+
코드 품질을 종합 점검하고 엔트로피(코드 복잡도 증가)를 관리합니다.
|
|
9
|
+
|
|
10
|
+
## 사용법
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
/code-garden [옵션]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**옵션:**
|
|
17
|
+
- `--check <type>`: 특정 검사만 실행 (`duplicates`, `complexity`, `unused`, `grade`, `all`)
|
|
18
|
+
- `--dir <path>`: 대상 디렉토리 지정
|
|
19
|
+
- `--auto-fix`: 자동 수정 안내 포함
|
|
20
|
+
- (기본: 전체 검사 + 리포트 출력)
|
|
21
|
+
|
|
22
|
+
## 절차
|
|
23
|
+
|
|
24
|
+
### 1단계: 도구 실행
|
|
25
|
+
|
|
26
|
+
`tools/code-garden/` 도구를 실행하여 코드 품질 지표를 수집합니다.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# 전체 검사
|
|
30
|
+
cd tools/code-garden && node dist/index.js --check all --dir <프로젝트_루트>
|
|
31
|
+
|
|
32
|
+
# 개별 검사
|
|
33
|
+
node dist/index.js --check duplicates --dir <프로젝트_루트>
|
|
34
|
+
node dist/index.js --check complexity --dir <프로젝트_루트>
|
|
35
|
+
node dist/index.js --check unused --dir <프로젝트_루트>
|
|
36
|
+
node dist/index.js --check grade --dir <프로젝트_루트>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
수집 항목:
|
|
40
|
+
1. **중복 코드 탐지** — 10줄 이상, 85%+ 유사도 코드 블록 탐지
|
|
41
|
+
2. **복잡도 급증 감지** — 최근 7일 대비 50%+ 복잡도 증가 파일
|
|
42
|
+
3. **미사용 코드 탐지** — export 했지만 다른 파일에서 import하지 않는 심볼
|
|
43
|
+
4. **품질 등급 산정** — 도메인(디렉토리)별 A~D 등급
|
|
44
|
+
|
|
45
|
+
### 2단계: 결과 분석 + 등급 산정
|
|
46
|
+
|
|
47
|
+
도구 출력 결과를 분석하여 도메인별 등급을 확인합니다.
|
|
48
|
+
|
|
49
|
+
| 등급 | 기준 |
|
|
50
|
+
|------|------|
|
|
51
|
+
| A | 린트 에러 0, 복잡도 낮음, 중복 코드 없음 |
|
|
52
|
+
| B | 린트 에러 5개 미만, 복잡도 중간 이하 |
|
|
53
|
+
| C | 린트 에러 10개 미만 |
|
|
54
|
+
| D | 위 기준 미달 |
|
|
55
|
+
|
|
56
|
+
분석 포인트:
|
|
57
|
+
- 등급이 하락한 도메인이 있는지 확인
|
|
58
|
+
- 복잡도 급증 파일의 원인 파악 (대규모 기능 추가? 리팩토링 필요?)
|
|
59
|
+
- 중복 코드가 공통 모듈로 추출 가능한지 검토
|
|
60
|
+
- 미사용 export가 의도적인지(향후 사용 예정) 확인
|
|
61
|
+
|
|
62
|
+
### 3단계: 리포트 출력
|
|
63
|
+
|
|
64
|
+
결과를 사용자에게 보고합니다. 형식:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
## 코드 품질 리포트 (YYYY-MM-DD)
|
|
68
|
+
|
|
69
|
+
### 전체 요약
|
|
70
|
+
- 전체 등급: X
|
|
71
|
+
- 총 파일 수: N
|
|
72
|
+
- 중복 코드: N건
|
|
73
|
+
- 복잡도 급증: N건
|
|
74
|
+
- 미사용 export: N건
|
|
75
|
+
|
|
76
|
+
### 도메인별 등급
|
|
77
|
+
| 도메인 | 등급 | 상세 |
|
|
78
|
+
|--------|------|------|
|
|
79
|
+
| ... | ... | ... |
|
|
80
|
+
|
|
81
|
+
### 주요 이슈
|
|
82
|
+
1. ...
|
|
83
|
+
2. ...
|
|
84
|
+
|
|
85
|
+
### 권장 조치
|
|
86
|
+
- ...
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`docs/quality/grades.md`를 도구 출력의 Markdown 리포트로 업데이트합니다.
|
|
90
|
+
|
|
91
|
+
### 4단계: 자동 수정 (--auto-fix 옵션 시)
|
|
92
|
+
|
|
93
|
+
`--auto-fix` 옵션이 지정된 경우, 자동 수정 가능한 항목을 안내합니다:
|
|
94
|
+
|
|
95
|
+
- **중복 코드**: 공통 함수/유틸로 추출할 위치 제안
|
|
96
|
+
- **미사용 export**: `export` 키워드 제거 또는 파일 삭제 제안
|
|
97
|
+
- **복잡도 급증**: 함수 분리, 조건문 단순화 등 리팩토링 제안
|
|
98
|
+
|
|
99
|
+
자동 수정은 직접 코드를 변경하며, 변경 전 확인을 요청합니다.
|
|
100
|
+
|
|
101
|
+
## 도구 경로
|
|
102
|
+
|
|
103
|
+
- **도구 위치**: `tools/code-garden/`
|
|
104
|
+
- **빌드**: `cd tools/code-garden && npm run build`
|
|
105
|
+
- **테스트**: `cd tools/code-garden && npm test`
|
|
106
|
+
- **CLI**: `node tools/code-garden/dist/index.js`
|
|
107
|
+
|
|
108
|
+
## 참고
|
|
109
|
+
|
|
110
|
+
- `docs/quality/grades-template.md` — 등급 문서 템플릿
|
|
111
|
+
- `docs/quality/tech-debt-template.md` — 기술 부채 추적 템플릿
|
|
112
|
+
- `docs/quality/daily-report-template.md` — 일일 리포트 템플릿
|
|
@@ -24,6 +24,11 @@ $ARGUMENTS - 버그 증상 또는 에러 메시지 (필수)
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
+
## 사전 참조
|
|
28
|
+
|
|
29
|
+
- `docs/standards/clarification-protocol.md` — 에러 정보가 부족하면 HIGH/MEDIUM 판정 후 질문
|
|
30
|
+
- `docs/standards/difficulty-guide.md` — 버그 복잡도에 따라 Phase 깊이 조절 (Simple 버그는 Phase 2에서 바로 수정 가능)
|
|
31
|
+
|
|
27
32
|
## 실행 절차 (4단계, 순서 엄수)
|
|
28
33
|
|
|
29
34
|
### Phase 1: 증상 수집 (Observe)
|
|
@@ -26,14 +26,47 @@ $ARGUMENTS - 구현할 기능/작업에 대한 설명 (필수)
|
|
|
26
26
|
|
|
27
27
|
> 간단한 작업은 Plan 모드(`EnterPlanMode`)로 충분합니다. `/deep-plan`은 **계획 자체의 품질 검증**이 필요할 때 사용합니다.
|
|
28
28
|
|
|
29
|
+
## 적응적 추천 (Auto-Suggest)
|
|
30
|
+
|
|
31
|
+
Plan 모드(`EnterPlanMode`) 진입 후 코드베이스를 탐색하면서 다음 조건 중 2개 이상 해당되면 `/deep-plan` 사용을 **추천**합니다. 최종 결정은 사용자에게 맡깁니다.
|
|
32
|
+
|
|
33
|
+
**복잡도 판정 기준:**
|
|
34
|
+
- 수정 대상 파일 5개 이상
|
|
35
|
+
- 2가지 이상 구현 방식 선택이 필요
|
|
36
|
+
- Human-in-the-Loop 필수 영역 해당 (인증/인가, 결제/정산, 개인정보, 암호화, 인프라, 마이그레이션)
|
|
37
|
+
- 신규 모듈/서비스 생성 포함
|
|
38
|
+
|
|
39
|
+
**추천 흐름:**
|
|
40
|
+
```
|
|
41
|
+
EnterPlanMode → 코드베이스 탐색 (Glob, Grep, Read)
|
|
42
|
+
↓
|
|
43
|
+
[복잡도 판정: 위 기준 2개+ 해당?]
|
|
44
|
+
├─ 예 → "이 작업은 L3 이상 복잡도입니다. `/deep-plan`으로 심층 계획을 수립하시겠습니까?"
|
|
45
|
+
│ → 사용자 승인 → `/deep-plan` 전환
|
|
46
|
+
│ → 사용자 거절 → 일반 Plan 모드 계속
|
|
47
|
+
└─ 아니오 → 일반 Plan 모드 진행
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**핵심: 추천은 하되 강제하지 않는다.** 사용자가 거절하면 일반 Plan 모드로 진행한다.
|
|
51
|
+
|
|
29
52
|
---
|
|
30
53
|
|
|
31
54
|
## 실행 절차
|
|
32
55
|
|
|
33
56
|
### 0단계: 사전 분석 및 요구사항 정제
|
|
34
57
|
|
|
35
|
-
|
|
36
|
-
|
|
58
|
+
> **필수 참조**: 이 단계에서 `docs/standards/prompt-structure.md`(4요소 구조), `docs/standards/clarification-protocol.md`(불확실성 대응)를 적용합니다.
|
|
59
|
+
|
|
60
|
+
1. 사용자의 요청(`$ARGUMENTS`)을 **4요소 프레임워크**로 분석:
|
|
61
|
+
- **Goal**: 명시적 요구사항과 암묵적 요구사항 분리
|
|
62
|
+
- **Context**: 관련 코드베이스 탐색 (Glob, Grep, Read)
|
|
63
|
+
- **Constraints**: CLAUDE.md 절대 규칙 + 작업 유형별 제약
|
|
64
|
+
- **Done When**: 검증 가능한 완료 기준 도출
|
|
65
|
+
2. **불확실성 판정** (`docs/standards/clarification-protocol.md`):
|
|
66
|
+
- LOW → 가정 기록 후 진행
|
|
67
|
+
- MEDIUM → 옵션 제시 + 사용자 선택
|
|
68
|
+
- HIGH → 질문 후 답변 받을 때까지 대기
|
|
69
|
+
3. **작업 유형 태그 자동 분류:**
|
|
37
70
|
|
|
38
71
|
| 태그 | 해당 조건 | Critic 가중치 영향 |
|
|
39
72
|
|------|----------|-------------------|
|
|
@@ -44,10 +77,6 @@ $ARGUMENTS - 구현할 기능/작업에 대한 설명 (필수)
|
|
|
44
77
|
| `비즈니스` | 핵심 도메인 로직, 결제/정산 | C6 가중 ×1.5, C4 가중 ×1.5 |
|
|
45
78
|
| `일반` | 위에 해당하지 않는 경우 | 기본 가중치 (모두 ×1.0) |
|
|
46
79
|
|
|
47
|
-
3. 모호하거나 결정이 필요한 부분이 있으면 `AskUserQuestion`으로 먼저 확인:
|
|
48
|
-
- 기술적 선택지 (예: JWT vs 세션, Redis vs 인메모리)
|
|
49
|
-
- 범위 확인 (어디까지 포함하는가)
|
|
50
|
-
- 우선순위 (성능 vs 구현 속도 vs 유지보수성)
|
|
51
80
|
4. 관련 코드베이스 탐색 (Glob, Grep, Read)으로 현재 상태 파악
|
|
52
81
|
|
|
53
82
|
### 1단계: 팀 구성
|
|
@@ -217,20 +246,6 @@ Task({
|
|
|
217
246
|
- 라운드 간 가중 비율 개선이 **+5%p 미만**이면 → 정체로 판단, 사용자 위임
|
|
218
247
|
- 3라운드 초과 시 → 전체 계획 + 비평 이력을 사용자에게 제시하고 판단 위임
|
|
219
248
|
|
|
220
|
-
**NightBuilder 환경 분기:**
|
|
221
|
-
|
|
222
|
-
NightBuilder(무인 자동 개발) 환경에서 3라운드 내 미수렴 시:
|
|
223
|
-
1. 현재까지의 계획서 + 비평 이력을 `.ai/PENDING_PLANS.md`에 저장:
|
|
224
|
-
```markdown
|
|
225
|
-
## [보류] YYYY-MM-DD HH:mm - [작업요약]
|
|
226
|
-
- 상태: 미수렴 (라운드 N, 가중 비율 NN.N%)
|
|
227
|
-
- C6 Hard Gate: 통과/실패/해당없음
|
|
228
|
-
- 저장된 계획서: `.ai/plans/YYYY-MM-DD_HHmm_[작업요약].md`
|
|
229
|
-
- 사유: [정체/라운드 초과/C6 Hard Gate 실패]
|
|
230
|
-
```
|
|
231
|
-
2. 다음 태스크로 진행 (교착 방지)
|
|
232
|
-
3. 다음 세션(사람 참여) 시 `session-briefing.cjs`가 보류 건을 감지하여 안내
|
|
233
|
-
|
|
234
249
|
**재작성 지시 시:**
|
|
235
250
|
```
|
|
236
251
|
SendMessage({
|
|
@@ -452,7 +467,7 @@ TeamDelete()
|
|
|
452
467
|
- Planner와 Critic은 **읽기 전용** 에이전트 (Plan 타입) — 코드를 직접 수정하지 않음
|
|
453
468
|
- Plan 타입이 사용 불가능한 경우 Explore → general-purpose(파일 수정 금지 지시) 순으로 폴백
|
|
454
469
|
- 비평은 냉혹하게 하되, **건설적인 대안**을 반드시 제시
|
|
455
|
-
- 3라운드 내 수렴하지 않으면 무한 반복하지 않고 사용자에게 위임
|
|
470
|
+
- 3라운드 내 수렴하지 않으면 무한 반복하지 않고 사용자에게 위임
|
|
456
471
|
- C6 Hard Gate는 보안/비즈니스 유형에서만 적용 — 일반 작업에 과도한 보안 검증을 강제하지 않음
|
|
457
472
|
|
|
458
473
|
---
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# dependency-guardian
|
|
2
|
+
|
|
3
|
+
npm 패키지 설치 안전성을 검증합니다.
|
|
4
|
+
|
|
5
|
+
## 트리거
|
|
6
|
+
|
|
7
|
+
사용자가 새로운 npm 패키지를 설치하려 할 때, 또는 `npm install`, `pnpm add` 등 패키지 추가 명령 실행 전에 이 스킬을 실행합니다.
|
|
8
|
+
|
|
9
|
+
## 데이터 소스 우선순위
|
|
10
|
+
|
|
11
|
+
패키지 상태 조회 시 아래 순서로 시도합니다:
|
|
12
|
+
|
|
13
|
+
### 1순위: JABIS API 실시간 조회
|
|
14
|
+
- URL: `{JABIS_API_URL}/api/v1/packages/check/{packageName}?mode={mode}`
|
|
15
|
+
- JABIS_API_URL은 프로젝트 CLAUDE.md의 `jabis_api_url` 설정에서 읽음
|
|
16
|
+
- 타임아웃: 3초
|
|
17
|
+
- 인증: JABIS JWT 토큰 (환경변수 `JABIS_API_TOKEN`)
|
|
18
|
+
|
|
19
|
+
### 2순위: 로컬 캐시 (assets/cache/*.json)
|
|
20
|
+
- `scripts/sync-jabis-cache.sh`로 주기적 동기화 (1일 1회 권장)
|
|
21
|
+
- 캐시 유효기간: 24시간 (파일 수정 시간 기준)
|
|
22
|
+
- 캐시 만료 시: "⚠️ JABIS 캐시가 24시간 이상 경과. sync-jabis-cache.sh 실행을 권장합니다."
|
|
23
|
+
|
|
24
|
+
### 3순위: 정적 파일 fallback
|
|
25
|
+
- `assets/BLOCKLIST.md`, `assets/ALLOWLIST_STRICT.md`
|
|
26
|
+
- API와 캐시 모두 실패 시 최종 fallback
|
|
27
|
+
- "⚠️ JABIS API 연결 불가. 정적 파일 기반 검사. 결과가 최신이 아닐 수 있습니다."
|
|
28
|
+
|
|
29
|
+
### 자동 모드 감지
|
|
30
|
+
- CLAUDE.md에 `jabis_api_url`이 없으면 → 정적 파일 모드로 동작 (기존 호환)
|
|
31
|
+
- `dependency_guard_mode: strict` 또는 `standard` (기본: standard)
|
|
32
|
+
|
|
33
|
+
## 실행 절차
|
|
34
|
+
|
|
35
|
+
### Step 0: JABIS 레지스트리 조회
|
|
36
|
+
1. JABIS API 호출 (또는 캐시/정적 파일 조회)
|
|
37
|
+
2. 응답 status에 따른 판정:
|
|
38
|
+
- **BLOCKED** → 즉시 ❌ BLOCK. reason과 alternative 표시. 이후 Step 스킵.
|
|
39
|
+
- **RECOMMENDED/ALLOWED** → 즉시 ✅ PASS. 이후 Step 스킵.
|
|
40
|
+
- **CAUTION** → ⚠️ WARN 후 Step 1~3 추가 검증 진행.
|
|
41
|
+
- **UNREGISTERED** → Step 1~3 일반 검사 플로우 진행.
|
|
42
|
+
- API 실패 → fallback 후 Step 1~3 진행.
|
|
43
|
+
3. STRICT 모드 + UNREGISTERED → 즉시 ❌ BLOCK:
|
|
44
|
+
"STRICT 모드에서 미등록 패키지는 설치 불가. JABIS 패키지 레지스트리에서 승인 요청을 먼저 진행하세요."
|
|
45
|
+
|
|
46
|
+
### Step 1: npm 메타데이터 검사
|
|
47
|
+
패키지의 npm 레지스트리 메타데이터를 확인합니다:
|
|
48
|
+
- 주간 다운로드 수 (1,000 미만 → 위험)
|
|
49
|
+
- 최종 발행일 (2년 초과 → 위험)
|
|
50
|
+
- 메인테이너 수 (1명 → 위험)
|
|
51
|
+
- install 스크립트 존재 여부
|
|
52
|
+
|
|
53
|
+
`references/check-package.md` 참조.
|
|
54
|
+
|
|
55
|
+
### Step 2: 취약점 검사
|
|
56
|
+
- `npm audit` 결과 확인
|
|
57
|
+
- Critical/High 취약점 → BLOCK
|
|
58
|
+
- Moderate → WARN
|
|
59
|
+
|
|
60
|
+
### Step 3: risk_score 계산
|
|
61
|
+
`references/scoring-criteria.md`의 기준으로 0~100 점수 산출.
|
|
62
|
+
|
|
63
|
+
## 결과 출력 형식
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
📦 패키지: {name}@{version}
|
|
67
|
+
🔒 모드: STRICT | STANDARD
|
|
68
|
+
📡 소스: JABIS API | 로컬 캐시 ({N}시간 전) | 정적 파일 (fallback)
|
|
69
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
70
|
+
✅ PASS | ⚠️ WARN | ❌ BLOCK
|
|
71
|
+
|
|
72
|
+
📊 위험도: {score}/100
|
|
73
|
+
📋 사유: {reason}
|
|
74
|
+
🔄 대안: {alternative} (BLOCK/CAUTION 시)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Lock 파일 전수 검사
|
|
78
|
+
|
|
79
|
+
`/dependency-guardian audit` 명령으로 package-lock.json 전체 패키지를 검사합니다.
|
|
80
|
+
- JABIS bulk-check API 활용 (가능한 경우)
|
|
81
|
+
- `references/audit-lockfile.md` 참조.
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
## CLAUDE.md 설정 예시
|
|
85
|
+
|
|
86
|
+
```markdown
|
|
87
|
+
## Dependency Guardian 설정
|
|
88
|
+
dependency_guard_mode: strict
|
|
89
|
+
jabis_api_url: https://jabis.jinhakapply.com
|
|
90
|
+
jabis_api_token: ${JABIS_API_TOKEN}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## 참조 문서
|
|
94
|
+
- `references/check-package.md` — 단일 패키지 검사 상세
|
|
95
|
+
- `references/audit-lockfile.md` — Lock 파일 전수 검사
|
|
96
|
+
- `references/scoring-criteria.md` — risk_score 계산 기준
|
|
97
|
+
- `references/jabis-api-guide.md` — JABIS API 연동 가이드
|