Files
ewoooc/.claude/hooks/commit-quality.js
ogt cac7303e46 feat(devteam): 引進 my-claude-devteam 架構 V11.0
- CLAUDE.md 升版至 V11.0:整合 P7/P9/P10 工作模式、12 人專家團隊、
  委派鐵律、三條紅線(保留狙擊手模式精神)
- .claude/hooks/:新增 8 個 Hook(momo-prod-guard / commit-quality /
  large-file-warner / mcp-health / audit-log / suggest-compact /
  cost-tracker / session-summary)
- .claude/agents/:新增 11 個 Agent 定義(critic / debugger / db-expert /
  vuln-verifier / fullstack-engineer / planner / refactor-specialist /
  migration-engineer / onboarder / tool-expert / web-researcher)
- .claude/settings.json:啟用 bypassPermissions + Hook 自動政策架構
- .gitignore:加入 settings.local.json 防止 Secret 意外 commit

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 22:13:57 +08:00

60 lines
2.2 KiB
JavaScript

/**
* commit-quality.js — PreToolUse Hook
* 阻擋 debugger 語句 + 硬編碼 Secret 進入 commit。
* 已針對 momo 環境加入 Telegram/Gemini/Gitea/Anthropic pattern。
*/
const { spawnSync } = require('child_process');
let d = '';
process.stdin.on('data', c => d += c);
process.stdin.on('end', () => {
try {
const i = JSON.parse(d);
const cmd = i.tool_input?.command || '';
if (!/git commit/.test(cmd) || /--amend/.test(cmd)) { process.stdout.write(d); return; }
const r = spawnSync('git', ['diff', '--cached', '--name-only', '--diff-filter=ACMR'], { encoding: 'utf8' });
const files = (r.stdout || '').trim().split('\n').filter(Boolean);
let blocked = false;
for (const f of files) {
if (!/\.(js|jsx|ts|tsx|py|sh|json|yaml|yml)$/.test(f)) continue;
const cr = spawnSync('git', ['show', ':' + f], { encoding: 'utf8' });
const c = cr.stdout || '';
if (/\.(js|jsx|ts|tsx)$/.test(f) && /\bdebugger\b/.test(c)) {
process.stderr.write(`[commit-quality] ERROR: debugger statement in ${f}\n`);
blocked = true;
}
const secrets = [
// 通用 API Keys
[/sk-[a-zA-Z0-9]{20,}/, 'OpenAI API Key'],
[/ghp_[a-zA-Z0-9]{36}/, 'GitHub PAT'],
[/AKIA[A-Z0-9]{16}/, 'AWS Access Key'],
[/AIza[a-zA-Z0-9_-]{35}/, 'Google API Key'],
// momo 專屬
[/\d{8,12}:[A-Za-z0-9_-]{35}/, 'Telegram Bot Token'],
[/TELEGRAM[_\s]*(?:BOT[_\s]*)?TOKEN\s*=\s*["']?[^\s"']{20,}/, 'Telegram Token 環境變數'],
[/GEMINI_API_KEY\s*=\s*["']?[A-Za-z0-9_-]{20,}/, 'Gemini API Key'],
[/sk-ant-api[0-9a-zA-Z_-]{20,}/, 'Anthropic API Key'],
[/glpat-[a-zA-Z0-9_-]{20}/, 'Gitea/GitLab PAT'],
[/GITEA[_\s]*TOKEN\s*=\s*["']?[^\s"']{20,}/, 'Gitea Token 環境變數'],
];
for (const [pattern, label] of secrets) {
if (pattern.test(c)) {
process.stderr.write(`[commit-quality] ERROR: 偵測到 ${label} in ${f}\n`);
blocked = true;
}
}
}
if (blocked) {
process.stderr.write('[commit-quality] Commit 已阻擋。請移除上述敏感資訊後重試。\n');
process.exit(2);
}
} catch (e) {}
process.stdout.write(d);
});