dw-kit 1.1.0 → 1.2.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.
@@ -6,17 +6,15 @@
6
6
  INPUT=$(cat)
7
7
 
8
8
  # Extract file path từ tool result
9
- FILE_PATH=$(echo "$INPUT" | python3 -c "
10
- import sys, json
11
- try:
12
- data = json.load(sys.stdin)
13
- # PostToolUse result có thể chứa file path theo nhiều cách
14
- for key in ['file_path', 'path', 'filePath']:
15
- if key in data:
16
- print(data[key])
17
- break
18
- except:
19
- pass
9
+ FILE_PATH=$(echo "$INPUT" | node -e "
10
+ let d='';
11
+ process.stdin.on('data',c=>d+=c).on('end',()=>{
12
+ try{
13
+ const data=JSON.parse(d);
14
+ const p=data.file_path||data.path||data.filePath||(data.tool_input&&(data.tool_input.file_path||data.tool_input.path))||'';
15
+ process.stdout.write(p);
16
+ }catch(e){}
17
+ });
20
18
  " 2>/dev/null || true)
21
19
 
22
20
  [ -z "$FILE_PATH" ] && exit 0
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env bash
2
+ # .claude/hooks/privacy-block.sh — dw-kit v1.2
3
+ # Block agent reads vào sensitive files (credentials, secrets, private keys).
4
+ # Học từ claudekit privacy-block pattern.
5
+ #
6
+ # PreToolUse hook cho: Read
7
+ # exit 0 = allow, exit 2 = block
8
+
9
+ INPUT=$(cat)
10
+
11
+ TOOL_NAME=$(echo "$INPUT" | node -e "
12
+ let d='';
13
+ process.stdin.on('data',c=>d+=c).on('end',()=>{
14
+ try{ process.stdout.write(JSON.parse(d).tool_name||''); }catch(e){}
15
+ });
16
+ " 2>/dev/null || true)
17
+
18
+ [ "$TOOL_NAME" != "Read" ] && exit 0
19
+
20
+ FILE_PATH=$(echo "$INPUT" | node -e "
21
+ let d='';
22
+ process.stdin.on('data',c=>d+=c).on('end',()=>{
23
+ try{ const p=JSON.parse(d); process.stdout.write((p.tool_input&&p.tool_input.file_path)||''); }catch(e){}
24
+ });
25
+ " 2>/dev/null || true)
26
+
27
+ [ -z "$FILE_PATH" ] && exit 0
28
+
29
+ BASENAME=$(basename "$FILE_PATH")
30
+ NORM=$(echo "$FILE_PATH" | tr '\\' '/')
31
+
32
+ # ── Allow-list: safe files dù tên giống sensitive ─────────────────────────────
33
+ ALLOWED_PATTERNS=(
34
+ ".env.example"
35
+ ".env.sample"
36
+ ".env.template"
37
+ ".env.test"
38
+ ".env.local.example"
39
+ "*.example"
40
+ "*.sample"
41
+ )
42
+
43
+ for allow in "${ALLOWED_PATTERNS[@]}"; do
44
+ if [[ "$BASENAME" == $allow ]]; then
45
+ exit 0
46
+ fi
47
+ done
48
+
49
+ # ── Block patterns ──────────────────────────────────────────────────────────────
50
+ BLOCKED=false
51
+ REASON=""
52
+
53
+ # .env files (nhưng không phải .env.example đã allow ở trên)
54
+ if [[ "$BASENAME" == ".env" ]] || [[ "$BASENAME" == .env.* ]]; then
55
+ BLOCKED=true
56
+ REASON="Environment file (có thể chứa secrets/API keys)"
57
+ fi
58
+
59
+ # Private key files
60
+ if [[ "$BASENAME" == *.pem ]] || [[ "$BASENAME" == *.key ]] || \
61
+ [[ "$BASENAME" == *.p12 ]] || [[ "$BASENAME" == *.pfx ]] || \
62
+ [[ "$BASENAME" == *.jks ]]; then
63
+ BLOCKED=true
64
+ REASON="Private key / certificate file"
65
+ fi
66
+
67
+ # Credentials & secrets files
68
+ if echo "$BASENAME" | grep -qiE '^(credentials|secrets?|secret[-_]key|api[-_]key|auth[-_]token|access[-_]token)(\.[a-z]+)?$'; then
69
+ BLOCKED=true
70
+ REASON="Credentials / secrets file"
71
+ fi
72
+
73
+ # Known credential file patterns
74
+ if [[ "$BASENAME" == "*.credentials.json" ]] || \
75
+ echo "$NORM" | grep -qiE '/(credentials|secrets)/'; then
76
+ BLOCKED=true
77
+ REASON="Credentials directory hoặc file"
78
+ fi
79
+
80
+ # Service account / GCP keys
81
+ if echo "$BASENAME" | grep -qiE 'service[-_]account.*\.json$|gcp.*key.*\.json$|firebase.*key.*\.json$'; then
82
+ BLOCKED=true
83
+ REASON="Service account / cloud credentials"
84
+ fi
85
+
86
+ if [ "$BLOCKED" = true ]; then
87
+ echo "🔒 privacy-block: Blocked sensitive file read" >&2
88
+ echo " File: $FILE_PATH" >&2
89
+ echo " Lý do: $REASON" >&2
90
+ echo " Nếu thực sự cần đọc file này, hãy confirm rõ ràng trong prompt." >&2
91
+ exit 2
92
+ fi
93
+
94
+ exit 0
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env bash
2
+ # .claude/hooks/scout-block.sh — dw-kit v1.2
3
+ # Block agent reads vào heavy/irrelevant directories để tăng performance.
4
+ # Học từ claudekit scout-block pattern.
5
+ #
6
+ # PreToolUse hook cho: Read, Glob
7
+ # exit 0 = allow, exit 2 = block
8
+
9
+ INPUT=$(cat)
10
+
11
+ # Extract tool name và file path từ JSON input
12
+ TOOL_NAME=$(echo "$INPUT" | node -e "
13
+ let d='';
14
+ process.stdin.on('data',c=>d+=c).on('end',()=>{
15
+ try{ process.stdout.write(JSON.parse(d).tool_name||''); }catch(e){}
16
+ });
17
+ " 2>/dev/null || true)
18
+
19
+ # Extract path tùy theo tool
20
+ if [ "$TOOL_NAME" = "Read" ]; then
21
+ TARGET=$(echo "$INPUT" | node -e "
22
+ let d='';
23
+ process.stdin.on('data',c=>d+=c).on('end',()=>{
24
+ try{ const p=JSON.parse(d); process.stdout.write((p.tool_input&&p.tool_input.file_path)||''); }catch(e){}
25
+ });
26
+ " 2>/dev/null || true)
27
+ elif [ "$TOOL_NAME" = "Glob" ]; then
28
+ TARGET=$(echo "$INPUT" | node -e "
29
+ let d='';
30
+ process.stdin.on('data',c=>d+=c).on('end',()=>{
31
+ try{ const p=JSON.parse(d); const ti=p.tool_input||{}; process.stdout.write(ti.path||ti.pattern||''); }catch(e){}
32
+ });
33
+ " 2>/dev/null || true)
34
+ else
35
+ exit 0
36
+ fi
37
+
38
+ [ -z "$TARGET" ] && exit 0
39
+
40
+ # Normalize: lowercase, forward slashes
41
+ NORM=$(echo "$TARGET" | tr '\\' '/')
42
+
43
+ # ── Danh sách heavy/irrelevant directories ─────────────────────────────────────
44
+ BLOCKED_PATTERNS=(
45
+ "node_modules/"
46
+ "/node_modules"
47
+ "dist/"
48
+ "/dist/"
49
+ "build/"
50
+ "/build/"
51
+ ".git/"
52
+ "/__pycache__/"
53
+ "/.pytest_cache/"
54
+ "/.next/"
55
+ "/.nuxt/"
56
+ "/vendor/"
57
+ "/coverage/"
58
+ "/.tmp/"
59
+ "/tmp/"
60
+ "/.cache/"
61
+ )
62
+
63
+ for pattern in "${BLOCKED_PATTERNS[@]}"; do
64
+ if echo "$NORM" | grep -q "$pattern"; then
65
+ echo "⚡ scout-block: Skipped heavy directory [${TOOL_NAME}] $(basename "$TARGET")/" >&2
66
+ echo " Path: $TARGET" >&2
67
+ echo " Dùng path cụ thể hơn nếu thực sự cần đọc file này." >&2
68
+ exit 2
69
+ fi
70
+ done
71
+
72
+ # Block pattern: kết thúc bằng thư mục blocked (không có trailing slash)
73
+ BLOCKED_EXACT=("node_modules" ".git" "dist" "build" "__pycache__" ".next" ".nuxt" "vendor" "coverage")
74
+ BASENAME=$(basename "$NORM")
75
+ for exact in "${BLOCKED_EXACT[@]}"; do
76
+ if [ "$BASENAME" = "$exact" ]; then
77
+ echo "⚡ scout-block: Skipped heavy directory [${TOOL_NAME}] $BASENAME/" >&2
78
+ exit 2
79
+ fi
80
+ done
81
+
82
+ exit 0
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env bash
2
+ # .claude/hooks/session-init.sh — dw-kit v1.2
3
+ # Inject active task context vào đầu session, giải quyết "session amnesia".
4
+ # Chỉ chạy một lần mỗi session (track bằng session_id).
5
+ #
6
+ # UserPromptSubmit hook
7
+ # Stdout output → được inject vào context của user prompt
8
+ # exit 0 = allow
9
+
10
+ INPUT=$(cat)
11
+
12
+ SESSION_ID=$(echo "$INPUT" | node -e "
13
+ let d='';
14
+ process.stdin.on('data',c=>d+=c).on('end',()=>{
15
+ try{ process.stdout.write(JSON.parse(d).session_id||''); }catch(e){}
16
+ });
17
+ " 2>/dev/null || true)
18
+
19
+ # Tier 2: pure-bash grep fallback — works without node (e.g. node absent or CRLF-corrupt shebang)
20
+ if [ -z "$SESSION_ID" ]; then
21
+ SESSION_ID=$(echo "$INPUT" | grep -o '"session_id":"[^"]*"' | cut -d'"' -f4 2>/dev/null || true)
22
+ fi
23
+
24
+ # Tier 3: project-scoped + hour-scoped stable ID
25
+ # cksum is POSIX — available on Linux, macOS, and Git Bash on Windows.
26
+ # Ensures marker is always created so re-injection is suppressed even when tiers 1+2 fail.
27
+ if [ -z "$SESSION_ID" ]; then
28
+ _dir_hash=$(pwd | cksum | cut -d' ' -f1)
29
+ SESSION_ID="fallback-${_dir_hash}-$(date +%Y%m%d-%H)"
30
+ fi
31
+
32
+ # ── Track session: chỉ chạy một lần mỗi session ───────────────────────────────
33
+ SESSION_MARKER="/tmp/dw-session-${SESSION_ID}"
34
+ if [ -f "$SESSION_MARKER" ]; then
35
+ exit 0
36
+ fi
37
+ touch "$SESSION_MARKER" 2>/dev/null || true
38
+
39
+ # ── Scan .dw/tasks/ tìm tasks In Progress ─────────────────────────────────────
40
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
41
+ TASKS_DIR="$PROJECT_DIR/.dw/tasks"
42
+
43
+ [ ! -d "$TASKS_DIR" ] && exit 0
44
+
45
+ ACTIVE_TASKS=()
46
+ ACTIVE_SUMMARIES=()
47
+
48
+ while IFS= read -r progress_file; do
49
+ if grep -q "Trạng thái: In Progress" "$progress_file" 2>/dev/null; then
50
+ task_name=$(basename "$(dirname "$progress_file")")
51
+
52
+ # Extract current subtask (dòng "In Progress" trong table)
53
+ current_st=$(grep -m1 "In Progress" "$progress_file" 2>/dev/null \
54
+ | grep -oP '\| ST-\d+ \| [^|]+' | sed 's/|//g' | xargs 2>/dev/null || echo "")
55
+
56
+ # Extract last handoff note nếu có
57
+ last_handoff=$(awk '/## Handoff Notes/{found=1} found{print}' "$progress_file" 2>/dev/null \
58
+ | grep -m1 "Bước tiếp theo:" | sed 's/.*Bước tiếp theo://' | xargs 2>/dev/null || echo "")
59
+
60
+ ACTIVE_TASKS+=("$task_name")
61
+ summary="$task_name"
62
+ [ -n "$current_st" ] && summary="$summary — $current_st"
63
+ [ -n "$last_handoff" ] && summary="$summary | Next: $last_handoff"
64
+ ACTIVE_SUMMARIES+=("$summary")
65
+ fi
66
+ done < <(find "$TASKS_DIR" -name "*-progress.md" 2>/dev/null)
67
+
68
+ [ ${#ACTIVE_TASKS[@]} -eq 0 ] && exit 0
69
+
70
+ # ── Output context vào stdout (injected vào conversation) ─────────────────────
71
+ echo ""
72
+ echo "---"
73
+ echo "[dw-kit session-init] Task đang in-progress:"
74
+ for summary in "${ACTIVE_SUMMARIES[@]}"; do
75
+ echo " • $summary"
76
+ done
77
+ if [ ${#ACTIVE_TASKS[@]} -eq 1 ]; then
78
+ echo "Context: .dw/tasks/${ACTIVE_TASKS[0]}/"
79
+ else
80
+ echo "Nhiều tasks đang active — hỏi user task nào cần tiếp tục."
81
+ fi
82
+ echo "---"
83
+ echo ""
84
+
85
+ exit 0
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env bash
2
+ # Stop hook: warn nếu có uncommitted changes hoặc task in-progress chưa update
3
+ # Output ra stderr để hiện thị cho user, exit 0 để không block
4
+
5
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
6
+ WARNINGS=()
7
+
8
+ # Check uncommitted changes
9
+ if git -C "$PROJECT_DIR" diff --quiet && git -C "$PROJECT_DIR" diff --cached --quiet; then
10
+ : # clean
11
+ else
12
+ CHANGED=$(git -C "$PROJECT_DIR" diff --stat --cached && git -C "$PROJECT_DIR" diff --stat)
13
+ WARNINGS+=("Uncommitted changes:"$'\n'"$CHANGED")
14
+ fi
15
+
16
+ # Check in-progress tasks
17
+ TASKS_DIR="$PROJECT_DIR/.dw/tasks"
18
+ if [ -d "$TASKS_DIR" ]; then
19
+ while IFS= read -r progress_file; do
20
+ if grep -q "Trạng thái: In Progress" "$progress_file" 2>/dev/null; then
21
+ task_name=$(basename "$(dirname "$progress_file")")
22
+ WARNINGS+=("Task in-progress chưa được update: $task_name")
23
+ fi
24
+ done < <(find "$TASKS_DIR" -name "*-progress.md" 2>/dev/null)
25
+ fi
26
+
27
+ # Print warnings
28
+ if [ ${#WARNINGS[@]} -gt 0 ]; then
29
+ echo "--- dw stop-check ---" >&2
30
+ for w in "${WARNINGS[@]}"; do
31
+ printf "⚠ %b\n" "$w" >&2
32
+ done
33
+ echo "---------------------" >&2
34
+ fi
35
+
36
+ exit 0
@@ -0,0 +1,100 @@
1
+ <!-- dw-kit | core: 1.2 -->
2
+ # dw Workflow
3
+
4
+ Config: `.dw/config/dw.config.yml`
5
+ Full methodology: `.dw/core/WORKFLOW.md` · `.dw/core/THINKING.md` · `.dw/core/QUALITY.md` · `.dw/core/ROLES.md`
6
+
7
+ ---
8
+
9
+ ## Override
10
+
11
+ If the prompt contains `--no-dw`: ignore all dw instructions, work as plain Claude Code. Applies only to that request.
12
+
13
+ ---
14
+
15
+ ## Depth Routing
16
+
17
+ Read `workflow.default_depth` from config. Assess per task based on facts (file count, API changes, git blame) — not assumptions:
18
+
19
+ | Scope | Depth | Approach |
20
+ |-------|-------|----------|
21
+ | ≤2 files, hotfix, familiar module | quick | Understand → Execute → Close |
22
+ | 3–5 files, new module | standard | Full 6-phase |
23
+ | 6+ files, API/DB/security changes | thorough | Full + arch-review + test-plan |
24
+
25
+ When unsure → default to `standard`.
26
+
27
+ ---
28
+
29
+ ## Session Start
30
+
31
+ 1. Read `.dw/config/dw.config.yml` — depth, roles, quality commands
32
+ 2. Check `.dw/tasks/` for active tasks; if one is in progress, resume from its `[task]-progress.md`
33
+
34
+ > `session-init` hook auto-injects active task context — no manual action needed.
35
+
36
+ ---
37
+
38
+ ## Task Docs
39
+
40
+ For tasks spanning 3+ files, research → plan → approve → execute gives better outcomes.
41
+
42
+ ```
43
+ .dw/tasks/[task-name]/
44
+ ├── [name]-context.md # Research findings
45
+ ├── [name]-plan.md # Implementation plan
46
+ └── [name]-progress.md # Progress + handoff notes
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Commit Format
52
+
53
+ ```
54
+ <type>(<scope>): <description ≤72 chars>
55
+ ```
56
+
57
+ Types: `feat` `fix` `refactor` `test` `docs` `chore` `style` `perf`
58
+
59
+ ---
60
+
61
+ ## Hooks (v1.2)
62
+
63
+ Auto-run — no user action needed:
64
+
65
+ | Hook | Trigger | Effect |
66
+ |------|---------|--------|
67
+ | `session-init` | Session start | Inject active task context |
68
+ | `scout-block` | Read/Glob | Block node_modules/, dist/, .git/ etc. |
69
+ | `privacy-block` | Read | Block .env*, *.pem, credentials* |
70
+ | `pre-commit-gate` | Bash (git commit) | Quality check + sensitive data scan |
71
+ | `safety-guard` | Bash | Block destructive commands |
72
+ | `post-write` | Write/Edit | Lint reminder |
73
+ | `stop-check` | Stop | Warn on uncommitted changes + in-progress tasks |
74
+
75
+ ---
76
+
77
+ ## Agent Reports (v1.2)
78
+
79
+ For multi-phase tasks (standard/thorough), create reports for audit trail:
80
+
81
+ ```
82
+ .dw/tasks/[task-name]/reports/[YYMMDD-HHMM]-from-[role]-to-[role]-[desc].md
83
+ ```
84
+
85
+ Status: `DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT`
86
+ Template: `.claude/templates/agent-report.md` · Guide: `.dw/core/AGENTS.md`
87
+
88
+ ---
89
+
90
+ ## Config Local Override (v1.2)
91
+
92
+ `.dw/config/dw.config.local.yml` (gitignored) for machine-specific settings:
93
+
94
+ ```yaml
95
+ claude:
96
+ models:
97
+ plan: "claude-opus-4-6"
98
+ quality:
99
+ test_command: "npm test"
100
+ ```
@@ -0,0 +1,53 @@
1
+ <!-- dw-kit | core: 1.2 -->
2
+ # dw Skills
3
+
4
+ Invoke via Claude Code slash commands. Availability governed by config flags and `workflow.default_depth`.
5
+
6
+ ## Core Workflow
7
+
8
+ | Skill | Description | Depth |
9
+ |-------|-------------|-------|
10
+ | `/dw-flow [task]` | Full workflow shortcut | all |
11
+ | `/dw-task-init [name]` | Init task docs | all |
12
+ | `/dw-research [name]` | Survey codebase | all |
13
+ | `/dw-plan [name]` | Design plan (waits for approval) | standard+ |
14
+ | `/dw-execute [name]` | Implement per plan (TDD) | all |
15
+ | `/dw-commit [msg]` | Smart commit + quality gates | all |
16
+ | `/dw-handoff` | Session handoff | all |
17
+
18
+ ## Dev
19
+
20
+ | Skill | Description |
21
+ |-------|-------------|
22
+ | `/dw-debug [issue]` | Investigate → diagnose → fix |
23
+ | `/dw-review` | Code review with checklist |
24
+ | `/dw-thinking [question]` | Apply thinking framework |
25
+ | `/dw-prompt [desc]` | Build structured prompt |
26
+ | `/dw-docs-update` | Update living docs |
27
+
28
+ ## Role-Specific
29
+
30
+ | Skill | Role | Description |
31
+ |-------|------|-------------|
32
+ | `/dw-requirements` | BA | Requirements + user stories |
33
+ | `/dw-test-plan` | QC | Test plan + regression |
34
+ | `/dw-arch-review` | TechLead | Architecture review |
35
+ | `/dw-dashboard` | PM | Metrics report |
36
+ | `/dw-sprint-review` | All | Retrospective |
37
+ | `/dw-estimate [name]` | if enabled | Effort estimation |
38
+ | `/dw-log-work [name]` | if enabled | Log actual effort |
39
+
40
+ ## Setup & Maintenance
41
+
42
+ | Skill | Description |
43
+ |-------|-------------|
44
+ | `/dw-onboard` | Onboard dw to existing project (breadth-first scan) |
45
+ | `/dw-retroactive [name]` | Document existing feature (depth-first) |
46
+ | `/dw-config-init` | Initialize new config |
47
+ | `/dw-config-validate` | Validate config file |
48
+ | `/dw-upgrade` | Upgrade toolkit |
49
+ | `/dw-rollback [name]` | Rollback task docs |
50
+ | `/dw-archive [name]` | Archive completed task |
51
+ | `/dw-kit-report [desc]` | Submit feedback/bug to GitHub |
52
+
53
+ > **Maintainer-only** (TechLead, dw-kit repo): `/dw-kit-evolve [issue#]` · `/dw-kit-audit [days]`
@@ -1,71 +1,101 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Read(*)",
5
- "Grep(*)",
6
- "Glob(*)",
7
- "Bash(git log *)",
8
- "Bash(git diff *)",
9
- "Bash(git show *)",
10
- "Bash(git status)",
11
- "Bash(git blame *)",
12
- "Bash(git stash list)",
13
- "Bash(ls *)",
14
- "Bash(wc *)"
15
- ]
16
- },
17
- "mcpServers": {},
18
- "hooks": {
19
- "PreToolUse": [
20
- {
21
- "matcher": "Bash",
22
- "hooks": [
23
- {
24
- "type": "command",
25
- "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/pre-commit-gate.sh\""
26
- }
27
- ]
28
- },
29
- {
30
- "matcher": "Bash",
31
- "hooks": [
32
- {
33
- "type": "command",
34
- "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/safety-guard.sh\""
35
- }
36
- ]
37
- }
38
- ],
39
- "PostToolUse": [
40
- {
41
- "matcher": "Write|Edit",
42
- "hooks": [
43
- {
44
- "type": "command",
45
- "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/post-write.sh\""
46
- }
47
- ]
48
- }
49
- ],
50
- "Stop": [
51
- {
52
- "hooks": [
53
- {
54
- "type": "prompt",
55
- "prompt": "Session context: $ARGUMENTS\n\nIf stop_hook_active is true in the context above, reply ONLY: {\"decision\":\"allow\"} to prevent infinite loops.\n\nOtherwise check: any uncommitted important changes? any in-progress task with outdated progress file? any unrecorded blockers?\n\nReply with ONLY valid JSON, no other text:\n- {\"decision\":\"block\",\"reason\":\"<describe what needs attention>\"} if action needed\n- {\"decision\":\"allow\"} if all clear"
56
- }
57
- ]
58
- }
59
- ],
60
- "Notification": [
61
- {
62
- "hooks": [
63
- {
64
- "type": "command",
65
- "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/progress-ping.sh\""
66
- }
67
- ]
68
- }
69
- ]
70
- }
71
- }
1
+ {
2
+ "includeCoAuthoredBy": false,
3
+ "permissions": {
4
+ "allow": [
5
+ "Read(*)",
6
+ "Grep(*)",
7
+ "Glob(*)",
8
+ "Bash(git log *)",
9
+ "Bash(git diff *)",
10
+ "Bash(git show *)",
11
+ "Bash(git status)",
12
+ "Bash(git blame *)",
13
+ "Bash(git stash list)",
14
+ "Bash(ls *)",
15
+ "Bash(wc *)",
16
+ "Bash(node src/smoke-test.mjs)"
17
+ ]
18
+ },
19
+ "hooks": {
20
+ "UserPromptSubmit": [
21
+ {
22
+ "hooks": [
23
+ {
24
+ "type": "command",
25
+ "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/session-init.sh\""
26
+ }
27
+ ]
28
+ }
29
+ ],
30
+ "PreToolUse": [
31
+ {
32
+ "matcher": "Read|Glob",
33
+ "hooks": [
34
+ {
35
+ "type": "command",
36
+ "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/scout-block.sh\""
37
+ }
38
+ ]
39
+ },
40
+ {
41
+ "matcher": "Read",
42
+ "hooks": [
43
+ {
44
+ "type": "command",
45
+ "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/privacy-block.sh\""
46
+ }
47
+ ]
48
+ },
49
+ {
50
+ "matcher": "Bash",
51
+ "hooks": [
52
+ {
53
+ "type": "command",
54
+ "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/pre-commit-gate.sh\""
55
+ }
56
+ ]
57
+ },
58
+ {
59
+ "matcher": "Bash",
60
+ "hooks": [
61
+ {
62
+ "type": "command",
63
+ "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/safety-guard.sh\""
64
+ }
65
+ ]
66
+ }
67
+ ],
68
+ "PostToolUse": [
69
+ {
70
+ "matcher": "Write|Edit",
71
+ "hooks": [
72
+ {
73
+ "type": "command",
74
+ "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/post-write.sh\""
75
+ }
76
+ ]
77
+ }
78
+ ],
79
+ "Stop": [
80
+ {
81
+ "hooks": [
82
+ {
83
+ "type": "command",
84
+ "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/stop-check.sh\""
85
+ }
86
+ ]
87
+ }
88
+ ],
89
+ "Notification": [
90
+ {
91
+ "hooks": [
92
+ {
93
+ "type": "command",
94
+ "command": "bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/progress-ping.sh\""
95
+ }
96
+ ]
97
+ }
98
+ ]
99
+ },
100
+ "mcpServers": {}
101
+ }