- CLAUDE.md: 프로젝트 규칙, 기술 스택, 코딩 규칙, 페이즈 로드맵 - .claude/settings.json: 권한, 강제 훅 (매 프롬프트 설계서 규칙 주입) - .claude/skills/: implement-phase, review-phase, scaffold, test-commit, debug - .claude/agents/: electron-architect, voice-pipeline-expert, ui-specialist - docs/design/00-09: 마스터 아키텍처, 서비스 명세(16개), IPC(113채널), DB스키마, UI컴포넌트, 검증리포트, 외부엔진연동, 갭분석, VoiceMode패턴, 디자인시스템, 히스토리팝업 - docs/phases/1-7+3.5: 전체 구현 페이즈 문서 - docs/re-findings/: Speakly RE 노하우 5개 문서
88 lines
3.3 KiB
JSON
88 lines
3.3 KiB
JSON
{
|
|
"permissions": {
|
|
"allow": [
|
|
"Read",
|
|
"Glob",
|
|
"Grep",
|
|
"Bash(npm *)",
|
|
"Bash(npx *)",
|
|
"Bash(node *)",
|
|
"Bash(git *)",
|
|
"Bash(ls *)",
|
|
"Bash(mkdir *)",
|
|
"Bash(cat *)",
|
|
"Bash(which *)",
|
|
"Bash(python *)",
|
|
"Bash(pip *)",
|
|
"Edit(src/**)",
|
|
"Edit(tests/**)",
|
|
"Edit(docs/**)",
|
|
"Edit(*.md)",
|
|
"Edit(*.json)",
|
|
"Edit(*.ts)",
|
|
"Edit(*.tsx)",
|
|
"Edit(*.js)",
|
|
"Edit(*.css)",
|
|
"Edit(*.html)",
|
|
"Write(src/**)",
|
|
"Write(tests/**)",
|
|
"Write(docs/**)",
|
|
"Write(scripts/**)",
|
|
"Write(*.md)",
|
|
"Write(*.json)",
|
|
"Write(*.ts)",
|
|
"Write(*.tsx)"
|
|
],
|
|
"deny": [
|
|
"Bash(rm -rf /)",
|
|
"Bash(git push --force*)",
|
|
"Bash(npm publish*)",
|
|
"Edit(.env*)",
|
|
"Edit(secrets.*)"
|
|
]
|
|
},
|
|
"hooks": {
|
|
"UserPromptSubmit": [
|
|
{
|
|
"matcher": "",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "cat <<'INJECT'\n[D3RO-VOICE 강제 규칙]\n1. 구현 전 반드시 설계서 참조: docs/design/00~03 (아키텍처, 서비스 명세, IPC 타입, DB/UI)\n2. 서비스: 싱글톤 + EventEmitter. 설계서 01의 인터페이스를 그대로 구현\n3. IPC: 설계서 02의 ipc-channels.ts 채널명/타입을 그대로 사용\n4. 에러: 설계서 02의 D3ROError + ErrorCode enum 사용\n5. DB: 설계서 03의 drizzle-orm 스키마를 그대로 사용\n6. UI: 설계서 03의 컴포넌트 Props/상태/IPC 명세를 그대로 따름\n7. 윈도우: 프리로딩 + 2-phase 리사이즈 (설계서 01 WindowManagerService)\n8. 상태머신: RecognitionState + AudioState 분리 (설계서 01 VoiceModeService)\n9. 팝업: Vanilla JS, 설계서 03의 HTML/CSS/애니메이션 스펙 준수\n10. any 타입 절대 금지, console.log 절대 금지\nINJECT"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"PostToolUse": [
|
|
{
|
|
"matcher": "Write|Edit",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "FILE=$(cat /dev/stdin | python -c \"import sys,json; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('file_path',''))\" 2>/dev/null); if echo \"$FILE\" | grep -qE '\\.(ts|tsx)$'; then cd 'D:/workspace/D3ROVoice' && npx tsc --noEmit 2>&1 | head -15 || true; fi"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"matcher": "Write",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "FILE=$(cat /dev/stdin | python -c \"import sys,json; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('file_path',''))\" 2>/dev/null); if echo \"$FILE\" | grep -qE '\\.(ts|tsx)$'; then grep -n 'any' \"$FILE\" 2>/dev/null | grep -v '// eslint-disable' | grep -v 'import' | head -5 && echo '[WARN] any 타입 발견 - 수정 필요' || true; fi"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Write|Edit",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "FILE=$(cat /dev/stdin | python -c \"import sys,json; d=json.load(sys.stdin); print(d.get('tool_input',{}).get('file_path',''))\" 2>/dev/null); if echo \"$FILE\" | grep -qE '\\.env|\\.secret|credentials'; then echo 'BLOCKED: 시크릿 파일 수정 금지' >&2; exit 2; fi; exit 0"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|