Skip to content
Development
Hook

Hooks

What aurakit runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.

From plugin
aurakit
413 skills23 agents33 hooks
Install
$ npx -y skills add smorky850612/Aurakit --agent claude-code

Ships with aurakit. Installing the plugin gets these hooks.

Where it lives

  • hooks/auto-format.jsGitHub
    Read the script
    #!/usr/bin/env node
    /**
     * AuraKit — PostToolUse Auto Formatter
     * Write/Edit 완료 후 자동 코드 포맷
     * Prettier(JS/TS/CSS/JSON/MD) · gofmt(Go) · black(Python) · rustfmt(Rust)
     * Hook: PostToolUse (matcher: Write|Edit)
     */
    'use strict';
    
    const { readInput, fileExists } = require('./lib/common.js');
    const { execSync } = require('child_process');
    const path = require('path');
    
    const input = readInput();
    const toolName = input.tool_name || '';
    const toolInput = input.tool_input || {};
    
    // Write/Edit 툴만 처리
    if (!['Write', 'Edit'].includes(toolName)) process.exit(0);
    
    const filePath = toolInput.file_path || '';
    if (!filePath) process.exit(0);
    
    const ext = path.extname(filePath).toLowerCase();
    
    // ── 도구 실행 헬퍼 ────────────────────────────────────────────────────
    function tryExec(cmd) {
      try {
        execSync(cmd, { timeout: 15000, stdio: 'ignore' });
        return true;
      } catch {
        return false;
      }
    }
    
    // ── Prettier 적용 대상 확장자 ─────────────────────────────────────────
    const PRETTIER_EXTS = new Set(['.js', '.jsx', '.ts', '.tsx', '.css', '.scss', '.json', '.md', '.yaml', '.yml', '.html']);
    
    if (PRETTIER_EXTS.has(ext)) {
      // Prettier 설정 파일 존재 확인 (프로젝트에 설정 없으면 포맷하지 않음)
      const hasPrettier =
        fileExists('.prettierrc') ||
        fileExists('.prettierrc.json') ||
        fileExists('.prettierrc.js') ||
        fileExists('.prettierrc.cjs') ||
        fileExists('.prettierrc.yaml') ||
        fileExists('.prettierrc.yml') ||
        fileExists('prettier.config.js') ||
        fileExists('prettier.config.cjs');
    
      if (hasPrettier) {
        // 로컬 설치 우선, 없으면 npx
        const localPrettier = path.join('node_modules', '.bin', 'prettier');
        if (fileExists(localPrettier)) {
          tryExec(`"${localPrettier}" --write "${filePath}" 2>/dev/null`);
        } else {
          tryExec(`npx --yes --quiet prettier --write "${filePath}" 2>/dev/null`);
        }
      }
      process.exit(0);
    }
    
    // ── Go ────────────────────────────────────────────────────────────────
    if (ext === '.go') {
      tryExec(`gofmt -w "${filePath}"`);
      process.exit(0);
    }
    
    // ── Python ────────────────────────────────────────────────────────────
    if (ext === '.py') {
      // black 우선, 없으면 autopep8
      if (!tryExec(`black "${filePath}" --quiet 2>/dev/null`)) {
        tryExec(`python -m black "${filePath}" --quiet 2>/dev/null`);
      }
      process.exit(0);
    }
    
    // ── Rust ──────────────────────────────────────────────────────────────
    if (ext === '.rs') {
      tryExec(`rustfmt "${filePath}" 2>/dev/null`);
      process.exit(0);
    }
    
    // ── Java / Kotlin ─────────────────────────────────────────────────────
    if (ext === '.java') {
      // google-java-format (있을 때만)
      tryExec(`google-java-format -i "${filePath}" 2>/dev/null`);
      process.exit(0);
    }
    
    if (ext === '.kt' || ext === '.kts') {
      tryExec(`ktlint -F "${filePath}" 2>/dev/null`);
      process.exit(0);
    }
    
    // ── PHP ───────────────────────────────────────────────────────────────
    if (ext === '.php') {
      tryExec(`php-cs-fixer fix "${filePath}" --quiet 2>/dev/null`);
      process.exit(0);
    }
    
    process.exit(0);
    
  • hooks/bash-guard.jsGitHub
    Read the script
    #!/usr/bin/env node
    /**
     * AuraKit — PreToolUse Bash Guard (Node.js 크로스 플랫폼 버전)
     * 위험한 Bash 명령 감지. matcher: Bash
     */
    
    'use strict';
    
    const { readInput, allow, block } = require('./lib/common.js');
    
    const input = readInput();
    const cmd = (input.tool_input || {}).command || '';
    
    if (!cmd) allow();
    
    // ── 파괴적 명령 패턴 ─────────────────────────────────────────────────
    const DANGEROUS = [
      { re: /rm\s+-rf?\s+\/(?:\s|$)/, desc: 'rm -rf /' },
      { re: /git\s+push\s+.*--force\s+(?:origin\s+)?main/, desc: 'force push to main' },
      { re: /git\s+reset\s+--hard\s+HEAD~(?:[2-9]|\d{2,})/, desc: 'git reset --hard HEAD~N (N≥2)' },
      { re: /git\s+clean\s+.*-[a-z]*f[a-z]*/, desc: 'git clean -f (미추적 파일 삭제)' },
      { re: /DROP\s+DATABASE/i, desc: 'DROP DATABASE' },
      { re: /chmod\s+-R\s+777/, desc: 'chmod -R 777' },
      { re: />\s*\/etc\/(passwd|shadow|sudoers)/, desc: '/etc/passwd|shadow 쓰기' },
      { re: /curl.*\|\s*(?:bash|sh)/, desc: 'curl | bash (원격 실행)' },
      { re: /wget.*\|\s*(?:bash|sh)/, desc: 'wget | bash (원격 실행)' },
    ];
    
    const found = DANGEROUS.filter(p => p.re.test(cmd));
    
    if (found.length > 0) {
      block(
        '🔴 AuraKit Bash Guard 차단\n' +
        '   위험한 명령이 감지되었습니다:\n' +
        found.map(f => '   - ' + f.desc).join('\n') + '\n' +
        '   의도한 명령이라면 직접 터미널에서 실행하세요.'
      );
    }
    
    allow();
    
  • hooks/bloat-check.jsGitHub
    Read the script
    #!/usr/bin/env node
    /**
     * AuraKit — PostToolUse Bloat Check (Node.js 크로스 플랫폼 버전)
     * 파일 크기 감시 (250줄 초과 경고). matcher: Write|Edit
     */
    'use strict';
    const fs = require('fs');
    const { readInput, allow } = require('./lib/common.js');
    const input = readInput();
    const filePath = (input.tool_input || {}).file_path || '';
    if (!filePath) allow();
    
    try {
      const content = fs.readFileSync(filePath, 'utf8');
      const lines = content.split('\n').length;
      if (lines > 250) {
        process.stderr.write(
          `⚠️  AuraKit Bloat: ${filePath} (${lines}줄 > 250줄)\n` +
          '   컴포넌트 분할을 권장합니다. /aura clean: 으로 정리 가능.\n'
        );
      }
    } catch {}
    allow();
    
  • hooks/bloat-check.shGitHub
    Read the script
    #!/bin/bash
    # AuraKit - 파일 크기(줄 수) 모니터링 및 블로트 경고
    # Hook: PostToolUse (matcher: Write|Edit)
    # stdin: JSON (tool_result + tool_input)
    # exit 0 (경고만, 블로킹 아님)
    
    set -euo pipefail
    
    # ── 설정 ───────────────────────────────────────────────────────────────
    WARN_LINES=250      # 경고 임계값
    CRITICAL_LINES=400  # 심각 경고 임계값
    
    # ── JSON 입력 읽기 ─────────────────────────────────────────────────────
    INPUT=$(cat)
    
    # file_path 추출
    if command -v jq &>/dev/null; then
      FILE_PATH=$(echo "${INPUT}" | jq -r '.tool_input.file_path // ""' 2>/dev/null || echo "")
    else
      FILE_PATH=$(echo "${INPUT}" | grep -o '"file_path":"[^"]*"' | sed 's/"file_path":"//;s/"$//' || echo "")
    fi
    
    # 파일 경로가 없거나 존재하지 않으면 스킵
    if [ -z "${FILE_PATH}" ] || [ ! -f "${FILE_PATH}" ]; then
      exit 0
    fi
    
    # ── 검사 대상 파일 필터링 ─────────────────────────────────────────────
    EXTENSION="${FILE_PATH##*.}"
    
    # 소스 코드 파일만 검사
    case "${EXTENSION}" in
      ts|tsx|js|jsx|py|go|rs|java|kt|swift|rb|php|vue|svelte|astro)
        # 검사 대상
        ;;
      *)
        # 설정 파일, 마크다운, JSON 등은 스킵
        exit 0
        ;;
    esac
    
    # 생성된 파일 / 노드 모듈 제외
    if echo "${FILE_PATH}" | grep -qE "node_modules|\.next|dist|build|__pycache__|\.pyc$|vendor"; then
      exit 0
    fi
    
    # ── 줄 수 카운트 ──────────────────────────────────────────────────────
    if command -v wc &>/dev/null; then
      LINE_COUNT=$(wc -l < "${FILE_PATH}" 2>/dev/null || echo "0")
    else
      LINE_COUNT=$(grep -c "" "${FILE_PATH}" 2>/dev/null || echo "0")
    fi
    
    # ── 결과 출력 ─────────────────────────────────────────────────────────
    FILE_BASENAME=$(basename "${FILE_PATH}")
    
    if [ "${LINE_COUNT}" -ge "${CRITICAL_LINES}" ] 2>/dev/null; then
      echo ""
      echo "🚨 AuraKit Bloat Warning [CRITICAL]: ${FILE_PATH}"
      echo "   현재 줄 수: ${LINE_COUNT}줄 (임계값: ${WARN_LINES}줄)"
      echo ""
      echo "   분할 권장:"
      case "${EXTENSION}" in
        tsx|jsx)
          echo "   → 서브 컴포넌트로 분리 ([Name]Item.tsx, [Name]List.tsx)"
          echo "   → 커스텀 훅 추출 (use[Name].ts)"
          echo "   → 타입 분리 ([name].types.ts)"
          ;;
        ts|js)
          if echo "${FILE_PATH}" | grep -qi "route\|controller\|handler"; then
            echo "   → 서비스 레이어 추출 ([name].service.ts)"
            echo "   → 리포지토리 레이어 추출 ([name].repository.ts)"
            echo "   → 스키마 분리 ([name].schema.ts)"
          else
            echo "   → 도메인별 유틸리티 분리 ([domain].utils.ts)"
            echo "   → 상수 분리 ([name].constants.ts)"
          fi
          ;;
        py)
          echo "   → 모듈로 분리 (services/, repositories/, schemas/)"
          echo "   → 믹스인 추출"
          ;;
      esac
      echo ""
      echo "   /aura 분할 리팩토링 해줘 — 로 자동 분할 요청 가능"
    
    elif [ "${LINE_COUNT}" -ge "${WARN_LINES}" ] 2>/dev/null; then
      echo ""
      echo "⚠️  AuraKit Bloat Warning: ${FILE_PATH}"
      echo "   현재 줄 수: ${LINE_COUNT}줄 (권장 최대: ${WARN_LINES}줄)"
      echo "   250줄 이내로 분할을 권장합니다."
      echo "   /aura ${FILE_BASENAME} 분할해줘 — 로 자동 분할 가능"
    fi
    
    # 경고는 출력하되 항상 exit 0 (블로킹 없음)
    exit 0
    
  • hooks/build-progress.jsGitHub
    Read the script
    #!/usr/bin/env node
    /**
     * AuraKit — PostToolUse Build Progress (Node.js 크로스 플랫폼 버전)
     * 파일 완료 시 스냅샷 업데이트 + 진행률 표시. matcher: Write|Edit
     */
    'use strict';
    const fs = require('fs');
    const path = require('path');
    const { readInput, allow, AURA_DIR, SNAPSHOTS_DIR } = require('./lib/common.js');
    
    const input = readInput();
    const filePath = (input.tool_input || {}).file_path || '';
    if (!filePath) allow();
    
    const snapshotFile = path.join(SNAPSHOTS_DIR, 'current.md');
    try {
      if (fs.existsSync(snapshotFile)) {
        let snap = fs.readFileSync(snapshotFile, 'utf8');
        // Remaining 섹션에서 완료된 파일 체크
        const baseName = path.basename(filePath);
        const escapedBase = baseName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        snap = snap.replace(new RegExp(`^- \\[ \\] .*${escapedBase}.*$`, 'm'), m => m.replace('[ ]', '[x]'));
        fs.writeFileSync(snapshotFile, snap, 'utf8');
      }
    } catch {}
    
    allow();
    
  • hooks/build-verify.jsGitHub
    Read the script
    #!/usr/bin/env node
    /**
     * AuraKit — PostToolUse Build Verify (Node.js 크로스 플랫폼 버전)
     * TypeScript/Python 문법 검사 + Convention Check (V1). matcher: Write|Edit
     */
    'use strict';
    const path = require('path');
    const fs = require('fs');
    const { execSync } = require('child_process');
    const { readInput, allow } = require('./lib/common.js');
    const input = readInput();
    const filePath = (input.tool_input || {}).file_path || '';
    if (!filePath) allow();
    
    // TypeScript 파일 검사 — tsconfig.json 없으면 스킵 (npx 기동비용 방지)
    if (/\.(ts|tsx)$/.test(filePath) && fs.existsSync('tsconfig.json')) {
      try {
        // 로컬 tsc 우선 사용 (npx 오버헤드 ~1s 제거)
        const localTsc = path.join('node_modules', '.bin', 'tsc');
        const tscCmd = fs.existsSync(localTsc) ? `"${localTsc}"` : 'npx tsc';
        execSync(`${tscCmd} --noEmit --skipLibCheck 2>&1`, { timeout: 15000, stdio: 'pipe' });
      } catch (e) {
        const out = e.stdout ? e.stdout.toString() : '';
        if (out && out.includes('error TS')) {
          process.stderr.write('⚠️  AuraKit V1: TypeScript 오류\n' + out.substring(0, 500) + '\n');
        }
      }
    }
    
    // Python 파일 검사
    if (/\.py$/.test(filePath)) {
      try {
        const py = process.platform === 'win32' ? 'python' : 'python3';
        execSync(`${py} -m py_compile "${filePath}" 2>&1`, { timeout: 10000, stdio: 'pipe' });
      } catch (e) {
        const out = e.stdout ? e.stdout.toString() : (e.stderr ? e.stderr.toString() : '');
        if (out) process.stderr.write('⚠️  AuraKit V1: Python 오류\n' + out.substring(0, 300) + '\n');
      }
    }
    
    // Convention Check (CONV-001~005) — 경고만, 차단 아님 (pre-commit에서 차단)
    if (/\.(ts|tsx|js|jsx|py|go)$/.test(filePath)) {
      try {
        const convScript = path.join(__dirname, '..', 'scripts', 'convention-check.sh');
        if (fs.existsSync(convScript)) {
          execSync(`bash "${convScript}" "${filePath}" 2>&1`, { timeout: 10000, stdio: 'pipe' });
        }
      } catch (e) {
        const out = e.stdout ? e.stdout.toString() : '';
        if (out && out.includes('CONV')) {
          process.stderr.write('⚠️  AuraKit V1 Convention:\n' + out.substring(0, 400) + '\n');
        }
      }
    }
    
    allow();
    
  • hooks/build-verify.shGitHub
  • hooks/cache-guard.jsGitHub
  • hooks/governance-capture.jsGitHub
  • hooks/injection-guard.jsGitHub
  • hooks/instinct-auto-save.jsGitHub
  • hooks/korean-command.jsGitHub
  • hooks/migration-guard.jsGitHub
  • hooks/output-filter.jsGitHub
  • hooks/post-compact-restore.jsGitHub
  • hooks/post-compact-restore.shGitHub
  • hooks/post-tool-failure.jsGitHub
  • hooks/pre-compact-snapshot.jsGitHub
  • hooks/pre-compact-snapshot.shGitHub
  • hooks/pre-session.jsGitHub
  • hooks/pre-session.shGitHub
  • hooks/security-scan.jsGitHub
  • hooks/security-scan.shGitHub
  • hooks/session-stop.jsGitHub
  • hooks/subagent-start.jsGitHub
  • hooks/subagent-stop.jsGitHub
  • hooks/task-completed.jsGitHub
  • hooks/teammate-idle.jsGitHub
  • hooks/token-stats-inject.jsGitHub
  • hooks/token-stats-inject.pyGitHub
  • hooks/token-tracker.jsGitHub
  • hooks/token-tracker.pyGitHub
  • hooks/uninstall.jsGitHub

All 33 scripts are listed above. The source is inlined for 6 of them, starting with whatever hooks.json actually runs. See all of them in the repo.

Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.

Ships withaurakit

One command. Full stack. Zero compromise. — All-in-one Claude Code skill with 33 modes, 6-layer security, 23 hooks, and 75% token savings. Works on Codex, Cursor, Manus, Windsurf.

Get the whole plugin
Stats
41
Stars
7
Forks
Maintained
Maintenance
JavaScript
Language
MIT
License
5mo ago
Last commit
6mo ago
Created

Repo: smorky850612/Aurakit