jinhak-ai-standard 2.6.0 → 2.7.1
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/readme-guard.cjs +99 -0
- package/.claude/settings.json +9 -0
- package/.claude/skills/apply-standard/SKILL.md +1 -1
- package/CHANGELOG.md +44 -1
- package/CLAUDE.md +14 -15
- package/PROMPT_LIBRARY_USAGE.md +1 -1
- package/QUICK_START_PROMPT.md +1 -1
- package/README.md +27 -28
- package/bin/cli.cjs +181 -10
- package/package.json +1 -1
- package/templates/project-claude.md +1 -1
|
@@ -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
|
+
}
|
package/.claude/settings.json
CHANGED
|
@@ -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`
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,48 @@ Claude Code의 `/session-start` 스킬이 이 파일을 참조하여 표준 업
|
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
+
## [2.7.1] - 2026-03-12
|
|
9
|
+
|
|
10
|
+
### README Guard Hook — 커밋 시 README.md 업데이트 누락 자동 감지
|
|
11
|
+
|
|
12
|
+
커밋 시점에 중요 파일이 변경되었지만 README.md가 staged에 포함되지 않은 경우 Claude에게 경고를 전달하여 자동으로 README 업데이트를 유도합니다.
|
|
13
|
+
|
|
14
|
+
### 추가
|
|
15
|
+
- `.claude/scripts/readme-guard.cjs` — PreToolUse Hook 스크립트 (git commit 시 README.md 누락 감지)
|
|
16
|
+
- `.claude/settings.json` — PreToolUse Hook에 readme-guard.cjs 등록
|
|
17
|
+
|
|
18
|
+
### 동작 방식
|
|
19
|
+
- `git commit` 실행 전 staged 파일 분석
|
|
20
|
+
- CLAUDE.md, skills, templates, scripts, security 등 중요 파일 변경 감지
|
|
21
|
+
- README.md 미포함 시 additionalContext로 경고 → Claude가 사용자에게 확인 요청
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## [2.7] - 2026-03-04
|
|
26
|
+
|
|
27
|
+
### CLI 기술 스택 자동 감지 + CLAUDE.md 완전 자동 생성
|
|
28
|
+
|
|
29
|
+
`npx jinhak-ai-standard` 실행 시 프로젝트의 기술 스택을 자동 감지하여 CLAUDE.md와 .ai/ 폴더를 의미있는 내용으로 생성합니다.
|
|
30
|
+
|
|
31
|
+
### 추가
|
|
32
|
+
- `detectTechStack()` — package.json에서 프레임워크, 언어, 패키지매니저, 상태관리, 스타일링, DB, ORM, 빌드도구, 테스트도구 자동 감지
|
|
33
|
+
- `applyStackToTemplate()` — templates/project-claude.md 템플릿의 `[대괄호]` 플레이스홀더를 감지된 기술 스택으로 자동 치환
|
|
34
|
+
- `generateFolderTree()` — 프로젝트 1-depth 폴더 트리 자동 생성
|
|
35
|
+
- `generateAiContent()` — .ai/ 폴더 파일에 감지된 기술 스택 기반 의미있는 초기 내용 생성 (ADR-001 포함)
|
|
36
|
+
|
|
37
|
+
### 변경
|
|
38
|
+
- `bin/cli.cjs`: apply() 흐름에 기술 스택 감지 → 템플릿 치환 → 의미있는 .ai/ 생성 단계 추가
|
|
39
|
+
- `package.json`: 버전 2.6.0 → 2.7.0
|
|
40
|
+
- `CLAUDE.md`: 버전 2.6 → 2.7
|
|
41
|
+
|
|
42
|
+
### Migration Guide (v2.6 → v2.7)
|
|
43
|
+
|
|
44
|
+
기존 v2.6 프로젝트에서 업데이트 시:
|
|
45
|
+
1. `npx jinhak-ai-standard` 재실행 — 기존 CLAUDE.md가 있으면 덮어쓰지 않고 버전만 안내
|
|
46
|
+
2. 새 프로젝트에서는 자동으로 기술 스택이 감지되어 CLAUDE.md에 반영됨
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
8
50
|
## [2.6] - 2026-03-02
|
|
9
51
|
|
|
10
52
|
### npm 패키지 + GitHub Releases 배포 시스템
|
|
@@ -17,9 +59,10 @@ Claude Code의 `/session-start` 스킬이 이 파일을 참조하여 표준 업
|
|
|
17
59
|
- `.github/workflows/release.yml` — 태그 push 시 GitHub Release + npm publish 자동화
|
|
18
60
|
|
|
19
61
|
### 변경
|
|
62
|
+
- `bin/cli.cjs`: CLAUDE.md 자동 생성(신규) 및 버전 메타데이터 업데이트(기존), prompts/ 디렉토리 복사 추가
|
|
20
63
|
- `.claude/skills/apply-standard/SKILL.md`: 0단계에 npm 패키지 → Release tarball → git clone 3단계 폴백 추가
|
|
21
64
|
- `QUICK_START_PROMPT.md`: 방법 1(npx), 방법 2(프롬프트), 방법 3(Release tarball) 구분
|
|
22
|
-
- `README.md`: v2.5 → v2.6, 적용 방법 1~4로 재정리, 문서 구조에 새 파일
|
|
65
|
+
- `README.md`: v2.5 → v2.6, 적용 방법 1~4로 재정리, 문서 구조에 새 파일 추가, npx 설명에 CLAUDE.md 자동 생성 반영
|
|
23
66
|
- `CLAUDE.md`: 버전 2.5 → 2.6, 프로젝트 구조에 package.json/bin/cli.cjs 추가
|
|
24
67
|
|
|
25
68
|
### Migration Guide (v2.5 → v2.6)
|
package/CLAUDE.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<!-- JINHAK Standard Metadata - 이 메타 정보는 자동 버전 관리에 사용됩니다. 삭제하지 마세요. -->
|
|
2
|
-
<!-- jinhak_standard_version: 2.
|
|
2
|
+
<!-- jinhak_standard_version: 2.7 -->
|
|
3
3
|
<!-- jinhak_standard_repo: https://github.com/JinhakStandard/ai-vibecoding -->
|
|
4
|
-
<!-- applied_date: 2026-03-
|
|
4
|
+
<!-- applied_date: 2026-03-04 -->
|
|
5
5
|
|
|
6
|
-
# JINHAK 전사 AI 개발 표준 v2.
|
|
6
|
+
# JINHAK 전사 AI 개발 표준 v2.7
|
|
7
7
|
|
|
8
8
|
이 문서는 JINHAK의 모든 프로젝트에서 AI(Claude Code / Claude.ai)와 협업할 때 따라야 하는 전사 표준입니다.
|
|
9
9
|
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
|
|
63
63
|
```
|
|
64
64
|
프로젝트루트/
|
|
65
|
-
├── package.json # npm 패키지 설정 — npx jinhak-ai-standard (v2.
|
|
66
|
-
├── bin/cli.cjs # CLI 진입점 (apply/info/link/help) (v2.
|
|
65
|
+
├── package.json # npm 패키지 설정 — npx jinhak-ai-standard (v2.7)
|
|
66
|
+
├── bin/cli.cjs # CLI 진입점 (apply/info/link/help + 기술 스택 자동 감지) (v2.7)
|
|
67
67
|
├── .github/workflows/ # GitHub Actions (release.yml → 태그 push 시 Release + npm publish) (v2.6)
|
|
68
68
|
├── CLAUDE.md # Claude Code 메인 설정 파일 (필수)
|
|
69
69
|
├── CLAUDE.local.md # 로컬 개발자 설정 (git 제외, 선택사항)
|
|
@@ -204,19 +204,18 @@ Claude는 다음 안티패턴을 감지하면 **즉시 경고하고 대안을
|
|
|
204
204
|
> 상세 내용: [security/AI_SECURITY_GUARDRAILS.md](./security/AI_SECURITY_GUARDRAILS.md)
|
|
205
205
|
> 상세 안티패턴 목록과 대화 예시는 [VIBE_CODING_GUIDE.md](./VIBE_CODING_GUIDE.md) 섹션 6.4~6.5를 참조하세요.
|
|
206
206
|
|
|
207
|
-
### 2.5 Hook
|
|
207
|
+
### 2.5 Hook 실행 환경 및 규칙
|
|
208
208
|
|
|
209
|
-
|
|
209
|
+
**Claude Code의 Hook은 bash 셸에서 실행**됩니다. 따라서 Unix 문법(`2>/dev/null`, `||`, `&&` 등)을 사용할 수 있으며, `node`, `npx`, `git` 등 bash PATH에 있는 모든 명령을 사용할 수 있습니다.
|
|
210
210
|
|
|
211
211
|
**필수 규칙:**
|
|
212
|
-
-
|
|
213
|
-
-
|
|
214
|
-
-
|
|
215
|
-
- 파일 경로는 `path.join()`으로 생성하고 슬래시(`/`)로 통일할 것
|
|
212
|
+
- Windows 전용 문법 사용 금지: `> nul`, `2>nul`, `powershell -Command` 등
|
|
213
|
+
- 파일 경로는 슬래시(`/`)로 통일할 것 (백슬래시 `\` 금지)
|
|
214
|
+
- 복잡한 로직은 `.cjs` 스크립트로 분리하여 `node script.cjs`로 실행 권장
|
|
216
215
|
|
|
217
216
|
**Windows `nul` 파일 방지:**
|
|
218
|
-
- `> nul`, `2>nul` 사용 금지 (예약 디바이스 이름 충돌로 `nul` 파일 생성)
|
|
219
|
-
-
|
|
217
|
+
- `> nul`, `2>nul` 사용 금지 (Windows 예약 디바이스 이름 충돌로 `nul` 파일 생성)
|
|
218
|
+
- bash 환경에서는 `> /dev/null 2>&1` 사용
|
|
220
219
|
|
|
221
220
|
### 2.6 Windows 개발 환경 규칙
|
|
222
221
|
|
|
@@ -507,7 +506,7 @@ body: { action: 'delete', id: '123' }
|
|
|
507
506
|
}
|
|
508
507
|
```
|
|
509
508
|
|
|
510
|
-
> Hook은
|
|
509
|
+
> Hook은 bash 셸에서 실행됩니다. `node`, `npx` 등 bash에서 사용 가능한 명령과 Unix 문법(`2>/dev/null`, `||` 등)을 모두 사용할 수 있습니다. Windows 전용 문법(`> nul`, `powershell`)은 사용하지 마세요.
|
|
511
510
|
|
|
512
511
|
### 6.1.1 글로벌 Hook (자동 표준 감지)
|
|
513
512
|
|
|
@@ -1165,4 +1164,4 @@ AI가 생성해서는 안 되는 12가지 위험 패턴:
|
|
|
1165
1164
|
---
|
|
1166
1165
|
|
|
1167
1166
|
*마지막 업데이트: 2026-03-01*
|
|
1168
|
-
*버전: 2.
|
|
1167
|
+
*버전: 2.7*
|
package/PROMPT_LIBRARY_USAGE.md
CHANGED
package/QUICK_START_PROMPT.md
CHANGED
|
@@ -99,7 +99,7 @@ CLAUDE.local.md
|
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
101
|
mkdir -p /tmp/jinhak-standards
|
|
102
|
-
curl -sL https://github.com/JinhakStandard/ai-vibecoding/archive/refs/tags/v2.
|
|
102
|
+
curl -sL https://github.com/JinhakStandard/ai-vibecoding/archive/refs/tags/v2.7.tar.gz \
|
|
103
103
|
| tar -xz -C /tmp/jinhak-standards --strip-components=1
|
|
104
104
|
```
|
|
105
105
|
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# JINHAK AI 개발 표준 v2.
|
|
1
|
+
# JINHAK AI 개발 표준 v2.7 (AI Vibe Coding Standards)
|
|
2
2
|
|
|
3
3
|
JINHAK 전사에서 AI(Claude Code / Claude.ai)와 협업할 때 따라야 하는 개발 표준 문서입니다.
|
|
4
4
|
|
|
@@ -13,8 +13,8 @@ cd my-project
|
|
|
13
13
|
npx jinhak-ai-standard
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
`.claude/`, `.ai/`, `security/` 등 표준 파일이 자동으로
|
|
17
|
-
|
|
16
|
+
`CLAUDE.md`, `.claude/`, `.ai/`, `security/`, `prompts/` 등 표준 파일이 자동으로 생성됩니다.
|
|
17
|
+
`CLAUDE.md`의 `[대괄호]` 내용을 프로젝트 정보로 수정한 뒤 Claude Code에서 `/session-start`로 시작하세요.
|
|
18
18
|
|
|
19
19
|
### 방법 2: Claude Code 프롬프트 (복사-붙여넣기)
|
|
20
20
|
|
|
@@ -105,9 +105,9 @@ claude
|
|
|
105
105
|
|
|
106
106
|
> 각 프로젝트의 CLAUDE.md에 다음 메타 정보가 기록되어 추적됩니다:
|
|
107
107
|
> ```html
|
|
108
|
-
> <!-- jinhak_standard_version: 2.
|
|
108
|
+
> <!-- jinhak_standard_version: 2.7 -->
|
|
109
109
|
> <!-- jinhak_standard_repo: https://github.com/JinhakStandard/ai-vibecoding -->
|
|
110
|
-
> <!-- applied_date: 2026-
|
|
110
|
+
> <!-- applied_date: 2026-03-04 -->
|
|
111
111
|
> ```
|
|
112
112
|
|
|
113
113
|
---
|
|
@@ -138,9 +138,9 @@ JinhakStandard/
|
|
|
138
138
|
├── VIBE_CODING_GUIDE.md # 바이브 코딩 방법론 (비개발자 포함)
|
|
139
139
|
├── PROJECT_STRUCTURE.md # 표준 프로젝트 구조
|
|
140
140
|
├── SECURITY_ISMS.md # ISMS 보안 가이드
|
|
141
|
-
├── PROMPT-LIBRARY.md # 프롬프트 라이브러리 시스템 가이드
|
|
142
|
-
├── PROMPT_LIBRARY_USAGE.md # 프롬프트 라이브러리 사용법
|
|
143
|
-
├── prompts/ # 프롬프트 라이브러리
|
|
141
|
+
├── PROMPT-LIBRARY.md # 프롬프트 라이브러리 시스템 가이드
|
|
142
|
+
├── PROMPT_LIBRARY_USAGE.md # 프롬프트 라이브러리 사용법
|
|
143
|
+
├── prompts/ # 프롬프트 라이브러리
|
|
144
144
|
│ ├── _template/ # 새 프롬프트 작성용 템플릿
|
|
145
145
|
│ ├── code-gen/ # 코드 생성 프롬프트
|
|
146
146
|
│ ├── code-review/ # 코드 리뷰 프롬프트
|
|
@@ -166,8 +166,9 @@ JinhakStandard/
|
|
|
166
166
|
├── .claude/ # Claude Code 설정 (표준 템플릿)
|
|
167
167
|
│ ├── settings.json # 권한, hooks 설정
|
|
168
168
|
│ ├── scripts/
|
|
169
|
-
│ │
|
|
170
|
-
│ └──
|
|
169
|
+
│ │ ├── session-briefing.cjs # 세션 자동 브리핑 Hook 스크립트
|
|
170
|
+
│ │ └── readme-guard.cjs # 커밋 시 README.md 누락 감지 (v2.7.1)
|
|
171
|
+
│ └── skills/ # 슬래시 명령어 (14개)
|
|
171
172
|
│ ├── apply-standard/ # /apply-standard - 표준 적용/업데이트
|
|
172
173
|
│ ├── commit/ # /commit - 커밋 생성
|
|
173
174
|
│ ├── debug/ # /debug - 체계적 디버깅 (v2.3)
|
|
@@ -175,9 +176,10 @@ JinhakStandard/
|
|
|
175
176
|
│ ├── orchestrate/ # /orchestrate - Agent Teams + 2단계 검증 (v2.3)
|
|
176
177
|
│ ├── review-pr/ # /review-pr - PR 리뷰
|
|
177
178
|
│ ├── security-check/ # /security-check - 보안 점검 (v2.0)
|
|
178
|
-
│ ├── prompt-register/ # /prompt-register - 프롬프트 등록
|
|
179
|
-
│ ├── prompt-search/ # /prompt-search - 프롬프트 검색
|
|
180
|
-
│ ├── prompt-quality-check/ # /prompt-quality-check - 품질 검증
|
|
179
|
+
│ ├── prompt-register/ # /prompt-register - 프롬프트 등록
|
|
180
|
+
│ ├── prompt-search/ # /prompt-search - 프롬프트 검색
|
|
181
|
+
│ ├── prompt-quality-check/ # /prompt-quality-check - 품질 검증
|
|
182
|
+
│ ├── prompt-report/ # /prompt-report - 사용량 리포트 (v2.5)
|
|
181
183
|
│ ├── session-end/ # /session-end - 세션 종료 (v2.0.2)
|
|
182
184
|
│ ├── session-start/ # /session-start - 세션 시작
|
|
183
185
|
│ └── test/ # /test - 테스트 + Red-Green 검증 (v2.3)
|
|
@@ -213,26 +215,20 @@ JinhakStandard/
|
|
|
213
215
|
|
|
214
216
|
## 빠른 시작
|
|
215
217
|
|
|
216
|
-
> **자동 적용(권장):** [QUICK_START_PROMPT.md](./QUICK_START_PROMPT.md)의 프롬프트를 사용하세요.
|
|
218
|
+
> **자동 적용(권장):** `npx jinhak-ai-standard` 또는 [QUICK_START_PROMPT.md](./QUICK_START_PROMPT.md)의 프롬프트를 사용하세요.
|
|
217
219
|
|
|
218
220
|
### 수동 적용 (필요 시)
|
|
219
221
|
|
|
220
222
|
```bash
|
|
221
|
-
#
|
|
222
|
-
|
|
223
|
+
# 방법 A: npx로 한 번에 적용 (권장)
|
|
224
|
+
npx jinhak-ai-standard
|
|
223
225
|
|
|
224
|
-
#
|
|
226
|
+
# 방법 B: 저장소 클론 후 수동 복사
|
|
227
|
+
git clone https://github.com/JinhakStandard/ai-vibecoding.git /tmp/jinhak-standards
|
|
225
228
|
cp /tmp/jinhak-standards/templates/project-claude.md ./CLAUDE.md
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
mkdir -p .ai
|
|
229
|
-
touch .ai/SESSION_LOG.md .ai/CURRENT_SPRINT.md .ai/DECISIONS.md .ai/ARCHITECTURE.md .ai/CONVENTIONS.md
|
|
230
|
-
|
|
231
|
-
# 4. 스킬 파일 및 settings.json 복사
|
|
232
|
-
cp /tmp/jinhak-standards/.claude/skills/*/SKILL.md 각_스킬_폴더/
|
|
233
|
-
cp /tmp/jinhak-standards/.claude/settings.json .claude/
|
|
234
|
-
|
|
235
|
-
# 5. .gitignore에 추가
|
|
229
|
+
cp -r /tmp/jinhak-standards/.claude .
|
|
230
|
+
cp -r /tmp/jinhak-standards/security .
|
|
231
|
+
mkdir -p .ai
|
|
236
232
|
echo "CLAUDE.local.md" >> .gitignore
|
|
237
233
|
```
|
|
238
234
|
|
|
@@ -308,7 +304,10 @@ claude
|
|
|
308
304
|
|
|
309
305
|
| 버전 | 날짜 | 변경 내용 |
|
|
310
306
|
|------|------|----------|
|
|
311
|
-
| **2.
|
|
307
|
+
| **2.7.1** | **2026-03-12** | **README Guard Hook: 커밋 시 중요 파일 변경 시 README.md 업데이트 누락 자동 감지** |
|
|
308
|
+
| 2.7 | 2026-03-04 | CLI 기술 스택 자동 감지 + CLAUDE.md 완전 자동 생성: `npx jinhak-ai-standard` 실행 시 package.json 분석하여 기술 스택 자동 반영 |
|
|
309
|
+
| 2.6 | 2026-03-02 | npm 패키지 + GitHub Releases 배포: `npx jinhak-ai-standard` CLI (CLAUDE.md 자동 생성/업데이트, prompts/ 복사 포함) |
|
|
310
|
+
| 2.5 | 2026-03-01 | 프롬프트 라이브러리 Phase 2: JABIS API 연동, `/prompt-report` 스킬, 사용량 추적 |
|
|
312
311
|
| 2.4 | 2026-02-28 | 프롬프트 라이브러리 Phase 1: 등록/검색/품질검증 시스템, 예시 프롬프트 3개, `/prompt-register` `/prompt-search` `/prompt-quality-check` 스킬 |
|
|
313
312
|
| 2.3 | 2026-02-28 | 적응적 추천 + skills.sh 모범사례 + 멀티 에이전트 패턴: 가중치 비평, C6 Hard Gate, State Contract, 스킬 조합 가이드, 2단계 검증, `/debug` 스킬, AI 합리화 방지 |
|
|
314
313
|
| 2.2 | 2026-02-28 | Planner-Critic 듀얼 에이전트 `/deep-plan` 스킬, Auto Memory 보강, memory-templates 추가 |
|
package/bin/cli.cjs
CHANGED
|
@@ -83,6 +83,143 @@ function ensureGitignoreEntries(entries) {
|
|
|
83
83
|
return added;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
// ─────────────────────────────────────────
|
|
87
|
+
// 기술 스택 자동 감지
|
|
88
|
+
// ─────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
function detectTechStack() {
|
|
91
|
+
const stack = { projectName: path.basename(TARGET), description: '', framework: [], language: 'JavaScript', packageManager: 'npm', stateManagement: '', styling: '', database: '', orm: '', buildTool: '', testTool: '', scripts: {} };
|
|
92
|
+
let pkg = null;
|
|
93
|
+
try { pkg = JSON.parse(fs.readFileSync(path.join(TARGET, 'package.json'), 'utf8')); } catch { /* ignore */ }
|
|
94
|
+
|
|
95
|
+
if (pkg) {
|
|
96
|
+
if (pkg.name) stack.projectName = pkg.name;
|
|
97
|
+
if (pkg.description) stack.description = pkg.description;
|
|
98
|
+
if (pkg.scripts) stack.scripts = pkg.scripts;
|
|
99
|
+
const deps = Object.keys(pkg.dependencies || {}), devDeps = Object.keys(pkg.devDependencies || {}), allDeps = [...deps, ...devDeps];
|
|
100
|
+
|
|
101
|
+
if (deps.includes('next')) stack.framework.push('Next.js');
|
|
102
|
+
if (deps.includes('react') && !deps.includes('next')) stack.framework.push('React');
|
|
103
|
+
if (deps.includes('@nestjs/core')) stack.framework.push('NestJS');
|
|
104
|
+
if (deps.includes('express')) stack.framework.push('Express');
|
|
105
|
+
if (deps.includes('fastify')) stack.framework.push('Fastify');
|
|
106
|
+
if (deps.includes('nuxt')) stack.framework.push('Nuxt');
|
|
107
|
+
if (deps.includes('vue')) stack.framework.push('Vue');
|
|
108
|
+
|
|
109
|
+
if (allDeps.includes('typescript') || fs.existsSync(path.join(TARGET, 'tsconfig.json'))) stack.language = 'TypeScript';
|
|
110
|
+
|
|
111
|
+
if (deps.includes('zustand')) stack.stateManagement = 'Zustand';
|
|
112
|
+
else if (deps.includes('@reduxjs/toolkit') || deps.includes('redux')) stack.stateManagement = 'Redux';
|
|
113
|
+
else if (deps.includes('recoil')) stack.stateManagement = 'Recoil';
|
|
114
|
+
else if (deps.includes('jotai')) stack.stateManagement = 'Jotai';
|
|
115
|
+
|
|
116
|
+
if (allDeps.includes('tailwindcss')) stack.styling = 'Tailwind CSS';
|
|
117
|
+
else if (allDeps.includes('styled-components')) stack.styling = 'styled-components';
|
|
118
|
+
else if (allDeps.includes('@emotion/react')) stack.styling = 'Emotion';
|
|
119
|
+
else if (allDeps.includes('sass') || allDeps.includes('node-sass')) stack.styling = 'Sass/SCSS';
|
|
120
|
+
|
|
121
|
+
if (deps.includes('pg')) stack.database = 'PostgreSQL';
|
|
122
|
+
else if (deps.includes('mssql') || deps.includes('tedious')) stack.database = 'MSSQL';
|
|
123
|
+
else if (deps.includes('mysql2') || deps.includes('mysql')) stack.database = 'MySQL';
|
|
124
|
+
else if (deps.includes('mongodb') || deps.includes('mongoose')) stack.database = 'MongoDB';
|
|
125
|
+
|
|
126
|
+
if (deps.includes('@prisma/client') || devDeps.includes('prisma')) stack.orm = 'Prisma';
|
|
127
|
+
else if (deps.includes('drizzle-orm')) stack.orm = 'Drizzle';
|
|
128
|
+
else if (deps.includes('typeorm')) stack.orm = 'TypeORM';
|
|
129
|
+
|
|
130
|
+
if (allDeps.includes('vite')) stack.buildTool = 'Vite';
|
|
131
|
+
else if (allDeps.includes('webpack')) stack.buildTool = 'Webpack';
|
|
132
|
+
else if (allDeps.includes('esbuild')) stack.buildTool = 'esbuild';
|
|
133
|
+
|
|
134
|
+
if (allDeps.includes('vitest')) stack.testTool = 'Vitest';
|
|
135
|
+
else if (allDeps.includes('jest')) stack.testTool = 'Jest';
|
|
136
|
+
else if (allDeps.includes('mocha')) stack.testTool = 'Mocha';
|
|
137
|
+
else if (allDeps.includes('playwright')) stack.testTool = 'Playwright';
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (fs.existsSync(path.join(TARGET, 'pnpm-lock.yaml'))) stack.packageManager = 'pnpm';
|
|
141
|
+
else if (fs.existsSync(path.join(TARGET, 'yarn.lock'))) stack.packageManager = 'yarn';
|
|
142
|
+
else if (fs.existsSync(path.join(TARGET, 'bun.lockb')) || fs.existsSync(path.join(TARGET, 'bun.lock'))) stack.packageManager = 'bun';
|
|
143
|
+
if (fs.existsSync(path.join(TARGET, 'tsconfig.json'))) stack.language = 'TypeScript';
|
|
144
|
+
|
|
145
|
+
return stack;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function generateFolderTree() {
|
|
149
|
+
try {
|
|
150
|
+
const entries = fs.readdirSync(TARGET, { withFileTypes: true })
|
|
151
|
+
.filter(e => !(e.name.startsWith('.') && e.name !== '.ai' && e.name !== '.claude') && e.name !== 'node_modules')
|
|
152
|
+
.sort((a, b) => a.isDirectory() === b.isDirectory() ? a.name.localeCompare(b.name) : a.isDirectory() ? -1 : 1);
|
|
153
|
+
return entries.map((e, i) => (i === entries.length - 1 ? '\u2514\u2500\u2500 ' : '\u251C\u2500\u2500 ') + e.name + (e.isDirectory() ? '/' : '')).join('\n');
|
|
154
|
+
} catch { return '[프로젝트 폴더 구조를 여기에 작성]'; }
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function applyStackToTemplate(template, stack, version) {
|
|
158
|
+
const today = new Date().toISOString().split('T')[0];
|
|
159
|
+
template = template.replace(/\r\n/g, '\n');
|
|
160
|
+
const metaStart = template.indexOf('<!-- JINHAK Standard Metadata');
|
|
161
|
+
if (metaStart > 0) template = template.substring(metaStart);
|
|
162
|
+
|
|
163
|
+
template = template.replace(/jinhak_standard_version:\s*[\d.]+/, 'jinhak_standard_version: ' + version);
|
|
164
|
+
template = template.replace('[YYYY-MM-DD]', today);
|
|
165
|
+
template = template.replace(/\[표준 저장소 URL[^\]]*\]/, 'https://github.com/JinhakStandard/ai-vibecoding');
|
|
166
|
+
template = template.replace(/\[프로젝트명\]/g, stack.projectName);
|
|
167
|
+
template = template.replace(/\[프로젝트 한 줄 설명\]/, stack.description || '<!-- TODO: 프로젝트 설명을 작성하세요 -->');
|
|
168
|
+
template = template.replace(/\[프로젝트 폴더 구조를 여기에 작성\]/, generateFolderTree());
|
|
169
|
+
|
|
170
|
+
const fw = stack.framework.length > 0 ? stack.framework.join(' + ') : '-';
|
|
171
|
+
template = template.replace(/\[React \/ Next\.js \/ Express \/ NestJS 등\]/, fw);
|
|
172
|
+
template = template.replace(/\[JavaScript \/ TypeScript\]/, stack.language);
|
|
173
|
+
template = template.replace(/\[pnpm \/ npm \/ yarn\]/, stack.packageManager);
|
|
174
|
+
template = template.replace(/\[Zustand \/ Redux 등\]/, stack.stateManagement || '-');
|
|
175
|
+
template = template.replace(/\[Tailwind CSS \/ CSS Modules 등\]/, stack.styling || '-');
|
|
176
|
+
template = template.replace(/\[PostgreSQL \/ MySQL \/ MongoDB 등\]/, stack.database || '-');
|
|
177
|
+
template = template.replace(/\[Prisma \/ Drizzle \/ TypeORM 등\]/, stack.orm || '-');
|
|
178
|
+
template = template.replace(/\[Vite \/ Webpack \/ Turbopack 등\]/, stack.buildTool || '-');
|
|
179
|
+
|
|
180
|
+
const pm = stack.packageManager, s = stack.scripts, run = pm === 'npm' ? 'npm run' : pm;
|
|
181
|
+
template = template.replace(/\[pnpm install\]/g, pm === 'npm' ? 'npm install' : `${pm} install`);
|
|
182
|
+
template = template.replace(/\[pnpm dev\]/, s.dev ? `${run} dev` : `# ${run} dev (스크립트 미정의)`);
|
|
183
|
+
template = template.replace(/\[pnpm build\]/g, s.build ? `${run} build` : `# ${run} build (스크립트 미정의)`);
|
|
184
|
+
template = template.replace(/\[pnpm test\]/, s.test ? `${run} test` : `# ${run} test (스크립트 미정의)`);
|
|
185
|
+
template = template.replace(/\[pnpm typecheck\]/, s.typecheck ? `${run} typecheck` : (stack.language === 'TypeScript' ? 'npx tsc --noEmit' : `# TypeScript 미사용`));
|
|
186
|
+
template = template.replace(/\[pnpm lint\]/, s.lint ? `${run} lint` : `# ${run} lint (스크립트 미정의)`);
|
|
187
|
+
template = template.replace(/### 5\. \[프로젝트 특화 규칙\]\n- \[규칙 1 설명\]\n- \[규칙 2 설명\]\n- \[규칙 3 설명\]/, '### 5. 프로젝트 특화 규칙\n<!-- TODO: 프로젝트에 맞는 규칙을 추가하세요 -->\n- (규칙 추가 필요)');
|
|
188
|
+
template = template.replace(/\[apps\/\*\/node_modules packages\/\*\/node_modules\]/, '');
|
|
189
|
+
|
|
190
|
+
return template;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function generateAiContent(filename, stack, version) {
|
|
194
|
+
const today = new Date().toISOString().split('T')[0];
|
|
195
|
+
const fw = stack.framework.length > 0 ? stack.framework.join(' + ') : '미감지';
|
|
196
|
+
|
|
197
|
+
switch (filename) {
|
|
198
|
+
case 'SESSION_LOG.md':
|
|
199
|
+
return `# 세션 작업 기록\n\n> 세션 종료 시 반드시 업데이트하세요.\n\n---\n\n## ${today}\n\n### 세션 요약\n- JINHAK AI 개발 표준 v${version} 적용\n\n### 주요 변경\n- \`CLAUDE.md\` - AI 협업 설정 파일 생성\n- \`.claude/\` - Claude Code 설정 복사\n- \`.ai/\` - 프로젝트 문서화 폴더 초기화\n\n### 커밋\n- (표준 적용 커밋 필요)\n\n---\n`;
|
|
200
|
+
case 'CURRENT_SPRINT.md':
|
|
201
|
+
return `# 현재 진행 중인 작업\n\n> 마지막 업데이트: ${today}\n\n---\n\n## 진행 중 (In Progress)\n\n없음\n\n---\n\n## 대기 중 (Pending)\n\n### 우선순위 1: CLAUDE.md 프로젝트 특화 내용 보완\n- [ ] 프로젝트 설명 작성\n- [ ] 프로젝트 특화 규칙 추가\n\n---\n\n## 최근 완료\n\n### ${today}\n- [x] JINHAK AI 개발 표준 v${version} 적용\n\n---\n`;
|
|
202
|
+
case 'DECISIONS.md':
|
|
203
|
+
return `# 아키텍처 의사결정 기록 (ADR)\n\n---\n\n## ADR-001: 기술 스택 선정\n\n### 상태\n승인됨 (${today.substring(0, 7)})\n\n### 컨텍스트\n- ${stack.projectName} 프로젝트의 기술 스택 결정\n\n### 결정\n| 항목 | 선택 |\n|------|------|\n| 프레임워크 | ${fw} |\n| 언어 | ${stack.language} |\n| 패키지 매니저 | ${stack.packageManager} |${stack.stateManagement ? '\n| 상태관리 | ' + stack.stateManagement + ' |' : ''}${stack.database ? '\n| DB | ' + stack.database + ' |' : ''}${stack.orm ? '\n| ORM | ' + stack.orm + ' |' : ''}${stack.buildTool ? '\n| 빌드 | ' + stack.buildTool + ' |' : ''}${stack.testTool ? '\n| 테스트 | ' + stack.testTool + ' |' : ''}\n\n---\n\n## 의사결정 변경 이력\n\n| 날짜 | ADR | 변경 내용 |\n|------|-----|----------|\n| ${today} | ADR-001 | 초기 작성 (CLI 자동 감지) |\n`;
|
|
204
|
+
case 'ARCHITECTURE.md': {
|
|
205
|
+
const lines = [`# ${stack.projectName} 시스템 아키텍처\n\n> ${stack.description || '<!-- TODO: 프로젝트 설명 -->'}\n\n## 기술 스택\n`];
|
|
206
|
+
const front = stack.framework.filter(f => ['React', 'Next.js', 'Vue', 'Nuxt', 'Svelte'].includes(f));
|
|
207
|
+
const back = stack.framework.filter(f => ['Express', 'Fastify', 'NestJS'].includes(f));
|
|
208
|
+
if (front.length) lines.push(`### 프론트엔드\n- **프레임워크**: ${front.join(' + ')}${stack.styling ? '\n- **스타일링**: ' + stack.styling : ''}${stack.stateManagement ? '\n- **상태관리**: ' + stack.stateManagement : ''}\n`);
|
|
209
|
+
if (back.length) lines.push(`### 백엔드\n- **런타임**: Node.js\n- **프레임워크**: ${back.join(' + ')}\n`);
|
|
210
|
+
if (stack.database) lines.push(`### 데이터베이스\n- **DBMS**: ${stack.database}${stack.orm ? '\n- **ORM**: ' + stack.orm : ''}\n`);
|
|
211
|
+
lines.push(`### 빌드 & 개발\n- **언어**: ${stack.language}\n- **패키지 매니저**: ${stack.packageManager}${stack.buildTool ? '\n- **빌드 도구**: ' + stack.buildTool : ''}${stack.testTool ? '\n- **테스트**: ' + stack.testTool : ''}\n\n---\n`);
|
|
212
|
+
return lines.join('\n');
|
|
213
|
+
}
|
|
214
|
+
case 'CONVENTIONS.md': {
|
|
215
|
+
const ext = stack.language === 'TypeScript' ? '.tsx' : '.jsx';
|
|
216
|
+
return `# ${stack.projectName} 코딩 컨벤션\n\nJINHAK 전사 표준 기반.\n\n---\n\n## 네이밍 규칙\n\n| 유형 | 규칙 | 예시 |\n|------|------|------|\n| 컴포넌트 | PascalCase | \`MyComponent${ext}\` |\n| 함수/변수 | camelCase | \`handleSubmit\` |\n| 상수 | UPPER_SNAKE_CASE | \`MAX_RETRY\` |${stack.language === 'TypeScript' ? '\n| 타입 | PascalCase | `UserProfile` |' : ''}\n\n---\n\n## 금지 사항\n\n1. ${stack.language === 'TypeScript' ? '`any` 타입 사용 금지' : '불필요한 타입 강제 변환 금지'}\n2. \`console.log\` 프로덕션 코드 사용 금지\n3. 하드코딩된 URL/포트/비밀키 사용 금지\n4. PUT/PATCH/DELETE HTTP 메서드 사용 금지\n\n---\n`;
|
|
217
|
+
}
|
|
218
|
+
default:
|
|
219
|
+
return `# ${filename.replace('.md', '').replace(/_/g, ' ')}\n\n> 마지막 업데이트: ${today}\n\n---\n`;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
86
223
|
// ─────────────────────────────────────────
|
|
87
224
|
// 메인 커맨드: apply
|
|
88
225
|
// ─────────────────────────────────────────
|
|
@@ -90,6 +227,7 @@ function ensureGitignoreEntries(entries) {
|
|
|
90
227
|
function apply() {
|
|
91
228
|
const version = getLatestVersion();
|
|
92
229
|
const current = getCurrentVersion();
|
|
230
|
+
const stack = detectTechStack();
|
|
93
231
|
|
|
94
232
|
log('');
|
|
95
233
|
log(c.bold('JINHAK AI 개발 표준 적용 도구'));
|
|
@@ -97,6 +235,18 @@ function apply() {
|
|
|
97
235
|
log(`대상 경로: ${c.cyan(TARGET)}`);
|
|
98
236
|
log('');
|
|
99
237
|
|
|
238
|
+
log(c.bold('감지된 기술 스택:'));
|
|
239
|
+
log(` 프로젝트: ${c.cyan(stack.projectName)}`);
|
|
240
|
+
if (stack.description) log(` 설명: ${stack.description}`);
|
|
241
|
+
log(` 프레임워크: ${stack.framework.length > 0 ? c.cyan(stack.framework.join(' + ')) : '-'}`);
|
|
242
|
+
log(` 언어: ${c.cyan(stack.language)} | 패키지 매니저: ${c.cyan(stack.packageManager)}`);
|
|
243
|
+
if (stack.stateManagement) log(` 상태관리: ${stack.stateManagement}`);
|
|
244
|
+
if (stack.styling) log(` 스타일링: ${stack.styling}`);
|
|
245
|
+
if (stack.database) log(` DB: ${stack.database}${stack.orm ? ' + ' + stack.orm : ''}`);
|
|
246
|
+
if (stack.buildTool) log(` 빌드: ${stack.buildTool}`);
|
|
247
|
+
if (stack.testTool) log(` 테스트: ${stack.testTool}`);
|
|
248
|
+
log('');
|
|
249
|
+
|
|
100
250
|
if (current) {
|
|
101
251
|
if (current === version) {
|
|
102
252
|
log(`이미 최신 버전 (v${current})이 적용되어 있습니다.`);
|
|
@@ -144,20 +294,14 @@ function apply() {
|
|
|
144
294
|
created.push('scripts/security-check-hook.cjs');
|
|
145
295
|
}
|
|
146
296
|
|
|
147
|
-
// 6. .ai/ 폴더
|
|
148
|
-
const aiFiles = [
|
|
149
|
-
'SESSION_LOG.md',
|
|
150
|
-
'CURRENT_SPRINT.md',
|
|
151
|
-
'DECISIONS.md',
|
|
152
|
-
'ARCHITECTURE.md',
|
|
153
|
-
'CONVENTIONS.md',
|
|
154
|
-
];
|
|
297
|
+
// 6. .ai/ 폴더 (기술 스택 기반 의미있는 초기 내용)
|
|
298
|
+
const aiFiles = ['SESSION_LOG.md', 'CURRENT_SPRINT.md', 'DECISIONS.md', 'ARCHITECTURE.md', 'CONVENTIONS.md'];
|
|
155
299
|
const aiDir = path.join(TARGET, '.ai');
|
|
156
300
|
fs.mkdirSync(aiDir, { recursive: true });
|
|
157
301
|
for (const f of aiFiles) {
|
|
158
302
|
const dest = path.join(aiDir, f);
|
|
159
303
|
if (!fs.existsSync(dest)) {
|
|
160
|
-
fs.writeFileSync(dest,
|
|
304
|
+
fs.writeFileSync(dest, generateAiContent(f, stack, version), 'utf8');
|
|
161
305
|
created.push(`.ai/${f}`);
|
|
162
306
|
}
|
|
163
307
|
}
|
|
@@ -175,6 +319,33 @@ function apply() {
|
|
|
175
319
|
created.push(`.gitignore (+${gitignoreAdded.length}개 항목)`);
|
|
176
320
|
}
|
|
177
321
|
|
|
322
|
+
// 8. CLAUDE.md (기술 스택 자동 치환)
|
|
323
|
+
const claudeMdDest = path.join(TARGET, 'CLAUDE.md');
|
|
324
|
+
const claudeTemplateSrc = path.join(STANDARD_ROOT, 'templates', 'project-claude.md');
|
|
325
|
+
if (!fs.existsSync(claudeMdDest)) {
|
|
326
|
+
if (fs.existsSync(claudeTemplateSrc)) {
|
|
327
|
+
let template = fs.readFileSync(claudeTemplateSrc, 'utf8');
|
|
328
|
+
template = applyStackToTemplate(template, stack, version);
|
|
329
|
+
fs.writeFileSync(claudeMdDest, template, 'utf8');
|
|
330
|
+
created.push('CLAUDE.md (기술 스택 자동 감지 적용)');
|
|
331
|
+
}
|
|
332
|
+
} else if (current && current !== version) {
|
|
333
|
+
let claudeContent = fs.readFileSync(claudeMdDest, 'utf8');
|
|
334
|
+
const today = new Date().toISOString().split('T')[0];
|
|
335
|
+
claudeContent = claudeContent.replace(/jinhak_standard_version:\s*[\d.]+/, 'jinhak_standard_version: ' + version);
|
|
336
|
+
claudeContent = claudeContent.replace(/applied_date:\s*[\d-]+/, 'applied_date: ' + today);
|
|
337
|
+
fs.writeFileSync(claudeMdDest, claudeContent, 'utf8');
|
|
338
|
+
created.push('CLAUDE.md (버전 ' + current + ' -> ' + version + ' 업데이트)');
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// 9. prompts/
|
|
342
|
+
const promptsSrc = path.join(STANDARD_ROOT, 'prompts');
|
|
343
|
+
const promptsDest = path.join(TARGET, 'prompts');
|
|
344
|
+
if (fs.existsSync(promptsSrc)) {
|
|
345
|
+
const promptCount = copyDir(promptsSrc, promptsDest);
|
|
346
|
+
if (promptCount > 0) created.push('prompts/ (' + promptCount + '개 파일)');
|
|
347
|
+
}
|
|
348
|
+
|
|
178
349
|
// 결과 출력
|
|
179
350
|
log('');
|
|
180
351
|
if (created.length > 0) {
|
|
@@ -188,7 +359,7 @@ function apply() {
|
|
|
188
359
|
|
|
189
360
|
log('');
|
|
190
361
|
log(c.bold('다음 단계:'));
|
|
191
|
-
log(' 1. CLAUDE.md
|
|
362
|
+
log(' 1. CLAUDE.md의 TODO 항목 확인 및 프로젝트에 맞게 수정');
|
|
192
363
|
log(' 2. Claude Code 세션 재시작 (settings.json 반영)');
|
|
193
364
|
log(' 3. /session-start 로 세션 시작');
|
|
194
365
|
log('');
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- JINHAK Standard Metadata - 이 메타 정보는 자동 버전 관리에 사용됩니다. 삭제하지 마세요. -->
|
|
8
|
-
<!-- jinhak_standard_version: 2.
|
|
8
|
+
<!-- jinhak_standard_version: 2.7 -->
|
|
9
9
|
<!-- jinhak_standard_repo: [표준 저장소 URL - https://github.com/JinhakStandard/ai-vibecoding 로 교체] -->
|
|
10
10
|
<!-- applied_date: [YYYY-MM-DD] -->
|
|
11
11
|
|